From f81719337e4e212c000af200c6e4d2b958bc0fad Mon Sep 17 00:00:00 2001 From: David Harris Date: Wed, 8 Jun 2022 01:31:34 +0000 Subject: [PATCH] Added ahbapbbridge and cleaning RAM --- pipelined/src/generic/flop/bram1p1rw.sv | 4 +- pipelined/src/generic/flop/simpleram.sv | 22 +--- pipelined/src/uncore/ahbapbbridge.sv | 98 ++++++++++++++++ pipelined/src/uncore/gpio_apb.sv | 146 ++++++++++++++++++++++++ pipelined/src/uncore/ram.sv | 1 + pipelined/src/uncore/ram_orig.sv | 107 +++++++++++++++++ pipelined/src/uncore/uncore.sv | 4 +- 7 files changed, 357 insertions(+), 25 deletions(-) create mode 100644 pipelined/src/uncore/ahbapbbridge.sv create mode 100644 pipelined/src/uncore/gpio_apb.sv create mode 100644 pipelined/src/uncore/ram_orig.sv diff --git a/pipelined/src/generic/flop/bram1p1rw.sv b/pipelined/src/generic/flop/bram1p1rw.sv index 2b17fb447..cccf1f1f1 100644 --- a/pipelined/src/generic/flop/bram1p1rw.sv +++ b/pipelined/src/generic/flop/bram1p1rw.sv @@ -44,7 +44,7 @@ module bram1p1rw //---------------------------------------------------------------------- ) ( input logic clk, - input logic ena, + input logic en, input logic [NUM_COL-1:0] we, input logic [ADDR_WIDTH-1:0] addr, output logic [DATA_WIDTH-1:0] dout, @@ -60,7 +60,7 @@ module bram1p1rw always @ (posedge clk) begin dout <= RAM[addr]; - if(ena) begin + if(en) begin for(i=0;i>(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 -----/\----- */ + memory(.clk, .en(we), .we(ByteMask), .addr(a[ADDR_WDITH+OFFSET-1:OFFSET]), .dout(rd), .din(wd)); endmodule diff --git a/pipelined/src/uncore/ahbapbbridge.sv b/pipelined/src/uncore/ahbapbbridge.sv new file mode 100644 index 000000000..e05ee3d82 --- /dev/null +++ b/pipelined/src/uncore/ahbapbbridge.sv @@ -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; i1 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 + diff --git a/pipelined/src/uncore/ram.sv b/pipelined/src/uncore/ram.sv index 442bfc508..c53d1f481 100644 --- a/pipelined/src/uncore/ram.sv +++ b/pipelined/src/uncore/ram.sv @@ -63,6 +63,7 @@ module ram #(parameter BASE=0, RANGE = 65535) ( // *** 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 diff --git a/pipelined/src/uncore/ram_orig.sv b/pipelined/src/uncore/ram_orig.sv new file mode 100644 index 000000000..e40da7b3e --- /dev/null +++ b/pipelined/src/uncore/ram_orig.sv @@ -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 + diff --git a/pipelined/src/uncore/uncore.sv b/pipelined/src/uncore/uncore.sv index c6728294f..d1a97bad6 100644 --- a/pipelined/src/uncore/uncore.sv +++ b/pipelined/src/uncore/uncore.sv @@ -194,7 +194,7 @@ module uncore ( ({`XLEN{HSELSDCD}} & HREADSDC); assign HRESP = HSELRamD & HRESPRam | - HSELEXTD & HRESPEXT | + HSELEXTD & HRESPEXT | HSELCLINTD & HRESPCLINT | HSELPLICD & HRESPPLIC | HSELGPIOD & HRESPGPIO | @@ -203,7 +203,7 @@ module uncore ( HSELSDC & HRESPSDC; assign HREADY = HSELRamD & HREADYRam | - HSELEXTD & HREADYEXT | + HSELEXTD & HREADYEXT | HSELCLINTD & HREADYCLINT | HSELPLICD & HREADYPLIC | HSELGPIOD & HREADYGPIO |