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
case 0x0F: // lui
return SignExtend(rt<<16, 32)
case 0x20: // lb
msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit
return SignExtend((mem>>(msb-uint32(rs&arch.ExtMask)*8))&0xFF, 8)
return SelectSubWord(rs, mem, 1, true)
case 0x21: // lh
msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit
mask := Word(arch.ExtMask - 1)
return SignExtend((mem>>(msb-uint32(rs&mask)*8))&0xFFFF, 16)
return SelectSubWord(rs, mem, 2, true)
case 0x22: // lwl
if arch.IsMips32 {
val := mem << ((rs & 3) * 8)
......@@ -356,26 +353,17 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32)
} else {
// similar to the above mips32 implementation but loads are constrained to the nearest 4-byte memory word
shift := 32 - ((rs & 0x4) << 3)
w := uint32(mem >> shift)
val := uint64(w << ((rs & 3) * 8))
w := uint32(SelectSubWord(rs, mem, 4, false))
val := w << ((rs & 3) * 8)
mask := Word(uint32(0xFFFFFFFF) << ((rs & 3) * 8))
return SignExtend(((rt & ^mask)|Word(val))&0xFFFFFFFF, 32)
}
case 0x23: // lw
if arch.IsMips32 {
return mem
} else {
// TODO(#12562): Simplify using LoadSubWord
return SignExtend((mem>>(32-((rs&0x4)<<3)))&0xFFFFFFFF, 32)
}
return SelectSubWord(rs, mem, 4, true)
case 0x24: // lbu
msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit
return (mem >> (msb - uint32(rs&arch.ExtMask)*8)) & 0xFF
return SelectSubWord(rs, mem, 1, false)
case 0x25: // lhu
msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit
mask := Word(arch.ExtMask - 1)
return (mem >> (msb - uint32(rs&mask)*8)) & 0xFFFF
return SelectSubWord(rs, mem, 2, false)
case 0x26: // lwr
if arch.IsMips32 {
val := mem >> (24 - (rs&3)*8)
......@@ -383,8 +371,7 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32)
} else {
// similar to the above mips32 implementation but constrained to the nearest 4-byte memory word
shift := 32 - ((rs & 0x4) << 3)
w := uint32(mem >> shift)
w := uint32(SelectSubWord(rs, mem, 4, false))
val := w >> (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8)
lwrResult := ((uint32(rt) & ^mask) | val) & 0xFFFFFFFF
......@@ -397,17 +384,9 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
}
}
case 0x28: // sb
msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit
val := (rt & 0xFF) << (msb - uint32(rs&arch.ExtMask)*8)
mask := ^Word(0) ^ Word(0xFF<<(msb-uint32(rs&arch.ExtMask)*8))
return (mem & mask) | val
return UpdateSubWord(rs, mem, 1, rt)
case 0x29: // sh
msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit
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
return UpdateSubWord(rs, mem, 2, rt)
case 0x2a: // swl
if arch.IsMips32 {
val := rt >> ((rs & 3) * 8)
......@@ -420,14 +399,7 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return (mem & Word(^mask)) | val
}
case 0x2b: // sw
if arch.IsMips32 {
return rt
} else {
sl := 32 - ((rs & 0x4) << 3)
val := (rt & 0xFFFFFFFF) << sl
mask := Word(0xFFFFFFFFFFFFFFFF ^ uint64(0xFFFFFFFF<<sl))
return Word(mem&mask) | Word(val)
}
return UpdateSubWord(rs, mem, 4, rt)
case 0x2e: // swr
if arch.IsMips32 {
val := rt << (24 - (rs&3)*8)
......@@ -435,18 +407,11 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return (mem & Word(^mask)) | val
} else {
// similar to the above mips32 implementation but constrained to the nearest 4-byte memory word
shift := 32 - ((rs & 0x4) << 3)
w := uint32(mem >> shift)
w := uint32(SelectSubWord(rs, mem, 4, false))
val := rt << (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8)
swrResult := (w & ^mask) | uint32(val)
// merge with the untouched bytes in mem
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))
}
return UpdateSubWord(rs, mem, 4, Word(swrResult))
}
// MIPS64
......@@ -663,45 +628,56 @@ func HandleRd(cpu *mipsevm.CpuScalars, registers *[32]Word, storeReg Word, val W
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
effAddr := (addr) & arch.AddressMask
effAddr := (vaddr) & arch.AddressMask
memoryTracker.TrackMemAccess(effAddr)
mem := memory.GetWord(effAddr)
// Extract a sub-word based on the low-order bits in addr
dataMask, bitOffset, bitLength := calculateSubWordMaskAndOffset(addr, byteLength)
retVal := (mem >> bitOffset) & dataMask
if signExtend {
retVal = SignExtend(retVal, bitLength)
}
return retVal
return SelectSubWord(vaddr, mem, byteLength, signExtend)
}
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
effAddr := (addr) & arch.AddressMask
effAddr := (vaddr) & arch.AddressMask
memoryTracker.TrackMemAccess(effAddr)
mem := memory.GetWord(effAddr)
// 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
memUpdateMask := dataMask << bitOffset
newMemVal := subWordValue<<bitOffset | (^memUpdateMask)&mem
memory.SetWord(effAddr, newMemVal)
return subWordValue<<bitOffset | (^memUpdateMask)&memWord
}
func calculateSubWordMaskAndOffset(addr Word, byteLength Word) (dataMask, bitOffset, bitLength Word) {
func calculateSubWordMaskAndOffset(vaddr Word, byteLength Word) (dataMask, bitOffset, bitLength Word) {
bitLength = byteLength << 3
dataMask = ^Word(0) >> (arch.WordSize - bitLength)
// Figure out sub-word index based on the low-order bits in addr
byteIndexMask := addr & arch.ExtMask & ^(byteLength - 1)
// Figure out sub-word index based on the low-order bits in vaddr
byteIndexMask := vaddr & arch.ExtMask & ^(byteLength - 1)
maxByteShift := arch.WordSizeBytes - byteLength
byteIndex := addr & byteIndexMask
byteIndex := vaddr & byteIndexMask
bitOffset = (maxByteShift - byteIndex) << 3
return dataMask, bitOffset, bitLength
......
......@@ -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 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=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=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=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=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=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=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=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: "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=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=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=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: "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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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), 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=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 @@
"sourceCodeHash": "0x0fa0633a769e73f5937514c0003ba7947a1c275bbe5b85d78879c42f0ed8895b"
},
"src/cannon/MIPS.sol": {
"initCodeHash": "0x696c3ce334c11d0f9633945babac22b1b65848ff00d2cf6c4cb18116bbf138b2",
"sourceCodeHash": "0x3c2e5d6d39b29a60dcd1a776363518c87fcfef9a8d80e38696f56b6eec5bd53a"
"initCodeHash": "0x94f2e8f7818a990c009cccb501216a7f6df29b05d8f178cfff10a40288bf588e",
"sourceCodeHash": "0x786d4947488a771a426cc38de307ae99b2c2af1efca38b7655c60be7c019371f"
},
"src/cannon/MIPS2.sol": {
"initCodeHash": "0x5c292882075bd06e68b89119be9096040bc913f51bb878ce4a9dfdd674330dd5",
"sourceCodeHash": "0x17c7b0edb9d20932eaf1b038e3e05e457f0461d2c8691ba1940fb4c2b0dfd123"
"initCodeHash": "0x3744036fa240c7d57f39307c0bf27cb7027d05d6b4f52142d5122b6e538ee0b2",
"sourceCodeHash": "0x5f79a0f99a288d570df243ea9560e67a319d1685b3209ae457fc714a76ff2908"
},
"src/cannon/PreimageOracle.sol": {
"initCodeHash": "0x5d7e8ae64f802bd9d760e3d52c0a620bd02405dc2c8795818db9183792ffe81c",
......
......@@ -44,8 +44,8 @@ contract MIPS is ISemver {
}
/// @notice The semantic version of the MIPS contract.
/// @custom:semver 1.2.1-beta.5
string public constant version = "1.2.1-beta.5";
/// @custom:semver 1.2.1-beta.6
string public constant version = "1.2.1-beta.6";
/// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE;
......
......@@ -60,8 +60,8 @@ contract MIPS2 is ISemver {
}
/// @notice The semantic version of the MIPS2 contract.
/// @custom:semver 1.0.0-beta.18
string public constant version = "1.0.0-beta.18";
/// @custom:semver 1.0.0-beta.19
string public constant version = "1.0.0-beta.19";
/// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE;
......
......@@ -379,11 +379,11 @@ library MIPSInstructions {
}
// lb
else if (_opcode == 0x20) {
return signExtend((_mem >> (24 - (_rs & 3) * 8)) & 0xFF, 8);
return selectSubWord(_rs, _mem, 1, true);
}
// lh
else if (_opcode == 0x21) {
return signExtend((_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF, 16);
return selectSubWord(_rs, _mem, 2, true);
}
// lwl
else if (_opcode == 0x22) {
......@@ -393,15 +393,15 @@ library MIPSInstructions {
}
// lw
else if (_opcode == 0x23) {
return _mem;
return selectSubWord(_rs, _mem, 4, true);
}
// lbu
else if (_opcode == 0x24) {
return (_mem >> (24 - (_rs & 3) * 8)) & 0xFF;
return selectSubWord(_rs, _mem, 1, false);
}
// lhu
else if (_opcode == 0x25) {
return (_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF;
return selectSubWord(_rs, _mem, 2, false);
}
// lwr
else if (_opcode == 0x26) {
......@@ -411,15 +411,11 @@ library MIPSInstructions {
}
// sb
else if (_opcode == 0x28) {
uint32 val = (_rt & 0xFF) << (24 - (_rs & 3) * 8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFF << (24 - (_rs & 3) * 8));
return (_mem & mask) | val;
return updateSubWord(_rs, _mem, 1, _rt);
}
// sh
else if (_opcode == 0x29) {
uint32 val = (_rt & 0xFFFF) << (16 - (_rs & 2) * 8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFFFF << (16 - (_rs & 2) * 8));
return (_mem & mask) | val;
return updateSubWord(_rs, _mem, 2, _rt);
}
// swl
else if (_opcode == 0x2a) {
......@@ -429,7 +425,7 @@ library MIPSInstructions {
}
// sw
else if (_opcode == 0x2b) {
return _rt;
return updateSubWord(_rs, _mem, 4, _rt);
}
// swr
else if (_opcode == 0x2e) {
......@@ -667,4 +663,69 @@ library MIPSInstructions {
_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