Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/isa/riscv_instr.sv
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ 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})) &&
!(!cfg.enable_floating_point &&
(instr_inst.group inside {RV32F, RV64F, RV32D, RV64D})) &&
!(!cfg.enable_vector_extension &&
Expand Down
16 changes: 16 additions & 0 deletions src/isa/riscv_instr_cov.svh
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,22 @@
// 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
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;
29 changes: 29 additions & 0 deletions src/isa/rv32zcb_instr.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.
*/

`DEFINE_ZCB_INSTR(C_LBU, CLB_FORMAT, LOAD, RV32ZCB, UIMM)
`DEFINE_ZCB_INSTR(C_LHU, CLH_FORMAT, LOAD, RV32ZCB, UIMM)
`DEFINE_ZCB_INSTR(C_LH, CLH_FORMAT, LOAD, RV32ZCB, UIMM)
`DEFINE_ZCB_INSTR(C_SB, CSB_FORMAT, STORE, RV32ZCB, UIMM)
`DEFINE_ZCB_INSTR(C_SH, CSH_FORMAT, STORE, RV32ZCB, UIMM)
`DEFINE_ZCB_INSTR(C_ZEXT_B, CU_FORMAT, ARITHMETIC, RV32ZCB)
`DEFINE_ZCB_INSTR(C_SEXT_B, CU_FORMAT, ARITHMETIC, RV32ZCB)
`DEFINE_ZCB_INSTR(C_ZEXT_H, CU_FORMAT, ARITHMETIC, RV32ZCB)
`DEFINE_ZCB_INSTR(C_SEXT_H, CU_FORMAT, ARITHMETIC, RV32ZCB)
`DEFINE_ZCB_INSTR(C_NOT, CU_FORMAT, LOGICAL, RV32ZCB)
`DEFINE_ZCB_INSTR(C_MUL, CA_FORMAT, ARITHMETIC, RV32ZCB)

18 changes: 18 additions & 0 deletions src/isa/rv64zcb_instr.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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.
*/

`DEFINE_ZCB_INSTR(C_ZEXT_W, CU_FORMAT, ARITHMETIC, RV64ZCB)
1 change: 1 addition & 0 deletions src/riscv_asm_program_gen.sv
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ class riscv_asm_program_gen extends uvm_object;
RV32X, RV64X : misa[MISA_EXT_X] = 1'b1;
RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS,
RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS : ; // No Misa bit for Zb* extensions
RV32ZCB, RV64ZCB : ; // No Misa bit for Zc* extensions
default : `uvm_fatal(`gfn, $sformatf("%0s is not yet supported",
supported_isa[i].name()))
endcase
Expand Down
5 changes: 5 additions & 0 deletions src/riscv_defines.svh
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,8 @@
`define DEFINE_ZBS_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_zbs_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)

//Zcb-extension instruction
`define DEFINE_ZCB_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_zcb_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
2 changes: 1 addition & 1 deletion src/riscv_directed_instr_lib.sv
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ class riscv_int_numeric_corner_stream extends riscv_directed_instr_stream;
for (int i = 0; i < num_of_instr; i++) begin
riscv_instr instr = riscv_instr::get_rand_instr(
.include_category({ARITHMETIC}),
.exclude_group({RV32C, RV64C, RV32F, RV64F, RV32D, RV64D}));
.exclude_group({RV32C, RV64C, RV32ZCB, RV64ZCB, RV32F, RV64F, RV32D, RV64D}));
randomize_gpr(instr);
instr_list.push_back(instr);
end
Expand Down
31 changes: 31 additions & 0 deletions src/riscv_illegal_instr.sv
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,37 @@ class riscv_illegal_instr extends uvm_object;
}
}

constraint zcb_extension_c {
// zcb adds instructions to the reserved funct6 space 6'b100111
// this constraint defines the subset of that op-code space which is still
// reserved. Only way to trigger this constraint should be with
// kReservedC0/C1 or by kIllegalCompressedOpcode. Since the reserved
// instructions at c_msb = 3'b100 && c_op = 2'b00 are not added to
// legal_c00_opcode this combination could occur.
if (RV32ZCB inside {supported_isa}) {
if (exception inside {kIllegalCompressedOpcode, kReservedCompressedInstr}
&& c_msb == 3'b100) {
if (c_op == 2'b00) {
!(instr_bin[12:10] inside {3'b000, 3'b001, 3'b010, 3'b011}); //load/store
// bits 9:2 don't have any inavlid combinations, hence only bit 12:10
// can yield an op-code which is reserved.
} else if (c_op == 2'b01 && instr_bin[12:10] == 3'b111) {
// if funct2 = 2'b10 there are no reserved op-codes
!(instr_bin[6:5] inside {2'b10}); //funct2
if (instr_bin[6:5] == 2'b11) {
if (XLEN == 32){
// c.zext.w not allowed in 32-bit mode
(instr_bin[4:2] inside {3'b100, 3'b110, 3'b111});
} else {
// reserved opcodes
(instr_bin[4:2] inside {3'b110, 3'b111});
}
}
}
}
}
}

constraint illegal_compressed_op_c {
if (exception == kIllegalCompressedOpcode) {
c_op != 2'b01;
Expand Down
Loading
Loading