Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 15 additions & 2 deletions src/isa/riscv_compressed_instr.sv
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,19 @@ class riscv_compressed_instr extends riscv_instr;
}
// C_ADDI16SP is only valid when rd == SP
if (instr_name == C_ADDI16SP) {
rs1 == SP;
rd == SP;
}
if (instr_name inside {C_JR, C_JALR}) {
rs2 == ZERO;
rs1 != ZERO;
}
// These formats potentially have rd == rs1
if (format inside {CA_FORMAT, CB_FORMAT, CI_FORMAT, CR_FORMAT}) {
if (has_rd && has_rs1) {
rd == rs1;
}
}
}

constraint imm_val_c {
Expand Down Expand Up @@ -156,7 +163,13 @@ class riscv_compressed_instr extends riscv_instr;
has_rs1 = 1'b0;
has_imm = 1'b0;
end
CI_FORMAT, CIW_FORMAT: begin
CI_FORMAT: begin
if (instr_name inside {C_LI, C_LUI, C_LWSP, C_NOP, C_EBREAK}) begin
has_rs1 = 1'b0;
end
has_rs2 = 1'b0;
end
CIW_FORMAT: begin
has_rs1 = 1'b0;
has_rs2 = 1'b0;
end
Expand All @@ -166,7 +179,7 @@ class riscv_compressed_instr extends riscv_instr;
has_rd = 1'b0;
end
CB_FORMAT: begin
if (instr_name != C_ANDI) has_rd = 1'b0;
if (instr_name inside {C_BEQZ, C_BNEZ}) has_rd = 1'b0;
has_rs2 = 1'b0;
end
endcase
Expand Down
46 changes: 45 additions & 1 deletion src/isa/riscv_instr.sv
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class riscv_instr extends uvm_object;
rand riscv_reg_t rs1;
rand riscv_reg_t rd;
rand bit [31:0] imm;
rand bit [3:0] rlist;
rand int stack_adj;

// Helper fields
bit [31:0] imm_mask = 32'hFFFF_FFFF;
Expand All @@ -66,6 +68,8 @@ class riscv_instr extends uvm_object;
bit has_rs2 = 1'b1;
bit has_rd = 1'b1;
bit has_imm = 1'b1;
bit has_rlist = 1'b0;
bit has_stack_adj = 1'b0;

constraint imm_c {
if (instr_name inside {SLLIW, SRLIW, SRAIW}) {
Expand Down Expand Up @@ -111,7 +115,8 @@ class riscv_instr extends uvm_object;
if (cfg.no_fence && (instr_name inside {FENCE, FENCE_I, SFENCE_VMA})) continue;
if ((instr_inst.group inside {supported_isa}) &&
!(cfg.disable_compressed_instr &&
(instr_inst.group inside {RV32C, RV64C, RV32DC, RV32FC, RV128C})) &&
(instr_inst.group inside {RV32C, RV64C, RV32DC, RV32FC, RV128C,
RV32ZCB, RV64ZCB, RV32ZCMP, RV64ZCMP})) &&
!(!cfg.enable_floating_point &&
(instr_inst.group inside {RV32F, RV64F, RV32D, RV64D})) &&
!(!cfg.enable_vector_extension &&
Expand Down Expand Up @@ -296,6 +301,7 @@ class riscv_instr extends uvm_object;
rs2.rand_mode(has_rs2);
rd.rand_mode(has_rd);
imm.rand_mode(has_imm);
stack_adj.rand_mode(has_stack_adj);
if (category != CSR) begin
csr.rand_mode(0);
end
Expand Down Expand Up @@ -586,6 +592,40 @@ class riscv_instr extends uvm_object;
return imm_str;
endfunction

virtual function string get_rlist();
// rlist 0-3 are reserved for future extensions
if (rlist < 4 || rlist > 15) begin
`uvm_fatal(`gfn, $sformatf("Unsupported rlist: %0d", rlist))
end
// Handle the specific cases and use a default for the general pattern.
case(rlist)
4: return "{ra}";
5: return "{ra, s0}";
15: return "{ra, s0-s11}"; // The special case for s10/s11
// The default case handles the general pattern for rlist 6 through 14
default: return $sformatf("{ra, s0-s%0d}", rlist - 5);
endcase
endfunction

virtual function riscv_reglist_t get_rlist_as_list();
case(rlist)
4: return '{RA};
5: return '{RA, S0};
6: return '{RA, S0, S1};
7: return '{RA, S0, S1, S2};
8: return '{RA, S0, S1, S2, S3};
9: return '{RA, S0, S1, S2, S3, S4};
10: return '{RA, S0, S1, S2, S3, S4, S5};
11: return '{RA, S0, S1, S2, S3, S4, S5, S6};
12: return '{RA, S0, S1, S2, S3, S4, S5, S6, S7};
13: return '{RA, S0, S1, S2, S3, S4, S5, S6, S7, S8};
14: return '{RA, S0, S1, S2, S3, S4, S5, S6, S7, S8, S9};
15: return '{RA, S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11};
default: `uvm_fatal(`gfn, $sformatf("Unsupported rlist: %0d", rlist))
endcase
return '{};
endfunction

virtual function void clear_unused_label();
if(has_label && !is_branch_target && is_local_numeric_label) begin
has_label = 1'b0;
Expand Down Expand Up @@ -620,6 +660,10 @@ class riscv_instr extends uvm_object;
imm_str = $sformatf("%0d", $signed(imm));
endfunction

virtual function int get_imm_val();
return $signed(imm);
endfunction

`include "isa/riscv_instr_cov.svh"

endclass
32 changes: 32 additions & 0 deletions src/isa/riscv_instr_cov.svh
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,38 @@
// c.j imm
get_val(operands[0], imm);
end
CU_FORMAT: begin
rs1 = get_gpr(operands[0]);
rs1_value = get_gpr_state(operands[0]);
end
CLB_FORMAT, CLH_FORMAT: begin
get_val(operands[2], imm);
rs1 = get_gpr(operands[1]);
rs1_value = get_gpr_state(operands[1]);
end
CSB_FORMAT, CSH_FORMAT: begin
rs2 = get_gpr(operands[0]);
rs2_value = get_gpr_state(operands[0]);
get_val(operands[2], imm);
rs1 = get_gpr(operands[1]);
rs1_value = get_gpr_state(operands[1]);
end
CMMV_FORMAT: begin
// cm.mva01s rs1, rs2
// cm.mvsa01 r1s, r2s
rs1 = get_gpr(operands[0]);
rs1_value = get_gpr_state(operands[0]);
rs2 = get_gpr(operands[1]);
rs2_value = get_gpr_state(operands[1]);
end
CMPP_FORMAT: begin
// cm.push {reg_list}, -stack_adj
// cm.pop {reg_list}, stack_adj
// cm.popret {reg_list}, stack_adj
// cm.popretz {reg_list}, stack_adj
get_val(operands[0], rlist);
get_val(operands[1], stack_adj);
end
default: `uvm_fatal(`gfn, $sformatf("Unsupported format %0s", format))
endcase
endfunction : update_src_regs
Expand Down
225 changes: 225 additions & 0 deletions src/isa/riscv_zcb_instr.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/*
* Copyright 2020 Google LLC
* Copyright 2023 Frontgrade Gaisler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

class riscv_zcb_instr extends riscv_instr;

// This code is based on the frozen v.1.0.1 code reduction specification.
// Most of the code is copied from the riscv_compressed_instr class.

constraint rvc_csr_c {
// Registers specified by the three-bit rs1’, rs2’, and rd/rs1’
if (format inside {CLB_FORMAT, CSB_FORMAT, CLH_FORMAT, CSH_FORMAT, CU_FORMAT, CA_FORMAT}) {
if (has_rs1) {
rs1 inside {[S0:A5]};
}
if (has_rs2) {
rs2 inside {[S0:A5]};
}
if (has_rd) {
rd inside {[S0:A5]};
}
}
// CU_FORMAT and CA_FORMAT has rd == rs1
if (format inside {CU_FORMAT, CA_FORMAT}) {
if (has_rd && has_rs1) {
rd == rs1;
}
}
}

`uvm_object_utils(riscv_zcb_instr)

function new(string name = "");
super.new(name);
rs1 = S0;
rs2 = S0;
rd = S0;
is_compressed = 1'b1;
endfunction : new

virtual function void set_imm_len();
if (format inside {CLB_FORMAT, CSB_FORMAT}) begin
imm_len = 2;
end else if (format inside {CLH_FORMAT, CSH_FORMAT}) begin
imm_len = 1;
end
endfunction : set_imm_len

virtual function void set_rand_mode();
case (format) inside
CLB_FORMAT: begin
has_rs2 = 1'b0;
end
CSB_FORMAT: begin
has_rd = 1'b0;
end
CLH_FORMAT: begin
has_rs2 = 1'b0;
end
CSH_FORMAT: begin
has_rd = 1'b0;
end
CU_FORMAT: begin
has_rs2 = 1'b0;
has_imm = 1'b0;
end
CA_FORMAT: begin
has_imm = 1'b0;
end
default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW)
endcase
endfunction

// Convert the instruction to assembly code
virtual function string convert2asm(string prefix = "");
string asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
case(format)
CLB_FORMAT, CLH_FORMAT:
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name());
CSB_FORMAT, CSH_FORMAT:
asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name());
CU_FORMAT:
asm_str = $sformatf("%0s%0s", asm_str, rs1.name);
CA_FORMAT:
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name());
default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW)
endcase

