eei: implement paging-based eei

This commit is contained in:
mappu 2022-12-28 14:11:07 +13:00
parent 29a94dd442
commit 453e8b39e4
3 changed files with 44 additions and 26 deletions

View File

@ -9,8 +9,7 @@ import (
) )
func main() { func main() {
memorySize := flag.Int("MemorySize", 4096, "Memory size (bytes)") loadAddress := flag.Int64("LoadAddress", 0, "Load address and initial program counter")
loadAddress := flag.Int("LoadAddress", 0, "Load address and initial progRam counter")
flag.Parse() flag.Parse()
@ -20,9 +19,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
sw := riscvemu.VirtualEEI{ sw := riscvemu.NewVirtualEEI()
Ram: make([]byte, *memorySize),
}
// Copy file into working memory // Copy file into working memory
fb, err := ioutil.ReadFile(files[0]) fb, err := ioutil.ReadFile(files[0])

View File

@ -6,14 +6,10 @@ import (
func TestCPU(t *testing.T) { func TestCPU(t *testing.T) {
sw := VirtualEEI{ env := NewVirtualEEI()
Ram: make([]byte, 1024), _ = env.Write32(0, 0b00000000000100000000000001110011) // EBREAK
}
_ = sw.Write32(0, 0b00000000000100000000000001110011) // EBREAK
c := CPUState{ c := NewCPU(&env)
w: &sw,
}
err := c.Step() err := c.Step()
panic(err) panic(err)

View File

@ -1,39 +1,64 @@
package riscvemu package riscvemu
import (
"math"
"os"
)
type VirtualEEI struct { type VirtualEEI struct {
Ram []byte memPages map[uint32][4096]byte
}
func NewVirtualEEI() VirtualEEI {
return VirtualEEI{
memPages: make(map[uint32][4096]byte),
}
} }
func (ve *VirtualEEI) ReadByte(addr uint32) (byte, error) { func (ve *VirtualEEI) ReadByte(addr uint32) (byte, error) {
if addr >= uint32(len(ve.Ram)) { page, _ := ve.memPages[addr>>12]
panic("out of bounds") return page[addr&0b111111111111], nil
}
return ve.Ram[addr], nil
} }
func (ve *VirtualEEI) Read32(addr uint32) (uint32, error) { func (ve *VirtualEEI) Read32(addr uint32) (uint32, error) {
// n.b. will panic on overflow // n.b. will panic on overflow
// RISC-V allows 32-bit load/stores to be implemented as either little-endian // RISC-V allows 32-bit load/stores to be implemented as either little-endian
// or big-endian. This is the little-endian version // or big-endian. This is the little-endian version
return (uint32(ve.Ram[addr]) << 24) | (uint32(ve.Ram[addr+1]) << 16) | (uint32(ve.Ram[addr+2]) << 8) | uint32(ve.Ram[addr+3]), nil
page, _ := ve.memPages[addr>>12]
inPageAddr := addr & 0b111111111111
return (uint32(page[inPageAddr]) << 24) | (uint32(page[inPageAddr+1]) << 16) | (uint32(page[inPageAddr+2]) << 8) | uint32(page[inPageAddr+3]), nil
} }
func (ve *VirtualEEI) WriteByte(addr uint32, value byte) error { func (ve *VirtualEEI) WriteByte(addr uint32, value byte) error {
if addr >= uint32(len(ve.Ram)) { page, ok := ve.memPages[addr>>12]
panic("out of bounds")
// Slices are reference-types, this will write-through into ve.memPages
page[addr&0b111111111111] = value
if !ok {
ve.memPages[addr>>12] = page
} }
ve.Ram[addr] = value
return nil return nil
} }
func (ve *VirtualEEI) Write32(addr, value uint32) error { func (ve *VirtualEEI) Write32(addr, value uint32) error {
// n.b. will panic on overflow // n.b. will panic on overflow
ve.Ram[addr] = byte((value >> 24) & 0b11111111)
ve.Ram[addr+1] = byte((value >> 16) & 0b11111111) page, ok := ve.memPages[addr>>12]
ve.Ram[addr+2] = byte((value >> 8) & 0b11111111) inPageAddr := addr & 0b111111111111
ve.Ram[addr+3] = byte(value & 0b11111111)
// Slices are reference-types, this will write-through into ve.memPages
page[inPageAddr] = byte((value >> 24) & 0b11111111)
page[inPageAddr+1] = byte((value >> 16) & 0b11111111)
page[inPageAddr+2] = byte((value >> 8) & 0b11111111)
page[inPageAddr+3] = byte(value & 0b11111111)
if !ok {
ve.memPages[addr>>12] = page
}
return nil return nil
} }