diff --git a/MacPlus.qsf b/MacPlus.qsf
index 56d2347..c61cccd 100644
--- a/MacPlus.qsf
+++ b/MacPlus.qsf
@@ -13,7 +13,7 @@ set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
-set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Standard Edition"
+set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Lite Edition"
set_global_assignment -name GENERATE_RBF_FILE ON
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
diff --git a/MacPlus.sv b/MacPlus.sv
index 74a73a9..ee41455 100644
--- a/MacPlus.sv
+++ b/MacPlus.sv
@@ -175,7 +175,7 @@ module emu
assign ADC_BUS = 'Z;
assign USER_OUT = '1;
-assign {UART_RTS, UART_TXD, UART_DTR} = 0;
+
assign {DDRAM_CLK, DDRAM_BURSTCNT, DDRAM_ADDR, DDRAM_DIN, DDRAM_BE, DDRAM_RD, DDRAM_WE} = 0;
assign {SD_SCK, SD_MOSI, SD_CS} = 'Z;
@@ -201,7 +201,7 @@ video_freak video_freak
`include "build_id.v"
localparam CONF_STR = {
- "MACPLUS;;",
+ "MACPLUS;UART115200;",
"-;",
"F1,DSK,Mount Pri Floppy;",
"F2,DSK,Mount Sec Floppy;",
@@ -216,6 +216,8 @@ localparam CONF_STR = {
"ODE,CPU,68000,68010,68020;",
"O4,Memory,1MB,4MB;",
"-;",
+ //"OA,Serial,Off,On;",
+ //"-;",
"R0,Reset & Apply CPU+Memory;",
"V,v",`BUILD_DATE
};
@@ -358,11 +360,44 @@ assign AUDIO_MIX = 0;
// set the real-world inputs to sane defaults
-localparam serialIn = 1'b0,
- configROMSize = 1'b1; // 128K ROM
+localparam configROMSize = 1'b1; // 128K ROM
wire [1:0] configRAMSize = status_mem?2'b11:2'b10; // 1MB/4MB
+//
+// Serial Ports
+//
+wire serialOut;
+wire serialIn;
+wire serialCTS;
+wire serialRTS;
+
+/*
+assign serialIn = ~status[10] ? 0 : UART_RXD;
+assign UART_TXD = serialOut;
+assign serialCTS = UART_CTS;
+assign UART_RTS = serialRTS;
+assign UART_DTR = UART_DSR;
+*/
+
+//assign serialIn = ~status[10] ? 0 : UART_RXD;
+assign serialIn = UART_RXD;
+assign UART_TXD = serialOut;
+//assign UART_RTS = UART_CTS;
+assign UART_RTS = serialRTS ;
+assign UART_DTR = UART_DSR;
+
+//assign {UART_RTS, UART_TXD, UART_DTR} = 0;
+/*
+ input UART_CTS,
+ output UART_RTS,
+ input UART_RXD,
+ output UART_TXD,
+ output UART_DTR,
+ input UART_DSR,
+*/
+
+
// interconnects
// CPU
wire clk8, _cpuReset, _cpuReset_o, _cpuUDS, _cpuLDS, _cpuRW, _cpuAS;
@@ -618,7 +653,13 @@ dataController_top dc0
.ps2_key(ps2_key),
.capslock(capslock),
.ps2_mouse(ps2_mouse),
+ // serial uart
.serialIn(serialIn),
+ .serialOut(serialOut),
+ .serialCTS(serialCTS),
+ .serialRTS(serialRTS),
+
+ // rtc unix ticks
.timestamp(TIMESTAMP),
// video
diff --git a/files.qip b/files.qip
index c76b310..5cd2109 100644
--- a/files.qip
+++ b/files.qip
@@ -8,6 +8,8 @@ set_global_assignment -name VERILOG_FILE rtl/floppy.v
set_global_assignment -name SYSTEMVERILOG_FILE rtl/ps2_kbd.sv
set_global_assignment -name VERILOG_FILE rtl/ps2_mouse.v
set_global_assignment -name VERILOG_FILE rtl/scc.v
+set_global_assignment -name VERILOG_FILE rtl/uart/txuart.v
+set_global_assignment -name VERILOG_FILE rtl/uart/rxuart.v
set_global_assignment -name VERILOG_FILE rtl/iwm.v
set_global_assignment -name VHDL_FILE rtl/via6522.vhd
set_global_assignment -name VERILOG_FILE rtl/addrDecoder.v
diff --git a/rtl/dataController_top.v b/rtl/dataController_top.v
index 44cb307..523d787 100644
--- a/rtl/dataController_top.v
+++ b/rtl/dataController_top.v
@@ -47,6 +47,8 @@ module dataController_top(
// serial:
input serialIn,
output serialOut,
+ input serialCTS,
+ output serialRTS,
// RTC
input [32:0] timestamp,
@@ -148,8 +150,6 @@ module dataController_top(
!_sccIrq?3'b101:
3'b111;
- // Serial port
- assign serialOut = 0;
reg [15:0] cpu_data;
always @(posedge clk32) if (cpuBusControl && memoryLatch) cpu_data <= memoryDataIn;
@@ -409,8 +409,13 @@ module dataController_top(
._irq(_sccIrq),
.dcd_a(mouseX1),
.dcd_b(mouseY1),
- .wreq(sccWReq));
-
+ .wreq(sccWReq),
+ .txd(serialOut),
+ .rxd(serialIn),
+ .cts(serialCTS),
+ .rts(serialRTS)
+ );
+
// Video
videoShifter vs(
.clk32(clk32),
diff --git a/rtl/ps2_kbd.sv b/rtl/ps2_kbd.sv
index 123708b..1a12afd 100644
--- a/rtl/ps2_kbd.sv
+++ b/rtl/ps2_kbd.sv
@@ -22,7 +22,7 @@ module ps2_kbd
reg [8:0] keymac;
reg key_pending;
-reg [21:0] pacetimer;
+reg [19:0] pacetimer;
reg inquiry_active;
reg cmd_inquiry;
reg cmd_instant;
@@ -68,8 +68,8 @@ always@(posedge clk or posedge reset) begin
end
end
-wire tick_long = pacetimer == 22'h3fffff;
-wire tick_short = pacetimer == 22'h000fff;
+wire tick_long = pacetimer == 20'hfffff;
+wire tick_short = pacetimer == 20'h00fff;
/* Delay inquiry responses to after tick_short */
always@(posedge clk or posedge reset) begin
diff --git a/rtl/scc.v b/rtl/scc.v
index bc3f8b7..acd6ae6 100644
--- a/rtl/scc.v
+++ b/rtl/scc.v
@@ -62,7 +62,8 @@ module scc
wire reset;
/* Data registers */
- reg [7:0] data_a = 0;
+// reg [7:0] data_a = 0;
+ wire[7:0] data_a ;
reg [7:0] data_b = 0;
/* Read registers */
@@ -84,6 +85,10 @@ module scc
reg [7:0] wr1_a;
reg [7:0] wr1_b;
reg [7:0] wr2;
+ reg [7:0] wr3_a; /* synthesis keep */
+ reg [7:0] wr3_b;
+ reg [7:0] wr4_a;
+ reg [7:0] wr4_b;
reg [7:0] wr5_a;
reg [7:0] wr5_b;
reg [7:0] wr6_a;
@@ -105,8 +110,10 @@ module scc
/* Status latches */
reg latch_open_a;
reg latch_open_b;
+ reg cts_latch_a;
reg dcd_latch_a;
reg dcd_latch_b;
+ wire cts_ip_a;
wire dcd_ip_a;
wire dcd_ip_b;
wire do_latch_a;
@@ -125,6 +132,10 @@ module scc
reg ex_irq_ip_b;
wire [2:0] rr2_vec_stat;
+ reg [7:0] tx_data_a;
+ reg wr8_wr_a;
+ reg wr8_wr_b;
+
/* Register/Data access helpers */
assign wreg_a = cs & we & (~rs[1]) & rs[0];
assign wreg_b = cs & we & (~rs[1]) & ~rs[0];
@@ -136,11 +147,28 @@ module scc
/* Register index is set by a write to WR0 and reset
* after any subsequent write. We ignore the side
*/
- always@(posedge clk or posedge reset) begin
+ reg wr_data_a;
+ reg wr_data_b;
+
+ reg rx_wr_a_latch;
+ reg rx_first_a=1;
+ always@(posedge clk /*or posedge reset*/) begin
+
+ if (rx_wr_a) begin
+ rx_wr_a_latch<=1;
+ end
+
+
+ wr_data_a<=0;
+ wr_data_b<=0;
if (reset) begin
rindex_latch <= 0;
- data_a <= 0;
- data_b <= 0;
+ //data_a <= 0;
+ tx_data_a<=0;
+ data_b <= 0;
+ rx_wr_a_latch<=0;
+ wr_data_a<=0;
+ rx_first_a<=1;
end else if (cen && cs) begin
if (!rs[1]) begin
/* Default, reset index */
@@ -153,12 +181,33 @@ module scc
/* Add point high */
rindex_latch[3] <= (wdata[5:3] == 3'b001);
+ /* enable int on next rx char */
+ if (wdata[5:3] == 3'b100)
+ rx_first_a<=1;
end
end else begin
if (we) begin
- if (rs[0]) data_a <= wdata;
- else data_b <= wdata;
- end
+ if (rs[0]) begin
+ //data_a <= wdata;
+ tx_data_a <= wdata;
+ wr_data_a<=1;
+ end
+ else
+ begin
+ data_b <= wdata;
+ wr_data_b<=1;
+ end
+ end
+ else begin
+ // clear the read register?
+ if (rs[0]) begin
+ rx_wr_a_latch<=0;
+ rx_first_a<=0;
+ end
+ else begin
+
+ end
+ end
end
end
end
@@ -207,6 +256,37 @@ module scc
wr2 <= wdata;
end
+ /* WR3
+ * Reset: unchanged
+ */
+ always@(posedge clk or posedge reset_hw) begin
+ if (reset_hw)
+ wr3_a <= 0;
+ else if (cen && wreg_a && rindex == 3)
+ wr3_a <= wdata;
+ end
+ always@(posedge clk or posedge reset_hw) begin
+ if (reset_hw)
+ wr3_b <= 0;
+ else if (cen && wreg_b && rindex == 3)
+ wr3_b <= wdata;
+ end
+ /* WR4
+ * Reset: unchanged
+ */
+ always@(posedge clk or posedge reset_hw) begin
+ if (reset_hw)
+ wr4_a <= 0;
+ else if (cen && wreg_a && rindex == 4)
+ wr4_a <= wdata;
+ end
+ always@(posedge clk or posedge reset_hw) begin
+ if (reset_hw)
+ wr4_b <= 0;
+ else if (cen && wreg_b && rindex == 4)
+ wr4_b <= wdata;
+ end
+
/* WR5
* Reset: Bits 7,4,3,2,1 to 0
*/
@@ -231,6 +311,39 @@ module scc
end
end
+ /* WR8 : write data to serial port -- a or b?
+ *
+ */
+ always@(posedge clk or posedge reset_hw) begin
+ if (reset_hw) begin
+ wr8_a <= 0;
+ wr8_wr_a <= 1'b0;
+ end
+ else if (cen && (rs[1] & we ) && rindex == 8) begin
+ wr8_wr_a <= 1'b1;
+ wr8_a <= wdata;
+ end
+ else begin
+ wr8_wr_a <= 1'b0;
+ end
+ end
+
+ always@(posedge clk or posedge reset_hw) begin
+ if (reset_hw) begin
+ wr8_b <= 0;
+ wr8_wr_b <= 1'b0;
+ end
+ else if (cen && (wreg_b ) && rindex == 8)
+ begin
+ wr8_wr_b <= 1'b1;
+ wr8_b <= wdata;
+ end
+ else
+ begin
+ wr8_wr_b <= 1'b0;
+ end
+ end
+
/* WR9. Special: top bits are reset, handled separately, bottom
* bits are only reset by a hw reset
*/
@@ -378,12 +491,13 @@ module scc
/* RR0 */
assign rr0_a = { 1'b0, /* Break */
1'b1, /* Tx Underrun/EOM */
- 1'b0, /* CTS */
+ wr15_a[5] ? cts_latch_a : cts_a, /* CTS */
1'b0, /* Sync/Hunt */
wr15_a[3] ? dcd_latch_a : dcd_a, /* DCD */
- 1'b1, /* Tx Empty */
+ //1'b1, /*TX EMPTY */
+ ~tx_busy_a, /* Tx Empty */
1'b0, /* Zero Count */
- 1'b0 /* Rx Available */
+ rx_wr_a_latch /* Rx Available */
};
assign rr0_b = { 1'b0, /* Break */
1'b1, /* Tx Underrun/EOM */
@@ -397,13 +511,13 @@ module scc
/* RR1 */
assign rr1_a = { 1'b0, /* End of frame */
- 1'b0, /* CRC/Framing error */
+ 1'b0,//frame_err_a, /* CRC/Framing error */
1'b0, /* Rx Overrun error */
- 1'b0, /* Parity error */
+ 1'b0,//parity_err_a, /* Parity error */
1'b0, /* Residue code 0 */
1'b1, /* Residue code 1 */
1'b1, /* Residue code 2 */
- 1'b1 /* All sent */
+ ~tx_busy_a /* All sent */
};
assign rr1_b = { 1'b0, /* End of frame */
@@ -483,15 +597,110 @@ module scc
*
* Need to add latches. Tx irq is latched when buffer goes from full->empty,
* it's not a permanent state. For now keep it clear. Will have to fix that.
+ * TODO: AJS - look at tx and interrupt logic
*/
- assign rx_irq_pend_a = 0;
- assign tx_irq_pend_a = 0 /*& wr1_a[1]*/; /* Tx always empty for now */
- assign ex_irq_pend_a = ex_irq_ip_a;
+
+ /*
+ The TxIP is reset either by writing data to the transmit buffer or by issuing the Reset Tx Int command in WR0
+ */
+
+reg tx_fin_pre;
+reg tx_ip;
+reg tx_mip;
+
+/*
+reg tx_ie;
+always @(posedge clk) begin
+ if (reset_a|reset_hw|reset)
+ tx_ie<=0;
+ else if (wreg_a & (rindex == 1) )
+ tx_ie<=wdata[1];
+end
+*/
+
+always @(posedge clk) begin
+ if (reset) begin
+ tx_ip<=0;
+ tx_mip<=0;
+ end
+ else begin
+ tx_fin_pre<=tx_busy_a;
+
+ if (wr5_a[3] & wr1_a[1] & tx_busy_a & ~tx_fin_pre) begin
+ tx_ip<=~tx_mip;
+ tx_mip<=0;
+ end
+ if (wreg_a & (rindex == 0) & (wdata[5:3] == 3'b111)) begin
+ tx_ip<=0;
+ end
+ if (wreg_a & (rindex == 0) & (wdata[5:3] == 3'b101)) begin
+ // If CIP=1, inhibit generation of next TX interrupt
+ // Actually, "Reset TxInt pend." clears current interrupt
+ tx_mip<= ~tx_ip;
+ tx_ip<=0;
+ end
+ if (wr5_a[3]==0)begin
+ tx_mip<=0;
+ tx_ip<=0;
+ end
+ end
+end
+
+
+
+
+
+ reg tx_busy_a_r;
+ reg tx_latch_a;
+ always @(posedge clk) begin
+ tx_busy_a_r <= tx_busy_a;
+ // when we transition from empty to full, we create an interrupt
+ if (reset | reset_hw | reset_a)
+ tx_latch_a<=0;
+ else if (tx_busy_a_r ==1 && tx_busy_a==0)
+ tx_latch_a<=1;
+ // cleared when we write again
+ else if (wr_data_a)
+ tx_latch_a<=0;
+ // or when we set the reset in wr0
+ else if (wreg_a & (rindex == 0) & (wdata[5:3] == 3'b010))
+ tx_latch_a<=0;
+ //else if (wreg_a & (rindex == 0) & (wdata[5:3] == 3'b111)) // clear highest under service?
+ end
+
+
+
+ wire wreq_n;
+ //assign rx_irq_pend_a = rx_wr_a_latch & ( (wr1_a[3] && ~wr1_a[4])|| (~wr1_a[3] && wr1_a[4])) & wr3_a[0]; /* figure out the interrupt on / off */
+ //assign rx_irq_pend_a = rx_wr_a_latch & ( (wr1_a[3] & ~wr1_a[4])| (~wr1_a[3] & wr1_a[4])) & wr3_a[0]; /* figure out the interrupt on / off */
+
+ /* figure out the interrupt on / off */
+ /* rx enable: wr3_a[0] */
+ /* wr1_a 4 3
+ 0 0 = rx int disable
+ 0 1 = rx int on first char or special
+ 1 0 = rx int on all rx chars or special
+ 1 1 = rx int on special cond only
+ */
+ // rx enable char waiting 01,10 only first char
+ assign rx_irq_pend_a = wr3_a[0] & rx_wr_a_latch & (wr1_a[3] ^ wr1_a[4]) & ((wr1_a[3] & rx_first_a )|(wr1_a[4]));
+
+// assign tx_irq_pend_a = 0;
+// assign tx_irq_pend_a = tx_busy_a & wr1_a[1];
+
+ assign tx_irq_pend_a = tx_ip;
+//assign tx_irq_pend_a = wr1_a[1]; /* Tx always empty for now */
+
+ wire cts_interrupt = wr1_a[0] && wr15_a[5] || (tx_busy_a_r ==1 && tx_busy_a==0) || (tx_busy_a_r ==0 && tx_busy_a==1);/* if cts changes */
+
+ assign ex_irq_pend_a = ex_irq_ip_a ;
assign rx_irq_pend_b = 0;
assign tx_irq_pend_b = 0 /*& wr1_b[1]*/; /* Tx always empty for now */
assign ex_irq_pend_b = ex_irq_ip_b;
assign _irq = ~(wr9[3] & (rx_irq_pend_a |
+
+
rx_irq_pend_b |
tx_irq_pend_a |
tx_irq_pend_b |
@@ -514,12 +723,13 @@ module scc
* corresponding interrupt is enabled in WR15
*/
assign dcd_ip_a = (dcd_a != dcd_latch_a) & wr15_a[3];
+ assign cts_ip_a = (cts_a != cts_latch_a) & wr15_a[5];
assign dcd_ip_b = (dcd_b != dcd_latch_b) & wr15_b[3];
/* Latches close when an enabled IP bit is set and latches
* are currently open
*/
- assign do_latch_a = latch_open_a & (dcd_ip_a /* | cts... */);
+ assign do_latch_a = latch_open_a & (dcd_ip_a | cts_ip_a /* | cts... */);
assign do_latch_b = latch_open_b & (dcd_ip_b /* | cts... */);
/* "Master" interrupt, set when latch close & WR1[0] is set */
@@ -570,10 +780,12 @@ module scc
always@(posedge clk or posedge reset) begin
if (reset) begin
dcd_latch_a <= 0;
+ cts_latch_a <= 0;
/* cts ... */
end else if(cep) begin
if (do_latch_a)
dcd_latch_a <= dcd_a;
+ cts_latch_a <= cts_a;
/* cts ... */
end
end
@@ -587,10 +799,151 @@ module scc
/* cts ... */
end
end
+
+
/* NYI */
- assign txd = 1;
- assign rts = 1;
+// assign txd = 1;
+// assign rts = 1;
- assign wreq = 1;
+ /* UART */
+
+//wr_3_a
+//wr_3_b
+// bit
+wire parity_ena_a= wr4_a[0];
+wire parity_even_a= wr4_a[1];
+reg [1:0] stop_bits_a= 2'b00;
+reg [1:0] bit_per_char_a = 2'b00;
+/*
+76543210
+data>>2 & 3
+wr4_a[3:2]
+case(wr4_a[3:2])
+2'b00:
+// sync mode enable
+2'b01:
+// 1 stop bit
+ stop_bits_a <= 2'b0;
+2'b10:
+// 1.5 stop bit
+ stop_bits_a <= 2'b0;
+2'b11:
+// 2 stop bit
+ stop_bits_a <= 2'b1;
+default:
+ stop_bits_a <= 2'b0;
+endcase
+
+*/
+/*
+76543210
+^__ 76
+wr_3_a[7:6] -- bits per char
+
+ case (wr_3_a[7:6]})
+ 2'b00: // 5
+ bit_per_char_a <= 2'b11;
+ 2'b01: // 7
+ bit_per_char_a <= 2'b01;
+ 2'b10: // 6
+ bit_per_char_a <= 2'b10;
+ 2'b11: // 8
+ bit_per_char_a <= 2'b00;
+ endcase
+*/
+/*
+300 -- 62.668800 / = 208896
+600 -- 62.668800 / = 104448
+1200-- 62.668800 / = 69632
+2400 -- 62.668800 / 2400 = 26112
+4800 -- 62.668800 / 4800 = 13056
+9600 -- 62.668800 / 9600 = 6528
+1440 -- 62.668800 / 14400 = 4352
+19200 -- 62.668800 / 19200= 3264
+38400 -- 62.668800 / 28800 = 2176
+38400 -- 62.668800 / 38400 = 1632
+57600 -- 62.668800 / 57600 = 1088
+115200 -- 62.668800 / 115200 = 544
+230400 -- 62.668800 / 230400 = 272
+
+
+32.5 / 115200 =
+
+*/
+// case the baud rate based on wr12_a and 13_a
+// wr_12_a -- contains the baud rate lower byte
+// wr_13_a -- contains the baud rate high byte
+/*
+ always @(posedge clk) begin
+ case ({wr13_a,wr12_a})
+ 16'd380: // 300 baud
+ baud_divid_speed_a <= 24'd108333;
+ 16'd94: // 1200 baud
+ baud_divid_speed_a <= 24'd27083;
+ 16'd46: // 2400 baud
+ baud_divid_speed_a <= 24'd13542;
+ 16'd22: // 4800 baud
+ baud_divid_speed_a <= 24'd6770;
+ 16'd10: // 9600 baud
+ baud_divid_speed_a <= 24'd3385;
+ 16'd6: // 14400 baud
+ baud_divid_speed_a <= 24'd2257;
+ 16'd4: // 19200 baud
+ baud_divid_speed_a <= 24'd1693;
+ 16'd2: // 28800 baud
+ baud_divid_speed_a <= 24'd1128;
+ 16'd1: // 38400 baud
+ baud_divid_speed_a <= 24'd846;
+ 16'd0: // 57600 baud
+ baud_divid_speed_a <= 24'd564;
+ default:
+ baud_divid_speed_a <= 24'd282;
+ endcase
+ end
+
+*/
+
+
+
+//reg [23:0] baud_divid_speed_a = 24'd1088;
+//reg [23:0] baud_divid_speed_a = 24'd544;
+reg [23:0] baud_divid_speed_a = 24'd282;
+//reg [23:0] baud_divid_speed_a = 24'd564;
+wire tx_busy_a;
+wire rx_wr_a;
+wire [30:0] uart_setup_rx_a = { 1'b0, bit_per_char_a, 1'b0, parity_ena_a, 1'b0, parity_even_a, baud_divid_speed_a } ;
+wire [30:0] uart_setup_tx_a = { 1'b0, bit_per_char_a, 1'b0, parity_ena_a, 1'b0, parity_even_a, baud_divid_speed_a } ;
+//wire [30:0] uart_setup_rx_a = { 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, baud_divid_speed_a } ;
+//wire [30:0] uart_setup_tx_a = { 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, baud_divid_speed_a } ;
+rxuart rxuart_a (
+ .i_clk(clk),
+ .i_reset(reset_a|reset_hw),
+ .i_setup(uart_setup_rx_a),
+ .i_uart_rx(rxd),
+ .o_wr(rx_wr_a), // TODO -- check on this flag
+ .o_data(data_a), // TODO we need to save this off only if wreq is set, and mux it into data_a in the right spot
+ .o_break(break_a),
+ .o_parity_err(parity_err_a),
+ .o_frame_err(frame_err_a),
+ .o_ck_uart()
+ );
+txuart txuart_a
+ (
+ .i_clk(clk),
+ .i_reset(reset_a|reset_hw),
+ .i_setup(uart_setup_tx_a),
+ .i_break(1'b0),
+ .i_wr(wr_data_a), // TODO -- we need to send data when we get the register command i guess???
+ .i_data(tx_data_a),
+ //.i_cts_n(~cts),
+ .i_cts_n(1'b0),
+ .o_uart_tx(txd),
+ .o_busy(tx_busy_a)); // TODO -- do we need this busy line?? probably
+
+ wire cts_a = ~tx_busy_a;
+
+ // RTS and CTS are active low
+ assign rts = rx_wr_a_latch;
+ assign wreq=1;
endmodule
diff --git a/rtl/uart/rxuart.v b/rtl/uart/rxuart.v
new file mode 100644
index 0000000..3bc3414
--- /dev/null
+++ b/rtl/uart/rxuart.v
@@ -0,0 +1,467 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: rxuart.v
+//
+// Project: wbuart32, a full featured UART with simulator
+//
+// Purpose: Receive and decode inputs from a single UART line.
+//
+//
+// To interface with this module, connect it to your system clock,
+// pass it the 32 bit setup register (defined below) and the UART
+// input. When data becomes available, the o_wr line will be asserted
+// for one clock cycle. On parity or frame errors, the o_parity_err
+// or o_frame_err lines will be asserted. Likewise, on a break
+// condition, o_break will be asserted. These lines are self clearing.
+//
+// There is a synchronous reset line, logic high.
+//
+// Now for the setup register. The register is 32 bits, so that this
+// UART may be set up over a 32-bit bus.
+//
+// i_setup[30] True if we are not using hardware flow control. This bit
+// is ignored within this module, as any receive hardware flow
+// control will need to be implemented elsewhere.
+//
+// i_setup[29:28] Indicates the number of data bits per word. This will
+// either be 2'b00 for an 8-bit word, 2'b01 for a 7-bit word, 2'b10
+// for a six bit word, or 2'b11 for a five bit word.
+//
+// i_setup[27] Indicates whether or not to use one or two stop bits.
+// Set this to one to expect two stop bits, zero for one.
+//
+// i_setup[26] Indicates whether or not a parity bit exists. Set this
+// to 1'b1 to include parity.
+//
+// i_setup[25] Indicates whether or not the parity bit is fixed. Set
+// to 1'b1 to include a fixed bit of parity, 1'b0 to allow the
+// parity to be set based upon data. (Both assume the parity
+// enable value is set.)
+//
+// i_setup[24] This bit is ignored if parity is not used. Otherwise,
+// in the case of a fixed parity bit, this bit indicates whether
+// mark (1'b1) or space (1'b0) parity is used. Likewise if the
+// parity is not fixed, a 1'b1 selects even parity, and 1'b0
+// selects odd.
+//
+// i_setup[23:0] Indicates the speed of the UART in terms of clocks.
+// So, for example, if you have a 200 MHz clock and wish to
+// run your UART at 9600 baud, you would take 200 MHz and divide
+// by 9600 to set this value to 24'd20834. Likewise if you wished
+// to run this serial port at 115200 baud from a 200 MHz clock,
+// you would set the value to 24'd1736
+//
+// Thus, to set the UART for the common setting of an 8-bit word,
+// one stop bit, no parity, and 115200 baud over a 200 MHz clock, you
+// would want to set the setup value to:
+//
+// 32'h0006c8 // For 115,200 baud, 8 bit, no parity
+// 32'h005161 // For 9600 baud, 8 bit, no parity
+//
+//
+//
+// Creator: Dan Gisselquist, Ph.D.
+// Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015-2019, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. (It's in the $(ROOT)/doc directory. Run make with no
+// target there if the PDF file isn't present.) If not, see
+// for a copy.
+//
+// License: GPL, v3, as defined and found on www.gnu.org,
+// http://www.gnu.org/licenses/gpl.html
+//
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+// States: (@ baud counter == 0)
+// 0 First bit arrives
+// ..7 Bits arrive
+// 8 Stop bit (x1)
+// 9 Stop bit (x2)
+// c break condition
+// d Waiting for the channel to go high
+// e Waiting for the reset to complete
+// f Idle state
+`define RXU_BIT_ZERO 4'h0
+`define RXU_BIT_ONE 4'h1
+`define RXU_BIT_TWO 4'h2
+`define RXU_BIT_THREE 4'h3
+`define RXU_BIT_FOUR 4'h4
+`define RXU_BIT_FIVE 4'h5
+`define RXU_BIT_SIX 4'h6
+`define RXU_BIT_SEVEN 4'h7
+`define RXU_PARITY 4'h8
+`define RXU_STOP 4'h9
+`define RXU_SECOND_STOP 4'ha
+// Unused 4'hb
+// Unused 4'hc
+`define RXU_BREAK 4'hd
+`define RXU_RESET_IDLE 4'he
+`define RXU_IDLE 4'hf
+
+module rxuart(i_clk, i_reset, i_setup, i_uart_rx, o_wr, o_data, o_break,
+ o_parity_err, o_frame_err, o_ck_uart);
+ parameter [30:0] INITIAL_SETUP = 31'd868;
+ // 8 data bits, no parity, (at least 1) stop bit
+ input wire i_clk, i_reset;
+ /* verilator lint_off UNUSED */
+ input wire [30:0] i_setup;
+ /* verilator lint_on UNUSED */
+ input wire i_uart_rx;
+ output reg o_wr;
+ output reg [7:0] o_data;
+ output reg o_break;
+ output reg o_parity_err, o_frame_err;
+ output wire o_ck_uart;
+
+
+ wire [27:0] clocks_per_baud, break_condition, half_baud;
+ wire [1:0] data_bits;
+ wire use_parity, parity_even, dblstop, fixd_parity;
+ reg [29:0] r_setup;
+ reg [3:0] state;
+
+ assign clocks_per_baud = { 4'h0, r_setup[23:0] };
+ // assign hw_flow_control = !r_setup[30];
+ assign data_bits = r_setup[29:28];
+ assign dblstop = r_setup[27];
+ assign use_parity = r_setup[26];
+ assign fixd_parity = r_setup[25];
+ assign parity_even = r_setup[24];
+ assign break_condition = { r_setup[23:0], 4'h0 };
+ assign half_baud = { 5'h00, r_setup[23:1] }-28'h1;
+ reg [27:0] baud_counter;
+ reg zero_baud_counter;
+
+
+ // Since this is an asynchronous receiver, we need to register our
+ // input a couple of clocks over to avoid any problems with
+ // metastability. We do that here, and then ignore all but the
+ // ck_uart wire.
+ reg q_uart, qq_uart, ck_uart;
+ initial q_uart = 1'b0;
+ initial qq_uart = 1'b0;
+ initial ck_uart = 1'b0;
+ always @(posedge i_clk)
+ begin
+ q_uart <= i_uart_rx;
+ qq_uart <= q_uart;
+ ck_uart <= qq_uart;
+ end
+
+ // In case anyone else wants this clocked, stabilized value, we
+ // offer it on our output.
+ assign o_ck_uart = ck_uart;
+
+ // Keep track of the number of clocks since the last change.
+ //
+ // This is used to determine if we are in either a break or an idle
+ // condition, as discussed further below.
+ reg [27:0] chg_counter;
+ initial chg_counter = 28'h00;
+ always @(posedge i_clk)
+ if (i_reset)
+ chg_counter <= 28'h00;
+ else if (qq_uart != ck_uart)
+ chg_counter <= 28'h00;
+ else if (chg_counter < break_condition)
+ chg_counter <= chg_counter + 1;
+
+ // Are we in a break condition?
+ //
+ // A break condition exists if the line is held low for longer than
+ // a data word. Hence, we keep track of when the last change occurred.
+ // If it was more than break_condition clocks ago, and the current input
+ // value is a 0, then we're in a break--and nothing can be read until
+ // the line idles again.
+ initial o_break = 1'b0;
+ always @(posedge i_clk)
+ o_break <= ((chg_counter >= break_condition)&&(~ck_uart))? 1'b1:1'b0;
+
+ // Are we between characters?
+ //
+ // The opposite of a break condition is where the line is held high
+ // for more clocks than would be in a character. When this happens,
+ // we know we have synchronization--otherwise, we might be sampling
+ // from within a data word.
+ //
+ // This logic is used later to hold the RXUART in a reset condition
+ // until we know we are between data words. At that point, we should
+ // be able to hold on to our synchronization.
+ reg line_synch;
+ initial line_synch = 1'b0;
+ always @(posedge i_clk)
+ line_synch <= ((chg_counter >= break_condition)&&(ck_uart));
+
+ // Are we in the middle of a baud iterval? Specifically, are we
+ // in the middle of a start bit? Set this to high if so. We'll use
+ // this within our state machine to transition out of the IDLE
+ // state.
+ reg half_baud_time;
+ initial half_baud_time = 0;
+ always @(posedge i_clk)
+ half_baud_time <= (~ck_uart)&&(chg_counter >= half_baud);
+
+
+ // Allow our controlling processor to change our setup at any time
+ // outside of receiving/processing a character.
+ initial r_setup = INITIAL_SETUP[29:0];
+ always @(posedge i_clk)
+ if (state >= `RXU_RESET_IDLE)
+ r_setup <= i_setup[29:0];
+
+
+ // Our monster state machine. YIKES!
+ //
+ // Yeah, this may be more complicated than it needs to be. The basic
+ // progression is:
+ // RESET -> RESET_IDLE -> (when line is idle) -> IDLE
+ // IDLE -> bit 0 -> bit 1 -> bit_{ndatabits} ->
+ // (optional) PARITY -> STOP -> (optional) SECOND_STOP
+ // -> IDLE
+ // ANY -> (on break) BREAK -> IDLE
+ //
+ // There are 16 states, although all are not used. These are listed
+ // at the top of this file.
+ //
+ // Logic inputs (12): (I've tried to minimize this number)
+ // state (4)
+ // i_reset
+ // line_synch
+ // o_break
+ // ckuart
+ // half_baud_time
+ // zero_baud_counter
+ // use_parity
+ // dblstop
+ // Logic outputs (4):
+ // state
+ //
+ initial state = `RXU_RESET_IDLE;
+ always @(posedge i_clk)
+ begin
+ if (i_reset)
+ state <= `RXU_RESET_IDLE;
+ else if (state == `RXU_RESET_IDLE)
+ begin
+ if (line_synch)
+ // Goto idle state from a reset
+ state <= `RXU_IDLE;
+ else // Otherwise, stay in this condition 'til reset
+ state <= `RXU_RESET_IDLE;
+ end else if (o_break)
+ begin // We are in a break condition
+ state <= `RXU_BREAK;
+ end else if (state == `RXU_BREAK)
+ begin // Goto idle state following return ck_uart going high
+ if (ck_uart)
+ state <= `RXU_IDLE;
+ else
+ state <= `RXU_BREAK;
+ end else if (state == `RXU_IDLE)
+ begin // Idle state, independent of baud counter
+ if ((~ck_uart)&&(half_baud_time))
+ begin
+ // We are in the center of a valid start bit
+ case (data_bits)
+ 2'b00: state <= `RXU_BIT_ZERO;
+ 2'b01: state <= `RXU_BIT_ONE;
+ 2'b10: state <= `RXU_BIT_TWO;
+ 2'b11: state <= `RXU_BIT_THREE;
+ endcase
+ end else // Otherwise, just stay here in idle
+ state <= `RXU_IDLE;
+ end else if (zero_baud_counter)
+ begin
+ if (state < `RXU_BIT_SEVEN)
+ // Data arrives least significant bit first.
+ // By the time this is clocked in, it's what
+ // you'll have.
+ state <= state + 1;
+ else if (state == `RXU_BIT_SEVEN)
+ state <= (use_parity) ? `RXU_PARITY:`RXU_STOP;
+ else if (state == `RXU_PARITY)
+ state <= `RXU_STOP;
+ else if (state == `RXU_STOP)
+ begin // Stop (or parity) bit(s)
+ if (~ck_uart) // On frame error, wait 4 ch idle
+ state <= `RXU_RESET_IDLE;
+ else if (dblstop)
+ state <= `RXU_SECOND_STOP;
+ else
+ state <= `RXU_IDLE;
+ end else // state must equal RX_SECOND_STOP
+ begin
+ if (~ck_uart) // On frame error, wait 4 ch idle
+ state <= `RXU_RESET_IDLE;
+ else
+ state <= `RXU_IDLE;
+ end
+ end
+ end
+
+ // Data bit capture logic.
+ //
+ // This is drastically simplified from the state machine above, based
+ // upon: 1) it doesn't matter what it is until the end of a captured
+ // byte, and 2) the data register will flush itself of any invalid
+ // data in all other cases. Hence, let's keep it real simple.
+ // The only trick, though, is that if we have parity, then the data
+ // register needs to be held through that state without getting
+ // updated.
+ reg [7:0] data_reg;
+ always @(posedge i_clk)
+ if ((zero_baud_counter)&&(state != `RXU_PARITY))
+ data_reg <= { ck_uart, data_reg[7:1] };
+
+ // Parity calculation logic
+ //
+ // As with the data capture logic, all that must be known about this
+ // bit is that it is the exclusive-OR of all bits prior. The first
+ // of those will follow idle, so we set ourselves to zero on idle.
+ // Then, as we walk through the states of a bit, all will adjust this
+ // value up until the parity bit, where the value will be read. Setting
+ // it then or after will be irrelevant, so ... this should be good
+ // and simplified. Note--we don't need to adjust this on reset either,
+ // since the reset state will lead to the idle state where we'll be
+ // reset before any transmission takes place.
+ reg calc_parity;
+ always @(posedge i_clk)
+ if (state == `RXU_IDLE)
+ calc_parity <= 0;
+ else if (zero_baud_counter)
+ calc_parity <= calc_parity ^ ck_uart;
+
+ // Parity error logic
+ //
+ // Set during the parity bit interval, read during the last stop bit
+ // interval, cleared on BREAK, RESET_IDLE, or IDLE states.
+ initial o_parity_err = 1'b0;
+ always @(posedge i_clk)
+ if ((zero_baud_counter)&&(state == `RXU_PARITY))
+ begin
+ if (fixd_parity)
+ // Fixed parity bit--independent of any dat
+ // value.
+ o_parity_err <= (ck_uart ^ parity_even);
+ else if (parity_even)
+ // Parity even: The XOR of all bits including
+ // the parity bit must be zero.
+ o_parity_err <= (calc_parity != ck_uart);
+ else
+ // Parity odd: the parity bit must equal the
+ // XOR of all the data bits.
+ o_parity_err <= (calc_parity == ck_uart);
+ end else if (state >= `RXU_BREAK)
+ o_parity_err <= 1'b0;
+
+ // Frame error determination
+ //
+ // For the purpose of this controller, a frame error is defined as a
+ // stop bit (or second stop bit, if so enabled) not being high midway
+ // through the stop baud interval. The frame error value is
+ // immediately read, so we can clear it under all other circumstances.
+ // Specifically, we want it clear in RXU_BREAK, RXU_RESET_IDLE, and
+ // most importantly in RXU_IDLE.
+ initial o_frame_err = 1'b0;
+ always @(posedge i_clk)
+ if ((zero_baud_counter)&&((state == `RXU_STOP)
+ ||(state == `RXU_SECOND_STOP)))
+ o_frame_err <= (o_frame_err)||(~ck_uart);
+ else if ((zero_baud_counter)||(state >= `RXU_BREAK))
+ o_frame_err <= 1'b0;
+
+ // Our data bit logic doesn't need nearly the complexity of all that
+ // work above. Indeed, we only need to know if we are at the end of
+ // a stop bit, in which case we copy the data_reg into our output
+ // data register, o_data.
+ //
+ // We would also set o_wr to be true when this is the case, but ... we
+ // won't know if there is a frame error on the second stop bit for
+ // another baud interval yet. So, instead, we set up the logic so that
+ // we know on the next zero baud counter that we can write out. That's
+ // the purpose of pre_wr.
+ initial o_data = 8'h00;
+ reg pre_wr;
+ initial pre_wr = 1'b0;
+ always @(posedge i_clk)
+ if (i_reset)
+ begin
+ pre_wr <= 1'b0;
+ o_data <= 8'h00;
+ end else if ((zero_baud_counter)&&(state == `RXU_STOP))
+ begin
+ pre_wr <= 1'b1;
+ case (data_bits)
+ 2'b00: o_data <= data_reg;
+ 2'b01: o_data <= { 1'b0, data_reg[7:1] };
+ 2'b10: o_data <= { 2'b0, data_reg[7:2] };
+ 2'b11: o_data <= { 3'b0, data_reg[7:3] };
+ endcase
+ end else if ((zero_baud_counter)||(state == `RXU_IDLE))
+ pre_wr <= 1'b0;
+
+ // Create an output strobe, true for one clock only, once we know
+ // all we need to know. o_data will be set on the last baud interval,
+ // o_parity_err on the last parity baud interval (if it existed,
+ // cleared otherwise, so ... we should be good to go here.)
+ initial o_wr = 1'b0;
+ always @(posedge i_clk)
+ if ((zero_baud_counter)||(state == `RXU_IDLE))
+ o_wr <= (pre_wr)&&(!i_reset);
+ else
+ o_wr <= 1'b0;
+
+ // The baud counter
+ //
+ // This is used as a "clock divider" if you will, but the clock needs
+ // to be reset before any byte can be decoded. In all other respects,
+ // we set ourselves up for clocks_per_baud counts between baud
+ // intervals.
+ always @(posedge i_clk)
+ if (i_reset)
+ baud_counter <= clocks_per_baud-28'h01;
+ else if (zero_baud_counter)
+ baud_counter <= clocks_per_baud-28'h01;
+ else case(state)
+ `RXU_RESET_IDLE:baud_counter <= clocks_per_baud-28'h01;
+ `RXU_BREAK: baud_counter <= clocks_per_baud-28'h01;
+ `RXU_IDLE: baud_counter <= clocks_per_baud-28'h01;
+ default: baud_counter <= baud_counter-28'h01;
+ endcase
+
+ // zero_baud_counter
+ //
+ // Rather than testing whether or not (baud_counter == 0) within our
+ // (already too complicated) state transition tables, we use
+ // zero_baud_counter to pre-charge that test on the clock
+ // before--cleaning up some otherwise difficult timing dependencies.
+ initial zero_baud_counter = 1'b0;
+ always @(posedge i_clk)
+ if (state == `RXU_IDLE)
+ zero_baud_counter <= 1'b0;
+ else
+ zero_baud_counter <= (baud_counter == 28'h01);
+
+
+endmodule
+
+
diff --git a/rtl/uart/txuart.v b/rtl/uart/txuart.v
new file mode 100644
index 0000000..cf92ea3
--- /dev/null
+++ b/rtl/uart/txuart.v
@@ -0,0 +1,1138 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: txuart.v
+//
+// Project: wbuart32, a full featured UART with simulator
+//
+// Purpose: Transmit outputs over a single UART line.
+//
+// To interface with this module, connect it to your system clock,
+// pass it the 32 bit setup register (defined below) and the byte
+// of data you wish to transmit. Strobe the i_wr line high for one
+// clock cycle, and your data will be off. Wait until the 'o_busy'
+// line is low before strobing the i_wr line again--this implementation
+// has NO BUFFER, so strobing i_wr while the core is busy will just
+// cause your data to be lost. The output will be placed on the o_txuart
+// output line. If you wish to set/send a break condition, assert the
+// i_break line otherwise leave it low.
+//
+// There is a synchronous reset line, logic high.
+//
+// Now for the setup register. The register is 32 bits, so that this
+// UART may be set up over a 32-bit bus.
+//
+// i_setup[30] Set this to zero to use hardware flow control, and to
+// one to ignore hardware flow control. Only works if the hardware
+// flow control has been properly wired.
+//
+// If you don't want hardware flow control, fix the i_rts bit to
+// 1'b1, and let the synthesys tools optimize out the logic.
+//
+// i_setup[29:28] Indicates the number of data bits per word. This will
+// either be 2'b00 for an 8-bit word, 2'b01 for a 7-bit word, 2'b10
+// for a six bit word, or 2'b11 for a five bit word.
+//
+// i_setup[27] Indicates whether or not to use one or two stop bits.
+// Set this to one to expect two stop bits, zero for one.
+//
+// i_setup[26] Indicates whether or not a parity bit exists. Set this
+// to 1'b1 to include parity.
+//
+// i_setup[25] Indicates whether or not the parity bit is fixed. Set
+// to 1'b1 to include a fixed bit of parity, 1'b0 to allow the
+// parity to be set based upon data. (Both assume the parity
+// enable value is set.)
+//
+// i_setup[24] This bit is ignored if parity is not used. Otherwise,
+// in the case of a fixed parity bit, this bit indicates whether
+// mark (1'b1) or space (1'b0) parity is used. Likewise if the
+// parity is not fixed, a 1'b1 selects even parity, and 1'b0
+// selects odd.
+//
+// i_setup[23:0] Indicates the speed of the UART in terms of clocks.
+// So, for example, if you have a 200 MHz clock and wish to
+// run your UART at 9600 baud, you would take 200 MHz and divide
+// by 9600 to set this value to 24'd20834. Likewise if you wished
+// to run this serial port at 115200 baud from a 200 MHz clock,
+// you would set the value to 24'd1736
+//
+// Thus, to set the UART for the common setting of an 8-bit word,
+// one stop bit, no parity, and 115200 baud over a 200 MHz clock, you
+// would want to set the setup value to:
+//
+// 32'h0006c8 // For 115,200 baud, 8 bit, no parity
+// 32'h005161 // For 9600 baud, 8 bit, no parity
+//
+//
+// Creator: Dan Gisselquist, Ph.D.
+// Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015-2019, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. (It's in the $(ROOT)/doc directory. Run make with no
+// target there if the PDF file isn't present.) If not, see
+// for a copy.
+//
+// License: GPL, v3, as defined and found on www.gnu.org,
+// http://www.gnu.org/licenses/gpl.html
+//
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+`default_nettype none
+//
+//
+module txuart(i_clk, i_reset, i_setup, i_break, i_wr, i_data,
+ i_cts_n, o_uart_tx, o_busy);
+ parameter [30:0] INITIAL_SETUP = 31'd868;
+ //
+ localparam [3:0] TXU_BIT_ZERO = 4'h0;
+ localparam [3:0] TXU_BIT_ONE = 4'h1;
+ localparam [3:0] TXU_BIT_TWO = 4'h2;
+ localparam [3:0] TXU_BIT_THREE = 4'h3;
+ localparam [3:0] TXU_BIT_FOUR = 4'h4;
+ localparam [3:0] TXU_BIT_FIVE = 4'h5;
+ localparam [3:0] TXU_BIT_SIX = 4'h6;
+ localparam [3:0] TXU_BIT_SEVEN = 4'h7;
+ localparam [3:0] TXU_PARITY = 4'h8;
+ localparam [3:0] TXU_STOP = 4'h9;
+ localparam [3:0] TXU_SECOND_STOP = 4'ha;
+ //
+ localparam [3:0] TXU_BREAK = 4'he;
+ localparam [3:0] TXU_IDLE = 4'hf;
+ //
+ //
+ input wire i_clk, i_reset;
+ input wire [30:0] i_setup;
+ input wire i_break;
+ input wire i_wr;
+ input wire [7:0] i_data;
+ // Hardware flow control Ready-To-Send bit. Set this to one to use
+ // the core without flow control. (A more appropriate name would be
+ // the Ready-To-Receive bit ...)
+ input wire i_cts_n;
+ // And the UART input line itself
+ output reg o_uart_tx;
+ // A line to tell others when we are ready to accept data. If
+ // (i_wr)&&(!o_busy) is ever true, then the core has accepted a byte
+ // for transmission.
+ output wire o_busy;
+
+ wire [27:0] clocks_per_baud, break_condition;
+ wire [1:0] i_data_bits, data_bits;
+ wire use_parity, parity_odd, dblstop, fixd_parity,
+ fixdp_value, hw_flow_control, i_parity_odd;
+ reg [30:0] r_setup;
+ assign clocks_per_baud = { 4'h0, r_setup[23:0] };
+ assign break_condition = { r_setup[23:0], 4'h0 };
+ assign hw_flow_control = !r_setup[30];
+ assign i_data_bits = i_setup[29:28];
+ assign data_bits = r_setup[29:28];
+ assign dblstop = r_setup[27];
+ assign use_parity = r_setup[26];
+ assign fixd_parity = r_setup[25];
+ assign i_parity_odd = i_setup[24];
+ assign parity_odd = r_setup[24];
+ assign fixdp_value = r_setup[24];
+
+ reg [27:0] baud_counter;
+ reg [3:0] state;
+ reg [7:0] lcl_data;
+ reg calc_parity, r_busy, zero_baud_counter, last_state;
+
+
+ // First step ... handle any hardware flow control, if so enabled.
+ //
+ // Clock in the flow control data, two clocks to avoid metastability
+ // Default to using hardware flow control (uart_setup[30]==0 to use it).
+ // Set this high order bit off if you do not wish to use it.
+ reg q_cts_n, qq_cts_n, ck_cts;
+ // While we might wish to give initial values to q_rts and ck_cts,
+ // 1) it's not required since the transmitter starts in a long wait
+ // state, and 2) doing so will prevent the synthesizer from optimizing
+ // this pin in the case it is hard set to 1'b1 external to this
+ // peripheral.
+ //
+ // initial q_cts_n = 1'b1;
+ // initial qq_cts_n = 1'b1;
+ // initial ck_cts = 1'b0;
+ always @(posedge i_clk)
+ { qq_cts_n, q_cts_n } <= { q_cts_n, i_cts_n };
+ always @(posedge i_clk)
+ ck_cts <= (!qq_cts_n)||(!hw_flow_control);
+
+ initial o_uart_tx = 1'b1;
+ initial r_busy = 1'b1;
+ initial state = TXU_IDLE;
+ always @(posedge i_clk)
+ if (i_reset)
+ begin
+ r_busy <= 1'b1;
+ state <= TXU_IDLE;
+ end else if (i_break)
+ begin
+ state <= TXU_BREAK;
+ r_busy <= 1'b1;
+ end else if (!zero_baud_counter)
+ begin // r_busy needs to be set coming into here
+ r_busy <= 1'b1;
+ end else if (state == TXU_BREAK)
+ begin
+ state <= TXU_IDLE;
+ r_busy <= !ck_cts;
+ end else if (state == TXU_IDLE) // STATE_IDLE
+ begin
+ if ((i_wr)&&(!r_busy))
+ begin // Immediately start us off with a start bit
+ r_busy <= 1'b1;
+ case(i_data_bits)
+ 2'b00: state <= TXU_BIT_ZERO;
+ 2'b01: state <= TXU_BIT_ONE;
+ 2'b10: state <= TXU_BIT_TWO;
+ 2'b11: state <= TXU_BIT_THREE;
+ endcase
+ end else begin // Stay in idle
+ r_busy <= !ck_cts;
+ end
+ end else begin
+ // One clock tick in each of these states ...
+ // baud_counter <= clocks_per_baud - 28'h01;
+ r_busy <= 1'b1;
+ if (state[3] == 0) // First 8 bits
+ begin
+ if (state == TXU_BIT_SEVEN)
+ state <= (use_parity)? TXU_PARITY:TXU_STOP;
+ else
+ state <= state + 1;
+ end else if (state == TXU_PARITY)
+ begin
+ state <= TXU_STOP;
+ end else if (state == TXU_STOP)
+ begin // two stop bit(s)
+ if (dblstop)
+ state <= TXU_SECOND_STOP;
+ else
+ state <= TXU_IDLE;
+ end else // `TXU_SECOND_STOP and default:
+ begin
+ state <= TXU_IDLE; // Go back to idle
+ // Still r_busy, since we need to wait
+ // for the baud clock to finish counting
+ // out this last bit.
+ end
+ end
+
+ // o_busy
+ //
+ // This is a wire, designed to be true is we are ever busy above.
+ // originally, this was going to be true if we were ever not in the
+ // idle state. The logic has since become more complex, hence we have
+ // a register dedicated to this and just copy out that registers value.
+ assign o_busy = (r_busy);
+
+
+ // r_setup
+ //
+ // Our setup register. Accept changes between any pair of transmitted
+ // words. The register itself has many fields to it. These are
+ // broken out up top, and indicate what 1) our baud rate is, 2) our
+ // number of stop bits, 3) what type of parity we are using, and 4)
+ // the size of our data word.
+ initial r_setup = INITIAL_SETUP;
+ always @(posedge i_clk)
+ if (!o_busy)
+ r_setup <= i_setup;
+
+ // lcl_data
+ //
+ // This is our working copy of the i_data register which we use
+ // when transmitting. It is only of interest during transmit, and is
+ // allowed to be whatever at any other time. Hence, if r_busy isn't
+ // true, we can always set it. On the one clock where r_busy isn't
+ // true and i_wr is, we set it and r_busy is true thereafter.
+ // Then, on any zero_baud_counter (i.e. change between baud intervals)
+ // we simple logically shift the register right to grab the next bit.
+ initial lcl_data = 8'hff;
+ always @(posedge i_clk)
+ if (!r_busy)
+ lcl_data <= i_data;
+ else if (zero_baud_counter)
+ lcl_data <= { 1'b0, lcl_data[7:1] };
+
+ // o_uart_tx
+ //
+ // This is the final result/output desired of this core. It's all
+ // centered about o_uart_tx. This is what finally needs to follow
+ // the UART protocol.
+ //
+ // Ok, that said, our rules are:
+ // 1'b0 on any break condition
+ // 1'b0 on a start bit (IDLE, write, and not busy)
+ // lcl_data[0] during any data transfer, but only at the baud
+ // change
+ // PARITY -- During the parity bit. This depends upon whether or
+ // not the parity bit is fixed, then what it's fixed to,
+ // or changing, and hence what it's calculated value is.
+ // 1'b1 at all other times (stop bits, idle, etc)
+ always @(posedge i_clk)
+ if (i_reset)
+ o_uart_tx <= 1'b1;
+ else if ((i_break)||((i_wr)&&(!r_busy)))
+ o_uart_tx <= 1'b0;
+ else if (zero_baud_counter)
+ casez(state)
+ 4'b0???: o_uart_tx <= lcl_data[0];
+ TXU_PARITY: o_uart_tx <= calc_parity;
+ default: o_uart_tx <= 1'b1;
+ endcase
+
+
+ // calc_parity
+ //
+ // Calculate the parity to be placed into the parity bit. If the
+ // parity is fixed, then the parity bit is given by the fixed parity
+ // value (r_setup[24]). Otherwise the parity is given by the GF2
+ // sum of all the data bits (plus one for even parity).
+ initial calc_parity = 1'b0;
+ always @(posedge i_clk)
+ if (!o_busy)
+ calc_parity <= i_setup[24];
+ else if (fixd_parity)
+ calc_parity <= fixdp_value;
+ else if (zero_baud_counter)
+ begin
+ if (state[3] == 0) // First 8 bits of msg
+ calc_parity <= calc_parity ^ lcl_data[0];
+ else if (state == TXU_IDLE)
+ calc_parity <= parity_odd;
+ end else if (!r_busy)
+ calc_parity <= parity_odd;
+
+
+ // All of the above logic is driven by the baud counter. Bits must last
+ // clocks_per_baud in length, and this baud counter is what we use to
+ // make certain of that.
+ //
+ // The basic logic is this: at the beginning of a bit interval, start
+ // the baud counter and set it to count clocks_per_baud. When it gets
+ // to zero, restart it.
+ //
+ // However, comparing a 28'bit number to zero can be rather complex--
+ // especially if we wish to do anything else on that same clock. For
+ // that reason, we create "zero_baud_counter". zero_baud_counter is
+ // nothing more than a flag that is true anytime baud_counter is zero.
+ // It's true when the logic (above) needs to step to the next bit.
+ // Simple enough?
+ //
+ // I wish we could stop there, but there are some other (ugly)
+ // conditions to deal with that offer exceptions to this basic logic.
+ //
+ // 1. When the user has commanded a BREAK across the line, we need to
+ // wait several baud intervals following the break before we start
+ // transmitting, to give any receiver a chance to recognize that we are
+ // out of the break condition, and to know that the next bit will be
+ // a stop bit.
+ //
+ // 2. A reset is similar to a break condition--on both we wait several
+ // baud intervals before allowing a start bit.
+ //
+ // 3. In the idle state, we stop our counter--so that upon a request
+ // to transmit when idle we can start transmitting immediately, rather
+ // than waiting for the end of the next (fictitious and arbitrary) baud
+ // interval.
+ //
+ // When (i_wr)&&(!r_busy)&&(state == TXU_IDLE) then we're not only in
+ // the idle state, but we also just accepted a command to start writing
+ // the next word. At this point, the baud counter needs to be reset
+ // to the number of clocks per baud, and zero_baud_counter set to zero.
+ //
+ // The logic is a bit twisted here, in that it will only check for the
+ // above condition when zero_baud_counter is false--so as to make
+ // certain the STOP bit is complete.
+ initial zero_baud_counter = 1'b0;
+ initial baud_counter = 28'h05;
+ always @(posedge i_clk)
+ begin
+ zero_baud_counter <= (baud_counter == 28'h01);
+ if ((i_reset)||(i_break))
+ begin
+ // Give ourselves 16 bauds before being ready
+ baud_counter <= break_condition;
+ zero_baud_counter <= 1'b0;
+ end else if (!zero_baud_counter)
+ baud_counter <= baud_counter - 28'h01;
+ else if (state == TXU_BREAK)
+ begin
+ baud_counter <= 0;
+ zero_baud_counter <= 1'b1;
+ end else if (state == TXU_IDLE)
+ begin
+ baud_counter <= 28'h0;
+ zero_baud_counter <= 1'b1;
+ if ((i_wr)&&(!r_busy))
+ begin
+ baud_counter <= { 4'h0, i_setup[23:0]} - 28'h01;
+ zero_baud_counter <= 1'b0;
+ end
+ end else if (last_state)
+ baud_counter <= clocks_per_baud - 28'h02;
+ else
+ baud_counter <= clocks_per_baud - 28'h01;
+ end
+
+ initial last_state = 1'b0;
+ always @(posedge i_clk)
+ if (dblstop)
+ last_state <= (state == TXU_SECOND_STOP);
+ else
+ last_state <= (state == TXU_STOP);
+
+ // Verilator lint_off UNUSED
+ wire [2:0] unused;
+ assign unused = { i_parity_odd, data_bits };
+ // Verilator lint_on UNUSED
+
+`ifdef FORMAL
+ reg fsv_parity;
+ reg [30:0] fsv_setup;
+ reg [7:0] fsv_data;
+ reg f_past_valid;
+
+ initial f_past_valid = 1'b0;
+ always @(posedge i_clk)
+ f_past_valid <= 1'b1;
+
+ always @(posedge i_clk)
+ if ((i_wr)&&(!o_busy))
+ fsv_data <= i_data;
+
+ initial fsv_setup = INITIAL_SETUP;
+ always @(posedge i_clk)
+ if (!o_busy)
+ fsv_setup <= i_setup;
+
+ always @(*)
+ assert(r_setup == fsv_setup);
+
+
+ always @(posedge i_clk)
+ assert(zero_baud_counter == (baud_counter == 0));
+
+ always @(*)
+ if (!o_busy)
+ assert(zero_baud_counter);
+
+ /*
+ *
+ * Will only pass if !i_break && !i_reset, otherwise the setup can
+ * change in the middle of this operation
+ *
+ always @(posedge i_clk)
+ if ((f_past_valid)&&(!$past(i_reset))&&(!$past(i_break))
+ &&(($past(o_busy))||($past(i_wr))))
+ assert(baud_counter <= { fsv_setup[23:0], 4'h0 });
+ */
+
+ // A single baud interval
+ always @(posedge i_clk)
+ if ((f_past_valid)&&(!$past(zero_baud_counter))
+ &&(!$past(i_reset))&&(!$past(i_break)))
+ begin
+ assert($stable(o_uart_tx));
+ assert($stable(state));
+ assert($stable(lcl_data));
+ if ((state != TXU_IDLE)&&(state != TXU_BREAK))
+ assert($stable(calc_parity));
+ assert(baud_counter == $past(baud_counter)-1'b1);
+ end
+
+ //
+ // Our various sequence data declarations
+ reg [5:0] f_five_seq;
+ reg [6:0] f_six_seq;
+ reg [7:0] f_seven_seq;
+ reg [8:0] f_eight_seq;
+ reg [2:0] f_stop_seq; // parity bit, stop bit, double stop bit
+
+
+ //
+ // One byte transmitted
+ //
+ // DATA = the byte that is sent
+ // CKS = the number of clocks per bit
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Five bit data
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ initial f_five_seq = 0;
+ always @(posedge i_clk)
+ if ((i_reset)||(i_break))
+ f_five_seq = 0;
+ else if ((state == TXU_IDLE)&&(i_wr)&&(!o_busy)
+ &&(i_data_bits == 2'b11)) // five data bits
+ f_five_seq <= 1;
+ else if (zero_baud_counter)
+ f_five_seq <= f_five_seq << 1;
+
+ always @(*)
+ if (|f_five_seq)
+ begin
+ assert(fsv_setup[29:28] == data_bits);
+ assert(data_bits == 2'b11);
+ assert(baud_counter < fsv_setup[23:0]);
+
+ assert(1'b0 == |f_six_seq);
+ assert(1'b0 == |f_seven_seq);
+ assert(1'b0 == |f_eight_seq);
+ assert(r_busy);
+ assert(state > 4'h2);
+ end
+
+ always @(*)
+ case(f_five_seq)
+ 6'h00: begin assert(1); end
+ 6'h01: begin
+ assert(state == 4'h3);
+ assert(o_uart_tx == 1'b0);
+ assert(lcl_data[4:0] == fsv_data[4:0]);
+ if (!fixd_parity)
+ assert(calc_parity == parity_odd);
+ end
+ 6'h02: begin
+ assert(state == 4'h4);
+ assert(o_uart_tx == fsv_data[0]);
+ assert(lcl_data[3:0] == fsv_data[4:1]);
+ if (!fixd_parity)
+ assert(calc_parity == fsv_data[0] ^ parity_odd);
+ end
+ 6'h04: begin
+ assert(state == 4'h5);
+ assert(o_uart_tx == fsv_data[1]);
+ assert(lcl_data[2:0] == fsv_data[4:2]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[1:0]) ^ parity_odd);
+ end
+ 6'h08: begin
+ assert(state == 4'h6);
+ assert(o_uart_tx == fsv_data[2]);
+ assert(lcl_data[1:0] == fsv_data[4:3]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[2:0]) ^ parity_odd);
+ end
+ 6'h10: begin
+ assert(state == 4'h7);
+ assert(o_uart_tx == fsv_data[3]);
+ assert(lcl_data[0] == fsv_data[4]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[3:0]) ^ parity_odd);
+ end
+ 6'h20: begin
+ if (use_parity)
+ assert(state == 4'h8);
+ else
+ assert(state == 4'h9);
+ assert(o_uart_tx == fsv_data[4]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[4:0]) ^ parity_odd);
+ end
+ default: begin assert(0); end
+ endcase
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Six bit data
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ initial f_six_seq = 0;
+ always @(posedge i_clk)
+ if ((i_reset)||(i_break))
+ f_six_seq = 0;
+ else if ((state == TXU_IDLE)&&(i_wr)&&(!o_busy)
+ &&(i_data_bits == 2'b10)) // six data bits
+ f_six_seq <= 1;
+ else if (zero_baud_counter)
+ f_six_seq <= f_six_seq << 1;
+
+ always @(*)
+ if (|f_six_seq)
+ begin
+ assert(fsv_setup[29:28] == 2'b10);
+ assert(fsv_setup[29:28] == data_bits);
+ assert(baud_counter < fsv_setup[23:0]);
+
+ assert(1'b0 == |f_five_seq);
+ assert(1'b0 == |f_seven_seq);
+ assert(1'b0 == |f_eight_seq);
+ assert(r_busy);
+ assert(state > 4'h1);
+ end
+
+ always @(*)
+ case(f_six_seq)
+ 7'h00: begin assert(1); end
+ 7'h01: begin
+ assert(state == 4'h2);
+ assert(o_uart_tx == 1'b0);
+ assert(lcl_data[5:0] == fsv_data[5:0]);
+ if (!fixd_parity)
+ assert(calc_parity == parity_odd);
+ end
+ 7'h02: begin
+ assert(state == 4'h3);
+ assert(o_uart_tx == fsv_data[0]);
+ assert(lcl_data[4:0] == fsv_data[5:1]);
+ if (!fixd_parity)
+ assert(calc_parity == fsv_data[0] ^ parity_odd);
+ end
+ 7'h04: begin
+ assert(state == 4'h4);
+ assert(o_uart_tx == fsv_data[1]);
+ assert(lcl_data[3:0] == fsv_data[5:2]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[1:0]) ^ parity_odd);
+ end
+ 7'h08: begin
+ assert(state == 4'h5);
+ assert(o_uart_tx == fsv_data[2]);
+ assert(lcl_data[2:0] == fsv_data[5:3]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[2:0]) ^ parity_odd);
+ end
+ 7'h10: begin
+ assert(state == 4'h6);
+ assert(o_uart_tx == fsv_data[3]);
+ assert(lcl_data[1:0] == fsv_data[5:4]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[3:0]) ^ parity_odd);
+ end
+ 7'h20: begin
+ assert(state == 4'h7);
+ assert(lcl_data[0] == fsv_data[5]);
+ assert(o_uart_tx == fsv_data[4]);
+ if (!fixd_parity)
+ assert(calc_parity == ((^fsv_data[4:0]) ^ parity_odd));
+ end
+ 7'h40: begin
+ if (use_parity)
+ assert(state == 4'h8);
+ else
+ assert(state == 4'h9);
+ assert(o_uart_tx == fsv_data[5]);
+ if (!fixd_parity)
+ assert(calc_parity == ((^fsv_data[5:0]) ^ parity_odd));
+ end
+ default: begin if (f_past_valid) assert(0); end
+ endcase
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Seven bit data
+ //
+ ////////////////////////////////////////////////////////////////////////
+ initial f_seven_seq = 0;
+ always @(posedge i_clk)
+ if ((i_reset)||(i_break))
+ f_seven_seq = 0;
+ else if ((state == TXU_IDLE)&&(i_wr)&&(!o_busy)
+ &&(i_data_bits == 2'b01)) // seven data bits
+ f_seven_seq <= 1;
+ else if (zero_baud_counter)
+ f_seven_seq <= f_seven_seq << 1;
+
+ always @(*)
+ if (|f_seven_seq)
+ begin
+ assert(fsv_setup[29:28] == 2'b01);
+ assert(fsv_setup[29:28] == data_bits);
+ assert(baud_counter < fsv_setup[23:0]);
+
+ assert(1'b0 == |f_five_seq);
+ assert(1'b0 == |f_six_seq);
+ assert(1'b0 == |f_eight_seq);
+ assert(r_busy);
+ assert(state != 4'h0);
+ end
+
+ always @(*)
+ case(f_seven_seq)
+ 8'h00: begin assert(1); end
+ 8'h01: begin
+ assert(state == 4'h1);
+ assert(o_uart_tx == 1'b0);
+ assert(lcl_data[6:0] == fsv_data[6:0]);
+ if (!fixd_parity)
+ assert(calc_parity == parity_odd);
+ end
+ 8'h02: begin
+ assert(state == 4'h2);
+ assert(o_uart_tx == fsv_data[0]);
+ assert(lcl_data[5:0] == fsv_data[6:1]);
+ if (!fixd_parity)
+ assert(calc_parity == fsv_data[0] ^ parity_odd);
+ end
+ 8'h04: begin
+ assert(state == 4'h3);
+ assert(o_uart_tx == fsv_data[1]);
+ assert(lcl_data[4:0] == fsv_data[6:2]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[1:0]) ^ parity_odd);
+ end
+ 8'h08: begin
+ assert(state == 4'h4);
+ assert(o_uart_tx == fsv_data[2]);
+ assert(lcl_data[3:0] == fsv_data[6:3]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[2:0]) ^ parity_odd);
+ end
+ 8'h10: begin
+ assert(state == 4'h5);
+ assert(o_uart_tx == fsv_data[3]);
+ assert(lcl_data[2:0] == fsv_data[6:4]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[3:0]) ^ parity_odd);
+ end
+ 8'h20: begin
+ assert(state == 4'h6);
+ assert(o_uart_tx == fsv_data[4]);
+ assert(lcl_data[1:0] == fsv_data[6:5]);
+ if (!fixd_parity)
+ assert(calc_parity == ((^fsv_data[4:0]) ^ parity_odd));
+ end
+ 8'h40: begin
+ assert(state == 4'h7);
+ assert(lcl_data[0] == fsv_data[6]);
+ assert(o_uart_tx == fsv_data[5]);
+ if (!fixd_parity)
+ assert(calc_parity == ((^fsv_data[5:0]) ^ parity_odd));
+ end
+ 8'h80: begin
+ if (use_parity)
+ assert(state == 4'h8);
+ else
+ assert(state == 4'h9);
+ assert(o_uart_tx == fsv_data[6]);
+ if (!fixd_parity)
+ assert(calc_parity == ((^fsv_data[6:0]) ^ parity_odd));
+ end
+ default: begin if (f_past_valid) assert(0); end
+ endcase
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Eight bit data
+ //
+ ////////////////////////////////////////////////////////////////////////
+ initial f_eight_seq = 0;
+ always @(posedge i_clk)
+ if ((i_reset)||(i_break))
+ f_eight_seq = 0;
+ else if ((state == TXU_IDLE)&&(i_wr)&&(!o_busy)
+ &&(i_data_bits == 2'b00)) // Eight data bits
+ f_eight_seq <= 1;
+ else if (zero_baud_counter)
+ f_eight_seq <= f_eight_seq << 1;
+
+ always @(*)
+ if (|f_eight_seq)
+ begin
+ assert(fsv_setup[29:28] == 2'b00);
+ assert(fsv_setup[29:28] == data_bits);
+ assert(baud_counter < { 6'h0, fsv_setup[23:0]});
+
+ assert(1'b0 == |f_five_seq);
+ assert(1'b0 == |f_six_seq);
+ assert(1'b0 == |f_seven_seq);
+ assert(r_busy);
+ end
+
+ always @(*)
+ case(f_eight_seq)
+ 9'h000: begin assert(1); end
+ 9'h001: begin
+ assert(state == 4'h0);
+ assert(o_uart_tx == 1'b0);
+ assert(lcl_data[7:0] == fsv_data[7:0]);
+ if (!fixd_parity)
+ assert(calc_parity == parity_odd);
+ end
+ 9'h002: begin
+ assert(state == 4'h1);
+ assert(o_uart_tx == fsv_data[0]);
+ assert(lcl_data[6:0] == fsv_data[7:1]);
+ if (!fixd_parity)
+ assert(calc_parity == fsv_data[0] ^ parity_odd);
+ end
+ 9'h004: begin
+ assert(state == 4'h2);
+ assert(o_uart_tx == fsv_data[1]);
+ assert(lcl_data[5:0] == fsv_data[7:2]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[1:0]) ^ parity_odd);
+ end
+ 9'h008: begin
+ assert(state == 4'h3);
+ assert(o_uart_tx == fsv_data[2]);
+ assert(lcl_data[4:0] == fsv_data[7:3]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[2:0]) ^ parity_odd);
+ end
+ 9'h010: begin
+ assert(state == 4'h4);
+ assert(o_uart_tx == fsv_data[3]);
+ assert(lcl_data[3:0] == fsv_data[7:4]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[3:0]) ^ parity_odd);
+ end
+ 9'h020: begin
+ assert(state == 4'h5);
+ assert(o_uart_tx == fsv_data[4]);
+ assert(lcl_data[2:0] == fsv_data[7:5]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[4:0]) ^ parity_odd);
+ end
+ 9'h040: begin
+ assert(state == 4'h6);
+ assert(o_uart_tx == fsv_data[5]);
+ assert(lcl_data[1:0] == fsv_data[7:6]);
+ if (!fixd_parity)
+ assert(calc_parity == (^fsv_data[5:0]) ^ parity_odd);
+ end
+ 9'h080: begin
+ assert(state == 4'h7);
+ assert(o_uart_tx == fsv_data[6]);
+ assert(lcl_data[0] == fsv_data[7]);
+ if (!fixd_parity)
+ assert(calc_parity == ((^fsv_data[6:0]) ^ parity_odd));
+ end
+ 9'h100: begin
+ if (use_parity)
+ assert(state == 4'h8);
+ else
+ assert(state == 4'h9);
+ assert(o_uart_tx == fsv_data[7]);
+ if (!fixd_parity)
+ assert(calc_parity == ((^fsv_data[7:0]) ^ parity_odd));
+ end
+ default: begin if (f_past_valid) assert(0); end
+ endcase
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Combined properties for all of the data sequences
+ //
+ ////////////////////////////////////////////////////////////////////////
+ always @(posedge i_clk)
+ if (((|f_five_seq[5:0]) || (|f_six_seq[6:0]) || (|f_seven_seq[7:0])
+ || (|f_eight_seq[8:0]))
+ && ($past(zero_baud_counter)))
+ assert(baud_counter == { 4'h0, fsv_setup[23:0] }-1);
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The stop sequence
+ //
+ // This consists of any parity bit, as well as one or two stop bits
+ ////////////////////////////////////////////////////////////////////////
+ initial f_stop_seq = 1'b0;
+ always @(posedge i_clk)
+ if ((i_reset)||(i_break))
+ f_stop_seq <= 0;
+ else if (zero_baud_counter)
+ begin
+ f_stop_seq <= 0;
+ if (f_stop_seq[0]) // Coming from a parity bit
+ begin
+ if (dblstop)
+ f_stop_seq[1] <= 1'b1;
+ else
+ f_stop_seq[2] <= 1'b1;
+ end
+
+ if (f_stop_seq[1])
+ f_stop_seq[2] <= 1'b1;
+
+ if (f_eight_seq[8] | f_seven_seq[7] | f_six_seq[6]
+ | f_five_seq[5])
+ begin
+ if (use_parity)
+ f_stop_seq[0] <= 1'b1;
+ else if (dblstop)
+ f_stop_seq[1] <= 1'b1;
+ else
+ f_stop_seq[2] <= 1'b1;
+ end
+ end
+
+ always @(*)
+ if (|f_stop_seq)
+ begin
+ assert(1'b0 == |f_five_seq[4:0]);
+ assert(1'b0 == |f_six_seq[5:0]);
+ assert(1'b0 == |f_seven_seq[6:0]);
+ assert(1'b0 == |f_eight_seq[7:0]);
+
+ assert(r_busy);
+ end
+
+ always @(*)
+ if (f_stop_seq[0])
+ begin
+ // 9 if dblstop and use_parity
+ if (dblstop)
+ assert(state == TXU_STOP);
+ else
+ assert(state == TXU_STOP);
+ assert(use_parity);
+ assert(o_uart_tx == fsv_parity);
+ end
+
+ always @(*)
+ if (f_stop_seq[1])
+ begin
+ // if (!use_parity)
+ assert(state == TXU_SECOND_STOP);
+ assert(dblstop);
+ assert(o_uart_tx);
+ end
+
+ always @(*)
+ if (f_stop_seq[2])
+ begin
+ assert(state == 4'hf);
+ assert(o_uart_tx);
+ assert(baud_counter < fsv_setup[23:0]-1'b1);
+ end
+
+
+ always @(*)
+ if (fsv_setup[25])
+ fsv_parity <= fsv_setup[24];
+ else
+ case(fsv_setup[29:28])
+ 2'b00: fsv_parity = (^fsv_data[7:0]) ^ fsv_setup[24];
+ 2'b01: fsv_parity = (^fsv_data[6:0]) ^ fsv_setup[24];
+ 2'b10: fsv_parity = (^fsv_data[5:0]) ^ fsv_setup[24];
+ 2'b11: fsv_parity = (^fsv_data[4:0]) ^ fsv_setup[24];
+ endcase
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // The break sequence
+ //
+ //////////////////////////////////////////////////////////////////////
+ reg [1:0] f_break_seq;
+ initial f_break_seq = 2'b00;
+ always @(posedge i_clk)
+ if (i_reset)
+ f_break_seq <= 2'b00;
+ else if (i_break)
+ f_break_seq <= 2'b01;
+ else if (!zero_baud_counter)
+ f_break_seq <= { |f_break_seq, 1'b0 };
+ else
+ f_break_seq <= 0;
+
+ always @(posedge i_clk)
+ if (f_break_seq[0])
+ assert(baud_counter == { $past(fsv_setup[23:0]), 4'h0 });
+ always @(posedge i_clk)
+ if ((f_past_valid)&&($past(f_break_seq[1]))&&(state != TXU_BREAK))
+ begin
+ assert(state == TXU_IDLE);
+ assert(o_uart_tx == 1'b1);
+ end
+
+ always @(*)
+ if (|f_break_seq)
+ begin
+ assert(state == TXU_BREAK);
+ assert(r_busy);
+ assert(o_uart_tx == 1'b0);
+ end
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Properties for use during induction if we are made a submodule of
+ // the rxuart
+ //
+ //////////////////////////////////////////////////////////////////////
+
+ // Need enough bits for reset (24+4) plus enough bits for all of the
+ // various characters, 24+4, so 24+5 is a minimum of this counter
+ //
+`ifndef TXUART
+ reg [28:0] f_counter;
+ initial f_counter = 0;
+ always @(posedge i_clk)
+ if (!o_busy)
+ f_counter <= 1'b0;
+ else
+ f_counter <= f_counter + 1'b1;
+
+ always @(*)
+ if (f_five_seq[0]|f_six_seq[0]|f_seven_seq[0]|f_eight_seq[0])
+ assert(f_counter == (fsv_setup[23:0] - baud_counter - 1));
+ else if (f_five_seq[1]|f_six_seq[1]|f_seven_seq[1]|f_eight_seq[1])
+ assert(f_counter == ({4'h0, fsv_setup[23:0], 1'b0} - baud_counter - 1));
+ else if (f_five_seq[2]|f_six_seq[2]|f_seven_seq[2]|f_eight_seq[2])
+ assert(f_counter == ({4'h0, fsv_setup[23:0], 1'b0}
+ +{5'h0, fsv_setup[23:0]}
+ - baud_counter - 1));
+ else if (f_five_seq[3]|f_six_seq[3]|f_seven_seq[3]|f_eight_seq[3])
+ assert(f_counter == ({3'h0, fsv_setup[23:0], 2'b0}
+ - baud_counter - 1));
+ else if (f_five_seq[4]|f_six_seq[4]|f_seven_seq[4]|f_eight_seq[4])
+ assert(f_counter == ({3'h0, fsv_setup[23:0], 2'b0}
+ +{5'h0, fsv_setup[23:0]}
+ - baud_counter - 1));
+ else if (f_five_seq[5]|f_six_seq[5]|f_seven_seq[5]|f_eight_seq[5])
+ assert(f_counter == ({3'h0, fsv_setup[23:0], 2'b0}
+ +{4'h0, fsv_setup[23:0], 1'b0}
+ - baud_counter - 1));
+ else if (f_six_seq[6]|f_seven_seq[6]|f_eight_seq[6])
+ assert(f_counter == ({3'h0, fsv_setup[23:0], 2'b0}
+ +{5'h0, fsv_setup[23:0]}
+ +{4'h0, fsv_setup[23:0], 1'b0}
+ - baud_counter - 1));
+ else if (f_seven_seq[7]|f_eight_seq[7])
+ assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0} // 8
+ - baud_counter - 1));
+ else if (f_eight_seq[8])
+ assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0} // 9
+ +{5'h0, fsv_setup[23:0]}
+ - baud_counter - 1));
+ else if (f_stop_seq[0] || (!use_parity && f_stop_seq[1]))
+ begin
+ // Parity bit, or first of two stop bits
+ case(data_bits)
+ 2'b00: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{4'h0, fsv_setup[23:0], 1'b0} // 10
+ - baud_counter - 1));
+ 2'b01: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{5'h0, fsv_setup[23:0]} // 9
+ - baud_counter - 1));
+ 2'b10: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ - baud_counter - 1)); // 8
+ 2'b11: assert(f_counter == ({3'h0, fsv_setup[23:0], 2'b0}
+ +{5'h0, fsv_setup[23:0]} // 7
+ +{4'h0, fsv_setup[23:0], 1'b0}
+ - baud_counter - 1));
+ endcase
+ end else if (!use_parity && !dblstop && f_stop_seq[2])
+ begin
+ // No parity, single stop bit
+ // Different from the one above, since the last counter is has
+ // one fewer items within it
+ case(data_bits)
+ 2'b00: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{4'h0, fsv_setup[23:0], 1'b0} // 10
+ - baud_counter - 2));
+ 2'b01: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{5'h0, fsv_setup[23:0]} // 9
+ - baud_counter - 2));
+ 2'b10: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ - baud_counter - 2)); // 8
+ 2'b11: assert(f_counter == ({3'h0, fsv_setup[23:0], 2'b0}
+ +{5'h0, fsv_setup[23:0]} // 7
+ +{4'h0, fsv_setup[23:0], 1'b0}
+ - baud_counter - 2));
+ endcase
+ end else if (f_stop_seq[1])
+ begin
+ // Parity and the first of two stop bits
+ assert(dblstop && use_parity);
+ case(data_bits)
+ 2'b00: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{5'h0, fsv_setup[23:0]} // 11
+ +{4'h0, fsv_setup[23:0], 1'b0}
+ - baud_counter - 1));
+ 2'b01: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{4'h0, fsv_setup[23:0], 1'b0} // 10
+ - baud_counter - 1));
+ 2'b10: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{5'h0, fsv_setup[23:0]} // 9
+ - baud_counter - 1));
+ 2'b11: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ - baud_counter - 1)); // 8
+ endcase
+ end else if ((dblstop ^ use_parity) && f_stop_seq[2])
+ begin
+ // Parity and one stop bit
+ // assert(!dblstop && use_parity);
+ case(data_bits)
+ 2'b00: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{5'h0, fsv_setup[23:0]} // 11
+ +{4'h0, fsv_setup[23:0], 1'b0}
+ - baud_counter - 2));
+ 2'b01: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{4'h0, fsv_setup[23:0], 1'b0} // 10
+ - baud_counter - 2));
+ 2'b10: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{5'h0, fsv_setup[23:0]} // 9
+ - baud_counter - 2));
+ 2'b11: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ - baud_counter - 2)); // 8
+ endcase
+ end else if (f_stop_seq[2])
+ begin
+ assert(dblstop);
+ assert(use_parity);
+ // Parity and two stop bits
+ case(data_bits)
+ 2'b00: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{3'h0, fsv_setup[23:0], 2'b00} // 12
+ - baud_counter - 2));
+ 2'b01: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{5'h0, fsv_setup[23:0]} // 11
+ +{4'h0, fsv_setup[23:0], 1'b0}
+ - baud_counter - 2));
+ 2'b10: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{4'h0, fsv_setup[23:0], 1'b0} // 10
+ - baud_counter - 2));
+ 2'b11: assert(f_counter == ({2'h0, fsv_setup[23:0], 3'b0}
+ +{5'h0, fsv_setup[23:0]} // 9
+ - baud_counter - 2));
+ endcase
+ end
+`endif
+
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Other properties, not necessarily associated with any sequences
+ //
+ //////////////////////////////////////////////////////////////////////
+ always @(*)
+ assert((state < 4'hb)||(state >= 4'he));
+ //////////////////////////////////////////////////////////////////////
+ //
+ // Careless/limiting assumption section
+ //
+ //////////////////////////////////////////////////////////////////////
+ always @(*)
+ assume(i_setup[23:0] > 2);
+ always @(*)
+ assert(fsv_setup[23:0] > 2);
+
+`endif // FORMAL
+endmodule
+