1
0
mirror of https://github.com/ariejan/i6502.git synced 2024-05-28 22:41:34 +00:00
i6502/address_bus.go
Marco Peereboom 43f3d06988 Iterate over pointers instead of copies.
Modify addressable to become a pointer because Go's range does not
provide a pointer to the element but a copy of the element (urgh).

Go's range operator really can be considered broken.  In this case it
copies the addressable all the time which significantly slows things
down.  To boot, it isn't writing in the memory you think it is (it ends
up in the copy of memory).

Before the change:
$ go test -v -test.run Klaus
=== RUN TestKlausDormann6502
Running Klaus Dormann' 6502 functional tests. This may take some time...
Klaus Dormann's 6502 functional tests passed.
--- PASS: TestKlausDormann6502 (13.51s)
PASS
ok      github.com/ariejan/i6502        13.522s

After the change:
$ go test -v -test.run Klaus
=== RUN TestKlausDormann6502
Running Klaus Dormann' 6502 functional tests. This may take some time...
Klaus Dormann's 6502 functional tests passed.
--- PASS: TestKlausDormann6502 (4.87s)
PASS
ok      github.com/ariejan/i6502        4.877s
2015-04-08 16:56:35 -05:00

121 lines
3.2 KiB
Go

package i6502
import (
"fmt"
)
/*
The AddressBus contains a list of all attached memory components,
like Ram, Rom and IO. It takes care of mapping the global 16-bit
address space of the Cpu to the relative memory addressing of
each component.
*/
type AddressBus struct {
addressables []*addressable // Different components
}
type addressable struct {
memory Memory // Actual memory
start uint16 // First address in address space
end uint16 // Last address in address space
}
func (a *addressable) String() string {
return fmt.Sprintf("\t0x%04X-%04X\n", a.start, a.end)
}
// Creates a new, empty 16-bit AddressBus
func NewAddressBus() (*AddressBus, error) {
return &AddressBus{addressables: make([]*addressable, 0)}, nil
}
// Returns a string with details about the AddressBus and attached memory
func (a *AddressBus) String() string {
output := "Address Bus:\n"
for _, addressable := range a.addressables {
output += addressable.String()
}
return output
}
/*
Attach the given Memory at the specified memory offset.
To attach 16kB ROM at 0xC000-FFFF, you simple attach the Rom at
address 0xC000, the Size of the Memory determines the end-address.
rom, _ := i6502.NewRom(0x4000)
bus.Attach(rom, 0xC000)
*/
func (a *AddressBus) Attach(memory Memory, offset uint16) {
start := offset
end := offset + memory.Size() - 1
addressable := addressable{memory: memory, start: start, end: end}
a.addressables = append(a.addressables, &addressable)
}
/*
Read an 8-bit value from Memory attached at the 16-bit address.
This will panic if you try to read from an address that has no Memory attached.
*/
func (a *AddressBus) ReadByte(address uint16) byte {
addressable, err := a.addressableForAddress(address)
if err != nil {
panic(err)
}
return addressable.memory.ReadByte(address - addressable.start)
}
/*
Convenience method to quickly read a 16-bit value from address and address + 1.
Note that we first read the LOW byte from address and then the HIGH byte from address + 1.
*/
func (a *AddressBus) Read16(address uint16) uint16 {
lo := uint16(a.ReadByte(address))
hi := uint16(a.ReadByte(address + 1))
return (hi << 8) | lo
}
/*
Write an 8-bit value to the Memory at the 16-bit address.
This will panic if you try to write to an address that has no Memory attached or
Memory that is read-only, like Rom.
*/
func (a *AddressBus) WriteByte(address uint16, data byte) {
addressable, err := a.addressableForAddress(address)
if err != nil {
panic(err)
}
addressable.memory.WriteByte(address-addressable.start, data)
}
/*
Convenience method to quickly write a 16-bit value to address and address + 1.
Note that the LOW byte will be stored in address and the high byte in address + 1.
*/
func (a *AddressBus) Write16(address uint16, data uint16) {
a.WriteByte(address, byte(data))
a.WriteByte(address+1, byte(data>>8))
}
// Returns the addressable for the specified address, or an error if no addressable exists.
func (a *AddressBus) addressableForAddress(address uint16) (*addressable, error) {
for _, addressable := range a.addressables {
if addressable.start <= address && addressable.end >= address {
return addressable, nil
}
}
return nil, fmt.Errorf("No addressable memory found at 0x%04X", address)
}