Conversation
The Sage II simulator has only ever been exercised by CP/M-68K, and the readme lists the UCSD p-System as not working yet. Trying to boot it turns up thirteen defects in the 68000 core. With these fixes the four Sage p-System IV.13 diskettes and the four Stride IV.21 diskettes reach their command prompts, the Filer lists both drives, and CP/M-68K 1.2 still boots exactly as before. What was wrong: * MOVE.B/.W/.L did not clear V and C. * CMP, CMPA and CMPI wrote the X flag, which they must leave untouched. * CMPA.W compared a truncated address register against an unextended source. * CMPM.B/.W/.L were not implemented. * SUBX had its operands the wrong way round in all six forms. * MOVE to SR, the immediate forms of ANDI/ORI/EORI to SR, and STOP did not swap A7 with USP when the S bit changed, so a program that dropped to user mode carried on pushing onto the supervisor stack. * The 8 bit displacement of the (d8,An,Xn) modes was sign extended as if it were 16 bits, in all eleven places that build such an address. Every negative displacement therefore reached the wrong memory. * OR.L <ea>,Dn computed an AND. * OR.W <ea>,Dn stored its result as a byte. * DIVS.W never fetched its source operand and used whatever the previous instruction had left in the temporary. * DIVS.W divided by the raw unsigned divisor instead of the sign extended one. * The bit mask table had four wrong entries, so BTST, BSET, BCLR and BCHG worked on the wrong bit whenever the bit number was 15, 19, 23 or 27. * ROXR.L and ROXL.L loaded a signed int32 into their 64 bit temporary, which carried the sign into the rotated result. How they were found: a differential tester runs one random instruction at a time on this core and on Musashi from the same starting state, then compares the sixteen registers, the PC, the condition codes and a 64 byte window of memory. Out of 425 comparable cases, 98 disagreed before these fixes and 8 after. Five of those eight are cases where the two models take a different view of addresses outside the simulated 512 KB. The remaining three are the carry flag of ROR.B and ROR.L and the flags of CHK.W, which are still open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Similar comment about identifying who you are mentioned in simh/simh#1256. Otherwise, since you're making a good jump at fixing things here in a simulator which, seems to have had a very quiet life in the 12 years it has been in the codebase, why stop before addressing the remaining 8 cases you found to be unexpected? |
Follow-up to the thirteen fixes already on this branch. The same differential
tester runs one random instruction at a time on this core and on Musashi from
an identical starting state, then compares the sixteen registers, the PC, the
condition codes and a 64 byte window of memory. Running it over four seeds
instead of one, and adding a targeted bank of cases for each family it
touched, brought out seven more real disagreements.
* ror.b, ror.w and ror.l took the carry from the bit one position above the
most significant bit of the result. For a right rotate the bit rotated out
is the msb of the result, and taking it there also makes a count that is a
multiple of the operand width come out right, which it did not before.
* rol.b and rol.w happened to pick the same bit as the least significant bit
of the result for counts of 1 to width-1, but not for multiples of the
width. rol.l was worse: MASK_32L is "& 0xffffffff", so the carry was set
whenever the result was nonzero.
* chk.w compared the whole 32 bit register against an unsigned bound. The
instruction is a signed 16 bit compare on both sides, so any Dn with bit
31 set trapped even when its low word was in range, and a negative bound
never trapped at all. Z, V and C are undefined in the programmer's manual;
they are now what the hardware leaves behind.
* cmpi.b, cmpi.w and cmpi.l set X. cmp, cmpa and cmpm in this file already
save and restore it; cmpi was left out because it shares its case with
subi, which does set X.
* asl.l indexed the carry as bitmask[32-cnt] where lsl.l a few lines below
correctly uses bitmask[33-cnt], and its cnt >= 32 arm still tested
cnt == 16, copied from asl.w, so the carry was never set there at all.
* bset with a register bit number and a memory destination took the bit
number from the register in bits 2..0, which is the effective address
register, not the bit number. btst, bchg and bclr all use bits 11..9.
* the four movem helpers threw away read and write errors. ASSERT_OK ends in
"break", which is meant for the switch in sim_instr; inside the for loop of
a helper it merely leaves the loop, and the function then returns SCPE_OK.
A misaligned movem moved nothing, reported nothing and let the program
counter walk on, while move.w at the same address reports the access.
ASSERT_OKRET, already defined in this file, is the right macro there.
Testing. A targeted bank of twenty cases covering these families, each chosen
so the correct answer is unambiguous, goes from eighteen disagreements to
none, and includes a subi.w control to confirm that subi still sets X. Over
four seeds of eight hundred random instructions the disagreements fall from
sixty to thirty-eight, and every one of the thirty-eight that remain has an
operand whose effective address falls outside the simulated 512 KB, or uses a
68020 memory indirect encoding that a 68000 does not have, so none of them is
an instruction semantics difference any more.
The two defects the differential tester cannot see, because there the two
cores disagree about whether to trap and such cases are skipped, were checked
directly against the programmer's manual instead: chk.w for width and sign,
and movem for the misaligned access.
CP/M-68K 1.2 and the UCSD p-System IV.13 still boot, and the simulator's own
register test still passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
On the remaining eight: they were in the description, but they were not one group, and widening the test changed the picture enough that the honest answer is longer than "three". Five of the eight were never core bugs. They are cases where this core and Musashi take a different view of an access whose effective address falls outside the simulated 512 KB, so there is nothing to fix until someone decides what the Sage ought to do there, and that is a hardware question rather than a 68000 one. The other three were real, and they are fixed in the commit I have just pushed. Going after them turned up four more in the same code, so the commit carries seven:
Why the answer grew is the useful part, so it is worth saying plainly: the "eight" in the description was one seed. Over four seeds of eight hundred random instructions the disagreements go from 60 to 38, and only after these seven fixes is every one of the 38 that remain an out of range address or a 68020 memory indirect encoding rather than an instruction semantics difference. A targeted bank of twenty cases for these families, each chosen so the correct answer is unambiguous and including a CP/M-68K 1.2 and the p-System IV.13 still boot, and the simulator's own register test still passes. On identity: And if that rule means these changes cannot be taken on, I understand, and there are no hard feelings. Each defect above says what was wrong and how it was measured, so the work is there for whoever wants to redo it under their own name. |
The Sage II simulator only ever gets exercised by CP/M-68K, and
readme-sage.txtstill lists UCSD Pascal as "does not run yet". It turns out the p-System is blocked by thirteen separate bugs in the 68000 core rather than by anything specific to the Sage hardware.With this patch:
Command: E(dit, R(un, F(ile, ...and the Filer lists both drivesThe commit message lists all thirteen. The three with the widest reach are probably these:
MOVEnever cleared V and C, which accounts for most of the difference on its own(d8,An,Xn)modes sign extended the 8 bit displacement as if it were 16 bits, in all eleven places that build such an address, so every negative displacement reached the wrong memoryBTST,BSET,BCLRandBCHGworked on the wrong bit whenever the bit number was 15, 19, 23 or 27How this was tested
A differential tester runs one random instruction at a time on this core and on Musashi from the same starting state, then compares the sixteen registers, the PC, the condition codes and a 64 byte window of memory. The SIMH side is driven through the simulator's own command interface, with
deposit,step 1andexamine, so what gets tested is the simulator as built rather than a relinked copy of the core.Out of 425 comparable cases in a run of 800 random instructions, 98 disagreed before these fixes and 8 after. Five of those eight are cases where the two models take a different view of addresses outside the simulated 512 KB. The other three are real and still open: the carry flag of
ROR.BandROR.L, and the flags ofCHK.W.The p-System images used for the boot tests are David Erhart's ImageDisk dumps of original Sage and Stride diskettes. They contain compressed sectors, so they need uncompressing before the simulator will mount them read/write.
🤖 Generated with Claude Code