From 77a155fd792449a82a4674a89827c6e49a183ded Mon Sep 17 00:00:00 2001 From: mappu Date: Wed, 28 Dec 2022 12:33:07 +1300 Subject: [PATCH] cpu: implement LUI, AUIPC, ADD/SUB/SLL/SLT/SLTU/XOR/SRL/SRA/OR/AND --- cpu.go | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/cpu.go b/cpu.go index 0ba8970..a8f0327 100644 --- a/cpu.go +++ b/cpu.go @@ -39,11 +39,17 @@ func (c *CPUState) Step() error { switch opcode & 0b1111111 { case 0b0110111: // 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: // 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: // JAL @@ -152,7 +158,108 @@ func (c *CPUState) Step() error { case 0b0110011: // 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: // FENCE/FENCE.TSO/PAUSE @@ -166,5 +273,8 @@ func (c *CPUState) Step() error { return ErrInvalidOpcode{} } + // Step program-counter forward + c.Pc++ + return nil }