Skip to content

Commit

Permalink
Support sideways ROMs
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanizag committed Aug 17, 2021
1 parent ad45591 commit 8e39b1f
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 85 deletions.
Binary file added ROMs/BASIC2.ROM
Binary file not shown.
Binary file added ROMs/LISP501.ROM
Binary file not shown.
31 changes: 25 additions & 6 deletions acornMemory.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import (
)

type acornMemory struct {
data [65536]uint8
memLog bool
data [65536]uint8
sideRom [16][]uint8
activeRom uint8
memLog bool
}

func newAcornMemory(memLog bool) *acornMemory {
var a acornMemory
a.memLog = memLog
a.activeRom = 0xf
return &a
}

Expand All @@ -24,6 +27,17 @@ func (m *acornMemory) Poke(address uint16, value uint8) {
}
}

if romStartAddress <= address && address <= romEndAddress {
m.sideRom[m.activeRom][address-romStartAddress] = value
return
}

if address == sheila_rom_latch {
m.activeRom = value & 0xf
if m.memLog {
fmt.Printf("[[[EnableROM(%x)]]]\n", m.activeRom)
}
}
m.data[address] = value
}

Expand All @@ -37,6 +51,10 @@ func (m *acornMemory) Peek(address uint16) uint8 {
}
}

if romStartAddress <= address && address <= romEndAddress {
return m.sideRom[m.activeRom][address-romStartAddress]
}

return value
}

Expand Down Expand Up @@ -67,15 +85,16 @@ func (m *acornMemory) loadFirmware(firmFilename string) {
}
}

func (m *acornMemory) loadRom(filename string) {
func (m *acornMemory) loadRom(filename string, slot uint8) {
data, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}

for i := 0; i < len(data); i++ {
m.data[romStartAddress+uint16(i)] = data[i]
}
m.sideRom[slot] = data

// Cache the ROM type
m.data[romTypeTable+uint16(slot)] = data[romTypeByte-romStartAddress]
}

