diff --git a/src/cmd_check.c b/src/cmd_check.c index ea7a315..98b0a13 100644 --- a/src/cmd_check.c +++ b/src/cmd_check.c @@ -50,6 +50,7 @@ static void commandsDEC() { static void letVar(int type) { vmvar_t *varno = getVariable(); int val = getCaliValue(); + uint32_t result; if (varno == NULL) { WARNING("varno is NULL"); @@ -60,11 +61,15 @@ static void letVar(int type) { case '!': *varno = val; break; case 0x10: /* += */ - *varno = (uint16_t)(*varno + val); break; + result = (uint32_t)*varno + val; + *varno = result > UINT16_MAX ? UINT16_MAX : result; + break; case 0x11: /* -= */ *varno = max(0, *varno - val); break; case 0x12: /* *= */ - *varno = (uint16_t)(*varno * val); break; + result = (uint32_t)*varno * val; + *varno = result > UINT16_MAX ? UINT16_MAX : result; + break; case 0x13: /* /= */ if (val == 0) *varno = 0; else *varno /= val; @@ -101,7 +106,7 @@ static void getDataTableAdr() { /* < ループ開始 */ static void loopStart() { int p1 = sl_getc(); - int exitadr, limit, direction, step; + int exitadr, limit, direction, step, value; vmvar_t *var; if (p1 == 0) { @@ -116,32 +121,33 @@ static void loopStart() { limit = getCaliValue(); direction = getCaliValue(); step = getCaliValue(); + value = *var; if (direction == 0) { /* dec */ if (p1 == 1) { - *var -= step; + value -= step; } - if (*var < limit) { - if (p1 == 0) *var-= step; + if (value < limit) { + if (p1 == 0) value -= step; sl_jmpNear(exitadr); - if (*var < 0) { *var = 0; } + *var = max(0, value); return; } } else if (direction == 1) { /* inc */ if (p1 == 1) { - *var += step; + value += step; } - if (*var > limit) { - // if (p1 == 0) *var+= step; + if (value > limit) { sl_jmpNear(exitadr); - if (*var > 65535) { *var = 65535; } + *var = (uint16_t)value; return; } } else { undeferr(); } + *var = value; return; } diff --git a/test/testSA.ALD b/test/testSA.ALD index 346ba3c..10bd02e 100644 Binary files a/test/testSA.ALD and b/test/testSA.ALD differ diff --git a/test/variable.adv b/test/variable.adv index c7a61f6..092d3fe 100644 --- a/test/variable.adv +++ b/test/variable.adv @@ -24,16 +24,16 @@ dec value: ~AssertEquals value,0,__LINE__: - ; Compound assignments preserve their documented wrap/saturate behavior. + ; Compound arithmetic assignments saturate at the word bounds. !value:65535! !value+:1! - ~AssertEquals value,0,__LINE__: + ~AssertEquals value,65535,__LINE__: !value:0! !value-:1! ~AssertEquals value,0,__LINE__: !value:32768! !value*:2! - ~AssertEquals value,0,__LINE__: + ~AssertEquals value,65535,__LINE__: !value:7! !value/:2! ~AssertEquals value,3,__LINE__: @@ -52,7 +52,7 @@ !value^:0x00ff! ~AssertEquals value,0x0f0f,__LINE__: - ; FOR loops terminate after crossing either word boundary. + ; FOR loops test the wide result, then store the terminal word value. !count:0! ~AssertEquals count,1,__LINE__: - ~AssertEquals value,65535,__LINE__: + ~AssertEquals value,0,__LINE__: ; A module result above 65535 is observed through expressions as a word. MS 10,"65536":