if (comment != "")
asm_str = {asm_str, " #",comment};
return asm_str.tolower();
endfunction : convert2asm

// Convert the instruction to assembly code
virtual function string convert2bin(string prefix = "");
string binary;
case (instr_name) inside
C_LBU:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), imm[0], imm[1],
get_c_gpr(rd), get_c_opcode()});
C_LHU:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b0, imm[1],
get_c_gpr(rd), get_c_opcode()});
C_LH:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b1, imm[1],
get_c_gpr(rd), get_c_opcode()});
C_SB:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), imm[0], imm[1],
get_c_gpr(rs2), get_c_opcode()});
C_SH:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b0, imm[1],
get_c_gpr(rs2), get_c_opcode()});
C_ZEXT_B:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11000,
get_c_opcode()});
C_SEXT_B:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11001,
get_c_opcode()});
C_ZEXT_H:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11010,
get_c_opcode()});
C_SEXT_H:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11011,
get_c_opcode()});
C_ZEXT_W:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11100,
get_c_opcode()});
C_NOT:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11101,
get_c_opcode()});
C_MUL:
binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 2'b10,
get_c_gpr(rs2), get_c_opcode()});
default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
endcase
return {prefix, binary};
endfunction : convert2bin

// Get opcode for zcb instruction
virtual function bit [1:0] get_c_opcode();
case (instr_name) inside
C_ZEXT_B, C_SEXT_B, C_ZEXT_H, C_SEXT_H,
C_ZEXT_W, C_NOT, C_MUL : get_c_opcode = 2'b01;
C_LBU, C_LHU, C_LH, C_SB, C_SH : get_c_opcode = 2'b00;
default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
endcase
endfunction : get_c_opcode

