mirror of https://git.sr.ht/~rabbits/uxn
30 changed files with 1046 additions and 5179 deletions
@ -1,389 +0,0 @@
|
||||
local generate_labels = false |
||||
local replacements = { |
||||
op_and16 = '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, d & b); push8(u->src, c & a); }', |
||||
op_ora16 = '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, d | b); push8(u->src, c | a); }', |
||||
op_eor16 = '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, d ^ b); push8(u->src, c ^ a); }', |
||||
op_lit16 = '{ push8(u->src, peek8(u->ram.dat, u->ram.ptr++)); push8(u->src, peek8(u->ram.dat, u->ram.ptr++)); }', |
||||
op_swp16 = '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, b); push8(u->src, a); push8(u->src, d); push8(u->src, c); }', |
||||
op_ovr16 = '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, d); push8(u->src, c); push8(u->src, b); push8(u->src, a); push8(u->src, d); push8(u->src, c); }', |
||||
op_dup16 = '{ Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b); push8(u->src, a); push8(u->src, b); push8(u->src, a); }', |
||||
op_rot16 = '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src), e = pop8(u->src), f = pop8(u->src); push8(u->src, d); push8(u->src, c); push8(u->src, b); push8(u->src, a); push8(u->src, f); push8(u->src, e); }', |
||||
op_sth16 = '{ Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->dst, b); push8(u->dst, a); }' |
||||
} |
||||
local top, bottom, pushtop |
||||
local offset |
||||
offset = function(n, s) |
||||
if s == nil then |
||||
s = '' |
||||
end |
||||
if n < 0 then |
||||
return (' -%s %d'):format(s, -n) |
||||
elseif n > 0 then |
||||
return (' +%s %d'):format(s, n) |
||||
elseif s ~= '' then |
||||
return (' +%s 0'):format(s) |
||||
else |
||||
return '' |
||||
end |
||||
end |
||||
local pop_push |
||||
pop_push = function(k, n, s) |
||||
local _exp_0 = k |
||||
if 'pop' == _exp_0 then |
||||
s = s:match('^%((%S+)%)$') |
||||
assert(s == 'src') |
||||
local _exp_1 = n |
||||
if '8' == _exp_1 then |
||||
top[s] = top[s] - 1 |
||||
if bottom[s] > top[s] then |
||||
bottom[s] = top[s] |
||||
end |
||||
return ('%s.dat[%s.ptr%s]'):format(s, s, offset(top[s])) |
||||
elseif '16' == _exp_1 then |
||||
top[s] = top[s] - 2 |
||||
if bottom[s] > top[s] then |
||||
bottom[s] = top[s] |
||||
end |
||||
return ('(%s.dat[%s.ptr%s] | (%s.dat[%s.ptr%s] << 8))'):format(s, s, offset(top[s] + 1), s, s, offset(top[s])) |
||||
end |
||||
elseif 'push' == _exp_0 then |
||||
local v |
||||
s, v = s:match('^%((%S+), (.*)%)$') |
||||
assert(s == 'src' or s == 'dst', s) |
||||
local _exp_1 = n |
||||
if '8' == _exp_1 then |
||||
pushtop[s] = pushtop[s] + 1 |
||||
return ('%s.dat[%s.ptr%s] = %s'):format(s, s, offset(pushtop[s] - 1), v) |
||||
elseif '16' == _exp_1 then |
||||
if v:match('%+%+') or v:match('%-%-') then |
||||
error('push16 has side effects: ' .. v) |
||||
end |
||||
local peek, args = v:match('^([md]e[mv]peek)16(%b())$') |
||||
if peek then |
||||
args = args:sub(2, -2) |
||||
return pop_push('push', '8', ('(%s, %s8(%s))'):format(s, peek, args)) .. ';\n' .. pop_push('push', '8', ('(%s, %s8(%s + 1))'):format(s, peek, args)) |
||||
end |
||||
pushtop[s] = pushtop[s] + 2 |
||||
if v:match(' ') then |
||||
v = '(' .. v .. ')' |
||||
end |
||||
return ('%s.dat[%s.ptr%s] = %s >> 8;\n%s.dat[%s.ptr%s] = %s & 0xff'):format(s, s, offset(pushtop[s] - 2), v, s, s, offset(pushtop[s] - 1), v) |
||||
end |
||||
else |
||||
return nil |
||||
end |
||||
end |
||||
local indented_block |
||||
indented_block = function(s) |
||||
s = s:gsub('^%{ *', '{\n'):gsub('\n', '\n\t'):gsub('\t%} *$', '}\n') |
||||
s = s:gsub('\n[^\n]+%.error = [^\n]+', '%0\n#ifndef NO_STACK_CHECKS\n\tgoto error;\n#endif') |
||||
return s |
||||
end |
||||
local process |
||||
process = function(body) |
||||
local out_body = body:gsub('^%{ *', ''):gsub(' *%}$', ''):gsub('; ', ';\n'):gsub('%b{} *', indented_block):gsub('(%a+)(%d+)(%b())', pop_push) |
||||
local in_ifdef = false |
||||
local _list_0 = { |
||||
'src', |
||||
'dst' |
||||
} |
||||
for _index_0 = 1, #_list_0 do |
||||
local k = _list_0[_index_0] |
||||
if bottom[k] ~= 0 then |
||||
if not in_ifdef then |
||||
out_body = out_body .. '\n#ifndef NO_STACK_CHECKS' |
||||
in_ifdef = true |
||||
end |
||||
out_body = out_body .. ('\nif(__builtin_expect(%s.ptr < %d, 0)) {\n\t%s.error = 1;\n\tgoto error;\n}'):format(k, -bottom[k], k) |
||||
end |
||||
if pushtop[k] ~= 0 then |
||||
if pushtop[k] > 0 then |
||||
if not in_ifdef then |
||||
out_body = out_body .. '\n#ifndef NO_STACK_CHECKS' |
||||
in_ifdef = true |
||||
end |
||||
out_body = out_body .. ('\nif(__builtin_expect(%s.ptr > %d, 0)) {\n\t%s.error = 2;\n\tgoto error;\n}'):format(k, 255 - pushtop[k], k) |
||||
end |
||||
if in_ifdef then |
||||
out_body = out_body .. '\n#endif' |
||||
in_ifdef = false |
||||
end |
||||
out_body = out_body .. ('\n%s.ptr %s= %d;'):format(k, pushtop[k] < 0 and '-' or '+', math.abs(pushtop[k])) |
||||
end |
||||
end |
||||
if in_ifdef then |
||||
out_body = out_body .. '\n#endif' |
||||
in_ifdef = false |
||||
end |
||||
local t = { } |
||||
out_body:gsub('[^%w_]([a-f]) = (src%.dat%[[^]]+%])[,;]', function(v, k) |
||||
t[k] = v |
||||
end) |
||||
out_body = out_body:gsub('(src%.dat%[[^]]+%]) = ([a-f]);\n', function(k, v) |
||||
if t[k] and t[k] == v then |
||||
return '' |
||||
end |
||||
return nil |
||||
end) |
||||
return out_body |
||||
end |
||||
local ops = { } |
||||
for l in assert(io.lines('src/uxn.c')) do |
||||
local _continue_0 = false |
||||
repeat |
||||
local name, body = l:match('void (op_%S*)%(Uxn %*u%) (%b{})') |
||||
if not name then |
||||
_continue_0 = true |
||||
break |
||||
end |
||||
if replacements[name] then |
||||
body = replacements[name] |
||||
end |
||||
body = body:gsub('u%-%>src%-%>', 'src.') |
||||
body = body:gsub('u%-%>dst%-%>', 'dst.') |
||||
body = body:gsub('u%-%>src', 'src') |
||||
body = body:gsub('u%-%>dst', 'dst') |
||||
top = { |
||||
src = 0, |
||||
dst = 0 |
||||
} |
||||
bottom = { |
||||
src = 0, |
||||
dst = 0 |
||||
} |
||||
pushtop = top |
||||
ops[name] = process(body) |
||||
top = { |
||||
src = 0, |
||||
dst = 0 |
||||
} |
||||
bottom = { |
||||
src = 0, |
||||
dst = 0 |
||||
} |
||||
pushtop = { |
||||
src = 0, |
||||
dst = 0 |
||||
} |
||||
ops['keep_' .. name] = process(body) |
||||
_continue_0 = true |
||||
until true |
||||
if not _continue_0 then |
||||
break |
||||
end |
||||
end |
||||
local dump |
||||
dump = function(s, src, dst) |
||||
local ret = '\t\t\t{\n' |
||||
for l in s:gmatch('[^\n]+') do |
||||
if not l:match('^%#') then |
||||
ret = ret .. '\t\t\t\t' |
||||
end |
||||
ret = ret .. ('%s\n'):format(l) |
||||
end |
||||
ret = ret .. '\t\t\t}\n\t\t\tbreak;\n' |
||||
return (ret:gsub('src', src):gsub('dst', dst)) |
||||
end |
||||
local i = 0 |
||||
local allops = { } |
||||
local wanted = false |
||||
for l in assert(io.lines('src/uxn.c')) do |
||||
if l == 'static void (*ops[])(Uxn *u) = {' then |
||||
wanted = true |
||||
elseif l == '};' then |
||||
wanted = false |
||||
elseif wanted then |
||||
l = l:gsub('%/%b**%/', '') |
||||
for op in l:gmatch('[%w_]+') do |
||||
if not ops[op] then |
||||
error('missing ' .. op) |
||||
end |
||||
allops[i + 0x00 + 1] = { |
||||
n = { |
||||
i + 0x00 |
||||
}, |
||||
body = dump(ops[op], 'u->wst', 'u->rst') |
||||
} |
||||
allops[i + 0x20 + 1] = { |
||||
n = { |
||||
i + 0x20 |
||||
}, |
||||
body = dump(ops[op], 'u->rst', 'u->wst') |
||||
} |
||||
allops[i + 0x80 + 1] = { |
||||
n = { |
||||
i + 0x80 |
||||
}, |
||||
body = dump(ops['keep_' .. op], 'u->wst', 'u->rst') |
||||
} |
||||
allops[i + 0xa0 + 1] = { |
||||
n = { |
||||
i + 0xa0 |
||||
}, |
||||
body = dump(ops['keep_' .. op], 'u->rst', 'u->wst') |
||||
} |
||||
i = i + 1 |
||||
if i == 0x20 then |
||||
i = i + 0x20 |
||||
end |
||||
end |
||||
end |
||||
end |
||||
i = 0 |
||||
wanted = false |
||||
for l in assert(io.lines('src/uxnasm.c')) do |
||||
if l == 'static char ops[][4] = {' then |
||||
wanted = true |
||||
elseif l == '};' then |
||||
wanted = false |
||||
elseif wanted then |
||||
for op in l:gmatch('"(...)"') do |
||||
i = i + 1 |
||||
allops[i + 0x00].name = op |
||||
allops[i + 0x20].name = op .. 'r' |
||||
allops[i + 0x40].name = op .. '2' |
||||
allops[i + 0x60].name = op .. '2r' |
||||
allops[i + 0x80].name = op .. 'k' |
||||
allops[i + 0xa0].name = op .. 'kr' |
||||
allops[i + 0xc0].name = op .. '2k' |
||||
allops[i + 0xe0].name = op .. '2kr' |
||||
end |
||||
end |
||||
end |
||||
for i = 1, 256 do |
||||
local _continue_0 = false |
||||
repeat |
||||
if not allops[i] then |
||||
_continue_0 = true |
||||
break |
||||
end |
||||
for j = i + 1, 256 do |
||||
if allops[i].body == allops[j].body then |
||||
table.insert(allops[i].n, (table.remove(allops[j].n))) |
||||
allops[j].body = nil |
||||
end |
||||
end |
||||
_continue_0 = true |
||||
until true |
||||
if not _continue_0 then |
||||
break |
||||
end |
||||
end |
||||
do |
||||
local _with_0 = assert(io.open('src/uxn-fast.c', 'w')) |
||||
local f = assert(io.open('src/uxn.c')) |
||||
while true do |
||||
local l = f:read('*l') |
||||
_with_0:write(('%s\n'):format(l)) |
||||
if l == '*/' then |
||||
break |
||||
end |
||||
end |
||||
_with_0:write('\n') |
||||
_with_0:write([[/* |
||||
^ |
||||
/!\ THIS FILE IS AUTOMATICALLY GENERATED |
||||
--- |
||||
|
||||
Its contents can get overwritten with the processed contents of src/uxn.c. |
||||
See etc/mkuxn-fast.moon for instructions. |
||||
|
||||
*/ |
||||
]]) |
||||
wanted = true |
||||
while true do |
||||
local _continue_0 = false |
||||
repeat |
||||
local l = f:read('*l') |
||||
if l:match(' push') or l:match('[ *]pop') or l:match('devr16') then |
||||
_continue_0 = true |
||||
break |
||||
end |
||||
if l == '/* Stack */' then |
||||
wanted = false |
||||
end |
||||
if wanted then |
||||
_with_0:write(('%s\n'):format(l)) |
||||
end |
||||
if l == '}' then |
||||
_with_0:write('\n') |
||||
break |
||||
end |
||||
_continue_0 = true |
||||
until true |
||||
if not _continue_0 then |
||||
break |
||||
end |
||||
end |
||||
_with_0:write([[/* clang-format on */ |
||||
|
||||
#pragma mark - Core |
||||
|
||||
int |
||||
uxn_eval(Uxn *u, Uint16 vec) |
||||
{ |
||||
Uint8 instr; |
||||
if(!vec || u->dev[0].dat[0xf]) |
||||
return 0; |
||||
u->ram.ptr = vec; |
||||
if(u->wst.ptr > 0xf8) u->wst.ptr = 0xf8; |
||||
while((instr = u->ram.dat[u->ram.ptr++])) { |
||||
switch(instr) { |
||||
#pragma GCC diagnostic push |
||||
#pragma GCC diagnostic ignored "-Wunused-value" |
||||
#pragma GCC diagnostic ignored "-Wunused-variable" |
||||
]]) |
||||
for i = 1, 256 do |
||||
local _continue_0 = false |
||||
repeat |
||||
if not allops[i].body then |
||||
_continue_0 = true |
||||
break |
||||
end |
||||
local _list_0 = allops[i].n |
||||
for _index_0 = 1, #_list_0 do |
||||
local n = _list_0[_index_0] |
||||
_with_0:write(('\t\tcase 0x%02x: /* %s */\n'):format(n, allops[n + 1].name)) |
||||
end |
||||
if generate_labels then |
||||
_with_0:write(('\t\t\t__asm__("evaluxn_%02x_%s:");\n'):format(allops[i].n[1], allops[i].name)) |
||||
end |
||||
_with_0:write(allops[i].body) |
||||
_continue_0 = true |
||||
until true |
||||
if not _continue_0 then |
||||
break |
||||
end |
||||
end |
||||
_with_0:write([[#pragma GCC diagnostic pop |
||||
} |
||||
} |
||||
return 1; |
||||
#ifndef NO_STACK_CHECKS |
||||
error: |
||||
if(u->wst.error) |
||||
return uxn_halt(u, u->wst.error, "Working-stack", instr); |
||||
else |
||||
return uxn_halt(u, u->rst.error, "Return-stack", instr); |
||||
#endif |
||||
} |
||||
|
||||
int |
||||
]]) |
||||
wanted = false |
||||
while true do |
||||
local l = f:read('*l') |
||||
if not l then |
||||
break |
||||
end |
||||
if l:match('^uxn_boot') then |
||||
wanted = true |
||||
end |
||||
if wanted then |
||||
_with_0:write(('%s\n'):format(l)) |
||||
end |
||||
end |
||||
f:close() |
||||
_with_0:close() |
||||
return _with_0 |
||||
end |
||||
@ -1,280 +0,0 @@
|
||||
-- |
||||
-- Uxn core unroller script |
||||
-- |
||||
-- This script updates src/uxn-fast.c when Uxn's opcode set changes, so that |
||||
-- updates in the human-readable src/uxn.c core can be easily converted into |
||||
-- high-performance code. |
||||
-- |
||||
-- To run, you need Lua or LuaJIT, and just run etc/mkuxn-fast.lua from the top |
||||
-- directory of Uxn's git repository: |
||||
-- |
||||
-- lua etc/mkuxn-fast.lua |
||||
-- |
||||
-- This file is written in MoonScript, which is a language that compiles to |
||||
-- Lua, the same way as e.g. CoffeeScript compiles to JavaScript. Since |
||||
-- installing MoonScript has more dependencies than Lua, the compiled |
||||
-- etc/mkuxn-fast.lua is kept in Uxn's repository and will be kept updated as |
||||
-- this file changes. |
||||
-- |
||||
|
||||
generate_labels = false -- add labels to each opcode to inspect disassembled code |
||||
|
||||
replacements = |
||||
op_and16: '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, d & b); push8(u->src, c & a); }' |
||||
op_ora16: '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, d | b); push8(u->src, c | a); }' |
||||
op_eor16: '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, d ^ b); push8(u->src, c ^ a); }' |
||||
op_lit16: '{ push8(u->src, peek8(u->ram.dat, u->ram.ptr++)); push8(u->src, peek8(u->ram.dat, u->ram.ptr++)); }' |
||||
op_swp16: '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, b); push8(u->src, a); push8(u->src, d); push8(u->src, c); }' |
||||
op_ovr16: '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src); push8(u->src, d); push8(u->src, c); push8(u->src, b); push8(u->src, a); push8(u->src, d); push8(u->src, c); }' |
||||
op_dup16: '{ Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b); push8(u->src, a); push8(u->src, b); push8(u->src, a); }' |
||||
op_rot16: '{ Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src), d = pop8(u->src), e = pop8(u->src), f = pop8(u->src); push8(u->src, d); push8(u->src, c); push8(u->src, b); push8(u->src, a); push8(u->src, f); push8(u->src, e); }' |
||||
op_sth16: '{ Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->dst, b); push8(u->dst, a); }' |
||||
|
||||
local top, bottom, pushtop |
||||
|
||||
offset = (n, s = '') -> |
||||
if n < 0 |
||||
' -%s %d'\format s, -n |
||||
elseif n > 0 |
||||
' +%s %d'\format s, n |
||||
elseif s != '' |
||||
' +%s 0'\format s |
||||
else |
||||
'' |
||||
|
||||
pop_push = (k, n, s) -> |
||||
switch k |
||||
when 'pop' |
||||
s = s\match '^%((%S+)%)$' |
||||
assert s == 'src' |
||||
switch n |
||||
when '8' |
||||
top[s] -= 1 |
||||
if bottom[s] > top[s] |
||||
bottom[s] = top[s] |
||||
'%s.dat[%s.ptr%s]'\format s, s, offset(top[s]) |
||||
when '16' |
||||
top[s] -= 2 |
||||
if bottom[s] > top[s] |
||||
bottom[s] = top[s] |
||||
'(%s.dat[%s.ptr%s] | (%s.dat[%s.ptr%s] << 8))'\format s, s, offset(top[s] + 1), s, s, offset(top[s]) |
||||
when 'push' |
||||
s, v = s\match '^%((%S+), (.*)%)$' |
||||
assert s == 'src' or s == 'dst', s |
||||
switch n |
||||
when '8' |
||||
pushtop[s] += 1 |
||||
'%s.dat[%s.ptr%s] = %s'\format s, s, offset(pushtop[s] - 1), v |
||||
when '16' |
||||
if v\match'%+%+' or v\match'%-%-' |
||||
error 'push16 has side effects: ' .. v |
||||
peek, args = v\match '^([md]e[mv]peek)16(%b())$' |
||||
if peek |
||||
args = args\sub 2, -2 |
||||
return pop_push('push', '8', '(%s, %s8(%s))'\format s, peek, args) .. ';\n' .. pop_push('push', '8', '(%s, %s8(%s + 1))'\format s, peek, args) |
||||
pushtop[s] += 2 |
||||
if v\match ' ' |
||||
v = '(' .. v .. ')' |
||||
'%s.dat[%s.ptr%s] = %s >> 8;\n%s.dat[%s.ptr%s] = %s & 0xff'\format s, s, offset(pushtop[s] - 2), v, s, s, offset(pushtop[s] - 1), v |
||||
else |
||||
nil |
||||
|
||||
indented_block = (s) -> |
||||
s = s\gsub('^%{ *', '{\n')\gsub('\n', '\n\t')\gsub('\t%} *$', '}\n') |
||||
s = s\gsub('\n[^\n]+%.error = [^\n]+', '%0\n#ifndef NO_STACK_CHECKS\n\tgoto error;\n#endif') |
||||
s |
||||
|
||||
process = (body) -> |
||||
out_body = body\gsub('^%{ *', '')\gsub(' *%}$', '')\gsub('; ', ';\n')\gsub('%b{} *', indented_block)\gsub '(%a+)(%d+)(%b())', pop_push |
||||
in_ifdef = false |
||||
for k in *{'src', 'dst'} |
||||
if bottom[k] != 0 |
||||
if not in_ifdef |
||||
out_body ..= '\n#ifndef NO_STACK_CHECKS' |
||||
in_ifdef = true |
||||
out_body ..= '\nif(__builtin_expect(%s.ptr < %d, 0)) {\n\t%s.error = 1;\n\tgoto error;\n}'\format k, -bottom[k], k |
||||
if pushtop[k] != 0 |
||||
if pushtop[k] > 0 |
||||
if not in_ifdef |
||||
out_body ..= '\n#ifndef NO_STACK_CHECKS' |
||||
in_ifdef = true |
||||
out_body ..= '\nif(__builtin_expect(%s.ptr > %d, 0)) {\n\t%s.error = 2;\n\tgoto error;\n}'\format k, 255 - pushtop[k], k |
||||
if in_ifdef |
||||
out_body ..= '\n#endif' |
||||
in_ifdef = false |
||||
out_body ..= '\n%s.ptr %s= %d;'\format k, pushtop[k] < 0 and '-' or '+', math.abs pushtop[k] |
||||
if in_ifdef |
||||
out_body ..= '\n#endif' |
||||
in_ifdef = false |
||||
t = {} |
||||
out_body\gsub '[^%w_]([a-f]) = (src%.dat%[[^]]+%])[,;]', (v, k) -> t[k] = v |
||||
out_body = out_body\gsub '(src%.dat%[[^]]+%]) = ([a-f]);\n', (k, v) -> |
||||
if t[k] and t[k] == v |
||||
return '' |
||||
return nil |
||||
out_body |
||||
|
||||
ops = {} |
||||
|
||||
for l in assert io.lines 'src/uxn.c' |
||||
name, body = l\match 'void (op_%S*)%(Uxn %*u%) (%b{})' |
||||
if not name |
||||
continue |
||||
if replacements[name] |
||||
body = replacements[name] |
||||
body = body\gsub 'u%-%>src%-%>', 'src.' |
||||
body = body\gsub 'u%-%>dst%-%>', 'dst.' |
||||
body = body\gsub 'u%-%>src', 'src' |
||||
body = body\gsub 'u%-%>dst', 'dst' |
||||
top = { src: 0, dst: 0 } |
||||
bottom = { src: 0, dst: 0 } |
||||
pushtop = top |
||||
ops[name] = process body |
||||
top = { src: 0, dst: 0 } |
||||
bottom = { src: 0, dst: 0 } |
||||
pushtop = { src: 0, dst: 0 } |
||||
ops['keep_' .. name] = process body |
||||
|
||||
dump = (s, src, dst) -> |
||||
ret = '\t\t\t{\n' |
||||
for l in s\gmatch '[^\n]+' |
||||
if not l\match '^%#' |
||||
ret ..= '\t\t\t\t' |
||||
ret ..= '%s\n'\format l |
||||
ret ..= '\t\t\t}\n\t\t\tbreak;\n' |
||||
(ret\gsub('src', src)\gsub('dst', dst)) |
||||
|
||||
i = 0 |
||||
allops = {} |
||||
wanted = false |
||||
for l in assert io.lines 'src/uxn.c' |
||||
if l == 'static void (*ops[])(Uxn *u) = {' |
||||
wanted = true |
||||
elseif l == '};' |
||||
wanted = false |
||||
elseif wanted |
||||
l = l\gsub '%/%b**%/', '' |
||||
for op in l\gmatch '[%w_]+' |
||||
if not ops[op] |
||||
error 'missing ' .. op |
||||
allops[i + 0x00 + 1] = { n: { i + 0x00 }, body: dump ops[op], 'u->wst', 'u->rst' } |
||||
allops[i + 0x20 + 1] = { n: { i + 0x20 }, body: dump ops[op], 'u->rst', 'u->wst' } |
||||
allops[i + 0x80 + 1] = { n: { i + 0x80 }, body: dump ops['keep_' .. op], 'u->wst', 'u->rst' } |
||||
allops[i + 0xa0 + 1] = { n: { i + 0xa0 }, body: dump ops['keep_' .. op], 'u->rst', 'u->wst' } |
||||
i += 1 |
||||
if i == 0x20 |
||||
i += 0x20 |
||||
|
||||
i = 0 |
||||
wanted = false |
||||
for l in assert io.lines 'src/uxnasm.c' |
||||
if l == 'static char ops[][4] = {' |
||||
wanted = true |
||||
elseif l == '};' |
||||
wanted = false |
||||
elseif wanted |
||||
for op in l\gmatch '"(...)"' |
||||
i += 1 |
||||
allops[i + 0x00].name = op |
||||
allops[i + 0x20].name = op .. 'r' |
||||
allops[i + 0x40].name = op .. '2' |
||||
allops[i + 0x60].name = op .. '2r' |
||||
allops[i + 0x80].name = op .. 'k' |
||||
allops[i + 0xa0].name = op .. 'kr' |
||||
allops[i + 0xc0].name = op .. '2k' |
||||
allops[i + 0xe0].name = op .. '2kr' |
||||
|
||||
for i = 1, 256 |
||||
if not allops[i] |
||||
continue |
||||
for j = i + 1, 256 |
||||
if allops[i].body == allops[j].body |
||||
table.insert allops[i].n, (table.remove allops[j].n) |
||||
allops[j].body = nil |
||||
|
||||
with assert io.open 'src/uxn-fast.c', 'w' |
||||
f = assert io.open 'src/uxn.c' |
||||
while true |
||||
l = f\read '*l' |
||||
\write '%s\n'\format l |
||||
if l == '*/' |
||||
break |
||||
\write '\n' |
||||
\write [[ |
||||
/* |
||||
^ |
||||
/!\ THIS FILE IS AUTOMATICALLY GENERATED |
||||
--- |
||||
|
||||
Its contents can get overwritten with the processed contents of src/uxn.c. |
||||
See etc/mkuxn-fast.moon for instructions. |
||||
|
||||
*/ |
||||
]] |
||||
wanted = true |
||||
while true |
||||
l = f\read '*l' |
||||
if l\match' push' or l\match'[ *]pop' or l\match'devr16' |
||||
continue |
||||
if l == '/* Stack */' |
||||
wanted = false |
||||
if wanted |
||||
\write '%s\n'\format l |
||||
if l == '}' |
||||
\write '\n' |
||||
break |
||||
\write [[ |
||||
/* clang-format on */ |
||||
|
||||
#pragma mark - Core |
||||
|
||||
int |
||||
uxn_eval(Uxn *u, Uint16 vec) |
||||
{ |
||||
Uint8 instr; |
||||
if(!vec || u->dev[0].dat[0xf]) |
||||
return 0; |
||||
u->ram.ptr = vec; |
||||
if(u->wst.ptr > 0xf8) u->wst.ptr = 0xf8; |
||||
while((instr = u->ram.dat[u->ram.ptr++])) { |
||||
switch(instr) { |
||||
#pragma GCC diagnostic push |
||||
#pragma GCC diagnostic ignored "-Wunused-value" |
||||
#pragma GCC diagnostic ignored "-Wunused-variable" |
||||
]] |
||||
for i = 1, 256 |
||||
if not allops[i].body |
||||
continue |
||||
for n in *allops[i].n |
||||
\write '\t\tcase 0x%02x: /* %s */\n'\format n, allops[n + 1].name |
||||
if generate_labels |
||||
\write '\t\t\t__asm__("evaluxn_%02x_%s:");\n'\format allops[i].n[1], allops[i].name |
||||
\write allops[i].body |
||||
\write [[ |
||||
#pragma GCC diagnostic pop |
||||
} |
||||
} |
||||
return 1; |
||||
#ifndef NO_STACK_CHECKS |
||||
error: |
||||
if(u->wst.error) |
||||
return uxn_halt(u, u->wst.error, "Working-stack", instr); |
||||
else |
||||
return uxn_halt(u, u->rst.error, "Return-stack", instr); |
||||
#endif |
||||
} |
||||
|
||||
int |
||||
]] |
||||
wanted = false |
||||
while true |
||||
l = f\read '*l' |
||||
if not l |
||||
break |
||||
if l\match '^uxn_boot' |
||||
wanted = true |
||||
if wanted |
||||
\write '%s\n'\format l |
||||
f\close! |
||||
\close! |
||||
|
||||
@ -0,0 +1,16 @@
|
||||
( devices ) |
||||
|
||||
|00 @System &vector $2 &wst $1 &rst $1 &eaddr $2 &ecode $1 &pad $1 &r $2 &g $2 &b $2 &debug $1 &halt $1 |
||||
|10 @Console &vector $2 &read $1 &pad $5 &write $1 &error $1 |
||||
|
||||
( program ) |
||||
|
||||
|0100 @Reset ( -> ) |
||||
~projects/library/debugger.tal |
||||
#0123 #4567 #89ab #cdef |
||||
LIT2r 1234 LIT2r 5678 LIT2r 9abc LIT2r def0 |
||||
( BREAKPOINT ) |
||||
( LIT2r 0000 DIVr ) |
||||
&loop INCk ,&loop JMP |
||||
BRK |
||||
|
||||
@ -0,0 +1,180 @@
|
||||
( in-Uxn debugger ) |
||||
|
||||
( To use, include this file just before the BRK in the program reset routine, e.g.: |
||||
|
||||
|0100 ( -> ) |
||||
( theme ) |
||||
#0fe5 .System/r DEO2 |
||||
#0fc5 .System/g DEO2 |
||||
#0f25 .System/b DEO2 |
||||
~projects/library/debugger.tal |
||||
BRK |
||||
|
||||
The debugger will catch stack errors that arise after that point. |
||||
|
||||
) |
||||
|
||||
%BREAKPOINT { LIT2r :debug JSR2r } |
||||
|
||||
@debug-start |
||||
;debug-vector .System/vector DEO2 |
||||
;debug-end JMP2 |
||||
|
||||
@debug ( pc* -- ) |
||||
#0001 SUB2 .System/eaddr DEO2 |
||||
.System/ecode DEIk #f8 AND #06 EOR SWP DEO |
||||
,debug-vector/main JMP |
||||
|
||||
@debug-vector ( -> ) |
||||
STH STH STH STH ( <- only run in case of working stack overflow ) |
||||
&main |
||||
|
||||
( flush the working stack ) |
||||
.System/wst DEI ;debug-wst/ptr STA |
||||
&flush-wst |
||||
.System/wst DEI #00 EQU ,&end-flush-wst JCN |
||||
#00 .System/wst DEI #0002 SUB2 ;debug-wst/dat ADD2 STA |
||||
,&flush-wst JMP |
||||
&end-flush-wst |
||||
|
||||
( in case of working stack overflow, we need to append the four return stack bytes ) |
||||
.System/ecode DEI #02 NEQ ,&skip-wst-append JCN |
||||
#00 ;debug-wst/ptr LDAk ( 00 ptr-hi ptr-lo ptr / ... z y x w ) |
||||
DUP #04 ADD OVR2 STA |
||||
ROT ROT ADD2 ( start* / ... z y x w ) |
||||
INC2 DUP2 #0004 ADD2 SWP2 ( end* start* / ... z y x w ) |
||||
&loop |
||||
DUP2 STHr ROT ROT STA |
||||
INC2 |
||||
GTH2k ,&loop JCN |
||||
POP2 POP2 |
||||
&skip-wst-append |
||||
|
||||
( flush the return stack ) |
||||
.System/rst DEI ;debug-rst/ptr STA |
||||
&flush-rst |
||||
.System/rst DEI #00 EQU ,&end-flush-rst JCN |
||||
STHr #00 .System/rst DEI ;debug-rst/dat ADD2 STA |
||||
,&flush-rst JMP |
||||
&end-flush-rst |
||||
|
||||
( Version 0.1 functionality: print the error and exit ) |
||||
;debug-print-error JSR2 |
||||
#01 .System/halt DEO |
||||
BRK |
||||
|
||||
@debug-print-opcode ( instr -- ) |
||||
DUP ,¬-brk JCN |
||||
POP ;&brk-msg ;debug-print JMP2 ( tail call ) |
||||
&brk-msg "BRK 00 |
||||
¬-brk |
||||
#00 OVR #1f AND #03 MUL ;&opcode-names ADD2 ( instr addr* ) |
||||
LDAk .Console/write DEO INC2 |
||||
LDAk .Console/write DEO INC2 |
||||
LDA .Console/write DEO |
||||
DUP #1f AND ,¬-lit JCN |
||||
#7f AND |
||||
¬-lit |
||||
DUP #20 AND #00 EQU ,¬-2 JCN |
||||
LIT '2 .Console/write DEO |
||||
¬-2 |
||||
DUP #80 AND #00 EQU ,¬-k JCN |
||||
LIT 'k .Console/write DEO |
||||
¬-k |
||||
#40 AND #00 EQU ,¬-r JCN |
||||
LIT 'r .Console/write DEO |
||||
¬-r |
||||
JMP2r |
||||
|
||||
&opcode-names |
||||
"LITINCPOPDUPNIPSWPOVRROT |
||||
"EQUNEQGTHLTHJMPJCNJSRSTH |
||||
"LDZSTZLDRSTRLDASTADEIDEO |
||||
"ADDSUBMULDIVANDORAEORSFT |
||||
|
||||
@debug-print ( addr* -- ) |
||||
LDAk #00 EQU ,&end JCN |
||||
LDAk .Console/write DEO |
||||
INC2 |
||||
,debug-print JMP |
||||
&end POP2 JMP2r |
||||
|
||||
@debug-print-error |
||||
;&halted-msg ,debug-print JSR |
||||
#00 .System/ecode DEI #07 AND #20 SFT2 ;&messages-table ADD2 |
||||
LDA2k ,debug-print JSR |
||||
INC2 INC2 LDA2 ,debug-print JSR |
||||
;&executing-msg ,debug-print JSR |
||||
.System/eaddr DEI2 LDA ;debug-print-opcode JSR2 |
||||
;&at-msg ,debug-print JSR |
||||
.System/eaddr DEI2 ;debug-print-hex-short JSR2 |
||||
#0a .Console/write DEO |
||||
;&wst-msg ,debug-print JSR |
||||
;&contents-msg ,debug-print JSR |
||||
;debug-wst ;debug-print-stack JSR2 |
||||
#0a .Console/write DEO |
||||
;&rst-msg ,debug-print JSR |
||||
;&contents-msg ,debug-print JSR |
||||
;debug-rst ;debug-print-stack JSR2 |
||||
#0a .Console/write DEO |
||||
JMP2r |
||||
|
||||
&messages-table |
||||
:&wst-msg :&underflow-msg |
||||
:&rst-msg :&underflow-msg |
||||
:&wst-msg :&overflow-msg |
||||
:&rst-msg :&overflow-msg |
||||
:&wst-msg :&divzero-msg |
||||
:&rst-msg :&divzero-msg |
||||
:&userdef-msg :&breakpoint-msg |
||||
:&userdef-msg :&custom-msg |
||||
|
||||
&halted-msg "Halted: 2000 ( #0002, at 0x0100 ) |
||||
&wst-msg "Working-stack 2000 |
||||
&rst-msg "Return-stack 2000 |
||||
&userdef-msg "User-defined 2000 |
||||
&underflow-msg "underflow 00 |
||||
&overflow-msg "overflow 00 |
||||
&divzero-msg "division 20 "by 20 "zero 00 |
||||
&breakpoint-msg "breakpoint 00 |
||||
&custom-msg "custom 20 "error 00 |
||||
&executing-msg 20 "executing 2000 |
||||
&at-msg 20 "at 20 "0x 00 |
||||
&contents-msg "contents: 00 |
||||
|
||||
@debug-print-hex-short ( value* -- ) |
||||
SWP ,debug-print-hex-byte JSR |
||||
( fall through ) |
||||
|
||||
@debug-print-hex-byte ( value -- ) |
||||
DUP #04 SFT ,debug-print-hex-nibble JSR |
||||
#0f AND |
||||
( fall through ) |
||||
|
||||
@debug-print-hex-nibble ( value -- ) |
||||
#30 ADD DUP #39 GTH #27 MUL ADD |
||||
.Console/write DEO |
||||
JMP2r |
||||
|
||||
@debug-print-stack ( addr* -- ) |
||||
LDAk ,¬-empty JCN |
||||
POP2 ;&empty-msg ;debug-print JMP2 ( tail call ) |
||||
¬-empty |
||||
LDAk STH INC2 ( dat* / count ) |
||||
&loop |
||||
STHkr #00 EQU ,&end JCN |
||||
#20 .Console/write DEO |
||||
LDAk ,debug-print-hex-byte JSR |
||||
INC2 |
||||
LITr 01 SUBr |
||||
,&loop JMP |
||||
&end |
||||
POP2 POPr |
||||
JMP2r |
||||
|
||||
&empty-msg 20 "(empty) 00 |
||||
|
||||
@debug-wst &ptr $1 &dat $ff |
||||
@debug-rst &ptr $1 &dat $ff |
||||
@debug-end |
||||
|
||||
@ -0,0 +1,270 @@
|
||||
( launcher ) |
||||
|
||||
%+ { ADD } %- { SUB } %* { MUL } %/ { DIV } |
||||
%< { LTH } %> { GTH } %= { EQU } %! { NEQ } |
||||
%++ { ADD2 } %-- { SUB2 } %** { MUL2 } %// { DIV2 } |
||||
%<< { LTH2 } %>> { GTH2 } %== { EQU2 } %!! { NEQ2 } |
||||
|
||||
%AUTO-X { #01 .Screen/auto DEO } |
||||
%AUTO-Y { #02 .Screen/auto DEO } |
||||
%AUTO-YADDR { #06 .Screen/auto DEO } |
||||
|
||||
%HALT { #010f DEO } |
||||
%EMIT { #18 DEO } |
||||
%PRINT { ;print-str JSR2 #0a EMIT } |
||||
%DEBUG { ;print-hex/byte JSR2 #0a EMIT } |
||||
%DEBUG2 { ;print-hex JSR2 #0a EMIT } |
||||
|
||||
%MODALW { #0024 } |
||||
%MODALH { #0009 } |
||||
|
||||
%RTN { JMP2r } |
||||
%2// { #01 SFT2 } |
||||
%8** { #30 SFT2 } |
||||
|
||||
%EADDR { #fd04 } |
||||
%ECODE { #fd06 } |
||||
|
||||
( devices ) |
||||
|
||||
|00 @System &vector $2 &wst $1 &rst $1 &eaddr $2 &ecode $1 &pad $1 &r $2 &g $2 &b $2 &debug $1 &halt $1 |
||||
|20 @Screen &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 |
||||
|80 @Controller &vector $2 &button $1 &key $1 &func $1 |
||||
|
||||
( variables ) |
||||
|
||||
|0000 |
||||
|
||||
@center |
||||
&x $2 &y $2 |
||||
@modal |
||||
&x $2 &y $2 |
||||
|
||||
( init ) |
||||
|
||||
|0100 ( -> ) |
||||
|
||||
.Screen/width DEI2 2// |
||||
DUP2 .center/x STZ2 |
||||
MODALW #31 SFT2 -- .modal/x STZ2 |
||||
.Screen/height DEI2 2// |
||||
DUP2 .center/y STZ2 |
||||
MODALH #31 SFT2 -- .modal/y STZ2 |
||||
|
||||
( vectors ) |
||||
;on-error .System/vector DEO2 |
||||
;on-frame .Screen/vector DEO2 |
||||
;on-button .Controller/vector DEO2 |
||||
|
||||
BRK |
||||
|
||||
@on-frame ( -> ) |
||||
|
||||
;draw-cross JSR2 |
||||
;draw-stacks JSR2 |
||||
|
||||
BRK |
||||
|
||||
@on-button ( -> ) |
||||
|
||||
.Controller/func DEI |
||||
DUP #02 ! ,&no-f2 JCN |
||||
;toggle-debugger JSR2 |
||||
&no-f2 |
||||
DUP #08 ! ,&no-f4 JCN |
||||
;reboot JSR2 |
||||
&no-f4 |
||||
POP |
||||
|
||||
BRK |
||||
|
||||
@on-error ( -> ) |
||||
|
||||
( background ) |
||||
#00 .Screen/auto DEO |
||||
;bg-icn .Screen/addr DEO2 |
||||
MODALH #0000 |
||||
&ver |
||||
DUP2 8** .modal/y LDZ2 ++ .Screen/y DEO2 |
||||
MODALW #0000 |
||||
&hor |
||||
DUP2 8** .modal/x LDZ2 ++ .Screen/x DEO2 |
||||
#42 .Screen/sprite DEO |
||||
INC2 GTH2k ,&hor JCN |
||||
POP2 POP2 |
||||
INC2 GTH2k ,&ver JCN |
||||
POP2 POP2 |
||||
|
||||
( corners ) |
||||
;corner-icn .Screen/addr DEO2 |
||||
.modal/x LDZ2 .Screen/x DEO2 |
||||
.modal/y LDZ2 .Screen/y DEO2 |
||||
#42 .Screen/sprite DEO |
||||
.modal/x LDZ2 MODALW #0001 -- 8** ++ .Screen/x DEO2 |
||||
#52 .Screen/sprite DEO |
||||
|
||||
.modal/y LDZ2 MODALH #0001 -- 8** ++ .Screen/y DEO2 |
||||
#72 .Screen/sprite DEO |
||||
|
||||
.modal/x LDZ2 .Screen/x DEO2 |
||||
#62 .Screen/sprite DEO |
||||
|
||||
( text ) |
||||
.modal/x LDZ2 #0010 ++ .Screen/x DEO2 |
||||
.modal/y LDZ2 #0010 ++ .Screen/y DEO2 |
||||
;error-txts/0 #4f ;draw-str JSR2 |
||||
|
||||
;at-txt #4f ;draw-str JSR2 |
||||
|
||||
EADDR LDA2 #47 ;draw-short JSR2 |
||||
|
||||
#0000 EADDR STA2 |
||||
|
||||
BRK |
||||
|
||||
@toggle-debugger ( -- ) |
||||
|
||||
( toggle debug ) #fd0e STH2k LDA #00 = STH2r STA |
||||
|
||||
RTN |
||||
|
||||
@reboot ( -- ) |
||||
|
||||
( clear devices/stacks ) |
||||
#fd00 #0300 ;mclr JSR2 |
||||
|
||||
RTN |
||||
&boot-path "boot.rom $1 |
||||
|
||||
@draw-stacks ( -- ) |
||||
|
||||
AUTO-YADDR |
||||
#0010 #0000 |
||||
&wst |
||||
( working stack ) |
||||
#0010 .Screen/y DEO2 |
||||
DUP2 #0018 ** #0010 ++ .Screen/x DEO2 |
||||
DUP #fe00 LDA ( ptr ) EQU #41 + STH |
||||
DUP2 #fe01 ++ LDA STHr ;draw-byte JSR2 |
||||
( return stack ) |
||||
#0028 .Screen/y DEO2 |
||||
DUP2 #0018 ** #0010 ++ .Screen/x DEO2 |
||||
DUP #ff00 LDA ( ptr ) EQU #41 + STH |
||||
DUP2 #ff01 ++ LDA STHr ;draw-byte JSR2 |
||||
INC2 GTH2k ,&wst JCN |
||||
POP2 POP2 |
||||
|
||||
RTN |
||||
|
||||
@draw-cross ( -- ) |
||||
|
||||
( ver ) |
||||
AUTO-Y |
||||
#0000 .Screen/y DEO2 |
||||
.center/x LDZ2 .Screen/x DEO2 |
||||
.Screen/height DEI2 #0000 |
||||
&ver |
||||
#43 .Screen/pixel DEO |
||||
.Screen/y DEI2k INC2 ROT DEO2 |
||||
INC2 GTH2k ,&ver JCN |
||||
POP2 POP2 |
||||
|
||||
( hor ) |
||||
AUTO-X |
||||
#0000 .Screen/x DEO2 |
||||
.center/y LDZ2 .Screen/y DEO2 |
||||
.Screen/width DEI2 #0000 |
||||
&hor |
||||
#43 .Screen/pixel DEO |
||||
.Screen/x DEI2k INC2 ROT DEO2 |
||||
INC2 GTH2k ,&hor JCN |
||||
POP2 POP2 |
||||
|
||||
RTN |
||||
|
||||
@draw-str ( text* color -- ) |
||||
|
||||
AUTO-YADDR |
||||
STH |
||||
&while |
||||
LDAk STHkr ,draw-char JSR |
||||
INC2 LDAk ,&while JCN |
||||
POP2 |
||||
POPr |
||||
|
||||
RTN |
||||
|
||||
@draw-short ( short* color -- ) |
||||
|
||||
STH SWP STHkr ,draw-byte JSR |
||||
STHr ,draw-byte JSR |
||||
|
||||
RTN |
||||
|
||||
@draw-byte ( byte color -- ) |
||||
|
||||
STH |
||||
DUP #04 SFT ,&parse JSR STHkr ,draw-char JSR |
||||
#0f AND ,&parse JSR STHr ,draw-char JSR |
||||
|
||||
RTN |
||||
&parse ( byte -- char ) DUP #09 GTH ,&above JCN #30 ADD JMP2r |
||||
&above #57 ADD JMP2r |
||||
|
||||
@draw-char ( char color -- ) |
||||
|
||||
SWP |
||||
[ #20 - #00 SWP #40 SFT2 ;font ++ ] .Screen/addr DEO2 |
||||
.Screen/sprite DEOk DEO |
||||
.Screen/x DEI2k #0008 ++ ROT DEO2 |
||||
.Screen/y DEI2k #0010 -- ROT DEO2 |
||||
|
||||
JMP2r |
||||
|
||||
@mclr ( addr* len* -- ) |
||||
|
||||
OVR2 ++ SWP2 |
||||
&loop |
||||
STH2k #00 STH2r STA |
||||
INC2 GTH2k ,&loop JCN |
||||
POP2 POP2 |
||||
|
||||
JMP2r |
||||
|
||||
@print-hex ( value* -- ) |
||||
|
||||
SWP ,&byte JSR |
||||
&byte ( byte -- ) |
||||
STHk #04 SFT ,&parse JSR #18 DEO |
||||
STHr #0f AND ,&parse JSR #18 DEO |
||||
JMP2r |
||||
&parse ( byte -- char ) DUP #09 GTH ,&above JCN #30 ADD JMP2r |
||||
&above #57 ADD JMP2r |
||||
|
||||
JMP2r |
||||
|
||||
@print-str ( string* -- ) |
||||
|
||||
#0001 SUB2 |
||||
&while |
||||
INC2 LDAk DUP #18 DEO ,&while JCN |
||||
POP2 |
||||
|
||||
JMP2r |
||||
|
||||
@error-txts |
||||
&0 "Working-stack 20 "underflow $1 |
||||
&1 "Return-stack 20 "underflow $1 |
||||
&2 "Working-stack 20 "overflow $1 |
||||
&3 "Return-stack 20 "overflow $1 |
||||
&4 "Working-stack 20 "division 20 "by 20 "zero $1 |
||||
&5 "Return-stack 20 "division 20 "by 20 "zero $1 |
||||
@at-txt |
||||
', 20 "at 20 $1 |
||||
|
||||
@bg-icn |
||||
ffff ffff ffff ffff |
||||
@corner-icn |
||||
1f7f 7fff ffff ffff |
||||
|
||||
~projects/assets/msx01x02.tal |
||||
@ -0,0 +1,40 @@
|
||||
#include <time.h> |
||||
|
||||
#include "../uxn.h" |
||||
#include "datetime.h" |
||||
|
||||
/*
|
||||
Copyright (c) 2021 Devine Lu Linvega |
||||
Copyright (c) 2021 Andrew Alderwick |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE. |
||||
*/ |
||||
|
||||
Uint8 |
||||
datetime_dei(Device *d, Uint8 port) |
||||
{ |
||||
time_t seconds = time(NULL); |
||||
struct tm zt = {0}; |
||||
struct tm *t = localtime(&seconds); |
||||
if(t == NULL) |
||||
t = &zt; |
||||
switch(port) { |
||||
case 0x0: return (t->tm_year + 1900) >> 8; |
||||
case 0x1: return (t->tm_year + 1900); |
||||
case 0x2: return t->tm_mon; |
||||
case 0x3: return t->tm_mday; |
||||
case 0x4: return t->tm_hour; |
||||
case 0x5: return t->tm_min; |
||||
case 0x6: return t->tm_sec; |
||||
case 0x7: return t->tm_wday; |
||||
case 0x8: return t->tm_yday >> 8; |
||||
case 0x9: return t->tm_yday; |
||||
case 0xa: return t->tm_isdst; |
||||
default: return d->dat[port]; |
||||
} |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
/*
|
||||
Copyright (c) 2021 Devine Lu Linvega |
||||
Copyright (c) 2021 Andrew Alderwick |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE. |
||||
*/ |
||||
|
||||
Uint8 datetime_dei(Device *d, Uint8 port); |
||||
@ -0,0 +1,66 @@
|
||||
#include "../uxn.h" |
||||
#include "system.h" |
||||
|
||||
#include <stdio.h> |
||||
|
||||
/*
|
||||
Copyright (c) 2022 Devine Lu Linvega, Andrew Alderwick |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE. |
||||
*/ |
||||
|
||||
Uxn supervisor; |
||||
|
||||
static const char *errors[] = { |
||||
"Working-stack underflow", |
||||
"Return-stack underflow", |
||||
"Working-stack overflow", |
||||
"Return-stack overflow", |
||||
"Working-stack division by zero", |
||||
"Return-stack division by zero"}; |
||||
|
||||
int |
||||
uxn_halt(Uxn *u, Uint8 error, Uint16 addr) |
||||
{ |
||||
Device *d = &u->dev[0]; |
||||
Uint16 vec = d->vector; |
||||
DEVPOKE16(0x4, addr); |
||||
d->dat[0x6] = error; |
||||
uxn_eval(&supervisor, supervisor.dev[0].vector); |
||||
if(vec) { |
||||
d->vector = 0; /* need to rearm to run System/vector again */ |
||||
if(error != 2) /* working stack overflow has special treatment */ |
||||
vec += 0x0004; |
||||
return uxn_eval(u, vec); |
||||
} |
||||
fprintf(stderr, "Halted: %s#%04x, at 0x%04x\n", errors[error], u->ram[addr], addr); |
||||
return 0; |
||||
} |
||||
|
||||
/* IO */ |
||||
|
||||
Uint8 |
||||
system_dei(Device *d, Uint8 port) |
||||
{ |
||||
switch(port) { |
||||
case 0x2: return d->u->wst->ptr; |
||||
case 0x3: return d->u->rst->ptr; |
||||
default: return d->dat[port]; |
||||
} |
||||
} |
||||
|
||||
void |
||||
system_deo(Device *d, Uint8 port) |
||||
{ |
||||
switch(port) { |
||||
case 0x1: DEVPEEK16(d->vector, 0x0); break; |
||||
case 0x2: d->u->wst->ptr = d->dat[port]; break; |
||||
case 0x3: d->u->rst->ptr = d->dat[port]; break; |
||||
default: system_deo_special(d, port); |
||||
} |
||||
} |
||||
@ -0,0 +1,16 @@
|
||||
/*
|
||||
Copyright (c) 2022 Devine Lu Linvega, Andrew Alderwick |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE. |
||||
*/ |
||||
|
||||
Uint8 system_dei(Device *d, Uint8 port); |
||||
void system_deo(Device *d, Uint8 port); |
||||
void system_deo_special(Device *d, Uint8 port); |
||||
|
||||
extern Uxn supervisor; |
||||
Loading…
Reference in new issue