stack-machine/rs232.v

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