Browse code

Added reporting of division by zero errors rather than crashing

Andrew Alderwick authored on 08/06/2021 21:58:02
Showing 4 changed files
... ...
@@ -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