// Chuck Benz, Hollis, NH Copyright (c)2006 // // The information and description contained herein is the // property of Chuck Benz. // // Permission is granted for any reuse of this information // and description as long as this copyright notice is // preserved. Modifications may be made as long as this // notice is preserved. // serdebug is a simple module that can be added to any design // to provide an RS232 port with a simple monitor allowing // read/write access to a memory space. A UART provides serial // connectivity, and an rx state machine looks for packets in // the form of: // Xcrraaaaaaaadddddddddddd // where X is the character 'X' or 'x' // c is a character specifying the command (A, B, G, and H are defined) // rr is two characters as hex digits representing an optional crc8 // aaaaaaaa is 8 characters as hex digits representing a 32 bit address // dddddddddddddddd is 16 chars as hex digits representing 64 data bits // the hex digits should be 0-9 and a-f or A-F. // at any position, a space or _ can be inserted to aid readability // The point of this format is that it's usable from a terminal, but also // usable from a program sending packets to the logic. module cbaf_serdebug ( input clk33, input resetl, // serial lines input rxd, output txd, // external memory output reg [31:0] mem_address, output reg [63:0] mem_wrdata, output reg mem_read, output reg mem_write, input [63:0] mem_rddata, input mem_ack) ; wire uart_tx_rege, uart_tx_bufe ; reg [7:0] uart_txdata ; reg uart_load, uart_txenable, uart_rxenable ; reg [11:0] uart_div ; reg [5:0] tx_state, rx_state ; reg rxdQ ; wire [7:0] uart_datain ; wire uart_drdy ; reg [3:0] val_line ; reg do_cmd, snd_ans ; reg [23:0] txline ; reg echochar ; reg checkcrc ; reg [31:0] rxaddress ; reg [63:0] rxdata, answer_data ; reg [7:0] rxcrc, rxtype ; reg [15:0] writecnt, scratch ; reg crcsupported ; // reg [31:0] count ; wire [3:0] datain_nibble = uart_datain[6] ? (uart_datain[2:0] + 9) : (uart_datain[3:0]) ; always @ (posedge clk33 or negedge resetl) if (~resetl) begin // count <= 0 ; uart_div <= 0 ; uart_txenable <= 0 ; uart_rxenable <= 0 ; uart_load <= 0 ; uart_txdata <= 0 ; tx_state <= 0 ; rx_state <= 0 ; rxdQ <= 0 ; val_line <= 4 ; do_cmd <= 0 ; txline <= 24'h0d4243 ; echochar <= 1 ; checkcrc <= 0 ; rxaddress <= 0 ; rxdata <= 0 ; rxcrc <= 0 ; rxtype <= 0 ; snd_ans <= 0 ; answer_data <= 0 ; crcsupported <= 0 ; writecnt <= 0 ; scratch <= 0 ; end else begin // if clk is 100 MHz... need divide by 64M, bit [25] // uart_load is divided 100 MHz to the Tx clk rate... // for 57600, divide by 108 * 16 ... // for 115200, divide by 54 * 16 ... // but from 33 MHz, 18 * 16 for 115200... if (uart_div[4:0] == 17) begin uart_div[4:0] <= 0 ; uart_div[11:8] <= uart_div[11:8] + 1 ; end else uart_div[4:0] <= uart_div[4:0] + 1 ; uart_div[7:5] <= 0 ; uart_txenable <= (uart_div == 0) ; uart_rxenable <= (uart_div[4:0] == 0) ; // tx state machine... send "hello\n" every 20 seconds /* count <= count + 1 ; case (tx_state) 0: if (count[30:0] == 0) tx_state <= 1 ; 1, 3, 5, 7, 9, 11, 13: if (uart_tx_bufe) begin uart_load <= 1 ; case (tx_state) 1: uart_txdata <= 8'h68 ; // h 3: uart_txdata <= 8'h65 ; // e 5: uart_txdata <= 8'h6c ; // l 7: uart_txdata <= 8'h6c ; // l 9: uart_txdata <= 8'h6f ; // o 11: uart_txdata <= 8'h0a ; // \n 13: uart_txdata <= 8'h0d ; // \r endcase tx_state <= tx_state + 1 ; end 15: begin tx_state <= 0 ; end default: begin uart_load <= 0 ; tx_state <= tx_state + 1 ; end endcase */ // tx state machine... send from txline or from answer_data uart_load <= 0 ; case (tx_state) 0: if (val_line > 0) tx_state <= 1 ; else if (snd_ans) tx_state <= 2 ; 1: if (uart_tx_bufe && ~uart_load) begin uart_load <= 1 ; uart_txdata <= txline[7:0] ; txline <= txline >> 8 ; if (val_line == 1) tx_state <= 0 ; val_line <= val_line - 1 ; end default: if (uart_tx_bufe && ~uart_load) begin uart_load <= 1 ; case (tx_state) 2: uart_txdata <= 8'h58 ; 3: uart_txdata <= 8'h30 ; // '0', 0x30 - answer type... 4: uart_txdata <= 8'h30 ; // will be crc.. 5: uart_txdata <= 8'h30 ; // will be crc.. 6, 7, 8, 9, 10, 11, 12, 13: uart_txdata <= 8'h30 ; 30: uart_txdata <= 8'h0d ; 31: uart_txdata <= 8'h0a ; default: uart_txdata <= answer_data[63:60] + ((answer_data[63:60] > 9) ? 8'h37 : 8'h30) ; endcase if (tx_state > 13) answer_data <= answer_data << 4 ; if (tx_state == 31) tx_state <= 0 ; else tx_state <= tx_state + 1 ; if (tx_state == 29) snd_ans <= 0 ; end endcase if (~crcsupported) checkcrc <= 0 ; mem_write <= do_cmd && (rxtype == 8'h48) && ~mem_ack ; mem_read <= do_cmd && (rxtype == 8'h42) && ~snd_ans && ~mem_ack ; mem_address <= rxaddress ; mem_wrdata <= rxdata ; // ops state machine if (do_cmd) case (rxtype) 8'h41: // 'A' - read our only csr begin if (~snd_ans) begin do_cmd <= 0 ; snd_ans <= 1 ; answer_data <= {16'hcbaf, scratch, writecnt, 13'b0, echochar, crcsupported, checkcrc} ; end end 8'h42: // 'B' read of memory begin if (~snd_ans && mem_ack) begin do_cmd <= 0 ; snd_ans <= 1 ; answer_data <= mem_rddata ; end end 8'h47: // 'G' - write to csr. begin do_cmd <= 0 ; if (rxaddress == 0) begin checkcrc <= rxdata[0] ; echochar <= rxdata[2] ; if (rxdata[31:16] != 0) writecnt <= 0 ; else writecnt <= writecnt + 1 ; scratch <= rxdata[47:32] ; end end 8'h48: // 'H' - write to memory begin if (mem_ack) begin do_cmd <= 0 ; writecnt <= writecnt + 1 ; end end default: do_cmd <= 0 ; endcase // rcv state machine... // Look for "X" or "x" as SOF. count bytes 0-27: // 0: SOF: x/X // 1: type // 2,3: CRC // 4-11: address, 4 bites per byte // 12-27: data, 4 bites per byte if (uart_drdy) begin if (((uart_datain == 8'h58) || (uart_datain == 8'h78)) && ~do_cmd) begin if ((rx_state != 0) && echochar) begin txline <= {uart_datain, 8'h0a, 8'h0d} ; val_line <= 3 ; end else if (echochar) begin val_line <= 1 ; txline <= uart_datain ; end rx_state <= 1 ; end else if (rx_state == 27) begin txline <= {8'h0a, 8'h0d, uart_datain} ; rx_state <= 0 ; do_cmd <= 1 ; if (echochar) val_line <= 3 ; end else if (rx_state > 0) begin if ((uart_datain != 8'h5f) && (uart_datain != 8'h20)) // (allowing '_' and space as optional extra chars rx_state <= rx_state + 1 ; txline <= uart_datain ; if (echochar) val_line <= 1 ; end case (rx_state) 1: rxtype <= uart_datain ; 2: rxcrc[7:4] <= datain_nibble ; 3: rxcrc[3:0] <= datain_nibble ; 4: rxaddress[31:28] <= datain_nibble ; 5: rxaddress[27:24] <= datain_nibble ; 6: rxaddress[23:20] <= datain_nibble ; 7: rxaddress[19:16] <= datain_nibble ; 8: rxaddress[15:12] <= datain_nibble ; 9: rxaddress[11:8] <= datain_nibble ; 10: rxaddress[7:4] <= datain_nibble ; 11: rxaddress[3:0] <= datain_nibble ; 12: rxdata[63:60] <= datain_nibble ; 13: rxdata[59:56] <= datain_nibble ; 14: rxdata[55:52] <= datain_nibble ; 15: rxdata[51:48] <= datain_nibble ; 16: rxdata[47:44] <= datain_nibble ; 17: rxdata[43:40] <= datain_nibble ; 18: rxdata[39:36] <= datain_nibble ; 19: rxdata[35:32] <= datain_nibble ; 20: rxdata[31:28] <= datain_nibble ; 21: rxdata[27:24] <= datain_nibble ; 22: rxdata[23:20] <= datain_nibble ; 23: rxdata[19:16] <= datain_nibble ; 24: rxdata[15:12] <= datain_nibble ; 25: rxdata[11:8] <= datain_nibble ; 26: rxdata[7:4] <= datain_nibble ; 27: rxdata[3:0] <= datain_nibble ; endcase end rxdQ <= rxd ; crcsupported <= 0 ; end wire [127:0] line = {rxtype, rxaddress, rxdata, 16'hcbaf, datain_nibble, uart_datain }; cbaf_uart_rxunit rxunit ( .ferr (ferr), .oerr (oerr), .drdy (uart_drdy), .datain (uart_datain), // Inputs .clk (clk33), .reset (resetl), .enable (uart_rxenable), .rxd (rxdQ), .rd (uart_drdy)); cbaf_uart_txunit txunit ( .txd (txd), .trege (uart_tx_rege), .tbufe (uart_tx_bufe), .clk (clk33), .reset (resetl), .enable (uart_txenable), .load (uart_load), .datao (uart_txdata)); endmodule