Multiplication

This commit is contained in:
2024-05-12 15:29:16 +02:00
parent 822fd8616c
commit 8ebaea4583
2 changed files with 121 additions and 48 deletions

View File

@ -45,6 +45,12 @@ static inline uint32_t sign_extend(uint32_t word, uint32_t size)
return (word ^ mask) - mask;
}
static inline uint64_t sign_extend_64(uint64_t word, uint32_t size)
{
const uint64_t mask = 1ULL << (size - 1);
return (word ^ mask) - mask;
}
struct Instruction
{
uint8_t opcode;
@ -165,47 +171,82 @@ static void execute_op(Hart* hart, uint32_t instruction)
{
const Instruction inst = decode_r_type(instruction);
if (inst.rd == 0) return;
switch (inst.funct3)
uint32_t bank = inst.funct7 & 0x5F;
if (bank == 0)
{
case 0: // ADD, SUB
if (instruction & 0x40000000)
{
hart->regs[inst.rd] = hart->regs[inst.rs1] - hart->regs[inst.rs2];
}
else
{
hart->regs[inst.rd] = hart->regs[inst.rs1] + hart->regs[inst.rs2];
}
break;
case 1: // SLL
hart->regs[inst.rd] = hart->regs[inst.rs1] << (hart->regs[inst.rs2] & 0x1F);
break;
case 2: // SLT
hart->regs[inst.rd] = (int32_t)hart->regs[inst.rs1] < (int32_t)hart->regs[inst.rs2] ? 1 : 0;
break;
case 3: // SLTU
hart->regs[inst.rd] = hart->regs[inst.rs1] < hart->regs[inst.rs2] ? 1 : 0;
break;
case 4: // XOR
hart->regs[inst.rd] = hart->regs[inst.rs1] ^ hart->regs[inst.rs2];
break;
case 5: // SRL, SRA
switch (inst.funct3)
{
const uint32_t shamt = hart->regs[inst.rs2] & 0x1F;
uint32_t res = hart->regs[inst.rs1] >> shamt;
if ((instruction & 0x40000000) && shamt > 0) { res = sign_extend(res, 32 - shamt); }
hart->regs[inst.rd] = res;
break;
case 0: // ADD, SUB
if (inst.funct7 & 0x20)
{
hart->regs[inst.rd] = hart->regs[inst.rs1] - hart->regs[inst.rs2];
}
else
{
hart->regs[inst.rd] = hart->regs[inst.rs1] + hart->regs[inst.rs2];
}
break;
case 1: // SLL
hart->regs[inst.rd] = hart->regs[inst.rs1] << (hart->regs[inst.rs2] & 0x1F);
break;
case 2: // SLT
hart->regs[inst.rd] = (int32_t)hart->regs[inst.rs1] < (int32_t)hart->regs[inst.rs2] ? 1 : 0;
break;
case 3: // SLTU
hart->regs[inst.rd] = hart->regs[inst.rs1] < hart->regs[inst.rs2] ? 1 : 0;
break;
case 4: // XOR
hart->regs[inst.rd] = hart->regs[inst.rs1] ^ hart->regs[inst.rs2];
break;
case 5: // SRL, SRA
{
const uint32_t shamt = hart->regs[inst.rs2] & 0x1F;
uint32_t res = hart->regs[inst.rs1] >> shamt;
if ((inst.funct7 & 0x20) && shamt > 0) { res = sign_extend(res, 32 - shamt); }
hart->regs[inst.rd] = res;
break;
}
case 6: // OR
hart->regs[inst.rd] = hart->regs[inst.rs1] | hart->regs[inst.rs2];
break;
case 7: // AND
hart->regs[inst.rd] = hart->regs[inst.rs1] & hart->regs[inst.rs2];
break;
default:
assert(!"Unhandled OP, bank = 0");
break;
}
case 6: // OR
hart->regs[inst.rd] = hart->regs[inst.rs1] | hart->regs[inst.rs2];
break;
case 7: // AND
hart->regs[inst.rd] = hart->regs[inst.rs1] & hart->regs[inst.rs2];
break;
default:
assert(!"Unhandled OP-IMM");
}
else if (bank == 1)
{
if ((inst.funct3 & 0x8) == 0)
{
uint64_t a = hart->regs[inst.rs1];
uint64_t b = hart->regs[inst.rs2];
switch (inst.funct3 & 0x3)
{
case 1: // MULH
b = sign_extend_64(b, 32);
case 2: // MULHSU
a = sign_extend_64(a, 32);
case 0: // MUL
case 3: // MULHU
break;
}
uint64_t r = a * b;
hart->regs[inst.rd] = (inst.funct3 == 0) ? r & 0xFFFFFFFF : r >> 32;
}
else
{
assert(!"Unhandled M OP");
}
}
else
{
assert(!"Unhandled OP bank");
}
}
@ -292,7 +333,7 @@ static void store_word(Hart* hart, uint32_t address, uint32_t value)
store_size(hart, address, value, 4);
}
static void execute_op_load(Hart* hart, uint32_t instruction)
static void execute_load(Hart* hart, uint32_t instruction)
{
const Instruction inst = decode_i_type(instruction);
const uint32_t address = hart->regs[inst.rs1] + inst.imm;
@ -329,7 +370,7 @@ static void execute_op_load(Hart* hart, uint32_t instruction)
}
}
static void execute_op_store(Hart* hart, uint32_t instruction)
static void execute_store(Hart* hart, uint32_t instruction)
{
const Instruction inst = decode_s_type(instruction);
const uint32_t address = hart->regs[inst.rs1] + inst.imm;
@ -545,7 +586,7 @@ void execute(Hart* hart, uint32_t instruction)
switch (instruction & 0x7f)
{
case 0x03:
execute_op_load(hart, instruction);
execute_load(hart, instruction);
hart->pc += 4;
break;
case 0x0F:
@ -567,7 +608,7 @@ void execute(Hart* hart, uint32_t instruction)
break;
}
case 0x23:
execute_op_store(hart, instruction);
execute_store(hart, instruction);
hart->pc += 4;
break;
case 0x33: