Merge branch 'cache' into main

This commit is contained in:
Jarred Allen 2021-03-30 12:56:19 -04:00
commit 108f18e580
12 changed files with 454 additions and 142 deletions

View File

@ -45,13 +45,15 @@ add wave /testbench_busybear/reset
add wave -divider add wave -divider
add wave -hex /testbench_busybear/PCtext add wave -hex /testbench_busybear/PCtext
add wave -hex /testbench_busybear/pcExpected add wave -hex /testbench_busybear/pcExpected
add wave -hex /testbench_busybear/dut/hart/ifu/PCF add wave -hex /testbench_busybear/dut/hart/ifu/PCD
add wave -hex /testbench_busybear/dut/hart/ifu/InstrF add wave -hex /testbench_busybear/dut/hart/ifu/InstrD
add wave -hex /testbench_busybear/dut/hart/ifu/StallD add wave -hex /testbench_busybear/dut/hart/ifu/StallD
add wave -hex /testbench_busybear/dut/hart/ifu/FlushD add wave -hex /testbench_busybear/dut/hart/ifu/FlushD
add wave -hex /testbench_busybear/dut/hart/ifu/StallE
add wave -hex /testbench_busybear/dut/hart/ifu/FlushE
add wave -hex /testbench_busybear/dut/hart/ifu/InstrRawD add wave -hex /testbench_busybear/dut/hart/ifu/InstrRawD
add wave /testbench_busybear/CheckInstrF add wave /testbench_busybear/CheckInstrD
add wave /testbench_busybear/lastCheckInstrF add wave /testbench_busybear/lastCheckInstrD
add wave /testbench_busybear/speculative add wave /testbench_busybear/speculative
add wave /testbench_busybear/lastPC2 add wave /testbench_busybear/lastPC2
add wave -divider add wave -divider

View File

@ -42,7 +42,7 @@ vsim workopt
view wave view wave
-- display input and output signals as hexidecimal values -- display input and output signals as hexidecimal values
do ./wave-dos/default-waves.do do ./wave-dos/ahb-waves.do
-- Set Wave Output Items -- Set Wave Output Items
TreeUpdate [SetDefaultTree] TreeUpdate [SetDefaultTree]

View File

