From 0f37a4394290d360068ac4ded7bbe3b75886f7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Izaguirre?= Date: Fri, 10 Sep 2021 16:12:58 +0200 Subject: [PATCH] Acceptance testing, OSRDRM, OSBYTE86, OSBYTE97 --- acornMemory.go | 6 ++++++ bbz.go | 15 +++++++++++++++ beeb_fstest_test.go | 14 +++----------- consoleMock.go | 3 +-- constants.go | 6 ++++-- environment.go | 4 ++-- files.go | 4 ++-- integrationTesting.go | 13 +++++++++++++ osByte.go | 10 ++++++++++ osCLI.go | 28 ++++++++++++---------------- osCLI_test.go | 36 ++++++++++++++++++++++++++---------- osWord.go | 11 ++++++++++- 12 files changed, 104 insertions(+), 46 deletions(-) create mode 100644 integrationTesting.go diff --git a/acornMemory.go b/acornMemory.go index fba1d04..922b699 100644 --- a/acornMemory.go +++ b/acornMemory.go @@ -58,6 +58,12 @@ func (m *acornMemory) Peek(address uint16) uint8 { } } + return m.peekInternal(address) +} + +func (m *acornMemory) peekInternal(address uint16) uint8 { + value := m.data[address] + if romStartAddress <= address && address <= romEndAddress && len(m.sideRom[m.activeRom]) > 0 { slot := m.sideRom[m.activeRom] if len(slot) > int(address-romStartAddress) { diff --git a/bbz.go b/bbz.go index c49c904..42c6cc5 100644 --- a/bbz.go +++ b/bbz.go @@ -145,6 +145,16 @@ func RunMOS(env *environment) { // The selected ROM has not defined a custom BRKV panic("Unhandled BRK") + case epRDRM: // OSRDRM + currentRom := env.mem.Peek(sheilaRomLatch) + address := env.mem.peekWord(zpAddress) + env.mem.Poke(sheilaRomLatch, y) + value := env.mem.Peek(address) + + env.cpu.SetAXYP(value, currentRom, 0, p) + env.mem.Poke(sheilaRomLatch, currentRom) + env.logIO(fmt.Sprintf("OSRDRM(%v:%04x)=%02x", y, address, value)) + case epSYSBRK: // 6502 BRK handler /* When the 6512 encounters a BRK instruction the operating system places @@ -181,6 +191,11 @@ func RunMOS(env *environment) { env.log(fmt.Sprintf("BREAK(ERR=%02x, '%s')", faultNumber, faultString)) + if env.panicOnErr && faultNumber == 0 && faultString == "" { + // The code is probably running on zeroed memory + panic("Running on zeroed memory") + } + default: env.notImplemented(fmt.Sprintf("MOS(EP=0x%04x,A=0x%02x,X=0x%02x,y=0x%02x)", pc, a, x, y)) } diff --git a/beeb_fstest_test.go b/beeb_fstest_test.go index 32a94a9..f995199 100644 --- a/beeb_fstest_test.go +++ b/beeb_fstest_test.go @@ -6,23 +6,15 @@ import ( ) func Test_beeb_ftest(t *testing.T) { - - def := "BASIC.ROM" - roms := []*string{&def} - - env := newEnvironment(roms, false, false, false, false, false) - con := newConsoleMock(env, []string{ + out := integrationTestBasic([]string{ "LOAD \"test/beeb-fstest/0/$.FSTEST\"", "1661 GOTO 1690", // Skip OSGBPB 06 and 07 tests "1791 GOTO 2130", // Skip OSGBPB 08 tests "RUN", }) - env.con = con - - RunMOS(env) - if !strings.Contains(con.output, "GOOD. TOOK") { - t.Log(con.output) + if !strings.Contains(out, "GOOD. TOOK") { + t.Log(out) t.Error("beeb-fstest failed") } } diff --git a/consoleMock.go b/consoleMock.go index 1dd802a..3e4686e 100644 --- a/consoleMock.go +++ b/consoleMock.go @@ -21,8 +21,7 @@ func (c *consoleMock) readline() (string, bool) { return "", true } line := c.linesIn[c.lineIn] - c.env.writeSpool(line) - c.env.writeSpool("\n") + c.write(line + "\n") c.lineIn++ return line, false } diff --git a/constants.go b/constants.go index ffce674..ffb5128 100644 --- a/constants.go +++ b/constants.go @@ -22,6 +22,7 @@ const ( zpY uint16 = 0x00f1 zpStr uint16 = 0x00f2 // OSCLI command line zpROMSelect uint16 = 0x00f4 + zpAddress uint16 = 0x00f6 zpAccumulator uint16 = 0x00fc zpErrorPointer uint16 = 0x00fd zpEscapeFlag uint16 = 0x00ff @@ -51,8 +52,8 @@ const ( //serviceNoOperation uint8 = 0 serviceOSCLI uint8 = 4 serviceOSBYTE uint8 = 7 - //serviceOSWORD uint8 = 8 - serviceHELP uint8 = 9 + serviceOSWORD uint8 = 8 + serviceHELP uint8 = 9 // Scratch area for errors in page 0xfa errorArea uint16 = 0xfa00 @@ -96,6 +97,7 @@ const ( epEntryPointsLast uint16 = 0xfb1f // Fred, Jim and Sheila + sheilaStart uint16 = 0xf000 sheilaRomLatch uint16 = 0xfe30 maxFiles uint8 = 100 diff --git a/environment.go b/environment.go index b9120e5..9f6a95d 100644 --- a/environment.go +++ b/environment.go @@ -41,8 +41,8 @@ func newEnvironment(roms []*string, cpuLog bool, apiLog bool, apiLogIO bool, mem env.lastTimerUpdate = time.Now() env.lastEscapeTimestamp = time.Now() env.mem = newAcornMemory(memLog) - env.cpu = core6502.NewNMOS6502(env.mem) - //env.cpu = core6502.NewCMOS65c02(env.mem) + //env.cpu = core6502.NewNMOS6502(env.mem) + env.cpu = core6502.NewCMOS65c02(env.mem) env.cpu.SetTrace(cpuLog) env.vdu = newVdu(&env) env.apiLog = apiLog diff --git a/files.go b/files.go index 3316eb7..f1ceedd 100644 --- a/files.go +++ b/files.go @@ -64,13 +64,13 @@ func (env *environment) closeFile(handle uint8) { } func (env *environment) writeSpool(s string) { - charDest := env.mem.Peek(charDestinations) + charDest := env.mem.peekInternal(charDestinations) if charDest&0x10 != 0 { // Spooled output is disabled return } - spoolHandle := env.mem.Peek(spoolFileHandle) + spoolHandle := env.mem.peekInternal(spoolFileHandle) if spoolHandle == 0 { // No spool file defined return diff --git a/integrationTesting.go b/integrationTesting.go new file mode 100644 index 0000000..8fc2fa7 --- /dev/null +++ b/integrationTesting.go @@ -0,0 +1,13 @@ +package main + +func integrationTestBasic(lines []string) string { + + def := "BASIC.ROM" + roms := []*string{&def} + + env := newEnvironment(roms, false, false, false, false, false) + con := newConsoleMock(env, lines) + env.con = con + RunMOS(env) + return con.output +} diff --git a/osByte.go b/osByte.go index 0f2b25b..2172427 100644 --- a/osByte.go +++ b/osByte.go @@ -250,6 +250,12 @@ func execOSBYTE(env *environment) { newX = uint8(romStartAddress & 0xff) newY = uint8(romStartAddress >> 8) + case 0x86: + option = "Read text cursor position" + // Not implemented. Returns 1, 1 + newX = 1 + newY = 1 + case 0x87: option = "Read character at text cursor position" /* @@ -284,6 +290,10 @@ func execOSBYTE(env *environment) { env.initLanguage(x) newA = 1 + case 0x97: + option = "Write SHEILA" + env.mem.Poke(sheilaStart+uint16(x), y) + case 0xa0: option = "Read VDU variable value" /* diff --git a/osCLI.go b/osCLI.go index 36a63ed..f4586d7 100644 --- a/osCLI.go +++ b/osCLI.go @@ -261,7 +261,7 @@ func execOSCLI(env *environment) { execOSCLIfx(env, 0x8d, line, pos) case "ROMS": - selectedROM := env.mem.Peek(sheilaRomLatch) + currentRom := env.mem.Peek(sheilaRomLatch) for i := 0xf; i >= 0; i-- { if env.mem.writeProtectRom[i] { env.mem.Poke(sheilaRomLatch, uint8(i)) @@ -286,7 +286,7 @@ func execOSCLI(env *environment) { env.con.write(fmt.Sprintf("RAM %X 16K\n", i)) } } - env.mem.Poke(sheilaRomLatch, selectedROM) + env.mem.Poke(sheilaRomLatch, currentRom) case "SAVE": // *SAVE [] [] @@ -387,31 +387,27 @@ func execOSCLI(env *environment) { func execOSCLIfx(env *environment, argA uint8, line string, pos int) { argX := uint8(0) argY := uint8(0) - fail := false + var valid bool if line[pos] != '\r' { - if line[pos] != ',' { - env.raiseError(254, "Bad Command") - return + if line[pos] == ',' { + pos++ // Skip ',' } - pos++ // Skip ',' pos = parseSkipSpaces(line, pos) - pos, argX, fail = parseByte(line, pos) - if fail { + pos, argX, valid = parseByte(line, pos) + if !valid { env.raiseError(254, "Bad Command") return } } if line[pos] != '\r' { - if line[pos] != ',' { - env.raiseError(254, "Bad Command") - return + if line[pos] == ',' { + pos++ // Skip ',' } - pos++ // Skip ',' pos = parseSkipSpaces(line, pos) - _, argY, fail = parseByte(line, pos) - if fail { + _, argY, valid = parseByte(line, pos) + if !valid { env.raiseError(254, "Bad Command") return } @@ -465,7 +461,7 @@ func parseByte(line string, pos int) (int, uint8, bool) { return cursor, 0, false } - cursor = parseSkipSpaces(line, pos) + cursor = parseSkipSpaces(line, cursor) return cursor, uint8(value), true } diff --git a/osCLI_test.go b/osCLI_test.go index d0b4a63..00dbf4c 100644 --- a/osCLI_test.go +++ b/osCLI_test.go @@ -6,20 +6,36 @@ import ( ) func Test_OSCLI_HELP(t *testing.T) { + out := integrationTestBasic([]string{ + "*HELP", + }) - def := "BASIC.ROM" - roms := []*string{&def} + if !strings.Contains(out, "BBZ") { + t.Log(out) + t.Error("*HELP is not returning BBZ") + } +} - env := newEnvironment(roms, false, false, false, false, false) - con := newConsoleMock(env, []string{ - "*HELP", +func Test_OSCLI_FX_commas(t *testing.T) { + out := integrationTestBasic([]string{ + "*FX 200,3", + "IF ERR=40 PRINT \"PA\" + \"SS\"", }) - env.con = con - RunMOS(env) + if !strings.Contains(out, "PASS") { + t.Log(out) + t.Error("*FX error") + } +} - if !strings.Contains(con.output, "BBZ") { - t.Log(con.output) - t.Error("*HELP is not returning BBZ") +func Test_OSCLI_FX_spaces(t *testing.T) { + out := integrationTestBasic([]string{ + "*FX200 3 1", + "IF ERR=40 PRINT \"PA\" + \"SS\"", + }) + + if !strings.Contains(out, "PASS") { + t.Log(out) + t.Error("*FX error") } } diff --git a/osWord.go b/osWord.go index 185bae4..0e1067a 100644 --- a/osWord.go +++ b/osWord.go @@ -144,6 +144,15 @@ func execOSWORD(env *environment) { env.log(fmt.Sprintf("OSWORD08('Define envelope',NUMBER=%v)", number)) default: - env.notImplemented(fmt.Sprintf("OSWORD%02x", a)) + + // Send to the other ROMS if available. + env.mem.Poke(zpA, a) + env.mem.Poke(zpX, x) + env.mem.Poke(zpY, y) + env.cpu.SetAXYP(serviceOSWORD, x, y, p) + + env.cpu.SetPC(procServiceRoms) + env.log(fmt.Sprintf("OSWORD%02x_to_roms(X=0x%02x,Y=0x%02x)", a, x, y)) + // procServiceRoms issues a 254-Bad command if the command is not handled by any ROM } }