diff --git a/src/ebu/ebufsmarb.sv b/src/ebu/ebufsmarb.sv index 66f85af81..75201e402 100644 --- a/src/ebu/ebufsmarb.sv +++ b/src/ebu/ebufsmarb.sv @@ -70,7 +70,7 @@ module ebufsmarb ( case (CurrState) IDLE: if (both) NextState = ARBITRATE; else NextState = IDLE; - ARBITRATE: if (HREADY & FinalBeatD & ~(LSUReq & IFUReq)) NextState = IDLE; + ARBITRATE: if (HREADY & FinalBeatD & ~both) NextState = IDLE; else NextState = ARBITRATE; default: NextState = IDLE; endcase @@ -80,7 +80,7 @@ module ebufsmarb ( // Controller 0 (IFU) assign IFUSave = CurrState == IDLE & both; assign IFURestore = CurrState == ARBITRATE; - assign IFUDisable = CurrState == ARBITRATE; + assign IFUDisable = IFURestore; assign IFUSelect = (NextState == ARBITRATE) ? 1'b0 : IFUReq; // Controller 1 (LSU) // When both the IFU and LSU request at the same time, the FSM will go into the arbitrate state. @@ -89,7 +89,8 @@ module ebufsmarb ( // This is necessary because the pipeline is stalled for the entire duration of both transactions, // and the LSU memory request will still be active. flopr #(1) ifureqreg(HCLK, ~HRESETn, IFUReq, IFUReqDelay); - assign LSUDisable = (CurrState == ARBITRATE) ? 1'b0 : (IFUReqDelay & ~(HREADY & FinalBeatD)); + //assign LSUDisable = (CurrState != ARBITRATE) & (IFUReqDelay & ~(HREADY & FinalBeatD)); + assign LSUDisable = (CurrState != ARBITRATE) & IFUReqDelay; assign LSUSelect = (NextState == ARBITRATE) ? 1'b1: LSUReq; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index 1621addd9..4a4d3ecc5 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -64,6 +64,7 @@ module ifu import cvw::*; #(parameter cvw_t P) ( output logic [31:0] InstrM, // The decoded instruction in Memory stage output logic [31:0] InstrOrigM, // Original compressed or uncompressed instruction in Memory stage for Illegal Instruction MTVAL output logic [P.XLEN-1:0] PCM, // Memory stage instruction address + output logic [P.XLEN-1:0] PCSpillM, // Memory stage instruction address // branch predictor output logic [3:0] IClassM, // The valid instruction class. 1-hot encoded as jalr, ret, jr (not ret), j, br output logic BPDirWrongM, // Prediction direction is wrong @@ -149,13 +150,23 @@ module ifu import cvw::*; #(parameter cvw_t P) ( ///////////////////////////////////////////////////////////////////////////////////////////// if(P.ZCA_SUPPORTED) begin : Spill + logic [P.XLEN-1:0] PCSpillD, PCSpillE; + logic [P.XLEN-1:0] PCIncrM; + logic SelSpillF, SelSpillD, SelSpillE, SelSpillM; spill #(P) spill(.clk, .reset, .StallF, .FlushD, .PCF, .PCPlus4F, .PCNextF, .InstrRawF, .CacheableF, - .IFUCacheBusStallF, .ITLBMissOrUpdateAF, .PCSpillNextF, .PCSpillF, .SelSpillNextF, .PostSpillInstrRawF, .CompressedF); + .IFUCacheBusStallF, .ITLBMissOrUpdateAF, .PCSpillNextF, .PCSpillF, .SelSpillNextF, .SelSpillF, .PostSpillInstrRawF, .CompressedF); + flopenr #(1) SpillDReg(clk, reset, ~StallD, SelSpillF, SelSpillD); + flopenr #(1) SpillEReg(clk, reset, ~StallE, SelSpillD, SelSpillE); + flopenr #(1) SpillMReg(clk, reset, ~StallM, SelSpillE, SelSpillM); + assign PCIncrM = PCM + 'd2; + mux2 #(P.XLEN) pcspillmmux(PCM, PCIncrM, SelSpillM, PCSpillM); + end else begin : NoSpill assign PCSpillNextF = PCNextF; assign PCSpillF = PCF; assign PostSpillInstrRawF = InstrRawF; assign {SelSpillNextF, CompressedF} = '0; + assign PCSpillM = PCM; end //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/ifu/spill.sv b/src/ifu/spill.sv index f073398f3..e4c8a61a1 100644 --- a/src/ifu/spill.sv +++ b/src/ifu/spill.sv @@ -44,6 +44,7 @@ module spill import cvw::*; #(parameter cvw_t P) ( output logic [P.XLEN-1:0] PCSpillNextF, // The next PCF for one of the two memory addresses of the spill output logic [P.XLEN-1:0] PCSpillF, // PCF for one of the two memory addresses of the spill output logic SelSpillNextF, // During the transition between the two spill operations, the IFU should stall the pipeline + output logic SelSpillF, // Select incremented PC on a spill output logic [31:0] PostSpillInstrRawF,// The final 32 bit instruction after merging the two spilled fetches into 1 instruction output logic CompressedF); // The fetched instruction is compressed @@ -54,7 +55,6 @@ module spill import cvw::*; #(parameter cvw_t P) ( logic [P.XLEN-1:0] PCPlus2NextF, PCPlus2F; logic TakeSpillF; logic SpillF; - logic SelSpillF; logic SpillSaveF; logic [15:0] InstrFirstHalfF; logic EarlyCompressedF; diff --git a/src/privileged/csr.sv b/src/privileged/csr.sv index 3a5edf2ea..fd7271379 100644 --- a/src/privileged/csr.sv +++ b/src/privileged/csr.sv @@ -36,6 +36,7 @@ module csr import cvw::*; #(parameter cvw_t P) ( input logic [31:0] InstrM, // current instruction input logic [31:0] InstrOrigM, // Original compressed or uncompressed instruction in Memory stage for Illegal Instruction MTVAL input logic [P.XLEN-1:0] PCM, // program counter, next PC going to trap/return logic + input logic [P.XLEN-1:0] PCSpillM, // program counter, next PC going to trap/return logic aligned after an instruction spill input logic [P.XLEN-1:0] SrcAM, IEUAdrxTvalM, // SrcA and memory address from IEU input logic CSRReadM, CSRWriteM, // read or write CSR input logic TrapM, // trap is occurring @@ -140,7 +141,7 @@ module csr import cvw::*; #(parameter cvw_t P) ( always_comb if (InterruptM) NextFaultMtvalM = '0; else case (CauseM) - 12, 1, 3: NextFaultMtvalM = PCM; // Instruction page/access faults, breakpoint + 12, 1, 3: NextFaultMtvalM = PCSpillM; // Instruction page/access faults, breakpoint 2: NextFaultMtvalM = {{(P.XLEN-32){1'b0}}, InstrOrigM}; // Illegal instruction fault 0, 4, 6, 13, 15, 5, 7: NextFaultMtvalM = IEUAdrxTvalM; // Instruction misaligned, Load/Store Misaligned/page/access faults default: NextFaultMtvalM = '0; // Ecall, interrupts diff --git a/src/privileged/privileged.sv b/src/privileged/privileged.sv index ea53d8769..11968b93e 100644 --- a/src/privileged/privileged.sv +++ b/src/privileged/privileged.sv @@ -39,6 +39,7 @@ module privileged import cvw::*; #(parameter cvw_t P) ( input logic [31:0] InstrOrigM, // Original compressed or uncompressed instruction in Memory stage for Illegal Instruction MTVAL input logic [P.XLEN-1:0] IEUAdrxTvalM, // address from IEU input logic [P.XLEN-1:0] PCM, // program counter + input logic [P.XLEN-1:0] PCSpillM, // program counter // control signals input logic InstrValidM, // Current instruction is valid (not flushed) input logic CommittedM, CommittedF, // current instruction is using bus; don't interrupt @@ -133,7 +134,7 @@ module privileged import cvw::*; #(parameter cvw_t P) ( // Control and Status Registers csr #(P) csr(.clk, .reset, .FlushM, .FlushW, .StallE, .StallM, .StallW, - .InstrM, .InstrOrigM, .PCM, .SrcAM, .IEUAdrxTvalM, + .InstrM, .InstrOrigM, .PCM, .PCSpillM, .SrcAM, .IEUAdrxTvalM, .CSRReadM, .CSRWriteM, .TrapM, .mretM, .sretM, .InterruptM, .MTimerInt, .MExtInt, .SExtInt, .MSwInt, .MTIME_CLINT, .InstrValidM, .FRegWriteM, .LoadStallD, .StoreStallD, diff --git a/src/wally/wallypipelinedcore.sv b/src/wally/wallypipelinedcore.sv index 4c8fd1cfe..a27b40f1f 100644 --- a/src/wally/wallypipelinedcore.sv +++ b/src/wally/wallypipelinedcore.sv @@ -62,7 +62,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( logic [31:0] InstrD; logic [31:0] InstrM, InstrOrigM; logic [P.XLEN-1:0] PCSpillF, PCE, PCLinkE; - logic [P.XLEN-1:0] PCM; + logic [P.XLEN-1:0] PCM, PCSpillM; logic [P.XLEN-1:0] CSRReadValW, MDUResultW; logic [P.XLEN-1:0] EPCM, TrapVectorM; logic [1:0] MemRWE; @@ -184,7 +184,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( .PCLinkE, .PCSrcE, .IEUAdrE, .IEUAdrM, .PCE, .BPWrongE, .BPWrongM, // Mem .CommittedF, .EPCM, .TrapVectorM, .RetM, .TrapM, .InvalidateICacheM, .CSRWriteFenceM, - .InstrD, .InstrM, .InstrOrigM, .PCM, .IClassM, .BPDirWrongM, + .InstrD, .InstrM, .InstrOrigM, .PCM, .PCSpillM, .IClassM, .BPDirWrongM, .BTAWrongM, .RASPredPCWrongM, .IClassWrongM, // Faults out .IllegalBaseInstrD, .IllegalFPUInstrD, .InstrPageFaultF, .IllegalIEUFPUInstrD, .InstrMisalignedFaultM, @@ -289,7 +289,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( privileged #(P) priv( .clk, .reset, .FlushD, .FlushE, .FlushM, .FlushW, .StallD, .StallE, .StallM, .StallW, - .CSRReadM, .CSRWriteM, .SrcAM, .PCM, + .CSRReadM, .CSRWriteM, .SrcAM, .PCM, .PCSpillM, .InstrM, .InstrOrigM, .CSRReadValW, .EPCM, .TrapVectorM, .RetM, .TrapM, .sfencevmaM, .InvalidateICacheM, .DCacheStallM, .ICacheStallF, .InstrValidM, .CommittedM, .CommittedF, diff --git a/tests/coverage/WALLY-init-lib-misalignedSpill.h b/tests/coverage/WALLY-init-lib-misalignedSpill.h new file mode 100644 index 000000000..f3fdaf317 --- /dev/null +++ b/tests/coverage/WALLY-init-lib-misalignedSpill.h @@ -0,0 +1,155 @@ +/////////////////////////////////////////// +// WALLY-init-lib.h +// +// Written: David_Harris@hmc.edu 21 March 2023 +// +// Purpose: Initialize stack, handle interrupts, terminate test case +// +// A component of the CORE-V-WALLY configurable RISC-V project. +// https://github.com/openhwgroup/cvw +// +// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file +// except in compliance with the License, or, at your option, the Apache License version 2.0. You +// may obtain a copy of the License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work distributed under the +// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +//////////////////////////////////////////////////////////////////////////////////////////////// + +// load code to initalize stack, handle interrupts, terminate +// The PMP tests are sensitive to the exact addresses in this code, so unfortunately +// modifying anything breaks those tests. + +.section .text.init +.global rvtest_entry_point + +rvtest_entry_point: + la sp, topofstack # Initialize stack pointer (not used) + + # Set up interrupts + la t0, trap_handler + csrw mtvec, t0 # Initialize MTVEC to trap_handler + csrw mideleg, zero # Don't delegate interrupts + csrw medeleg, zero # Don't delegate exceptions +# li t0, -1 # set mtimecmp to biggest number so it doesnt interrupt again +# li t1, 0x02004000 # MTIMECMP in CLINT +# sd t0, 0(t1) + li t0, 0x80 +# li t0, 0x00 + csrw mie, t0 # Enable machine timer interrupt + la t0, topoftrapstack + csrw mscratch, t0 # MSCRATCH holds trap stack pointer + csrsi mstatus, 0x8 # Turn on mstatus.MIE global interrupt enable + # set up PMP so user and supervisor mode can access full address space + csrw pmpcfg0, 0xF # configure PMP0 to TOR RWX + li t0, 0xFFFFFFFF + csrw pmpaddr0, t0 # configure PMP0 top of range to 0xFFFFFFFF to allow all 32-bit addresses + j main # Call main function in user test program + +done: + li a0, 4 # argument to finish program + ecall # system call to finish program + j self_loop # wait forever (not taken) + +.align 4 # trap handlers must be aligned to multiple of 4 +trap_handler: + # Load trap handler stack pointer tp + csrrw tp, mscratch, tp # swap MSCRATCH and tp + sd t0, 0(tp) # Save t0 and t1 on the stack + sd t1, -8(tp) + csrr t0, mcause # Check the cause + csrr t1, mtval # And the trap value + bgez t0, exception # if msb is clear, it is an exception + +interrupt: # must be a timer interrupt + li t0, -1 # set mtimecmp to biggest number so it doesnt interrupt again + li t1, 0x02004000 # MTIMECMP in CLIN + sd t0, 0(t1) + csrw stimecmp, t0 # sets stimecmp to big number so it doesnt interrupt + li t0, 32 + csrc sip, t0 # clears stimer interrupt + j trap_return # clean up and return + +exception: + csrr t0, mcause + li t1, 0xC # is it an instruction page fault + li a0, 3 # set a0 to 3 to ecall looks like a program terminate + beq t0, t1, ecall # terminate program for instruction page fault + li t1, 8 # is it an ecall trap? + andi t0, t0, 0xFC # if CAUSE = 8, 9, or 11 + bne t0, t1, trap_return # ignore other exceptions + +ecall: + li t0, 4 + beq a0, t0, write_tohost # call 4: terminate program + bltu a0, t0, changeprivilege # calls 0-3: change privilege level + j trap_return # ignore other ecalls + +changeprivilege: + li t0, 0x00001800 # mask off mstatus.MPP in bits 11-12 + csrc mstatus, t0 + andi a0, a0, 0x003 # only keep bottom two bits of argument + slli a0, a0, 11 # move into mstatus.MPP position + csrs mstatus, a0 # set mstatus.MPP with desired privilege + +trap_return: # return from trap handler + csrr t0, mepc # get address of instruction that caused exception + li t1, 0x20000 + csrs mstatus, t1 # set mprv bit to fetch instruction with permission of code that trapped + lh t0, 0(t0) # get instruction that caused exception + csrc mstatus, t1 # clear mprv bit to restore normal operation + li t1, 3 + and t0, t0, t1 # mask off upper bits + beq t0, t1, instr32 # if lower 2 bits are 11, instruction is uncompresssed + li t0, 2 # increment PC by 2 for compressed instruction + j updateepc +instr32: + li t0, 4 +updateepc: + csrr t1, mepc # add 2 or 4 (from t0) to MEPC to determine return Address + add t1, t1, t0 + csrw mepc, t1 + + ld t1, -8(tp) # restore t1 and t0 + ld t0, 0(tp) + csrrw tp, mscratch, tp # restore tp + mret # return from trap + +write_tohost: + la t1, tohost + li t0, 1 # 1 for success, 3 for failure + sd t0, 0(t1) # send success code + +self_loop: + j self_loop # wait + +.section .tohost +tohost: # write to HTIF + .dword 0 +fromhost: + .dword 0 + +.EQU XLEN,64 +begin_signature: + .fill 6*(XLEN/32),4,0xdeadbeef # +end_signature: + +# Initialize stack with room for 512 bytes +.bss + .space 512 +topofstack: +# And another stack for the trap handler +.bss + .space 512 +topoftrapstack: + +.align 4 +.section .text.main diff --git a/tests/coverage/misalignedInstrSpill.S b/tests/coverage/misalignedInstrSpill.S index 72be421d7..13aab110f 100644 --- a/tests/coverage/misalignedInstrSpill.S +++ b/tests/coverage/misalignedInstrSpill.S @@ -26,7 +26,7 @@ // load code to initalize stack, handle interrupts, terminate -#include "WALLY-init-lib.h" +#include "WALLY-init-lib-misalignedSpill.h" # run-elf.bash find this in project description main: