1
0
mirror of https://github.com/ariejan/i6502.git synced 2024-05-28 22:41:34 +00:00
i6502/address_bus.go
Ariejan de Vroom da43c2bca1 Update Memory interface
Because io.Reader and io.Writer already claim the functions Read and
Write it was necessary to rename the Memory interface methods Read and
Write to ReadByte and WriteByte.
2014-08-19 16:49:48 +02: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)
}