URL
https://opencores.org/ocsvn/uart2bus_testbench/uart2bus_testbench/trunk
Subversion Repositories uart2bus_testbench
[/] [uart2bus_testbench/] [trunk/] [rtl/] [uart_parser.v] - Rev 2
Compare with Previous | Blame | View Log
//--------------------------------------------------------------------------------------- // uart parser module // //--------------------------------------------------------------------------------------- module uart_parser ( // global signals clock, reset, // transmit and receive internal interface signals from uart interface rx_data, new_rx_data, tx_data, new_tx_data, tx_busy, // internal bus to register file int_address, int_wr_data, int_write, int_rd_data, int_read, int_req, int_gnt ); //--------------------------------------------------------------------------------------- // parameters parameter AW = 8; // address bus width parameter // modules inputs and outputs input clock; // global clock input input reset; // global reset input output [7:0] tx_data; // data byte to transmit output new_tx_data; // asserted to indicate that there is a new data byte for // transmission input tx_busy; // signs that transmitter is busy input [7:0] rx_data; // data byte received input new_rx_data; // signs that a new byte was received output [AW-1:0] int_address; // address bus to register file output [7:0] int_wr_data; // write data to register file output int_write; // write control to register file output int_read; // read control to register file input [7:0] int_rd_data; // data read from register file output int_req; // bus access request signal input int_gnt; // bus access grant signal // registered outputs reg [7:0] tx_data; reg new_tx_data; reg [AW-1:0] int_address; reg [7:0] int_wr_data; reg write_req, read_req, int_write, int_read; // internal constants // define characters used by the parser `define CHAR_CR 8'h0d `define CHAR_LF 8'h0a `define CHAR_SPACE 8'h20 `define CHAR_TAB 8'h09 `define CHAR_COMMA 8'h2C `define CHAR_R_UP 8'h52 `define CHAR_r_LO 8'h72 `define CHAR_W_UP 8'h57 `define CHAR_w_LO 8'h77 `define CHAR_0 8'h30 `define CHAR_1 8'h31 `define CHAR_2 8'h32 `define CHAR_3 8'h33 `define CHAR_4 8'h34 `define CHAR_5 8'h35 `define CHAR_6 8'h36 `define CHAR_7 8'h37 `define CHAR_8 8'h38 `define CHAR_9 8'h39 `define CHAR_A_UP 8'h41 `define CHAR_B_UP 8'h42 `define CHAR_C_UP 8'h43 `define CHAR_D_UP 8'h44 `define CHAR_E_UP 8'h45 `define CHAR_F_UP 8'h46 `define CHAR_a_LO 8'h61 `define CHAR_b_LO 8'h62 `define CHAR_c_LO 8'h63 `define CHAR_d_LO 8'h64 `define CHAR_e_LO 8'h65 `define CHAR_f_LO 8'h66 // main (receive) state machine states `define MAIN_IDLE 4'b0000 `define MAIN_WHITE1 4'b0001 `define MAIN_DATA 4'b0010 `define MAIN_WHITE2 4'b0011 `define MAIN_ADDR 4'b0100 `define MAIN_EOL 4'b0101 // binary mode extension states `define MAIN_BIN_CMD 4'b1000 `define MAIN_BIN_ADRH 4'b1001 `define MAIN_BIN_ADRL 4'b1010 `define MAIN_BIN_LEN 4'b1011 `define MAIN_BIN_DATA 4'b1100 // transmit state machine `define TX_IDLE 3'b000 `define TX_HI_NIB 3'b001 `define TX_LO_NIB 3'b100 `define TX_CHAR_CR 3'b101 `define TX_CHAR_LF 3'b110 // binary extension mode commands - the command is indicated by bits 5:4 of the command byte `define BIN_CMD_NOP 2'b00 `define BIN_CMD_READ 2'b01 `define BIN_CMD_WRITE 2'b10 // internal wires and registers reg [3:0] main_sm; // main state machine reg read_op; // read operation flag reg write_op; // write operation flag reg data_in_hex_range; // indicates that the received data is in the range of hex number reg [7:0] data_param; // operation data parameter reg [15:0] addr_param; // operation address parameter reg [3:0] data_nibble; // data nibble from received character reg read_done; // internally generated read done flag reg read_done_s; // sampled read done reg [7:0] read_data_s; // sampled read data reg [3:0] tx_nibble; // nibble value for transmission reg [7:0] tx_char; // transmit byte from nibble to character conversion reg [2:0] tx_sm; // transmit state machine reg s_tx_busy; // sampled tx_busy for falling edge detection reg bin_read_op; // binary mode read operation flag reg bin_write_op; // binary mode write operation flag reg addr_auto_inc; // address auto increment mode reg send_stat_flag; // send status flag reg [7:0] bin_byte_count; // binary mode byte counter wire bin_last_byte; // last byte flag indicates that the current byte in the command is the last wire tx_end_p; // transmission end pulse //--------------------------------------------------------------------------------------- // module implementation // main state machine always @ (posedge clock or posedge reset) begin if (reset) main_sm <= `MAIN_IDLE; else if (new_rx_data) begin case (main_sm) // wait for a read ('r') or write ('w') command // binary extension - an all zeros byte enabled binary commands `MAIN_IDLE: // check received character if (rx_data == 8'h0) // an all zeros received byte enters binary mode main_sm <= `MAIN_BIN_CMD; else if ((rx_data == `CHAR_r_LO) | (rx_data == `CHAR_R_UP)) // on read wait to receive only address field main_sm <= `MAIN_WHITE2; else if ((rx_data == `CHAR_w_LO) | (rx_data == `CHAR_W_UP)) // on write wait to receive data and address main_sm <= `MAIN_WHITE1; else if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF)) // on new line sta in idle main_sm <= `MAIN_IDLE; else // any other character wait to end of line (EOL) main_sm <= `MAIN_EOL; // wait for white spaces till first data nibble `MAIN_WHITE1: // wait in this case until any white space character is received. in any // valid character for data value switch to data state. a new line or carriage // return should reset the state machine to idle. // any other character transitions the state machine to wait for EOL. if ((rx_data == `CHAR_SPACE) | (rx_data == `CHAR_TAB)) main_sm <= `MAIN_WHITE1; else if (data_in_hex_range) main_sm <= `MAIN_DATA; else if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF)) main_sm <= `MAIN_IDLE; else main_sm <= `MAIN_EOL; // receive data field `MAIN_DATA: // wait while data in hex range. white space transition to wait white 2 state. // CR and LF resets the state machine. any other value cause state machine to // wait til end of line. if (data_in_hex_range) main_sm <= `MAIN_DATA; else if ((rx_data == `CHAR_SPACE) | (rx_data == `CHAR_TAB)) main_sm <= `MAIN_WHITE2; else if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF)) main_sm <= `MAIN_IDLE; else main_sm <= `MAIN_EOL; // wait for white spaces till first address nibble `MAIN_WHITE2: // similar to MAIN_WHITE1 if ((rx_data == `CHAR_SPACE) | (rx_data == `CHAR_TAB)) main_sm <= `MAIN_WHITE2; else if (data_in_hex_range) main_sm <= `MAIN_ADDR; else if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF)) main_sm <= `MAIN_IDLE; else main_sm <= `MAIN_EOL; // receive address field `MAIN_ADDR: // similar to MAIN_DATA if (data_in_hex_range) main_sm <= `MAIN_ADDR; else if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF)) main_sm <= `MAIN_IDLE; else main_sm <= `MAIN_EOL; // wait to EOL `MAIN_EOL: // wait for CR or LF to move back to idle if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF)) main_sm <= `MAIN_IDLE; // binary extension // wait for command - one byte `MAIN_BIN_CMD: // check if command is a NOP command if (rx_data[5:4] == `BIN_CMD_NOP) // if NOP command then switch back to idle state main_sm <= `MAIN_IDLE; else // not a NOP command, continue receiving parameters main_sm <= `MAIN_BIN_ADRH; // wait for address parameter - two bytes // high address byte `MAIN_BIN_ADRH: // switch to next state main_sm <= `MAIN_BIN_ADRL; // low address byte `MAIN_BIN_ADRL: // switch to next state main_sm <= `MAIN_BIN_LEN; // wait for length parameter - one byte `MAIN_BIN_LEN: // check if write command else command reception ended if (bin_write_op) // wait for write data main_sm <= `MAIN_BIN_DATA; else // command reception has ended main_sm <= `MAIN_IDLE; // on write commands wait for data till end of buffer as specified by length parameter `MAIN_BIN_DATA: // if this is the last data byte then return to idle if (bin_last_byte) main_sm <= `MAIN_IDLE; // go to idle default: main_sm <= `MAIN_IDLE; endcase end end // indicates that the received data is in the range of hex number always @ (rx_data) begin if (((rx_data >= `CHAR_0 ) && (rx_data <= `CHAR_9 )) || ((rx_data >= `CHAR_A_UP) && (rx_data <= `CHAR_F_UP)) || ((rx_data >= `CHAR_a_LO) && (rx_data <= `CHAR_f_LO))) data_in_hex_range <= 1'b1; else data_in_hex_range <= 1'b0; end // read operation flag always @ (posedge clock or posedge reset) begin if (reset) read_op <= 1'b0; else if ((main_sm == `MAIN_IDLE) && new_rx_data) begin // the read operation flag is set when a read command is received in idle state and cleared // if any other character is received during that state. if ((rx_data == `CHAR_r_LO) | (rx_data == `CHAR_R_UP)) read_op <= 1'b1; else read_op <= 1'b0; end end // write operation flag always @ (posedge clock or posedge reset) begin if (reset) write_op <= 1'b0; else if ((main_sm == `MAIN_IDLE) & new_rx_data) begin // the write operation flag is set when a write command is received in idle state and cleared // if any other character is received during that state. if ((rx_data == `CHAR_w_LO) | (rx_data == `CHAR_W_UP)) write_op <= 1'b1; else write_op <= 1'b0; end end // binary mode read operation flag always @ (posedge clock or posedge reset) begin if (reset) bin_read_op <= 1'b0; else if ((main_sm == `MAIN_BIN_CMD) && new_rx_data && (rx_data[5:4] == `BIN_CMD_READ)) // read command is started on reception of a read command bin_read_op <= 1'b1; else if (bin_read_op && tx_end_p && bin_last_byte) // read command ends on transmission of the last byte read bin_read_op <= 1'b0; end // binary mode write operation flag always @ (posedge clock or posedge reset) begin if (reset) bin_write_op <= 1'b0; else if ((main_sm == `MAIN_BIN_CMD) && new_rx_data && (rx_data[5:4] == `BIN_CMD_WRITE)) // write command is started on reception of a write command bin_write_op <= 1'b1; else if ((main_sm == `MAIN_BIN_DATA) && new_rx_data && bin_last_byte) bin_write_op <= 1'b0; end // send status flag - used only in binary extension mode always @ (posedge clock or posedge reset) begin if (reset) send_stat_flag <= 1'b0; else if ((main_sm == `MAIN_BIN_CMD) && new_rx_data) begin // check if a status byte should be sent at the end of the command if (rx_data[0] == 1'b1) send_stat_flag <= 1'b1; else send_stat_flag <= 1'b0; end end // address auto increment - used only in binary extension mode always @ (posedge clock or posedge reset) begin if (reset) addr_auto_inc <= 1'b0; else if ((main_sm == `MAIN_BIN_CMD) && new_rx_data) begin // check if address should be automatically incremented or not. // Note that when rx_data[1] is set, address auto increment is disabled. if (rx_data[1] == 1'b0) addr_auto_inc <= 1'b1; else addr_auto_inc <= 1'b0; end end // operation data parameter always @ (posedge clock or posedge reset) begin if (reset) data_param <= 8'h0; else if ((main_sm == `MAIN_WHITE1) & new_rx_data & data_in_hex_range) data_param <= {4'h0, data_nibble}; else if ((main_sm == `MAIN_DATA) & new_rx_data & data_in_hex_range) data_param <= {data_param[3:0], data_nibble}; end // operation address parameter always @ (posedge clock or posedge reset) begin if (reset) addr_param <= 0; else if ((main_sm == `MAIN_WHITE2) & new_rx_data & data_in_hex_range) addr_param <= {12'b0, data_nibble}; else if ((main_sm == `MAIN_ADDR) & new_rx_data & data_in_hex_range) addr_param <= {addr_param[11:0], data_nibble}; // binary extension else if (main_sm == `MAIN_BIN_ADRH) addr_param[15:8] <= rx_data; else if (main_sm == `MAIN_BIN_ADRL) addr_param[7:0] <= rx_data; end // binary mode command byte counter is loaded with the length parameter and counts down to zero. // NOTE: a value of zero for the length parameter indicates a command of 256 bytes. always @ (posedge clock or posedge reset) begin if (reset) bin_byte_count <= 8'b0; else if ((main_sm == `MAIN_BIN_LEN) && new_rx_data) bin_byte_count <= rx_data; else if ((bin_write_op && (main_sm == `MAIN_BIN_DATA) && new_rx_data) || (bin_read_op && tx_end_p)) // byte counter is updated on every new data received in write operations and for every // byte transmitted for read operations. bin_byte_count <= bin_byte_count - 1; end // last byte in command flag assign bin_last_byte = (bin_byte_count == 8'h01) ? 1'b1 : 1'b0; // internal write control and data always @ (posedge clock or posedge reset) begin if (reset) begin write_req <= 1'b0; int_write <= 1'b0; int_wr_data <= 0; end else if (write_op && (main_sm == `MAIN_ADDR) && new_rx_data && !data_in_hex_range) begin write_req <= 1'b1; int_wr_data <= data_param; end // binary extension mode else if (bin_write_op && (main_sm == `MAIN_BIN_DATA) && new_rx_data) begin write_req <= 1'b1; int_wr_data <= rx_data; end else if (int_gnt && write_req) begin // set internal bus write and clear the write request flag int_write <= 1'b1; write_req <= 1'b0; end else int_write <= 1'b0; end // internal read control always @ (posedge clock or posedge reset) begin if (reset) begin int_read <= 1'b0; read_req <= 1'b0; end else if (read_op && (main_sm == `MAIN_ADDR) && new_rx_data && !data_in_hex_range) read_req <= 1'b1; // binary extension else if (bin_read_op && (main_sm == `MAIN_BIN_LEN) && new_rx_data) // the first read request is issued on reception of the length byte read_req <= 1'b1; else if (bin_read_op && tx_end_p && !bin_last_byte) // the next read requests are issued after the previous read value was transmitted and // this is not the last byte to be read. read_req <= 1'b1; else if (int_gnt && read_req) begin // set internal bus read and clear the read request flag int_read <= 1'b1; read_req <= 1'b0; end else int_read <= 1'b0; end // external request signal is active on read or write request assign int_req = write_req | read_req; // internal address always @ (posedge clock or posedge reset) begin if (reset) int_address <= 0; else if ((main_sm == `MAIN_ADDR) && new_rx_data && !data_in_hex_range) int_address <= addr_param[AW-1:0]; // binary extension else if ((main_sm == `MAIN_BIN_LEN) && new_rx_data) // sample address parameter on reception of length byte int_address <= addr_param[AW-1:0]; else if (addr_auto_inc && ((bin_read_op && tx_end_p && !bin_last_byte) || (bin_write_op && int_write))) // address is incremented on every read or write if enabled int_address <= int_address + 1; end // read done flag and sampled data read always @ (posedge clock or posedge reset) begin if (reset) begin read_done <= 1'b0; read_done_s <= 1'b0; read_data_s <= 8'h0; end else begin // read done flag if (int_read) read_done <= 1'b1; else read_done <= 1'b0; // sampled read done read_done_s <= read_done; // sampled data read if (read_done) read_data_s <= int_rd_data; end end // transmit state machine and control always @ (posedge clock or posedge reset) begin if (reset) begin tx_sm <= `TX_IDLE; tx_data <= 8'h0; new_tx_data <= 1'b0; end else case (tx_sm) // wait for read done indication `TX_IDLE: // on end of every read operation check how the data read should be transmitted // according to read type: ascii or binary. if (read_done_s) // on binary mode read transmit byte value if (bin_read_op) begin // note that there is no need to change state tx_data <= read_data_s; new_tx_data <= 1'b1; end else begin tx_sm <= `TX_HI_NIB; tx_data <= tx_char; new_tx_data <= 1'b1; end // check if status byte should be transmitted else if ((send_stat_flag && bin_read_op && tx_end_p && bin_last_byte) || // end of read command (send_stat_flag && bin_write_op && new_rx_data && bin_last_byte) || // end of write command ((main_sm == `MAIN_BIN_CMD) && new_rx_data && (rx_data[5:4] == `BIN_CMD_NOP))) // NOP begin // send status byte - currently a constant tx_data <= 8'h5a; new_tx_data <= 1'b1; end else new_tx_data <= 1'b0; // wait for transmit to end `TX_HI_NIB: if (tx_end_p) begin tx_sm <= `TX_LO_NIB; tx_data <= tx_char; new_tx_data <= 1'b1; end else new_tx_data <= 1'b0; // wait for transmit to end `TX_LO_NIB: if (tx_end_p) begin tx_sm <= `TX_CHAR_CR; tx_data <= `CHAR_CR; new_tx_data <= 1'b1; end else new_tx_data <= 1'b0; // wait for transmit to end `TX_CHAR_CR: if (tx_end_p) begin tx_sm <= `TX_CHAR_LF; tx_data <= `CHAR_LF; new_tx_data <= 1'b1; end else new_tx_data <= 1'b0; // wait for transmit to end `TX_CHAR_LF: begin if (tx_end_p) tx_sm <= `TX_IDLE; // clear tx new data flag new_tx_data <= 1'b0; end // return to idle default: tx_sm <= `TX_IDLE; endcase end // select the nibble to the nibble to character conversion always @ (tx_sm or read_data_s) begin case (tx_sm) `TX_IDLE: tx_nibble = read_data_s[7:4]; `TX_HI_NIB: tx_nibble = read_data_s[3:0]; default: tx_nibble = read_data_s[7:4]; endcase end // sampled tx_busy always @ (posedge clock or posedge reset) begin if (reset) s_tx_busy <= 1'b0; else s_tx_busy <= tx_busy; end // tx end pulse assign tx_end_p = ~tx_busy & s_tx_busy; // character to nibble conversion always @ (rx_data) begin case (rx_data) `CHAR_0: data_nibble = 4'h0; `CHAR_1: data_nibble = 4'h1; `CHAR_2: data_nibble = 4'h2; `CHAR_3: data_nibble = 4'h3; `CHAR_4: data_nibble = 4'h4; `CHAR_5: data_nibble = 4'h5; `CHAR_6: data_nibble = 4'h6; `CHAR_7: data_nibble = 4'h7; `CHAR_8: data_nibble = 4'h8; `CHAR_9: data_nibble = 4'h9; `CHAR_A_UP, `CHAR_a_LO: data_nibble = 4'ha; `CHAR_B_UP, `CHAR_b_LO: data_nibble = 4'hb; `CHAR_C_UP, `CHAR_c_LO: data_nibble = 4'hc; `CHAR_D_UP, `CHAR_d_LO: data_nibble = 4'hd; `CHAR_E_UP, `CHAR_e_LO: data_nibble = 4'he; `CHAR_F_UP, `CHAR_f_LO: data_nibble = 4'hf; default: data_nibble = 4'hf; endcase end // nibble to character conversion always @ (tx_nibble) begin case (tx_nibble) 4'h0: tx_char = `CHAR_0; 4'h1: tx_char = `CHAR_1; 4'h2: tx_char = `CHAR_2; 4'h3: tx_char = `CHAR_3; 4'h4: tx_char = `CHAR_4; 4'h5: tx_char = `CHAR_5; 4'h6: tx_char = `CHAR_6; 4'h7: tx_char = `CHAR_7; 4'h8: tx_char = `CHAR_8; 4'h9: tx_char = `CHAR_9; 4'ha: tx_char = `CHAR_A_UP; 4'hb: tx_char = `CHAR_B_UP; 4'hc: tx_char = `CHAR_C_UP; 4'hd: tx_char = `CHAR_D_UP; 4'he: tx_char = `CHAR_E_UP; default: tx_char = `CHAR_F_UP; endcase end endmodule //--------------------------------------------------------------------------------------- // Th.. Th.. Th.. Thats all folks !!! //---------------------------------------------------------------------------------------