@ -14,14 +14,21 @@ 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 /testbench/InstrFName
add wave -hex /testbench/dut/hart/ifu/PCD 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 -hex /testbench/dut/hart/ifu/ic/InstrRawD
add wave -hex /testbench/dut/hart/ifu/ic/AlignedInstrD
add wave -divider
add wave -hex /testbench/dut/hart/ifu/ic/InstrPAdrF
add wave /testbench/dut/hart/ifu/ic/DelayF
add wave /testbench/dut/hart/ifu/ic/DelaySideF
add wave /testbench/dut/hart/ifu/ic/DelayD
add wave -hex /testbench/dut/hart/ifu/ic/MisalignedHalfInstrD
add wave -divider add wave -divider
add wave -hex /testbench/dut/hart/ifu/PCE add wave -hex /testbench/dut/hart/ifu/PCE
@ -55,8 +62,11 @@ add wave -hex /testbench/dut/hart/ebu/CaptureDataM
add wave -hex /testbench/dut/hart/ebu/InstrStall add wave -hex /testbench/dut/hart/ebu/InstrStall
add wave -divider add wave -divider
add wave -hex /testbench/PCW add wave -hex /testbench/dut/uncore/dtim/*
add wave -hex /testbench/InstrW add wave -divider
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 /testbench/dut/hart/ieu/dp/RegWriteW
add wave -hex /testbench/dut/hart/ebu/ReadDataW add wave -hex /testbench/dut/hart/ebu/ReadDataW
@ -67,4 +77,4 @@ add wave -divider
add wave -hex /testbench/dut/uncore/dtim/* add wave -hex /testbench/dut/uncore/dtim/*
add wave -divider add wave -divider
add wave -hex -r /testbench/* add wave -hex -r /testbench/*

View File

@ -19,11 +19,15 @@ 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 /testbench/InstrFName
add wave -hex /testbench/dut/hart/ifu/PCD 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 -hex /testbench/dut/hart/ifu/ic/InstrRawD
add wave -hex /testbench/dut/hart/ifu/ic/AlignedInstrD
add wave /testbench/dut/hart/ifu/ic/DelayF
add wave /testbench/dut/hart/ifu/ic/DelaySideF
add wave /testbench/dut/hart/ifu/ic/DelayD
add wave -hex /testbench/dut/hart/ifu/ic/MisalignedHalfInstrD
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
@ -48,4 +52,4 @@ add wave -hex /testbench/dut/hart/ieu/dp/ResultW
add wave -hex /testbench/dut/hart/ieu/dp/RdW add wave -hex /testbench/dut/hart/ieu/dp/RdW
add wave -divider add wave -divider
#add ww #add ww
add wave -hex -r /testbench/* add wave -hex -r /testbench/*

93
wally-pipelined/src/cache/dmapped.sv vendored Normal file
View File

@ -0,0 +1,93 @@
///////////////////////////////////////////
// dmapped.sv
//
// Written: jaallen@g.hmc.edu 2021-03-23
// Modified:
//
// Purpose: An implementation of a direct-mapped cache memory
// This cache is read-only, so "write"s to the memory are loading new data
//
// 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"
module rodirectmappedmem #(parameter LINESIZE = 256, parameter NUMLINES = 512, parameter WORDSIZE = `XLEN) (
// Pipeline stuff
input logic clk,
input logic reset,
// If flush is high, invalidate the entire cache
input logic flush,
// Select which address to read (broken for efficiency's sake)
input logic [`XLEN-1:12] ReadUpperPAdr,
input logic [11:0] ReadLowerAdr,
// Write new data to the cache
input logic WriteEnable,
input logic [LINESIZE-1:0] WriteLine,
input logic [`XLEN-1:0] WritePAdr,
// Output the word, as well as if it is valid
output logic [WORDSIZE-1:0] DataWord,
output logic DataValid
);
localparam integer SETWIDTH = $clog2(NUMLINES);
localparam integer OFFSETWIDTH = $clog2(LINESIZE/8);
localparam integer TAGWIDTH = `XLEN-SETWIDTH-OFFSETWIDTH;
logic [NUMLINES-1:0][WORDSIZE-1:0] LineOutputs;
logic [NUMLINES-1:0] ValidOutputs;
logic [NUMLINES-1:0][TAGWIDTH-1:0] TagOutputs;
logic [OFFSETWIDTH-1:0] WordSelect;
logic [`XLEN-1:0] ReadPAdr;
logic [SETWIDTH-1:0] ReadSet, WriteSet;
logic [TAGWIDTH-1:0] ReadTag, WriteTag;
// Swizzle bits to get the offset, set, and tag out of the read and write addresses
always_comb begin
// Read address
assign WordSelect = ReadLowerAdr[OFFSETWIDTH-1:0];
assign ReadPAdr = {ReadUpperPAdr, ReadLowerAdr};
assign ReadSet = ReadPAdr[SETWIDTH+OFFSETWIDTH-1:OFFSETWIDTH];
assign ReadTag = ReadPAdr[`XLEN-1:SETWIDTH+OFFSETWIDTH];
// Write address
assign WriteSet = WritePAdr[SETWIDTH+OFFSETWIDTH-1:OFFSETWIDTH];
assign WriteTag = WritePAdr[`XLEN-1:SETWIDTH+OFFSETWIDTH];
end
genvar i;
generate
for (i=0; i < NUMLINES; i++) begin
rocacheline #(LINESIZE, TAGWIDTH, WORDSIZE) lines (
.*,
.WriteEnable(WriteEnable & (WriteSet == i)),
.WriteData(WriteLine),
.WriteTag(WriteTag),
.DataWord(LineOutputs[i]),
.DataTag(TagOutputs[i]),
.DataValid(ValidOutputs[i])
);
end
endgenerate
// Get the data and valid out of the lines
always_comb begin
assign DataWord = LineOutputs[ReadSet];
assign DataValid = ValidOutputs[ReadSet] & (TagOutputs[ReadSet] == ReadTag);
end
endmodule

68
wally-pipelined/src/cache/line.sv vendored Normal file
View File

@ -0,0 +1,68 @@
///////////////////////////////////////////
// line.sv
//
// Written: jaallen@g.hmc.edu 2021-03-23
// Modified:
//
// Purpose: An implementation of a single cache line
//
// 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"
// A read-only cache line ("write"ing to this line is loading new data, not writing to memory
module rocacheline #(parameter LINESIZE = 256, parameter TAGSIZE = 32, parameter WORDSIZE = `XLEN) (
// Pipeline stuff
input logic clk,
input logic reset,
// If flush is high, invalidate this word
input logic flush,
// Select which word within the line
input logic [$clog2(LINESIZE/8)-1:0] WordSelect,
// Write new data to the line
input logic WriteEnable,
input logic [LINESIZE-1:0] WriteData,
input logic [TAGSIZE-1:0] WriteTag,
// Output the word, as well as the tag and if it is valid
output logic [WORDSIZE-1:0] DataWord,
output logic [TAGSIZE-1:0] DataTag,
output logic DataValid
);
localparam integer OFFSETSIZE = $clog2(LINESIZE/8);
localparam integer NUMWORDS = LINESIZE/WORDSIZE;
logic [NUMWORDS-1:0][WORDSIZE-1:0] DataLinesIn, DataLinesOut;
flopenr #(1) ValidBitFlop(clk, reset, WriteEnable | flush, ~flush, DataValid);
flopenr #(TAGSIZE) TagFlop(clk, reset, WriteEnable, WriteTag, DataTag);
genvar i;
generate
for (i=0; i < NUMWORDS; i++) begin
assign DataLinesIn[i] = WriteData[NUMWORDS*i+WORDSIZE-1:NUMWORDS*i];
flopenr #(LINESIZE) LineFlop(clk, reset, WriteEnable, DataLinesIn[i], DataLinesOut[i]);
end
endgenerate
always_comb begin
assign DataWord = DataLinesOut[WordSelect[OFFSETSIZE-1:$clog2(WORDSIZE)]];
end
endmodule

View File

@ -29,7 +29,7 @@ module hazard(
// Detect hazards // Detect hazards
input logic BPPredWrongE, CSRWritePendingDEM, RetM, TrapM, input logic BPPredWrongE, CSRWritePendingDEM, RetM, TrapM,
input logic LoadStallD, MulDivStallD, CSRRdStallD, input logic LoadStallD, MulDivStallD, CSRRdStallD,
input logic InstrStall, DataStall, input logic InstrStall, DataStall, ICacheStallF,
// Stall & flush outputs // Stall & flush outputs
output logic StallF, StallD, StallE, StallM, StallW, output logic StallF, StallD, StallE, StallM, StallW,
output logic FlushF, FlushD, FlushE, FlushM, FlushW output logic FlushF, FlushD, FlushE, FlushM, FlushW

View File

@ -0,0 +1,138 @@
///////////////////////////////////////////
// icache.sv
//
// Written: jaallen@g.hmc.edu 2021-03-02
// Modified:
//
// Purpose: Cache instructions for the ifu so it can access memory less often, saving cycles
//
// 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"
module icache(
// Basic pipeline stuff
input logic clk, reset,
input logic StallF, StallD,
input logic FlushD,
// Upper bits of physical address for PC
input logic [`XLEN-1:12] UpperPCPF,
// Lower 12 bits of virtual PC address, since it's faster this way
input logic [11:0] LowerPCF,
// Data read in from the ebu unit
input logic [`XLEN-1:0] InstrInF,
// Read requested from the ebu unit
output logic [`XLEN-1:0] InstrPAdrF,
output logic InstrReadF,
// High if the instruction currently in the fetch stage is compressed
output logic CompressedF,
// High if the icache is requesting a stall
output logic ICacheStallF,
// The raw (not decompressed) instruction that was requested
// If the next instruction is compressed, the upper 16 bits may be anything
output logic [31:0] InstrRawD
);
logic DelayF, DelaySideF, FlushDLastCyclen, DelayD;
logic [1:0] InstrDMuxChoice;
logic [15:0] MisalignedHalfInstrF, MisalignedHalfInstrD;
logic [31:0] InstrF, AlignedInstrD;
// Buffer the last read, for ease of accessing it again
logic LastReadDataValidF;
logic [`XLEN-1:0] LastReadDataF, LastReadAdrF, InDataF;
// instruction for NOP
logic [31:0] nop = 32'h00000013;
// Temporary change to bridge the new interface to old behaviors
logic [`XLEN-1:0] PCPF;
assign PCPF = {UpperPCPF, LowerPCF};
// This flop doesn't stall if StallF is high because we should output a nop
// when FlushD happens, even if the pipeline is also stalled.
flopr #(1) flushDLastCycleFlop(clk, reset, ~FlushD & (FlushDLastCyclen | ~StallF), FlushDLastCyclen);
flopenr #(1) delayDFlop(clk, reset, ~StallF, DelayF & ~CompressedF, DelayD);
flopenrc#(1) delayStateFlop(clk, reset, FlushD, ~StallF, DelayF & ~DelaySideF, DelaySideF);
// This flop stores the first half of a misaligned instruction while waiting for the other half
flopenr #(16) halfInstrFlop(clk, reset, DelayF & ~StallF, MisalignedHalfInstrF, MisalignedHalfInstrD);
// This flop is here to simulate pulling data out of the cache, which is edge-triggered
flopenr #(32) instrFlop(clk, reset, ~StallF, InstrF, AlignedInstrD);
// These flops cache the previous read, to accelerate things
flopenr #(`XLEN) lastReadDataFlop(clk, reset, InstrReadF & ~StallF, InstrInF, LastReadDataF);
flopenr #(1) lastReadDataVFlop(clk, reset, InstrReadF & ~StallF, 1'b1, LastReadDataValidF);
flopenr #(`XLEN) lastReadAdrFlop(clk, reset, InstrReadF & ~StallF, InstrPAdrF, LastReadAdrF);
// Decide which address needs to be fetched and sent out over InstrPAdrF
// If the requested address fits inside one read from memory, we fetch that
// address, adjusted to the bit width. Otherwise, we request the lower word
// and then the upper word, in that order.
generate
if (`XLEN == 32) begin
assign InstrPAdrF = PCPF[1] ? ((DelaySideF & ~CompressedF) ? {PCPF[31:2], 2'b00} : {PCPF[31:2], 2'b00}) : PCPF;
end else begin
assign InstrPAdrF = PCPF[2] ? (PCPF[1] ? ((DelaySideF & ~CompressedF) ? {PCPF[63:3]+1, 3'b000} : {PCPF[63:3], 3'b000}) : {PCPF[63:3], 3'b000}) : {PCPF[63:3], 3'b000};
end
endgenerate
// Read from memory if we don't have the address we want
always_comb if (LastReadDataValidF & (InstrPAdrF == LastReadAdrF)) begin
assign InstrReadF = 0;
end else begin
assign InstrReadF = 1;
end
// Pick from the memory input or from the previous read, as appropriate
mux2 #(`XLEN) inDataMux(LastReadDataF, InstrInF, InstrReadF, InDataF);
// If the instruction fits in one memory read, then we put the right bits
// into InstrF. Otherwise, we activate DelayF to signal the rest of the
// machinery to swizzle bits.
generate
if (`XLEN == 32) begin
assign InstrF = PCPF[1] ? {16'b0, InDataF[31:16]} : InDataF;
assign DelayF = PCPF[1];
assign MisalignedHalfInstrF = InDataF[31:16];
end else begin
assign InstrF = PCPF[2] ? (PCPF[1] ? {16'b0, InDataF[63:48]} : InDataF[63:32]) : (PCPF[1] ? InDataF[47:16] : InDataF[31:0]);
assign DelayF = PCPF[1] && PCPF[2];
assign MisalignedHalfInstrF = InDataF[63:48];
end
endgenerate
// We will likely need to stall later, but stalls are handled by the rest of the pipeline for now
assign ICacheStallF = 0;
// Detect if the instruction is compressed
assign CompressedF = InstrF[1:0] != 2'b11;
// Pick the correct output, depending on whether we have to assemble this
// instruction from two reads or not.
// Output the requested instruction (we don't need to worry if the read is
// incomplete, since the pipeline stalls for us when it isn't), or a NOP for
// the cycle when the first of two reads comes in.
always_comb if (~FlushDLastCyclen) begin
assign InstrDMuxChoice = 2'b10;
end else if (DelayD & (MisalignedHalfInstrD[1:0] != 2'b11)) begin
assign InstrDMuxChoice = 2'b11;
end else begin
assign InstrDMuxChoice = {1'b0, DelayD};
end
mux4 #(32) instrDMux (AlignedInstrD, {InstrInF[15:0], MisalignedHalfInstrD}, nop, {16'b0, MisalignedHalfInstrD}, InstrDMuxChoice, InstrRawD);
endmodule

View File

@ -2,7 +2,7 @@
// ifu.sv // ifu.sv
// //
// Written: David_Harris@hmc.edu 9 January 2021 // Written: David_Harris@hmc.edu 9 January 2021
// Modified: // Modified:
// //
// Purpose: Instrunction Fetch Unit // Purpose: Instrunction Fetch Unit
// PC, branch prediction, instruction cache // PC, branch prediction, instruction cache
@ -35,6 +35,7 @@ module ifu (
output logic [`XLEN-1:0] PCF, output logic [`XLEN-1:0] PCF,
output logic [`XLEN-1:0] InstrPAdrF, output logic [`XLEN-1:0] InstrPAdrF,
output logic InstrReadF, output logic InstrReadF,
output logic ICacheStallF,
// Decode // Decode
// Execute // Execute
output logic [`XLEN-1:0] PCLinkE, output logic [`XLEN-1:0] PCLinkE,
@ -61,27 +62,25 @@ module ifu (
input logic [`XLEN-1:0] PageTableEntryF, input logic [`XLEN-1:0] PageTableEntryF,
input logic [`XLEN-1:0] SATP_REGW, input logic [`XLEN-1:0] SATP_REGW,
input logic ITLBWriteF, // ITLBFlushF, input logic ITLBWriteF, // ITLBFlushF,
output logic ITLBMissF, ITLBHitF, output logic ITLBMissF, ITLBHitF
// bogus
input logic [15:0] rd2
); );
logic [`XLEN-1:0] UnalignedPCNextF, PCNextF; logic [`XLEN-1:0] UnalignedPCNextF, PCNextF;
logic misaligned, BranchMisalignedFaultE, BranchMisalignedFaultM, TrapMisalignedFaultM; logic misaligned, BranchMisalignedFaultE, BranchMisalignedFaultM, TrapMisalignedFaultM;
logic PrivilegedChangePCM; logic PrivilegedChangePCM;
logic IllegalCompInstrD; logic IllegalCompInstrD;
logic [`XLEN-1:0] PCPlusUpperF, PCPlus2or4F, PCD, PCLinkD, PCLinkM; logic [`XLEN-1:0] PCPlusUpperF, PCPlus2or4F, PCD, PCW, PCLinkD, PCLinkM, PCPF;
logic CompressedF; logic CompressedF;
logic [31:0] InstrF, InstrRawD, InstrE; logic [31:0] InstrRawD, InstrE, InstrW;
logic [31:0] nop = 32'h00000013; // instruction for NOP logic [31:0] nop = 32'h00000013; // instruction for NOP
logic [`XLEN-1:0] ITLBInstrPAdrF, ICacheInstrPAdrF;
// *** temporary hack until walker is hooked up -- Thomas F // *** temporary hack until walker is hooked up -- Thomas F
// logic [`XLEN-1:0] PageTableEntryF = '0; // logic [`XLEN-1:0] PageTableEntryF = '0;
logic ITLBFlushF = '0; logic ITLBFlushF = '0;
// logic ITLBWriteF = '0; // logic ITLBWriteF = '0;
tlb #(3) itlb(clk, reset, SATP_REGW, PrivilegeModeW, PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF, tlb #(3) itlb(clk, reset, SATP_REGW, PrivilegeModeW, PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF,
InstrPAdrF, ITLBMissF, ITLBHitF); ITLBInstrPAdrF, ITLBMissF, ITLBHitF);
// branch predictor signals // branch predictor signals
logic SelBPPredF; logic SelBPPredF;
@ -92,11 +91,21 @@ module ifu (
// *** 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
// jarred 2021-03-14 Add instrution cache block to remove rd2
assign PCPF = PCF; // Temporary workaround until iTLB is live
icache ic(
.*,
.InstrPAdrF(ICacheInstrPAdrF),
.UpperPCPF(PCPF[`XLEN-1:12]),
.LowerPCF(PCF[11:0])
);
// Prioritize the iTLB for reads if it wants one
mux2 #(`XLEN) instrPAdrMux(ICacheInstrPAdrF, ITLBInstrPAdrF, ITLBMissF, InstrPAdrF);
assign PrivilegedChangePCM = RetM | TrapM; assign PrivilegedChangePCM = RetM | TrapM;
//mux3 #(`XLEN) pcmux(PCPlus2or4F, PCCorrectE, PrivilegedNextPCM, {PrivilegedChangePCM, BPPredWrongE}, UnalignedPCNextF); //mux3 #(`XLEN) pcmux(PCPlus2or4F, PCCorrectE, PrivilegedNextPCM, {PrivilegedChangePCM, BPPredWrongE}, UnalignedPCNextF);
mux2 #(`XLEN) pcmux0(.d0(PCPlus2or4F), mux2 #(`XLEN) pcmux0(.d0(PCPlus2or4F),
.d1(BPPredPCF), .d1(BPPredPCF),
@ -114,7 +123,7 @@ module ifu (
.y(UnalignedPCNextF)); .y(UnalignedPCNextF));
assign PCNextF = {UnalignedPCNextF[`XLEN-1:1], 1'b0}; // hart-SPEC p. 21 about 16-bit alignment assign PCNextF = {UnalignedPCNextF[`XLEN-1:1], 1'b0}; // hart-SPEC p. 21 about 16-bit alignment
flopenl #(`XLEN) pcreg(clk, reset, ~StallF, PCNextF, `RESET_VECTOR, PCF); flopenl #(`XLEN) pcreg(clk, reset, ~StallF & ~ICacheStallF, PCNextF, `RESET_VECTOR, PCF);
// branch and jump predictor // branch and jump predictor
// I am making the port connection explicit for now as I want to see them and they will be changing. // I am making the port connection explicit for now as I want to see them and they will be changing.
@ -141,9 +150,7 @@ module ifu (
// pcadder // pcadder
// add 2 or 4 to the PC, based on whether the instruction is 16 bits or 32 // add 2 or 4 to the PC, based on whether the instruction is 16 bits or 32
assign CompressedF = (InstrF[1:0] != 2'b11); // is it a 16-bit compressed instruction?
assign PCPlusUpperF = PCF[`XLEN-1:2] + 1; // add 4 to PC assign PCPlusUpperF = PCF[`XLEN-1:2] + 1; // add 4 to PC
// choose PC+2 or PC+4 // choose PC+2 or PC+4
always_comb always_comb
if (CompressedF) // add 2 if (CompressedF) // add 2
@ -151,18 +158,7 @@ module ifu (
else PCPlus2or4F = {PCF[`XLEN-1:2], 2'b10}; else PCPlus2or4F = {PCF[`XLEN-1:2], 2'b10};
else PCPlus2or4F = {PCPlusUpperF, PCF[1:0]}; // add 4 else PCPlus2or4F = {PCPlusUpperF, PCF[1:0]}; // add 4
// harris 2/23/21 Add code to fetch instruction split across two words
generate
if (`XLEN==32) begin
assign InstrF = PCF[1] ? {rd2[15:0], InstrInF[31:16]} : InstrInF;
end else begin
assign InstrF = PCF[2] ? (PCF[1] ? {rd2[15:0], InstrInF[63:48]} : InstrInF[63:32])
: (PCF[1] ? InstrInF[47:16] : InstrInF[31:0]);
end
endgenerate
// Decode stage pipeline register and logic // Decode stage pipeline register and logic
flopenl #(32) InstrDReg(clk, reset, ~StallD | FlushD, (FlushD ? nop : InstrF), nop, InstrRawD);
flopenrc #(`XLEN) PCDReg(clk, reset, FlushD, ~StallD, PCF, PCD); flopenrc #(`XLEN) PCDReg(clk, reset, FlushD, ~StallD, PCF, PCD);
// expand 16-bit compressed instructions to 32 bits // expand 16-bit compressed instructions to 32 bits

View File

@ -98,6 +98,8 @@ module wallypipelinedhart (
logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM; logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM;
// IMem stalls
logic ICacheStallF;
logic [`XLEN-1:0] MMUPAdr, MMUReadPTE; logic [`XLEN-1:0] MMUPAdr, MMUReadPTE;
logic MMUTranslate, MMUTranslationComplete, MMUReady; logic MMUTranslate, MMUTranslationComplete, MMUReady;

View File

@ -7,7 +7,7 @@ module testbench_busybear();
logic [31:0] GPIOPinsOut, GPIOPinsEn; logic [31:0] GPIOPinsOut, GPIOPinsEn;
// instantiate device to be tested // instantiate device to be tested
logic [31:0] CheckInstrF; logic [31:0] CheckInstrD;
logic [`AHBW-1:0] HRDATA; logic [`AHBW-1:0] HRDATA;
logic [31:0] HADDR; logic [31:0] HADDR;
@ -194,8 +194,8 @@ module testbench_busybear();
logic [`XLEN-1:0] readAdrExpected; logic [`XLEN-1:0] readAdrExpected;
always @(dut.HRDATA) begin always @(dut.HRDATA) begin
#1; #2;
if (dut.hart.MemRWM[1] && ~HWRITE && HADDR != dut.PCF && dut.HRDATA !== {64{1'bx}}) begin if (dut.hart.MemRWM[1] && ~HWRITE && HADDR[31:3] != dut.PCF[31:3] && dut.HRDATA !== {64{1'bx}}) begin
//$display("%0t", $time); //$display("%0t", $time);
if($feof(data_file_memR)) begin if($feof(data_file_memR)) begin
$display("no more memR data to read"); $display("no more memR data to read");
@ -265,7 +265,7 @@ module testbench_busybear();
end end
always @(dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW) begin always @(dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW) begin
if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 2 && instrs != 0) begin if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 2 && instrs > 1) begin
$display("!!!!!! illegal instruction !!!!!!!!!!"); $display("!!!!!! illegal instruction !!!!!!!!!!");
$display("(as a reminder, MCAUSE and MEPC are set by this)"); $display("(as a reminder, MCAUSE and MEPC are set by this)");
$display("at %0t ps, instr %0d, HADDR %x", $time, instrs, HADDR); $display("at %0t ps, instr %0d, HADDR %x", $time, instrs, HADDR);
@ -337,7 +337,7 @@ module testbench_busybear();
`CHECK_CSR(STVEC) `CHECK_CSR(STVEC)
initial begin //this is temporary until the bug can be fixed!!! initial begin //this is temporary until the bug can be fixed!!!
#18909760; #11130100;
force dut.hart.ieu.dp.regf.rf[5] = 64'h0000000080000004; force dut.hart.ieu.dp.regf.rf[5] = 64'h0000000080000004;
#100; #100;
release dut.hart.ieu.dp.regf.rf[5]; release dut.hart.ieu.dp.regf.rf[5];
@ -347,7 +347,7 @@ module testbench_busybear();
initial begin initial begin
speculative = 0; speculative = 0;
end end
logic [63:0] lastCheckInstrF, lastPC, lastPC2; logic [63:0] lastCheckInstrD, lastPC, lastPC2;
string PCtextW, PCtext2W; string PCtextW, PCtext2W;
logic [31:0] InstrWExpected; logic [31:0] InstrWExpected;
@ -382,102 +382,102 @@ module testbench_busybear();
end end
logic [31:0] InstrMask; logic [31:0] InstrMask;
logic forcedInstr; logic forcedInstr;
logic [63:0] lastPCF; logic [63:0] lastPCD;
always @(dut.PCF or dut.hart.ifu.InstrF or reset) begin always @(dut.hart.ifu.PCD or dut.hart.ifu.InstrRawD or reset or negedge dut.hart.ifu.StallE) begin
if(~HWRITE) begin if(~HWRITE) begin
#3; #2;
if (~reset && dut.hart.ifu.InstrF[15:0] !== {16{1'bx}} && ~dut.hart.StallD) begin if (~reset && dut.hart.ifu.InstrRawD[15:0] !== {16{1'bx}} && dut.hart.ifu.PCD !== 64'h0 && ~dut.hart.ifu.StallE) begin
if (dut.PCF !== lastPCF) begin if (dut.hart.ifu.PCD !== lastPCD) begin
lastCheckInstrF = CheckInstrF; lastCheckInstrD = CheckInstrD;
lastPC <= dut.PCF; lastPC <= dut.hart.ifu.PCD;
lastPC2 <= lastPC; lastPC2 <= lastPC;
if (speculative && (lastPC != pcExpected)) begin if (speculative && (lastPC != pcExpected)) begin
speculative = ~equal(dut.PCF,pcExpected,3); speculative = ~equal(dut.hart.ifu.PCD,pcExpected,3);
if(dut.PCF===pcExpected) begin if(dut.hart.ifu.PCD===pcExpected) begin
if(dut.hart.ifu.InstrF[6:0] == 7'b1010011) begin // for now, NOP out any float instrs if(dut.hart.ifu.InstrRawD[6:0] == 7'b1010011) begin // for now, NOP out any float instrs
force CheckInstrF = 32'b0010011; force CheckInstrD = 32'b0010011;
release CheckInstrF; release CheckInstrD;
force dut.hart.ifu.InstrF = 32'b0010011; force dut.hart.ifu.InstrRawD = 32'b0010011;
#7; #7;
release dut.hart.ifu.InstrF; release dut.hart.ifu.InstrRawD;
$display("warning: NOPing out %s at PC=%0x, instr %0d, time %0t", PCtext, dut.PCF, instrs, $time); $display("warning: NOPing out %s at PC=%0x, instr %0d, time %0t", PCtext, dut.hart.ifu.PCD, instrs, $time);
warningCount += 1; warningCount += 1;
forcedInstr = 1; forcedInstr = 1;
end end
else begin else begin
forcedInstr = 0; forcedInstr = 0;
end
end end
end end
end else begin
else begin if($feof(data_file_PC)) begin
if($feof(data_file_PC)) begin $display("no more PC data to read");
$display("no more PC data to read"); `ERROR
`ERROR
end
scan_file_PC = $fscanf(data_file_PC, "%s\n", PCtext);
if (PCtext != "ret" && PCtext != "fence" && PCtext != "nop" && PCtext != "mret" && PCtext != "sfence.vma" && PCtext != "unimp") begin
scan_file_PC = $fscanf(data_file_PC, "%s\n", PCtext2);
PCtext = {PCtext, " ", PCtext2};
end
scan_file_PC = $fscanf(data_file_PC, "%x\n", CheckInstrF);
if(dut.PCF === pcExpected) begin
if(dut.hart.ifu.InstrF[6:0] == 7'b1010011) begin // for now, NOP out any float instrs
force CheckInstrF = 32'b0010011;
release CheckInstrF;
force dut.hart.ifu.InstrF = 32'b0010011;
#7;
release dut.hart.ifu.InstrF;
$display("warning: NOPing out %s at PC=%0x, instr %0d, time %0t", PCtext, dut.PCF, instrs, $time);
warningCount += 1;
forcedInstr = 1;
end end
else begin scan_file_PC = $fscanf(data_file_PC, "%s\n", PCtext);
forcedInstr = 0; if (PCtext != "ret" && PCtext != "fence" && PCtext != "nop" && PCtext != "mret" && PCtext != "sfence.vma" && PCtext != "unimp") begin
scan_file_PC = $fscanf(data_file_PC, "%s\n", PCtext2);
PCtext = {PCtext, " ", PCtext2};
end end
end scan_file_PC = $fscanf(data_file_PC, "%x\n", CheckInstrD);
// then expected PC value if(dut.hart.ifu.PCD === pcExpected) begin
scan_file_PC = $fscanf(data_file_PC, "%x\n", pcExpected); if(dut.hart.ifu.InstrRawD[6:0] == 7'b1010011) begin // for now, NOP out any float instrs
if (instrs <= 10 || (instrs <= 100 && instrs % 10 == 0) || force CheckInstrD = 32'b0010011;
(instrs <= 1000 && instrs % 100 == 0) || (instrs <= 10000 && instrs % 1000 == 0) || release CheckInstrD;
(instrs <= 100000 && instrs % 10000 == 0) || (instrs <= 1000000 && instrs % 100000 == 0)) begin force dut.hart.ifu.InstrRawD = 32'b0010011;
$display("loaded %0d instructions", instrs); #7;
end release dut.hart.ifu.InstrRawD;
instrs += 1; $display("warning: NOPing out %s at PC=%0x, instr %0d, time %0t", PCtext, dut.hart.ifu.PCD, instrs, $time);
// are we at a branch/jump? warningCount += 1;
casex (lastCheckInstrF[31:0]) forcedInstr = 1;
32'b00000000001000000000000001110011, // URET end
32'b00010000001000000000000001110011, // SRET else begin
32'b00110000001000000000000001110011, // MRET forcedInstr = 0;
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1101111, // JAL end
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1100111, // JALR end
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1100011, // B // then expected PC value
32'bXXXXXXXXXXXXXXXX110XXXXXXXXXXX01, // C.BEQZ scan_file_PC = $fscanf(data_file_PC, "%x\n", pcExpected);
32'bXXXXXXXXXXXXXXXX111XXXXXXXXXXX01, // C.BNEZ if (instrs <= 10 || (instrs <= 100 && instrs % 10 == 0) ||
32'bXXXXXXXXXXXXXXXX101XXXXXXXXXXX01: // C.J (instrs <= 1000 && instrs % 100 == 0) || (instrs <= 10000 && instrs % 1000 == 0) ||
speculative = 1; (instrs <= 100000 && instrs % 10000 == 0) || (instrs <= 1000000 && instrs % 100000 == 0)) begin
32'bXXXXXXXXXXXXXXXX1001000000000010: // C.EBREAK: $display("loaded %0d instructions", instrs);
speculative = 0; // tbh don't really know what should happen here end
32'bXXXXXXXXXXXXXXXX1000XXXXX0000010, // C.JR instrs += 1;
32'bXXXXXXXXXXXXXXXX1001XXXXX0000010: // C.JALR //this is RV64 only so no C.JAL // are we at a branch/jump?
speculative = 1; casex (lastCheckInstrD[31:0])
default: 32'b00000000001000000000000001110011, // URET
speculative = 0; 32'b00010000001000000000000001110011, // SRET
endcase 32'b00110000001000000000000001110011, // MRET
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1101111, // JAL
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1100111, // JALR
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1100011, // B
32'bXXXXXXXXXXXXXXXX110XXXXXXXXXXX01, // C.BEQZ
32'bXXXXXXXXXXXXXXXX111XXXXXXXXXXX01, // C.BNEZ
32'bXXXXXXXXXXXXXXXX101XXXXXXXXXXX01: // C.J
speculative = 1;
32'bXXXXXXXXXXXXXXXX1001000000000010: // C.EBREAK:
speculative = 0; // tbh don't really know what should happen here
32'bXXXXXXXXXXXXXXXX1000XXXXX0000010, // C.JR
32'bXXXXXXXXXXXXXXXX1001XXXXX0000010: // C.JALR //this is RV64 only so no C.JAL
speculative = 1;
default:
speculative = 0;
endcase
//check things! //check things!
if ((~speculative) && (~equal(dut.PCF,pcExpected,3))) begin if ((~speculative) && (~equal(dut.hart.ifu.PCD,pcExpected,3))) begin
$display("%0t ps, instr %0d: PC does not equal PC expected: %x, %x", $time, instrs, dut.PCF, pcExpected); $display("%0t ps, instr %0d: PC does not equal PC expected: %x, %x", $time, instrs, dut.hart.ifu.PCD, pcExpected);
`ERROR `ERROR
end end
InstrMask = CheckInstrF[1:0] == 2'b11 ? 32'hFFFFFFFF : 32'h0000FFFF; InstrMask = CheckInstrD[1:0] == 2'b11 ? 32'hFFFFFFFF : 32'h0000FFFF;
if ((~forcedInstr) && (~speculative) && ((InstrMask & dut.hart.ifu.InstrF) !== (InstrMask & CheckInstrF))) begin if ((~forcedInstr) && (~speculative) && ((InstrMask & dut.hart.ifu.InstrRawD) !== (InstrMask & CheckInstrD))) begin
$display("%0t ps, instr %0d: InstrF does not equal CheckInstrF: %x, %x, PC: %x", $time, instrs, dut.hart.ifu.InstrF, CheckInstrF, dut.PCF); $display("%0t ps, instr %0d: InstrD does not equal CheckInstrD: %x, %x, PC: %x", $time, instrs, dut.hart.ifu.InstrRawD, CheckInstrD, dut.hart.ifu.PCD);
`ERROR `ERROR
end
end end
end end
lastPCD = dut.hart.ifu.PCD;
end end
lastPCF = dut.PCF;
end
end end
end end
@ -485,7 +485,7 @@ module testbench_busybear();
string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName;
logic [31:0] InstrW; logic [31:0] InstrW;
flopenr #(32) InstrWReg(clk, reset, ~dut.hart.ieu.dp.StallW, dut.hart.ifu.InstrM, InstrW); flopenr #(32) InstrWReg(clk, reset, ~dut.hart.ieu.dp.StallW, dut.hart.ifu.InstrM, InstrW);
instrNameDecTB dec(dut.hart.ifu.InstrF, InstrFName); instrNameDecTB dec(dut.hart.ifu.ic.InstrF, InstrFName);
instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE, instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE,
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, InstrW,

View File

@ -65,7 +65,6 @@ module testbench();
// "rv64m/I-REMW-01", "3000" // "rv64m/I-REMW-01", "3000"
}; };
string tests64ic[] = '{ string tests64ic[] = '{
"rv64ic/I-C-ADD-01", "3000", "rv64ic/I-C-ADD-01", "3000",
"rv64ic/I-C-ADDI-01", "3000", "rv64ic/I-C-ADDI-01", "3000",
"rv64ic/I-C-ADDIW-01", "3000", "rv64ic/I-C-ADDIW-01", "3000",
@ -381,9 +380,9 @@ string tests32i[] = {
// 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.ic.InstrF, dut.hart.ifu.InstrD, dut.hart.ifu.InstrE,
dut.hart.ifu.InstrM, InstrW, dut.hart.ifu.InstrM, InstrW, InstrFName, InstrDName,
InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); InstrEName, InstrMName, InstrWName);
// initialize tests // initialize tests
initial initial