444 lines
12 KiB
C
444 lines
12 KiB
C
/*
|
|
* Copyright (c) 2020-2021, SERI Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2023-06-23 Lyons first version
|
|
*/
|
|
|
|
uint32_t exec_lui(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->imm << 12 );
|
|
}
|
|
|
|
uint32_t exec_auipc(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->current_pc + (inst_info->imm << 12) );
|
|
}
|
|
|
|
uint32_t exec_jal(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->next_pc;
|
|
inst_info->imm <<= 1; // imm20 << 1
|
|
inst_info->next_pc = (int32_t)inst_info->current_pc + (int32_t)SIGN_EXTEND(inst_info->imm, 21);
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_jalr(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->next_pc;
|
|
inst_info->next_pc = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->next_pc &= 0xfffffffe;
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_beq(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->imm <<= 1; // im12 << 1
|
|
if ( inst_info->rs1_data == inst_info->rs2_data )
|
|
inst_info->next_pc = (int32_t)inst_info->current_pc + (int32_t)SIGN_EXTEND(inst_info->imm, 13);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_bne(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->imm <<= 1; // im12 << 1
|
|
if ( inst_info->rs1_data != inst_info->rs2_data )
|
|
inst_info->next_pc = (int32_t)inst_info->current_pc + (int32_t)SIGN_EXTEND(inst_info->imm, 13);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_blt(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->imm <<= 1; // im12 << 1
|
|
if ( (int32_t)inst_info->rs1_data < (int32_t)inst_info->rs2_data )
|
|
inst_info->next_pc = (int32_t)inst_info->current_pc + (int32_t)SIGN_EXTEND(inst_info->imm, 13);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_bge(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->imm <<= 1; // im12 << 1
|
|
if ( (int32_t)inst_info->rs1_data >= (int32_t)inst_info->rs2_data )
|
|
inst_info->next_pc = (int32_t)inst_info->current_pc + (int32_t)SIGN_EXTEND(inst_info->imm, 13);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_bltu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->imm <<= 1; // im12 << 1
|
|
if ( inst_info->rs1_data < inst_info->rs2_data )
|
|
inst_info->next_pc = (int32_t)inst_info->current_pc + SIGN_EXTEND(inst_info->imm, 13);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_bgeu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->imm <<= 1; // im12 << 1
|
|
if ( inst_info->rs1_data >= inst_info->rs2_data )
|
|
inst_info->next_pc = (int32_t)inst_info->current_pc + SIGN_EXTEND(inst_info->imm, 13);
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_lb(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mem_addr = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->mem_rd = 1;
|
|
inst_info->mem_ext = eMemoryExtType_Sign;
|
|
inst_info->mem_size = eMemorySize_Byte;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_lh(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mem_addr = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->mem_rd = 1;
|
|
inst_info->mem_ext = eMemoryExtType_Sign;
|
|
inst_info->mem_size = eMemorySize_HalfWord;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_lw(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mem_addr = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->mem_rd = 1;
|
|
inst_info->mem_ext = eMemoryExtType_Sign;
|
|
inst_info->mem_size = eMemorySize_Word;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_lbu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mem_addr = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->mem_rd = 1;
|
|
inst_info->mem_ext = eMemoryExtType_Zero;
|
|
inst_info->mem_size = eMemorySize_Byte;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_lhu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mem_addr = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->mem_rd = 1;
|
|
inst_info->mem_ext = eMemoryExtType_Zero;
|
|
inst_info->mem_size = eMemorySize_HalfWord;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_sb(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mem_addr = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->mem_data = inst_info->rs2_data;
|
|
inst_info->mem_we = 1;
|
|
inst_info->mem_size = eMemorySize_Byte;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_sh(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mem_addr = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->mem_data = inst_info->rs2_data;
|
|
inst_info->mem_we = 1;
|
|
inst_info->mem_size = eMemorySize_HalfWord;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_sw(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mem_addr = (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12);
|
|
inst_info->mem_data = inst_info->rs2_data;
|
|
inst_info->mem_we = 1;
|
|
inst_info->mem_size = eMemorySize_Word;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_addi(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( (int32_t)inst_info->rs1_data + (int32_t)SIGN_EXTEND(inst_info->imm, 12) );
|
|
}
|
|
|
|
uint32_t exec_slli(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data << inst_info->shamt );
|
|
}
|
|
|
|
uint32_t exec_slti(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( ((int32_t)inst_info->rs1_data < (int32_t)SIGN_EXTEND(inst_info->imm, 12)) ? 1 : 0 );
|
|
}
|
|
|
|
uint32_t exec_sltiu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( (inst_info->rs1_data < SIGN_EXTEND(inst_info->imm, 12)) ? 1 : 0 );
|
|
}
|
|
|
|
uint32_t exec_xori(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data ^ SIGN_EXTEND(inst_info->imm, 12) );
|
|
}
|
|
|
|
uint32_t exec_srli(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data >> inst_info->shamt );
|
|
}
|
|
|
|
uint32_t exec_srai(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->rs1_data >> inst_info->shamt;
|
|
uint32_t mask = SIGN_EXTEND(BIT(inst_info->rs1_data, 31), 1) >> inst_info->shamt;
|
|
if ( BIT(inst_info->rs1_data, 31) ) {
|
|
iresult |= ~mask;
|
|
}
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_ori(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data | SIGN_EXTEND(inst_info->imm, 12) );
|
|
}
|
|
|
|
uint32_t exec_andi(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data & SIGN_EXTEND(inst_info->imm, 12) );
|
|
}
|
|
|
|
uint32_t exec_add(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( (int32_t)inst_info->rs1_data + (int32_t)inst_info->rs2_data );
|
|
}
|
|
|
|
uint32_t exec_sub(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( (int32_t)inst_info->rs1_data - (int32_t)inst_info->rs2_data );
|
|
}
|
|
|
|
uint32_t exec_sll(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data << inst_info->rs2_data );
|
|
}
|
|
|
|
uint32_t exec_slt(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( ((int32_t)inst_info->rs1_data < (int32_t)inst_info->rs2_data) ? 1 : 0 );
|
|
}
|
|
|
|
uint32_t exec_sltu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( (inst_info->rs1_data < inst_info->rs2_data) ? 1 : 0 );
|
|
}
|
|
|
|
uint32_t exec_xor(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data ^ inst_info->rs2_data );
|
|
}
|
|
|
|
uint32_t exec_srl(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data >> inst_info->rs2_data );
|
|
}
|
|
|
|
uint32_t exec_sra(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->rs1_data >> inst_info->rs2_data;
|
|
uint32_t mask = SIGN_EXTEND(BIT(inst_info->rs1_data, 31), 1) >> inst_info->rs2_data;
|
|
if ( BIT(inst_info->rs1_data, 31) ) {
|
|
iresult |= ~mask;
|
|
}
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_or(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data | inst_info->rs2_data );
|
|
}
|
|
|
|
uint32_t exec_and(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return ( inst_info->rs1_data & inst_info->rs2_data );
|
|
}
|
|
|
|
uint32_t exec_fence(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_mret(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
inst_info->mret = 1;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t exec_csrrw(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->csr_data;
|
|
inst_info->csr_data = inst_info->rs1_data;
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_csrrs(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->csr_data;
|
|
inst_info->csr_data |= inst_info->rs1_data;
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_csrrc(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->csr_data;
|
|
inst_info->csr_data &= ~inst_info->rs1_data;
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_csrrwi(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->csr_data;
|
|
inst_info->csr_data = ZERO_EXTEND(inst_info->imm, 5);
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_csrrsi(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->csr_data;
|
|
inst_info->csr_data |= ZERO_EXTEND(inst_info->imm, 5);
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_csrrci(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->csr_data;
|
|
inst_info->csr_data &= ~ZERO_EXTEND(inst_info->imm, 5);
|
|
return iresult;
|
|
}
|
|
|
|
|
|
#ifdef RV32M
|
|
|
|
uint32_t exec_mul(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint64_t data1 = (uint64_t)inst_info->rs1_data + (BIT(inst_info->rs1_data, 31) ? 0xffffffff00000000 : 0);
|
|
uint64_t data2 = (uint64_t)inst_info->rs2_data + (BIT(inst_info->rs2_data, 31) ? 0xffffffff00000000 : 0);
|
|
uint64_t result64 = (int64_t)data1 * (int64_t)data2;
|
|
return ( result64 );
|
|
}
|
|
|
|
#ifndef __linux__
|
|
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
|
#endif
|
|
|
|
uint32_t exec_mulh(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint64_t data1 = (uint64_t)inst_info->rs1_data + (BIT(inst_info->rs1_data, 31) ? 0xffffffff00000000 : 0);
|
|
uint64_t data2 = (uint64_t)inst_info->rs2_data + (BIT(inst_info->rs2_data, 31) ? 0xffffffff00000000 : 0);
|
|
uint64_t result64 = (int64_t)data1 * (int64_t)data2;
|
|
return ( result64 >> 32 );
|
|
}
|
|
|
|
uint32_t exec_mulhsu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint64_t data1 = (uint64_t)inst_info->rs1_data + (BIT(inst_info->rs1_data, 31) ? 0xffffffff00000000 : 0);
|
|
uint64_t data2 = (uint64_t)inst_info->rs2_data;
|
|
uint64_t result64 = (int64_t)data1 * (int64_t)data2;
|
|
return ( result64 >> 32 );
|
|
}
|
|
|
|
uint32_t exec_mulhu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint64_t data1 = (uint64_t)inst_info->rs1_data;
|
|
uint64_t data2 = (uint64_t)inst_info->rs2_data;
|
|
uint64_t result64 = (int64_t)data1 * (int64_t)data2;
|
|
return ( result64 >> 32 );
|
|
}
|
|
|
|
uint32_t exec_div(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = 0xffffffff;
|
|
if ( 0 != (int32_t)inst_info->rs2_data ) {
|
|
iresult = (int32_t)inst_info->rs1_data / (int32_t)inst_info->rs2_data;
|
|
}
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_divu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = 0xffffffff;
|
|
if ( 0 != (uint32_t)inst_info->rs2_data ) {
|
|
iresult = (uint32_t)inst_info->rs1_data / (uint32_t)inst_info->rs2_data;
|
|
}
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_rem(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->rs1_data;
|
|
if ( 0 != (int32_t)inst_info->rs2_data ) {
|
|
iresult = (int32_t)inst_info->rs1_data % (int32_t)inst_info->rs2_data;
|
|
}
|
|
return iresult;
|
|
}
|
|
|
|
uint32_t exec_remu(void *info)
|
|
{
|
|
InstInfo_t *inst_info = (InstInfo_t*)info;
|
|
uint32_t iresult = inst_info->rs1_data;
|
|
if ( 0 != (uint32_t)inst_info->rs2_data ) {
|
|
iresult = (uint32_t)inst_info->rs1_data % (uint32_t)inst_info->rs2_data;
|
|
}
|
|
return iresult;
|
|
}
|
|
|
|
#endif // #ifdef RV32M
|