Commit 4af15d02 authored by Inphi's avatar Inphi Committed by GitHub

cannon: Refactor ALU execution (#6868)

* cannon: Refactor ALU execution

Reduce cyclomatic complexity of Go and Solidity MIPS VMs.
This has minimal effect on runtime. Though better gas savings in
Solidity.

* Make Go and Solidity MIPS VMs more similar
parent 875bac3c
...@@ -395,12 +395,10 @@ func (m *InstrumentedState) mipsStep() error { ...@@ -395,12 +395,10 @@ func (m *InstrumentedState) mipsStep() error {
func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 { func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
opcode := insn >> 26 // 6-bits opcode := insn >> 26 // 6-bits
fun := insn & 0x3f // 6-bits
if opcode < 0x20 { if opcode == 0 || (opcode >= 8 && opcode < 0xF) {
// transform ArithLogI fun := insn & 0x3f // 6-bits
// TODO(CLI-4136): replace with table // transform ArithLogI to SPECIAL
if opcode >= 8 && opcode < 0xF {
switch opcode { switch opcode {
case 8: case 8:
fun = 0x20 // addi fun = 0x20 // addi
...@@ -417,65 +415,90 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 { ...@@ -417,65 +415,90 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
case 0xE: case 0xE:
fun = 0x26 // xori fun = 0x26 // xori
} }
opcode = 0
}
// 0 is opcode SPECIAL
if opcode == 0 {
shamt := (insn >> 6) & 0x1F
if fun < 0x20 {
switch {
case fun >= 0x08:
return rs // jr/jalr/div + others
case fun == 0x00:
return rt << shamt // sll
case fun == 0x02:
return rt >> shamt // srl
case fun == 0x03:
return SE(rt>>shamt, 32-shamt) // sra
case fun == 0x04:
return rt << (rs & 0x1F) // sllv
case fun == 0x06:
return rt >> (rs & 0x1F) // srlv
case fun == 0x07:
return SE(rt>>rs, 32-rs) // srav
}
}
// 0x10-0x13 = mfhi, mthi, mflo, mtlo
// R-type (ArithLog)
switch fun { switch fun {
case 0x20, 0x21: case 0x00: // sll
return rs + rt // add or addu return rt << ((insn >> 6) & 0x1F)
case 0x22, 0x23: case 0x02: // srl
return rs - rt // sub or subu return rt >> ((insn >> 6) & 0x1F)
case 0x24: case 0x03: // sra
return rs & rt // and shamt := (insn >> 6) & 0x1F
case 0x25: return SE(rt>>shamt, 32-shamt)
return rs | rt // or case 0x04: // sllv
case 0x26: return rt << (rs & 0x1F)
return rs ^ rt // xor case 0x06: // srlv
case 0x27: return rt >> (rs & 0x1F)
return ^(rs | rt) // nor case 0x07: // srav
case 0x2A: return SE(rt>>rs, 32-rs)
// functs in range [0x8, 0x1b] are handled specially by other functions
case 0x08: // jr
return rs
case 0x09: // jalr
return rs
case 0x0a: // movz
return rs
case 0x0b: // movn
return rs
case 0x0c: // syscall
return rs
// 0x0d - break not supported
case 0x0f: // sync
return rs
case 0x10: // mfhi
return rs
case 0x11: // mthi
return rs
case 0x12: // mflo
return rs
case 0x13: // mtlo
return rs
case 0x18: // mult
return rs
case 0x19: // multu
return rs
case 0x1a: // div
return rs
case 0x1b: // divu
return rs
// The rest includes transformed R-type arith imm instructions
case 0x20: // add
return rs + rt
case 0x21: // addu
return rs + rt
case 0x22: // sub
return rs - rt
case 0x23: // subu
return rs - rt
case 0x24: // and
return rs & rt
case 0x25: // or
return rs | rt
case 0x26: // xor
return rs ^ rt
case 0x27: // nor
return ^(rs | rt)
case 0x2a: // slti
if int32(rs) < int32(rt) { if int32(rs) < int32(rt) {
return 1 // slt return 1
} else {
return 0
} }
case 0x2B:
if rs < rt {
return 1 // sltu
} else {
return 0 return 0
case 0x2b: // sltiu
if rs < rt {
return 1
} }
return 0
default:
panic("invalid instruction")
} }
} else if opcode == 0xF { } else {
return rt << 16 // lui switch opcode {
} else if opcode == 0x1C { // SPECIAL2 // SPECIAL2
if fun == 2 { // mul case 0x1C:
fun := insn & 0x3f // 6-bits
switch fun {
case 0x2: // mul
return uint32(int32(rs) * int32(rt)) return uint32(int32(rs) * int32(rt))
} case 0x20, 0x21: // clo
if fun == 0x20 || fun == 0x21 { // clo
if fun == 0x20 { if fun == 0x20 {
rs = ^rs rs = ^rs
} }
...@@ -485,9 +508,8 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 { ...@@ -485,9 +508,8 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
} }
return i return i
} }
} case 0x0F: // lui
} else if opcode < 0x28 { return rt << 16
switch opcode {
case 0x20: // lb case 0x20: // lb
return SE((mem>>(24-(rs&3)*8))&0xFF, 8) return SE((mem>>(24-(rs&3)*8))&0xFF, 8)
case 0x21: // lh case 0x21: // lh
...@@ -506,31 +528,32 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 { ...@@ -506,31 +528,32 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
val := mem >> (24 - (rs&3)*8) val := mem >> (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8) mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8)
return (rt & ^mask) | val return (rt & ^mask) | val
} case 0x28: // sb
} else if opcode == 0x28 { // sb
val := (rt & 0xFF) << (24 - (rs&3)*8) val := (rt & 0xFF) << (24 - (rs&3)*8)
mask := 0xFFFFFFFF ^ uint32(0xFF<<(24-(rs&3)*8)) mask := 0xFFFFFFFF ^ uint32(0xFF<<(24-(rs&3)*8))
return (mem & mask) | val return (mem & mask) | val
} else if opcode == 0x29 { // sh case 0x29: // sh
val := (rt & 0xFFFF) << (16 - (rs&2)*8) val := (rt & 0xFFFF) << (16 - (rs&2)*8)
mask := 0xFFFFFFFF ^ uint32(0xFFFF<<(16-(rs&2)*8)) mask := 0xFFFFFFFF ^ uint32(0xFFFF<<(16-(rs&2)*8))
return (mem & mask) | val return (mem & mask) | val
} else if opcode == 0x2a { // swl case 0x2a: // swl
val := rt >> ((rs & 3) * 8) val := rt >> ((rs & 3) * 8)
mask := uint32(0xFFFFFFFF) >> ((rs & 3) * 8) mask := uint32(0xFFFFFFFF) >> ((rs & 3) * 8)
return (mem & ^mask) | val return (mem & ^mask) | val
} else if opcode == 0x2b { // sw case 0x2b: // sw
return rt return rt
} else if opcode == 0x2e { // swr case 0x2e: // swr
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)
return (mem & ^mask) | val return (mem & ^mask) | val
} else if opcode == 0x30 { case 0x30: // ll
return mem // ll return mem
} else if opcode == 0x38 { case 0x38: // sc
return rt // sc return rt
default:
panic("invalid instruction")
}
} }
panic("invalid instruction") panic("invalid instruction")
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -298,12 +298,13 @@ LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957) ...@@ -298,12 +298,13 @@ LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957)
LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755) LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755)
LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524) LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524)
LibPosition_Test:test_pos_correctness_succeeds() (gas: 38689) LibPosition_Test:test_pos_correctness_succeeds() (gas: 38689)
MIPS_Test:test_add_succeeds() (gas: 121593) MIPS_Test:test_add_succeeds() (gas: 122197)
MIPS_Test:test_addi_succeeds() (gas: 121918) MIPS_Test:test_addiSign_succeeds() (gas: 122188)
MIPS_Test:test_addu_succeeds() (gas: 121601) MIPS_Test:test_addi_succeeds() (gas: 122385)
MIPS_Test:test_addui_succeeds() (gas: 121975) MIPS_Test:test_addu_succeeds() (gas: 122239)
MIPS_Test:test_and_succeeds() (gas: 121650) MIPS_Test:test_addui_succeeds() (gas: 122447)
MIPS_Test:test_andi_succeeds() (gas: 121792) MIPS_Test:test_and_succeeds() (gas: 122258)
MIPS_Test:test_andi_succeeds() (gas: 122191)
MIPS_Test:test_beq_succeeds() (gas: 202355) MIPS_Test:test_beq_succeeds() (gas: 202355)
MIPS_Test:test_bgez_succeeds() (gas: 121484) MIPS_Test:test_bgez_succeeds() (gas: 121484)
MIPS_Test:test_bgtz_succeeds() (gas: 121405) MIPS_Test:test_bgtz_succeeds() (gas: 121405)
...@@ -311,67 +312,67 @@ MIPS_Test:test_blez_succeeds() (gas: 121361) ...@@ -311,67 +312,67 @@ MIPS_Test:test_blez_succeeds() (gas: 121361)
MIPS_Test:test_bltz_succeeds() (gas: 121504) MIPS_Test:test_bltz_succeeds() (gas: 121504)
MIPS_Test:test_bne_succeeds() (gas: 121570) MIPS_Test:test_bne_succeeds() (gas: 121570)
MIPS_Test:test_branch_inDelaySlot_fails() (gas: 85999) MIPS_Test:test_branch_inDelaySlot_fails() (gas: 85999)
MIPS_Test:test_brk_succeeds() (gas: 121531) MIPS_Test:test_brk_succeeds() (gas: 121869)
MIPS_Test:test_clo_succeeds() (gas: 121991) MIPS_Test:test_clo_succeeds() (gas: 121926)
MIPS_Test:test_clone_succeeds() (gas: 121484) MIPS_Test:test_clone_succeeds() (gas: 121822)
MIPS_Test:test_clz_succeeds() (gas: 122462) MIPS_Test:test_clz_succeeds() (gas: 122397)
MIPS_Test:test_div_succeeds() (gas: 121806) MIPS_Test:test_div_succeeds() (gas: 122376)
MIPS_Test:test_divu_succeeds() (gas: 121762) MIPS_Test:test_divu_succeeds() (gas: 122361)
MIPS_Test:test_exit_succeeds() (gas: 121408) MIPS_Test:test_exit_succeeds() (gas: 121746)
MIPS_Test:test_fcntl_succeeds() (gas: 203129) MIPS_Test:test_fcntl_succeeds() (gas: 203827)
MIPS_Test:test_illegal_instruction_fails() (gas: 91175) MIPS_Test:test_illegal_instruction_fails() (gas: 91462)
MIPS_Test:test_invalid_root_fails() (gas: 435678) MIPS_Test:test_invalid_root_fails() (gas: 435636)
MIPS_Test:test_jal_nonzeroRegion_succeeds() (gas: 120492) MIPS_Test:test_jal_nonzeroRegion_succeeds() (gas: 120514)
MIPS_Test:test_jal_succeeds() (gas: 120481) MIPS_Test:test_jal_succeeds() (gas: 120503)
MIPS_Test:test_jalr_succeeds() (gas: 121349) MIPS_Test:test_jalr_succeeds() (gas: 121622)
MIPS_Test:test_jr_succeeds() (gas: 121094) MIPS_Test:test_jr_succeeds() (gas: 121316)
MIPS_Test:test_jump_inDelaySlot_fails() (gas: 85345) MIPS_Test:test_jump_inDelaySlot_fails() (gas: 85367)
MIPS_Test:test_jump_nonzeroRegion_succeeds() (gas: 120236) MIPS_Test:test_jump_nonzeroRegion_succeeds() (gas: 120258)
MIPS_Test:test_jump_succeeds() (gas: 120188) MIPS_Test:test_jump_succeeds() (gas: 120188)
MIPS_Test:test_lb_succeeds() (gas: 127346) MIPS_Test:test_lb_succeeds() (gas: 127429)
MIPS_Test:test_lbu_succeeds() (gas: 127222) MIPS_Test:test_lbu_succeeds() (gas: 127327)
MIPS_Test:test_lh_succeeds() (gas: 127367) MIPS_Test:test_lh_succeeds() (gas: 127450)
MIPS_Test:test_lhu_succeeds() (gas: 127284) MIPS_Test:test_lhu_succeeds() (gas: 127367)
MIPS_Test:test_ll_succeeds() (gas: 127304) MIPS_Test:test_ll_succeeds() (gas: 127589)
MIPS_Test:test_lui_succeeds() (gas: 121488) MIPS_Test:test_lui_succeeds() (gas: 121470)
MIPS_Test:test_lw_succeeds() (gas: 127158) MIPS_Test:test_lw_succeeds() (gas: 127218)
MIPS_Test:test_lwl_succeeds() (gas: 241434) MIPS_Test:test_lwl_succeeds() (gas: 241600)
MIPS_Test:test_lwr_succeeds() (gas: 241722) MIPS_Test:test_lwr_succeeds() (gas: 241888)
MIPS_Test:test_mfhi_succeeds() (gas: 121458) MIPS_Test:test_mfhi_succeeds() (gas: 121831)
MIPS_Test:test_mflo_succeeds() (gas: 121484) MIPS_Test:test_mflo_succeeds() (gas: 121960)
MIPS_Test:test_mmap_succeeds() (gas: 118451) MIPS_Test:test_mmap_succeeds() (gas: 118789)
MIPS_Test:test_movn_succeeds() (gas: 202409) MIPS_Test:test_movn_succeeds() (gas: 203027)
MIPS_Test:test_movz_succeeds() (gas: 202313) MIPS_Test:test_movz_succeeds() (gas: 202895)
MIPS_Test:test_mthi_succeeds() (gas: 121450) MIPS_Test:test_mthi_succeeds() (gas: 121875)
MIPS_Test:test_mtlo_succeeds() (gas: 121478) MIPS_Test:test_mtlo_succeeds() (gas: 121983)
MIPS_Test:test_mul_succeeds() (gas: 121563) MIPS_Test:test_mul_succeeds() (gas: 121475)
MIPS_Test:test_mult_succeeds() (gas: 121667) MIPS_Test:test_mult_succeeds() (gas: 122179)
MIPS_Test:test_multu_succeeds() (gas: 121675) MIPS_Test:test_multu_succeeds() (gas: 122216)
MIPS_Test:test_nor_succeeds() (gas: 121697) MIPS_Test:test_nor_succeeds() (gas: 122308)
MIPS_Test:test_or_succeeds() (gas: 121657) MIPS_Test:test_or_succeeds() (gas: 122265)
MIPS_Test:test_ori_succeeds() (gas: 121865) MIPS_Test:test_ori_succeeds() (gas: 122268)
MIPS_Test:test_preimage_read_succeeds() (gas: 233847) MIPS_Test:test_preimage_read_succeeds() (gas: 234185)
MIPS_Test:test_preimage_write_succeeds() (gas: 126473) MIPS_Test:test_preimage_write_succeeds() (gas: 126811)
MIPS_Test:test_prestate_exited_succeeds() (gas: 112992) MIPS_Test:test_prestate_exited_succeeds() (gas: 112992)
MIPS_Test:test_sb_succeeds() (gas: 159993) MIPS_Test:test_sb_succeeds() (gas: 160300)
MIPS_Test:test_sc_succeeds() (gas: 160187) MIPS_Test:test_sc_succeeds() (gas: 160494)
MIPS_Test:test_sh_succeeds() (gas: 160052) MIPS_Test:test_sh_succeeds() (gas: 160337)
MIPS_Test:test_sll_succeeds() (gas: 121456) MIPS_Test:test_sll_succeeds() (gas: 121436)
MIPS_Test:test_sllv_succeeds() (gas: 121646) MIPS_Test:test_sllv_succeeds() (gas: 121665)
MIPS_Test:test_slt_succeeds() (gas: 203266) MIPS_Test:test_slt_succeeds() (gas: 204222)
MIPS_Test:test_sltu_succeeds() (gas: 121871) MIPS_Test:test_sltu_succeeds() (gas: 122482)
MIPS_Test:test_sra_succeeds() (gas: 121763) MIPS_Test:test_sra_succeeds() (gas: 121687)
MIPS_Test:test_srav_succeeds() (gas: 121959) MIPS_Test:test_srav_succeeds() (gas: 121955)
MIPS_Test:test_srl_succeeds() (gas: 121514) MIPS_Test:test_srl_succeeds() (gas: 121518)
MIPS_Test:test_srlv_succeeds() (gas: 121707) MIPS_Test:test_srlv_succeeds() (gas: 121683)
MIPS_Test:test_step_abi_succeeds() (gas: 57876) MIPS_Test:test_step_abi_succeeds() (gas: 58312)
MIPS_Test:test_sub_succeeds() (gas: 121696) MIPS_Test:test_sub_succeeds() (gas: 122292)
MIPS_Test:test_subu_succeeds() (gas: 121659) MIPS_Test:test_subu_succeeds() (gas: 122289)
MIPS_Test:test_sw_succeeds() (gas: 160027) MIPS_Test:test_sw_succeeds() (gas: 160312)
MIPS_Test:test_swl_succeeds() (gas: 160088) MIPS_Test:test_swl_succeeds() (gas: 160373)
MIPS_Test:test_swr_succeeds() (gas: 160163) MIPS_Test:test_swr_succeeds() (gas: 160448)
MIPS_Test:test_xor_succeeds() (gas: 121685) MIPS_Test:test_xor_succeeds() (gas: 122293)
MIPS_Test:test_xori_succeeds() (gas: 121916) MIPS_Test:test_xori_succeeds() (gas: 122345)
MerkleTrie_get_Test:test_get_corruptedProof_reverts() (gas: 5733) MerkleTrie_get_Test:test_get_corruptedProof_reverts() (gas: 5733)
MerkleTrie_get_Test:test_get_extraProofElements_reverts() (gas: 58889) MerkleTrie_get_Test:test_get_extraProofElements_reverts() (gas: 58889)
MerkleTrie_get_Test:test_get_invalidDataRemainder_reverts() (gas: 35845) MerkleTrie_get_Test:test_get_invalidDataRemainder_reverts() (gas: 35845)
......
...@@ -67,7 +67,7 @@ contract MIPS { ...@@ -67,7 +67,7 @@ contract MIPS {
} }
/// @notice Extends the value leftwards with its most significant bit (sign extension). /// @notice Extends the value leftwards with its most significant bit (sign extension).
function SE(uint32 _dat, uint32 _idx) internal pure returns (uint32) { function SE(uint32 _dat, uint32 _idx) internal pure returns (uint32 out_) {
unchecked { unchecked {
bool isSigned = (_dat >> (_idx - 1)) != 0; bool isSigned = (_dat >> (_idx - 1)) != 0;
uint256 signed = ((1 << (32 - _idx)) - 1) << _idx; uint256 signed = ((1 << (32 - _idx)) - 1) << _idx;
...@@ -771,78 +771,135 @@ contract MIPS { ...@@ -771,78 +771,135 @@ contract MIPS {
} }
/// @notice Execute an instruction. /// @notice Execute an instruction.
function execute(uint32 insn, uint32 rs, uint32 rt, uint32 mem) internal pure returns (uint32) { function execute(uint32 insn, uint32 rs, uint32 rt, uint32 mem) internal pure returns (uint32 out) {
unchecked { unchecked {
uint32 opcode = insn >> 26; // 6-bits uint32 opcode = insn >> 26; // 6-bits
uint32 func = insn & 0x3f; // 6-bits
if (opcode < 0x20) {
// transform ArithLogI
// TODO(CLI-4136): replace with table
if (opcode >= 8 && opcode < 0xF) {
if (opcode == 8) func = 0x20; // addi
else if (opcode == 9) func = 0x21; // addiu
else if (opcode == 0xa) func = 0x2a; // slti
else if (opcode == 0xb) func = 0x2B; // sltiu if (opcode == 0 || (opcode >= 8 && opcode < 0xF)) {
uint32 func = insn & 0x3f; // 6-bits
else if (opcode == 0xc) func = 0x24; // andi assembly {
// transform ArithLogI to SPECIAL
else if (opcode == 0xd) func = 0x25; // ori switch opcode
// addi
else if (opcode == 0xe) func = 0x26; // xori case 0x8 { func := 0x20 }
opcode = 0; // addiu
} case 0x9 { func := 0x21 }
// stli
// 0 is opcode SPECIAL case 0xA { func := 0x2A }
if (opcode == 0) { // sltiu
uint32 shamt = (insn >> 6) & 0x1f; case 0xB { func := 0x2B }
if (func < 0x20) { // andi
// jr/jalr/div + others case 0xC { func := 0x24 }
if (func >= 0x08) { // ori
return rs; case 0xD { func := 0x25 }
} // xori
// sll: Logical Shift Left case 0xE { func := 0x26 }
else if (func == 0x00) { }
return rt << shamt;
} // sll
// srl: Logical Shift Right if (func == 0x00) {
return rt << ((insn >> 6) & 0x1F);
}
// srl
else if (func == 0x02) { else if (func == 0x02) {
return rt >> shamt; return rt >> ((insn >> 6) & 0x1F);
} }
// sra: Arithmetic Shift Right // sra
else if (func == 0x03) { else if (func == 0x03) {
uint32 shamt = (insn >> 6) & 0x1F;
return SE(rt >> shamt, 32 - shamt); return SE(rt >> shamt, 32 - shamt);
} }
// sllv: Variable Logical Shift Left // sllv
else if (func == 0x04) { else if (func == 0x04) {
return rt << (rs & 0x1F); return rt << (rs & 0x1F);
} }
// srlv: Variable Logical Shift Right // srlv
else if (func == 0x06) { else if (func == 0x6) {
return rt >> (rs & 0x1F); return rt >> (rs & 0x1F);
} }
// srav: Variable Arithmetic Shift Right // srav
else if (func == 0x07) { else if (func == 0x07) {
return SE(rt >> rs, 32 - rs); return SE(rt >> rs, 32 - rs);
} }
// functs in range [0x8, 0x1b] are handled specially by other functions
// Explicitly enumerate each funct in range to reduce code diff against Go Vm
// jr
else if (func == 0x08) {
return rs;
}
// jalr
else if (func == 0x09) {
return rs;
} }
// movz
// R-type (ArithLog) else if (func == 0x0a) {
// 0x10-0x13 = mfhi, mthi, mflo, mtlo return rs;
// add or addu }
if (func == 0x20 || func == 0x21) { // movn
return rs + rt; else if (func == 0x0b) {
return rs;
}
// syscall
else if (func == 0x0c) {
return rs;
}
// 0x0d - break not supported
// sync
else if (func == 0x0f) {
return rs;
}
// mfhi
else if (func == 0x10) {
return rs;
}
// mthi
else if (func == 0x11) {
return rs;
}
// mflo
else if (func == 0x12) {
return rs;
}
// mtlo
else if (func == 0x13) {
return rs;
}
// mult
else if (func == 0x18) {
return rs;
}
// multu
else if (func == 0x19) {
return rs;
}
// div
else if (func == 0x1a) {
return rs;
}
// divu
else if (func == 0x1b) {
return rs;
}
// The rest includes transformed R-type arith imm instructions
// add
else if (func == 0x20) {
return (rs + rt);
}
// addu
else if (func == 0x21) {
return (rs + rt);
} }
// sub or subu // sub
else if (func == 0x22 || func == 0x23) { else if (func == 0x22) {
return rs - rt; return (rs - rt);
}
// subu
else if (func == 0x23) {
return (rs - rt);
} }
// and // and
else if (func == 0x24) { else if (func == 0x24) {
return rs & rt; return (rs & rt);
} }
// or // or
else if (func == 0x25) { else if (func == 0x25) {
...@@ -856,27 +913,26 @@ contract MIPS { ...@@ -856,27 +913,26 @@ contract MIPS {
else if (func == 0x27) { else if (func == 0x27) {
return ~(rs | rt); return ~(rs | rt);
} }
// slt: Set to 1 if less than // slti
else if (func == 0x2a) { else if (func == 0x2a) {
return int32(rs) < int32(rt) ? 1 : 0; return int32(rs) < int32(rt) ? 1 : 0;
} }
// sltu: Set to 1 if less than unsigned // sltiu
else if (func == 0x2B) { else if (func == 0x2b) {
return rs < rt ? 1 : 0; return rs < rt ? 1 : 0;
} else {
revert("invalid instruction");
} }
} } else {
// lui: Load Upper Immediate
else if (opcode == 0xf) {
return rt << 16;
}
// SPECIAL2 // SPECIAL2
else if (opcode == 0x1c) { if (opcode == 0x1C) {
uint32 func = insn & 0x3f; // 6-bits
// mul // mul
if (func == 2) { if (func == 0x2) {
return uint32(int32(rs) * int32(rt)); return uint32(int32(rs) * int32(rt));
} }
// clo // clz, clo
if (func == 0x20 || func == 0x21) { else if (func == 0x20 || func == 0x21) {
if (func == 0x20) { if (func == 0x20) {
rs = ~rs; rs = ~rs;
} }
...@@ -888,9 +944,12 @@ contract MIPS { ...@@ -888,9 +944,12 @@ contract MIPS {
return i; return i;
} }
} }
} else if (opcode < 0x28) { // lui
else if (opcode == 0x0F) {
return rt << 16;
}
// lb // lb
if (opcode == 0x20) { else if (opcode == 0x20) {
return SE((mem >> (24 - (rs & 3) * 8)) & 0xFF, 8); return SE((mem >> (24 - (rs & 3) * 8)) & 0xFF, 8);
} }
// lh // lh
...@@ -921,7 +980,6 @@ contract MIPS { ...@@ -921,7 +980,6 @@ contract MIPS {
uint32 mask = uint32(0xFFFFFFFF) >> (24 - (rs & 3) * 8); uint32 mask = uint32(0xFFFFFFFF) >> (24 - (rs & 3) * 8);
return (rt & ~mask) | val; return (rt & ~mask) | val;
} }
}
// sb // sb
else if (opcode == 0x28) { else if (opcode == 0x28) {
uint32 val = (rt & 0xFF) << (24 - (rs & 3) * 8); uint32 val = (rt & 0xFF) << (24 - (rs & 3) * 8);
...@@ -957,8 +1015,10 @@ contract MIPS { ...@@ -957,8 +1015,10 @@ contract MIPS {
// sc // sc
else if (opcode == 0x38) { else if (opcode == 0x38) {
return rt; return rt;
} else {
revert("invalid instruction");
}
} }
revert("invalid instruction"); revert("invalid instruction");
} }
} }
......
...@@ -102,6 +102,26 @@ contract MIPS_Test is CommonTest { ...@@ -102,6 +102,26 @@ contract MIPS_Test is CommonTest {
assertEq(postState, outputState(expect), "unexpected post state"); assertEq(postState, outputState(expect), "unexpected post state");
} }
function test_addiSign_succeeds() external {
uint16 imm = 0xfffe; // -2
uint32 insn = encodeitype(0x8, 17, 8, imm); // addi t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 2; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_addui_succeeds() external { function test_addui_succeeds() external {
uint16 imm = 40; uint16 imm = 40;
uint32 insn = encodeitype(0x9, 17, 8, imm); // addui t0, s1, 40 uint32 insn = encodeitype(0x9, 17, 8, imm); // addui t0, s1, 40
...@@ -305,15 +325,15 @@ contract MIPS_Test is CommonTest { ...@@ -305,15 +325,15 @@ contract MIPS_Test is CommonTest {
function test_slt_succeeds() external { function test_slt_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x2a); // slt t0, s1, s2 uint32 insn = encodespec(17, 18, 8, 0x2a); // slt t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0); (MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200; state.registers[17] = 0xFF_FF_FF_FE; // -2
state.registers[18] = 490; state.registers[18] = 5;
MIPS.State memory expect; MIPS.State memory expect;
expect.memRoot = state.memRoot; expect.memRoot = state.memRoot;
expect.pc = state.nextPC; expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4; expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1; expect.step = state.step + 1;
expect.registers[8] = state.registers[17] < state.registers[18] ? 1 : 0; // t0 expect.registers[8] = 1; // t0
expect.registers[17] = state.registers[17]; expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18]; expect.registers[18] = state.registers[18];
...@@ -326,7 +346,7 @@ contract MIPS_Test is CommonTest { ...@@ -326,7 +346,7 @@ contract MIPS_Test is CommonTest {
state.registers[18] = tmp; state.registers[18] = tmp;
expect.registers[17] = state.registers[17]; expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18]; expect.registers[18] = state.registers[18];
expect.registers[8] = state.registers[17] < state.registers[18] ? 1 : 0; // t0 expect.registers[8] = 0; // t0
postState = mips.step(encodeState(state), proof); postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state"); assertEq(postState, outputState(expect), "unexpected post state");
} }
...@@ -1127,14 +1147,14 @@ contract MIPS_Test is CommonTest { ...@@ -1127,14 +1147,14 @@ contract MIPS_Test is CommonTest {
uint8 shiftamt = 4; uint8 shiftamt = 4;
uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6 | 3); // sra t0, t1, 3 uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6 | 3); // sra t0, t1, 3
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0); (MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1 state.registers[9] = 0x80_00_00_20; // t1
MIPS.State memory expect; MIPS.State memory expect;
expect.memRoot = state.memRoot; expect.memRoot = state.memRoot;
expect.pc = state.nextPC; expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4; expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1; expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> shiftamt; expect.registers[8] = 0xF8_00_00_02; // 4 shifts while preserving sign bit
expect.registers[9] = state.registers[9]; expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state); bytes memory enc = encodeState(state);
......
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