virtual function bit [5:0] get_func6();
case (instr_name)
C_LBU: get_func6 = 6'b100000;
C_LHU: get_func6 = 6'b100001;
C_LH: get_func6 = 6'b100001;
C_SB: get_func6 = 6'b100010;
C_SH: get_func6 = 6'b100011;
C_ZEXT_B: get_func6 = 6'b100011;
C_SEXT_B: get_func6 = 6'b100111;
C_ZEXT_H: get_func6 = 6'b100111;
C_SEXT_H: get_func6 = 6'b100111;
C_ZEXT_W: get_func6 = 6'b100111;
C_NOT: get_func6 = 6'b100111;
C_MUL: get_func6 = 6'b100111;
default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
endcase
endfunction : get_func6

virtual function bit is_supported(riscv_instr_gen_config cfg);
return (cfg.enable_zcb_extension &&
// RV32C, RV32Zbb, RV32Zba, M/Zmmul is prerequisites for this extension
(RV32ZBB inside {supported_isa}) &&
(RV32C inside {supported_isa}) &&
(RV32ZBA inside {supported_isa}) &&
((RV32M inside {supported_isa}) || (RV32ZMMUL inside {supported_isa})) &&
((RV32ZCB inside {supported_isa} || RV64ZCB inside {supported_isa})) &&
instr_name inside {
C_ZEXT_B, C_SEXT_B, C_ZEXT_H, C_SEXT_H, C_ZEXT_W,
C_NOT, C_MUL, C_LBU, C_LHU, C_LH, C_SB, C_SH
});
endfunction : is_supported

// For coverage
virtual function void update_src_regs(string operands[$]);
case(format)
CU_FORMAT: begin
rs1 = get_gpr(operands[0]);
rs1_value = get_gpr_state(operands[0]);
end
CLB_FORMAT, CLH_FORMAT: begin
get_val(operands[2], imm);
rs1 = get_gpr(operands[1]);
rs1_value = get_gpr_state(operands[1]);
end
CSB_FORMAT, CSH_FORMAT: begin
rs2 = get_gpr(operands[0]);
rs2_value = get_gpr_state(operands[0]);
get_val(operands[2], imm);
rs1 = get_gpr(operands[1]);
rs1_value = get_gpr_state(operands[1]);
end
CA_FORMAT: begin
rs2 = get_gpr(operands[1]);
rs2_value = get_gpr_state(operands[1]);
rs1 = get_gpr(operands[0]);
rs1_value = get_gpr_state(operands[0]);
end
default: ;
endcase
super.update_src_regs(operands);
endfunction : update_src_regs

endclass : riscv_zcb_instr;
Loading