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:
parent
b692c8a7b1
commit
9e3c9454e8
63
cpu/cpu.go
63
cpu/cpu.go
@ -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.
|
||||||
|
@ -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) {
|
||||||
|
11
machine.go
11
machine.go
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
Loading…
Reference in New Issue
Block a user