mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	PLIC and UART passing tests on APB
This commit is contained in:
		
							parent
							
								
									d73645944f
								
							
						
					
					
						commit
						a599084b88
					
				| @ -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}; | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
| */ | ||||
							
								
								
									
										273
									
								
								pipelined/src/uncore/plic_apb.sv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								pipelined/src/uncore/plic_apb.sv
									
									
									
									
									
										Normal file
									
								
							| @ -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 <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 | ||||
| 
 | ||||
| @ -30,6 +30,7 @@ | ||||
| //   OR OTHER DEALINGS IN THE SOFTWARE.
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /* | ||||
| `include "wally-config.vh" | ||||
| 
 | ||||
| module uart ( | ||||
| @ -103,3 +104,4 @@ module uart ( | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| */ | ||||
| @ -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
 | ||||
|  | ||||
							
								
								
									
										123
									
								
								pipelined/src/uncore/uart_apb.sv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								pipelined/src/uncore/uart_apb.sv
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| 
 | ||||
| @ -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}); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user