... | ... |
@@ -72,9 +72,15 @@ pop_push = function(k, n, s) |
72 | 72 |
return nil |
73 | 73 |
end |
74 | 74 |
end |
75 |
+local indented_block |
|
76 |
+indented_block = function(s) |
|
77 |
+ s = s:gsub('^%{ *', '{\n'):gsub('\n', '\n\t'):gsub('\t%} *$', '}\n') |
|
78 |
+ s = s:gsub('\n[^\n]+%.error = [^\n]+', '%0\n#ifndef NO_STACK_CHECKS\n\tgoto error;\n#endif') |
|
79 |
+ return s |
|
80 |
+end |
|
75 | 81 |
local process |
76 | 82 |
process = function(body) |
77 |
- local out_body = body:gsub('^%{ *', ''):gsub(' *%}$', ''):gsub('; ', ';\n'):gsub('(%a+)(%d+)(%b())', pop_push) |
|
83 |
+ local out_body = body:gsub('^%{ *', ''):gsub(' *%}$', ''):gsub('; ', ';\n'):gsub('%b{} *', indented_block):gsub('(%a+)(%d+)(%b())', pop_push) |
|
78 | 84 |
local in_ifdef = false |
79 | 85 |
local _list_0 = { |
80 | 86 |
'src', |
... | ... |
@@ -132,6 +138,8 @@ for l in assert(io.lines('src/uxn.c')) do |
132 | 138 |
if replacements[name] then |
133 | 139 |
body = replacements[name] |
134 | 140 |
end |
141 |
+ body = body:gsub('u%-%>src%-%>', 'src.') |
|
142 |
+ body = body:gsub('u%-%>dst%-%>', 'dst.') |
|
135 | 143 |
body = body:gsub('u%-%>src', 'src') |
136 | 144 |
body = body:gsub('u%-%>dst', 'dst') |
137 | 145 |
top = { |
... | ... |
@@ -278,6 +286,7 @@ See etc/mkuxn-fast.moon for instructions. |
278 | 286 |
|
279 | 287 |
*/ |
280 | 288 |
]]) |
289 |
+ wanted = true |
|
281 | 290 |
while true do |
282 | 291 |
local _continue_0 = false |
283 | 292 |
repeat |
... | ... |
@@ -287,9 +296,19 @@ See etc/mkuxn-fast.moon for instructions. |
287 | 296 |
break |
288 | 297 |
end |
289 | 298 |
if l == '/* Stack */' then |
299 |
+ wanted = false |
|
300 |
+ end |
|
301 |
+ if l:match('errors%[%]') then |
|
302 |
+ _with_0:write('\n#ifndef NO_STACK_CHECKS\n') |
|
303 |
+ wanted = true |
|
304 |
+ end |
|
305 |
+ if wanted then |
|
306 |
+ _with_0:write(('%s\n'):format(l)) |
|
307 |
+ end |
|
308 |
+ if l == '}' then |
|
309 |
+ _with_0:write('#endif\n\n') |
|
290 | 310 |
break |
291 | 311 |
end |
292 |
- _with_0:write(('%s\n'):format(l)) |
|
293 | 312 |
_continue_0 = true |
294 | 313 |
until true |
295 | 314 |
if not _continue_0 then |
... | ... |
@@ -338,12 +357,10 @@ evaluxn(Uxn *u, Uint16 vec) |
338 | 357 |
return 1; |
339 | 358 |
#ifndef NO_STACK_CHECKS |
340 | 359 |
error: |
341 |
- printf("Halted: %s-stack %sflow#%04x, at 0x%04x\n", |
|
342 |
- u->wst.error ? "Working" : "Return", |
|
343 |
- ((u->wst.error | u->rst.error) & 2) ? "over" : "under", |
|
344 |
- instr, |
|
345 |
- u->ram.ptr); |
|
346 |
- return 0; |
|
360 |
+ if(u->wst.error) |
|
361 |
+ return haltuxn(u, u->wst.error, "Working-stack", instr); |
|
362 |
+ else |
|
363 |
+ return haltuxn(u, u->rst.error, "Return-stack", instr); |
|
347 | 364 |
#endif |
348 | 365 |
} |
349 | 366 |
|
... | ... |
@@ -77,8 +77,13 @@ pop_push = (k, n, s) -> |
77 | 77 |
else |
78 | 78 |
nil |
79 | 79 |
|
80 |
+indented_block = (s) -> |
|
81 |
+ s = s\gsub('^%{ *', '{\n')\gsub('\n', '\n\t')\gsub('\t%} *$', '}\n') |
|
82 |
+ s = s\gsub('\n[^\n]+%.error = [^\n]+', '%0\n#ifndef NO_STACK_CHECKS\n\tgoto error;\n#endif') |
|
83 |
+ s |
|
84 |
+ |
|
80 | 85 |
process = (body) -> |
81 |
- out_body = body\gsub('^%{ *', '')\gsub(' *%}$', '')\gsub('; ', ';\n')\gsub '(%a+)(%d+)(%b())', pop_push |
|
86 |
+ out_body = body\gsub('^%{ *', '')\gsub(' *%}$', '')\gsub('; ', ';\n')\gsub('%b{} *', indented_block)\gsub '(%a+)(%d+)(%b())', pop_push |
|
82 | 87 |
in_ifdef = false |
83 | 88 |
for k in *{'src', 'dst'} |
84 | 89 |
if bottom[k] != 0 |
... | ... |
@@ -115,6 +120,8 @@ for l in assert io.lines 'src/uxn.c' |
115 | 120 |
continue |
116 | 121 |
if replacements[name] |
117 | 122 |
body = replacements[name] |
123 |
+ body = body\gsub 'u%-%>src%-%>', 'src.' |
|
124 |
+ body = body\gsub 'u%-%>dst%-%>', 'dst.' |
|
118 | 125 |
body = body\gsub 'u%-%>src', 'src' |
119 | 126 |
body = body\gsub 'u%-%>dst', 'dst' |
120 | 127 |
top = { src: 0, dst: 0 } |
... | ... |
@@ -200,13 +207,21 @@ See etc/mkuxn-fast.moon for instructions. |
200 | 207 |
|
201 | 208 |
*/ |
202 | 209 |
]] |
210 |
+ wanted = true |
|
203 | 211 |
while true |
204 | 212 |
l = f\read '*l' |
205 | 213 |
if l\match' push' or l\match'[ *]pop' |
206 | 214 |
continue |
207 | 215 |
if l == '/* Stack */' |
216 |
+ wanted = false |
|
217 |
+ if l\match 'errors%[%]' |
|
218 |
+ \write '\n#ifndef NO_STACK_CHECKS\n' |
|
219 |
+ wanted = true |
|
220 |
+ if wanted |
|
221 |
+ \write '%s\n'\format l |
|
222 |
+ if l == '}' |
|
223 |
+ \write '#endif\n\n' |
|
208 | 224 |
break |
209 |
- \write '%s\n'\format l |
|
210 | 225 |
\write [[ |
211 | 226 |
/* clang-format on */ |
212 | 227 |
|
... | ... |
@@ -238,12 +253,10 @@ evaluxn(Uxn *u, Uint16 vec) |
238 | 253 |
return 1; |
239 | 254 |
#ifndef NO_STACK_CHECKS |
240 | 255 |
error: |
241 |
- printf("Halted: %s-stack %sflow#%04x, at 0x%04x\n", |
|
242 |
- u->wst.error ? "Working" : "Return", |
|
243 |
- ((u->wst.error | u->rst.error) & 2) ? "over" : "under", |
|
244 |
- instr, |
|
245 |
- u->ram.ptr); |
|
246 |
- return 0; |
|
256 |
+ if(u->wst.error) |
|
257 |
+ return haltuxn(u, u->wst.error, "Working-stack", instr); |
|
258 |
+ else |
|
259 |
+ return haltuxn(u, u->rst.error, "Return-stack", instr); |
|
247 | 260 |
#endif |
248 | 261 |
} |
249 | 262 |
|
... | ... |
@@ -34,6 +34,19 @@ void mempoke16(Uint8 *m, Uint16 a, Uint16 b) { mempoke8(m, a, b >> 8); mempoke |
34 | 34 |
Uint16 mempeek16(Uint8 *m, Uint16 a) { return (mempeek8(m, a) << 8) + mempeek8(m, a + 1); } |
35 | 35 |
void devpoke16(Device *d, Uint8 a, Uint16 b) { devpoke8(d, a, b >> 8); devpoke8(d, a + 1, b); } |
36 | 36 |
Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) << 8) + devpeek8(d, a + 1); } |
37 |
+ |
|
38 |
+#ifndef NO_STACK_CHECKS |
|
39 |
+static const char *errors[] = {"underflow", "overflow", "division by zero"}; |
|
40 |
+ |
|
41 |
+int |
|
42 |
+haltuxn(Uxn *u, Uint8 error, char *name, int id) |
|
43 |
+{ |
|
44 |
+ printf("Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr); |
|
45 |
+ u->ram.ptr = 0; |
|
46 |
+ return 0; |
|
47 |
+} |
|
48 |
+#endif |
|
49 |
+ |
|
37 | 50 |
/* clang-format on */ |
38 | 51 |
|
39 | 52 |
#pragma mark - Core |
... | ... |
@@ -453,6 +466,13 @@ evaluxn(Uxn *u, Uint16 vec) |
453 | 466 |
__asm__("evaluxn_1b_DIV:"); |
454 | 467 |
{ |
455 | 468 |
Uint8 a = u->wst.dat[u->wst.ptr - 1], b = u->wst.dat[u->wst.ptr - 2]; |
469 |
+ if(a == 0) { |
|
470 |
+ u->wst.error = 3; |
|
471 |
+#ifndef NO_STACK_CHECKS |
|
472 |
+ goto error; |
|
473 |
+#endif |
|
474 |
+ a = 1; |
|
475 |
+ } |
|
456 | 476 |
u->wst.dat[u->wst.ptr - 2] = b / a; |
457 | 477 |
#ifndef NO_STACK_CHECKS |
458 | 478 |
if(__builtin_expect(u->wst.ptr < 2, 0)) { |
... | ... |
@@ -926,6 +946,13 @@ evaluxn(Uxn *u, Uint16 vec) |
926 | 946 |
__asm__("evaluxn_3b_DIV2:"); |
927 | 947 |
{ |
928 | 948 |
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)); |
949 |
+ if(a == 0) { |
|
950 |
+ u->wst.error = 3; |
|
951 |
+#ifndef NO_STACK_CHECKS |
|
952 |
+ goto error; |
|
953 |
+#endif |
|
954 |
+ a = 1; |
|
955 |
+ } |
|
929 | 956 |
u->wst.dat[u->wst.ptr - 4] = (b / a) >> 8; |
930 | 957 |
u->wst.dat[u->wst.ptr - 3] = (b / a) & 0xff; |
931 | 958 |
#ifndef NO_STACK_CHECKS |
... | ... |
@@ -1376,6 +1403,13 @@ evaluxn(Uxn *u, Uint16 vec) |
1376 | 1403 |
__asm__("evaluxn_5b_DIVr:"); |
1377 | 1404 |
{ |
1378 | 1405 |
Uint8 a = u->rst.dat[u->rst.ptr - 1], b = u->rst.dat[u->rst.ptr - 2]; |
1406 |
+ if(a == 0) { |
|
1407 |
+ u->rst.error = 3; |
|
1408 |
+#ifndef NO_STACK_CHECKS |
|
1409 |
+ goto error; |
|
1410 |
+#endif |
|
1411 |
+ a = 1; |
|
1412 |
+ } |
|
1379 | 1413 |
u->rst.dat[u->rst.ptr - 2] = b / a; |
1380 | 1414 |
#ifndef NO_STACK_CHECKS |
1381 | 1415 |
if(__builtin_expect(u->rst.ptr < 2, 0)) { |
... | ... |
@@ -1849,6 +1883,13 @@ evaluxn(Uxn *u, Uint16 vec) |
1849 | 1883 |
__asm__("evaluxn_7b_DIV2r:"); |
1850 | 1884 |
{ |
1851 | 1885 |
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)); |
1886 |
+ if(a == 0) { |
|
1887 |
+ u->rst.error = 3; |
|
1888 |
+#ifndef NO_STACK_CHECKS |
|
1889 |
+ goto error; |
|
1890 |
+#endif |
|
1891 |
+ a = 1; |
|
1892 |
+ } |
|
1852 | 1893 |
u->rst.dat[u->rst.ptr - 4] = (b / a) >> 8; |
1853 | 1894 |
u->rst.dat[u->rst.ptr - 3] = (b / a) & 0xff; |
1854 | 1895 |
#ifndef NO_STACK_CHECKS |
... | ... |
@@ -2332,6 +2373,13 @@ evaluxn(Uxn *u, Uint16 vec) |
2332 | 2373 |
__asm__("evaluxn_9b_DIVk:"); |
2333 | 2374 |
{ |
2334 | 2375 |
Uint8 a = u->wst.dat[u->wst.ptr - 1], b = u->wst.dat[u->wst.ptr - 2]; |
2376 |
+ if(a == 0) { |
|
2377 |
+ u->wst.error = 3; |
|
2378 |
+#ifndef NO_STACK_CHECKS |
|
2379 |
+ goto error; |
|
2380 |
+#endif |
|
2381 |
+ a = 1; |
|
2382 |
+ } |
|
2335 | 2383 |
u->wst.dat[u->wst.ptr] = b / a; |
2336 | 2384 |
#ifndef NO_STACK_CHECKS |
2337 | 2385 |
if(__builtin_expect(u->wst.ptr < 2, 0)) { |
... | ... |
@@ -2846,6 +2894,13 @@ evaluxn(Uxn *u, Uint16 vec) |
2846 | 2894 |
__asm__("evaluxn_bb_DIV2k:"); |
2847 | 2895 |
{ |
2848 | 2896 |
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)); |
2897 |
+ if(a == 0) { |
|
2898 |
+ u->wst.error = 3; |
|
2899 |
+#ifndef NO_STACK_CHECKS |
|
2900 |
+ goto error; |
|
2901 |
+#endif |
|
2902 |
+ a = 1; |
|
2903 |
+ } |
|
2849 | 2904 |
u->wst.dat[u->wst.ptr] = (b / a) >> 8; |
2850 | 2905 |
u->wst.dat[u->wst.ptr + 1] = (b / a) & 0xff; |
2851 | 2906 |
#ifndef NO_STACK_CHECKS |
... | ... |
@@ -3349,6 +3404,13 @@ evaluxn(Uxn *u, Uint16 vec) |
3349 | 3404 |
__asm__("evaluxn_db_DIVkr:"); |
3350 | 3405 |
{ |
3351 | 3406 |
Uint8 a = u->rst.dat[u->rst.ptr - 1], b = u->rst.dat[u->rst.ptr - 2]; |
3407 |
+ if(a == 0) { |
|
3408 |
+ u->rst.error = 3; |
|
3409 |
+#ifndef NO_STACK_CHECKS |
|
3410 |
+ goto error; |
|
3411 |
+#endif |
|
3412 |
+ a = 1; |
|
3413 |
+ } |
|
3352 | 3414 |
u->rst.dat[u->rst.ptr] = b / a; |
3353 | 3415 |
#ifndef NO_STACK_CHECKS |
3354 | 3416 |
if(__builtin_expect(u->rst.ptr < 2, 0)) { |
... | ... |
@@ -3863,6 +3925,13 @@ evaluxn(Uxn *u, Uint16 vec) |
3863 | 3925 |
__asm__("evaluxn_fb_DIV2kr:"); |
3864 | 3926 |
{ |
3865 | 3927 |
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)); |
3928 |
+ if(a == 0) { |
|
3929 |
+ u->rst.error = 3; |
|
3930 |
+#ifndef NO_STACK_CHECKS |
|
3931 |
+ goto error; |
|
3932 |
+#endif |
|
3933 |
+ a = 1; |
|
3934 |
+ } |
|
3866 | 3935 |
u->rst.dat[u->rst.ptr] = (b / a) >> 8; |
3867 | 3936 |
u->rst.dat[u->rst.ptr + 1] = (b / a) & 0xff; |
3868 | 3937 |
#ifndef NO_STACK_CHECKS |
... | ... |
@@ -3961,12 +4030,10 @@ evaluxn(Uxn *u, Uint16 vec) |
3961 | 4030 |
return 1; |
3962 | 4031 |
#ifndef NO_STACK_CHECKS |
3963 | 4032 |
error: |
3964 |
- printf("Halted: %s-stack %sflow#%04x, at 0x%04x\n", |
|
3965 |
- u->wst.error ? "Working" : "Return", |
|
3966 |
- ((u->wst.error | u->rst.error) & 2) ? "over" : "under", |
|
3967 |
- instr, |
|
3968 |
- u->ram.ptr); |
|
3969 |
- return 0; |
|
4033 |
+ if(u->wst.error) |
|
4034 |
+ return haltuxn(u, u->wst.error, "Working-stack", instr); |
|
4035 |
+ else |
|
4036 |
+ return haltuxn(u, u->rst.error, "Return-stack", instr); |
|
3970 | 4037 |
#endif |
3971 | 4038 |
} |
3972 | 4039 |
|
... | ... |
@@ -61,7 +61,7 @@ void op_deo(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); devpoke8(&u->dev |
61 | 61 |
void op_add(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b + a); } |
62 | 62 |
void op_sub(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b - a); } |
63 | 63 |
void op_mul(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b * a); } |
64 |
-void op_div(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b / a); } |
|
64 |
+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); } |
|
65 | 65 |
void op_and(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b & a); } |
66 | 66 |
void op_ora(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b | a); } |
67 | 67 |
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 |
95 | 95 |
void op_add16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b + a); } |
96 | 96 |
void op_sub16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b - a); } |
97 | 97 |
void op_mul16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b * a); } |
98 |
-void op_div16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b / a); } |
|
98 |
+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); } |
|
99 | 99 |
void op_and16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b & a); } |
100 | 100 |
void op_ora16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b | a); } |
101 | 101 |
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) = { |
117 | 117 |
|
118 | 118 |
#pragma mark - Core |
119 | 119 |
|
120 |
+static const char *errors[] = {"underflow", "overflow", "division by zero"}; |
|
121 |
+ |
|
120 | 122 |
int |
121 |
-haltuxn(Uxn *u, char *name, int id) |
|
123 |
+haltuxn(Uxn *u, Uint8 error, char *name, int id) |
|
122 | 124 |
{ |
123 |
- printf("Halted: %s#%04x, at 0x%04x\n", name, id, u->ram.ptr); |
|
125 |
+ printf("Halted: %s %s#%04x, at 0x%04x\n", name, errors[error - 1], id, u->ram.ptr); |
|
124 | 126 |
u->ram.ptr = 0; |
125 | 127 |
return 0; |
126 | 128 |
} |
... | ... |
@@ -145,9 +147,9 @@ stepuxn(Uxn *u, Uint8 instr) |
145 | 147 |
{ |
146 | 148 |
opcuxn(u, instr); |
147 | 149 |
if(u->wst.error) |
148 |
- return haltuxn(u, u->wst.error == 1 ? "Working-stack underflow" : "Working-stack overflow", instr); |
|
150 |
+ return haltuxn(u, u->wst.error, "Working-stack", instr); |
|
149 | 151 |
if(u->rst.error) |
150 |
- return haltuxn(u, u->rst.error == 1 ? "Return-stack underflow" : "Return-stack overflow", instr); |
|
152 |
+ return haltuxn(u, u->rst.error, "Return-stack", instr); |
|
151 | 153 |
return 1; |
152 | 154 |
} |
153 | 155 |
|