From 12f64bf7d38e7443c1322ac19bd8b9657c43880d Mon Sep 17 00:00:00 2001 From: Ariejan de Vroom Date: Mon, 11 Aug 2014 10:15:56 +0200 Subject: [PATCH] WIP --- devices/acia6551.go | 191 ++++++++++++++++++++++++++++++++++++++++++++ i6502.go | 8 +- rom/ehbasic.rom | Bin 0 -> 16384 bytes server.go | 60 ++++++++++++++ 4 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 devices/acia6551.go create mode 100644 rom/ehbasic.rom create mode 100644 server.go diff --git a/devices/acia6551.go b/devices/acia6551.go new file mode 100644 index 0000000..e51a243 --- /dev/null +++ b/devices/acia6551.go @@ -0,0 +1,191 @@ +package devices + +import ( + "fmt" + "time" +) + +const ( + aciaData = iota + aciaStatus + aciaCommand + aciaControl +) + +var baudRateSelectors = [...]int{0, 50, 75, 110, 135, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 19200} + +type Acia6551 struct { + // Registers + rx byte + tx byte + commandRegister byte + controlRegister byte + + // Other required bits and pieces + lastTxWrite int64 + lastRxRead int64 + overrun bool + baudRate int + baudRateDelay int64 + rxFull bool + txEmpty bool + + RxChan chan byte + TxChan chan byte +} + +func NewAcia6551() *Acia6551 { + fmt.Println("Resetting the Acia6551") + acia := &Acia6551{} + acia.Reset() + return acia +} + +func (a *Acia6551) Reset() { + a.RxChan = make(chan byte, 4096) + a.TxChan = make(chan byte, 4096) + + a.tx = 0 + a.txEmpty = true + + a.rx = 0 + a.rxFull = false + + a.lastTxWrite = 0 + a.lastRxRead = 0 + a.overrun = false +} + +func (a *Acia6551) Size() int { + return 4 +} + +func (a *Acia6551) Read(address uint16) byte { + switch address { + case aciaData: + return a.rxRead() + case aciaStatus: + return a.statusRegister() + case aciaCommand: + return a.commandRegister + case aciaControl: + return a.controlRegister + default: + panic(fmt.Errorf("ACIA 6551 cannot handle addressing 0x%04X", address)) + } +} + +func (a *Acia6551) rxRead() byte { + a.lastRxRead = unixTime() + a.overrun = false + a.rxFull = false + return a.rx +} + +func (a *Acia6551) RxWrite(data byte) { + // Oh noes! + if a.rxFull { + a.overrun = true + } + + a.rx = data + a.rxFull = true + + // TODO: IRQs +} + +func (a *Acia6551) statusRegister() byte { + now := unixTime() + status := byte(0) + + if a.rxFull && (now >= (a.lastRxRead + a.baudRateDelay)) { + status |= 0x08 + } + + if a.txEmpty && (now >= (a.lastTxWrite + a.baudRateDelay)) { + status |= 0x10 + } + + if a.overrun { + status |= 0x04 + } + + return status +} + +func (a *Acia6551) Write(address uint16, value byte) { + switch address { + case aciaData: + a.txWrite(value) + case aciaStatus: + a.Reset() + case aciaCommand: + a.setCommandRegister(value) + case aciaControl: + a.setControlRegister(value) + default: + panic(fmt.Errorf("ACIA 6551 cannot handle addressing 0x%04X", address)) + } +} + +func (a *Acia6551) txWrite(value byte) { + a.lastTxWrite = unixTime() + a.tx = value + a.txEmpty = false + + // Post for others + a.debugTxOutput() +} + +func (a *Acia6551) TxRead() byte { + a.txEmpty = true + return a.tx +} + +func (a *Acia6551) HasTx() bool { + return !a.txEmpty +} + +func (a *Acia6551) HasRx() bool { + return a.rxFull +} + +func (a *Acia6551) debugTxOutput() { + if a.HasTx() { + a.TxChan <- a.TxRead() + fmt.Printf("%c", a.TxRead()) + } +} + +func (a *Acia6551) setCommandRegister(data byte) { + fmt.Printf("Setting Acia6551 Command Register: %02X\n", data) + a.commandRegister = data + // TODO: Maybe implement IRQs. +} + +func (a *Acia6551) setControlRegister(data byte) { + a.controlRegister = data + + if data == 0x00 { + a.Reset() + } else { + a.setBaudRate(baudRateSelectors[data&0x0f]) + } +} + +func (a *Acia6551) setBaudRate(baudRate int) { + fmt.Printf("Setting baudrate at %d\n", baudRate) + + a.baudRate = baudRate + + // Set baudRateDelay in nanoseconds. It's an approximation. + if baudRate > 0 { + a.baudRateDelay = int64((1.0 / float64(baudRate)) * 1000000000 * 8) + } else { + a.baudRateDelay = 0 + } +} + +func unixTime() int64 { + return time.Now().UnixNano() +} diff --git a/i6502.go b/i6502.go index 623b4c8..e6a90d3 100644 --- a/i6502.go +++ b/i6502.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/ariejan/i6502/bus" "github.com/ariejan/i6502/cpu" + "github.com/ariejan/i6502/devices" "github.com/ariejan/i6502/memory" "os" "os/signal" @@ -22,15 +23,18 @@ func mainReturningStatus() int { ram := memory.CreateRam() // 16kB ROM, filled from file - rom, err := memory.LoadRomFromFile("rom/test.rom") + rom, err := memory.LoadRomFromFile("rom/ehbasic.rom") if err != nil { panic(err) } + acia6551 := devices.NewAcia6551() + // 16-bit address bus bus, _ := bus.CreateBus() bus.Attach(ram, "32kB RAM", 0x0000) bus.Attach(rom, "16kB ROM", 0xC000) + bus.Attach(acia6551, "ACIA 6551", 0x8800) fmt.Println(bus) @@ -39,6 +43,8 @@ func mainReturningStatus() int { cpu := &cpu.Cpu{Bus: bus, ExitChan: exitChan} cpu.Reset() + go serialServer(cpu, acia6551) + go func() { for { cpu.Step() diff --git a/rom/ehbasic.rom b/rom/ehbasic.rom new file mode 100644 index 0000000000000000000000000000000000000000..24f4bef76d808f598405dc240fb658fabd3efb33 GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/server.go b/server.go new file mode 100644 index 0000000..e14d5af --- /dev/null +++ b/server.go @@ -0,0 +1,60 @@ +package main + +import ( + "bufio" + "fmt" + "github.com/ariejan/i6502/cpu" + "github.com/ariejan/i6502/devices" + "net" +) + +func handleConnection(c net.Conn, cpu *cpu.Cpu, acia *devices.Acia6551) { + + // Force telnet into character mode + c.Write([]byte("\377\375\042\377\373\001")) + c.Write([]byte("-- i6502 Serial Terminal --\n")) + + // Transfer output to the client + go func() { + for { + select { + case data := <-acia.TxChan: + c.Write([]byte{data}) + } + } + }() + + go func() { + reader := bufio.NewReader(c) + + for { + b, err := reader.ReadByte() + if err != nil { + panic(err) + } + + // Push to CPU + acia.RxChan <- b + } + }() + + fmt.Println("Client connected. Resetting CPU.") + cpu.Reset() +} + +func serialServer(cpu *cpu.Cpu, acia *devices.Acia6551) { + listen, err := net.Listen("tcp", ":6000") + if err != nil { + panic(err) + } + + for { + conn, err := listen.Accept() + defer conn.Close() + + if err != nil { + continue + } + go handleConnection(conn, cpu, acia) + } +}