USTC-RVSoC/RTL/isp_uart.sv
2019-02-05 16:19:46 +08:00

243 lines
8.8 KiB
Systemverilog
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 一个能作为naive bus 主设备的调试模块
// 它接收用户从UART发来的命令操控复位等信号或对总线进行读写。用户可以使用UART命令复位整个SoC上传程序或者查看运行时的RAM数据。
// 命令列表(全部命令为ASCII人类可读, 每个命令使用\r或\n或\r\n或\n\r结尾):
// 1、复位命令
// 发送: r\n
// 效果: 将o_rst_n信号拉低若干个时钟周期
// 返回: rst done\n
// 2. w\n : o_run = 1 , return running \n
// 3. s\n : o_run = 0 , return stoped \n
// 4. addr=data\n : write [addr] = data , example: 00000100 928cd0f1\n , return : 00000100=928cd0f1 , note:automaticly align address to 4byte
// 5. addr\n : read [addr] , example: 00000100\n return : 928cd0f1
//
module isp_uart #(
parameter UART_RX_CLK_DIV = 108, // 50MHz/4/115200Hz=108
parameter UART_TX_CLK_DIV = 434 // 50MHz/1/115200Hz=434
)(
input logic clk,
input logic i_uart_rx,
output logic o_uart_tx,
output logic o_rst_n, o_stop,
naive_bus.master bus
);
logic [ 5:0] rst_chain = 3'b0;
logic rx_ready, rd_ok=1'b0, wr_ok=1'b0, tx_start=1'b0;
logic [ 7:0] rx_data, rx_binary;
logic [ 3:0] rx_binary_l;
logic [31:0] addr=0, wr_data=0;
logic [ 7:0][ 7:0] rd_data_ascii;
logic [ 7:0][ 7:0] tx_data = 64'h0;
enum {NONE, RST, RUN, STOP} cmd=NONE;
enum {NEW, CMD, ADDR, EQUAL, DATA, FINAL, TRASH} fsm = NEW;
`define C (rx_data=="r" || rx_data=="w" || rx_data=="s")
`define S (rx_data==" " || rx_data=="\t" )
`define E (rx_data=="\n" || rx_data=="\r" )
`define N ( (rx_data>="0" && rx_data<="9" ) || (rx_data>="a" && rx_data<="f" ) )
initial o_stop = 1'b0;
assign o_rst_n = ~(|rst_chain);
initial begin bus.rd_req = 1'b0; bus.wr_req = 1'b0; bus.rd_addr = 0; bus.wr_addr = 0; bus.wr_data = 0; end
assign bus.rd_be = 4'hf;
assign bus.wr_be = 4'hf;
assign rx_binary_l = rx_binary[3:0];
always_comb
if(rx_data>="0" && rx_data<="9" ) begin
rx_binary = rx_data - "0";
end else if(rx_data>="a" && rx_data<="f" ) begin
rx_binary = rx_data - "a" + 8'd10;
end else begin
rx_binary = 8'h0;
end
uart_rx #(
.UART_RX_CLK_DIV (UART_RX_CLK_DIV)
) uart_rx_inst (
.clk ( clk ),
.i_rx ( i_uart_rx ),
.o_ready ( rx_ready ),
.o_data ( rx_data )
);
uart_tx_line #(
.UART_TX_CLK_DIV (UART_TX_CLK_DIV)
) uart_tx_line_inst (
.clk ( clk ),
.o_tx ( o_uart_tx ),
.i_start ( tx_start ),
.i_data ( tx_data )
);
generate
genvar i;
for(i=0; i<8; i++) begin : convert_binary_to_ascii
always_comb
if(bus.rd_data[3+4*i:4*i]>4'h9)
rd_data_ascii[i] = "a" - 8'd10 + bus.rd_data[3+4*i:4*i];
else
rd_data_ascii[i] = "0" + bus.rd_data[3+4*i:4*i];
end
endgenerate
always @ (posedge clk)
rd_ok <= (bus.rd_req & bus.rd_gnt);
always @ (posedge clk)
wr_ok <= (bus.wr_req & bus.wr_gnt);
always @ (posedge clk)
if (rd_ok) begin
tx_start<= 1'b1;
tx_data <= rd_data_ascii;
end else if(wr_ok) begin
tx_start<= 1'b1;
tx_data <= "wr done ";
end else if(rx_ready && fsm==CMD && `E) begin
tx_start<= 1'b1;
if(cmd==RST)
tx_data <= "rst done";
else if(cmd==RUN)
tx_data <= "running ";
else if(cmd==STOP)
tx_data <= "stoped ";
else
tx_data <= 64'h0;
end else begin
tx_start<= 1'b0;
tx_data <= 64'h0;
end
always @ (posedge clk)
if(rx_ready && fsm==CMD && `E && cmd==RST)
rst_chain <= 6'h0;
else
rst_chain <= {rst_chain[4:0],1'b0};
always @ (posedge clk)
if(rx_ready && fsm==CMD && `E) begin
if(cmd==RUN)
o_stop <= 1'b0;
else
o_stop <= 1'b1;
end
always @ (posedge clk)
if (bus.rd_req) begin
if(bus.rd_gnt)
bus.rd_req <= 1'b0;
end else if(bus.wr_req) begin
if(bus.wr_gnt)
bus.wr_req <= 1'b0;
end else if( rx_ready ) begin
case(fsm)
NEW : if (`C) begin
fsm <= CMD;
if(rx_data=="r") begin // check rx_data to see which command it is
cmd <= RST;
end else if(rx_data=="w") begin
cmd <= RUN;
end else if(rx_data=="s") begin
cmd <= STOP;
end else begin
cmd <= NONE;
end
end else if(`S || `E) begin
fsm <= NEW;
addr <= 0;
wr_data <= 0;
cmd <= NONE;
end else if(`N) begin
fsm <= ADDR;
addr <= {addr[27:0], rx_binary_l}; // get a addr
end else begin
fsm <= TRASH;
end
CMD : if (`E) begin
fsm <= NEW; // cmd ok!
addr <= 0;
wr_data <= 0;
cmd <= NONE;
end else if(`S) begin
fsm <= CMD;
end else begin
fsm <= TRASH;
end
ADDR : if (`E) begin
fsm <= NEW; // get a read command
bus.rd_req <= 1'b1; // TODO : launch a bus read
bus.rd_addr <= addr;
addr <= 0;
wr_data <= 0;
cmd <= NONE;
end else if(`N) begin
fsm <= ADDR;
addr <= {addr[27:0], rx_binary_l}; // get a addr
end else if(`S) begin
fsm <= EQUAL; // get addr down, waiting for data, maybe a write command
end else begin
fsm <= TRASH;
end
EQUAL : if (`E) begin
fsm <= NEW; // get a read command
bus.rd_req <= 1'b1; // TODO : launch a bus read
bus.rd_addr <= addr;
addr <= 0;
wr_data <= 0;
cmd <= NONE;
end else if(`N) begin
fsm <= DATA; // get a data
wr_data <= {wr_data[27:0], rx_binary_l}; // get a data
end else if(`S) begin
fsm <= EQUAL;
end else begin
fsm <= TRASH;
end
DATA : if (`E) begin
fsm <= NEW; // get a write command
bus.wr_req <= 1'b1; // TODO : launch a bus write
bus.wr_addr <= addr;
bus.wr_data <= wr_data;
addr <= 0;
wr_data <= 0;
cmd <= NONE;
end else if(`N) begin
fsm <= DATA; // get a data
wr_data <= {wr_data[27:0], rx_binary_l}; // get a data
end else if(`S) begin
fsm <= FINAL; // get data down, waiting for \r or \n
end else begin
fsm <= TRASH;
end
FINAL : if (`E) begin
fsm <= NEW; // get a write command
bus.wr_req <= 1'b1; // TODO : launch a bus write
bus.wr_addr <= addr;
bus.wr_data <= wr_data;
addr <= 0;
wr_data <= 0;
cmd <= NONE;
end else if(`S) begin
fsm <= FINAL; // get addr down, waiting for \r or \n
end else begin
fsm <= TRASH;
end
default : if (`E) begin
// get a syntax error
fsm <= NEW;
addr <= 0;
wr_data <= 0;
cmd <= NONE;
end else begin
fsm <= TRASH;
end
endcase
end
endmodule