mirror of https://github.com/ariejan/i6502.git
Working Rx/Tx for serial/websockets
This commit is contained in:
parent
b692c8a7b1
commit
9e3c9454e8
77
cpu/cpu.go
77
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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
11
machine.go
11
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)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
Loading…
Reference in New Issue