Commit 1b7a4140 authored by Inphi's avatar Inphi Committed by GitHub

cannon: Simplify load/stores with helper functions (#12599)

* cannon: Simplify load/stores with helper functions

* use subword utils in MIPS.sol

* lint MIPS.sol

* add natspec to MIPSInstructions.sol

* use updateSubWord in MIPSInstructions.sol

* bump MIPS contract semver

* fix nits
parent f59d257e
...@@ -343,12 +343,9 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem ...@@ -343,12 +343,9 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
case 0x0F: // lui case 0x0F: // lui
return SignExtend(rt<<16, 32) return SignExtend(rt<<16, 32)
case 0x20: // lb case 0x20: // lb
msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit return SelectSubWord(rs, mem, 1, true)
return SignExtend((mem>>(msb-uint32(rs&arch.ExtMask)*8))&0xFF, 8)
case 0x21: // lh case 0x21: // lh
msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit return SelectSubWord(rs, mem, 2, true)
mask := Word(arch.ExtMask - 1)
return SignExtend((mem>>(msb-uint32(rs&mask)*8))&0xFFFF, 16)
case 0x22: // lwl case 0x22: // lwl
if arch.IsMips32 { if arch.IsMips32 {
val := mem << ((rs & 3) * 8) val := mem << ((rs & 3) * 8)
...@@ -356,26 +353,17 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem ...@@ -356,26 +353,17 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32) return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32)
} else { } else {
// similar to the above mips32 implementation but loads are constrained to the nearest 4-byte memory word // similar to the above mips32 implementation but loads are constrained to the nearest 4-byte memory word
shift := 32 - ((rs & 0x4) << 3) w := uint32(SelectSubWord(rs, mem, 4, false))
w := uint32(mem >> shift) val := w << ((rs & 3) * 8)
val := uint64(w << ((rs & 3) * 8))
mask := Word(uint32(0xFFFFFFFF) << ((rs & 3) * 8)) mask := Word(uint32(0xFFFFFFFF) << ((rs & 3) * 8))
return SignExtend(((rt & ^mask)|Word(val))&0xFFFFFFFF, 32) return SignExtend(((rt & ^mask)|Word(val))&0xFFFFFFFF, 32)
} }
case 0x23: // lw case 0x23: // lw
if arch.IsMips32 { return SelectSubWord(rs, mem, 4, true)
return mem
} else {
// TODO(#12562): Simplify using LoadSubWord
return SignExtend((mem>>(32-((rs&0x4)<<3)))&0xFFFFFFFF, 32)
}
case 0x24: // lbu case 0x24: // lbu
msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit return SelectSubWord(rs, mem, 1, false)
return (mem >> (msb - uint32(rs&arch.ExtMask)*8)) & 0xFF
case 0x25: // lhu case 0x25: // lhu
msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit return SelectSubWord(rs, mem, 2, false)
mask := Word(arch.ExtMask - 1)
return (mem >> (msb - uint32(rs&mask)*8)) & 0xFFFF
case 0x26: // lwr case 0x26: // lwr
if arch.IsMips32 { if arch.IsMips32 {
val := mem >> (24 - (rs&3)*8) val := mem >> (24 - (rs&3)*8)
...@@ -383,8 +371,7 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem ...@@ -383,8 +371,7 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32) return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32)
} else { } else {
// similar to the above mips32 implementation but constrained to the nearest 4-byte memory word // similar to the above mips32 implementation but constrained to the nearest 4-byte memory word
shift := 32 - ((rs & 0x4) << 3) w := uint32(SelectSubWord(rs, mem, 4, false))
w := uint32(mem >> shift)
val := w >> (24 - (rs&3)*8) val := w >> (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8) mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8)
lwrResult := ((uint32(rt) & ^mask) | val) & 0xFFFFFFFF lwrResult := ((uint32(rt) & ^mask) | val) & 0xFFFFFFFF
...@@ -397,17 +384,9 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem ...@@ -397,17 +384,9 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
} }
} }
case 0x28: // sb case 0x28: // sb
msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit return UpdateSubWord(rs, mem, 1, rt)
val := (rt & 0xFF) << (msb - uint32(rs&arch.ExtMask)*8)
mask := ^Word(0) ^ Word(0xFF<<(msb-uint32(rs&arch.ExtMask)*8))
return (mem & mask) | val
case 0x29: // sh case 0x29: // sh
msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit return UpdateSubWord(rs, mem, 2, rt)
rsMask := Word(arch.ExtMask - 1) // 2 for 32-bit and 6 for 64-bit
sl := msb - uint32(rs&rsMask)*8
val := (rt & 0xFFFF) << sl
mask := ^Word(0) ^ Word(0xFFFF<<sl)
return (mem & mask) | val
case 0x2a: // swl case 0x2a: // swl
if arch.IsMips32 { if arch.IsMips32 {
val := rt >> ((rs & 3) * 8) val := rt >> ((rs & 3) * 8)
...@@ -420,14 +399,7 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem ...@@ -420,14 +399,7 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return (mem & Word(^mask)) | val return (mem & Word(^mask)) | val
} }
case 0x2b: // sw case 0x2b: // sw
if arch.IsMips32 { return UpdateSubWord(rs, mem, 4, rt)
return rt
} else {
sl := 32 - ((rs & 0x4) << 3)
val := (rt & 0xFFFFFFFF) << sl
mask := Word(0xFFFFFFFFFFFFFFFF ^ uint64(0xFFFFFFFF<<sl))
return Word(mem&mask) | Word(val)
}
case 0x2e: // swr case 0x2e: // swr
if arch.IsMips32 { if arch.IsMips32 {
val := rt << (24 - (rs&3)*8) val := rt << (24 - (rs&3)*8)
...@@ -435,18 +407,11 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem ...@@ -435,18 +407,11 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return (mem & Word(^mask)) | val return (mem & Word(^mask)) | val
} else { } else {
// similar to the above mips32 implementation but constrained to the nearest 4-byte memory word // similar to the above mips32 implementation but constrained to the nearest 4-byte memory word
shift := 32 - ((rs & 0x4) << 3) w := uint32(SelectSubWord(rs, mem, 4, false))
w := uint32(mem >> shift)
val := rt << (24 - (rs&3)*8) val := rt << (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8) mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8)
swrResult := (w & ^mask) | uint32(val) swrResult := (w & ^mask) | uint32(val)
// merge with the untouched bytes in mem return UpdateSubWord(rs, mem, 4, Word(swrResult))
if shift > 0 {
return (Word(swrResult) << 32) | (mem & Word(^uint32(0))) // nolint: staticcheck
} else {
memMask := uint64(0xFF_FF_FF_FF_00_00_00_00)
return (mem & Word(memMask)) | Word(swrResult & ^uint32(0))
}
} }
// MIPS64 // MIPS64
...@@ -663,45 +628,56 @@ func HandleRd(cpu *mipsevm.CpuScalars, registers *[32]Word, storeReg Word, val W ...@@ -663,45 +628,56 @@ func HandleRd(cpu *mipsevm.CpuScalars, registers *[32]Word, storeReg Word, val W
return nil return nil
} }
func LoadSubWord(memory *memory.Memory, addr Word, byteLength Word, signExtend bool, memoryTracker MemTracker) Word { // LoadSubWord loads a subword of byteLength size from memory based on the low-order bits of vaddr
func LoadSubWord(memory *memory.Memory, vaddr Word, byteLength Word, signExtend bool, memoryTracker MemTracker) Word {
// Pull data from memory // Pull data from memory
effAddr := (addr) & arch.AddressMask effAddr := (vaddr) & arch.AddressMask
memoryTracker.TrackMemAccess(effAddr) memoryTracker.TrackMemAccess(effAddr)
mem := memory.GetWord(effAddr) mem := memory.GetWord(effAddr)
// Extract a sub-word based on the low-order bits in addr return SelectSubWord(vaddr, mem, byteLength, signExtend)
dataMask, bitOffset, bitLength := calculateSubWordMaskAndOffset(addr, byteLength)
retVal := (mem >> bitOffset) & dataMask
if signExtend {
retVal = SignExtend(retVal, bitLength)
}
return retVal
} }
func StoreSubWord(memory *memory.Memory, addr Word, byteLength Word, value Word, memoryTracker MemTracker) { // StoreSubWord stores a [Word] that has been updated by the specified value at bit positions determined by the vaddr
func StoreSubWord(memory *memory.Memory, vaddr Word, byteLength Word, value Word, memoryTracker MemTracker) {
// Pull data from memory // Pull data from memory
effAddr := (addr) & arch.AddressMask effAddr := (vaddr) & arch.AddressMask
memoryTracker.TrackMemAccess(effAddr) memoryTracker.TrackMemAccess(effAddr)
mem := memory.GetWord(effAddr) mem := memory.GetWord(effAddr)
// Modify isolated sub-word within mem // Modify isolated sub-word within mem
dataMask, bitOffset, _ := calculateSubWordMaskAndOffset(addr, byteLength) newMemVal := UpdateSubWord(vaddr, mem, byteLength, value)
memory.SetWord(effAddr, newMemVal)
}
// SelectSubWord selects a subword of byteLength size contained in memWord based on the low-order bits of vaddr
// This is the nearest subword that is naturally aligned by the specified byteLength
func SelectSubWord(vaddr Word, memWord Word, byteLength Word, signExtend bool) Word {
// Extract a sub-word based on the low-order bits in vaddr
dataMask, bitOffset, bitLength := calculateSubWordMaskAndOffset(vaddr, byteLength)
retVal := (memWord >> bitOffset) & dataMask
if signExtend {
retVal = SignExtend(retVal, bitLength)
}
return retVal
}
// UpdateSubWord returns a [Word] that has been updated by the specified value at bit positions determined by the vaddr
func UpdateSubWord(vaddr Word, memWord Word, byteLength Word, value Word) Word {
dataMask, bitOffset, _ := calculateSubWordMaskAndOffset(vaddr, byteLength)
subWordValue := dataMask & value subWordValue := dataMask & value
memUpdateMask := dataMask << bitOffset memUpdateMask := dataMask << bitOffset
newMemVal := subWordValue<<bitOffset | (^memUpdateMask)&mem return subWordValue<<bitOffset | (^memUpdateMask)&memWord
memory.SetWord(effAddr, newMemVal)
} }
func calculateSubWordMaskAndOffset(addr Word, byteLength Word) (dataMask, bitOffset, bitLength Word) { func calculateSubWordMaskAndOffset(vaddr Word, byteLength Word) (dataMask, bitOffset, bitLength Word) {
bitLength = byteLength << 3 bitLength = byteLength << 3
dataMask = ^Word(0) >> (arch.WordSize - bitLength) dataMask = ^Word(0) >> (arch.WordSize - bitLength)
// Figure out sub-word index based on the low-order bits in addr // Figure out sub-word index based on the low-order bits in vaddr
byteIndexMask := addr & arch.ExtMask & ^(byteLength - 1) byteIndexMask := vaddr & arch.ExtMask & ^(byteLength - 1)
maxByteShift := arch.WordSizeBytes - byteLength maxByteShift := arch.WordSizeBytes - byteLength
byteIndex := addr & byteIndexMask byteIndex := vaddr & byteIndexMask
bitOffset = (maxByteShift - byteIndex) << 3 bitOffset = (maxByteShift - byteIndex) << 3
return dataMask, bitOffset, bitLength return dataMask, bitOffset, bitLength
......
...@@ -322,19 +322,19 @@ func TestEVMSingleStep_LoadStore64(t *testing.T) { ...@@ -322,19 +322,19 @@ func TestEVMSingleStep_LoadStore64(t *testing.T) {
{name: "lwr sign-extended imm 7 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_71_B1_C1_D1), expectRes: Word(0x00_00_00_00_71_B1_C1_D1)}, // lwr $t0, 7($t1) {name: "lwr sign-extended imm 7 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_71_B1_C1_D1), expectRes: Word(0x00_00_00_00_71_B1_C1_D1)}, // lwr $t0, 7($t1)
{name: "lwr sign-extended imm 7 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_A1_B1_C1_D1)}, // lwr $t0, 7($t1) {name: "lwr sign-extended imm 7 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_A1_B1_C1_D1)}, // lwr $t0, 7($t1)
{name: "sb offset=0", opcode: uint32(0x28), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, expectMemVal: Word(0x88_00_00_00_00_00_00_00)}, // sb $t0, 0($t1) {name: "sb offset=0", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, expectMemVal: Word(0x88_BB_CC_DD_A1_B1_C1_D1)}, // sb $t0, 0($t1)
{name: "sb offset=1", opcode: uint32(0x28), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, expectMemVal: Word(0x00_88_00_00_00_00_00_00)}, // sb $t0, 1($t1) {name: "sb offset=1", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, expectMemVal: Word(0xAA_88_CC_DD_A1_B1_C1_D1)}, // sb $t0, 1($t1)
{name: "sb offset=2", opcode: uint32(0x28), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, expectMemVal: Word(0x00_00_88_00_00_00_00_00)}, // sb $t0, 2($t1) {name: "sb offset=2", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, expectMemVal: Word(0xAA_BB_88_DD_A1_B1_C1_D1)}, // sb $t0, 2($t1)
{name: "sb offset=3", opcode: uint32(0x28), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, expectMemVal: Word(0x00_00_00_88_00_00_00_00)}, // sb $t0, 3($t1) {name: "sb offset=3", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, expectMemVal: Word(0xAA_BB_CC_88_A1_B1_C1_D1)}, // sb $t0, 3($t1)
{name: "sb offset=4", opcode: uint32(0x28), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, expectMemVal: Word(0x00_00_00_00_88_00_00_00)}, // sb $t0, 4($t1) {name: "sb offset=4", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, expectMemVal: Word(0xAA_BB_CC_DD_88_B1_C1_D1)}, // sb $t0, 4($t1)
{name: "sb offset=5", opcode: uint32(0x28), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, expectMemVal: Word(0x00_00_00_00_00_88_00_00)}, // sb $t0, 5($t1) {name: "sb offset=5", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, expectMemVal: Word(0xAA_BB_CC_DD_A1_88_C1_D1)}, // sb $t0, 5($t1)
{name: "sb offset=6", opcode: uint32(0x28), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, expectMemVal: Word(0x00_00_00_00_00_00_88_00)}, // sb $t0, 6($t1) {name: "sb offset=6", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_88_D1)}, // sb $t0, 6($t1)
{name: "sb offset=7", opcode: uint32(0x28), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, expectMemVal: Word(0x00_00_00_00_00_00_00_88)}, // sb $t0, 7($t1) {name: "sb offset=7", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_C1_88)}, // sb $t0, 7($t1)
{name: "sh offset=0", opcode: uint32(0x29), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, expectMemVal: Word(0x77_88_00_00_00_00_00_00)}, // sh $t0, 0($t1) {name: "sh offset=0", opcode: uint32(0x29), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, expectMemVal: Word(0x77_88_CC_DD_A1_B1_C1_D1)}, // sh $t0, 0($t1)
{name: "sh offset=2", opcode: uint32(0x29), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, expectMemVal: Word(0x00_00_77_88_00_00_00_00)}, // sh $t0, 2($t1) {name: "sh offset=2", opcode: uint32(0x29), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, expectMemVal: Word(0xAA_BB_77_88_A1_B1_C1_D1)}, // sh $t0, 2($t1)
{name: "sh offset=4", opcode: uint32(0x29), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, expectMemVal: Word(0x00_00_00_00_77_88_00_00)}, // sh $t0, 4($t1) {name: "sh offset=4", opcode: uint32(0x29), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, expectMemVal: Word(0xAA_BB_CC_DD_77_88_C1_D1)}, // sh $t0, 4($t1)
{name: "sh offset=6", opcode: uint32(0x29), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, expectMemVal: Word(0x00_00_00_00_00_00_77_88)}, // sh $t0, 6($t1) {name: "sh offset=6", opcode: uint32(0x29), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_77_88)}, // sh $t0, 6($t1)
{name: "swl offset=0", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 0, expectMemVal: Word(0x55_66_77_88_A1_B1_C1_D1)}, // swl $t0, 0($t1) {name: "swl offset=0", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 0, expectMemVal: Word(0x55_66_77_88_A1_B1_C1_D1)}, // swl $t0, 0($t1)
{name: "swl offset=1", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 1, expectMemVal: Word(0xAA_55_66_77_A1_B1_C1_D1)}, // swl $t0, 1($t1) {name: "swl offset=1", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 1, expectMemVal: Word(0xAA_55_66_77_A1_B1_C1_D1)}, // swl $t0, 1($t1)
......
...@@ -140,12 +140,12 @@ ...@@ -140,12 +140,12 @@
"sourceCodeHash": "0x0fa0633a769e73f5937514c0003ba7947a1c275bbe5b85d78879c42f0ed8895b" "sourceCodeHash": "0x0fa0633a769e73f5937514c0003ba7947a1c275bbe5b85d78879c42f0ed8895b"
}, },
"src/cannon/MIPS.sol": { "src/cannon/MIPS.sol": {
"initCodeHash": "0x696c3ce334c11d0f9633945babac22b1b65848ff00d2cf6c4cb18116bbf138b2", "initCodeHash": "0x94f2e8f7818a990c009cccb501216a7f6df29b05d8f178cfff10a40288bf588e",
"sourceCodeHash": "0x3c2e5d6d39b29a60dcd1a776363518c87fcfef9a8d80e38696f56b6eec5bd53a" "sourceCodeHash": "0x786d4947488a771a426cc38de307ae99b2c2af1efca38b7655c60be7c019371f"
}, },
"src/cannon/MIPS2.sol": { "src/cannon/MIPS2.sol": {
"initCodeHash": "0x5c292882075bd06e68b89119be9096040bc913f51bb878ce4a9dfdd674330dd5", "initCodeHash": "0x3744036fa240c7d57f39307c0bf27cb7027d05d6b4f52142d5122b6e538ee0b2",
"sourceCodeHash": "0x17c7b0edb9d20932eaf1b038e3e05e457f0461d2c8691ba1940fb4c2b0dfd123" "sourceCodeHash": "0x5f79a0f99a288d570df243ea9560e67a319d1685b3209ae457fc714a76ff2908"
}, },
"src/cannon/PreimageOracle.sol": { "src/cannon/PreimageOracle.sol": {
"initCodeHash": "0x5d7e8ae64f802bd9d760e3d52c0a620bd02405dc2c8795818db9183792ffe81c", "initCodeHash": "0x5d7e8ae64f802bd9d760e3d52c0a620bd02405dc2c8795818db9183792ffe81c",
......
...@@ -44,8 +44,8 @@ contract MIPS is ISemver { ...@@ -44,8 +44,8 @@ contract MIPS is ISemver {
} }
/// @notice The semantic version of the MIPS contract. /// @notice The semantic version of the MIPS contract.
/// @custom:semver 1.2.1-beta.5 /// @custom:semver 1.2.1-beta.6
string public constant version = "1.2.1-beta.5"; string public constant version = "1.2.1-beta.6";
/// @notice The preimage oracle contract. /// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE; IPreimageOracle internal immutable ORACLE;
......
...@@ -60,8 +60,8 @@ contract MIPS2 is ISemver { ...@@ -60,8 +60,8 @@ contract MIPS2 is ISemver {
} }
/// @notice The semantic version of the MIPS2 contract. /// @notice The semantic version of the MIPS2 contract.
/// @custom:semver 1.0.0-beta.18 /// @custom:semver 1.0.0-beta.19
string public constant version = "1.0.0-beta.18"; string public constant version = "1.0.0-beta.19";
/// @notice The preimage oracle contract. /// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE; IPreimageOracle internal immutable ORACLE;
......
...@@ -379,11 +379,11 @@ library MIPSInstructions { ...@@ -379,11 +379,11 @@ library MIPSInstructions {
} }
// lb // lb
else if (_opcode == 0x20) { else if (_opcode == 0x20) {
return signExtend((_mem >> (24 - (_rs & 3) * 8)) & 0xFF, 8); return selectSubWord(_rs, _mem, 1, true);
} }
// lh // lh
else if (_opcode == 0x21) { else if (_opcode == 0x21) {
return signExtend((_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF, 16); return selectSubWord(_rs, _mem, 2, true);
} }
// lwl // lwl
else if (_opcode == 0x22) { else if (_opcode == 0x22) {
...@@ -393,15 +393,15 @@ library MIPSInstructions { ...@@ -393,15 +393,15 @@ library MIPSInstructions {
} }
// lw // lw
else if (_opcode == 0x23) { else if (_opcode == 0x23) {
return _mem; return selectSubWord(_rs, _mem, 4, true);
} }
// lbu // lbu
else if (_opcode == 0x24) { else if (_opcode == 0x24) {
return (_mem >> (24 - (_rs & 3) * 8)) & 0xFF; return selectSubWord(_rs, _mem, 1, false);
} }
// lhu // lhu
else if (_opcode == 0x25) { else if (_opcode == 0x25) {
return (_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF; return selectSubWord(_rs, _mem, 2, false);
} }
// lwr // lwr
else if (_opcode == 0x26) { else if (_opcode == 0x26) {
...@@ -411,15 +411,11 @@ library MIPSInstructions { ...@@ -411,15 +411,11 @@ library MIPSInstructions {
} }
// sb // sb
else if (_opcode == 0x28) { else if (_opcode == 0x28) {
uint32 val = (_rt & 0xFF) << (24 - (_rs & 3) * 8); return updateSubWord(_rs, _mem, 1, _rt);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFF << (24 - (_rs & 3) * 8));
return (_mem & mask) | val;
} }
// sh // sh
else if (_opcode == 0x29) { else if (_opcode == 0x29) {
uint32 val = (_rt & 0xFFFF) << (16 - (_rs & 2) * 8); return updateSubWord(_rs, _mem, 2, _rt);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFFFF << (16 - (_rs & 2) * 8));
return (_mem & mask) | val;
} }
// swl // swl
else if (_opcode == 0x2a) { else if (_opcode == 0x2a) {
...@@ -429,7 +425,7 @@ library MIPSInstructions { ...@@ -429,7 +425,7 @@ library MIPSInstructions {
} }
// sw // sw
else if (_opcode == 0x2b) { else if (_opcode == 0x2b) {
return _rt; return updateSubWord(_rs, _mem, 4, _rt);
} }
// swr // swr
else if (_opcode == 0x2e) { else if (_opcode == 0x2e) {
...@@ -667,4 +663,69 @@ library MIPSInstructions { ...@@ -667,4 +663,69 @@ library MIPSInstructions {
_cpu.nextPC = _cpu.nextPC + 4; _cpu.nextPC = _cpu.nextPC + 4;
} }
} }
/// @notice Selects a subword of byteLength size contained in memWord based on the low-order bits of vaddr
/// @param _vaddr The virtual address of the the subword.
/// @param _memWord The full word to select a subword from.
/// @param _byteLength The size of the subword.
/// @param _signExtend Whether to sign extend the selected subwrod.
function selectSubWord(
uint32 _vaddr,
uint32 _memWord,
uint32 _byteLength,
bool _signExtend
)
internal
pure
returns (uint32 retval_)
{
(uint32 dataMask, uint32 bitOffset, uint32 bitLength) = calculateSubWordMaskAndOffset(_vaddr, _byteLength);
retval_ = (_memWord >> bitOffset) & dataMask;
if (_signExtend) {
retval_ = signExtend(retval_, bitLength);
}
return retval_;
}
/// @notice Returns a word that has been updated by the specified subword at bit positions determined by the virtual
/// address
/// @param _vaddr The virtual address of the subword.
/// @param _memWord The full word to update.
/// @param _byteLength The size of the subword.
/// @param _value The subword that updates _memWord.
function updateSubWord(
uint32 _vaddr,
uint32 _memWord,
uint32 _byteLength,
uint32 _value
)
internal
pure
returns (uint32 word_)
{
(uint32 dataMask, uint32 bitOffset,) = calculateSubWordMaskAndOffset(_vaddr, _byteLength);
uint32 subWordValue = dataMask & _value;
uint32 memUpdateMask = dataMask << bitOffset;
return subWordValue << bitOffset | (~memUpdateMask) & _memWord;
}
function calculateSubWordMaskAndOffset(
uint32 _vaddr,
uint32 _byteLength
)
internal
pure
returns (uint32 dataMask_, uint32 bitOffset_, uint32 bitLength_)
{
uint32 bitLength = _byteLength << 3;
uint32 dataMask = ~uint32(0) >> (32 - bitLength);
// Figure out sub-word index based on the low-order bits in vaddr
uint32 byteIndexMask = _vaddr & 0x3 & ~(_byteLength - 1);
uint32 maxByteShift = 4 - _byteLength;
uint32 byteIndex = _vaddr & byteIndexMask;
uint32 bitOffset = (maxByteShift - byteIndex) << 3;
return (dataMask, bitOffset, bitLength);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment