eei: fixes for write-through pages, endianness
This commit is contained in:
parent
396cece705
commit
9826230bc4
@ -6,27 +6,35 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type VirtualEEI struct {
|
type VirtualEEI struct {
|
||||||
memPages map[uint32][4096]byte
|
memPages map[uint32]*[4096]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVirtualEEI() VirtualEEI {
|
func NewVirtualEEI() VirtualEEI {
|
||||||
return VirtualEEI{
|
return VirtualEEI{
|
||||||
memPages: make(map[uint32][4096]byte),
|
memPages: make(map[uint32]*[4096]byte),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ve *VirtualEEI) ReadByte(addr uint32) (byte, error) {
|
func (ve *VirtualEEI) ReadByte(addr uint32) (byte, error) {
|
||||||
page, _ := ve.memPages[addr>>12]
|
page, ok := ve.memPages[addr>>12]
|
||||||
|
if !ok {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
return page[addr&0b111111111111], nil
|
return page[addr&0b111111111111], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ve *VirtualEEI) Read16(addr uint32) (uint16, error) {
|
func (ve *VirtualEEI) Read16(addr uint32) (uint16, error) {
|
||||||
// n.b. will panic on overflow
|
// n.b. will panic on overflow
|
||||||
|
|
||||||
page, _ := ve.memPages[addr>>12]
|
page, ok := ve.memPages[addr>>12]
|
||||||
|
if !ok {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
inPageAddr := addr & 0b111111111111
|
inPageAddr := addr & 0b111111111111
|
||||||
|
|
||||||
return (uint16(page[inPageAddr]) << 8) | uint16(page[inPageAddr+1]), nil
|
return (uint16(page[inPageAddr+1]) << 8) | uint16(page[inPageAddr]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ve *VirtualEEI) Read32(addr uint32) (uint32, error) {
|
func (ve *VirtualEEI) Read32(addr uint32) (uint32, error) {
|
||||||
@ -34,57 +42,61 @@ func (ve *VirtualEEI) Read32(addr uint32) (uint32, error) {
|
|||||||
// 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
|
||||||
|
|
||||||
page, _ := ve.memPages[addr>>12]
|
page, ok := ve.memPages[addr>>12]
|
||||||
|
if !ok {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
inPageAddr := addr & 0b111111111111
|
inPageAddr := addr & 0b111111111111
|
||||||
|
|
||||||
return (uint32(page[inPageAddr]) << 24) | (uint32(page[inPageAddr+1]) << 16) | (uint32(page[inPageAddr+2]) << 8) | uint32(page[inPageAddr+3]), nil
|
return (uint32(page[inPageAddr+3]) << 24) | (uint32(page[inPageAddr+2]) << 16) | (uint32(page[inPageAddr+1]) << 8) | uint32(page[inPageAddr]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ve *VirtualEEI) WriteByte(addr uint32, value byte) error {
|
func (ve *VirtualEEI) WriteByte(addr uint32, value byte) error {
|
||||||
page, ok := ve.memPages[addr>>12]
|
page, ok := ve.memPages[addr>>12]
|
||||||
|
|
||||||
// Slices are reference-types, this will write-through into ve.memPages
|
|
||||||
page[addr&0b111111111111] = value
|
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
|
page = new([4096]byte)
|
||||||
ve.memPages[addr>>12] = page
|
ve.memPages[addr>>12] = page
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The pointer-to-page-array is a reference type, this will write-through into ve.memPages
|
||||||
|
page[addr&0b111111111111] = value
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ve *VirtualEEI) Write16(addr uint32, value uint16) error {
|
func (ve *VirtualEEI) Write16(addr uint32, value uint16) error {
|
||||||
// n.b. will panic on split page boundary
|
|
||||||
|
|
||||||
page, ok := ve.memPages[addr>>12]
|
page, ok := ve.memPages[addr>>12]
|
||||||
inPageAddr := addr & 0b111111111111
|
|
||||||
|
|
||||||
// Slices are reference-types, this will write-through into ve.memPages
|
|
||||||
page[inPageAddr] = byte((value >> 8) & 0b11111111)
|
|
||||||
page[inPageAddr+1] = byte(value & 0b11111111)
|
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
|
page = new([4096]byte)
|
||||||
ve.memPages[addr>>12] = page
|
ve.memPages[addr>>12] = page
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inPageAddr := addr & 0b111111111111
|
||||||
|
|
||||||
|
// The pointer-to-page-array is a reference type, this will write-through into ve.memPages
|
||||||
|
// n.b. will panic on split page boundary
|
||||||
|
page[inPageAddr+1] = byte((value >> 8) & 0b11111111)
|
||||||
|
page[inPageAddr] = byte(value & 0b11111111)
|
||||||
|
|
||||||
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 split page boundary
|
|
||||||
|
|
||||||
page, ok := ve.memPages[addr>>12]
|
page, ok := ve.memPages[addr>>12]
|
||||||
inPageAddr := addr & 0b111111111111
|
|
||||||
|
|
||||||
// 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 {
|
if !ok {
|
||||||
|
page = new([4096]byte)
|
||||||
ve.memPages[addr>>12] = page
|
ve.memPages[addr>>12] = page
|
||||||
}
|
}
|
||||||
|
inPageAddr := addr & 0b111111111111
|
||||||
|
|
||||||
|
// The pointer-to-page-array is a reference type, this will write-through into ve.memPages
|
||||||
|
// n.b. will panic on split page boundary
|
||||||
|
page[inPageAddr+3] = byte((value >> 24) & 0b11111111)
|
||||||
|
page[inPageAddr+2] = byte((value >> 16) & 0b11111111)
|
||||||
|
page[inPageAddr+1] = byte((value >> 8) & 0b11111111)
|
||||||
|
page[inPageAddr] = byte(value & 0b11111111)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
57
virtualEei_test.go
Normal file
57
virtualEei_test.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package riscvemu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEndianness(t *testing.T) {
|
||||||
|
e := NewVirtualEEI()
|
||||||
|
|
||||||
|
err := e.Write32(0, 0x12345678)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rw, err := e.Read32(0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if rw != 0x12345678 {
|
||||||
|
t.Errorf("got %x expected 0x12345678", rw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// In little-endian, the 32-bit value 0x12345678 is written in order with its
|
||||||
|
// least-significant bytes first (i.e. in a hex editor: 78563412)
|
||||||
|
|
||||||
|
rb, err := e.ReadByte(0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if rb != 0x78 {
|
||||||
|
t.Errorf("got %x expected 0x78", rb)
|
||||||
|
}
|
||||||
|
|
||||||
|
rb, err = e.ReadByte(1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if rb != 0x56 {
|
||||||
|
t.Errorf("got %x expected 0x56", rb)
|
||||||
|
}
|
||||||
|
|
||||||
|
rb, err = e.ReadByte(2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if rb != 0x34 {
|
||||||
|
t.Errorf("got %x expected 0x34", rb)
|
||||||
|
}
|
||||||
|
|
||||||
|
rb, err = e.ReadByte(3)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if rb != 0x12 {
|
||||||
|
t.Errorf("got %x expected 0x12", rb)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user