// helpers
Expand Down
73 changes: 56 additions & 17 deletions asm/firmware.lst
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ Current file: asm/firmware.s
000000r 1
000000r 1
000000r 1 ; constants
000000r 1 .exportzp ROM_SELECT := $f4
000000r 1 .export ROM_TABLE := $023a
000000r 1 .export LANGUAGE_ENTRY := $8000
000000r 1 .export SERVICE_ENTRY := $8003
000000r 1 .export ROM_LATCH := $fe30
000000r 1
000000r 1
000000r 1 ; boot code
Expand Down Expand Up @@ -59,30 +62,66 @@ Current file: asm/firmware.s
00023E 1 xx xx xx xx
00F000 1 .org $f000
00F000 1
00F000 1 ; Send cli command to ROM and check the result
00F000 1 ; Send cli command to ROMS and check the result
00F000 1 ; See https://github.com/raybellis/mos120/blob/2e2ff80708e79553643e4b77c947b0652117731b/mos120.s#L10701
00F000 1 ; Expects A=4, X=F, Y=0, the command to be pointed by $f2
00F000 1 CLITOROM:
00F000 1 20 03 80 jsr SERVICE_ENTRY
00F003 1 AA tax
00F004 1 F0 0E beq CLAIMED
00F000 1 AA CLITOROMS: tax ; Service call number
00F001 1 20 15 F0 jsr OSBYTE_143
00F004 1 F0 0E beq CTR_CLAIMED
00F006 1 00 brk ; "254-Bad command" error
00F007 1 FE .byte $fe
00F008 1 C2 41 44 20 .asciiz "Bad command"
00F00C 1 43 4F 4D 4D
00F010 1 41 4E 44 00
00F014 1 60 CLAIMED: rts
00F008 1 42 61 64 20 .asciiz "Bad command"
00F00C 1 63 6F 6D 6D
00F010 1 61 6E 64 00
00F014 1 60 CTR_CLAIMED: rts
00F015 1
00F015 1
00F015 1 ; area to store an error message
00F015 1 xx xx xx xx .res $fa00 - *
00F019 1 xx xx xx xx
00F01D 1 xx xx xx xx
00F015 1 ;*************************************************************************
00F015 1 ;*
00F015 1 ;* OSBYTE 143: Pass service commands to sideways ROMs
00F015 1 ; On entry X=service call number
00F015 1 ; Y=any additional parameter
00F015 1 ; On entry X=0 if claimed, or preserved if unclaimed
00F015 1 ; Y=any returned parameter
00F015 1 ; When called internally, EQ set if call claimed
00F015 1 ;* See https://github.com/raybellis/mos120/blob/2e2ff80708e79553643e4b77c947b0652117731b/mos120.s#L10683
00F015 1
00F015 1 A5 F4 OSBYTE_143: lda ROM_SELECT ; Get current ROM number
00F017 1 48 pha ; Save it
00F018 1 8A txa ; Pass service call number to A
00F019 1 A2 0F ldx #$0f ; Start at ROM 15
00F01B 1 ; Issue service call loop
00F01B 1 FE 3A 02 NEXT: inc ROM_TABLE,X ; Read bit 7 on ROM type table (no ROM has type 254 &FE)
00F01E 1 DE 3A 02 dec ROM_TABLE,X ;
00F021 1 10 0D bpl SKIP ; If not set (+ve result), step to next ROM down
00F023 1 86 F4 stx ROM_SELECT ; Otherwise, select this ROM, &F4 RAM copy
00F025 1 8E 30 FE stx ROM_LATCH ; Page in selected ROM
00F028 1 20 03 80 jsr SERVICE_ENTRY ; Call the ROM's service entry
00F02B 1 ; X and P do not need to be preserved by the ROM
00F02B 1 AA tax ; On exit pass A to X to chech if claimed
00F02C 1 F0 05 beq CLAIMED ; If 0, service call claimed, reselect ROM and exit
00F02E 1 A6 F4 ldx ROM_SELECT ; Otherwise, get current ROM back
00F030 1 CA SKIP: dex ; Step to next ROM down
00F031 1 10 E8 bpl NEXT ; Loop until done ROM 0
00F033 1
00F033 1 68 CLAIMED: pla ; Get back original ROM number
00F034 1 85 F4 sta ROM_SELECT ; Set ROM number RAM copy
00F036 1 8D 30 FE sta ROM_LATCH ; Page in the original ROM
00F039 1 8A txa ; Pass X back to A to set zero flag
00F03A 1 60 rts ; And return
00F03B 1
00F03B 1
00F03B 1
00F03B 1 ; area to store an error message
00F03B 1 xx xx xx xx .res $fa00 - *
00F03F 1 xx xx xx xx
00F043 1 xx xx xx xx
00FA00 1 .org $fa00
00FA00 1 00 errorArea: brk
00FA01 1 00 errorCode: .byte 0
00FA02 1 C8 45 4C 4C errorMessage: .asciiz "Hello world"
00FA06 1 4F 20 57 4F
00FA0A 1 52 4C 44 00
00FA02 1 48 65 6C 6C errorMessage: .asciiz "Hello world"
00FA06 1 6F 20 77 6F
00FA0A 1 72 6C 64 00
00FA0E 1
00FA0E 1 ; bbz host entry points
00FA0E 1 xx xx xx xx .res $fb00 - *
Expand Down Expand Up @@ -137,7 +176,7 @@ Current file: asm/firmware.s
00FFCB 1 4C 0A FB NVWRCH: jmp epWRCH ; NVWRCH non vectored OSWRCH
00FFCE 1 6C 1C 02 OSFIND: jmp (FINDV) ; OSFIND open or close a file
00FFD1 1 6C 1A 02 jmp (GBPBV) ; OSGBPB transfer block to or from a file
00FFD4 1 6C 18 02 OSBPUT: jmp (BPUTV) ; OSBPUT save a byte to file
00FFD4 1 6C 18 02 OSBPUT: jmp (BPUTV) ; OSBPUT save a byte to file
00FFD7 1 6C 16 02 OSBGET: jmp (BGETV) ; OSBGET get a byte from file
00FFDA 1 6C 14 02 OSARGS: jmp (ARGSV) ; OSARGS read or write file arguments
00FFDD 1 6C 12 02 OSFILE: jmp (FILEV) ; OSFILE read or write a file
Expand Down
55 changes: 47 additions & 8 deletions asm/firmware.s
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
; build:
; cl65 -l asm/firmware.lst asm/firmware.s --config asm/firmware.cfg -o firmware
; cl65 --target none -l asm/firmware.lst asm/firmware.s --config asm/firmware.cfg -o firmware
; Review constants.go when this code is changed


