forked from Github_Repos/cvw
Moved HWSTRB to ahblite, factored out of peripherals. Moved old AHB peripherals to unusedsrc
This commit is contained in:
parent
1ce0975366
commit
381f3298d8
@ -157,7 +157,10 @@ 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;
|
||||
//assign HWSTRB = ByteMaskM;
|
||||
// Byte mask for HWSTRB
|
||||
swbytemask swbytemask(.Size(HSIZED[1:0]), .Adr(HADDRD[2:0]), .ByteMask(HWSTRB));
|
||||
|
||||
// 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
|
||||
|
@ -1,261 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// clint.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 (
|
||||
input logic HCLK, HRESETn, TIMECLK,
|
||||
input logic HSELCLINT,
|
||||
input logic [15:0] HADDR,
|
||||
input logic [3:0] HSIZED,
|
||||
input logic HWRITE,
|
||||
input logic [`XLEN-1:0] HWDATA,
|
||||
input logic HREADY,
|
||||
input logic [1:0] HTRANS,
|
||||
output logic [`XLEN-1:0] HREADCLINT,
|
||||
output logic HRESPCLINT, HREADYCLINT,
|
||||
(* mark_debug = "true" *) output logic [63:0] MTIME,
|
||||
output logic MTimerInt, MSwInt);
|
||||
|
||||
logic MSIP;
|
||||
|
||||
logic [15:0] entry, entryd;
|
||||
logic memwrite;
|
||||
logic initTrans;
|
||||
(* mark_debug = "true" *) logic [63:0] MTIMECMP;
|
||||
logic [`XLEN/8-1:0] ByteMaskM;
|
||||
integer i, j;
|
||||
|
||||
assign initTrans = HREADY & HSELCLINT & (HTRANS != 2'b00);
|
||||
// entryd and memwrite are delayed by a cycle because AHB controller waits a cycle before outputting write data
|
||||
flopr #(1) memwriteflop(HCLK, ~HRESETn, initTrans & HWRITE, memwrite);
|
||||
flopr #(16) entrydflop(HCLK, ~HRESETn, entry, entryd);
|
||||
|
||||
assign HRESPCLINT = 0; // OK
|
||||
assign HREADYCLINT = 1'b1; // *** needs to depend on DONE during asynchronous MTIME accesses
|
||||
|
||||
// word aligned reads
|
||||
if (`XLEN==64) assign #2 entry = {HADDR[15:3], 3'b000};
|
||||
else assign #2 entry = {HADDR[15:2], 2'b00};
|
||||
|
||||
swbytemask swbytemask(.Size(HSIZED[1:0]), .Adr(entryd[2:0]), .ByteMask(ByteMaskM));
|
||||
|
||||
// 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 HCLK) begin
|
||||
case(entry)
|
||||
16'h0000: HREADCLINT <= {63'b0, MSIP};
|
||||
16'h4000: HREADCLINT <= MTIMECMP;
|
||||
16'hBFF8: HREADCLINT <= MTIME;
|
||||
default: HREADCLINT <= 0;
|
||||
endcase
|
||||
end
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) 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 (entryd == 16'h0000) MSIP <= HWDATA[0];
|
||||
if (entryd == 16'h4000) begin
|
||||
for(i=0;i<`XLEN/8;i++)
|
||||
if(ByteMaskM[i])
|
||||
MTIMECMP[i*8 +: 8] <= HWDATA[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(HCLK, HRESETn, TIMECLK, memwrite & (entryd==16'hBFF8), 1'b0, HWDATA, MTIME, done);
|
||||
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MTIME <= 0;
|
||||
end else if (memwrite & entryd == 16'hBFF8) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
for(j=0;j<`XLEN/8;j++)
|
||||
if(ByteMaskM[j])
|
||||
MTIME[j*8 +: 8] <= HWDATA[j*8 +: 8];
|
||||
end else MTIME <= MTIME + 1;
|
||||
end else begin:clint // 32-bit
|
||||
always @(posedge HCLK) begin
|
||||
case(entry)
|
||||
16'h0000: HREADCLINT <= {31'b0, MSIP};
|
||||
16'h4000: HREADCLINT <= MTIMECMP[31:0];
|
||||
16'h4004: HREADCLINT <= MTIMECMP[63:32];
|
||||
16'hBFF8: HREADCLINT <= MTIME[31:0];
|
||||
16'hBFFC: HREADCLINT <= MTIME[63:32];
|
||||
default: HREADCLINT <= 0;
|
||||
endcase
|
||||
end
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MSIP <= 0;
|
||||
MTIMECMP <= 0;
|
||||
// MTIMECMP is not reset ***?
|
||||
end else if (memwrite) begin
|
||||
if (entryd == 16'h0000) MSIP <= HWDATA[0];
|
||||
if (entryd == 16'h4000)
|
||||
for(j=0;j<`XLEN/8;j++)
|
||||
if(ByteMaskM[j])
|
||||
MTIMECMP[j*8 +: 8] <= HWDATA[j*8 +: 8];
|
||||
if (entryd == 16'h4004)
|
||||
for(j=0;j<`XLEN/8;j++)
|
||||
if(ByteMaskM[j])
|
||||
MTIMECMP[32 + j*8 +: 8] <= HWDATA[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(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;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite & (entryd == 16'hBFF8)) begin
|
||||
for(i=0;i<`XLEN/8;i++)
|
||||
if(ByteMaskM[i])
|
||||
MTIME[i*8 +: 8] <= HWDATA[i*8 +: 8];
|
||||
end else if (memwrite & (entryd == 16'hBFFC)) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
for(i=0;i<`XLEN/8;i++)
|
||||
if(ByteMaskM[i])
|
||||
MTIME[32 + i*8 +: 8]<= HWDATA[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 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
|
||||
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
|
||||
*/
|
@ -1,161 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// gpio.sv
|
||||
//
|
||||
// Written: David_Harris@hmc.edu 14 January 2021
|
||||
// Modified: bbracker@hmc.edu 15 Apr. 2021
|
||||
//
|
||||
// Purpose: General Purpose I/O peripheral
|
||||
// See FE310-G002-Manual-v19p05 for specifications
|
||||
// No interrupts, drive strength, or pull-ups supported
|
||||
//
|
||||
// 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 gpio (
|
||||
input logic HCLK, HRESETn,
|
||||
input logic HSELGPIO,
|
||||
input logic [7:0] HADDR,
|
||||
input logic [`XLEN-1:0] HWDATA,
|
||||
input logic HWRITE,
|
||||
input logic HREADY,
|
||||
input logic [1:0] HTRANS,
|
||||
output logic [`XLEN-1:0] HREADGPIO,
|
||||
output logic HRESPGPIO, HREADYGPIO,
|
||||
input logic [31:0] GPIOPinsIn,
|
||||
output logic [31:0] GPIOPinsOut, GPIOPinsEn,
|
||||
output logic GPIOIntr);
|
||||
|
||||
logic [31:0] input0d, input1d, input2d, input3d;
|
||||
logic [31:0] input_val, input_en, output_en, output_val;
|
||||
logic [31:0] rise_ie, rise_ip, fall_ie, fall_ip, high_ie, high_ip, low_ie, low_ip, out_xor;
|
||||
|
||||
logic initTrans, memwrite;
|
||||
logic [7:0] entry, entryd;
|
||||
logic [31:0] Din, Dout;
|
||||
|
||||
// AHB I/O
|
||||
assign entry = {HADDR[7:2],2'b0};
|
||||
assign initTrans = HREADY & HSELGPIO & (HTRANS != 2'b00);
|
||||
// entryd and memwrite are delayed by a cycle because AHB controller waits a cycle before outputting write data
|
||||
flopr #(1) memwriteflop(HCLK, ~HRESETn, initTrans & HWRITE, memwrite);
|
||||
flopr #(8) entrydflop(HCLK, ~HRESETn, entry, entryd);
|
||||
assign HRESPGPIO = 0; // OK
|
||||
assign HREADYGPIO = 1'b1; // GPIO never takes >1 cycle to respond
|
||||
|
||||
// account for subword read/write circuitry
|
||||
// -- Note GPIO registers are 32 bits no matter what; access them with LW SW.
|
||||
// (At least that's what I think when FE310 spec says "only naturally aligned 32-bit accesses are supported")
|
||||
if (`XLEN == 64) begin
|
||||
assign Din = entryd[2] ? HWDATA[63:32] : HWDATA[31:0];
|
||||
assign HREADGPIO = entryd[2] ? {Dout,32'b0} : {32'b0,Dout};
|
||||
end else begin // 32-bit
|
||||
assign Din = HWDATA[31:0];
|
||||
assign HREADGPIO = Dout;
|
||||
end
|
||||
|
||||
// register access
|
||||
always_ff @(posedge HCLK, negedge HRESETn) begin
|
||||
// writes
|
||||
if (~HRESETn) begin
|
||||
// asynch reset
|
||||
input_en <= 0;
|
||||
output_en <= 0;
|
||||
// *** synch reset not yet implemented
|
||||
output_val <= #1 0;
|
||||
rise_ie <= #1 0;
|
||||
rise_ip <= #1 0;
|
||||
fall_ie <= #1 0;
|
||||
fall_ip <= #1 0;
|
||||
high_ie <= #1 0;
|
||||
high_ip <= #1 0;
|
||||
low_ie <= #1 0;
|
||||
low_ip <= #1 0;
|
||||
out_xor <= #1 0;
|
||||
end else begin
|
||||
// writes
|
||||
if (memwrite)
|
||||
// According to FE310 spec: Once the interrupt is pending, it will remain set until a 1 is written to the *_ip register at that bit.
|
||||
/* verilator lint_off CASEINCOMPLETE */
|
||||
case(entryd)
|
||||
8'h04: input_en <= #1 Din;
|
||||
8'h08: output_en <= #1 Din;
|
||||
8'h0C: output_val <= #1 Din;
|
||||
8'h18: rise_ie <= #1 Din;
|
||||
8'h20: fall_ie <= #1 Din;
|
||||
8'h28: high_ie <= #1 Din;
|
||||
8'h30: low_ie <= #1 Din;
|
||||
8'h40: out_xor <= #1 Din;
|
||||
endcase
|
||||
/* verilator lint_on CASEINCOMPLETE */
|
||||
// reads
|
||||
case(entry)
|
||||
8'h00: Dout <= #1 input_val;
|
||||
8'h04: Dout <= #1 input_en;
|
||||
8'h08: Dout <= #1 output_en;
|
||||
8'h0C: Dout <= #1 output_val;
|
||||
8'h18: Dout <= #1 rise_ie;
|
||||
8'h1C: Dout <= #1 rise_ip;
|
||||
8'h20: Dout <= #1 fall_ie;
|
||||
8'h24: Dout <= #1 fall_ip;
|
||||
8'h28: Dout <= #1 high_ie;
|
||||
8'h2C: Dout <= #1 high_ip;
|
||||
8'h30: Dout <= #1 low_ie;
|
||||
8'h34: Dout <= #1 low_ip;
|
||||
8'h40: Dout <= #1 out_xor;
|
||||
default: Dout <= #1 0;
|
||||
endcase
|
||||
// interrupts
|
||||
if (memwrite & (entryd == 8'h1C))
|
||||
rise_ip <= rise_ip & ~Din;
|
||||
else
|
||||
rise_ip <= rise_ip | (input2d & ~input3d);
|
||||
if (memwrite & (entryd == 8'h24))
|
||||
fall_ip <= fall_ip & ~Din;
|
||||
else
|
||||
fall_ip <= fall_ip | (~input2d & input3d);
|
||||
if (memwrite & (entryd == 8'h2C))
|
||||
high_ip <= high_ip & ~Din;
|
||||
else
|
||||
high_ip <= high_ip | input3d;
|
||||
if (memwrite & (entryd == 8'h34))
|
||||
low_ip <= low_ip & ~Din;
|
||||
else
|
||||
low_ip <= low_ip | ~input3d;
|
||||
end
|
||||
end
|
||||
|
||||
// chip i/o
|
||||
// connect OUT to IN for loopback testing
|
||||
if (`GPIO_LOOPBACK_TEST) assign input0d = ((output_en & GPIOPinsOut) | (~output_en & GPIOPinsIn)) & input_en;
|
||||
else assign input0d = GPIOPinsIn & input_en;
|
||||
flop #(32) sync1(HCLK,input0d,input1d);
|
||||
flop #(32) sync2(HCLK,input1d,input2d);
|
||||
flop #(32) sync3(HCLK,input2d,input3d);
|
||||
assign input_val = input3d;
|
||||
assign GPIOPinsOut = output_val ^ out_xor;
|
||||
assign GPIOPinsEn = output_en;
|
||||
|
||||
assign GPIOIntr = |{(rise_ip & rise_ie),(fall_ip & fall_ie),(high_ip & high_ie),(low_ip & low_ie)};
|
||||
endmodule
|
||||
|
@ -1,261 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// plic.sv
|
||||
//
|
||||
// Written: bbracker@hmc.edu 18 January 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: Platform-Level Interrupt Controller
|
||||
// Based on RISC-V spec (https://github.com/riscv/riscv-plic-spec/blob/master/riscv-plic.adoc)
|
||||
// With clarifications from ROA's existing implementation (https://roalogic.github.io/plic/docs/AHB-Lite_PLIC_Datasheet.pdf)
|
||||
// Supports only 1 target core and only a global threshold.
|
||||
//
|
||||
// *** Big questions:
|
||||
// Do we detect requests as level-triggered or edge-trigged?
|
||||
// If edge-triggered, do we want to allow 1 source to be able to make a number of repeated requests?
|
||||
//
|
||||
// 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"
|
||||
|
||||
`define N `PLIC_NUM_SRC
|
||||
// number of interrupt sources
|
||||
// does not include source 0, which does not connect to anything according to spec
|
||||
// up to 63 sources supported; *** in the future, allow up to 1023 sources
|
||||
|
||||
`define C 2
|
||||
// number of conexts
|
||||
// hardcoded to 2 contexts for now; *** later upgrade to arbitrary (up to 15872) contexts
|
||||
|
||||
module plic (
|
||||
input logic HCLK, HRESETn,
|
||||
input logic HSELPLIC,
|
||||
input logic [27:0] HADDR, // *** could factor out entryd into HADDRd at the level of uncore
|
||||
input logic HWRITE,
|
||||
input logic HREADY,
|
||||
input logic [1:0] HTRANS,
|
||||
input logic [`XLEN-1:0] HWDATA,
|
||||
input logic UARTIntr,GPIOIntr,
|
||||
output logic [`XLEN-1:0] HREADPLIC,
|
||||
output logic HRESPPLIC, HREADYPLIC,
|
||||
(* mark_debug = "true" *) output logic MExtInt, SExtInt);
|
||||
|
||||
logic memwrite, memread, initTrans;
|
||||
logic [23:0] entry, entryd;
|
||||
logic [31:0] Din, Dout;
|
||||
|
||||
// context-independent signals
|
||||
(* mark_debug = "true" *) logic [`N:1] requests;
|
||||
(* mark_debug = "true" *) logic [`N:1][2:0] intPriority;
|
||||
(* mark_debug = "true" *) logic [`N:1] intInProgress, intPending, nextIntPending;
|
||||
|
||||
// context-dependent signals
|
||||
logic [`C-1:0][2:0] intThreshold;
|
||||
(* mark_debug = "true" *) logic [`C-1:0][`N:1] intEn;
|
||||
logic [`C-1:0][5:0] intClaim; // ID's are 6 bits if we stay within 63 sources
|
||||
(* mark_debug = "true" *) logic [`C-1:0][7:1][`N:1] irqMatrix;
|
||||
logic [`C-1:0][7:1] priorities_with_irqs;
|
||||
logic [`C-1:0][7:1] max_priority_with_irqs;
|
||||
logic [`C-1:0][`N:1] irqs_at_max_priority;
|
||||
logic [`C-1:0][7:1] threshMask;
|
||||
|
||||
// =======
|
||||
// AHB I/O
|
||||
// =======
|
||||
assign entry = {HADDR[23:2],2'b0};
|
||||
assign initTrans = HREADY & HSELPLIC & (HTRANS != 2'b00);
|
||||
assign memread = initTrans & ~HWRITE;
|
||||
// entryd and memwrite are delayed by a cycle because AHB controller waits a cycle before outputting write data
|
||||
flopr #(1) memwriteflop(HCLK, ~HRESETn, initTrans & HWRITE, memwrite);
|
||||
flopr #(24) entrydflop(HCLK, ~HRESETn, entry, entryd);
|
||||
assign HRESPPLIC = 0; // OK
|
||||
assign HREADYPLIC = 1'b1; // PLIC never takes >1 cycle to respond
|
||||
|
||||
// account for subword read/write circuitry
|
||||
// -- Note PLIC registers are 32 bits no matter what; access them with LW SW.
|
||||
if (`XLEN == 64) begin
|
||||
assign Din = entryd[2] ? HWDATA[63:32] : HWDATA[31:0];
|
||||
assign HREADPLIC = entryd[2] ? {Dout,32'b0} : {32'b0,Dout};
|
||||
end else begin // 32-bit
|
||||
assign HREADPLIC = Dout;
|
||||
assign Din = HWDATA[31:0];
|
||||
end
|
||||
|
||||
// ==================
|
||||
// Register Interface
|
||||
// ==================
|
||||
always @(posedge HCLK,negedge HRESETn) begin
|
||||
// resetting
|
||||
if (~HRESETn) begin
|
||||
intPriority <= #1 {`N{3'b0}};
|
||||
intEn <= #1 {2{`N'b0}};
|
||||
intThreshold <= #1 {2{3'b0}};
|
||||
intInProgress <= #1 `N'b0;
|
||||
// writing
|
||||
end else begin
|
||||
if (memwrite)
|
||||
casez(entryd)
|
||||
24'h0000??: intPriority[entryd[7:2]] <= #1 Din[2:0];
|
||||
`ifdef PLIC_NUM_SRC_LT_32 // *** switch to a generate for loop so as to deprecate PLIC_NUM_SRC_LT_32 and allow up to 1023 sources
|
||||
24'h002000: intEn[0][`N:1] <= #1 Din[`N:1];
|
||||
24'h002080: intEn[1][`N:1] <= #1 Din[`N:1];
|
||||
`endif
|
||||
`ifndef PLIC_NUM_SRC_LT_32
|
||||
24'h002000: intEn[0][31:1] <= #1 Din[31:1];
|
||||
24'h002004: intEn[0][`N:32] <= #1 Din[31:0];
|
||||
24'h002080: intEn[1][31:1] <= #1 Din[31:1];
|
||||
24'h002084: intEn[1][`N:32] <= #1 Din[31:0];
|
||||
`endif
|
||||
24'h200000: intThreshold[0] <= #1 Din[2:0];
|
||||
24'h200004: intInProgress <= #1 intInProgress & ~(`N'b1 << (Din[5:0]-1)); // lower "InProgress" to signify completion
|
||||
24'h201000: intThreshold[1] <= #1 Din[2:0];
|
||||
24'h201004: intInProgress <= #1 intInProgress & ~(`N'b1 << (Din[5:0]-1)); // lower "InProgress" to signify completion
|
||||
endcase
|
||||
// reading
|
||||
if (memread)
|
||||
casez(entry)
|
||||
24'h0000??: Dout <= #1 {29'b0,intPriority[entry[7:2]]};
|
||||
`ifdef PLIC_NUM_SRC_LT_32
|
||||
24'h001000: Dout <= #1 {{(31-`N){1'b0}},intPending,1'b0};
|
||||
24'h002000: Dout <= #1 {{(31-`N){1'b0}},intEn[0],1'b0};
|
||||
24'h002080: Dout <= #1 {{(31-`N){1'b0}},intEn[1],1'b0};
|
||||
`endif
|
||||
`ifndef PLIC_NUM_SRC_LT_32
|
||||
24'h001000: Dout <= #1 {intPending[31:1],1'b0};
|
||||
24'h001004: Dout <= #1 {{(63-`N){1'b0}},intPending[`N:32]};
|
||||
24'h002000: Dout <= #1 {intEn[0][31:1],1'b0};
|
||||
24'h002004: Dout <= #1 {{(63-`N){1'b0}},intEn[0][`N:32]};
|
||||
24'h002080: Dout <= #1 {intEn[0][31:1],1'b0};
|
||||
24'h002084: Dout <= #1 {{(63-`N){1'b0}},intEn[1][`N:32]};
|
||||
`endif
|
||||
24'h200000: Dout <= #1 {29'b0,intThreshold[0]};
|
||||
24'h200004: begin
|
||||
Dout <= #1 {26'b0,intClaim[0]};
|
||||
intInProgress <= #1 intInProgress | (`N'b1 << (intClaim[0]-1)); // claimed requests are currently in progress of being serviced until they are completed
|
||||
end
|
||||
24'h201000: Dout <= #1 {29'b0,intThreshold[1]};
|
||||
24'h201004: begin
|
||||
Dout <= #1 {26'b0,intClaim[1]};
|
||||
intInProgress <= #1 intInProgress | (`N'b1 << (intClaim[1]-1)); // claimed requests are currently in progress of being serviced until they are completed
|
||||
end
|
||||
default: Dout <= #1 32'h0; // invalid access
|
||||
endcase
|
||||
else
|
||||
Dout <= #1 32'h0;
|
||||
end
|
||||
end
|
||||
|
||||
// connect sources to requests
|
||||
always_comb begin
|
||||
requests = `N'b0;
|
||||
`ifdef PLIC_GPIO_ID
|
||||
requests[`PLIC_GPIO_ID] = GPIOIntr;
|
||||
`endif
|
||||
`ifdef PLIC_UART_ID
|
||||
requests[`PLIC_UART_ID] = UARTIntr;
|
||||
`endif
|
||||
end
|
||||
|
||||
// pending interrupt requests
|
||||
//assign nextIntPending = (intPending | requests) & ~intInProgress; //
|
||||
assign nextIntPending = requests; // DH: RT made this change May 2022, but it seems to be a bug to not consider intInProgress; see May 23, 2022 slack discussion
|
||||
flopr #(`N) intPendingFlop(HCLK,~HRESETn,nextIntPending,intPending);
|
||||
|
||||
// context-dependent signals
|
||||
genvar ctx;
|
||||
for (ctx=0; ctx<`C; ctx++) begin
|
||||
// request matrix
|
||||
// priority level (rows) X source ID (columns)
|
||||
//
|
||||
// irqMatrix[ctx][pri][src] is high if source <src>
|
||||
// has priority level <pri> and has an "active" interrupt request
|
||||
// ("active" meaning it is enabled in context <ctx> and is pending)
|
||||
genvar src, pri;
|
||||
for (pri=1; pri<=7; pri++) begin
|
||||
for (src=1; src<=`N; src++) begin
|
||||
assign irqMatrix[ctx][pri][src] = (intPriority[src]==pri) & intPending[src] & intEn[ctx][src];
|
||||
end
|
||||
end
|
||||
|
||||
// which prority levels have one or more active requests?
|
||||
assign priorities_with_irqs[ctx][7:1] = {
|
||||
|irqMatrix[ctx][7],
|
||||
|irqMatrix[ctx][6],
|
||||
|irqMatrix[ctx][5],
|
||||
|irqMatrix[ctx][4],
|
||||
|irqMatrix[ctx][3],
|
||||
|irqMatrix[ctx][2],
|
||||
|irqMatrix[ctx][1]
|
||||
};
|
||||
|
||||
// get the highest priority level that has active requests
|
||||
assign max_priority_with_irqs[ctx][7:1] = {
|
||||
priorities_with_irqs[ctx][7],
|
||||
priorities_with_irqs[ctx][6] & ~|priorities_with_irqs[ctx][7],
|
||||
priorities_with_irqs[ctx][5] & ~|priorities_with_irqs[ctx][7:6],
|
||||
priorities_with_irqs[ctx][4] & ~|priorities_with_irqs[ctx][7:5],
|
||||
priorities_with_irqs[ctx][3] & ~|priorities_with_irqs[ctx][7:4],
|
||||
priorities_with_irqs[ctx][2] & ~|priorities_with_irqs[ctx][7:3],
|
||||
priorities_with_irqs[ctx][1] & ~|priorities_with_irqs[ctx][7:2]
|
||||
};
|
||||
|
||||
// of the sources at the highest priority level that has active requests,
|
||||
// which sources have active requests?
|
||||
assign irqs_at_max_priority[ctx][`N:1] =
|
||||
({`N{max_priority_with_irqs[ctx][7]}} & irqMatrix[ctx][7]) |
|
||||
({`N{max_priority_with_irqs[ctx][6]}} & irqMatrix[ctx][6]) |
|
||||
({`N{max_priority_with_irqs[ctx][5]}} & irqMatrix[ctx][5]) |
|
||||
({`N{max_priority_with_irqs[ctx][4]}} & irqMatrix[ctx][4]) |
|
||||
({`N{max_priority_with_irqs[ctx][3]}} & irqMatrix[ctx][3]) |
|
||||
({`N{max_priority_with_irqs[ctx][2]}} & irqMatrix[ctx][2]) |
|
||||
({`N{max_priority_with_irqs[ctx][1]}} & irqMatrix[ctx][1]);
|
||||
|
||||
// of the sources at the highest priority level that has active requests,
|
||||
// choose the source with the lowest source ID to be the most urgent
|
||||
// and set intClaim to the source ID of the most urgent active request
|
||||
integer k;
|
||||
always_comb begin
|
||||
intClaim[ctx] = 6'b0;
|
||||
for (k=`N; k>0; k--) begin
|
||||
if (irqs_at_max_priority[ctx][k]) intClaim[ctx] = k[5:0];
|
||||
end
|
||||
end
|
||||
|
||||
// create threshold mask
|
||||
always_comb begin
|
||||
threshMask[ctx][7] = (intThreshold[ctx] != 7);
|
||||
threshMask[ctx][6] = (intThreshold[ctx] != 6) & threshMask[ctx][7];
|
||||
threshMask[ctx][5] = (intThreshold[ctx] != 5) & threshMask[ctx][6];
|
||||
threshMask[ctx][4] = (intThreshold[ctx] != 4) & threshMask[ctx][5];
|
||||
threshMask[ctx][3] = (intThreshold[ctx] != 3) & threshMask[ctx][4];
|
||||
threshMask[ctx][2] = (intThreshold[ctx] != 2) & threshMask[ctx][3];
|
||||
threshMask[ctx][1] = (intThreshold[ctx] != 1) & threshMask[ctx][2];
|
||||
end
|
||||
end
|
||||
// is the max priority > threshold?
|
||||
// *** would it be any better to first priority encode maxPriority into binary and then ">" with threshold?
|
||||
assign MExtInt = |(threshMask[0] & priorities_with_irqs[0]);
|
||||
assign SExtInt = |(threshMask[1] & priorities_with_irqs[1]);
|
||||
endmodule
|
||||
|
||||
*/
|
@ -56,16 +56,6 @@ module plic_apb (
|
||||
input logic PENABLE,
|
||||
output logic [`XLEN-1:0] PRDATA,
|
||||
output logic PREADY,
|
||||
/*
|
||||
input logic PCLK, PRESETn,
|
||||
input logic HSELPLIC,
|
||||
input logic [27:0] HADDR, // *** could factor out entry into HADDRd at the level of uncore
|
||||
input logic HWRITE,
|
||||
input logic HREADY,
|
||||
input logic [1:0] HTRANS,
|
||||
input logic [`XLEN-1:0] HWDATA,
|
||||
output logic [`XLEN-1:0] PRDATA,
|
||||
output logic HRESPPLIC, HREADYPLIC, */
|
||||
input logic UARTIntr,GPIOIntr,
|
||||
(* mark_debug = "true" *) output logic MExtInt, SExtInt);
|
||||
|
||||
@ -96,14 +86,6 @@ module plic_apb (
|
||||
assign memread = ~PWRITE & PSEL; // read at start of access phase. PENABLE hasn't set up before this
|
||||
assign PREADY = 1'b1; // PLIC never takes >1 cycle to respond
|
||||
assign entry = {PADDR[23:2],2'b0};
|
||||
/*
|
||||
assign initTrans = HREADY & HSELPLIC & (HTRANS != 2'b00);
|
||||
assign memread = initTrans & ~HWRITE;
|
||||
// entryd and memwrite are delayed by a cycle because AHB controller waits a cycle before outputting write data
|
||||
flopr #(1) memwriteflop(PCLK, ~HRESETn, initTrans & HWRITE, memwrite);
|
||||
flopr #(24) entrydflop(PCLK, ~PRESETn, entry, entryd);
|
||||
assign HRESPPLIC = 0; // OK
|
||||
assign HREADYPLIC = 1'b1; // PLIC never takes >1 cycle to respond */
|
||||
|
||||
// account for subword read/write circuitry
|
||||
// -- Note PLIC registers are 32 bits no matter what; access them with LW SW.
|
||||
|
@ -39,7 +39,6 @@ module ram #(parameter BASE=0, RANGE = 65535) (
|
||||
input logic [1:0] HTRANS,
|
||||
input logic [`XLEN-1:0] HWDATA,
|
||||
input logic [`XLEN/8-1:0] HWSTRB,
|
||||
input logic [3:0] HSIZED,
|
||||
output logic [`XLEN-1:0] HREADRam,
|
||||
output logic HRESPRam, HREADYRam
|
||||
);
|
||||
@ -70,17 +69,8 @@ module ram #(parameter BASE=0, RANGE = 65535) (
|
||||
// On writes or during a wait state, use address delayed by one cycle to sync RamAddr with HWDATA or hold stalled address
|
||||
mux2 #(32) adrmux(HADDR, HADDRD, memwriteD | ~HREADY, RamAddr);
|
||||
|
||||
// Byte mask for subword writes
|
||||
// ***the CLINT and other peripherals duplicate this hardware
|
||||
// *** it shoudl be centralized and sent over HWSTRB
|
||||
swbytemask swbytemask(.Size(HSIZED[1:0]), .Adr(HADDRD[2:0]), .ByteMask(ByteMask));
|
||||
|
||||
always @(posedge HCLK) begin
|
||||
assert (ByteMask == HWSTRB | ~memwriteD) else $display("HSIZED %b HADDRD %b ByteMask %b HWSTRB %b\n", HSIZED[1:0], HADDRD[2:0], ByteMask, HWSTRB);
|
||||
end
|
||||
|
||||
// single-ported RAM
|
||||
bram1p1rw #(`XLEN/8, 8, ADDR_WIDTH)
|
||||
memory(.clk(HCLK), .we(memwriteD), /*.bwe(HWSTRB), */ .bwe(ByteMask), .addr(RamAddr[ADDR_WIDTH+OFFSET-1:OFFSET]), .dout(HREADRam), .din(HWDATA));
|
||||
memory(.clk(HCLK), .we(memwriteD), .bwe(HWSTRB), .addr(RamAddr[ADDR_WIDTH+OFFSET-1:OFFSET]), .dout(HREADRam), .din(HWDATA));
|
||||
endmodule
|
||||
|
||||
|
@ -1,107 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// ram_orig.sv
|
||||
//
|
||||
// Written: David_Harris@hmc.edu 9 January 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: On-chip RAM, external to core
|
||||
//
|
||||
// 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 ram_orig #(parameter BASE=0, RANGE = 65535) (
|
||||
input logic HCLK, HRESETn,
|
||||
input logic HSELRam,
|
||||
input logic [31:0] HADDR,
|
||||
input logic HWRITE,
|
||||
input logic HREADY,
|
||||
input logic [1:0] HTRANS,
|
||||
input logic [`XLEN-1:0] HWDATA,
|
||||
input logic [3:0] HSIZED,
|
||||
output logic [`XLEN-1:0] HREADRam,
|
||||
output logic HRESPRam, HREADYRam
|
||||
);
|
||||
|
||||
// Desired changes.
|
||||
// 1. find a way to merge read and write address into 1 port.
|
||||
// 2. remove all unnecessary latencies. (HREADY needs to be able to constant high.)
|
||||
// 3. implement burst.
|
||||
// 4. remove the configurable latency.
|
||||
|
||||
logic [`XLEN/8-1:0] ByteMaskM;
|
||||
logic [31:0] HWADDR, A;
|
||||
logic prevHREADYRam, risingHREADYRam;
|
||||
logic initTrans;
|
||||
logic memwrite;
|
||||
logic [3:0] busycount;
|
||||
|
||||
swbytemask swbytemask(.Size(HSIZED[1:0]), .Adr(HWADDR[2:0]), .ByteMask(ByteMaskM));
|
||||
|
||||
assign initTrans = HREADY & HSELRam & (HTRANS != 2'b00);
|
||||
|
||||
// *** this seems like a weird way to use reset
|
||||
flopenr #(1) memwritereg(HCLK, 1'b0, initTrans | ~HRESETn, HSELRam & HWRITE, memwrite);
|
||||
flopenr #(32) haddrreg(HCLK, 1'b0, initTrans | ~HRESETn, HADDR, A);
|
||||
|
||||
// busy FSM to extend READY signal
|
||||
always @(posedge HCLK, negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
busycount <= 0;
|
||||
HREADYRam <= #1 0;
|
||||
end else begin
|
||||
if (initTrans) begin
|
||||
busycount <= 0;
|
||||
HREADYRam <= #1 0;
|
||||
end else if (~HREADYRam) begin
|
||||
if (busycount == 0) begin // Ram latency, for testing purposes. *** test with different values such as 2
|
||||
HREADYRam <= #1 1;
|
||||
end else begin
|
||||
busycount <= busycount + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
assign HRESPRam = 0; // OK
|
||||
|
||||
localparam ADDR_WDITH = $clog2(RANGE/8);
|
||||
localparam OFFSET = $clog2(`XLEN/8);
|
||||
|
||||
// Rising HREADY edge detector
|
||||
// Indicates when ram is finishing up
|
||||
// Needed because HREADY may go high for other reasons,
|
||||
// and we only want to write data when finishing up.
|
||||
flopenr #(1) prevhreadyRamreg(HCLK,~HRESETn, 1'b1, HREADYRam,prevHREADYRam);
|
||||
assign risingHREADYRam = HREADYRam & ~prevHREADYRam;
|
||||
|
||||
always @(posedge HCLK)
|
||||
HWADDR <= #1 A;
|
||||
|
||||
bram2p1r1w #(`XLEN/8, 8, ADDR_WDITH, `FPGA)
|
||||
memory(.clk(HCLK), .reA(1'b1),
|
||||
.addrA(A[ADDR_WDITH+OFFSET-1:OFFSET]), .doutA(HREADRam),
|
||||
.weB(memwrite & risingHREADYRam), .bweB(ByteMaskM),
|
||||
.addrB(HWADDR[ADDR_WDITH+OFFSET-1:OFFSET]), .dinB(HWDATA));
|
||||
|
||||
|
||||
endmodule
|
||||
|
@ -144,7 +144,7 @@ module SDC
|
||||
|
||||
// currently does not support writes
|
||||
|
||||
assign InitTrans = HREADY & HSELSDC & (HTRANS != 2'b00);
|
||||
assign InitTrans = HREADY & HSELSDC & HTRANS[1];
|
||||
//assign RegRead = InitTrans & ~HWRITE;
|
||||
// register resolve combo loop
|
||||
flopr #(1) RegReadReg(HCLK, ~HRESETn, InitTrans & ~HWRITE, RegRead);
|
||||
|
@ -1,107 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// uart.sv
|
||||
//
|
||||
// Written: David_Harris@hmc.edu 21 January 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: Interface to Universial Asynchronous Receiver/ Transmitter with FIFOs
|
||||
// Emulates interface of Texas Instruments PC165550D
|
||||
// Compatible with UART in Imperas Virtio model ***
|
||||
//
|
||||
// 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 uart (
|
||||
input logic HCLK, HRESETn,
|
||||
input logic HSELUART,
|
||||
input logic [2:0] HADDR,
|
||||
input logic HWRITE,
|
||||
input logic [`XLEN-1:0] HWDATA,
|
||||
output logic [`XLEN-1:0] HREADUART,
|
||||
output logic HRESPUART, HREADYUART,
|
||||
(* mark_debug = "true" *) input logic SIN, DSRb, DCDb, CTSb, RIb, // from E1A driver from RS232 interface
|
||||
(* mark_debug = "true" *) output logic SOUT, RTSb, DTRb, // to E1A driver to RS232 interface
|
||||
(* mark_debug = "true" *) output logic OUT1b, OUT2b, INTR, TXRDYb, RXRDYb); // to CPU
|
||||
|
||||
// UART interface signals
|
||||
logic [2:0] A;
|
||||
logic MEMRb, MEMWb, memread, memwrite;
|
||||
logic [7:0] Din, Dout;
|
||||
|
||||
// rename processor interface signals to match PC16550D and provide one-byte interface
|
||||
flopr #(1) memreadreg(HCLK, ~HRESETn, (HSELUART & ~HWRITE), memread);
|
||||
flopr #(1) memwritereg(HCLK, ~HRESETn, (HSELUART & HWRITE), memwrite);
|
||||
flopr #(3) haddrreg(HCLK, ~HRESETn, HADDR[2:0], A);
|
||||
assign MEMRb = ~memread;
|
||||
assign MEMWb = ~memwrite;
|
||||
|
||||
assign HRESPUART = 0; // OK
|
||||
assign HREADYUART = 1; // should idle high during address phase and respond high when done; will need to be modified if UART ever needs more than 1 cycle to do something
|
||||
|
||||
if (`XLEN == 64) begin:uart
|
||||
always_comb begin
|
||||
HREADUART = {Dout, Dout, Dout, Dout, Dout, Dout, Dout, Dout};
|
||||
case (A)
|
||||
3'b000: Din = HWDATA[7:0];
|
||||
3'b001: Din = HWDATA[15:8];
|
||||
3'b010: Din = HWDATA[23:16];
|
||||
3'b011: Din = HWDATA[31:24];
|
||||
3'b100: Din = HWDATA[39:32];
|
||||
3'b101: Din = HWDATA[47:40];
|
||||
3'b110: Din = HWDATA[55:48];
|
||||
3'b111: Din = HWDATA[63:56];
|
||||
endcase
|
||||
end
|
||||
end else begin:uart // 32-bit
|
||||
always_comb begin
|
||||
HREADUART = {Dout, Dout, Dout, Dout};
|
||||
case (A[1:0])
|
||||
2'b00: Din = HWDATA[7:0];
|
||||
2'b01: Din = HWDATA[15:8];
|
||||
2'b10: Din = HWDATA[23:16];
|
||||
2'b11: Din = HWDATA[31:24];
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
logic BAUDOUTb; // loop tx clock BAUDOUTb back to rx clock RCLK
|
||||
// *** make sure reads don't occur on UART unless fully selected because they could change state. This applies to all peripherals
|
||||
uartPC16550D u(
|
||||
// Processor Interface
|
||||
.HCLK, .HRESETn,
|
||||
.A, .Din,
|
||||
.Dout,
|
||||
.MEMRb, .MEMWb,
|
||||
.INTR, .TXRDYb, .RXRDYb,
|
||||
// Clocks
|
||||
.BAUDOUTb, .RCLK(BAUDOUTb),
|
||||
// E1A Driver
|
||||
.SIN, .DSRb, .DCDb, .CTSb, .RIb,
|
||||
.SOUT, .RTSb, .DTRb, .OUT1b, .OUT2b
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
*/
|
@ -53,7 +53,6 @@ module uncore (
|
||||
output logic HSELEXT,
|
||||
// delayed signals
|
||||
input logic [2:0] HADDRD,
|
||||
input logic [3:0] HSIZED,
|
||||
input logic HWRITED,
|
||||
// peripheral pins
|
||||
output logic MTimerInt, MSwInt, MExtInt, SExtInt,
|
||||
@ -83,21 +82,14 @@ module uncore (
|
||||
logic SDCIntM;
|
||||
|
||||
logic PCLK, PRESETn, PWRITE, PENABLE;
|
||||
// logic PSEL, PREADY;
|
||||
logic [3:0] PSEL, PREADY;
|
||||
logic [31:0] PADDR;
|
||||
logic [`XLEN-1:0] PWDATA;
|
||||
logic [`XLEN/8-1:0] PSTRB;
|
||||
logic [3:0][`XLEN-1:0] PRDATA;
|
||||
// logic [`XLEN-1:0][8:0] PRDATA;
|
||||
logic [`XLEN-1:0] HREADBRIDGE;
|
||||
logic HRESPBRIDGE, HREADYBRIDGE, HSELBRIDGE, HSELBRIDGED;
|
||||
|
||||
// *** to do:
|
||||
// hook up HWSTRB and remove subword write decoders
|
||||
// add other peripherals on AHB
|
||||
// HTRANS encoding
|
||||
|
||||
// Determine which region of physical memory (if any) is being accessed
|
||||
// Use a trimmed down portion of the PMA checker - only the address decoders
|
||||
// Set access types to all 1 as don't cares because the MMU has already done access checking
|
||||
@ -119,7 +111,7 @@ module uncore (
|
||||
.BASE(`RAM_BASE), .RANGE(`RAM_RANGE)) ram (
|
||||
.HCLK, .HRESETn,
|
||||
.HSELRam, .HADDR,
|
||||
.HWRITE, .HREADY, .HSIZED,
|
||||
.HWRITE, .HREADY,
|
||||
.HTRANS, .HWDATA, .HWSTRB, .HREADRam,
|
||||
.HRESPRam, .HREADYRam);
|
||||
end
|
||||
@ -130,7 +122,7 @@ module uncore (
|
||||
bootrom(
|
||||
.HCLK, .HRESETn,
|
||||
.HSELRam(HSELBootRom), .HADDR,
|
||||
.HWRITE, .HREADY, .HTRANS, .HSIZED,
|
||||
.HWRITE, .HREADY, .HTRANS,
|
||||
.HWDATA, .HWSTRB,
|
||||
.HREADRam(HREADBootRom), .HRESPRam(HRESPBootRom), .HREADYRam(HREADYBootRom));
|
||||
end
|
||||
@ -189,38 +181,26 @@ module uncore (
|
||||
assign SDCCmdOE = 0;
|
||||
end
|
||||
|
||||
// mux could also include external memory
|
||||
// AHB Read Multiplexer
|
||||
assign HRDATA = ({`XLEN{HSELRamD}} & HREADRam) |
|
||||
({`XLEN{HSELEXTD}} & HRDATAEXT) |
|
||||
({`XLEN{HSELEXTD}} & HRDATAEXT) |
|
||||
({`XLEN{HSELBRIDGED}} & HREADBRIDGE) |
|
||||
({`XLEN{HSELBootRomD}} & HREADBootRom) |
|
||||
// ({`XLEN{HSELUARTD}} & HREADUART) |
|
||||
({`XLEN{HSELSDCD}} & HREADSDC);
|
||||
|
||||
assign HRESP = HSELRamD & HRESPRam |
|
||||
HSELEXTD & HRESPEXT |
|
||||
// HSELCLINTD & HRESPCLINT |
|
||||
// HSELPLICD & HRESPPLIC |
|
||||
// HSELGPIOD & HRESPGPIO |
|
||||
HSELBRIDGE & HRESPBRIDGE |
|
||||
HSELBootRomD & HRESPBootRom |
|
||||
// HSELUARTD & HRESPUART |
|
||||
HSELSDC & HRESPSDC;
|
||||
|
||||
assign HREADY = HSELRamD & HREADYRam |
|
||||
HSELEXTD & HREADYEXT |
|
||||
// HSELCLINTD & HREADYCLINT |
|
||||
// HSELPLICD & HREADYPLIC |
|
||||
// HSELGPIOD & HREADYGPIO |
|
||||
HSELBRIDGED & HREADYBRIDGE |
|
||||
HSELBootRomD & HREADYBootRom |
|
||||
// HSELUARTD & HREADYUART |
|
||||
HSELSDCD & HREADYSDC |
|
||||
HSELNoneD; // don't lock up the bus if no region is being accessed
|
||||
|
||||
// *** remove HREADYGPIO, others that are now unused
|
||||
|
||||
// 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);
|
||||
|
@ -95,7 +95,7 @@ module wallypipelinedsoc (
|
||||
|
||||
uncore uncore(.HCLK, .HRESETn, .TIMECLK,
|
||||
.HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, .HRDATAEXT,
|
||||
.HREADYEXT, .HRESPEXT, .HRDATA, .HREADY, .HRESP, .HADDRD, .HSIZED, .HWRITED,
|
||||
.HREADYEXT, .HRESPEXT, .HRDATA, .HREADY, .HRESP, .HADDRD, .HWRITED,
|
||||
.MTimerInt, .MSwInt, .MExtInt, .SExtInt, .GPIOPinsIn, .GPIOPinsOut, .GPIOPinsEn, .UARTSin, .UARTSout, .MTIME_CLINT,
|
||||
.HSELEXT,
|
||||
.SDCCmdOut, .SDCCmdOE, .SDCCmdIn, .SDCDatIn, .SDCCLK
|
||||
|
Loading…
Reference in New Issue
Block a user