From 9e3c9454e81aea8e9afebb80cd729efe1dd0ffbd Mon Sep 17 00:00:00 2001 From: Ariejan de Vroom Date: Mon, 11 Aug 2014 14:40:21 +0200 Subject: [PATCH] Working Rx/Tx for serial/websockets --- cpu/cpu.go | 77 ++++++++++++++++++++++++++++++++++++--------- devices/acia6551.go | 23 +++++++++----- machine.go | 11 ++++--- 3 files changed, 84 insertions(+), 27 deletions(-) diff --git a/cpu/cpu.go b/cpu/cpu.go index bb5f58a..682592d 100644 --- a/cpu/cpu.go +++ b/cpu/cpu.go @@ -42,6 +42,8 @@ type Cpu struct { // Memory bus Bus *bus.Bus + InterruptChan chan bool + // Handle exiting ExitChan chan int } @@ -63,16 +65,49 @@ 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() { - // Read the instruction (including operands) - instruction := ReadInstruction(c.PC, c.Bus) + select { + case <-c.InterruptChan: + if !c.getStatus(sInterrupt) { + // Handle interrupt + c.handleInterrupt(c.PC) + } + default: + // Read the instruction (including operands) + instruction := ReadInstruction(c.PC, c.Bus) - // Move the Program Counter forward, depending - // on the size of the optype we just read. - c.PC += uint16(instruction.Bytes) + // Move the Program Counter forward, depending + // on the size of the optype we just read. + c.PC += uint16(instruction.Bytes) - // Execute the instruction - c.execute(instruction) + // Execute the instruction + c.execute(instruction) + } } func (c *Cpu) stackHead(offset int8) uint16 { @@ -240,8 +275,12 @@ func (c *Cpu) execute(in Instruction) { c.ORA(in) case pha: c.PHA(in) + case php: + c.PHP(in) case pla: c.PLA(in) + case plp: + c.PLP(in) case rol: c.ROL(in) case ror: @@ -275,7 +314,7 @@ func (c *Cpu) execute(in Instruction) { case _end: c._END(in) 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 func (c *Cpu) BRK(in Instruction) { - // temporarily used to dump status - fmt.Println("BRK:", c) + // Force interrupt + if !c.getStatus(sInterrupt) { + c.handleInterrupt(c.PC + 1) + } } // CLC: Clear carry flag. @@ -500,14 +541,22 @@ func (c *Cpu) ORA(in Instruction) { // PHA: Push accumulator onto stack. func (c *Cpu) PHA(in Instruction) { - c.Bus.Write(0x0100+uint16(c.SP), c.A) - c.SP-- + c.stackPush(c.A) +} + +// PHP: Push SR to stack +func (c *Cpu) PHP(in Instruction) { + c.stackPush(c.SR) } // PLA: Pull accumulator from stack. func (c *Cpu) PLA(in Instruction) { - c.SP++ - c.A = c.Bus.Read(0x0100 + uint16(c.SP)) + c.A = c.stackPop() +} + +// PLP: Pull SR from stack +func (c *Cpu) PLP(in Instruction) { + c.SR = c.stackPop() } // ROL: Rotate memory or accumulator left one bit. diff --git a/devices/acia6551.go b/devices/acia6551.go index a52fcc0..42e675d 100644 --- a/devices/acia6551.go +++ b/devices/acia6551.go @@ -35,18 +35,17 @@ type Acia6551 struct { InterruptChan chan bool - RxChan chan byte TxChan chan byte } -func NewAcia6551(cpu *Cpu) *Acia6551 { - acia := &Acia6551{} +func NewAcia6551(interruptChan chan bool) *Acia6551 { + acia := &Acia6551{InterruptChan: interruptChan} acia.Reset() + return acia } func (a *Acia6551) Reset() { - a.RxChan = make(chan byte, 4096) a.TxChan = make(chan byte, 4096) a.tx = 0 @@ -61,8 +60,6 @@ func (a *Acia6551) Reset() { a.rxInterruptEnabled = false a.txInterruptEnabled = false - - a.InterruptChan = make(chan bool, 0) } func (a *Acia6551) Size() int { @@ -101,7 +98,7 @@ func (a *Acia6551) RxWrite(data byte) { a.rxFull = true if a.rxInterruptEnabled { - // getbus.assertIrq() + a.InterruptChan <- true } } @@ -150,6 +147,11 @@ func (a *Acia6551) txWrite(value byte) { func (a *Acia6551) TxRead() byte { a.txEmpty = true + + if a.txInterruptEnabled { + a.InterruptChan <- true + } + return a.tx } @@ -169,8 +171,13 @@ func (a *Acia6551) debugTxOutput() { func (a *Acia6551) setCommandRegister(data byte) { fmt.Printf("Setting Acia6551 Command Register: %02X\n", 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) { diff --git a/machine.go b/machine.go index 5a551f8..0b6a4bb 100644 --- a/machine.go +++ b/machine.go @@ -5,7 +5,6 @@ import ( "github.com/ariejan/i6502/cpu" "github.com/ariejan/i6502/devices" "github.com/ariejan/i6502/memory" - "log" ) type Machine struct { @@ -22,6 +21,9 @@ type Machine struct { // Creates a new i6502 Machine instance func CreateMachine() *Machine { + // Channel for handling interrupts + interruptChan := make(chan bool, 0) + ram := memory.CreateRam() rom, err := memory.LoadRomFromFile("rom/ehbasic.rom") @@ -29,14 +31,14 @@ func CreateMachine() *Machine { panic(err) } - acia6551 := devices.NewAcia6551() + acia6551 := devices.NewAcia6551(interruptChan) bus, _ := bus.CreateBus() bus.Attach(ram, "32kB RAM", 0x0000) bus.Attach(rom, "16kB ROM", 0xC000) 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} @@ -62,8 +64,7 @@ func CreateMachine() *Machine { for { select { case data := <-machine.SerialRx: - log.Printf("Rx: %c", data) - acia6551.RxChan <- data + acia6551.RxWrite(data) } } }()