Skip to content

Commit

Permalink
Trace access to Fred, Jim and Sheila
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanizag committed Aug 16, 2021
1 parent 16dbebc commit cf74b04
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 188 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ bbz [flags] [filename]
`filename` is the filename of the ROM to run. With no arguments it
runs the BBC Basic ROM in `BASIC.ROM`.

Avaliable flags (to put before the ROM filename if present):
AvaIlable flags (to put before the ROM filename if present):

```
-M dump to the console the MOS calls including console I/O calls
-c dump to the console the CPU execution operations
-m dump to the console the MOS calls excluding console I/O calls
-p panic on not implemented MOS calls
-s dump to the console the accesses to Fred, Jim or Sheila
```

## Usage example
Expand Down
99 changes: 72 additions & 27 deletions acornMemory.go
Original file line number Diff line number Diff line change
@@ -1,41 +1,86 @@
package main

import "io/ioutil"
import (
"fmt"
"io/ioutil"
)

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

// FlatMemory puts RAM on the 64Kb addressable by the processor
type AcornMemory struct {
data [65536]uint8
func newAcornMemory(memLog bool) *acornMemory {
var a acornMemory
a.memLog = memLog
return &a
}

// Peek returns the data on the given address
func (m *AcornMemory) Peek(address uint16) uint8 {
return m.data[address]
func (m *acornMemory) Poke(address uint16, value uint8) {
if m.memLog {
area := memoryArea(address)
if area != "" {
fmt.Printf("[[[Poke(%s:%02x, %02x]]]\n", area, address&0xff, value)
}
}

m.data[address] = value
}

// PeekCode returns the data on the given address
func (m *AcornMemory) PeekCode(address uint16) uint8 {
return m.data[address]
func (m *acornMemory) Peek(address uint16) uint8 {
value := m.data[address]

if m.memLog {
area := memoryArea(address)
if area != "" {
fmt.Printf("[[[Peek(%s:%02x) => %02x]]]\n", area, address&0xff, value)
}
}

return value
}

// Poke sets the data at the given address
func (m *AcornMemory) Poke(address uint16, value uint8) {
m.data[address] = value
func (m *acornMemory) PeekCode(address uint16) uint8 {
return m.Peek(address)
}

func (m *AcornMemory) loadBinary(filename string) error {
bytes, err := ioutil.ReadFile(filename)
func memoryArea(address uint16) string {
switch address >> 8 {
case 0xfc:
return "FRED"
case 0xfd:
return "JIM"
case 0xfe:
return "SHEILA"
}
return ""
}

func (m *acornMemory) loadFirmware(firmFilename string) {
data, err := ioutil.ReadFile(firmFilename)
if err != nil {
return err
panic(err)
}

for i, v := range bytes {
m.Poke(uint16(i), uint8(v))
for i := 0; i < len(data); i++ {
m.data[i] = data[i]
}
}

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

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

func (m *AcornMemory) getString(address uint16, terminator uint8) string {
// helpers

func (m *acornMemory) getString(address uint16, terminator uint8) string {
str := ""
for {
ch := m.Peek(address)
Expand All @@ -49,7 +94,7 @@ func (m *AcornMemory) getString(address uint16, terminator uint8) string {
return str
}

func (m *AcornMemory) storeString(address uint16, s string, terminator uint8, maxLength uint8) {
func (m *acornMemory) storeString(address uint16, s string, terminator uint8, maxLength uint8) {
// maxLength not including terminator
var i int
for i = 0; i < len(s) && i < int(maxLength); i++ {
Expand All @@ -58,32 +103,32 @@ func (m *AcornMemory) storeString(address uint16, s string, terminator uint8, ma
m.Poke(address+uint16(i), terminator)
}

func (m *AcornMemory) getSlice(address uint16, length uint16) []uint8 {
func (m *acornMemory) getSlice(address uint16, length uint16) []uint8 {
slice := make([]uint8, 0, length)
for i := uint16(0); i < length; i++ {
slice = append(slice, m.Peek(address+i))
}
return slice
}

func (m *AcornMemory) storeSlice(address uint16, maxLength uint16, data []uint8) uint16 {
func (m *acornMemory) storeSlice(address uint16, maxLength uint16, data []uint8) uint16 {
var i uint16
for i = 0; i < maxLength && i < uint16(len(data)); i++ {
m.Poke(address+i, data[i])
}
return i
}

func (m *AcornMemory) peekWord(address uint16) uint16 {
func (m *acornMemory) peekWord(address uint16) uint16 {
return uint16(m.Peek(address)) + uint16(m.Peek(address+1))<<8
}

func (m *AcornMemory) pokeWord(address uint16, value uint16) {
func (m *acornMemory) pokeWord(address uint16, value uint16) {
m.Poke(address, uint8(value&0xff))
m.Poke(address+1, uint8(value>>8))
}

func (m *AcornMemory) peeknbytes(address uint16, n int) uint64 {
func (m *acornMemory) peeknbytes(address uint16, n int) uint64 {
ticks := uint64(0)
for i := n - 1; i >= 0; i-- {
ticks <<= 8
Expand All @@ -92,7 +137,7 @@ func (m *AcornMemory) peeknbytes(address uint16, n int) uint64 {
return ticks
}

func (m *AcornMemory) pokenbytes(address uint16, n int, value uint64) {
func (m *acornMemory) pokenbytes(address uint16, n int, value uint64) {
for i := 0; i < n; i++ {
m.Poke(address+uint16(i), uint8(value&0xff))
value >>= 8
Expand Down
33 changes: 25 additions & 8 deletions bbz.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,48 @@ import (
"github.com/ivanizag/izapple2/core6502"
)

func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, apiLog bool, apiLogIO bool, panicOnErr bool) {
/*
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 = new(AcornMemory)
env.mem = newAcornMemory(memLog)
env.cpu = core6502.NewNMOS6502(env.mem)
env.cpu.SetTrace(cpuLog)
env.vdu = newVdu()

loadMosFromFile(&env, firmFilename)
loadRom(&env, romFilename)

env.apiLog = apiLog
env.apiLogIO = apiLogIO
env.panicOnErr = panicOnErr

env.mem.loadFirmware(firmFilename)
env.mem.loadRom(romFilename)

/*
Next, the MOS will set the error point at &FD/&FE to point at the version string (or copyright
message if no version string is present).
*/
copyrightAddress := 0x8000 + 1 + uint16(env.mem.Peek(romCopyrightOffsetPointer))
copyrigt := env.mem.getString(copyrightAddress, 0)
env.mem.pokeWord(zpErrorPointer, copyrightAddress)
/*
The MOS also automatically prints the ROM's title string (&8009) so that the user is acknowledged.
*/
language := env.mem.getString(romTitleString, 0)
fmt.Printf("%s - %s\n", language, copyrigt)

// Execute
for !env.stop {
env.cpu.ExecuteInstruction()

pc, sp := env.cpu.GetPCAndSP()
if pc >= entryPoints && pc < mosVectors {
if pc >= entryPoints && pc <= epEntryPointsLast {
a, x, y, p := env.cpu.GetAXYP()

// Intercept MOS API calls.
Expand Down Expand Up @@ -187,7 +204,7 @@ func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, api
env.mem.Poke(zpAccumulator, a)
env.mem.pokeWord(zpErrorPointer, address)
env.cpu.SetAXYP(pStacked&0x10, x, y, p)
brkv := env.mem.peekWord(vectorBRKV)
brkv := env.mem.peekWord(vectorBRK)
env.cpu.SetPC(brkv)

env.log(fmt.Sprintf("BREAK(ERR=%02x, '%s')", faultNumber, faultString))
Expand Down
75 changes: 75 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

/*
Memory map, pages:
00: zero page
01: stack
02: mos vectors and other
...
80: loaded rom
...
fa: brk error messages
fb: entrypoints trapped by the host
fc: FRED
fd: JIM
fe: SHEILA
ff: mos and 6502 entrypoints
*/
const (
zpAccumulator uint16 = 0x00fc
zpErrorPointer uint16 = 0x00fd

vectorBRK uint16 = 0x0202

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

// Scratch area for errors in page 0xfa
errorArea uint16 = 0xfa00
errorMessageMaxLength int = 100

// Entry points for host interception in page 0xfb
entryPoints uint16 = 0xfb00
epUPT uint16 = 0xfb00
epEVNT uint16 = 0xfb01
epFSC uint16 = 0xfb02
epFIND uint16 = 0xfb03
epGBPB uint16 = 0xfb04
epBPUT uint16 = 0xfb05
epBGET uint16 = 0xfb06
epARGS uint16 = 0xfb07
epFILE uint16 = 0xfb08
epRDCH uint16 = 0xfb09
epWRCH uint16 = 0xfb0a
epWORD uint16 = 0xfb0b
epBYTE uint16 = 0xfb0c
epCLI uint16 = 0xfb0d
epIRQ2 uint16 = 0xfb0e
epIRQ1 uint16 = 0xfb0f
epBRK uint16 = 0xfb10
epUSER uint16 = 0xfb11
epSYSBRK uint16 = 0xfb12
epRDRM uint16 = 0xfb13
epVDUCH uint16 = 0xfb14
epGSINIT uint16 = 0xfb16
epGSREAD uint16 = 0xfb17
epNET uint16 = 0xfb18
epVDU uint16 = 0xfb19
epKEY uint16 = 0xfb1a
epINS uint16 = 0xfb1b
epREM uint16 = 0xfb1c
epCNP uint16 = 0xfb1d
epIND1 uint16 = 0xfb1e
epIND2 uint16 = 0xfb1f
epIND3 uint16 = 0xfb20
epEntryPointsLast uint16 = 0xfb20

maxFiles = 5
errorTodo uint8 = 129 // TODO: find proper error number
)
2 changes: 1 addition & 1 deletion environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

type environment struct {
cpu *core6502.State
mem *AcornMemory
mem *acornMemory
vdu *vdu
in *bufio.Scanner

Expand Down
Loading

0 comments on commit cf74b04

Please sign in to comment.