2023-10-26 15:47:00 +00:00
///////////////////////////////////////////
// spill.sv
//
// Written: Rose Thompson ross1728@gmail.com
// Created: 26 October 2023
// Modified: 26 October 2023
//
// Purpose: This module implements native alignment support for the Zicclsm extension
// It is simlar to the IFU's spill module and probably could be merged together with
// some effort.
//
// Documentation: RISC-V System on Chip Design Chapter 11 (Figure 11.5)
//
// A component of the CORE-V-WALLY configurable RISC-V project.
2024-01-29 13:38:11 +00:00
// https://github.com/openhwgroup/cvw
2023-10-26 15:47:00 +00:00
//
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////
module align import cvw : : * ; # ( parameter cvw_t P ) (
2023-11-19 01:01:39 +00:00
input logic clk ,
input logic reset ,
input logic StallM , FlushM ,
input logic [ P . XLEN - 1 : 0 ] IEUAdrM , // 2 byte aligned PC in Fetch stage
input logic [ P . XLEN - 1 : 0 ] IEUAdrE , // The next IEUAdrM
input logic [ 2 : 0 ] Funct3M , // Size of memory operation
2024-02-23 20:00:19 +00:00
input logic FpLoadStoreM , // Floating point Load or Store
2023-11-19 01:01:39 +00:00
input logic [ 1 : 0 ] MemRWM ,
input logic [ P . LLEN * 2 - 1 : 0 ] DCacheReadDataWordM , // Instruction from the IROM, I$, or bus. Used to check if the instruction if compressed
input logic CacheBusHPWTStall , // I$ or bus are stalled. Transition to second fetch of spill after the first is fetched
input logic SelHPTW ,
2023-10-26 15:47:00 +00:00
2023-11-19 01:01:39 +00:00
input logic [ ( P . LLEN - 1 ) / 8 : 0 ] ByteMaskM ,
input logic [ ( P . LLEN - 1 ) / 8 : 0 ] ByteMaskExtendedM ,
input logic [ P . LLEN - 1 : 0 ] LSUWriteDataM ,
2023-10-30 19:00:49 +00:00
output logic [ ( P . LLEN * 2 - 1 ) / 8 : 0 ] ByteMaskSpillM ,
2024-03-06 21:15:26 +00:00
output logic [ P . LLEN * 2 - 1 : 0 ] LSUWriteDataSpillM ,
2023-10-30 19:00:49 +00:00
2023-11-19 01:01:39 +00:00
output logic [ P . XLEN - 1 : 0 ] IEUAdrSpillE , // The next PCF for one of the two memory addresses of the spill
output logic [ P . XLEN - 1 : 0 ] IEUAdrSpillM , // IEUAdrM for one of the two memory addresses of the spill
output logic SelSpillE , // During the transition between the two spill operations, the IFU should stall the pipeline
2024-03-06 21:19:17 +00:00
output logic [ P . LLEN - 1 : 0 ] DCacheReadDataWordSpillM , // The final 32 bit instruction after merging the two spilled fetches into 1 instruction
2023-11-19 01:01:39 +00:00
output logic SpillStallM ) ;
2023-10-26 15:47:00 +00:00
2023-11-13 20:28:22 +00:00
localparam LLENINBYTES = P . LLEN / 8 ;
localparam OFFSET_BIT_POS = $clog2 ( P . DCACHE_LINELENINBITS / 8 ) ;
2023-10-26 15:47:00 +00:00
// Spill threshold occurs when all the cache offset PC bits are 1 (except [0]). Without a cache this is just PCF[1]
2023-11-01 19:25:18 +00:00
typedef enum logic [ 1 : 0 ] { STATE_READY , STATE_SPILL , STATE_STORE_DELAY } statetype ;
2023-10-26 15:47:00 +00:00
statetype CurrState , NextState ;
2023-11-28 20:18:06 +00:00
logic ValidSpillM ;
2023-10-27 16:41:49 +00:00
logic SelSpillM ;
logic SpillSaveM ;
2023-11-29 01:54:25 +00:00
logic [ P . LLEN - 1 : 0 ] ReadDataWordFirstHalfM ;
2023-11-29 05:05:47 +00:00
logic MisalignedM ;
2024-03-06 21:19:17 +00:00
logic [ P . LLEN * 2 - 1 : 0 ] ReadDataWordSpillAllM ;
logic [ P . LLEN * 2 - 1 : 0 ] ReadDataWordSpillShiftedM ;
2023-10-26 15:47:00 +00:00
2023-11-29 01:54:25 +00:00
logic [ P . XLEN - 1 : 0 ] IEUAdrIncrementM ;
2023-10-31 23:50:13 +00:00
2024-02-23 20:00:19 +00:00
localparam OFFSET_LEN = $clog2 ( LLENINBYTES ) ;
2024-03-06 21:15:26 +00:00
logic [ $clog2 ( LLENINBYTES ) - 1 : 0 ] AccessByteOffsetM ;
logic [ $clog2 ( LLENINBYTES ) + 2 : 0 ] ShiftAmount ;
logic PotentialSpillM ;
2023-10-31 23:50:13 +00:00
2023-10-30 19:00:49 +00:00
/* verilator lint_off WIDTHEXPAND */
2023-11-11 00:39:36 +00:00
assign IEUAdrIncrementM = IEUAdrM + LLENINBYTES ;
2023-10-30 19:00:49 +00:00
/* verilator lint_on WIDTHEXPAND */
2023-10-27 19:41:42 +00:00
mux2 # ( P . XLEN ) ieuadrspillemux ( . d0 ( IEUAdrE ) , . d1 ( IEUAdrIncrementM ) , . s ( SelSpillE ) , . y ( IEUAdrSpillE ) ) ;
2023-10-30 19:54:58 +00:00
mux2 # ( P . XLEN ) ieuadrspillmmux ( . d0 ( IEUAdrM ) , . d1 ( IEUAdrIncrementM ) , . s ( SelSpillM ) , . y ( IEUAdrSpillM ) ) ;
2023-10-26 15:47:00 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////
// Detect spill
////////////////////////////////////////////////////////////////////////////////////////////////////
// spill detection in lsu is more complex than ifu, depends on 3 factors
// 1) operation size
// 2) offset
2023-10-27 14:35:44 +00:00
// 3) access location within the cacheline
2023-11-11 00:26:55 +00:00
2023-11-29 05:05:47 +00:00
// compute misalignement
2023-11-11 00:26:55 +00:00
always_comb begin
2024-02-23 20:00:19 +00:00
case ( Funct3M & { FpLoadStoreM , 2 'b11 } )
2024-03-06 21:35:34 +00:00
3 'b000 : AccessByteOffsetM = 0 ; // byte access
2024-02-23 20:00:19 +00:00
3 'b001 : AccessByteOffsetM = { { OFFSET_LEN - 1 { 1 'b0 } } , IEUAdrM [ 0 ] } ; // half access
3 'b010 : AccessByteOffsetM = { { OFFSET_LEN - 2 { 1 'b0 } } , IEUAdrM [ 1 : 0 ] } ; // word access
2024-03-06 21:43:55 +00:00
3 'b011 : if ( P . LLEN > = 64 ) AccessByteOffsetM = { { OFFSET_LEN - 3 { 1 'b0 } } , IEUAdrM [ 2 : 0 ] } ; // double access
else AccessByteOffsetM = 0 ; // shouldn't happen
2024-02-23 20:00:19 +00:00
3 'b100 : if ( P . LLEN = = 128 ) AccessByteOffsetM = IEUAdrM [ OFFSET_LEN - 1 : 0 ] ; // quad access
2024-03-06 21:43:55 +00:00
else AccessByteOffsetM = IEUAdrM [ OFFSET_LEN - 1 : 0 ] ;
default : AccessByteOffsetM = 0 ; // shouldn't happen
2023-11-29 04:28:11 +00:00
endcase
case ( Funct3M [ 1 : 0 ] )
2024-03-06 13:48:17 +00:00
2 'b00 : PotentialSpillM = 0 ; // byte access
2023-11-29 04:28:11 +00:00
2 'b01 : PotentialSpillM = IEUAdrM [ OFFSET_BIT_POS - 1 : 1 ] = = '1 ; // half access
2 'b10 : PotentialSpillM = IEUAdrM [ OFFSET_BIT_POS - 1 : 2 ] = = '1 ; // word access
2 'b11 : PotentialSpillM = IEUAdrM [ OFFSET_BIT_POS - 1 : 3 ] = = '1 ; // double access
2024-03-06 13:48:17 +00:00
default : PotentialSpillM = 0 ;
2023-11-11 00:26:55 +00:00
endcase
end
2024-03-06 13:48:17 +00:00
assign MisalignedM = ( | MemRWM ) & ( AccessByteOffsetM ! = 0 ) ;
2023-10-27 14:35:44 +00:00
2023-11-29 05:28:50 +00:00
assign ValidSpillM = MisalignedM & PotentialSpillM & ~ CacheBusHPWTStall ; // Don't take the spill if there is a stall
2023-10-26 15:47:00 +00:00
always_ff @ ( posedge clk )
2024-03-08 19:22:04 +00:00
if ( reset | FlushM ) CurrState < = STATE_READY ;
else CurrState < = NextState ;
2023-10-26 15:47:00 +00:00
always_comb begin
case ( CurrState )
2024-03-02 22:20:31 +00:00
STATE_READY: if ( ValidSpillM ) NextState = STATE_SPILL ; // load spill
2024-01-01 16:21:31 +00:00
else NextState = STATE_READY ; // no spill
2023-10-26 15:47:00 +00:00
STATE_SPILL: if ( StallM ) NextState = STATE_SPILL ;
else NextState = STATE_READY ;
default : NextState = STATE_READY ;
endcase
end
2024-03-02 22:20:31 +00:00
assign SelSpillM = CurrState = = STATE_SPILL ;
assign SelSpillE = ( CurrState = = STATE_READY & ValidSpillM ) | ( CurrState = = STATE_SPILL & CacheBusHPWTStall ) ;
2023-11-28 20:18:06 +00:00
assign SpillSaveM = ( CurrState = = STATE_READY ) & ValidSpillM & ~ FlushM ;
2024-01-01 16:31:09 +00:00
assign SpillStallM = SelSpillE ;
2023-10-26 15:47:00 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2023-10-27 16:41:49 +00:00
// Merge spilled data
2023-10-26 15:47:00 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////
2023-11-13 20:28:22 +00:00
// save the first native word
2023-10-27 18:55:16 +00:00
flopenr # ( P . LLEN ) SpillDataReg ( clk , reset , SpillSaveM , DCacheReadDataWordM [ P . LLEN - 1 : 0 ] , ReadDataWordFirstHalfM ) ;
2023-10-26 15:47:00 +00:00
// merge together
2023-11-13 20:28:22 +00:00
mux2 # ( 2 * P . LLEN ) postspillmux ( DCacheReadDataWordM , { DCacheReadDataWordM [ P . LLEN - 1 : 0 ] , ReadDataWordFirstHalfM } , SelSpillM , ReadDataWordSpillAllM ) ;
2023-10-26 15:47:00 +00:00
2024-03-06 21:15:26 +00:00
// shifter (4:1 mux for 32 bit, 8:1 mux for 64 bit)
// 8 * is for shifting by bytes not bits
2024-03-06 13:48:17 +00:00
assign ShiftAmount = SelHPTW ? 0 : { AccessByteOffsetM , 3 'b0 } ; // AND gate
2024-03-06 21:19:17 +00:00
assign ReadDataWordSpillShiftedM = ReadDataWordSpillAllM > > ShiftAmount ;
assign DCacheReadDataWordSpillM = ReadDataWordSpillShiftedM [ P . LLEN - 1 : 0 ] ;
2024-03-06 21:15:26 +00:00
// write path. Also has the 8:1 shifter muxing for the byteoffset
// then it also has the mux to select when a spill occurs
logic [ P . LLEN * 3 - 1 : 0 ] LSUWriteDataShiftedExtM ; // *** RT: Find a better way. I've extending in both directions so we don't shift in zeros. The cache expects the writedata to not have any zero data, but instead replicated data.
assign LSUWriteDataShiftedExtM = { LSUWriteDataM , LSUWriteDataM , LSUWriteDataM } < < ShiftAmount ;
assign LSUWriteDataSpillM = LSUWriteDataShiftedExtM [ P . LLEN * 3 - 1 : P . LLEN ] ;
2023-11-29 01:54:25 +00:00
mux3 # ( 2 * P . LLEN / 8 ) bytemaskspillmux ( { ByteMaskExtendedM , ByteMaskM } , // no spill
2023-11-13 22:15:23 +00:00
{ { { P . LLEN / 8 } { 1 'b0 } } , ByteMaskM } , // spill, first half
2023-11-29 01:54:25 +00:00
{ { { P . LLEN / 8 } { 1 'b0 } } , ByteMaskExtendedM } , // spill, second half
2023-11-13 22:15:23 +00:00
{ SelSpillM , SelSpillE } , ByteMaskSpillM ) ;
2023-10-31 23:50:13 +00:00
2023-10-26 15:47:00 +00:00
endmodule