commit 064f7745d4faee1e41e9cb4ade5bc96f51fd7d14
parent 6bf7e7f7a1d442185d83963e4c875abe955abcce
Author: Andrew Alderwick <andrew@alderwick.co.uk>
Date: Tue, 8 Jun 2021 22:58:02 +0100
Added reporting of division by zero errors rather than crashing
Diffstat:
4 files changed, 127 insertions(+), 28 deletions(-)
diff --git a/etc/mkuxn-fast.lua b/etc/mkuxn-fast.lua
@@ -72,9 +72,15 @@ pop_push = function(k, n, s)
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('(%a+)(%d+)(%b())', pop_push)
+ 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',
@@ -132,6 +138,8 @@ for l in assert(io.lines('src/uxn.c')) do
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 = {
@@ -278,6 +286,7 @@ See etc/mkuxn-fast.moon for instructions.
*/
]])
+ wanted = true
while true do
local _continue_0 = false
repeat
@@ -287,9 +296,19 @@ See etc/mkuxn-fast.moon for instructions.
break
end
if l == '/* Stack */' then
+ wanted = false
+ end
+ if l:match('errors%[%]') then
+ _with_0:write('\n#ifndef NO_STACK_CHECKS\n')
+ wanted = true
+ end
+ if wanted then
+ _with_0:write(('%s\n'):format(l))
+ end
+ if l == '}' then
+ _with_0:write('#endif\n\n')
break
end
- _with_0:write(('%s\n'):format(l))
_continue_0 = true
until true
if not _continue_0 then
@@ -338,12 +357,10 @@ evaluxn(Uxn *u, Uint16 vec)
return 1;
#ifndef NO_STACK_CHECKS
error:
- printf("Halted: %s-stack %sflow#%04x, at 0x%04x\n",
- u->wst.error ? "Working" : "Return",
- ((u->wst.error | u->rst.error) & 2) ? "over" : "under",
- instr,
- u->ram.ptr);
- return 0;
+ if(u->wst.error)
+ return haltuxn(u, u->wst.error, "Working-stack", instr);
+ else
+ return haltuxn(u, u->rst.error, "Return-stack", instr);
#endif
}
diff --git a/etc/mkuxn-fast.moon b/etc/mkuxn-fast.moon
@@ -77,8 +77,13 @@ pop_push = (k, n, s) ->
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 '(%a+)(%d+)(%b())', pop_push
+ 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
@@ -115,6 +120,8 @@ for l in assert io.lines 'src/uxn.c'
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 }
@@ -200,13 +207,21 @@ See etc/mkuxn-fast.moon for instructions.
*/
]]
+ wanted = true
while true
l = f\read '*l'
if l\match' push' or l\match'[ *]pop'
continue
if l == '/* Stack */'
+ wanted = false
+ if l\match 'errors%[%]'
+ \write '\n#ifndef NO_STACK_CHECKS\n'
+ wanted = true
+ if wanted
+ \write '%s\n'\format l
+ if l == '}'
+ \write '#endif\n\n'
break
- \write '%s\n'\format l
\write [[
/* clang-format on */
@@ -238,12 +253,10 @@ evaluxn(Uxn *u, Uint16 vec)
return 1;
#ifndef NO_STACK_CHECKS
error:
- printf("Halted: %s-stack %sflow#%04x, at 0x%04x\n",
- u->wst.error ? "Working" : "Return",
- ((u->wst.error | u->rst.error) & 2) ? "over" : "under",
- instr,
- u->ram.ptr);
- return 0;
+ if(u->wst.error)
+ return haltuxn(u, u->wst.error, "Working-stack", instr);
+ else
+ return haltuxn(u, u->rst.error, "Return-stack", instr);
#endif
}
diff --git a/src/uxn-fast.c b/src/uxn-fast.c
@@ -34,6 +34,19 @@ void mempoke16(Uint8 *m, Uint16 a, Uint16 b) { mempoke8(m, a, b >> 8); mempoke
Uint16 mempeek16(Uint8 *m, Uint16 a) { return (mempeek8(m, a) << 8) + mempeek8(m, a + 1); }
void devpoke16(Device *d, Uint8 a, Uint16 b) { devpoke8(d, a, b >> 8); devpoke8(d, a + 1, b); }
Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) << 8) + devpeek8(d, a + 1); }
+
+#ifndef NO_STACK_CHECKS
+static const char *errors[] = {"underflow", "overflow", "division by zero"};
+
+int
+haltuxn(Uxn *u, Uint8 error, char *name, int id)
+{
+ printf("Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
+ u->ram.ptr = 0;
+ return 0;
+}
+#endif
+
/* clang-format on */
#pragma mark - Core
@@ -453,6 +466,13 @@ evaluxn(Uxn *u, Uint16 vec)
__asm__("evaluxn_1b_DIV:");
{
Uint8 a = u->wst.dat[u->wst.ptr - 1], b = u->wst.dat[u->wst.ptr - 2];
+ if(a == 0) {
+ u->wst.error = 3;
+#ifndef NO_STACK_CHECKS
+ goto error;
+#endif
+ a = 1;
+ }
u->wst.dat[u->wst.ptr - 2] = b / a;
#ifndef NO_STACK_CHECKS
if(__builtin_expect(u->wst.ptr < 2, 0)) {
@@ -926,6 +946,13 @@ evaluxn(Uxn *u, Uint16 vec)
__asm__("evaluxn_3b_DIV2:");
{
Uint16 a = (u->wst.dat[u->wst.ptr - 1] | (u->wst.dat[u->wst.ptr - 2] << 8)), b = (u->wst.dat[u->wst.ptr - 3] | (u->wst.dat[u->wst.ptr - 4] << 8));
+ if(a == 0) {
+ u->wst.error = 3;
+#ifndef NO_STACK_CHECKS
+ goto error;
+#endif
+ a = 1;
+ }
u->wst.dat[u->wst.ptr - 4] = (b / a) >> 8;
u->wst.dat[u->wst.ptr - 3] = (b / a) & 0xff;
#ifndef NO_STACK_CHECKS
@@ -1376,6 +1403,13 @@ evaluxn(Uxn *u, Uint16 vec)
__asm__("evaluxn_5b_DIVr:");
{
Uint8 a = u->rst.dat[u->rst.ptr - 1], b = u->rst.dat[u->rst.ptr - 2];
+ if(a == 0) {
+ u->rst.error = 3;
+#ifndef NO_STACK_CHECKS
+ goto error;
+#endif
+ a = 1;
+ }
u->rst.dat[u->rst.ptr - 2] = b / a;
#ifndef NO_STACK_CHECKS
if(__builtin_expect(u->rst.ptr < 2, 0)) {
@@ -1849,6 +1883,13 @@ evaluxn(Uxn *u, Uint16 vec)
__asm__("evaluxn_7b_DIV2r:");
{
Uint16 a = (u->rst.dat[u->rst.ptr - 1] | (u->rst.dat[u->rst.ptr - 2] << 8)), b = (u->rst.dat[u->rst.ptr - 3] | (u->rst.dat[u->rst.ptr - 4] << 8));
+ if(a == 0) {
+ u->rst.error = 3;
+#ifndef NO_STACK_CHECKS
+ goto error;
+#endif
+ a = 1;
+ }
u->rst.dat[u->rst.ptr - 4] = (b / a) >> 8;
u->rst.dat[u->rst.ptr - 3] = (b / a) & 0xff;
#ifndef NO_STACK_CHECKS
@@ -2332,6 +2373,13 @@ evaluxn(Uxn *u, Uint16 vec)
__asm__("evaluxn_9b_DIVk:");
{
Uint8 a = u->wst.dat[u->wst.ptr - 1], b = u->wst.dat[u->wst.ptr - 2];
+ if(a == 0) {
+ u->wst.error = 3;
+#ifndef NO_STACK_CHECKS
+ goto error;
+#endif
+ a = 1;
+ }
u->wst.dat[u->wst.ptr] = b / a;
#ifndef NO_STACK_CHECKS
if(__builtin_expect(u->wst.ptr < 2, 0)) {
@@ -2846,6 +2894,13 @@ evaluxn(Uxn *u, Uint16 vec)
__asm__("evaluxn_bb_DIV2k:");
{
Uint16 a = (u->wst.dat[u->wst.ptr - 1] | (u->wst.dat[u->wst.ptr - 2] << 8)), b = (u->wst.dat[u->wst.ptr - 3] | (u->wst.dat[u->wst.ptr - 4] << 8));
+ if(a == 0) {
+ u->wst.error = 3;
+#ifndef NO_STACK_CHECKS
+ goto error;
+#endif
+ a = 1;
+ }
u->wst.dat[u->wst.ptr] = (b / a) >> 8;
u->wst.dat[u->wst.ptr + 1] = (b / a) & 0xff;
#ifndef NO_STACK_CHECKS
@@ -3349,6 +3404,13 @@ evaluxn(Uxn *u, Uint16 vec)
__asm__("evaluxn_db_DIVkr:");
{
Uint8 a = u->rst.dat[u->rst.ptr - 1], b = u->rst.dat[u->rst.ptr - 2];
+ if(a == 0) {
+ u->rst.error = 3;
+#ifndef NO_STACK_CHECKS
+ goto error;
+#endif
+ a = 1;
+ }
u->rst.dat[u->rst.ptr] = b / a;
#ifndef NO_STACK_CHECKS
if(__builtin_expect(u->rst.ptr < 2, 0)) {
@@ -3863,6 +3925,13 @@ evaluxn(Uxn *u, Uint16 vec)
__asm__("evaluxn_fb_DIV2kr:");
{
Uint16 a = (u->rst.dat[u->rst.ptr - 1] | (u->rst.dat[u->rst.ptr - 2] << 8)), b = (u->rst.dat[u->rst.ptr - 3] | (u->rst.dat[u->rst.ptr - 4] << 8));
+ if(a == 0) {
+ u->rst.error = 3;
+#ifndef NO_STACK_CHECKS
+ goto error;
+#endif
+ a = 1;
+ }
u->rst.dat[u->rst.ptr] = (b / a) >> 8;
u->rst.dat[u->rst.ptr + 1] = (b / a) & 0xff;
#ifndef NO_STACK_CHECKS
@@ -3961,12 +4030,10 @@ evaluxn(Uxn *u, Uint16 vec)
return 1;
#ifndef NO_STACK_CHECKS
error:
- printf("Halted: %s-stack %sflow#%04x, at 0x%04x\n",
- u->wst.error ? "Working" : "Return",
- ((u->wst.error | u->rst.error) & 2) ? "over" : "under",
- instr,
- u->ram.ptr);
- return 0;
+ if(u->wst.error)
+ return haltuxn(u, u->wst.error, "Working-stack", instr);
+ else
+ return haltuxn(u, u->rst.error, "Return-stack", instr);
#endif
}
diff --git a/src/uxn.c b/src/uxn.c
@@ -61,7 +61,7 @@ void op_deo(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); devpoke8(&u->dev
void op_add(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b + a); }
void op_sub(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b - a); }
void op_mul(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b * a); }
-void op_div(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b / a); }
+void op_div(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); if(a == 0) { u->src->error = 3; a = 1; } push8(u->src, b / a); }
void op_and(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b & a); }
void op_ora(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b | a); }
void op_eor(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b ^ a); }
@@ -95,7 +95,7 @@ void op_deo16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); devpok
void op_add16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b + a); }
void op_sub16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b - a); }
void op_mul16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b * a); }
-void op_div16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b / a); }
+void op_div16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); if(a == 0) { u->src->error = 3; a = 1; } push16(u->src, b / a); }
void op_and16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b & a); }
void op_ora16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b | a); }
void op_eor16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b ^ a); }
@@ -117,10 +117,12 @@ void (*ops[])(Uxn *u) = {
#pragma mark - Core
+static const char *errors[] = {"underflow", "overflow", "division by zero"};
+
int
-haltuxn(Uxn *u, char *name, int id)
+haltuxn(Uxn *u, Uint8 error, char *name, int id)
{
- printf("Halted: %s#%04x, at 0x%04x\n", name, id, u->ram.ptr);
+ printf("Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr);
u->ram.ptr = 0;
return 0;
}
@@ -145,9 +147,9 @@ stepuxn(Uxn *u, Uint8 instr)
{
opcuxn(u, instr);
if(u->wst.error)
- return haltuxn(u, u->wst.error == 1 ? "Working-stack underflow" : "Working-stack overflow", instr);
+ return haltuxn(u, u->wst.error, "Working-stack", instr);
if(u->rst.error)
- return haltuxn(u, u->rst.error == 1 ? "Return-stack underflow" : "Return-stack overflow", instr);
+ return haltuxn(u, u->rst.error, "Return-stack", instr);
return 1;
}