mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
parameterized register names in peripherals
This commit is contained in:
parent
00a1c0fc57
commit
0419b5484a
@ -42,6 +42,11 @@ module clint_apb import cvw::*; #(parameter cvw_t P) (
|
||||
output logic MTimerInt, MSwInt
|
||||
);
|
||||
|
||||
// register map
|
||||
localparam CLINT_MSIP = 16'h0000;
|
||||
localparam CLINT_MTIMECMP = 16'h4000;
|
||||
localparam CLINT_MTIME = 16'hBFF8;
|
||||
|
||||
logic MSIP;
|
||||
logic [15:0] entry;
|
||||
logic memwrite;
|
||||
@ -65,19 +70,19 @@ module clint_apb import cvw::*; #(parameter cvw_t P) (
|
||||
if (P.XLEN==64) begin:clint // 64-bit
|
||||
always_ff @(posedge PCLK) begin
|
||||
case(entry)
|
||||
16'h0000: PRDATA <= {63'b0, MSIP};
|
||||
16'h4000: PRDATA <= MTIMECMP;
|
||||
16'hBFF8: PRDATA <= MTIME;
|
||||
default: PRDATA <= 0;
|
||||
CLINT_MSIP: PRDATA <= {63'b0, MSIP};
|
||||
CLINT_MTIMECMP: PRDATA <= MTIMECMP;
|
||||
CLINT_MTIME: PRDATA <= MTIME;
|
||||
default: PRDATA <= '0;
|
||||
endcase
|
||||
end
|
||||
always_ff @(posedge PCLK or negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
MSIP <= 0;
|
||||
MSIP <= 1'b0;
|
||||
MTIMECMP <= 64'hFFFFFFFFFFFFFFFF; // Spec says MTIMECMP is not reset, but we reset to maximum value to prevent spurious timer interrupts
|
||||
end else if (memwrite) begin
|
||||
if (entry == 16'h0000) MSIP <= PWDATA[0];
|
||||
if (entry == 16'h4000) begin
|
||||
if (entry == CLINT_MSIP) MSIP <= PWDATA[0];
|
||||
if (entry == CLINT_MTIMECMP) begin
|
||||
for(i=0;i<P.XLEN/8;i++)
|
||||
if(PSTRB[i])
|
||||
MTIMECMP[i*8 +: 8] <= PWDATA[i*8 +: 8]; // ***dh: this notation isn't in book yet - maybe from Ross
|
||||
@ -89,7 +94,7 @@ module clint_apb import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
always_ff @(posedge PCLK or negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
MTIME <= 0;
|
||||
MTIME <= '0;
|
||||
end else if (memwrite & entry == 16'hBFF8) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
for(j=0;j<P.XLEN/8;j++)
|
||||
@ -104,13 +109,13 @@ module clint_apb import cvw::*; #(parameter cvw_t P) (
|
||||
16'h4004: PRDATA <= MTIMECMP[63:32];
|
||||
16'hBFF8: PRDATA <= MTIME[31:0];
|
||||
16'hBFFC: PRDATA <= MTIME[63:32];
|
||||
default: PRDATA <= 0;
|
||||
default: PRDATA <= '0;
|
||||
endcase
|
||||
end
|
||||
always_ff @(posedge PCLK or negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
MSIP <= 0;
|
||||
MTIMECMP <= 0;
|
||||
MSIP <= 1'b0;
|
||||
MTIMECMP <= '0;
|
||||
// MTIMECMP is not reset ***?
|
||||
end else if (memwrite) begin
|
||||
if (entry == 16'h0000) MSIP <= PWDATA[0];
|
||||
@ -129,7 +134,7 @@ module clint_apb import cvw::*; #(parameter cvw_t P) (
|
||||
// timereg tr(PCLK, PRESETn, TIMECLK, memwrite & (entry==16'hBFF8), memwrite & (entry == 16'hBFFC), PWDATA, MTIME, done);
|
||||
always_ff @(posedge PCLK or negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
MTIME <= 0;
|
||||
MTIME <= '0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite & (entry == 16'hBFF8)) begin
|
||||
for(i=0;i<P.XLEN/8;i++)
|
||||
@ -159,12 +164,12 @@ module timeregsync import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
if (P.XLEN==64)
|
||||
always_ff @(posedge clk or negedge resetn)
|
||||
if (~resetn) q <= 0;
|
||||
if (~resetn) q <= '0;
|
||||
else if (we0) q <= wd;
|
||||
else q <= q + 1;
|
||||
else
|
||||
always_ff @(posedge clk or negedge resetn)
|
||||
if (~resetn) q <= 0;
|
||||
if (~resetn) q <= '0;
|
||||
else if (we0) q[31:0] <= wd;
|
||||
else if (we1) q[63:32] <= wd;
|
||||
else q <= q + 1;
|
||||
|
@ -45,6 +45,23 @@ module gpio_apb import cvw::*; #(parameter cvw_t P) (
|
||||
output logic GPIOIntr
|
||||
);
|
||||
|
||||
// register map
|
||||
localparam GPIO_INPUT_VAL = 8'h00;
|
||||
localparam GPIO_INPUT_EN = 8'h04;
|
||||
localparam GPIO_OUTPUT_EN = 8'h08;
|
||||
localparam GPIO_OUTPUT_VAL = 8'h0C;
|
||||
localparam GPIO_RISE_IE = 8'h18;
|
||||
localparam GPIO_RISE_IP = 8'h1C;
|
||||
localparam GPIO_FALL_IE = 8'h20;
|
||||
localparam GPIO_FALL_IP = 8'h24;
|
||||
localparam GPIO_HIGH_IE = 8'h28;
|
||||
localparam GPIO_HIGH_IP = 8'h2C;
|
||||
localparam GPIO_LOW_IE = 8'h30;
|
||||
localparam GPIO_LOW_IP = 8'h34;
|
||||
localparam GPIO_IOF_EN = 8'h38;
|
||||
localparam GPIO_IOF_SEL = 8'h3C;
|
||||
localparam GPIO_OUT_XOR = 8'h40;
|
||||
|
||||
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;
|
||||
@ -67,66 +84,66 @@ module gpio_apb import cvw::*; #(parameter cvw_t P) (
|
||||
// register access
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) begin // asynch reset
|
||||
input_en <= 0;
|
||||
output_en <= 0;
|
||||
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 <= 0;
|
||||
rise_ie <= 0;
|
||||
rise_ip <= 0;
|
||||
fall_ie <= 0;
|
||||
fall_ip <= 0;
|
||||
high_ie <= 0;
|
||||
high_ip <= 0;
|
||||
low_ie <= 0;
|
||||
low_ip <= 0;
|
||||
iof_en <= 0;
|
||||
iof_sel <= 0;
|
||||
out_xor <= 0;
|
||||
output_val <= '0;
|
||||
rise_ie <= '0;
|
||||
rise_ip <= '0;
|
||||
fall_ie <= '0;
|
||||
fall_ip <= '0;
|
||||
high_ie <= '0;
|
||||
high_ip <= '0;
|
||||
low_ie <= '0;
|
||||
low_ip <= '0;
|
||||
iof_en <= '0;
|
||||
iof_sel <= '0;
|
||||
out_xor <= '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 <= Din;
|
||||
8'h08: output_en <= Din;
|
||||
8'h0C: output_val <= Din;
|
||||
8'h18: rise_ie <= Din;
|
||||
8'h20: fall_ie <= Din;
|
||||
8'h28: high_ie <= Din;
|
||||
8'h30: low_ie <= Din;
|
||||
8'h38: iof_en <= Din;
|
||||
8'h3C: iof_sel <= Din;
|
||||
8'h40: out_xor <= Din;
|
||||
GPIO_INPUT_EN: input_en <= Din;
|
||||
GPIO_OUTPUT_EN: output_en <= Din;
|
||||
GPIO_OUTPUT_VAL: output_val <= Din;
|
||||
GPIO_RISE_IE: rise_ie <= Din;
|
||||
GPIO_FALL_IE: fall_ie <= Din;
|
||||
GPIO_HIGH_IE: high_ie <= Din;
|
||||
GPIO_LOW_IE: low_ie <= Din;
|
||||
GPIO_IOF_EN: iof_en <= Din;
|
||||
GPIO_IOF_SEL: iof_sel <= Din;
|
||||
GPIO_OUT_XOR: out_xor <= Din;
|
||||
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;
|
||||
if (memwrite & entry == GPIO_RISE_IP) rise_ip <= rise_ip & ~Din;
|
||||
else rise_ip <= rise_ip | (input2d & ~input3d);
|
||||
if (memwrite & (entry == GPIO_FALL_IP)) fall_ip <= fall_ip & ~Din;
|
||||
else fall_ip <= fall_ip | (~input2d & input3d);
|
||||
if (memwrite & (entry == GPIO_HIGH_IP)) high_ip <= high_ip & ~Din;
|
||||
else high_ip <= high_ip | input3d;
|
||||
if (memwrite & (entry == GPIO_LOW_IP)) low_ip <= low_ip & ~Din;
|
||||
else low_ip <= low_ip | ~input3d;
|
||||
|
||||
case(entry) // flop to sample inputs
|
||||
8'h00: Dout <= input_val;
|
||||
8'h04: Dout <= input_en;
|
||||
8'h08: Dout <= output_en;
|
||||
8'h0C: Dout <= output_val;
|
||||
8'h18: Dout <= rise_ie;
|
||||
8'h1C: Dout <= rise_ip;
|
||||
8'h20: Dout <= fall_ie;
|
||||
8'h24: Dout <= fall_ip;
|
||||
8'h28: Dout <= high_ie;
|
||||
8'h2C: Dout <= high_ip;
|
||||
8'h30: Dout <= low_ie;
|
||||
8'h34: Dout <= low_ip;
|
||||
8'h38: Dout <= iof_en;
|
||||
8'h3C: Dout <= iof_sel;
|
||||
8'h40: Dout <= out_xor;
|
||||
default: Dout <= 0;
|
||||
GPIO_INPUT_VAL: Dout <= input_val;
|
||||
GPIO_INPUT_EN: Dout <= input_en;
|
||||
GPIO_OUTPUT_EN: Dout <= output_en;
|
||||
GPIO_OUTPUT_VAL: Dout <= output_val;
|
||||
GPIO_RISE_IE: Dout <= rise_ie;
|
||||
GPIO_RISE_IP: Dout <= rise_ip;
|
||||
GPIO_FALL_IE: Dout <= fall_ie;
|
||||
GPIO_FALL_IP: Dout <= fall_ip;
|
||||
GPIO_HIGH_IE: Dout <= high_ie;
|
||||
GPIO_HIGH_IP: Dout <= high_ip;
|
||||
GPIO_LOW_IE: Dout <= low_ie;
|
||||
GPIO_LOW_IP: Dout <= low_ip;
|
||||
GPIO_IOF_EN: Dout <= iof_en;
|
||||
GPIO_IOF_SEL: Dout <= iof_sel;
|
||||
GPIO_OUT_XOR: Dout <= out_xor;
|
||||
default: Dout <= '0;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
@ -54,6 +54,19 @@ module plic_apb import cvw::*; #(parameter cvw_t P) (
|
||||
output logic MExtInt, SExtInt
|
||||
);
|
||||
|
||||
// register map
|
||||
localparam PLIC_INTPRIORITY0 = 24'h000000;
|
||||
localparam PLIC_INTPENDING0 = 24'h001000;
|
||||
localparam PLIC_INTPENDING1 = 24'h001004;
|
||||
localparam PLIC_INTEN00 = 24'h002000;
|
||||
localparam PLIC_INTEN01 = 24'h002004;
|
||||
localparam PLIC_INTEN10 = 24'h002080;
|
||||
localparam PLIC_INTEN11 = 24'h002084;
|
||||
localparam PLIC_THRESHOLD0 = 24'h200000;
|
||||
localparam PLIC_CLAIMCOMPLETE0 = 24'h200004;
|
||||
localparam PLIC_THRESHOLD1 = 24'h201000;
|
||||
localparam PLIC_CLAIMCOMPLETE1 = 24'h201004;
|
||||
|
||||
logic memwrite, memread;
|
||||
logic [23:0] entry;
|
||||
logic [31:0] Din, Dout;
|
||||
@ -91,7 +104,7 @@ module plic_apb import cvw::*; #(parameter cvw_t P) (
|
||||
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 One[P.PLIC_NUM_SRC-1:1] = 0; assign One[0] = 1'b1; // Vivado does not like this as a single assignment.
|
||||
assign One[P.PLIC_NUM_SRC-1:1] = '0; assign One[0] = 1'b1; // Vivado does not like this as a single assignment.
|
||||
|
||||
// account for subword read/write circuitry
|
||||
// -- Note PLIC registers are 32 bits no matter what; access them with LW SW.
|
||||
@ -107,48 +120,49 @@ module plic_apb import cvw::*; #(parameter cvw_t P) (
|
||||
always_ff @(posedge PCLK) begin
|
||||
// resetting
|
||||
if (~PRESETn) begin
|
||||
intPriority <= 0;
|
||||
intEn <= 0;
|
||||
intThreshold <= 0;
|
||||
intInProgress <= 0;
|
||||
intPriority <= '0;
|
||||
intEn <= '0;
|
||||
intThreshold <= '0;
|
||||
intInProgress <= '0;
|
||||
// writing
|
||||
end else begin
|
||||
if (memwrite)
|
||||
casez(entry)
|
||||
24'h0000??: intPriority[entry[7:2]] <= Din[2:0];
|
||||
24'h002000: intEn[0][PLIC_NUM_SRC_MIN_32:1] <= Din[PLIC_NUM_SRC_MIN_32:1];
|
||||
24'h002080: intEn[1][PLIC_NUM_SRC_MIN_32:1] <= Din[PLIC_NUM_SRC_MIN_32:1];
|
||||
24'h002004: if (P.PLIC_NUM_SRC >= 32) intEn[0][PLIC_SRC_TOP:PLIC_SRC_BOT] <= Din[PLIC_SRC_DINTOP:0];
|
||||
24'h002084: if (P.PLIC_NUM_SRC >= 32) intEn[1][PLIC_SRC_TOP:PLIC_SRC_BOT] <= Din[PLIC_SRC_DINTOP:0];
|
||||
24'h200000: intThreshold[0] <= Din[2:0];
|
||||
24'h200004: intInProgress <= intInProgress & ~(One << (Din[5:0]-1)); // lower "InProgress" to signify completion
|
||||
24'h201000: intThreshold[1] <= Din[2:0];
|
||||
24'h201004: intInProgress <= intInProgress & ~(One << (Din[5:0]-1)); // lower "InProgress" to signify completion
|
||||
24'h0000??: intPriority[entry[7:2]] <= Din[2:0];
|
||||
PLIC_INTEN00: intEn[0][PLIC_NUM_SRC_MIN_32:1] <= Din[PLIC_NUM_SRC_MIN_32:1];
|
||||
PLIC_INTEN10: intEn[1][PLIC_NUM_SRC_MIN_32:1] <= Din[PLIC_NUM_SRC_MIN_32:1];
|
||||
PLIC_INTEN01: if (P.PLIC_NUM_SRC >= 32) intEn[0][PLIC_SRC_TOP:PLIC_SRC_BOT] <= Din[PLIC_SRC_DINTOP:0];
|
||||
PLIC_INTEN11: if (P.PLIC_NUM_SRC >= 32) intEn[1][PLIC_SRC_TOP:PLIC_SRC_BOT] <= Din[PLIC_SRC_DINTOP:0];
|
||||
PLIC_THRESHOLD0: intThreshold[0] <= Din[2:0];
|
||||
PLIC_CLAIMCOMPLETE0: intInProgress <= intInProgress & ~(One << (Din[5:0]-1)); // lower "InProgress" to signify completion
|
||||
PLIC_THRESHOLD1: intThreshold[1] <= Din[2:0];
|
||||
PLIC_CLAIMCOMPLETE1: intInProgress <= intInProgress & ~(One << (Din[5:0]-1)); // lower "InProgress" to signify completion
|
||||
endcase
|
||||
|
||||
// Read synchronously because a read can have side effect of changing intInProgress
|
||||
if (memread) begin
|
||||
casez(entry)
|
||||
24'h000000: Dout <= 32'b0; // there is no intPriority[0]
|
||||
24'h0000??: Dout <= {29'b0,intPriority[entry[7:2]]};
|
||||
24'h001000: Dout <= {{(31-PLIC_NUM_SRC_MIN_32){1'b0}},intPending[PLIC_NUM_SRC_MIN_32:1],1'b0};
|
||||
24'h002000: Dout <= {{(31-PLIC_NUM_SRC_MIN_32){1'b0}},intEn[0][PLIC_NUM_SRC_MIN_32:1],1'b0};
|
||||
24'h001004: if (P.PLIC_NUM_SRC >= 32) Dout <= {{(PLIC_SRC_EXT){1'b0}},intPending[PLIC_SRC_TOP:PLIC_SRC_BOT]};
|
||||
24'h002004: if (P.PLIC_NUM_SRC >= 32) Dout <= {{(PLIC_SRC_EXT){1'b0}},intEn[0][PLIC_SRC_TOP:PLIC_SRC_BOT]};
|
||||
24'h002080: Dout <= {{(31-PLIC_NUM_SRC_MIN_32){1'b0}},intEn[1][PLIC_NUM_SRC_MIN_32:1],1'b0};
|
||||
24'h002084: if (P.PLIC_NUM_SRC >= 32) Dout <= {{(PLIC_SRC_EXT){1'b0}},intEn[1][PLIC_SRC_TOP:PLIC_SRC_BOT]};
|
||||
24'h200000: Dout <= {29'b0,intThreshold[0]};
|
||||
24'h200004: begin
|
||||
PLIC_INTPRIORITY0: Dout <= 32'b0; // there is no intPriority[0]
|
||||
24'h0000??: Dout <= {29'b0,intPriority[entry[7:2]]};
|
||||
PLIC_INTPENDING0: Dout <= {{(31-PLIC_NUM_SRC_MIN_32){1'b0}},intPending[PLIC_NUM_SRC_MIN_32:1],1'b0};
|
||||
PLIC_INTEN00: Dout <= {{(31-PLIC_NUM_SRC_MIN_32){1'b0}},intEn[0][PLIC_NUM_SRC_MIN_32:1],1'b0};
|
||||
PLIC_INTPENDING1: if (P.PLIC_NUM_SRC >= 32) Dout <= {{(PLIC_SRC_EXT){1'b0}},intPending[PLIC_SRC_TOP:PLIC_SRC_BOT]};
|
||||
PLIC_INTEN01: if (P.PLIC_NUM_SRC >= 32) Dout <= {{(PLIC_SRC_EXT){1'b0}},intEn[0][PLIC_SRC_TOP:PLIC_SRC_BOT]};
|
||||
PLIC_INTEN10: Dout <= {{(31-PLIC_NUM_SRC_MIN_32){1'b0}},intEn[1][PLIC_NUM_SRC_MIN_32:1],1'b0};
|
||||
PLIC_INTEN11: if (P.PLIC_NUM_SRC >= 32) Dout <= {{(PLIC_SRC_EXT){1'b0}},intEn[1][PLIC_SRC_TOP:PLIC_SRC_BOT]};
|
||||
PLIC_THRESHOLD0: Dout <= {29'b0,intThreshold[0]};
|
||||
PLIC_CLAIMCOMPLETE0: begin
|
||||
Dout <= {26'b0,intClaim[0]};
|
||||
intInProgress <= intInProgress | (One << (intClaim[0]-1)); // claimed requests are currently in progress of being serviced until they are completed
|
||||
end
|
||||
24'h201000: Dout <= {29'b0,intThreshold[1]};
|
||||
24'h201004: begin
|
||||
PLIC_THRESHOLD1: Dout <= {29'b0,intThreshold[1]};
|
||||
PLIC_CLAIMCOMPLETE1: begin
|
||||
Dout <= {26'b0,intClaim[1]};
|
||||
intInProgress <= intInProgress | (One << (intClaim[1]-1)); // claimed requests are currently in progress of being serviced until they are completed
|
||||
end
|
||||
default: Dout <= 32'h0; // invalid access
|
||||
default: Dout <= 32'h0; // invalid access
|
||||
endcase
|
||||
end else Dout <= 32'h0;
|
||||
end else Dout <= 32'h0;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -64,7 +64,7 @@ module ram_ahb import cvw::*; #(parameter cvw_t P,
|
||||
assign nextHREADYRam = (~(memwriteD & memread)) & ~DelayReady;
|
||||
flopr #(1) readyreg(HCLK, ~HRESETn, nextHREADYRam, HREADYRam);
|
||||
|
||||
assign HRESPRam = 0; // OK
|
||||
assign HRESPRam = 1'b0; // OK
|
||||
|
||||
// On writes or during a wait state, use address delayed by one cycle to sync RamAddr with HWDATA or hold stalled address
|
||||
mux2 #(P.PA_BITS) adrmux(HADDR, HADDRD, memwriteD | ~HREADY, RamAddr);
|
||||
@ -104,7 +104,7 @@ module ram_ahb import cvw::*; #(parameter cvw_t P,
|
||||
assign DelayReady = NextState == DELAY;
|
||||
assign CntRst = NextState == READY;
|
||||
end else begin
|
||||
assign DelayReady = 0;
|
||||
assign DelayReady = 1'b0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -45,6 +45,22 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
output logic SPIIntr
|
||||
);
|
||||
|
||||
// register map
|
||||
localparam SPI_SCKDIV = 8'h00;
|
||||
localparam SPI_SCKMODE = 8'h04;
|
||||
localparam SPI_CSID = 8'h10;
|
||||
localparam SPI_CSDEF = 8'h14;
|
||||
localparam SPI_CSMODE = 8'h18;
|
||||
localparam SPI_DELAY0 = 8'h28;
|
||||
localparam SPI_DELAY1 = 8'h2C;
|
||||
localparam SPI_FMT = 8'h40;
|
||||
localparam SPI_TXDATA = 8'h48;
|
||||
localparam SPI_RXDATA = 8'h4C;
|
||||
localparam SPI_TXMARK = 8'h50;
|
||||
localparam SPI_RXMARK = 8'h54;
|
||||
localparam SPI_IE = 8'h70;
|
||||
localparam SPI_IP = 8'h74;
|
||||
|
||||
// SPI control registers. Refer to SiFive FU540-C000 manual
|
||||
logic [11:0] SckDiv;
|
||||
logic [1:0] SckMode;
|
||||
@ -61,7 +77,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
// Bus interface signals
|
||||
logic [7:0] Entry;
|
||||
logic Memwrite;
|
||||
logic [31:0] Din, Dout;
|
||||
logic [31:0] Din, Dout;
|
||||
logic TransmitInactive; // High when there is no transmission, used as hardware interlock signal
|
||||
|
||||
// FIFO FSM signals
|
||||
@ -130,8 +146,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
// -- Note SPI registers are 32 bits no matter what; access them with LW SW.
|
||||
|
||||
assign Din = PWDATA[31:0];
|
||||
if (P.XLEN == 64) assign PRDATA = {Dout, Dout};
|
||||
else assign PRDATA = Dout;
|
||||
if (P.XLEN == 64) assign PRDATA = { Dout, Dout};
|
||||
else assign PRDATA = Dout;
|
||||
|
||||
// Register access
|
||||
always_ff@(posedge PCLK, negedge PRESETn)
|
||||
@ -140,7 +156,7 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
SckMode <= 2'b0;
|
||||
ChipSelectID <= 2'b0;
|
||||
ChipSelectDef <= 4'b1111;
|
||||
ChipSelectMode <= 0;
|
||||
ChipSelectMode <= 2'b0;
|
||||
Delay0 <= {8'b1,8'b1};
|
||||
Delay1 <= {8'b0,8'b1};
|
||||
Format <= {5'b10000};
|
||||
@ -155,18 +171,18 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
/* verilator lint_off CASEINCOMPLETE */
|
||||
if (Memwrite & TransmitInactive)
|
||||
case(Entry) // flop to sample inputs
|
||||
8'h00: SckDiv <= Din[11:0];
|
||||
8'h04: SckMode <= Din[1:0];
|
||||
8'h10: ChipSelectID <= Din[1:0];
|
||||
8'h14: ChipSelectDef <= Din[3:0];
|
||||
8'h18: ChipSelectMode <= Din[1:0];
|
||||
8'h28: Delay0 <= {Din[23:16], Din[7:0]};
|
||||
8'h2C: Delay1 <= {Din[23:16], Din[7:0]};
|
||||
8'h40: Format <= {Din[19:16], Din[2]};
|
||||
8'h48: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0];
|
||||
8'h50: TransmitWatermark <= Din[2:0];
|
||||
8'h54: ReceiveWatermark <= Din[2:0];
|
||||
8'h70: InterruptEnable <= Din[1:0];
|
||||
SPI_SCKDIV: SckDiv <= Din[11:0];
|
||||
SPI_SCKMODE: SckMode <= Din[1:0];
|
||||
SPI_CSID: ChipSelectID <= Din[1:0];
|
||||
SPI_CSDEF: ChipSelectDef <= Din[3:0];
|
||||
SPI_CSMODE: ChipSelectMode <= Din[1:0];
|
||||
SPI_DELAY0: Delay0 <= {Din[23:16], Din[7:0]};
|
||||
SPI_DELAY1: Delay1 <= {Din[23:16], Din[7:0]};
|
||||
SPI_FMT: Format <= {Din[19:16], Din[2]};
|
||||
SPI_TXDATA: if (~TransmitFIFOWriteFull) TransmitData[7:0] <= Din[7:0];
|
||||
SPI_TXMARK: TransmitWatermark <= Din[2:0];
|
||||
SPI_RXMARK: ReceiveWatermark <= Din[2:0];
|
||||
SPI_IE: InterruptEnable <= Din[1:0];
|
||||
endcase
|
||||
/* verilator lint_off CASEINCOMPLETE */
|
||||
|
||||
@ -176,21 +192,21 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
InterruptPending[1] <= RecieveWriteMark;
|
||||
|
||||
case(Entry) // Flop to sample inputs
|
||||
8'h00: Dout <= {20'b0, SckDiv};
|
||||
8'h04: Dout <= {30'b0, SckMode};
|
||||
8'h10: Dout <= {30'b0, ChipSelectID};
|
||||
8'h14: Dout <= {28'b0, ChipSelectDef};
|
||||
8'h18: Dout <= {30'b0, ChipSelectMode};
|
||||
8'h28: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
|
||||
8'h2C: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
|
||||
8'h40: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
|
||||
8'h48: Dout <= {23'b0, TransmitFIFOWriteFull, 8'b0};
|
||||
8'h4C: Dout <= {23'b0, ReceiveFIFOReadEmpty, ReceiveData[7:0]};
|
||||
8'h50: Dout <= {29'b0, TransmitWatermark};
|
||||
8'h54: Dout <= {29'b0, ReceiveWatermark};
|
||||
8'h70: Dout <= {30'b0, InterruptEnable};
|
||||
8'h74: Dout <= {30'b0, InterruptPending};
|
||||
default: Dout <= 32'b0;
|
||||
SPI_SCKDIV: Dout <= {20'b0, SckDiv};
|
||||
SPI_SCKMODE: Dout <= {30'b0, SckMode};
|
||||
SPI_CSID: Dout <= {30'b0, ChipSelectID};
|
||||
SPI_CSDEF: Dout <= {28'b0, ChipSelectDef};
|
||||
SPI_CSMODE: Dout <= {30'b0, ChipSelectMode};
|
||||
SPI_DELAY0: Dout <= {8'b0, Delay0[15:8], 8'b0, Delay0[7:0]};
|
||||
SPI_DELAY1: Dout <= {8'b0, Delay1[15:8], 8'b0, Delay1[7:0]};
|
||||
SPI_FMT: Dout <= {12'b0, Format[4:1], 13'b0, Format[0], 2'b0};
|
||||
SPI_TXDATA: Dout <= {23'b0, TransmitFIFOWriteFull, 8'b0};
|
||||
SPI_RXDATA: Dout <= {23'b0, ReceiveFIFOReadEmpty, ReceiveData[7:0]};
|
||||
SPI_TXMARK: Dout <= {29'b0, TransmitWatermark};
|
||||
SPI_RXMARK: Dout <= {29'b0, ReceiveWatermark};
|
||||
SPI_IE: Dout <= {30'b0, InterruptEnable};
|
||||
SPI_IP: Dout <= {30'b0, InterruptPending};
|
||||
default: Dout <= 32'b0;
|
||||
endcase
|
||||
end
|
||||
|
||||
@ -200,8 +216,8 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
assign SCLKenable = (DivCounter == SckDiv);
|
||||
assign SCLKenableEarly = ((DivCounter + 12'b1) == SckDiv);
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) DivCounter <= 0;
|
||||
else if (SCLKenable) DivCounter <= 0;
|
||||
if (~PRESETn) DivCounter <= '0;
|
||||
else if (SCLKenable) DivCounter <= 12'b0;
|
||||
else DivCounter <= DivCounter + 12'b1;
|
||||
|
||||
// Asserts when transmission is one frame before complete
|
||||
@ -219,11 +235,11 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
// Calculate tx/rx fifo write and recieve increment signals
|
||||
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) TransmitFIFOWriteIncrement <= 0;
|
||||
if (~PRESETn) TransmitFIFOWriteIncrement <= 1'b0;
|
||||
else TransmitFIFOWriteIncrement <= (Memwrite & (Entry == 8'h48) & ~TransmitFIFOWriteFull & TransmitInactive);
|
||||
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) ReceiveFIFOReadIncrement <= 0;
|
||||
if (~PRESETn) ReceiveFIFOReadIncrement <= 1'b0;
|
||||
else ReceiveFIFOReadIncrement <= ((Entry == 8'h4C) & ~ReceiveFIFOReadEmpty & PSEL & ~ReceiveFIFOReadIncrement);
|
||||
|
||||
// Tx/Rx FIFOs
|
||||
@ -233,14 +249,14 @@ module spi_apb import cvw::*; #(parameter cvw_t P) (
|
||||
ReceiveData[7:0], ReceiveFIFOWriteFull, ReceiveFIFOReadEmpty, RecieveWriteMark, RecieveReadMark);
|
||||
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1;
|
||||
if (~PRESETn) TransmitFIFOReadEmptyDelay <= 1'b1;
|
||||
else if (SCLKenable) TransmitFIFOReadEmptyDelay <= TransmitFIFOReadEmpty;
|
||||
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) ReceiveShiftFullDelay <= 0;
|
||||
if (~PRESETn) ReceiveShiftFullDelay <= 1'b0;
|
||||
else if (SCLKenable) ReceiveShiftFullDelay <= ReceiveShiftFull;
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) ReceiveShiftFullDelayPCLK <= 0;
|
||||
if (~PRESETn) ReceiveShiftFullDelayPCLK <= 1'b0;
|
||||
else if (SCLKenableEarly) ReceiveShiftFullDelayPCLK <= ReceiveShiftFull;
|
||||
|
||||
assign TransmitShiftRegLoad = ~TransmitShiftEmpty & ~Active | (((ChipSelectMode == 2'b10) & ~|(Delay1[15:8])) & ((ReceiveShiftFullDelay | ReceiveShiftFull) & ~SampleEdge & ~TransmitFIFOReadEmpty));
|
||||
@ -399,12 +415,11 @@ module SynchFIFO #(parameter M=3, N=8)( // 2^M entries of N bits
|
||||
// write and read are enabled
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
rptr <= 0;
|
||||
wptr <= 0;
|
||||
rptr <= '0;
|
||||
wptr <= '0;
|
||||
wfull <= 1'b0;
|
||||
rempty <= 1'b1;
|
||||
end
|
||||
else begin
|
||||
end else begin
|
||||
if (wen) begin
|
||||
wfull <= ({~wptrnext[M], wptrnext[M-1:0]} == rptr);
|
||||
wptr <= wptrnext;
|
||||
@ -429,13 +444,13 @@ module TransmitShiftFSM(
|
||||
output logic TransmitShiftEmpty);
|
||||
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) TransmitShiftEmpty <= 1;
|
||||
if (~PRESETn) TransmitShiftEmpty <= 1'b1;
|
||||
else if (TransmitShiftEmpty) begin
|
||||
if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrame & Active0))) TransmitShiftEmpty <= 1;
|
||||
else if (~TransmitFIFOReadEmpty) TransmitShiftEmpty <= 0;
|
||||
if (TransmitFIFOReadEmpty | (~TransmitFIFOReadEmpty & (ReceivePenultimateFrame & Active0))) TransmitShiftEmpty <= 1'b1;
|
||||
else if (~TransmitFIFOReadEmpty) TransmitShiftEmpty <= 1'b0;
|
||||
end else begin
|
||||
if (ReceivePenultimateFrame & Active0) TransmitShiftEmpty <= 1;
|
||||
else TransmitShiftEmpty <= 0;
|
||||
if (ReceivePenultimateFrame & Active0) TransmitShiftEmpty <= 1'b1;
|
||||
else TransmitShiftEmpty <= 1'b0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -52,6 +52,16 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
output logic SOUT, RTSb, DTRb, OUT1b, OUT2b // UART external serial and flow-control outputs
|
||||
);
|
||||
|
||||
// register map
|
||||
localparam UART_DLL_RBR = 3'b000;
|
||||
localparam UART_DLM_IER = 3'b001;
|
||||
localparam UART_IIR = 3'b010;
|
||||
localparam UART_LCR = 3'b011;
|
||||
localparam UART_MCR = 3'b100;
|
||||
localparam UART_LSR = 3'b101;
|
||||
localparam UART_MSR = 3'b110;
|
||||
localparam UART_SCR = 3'b111;
|
||||
|
||||
// transmit and receive states
|
||||
typedef enum logic [1:0] {UART_IDLE, UART_ACTIVE, UART_DONE, UART_BREAK} statetype;
|
||||
|
||||
@ -150,35 +160,35 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
if (~MEMWb) begin
|
||||
/* verilator lint_off CASEINCOMPLETE */
|
||||
case (A)
|
||||
3'b000: if (DLAB) DLL <= Din; // else TXHR <= Din; // TX handled in TX register/FIFO section
|
||||
3'b001: if (DLAB) DLM <= Din; else IER <= Din[3:0];
|
||||
3'b010: FCR <= {Din[7:6], 2'b0, Din[3], 2'b0, Din[0]}; // Write only FIFO Control Register; 4:5 reserved and 2:1 self-clearing
|
||||
3'b011: LCR <= Din;
|
||||
3'b100: MCR <= Din[4:0];
|
||||
3'b111: SCR <= Din;
|
||||
UART_DLL_RBR: if (DLAB) DLL <= Din; // else TXHR <= Din; // TX handled in TX register/FIFO section
|
||||
UART_DLM_IER: if (DLAB) DLM <= Din; else IER <= Din[3:0];
|
||||
UART_IIR: FCR <= {Din[7:6], 2'b0, Din[3], 2'b0, Din[0]}; // Write only FIFO Control Register; 4:5 reserved and 2:1 self-clearing
|
||||
UART_LCR: LCR <= Din;
|
||||
UART_MCR: MCR <= Din[4:0];
|
||||
UART_SCR: SCR <= Din;
|
||||
endcase
|
||||
/* verilator lint_on CASEINCOMPLETE */
|
||||
end
|
||||
|
||||
// Line Status Register (8.6.3)
|
||||
// Ben 6/9/21 I don't like how this is a register. A lot of the individual bits have clocked components, so this just adds unecessary delay.
|
||||
if (~MEMWb & (A == 3'b101))
|
||||
if (~MEMWb & (A == UART_LSR))
|
||||
LSR[6:1] <= Din[6:1]; // recommended only for test, see 8.6.3
|
||||
else begin
|
||||
LSR[0] <= rxdataready; // Data ready
|
||||
LSR[1] <= (LSR[1] | RXBR[10]) & ~squashRXerrIP;; // overrun error
|
||||
LSR[2] <= (LSR[2] | RXBR[9]) & ~squashRXerrIP; // parity error
|
||||
LSR[3] <= (LSR[3] | RXBR[8]) & ~squashRXerrIP; // framing error
|
||||
LSR[4] <= (LSR[4] | rxbreak) & ~squashRXerrIP; // break indicator
|
||||
LSR[1] <= (LSR[1] | RXBR[10]) & ~squashRXerrIP; // overrun error
|
||||
LSR[2] <= (LSR[2] | RXBR[9]) & ~squashRXerrIP; // parity error
|
||||
LSR[3] <= (LSR[3] | RXBR[8]) & ~squashRXerrIP; // framing error
|
||||
LSR[4] <= (LSR[4] | rxbreak) & ~squashRXerrIP; // break indicator
|
||||
LSR[5] <= THRE; // THRE
|
||||
LSR[6] <= ~txsrfull & THRE; // TEMT
|
||||
if (rxfifohaserr) LSR[7] <= 1; // any bits in FIFO have error
|
||||
if (rxfifohaserr) LSR[7] <= 1'b1; // any bits in FIFO have error
|
||||
end
|
||||
|
||||
// Modem Status Register (8.6.8)
|
||||
if (~MEMWb & (A == 3'b110))
|
||||
if (~MEMWb & (A == UART_MSR))
|
||||
MSR <= Din[3:0];
|
||||
else if (~MEMRb & (A == 3'b110))
|
||||
else if (~MEMRb & (A == UART_MSR))
|
||||
MSR <= 4'b0; // Reading MSR clears the flags in MSR bits 3:0
|
||||
else begin
|
||||
MSR[0] <= MSR[0] | CTSb2 ^ CTSbsync; // Delta Clear to Send
|
||||
@ -187,18 +197,18 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
MSR[3] <= MSR[3] | DCDb2 ^ DCDbsync; // Delta Data Carrier Detect
|
||||
end
|
||||
end
|
||||
|
||||
always_comb
|
||||
if (~MEMRb)
|
||||
case (A)
|
||||
3'b000: if (DLAB) Dout = DLL; else Dout = RBR[7:0];
|
||||
3'b001: if (DLAB) Dout = DLM; else Dout = {4'b0, IER[3:0]};
|
||||
3'b010: Dout = {{2{fifoenabled}}, 2'b00, intrID[2:0], ~intrpending}; // Read only Interupt Ident Register
|
||||
3'b011: Dout = LCR;
|
||||
3'b100: Dout = {3'b000, MCR};
|
||||
3'b101: Dout = LSR;
|
||||
// 3'b110: Dout = {~CTSbsync, ~DSRbsync, ~RIbsync, ~DCDbsync, MSR[3:0]};
|
||||
3'b110: Dout = {~DCDbsync, ~RIbsync, ~DSRbsync, ~CTSbsync, MSR[3:0]};
|
||||
3'b111: Dout = SCR;
|
||||
UART_DLL_RBR: if (DLAB) Dout = DLL; else Dout = RBR[7:0];
|
||||
UART_DLM_IER: if (DLAB) Dout = DLM; else Dout = {4'b0, IER[3:0]};
|
||||
UART_IIR: Dout = {{2{fifoenabled}}, 2'b00, intrID[2:0], ~intrpending}; // Read only Interupt Ident Register
|
||||
UART_LCR: Dout = LCR;
|
||||
UART_MCR: Dout = {3'b000, MCR};
|
||||
UART_LSR: Dout = LSR;
|
||||
UART_MSR: Dout = {~DCDbsync, ~RIbsync, ~DSRbsync, ~CTSbsync, MSR[3:0]};
|
||||
UART_SCR: Dout = SCR;
|
||||
endcase
|
||||
else Dout = 8'b0;
|
||||
|
||||
@ -215,7 +225,7 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
baudcount <= 1;
|
||||
baudpulse <= 0;
|
||||
baudpulse <= 1'b0;
|
||||
end else if (~MEMWb & DLAB & (A == 3'b0 | A == 3'b1)) begin
|
||||
baudcount <= 1;
|
||||
end else begin
|
||||
@ -240,18 +250,18 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
rxoversampledcnt <= 0;
|
||||
rxoversampledcnt <= '0;
|
||||
rxstate <= UART_IDLE;
|
||||
rxbitsreceived <= 0;
|
||||
rxtimeoutcnt <= 0;
|
||||
rxbitsreceived <= '0;
|
||||
rxtimeoutcnt <= '0;
|
||||
end else begin
|
||||
if (rxstate == UART_IDLE & ~SINsync) begin // got start bit
|
||||
rxstate <= UART_ACTIVE;
|
||||
rxoversampledcnt <= 0;
|
||||
rxbitsreceived <= 0;
|
||||
if (~rxfifotimeout) rxtimeoutcnt <= 0; // reset timeout when new character is arriving. Jacob Pease: Only if the timeout was not already reached. p.16 PC16550D.pdf
|
||||
rxoversampledcnt <= '0;
|
||||
rxbitsreceived <= '0;
|
||||
if (~rxfifotimeout) rxtimeoutcnt <= '0; // reset timeout when new character is arriving. Jacob Pease: Only if the timeout was not already reached. p.16 PC16550D.pdf
|
||||
end else if (rxbaudpulse & (rxstate == UART_ACTIVE)) begin
|
||||
rxoversampledcnt <= rxoversampledcnt + 1; // 16x oversampled counter
|
||||
rxoversampledcnt <= rxoversampledcnt + 4'b1; // 16x oversampled counter
|
||||
if (rxcentered) rxbitsreceived <= rxbitsreceived + 1;
|
||||
if (rxbitsreceived == rxbitsexpected) rxstate <= UART_DONE; // pulse rxdone for a cycle
|
||||
end else if (rxstate == UART_DONE | rxstate == UART_BREAK) begin
|
||||
@ -259,7 +269,7 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
else rxstate <= UART_IDLE;
|
||||
end
|
||||
// timeout counting
|
||||
if (~MEMRb & A == 3'b000 & ~DLAB) rxtimeoutcnt <= 0; // reset timeout on read
|
||||
if (~MEMRb & A == 3'b000 & ~DLAB) rxtimeoutcnt <= '0; // reset timeout on read
|
||||
else if (fifoenabled & ~rxfifoempty & rxbaudpulse & ~rxfifotimeout) rxtimeoutcnt <= rxtimeoutcnt+1; // may not be right
|
||||
end
|
||||
|
||||
@ -295,32 +305,32 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
// receive FIFO and register
|
||||
always_ff @(posedge PCLK)
|
||||
if (~PRESETn) begin
|
||||
rxfifohead <= 0; rxfifotail <= 0; rxdataready <= 0; RXBR <= 0;
|
||||
rxfifohead <= '0; rxfifotail <= '0; rxdataready <= 1'b0; RXBR <= '0;
|
||||
end else begin
|
||||
if (~MEMWb & (A == 3'b010) & Din[1]) begin
|
||||
rxfifohead <= 0; rxfifotail <= 0; rxdataready <= 0;
|
||||
rxfifohead <= '0; rxfifotail <= '0; rxdataready <= 1'b0;
|
||||
end else if (rxstate == UART_DONE) begin
|
||||
RXBR <= {rxoverrunerr, rxparityerr, rxframingerr, rxdata}; // load recevive buffer register
|
||||
if (rxoverrunerr) $warning("UART RX Overrun Err\n");
|
||||
if (rxparityerr) $warning("UART RX Parity Err\n");
|
||||
if (rxframingerr) $warning("UART RX Framing Err\n");
|
||||
// if (rxoverrunerr) $warning("UART RX Overrun Err\n");
|
||||
// if (rxparityerr) $warning("UART RX Parity Err\n");
|
||||
// if (rxframingerr) $warning("UART RX Framing Err\n");
|
||||
if (fifoenabled) begin
|
||||
rxfifo[rxfifohead] <= {rxoverrunerr, rxparityerr, rxframingerr, rxdata};
|
||||
rxfifohead <= rxfifohead + 1;
|
||||
rxfifohead <= rxfifohead + 1'b1;
|
||||
end
|
||||
rxdataready <= 1;
|
||||
rxdataready <= 1'b1;
|
||||
end else if (~MEMRb & A == 3'b000 & ~DLAB) begin // reading RBR updates ready / pops fifo
|
||||
if (fifoenabled) begin
|
||||
if (~rxfifoempty) rxfifotail <= rxfifotail + 1;
|
||||
// if (rxfifoempty) rxdataready <= 0;
|
||||
if (rxfifoentries == 1) rxdataready <= 0; // When reading the last entry, data ready becomes zero
|
||||
// if (rxfifoempty) rxdataready <= 1'b0;
|
||||
if (rxfifoentries == 1) rxdataready <= 1'b0; // When reading the last entry, data ready becomes zero
|
||||
end else begin
|
||||
rxdataready <= 0;
|
||||
rxdataready <= 1'b0;
|
||||
RXBR <= {1'b0, RXBR[9:0]}; // Ben 31 March 2022: I added this so that rxoverrunerr permanently goes away upon reading RBR (when not in FIFO mode)
|
||||
end
|
||||
end else if (~MEMWb & A == 3'b010) // writes to FIFO Control Register
|
||||
if (Din[1] | ~Din[0]) begin // rx FIFO reset or FIFO disable clears FIFO contents
|
||||
rxfifohead <= 0; rxfifotail <= 0;
|
||||
rxfifohead <= '0; rxfifotail <= '0;
|
||||
end
|
||||
end
|
||||
|
||||
@ -354,9 +364,9 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
|
||||
// receive buffer register and ready bit
|
||||
always_ff @(posedge PCLK, negedge PRESETn) // track rxrdy for DMA mode (FCR3 = FCR0 = 1)
|
||||
if (~PRESETn) rxfifodmaready <= 0;
|
||||
else if (rxfifotriggered | rxfifotimeout) rxfifodmaready <= 1;
|
||||
else if (rxfifoempty) rxfifodmaready <= 0;
|
||||
if (~PRESETn) rxfifodmaready <= 1'b0;
|
||||
else if (rxfifotriggered | rxfifotimeout) rxfifodmaready <= 1'b1;
|
||||
else if (rxfifoempty) rxfifodmaready <= 1'b0;
|
||||
|
||||
always_comb
|
||||
if (fifoenabled) begin
|
||||
@ -375,17 +385,17 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
txoversampledcnt <= 0;
|
||||
txoversampledcnt <= '0;
|
||||
txstate <= UART_IDLE;
|
||||
txbitssent <= 0;
|
||||
txbitssent <= '0;
|
||||
end else if ((txstate == UART_IDLE) & txsrfull) begin // start transmitting
|
||||
txstate <= UART_ACTIVE;
|
||||
txoversampledcnt <= 1;
|
||||
txbitssent <= 0;
|
||||
txoversampledcnt <= 4'b1;
|
||||
txbitssent <= '0;
|
||||
end else if (txbaudpulse & (txstate == UART_ACTIVE)) begin
|
||||
txoversampledcnt <= txoversampledcnt + 1;
|
||||
txoversampledcnt <= txoversampledcnt + 1'b1;
|
||||
if (txnextbit) begin // transmit at end of phase
|
||||
txbitssent <= txbitssent+1;
|
||||
txbitssent <= txbitssent + 1'b1;
|
||||
if (txbitssent == txbitsexpected) txstate <= UART_DONE;
|
||||
end
|
||||
end else if (txstate == UART_DONE) begin
|
||||
@ -423,17 +433,17 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
// registers & FIFO
|
||||
always_ff @(posedge PCLK, negedge PRESETn)
|
||||
if (~PRESETn) begin
|
||||
txfifohead <= 0; txfifotail <= 0; txhrfull <= 0; txsrfull <= 0; TXHR <= 0; txsr <= 12'hfff;
|
||||
txfifohead <= '0; txfifotail <= '0; txhrfull <= 1'b0; txsrfull <= 1'b0; TXHR <= '0; txsr <= 12'hfff;
|
||||
end else if (~MEMWb & (A == 3'b010) & Din[2]) begin
|
||||
txfifohead <= 0; txfifotail <= 0;
|
||||
txfifohead <= '0; txfifotail <= '0;
|
||||
end else begin
|
||||
if (~MEMWb & A == 3'b000 & ~DLAB) begin // writing transmit holding register or fifo
|
||||
if (fifoenabled) begin
|
||||
txfifo[txfifohead] <= Din;
|
||||
txfifohead <= txfifohead + 1;
|
||||
txfifohead <= txfifohead + 4'b1;
|
||||
end else begin
|
||||
TXHR <= Din;
|
||||
txhrfull <= 1;
|
||||
txhrfull <= 1'b1;
|
||||
end
|
||||
$write("%c",Din); // for testbench
|
||||
end
|
||||
@ -442,18 +452,18 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
if (~txfifoempty & ~txsrfull) begin
|
||||
txsr <= txdata;
|
||||
txfifotail <= txfifotail+1;
|
||||
txsrfull <= 1;
|
||||
txsrfull <= 1'b1;
|
||||
end
|
||||
end else if (txhrfull) begin
|
||||
txsr <= txdata;
|
||||
txhrfull <= 0;
|
||||
txsrfull <= 1;
|
||||
txhrfull <= 1'b0;
|
||||
txsrfull <= 1'b1;
|
||||
end
|
||||
end else if (txstate == UART_DONE) txsrfull <= 0; // done transmitting shift register
|
||||
end else if (txstate == UART_DONE) txsrfull <= 1'b0; // done transmitting shift register
|
||||
else if (txstate == UART_ACTIVE & txnextbit) txsr <= {txsr[10:0], 1'b1}; // shift txhr
|
||||
if (!MEMWb & A == 3'b010) // writes to FIFO control register
|
||||
if (Din[2] | ~Din[0]) begin // tx FIFO reste or FIFO disable clears FIFO contents
|
||||
txfifohead <= 0; txfifotail <= 0;
|
||||
txfifohead <= '0; txfifotail <= '0;
|
||||
end
|
||||
end
|
||||
|
||||
@ -483,9 +493,9 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
|
||||
// transmit buffer ready bit
|
||||
always_ff @(posedge PCLK, negedge PRESETn) // track txrdy for DMA mode (FCR3 = FCR0 = 1)
|
||||
if (~PRESETn) txfifodmaready <= 0;
|
||||
else if (txfifoempty) txfifodmaready <= 1;
|
||||
else if (txfifofull) txfifodmaready <= 0;
|
||||
if (~PRESETn) txfifodmaready <= 1'b0;
|
||||
else if (txfifoempty) txfifodmaready <= 1'b1;
|
||||
else if (txfifofull) txfifodmaready <= 1'b0;
|
||||
|
||||
always_comb
|
||||
if (fifoenabled & fifodmamodesel) TXRDYb = ~txfifodmaready;
|
||||
@ -493,7 +503,7 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
|
||||
// Transmitter pin
|
||||
assign SOUTbit = txsr[11]; // transmit most significant bit
|
||||
assign SOUT = loop ? 1 : (LCR[6] ? 0 : SOUTbit); // tied to 1 during loopback or 0 during break
|
||||
assign SOUT = loop ? 1 : (LCR[6] ? '0 : SOUTbit); // tied to 1 during loopback or 0 during break
|
||||
|
||||
///////////////////////////////////////////
|
||||
// interrupts
|
||||
@ -509,7 +519,7 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
// IIR: interrupt priority (Table 5)
|
||||
// set intrID based on highest priority pending interrupt source; otherwise, no interrupt is pending
|
||||
always_comb begin
|
||||
intrpending = 1;
|
||||
intrpending = 1'b1;
|
||||
if (RXerrIP & IER[2]) intrID = 3'b011;
|
||||
else if (rxdataavailintr & IER[0]) intrID = 3'b010;
|
||||
else if (rxfifotimeout & fifoenabled & IER[0]) intrID = 3'b110;
|
||||
@ -517,7 +527,7 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
else if (modemstatusintr & IER[3]) intrID = 3'b000;
|
||||
else begin
|
||||
intrID = 3'b000;
|
||||
intrpending = 0;
|
||||
intrpending = 1'b0;
|
||||
end
|
||||
end
|
||||
always_ff @(posedge PCLK) INTR <= intrpending; // prevent glitches on interrupt pin
|
||||
@ -549,10 +559,10 @@ module uartPC16550D #(parameter UART_PRESCALE) (
|
||||
assign fifodmamodesel = FCR[3];
|
||||
always_comb
|
||||
case (FCR[7:6])
|
||||
2'b00: rxfifotriggerlevel = 1;
|
||||
2'b01: rxfifotriggerlevel = 4;
|
||||
2'b10: rxfifotriggerlevel = 8;
|
||||
2'b11: rxfifotriggerlevel = 14;
|
||||
2'b00: rxfifotriggerlevel = 4'd1;
|
||||
2'b01: rxfifotriggerlevel = 4'd4;
|
||||
2'b10: rxfifotriggerlevel = 4'd8;
|
||||
2'b11: rxfifotriggerlevel = 4'd14;
|
||||
endcase
|
||||
|
||||
endmodule
|
||||
|
Loading…
Reference in New Issue
Block a user