uxn

Varvara Ordinator, written in ANSI C(SDL2)
git clone https://git.eamoncaddigan.net/uxn.git
Log | Files | Refs | README | LICENSE

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:
Metc/mkuxn-fast.lua | 33+++++++++++++++++++++++++--------
Metc/mkuxn-fast.moon | 29+++++++++++++++++++++--------
Msrc/uxn-fast.c | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/uxn.c | 14++++++++------
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; }