forked from Github_Repos/cvw
Merge branch 'main' into busybear
Conflicts: wally-pipelined/src/uncore/imem.sv
This commit is contained in:
commit
827dfd774b
@ -43,46 +43,54 @@ add wave /testbench/clk
|
|||||||
add wave /testbench/reset
|
add wave /testbench/reset
|
||||||
add wave -divider
|
add wave -divider
|
||||||
#add wave /testbench/dut/hart/ebu/IReadF
|
#add wave /testbench/dut/hart/ebu/IReadF
|
||||||
add wave /testbench/dut/hart/DataStall
|
#add wave /testbench/dut/hart/DataStall
|
||||||
add wave /testbench/dut/hart/InstrStall
|
#add wave /testbench/dut/hart/InstrStall
|
||||||
add wave /testbench/dut/hart/StallF
|
#add wave /testbench/dut/hart/StallF
|
||||||
add wave /testbench/dut/hart/StallD
|
#add wave /testbench/dut/hart/StallD
|
||||||
add wave /testbench/dut/hart/FlushD
|
#add wave /testbench/dut/hart/FlushD
|
||||||
add wave /testbench/dut/hart/FlushE
|
#add wave /testbench/dut/hart/FlushE
|
||||||
add wave /testbench/dut/hart/FlushM
|
#add wave /testbench/dut/hart/FlushM
|
||||||
add wave /testbench/dut/hart/FlushW
|
#add wave /testbench/dut/hart/FlushW
|
||||||
|
|
||||||
add wave -divider
|
add wave -divider
|
||||||
add wave -hex /testbench/dut/hart/ifu/PCF
|
add wave -hex /testbench/dut/hart/ifu/PCF
|
||||||
add wave -hex /testbench/dut/hart/ifu/InstrF
|
add wave -hex /testbench/dut/hart/ifu/InstrF
|
||||||
add wave /testbench/InstrFName
|
add wave /testbench/InstrFName
|
||||||
#add wave -hex /testbench/dut/hart/ifu/PCD
|
add wave -divider
|
||||||
|
add wave -hex /testbench/dut/hart/ifu/PCD
|
||||||
add wave -hex /testbench/dut/hart/ifu/InstrD
|
add wave -hex /testbench/dut/hart/ifu/InstrD
|
||||||
add wave /testbench/InstrDName
|
add wave /testbench/InstrDName
|
||||||
add wave -divider
|
add wave -divider
|
||||||
#add wave -hex /testbench/dut/hart/ifu/PCE
|
add wave -hex /testbench/dut/hart/ifu/PCE
|
||||||
#add wave -hex /testbench/dut/hart/ifu/InstrE
|
add wave -hex /testbench/dut/hart/ifu/InstrE
|
||||||
add wave /testbench/InstrEName
|
add wave /testbench/InstrEName
|
||||||
add wave -hex /testbench/dut/hart/ieu/dp/SrcAE
|
|
||||||
add wave -hex /testbench/dut/hart/ieu/dp/SrcBE
|
|
||||||
add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE
|
|
||||||
add wave /testbench/dut/hart/ieu/dp/PCSrcE
|
|
||||||
add wave -divider
|
add wave -divider
|
||||||
#add wave -hex /testbench/dut/hart/ifu/PCM
|
add wave -hex /testbench/dut/hart/ifu/PCM
|
||||||
#add wave -hex /testbench/dut/hart/ifu/InstrM
|
add wave -hex /testbench/dut/hart/ifu/InstrM
|
||||||
add wave /testbench/InstrMName
|
add wave /testbench/InstrMName
|
||||||
add wave /testbench/dut/uncore/dtim/memwrite
|
|
||||||
add wave -hex /testbench/dut/uncore/HADDR
|
|
||||||
add wave -hex /testbench/dut/uncore/HWDATA
|
|
||||||
add wave -divider
|
add wave -divider
|
||||||
add wave -hex /testbench/dut/hart/ifu/PCW
|
add wave -hex /testbench/dut/hart/ifu/PCW
|
||||||
|
add wave -hex /testbench/dut/hart/ifu/InstrW
|
||||||
add wave /testbench/InstrWName
|
add wave /testbench/InstrWName
|
||||||
add wave /testbench/dut/hart/ieu/dp/RegWriteW
|
#add wave -hex /testbench/dut/hart/ieu/dp/SrcAE
|
||||||
add wave -hex /testbench/dut/hart/ieu/dp/ResultW
|
#add wave -hex /testbench/dut/hart/ieu/dp/SrcBE
|
||||||
add wave -hex /testbench/dut/hart/ieu/dp/RdW
|
#add wave -hex /testbench/dut/hart/ieu/dp/ALUResultE
|
||||||
|
#add wave /testbench/dut/hart/ieu/dp/PCSrcE
|
||||||
add wave -divider
|
add wave -divider
|
||||||
#add ww
|
#add wave /testbench/dut/uncore/dtim/memwrite
|
||||||
add wave -hex -r /testbench/*
|
#add wave -hex /testbench/dut/uncore/HADDR
|
||||||
|
#add wave -hex /testbench/dut/uncore/HWDATA
|
||||||
|
#add wave -divider
|
||||||
|
#add wave -hex /testbench/dut/hart/ifu/PCW
|
||||||
|
#add wave /testbench/InstrWName
|
||||||
|
#add wave /testbench/dut/hart/ieu/dp/RegWriteW
|
||||||
|
#add wave -hex /testbench/dut/hart/ieu/dp/ResultW
|
||||||
|
#add wave -hex /testbench/dut/hart/ieu/dp/RdW
|
||||||
|
#add wave -hex -r /testbench/*
|
||||||
|
add wave -hex -r /testbench/dut/hart/ieu/dp/regf/*
|
||||||
|
add wave -divider
|
||||||
|
add wave -divider
|
||||||
|
add wave -hex -r /testbench/dut/hart/ebu/ReadDataW
|
||||||
|
|
||||||
-- Set Wave Output Items
|
-- Set Wave Output Items
|
||||||
TreeUpdate [SetDefaultTree]
|
TreeUpdate [SetDefaultTree]
|
||||||
@ -98,6 +106,6 @@ configure wave -childrowmargin 2
|
|||||||
set DefaultRadix hexadecimal
|
set DefaultRadix hexadecimal
|
||||||
|
|
||||||
-- Run the Simulation
|
-- Run the Simulation
|
||||||
#run 1000
|
run 3000
|
||||||
run -all
|
#run -all
|
||||||
#quit
|
#quit
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
module dmem (
|
module dmem (
|
||||||
input logic clk, reset,
|
input logic clk, reset,
|
||||||
input logic FlushW,
|
input logic StallW, FlushW,
|
||||||
//output logic DataStall,
|
//output logic DataStall,
|
||||||
// Memory Stage
|
// Memory Stage
|
||||||
input logic [1:0] MemRWM,
|
input logic [1:0] MemRWM,
|
||||||
@ -37,34 +37,53 @@ module dmem (
|
|||||||
input logic [2:0] Funct3M,
|
input logic [2:0] Funct3M,
|
||||||
//input logic [`XLEN-1:0] ReadDataW,
|
//input logic [`XLEN-1:0] ReadDataW,
|
||||||
input logic [`XLEN-1:0] WriteDataM,
|
input logic [`XLEN-1:0] WriteDataM,
|
||||||
|
input logic AtomicM,
|
||||||
output logic [`XLEN-1:0] MemPAdrM,
|
output logic [`XLEN-1:0] MemPAdrM,
|
||||||
output logic MemReadM, MemWriteM,
|
output logic MemReadM, MemWriteM,
|
||||||
output logic DataMisalignedM,
|
output logic DataMisalignedM,
|
||||||
// Writeback Stage
|
// Writeback Stage
|
||||||
input logic MemAckW,
|
input logic MemAckW,
|
||||||
input logic [`XLEN-1:0] ReadDataW,
|
input logic [`XLEN-1:0] ReadDataW,
|
||||||
|
output logic SquashSCW,
|
||||||
// faults
|
// faults
|
||||||
input logic DataAccessFaultM,
|
input logic DataAccessFaultM,
|
||||||
output logic LoadMisalignedFaultM, LoadAccessFaultM,
|
output logic LoadMisalignedFaultM, LoadAccessFaultM,
|
||||||
output logic StoreMisalignedFaultM, StoreAccessFaultM
|
output logic StoreMisalignedFaultM, StoreAccessFaultM,
|
||||||
|
// TLB management
|
||||||
|
//input logic [`XLEN-1:0] PageTableEntryM,
|
||||||
|
//input logic DTLBWriteM, DTLBFlushM,
|
||||||
|
// *** satp value will come from CSRs
|
||||||
|
// input logic [`XLEN-1:0] SATP,
|
||||||
|
output logic DTLBMissM, DTLBHitM
|
||||||
);
|
);
|
||||||
|
|
||||||
|
logic SquashSCM;
|
||||||
|
|
||||||
// Initially no MMU
|
// Initially no MMU
|
||||||
assign MemPAdrM = MemAdrM;
|
// *** temporary hack until we can figure out how to get actual satp value
|
||||||
|
// from priv unit -- Thomas F
|
||||||
|
logic [`XLEN-1:0] SATP = '0;
|
||||||
|
// *** temporary hack until walker is hooked up -- Thomas F
|
||||||
|
logic [`XLEN-1:0] PageTableEntryM = '0;
|
||||||
|
logic DTLBFlushM = '0;
|
||||||
|
logic DTLBWriteM = '0;
|
||||||
|
tlb #(3) dtlb(clk, reset, SATP, MemAdrM, PageTableEntryM, DTLBWriteM,
|
||||||
|
DTLBFlushM, MemPAdrM, DTLBMissM, DTLBHitM);
|
||||||
|
//assign MemPAdrM = MemAdrM;
|
||||||
|
|
||||||
// Determine if an Unaligned access is taking place
|
// Determine if an Unaligned access is taking place
|
||||||
always_comb
|
always_comb
|
||||||
case(Funct3M[1:0])
|
case(Funct3M[1:0])
|
||||||
2'b00: DataMisalignedM = 0; // lb, sb, lbu
|
2'b00: DataMisalignedM = 0; // lb, sb, lbu
|
||||||
2'b01: DataMisalignedM = MemAdrM[0]; // lh, sh, lhu
|
2'b01: DataMisalignedM = MemAdrM[0]; // lh, sh, lhu
|
||||||
2'b10: DataMisalignedM = MemAdrM[1] | MemAdrM[0]; // lw, sw, flw, fsw, lwu
|
2'b10: DataMisalignedM = MemAdrM[1] | MemAdrM[0]; // lw, sw, flw, fsw, lwu
|
||||||
2'b11: DataMisalignedM = |MemAdrM[2:0]; // ld, sd, fld, fsd
|
2'b11: DataMisalignedM = |MemAdrM[2:0]; // ld, sd, fld, fsd
|
||||||
endcase
|
endcase
|
||||||
|
|
||||||
// Squash unaligned data accesses
|
// Squash unaligned data accesses and failed store conditionals
|
||||||
// *** this is also the place to squash if the cache is hit
|
// *** this is also the place to squash if the cache is hit
|
||||||
assign MemReadM = MemRWM[1] & ~DataMisalignedM;
|
assign MemReadM = MemRWM[1] & ~DataMisalignedM;
|
||||||
assign MemWriteM = MemRWM[0] & ~DataMisalignedM;
|
assign MemWriteM = MemRWM[0] & ~DataMisalignedM && ~SquashSCM;
|
||||||
|
|
||||||
// Determine if address is valid
|
// Determine if address is valid
|
||||||
assign LoadMisalignedFaultM = DataMisalignedM & MemRWM[1];
|
assign LoadMisalignedFaultM = DataMisalignedM & MemRWM[1];
|
||||||
@ -72,6 +91,31 @@ module dmem (
|
|||||||
assign StoreMisalignedFaultM = DataMisalignedM & MemRWM[0];
|
assign StoreMisalignedFaultM = DataMisalignedM & MemRWM[0];
|
||||||
assign StoreAccessFaultM = DataAccessFaultM & MemRWM[0];
|
assign StoreAccessFaultM = DataAccessFaultM & MemRWM[0];
|
||||||
|
|
||||||
|
// Handle atomic load reserved / store conditional
|
||||||
|
generate
|
||||||
|
if (`A_SUPPORTED) begin // atomic instructions supported
|
||||||
|
logic [`XLEN-1:2] ReservationPAdrW;
|
||||||
|
logic ReservationValidM, ReservationValidW;
|
||||||
|
logic lrM, scM, WriteAdrMatchM;
|
||||||
|
|
||||||
|
assign lrM = MemReadM && AtomicM;
|
||||||
|
assign scM = MemRWM[0] && AtomicM;
|
||||||
|
assign WriteAdrMatchM = MemRWM[0] && (MemPAdrM == ReservationPAdrW) && ReservationValidW;
|
||||||
|
assign SquashSCM = scM && ~WriteAdrMatchM;
|
||||||
|
always_comb begin // ReservationValidM (next valiue of valid reservation)
|
||||||
|
if (lrM) ReservationValidM = 1; // set valid on load reserve
|
||||||
|
else if (scM || WriteAdrMatchM) ReservationValidM = 0; // clear valid on store to same address or any sc
|
||||||
|
else ReservationValidM = ReservationValidW; // otherwise don't change valid
|
||||||
|
end
|
||||||
|
flopenrc #(`XLEN-2) resadrreg(clk, reset, FlushW, ~StallW && lrM, MemPAdrM[`XLEN-1:2], ReservationPAdrW); // could drop clear on this one but not valid
|
||||||
|
flopenrc #(1) resvldreg(clk, reset, FlushW, ~StallW, ReservationValidM, ReservationValidW);
|
||||||
|
flopenrc #(1) squashreg(clk, reset, FlushW, ~StallW, SquashSCM, SquashSCW);
|
||||||
|
end else begin // Atomic operations not supported
|
||||||
|
assign SquashSCM = 0;
|
||||||
|
assign SquashSCW = 0;
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
// Data stall
|
// Data stall
|
||||||
//assign DataStall = 0;
|
//assign DataStall = 0;
|
||||||
|
|
||||||
|
@ -59,4 +59,12 @@ module mux5 #(parameter WIDTH = 8) (
|
|||||||
assign y = s[2] ? d4 : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0));
|
assign y = s[2] ? d4 : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0));
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module mux6 #(parameter WIDTH = 8) (
|
||||||
|
input logic [WIDTH-1:0] d0, d1, d2, d3, d4, d5,
|
||||||
|
input logic [2:0] s,
|
||||||
|
output logic [WIDTH-1:0] y);
|
||||||
|
|
||||||
|
assign y = s[2] ? (s[0] ? d5 : d4) : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0));
|
||||||
|
endmodule
|
||||||
|
|
||||||
/* verilator lint_on DECLFILENAME */
|
/* verilator lint_on DECLFILENAME */
|
||||||
|
@ -47,6 +47,7 @@ module controller(
|
|||||||
input logic StallM, FlushM,
|
input logic StallM, FlushM,
|
||||||
output logic [1:0] MemRWM,
|
output logic [1:0] MemRWM,
|
||||||
output logic CSRReadM, CSRWriteM, PrivilegedM,
|
output logic CSRReadM, CSRWriteM, PrivilegedM,
|
||||||
|
output logic AtomicM,
|
||||||
output logic [2:0] Funct3M,
|
output logic [2:0] Funct3M,
|
||||||
output logic RegWriteM, // for Hazard Unit
|
output logic RegWriteM, // for Hazard Unit
|
||||||
// Writeback stage control signals
|
// Writeback stage control signals
|
||||||
@ -75,10 +76,11 @@ module controller(
|
|||||||
logic TargetSrcD, W64D, MulDivD;
|
logic TargetSrcD, W64D, MulDivD;
|
||||||
logic CSRZeroSrcD;
|
logic CSRZeroSrcD;
|
||||||
logic CSRReadD;
|
logic CSRReadD;
|
||||||
|
logic AtomicD, AtomicE;
|
||||||
logic CSRWriteD, CSRWriteE;
|
logic CSRWriteD, CSRWriteE;
|
||||||
logic InstrValidE, InstrValidM;
|
logic InstrValidE, InstrValidM;
|
||||||
logic PrivilegedD, PrivilegedE;
|
logic PrivilegedD, PrivilegedE;
|
||||||
logic [20:0] ControlsD;
|
logic [21:0] ControlsD;
|
||||||
logic aluc3D;
|
logic aluc3D;
|
||||||
logic subD, sraD, sltD, sltuD;
|
logic subD, sraD, sltD, sltuD;
|
||||||
logic BranchTakenE;
|
logic BranchTakenE;
|
||||||
@ -97,38 +99,48 @@ module controller(
|
|||||||
generate
|
generate
|
||||||
always_comb
|
always_comb
|
||||||
case(OpD)
|
case(OpD)
|
||||||
// RegWrite_ImmSrc_ALUSrc_MemRW_ResultSrc_Branch_ALUOp_Jump_TargetSrc_W64_CSRRead_Privileged_MulDiv_Illegal
|
// *** Atomic p. 132 assembly encodings, defs 48
|
||||||
7'b0000011: ControlsD = 21'b1_000_01_10_001_0_00_0_0_0_0_0_0_0; // lw
|
// RegWrite_ImmSrc_ALUSrc_MemRW_ResultSrc_Branch_ALUOp_Jump_TargetSrc_W64_CSRRead_Privileged_MulDiv_Atomic_Illegal
|
||||||
7'b0100011: ControlsD = 21'b0_001_01_01_000_0_00_0_0_0_0_0_0_0; // sw
|
7'b0000000: ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // illegal instruction
|
||||||
7'b0110011: if (Funct7D == 7'b0000000 || Funct7D == 7'b0100000)
|
7'b0000011: ControlsD = 22'b1_000_01_10_001_0_00_0_0_0_0_0_0_0_0; // lw
|
||||||
ControlsD = 21'b1_000_00_00_000_0_10_0_0_0_0_0_0_0; // R-type
|
7'b0001111: ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_0; // fence = nop
|
||||||
else if (Funct7D == 7'b0000001 && `M_SUPPORTED)
|
7'b0010011: ControlsD = 22'b1_000_01_00_000_0_10_0_0_0_0_0_0_0_0; // I-type ALU
|
||||||
ControlsD = 21'b1_000_00_00_100_0_00_0_0_0_0_0_1_0; // Multiply/Divide
|
7'b0010111: ControlsD = 22'b1_100_11_00_000_0_00_0_0_0_0_0_0_0_0; // auipc
|
||||||
else
|
|
||||||
ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction
|
|
||||||
7'b0111011: if ((Funct7D == 7'b0000000 || Funct7D == 7'b0100000) && `XLEN == 64)
|
|
||||||
ControlsD = 21'b1_000_00_00_000_0_10_0_0_1_0_0_0_0; // R-type W instructions for RV64i
|
|
||||||
else if (Funct7D == 7'b0000001 && `M_SUPPORTED && `XLEN == 64)
|
|
||||||
ControlsD = 21'b1_000_00_00_100_0_00_0_0_1_0_0_1_0; // W-type Multiply/Divide
|
|
||||||
else
|
|
||||||
ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction
|
|
||||||
7'b1100011: ControlsD = 21'b0_010_00_00_000_1_01_0_0_0_0_0_0_0; // beq
|
|
||||||
7'b0010011: ControlsD = 21'b1_000_01_00_000_0_10_0_0_0_0_0_0_0; // I-type ALU
|
|
||||||
7'b0011011: if (`XLEN == 64)
|
7'b0011011: if (`XLEN == 64)
|
||||||
ControlsD = 21'b1_000_01_00_000_0_10_0_0_1_0_0_0_0; // IW-type ALU for RV64i
|
ControlsD = 22'b1_000_01_00_000_0_10_0_0_1_0_0_0_0_0; // IW-type ALU for RV64i
|
||||||
else
|
else
|
||||||
ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction
|
ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction
|
||||||
7'b1101111: ControlsD = 21'b1_011_00_00_010_0_00_1_0_0_0_0_0_0; // jal
|
7'b0100011: ControlsD = 22'b0_001_01_01_000_0_00_0_0_0_0_0_0_0_0; // sw
|
||||||
7'b1100111: ControlsD = 21'b1_000_00_00_010_0_00_1_1_0_0_0_0_0; // jalr
|
7'b0101111: if (`A_SUPPORTED) begin
|
||||||
7'b0010111: ControlsD = 21'b1_100_11_00_000_0_00_0_0_0_0_0_0_0; // auipc
|
if (InstrD[31:27] == 5'b00010)
|
||||||
7'b0110111: ControlsD = 21'b1_100_01_00_000_0_11_0_0_0_0_0_0_0; // lui
|
ControlsD = 22'b1_000_00_10_001_0_00_0_0_0_0_0_0_1_0; // lr
|
||||||
7'b0001111: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_0; // fence = nop
|
else if (InstrD[31:27] == 5'b00011)
|
||||||
|
ControlsD = 22'b1_101_01_01_110_0_00_0_0_0_0_0_0_1_0; // sc
|
||||||
|
else
|
||||||
|
ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_1_0; // other atomic; decode later
|
||||||
|
end else
|
||||||
|
ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction
|
||||||
|
7'b0110011: if (Funct7D == 7'b0000000 || Funct7D == 7'b0100000)
|
||||||
|
ControlsD = 22'b1_000_00_00_000_0_10_0_0_0_0_0_0_0_0; // R-type
|
||||||
|
else if (Funct7D == 7'b0000001 && `M_SUPPORTED)
|
||||||
|
ControlsD = 22'b1_000_00_00_100_0_00_0_0_0_0_0_1_0_0; // Multiply/Divide
|
||||||
|
else
|
||||||
|
ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction
|
||||||
|
7'b0110111: ControlsD = 22'b1_100_01_00_000_0_11_0_0_0_0_0_0_0_0; // lui
|
||||||
|
7'b0111011: if ((Funct7D == 7'b0000000 || Funct7D == 7'b0100000) && `XLEN == 64)
|
||||||
|
ControlsD = 22'b1_000_00_00_000_0_10_0_0_1_0_0_0_0_0; // R-type W instructions for RV64i
|
||||||
|
else if (Funct7D == 7'b0000001 && `M_SUPPORTED && `XLEN == 64)
|
||||||
|
ControlsD = 22'b1_000_00_00_100_0_00_0_0_1_0_0_1_0_0; // W-type Multiply/Divide
|
||||||
|
else
|
||||||
|
ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction
|
||||||
|
7'b1100011: ControlsD = 22'b0_010_00_00_000_1_01_0_0_0_0_0_0_0_0; // beq
|
||||||
|
7'b1100111: ControlsD = 22'b1_000_00_00_010_0_00_1_1_0_0_0_0_0_0; // jalr
|
||||||
|
7'b1101111: ControlsD = 22'b1_011_00_00_010_0_00_1_0_0_0_0_0_0_0; // jal
|
||||||
7'b1110011: if (Funct3D == 3'b000)
|
7'b1110011: if (Funct3D == 3'b000)
|
||||||
ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_1_0_0; // privileged; decoded further in priveleged modules
|
ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_1_0_0_0; // privileged; decoded further in priveleged modules
|
||||||
else
|
else
|
||||||
ControlsD = 21'b1_000_00_00_011_0_00_0_0_0_1_0_0_0; // csrs
|
ControlsD = 22'b1_000_00_00_011_0_00_0_0_0_1_0_0_0_0; // csrs
|
||||||
7'b0000000: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // illegal instruction
|
default: ControlsD = 22'b0_000_00_00_000_0_00_0_0_0_0_0_0_0_1; // non-implemented instruction
|
||||||
default: ControlsD = 21'b0_000_00_00_000_0_00_0_0_0_0_0_0_1; // non-implemented instruction
|
|
||||||
endcase
|
endcase
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
||||||
@ -137,7 +149,7 @@ module controller(
|
|||||||
assign IllegalBaseInstrFaultD = ControlsD[0];
|
assign IllegalBaseInstrFaultD = ControlsD[0];
|
||||||
assign {RegWriteD, ImmSrcD, ALUSrcAD, ALUSrcBD, MemRWD,
|
assign {RegWriteD, ImmSrcD, ALUSrcAD, ALUSrcBD, MemRWD,
|
||||||
ResultSrcD, BranchD, ALUOpD, JumpD, TargetSrcD, W64D, CSRReadD,
|
ResultSrcD, BranchD, ALUOpD, JumpD, TargetSrcD, W64D, CSRReadD,
|
||||||
PrivilegedD, MulDivD, unused} = ControlsD & ~IllegalIEUInstrFaultD;
|
PrivilegedD, MulDivD, AtomicD, unused} = ControlsD & ~IllegalIEUInstrFaultD;
|
||||||
// *** move Privileged, CSRwrite?? Or move controller out of IEU into datapath and handle all instructions
|
// *** move Privileged, CSRwrite?? Or move controller out of IEU into datapath and handle all instructions
|
||||||
|
|
||||||
assign CSRZeroSrcD = InstrD[14] ? (InstrD[19:15] == 0) : (Rs1D == 0); // Is a CSR instruction using zero as the source?
|
assign CSRZeroSrcD = InstrD[14] ? (InstrD[19:15] == 0) : (Rs1D == 0); // Is a CSR instruction using zero as the source?
|
||||||
@ -160,9 +172,9 @@ module controller(
|
|||||||
endcase
|
endcase
|
||||||
|
|
||||||
// Execute stage pipeline control register and logic
|
// Execute stage pipeline control register and logic
|
||||||
flopenrc #(25) controlregE(clk, reset, FlushE, ~StallE,
|
flopenrc #(26) controlregE(clk, reset, FlushE, ~StallE,
|
||||||
{RegWriteD, ResultSrcD, MemRWD, JumpD, BranchD, ALUControlD, ALUSrcAD, ALUSrcBD, TargetSrcD, CSRReadD, CSRWriteD, PrivilegedD, Funct3D, W64D, MulDivD, 1'b1},
|
{RegWriteD, ResultSrcD, MemRWD, JumpD, BranchD, ALUControlD, ALUSrcAD, ALUSrcBD, TargetSrcD, CSRReadD, CSRWriteD, PrivilegedD, Funct3D, W64D, MulDivD, AtomicD, 1'b1},
|
||||||
{RegWriteE, ResultSrcE, MemRWE, JumpE, BranchE, ALUControlE, ALUSrcAE, ALUSrcBE, TargetSrcE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, W64E, MulDivE, InstrValidE});
|
{RegWriteE, ResultSrcE, MemRWE, JumpE, BranchE, ALUControlE, ALUSrcAE, ALUSrcBE, TargetSrcE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, W64E, MulDivE, AtomicE, InstrValidE});
|
||||||
|
|
||||||
// Branch Logic
|
// Branch Logic
|
||||||
assign {zeroE, ltE, ltuE} = FlagsE;
|
assign {zeroE, ltE, ltuE} = FlagsE;
|
||||||
@ -183,9 +195,9 @@ module controller(
|
|||||||
assign MemReadE = MemRWE[1];
|
assign MemReadE = MemRWE[1];
|
||||||
|
|
||||||
// Memory stage pipeline control register
|
// Memory stage pipeline control register
|
||||||
flopenrc #(13) controlregM(clk, reset, FlushM, ~StallM,
|
flopenrc #(14) controlregM(clk, reset, FlushM, ~StallM,
|
||||||
{RegWriteE, ResultSrcE, MemRWE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, InstrValidE},
|
{RegWriteE, ResultSrcE, MemRWE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, AtomicE, InstrValidE},
|
||||||
{RegWriteM, ResultSrcM, MemRWM, CSRReadM, CSRWriteM, PrivilegedM, Funct3M, InstrValidM});
|
{RegWriteM, ResultSrcM, MemRWM, CSRReadM, CSRWriteM, PrivilegedM, Funct3M, AtomicM, InstrValidM});
|
||||||
|
|
||||||
// Writeback stage pipeline control register
|
// Writeback stage pipeline control register
|
||||||
flopenrc #(5) controlregW(clk, reset, FlushW, ~StallW,
|
flopenrc #(5) controlregW(clk, reset, FlushW, ~StallW,
|
||||||
|
@ -47,9 +47,10 @@ module datapath (
|
|||||||
// Writeback stage signals
|
// Writeback stage signals
|
||||||
input logic StallW, FlushW,
|
input logic StallW, FlushW,
|
||||||
input logic RegWriteW,
|
input logic RegWriteW,
|
||||||
|
input logic SquashSCW,
|
||||||
input logic [2:0] ResultSrcW,
|
input logic [2:0] ResultSrcW,
|
||||||
input logic [`XLEN-1:0] PCLinkW,
|
input logic [`XLEN-1:0] PCLinkW,
|
||||||
input logic [`XLEN-1:0] CSRReadValW, ReadDataW, MulDivResultW,
|
input logic [`XLEN-1:0] CSRReadValW, ReadDataW, MulDivResultW,
|
||||||
// Hazard Unit signals
|
// Hazard Unit signals
|
||||||
output logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E,
|
output logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E,
|
||||||
output logic [4:0] RdE, RdM, RdW
|
output logic [4:0] RdE, RdM, RdW
|
||||||
@ -70,6 +71,7 @@ module datapath (
|
|||||||
// Memory stage signals
|
// Memory stage signals
|
||||||
logic [`XLEN-1:0] ALUResultM;
|
logic [`XLEN-1:0] ALUResultM;
|
||||||
// Writeback stage signals
|
// Writeback stage signals
|
||||||
|
logic [`XLEN-1:0] SCResultW;
|
||||||
logic [`XLEN-1:0] ALUResultW;
|
logic [`XLEN-1:0] ALUResultW;
|
||||||
logic [`XLEN-1:0] ResultW;
|
logic [`XLEN-1:0] ResultW;
|
||||||
|
|
||||||
@ -107,5 +109,13 @@ module datapath (
|
|||||||
flopenrc #(`XLEN) ALUResultWReg(clk, reset, FlushW, ~StallW, ALUResultM, ALUResultW);
|
flopenrc #(`XLEN) ALUResultWReg(clk, reset, FlushW, ~StallW, ALUResultM, ALUResultW);
|
||||||
flopenrc #(5) RdWEg(clk, reset, FlushW, ~StallW, RdM, RdW);
|
flopenrc #(5) RdWEg(clk, reset, FlushW, ~StallW, RdM, RdW);
|
||||||
|
|
||||||
mux5 #(`XLEN) resultmux(ALUResultW, ReadDataW, PCLinkW, CSRReadValW, MulDivResultW, ResultSrcW, ResultW);
|
// handle Store Conditional result if atomic extension supported
|
||||||
|
generate
|
||||||
|
if (`A_SUPPORTED)
|
||||||
|
assign SCResultW = SquashSCW ? {{(`XLEN-1){1'b0}}, 1'b1} : {{(`XLEN-1){1'b0}}, 1'b0};
|
||||||
|
else
|
||||||
|
assign SCResultW = 0;
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
mux6 #(`XLEN) resultmux(ALUResultW, ReadDataW, PCLinkW, CSRReadValW, MulDivResultW, SCResultW, ResultSrcW, ResultW);
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -29,19 +29,26 @@ module extend (
|
|||||||
input logic [31:7] InstrD,
|
input logic [31:7] InstrD,
|
||||||
input logic [2:0] ImmSrcD,
|
input logic [2:0] ImmSrcD,
|
||||||
output logic [`XLEN-1:0 ] ExtImmD);
|
output logic [`XLEN-1:0 ] ExtImmD);
|
||||||
|
|
||||||
|
logic [`XLEN-1:0] undefined = {(`XLEN){1'bx}}; // could change to 0 after debug
|
||||||
|
|
||||||
always_comb
|
generate
|
||||||
case(ImmSrcD)
|
always_comb
|
||||||
// I-type
|
case(ImmSrcD)
|
||||||
3'b000: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:20]};
|
// I-type
|
||||||
// S-type (stores)
|
3'b000: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:20]};
|
||||||
3'b001: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:25], InstrD[11:7]};
|
// S-type (stores)
|
||||||
// B-type (branches)
|
3'b001: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[31:25], InstrD[11:7]};
|
||||||
3'b010: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[7], InstrD[30:25], InstrD[11:8], 1'b0};
|
// B-type (branches)
|
||||||
// J-type (jal)
|
3'b010: ExtImmD = {{(`XLEN-12){InstrD[31]}}, InstrD[7], InstrD[30:25], InstrD[11:8], 1'b0};
|
||||||
3'b011: ExtImmD = {{(`XLEN-20){InstrD[31]}}, InstrD[19:12], InstrD[20], InstrD[30:21], 1'b0};
|
// J-type (jal)
|
||||||
// U-type (lui, auipc)
|
3'b011: ExtImmD = {{(`XLEN-20){InstrD[31]}}, InstrD[19:12], InstrD[20], InstrD[30:21], 1'b0};
|
||||||
3'b100: ExtImmD = {{(`XLEN-31){InstrD[31]}}, InstrD[30:12], 12'b0};
|
// U-type (lui, auipc)
|
||||||
default: ExtImmD = {(`XLEN-1){1'bx}}; // undefined
|
3'b100: ExtImmD = {{(`XLEN-31){InstrD[31]}}, InstrD[30:12], 12'b0};
|
||||||
endcase
|
// Store Conditional: zero offset
|
||||||
|
3'b101: if (`A_SUPPORTED) ExtImmD = 0;
|
||||||
|
else ExtImmD = undefined;
|
||||||
|
default: ExtImmD = undefined; // undefined
|
||||||
|
endcase
|
||||||
|
endgenerate
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -40,7 +40,9 @@ module ieu (
|
|||||||
// Memory stage interface
|
// Memory stage interface
|
||||||
input logic DataMisalignedM,
|
input logic DataMisalignedM,
|
||||||
input logic DataAccessFaultM,
|
input logic DataAccessFaultM,
|
||||||
|
input logic SquashSCW,
|
||||||
output logic [1:0] MemRWM,
|
output logic [1:0] MemRWM,
|
||||||
|
output logic AtomicM,
|
||||||
output logic [`XLEN-1:0] MemAdrM, WriteDataM,
|
output logic [`XLEN-1:0] MemAdrM, WriteDataM,
|
||||||
output logic [`XLEN-1:0] SrcAM,
|
output logic [`XLEN-1:0] SrcAM,
|
||||||
output logic [2:0] Funct3M,
|
output logic [2:0] Funct3M,
|
||||||
|
@ -52,6 +52,12 @@ module ifu (
|
|||||||
output logic IllegalIEUInstrFaultD,
|
output logic IllegalIEUInstrFaultD,
|
||||||
output logic InstrMisalignedFaultM,
|
output logic InstrMisalignedFaultM,
|
||||||
output logic [`XLEN-1:0] InstrMisalignedAdrM,
|
output logic [`XLEN-1:0] InstrMisalignedAdrM,
|
||||||
|
// TLB management
|
||||||
|
//input logic [`XLEN-1:0] PageTableEntryF,
|
||||||
|
//input logic ITLBWriteF, ITLBFlushF,
|
||||||
|
// *** satp value will come from CSRs
|
||||||
|
// input logic [`XLEN-1:0] SATP,
|
||||||
|
output logic ITLBMissF, ITLBHitF,
|
||||||
// bogus
|
// bogus
|
||||||
input logic [15:0] rd2
|
input logic [15:0] rd2
|
||||||
);
|
);
|
||||||
@ -65,8 +71,18 @@ module ifu (
|
|||||||
logic [31:0] InstrF, InstrRawD, InstrE, InstrW;
|
logic [31:0] InstrF, InstrRawD, InstrE, InstrW;
|
||||||
logic [31:0] nop = 32'h00000013; // instruction for NOP
|
logic [31:0] nop = 32'h00000013; // instruction for NOP
|
||||||
|
|
||||||
|
// *** temporary hack until we can figure out how to get actual satp value
|
||||||
|
// from priv unit -- Thomas F
|
||||||
|
logic [`XLEN-1:0] SATP = '0;
|
||||||
|
// *** temporary hack until walker is hooked up -- Thomas F
|
||||||
|
logic [`XLEN-1:0] PageTableEntryF = '0;
|
||||||
|
logic ITLBFlushF = '0;
|
||||||
|
logic ITLBWriteF = '0;
|
||||||
|
tlb #(3) itlb(clk, reset, SATP, PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF,
|
||||||
|
InstrPAdrF, ITLBMissF, ITLBHitF);
|
||||||
|
|
||||||
// *** put memory interface on here, InstrF becomes output
|
// *** put memory interface on here, InstrF becomes output
|
||||||
assign InstrPAdrF = PCF; // *** no MMU
|
//assign InstrPAdrF = PCF; // *** no MMU
|
||||||
//assign InstrReadF = ~StallD; // *** & ICacheMissF; add later
|
//assign InstrReadF = ~StallD; // *** & ICacheMissF; add later
|
||||||
assign InstrReadF = 1; // *** & ICacheMissF; add later
|
assign InstrReadF = 1; // *** & ICacheMissF; add later
|
||||||
|
|
||||||
|
234
wally-pipelined/src/mmu/tlb.sv
Normal file
234
wally-pipelined/src/mmu/tlb.sv
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
///////////////////////////////////////////
|
||||||
|
// tlb_toy.sv
|
||||||
|
//
|
||||||
|
// Written: jtorrey@hmc.edu 16 February 2021
|
||||||
|
// Modified:
|
||||||
|
//
|
||||||
|
// Purpose: Example translation lookaside buffer
|
||||||
|
// Cache of virtural-to-physical address translations
|
||||||
|
//
|
||||||
|
// 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"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sv32 specs
|
||||||
|
* ----------
|
||||||
|
* Virtual address [31:0] (32 bits)
|
||||||
|
* [________________________________]
|
||||||
|
* |--VPN1--||--VPN0--||----OFF---|
|
||||||
|
* 10 10 12
|
||||||
|
*
|
||||||
|
* Physical address [33:0] (34 bits)
|
||||||
|
* [__________________________________]
|
||||||
|
* |---PPN1---||--PPN0--||----OFF---|
|
||||||
|
* 12 10 12
|
||||||
|
*
|
||||||
|
* Page Table Entry [31:0] (32 bits)
|
||||||
|
* [________________________________]
|
||||||
|
* |---PPN1---||--PPN0--|||DAGUXWRV
|
||||||
|
* 12 10 ^^
|
||||||
|
* RSW(2) -- for OS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* *** TODO:
|
||||||
|
* - add LRU algorithm (select the write index based on which entry was used
|
||||||
|
* least recently)
|
||||||
|
* - refactor modules into multiple files
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The TLB will have 2**ENTRY_BITS total entries
|
||||||
|
module tlb #(parameter ENTRY_BITS = 3) (
|
||||||
|
input clk, reset,
|
||||||
|
|
||||||
|
// Current value of satp CSR (from privileged unit)
|
||||||
|
input [`XLEN-1:0] SATP, // *** How do we get this?
|
||||||
|
|
||||||
|
// Virtual address input
|
||||||
|
input [`XLEN-1:0] VirtualAddress,
|
||||||
|
|
||||||
|
// Controls for writing a new entry to the TLB
|
||||||
|
input [`XLEN-1:0] PageTableEntryWrite,
|
||||||
|
input TLBWrite,
|
||||||
|
|
||||||
|
// Invalidate all TLB entries
|
||||||
|
input TLBFlush,
|
||||||
|
|
||||||
|
// Physical address outputs
|
||||||
|
output [`XLEN-1:0] PhysicalAddress,
|
||||||
|
output TLBMiss,
|
||||||
|
output TLBHit
|
||||||
|
);
|
||||||
|
|
||||||
|
generate
|
||||||
|
if (`XLEN == 32) begin: ARCH
|
||||||
|
localparam VPN_BITS = 20;
|
||||||
|
localparam PPN_BITS = 22;
|
||||||
|
localparam PA_BITS = 34;
|
||||||
|
|
||||||
|
logic SvMode;
|
||||||
|
assign SvMode = SATP[31]; // *** change to an enum somehow?
|
||||||
|
end else begin: ARCH
|
||||||
|
localparam VPN_BITS = 27;
|
||||||
|
localparam PPN_BITS = 44;
|
||||||
|
localparam PA_BITS = 56;
|
||||||
|
|
||||||
|
logic SvMode; // currently just a boolean whether translation enabled
|
||||||
|
assign SvMode = SATP[63]; // *** change to an enum somehow?
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
// Index (currently random) to write the next TLB entry
|
||||||
|
logic [ENTRY_BITS-1:0] WriteIndex;
|
||||||
|
|
||||||
|
// Sections of the virtual and physical addresses
|
||||||
|
logic [ARCH.VPN_BITS-1:0] VirtualPageNumber;
|
||||||
|
logic [ARCH.PPN_BITS-1:0] PhysicalPageNumber;
|
||||||
|
logic [11:0] PageOffset;
|
||||||
|
logic [ARCH.PA_BITS-1:0] PhysicalAddressFull;
|
||||||
|
|
||||||
|
// Pattern and pattern location in the CAM
|
||||||
|
logic [ENTRY_BITS-1:0] VPNIndex;
|
||||||
|
|
||||||
|
// RAM access location
|
||||||
|
logic [ENTRY_BITS-1:0] EntryIndex;
|
||||||
|
|
||||||
|
// Page table entry matching the virtual address
|
||||||
|
logic [`XLEN-1:0] PageTableEntry;
|
||||||
|
|
||||||
|
assign VirtualPageNumber = VirtualAddress[ARCH.VPN_BITS+11:12];
|
||||||
|
assign PageOffset = VirtualAddress[11:0];
|
||||||
|
|
||||||
|
// Choose a read or write location to the entry list
|
||||||
|
mux2 #(3) indexmux(VPNIndex, WriteIndex, TLBWrite, EntryIndex);
|
||||||
|
|
||||||
|
// Currently use random replacement algorithm
|
||||||
|
tlb_rand rdm(.*);
|
||||||
|
|
||||||
|
tlb_ram #(ENTRY_BITS) ram(.*);
|
||||||
|
tlb_cam #(ENTRY_BITS, ARCH.VPN_BITS) cam(.*);
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
assign PhysicalPageNumber = PageTableEntry[ARCH.PPN_BITS+9:10];
|
||||||
|
|
||||||
|
if (TLBHit) begin
|
||||||
|
assign PhysicalAddressFull = {PhysicalPageNumber, PageOffset};
|
||||||
|
end else begin
|
||||||
|
assign PhysicalAddressFull = 8'b0; // *** Actual behavior; disabled until walker functioning
|
||||||
|
//assign PhysicalAddressFull = {2'b0, VirtualPageNumber, PageOffset} // *** pass through should be removed as soon as walker ready
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
generate
|
||||||
|
if (`XLEN == 32) begin
|
||||||
|
mux2 #(`XLEN) addressmux(VirtualAddress, PhysicalAddressFull[31:0], ARCH.SvMode, PhysicalAddress);
|
||||||
|
end else begin
|
||||||
|
mux2 #(`XLEN) addressmux(VirtualAddress, {8'b0, PhysicalAddressFull}, ARCH.SvMode, PhysicalAddress);
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
assign TLBMiss = ~TLBHit & ~(TLBWrite | TLBFlush) & ARCH.SvMode;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module tlb_ram #(parameter ENTRY_BITS = 3) (
|
||||||
|
input clk, reset,
|
||||||
|
input [ENTRY_BITS-1:0] EntryIndex,
|
||||||
|
input [`XLEN-1:0] PageTableEntryWrite,
|
||||||
|
input TLBWrite,
|
||||||
|
|
||||||
|
output [`XLEN-1:0] PageTableEntry
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam NENTRIES = 2**ENTRY_BITS;
|
||||||
|
|
||||||
|
logic [`XLEN-1:0] ram [0:NENTRIES-1];
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (TLBWrite) ram[EntryIndex] <= PageTableEntryWrite;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign PageTableEntry = ram[EntryIndex];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
for (int i = 0; i < NENTRIES; i++)
|
||||||
|
ram[i] = `XLEN'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module tlb_cam #(parameter ENTRY_BITS = 3,
|
||||||
|
parameter KEY_BITS = 20) (
|
||||||
|
input clk, reset,
|
||||||
|
input [KEY_BITS-1:0] VirtualPageNumber,
|
||||||
|
input [ENTRY_BITS-1:0] WriteIndex,
|
||||||
|
input TLBWrite,
|
||||||
|
input TLBFlush,
|
||||||
|
output [ENTRY_BITS-1:0] VPNIndex,
|
||||||
|
output TLBHit
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam NENTRIES = 2**ENTRY_BITS;
|
||||||
|
|
||||||
|
// Each entry of this memory has KEY_BITS for the key plus one valid bit.
|
||||||
|
logic [KEY_BITS:0] ram [0:NENTRIES-1];
|
||||||
|
|
||||||
|
logic [ENTRY_BITS-1:0] matched_address_comb;
|
||||||
|
logic match_found_comb;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (TLBWrite) ram[WriteIndex] <= {1'b1,VirtualPageNumber};
|
||||||
|
if (TLBFlush) begin
|
||||||
|
for (int i = 0; i < NENTRIES; i++)
|
||||||
|
ram[i][KEY_BITS] = 1'b0; // Zero out msb (valid bit) of all entries
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// *** Check whether this for loop synthesizes correctly
|
||||||
|
always_comb begin
|
||||||
|
match_found_comb = 1'b0;
|
||||||
|
matched_address_comb = '0;
|
||||||
|
for (int i = 0; i < NENTRIES; i++) begin
|
||||||
|
if (ram[i] == {1'b1,VirtualPageNumber} && !match_found_comb) begin
|
||||||
|
matched_address_comb = i;
|
||||||
|
match_found_comb = 1;
|
||||||
|
end else begin
|
||||||
|
matched_address_comb = matched_address_comb;
|
||||||
|
match_found_comb = match_found_comb;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign VPNIndex = matched_address_comb;
|
||||||
|
assign TLBHit = match_found_comb & ~(TLBWrite | TLBFlush);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
for (int i = 0; i < NENTRIES; i++)
|
||||||
|
ram[i] <= '0;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module tlb_rand #(parameter ENTRY_BITS = 3) (
|
||||||
|
input clk, reset,
|
||||||
|
output [ENTRY_BITS-1:0] WriteIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
logic [31:0] data;
|
||||||
|
assign data = $urandom;
|
||||||
|
assign WriteIndex = data[ENTRY_BITS:0];
|
||||||
|
|
||||||
|
endmodule
|
@ -1,20 +1,25 @@
|
|||||||
module testbench();
|
`include "wally-config.vh"
|
||||||
|
|
||||||
|
module tlb_testbench();
|
||||||
logic clk, reset;
|
logic clk, reset;
|
||||||
|
|
||||||
// DUT inputs
|
// DUT inputs
|
||||||
logic [31:0] PCF;
|
logic [`XLEN-1:0] SATP;
|
||||||
logic [31:0] PageTableEntryF;
|
logic [`XLEN-1:0] VirtualAddress;
|
||||||
logic ITLBWriteF, ITLBFlushF;
|
logic [`XLEN-1:0] PageTableEntryWrite;
|
||||||
|
logic TLBWrite, TLBFlush;
|
||||||
|
|
||||||
// DUT outputs
|
// DUT outputs
|
||||||
logic [31:0] PCPF;
|
logic [`XLEN-1:0] PhysicalAddress;
|
||||||
logic ITLBMissF, ITLBHitF;
|
logic TLBMiss, TLBHit;
|
||||||
|
|
||||||
// Testbench signals
|
// Testbench signals
|
||||||
logic [33:0] expected;
|
logic [33:0] expected;
|
||||||
logic [31:0] vectornum, errors;
|
logic [31:0] vectornum, errors;
|
||||||
logic [99:0] testvectors[10000:0];
|
logic [99:0] testvectors[10000:0];
|
||||||
|
|
||||||
|
assign SATP = {1'b1, 31'b0};
|
||||||
|
|
||||||
// instantiate device under test
|
// instantiate device under test
|
||||||
tlb_toy dut(.*);
|
tlb_toy dut(.*);
|
||||||
|
|
||||||
@ -31,17 +36,17 @@ module testbench();
|
|||||||
|
|
||||||
// apply test vectors on rising edge of clk
|
// apply test vectors on rising edge of clk
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
#1; {PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF, expected} = testvectors[vectornum];
|
#1; {VirtualAddress, PageTableEntryWrite, TLBWrite, TLBFlush, expected} = testvectors[vectornum];
|
||||||
end
|
end
|
||||||
|
|
||||||
// check results on falling edge of clk
|
// check results on falling edge of clk
|
||||||
always @(negedge clk)
|
always @(negedge clk)
|
||||||
if (~reset) begin // skip during reset
|
if (~reset) begin // skip during reset
|
||||||
if ({PCPF, ITLBMissF, ITLBHitF} !== expected) begin // check result
|
if ({PhysicalAddress, TLBMiss, TLBHit} !== expected) begin // check result
|
||||||
$display("Error: PCF = %b, write = %b, data = %b, flush = %b", PCF,
|
$display("Error: VirtualAddress = %b, write = %b, data = %b, flush = %b", VirtualAddress,
|
||||||
ITLBWriteF, PageTableEntryF, ITLBFlushF);
|
TLBWrite, PageTableEntryWrite, TLBFlush);
|
||||||
$display(" outputs = %b %b %b (%b expected)",
|
$display(" outputs = %b %b %b (%b expected)",
|
||||||
PCPF, ITLBMissF, ITLBHitF, expected);
|
PhysicalAddress, TLBMiss, TLBHit, expected);
|
||||||
errors = errors + 1;
|
errors = errors + 1;
|
||||||
end
|
end
|
||||||
vectornum = vectornum + 1;
|
vectornum = vectornum + 1;
|
||||||
|
@ -1,208 +0,0 @@
|
|||||||
///////////////////////////////////////////
|
|
||||||
// tlb_toy.sv
|
|
||||||
//
|
|
||||||
// Written: jtorrey@hmc.edu 16 February 2021
|
|
||||||
// Modified:
|
|
||||||
//
|
|
||||||
// Purpose: Example translation lookaside buffer
|
|
||||||
// Cache of virtural-to-physical address translations
|
|
||||||
//
|
|
||||||
// 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"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sv32 specs
|
|
||||||
* ----------
|
|
||||||
* Virtual address [31:0] (32 bits)
|
|
||||||
* [________________________________]
|
|
||||||
* |--VPN1--||--VPN0--||----OFF---|
|
|
||||||
* 10 10 12
|
|
||||||
*
|
|
||||||
* Physical address [33:0] (34 bits)
|
|
||||||
* [__________________________________]
|
|
||||||
* |---PPN1---||--PPN0--||----OFF---|
|
|
||||||
* 12 10 12
|
|
||||||
*
|
|
||||||
* Page Table Entry [31:0] (32 bits)
|
|
||||||
* [________________________________]
|
|
||||||
* |---PPN1---||--PPN0--|||DAGUXWRV
|
|
||||||
* 12 10 ^^
|
|
||||||
* RSW(2) -- for OS
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* *** TODO:
|
|
||||||
* - add LRU algorithm (select the write index based on which entry was used
|
|
||||||
* least recently)
|
|
||||||
* - rename signals to use .* notation in CAM and RAM
|
|
||||||
*/
|
|
||||||
|
|
||||||
module tlb_toy (
|
|
||||||
input clk, reset,
|
|
||||||
|
|
||||||
// Virtual address input
|
|
||||||
input [31:0] PCF,
|
|
||||||
|
|
||||||
// Controls for writing a new entry to the TLB
|
|
||||||
input [31:0] PageTableEntryF,
|
|
||||||
input ITLBWriteF,
|
|
||||||
|
|
||||||
// Invalidate all TLB entries
|
|
||||||
input ITLBFlushF,
|
|
||||||
|
|
||||||
// Physical address outputs
|
|
||||||
output [31:0] PCPF,
|
|
||||||
output ITLBMissF,
|
|
||||||
output ITLBHitF
|
|
||||||
);
|
|
||||||
// Index (currently random) to write the next TLB entry
|
|
||||||
logic [2:0] WriteIndexF;
|
|
||||||
|
|
||||||
// Sections of the virtual and physical addresses
|
|
||||||
logic [19:0] VirtualPageNumberF;
|
|
||||||
logic [21:0] PhysicalPageNumberF;
|
|
||||||
logic [11:0] PageOffsetF;
|
|
||||||
logic [33:0] PhysicalAddressF;
|
|
||||||
|
|
||||||
// Pattern and pattern location in the CAM
|
|
||||||
logic [2:0] VPNIndexF;
|
|
||||||
|
|
||||||
// RAM access location
|
|
||||||
logic [2:0] ITLBEntryIndex;
|
|
||||||
|
|
||||||
// Page table entry matching the virtual address
|
|
||||||
logic [31:0] PTEMatchF;
|
|
||||||
|
|
||||||
assign VirtualPageNumberF = PCF[31:12];
|
|
||||||
assign PageOffsetF = PCF[11:0];
|
|
||||||
|
|
||||||
// Choose a read or write location to the entry list
|
|
||||||
mux2 #(3) indexmux(VPNIndexF, WriteIndexF, ITLBWriteF, ITLBEntryIndex);
|
|
||||||
|
|
||||||
// Currently use random replacement algorithm
|
|
||||||
rand3 rdm(clk, reset, WriteIndexF);
|
|
||||||
|
|
||||||
ram8x32 ram(clk, reset, ITLBEntryIndex, PageTableEntryF, ITLBWriteF, PTEMatchF);
|
|
||||||
cam8x21 cam(clk, reset, ITLBWriteF, VirtualPageNumberF, WriteIndexF,
|
|
||||||
ITLBFlushF, VPNIndexF, ITLBHitF);
|
|
||||||
|
|
||||||
always_comb begin
|
|
||||||
assign PhysicalPageNumberF = PTEMatchF[31:10];
|
|
||||||
|
|
||||||
if (ITLBHitF) begin
|
|
||||||
assign PhysicalAddressF = {PhysicalPageNumberF, PageOffsetF};
|
|
||||||
end else begin
|
|
||||||
assign PhysicalAddressF = 34'b0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assign PCPF = PhysicalAddressF[31:0];
|
|
||||||
assign ITLBMissF = ~ITLBHitF & ~(ITLBWriteF | ITLBFlushF);
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
// *** Add parameter for number of tlb lines (currently 8)
|
|
||||||
module ram8x32 (
|
|
||||||
input clk, reset,
|
|
||||||
input [2:0] address,
|
|
||||||
input [31:0] data,
|
|
||||||
input we,
|
|
||||||
|
|
||||||
output [31:0] out_data
|
|
||||||
);
|
|
||||||
|
|
||||||
logic [31:0] ram [0:7];
|
|
||||||
always @(posedge clk) begin
|
|
||||||
if (we) ram[address] <= data;
|
|
||||||
end
|
|
||||||
|
|
||||||
assign out_data = ram[address];
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
ram[i] = 32'h0;
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module cam8x21 (
|
|
||||||
input clk, reset, we,
|
|
||||||
input [19:0] pattern,
|
|
||||||
input [2:0] write_address,
|
|
||||||
input ITLBFlushF,
|
|
||||||
output [2:0] matched_address,
|
|
||||||
output match_found
|
|
||||||
);
|
|
||||||
|
|
||||||
logic [20:0] ram [0:7];
|
|
||||||
logic [7:0] match_line;
|
|
||||||
|
|
||||||
logic [2:0] matched_address_comb;
|
|
||||||
logic match_found_comb;
|
|
||||||
|
|
||||||
always @(posedge clk) begin
|
|
||||||
if (we) ram[write_address] <= {1'b1,pattern};
|
|
||||||
if (ITLBFlushF) begin
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
ram[i][20] = 1'b0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
// *** Check whether this for loop synthesizes correctly
|
|
||||||
always_comb begin
|
|
||||||
match_found_comb = 1'b0;
|
|
||||||
matched_address_comb = 3'b0;
|
|
||||||
for (int i = 0; i < 8; i++) begin
|
|
||||||
if (ram[i] == {1'b1,pattern} && !match_found_comb) begin
|
|
||||||
matched_address_comb = i;
|
|
||||||
match_found_comb = 1;
|
|
||||||
end else begin
|
|
||||||
matched_address_comb = matched_address_comb;
|
|
||||||
match_found_comb = match_found_comb;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assign matched_address = matched_address_comb;
|
|
||||||
assign match_found = match_found_comb & ~(we | ITLBFlushF);
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
ram[i] <= 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module mux2 #(parameter WIDTH = 8) (
|
|
||||||
input logic [WIDTH-1:0] d0, d1,
|
|
||||||
input logic s,
|
|
||||||
output logic [WIDTH-1:0] y);
|
|
||||||
|
|
||||||
assign y = s ? d1 : d0;
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
module rand3 (
|
|
||||||
input clk, reset,
|
|
||||||
output [2:0] WriteIndexF
|
|
||||||
);
|
|
||||||
|
|
||||||
logic [31:0] data;
|
|
||||||
assign data = $urandom;
|
|
||||||
assign WriteIndexF = data[2:0];
|
|
||||||
|
|
||||||
endmodule
|
|
233
wally-pipelined/src/tlb_toy/tlb_toy.sv.OLD
Normal file
233
wally-pipelined/src/tlb_toy/tlb_toy.sv.OLD
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
///////////////////////////////////////////
|
||||||
|
// tlb_toy.sv
|
||||||
|
//
|
||||||
|
// Written: jtorrey@hmc.edu 16 February 2021
|
||||||
|
// Modified:
|
||||||
|
//
|
||||||
|
// Purpose: Example translation lookaside buffer
|
||||||
|
// Cache of virtural-to-physical address translations
|
||||||
|
//
|
||||||
|
// 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"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sv32 specs
|
||||||
|
* ----------
|
||||||
|
* Virtual address [31:0] (32 bits)
|
||||||
|
* [________________________________]
|
||||||
|
* |--VPN1--||--VPN0--||----OFF---|
|
||||||
|
* 10 10 12
|
||||||
|
*
|
||||||
|
* Physical address [33:0] (34 bits)
|
||||||
|
* [__________________________________]
|
||||||
|
* |---PPN1---||--PPN0--||----OFF---|
|
||||||
|
* 12 10 12
|
||||||
|
*
|
||||||
|
* Page Table Entry [31:0] (32 bits)
|
||||||
|
* [________________________________]
|
||||||
|
* |---PPN1---||--PPN0--|||DAGUXWRV
|
||||||
|
* 12 10 ^^
|
||||||
|
* RSW(2) -- for OS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* *** TODO:
|
||||||
|
* - add LRU algorithm (select the write index based on which entry was used
|
||||||
|
* least recently)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The TLB will have 2**ENTRY_BITS total entries
|
||||||
|
module tlb_toy #(parameter ENTRY_BITS = 3) (
|
||||||
|
input clk, reset,
|
||||||
|
|
||||||
|
// Current value of satp CSR (from privileged unit)
|
||||||
|
input [`XLEN-1:0] SATP, // *** How do we get this?
|
||||||
|
|
||||||
|
// Virtual address input
|
||||||
|
input [`XLEN-1:0] VirtualAddress,
|
||||||
|
|
||||||
|
// Controls for writing a new entry to the TLB
|
||||||
|
input [`XLEN-1:0] PageTableEntryWrite,
|
||||||
|
input TLBWrite,
|
||||||
|
|
||||||
|
// Invalidate all TLB entries
|
||||||
|
input TLBFlush,
|
||||||
|
|
||||||
|
// Physical address outputs
|
||||||
|
output [`XLEN-1:0] PhysicalAddress,
|
||||||
|
output TLBMiss,
|
||||||
|
output TLBHit
|
||||||
|
);
|
||||||
|
|
||||||
|
generate
|
||||||
|
if (`XLEN == 32) begin: ARCH
|
||||||
|
localparam VPN_BITS = 20;
|
||||||
|
localparam PPN_BITS = 22;
|
||||||
|
localparam PA_BITS = 34;
|
||||||
|
|
||||||
|
logic SvMode;
|
||||||
|
assign SvMode = SATP[31]; // *** change to an enum somehow?
|
||||||
|
end else begin: ARCH
|
||||||
|
localparam VPN_BITS = 27;
|
||||||
|
localparam PPN_BITS = 44;
|
||||||
|
localparam PA_BITS = 56;
|
||||||
|
|
||||||
|
logic SvMode; // currently just a boolean whether translation enabled
|
||||||
|
assign SvMode = SATP[63]; // *** change to an enum somehow?
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
// Index (currently random) to write the next TLB entry
|
||||||
|
logic [ENTRY_BITS-1:0] WriteIndex;
|
||||||
|
|
||||||
|
// Sections of the virtual and physical addresses
|
||||||
|
logic [ARCH.VPN_BITS-1:0] VirtualPageNumber;
|
||||||
|
logic [ARCH.PPN_BITS-1:0] PhysicalPageNumber;
|
||||||
|
logic [11:0] PageOffset;
|
||||||
|
logic [ARCH.PA_BITS-1:0] PhysicalAddressFull;
|
||||||
|
|
||||||
|
// Pattern and pattern location in the CAM
|
||||||
|
logic [ENTRY_BITS-1:0] VPNIndex;
|
||||||
|
|
||||||
|
// RAM access location
|
||||||
|
logic [ENTRY_BITS-1:0] EntryIndex;
|
||||||
|
|
||||||
|
// Page table entry matching the virtual address
|
||||||
|
logic [`XLEN-1:0] PageTableEntry;
|
||||||
|
|
||||||
|
assign VirtualPageNumber = VirtualAddress[ARCH.VPN_BITS+11:12];
|
||||||
|
assign PageOffset = VirtualAddress[11:0];
|
||||||
|
|
||||||
|
// Choose a read or write location to the entry list
|
||||||
|
mux2 #(3) indexmux(VPNIndex, WriteIndex, TLBWrite, EntryIndex);
|
||||||
|
|
||||||
|
// Currently use random replacement algorithm
|
||||||
|
tlb_rand rdm(.*);
|
||||||
|
|
||||||
|
tlb_ram #(ENTRY_BITS) ram(.*);
|
||||||
|
tlb_cam #(ENTRY_BITS, ARCH.VPN_BITS) cam(.*);
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
assign PhysicalPageNumber = PageTableEntry[ARCH.PPN_BITS+9:10];
|
||||||
|
|
||||||
|
if (TLBHit) begin
|
||||||
|
assign PhysicalAddressFull = {PhysicalPageNumber, PageOffset};
|
||||||
|
end else begin
|
||||||
|
assign PhysicalAddressFull = 8'b0; // *** Actual behavior; disabled until walker functioning
|
||||||
|
//assign PhysicalAddressFull = {2'b0, VirtualPageNumber, PageOffset} // *** pass through should be removed as soon as walker ready
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
generate
|
||||||
|
if (`XLEN == 32) begin
|
||||||
|
mux2 #(`XLEN) addressmux(VirtualAddress, PhysicalAddressFull[31:0], ARCH.SvMode, PhysicalAddress);
|
||||||
|
end else begin
|
||||||
|
mux2 #(`XLEN) addressmux(VirtualAddress, {8'b0, PhysicalAddressFull}, ARCH.SvMode, PhysicalAddress);
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
assign TLBMiss = ~TLBHit & ~(TLBWrite | TLBFlush) & ARCH.SvMode;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module tlb_ram #(parameter ENTRY_BITS = 3) (
|
||||||
|
input clk, reset,
|
||||||
|
input [ENTRY_BITS-1:0] EntryIndex,
|
||||||
|
input [`XLEN-1:0] PageTableEntryWrite,
|
||||||
|
input TLBWrite,
|
||||||
|
|
||||||
|
output [`XLEN-1:0] PageTableEntry
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam NENTRIES = 2**ENTRY_BITS;
|
||||||
|
|
||||||
|
logic [`XLEN-1:0] ram [0:NENTRIES-1];
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (TLBWrite) ram[EntryIndex] <= PageTableEntryWrite;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign PageTableEntry = ram[EntryIndex];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
for (int i = 0; i < NENTRIES; i++)
|
||||||
|
ram[i] = `XLEN'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module tlb_cam #(parameter ENTRY_BITS = 3,
|
||||||
|
parameter KEY_BITS = 20) (
|
||||||
|
input clk, reset,
|
||||||
|
input [KEY_BITS-1:0] VirtualPageNumber,
|
||||||
|
input [ENTRY_BITS-1:0] WriteIndex,
|
||||||
|
input TLBWrite,
|
||||||
|
input TLBFlush,
|
||||||
|
output [ENTRY_BITS-1:0] VPNIndex,
|
||||||
|
output TLBHit
|
||||||
|
);
|
||||||
|
|
||||||
|
localparam NENTRIES = 2**ENTRY_BITS;
|
||||||
|
|
||||||
|
// Each entry of this memory has KEY_BITS for the key plus one valid bit.
|
||||||
|
logic [KEY_BITS:0] ram [0:NENTRIES-1];
|
||||||
|
|
||||||
|
logic [ENTRY_BITS-1:0] matched_address_comb;
|
||||||
|
logic match_found_comb;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (TLBWrite) ram[WriteIndex] <= {1'b1,VirtualPageNumber};
|
||||||
|
if (TLBFlush) begin
|
||||||
|
for (int i = 0; i < NENTRIES; i++)
|
||||||
|
ram[i][KEY_BITS] = 1'b0; // Zero out msb (valid bit) of all entries
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// *** Check whether this for loop synthesizes correctly
|
||||||
|
always_comb begin
|
||||||
|
match_found_comb = 1'b0;
|
||||||
|
matched_address_comb = '0;
|
||||||
|
for (int i = 0; i < NENTRIES; i++) begin
|
||||||
|
if (ram[i] == {1'b1,VirtualPageNumber} && !match_found_comb) begin
|
||||||
|
matched_address_comb = i;
|
||||||
|
match_found_comb = 1;
|
||||||
|
end else begin
|
||||||
|
matched_address_comb = matched_address_comb;
|
||||||
|
match_found_comb = match_found_comb;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign VPNIndex = matched_address_comb;
|
||||||
|
assign TLBHit = match_found_comb & ~(TLBWrite | TLBFlush);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
for (int i = 0; i < NENTRIES; i++)
|
||||||
|
ram[i] <= '0;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module tlb_rand #(parameter ENTRY_BITS = 3) (
|
||||||
|
input clk, reset,
|
||||||
|
output [ENTRY_BITS:0] WriteIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
logic [31:0] data;
|
||||||
|
assign data = $urandom;
|
||||||
|
assign WriteIndex = data[ENTRY_BITS:0];
|
||||||
|
|
||||||
|
endmodule
|
@ -56,20 +56,12 @@ module imem (
|
|||||||
generate
|
generate
|
||||||
if (`XLEN==32) begin
|
if (`XLEN==32) begin
|
||||||
assign InstrF = AdrF[1] ? {rd2[15:0], rd[31:16]} : rd;
|
assign InstrF = AdrF[1] ? {rd2[15:0], rd[31:16]} : rd;
|
||||||
if(`TIMBASE==0) begin
|
assign InstrAccessFaultF = ~&(({AdrF,1'b0} ~^ `TIMBASE) | `TIMRANGE);
|
||||||
assign InstrAccessFaultF = 0;
|
|
||||||
end else begin
|
|
||||||
assign InstrAccessFaultF = ~AdrF[31] | (|AdrF[30:16]); // memory mapped to 0x80000000-0x8000FFFF
|
|
||||||
end
|
|
||||||
end else begin
|
end else begin
|
||||||
assign InstrF = AdrF[2] ? (AdrF[1] ? {rd2[15:0], rd[63:48]} : rd[63:32])
|
assign InstrF = AdrF[2] ? (AdrF[1] ? {rd2[15:0], rd[63:48]} : rd[63:32])
|
||||||
: (AdrF[1] ? rd[47:16] : rd[31:0]);
|
: (AdrF[1] ? rd[47:16] : rd[31:0]);
|
||||||
/*if(`TIMBASE==0) begin
|
//assign InstrAccessFaultF = 0; //busybear: for now, i know we're not doing this
|
||||||
assign InstrAccessFaultF = 0;
|
assign InstrAccessFaultF = |AdrF[`XLEN-1:32] | ~&({AdrF[31:1],1'b0} ~^ `TIMBASE | `TIMRANGE);
|
||||||
end else begin
|
|
||||||
assign InstrAccessFaultF = (|AdrF[`XLEN-1:32]) | ~AdrF[31] | (|AdrF[30:16]); // memory mapped to 0x80000000-0x8000FFFF]
|
|
||||||
end*/
|
|
||||||
assign InstrAccessFaultF = 0; //busybear: for now, i know we're not doing this
|
|
||||||
end
|
end
|
||||||
endgenerate
|
endgenerate
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -60,7 +60,7 @@ module wallypipelinedhart (
|
|||||||
|
|
||||||
// new signals that must connect through DP
|
// new signals that must connect through DP
|
||||||
logic MulDivE, W64E;
|
logic MulDivE, W64E;
|
||||||
logic CSRReadM, CSRWriteM, PrivilegedM;
|
logic CSRReadM, CSRWriteM, PrivilegedM, AtomicM;
|
||||||
logic [`XLEN-1:0] SrcAE, SrcBE;
|
logic [`XLEN-1:0] SrcAE, SrcBE;
|
||||||
logic [`XLEN-1:0] SrcAM;
|
logic [`XLEN-1:0] SrcAM;
|
||||||
logic [2:0] Funct3E;
|
logic [2:0] Funct3E;
|
||||||
@ -85,6 +85,11 @@ module wallypipelinedhart (
|
|||||||
logic [4:0] SetFflagsM;
|
logic [4:0] SetFflagsM;
|
||||||
logic [2:0] FRM_REGW;
|
logic [2:0] FRM_REGW;
|
||||||
logic FloatRegWriteW;
|
logic FloatRegWriteW;
|
||||||
|
logic SquashSCW;
|
||||||
|
|
||||||
|
// memory management unit signals
|
||||||
|
logic ITLBMissF, ITLBHitF;
|
||||||
|
logic DTLBMissM, DTLBHitM;
|
||||||
|
|
||||||
// bus interface to dmem
|
// bus interface to dmem
|
||||||
logic MemReadM, MemWriteM;
|
logic MemReadM, MemWriteM;
|
||||||
|
@ -32,7 +32,6 @@ module testbench();
|
|||||||
logic [`XLEN-1:0] signature[0:10000];
|
logic [`XLEN-1:0] signature[0:10000];
|
||||||
logic [`XLEN-1:0] testadr;
|
logic [`XLEN-1:0] testadr;
|
||||||
string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName;
|
string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName;
|
||||||
logic [31:0] InstrW;
|
|
||||||
logic [`XLEN-1:0] meminit;
|
logic [`XLEN-1:0] meminit;
|
||||||
string tests[];
|
string tests[];
|
||||||
logic [`AHBW-1:0] HRDATAEXT;
|
logic [`AHBW-1:0] HRDATAEXT;
|
||||||
@ -62,9 +61,10 @@ module testbench();
|
|||||||
wallypipelinedsoc dut(.*);
|
wallypipelinedsoc dut(.*);
|
||||||
// Track names of instructions
|
// Track names of instructions
|
||||||
instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE,
|
instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE,
|
||||||
|
dut.hart.ifu.InstrF,
|
||||||
dut.hart.ifu.InstrD, dut.hart.ifu.InstrE,
|
dut.hart.ifu.InstrD, dut.hart.ifu.InstrE,
|
||||||
dut.hart.ifu.InstrM, InstrW,
|
dut.hart.ifu.InstrM, dut.hart.ifu.InstrW,
|
||||||
InstrDName, InstrEName, InstrMName, InstrWName);
|
InstrFName, InstrDName, InstrEName, InstrMName, InstrWName);
|
||||||
// initialize tests
|
// initialize tests
|
||||||
initial
|
initial
|
||||||
begin
|
begin
|
||||||
@ -86,13 +86,13 @@ endmodule
|
|||||||
/* verilator lint_on WIDTH */
|
/* verilator lint_on WIDTH */
|
||||||
module instrTrackerTB(
|
module instrTrackerTB(
|
||||||
input logic clk, reset, FlushE,
|
input logic clk, reset, FlushE,
|
||||||
input logic [31:0] InstrD,
|
input logic [31:0] InstrF, InstrD,
|
||||||
input logic [31:0] InstrE, InstrM,
|
input logic [31:0] InstrE, InstrM,
|
||||||
output logic [31:0] InstrW,
|
input logic [31:0] InstrW,
|
||||||
output string InstrDName, InstrEName, InstrMName, InstrWName);
|
output string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName);
|
||||||
|
|
||||||
// stage Instr to Writeback for visualization
|
// stage Instr to Writeback for visualization
|
||||||
flopr #(32) InstrWReg(clk, reset, InstrM, InstrW);
|
instrNameDecTB fdec(InstrF, InstrFName);
|
||||||
instrNameDecTB ddec(InstrD, InstrDName);
|
instrNameDecTB ddec(InstrD, InstrDName);
|
||||||
instrNameDecTB edec(InstrE, InstrEName);
|
instrNameDecTB edec(InstrE, InstrEName);
|
||||||
instrNameDecTB mdec(InstrM, InstrMName);
|
instrNameDecTB mdec(InstrM, InstrMName);
|
||||||
|
@ -90,7 +90,6 @@ string tests64iNOc[] = {
|
|||||||
"rv64i/I-MISALIGN_JMP-01","2000"
|
"rv64i/I-MISALIGN_JMP-01","2000"
|
||||||
};
|
};
|
||||||
string tests64i[] = '{
|
string tests64i[] = '{
|
||||||
"rv64i/I-MISALIGN_LDST-01", "2010",
|
|
||||||
"rv64i/I-ADD-01", "3000",
|
"rv64i/I-ADD-01", "3000",
|
||||||
"rv64i/I-ADDI-01", "3000",
|
"rv64i/I-ADDI-01", "3000",
|
||||||
"rv64i/I-ADDIW-01", "3000",
|
"rv64i/I-ADDIW-01", "3000",
|
||||||
@ -163,6 +162,7 @@ string tests64iNOc[] = {
|
|||||||
"rv64i/WALLY-SRAI", "3000",
|
"rv64i/WALLY-SRAI", "3000",
|
||||||
"rv64i/WALLY-LOAD", "11bf0",
|
"rv64i/WALLY-LOAD", "11bf0",
|
||||||
"rv64i/WALLY-JAL", "4000",
|
"rv64i/WALLY-JAL", "4000",
|
||||||
|
"rv64i/WALLY-JALR", "3000",
|
||||||
"rv64i/WALLY-STORE", "3000",
|
"rv64i/WALLY-STORE", "3000",
|
||||||
"rv64i/WALLY-ADDIW", "3000",
|
"rv64i/WALLY-ADDIW", "3000",
|
||||||
"rv64i/WALLY-SLLIW", "3000",
|
"rv64i/WALLY-SLLIW", "3000",
|
||||||
@ -289,6 +289,7 @@ string tests32i[] = {
|
|||||||
"rv32i/WALLY-SUB", "3000",
|
"rv32i/WALLY-SUB", "3000",
|
||||||
"rv32i/WALLY-STORE", "2000",
|
"rv32i/WALLY-STORE", "2000",
|
||||||
"rv32i/WALLY-JAL", "3000",
|
"rv32i/WALLY-JAL", "3000",
|
||||||
|
"rv32i/WALLY-JALR", "2000",
|
||||||
"rv32i/WALLY-BEQ" ,"4000",
|
"rv32i/WALLY-BEQ" ,"4000",
|
||||||
"rv32i/WALLY-BNE", "4000 ",
|
"rv32i/WALLY-BNE", "4000 ",
|
||||||
"rv32i/WALLY-BLTU", "4000 ",
|
"rv32i/WALLY-BLTU", "4000 ",
|
||||||
|
@ -19,9 +19,8 @@ from random import getrandbits
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
# functions
|
# helper functions
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
def InitTestGroup():
|
def InitTestGroup():
|
||||||
global TestGroup,TestGroupSizes,AllRegs,UnusedRegs,StoreAdrReg
|
global TestGroup,TestGroupSizes,AllRegs,UnusedRegs,StoreAdrReg
|
||||||
TestGroup += 1
|
TestGroup += 1
|
||||||
@ -44,19 +43,21 @@ def registerSelect():
|
|||||||
if len(UnusedRegs)==0:
|
if len(UnusedRegs)==0:
|
||||||
InitTestGroup()
|
InitTestGroup()
|
||||||
rd = choice(UnusedRegs)
|
rd = choice(UnusedRegs)
|
||||||
rs = choice(UnusedRegs)
|
|
||||||
UnusedRegs.remove(rd)
|
UnusedRegs.remove(rd)
|
||||||
|
OtherRegs = deepcopy(UnusedRegs)
|
||||||
|
if 0 in OtherRegs:
|
||||||
|
OtherRegs.remove(0)
|
||||||
|
if len(OtherRegs) == 0:
|
||||||
|
OtherRegs = deepcopy(AllRegs)
|
||||||
|
OtherRegs.remove(0)
|
||||||
|
rs = choice(OtherRegs)
|
||||||
OtherRegs = deepcopy(AllRegs)
|
OtherRegs = deepcopy(AllRegs)
|
||||||
OtherRegs.remove(StoreAdrReg)
|
OtherRegs.remove(StoreAdrReg)
|
||||||
OtherRegs.remove(rd)
|
OtherRegs.remove(rd)
|
||||||
try:
|
if 0 in OtherRegs:
|
||||||
OtherRegs.remove(0)
|
OtherRegs.remove(0)
|
||||||
except:
|
if rs in OtherRegs:
|
||||||
pass
|
|
||||||
try:
|
|
||||||
OtherRegs.remove(rs)
|
OtherRegs.remove(rs)
|
||||||
except:
|
|
||||||
pass
|
|
||||||
DataReg = choice(OtherRegs)
|
DataReg = choice(OtherRegs)
|
||||||
OtherRegs.remove(DataReg)
|
OtherRegs.remove(DataReg)
|
||||||
OtherRd = choice(OtherRegs)
|
OtherRd = choice(OtherRegs)
|
||||||
@ -65,52 +66,74 @@ def registerSelect():
|
|||||||
def addInst(line):
|
def addInst(line):
|
||||||
global CurrAdr
|
global CurrAdr
|
||||||
f.write(line)
|
f.write(line)
|
||||||
if ("li x" in line):
|
if ("li x" in line) and ("slli x" not in line):
|
||||||
CurrAdr += 8 if (xlen == 32) else 20
|
CurrAdr += 8 if (xlen == 32) else 20
|
||||||
elif ("la x" in line):
|
elif ("la x" in line):
|
||||||
CurrAdr += 8
|
CurrAdr += 8
|
||||||
else:
|
else:
|
||||||
CurrAdr += 4
|
CurrAdr += 4
|
||||||
|
|
||||||
def writeForwardsJumpVector(spacers):
|
def expectValue(expectReg, expectVal, sigOffset):
|
||||||
global TestNum
|
global TestGroupSizes
|
||||||
rd, rs, DataReg, OtherRd = registerSelect()
|
TestGroupSizes[TestGroup-1] += 1
|
||||||
if (xlen==64):
|
addInst(" "+storecmd+" x"+str(expectReg)+", "+str(wordsize*sigOffset)+"(x"+str(StoreAdrReg)+")\n")
|
||||||
expected = int("fedbca9876540000",16)
|
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(expectReg)+", "+formatstr.format(expectVal)+")\n")
|
||||||
unexpected = int("ffff0000ffff0000",16)
|
if (xlen == 32):
|
||||||
|
r.write(formatrefstr.format(expectVal)+"\n")
|
||||||
else:
|
else:
|
||||||
expected = int("fedbca98",16)
|
r.write(formatrefstr.format(expectVal % 2**32)+"\n" + formatrefstr.format(expectVal >> 32)+"\n")
|
||||||
unexpected = int("ff00ff00",16)
|
|
||||||
|
|
||||||
|
def addJalr(rs,rd,dist):
|
||||||
|
target = CurrAdr + 20 + dist
|
||||||
|
target31_12 = CurrAdr >> 12 # 20 bits for lui
|
||||||
|
target11_0 = target - (target31_12 << 12) # 12 remaining bits
|
||||||
|
target31_16 = target31_12 >> 4 # lui sign extends, so shift in a leading 0
|
||||||
|
target15_12 = target31_12 - (target31_16 << 4) # the nibble we just lost
|
||||||
|
if target11_0 > 0:
|
||||||
|
offset = randint(-(1<<11)-1,(1<<11)-2-target11_0)
|
||||||
|
else:
|
||||||
|
offset = randint(-(1<<11)-1-target11_0,(1<<11)-2)
|
||||||
|
addInst(" lui x"+str(rs)+", 0x"+imm20formatstr.format(target31_16)+"\n")
|
||||||
|
addInst(" addi x"+str(rs)+", x"+str(rs)+", SEXT_IMM(0x0"+imm12formatstr.format(target15_12 << 8)+")\n")
|
||||||
|
addInst(" slli x"+str(rs)+", x"+str(rs)+", SEXT_IMM(4)\n")
|
||||||
|
addInst(" addi x"+str(rs)+", x"+str(rs)+", SEXT_IMM(0x"+imm12formatstr.format(0xfff&(offset+target11_0+randint(0,1)))+")\n")
|
||||||
|
addInst(" JALR x"+str(rd)+", x"+str(rs)+", SEXT_IMM(0x"+imm12formatstr.format(0xfff&(-offset))+")\n")
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# test functions
|
||||||
|
##################################
|
||||||
|
def writeForwardsJumpVector(spacers,instr):
|
||||||
|
global TestNum
|
||||||
|
TestNum += 1
|
||||||
|
rd, rs, DataReg, OtherRd = registerSelect()
|
||||||
|
# Header
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"("+formatstr.format(CurrAdr+44)+") data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n")
|
f.write(" # Testcase "+str(TestNum)+"\n")
|
||||||
|
# Test Code
|
||||||
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
|
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
|
||||||
addInst(" JAL x"+str(rd)+", 1f\n")
|
if (instr=="JAL"):
|
||||||
|
addInst(" JAL x"+str(rd)+", 1f\n")
|
||||||
|
elif (instr=="JALR"):
|
||||||
|
dist = spacers*(8 if (xlen == 32) else 20) # Compute distance from linked adr to target adr
|
||||||
|
addJalr(rs,rd,dist);
|
||||||
|
else:
|
||||||
|
exit("invalid instruction")
|
||||||
LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
|
LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
|
||||||
for i in range(spacers):
|
for i in range(spacers):
|
||||||
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
|
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
|
||||||
f.write("1:\n")
|
f.write("1:\n")
|
||||||
addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n")
|
# Store values to be verified
|
||||||
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n")
|
expectValue(rd, LinkAdr, 2*TestNum+0)
|
||||||
addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n")
|
expectValue(DataReg, expected, 2*TestNum+1)
|
||||||
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n")
|
|
||||||
writeExpectedToRef(LinkAdr)
|
|
||||||
writeExpectedToRef(expected)
|
|
||||||
TestNum = TestNum+1
|
|
||||||
|
|
||||||
def writeBackwardsJumpVector(spacers):
|
def writeBackwardsJumpVector(spacers,instr):
|
||||||
global TestNum
|
global TestNum
|
||||||
rd, rs, DataReg,OtherRd = registerSelect()
|
TestNum += 1
|
||||||
if (xlen==64):
|
rd, rs, DataReg, OtherRd = registerSelect()
|
||||||
expected = int("fedbca9876540000",16)
|
# Header
|
||||||
unexpected = int("ffff0000ffff0000",16)
|
|
||||||
else:
|
|
||||||
expected = int("fedbca98",16)
|
|
||||||
unexpected = int("ff00ff00",16)
|
|
||||||
|
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"("+formatstr.format(CurrAdr+20+8*spacers)+") data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n")
|
f.write(" # Testcase "+str(TestNum)+"\n")
|
||||||
|
# Test Code
|
||||||
addInst(" JAL x"+str(OtherRd)+", 2f\n")
|
addInst(" JAL x"+str(OtherRd)+", 2f\n")
|
||||||
f.write("1:\n")
|
f.write("1:\n")
|
||||||
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
|
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
|
||||||
@ -118,29 +141,27 @@ def writeBackwardsJumpVector(spacers):
|
|||||||
f.write("2:\n")
|
f.write("2:\n")
|
||||||
for i in range(spacers):
|
for i in range(spacers):
|
||||||
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
|
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
|
||||||
addInst(" JAL x"+str(rd)+", 1b\n")
|
if (instr=="JAL"):
|
||||||
|
addInst(" JAL x"+str(rd)+", 1b\n")
|
||||||
|
elif (instr=="JALR"):
|
||||||
|
dist = -20 - 4 - (1+spacers)*(8 if (xlen == 32) else 20) # Compute distance from linked adr to target adr
|
||||||
|
addJalr(rs,rd,dist);
|
||||||
|
else:
|
||||||
|
exit("invalid instruction")
|
||||||
LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
|
LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
|
||||||
f.write("3:\n")
|
f.write("3:\n")
|
||||||
addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n")
|
# Store values to be verified
|
||||||
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n")
|
expectValue(rd, LinkAdr, 2*TestNum+0)
|
||||||
addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n")
|
expectValue(DataReg, expected, 2*TestNum+1)
|
||||||
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n")
|
|
||||||
writeExpectedToRef(LinkAdr)
|
|
||||||
writeExpectedToRef(expected)
|
|
||||||
TestNum = TestNum+1
|
|
||||||
|
|
||||||
def writeChainVector(repetitions,spacers):
|
def writeChainVector(repetitions,spacers):
|
||||||
global TestNum
|
global TestNum
|
||||||
|
TestNum += 1
|
||||||
rd, rs, DataReg,OtherRd = registerSelect()
|
rd, rs, DataReg,OtherRd = registerSelect()
|
||||||
if (xlen==64):
|
# Header
|
||||||
expected = int("fedbca9876540000",16)
|
|
||||||
unexpected = int("ffff0000ffff0000",16)
|
|
||||||
else:
|
|
||||||
expected = int("fedbca98",16)
|
|
||||||
unexpected = int("ff00ff00",16)
|
|
||||||
|
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
f.write(" # Testcase "+str(TestNum)+" address cmp result rd:x"+str(rd)+"(ugh; if you really wanted to, you could figure it out) data result rd:x"+str(DataReg)+"("+formatstr.format(expected)+")\n")
|
f.write(" # Testcase "+str(TestNum)+"\n")
|
||||||
|
# Test Code
|
||||||
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
|
addInst(" li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
|
||||||
for i in range(repetitions):
|
for i in range(repetitions):
|
||||||
addInst(" JAL x"+str(OtherRd)+", "+str(3*i+2)+"f\n")
|
addInst(" JAL x"+str(OtherRd)+", "+str(3*i+2)+"f\n")
|
||||||
@ -159,57 +180,56 @@ def writeChainVector(repetitions,spacers):
|
|||||||
for j in range(i):
|
for j in range(i):
|
||||||
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
|
addInst(" li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
|
||||||
f.write(str(3*i+3)+":\n")
|
f.write(str(3*i+3)+":\n")
|
||||||
addInst(" "+storecmd+" x"+str(rd)+", "+str(wordsize*(2*TestNum+0))+"(x"+str(StoreAdrReg)+")\n")
|
# Store values to be verified
|
||||||
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(rd)+", "+formatstr.format(LinkAdr)+")\n")
|
expectValue(rd, LinkAdr, 2*TestNum+0)
|
||||||
addInst(" "+storecmd+" x"+str(DataReg)+", "+str(wordsize*(2*TestNum+1))+"(x"+str(StoreAdrReg)+")\n")
|
expectValue(DataReg, expected, 2*TestNum+1)
|
||||||
f.write(" RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(DataReg)+", "+formatstr.format(expected)+")\n")
|
|
||||||
writeExpectedToRef(LinkAdr)
|
|
||||||
writeExpectedToRef(expected)
|
|
||||||
TestNum = TestNum+1
|
|
||||||
|
|
||||||
|
|
||||||
def writeExpectedToRef(expected):
|
|
||||||
global TestGroupSizes
|
|
||||||
TestGroupSizes[TestGroup-1] += 1
|
|
||||||
if (xlen == 32):
|
|
||||||
r.write(formatrefstr.format(expected)+"\n")
|
|
||||||
else:
|
|
||||||
r.write(formatrefstr.format(expected % 2**32)+"\n" + formatrefstr.format(expected >> 32)+"\n")
|
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
# main body
|
# main body
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
# change these to suite your tests
|
# change these to suite your tests
|
||||||
tests = ["JAL"]
|
test = 0
|
||||||
|
tests = ["JAL","JALR"]
|
||||||
author = "Ben Bracker (bbracker@hmc.edu)"
|
author = "Ben Bracker (bbracker@hmc.edu)"
|
||||||
xlens = [32,64]
|
xlens = [32,64]
|
||||||
numtests = 100;
|
numtests = 100
|
||||||
|
|
||||||
# setup
|
# setup
|
||||||
seed(0) # make tests reproducible
|
seed(0) # make tests reproducible
|
||||||
|
|
||||||
# generate files for each test
|
# generate files for each test
|
||||||
for xlen in xlens:
|
for test in tests:
|
||||||
CurrAdr = int("80000108",16)
|
for xlen in xlens:
|
||||||
TestNum = 0
|
print(test+" "+str(xlen))
|
||||||
TestGroup = 1
|
CurrAdr = int("80000108",16)
|
||||||
TestGroupSizes = [0]
|
TestNum = -1
|
||||||
AllRegs = list(range(0,32))
|
TestGroup = 1
|
||||||
UnusedRegs = deepcopy(AllRegs)
|
TestGroupSizes = [0]
|
||||||
StoreAdrReg = 6 # matches what's in header script
|
AllRegs = list(range(0,32))
|
||||||
UnusedRegs.remove(6)
|
UnusedRegs = deepcopy(AllRegs)
|
||||||
|
StoreAdrReg = 6 # matches what's in header script
|
||||||
|
UnusedRegs.remove(6)
|
||||||
|
if (xlen==64):
|
||||||
|
expected = int("fedbca9876540000",16)
|
||||||
|
unexpected = int("ffff0000ffff0000",16)
|
||||||
|
else:
|
||||||
|
expected = int("fedbca98",16)
|
||||||
|
unexpected = int("ff00ff00",16)
|
||||||
|
|
||||||
|
formatstrlen = str(int(xlen/4))
|
||||||
|
formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number
|
||||||
|
formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x
|
||||||
|
imm20formatstr = "{:05x}"
|
||||||
|
imm12formatstr = "{:03x}"
|
||||||
|
|
||||||
|
if (xlen == 32):
|
||||||
|
storecmd = "sw"
|
||||||
|
wordsize = 4
|
||||||
|
else:
|
||||||
|
storecmd = "sd"
|
||||||
|
wordsize = 8
|
||||||
|
|
||||||
formatstrlen = str(int(xlen/4))
|
|
||||||
formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number
|
|
||||||
formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x
|
|
||||||
if (xlen == 32):
|
|
||||||
storecmd = "sw"
|
|
||||||
wordsize = 4
|
|
||||||
else:
|
|
||||||
storecmd = "sd"
|
|
||||||
wordsize = 8
|
|
||||||
for test in tests:
|
|
||||||
imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/"
|
imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/"
|
||||||
basename = "WALLY-" + test
|
basename = "WALLY-" + test
|
||||||
fname = imperaspath + "src/" + basename + ".S"
|
fname = imperaspath + "src/" + basename + ".S"
|
||||||
@ -221,7 +241,7 @@ for xlen in xlens:
|
|||||||
f.write("///////////////////////////////////////////\n")
|
f.write("///////////////////////////////////////////\n")
|
||||||
f.write("// "+fname+ "\n")
|
f.write("// "+fname+ "\n")
|
||||||
f.write("//\n")
|
f.write("//\n")
|
||||||
f.write("// This file can be used to test the RISC-V JAL instruction.\n")
|
f.write("// This file can be used to test the RISC-V JAL(R) instruction.\n")
|
||||||
f.write("// But be warned that altering the test environment may break this test!\n")
|
f.write("// But be warned that altering the test environment may break this test!\n")
|
||||||
f.write("// In order to work, this test expects that the first instruction (la)\n")
|
f.write("// In order to work, this test expects that the first instruction (la)\n")
|
||||||
f.write("// be allocated at 0x80000100.\n")
|
f.write("// be allocated at 0x80000100.\n")
|
||||||
@ -235,14 +255,24 @@ for xlen in xlens:
|
|||||||
f.write(line)
|
f.write(line)
|
||||||
|
|
||||||
# print directed test vectors
|
# print directed test vectors
|
||||||
for i in range(0,31):
|
if test == "JAL":
|
||||||
writeForwardsJumpVector(randint(0,4))
|
for i in range(0,31):
|
||||||
for i in range(0,31):
|
writeForwardsJumpVector(randint(0,4),"JAL")
|
||||||
writeBackwardsJumpVector(randint(0,4))
|
for i in range(0,31):
|
||||||
writeForwardsJumpVector(100)
|
writeBackwardsJumpVector(randint(0,4),"JAL")
|
||||||
writeBackwardsJumpVector(100)
|
writeForwardsJumpVector(100,"JAL")
|
||||||
writeChainVector(6,True)
|
writeBackwardsJumpVector(100,"JAL")
|
||||||
writeChainVector(16,False)
|
writeChainVector(6,True)
|
||||||
|
writeChainVector(16,False)
|
||||||
|
elif test == "JALR":
|
||||||
|
for i in range(0,31):
|
||||||
|
writeForwardsJumpVector(randint(0,4),"JALR")
|
||||||
|
for i in range(0,31):
|
||||||
|
writeBackwardsJumpVector(randint(0,4),"JALR")
|
||||||
|
# can't make these latter two too long else 12 bit immediate overflows
|
||||||
|
# (would need to lui or slli rs to achieve longer ranges)
|
||||||
|
writeForwardsJumpVector(15,"JALR")
|
||||||
|
writeBackwardsJumpVector(15,"JALR")
|
||||||
|
|
||||||
# print footer
|
# print footer
|
||||||
h = open("testgen_footer.S", "r")
|
h = open("testgen_footer.S", "r")
|
||||||
@ -254,7 +284,3 @@ for xlen in xlens:
|
|||||||
f.write("\nRV_COMPLIANCE_DATA_END\n")
|
f.write("\nRV_COMPLIANCE_DATA_END\n")
|
||||||
f.close()
|
f.close()
|
||||||
r.close()
|
r.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
285
wally-pipelined/testgen/testgen-VIRTUALMEMORY.py
Normal file
285
wally-pipelined/testgen/testgen-VIRTUALMEMORY.py
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
##################################
|
||||||
|
# testgen-VIRTUALMEMORY.py
|
||||||
|
#
|
||||||
|
# Jessica Torrey <jtorrey@hmc.edu> 01 March 2021
|
||||||
|
# Thomas Fleming <tfleming@hmc.edu> 01 March 2021
|
||||||
|
#
|
||||||
|
# Generate an ad-hoc test program for RISC-V Design Validation. Tests the
|
||||||
|
# functionality of the memory management unit (MMU).
|
||||||
|
##################################
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# libraries
|
||||||
|
##################################
|
||||||
|
from datetime import datetime
|
||||||
|
from random import randint, seed, getrandbits
|
||||||
|
from textwrap import dedent
|
||||||
|
from virtual_memory_util import *
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# global structures
|
||||||
|
##################################
|
||||||
|
|
||||||
|
testcase_num = 0
|
||||||
|
signature_len = 2000
|
||||||
|
signature = [0xff for _ in range(signature_len)]
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# functions
|
||||||
|
##################################
|
||||||
|
|
||||||
|
def rand_reg():
|
||||||
|
"""
|
||||||
|
Produce a random register from 1 to 31 (skipping 6, since r6 is used for
|
||||||
|
other things).
|
||||||
|
"""
|
||||||
|
r = randint(1,30)
|
||||||
|
if r >= 6:
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
def rand_regs():
|
||||||
|
"""
|
||||||
|
Generate two random, unequal register numbers (skipping x6).
|
||||||
|
"""
|
||||||
|
rs1 = rand_reg()
|
||||||
|
rs2 = rand_reg()
|
||||||
|
while rs1 == rs2:
|
||||||
|
rs2 = rand_reg()
|
||||||
|
|
||||||
|
return rs1, rs2
|
||||||
|
|
||||||
|
def initialize_page_directory()
|
||||||
|
|
||||||
|
def generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta):
|
||||||
|
"""
|
||||||
|
Create assembly code for a given STORE test case, returned as a string.
|
||||||
|
|
||||||
|
Generates an `xlen`-bit test case for `instruction` (one of sb, sh, sw, or
|
||||||
|
sd) that loads `value` into `value_register`, then attempts to store that
|
||||||
|
value in memory at address (x6 + `base_delta`). The test case
|
||||||
|
assumes the current base address for the signature is in register x6.
|
||||||
|
|
||||||
|
The form of the STORE instruction is as follows:
|
||||||
|
|
||||||
|
`instruction` `value_register` `offset`(`addr_register`)
|
||||||
|
"""
|
||||||
|
global testcase_num
|
||||||
|
|
||||||
|
hex_value = f"{value:0{xlen // 4}x}"
|
||||||
|
|
||||||
|
data = f"""# Testcase {testcase_num}: source: x{value_register} (value 0x{hex_value}), destination: {offset}(x{addr_register}) ({base_delta} bytes into signature)
|
||||||
|
addi x{addr_register}, x6, {base_delta}
|
||||||
|
li x{value_register}, MASK_XLEN({-offset})
|
||||||
|
add x{addr_register}, x{addr_register}, x{value_register}
|
||||||
|
li x{value_register}, 0x{hex_value}
|
||||||
|
{instruction} x{value_register}, {offset}(x{addr_register})
|
||||||
|
"""
|
||||||
|
|
||||||
|
#update_signature(store_to_size[instruction], value, base_delta)
|
||||||
|
|
||||||
|
testcase_num += 1
|
||||||
|
return data
|
||||||
|
|
||||||
|
def validate_memory(scratch_register, value_register, value, base_delta, length):
|
||||||
|
"""
|
||||||
|
Create assembly code to verify that `length` bytes at mem[x6 + `base_delta`]
|
||||||
|
store `value`.
|
||||||
|
|
||||||
|
Assumes x6 stores the current base address for the signature.
|
||||||
|
"""
|
||||||
|
truncated_value = value & (2**(length * 8) - 1)
|
||||||
|
hex_value = f"{truncated_value:0{length * 2}x}"
|
||||||
|
|
||||||
|
load = size_to_load[length]
|
||||||
|
data = f"""addi x{scratch_register}, x6, {base_delta}
|
||||||
|
{load} x{value_register}, 0(x{scratch_register})
|
||||||
|
RVTEST_IO_ASSERT_GPR_EQ(x{scratch_register}, x{value_register}, 0x{hex_value})
|
||||||
|
|
||||||
|
"""
|
||||||
|
return data
|
||||||
|
|
||||||
|
def update_signature(length, value, base_delta):
|
||||||
|
"""
|
||||||
|
Write the lower `length` bytes of `value` to the little-endian signature
|
||||||
|
array, starting at byte `base_delta`.
|
||||||
|
"""
|
||||||
|
truncated_value = value & (2**(length * 8) - 1)
|
||||||
|
value_bytes = truncated_value.to_bytes(length, 'little')
|
||||||
|
#print("n: {}, value: {:x}, trunc: {:x}, length: {}, bd: {:x}".format(testcase_num, value, truncated_value, length, base_delta))
|
||||||
|
for i in range(length):
|
||||||
|
signature[base_delta + i] = value_bytes[i]
|
||||||
|
|
||||||
|
def write_signature(outfile):
|
||||||
|
"""
|
||||||
|
Writes successive 32-bit words from the signature array into a given file.
|
||||||
|
"""
|
||||||
|
for i in range(0, signature_len, 4):
|
||||||
|
word = list(reversed(signature[i:i+4]))
|
||||||
|
hexword = bytearray(word).hex()
|
||||||
|
outfile.write(f"{hexword}\n")
|
||||||
|
|
||||||
|
def write_header(outfile):
|
||||||
|
"""
|
||||||
|
Write the name of the test file, authors, and creation date.
|
||||||
|
"""
|
||||||
|
outfile.write(dedent(f"""\
|
||||||
|
///////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// WALLY-STORE
|
||||||
|
//
|
||||||
|
// Author: {author}
|
||||||
|
//
|
||||||
|
// Created {str(datetime.now())}
|
||||||
|
"""))
|
||||||
|
outfile.write(open("testgen_header.S", "r").read())
|
||||||
|
|
||||||
|
def write_footer(outfile):
|
||||||
|
"""
|
||||||
|
Write necessary closing code, including a data section for the signature.
|
||||||
|
"""
|
||||||
|
outfile.write(open("testgen_footer.S", 'r').read())
|
||||||
|
data_section = dedent(f"""\
|
||||||
|
\t.fill {signature_len}, 1, -1
|
||||||
|
RV_COMPLIANCE_DATA_END
|
||||||
|
""")
|
||||||
|
outfile.write(data_section)
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# test cases
|
||||||
|
##################################
|
||||||
|
|
||||||
|
def write_basic_tests(outfile, xlen, instr_len, num, base_delta):
|
||||||
|
"""
|
||||||
|
Test basic functionality of STORE, using random registers, offsets, and
|
||||||
|
values.
|
||||||
|
|
||||||
|
Creates `num` tests for a single store instruction of length `instr_len`,
|
||||||
|
writing to memory at consecutive locations, starting `base_delta` bytes from
|
||||||
|
the start of the signature.
|
||||||
|
|
||||||
|
Returns the number of bytes from the start of the signature where testing
|
||||||
|
ended.
|
||||||
|
"""
|
||||||
|
instruction = size_to_store[instr_len]
|
||||||
|
for i in range(num):
|
||||||
|
value_register, addr_register = rand_regs()
|
||||||
|
offset = randint(-2**(12 - 1), 2**(12 - 1) - 1)
|
||||||
|
value = randint(0, 2**(instr_len * 8) - 1)
|
||||||
|
test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta)
|
||||||
|
validate = validate_memory(addr_register, value_register, value, base_delta, instr_len)
|
||||||
|
outfile.write(test)
|
||||||
|
outfile.write(validate)
|
||||||
|
base_delta += instr_len
|
||||||
|
return base_delta
|
||||||
|
|
||||||
|
def write_random_store_tests(outfile, xlen, instr_len, num, min_base_delta):
|
||||||
|
"""
|
||||||
|
Test random access of STORE, using random registers, offsets, values, and
|
||||||
|
memory locations.
|
||||||
|
|
||||||
|
Creates `num` tests for a single store instruction of length `instr_len`,
|
||||||
|
writing to memory at random locations between `min_base_delta` bytes past
|
||||||
|
the start of the signature to the end of the signature.
|
||||||
|
"""
|
||||||
|
instruction = size_to_store[instr_len]
|
||||||
|
for i in range(num):
|
||||||
|
base_delta = randint(min_base_delta, signature_len - 1)
|
||||||
|
base_delta -= (base_delta % instr_len)
|
||||||
|
value_register, addr_register = rand_regs()
|
||||||
|
offset = randint(-2**(12 - 1), 2**(12 - 1) - 1)
|
||||||
|
value = randint(0, 2**(instr_len * 8) - 1)
|
||||||
|
|
||||||
|
test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta)
|
||||||
|
validate = validate_memory(addr_register, value_register, value, base_delta, instr_len)
|
||||||
|
outfile.write(test)
|
||||||
|
outfile.write(validate)
|
||||||
|
|
||||||
|
def write_repeated_store_tests(outfile, xlen, instr_len, num, base_delta):
|
||||||
|
"""
|
||||||
|
Test repeated access of STORE, using random registers, offsets, values, and a
|
||||||
|
single memory location.
|
||||||
|
|
||||||
|
Creates `num` tests for a single store instruction of length `instr_len`,
|
||||||
|
writing to memory `base_delta` bytes past the start of the signature.
|
||||||
|
"""
|
||||||
|
instruction = size_to_store[instr_len]
|
||||||
|
for i in range(num):
|
||||||
|
value_register, addr_register = rand_regs()
|
||||||
|
offset = 0
|
||||||
|
value = (1 << ((2 * i) % xlen))
|
||||||
|
|
||||||
|
test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta)
|
||||||
|
validate = validate_memory(addr_register, value_register, value, base_delta, instr_len)
|
||||||
|
|
||||||
|
outfile.write(test)
|
||||||
|
outfile.write(validate)
|
||||||
|
|
||||||
|
def write_corner_case_tests(outfile, xlen, instr_len, base_delta):
|
||||||
|
instruction = size_to_store[instr_len]
|
||||||
|
|
||||||
|
corner_cases_32 = [0x0, 0x10000001, 0x01111111]
|
||||||
|
corner_cases_64 = [0x1000000000000001, 0x0111111111111111]
|
||||||
|
corner_cases = corner_cases_32
|
||||||
|
if xlen == 64:
|
||||||
|
corner_cases += corner_cases_64
|
||||||
|
|
||||||
|
for offset in corner_cases:
|
||||||
|
for value in corner_cases:
|
||||||
|
value_register, addr_register = rand_regs()
|
||||||
|
test = generate_case(xlen, instruction, value_register, value, addr_register, offset, base_delta)
|
||||||
|
validate = validate_memory(addr_register, value_register, value, base_delta, instr_len)
|
||||||
|
|
||||||
|
outfile.write(test)
|
||||||
|
outfile.write(validate)
|
||||||
|
|
||||||
|
base_delta += instr_len
|
||||||
|
|
||||||
|
return base_delta
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# main body
|
||||||
|
##################################
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
instructions = ["sd", "sw", "sh", "sb"]
|
||||||
|
author = "Jessica Torrey <jtorrey@hmc.edu> & Thomas Fleming <tfleming@hmc.edu>"
|
||||||
|
xlens = [32, 64]
|
||||||
|
numrand = 100
|
||||||
|
|
||||||
|
# setup
|
||||||
|
seed(0) # make tests reproducible
|
||||||
|
|
||||||
|
for xlen in xlens:
|
||||||
|
if (xlen == 32):
|
||||||
|
wordsize = 4
|
||||||
|
else:
|
||||||
|
wordsize = 8
|
||||||
|
|
||||||
|
fname = f"../../imperas-riscv-tests/riscv-test-suite/rv{xlen}i/src/WALLY-VIRTUALMEMORY.S"
|
||||||
|
refname = f"../../imperas-riscv-tests/riscv-test-suite/rv{xlen}i/references/WALLY-VIRTUALMEMORY.reference_output"
|
||||||
|
f = open(fname, "w")
|
||||||
|
r = open(refname, "w")
|
||||||
|
|
||||||
|
write_header(f)
|
||||||
|
|
||||||
|
base_delta = 0
|
||||||
|
|
||||||
|
for instruction in instructions:
|
||||||
|
if xlen == 32 and instruction == 'sd':
|
||||||
|
continue
|
||||||
|
instr_len = store_to_size[instruction]
|
||||||
|
base_delta = write_basic_tests(f, xlen, instr_len, 5, base_delta)
|
||||||
|
write_repeated_store_tests(f, xlen, instr_len, 32, base_delta)
|
||||||
|
write_random_store_tests(f, xlen, instr_len, 5, base_delta + wordsize)
|
||||||
|
|
||||||
|
write_footer(f)
|
||||||
|
|
||||||
|
write_signature(r)
|
||||||
|
f.close()
|
||||||
|
r.close()
|
||||||
|
|
||||||
|
# Reset testcase_num and signature
|
||||||
|
testcase_num = 0
|
||||||
|
signature = [0xff for _ in range(signature_len)]
|
125
wally-pipelined/testgen/virtual_memory_util.py
Normal file
125
wally-pipelined/testgen/virtual_memory_util.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
##################################
|
||||||
|
# virtual_memory_util.py
|
||||||
|
#
|
||||||
|
# Jessica Torrey <jtorrey@hmc.edu> 01 March 2021
|
||||||
|
# Thomas Fleming <tfleming@hmc.edu> 01 March 2021
|
||||||
|
#
|
||||||
|
# Utility functions for simulating and testing virtual memory on RISC-V.
|
||||||
|
##################################
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# libraries
|
||||||
|
##################################
|
||||||
|
from datetime import datetime
|
||||||
|
from random import randint, seed, getrandbits
|
||||||
|
from textwrap import dedent
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# global structures
|
||||||
|
##################################
|
||||||
|
PTE_D = 1 << 7
|
||||||
|
PTE_A = 1 << 6
|
||||||
|
PTE_G = 1 << 5
|
||||||
|
PTE_U = 1 << 4
|
||||||
|
PTE_X = 1 << 3
|
||||||
|
PTE_W = 1 << 2
|
||||||
|
PTE_R = 1 << 1
|
||||||
|
PTE_V = 1 << 0
|
||||||
|
|
||||||
|
|
||||||
|
pgdir = []
|
||||||
|
|
||||||
|
testcase_num = 0
|
||||||
|
signature_len = 2000
|
||||||
|
signature = [0xff for _ in range(signature_len)]
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# classes
|
||||||
|
##################################
|
||||||
|
class Architecture:
|
||||||
|
def __init__(self, xlen):
|
||||||
|
if (xlen == 32):
|
||||||
|
self.PTESIZE = 4
|
||||||
|
|
||||||
|
self.VPN_BITS = 20
|
||||||
|
self.VPN_SEGMENT_BITS = 10
|
||||||
|
|
||||||
|
self.PPN_BITS = 22
|
||||||
|
|
||||||
|
self.LEVELS = 2
|
||||||
|
elif (xlen == 64):
|
||||||
|
self.PTESIZE = 8
|
||||||
|
|
||||||
|
self.VPN_BITS = 27
|
||||||
|
self.VPN_SEGMENT_BITS = 9
|
||||||
|
|
||||||
|
self.PPN_BITS = 44
|
||||||
|
|
||||||
|
self.LEVELS = 3
|
||||||
|
else:
|
||||||
|
raise ValueError('Only rv32 and rv64 are allowed.')
|
||||||
|
|
||||||
|
self.PGSIZE = 2**12
|
||||||
|
self.NPTENTRIES = self.PGSIZE // self.PTESIZE
|
||||||
|
self.PTE_BITS = 8 * self.PTESIZE
|
||||||
|
self.OFFSET_BITS = 12
|
||||||
|
self.FLAG_BITS = 8
|
||||||
|
|
||||||
|
class PageTableEntry:
|
||||||
|
def __init__(self, ppn, flags, arch):
|
||||||
|
assert 0 <= ppn and ppn < 2**arch.PPN_BITS, "Invalid physical page number for PTE"
|
||||||
|
assert 0 <= flags and flags < 2**arch.FLAG_BITS, "Invalid flags for PTE"
|
||||||
|
self.ppn = ppn
|
||||||
|
self.flags = flags
|
||||||
|
self.arch = arch
|
||||||
|
|
||||||
|
def entry(self):
|
||||||
|
return (self.ppn << (self.arch.PTE_BITS - self.arch.PPN_BITS)) | self.flags
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "0x{0:0{1}x}".format(self.entry(), self.arch.PTESIZE*2)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<ppn: {hex(self.ppn)}, flags: {self.flags:08b}>"
|
||||||
|
|
||||||
|
class PageTable:
|
||||||
|
"""
|
||||||
|
Represents a single level of the page table, with
|
||||||
|
"""
|
||||||
|
def __init__(self, name, arch):
|
||||||
|
self.table = {}
|
||||||
|
self.name = name
|
||||||
|
self.arch = arch
|
||||||
|
|
||||||
|
def add_entry(self, vpn_segment, ppn_segment, flags, linked_table = None):
|
||||||
|
if not (0 <= vpn_segment < 2**self.arch.VPN_SEGMENT_BITS):
|
||||||
|
raise ValueError("Invalid virtual page segment number")
|
||||||
|
self.table[vpn_segment] = (PageTableEntry(ppn_segment, flags, self.arch), linked_table)
|
||||||
|
|
||||||
|
def add_mapping(self, va, pa, flags):
|
||||||
|
if not (0 <= va < 2**self.arch.VPN_BITS):
|
||||||
|
raise ValueError("Invalid virtual page number")
|
||||||
|
for level in range(self.arch.LEVELS - 1, -1, -1):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def assembly(self):
|
||||||
|
entries = list(sorted(self.table.items(), key=lambda item: item[0]))
|
||||||
|
current_index = 0
|
||||||
|
asm = f".balign {self.arch.PGSIZE}\n{self.name}:\n"
|
||||||
|
for entry in entries:
|
||||||
|
vpn_index, (pte, _) = entry
|
||||||
|
if current_index < vpn_index:
|
||||||
|
asm += f" .fill {vpn_index - current_index}, {self.arch.PTESIZE}, 0\n"
|
||||||
|
asm += f" .4byte {str(pte)}\n"
|
||||||
|
current_index = vpn_index + 1
|
||||||
|
if current_index < self.arch.NPTENTRIES:
|
||||||
|
asm += f" .fill {self.arch.NPTENTRIES - current_index}, {self.arch.PTESIZE}, 0\n"
|
||||||
|
return asm
|
||||||
|
|
||||||
|
##################################
|
||||||
|
# functions
|
||||||
|
##################################
|
||||||
|
|
Loading…
Reference in New Issue
Block a user