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
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.

View File

@ -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) {

View File

@ -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)
}
}
}()