Skip to content

Commit

Permalink
Custom memory model
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanizag committed Aug 16, 2021
1 parent 4aff688 commit 16dbebc
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 107 deletions.
100 changes: 100 additions & 0 deletions acornMemory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package main

import "io/ioutil"

// FlatMemory puts RAM on the 64Kb addressable by the processor
type AcornMemory struct {
data [65536]uint8
}

// Peek returns the data on the given address
func (m *AcornMemory) Peek(address uint16) uint8 {
return m.data[address]
}

// PeekCode returns the data on the given address
func (m *AcornMemory) PeekCode(address uint16) uint8 {
return m.data[address]
}

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

func (m *AcornMemory) loadBinary(filename string) error {
bytes, err := ioutil.ReadFile(filename)
if err != nil {
return err
}

for i, v := range bytes {
m.Poke(uint16(i), uint8(v))
}

return nil
}

func (m *AcornMemory) getString(address uint16, terminator uint8) string {
str := ""
for {
ch := m.Peek(address)
//fmt.Printf("{%04x: %02x\n", address, ch)
if ch == terminator {
break
}
str += string(ch)
address++
}
return str
}

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++ {
m.Poke(address+uint16(i), s[i])
}
m.Poke(address+uint16(i), terminator)
}

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 {
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 {
return uint16(m.Peek(address)) + uint16(m.Peek(address+1))<<8
}

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 {
ticks := uint64(0)
for i := n - 1; i >= 0; i-- {
ticks <<= 8
ticks += uint64(m.Peek(address + uint16(i)))
}
return ticks
}

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
}
}
10 changes: 5 additions & 5 deletions bbz.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, api
env.referenceTime = time.Now()
env.timer = 0
env.lastTimerUpdate = time.Now()
env.mem = new(core6502.FlatMemory)
env.mem = new(AcornMemory)
env.cpu = core6502.NewNMOS6502(env.mem)
env.cpu.SetTrace(cpuLog)
env.vdu = newVdu()
Expand Down Expand Up @@ -179,15 +179,15 @@ func RunMOSEnvironment(romFilename string, firmFilename string, cpuLog bool, api
language has previously set up to point to its error handler).
*/
pStacked := env.mem.Peek(0x100 + uint16(sp+1))
address := env.peekWord(0x100+uint16(sp+2)) - 1
address := env.mem.peekWord(0x100+uint16(sp+2)) - 1
faultNumber := env.mem.Peek(address)
faultMessage := address + 1
faultString := env.getStringFromMem(faultMessage, 0)
faultString := env.mem.getString(faultMessage, 0)

env.mem.Poke(zpAccumulator, a)
env.pokeWord(zpErrorPointer, address)
env.mem.pokeWord(zpErrorPointer, address)
env.cpu.SetAXYP(pStacked&0x10, x, y, p)
brkv := env.peekWord(vectorBRKV)
brkv := env.mem.peekWord(vectorBRKV)
env.cpu.SetPC(brkv)

env.log(fmt.Sprintf("BREAK(ERR=%02x, '%s')", faultNumber, faultString))
Expand Down
72 changes: 2 additions & 70 deletions 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 core6502.Memory
mem *AcornMemory
vdu *vdu
in *bufio.Scanner

Expand Down Expand Up @@ -81,7 +81,7 @@ func (env *environment) storeError(address uint16, code uint8, msg string, maxMs
*/
env.mem.Poke(address, 0x00 /* BRK opcode */)
env.mem.Poke(address+1, code)
env.putStringInMem(address+2, msg, 0, uint8(maxMsgLen))
env.mem.storeString(address+2, msg, 0, uint8(maxMsgLen))

}

Expand All @@ -104,71 +104,3 @@ func (env *environment) notImplemented(feature string) {
}
env.log(msg)
}

///////////////////////////
// Memory Access
///////////////////////////

func (env *environment) putStringInMem(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++ {
env.mem.Poke(address+uint16(i), s[i])
}
env.mem.Poke(address+uint16(i), terminator)
}

func (env *environment) getStringFromMem(address uint16, terminator uint8) string {
str := ""
for {
ch := env.mem.Peek(address)
//fmt.Printf("{%04x: %02x\n", address, ch)
if ch == terminator {
break
}
str += string(ch)
address++
}
return str
}

func (env *environment) getMemSlice(address uint16, length uint16) []uint8 {
slice := make([]uint8, 0, length)
for i := uint16(0); i < length; i++ {
slice = append(slice, env.mem.Peek(address+i))
}
return slice
}

func (env *environment) storeSliceinMem(address uint16, maxLength uint16, data []uint8) uint16 {
var i uint16
for i = 0; i < maxLength && i < uint16(len(data)); i++ {
env.mem.Poke(address+i, data[i])
}
return i
}

func (env *environment) peekWord(address uint16) uint16 {
return uint16(env.mem.Peek(address)) + uint16(env.mem.Peek(address+1))<<8
}

func (env *environment) pokeWord(address uint16, value uint16) {
env.mem.Poke(address, uint8(value&0xff))
env.mem.Poke(address+1, uint8(value>>8))
}

func (env *environment) peeknbytes(address uint16, n int) uint64 {
ticks := uint64(0)
for i := n - 1; i >= 0; i-- {
ticks <<= 8
ticks += uint64(env.mem.Peek(address + uint16(i)))
}
return ticks
}

