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 rxInterruptEnabled bool txInterruptEnabled bool InterruptChan chan bool TxChan chan byte } func NewAcia6551(interruptChan chan bool) *Acia6551 { acia := &Acia6551{InterruptChan: interruptChan} acia.Reset() return acia } func (a *Acia6551) Reset() { 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 a.rxInterruptEnabled = false a.txInterruptEnabled = 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 if a.rxInterruptEnabled { a.InterruptChan <- true } } 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 if a.txInterruptEnabled { a.InterruptChan <- 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() } } func (a *Acia6551) setCommandRegister(data byte) { fmt.Printf("Setting Acia6551 Command Register: %02X\n", data) a.commandRegister = data 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) { 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() }