; constants
.exportzp ROM_SELECT := $f4
.export ROM_TABLE := $023a
.export LANGUAGE_ENTRY := $8000
.export SERVICE_ENTRY := $8003
.export ROM_LATCH := $fe30


; boot code
Expand Down Expand Up @@ -51,16 +54,52 @@ IND3V: .addr epIND3
.res $f000 - *
.org $f000

; Send cli command to ROM and check the result
; Send cli command to ROMS and check the result
; See https://github.com/raybellis/mos120/blob/2e2ff80708e79553643e4b77c947b0652117731b/mos120.s#L10701
; Expects A=4, X=F, Y=0, the command to be pointed by $f2
CLITOROM:
jsr SERVICE_ENTRY
tax
beq CLAIMED
CLITOROMS: tax ; Service call number
jsr OSBYTE_143
beq CTR_CLAIMED
brk ; "254-Bad command" error
.byte $fe
.asciiz "Bad command"
CLAIMED: rts
CTR_CLAIMED: rts


;*************************************************************************
;*
;* OSBYTE 143: Pass service commands to sideways ROMs
; On entry X=service call number
; Y=any additional parameter
; On entry X=0 if claimed, or preserved if unclaimed
; Y=any returned parameter
; When called internally, EQ set if call claimed
;* See https://github.com/raybellis/mos120/blob/2e2ff80708e79553643e4b77c947b0652117731b/mos120.s#L10683

OSBYTE_143: lda ROM_SELECT ; Get current ROM number
pha ; Save it
txa ; Pass service call number to A
ldx #$0f ; Start at ROM 15
; Issue service call loop
NEXT: inc ROM_TABLE,X ; Read bit 7 on ROM type table (no ROM has type 254 &FE)
dec ROM_TABLE,X ;
bpl SKIP ; If not set (+ve result), step to next ROM down
stx ROM_SELECT ; Otherwise, select this ROM, &F4 RAM copy
stx ROM_LATCH ; Page in selected ROM
jsr SERVICE_ENTRY ; Call the ROM's service entry
; X and P do not need to be preserved by the ROM
tax ; On exit pass A to X to chech if claimed
beq CLAIMED ; If 0, service call claimed, reselect ROM and exit
ldx ROM_SELECT ; Otherwise, get current ROM back
SKIP: dex ; Step to next ROM down
bpl NEXT ; Loop until done ROM 0

CLAIMED: pla ; Get back original ROM number
sta ROM_SELECT ; Set ROM number RAM copy
sta ROM_LATCH ; Page in the original ROM
txa ; Pass X back to A to set zero flag
rts ; And return



; area to store an error message
Expand Down Expand Up @@ -119,7 +158,7 @@ NVRDCH: jmp epRDCH ; NVRDCH non vectored OSRDCH
NVWRCH: jmp epWRCH ; NVWRCH non vectored OSWRCH
OSFIND: jmp (FINDV) ; OSFIND open or close a file
jmp (GBPBV) ; OSGBPB transfer block to or from a file
OSBPUT: jmp (BPUTV) ; OSBPUT save a byte to file
OSBPUT: jmp (BPUTV) ; OSBPUT save a byte to file
OSBGET: jmp (BGETV) ; OSBGET get a byte from file
OSARGS: jmp (ARGSV) ; OSARGS read or write file arguments
OSFILE: jmp (FILEV) ; OSFILE read or write a file
Expand Down
41 changes: 10 additions & 31 deletions bbz.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,17 @@
package main

import (
"bufio"
"fmt"
"io"
"os"
"time"
"unicode"

"github.com/ivanizag/izapple2/core6502"
)

/*
See:
http://www.sprow.co.uk/bbc/library/sidewrom.pdf
*/