func (env *environment) pokenbytes(address uint16, n int, value uint64) {
for i := 0; i < n; i++ {
env.mem.Poke(address+uint16(i), uint8(value&0xff))
value >>= 8
}
}
6 changes: 3 additions & 3 deletions loadMemory.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,15 @@ func loadRom(env *environment, filename string) {
}

// See http://www.sprow.co.uk/bbc/library/sidewrom.pdf
language := env.getStringFromMem(romTitleString, 0)
language := env.mem.getString(romTitleString, 0)
copyrightAddress := 0x8000 + 1 + uint16(env.mem.Peek(romCopyrightOffsetPointer))
copyrigt := env.getStringFromMem(copyrightAddress, 0)
copyrigt := env.mem.getString(copyrightAddress, 0)

/*
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).
*/
env.pokeWord(zpErrorPointer, copyrightAddress)
env.mem.pokeWord(zpErrorPointer, copyrightAddress)
/*
The MOS also automatically prints the ROM's title string (&8009) so that the user is acknowledged.
*/
Expand Down
6 changes: 3 additions & 3 deletions osArgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ func execOSARGS(env *environment) {
if err != nil {
env.raiseError(errorTodo, err.Error())
} else {
env.pokenbytes(uint16(x), 4, uint64(pos))
env.mem.pokenbytes(uint16(x), 4, uint64(pos))
}
env.log(fmt.Sprintf("OSARGS('Get PTR#',FILE=%v) => %v", y, pos))

case 1: // Write sequential pointer of file
pos := int64(env.peeknbytes(uint16(x), 4))
pos := int64(env.mem.peeknbytes(uint16(x), 4))
_, err := file.Seek(pos, io.SeekStart)
if err != nil {
env.raiseError(errorTodo, err.Error())
Expand All @@ -65,7 +65,7 @@ func execOSARGS(env *environment) {
if err != nil {
env.raiseError(errorTodo, err.Error())
} else {
env.pokenbytes(uint16(x), 4, uint64(info.Size()))
env.mem.pokenbytes(uint16(x), 4, uint64(info.Size()))
}
env.log(fmt.Sprintf("OSARGS('Get EXT#',FILE=%v)=%v", y, info.Size()))

Expand Down
2 changes: 1 addition & 1 deletion osCLI.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func execOSCLI(env *environment) {
carriage return character (ASCII &0D/13)
*/
xy := uint16(x) + uint16(y)<<8
line := env.getStringFromMem(xy, 0x0d)
line := env.mem.getString(xy, 0x0d)
fields := strings.Fields(line)
command := strings.ToUpper(fields[0])
// The command-line interpreter does not distinguish between upper and lower case characters in the command name
Expand Down
20 changes: 10 additions & 10 deletions osFile.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ func execOSFILE(env *environment) {

// See: http://beebwiki.mdfs.net/OSFILE
controlBlock := uint16(x) + uint16(y)<<8
filenameAddress := env.peekWord(controlBlock)
loadAddress := env.peekWord(controlBlock + 0x2)
executionAddress := env.peekWord(controlBlock + 0x6)
startAddress := env.peekWord(controlBlock + 0xa)
endAddress := env.peekWord(controlBlock + 0xe)
filenameAddress := env.mem.peekWord(controlBlock)
loadAddress := env.mem.peekWord(controlBlock + 0x2)
executionAddress := env.mem.peekWord(controlBlock + 0x6)
startAddress := env.mem.peekWord(controlBlock + 0xa)
endAddress := env.mem.peekWord(controlBlock + 0xe)

filename := env.getStringFromMem(filenameAddress, 0x0d)
filename := env.mem.getString(filenameAddress, 0x0d)
filesize := endAddress - startAddress

switch a {
Expand All @@ -25,7 +25,7 @@ func execOSFILE(env *environment) {
Save a block of memory as a file using the
information provided in the parameter block.
*/
data := env.getMemSlice(startAddress, filesize)
data := env.mem.getSlice(startAddress, filesize)
err := ioutil.WriteFile(filename, data, 0644)
if err != nil {
env.raiseError(errorTodo, err.Error())
Expand All @@ -48,12 +48,12 @@ func execOSFILE(env *environment) {
env.raiseError(errorTodo, err.Error())
}
// NOTE: There is no maxLength?
env.storeSliceinMem(loadAddress, uint16(len(data)), data)
env.mem.storeSlice(loadAddress, uint16(len(data)), data)
filesize = uint16(len(data))
}

env.pokeWord(controlBlock+0xa, filesize)
env.pokeWord(controlBlock+0x3, 0x33 /*attributes*/)
env.mem.pokeWord(controlBlock+0xa, filesize)
env.mem.pokeWord(controlBlock+0x3, 0x33 /*attributes*/)

env.log(fmt.Sprintf("OSFILE(A=%02x,FCB=%04x,FILE=%s,SIZE=%v)", a, controlBlock, filename, filesize))

Expand Down
2 changes: 1 addition & 1 deletion osFind.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func execOSFIND(env *environment) {

// Open file
address := uint16(x) + uint16(y)<<8
filename := env.getStringFromMem(address, 0x0d)
filename := env.mem.getString(address, 0x0d)

// Find the first free file handle
handle := -1
Expand Down
Loading

0 comments on commit 16dbebc

Please sign in to comment.