131 lines
2.6 KiB
Verilog
131 lines
2.6 KiB
Verilog
// synthesis attribute slice_utilization_ratio of RS232 is 7;
|
|
module RS232 (CLK_I, RST_I, DAT_I, DAT_O, STB_I, WE_I, SEL_I, ACK_O,
|
|
TX_EMPTY, TX_FULL, RX_EMPTY, RX_FULL, RX, TX);
|
|
|
|
//parameter CLOCK_DIV = 5207; // 9600 bps @ 50 MHz CLK_I
|
|
parameter CLOCK_DIV = 434; // 115200 bps @ 50 MHz CLK_I
|
|
|
|
input CLK_I;
|
|
input RST_I;
|
|
input [31:0] DAT_I;
|
|
output [31:0] DAT_O;
|
|
input STB_I;
|
|
input WE_I;
|
|
input [3:0] SEL_I;
|
|
output ACK_O;
|
|
output TX_EMPTY, TX_FULL;
|
|
output RX_EMPTY, RX_FULL;
|
|
input RX;
|
|
output TX;
|
|
|
|
reg TX = 1'b1;
|
|
|
|
`define IDLE 4'd0
|
|
`define START 4'd1
|
|
`define BIT0 4'd2
|
|
`define BIT1 4'd3
|
|
`define BIT2 4'd4
|
|
`define BIT3 4'd5
|
|
`define BIT4 4'd6
|
|
`define BIT5 4'd7
|
|
`define BIT6 4'd8
|
|
`define BIT7 4'd9
|
|
`define STOP 4'd10
|
|
|
|
reg [17:0] TX_COUNTER;
|
|
reg [9:0] TX_BUFFER;
|
|
reg [3:0] TX_STATE = `IDLE;
|
|
|
|
reg [18:0] RX_COUNTER;
|
|
reg [6:0] RX_BUFFER;
|
|
reg [3:0] RX_STATE = `IDLE;
|
|
|
|
wire [7:0] TX_DATA;
|
|
wire [7:0] RX_DATA;
|
|
|
|
FIFO #(
|
|
.QUEUE_SIZE(4), // 16 characters
|
|
.DATA_WIDTH(8)
|
|
) TransmitFIFO (
|
|
.CLK_I(CLK_I),
|
|
.RST_I(RST_I),
|
|
.DAT_I(DAT_I[7:0]),
|
|
.DAT_O(TX_DATA),
|
|
.QUEUE_I(ACK_O & WE_I & SEL_I[0]),
|
|
.DEQUEUE_I(TX_STATE == `IDLE),
|
|
.FULL_O(TX_FULL),
|
|
.EMPTY_O(TX_EMPTY)
|
|
);
|
|
|
|
FIFO #(
|
|
.QUEUE_SIZE(4), // 16 characters
|
|
.DATA_WIDTH(8)
|
|
) ReceiveFIFO (
|
|
.CLK_I(CLK_I),
|
|
.RST_I(RST_I),
|
|
.DAT_I({ RX, RX_BUFFER }),
|
|
.DAT_O(RX_DATA),
|
|
.QUEUE_I((RX_STATE == `BIT7) & (RX_COUNTER == 0)),
|
|
.DEQUEUE_I(ACK_O & ~WE_I & SEL_I[0]),
|
|
.FULL_O(RX_FULL),
|
|
.EMPTY_O(RX_EMPTY)
|
|
);
|
|
|
|
assign DAT_O = { 22'h000000, TX_FULL, ~RX_EMPTY, RX_DATA };
|
|
assign ACK_O = STB_I;
|
|
|
|
always @(posedge CLK_I)
|
|
begin
|
|
if (TX_STATE == `IDLE)
|
|
begin
|
|
TX <= 1'b1;
|
|
TX_COUNTER <= (CLOCK_DIV - 1);
|
|
|
|
if (~TX_EMPTY)
|
|
begin
|
|
TX_BUFFER <= { 1'b1, 1'b1, TX_DATA, 1'b0 };
|
|
TX_STATE <= `START;
|
|
end
|
|
end
|
|
else if (~|TX_COUNTER)
|
|
begin
|
|
TX <= TX_BUFFER[0];
|
|
TX_BUFFER <= TX_BUFFER >> 1;
|
|
TX_COUNTER <= (CLOCK_DIV - 1);
|
|
|
|
if (TX_STATE == `STOP)
|
|
TX_STATE <= `IDLE;
|
|
else
|
|
TX_STATE <= TX_STATE + 1;
|
|
end
|
|
else
|
|
TX_COUNTER <= TX_COUNTER - 1;
|
|
end
|
|
|
|
always @(posedge CLK_I)
|
|
begin
|
|
if ((RX_STATE == `IDLE) | RST_I)
|
|
begin
|
|
RX_COUNTER <= (CLOCK_DIV / 2);
|
|
|
|
if (RX == 1'b0)
|
|
RX_STATE <= `START;
|
|
else
|
|
RX_STATE <= `IDLE;
|
|
end
|
|
else if (RX_COUNTER == 0)
|
|
begin
|
|
RX_BUFFER <= { RX, RX_BUFFER[6:1] };
|
|
RX_COUNTER <= (CLOCK_DIV - 1);
|
|
|
|
if (RX_STATE == `STOP)
|
|
RX_STATE <= `IDLE;
|
|
else
|
|
RX_STATE <= RX_STATE + 1;
|
|
end
|
|
else
|
|
RX_COUNTER <= RX_COUNTER - 1;
|
|
end
|
|
|
|
endmodule
|