mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Removed generate statements
This commit is contained in:
parent
98be8201b2
commit
d66f7c841b
@ -3,11 +3,14 @@ make all:
|
||||
make -C ../../addins/riscv-arch-test
|
||||
make -C ../../addins/riscv-arch-test XLEN=32
|
||||
exe2memfile.pl ../../addins/riscv-arch-test/work/*/*/*.elf
|
||||
# extractFunctionRadix. ***
|
||||
|
||||
# Build wally-riscv-arch-test
|
||||
make -C ../../tests/wally-riscv-arch-test/
|
||||
make -C ../../tests/wally-riscv-arch-test/ XLEN=32
|
||||
exe2memfile.pl ../../tests/wally-riscv-arch-test/work/*/*/*.elf
|
||||
# ***extractFunctionRadix
|
||||
# *** use elf2hex
|
||||
|
||||
# *** add optional imperas tests
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
vsim -c <<!
|
||||
do wally-pipelined-batch.do rv64gc imperas64i
|
||||
do wally-pipelined-batch.do rv32gc wally32priv
|
||||
!
|
||||
|
@ -174,3 +174,22 @@ module divconv_pipe (q1, qm1, qp1, q0, qm0, qp0, rega_out, regb_out, regc_out, r
|
||||
flopenr #(60) regk (clk, reset, regs_pipe2, {qp_out0[59:35], (qp_out0[34:6] & {29{~P_pipe}}), 6'h0}, qp0);
|
||||
|
||||
endmodule // divconv
|
||||
|
||||
// *** rewrote behaviorally dh 5 Jan 2021 for speed
|
||||
module csa #(parameter WIDTH=8) (
|
||||
input logic [WIDTH-1:0] a, b, c,
|
||||
output logic [WIDTH-1:0] sum, carry);
|
||||
|
||||
assign sum = a ^ b ^ c;
|
||||
assign carry = (a & (b | c)) | (b & c);
|
||||
/*
|
||||
logic [WIDTH:0] carry_temp;
|
||||
genvar i;
|
||||
generate
|
||||
for (i=0;i<WIDTH;i=i+1) begin : genbit
|
||||
fa fa_inst (a[i], b[i], c[i], sum[i], carry_temp[i+1]);
|
||||
end
|
||||
endgenerate
|
||||
assign carry = {carry_temp[WIDTH-1:1], 1'b0};
|
||||
*/
|
||||
endmodule // csa
|
||||
|
@ -37,22 +37,17 @@ module redundantmul #(parameter WIDTH =8)(
|
||||
input logic [WIDTH-1:0] a,b,
|
||||
output logic [2*WIDTH-1:0] out0, out1);
|
||||
|
||||
//
|
||||
|
||||
generate
|
||||
if (`DESIGN_COMPILER == 1) begin:mul
|
||||
logic [2*WIDTH-1+2:0] tmp_out0;
|
||||
logic [2*WIDTH-1+2:0] tmp_out1;
|
||||
|
||||
DW02_multp #(WIDTH, WIDTH, 2*WIDTH+2) mul(.a, .b, .tc(1'b0), .out0(tmp_out0), .out1(tmp_out1));
|
||||
assign out0 = tmp_out0[2*WIDTH-1:0];
|
||||
assign out1 = tmp_out1[2*WIDTH-1:0];
|
||||
end else begin:mul // force a nonredunant multipler. This will simulate properly and also is appropriate for FPGAs.
|
||||
assign out0 = a * b;
|
||||
assign out1 = 0;
|
||||
end
|
||||
endgenerate
|
||||
if (`DESIGN_COMPILER == 1) begin:mul
|
||||
logic [2*WIDTH-1+2:0] tmp_out0;
|
||||
logic [2*WIDTH-1+2:0] tmp_out1;
|
||||
|
||||
DW02_multp #(WIDTH, WIDTH, 2*WIDTH+2) mul(.a, .b, .tc(1'b0), .out0(tmp_out0), .out1(tmp_out1));
|
||||
assign out0 = tmp_out0[2*WIDTH-1:0];
|
||||
assign out1 = tmp_out1[2*WIDTH-1:0];
|
||||
end else begin:mul // force a nonredunant multipler. This will simulate properly and also is appropriate for FPGAs.
|
||||
assign out0 = a * b;
|
||||
assign out1 = 0;
|
||||
end
|
||||
endmodule
|
||||
|
||||
|
@ -1,195 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// lzd.sv
|
||||
//
|
||||
// Written: James.Stine@okstate.edu 1 February 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: Integer Divide instructions
|
||||
//
|
||||
// A component of the Wally configurable RISC-V project.
|
||||
//
|
||||
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
///////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
|
||||
// Original idea came from V. G. Oklobdzija, "An algorithmic and novel
|
||||
// design of a leading zero detector circuit: comparison with logic
|
||||
// synthesis," in IEEE Transactions on Very Large Scale Integration
|
||||
// (VLSI) Systems, vol. 2, no. 1, pp. 124-128, March 1994, doi:
|
||||
// 10.1109/92.273153.
|
||||
|
||||
// Modified to be more hierarchical
|
||||
|
||||
module lzd2 (P, V, B);
|
||||
|
||||
input logic [1:0] B;
|
||||
|
||||
output logic P;
|
||||
output logic V;
|
||||
|
||||
assign V = B[0] | B[1];
|
||||
assign P = B[0] & ~B[1];
|
||||
|
||||
endmodule // lzd2
|
||||
|
||||
module lzd_hier #(parameter WIDTH=8)
|
||||
(input logic [WIDTH-1:0] B,
|
||||
output logic [$clog2(WIDTH)-1:0] ZP,
|
||||
output logic ZV);
|
||||
|
||||
if (WIDTH == 128)
|
||||
lzd128 lz127 (ZP, ZV, B);
|
||||
else if (WIDTH == 64)
|
||||
lzd64 lz64 (ZP, ZV, B);
|
||||
else if (WIDTH == 32)
|
||||
lzd32 lz32 (ZP, ZV, B);
|
||||
else if (WIDTH == 16)
|
||||
lzd16 lz16 (ZP, ZV, B);
|
||||
else if (WIDTH == 8)
|
||||
lzd8 lz8 (ZP, ZV, B);
|
||||
else if (WIDTH == 4)
|
||||
lzd4 lz4 (ZP, ZV, B);
|
||||
|
||||
endmodule // lzd_hier
|
||||
|
||||
module lzd4 (ZP, ZV, B);
|
||||
|
||||
input logic [3:0] B;
|
||||
|
||||
logic ZPa;
|
||||
logic ZPb;
|
||||
logic ZVa;
|
||||
logic ZVb;
|
||||
|
||||
output logic [1:0] ZP;
|
||||
output logic ZV;
|
||||
|
||||
lzd2 l1(ZPa, ZVa, B[1:0]);
|
||||
lzd2 l2(ZPb, ZVb, B[3:2]);
|
||||
|
||||
assign ZP[0] = ZVb ? ZPb : ZPa;
|
||||
assign ZP[1] = ~ZVb;
|
||||
assign ZV = ZVa | ZVb;
|
||||
|
||||
endmodule // lzd4
|
||||
|
||||
module lzd8 (ZP, ZV, B);
|
||||
|
||||
input logic [7:0] B;
|
||||
|
||||
logic [1:0] ZPa;
|
||||
logic [1:0] ZPb;
|
||||
logic ZVa;
|
||||
logic ZVb;
|
||||
|
||||
output logic [2:0] ZP;
|
||||
output logic ZV;
|
||||
|
||||
lzd4 l1(ZPa, ZVa, B[3:0]);
|
||||
lzd4 l2(ZPb, ZVb, B[7:4]);
|
||||
|
||||
assign ZP[1:0] = ZVb ? ZPb : ZPa;
|
||||
assign ZP[2] = ~ZVb;
|
||||
assign ZV = ZVa | ZVb;
|
||||
|
||||
endmodule // lzd8
|
||||
|
||||
module lzd16 (ZP, ZV, B);
|
||||
|
||||
input logic [15:0] B;
|
||||
|
||||
logic [2:0] ZPa;
|
||||
logic [2:0] ZPb;
|
||||
logic ZVa;
|
||||
logic ZVb;
|
||||
|
||||
output logic [3:0] ZP;
|
||||
output logic ZV;
|
||||
|
||||
lzd8 l1(ZPa, ZVa, B[7:0]);
|
||||
lzd8 l2(ZPb, ZVb, B[15:8]);
|
||||
|
||||
assign ZP[2:0] = ZVb ? ZPb : ZPa;
|
||||
assign ZP[3] = ~ZVb;
|
||||
assign ZV = ZVa | ZVb;
|
||||
|
||||
endmodule // lzd16
|
||||
|
||||
module lzd32 (ZP, ZV, B);
|
||||
|
||||
input logic [31:0] B;
|
||||
|
||||
logic [3:0] ZPa;
|
||||
logic [3:0] ZPb;
|
||||
logic ZVa;
|
||||
logic ZVb;
|
||||
|
||||
output logic [4:0] ZP;
|
||||
output logic ZV;
|
||||
|
||||
lzd16 l1(ZPa, ZVa, B[15:0]);
|
||||
lzd16 l2(ZPb, ZVb, B[31:16]);
|
||||
|
||||
assign ZP[3:0] = ZVb ? ZPb : ZPa;
|
||||
assign ZP[4] = ~ZVb;
|
||||
assign ZV = ZVa | ZVb;
|
||||
|
||||
endmodule // lzd32
|
||||
|
||||
module lzd64 (ZP, ZV, B);
|
||||
|
||||
input logic [63:0] B;
|
||||
|
||||
logic [4:0] ZPa;
|
||||
logic [4:0] ZPb;
|
||||
logic ZVa;
|
||||
logic ZVb;
|
||||
|
||||
output logic [5:0] ZP;
|
||||
output logic ZV;
|
||||
|
||||
lzd32 l1(ZPa, ZVa, B[31:0]);
|
||||
lzd32 l2(ZPb, ZVb, B[63:32]);
|
||||
|
||||
assign ZP[4:0] = ZVb ? ZPb : ZPa;
|
||||
assign ZP[5] = ~ZVb;
|
||||
assign ZV = ZVa | ZVb;
|
||||
|
||||
endmodule // lzd64
|
||||
|
||||
module lzd128 (ZP, ZV, B);
|
||||
|
||||
input logic [127:0] B;
|
||||
|
||||
logic [5:0] ZPa;
|
||||
logic [5:0] ZPb;
|
||||
logic ZVa;
|
||||
logic ZVb;
|
||||
|
||||
output logic [6:0] ZP;
|
||||
output logic ZV;
|
||||
|
||||
lzd64 l1(ZPa, ZVa, B[64:0]);
|
||||
lzd64 l2(ZPb, ZVb, B[127:63]);
|
||||
|
||||
assign ZP[5:0] = ZVb ? ZPb : ZPa;
|
||||
assign ZP[6] = ~ZVb;
|
||||
assign ZV = ZVa | ZVb;
|
||||
|
||||
endmodule // lzd128
|
||||
|
||||
/* verilator lint_on DECLFILENAME */
|
@ -33,18 +33,16 @@ module or_rows #(parameter ROWS = 8, COLS=2) (
|
||||
input var logic [COLS-1:0] a[ROWS-1:0],
|
||||
output logic [COLS-1:0] y);
|
||||
|
||||
logic [COLS-1:0] mid[ROWS-1:1];
|
||||
genvar row, col;
|
||||
generate
|
||||
if(ROWS == 1)
|
||||
assign y = a[0];
|
||||
else begin
|
||||
assign mid[1] = a[0] | a[1];
|
||||
for (row=2; row < ROWS; row++)
|
||||
assign mid[row] = mid[row-1] | a[row];
|
||||
assign y = mid[ROWS-1];
|
||||
end
|
||||
endgenerate
|
||||
genvar row;
|
||||
if(ROWS == 1)
|
||||
assign y = a[0];
|
||||
else begin
|
||||
logic [COLS-1:0] mid[ROWS-1:1];
|
||||
assign mid[1] = a[0] | a[1];
|
||||
for (row=2; row < ROWS; row++)
|
||||
assign mid[row] = mid[row-1] | a[row];
|
||||
assign y = mid[ROWS-1];
|
||||
end
|
||||
endmodule
|
||||
|
||||
/* verilator lint_on UNOPTFLAT */
|
||||
|
@ -1,74 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// shifters.sv
|
||||
//
|
||||
// Written: James.Stine@okstate.edu 1 February 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: Integer Divide instructions
|
||||
//
|
||||
// A component of the Wally configurable RISC-V project.
|
||||
//
|
||||
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
///////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
/* verilator lint_off UNOPTFLAT */
|
||||
|
||||
module shift_right #(parameter WIDTH=8)
|
||||
(input logic [WIDTH-1:0] A,
|
||||
input logic [$clog2(WIDTH)-1:0] Shift,
|
||||
output logic [WIDTH-1:0] Z);
|
||||
|
||||
logic [WIDTH-1:0] stage [$clog2(WIDTH):0];
|
||||
logic sign;
|
||||
genvar i;
|
||||
|
||||
assign stage[0] = A;
|
||||
generate
|
||||
for (i=0;i<$clog2(WIDTH);i=i+1) begin : genbit
|
||||
mux2 #(WIDTH) mux_inst (stage[i],
|
||||
{{(WIDTH/(2**(i+1))){1'b0}}, stage[i][WIDTH-1:WIDTH/(2**(i+1))]},
|
||||
Shift[$clog2(WIDTH)-i-1],
|
||||
stage[i+1]);
|
||||
end
|
||||
endgenerate
|
||||
assign Z = stage[$clog2(WIDTH)];
|
||||
|
||||
endmodule // shift_right
|
||||
|
||||
module shift_left #(parameter WIDTH=8)
|
||||
(input logic [WIDTH-1:0] A,
|
||||
input logic [$clog2(WIDTH)-1:0] Shift,
|
||||
output logic [WIDTH-1:0] Z);
|
||||
|
||||
logic [WIDTH-1:0] stage [$clog2(WIDTH):0];
|
||||
genvar i;
|
||||
|
||||
assign stage[0] = A;
|
||||
generate
|
||||
for (i=0;i<$clog2(WIDTH);i=i+1) begin : genbit
|
||||
mux2 #(WIDTH) mux_inst (stage[i],
|
||||
{stage[i][WIDTH-1-WIDTH/(2**(i+1)):0], {(WIDTH/(2**(i+1))){1'b0}}},
|
||||
Shift[$clog2(WIDTH)-i-1],
|
||||
stage[i+1]);
|
||||
end
|
||||
endgenerate
|
||||
assign Z = stage[$clog2(WIDTH)];
|
||||
|
||||
endmodule // shift_left
|
||||
|
||||
/* verilator lint_on DECLFILENAME */
|
||||
/* verilator lint_on UNOPTFLAT */
|
@ -78,9 +78,7 @@ module alu #(parameter WIDTH=32) (
|
||||
endcase
|
||||
|
||||
// support W-type RV64I ADDW/SUBW/ADDIW/Shifts that sign-extend 32-bit result to 64 bits
|
||||
generate
|
||||
if (WIDTH==64) assign Result = W64 ? {{32{FullResult[31]}}, FullResult[31:0]} : FullResult;
|
||||
else assign Result = FullResult;
|
||||
endgenerate
|
||||
if (WIDTH==64) assign Result = W64 ? {{32{FullResult[31]}}, FullResult[31:0]} : FullResult;
|
||||
else assign Result = FullResult;
|
||||
endmodule
|
||||
|
||||
|
@ -109,55 +109,53 @@ module controller(
|
||||
assign Rs1D = InstrD[19:15];
|
||||
|
||||
// Main Instruction Decoder
|
||||
generate
|
||||
always_comb
|
||||
case(OpD)
|
||||
// RegWrite_ImmSrc_ALUSrc_MemRW_ResultSrc_Branch_ALUOp_Jump_ALUResultSrc_W64_CSRRead_Privileged_Fence_MulDiv_Atomic_Illegal
|
||||
7'b0000000: ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // illegal instruction
|
||||
7'b0000011: ControlsD = `CTRLW'b1_000_01_10_001_0_0_0_0_0_0_0_0_0_00_0; // lw
|
||||
7'b0000111: ControlsD = `CTRLW'b0_000_01_10_001_0_0_0_0_0_0_0_0_0_00_0; // flw
|
||||
7'b0001111: ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_1_0_00_0; // fence
|
||||
7'b0010011: ControlsD = `CTRLW'b1_000_01_00_000_0_1_0_0_0_0_0_0_0_00_0; // I-type ALU
|
||||
7'b0010111: ControlsD = `CTRLW'b1_100_11_00_000_0_0_0_0_0_0_0_0_0_00_0; // auipc
|
||||
7'b0011011: if (`XLEN == 64)
|
||||
ControlsD = `CTRLW'b1_000_01_00_000_0_1_0_0_1_0_0_0_0_00_0; // IW-type ALU for RV64i
|
||||
else
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
7'b0100011: ControlsD = `CTRLW'b0_001_01_01_000_0_0_0_0_0_0_0_0_0_00_0; // sw
|
||||
7'b0100111: ControlsD = `CTRLW'b0_001_01_01_000_0_0_0_0_0_0_0_0_0_00_0; // fsw
|
||||
7'b0101111: if (`A_SUPPORTED) begin
|
||||
if (InstrD[31:27] == 5'b00010)
|
||||
ControlsD = `CTRLW'b1_000_00_10_001_0_0_0_0_0_0_0_0_0_01_0; // lr
|
||||
else if (InstrD[31:27] == 5'b00011)
|
||||
ControlsD = `CTRLW'b1_101_01_01_100_0_0_0_0_0_0_0_0_0_01_0; // sc
|
||||
else
|
||||
ControlsD = `CTRLW'b1_101_01_11_001_0_0_0_0_0_0_0_0_0_10_0;; // amo
|
||||
end else
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
7'b0110011: if (Funct7D == 7'b0000000 | Funct7D == 7'b0100000)
|
||||
ControlsD = `CTRLW'b1_000_00_00_000_0_1_0_0_0_0_0_0_0_00_0; // R-type
|
||||
else if (Funct7D == 7'b0000001 & `M_SUPPORTED)
|
||||
ControlsD = `CTRLW'b1_000_00_00_011_0_0_0_0_0_0_0_0_1_00_0; // Multiply/Divide
|
||||
else
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
7'b0110111: ControlsD = `CTRLW'b1_100_01_00_000_0_0_0_1_0_0_0_0_0_00_0; // lui
|
||||
7'b0111011: if ((Funct7D == 7'b0000000 | Funct7D == 7'b0100000) & `XLEN == 64)
|
||||
ControlsD = `CTRLW'b1_000_00_00_000_0_1_0_0_1_0_0_0_0_00_0; // R-type W instructions for RV64i
|
||||
else if (Funct7D == 7'b0000001 & `M_SUPPORTED & `XLEN == 64)
|
||||
ControlsD = `CTRLW'b1_000_00_00_011_0_0_0_0_1_0_0_0_1_00_0; // W-type Multiply/Divide
|
||||
else
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
//7'b1010011: ControlsD = `CTRLW'b0_000_00_00_101_0_00_0_0_0_0_0_0_0_00_1; // FP
|
||||
7'b1100011: ControlsD = `CTRLW'b0_010_11_00_000_1_0_0_0_0_0_0_0_0_00_0; // branches
|
||||
7'b1100111: ControlsD = `CTRLW'b1_000_01_00_000_0_0_1_1_0_0_0_0_0_00_0; // jalr
|
||||
7'b1101111: ControlsD = `CTRLW'b1_011_11_00_000_0_0_1_1_0_0_0_0_0_00_0; // jal
|
||||
7'b1110011: if (Funct3D == 3'b000)
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_1_0_0_00_0; // privileged; decoded further in priveleged modules
|
||||
else
|
||||
ControlsD = `CTRLW'b1_000_00_00_010_0_0_0_0_0_1_0_0_0_00_0; // csrs
|
||||
default: ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
endcase
|
||||
endgenerate
|
||||
always_comb
|
||||
case(OpD)
|
||||
// RegWrite_ImmSrc_ALUSrc_MemRW_ResultSrc_Branch_ALUOp_Jump_ALUResultSrc_W64_CSRRead_Privileged_Fence_MulDiv_Atomic_Illegal
|
||||
7'b0000000: ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // illegal instruction
|
||||
7'b0000011: ControlsD = `CTRLW'b1_000_01_10_001_0_0_0_0_0_0_0_0_0_00_0; // lw
|
||||
7'b0000111: ControlsD = `CTRLW'b0_000_01_10_001_0_0_0_0_0_0_0_0_0_00_0; // flw
|
||||
7'b0001111: ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_1_0_00_0; // fence
|
||||
7'b0010011: ControlsD = `CTRLW'b1_000_01_00_000_0_1_0_0_0_0_0_0_0_00_0; // I-type ALU
|
||||
7'b0010111: ControlsD = `CTRLW'b1_100_11_00_000_0_0_0_0_0_0_0_0_0_00_0; // auipc
|
||||
7'b0011011: if (`XLEN == 64)
|
||||
ControlsD = `CTRLW'b1_000_01_00_000_0_1_0_0_1_0_0_0_0_00_0; // IW-type ALU for RV64i
|
||||
else
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
7'b0100011: ControlsD = `CTRLW'b0_001_01_01_000_0_0_0_0_0_0_0_0_0_00_0; // sw
|
||||
7'b0100111: ControlsD = `CTRLW'b0_001_01_01_000_0_0_0_0_0_0_0_0_0_00_0; // fsw
|
||||
7'b0101111: if (`A_SUPPORTED) begin
|
||||
if (InstrD[31:27] == 5'b00010)
|
||||
ControlsD = `CTRLW'b1_000_00_10_001_0_0_0_0_0_0_0_0_0_01_0; // lr
|
||||
else if (InstrD[31:27] == 5'b00011)
|
||||
ControlsD = `CTRLW'b1_101_01_01_100_0_0_0_0_0_0_0_0_0_01_0; // sc
|
||||
else
|
||||
ControlsD = `CTRLW'b1_101_01_11_001_0_0_0_0_0_0_0_0_0_10_0;; // amo
|
||||
end else
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
7'b0110011: if (Funct7D == 7'b0000000 | Funct7D == 7'b0100000)
|
||||
ControlsD = `CTRLW'b1_000_00_00_000_0_1_0_0_0_0_0_0_0_00_0; // R-type
|
||||
else if (Funct7D == 7'b0000001 & `M_SUPPORTED)
|
||||
ControlsD = `CTRLW'b1_000_00_00_011_0_0_0_0_0_0_0_0_1_00_0; // Multiply/Divide
|
||||
else
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
7'b0110111: ControlsD = `CTRLW'b1_100_01_00_000_0_0_0_1_0_0_0_0_0_00_0; // lui
|
||||
7'b0111011: if ((Funct7D == 7'b0000000 | Funct7D == 7'b0100000) & `XLEN == 64)
|
||||
ControlsD = `CTRLW'b1_000_00_00_000_0_1_0_0_1_0_0_0_0_00_0; // R-type W instructions for RV64i
|
||||
else if (Funct7D == 7'b0000001 & `M_SUPPORTED & `XLEN == 64)
|
||||
ControlsD = `CTRLW'b1_000_00_00_011_0_0_0_0_1_0_0_0_1_00_0; // W-type Multiply/Divide
|
||||
else
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
//7'b1010011: ControlsD = `CTRLW'b0_000_00_00_101_0_00_0_0_0_0_0_0_0_00_1; // FP
|
||||
7'b1100011: ControlsD = `CTRLW'b0_010_11_00_000_1_0_0_0_0_0_0_0_0_00_0; // branches
|
||||
7'b1100111: ControlsD = `CTRLW'b1_000_01_00_000_0_0_1_1_0_0_0_0_0_00_0; // jalr
|
||||
7'b1101111: ControlsD = `CTRLW'b1_011_11_00_000_0_0_1_1_0_0_0_0_0_00_0; // jal
|
||||
7'b1110011: if (Funct3D == 3'b000)
|
||||
ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_1_0_0_00_0; // privileged; decoded further in priveleged modules
|
||||
else
|
||||
ControlsD = `CTRLW'b1_000_00_00_010_0_0_0_0_0_1_0_0_0_00_0; // csrs
|
||||
default: ControlsD = `CTRLW'b0_000_00_00_000_0_0_0_0_0_0_0_0_0_00_1; // non-implemented instruction
|
||||
endcase
|
||||
|
||||
// unswizzle control bits
|
||||
// squash control signals if coming from an illegal compressed instruction
|
||||
@ -181,17 +179,15 @@ module controller(
|
||||
// Fences
|
||||
// Ordinary fence is presently a nop
|
||||
// FENCE.I flushes the D$ and invalidates the I$ if Zifencei is supported and I$ is implemented
|
||||
generate
|
||||
if (`ZIFENCEI_SUPPORTED & `MEM_ICACHE) begin:fencei
|
||||
logic FenceID;
|
||||
assign FenceID = FenceD & (Funct3D == 3'b001); // is it a FENCE.I instruction?
|
||||
assign InvalidateICacheD = FenceID;
|
||||
assign FlushDCacheD = FenceID;
|
||||
end else begin:fencei
|
||||
assign InvalidateICacheD = 0;
|
||||
assign FlushDCacheD = 0;
|
||||
end
|
||||
endgenerate
|
||||
if (`ZIFENCEI_SUPPORTED & `MEM_ICACHE) begin:fencei
|
||||
logic FenceID;
|
||||
assign FenceID = FenceD & (Funct3D == 3'b001); // is it a FENCE.I instruction?
|
||||
assign InvalidateICacheD = FenceID;
|
||||
assign FlushDCacheD = FenceID;
|
||||
end else begin:fencei
|
||||
assign InvalidateICacheD = 0;
|
||||
assign FlushDCacheD = 0;
|
||||
end
|
||||
|
||||
// Decocde stage pipeline control register
|
||||
flopenrc #(1) controlregD(clk, reset, FlushD, ~StallD, 1'b1, InstrValidD);
|
||||
|
@ -124,19 +124,15 @@ module datapath (
|
||||
mux5 #(`XLEN) resultmuxW(ResultW, ReadDataW, CSRReadValW, MulDivResultW, SCResultW, ResultSrcW, WriteDataW);
|
||||
|
||||
// floating point interactions: fcvt, fp stores
|
||||
generate
|
||||
if (`F_SUPPORTED) begin:fpmux
|
||||
mux2 #(`XLEN) resultmuxM(IEUResultM, FIntResM, FWriteIntM, ResultM);
|
||||
mux2 #(`XLEN) writedatamux(ForwardedSrcBE, FWriteDataE, ~IllegalFPUInstrE, WriteDataE);
|
||||
end else begin:fpmux
|
||||
assign ResultM = IEUResultM;
|
||||
assign WriteDataE = ForwardedSrcBE;
|
||||
end
|
||||
endgenerate
|
||||
if (`F_SUPPORTED) begin:fpmux
|
||||
mux2 #(`XLEN) resultmuxM(IEUResultM, FIntResM, FWriteIntM, ResultM);
|
||||
mux2 #(`XLEN) writedatamux(ForwardedSrcBE, FWriteDataE, ~IllegalFPUInstrE, WriteDataE);
|
||||
end else begin:fpmux
|
||||
assign ResultM = IEUResultM;
|
||||
assign WriteDataE = ForwardedSrcBE;
|
||||
end
|
||||
|
||||
// handle Store Conditional result if atomic extension supported
|
||||
generate
|
||||
if (`A_SUPPORTED) assign SCResultW = {{(`XLEN-1){1'b0}}, SquashSCW};
|
||||
else assign SCResultW = 0;
|
||||
endgenerate
|
||||
if (`A_SUPPORTED) assign SCResultW = {{(`XLEN-1){1'b0}}, SquashSCW};
|
||||
else assign SCResultW = 0;
|
||||
endmodule
|
||||
|
@ -32,23 +32,24 @@ module extend (
|
||||
|
||||
localparam [`XLEN-1:0] undefined = {(`XLEN){1'bx}}; // could change to 0 after debug
|
||||
|
||||
// generate
|
||||
always_comb
|
||||
case(ImmSrcD)
|
||||
// I-type
|
||||
3'b000: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:20]};
|
||||
// S-type (stores)
|
||||
3'b001: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:25], InstrD[11:7]};
|
||||
// B-type (branches)
|
||||
3'b010: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[7], InstrD[30:25], InstrD[11:8], 1'b0};
|
||||
// J-type (jal)
|
||||
3'b011: ExtImmD = {{(`XLEN-20){InstrD[31]}}, InstrD[19:12], InstrD[20], InstrD[30:21], 1'b0};
|
||||
// U-type (lui, auipc)
|
||||
3'b100: ExtImmD = {{(`XLEN-31){InstrD[31]}}, InstrD[30:12], 12'b0};
|
||||
// Store Conditional: zero offset
|
||||
3'b101: if (`A_SUPPORTED) ExtImmD = 0;
|
||||
else ExtImmD = undefined;
|
||||
default: ExtImmD = undefined; // undefined
|
||||
endcase
|
||||
// endgenerate
|
||||
always_comb
|
||||
case(ImmSrcD)
|
||||
// I-type
|
||||
3'b000: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:20]};
|
||||
// S-type (stores)
|
||||
3'b001: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:25], InstrD[11:7]};
|
||||
// B-type (branches)
|
||||
3'b010: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[7], InstrD[30:25], InstrD[11:8], 1'b0};
|
||||
// J-type (jal)
|
||||
3'b011: ExtImmD = {{(`XLEN-20){InstrD[31]}}, InstrD[19:12], InstrD[20], InstrD[30:21], 1'b0};
|
||||
// U-type (lui, auipc)
|
||||
3'b100: ExtImmD = {{(`XLEN-31){InstrD[31]}}, InstrD[30:12], 12'b0};
|
||||
// Store Conditional: zero offset
|
||||
3'b101: if (`A_SUPPORTED) ExtImmD = 0;
|
||||
else ExtImmD = undefined;
|
||||
default: begin
|
||||
ExtImmD = undefined; // undefined
|
||||
$error("Invalid ImmSrcD in extend");
|
||||
end
|
||||
endcase
|
||||
endmodule
|
||||
|
@ -39,7 +39,7 @@ module shifter (
|
||||
// For RV64, 32 and 64-bit shifts are needed, with sign extension.
|
||||
|
||||
// funnel shifter input (see CMOS VLSI Design 4e Section 11.8.1, note Table 11.11 shift types wrong)
|
||||
generate
|
||||
// generate
|
||||
if (`XLEN==32) begin:shifter // RV32
|
||||
always_comb // funnel mux
|
||||
if (Right)
|
||||
@ -62,7 +62,7 @@ module shifter (
|
||||
end
|
||||
assign amttrunc = W64 ? {1'b0, Amt[4:0]} : Amt; // 32 or 64-bit shift
|
||||
end
|
||||
endgenerate
|
||||
// endgenerate
|
||||
|
||||
// opposite offset for right shfits
|
||||
assign offset = Right ? amttrunc : ~amttrunc;
|
||||
|
@ -92,20 +92,17 @@ module SRAM2P1R1W
|
||||
.q(WD1Q));
|
||||
// read port
|
||||
assign RD1 = mem[RA1Q];
|
||||
|
||||
genvar index;
|
||||
|
||||
// write port
|
||||
generate
|
||||
for (index = 0; index < WIDTH; index = index + 1) begin:bitwrite
|
||||
always_ff @ (posedge clk) begin
|
||||
if (WEN1Q & BitWEN1[index]) begin
|
||||
mem[WA1Q][index] <= WD1Q[index];
|
||||
end
|
||||
genvar index;
|
||||
for (index = 0; index < WIDTH; index = index + 1) begin:bitwrite
|
||||
always_ff @(posedge clk) begin
|
||||
if (WEN1Q & BitWEN1[index]) begin
|
||||
mem[WA1Q][index] <= WD1Q[index];
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
|
@ -38,141 +38,139 @@ module decompress (
|
||||
logic [1:0] op;
|
||||
|
||||
// if the system handles compressed instructions, decode appropriately
|
||||
generate
|
||||
if (!(`C_SUPPORTED)) begin:decompress // no compressed mode
|
||||
assign InstrD = InstrRawD;
|
||||
assign IllegalCompInstrD = 0;
|
||||
end else begin : decompress // COMPRESSED mode supported
|
||||
assign instr16 = InstrRawD[15:0]; // instruction is alreay aligned
|
||||
assign op = instr16[1:0];
|
||||
assign rds1 = instr16[11:7];
|
||||
assign rs2 = instr16[6:2];
|
||||
assign rs1p = {2'b01, instr16[9:7]};
|
||||
assign rds1p = {2'b01, instr16[9:7]};
|
||||
assign rs2p = {2'b01, instr16[4:2]};
|
||||
assign rdp = {2'b01, instr16[4:2]};
|
||||
|
||||
// many compressed immediate formats
|
||||
assign immCILSP = {4'b0000, instr16[3:2], instr16[12], instr16[6:4], 2'b00};
|
||||
assign immCILSPD = {3'b000, instr16[4:2], instr16[12], instr16[6:5], 3'b000};
|
||||
assign immCSS = {4'b0000, instr16[8:7], instr16[12:9], 2'b00};
|
||||
assign immCSSD = {3'b000, instr16[9:7], instr16[12:10], 3'b000};
|
||||
assign immCL = {5'b0, instr16[5], instr16[12:10], instr16[6], 2'b00};
|
||||
assign immCLD = {4'b0, instr16[6:5], instr16[12:10], 3'b000};
|
||||
assign immCS = {5'b0, instr16[5], instr16[12:10], instr16[6], 2'b00};
|
||||
assign immCSD = {4'b0, instr16[6:5], instr16[12:10], 3'b000};
|
||||
assign immCJ = {instr16[12], instr16[8], instr16[10:9], instr16[6], instr16[7], instr16[2], instr16[11], instr16[5:3], {9{instr16[12]}}};
|
||||
assign immCB = {{4{instr16[12]}}, instr16[6:5], instr16[2], instr16[11:10], instr16[4:3], instr16[12]};
|
||||
assign immCI = {{7{instr16[12]}}, instr16[6:2]};
|
||||
assign immCILUI = {{15{instr16[12]}}, instr16[6:2]};
|
||||
assign immCIASP = {{3{instr16[12]}}, instr16[4:3], instr16[5], instr16[2], instr16[6], 4'b0000};
|
||||
assign immCIW = {2'b00, instr16[10:7], instr16[12:11], instr16[5], instr16[6], 2'b00};
|
||||
assign immSH = {instr16[12], instr16[6:2]};
|
||||
if (!(`C_SUPPORTED)) begin:decompress // no compressed mode
|
||||
assign InstrD = InstrRawD;
|
||||
assign IllegalCompInstrD = 0;
|
||||
end else begin : decompress // COMPRESSED mode supported
|
||||
assign instr16 = InstrRawD[15:0]; // instruction is alreay aligned
|
||||
assign op = instr16[1:0];
|
||||
assign rds1 = instr16[11:7];
|
||||
assign rs2 = instr16[6:2];
|
||||
assign rs1p = {2'b01, instr16[9:7]};
|
||||
assign rds1p = {2'b01, instr16[9:7]};
|
||||
assign rs2p = {2'b01, instr16[4:2]};
|
||||
assign rdp = {2'b01, instr16[4:2]};
|
||||
|
||||
// many compressed immediate formats
|
||||
assign immCILSP = {4'b0000, instr16[3:2], instr16[12], instr16[6:4], 2'b00};
|
||||
assign immCILSPD = {3'b000, instr16[4:2], instr16[12], instr16[6:5], 3'b000};
|
||||
assign immCSS = {4'b0000, instr16[8:7], instr16[12:9], 2'b00};
|
||||
assign immCSSD = {3'b000, instr16[9:7], instr16[12:10], 3'b000};
|
||||
assign immCL = {5'b0, instr16[5], instr16[12:10], instr16[6], 2'b00};
|
||||
assign immCLD = {4'b0, instr16[6:5], instr16[12:10], 3'b000};
|
||||
assign immCS = {5'b0, instr16[5], instr16[12:10], instr16[6], 2'b00};
|
||||
assign immCSD = {4'b0, instr16[6:5], instr16[12:10], 3'b000};
|
||||
assign immCJ = {instr16[12], instr16[8], instr16[10:9], instr16[6], instr16[7], instr16[2], instr16[11], instr16[5:3], {9{instr16[12]}}};
|
||||
assign immCB = {{4{instr16[12]}}, instr16[6:5], instr16[2], instr16[11:10], instr16[4:3], instr16[12]};
|
||||
assign immCI = {{7{instr16[12]}}, instr16[6:2]};
|
||||
assign immCILUI = {{15{instr16[12]}}, instr16[6:2]};
|
||||
assign immCIASP = {{3{instr16[12]}}, instr16[4:3], instr16[5], instr16[2], instr16[6], 4'b0000};
|
||||
assign immCIW = {2'b00, instr16[10:7], instr16[12:11], instr16[5], instr16[6], 2'b00};
|
||||
assign immSH = {instr16[12], instr16[6:2]};
|
||||
|
||||
// only for RV128
|
||||
// assign immCILSPQ = {2{instr16[5]}, instr16[5:2], instr16[12], instr16[6], 4'b0000};
|
||||
// assign immCSSQ = {2{instr16[10]}, instr16[10:7], instr16[12:11], 4'b0000};
|
||||
// assign immCLQ = {4{instr16[10]}, instr16[6:5], instr16[12:11], 4'b0000};
|
||||
// assign immCSQ = {4{instr16[10]}, instr16[6:5], instr16[12:11], 4'b0000};
|
||||
|
||||
always_comb
|
||||
if (op == 2'b11) begin // noncompressed instruction
|
||||
InstrD = InstrRawD;
|
||||
IllegalCompInstrD = 0;
|
||||
end else begin // convert compressed instruction into uncompressed
|
||||
IllegalCompInstrD = 0;
|
||||
case ({op, instr16[15:13]})
|
||||
5'b00000: if (immCIW != 0) InstrD = {immCIW, 5'b00010, 3'b000, rdp, 7'b0010011}; // c.addi4spn
|
||||
else begin // illegal instruction
|
||||
|
||||
always_comb
|
||||
if (op == 2'b11) begin // noncompressed instruction
|
||||
InstrD = InstrRawD;
|
||||
IllegalCompInstrD = 0;
|
||||
end else begin // convert compressed instruction into uncompressed
|
||||
IllegalCompInstrD = 0;
|
||||
case ({op, instr16[15:13]})
|
||||
5'b00000: if (immCIW != 0) InstrD = {immCIW, 5'b00010, 3'b000, rdp, 7'b0010011}; // c.addi4spn
|
||||
else begin // illegal instruction
|
||||
IllegalCompInstrD = 1;
|
||||
InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap
|
||||
end
|
||||
5'b00001: InstrD = {immCLD, rs1p, 3'b011, rdp, 7'b0000111}; // c.fld
|
||||
5'b00010: InstrD = {immCL, rs1p, 3'b010, rdp, 7'b0000011}; // c.lw
|
||||
5'b00011: if (`XLEN==32)
|
||||
InstrD = {immCL, rs1p, 3'b010, rdp, 7'b0000111}; // c.flw
|
||||
else
|
||||
InstrD = {immCLD, rs1p, 3'b011, rdp, 7'b0000011}; // c.ld;
|
||||
5'b00101: InstrD = {immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100111}; // c.fsd
|
||||
5'b00110: InstrD = {immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100011}; // c.sw
|
||||
5'b00111: if (`XLEN==32)
|
||||
InstrD = {immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100111}; // c.fsw
|
||||
else
|
||||
InstrD = {immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100011}; //c.sd
|
||||
5'b01000: InstrD = {immCI, rds1, 3'b000, rds1, 7'b0010011}; // c.addi
|
||||
5'b01001: if (`XLEN==32)
|
||||
InstrD = {immCJ, 5'b00001, 7'b1101111}; // c.jal
|
||||
else
|
||||
InstrD = {immCI, rds1, 3'b000, rds1, 7'b0011011}; // c.addiw
|
||||
5'b01010: InstrD = {immCI, 5'b00000, 3'b000, rds1, 7'b0010011}; // c.li
|
||||
5'b01011: if (rds1 != 5'b00010)
|
||||
InstrD = {immCILUI, rds1, 7'b0110111}; // c.lui
|
||||
else
|
||||
InstrD = {immCIASP, rds1, 3'b000, rds1, 7'b0010011}; // c.addi16sp
|
||||
5'b01100: if (instr16[11:10] == 2'b00)
|
||||
InstrD = {6'b000000, immSH, rds1p, 3'b101, rds1p, 7'b0010011}; // c.srli
|
||||
else if (instr16[11:10] == 2'b01)
|
||||
InstrD = {6'b010000, immSH, rds1p, 3'b101, rds1p, 7'b0010011}; // c.srai
|
||||
else if (instr16[11:10] == 2'b10)
|
||||
InstrD = {immCI, rds1p, 3'b111, rds1p, 7'b0010011}; // c.andi
|
||||
else if (instr16[12:10] == 3'b011)
|
||||
if (instr16[6:5] == 2'b00)
|
||||
InstrD = {7'b0100000, rs2p, rds1p, 3'b000, rds1p, 7'b0110011}; // c.sub
|
||||
else if (instr16[6:5] == 2'b01)
|
||||
InstrD = {7'b0000000, rs2p, rds1p, 3'b100, rds1p, 7'b0110011}; // c.xor
|
||||
else if (instr16[6:5] == 2'b10)
|
||||
InstrD = {7'b0000000, rs2p, rds1p, 3'b110, rds1p, 7'b0110011}; // c.or
|
||||
else // if (instr16[6:5] == 2'b11)
|
||||
InstrD = {7'b0000000, rs2p, rds1p, 3'b111, rds1p, 7'b0110011}; // c.and
|
||||
else if (instr16[12:10] == 3'b111 & `XLEN > 32)
|
||||
if (instr16[6:5] == 2'b00)
|
||||
InstrD = {7'b0100000, rs2p, rds1p, 3'b000, rds1p, 7'b0111011}; // c.subw
|
||||
else if (instr16[6:5] == 2'b01)
|
||||
InstrD = {7'b0000000, rs2p, rds1p, 3'b000, rds1p, 7'b0111011}; // c.addw
|
||||
else begin // reserved
|
||||
IllegalCompInstrD = 1;
|
||||
InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap
|
||||
end
|
||||
5'b00001: InstrD = {immCLD, rs1p, 3'b011, rdp, 7'b0000111}; // c.fld
|
||||
5'b00010: InstrD = {immCL, rs1p, 3'b010, rdp, 7'b0000011}; // c.lw
|
||||
5'b00011: if (`XLEN==32)
|
||||
InstrD = {immCL, rs1p, 3'b010, rdp, 7'b0000111}; // c.flw
|
||||
else begin // illegal instruction
|
||||
IllegalCompInstrD = 1;
|
||||
InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap
|
||||
end
|
||||
5'b01101: InstrD = {immCJ, 5'b00000, 7'b1101111}; // c.j
|
||||
5'b01110: InstrD = {immCB[11:5], 5'b00000, rs1p, 3'b000, immCB[4:0], 7'b1100011}; // c.beqz
|
||||
5'b01111: InstrD = {immCB[11:5], 5'b00000, rs1p, 3'b001, immCB[4:0], 7'b1100011}; // c.bnez
|
||||
5'b10000: InstrD = {6'b000000, immSH, rds1, 3'b001, rds1, 7'b0010011}; // c.slli
|
||||
5'b10001: InstrD = {immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000111}; // c.fldsp
|
||||
5'b10010: InstrD = {immCILSP, 5'b00010, 3'b010, rds1, 7'b0000011}; // c.lwsp
|
||||
5'b10011: if (`XLEN == 32)
|
||||
InstrD = {immCILSP, 5'b00010, 3'b010, rds1, 7'b0000111}; // c.flwsp
|
||||
else
|
||||
InstrD = {immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000011}; // c.ldsp
|
||||
5'b10100: if (instr16[12] == 0)
|
||||
if (instr16[6:2] == 5'b00000)
|
||||
InstrD = {7'b0000000, 5'b00000, rds1, 3'b000, 5'b00000, 7'b1100111}; // c.jr
|
||||
else
|
||||
InstrD = {immCLD, rs1p, 3'b011, rdp, 7'b0000011}; // c.ld;
|
||||
5'b00101: InstrD = {immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100111}; // c.fsd
|
||||
5'b00110: InstrD = {immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100011}; // c.sw
|
||||
5'b00111: if (`XLEN==32)
|
||||
InstrD = {immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100111}; // c.fsw
|
||||
else
|
||||
InstrD = {immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100011}; //c.sd
|
||||
5'b01000: InstrD = {immCI, rds1, 3'b000, rds1, 7'b0010011}; // c.addi
|
||||
5'b01001: if (`XLEN==32)
|
||||
InstrD = {immCJ, 5'b00001, 7'b1101111}; // c.jal
|
||||
else
|
||||
InstrD = {immCI, rds1, 3'b000, rds1, 7'b0011011}; // c.addiw
|
||||
5'b01010: InstrD = {immCI, 5'b00000, 3'b000, rds1, 7'b0010011}; // c.li
|
||||
5'b01011: if (rds1 != 5'b00010)
|
||||
InstrD = {immCILUI, rds1, 7'b0110111}; // c.lui
|
||||
else
|
||||
InstrD = {immCIASP, rds1, 3'b000, rds1, 7'b0010011}; // c.addi16sp
|
||||
5'b01100: if (instr16[11:10] == 2'b00)
|
||||
InstrD = {6'b000000, immSH, rds1p, 3'b101, rds1p, 7'b0010011}; // c.srli
|
||||
else if (instr16[11:10] == 2'b01)
|
||||
InstrD = {6'b010000, immSH, rds1p, 3'b101, rds1p, 7'b0010011}; // c.srai
|
||||
else if (instr16[11:10] == 2'b10)
|
||||
InstrD = {immCI, rds1p, 3'b111, rds1p, 7'b0010011}; // c.andi
|
||||
else if (instr16[12:10] == 3'b011)
|
||||
if (instr16[6:5] == 2'b00)
|
||||
InstrD = {7'b0100000, rs2p, rds1p, 3'b000, rds1p, 7'b0110011}; // c.sub
|
||||
else if (instr16[6:5] == 2'b01)
|
||||
InstrD = {7'b0000000, rs2p, rds1p, 3'b100, rds1p, 7'b0110011}; // c.xor
|
||||
else if (instr16[6:5] == 2'b10)
|
||||
InstrD = {7'b0000000, rs2p, rds1p, 3'b110, rds1p, 7'b0110011}; // c.or
|
||||
else // if (instr16[6:5] == 2'b11)
|
||||
InstrD = {7'b0000000, rs2p, rds1p, 3'b111, rds1p, 7'b0110011}; // c.and
|
||||
else if (instr16[12:10] == 3'b111 & `XLEN > 32)
|
||||
if (instr16[6:5] == 2'b00)
|
||||
InstrD = {7'b0100000, rs2p, rds1p, 3'b000, rds1p, 7'b0111011}; // c.subw
|
||||
else if (instr16[6:5] == 2'b01)
|
||||
InstrD = {7'b0000000, rs2p, rds1p, 3'b000, rds1p, 7'b0111011}; // c.addw
|
||||
else begin // reserved
|
||||
IllegalCompInstrD = 1;
|
||||
InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap
|
||||
end
|
||||
else begin // illegal instruction
|
||||
IllegalCompInstrD = 1;
|
||||
InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap
|
||||
end
|
||||
5'b01101: InstrD = {immCJ, 5'b00000, 7'b1101111}; // c.j
|
||||
5'b01110: InstrD = {immCB[11:5], 5'b00000, rs1p, 3'b000, immCB[4:0], 7'b1100011}; // c.beqz
|
||||
5'b01111: InstrD = {immCB[11:5], 5'b00000, rs1p, 3'b001, immCB[4:0], 7'b1100011}; // c.bnez
|
||||
5'b10000: InstrD = {6'b000000, immSH, rds1, 3'b001, rds1, 7'b0010011}; // c.slli
|
||||
5'b10001: InstrD = {immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000111}; // c.fldsp
|
||||
5'b10010: InstrD = {immCILSP, 5'b00010, 3'b010, rds1, 7'b0000011}; // c.lwsp
|
||||
5'b10011: if (`XLEN == 32)
|
||||
InstrD = {immCILSP, 5'b00010, 3'b010, rds1, 7'b0000111}; // c.flwsp
|
||||
else
|
||||
InstrD = {immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000011}; // c.ldsp
|
||||
5'b10100: if (instr16[12] == 0)
|
||||
if (instr16[6:2] == 5'b00000)
|
||||
InstrD = {7'b0000000, 5'b00000, rds1, 3'b000, 5'b00000, 7'b1100111}; // c.jr
|
||||
InstrD = {7'b0000000, rs2, 5'b00000, 3'b000, rds1, 7'b0110011}; // c.mv
|
||||
else
|
||||
if (rs2 == 5'b00000)
|
||||
if (rds1 == 5'b00000)
|
||||
InstrD = {12'b1, 5'b00000, 3'b000, 5'b00000, 7'b1110011}; // c.ebreak
|
||||
else
|
||||
InstrD = {7'b0000000, rs2, 5'b00000, 3'b000, rds1, 7'b0110011}; // c.mv
|
||||
InstrD = {12'b0, rds1, 3'b000, 5'b00001, 7'b1100111}; // c.jalr
|
||||
else
|
||||
if (rs2 == 5'b00000)
|
||||
if (rds1 == 5'b00000)
|
||||
InstrD = {12'b1, 5'b00000, 3'b000, 5'b00000, 7'b1110011}; // c.ebreak
|
||||
else
|
||||
InstrD = {12'b0, rds1, 3'b000, 5'b00001, 7'b1100111}; // c.jalr
|
||||
else
|
||||
InstrD = {7'b0000000, rs2, rds1, 3'b000, rds1, 7'b0110011}; // c.add
|
||||
5'b10101: InstrD = {immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100111}; // c.fsdsp
|
||||
5'b10110: InstrD = {immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100011}; // c.swsp
|
||||
5'b10111: if (`XLEN==32)
|
||||
InstrD = {immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100111}; // c.fswsp
|
||||
else
|
||||
InstrD = {immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100011}; // c.sdsp
|
||||
default: begin // illegal instruction
|
||||
IllegalCompInstrD = 1;
|
||||
InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
InstrD = {7'b0000000, rs2, rds1, 3'b000, rds1, 7'b0110011}; // c.add
|
||||
5'b10101: InstrD = {immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100111}; // c.fsdsp
|
||||
5'b10110: InstrD = {immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100011}; // c.swsp
|
||||
5'b10111: if (`XLEN==32)
|
||||
InstrD = {immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100111}; // c.fswsp
|
||||
else
|
||||
InstrD = {immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100011}; // c.sdsp
|
||||
default: begin // illegal instruction
|
||||
IllegalCompInstrD = 1;
|
||||
InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
|
@ -38,77 +38,75 @@ module subwordread
|
||||
// Funct3M[2] is the unsigned bit. mask upper bits.
|
||||
// Funct3M[1:0] is the size of the memory access.
|
||||
|
||||
generate
|
||||
if (`XLEN == 64) begin:swrmux
|
||||
// ByteMe mux
|
||||
always_comb
|
||||
case(LsuPAdrM[2:0])
|
||||
3'b000: ByteM = ReadDataWordMuxM[7:0];
|
||||
3'b001: ByteM = ReadDataWordMuxM[15:8];
|
||||
3'b010: ByteM = ReadDataWordMuxM[23:16];
|
||||
3'b011: ByteM = ReadDataWordMuxM[31:24];
|
||||
3'b100: ByteM = ReadDataWordMuxM[39:32];
|
||||
3'b101: ByteM = ReadDataWordMuxM[47:40];
|
||||
3'b110: ByteM = ReadDataWordMuxM[55:48];
|
||||
3'b111: ByteM = ReadDataWordMuxM[63:56];
|
||||
endcase
|
||||
if (`XLEN == 64) begin:swrmux
|
||||
// ByteMe mux
|
||||
always_comb
|
||||
case(LsuPAdrM[2:0])
|
||||
3'b000: ByteM = ReadDataWordMuxM[7:0];
|
||||
3'b001: ByteM = ReadDataWordMuxM[15:8];
|
||||
3'b010: ByteM = ReadDataWordMuxM[23:16];
|
||||
3'b011: ByteM = ReadDataWordMuxM[31:24];
|
||||
3'b100: ByteM = ReadDataWordMuxM[39:32];
|
||||
3'b101: ByteM = ReadDataWordMuxM[47:40];
|
||||
3'b110: ByteM = ReadDataWordMuxM[55:48];
|
||||
3'b111: ByteM = ReadDataWordMuxM[63:56];
|
||||
endcase
|
||||
|
||||
// halfword mux
|
||||
always_comb
|
||||
case(LsuPAdrM[2:1])
|
||||
2'b00: HalfwordM = ReadDataWordMuxM[15:0];
|
||||
2'b01: HalfwordM = ReadDataWordMuxM[31:16];
|
||||
2'b10: HalfwordM = ReadDataWordMuxM[47:32];
|
||||
2'b11: HalfwordM = ReadDataWordMuxM[63:48];
|
||||
endcase
|
||||
|
||||
// halfword mux
|
||||
always_comb
|
||||
case(LsuPAdrM[2:1])
|
||||
2'b00: HalfwordM = ReadDataWordMuxM[15:0];
|
||||
2'b01: HalfwordM = ReadDataWordMuxM[31:16];
|
||||
2'b10: HalfwordM = ReadDataWordMuxM[47:32];
|
||||
2'b11: HalfwordM = ReadDataWordMuxM[63:48];
|
||||
endcase
|
||||
|
||||
logic [31:0] WordM;
|
||||
|
||||
always_comb
|
||||
case(LsuPAdrM[2])
|
||||
1'b0: WordM = ReadDataWordMuxM[31:0];
|
||||
1'b1: WordM = ReadDataWordMuxM[63:32];
|
||||
endcase
|
||||
|
||||
// sign extension
|
||||
always_comb
|
||||
case(Funct3M)
|
||||
3'b000: ReadDataM = {{56{ByteM[7]}}, ByteM}; // lb
|
||||
3'b001: ReadDataM = {{48{HalfwordM[15]}}, HalfwordM[15:0]}; // lh
|
||||
3'b010: ReadDataM = {{32{WordM[31]}}, WordM[31:0]}; // lw
|
||||
3'b011: ReadDataM = ReadDataWordMuxM; // ld
|
||||
3'b100: ReadDataM = {56'b0, ByteM[7:0]}; // lbu
|
||||
3'b101: ReadDataM = {48'b0, HalfwordM[15:0]}; // lhu
|
||||
3'b110: ReadDataM = {32'b0, WordM[31:0]}; // lwu
|
||||
default: ReadDataM = ReadDataWordMuxM; // Shouldn't happen
|
||||
endcase
|
||||
end else begin :swrmux // 32-bit
|
||||
// byte mux
|
||||
always_comb
|
||||
case(LsuPAdrM[1:0])
|
||||
2'b00: ByteM = ReadDataWordMuxM[7:0];
|
||||
2'b01: ByteM = ReadDataWordMuxM[15:8];
|
||||
2'b10: ByteM = ReadDataWordMuxM[23:16];
|
||||
2'b11: ByteM = ReadDataWordMuxM[31:24];
|
||||
endcase
|
||||
logic [31:0] WordM;
|
||||
|
||||
// halfword mux
|
||||
always_comb
|
||||
case(LsuPAdrM[1])
|
||||
1'b0: HalfwordM = ReadDataWordMuxM[15:0];
|
||||
1'b1: HalfwordM = ReadDataWordMuxM[31:16];
|
||||
always_comb
|
||||
case(LsuPAdrM[2])
|
||||
1'b0: WordM = ReadDataWordMuxM[31:0];
|
||||
1'b1: WordM = ReadDataWordMuxM[63:32];
|
||||
endcase
|
||||
|
||||
// sign extension
|
||||
always_comb
|
||||
case(Funct3M)
|
||||
3'b000: ReadDataM = {{24{ByteM[7]}}, ByteM}; // lb
|
||||
3'b001: ReadDataM = {{16{HalfwordM[15]}}, HalfwordM[15:0]}; // lh
|
||||
3'b010: ReadDataM = ReadDataWordMuxM; // lw
|
||||
3'b100: ReadDataM = {24'b0, ByteM[7:0]}; // lbu
|
||||
3'b101: ReadDataM = {16'b0, HalfwordM[15:0]}; // lhu
|
||||
default: ReadDataM = ReadDataWordMuxM;
|
||||
endcase
|
||||
end
|
||||
endgenerate
|
||||
// sign extension
|
||||
always_comb
|
||||
case(Funct3M)
|
||||
3'b000: ReadDataM = {{56{ByteM[7]}}, ByteM}; // lb
|
||||
3'b001: ReadDataM = {{48{HalfwordM[15]}}, HalfwordM[15:0]}; // lh
|
||||
3'b010: ReadDataM = {{32{WordM[31]}}, WordM[31:0]}; // lw
|
||||
3'b011: ReadDataM = ReadDataWordMuxM; // ld
|
||||
3'b100: ReadDataM = {56'b0, ByteM[7:0]}; // lbu
|
||||
3'b101: ReadDataM = {48'b0, HalfwordM[15:0]}; // lhu
|
||||
3'b110: ReadDataM = {32'b0, WordM[31:0]}; // lwu
|
||||
default: ReadDataM = ReadDataWordMuxM; // Shouldn't happen
|
||||
endcase
|
||||
end else begin:swrmux // 32-bit
|
||||
// byte mux
|
||||
always_comb
|
||||
case(LsuPAdrM[1:0])
|
||||
2'b00: ByteM = ReadDataWordMuxM[7:0];
|
||||
2'b01: ByteM = ReadDataWordMuxM[15:8];
|
||||
2'b10: ByteM = ReadDataWordMuxM[23:16];
|
||||
2'b11: ByteM = ReadDataWordMuxM[31:24];
|
||||
endcase
|
||||
|
||||
// halfword mux
|
||||
always_comb
|
||||
case(LsuPAdrM[1])
|
||||
1'b0: HalfwordM = ReadDataWordMuxM[15:0];
|
||||
1'b1: HalfwordM = ReadDataWordMuxM[31:16];
|
||||
endcase
|
||||
|
||||
// sign extension
|
||||
always_comb
|
||||
case(Funct3M)
|
||||
3'b000: ReadDataM = {{24{ByteM[7]}}, ByteM}; // lb
|
||||
3'b001: ReadDataM = {{16{HalfwordM[15]}}, HalfwordM[15:0]}; // lh
|
||||
3'b010: ReadDataM = ReadDataWordMuxM; // lw
|
||||
3'b100: ReadDataM = {24'b0, ByteM[7:0]}; // lbu
|
||||
3'b101: ReadDataM = {16'b0, HalfwordM[15:0]}; // lhu
|
||||
default: ReadDataM = ReadDataWordMuxM;
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
|
@ -52,7 +52,7 @@ module hptw
|
||||
L1_ADR, L1_RD,
|
||||
L2_ADR, L2_RD,
|
||||
L3_ADR, L3_RD,
|
||||
LEAF, IDLE} statetype; // *** placed outside generate statement to remove synthesis errors
|
||||
LEAF, IDLE} statetype;
|
||||
|
||||
logic DTLBWalk; // register TLBs translation miss requests
|
||||
logic [`PPN_BITS-1:0] BasePageTablePPN;
|
||||
|
@ -90,27 +90,25 @@ module mmu #(parameter TLB_ENTRIES = 8, // number of TLB Entries
|
||||
|
||||
|
||||
// only instantiate TLB if Virtual Memory is supported
|
||||
generate
|
||||
if (`MEM_VIRTMEM) begin:tlb
|
||||
logic ReadAccess, WriteAccess;
|
||||
assign ReadAccess = ExecuteAccessF | ReadAccessM; // execute also acts as a TLB read. Execute and Read are never active for the same MMU, so safe to mix pipestages
|
||||
assign WriteAccess = WriteAccessM;
|
||||
tlb #(.TLB_ENTRIES(TLB_ENTRIES), .ITLB(IMMU))
|
||||
tlb(.clk, .reset,
|
||||
.SATP_MODE(SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS]),
|
||||
.SATP_ASID(SATP_REGW[`ASID_BASE+`ASID_BITS-1:`ASID_BASE]),
|
||||
.VAdr, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess,
|
||||
.DisableTranslation, .PTE, .PageTypeWriteVal,
|
||||
.TLBWrite, .TLBFlush, .TLBPAdr, .TLBMiss, .TLBHit,
|
||||
.Translate, .TLBPageFault);
|
||||
end else begin:tlb// just pass address through as physical
|
||||
assign Translate = 0;
|
||||
assign TLBMiss = 0;
|
||||
assign TLBHit = 1; // *** is this necessary
|
||||
assign TLBPageFault = 0;
|
||||
end
|
||||
endgenerate
|
||||
if (`MEM_VIRTMEM) begin:tlb
|
||||
logic ReadAccess, WriteAccess;
|
||||
assign ReadAccess = ExecuteAccessF | ReadAccessM; // execute also acts as a TLB read. Execute and Read are never active for the same MMU, so safe to mix pipestages
|
||||
assign WriteAccess = WriteAccessM;
|
||||
tlb #(.TLB_ENTRIES(TLB_ENTRIES), .ITLB(IMMU))
|
||||
tlb(.clk, .reset,
|
||||
.SATP_MODE(SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS]),
|
||||
.SATP_ASID(SATP_REGW[`ASID_BASE+`ASID_BITS-1:`ASID_BASE]),
|
||||
.VAdr, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess,
|
||||
.DisableTranslation, .PTE, .PageTypeWriteVal,
|
||||
.TLBWrite, .TLBFlush, .TLBPAdr, .TLBMiss, .TLBHit,
|
||||
.Translate, .TLBPageFault);
|
||||
end else begin:tlb// just pass address through as physical
|
||||
assign Translate = 0;
|
||||
assign TLBMiss = 0;
|
||||
assign TLBHit = 1; // *** is this necessary
|
||||
assign TLBPageFault = 0;
|
||||
end
|
||||
|
||||
// If translation is occuring, select translated physical address from TLB
|
||||
mux2 #(`PA_BITS) addressmux(PAdr, TLBPAdr, Translate, PhysicalAddress);
|
||||
|
@ -68,7 +68,7 @@ module pmpadrdec (
|
||||
|
||||
assign NAMask[1:0] = {2'b11};
|
||||
assign NAMask[`PA_BITS-1:2] = (PMPAdr[`PA_BITS-3:0] + {{(`PA_BITS-3){1'b0}}, (AdrMode == NAPOT)}) ^ PMPAdr[`PA_BITS-3:0];
|
||||
// generates a mask where the bottom k bits are 1, corresponding to a size of 2^k bytes for this memory region.
|
||||
// form a mask where the bottom k bits are 1, corresponding to a size of 2^k bytes for this memory region.
|
||||
// This assumes we're using at least an NA4 region, but works for any size NAPOT region.
|
||||
assign NABase = {(PMPAdr[`PA_BITS-3:0] & ~NAMask[`PA_BITS-1:2]), 2'b00}; // base physical address of the pmp.
|
||||
|
||||
|
@ -47,37 +47,34 @@ module pmpchecker (
|
||||
output logic PMPStoreAccessFaultM
|
||||
);
|
||||
|
||||
generate
|
||||
if (`PMP_ENTRIES > 0) begin: pmpchecker
|
||||
// Bit i is high when the address falls in PMP region i
|
||||
logic EnforcePMP;
|
||||
logic [`PMP_ENTRIES-1:0] Match; // physical address matches one of the pmp ranges
|
||||
logic [`PMP_ENTRIES-1:0] FirstMatch; // onehot encoding for the first pmpaddr to match the current address.
|
||||
logic [`PMP_ENTRIES-1:0] Active; // PMP register i is non-null
|
||||
logic [`PMP_ENTRIES-1:0] L, X, W, R; // PMP matches and has flag set
|
||||
logic [`PMP_ENTRIES-1:0] PAgePMPAdr; // for TOR PMP matching, PhysicalAddress > PMPAdr[i]
|
||||
|
||||
pmpadrdec pmpadrdecs[`PMP_ENTRIES-1:0](
|
||||
.PhysicalAddress,
|
||||
.PMPCfg(PMPCFG_ARRAY_REGW),
|
||||
.PMPAdr(PMPADDR_ARRAY_REGW),
|
||||
.PAgePMPAdrIn({PAgePMPAdr[`PMP_ENTRIES-2:0], 1'b1}),
|
||||
.PAgePMPAdrOut(PAgePMPAdr),
|
||||
.FirstMatch, .Match, .Active, .L, .X, .W, .R);
|
||||
if (`PMP_ENTRIES > 0) begin: pmpchecker
|
||||
// Bit i is high when the address falls in PMP region i
|
||||
logic EnforcePMP;
|
||||
logic [`PMP_ENTRIES-1:0] Match; // physical address matches one of the pmp ranges
|
||||
logic [`PMP_ENTRIES-1:0] FirstMatch; // onehot encoding for the first pmpaddr to match the current address.
|
||||
logic [`PMP_ENTRIES-1:0] Active; // PMP register i is non-null
|
||||
logic [`PMP_ENTRIES-1:0] L, X, W, R; // PMP matches and has flag set
|
||||
logic [`PMP_ENTRIES-1:0] PAgePMPAdr; // for TOR PMP matching, PhysicalAddress > PMPAdr[i]
|
||||
|
||||
priorityonehot #(`PMP_ENTRIES) pmppriority(.a(Match), .y(FirstMatch)); // combine the match signal from all the adress decoders to find the first one that matches.
|
||||
pmpadrdec pmpadrdecs[`PMP_ENTRIES-1:0](
|
||||
.PhysicalAddress,
|
||||
.PMPCfg(PMPCFG_ARRAY_REGW),
|
||||
.PMPAdr(PMPADDR_ARRAY_REGW),
|
||||
.PAgePMPAdrIn({PAgePMPAdr[`PMP_ENTRIES-2:0], 1'b1}),
|
||||
.PAgePMPAdrOut(PAgePMPAdr),
|
||||
.FirstMatch, .Match, .Active, .L, .X, .W, .R);
|
||||
|
||||
// Only enforce PMP checking for S and U modes when at least one PMP is active or in Machine mode when L bit is set in selected region
|
||||
assign EnforcePMP = (PrivilegeModeW == `M_MODE) ? |L : |Active;
|
||||
priorityonehot #(`PMP_ENTRIES) pmppriority(.a(Match), .y(FirstMatch)); // combine the match signal from all the adress decoders to find the first one that matches.
|
||||
|
||||
assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~|X;
|
||||
assign PMPStoreAccessFaultM = EnforcePMP & WriteAccessM & ~|W;
|
||||
assign PMPLoadAccessFaultM = EnforcePMP & ReadAccessM & ~|R;
|
||||
end else begin: pmpchecker // no checker
|
||||
assign PMPInstrAccessFaultF = 0;
|
||||
assign PMPLoadAccessFaultM = 0;
|
||||
assign PMPStoreAccessFaultM = 0;
|
||||
end
|
||||
endgenerate
|
||||
//assign PMPSquashBusAccess = PMPInstrAccessFaultF | PMPLoadAccessFaultM | PMPStoreAccessFaultM;
|
||||
// Only enforce PMP checking for S and U modes when at least one PMP is active or in Machine mode when L bit is set in selected region
|
||||
assign EnforcePMP = (PrivilegeModeW == `M_MODE) ? |L : |Active;
|
||||
|
||||
assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~|X;
|
||||
assign PMPStoreAccessFaultM = EnforcePMP & WriteAccessM & ~|W;
|
||||
assign PMPLoadAccessFaultM = EnforcePMP & ReadAccessM & ~|R;
|
||||
end else begin: pmpchecker // no checker
|
||||
assign PMPInstrAccessFaultF = 0;
|
||||
assign PMPLoadAccessFaultM = 0;
|
||||
assign PMPStoreAccessFaultM = 0;
|
||||
end
|
||||
endmodule
|
||||
|
@ -34,25 +34,9 @@ module priorityonehot #(parameter ENTRIES = 8) (
|
||||
input logic [ENTRIES-1:0] a,
|
||||
output logic [ENTRIES-1:0] y
|
||||
);
|
||||
|
||||
/* verilator lint_off UNOPTFLAT */
|
||||
|
||||
logic [ENTRIES-1:0] nolower;
|
||||
|
||||
// generate thermometer code mask
|
||||
// create thermometer code mask
|
||||
prioritythermometer #(ENTRIES) maskgen(.a({a[ENTRIES-2:0], 1'b1}), .y(nolower));
|
||||
// genvar i;
|
||||
// generate
|
||||
// assign nolower[0] = 1'b1;
|
||||
// for (i=1; i<ENTRIES; i++) begin:therm
|
||||
// assign nolower[i] = nolower[i-1] & ~a[i-1];
|
||||
// end
|
||||
// endgenerate
|
||||
// *** replace mask generation logic ^^^ with priority thermometer
|
||||
|
||||
|
||||
assign y = a & nolower;
|
||||
|
||||
/* verilator lint_on UNOPTFLAT */
|
||||
|
||||
endmodule
|
||||
|
@ -37,20 +37,15 @@ module prioritythermometer #(parameter N = 8) (
|
||||
output logic [N-1:0] y
|
||||
);
|
||||
|
||||
// Carefully crafted so design compiler would synthesize into a fast tree structure
|
||||
// Carefully crafted so design compiler will synthesize into a fast tree structure
|
||||
// Rather than linear.
|
||||
|
||||
// generate thermometer code mask
|
||||
// create thermometer code mask
|
||||
genvar i;
|
||||
generate
|
||||
assign y[0] = a[0];
|
||||
for (i=1; i<N; i++) begin:therm
|
||||
assign y[i] = y[i-1] & ~a[i]; // *** made to be the same as onehot (without the inverter) to see if the probelme is something weird with synthesis
|
||||
// assign y[i] = y[i-1] & a[i];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
assign y[0] = a[0];
|
||||
for (i=1; i<N; i++) begin:therm
|
||||
assign y[i] = y[i-1] & ~a[i];
|
||||
end
|
||||
endmodule
|
||||
|
||||
|
||||
|
@ -60,38 +60,36 @@ module tlbcamline #(parameter KEY_BITS = 20,
|
||||
|
||||
assign MatchASID = (SATP_ASID == Key_ASID) | PTE_G;
|
||||
|
||||
generate
|
||||
if (`XLEN == 32) begin:match
|
||||
if (`XLEN == 32) begin: match
|
||||
|
||||
assign {Key_ASID, Key1, Key0} = Key;
|
||||
assign {Query1, Query0} = VPN;
|
||||
assign {Key_ASID, Key1, Key0} = Key;
|
||||
assign {Query1, Query0} = VPN;
|
||||
|
||||
// Calculate the actual match value based on the input vpn and the page type.
|
||||
// For example, a megapage in SV32 only cares about VPN[1], so VPN[0]
|
||||
// should automatically match.
|
||||
assign Match0 = (Query0 == Key0) | (PageType[0]); // least signifcant section
|
||||
assign Match1 = (Query1 == Key1);
|
||||
// Calculate the actual match value based on the input vpn and the page type.
|
||||
// For example, a megapage in SV32 only cares about VPN[1], so VPN[0]
|
||||
// should automatically match.
|
||||
assign Match0 = (Query0 == Key0) | (PageType[0]); // least signifcant section
|
||||
assign Match1 = (Query1 == Key1);
|
||||
|
||||
assign Match = Match0 & Match1 & MatchASID & Valid;
|
||||
end else begin:match
|
||||
assign Match = Match0 & Match1 & MatchASID & Valid;
|
||||
end else begin: match
|
||||
|
||||
logic [SEGMENT_BITS-1:0] Key2, Key3, Query2, Query3;
|
||||
logic Match2, Match3;
|
||||
logic [SEGMENT_BITS-1:0] Key2, Key3, Query2, Query3;
|
||||
logic Match2, Match3;
|
||||
|
||||
assign {Query3, Query2, Query1, Query0} = VPN;
|
||||
assign {Key_ASID, Key3, Key2, Key1, Key0} = Key;
|
||||
assign {Query3, Query2, Query1, Query0} = VPN;
|
||||
assign {Key_ASID, Key3, Key2, Key1, Key0} = Key;
|
||||
|
||||
// Calculate the actual match value based on the input vpn and the page type.
|
||||
// For example, a gigapage in SV39 only cares about VPN[2], so VPN[0] and VPN[1]
|
||||
// should automatically match.
|
||||
assign Match0 = (Query0 == Key0) | (PageType > 2'd0); // least signifcant section
|
||||
assign Match1 = (Query1 == Key1) | (PageType > 2'd1);
|
||||
assign Match2 = (Query2 == Key2) | (PageType > 2'd2);
|
||||
assign Match3 = (Query3 == Key3) | SV39Mode; // this should always match in sv39 because they aren't used
|
||||
|
||||
assign Match = Match0 & Match1 & Match2 & Match3 & MatchASID & Valid;
|
||||
end
|
||||
endgenerate
|
||||
// Calculate the actual match value based on the input vpn and the page type.
|
||||
// For example, a gigapage in SV39 only cares about VPN[2], so VPN[0] and VPN[1]
|
||||
// should automatically match.
|
||||
assign Match0 = (Query0 == Key0) | (PageType > 2'd0); // least signifcant section
|
||||
assign Match1 = (Query1 == Key1) | (PageType > 2'd1);
|
||||
assign Match2 = (Query2 == Key2) | (PageType > 2'd2);
|
||||
assign Match3 = (Query3 == Key3) | SV39Mode; // this should always match in sv39 because they aren't used
|
||||
|
||||
assign Match = Match0 & Match1 & Match2 & Match3 & MatchASID & Valid;
|
||||
end
|
||||
|
||||
// On a write, update the type of the page referred to by this line.
|
||||
flopenr #(2) pagetypeflop(clk, reset, WriteEnable, PageTypeWriteVal, PageType);
|
||||
|
@ -60,65 +60,59 @@ module tlbcontrol #(parameter ITLB = 0) (
|
||||
logic UpperBitsUnequalPageFault;
|
||||
logic DAPageFault;
|
||||
logic TLBAccess;
|
||||
logic ImproperPrivilege;
|
||||
|
||||
// Grab the sv mode from SATP and determine whether translation should occur
|
||||
assign EffectivePrivilegeMode = (ITLB == 1) ? PrivilegeModeW : (STATUS_MPRV ? STATUS_MPP : PrivilegeModeW); // DTLB uses MPP mode when MPRV is 1
|
||||
assign Translate = (SATP_MODE != `NO_TRANSLATE) & (EffectivePrivilegeMode != `M_MODE) & ~DisableTranslation;
|
||||
generate
|
||||
if (`XLEN==64) begin:rv64
|
||||
assign SV39Mode = (SATP_MODE == `SV39);
|
||||
// generate page fault if upper bits aren't all the same
|
||||
logic UpperEqual39, UpperEqual48;
|
||||
assign UpperEqual39 = &(VAdr[63:38]) | ~|(VAdr[63:38]);
|
||||
assign UpperEqual48 = &(VAdr[63:47]) | ~|(VAdr[63:47]);
|
||||
assign UpperBitsUnequalPageFault = SV39Mode ? ~UpperEqual39 : ~UpperEqual48;
|
||||
end else begin
|
||||
assign SV39Mode = 0;
|
||||
assign UpperBitsUnequalPageFault = 0;
|
||||
end
|
||||
endgenerate
|
||||
if (`XLEN==64) begin:rv64
|
||||
assign SV39Mode = (SATP_MODE == `SV39);
|
||||
// page fault if upper bits aren't all the same
|
||||
logic UpperEqual39, UpperEqual48;
|
||||
assign UpperEqual39 = &(VAdr[63:38]) | ~|(VAdr[63:38]);
|
||||
assign UpperEqual48 = &(VAdr[63:47]) | ~|(VAdr[63:47]);
|
||||
assign UpperBitsUnequalPageFault = SV39Mode ? ~UpperEqual39 : ~UpperEqual48;
|
||||
end else begin
|
||||
assign SV39Mode = 0;
|
||||
assign UpperBitsUnequalPageFault = 0;
|
||||
end
|
||||
|
||||
// Determine whether TLB is being used
|
||||
assign TLBAccess = ReadAccess | WriteAccess;
|
||||
|
||||
// Check whether upper bits of virtual addresss are all equal
|
||||
|
||||
|
||||
// unswizzle useful PTE bits
|
||||
assign {PTE_D, PTE_A} = PTEAccessBits[7:6];
|
||||
assign {PTE_U, PTE_X, PTE_W, PTE_R, PTE_V} = PTEAccessBits[4:0];
|
||||
|
||||
// Check whether the access is allowed, page faulting if not.
|
||||
generate
|
||||
if (ITLB == 1) begin:itlb // Instruction TLB fault checking
|
||||
logic ImproperPrivilege;
|
||||
if (ITLB == 1) begin:itlb // Instruction TLB fault checking
|
||||
// User mode may only execute user mode pages, and supervisor mode may
|
||||
// only execute non-user mode pages.
|
||||
assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) & ~PTE_U) |
|
||||
((EffectivePrivilegeMode == `S_MODE) & PTE_U);
|
||||
// fault for software handling if access bit is off
|
||||
assign DAPageFault = ~PTE_A;
|
||||
assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | ~PTE_X | DAPageFault | UpperBitsUnequalPageFault | Misaligned | ~PTE_V));
|
||||
end else begin:dtlb // Data TLB fault checking
|
||||
logic InvalidRead, InvalidWrite;
|
||||
|
||||
// User mode may only execute user mode pages, and supervisor mode may
|
||||
// only execute non-user mode pages.
|
||||
assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) & ~PTE_U) |
|
||||
((EffectivePrivilegeMode == `S_MODE) & PTE_U);
|
||||
// fault for software handling if access bit is off
|
||||
assign DAPageFault = ~PTE_A;
|
||||
assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | ~PTE_X | DAPageFault | UpperBitsUnequalPageFault | Misaligned | ~PTE_V));
|
||||
end else begin:dtlb // Data TLB fault checking
|
||||
logic ImproperPrivilege, InvalidRead, InvalidWrite;
|
||||
|
||||
// User mode may only load/store from user mode pages, and supervisor mode
|
||||
// may only access user mode pages when STATUS_SUM is low.
|
||||
assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) & ~PTE_U) |
|
||||
((EffectivePrivilegeMode == `S_MODE) & PTE_U & ~STATUS_SUM);
|
||||
// Check for read error. Reads are invalid when the page is not readable
|
||||
// (and executable pages are not readable) or when the page is neither
|
||||
// readable nor executable (and executable pages are readable).
|
||||
assign InvalidRead = ReadAccess & ~PTE_R & (~STATUS_MXR | ~PTE_X);
|
||||
// Check for write error. Writes are invalid when the page's write bit is
|
||||
// low.
|
||||
assign InvalidWrite = WriteAccess & ~PTE_W;
|
||||
// Fault for software handling if access bit is off or writing a page with dirty bit off
|
||||
assign DAPageFault = ~PTE_A | WriteAccess & ~PTE_D;
|
||||
assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | InvalidRead | InvalidWrite | DAPageFault | UpperBitsUnequalPageFault | Misaligned | ~PTE_V));
|
||||
end
|
||||
endgenerate
|
||||
// User mode may only load/store from user mode pages, and supervisor mode
|
||||
// may only access user mode pages when STATUS_SUM is low.
|
||||
assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) & ~PTE_U) |
|
||||
((EffectivePrivilegeMode == `S_MODE) & PTE_U & ~STATUS_SUM);
|
||||
// Check for read error. Reads are invalid when the page is not readable
|
||||
// (and executable pages are not readable) or when the page is neither
|
||||
// readable nor executable (and executable pages are readable).
|
||||
assign InvalidRead = ReadAccess & ~PTE_R & (~STATUS_MXR | ~PTE_X);
|
||||
// Check for write error. Writes are invalid when the page's write bit is
|
||||
// low.
|
||||
assign InvalidWrite = WriteAccess & ~PTE_W;
|
||||
// Fault for software handling if access bit is off or writing a page with dirty bit off
|
||||
assign DAPageFault = ~PTE_A | WriteAccess & ~PTE_D;
|
||||
assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | InvalidRead | InvalidWrite | DAPageFault | UpperBitsUnequalPageFault | Misaligned | ~PTE_V));
|
||||
end
|
||||
|
||||
assign TLBHit = CAMHit & TLBAccess;
|
||||
assign TLBMiss = (~CAMHit | TLBFlush) & Translate & TLBAccess;
|
||||
|
@ -43,18 +43,16 @@ module tlbmixer (
|
||||
logic [`PPN_BITS-1:0] PPNMixed;
|
||||
|
||||
// produce PageNumberMask with 1s where virtual page number bits should be untranslaetd for superpages
|
||||
generate
|
||||
if (`XLEN == 32)
|
||||
// kilopage: 22 bits of PPN, 0 bits of VPN
|
||||
// megapage: 12 bits of PPN, 10 bits of VPN
|
||||
mux2 #(22) pnm(22'h000000, 22'h0003FF, HitPageType[0], PageNumberMask);
|
||||
else
|
||||
// kilopage: 44 bits of PPN, 0 bits of VPN
|
||||
// megapage: 35 bits of PPN, 9 bits of VPN
|
||||
// gigapage: 26 bits of PPN, 18 bits of VPN
|
||||
// terapage: 17 bits of PPN, 27 bits of VPN
|
||||
mux4 #(44) pnm(44'h00000000000, 44'h000000001FF, 44'h0000003FFFF, 44'h00007FFFFFF, HitPageType, PageNumberMask);
|
||||
endgenerate
|
||||
if (`XLEN == 32)
|
||||
// kilopage: 22 bits of PPN, 0 bits of VPN
|
||||
// megapage: 12 bits of PPN, 10 bits of VPN
|
||||
mux2 #(22) pnm(22'h000000, 22'h0003FF, HitPageType[0], PageNumberMask);
|
||||
else
|
||||
// kilopage: 44 bits of PPN, 0 bits of VPN
|
||||
// megapage: 35 bits of PPN, 9 bits of VPN
|
||||
// gigapage: 26 bits of PPN, 18 bits of VPN
|
||||
// terapage: 17 bits of PPN, 27 bits of VPN
|
||||
mux4 #(44) pnm(44'h00000000000, 44'h000000001FF, 44'h0000003FFFF, 44'h00007FFFFFF, HitPageType, PageNumberMask);
|
||||
|
||||
// merge low segments of VPN with high segments of PPN decided by the pagetype.
|
||||
assign ZeroExtendedVPN = {{EXTRA_BITS{1'b0}}, VPN}; // forces the VPN to be the same width as PPN.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -60,15 +60,13 @@ module intdivrestoring (
|
||||
assign DivBusyE = (state == BUSY) | DivStartE;
|
||||
|
||||
// Handle sign extension for W-type instructions
|
||||
generate
|
||||
if (`XLEN == 64) begin:rv64 // RV64 has W-type instructions
|
||||
mux2 #(`XLEN) xinmux(ForwardedSrcAE, {ForwardedSrcAE[31:0], 32'b0}, W64E, XinE);
|
||||
mux2 #(`XLEN) dinmux(ForwardedSrcBE, {{32{ForwardedSrcBE[31]&DivSignedE}}, ForwardedSrcBE[31:0]}, W64E, DinE);
|
||||
end else begin // RV32 has no W-type instructions
|
||||
assign XinE = ForwardedSrcAE;
|
||||
assign DinE = ForwardedSrcBE;
|
||||
if (`XLEN == 64) begin:rv64 // RV64 has W-type instructions
|
||||
mux2 #(`XLEN) xinmux(ForwardedSrcAE, {ForwardedSrcAE[31:0], 32'b0}, W64E, XinE);
|
||||
mux2 #(`XLEN) dinmux(ForwardedSrcBE, {{32{ForwardedSrcBE[31]&DivSignedE}}, ForwardedSrcBE[31:0]}, W64E, DinE);
|
||||
end else begin // RV32 has no W-type instructions
|
||||
assign XinE = ForwardedSrcAE;
|
||||
assign DinE = ForwardedSrcBE;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Extract sign bits and check fo division by zero
|
||||
assign SignDE = DivSignedE & DinE[`XLEN-1];
|
||||
@ -97,11 +95,9 @@ module intdivrestoring (
|
||||
flopen #(3) Div0eMReg(clk, DivStartE, {Div0E, NegQE, SignXE}, {Div0M, NegQM, NegWM});
|
||||
|
||||
// one copy of divstep for each bit produced per cycle
|
||||
generate
|
||||
genvar i;
|
||||
for (i=0; i<`DIV_BITSPERCYCLE; i = i+1)
|
||||
intdivrestoringstep divstep(WM[i], XQM[i], DAbsBM, WM[i+1], XQM[i+1]);
|
||||
endgenerate
|
||||
genvar i;
|
||||
for (i=0; i<`DIV_BITSPERCYCLE; i = i+1)
|
||||
intdivrestoringstep divstep(WM[i], XQM[i], DAbsBM, WM[i+1], XQM[i+1]);
|
||||
|
||||
// On final setp of signed operations, negate outputs as needed to get correct sign
|
||||
neg #(`XLEN) qneg(XQM[0], XQnM);
|
||||
|
@ -49,8 +49,8 @@ module mul (
|
||||
// Signed * Unsigned = P' + ( PA - PB)*2^(XLEN-1) - PP*2^(2XLEN-2)
|
||||
// Unsigned * Unsigned = P' + ( PA + PB)*2^(XLEN-1) + PP*2^(2XLEN-2)
|
||||
|
||||
logic [`XLEN*2-1:0] PP0E, PP1E, PP2E, PP3E, PP4E;
|
||||
logic [`XLEN*2-1:0] PP0M, PP1M, PP2M, PP3M, PP4M;
|
||||
logic [`XLEN*2-1:0] PP1E, PP2E, PP3E, PP4E;
|
||||
logic [`XLEN*2-1:0] PP1M, PP2M, PP3M, PP4M;
|
||||
logic [`XLEN-2:0] PA, PB;
|
||||
logic PP;
|
||||
logic MULH, MULHSU;
|
||||
@ -62,7 +62,7 @@ module mul (
|
||||
|
||||
assign Aprime = {1'b0, ForwardedSrcAE[`XLEN-2:0]};
|
||||
assign Bprime = {1'b0, ForwardedSrcBE[`XLEN-2:0]};
|
||||
redundantmul #(`XLEN) bigmul(.a(Aprime), .b(Bprime), .out0(PP0E), .out1(PP1E));
|
||||
assign PP1E = Aprime * Bprime;
|
||||
assign PA = {(`XLEN-1){ForwardedSrcAE[`XLEN-1]}} & ForwardedSrcBE[`XLEN-2:0];
|
||||
assign PB = {(`XLEN-1){ForwardedSrcBE[`XLEN-1]}} & ForwardedSrcAE[`XLEN-2:0];
|
||||
assign PP = ForwardedSrcAE[`XLEN-1] & ForwardedSrcBE[`XLEN-1];
|
||||
@ -83,12 +83,11 @@ module mul (
|
||||
// Memory Stage: Sum partial proudcts
|
||||
//////////////////////////////
|
||||
|
||||
flopenrc #(`XLEN*2) PP0Reg(clk, reset, FlushM, ~StallM, PP0E, PP0M);
|
||||
flopenrc #(`XLEN*2) PP1Reg(clk, reset, FlushM, ~StallM, PP1E, PP1M);
|
||||
flopenrc #(`XLEN*2) PP2Reg(clk, reset, FlushM, ~StallM, PP2E, PP2M);
|
||||
flopenrc #(`XLEN*2) PP3Reg(clk, reset, FlushM, ~StallM, PP3E, PP3M);
|
||||
flopenrc #(`XLEN*2) PP4Reg(clk, reset, FlushM, ~StallM, PP4E, PP4M);
|
||||
|
||||
assign ProdM = PP0M + PP1M + PP2M + PP3M + PP4M; //ForwardedSrcAE * ForwardedSrcBE;
|
||||
assign ProdM = PP1M + PP2M + PP3M + PP4M; //ForwardedSrcAE * ForwardedSrcBE;
|
||||
endmodule
|
||||
|
||||
|
@ -74,13 +74,11 @@ module muldiv (
|
||||
|
||||
// Handle sign extension for W-type instructions
|
||||
flopenrc #(1) W64MReg(clk, reset, FlushM, ~StallM, W64E, W64M);
|
||||
generate
|
||||
if (`XLEN == 64) begin:resmux // RV64 has W-type instructions
|
||||
assign MulDivResultM = W64M ? {{32{PrelimResultM[31]}}, PrelimResultM[31:0]} : PrelimResultM;
|
||||
end else begin:resmux // RV32 has no W-type instructions
|
||||
assign MulDivResultM = PrelimResultM;
|
||||
end
|
||||
endgenerate
|
||||
if (`XLEN == 64) begin:resmux // RV64 has W-type instructions
|
||||
assign MulDivResultM = W64M ? {{32{PrelimResultM[31]}}, PrelimResultM[31:0]} : PrelimResultM;
|
||||
end else begin:resmux // RV32 has no W-type instructions
|
||||
assign MulDivResultM = PrelimResultM;
|
||||
end
|
||||
|
||||
// Writeback stage pipeline register
|
||||
flopenrc #(`XLEN) MulDivResultWReg(clk, reset, FlushW, ~StallW, MulDivResultM, MulDivResultW);
|
||||
|
@ -56,111 +56,109 @@ module csrc #(parameter
|
||||
output logic IllegalCSRCAccessM
|
||||
);
|
||||
|
||||
generate
|
||||
if (`ZICOUNTERS_SUPPORTED) begin:counters
|
||||
(* mark_debug = "true" *) logic [63:0] CYCLE_REGW, INSTRET_REGW;
|
||||
logic [63:0] CYCLEPlusM, INSTRETPlusM;
|
||||
logic [`XLEN-1:0] NextCYCLEM, NextINSTRETM;
|
||||
logic WriteCYCLEM, WriteINSTRETM;
|
||||
logic [4:0] CounterNumM;
|
||||
logic [`XLEN-1:0] HPMCOUNTER_REGW[`COUNTERS-1:0];
|
||||
logic [`XLEN-1:0] HPMCOUNTERH_REGW[`COUNTERS-1:0];
|
||||
logic InstrValidNotFlushedM;
|
||||
logic LoadStallE, LoadStallM;
|
||||
logic [`COUNTERS-1:0] WriteHPMCOUNTERM;
|
||||
logic [`COUNTERS-1:0] CounterEvent;
|
||||
logic [63:0] HPMCOUNTERPlusM[`COUNTERS-1:0];
|
||||
logic [`XLEN-1:0] NextHPMCOUNTERM[`COUNTERS-1:0];
|
||||
genvar i;
|
||||
if (`ZICOUNTERS_SUPPORTED) begin:counters
|
||||
(* mark_debug = "true" *) logic [63:0] CYCLE_REGW, INSTRET_REGW;
|
||||
logic [63:0] CYCLEPlusM, INSTRETPlusM;
|
||||
logic [`XLEN-1:0] NextCYCLEM, NextINSTRETM;
|
||||
logic WriteCYCLEM, WriteINSTRETM;
|
||||
logic [4:0] CounterNumM;
|
||||
logic [`XLEN-1:0] HPMCOUNTER_REGW[`COUNTERS-1:0];
|
||||
logic [`XLEN-1:0] HPMCOUNTERH_REGW[`COUNTERS-1:0];
|
||||
logic InstrValidNotFlushedM;
|
||||
logic LoadStallE, LoadStallM;
|
||||
logic [`COUNTERS-1:0] WriteHPMCOUNTERM;
|
||||
logic [`COUNTERS-1:0] CounterEvent;
|
||||
logic [63:0] HPMCOUNTERPlusM[`COUNTERS-1:0];
|
||||
logic [`XLEN-1:0] NextHPMCOUNTERM[`COUNTERS-1:0];
|
||||
genvar i;
|
||||
|
||||
// Interface signals
|
||||
flopenrc #(1) LoadStallEReg(.clk, .reset, .clear(1'b0), .en(~StallE), .d(LoadStallD), .q(LoadStallE)); // don't flush the load stall during a load stall.
|
||||
flopenrc #(1) LoadStallMReg(.clk, .reset, .clear(FlushM), .en(~StallM), .d(LoadStallE), .q(LoadStallM));
|
||||
assign InstrValidNotFlushedM = InstrValidM & ~StallW & ~FlushW;
|
||||
|
||||
// Determine when to increment each counter
|
||||
assign CounterEvent[0] = 1'b1; // MCYCLE always increments
|
||||
assign CounterEvent[1] = 1'b0; // Counter 0 doesn't exist
|
||||
assign CounterEvent[2] = InstrValidNotFlushedM;
|
||||
if(`QEMU) begin // No other performance counters in QEMU
|
||||
assign CounterEvent[`COUNTERS-1:3] = 0;
|
||||
end else begin // User-defined counters
|
||||
assign CounterEvent[3] = LoadStallM; // don't want to suppress on flush as this only happens if flushed.
|
||||
assign CounterEvent[4] = BPPredDirWrongM & InstrValidNotFlushedM;
|
||||
assign CounterEvent[5] = InstrClassM[0] & InstrValidNotFlushedM;
|
||||
assign CounterEvent[6] = BTBPredPCWrongM & InstrValidNotFlushedM;
|
||||
assign CounterEvent[7] = (InstrClassM[4] | InstrClassM[2] | InstrClassM[1]) & InstrValidNotFlushedM;
|
||||
assign CounterEvent[8] = RASPredPCWrongM & InstrValidNotFlushedM;
|
||||
assign CounterEvent[9] = InstrClassM[3] & InstrValidNotFlushedM;
|
||||
assign CounterEvent[10] = BPPredClassNonCFIWrongM & InstrValidNotFlushedM;
|
||||
assign CounterEvent[11] = DCacheAccess;
|
||||
assign CounterEvent[12] = DCacheMiss;
|
||||
assign CounterEvent[`COUNTERS-1:13] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions
|
||||
end
|
||||
|
||||
// Counter update and write logic
|
||||
for (i = 0; i < `COUNTERS; i = i+1) begin
|
||||
assign WriteHPMCOUNTERM[i] = CSRMWriteM & (CSRAdrM == MHPMCOUNTERBASE + i);
|
||||
assign NextHPMCOUNTERM[i][`XLEN-1:0] = WriteHPMCOUNTERM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][`XLEN-1:0];
|
||||
always_ff @(posedge clk) //, posedge reset) // ModelSim doesn't like syntax of passing array element to flop
|
||||
if (reset) HPMCOUNTER_REGW[i][`XLEN-1:0] <= #1 0;
|
||||
else HPMCOUNTER_REGW[i][`XLEN-1:0] <= #1 NextHPMCOUNTERM[i];
|
||||
|
||||
if (`XLEN==32) begin // write high and low separately
|
||||
logic [`COUNTERS-1:0] WriteHPMCOUNTERHM;
|
||||
logic [`XLEN-1:0] NextHPMCOUNTERHM[`COUNTERS-1:0];
|
||||
assign HPMCOUNTERPlusM[i] = {HPMCOUNTERH_REGW[i], HPMCOUNTER_REGW[i]} + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]};
|
||||
assign WriteHPMCOUNTERHM[i] = CSRMWriteM & (CSRAdrM == MHPMCOUNTERHBASE + i);
|
||||
assign NextHPMCOUNTERHM[i] = WriteHPMCOUNTERHM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][63:32];
|
||||
always_ff @(posedge clk) //, posedge reset) // ModelSim doesn't like syntax of passing array element to flop
|
||||
if (reset) HPMCOUNTERH_REGW[i][`XLEN-1:0] <= #1 0;
|
||||
else HPMCOUNTERH_REGW[i][`XLEN-1:0] <= #1 NextHPMCOUNTERHM[i];
|
||||
end else begin // XLEN=64; write entire register
|
||||
assign HPMCOUNTERPlusM[i] = HPMCOUNTER_REGW[i] + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]};
|
||||
end
|
||||
end
|
||||
|
||||
// Read Counters, or cause excepiton if insufficient privilege in light of COUNTEREN flags
|
||||
assign CounterNumM = CSRAdrM[4:0]; // which counter to read?
|
||||
always_comb
|
||||
if (PrivilegeModeW == `M_MODE |
|
||||
MCOUNTEREN_REGW[CounterNumM] & (!`S_SUPPORTED | PrivilegeModeW == `S_MODE | SCOUNTEREN_REGW[CounterNumM])) begin
|
||||
IllegalCSRCAccessM = 0;
|
||||
if (`XLEN==64) begin // 64-bit counter reads
|
||||
// Veri lator doesn't realize this only occurs for XLEN=64
|
||||
/* verilator lint_off WIDTH */
|
||||
if (CSRAdrM == TIME) CSRCReadValM = MTIME_CLINT; // TIME register is a shadow of the memory-mapped MTIME from the CLINT
|
||||
/* verilator lint_on WIDTH */
|
||||
else if (CSRAdrM >= MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else begin
|
||||
CSRCReadValM = 0;
|
||||
IllegalCSRCAccessM = 1; // requested CSR doesn't exist
|
||||
end
|
||||
end else begin // 32-bit counter reads
|
||||
// Veri lator doesn't realize this only occurs for XLEN=32
|
||||
/* verilator lint_off WIDTH */
|
||||
if (CSRAdrM == TIME) CSRCReadValM = MTIME_CLINT[31:0];// TIME register is a shadow of the memory-mapped MTIME from the CLINT
|
||||
else if (CSRAdrM == TIMEH) CSRCReadValM = MTIME_CLINT[63:32];
|
||||
/* verilator lint_on WIDTH */
|
||||
else if (CSRAdrM >= MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= MHPMCOUNTERHBASE & CSRAdrM < MHPMCOUNTERHBASE+`COUNTERS) CSRCReadValM = HPMCOUNTERH_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERHBASE & CSRAdrM < HPMCOUNTERHBASE+`COUNTERS) CSRCReadValM = HPMCOUNTERH_REGW[CounterNumM];
|
||||
else begin
|
||||
CSRCReadValM = 0;
|
||||
IllegalCSRCAccessM = 1; // requested CSR doesn't exist
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
CSRCReadValM = 0;
|
||||
IllegalCSRCAccessM = 1; // no privileges for this csr
|
||||
end
|
||||
end else begin
|
||||
assign CSRCReadValM = 0;
|
||||
assign IllegalCSRCAccessM = 1; // counters aren't enabled
|
||||
// Interface signals
|
||||
flopenrc #(1) LoadStallEReg(.clk, .reset, .clear(1'b0), .en(~StallE), .d(LoadStallD), .q(LoadStallE)); // don't flush the load stall during a load stall.
|
||||
flopenrc #(1) LoadStallMReg(.clk, .reset, .clear(FlushM), .en(~StallM), .d(LoadStallE), .q(LoadStallM));
|
||||
assign InstrValidNotFlushedM = InstrValidM & ~StallW & ~FlushW;
|
||||
|
||||
// Determine when to increment each counter
|
||||
assign CounterEvent[0] = 1'b1; // MCYCLE always increments
|
||||
assign CounterEvent[1] = 1'b0; // Counter 0 doesn't exist
|
||||
assign CounterEvent[2] = InstrValidNotFlushedM;
|
||||
if(`QEMU) begin: cevent // No other performance counters in QEMU
|
||||
assign CounterEvent[`COUNTERS-1:3] = 0;
|
||||
end else begin: cevent // User-defined counters
|
||||
assign CounterEvent[3] = LoadStallM; // don't want to suppress on flush as this only happens if flushed.
|
||||
assign CounterEvent[4] = BPPredDirWrongM & InstrValidNotFlushedM;
|
||||
assign CounterEvent[5] = InstrClassM[0] & InstrValidNotFlushedM;
|
||||
assign CounterEvent[6] = BTBPredPCWrongM & InstrValidNotFlushedM;
|
||||
assign CounterEvent[7] = (InstrClassM[4] | InstrClassM[2] | InstrClassM[1]) & InstrValidNotFlushedM;
|
||||
assign CounterEvent[8] = RASPredPCWrongM & InstrValidNotFlushedM;
|
||||
assign CounterEvent[9] = InstrClassM[3] & InstrValidNotFlushedM;
|
||||
assign CounterEvent[10] = BPPredClassNonCFIWrongM & InstrValidNotFlushedM;
|
||||
assign CounterEvent[11] = DCacheAccess;
|
||||
assign CounterEvent[12] = DCacheMiss;
|
||||
assign CounterEvent[`COUNTERS-1:13] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Counter update and write logic
|
||||
for (i = 0; i < `COUNTERS; i = i+1) begin:cntr
|
||||
assign WriteHPMCOUNTERM[i] = CSRMWriteM & (CSRAdrM == MHPMCOUNTERBASE + i);
|
||||
assign NextHPMCOUNTERM[i][`XLEN-1:0] = WriteHPMCOUNTERM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][`XLEN-1:0];
|
||||
always_ff @(posedge clk) //, posedge reset) // ModelSim doesn't like syntax of passing array element to flop
|
||||
if (reset) HPMCOUNTER_REGW[i][`XLEN-1:0] <= #1 0;
|
||||
else HPMCOUNTER_REGW[i][`XLEN-1:0] <= #1 NextHPMCOUNTERM[i];
|
||||
|
||||
if (`XLEN==32) begin // write high and low separately
|
||||
logic [`COUNTERS-1:0] WriteHPMCOUNTERHM;
|
||||
logic [`XLEN-1:0] NextHPMCOUNTERHM[`COUNTERS-1:0];
|
||||
assign HPMCOUNTERPlusM[i] = {HPMCOUNTERH_REGW[i], HPMCOUNTER_REGW[i]} + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]};
|
||||
assign WriteHPMCOUNTERHM[i] = CSRMWriteM & (CSRAdrM == MHPMCOUNTERHBASE + i);
|
||||
assign NextHPMCOUNTERHM[i] = WriteHPMCOUNTERHM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][63:32];
|
||||
always_ff @(posedge clk) //, posedge reset) // ModelSim doesn't like syntax of passing array element to flop
|
||||
if (reset) HPMCOUNTERH_REGW[i][`XLEN-1:0] <= #1 0;
|
||||
else HPMCOUNTERH_REGW[i][`XLEN-1:0] <= #1 NextHPMCOUNTERHM[i];
|
||||
end else begin // XLEN=64; write entire register
|
||||
assign HPMCOUNTERPlusM[i] = HPMCOUNTER_REGW[i] + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]};
|
||||
end
|
||||
end
|
||||
|
||||
// Read Counters, or cause excepiton if insufficient privilege in light of COUNTEREN flags
|
||||
assign CounterNumM = CSRAdrM[4:0]; // which counter to read?
|
||||
always_comb
|
||||
if (PrivilegeModeW == `M_MODE |
|
||||
MCOUNTEREN_REGW[CounterNumM] & (!`S_SUPPORTED | PrivilegeModeW == `S_MODE | SCOUNTEREN_REGW[CounterNumM])) begin
|
||||
IllegalCSRCAccessM = 0;
|
||||
if (`XLEN==64) begin // 64-bit counter reads
|
||||
// Veri lator doesn't realize this only occurs for XLEN=64
|
||||
/* verilator lint_off WIDTH */
|
||||
if (CSRAdrM == TIME) CSRCReadValM = MTIME_CLINT; // TIME register is a shadow of the memory-mapped MTIME from the CLINT
|
||||
/* verilator lint_on WIDTH */
|
||||
else if (CSRAdrM >= MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else begin
|
||||
CSRCReadValM = 0;
|
||||
IllegalCSRCAccessM = 1; // requested CSR doesn't exist
|
||||
end
|
||||
end else begin // 32-bit counter reads
|
||||
// Veri lator doesn't realize this only occurs for XLEN=32
|
||||
/* verilator lint_off WIDTH */
|
||||
if (CSRAdrM == TIME) CSRCReadValM = MTIME_CLINT[31:0];// TIME register is a shadow of the memory-mapped MTIME from the CLINT
|
||||
else if (CSRAdrM == TIMEH) CSRCReadValM = MTIME_CLINT[63:32];
|
||||
/* verilator lint_on WIDTH */
|
||||
else if (CSRAdrM >= MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= MHPMCOUNTERHBASE & CSRAdrM < MHPMCOUNTERHBASE+`COUNTERS) CSRCReadValM = HPMCOUNTERH_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERHBASE & CSRAdrM < HPMCOUNTERHBASE+`COUNTERS) CSRCReadValM = HPMCOUNTERH_REGW[CounterNumM];
|
||||
else begin
|
||||
CSRCReadValM = 0;
|
||||
IllegalCSRCAccessM = 1; // requested CSR doesn't exist
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
CSRCReadValM = 0;
|
||||
IllegalCSRCAccessM = 1; // no privileges for this csr
|
||||
end
|
||||
end else begin
|
||||
assign CSRCReadValM = 0;
|
||||
assign IllegalCSRCAccessM = 1; // counters aren't enabled
|
||||
end
|
||||
endmodule
|
||||
|
||||
// To Do:
|
||||
|
@ -66,58 +66,54 @@ module csri #(parameter
|
||||
assign WriteSIPM = CSRSWriteM & (CSRAdrM == SIP) & ~StallW;
|
||||
assign WriteSIEM = CSRSWriteM & (CSRAdrM == SIE) & ~StallW;
|
||||
|
||||
// Interrupt Pending and Enable Registers
|
||||
// MEIP, MTIP, MSIP are read-only
|
||||
// SEIP, STIP, SSIP is writable in MIP if S mode exists
|
||||
// SSIP is writable in SIP if S mode exists
|
||||
generate
|
||||
if (`S_SUPPORTED) begin:mask
|
||||
assign MIP_WRITE_MASK = 12'h222; // SEIP, STIP, SSIP are writable in MIP (20210108-draft 3.1.9)
|
||||
assign SIP_WRITE_MASK = 12'h002; // SSIP is writable in SIP (privileged 20210108-draft 4.1.3)
|
||||
end else begin:mask
|
||||
assign MIP_WRITE_MASK = 12'h000;
|
||||
assign SIP_WRITE_MASK = 12'h000;
|
||||
end
|
||||
always @(posedge clk) //, posedge reset) begin // *** I strongly feel that IntInM should go directly to IP_REGW -- Ben 9/7/21
|
||||
if (reset) IP_REGW_writeable <= 10'b0;
|
||||
else if (WriteMIPM) IP_REGW_writeable <= (CSRWriteValM[9:0] & MIP_WRITE_MASK[9:0]) | IntInM[9:0]; // MTIP unclearable
|
||||
else if (WriteSIPM) IP_REGW_writeable <= (CSRWriteValM[9:0] & SIP_WRITE_MASK[9:0]) | IntInM[9:0]; // MTIP unclearable
|
||||
// Interrupt Pending and Enable Registers
|
||||
// MEIP, MTIP, MSIP are read-only
|
||||
// SEIP, STIP, SSIP is writable in MIP if S mode exists
|
||||
// SSIP is writable in SIP if S mode exists
|
||||
if (`S_SUPPORTED) begin:mask
|
||||
assign MIP_WRITE_MASK = 12'h222; // SEIP, STIP, SSIP are writable in MIP (20210108-draft 3.1.9)
|
||||
assign SIP_WRITE_MASK = 12'h002; // SSIP is writable in SIP (privileged 20210108-draft 4.1.3)
|
||||
end else begin:mask
|
||||
assign MIP_WRITE_MASK = 12'h000;
|
||||
assign SIP_WRITE_MASK = 12'h000;
|
||||
end
|
||||
always @(posedge clk) //, posedge reset) begin // *** I strongly feel that IntInM should go directly to IP_REGW -- Ben 9/7/21
|
||||
if (reset) IP_REGW_writeable <= 10'b0;
|
||||
else if (WriteMIPM) IP_REGW_writeable <= (CSRWriteValM[9:0] & MIP_WRITE_MASK[9:0]) | IntInM[9:0]; // MTIP unclearable
|
||||
else if (WriteSIPM) IP_REGW_writeable <= (CSRWriteValM[9:0] & SIP_WRITE_MASK[9:0]) | IntInM[9:0]; // MTIP unclearable
|
||||
// else if (WriteUIPM) IP_REGW = (CSRWriteValM & 12'hBBB) | (NextIPM & 12'h080); // MTIP unclearable
|
||||
else IP_REGW_writeable <= IP_REGW_writeable | IntInM[9:0]; // *** check this turns off interrupts properly even when MIDELEG changes
|
||||
always @(posedge clk) //, posedge reset) begin
|
||||
if (reset) IE_REGW <= 12'b0;
|
||||
else if (WriteMIEM) IE_REGW <= (CSRWriteValM[11:0] & 12'hAAA); // MIE controls M and S fields
|
||||
else if (WriteSIEM) IE_REGW <= (CSRWriteValM[11:0] & 12'h222) | (IE_REGW & 12'h888); // only S fields
|
||||
else IP_REGW_writeable <= IP_REGW_writeable | IntInM[9:0]; // *** check this turns off interrupts properly even when MIDELEG changes
|
||||
always @(posedge clk) //, posedge reset) begin
|
||||
if (reset) IE_REGW <= 12'b0;
|
||||
else if (WriteMIEM) IE_REGW <= (CSRWriteValM[11:0] & 12'hAAA); // MIE controls M and S fields
|
||||
else if (WriteSIEM) IE_REGW <= (CSRWriteValM[11:0] & 12'h222) | (IE_REGW & 12'h888); // only S fields
|
||||
// else if (WriteUIEM) IE_REGW = (CSRWriteValM & 12'h111) | (IE_REGW & 12'hAAA); // only U field
|
||||
endgenerate
|
||||
|
||||
// restricted views of registers
|
||||
generate
|
||||
always_comb begin:regs
|
||||
// Add MEIP read-only signal
|
||||
IP_REGW = {IntInM[11],1'b0,IP_REGW_writeable};
|
||||
always_comb begin:regs
|
||||
// Add MEIP read-only signal
|
||||
IP_REGW = {IntInM[11],1'b0,IP_REGW_writeable};
|
||||
|
||||
// Machine Mode
|
||||
MIP_REGW = IP_REGW;
|
||||
MIE_REGW = IE_REGW;
|
||||
// Machine Mode
|
||||
MIP_REGW = IP_REGW;
|
||||
MIE_REGW = IE_REGW;
|
||||
|
||||
// Supervisor mode
|
||||
if (`S_SUPPORTED) begin
|
||||
SIP_REGW = IP_REGW & MIDELEG_REGW[11:0] & 'h222; // only delegated interrupts visible
|
||||
SIE_REGW = IE_REGW & MIDELEG_REGW[11:0] & 'h222;
|
||||
end else begin
|
||||
SIP_REGW = 12'b0;
|
||||
SIE_REGW = 12'b0;
|
||||
end
|
||||
|
||||
// User Modes iterrupts depricated
|
||||
/*if (`U_SUPPORTED & `N_SUPPORTED) begin
|
||||
UIP_REGW = IP_REGW & MIDELEG_REGW & SIDELEG_REGW & 'h111; // only delegated interrupts visible
|
||||
UIE_REGW = IE_REGW & MIDELEG_REGW & SIDELEG_REGW & 'h111; // only delegated interrupts visible
|
||||
end else begin
|
||||
UIP_REGW = 12'b0;
|
||||
UIE_REGW = 12'b0;
|
||||
end */
|
||||
// Supervisor mode
|
||||
if (`S_SUPPORTED) begin
|
||||
SIP_REGW = IP_REGW & MIDELEG_REGW[11:0] & 'h222; // only delegated interrupts visible
|
||||
SIE_REGW = IE_REGW & MIDELEG_REGW[11:0] & 'h222;
|
||||
end else begin
|
||||
SIP_REGW = 12'b0;
|
||||
SIE_REGW = 12'b0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// User Modes iterrupts depricated
|
||||
/*if (`U_SUPPORTED & `N_SUPPORTED) begin
|
||||
UIP_REGW = IP_REGW & MIDELEG_REGW & SIDELEG_REGW & 'h111; // only delegated interrupts visible
|
||||
UIE_REGW = IE_REGW & MIDELEG_REGW & SIDELEG_REGW & 'h111; // only delegated interrupts visible
|
||||
end else begin
|
||||
UIP_REGW = 12'b0;
|
||||
UIE_REGW = 12'b0;
|
||||
end */
|
||||
end
|
||||
endmodule
|
||||
|
@ -92,32 +92,30 @@ module csrm #(parameter
|
||||
|
||||
// There are PMP_ENTRIES = 0, 16, or 64 PMPADDR registers, each of which has its own flop
|
||||
genvar i;
|
||||
generate
|
||||
if (`PMP_ENTRIES > 0) begin:pmp
|
||||
logic [`PMP_ENTRIES-1:0] WritePMPCFGM;
|
||||
logic [`PMP_ENTRIES-1:0] WritePMPADDRM ;
|
||||
logic [`PMP_ENTRIES-1:0] ADDRLocked, CFGLocked;
|
||||
for(i=0; i<`PMP_ENTRIES; i++) begin
|
||||
// when the lock bit is set, don't allow writes to the PMPCFG or PMPADDR
|
||||
// also, when the lock bit of the next entry is set and the next entry is TOR, don't allow writes to this entry PMPADDR
|
||||
assign CFGLocked[i] = PMPCFG_ARRAY_REGW[i][7];
|
||||
if (i == `PMP_ENTRIES-1)
|
||||
assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7];
|
||||
else
|
||||
assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7] | (PMPCFG_ARRAY_REGW[i+1][7] & PMPCFG_ARRAY_REGW[i+1][4:3] == 2'b01);
|
||||
|
||||
assign WritePMPADDRM[i] = (CSRMWriteM & (CSRAdrM == (PMPADDR0+i))) & ~StallW & ~ADDRLocked[i];
|
||||
flopenr #(`XLEN) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM, PMPADDR_ARRAY_REGW[i]);
|
||||
if (`XLEN==64) begin
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+2*(i/8)))) & ~StallW & ~CFGLocked[i];
|
||||
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%8)*8+7:(i%8)*8], PMPCFG_ARRAY_REGW[i]);
|
||||
end else begin
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+i/4))) & ~StallW & ~CFGLocked[i];
|
||||
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%4)*8+7:(i%4)*8], PMPCFG_ARRAY_REGW[i]);
|
||||
end
|
||||
if (`PMP_ENTRIES > 0) begin:pmp
|
||||
logic [`PMP_ENTRIES-1:0] WritePMPCFGM;
|
||||
logic [`PMP_ENTRIES-1:0] WritePMPADDRM ;
|
||||
logic [`PMP_ENTRIES-1:0] ADDRLocked, CFGLocked;
|
||||
for(i=0; i<`PMP_ENTRIES; i++) begin
|
||||
// when the lock bit is set, don't allow writes to the PMPCFG or PMPADDR
|
||||
// also, when the lock bit of the next entry is set and the next entry is TOR, don't allow writes to this entry PMPADDR
|
||||
assign CFGLocked[i] = PMPCFG_ARRAY_REGW[i][7];
|
||||
if (i == `PMP_ENTRIES-1)
|
||||
assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7];
|
||||
else
|
||||
assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7] | (PMPCFG_ARRAY_REGW[i+1][7] & PMPCFG_ARRAY_REGW[i+1][4:3] == 2'b01);
|
||||
|
||||
assign WritePMPADDRM[i] = (CSRMWriteM & (CSRAdrM == (PMPADDR0+i))) & ~StallW & ~ADDRLocked[i];
|
||||
flopenr #(`XLEN) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM, PMPADDR_ARRAY_REGW[i]);
|
||||
if (`XLEN==64) begin
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+2*(i/8)))) & ~StallW & ~CFGLocked[i];
|
||||
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%8)*8+7:(i%8)*8], PMPCFG_ARRAY_REGW[i]);
|
||||
end else begin
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+i/4))) & ~StallW & ~CFGLocked[i];
|
||||
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%4)*8+7:(i%4)*8], PMPCFG_ARRAY_REGW[i]);
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
end
|
||||
|
||||
localparam MISA_26 = (`MISA) & 32'h03ffffff;
|
||||
|
||||
@ -143,28 +141,24 @@ module csrm #(parameter
|
||||
|
||||
// CSRs
|
||||
flopenr #(`XLEN) MTVECreg(clk, reset, WriteMTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, MTVEC_REGW); //busybear: changed reset value to 0
|
||||
generate
|
||||
if (`S_SUPPORTED | (`U_SUPPORTED & `N_SUPPORTED)) begin:deleg // DELEG registers should exist
|
||||
flopenr #(`XLEN) MEDELEGreg(clk, reset, WriteMEDELEGM, CSRWriteValM & MEDELEG_MASK /*12'h7FF*/, MEDELEG_REGW);
|
||||
flopenr #(`XLEN) MIDELEGreg(clk, reset, WriteMIDELEGM, CSRWriteValM & MIDELEG_MASK /*12'h222*/, MIDELEG_REGW);
|
||||
end else begin
|
||||
assign MEDELEG_REGW = 0;
|
||||
assign MIDELEG_REGW = 0;
|
||||
end
|
||||
endgenerate
|
||||
if (`S_SUPPORTED | (`U_SUPPORTED & `N_SUPPORTED)) begin:deleg // DELEG registers should exist
|
||||
flopenr #(`XLEN) MEDELEGreg(clk, reset, WriteMEDELEGM, CSRWriteValM & MEDELEG_MASK /*12'h7FF*/, MEDELEG_REGW);
|
||||
flopenr #(`XLEN) MIDELEGreg(clk, reset, WriteMIDELEGM, CSRWriteValM & MIDELEG_MASK /*12'h222*/, MIDELEG_REGW);
|
||||
end else begin
|
||||
assign MEDELEG_REGW = 0;
|
||||
assign MIDELEG_REGW = 0;
|
||||
end
|
||||
|
||||
flopenr #(`XLEN) MSCRATCHreg(clk, reset, WriteMSCRATCHM, CSRWriteValM, MSCRATCH_REGW);
|
||||
flopenr #(`XLEN) MEPCreg(clk, reset, WriteMEPCM, NextEPCM, MEPC_REGW);
|
||||
flopenr #(`XLEN) MCAUSEreg(clk, reset, WriteMCAUSEM, NextCauseM, MCAUSE_REGW);
|
||||
if(`QEMU) assign MTVAL_REGW = `XLEN'b0;
|
||||
else flopenr #(`XLEN) MTVALreg(clk, reset, WriteMTVALM, NextMtvalM, MTVAL_REGW);
|
||||
generate // *** needs comment about bit 1
|
||||
if (`BUSYBEAR == 1) begin:counters
|
||||
if (`BUSYBEAR == 1) begin:counters // counter 1 (TIME) enable tied to 0 to match simulator***
|
||||
flopenr #(32) MCOUNTERENreg(clk, reset, WriteMCOUNTERENM, {CSRWriteValM[31:2],1'b0,CSRWriteValM[0]}, MCOUNTEREN_REGW);
|
||||
end else begin:counters
|
||||
flopenr #(32) MCOUNTERENreg(clk, reset, WriteMCOUNTERENM, CSRWriteValM[31:0], MCOUNTEREN_REGW);
|
||||
end
|
||||
endgenerate
|
||||
flopenr #(32) MCOUNTINHIBITreg(clk, reset, WriteMCOUNTINHIBITM, CSRWriteValM[31:0], MCOUNTINHIBIT_REGW);
|
||||
|
||||
|
||||
|
@ -49,52 +49,50 @@ module csrn #(parameter
|
||||
);
|
||||
|
||||
// User mode CSRs below only needed when user mode traps are supported
|
||||
generate
|
||||
if (`N_SUPPORTED) begin:nmode
|
||||
logic WriteUTVECM;
|
||||
logic WriteUSCRATCHM, WriteUEPCM;
|
||||
logic WriteUCAUSEM, WriteUTVALM;
|
||||
logic [`XLEN-1:0] UEDELEG_REGW, UIDELEG_REGW;
|
||||
logic [`XLEN-1:0] USCRATCH_REGW, UCAUSE_REGW, UTVAL_REGW;
|
||||
|
||||
// Write enables
|
||||
assign WriteUSTATUSM = CSRNWriteM & (CSRAdrM == USTATUS) & ~StallW;
|
||||
assign WriteUTVECM = CSRNWriteM & (CSRAdrM == UTVEC) & ~StallW;
|
||||
assign WriteUEPCM = UTrapM | (CSRNWriteM & (CSRAdrM == UEPC)) & ~StallW;
|
||||
assign WriteUCAUSEM = UTrapM | (CSRNWriteM & (CSRAdrM == UCAUSE)) & ~StallW;
|
||||
assign WriteUTVALM = UTrapM | (CSRNWriteM & (CSRAdrM == UTVAL)) & ~StallW;
|
||||
if (`N_SUPPORTED) begin:nmode // depricated; consider removing***
|
||||
logic WriteUTVECM;
|
||||
logic WriteUSCRATCHM, WriteUEPCM;
|
||||
logic WriteUCAUSEM, WriteUTVALM;
|
||||
logic [`XLEN-1:0] UEDELEG_REGW, UIDELEG_REGW;
|
||||
logic [`XLEN-1:0] USCRATCH_REGW, UCAUSE_REGW, UTVAL_REGW;
|
||||
|
||||
// Write enables
|
||||
assign WriteUSTATUSM = CSRNWriteM & (CSRAdrM == USTATUS) & ~StallW;
|
||||
assign WriteUTVECM = CSRNWriteM & (CSRAdrM == UTVEC) & ~StallW;
|
||||
assign WriteUEPCM = UTrapM | (CSRNWriteM & (CSRAdrM == UEPC)) & ~StallW;
|
||||
assign WriteUCAUSEM = UTrapM | (CSRNWriteM & (CSRAdrM == UCAUSE)) & ~StallW;
|
||||
assign WriteUTVALM = UTrapM | (CSRNWriteM & (CSRAdrM == UTVAL)) & ~StallW;
|
||||
|
||||
// CSRs
|
||||
flopenl #(`XLEN) UTVECreg(clk, reset, WriteUTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, `RESET_VECTOR, UTVEC_REGW);
|
||||
flopenr #(`XLEN) USCRATCHreg(clk, reset, WriteUSCRATCHM, CSRWriteValM, USCRATCH_REGW);
|
||||
flopenr #(`XLEN) UEPCreg(clk, reset, WriteUEPCM, NextEPCM, UEPC_REGW);
|
||||
flopenr #(`XLEN) UCAUSEreg(clk, reset, WriteUCAUSEM, NextCauseM, UCAUSE_REGW);
|
||||
flopenr #(`XLEN) UTVALreg(clk, reset, WriteUTVALM, NextMtvalM, UTVAL_REGW);
|
||||
// CSRs
|
||||
flopenl #(`XLEN) UTVECreg(clk, reset, WriteUTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, `RESET_VECTOR, UTVEC_REGW);
|
||||
flopenr #(`XLEN) USCRATCHreg(clk, reset, WriteUSCRATCHM, CSRWriteValM, USCRATCH_REGW);
|
||||
flopenr #(`XLEN) UEPCreg(clk, reset, WriteUEPCM, NextEPCM, UEPC_REGW);
|
||||
flopenr #(`XLEN) UCAUSEreg(clk, reset, WriteUCAUSEM, NextCauseM, UCAUSE_REGW);
|
||||
flopenr #(`XLEN) UTVALreg(clk, reset, WriteUTVALM, NextMtvalM, UTVAL_REGW);
|
||||
|
||||
// CSR Reads
|
||||
always_comb begin
|
||||
IllegalCSRNAccessM = 0;
|
||||
case (CSRAdrM)
|
||||
USTATUS: CSRNReadValM = USTATUS_REGW;
|
||||
UTVEC: CSRNReadValM = UTVEC_REGW;
|
||||
UIP: CSRNReadValM = {{(`XLEN-12){1'b0}}, UIP_REGW};
|
||||
UIE: CSRNReadValM = {{(`XLEN-12){1'b0}}, UIE_REGW};
|
||||
USCRATCH: CSRNReadValM = USCRATCH_REGW;
|
||||
UEPC: CSRNReadValM = UEPC_REGW;
|
||||
UCAUSE: CSRNReadValM = UCAUSE_REGW;
|
||||
UTVAL: CSRNReadValM = UTVAL_REGW;
|
||||
default: begin
|
||||
CSRNReadValM = 0;
|
||||
IllegalCSRNAccessM = 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end else begin // if not supported
|
||||
assign WriteUSTATUSM = 0;
|
||||
assign CSRNReadValM = 0;
|
||||
assign UEPC_REGW = 0;
|
||||
assign UTVEC_REGW = 0;
|
||||
assign IllegalCSRNAccessM = 1;
|
||||
// CSR Reads
|
||||
always_comb begin
|
||||
IllegalCSRNAccessM = 0;
|
||||
case (CSRAdrM)
|
||||
USTATUS: CSRNReadValM = USTATUS_REGW;
|
||||
UTVEC: CSRNReadValM = UTVEC_REGW;
|
||||
UIP: CSRNReadValM = {{(`XLEN-12){1'b0}}, UIP_REGW};
|
||||
UIE: CSRNReadValM = {{(`XLEN-12){1'b0}}, UIE_REGW};
|
||||
USCRATCH: CSRNReadValM = USCRATCH_REGW;
|
||||
UEPC: CSRNReadValM = UEPC_REGW;
|
||||
UCAUSE: CSRNReadValM = UCAUSE_REGW;
|
||||
UTVAL: CSRNReadValM = UTVAL_REGW;
|
||||
default: begin
|
||||
CSRNReadValM = 0;
|
||||
IllegalCSRNAccessM = 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
end else begin // if not supported
|
||||
assign WriteUSTATUSM = 0;
|
||||
assign CSRNReadValM = 0;
|
||||
assign UEPC_REGW = 0;
|
||||
assign UTVEC_REGW = 0;
|
||||
assign IllegalCSRNAccessM = 1;
|
||||
end
|
||||
endmodule
|
||||
|
@ -69,89 +69,87 @@ module csrs #(parameter
|
||||
//logic [`XLEN-1:0] SEDELEG_MASK = ~(zero | 3'b111 << 9); // sedeleg[11:9] hardwired to zero per Privileged Spec 3.1.8
|
||||
|
||||
// Supervisor mode CSRs sometimes supported
|
||||
generate
|
||||
if (`S_SUPPORTED) begin:csrs
|
||||
logic WriteSTVECM;
|
||||
logic WriteSSCRATCHM, WriteSEPCM;
|
||||
logic WriteSCAUSEM, WriteSTVALM, WriteSATPM, WriteSCOUNTERENM;
|
||||
logic [`XLEN-1:0] SSCRATCH_REGW, STVAL_REGW;
|
||||
(* mark_debug = "true" *) logic [`XLEN-1:0] SCAUSE_REGW;
|
||||
|
||||
assign WriteSSTATUSM = CSRSWriteM & (CSRAdrM == SSTATUS) & ~StallW;
|
||||
assign WriteSTVECM = CSRSWriteM & (CSRAdrM == STVEC) & ~StallW;
|
||||
assign WriteSSCRATCHM = CSRSWriteM & (CSRAdrM == SSCRATCH) & ~StallW;
|
||||
assign WriteSEPCM = STrapM | (CSRSWriteM & (CSRAdrM == SEPC)) & ~StallW;
|
||||
assign WriteSCAUSEM = STrapM | (CSRSWriteM & (CSRAdrM == SCAUSE)) & ~StallW;
|
||||
assign WriteSTVALM = STrapM | (CSRSWriteM & (CSRAdrM == STVAL)) & ~StallW;
|
||||
assign WriteSATPM = CSRSWriteM & (CSRAdrM == SATP) & (PrivilegeModeW == `M_MODE | ~STATUS_TVM) & ~StallW;
|
||||
assign WriteSCOUNTERENM = CSRSWriteM & (CSRAdrM == SCOUNTEREN) & ~StallW;
|
||||
if (`S_SUPPORTED) begin:csrs
|
||||
logic WriteSTVECM;
|
||||
logic WriteSSCRATCHM, WriteSEPCM;
|
||||
logic WriteSCAUSEM, WriteSTVALM, WriteSATPM, WriteSCOUNTERENM;
|
||||
logic [`XLEN-1:0] SSCRATCH_REGW, STVAL_REGW;
|
||||
(* mark_debug = "true" *) logic [`XLEN-1:0] SCAUSE_REGW;
|
||||
|
||||
assign WriteSSTATUSM = CSRSWriteM & (CSRAdrM == SSTATUS) & ~StallW;
|
||||
assign WriteSTVECM = CSRSWriteM & (CSRAdrM == STVEC) & ~StallW;
|
||||
assign WriteSSCRATCHM = CSRSWriteM & (CSRAdrM == SSCRATCH) & ~StallW;
|
||||
assign WriteSEPCM = STrapM | (CSRSWriteM & (CSRAdrM == SEPC)) & ~StallW;
|
||||
assign WriteSCAUSEM = STrapM | (CSRSWriteM & (CSRAdrM == SCAUSE)) & ~StallW;
|
||||
assign WriteSTVALM = STrapM | (CSRSWriteM & (CSRAdrM == STVAL)) & ~StallW;
|
||||
assign WriteSATPM = CSRSWriteM & (CSRAdrM == SATP) & (PrivilegeModeW == `M_MODE | ~STATUS_TVM) & ~StallW;
|
||||
assign WriteSCOUNTERENM = CSRSWriteM & (CSRAdrM == SCOUNTEREN) & ~StallW;
|
||||
|
||||
// CSRs
|
||||
flopenr #(`XLEN) STVECreg(clk, reset, WriteSTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, STVEC_REGW); //busybear: change reset to 0
|
||||
flopenr #(`XLEN) SSCRATCHreg(clk, reset, WriteSSCRATCHM, CSRWriteValM, SSCRATCH_REGW);
|
||||
flopenr #(`XLEN) SEPCreg(clk, reset, WriteSEPCM, NextEPCM, SEPC_REGW);
|
||||
flopenr #(`XLEN) SCAUSEreg(clk, reset, WriteSCAUSEM, NextCauseM, SCAUSE_REGW);
|
||||
flopenr #(`XLEN) STVALreg(clk, reset, WriteSTVALM, NextMtvalM, STVAL_REGW);
|
||||
if (`MEM_VIRTMEM)
|
||||
flopenr #(`XLEN) SATPreg(clk, reset, WriteSATPM, CSRWriteValM, SATP_REGW);
|
||||
else
|
||||
assign SATP_REGW = 0; // hardwire to zero if virtual memory not supported
|
||||
if (`BUSYBEAR == 1) begin:scounteren
|
||||
flopenr #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, {CSRWriteValM[31:2],1'b0,CSRWriteValM[0]}, SCOUNTEREN_REGW);
|
||||
end else if (`BUILDROOT == 1) begin:scounteren
|
||||
flopenr #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, CSRWriteValM[31:0], SCOUNTEREN_REGW);
|
||||
end else begin:scounteren
|
||||
flopens #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, CSRWriteValM[31:0], SCOUNTEREN_REGW);
|
||||
end
|
||||
if (`N_SUPPORTED) begin:nregs
|
||||
logic WriteSEDELEGM, WriteSIDELEGM;
|
||||
assign WriteSEDELEGM = CSRSWriteM & (CSRAdrM == SEDELEG);
|
||||
assign WriteSIDELEGM = CSRSWriteM & (CSRAdrM == SIDELEG);
|
||||
flopenr #(`XLEN) SEDELEGreg(clk, reset, WriteSEDELEGM, CSRWriteValM & SEDELEG_MASK, SEDELEG_REGW);
|
||||
flopenr #(`XLEN) SIDELEGreg(clk, reset, WriteSIDELEGM, CSRWriteValM, SIDELEG_REGW);
|
||||
end else begin
|
||||
assign SEDELEG_REGW = 0;
|
||||
assign SIDELEG_REGW = 0;
|
||||
end
|
||||
|
||||
// CSR Reads
|
||||
always_comb begin:csrr
|
||||
IllegalCSRSAccessM = !(`N_SUPPORTED) & (CSRAdrM == SEDELEG | CSRAdrM == SIDELEG); // trap on DELEG register access when no N-mode
|
||||
case (CSRAdrM)
|
||||
SSTATUS: CSRSReadValM = SSTATUS_REGW;
|
||||
STVEC: CSRSReadValM = STVEC_REGW;
|
||||
// SIDELEG: CSRSReadValM = {{(`XLEN-12){1'b0}}, SIDELEG_REGW};
|
||||
// SEDELEG: CSRSReadValM = {{(`XLEN-12){1'b0}}, SEDELEG_REGW};
|
||||
SIDELEG: CSRSReadValM = SIDELEG_REGW;
|
||||
SEDELEG: CSRSReadValM = SEDELEG_REGW;
|
||||
SIP: CSRSReadValM = {{(`XLEN-12){1'b0}}, SIP_REGW};
|
||||
SIE: CSRSReadValM = {{(`XLEN-12){1'b0}}, SIE_REGW};
|
||||
SSCRATCH: CSRSReadValM = SSCRATCH_REGW;
|
||||
SEPC: CSRSReadValM = SEPC_REGW;
|
||||
SCAUSE: CSRSReadValM = SCAUSE_REGW;
|
||||
STVAL: CSRSReadValM = STVAL_REGW;
|
||||
SATP: if (`MEM_VIRTMEM & (PrivilegeModeW == `M_MODE | ~STATUS_TVM)) CSRSReadValM = SATP_REGW;
|
||||
else begin
|
||||
CSRSReadValM = 0;
|
||||
if (PrivilegeModeW == `S_MODE & STATUS_TVM) IllegalCSRSAccessM = 1;
|
||||
end
|
||||
SCOUNTEREN:CSRSReadValM = {{(`XLEN-32){1'b0}}, SCOUNTEREN_REGW};
|
||||
default: begin
|
||||
CSRSReadValM = 0;
|
||||
IllegalCSRSAccessM = 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
// CSRs
|
||||
flopenr #(`XLEN) STVECreg(clk, reset, WriteSTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, STVEC_REGW); //busybear: change reset to 0
|
||||
flopenr #(`XLEN) SSCRATCHreg(clk, reset, WriteSSCRATCHM, CSRWriteValM, SSCRATCH_REGW);
|
||||
flopenr #(`XLEN) SEPCreg(clk, reset, WriteSEPCM, NextEPCM, SEPC_REGW);
|
||||
flopenr #(`XLEN) SCAUSEreg(clk, reset, WriteSCAUSEM, NextCauseM, SCAUSE_REGW);
|
||||
flopenr #(`XLEN) STVALreg(clk, reset, WriteSTVALM, NextMtvalM, STVAL_REGW);
|
||||
if (`MEM_VIRTMEM)
|
||||
flopenr #(`XLEN) SATPreg(clk, reset, WriteSATPM, CSRWriteValM, SATP_REGW);
|
||||
else
|
||||
assign SATP_REGW = 0; // hardwire to zero if virtual memory not supported
|
||||
if (`BUSYBEAR == 1) begin:scounteren
|
||||
flopenr #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, {CSRWriteValM[31:2],1'b0,CSRWriteValM[0]}, SCOUNTEREN_REGW);
|
||||
end else if (`BUILDROOT == 1) begin:scounteren
|
||||
flopenr #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, CSRWriteValM[31:0], SCOUNTEREN_REGW);
|
||||
end else begin:scounteren
|
||||
flopens #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, CSRWriteValM[31:0], SCOUNTEREN_REGW);
|
||||
end
|
||||
if (`N_SUPPORTED) begin:nregs
|
||||
logic WriteSEDELEGM, WriteSIDELEGM;
|
||||
assign WriteSEDELEGM = CSRSWriteM & (CSRAdrM == SEDELEG);
|
||||
assign WriteSIDELEGM = CSRSWriteM & (CSRAdrM == SIDELEG);
|
||||
flopenr #(`XLEN) SEDELEGreg(clk, reset, WriteSEDELEGM, CSRWriteValM & SEDELEG_MASK, SEDELEG_REGW);
|
||||
flopenr #(`XLEN) SIDELEGreg(clk, reset, WriteSIDELEGM, CSRWriteValM, SIDELEG_REGW);
|
||||
end else begin
|
||||
assign WriteSSTATUSM = 0;
|
||||
assign CSRSReadValM = 0;
|
||||
assign SEPC_REGW = 0;
|
||||
assign STVEC_REGW = 0;
|
||||
assign SEDELEG_REGW = 0;
|
||||
assign SIDELEG_REGW = 0;
|
||||
assign SCOUNTEREN_REGW = 0;
|
||||
assign SATP_REGW = 0;
|
||||
assign IllegalCSRSAccessM = 1;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// CSR Reads
|
||||
always_comb begin:csrr
|
||||
IllegalCSRSAccessM = !(`N_SUPPORTED) & (CSRAdrM == SEDELEG | CSRAdrM == SIDELEG); // trap on DELEG register access when no N-mode
|
||||
case (CSRAdrM)
|
||||
SSTATUS: CSRSReadValM = SSTATUS_REGW;
|
||||
STVEC: CSRSReadValM = STVEC_REGW;
|
||||
// SIDELEG: CSRSReadValM = {{(`XLEN-12){1'b0}}, SIDELEG_REGW};
|
||||
// SEDELEG: CSRSReadValM = {{(`XLEN-12){1'b0}}, SEDELEG_REGW};
|
||||
SIDELEG: CSRSReadValM = SIDELEG_REGW;
|
||||
SEDELEG: CSRSReadValM = SEDELEG_REGW;
|
||||
SIP: CSRSReadValM = {{(`XLEN-12){1'b0}}, SIP_REGW};
|
||||
SIE: CSRSReadValM = {{(`XLEN-12){1'b0}}, SIE_REGW};
|
||||
SSCRATCH: CSRSReadValM = SSCRATCH_REGW;
|
||||
SEPC: CSRSReadValM = SEPC_REGW;
|
||||
SCAUSE: CSRSReadValM = SCAUSE_REGW;
|
||||
STVAL: CSRSReadValM = STVAL_REGW;
|
||||
SATP: if (`MEM_VIRTMEM & (PrivilegeModeW == `M_MODE | ~STATUS_TVM)) CSRSReadValM = SATP_REGW;
|
||||
else begin
|
||||
CSRSReadValM = 0;
|
||||
if (PrivilegeModeW == `S_MODE & STATUS_TVM) IllegalCSRSAccessM = 1;
|
||||
end
|
||||
SCOUNTEREN:CSRSReadValM = {{(`XLEN-32){1'b0}}, SCOUNTEREN_REGW};
|
||||
default: begin
|
||||
CSRSReadValM = 0;
|
||||
IllegalCSRSAccessM = 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end else begin
|
||||
assign WriteSSTATUSM = 0;
|
||||
assign CSRSReadValM = 0;
|
||||
assign SEPC_REGW = 0;
|
||||
assign STVEC_REGW = 0;
|
||||
assign SEDELEG_REGW = 0;
|
||||
assign SIDELEG_REGW = 0;
|
||||
assign SCOUNTEREN_REGW = 0;
|
||||
assign SATP_REGW = 0;
|
||||
assign IllegalCSRSAccessM = 1;
|
||||
end
|
||||
endmodule
|
||||
|
@ -50,54 +50,50 @@ module csrsr (
|
||||
// See Privileged Spec Section 3.1.6
|
||||
// Lower privilege status registers are a subset of the full status register
|
||||
// *** consider adding MBE, SBE, UBE fields later from 20210108 draft spec
|
||||
generate
|
||||
if (`XLEN==64) begin: csrsr64 // RV64
|
||||
assign MSTATUS_REGW = {STATUS_SD, 27'b0, STATUS_SXL, STATUS_UXL, 9'b0,
|
||||
STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
STATUS_XS, STATUS_FS, STATUS_MPP, 2'b0,
|
||||
STATUS_SPP, STATUS_MPIE, 1'b0, STATUS_SPIE, STATUS_UPIE,
|
||||
STATUS_MIE, 1'b0, STATUS_SIE, STATUS_UIE};
|
||||
assign SSTATUS_REGW = {STATUS_SD, /*27'b0, */ 29'b0, /*STATUS_SXL, */ STATUS_UXL, /*9'b0, */ 12'b0,
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, */STATUS_MXR, STATUS_SUM, /* STATUS_MPRV, */ 1'b0,
|
||||
STATUS_XS, STATUS_FS, /*STATUS_MPP, 2'b0*/ 4'b0,
|
||||
STATUS_SPP, /*STATUS_MPIE, 1'b0*/ 2'b0, STATUS_SPIE, STATUS_UPIE,
|
||||
/*STATUS_MIE, 1'b0*/ 2'b0, STATUS_SIE, STATUS_UIE};
|
||||
assign USTATUS_REGW = {/*STATUS_SD, */ 59'b0, /*STATUS_SXL, STATUS_UXL, 9'b0, */
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV, , 1'b0,*/
|
||||
/* STATUS_XS, STATUS_FS, /*STATUS_MPP, 8'b0, */
|
||||
/*STATUS_SPP, STATUS_MPIE, 1'b0 2'b0, STATUS_SPIE,*/ STATUS_UPIE,
|
||||
/*STATUS_MIE, 1'b0*/ 3'b0, /*STATUS_SIE, */STATUS_UIE};
|
||||
end else begin: csrsr32 // RV32
|
||||
assign MSTATUS_REGW = {STATUS_SD, 8'b0,
|
||||
STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
STATUS_XS, STATUS_FS, STATUS_MPP, 2'b0,
|
||||
STATUS_SPP, STATUS_MPIE, 1'b0, STATUS_SPIE, STATUS_UPIE, STATUS_MIE, 1'b0, STATUS_SIE, STATUS_UIE};
|
||||
assign SSTATUS_REGW = {STATUS_SD, 11'b0,
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, */STATUS_MXR, STATUS_SUM, /* STATUS_MPRV, */ 1'b0,
|
||||
STATUS_XS, STATUS_FS, /*STATUS_MPP, 2'b0*/ 4'b0,
|
||||
STATUS_SPP, /*STATUS_MPIE, 1'b0*/ 2'b0, STATUS_SPIE, STATUS_UPIE,
|
||||
/*STATUS_MIE, 1'b0*/ 2'b0, STATUS_SIE, STATUS_UIE};
|
||||
assign USTATUS_REGW = {/*STATUS_SD, */ 27'b0, /*STATUS_SXL, STATUS_UXL, 9'b0, */
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV, , 1'b0,*/
|
||||
/*STATUS_XS, STATUS_FS, STATUS_MPP, 8'b0, */
|
||||
/*STATUS_SPP, STATUS_MPIE, 1'b0 2'b0, STATUS_SPIE,*/ STATUS_UPIE,
|
||||
/*STATUS_MIE, 1'b0*/ 3'b0, /*STATUS_SIE, */STATUS_UIE};
|
||||
end
|
||||
endgenerate
|
||||
if (`XLEN==64) begin: csrsr64 // RV64
|
||||
assign MSTATUS_REGW = {STATUS_SD, 27'b0, STATUS_SXL, STATUS_UXL, 9'b0,
|
||||
STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
STATUS_XS, STATUS_FS, STATUS_MPP, 2'b0,
|
||||
STATUS_SPP, STATUS_MPIE, 1'b0, STATUS_SPIE, STATUS_UPIE,
|
||||
STATUS_MIE, 1'b0, STATUS_SIE, STATUS_UIE};
|
||||
assign SSTATUS_REGW = {STATUS_SD, /*27'b0, */ 29'b0, /*STATUS_SXL, */ STATUS_UXL, /*9'b0, */ 12'b0,
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, */STATUS_MXR, STATUS_SUM, /* STATUS_MPRV, */ 1'b0,
|
||||
STATUS_XS, STATUS_FS, /*STATUS_MPP, 2'b0*/ 4'b0,
|
||||
STATUS_SPP, /*STATUS_MPIE, 1'b0*/ 2'b0, STATUS_SPIE, STATUS_UPIE,
|
||||
/*STATUS_MIE, 1'b0*/ 2'b0, STATUS_SIE, STATUS_UIE};
|
||||
assign USTATUS_REGW = {/*STATUS_SD, */ 59'b0, /*STATUS_SXL, STATUS_UXL, 9'b0, */
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV, , 1'b0,*/
|
||||
/* STATUS_XS, STATUS_FS, /*STATUS_MPP, 8'b0, */
|
||||
/*STATUS_SPP, STATUS_MPIE, 1'b0 2'b0, STATUS_SPIE,*/ STATUS_UPIE,
|
||||
/*STATUS_MIE, 1'b0*/ 3'b0, /*STATUS_SIE, */STATUS_UIE};
|
||||
end else begin: csrsr32 // RV32
|
||||
assign MSTATUS_REGW = {STATUS_SD, 8'b0,
|
||||
STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
STATUS_XS, STATUS_FS, STATUS_MPP, 2'b0,
|
||||
STATUS_SPP, STATUS_MPIE, 1'b0, STATUS_SPIE, STATUS_UPIE, STATUS_MIE, 1'b0, STATUS_SIE, STATUS_UIE};
|
||||
assign SSTATUS_REGW = {STATUS_SD, 11'b0,
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, */STATUS_MXR, STATUS_SUM, /* STATUS_MPRV, */ 1'b0,
|
||||
STATUS_XS, STATUS_FS, /*STATUS_MPP, 2'b0*/ 4'b0,
|
||||
STATUS_SPP, /*STATUS_MPIE, 1'b0*/ 2'b0, STATUS_SPIE, STATUS_UPIE,
|
||||
/*STATUS_MIE, 1'b0*/ 2'b0, STATUS_SIE, STATUS_UIE};
|
||||
assign USTATUS_REGW = {/*STATUS_SD, */ 27'b0, /*STATUS_SXL, STATUS_UXL, 9'b0, */
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV, , 1'b0,*/
|
||||
/*STATUS_XS, STATUS_FS, STATUS_MPP, 8'b0, */
|
||||
/*STATUS_SPP, STATUS_MPIE, 1'b0 2'b0, STATUS_SPIE,*/ STATUS_UPIE,
|
||||
/*STATUS_MIE, 1'b0*/ 3'b0, /*STATUS_SIE, */STATUS_UIE};
|
||||
end
|
||||
|
||||
// harwired STATUS bits
|
||||
generate
|
||||
assign STATUS_TSR = `S_SUPPORTED & STATUS_TSR_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_TW = (`S_SUPPORTED | `U_SUPPORTED) & STATUS_TW_INT; // override reigster with 0 if only machine mode supported
|
||||
assign STATUS_TVM = `S_SUPPORTED & STATUS_TVM_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_MXR = `S_SUPPORTED & STATUS_MXR_INT; // override reigster with 0 if supervisor mode not supported
|
||||
// SXL and UXL bits only matter for RV64. Set to 10 for RV64 if mode is supported, or 0 if not
|
||||
assign STATUS_SXL = `S_SUPPORTED & ~`QEMU ? 2'b10 : 2'b00; // 10 if supervisor mode supported
|
||||
assign STATUS_UXL = `U_SUPPORTED & ~`QEMU ? 2'b10 : 2'b00; // 10 if user mode supported
|
||||
assign STATUS_SUM = `S_SUPPORTED & `MEM_VIRTMEM & STATUS_SUM_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_MPRV = `U_SUPPORTED & STATUS_MPRV_INT; // override with 0 if user mode not supported
|
||||
assign STATUS_FS = (`S_SUPPORTED & (`F_SUPPORTED | `D_SUPPORTED)) ? STATUS_FS_INT : 2'b00; // off if no FP
|
||||
endgenerate
|
||||
assign STATUS_TSR = `S_SUPPORTED & STATUS_TSR_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_TW = (`S_SUPPORTED | `U_SUPPORTED) & STATUS_TW_INT; // override reigster with 0 if only machine mode supported
|
||||
assign STATUS_TVM = `S_SUPPORTED & STATUS_TVM_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_MXR = `S_SUPPORTED & STATUS_MXR_INT; // override reigster with 0 if supervisor mode not supported
|
||||
// SXL and UXL bits only matter for RV64. Set to 10 for RV64 if mode is supported, or 0 if not
|
||||
assign STATUS_SXL = `S_SUPPORTED & ~`QEMU ? 2'b10 : 2'b00; // 10 if supervisor mode supported
|
||||
assign STATUS_UXL = `U_SUPPORTED & ~`QEMU ? 2'b10 : 2'b00; // 10 if user mode supported
|
||||
assign STATUS_SUM = `S_SUPPORTED & `MEM_VIRTMEM & STATUS_SUM_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_MPRV = `U_SUPPORTED & STATUS_MPRV_INT; // override with 0 if user mode not supported
|
||||
assign STATUS_FS = (`S_SUPPORTED & (`F_SUPPORTED | `D_SUPPORTED)) ? STATUS_FS_INT : 2'b00; // off if no FP
|
||||
assign STATUS_SD = (STATUS_FS == 2'b11) | (STATUS_XS == 2'b11); // dirty state logic
|
||||
assign STATUS_XS = 2'b00; // No additional user-mode state to be dirty
|
||||
|
||||
|
@ -44,42 +44,40 @@ module csru #(parameter
|
||||
);
|
||||
|
||||
// Floating Point CSRs in User Mode only needed if Floating Point is supported
|
||||
generate
|
||||
if (`F_SUPPORTED | `D_SUPPORTED) begin:csru
|
||||
logic [4:0] FFLAGS_REGW;
|
||||
logic [2:0] NextFRMM;
|
||||
logic [4:0] NextFFLAGSM;
|
||||
|
||||
// Write enables
|
||||
//assign WriteFCSRM = CSRUWriteM & (CSRAdrM == FCSR) & ~StallW;
|
||||
assign WriteFRMM = (CSRUWriteM & (CSRAdrM == FRM | CSRAdrM == FCSR)) & ~StallW;
|
||||
assign WriteFFLAGSM = (CSRUWriteM & (CSRAdrM == FFLAGS | CSRAdrM == FCSR)) & ~StallW;
|
||||
|
||||
// Write Values
|
||||
assign NextFRMM = (CSRAdrM == FCSR) ? CSRWriteValM[7:5] : CSRWriteValM[2:0];
|
||||
assign NextFFLAGSM = WriteFFLAGSM ? CSRWriteValM[4:0] : FFLAGS_REGW | SetFflagsM;
|
||||
if (`F_SUPPORTED | `D_SUPPORTED) begin:csru
|
||||
logic [4:0] FFLAGS_REGW;
|
||||
logic [2:0] NextFRMM;
|
||||
logic [4:0] NextFFLAGSM;
|
||||
|
||||
// Write enables
|
||||
//assign WriteFCSRM = CSRUWriteM & (CSRAdrM == FCSR) & ~StallW;
|
||||
assign WriteFRMM = (CSRUWriteM & (CSRAdrM == FRM | CSRAdrM == FCSR)) & ~StallW;
|
||||
assign WriteFFLAGSM = (CSRUWriteM & (CSRAdrM == FFLAGS | CSRAdrM == FCSR)) & ~StallW;
|
||||
|
||||
// Write Values
|
||||
assign NextFRMM = (CSRAdrM == FCSR) ? CSRWriteValM[7:5] : CSRWriteValM[2:0];
|
||||
assign NextFFLAGSM = WriteFFLAGSM ? CSRWriteValM[4:0] : FFLAGS_REGW | SetFflagsM;
|
||||
|
||||
// CSRs
|
||||
flopenr #(3) FRMreg(clk, reset, WriteFRMM, NextFRMM, FRM_REGW);
|
||||
flopr #(5) FFLAGSreg(clk, reset, NextFFLAGSM, FFLAGS_REGW);
|
||||
// CSRs
|
||||
flopenr #(3) FRMreg(clk, reset, WriteFRMM, NextFRMM, FRM_REGW);
|
||||
flopr #(5) FFLAGSreg(clk, reset, NextFFLAGSM, FFLAGS_REGW);
|
||||
|
||||
// CSR Reads
|
||||
always_comb begin
|
||||
IllegalCSRUAccessM = 0;
|
||||
case (CSRAdrM)
|
||||
FFLAGS: CSRUReadValM = {{(`XLEN-5){1'b0}}, FFLAGS_REGW};
|
||||
FRM: CSRUReadValM = {{(`XLEN-3){1'b0}}, FRM_REGW};
|
||||
FCSR: CSRUReadValM = {{(`XLEN-8){1'b0}}, FRM_REGW, FFLAGS_REGW};
|
||||
default: begin
|
||||
CSRUReadValM = 0;
|
||||
IllegalCSRUAccessM = 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end else begin // if not supported
|
||||
assign FRM_REGW = 0;
|
||||
assign CSRUReadValM = 0;
|
||||
assign IllegalCSRUAccessM = 1;
|
||||
// CSR Reads
|
||||
always_comb begin
|
||||
IllegalCSRUAccessM = 0;
|
||||
case (CSRAdrM)
|
||||
FFLAGS: CSRUReadValM = {{(`XLEN-5){1'b0}}, FFLAGS_REGW};
|
||||
FRM: CSRUReadValM = {{(`XLEN-3){1'b0}}, FRM_REGW};
|
||||
FCSR: CSRUReadValM = {{(`XLEN-8){1'b0}}, FRM_REGW, FFLAGS_REGW};
|
||||
default: begin
|
||||
CSRUReadValM = 0;
|
||||
IllegalCSRUAccessM = 1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endgenerate
|
||||
end else begin // if not supported
|
||||
assign FRM_REGW = 0;
|
||||
assign CSRUReadValM = 0;
|
||||
assign IllegalCSRUAccessM = 1;
|
||||
end
|
||||
endmodule
|
||||
|
@ -103,18 +103,16 @@ module trap (
|
||||
// > implemented without a hardware adder circuit.
|
||||
// For example, we could require m/stvec be aligned on 7 bits to let us replace the adder directly below with
|
||||
// [untested] PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:7], CauseM[3:0], 4'b0000}
|
||||
generate
|
||||
if(`VECTORED_INTERRUPTS_SUPPORTED) begin:vec
|
||||
always_comb
|
||||
if (PrivilegedTrapVector[1:0] == 2'b01 & CauseM[`XLEN-1] == 1)
|
||||
PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2] + {CauseM[`XLEN-5:0], 2'b00}, 2'b00};
|
||||
else
|
||||
PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2], 2'b00};
|
||||
end
|
||||
else begin
|
||||
assign PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2], 2'b00};
|
||||
end
|
||||
endgenerate
|
||||
if(`VECTORED_INTERRUPTS_SUPPORTED) begin:vec
|
||||
always_comb
|
||||
if (PrivilegedTrapVector[1:0] == 2'b01 & CauseM[`XLEN-1] == 1)
|
||||
PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2] + {CauseM[`XLEN-5:0], 2'b00}, 2'b00};
|
||||
else
|
||||
PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2], 2'b00};
|
||||
end
|
||||
else begin
|
||||
assign PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2], 2'b00};
|
||||
end
|
||||
|
||||
always_comb
|
||||
if (mretM) PrivilegedNextPCM = MEPC_REGW;
|
||||
|
@ -55,12 +55,8 @@ module clint (
|
||||
assign HREADYCLINT = 1'b1; // *** needs to depend on DONE during accesses
|
||||
|
||||
// word aligned reads
|
||||
generate
|
||||
if (`XLEN==64)
|
||||
assign #2 entry = {HADDR[15:3], 3'b000};
|
||||
else
|
||||
assign #2 entry = {HADDR[15:2], 2'b00};
|
||||
endgenerate
|
||||
if (`XLEN==64) assign #2 entry = {HADDR[15:3], 3'b000};
|
||||
else assign #2 entry = {HADDR[15:2], 2'b00};
|
||||
|
||||
// DH 2/20/21: Eventually allow MTIME to run off a separate clock
|
||||
// This will require synchronizing MTIME to the system clock
|
||||
@ -69,74 +65,72 @@ module clint (
|
||||
// Use req and ack signals synchronized across the clock domains.
|
||||
|
||||
// register access
|
||||
generate
|
||||
if (`XLEN==64) begin:clint // 64-bit
|
||||
always @(posedge HCLK) begin
|
||||
case(entry)
|
||||
16'h0000: HREADCLINT <= {63'b0, MSIP};
|
||||
16'h4000: HREADCLINT <= MTIMECMP;
|
||||
16'hBFF8: HREADCLINT <= MTIME;
|
||||
default: HREADCLINT <= 0;
|
||||
endcase
|
||||
end
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MSIP <= 0;
|
||||
MTIMECMP <= 0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite) begin
|
||||
if (entryd == 16'h0000) MSIP <= HWDATA[0];
|
||||
if (entryd == 16'h4000) MTIMECMP <= HWDATA;
|
||||
end
|
||||
|
||||
// eventually replace MTIME logic below with timereg
|
||||
// timereg tr(HCLK, HRESETn, TIMECLK, memwrite & (entryd==16'hBFF8), 1'b0, HWDATA, MTIME, done);
|
||||
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MTIME <= 0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite & entryd == 16'hBFF8) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
MTIME <= HWDATA;
|
||||
end else MTIME <= MTIME + 1;
|
||||
end else begin:clint // 32-bit
|
||||
always @(posedge HCLK) begin
|
||||
case(entry)
|
||||
16'h0000: HREADCLINT <= {31'b0, MSIP};
|
||||
16'h4000: HREADCLINT <= MTIMECMP[31:0];
|
||||
16'h4004: HREADCLINT <= MTIMECMP[63:32];
|
||||
16'hBFF8: HREADCLINT <= MTIME[31:0];
|
||||
16'hBFFC: HREADCLINT <= MTIME[63:32];
|
||||
default: HREADCLINT <= 0;
|
||||
endcase
|
||||
end
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MSIP <= 0;
|
||||
MTIMECMP <= 0;
|
||||
// MTIMECMP is not reset ***?
|
||||
end else if (memwrite) begin
|
||||
if (entryd == 16'h0000) MSIP <= HWDATA[0];
|
||||
if (entryd == 16'h4000) MTIMECMP[31:0] <= HWDATA;
|
||||
if (entryd == 16'h4004) MTIMECMP[63:32] <= HWDATA;
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
end
|
||||
if (`XLEN==64) begin:clint // 64-bit
|
||||
always @(posedge HCLK) begin
|
||||
case(entry)
|
||||
16'h0000: HREADCLINT <= {63'b0, MSIP};
|
||||
16'h4000: HREADCLINT <= MTIMECMP;
|
||||
16'hBFF8: HREADCLINT <= MTIME;
|
||||
default: HREADCLINT <= 0;
|
||||
endcase
|
||||
end
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MSIP <= 0;
|
||||
MTIMECMP <= 0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite) begin
|
||||
if (entryd == 16'h0000) MSIP <= HWDATA[0];
|
||||
if (entryd == 16'h4000) MTIMECMP <= HWDATA;
|
||||
end
|
||||
|
||||
// eventually replace MTIME logic below with timereg
|
||||
// timereg tr(HCLK, HRESETn, TIMECLK, memwrite & (entryd==16'hBFF8), memwrite & (entryd == 16'hBFFC), HWDATA, MTIME, done);
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MTIME <= 0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite & (entryd == 16'hBFF8)) begin
|
||||
MTIME[31:0] <= HWDATA;
|
||||
end else if (memwrite & (entryd == 16'hBFFC)) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
MTIME[63:32]<= HWDATA;
|
||||
end else MTIME <= MTIME + 1;
|
||||
// timereg tr(HCLK, HRESETn, TIMECLK, memwrite & (entryd==16'hBFF8), 1'b0, HWDATA, MTIME, done);
|
||||
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MTIME <= 0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite & entryd == 16'hBFF8) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
MTIME <= HWDATA;
|
||||
end else MTIME <= MTIME + 1;
|
||||
end else begin:clint // 32-bit
|
||||
always @(posedge HCLK) begin
|
||||
case(entry)
|
||||
16'h0000: HREADCLINT <= {31'b0, MSIP};
|
||||
16'h4000: HREADCLINT <= MTIMECMP[31:0];
|
||||
16'h4004: HREADCLINT <= MTIMECMP[63:32];
|
||||
16'hBFF8: HREADCLINT <= MTIME[31:0];
|
||||
16'hBFFC: HREADCLINT <= MTIME[63:32];
|
||||
default: HREADCLINT <= 0;
|
||||
endcase
|
||||
end
|
||||
endgenerate
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MSIP <= 0;
|
||||
MTIMECMP <= 0;
|
||||
// MTIMECMP is not reset ***?
|
||||
end else if (memwrite) begin
|
||||
if (entryd == 16'h0000) MSIP <= HWDATA[0];
|
||||
if (entryd == 16'h4000) MTIMECMP[31:0] <= HWDATA;
|
||||
if (entryd == 16'h4004) MTIMECMP[63:32] <= HWDATA;
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
end
|
||||
|
||||
// eventually replace MTIME logic below with timereg
|
||||
// timereg tr(HCLK, HRESETn, TIMECLK, memwrite & (entryd==16'hBFF8), memwrite & (entryd == 16'hBFFC), HWDATA, MTIME, done);
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MTIME <= 0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite & (entryd == 16'hBFF8)) begin
|
||||
MTIME[31:0] <= HWDATA;
|
||||
end else if (memwrite & (entryd == 16'hBFFC)) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
MTIME[63:32]<= HWDATA;
|
||||
end else MTIME <= MTIME + 1;
|
||||
end
|
||||
|
||||
// Software interrupt when MSIP is set
|
||||
assign SwIntM = MSIP;
|
||||
@ -234,13 +228,9 @@ module graytobinary #(parameter N = `XLEN) (
|
||||
|
||||
// B[N-1] = G[N-1]; B[i] = G[i] ^ B[i+1] for 0 <= i < N-1
|
||||
// requires rippling through N-1 XOR gates
|
||||
generate
|
||||
begin
|
||||
genvar i;
|
||||
assign b[N-1] = g[N-1];
|
||||
for (i=N-2; i >= 0; i--) begin:g2b
|
||||
assign b[i] = g[i] ^ b[i+1];
|
||||
end
|
||||
genvar i;
|
||||
assign b[N-1] = g[N-1];
|
||||
for (i=N-2; i >= 0; i--) begin:g2b
|
||||
assign b[i] = g[i] ^ b[i+1];
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
|
@ -61,23 +61,13 @@ module gpio (
|
||||
// account for subword read/write circuitry
|
||||
// -- Note GPIO registers are 32 bits no matter what; access them with LW SW.
|
||||
// (At least that's what I think when FE310 spec says "only naturally aligned 32-bit accesses are supported")
|
||||
generate
|
||||
if (`XLEN == 64) begin:gpio
|
||||
always_comb
|
||||
if (entryd[2]) begin
|
||||
Din = HWDATA[63:32];
|
||||
HREADGPIO = {Dout,32'b0};
|
||||
end else begin
|
||||
Din = HWDATA[31:0];
|
||||
HREADGPIO = {32'b0,Dout};
|
||||
end
|
||||
end else begin:gpio // 32-bit
|
||||
always_comb begin
|
||||
Din = HWDATA[31:0];
|
||||
HREADGPIO = Dout;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
if (`XLEN == 64) begin:gpio
|
||||
assign Din = entryd[2] ? HWDATA[63:32] : HWDATA[31:0];
|
||||
assign HREADGPIO = entryd[2] ? {Dout,32'b0} : {32'b0,Dout};
|
||||
end else begin:gpio // 32-bit
|
||||
assign Din = HWDATA[31:0];
|
||||
assign HREADGPIO = Dout;
|
||||
end
|
||||
|
||||
// register access
|
||||
always_ff @(posedge HCLK, negedge HRESETn) begin
|
||||
|
Loading…
Reference in New Issue
Block a user