Merge branch 'main' into aarch64

This commit is contained in:
Sigrid Solveig Haflínudóttir 2022-01-08 00:05:39 +01:00
commit e9241f13e2
30 changed files with 1063 additions and 5196 deletions

2
.gitignore vendored
View File

@ -13,3 +13,5 @@
*theme
*.rom
*.[o0125678vqki]

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ,&not-brk JCN
POP ;&brk-msg ;debug-print JMP2 ( tail call )
&brk-msg "BRK 00
&not-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 ,&not-lit JCN
#7f AND
&not-lit
DUP #20 AND #00 EQU ,&not-2 JCN
LIT '2 .Console/write DEO
&not-2
DUP #80 AND #00 EQU ,&not-k JCN
LIT 'k .Console/write DEO
&not-k
#40 AND #00 EQU ,&not-r JCN
LIT 'r .Console/write DEO
&not-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 ,&not-empty JCN
POP2 ;&empty-msg ;debug-print JMP2 ( tail call )
&not-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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);

40
src/devices/datetime.c Normal file
View File

@ -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];
}
}

13
src/devices/datetime.h Normal file
View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);

66
src/devices/system.c Normal file
View File

@ -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);
}
}

16
src/devices/system.h Normal file
View File

@ -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;

File diff suppressed because it is too large Load Diff

194
src/uxn.c
View File

@ -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;
}

View File

@ -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));

View File

@ -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)

View File

@ -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");

View File

@ -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)