library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.gen_pkg.all; entity parser is port ( sys_clk : in std_logic; sys_res_n : in std_logic; -- History p_rget : out std_logic; p_rdone : in std_logic; p_read : in hbyte; p_wtake : out std_logic; p_wdone : in std_logic; p_write : out hbyte; p_finished : out std_logic; -- Scanner do_it : in std_logic; finished : out std_logic ); end entity parser; architecture beh of parser is type PARSER_STATE is (SIDLE, SREAD_NEWNUMBER, SREAD_SPACE_GET, SREAD_SPACE_GET_SIGN, SREAD_SPACE_PROC, SREAD_SPACE_PROC_SIGN, SREAD_OP1, SREAD_OP2, SREAD_SIGN, SREAD_NEXTBYTE, SREAD_CALCNUMBER1, SREAD_CALCNUMBER2, SCALC_1, SCALC_14, SCALC_15, SCALC_2, SWRITE_CHAR0, SWRITE_CHAR1, SWRITE_CHAR2, SWRITE_SIGN1, SWRITE_SIGN2, SDONE, SERROR1, SERROR2, SBLANK1, SBLANK2); signal state_int, state_next : PARSER_STATE; signal z_int, z_next, strich_int, strich_next, wtmp_int, wtmp_next : csigned; signal punkt_int, punkt_next : csigned; signal rbyte_int, rbyte_next : hbyte; signal p_write_int, p_write_next : hbyte; signal p_rget_int, p_rget_next : std_logic; signal p_wtake_int, p_wtake_next : std_logic; signal p_finished_int, p_finished_next : std_logic; signal finished_int, finished_next : std_logic; signal aktop_int, aktop_next : alu_ops; signal opp_int, opp_next : alu_ops; signal opcode_int, opcode_next : alu_ops; signal op1_int, op1_next : csigned; signal op2_int, op2_next : csigned; signal do_calc_int, do_calc_next : std_logic; signal z_sign_next, z_sign_int : std_logic; signal firstz_next, firstz_int : boolean; signal err_next, err_int : hstr_int; signal errc_next, errc_int : hstr_int; -- ALU signal opcode : alu_ops; signal op1 : csigned; signal op2 : csigned; signal op3 : csigned; signal opM : csigned; signal do_calc : std_logic; signal calc_done : std_logic; signal calc_error : std_logic; begin instalu : alu port map ( sys_clk => sys_clk, sys_res_n => sys_res_n, do_calc => do_calc, calc_done => calc_done, calc_error => calc_error, op1 => op1, op2 => op2, op3 => op3, opM => opM, opcode => opcode ); p_write <= p_write_int; p_rget <= p_rget_int; p_wtake <= p_wtake_int; p_finished <= p_finished_int; finished <= finished_int; opcode <= opcode_int; op1 <= op1_int; op2 <= op2_int; do_calc <= do_calc_int; process(sys_clk, sys_res_n) begin if sys_res_n = '0' then state_int <= SIDLE; z_int <= (others => '0'); z_sign_int <= '0'; strich_int <= (others => '0'); punkt_int <= (others => '0'); wtmp_int <= (others => '0'); rbyte_int <= (others => '0'); aktop_int <= ALU_NOP; opp_int <= ALU_NOP; err_int <= 0; errc_int <= HSPALTE_MAX; firstz_int <= true; -- out ports p_rget_int <= '0'; p_write_int <= (others => '0'); p_wtake_int <= '0'; p_finished_int <= '0'; finished_int <= '0'; opcode_int <= ALU_NOP; op1_int <= (others => '0'); op2_int <= (others => '0'); do_calc_int <= '0'; elsif rising_edge(sys_clk) then -- internal state_int <= state_next; z_int <= z_next; z_sign_int <= z_sign_next; strich_int <= strich_next; punkt_int <= punkt_next; wtmp_int <= wtmp_next; rbyte_int <= rbyte_next; aktop_int <= aktop_next; opp_int <= opp_next; err_int <= err_next; errc_int <= errc_next; firstz_int <= firstz_next; -- out ports p_rget_int <= p_rget_next; p_write_int <= p_write_next; p_wtake_int <= p_wtake_next; p_finished_int <= p_finished_next; finished_int <= finished_next; opcode_int <= opcode_next; op1_int <= op1_next; op2_int <= op2_next; do_calc_int <= do_calc_next; end if; end process; -- next state process(do_it, p_rdone, p_wdone, p_read, aktop_int, strich_int, punkt_int, calc_done, wtmp_int, opp_int, z_sign_int, err_int, errc_int, calc_error, op2_int, state_int, p_write_int, z_int, rbyte_int, p_rget_int, opcode_int, op1_int, op3, opM, do_calc_int, firstz_int) function hbyte2csigned (x : hbyte) return csigned is variable y : csigned; begin case x is when x"30" => y := x"00000000"; when x"31" => y := x"00000001"; when x"32" => y := x"00000002"; when x"33" => y := x"00000003"; when x"34" => y := x"00000004"; when x"35" => y := x"00000005"; when x"36" => y := x"00000006"; when x"37" => y := x"00000007"; when x"38" => y := x"00000008"; when x"39" => y := x"00000009"; when others => assert(false) report "hbyte2csigned: shouldn't happen"; end case; return y; end function hbyte2csigned; function csigned2hbyte (x : csigned) return hbyte is variable y : hbyte; begin case x is when x"00000000" => y := x"30"; when x"00000001" => y := x"31"; when x"00000002" => y := x"32"; when x"00000003" => y := x"33"; when x"00000004" => y := x"34"; when x"00000005" => y := x"35"; when x"00000006" => y := x"36"; when x"00000007" => y := x"37"; when x"00000008" => y := x"38"; when x"00000009" => y := x"39"; when others => assert(false) report "csigned2hbyte: shouldn't happen"; end case; return y; end function csigned2hbyte; variable multmp : signed(((2*CBITS)-1) downto 0); variable tmp : csigned; type errstrings is array (natural range 1 to 3) of hstring; constant error_str : errstrings := ( 1 => " Fehler: Division durch Null " & nul, 2 => " Fehler: Syntax " & nul, 3 => " Fehler: Over- bzw. Underflow " & nul ); begin state_next <= state_int; -- internal z_next <= z_int; z_sign_next <= z_sign_int; strich_next <= strich_int; punkt_next <= punkt_int; wtmp_next <= wtmp_int; rbyte_next <= rbyte_int; aktop_next <= aktop_int; opp_next <= opp_int; err_next <= err_int; errc_next <= errc_int; firstz_next <= firstz_int; -- signals p_rget_next <= '0'; p_write_next <= p_write_int; p_wtake_next <= '0'; p_finished_next <= '0'; finished_next <= '0'; opcode_next <= opcode_int; op1_next <= op1_int; op2_next <= op2_int; do_calc_next <= '0'; case state_int is when SIDLE => strich_next <= (others => '0'); punkt_next <= (0 => '1', others => '0'); opp_next <= ALU_NOP; if do_it = '1' then state_next <= SREAD_NEWNUMBER; end if; when SREAD_NEWNUMBER => z_next <= (others => '0'); z_sign_next <= '0'; firstz_next <= true; rbyte_next <= (others => '0'); p_write_next <= (others => '0'); aktop_next <= ALU_NOP; state_next <= SREAD_SPACE_GET; when SREAD_SPACE_GET => p_rget_next <= '1'; if p_rdone = '1' then state_next <= SREAD_SPACE_PROC; end if; when SREAD_SPACE_GET_SIGN => p_rget_next <= '1'; if p_rdone = '1' then state_next <= SREAD_SPACE_PROC_SIGN; end if; when SREAD_SPACE_PROC | SREAD_SPACE_PROC_SIGN => if p_rdone = '0' then case state_int is when SREAD_SPACE_PROC => state_next <= SREAD_SPACE_GET; when SREAD_SPACE_PROC_SIGN => state_next <= SREAD_SPACE_GET_SIGN; when others => assert(false) report "wtf @ state1"; end case; else if p_read = x"2d" and state_int = SREAD_SPACE_PROC then -- vorzeichen? state_next <= SREAD_SIGN; elsif p_read /= x"20" then -- leerzeichen sollen ignoriert werden p_rget_next <= '1'; case state_int is when SREAD_SPACE_PROC => state_next <= SREAD_NEXTBYTE; when SREAD_SPACE_PROC_SIGN => state_next <= SREAD_OP1; when others => assert(false) report "SREAD_SPACE_PROC{,_SIGN}: shouldn't happen"; end case; end if; end if; when SREAD_SIGN => z_sign_next <= '1'; if p_rdone = '0' then state_next <= SREAD_NEXTBYTE; end if; when SREAD_NEXTBYTE => p_rget_next <= '1'; if p_rdone = '1' then state_next <= SREAD_CALCNUMBER1; end if; when SREAD_CALCNUMBER1 => case p_read is -- '+', '-', '*', '/' when x"2B" | x"2D" | x"2A" | x"2F" | x"00" => if firstz_int then err_next <= 2; else state_next <= SREAD_OP1; p_rget_next <= '1'; end if; -- ' ' when x"20" => state_next <= SREAD_SPACE_PROC_SIGN; p_rget_next <= '1'; when others => op1_next <= z_int; opcode_next <= ALU_MUL; op2_next <= to_signed(10,CBITS); firstz_next <= false; do_calc_next <= '1'; end case; if calc_done = '1' then state_next <= SREAD_CALCNUMBER2; end if; when SREAD_CALCNUMBER2 => z_next <= op3 + hbyte2csigned(p_read); if p_rdone = '0' and calc_done = '0' then state_next <= SREAD_NEXTBYTE; end if; when SREAD_OP1 => case p_read is when x"2B" => aktop_next <= ALU_ADD; -- '+' when x"2D" => aktop_next <= ALU_SUB; -- '-' when x"2A" => aktop_next <= ALU_MUL; -- '*' when x"2F" => aktop_next <= ALU_DIV; -- '/' when x"00" => aktop_next <= ALU_DONE; -- '\0' when others => err_next <= 2; end case; state_next <= SREAD_OP2; when SREAD_OP2 => if p_rdone = '0' then state_next <= SCALC_1; end if; when SCALC_1 => if z_sign_int = '1' then tmp := (not z_int) + 1; z_next <= tmp; z_sign_next <= '0'; else tmp := z_int; end if; case opp_int is when ALU_NOP | ALU_ADD | ALU_SUB => case opp_int is when ALU_SUB => -- xst (xilinx) workaround if x"80000000" = tmp then -- vgl. testfall 37 und 38 err_next <= 3; op1_next <= tmp; else op1_next <= (not tmp) + 1; end if; when others => op1_next <= tmp; end case; case aktop_int is when ALU_ADD | ALU_SUB | ALU_DONE => opcode_next <= ALU_ADD; op2_next <= strich_int; when ALU_MUL | ALU_DIV => opcode_next <= ALU_MUL; op2_next <= punkt_int; when others => assert(false) report "SCALC_1/1: shouldn't happen!"; end case; when ALU_MUL | ALU_DIV => case aktop_int is when ALU_ADD | ALU_SUB | ALU_DONE | ALU_MUL | ALU_DIV => op1_next <= punkt_int; opcode_next <= opp_int; op2_next <= tmp; when others => assert(false) report "SCALC_1/2: shouldn't happen!"; end case; when others => assert(false) report "SCALC_1/3: shouldn't happen!"; end case; do_calc_next <= '1'; if calc_done = '1' then case opp_int is -- spezialfall: eine zwischenberechnung wird fuer diese -- kombination benoetigt when ALU_MUL | ALU_DIV => case aktop_int is when ALU_ADD | ALU_SUB | ALU_DONE => state_next <= SCALC_14; when others => state_next <= SCALC_2; end case; when others => state_next <= SCALC_2; end case; end if; when SCALC_14 => -- ueberpruefung kann man sich sparen, da diese ohnehin in -- nextstate gemacht wird. op1_next <= op3; do_calc_next <= '0'; if calc_done = '0' then state_next <= SCALC_15; end if; when SCALC_15 => -- ueberpruefung kann man sich sparen, da diese ohnehin in -- nextstate gemacht wird. opcode_next <= ALU_ADD; op2_next <= strich_int; punkt_next <= (0 => '1', others => '0'); do_calc_next <= '1'; if calc_done = '1' then state_next <= SCALC_2; end if; when SCALC_2 => case opp_int is when ALU_NOP | ALU_ADD | ALU_SUB | ALU_MUL | ALU_DIV => case aktop_int is when ALU_ADD | ALU_SUB | ALU_DONE => if aktop_int = ALU_DONE and op3 < 0 then strich_next <= (not op3) + 1; wtmp_next <= (not op3) + 1; z_sign_next <= '1'; else strich_next <= op3; wtmp_next <= op3; end if; when ALU_MUL | ALU_DIV => punkt_next <= op3; when others => assert (false) report "SCALC_2/1: shouldn't happen!"; end case; when ALU_DONE => null; when others => assert (false) report "SCALC_2/2: shouldn't happen!"; end case; -- aktuelle rechenoperation fuer naechste 'runde' uebernehmen opp_next <= aktop_int; if calc_done = '0' then if aktop_int = ALU_DONE then state_next <= SWRITE_CHAR2; else state_next <= SREAD_NEWNUMBER; end if; end if; when SWRITE_CHAR0 => -- fuer testfall 39 und 40 if strich_int = to_signed(-214748364,CBITS) then op1_next <= to_signed(214748364,CBITS); strich_next <= to_signed(214748364,CBITS); else op1_next <= strich_int; end if; opcode_next <= ALU_DIV; op2_next <= to_signed(10,CBITS); do_calc_next <= '1'; if calc_done = '1' then state_next <= SWRITE_CHAR1; end if; when SWRITE_CHAR1 => do_calc_next <= '1'; p_wtake_next <= '1'; tmp := opM; p_write_next <= csigned2hbyte(tmp); wtmp_next <= op3; if p_wdone = '1' then errc_next <= errc_int - 1; -- ueberpruefung auf -2147483648 fuer testfall 39 und 40 -- x"80000000": xst (xilinx) workaround if strich_int < 10 and strich_int /= x"80000000" then if z_sign_int = '1' then state_next <= SWRITE_SIGN1; else state_next <= SBLANK1; end if; else state_next <= SWRITE_CHAR2; end if; end if; when SWRITE_CHAR2 => strich_next <= wtmp_int; if p_wdone = '0' and calc_done = '0' then state_next <= SWRITE_CHAR0; end if; when SWRITE_SIGN1 => if p_wdone = '0' then state_next <= SWRITE_SIGN2; end if; when SWRITE_SIGN2 => if z_sign_int = '1' then p_wtake_next <= '1'; p_write_next <= x"2D"; else assert(false) report "SWRITE_SIGN: shouldn't happen!"; end if; if p_wdone = '1' then errc_next <= errc_int - 1; state_next <= SDONE; end if; when SBLANK1 => p_wtake_next <= '1'; p_write_next <= x"20"; if p_wdone = '1' then errc_next <= errc_int - 1; if errc_int <= 2 then state_next <= SDONE; else state_next <= SBLANK2; end if; end if; when SBLANK2 => if p_wdone = '0' then state_next <= SBLANK1; end if; when SERROR1 => p_wtake_next <= '1'; p_write_next <= hbyte(to_unsigned (character'pos(error_str(err_int)(errc_int)),8)); if p_wdone = '1' then errc_next <= errc_int - 1; if errc_int <= 2 then state_next <= SDONE; else state_next <= SERROR2; end if; end if; when SERROR2 => if p_wdone = '0' then state_next <= SERROR1; end if; when SDONE => err_next <= 0; errc_next <= HSPALTE_MAX; p_finished_next <= '1'; finished_next <= '1'; if p_wdone = '0' and do_it = '0' then state_next <= SIDLE; end if; end case; -- fehlerbehandlung case state_int is -- diese states sind ausgenommen vom "pokemon-exception-handling" when SERROR1 | SERROR2 | SDONE => null; when others => if calc_error = '1' then if op2_int = 0 then err_next <= 1; else err_next <= 3; end if; end if; if err_int > 0 then state_next <= SERROR1; end if; end case; end process; end architecture beh;