Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ed21d40
cannon: mipsevm: Implement rotation instrs
pcw109550 Feb 12, 2025
8c37768
cannon: mipsevm: Implement SPECIAL3 instrs
pcw109550 Feb 12, 2025
dac5f08
cannon: mipsevm: Store logic for SPECIAL3 instrs
pcw109550 Feb 13, 2025
45bdea2
cannon: mipsevm: Implement SPECIAL3 instrs + dclz
pcw109550 Feb 13, 2025
b6d2171
cannon: mipsevm: Store logic for SPECIAL3 instrs
pcw109550 Feb 13, 2025
0730f42
cannon: mipsevm: Style consistency
pcw109550 Feb 13, 2025
df45664
cannon: mipsevm: dclz tests and bugfix
pcw109550 Feb 13, 2025
653d3ac
cannon: mipsevm: drotr tests
pcw109550 Feb 14, 2025
42021a8
cannon: mipsevm: Fix store logic
pcw109550 Feb 14, 2025
99ae582
cannon: mipsevm: drotr32 tests
pcw109550 Feb 14, 2025
b91c9ea
cannon: mipsevm: drotrv tests
pcw109550 Feb 14, 2025
124fb9a
cannon: mipsevm: rotr, rotrv tests
pcw109550 Feb 14, 2025
113b14f
cannon: mipsevm: test style
pcw109550 Feb 14, 2025
142e831
cannon: mipsevm: dext, dextu, dextm tests
pcw109550 Feb 14, 2025
0a0639f
cannon: mipsevm: dins, dinsm, dinsu tests
pcw109550 Feb 14, 2025
4f187ac
cannon: mipsevm: Fix store logic
pcw109550 Feb 14, 2025
36c062e
cannon: mipsevm: dsbh, dshd tests
pcw109550 Feb 14, 2025
c0fc3ac
cannon: mipsevm: seb, seh tests
pcw109550 Feb 14, 2025
b3f9426
cannon: mipsevm: wsbh tests
pcw109550 Feb 14, 2025
3099ab0
cannon: mipsevm: ext tests
pcw109550 Feb 14, 2025
48315a8
cannon: mipsevm: fix ext instr impl
pcw109550 Feb 14, 2025
11bcf69
cannon: mipsevm: ins tests
pcw109550 Feb 14, 2025
ccf14c6
cannon: mipsevm: test style
pcw109550 Feb 14, 2025
9be0c81
cannon: mipsevm: remove comment
pcw109550 Feb 18, 2025
8f19be0
cannon: mipsevm: add comment for onchain mips64r2 impl
pcw109550 Feb 18, 2025
f7274b2
cannon: Update MIPS README for mips64r2
pcw109550 Feb 18, 2025
edcce94
cannon: mipsevm: handle signExtension for mips64r2 instrs for 32bit
pcw109550 Feb 18, 2025
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
19 changes: 19 additions & 0 deletions cannon/mipsevm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,22 @@ Supported 63 instructions:
| `Conditional Branch` | `bne` | Branch on not equal. |
| `Logical` | `clo` | Count leading ones. |
| `Logical` | `clz` | Count leading zeros. |
| `Logical` | `dclz` | Count Leading Zeros in Doubleword. |
| `Bit Manipulation` | `dext` | Doubleword Extract Bit Field. |
| `Bit Manipulation` | `dextm` | Doubleword Extract Bit Field Middle. |
| `Bit Manipulation` | `dextu` | Doubleword Extract Bit Field Upper. |
| `Bit Manipulation` | `dins` | Doubleword Insert Bit Field. |
| `Bit Manipulation` | `dinsm` | Doubleword Insert Bit Field Middle. |
| `Bit Manipulation` | `dinsu` | Doubleword Insert Bit Field Upper. |
| `Arithmetic` | `div` | Divide. |
| `Arithmetic` | `divu` | Divide unsigned. |
| `Logical` | `drotr` | Doubleword Rotate Right. |
| `Logical` | `drotr32` | Doubleword Rotate Right Plus 32. |
| `Logical` | `drotrv` | Doubleword Rotate Right Variable. |
| `Bit Manipulation` | `dsbh` | Doubleword Swap Bytes Within Halfwords. |
| `Bit Manipulation` | `dshd` | Doubleword Swap Halfwords Within Doublewords.|
| `Bit Manipulation` | `ext` | Extract Bit Field. |
| `Bit Manipulation` | `ins` | Insert Bit Field. |
| `Unconditional Jump` | `j` | Jump. |
| `Unconditional Jump` | `jal` | Jump and link. |
| `Unconditional Jump` | `jalr` | Jump and link register. |
Expand All @@ -46,8 +60,12 @@ Supported 63 instructions:
| `Logical` | `nor` | Bitwise NOR. |
| `Logical` | `or` | Bitwise OR. |
| `Logical` | `ori` | Bitwise OR immediate. |
| `Logical` | `rotr` | Rotate Word Right. |
| `Logical` | `rotrv` | Rotate Word Right Variable. |
| `Data Transfer` | `sb` | Store byte. |
| `Data Transfer` | `sc` | Store conditional. |
| `Arithmetic` | `seb` | Sign-Extend Byte. |
| `Arithmetic` | `seh` | Sign-Extend Halfword. |
| `Data Transfer` | `sh` | Store halfword. |
| `Logical` | `sll` | Shift left logical. |
| `Logical` | `sllv` | Shift left logical variable. |
Expand All @@ -66,6 +84,7 @@ Supported 63 instructions:
| `Data Transfer` | `swr` | Store word right. |
| `Serialization` | `sync` | Synchronize shared memory. |
| `System Calls` | `syscall` | System call. |
| `Bit Manipulation` | `wsbh` | Word Swap Bytes Within Halfwords. |
| `Logical` | `xor` | Bitwise XOR. |
| `Logical` | `xori` | Bitwise XOR immediate. |

