APB CLINT passing regression

This commit is contained in:
David Harris 2022-07-05 15:51:35 +00:00
parent d033659beb
commit d73645944f
8 changed files with 288 additions and 20 deletions

View File

@ -49,6 +49,8 @@ module ahblite (
input logic [2:0] IFUBurstType,
input logic [1:0] IFUTransType,
input logic IFUTransComplete,
input logic [(`XLEN-1)/8:0] ByteMaskM,
// Signals from Data Cache
input logic [`PA_BITS-1:0] LSUBusAdr,
input logic LSUBusRead,
@ -67,6 +69,7 @@ module ahblite (
(* mark_debug = "true" *) output logic HCLK, HRESETn,
(* mark_debug = "true" *) output logic [31:0] HADDR, // *** one day switch to a different bus that supports the full physical address
(* mark_debug = "true" *) output logic [`AHBW-1:0] HWDATA,
output logic [`XLEN/8-1:0] HWSTRB,
(* mark_debug = "true" *) output logic HWRITE,
(* mark_debug = "true" *) output logic [2:0] HSIZE,
(* mark_debug = "true" *) output logic [2:0] HBURST,
@ -154,6 +157,7 @@ module ahblite (
assign HTRANS = (GrantData) ? LSUTransType : IFUTransType; // SEQ if not first read or write, NONSEQ if first read or write, IDLE otherwise
assign HMASTLOCK = 0; // no locking supported
assign HWRITE = (NextBusState == MEMWRITE);
assign HWSTRB = ByteMaskM;
// delay write data by one cycle for
flopen #(`XLEN) wdreg(HCLK, (LSUBusAck | LSUBusInit), LSUBusHWDATA, HWDATA); // delay HWDATA by 1 cycle per spec; *** assumes AHBW = XLEN
// delay signals for subword writes

View File

@ -77,6 +77,8 @@ module lsu (
(* mark_debug = "true" *) output logic [2:0] LSUBurstType,
(* mark_debug = "true" *) output logic [1:0] LSUTransType,
(* mark_debug = "true" *) output logic LSUTransComplete,
output logic [(`XLEN-1)/8:0] ByteMaskM,
// page table walker
input logic [`XLEN-1:0] SATP_REGW, // from csr
input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV,
@ -112,7 +114,6 @@ module lsu (
logic LSUBusWriteCrit;
logic DataDAPageFaultM;
logic [`XLEN-1:0] LSUWriteDataM;
logic [(`XLEN-1)/8:0] ByteMaskM;
logic [`XLEN-1:0] WriteDataM;
logic [`LLEN-1:0] ReadDataM;
@ -268,10 +269,10 @@ module lsu (
/////////////////////////////////////////////////////////////////////////////////////////////
// Subword Accesses
/////////////////////////////////////////////////////////////////////////////////////////////
subwordwrite subwordwrite(.LSUPAdrM(LSUPAdrM[2:0]),
.LSUFunct3M, .AMOWriteDataM, .LittleEndianWriteDataM, .ByteMaskM);
subwordread subwordread(.ReadDataWordMuxM, .LSUPAdrM(LSUPAdrM[2:0]),
.FpLoadStoreM, .Funct3M(LSUFunct3M), .ReadDataM);
subwordwrite subwordwrite(.LSUPAdrM(LSUPAdrM[2:0]),
.LSUFunct3M, .AMOWriteDataM, .LittleEndianWriteDataM, .ByteMaskM);
/////////////////////////////////////////////////////////////////////////////////////////////
// MW Pipeline Register

View File

@ -34,10 +34,10 @@ module ahbapbbridge #(PERIPHS = 2) (
input logic [PERIPHS-1:0] HSEL,
input logic [31:0] HADDR,
input logic [`XLEN-1:0] HWDATA,
input logic [`XLEN/8-1:0] HWSTRB,
input logic HWRITE,
input logic [1:0] HTRANS,
input logic HREADY,
input logic [`XLEN/8-1:0] HWSTRB,
// input logic [3:0] HPROT, // not used
output logic [`XLEN-1:0] HRDATA,
output logic HRESP, HREADYOUT,
@ -102,7 +102,7 @@ module ahbapbbridge #(PERIPHS = 2) (
end
end
end
assign HREADYOUT = PREADYOUT & PENABLE; // don't raise HREADYOUT until access phase
assign HREADYOUT = PREADYOUT & ~initTransSelD; // don't raise HREADYOUT before access phase
// resp logic
assign HRESP = 0; // bridge never indicates errors

View File

@ -28,7 +28,7 @@
// 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 clint (
@ -258,3 +258,4 @@ module graytobinary #(parameter N = `XLEN) (
assign b[i] = g[i] ^ b[i+1];
end
endmodule
*/

View File

@ -0,0 +1,252 @@
///////////////////////////////////////////
// clint_apb.sv
//
// Written: David_Harris@hmc.edu 14 January 2021
// Modified:
//
// Purpose: Core-Local Interruptor
// See FE310-G002-Manual-v19p05 for specifications
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// MIT LICENSE
// 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 clint_apb (
input logic PCLK, PRESETn,
input logic PSEL,
input logic [15:0] PADDR,
input logic [`XLEN-1:0] PWDATA,
input logic [`XLEN/8-1:0] PSTRB,
input logic PWRITE,
input logic PENABLE,
output logic [`XLEN-1:0] PRDATA,
output logic PREADY,
(* mark_debug = "true" *) output logic [63:0] MTIME,
output logic MTimerInt, MSwInt);
logic MSIP;
logic [15:0] entry;
logic memwrite;
(* mark_debug = "true" *) logic [63:0] MTIMECMP;
integer i, j;
assign memwrite = PWRITE & PENABLE & PSEL; // only write in access phase
assign PREADY = 1'b1; // GPIO never takes >1 cycle to respond
// word aligned reads
if (`XLEN==64) assign #2 entry = {PADDR[15:3], 3'b000};
else assign #2 entry = {PADDR[15:2], 2'b00};
//swbytemask swbytemask(.Size(HSIZED[1:0]), .Adr(entry[2:0]), .ByteMask(PSTRB));
// DH 2/20/21: Eventually allow MTIME to run off a separate clock
// This will require synchronizing MTIME to the system clock
// before it is read or compared to MTIMECMP.
// It will also require synchronizing the write to MTIMECMP.
// Use req and ack signals synchronized across the clock domains.
// register access
if (`XLEN==64) begin:clint // 64-bit
always @(posedge PCLK) begin
case(entry)
16'h0000: PRDATA <= {63'b0, MSIP};
16'h4000: PRDATA <= MTIMECMP;
16'hBFF8: PRDATA <= MTIME;
default: PRDATA <= 0;
endcase
end
always_ff @(posedge PCLK or negedge PRESETn)
if (~PRESETn) begin
MSIP <= 0;
MTIMECMP <= 64'hFFFFFFFFFFFFFFFF; // Spec says MTIMECMP is not reset, but we reset to maximum value to prevent spurious timer interrupts
end else if (memwrite) begin
if (entry == 16'h0000) MSIP <= PWDATA[0];
if (entry == 16'h4000) begin
for(i=0;i<`XLEN/8;i++)
if(PSTRB[i])
MTIMECMP[i*8 +: 8] <= PWDATA[i*8 +: 8]; // ***dh: this notation isn't in book yet - maybe from Ross
end
end
// eventually replace MTIME logic below with timereg
// timereg tr(PCLK, PRESETn, TIMECLK, memwrite & (entry==16'hBFF8), 1'b0, PWDATA, MTIME, done);
always_ff @(posedge PCLK or negedge PRESETn)
if (~PRESETn) begin
MTIME <= 0;
end else if (memwrite & entry == 16'hBFF8) begin
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
for(j=0;j<`XLEN/8;j++)
if(PSTRB[j])
MTIME[j*8 +: 8] <= PWDATA[j*8 +: 8];
end else MTIME <= MTIME + 1;
end else begin:clint // 32-bit
always @(posedge PCLK) begin
case(entry)
16'h0000: PRDATA <= {31'b0, MSIP};
16'h4000: PRDATA <= MTIMECMP[31:0];
16'h4004: PRDATA <= MTIMECMP[63:32];
16'hBFF8: PRDATA <= MTIME[31:0];
16'hBFFC: PRDATA <= MTIME[63:32];
default: PRDATA <= 0;
endcase
end
always_ff @(posedge PCLK or negedge PRESETn)
if (~PRESETn) begin
MSIP <= 0;
MTIMECMP <= 0;
// MTIMECMP is not reset ***?
end else if (memwrite) begin
if (entry == 16'h0000) MSIP <= PWDATA[0];
if (entry == 16'h4000)
for(j=0;j<`XLEN/8;j++)
if(PSTRB[j])
MTIMECMP[j*8 +: 8] <= PWDATA[j*8 +: 8];
if (entry == 16'h4004)
for(j=0;j<`XLEN/8;j++)
if(PSTRB[j])
MTIMECMP[32 + j*8 +: 8] <= PWDATA[j*8 +: 8];
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
end
// eventually replace MTIME logic below with timereg
// timereg tr(PCLK, PRESETn, TIMECLK, memwrite & (entry==16'hBFF8), memwrite & (entry == 16'hBFFC), PWDATA, MTIME, done);
always_ff @(posedge PCLK or negedge PRESETn)
if (~PRESETn) begin
MTIME <= 0;
// MTIMECMP is not reset
end else if (memwrite & (entry == 16'hBFF8)) begin
for(i=0;i<`XLEN/8;i++)
if(PSTRB[i])
MTIME[i*8 +: 8] <= PWDATA[i*8 +: 8];
end else if (memwrite & (entry == 16'hBFFC)) begin
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
for(i=0;i<`XLEN/8;i++)
if(PSTRB[i])
MTIME[32 + i*8 +: 8]<= PWDATA[i*8 +: 8];
end else MTIME <= MTIME + 1;
end
// Software interrupt when MSIP is set
assign MSwInt = MSIP;
// Timer interrupt when MTIME >= MTIMECMP
assign MTimerInt = ({1'b0, MTIME} >= {1'b0, MTIMECMP}); // unsigned comparison
endmodule
module timeregsync(
input logic clk, resetn,
input logic we0, we1,
input logic [`XLEN-1:0] wd,
output logic [63:0] q);
if (`XLEN==64)
always_ff @(posedge clk or negedge resetn)
if (~resetn) q <= 0;
else if (we0) q <= wd;
else q <= q + 1;
else
always_ff @(posedge clk or negedge resetn)
if (~resetn) q <= 0;
else if (we0) q[31:0] <= wd;
else if (we1) q[63:32] <= wd;
else q <= q + 1;
endmodule
module timereg(
input logic PCLK, PRESETn, TIMECLK,
input logic we0, we1,
input logic [`XLEN-1:0] PWDATA,
output logic [63:0] MTIME,
output logic done);
// if (`TIMEBASE_SYNC) begin:timereg // use PCLK for MTIME
if (1) begin:timereg // use PCLK for MTIME
timregsync timeregsync(.clk(PCLK), .resetn(PRESETn), .we0, .we1, .wd(PWDATA), .q(MTIME));
assign done = 1; // immediately completes
end else begin // use asynchronous TIMECLK
// TIME counter runs on TIMECLK but bus interface runs on PCLK
// Need to synchronize reads and writes
// This is subtle because synchronizing a binary counter on a per-bit basis could give a mix of old and new bits
// Instead, we use a Gray coded counter that only changes one bit per cycle
// Synchronizing this for a read is safe because we are guaranteed to get either the old or the new value.
// Writing to the counter requires a request/acknowledge handshake to ensure the write value is held long enough.
// The handshake signals are synchronized in each direction across the interface
// There is no back pressure on instructions, so if multiple counter writes occur ***
logic req, req_sync, ack, we0_stored, we1_stored, ack_stored, resetn_sync;
logic [`XLEN-1:0] wd_stored;
logic [63:0] time_int, time_int_gc, time_gc, MTIME_GC;
// When a write enable is asserted for a cycle, sample the enables and data and raise a request until it is acknowledged
// When the acknowledge falls, the transaction is done and the system is ready for another write.
// ***look at redoing this assuming write enable and data are held rather than pulsed.
always_ff @(posedge PCLK or negedge PRESETn)
if (~PRESETn)
req <= 0; // don't bother resetting wd
else begin
req <= we0 | we1 | req & ~ack;
we0_stored <= we0;
we1_stored <= we1;
wd_stored <= PWDATA;
ack_stored <= ack;
done <= ack_stored & ~ack;
end
// synchronize the reset and reqest into the TIMECLK domain
sync resetsync(TIMECLK, PRESETn, resetn_sync);
sync rsync(TIMECLK, req, req_sync);
// synchronize the acknowledge back to the PCLK domain to indicate the request was handled and can be lowered
sync async(PCLK, req_sync, ack);
timeregsync timeregsync(.clk(TIMECLK), .resetn(resetn_sync), .we0(we0_stored), .we1(we1_stored), .wd(wd_stored), .q(time_int));
binarytogray b2g(time_int, time_int_gc);
flop gcreg(TIMECLK, time_int_gc, time_gc);
sync timesync[63:0](PCLK, time_gc, MTIME_GC);
graytobinary g2b(MTIME_GC, MTIME);
end
endmodule
module binarytogray #(parameter N = `XLEN) (
input logic [N-1:0] b,
output logic [N-1:0] g);
// G[N-1] = B[N-1]; G[i] = B[i] ^ B[i+1] for 0 <= i < N-1
// requires single layer of N-1 XOR gates
assign g = b ^ {1'b0, b[N-1:1]};
endmodule
module graytobinary #(parameter N = `XLEN) (
input logic [N-1:0] g,
output logic [N-1:0] b);
// B[N-1] = G[N-1]; B[i] = G[i] ^ B[i+1] for 0 <= i < N-1
// requires rippling through N-1 XOR gates
genvar i;
assign b[N-1] = g[N-1];
for (i=N-2; i >= 0; i--) begin:g2b
assign b[i] = g[i] ^ b[i+1];
end
endmodule

View File

@ -39,6 +39,7 @@ module uncore (
input logic TIMECLK,
input logic [31:0] HADDR,
input logic [`AHBW-1:0] HWDATA,
input logic [`XLEN/8-1:0] HWSTRB,
input logic HWRITE,
input logic [2:0] HSIZE,
input logic [2:0] HBURST,
@ -93,8 +94,6 @@ module uncore (
logic HRESPBRIDGE, HREADYBRIDGE, HSELBRIDGE, HSELBRIDGED;
// *** to do:
// combinational loop related to HREADY, HREADYOUT through PENABLE
// hook up and test GPIO on AHB
// hook up HWSTRB and remove subword write decoders
// add other peripherals on AHB
// HTRANS encoding
@ -109,13 +108,10 @@ module uncore (
// AHB -> APB bridge
ahbapbbridge #(2) ahbapbbridge
(.HCLK, .HRESETn, .HSEL({1'b0, HSELGPIO}), .HADDR, .HWDATA, .HWRITE, .HTRANS, .HREADY, .HWSTRB('1),
(.HCLK, .HRESETn, .HSEL({HSELCLINT, HSELGPIO}), .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HTRANS, .HREADY,
.HRDATA(HREADBRIDGE), .HRESP(HRESPBRIDGE), .HREADYOUT(HREADYBRIDGE),
.PCLK, .PRESETn, .PSEL, .PWRITE, .PENABLE, .PADDR, .PWDATA, .PSTRB, .PREADY, .PRDATA);
assign PREADY[1] = 0; // *** replace these with connections to other peripherals
assign PRDATA[1] = 0;
assign HSELBRIDGE = HSELGPIO; // if any of the bridge signals are selected
// This system is showing a combinatonal loop related to HREADY and HREADYBRIDGE and HREADYGPIO
assign HSELBRIDGE = HSELGPIO | HSELCLINT; // if any of the bridge signals are selected
// on-chip RAM
if (`RAM_SUPPORTED) begin : ram
@ -140,13 +136,18 @@ module uncore (
// memory-mapped I/O peripherals
if (`CLINT_SUPPORTED == 1) begin : clint
clint clint(
/* clint clint(
.HCLK, .HRESETn, .TIMECLK,
.HSELCLINT, .HADDR(HADDR[15:0]), .HWRITE,
.HWDATA, .HREADY, .HTRANS, .HSIZED,
.HREADCLINT,
.HRESPCLINT, .HREADYCLINT,
.MTIME(MTIME_CLINT),
.MTimerInt, .MSwInt);*/
clint_apb clint(
.PCLK, .PRESETn, .PSEL(PSEL[1]), .PADDR(PADDR[15:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE,
.PRDATA(PRDATA[1]), .PREADY(PREADY[1]),
.MTIME(MTIME_CLINT),
.MTimerInt, .MSwInt);
end else begin : clint
@ -215,7 +216,7 @@ module uncore (
// AHB Read Multiplexer
assign HRDATA = ({`XLEN{HSELRamD}} & HREADRam) |
({`XLEN{HSELEXTD}} & HRDATAEXT) |
({`XLEN{HSELCLINTD}} & HREADCLINT) |
// ({`XLEN{HSELCLINTD}} & HREADCLINT) |
({`XLEN{HSELPLICD}} & HREADPLIC) |
// ({`XLEN{HSELGPIOD}} & HREADGPIO) |
({`XLEN{HSELBRIDGED}} & HREADBRIDGE) |
@ -225,7 +226,7 @@ module uncore (
assign HRESP = HSELRamD & HRESPRam |
HSELEXTD & HRESPEXT |
HSELCLINTD & HRESPCLINT |
// HSELCLINTD & HRESPCLINT |
HSELPLICD & HRESPPLIC |
// HSELGPIOD & HRESPGPIO |
HSELBRIDGE & HRESPBRIDGE |
@ -235,7 +236,7 @@ module uncore (
assign HREADY = HSELRamD & HREADYRam |
HSELEXTD & HREADYEXT |
HSELCLINTD & HREADYCLINT |
// HSELCLINTD & HREADYCLINT |
HSELPLICD & HREADYPLIC |
// HSELGPIOD & HREADYGPIO |
HSELBRIDGED & HREADYBRIDGE |
@ -244,6 +245,8 @@ module uncore (
HSELSDCD & HREADYSDC |
HSELNoneD; // don't lock up the bus if no region is being accessed
// *** remove HREADYGPIO, others
// Address Decoder Delay (figure 4-2 in spec)
flopr #(9) hseldelayreg(HCLK, ~HRESETn, HSELRegions, {HSELNoneD, HSELEXTD, HSELBootRomD, HSELRamD, HSELCLINTD, HSELGPIOD, HSELUARTD, HSELPLICD, HSELSDCD});
flopr #(1) hselbridgedelayreg(HCLK, ~HRESETn, HSELBRIDGE, HSELBRIDGED);

View File

@ -42,6 +42,7 @@ module wallypipelinedcore (
output logic HCLK, HRESETn,
output logic [31:0] HADDR,
output logic [`AHBW-1:0] HWDATA,
output logic [`XLEN/8-1:0] HWSTRB,
output logic HWRITE,
output logic [2:0] HSIZE,
output logic [2:0] HBURST,
@ -115,6 +116,8 @@ module wallypipelinedcore (
logic [1:0] PageType;
logic sfencevmaM, wfiM, IntPendingM;
logic SelHPTW;
logic [`XLEN/8-1:0] ByteMaskM;
// PMA checker signals
var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0];
@ -263,6 +266,7 @@ module wallypipelinedcore (
// connected to ahb (all stay the same)
.LSUBusAdr, .LSUBusRead, .LSUBusWrite, .LSUBusAck, .LSUBusInit,
.LSUBusHRDATA, .LSUBusHWDATA, .LSUBusSize, .LSUBurstType, .LSUTransType, .LSUTransComplete,
.ByteMaskM,
// connect to csr or privilege and stay the same.
.PrivilegeModeW, .BigEndianM, // connects to csr
@ -309,9 +313,10 @@ module wallypipelinedcore (
.LSUTransComplete,
.LSUBusAck,
.LSUBusInit,
.ByteMaskM,
.HRDATA, .HREADY, .HRESP, .HCLK, .HRESETn,
.HADDR, .HWDATA, .HWRITE, .HSIZE, .HBURST,
.HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST,
.HPROT, .HTRANS, .HMASTLOCK, .HADDRD, .HSIZED,
.HWRITED);

View File

@ -48,6 +48,7 @@ module wallypipelinedsoc (
output logic HCLK, HRESETn,
output logic [31:0] HADDR,
output logic [`AHBW-1:0] HWDATA,
output logic [`XLEN/8-1:0] HWSTRB,
output logic HWRITE,
output logic [2:0] HSIZE,
output logic [2:0] HBURST,
@ -79,6 +80,7 @@ module wallypipelinedsoc (
logic [3:0] HSIZED;
logic HWRITED;
// synchronize reset to SOC clock domain
synchronizer resetsync(.clk, .d(reset_ext), .q(reset));
@ -86,13 +88,13 @@ module wallypipelinedsoc (
wallypipelinedcore core(.clk, .reset,
.MTimerInt, .MExtInt, .SExtInt, .MSwInt,
.MTIME_CLINT,
.HRDATA, .HREADY, .HRESP, .HCLK, .HRESETn, .HADDR, .HWDATA,
.HRDATA, .HREADY, .HRESP, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB,
.HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK,
.HADDRD, .HSIZED, .HWRITED
);
uncore uncore(.HCLK, .HRESETn, .TIMECLK,
.HADDR, .HWDATA, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HRDATAEXT,
.HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HRDATAEXT,
.HREADYEXT, .HRESPEXT, .HRDATA, .HREADY, .HRESP, .HADDRD, .HSIZED, .HWRITED,
.MTimerInt, .MSwInt, .MExtInt, .SExtInt, .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn, .UARTSin, .UARTSout, .MTIME_CLINT,
.HSELEXT,