mirror of https://git.sr.ht/~rabbits/uxn
Merge remote-tracking branch 'origin/main' into android
This commit is contained in:
commit
dd9bd1532d
2
build.sh
2
build.sh
|
@ -57,7 +57,7 @@ then
|
|||
CORE='src/uxn.c'
|
||||
else
|
||||
CFLAGS="${CFLAGS} -DNDEBUG -Os -g0 -s"
|
||||
CORE='src/uxn-fast.c'
|
||||
CORE='src/uxn.c'
|
||||
fi
|
||||
|
||||
echo "Building.."
|
||||
|
|
|
@ -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!
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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 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;
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,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 +109,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,9 +119,9 @@ 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;
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ void
|
|||
screen_debug(UxnScreen *p, Uint8 *stack, Uint8 wptr, Uint8 rptr, Uint8 *memory)
|
||||
{
|
||||
Uint8 i, x, y, b;
|
||||
for(i = 0; i < 0x20; ++i) {
|
||||
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);
|
||||
|
@ -145,7 +145,7 @@ screen_debug(UxnScreen *p, Uint8 *stack, Uint8 wptr, Uint8 rptr, Uint8 *memory)
|
|||
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) {
|
||||
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);
|
||||
|
@ -173,29 +173,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;
|
||||
}
|
||||
}
|
||||
|
|
4040
src/uxn-fast.c
4040
src/uxn-fast.c
File diff suppressed because it is too large
Load Diff
185
src/uxn.c
185
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,108 @@ 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 FAULT(s, n) { errcode = n * 2 + (s == &u->rst); goto fault; }
|
||||
#define PUSH8(s, x) { if(s->ptr == 0xff) { FAULT(s, 2) } s->dat[s->ptr++] = (x); }
|
||||
#define PUSH16(s, x) { if((j = s->ptr) >= 0xfe) { FAULT(s, 2) } 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)) { FAULT(src, 1) } o = (Uint16)src->dat[--j]; *sp = j; }
|
||||
#define POP16(o) { if((j = *sp) <= 1) { FAULT(src, 1) } 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;
|
||||
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.dat[u->ram.ptr++])) {
|
||||
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) { FAULT(src, 3) } 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;
|
||||
|
||||
fault:
|
||||
return uxn_halt(u, errcode >> 1, (errcode & 1) == 0 ? "Working-stack" : "Return-stack", pc - 1);
|
||||
}
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
int
|
||||
uxn_boot(Uxn *u)
|
||||
uxn_boot(Uxn *u, Uint8 *memory)
|
||||
{
|
||||
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 = memory;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -151,7 +122,7 @@ uxn_port(Uxn *u, Uint8 id, Uint8 (*deifn)(Device *d, Uint8 port), void (*deofn)(
|
|||
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;
|
||||
return d;
|
||||
|
|
29
src/uxn.h
29
src/uxn.h
|
@ -17,15 +17,17 @@ typedef unsigned int Uint32;
|
|||
|
||||
#define PAGE_PROGRAM 0x0100
|
||||
|
||||
typedef struct {
|
||||
Uint8 ptr, kptr, error;
|
||||
Uint8 dat[256];
|
||||
} Stack;
|
||||
/* 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 {
|
||||
Uint16 ptr;
|
||||
Uint8 dat[65536];
|
||||
} Memory;
|
||||
Uint8 ptr;
|
||||
Uint8 dat[256];
|
||||
} Stack;
|
||||
|
||||
typedef struct Device {
|
||||
struct Uxn *u;
|
||||
|
@ -36,15 +38,12 @@ typedef struct Device {
|
|||
} Device;
|
||||
|
||||
typedef struct Uxn {
|
||||
Stack wst, rst, *src, *dst;
|
||||
Memory ram;
|
||||
Stack wst, rst;
|
||||
Uint8 *ram;
|
||||
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 *c, Uint8 *memory);
|
||||
int uxn_eval(Uxn *u, Uint16 pc);
|
||||
int uxn_halt(Uxn *u, Uint8 error, char *name, 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)
|
||||
|
|
23
src/uxncli.c
23
src/uxncli.c
|
@ -1,4 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include "uxn.h"
|
||||
|
@ -31,8 +32,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 ",
|
||||
|
@ -71,7 +72,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);
|
||||
}
|
||||
|
@ -109,7 +110,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);
|
||||
}
|
||||
|
||||
#pragma mark - Generics
|
||||
|
@ -117,9 +118,9 @@ nil_deo(Device *d, Uint8 port)
|
|||
static const char *errors[] = {"underflow", "overflow", "division by zero"};
|
||||
|
||||
int
|
||||
uxn_halt(Uxn *u, Uint8 error, char *name, int id)
|
||||
uxn_halt(Uxn *u, Uint8 error, char *name, Uint16 addr)
|
||||
{
|
||||
fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
|
||||
fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], u->ram[addr], addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -134,9 +135,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,7 +148,7 @@ 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);
|
||||
|
@ -160,7 +161,7 @@ main(int argc, char **argv)
|
|||
Uxn u;
|
||||
int i, loaded = 0;
|
||||
|
||||
if(!uxn_boot(&u))
|
||||
if(!uxn_boot(&u, (Uint8 *)calloc(0xffff, sizeof(Uint8))))
|
||||
return error("Boot", "Failed");
|
||||
|
||||
/* system */ devsystem = uxn_port(&u, 0x0, system_dei, system_deo);
|
||||
|
@ -180,7 +181,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");
|
||||
|
|
55
src/uxnemu.c
55
src/uxnemu.c
|
@ -80,7 +80,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);
|
||||
|
@ -153,7 +153,7 @@ static void
|
|||
redraw(Uxn *u)
|
||||
{
|
||||
if(devsystem->dat[0xe])
|
||||
screen_debug(&uxn_screen, u->wst.dat, u->wst.ptr, u->rst.ptr, u->ram.dat);
|
||||
screen_debug(&uxn_screen, u->wst.dat, u->wst.ptr, u->rst.ptr, u->ram);
|
||||
screen_redraw(&uxn_screen, uxn_screen.pixels);
|
||||
if(SDL_UpdateTexture(gTexture, &gRect, uxn_screen.pixels, uxn_screen.width * sizeof(Uint32)) != 0)
|
||||
error("SDL_UpdateTexture", SDL_GetError());
|
||||
|
@ -244,7 +244,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);
|
||||
}
|
||||
|
@ -256,7 +256,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];
|
||||
}
|
||||
}
|
||||
|
@ -267,13 +267,16 @@ 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);
|
||||
}
|
||||
|
@ -312,7 +315,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 */
|
||||
|
@ -323,7 +326,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);
|
||||
|
@ -334,7 +337,8 @@ load(Uxn *u, char *rom)
|
|||
static int
|
||||
start(Uxn *u, char *rom)
|
||||
{
|
||||
if(!uxn_boot(u))
|
||||
Uint8 *memory = (Uint8 *)calloc(0xffff, sizeof(Uint8));
|
||||
if(!uxn_boot(u, memory))
|
||||
return error("Boot", "Failed to start uxn.");
|
||||
if(!load(u, rom))
|
||||
return error("Boot", "Failed to load rom.");
|
||||
|
@ -466,9 +470,9 @@ do_shortcut(Uxn *u, SDL_Event *event)
|
|||
static const char *errors[] = {"underflow", "overflow", "division by zero"};
|
||||
|
||||
int
|
||||
uxn_halt(Uxn *u, Uint8 error, char *name, int id)
|
||||
uxn_halt(Uxn *u, Uint8 error, char *name, Uint16 addr)
|
||||
{
|
||||
fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
|
||||
fprintf(stderr, "Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], u->ram[addr], addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -537,8 +541,12 @@ run(Uxn *u)
|
|||
force_redraw = 1;
|
||||
}
|
||||
/* 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_steal(&event))
|
||||
mouse_pos(devmouse,
|
||||
|
@ -551,20 +559,19 @@ 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
|
||||
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) {
|
||||
|
@ -607,7 +614,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