mirror of
https://github.com/ariejan/i6502.git
synced 2024-10-31 23:09:44 +00:00
Merge pull request #3 from ariejan/issue_3_acia6551
Add support for 6551 Asynchronous Communications Interface Adapter (ACIA)
This commit is contained in:
commit
4764cb24ca
165
acia6551.go
Normal file
165
acia6551.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
package i6502
|
||||||
|
|
||||||
|
const (
|
||||||
|
aciaData = iota
|
||||||
|
aciaStatus
|
||||||
|
aciaCommand
|
||||||
|
aciaControl
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
ACIA 6551 Serial IO
|
||||||
|
|
||||||
|
This Asynchronous Communications Interface Adapater can be
|
||||||
|
directly attached to the 6502's address and data busses.
|
||||||
|
|
||||||
|
It provides serial IO.
|
||||||
|
|
||||||
|
The supplied Rx and Tx channels can be used to read and wirte
|
||||||
|
data to the ACIA 6551.
|
||||||
|
*/
|
||||||
|
type Acia6551 struct {
|
||||||
|
rx byte
|
||||||
|
tx byte
|
||||||
|
|
||||||
|
commandData byte
|
||||||
|
controlData byte
|
||||||
|
|
||||||
|
rxFull bool
|
||||||
|
txEmpty bool
|
||||||
|
|
||||||
|
rxIrqEnabled bool
|
||||||
|
txIrqEnabled bool
|
||||||
|
|
||||||
|
overrun bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAcia6551() (*Acia6551, error) {
|
||||||
|
acia := &Acia6551{}
|
||||||
|
acia.Reset()
|
||||||
|
|
||||||
|
return acia, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acia6551) Size() uint16 {
|
||||||
|
// We have a only 4 addresses, Data, Status, Command and Control
|
||||||
|
return 0x04
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emulates a hardware reset
|
||||||
|
func (a *Acia6551) Reset() {
|
||||||
|
a.rx = 0
|
||||||
|
a.rxFull = false
|
||||||
|
|
||||||
|
a.tx = 0
|
||||||
|
a.txEmpty = true
|
||||||
|
|
||||||
|
a.rxIrqEnabled = false
|
||||||
|
a.txIrqEnabled = false
|
||||||
|
|
||||||
|
a.overrun = false
|
||||||
|
|
||||||
|
a.setControl(0)
|
||||||
|
a.setCommand(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acia6551) setControl(data byte) {
|
||||||
|
a.controlData = data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acia6551) setCommand(data byte) {
|
||||||
|
a.commandData = data
|
||||||
|
|
||||||
|
a.rxIrqEnabled = (data & 0x02) != 0
|
||||||
|
a.txIrqEnabled = ((data & 0x04) != 0) && ((data & 0x08) != 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acia6551) statusRegister() byte {
|
||||||
|
status := byte(0)
|
||||||
|
|
||||||
|
if a.rxFull {
|
||||||
|
status |= 0x08
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.txEmpty {
|
||||||
|
status |= 0x10
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.overrun {
|
||||||
|
status |= 0x04
|
||||||
|
}
|
||||||
|
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements io.Reader, for external programs to read TX'ed data from
|
||||||
|
// the serial output.
|
||||||
|
func (a *Acia6551) Read(p []byte) (n int, err error) {
|
||||||
|
a.txEmpty = true
|
||||||
|
copy(p, []byte{a.tx})
|
||||||
|
// TODO: Handle txInterrupt
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements io.Writer, for external programs to write to the
|
||||||
|
// ACIA's RX
|
||||||
|
func (a *Acia6551) Write(p []byte) (n int, err error) {
|
||||||
|
for _, b := range p {
|
||||||
|
a.rxWrite(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the AddressBus to read data from the ACIA 6551
|
||||||
|
func (a *Acia6551) ReadByte(address uint16) byte {
|
||||||
|
switch address {
|
||||||
|
case aciaData:
|
||||||
|
return a.rxRead()
|
||||||
|
case aciaStatus:
|
||||||
|
return a.statusRegister()
|
||||||
|
case aciaCommand:
|
||||||
|
return a.commandData
|
||||||
|
case aciaControl:
|
||||||
|
return a.controlData
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x00
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the AddressBus to write data to the ACIA 6551
|
||||||
|
func (a *Acia6551) WriteByte(address uint16, data byte) {
|
||||||
|
switch address {
|
||||||
|
case aciaData:
|
||||||
|
a.txWrite(data)
|
||||||
|
case aciaStatus:
|
||||||
|
a.Reset()
|
||||||
|
case aciaCommand:
|
||||||
|
a.setCommand(data)
|
||||||
|
case aciaControl:
|
||||||
|
a.setControl(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acia6551) rxRead() byte {
|
||||||
|
a.overrun = false
|
||||||
|
a.rxFull = false
|
||||||
|
return a.rx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acia6551) rxWrite(data byte) {
|
||||||
|
// Oh no, overrun. Set the appropriate status
|
||||||
|
if a.rxFull {
|
||||||
|
a.overrun = true
|
||||||
|
}
|
||||||
|
|
||||||
|
a.rx = data
|
||||||
|
a.rxFull = true
|
||||||
|
|
||||||
|
// TODO: Interrupts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Acia6551) txWrite(data byte) {
|
||||||
|
a.tx = data
|
||||||
|
a.txEmpty = false
|
||||||
|
}
|
157
acia6551_test.go
Normal file
157
acia6551_test.go
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
package i6502
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AciaSubject() *Acia6551 {
|
||||||
|
acia, _ := NewAcia6551()
|
||||||
|
return acia
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewAcia6551(t *testing.T) {
|
||||||
|
acia, err := NewAcia6551()
|
||||||
|
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 0x4, acia.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAciaReset(t *testing.T) {
|
||||||
|
a := AciaSubject()
|
||||||
|
|
||||||
|
a.Reset()
|
||||||
|
|
||||||
|
assert.Equal(t, a.tx, 0)
|
||||||
|
assert.True(t, a.txEmpty)
|
||||||
|
|
||||||
|
assert.Equal(t, a.rx, 0)
|
||||||
|
assert.False(t, a.rxFull)
|
||||||
|
|
||||||
|
assert.False(t, a.txIrqEnabled)
|
||||||
|
assert.False(t, a.rxIrqEnabled)
|
||||||
|
|
||||||
|
assert.False(t, a.overrun)
|
||||||
|
assert.Equal(t, 0, a.controlData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAciaWriteByteAndReader(t *testing.T) {
|
||||||
|
a := AciaSubject()
|
||||||
|
|
||||||
|
// CPU writes data
|
||||||
|
a.WriteByte(aciaData, 0x42)
|
||||||
|
|
||||||
|
// System reads from Tx
|
||||||
|
value := make([]byte, 1)
|
||||||
|
bytesRead, _ := a.Read(value)
|
||||||
|
|
||||||
|
if assert.Equal(t, 1, bytesRead) {
|
||||||
|
assert.Equal(t, 0x42, value[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAciaWriterAndReadByte(t *testing.T) {
|
||||||
|
a := AciaSubject()
|
||||||
|
|
||||||
|
// System writes a single byte
|
||||||
|
bytesWritten, _ := a.Write([]byte{0x42})
|
||||||
|
|
||||||
|
if assert.Equal(t, 1, bytesWritten) {
|
||||||
|
assert.Equal(t, 0x42, a.ReadByte(aciaData))
|
||||||
|
}
|
||||||
|
|
||||||
|
// System writes multiple bytes
|
||||||
|
bytesWritten, _ = a.Write([]byte{0x42, 0x32, 0xAB})
|
||||||
|
|
||||||
|
if assert.Equal(t, 3, bytesWritten) {
|
||||||
|
assert.Equal(t, 0xAB, a.ReadByte(aciaData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAciaCommandRegister(t *testing.T) {
|
||||||
|
a := AciaSubject()
|
||||||
|
assert.False(t, a.rxIrqEnabled)
|
||||||
|
assert.False(t, a.txIrqEnabled)
|
||||||
|
|
||||||
|
a.WriteByte(aciaCommand, 0x02) // b0000 0010 RX Irq enabled
|
||||||
|
assert.True(t, a.rxIrqEnabled)
|
||||||
|
assert.False(t, a.txIrqEnabled)
|
||||||
|
|
||||||
|
a.WriteByte(aciaCommand, 0x04) // b0000 0100 TX Irq enabled
|
||||||
|
assert.False(t, a.rxIrqEnabled)
|
||||||
|
assert.True(t, a.txIrqEnabled)
|
||||||
|
|
||||||
|
a.WriteByte(aciaCommand, 0x06) // b0000 0110 RX + TX Irq enabled
|
||||||
|
assert.True(t, a.rxIrqEnabled)
|
||||||
|
assert.True(t, a.txIrqEnabled)
|
||||||
|
|
||||||
|
assert.Equal(t, 0x06, a.ReadByte(aciaCommand))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAciaControlRegister(t *testing.T) {
|
||||||
|
a := AciaSubject()
|
||||||
|
|
||||||
|
a.WriteByte(aciaControl, 0xB8)
|
||||||
|
assert.Equal(t, 0xB8, a.ReadByte(aciaControl))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAciaStatusRegister(t *testing.T) {
|
||||||
|
a := AciaSubject()
|
||||||
|
|
||||||
|
a.rxFull = false
|
||||||
|
a.txEmpty = false
|
||||||
|
a.overrun = false
|
||||||
|
assert.Equal(t, 0x00, a.ReadByte(aciaStatus))
|
||||||
|
|
||||||
|
a.rxFull = true
|
||||||
|
a.txEmpty = false
|
||||||
|
a.overrun = false
|
||||||
|
assert.Equal(t, 0x08, a.ReadByte(aciaStatus))
|
||||||
|
|
||||||
|
a.rxFull = false
|
||||||
|
a.txEmpty = true
|
||||||
|
a.overrun = false
|
||||||
|
assert.Equal(t, 0x10, a.ReadByte(aciaStatus))
|
||||||
|
|
||||||
|
a.rxFull = false
|
||||||
|
a.txEmpty = false
|
||||||
|
a.overrun = true
|
||||||
|
assert.Equal(t, 0x04, a.ReadByte(aciaStatus))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAciaIntegration(t *testing.T) {
|
||||||
|
// Create a system
|
||||||
|
// * 32kB RAM at 0x0000-7FFFF
|
||||||
|
// * ACIA at 0x8800-8803
|
||||||
|
ram, _ := NewRam(0x8000)
|
||||||
|
acia, _ := NewAcia6551()
|
||||||
|
bus, _ := NewAddressBus()
|
||||||
|
bus.Attach(ram, 0x0000)
|
||||||
|
bus.Attach(acia, 0x8800)
|
||||||
|
cpu, _ := NewCpu(bus)
|
||||||
|
|
||||||
|
program := []byte{
|
||||||
|
0xA9, 0x00, // LDA #$00
|
||||||
|
0x8D, 0x01, 0x88, // STA AciaStatus (Reset)
|
||||||
|
0xA9, 0x42, // LDA #$42
|
||||||
|
0x8D, 0x00, 0x88, // STA AciaData (Write)
|
||||||
|
0xAD, 0x00, 0x88, // LDA AciaData (Read)
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu.LoadProgram(program, 0x0200)
|
||||||
|
cpu.Steps(2)
|
||||||
|
|
||||||
|
acia.Write([]byte{0xAB})
|
||||||
|
|
||||||
|
cpu.Steps(3)
|
||||||
|
|
||||||
|
value := make([]byte, 1)
|
||||||
|
bytesRead, _ := acia.Read(value)
|
||||||
|
|
||||||
|
if assert.Equal(t, 1, bytesRead) {
|
||||||
|
assert.Equal(t, 0x42, value[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 0xAB, cpu.A)
|
||||||
|
}
|
@ -62,13 +62,13 @@ 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.
|
This will panic if you try to read from an address that has no Memory attached.
|
||||||
*/
|
*/
|
||||||
func (a *AddressBus) Read(address uint16) byte {
|
func (a *AddressBus) ReadByte(address uint16) byte {
|
||||||
addressable, err := a.addressableForAddress(address)
|
addressable, err := a.addressableForAddress(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return addressable.memory.Read(address - addressable.start)
|
return addressable.memory.ReadByte(address - addressable.start)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -77,8 +77,8 @@ 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.
|
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 {
|
func (a *AddressBus) Read16(address uint16) uint16 {
|
||||||
lo := uint16(a.Read(address))
|
lo := uint16(a.ReadByte(address))
|
||||||
hi := uint16(a.Read(address + 1))
|
hi := uint16(a.ReadByte(address + 1))
|
||||||
|
|
||||||
return (hi << 8) | lo
|
return (hi << 8) | lo
|
||||||
}
|
}
|
||||||
@ -89,13 +89,13 @@ 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
|
This will panic if you try to write to an address that has no Memory attached or
|
||||||
Memory that is read-only, like Rom.
|
Memory that is read-only, like Rom.
|
||||||
*/
|
*/
|
||||||
func (a *AddressBus) Write(address uint16, data byte) {
|
func (a *AddressBus) WriteByte(address uint16, data byte) {
|
||||||
addressable, err := a.addressableForAddress(address)
|
addressable, err := a.addressableForAddress(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
addressable.memory.Write(address-addressable.start, data)
|
addressable.memory.WriteByte(address-addressable.start, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -104,8 +104,8 @@ 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.
|
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) {
|
func (a *AddressBus) Write16(address uint16, data uint16) {
|
||||||
a.Write(address, byte(data))
|
a.WriteByte(address, byte(data))
|
||||||
a.Write(address+1, byte(data>>8))
|
a.WriteByte(address+1, byte(data>>8))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the addressable for the specified address, or an error if no addressable exists.
|
// Returns the addressable for the specified address, or an error if no addressable exists.
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package i6502
|
package i6502
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEmptyAddressBus(t *testing.T) {
|
func TestEmptyAddressBus(t *testing.T) {
|
||||||
@ -37,29 +38,29 @@ func TestBusReadWrite(t *testing.T) {
|
|||||||
bus.Attach(ram2, 0x8000)
|
bus.Attach(ram2, 0x8000)
|
||||||
|
|
||||||
// 8-bit Writing
|
// 8-bit Writing
|
||||||
bus.Write(0x1234, 0xFA)
|
bus.WriteByte(0x1234, 0xFA)
|
||||||
assert.Equal(0xFA, ram.Read(0x1234))
|
assert.Equal(0xFA, ram.ReadByte(0x1234))
|
||||||
|
|
||||||
// 16-bit Writing
|
// 16-bit Writing
|
||||||
bus.Write16(0x1000, 0xAB42)
|
bus.Write16(0x1000, 0xAB42)
|
||||||
assert.Equal(0x42, ram.Read(0x1000))
|
assert.Equal(0x42, ram.ReadByte(0x1000))
|
||||||
assert.Equal(0xAB, ram.Read(0x1001))
|
assert.Equal(0xAB, ram.ReadByte(0x1001))
|
||||||
|
|
||||||
// 8-bit Reading
|
// 8-bit Reading
|
||||||
ram.Write(0x5522, 0xDA)
|
ram.WriteByte(0x5522, 0xDA)
|
||||||
assert.Equal(0xDA, bus.Read(0x5522))
|
assert.Equal(0xDA, bus.ReadByte(0x5522))
|
||||||
|
|
||||||
// 16-bit Reading
|
// 16-bit Reading
|
||||||
ram.Write(0x4440, 0x7F)
|
ram.WriteByte(0x4440, 0x7F)
|
||||||
ram.Write(0x4441, 0x56)
|
ram.WriteByte(0x4441, 0x56)
|
||||||
assert.Equal(0x567F, bus.Read16(0x4440))
|
assert.Equal(0x567F, bus.Read16(0x4440))
|
||||||
|
|
||||||
//// Test addressing memory not mounted at 0x0000
|
//// Test addressing memory not mounted at 0x0000
|
||||||
|
|
||||||
// Read from relative addressable Ram2: $C123
|
// Read from relative addressable Ram2: $C123
|
||||||
ram2.Write(0x4123, 0xEF)
|
ram2.WriteByte(0x4123, 0xEF)
|
||||||
assert.Equal(0xEF, bus.Read(0xC123))
|
assert.Equal(0xEF, bus.ReadByte(0xC123))
|
||||||
|
|
||||||
bus.Write(0x8001, 0x12)
|
bus.WriteByte(0x8001, 0x12)
|
||||||
assert.Equal(0x12, ram2.Read(0x0001))
|
assert.Equal(0x12, ram2.ReadByte(0x0001))
|
||||||
}
|
}
|
||||||
|
50
cpu.go
50
cpu.go
@ -90,12 +90,18 @@ func (c *Cpu) handleIrq(PC uint16) {
|
|||||||
// and point the Program Counter to the beginning of the program.
|
// and point the Program Counter to the beginning of the program.
|
||||||
func (c *Cpu) LoadProgram(data []byte, location uint16) {
|
func (c *Cpu) LoadProgram(data []byte, location uint16) {
|
||||||
for i, b := range data {
|
for i, b := range data {
|
||||||
c.Bus.Write(location+uint16(i), b)
|
c.Bus.WriteByte(location+uint16(i), b)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.PC = location
|
c.PC = location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cpu) Steps(steps int) {
|
||||||
|
for i := 0; i < steps; i++ {
|
||||||
|
c.Step()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Read and execute the instruction pointed to by the Program Counter (PC)
|
// Read and execute the instruction pointed to by the Program Counter (PC)
|
||||||
func (c *Cpu) Step() {
|
func (c *Cpu) Step() {
|
||||||
instruction := c.readNextInstruction()
|
instruction := c.readNextInstruction()
|
||||||
@ -158,13 +164,13 @@ func (c *Cpu) execute(instruction Instruction) {
|
|||||||
c.setA(c.A ^ value)
|
c.setA(c.A ^ value)
|
||||||
case sta:
|
case sta:
|
||||||
address := c.memoryAddress(instruction)
|
address := c.memoryAddress(instruction)
|
||||||
c.Bus.Write(address, c.A)
|
c.Bus.WriteByte(address, c.A)
|
||||||
case stx:
|
case stx:
|
||||||
address := c.memoryAddress(instruction)
|
address := c.memoryAddress(instruction)
|
||||||
c.Bus.Write(address, c.X)
|
c.Bus.WriteByte(address, c.X)
|
||||||
case sty:
|
case sty:
|
||||||
address := c.memoryAddress(instruction)
|
address := c.memoryAddress(instruction)
|
||||||
c.Bus.Write(address, c.Y)
|
c.Bus.WriteByte(address, c.Y)
|
||||||
case tax:
|
case tax:
|
||||||
c.setX(c.A)
|
c.setX(c.A)
|
||||||
case tay:
|
case tay:
|
||||||
@ -264,7 +270,7 @@ func (c *Cpu) execute(instruction Instruction) {
|
|||||||
|
|
||||||
func (c *Cpu) readNextInstruction() Instruction {
|
func (c *Cpu) readNextInstruction() Instruction {
|
||||||
// Read the opcode
|
// Read the opcode
|
||||||
opcode := c.Bus.Read(c.PC)
|
opcode := c.Bus.ReadByte(c.PC)
|
||||||
|
|
||||||
optype, ok := opTypes[opcode]
|
optype, ok := opTypes[opcode]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -275,7 +281,7 @@ func (c *Cpu) readNextInstruction() Instruction {
|
|||||||
switch instruction.Size {
|
switch instruction.Size {
|
||||||
case 1: // Zero operand instruction
|
case 1: // Zero operand instruction
|
||||||
case 2: // 8-bit operand
|
case 2: // 8-bit operand
|
||||||
instruction.Op8 = c.Bus.Read(c.PC + 1)
|
instruction.Op8 = c.Bus.ReadByte(c.PC + 1)
|
||||||
case 3: // 16-bit operand
|
case 3: // 16-bit operand
|
||||||
instruction.Op16 = c.Bus.Read16(c.PC + 1)
|
instruction.Op16 = c.Bus.Read16(c.PC + 1)
|
||||||
}
|
}
|
||||||
@ -297,7 +303,7 @@ func (c *Cpu) resolveOperand(in Instruction) uint8 {
|
|||||||
case immediate:
|
case immediate:
|
||||||
return in.Op8
|
return in.Op8
|
||||||
default:
|
default:
|
||||||
return c.Bus.Read(c.memoryAddress(in))
|
return c.Bus.ReadByte(c.memoryAddress(in))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,17 +362,17 @@ func (c *Cpu) sbc(in Instruction) {
|
|||||||
|
|
||||||
func (c *Cpu) inc(in Instruction) {
|
func (c *Cpu) inc(in Instruction) {
|
||||||
address := c.memoryAddress(in)
|
address := c.memoryAddress(in)
|
||||||
value := c.Bus.Read(address) + 1
|
value := c.Bus.ReadByte(address) + 1
|
||||||
|
|
||||||
c.Bus.Write(address, value)
|
c.Bus.WriteByte(address, value)
|
||||||
c.setArithmeticFlags(value)
|
c.setArithmeticFlags(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cpu) dec(in Instruction) {
|
func (c *Cpu) dec(in Instruction) {
|
||||||
address := c.memoryAddress(in)
|
address := c.memoryAddress(in)
|
||||||
value := c.Bus.Read(address) - 1
|
value := c.Bus.ReadByte(address) - 1
|
||||||
|
|
||||||
c.Bus.Write(address, value)
|
c.Bus.WriteByte(address, value)
|
||||||
c.setArithmeticFlags(value)
|
c.setArithmeticFlags(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,10 +384,10 @@ func (c *Cpu) asl(in Instruction) {
|
|||||||
c.setArithmeticFlags(c.A)
|
c.setArithmeticFlags(c.A)
|
||||||
default:
|
default:
|
||||||
address := c.memoryAddress(in)
|
address := c.memoryAddress(in)
|
||||||
value := c.Bus.Read(address)
|
value := c.Bus.ReadByte(address)
|
||||||
c.setCarry((value >> 7) == 1)
|
c.setCarry((value >> 7) == 1)
|
||||||
value <<= 1
|
value <<= 1
|
||||||
c.Bus.Write(address, value)
|
c.Bus.WriteByte(address, value)
|
||||||
c.setArithmeticFlags(value)
|
c.setArithmeticFlags(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,10 +400,10 @@ func (c *Cpu) lsr(in Instruction) {
|
|||||||
c.setArithmeticFlags(c.A)
|
c.setArithmeticFlags(c.A)
|
||||||
default:
|
default:
|
||||||
address := c.memoryAddress(in)
|
address := c.memoryAddress(in)
|
||||||
value := c.Bus.Read(address)
|
value := c.Bus.ReadByte(address)
|
||||||
c.setCarry((value & 0x01) == 1)
|
c.setCarry((value & 0x01) == 1)
|
||||||
value >>= 1
|
value >>= 1
|
||||||
c.Bus.Write(address, value)
|
c.Bus.WriteByte(address, value)
|
||||||
c.setArithmeticFlags(value)
|
c.setArithmeticFlags(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -412,10 +418,10 @@ func (c *Cpu) rol(in Instruction) {
|
|||||||
c.setArithmeticFlags(c.A)
|
c.setArithmeticFlags(c.A)
|
||||||
default:
|
default:
|
||||||
address := c.memoryAddress(in)
|
address := c.memoryAddress(in)
|
||||||
value := c.Bus.Read(address)
|
value := c.Bus.ReadByte(address)
|
||||||
c.setCarry((value & 0x80) != 0)
|
c.setCarry((value & 0x80) != 0)
|
||||||
value = value<<1 | carry
|
value = value<<1 | carry
|
||||||
c.Bus.Write(address, value)
|
c.Bus.WriteByte(address, value)
|
||||||
c.setArithmeticFlags(value)
|
c.setArithmeticFlags(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -430,10 +436,10 @@ func (c *Cpu) ror(in Instruction) {
|
|||||||
c.setArithmeticFlags(c.A)
|
c.setArithmeticFlags(c.A)
|
||||||
default:
|
default:
|
||||||
address := c.memoryAddress(in)
|
address := c.memoryAddress(in)
|
||||||
value := c.Bus.Read(address)
|
value := c.Bus.ReadByte(address)
|
||||||
c.setCarry(value&0x01 == 1)
|
c.setCarry(value&0x01 == 1)
|
||||||
value = value>>1 | carry<<7
|
value = value>>1 | carry<<7
|
||||||
c.Bus.Write(address, value)
|
c.Bus.WriteByte(address, value)
|
||||||
c.setArithmeticFlags(value)
|
c.setArithmeticFlags(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -513,15 +519,15 @@ func (c *Cpu) sbcDecimal(a uint8, b uint8, carryIn uint8) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cpu) stackPush(data byte) {
|
func (c *Cpu) stackPush(data byte) {
|
||||||
c.Bus.Write(StackBase+uint16(c.SP), data)
|
c.Bus.WriteByte(StackBase+uint16(c.SP), data)
|
||||||
c.SP -= 1
|
c.SP -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cpu) stackPeek() byte {
|
func (c *Cpu) stackPeek() byte {
|
||||||
return c.Bus.Read(StackBase + uint16(c.SP+1))
|
return c.Bus.ReadByte(StackBase + uint16(c.SP+1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cpu) stackPop() byte {
|
func (c *Cpu) stackPop() byte {
|
||||||
c.SP += 1
|
c.SP += 1
|
||||||
return c.Bus.Read(StackBase + uint16(c.SP))
|
return c.Bus.ReadByte(StackBase + uint16(c.SP))
|
||||||
}
|
}
|
||||||
|
341
cpu_test.go
341
cpu_test.go
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,6 @@ and become accessible by the Cpu.
|
|||||||
*/
|
*/
|
||||||
type Memory interface {
|
type Memory interface {
|
||||||
Size() uint16
|
Size() uint16
|
||||||
Read(address uint16) byte
|
ReadByte(address uint16) byte
|
||||||
Write(address uint16, data byte)
|
WriteByte(address uint16, data byte)
|
||||||
}
|
}
|
||||||
|
4
ram.go
4
ram.go
@ -16,10 +16,10 @@ func (r *Ram) Size() uint16 {
|
|||||||
return uint16(len(r.data))
|
return uint16(len(r.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Ram) Read(address uint16) byte {
|
func (r *Ram) ReadByte(address uint16) byte {
|
||||||
return r.data[address]
|
return r.data[address]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Ram) Write(address uint16, data byte) {
|
func (r *Ram) WriteByte(address uint16, data byte) {
|
||||||
r.data[address] = data
|
r.data[address] = data
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package i6502
|
package i6502
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRamSize(t *testing.T) {
|
func TestRamSize(t *testing.T) {
|
||||||
@ -18,6 +19,6 @@ func TestRamReadWrite(t *testing.T) {
|
|||||||
assert.Equal(t, 0x00, ram.data[i])
|
assert.Equal(t, 0x00, ram.data[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
ram.Write(0x1000, 0x42)
|
ram.WriteByte(0x1000, 0x42)
|
||||||
assert.Equal(t, 0x42, ram.Read(0x1000))
|
assert.Equal(t, 0x42, ram.ReadByte(0x1000))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user