Skip to content

Commit

Permalink
corrected how PlusROM reads host/path information
Browse files Browse the repository at this point in the history
fixes issue #35
  • Loading branch information
JetSetIlly committed Dec 14, 2024
1 parent 3029b8c commit 58d289e
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 42 deletions.
2 changes: 1 addition & 1 deletion hardware/memory/cartridge/cartridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ func (cart *Cartridge) Attach(cartload cartridgeloader.Loader) error {
// is PlusROM cartridge (which can be combined with a regular cartridge
// format)
if cart.fingerprintPlusROM(cartload) {
plus, err := plusrom.NewPlusROM(cart.env, cart.mapper)
plus, err := plusrom.NewPlusROM(cart.env, cart.mapper, cartload)

if err != nil {
if errors.Is(err, plusrom.NotAPlusROM) {
Expand Down
81 changes: 40 additions & 41 deletions hardware/memory/cartridge/plusrom/plusrom.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package plusrom
import (
"errors"
"fmt"
"io"
"strings"

"github.com/jetsetilly/gopher2600/environment"
Expand Down Expand Up @@ -59,75 +60,73 @@ func (s *state) Plumb(env *environment.Environment) {
s.child.Plumb(env)
}

func NewPlusROM(env *environment.Environment, child mapper.CartMapper) (mapper.CartMapper, error) {
func NewPlusROM(env *environment.Environment, child mapper.CartMapper, romfile io.ReadSeeker) (mapper.CartMapper, error) {
cart := &PlusROM{env: env}
cart.state = &state{}
cart.state.child = child

cart.net = newNetwork(cart.env)

// get reference to last bank
banks := child.CopyBanks()
if banks == nil {
return nil, fmt.Errorf("plusrom: %w: %s is not providing bank data", CannotAdoptROM, child.ID())
}
lastBank := banks[cart.NumBanks()-1]

// host/path information is found at address 0x1ffa. we've got a reference
// to the last bank above but we need to consider that the last bank might not
// take the entirity of the cartridge map.
addrMask := uint16(len(lastBank.Data) - 1)
// host/path information are found at the address pointed to by an address
// stored near the end of the ROM file. this is roughly equivalent to the
// NMI vector of the last bank stored in the ROM file

// host/path information are found at the address pointed to by the following
// 16bit address
const addrinfoMSB = 0x1ffb
const addrinfoLSB = 0x1ffa
var b [2]byte

a := uint16(lastBank.Data[addrinfoLSB&addrMask])
a |= (uint16(lastBank.Data[addrinfoMSB&addrMask]) << 8)
_, err := romfile.Seek(-6, io.SeekEnd)
if err != nil {
return nil, fmt.Errorf("plusrom: %w: %w", CannotAdoptROM, err)
}
n, err := romfile.Read(b[:])
if err != nil {
if !errors.Is(err, io.EOF) {
return nil, fmt.Errorf("plusrom: %w: %w", CannotAdoptROM, err)
}
}
if n != 2 {
return nil, fmt.Errorf("plusrom: %w: invalid NMI vector", CannotAdoptROM)
}

// get bank to which the NMI vector points
b := int((a & 0xf000) >> 12)
// the address of the host/path information
hostPathAddr := (uint16(b[1]) << 8) | uint16(b[0])

if b == 0 || b > cart.NumBanks() {
return nil, fmt.Errorf("plusrom: %w: invalid NMI vector", NotAPlusROM)
}
// the retrieved address is defined to be relative to memory origin 0x1000
// but is actually an offset into the ROM file. correcting the origin
// address by subtracting 0x1000
hostPathAddr -= 0x1000

// normalise indirect address so it's suitable for indexing bank data
a &= addrMask
logger.Logf(env, "plusrom", "host address at ROM offset 0x%04x", hostPathAddr)

// get the bank to which the NMI vector points
lastBank = child.CopyBanks()[b-1]
_, err = romfile.Seek(int64(hostPathAddr), io.SeekStart)
if err != nil {
return nil, fmt.Errorf("plusrom: %w: %w", CannotAdoptROM, err)
}

// read path string from the first bank using the indirect address retrieved above
path := strings.Builder{}
for path.Len() < maxPathLength {
if int(a) >= len(lastBank.Data) {
a = 0x0000
_, err := romfile.Read(b[:1])
if err != nil {
return nil, fmt.Errorf("plusrom: %w: %w", CannotAdoptROM, err)
}
c := lastBank.Data[a]

a++
if c == 0x00 {
if b[0] == 0x00 {
break // for loop
}
path.WriteRune(rune(c))
path.WriteRune(rune(b[0]))
}

// read host string. this string continues on from the path string. the
// address pointer will be in the correct place.
host := strings.Builder{}
for host.Len() <= maxHostLength {
if int(a) >= len(lastBank.Data) {
a = 0x0000
_, err := romfile.Read(b[:1])
if err != nil {
return nil, fmt.Errorf("plusrom: %w: %w", CannotAdoptROM, err)
}
c := lastBank.Data[a]

a++
if c == 0x00 {
if b[0] == 0x00 {
break // for loop
}
host.WriteRune(rune(c))
host.WriteRune(rune(b[0]))
}

// fail if host or path is not valid
Expand Down

0 comments on commit 58d289e

Please sign in to comment.