-------------------------------------------------------------------------------- -- -- Prawn CPU Benchmark : CPU Behavioral Model -- -- Derived from -- Parwan : a reduced processor -- from Chapter 9 of NAVABI : "VHDL: Analysis and Modeling of -- Digital Systems" McGraw-Hill,Inc. 1993 -- -- Author: Tadatoshi Ishii -- Information and Computer Science, -- University Of California, Irvine, CA 92717 -- -- Developed on Nov 1, 1992 -- -- Verification Information: -- -- Verified By whom? Date Simulator -- -------- ------------ -------- ------------ -- Syntax yes Tadatoshi Ishii 01 Nov 92 Synopsys -- Functionality yes Tadatoshi Ishii 01 Nov 92 Synopsys -------------------------------------------------------------------------------- library synopsys; use synopsys.bv_arithmetic.all; use work.types.all; entity prawn is -- { port ( CLK : in bit; Reset : in bit; read_mem : out bit; write_mem : out bit; databus_i : in bv8; databus_o : out bit_vector(7 downto 0); adbus : out bit_vector(11 downto 0); interrupt : in bit; inta : out bit ); end prawn; -- } architecture prawn of prawn is begin process -- -- declare necessary variables. -- variable pc : bit_vector(11 downto 0); variable ipc : nat8; variable ac : bit_vector(7 downto 0); variable byte1 : bit_vector(7 downto 0); variable byte2 : bit_vector(7 downto 0); variable byte3 : bit_vector(7 downto 0); variable ibyte1 : nat3; variable ibyte3 : nat8; variable i : bit; variable v : bit; variable c : bit; variable n : bit; variable z : bit; variable ns : bit; variable i_status : bit; variable flag : bit_vector(4 downto 0); variable temp : bit_vector(9 downto 0); variable itemp : nat10; variable iac : nat10; variable idbus : nat10; variable icarry : nat10; begin -- { -- -- start process description. -- if (Reset = '1') then -- { -- -- handle reset. -- pc := "000000000000"; databus_o <= "00000000"; adbus <= "000000000000"; read_mem <= '0'; write_mem <= '0'; inta <= '0'; i := '0'; v := '0'; c := '0'; z := '0'; n := '0'; wait until (CLK = '1'); else -- }{ -- -- if there is no reset, execute following part. -- -- check the interrupt request and the interrupt flag. -- if ((interrupt = '1') and (i = '1')) then -- { i_status := '1'; else -- }{ i_status := '0'; end if; -- } flag := i & v & c & z & n; -- -- read first byte into byte1, increment the program counter. -- if interrupt was accepted, -- read first byte of start address of interrupt handling routine. -- adbus <= pc; if (i_status = '1') then inta <= '1'; else read_mem <= '1'; end if; wait until (CLK = '1'); byte1 := databus_i; if (i_status = '1') then inta <= '0'; else read_mem <= '0'; end if; wait until (CLK = '1'); if (i_status = '0') then ipc := bvtoi(pc(7 downto 0)); ipc := ipc + 1; pc(7 downto 0) := itobv(ipc,8); end if; -- -- start decode & execution. -- if (((byte1(7 downto 4) = "1110") or (byte1 (7 downto 0) = "11011111")) and (i_status = '0')) then -- { -- -- execute single-byte instructions. -- if ((byte1(3 downto 2) = "11") or (byte1(7 downto 0) = "11011111") or (byte1(3 downto 0) = "0011") or (byte1(3 downto 0) = "0110")) then -- { -- -- execute single-byte instructions which need stack operations. -- -- read the stack pointer for all instructions -- which need stack operations. -- adbus <= "111111111111"; read_mem <= '1'; wait until (CLK = '1'); byte3 := databus_i; read_mem <= '0'; wait until (CLK = '1'); if (byte1(1) = '1') then -- { -- -- execute instructions which need to pop data from the stack, -- which are POP & POPF & JRT & BRT & IRT. -- adbus <= "1111" & byte3; read_mem <= '1'; wait until (CLK = '1'); if ((byte1 = "11011111") or (byte1(3 downto 0) = "0011") or (byte1(3 downto 0) = "0110")) then -- { -- -- execute return instructions. -- if (byte1(3 downto 0) = "0110") then -- { -- -- pop flags from the stack for IRT, -- increment the stack pointer for popping flags. -- flag := databus_i(4 downto 0); i:=flag(4); v:=flag(3); c:=flag(2); z:=flag(1); n:=flag(0); read_mem <= '0'; wait until (CLK = '1'); ibyte3 := bvtoi(byte3); ibyte3 := ibyte3 + 1; byte3 := itobv(ibyte3,8); adbus <= "1111" & byte3; read_mem <= '1'; wait until (CLK = '1'); end if; -- } -- -- pop offset part of address from the stack -- for all return instructions, -- return to the original(caller) control sequence. -- pc(7 downto 0) := databus_i; if (byte1(3 downto 0) /= "0011") then -- { -- -- pop page part of address from the stack for IRT & JRT, -- increment the stack pointer for popping the address, -- return to the original(caller) control sequence. -- read_mem <= '0'; wait until (CLK = '1'); ibyte3 := bvtoi(byte3); ibyte3 := ibyte3 + 1; byte3 := itobv(ibyte3,8); adbus <= "1111" & byte3; read_mem <= '1'; wait until (CLK = '1'); pc(11 downto 8) := databus_i(3 downto 0); end if; -- } elsif (byte1(0) = '0') then -- }{ -- -- execute POP. -- ac := databus_i; else -- }{ -- -- execute POPF. -- flag := databus_i(4 downto 0); i:=flag(4); v:=flag(3); c:=flag(2); z:=flag(1); n:=flag(0); -- end if; -- } return instructions / POP / POPF -- read_mem <= '0'; wait until (CLK = '1'); -- -- increment the stack pointer -- for all instructions which need pop operation. -- ibyte3 := bvtoi(byte3); ibyte3 := ibyte3 + 1; byte3 := itobv(ibyte3,8); else -- }{ -- -- execute instructions which need to push datum onto the stack, -- which are PUSH & PUSHF. -- -- decrement the stack pointer -- for all instructions which need pop operation. -- ibyte3 := bvtoi(byte3); ibyte3 := ibyte3 - 1; byte3 := itobv(ibyte3,8); wait until (CLK = '1'); adbus <= "1111" & byte3; if (byte1(0) = '0') then -- { -- -- execute PUSH. -- databus_o <= ac; else -- }{ -- -- execute PUSHF. -- databus_o <= "000" & flag; end if; -- } write_mem <= '1'; wait until (CLK = '1'); write_mem <= '0'; wait until (CLK = '1'); -- end if; -- } instructions which need pop / push operations -- -- -- write the stack pointer incremented/decremented -- for all instructions which need stack operations. -- databus_o <= byte3; adbus <= "111111111111"; write_mem <= '1'; wait until (CLK = '1'); write_mem <= '0'; wait until (CLK = '1'); -- databus <= HI_IMP_8; else -- }{ -- -- execute single-byte instructions -- which do not need the stack operations. -- case byte1(3 downto 0) is -- { when "0001" => ac := "00000000"; when "0010" => ac := not ac; if (ac = "000000") then z := '1'; else z := '0'; end if; n := ac(7); when "0100" => c := not c; when "0101" => i := '1'; when "0111" => i := '0'; when "1000" => c := ac(7); ac := ac (6 downto 0) & '0'; n := ac(7); if (c /= n) then v := '1'; else v := '0'; end if; if (ac = "00000000") then z := '1'; else z := '0'; end if; when "1001" => ac := ac(7) & ac(7 downto 1); if (ac = "00000000") then z := '1'; else z := '0'; end if; n := ac(7); when "1010" => ac := ac(6 downto 0) & ac(7); if (ac = "00000000") then z := '1'; else z := '0'; end if; n := ac(7); when "1011" => ac := ac(0) & ac(7 downto 1); if (ac = "00000000") then z := '1'; else z := '0'; end if; n := ac(7); when others => null; end case; -- } -- end if; -- } instructions which need / do not need stack operations -- else -- }{ -- -- execute two-byte instructions. -- -- read second byte into byte2, increment the program counter. -- if interrupt was accepted, -- read second byte of start address of interrupt handling routine. -- adbus <= pc; if (i_status='1') then inta <= '1'; else read_mem <= '1'; end if; wait until (CLK = '1'); byte2 := databus_i; if (i_status='1') then inta <= '0'; else read_mem <= '0'; end if; wait until (CLK = '1'); if (i_status='0') then ipc := bvtoi(pc(7 downto 0)); ipc := ipc + 1; pc(7 downto 0) := itobv(ipc,8); end if; if ((byte1(7 downto 4) = "1100") or (byte1(7 downto 0) = "11111100") or (i_status = '1')) then -- { -- -- execute subroutine instructions/interrupt handling. -- -- read the stack pointer, decrement it. -- adbus <= "111111111111"; read_mem <= '1'; wait until (CLK = '1'); byte3 := databus_i; read_mem <= '0'; wait until (CLK = '1'); ibyte3 := bvtoi(byte3); ibyte3 := ibyte3 - 1; byte3 := itobv(ibyte3,8); wait until (CLK = '1'); if (byte1(7 downto 0) /= "11111100") then -- { -- -- push page part of address onto the stack -- for JRT and interrupt handling, -- increment the stack pointer for pushing the address. -- adbus <= "1111" & byte3; databus_o <= "0000" & pc(11 downto 8); write_mem <= '1'; wait until (CLK = '1'); write_mem <= '0'; wait until (CLK = '1'); ibyte3 := bvtoi(byte3); ibyte3 := ibyte3 - 1; byte3 := itobv(ibyte3,8); end if; -- } -- -- push offset part of address onto the stack -- for subroutine instructions and interrupt handling. -- adbus <= "1111" & byte3; databus_o <= pc(7 downto 0); write_mem <= '1'; wait until (CLK = '1'); write_mem <= '0'; wait until (CLK = '1'); if (i_status = '1') then -- { -- -- push flags onto the stack for interrupt handling, -- decrement the stack pointer for pushing flags -- ibyte3 := bvtoi(byte3); ibyte3 := ibyte3 - 1; byte3 := itobv(ibyte3,8); adbus <= "1111" & byte3; databus_o <= "000" & flag; write_mem <= '1'; wait until (CLK = '1'); write_mem <= '0'; wait until (CLK = '1'); i := '0'; end if; -- } -- -- write the stack pointer decremented -- for subroutine instructions/interrupt handling -- databus_o <= byte3; adbus <= "111111111111"; write_mem <= '1'; wait until (CLK = '1'); write_mem <= '0'; wait until (CLK = '1'); -- databus <= HI_IMP_8; -- -- change the control sequence to the designated address. -- if (byte1(7 downto 0) /= "11111100") then -- { pc := byte1(3 downto 0) & byte2; else -- }{ pc := pc(11 downto 8) & byte2; end if; -- } elsif (byte1(7 downto 4) = "1111") then -- }{ -- -- execute branch instructions. -- if ((byte1(3 downto 0) = "1101") or -- BRA ((byte1(3 downto 0) = "0000") and (n='1')) or -- BRA_N ((byte1(3 downto 0) = "0001") and (n='0')) or -- BRA_NN ((byte1(3 downto 0) = "0010") and (z='1')) or -- BRA_Z ((byte1(3 downto 0) = "0011") and (z='0')) or -- BRA_NZ ((byte1(3 downto 0) = "0100") and (c='1')) or -- BRA_C ((byte1(3 downto 0) = "0101") and (c='0')) or -- BRA_NC ((byte1(3 downto 0) = "0110") and (c='0') and (z='0')) or -- BRA_HI ((byte1(3 downto 0) = "0111") and ((c='1') or (z='1'))) or -- BRA_LO ((byte1(3 downto 0) = "1000") and (v='1')) or -- BRA_V ((byte1(3 downto 0) = "1001") and (v='0')) or -- BRA_NV ((byte1(3 downto 0) = "1010") and (((n='1') and (v='0')) or ((n='0') and (v='1')))) or -- BRA_LT ((byte1(3 downto 0) = "1011") and (((n='0') and (v='0')) or ((n='1') and (v='1')))) or -- BRA_GE ((byte1(3 downto 0) = "1110") and ((z='1') or (((n='1') and (v='0')) or ((n='0') and (v='1'))))) or -- BRA_LE ((byte1(3 downto 0) = "1111") and ((z='0') and(((n='0') and (v='0')) or ((n='1') and (v='1')))))) -- BRA_GT then -- { -- -- change the control sequence to the designated address. -- pc(7 downto 0) := byte2; end if; -- } else -- }{ -- -- execute all other two-byte instructions -- if (byte1(4) = '1') then -- { -- -- use byte1 and byte2 to get destination address. -- adbus(11 downto 8) <= byte1(3 downto 0); adbus(7 downto 0) <= byte2; read_mem <= '1'; wait until (CLK = '1'); byte2 := databus_i; read_mem <= '0'; wait until (CLK = '1'); -- end if; -- } indirect -- if (byte1(7 downto 5) = "100") then -- { -- -- execute JMP instruction, -- change the control sequence to the destination address. -- pc := byte1(3 downto 0) & byte2; elsif (byte1(7 downto 5) = "101") then -- }{ -- -- execute STA instruction, write ac to the destination address. -- adbus <= byte1(3 downto 0) & byte2; databus_o <= ac; write_mem <= '1'; wait until (CLK = '1'); write_mem <= '0'; wait until (CLK = '1'); -- databus <= HI_IMP_8; else -- }{ -- -- read operand for LDA, AND, ADD, SUB. -- -- read the contents of the destination memory onto databus. -- adbus(11 downto 8) <= byte1(3 downto 0); adbus(7 downto 0) <= byte2; read_mem <= '1'; wait until (CLK = '1'); ibyte1 := bvtoi(byte1(7 downto 5)); case ibyte1 is -- { -- -- execute LDA, AND, ADD, and SUB. -- when 0 => ac := databus_i; when 1 => ac := (ac and databus_i); when 2 => iac := bvtoi(ac); idbus := bvtoi(databus_i); if (c = '1') then icarry := 1; else icarry := 0; end if; itemp := iac + idbus + icarry; temp := itobv(itemp,10); ac := temp (7 downto 0); c := temp (8); v := temp (9); when 3 => iac := bvtoi(ac); idbus := bvtoi(databus_i); if (c = '1') then icarry := 1; else icarry := 0; end if; itemp := iac - idbus - icarry; temp := itobv(itemp,10); ac := temp (7 downto 0); c := temp (8); v := temp (9); when others => null; end case; -- } -- -- change zero flag & negative flag. -- if (ac = "00000000") then z := '1'; else z := '0'; end if; n := ac(7); -- -- remove memory from databus; -- read_mem <= '0'; wait until (CLK = '1'); -- end if; -- } JMP / STA / LDA,AND,ADD,SUB -- -- end if; -- } subroutine & interrupt / branch / other two-byte inst's -- -- end if; -- } single-byte / two-byte instructions -- -- end if; -- } reset / otherwise -- end process; -- } end prawn;