Started adding asynchronous TIMECLK for CLINT

This commit is contained in:
David Harris 2022-01-02 21:18:16 +00:00
parent 9d4e1671c9
commit 9693110857
12 changed files with 169 additions and 54 deletions

@ -1 +1 @@
Subproject commit be67c99bd461742aa1c100bcc0732657faae2230
Subproject commit 307c77b26e070ae85ffea665ad9b642b40e33c86

View file

@ -29,8 +29,8 @@
rv32i_sc_tests = \
WALLY-MMU-SV32 \
WALLY-PMA \
WALLY-PMP
# WALLY-PMA \
rv32i_tests = $(addsuffix .elf, $(rv32i_sc_tests))

View file

@ -30,8 +30,8 @@
rv64i_sc_tests = \
WALLY-MMU-SV39 \
WALLY-MMU-SV48 \
WALLY-PMA \
WALLY-PMP
# WALLY-PMP
# WALLY-PMA \
rv64i_tests = $(addsuffix .elf, $(rv64i_sc_tests))

View file

@ -30,6 +30,7 @@
module csrc #(parameter
MHPMCOUNTERBASE = 12'hB00,
MHPMCOUNTERHBASE = 12'hB80,
MHPMEVENTBASE = 12'h320,
HPMCOUNTERBASE = 12'hC00,
HPMCOUNTERHBASE = 12'hC80,
TIME = 12'hC01,
@ -162,3 +163,8 @@ module csrc #(parameter
endgenerate
endmodule
// To Do:
// review couunter spec
// upper unimplemented counters should read as 0 rather than illegal access
// mounteren should only exist if u-mode exists
// Implement MHPMEVENT

View file

