Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MT Cannon: add cannon load/store opcodes tests #12196

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions cannon/mipsevm/tests/evm_common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,75 @@ func TestEVMSingleStep_Operators(t *testing.T) {
}
}

func TestEVMSingleStep_LoadStore(t *testing.T) {
var tracer *tracing.Hooks

versions := GetMipsVersionTestCases(t)
cases := []struct {
name string
rs uint32
rt uint32
isUnAligned bool
opcode uint32
memVal uint32
expectMemVal uint32
expectRes uint32
}{
{name: "lb", opcode: uint32(0x20), memVal: uint32(0x12_00_00_00), expectRes: uint32(0x12)}, // lb $t0, 4($t1)
{name: "lh", opcode: uint32(0x21), memVal: uint32(0x12_23_00_00), expectRes: uint32(0x12_23)}, // lh $t0, 4($t1)
{name: "lw", opcode: uint32(0x23), memVal: uint32(0x12_23_45_67), expectRes: uint32(0x12_23_45_67)}, // lw $t0, 4($t1)
{name: "lbu", opcode: uint32(0x24), memVal: uint32(0x12_23_00_00), expectRes: uint32(0x12)}, // lbu $t0, 4($t1)
{name: "lhu", opcode: uint32(0x25), memVal: uint32(0x12_23_00_00), expectRes: uint32(0x12_23)}, // lhu $t0, 4($t1)
{name: "lwl", opcode: uint32(0x22), rt: uint32(0xaa_bb_cc_dd), memVal: uint32(0x12_34_56_78), expectRes: uint32(0x12_34_56_78)}, // lwl $t0, 4($t1)
{name: "lwl unaligned address", opcode: uint32(0x22), rt: uint32(0xaa_bb_cc_dd), isUnAligned: true, memVal: uint32(0x12_34_56_78), expectRes: uint32(0x34_56_78_dd)}, // lwl $t0, 5($t1)
{name: "lwr", opcode: uint32(0x26), rt: uint32(0xaa_bb_cc_dd), memVal: uint32(0x12_34_56_78), expectRes: uint32(0xaa_bb_cc_12)}, // lwr $t0, 4($t1)
{name: "lwr unaligned address", opcode: uint32(0x26), rt: uint32(0xaa_bb_cc_dd), isUnAligned: true, memVal: uint32(0x12_34_56_78), expectRes: uint32(0xaa_bb_12_34)}, // lwr $t0, 5($t1)
{name: "sb", opcode: uint32(0x28), rt: uint32(0xaa_bb_cc_dd), expectRes: uint32(0xaa_bb_cc_dd), expectMemVal: uint32(0xdd_00_00_00)}, // sb $t0, 4($t1)
{name: "sh", opcode: uint32(0x29), rt: uint32(0xaa_bb_cc_dd), expectRes: uint32(0xaa_bb_cc_dd), expectMemVal: uint32(0xcc_dd_00_00)}, // sh $t0, 4($t1)
{name: "swl", opcode: uint32(0x2a), rt: uint32(0xaa_bb_cc_dd), expectRes: uint32(0xaa_bb_cc_dd), expectMemVal: uint32(0xaa_bb_cc_dd)}, // swl $t0, 4($t1)
{name: "sw", opcode: uint32(0x2b), rt: uint32(0xaa_bb_cc_dd), expectRes: uint32(0xaa_bb_cc_dd), expectMemVal: uint32(0xaa_bb_cc_dd)}, // sw $t0, 4($t1)
{name: "swr unaligned address", opcode: uint32(0x2e), rt: uint32(0xaa_bb_cc_dd), isUnAligned: true, expectRes: uint32(0xaa_bb_cc_dd), expectMemVal: uint32(0xcc_dd_00_00)}, // swr $t0, 5($t1)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Store operations don't write back to a register, so I'd suggest cutting the expectedRes value for these, and only setting an expectation on the return register iff we have a value for expectedRes.


var t1 uint32 = 0x100
for _, v := range versions {
for i, tt := range cases {
testName := fmt.Sprintf("%v (%v)", tt.name, v.Name)
t.Run(testName, func(t *testing.T) {
goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(0), testutil.WithNextPC(4))
state := goVm.GetState()
var insn uint32
imm := uint32(0x4)
if tt.isUnAligned {
imm = uint32(0x5)
}

insn = tt.opcode<<26 | uint32(9)<<21 | uint32(8)<<16 | imm
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) For clarity, would be helpful to replace the magic numbers here with variables, something like:

Suggested change
insn = tt.opcode<<26 | uint32(9)<<21 | uint32(8)<<16 | imm
insn = tt.opcode<<26 | uint32(baseReg)<<21 | uint32(rtReg)<<16 | imm

state.GetRegistersRef()[8] = tt.rt
state.GetRegistersRef()[9] = t1

state.GetMemory().SetMemory(0, insn)
state.GetMemory().SetMemory(t1+4, tt.memVal)
step := state.GetStep()

// Setup expectations
expected := testutil.NewExpectedState(state)
expected.ExpectStep()
expected.Registers[8] = tt.expectRes
if tt.expectMemVal != 0 {
expected.ExpectMemoryWrite(t1+4, tt.expectMemVal)
}
stepWitness, err := goVm.Step(true)
require.NoError(t, err)

// Check expectations
expected.Validate(t, state)
testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer)
})
}
}
}

func TestEVM_MMap(t *testing.T) {
var tracer *tracing.Hooks

Expand Down