diff --git a/pipelined/src/uncore/clint_apb.sv b/pipelined/src/uncore/clint_apb.sv index 0cbd49aeb..fb704cf5c 100644 --- a/pipelined/src/uncore/clint_apb.sv +++ b/pipelined/src/uncore/clint_apb.sv @@ -52,7 +52,7 @@ module clint_apb ( integer i, j; assign memwrite = PWRITE & PENABLE & PSEL; // only write in access phase - assign PREADY = 1'b1; // GPIO never takes >1 cycle to respond + assign PREADY = 1'b1; // CLINT never takes >1 cycle to respond // word aligned reads if (`XLEN==64) assign #2 entry = {PADDR[15:3], 3'b000}; diff --git a/pipelined/src/uncore/plic.sv b/pipelined/src/uncore/plic.sv index 120e110a9..ef27e5be8 100644 --- a/pipelined/src/uncore/plic.sv +++ b/pipelined/src/uncore/plic.sv @@ -35,6 +35,7 @@ // OR OTHER DEALINGS IN THE SOFTWARE. //////////////////////////////////////////////////////////////////////////////////////////////// +/* `include "wally-config.vh" `define N `PLIC_NUM_SRC @@ -257,3 +258,4 @@ module plic ( assign SExtInt = |(threshMask[1] & priorities_with_irqs[1]); endmodule +*/ \ No newline at end of file diff --git a/pipelined/src/uncore/plic_apb.sv b/pipelined/src/uncore/plic_apb.sv new file mode 100644 index 000000000..90487baf3 --- /dev/null +++ b/pipelined/src/uncore/plic_apb.sv @@ -0,0 +1,273 @@ +/////////////////////////////////////////// +// plic_apb.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_apb ( + input logic PCLK, PRESETn, + input logic PSEL, + input logic [27: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, +/* + 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); + + logic memwrite, memread, initTrans; + logic [23:0] entry; + 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 memwrite = PWRITE & PENABLE & PSEL; // only write in access phase + 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. + 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 PRDATA = Dout; + assign Din = PWDATA[31:0]; + end + + // ================== + // Register Interface + // ================== + always @(posedge PCLK,negedge PRESETn) begin + // resetting + if (~PRESETn) 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(entry) + 24'h0000??: intPriority[entry[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 + // Read synchronously because a read can have side effect of changing intInProgress + 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(PCLK,~PRESETn,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 + // has priority level and has an "active" interrupt request + // ("active" meaning it is enabled in context 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 + diff --git a/pipelined/src/uncore/uart.sv b/pipelined/src/uncore/uart.sv index dc620d734..ed062035b 100644 --- a/pipelined/src/uncore/uart.sv +++ b/pipelined/src/uncore/uart.sv @@ -30,6 +30,7 @@ // OR OTHER DEALINGS IN THE SOFTWARE. //////////////////////////////////////////////////////////////////////////////////////////////// +/* `include "wally-config.vh" module uart ( @@ -103,3 +104,4 @@ module uart ( endmodule +*/ \ No newline at end of file diff --git a/pipelined/src/uncore/uartPC16550D.sv b/pipelined/src/uncore/uartPC16550D.sv index ca9481fa3..524a63454 100644 --- a/pipelined/src/uncore/uartPC16550D.sv +++ b/pipelined/src/uncore/uartPC16550D.sv @@ -40,7 +40,7 @@ module uartPC16550D( // Processor Interface - input logic HCLK, HRESETn, + input logic PCLK, PRESETn, input logic [2:0] A, input logic [7:0] Din, output logic [7:0] Dout, @@ -132,7 +132,7 @@ module uartPC16550D( /////////////////////////////////////////// // Input synchronization: 2-stage synchronizer /////////////////////////////////////////// - always_ff @(posedge HCLK) begin + always_ff @(posedge PCLK) begin {SINd, DSRbd, DCDbd, CTSbd, RIbd} <= #1 {SIN, DSRb, DCDb, CTSb, RIb}; {SINsync, DSRbsync, DCDbsync, CTSbsync, RIbsync} <= #1 loop ? {SOUTbit, ~MCR[0], ~MCR[3], ~MCR[1], ~MCR[2]} : {SINd, DSRbd, DCDbd, CTSbd, RIbd}; // syncrhonized signals, handle loopback testing @@ -142,8 +142,8 @@ module uartPC16550D( /////////////////////////////////////////// // Register interface (Table 1, note some are read only and some write only) /////////////////////////////////////////// - always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) begin // Table 3 Reset Configuration + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin // Table 3 Reset Configuration IER <= #1 4'b0; FCR <= #1 8'b0; if (`QEMU) LCR <= #1 8'b0; else LCR <= #1 8'b11; // fpga only **** BUG @@ -229,8 +229,8 @@ module uartPC16550D( /////////////////////////////////////////// // Ross Thompson: Found a bug. If the baud rate dividers DLM, and DLL are reloaded // the baudcount is not reset to {DLM, DLL, UART_PRESCALE} - always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) begin + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin baudcount <= #1 1; baudpulse <= #1 0; end else if (~MEMWb & DLAB & (A == 3'b0 | A == 3'b1)) begin @@ -254,8 +254,8 @@ module uartPC16550D( /////////////////////////////////////////// // receive timing and control /////////////////////////////////////////// - always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) begin + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin rxoversampledcnt <= #1 0; rxstate <= #1 UART_IDLE; rxbitsreceived <= #1 0; @@ -288,8 +288,8 @@ module uartPC16550D( /////////////////////////////////////////// // receive shift register, buffer register, FIFO /////////////////////////////////////////// - always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) rxshiftreg <= #1 10'b0000000001; // initialize so that there is a valid stop bit + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) rxshiftreg <= #1 10'b0000000001; // initialize so that there is a valid stop bit else if (rxcentered) rxshiftreg <= #1 {rxshiftreg[8:0], SINsync}; // capture bit assign rxparitybit = rxshiftreg[1]; // parity, if it exists, in bit 1 when all done assign rxstopbit = rxshiftreg[0]; @@ -310,8 +310,8 @@ module uartPC16550D( assign rxbreak = rxframingerr & (rxdata9 == 9'b0); // break when 0 for start + data + parity + stop time // receive FIFO and register - always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) begin + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin rxfifohead <= #1 0; rxfifotail <= #1 0; rxdataready <= #1 0; RXBR <= #1 0; end else begin if (rxstate == UART_DONE) begin @@ -367,8 +367,8 @@ module uartPC16550D( assign rxfifohaserr = |(RXerrbit & rxfullbit); // receive buffer register and ready bit - always_ff @(posedge HCLK, negedge HRESETn) // track rxrdy for DMA mode (FCR3 = FCR0 = 1) - if (~HRESETn) rxfifodmaready <= #1 0; + always_ff @(posedge PCLK, negedge PRESETn) // track rxrdy for DMA mode (FCR3 = FCR0 = 1) + if (~PRESETn) rxfifodmaready <= #1 0; else if (rxfifotriggered | rxfifotimeout) rxfifodmaready <= #1 1; else if (rxfifoempty) rxfifodmaready <= #1 0; @@ -386,8 +386,8 @@ module uartPC16550D( /////////////////////////////////////////// // transmit timing and control /////////////////////////////////////////// - always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) begin + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin txoversampledcnt <= #1 0; txstate <= #1 UART_IDLE; txbitssent <= #1 0; @@ -435,8 +435,8 @@ module uartPC16550D( end // registers & FIFO - always_ff @(posedge HCLK, negedge HRESETn) - if (~HRESETn) begin + always_ff @(posedge PCLK, negedge PRESETn) + if (~PRESETn) begin txfifohead <= #1 0; txfifotail <= #1 0; txhrfull <= #1 0; txsrfull <= #1 0; TXHR <= #1 0; txsr <= #1 12'hfff; end else begin if (~MEMWb & A == 3'b000 & ~DLAB) begin // writing transmit holding register or fifo @@ -477,8 +477,8 @@ module uartPC16550D( assign txfifofull = (txfifoentries == 4'b1111); // transmit buffer ready bit - always_ff @(posedge HCLK, negedge HRESETn) // track txrdy for DMA mode (FCR3 = FCR0 = 1) - if (~HRESETn) txfifodmaready <= #1 0; + always_ff @(posedge PCLK, negedge PRESETn) // track txrdy for DMA mode (FCR3 = FCR0 = 1) + if (~PRESETn) txfifodmaready <= #1 0; else if (txfifoempty) txfifodmaready <= #1 1; else if (txfifofull) txfifodmaready <= #1 0; @@ -514,18 +514,18 @@ module uartPC16550D( intrpending = 0; end end - always @(posedge HCLK) INTR <= #1 intrpending; // prevent glitches on interrupt pin + always @(posedge PCLK) INTR <= #1 intrpending; // prevent glitches on interrupt pin // Side effect of reading LSR is lowering overrun, parity, framing, break intr's assign setSquashRXerrIP = ~MEMRb & (A==3'b101); assign resetSquashRXerrIP = (rxstate == UART_DONE); assign squashRXerrIP = (prevSquashRXerrIP | setSquashRXerrIP) & ~resetSquashRXerrIP; - flopr #(1) squashRXerrIPreg(HCLK, ~HRESETn, squashRXerrIP, prevSquashRXerrIP); + flopr #(1) squashRXerrIPreg(PCLK, ~PRESETn, squashRXerrIP, prevSquashRXerrIP); // Side effect of reading IIR is lowering THRE_IP if most significant intr assign setSquashTHRE_IP = ~MEMRb & (A==3'b010) & (intrID==3'h1); // there's a 1-cycle delay on set squash so that THRE_IP doesn't change during the process of reading IIR (otherwise combinational loop) assign resetSquashTHRE_IP = ~THRE; assign squashTHRE_IP = prevSquashTHRE_IP & ~resetSquashTHRE_IP; - flopr #(1) squashTHRE_IPreg(HCLK, ~HRESETn, squashTHRE_IP | setSquashTHRE_IP, prevSquashTHRE_IP); + flopr #(1) squashTHRE_IPreg(PCLK, ~PRESETn, squashTHRE_IP | setSquashTHRE_IP, prevSquashTHRE_IP); /////////////////////////////////////////// // modem control logic diff --git a/pipelined/src/uncore/uart_apb.sv b/pipelined/src/uncore/uart_apb.sv new file mode 100644 index 000000000..6108b5807 --- /dev/null +++ b/pipelined/src/uncore/uart_apb.sv @@ -0,0 +1,123 @@ +/////////////////////////////////////////// +// uart_apb.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_apb ( + input logic PCLK, PRESETn, + input logic PSEL, + input logic [2: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, +/* + input logic HCLK, HRESETn, + input logic HSELUART, + input logic [2:0] HADDR, + input logic HWRITE, + input logic [`XLEN-1:0] PWDATA, + 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] entry; + logic MEMRb, MEMWb, memread, memwrite; + logic [7:0] Din, Dout; + + assign memwrite = PWRITE & PENABLE & PSEL; // only write in access phase + assign memread = ~PWRITE & PENABLE & PSEL; + assign PREADY = 1'b1; // CLINT never takes >1 cycle to respond + assign entry = PADDR[2:0]; + assign MEMRb = ~memread; + assign MEMWb = ~memwrite; + +/* + // 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 + PRDATA = {Dout, Dout, Dout, Dout, Dout, Dout, Dout, Dout}; + case (entry) + 3'b000: Din = PWDATA[7:0]; + 3'b001: Din = PWDATA[15:8]; + 3'b010: Din = PWDATA[23:16]; + 3'b011: Din = PWDATA[31:24]; + 3'b100: Din = PWDATA[39:32]; + 3'b101: Din = PWDATA[47:40]; + 3'b110: Din = PWDATA[55:48]; + 3'b111: Din = PWDATA[63:56]; + endcase + end + end else begin:uart // 32-bit + always_comb begin + PRDATA = {Dout, Dout, Dout, Dout}; + case (entry[1:0]) + 2'b00: Din = PWDATA[7:0]; + 2'b01: Din = PWDATA[15:8]; + 2'b10: Din = PWDATA[23:16]; + 2'b11: Din = PWDATA[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 + .PCLK, .PRESETn, + .A(entry), .Din, + .Dout, + .MEMRb, .MEMWb, + .INTR, .TXRDYb, .RXRDYb, + // Clocks + .BAUDOUTb, .RCLK(BAUDOUTb), + // E1A Driver + .SIN, .DSRb, .DCDb, .CTSb, .RIb, + .SOUT, .RTSb, .DTRb, .OUT1b, .OUT2b +); + +endmodule + diff --git a/pipelined/src/uncore/uncore.sv b/pipelined/src/uncore/uncore.sv index 867758abe..f4b1202ea 100644 --- a/pipelined/src/uncore/uncore.sv +++ b/pipelined/src/uncore/uncore.sv @@ -84,11 +84,11 @@ module uncore ( logic PCLK, PRESETn, PWRITE, PENABLE; // logic PSEL, PREADY; - logic [1:0] PSEL, PREADY; + logic [3:0] PSEL, PREADY; logic [31:0] PADDR; logic [`XLEN-1:0] PWDATA; logic [`XLEN/8-1:0] PSTRB; - logic [1:0][`XLEN-1:0] PRDATA; + logic [3:0][`XLEN-1:0] PRDATA; // logic [`XLEN-1:0][8:0] PRDATA; logic [`XLEN-1:0] HREADBRIDGE; logic HRESPBRIDGE, HREADYBRIDGE, HSELBRIDGE, HSELBRIDGED; @@ -107,11 +107,11 @@ module uncore ( assign {HSELEXT, HSELBootRom, HSELRam, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC, HSELSDC} = HSELRegions[7:0]; // AHB -> APB bridge - ahbapbbridge #(2) ahbapbbridge - (.HCLK, .HRESETn, .HSEL({HSELCLINT, HSELGPIO}), .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HTRANS, .HREADY, + ahbapbbridge #(4) ahbapbbridge + (.HCLK, .HRESETn, .HSEL({HSELUART, HSELPLIC, 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 HSELBRIDGE = HSELGPIO | HSELCLINT; // if any of the bridge signals are selected + assign HSELBRIDGE = HSELGPIO | HSELCLINT | HSELPLIC | HSELUART; // if any of the bridge signals are selected // on-chip RAM if (`RAM_SUPPORTED) begin : ram @@ -155,12 +155,17 @@ module uncore ( assign MTimerInt = 0; assign MSwInt = 0; end if (`PLIC_SUPPORTED == 1) begin : plic - plic plic( +/* plic plic( .HCLK, .HRESETn, .HSELPLIC, .HADDR(HADDR[27:0]), .HWRITE, .HREADY, .HTRANS, .HWDATA, .UARTIntr, .GPIOIntr, .HREADPLIC, .HRESPPLIC, .HREADYPLIC, + .MExtInt, .SExtInt); */ + plic_apb plic( + .PCLK, .PRESETn, .PSEL(PSEL[2]), .PADDR(PADDR[27:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE, + .PRDATA(PRDATA[2]), .PREADY(PREADY[2]), + .UARTIntr, .GPIOIntr, .MExtInt, .SExtInt); end else begin : plic assign MExtInt = 0; @@ -186,7 +191,7 @@ module uncore ( assign GPIOPinsOut = 0; assign GPIOPinsEn = 0; assign GPIOIntr = 0; end if (`UART_SUPPORTED == 1) begin : uart - uart uart( +/* uart uart( .HCLK, .HRESETn, .HSELUART, .HADDR(HADDR[2:0]), @@ -194,6 +199,12 @@ module uncore ( .HREADUART, .HRESPUART, .HREADYUART, .SIN(UARTSin), .DSRb(1'b1), .DCDb(1'b1), .CTSb(1'b0), .RIb(1'b1), // from E1A driver from RS232 interface .SOUT(UARTSout), .RTSb(), .DTRb(), // to E1A driver to RS232 interface + .OUT1b(), .OUT2b(), .INTR(UARTIntr), .TXRDYb(), .RXRDYb()); // to CPU */ + uart_apb uart( + .PCLK, .PRESETn, .PSEL(PSEL[3]), .PADDR(PADDR[2:0]), .PWDATA, .PSTRB, .PWRITE, .PENABLE, + .PRDATA(PRDATA[3]), .PREADY(PREADY[3]), + .SIN(UARTSin), .DSRb(1'b1), .DCDb(1'b1), .CTSb(1'b0), .RIb(1'b1), // from E1A driver from RS232 interface + .SOUT(UARTSout), .RTSb(), .DTRb(), // to E1A driver to RS232 interface .OUT1b(), .OUT2b(), .INTR(UARTIntr), .TXRDYb(), .RXRDYb()); // to CPU end else begin : uart assign UARTSout = 0; assign UARTIntr = 0; @@ -217,35 +228,35 @@ module uncore ( assign HRDATA = ({`XLEN{HSELRamD}} & HREADRam) | ({`XLEN{HSELEXTD}} & HRDATAEXT) | // ({`XLEN{HSELCLINTD}} & HREADCLINT) | - ({`XLEN{HSELPLICD}} & HREADPLIC) | +// ({`XLEN{HSELPLICD}} & HREADPLIC) | // ({`XLEN{HSELGPIOD}} & HREADGPIO) | ({`XLEN{HSELBRIDGED}} & HREADBRIDGE) | ({`XLEN{HSELBootRomD}} & HREADBootRom) | - ({`XLEN{HSELUARTD}} & HREADUART) | +// ({`XLEN{HSELUARTD}} & HREADUART) | ({`XLEN{HSELSDCD}} & HREADSDC); assign HRESP = HSELRamD & HRESPRam | HSELEXTD & HRESPEXT | // HSELCLINTD & HRESPCLINT | - HSELPLICD & HRESPPLIC | +// HSELPLICD & HRESPPLIC | // HSELGPIOD & HRESPGPIO | HSELBRIDGE & HRESPBRIDGE | HSELBootRomD & HRESPBootRom | - HSELUARTD & HRESPUART | +// HSELUARTD & HRESPUART | HSELSDC & HRESPSDC; assign HREADY = HSELRamD & HREADYRam | HSELEXTD & HREADYEXT | // HSELCLINTD & HREADYCLINT | - HSELPLICD & HREADYPLIC | +// HSELPLICD & HREADYPLIC | // HSELGPIOD & HREADYGPIO | HSELBRIDGED & HREADYBRIDGE | HSELBootRomD & HREADYBootRom | - HSELUARTD & HREADYUART | +// HSELUARTD & HREADYUART | HSELSDCD & HREADYSDC | HSELNoneD; // don't lock up the bus if no region is being accessed - // *** remove HREADYGPIO, others + // *** 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});