mirror of
https://github.com/rzzzwilson/pymlac.git
synced 2025-06-10 09:32:41 +00:00
Almost finished, need to assemble opcode
This commit is contained in:
parent
01d2d7b60d
commit
86a6f7bb14
150
pyasm/pyasm
150
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:
|
||||
# <expr> ::= <string> | <numeric_expression>
|
||||
# <string> ::= ('|") <characters> ('|")
|
||||
<expr> ::= <string> | <numeric_expression>
|
||||
<string> ::= ('|") <characters> ('|")
|
||||
<numeric_expression> ::= (<numeric_const>|<name_const>|".") [ (+|-) <numeric_expression> ]
|
||||
<name_const> ::= <name_characters>
|
||||
"""
|
||||
|
||||
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."""
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user