2021-01-29 06:07:17 +00:00
///////////////////////////////////////////
// ahblite.sv
//
// Written: David_Harris@hmc.edu 9 January 2021
// Modified:
//
// Purpose: AHB Lite External Bus Unit
// See ARM_HIH0033A_AMBA_AHB-Lite_SPEC 1.0
// Arbitrates requests from instruction and data streams
// Connects hart to peripherals and I/O pins on SOC
// Bus width presently matches XLEN
// Anticipate replacing this with an AXI bus interface to communicate with FPGA DRAM/Flash controllers
//
// 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 ahblite (
input logic clk , reset ,
2021-02-08 04:28:21 +00:00
input logic StallW , FlushW ,
2021-01-30 04:43:48 +00:00
// Load control
input logic UnsignedLoadM ,
2021-03-11 05:11:31 +00:00
input logic [ 1 : 0 ] AtomicM ,
input logic [ 6 : 0 ] Funct7M ,
2021-01-29 06:07:17 +00:00
// Signals from Instruction Cache
2021-02-02 20:09:24 +00:00
input logic [ `XLEN - 1 : 0 ] InstrPAdrF , // *** rename these to match block diagram
2021-02-08 04:21:55 +00:00
input logic InstrReadF ,
2021-02-24 12:25:03 +00:00
output logic [ `XLEN - 1 : 0 ] InstrRData ,
2021-01-29 06:07:17 +00:00
// Signals from Data Cache
2021-02-02 20:09:24 +00:00
input logic [ `XLEN - 1 : 0 ] MemPAdrM ,
2021-02-08 04:21:55 +00:00
input logic MemReadM , MemWriteM ,
2021-02-02 20:09:24 +00:00
input logic [ `XLEN - 1 : 0 ] WriteDataM ,
2021-02-08 04:21:55 +00:00
input logic [ 1 : 0 ] MemSizeM ,
2021-03-18 18:35:46 +00:00
// Signals from MMU
input logic [ `XLEN - 1 : 0 ] MMUPAdr ,
input logic MMUTranslate ,
output logic [ `XLEN - 1 : 0 ] MMUReadPTE ,
output logic MMUReady ,
2021-01-30 06:57:51 +00:00
// Return from bus
2021-02-08 04:21:55 +00:00
output logic [ `XLEN - 1 : 0 ] ReadDataW ,
2021-01-29 06:07:17 +00:00
// AHB-Lite external signals
input logic [ `AHBW - 1 : 0 ] HRDATA ,
input logic HREADY , HRESP ,
2021-01-30 05:56:12 +00:00
output logic HCLK , HRESETn ,
output logic [ 31 : 0 ] HADDR ,
2021-01-29 06:07:17 +00:00
output logic [ `AHBW - 1 : 0 ] HWDATA ,
2021-01-30 05:56:12 +00:00
output logic HWRITE ,
2021-01-29 06:07:17 +00:00
output logic [ 2 : 0 ] HSIZE ,
output logic [ 2 : 0 ] HBURST ,
output logic [ 3 : 0 ] HPROT ,
output logic [ 1 : 0 ] HTRANS ,
2021-01-30 06:43:49 +00:00
output logic HMASTLOCK ,
2021-02-15 15:10:50 +00:00
// Delayed signals for writes
2021-02-08 04:21:55 +00:00
output logic [ 2 : 0 ] HADDRD ,
output logic [ 3 : 0 ] HSIZED ,
output logic HWRITED ,
2021-01-30 06:43:49 +00:00
// Stalls
2021-02-15 15:10:50 +00:00
output logic InstrStall , /*InstrUpdate, */ DataStall
2021-03-05 06:22:53 +00:00
// *** add a chip-level ready signal as part of handshake
2021-01-29 06:07:17 +00:00
) ;
logic GrantData ;
logic [ 2 : 0 ] ISize ;
2021-03-18 22:25:12 +00:00
logic [ `AHBW - 1 : 0 ] HRDATAMasked , ReadDataM , ReadDataNewW , ReadDataOldW , WriteData ;
2021-01-30 06:43:49 +00:00
logic IReady , DReady ;
2021-02-24 12:25:03 +00:00
logic CaptureDataM ;
2021-01-29 06:07:17 +00:00
assign HCLK = clk ;
assign HRESETn = ~ reset ;
2021-03-05 06:22:53 +00:00
// *** initially support AHBW = XLEN
2021-01-29 06:07:17 +00:00
2021-02-08 04:21:55 +00:00
// track bus state
2021-02-15 15:10:50 +00:00
// Data accesses have priority over instructions. However, if a data access comes
// while an instruction read is occuring, the instruction read finishes before
// the data access can take place.
2021-03-18 22:25:12 +00:00
typedef enum { IDLE , MEMREAD , MEMWRITE , INSTRREAD , INSTRREADC , ATOMICREAD , ATOMICWRITE } statetype ;
2021-02-15 15:10:50 +00:00
statetype BusState , NextBusState ;
2021-03-10 19:14:02 +00:00
flopenl # ( . TYPE ( statetype ) ) busreg ( HCLK , ~ HRESETn , 1 'b1 , NextBusState , IDLE , BusState ) ;
2021-02-15 15:10:50 +00:00
always_comb
case ( BusState )
2021-03-18 22:25:12 +00:00
IDLE: if ( AtomicM [ 1 ] ) NextBusState = ATOMICREAD ;
else if ( MemReadM ) NextBusState = MEMREAD ; // Memory has pirority over instructions
else if ( MemWriteM ) NextBusState = MEMWRITE ;
else if ( InstrReadF ) NextBusState = INSTRREAD ;
else NextBusState = IDLE ;
ATOMICREAD: if ( ~ HREADY ) NextBusState = ATOMICREAD ;
else NextBusState = ATOMICWRITE ;
ATOMICWRITE: if ( ~ HREADY ) NextBusState = ATOMICWRITE ;
else if ( InstrReadF ) NextBusState = INSTRREAD ;
else NextBusState = IDLE ;
MEMREAD: if ( ~ HREADY ) NextBusState = MEMREAD ;
else if ( InstrReadF ) NextBusState = INSTRREADC ;
else NextBusState = IDLE ;
MEMWRITE: if ( ~ HREADY ) NextBusState = MEMWRITE ;
else if ( InstrReadF ) NextBusState = INSTRREAD ;
else NextBusState = IDLE ;
INSTRREAD:
if ( ~ HREADY ) NextBusState = INSTRREAD ;
else NextBusState = IDLE ; // if (InstrReadF still high)
INSTRREADC: if ( ~ HREADY ) NextBusState = INSTRREADC ; // "C" for "competing", meaning please don't mess up the memread in the W stage.
else NextBusState = IDLE ;
2021-02-15 15:10:50 +00:00
endcase
// stall signals
2021-03-11 05:11:31 +00:00
assign # 2 DataStall = ( NextBusState = = MEMREAD ) | | ( NextBusState = = MEMWRITE ) | |
2021-03-18 22:25:12 +00:00
( NextBusState = = ATOMICREAD ) | | ( NextBusState = = ATOMICWRITE ) ;
assign # 1 InstrStall = ( NextBusState = = INSTRREAD ) | | ( NextBusState = = INSTRREADC ) ;
2021-03-11 05:11:31 +00:00
2021-02-15 15:10:50 +00:00
// bus outputs
2021-03-11 05:11:31 +00:00
assign # 1 GrantData = ( NextBusState = = MEMREAD ) | | ( NextBusState = = MEMWRITE ) | |
( NextBusState = = ATOMICREAD ) | | ( NextBusState = = ATOMICWRITE ) ;
2021-02-15 15:10:50 +00:00
assign # 1 HADDR = ( GrantData ) ? MemPAdrM [ 31 : 0 ] : InstrPAdrF [ 31 : 0 ] ;
2021-02-26 06:03:47 +00:00
assign ISize = 3 'b010 ; // 32 bit instructions for now; later improve for filling cache with full width; ignored on reads anyway
2021-02-15 15:10:50 +00:00
assign # 1 HSIZE = GrantData ? { 1 'b0 , MemSizeM } : ISize ;
assign HBURST = 3 'b000 ; // Single burst only supported; consider generalizing for cache fillsfH
assign HPROT = 4 'b0011 ; // not used; see Section 3.7
assign HTRANS = ( NextBusState ! = IDLE ) ? 2 'b10 : 2 'b00 ; // NONSEQ if reading or writing, IDLE otherwise
assign HMASTLOCK = 0 ; // no locking supported
2021-03-11 05:11:31 +00:00
assign HWRITE = ( NextBusState = = MEMWRITE ) | | ( NextBusState = = ATOMICWRITE ) ;
2021-02-15 15:10:50 +00:00
// delay write data by one cycle for
2021-03-11 05:11:31 +00:00
flop # ( `XLEN ) wdreg ( HCLK , WriteData , HWDATA ) ; // delay HWDATA by 1 cycle per spec; *** assumes AHBW = XLEN
2021-02-15 15:10:50 +00:00
// delay signals for subword writes
flop # ( 3 ) adrreg ( HCLK , HADDR [ 2 : 0 ] , HADDRD ) ;
flop # ( 4 ) sizereg ( HCLK , { UnsignedLoadM , HSIZE } , HSIZED ) ;
flop # ( 1 ) writereg ( HCLK , HWRITE , HWRITED ) ;
2021-02-22 18:48:30 +00:00
// Route signals to Instruction and Data Caches
// *** assumes AHBW = XLEN
2021-02-24 12:25:03 +00:00
assign InstrRData = HRDATA ;
2021-02-22 18:48:30 +00:00
assign ReadDataM = HRDATAMasked ; // changed from W to M dh 2/7/2021
2021-03-11 05:11:31 +00:00
assign CaptureDataM = ( ( BusState = = MEMREAD ) & & ( NextBusState ! = MEMREAD ) ) | |
( ( BusState = = ATOMICREAD ) & & ( NextBusState = = ATOMICWRITE ) ) ;
2021-03-18 22:25:12 +00:00
// We think this introduces an unnecessary cycle of latency in memory accesses
flopenr # ( `XLEN ) ReadDataNewWReg ( clk , reset , CaptureDataM , ReadDataM , ReadDataNewW ) ; // *** check that this does not break when there is no instruction read after data read
flopenr # ( `XLEN ) ReadDataOldWReg ( clk , reset , CaptureDataM , ReadDataNewW , ReadDataOldW ) ; // *** check that this does not break when there is no instruction read after data read
assign ReadDataW = ( BusState = = INSTRREADC ) ? ReadDataOldW : ReadDataNewW ;
2021-02-22 18:48:30 +00:00
2021-03-11 05:11:31 +00:00
// Extract and sign-extend subwords if necessary
2021-01-30 04:43:48 +00:00
subwordread swr ( . * ) ;
2021-03-11 05:11:31 +00:00
// Handle AMO instructions if applicable
generate
if ( `A_SUPPORTED ) begin
logic [ `XLEN - 1 : 0 ] AMOResult ;
2021-03-12 04:18:33 +00:00
// amoalu amoalu(.a(HRDATA), .b(WriteDataM), .funct(Funct7M), .width(MemSizeM),
// .result(AMOResult));
2021-03-18 22:25:12 +00:00
amoalu amoalu ( . srca ( ReadDataW ) , . srcb ( WriteDataM ) , . funct ( Funct7M ) , . width ( MemSizeM ) ,
2021-03-11 05:11:31 +00:00
. result ( AMOResult ) ) ;
mux2 # ( `XLEN ) wdmux ( WriteDataM , AMOResult , AtomicM [ 1 ] , WriteData ) ;
end else
assign WriteData = WriteDataM ;
endgenerate
2021-01-29 06:07:17 +00:00
2021-03-11 05:11:31 +00:00
endmodule