diff --git a/pyasm/pyasm b/pyasm/pyasm index eaf7b90..b7b83c6 100755 --- a/pyasm/pyasm +++ b/pyasm/pyasm @@ -64,6 +64,9 @@ BackpatchList = [] CurrentLine = None CurrentLineNumber = None +# Any undefined label +Undefined = None + ###### # Mostly constant stuff ###### @@ -119,9 +122,11 @@ def write_list(code, addr, lnum, line): code_str = '%06o' % code if code else '' addr_str = '%04o' % addr if addr else '' + lnum_str = '%04d:' % lnum if lnum else '' + line_str = '%s' % line if line else '' - ListFileHandle.write('%6s %4s %04d: %s\n' - % (code_str, addr_str, lnum, line)) + ListFileHandle.write('%6s %4s %s %s\n' + % (code_str, addr_str, lnum_str, line_str)) ListFileHandle.flush() def eval_expression(expr, dot): @@ -131,12 +136,27 @@ def eval_expression(expr, dot): dot current code address (the "." symbol value) Valid expressions are: -# ::= | -# ::= ('|") ('|") + ::= | + ::= ('|") ('|") ::= (||".") [ (+|-) ] ::= """ + global Undefined + + print('eval_expression: expr=%s' % expr) + + # if no expression, do nothing + if expr is None: + return None + + # if expression is a string, return an iterable of ASCII values + if expr[0] in "'\"": + delim = expr[0] + if expr[-1] != delim: + error("Badly formed string value: '%s'" % expr) + return expr[1:-1] + # replace any "." value with "dot" defined in the symbol table expr = string.replace(expr, '.', 'dot') expr = expr.upper() @@ -149,6 +169,11 @@ def eval_expression(expr, dot): except TypeError as e: error('ORG pseudo-opcode expression contains unsatisfied references\n' '%d: %s' % (CurrentLineNumber, CurrentLine)) + except NameError as e: + Undefined = e.message + if 'is not defined' in e.message: + Undefined = e.message[len("name '"):-len("' is not defined")] + raise return result @@ -211,8 +236,11 @@ def assemble_oblock(oblock): if label: error('%d: %s\nORG opcode may not have a label' % (lnum, line)) - address = eval_expression(addr, address) - code = None + try: + address = eval_expression(addr, address) + except NameError as e: + error("%d: %s\nName '%s' is undefined" + % (lnum, line, Undefined)) cblock = [address, []] write_list(None, None, lnum, line) continue @@ -220,20 +248,46 @@ def assemble_oblock(oblock): # END pseudo-op, terminate assembly start_addr = None if addr: - start_addr = eval_expression(addr, address) + try: + start_addr = eval_expression(addr, address) + except NameError as e: + error("%d: %s\nName '%s' is undefined" + % (lnum, line, undefined)) write_list(None, start_addr, lnum, line) return cblock elif opcode == 'EQU': if label is None: error('%d: %s\nEQU opcode missing a label' % (lnum, line)) - value = eval_expression(addr, None) + try: + value = eval_expression(addr, None) + except NameError as e: + error("%d: %s\nName '%s' is undefined" + % (lnum, line, Undefined)) define_label(label, value, lnum) write_list(None, None, lnum, line) continue + elif opcode == 'DATA': + try: + value = eval_expression(addr, address) + except NameError as e: + error("%d: %s\nName '%s' is undefined" + % (lnum, line, Undefined)) + ln = lnum + li = line + if isinstance(value, basestring): + # ASCII constant + for ch in value: + write_list(ord(ch), address, ln, li) + address += 1 + ln = None + li = None + else: + write_list(value, address, lnum, line) + address += 1 else: code = assemble_line(lnum, opcode, addr) - cblock[1].append(code) + cblock[1].append((code, addr)) write_list(code, address, lnum, line) if label: define_label(label, address, lnum) @@ -243,6 +297,8 @@ def assemble_oblock(oblock): define_label(label, address, lnum) write_list(None, None, lnum, line) + return cblock + def assemble_org_blocks(blocks): """Assemble org blocks producing a code blocks list.""" @@ -304,7 +360,7 @@ def split_fields(line): if ndx == -1: error('Unbalanced string delimiter:\n' '%d: %s' % (CurrentLineNumber, CurrentLine)) - address = remainder[:ndx].strip() + address = '"' + remainder[:ndx].strip() + '"' remainder = remainder[ndx+1:].strip() else: # strip off any comment @@ -354,6 +410,72 @@ def split_orgs(asm_lines): return result +def check_org_overlap(code_blocks): + """Check that we don't have overlapping ORG blocks.""" + + # remember org block span: [(start, end), (start', end'), ...] + block_span = [] + + for cb in code_blocks: + (address, code) = cb + if address is None and not code: + # empty code block, ignore + continue + (block_start, code) = cb + block_end = block_start + len(code) - 1 + + print('block: %06o,%06o' % (block_start, block_end)) + + for (start, end) in block_span: + print('check block: %06o,%06o' % (start, end)) + if start <= block_start <= end: + error('ORG block at address %06o overwrites previous block at [%06o,%06o]' + % (block_start, start, end)) + if start <= block_end <= end: + error('ORG block at address %06o overwrites previous block at [%06o,%06o]' + % (block_start, start, end)) + + block_span.append((block_start, block_end)) + +def allocate_literals(code_blocks): + """Allocate space for literal blocks.""" + + pass + +def backpatch(code_blocks): + """Generate final code values, evaluate address fields. + + Returns a simplified code block list: [[address, [code, code, ...]], ...]. + """ + + print('backpatch: code_blocks=%s' % str(code_blocks)) + + result = [] + + for cb in code_blocks: + print('cb=%s' % str(cb)) + (address, codes) = cb + if address is None and not codes: + # empty code block, ignore + continue + + # got a code_block that has code + dot = address + new_code = [] + for (code, addr) in codes: + try: + addr_value = eval_expression(addr, dot) + except NameError as e: + error("Name '%s' is undefined" % Undefined) + if addr_value: + code |= addr_value + new_code.append(code) + dot += 1 + + result.append([address, new_code]) + + return [address, new_code] + def assemble_file(): """Assemble the file and produce listing, output files.""" @@ -372,6 +494,14 @@ def assemble_file(): print('SymTable=%s' % str(SymTable)) print('SymTableLine=%s' % str(SymTableLine)) +# allow programmer to overlap ORG blocks +# check_org_overlap(code_blocks) + + allocate_literals(code_blocks) + + patched_code_blocks = backpatch(code_blocks) + print('patched_code_blocks=%s' % str(patched_code_blocks)) + def main(): """The assembler."""