Expand Down
146 changes: 131 additions & 15 deletions cannon/mipsevm/exec/mips_instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]Word, memory
// R-type (stores rd)
rt = registers[rtReg]
rdReg = Word((insn >> 11) & 0x1F)
} else if opcode == 0x1f { // SPECIAL3
// SPECIAL3 is generally R-type with exceptions
if fun == 0x20 {
// seb, seh, wsbh
// R-type (stores rd)
rt = registers[rtReg]
rdReg = Word((insn >> 11) & 0x1F)
} else if fun == 0x24 {
// dsbh, dshd
// R-type (stores rd)
assertMips64(insn)
rt = registers[rtReg]
rdReg = Word((insn >> 11) & 0x1F)
} else if fun == 0x3 || fun == 0x1 || fun == 0x2 || fun == 0x7 || fun == 0x5 || fun == 0x6 || fun == 0x4 || fun == 0x0 {
// dext, dextm, dextu, dins, dinsm, dinsu, ins, ext
// Exception (stores rt)
if !(fun == 0x4 || fun == 0x0) {
assertMips64(insn)
}
rt = registers[rtReg]
rdReg = Word((insn >> 16) & 0x1F)
}
} else if opcode < 0x20 {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
Expand Down Expand Up @@ -148,7 +170,7 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]Word, memory
// lo and hi registers
// can write back
if fun >= 0x10 && fun < funSel {
err = HandleHiLo(cpu, registers, fun, rs, rt, rdReg)
err = HandleHiLo(cpu, registers, insn, fun, rs, rt, rdReg)
return
}
}
Expand Down Expand Up @@ -210,16 +232,28 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
case 0x00: // sll
shiftAmt := (insn >> 6) & 0x1F
return SignExtend((rt<<shiftAmt)&U32Mask, 32)
case 0x02: // srl
return SignExtend((rt&U32Mask)>>((insn>>6)&0x1F), 32)
case 0x02:
sa := (insn >> 6) & 0x1F
maskedRt := rt & U32Mask
if (insn>>21)&0x1 == 1 { // rotr
return SignExtend((maskedRt>>sa)|(maskedRt<<(32-sa)), 32)
} else { // srl
return SignExtend(maskedRt>>sa, 32)
}
case 0x03: // sra
shamt := Word((insn >> 6) & 0x1F)
return SignExtend((rt&U32Mask)>>shamt, 32-shamt)
case 0x04: // sllv
shiftAmt := rs & 0x1F
return SignExtend((rt<<shiftAmt)&U32Mask, 32)
case 0x06: // srlv
return SignExtend((rt&U32Mask)>>(rs&0x1F), 32)
case 0x06:
shift := rs & 0x1F
maskedRt := rt & U32Mask
if (insn>>6)&0x1 == 1 { // rotrv
return SignExtend((maskedRt>>shift)|(maskedRt<<(32-shift)), 32)
} else { // srlv
return SignExtend(maskedRt>>shift, 32)
}
case 0x07: // srav
shamt := Word(rs & 0x1F)
return SignExtend((rt&U32Mask)>>shamt, 32-shamt)
Expand Down Expand Up @@ -291,12 +325,12 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return rs ^ rt
case 0x27: // nor
return ^(rs | rt)
case 0x2a: // slti
case 0x2a: // slti, slt(SPECIAL)
if arch.SignedInteger(rs) < arch.SignedInteger(rt) {
return 1
}
return 0
case 0x2b: // sltiu
case 0x2b: // sltiu, sltu(SPECIAL)
if rs < rt {
return 1
}
Expand All @@ -316,18 +350,28 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
case 0x38: // dsll
assertMips64(insn)
return rt << ((insn >> 6) & 0x1f)
case 0x3A: // dsrl
case 0x3A:
assertMips64(insn)
return rt >> ((insn >> 6) & 0x1f)
shift := (insn >> 6) & 0x1f
if (insn>>21)&0x1 == 1 { // drotr
return (rt >> shift) | (rt << (64 - shift))
} else { // dsrl
return rt >> shift
}
case 0x3B: // dsra
assertMips64(insn)
return Word(int64(rt) >> ((insn >> 6) & 0x1f))
case 0x3C: // dsll32
assertMips64(insn)
return rt << (((insn >> 6) & 0x1f) + 32)
case 0x3E: // dsrl32
case 0x3E:
assertMips64(insn)
return rt >> (((insn >> 6) & 0x1f) + 32)
shift := ((insn >> 6) & 0x1f) + 32
if (insn>>21)&0x1 == 1 { // drotr32
return (rt >> shift) | (rt << (64 - shift))
} else {
return rt >> shift // dsrl32
}
case 0x3F: // dsra32
assertMips64(insn)
return Word(int64(rt) >> (((insn >> 6) & 0x1f) + 32))
Expand All @@ -350,6 +394,9 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
rs <<= 1
}
return Word(i)
case 0x24: // dclz
assertMips64(insn)
return Word(bits.LeadingZeros64(uint64(rs)))
}
case 0x0F: // lui
return SignExtend(rt<<16, 32)
Expand Down Expand Up @@ -425,7 +472,6 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
return UpdateSubWord(rs, mem, 4, Word(swrResult))
}

