Rewritten asma

This commit is contained in:
Andrew Alderwick 2021-05-03 19:15:06 +01:00
parent ce00dc2189
commit 16f51cb876
5 changed files with 1033 additions and 1346 deletions

235
etc/asma.lua Normal file
View File

@ -0,0 +1,235 @@
local band, bor, lshift, rshift
do
local _obj_0 = require('bit')
band, bor, lshift, rshift = _obj_0.band, _obj_0.bor, _obj_0.lshift, _obj_0.rshift
end
local spairs
spairs = function(t)
local keys
do
local _accum_0 = { }
local _len_0 = 1
for k in pairs(t) do
_accum_0[_len_0] = k
_len_0 = _len_0 + 1
end
keys = _accum_0
end
table.sort(keys)
local i = 0
return function()
i = i + 1
return keys[i], t[keys[i]]
end
end
local trees = {
['asma-labels'] = { },
['asma-opcodes'] = { }
}
local opcodes_in_order = { }
do
local wanted = false
for l in assert(io.lines('src/assembler.c')) do
if l == 'char ops[][4] = {' then
wanted = true
elseif wanted then
if l == '};' then
break
end
for w in l:gmatch('[^%s",][^%s",][^%s",]') do
if w ~= '---' then
trees['asma-opcodes'][w] = {
('"%s 00'):format(w),
''
}
end
table.insert(opcodes_in_order, w)
end
end
end
assert(#opcodes_in_order == 32, 'didn\'t find 32 opcodes in assembler code!')
end
do
local add_device
add_device = function(addr, name, fields)
addr = tonumber(addr, 16)
local k
if name:match('^Audio%x+$') then
k = 'asma-ldev-Audio'
else
k = ('asma-ldev-%s'):format(name)
end
trees['asma-labels'][name] = {
('"%s 00'):format(name),
('00%02x :%s/_entry'):format(addr, k)
}
trees[k] = { }
addr = 0
for fname, flen in fields:gmatch('%&(%S+) +%$(%x+)') do
if fname ~= 'pad' then
trees[k][fname] = {
('"%s 00'):format(fname),
('00%02x'):format(addr)
}
end
addr = addr + tonumber(flen, 16)
end
end
for l in assert(io.lines('projects/examples/blank.usm')) do
local f = {
l:match('^%|(%x%x) +%@(%S+) +%[ (.*) %]')
}
if f[1] then
add_device(unpack(f))
end
end
end
do
local representation = setmetatable({
['&'] = '26 00 ( & )'
}, {
__index = function(self, c)
return ("'%s 00"):format(c)
end
})
local process
process = function(label, t)
trees[label] = { }
for k, v in pairs(t) do
trees[label][('%02x'):format(k:byte())] = {
representation[k],
(':%s'):format(v)
}
end
end
process('asma-first-char-normal', {
['%'] = 'asma-macro-define',
['|'] = 'asma-pad-absolute',
['$'] = 'asma-pad-relative',
['@'] = 'asma-label-define',
['&'] = 'asma-sublabel-define',
['#'] = 'asma-literal-hex',
['.'] = 'asma-literal-zero-addr',
[','] = 'asma-literal-rel-addr',
[';'] = 'asma-literal-abs-addr',
[':'] = 'asma-abs-addr',
["'"] = 'asma-raw-char',
['"'] = 'asma-raw-word',
['{'] = 'asma-ignore',
['}'] = 'asma-ignore',
['['] = 'asma-ignore',
[']'] = 'asma-ignore',
['('] = 'asma-comment-start',
[')'] = 'asma-comment-end'
})
process('asma-first-char-macro', {
['('] = 'asma-comment-start',
[')'] = 'asma-comment-end',
['{'] = 'asma-ignore',
['}'] = 'asma-macro-end'
})
process('asma-first-char-comment', {
[')'] = 'asma-comment-end'
})
end
local traverse_node
traverse_node = function(t, min, max, lefts, rights)
local i = math.ceil((min + max) / 2)
if min < i then
lefts[t[i]] = (':&%s'):format(traverse_node(t, min, i - 1, lefts, rights))
end
if i < max then
rights[t[i]] = (':&%s'):format(traverse_node(t, i + 1, max, lefts, rights))
end
return t[i]
end
local traverse_tree
traverse_tree = function(t)
local lefts, rights = { }, { }
local keys
do
local _accum_0 = { }
local _len_0 = 1
for k in pairs(t) do
_accum_0[_len_0] = k
_len_0 = _len_0 + 1
end
keys = _accum_0
end
table.sort(keys)
return lefts, rights, traverse_node(keys, 1, #keys, lefts, rights)
end
local ptr
ptr = function(s)
if s then
return (':&%s'):format(s)
end
return ' $2'
end
local ordered_opcodes
ordered_opcodes = function(t)
local i = 0
return function()
i = i + 1
local v = opcodes_in_order[i]
if t[v] then
return v, t[v]
elseif v then
return false, {
'"--- 00',
''
}
end
end
end
local printout = true
local fmt
fmt = function(...)
return (('\t%-11s %-10s %-12s %-14s %s '):format(...):gsub(' +$', '\n'))
end
do
local _with_0 = assert(io.open('projects/software/asma.usm.tmp', 'w'))
for l in assert(io.lines('projects/software/asma.usm')) do
if l:match('--- cut here ---') then
break
end
_with_0:write(l)
_with_0:write('\n')
end
_with_0:write('( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )\n')
_with_0:write('( automatically generated code below )\n')
_with_0:write('( see etc/asma.moon for instructions )\n')
_with_0:write('\n(')
_with_0:write(fmt('label', 'less than', 'greater than', 'key', 'data )'))
_with_0:write('\n')
for name, tree in spairs(trees) do
_with_0:write(('@%s\n'):format(name))
local lefts, rights, entry = traverse_tree(tree)
local sort_fn
if name == 'asma-opcodes' then
if rights[opcodes_in_order[1]] then
rights[opcodes_in_order[1]] = rights[opcodes_in_order[1]] .. ' &_disasm'
else
rights[opcodes_in_order[1]] = ' $2 &_disasm'
end
sort_fn = ordered_opcodes
else
sort_fn = spairs
end
for k, v in sort_fn(tree) do
local label
if k == entry then
label = '&_entry'
elseif k then
label = ('&%s'):format(k)
else
label = ''
end
_with_0:write(fmt(label, lefts[k] or ' $2', rights[k] or ' $2', unpack(v)))
end
_with_0:write('\n')
end
_with_0:write('@asma-heap\n\n')
_with_0:close()
end
return os.execute('mv projects/software/asma.usm.tmp projects/software/asma.usm')

169
etc/asma.moon Normal file
View File

@ -0,0 +1,169 @@
import band, bor, lshift, rshift from require 'bit'
spairs = (t) ->
keys = [ k for k in pairs t ]
table.sort keys
i = 0
->
i = i + 1
keys[i], t[keys[i]]
trees = {
['asma-labels']: {}
['asma-opcodes']: {}
}
opcodes_in_order = {}
do -- opcodes
wanted = false
for l in assert io.lines 'src/assembler.c'
if l == 'char ops[][4] = {'
wanted = true
elseif wanted
if l == '};'
break
for w in l\gmatch '[^%s",][^%s",][^%s",]'
if w != '---'
trees['asma-opcodes'][w] = {
'"%s 00'\format w
''
}
table.insert opcodes_in_order, w
assert #opcodes_in_order == 32, 'didn\'t find 32 opcodes in assembler code!'
do -- devices -> labels
add_device = (addr, name, fields) ->
addr = tonumber addr, 16
k = if name\match '^Audio%x+$'
'asma-ldev-Audio'
else
'asma-ldev-%s'\format name
trees['asma-labels'][name] = {
'"%s 00'\format name
'00%02x :%s/_entry'\format addr, k
}
trees[k] = {}
addr = 0
for fname, flen in fields\gmatch '%&(%S+) +%$(%x+)'
if fname != 'pad'
trees[k][fname] = {
'"%s 00'\format fname,
'00%02x'\format addr
}
addr += tonumber flen, 16
for l in assert io.lines 'projects/examples/blank.usm'
f = { l\match '^%|(%x%x) +%@(%S+) +%[ (.*) %]' }
if f[1]
add_device unpack f
do -- first characters
representation = setmetatable {
'&': '26 00 ( & )'
},
__index: (c) => "'%s 00"\format c
process = (label, t) ->
trees[label] = {}
for k, v in pairs t
trees[label]['%02x'\format k\byte!] = {
representation[k]
':%s'\format v
}
process 'asma-first-char-normal',
'%': 'asma-macro-define'
'|': 'asma-pad-absolute'
'$': 'asma-pad-relative'
'@': 'asma-label-define'
'&': 'asma-sublabel-define'
'#': 'asma-literal-hex'
'.': 'asma-literal-zero-addr'
',': 'asma-literal-rel-addr'
';': 'asma-literal-abs-addr'
':': 'asma-abs-addr'
"'": 'asma-raw-char'
'"': 'asma-raw-word'
'{': 'asma-ignore'
'}': 'asma-ignore'
'[': 'asma-ignore'
']': 'asma-ignore'
'(': 'asma-comment-start'
')': 'asma-comment-end'
process 'asma-first-char-macro',
'(': 'asma-comment-start'
')': 'asma-comment-end'
'{': 'asma-ignore'
'}': 'asma-macro-end'
process 'asma-first-char-comment',
')': 'asma-comment-end'
traverse_node = (t, min, max, lefts, rights) ->
i = math.ceil (min + max) / 2
if min < i
lefts[t[i]] = ':&%s'\format traverse_node t, min, i - 1, lefts, rights
if i < max
rights[t[i]] = ':&%s'\format traverse_node t, i + 1, max, lefts, rights
return t[i]
traverse_tree = (t) ->
lefts, rights = {}, {}
keys = [ k for k in pairs t ]
table.sort keys
lefts, rights, traverse_node keys, 1, #keys, lefts, rights
ptr = (s) ->
if s
return ':&%s'\format s
return ' $2'
ordered_opcodes = (t) ->
i = 0
->
i = i + 1
v = opcodes_in_order[i]
if t[v]
return v, t[v]
elseif v
return false, { '"--- 00', '' }
printout = true
fmt = (...) ->
('\t%-11s %-10s %-12s %-14s %s '\format(...)\gsub ' +$', '\n')
with assert io.open 'projects/software/asma.usm.tmp', 'w'
for l in assert io.lines 'projects/software/asma.usm'
if l\match '--- cut here ---'
break
\write l
\write '\n'
\write '( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )\n'
\write '( automatically generated code below )\n'
\write '( see etc/asma.moon for instructions )\n'
\write '\n('
\write fmt 'label', 'less than', 'greater than', 'key', 'data )'
\write '\n'
for name, tree in spairs trees
\write '@%s\n'\format name
lefts, rights, entry = traverse_tree tree
sort_fn = if name == 'asma-opcodes'
if rights[opcodes_in_order[1]]
rights[opcodes_in_order[1]] ..= ' &_disasm'
else
rights[opcodes_in_order[1]] = ' $2 &_disasm'
ordered_opcodes
else
spairs
for k, v in sort_fn tree
label = if k == entry
'&_entry'
elseif k
'&%s'\format k
else
''
\write fmt label, lefts[k] or ' $2', rights[k] or ' $2', unpack v
\write '\n'
\write '@asma-heap\n\n'
\close!
os.execute 'mv projects/software/asma.usm.tmp projects/software/asma.usm'

View File

@ -1,350 +0,0 @@
local build_dag
build_dag = function(t, dag, i, j, level)
if dag == nil then
dag = { }
end
if i == nil then
i = 1
end
if j == nil then
j = #t
end
if level == nil then
level = 0
end
if i > j then
return
end
local mid = math.floor((i + j) / 2)
dag[t[mid]] = {
(build_dag(t, dag, i, mid - 1, level + 1)),
(build_dag(t, dag, mid + 1, j, level + 1))
}
return t[mid], dag
end
local append_dag
append_dag = function(node, dag, k)
local i = k > node and 2 or 1
local next_node = dag[node][i]
if next_node then
return append_dag(next_node, dag, k)
end
dag[node][i] = k
dag[k] = { }
end
local build_dag_from_chars
build_dag_from_chars = function(s, ...)
local t
do
local _accum_0 = { }
local _len_0 = 1
for i = 1, #s do
_accum_0[_len_0] = s:sub(i, i)
_len_0 = _len_0 + 1
end
t = _accum_0
end
table.sort(t)
local root, dag = build_dag(t)
for i = 1, select('#', ...) do
append_dag(root, dag, (select(i, ...)))
end
return root, dag
end
local check_terminals
check_terminals = function(dag, s)
for i = 1, #s do
local k = s:sub(i, i)
assert(not dag[k][1], ('%s has left child node'):format(k))
assert(not dag[k][2], ('%s has right child node'):format(k))
end
end
local dump
dump = function(f, root, dag, level)
if level == nil then
level = 0
end
if dag[root][1] then
dump(f, dag[root][1], dag, level + 1)
end
f:write((' '):rep(level))
f:write(root)
f:write('\n')
if dag[root][2] then
return dump(f, dag[root][2], dag, level + 1)
end
end
local convert = setmetatable({
['.'] = 'dot',
['\0'] = 'nul'
}, {
__index = function(self, k)
return k
end
})
local write_opcode_tree
do
local byte_to_opcode = { }
local byte = false
for l in assert(io.lines('src/assembler.c')) do
if l:match('^%s*char%s+ops%[%]%[4%]') then
byte = 0
elseif l:match('%}') then
byte = false
elseif byte then
for opcode in l:gmatch('"([A-Z-][A-Z-][A-Z-])"') do
byte_to_opcode[byte] = opcode
byte = byte + 1
end
end
end
local order_to_opcode
do
local _accum_0 = { }
local _len_0 = 1
for i = 0, #byte_to_opcode do
if byte_to_opcode[i] ~= '---' then
_accum_0[_len_0] = byte_to_opcode[i]
_len_0 = _len_0 + 1
end
end
order_to_opcode = _accum_0
end
table.sort(order_to_opcode)
local root, opcode_to_links = build_dag(order_to_opcode)
write_opcode_tree = function(f)
f:write(('\t$tree .$op-%s ( opcode tree )\n'):format(root:lower()))
f:write('\t$start\n')
for i = 0, #byte_to_opcode do
local opcode = byte_to_opcode[i]
f:write('\t')
if opcode ~= '---' then
f:write(('$op-%s '):format(opcode:lower()))
else
f:write(' ')
end
for j = 1, 2 do
if opcode ~= '---' and opcode_to_links[opcode][j] then
f:write(('.$op-%s '):format(opcode_to_links[opcode][j]:lower()))
else
f:write('[ 0000 ] ')
end
end
if i == 0 then
f:write('$disasm ')
else
f:write(' ')
end
if opcode ~= '---' then
f:write(('[ %s ]'):format(opcode))
else
f:write('[ ??? ]')
end
if i == 0 then
f:write(' $asm')
end
f:write('\n')
end
end
end
local type_byte
type_byte = function(size, has_subtree)
local n1 = has_subtree and '8' or '0'
local n2
local _exp_0 = size
if '1' == _exp_0 then
n2 = '1'
elseif '2' == _exp_0 then
n2 = '2'
else
n2 = '0'
end
return n1 .. n2
end
local globals = { }
local add_globals
add_globals = function(root, dag, key_to_label, key_to_contents, pad_before, pad_after)
if pad_before == nil then
pad_before = ''
end
if pad_after == nil then
pad_after = ''
end
for k in pairs(dag) do
local l = ''
if k == root then
l = l .. ('@%s\n'):format(key_to_label('root'):gsub('%s', ''))
end
l = l .. ('@%s '):format(key_to_label(k))
for j = 1, 2 do
if dag[k][j] then
l = l .. ('.%s '):format(key_to_label(dag[k][j]))
else
l = l .. ('%s[ 0000 ]%s '):format(pad_before, pad_after)
end
end
l = l .. key_to_contents(k)
l = l .. '\n'
globals[key_to_label(k):gsub('%s', '')] = l
end
globals[key_to_label('root'):gsub('%s', '')] = ''
end
do
local root, dag = build_dag_from_chars('{}[]%@$;|=~,.^#"\0', '(', ')')
check_terminals(dag, ')')
local label_name
label_name = function(s)
return ('normal-%-3s'):format(convert[s])
end
local label_value
label_value = function(k)
return ('[ %02x ]'):format(k:byte())
end
add_globals(root, dag, label_name, label_value, '', ' ')
end
do
local root, dag = build_dag_from_chars('{}', '\0', '(')
dump(io.stdout, root, dag)
local label_name
label_name = function(s)
if s == '(' then
return 'normal-( '
end
return ('variable-%s'):format(convert[s])
end
local label_value
label_value = function(k)
return ('[ %02x ]'):format(k:byte())
end
dag['('] = nil
add_globals(root, dag, label_name, label_value, '', ' ')
end
do
local root, dag = build_dag_from_chars('{}\0', '(')
dump(io.stdout, root, dag)
local label_name
label_name = function(s)
if s == '(' then
return 'normal-( '
end
return ('macro-%-3s'):format(convert[s])
end
local label_value
label_value = function(k)
return ('[ %02x ]'):format(k:byte())
end
dag['('] = nil
add_globals(root, dag, label_name, label_value, '', ' ')
end
do
local root, dag = build_dag_from_chars(']\0', '(')
dump(io.stdout, root, dag)
local label_name
label_name = function(s)
if s == '(' then
return 'normal-( '
end
return ('data-%-4s'):format(convert[s])
end
local label_value
label_value = function(k)
return ('[ %02x ]'):format(k:byte())
end
dag['('] = nil
add_globals(root, dag, label_name, label_value, '', ' ')
end
local devices = { }
local add_device
add_device = function(name, fields)
local field_sizes
do
local _tbl_0 = { }
for k, size in fields:gmatch('(%S+) (%d+)') do
_tbl_0[k] = size
end
field_sizes = _tbl_0
end
field_sizes.pad = nil
local field_names
do
local _accum_0 = { }
local _len_0 = 1
for k in pairs(field_sizes) do
_accum_0[_len_0] = k
_len_0 = _len_0 + 1
end
field_names = _accum_0
end
table.sort(field_names)
local root, dag = build_dag(field_names)
local label_name
label_name = function(k)
return ('l-%-14s'):format(name .. '-' .. k)
end
local label_value
label_value = function(k)
return ('%-17s [ %s ] .%s.%s'):format(('[ %s 00 ]'):format(k), type_byte(field_sizes[k], false), name, k)
end
add_globals(root, dag, label_name, label_value, ' ', ' ')
return table.insert(devices, name)
end
local add_devices
add_devices = function()
table.sort(devices)
local root, dag = build_dag(devices)
local label_name
label_name = function(k)
return ('l-%-14s'):format(k)
end
local label_value
label_value = function(k)
return ('%-17s [ %s ] .%s .l-%s-root'):format(('[ %s 00 ]'):format(k), type_byte(0, true), k, k)
end
return add_globals(root, dag, label_name, label_value, ' ', ' ')
end
local filename = 'projects/software/assembler.usm'
local f = assert(io.open(('%s.tmp'):format(filename), 'w'))
local state = 'normal'
local machine = {
normal = function(l)
if l:match('%( opcode tree %)') then
write_opcode_tree(f)
state = 'opcode'
elseif l:match('^%@') then
if l == '@RESET' then
add_devices()
end
for k in l:gmatch('%@(%S+)') do
if globals[k] then
f:write(globals[k])
globals[k] = nil
return
end
end
f:write(l)
return f:write('\n')
else
if l:match('^%|%x%x%x%x %;') then
add_device(l:match('%;(%S+) %{ (.*) %}'))
end
f:write(l)
return f:write('\n')
end
end,
opcode = function(l)
if not l:match('.') then
f:write(l)
f:write('\n')
state = 'normal'
end
end
}
for l in assert(io.lines(filename)) do
machine[state](l)
end
for _, l in pairs(globals) do
f:write(l)
end
f:close()
assert(0 == os.execute(('mv %s %s.bak'):format(filename, filename)))
return assert(0 == os.execute(('mv %s.tmp %s'):format(filename, filename)))

View File

@ -1,210 +0,0 @@
build_dag = (t, dag = {}, i = 1, j = #t, level = 0) ->
if i > j
return
mid = math.floor (i + j) / 2
dag[t[mid]] = {
(build_dag t, dag, i, mid - 1, level + 1)
(build_dag t, dag, mid + 1, j, level + 1)
}
t[mid], dag
append_dag = (node, dag, k) ->
i = k > node and 2 or 1
next_node = dag[node][i]
if next_node
return append_dag next_node, dag, k
dag[node][i] = k
dag[k] = {}
build_dag_from_chars = (s, ...) ->
t = [ s\sub i, i for i = 1, #s ]
table.sort t
root, dag = build_dag t
for i = 1, select '#', ...
append_dag root, dag, (select i, ...)
return root, dag
check_terminals = (dag, s) ->
for i = 1, #s
k = s\sub i, i
assert not dag[k][1], '%s has left child node'\format k
assert not dag[k][2], '%s has right child node'\format k
dump = (f, root, dag, level = 0) ->
if dag[root][1]
dump f, dag[root][1], dag, level + 1
f\write ' '\rep level
f\write root
f\write '\n'
if dag[root][2]
dump f, dag[root][2], dag, level + 1
convert = setmetatable { ['.']: 'dot', ['\0']: 'nul' },
__index: (k) => k
-- deal with opcodes
write_opcode_tree = do
byte_to_opcode = {}
byte = false
for l in assert io.lines 'src/assembler.c'
if l\match '^%s*char%s+ops%[%]%[4%]'
byte = 0
elseif l\match '%}'
byte = false
elseif byte
for opcode in l\gmatch '"([A-Z-][A-Z-][A-Z-])"'
byte_to_opcode[byte] = opcode
byte += 1
order_to_opcode = [ byte_to_opcode[i] for i = 0, #byte_to_opcode when byte_to_opcode[i] != '---' ]
table.sort order_to_opcode
root, opcode_to_links = build_dag order_to_opcode
(f) ->
f\write '\t$tree .$op-%s ( opcode tree )\n'\format root\lower!
f\write '\t$start\n'
for i = 0, #byte_to_opcode
opcode = byte_to_opcode[i]
f\write '\t'
if opcode != '---'
f\write '$op-%s '\format opcode\lower!
else
f\write ' '
for j = 1, 2
if opcode != '---' and opcode_to_links[opcode][j]
f\write '.$op-%s '\format opcode_to_links[opcode][j]\lower!
else
f\write '[ 0000 ] '
if i == 0
f\write '$disasm '
else
f\write ' '
if opcode != '---'
f\write '[ %s ]'\format opcode
else
f\write '[ ??? ]'
if i == 0
f\write ' $asm'
f\write '\n'
type_byte = (size, has_subtree) ->
n1 = has_subtree and '8' or '0'
n2 = switch size
when '1'
'1'
when '2'
'2'
else
'0'
n1 .. n2
globals = {}
add_globals = (root, dag, key_to_label, key_to_contents, pad_before = '', pad_after = '') ->
for k in pairs dag
l = ''
if k == root
l ..= '@%s\n'\format key_to_label('root')\gsub '%s', ''
l ..= '@%s '\format key_to_label k
for j = 1, 2
if dag[k][j]
l ..= '.%s '\format key_to_label dag[k][j]
else
l ..= '%s[ 0000 ]%s '\format pad_before, pad_after
l ..= key_to_contents k
l ..= '\n'
globals[key_to_label(k)\gsub '%s', ''] = l
globals[key_to_label('root')\gsub '%s', ''] = ''
do
root, dag = build_dag_from_chars '{}[]%@$;|=~,.^#"\0', '(', ')'
check_terminals dag, ')'
label_name = (s) -> 'normal-%-3s'\format convert[s]
label_value = (k) -> '[ %02x ]'\format k\byte!
add_globals root, dag, label_name, label_value, '', ' '
do
root, dag = build_dag_from_chars '{}', '\0', '('
dump io.stdout, root, dag
label_name = (s) ->
if s == '('
return 'normal-( '
'variable-%s'\format convert[s]
label_value = (k) -> '[ %02x ]'\format k\byte!
dag['('] = nil
add_globals root, dag, label_name, label_value, '', ' '
do
root, dag = build_dag_from_chars '{}\0', '('
dump io.stdout, root, dag
label_name = (s) ->
if s == '('
return 'normal-( '
'macro-%-3s'\format convert[s]
label_value = (k) -> '[ %02x ]'\format k\byte!
dag['('] = nil
add_globals root, dag, label_name, label_value, '', ' '
do
root, dag = build_dag_from_chars ']\0', '('
dump io.stdout, root, dag
label_name = (s) ->
if s == '('
return 'normal-( '
'data-%-4s'\format convert[s]
label_value = (k) -> '[ %02x ]'\format k\byte!
dag['('] = nil
add_globals root, dag, label_name, label_value, '', ' '
devices = {}
add_device = (name, fields) ->
field_sizes = { k, size for k, size in fields\gmatch '(%S+) (%d+)' }
field_sizes.pad = nil
field_names = [ k for k in pairs field_sizes ]
table.sort field_names
root, dag = build_dag field_names
label_name = (k) -> 'l-%-14s'\format name .. '-' .. k
label_value = (k) -> '%-17s [ %s ] .%s.%s'\format '[ %s 00 ]'\format(k), type_byte(field_sizes[k], false), name, k
add_globals root, dag, label_name, label_value, ' ', ' '
table.insert devices, name
add_devices = ->
table.sort devices
root, dag = build_dag devices
label_name = (k) -> 'l-%-14s'\format k
label_value = (k) -> '%-17s [ %s ] .%s .l-%s-root'\format '[ %s 00 ]'\format(k), type_byte(0, true), k, k
add_globals root, dag, label_name, label_value, ' ', ' '
filename = 'projects/software/assembler.usm'
f = assert io.open '%s.tmp'\format(filename), 'w'
-- f = io.stdout
state = 'normal'
machine =
normal: (l) ->
if l\match '%( opcode tree %)'
write_opcode_tree f
state = 'opcode'
elseif l\match '^%@'
if l == '@RESET'
add_devices!
for k in l\gmatch '%@(%S+)'
if globals[k]
f\write globals[k]
globals[k] = nil
return
f\write l
f\write '\n'
else
if l\match '^%|%x%x%x%x %;'
add_device l\match '%;(%S+) %{ (.*) %}'
f\write l
f\write '\n'
opcode: (l) ->
if not l\match '.'
f\write l
f\write '\n'
state = 'normal'
for l in assert io.lines filename
machine[state] l
for _, l in pairs globals
f\write l
f\close!
assert 0 == os.execute 'mv %s %s.bak'\format filename, filename
assert 0 == os.execute 'mv %s.tmp %s'\format filename, filename

File diff suppressed because it is too large Load Diff