Added ahbapbbridge and cleaning RAM

This commit is contained in:
David Harris 2022-06-08 01:31:34 +00:00
parent 1d41e98504
commit f81719337e
7 changed files with 357 additions and 25 deletions

View File

@ -44,7 +44,7 @@ module bram1p1rw
//---------------------------------------------------------------------- //----------------------------------------------------------------------
) ( ) (
input logic clk, input logic clk,
input logic ena, input logic en,
input logic [NUM_COL-1:0] we, input logic [NUM_COL-1:0] we,
input logic [ADDR_WIDTH-1:0] addr, input logic [ADDR_WIDTH-1:0] addr,
output logic [DATA_WIDTH-1:0] dout, output logic [DATA_WIDTH-1:0] dout,
@ -60,7 +60,7 @@ module bram1p1rw
always @ (posedge clk) begin always @ (posedge clk) begin
dout <= RAM[addr]; dout <= RAM[addr];
if(ena) begin if(en) begin
for(i=0;i<NUM_COL;i=i+1) begin for(i=0;i<NUM_COL;i=i+1) begin
if(we[i]) begin if(we[i]) begin
RAM[addr][i*COL_WIDTH +: COL_WIDTH] <= din[i*COL_WIDTH +:COL_WIDTH]; RAM[addr][i*COL_WIDTH +: COL_WIDTH] <= din[i*COL_WIDTH +:COL_WIDTH];

View File

@ -42,27 +42,7 @@ module simpleram #(parameter BASE=0, RANGE = 65535) (
localparam ADDR_WDITH = $clog2(RANGE/8); localparam ADDR_WDITH = $clog2(RANGE/8);
localparam OFFSET = $clog2(`XLEN/8); localparam OFFSET = $clog2(`XLEN/8);
bram1p1rw #(`XLEN/8, 8, ADDR_WDITH) bram1p1rw #(`XLEN/8, 8, ADDR_WDITH)
memory(.clk, .ena(we), .we(ByteMask), .addr(a[ADDR_WDITH+OFFSET-1:OFFSET]), .dout(rd), .din(wd)); memory(.clk, .en(we), .we(ByteMask), .addr(a[ADDR_WDITH+OFFSET-1:OFFSET]), .dout(rd), .din(wd));
/* -----\/----- EXCLUDED -----\/-----
logic [`XLEN-1:0] RAM[BASE>>(1+`XLEN/32):(RANGE+BASE)>>1+(`XLEN/32)];
// discard bottom 2 or 3 bits of address offset within word or doubleword
localparam adrlsb = (`XLEN==64) ? 3 : 2;
logic [31:adrlsb] adrmsbs;
assign adrmsbs = a[31:adrlsb];
always_ff @(posedge clk)
rd <= RAM[adrmsbs];
genvar index;
for(index = 0; index < `XLEN/8; index++) begin
always_ff @(posedge clk) begin
if (we & ByteMask[index]) RAM[adrmsbs][8*(index+1)-1:8*index] <= #1 wd[8*(index+1)-1:8*index];
end
end
-----/\----- EXCLUDED -----/\----- */
endmodule endmodule

View File

@ -0,0 +1,98 @@
///////////////////////////////////////////
// ahbapbbridge.sv
//
// Written: David_Harris@hmc.edu & Nic Lucio 7 June 2022
//
// Purpose: AHB to APB bridge
//
// 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 ahbapbbridge #(PERIPHS = 2) (
input logic HCLK, HRESETn,
input logic [PERIPHS-1:0] HSEL,
input logic [31:0] HADDR,
input logic [`XLEN-1:0] HWDATA,
input logic HWRITE,
input logic [1:0] HTRANS,
input logic HREADY,
output logic [`XLEN-1:0] HRDATA,
output logic HRESP, HREADYOUT,
output logic PCLK, PRESETn,
output logic [PERIPHS-1:0] PSEL,
output logic PWRITE,
output logic PENABLE,
output logic [31:0] PADDR,
output logic [`XLEN-1:0] PWDATA,
input logic [PERIPHS-1:0] PREADY,
input var [`XLEN-1:0][PERIPHS-1:0] PRDATA
);
logic activeTrans;
logic initTrans, initTransSel, initTransSelD;
logic nextPENABLE;
// convert AHB to APB signals
assign PCLK = HCLK;
assign PRESETn = HRESETn;
// identify start of a transaction
assign activeTrans = (HTRANS == 2'b10); // only accept nonsequential transactions
assign initTrans = activeTrans & HREADY; // start a transaction when the bus is ready and an active transaction is requested
assign initTransSel = initTrans & |HSEL; // capture data and address if any of the peripherals are selected
// delay AHB Address phase signals to align with AHB Data phase because APB expects them at the same time
flopenr #(32) addrreg(HCLK, ~HRESETn, initTransSel, HADDR, PADDR);
flopenr #(1) writereg(HCLK, ~HRESETn, initTransSel, HWRITE, PWRITE);
// enable selreg with iniTrans rather than initTransSel so PSEL can turn off
flopenr #(PERIPHS) selreg(HCLK, ~HRESETn, initTrans, HSEL & {PERIPHS{activeTrans}}, PSEL);
// AHB Data phase signal doesn't need delay. Note that HWDATA is guaranteed to remain stable until READY is asserted
assign PWDATA = HWDATA;
// enable logic: goes high a cycle after initTrans, then back low on cycle after desired PREADY is asserted
// cycle1: AHB puts HADDR, HWRITE, HSEL on bus. initTrans is 1, and these are captured
// cycle2: AHB puts HWDATA on the bus. This effectively extends the setup phase
// cycle3: bridge raises PENABLE. Peripheral typically responds with PREADY.
// Read occurs by end of cycle. Write occurs at end of cycle.
flopr #(1) inittransreg(HCLK, ~HRESETn, initTransSel, initTransSelD);
assign nextPENABLE = PENABLE ? ~HREADY : initTransSelD;
flopr #(1) enablereg(HCLK, ~HRESETn, nextPENABLE, PENABLE);
// result and ready multiplexer
int i;
always_comb
for (i=0; i<PERIPHS; i++) begin
// no peripheral selected: read 0, indicate ready
HRDATA = 0;
HREADYOUT = 1;
if (PSEL[i]) begin // highest numbered peripheral has priority, but multiple PSEL should never be asserted
HRDATA = PRDATA[i];
HREADYOUT = PREADY[i];
end
end
// resp logic
assign HRESP = 0; // bridge never indicates errors
endmodule

View File

@ -0,0 +1,146 @@
///////////////////////////////////////////
// gpio_apb.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_apb (
input logic PCLK, PRESETn,
input logic PSEL,
input logic [7:0] PADDR,
input logic [`XLEN-1:0] PWDATA,
input logic PWRITE,
input logic PENABLE,
output logic [`XLEN-1:0] PRDATA,
output logic PREADY,
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;
logic [7:0] entry;
logic [31:0] Din, Dout;
logic memwrite;
// APB I/O
assign entry = {PADDR[7:2],2'b00}; // 32-bit word-aligned accesses
assign memwrite = PWRITE & PENABLE; // only write in access phase
assign PREADY = PENABLE; // 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 = entry[2] ? PWDATA[63:32] : PWDATA[31:0];
assign PRDATA = entry[2] ? {Dout,32'b0} : {32'b0,Dout};
end else begin // 32-bit
assign Din = PWDATA[31:0];
assign PRDATA = Dout;
end
// register access
always_ff @(posedge PCLK, negedge PRESETn)
if (~PRESETn) begin // asynch reset
input_en <= 0;
output_en <= 0;
// *** synch reset not yet implemented [DH: can we delete this comment? Check if a sync reset is required]
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;
end else begin // writes
// 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 */
if (memwrite)
case(entry)
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: output_val <= #1 output_val ^ Din; // OUT_XOR
endcase
/* verilator lint_on CASEINCOMPLETE */
// interrupts can be cleared by writing corresponding bits to a register
if (memwrite & entry == 8'h1C) rise_ip <= rise_ip & ~Din;
else rise_ip <= rise_ip | (input2d & ~input3d);
if (memwrite & (entry == 8'h24)) fall_ip <= fall_ip & ~Din;
else fall_ip <= fall_ip | (~input2d & input3d);
if (memwrite & (entry == 8'h2C)) high_ip <= high_ip & ~Din;
else high_ip <= high_ip | input3d;
if (memwrite & (entry == 8'h34)) low_ip <= low_ip & ~Din;
else low_ip <= low_ip | ~input3d;
case(entry) // flop to sample inputs
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 0; // OUT_XOR reads as 0
default: Dout <= #1 0;
endcase
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;
// synchroninzer for inputs
flop #(32) sync1(PCLK,input0d,input1d);
flop #(32) sync2(PCLK,input1d,input2d);
flop #(32) sync3(PCLK,input2d,input3d);
assign input_val = input3d;
assign GPIOPinsOut = output_val;
assign GPIOPinsEn = output_en;
assign GPIOIntr = |{(rise_ip & rise_ie),(fall_ip & fall_ie),(high_ip & high_ie),(low_ip & low_ie)};
endmodule

View File

@ -63,6 +63,7 @@ module ram #(parameter BASE=0, RANGE = 65535) (
// *** this seems like a weird way to use reset // *** this seems like a weird way to use reset
flopenr #(1) memwritereg(HCLK, 1'b0, initTrans | ~HRESETn, HSELRam & HWRITE, memwrite); flopenr #(1) memwritereg(HCLK, 1'b0, initTrans | ~HRESETn, HSELRam & HWRITE, memwrite);
flopenr #(32) haddrreg(HCLK, 1'b0, initTrans | ~HRESETn, HADDR, A); flopenr #(32) haddrreg(HCLK, 1'b0, initTrans | ~HRESETn, HADDR, A);
// busy FSM to extend READY signal // busy FSM to extend READY signal
always @(posedge HCLK, negedge HRESETn) always @(posedge HCLK, negedge HRESETn)
if (~HRESETn) begin if (~HRESETn) begin

View File

@ -0,0 +1,107 @@
///////////////////////////////////////////
// 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), .enaA(1'b1),
.addrA(A[ADDR_WDITH+OFFSET-1:OFFSET]), .doutA(HREADRam),
.enaB(memwrite & risingHREADYRam), .weB(ByteMaskM),
.addrB(HWADDR[ADDR_WDITH+OFFSET-1:OFFSET]), .dinB(HWDATA));
endmodule

View File

@ -194,7 +194,7 @@ module uncore (
({`XLEN{HSELSDCD}} & HREADSDC); ({`XLEN{HSELSDCD}} & HREADSDC);
assign HRESP = HSELRamD & HRESPRam | assign HRESP = HSELRamD & HRESPRam |
HSELEXTD & HRESPEXT | HSELEXTD & HRESPEXT |
HSELCLINTD & HRESPCLINT | HSELCLINTD & HRESPCLINT |
HSELPLICD & HRESPPLIC | HSELPLICD & HRESPPLIC |
HSELGPIOD & HRESPGPIO | HSELGPIOD & HRESPGPIO |
@ -203,7 +203,7 @@ module uncore (
HSELSDC & HRESPSDC; HSELSDC & HRESPSDC;
assign HREADY = HSELRamD & HREADYRam | assign HREADY = HSELRamD & HREADYRam |
HSELEXTD & HREADYEXT | HSELEXTD & HREADYEXT |
HSELCLINTD & HREADYCLINT | HSELCLINTD & HREADYCLINT |
HSELPLICD & HREADYPLIC | HSELPLICD & HREADYPLIC |
HSELGPIOD & HREADYGPIO | HSELGPIOD & HREADYGPIO |