// MIPS64
case 0x1A: // ldl
assertMips64(insn)
sl := (rs & 0x7) << 3
Expand Down Expand Up @@ -459,6 +505,72 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem
case 0x3F: // sd
assertMips64(insn)
return rt
case 0x1f: // SPECIAL3
switch fun {
case 0x20: // bshfl
switch (insn >> 6) & 0x1f {
case 0x10: // seb
return SignExtend(rt&0xFF, 8)
case 0x18: // seh
return SignExtend(rt&0xFFFF, 16)
case 0x02: // wsbh
return SignExtend(((rt&0xFF00FF00)>>8)|((rt&0x00FF00FF)<<8), 32)
}
case 0x03: // dext
assertMips64(insn)
lsb := (insn >> 6) & 0x1F
size := ((insn >> 11) & 0x1F) + 1
mask := ((Word(1) << size) - 1) << lsb
return Word((rs & mask) >> lsb)
case 0x01: // dextm
assertMips64(insn)
lsb := (insn >> 6) & 0x1F
size := ((insn >> 11) & 0x1F) + 1 + 32
mask := ((Word(1) << size) - 1) << lsb
return Word((rs & mask) >> lsb)
case 0x02: // dextu
assertMips64(insn)
lsb := (insn>>6)&0x1F + 32
size := ((insn >> 11) & 0x1F) + 1
mask := ((Word(1) << size) - 1) << lsb
return Word((rs & mask) >> lsb)
case 0x07: // dins
assertMips64(insn)
lsb := (insn >> 6) & 0x1F
size := ((insn >> 11) & 0x1F) + 1 - lsb
mask := (Word(1) << size) - 1
return (rt & ^(mask << lsb)) | ((rs & mask) << lsb)
case 0x05: // dinsm
assertMips64(insn)
lsb := (insn >> 6) & 0x1F
size := ((insn >> 11) & 0x1F) + 1 + 32 - lsb
mask := (Word(1) << size) - 1
return (rt & ^(mask << lsb)) | ((rs & mask) << lsb)
case 0x06: // dinsu
assertMips64(insn)
lsb := (insn>>6)&0x1F + 32
size := ((insn >> 11) & 0x1F) + 1 + 32 - lsb
mask := (Word(1) << size) - 1
return (rt & ^(mask << lsb)) | ((rs & mask) << lsb)
case 0x04: // ins
lsb := (insn >> 6) & 0x1F
size := ((insn >> 11) & 0x1F) + 1 - lsb
mask := (Word(1) << size) - 1
return SignExtend(((rt & ^(mask << lsb)) | ((rs & mask) << lsb)), 32)
case 0x00: // ext
lsb := (insn >> 6) & 0x1F
size := ((insn >> 11) & 0x1F) + 1
mask := (Word(1) << size) - 1
return SignExtend((rs&(mask<<lsb))>>lsb, 32)
case 0x24: // dbshfl
assertMips64(insn)
switch (insn >> 6) & 0x1f {
case 0x02: // dsbh
return Word(((uint64(rt) & 0xFF00FF00FF00FF00) >> 8) | ((uint64(rt) & 0x00FF00FF00FF00FF) << 8))
case 0x05: // dshd
return Word(((uint64(rt) & 0xFFFF) << 48) | (((uint64(rt) >> 16) & 0xFFFF) << 32) | (((uint64(rt) >> 32) & 0xFFFF) << 16) | ((uint64(rt) >> 48) & 0xFFFF))
}
}
default:
panic(fmt.Sprintf("invalid instruction: %x", insn))
}
Expand Down Expand Up @@ -526,7 +638,7 @@ func HandleBranch(cpu *mipsevm.CpuScalars, registers *[32]Word, opcode uint32, i
}

// HandleHiLo handles instructions that modify HI and LO registers. It also additionally handles doubleword variable shift operations
func HandleHiLo(cpu *mipsevm.CpuScalars, registers *[32]Word, fun uint32, rs Word, rt Word, storeReg Word) error {
func HandleHiLo(cpu *mipsevm.CpuScalars, registers *[32]Word, insn, fun uint32, rs Word, rt Word, storeReg Word) error {
val := Word(0)
switch fun {
case 0x10: // mfhi
Expand Down Expand Up @@ -560,9 +672,13 @@ func HandleHiLo(cpu *mipsevm.CpuScalars, registers *[32]Word, fun uint32, rs Wor
case 0x14: // dsllv
assertMips64Fun(fun)
val = rt << (rs & 0x3F)
case 0x16: // dsrlv
case 0x16:
assertMips64Fun(fun)
val = rt >> (rs & 0x3F)
if (insn>>6)&0x1 == 1 { // drotrv
val = (rt >> (rs & 0x3F)) | (rt << (64 - (rs & 0x3F)))
} else { // dsrlv
val = rt >> (rs & 0x3F)
}
case 0x17: // dsrav
assertMips64Fun(fun)
val = Word(int64(rt) >> (rs & 0x3F))
Expand Down
Loading