From fda1007dda81f885ac3700c09d8f0da07216d664 Mon Sep 17 00:00:00 2001 From: Hidetatz Yaginuma Date: Fri, 16 Dec 2022 16:47:35 +0900 Subject: [PATCH] wip uart --- clint.go | 7 +++ cpu.go | 11 ++-- plic.go | 7 +++ uart.go | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++- virtio.go | 7 +++ 5 files changed, 199 insertions(+), 8 deletions(-) diff --git a/clint.go b/clint.go index b66313e..1373ce7 100644 --- a/clint.go +++ b/clint.go @@ -5,3 +5,10 @@ type Clint struct{} func NewClint() *Clint { return nil } + +func (c *Clint) read(addr uint64) uint8 { + return 0 +} + +func (c *Clint) write(addr uint64, value uint8) { +} diff --git a/cpu.go b/cpu.go index c8e5861..1598943 100644 --- a/cpu.go +++ b/cpu.go @@ -1,7 +1,6 @@ package main import ( - "io" "math" "math/big" ) @@ -147,7 +146,7 @@ func NewCPU() *CPU { clint: NewClint(), disk: NewVirtIODisk(), plic: NewPlic(), - uart: NewUart(os.Stdout), + uart: NewUart(), ram: NewMemory(), } } @@ -371,10 +370,10 @@ func (cpu *CPU) readRaw(vaddr uint64, size int) uint64 { data := uint64(0) for i := 0; i < size/8; i++ { a := eaddr + uint64(i) - d := 0 + var d uint8 = 0 switch { case 0x00001010 <= a && a < 0x00001fff: - d = uint64(cpu.dtb[a-0x1020]) + d = cpu.dtb[a-0x1020] case 0x02000000 <= a && a < 0x0200ffff: d = cpu.clint.read(a) case 0x0c000000 <= a && a < 0x0fffffff: @@ -386,7 +385,7 @@ func (cpu *CPU) readRaw(vaddr uint64, size int) uint64 { default: panic("unknown mem seg") } - data |= d << (i * 8) + data |= uint64(d << (uint8(i) * 8)) } return data @@ -437,7 +436,7 @@ func (cpu *CPU) writeRaw(addr, val uint64, size int) { } for i := 0; i < size/8; i++ { - v := (val >> (i * 8)) & 0xff + v := uint8((val >> (i * 8)) & 0xff) a := ea + uint64(i) switch { case 0x02000000 <= a && a < 0x0200ffff: diff --git a/plic.go b/plic.go index 64f0f7d..38a7292 100644 --- a/plic.go +++ b/plic.go @@ -5,3 +5,10 @@ type Plic struct{} func NewPlic() *Plic { return nil } + +func (p *Plic) read(addr uint64) uint8 { + return 0 +} + +func (p *Plic) write(addr uint64, value uint8) { +} diff --git a/uart.go b/uart.go index 732dbd6..51bb5cd 100644 --- a/uart.go +++ b/uart.go @@ -1,7 +1,178 @@ package main -type Uart struct{} +import ( + "bufio" + "fmt" + "os" + "sync" +) + +const ( + ierRxintBit = 0x1 + ierThreintBit = 0x2 + + iirThrEmpty = 0x2 + iirRdAvailable = 0x4 + iirNoInterrupt = 0x7 + + lsrDataAvailable = 0x1 + lsrThrEmpty = 0x20 +) + +type Uart struct { + clock uint64 + rbr uint8 // receiver buffer register + thr uint8 // transmitter holding register + ier uint8 // interrupt enable register + iir uint8 // interrupt identification register + lcr uint8 // line control register + mcr uint8 // modem control register + lsr uint8 // line status register + scr uint8 // scratch, + threip bool + interrupting bool + + sync.Mutex + buffer []byte +} func NewUart() *Uart { - return nil + u := &Uart{ + clock: 0, + rbr: 0, + thr: 0, + ier: 0, + iir: 0, + lcr: 0, + mcr: 0, + lsr: lsrThrEmpty, + scr: 0, + threip: false, + interrupting: false, + + buffer: []byte{}, // stdin buffer + } + // read input + go func() { + r := bufio.NewReader(os.Stdin) + for { + b, err := r.ReadByte() + if err != nil { + fmt.Fprintf(os.Stderr, "read stdin: %s", err) + continue + } + + u.Lock() + u.buffer = append(u.buffer, b) + u.Unlock() + } + }() + + return u +} + +func (u *Uart) Tick() { + u.clock++ + rxip := false + + // read input and store into register + if u.clock%0x38400 == 0 && u.rbr == 0 { + // get single byte + u.Lock() + b := u.buffer[0] + u.buffer = u.buffer[1:] + u.Unlock() + + if b != 0 { + u.rbr = b + u.lsr |= lsrDataAvailable + u.updateIir() + if u.ier&ierRxintBit != 0 { + rxip = true + } + } + } + + // write reg value to stdout + if u.clock%0x10 == 0 && u.thr != 0 { + fmt.Fprint(os.Stdout, string(u.thr)) + u.thr = 0 + u.lsr |= lsrThrEmpty + u.updateIir() + if u.ier&ierThreintBit != 0 { + u.threip = true + } + } + + if u.threip || rxip { + u.interrupting = true + u.threip = false + } else { + u.interrupting = false + } +} + +func (u *Uart) updateIir() { + rxip := u.ier&ierRxintBit != 0 && u.rbr != 0 + threip := u.ier&ierThreintBit != 0 && u.thr == 0 + + if rxip { + u.iir = iirRdAvailable + } else if threip { + u.iir = iirThrEmpty + } else { + u.iir = iirNoInterrupt + } +} + +func (u *Uart) read(address uint64) uint8 { + switch address { + case 0x10000000: + if (u.lcr >> 7) == 0 { + rbr := u.rbr + u.rbr = 0 + u.lsr &= uint8(^lsrDataAvailable) + u.updateIir() + return rbr + } + case 0x10000001: + if (u.lcr >> 7) == 0 { + return u.ier + } + case 0x10000002: + return u.iir + case 0x10000003: + return u.lcr + case 0x10000004: + return u.mcr + case 0x10000005: + return u.lsr + case 0x10000007: + return u.scr + } + return 0 +} + +func (u *Uart) write(address uint64, value uint8) { + switch address { + case 0x10000000: + if (u.lcr >> 7) == 0 { + u.thr = value + u.lsr &= ^lsrThrEmpty + u.updateIir() + } + case 0x10000001: + if u.ier&ierThreintBit == 0 && value&ierThreintBit != 0 && u.thr == 0 { + u.threip = true + } + + u.ier = value + u.updateIir() + case 0x10000003: + u.lcr = value + case 0x10000004: + u.mcr = value + case 0x10000007: + u.scr = value + } } diff --git a/virtio.go b/virtio.go index 7b016e0..ef869e9 100644 --- a/virtio.go +++ b/virtio.go @@ -5,3 +5,10 @@ type VirtIODisk struct{} func NewVirtIODisk() *VirtIODisk { return nil } + +func (v *VirtIODisk) read(addr uint64) uint8 { + return 0 +} + +func (v *VirtIODisk) write(addr uint64, value uint8) { +}