func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, apiLog bool, apiLogIO bool, memLog bool, panicOnErr bool) {
// Prepare environment
var env environment
env.in = bufio.NewScanner(os.Stdin)
env.referenceTime = time.Now()
env.timer = 0
env.lastTimerUpdate = time.Now()
env.mem = newAcornMemory(memLog)
env.cpu = core6502.NewNMOS6502(env.mem)
env.cpu.SetTrace(cpuLog)
env.vdu = newVdu()
env.apiLog = apiLog
env.apiLogIO = apiLogIO
env.panicOnErr = panicOnErr

env.mem.loadFirmware(firmFilename)
env.mem.loadRom(romFilename)
func RunMOS(env *environment) {

/*
Next, the MOS will set the error point at &FD/&FE to point at the version string (or copyright
Expand All @@ -55,10 +34,10 @@ func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, api

if pc == romStartAddress {
a, _, _, _ := env.cpu.GetAXYP()
env.log(fmt.Sprintf("LANGUAGE(A=%02x)", a))
env.log(fmt.Sprintf("LANGUAGE(A=%02x, ROM=%x)", a, env.mem.activeRom))
} else if pc == romServiceEntry {
a, x, _, _ := env.cpu.GetAXYP()
env.log(fmt.Sprintf("SERVICE(CMD=%02x, SLOT=%02x)", a, x))
a, _, _, _ := env.cpu.GetAXYP()
env.log(fmt.Sprintf("SERVICE(CMD=%02x, ROM=%x)", a, env.mem.activeRom))
} else if pc >= entryPoints && pc <= epEntryPointsLast {
a, x, y, p := env.cpu.GetAXYP()

Expand All @@ -75,7 +54,7 @@ func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, api
env.notImplemented(fmt.Sprintf("OSFSC(A=0x%02x,X=0x%02x,y=0x%02x)", a, x, y))

case epFIND: // OSFIND
execOSFIND(&env)
execOSFIND(env)

case epGBPB: // OSGBPB
/*
Expand Down Expand Up @@ -133,10 +112,10 @@ func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, api
env.log(fmt.Sprintf("OSBGET(FILE=%v)=0x%02x,EOF=%v", y, value, eof))

case epARGS: // OSARGS
execOSARGS(&env)
execOSARGS(env)

case epFILE: // OSFILE: Load or save a complete file. BPUG page 446
execOSFILE(&env)
execOSFILE(env)

case epRDCH: // OSRDCH
/*
Expand Down Expand Up @@ -170,13 +149,13 @@ func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, api
env.logIO(fmt.Sprintf("OSWRCH(0x%02x, '%v')", a, ch))

case epWORD: // OSWORD
execOSWORD(&env)
execOSWORD(env)

case epBYTE: // OSBYTE
execOSBYTE(&env)
execOSBYTE(env)

case epCLI: // OSCLI
execOSCLI(&env)
execOSCLI(env)

case epBRK: // BRKV
// The selected ROM has not defined a custom BRKV
Expand Down
10 changes: 8 additions & 2 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,24 @@ Memory map, pages:
*/
const (
zpStr uint16 = 0x00f2 // OSCLI command line
zpROMSelect uint16 = 0x00f4
zpAccumulator uint16 = 0x00fc
zpErrorPointer uint16 = 0x00fd

vectorBRK uint16 = 0x0202
vectorBRK uint16 = 0x0202
romTypeTable uint16 = 0x023a

// ROM header https://tobylobster.github.io/mos/mos/S-s2.html#SP26
userMemBottom uint16 = 0x0e00
romStartAddress uint16 = 0x8000
romEndAddress uint16 = 0xbfff
romServiceEntry uint16 = 0x8003
romTypeByte uint16 = 0x8006
romCopyrightOffsetPointer uint16 = 0x8007
romTitleString uint16 = 0x8009

// Support code on the firmware. Check firmware.lst when changing firmware.s
procCLITOROM uint16 = 0xf000
procCLITOROMS uint16 = 0xf000

// Scratch area for errors in page 0xfa
errorArea uint16 = 0xfa00
Expand Down Expand Up @@ -74,6 +77,9 @@ const (
epIND3 uint16 = 0xfb20
epEntryPointsLast uint16 = 0xfb20

// Fred, Jim and Sheila
sheila_rom_latch uint16 = 0xfe30

maxFiles = 5
errorTodo uint8 = 129 // TODO: find proper error number
)
Loading

0 comments on commit 8e39b1f

Please sign in to comment.