| 10 | 11 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,295 @@ |
| 1 |
+local build_dag |
|
| 2 |
+build_dag = function(t, dag, i, j, level) |
|
| 3 |
+ if dag == nil then |
|
| 4 |
+ dag = { }
|
|
| 5 |
+ end |
|
| 6 |
+ if i == nil then |
|
| 7 |
+ i = 1 |
|
| 8 |
+ end |
|
| 9 |
+ if j == nil then |
|
| 10 |
+ j = #t |
|
| 11 |
+ end |
|
| 12 |
+ if level == nil then |
|
| 13 |
+ level = 0 |
|
| 14 |
+ end |
|
| 15 |
+ if i > j then |
|
| 16 |
+ return |
|
| 17 |
+ end |
|
| 18 |
+ local mid = math.floor((i + j) / 2) |
|
| 19 |
+ dag[t[mid]] = {
|
|
| 20 |
+ (build_dag(t, dag, i, mid - 1, level + 1)), |
|
| 21 |
+ (build_dag(t, dag, mid + 1, j, level + 1)) |
|
| 22 |
+ } |
|
| 23 |
+ return t[mid], dag |
|
| 24 |
+end |
|
| 25 |
+local append_dag |
|
| 26 |
+append_dag = function(node, dag, k) |
|
| 27 |
+ local i = k > node and 2 or 1 |
|
| 28 |
+ local next_node = dag[node][i] |
|
| 29 |
+ if next_node then |
|
| 30 |
+ return append_dag(next_node, dag, k) |
|
| 31 |
+ end |
|
| 32 |
+ dag[node][i] = k |
|
| 33 |
+ dag[k] = { }
|
|
| 34 |
+end |
|
| 35 |
+local build_dag_from_chars |
|
| 36 |
+build_dag_from_chars = function(s, ...) |
|
| 37 |
+ local t |
|
| 38 |
+ do |
|
| 39 |
+ local _accum_0 = { }
|
|
| 40 |
+ local _len_0 = 1 |
|
| 41 |
+ for i = 1, #s do |
|
| 42 |
+ _accum_0[_len_0] = s:sub(i, i) |
|
| 43 |
+ _len_0 = _len_0 + 1 |
|
| 44 |
+ end |
|
| 45 |
+ t = _accum_0 |
|
| 46 |
+ end |
|
| 47 |
+ table.sort(t) |
|
| 48 |
+ local root, dag = build_dag(t) |
|
| 49 |
+ for i = 1, select('#', ...) do
|
|
| 50 |
+ append_dag(root, dag, (select(i, ...))) |
|
| 51 |
+ end |
|
| 52 |
+ return root, dag |
|
| 53 |
+end |
|
| 54 |
+local check_terminals |
|
| 55 |
+check_terminals = function(dag, s) |
|
| 56 |
+ for i = 1, #s do |
|
| 57 |
+ local k = s:sub(i, i) |
|
| 58 |
+ assert(not dag[k][1], ('%s has left child node'):format(k))
|
|
| 59 |
+ assert(not dag[k][2], ('%s has right child node'):format(k))
|
|
| 60 |
+ end |
|
| 61 |
+end |
|
| 62 |
+local dump |
|
| 63 |
+dump = function(f, root, dag, level) |
|
| 64 |
+ if level == nil then |
|
| 65 |
+ level = 0 |
|
| 66 |
+ end |
|
| 67 |
+ if dag[root][1] then |
|
| 68 |
+ dump(f, dag[root][1], dag, level + 1) |
|
| 69 |
+ end |
|
| 70 |
+ f:write((' '):rep(level))
|
|
| 71 |
+ f:write(root) |
|
| 72 |
+ f:write('\n')
|
|
| 73 |
+ if dag[root][2] then |
|
| 74 |
+ return dump(f, dag[root][2], dag, level + 1) |
|
| 75 |
+ end |
|
| 76 |
+end |
|
| 77 |
+local write_opcode_tree |
|
| 78 |
+do |
|
| 79 |
+ local byte_to_opcode = { }
|
|
| 80 |
+ local byte = false |
|
| 81 |
+ for l in assert(io.lines('src/assembler.c')) do
|
|
| 82 |
+ if l:match('^%s*char%s+ops%[%]%[4%]') then
|
|
| 83 |
+ byte = 0 |
|
| 84 |
+ elseif l:match('%}') then
|
|
| 85 |
+ byte = false |
|
| 86 |
+ elseif byte then |
|
| 87 |
+ for opcode in l:gmatch('"([A-Z-][A-Z-][A-Z-])"') do
|
|
| 88 |
+ byte_to_opcode[byte] = opcode |
|
| 89 |
+ byte = byte + 1 |
|
| 90 |
+ end |
|
| 91 |
+ end |
|
| 92 |
+ end |
|
| 93 |
+ local order_to_opcode |
|
| 94 |
+ do |
|
| 95 |
+ local _accum_0 = { }
|
|
| 96 |
+ local _len_0 = 1 |
|
| 97 |
+ for i = 0, #byte_to_opcode do |
|
| 98 |
+ if byte_to_opcode[i] ~= '---' then |
|
| 99 |
+ _accum_0[_len_0] = byte_to_opcode[i] |
|
| 100 |
+ _len_0 = _len_0 + 1 |
|
| 101 |
+ end |
|
| 102 |
+ end |
|
| 103 |
+ order_to_opcode = _accum_0 |
|
| 104 |
+ end |
|
| 105 |
+ table.sort(order_to_opcode) |
|
| 106 |
+ local root, opcode_to_links = build_dag(order_to_opcode) |
|
| 107 |
+ write_opcode_tree = function(f) |
|
| 108 |
+ for i = 0, #byte_to_opcode do |
|
| 109 |
+ local opcode = byte_to_opcode[i] |
|
| 110 |
+ f:write('\t')
|
|
| 111 |
+ if opcode == root then |
|
| 112 |
+ f:write('$root ')
|
|
| 113 |
+ elseif opcode ~= '---' then |
|
| 114 |
+ f:write(('$op-%s '):format(opcode:lower()))
|
|
| 115 |
+ else |
|
| 116 |
+ f:write(' ')
|
|
| 117 |
+ end |
|
| 118 |
+ for j = 1, 2 do |
|
| 119 |
+ if opcode ~= '---' and opcode_to_links[opcode][j] then |
|
| 120 |
+ f:write(('.$op-%s '):format(opcode_to_links[opcode][j]:lower()))
|
|
| 121 |
+ else |
|
| 122 |
+ f:write('[ 0000 ] ')
|
|
| 123 |
+ end |
|
| 124 |
+ end |
|
| 125 |
+ if i == 0 then |
|
| 126 |
+ f:write('$disasm ')
|
|
| 127 |
+ else |
|
| 128 |
+ f:write(' ')
|
|
| 129 |
+ end |
|
| 130 |
+ if opcode ~= '---' then |
|
| 131 |
+ f:write(('[ %s ]'):format(opcode))
|
|
| 132 |
+ else |
|
| 133 |
+ f:write('[ ??? ]')
|
|
| 134 |
+ end |
|
| 135 |
+ if i == 0 then |
|
| 136 |
+ f:write(' $asm')
|
|
| 137 |
+ end |
|
| 138 |
+ f:write('\n')
|
|
| 139 |
+ end |
|
| 140 |
+ end |
|
| 141 |
+end |
|
| 142 |
+local type_byte |
|
| 143 |
+type_byte = function(size, has_subtree) |
|
| 144 |
+ local n1 = has_subtree and '8' or '0' |
|
| 145 |
+ local n2 |
|
| 146 |
+ local _exp_0 = size |
|
| 147 |
+ if '1' == _exp_0 then |
|
| 148 |
+ n2 = '1' |
|
| 149 |
+ elseif '2' == _exp_0 then |
|
| 150 |
+ n2 = '3' |
|
| 151 |
+ else |
|
| 152 |
+ n2 = '0' |
|
| 153 |
+ end |
|
| 154 |
+ return n1 .. n2 |
|
| 155 |
+end |
|
| 156 |
+local globals = { }
|
|
| 157 |
+local add_globals |
|
| 158 |
+add_globals = function(root, dag, key_to_label, key_to_contents, pad_before, pad_after) |
|
| 159 |
+ if pad_before == nil then |
|
| 160 |
+ pad_before = '' |
|
| 161 |
+ end |
|
| 162 |
+ if pad_after == nil then |
|
| 163 |
+ pad_after = '' |
|
| 164 |
+ end |
|
| 165 |
+ for k in pairs(dag) do |
|
| 166 |
+ local l = '' |
|
| 167 |
+ if k == root then |
|
| 168 |
+ l = l .. ('@%s\n'):format(key_to_label('root'):gsub('%s', ''))
|
|
| 169 |
+ end |
|
| 170 |
+ l = l .. ('@%s '):format(key_to_label(k))
|
|
| 171 |
+ for j = 1, 2 do |
|
| 172 |
+ if dag[k][j] then |
|
| 173 |
+ l = l .. ('.%s '):format(key_to_label(dag[k][j]))
|
|
| 174 |
+ else |
|
| 175 |
+ l = l .. ('%s[ 0000 ]%s '):format(pad_before, pad_after)
|
|
| 176 |
+ end |
|
| 177 |
+ end |
|
| 178 |
+ l = l .. key_to_contents(k) |
|
| 179 |
+ l = l .. '\n' |
|
| 180 |
+ globals[key_to_label(k):gsub('%s', '')] = l
|
|
| 181 |
+ end |
|
| 182 |
+ globals[key_to_label('root'):gsub('%s', '')] = ''
|
|
| 183 |
+end |
|
| 184 |
+do |
|
| 185 |
+ local root, dag = build_dag_from_chars('{}[]%@$;|=~,.^#"\0', '(', ')')
|
|
| 186 |
+ check_terminals(dag, ')') |
|
| 187 |
+ local convert = {
|
|
| 188 |
+ ['.'] = 'dot', |
|
| 189 |
+ ['\0'] = 'nul' |
|
| 190 |
+ } |
|
| 191 |
+ local label_name |
|
| 192 |
+ label_name = function(s) |
|
| 193 |
+ return ('first-char-%-3s'):format(convert[s] or s)
|
|
| 194 |
+ end |
|
| 195 |
+ local label_value |
|
| 196 |
+ label_value = function(k) |
|
| 197 |
+ return ('[ %02x ]'):format(k:byte())
|
|
| 198 |
+ end |
|
| 199 |
+ add_globals(root, dag, label_name, label_value, ' ', ' ') |
|
| 200 |
+end |
|
| 201 |
+local devices = { }
|
|
| 202 |
+local add_device |
|
| 203 |
+add_device = function(name, fields) |
|
| 204 |
+ local field_sizes |
|
| 205 |
+ do |
|
| 206 |
+ local _tbl_0 = { }
|
|
| 207 |
+ for k, size in fields:gmatch('(%S+) (%d+)') do
|
|
| 208 |
+ _tbl_0[k] = size |
|
| 209 |
+ end |
|
| 210 |
+ field_sizes = _tbl_0 |
|
| 211 |
+ end |
|
| 212 |
+ field_sizes.pad = nil |
|
| 213 |
+ local field_names |
|
| 214 |
+ do |
|
| 215 |
+ local _accum_0 = { }
|
|
| 216 |
+ local _len_0 = 1 |
|
| 217 |
+ for k in pairs(field_sizes) do |
|
| 218 |
+ _accum_0[_len_0] = k |
|
| 219 |
+ _len_0 = _len_0 + 1 |
|
| 220 |
+ end |
|
| 221 |
+ field_names = _accum_0 |
|
| 222 |
+ end |
|
| 223 |
+ table.sort(field_names) |
|
| 224 |
+ local root, dag = build_dag(field_names) |
|
| 225 |
+ local label_name |
|
| 226 |
+ label_name = function(k) |
|
| 227 |
+ return ('l-%-14s'):format(name .. '-' .. k)
|
|
| 228 |
+ end |
|
| 229 |
+ local label_value |
|
| 230 |
+ label_value = function(k) |
|
| 231 |
+ return ('%-17s [ %s ] .%s.%s'):format(('[ %s 00 ]'):format(k), type_byte(field_sizes[k], false), name, k)
|
|
| 232 |
+ end |
|
| 233 |
+ add_globals(root, dag, label_name, label_value, ' ', ' ') |
|
| 234 |
+ return table.insert(devices, name) |
|
| 235 |
+end |
|
| 236 |
+local add_devices |
|
| 237 |
+add_devices = function() |
|
| 238 |
+ table.sort(devices) |
|
| 239 |
+ local root, dag = build_dag(devices) |
|
| 240 |
+ local label_name |
|
| 241 |
+ label_name = function(k) |
|
| 242 |
+ return ('l-%-14s'):format(k)
|
|
| 243 |
+ end |
|
| 244 |
+ local label_value |
|
| 245 |
+ label_value = function(k) |
|
| 246 |
+ return ('%-17s [ %s ] .%s .l-%s-root'):format(('[ %s 00 ]'):format(k), type_byte(0, true), k, k)
|
|
| 247 |
+ end |
|
| 248 |
+ return add_globals(root, dag, label_name, label_value, ' ', ' ') |
|
| 249 |
+end |
|
| 250 |
+local filename = 'projects/software/assembler.usm' |
|
| 251 |
+local f = assert(io.open(('%s.tmp'):format(filename), 'w'))
|
|
| 252 |
+local state = 'normal' |
|
| 253 |
+local machine = {
|
|
| 254 |
+ normal = function(l) |
|
| 255 |
+ if l:match('%$disasm .*%$asm') then
|
|
| 256 |
+ write_opcode_tree(f) |
|
| 257 |
+ state = 'opcode' |
|
| 258 |
+ elseif l:match('^%@') then
|
|
| 259 |
+ if l == '@RESET' then |
|
| 260 |
+ add_devices() |
|
| 261 |
+ end |
|
| 262 |
+ for k in l:gmatch('%@(%S+)') do
|
|
| 263 |
+ if globals[k] then |
|
| 264 |
+ f:write(globals[k]) |
|
| 265 |
+ globals[k] = nil |
|
| 266 |
+ return |
|
| 267 |
+ end |
|
| 268 |
+ end |
|
| 269 |
+ f:write(l) |
|
| 270 |
+ return f:write('\n')
|
|
| 271 |
+ else |
|
| 272 |
+ if l:match('^%|%x%x%x%x %;') then
|
|
| 273 |
+ add_device(l:match('%;(%S+) %{ (.*) %}'))
|
|
| 274 |
+ end |
|
| 275 |
+ f:write(l) |
|
| 276 |
+ return f:write('\n')
|
|
| 277 |
+ end |
|
| 278 |
+ end, |
|
| 279 |
+ opcode = function(l) |
|
| 280 |
+ if not l:match('%[') then
|
|
| 281 |
+ f:write(l) |
|
| 282 |
+ f:write('\n')
|
|
| 283 |
+ state = 'normal' |
|
| 284 |
+ end |
|
| 285 |
+ end |
|
| 286 |
+} |
|
| 287 |
+for l in assert(io.lines(filename)) do |
|
| 288 |
+ machine[state](l) |
|
| 289 |
+end |
|
| 290 |
+for _, l in pairs(globals) do |
|
| 291 |
+ f:write(l) |
|
| 292 |
+end |
|
| 293 |
+f:close() |
|
| 294 |
+assert(0 == os.execute(('mv %s %s.bak'):format(filename, filename)))
|
|
| 295 |
+return assert(0 == os.execute(('mv %s.tmp %s'):format(filename, filename)))
|
| 0 | 296 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,180 @@ |
| 1 |
+build_dag = (t, dag = {}, i = 1, j = #t, level = 0) ->
|
|
| 2 |
+ if i > j |
|
| 3 |
+ return |
|
| 4 |
+ mid = math.floor (i + j) / 2 |
|
| 5 |
+ dag[t[mid]] = {
|
|
| 6 |
+ (build_dag t, dag, i, mid - 1, level + 1) |
|
| 7 |
+ (build_dag t, dag, mid + 1, j, level + 1) |
|
| 8 |
+ } |
|
| 9 |
+ t[mid], dag |
|
| 10 |
+append_dag = (node, dag, k) -> |
|
| 11 |
+ i = k > node and 2 or 1 |
|
| 12 |
+ next_node = dag[node][i] |
|
| 13 |
+ if next_node |
|
| 14 |
+ return append_dag next_node, dag, k |
|
| 15 |
+ dag[node][i] = k |
|
| 16 |
+ dag[k] = {}
|
|
| 17 |
+build_dag_from_chars = (s, ...) -> |
|
| 18 |
+ t = [ s\sub i, i for i = 1, #s ] |
|
| 19 |
+ table.sort t |
|
| 20 |
+ root, dag = build_dag t |
|
| 21 |
+ for i = 1, select '#', ... |
|
| 22 |
+ append_dag root, dag, (select i, ...) |
|
| 23 |
+ return root, dag |
|
| 24 |
+check_terminals = (dag, s) -> |
|
| 25 |
+ for i = 1, #s |
|
| 26 |
+ k = s\sub i, i |
|
| 27 |
+ assert not dag[k][1], '%s has left child node'\format k |
|
| 28 |
+ assert not dag[k][2], '%s has right child node'\format k |
|
| 29 |
+dump = (f, root, dag, level = 0) -> |
|
| 30 |
+ if dag[root][1] |
|
| 31 |
+ dump f, dag[root][1], dag, level + 1 |
|
| 32 |
+ f\write ' '\rep level |
|
| 33 |
+ f\write root |
|
| 34 |
+ f\write '\n' |
|
| 35 |
+ if dag[root][2] |
|
| 36 |
+ dump f, dag[root][2], dag, level + 1 |
|
| 37 |
+ |
|
| 38 |
+-- deal with opcodes |
|
| 39 |
+ |
|
| 40 |
+write_opcode_tree = do |
|
| 41 |
+ byte_to_opcode = {}
|
|
| 42 |
+ byte = false |
|
| 43 |
+ for l in assert io.lines 'src/assembler.c' |
|
| 44 |
+ if l\match '^%s*char%s+ops%[%]%[4%]' |
|
| 45 |
+ byte = 0 |
|
| 46 |
+ elseif l\match '%}' |
|
| 47 |
+ byte = false |
|
| 48 |
+ elseif byte |
|
| 49 |
+ for opcode in l\gmatch '"([A-Z-][A-Z-][A-Z-])"' |
|
| 50 |
+ byte_to_opcode[byte] = opcode |
|
| 51 |
+ byte += 1 |
|
| 52 |
+ order_to_opcode = [ byte_to_opcode[i] for i = 0, #byte_to_opcode when byte_to_opcode[i] != '---' ] |
|
| 53 |
+ table.sort order_to_opcode |
|
| 54 |
+ root, opcode_to_links = build_dag order_to_opcode |
|
| 55 |
+ (f) -> |
|
| 56 |
+ for i = 0, #byte_to_opcode |
|
| 57 |
+ opcode = byte_to_opcode[i] |
|
| 58 |
+ f\write '\t' |
|
| 59 |
+ if opcode == root |
|
| 60 |
+ f\write '$root ' |
|
| 61 |
+ elseif opcode != '---' |
|
| 62 |
+ f\write '$op-%s '\format opcode\lower! |
|
| 63 |
+ else |
|
| 64 |
+ f\write ' ' |
|
| 65 |
+ for j = 1, 2 |
|
| 66 |
+ if opcode != '---' and opcode_to_links[opcode][j] |
|
| 67 |
+ f\write '.$op-%s '\format opcode_to_links[opcode][j]\lower! |
|
| 68 |
+ else |
|
| 69 |
+ f\write '[ 0000 ] ' |
|
| 70 |
+ if i == 0 |
|
| 71 |
+ f\write '$disasm ' |
|
| 72 |
+ else |
|
| 73 |
+ f\write ' ' |
|
| 74 |
+ if opcode != '---' |
|
| 75 |
+ f\write '[ %s ]'\format opcode |
|
| 76 |
+ else |
|
| 77 |
+ f\write '[ ??? ]' |
|
| 78 |
+ if i == 0 |
|
| 79 |
+ f\write ' $asm' |
|
| 80 |
+ f\write '\n' |
|
| 81 |
+ |
|
| 82 |
+type_byte = (size, has_subtree) -> |
|
| 83 |
+ n1 = has_subtree and '8' or '0' |
|
| 84 |
+ n2 = switch size |
|
| 85 |
+ when '1' |
|
| 86 |
+ '1' |
|
| 87 |
+ when '2' |
|
| 88 |
+ '3' |
|
| 89 |
+ else |
|
| 90 |
+ '0' |
|
| 91 |
+ n1 .. n2 |
|
| 92 |
+ |
|
| 93 |
+globals = {}
|
|
| 94 |
+ |
|
| 95 |
+add_globals = (root, dag, key_to_label, key_to_contents, pad_before = '', pad_after = '') -> |
|
| 96 |
+ for k in pairs dag |
|
| 97 |
+ l = '' |
|
| 98 |
+ if k == root |
|
| 99 |
+ l ..= '@%s\n'\format key_to_label('root')\gsub '%s', ''
|
|
| 100 |
+ l ..= '@%s '\format key_to_label k |
|
| 101 |
+ for j = 1, 2 |
|
| 102 |
+ if dag[k][j] |
|
| 103 |
+ l ..= '.%s '\format key_to_label dag[k][j] |
|
| 104 |
+ else |
|
| 105 |
+ l ..= '%s[ 0000 ]%s '\format pad_before, pad_after |
|
| 106 |
+ l ..= key_to_contents k |
|
| 107 |
+ l ..= '\n' |
|
| 108 |
+ globals[key_to_label(k)\gsub '%s', ''] = l |
|
| 109 |
+ globals[key_to_label('root')\gsub '%s', ''] = ''
|
|
| 110 |
+ |
|
| 111 |
+do |
|
| 112 |
+ root, dag = build_dag_from_chars '{}[]%@$;|=~,.^#"\0', '(', ')'
|
|
| 113 |
+ check_terminals dag, ')' |
|
| 114 |
+-- dump io.stdout, root, dag |
|
| 115 |
+ convert = {
|
|
| 116 |
+ ['.']: 'dot' |
|
| 117 |
+ ['\0']: 'nul' |
|
| 118 |
+ } |
|
| 119 |
+ label_name = (s) -> 'first-char-%-3s'\format convert[s] or s |
|
| 120 |
+ label_value = (k) -> '[ %02x ]'\format k\byte! |
|
| 121 |
+ add_globals root, dag, label_name, label_value, ' ', ' ' |
|
| 122 |
+ |
|
| 123 |
+devices = {}
|
|
| 124 |
+ |
|
| 125 |
+add_device = (name, fields) -> |
|
| 126 |
+ field_sizes = { k, size for k, size in fields\gmatch '(%S+) (%d+)' }
|
|
| 127 |
+ field_sizes.pad = nil |
|
| 128 |
+ field_names = [ k for k in pairs field_sizes ] |
|
| 129 |
+ table.sort field_names |
|
| 130 |
+ root, dag = build_dag field_names |
|
| 131 |
+ label_name = (k) -> 'l-%-14s'\format name .. '-' .. k |
|
| 132 |
+ label_value = (k) -> '%-17s [ %s ] .%s.%s'\format '[ %s 00 ]'\format(k), type_byte(field_sizes[k], false), name, k |
|
| 133 |
+ add_globals root, dag, label_name, label_value, ' ', ' ' |
|
| 134 |
+ table.insert devices, name |
|
| 135 |
+ |
|
| 136 |
+add_devices = -> |
|
| 137 |
+ table.sort devices |
|
| 138 |
+ root, dag = build_dag devices |
|
| 139 |
+ label_name = (k) -> 'l-%-14s'\format k |
|
| 140 |
+ label_value = (k) -> '%-17s [ %s ] .%s .l-%s-root'\format '[ %s 00 ]'\format(k), type_byte(0, true), k, k |
|
| 141 |
+ add_globals root, dag, label_name, label_value, ' ', ' ' |
|
| 142 |
+ |
|
| 143 |
+filename = 'projects/software/assembler.usm' |
|
| 144 |
+ |
|
| 145 |
+f = assert io.open '%s.tmp'\format(filename), 'w' |
|
| 146 |
+-- f = io.stdout |
|
| 147 |
+state = 'normal' |
|
| 148 |
+machine = |
|
| 149 |
+ normal: (l) -> |
|
| 150 |
+ if l\match '%$disasm .*%$asm' |
|
| 151 |
+ write_opcode_tree f |
|
| 152 |
+ state = 'opcode' |
|
| 153 |
+ elseif l\match '^%@' |
|
| 154 |
+ if l == '@RESET' |
|
| 155 |
+ add_devices! |
|
| 156 |
+ for k in l\gmatch '%@(%S+)' |
|
| 157 |
+ if globals[k] |
|
| 158 |
+ f\write globals[k] |
|
| 159 |
+ globals[k] = nil |
|
| 160 |
+ return |
|
| 161 |
+ f\write l |
|
| 162 |
+ f\write '\n' |
|
| 163 |
+ else |
|
| 164 |
+ if l\match '^%|%x%x%x%x %;' |
|
| 165 |
+ add_device l\match '%;(%S+) %{ (.*) %}'
|
|
| 166 |
+ f\write l |
|
| 167 |
+ f\write '\n' |
|
| 168 |
+ opcode: (l) -> |
|
| 169 |
+ if not l\match '%[' |
|
| 170 |
+ f\write l |
|
| 171 |
+ f\write '\n' |
|
| 172 |
+ state = 'normal' |
|
| 173 |
+for l in assert io.lines filename |
|
| 174 |
+ machine[state] l |
|
| 175 |
+for _, l in pairs globals |
|
| 176 |
+ f\write l |
|
| 177 |
+f\close! |
|
| 178 |
+assert 0 == os.execute 'mv %s %s.bak'\format filename, filename |
|
| 179 |
+assert 0 == os.execute 'mv %s.tmp %s'\format filename, filename |
|
| 180 |
+ |
| 0 | 181 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,465 @@ |
| 1 |
+;tree { search-key 2 max-key-len 1 }
|
|
| 2 |
+;assembler { pass 1 state 1 token 2 scope-len 1 scope 80 }
|
|
| 3 |
+ |
|
| 4 |
+%HCF { #0000 DIV }
|
|
| 5 |
+ |
|
| 6 |
+( devices ) |
|
| 7 |
+ |
|
| 8 |
+|0100 ;Console { pad 8 char 1 byte 1 short 2 string 2 }
|
|
| 9 |
+|0110 ;Screen { width 2 height 2 pad 4 x 2 y 2 color 1 }
|
|
| 10 |
+|0120 ;Sprite { pad 8 x 2 y 2 addr 2 color 1 }
|
|
| 11 |
+|0130 ;Controller { p1 1 }
|
|
| 12 |
+|0140 ;Keys { key 1 }
|
|
| 13 |
+|0150 ;Mouse { x 2 y 2 state 1 chord 1 }
|
|
| 14 |
+|0160 ;File { pad 8 name 2 length 2 load 2 save 2 }
|
|
| 15 |
+|01F0 ;System { pad 8 r 2 g 2 b 2 }
|
|
| 16 |
+ |
|
| 17 |
+( vectors ) |
|
| 18 |
+ |
|
| 19 |
+|0200 ,RESET JMP2 |
|
| 20 |
+|0204 BRK |
|
| 21 |
+|0208 BRK |
|
| 22 |
+ |
|
| 23 |
+@RESET |
|
| 24 |
+ #b000 #c000 #0010 ,memcpy JSR2 |
|
| 25 |
+ HCF |
|
| 26 |
+ |
|
| 27 |
+ ,$token ,strlen JSR2 |
|
| 28 |
+ HCF |
|
| 29 |
+ |
|
| 30 |
+ #00 |
|
| 31 |
+ $loop |
|
| 32 |
+ DUP ,highest-bit JSR2 |
|
| 33 |
+ ( ) |
|
| 34 |
+ POP |
|
| 35 |
+ #01 ADD |
|
| 36 |
+ DUP ^$loop JNZ |
|
| 37 |
+ POP |
|
| 38 |
+ |
|
| 39 |
+ |
|
| 40 |
+ ,$token ^assemble-token JSR |
|
| 41 |
+ ,$token2 ^assemble-token JSR |
|
| 42 |
+ ,$token3 ^assemble-token JSR |
|
| 43 |
+ ~assembler.state |
|
| 44 |
+ HCF |
|
| 45 |
+ |
|
| 46 |
+ $token [ hello 00 ] |
|
| 47 |
+ $token2 [ 00 ] |
|
| 48 |
+ $token3 [ 00 ] |
|
| 49 |
+ |
|
| 50 |
+@assemble-tokens ( string-ptr* -- ) |
|
| 51 |
+ DUP2 ^assemble-token JSR |
|
| 52 |
+ |
|
| 53 |
+@assemble-token ( string-ptr* -- ) |
|
| 54 |
+ ( get location of tree ) |
|
| 55 |
+ DUP2 |
|
| 56 |
+ ,state-machine-pointers #00 ~assembler.state ,highest-bit JSR2 #0004 MUL2 ADD2 |
|
| 57 |
+ DUP2 STH2 |
|
| 58 |
+ ( see if first char is recognised ) |
|
| 59 |
+ SWP2 #01 ,traverse-tree JSR2 |
|
| 60 |
+ ^$not-found JNZ |
|
| 61 |
+ ( skip first character of token ) |
|
| 62 |
+ SWP2 #0001 ADD2 =assembler.token |
|
| 63 |
+ ( tail call handling function defined in tree ) |
|
| 64 |
+ POP2r JMP2 |
|
| 65 |
+ |
|
| 66 |
+ $not-found |
|
| 67 |
+ ( not interested in incoming-ptr ) |
|
| 68 |
+ POP2 |
|
| 69 |
+ =assembler.token |
|
| 70 |
+ ( tail call default handling function defined in state-machine-pointers ) |
|
| 71 |
+ LIT2r [ 0002 ] ADD2r LDR2r |
|
| 72 |
+ JMP2r |
|
| 73 |
+ |
|
| 74 |
+@parse-hex-length ( string-ptr* -- value 01 if one or two hex digits |
|
| 75 |
+ OR 00 otherwise ) |
|
| 76 |
+ DUP2 #0001 ADD2 PEK2 ^parse-hex-string-try-two JNZ |
|
| 77 |
+ PEK2 ^parse-hex-digit JSR DUP #04 SFT ^parse-hex-string-fail1 JNZ |
|
| 78 |
+ #01 JMP2r |
|
| 79 |
+ |
|
| 80 |
+@parse-hex-string ( string-ptr* -- value* 02 if four hex digits |
|
| 81 |
+ OR value 01 if two hex digits |
|
| 82 |
+ OR 00 otherwise ) |
|
| 83 |
+ DUP2 #0004 ADD2 PEK2 #00 EQU ^$try-four JNZ |
|
| 84 |
+ $try-two |
|
| 85 |
+ DUP2 #0002 ADD2 PEK2 ^$fail2 JNZ |
|
| 86 |
+ $known-two |
|
| 87 |
+ DUP2 PEK2 ^parse-hex-digit JSR DUP #04 SFT ^$fail3 JNZ ROT ROT |
|
| 88 |
+ #0001 ADD2 PEK2 ^parse-hex-digit JSR DUP #04 SFT ^$fail2 JNZ |
|
| 89 |
+ SWP #40 SFT ORA #01 JMP2r |
|
| 90 |
+ |
|
| 91 |
+ $fail3 POP |
|
| 92 |
+ $fail2 POP |
|
| 93 |
+ $fail1 POP #00 JMP2r |
|
| 94 |
+ |
|
| 95 |
+ $try-four |
|
| 96 |
+ DUP2 #0002 ADD2 ^$known-two JSR ^$maybe-four JNZ |
|
| 97 |
+ ^$try-two JMP |
|
| 98 |
+ |
|
| 99 |
+ $maybe-four |
|
| 100 |
+ ROT ROT ^$known-two JSR ^$four JNZ |
|
| 101 |
+ ^$fail1 JMP |
|
| 102 |
+ |
|
| 103 |
+ $four |
|
| 104 |
+ SWP #02 JMP2r |
|
| 105 |
+ |
|
| 106 |
+@parse-hex-digit ( charcode -- 00-0f if valid hex |
|
| 107 |
+ -- 10-ff otherwise ) |
|
| 108 |
+ DUP #3a LTH ^$digit JNZ |
|
| 109 |
+ DUP #60 GTH ^$lowercase JNZ |
|
| 110 |
+ DUP #40 GTH ^$uppercase JNZ |
|
| 111 |
+ JMP2r |
|
| 112 |
+ |
|
| 113 |
+ $digit ( #30 is #00 ) |
|
| 114 |
+ #30 SUB JMP2r |
|
| 115 |
+ |
|
| 116 |
+ $lowercase ( #61 is #0a ) |
|
| 117 |
+ #57 SUB JMP2r |
|
| 118 |
+ |
|
| 119 |
+ $uppercase ( #41 is #0a ) |
|
| 120 |
+ #37 SUB JMP2r |
|
| 121 |
+ |
|
| 122 |
+@find-opcode ( name* -- byte 00 if valid opcode name |
|
| 123 |
+ OR 01 if not found ) |
|
| 124 |
+ ,opcodes-tree SWP2 #03 ^traverse-tree JSR |
|
| 125 |
+ ^$nomatch JNZ |
|
| 126 |
+ ,opcodes-asm SUB2 #0007 DIV2 |
|
| 127 |
+ SWP JMP2r |
|
| 128 |
+ |
|
| 129 |
+ $nomatch |
|
| 130 |
+ DUP2 EQU2 JMP2r |
|
| 131 |
+ |
|
| 132 |
+@traverse-tree ( tree-ptr* search-key* max-key-len -- |
|
| 133 |
+ binary-ptr* 00 if key matched |
|
| 134 |
+ OR incoming-ptr* 01 if key not found ) |
|
| 135 |
+ =tree.max-key-len =tree.search-key |
|
| 136 |
+ |
|
| 137 |
+ $loop |
|
| 138 |
+ DUP2 LDR2 #0000 NEQ2 ^$valid-node JNZ |
|
| 139 |
+ #01 JMP2r |
|
| 140 |
+ |
|
| 141 |
+ $valid-node |
|
| 142 |
+ LDR2 DUP2 STH2 #0004 ADD2 ^strcmp-tree JSR |
|
| 143 |
+ DUP ^$nomatch JNZ |
|
| 144 |
+ POP2r JMP2r |
|
| 145 |
+ |
|
| 146 |
+ $nomatch |
|
| 147 |
+ #07 SFT #02 MUL #00 SWP |
|
| 148 |
+ STH2r ADD2 |
|
| 149 |
+ ^$loop JMP |
|
| 150 |
+ |
|
| 151 |
+@strcmp-tree ( node-key* -- order if strings differ |
|
| 152 |
+ OR after-node-key* 00 if strings match ) |
|
| 153 |
+ ~tree.search-key STH2 |
|
| 154 |
+ ~tree.max-key-len |
|
| 155 |
+ |
|
| 156 |
+ $loop ( node-key* key-len in wst, search-key* in rst ) |
|
| 157 |
+ DUP ^$keep-going JNZ |
|
| 158 |
+ |
|
| 159 |
+ ( exhausted key-len, match found ) |
|
| 160 |
+ POP2r |
|
| 161 |
+ JMP2r |
|
| 162 |
+ |
|
| 163 |
+ $keep-going |
|
| 164 |
+ #01 OVR2 PEK2 DUP2r PEK2r STHr |
|
| 165 |
+ DUP2 ORA ^$not-end JNZ |
|
| 166 |
+ |
|
| 167 |
+ ( end of C strings, match found ) |
|
| 168 |
+ POP2r POP ROT POP SWP ADD2 #00 |
|
| 169 |
+ JMP2r |
|
| 170 |
+ |
|
| 171 |
+ $not-end |
|
| 172 |
+ SUB DUP ^$nomatch JNZ |
|
| 173 |
+ POP SUB |
|
| 174 |
+ LIT2r [ 0001 ] ADD2r STH |
|
| 175 |
+ LIT2 [ 0001 ] ADD2 STHr |
|
| 176 |
+ ^$loop JMP |
|
| 177 |
+ |
|
| 178 |
+ $nomatch |
|
| 179 |
+ STH POP2 POP2 STHr POP2r |
|
| 180 |
+ JMP2r |
|
| 181 |
+ |
|
| 182 |
+@memcpy ( src-ptr* dest-ptr* length* -- ) |
|
| 183 |
+ SWP2 STH2 |
|
| 184 |
+ |
|
| 185 |
+ $loop |
|
| 186 |
+ DUP2 ORA ^$keep-going JNZ |
|
| 187 |
+ POP2 POP2 POP2r |
|
| 188 |
+ JMP2r |
|
| 189 |
+ |
|
| 190 |
+ $keep-going |
|
| 191 |
+ #0001 SUB2 |
|
| 192 |
+ SWP2 DUP2 PEK2 DUP2r STH2r POK2 |
|
| 193 |
+ #0001 ADD2 SWP2 |
|
| 194 |
+ LIT2r [ 0001 ] ADD2r |
|
| 195 |
+ ^$loop JMP |
|
| 196 |
+ |
|
| 197 |
+@strlen ( string-ptr* -- length* ) |
|
| 198 |
+ DUP2 #0001 SUB2 |
|
| 199 |
+ $loop |
|
| 200 |
+ #0001 ADD2 |
|
| 201 |
+ DUP2 PEK2 ^$loop JNZ |
|
| 202 |
+ SWP2 SUB2 |
|
| 203 |
+ JMP2r |
|
| 204 |
+ |
|
| 205 |
+ |
|
| 206 |
+ |
|
| 207 |
+ |
|
| 208 |
+@add-label ( string-ptr* label-flags -- ) |
|
| 209 |
+ ( NYI ) |
|
| 210 |
+ POP POP2 JMP2r |
|
| 211 |
+ |
|
| 212 |
+@highest-bit ( n -- 00 if n is 00 |
|
| 213 |
+ OR 01 if n is 01 |
|
| 214 |
+ OR 02 if n is 02..03 |
|
| 215 |
+ OR 03 if n is 04..07 |
|
| 216 |
+ OR 04 if n is 08..0f |
|
| 217 |
+ .. |
|
| 218 |
+ OR 08 if n is 80..ff ) |
|
| 219 |
+ DUP #00 NEQ JMP JMP2r |
|
| 220 |
+ DUP #01 SFT ORA |
|
| 221 |
+ DUP #02 SFT ORA |
|
| 222 |
+ DUP #04 SFT ORA |
|
| 223 |
+ #1d MUL #05 SFT #00 SWP ,$lookup ADD2 PEK2 |
|
| 224 |
+ JMP2r |
|
| 225 |
+ |
|
| 226 |
+ $lookup |
|
| 227 |
+ [ 01 06 02 07 05 04 03 08 ] |
|
| 228 |
+ |
|
| 229 |
+@opcodes |
|
| 230 |
+ ( |
|
| 231 |
+ The code for this section is automatically generated, and needs to be |
|
| 232 |
+ regenerated when the opcode list in src/assembler.c is updated. |
|
| 233 |
+ |
|
| 234 |
+ After editing src/assembler.c, run "lua etc/assembler-trees.lua" |
|
| 235 |
+ and this file will be edited automatically. |
|
| 236 |
+ |
|
| 237 |
+ This is the first example of a binary tree in this code, so let's |
|
| 238 |
+ explore them in general. The format of a tree node in memory is: |
|
| 239 |
+ |
|
| 240 |
+ left-node* right-node* node-key-cstring binary-data |
|
| 241 |
+ |
|
| 242 |
+ and the general algorithm is to compare the key you're looking for |
|
| 243 |
+ against node-key-cstring, and move to the node pointed to by left-node* |
|
| 244 |
+ or right-node* if the keys don't match. If your key sorts earlier than |
|
| 245 |
+ use left-node*, otherwise go to right-node*. When you find a node that |
|
| 246 |
+ matches your key, traverse-bintree gives you a pointer to the |
|
| 247 |
+ binary-data straight after the node-key-cstring. This data can contain |
|
| 248 |
+ anything you want: fixed length fields, executable code... in this case |
|
| 249 |
+ of this opcode tree, we store nothing. traverse-bintree is passed the |
|
| 250 |
+ maximum length of node-key-cstring, not including the zero, so the zero |
|
| 251 |
+ can be omitted if the string is at that maximum length. |
|
| 252 |
+ |
|
| 253 |
+ If the key isn't present in the tree, you'll eventually get to a node |
|
| 254 |
+ where the left-node* or right-node* pointer you'll need to follow is |
|
| 255 |
+ null (0000). traverse-bintree will give you the location of that |
|
| 256 |
+ pointer, so if you want to insert another node, you can write it to the |
|
| 257 |
+ heap and overwrite the pointer with the new node's location. This |
|
| 258 |
+ approach works even if the tree is completely empty and the pointer |
|
| 259 |
+ you've provided to the root node is null, since that pointer gets |
|
| 260 |
+ updated to point to the first node without needing any special logic. |
|
| 261 |
+ |
|
| 262 |
+ The ordering of nodes in memory is totally arbitrary, so for pre- |
|
| 263 |
+ prepared trees like this one we can have our own meaning for the order |
|
| 264 |
+ of the nodes. By ordering the opcodes by their byte value, we can find |
|
| 265 |
+ the byte by subtracting $asm from the binary-data pointer and dividing |
|
| 266 |
+ by seven (the size of each node). By multiplying the byte value by seven |
|
| 267 |
+ and adding to $disasm, we get the opcode name when disassembling too. |
|
| 268 |
+ ) |
|
| 269 |
+ $tree .$root |
|
| 270 |
+ $op-brk .$op-add .$op-dup $disasm [ BRK ] $asm |
|
| 271 |
+ $op-nop .$op-mul .$op-ovr [ NOP ] |
|
| 272 |
+ $op-lit [ 0000 ] [ 0000 ] [ LIT ] |
|
| 273 |
+ $op-pop [ 0000 ] [ 0000 ] [ POP ] |
|
| 274 |
+ $op-dup .$op-div .$op-eor [ DUP ] |
|
| 275 |
+ $op-swp [ 0000 ] [ 0000 ] [ SWP ] |
|
| 276 |
+ $op-ovr .$op-ora .$op-pek [ OVR ] |
|
| 277 |
+ $op-rot .$op-pop .$op-sft [ ROT ] |
|
| 278 |
+ $op-equ .$op-brk .$op-jnz [ EQU ] |
|
| 279 |
+ $op-neq [ 0000 ] [ 0000 ] [ NEQ ] |
|
| 280 |
+ $op-gth [ 0000 ] [ 0000 ] [ GTH ] |
|
| 281 |
+ $root .$op-equ .$op-pok [ LTH ] |
|
| 282 |
+ $op-gts .$op-gth .$op-jmp [ GTS ] |
|
| 283 |
+ $op-lts [ 0000 ] [ 0000 ] [ LTS ] |
|
| 284 |
+ [ 0000 ] [ 0000 ] [ ??? ] |
|
| 285 |
+ [ 0000 ] [ 0000 ] [ ??? ] |
|
| 286 |
+ $op-pek [ 0000 ] [ 0000 ] [ PEK ] |
|
| 287 |
+ $op-pok .$op-nop .$op-sth [ POK ] |
|
| 288 |
+ $op-ldr .$op-jsr .$op-lit [ LDR ] |
|
| 289 |
+ $op-str [ 0000 ] [ 0000 ] [ STR ] |
|
| 290 |
+ $op-jmp [ 0000 ] [ 0000 ] [ JMP ] |
|
| 291 |
+ $op-jnz .$op-gts .$op-ldr [ JNZ ] |
|
| 292 |
+ $op-jsr [ 0000 ] [ 0000 ] [ JSR ] |
|
| 293 |
+ $op-sth .$op-rot .$op-sub [ STH ] |
|
| 294 |
+ $op-add [ 0000 ] .$op-and [ ADD ] |
|
| 295 |
+ $op-sub .$op-str .$op-swp [ SUB ] |
|
| 296 |
+ $op-mul .$op-lts .$op-neq [ MUL ] |
|
| 297 |
+ $op-div [ 0000 ] [ 0000 ] [ DIV ] |
|
| 298 |
+ $op-and [ 0000 ] [ 0000 ] [ AND ] |
|
| 299 |
+ $op-ora [ 0000 ] [ 0000 ] [ ORA ] |
|
| 300 |
+ $op-eor [ 0000 ] [ 0000 ] [ EOR ] |
|
| 301 |
+ $op-sft [ 0000 ] [ 0000 ] [ SFT ] |
|
| 302 |
+ |
|
| 303 |
+@state-machine-pointers |
|
| 304 |
+( normal mode 00 ) |
|
| 305 |
+.first-char-root .nyi |
|
| 306 |
+( FIXME 01 ) |
|
| 307 |
+.nyi .nyi |
|
| 308 |
+( FIXME 02 ) |
|
| 309 |
+.nyi .nyi |
|
| 310 |
+( FIXME 04 ) |
|
| 311 |
+.nyi .nyi |
|
| 312 |
+( FIXME 08 ) |
|
| 313 |
+.nyi .nyi |
|
| 314 |
+( FIXME 10 ) |
|
| 315 |
+.nyi .nyi |
|
| 316 |
+( literal data 20 ) |
|
| 317 |
+[ 0000 ] .nyi |
|
| 318 |
+( FIXME 40 ) |
|
| 319 |
+.nyi .nyi |
|
| 320 |
+( comment 80 ) |
|
| 321 |
+.first-char-) .ignore |
|
| 322 |
+ |
|
| 323 |
+( |
|
| 324 |
+ Next up, we have the tree of code corresponding to each token's |
|
| 325 |
+ first character. Here we do have a binary payload, which is |
|
| 326 |
+ the code to run when the assembler considers the token. |
|
| 327 |
+ |
|
| 328 |
+ Some special assembler modes have their own trees. Since comments |
|
| 329 |
+ have a very simple tree that only understands the end of comments, |
|
| 330 |
+ we reuse the terminal branch of the main tree as the root of |
|
| 331 |
+ the comment tree. |
|
| 332 |
+) |
|
| 333 |
+ |
|
| 334 |
+( |
|
| 335 |
+ Left and right parentheses start and end comment sections. They use the |
|
| 336 |
+ highest bit in assembler state, so they receive highest priority: it |
|
| 337 |
+ doesn't matter what other bits are set, a comment's a comment. |
|
| 338 |
+) |
|
| 339 |
+ |
|
| 340 |
+@first-char-( [ 0000 ] .first-char-) [ 28 ] |
|
| 341 |
+ ~assembler.state #80 ORA =assembler.state |
|
| 342 |
+JMP2r |
|
| 343 |
+ |
|
| 344 |
+@first-char-) [ 0000 ] [ 0000 ] [ 29 ] |
|
| 345 |
+ ~assembler.state #7f AND =assembler.state |
|
| 346 |
+JMP2r |
|
| 347 |
+ |
|
| 348 |
+( |
|
| 349 |
+ Left and right square brackets start and end literal data sections. |
|
| 350 |
+) |
|
| 351 |
+ |
|
| 352 |
+@first-char-[ .first-char-@ .first-char-] [ 5b ] |
|
| 353 |
+ ~assembler.state #20 ORA =assembler.state |
|
| 354 |
+JMP2r |
|
| 355 |
+ |
|
| 356 |
+@first-char-] [ 0000 ] [ 0000 ] [ 5d ] |
|
| 357 |
+ ~assembler.state #df AND =assembler.state |
|
| 358 |
+JMP2r |
|
| 359 |
+ |
|
| 360 |
+( |
|
| 361 |
+ Ampersands introduce global labels, and define the scope for any |
|
| 362 |
+ local labels that follow. |
|
| 363 |
+) |
|
| 364 |
+ |
|
| 365 |
+@first-char-@ [ 0000 ] [ 0000 ] [ 40 ] |
|
| 366 |
+ ~assembler.pass ^$scope JNZ |
|
| 367 |
+ DUP2 #00 ,add-label JSR2 |
|
| 368 |
+ |
|
| 369 |
+ $scope |
|
| 370 |
+ DUP2 ,strlen JSR2 |
|
| 371 |
+ DUP2 =assembler.scope-len POP |
|
| 372 |
+ ,assembler.scope SWP2 JMP2 |
|
| 373 |
+ |
|
| 374 |
+@first-char-root |
|
| 375 |
+@first-char-= .first-char-$ .first-char-^ [ 3d ] |
|
| 376 |
+@first-char-" .first-char-nul .first-char-# [ 22 ] |
|
| 377 |
+@first-char-# [ 0000 ] [ 0000 ] [ 23 ] |
|
| 378 |
+@first-char-$ .first-char-" .first-char-, [ 24 ] |
|
| 379 |
+@first-char-% [ 0000 ] .first-char-( [ 25 ] |
|
| 380 |
+@first-char-, .first-char-% .first-char-dot [ 2c ] |
|
| 381 |
+@first-char-dot [ 0000 ] .first-char-; [ 2e ] |
|
| 382 |
+@first-char-; [ 0000 ] [ 0000 ] [ 3b ] |
|
| 383 |
+@first-char-^ .first-char-[ .first-char-| [ 5e ] |
|
| 384 |
+@first-char-{ [ 0000 ] [ 0000 ] [ 7b ]
|
|
| 385 |
+@first-char-| .first-char-{ .first-char-} [ 7c ]
|
|
| 386 |
+@first-char-} [ 0000 ] .first-char-~ [ 7d ] |
|
| 387 |
+@first-char-~ [ 0000 ] [ 0000 ] [ 7e ] |
|
| 388 |
+ |
|
| 389 |
+@first-char-nul [ 0000 ] [ 0000 ] [ 00 ] |
|
| 390 |
+@ignore |
|
| 391 |
+JMP2r |
|
| 392 |
+ |
|
| 393 |
+@nyi |
|
| 394 |
+ ,$string =Console.string |
|
| 395 |
+ HCF |
|
| 396 |
+ |
|
| 397 |
+ $string [ Not 20 implemented 0a 00 ] |
|
| 398 |
+ |
|
| 399 |
+( |
|
| 400 |
+ Here's the big set of trees relating to labels. Starting from l-root, all |
|
| 401 |
+ the devices are stored here, perhaps some helper functions in the future, |
|
| 402 |
+ too. |
|
| 403 |
+ |
|
| 404 |
+ left-node* right-node* node-key-cstring binary-data |
|
| 405 |
+ |
|
| 406 |
+ The node-keys are terminated with NUL since, unlike the opcodes and first |
|
| 407 |
+ characters, the keys are variable length. |
|
| 408 |
+ |
|
| 409 |
+ The binary-data is either three or five bytes long: |
|
| 410 |
+ flags value* [ subtree-pointer* ] |
|
| 411 |
+ |
|
| 412 |
+ The flags byte is divided up into bits: |
|
| 413 |
+ |
|
| 414 |
+ bit 0: 01 means load or store helpers can be used, |
|
| 415 |
+ bit 1: 02 means the helpers use STR/LDR, 00 means they use POK/PEK; |
|
| 416 |
+ bits 2-6 are reserved; and |
|
| 417 |
+ bit 7: 80 means there is a subtree. |
|
| 418 |
+ |
|
| 419 |
+ If there is a subtree, it is searched when the reference contains a dot. |
|
| 420 |
+) |
|
| 421 |
+ |
|
| 422 |
+@l-Console [ 0000 ] [ 0000 ] [ Console 00 ] [ 80 ] .Console .l-Console-root |
|
| 423 |
+@l-Console-byte [ 0000 ] [ 0000 ] [ byte 00 ] [ 01 ] .Console.byte |
|
| 424 |
+@l-Console-root |
|
| 425 |
+@l-Console-char .l-Console-byte .l-Console-short [ char 00 ] [ 01 ] .Console.char |
|
| 426 |
+@l-Console-short [ 0000 ] .l-Console-string [ short 00 ] [ 03 ] .Console.short |
|
| 427 |
+@l-Console-string [ 0000 ] [ 0000 ] [ string 00 ] [ 03 ] .Console.string |
|
| 428 |
+@l-Controller .l-Console .l-File [ Controller 00 ] [ 80 ] .Controller .l-Controller-root |
|
| 429 |
+@l-Controller-root |
|
| 430 |
+@l-Controller-p1 [ 0000 ] [ 0000 ] [ p1 00 ] [ 01 ] .Controller.p1 |
|
| 431 |
+@l-File [ 0000 ] [ 0000 ] [ File 00 ] [ 80 ] .File .l-File-root |
|
| 432 |
+@l-File-length [ 0000 ] [ 0000 ] [ length 00 ] [ 03 ] .File.length |
|
| 433 |
+@l-File-root |
|
| 434 |
+@l-File-load .l-File-length .l-File-name [ load 00 ] [ 03 ] .File.load |
|
| 435 |
+@l-File-name [ 0000 ] .l-File-save [ name 00 ] [ 03 ] .File.name |
|
| 436 |
+@l-File-save [ 0000 ] [ 0000 ] [ save 00 ] [ 03 ] .File.save |
|
| 437 |
+@l-root |
|
| 438 |
+@l-Keys .l-Controller .l-Screen [ Keys 00 ] [ 80 ] .Keys .l-Keys-root |
|
| 439 |
+@l-Keys-root |
|
| 440 |
+@l-Keys-key [ 0000 ] [ 0000 ] [ key 00 ] [ 01 ] .Keys.key |
|
| 441 |
+@l-Mouse [ 0000 ] [ 0000 ] [ Mouse 00 ] [ 80 ] .Mouse .l-Mouse-root |
|
| 442 |
+@l-Mouse-chord [ 0000 ] [ 0000 ] [ chord 00 ] [ 01 ] .Mouse.chord |
|
| 443 |
+@l-Mouse-root |
|
| 444 |
+@l-Mouse-state .l-Mouse-chord .l-Mouse-x [ state 00 ] [ 01 ] .Mouse.state |
|
| 445 |
+@l-Mouse-x [ 0000 ] .l-Mouse-y [ x 00 ] [ 03 ] .Mouse.x |
|
| 446 |
+@l-Mouse-y [ 0000 ] [ 0000 ] [ y 00 ] [ 03 ] .Mouse.y |
|
| 447 |
+@l-Screen .l-Mouse .l-Sprite [ Screen 00 ] [ 80 ] .Screen .l-Screen-root |
|
| 448 |
+@l-Screen-color [ 0000 ] .l-Screen-height [ color 00 ] [ 01 ] .Screen.color |
|
| 449 |
+@l-Screen-height [ 0000 ] [ 0000 ] [ height 00 ] [ 03 ] .Screen.height |
|
| 450 |
+@l-Screen-root |
|
| 451 |
+@l-Screen-width .l-Screen-color .l-Screen-x [ width 00 ] [ 03 ] .Screen.width |
|
| 452 |
+@l-Screen-x [ 0000 ] .l-Screen-y [ x 00 ] [ 03 ] .Screen.x |
|
| 453 |
+@l-Screen-y [ 0000 ] [ 0000 ] [ y 00 ] [ 03 ] .Screen.y |
|
| 454 |
+@l-Sprite [ 0000 ] .l-System [ Sprite 00 ] [ 80 ] .Sprite .l-Sprite-root |
|
| 455 |
+@l-Sprite-addr [ 0000 ] [ 0000 ] [ addr 00 ] [ 03 ] .Sprite.addr |
|
| 456 |
+@l-Sprite-root |
|
| 457 |
+@l-Sprite-color .l-Sprite-addr .l-Sprite-x [ color 00 ] [ 01 ] .Sprite.color |
|
| 458 |
+@l-Sprite-x [ 0000 ] .l-Sprite-y [ x 00 ] [ 03 ] .Sprite.x |
|
| 459 |
+@l-Sprite-y [ 0000 ] [ 0000 ] [ y 00 ] [ 03 ] .Sprite.y |
|
| 460 |
+@l-System [ 0000 ] [ 0000 ] [ System 00 ] [ 80 ] .System .l-System-root |
|
| 461 |
+@l-System-b [ 0000 ] [ 0000 ] [ b 00 ] [ 03 ] .System.b |
|
| 462 |
+@l-System-root |
|
| 463 |
+@l-System-g .l-System-b .l-System-r [ g 00 ] [ 03 ] .System.g |
|
| 464 |
+@l-System-r [ 0000 ] [ 0000 ] [ r 00 ] [ 03 ] .System.r |
|
| 465 |
+ |