1
0
mirror of https://github.com/ariejan/i6502.git synced 2024-09-28 14:55:07 +00:00

Working Rx/Tx for serial/websockets

This commit is contained in:
Ariejan de Vroom 2014-08-11 14:40:21 +02:00
parent b692c8a7b1
commit 9e3c9454e8
3 changed files with 84 additions and 27 deletions

View File

@ -42,6 +42,8 @@ type Cpu struct {
// Memory bus // Memory bus
Bus *bus.Bus Bus *bus.Bus
InterruptChan chan bool
// Handle exiting // Handle exiting
ExitChan chan int ExitChan chan int
} }
@ -63,7 +65,39 @@ func (c *Cpu) String() string {
) )
} }
func (c *Cpu) handleInterrupt(returnPC uint16) {
c.setStatus(sBreak, true)
// Push PC + 1 onto stack
c.stackPush(byte(returnPC >> 8))
c.stackPush(byte(returnPC))
// Push status register to the stack
c.stackPush(c.SR)
// Disable interrupts
c.setStatus(sInterrupt, true)
c.PC = c.Bus.Read16(0xFFFE)
}
func (c *Cpu) stackPush(data byte) {
c.Bus.Write(StackBase+uint16(c.SP), data)
c.SP--
}
func (c *Cpu) stackPop() byte {
c.SP++
return c.Bus.Read(StackBase + uint16(c.SP))
}
func (c *Cpu) Step() { func (c *Cpu) Step() {
select {
case <-c.InterruptChan:
if !c.getStatus(sInterrupt) {
// Handle interrupt
c.handleInterrupt(c.PC)
}
default:
// Read the instruction (including operands) // Read the instruction (including operands)
instruction := ReadInstruction(c.PC, c.Bus) instruction := ReadInstruction(c.PC, c.Bus)
@ -74,6 +108,7 @@ func (c *Cpu) Step() {
// Execute the instruction // Execute the instruction
c.execute(instruction) c.execute(instruction)
} }
}
func (c *Cpu) stackHead(offset int8) uint16 { func (c *Cpu) stackHead(offset int8) uint16 {
return uint16(StackBase) + uint16(c.SP) + uint16(offset) return uint16(StackBase) + uint16(c.SP) + uint16(offset)
@ -240,8 +275,12 @@ func (c *Cpu) execute(in Instruction) {
c.ORA(in) c.ORA(in)
case pha: case pha:
c.PHA(in) c.PHA(in)
case php:
c.PHP(in)
case pla: case pla:
c.PLA(in) c.PLA(in)
case plp:
c.PLP(in)
case rol: case rol:
c.ROL(in) c.ROL(in)
case ror: case ror:
@ -275,7 +314,7 @@ func (c *Cpu) execute(in Instruction) {
case _end: case _end:
c._END(in) c._END(in)
default: default:
panic(fmt.Sprintf("Unhandled instruction: %v", in)) panic(fmt.Sprintf("Unhandled instruction: %X", in.OpType))
} }
} }
@ -354,8 +393,10 @@ func (c *Cpu) BPL(in Instruction) {
// BRK: software interrupt // BRK: software interrupt
func (c *Cpu) BRK(in Instruction) { func (c *Cpu) BRK(in Instruction) {
// temporarily used to dump status // Force interrupt
fmt.Println("BRK:", c) if !c.getStatus(sInterrupt) {
c.handleInterrupt(c.PC + 1)
}
} }
// CLC: Clear carry flag. // CLC: Clear carry flag.
@ -500,14 +541,22 @@ func (c *Cpu) ORA(in Instruction) {
// PHA: Push accumulator onto stack. // PHA: Push accumulator onto stack.
func (c *Cpu) PHA(in Instruction) { func (c *Cpu) PHA(in Instruction) {
c.Bus.Write(0x0100+uint16(c.SP), c.A) c.stackPush(c.A)
c.SP-- }
// PHP: Push SR to stack
func (c *Cpu) PHP(in Instruction) {
c.stackPush(c.SR)
} }
// PLA: Pull accumulator from stack. // PLA: Pull accumulator from stack.
func (c *Cpu) PLA(in Instruction) { func (c *Cpu) PLA(in Instruction) {
c.SP++ c.A = c.stackPop()
c.A = c.Bus.Read(0x0100 + uint16(c.SP)) }
// PLP: Pull SR from stack
func (c *Cpu) PLP(in Instruction) {
c.SR = c.stackPop()
} }
// ROL: Rotate memory or accumulator left one bit. // ROL: Rotate memory or accumulator left one bit.

View File

@ -35,18 +35,17 @@ type Acia6551 struct {
InterruptChan chan bool InterruptChan chan bool
RxChan chan byte
TxChan chan byte TxChan chan byte
} }
func NewAcia6551(cpu *Cpu) *Acia6551 { func NewAcia6551(interruptChan chan bool) *Acia6551 {
acia := &Acia6551{} acia := &Acia6551{InterruptChan: interruptChan}
acia.Reset() acia.Reset()
return acia return acia
} }
func (a *Acia6551) Reset() { func (a *Acia6551) Reset() {
a.RxChan = make(chan byte, 4096)
a.TxChan = make(chan byte, 4096) a.TxChan = make(chan byte, 4096)
a.tx = 0 a.tx = 0
@ -61,8 +60,6 @@ func (a *Acia6551) Reset() {
a.rxInterruptEnabled = false a.rxInterruptEnabled = false
a.txInterruptEnabled = false a.txInterruptEnabled = false
a.InterruptChan = make(chan bool, 0)
} }
func (a *Acia6551) Size() int { func (a *Acia6551) Size() int {
@ -101,7 +98,7 @@ func (a *Acia6551) RxWrite(data byte) {
a.rxFull = true a.rxFull = true
if a.rxInterruptEnabled { if a.rxInterruptEnabled {
// getbus.assertIrq() a.InterruptChan <- true
} }
} }
@ -150,6 +147,11 @@ func (a *Acia6551) txWrite(value byte) {
func (a *Acia6551) TxRead() byte { func (a *Acia6551) TxRead() byte {
a.txEmpty = true a.txEmpty = true
if a.txInterruptEnabled {
a.InterruptChan <- true
}
return a.tx return a.tx
} }
@ -169,8 +171,13 @@ func (a *Acia6551) debugTxOutput() {
func (a *Acia6551) setCommandRegister(data byte) { func (a *Acia6551) setCommandRegister(data byte) {
fmt.Printf("Setting Acia6551 Command Register: %02X\n", data) fmt.Printf("Setting Acia6551 Command Register: %02X\n", data)
a.commandRegister = data a.commandRegister = data
// TODO: Maybe implement IRQs.
a.rxInterruptEnabled = ((data >> 1) & 1) == 0
a.txInterruptEnabled = ((data>>2)&1) == 1 && ((data>>3)&1) == 0
fmt.Printf("RxIRQ: %t; TxIRQ: %t\n", a.rxInterruptEnabled, a.txInterruptEnabled)
} }
func (a *Acia6551) setControlRegister(data byte) { func (a *Acia6551) setControlRegister(data byte) {

View File

@ -5,7 +5,6 @@ import (
"github.com/ariejan/i6502/cpu" "github.com/ariejan/i6502/cpu"
"github.com/ariejan/i6502/devices" "github.com/ariejan/i6502/devices"
"github.com/ariejan/i6502/memory" "github.com/ariejan/i6502/memory"
"log"
) )
type Machine struct { type Machine struct {
@ -22,6 +21,9 @@ type Machine struct {
// Creates a new i6502 Machine instance // Creates a new i6502 Machine instance
func CreateMachine() *Machine { func CreateMachine() *Machine {
// Channel for handling interrupts
interruptChan := make(chan bool, 0)
ram := memory.CreateRam() ram := memory.CreateRam()
rom, err := memory.LoadRomFromFile("rom/ehbasic.rom") rom, err := memory.LoadRomFromFile("rom/ehbasic.rom")
@ -29,14 +31,14 @@ func CreateMachine() *Machine {
panic(err) panic(err)
} }
acia6551 := devices.NewAcia6551() acia6551 := devices.NewAcia6551(interruptChan)
bus, _ := bus.CreateBus() bus, _ := bus.CreateBus()
bus.Attach(ram, "32kB RAM", 0x0000) bus.Attach(ram, "32kB RAM", 0x0000)
bus.Attach(rom, "16kB ROM", 0xC000) bus.Attach(rom, "16kB ROM", 0xC000)
bus.Attach(acia6551, "ACIA 6551 Serial", 0x8800) bus.Attach(acia6551, "ACIA 6551 Serial", 0x8800)
cpu := &cpu.Cpu{Bus: bus, ExitChan: make(chan int, 0)} cpu := &cpu.Cpu{Bus: bus, InterruptChan: interruptChan, ExitChan: make(chan int, 0)}
machine := &Machine{SerialTx: make(chan byte, 256), SerialRx: make(chan byte, 256), cpu: cpu, bus: bus} machine := &Machine{SerialTx: make(chan byte, 256), SerialRx: make(chan byte, 256), cpu: cpu, bus: bus}
@ -62,8 +64,7 @@ func CreateMachine() *Machine {
for { for {
select { select {
case data := <-machine.SerialRx: case data := <-machine.SerialRx:
log.Printf("Rx: %c", data) acia6551.RxWrite(data)
acia6551.RxChan <- data
} }
} }
}() }()