Rewritten asma
This commit is contained in:
parent
ce00dc2189
commit
16f51cb876
|
@ -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')
|
|
@ -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'
|
||||||
|
|
|
@ -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)))
|
|
|
@ -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
Loading…
Reference in New Issue