-------------------------------------------------------------------------- -------------------------------------------------------------------------- -- File Name : viper.v -- Author(s) : Prasad Subbarao and B. Subramanyam -- Affiliation : Laboratory for Digital Design Environments -- Department of Electrical & Computer Engineering -- University of Cincinnati -- Date Created : June 1991 -- Introduction : Behavioral description of the VIPER micro-processor -- written in a synthesizable subset of VHDL. -- Source : Textual description from --- -- W. J. Cullyer, -- "Implementing Safety Critical Systems: -- The VIPER Microprocessor", pp. 1-26, in -- G. Birtwistle and P. A. Subrahmanyam (eds.), -- "VLSI Specification, Verification, and Synthesis", -- Kluwer Academic Publishers, 1988. -- -- -- Modified For Synthesis by Jay(anta) Roy, University of Cincinnati. -- Date Modified : Sept, 91. -- -- Disclaimer : This comes with absolutely no guarantees of any -- kind (just stating the obvious ...) -- -- Acknowledgement : The Distributed Synthesis Systems research at -- the Laboratory for Digital Design Environments, -- University of Cincinnati, is sponsored in part -- by the Defense Advanced Research Projects Agency -- under order number 7056 monitored by the Federal -- Bureau of Investigation under contract number -- J-FBI-89-094. -- -------------------------------------------------------------------------- -------------------------------------------------------------------------- -- This is the description of the VIPER microprocessor. The code has been -- written so that it is fully synthesizable. -- The VIPER microprocessor is a simple microprocessor which consists of -- three 32 bit registers, A (accumulator), X and Y (index registers) and a -- 20 bit program counter, P. There is a single bit register, B, which holds -- the results of comparisons and can be concatenated with registers in shift -- operations. Unique to VIPER is the 'stop' signal from the ALU. Any illegal -- operation, arithmetic overflow or computation of an illegal address causes -- the device to stop and raise an exception. -- All instructions have an identical format and comparisons subsume all other -- operations. -- VIPER has a memory size of 1M bytes each 32 bits wide. -- use STD.TEXTIO.all; entity viper is end viper; use Work.functions.all; architecture viper_microprocessor of viper is -- type memory is array (0 to 1048575) of bit_vector(31 downto 0); type memory is array (0 to 1024) of bit_vector(31 downto 0); type regstr is array (0 to 3) of bit_vector(31 downto 0); -- file S_IN : TEXT is out "results"; signal stop_sim : bit := '0'; begin P1 : process variable mem : memory; -- 1M of memory. Each memory word is 32 bits long -- variable io : memory; -- 1M of io. variable reg : regstr; -- Three registers A{reg(0)}, X{reg(1)}, Y{reg(2)} -- and P{reg(3)}. A is the accumulator -- and X and Y are index registers. All the three -- are 32 bits wide. variable B : bit; -- This is a one bit register which holds the results of -- comparisons. variable STOP : bit; -- This is set whenever any illegal operation is executed variable MAR : bit_vector (19 downto 0); -- This is the address latch variable MBR : bit_vector (31 downto 0); -- This is the memory buffer register variable IR : bit_vector (31 downto 0); -- This is the instruction latch variable temp : bit_vector (32 downto 0); alias temp_no_carry : bit_vector (31 downto 0) is temp(31 downto 0); alias temp_carry : bit is temp(32); -- The instruction format is described below alias rf : bit_vector(1 downto 0) is IR(31 downto 30); -- This is the register select field alias mf : bit_vector(1 downto 0) is IR(29 downto 28); -- This is the memory select field alias df : bit_vector(2 downto 0) is IR(27 downto 25); -- This is the destination select field alias cf : bit is IR(24); -- This is the comparison flag field alias ff : bit_vector(3 downto 0) is IR(23 downto 20); -- This is the function select field alias tail : bit_vector(19 downto 0) is IR(19 downto 0); -- This is the address or offset field variable inc : bit_vector(31 downto 0); -- variable L : Line; procedure register_select(reg_select : out bit_vector(31 downto 0)) is -- This procedure selects one of the four registers depending on the -- value of the rf field. begin case rf is when "00" => reg_select := reg(0); -- read from A when "01" => reg_select := reg(1); -- read from X when "10" => reg_select := reg(2); -- read from Y when "11" => reg_select := reg(3); -- read from P end case; end register_select; procedure memory_select(mem_select : out bit_vector(31 downto 0)) is -- This procedure selects the type of memory addressing based on the value -- of the mf field. variable t : integer; begin case mf is when "00" => mem_select := "000000000000" & tail; when "01" => mem_select := mem(bits_to_int(tail)); when "10" => t := bits_to_int(reg(1)) + bits_to_int(tail); mem_select := mem(t); when "11" => t := bits_to_int(reg(2)) + bits_to_int(tail); mem_select := mem(t); end case; end memory_select; -- procedure io_select(inpout_select : out bit_vector(31 downto 0)) is -- This procedure selects the type of io addressing based on the value -- of the mf field. -- variable t : integer; -- begin -- case mf is -- when "00" => inpout_select := "000000000000" & tail; -- when "01" => inpout_select := io(bits_to_int(tail)); -- when "10" => t := bits_to_int(reg(0)) + bits_to_int(tail); -- inpout_select := io(t); -- when "11" => t := bits_to_int(reg(2)) + bits_to_int(tail); -- inpout_select := io(t); -- end case; -- end io_select; procedure shr (data : inout bit_vector( 31 downto 0); result : out bit_vector(31 downto 0)) is -- shift right, copy sign. (Changed from the simulatable version) begin data := data / 2; result := data; end shr; procedure shrb (data : inout bit_vector(31 downto 0); b : in bit;result : out bit_vector(31 downto 0)) is -- shift right through B. (Changed from the simulatable version) alias data_31 : bit is data(31); begin data := data / 2; data_31 := b; result := data; end shrb; procedure shl (data : inout bit_vector(31 downto 0); result : out bit_vector(31 downto 0)) is -- shift left, stop on overflow. (Changed from the simulatable version) alias data_31 : bit is data(31); begin if data_31 = '1' then STOP := '1'; else STOP := '0'; end if; data := data * 2; result := data; end shl; procedure shlb (data : inout bit_vector(31 downto 0); b : out bit;result : out bit_vector(31 downto 0)) is -- shift left through B. (Changed from the simulatable version) alias data_31 : bit is data(31); begin b := data_31; data := data * 2; result := data; end shlb; procedure write_mem is -- This procedure write the contents of a register into memory. variable r : bit_vector (31 downto 0); variable m : integer; begin register_select(r); case mf is when "00" => m := bits_to_int(tail); when "01" => m := bits_to_int(tail); when "10" => m := bits_to_int(reg(1)) + bits_to_int(tail); when "11" => m := bits_to_int(reg(2)) + bits_to_int(tail); end case; mem(m) := r; end write_mem; procedure write_io is -- This procedure write the contents of a register into io. -- variable r : bit_vector (31 downto 0); -- variable m : integer; begin -- register_select(r); -- case mf is -- when "00" => m := bits_to_int(tail); -- when "01" => m := bits_to_int(tail); -- when "10" => m := bits_to_int(reg(0)) + bits_to_int(tail); -- when "11" => m := bits_to_int(reg(2)) + bits_to_int(tail); -- end case; -- io(m) := r; end write_io; procedure destination (d : out integer) is -- This procedure selects the the destination register. An index(d) is returned -- by this procedure. The index can have four values. Depending on the value -- of d (3, 2, 1, or 0), the destination register is P{reg(3)}, Y{reg(2)}, -- X{reg(1)} or A{reg(0)}. begin if df = "101" then if not(B) = '1' then d := 3; end if; elsif df = "100" then if B = '1' then d := 3; end if; elsif df = "011" then d := 3; elsif df = "010" then d := 2; elsif df = "001" then d := 1; elsif df = "000" then d := 0; end if; end destination; procedure comparison is -- compare instructions -- This procedure handles the compare instructions. There are 15 such -- instructions in VIPER. Each of the compare instructions compares the -- contents of a register(r) and a memory element(m) and the B register is set -- or reset depending on the success or the failure of the comparison. variable r,m : bit_vector (31 downto 0); alias r_31 : bit is r(31); begin register_select(r); memory_select(m); case ff is when "0000" => if r < m then -- this inst checks -- for r less than m B := '1'; else B := '0'; end if; when "0001" => if not(r < m) then -- this inst checks for -- r greater than or equal to m B := '1'; else B := '0'; end if; when "0010" => if r = m then -- this inst checks for -- r equal to m B := '1'; else B := '0'; end if; when "0011" => if not(r = m) then -- this inst checks for -- r not equal to m B := '1'; else B := '0'; end if; when "0100" => if not( r > m) then -- this inst checks for -- r less than or equal to m B := '1'; else B := '0'; end if; when "0101" => if r > m then -- this inst checks for -- r greater than m B := '1'; else B := '0'; end if; when "0110" => r_31 := '0'; -- r is made positive. -- this inst checks for -- abs(r) < m. if (bits_to_int(r) < bits_to_int(m)) then B := '1'; else B := '0'; end if; when "0111" => r_31 := '0'; -- r is made positive -- this inst checks for -- abs(not(r)) < m if (not(bits_to_int(r) < bits_to_int(m))) then B := '1'; else B := '0'; end if; when "1000" => if (r < m) or ( B = '1') then -- this inst checks for -- r less than m OR B set B := '1'; else B := '0'; end if; when "1001" => if not(r < m) or ( B = '1') then -- this inst checks for -- r greater than or equal -- to m OR B set B := '1'; else B := '0'; end if; when "1010" => if (r = m) or ( B = '1') then -- this inst checks for -- r equal to m OR B set B := '1'; else B := '0'; end if; when "1011" => if not(r = m) or ( B = '1') then -- this inst checks for -- r not equal m OR B set B := '1'; else B := '0'; end if; when "1100" => if not(r > m) or (B = '1') then -- this inst checks for -- r less than or equal to -- m OR B set B := '1'; else B := '0'; end if; when "1101" => if (r > m) or (B = '1') then -- this inst checks for -- r greater than m OR B -- set B := '1'; else B := '0'; end if; when "1110" => r_31 := '0'; -- make r positive if ((bits_to_int(r)) < bits_to_int(m)) or ( B = '1') then -- this inst checks for abs(r) -- less than m OR B set B := '1'; else B := '0'; end if; when "1111" => r_31 := '0'; -- make r positive if (not((bits_to_int(r)) < bits_to_int(m))) or ( B = '1') then -- this inst checks for abs(not(r)) -- less than m OR B set B := '1'; else B := '0'; end if; end case; end comparison; procedure not_comparison is -- This procedure handles the not compare instructions. The value of df -- decides the destination of the results. variable r,m,t: bit_vector (31 downto 0); variable d : integer; variable temp : bit_vector(32 downto 0); alias temp_no_carry : bit_vector(31 downto 0) is temp(31 downto 0); alias temp_carry : bit is temp(32); begin if not((df = "111") or (df = "110")) then register_select(r); destination(d); case ff is when "0000" => memory_select(m); -- negate m t := X"0000_0000"; temp := t - m; reg(d) := temp_no_carry; when "0001" => memory_select(m); -- call reg(2) := reg(3); reg(3) := m; when "0010" => memory_select(m); -- read from peripheral reg(d) := m; when "0011" => memory_select(m); -- read from memory reg(d) := m; STOP := '1'; when "0100" => memory_select(m); -- add r and m and store carry in B temp := r + m; reg(d) := temp_no_carry; B := temp_carry; when "0101" => memory_select(m); -- add r and m and stop on overflow temp := r + m; reg(d) := temp_no_carry; if temp_carry = '1' then STOP := '1'; else STOP := '0'; end if; when "0110" => memory_select(m); -- subtract r and m and store -- borrow in B temp := r - m; reg(d) := temp_no_carry; B := temp_carry; when "0111" => memory_select(m); -- subtract r and m and stop on -- overflow temp := r - m; reg(d) := temp_no_carry; if temp_carry = '1' then STOP := '1'; else STOP := '0'; end if; when "1000" => memory_select(m); -- XOR r and m reg(d) := (r and (not(m))) or (not(r) and m); when "1001" => memory_select(m); -- AND r and m reg(d) := r and m; when "1010" => memory_select(m); -- NOR r and m reg(d) := not( r or m); when "1011" => memory_select(m); -- AND r and NOT(m) reg(d) := r and (not(m)); when "1100" => case mf is when "00" => shr(r,reg(d)); -- shift right r. -- copy the sign bit when "01" => shrb(r,B,reg(d)); -- shift right r thru' b when "10" => shl(r,reg(d)); -- shift left r and stop -- on overflow when "11" => shlb(r,B,reg(d)); -- shift left r through b end case; when "1101" => STOP := '1'; -- illegal instruction when "1110" => STOP := '1'; -- illegal instruction when "1111" => STOP := '1'; -- illegal instruction end case; elsif df = "111" then write_mem; elsif df ="110" then write_io; end if; end not_comparison; procedure decod is -- This procedure starts the decoding by checking the cf field begin case cf is when '1' => comparison; when '0' => not_comparison; end case; end decod; procedure read is -- This procedure reads from memory the value pointed to by MAR.The MAR is -- to the value of the first 20 bits of reg(3). begin MBR := mem(bits_to_int(MAR)); end read; variable reg_P : Bit_Vector(31 downto 0); alias from_P_19 : Bit_Vector (19 downto 0) is reg_P(19 downto 0); begin mem(0) := X"1100_0010"; -- checks reg(0) < mem(15) mem(1) := X"1130_0010"; -- checks reg(0) <> mem(15) mem(2) := X"1570_0010"; -- checks unsigned(reg(2)) >= mem(15) --mem(2) := X"9570_0010"; -- checks unsigned(reg(2)) >= mem(15) mem(3) := X"53a0_0010"; -- checks X = mem(15) OR B set mem(4) := X"05f0_0007"; -- checks unsigned(reg(2)) >= 7 -- (immediate data) OR B set --mem(4) := X"85f0_0007"; -- checks unsigned(reg(2)) >= -- 7(immediate data) OR B set mem(5) := X"1000_000f"; -- reg(0) = negate(mem(15)) mem(6) := X"1440_000f"; -- reg(2) = reg(2) + mem(15); B = carry --mem(6) := X"9440_000f"; -- reg(2) = reg(2) + mem(15); B = carry mem(7) := X"5260_000f"; -- reg(1) = reg(1) - mem(15); B = borrow mem(8) := X"5280_000f"; -- reg(1) = reg(3) XOR mem(15) --mem(8) := X"d280_000f"; -- reg(1) = reg(3) XOR mem(15) mem(9) := X"04c0_0000"; -- reg(2) = shift right(reg(2)) --mem(9) := X"84c0_0000"; -- reg(2) = shift right(reg(2)) mem(10) := X"34c0_0000"; -- reg(2) = shift left (reg(2)) thru' B --mem(10) := X"b4c0_0000"; -- reg(2) = shift left (reg(2)) thru' B mem(15) := X"0000_0001"; reg(0) := X"0000_0003"; reg(1) := X"0000_0001"; reg(2) := X"0000_0002"; reg(3) := X"0000_0000"; inc := X"0000_0008"; STOP := '0'; --write(L,string'(" R E S U L T S")); --writeline(S_IN, L); while (STOP = '0') and not (reg(3) > X"0000_0008") loop reg_P := reg(3); MAR := from_P_19; read; wait for 1 ns; IR := MBR; temp := inc + reg(3); reg(3) := temp_no_carry; decod; -- write(L,string'("Reg A{reg(0)} = "));write ( L,reg(0)); -- writeline(S_IN, L); -- write(L,string'("Reg X{reg(1)} = "));write ( L,reg(1)); -- writeline(S_IN, L); -- write(L,string'("Reg Y{reg(2)} = "));write ( L,reg(2)); -- writeline(S_IN, L); -- write(L,string'("Reg P{reg(3)} = "));write ( L,reg(3)); -- writeline(S_IN, L); -- write(L,string'("Reg B = "));write ( L,B); -- writeline(S_IN, L); -- write(L,string'(" ")); -- writeline(S_IN, L); end loop; stop_sim <= '1'; end process; stop : process begin wait until stop_sim = '1'; assert false report "stopping stimulation" severity failure; end process ; end viper_microprocessor;