cpu: implement LUI, AUIPC, ADD/SUB/SLL/SLT/SLTU/XOR/SRL/SRA/OR/AND
This commit is contained in:
parent
038f3d623c
commit
77a155fd79
116
cpu.go
116
cpu.go
@ -39,11 +39,17 @@ func (c *CPUState) Step() error {
|
|||||||
switch opcode & 0b1111111 {
|
switch opcode & 0b1111111 {
|
||||||
case 0b0110111:
|
case 0b0110111:
|
||||||
// LUI
|
// LUI
|
||||||
panic("todo")
|
// LUI (load upper immediate) is used to build 32-bit constants and uses the U-type format. LUI
|
||||||
|
// places the 32-bit U-immediate value into the destination register rd, filling in the lowest 12 bits
|
||||||
|
// with zeros.
|
||||||
|
c.Registers[opcode_rd(opcode)] = opcode & 0b11111111111111111111000000000000
|
||||||
|
|
||||||
case 0b0010111:
|
case 0b0010111:
|
||||||
// AUIPC
|
// AUIPC
|
||||||
panic("todo")
|
// AUIPC (add upper immediate to pc) is used to build pc-relative addresses and uses the U-type
|
||||||
|
// format. AUIPC forms a 32-bit offset from the U-immediate, filling in the lowest 12 bits with zeros,
|
||||||
|
// adds this offset to the address of the AUIPC instruction, then places the result in register rd.
|
||||||
|
c.Registers[opcode_rd(opcode)] = c.Pc + (opcode & 0b11111111111111111111000000000000)
|
||||||
|
|
||||||
case 0b01101111:
|
case 0b01101111:
|
||||||
// JAL
|
// JAL
|
||||||
@ -152,7 +158,108 @@ func (c *CPUState) Step() error {
|
|||||||
|
|
||||||
case 0b0110011:
|
case 0b0110011:
|
||||||
// ADD/SUB/SLL/SLT/SLTU/XOR/SRL/SRA/OR/AND
|
// ADD/SUB/SLL/SLT/SLTU/XOR/SRL/SRA/OR/AND
|
||||||
panic("todo")
|
// RV32I defines several arithmetic R-type operations. All operations read the rs1 and rs2 registers
|
||||||
|
// as source operands and write the result into register rd. The funct7 and funct3 fields select the
|
||||||
|
// type of operation.
|
||||||
|
|
||||||
|
funct3 := (opcode >> 12) & 0b111
|
||||||
|
funct7 := (opcode >> 25) & 0b1111111
|
||||||
|
|
||||||
|
switch funct3 {
|
||||||
|
case 0b000:
|
||||||
|
// ADD/SUB
|
||||||
|
// ADD performs the addition of rs1 and rs2. SUB performs the subtraction of rs2 from rs1. Overflows
|
||||||
|
// are ignored and the low XLEN bits of results are written to the destination rd.
|
||||||
|
|
||||||
|
if funct7 == 0b0000000 {
|
||||||
|
c.Registers[opcode_rd(opcode)] = c.Registers[opcode_rs1(opcode)] + c.Registers[opcode_rs2(opcode)]
|
||||||
|
|
||||||
|
} else if funct7 == 0b0100000 {
|
||||||
|
c.Registers[opcode_rd(opcode)] = c.Registers[opcode_rs1(opcode)] - c.Registers[opcode_rs2(opcode)]
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0b111:
|
||||||
|
// AND
|
||||||
|
// AND, OR, and XOR perform bitwise logical operations.
|
||||||
|
if funct7 != 0b0000000 {
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Registers[opcode_rd(opcode)] = c.Registers[opcode_rs1(opcode)] & c.Registers[opcode_rs2(opcode)]
|
||||||
|
|
||||||
|
case 0b110:
|
||||||
|
// OR
|
||||||
|
if funct7 != 0b0000000 {
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Registers[opcode_rd(opcode)] = c.Registers[opcode_rs1(opcode)] | c.Registers[opcode_rs2(opcode)]
|
||||||
|
|
||||||
|
case 0b100:
|
||||||
|
// XOR
|
||||||
|
if funct7 != 0b0000000 {
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Registers[opcode_rd(opcode)] = c.Registers[opcode_rs1(opcode)] ^ c.Registers[opcode_rs2(opcode)]
|
||||||
|
|
||||||
|
case 0b010:
|
||||||
|
// SLT
|
||||||
|
if funct7 != 0b0000000 {
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SLT and SLTU perform signed and unsigned compares respectively, writing 1 to rd if rs1 < rs2,
|
||||||
|
// 0 otherwise. Note, SLTU rd, x0, rs2 sets rd to 1 if rs2 is not equal to zero, otherwise sets rd
|
||||||
|
// to zero (assembler pseudoinstruction SNEZ rd, rs).
|
||||||
|
if int32(c.Registers[opcode_rs1(opcode)]) < int32(c.Registers[opcode_rs2(opcode)]) {
|
||||||
|
c.Registers[opcode_rd(opcode)] = 1
|
||||||
|
} else {
|
||||||
|
c.Registers[opcode_rd(opcode)] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0b011:
|
||||||
|
// SLTU
|
||||||
|
if funct7 != 0b0000000 {
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Registers[opcode_rs1(opcode)] < c.Registers[opcode_rs2(opcode)] {
|
||||||
|
c.Registers[opcode_rd(opcode)] = 1
|
||||||
|
} else {
|
||||||
|
c.Registers[opcode_rd(opcode)] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0b001:
|
||||||
|
// SLL
|
||||||
|
if funct7 != 0b0000000 {
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SLL, SRL, and SRA perform logical left, logical right, and arithmetic right shifts on the value in
|
||||||
|
// register rs1 by the shift amount held in the lower 5 bits of register rs2.
|
||||||
|
c.Registers[opcode_rd(opcode)] = c.Registers[opcode_rs1(opcode)] << (c.Registers[opcode_rs2(opcode)] & 0b11111)
|
||||||
|
|
||||||
|
case 0b101:
|
||||||
|
// SRL/SRA
|
||||||
|
if funct7 == 0b0000000 {
|
||||||
|
// SRL
|
||||||
|
c.Registers[opcode_rd(opcode)] = c.Registers[opcode_rs1(opcode)] >> (c.Registers[opcode_rs2(opcode)] & 0b11111)
|
||||||
|
|
||||||
|
} else if funct7 == 0100000 {
|
||||||
|
// SRA
|
||||||
|
c.Registers[opcode_rd(opcode)] = uint32(int32(c.Registers[opcode_rs1(opcode)]) >> (c.Registers[opcode_rs2(opcode)] & 0b11111))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ErrInvalidOpcode{}
|
||||||
|
}
|
||||||
|
|
||||||
case 0b0001111:
|
case 0b0001111:
|
||||||
// FENCE/FENCE.TSO/PAUSE
|
// FENCE/FENCE.TSO/PAUSE
|
||||||
@ -166,5 +273,8 @@ func (c *CPUState) Step() error {
|
|||||||
return ErrInvalidOpcode{}
|
return ErrInvalidOpcode{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step program-counter forward
|
||||||
|
c.Pc++
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user