Skip to content

Commit

Permalink
wip uart
Browse files Browse the repository at this point in the history
  • Loading branch information
hidetatz committed Dec 16, 2022
1 parent ce646a7 commit fda1007
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 8 deletions.
7 changes: 7 additions & 0 deletions clint.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
}
11 changes: 5 additions & 6 deletions cpu.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"io"
"math"
"math/big"
)
Expand Down Expand Up @@ -147,7 +146,7 @@ func NewCPU() *CPU {
clint: NewClint(),
disk: NewVirtIODisk(),
plic: NewPlic(),
uart: NewUart(os.Stdout),
uart: NewUart(),
ram: NewMemory(),
}
}
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down
7 changes: 7 additions & 0 deletions plic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
}
175 changes: 173 additions & 2 deletions uart.go
Original file line number Diff line number Diff line change
@@ -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
}
}
7 changes: 7 additions & 0 deletions virtio.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
}

0 comments on commit fda1007

Please sign in to comment.