From 30188c3a4f66ccd2ededfc97262482449028a753 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Fri, 17 Jul 2026 09:11:52 +0900 Subject: [PATCH] Match variable bounds with System 3.9 System 3.9 saturates compound addition and multiplication at 65535, while an overflowing ascending loop stores the wrapped 16-bit result after testing the wide value. Update the scenario expectations and regenerated fixture to cover both cases. The suite passes with xsystem35 and the original System39.exe. --- src/cmd_check.c | 28 +++++++++++++++++----------- test/testSA.ALD | Bin 8720 -> 8720 bytes test/variable.adv | 10 +++++----- 3 files changed, 22 insertions(+), 16 deletions(-) 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 346ba3c76bb091118f4a92a8a76eb7ea3aa705ff..10bd02e1d0a9d3e4e21201e89a88ac705266e598 100644 GIT binary patch delta 180 zcmbQ>GQnj7ClgEc-M=lHd71t&LRl28ITZ zQImOPrI}b*Hfzc1GVXN@K@MedqVITHiJih2hibgI{9TUl?HFu6wF cneoQt1M)JATPNR@mt}O=%&zd3agve%0R9U}6951J delta 180 zcmbQ>GQnj7ClgC>*um1xyi9)>p)3|Si|r3HRE+BnOdanZ4yc$ITvqBk6Xy?R28ITZ zQImOPrI~&(Z`P94Wn^@ioFZopB-hAY6N+bIU|3P_0EABU`fMxf?K~z=k#}Z1F!_eO tjKo}^q~i3I^@=kb>lJ4*IMvrNG3YQbFiZ}V6Wc7N@QQJw0na2Q0RZnmI^+NV 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":