1 #
2 # Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions an
14 # limitations under the License.
15 #
16 #
17 # LASM Command Parser
18 #
19 # Search a command and convert into 16bit code
20 # Written based on documents below
21 # - www.ti.com/lit/ds/symlink/lp5523.pdf
22 # - www.ti.com/lit/an/snva664/snva664.pdf
23 #
25 import six # support compatibility between Python 2.x and 3
26 import _lasm_utils as util
28 # Constant numbers for ramp/wait command
29 PRESCALE0 = 0.015625
30 PRESCALE1 = 0.5
31 MASTER_FREQ = 32768
32 PRESCALE0_CLK = MASTER_FREQ / 16
33 PRESCALE1_CLK = MASTER_FREQ / 512
34 MAXCODE = 0x1F
35 PRESCALE_CODE = 0x40
38 # Display error
39 # Format: 'function name' 'error message'
40 def put_error(message):
41 func_name = util.get_caller_func_name()
42 util.put_error(func_name, message)
43 return False
46 # Segment command is used for program engine selection (1,2,3)
47 # Save start SRAM address to calculate label offset
48 def segment(name):
49 args = name.split()
50 if len(args) != 1:
51 return put_error('must have one argument')
53 if util.add_segment_list(args[0]) is False:
54 return put_error('duplicate segment name')
56 return True
59 def mux_map_start(label):
60 args = label.split()
61 if len(args) != 1:
62 return put_error('must have one argument')
64 code = util.get_address_of_label(args[0], '')
65 if code == util.INVALID_ADDR:
66 return False
68 MUX_MAP_START = 0x9C00
69 return util.put_code(MUX_MAP_START | code)
72 def mux_map_next(val):
73 return util.put_code(0x9D80)
76 def mux_map_prev(val):
77 return util.put_code(0x9DC0)
80 def mux_ld_next(val):
81 return util.put_code(0x9D81)
84 def mux_ld_prev(val):
85 return util.put_code(0x9DC1)
88 def mux_ld_addr(label):
89 args = label.split()
90 if len(args) != 1:
91 return put_error('must have one argument')
93 code = util.get_address_of_label(args[0], '')
94 if code == util.INVALID_ADDR:
95 return False
97 MUX_LD_ADDR = 0x9F00
98 return util.put_code(MUX_LD_ADDR | code)
101 def mux_map_addr(label):
102 args = label.split()
103 if len(args) != 1:
104 return put_error('must have one argument')
106 code = util.get_address_of_label(args[0], '')
107 if code == util.INVALID_ADDR:
108 return False
110 MUX_MAP_ADDR = 0x9F80
111 return util.put_code(MUX_MAP_ADDR | code)
114 def mux_sel(val):
115 args = val.split()
116 if len(args) != 1:
117 return put_error('must have one argument')
119 MAX_LEDS = 9
120 GPO = 16
121 led = int(args[0])
122 if (led < 0 or (led > MAX_LEDS and led is not GPO)):
123 return put_error('%d is invalid argument' % led)
125 MUX_SEL = 0x9D00
126 return util.put_code(MUX_SEL | led)
129 def mux_clr(val):
130 return util.put_code(0x9D00)
133 def mux_ld_start(label):
134 args = label.split()
135 if len(args) != 1:
136 return put_error('must have one argument')
138 code = util.get_address_of_label(args[0], '')
139 if code == util.INVALID_ADDR:
140 return False
142 MUX_LD_START = 0x9E00
143 return util.put_code(MUX_LD_START | code)
146 def mux_ld_end(label):
147 args = label.split()
148 if len(args) != 1:
149 return put_error('must have one argument')
151 code = util.get_address_of_label(args[0], '')
152 if code == util.INVALID_ADDR:
153 return False
155 MUX_LD_END = 0x9C80
156 return util.put_code(MUX_LD_END | code)
159 def set_pwm(val):
160 args = val.split()
161 if len(args) != 1:
162 return put_error('must have one argument')
164 arg = args[0]
165 # Format: set_pwm 'ra' or 'rb' or 'rc' or 'rd'
166 # set_pwm <number>
167 variables = {'ra': 0, 'rb': 1, 'rc': 2, 'rd': 3}
168 index_var = variables.get(arg)
169 if index_var is None:
170 if arg.isdigit() is False:
171 t = util.number_type(arg)
172 types = {'b', 'B', 'h', 'H'}
173 if t not in types:
174 return put_error('%s is invalid argument' % arg)
176 SET_PWM = 0x4000
177 code = util.format_number(arg)
178 return util.put_code(SET_PWM | code)
180 SET_PWM = 0x8460
181 return util.put_code(SET_PWM | index_var)
184 def wait(val):
185 args = val.split()
186 if len(args) != 1:
187 return put_error('must have one argument')
189 time = float(args[0])
190 if time < 0:
191 return put_error('time should be positive value')
193 if time < PRESCALE0:
194 code = min(int(round(time * PRESCALE0_CLK, 0)), MAXCODE)
195 code = code << 1
196 elif time < PRESCALE1:
197 code = min(int(round(time * PRESCALE1_CLK, 0)), MAXCODE)
198 code = PRESCALE_CODE | (code << 1)
199 else:
200 return put_error('time should be less than 0.48')
202 return util.put_code(code << 8)
205 # Format: ramp <time>, <pwm>
206 # ramp <variable1>, <prescale>, <variable2>
207 # variable1 = 'ra' or 'rb' or 'rc' or 'rd'
208 # prescale = 'pre=0' or 'pre=1'
209 # variable2 = '+ra' or '+rb' or '+rc' or '+rd' or
210 # '-ra' or '-rb' or '-rc' or '-rd'
211 def ramp(val):
212 args = val.split(',')
213 if len(args) == 2: # format : ramp <time>, <pwm>
214 # Remove space and check whether it is digit or not
215 stime = args[0].split()[0]
216 spwm = args[1].split()[0]
217 if util.is_float(stime):
218 time = float(stime)
219 pwm = int(spwm)
221 if time < 0:
222 return put_error('time should be positive value')
224 if (pwm < -255 or pwm > 255):
225 return put_error('%d is out of range. -255 <= value <= 255'
226 % pwm)
228 if pwm == 0:
229 return put_error('%d is invalid. should not zero' % pwm)
231 time = time / abs(pwm)
232 if time < PRESCALE0:
233 code = min(int(round(time * PRESCALE0_CLK, 0)), MAXCODE)
234 code = code << 1
235 elif time < PRESCALE1:
236 code = min(int(round(time * PRESCALE1_CLK, 0)), MAXCODE)
237 code = PRESCALE_CODE | (code << 1)
238 else:
239 return put_error('too long time')
241 NEGATIVE = 0x01
242 if pwm < 0:
243 code = code | NEGATIVE
245 return util.put_code((code << 8) | abs(pwm))
246 else:
247 return put_error('invalid value')
248 elif len(args) == 3: # format : ramp <var1>, <prescale>, <var2>
249 # Step time
250 var1 = args[0].split()[0]
251 variables = {'ra': 0x0, 'rb': 0x04, 'rc': 0x08, 'rd': 0x0C}
252 step_time = variables.get(var1)
253 if step_time is None:
254 return put_error('%s is invalid argument' % var1)
256 # Prescale
257 if args[1].split()[0] == 'pre=0':
258 prescale = 0 << 4
259 elif args[1].split()[0] == 'pre=1':
260 prescale = 1 << 4
261 else:
262 return put_error('%s is invalid argument' % args[1].split()[0])
264 # Sign bit and number of increments
265 var2 = args[2].split()[0]
266 variables = {'+ra': 0x00, '+rb': 0x01, '+rc': 0x02, '+rd': 0x03,
267 '-ra': 0x10, '-rb': 0x11, '-rc': 0x12, '-rd': 0x13}
268 sign_and_inc = variables.get(var2)
269 if sign_and_inc is None:
270 return put_error('%s is invalid argument' % var2)
272 RAMP = 0x8400
273 return util.put_code(RAMP | prescale | sign_and_inc | step_time)
275 return put_error('invalid arguments')
278 # Convert ds argument to offset
279 def get_offset_size(val):
280 args = val.split()
281 if len(args) != 1:
282 return -1
283 return util.format_number(args[0])
286 def ds(val):
287 size = get_offset_size(val)
288 if size < 0:
289 return put_error('must have one argument')
291 for i in range(0, size):
292 util.put_code(0x0000)
293 return True
296 def dw(val):
297 args = val.split()
298 if len(args) != 1:
299 return put_error('must have one argument')
301 code = util.format_number(args[0])
302 return util.put_code(code)
305 # Format: branch <number>, label
306 # branch 'ra' or 'rb' or 'rc' or 'rd', label
307 def branch(val):
308 args = val.split(',')
309 if len(args) != 2:
310 return put_error('must have two arguments')
312 # Remove space and check whether it is digit or not
313 if args[0].split()[0].isdigit():
314 loop_count = int(args[0].split()[0])
315 if (loop_count < 0 or loop_count > 64):
316 return put_error('%d is out of range. 0 <= loop count <= 63'
317 % loop_count)
319 label = args[1].split()[0]
320 step_no = util.get_offset_address_of_label(label)
321 if step_no == util.INVALID_ADDR:
322 return False
324 BRANCH = 0xA000
325 word = (BRANCH | (loop_count << 7) | (step_no & 0x7F))
326 else:
327 variables = {'ra': 0, 'rb': 1, 'rc': 2, 'rd': 3}
328 index_var = variables.get(args[0].split()[0])
329 if index_var is None:
330 return put_error('%s is invalid argument' % args[0].split()[0])
332 label = args[1].split()[0]
333 step_no = util.get_offset_address_of_label(label)
334 if step_no == util.INVALID_ADDR:
335 return False
337 BRANCH = 0x8600
338 word = (BRANCH | (step_no << 2) | index_var)
340 return util.put_code(word)
343 def reset(val):
344 return util.put_code(0x0000)
347 def interrupt(val):
348 return util.put_code(0xC400)
351 def end(val):
352 args = val.split()
353 if len(args) == 0: # format: 'end'
354 return util.put_code(0xC000)
356 args = args[0].split(',')
357 num_args = len(args)
358 if num_args == 1: # format: 'end i' or 'end r'
359 arg = args[0]
360 if arg == 'i':
361 return util.put_code(0xD000)
362 elif arg == 'r':
363 return util.put_code(0xC800)
364 elif num_args == 2: # format: 'end i,r' or 'end r,i'
365 arg1 = args[0]
366 arg2 = args[1]
367 if (arg1 == 'i' and arg2 == 'r') or (arg1 == 'r' and arg2 == 'i'):
368 return util.put_code(0xD800)
370 return put_error('invalid argument')
373 # Generate trigger code
374 def get_trigger_code(val):
375 code = 0
376 if (val.find('1') > 0):
377 code |= 0x01
378 if (val.find('2') > 0):
379 code |= 0x02
380 if (val.find('3') > 0):
381 code |= 0x04
382 if (val.find('e') > 0):
383 code |= 0x20
385 return code
388 # Format: trigger w{source1 | source 2 .. }
389 # trigger s{source1 | source 2 .. }
390 # trigger w{source1 | source 2 .. }, s{source1 | source 2 .. }
391 # trigger s{source1 | source 2 .. }, w{source1 | source 2 .. }
392 # trigger w{source1 | source 2 .. } s{source1 | source 2 .. }
393 # trigger s{source1 | source 2 .. } w{source1 | source 2 .. }
394 def trigger(val):
395 WAIT = 'w{'
396 START = 's{'
397 w_code = 0
398 s_code = 0
400 idx_wait = val.find(WAIT)
401 if idx_wait > 0:
402 w_code = get_trigger_code(val[idx_wait:])
404 idx_start = val.find(START)
405 if idx_start > 0:
406 s_code = get_trigger_code(val[idx_start:])
408 if idx_wait < 0 and idx_start < 0:
409 return put_error('invalid argument')
411 TRIGGER = 0xE000
412 return util.put_code(TRIGGER | (w_code << 7) | (s_code << 1))
415 # Common function for jne, jl, jge and je
416 # Format: <command> var1, var2, label(address)
417 def jump(val, action):
418 args = val.split(',')
419 if len(args) != 3:
420 return put_error('must have three arguments')
422 # Check the 1st and 2nd argument are variable or not
423 var1 = args[0].split()[0]
424 var2 = args[1].split()[0]
425 variables = {'ra': 0, 'rb': 1, 'rc': 2, 'rd': 3}
426 index_var1 = variables.get(var1)
427 if index_var1 is None:
428 return put_error('%s is invalid argument' % var1)
430 index_var2 = variables.get(var2)
431 if index_var2 is None:
432 return put_error('%s is invalid argument' % var2)
434 # Check the 3rd is label or not
435 var3 = args[2].split()[0]
436 addr = util.get_address_of_label(var3, "")
437 if addr == util.INVALID_ADDR:
438 return False
440 cmds = {'jne': 0x8800, 'jl': 0x8A00, 'jge': 0x8C00, 'je': 0x8E00}
441 code = cmds.get(action)
442 if code is None:
443 return put_error('%s is invalid argument' % action)
445 offset = abs(addr - util.get_sram_address()) - 1
446 word = (code | (offset << 4) | (index_var1 << 2) | index_var2)
447 return util.put_code(word)
450 def jne(val):
451 return jump(val, 'jne')
454 def jl(val):
455 return jump(val, 'jl')
458 def jge(val):
459 return jump(val, 'jge')
462 def je(val):
463 return jump(val, 'je')
466 def ld(val):
467 args = val.split(',')
468 if len(args) != 2:
469 return put_error('must have two arguments')
471 # Check the 1st argument is variable or not
472 var = args[0].split()[0]
473 target = {'ra': 0, 'rb': 1, 'rc': 2}
474 index = target.get(var)
475 if index is None:
476 return put_error('%s is invalid argument' % var)
478 # Check the 2nd argument is valid or not
479 val = util.format_number(args[1].split()[0])
480 if val < 0 or val > 255:
481 return put_error('%d is out of range. 0 <= value <=255' % val)
483 LD = 0x9000
484 word = (LD | (index << 10) | val)
485 return util.put_code(word)
488 # Common function for 'add' and 'sub'
489 # Two formats supported
490 # <command> var, value
491 # <command> var1, var2, var3
492 def add_or_sub(val, action):
493 args = val.split(',')
494 if len(args) == 2: # format: add var, value
495 # Check the 1st argument is variable or not
496 var = args[0].split()[0]
497 target = {'ra': 0, 'rb': 1, 'rc': 2}
498 index = target.get(var)
499 if index is None:
500 return put_error('%s is invalid argument' % var)
502 # Check the 2nd argument is valid or not
503 val = util.format_number(args[1].split()[0])
504 if (val < 0 or val > 255):
505 return put_error('%d is out of range. 0 <= value <=255' % val)
507 cmds = {'add': 0x9100, 'sub': 0x9200}
508 code = cmds.get(action)
509 if code is None:
510 return put_error('%s is invalid argument' % action)
512 word = (code | (index << 10) | val)
513 util.put_code(word)
514 elif len(args) == 3: # format: add var1, var2, var3
515 # Check the 1st argument is variable or not
516 var1 = args[0].split()[0]
517 target = {'ra': 0, 'rb': 1, 'rc': 2}
518 index_var1 = target.get(var1)
519 if index_var1 is None:
520 return put_error('%s is invalid argument' % var1)
522 # Check the others are variable or not
523 var2 = args[1].split()[0]
524 var3 = args[2].split()[0]
525 others = {'ra': 0, 'rb': 1, 'rc': 2, 'rd': 3}
526 index_var2 = others.get(var2)
527 if index_var2 is None:
528 return put_error('%s is invalid argument' % var2)
530 index_var3 = others.get(var3)
531 if index_var3 is None:
532 return put_error('%s is invalid argument' % var3)
534 cmds = {'add': 0x9300, 'sub': 0x9310}
535 code = cmds.get(action)
536 if code is None:
537 return put_error('%s is invalid argument' % action)
539 word = (code | (index_var1 << 10) | (index_var2 << 2) | index_var3)
540 return util.put_code(word)
541 else:
542 return put_error('invalid arguments')
545 def add(val):
546 return add_or_sub(val, "add")
549 def sub(val):
550 return add_or_sub(val, "sub")
553 # Command map
554 # Format: { 'command':function }
555 # If 'command' is found, then function is called by lookup_command() in case
556 # the action is 'generate_code'
557 commands = {
558 '.segment': segment,
559 'mux_map_start': mux_map_start,
560 'mux_map_next': mux_map_next,
561 'mux_map_prev': mux_map_prev,
562 'mux_ld_next': mux_ld_next,
563 'mux_ld_prev': mux_ld_prev,
564 'mux_ld_addr': mux_ld_addr,
565 'mux_map_addr': mux_map_addr,
566 'mux_sel': mux_sel,
567 'mux_clr': mux_clr,
568 'mux_ld_start': mux_ld_start,
569 'mux_ld_end': mux_ld_end,
570 'set_pwm': set_pwm,
571 'wait': wait,
572 'ramp': ramp,
573 'ds': ds,
574 'dw': dw,
575 'branch': branch,
576 'rst': reset,
577 'int': interrupt,
578 'end': end,
579 'trigger': trigger,
580 'jne': jne,
581 'jl': jl,
582 'jge': jge,
583 'je': je,
584 'ld': ld,
585 'add': add,
586 'sub': sub,
587 }
590 # Command Parser
591 #
592 # Format: <command> <argument1> .. <argumentsN>
593 # To ignore spaces, split() is used
594 def lookup_command(cmd, action):
595 # Skip checking if the command is space character
596 if len(cmd.split()) == 0:
597 return True
599 for key, func in six.iteritems(commands):
600 if cmd.split()[0] == key:
601 # Two actions are allowed when the command is matched
602 # - create_label: just increase SRAM address for next use
603 # - generate_code: code is generated by each function call
604 if action == 'create_label':
605 # .segment command does not require SRAM address increment
606 if key == '.segment':
607 return True
609 # ds command needs to update SRAM size offset
610 if key == 'ds':
611 arg = cmd.split(key)[1]
612 size = get_offset_size(arg)
613 if size < 0:
614 return put_error("wrong size information")
616 for x in range(0, size):
617 if util.inc_sram_address() is False:
618 return put_error("code size should be less than %d"
619 % util.MAX_SRAM_SIZE)
621 return True
623 # Other commands, just increase SRAM address
624 if util.inc_sram_address() is False:
625 return put_error("code size should be less than %d"
626 % util.MAX_SRAM_SIZE)
628 return True
629 elif action == 'generate_code':
630 arg = cmd.split(key)[1]
631 return func(arg) # call a function
633 return put_error("%s command is not found" % cmd)
636 # Line format
637 #
638 # COMMAND ARGUMENTS(S) 'COMMAND format'
639 # LABEL: COMMAND ARGUMENT(S) 'LABEL format'
640 def parse_line(string, action):
641 LABEL = ":"
642 index = string.find(LABEL)
643 if index > 0: # LABEL format
644 if action == 'create_label':
645 util.add_label_list(string[:index])
646 return lookup_command(string[index + 1:], action)
647 else: # COMMAND format
648 return lookup_command(string, action)