OpenCores
URL https://opencores.org/ocsvn/rs232_syscon/rs232_syscon/trunk

Subversion Repositories rs232_syscon

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 3 to Rev 4
    Reverse comparison

Rev 3 → Rev 4

/tags/V001/rs232_syscon.doc Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
tags/V001/rs232_syscon.doc Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: tags/V001/b13c_environment.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: tags/V001/b13c_environment.zip =================================================================== --- tags/V001/b13c_environment.zip (revision 3) +++ tags/V001/b13c_environment.zip (nonexistent)
tags/V001/b13c_environment.zip Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: trunk/rs232_syscon.v =================================================================== --- trunk/rs232_syscon.v (revision 3) +++ trunk/rs232_syscon.v (nonexistent) @@ -1,1168 +0,0 @@ -//------------------------------------------------------------------------------------- -// -// Author: John Clayton -// Date : June 25, 2001 -// Update: 6/25/01 copied this file from ps2_mouse.v (pared down). -// Update: 6/07/01 Finished initial coding efforts. -// Update: 7/19/01 First compilation. Added master_br_o and master_bg_i; -// Update: 7/25/01 Testing. Eliminated msg_active signal. Changed serial.v -// to reflect new handshaking (i.e. "load_request" is now a -// periodic pulse of tx_clk_1x from rs232_tx...) -// Update: 7/30/01 Began coding m2 state machine. Defined response codes. -// Update: 8/01/01 After some testing with m2, merged m2 into m1. Eliminated -// response codes. -// Update: 8/02/01 Tested & measured the single "combined" state machine's -// performance, and "it was found wanting." (The 49.152MHz -// clock frequency was too fast for it...) Created clk_s -// at 49.152/2 MHz, and this worked. -// Update: 8/03/01 Added counter loop to "execute" and "bus_granted" states -// so that multiple bus cycles are generated, at sequential -// addresses. However, the qty field is not cleared before -// being loaded with new characters, which causes problems. -// Update: 8/07/01 Finished debugging. The read print formatting is now -// correct, and the unit appears to operate correctly. -// Many hours were spent puzzling over how to make this work. -// Removed port "debug". -// Update: 8/24/01 Added "master_stb_i" and "master_we_i" inputs and logic. -// Update: 12/13/01 For memory_sizer.v, I lowered the frequency of clk_s down -// to 49.152/4 MHz, so I changed the CLOCK_FACTOR from 8 to 4 -// on the rs232 transciever, and this worked fine. -// Update: 9/09/02 Incorporated the "autobaud_with_tracking" module so that -// the serial clock is generated automatically, no matter -// what frequency clk_i is used. The user simply needs to -// press "enter" from the terminal program to synchronize -// the baud rate generator. Changing BAUD rates on the fly -// is also permitted, simply change to a new BAUD rate in the -// terminal program and hit enter. -// Update:11/26/02 Changed the string constants to binary representation -// (Just to eliminate warnings in XST.) -// -// -// -// -// -// Description -//------------------------------------------------------------------------------------- -// This is a state-machine driven rs232 serial port interface to a "Wishbone" -// type of bus. It is intended to be used as a "Wishbone system controller" -// for debugging purposes. Specifically, the unit allows the user to send -// text commands to the "rs232_syscon" unit, in order to generate read and -// write cycles on the Wishbone compatible bus. The command structure is -// quite terse and spartan in nature, this is for the sake of the logic itself. -// Because the menu-driven command structure is supported without the use of -// dedicated memory blocks (in order to maintain cross-platform portability -// as much as possible) the menus and command responses were kept as small -// as possible. In most cases, the responses from the unit to the user -// consist of a "newline" and one or two visible characters. The command -// structure consists of the following commands and responses: -// -// Command Syntax Purpose -// --------------- --------------------------------------- -// w aaaa dddd xx Write data "dddd" starting at address "aaaa" -// perform this "xx" times at sequential addresses. -// (The quantity field is optional, default is 1). -// r aaaa xx Read data starting from address "aaaa." -// Perform this "xx" times at sequential addresses. -// (The quantity field is optional, default is 1). -// i Send a reset pulse to the system. (initialize). -// -// Response from rs232_syscon Meaning -// -------------------------- --------------------------------------- -// OK Command received and performed. No errors. -// ? Command buffer full, without receiving "enter." -// C? Command not recognized. -// A? Address field syntax error. -// D? Data field syntax error. -// Q? Quantity field syntax error. -// ! No "ack_i", or else "err_i" received from bus. -// B! No "bg_i" received from master. -// -// NOTES on the operation of this unit: -// -// - The unit generates a command prompt which is "-> ". -// - Capitalization is not important. -// - Each command is terminated by the "enter" key (0x0d character). -// Commands are executed as soon as "enter" is received. -// - Trailing parameters need not be re-entered. Their values will -// remain the same as their previous settings. -// - Use of the backspace key is supported, so mistakes can be corrected. -// - The length of the command line is limited to a fixed number of -// characters, as configured by parameter. -// - Fields are separated by white space, including "tab" and/or "space" -// - All numerical fields are interpreted as hexadecimal numbers. -// Decimal is not supported. -// - Numerical field values are retained between commands. If a "r" is issued -// without any fields following it, the previous values will be used. A -// set of "quantity" reads will take place at sequential addresses. -// If a "w" is issued without any fields following it, the previous data -// value will be written "quantity" times at sequential addresses, starting -// from the next location beyond where the last command ended. -// - If the user does not wish to use "ack" functionality, simply tie the -// "ack_i" input to 1b'1, and then the ! response will never be generated. -// - The data which is read in by the "r" command is displayed using lines -// which begin with the address, followed by the data fields. The number -// of data fields displayed per line (following the address) is adjustable -// by setting a parameter. No other display format adjustments can be made. -// - There is currently only a single watchdog timer. It begins to count at -// the time a user hits "enter" to execute a command. If the bus is granted -// and the ack is received before the expiration of the timer, then the -// cycle will complete normally. Therefore, the watchdog timeout value -// needs to include time for the request and granting of the bus, in -// addition to the time needed for the actual bus cycle to complete. -// -// -// Currently, there is only a single indicator (stb_o) generated during bus -// output cycles which are generated from this unit. -// The user can easily implement decoding logic based upon adr_o and stb_o -// which would serve as multiple "stb_o" type signals for different cores -// which would be sharing the same bus. -// -// The dat_io bus supported by this module is a tri-state type of bus. The -// Wishbone spec. allows for this type of bus (see Wishbone spec. pg. 66). -// However, if separate dat_o and dat_i busses are desired, they can be added -// to the module without too much trouble. Supposedly the only difference -// between the two forms of data bus is that one of them avoids using tri-state -// at the cost of doubling the number of interconnects used to carry data back -// and forth... Some people say that tri-state should be avoided for use -// in internal busses in ASICs. Maybe they are right. -// But in FPGAs tri-state seems to work pretty well, even for internal busses. -// -// Parameters are provided to configure the width of the different command -// fields. To simplify the logic for binary to hexadecimal conversion, these -// parameters allow adjustment in units of 1 hex digit, not anything smaller. -// If your bus has 10 bits, for instance, simply set the address width to 3 -// which produces 12 bits, and then just don't use the 2 msbs of address -// output. -// -// No support for the optional Wishbone "retry" (rty_i) input is provided at -// this time. -// No support for "tagn_o" bits is provided at this time, although a register -// might be added external to this module in order to implement to tag bits. -// No BLOCK or RMW cycles are supported currently, so cyc_o is equivalent to -// stb_o... -// The output busses are not tri-stated. The user may add tri-state buffers -// external to the module, using "stb_o" to enable the buffer outputs. -// -//------------------------------------------------------------------------------------- - - -`define NIBBLE_SIZE 4 // Number of bits in one nibble - -// The command register has these values -`define CMD_0 0 // Unused command -`define CMD_I 1 // Initialize (or reset) -`define CMD_R 2 // Read -`define CMD_W 3 // Write - -module rs232_syscon ( - clk_i, - reset_i, - ack_i, - err_i, - master_bg_i, - master_adr_i, - master_stb_i, - master_we_i, - rs232_rxd_i, - dat_io, - rst_o, - master_br_o, - stb_o, - cyc_o, - adr_o, - we_o, - rs232_txd_o - ); - - -// Parameters - -// The timer value can be from [0 to (2^WATCHDOG_TIMER_BITS_PP)-1] inclusive. -// RD_FIELDS_PP can be from [0 to (2^RD_FIELD_CTR_BITS_PP)-1] inclusive. -// Ensure that (2^CHAR_COUNT_BITS_PP) >= CMD_BUFFER_SIZE_PP. -// The setting of CMD_BUFFER_SIZE_PP should be large enough to hold the -// largest command, obviously. -// Ensure that (2^RD_DIGIT_COUNT_BITS_PP) is greater than or equal to the -// larger of {ADR_DIGITS_PP,DAT_DIGITS_PP}. -parameter ADR_DIGITS_PP = 4; // # of hex digits for address. -parameter DAT_DIGITS_PP = 4; // # of hex digits for data. -parameter QTY_DIGITS_PP = 2; // # of hex digits for quantity. -parameter CMD_BUFFER_SIZE_PP = 32; // # of chars in the command buffer. -parameter CMD_PTR_BITS_PP = 4; // # of Bits in command buffer ptr. -parameter WATCHDOG_TIMER_VALUE_PP = 200; // # of sys_clks before ack expected. -parameter WATCHDOG_TIMER_BITS_PP = 8; // # of bits needed for timer. -parameter RD_FIELDS_PP = 8; // # of fields/line (when qty > 1). -parameter RD_FIELD_COUNT_BITS_PP = 3; // # of bits in the fields counter. -parameter RD_DIGIT_COUNT_BITS_PP = 2; // # of bits in the digits counter. - - -// State encodings, provided as parameters -// for flexibility to the one instantiating the module. -// In general, the default values need not be changed. - -// There is one state machines: m1. -// "default" state upon power-up and configuration is: -// "m1_initial_state" - -parameter m1_initial_state = 5'h00; -parameter m1_send_ok = 5'h01; // Sends OK -parameter m1_send_prompt = 5'h02; // Sends "-> " -parameter m1_check_received_char = 5'h03; -parameter m1_send_crlf = 5'h04; // Sends cr,lf -parameter m1_parse_error_indicator_crlf = 5'h05; // Sends cr,lf -parameter m1_parse_error_indicator = 5'h06; // Sends ? -parameter m1_ack_error_indicator = 5'h07; // Sends ! -parameter m1_bg_error_indicator = 5'h08; // Sends B! -parameter m1_cmd_error_indicator = 5'h09; // Sends C? -parameter m1_adr_error_indicator = 5'h0a; // Sends A? -parameter m1_dat_error_indicator = 5'h0b; // Sends D? -parameter m1_qty_error_indicator = 5'h0c; // Sends Q? -parameter m1_scan_command = 5'h10; -parameter m1_scan_adr_whitespace = 5'h11; -parameter m1_get_adr_field = 5'h12; -parameter m1_scan_dat_whitespace = 5'h13; -parameter m1_get_dat_field = 5'h14; -parameter m1_scan_qty_whitespace = 5'h15; -parameter m1_get_qty_field = 5'h16; -parameter m1_start_execution = 5'h17; -parameter m1_request_bus = 5'h18; -parameter m1_bus_granted = 5'h19; -parameter m1_execute = 5'h1a; -parameter m1_rd_send_adr_sr = 5'h1b; -parameter m1_rd_send_separator = 5'h1c; -parameter m1_rd_send_dat_sr = 5'h1d; -parameter m1_rd_send_space = 5'h1e; -parameter m1_rd_send_crlf = 5'h1f; - -// I/O declarations -input clk_i; // System clock input -input reset_i; // Reset signal for this module -input ack_i; // Ack input from Wishbone "slaves" -input err_i; // Err input from Wishbone "slaves" -input master_bg_i; // Bus Grant (grants this module the bus) - // Address bus input from "normal" Wishbone - // master (i.e. from processor) -input [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] master_adr_i; -input master_stb_i; // bus cycle signal from "normal" bus master -input master_we_i; // write enable from "normal" bus master -input rs232_rxd_i; // Serial data from debug host terminal. - // Data bus (tri-state, to save interconnect) -inout [`NIBBLE_SIZE*DAT_DIGITS_PP-1:0] dat_io; - -output rst_o; // Rst output to Wishbone "slaves" -output master_br_o; // Bus request to normal master device. -output stb_o; // Bus cycle indicator to Wishbone "slaves" -output cyc_o; // Bus cycle indicator to Wishbone "slaves" - // Address bus output to Wishbone "slaves" -output [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_o; -output we_o; // Write enable to Wishbone "slaves" -output rs232_txd_o; // Serial transmit data to debug host terminal - -reg rst_o; -reg master_br_o; - -// Internal signal declarations -wire watchdog_timer_done; // High when watchdog timer is expired -wire rd_addr_field_done; // High when displayed addr field is complete -wire rd_data_field_done; // High when displayed data field is complete -wire rd_line_done; // High when displayed line is complete -wire char_is_enter; // High when cmd_buffer[char_count] is enter. -wire char_is_whitespace; // High when cmd_buffer[char_count] is whitespace. -wire char_is_num; // High when cmd_buffer[char_count] is 0..9 -wire char_is_a_f; // High when cmd_buffer[char_count] is a..f -wire char_is_hex; // High when cmd_buffer[char_count] is a hex char. -wire char_is_r; // High when cmd_buffer[char_count] is r. -wire char_is_w; // High when cmd_buffer[char_count] is w. -wire char_is_i; // High when cmd_buffer[char_count] is i. -wire rx_char_is_enter; // High when rs232_rx_char is enter. -wire rx_char_is_backspace; // High when rs232_rx_char is backspace. -wire [4:0] msg_pointer; // Determines message position or address. -wire [3:0] hex_digit; // This is the digit to be stored. - -reg rs232_echo; // High == echo char's received. -reg [7:0] msg_char; // Selected response message character. -reg [4:0] msg_base; // Added to msg_offset to form msg_pointer. -reg [4:0] msg_offset; // Offset from start of message. -reg reset_msg_offset; // High == set message offset to zero -reg incr_msg_offset; // Used for output messages. -reg cmd_i; // Sets command. -reg cmd_r; // Sets command. -reg cmd_w; // Sets command. -reg shift_rd_adr; // Shifts the rd_adr_sr by one character. -reg store_adr; // Allows adr_sr to store hex_digit. -reg store_dat; // Allows dat_sr to store hex_digit. -reg store_qty; // Allows qty_sr to store hex_digit. -reg reset_adr; // Clears adr_sr -reg reset_dat; // Clears dat_sr -reg reset_qty; // Clears qty_sr -reg init_qty; // Sets qty_sr to 1 -reg capture_dat; // Puts dat_io into dat_sr for later display. - - // For the buses -wire [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_ptr; // = adr_sr + adr_offset - -reg stb_l; // "local" stb signal (to distinguish from stb_o) -reg we_l; // "local" we signal (to distinguish from we_o) - -reg [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] rd_adr_sr; // sr for printing addresses -reg [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_sr; // "nibble" shift register -reg [`NIBBLE_SIZE*DAT_DIGITS_PP-1:0] dat_sr; // "nibble" shift register -reg [`NIBBLE_SIZE*QTY_DIGITS_PP-1:0] qty_sr; // "nibble" shift register -reg [1:0] command; -reg [`NIBBLE_SIZE*QTY_DIGITS_PP-1:0] adr_offset; // counts from 0 to qty_sr -reg reset_adr_offset; -reg incr_adr_offset; - - // For the command buffer -reg [CMD_PTR_BITS_PP-1:0] cmd_ptr; // Offset from start of command. -reg reset_cmd_ptr; // High == set command pointer to zero. -reg incr_cmd_ptr; // Used for "write port" side of the command buffer -reg decr_cmd_ptr; // Used for "write port" side of the command buffer -reg cmd_buffer_write; -reg [7:0] cmd_buffer [0:CMD_BUFFER_SIZE_PP-1]; -wire [7:0] cmd_char; -wire [7:0] lc_cmd_char; // Lowercase version of cmd_char - - // For the state machine -reg [4:0] m1_state; -reg [4:0] m1_next_state; - - // For various counters -reg reset_rd_field_count; -reg reset_rd_digit_count; -reg incr_rd_field_count; -reg incr_rd_digit_count; -reg [RD_FIELD_COUNT_BITS_PP-1:0] rd_field_count; // "fields displayed" -reg [RD_DIGIT_COUNT_BITS_PP-1:0] rd_digit_count; // "digits displayed" -reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_timer_count; -reg reset_watchdog; - - // For the rs232 interface -wire serial_clk; -wire [2:0] rs232_rx_error; -wire rs232_tx_load; -wire rs232_tx_load_request; -wire rs232_rx_data_ready; -wire [7:0] rs232_rx_char; -wire [7:0] rs232_tx_char; // Either rs232_rx_char or msg_char - -//-------------------------------------------------------------------------- -// Instantiations -//-------------------------------------------------------------------------- - - -// These defines are for the rs232 interface -`define START_BITS 1 -`define DATA_BITS 8 -`define STOP_BITS 1 -`define CLOCK_FACTOR 8 - -// This module generates a serial BAUD clock automatically. -// The unit synchronizes on the carriage return character, so the user -// only needs to press the "enter" key for serial communications to start -// working, no matter what BAUD rate and clk_i frequency are used! -auto_baud_with_tracking #( - `CLOCK_FACTOR, // CLOCK_FACTOR_PP - 16 // LOG2_MAX_COUNT_PP - ) - clock_unit_2 - ( - .clk_i(clk_i), - .reset_i(reset_i), - .serial_dat_i(rs232_rxd_i), - .auto_baud_locked_o(), - .baud_clk_o(serial_clk) - ); - -// A transmitter, which asserts load_request at the end of the currently -// transmitted word. The tx_clk must be a "clock enable" (narrow positive -// pulse) which occurs at 16x the desired transmit rate. If load_request -// is connected directly to load, the unit will transmit continuously. -rs232tx #( - `START_BITS, // start_bits - `DATA_BITS, // data_bits - `STOP_BITS, // stop_bits (add intercharacter delay...) - `CLOCK_FACTOR // clock_factor - ) - rs232_tx_block // instance name - ( - .clk(clk_i), - .tx_clk(serial_clk), - .reset(reset_i), - .load(rs232_tx_load), - .data(rs232_tx_char), - .load_request(rs232_tx_load_request), - .txd(rs232_txd_o) - ); - -// A receiver, which asserts "word_ready" to indicate a received word. -// Asserting "read_word" will cause "word_ready" to go low again if it was high. -// The character is held in the output register, during the time the next -// character is coming in. -rs232rx #( - `START_BITS, // start_bits - `DATA_BITS, // data_bits - `STOP_BITS, // stop_bits - `CLOCK_FACTOR // clock_factor - ) - rs232_rx_block // instance name - ( - .clk(clk_i), - .rx_clk(serial_clk), - .reset(reset_i || (| rs232_rx_error)), - .rxd(rs232_rxd_i), - .read(rs232_tx_load), - .data(rs232_rx_char), - .data_ready(rs232_rx_data_ready), - .error_over_run(rs232_rx_error[0]), - .error_under_run(rs232_rx_error[1]), - .error_all_low(rs232_rx_error[2]) - ); - -//`undef START_BITS -//`undef DATA_BITS -//`undef STOP_BITS -//`undef CLOCK_FACTOR - - -//-------------------------------------------------------------------------- -// Module code -//-------------------------------------------------------------------------- - -assign adr_o = master_bg_i?adr_ptr:master_adr_i; -assign we_o = master_bg_i?we_l:master_we_i; -assign stb_o = master_bg_i?stb_l:master_stb_i; - - -assign dat_io = (master_bg_i && we_l && stb_l)? - dat_sr:{`NIBBLE_SIZE*DAT_DIGITS_PP{1'bZ}}; - -// Temporary -assign cyc_o = stb_o; // Separate cyc_o is not yet supported! - - -// This is the adress offset counter -always @(posedge clk_i) -begin - if (reset_i || reset_adr_offset) adr_offset <= 0; - else if (incr_adr_offset) adr_offset <= adr_offset + 1; -end -// This forms the adress pointer which is used on the bus. -assign adr_ptr = adr_sr + adr_offset; - - -// This is the ROM for the ASCII characters to be transmitted. -always @(msg_pointer) -begin - case (msg_pointer) // synthesis parallel_case - 5'b00000 : msg_char <= 8'h30; // "0"; // Hexadecimal characters - 5'b00001 : msg_char <= 8'h31; // "1"; - 5'b00010 : msg_char <= 8'h32; // "2"; - 5'b00011 : msg_char <= 8'h33; // "3"; - 5'b00100 : msg_char <= 8'h34; // "4"; - 5'b00101 : msg_char <= 8'h35; // "5"; - 5'b00110 : msg_char <= 8'h36; // "6"; - 5'b00111 : msg_char <= 8'h37; // "7"; - 5'b01000 : msg_char <= 8'h38; // "8"; - 5'b01001 : msg_char <= 8'h39; // "9"; - 5'b01010 : msg_char <= 8'h41; // "A"; // Address error indication - 5'b01011 : msg_char <= 8'h42; // "B"; - 5'b01100 : msg_char <= 8'h43; // "C"; // Command error indication - 5'b01101 : msg_char <= 8'h44; // "D"; // Data error indication - 5'b01110 : msg_char <= 8'h45; // "E"; - 5'b01111 : msg_char <= 8'h46; // "F"; - 5'b10000 : msg_char <= 8'h20; // " "; // Space - 5'b10001 : msg_char <= 8'h3A; // ":"; // Colon - 5'b10010 : msg_char <= 8'h20; // " "; // Space - 5'b10011 : msg_char <= 8'h3F; // "?"; // Parse error indication - 5'b10100 : msg_char <= 8'h21; // "!"; // ack_i/err_i error indication - 5'b10101 : msg_char <= 8'h4F; // "O"; // "All is well" message - 5'b10110 : msg_char <= 8'h4B; // "K"; - 5'b10111 : msg_char <= 8'h0D; // Carriage return & line feed - 5'b11000 : msg_char <= 8'h0A; - 5'b11001 : msg_char <= 8'h2D; // "-"; // Command Prompt - 5'b11010 : msg_char <= 8'h3E; // ">"; - 5'b11011 : msg_char <= 8'h20; // " "; - 5'b11100 : msg_char <= 8'h51; // "Q"; // Quantity error indication - default : msg_char <= 8'h3D; // "="; - endcase -end - -// This logic determines when to load a transmit character. -assign rs232_tx_load = rs232_echo? - (rs232_rx_data_ready && rs232_tx_load_request):rs232_tx_load_request; - -// This is the counter for incrementing, decrementing or resetting the -// message pointer. -always @(posedge clk_i) -begin - if (reset_i || reset_msg_offset) msg_offset <= 0; - else if (incr_msg_offset) msg_offset <= msg_offset + 1; -end -assign msg_pointer = msg_offset + msg_base; - - - -// This is the mux which selects whether to echo back the characters -// received (as during the entering of a command) or to send back response -// characters. -assign rs232_tx_char = (rs232_echo)?rs232_rx_char:msg_char; - - -// These assigments are for detecting whether the received rs232 character is -// anything of special interest. -assign rx_char_is_enter = (rs232_rx_char == 8'h0d); -assign rx_char_is_backspace = (rs232_rx_char == 8'h08); - - - -// This is state machine m1. It handles receiving the command line, including -// backspaces, and prints error/response messages. It also parses and -// executes the commands. - -// State register -always @(posedge clk_i) -begin : m1_state_register - if (reset_i) m1_state <= m1_initial_state; // perform reset for rest of system - else m1_state <= m1_next_state; -end - -// State transition logic -always @(m1_state - or rx_char_is_enter - or rx_char_is_backspace - or msg_offset - or cmd_ptr - or rs232_tx_load - or char_is_whitespace - or char_is_hex - or char_is_enter - or char_is_i - or char_is_r - or char_is_w - or command - or master_bg_i - or watchdog_timer_done - or err_i - or ack_i - or adr_offset - or qty_sr - or dat_sr - or rd_adr_sr - or rd_field_count - or rd_digit_count - ) -begin : m1_state_logic - - // Default values for outputs. The individual states can override these. - msg_base <= 5'b0; - reset_msg_offset <= 0; - incr_msg_offset <= 0; - rs232_echo <= 0; - rst_o <= 0; - we_l <= 0; - stb_l <= 0; - cmd_buffer_write <= 0; - reset_cmd_ptr <= 0; - incr_cmd_ptr <= 0; - decr_cmd_ptr <= 0; - master_br_o <= 0; - cmd_r <= 0; - cmd_w <= 0; - cmd_i <= 0; - shift_rd_adr <= 0; - store_adr <= 0; // enables storing hex chars in adr_sr (shift) - store_dat <= 0; // enables storing hex chars in dat_sr (shift) - store_qty <= 0; // enables storing hex chars in qty_sr (shift) - reset_adr <= 0; - reset_dat <= 0; - reset_qty <= 0; - init_qty <= 0; - capture_dat <= 0; // enables capturing bus data in dat_sr (load) - incr_adr_offset <= 0; - reset_adr_offset <= 0; - reset_watchdog <= 0; - incr_rd_field_count <= 0; - incr_rd_digit_count <= 0; - reset_rd_field_count <= 0; - reset_rd_digit_count <= 0; - - case (m1_state) // synthesis parallel_case - - m1_initial_state : - begin - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 15) && rs232_tx_load) begin - m1_next_state <= m1_send_prompt; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_initial_state; - end - - m1_send_ok : - begin - msg_base <= 5'b10101; // Address of the OK message - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 1) && rs232_tx_load) begin - m1_next_state <= m1_send_prompt; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_send_ok; - end - - m1_send_prompt : - begin - msg_base <= 5'b10111; // Address of the cr,lf,prompt message - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 4) && rs232_tx_load) begin - m1_next_state <= m1_check_received_char; - reset_cmd_ptr <= 1; - end - else m1_next_state <= m1_send_prompt; - end - - // This state always leads to activating the parser... - m1_send_crlf : - begin - msg_base <= 5'b10111; // Address of the cr/lf message - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 1) && rs232_tx_load) begin - m1_next_state <= m1_scan_command; - reset_cmd_ptr <= 1; - end - else m1_next_state <= m1_send_crlf; - end - - m1_check_received_char : - begin - rs232_echo <= 1; // Allow echoing of characters - if (rx_char_is_backspace && rs232_tx_load) - begin - m1_next_state <= m1_check_received_char; - decr_cmd_ptr <= 1; // This effectively eliminates the last char - end - else if (rx_char_is_enter && rs232_tx_load) - begin - m1_next_state <= m1_send_crlf; - cmd_buffer_write <= 1; // Store the enter as "marker" for parsing - reset_msg_offset <= 1; - end - else if (rs232_tx_load && (cmd_ptr == CMD_BUFFER_SIZE_PP-1)) - begin - m1_next_state <= m1_parse_error_indicator_crlf; - reset_msg_offset <= 1; - reset_cmd_ptr <= 1; - end - else if (rs232_tx_load) - begin - incr_cmd_ptr <= 1; - cmd_buffer_write <= 1; - m1_next_state <= m1_check_received_char; - end - else m1_next_state <= m1_check_received_char; - end - - m1_bg_error_indicator : - begin - msg_base <= 5'b01011; // Address of the B character - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 0) && rs232_tx_load) begin - m1_next_state <= m1_ack_error_indicator; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_bg_error_indicator; - end - - m1_ack_error_indicator : - begin - msg_base <= 5'b10100; // Address of the ! error message - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 0) && rs232_tx_load) begin - m1_next_state <= m1_send_prompt; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_ack_error_indicator; - end - - // This state is used when the line is too long... - m1_parse_error_indicator_crlf : - begin - msg_base <= 5'b10111; // Address of the cr,lf message. - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 1) && rs232_tx_load) begin - m1_next_state <= m1_parse_error_indicator; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_parse_error_indicator_crlf; - end - - m1_parse_error_indicator : - begin - msg_base <= 5'b10011; // Address of the ? message. - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 0) && rs232_tx_load) begin - m1_next_state <= m1_send_prompt; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_parse_error_indicator; - end - - m1_cmd_error_indicator : - begin - msg_base <= 5'b01100; // Address of 'C' - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 0) && rs232_tx_load) begin - m1_next_state <= m1_parse_error_indicator; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_cmd_error_indicator; - end - - m1_adr_error_indicator : - begin - msg_base <= 5'b01010; // Address of 'A' - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 0) && rs232_tx_load) - begin - m1_next_state <= m1_parse_error_indicator; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_adr_error_indicator; - end - - m1_dat_error_indicator : - begin - msg_base <= 5'b01101; // Address of 'D' - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 0) && rs232_tx_load) - begin - m1_next_state <= m1_parse_error_indicator; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_dat_error_indicator; - end - - m1_qty_error_indicator : - begin - msg_base <= 5'b11100; // Address of 'Q' - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 0) && rs232_tx_load) - begin - m1_next_state <= m1_parse_error_indicator; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_qty_error_indicator; - end - - // The following states are for parsing and executing the command. - - // This state takes care of leading whitespace before the command - m1_scan_command : - begin - rs232_echo <= 1; // Don't send message characters - reset_msg_offset <= 1; // This one reset should cover all of the - // parse/exec. states. With rs232_echo - // on, and no receive characters arrive, - // then the msg_offset will remain reset. - // This means the watchdog timer can take - // a long time, if need be, during exec. - // (NOTE: It might be better to disable - // the echoing of rx chars during these - // states.) - init_qty <= 1; // Set qty = 1 by default. That can be - // overridden later, if the command has - // a different qty field. - if (char_is_whitespace) begin - m1_next_state <= m1_scan_command; - incr_cmd_ptr <= 1; - end - else if (char_is_r) begin - m1_next_state <= m1_scan_adr_whitespace; - incr_cmd_ptr <= 1; - cmd_r <= 1; - end - else if (char_is_w) begin - m1_next_state <= m1_scan_adr_whitespace; - incr_cmd_ptr <= 1; - cmd_w <= 1; - end - else if (char_is_i) begin - m1_next_state <= m1_start_execution; - cmd_i <= 1; - end - else m1_next_state <= m1_cmd_error_indicator; - end - - // The only way to determine the end of a valid field is to find - // whitespace. Therefore, char_is_whitespace must be used as an exit - // condition from the "get_xxx_field" states. So, this state is used to - // scan through any leading whitespace prior to it. - m1_scan_adr_whitespace : - begin - rs232_echo <= 1; // Don't send message characters - if (char_is_whitespace) begin - m1_next_state <= m1_scan_adr_whitespace; - incr_cmd_ptr <= 1; - end - else if (char_is_enter) m1_next_state <= m1_start_execution; - else begin - m1_next_state <= m1_get_adr_field; - reset_adr <= 1; - end - end - - m1_get_adr_field : - begin - rs232_echo <= 1; // Don't send message characters - if (char_is_hex) begin - m1_next_state <= m1_get_adr_field; - store_adr <= 1; - incr_cmd_ptr <= 1; - end - else if (char_is_whitespace) begin // Normal exit - m1_next_state <= m1_scan_dat_whitespace; - end - else if (char_is_enter) m1_next_state <= m1_start_execution; - else m1_next_state <= m1_adr_error_indicator; - end - - m1_scan_dat_whitespace : - begin - rs232_echo <= 1; // Don't send message characters - // There is no DAT field for reads, so skip it. - if (command == `CMD_R) m1_next_state <= m1_scan_qty_whitespace; - else if (char_is_whitespace) begin - m1_next_state <= m1_scan_dat_whitespace; - incr_cmd_ptr <= 1; - end - else if (char_is_enter) m1_next_state <= m1_start_execution; - else begin - m1_next_state <= m1_get_dat_field; - reset_dat <= 1; - end - end - - m1_get_dat_field : - begin - rs232_echo <= 1; // Don't send message characters - if (char_is_hex) begin - m1_next_state <= m1_get_dat_field; - store_dat <= 1; - incr_cmd_ptr <= 1; - end - else if (char_is_whitespace) begin // Normal exit - m1_next_state <= m1_scan_qty_whitespace; - end - else if (char_is_enter) m1_next_state <= m1_start_execution; - else m1_next_state <= m1_dat_error_indicator; - end - - m1_scan_qty_whitespace : - begin - rs232_echo <= 1; // Don't send message characters - if (char_is_whitespace) begin - m1_next_state <= m1_scan_qty_whitespace; - incr_cmd_ptr <= 1; - end - else if (char_is_enter) m1_next_state <= m1_start_execution; - else begin - m1_next_state <= m1_get_qty_field; - reset_qty <= 1; - end - end - - m1_get_qty_field : - begin - rs232_echo <= 1; // Don't send message characters - if (char_is_hex) begin - m1_next_state <= m1_get_qty_field; - store_qty <= 1; - incr_cmd_ptr <= 1; - end - else if (char_is_whitespace || char_is_enter) begin // Normal exit - m1_next_state <= m1_start_execution; - end - else m1_next_state <= m1_qty_error_indicator; - end - - // This state seeks to obtain master_bg_i, which grants the bus to - // rs232_syscon. - m1_start_execution : - begin - rs232_echo <= 1; // Don't send message characters - reset_watchdog <= 1; // Reset the timer. - reset_adr_offset <= 1; // Reset the address offset. - reset_rd_field_count <= 1; // Reset the rd_field_count. - m1_next_state <= m1_request_bus; - end - - m1_request_bus : - begin - rs232_echo <= 1; // Don't send message characters - master_br_o <= 1; // Request the bus. - if (master_bg_i) m1_next_state <= m1_bus_granted; - else if (watchdog_timer_done) begin - m1_next_state <= m1_bg_error_indicator; - end - else m1_next_state <= m1_request_bus; - end - - m1_bus_granted : - begin - rs232_echo <= 1; // Don't send message characters - master_br_o <= 1; // Keep holding the bus - reset_watchdog <= 1; // Reset the timer. - if (adr_offset != qty_sr) m1_next_state <= m1_execute; - else m1_next_state <= m1_send_ok; - end - - // This single state does reset/write/read depending upon the value - // contained in "command"! - m1_execute : - begin - rs232_echo <= 1; // Don't send message characters - master_br_o <= 1; // Keep holding the bus - stb_l <= 1'b1; // Show that a bus cycle is happening - case (command) // Assert the appropriate signals - `CMD_I : rst_o <= 1; - `CMD_R : capture_dat <= ack_i; - `CMD_W : we_l <= 1; - default: ; - endcase - if (watchdog_timer_done || err_i) begin - m1_next_state <= m1_ack_error_indicator; - end - else if (ack_i - && (command == `CMD_R) - && (rd_field_count == 0) - ) - begin - m1_next_state <= m1_rd_send_adr_sr; // Leads to a new address line. - reset_rd_digit_count <= 1; - incr_adr_offset <= 1; // move to the next address - end - else if (ack_i && (command == `CMD_R)) begin - m1_next_state <= m1_rd_send_dat_sr; // Leads to a new data field. - reset_rd_digit_count <= 1; - reset_msg_offset <= 1; - incr_adr_offset <= 1; // move to the next address - end - else if (ack_i) begin - m1_next_state <= m1_bus_granted; // continue to the next cycle - incr_adr_offset <= 1; // move to the next address - end - else m1_next_state <= m1_execute; - end - - m1_rd_send_adr_sr : - begin - msg_base <= {1'b0,rd_adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1: - `NIBBLE_SIZE*(ADR_DIGITS_PP-1)]}; - if ((rd_digit_count == ADR_DIGITS_PP-1) && rs232_tx_load) begin - m1_next_state <= m1_rd_send_separator; - reset_msg_offset <= 1; - end - else if (rs232_tx_load) begin - shift_rd_adr <= 1; - incr_rd_digit_count <= 1; - m1_next_state <= m1_rd_send_adr_sr; - end - else m1_next_state <= m1_rd_send_adr_sr; - end - - m1_rd_send_separator : - begin - msg_base <= 5'b10000; // Address of the separator message - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 2) && rs232_tx_load) - begin - m1_next_state <= m1_rd_send_dat_sr; - reset_rd_digit_count <= 1; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_rd_send_separator; - end - - m1_rd_send_dat_sr : - begin - msg_base <= {1'b0,dat_sr[`NIBBLE_SIZE*DAT_DIGITS_PP-1: - `NIBBLE_SIZE*(DAT_DIGITS_PP-1)]}; - if ( - (rd_digit_count == DAT_DIGITS_PP-1) - && (rd_field_count == RD_FIELDS_PP-1) - && rs232_tx_load - ) - begin - m1_next_state <= m1_rd_send_crlf; - reset_rd_field_count <= 1; - end - else if ((rd_digit_count == DAT_DIGITS_PP-1) && rs232_tx_load) begin - m1_next_state <= m1_rd_send_space; - incr_rd_field_count <= 1; - end - else if (rs232_tx_load) begin - store_dat <= 1; - incr_rd_digit_count <= 1; - m1_next_state <= m1_rd_send_dat_sr; - end - else m1_next_state <= m1_rd_send_dat_sr; - end - - m1_rd_send_space : - begin - msg_base <= 5'b10000; // Address of the space - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 0) && rs232_tx_load) begin - m1_next_state <= m1_bus_granted; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_rd_send_space; - end - - m1_rd_send_crlf : - begin - msg_base <= 5'b10111; // Address of the cr/lf message - incr_msg_offset <= rs232_tx_load; - if ((msg_offset == 1) && rs232_tx_load) begin - m1_next_state <= m1_bus_granted; - reset_msg_offset <= 1; - end - else m1_next_state <= m1_rd_send_crlf; - end - - default : m1_next_state <= m1_initial_state; - endcase -end - - -// This is the counter for incrementing or loading the cmd_ptr -always @(posedge clk_i) -begin - if (reset_i || reset_cmd_ptr) cmd_ptr <= 0; - else if (decr_cmd_ptr) cmd_ptr <= cmd_ptr - 1; - else if (incr_cmd_ptr) cmd_ptr <= cmd_ptr + 1; -end - - -// This is the command buffer writing section -always @(posedge clk_i) -begin - if (rs232_echo && cmd_buffer_write) cmd_buffer[cmd_ptr] <= rs232_rx_char; -end -// This is the command buffer reading section -assign cmd_char = cmd_buffer[cmd_ptr]; -assign lc_cmd_char = (cmd_buffer[cmd_ptr] | 8'h20); // lowercase - - - -// These assigments are for detecting whether the cmd_char is -// anything of special interest. -assign char_is_enter = (cmd_char == 8'h0d); // enter -assign char_is_whitespace = ( - (cmd_char == 8'h20) // space - || (cmd_char == 8'h09) // tab - ); -assign char_is_num = ((cmd_char>=8'h30)&&(cmd_char<=8'h39)); -assign char_is_a_f = ((lc_cmd_char>=8'h61)&&(lc_cmd_char<=8'h66)); -assign char_is_hex = ( char_is_num || char_is_a_f ); -assign char_is_r = (lc_cmd_char == 8'h72); // "r" -assign char_is_w = (lc_cmd_char == 8'h77); // "w" -assign char_is_i = (lc_cmd_char == 8'h69); // "i" - -assign hex_digit = char_is_num?cmd_char[3:0]:(cmd_char[3:0]+9); - -// This is the command register. It stores the type of command to execute. -// This is so that the state machine can parse address, data and qty -// into "generic" storage locations, and then when it executes the command, -// it refers back to this register in order to determine what type of -// operation to perform. - -always @(posedge clk_i) -begin - if (reset_i) command <= `CMD_0; - else if (cmd_i) command <= `CMD_I; - else if (cmd_r) command <= `CMD_R; - else if (cmd_w) command <= `CMD_W; -end - -// This is the "nibble" shift register for the address which is sent character -// by character to the user. It is loaded each time the adr_offset is -// incremented, in order to save the previous address for use in printing -// to the user. -always @(posedge clk_i) -begin - if (reset_i || reset_adr) rd_adr_sr <= 0; - else if (incr_adr_offset) rd_adr_sr <= adr_ptr; - else if (shift_rd_adr) begin - rd_adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1:`NIBBLE_SIZE] <= - rd_adr_sr[`NIBBLE_SIZE*(ADR_DIGITS_PP-1)-1:0]; - rd_adr_sr[`NIBBLE_SIZE-1:0] <= {`NIBBLE_SIZE{1'b0}}; - end -end - -// These are the "nibble" shift registers. They handle loading the -// hexadecimal digits from the command line. -always @(posedge clk_i) -begin - if (reset_i || reset_adr) adr_sr <= 0; - else if (store_adr) begin - adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1:`NIBBLE_SIZE] <= - adr_sr[`NIBBLE_SIZE*(ADR_DIGITS_PP-1)-1:0]; - adr_sr[`NIBBLE_SIZE-1:0] <= hex_digit; - end -end - -always @(posedge clk_i) -begin - if (reset_i || reset_dat) dat_sr <= 0; - else if (capture_dat) dat_sr <= dat_io; - else if (store_dat) begin - dat_sr[`NIBBLE_SIZE*DAT_DIGITS_PP-1:`NIBBLE_SIZE] <= - dat_sr[`NIBBLE_SIZE*(DAT_DIGITS_PP-1)-1:0]; - dat_sr[`NIBBLE_SIZE-1:0] <= hex_digit; - end -end - -always @(posedge clk_i) -begin - if (reset_i || reset_qty) qty_sr <= 0; - else if (init_qty) qty_sr <= 1; - else if (store_qty) begin - qty_sr[`NIBBLE_SIZE*QTY_DIGITS_PP-1:`NIBBLE_SIZE] <= - qty_sr[`NIBBLE_SIZE*(QTY_DIGITS_PP-1)-1:0]; - qty_sr[`NIBBLE_SIZE-1:0] <= hex_digit; - end -end - -// This is the rd_digit_count counter. It is used for counting digits -// displayed of both the adr_sr and dat_sr, so it must be able to count up -// to the extent of the larger of the two... -always @(posedge clk_i) -begin - if (reset_i || reset_rd_digit_count) rd_digit_count <= 0; - else if (incr_rd_digit_count) rd_digit_count <= rd_digit_count + 1; -end - -// This is the rd_field_count counter. It is used for counting dat_sr fields -// displayed per line. -always @(posedge clk_i) -begin - if (reset_i || reset_rd_field_count) rd_field_count <= 0; - else if (incr_rd_field_count) rd_field_count <= rd_field_count + 1; -end - - -// This is the watchdog timer counter -// The watchdog timer is always "enabled" to operate. -always @(posedge clk_i) -begin - if (reset_i || reset_watchdog) watchdog_timer_count <= 0; - else if (~watchdog_timer_done) - watchdog_timer_count <= watchdog_timer_count + 1; -end -assign watchdog_timer_done = (watchdog_timer_count==WATCHDOG_TIMER_VALUE_PP); - - -endmodule - - Index: trunk/rs232_syscon.doc =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: trunk/rs232_syscon.doc =================================================================== --- trunk/rs232_syscon.doc (revision 3) +++ trunk/rs232_syscon.doc (nonexistent)
trunk/rs232_syscon.doc Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: trunk/b13c_environment.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: trunk/b13c_environment.zip =================================================================== --- trunk/b13c_environment.zip (revision 3) +++ trunk/b13c_environment.zip (nonexistent)
trunk/b13c_environment.zip Property changes : Deleted: svn:mime-type ## -1 +0,0 ## -application/octet-stream \ No newline at end of property Index: rs232_syscon/trunk/b13c_environment.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rs232_syscon/trunk/b13c_environment.zip =================================================================== --- rs232_syscon/trunk/b13c_environment.zip (nonexistent) +++ rs232_syscon/trunk/b13c_environment.zip (revision 4)
rs232_syscon/trunk/b13c_environment.zip Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rs232_syscon/trunk/rs232_syscon.doc =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rs232_syscon/trunk/rs232_syscon.doc =================================================================== --- rs232_syscon/trunk/rs232_syscon.doc (nonexistent) +++ rs232_syscon/trunk/rs232_syscon.doc (revision 4)
rs232_syscon/trunk/rs232_syscon.doc Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rs232_syscon/trunk/rs232_syscon.v =================================================================== --- rs232_syscon/trunk/rs232_syscon.v (nonexistent) +++ rs232_syscon/trunk/rs232_syscon.v (revision 4) @@ -0,0 +1,1168 @@ +//------------------------------------------------------------------------------------- +// +// Author: John Clayton +// Date : June 25, 2001 +// Update: 6/25/01 copied this file from ps2_mouse.v (pared down). +// Update: 6/07/01 Finished initial coding efforts. +// Update: 7/19/01 First compilation. Added master_br_o and master_bg_i; +// Update: 7/25/01 Testing. Eliminated msg_active signal. Changed serial.v +// to reflect new handshaking (i.e. "load_request" is now a +// periodic pulse of tx_clk_1x from rs232_tx...) +// Update: 7/30/01 Began coding m2 state machine. Defined response codes. +// Update: 8/01/01 After some testing with m2, merged m2 into m1. Eliminated +// response codes. +// Update: 8/02/01 Tested & measured the single "combined" state machine's +// performance, and "it was found wanting." (The 49.152MHz +// clock frequency was too fast for it...) Created clk_s +// at 49.152/2 MHz, and this worked. +// Update: 8/03/01 Added counter loop to "execute" and "bus_granted" states +// so that multiple bus cycles are generated, at sequential +// addresses. However, the qty field is not cleared before +// being loaded with new characters, which causes problems. +// Update: 8/07/01 Finished debugging. The read print formatting is now +// correct, and the unit appears to operate correctly. +// Many hours were spent puzzling over how to make this work. +// Removed port "debug". +// Update: 8/24/01 Added "master_stb_i" and "master_we_i" inputs and logic. +// Update: 12/13/01 For memory_sizer.v, I lowered the frequency of clk_s down +// to 49.152/4 MHz, so I changed the CLOCK_FACTOR from 8 to 4 +// on the rs232 transciever, and this worked fine. +// Update: 9/09/02 Incorporated the "autobaud_with_tracking" module so that +// the serial clock is generated automatically, no matter +// what frequency clk_i is used. The user simply needs to +// press "enter" from the terminal program to synchronize +// the baud rate generator. Changing BAUD rates on the fly +// is also permitted, simply change to a new BAUD rate in the +// terminal program and hit enter. +// Update:11/26/02 Changed the string constants to binary representation +// (Just to eliminate warnings in XST.) +// +// +// +// +// +// Description +//------------------------------------------------------------------------------------- +// This is a state-machine driven rs232 serial port interface to a "Wishbone" +// type of bus. It is intended to be used as a "Wishbone system controller" +// for debugging purposes. Specifically, the unit allows the user to send +// text commands to the "rs232_syscon" unit, in order to generate read and +// write cycles on the Wishbone compatible bus. The command structure is +// quite terse and spartan in nature, this is for the sake of the logic itself. +// Because the menu-driven command structure is supported without the use of +// dedicated memory blocks (in order to maintain cross-platform portability +// as much as possible) the menus and command responses were kept as small +// as possible. In most cases, the responses from the unit to the user +// consist of a "newline" and one or two visible characters. The command +// structure consists of the following commands and responses: +// +// Command Syntax Purpose +// --------------- --------------------------------------- +// w aaaa dddd xx Write data "dddd" starting at address "aaaa" +// perform this "xx" times at sequential addresses. +// (The quantity field is optional, default is 1). +// r aaaa xx Read data starting from address "aaaa." +// Perform this "xx" times at sequential addresses. +// (The quantity field is optional, default is 1). +// i Send a reset pulse to the system. (initialize). +// +// Response from rs232_syscon Meaning +// -------------------------- --------------------------------------- +// OK Command received and performed. No errors. +// ? Command buffer full, without receiving "enter." +// C? Command not recognized. +// A? Address field syntax error. +// D? Data field syntax error. +// Q? Quantity field syntax error. +// ! No "ack_i", or else "err_i" received from bus. +// B! No "bg_i" received from master. +// +// NOTES on the operation of this unit: +// +// - The unit generates a command prompt which is "-> ". +// - Capitalization is not important. +// - Each command is terminated by the "enter" key (0x0d character). +// Commands are executed as soon as "enter" is received. +// - Trailing parameters need not be re-entered. Their values will +// remain the same as their previous settings. +// - Use of the backspace key is supported, so mistakes can be corrected. +// - The length of the command line is limited to a fixed number of +// characters, as configured by parameter. +// - Fields are separated by white space, including "tab" and/or "space" +// - All numerical fields are interpreted as hexadecimal numbers. +// Decimal is not supported. +// - Numerical field values are retained between commands. If a "r" is issued +// without any fields following it, the previous values will be used. A +// set of "quantity" reads will take place at sequential addresses. +// If a "w" is issued without any fields following it, the previous data +// value will be written "quantity" times at sequential addresses, starting +// from the next location beyond where the last command ended. +// - If the user does not wish to use "ack" functionality, simply tie the +// "ack_i" input to 1b'1, and then the ! response will never be generated. +// - The data which is read in by the "r" command is displayed using lines +// which begin with the address, followed by the data fields. The number +// of data fields displayed per line (following the address) is adjustable +// by setting a parameter. No other display format adjustments can be made. +// - There is currently only a single watchdog timer. It begins to count at +// the time a user hits "enter" to execute a command. If the bus is granted +// and the ack is received before the expiration of the timer, then the +// cycle will complete normally. Therefore, the watchdog timeout value +// needs to include time for the request and granting of the bus, in +// addition to the time needed for the actual bus cycle to complete. +// +// +// Currently, there is only a single indicator (stb_o) generated during bus +// output cycles which are generated from this unit. +// The user can easily implement decoding logic based upon adr_o and stb_o +// which would serve as multiple "stb_o" type signals for different cores +// which would be sharing the same bus. +// +// The dat_io bus supported by this module is a tri-state type of bus. The +// Wishbone spec. allows for this type of bus (see Wishbone spec. pg. 66). +// However, if separate dat_o and dat_i busses are desired, they can be added +// to the module without too much trouble. Supposedly the only difference +// between the two forms of data bus is that one of them avoids using tri-state +// at the cost of doubling the number of interconnects used to carry data back +// and forth... Some people say that tri-state should be avoided for use +// in internal busses in ASICs. Maybe they are right. +// But in FPGAs tri-state seems to work pretty well, even for internal busses. +// +// Parameters are provided to configure the width of the different command +// fields. To simplify the logic for binary to hexadecimal conversion, these +// parameters allow adjustment in units of 1 hex digit, not anything smaller. +// If your bus has 10 bits, for instance, simply set the address width to 3 +// which produces 12 bits, and then just don't use the 2 msbs of address +// output. +// +// No support for the optional Wishbone "retry" (rty_i) input is provided at +// this time. +// No support for "tagn_o" bits is provided at this time, although a register +// might be added external to this module in order to implement to tag bits. +// No BLOCK or RMW cycles are supported currently, so cyc_o is equivalent to +// stb_o... +// The output busses are not tri-stated. The user may add tri-state buffers +// external to the module, using "stb_o" to enable the buffer outputs. +// +//------------------------------------------------------------------------------------- + + +`define NIBBLE_SIZE 4 // Number of bits in one nibble + +// The command register has these values +`define CMD_0 0 // Unused command +`define CMD_I 1 // Initialize (or reset) +`define CMD_R 2 // Read +`define CMD_W 3 // Write + +module rs232_syscon ( + clk_i, + reset_i, + ack_i, + err_i, + master_bg_i, + master_adr_i, + master_stb_i, + master_we_i, + rs232_rxd_i, + dat_io, + rst_o, + master_br_o, + stb_o, + cyc_o, + adr_o, + we_o, + rs232_txd_o + ); + + +// Parameters + +// The timer value can be from [0 to (2^WATCHDOG_TIMER_BITS_PP)-1] inclusive. +// RD_FIELDS_PP can be from [0 to (2^RD_FIELD_CTR_BITS_PP)-1] inclusive. +// Ensure that (2^CHAR_COUNT_BITS_PP) >= CMD_BUFFER_SIZE_PP. +// The setting of CMD_BUFFER_SIZE_PP should be large enough to hold the +// largest command, obviously. +// Ensure that (2^RD_DIGIT_COUNT_BITS_PP) is greater than or equal to the +// larger of {ADR_DIGITS_PP,DAT_DIGITS_PP}. +parameter ADR_DIGITS_PP = 4; // # of hex digits for address. +parameter DAT_DIGITS_PP = 4; // # of hex digits for data. +parameter QTY_DIGITS_PP = 2; // # of hex digits for quantity. +parameter CMD_BUFFER_SIZE_PP = 32; // # of chars in the command buffer. +parameter CMD_PTR_BITS_PP = 4; // # of Bits in command buffer ptr. +parameter WATCHDOG_TIMER_VALUE_PP = 200; // # of sys_clks before ack expected. +parameter WATCHDOG_TIMER_BITS_PP = 8; // # of bits needed for timer. +parameter RD_FIELDS_PP = 8; // # of fields/line (when qty > 1). +parameter RD_FIELD_COUNT_BITS_PP = 3; // # of bits in the fields counter. +parameter RD_DIGIT_COUNT_BITS_PP = 2; // # of bits in the digits counter. + + +// State encodings, provided as parameters +// for flexibility to the one instantiating the module. +// In general, the default values need not be changed. + +// There is one state machines: m1. +// "default" state upon power-up and configuration is: +// "m1_initial_state" + +parameter m1_initial_state = 5'h00; +parameter m1_send_ok = 5'h01; // Sends OK +parameter m1_send_prompt = 5'h02; // Sends "-> " +parameter m1_check_received_char = 5'h03; +parameter m1_send_crlf = 5'h04; // Sends cr,lf +parameter m1_parse_error_indicator_crlf = 5'h05; // Sends cr,lf +parameter m1_parse_error_indicator = 5'h06; // Sends ? +parameter m1_ack_error_indicator = 5'h07; // Sends ! +parameter m1_bg_error_indicator = 5'h08; // Sends B! +parameter m1_cmd_error_indicator = 5'h09; // Sends C? +parameter m1_adr_error_indicator = 5'h0a; // Sends A? +parameter m1_dat_error_indicator = 5'h0b; // Sends D? +parameter m1_qty_error_indicator = 5'h0c; // Sends Q? +parameter m1_scan_command = 5'h10; +parameter m1_scan_adr_whitespace = 5'h11; +parameter m1_get_adr_field = 5'h12; +parameter m1_scan_dat_whitespace = 5'h13; +parameter m1_get_dat_field = 5'h14; +parameter m1_scan_qty_whitespace = 5'h15; +parameter m1_get_qty_field = 5'h16; +parameter m1_start_execution = 5'h17; +parameter m1_request_bus = 5'h18; +parameter m1_bus_granted = 5'h19; +parameter m1_execute = 5'h1a; +parameter m1_rd_send_adr_sr = 5'h1b; +parameter m1_rd_send_separator = 5'h1c; +parameter m1_rd_send_dat_sr = 5'h1d; +parameter m1_rd_send_space = 5'h1e; +parameter m1_rd_send_crlf = 5'h1f; + +// I/O declarations +input clk_i; // System clock input +input reset_i; // Reset signal for this module +input ack_i; // Ack input from Wishbone "slaves" +input err_i; // Err input from Wishbone "slaves" +input master_bg_i; // Bus Grant (grants this module the bus) + // Address bus input from "normal" Wishbone + // master (i.e. from processor) +input [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] master_adr_i; +input master_stb_i; // bus cycle signal from "normal" bus master +input master_we_i; // write enable from "normal" bus master +input rs232_rxd_i; // Serial data from debug host terminal. + // Data bus (tri-state, to save interconnect) +inout [`NIBBLE_SIZE*DAT_DIGITS_PP-1:0] dat_io; + +output rst_o; // Rst output to Wishbone "slaves" +output master_br_o; // Bus request to normal master device. +output stb_o; // Bus cycle indicator to Wishbone "slaves" +output cyc_o; // Bus cycle indicator to Wishbone "slaves" + // Address bus output to Wishbone "slaves" +output [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_o; +output we_o; // Write enable to Wishbone "slaves" +output rs232_txd_o; // Serial transmit data to debug host terminal + +reg rst_o; +reg master_br_o; + +// Internal signal declarations +wire watchdog_timer_done; // High when watchdog timer is expired +wire rd_addr_field_done; // High when displayed addr field is complete +wire rd_data_field_done; // High when displayed data field is complete +wire rd_line_done; // High when displayed line is complete +wire char_is_enter; // High when cmd_buffer[char_count] is enter. +wire char_is_whitespace; // High when cmd_buffer[char_count] is whitespace. +wire char_is_num; // High when cmd_buffer[char_count] is 0..9 +wire char_is_a_f; // High when cmd_buffer[char_count] is a..f +wire char_is_hex; // High when cmd_buffer[char_count] is a hex char. +wire char_is_r; // High when cmd_buffer[char_count] is r. +wire char_is_w; // High when cmd_buffer[char_count] is w. +wire char_is_i; // High when cmd_buffer[char_count] is i. +wire rx_char_is_enter; // High when rs232_rx_char is enter. +wire rx_char_is_backspace; // High when rs232_rx_char is backspace. +wire [4:0] msg_pointer; // Determines message position or address. +wire [3:0] hex_digit; // This is the digit to be stored. + +reg rs232_echo; // High == echo char's received. +reg [7:0] msg_char; // Selected response message character. +reg [4:0] msg_base; // Added to msg_offset to form msg_pointer. +reg [4:0] msg_offset; // Offset from start of message. +reg reset_msg_offset; // High == set message offset to zero +reg incr_msg_offset; // Used for output messages. +reg cmd_i; // Sets command. +reg cmd_r; // Sets command. +reg cmd_w; // Sets command. +reg shift_rd_adr; // Shifts the rd_adr_sr by one character. +reg store_adr; // Allows adr_sr to store hex_digit. +reg store_dat; // Allows dat_sr to store hex_digit. +reg store_qty; // Allows qty_sr to store hex_digit. +reg reset_adr; // Clears adr_sr +reg reset_dat; // Clears dat_sr +reg reset_qty; // Clears qty_sr +reg init_qty; // Sets qty_sr to 1 +reg capture_dat; // Puts dat_io into dat_sr for later display. + + // For the buses +wire [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_ptr; // = adr_sr + adr_offset + +reg stb_l; // "local" stb signal (to distinguish from stb_o) +reg we_l; // "local" we signal (to distinguish from we_o) + +reg [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] rd_adr_sr; // sr for printing addresses +reg [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_sr; // "nibble" shift register +reg [`NIBBLE_SIZE*DAT_DIGITS_PP-1:0] dat_sr; // "nibble" shift register +reg [`NIBBLE_SIZE*QTY_DIGITS_PP-1:0] qty_sr; // "nibble" shift register +reg [1:0] command; +reg [`NIBBLE_SIZE*QTY_DIGITS_PP-1:0] adr_offset; // counts from 0 to qty_sr +reg reset_adr_offset; +reg incr_adr_offset; + + // For the command buffer +reg [CMD_PTR_BITS_PP-1:0] cmd_ptr; // Offset from start of command. +reg reset_cmd_ptr; // High == set command pointer to zero. +reg incr_cmd_ptr; // Used for "write port" side of the command buffer +reg decr_cmd_ptr; // Used for "write port" side of the command buffer +reg cmd_buffer_write; +reg [7:0] cmd_buffer [0:CMD_BUFFER_SIZE_PP-1]; +wire [7:0] cmd_char; +wire [7:0] lc_cmd_char; // Lowercase version of cmd_char + + // For the state machine +reg [4:0] m1_state; +reg [4:0] m1_next_state; + + // For various counters +reg reset_rd_field_count; +reg reset_rd_digit_count; +reg incr_rd_field_count; +reg incr_rd_digit_count; +reg [RD_FIELD_COUNT_BITS_PP-1:0] rd_field_count; // "fields displayed" +reg [RD_DIGIT_COUNT_BITS_PP-1:0] rd_digit_count; // "digits displayed" +reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_timer_count; +reg reset_watchdog; + + // For the rs232 interface +wire serial_clk; +wire [2:0] rs232_rx_error; +wire rs232_tx_load; +wire rs232_tx_load_request; +wire rs232_rx_data_ready; +wire [7:0] rs232_rx_char; +wire [7:0] rs232_tx_char; // Either rs232_rx_char or msg_char + +//-------------------------------------------------------------------------- +// Instantiations +//-------------------------------------------------------------------------- + + +// These defines are for the rs232 interface +`define START_BITS 1 +`define DATA_BITS 8 +`define STOP_BITS 1 +`define CLOCK_FACTOR 8 + +// This module generates a serial BAUD clock automatically. +// The unit synchronizes on the carriage return character, so the user +// only needs to press the "enter" key for serial communications to start +// working, no matter what BAUD rate and clk_i frequency are used! +auto_baud_with_tracking #( + `CLOCK_FACTOR, // CLOCK_FACTOR_PP + 16 // LOG2_MAX_COUNT_PP + ) + clock_unit_2 + ( + .clk_i(clk_i), + .reset_i(reset_i), + .serial_dat_i(rs232_rxd_i), + .auto_baud_locked_o(), + .baud_clk_o(serial_clk) + ); + +// A transmitter, which asserts load_request at the end of the currently +// transmitted word. The tx_clk must be a "clock enable" (narrow positive +// pulse) which occurs at 16x the desired transmit rate. If load_request +// is connected directly to load, the unit will transmit continuously. +rs232tx #( + `START_BITS, // start_bits + `DATA_BITS, // data_bits + `STOP_BITS, // stop_bits (add intercharacter delay...) + `CLOCK_FACTOR // clock_factor + ) + rs232_tx_block // instance name + ( + .clk(clk_i), + .tx_clk(serial_clk), + .reset(reset_i), + .load(rs232_tx_load), + .data(rs232_tx_char), + .load_request(rs232_tx_load_request), + .txd(rs232_txd_o) + ); + +// A receiver, which asserts "word_ready" to indicate a received word. +// Asserting "read_word" will cause "word_ready" to go low again if it was high. +// The character is held in the output register, during the time the next +// character is coming in. +rs232rx #( + `START_BITS, // start_bits + `DATA_BITS, // data_bits + `STOP_BITS, // stop_bits + `CLOCK_FACTOR // clock_factor + ) + rs232_rx_block // instance name + ( + .clk(clk_i), + .rx_clk(serial_clk), + .reset(reset_i || (| rs232_rx_error)), + .rxd(rs232_rxd_i), + .read(rs232_tx_load), + .data(rs232_rx_char), + .data_ready(rs232_rx_data_ready), + .error_over_run(rs232_rx_error[0]), + .error_under_run(rs232_rx_error[1]), + .error_all_low(rs232_rx_error[2]) + ); + +//`undef START_BITS +//`undef DATA_BITS +//`undef STOP_BITS +//`undef CLOCK_FACTOR + + +//-------------------------------------------------------------------------- +// Module code +//-------------------------------------------------------------------------- + +assign adr_o = master_bg_i?adr_ptr:master_adr_i; +assign we_o = master_bg_i?we_l:master_we_i; +assign stb_o = master_bg_i?stb_l:master_stb_i; + + +assign dat_io = (master_bg_i && we_l && stb_l)? + dat_sr:{`NIBBLE_SIZE*DAT_DIGITS_PP{1'bZ}}; + +// Temporary +assign cyc_o = stb_o; // Separate cyc_o is not yet supported! + + +// This is the adress offset counter +always @(posedge clk_i) +begin + if (reset_i || reset_adr_offset) adr_offset <= 0; + else if (incr_adr_offset) adr_offset <= adr_offset + 1; +end +// This forms the adress pointer which is used on the bus. +assign adr_ptr = adr_sr + adr_offset; + + +// This is the ROM for the ASCII characters to be transmitted. +always @(msg_pointer) +begin + case (msg_pointer) // synthesis parallel_case + 5'b00000 : msg_char <= 8'h30; // "0"; // Hexadecimal characters + 5'b00001 : msg_char <= 8'h31; // "1"; + 5'b00010 : msg_char <= 8'h32; // "2"; + 5'b00011 : msg_char <= 8'h33; // "3"; + 5'b00100 : msg_char <= 8'h34; // "4"; + 5'b00101 : msg_char <= 8'h35; // "5"; + 5'b00110 : msg_char <= 8'h36; // "6"; + 5'b00111 : msg_char <= 8'h37; // "7"; + 5'b01000 : msg_char <= 8'h38; // "8"; + 5'b01001 : msg_char <= 8'h39; // "9"; + 5'b01010 : msg_char <= 8'h41; // "A"; // Address error indication + 5'b01011 : msg_char <= 8'h42; // "B"; + 5'b01100 : msg_char <= 8'h43; // "C"; // Command error indication + 5'b01101 : msg_char <= 8'h44; // "D"; // Data error indication + 5'b01110 : msg_char <= 8'h45; // "E"; + 5'b01111 : msg_char <= 8'h46; // "F"; + 5'b10000 : msg_char <= 8'h20; // " "; // Space + 5'b10001 : msg_char <= 8'h3A; // ":"; // Colon + 5'b10010 : msg_char <= 8'h20; // " "; // Space + 5'b10011 : msg_char <= 8'h3F; // "?"; // Parse error indication + 5'b10100 : msg_char <= 8'h21; // "!"; // ack_i/err_i error indication + 5'b10101 : msg_char <= 8'h4F; // "O"; // "All is well" message + 5'b10110 : msg_char <= 8'h4B; // "K"; + 5'b10111 : msg_char <= 8'h0D; // Carriage return & line feed + 5'b11000 : msg_char <= 8'h0A; + 5'b11001 : msg_char <= 8'h2D; // "-"; // Command Prompt + 5'b11010 : msg_char <= 8'h3E; // ">"; + 5'b11011 : msg_char <= 8'h20; // " "; + 5'b11100 : msg_char <= 8'h51; // "Q"; // Quantity error indication + default : msg_char <= 8'h3D; // "="; + endcase +end + +// This logic determines when to load a transmit character. +assign rs232_tx_load = rs232_echo? + (rs232_rx_data_ready && rs232_tx_load_request):rs232_tx_load_request; + +// This is the counter for incrementing, decrementing or resetting the +// message pointer. +always @(posedge clk_i) +begin + if (reset_i || reset_msg_offset) msg_offset <= 0; + else if (incr_msg_offset) msg_offset <= msg_offset + 1; +end +assign msg_pointer = msg_offset + msg_base; + + + +// This is the mux which selects whether to echo back the characters +// received (as during the entering of a command) or to send back response +// characters. +assign rs232_tx_char = (rs232_echo)?rs232_rx_char:msg_char; + + +// These assigments are for detecting whether the received rs232 character is +// anything of special interest. +assign rx_char_is_enter = (rs232_rx_char == 8'h0d); +assign rx_char_is_backspace = (rs232_rx_char == 8'h08); + + + +// This is state machine m1. It handles receiving the command line, including +// backspaces, and prints error/response messages. It also parses and +// executes the commands. + +// State register +always @(posedge clk_i) +begin : m1_state_register + if (reset_i) m1_state <= m1_initial_state; // perform reset for rest of system + else m1_state <= m1_next_state; +end + +// State transition logic +always @(m1_state + or rx_char_is_enter + or rx_char_is_backspace + or msg_offset + or cmd_ptr + or rs232_tx_load + or char_is_whitespace + or char_is_hex + or char_is_enter + or char_is_i + or char_is_r + or char_is_w + or command + or master_bg_i + or watchdog_timer_done + or err_i + or ack_i + or adr_offset + or qty_sr + or dat_sr + or rd_adr_sr + or rd_field_count + or rd_digit_count + ) +begin : m1_state_logic + + // Default values for outputs. The individual states can override these. + msg_base <= 5'b0; + reset_msg_offset <= 0; + incr_msg_offset <= 0; + rs232_echo <= 0; + rst_o <= 0; + we_l <= 0; + stb_l <= 0; + cmd_buffer_write <= 0; + reset_cmd_ptr <= 0; + incr_cmd_ptr <= 0; + decr_cmd_ptr <= 0; + master_br_o <= 0; + cmd_r <= 0; + cmd_w <= 0; + cmd_i <= 0; + shift_rd_adr <= 0; + store_adr <= 0; // enables storing hex chars in adr_sr (shift) + store_dat <= 0; // enables storing hex chars in dat_sr (shift) + store_qty <= 0; // enables storing hex chars in qty_sr (shift) + reset_adr <= 0; + reset_dat <= 0; + reset_qty <= 0; + init_qty <= 0; + capture_dat <= 0; // enables capturing bus data in dat_sr (load) + incr_adr_offset <= 0; + reset_adr_offset <= 0; + reset_watchdog <= 0; + incr_rd_field_count <= 0; + incr_rd_digit_count <= 0; + reset_rd_field_count <= 0; + reset_rd_digit_count <= 0; + + case (m1_state) // synthesis parallel_case + + m1_initial_state : + begin + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 15) && rs232_tx_load) begin + m1_next_state <= m1_send_prompt; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_initial_state; + end + + m1_send_ok : + begin + msg_base <= 5'b10101; // Address of the OK message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 1) && rs232_tx_load) begin + m1_next_state <= m1_send_prompt; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_send_ok; + end + + m1_send_prompt : + begin + msg_base <= 5'b10111; // Address of the cr,lf,prompt message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 4) && rs232_tx_load) begin + m1_next_state <= m1_check_received_char; + reset_cmd_ptr <= 1; + end + else m1_next_state <= m1_send_prompt; + end + + // This state always leads to activating the parser... + m1_send_crlf : + begin + msg_base <= 5'b10111; // Address of the cr/lf message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 1) && rs232_tx_load) begin + m1_next_state <= m1_scan_command; + reset_cmd_ptr <= 1; + end + else m1_next_state <= m1_send_crlf; + end + + m1_check_received_char : + begin + rs232_echo <= 1; // Allow echoing of characters + if (rx_char_is_backspace && rs232_tx_load) + begin + m1_next_state <= m1_check_received_char; + decr_cmd_ptr <= 1; // This effectively eliminates the last char + end + else if (rx_char_is_enter && rs232_tx_load) + begin + m1_next_state <= m1_send_crlf; + cmd_buffer_write <= 1; // Store the enter as "marker" for parsing + reset_msg_offset <= 1; + end + else if (rs232_tx_load && (cmd_ptr == CMD_BUFFER_SIZE_PP-1)) + begin + m1_next_state <= m1_parse_error_indicator_crlf; + reset_msg_offset <= 1; + reset_cmd_ptr <= 1; + end + else if (rs232_tx_load) + begin + incr_cmd_ptr <= 1; + cmd_buffer_write <= 1; + m1_next_state <= m1_check_received_char; + end + else m1_next_state <= m1_check_received_char; + end + + m1_bg_error_indicator : + begin + msg_base <= 5'b01011; // Address of the B character + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_ack_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_bg_error_indicator; + end + + m1_ack_error_indicator : + begin + msg_base <= 5'b10100; // Address of the ! error message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_send_prompt; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_ack_error_indicator; + end + + // This state is used when the line is too long... + m1_parse_error_indicator_crlf : + begin + msg_base <= 5'b10111; // Address of the cr,lf message. + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 1) && rs232_tx_load) begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_parse_error_indicator_crlf; + end + + m1_parse_error_indicator : + begin + msg_base <= 5'b10011; // Address of the ? message. + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_send_prompt; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_parse_error_indicator; + end + + m1_cmd_error_indicator : + begin + msg_base <= 5'b01100; // Address of 'C' + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_cmd_error_indicator; + end + + m1_adr_error_indicator : + begin + msg_base <= 5'b01010; // Address of 'A' + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) + begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_adr_error_indicator; + end + + m1_dat_error_indicator : + begin + msg_base <= 5'b01101; // Address of 'D' + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) + begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_dat_error_indicator; + end + + m1_qty_error_indicator : + begin + msg_base <= 5'b11100; // Address of 'Q' + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) + begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_qty_error_indicator; + end + + // The following states are for parsing and executing the command. + + // This state takes care of leading whitespace before the command + m1_scan_command : + begin + rs232_echo <= 1; // Don't send message characters + reset_msg_offset <= 1; // This one reset should cover all of the + // parse/exec. states. With rs232_echo + // on, and no receive characters arrive, + // then the msg_offset will remain reset. + // This means the watchdog timer can take + // a long time, if need be, during exec. + // (NOTE: It might be better to disable + // the echoing of rx chars during these + // states.) + init_qty <= 1; // Set qty = 1 by default. That can be + // overridden later, if the command has + // a different qty field. + if (char_is_whitespace) begin + m1_next_state <= m1_scan_command; + incr_cmd_ptr <= 1; + end + else if (char_is_r) begin + m1_next_state <= m1_scan_adr_whitespace; + incr_cmd_ptr <= 1; + cmd_r <= 1; + end + else if (char_is_w) begin + m1_next_state <= m1_scan_adr_whitespace; + incr_cmd_ptr <= 1; + cmd_w <= 1; + end + else if (char_is_i) begin + m1_next_state <= m1_start_execution; + cmd_i <= 1; + end + else m1_next_state <= m1_cmd_error_indicator; + end + + // The only way to determine the end of a valid field is to find + // whitespace. Therefore, char_is_whitespace must be used as an exit + // condition from the "get_xxx_field" states. So, this state is used to + // scan through any leading whitespace prior to it. + m1_scan_adr_whitespace : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_whitespace) begin + m1_next_state <= m1_scan_adr_whitespace; + incr_cmd_ptr <= 1; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else begin + m1_next_state <= m1_get_adr_field; + reset_adr <= 1; + end + end + + m1_get_adr_field : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_hex) begin + m1_next_state <= m1_get_adr_field; + store_adr <= 1; + incr_cmd_ptr <= 1; + end + else if (char_is_whitespace) begin // Normal exit + m1_next_state <= m1_scan_dat_whitespace; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else m1_next_state <= m1_adr_error_indicator; + end + + m1_scan_dat_whitespace : + begin + rs232_echo <= 1; // Don't send message characters + // There is no DAT field for reads, so skip it. + if (command == `CMD_R) m1_next_state <= m1_scan_qty_whitespace; + else if (char_is_whitespace) begin + m1_next_state <= m1_scan_dat_whitespace; + incr_cmd_ptr <= 1; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else begin + m1_next_state <= m1_get_dat_field; + reset_dat <= 1; + end + end + + m1_get_dat_field : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_hex) begin + m1_next_state <= m1_get_dat_field; + store_dat <= 1; + incr_cmd_ptr <= 1; + end + else if (char_is_whitespace) begin // Normal exit + m1_next_state <= m1_scan_qty_whitespace; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else m1_next_state <= m1_dat_error_indicator; + end + + m1_scan_qty_whitespace : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_whitespace) begin + m1_next_state <= m1_scan_qty_whitespace; + incr_cmd_ptr <= 1; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else begin + m1_next_state <= m1_get_qty_field; + reset_qty <= 1; + end + end + + m1_get_qty_field : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_hex) begin + m1_next_state <= m1_get_qty_field; + store_qty <= 1; + incr_cmd_ptr <= 1; + end + else if (char_is_whitespace || char_is_enter) begin // Normal exit + m1_next_state <= m1_start_execution; + end + else m1_next_state <= m1_qty_error_indicator; + end + + // This state seeks to obtain master_bg_i, which grants the bus to + // rs232_syscon. + m1_start_execution : + begin + rs232_echo <= 1; // Don't send message characters + reset_watchdog <= 1; // Reset the timer. + reset_adr_offset <= 1; // Reset the address offset. + reset_rd_field_count <= 1; // Reset the rd_field_count. + m1_next_state <= m1_request_bus; + end + + m1_request_bus : + begin + rs232_echo <= 1; // Don't send message characters + master_br_o <= 1; // Request the bus. + if (master_bg_i) m1_next_state <= m1_bus_granted; + else if (watchdog_timer_done) begin + m1_next_state <= m1_bg_error_indicator; + end + else m1_next_state <= m1_request_bus; + end + + m1_bus_granted : + begin + rs232_echo <= 1; // Don't send message characters + master_br_o <= 1; // Keep holding the bus + reset_watchdog <= 1; // Reset the timer. + if (adr_offset != qty_sr) m1_next_state <= m1_execute; + else m1_next_state <= m1_send_ok; + end + + // This single state does reset/write/read depending upon the value + // contained in "command"! + m1_execute : + begin + rs232_echo <= 1; // Don't send message characters + master_br_o <= 1; // Keep holding the bus + stb_l <= 1'b1; // Show that a bus cycle is happening + case (command) // Assert the appropriate signals + `CMD_I : rst_o <= 1; + `CMD_R : capture_dat <= ack_i; + `CMD_W : we_l <= 1; + default: ; + endcase + if (watchdog_timer_done || err_i) begin + m1_next_state <= m1_ack_error_indicator; + end + else if (ack_i + && (command == `CMD_R) + && (rd_field_count == 0) + ) + begin + m1_next_state <= m1_rd_send_adr_sr; // Leads to a new address line. + reset_rd_digit_count <= 1; + incr_adr_offset <= 1; // move to the next address + end + else if (ack_i && (command == `CMD_R)) begin + m1_next_state <= m1_rd_send_dat_sr; // Leads to a new data field. + reset_rd_digit_count <= 1; + reset_msg_offset <= 1; + incr_adr_offset <= 1; // move to the next address + end + else if (ack_i) begin + m1_next_state <= m1_bus_granted; // continue to the next cycle + incr_adr_offset <= 1; // move to the next address + end + else m1_next_state <= m1_execute; + end + + m1_rd_send_adr_sr : + begin + msg_base <= {1'b0,rd_adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1: + `NIBBLE_SIZE*(ADR_DIGITS_PP-1)]}; + if ((rd_digit_count == ADR_DIGITS_PP-1) && rs232_tx_load) begin + m1_next_state <= m1_rd_send_separator; + reset_msg_offset <= 1; + end + else if (rs232_tx_load) begin + shift_rd_adr <= 1; + incr_rd_digit_count <= 1; + m1_next_state <= m1_rd_send_adr_sr; + end + else m1_next_state <= m1_rd_send_adr_sr; + end + + m1_rd_send_separator : + begin + msg_base <= 5'b10000; // Address of the separator message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 2) && rs232_tx_load) + begin + m1_next_state <= m1_rd_send_dat_sr; + reset_rd_digit_count <= 1; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_rd_send_separator; + end + + m1_rd_send_dat_sr : + begin + msg_base <= {1'b0,dat_sr[`NIBBLE_SIZE*DAT_DIGITS_PP-1: + `NIBBLE_SIZE*(DAT_DIGITS_PP-1)]}; + if ( + (rd_digit_count == DAT_DIGITS_PP-1) + && (rd_field_count == RD_FIELDS_PP-1) + && rs232_tx_load + ) + begin + m1_next_state <= m1_rd_send_crlf; + reset_rd_field_count <= 1; + end + else if ((rd_digit_count == DAT_DIGITS_PP-1) && rs232_tx_load) begin + m1_next_state <= m1_rd_send_space; + incr_rd_field_count <= 1; + end + else if (rs232_tx_load) begin + store_dat <= 1; + incr_rd_digit_count <= 1; + m1_next_state <= m1_rd_send_dat_sr; + end + else m1_next_state <= m1_rd_send_dat_sr; + end + + m1_rd_send_space : + begin + msg_base <= 5'b10000; // Address of the space + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_bus_granted; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_rd_send_space; + end + + m1_rd_send_crlf : + begin + msg_base <= 5'b10111; // Address of the cr/lf message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 1) && rs232_tx_load) begin + m1_next_state <= m1_bus_granted; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_rd_send_crlf; + end + + default : m1_next_state <= m1_initial_state; + endcase +end + + +// This is the counter for incrementing or loading the cmd_ptr +always @(posedge clk_i) +begin + if (reset_i || reset_cmd_ptr) cmd_ptr <= 0; + else if (decr_cmd_ptr) cmd_ptr <= cmd_ptr - 1; + else if (incr_cmd_ptr) cmd_ptr <= cmd_ptr + 1; +end + + +// This is the command buffer writing section +always @(posedge clk_i) +begin + if (rs232_echo && cmd_buffer_write) cmd_buffer[cmd_ptr] <= rs232_rx_char; +end +// This is the command buffer reading section +assign cmd_char = cmd_buffer[cmd_ptr]; +assign lc_cmd_char = (cmd_buffer[cmd_ptr] | 8'h20); // lowercase + + + +// These assigments are for detecting whether the cmd_char is +// anything of special interest. +assign char_is_enter = (cmd_char == 8'h0d); // enter +assign char_is_whitespace = ( + (cmd_char == 8'h20) // space + || (cmd_char == 8'h09) // tab + ); +assign char_is_num = ((cmd_char>=8'h30)&&(cmd_char<=8'h39)); +assign char_is_a_f = ((lc_cmd_char>=8'h61)&&(lc_cmd_char<=8'h66)); +assign char_is_hex = ( char_is_num || char_is_a_f ); +assign char_is_r = (lc_cmd_char == 8'h72); // "r" +assign char_is_w = (lc_cmd_char == 8'h77); // "w" +assign char_is_i = (lc_cmd_char == 8'h69); // "i" + +assign hex_digit = char_is_num?cmd_char[3:0]:(cmd_char[3:0]+9); + +// This is the command register. It stores the type of command to execute. +// This is so that the state machine can parse address, data and qty +// into "generic" storage locations, and then when it executes the command, +// it refers back to this register in order to determine what type of +// operation to perform. + +always @(posedge clk_i) +begin + if (reset_i) command <= `CMD_0; + else if (cmd_i) command <= `CMD_I; + else if (cmd_r) command <= `CMD_R; + else if (cmd_w) command <= `CMD_W; +end + +// This is the "nibble" shift register for the address which is sent character +// by character to the user. It is loaded each time the adr_offset is +// incremented, in order to save the previous address for use in printing +// to the user. +always @(posedge clk_i) +begin + if (reset_i || reset_adr) rd_adr_sr <= 0; + else if (incr_adr_offset) rd_adr_sr <= adr_ptr; + else if (shift_rd_adr) begin + rd_adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1:`NIBBLE_SIZE] <= + rd_adr_sr[`NIBBLE_SIZE*(ADR_DIGITS_PP-1)-1:0]; + rd_adr_sr[`NIBBLE_SIZE-1:0] <= {`NIBBLE_SIZE{1'b0}}; + end +end + +// These are the "nibble" shift registers. They handle loading the +// hexadecimal digits from the command line. +always @(posedge clk_i) +begin + if (reset_i || reset_adr) adr_sr <= 0; + else if (store_adr) begin + adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1:`NIBBLE_SIZE] <= + adr_sr[`NIBBLE_SIZE*(ADR_DIGITS_PP-1)-1:0]; + adr_sr[`NIBBLE_SIZE-1:0] <= hex_digit; + end +end + +always @(posedge clk_i) +begin + if (reset_i || reset_dat) dat_sr <= 0; + else if (capture_dat) dat_sr <= dat_io; + else if (store_dat) begin + dat_sr[`NIBBLE_SIZE*DAT_DIGITS_PP-1:`NIBBLE_SIZE] <= + dat_sr[`NIBBLE_SIZE*(DAT_DIGITS_PP-1)-1:0]; + dat_sr[`NIBBLE_SIZE-1:0] <= hex_digit; + end +end + +always @(posedge clk_i) +begin + if (reset_i || reset_qty) qty_sr <= 0; + else if (init_qty) qty_sr <= 1; + else if (store_qty) begin + qty_sr[`NIBBLE_SIZE*QTY_DIGITS_PP-1:`NIBBLE_SIZE] <= + qty_sr[`NIBBLE_SIZE*(QTY_DIGITS_PP-1)-1:0]; + qty_sr[`NIBBLE_SIZE-1:0] <= hex_digit; + end +end + +// This is the rd_digit_count counter. It is used for counting digits +// displayed of both the adr_sr and dat_sr, so it must be able to count up +// to the extent of the larger of the two... +always @(posedge clk_i) +begin + if (reset_i || reset_rd_digit_count) rd_digit_count <= 0; + else if (incr_rd_digit_count) rd_digit_count <= rd_digit_count + 1; +end + +// This is the rd_field_count counter. It is used for counting dat_sr fields +// displayed per line. +always @(posedge clk_i) +begin + if (reset_i || reset_rd_field_count) rd_field_count <= 0; + else if (incr_rd_field_count) rd_field_count <= rd_field_count + 1; +end + + +// This is the watchdog timer counter +// The watchdog timer is always "enabled" to operate. +always @(posedge clk_i) +begin + if (reset_i || reset_watchdog) watchdog_timer_count <= 0; + else if (~watchdog_timer_done) + watchdog_timer_count <= watchdog_timer_count + 1; +end +assign watchdog_timer_done = (watchdog_timer_count==WATCHDOG_TIMER_VALUE_PP); + + +endmodule + + Index: rs232_syscon/trunk =================================================================== --- rs232_syscon/trunk (nonexistent) +++ rs232_syscon/trunk (revision 4)
rs232_syscon/trunk Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: rs232_syscon/web_uploads =================================================================== --- rs232_syscon/web_uploads (nonexistent) +++ rs232_syscon/web_uploads (revision 4)
rs232_syscon/web_uploads Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: rs232_syscon/branches =================================================================== --- rs232_syscon/branches (nonexistent) +++ rs232_syscon/branches (revision 4)
rs232_syscon/branches Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ## Index: rs232_syscon/tags/V001/b13c_environment.zip =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rs232_syscon/tags/V001/b13c_environment.zip =================================================================== --- rs232_syscon/tags/V001/b13c_environment.zip (nonexistent) +++ rs232_syscon/tags/V001/b13c_environment.zip (revision 4)
rs232_syscon/tags/V001/b13c_environment.zip Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rs232_syscon/tags/V001/rs232_syscon.doc =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: rs232_syscon/tags/V001/rs232_syscon.doc =================================================================== --- rs232_syscon/tags/V001/rs232_syscon.doc (nonexistent) +++ rs232_syscon/tags/V001/rs232_syscon.doc (revision 4)
rs232_syscon/tags/V001/rs232_syscon.doc Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: rs232_syscon/tags/V001/rs232_syscon.v =================================================================== --- rs232_syscon/tags/V001/rs232_syscon.v (nonexistent) +++ rs232_syscon/tags/V001/rs232_syscon.v (revision 4) @@ -0,0 +1,1168 @@ +//------------------------------------------------------------------------------------- +// +// Author: John Clayton +// Date : June 25, 2001 +// Update: 6/25/01 copied this file from ps2_mouse.v (pared down). +// Update: 6/07/01 Finished initial coding efforts. +// Update: 7/19/01 First compilation. Added master_br_o and master_bg_i; +// Update: 7/25/01 Testing. Eliminated msg_active signal. Changed serial.v +// to reflect new handshaking (i.e. "load_request" is now a +// periodic pulse of tx_clk_1x from rs232_tx...) +// Update: 7/30/01 Began coding m2 state machine. Defined response codes. +// Update: 8/01/01 After some testing with m2, merged m2 into m1. Eliminated +// response codes. +// Update: 8/02/01 Tested & measured the single "combined" state machine's +// performance, and "it was found wanting." (The 49.152MHz +// clock frequency was too fast for it...) Created clk_s +// at 49.152/2 MHz, and this worked. +// Update: 8/03/01 Added counter loop to "execute" and "bus_granted" states +// so that multiple bus cycles are generated, at sequential +// addresses. However, the qty field is not cleared before +// being loaded with new characters, which causes problems. +// Update: 8/07/01 Finished debugging. The read print formatting is now +// correct, and the unit appears to operate correctly. +// Many hours were spent puzzling over how to make this work. +// Removed port "debug". +// Update: 8/24/01 Added "master_stb_i" and "master_we_i" inputs and logic. +// Update: 12/13/01 For memory_sizer.v, I lowered the frequency of clk_s down +// to 49.152/4 MHz, so I changed the CLOCK_FACTOR from 8 to 4 +// on the rs232 transciever, and this worked fine. +// Update: 9/09/02 Incorporated the "autobaud_with_tracking" module so that +// the serial clock is generated automatically, no matter +// what frequency clk_i is used. The user simply needs to +// press "enter" from the terminal program to synchronize +// the baud rate generator. Changing BAUD rates on the fly +// is also permitted, simply change to a new BAUD rate in the +// terminal program and hit enter. +// Update:11/26/02 Changed the string constants to binary representation +// (Just to eliminate warnings in XST.) +// +// +// +// +// +// Description +//------------------------------------------------------------------------------------- +// This is a state-machine driven rs232 serial port interface to a "Wishbone" +// type of bus. It is intended to be used as a "Wishbone system controller" +// for debugging purposes. Specifically, the unit allows the user to send +// text commands to the "rs232_syscon" unit, in order to generate read and +// write cycles on the Wishbone compatible bus. The command structure is +// quite terse and spartan in nature, this is for the sake of the logic itself. +// Because the menu-driven command structure is supported without the use of +// dedicated memory blocks (in order to maintain cross-platform portability +// as much as possible) the menus and command responses were kept as small +// as possible. In most cases, the responses from the unit to the user +// consist of a "newline" and one or two visible characters. The command +// structure consists of the following commands and responses: +// +// Command Syntax Purpose +// --------------- --------------------------------------- +// w aaaa dddd xx Write data "dddd" starting at address "aaaa" +// perform this "xx" times at sequential addresses. +// (The quantity field is optional, default is 1). +// r aaaa xx Read data starting from address "aaaa." +// Perform this "xx" times at sequential addresses. +// (The quantity field is optional, default is 1). +// i Send a reset pulse to the system. (initialize). +// +// Response from rs232_syscon Meaning +// -------------------------- --------------------------------------- +// OK Command received and performed. No errors. +// ? Command buffer full, without receiving "enter." +// C? Command not recognized. +// A? Address field syntax error. +// D? Data field syntax error. +// Q? Quantity field syntax error. +// ! No "ack_i", or else "err_i" received from bus. +// B! No "bg_i" received from master. +// +// NOTES on the operation of this unit: +// +// - The unit generates a command prompt which is "-> ". +// - Capitalization is not important. +// - Each command is terminated by the "enter" key (0x0d character). +// Commands are executed as soon as "enter" is received. +// - Trailing parameters need not be re-entered. Their values will +// remain the same as their previous settings. +// - Use of the backspace key is supported, so mistakes can be corrected. +// - The length of the command line is limited to a fixed number of +// characters, as configured by parameter. +// - Fields are separated by white space, including "tab" and/or "space" +// - All numerical fields are interpreted as hexadecimal numbers. +// Decimal is not supported. +// - Numerical field values are retained between commands. If a "r" is issued +// without any fields following it, the previous values will be used. A +// set of "quantity" reads will take place at sequential addresses. +// If a "w" is issued without any fields following it, the previous data +// value will be written "quantity" times at sequential addresses, starting +// from the next location beyond where the last command ended. +// - If the user does not wish to use "ack" functionality, simply tie the +// "ack_i" input to 1b'1, and then the ! response will never be generated. +// - The data which is read in by the "r" command is displayed using lines +// which begin with the address, followed by the data fields. The number +// of data fields displayed per line (following the address) is adjustable +// by setting a parameter. No other display format adjustments can be made. +// - There is currently only a single watchdog timer. It begins to count at +// the time a user hits "enter" to execute a command. If the bus is granted +// and the ack is received before the expiration of the timer, then the +// cycle will complete normally. Therefore, the watchdog timeout value +// needs to include time for the request and granting of the bus, in +// addition to the time needed for the actual bus cycle to complete. +// +// +// Currently, there is only a single indicator (stb_o) generated during bus +// output cycles which are generated from this unit. +// The user can easily implement decoding logic based upon adr_o and stb_o +// which would serve as multiple "stb_o" type signals for different cores +// which would be sharing the same bus. +// +// The dat_io bus supported by this module is a tri-state type of bus. The +// Wishbone spec. allows for this type of bus (see Wishbone spec. pg. 66). +// However, if separate dat_o and dat_i busses are desired, they can be added +// to the module without too much trouble. Supposedly the only difference +// between the two forms of data bus is that one of them avoids using tri-state +// at the cost of doubling the number of interconnects used to carry data back +// and forth... Some people say that tri-state should be avoided for use +// in internal busses in ASICs. Maybe they are right. +// But in FPGAs tri-state seems to work pretty well, even for internal busses. +// +// Parameters are provided to configure the width of the different command +// fields. To simplify the logic for binary to hexadecimal conversion, these +// parameters allow adjustment in units of 1 hex digit, not anything smaller. +// If your bus has 10 bits, for instance, simply set the address width to 3 +// which produces 12 bits, and then just don't use the 2 msbs of address +// output. +// +// No support for the optional Wishbone "retry" (rty_i) input is provided at +// this time. +// No support for "tagn_o" bits is provided at this time, although a register +// might be added external to this module in order to implement to tag bits. +// No BLOCK or RMW cycles are supported currently, so cyc_o is equivalent to +// stb_o... +// The output busses are not tri-stated. The user may add tri-state buffers +// external to the module, using "stb_o" to enable the buffer outputs. +// +//------------------------------------------------------------------------------------- + + +`define NIBBLE_SIZE 4 // Number of bits in one nibble + +// The command register has these values +`define CMD_0 0 // Unused command +`define CMD_I 1 // Initialize (or reset) +`define CMD_R 2 // Read +`define CMD_W 3 // Write + +module rs232_syscon ( + clk_i, + reset_i, + ack_i, + err_i, + master_bg_i, + master_adr_i, + master_stb_i, + master_we_i, + rs232_rxd_i, + dat_io, + rst_o, + master_br_o, + stb_o, + cyc_o, + adr_o, + we_o, + rs232_txd_o + ); + + +// Parameters + +// The timer value can be from [0 to (2^WATCHDOG_TIMER_BITS_PP)-1] inclusive. +// RD_FIELDS_PP can be from [0 to (2^RD_FIELD_CTR_BITS_PP)-1] inclusive. +// Ensure that (2^CHAR_COUNT_BITS_PP) >= CMD_BUFFER_SIZE_PP. +// The setting of CMD_BUFFER_SIZE_PP should be large enough to hold the +// largest command, obviously. +// Ensure that (2^RD_DIGIT_COUNT_BITS_PP) is greater than or equal to the +// larger of {ADR_DIGITS_PP,DAT_DIGITS_PP}. +parameter ADR_DIGITS_PP = 4; // # of hex digits for address. +parameter DAT_DIGITS_PP = 4; // # of hex digits for data. +parameter QTY_DIGITS_PP = 2; // # of hex digits for quantity. +parameter CMD_BUFFER_SIZE_PP = 32; // # of chars in the command buffer. +parameter CMD_PTR_BITS_PP = 4; // # of Bits in command buffer ptr. +parameter WATCHDOG_TIMER_VALUE_PP = 200; // # of sys_clks before ack expected. +parameter WATCHDOG_TIMER_BITS_PP = 8; // # of bits needed for timer. +parameter RD_FIELDS_PP = 8; // # of fields/line (when qty > 1). +parameter RD_FIELD_COUNT_BITS_PP = 3; // # of bits in the fields counter. +parameter RD_DIGIT_COUNT_BITS_PP = 2; // # of bits in the digits counter. + + +// State encodings, provided as parameters +// for flexibility to the one instantiating the module. +// In general, the default values need not be changed. + +// There is one state machines: m1. +// "default" state upon power-up and configuration is: +// "m1_initial_state" + +parameter m1_initial_state = 5'h00; +parameter m1_send_ok = 5'h01; // Sends OK +parameter m1_send_prompt = 5'h02; // Sends "-> " +parameter m1_check_received_char = 5'h03; +parameter m1_send_crlf = 5'h04; // Sends cr,lf +parameter m1_parse_error_indicator_crlf = 5'h05; // Sends cr,lf +parameter m1_parse_error_indicator = 5'h06; // Sends ? +parameter m1_ack_error_indicator = 5'h07; // Sends ! +parameter m1_bg_error_indicator = 5'h08; // Sends B! +parameter m1_cmd_error_indicator = 5'h09; // Sends C? +parameter m1_adr_error_indicator = 5'h0a; // Sends A? +parameter m1_dat_error_indicator = 5'h0b; // Sends D? +parameter m1_qty_error_indicator = 5'h0c; // Sends Q? +parameter m1_scan_command = 5'h10; +parameter m1_scan_adr_whitespace = 5'h11; +parameter m1_get_adr_field = 5'h12; +parameter m1_scan_dat_whitespace = 5'h13; +parameter m1_get_dat_field = 5'h14; +parameter m1_scan_qty_whitespace = 5'h15; +parameter m1_get_qty_field = 5'h16; +parameter m1_start_execution = 5'h17; +parameter m1_request_bus = 5'h18; +parameter m1_bus_granted = 5'h19; +parameter m1_execute = 5'h1a; +parameter m1_rd_send_adr_sr = 5'h1b; +parameter m1_rd_send_separator = 5'h1c; +parameter m1_rd_send_dat_sr = 5'h1d; +parameter m1_rd_send_space = 5'h1e; +parameter m1_rd_send_crlf = 5'h1f; + +// I/O declarations +input clk_i; // System clock input +input reset_i; // Reset signal for this module +input ack_i; // Ack input from Wishbone "slaves" +input err_i; // Err input from Wishbone "slaves" +input master_bg_i; // Bus Grant (grants this module the bus) + // Address bus input from "normal" Wishbone + // master (i.e. from processor) +input [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] master_adr_i; +input master_stb_i; // bus cycle signal from "normal" bus master +input master_we_i; // write enable from "normal" bus master +input rs232_rxd_i; // Serial data from debug host terminal. + // Data bus (tri-state, to save interconnect) +inout [`NIBBLE_SIZE*DAT_DIGITS_PP-1:0] dat_io; + +output rst_o; // Rst output to Wishbone "slaves" +output master_br_o; // Bus request to normal master device. +output stb_o; // Bus cycle indicator to Wishbone "slaves" +output cyc_o; // Bus cycle indicator to Wishbone "slaves" + // Address bus output to Wishbone "slaves" +output [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_o; +output we_o; // Write enable to Wishbone "slaves" +output rs232_txd_o; // Serial transmit data to debug host terminal + +reg rst_o; +reg master_br_o; + +// Internal signal declarations +wire watchdog_timer_done; // High when watchdog timer is expired +wire rd_addr_field_done; // High when displayed addr field is complete +wire rd_data_field_done; // High when displayed data field is complete +wire rd_line_done; // High when displayed line is complete +wire char_is_enter; // High when cmd_buffer[char_count] is enter. +wire char_is_whitespace; // High when cmd_buffer[char_count] is whitespace. +wire char_is_num; // High when cmd_buffer[char_count] is 0..9 +wire char_is_a_f; // High when cmd_buffer[char_count] is a..f +wire char_is_hex; // High when cmd_buffer[char_count] is a hex char. +wire char_is_r; // High when cmd_buffer[char_count] is r. +wire char_is_w; // High when cmd_buffer[char_count] is w. +wire char_is_i; // High when cmd_buffer[char_count] is i. +wire rx_char_is_enter; // High when rs232_rx_char is enter. +wire rx_char_is_backspace; // High when rs232_rx_char is backspace. +wire [4:0] msg_pointer; // Determines message position or address. +wire [3:0] hex_digit; // This is the digit to be stored. + +reg rs232_echo; // High == echo char's received. +reg [7:0] msg_char; // Selected response message character. +reg [4:0] msg_base; // Added to msg_offset to form msg_pointer. +reg [4:0] msg_offset; // Offset from start of message. +reg reset_msg_offset; // High == set message offset to zero +reg incr_msg_offset; // Used for output messages. +reg cmd_i; // Sets command. +reg cmd_r; // Sets command. +reg cmd_w; // Sets command. +reg shift_rd_adr; // Shifts the rd_adr_sr by one character. +reg store_adr; // Allows adr_sr to store hex_digit. +reg store_dat; // Allows dat_sr to store hex_digit. +reg store_qty; // Allows qty_sr to store hex_digit. +reg reset_adr; // Clears adr_sr +reg reset_dat; // Clears dat_sr +reg reset_qty; // Clears qty_sr +reg init_qty; // Sets qty_sr to 1 +reg capture_dat; // Puts dat_io into dat_sr for later display. + + // For the buses +wire [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_ptr; // = adr_sr + adr_offset + +reg stb_l; // "local" stb signal (to distinguish from stb_o) +reg we_l; // "local" we signal (to distinguish from we_o) + +reg [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] rd_adr_sr; // sr for printing addresses +reg [`NIBBLE_SIZE*ADR_DIGITS_PP-1:0] adr_sr; // "nibble" shift register +reg [`NIBBLE_SIZE*DAT_DIGITS_PP-1:0] dat_sr; // "nibble" shift register +reg [`NIBBLE_SIZE*QTY_DIGITS_PP-1:0] qty_sr; // "nibble" shift register +reg [1:0] command; +reg [`NIBBLE_SIZE*QTY_DIGITS_PP-1:0] adr_offset; // counts from 0 to qty_sr +reg reset_adr_offset; +reg incr_adr_offset; + + // For the command buffer +reg [CMD_PTR_BITS_PP-1:0] cmd_ptr; // Offset from start of command. +reg reset_cmd_ptr; // High == set command pointer to zero. +reg incr_cmd_ptr; // Used for "write port" side of the command buffer +reg decr_cmd_ptr; // Used for "write port" side of the command buffer +reg cmd_buffer_write; +reg [7:0] cmd_buffer [0:CMD_BUFFER_SIZE_PP-1]; +wire [7:0] cmd_char; +wire [7:0] lc_cmd_char; // Lowercase version of cmd_char + + // For the state machine +reg [4:0] m1_state; +reg [4:0] m1_next_state; + + // For various counters +reg reset_rd_field_count; +reg reset_rd_digit_count; +reg incr_rd_field_count; +reg incr_rd_digit_count; +reg [RD_FIELD_COUNT_BITS_PP-1:0] rd_field_count; // "fields displayed" +reg [RD_DIGIT_COUNT_BITS_PP-1:0] rd_digit_count; // "digits displayed" +reg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_timer_count; +reg reset_watchdog; + + // For the rs232 interface +wire serial_clk; +wire [2:0] rs232_rx_error; +wire rs232_tx_load; +wire rs232_tx_load_request; +wire rs232_rx_data_ready; +wire [7:0] rs232_rx_char; +wire [7:0] rs232_tx_char; // Either rs232_rx_char or msg_char + +//-------------------------------------------------------------------------- +// Instantiations +//-------------------------------------------------------------------------- + + +// These defines are for the rs232 interface +`define START_BITS 1 +`define DATA_BITS 8 +`define STOP_BITS 1 +`define CLOCK_FACTOR 8 + +// This module generates a serial BAUD clock automatically. +// The unit synchronizes on the carriage return character, so the user +// only needs to press the "enter" key for serial communications to start +// working, no matter what BAUD rate and clk_i frequency are used! +auto_baud_with_tracking #( + `CLOCK_FACTOR, // CLOCK_FACTOR_PP + 16 // LOG2_MAX_COUNT_PP + ) + clock_unit_2 + ( + .clk_i(clk_i), + .reset_i(reset_i), + .serial_dat_i(rs232_rxd_i), + .auto_baud_locked_o(), + .baud_clk_o(serial_clk) + ); + +// A transmitter, which asserts load_request at the end of the currently +// transmitted word. The tx_clk must be a "clock enable" (narrow positive +// pulse) which occurs at 16x the desired transmit rate. If load_request +// is connected directly to load, the unit will transmit continuously. +rs232tx #( + `START_BITS, // start_bits + `DATA_BITS, // data_bits + `STOP_BITS, // stop_bits (add intercharacter delay...) + `CLOCK_FACTOR // clock_factor + ) + rs232_tx_block // instance name + ( + .clk(clk_i), + .tx_clk(serial_clk), + .reset(reset_i), + .load(rs232_tx_load), + .data(rs232_tx_char), + .load_request(rs232_tx_load_request), + .txd(rs232_txd_o) + ); + +// A receiver, which asserts "word_ready" to indicate a received word. +// Asserting "read_word" will cause "word_ready" to go low again if it was high. +// The character is held in the output register, during the time the next +// character is coming in. +rs232rx #( + `START_BITS, // start_bits + `DATA_BITS, // data_bits + `STOP_BITS, // stop_bits + `CLOCK_FACTOR // clock_factor + ) + rs232_rx_block // instance name + ( + .clk(clk_i), + .rx_clk(serial_clk), + .reset(reset_i || (| rs232_rx_error)), + .rxd(rs232_rxd_i), + .read(rs232_tx_load), + .data(rs232_rx_char), + .data_ready(rs232_rx_data_ready), + .error_over_run(rs232_rx_error[0]), + .error_under_run(rs232_rx_error[1]), + .error_all_low(rs232_rx_error[2]) + ); + +//`undef START_BITS +//`undef DATA_BITS +//`undef STOP_BITS +//`undef CLOCK_FACTOR + + +//-------------------------------------------------------------------------- +// Module code +//-------------------------------------------------------------------------- + +assign adr_o = master_bg_i?adr_ptr:master_adr_i; +assign we_o = master_bg_i?we_l:master_we_i; +assign stb_o = master_bg_i?stb_l:master_stb_i; + + +assign dat_io = (master_bg_i && we_l && stb_l)? + dat_sr:{`NIBBLE_SIZE*DAT_DIGITS_PP{1'bZ}}; + +// Temporary +assign cyc_o = stb_o; // Separate cyc_o is not yet supported! + + +// This is the adress offset counter +always @(posedge clk_i) +begin + if (reset_i || reset_adr_offset) adr_offset <= 0; + else if (incr_adr_offset) adr_offset <= adr_offset + 1; +end +// This forms the adress pointer which is used on the bus. +assign adr_ptr = adr_sr + adr_offset; + + +// This is the ROM for the ASCII characters to be transmitted. +always @(msg_pointer) +begin + case (msg_pointer) // synthesis parallel_case + 5'b00000 : msg_char <= 8'h30; // "0"; // Hexadecimal characters + 5'b00001 : msg_char <= 8'h31; // "1"; + 5'b00010 : msg_char <= 8'h32; // "2"; + 5'b00011 : msg_char <= 8'h33; // "3"; + 5'b00100 : msg_char <= 8'h34; // "4"; + 5'b00101 : msg_char <= 8'h35; // "5"; + 5'b00110 : msg_char <= 8'h36; // "6"; + 5'b00111 : msg_char <= 8'h37; // "7"; + 5'b01000 : msg_char <= 8'h38; // "8"; + 5'b01001 : msg_char <= 8'h39; // "9"; + 5'b01010 : msg_char <= 8'h41; // "A"; // Address error indication + 5'b01011 : msg_char <= 8'h42; // "B"; + 5'b01100 : msg_char <= 8'h43; // "C"; // Command error indication + 5'b01101 : msg_char <= 8'h44; // "D"; // Data error indication + 5'b01110 : msg_char <= 8'h45; // "E"; + 5'b01111 : msg_char <= 8'h46; // "F"; + 5'b10000 : msg_char <= 8'h20; // " "; // Space + 5'b10001 : msg_char <= 8'h3A; // ":"; // Colon + 5'b10010 : msg_char <= 8'h20; // " "; // Space + 5'b10011 : msg_char <= 8'h3F; // "?"; // Parse error indication + 5'b10100 : msg_char <= 8'h21; // "!"; // ack_i/err_i error indication + 5'b10101 : msg_char <= 8'h4F; // "O"; // "All is well" message + 5'b10110 : msg_char <= 8'h4B; // "K"; + 5'b10111 : msg_char <= 8'h0D; // Carriage return & line feed + 5'b11000 : msg_char <= 8'h0A; + 5'b11001 : msg_char <= 8'h2D; // "-"; // Command Prompt + 5'b11010 : msg_char <= 8'h3E; // ">"; + 5'b11011 : msg_char <= 8'h20; // " "; + 5'b11100 : msg_char <= 8'h51; // "Q"; // Quantity error indication + default : msg_char <= 8'h3D; // "="; + endcase +end + +// This logic determines when to load a transmit character. +assign rs232_tx_load = rs232_echo? + (rs232_rx_data_ready && rs232_tx_load_request):rs232_tx_load_request; + +// This is the counter for incrementing, decrementing or resetting the +// message pointer. +always @(posedge clk_i) +begin + if (reset_i || reset_msg_offset) msg_offset <= 0; + else if (incr_msg_offset) msg_offset <= msg_offset + 1; +end +assign msg_pointer = msg_offset + msg_base; + + + +// This is the mux which selects whether to echo back the characters +// received (as during the entering of a command) or to send back response +// characters. +assign rs232_tx_char = (rs232_echo)?rs232_rx_char:msg_char; + + +// These assigments are for detecting whether the received rs232 character is +// anything of special interest. +assign rx_char_is_enter = (rs232_rx_char == 8'h0d); +assign rx_char_is_backspace = (rs232_rx_char == 8'h08); + + + +// This is state machine m1. It handles receiving the command line, including +// backspaces, and prints error/response messages. It also parses and +// executes the commands. + +// State register +always @(posedge clk_i) +begin : m1_state_register + if (reset_i) m1_state <= m1_initial_state; // perform reset for rest of system + else m1_state <= m1_next_state; +end + +// State transition logic +always @(m1_state + or rx_char_is_enter + or rx_char_is_backspace + or msg_offset + or cmd_ptr + or rs232_tx_load + or char_is_whitespace + or char_is_hex + or char_is_enter + or char_is_i + or char_is_r + or char_is_w + or command + or master_bg_i + or watchdog_timer_done + or err_i + or ack_i + or adr_offset + or qty_sr + or dat_sr + or rd_adr_sr + or rd_field_count + or rd_digit_count + ) +begin : m1_state_logic + + // Default values for outputs. The individual states can override these. + msg_base <= 5'b0; + reset_msg_offset <= 0; + incr_msg_offset <= 0; + rs232_echo <= 0; + rst_o <= 0; + we_l <= 0; + stb_l <= 0; + cmd_buffer_write <= 0; + reset_cmd_ptr <= 0; + incr_cmd_ptr <= 0; + decr_cmd_ptr <= 0; + master_br_o <= 0; + cmd_r <= 0; + cmd_w <= 0; + cmd_i <= 0; + shift_rd_adr <= 0; + store_adr <= 0; // enables storing hex chars in adr_sr (shift) + store_dat <= 0; // enables storing hex chars in dat_sr (shift) + store_qty <= 0; // enables storing hex chars in qty_sr (shift) + reset_adr <= 0; + reset_dat <= 0; + reset_qty <= 0; + init_qty <= 0; + capture_dat <= 0; // enables capturing bus data in dat_sr (load) + incr_adr_offset <= 0; + reset_adr_offset <= 0; + reset_watchdog <= 0; + incr_rd_field_count <= 0; + incr_rd_digit_count <= 0; + reset_rd_field_count <= 0; + reset_rd_digit_count <= 0; + + case (m1_state) // synthesis parallel_case + + m1_initial_state : + begin + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 15) && rs232_tx_load) begin + m1_next_state <= m1_send_prompt; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_initial_state; + end + + m1_send_ok : + begin + msg_base <= 5'b10101; // Address of the OK message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 1) && rs232_tx_load) begin + m1_next_state <= m1_send_prompt; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_send_ok; + end + + m1_send_prompt : + begin + msg_base <= 5'b10111; // Address of the cr,lf,prompt message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 4) && rs232_tx_load) begin + m1_next_state <= m1_check_received_char; + reset_cmd_ptr <= 1; + end + else m1_next_state <= m1_send_prompt; + end + + // This state always leads to activating the parser... + m1_send_crlf : + begin + msg_base <= 5'b10111; // Address of the cr/lf message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 1) && rs232_tx_load) begin + m1_next_state <= m1_scan_command; + reset_cmd_ptr <= 1; + end + else m1_next_state <= m1_send_crlf; + end + + m1_check_received_char : + begin + rs232_echo <= 1; // Allow echoing of characters + if (rx_char_is_backspace && rs232_tx_load) + begin + m1_next_state <= m1_check_received_char; + decr_cmd_ptr <= 1; // This effectively eliminates the last char + end + else if (rx_char_is_enter && rs232_tx_load) + begin + m1_next_state <= m1_send_crlf; + cmd_buffer_write <= 1; // Store the enter as "marker" for parsing + reset_msg_offset <= 1; + end + else if (rs232_tx_load && (cmd_ptr == CMD_BUFFER_SIZE_PP-1)) + begin + m1_next_state <= m1_parse_error_indicator_crlf; + reset_msg_offset <= 1; + reset_cmd_ptr <= 1; + end + else if (rs232_tx_load) + begin + incr_cmd_ptr <= 1; + cmd_buffer_write <= 1; + m1_next_state <= m1_check_received_char; + end + else m1_next_state <= m1_check_received_char; + end + + m1_bg_error_indicator : + begin + msg_base <= 5'b01011; // Address of the B character + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_ack_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_bg_error_indicator; + end + + m1_ack_error_indicator : + begin + msg_base <= 5'b10100; // Address of the ! error message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_send_prompt; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_ack_error_indicator; + end + + // This state is used when the line is too long... + m1_parse_error_indicator_crlf : + begin + msg_base <= 5'b10111; // Address of the cr,lf message. + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 1) && rs232_tx_load) begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_parse_error_indicator_crlf; + end + + m1_parse_error_indicator : + begin + msg_base <= 5'b10011; // Address of the ? message. + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_send_prompt; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_parse_error_indicator; + end + + m1_cmd_error_indicator : + begin + msg_base <= 5'b01100; // Address of 'C' + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_cmd_error_indicator; + end + + m1_adr_error_indicator : + begin + msg_base <= 5'b01010; // Address of 'A' + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) + begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_adr_error_indicator; + end + + m1_dat_error_indicator : + begin + msg_base <= 5'b01101; // Address of 'D' + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) + begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_dat_error_indicator; + end + + m1_qty_error_indicator : + begin + msg_base <= 5'b11100; // Address of 'Q' + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) + begin + m1_next_state <= m1_parse_error_indicator; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_qty_error_indicator; + end + + // The following states are for parsing and executing the command. + + // This state takes care of leading whitespace before the command + m1_scan_command : + begin + rs232_echo <= 1; // Don't send message characters + reset_msg_offset <= 1; // This one reset should cover all of the + // parse/exec. states. With rs232_echo + // on, and no receive characters arrive, + // then the msg_offset will remain reset. + // This means the watchdog timer can take + // a long time, if need be, during exec. + // (NOTE: It might be better to disable + // the echoing of rx chars during these + // states.) + init_qty <= 1; // Set qty = 1 by default. That can be + // overridden later, if the command has + // a different qty field. + if (char_is_whitespace) begin + m1_next_state <= m1_scan_command; + incr_cmd_ptr <= 1; + end + else if (char_is_r) begin + m1_next_state <= m1_scan_adr_whitespace; + incr_cmd_ptr <= 1; + cmd_r <= 1; + end + else if (char_is_w) begin + m1_next_state <= m1_scan_adr_whitespace; + incr_cmd_ptr <= 1; + cmd_w <= 1; + end + else if (char_is_i) begin + m1_next_state <= m1_start_execution; + cmd_i <= 1; + end + else m1_next_state <= m1_cmd_error_indicator; + end + + // The only way to determine the end of a valid field is to find + // whitespace. Therefore, char_is_whitespace must be used as an exit + // condition from the "get_xxx_field" states. So, this state is used to + // scan through any leading whitespace prior to it. + m1_scan_adr_whitespace : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_whitespace) begin + m1_next_state <= m1_scan_adr_whitespace; + incr_cmd_ptr <= 1; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else begin + m1_next_state <= m1_get_adr_field; + reset_adr <= 1; + end + end + + m1_get_adr_field : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_hex) begin + m1_next_state <= m1_get_adr_field; + store_adr <= 1; + incr_cmd_ptr <= 1; + end + else if (char_is_whitespace) begin // Normal exit + m1_next_state <= m1_scan_dat_whitespace; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else m1_next_state <= m1_adr_error_indicator; + end + + m1_scan_dat_whitespace : + begin + rs232_echo <= 1; // Don't send message characters + // There is no DAT field for reads, so skip it. + if (command == `CMD_R) m1_next_state <= m1_scan_qty_whitespace; + else if (char_is_whitespace) begin + m1_next_state <= m1_scan_dat_whitespace; + incr_cmd_ptr <= 1; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else begin + m1_next_state <= m1_get_dat_field; + reset_dat <= 1; + end + end + + m1_get_dat_field : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_hex) begin + m1_next_state <= m1_get_dat_field; + store_dat <= 1; + incr_cmd_ptr <= 1; + end + else if (char_is_whitespace) begin // Normal exit + m1_next_state <= m1_scan_qty_whitespace; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else m1_next_state <= m1_dat_error_indicator; + end + + m1_scan_qty_whitespace : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_whitespace) begin + m1_next_state <= m1_scan_qty_whitespace; + incr_cmd_ptr <= 1; + end + else if (char_is_enter) m1_next_state <= m1_start_execution; + else begin + m1_next_state <= m1_get_qty_field; + reset_qty <= 1; + end + end + + m1_get_qty_field : + begin + rs232_echo <= 1; // Don't send message characters + if (char_is_hex) begin + m1_next_state <= m1_get_qty_field; + store_qty <= 1; + incr_cmd_ptr <= 1; + end + else if (char_is_whitespace || char_is_enter) begin // Normal exit + m1_next_state <= m1_start_execution; + end + else m1_next_state <= m1_qty_error_indicator; + end + + // This state seeks to obtain master_bg_i, which grants the bus to + // rs232_syscon. + m1_start_execution : + begin + rs232_echo <= 1; // Don't send message characters + reset_watchdog <= 1; // Reset the timer. + reset_adr_offset <= 1; // Reset the address offset. + reset_rd_field_count <= 1; // Reset the rd_field_count. + m1_next_state <= m1_request_bus; + end + + m1_request_bus : + begin + rs232_echo <= 1; // Don't send message characters + master_br_o <= 1; // Request the bus. + if (master_bg_i) m1_next_state <= m1_bus_granted; + else if (watchdog_timer_done) begin + m1_next_state <= m1_bg_error_indicator; + end + else m1_next_state <= m1_request_bus; + end + + m1_bus_granted : + begin + rs232_echo <= 1; // Don't send message characters + master_br_o <= 1; // Keep holding the bus + reset_watchdog <= 1; // Reset the timer. + if (adr_offset != qty_sr) m1_next_state <= m1_execute; + else m1_next_state <= m1_send_ok; + end + + // This single state does reset/write/read depending upon the value + // contained in "command"! + m1_execute : + begin + rs232_echo <= 1; // Don't send message characters + master_br_o <= 1; // Keep holding the bus + stb_l <= 1'b1; // Show that a bus cycle is happening + case (command) // Assert the appropriate signals + `CMD_I : rst_o <= 1; + `CMD_R : capture_dat <= ack_i; + `CMD_W : we_l <= 1; + default: ; + endcase + if (watchdog_timer_done || err_i) begin + m1_next_state <= m1_ack_error_indicator; + end + else if (ack_i + && (command == `CMD_R) + && (rd_field_count == 0) + ) + begin + m1_next_state <= m1_rd_send_adr_sr; // Leads to a new address line. + reset_rd_digit_count <= 1; + incr_adr_offset <= 1; // move to the next address + end + else if (ack_i && (command == `CMD_R)) begin + m1_next_state <= m1_rd_send_dat_sr; // Leads to a new data field. + reset_rd_digit_count <= 1; + reset_msg_offset <= 1; + incr_adr_offset <= 1; // move to the next address + end + else if (ack_i) begin + m1_next_state <= m1_bus_granted; // continue to the next cycle + incr_adr_offset <= 1; // move to the next address + end + else m1_next_state <= m1_execute; + end + + m1_rd_send_adr_sr : + begin + msg_base <= {1'b0,rd_adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1: + `NIBBLE_SIZE*(ADR_DIGITS_PP-1)]}; + if ((rd_digit_count == ADR_DIGITS_PP-1) && rs232_tx_load) begin + m1_next_state <= m1_rd_send_separator; + reset_msg_offset <= 1; + end + else if (rs232_tx_load) begin + shift_rd_adr <= 1; + incr_rd_digit_count <= 1; + m1_next_state <= m1_rd_send_adr_sr; + end + else m1_next_state <= m1_rd_send_adr_sr; + end + + m1_rd_send_separator : + begin + msg_base <= 5'b10000; // Address of the separator message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 2) && rs232_tx_load) + begin + m1_next_state <= m1_rd_send_dat_sr; + reset_rd_digit_count <= 1; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_rd_send_separator; + end + + m1_rd_send_dat_sr : + begin + msg_base <= {1'b0,dat_sr[`NIBBLE_SIZE*DAT_DIGITS_PP-1: + `NIBBLE_SIZE*(DAT_DIGITS_PP-1)]}; + if ( + (rd_digit_count == DAT_DIGITS_PP-1) + && (rd_field_count == RD_FIELDS_PP-1) + && rs232_tx_load + ) + begin + m1_next_state <= m1_rd_send_crlf; + reset_rd_field_count <= 1; + end + else if ((rd_digit_count == DAT_DIGITS_PP-1) && rs232_tx_load) begin + m1_next_state <= m1_rd_send_space; + incr_rd_field_count <= 1; + end + else if (rs232_tx_load) begin + store_dat <= 1; + incr_rd_digit_count <= 1; + m1_next_state <= m1_rd_send_dat_sr; + end + else m1_next_state <= m1_rd_send_dat_sr; + end + + m1_rd_send_space : + begin + msg_base <= 5'b10000; // Address of the space + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 0) && rs232_tx_load) begin + m1_next_state <= m1_bus_granted; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_rd_send_space; + end + + m1_rd_send_crlf : + begin + msg_base <= 5'b10111; // Address of the cr/lf message + incr_msg_offset <= rs232_tx_load; + if ((msg_offset == 1) && rs232_tx_load) begin + m1_next_state <= m1_bus_granted; + reset_msg_offset <= 1; + end + else m1_next_state <= m1_rd_send_crlf; + end + + default : m1_next_state <= m1_initial_state; + endcase +end + + +// This is the counter for incrementing or loading the cmd_ptr +always @(posedge clk_i) +begin + if (reset_i || reset_cmd_ptr) cmd_ptr <= 0; + else if (decr_cmd_ptr) cmd_ptr <= cmd_ptr - 1; + else if (incr_cmd_ptr) cmd_ptr <= cmd_ptr + 1; +end + + +// This is the command buffer writing section +always @(posedge clk_i) +begin + if (rs232_echo && cmd_buffer_write) cmd_buffer[cmd_ptr] <= rs232_rx_char; +end +// This is the command buffer reading section +assign cmd_char = cmd_buffer[cmd_ptr]; +assign lc_cmd_char = (cmd_buffer[cmd_ptr] | 8'h20); // lowercase + + + +// These assigments are for detecting whether the cmd_char is +// anything of special interest. +assign char_is_enter = (cmd_char == 8'h0d); // enter +assign char_is_whitespace = ( + (cmd_char == 8'h20) // space + || (cmd_char == 8'h09) // tab + ); +assign char_is_num = ((cmd_char>=8'h30)&&(cmd_char<=8'h39)); +assign char_is_a_f = ((lc_cmd_char>=8'h61)&&(lc_cmd_char<=8'h66)); +assign char_is_hex = ( char_is_num || char_is_a_f ); +assign char_is_r = (lc_cmd_char == 8'h72); // "r" +assign char_is_w = (lc_cmd_char == 8'h77); // "w" +assign char_is_i = (lc_cmd_char == 8'h69); // "i" + +assign hex_digit = char_is_num?cmd_char[3:0]:(cmd_char[3:0]+9); + +// This is the command register. It stores the type of command to execute. +// This is so that the state machine can parse address, data and qty +// into "generic" storage locations, and then when it executes the command, +// it refers back to this register in order to determine what type of +// operation to perform. + +always @(posedge clk_i) +begin + if (reset_i) command <= `CMD_0; + else if (cmd_i) command <= `CMD_I; + else if (cmd_r) command <= `CMD_R; + else if (cmd_w) command <= `CMD_W; +end + +// This is the "nibble" shift register for the address which is sent character +// by character to the user. It is loaded each time the adr_offset is +// incremented, in order to save the previous address for use in printing +// to the user. +always @(posedge clk_i) +begin + if (reset_i || reset_adr) rd_adr_sr <= 0; + else if (incr_adr_offset) rd_adr_sr <= adr_ptr; + else if (shift_rd_adr) begin + rd_adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1:`NIBBLE_SIZE] <= + rd_adr_sr[`NIBBLE_SIZE*(ADR_DIGITS_PP-1)-1:0]; + rd_adr_sr[`NIBBLE_SIZE-1:0] <= {`NIBBLE_SIZE{1'b0}}; + end +end + +// These are the "nibble" shift registers. They handle loading the +// hexadecimal digits from the command line. +always @(posedge clk_i) +begin + if (reset_i || reset_adr) adr_sr <= 0; + else if (store_adr) begin + adr_sr[`NIBBLE_SIZE*ADR_DIGITS_PP-1:`NIBBLE_SIZE] <= + adr_sr[`NIBBLE_SIZE*(ADR_DIGITS_PP-1)-1:0]; + adr_sr[`NIBBLE_SIZE-1:0] <= hex_digit; + end +end + +always @(posedge clk_i) +begin + if (reset_i || reset_dat) dat_sr <= 0; + else if (capture_dat) dat_sr <= dat_io; + else if (store_dat) begin + dat_sr[`NIBBLE_SIZE*DAT_DIGITS_PP-1:`NIBBLE_SIZE] <= + dat_sr[`NIBBLE_SIZE*(DAT_DIGITS_PP-1)-1:0]; + dat_sr[`NIBBLE_SIZE-1:0] <= hex_digit; + end +end + +always @(posedge clk_i) +begin + if (reset_i || reset_qty) qty_sr <= 0; + else if (init_qty) qty_sr <= 1; + else if (store_qty) begin + qty_sr[`NIBBLE_SIZE*QTY_DIGITS_PP-1:`NIBBLE_SIZE] <= + qty_sr[`NIBBLE_SIZE*(QTY_DIGITS_PP-1)-1:0]; + qty_sr[`NIBBLE_SIZE-1:0] <= hex_digit; + end +end + +// This is the rd_digit_count counter. It is used for counting digits +// displayed of both the adr_sr and dat_sr, so it must be able to count up +// to the extent of the larger of the two... +always @(posedge clk_i) +begin + if (reset_i || reset_rd_digit_count) rd_digit_count <= 0; + else if (incr_rd_digit_count) rd_digit_count <= rd_digit_count + 1; +end + +// This is the rd_field_count counter. It is used for counting dat_sr fields +// displayed per line. +always @(posedge clk_i) +begin + if (reset_i || reset_rd_field_count) rd_field_count <= 0; + else if (incr_rd_field_count) rd_field_count <= rd_field_count + 1; +end + + +// This is the watchdog timer counter +// The watchdog timer is always "enabled" to operate. +always @(posedge clk_i) +begin + if (reset_i || reset_watchdog) watchdog_timer_count <= 0; + else if (~watchdog_timer_done) + watchdog_timer_count <= watchdog_timer_count + 1; +end +assign watchdog_timer_done = (watchdog_timer_count==WATCHDOG_TIMER_VALUE_PP); + + +endmodule + + Index: rs232_syscon/tags =================================================================== --- rs232_syscon/tags (nonexistent) +++ rs232_syscon/tags (revision 4)
rs232_syscon/tags Property changes : Added: svn:mergeinfo ## -0,0 +0,0 ##

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.