p align="left">000c41Load R1 000d53Add R3 000e35Store R5 Loop: 000f44Load R4Показати мол. цифру. Показати старшу цифру. Показувати безперервно. 001045Load R5 00118fJump #loop Ясна річ, машинні коди тестової програми мають фіксуватися в VHDL моделі пам'яті програм. Зауважимо, що для виконуваних пар інструкцій з кодами 0х53/0x35 та 0x44/0x8F часовим симулюванням отримано і проаналізовано подані нижче часові діаграми виконання тестової програми. Розробка VHDL моделі процесора Виконаємо розробку VHDL моделі процесора на основі прототипної моделі процесора “Gnome”, що подана роботою [1] мовою ABEL. На відміну від прототипа ми задамо цільову ПЛІС Віртекс-2 з вбудованими елементами RAM і ROM. При цьому об'єднаємо CPU, RAM і ROM до єдиного комп'ютера внутрішньо кристальними шинами, одна з яких є двонаправленою. Розглянемо VHDL текст моделі. -- GNOME micro processor unit LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_unsigned.all; -- interface ENTITY gnome IS PORT ( clk: IN STD_LOGIC;-- clock reset: IN STD_LOGIC;-- reset control input address: OUT STD_LOGIC_VECTOR (6 DOWNTO 0); -- external RAM address data: INOUT STD_LOGIC_VECTOR (7 DOWNTO 0); -- system bus web: OUT STD_LOGIC; -- external RAM active-low write-enable oeb: OUT STD_LOGIC; -- external RAM active-low output-enable sel_ram: out std_logic; carry_out : out std_logic; pc_out: OUT STD_LOGIC_VECTOR (6 DOWNTO 0); ir_out: out std_logic_vector (7 downto 0); acc_out: out std_logic_vector (3 downto 0)); END gnome; -- GNOME processor architecture behavioral description ARCHITECTURE gnome_arch OF gnome IS -- current and next GNOME state-machine state SIGNAL curr_st, next_st: STD_LOGIC_VECTOR (1 DOWNTO 0); -- possible GNOME state-machine states and their definitions CONSTANT FETCH: STD_LOGIC_VECTOR (1 DOWNTO 0) := "00"; -- fetch instruction CONSTANT DECODE: STD_LOGIC_VECTOR (1 DOWNTO 0) := "01"; -- decode CONSTANT EXECUTE: STD_LOGIC_VECTOR (1 DOWNTO 0) := "11"; -- execute -- current and next program counter value SIGNAL curr_pc, next_pc: STD_LOGIC_VECTOR (6 DOWNTO 0); -- current and next accumulator value SIGNAL curr_acc, next_acc: STD_LOGIC_VECTOR (3 DOWNTO 0); -- current and next carry flag value SIGNAL curr_carry, next_carry: STD_LOGIC; -- current and next zero flag value SIGNAL curr_zero, next_zero: STD_LOGIC; -- sum vector for holding adder output SIGNAL sum: STD_LOGIC_VECTOR (4 DOWNTO 0); SIGNAL read: STD_LOGIC; -- 1 when reading RAM SIGNAL write: STD_LOGIC; -- 1 when writing RAM SIGNAL sel_data_ram: STD_LOGIC;-- 1 when accessing R0-R15 SIGNAL jump_pc: STD_LOGIC; -- 1 when overwriting PC SIGNAL inc_pc: STD_LOGIC; -- 1 when incrementing PC SIGNAL ld_ir: STD_LOGIC; -- 1 when loading IR SIGNAL ld_ir_lsn: STD_LOGIC;-- 1 when loading LSN of IR -- ALU operation code possible ALU opcodes SIGNAL alu_op: STD_LOGIC_VECTOR (2 DOWNTO 0); --pass input to output CONSTANT PASS_OP: STD_LOGIC_VECTOR (2 DOWNTO 0):= "001"; CONSTANT ADD_OP: STD_LOGIC_VECTOR (2 DOWNTO 0):= "010"; -- add inputs CONSTANT XOR_OP: STD_LOGIC_VECTOR (2 DOWNTO 0):= "011"; -- XOR inputs CONSTANT AND_OP: STD_LOGIC_VECTOR (2 DOWNTO 0):= "100"; -- test input for 0 CONSTANT SET_CARRY_OP: STD_LOGIC_VECTOR (2 DOWNTO 0) := "101"; --set carry CONSTANT CLR_CARRY_OP: STD_LOGIC_VECTOR (2 DOWNTO 0) := "110"; --clear carry -- current and next instruction register SIGNAL curr_ir, next_ir: STD_LOGIC_VECTOR (7 DOWNTO 0); -- possible instruction opcodes CONSTANT CLEAR_C: STD_LOGIC_VECTOR (7 DOWNTO 0) := "00000000"; CONSTANT SET_C: STD_LOGIC_VECTOR (7 DOWNTO 0) := "00000001"; CONSTANT SKIP_C: STD_LOGIC_VECTOR (7 DOWNTO 0) := "00000010"; CONSTANT SKIP_Z: STD_LOGIC_VECTOR (7 DOWNTO 0) := "00000011"; CONSTANT LOAD_IMM: STD_LOGIC_VECTOR (3 DOWNTO 0) := "0001"; CONSTANT ADD_IMM: STD_LOGIC_VECTOR (3 DOWNTO 0) := "0010"; CONSTANT STORE_DIR:STD_LOGIC_VECTOR (3 DOWNTO 0) := "0011"; CONSTANT LOAD_DIR: STD_LOGIC_VECTOR (3 DOWNTO 0) := "0100"; CONSTANT ADD_DIR: STD_LOGIC_VECTOR (3 DOWNTO 0) := "0101"; CONSTANT XOR_DIR: STD_LOGIC_VECTOR (3 DOWNTO 0) := "0110"; CONSTANT TEST_DIR: STD_LOGIC_VECTOR (3 DOWNTO 0) := "0111"; CONSTANT JUMP: STD_LOGIC := '1'; BEGIN carry_out <= curr_carry; pc_out <= curr_pc; acc_out <= curr_acc; ir_out <= curr_ir; sel_ram <= sel_data_ram; -- external RAM control signals oeb <= NOT(read);-- enable RAM drivers during RAM read operations web <= NOT(write);-- RAM write line (in last half of clock) -- address either the data or program sections of the external RAM address <= "000" & curr_ir(3 DOWNTO 0) WHEN sel_data_ram='1' ELSE curr_pc; -- drive the accumulator contents into the RAM during write operations -- but disable the drivers into high-impedance state at all other times data <= "0000" & curr_acc WHEN write='1' ELSE "ZZZZZZZZ"; -- load the instruction register with a new opcode next_ir <= data WHEN ld_ir='1' ELSE -- or load only the lower 4 bits of the IR with data curr_ir(7 DOWNTO 4) & data(3 DOWNTO 0) WHEN ld_ir_lsn='1' ELSE -- or else don't change the IR curr_ir; -- load the PC with an address to jump to next_pc <= curr_ir(6 DOWNTO 0) WHEN jump_pc='1' ELSE -- or increment the PC curr_pc+1 WHEN inc_pc='1' ELSE -- or else don't change the PC curr_pc; -- this process describes the operations of the ALU PROCESS (alu_op,curr_zero,curr_carry,curr_acc,curr_ir,sum) BEGIN -- set the default values for these signals to avoid synthesis of -- implied latches sum <= "00000"; next_acc <= "0000"; next_carry <= '0'; next_zero <= '0'; CASE alu_op IS WHEN ADD_OP => -- add the accumulator with the lower 4 bits of the IR and the carry sum <= ('0' & curr_acc) + ('0' & curr_ir(3 DOWNTO 0)) + ("0000" & curr_carry); next_acc <= sum(3 DOWNTO 0);-- ACC gets lower 4 bits of the sum next_carry <= sum(4);-- carry is the most significant bit of the sum next_zero <= curr_zero;-- zero flag is not changed WHEN XOR_OP => -- XOR the accumulator with the lower 4 bits of the IR next_acc <= curr_acc XOR curr_ir(3 DOWNTO 0); next_carry <= curr_carry; -- carry flag is not changed next_zero <= curr_zero; -- zero flag is not changed WHEN PASS_OP => -- pass lower 4 bits of IR into ACC next_acc <= curr_ir(3 DOWNTO 0); next_carry <= curr_carry; -- carry flag is not changed next_zero <= curr_zero; -- zero flag is not changed WHEN AND_OP => -- test the ACC for zeroes in unmasked bit positions next_acc <= curr_acc; -- ACC is not changed next_carry <= curr_carry;-- carry is not changed -- zero flag is set if ACC has zeroes where IR has ones next_zero <= NOT( (curr_acc(3) AND curr_ir(3)) OR (curr_acc(2) AND curr_ir(2)) OR (curr_acc(1) AND curr_ir(1)) OR (curr_acc(0) AND curr_ir(0))); WHEN SET_CARRY_OP => -- set the carry bit next_acc <= curr_acc;-- ACC is not changed next_carry <= '1'; next_zero <= curr_zero;-- zero flag is not changed WHEN CLR_CARRY_OP => -- clear the carry bit next_acc <= curr_acc;-- ACC is not changed next_carry <= '0'; next_zero <= curr_zero;-- zero flag is not changed WHEN OTHERS => -- don't do anything for undefined ALU opcodes next_acc <= curr_acc; next_carry <= curr_carry; next_zero <= curr_zero; END CASE; END PROCESS; -- this process describes the transitions of the GNOME state machine -- and sets the control signals that are activated in each state PROCESS(curr_st,curr_carry,curr_zero,curr_ir) BEGIN -- set the default values for these signals to avoid synthesis -- of implied latches sel_data_ram <= '0'; read <= '0'; write <= '0'; ld_ir <= '0'; ld_ir_lsn <= '0'; inc_pc <= '0'; jump_pc <= '0'; alu_op <= "000"; CASE curr_st IS WHEN FETCH => -- fetch an instruction from external RAM sel_data_ram <= '0'; -- select the instruction RAM read <= '1'; -- read from the RAM ld_ir <= '1';-- load the instruction -- register with the opcode inc_pc <= '1'; -- increment the PC -- to the next instruction next_st <= DECODE; -- then decode the -- instruction that was just loaded WHEN DECODE => -- decode the instruction. Actually, this state is used to -- read a direct-address operand from the data section of the -- external RAM and store it in the lower 4 bits of the IR. IF curr_ir(7 DOWNTO 4)=LOAD_DIR THEN sel_data_ram <= '1'; read <= '1'; ld_ir_lsn <= '1'; END IF; IF curr_ir(7 DOWNTO 4)=ADD_DIR THEN sel_data_ram <= '1'; read <= '1'; ld_ir_lsn <= '1'; END IF; IF curr_ir(7 DOWNTO 4)=XOR_DIR THEN sel_data_ram <= '1'; read <= '1'; ld_ir_lsn <= '1'; END IF; IF curr_ir(7 DOWNTO 4)=TEST_DIR THEN sel_data_ram <= '1'; read <= '1'; ld_ir_lsn <= '1'; END IF; next_st <= EXECUTE;-- then execute the instruction WHEN EXECUTE => -- execute the instruction. IF curr_ir=CLEAR_C THEN alu_op <= CLR_CARRY_OP;-- clear the carry flag END IF; IF curr_ir=SET_C THEN alu_op <= SET_CARRY_OP;-- set the carry flag END IF; IF curr_ir=SKIP_C THEN-- skip the next instruction inc_pc <= curr_carry; -- if the carry flag is set END IF; IF curr_ir=SKIP_Z THEN-- skip the next instruction inc_pc <= curr_zero; -- if the zero flag is set END IF; IF curr_ir(7 DOWNTO 4)=LOAD_IMM THEN -- load the ACC with immediate alu_op <= PASS_OP; -- data from the lower 4 bits of IR END IF; IF curr_ir(7 DOWNTO 4)=ADD_IMM THEN -- add the lower 4 bits of the alu_op <= ADD_OP;-- IR to the ACC END IF; IF curr_ir(7)=JUMP THEN -- jump to the address stored in the jump_pc <= '1'; -- lower 7 bits of the IR END IF; IF curr_ir(7 DOWNTO 4)=STORE_DIR THEN
Страницы: 1, 2, 3
|