@ -27,7 +27,7 @@
`include "wally-config.vh"
module clint (
input logic HCLK, HRESETn,
input logic HCLK, HRESETn, TIMECLK,
input logic HSELCLINT,
input logic [15:0] HADDR,
input logic HWRITE,
@ -52,7 +52,7 @@ module clint (
flopr #(16) entrydflop(HCLK, ~HRESETn, entry, entryd);
assign HRESPCLINT = 0; // OK
assign HREADYCLINT = 1'b1; // will need to be modified if CLINT ever needs more than 1 cycle to do something
assign HREADYCLINT = 1'b1; // *** needs to depend on DONE during accesses
// word aligned reads
generate
@ -70,7 +70,7 @@ module clint (
// register access
generate
if (`XLEN==64) begin:clint
if (`XLEN==64) begin:clint // 64-bit
always @(posedge HCLK) begin
case(entry)
16'h0000: HREADCLINT <= {63'b0, MSIP};
@ -82,14 +82,16 @@ module clint (
always_ff @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin
MSIP <= 0;
MTIMECMP <= (64)'(0);
MTIMECMP <= 0;
// MTIMECMP is not reset
end else if (memwrite) begin
if (entryd == 16'h0000) MSIP <= HWDATA[0];
if (entryd == 16'h4000) MTIMECMP <= HWDATA;
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
end
// eventually replace MTIME logic below with timereg
// timereg tr(HCLK, HRESETn, TIMECLK, memwrite & (entryd==16'hBFF8), 1'b0, HWDATA, MTIME, done);
always_ff @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin
MTIME <= 0;
@ -112,8 +114,8 @@ module clint (
always_ff @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin
MSIP <= 0;
MTIMECMP <= (64)'(0);
// MTIMECMP is not reset
MTIMECMP <= 0;
// MTIMECMP is not reset ***?
end else if (memwrite) begin
if (entryd == 16'h0000) MSIP <= HWDATA[0];
if (entryd == 16'h4000) MTIMECMP[31:0] <= HWDATA;
@ -121,6 +123,8 @@ module clint (
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
end
// eventually replace MTIME logic below with timereg
// timereg tr(HCLK, HRESETn, TIMECLK, memwrite & (entryd==16'hBFF8), memwrite & (entryd == 16'hBFFC), HWDATA, MTIME, done);
always_ff @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin
MTIME <= 0;
@ -141,3 +145,102 @@ module clint (
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 HCLK, HRESETn, TIMECLK,
input logic we0, we1,
input logic [`XLEN-1:0] HWDATA,
output logic [63:0] MTIME,
output logic done);
// if (`TIMEBASE_SYNC) begin:timereg // use HCLK for MTIME
if (1) begin:timereg // use HCLK for MTIME
timregsync timeregsync(.clk(HCLK), .resetn(HRESETn), .we0, .we1, .wd(HWDATA), .q(MTIME));
assign done = 1; // immediately completes
end else begin // use asynchronous TIMECLK
// TIME counter runs on TIMECLK but bus interface runs on HCLK
// 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 HCLK or negedge HRESETn)
if (~HRESETn)
req <= 0; // don't bother resetting wd
else begin
req <= we0 | we1 | req & ~ack;
we0_stored <= we0;
we1_stored <= we1;
wd_stored <= HWDATA;
ack_stored <= ack;
done <= ack_stored & ~ack;
end
// synchronize the reset and reqest into the TIMECLK domain
sync resetsync(TIMECLK, HRESETn, resetn_sync);
sync rsync(TIMECLK, req, req_sync);
// synchronize the acknowledge back to the HCLK domain to indicate the request was handled and can be lowered
sync async(HCLK, 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](HCLK, 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
generate
begin
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
end
endgenerate
endmodule

View file

@ -31,6 +31,7 @@
module uncore (
// AHB Bus Interface
input logic HCLK, HRESETn,
input logic TIMECLK,
input logic [31:0] HADDR,
input logic [`AHBW-1:0] HWDATAIN,
input logic HWRITE,
@ -115,7 +116,7 @@ module uncore (
// memory-mapped I/O peripherals
if (`CLINT_SUPPORTED == 1) begin : clint
clint clint(
.HCLK, .HRESETn,
.HCLK, .HRESETn, .TIMECLK,
.HSELCLINT, .HADDR(HADDR[15:0]), .HWRITE,
.HWDATA, .HREADY, .HTRANS,
.HREADCLINT,

View file

@ -51,6 +51,7 @@ module wallypipelinedsoc (
output logic HMASTLOCK,
output logic HREADY,
// I/O Interface
input logic TIMECLK,
input logic [31:0] GPIOPinsIn,
output logic [31:0] GPIOPinsOut, GPIOPinsEn,
input logic UARTSin,
@ -85,7 +86,7 @@ module wallypipelinedsoc (
.HADDRD, .HSIZED, .HWRITED
);
uncore uncore(.HCLK, .HRESETn,
uncore uncore(.HCLK, .HRESETn, .TIMECLK,
.HADDR, .HWDATAIN(HWDATA), .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HRDATAEXT,
.HREADYEXT, .HRESPEXT, .HRDATA, .HREADY, .HRESP, .HADDRD, .HSIZED, .HWRITED,
.TimerIntM, .SwIntM, .ExtIntM, .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn, .UARTSin, .UARTSout, .MTIME_CLINT,

View file

@ -50,6 +50,7 @@ module wallypipelinedsocwrapper (
output HMASTLOCK,
output HREADY,
// I/O Interface
input TIMECLK,
input [3:0] GPIOPinsIn_IO,
output [4:0] GPIOPinsOut_IO,
input UARTSin,
@ -89,32 +90,33 @@ module wallypipelinedsocwrapper (
// wrapper for fpga
wallypipelinedsoc wallypipelinedsoc
(.clk(clk),
(.clk,
.reset_ext(reset),
.HRDATAEXT(HRDATAEXT),
.HREADYEXT(HREADYEXT),
.HRESPEXT(HRESPEXT),
.HSELEXT(HSELEXT),
.HCLK(HCLK),
.HRESETn(HRESETn),
.HADDR(HADDR),
.HWDATA(HWDATA),
.HWRITE(HWRITE),
.HSIZE(HSIZE),
.HBURST(HBURST),
.HPROT(HPROT),
.HTRANS(HTRANS),
.HMASTLOCK(HMASTLOCK),
.HREADY(HREADY),
.GPIOPinsIn(GPIOPinsIn),
.GPIOPinsOut(GPIOPinsOut),
.GPIOPinsEn(GPIOPinsEn),
.UARTSin(UARTSin),
.UARTSout(UARTSout),
.SDCDatIn(SDCDatIn),
.SDCCLK(SDCCLK),
.SDCCmdIn(SDCCmdIn),
.SDCCmdOut(SDCCmdOut),
.SDCCmdOE(SDCCmdOE));
.HRDATAEXT,
.HREADYEXT,
.HRESPEXT,
.HSELEXT,
.HCLK,
.HRESETn,
.HADDR,
.HWDATA,
.HWRITE,
.HSIZE,
.HBURST,
.HPROT,
.HTRANS,
.HMASTLOCK,
.HREADY,
.TIMECLK,
.GPIOPinsIn,
.GPIOPinsOut,
.GPIOPinsEn,
.UARTSin,
.UARTSout,
.SDCDatIn,
.SDCCLK,
.SDCCmdIn,
.SDCCmdOut,
.SDCCmdOE);
endmodule

View file

@ -74,7 +74,7 @@ module testbench();
assign HRDATAEXT = 0;
wallypipelinedsoc dut(.clk, .reset_ext, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT,
.HCLK, .HRESETn, .HADDR, .HWDATA, .HWRITE, .HSIZE, .HBURST, .HPROT,
.HTRANS, .HMASTLOCK, .HREADY, .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn,
.HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(0), .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn,
.UARTSin, .UARTSout, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn, .SDCCLK);
logic [31:0] InstrW;

View file

@ -602,7 +602,7 @@ string tests32f[] = '{
wallypipelinedsocwrapper dut(.clk, .reset_ext, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT,
.HCLK, .HRESETn, .HADDR, .HWDATA, .HWRITE, .HSIZE, .HBURST, .HPROT,
.HTRANS, .HMASTLOCK, .HREADY, .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn,
.HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(0), .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn,
.UARTSin, .UARTSout, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn, .SDCCLK);
// Track names of instructions

View file

@ -82,7 +82,7 @@ module testbench();
.HRDATAEXT, .HREADYEXT, .HREADY, .HSELEXT, .HRESPEXT, .HCLK,
.HRESETn, .HADDR, .HWDATA, .HWRITE, .HSIZE, .HBURST, .HPROT,
.HTRANS, .HMASTLOCK,
.GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn,
.TIMECLK(0), .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn,
.UARTSin, .UARTSout,
.SDCCLK, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn);

View file

@ -152,7 +152,7 @@ logic [3:0] dummy;
wallypipelinedsoc dut(.clk, .reset_ext, .reset, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT,
.HCLK, .HRESETn, .HADDR, .HWDATA, .HWRITE, .HSIZE, .HBURST, .HPROT,
.HTRANS, .HMASTLOCK, .HREADY, .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn,
.HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn,
.UARTSin, .UARTSout, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn, .SDCCLK);
// Track names of instructions
@ -332,9 +332,9 @@ logic [3:0] dummy;
endmodule
module riscvassertions;
// Legal number of PMP entries are 0, 16, or 64
initial begin
assert (`PMP_ENTRIES == 0 || `PMP_ENTRIES==16 || `PMP_ENTRIES==64) else $error("Illegal number of PMP entries: PMP_ENTRIES must be 0, 16, or 64");
assert (`S_SUPPORTED || `MEM_VIRTMEM == 0) else $error("Virtual memory requires S mode support");
assert (`DIV_BITSPERCYCLE == 1 || `DIV_BITSPERCYCLE==2 || `DIV_BITSPERCYCLE==4) else $error("Illegal number of divider bits/cycle: DIV_BITSPERCYCLE must be 1, 2, or 4");
assert (`F_SUPPORTED || ~`D_SUPPORTED) else $error("Can't support double (D) without supporting float (F)");
assert (`XLEN == 64 || ~`D_SUPPORTED) else $error("Wally does not yet support D extensions on RV32");
@ -352,6 +352,8 @@ module riscvassertions;
assert (2**$clog2(`DTLB_ENTRIES) == `DTLB_ENTRIES || `MEM_VIRTMEM==0) else $error("DTLB_ENTRIES must be a power of 2");
assert (`RAM_RANGE >= 56'h07FFFFFF) else $warning("Some regression tests will fail if RAM_RANGE is less than 56'h07FFFFFF");
assert (`ZICSR_SUPPORTED == 1 || (`PMP_ENTRIES == 0 && `MEM_VIRTMEM == 0)) else $error("PMP_ENTRIES and MEM_VIRTMEM must be zero if ZICSR not supported.");
assert (`ZICSR_SUPPORTED == 1 || (`S_SUPPORTED == 0 && `U_SUPPORTED == 0)) else $error("S and U modes not supported if ZISR not supported");
assert (`U_SUPPORTED || (`S_SUPPORTED == 0)) else $error ("S mode only supported if U also is supported");
end
endmodule