diff --git a/.gitignore b/.gitignore index 6309b28..30a5f23 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -riscvemu -riscvemu.debug +cmd/riscvrun/riscvrun diff --git a/cmd/riscvrun/main.go b/cmd/riscvrun/main.go new file mode 100644 index 0000000..9c02259 --- /dev/null +++ b/cmd/riscvrun/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "io/ioutil" + "os" + + "riscvemu" +) + +func main() { + memorySize := flag.Int("MemorySize", 4096, "Memory size (bytes)") + loadAddress := flag.Int("LoadAddress", 0, "Load address and initial progRam counter") + + flag.Parse() + + files := flag.Args() + if len(files) != 1 { + flag.Usage() + os.Exit(1) + } + + sw := riscvemu.MemoryWorld{ + Ram: make([]byte, *memorySize), + } + + // Copy file into working memory + fb, err := ioutil.ReadFile(files[0]) + if err != nil { + panic(err) + } + copy(sw.Ram[*loadAddress:*loadAddress+len(fb)], fb) + + c := riscvemu.NewCPU(&sw) + c.Pc = uint32(*loadAddress) + + for { + err := c.Step() + if err != nil { + panic(err) + } + } +} diff --git a/main.go b/cpu.go similarity index 85% rename from main.go rename to cpu.go index b96c34b..0ba8970 100644 --- a/main.go +++ b/cpu.go @@ -1,4 +1,4 @@ -package main +package riscvemu import ( "fmt" @@ -14,6 +14,10 @@ type CPUState struct { w World } +func NewCPU(w World) CPUState { + return CPUState{w: w} +} + func opcode_rd(opcode uint32) uint32 { return (opcode >> 7) & 0b11111 } func opcode_rs1(opcode uint32) uint32 { return (opcode >> 15) & 0b11111 } // 2^5 is 32 for 32 registers func opcode_rs2(opcode uint32) uint32 { return (opcode >> 19) & 0b11111 } @@ -27,7 +31,7 @@ func (c *CPUState) ReadRegister(r uint32) uint32 { } func (c *CPUState) Step() error { - opcode, err := c.w.ReadMemory(c.Pc) + opcode, err := c.w.Read32(c.Pc) if err != nil { return fmt.Errorf("ReadMemory: %w", err) } @@ -164,51 +168,3 @@ func (c *CPUState) Step() error { return nil } - -type World interface { - ReadMemory(addr uint32) (uint32, error) - WriteMemory(addr, value uint32) error - Syscall() - Trap() (bool, error) -} - -type SampleWorld struct { - ram [1024]uint32 -} - -func (sw *SampleWorld) ReadMemory(addr uint32) (uint32, error) { - if addr >= uint32(len(sw.ram)) { - panic("out of bounds") - } - - return sw.ram[addr], nil -} - -func (sw *SampleWorld) WriteMemory(addr, value uint32) error { - if addr >= uint32(len(sw.ram)) { - panic("out of bounds") - } - - sw.ram[addr] = value - return nil -} - -func (sw *SampleWorld) Syscall() { - panic("syscall") -} - -func (sw *SampleWorld) Trap() (bool, error) { - panic("trap") -} - -func main() { - sw := SampleWorld{} - sw.ram[0] = 0b00000000000100000000000001110011 // EBREAK - - c := CPUState{ - w: &sw, - } - - err := c.Step() - panic(err) -} diff --git a/cpu_test.go b/cpu_test.go new file mode 100644 index 0000000..cb89695 --- /dev/null +++ b/cpu_test.go @@ -0,0 +1,21 @@ +package riscvemu + +import ( + "testing" +) + +func TestCPU(t *testing.T) { + + sw := MemoryWorld{ + Ram: make([]byte, 1024), + } + _ = sw.Write32(0, 0b00000000000100000000000001110011) // EBREAK + + c := CPUState{ + w: &sw, + } + + err := c.Step() + panic(err) + +} diff --git a/memoryWorld.go b/memoryWorld.go new file mode 100644 index 0000000..3684ee4 --- /dev/null +++ b/memoryWorld.go @@ -0,0 +1,45 @@ +package riscvemu + +type MemoryWorld struct { + Ram []byte +} + +func (mw *MemoryWorld) ReadByte(addr uint32) (byte, error) { + if addr >= uint32(len(mw.Ram)) { + panic("out of bounds") + } + + return mw.Ram[addr], nil +} + +func (mw *MemoryWorld) Read32(addr uint32) (uint32, error) { + // n.b. will panic on overflow + return (uint32(mw.Ram[addr]) << 24) | (uint32(mw.Ram[addr+1]) << 16) | (uint32(mw.Ram[addr+2]) << 8) | uint32(mw.Ram[addr+3]), nil +} + +func (mw *MemoryWorld) WriteByte(addr uint32, value byte) error { + if addr >= uint32(len(mw.Ram)) { + panic("out of bounds") + } + + mw.Ram[addr] = value + return nil +} + +func (mw *MemoryWorld) Write32(addr, value uint32) error { + // n.b. will panic on overflow + mw.Ram[addr] = byte((value >> 24) & 0b11111111) + mw.Ram[addr+1] = byte((value >> 16) & 0b11111111) + mw.Ram[addr+2] = byte((value >> 8) & 0b11111111) + mw.Ram[addr+3] = byte(value & 0b11111111) + + return nil +} + +func (mw *MemoryWorld) Syscall() { + panic("syscall") +} + +func (mw *MemoryWorld) Trap() (bool, error) { + panic("trap") +} diff --git a/world.go b/world.go new file mode 100644 index 0000000..4276a7b --- /dev/null +++ b/world.go @@ -0,0 +1,12 @@ +package riscvemu + +type World interface { + ReadByte(addr uint32) (byte, error) + Read32(addr uint32) (uint32, error) + WriteByte(addr uint32, value byte) error + Write32(addr, value uint32) error + + Syscall() + + Trap() (bool, error) +}