---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 16:04:58 09/23/2009 -- Design Name: -- Module Name: UARTNumberConvert - beh -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.all; -- clk and reset needed for UART state machine. tx_wire is output wire to UART connector. -- rx_wire is input wire from UART connector. Enter pushbutton is used to send result to -- screen, other pushbuttons to be connected to microcontroller instructions. LEDs are -- just for fun -- use them any way you want entity UARTNumberConvert is Port ( clk : in std_logic; reset : in std_logic; but1 : in std_logic; but2: in std_logic; but3: in std_logic; LED_0 : out std_logic; LED_1 : out std_logic; LED_2 : out std_logic; LED_3 : out std_logic; rx_wire : in std_logic; tx_wire : out std_logic); end UARTNumberConvert; architecture beh of UARTNumberConvert is signal tx_full, rx_empty : std_logic; signal ascii_receive_data: std_logic_vector(7 downto 0); signal ascii_send_data: std_logic_vector(7 downto 0); signal but1_pb, but1_pb_stable, but1_button_level : std_logic; signal but2_pb, but2_pb_stable, but2_button_level : std_logic; signal but3_pb, but3_pb_stable, but3_button_level : std_logic; signal send_one_byte : std_logic; signal BTA_ready, convert_BTA_done_tick, start_BTA_convert : std_logic; signal result_binary_val: std_logic_vector(11 downto 0); signal R0, R1, R2, R3 : std_logic_vector(7 downto 0); signal BTA_sign_char: std_logic_vector(7 downto 0); signal A0_reg, A0_next, A1_reg, A1_next, A2_reg, A2_next, A3_reg, A3_next : std_logic_vector(7 downto 0); signal A_op_reg, A_op_next, B_op_reg, B_op_next, ATB_out_operand: std_logic_vector(11 downto 0); signal ATB_sign_char_reg, ATB_sign_char_next: std_logic_vector(7 downto 0); signal ATB_ready, convert_ATB_done_tick, start_ATB_convert : std_logic; signal char_ptr_reg, char_ptr_next : unsigned(1 downto 0); signal A_or_B_reg, A_or_B_next : std_logic; signal read_byte : std_logic; type state_type is (idle, convert_BTA, get_char, clear_chars, send, done); signal state_reg, state_next: state_type; signal cnt_reg, cnt_next : unsigned(2 downto 0); begin UARTComponent: entity work.UARTUnit(beh) port map ( clk=>clk, reset=>reset, rd_uart=>read_byte, wr_uart=>send_one_byte, rx_wire=>rx_wire, tx_loc_sys_data=>ascii_send_data, tx_full=>tx_full, rx_empty=>rx_empty, rx_loc_sys_data=>ascii_receive_data, tx_wire=>tx_wire); -- Take the bounce out of the pushbutton (only works for buttons normally at 0 and then go to 1 when pressed!) DebounceInst1: entity work.DEBOUNCE(beh) port map (clk=>clk, reset=>reset, button=>but1, button_level=>but1_button_level, button_stable=>but1_pb_stable); DebounceInst2: entity work.DEBOUNCE(beh) port map (clk=>clk, reset=>reset, button=>but2, button_level=>but2_button_level, button_stable=>but2_pb_stable); DebounceInst3: entity work.DEBOUNCE(beh) port map (clk=>clk, reset=>reset, button=>but3, button_level=>but3_button_level, button_stable=>but3_pb_stable); -- BinToASCII is called to convert a binary number to ASCII with start_BTA_convert. Since numbers -- are 12 bits, this restricts there size to be between -2048 and +2047 -- the sign plus 4 digits. BTAInst: entity work.BinToASCII(beh) port map (clk=>clk, reset=>reset, ready=>BTA_ready, convert_done_tick=>convert_BTA_done_tick, start_convert=>start_BTA_convert, result_binary_val=>result_binary_val, dig0=>R0, dig1=>R1, dig2=>R2, dig3=>R3, sign_char=>BTA_sign_char); -- ASCIIToBin converts an ASCII string (terminated with a carriage return) into a binary value. ATBInst: entity work.ASCIIToBin(beh) port map (clk=>clk, reset=>reset, ready=>ATB_ready, convert_done_tick=>convert_ATB_done_tick, start_convert=>start_ATB_convert, op_binary_val=>ATB_out_operand, dig0=>A0_reg, dig1=>A1_reg, dig2=>A2_reg, dig3=>A3_reg, sign_char=>ATB_sign_char_reg); -- LED is on when '0' is written. If rx_empty is '1' (NO DATA), then it writes a 0 turning ON the led. LED_0 <= A_or_B_reg; LED_1 <= reset; LED_2 <= tx_full; LED_3 <= rx_empty; -- ===================================================================================================== result_binary_val <= std_logic_vector(signed(A_op_reg) + signed(B_op_reg)); -- ===================================================================================================== -- ===================================================================================================== -- ===================================================================================================== -- ===================================================================================================== -- state and register logic process(clk, reset) begin if (reset = '1') then state_reg <= idle; -- This counter used when outputting the result -- counts from 0 to 6, which includes sign -- character, 4 digits of number and carriage return and line feed cnt_reg <= to_unsigned(0, 3); -- Determine which operand (A, B) is loaded with the next set of chars typed by the user. -- Initialize with 1 because this register is inverted in 'clear_chars' state BEFORE the -- actual conversion is completed. So it will be inverted to '0' (the A_op_reg) after the -- user enters the FIRST number. A_or_B_reg <= '1'; -- One ASCII character at a time is read and processed -- this keeps track of which character -- is being entered (1 of 4 positions). char_ptr_reg <= to_unsigned(0, 2); -- The actual character registers A0_reg <= (others => '0'); A1_reg <= (others => '0'); A2_reg <= (others => '0'); A3_reg <= (others => '0'); -- The sign register ATB_sign_char_reg <= (others => '0'); -- The converted binary operands A_op_reg <= (others => '0'); B_op_reg <= (others => '0'); -- Update registers with next state value elsif (clk'event and clk = '1') then state_reg <= state_next; cnt_reg <= cnt_next; A_or_B_reg <= A_or_B_next; char_ptr_reg <= char_ptr_next; A0_reg <= A0_next; A1_reg <= A1_next; A2_reg <= A2_next; A3_reg <= A3_next; ATB_sign_char_reg <= ATB_sign_char_next; A_op_reg <= A_op_next; B_op_reg <= B_op_next; end if; end process; -- ===================================================================================================== -- Combinational Block -- little more involved than I would have liked it but manageable -- ===================================================================================================== process(state_reg, cnt_reg, R0, R1, R2, R3, BTA_ready, convert_BTA_done_tick, but1_pb_stable, BTA_sign_char, A_or_B_reg, char_ptr_reg, rx_empty, ascii_receive_data, A0_reg, A1_reg, A2_reg, A3_reg, ATB_sign_char_reg, A_op_reg, B_op_reg, convert_ATB_done_tick, ATB_out_operand) begin -- Default assignments to wires and registers (latter just preserves current value) state_next <= state_reg; cnt_next <= cnt_reg; ascii_send_data <= R0; start_BTA_convert <= '0'; send_one_byte <= '0'; A_or_B_next <= A_or_B_reg; char_ptr_next <= char_ptr_reg; A0_next <= A0_reg; A1_next <= A1_reg; A2_next <= A2_reg; A3_next <= A3_reg; ATB_sign_char_next <= ATB_sign_char_reg; A_op_next <= A_op_reg; B_op_next <= B_op_reg; start_ATB_convert <= '0'; read_byte <= '0'; case state_reg is -- --------------------------------------- -- ASCII INPUT AND OUTPUT when idle => -- Pushbutton is pressed -- start process of conversion from binary to ASCII, and then -- transmit the bytes through UART to screen if (but1_pb_stable = '1') then -- initialize cnter and start conversion cnt_next <= (others => '0'); state_next <= convert_BTA; end if; -- If the receive buffer has a character, process it if (rx_empty = '0') then -- Skip all characters that are not valid -- only valid chars are carriage return, '-' and '+', -- and numbers '0' through '9'. If character is left over linefeed -- eliminate it -- under -- Linux, this doesn't happen if ( unsigned(ascii_receive_data) = to_unsigned(13, 8) or unsigned(ascii_receive_data) = to_unsigned(character'pos('-'), 8) or unsigned(ascii_receive_data) = to_unsigned(character'pos('+'), 8) or (unsigned(ascii_receive_data) >= to_unsigned(character'pos('0'), 8) and unsigned(ascii_receive_data) <= to_unsigned(character'pos('9'), 8))) then state_next <= get_char; else read_byte <= '1'; end if; end if; -- Monitor for the convert_ATB_done_tick which indicates that a set of characters have -- been converted to a binary value. Save the ASCIIToBin output value (ATB_out_operand) -- into either the A_op or B_op, depending on the value of A_or_B_reg if ( convert_ATB_done_tick = '1' ) then if ( A_or_B_reg = '0' ) then A_op_next <= ATB_out_operand; else B_op_next <= ATB_out_operand; end if; end if; -- --------------------------------------- -- ASCII INPUT: If the user presses a number key, get character and save in one of four A registers -- Also, process '+', '-' and carriage return (13) when get_char => -- Check if the received value is a carriage return -- linefeed are filtered above in idle if ( unsigned(ascii_receive_data) = to_unsigned(13, 8) ) then -- Start ascii to binary conversion -- I should check ATB_ready before I do this but -- I assume there will be plenty of cycles between carriage returns start_ATB_convert <= '1'; -- Last thing to do is clear registers for next operand state_next <= clear_chars; -- If the character received in a '+' or '-', save sign. elsif ( unsigned(ascii_receive_data) = to_unsigned(character'pos('-'), 8) or unsigned(ascii_receive_data) = to_unsigned(character'pos('+'), 8)) then ATB_sign_char_next <= ascii_receive_data; state_next <= idle; -- Else assume it is a number character (0 to 9) -- save it into a corresponding character -- register else char_ptr_next <= char_ptr_reg + 1; -- Create a shift reg -- this allows the user to enter fewer than 4 number characters A3_next <= A2_reg; A2_next <= A1_reg; A1_next <= A0_reg; A0_next <= ascii_receive_data; state_next <= idle; end if; -- Remove the byte from the read buffer read_byte <= '1'; -- --------------------------------------- -- ASCII INPUT: Reset pointer and character registers after the ATB routine has latched and processed -- This gets called one clock cycle AFTER carriage return is received when clear_chars => A_or_B_next <= not A_or_B_reg; char_ptr_next <= to_unsigned(0, 2); A0_next <= (others => '0'); A1_next <= (others => '0'); A2_next <= (others => '0'); A3_next <= (others => '0'); ATB_sign_char_next <= std_logic_vector(to_unsigned(character'pos('+'), 8)); state_next <= idle; -- --------------------------------------- -- --------------------------------------- -- ASCII OUTPUT: Convert the 12-bit binary value to 4 ascii bytes when convert_BTA => if ( BTA_ready = '1' ) then start_BTA_convert <= '1'; end if; -- Wait for conversion from binary to ASCII to finish if ( convert_BTA_done_tick = '1' ) then state_next <= send; end if; -- --------------------------------------- -- ASCII OUTPUT: Load up the FIFO and let the transmitter do its work when send => cnt_next <= cnt_reg + 1; -- sign bit is first. if ( cnt_reg = 0 ) then send_one_byte <= '1'; ascii_send_data <= BTA_sign_char; end if; -- followed by 4 digits if ( cnt_reg = 1 ) then send_one_byte <= '1'; ascii_send_data <= R3; end if; if ( cnt_reg = 2 ) then send_one_byte <= '1'; ascii_send_data <= R2; end if; if ( cnt_reg = 3 ) then send_one_byte <= '1'; ascii_send_data <= R1; end if; if ( cnt_reg = 4 ) then send_one_byte <= '1'; ascii_send_data <= R0; end if; -- carriage return if ( cnt_reg = 5 ) then send_one_byte <= '1'; ascii_send_data <= std_logic_vector(to_unsigned(10, 8)); end if; -- line feed -- exit after the last byte is transmitted if ( cnt_reg = 6 ) then send_one_byte <= '1'; ascii_send_data <= std_logic_vector(to_unsigned(13, 8)); state_next <= done; end if; -- --------------------------------------- -- ASCII OUTPUT: Wait for the user to release the button when done => if (but1_pb_stable = '0') then state_next <= idle; end if; end case; end process; end beh;