mirror of https://git.sr.ht/~rabbits/uxn
Merge branch 'main' into aarch64
This commit is contained in:
commit
e9241f13e2
|
@ -13,3 +13,5 @@
|
|||
*theme
|
||||
|
||||
*.rom
|
||||
|
||||
*.[o0125678vqki]
|
||||
|
|
53
build.sh
53
build.sh
|
@ -1,19 +1,54 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
format=0
|
||||
console=0
|
||||
debug=0
|
||||
norun=0
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--format)
|
||||
format=1
|
||||
shift
|
||||
;;
|
||||
|
||||
--console)
|
||||
console=1
|
||||
shift
|
||||
;;
|
||||
|
||||
--debug)
|
||||
debug=1
|
||||
shift
|
||||
;;
|
||||
|
||||
--no-run)
|
||||
norun=1
|
||||
shift
|
||||
;;
|
||||
|
||||
*)
|
||||
shift
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Cleaning.."
|
||||
rm -f ./bin/uxnasm
|
||||
rm -f ./bin/uxnemu
|
||||
rm -f ./bin/uxncli
|
||||
rm -f ./bin/supervisor.rom
|
||||
rm -f ./bin/boot.rom
|
||||
rm -f ./bin/asma.rom
|
||||
|
||||
# When clang-format is present
|
||||
|
||||
if [ "${1}" = '--format' ];
|
||||
if [ $format = 1 ];
|
||||
then
|
||||
echo "Formatting.."
|
||||
clang-format -i src/uxn.h
|
||||
clang-format -i src/uxn.c
|
||||
clang-format -i src/devices/system.h
|
||||
clang-format -i src/devices/system.c
|
||||
clang-format -i src/devices/screen.h
|
||||
clang-format -i src/devices/screen.c
|
||||
clang-format -i src/devices/audio.h
|
||||
|
@ -24,6 +59,8 @@ then
|
|||
clang-format -i src/devices/mouse.c
|
||||
clang-format -i src/devices/controller.h
|
||||
clang-format -i src/devices/controller.c
|
||||
clang-format -i src/devices/datetime.h
|
||||
clang-format -i src/devices/datetime.c
|
||||
clang-format -i src/uxnasm.c
|
||||
clang-format -i src/uxnemu.c
|
||||
clang-format -i src/uxncli.c
|
||||
|
@ -34,7 +71,7 @@ CC="${CC:-clang}"
|
|||
CFLAGS="${CFLAGS:--std=c89 -Wall -Wno-unknown-pragmas}"
|
||||
case "$(uname -s 2>/dev/null)" in
|
||||
MSYS_NT*|MINGW*) # MSYS2 on Windows
|
||||
if [ "${1}" = '--console' ];
|
||||
if [ $console = 1 ];
|
||||
then
|
||||
UXNEMU_LDFLAGS="-static $(sdl2-config --cflags --static-libs | sed -e 's/ -mwindows//g')"
|
||||
else
|
||||
|
@ -50,20 +87,20 @@ Linux|*)
|
|||
;;
|
||||
esac
|
||||
|
||||
if [ "${1}" = '--debug' ];
|
||||
if [ $debug = 1 ];
|
||||
then
|
||||
echo "[debug]"
|
||||
CFLAGS="${CFLAGS} -DDEBUG -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined"
|
||||
CORE='src/uxn.c'
|
||||
else
|
||||
CFLAGS="${CFLAGS} -DNDEBUG -Os -g0 -s"
|
||||
CORE='src/uxn-fast.c'
|
||||
CORE='src/uxn.c'
|
||||
fi
|
||||
|
||||
echo "Building.."
|
||||
${CC} ${CFLAGS} src/uxnasm.c -o bin/uxnasm
|
||||
${CC} ${CFLAGS} ${CORE} src/devices/*_aarch64.c src/devices/file.c src/devices/mouse.c src/devices/controller.c src/devices/screen.c src/devices/audio.c src/uxnemu.c ${UXNEMU_LDFLAGS} -o bin/uxnemu
|
||||
${CC} ${CFLAGS} ${CORE} src/devices/file.c src/uxncli.c -o bin/uxncli
|
||||
${CC} ${CFLAGS} ${CORE} src/devices/*_aarch64.c src/devices/system.c src/devices/file.c src/devices/datetime.c src/devices/mouse.c src/devices/controller.c src/devices/screen.c src/devices/audio.c src/uxnemu.c ${UXNEMU_LDFLAGS} -o bin/uxnemu
|
||||
${CC} ${CFLAGS} ${CORE} src/devices/system.c src/devices/file.c src/devices/datetime.c src/uxncli.c -o bin/uxncli
|
||||
|
||||
if [ -d "$HOME/bin" ]
|
||||
then
|
||||
|
@ -71,12 +108,14 @@ then
|
|||
cp bin/uxnemu bin/uxnasm bin/uxncli $HOME/bin/
|
||||
fi
|
||||
|
||||
echo "Assembling(supervisor).."
|
||||
./bin/uxnasm projects/software/supervisor.tal bin/supervisor.rom
|
||||
echo "Assembling(boot).."
|
||||
./bin/uxnasm projects/software/boot.tal bin/boot.rom
|
||||
echo "Assembling(asma).."
|
||||
./bin/uxnasm projects/software/asma.tal bin/asma.rom
|
||||
|
||||
if [ "${1}" = '--no-run' ]; then exit; fi
|
||||
if [ $norun = 1 ]; then exit; fi
|
||||
|
||||
echo "Assembling(piano).."
|
||||
bin/uxncli bin/asma.rom projects/examples/demos/piano.tal bin/piano.rom 2> bin/piano.log
|
||||
|
|
|
@ -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!
|
||||
|
8
mkfile
8
mkfile
|
@ -8,9 +8,11 @@ HFILES=\
|
|||
/sys/include/npe/stdio.h\
|
||||
src/devices/audio.h\
|
||||
src/devices/controller.h\
|
||||
src/devices/datetime.h\
|
||||
src/devices/file.h\
|
||||
src/devices/mouse.h\
|
||||
src/devices/screen.h\
|
||||
src/devices/system.h\
|
||||
src/uxn.h\
|
||||
|
||||
CLEANFILES=$TARG $ROM
|
||||
|
@ -31,19 +33,19 @@ bin:
|
|||
%.rom:Q: %.tal bin/uxnasm
|
||||
bin/uxnasm $stem.tal $target >/dev/null
|
||||
|
||||
bin/uxncli: file.$O uxncli.$O uxn.$O
|
||||
bin/uxncli: file.$O datetime.$O system.$O uxncli.$O uxn.$O
|
||||
$LD $LDFLAGS -o $target $prereq
|
||||
|
||||
bin/uxnasm: uxnasm.$O
|
||||
$LD $LDFLAGS -o $target $prereq
|
||||
|
||||
bin/uxnemu: uxnemu.$O audio.$O controller.$O file.$O mouse.$O screen.$O uxn.$O
|
||||
bin/uxnemu: audio.$O controller.$O datetime.$O file.$O mouse.$O screen.$O system.$O uxn.$O uxnemu.$O
|
||||
$LD $LDFLAGS -o $target $prereq
|
||||
|
||||
(uxnasm|uxncli|uxnemu|uxn)\.$O:R: src/\1.c
|
||||
$CC $CFLAGS -Isrc -o $target src/$stem1.c
|
||||
|
||||
(audio|controller|file|mouse|screen)\.$O:R: src/devices/\1.c
|
||||
(audio|controller|datetime|file|mouse|screen|system)\.$O:R: src/devices/\1.c
|
||||
$CC $CFLAGS -Isrc -o $target src/devices/$stem1.c
|
||||
|
||||
nuke:V: clean
|
||||
|
|
|
@ -22,14 +22,14 @@
|
|||
|
||||
( devices )
|
||||
|
||||
|00 @System &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 &debug $1 &halt $1
|
||||
|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
|
||||
|20 @Screen &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1
|
||||
|20 @Screen &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1
|
||||
|30 @Audio0 &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1
|
||||
|40 @Audio1 &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1
|
||||
|50 @Audio2 &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1
|
||||
|60 @Audio3 &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1
|
||||
|80 @Controller &vector $2 &button $1 &key $1
|
||||
|80 @Controller &vector $2 &button $1 &key $1 &func $1
|
||||
|90 @Mouse &vector $2 &x $2 &y $2 &state $1 &pad $3 &scrollx $2 &scrolly $2
|
||||
|a0 @File &vector $2 &success $2 &stat $2 &delete $1 &append $1 &name $2 &length $2 &read $2 &write $2
|
||||
|b0 @DateTime &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
( polycat )
|
||||
|
||||
%RTN { JMP2r }
|
||||
%2// { #01 SFT2 }
|
||||
%4// { #02 SFT2 }
|
||||
%!~ { NEQk NIP }
|
||||
%!~ { NEQk NIP }
|
||||
%AUTO-XADDR { #05 .Screen/auto DEO }
|
||||
|
||||
( devices )
|
||||
|
||||
|00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 ]
|
||||
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
|
||||
|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ]
|
||||
|00 @System &vector $2 &wst $1 &rst $1 &pad $4 &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
|
||||
|90 @Mouse &vector $2 &x $2 &y $2 &state $1 &pad $3 &scrollx $2 &scrolly $2
|
||||
|
||||
( variables )
|
||||
|
||||
|0000
|
||||
|
||||
@cat [ &x $2 &y $2 &timer $1 ]
|
||||
@pointer [ &x $2 &y $2 ]
|
||||
@cat
|
||||
&x $2 &y $2 &timer $1
|
||||
@pointer
|
||||
&x $2 &y $2
|
||||
|
||||
( program )
|
||||
|
||||
|
@ -26,124 +27,121 @@
|
|||
#0a3f .System/r DEO2
|
||||
#05df .System/g DEO2
|
||||
#0caf .System/b DEO2
|
||||
|
||||
( find center )
|
||||
.Screen/width DEI2 2// #0008 SUB2 .cat/x STZ2
|
||||
.Screen/height DEI2 4// DUP2k ADD2 ADD2 #0018 SUB2 .cat/y STZ2
|
||||
|
||||
( DOS resolution )
|
||||
#0140 .Screen/width DEO2
|
||||
#00c8 .Screen/height DEO2
|
||||
( vectors )
|
||||
;on-mouse .Mouse/vector DEO2
|
||||
;on-frame .Screen/vector DEO2
|
||||
|
||||
;draw-polycat JSR2
|
||||
;draw-ground JSR2
|
||||
( find center )
|
||||
.Screen/width DEI2 2// .cat/x STZ2
|
||||
.Screen/height DEI2 2// .cat/y STZ2
|
||||
( set screen mode )
|
||||
AUTO-XADDR
|
||||
( init )
|
||||
#ff ;draw-eye/last STA
|
||||
#ff ;draw-tail/last STA
|
||||
,draw-polycat JSR
|
||||
,draw-ground JSR
|
||||
|
||||
BRK
|
||||
|
||||
@on-mouse ( -> )
|
||||
|
||||
;draw-cursor JSR2
|
||||
|
||||
.Mouse/x DEI2 .cat/x LDZ2 GTH2 #50 SFT
|
||||
.Mouse/y DEI2 .cat/y LDZ2 GTH2 #60 SFT
|
||||
ADD #00 SWP ;draw-eye JSR2
|
||||
|
||||
BRK
|
||||
|
||||
@on-frame ( -> )
|
||||
|
||||
.cat/timer LDZ INC [ DUP ] .cat/timer STZ
|
||||
DUP ,&skip0 JCN #0000 ;draw-tail JSR2 &skip0
|
||||
[ #10 ] !~ ,&skip1 JCN #0001 ;draw-tail JSR2 &skip1
|
||||
[ #20 ] !~ ,&skip2 JCN #0002 ;draw-tail JSR2 &skip2
|
||||
[ #30 ] !~ ,&skip3 JCN #0003 ;draw-tail JSR2 &skip3
|
||||
[ #40 ] !~ ,&skip4 JCN #0002 ;draw-tail JSR2 &skip4
|
||||
[ #50 ] !~ ,&skip5 JCN #0001 ;draw-tail JSR2 &skip5
|
||||
POP
|
||||
|
||||
BRK
|
||||
|
||||
@draw-polycat ( -- )
|
||||
|
||||
( ears )
|
||||
.cat/y LDZ2 .Screen/y DEO2
|
||||
.cat/x LDZ2 STH2k #0008 SUB2 .Screen/x DEO2
|
||||
;ears .Screen/addr DEO2
|
||||
#81 .Screen/sprite DEO
|
||||
STH2r .Screen/x DEO2
|
||||
;ears #0010 ADD2 .Screen/addr DEO2
|
||||
#81 .Screen/sprite DEO
|
||||
|
||||
#0000 ,draw-eye JSR
|
||||
#0000 ,draw-tail JSR
|
||||
|
||||
RTN
|
||||
|
||||
@draw-eye ( quad* -- )
|
||||
|
||||
.cat/y LDZ2 #0008 ADD2 .Screen/y DEO2
|
||||
.cat/x LDZ2 STH2k #0008 SUB2 .Screen/x DEO2
|
||||
DUP2 ;eye ADD2 .Screen/addr DEO2
|
||||
( draw ) #81 .Screen/sprite DEO
|
||||
STH2r .Screen/x DEO2
|
||||
;eye #0010 ADD2 ADD2 .Screen/addr DEO2
|
||||
( draw ) #81 .Screen/sprite DEO
|
||||
|
||||
RTN
|
||||
|
||||
@draw-tail ( frame* -- )
|
||||
|
||||
.cat/y LDZ2 #0010 ADD2 .Screen/y DEO2
|
||||
.cat/x LDZ2 STH2k #0008 SUB2 .Screen/x DEO2
|
||||
;body .Screen/addr DEO2
|
||||
( draw ) #81 .Screen/sprite DEO
|
||||
STH2r .Screen/x DEO2
|
||||
#40 SFT2 ;body #0010 ADD2 ADD2 .Screen/addr DEO2
|
||||
( draw ) #81 .Screen/sprite DEO
|
||||
|
||||
RTN
|
||||
|
||||
@draw-cursor ( -- )
|
||||
|
||||
( clear last cursor )
|
||||
;cursor .Screen/addr DEO2
|
||||
.pointer/x LDZ2 .Screen/x DEO2
|
||||
.pointer/y LDZ2 .Screen/y DEO2
|
||||
#40 .Screen/sprite DEO
|
||||
|
||||
( record pointer positions )
|
||||
.Mouse/x DEI2 DUP2 .pointer/x STZ2 .Screen/x DEO2
|
||||
.Mouse/y DEI2 DUP2 .pointer/y STZ2 .Screen/y DEO2
|
||||
|
||||
( colorize on state )
|
||||
#41 [ .Mouse/state DEI #00 NEQ ] ADD .Screen/sprite DEO
|
||||
|
||||
RTN
|
||||
|
||||
@draw-ground ( -- )
|
||||
|
||||
.cat/y LDZ2 #0018 ADD2 .Screen/y DEO2
|
||||
.cat/x LDZ2 #0010 SUB2 .Screen/x DEO2
|
||||
;ground .Screen/addr DEO2
|
||||
|
||||
#10 #00
|
||||
#1000
|
||||
&loop
|
||||
( draw ) #01 .Screen/sprite DEO
|
||||
( sety ) .Screen/addr DEI2 #0008 ADD2 .Screen/addr DEO2
|
||||
( setx ) .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2
|
||||
( incr ) INC
|
||||
GTHk ,&loop JCN
|
||||
#01 .Screen/sprite DEO
|
||||
INC GTHk ,&loop JCN
|
||||
POP2
|
||||
|
||||
RTN
|
||||
JMP2r
|
||||
|
||||
@draw-polycat ( -- )
|
||||
|
||||
( ears )
|
||||
.cat/y LDZ2 .Screen/y DEO2
|
||||
.cat/x LDZ2 #0008 SUB2 .Screen/x DEO2
|
||||
;ears .Screen/addr DEO2
|
||||
#81 .Screen/sprite DEOk DEO
|
||||
( body )
|
||||
.cat/y LDZ2 #0010 ADD2 .Screen/y DEO2
|
||||
.cat/x LDZ2 #0008 SUB2 .Screen/x DEO2
|
||||
;body .Screen/addr DEO2
|
||||
#81 .Screen/sprite DEO
|
||||
( eye/tail )
|
||||
#00 ,draw-eye JSR
|
||||
#00 ,draw-tail JSR
|
||||
|
||||
JMP2r
|
||||
|
||||
@on-mouse ( -> )
|
||||
|
||||
.Mouse/x DEI2 .cat/x LDZ2 GTH2 #50 SFT
|
||||
.Mouse/y DEI2 .cat/y LDZ2 GTH2 #60 SFT
|
||||
ADD ,draw-eye JSR
|
||||
.cat/timer LDZ INC [ DUP ] .cat/timer STZ
|
||||
#04 SFT ,draw-tail JSR
|
||||
,draw-cursor JSR
|
||||
|
||||
BRK
|
||||
|
||||
@draw-eye ( quad -- )
|
||||
|
||||
DUP ,&last LDR NEQ ,&changed JCN
|
||||
POP JMP2r &changed
|
||||
( only redraw on change )
|
||||
DUP
|
||||
#00 SWP ;eye ADD2 .Screen/addr DEO2
|
||||
.cat/y LDZ2 #0008 ADD2 .Screen/y DEO2
|
||||
.cat/x LDZ2 #0008 SUB2 .Screen/x DEO2
|
||||
#81 .Screen/sprite DEOk DEO
|
||||
,&last STR
|
||||
|
||||
JMP2r
|
||||
&last $1
|
||||
|
||||
@draw-tail ( frame -- )
|
||||
|
||||
DUP ,&last LDR NEQ ,&changed JCN
|
||||
POP JMP2r &changed
|
||||
( only redraw on change )
|
||||
DUP
|
||||
;frames ROT #00 SWP ADD2 LDA
|
||||
#00 SWP #40 SFT2 ;body/tail ADD2
|
||||
.Screen/addr DEO2
|
||||
.cat/x LDZ2 .Screen/x DEO2
|
||||
.cat/y LDZ2 #0010 ADD2 .Screen/y DEO2
|
||||
#81 .Screen/sprite DEO
|
||||
,&last STR
|
||||
|
||||
JMP2r
|
||||
&last $1
|
||||
|
||||
@draw-cursor ( -- )
|
||||
|
||||
( last cursor )
|
||||
;cursor STH2k .Screen/addr DEO2
|
||||
.pointer/x LDZ2 .Screen/x DEO2
|
||||
.pointer/y LDZ2 .Screen/y DEO2
|
||||
#40 .Screen/sprite DEO
|
||||
( new cursor )
|
||||
STH2r .Screen/addr DEO2
|
||||
.Mouse/x DEI2 DUP2 .pointer/x STZ2 .Screen/x DEO2
|
||||
.Mouse/y DEI2 DUP2 .pointer/y STZ2 .Screen/y DEO2
|
||||
#41 .Mouse/state DEI #00 NEQ ADD .Screen/sprite DEO
|
||||
|
||||
JMP2r
|
||||
|
||||
@cursor
|
||||
80c0 e0f0 f8e0 1000
|
||||
|
||||
@frames
|
||||
00 01 02 03 02 01 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
@ears
|
||||
081c 3e3e 7f7f ffff 081c 3e3e 7f7f fffc
|
||||
081c 3c3e 7e7e ffff 081c 3c3e 7e7e ff1f
|
||||
|
||||
@eye
|
||||
ffff ffff ff7f 3f0f f7ef cfe7 f07c 3f0f
|
||||
ffff ffff fffe fcf0 87c3 c183 071e fcf0
|
||||
|
@ -153,16 +151,15 @@ RTN
|
|||
ffff ffff fffe fcf0 0783 c1c3 871e fcf0
|
||||
ffff ffff ff7f 3f0f f0e0 c1e1 f07c 3f0f
|
||||
ffff ffff fffe fcf0 07f3 f9fb f71e fcf0
|
||||
|
||||
@body
|
||||
0707 0707 0302 0200 0107 0707 0300 0000
|
||||
&tail
|
||||
e0f0 f0e0 e080 8000 c0f2 f9f9 fef8 b000
|
||||
e0f0 f0e0 e080 8000 c0f2 f9f9 fef8 b000
|
||||
e0f0 f0e0 e080 8000 c0f2 faf9 fef8 b000
|
||||
e0f0 f0e0 e080 8000 c0f1 faf9 fef8 b000
|
||||
0707 0707 0f08 1000 0307 0707 0f00 0000
|
||||
e0e0 e0e0 e080 8000 f2f9 f9fe b884 8400
|
||||
|
||||
@ground
|
||||
bf00 5c02 0202 020c ef10 6f90 8080 8074
|
||||
ff00 fe01 0100 0116 fd00 3c40 4040 4028
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
( dev/console )
|
||||
|
||||
|00 @System $e &debug
|
||||
|10 @Console $8 &write
|
||||
%HALT { #010f DEO }
|
||||
%EMIT { #18 DEO }
|
||||
|
||||
( init )
|
||||
|
||||
|
@ -9,11 +9,11 @@
|
|||
|
||||
;hello-word
|
||||
&while
|
||||
( send ) LDAk .Console/write DEO
|
||||
( send ) LDAk EMIT
|
||||
INC2 LDAk ,&while JCN
|
||||
POP2
|
||||
( show debugger ) #01 .System/debug DEO
|
||||
( stop ) HALT
|
||||
|
||||
BRK
|
||||
|
||||
@hello-word "Hello 20 "Uxn!
|
||||
@hello-word "Hello 20 "Uxn! $1
|
|
@ -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
|
|
@ -90,7 +90,7 @@ audio_get_vu(UxnAudio *c)
|
|||
int i;
|
||||
Sint32 sum[2] = {0, 0};
|
||||
if(!c->advance || !c->period) return 0;
|
||||
for(i = 0; i < 2; ++i) {
|
||||
for(i = 0; i < 2; i++) {
|
||||
if(!c->volume[i]) continue;
|
||||
sum[i] = 1 + envelope(c, c->age) * c->volume[i] / 0x800;
|
||||
if(sum[i] > 0xf) sum[i] = 0xf;
|
||||
|
|
|
@ -28,4 +28,4 @@ extern UxnAudio uxn_audio[POLYPHONY];
|
|||
Uint8 audio_get_vu(UxnAudio *c);
|
||||
int audio_render(UxnAudio *c, Sint16 *sample, Sint16 *end);
|
||||
void audio_start(UxnAudio *c, Uint16 adsr, Uint8 pitch);
|
||||
void audio_finished_handler(UxnAudio *c);
|
||||
void audio_finished_handler(UxnAudio *c);
|
||||
|
|
|
@ -39,4 +39,14 @@ controller_key(Device *d, Uint8 key)
|
|||
uxn_eval(d->u, d->vector);
|
||||
d->dat[3] = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
controller_special(Device *d, Uint8 key)
|
||||
{
|
||||
if(key) {
|
||||
d->dat[4] = key;
|
||||
uxn_eval(d->u, d->vector);
|
||||
d->dat[4] = 0x00;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,4 +12,5 @@ WITH REGARD TO THIS SOFTWARE.
|
|||
|
||||
void controller_down(Device *d, Uint8 mask);
|
||||
void controller_up(Device *d, Uint8 mask);
|
||||
void controller_key(Device *d, Uint8 key);
|
||||
void controller_key(Device *d, Uint8 key);
|
||||
void controller_special(Device *d, Uint8 key);
|
||||
|
|
|
@ -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);
|
|
@ -127,7 +127,7 @@ file_stat(void *dest, Uint16 len)
|
|||
{
|
||||
char *basename = strrchr(current_filename, '/');
|
||||
if(basename != NULL)
|
||||
++basename;
|
||||
basename++;
|
||||
else
|
||||
basename = current_filename;
|
||||
return get_entry(dest, len, current_filename, basename, 0);
|
||||
|
@ -144,12 +144,37 @@ file_delete(void)
|
|||
void
|
||||
file_deo(Device *d, Uint8 port)
|
||||
{
|
||||
Uint16 a, b, res;
|
||||
switch(port) {
|
||||
case 0x1: d->vector = peek16(d->dat, 0x0); break;
|
||||
case 0x9: poke16(d->dat, 0x2, file_init(&d->mem[peek16(d->dat, 0x8)])); break;
|
||||
case 0xd: poke16(d->dat, 0x2, file_read(&d->mem[peek16(d->dat, 0xc)], peek16(d->dat, 0xa))); break;
|
||||
case 0xf: poke16(d->dat, 0x2, file_write(&d->mem[peek16(d->dat, 0xe)], peek16(d->dat, 0xa), d->dat[0x7])); break;
|
||||
case 0x5: poke16(d->dat, 0x2, file_stat(&d->mem[peek16(d->dat, 0x4)], peek16(d->dat, 0xa))); break;
|
||||
case 0x6: poke16(d->dat, 0x2, file_delete()); break;
|
||||
case 0x1:
|
||||
DEVPEEK16(d->vector, 0x0);
|
||||
break;
|
||||
case 0x5:
|
||||
DEVPEEK16(a, 0x4);
|
||||
DEVPEEK16(b, 0xa);
|
||||
res = file_stat(&d->mem[a], b);
|
||||
DEVPOKE16(0x2, res);
|
||||
break;
|
||||
case 0x6:
|
||||
res = file_delete();
|
||||
DEVPOKE16(0x2, res);
|
||||
break;
|
||||
case 0x9:
|
||||
DEVPEEK16(a, 0x8);
|
||||
res = file_init(&d->mem[a]);
|
||||
DEVPOKE16(0x2, res);
|
||||
break;
|
||||
case 0xd:
|
||||
DEVPEEK16(a, 0xc);
|
||||
DEVPEEK16(b, 0xa);
|
||||
res = file_read(&d->mem[a], b);
|
||||
DEVPOKE16(0x2, res);
|
||||
break;
|
||||
case 0xf:
|
||||
DEVPEEK16(a, 0xe);
|
||||
DEVPEEK16(b, 0xa);
|
||||
res = file_write(&d->mem[a], b, d->dat[0x7]);
|
||||
DEVPOKE16(0x2, res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,4 +10,4 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|||
WITH REGARD TO THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
void file_deo(Device *d, Uint8 port);
|
||||
void file_deo(Device *d, Uint8 port);
|
||||
|
|
|
@ -30,17 +30,17 @@ mouse_up(Device *d, Uint8 mask)
|
|||
void
|
||||
mouse_pos(Device *d, Uint16 x, Uint16 y)
|
||||
{
|
||||
poke16(d->dat, 0x2, x);
|
||||
poke16(d->dat, 0x4, y);
|
||||
DEVPOKE16(0x2, x);
|
||||
DEVPOKE16(0x4, y);
|
||||
uxn_eval(d->u, d->vector);
|
||||
}
|
||||
|
||||
void
|
||||
mouse_scroll(Device *d, Uint16 x, Uint16 y)
|
||||
{
|
||||
poke16(d->dat, 0xa, x);
|
||||
poke16(d->dat, 0xc, -y);
|
||||
DEVPOKE16(0xa, x);
|
||||
DEVPOKE16(0xc, -y);
|
||||
uxn_eval(d->u, d->vector);
|
||||
poke16(d->dat, 0xa, 0);
|
||||
poke16(d->dat, 0xc, 0);
|
||||
DEVPOKE16(0xa, 0);
|
||||
DEVPOKE16(0xc, 0);
|
||||
}
|
||||
|
|
|
@ -22,24 +22,6 @@ static Uint8 blending[5][16] = {
|
|||
{2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2},
|
||||
{1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}};
|
||||
|
||||
static Uint8 font[][8] = {
|
||||
{0x00, 0x7c, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7c},
|
||||
{0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10},
|
||||
{0x00, 0x7c, 0x82, 0x02, 0x7c, 0x80, 0x80, 0xfe},
|
||||
{0x00, 0x7c, 0x82, 0x02, 0x1c, 0x02, 0x82, 0x7c},
|
||||
{0x00, 0x0c, 0x14, 0x24, 0x44, 0x84, 0xfe, 0x04},
|
||||
{0x00, 0xfe, 0x80, 0x80, 0x7c, 0x02, 0x82, 0x7c},
|
||||
{0x00, 0x7c, 0x82, 0x80, 0xfc, 0x82, 0x82, 0x7c},
|
||||
{0x00, 0x7c, 0x82, 0x02, 0x1e, 0x02, 0x02, 0x02},
|
||||
{0x00, 0x7c, 0x82, 0x82, 0x7c, 0x82, 0x82, 0x7c},
|
||||
{0x00, 0x7c, 0x82, 0x82, 0x7e, 0x02, 0x82, 0x7c},
|
||||
{0x00, 0x7c, 0x82, 0x02, 0x7e, 0x82, 0x82, 0x7e},
|
||||
{0x00, 0xfc, 0x82, 0x82, 0xfc, 0x82, 0x82, 0xfc},
|
||||
{0x00, 0x7c, 0x82, 0x80, 0x80, 0x80, 0x82, 0x7c},
|
||||
{0x00, 0xfc, 0x82, 0x82, 0x82, 0x82, 0x82, 0xfc},
|
||||
{0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x82, 0x7c},
|
||||
{0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x80, 0x80}};
|
||||
|
||||
static void
|
||||
screen_write(UxnScreen *p, Layer *layer, Uint16 x, Uint16 y, Uint8 color)
|
||||
{
|
||||
|
@ -56,7 +38,7 @@ static void
|
|||
screen_blit(UxnScreen *p, Layer *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy, Uint8 twobpp)
|
||||
{
|
||||
int v, h, opaque = blending[4][color];
|
||||
for(v = 0; v < 8; ++v) {
|
||||
for(v = 0; v < 8; v++) {
|
||||
Uint16 c = sprite[v] | (twobpp ? sprite[v + 8] : 0) << 8;
|
||||
for(h = 7; h >= 0; --h, c >>= 1) {
|
||||
Uint8 ch = (c & 1) | ((c >> 7) & 2);
|
||||
|
@ -109,7 +91,7 @@ void
|
|||
screen_clear(UxnScreen *p, Layer *layer)
|
||||
{
|
||||
Uint32 i, size = p->width * p->height;
|
||||
for(i = 0; i < size; ++i)
|
||||
for(i = 0; i < size; i++)
|
||||
layer->pixels[i] = 0x00;
|
||||
layer->changed = 1;
|
||||
}
|
||||
|
@ -119,42 +101,13 @@ void
|
|||
screen_redraw(UxnScreen *p, Uint32 *pixels)
|
||||
{
|
||||
Uint32 i, size = p->width * p->height, palette[16];
|
||||
for(i = 0; i < 16; ++i)
|
||||
for(i = 0; i < 16; i++)
|
||||
palette[i] = p->palette[(i >> 2) ? (i >> 2) : (i & 3)];
|
||||
for(i = 0; i < size; ++i)
|
||||
for(i = 0; i < size; i++)
|
||||
pixels[i] = palette[p->fg.pixels[i] << 2 | p->bg.pixels[i]];
|
||||
p->fg.changed = p->bg.changed = 0;
|
||||
}
|
||||
|
||||
void
|
||||
screen_debug(UxnScreen *p, Uint8 *stack, Uint8 wptr, Uint8 rptr, Uint8 *memory)
|
||||
{
|
||||
Uint8 i, x, y, b;
|
||||
for(i = 0; i < 0x20; ++i) {
|
||||
x = ((i % 8) * 3 + 1) * 8, y = (i / 8 + 1) * 8, b = stack[i];
|
||||
/* working stack */
|
||||
screen_blit(p, &p->fg, x, y, font[(b >> 4) & 0xf], 1 + (wptr == i) * 0x7, 0, 0, 0);
|
||||
screen_blit(p, &p->fg, x + 8, y, font[b & 0xf], 1 + (wptr == i) * 0x7, 0, 0, 0);
|
||||
y = 0x28 + (i / 8 + 1) * 8;
|
||||
b = memory[i];
|
||||
/* return stack */
|
||||
screen_blit(p, &p->fg, x, y, font[(b >> 4) & 0xf], 3, 0, 0, 0);
|
||||
screen_blit(p, &p->fg, x + 8, y, font[b & 0xf], 3, 0, 0, 0);
|
||||
}
|
||||
/* return pointer */
|
||||
screen_blit(p, &p->fg, 0x8, y + 0x10, font[(rptr >> 4) & 0xf], 0x2, 0, 0, 0);
|
||||
screen_blit(p, &p->fg, 0x10, y + 0x10, font[rptr & 0xf], 0x2, 0, 0, 0);
|
||||
/* guides */
|
||||
for(x = 0; x < 0x10; ++x) {
|
||||
screen_write(p, &p->fg, x, p->height / 2, 2);
|
||||
screen_write(p, &p->fg, p->width - x, p->height / 2, 2);
|
||||
screen_write(p, &p->fg, p->width / 2, p->height - x, 2);
|
||||
screen_write(p, &p->fg, p->width / 2, x, 2);
|
||||
screen_write(p, &p->fg, p->width / 2 - 0x10 / 2 + x, p->height / 2, 2);
|
||||
screen_write(p, &p->fg, p->width / 2, p->height / 2 - 0x10 / 2 + x, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* IO */
|
||||
|
||||
Uint8
|
||||
|
@ -165,6 +118,8 @@ screen_dei(Device *d, Uint8 port)
|
|||
case 0x3: return uxn_screen.width;
|
||||
case 0x4: return uxn_screen.height >> 8;
|
||||
case 0x5: return uxn_screen.height;
|
||||
case 0x6:
|
||||
|
||||
default: return d->dat[port];
|
||||
}
|
||||
}
|
||||
|
@ -173,29 +128,36 @@ void
|
|||
screen_deo(Device *d, Uint8 port)
|
||||
{
|
||||
switch(port) {
|
||||
case 0x1: d->vector = peek16(d->dat, 0x0); break;
|
||||
case 0x1: DEVPEEK16(d->vector, 0x0); break;
|
||||
case 0x5:
|
||||
if(!FIXED_SIZE) set_size(peek16(d->dat, 0x2), peek16(d->dat, 0x4), 1);
|
||||
if(!FIXED_SIZE) {
|
||||
Uint16 w, h;
|
||||
DEVPEEK16(w, 0x2);
|
||||
DEVPEEK16(h, 0x4);
|
||||
set_size(w, h, 1);
|
||||
}
|
||||
break;
|
||||
case 0xe: {
|
||||
Uint16 x = peek16(d->dat, 0x8);
|
||||
Uint16 y = peek16(d->dat, 0xa);
|
||||
Uint16 x, y;
|
||||
Uint8 layer = d->dat[0xe] & 0x40;
|
||||
DEVPEEK16(x, 0x8);
|
||||
DEVPEEK16(y, 0xa);
|
||||
screen_write(&uxn_screen, layer ? &uxn_screen.fg : &uxn_screen.bg, x, y, d->dat[0xe] & 0x3);
|
||||
if(d->dat[0x6] & 0x01) poke16(d->dat, 0x8, x + 1); /* auto x+1 */
|
||||
if(d->dat[0x6] & 0x02) poke16(d->dat, 0xa, y + 1); /* auto y+1 */
|
||||
if(d->dat[0x6] & 0x01) DEVPOKE16(0x8, x + 1); /* auto x+1 */
|
||||
if(d->dat[0x6] & 0x02) DEVPOKE16(0xa, y + 1); /* auto y+1 */
|
||||
break;
|
||||
}
|
||||
case 0xf: {
|
||||
Uint16 x = peek16(d->dat, 0x8);
|
||||
Uint16 y = peek16(d->dat, 0xa);
|
||||
Layer *layer = (d->dat[0xf] & 0x40) ? &uxn_screen.fg : &uxn_screen.bg;
|
||||
Uint8 *addr = &d->mem[peek16(d->dat, 0xc)];
|
||||
Uint16 x, y, addr;
|
||||
Uint8 twobpp = !!(d->dat[0xf] & 0x80);
|
||||
screen_blit(&uxn_screen, layer, x, y, addr, d->dat[0xf] & 0xf, d->dat[0xf] & 0x10, d->dat[0xf] & 0x20, twobpp);
|
||||
if(d->dat[0x6] & 0x04) poke16(d->dat, 0xc, peek16(d->dat, 0xc) + 8 + twobpp * 8); /* auto addr+8 / auto addr+16 */
|
||||
if(d->dat[0x6] & 0x01) poke16(d->dat, 0x8, x + 8); /* auto x+8 */
|
||||
if(d->dat[0x6] & 0x02) poke16(d->dat, 0xa, y + 8); /* auto y+8 */
|
||||
Layer *layer = (d->dat[0xf] & 0x40) ? &uxn_screen.fg : &uxn_screen.bg;
|
||||
DEVPEEK16(x, 0x8);
|
||||
DEVPEEK16(y, 0xa);
|
||||
DEVPEEK16(addr, 0xc);
|
||||
screen_blit(&uxn_screen, layer, x, y, &d->mem[addr], d->dat[0xf] & 0xf, d->dat[0xf] & 0x10, d->dat[0xf] & 0x20, twobpp);
|
||||
if(d->dat[0x6] & 0x04) DEVPOKE16(0xc, addr + 8 + twobpp * 8); /* auto addr+length */
|
||||
if(d->dat[0x6] & 0x01) DEVPOKE16(0x8, x + 8); /* auto x+8 */
|
||||
if(d->dat[0x6] & 0x02) DEVPOKE16(0xa, y + 8); /* auto y+8 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ void screen_palette(UxnScreen *p, Uint8 *addr);
|
|||
void screen_resize(UxnScreen *p, Uint16 width, Uint16 height);
|
||||
void screen_clear(UxnScreen *p, Layer *layer);
|
||||
void screen_redraw(UxnScreen *p, Uint32 *pixels);
|
||||
void screen_debug(UxnScreen *p, Uint8 *stack, Uint8 wptr, Uint8 rptr, Uint8 *memory);
|
||||
|
||||
Uint8 screen_dei(Device *d, Uint8 port);
|
||||
void screen_deo(Device *d, Uint8 port);
|
||||
void screen_deo(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;
|
4040
src/uxn-fast.c
4040
src/uxn-fast.c
File diff suppressed because it is too large
Load Diff
194
src/uxn.c
194
src/uxn.c
|
@ -1,8 +1,7 @@
|
|||
#include "uxn.h"
|
||||
|
||||
/*
|
||||
Copyright (u) 2021 Devine Lu Linvega
|
||||
Copyright (u) 2021 Andrew Alderwick
|
||||
Copyright (u) 2022 Devine Lu Linvega, Andrew Alderwick, Andrew Richards
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -12,136 +11,113 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|||
WITH REGARD TO THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#define MODE_SHORT 0x20
|
||||
#define MODE_RETURN 0x40
|
||||
#define MODE_KEEP 0x80
|
||||
|
||||
#pragma mark - Operations
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
/* Utilities */
|
||||
static void (*push)(Stack *s, Uint16 a);
|
||||
static Uint16 (*pop8)(Stack *s);
|
||||
static Uint16 (*pop)(Stack *s);
|
||||
static void (*poke)(Uint8 *m, Uint16 a, Uint16 b);
|
||||
static Uint16 (*peek)(Uint8 *m, Uint16 a);
|
||||
static void (*devw)(Device *d, Uint8 a, Uint16 b);
|
||||
static Uint16 (*devr)(Device *d, Uint8 a);
|
||||
static void (*warp)(Uxn *u, Uint16 a);
|
||||
static void (*pull)(Uxn *u);
|
||||
/* byte mode */
|
||||
static void push8(Stack *s, Uint16 a) { if(s->ptr == 0xff) { s->error = 2; return; } s->dat[s->ptr++] = a; }
|
||||
static Uint16 pop8k(Stack *s) { if(s->kptr == 0) { s->error = 1; return 0; } return s->dat[--s->kptr]; }
|
||||
static Uint16 pop8d(Stack *s) { if(s->ptr == 0) { s->error = 1; return 0; } return s->dat[--s->ptr]; }
|
||||
static void poke8(Uint8 *m, Uint16 a, Uint16 b) { m[a] = b; }
|
||||
static Uint16 peek8(Uint8 *m, Uint16 a) { return m[a]; }
|
||||
static void devw8(Device *d, Uint8 a, Uint16 b) { d->dat[a & 0xf] = b; d->deo(d, a & 0x0f); }
|
||||
static Uint16 devr8(Device *d, Uint8 a) { return d->dei(d, a & 0x0f); }
|
||||
static void warp8(Uxn *u, Uint16 a){ u->ram.ptr += (Sint8)a; }
|
||||
static void pull8(Uxn *u){ push8(u->src, peek8(u->ram.dat, u->ram.ptr++)); }
|
||||
/* short mode */
|
||||
static void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); }
|
||||
static Uint16 pop16(Stack *s) { Uint8 a = pop8(s), b = pop8(s); return a + (b << 8); }
|
||||
void poke16(Uint8 *m, Uint16 a, Uint16 b) { poke8(m, a, b >> 8); poke8(m, a + 1, b); }
|
||||
Uint16 peek16(Uint8 *m, Uint16 a) { return (peek8(m, a) << 8) + peek8(m, a + 1); }
|
||||
static void devw16(Device *d, Uint8 a, Uint16 b) { devw8(d, a, b >> 8); devw8(d, a + 1, b); }
|
||||
static Uint16 devr16(Device *d, Uint8 a) { return (devr8(d, a) << 8) + devr8(d, a + 1); }
|
||||
static void warp16(Uxn *u, Uint16 a){ u->ram.ptr = a; }
|
||||
static void pull16(Uxn *u){ push16(u->src, peek16(u->ram.dat, u->ram.ptr++)); u->ram.ptr++; }
|
||||
/* a,b,c: general use. bs: byte/short bool. src, dst: stack ptrs, swapped in return mode.
|
||||
pc: program counter. sp: ptr to src stack ptr. kptr: "keep" mode copy of src stack ptr.
|
||||
x,y: macro in params. d: macro in device. j,k,dev: macro temp variables. o: macro out param. */
|
||||
|
||||
#pragma mark - Core
|
||||
#define PUSH8(s, x) { if(s->ptr == 0xff) { errcode = 2; goto err; } s->dat[s->ptr++] = (x); }
|
||||
#define PUSH16(s, x) { if((j = s->ptr) >= 0xfe) { errcode = 2; goto err; } k = (x); s->dat[j] = k >> 8; s->dat[j + 1] = k; s->ptr = j + 2; }
|
||||
#define PUSH(s, x) { if(bs) { PUSH16(s, (x)) } else { PUSH8(s, (x)) } }
|
||||
#define POP8(o) { if(!(j = *sp)) { errcode = 0; goto err; } o = (Uint16)src->dat[--j]; *sp = j; }
|
||||
#define POP16(o) { if((j = *sp) <= 1) { errcode = 0; goto err; } o = src->dat[j - 1]; o += src->dat[j - 2] << 8; *sp = j - 2; }
|
||||
#define POP(o) { if(bs) { POP16(o) } else { POP8(o) } }
|
||||
#define POKE(x, y) { if(bs) { u->ram[(x)] = (y) >> 8; u->ram[(x) + 1] = (y); } else { u->ram[(x)] = y; } }
|
||||
#define PEEK16(o, x) { o = (u->ram[(x)] << 8) + u->ram[(x) + 1]; }
|
||||
#define PEEK(o, x) { if(bs) { PEEK16(o, x) } else { o = u->ram[(x)]; } }
|
||||
#define DEVR(o, d, x) { dev = (d); o = dev->dei(dev, (x) & 0x0f); if(bs) { o = (o << 8) + dev->dei(dev, ((x) + 1) & 0x0f); } }
|
||||
#define DEVW8(x, y) { dev->dat[(x) & 0xf] = y; dev->deo(dev, (x) & 0x0f); }
|
||||
#define DEVW(d, x, y) { dev = (d); if(bs) { DEVW8((x), (y) >> 8); DEVW8((x) + 1, (y)); } else { DEVW8((x), (y)) } }
|
||||
#define WARP(x) { if(bs) pc = (x); else pc += (Sint8)(x); }
|
||||
|
||||
int
|
||||
uxn_eval(Uxn *u, Uint16 vec)
|
||||
uxn_eval(Uxn *u, Uint16 pc)
|
||||
{
|
||||
Uint8 instr;
|
||||
Uint16 a,b,c;
|
||||
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++])) {
|
||||
unsigned int a, b, c, j, k, bs, instr, errcode;
|
||||
Uint8 kptr, *sp;
|
||||
Stack *src, *dst;
|
||||
Device *dev;
|
||||
if(!pc || u->dev[0].dat[0xf]) return 0;
|
||||
if(u->wst->ptr > 0xf8) u->wst->ptr = 0xf8;
|
||||
while((instr = u->ram[pc++])) {
|
||||
/* Return Mode */
|
||||
if(instr & MODE_RETURN) {
|
||||
u->src = &u->rst;
|
||||
u->dst = &u->wst;
|
||||
if(instr & 0x40) {
|
||||
src = u->rst; dst = u->wst;
|
||||
} else {
|
||||
u->src = &u->wst;
|
||||
u->dst = &u->rst;
|
||||
src = u->wst; dst = u->rst;
|
||||
}
|
||||
/* Keep Mode */
|
||||
if(instr & MODE_KEEP) {
|
||||
pop8 = pop8k;
|
||||
u->src->kptr = u->src->ptr;
|
||||
if(instr & 0x80) {
|
||||
kptr = src->ptr;
|
||||
sp = &kptr;
|
||||
} else {
|
||||
pop8 = pop8d;
|
||||
sp = &src->ptr;
|
||||
}
|
||||
/* Short Mode */
|
||||
if(instr & MODE_SHORT) {
|
||||
push = push16; pop = pop16;
|
||||
poke = poke16; peek = peek16;
|
||||
devw = devw16; devr = devr16;
|
||||
warp = warp16; pull = pull16;
|
||||
} else {
|
||||
push = push8; pop = pop8;
|
||||
poke = poke8; peek = peek8;
|
||||
devw = devw8; devr = devr8;
|
||||
warp = warp8; pull = pull8;
|
||||
bs = instr & 0x20 ? 1 : 0;
|
||||
switch(instr & 0x1f) {
|
||||
/* Stack */
|
||||
case 0x00: /* LIT */ if(bs) { PEEK16(a, pc) PUSH16(src, a) pc += 2; }
|
||||
else { a = u->ram[pc]; PUSH8(src, a) pc++; } break;
|
||||
case 0x01: /* INC */ POP(a) PUSH(src, a + 1) break;
|
||||
case 0x02: /* POP */ POP(a) break;
|
||||
case 0x03: /* DUP */ POP(a) PUSH(src, a) PUSH(src, a) break;
|
||||
case 0x04: /* NIP */ POP(a) POP(b) PUSH(src, a) break;
|
||||
case 0x05: /* SWP */ POP(a) POP(b) PUSH(src, a) PUSH(src, b) break;
|
||||
case 0x06: /* OVR */ POP(a) POP(b) PUSH(src, b) PUSH(src, a) PUSH(src, b) break;
|
||||
case 0x07: /* ROT */ POP(a) POP(b) POP(c) PUSH(src, b) PUSH(src, a) PUSH(src, c) break;
|
||||
/* Logic */
|
||||
case 0x08: /* EQU */ POP(a) POP(b) PUSH8(src, b == a) break;
|
||||
case 0x09: /* NEQ */ POP(a) POP(b) PUSH8(src, b != a) break;
|
||||
case 0x0a: /* GTH */ POP(a) POP(b) PUSH8(src, b > a) break;
|
||||
case 0x0b: /* LTH */ POP(a) POP(b) PUSH8(src, b < a) break;
|
||||
case 0x0c: /* JMP */ POP(a) WARP(a) break;
|
||||
case 0x0d: /* JCN */ POP(a) POP8(b) if(b) WARP(a) break;
|
||||
case 0x0e: /* JSR */ POP(a) PUSH16(dst, pc) WARP(a) break;
|
||||
case 0x0f: /* STH */ POP(a) PUSH(dst, a) break;
|
||||
/* Memory */
|
||||
case 0x10: /* LDZ */ POP8(a) PEEK(b, a) PUSH(src, b) break;
|
||||
case 0x11: /* STZ */ POP8(a) POP(b) POKE(a, b) break;
|
||||
case 0x12: /* LDR */ POP8(a) PEEK(b, pc + (Sint8)a) PUSH(src, b) break;
|
||||
case 0x13: /* STR */ POP8(a) POP(b) c = pc + (Sint8)a; POKE(c, b) break;
|
||||
case 0x14: /* LDA */ POP16(a) PEEK(b, a) PUSH(src, b) break;
|
||||
case 0x15: /* STA */ POP16(a) POP(b) POKE(a, b) break;
|
||||
case 0x16: /* DEI */ POP8(a) DEVR(b, &u->dev[a >> 4], a) PUSH(src, b) break;
|
||||
case 0x17: /* DEO */ POP8(a) POP(b) DEVW(&u->dev[a >> 4], a, b) break;
|
||||
/* Arithmetic */
|
||||
case 0x18: /* ADD */ POP(a) POP(b) PUSH(src, b + a) break;
|
||||
case 0x19: /* SUB */ POP(a) POP(b) PUSH(src, b - a) break;
|
||||
case 0x1a: /* MUL */ POP(a) POP(b) PUSH(src, (Uint32)b * a) break;
|
||||
case 0x1b: /* DIV */ POP(a) POP(b) if(a == 0) { errcode = 4; goto err; } PUSH(src, b / a) break;
|
||||
case 0x1c: /* AND */ POP(a) POP(b) PUSH(src, b & a) break;
|
||||
case 0x1d: /* ORA */ POP(a) POP(b) PUSH(src, b | a) break;
|
||||
case 0x1e: /* EOR */ POP(a) POP(b) PUSH(src, b ^ a) break;
|
||||
case 0x1f: /* SFT */ POP8(a) POP(b) c = b >> (a & 0x0f) << ((a & 0xf0) >> 4); PUSH(src, c) break;
|
||||
}
|
||||
switch(instr & 0x1f){
|
||||
/* Stack */
|
||||
case 0x00: /* LIT */ pull(u); break;
|
||||
case 0x01: /* INC */ a = pop(u->src); push(u->src, a + 1); break;
|
||||
case 0x02: /* POP */ pop(u->src); break;
|
||||
case 0x03: /* DUP */ a = pop(u->src); push(u->src, a); push(u->src, a); break;
|
||||
case 0x04: /* NIP */ a = pop(u->src); pop(u->src); push(u->src, a); break;
|
||||
case 0x05: /* SWP */ a = pop(u->src), b = pop(u->src); push(u->src, a); push(u->src, b); break;
|
||||
case 0x06: /* OVR */ a = pop(u->src), b = pop(u->src); push(u->src, b); push(u->src, a); push(u->src, b); break;
|
||||
case 0x07: /* ROT */ a = pop(u->src), b = pop(u->src), c = pop(u->src); push(u->src, b); push(u->src, a); push(u->src, c); break;
|
||||
/* Logic */
|
||||
case 0x08: /* EQU */ a = pop(u->src), b = pop(u->src); push8(u->src, b == a); break;
|
||||
case 0x09: /* NEQ */ a = pop(u->src), b = pop(u->src); push8(u->src, b != a); break;
|
||||
case 0x0a: /* GTH */ a = pop(u->src), b = pop(u->src); push8(u->src, b > a); break;
|
||||
case 0x0b: /* LTH */ a = pop(u->src), b = pop(u->src); push8(u->src, b < a); break;
|
||||
case 0x0c: /* JMP */ a = pop(u->src); warp(u, a); break;
|
||||
case 0x0d: /* JCN */ a = pop(u->src); if(pop8(u->src)) warp(u, a); break;
|
||||
case 0x0e: /* JSR */ a = pop(u->src); push16(u->dst, u->ram.ptr); warp(u, a); break;
|
||||
case 0x0f: /* STH */ a = pop(u->src); push(u->dst, a); break;
|
||||
/* Memory */
|
||||
case 0x10: /* LDZ */ a = pop8(u->src); push(u->src, peek(u->ram.dat, a)); break;
|
||||
case 0x11: /* STZ */ a = pop8(u->src); b = pop(u->src); poke(u->ram.dat, a, b); break;
|
||||
case 0x12: /* LDR */ a = pop8(u->src); push(u->src, peek(u->ram.dat, u->ram.ptr + (Sint8)a)); break;
|
||||
case 0x13: /* STR */ a = pop8(u->src); b = pop(u->src); poke(u->ram.dat, u->ram.ptr + (Sint8)a, b); break;
|
||||
case 0x14: /* LDA */ a = pop16(u->src); push(u->src, peek(u->ram.dat, a)); break;
|
||||
case 0x15: /* STA */ a = pop16(u->src); b = pop(u->src); poke(u->ram.dat, a, b); break;
|
||||
case 0x16: /* DEI */ a = pop8(u->src); push(u->src, devr(&u->dev[a >> 4], a)); break;
|
||||
case 0x17: /* DEO */ a = pop8(u->src); b = pop(u->src); devw(&u->dev[a >> 4], a, b); break;
|
||||
/* Arithmetic */
|
||||
case 0x18: /* ADD */ a = pop(u->src), b = pop(u->src); push(u->src, b + a); break;
|
||||
case 0x19: /* SUB */ a = pop(u->src), b = pop(u->src); push(u->src, b - a); break;
|
||||
case 0x1a: /* MUL */ a = pop(u->src), b = pop(u->src); push(u->src, (Uint32)b * a); break;
|
||||
case 0x1b: /* DIV */ a = pop(u->src), b = pop(u->src); if(a == 0) { u->src->error = 3; a = 1; } push(u->src, b / a); break;
|
||||
case 0x1c: /* AND */ a = pop(u->src), b = pop(u->src); push(u->src, b & a); break;
|
||||
case 0x1d: /* ORA */ a = pop(u->src), b = pop(u->src); push(u->src, b | a); break;
|
||||
case 0x1e: /* EOR */ a = pop(u->src), b = pop(u->src); push(u->src, b ^ a); break;
|
||||
case 0x1f: /* SFT */ a = pop8(u->src), b = pop(u->src); push(u->src, b >> (a & 0x0f) << ((a & 0xf0) >> 4)); break;
|
||||
}
|
||||
if(u->wst.error) return uxn_halt(u, u->wst.error, "Working-stack", instr);
|
||||
if(u->rst.error) return uxn_halt(u, u->rst.error, "Return-stack", instr);
|
||||
}
|
||||
return 1;
|
||||
|
||||
err:
|
||||
/* set 1 in errcode if it involved the return stack instead of the working stack */
|
||||
/* (stack overflow & ( opcode was STH / JSR )) ^ Return Mode */
|
||||
errcode |= ((errcode >> 1 & ((instr & 0x1e) == 0x0e)) ^ instr >> 6) & 1;
|
||||
return uxn_halt(u, errcode, pc - 1);
|
||||
}
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
int
|
||||
uxn_boot(Uxn *u)
|
||||
uxn_boot(Uxn *u, Uint8 *ram, Uint8 *devpage, Stack *wst, Stack *rst)
|
||||
{
|
||||
Uint32 i;
|
||||
char *cptr = (char *)u;
|
||||
for(i = 0; i < sizeof(*u); ++i)
|
||||
for(i = 0; i < sizeof(*u); i++)
|
||||
cptr[i] = 0x00;
|
||||
u->ram = ram;
|
||||
u->devpage = devpage;
|
||||
u->wst = wst;
|
||||
u->rst = rst;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -149,10 +125,10 @@ Device *
|
|||
uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *d, Uint8 port), void (*deofn)(Device *d, Uint8 port))
|
||||
{
|
||||
Device *d = &u->dev[id];
|
||||
d->addr = id * 0x10;
|
||||
d->u = u;
|
||||
d->mem = u->ram.dat;
|
||||
d->mem = u->ram;
|
||||
d->dei = deifn;
|
||||
d->deo = deofn;
|
||||
d->dat = u->devpage + id * 0x10;
|
||||
return d;
|
||||
}
|
||||
|
|
36
src/uxn.h
36
src/uxn.h
|
@ -16,35 +16,39 @@ typedef signed short Sint16;
|
|||
typedef unsigned int Uint32;
|
||||
|
||||
#define PAGE_PROGRAM 0x0100
|
||||
#define VISOR_DEV 0xfa00
|
||||
#define VISOR_WST 0xfb00
|
||||
#define VISOR_RST 0xfc00
|
||||
#define PAGE_DEV 0xfd00
|
||||
#define PAGE_WST 0xfe00
|
||||
#define PAGE_RST 0xff00
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define DEVPEEK16(o, x) { (o) = (d->dat[(x)] << 8) + d->dat[(x) + 1]; }
|
||||
#define DEVPOKE16(x, y) { d->dat[(x)] = (y) >> 8; d->dat[(x) + 1] = (y); }
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
typedef struct {
|
||||
Uint8 ptr, kptr, error;
|
||||
Uint8 dat[256];
|
||||
Uint8 ptr, dat[255];
|
||||
} Stack;
|
||||
|
||||
typedef struct {
|
||||
Uint16 ptr;
|
||||
Uint8 dat[65536];
|
||||
} Memory;
|
||||
|
||||
typedef struct Device {
|
||||
struct Uxn *u;
|
||||
Uint8 addr, dat[16], *mem;
|
||||
Uint8 *dat, *mem;
|
||||
Uint16 vector;
|
||||
Uint8 (*dei)(struct Device *d, Uint8);
|
||||
void (*deo)(struct Device *d, Uint8);
|
||||
} Device;
|
||||
|
||||
typedef struct Uxn {
|
||||
Stack wst, rst, *src, *dst;
|
||||
Memory ram;
|
||||
Uint8 *ram, *devpage;
|
||||
Stack *wst, *rst;
|
||||
Device dev[16];
|
||||
} Uxn;
|
||||
|
||||
void poke16(Uint8 *m, Uint16 a, Uint16 b);
|
||||
Uint16 peek16(Uint8 *m, Uint16 a);
|
||||
|
||||
int uxn_boot(Uxn *c);
|
||||
int uxn_eval(Uxn *u, Uint16 vec);
|
||||
int uxn_halt(Uxn *u, Uint8 error, char *name, int id);
|
||||
int uxn_boot(Uxn *u, Uint8 *ram, Uint8 *devpage, Stack *wst, Stack *rst);
|
||||
int uxn_eval(Uxn *u, Uint16 pc);
|
||||
int uxn_halt(Uxn *u, Uint8 error, Uint16 addr);
|
||||
Device *uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *, Uint8), void (*deofn)(Device *, Uint8));
|
||||
|
|
18
src/uxnasm.c
18
src/uxnasm.c
|
@ -57,8 +57,8 @@ static char ops[][4] = {
|
|||
static int scmp(char *a, char *b, int len) { int i = 0; while(a[i] == b[i]) if(!a[i] || ++i >= len) return 1; return 0; } /* string compare */
|
||||
static int sihx(char *s) { int i = 0; char c; while((c = s[i++])) if(!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f')) return 0; return i > 1; } /* string is hexadecimal */
|
||||
static int shex(char *s) { int n = 0, i = 0; char c; while((c = s[i++])) if(c >= '0' && c <= '9') n = n * 16 + (c - '0'); else if(c >= 'a' && c <= 'f') n = n * 16 + 10 + (c - 'a'); return n; } /* string to num */
|
||||
static int slen(char *s) { int i = 0; while(s[i]) ++i; return i; } /* string length */
|
||||
static char *scpy(char *src, char *dst, int len) { int i = 0; while((dst[i] = src[i]) && i < len - 2) ++i; dst[i + 1] = '\0'; return dst; } /* string copy */
|
||||
static int slen(char *s) { int i = 0; while(s[i]) i++; return i; } /* string length */
|
||||
static char *scpy(char *src, char *dst, int len) { int i = 0; while((dst[i] = src[i]) && i < len - 2) i++; dst[i + 1] = '\0'; return dst; } /* string copy */
|
||||
static char *scat(char *dst, const char *src) { char *ptr = dst + slen(dst); while(*src) *ptr++ = *src++; *ptr = '\0'; return dst; } /* string cat */
|
||||
|
||||
/* clang-format on */
|
||||
|
@ -82,7 +82,7 @@ static Macro *
|
|||
findmacro(char *name)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < p.mlen; ++i)
|
||||
for(i = 0; i < p.mlen; i++)
|
||||
if(scmp(p.macros[i].name, name, 64))
|
||||
return &p.macros[i];
|
||||
return NULL;
|
||||
|
@ -92,7 +92,7 @@ static Label *
|
|||
findlabel(char *name)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < p.llen; ++i)
|
||||
for(i = 0; i < p.llen; i++)
|
||||
if(scmp(p.labels[i].name, name, 64))
|
||||
return &p.labels[i];
|
||||
return NULL;
|
||||
|
@ -102,7 +102,7 @@ static Uint8
|
|||
findopcode(char *s)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 0x20; ++i) {
|
||||
for(i = 0; i < 0x20; i++) {
|
||||
int m = 0;
|
||||
if(!scmp(ops[i], s, 3))
|
||||
continue;
|
||||
|
@ -116,7 +116,7 @@ findopcode(char *s)
|
|||
i |= (1 << 7); /* mode: keep */
|
||||
else
|
||||
return 0; /* failed to match */
|
||||
++m;
|
||||
m++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ parse(char *w, FILE *f)
|
|||
writeshort(shex(w), 0);
|
||||
/* macro */
|
||||
else if((m = findmacro(w))) {
|
||||
for(i = 0; i < m->len; ++i)
|
||||
for(i = 0; i < m->len; i++)
|
||||
if(!parse(m->items[i], f))
|
||||
return 0;
|
||||
return 1;
|
||||
|
@ -346,7 +346,7 @@ resolve(void)
|
|||
{
|
||||
Label *l;
|
||||
int i;
|
||||
for(i = 0; i < p.rlen; ++i) {
|
||||
for(i = 0; i < p.rlen; i++) {
|
||||
Reference *r = &p.refs[i];
|
||||
switch(r->rune) {
|
||||
case '.':
|
||||
|
@ -399,7 +399,7 @@ static void
|
|||
review(char *filename)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < p.llen; ++i)
|
||||
for(i = 0; i < p.llen; i++)
|
||||
if(p.labels[i].name[0] >= 'A' && p.labels[i].name[0] <= 'Z')
|
||||
continue; /* Ignore capitalized labels(devices) */
|
||||
else if(!p.labels[i].refs)
|
||||
|
|
83
src/uxncli.c
83
src/uxncli.c
|
@ -1,8 +1,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "uxn.h"
|
||||
#include "devices/system.h"
|
||||
#include "devices/file.h"
|
||||
#include "devices/datetime.h"
|
||||
|
||||
/*
|
||||
Copyright (c) 2021 Devine Lu Linvega
|
||||
|
@ -31,8 +35,8 @@ inspect(Stack *s, char *name)
|
|||
{
|
||||
Uint8 x, y;
|
||||
fprintf(stderr, "\n%s\n", name);
|
||||
for(y = 0; y < 0x04; ++y) {
|
||||
for(x = 0; x < 0x08; ++x) {
|
||||
for(y = 0; y < 0x04; y++) {
|
||||
for(x = 0; x < 0x08; x++) {
|
||||
Uint8 p = y * 0x08 + x;
|
||||
fprintf(stderr,
|
||||
p == s->ptr ? "[%02x]" : " %02x ",
|
||||
|
@ -44,26 +48,12 @@ inspect(Stack *s, char *name)
|
|||
|
||||
#pragma mark - Devices
|
||||
|
||||
static Uint8
|
||||
system_dei(Device *d, Uint8 port)
|
||||
void
|
||||
system_deo_special(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];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
system_deo(Device *d, Uint8 port)
|
||||
{
|
||||
switch(port) {
|
||||
case 0x2: d->u->wst.ptr = d->dat[port]; break;
|
||||
case 0x3: d->u->rst.ptr = d->dat[port]; break;
|
||||
case 0xe:
|
||||
inspect(&d->u->wst, "Working-stack");
|
||||
inspect(&d->u->rst, "Return-stack");
|
||||
break;
|
||||
if(port == 0xe) {
|
||||
inspect(d->u->wst, "Working-stack");
|
||||
inspect(d->u->rst, "Return-stack");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,35 +61,11 @@ static void
|
|||
console_deo(Device *d, Uint8 port)
|
||||
{
|
||||
if(port == 0x1)
|
||||
d->vector = peek16(d->dat, 0x0);
|
||||
DEVPEEK16(d->vector, 0x0);
|
||||
if(port > 0x7)
|
||||
write(port - 0x7, (char *)&d->dat[port], 1);
|
||||
}
|
||||
|
||||
static 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];
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8
|
||||
nil_dei(Device *d, Uint8 port)
|
||||
{
|
||||
|
@ -109,20 +75,11 @@ nil_dei(Device *d, Uint8 port)
|
|||
static void
|
||||
nil_deo(Device *d, Uint8 port)
|
||||
{
|
||||
if(port == 0x1) d->vector = peek16(d->dat, 0x0);
|
||||
if(port == 0x1) DEVPEEK16(d->vector, 0x0);
|
||||
}
|
||||
|
||||
#pragma mark - Generics
|
||||
|
||||
static const char *errors[] = {"underflow", "overflow", "division by zero"};
|
||||
|
||||
int
|
||||
uxn_halt(Uxn *u, Uint8 error, char *name, int id)
|
||||
{
|
||||
fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
console_input(Uxn *u, char c)
|
||||
{
|
||||
|
@ -134,9 +91,9 @@ static void
|
|||
run(Uxn *u)
|
||||
{
|
||||
Uint16 vec;
|
||||
Device *d = devconsole;
|
||||
while((!u->dev[0].dat[0xf]) && (read(0, &devconsole->dat[0x2], 1) > 0)) {
|
||||
vec = peek16(devconsole->dat, 0);
|
||||
if(!vec) vec = u->ram.ptr; /* continue after last BRK */
|
||||
DEVPEEK16(vec, 0);
|
||||
uxn_eval(u, vec);
|
||||
}
|
||||
}
|
||||
|
@ -147,20 +104,24 @@ load(Uxn *u, char *filepath)
|
|||
FILE *f;
|
||||
int r;
|
||||
if(!(f = fopen(filepath, "rb"))) return 0;
|
||||
r = fread(u->ram.dat + PAGE_PROGRAM, 1, sizeof(u->ram.dat) - PAGE_PROGRAM, f);
|
||||
r = fread(u->ram + PAGE_PROGRAM, 1, 0xffff - PAGE_PROGRAM, f);
|
||||
fclose(f);
|
||||
if(r < 1) return 0;
|
||||
fprintf(stderr, "Loaded %s\n", filepath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Uint8 *shadow, *memory;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Uxn u;
|
||||
int i, loaded = 0;
|
||||
|
||||
if(!uxn_boot(&u))
|
||||
shadow = (Uint8 *)calloc(0xffff, sizeof(Uint8));
|
||||
memory = (Uint8 *)calloc(0xffff, sizeof(Uint8));
|
||||
if(!uxn_boot(&u, memory, shadow + PAGE_DEV, (Stack *)(shadow + PAGE_WST), (Stack *)(shadow + PAGE_RST)))
|
||||
return error("Boot", "Failed");
|
||||
|
||||
/* system */ devsystem = uxn_port(&u, 0x0, system_dei, system_deo);
|
||||
|
@ -180,7 +141,7 @@ main(int argc, char **argv)
|
|||
/* empty */ uxn_port(&u, 0xe, nil_dei, nil_deo);
|
||||
/* empty */ uxn_port(&u, 0xf, nil_dei, nil_deo);
|
||||
|
||||
for(i = 1; i < argc; ++i) {
|
||||
for(i = 1; i < argc; i++) {
|
||||
if(!loaded++) {
|
||||
if(!load(&u, argv[i]))
|
||||
return error("Load", "Failed");
|
||||
|
|
155
src/uxnemu.c
155
src/uxnemu.c
|
@ -8,11 +8,13 @@
|
|||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
#pragma clang diagnostic ignored "-Wtypedef-redefinition"
|
||||
#include <SDL.h>
|
||||
#include "devices/system.h"
|
||||
#include "devices/screen.h"
|
||||
#include "devices/audio.h"
|
||||
#include "devices/file.h"
|
||||
#include "devices/controller.h"
|
||||
#include "devices/mouse.h"
|
||||
#include "devices/datetime.h"
|
||||
#pragma GCC diagnostic pop
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
@ -65,7 +67,7 @@ audio_callback(void *u, Uint8 *stream, int len)
|
|||
int i, running = 0;
|
||||
Sint16 *samples = (Sint16 *)stream;
|
||||
SDL_memset(stream, 0, len);
|
||||
for(i = 0; i < POLYPHONY; ++i)
|
||||
for(i = 0; i < POLYPHONY; i++)
|
||||
running += audio_render(&uxn_audio[i], samples, samples + len / 2);
|
||||
if(!running)
|
||||
SDL_PauseAudioDevice(audio_id, 1);
|
||||
|
@ -111,7 +113,7 @@ set_size(Uint16 width, Uint16 height, int is_resize)
|
|||
gRect.h = uxn_screen.height;
|
||||
if(gTexture != NULL) SDL_DestroyTexture(gTexture);
|
||||
SDL_RenderSetLogicalSize(gRenderer, uxn_screen.width + PAD * 2, uxn_screen.height + PAD * 2);
|
||||
gTexture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, uxn_screen.width + PAD * 2, uxn_screen.height + PAD * 2);
|
||||
gTexture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STATIC, uxn_screen.width, uxn_screen.height);
|
||||
if(gTexture == NULL || SDL_SetTextureBlendMode(gTexture, SDL_BLENDMODE_NONE))
|
||||
return error("gTexture", SDL_GetError());
|
||||
if(SDL_UpdateTexture(gTexture, NULL, uxn_screen.pixels, sizeof(Uint32)) != 0)
|
||||
|
@ -122,15 +124,13 @@ set_size(Uint16 width, Uint16 height, int is_resize)
|
|||
}
|
||||
|
||||
static void
|
||||
redraw(Uxn *u)
|
||||
redraw(void)
|
||||
{
|
||||
if(devsystem->dat[0xe])
|
||||
screen_debug(&uxn_screen, u->wst.dat, u->wst.ptr, u->rst.ptr, u->ram.dat);
|
||||
screen_redraw(&uxn_screen, uxn_screen.pixels);
|
||||
if(SDL_UpdateTexture(gTexture, &gRect, uxn_screen.pixels, uxn_screen.width * sizeof(Uint32)) != 0)
|
||||
if(SDL_UpdateTexture(gTexture, NULL, uxn_screen.pixels, uxn_screen.width * sizeof(Uint32)) != 0)
|
||||
error("SDL_UpdateTexture", SDL_GetError());
|
||||
SDL_RenderClear(gRenderer);
|
||||
SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
|
||||
SDL_RenderCopy(gRenderer, gTexture, NULL, &gRect);
|
||||
SDL_RenderPresent(gRenderer);
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,7 @@ init(void)
|
|||
gRenderer = SDL_CreateRenderer(gWindow, -1, 0);
|
||||
if(gRenderer == NULL)
|
||||
return error("sdl_renderer", SDL_GetError());
|
||||
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xff);
|
||||
audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
|
||||
if(!audio_id)
|
||||
error("sdl_audio", SDL_GetError());
|
||||
|
@ -169,23 +170,9 @@ init(void)
|
|||
|
||||
#pragma mark - Devices
|
||||
|
||||
static Uint8
|
||||
system_dei(Device *d, Uint8 port)
|
||||
void
|
||||
system_deo_special(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];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
system_deo(Device *d, Uint8 port)
|
||||
{
|
||||
switch(port) {
|
||||
case 0x2: d->u->wst.ptr = d->dat[port]; break;
|
||||
case 0x3: d->u->rst.ptr = d->dat[port]; break;
|
||||
}
|
||||
if(port > 0x7 && port < 0xe)
|
||||
screen_palette(&uxn_screen, &d->dat[0x8]);
|
||||
}
|
||||
|
@ -194,7 +181,7 @@ static void
|
|||
console_deo(Device *d, Uint8 port)
|
||||
{
|
||||
if(port == 0x1)
|
||||
d->vector = peek16(d->dat, 0x0);
|
||||
DEVPEEK16(d->vector, 0x0);
|
||||
if(port > 0x7)
|
||||
write(port - 0x7, (char *)&d->dat[port], 1);
|
||||
}
|
||||
|
@ -206,7 +193,7 @@ audio_dei(Device *d, Uint8 port)
|
|||
if(!audio_id) return d->dat[port];
|
||||
switch(port) {
|
||||
case 0x4: return audio_get_vu(c);
|
||||
case 0x2: poke16(d->dat, 0x2, c->i); /* fall through */
|
||||
case 0x2: DEVPOKE16(0x2, c->i); /* fall through */
|
||||
default: return d->dat[port];
|
||||
}
|
||||
}
|
||||
|
@ -217,42 +204,21 @@ audio_deo(Device *d, Uint8 port)
|
|||
UxnAudio *c = &uxn_audio[d - devaudio0];
|
||||
if(!audio_id) return;
|
||||
if(port == 0xf) {
|
||||
Uint16 addr, adsr;
|
||||
SDL_LockAudioDevice(audio_id);
|
||||
c->len = peek16(d->dat, 0xa);
|
||||
c->addr = &d->mem[peek16(d->dat, 0xc)];
|
||||
DEVPEEK16(adsr, 0x8);
|
||||
DEVPEEK16(c->len, 0xa);
|
||||
DEVPEEK16(addr, 0xc);
|
||||
c->addr = &d->mem[addr];
|
||||
c->volume[0] = d->dat[0xe] >> 4;
|
||||
c->volume[1] = d->dat[0xe] & 0xf;
|
||||
c->repeat = !(d->dat[0xf] & 0x80);
|
||||
audio_start(c, peek16(d->dat, 0x8), d->dat[0xf] & 0x7f);
|
||||
audio_start(c, adsr, d->dat[0xf] & 0x7f);
|
||||
SDL_UnlockAudioDevice(audio_id);
|
||||
SDL_PauseAudioDevice(audio_id, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static 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];
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8
|
||||
nil_dei(Device *d, Uint8 port)
|
||||
{
|
||||
|
@ -262,7 +228,7 @@ nil_dei(Device *d, Uint8 port)
|
|||
static void
|
||||
nil_deo(Device *d, Uint8 port)
|
||||
{
|
||||
if(port == 0x1) d->vector = peek16(d->dat, 0x0);
|
||||
if(port == 0x1) DEVPEEK16(d->vector, 0x0);
|
||||
}
|
||||
|
||||
/* Boot */
|
||||
|
@ -273,7 +239,7 @@ load(Uxn *u, char *rom)
|
|||
SDL_RWops *f;
|
||||
int r;
|
||||
if(!(f = SDL_RWFromFile(rom, "rb"))) return 0;
|
||||
r = f->read(f, u->ram.dat + PAGE_PROGRAM, 1, sizeof(u->ram.dat) - PAGE_PROGRAM);
|
||||
r = f->read(f, u->ram + PAGE_PROGRAM, 1, 0xffff - PAGE_PROGRAM);
|
||||
f->close(f);
|
||||
if(r < 1) return 0;
|
||||
fprintf(stderr, "Loaded %s\n", rom);
|
||||
|
@ -281,11 +247,20 @@ load(Uxn *u, char *rom)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static Uint8 *shadow, *memory;
|
||||
|
||||
static int
|
||||
start(Uxn *u, char *rom)
|
||||
{
|
||||
if(!uxn_boot(u))
|
||||
memory = (Uint8 *)calloc(0xffff, sizeof(Uint8));
|
||||
shadow = (Uint8 *)calloc(0xffff, sizeof(Uint8));
|
||||
|
||||
if(!uxn_boot(&supervisor, shadow, shadow + VISOR_DEV, (Stack *)(shadow + VISOR_WST), (Stack *)(shadow + VISOR_RST)))
|
||||
return error("Boot", "Failed to start uxn.");
|
||||
if(!uxn_boot(u, memory, shadow + PAGE_DEV, (Stack *)(shadow + PAGE_WST), (Stack *)(shadow + PAGE_RST)))
|
||||
return error("Boot", "Failed to start uxn.");
|
||||
if(!load(&supervisor, "supervisor.rom"))
|
||||
error("Supervisor", "No debugger found.");
|
||||
if(!load(u, rom))
|
||||
return error("Boot", "Failed to load rom.");
|
||||
|
||||
|
@ -306,6 +281,14 @@ start(Uxn *u, char *rom)
|
|||
/* unused */ uxn_port(u, 0xe, nil_dei, nil_deo);
|
||||
/* unused */ uxn_port(u, 0xf, nil_dei, nil_deo);
|
||||
|
||||
/* Supervisor */
|
||||
uxn_port(&supervisor, 0x0, system_dei, system_deo);
|
||||
uxn_port(&supervisor, 0x1, nil_dei, console_deo);
|
||||
uxn_port(&supervisor, 0x2, screen_dei, screen_deo);
|
||||
uxn_port(&supervisor, 0x8, nil_dei, nil_deo);
|
||||
|
||||
uxn_eval(&supervisor, PAGE_PROGRAM);
|
||||
|
||||
if(!uxn_eval(u, PAGE_PROGRAM))
|
||||
return error("Boot", "Failed to start rom.");
|
||||
|
||||
|
@ -366,6 +349,22 @@ get_button(SDL_Event *event)
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
static Uint8
|
||||
get_fkey(SDL_Event *event)
|
||||
{
|
||||
switch(event->key.keysym.sym) {
|
||||
case SDLK_F1: return 0x01;
|
||||
case SDLK_F2: return 0x02;
|
||||
case SDLK_F3: return 0x04;
|
||||
case SDLK_F4: return 0x08;
|
||||
case SDLK_F5: return 0x10;
|
||||
case SDLK_F6: return 0x20;
|
||||
case SDLK_F7: return 0x40;
|
||||
case SDLK_F8: return 0x80;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static Uint8
|
||||
get_button_joystick(SDL_Event *event)
|
||||
{
|
||||
|
@ -406,15 +405,6 @@ do_shortcut(Uxn *u, SDL_Event *event)
|
|||
restart(u);
|
||||
}
|
||||
|
||||
static const char *errors[] = {"underflow", "overflow", "division by zero"};
|
||||
|
||||
int
|
||||
uxn_halt(Uxn *u, Uint8 error, char *name, int id)
|
||||
{
|
||||
fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
console_input(Uxn *u, char c)
|
||||
{
|
||||
|
@ -425,7 +415,7 @@ console_input(Uxn *u, char c)
|
|||
static int
|
||||
run(Uxn *u)
|
||||
{
|
||||
redraw(u);
|
||||
redraw();
|
||||
while(!devsystem->dat[0xf]) {
|
||||
SDL_Event event;
|
||||
double elapsed, begin;
|
||||
|
@ -436,15 +426,19 @@ run(Uxn *u)
|
|||
if(event.type == SDL_QUIT)
|
||||
return error("Run", "Quit.");
|
||||
else if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED)
|
||||
redraw(u);
|
||||
redraw();
|
||||
else if(event.type == SDL_DROPFILE) {
|
||||
set_size(WIDTH, HEIGHT, 0);
|
||||
start(u, event.drop.file);
|
||||
SDL_free(event.drop.file);
|
||||
}
|
||||
/* Audio */
|
||||
else if(event.type >= audio0_event && event.type < audio0_event + POLYPHONY)
|
||||
uxn_eval(u, peek16((devaudio0 + (event.type - audio0_event))->dat, 0));
|
||||
else if(event.type >= audio0_event && event.type < audio0_event + POLYPHONY) {
|
||||
Device *d = devaudio0 + (event.type - audio0_event);
|
||||
Uint16 res;
|
||||
DEVPEEK16(res, 0x00);
|
||||
uxn_eval(u, res);
|
||||
}
|
||||
/* Mouse */
|
||||
else if(event.type == SDL_MOUSEMOTION)
|
||||
mouse_pos(devmouse,
|
||||
|
@ -457,20 +451,21 @@ run(Uxn *u)
|
|||
else if(event.type == SDL_MOUSEWHEEL)
|
||||
mouse_scroll(devmouse, event.wheel.x, event.wheel.y);
|
||||
/* Controller */
|
||||
else if(event.type == SDL_KEYDOWN || event.type == SDL_TEXTINPUT) {
|
||||
if(event.type == SDL_TEXTINPUT)
|
||||
controller_key(devctrl, event.text.text[0]);
|
||||
else if(get_key(&event))
|
||||
else if(event.type == SDL_TEXTINPUT)
|
||||
controller_key(devctrl, event.text.text[0]);
|
||||
else if(event.type == SDL_KEYDOWN) {
|
||||
int ksym;
|
||||
if(get_key(&event))
|
||||
controller_key(devctrl, get_key(&event));
|
||||
else if(get_button(&event))
|
||||
controller_down(devctrl, get_button(&event));
|
||||
/* else if(get_fkey(&event))
|
||||
controller_special(&supervisor.dev[0x8], get_fkey(&event)); */
|
||||
else
|
||||
do_shortcut(u, &event);
|
||||
if(event.type == SDL_KEYDOWN) {
|
||||
int ksym = event.key.keysym.sym;
|
||||
if(SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYUP, SDL_KEYUP) == 1 && ksym == event.key.keysym.sym)
|
||||
break;
|
||||
}
|
||||
ksym = event.key.keysym.sym;
|
||||
if(SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYUP, SDL_KEYUP) == 1 && ksym == event.key.keysym.sym)
|
||||
break;
|
||||
} else if(event.type == SDL_KEYUP)
|
||||
controller_up(devctrl, get_button(&event));
|
||||
else if(event.type == SDL_JOYAXISMOTION) {
|
||||
|
@ -487,9 +482,11 @@ run(Uxn *u)
|
|||
else if(event.type == stdin_event)
|
||||
console_input(u, event.cbutton.button);
|
||||
}
|
||||
if(devsystem->dat[0xe])
|
||||
uxn_eval(&supervisor, supervisor.dev[2].vector);
|
||||
uxn_eval(u, devscreen->vector);
|
||||
if(uxn_screen.fg.changed || uxn_screen.bg.changed || devsystem->dat[0xe])
|
||||
redraw(u);
|
||||
redraw();
|
||||
if(!BENCH) {
|
||||
elapsed = (SDL_GetPerformanceCounter() - begin) / (double)SDL_GetPerformanceFrequency() * 1000.0f;
|
||||
SDL_Delay(clamp(16.666f - elapsed, 0, 1000));
|
||||
|
@ -513,7 +510,7 @@ main(int argc, char **argv)
|
|||
/* set default zoom */
|
||||
if(SDL_GetCurrentDisplayMode(0, &DM) == 0)
|
||||
set_zoom(DM.w / 1280);
|
||||
for(i = 1; i < argc; ++i) {
|
||||
for(i = 1; i < argc; i++) {
|
||||
/* get default zoom from flags */
|
||||
if(strcmp(argv[i], "-s") == 0) {
|
||||
if(i < argc - 1)
|
||||
|
|
Loading…
Reference in New Issue