410 likes | 515 Views
Desenvolvimento de um processador (8 bits). Processador. 8 bits de dados e 16 bits de endereço. master. I/O. ROM. RAM. slave. slave. slave. x ”8000” ----------- x ”FFFF”. x ”4000” ----------- x ”7FFF”. x ”0000” ----------- x ”3FFF”.
E N D
Desenvolvimento de um processador (8 bits) Processador 8 bits de dados e 16 bits de endereço master I/O ROM RAM slave slave slave x”8000” ----------- x”FFFF” x”4000” ----------- x”7FFF” x”0000” ----------- x”3FFF” http://www-md.e-technik.uni-rostock.de/lehre/vlsi_i/proc8/index.html.
Package constant data_width : integer := 8; constant addr_width : integer := 16; subtype data_type is integer range 0 to 2** data_width-1 subtype addr_type is integer range 0 to 2** addr_width-1 + outros tipos de dados
Grupos de sinais de interface type bus_slv_in_type is record data : data_type; -- Data in addr : addr_type; -- Address in en : boolean; -- Enable wr : boolean; -- Write end record; type bus_slv_out_type is record data : data_type; -- Data out end record; ------------------------------------------------------ -- RAM (Bus Slave) ----------------------------------------------------- component ram generic ( depth : integer); port ( clk : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type); end component; subtype data_type is integer range 0 to 2** data_width-1 subtype addr_type is integer range 0 to 2** addr_width-1
-- Shift constant SLLi : data_type := 24; -- shift logical left constant SLRi : data_type := 25; -- shift logical right constant ROLi : data_type := 26; -- rotate left constant RORi : data_type := 27; -- rotate right -- Jump constant JMPi : data_type := 32; -- jump to address constant JCi : data_type := 33; -- jump when carry flag is set constant JNCi : data_type := 34; -- jump when carry flag is not set constant JZi : data_type := 35; -- jump when zero flag is set constant JNZi : data_type := 36; -- jump when zero flag is not set ----------------------------------------------------------------------------- -- Memory mapped addresses ----------------------------------------------------------------------------- constant ADDR_LED : addr_type := 0; constant ADDR_SEG : addr_type := 1; constant ADDR_SWITCH : addr_type := 2; ----------------------------------------------------------------------------- -- Processor Flags ----------------------------------------------------------------------------- type flags_type is record c : boolean; -- Carry flag z : boolean; -- Zero flag end record; ----------------------------------------------------------------------------- -- -- Interfaces and Components -- ----------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; package proc_pack is ----------------------------------------------------------------------------- -- Data and address width ----------------------------------------------------------------------------- constant data_width : integer := 8; constant addr_width : integer := 16; subtype data_type is integer range 0 to 2 ** data_width - 1; subtype addr_type is integer range 0 to 2 ** addr_width - 1; ----------------------------------------------------------------------------- -- Opcodes ----------------------------------------------------------------------------- -- NOP constant NOPi : data_type := 0; -- No Operation -- Load and store constant LDAi : data_type := 1; -- load from address to accu constant LDCi : data_type := 2; -- load constant to accu constant STAi : data_type := 3; -- store accu to address constant LDXi : data_type := 8; -- load index register with constant constant INCXi : data_type := 9; -- increment index register constant DECXi : data_type := 10; -- decrement index register -- Arithmetic constant ADDi : data_type := 16; -- add data from address to accu constant SUBi : data_type := 17; -- sub data from address from accu constant NOTi : data_type := 18; -- sub data from address from accu constant ANDi : data_type := 19; -- AND data from address with accu constant ORi : data_type := 20; -- OR data from address with accu constant XORi : data_type := 21; -- XOR data from address with accu
----------------------------------------------------------------------------- ----------------------------------------------------------------------------- -- Bus arbiter ----------------------------------------------------------------------------- component arb generic ( slaves : integer); port ( msti : out bus_mst_in_type; msto : in bus_mst_out_type; slvi : out bus_slv_in_vector(0 to slaves - 1); slvo : in bus_slv_out_vector(0 to slaves - 1)); end component; ----------------------------------------------------------------------------- -- Processor (Bus Master) ----------------------------------------------------------------------------- component proc port ( clk : in std_logic; rst : in std_logic; en : in boolean; busi : in bus_mst_in_type; buso : out bus_mst_out_type); end component; ----------------------------------------------------------------------------- -- RAM (Bus Slave) ----------------------------------------------------------------------------- component ram generic ( depth : integer); port ( clk : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type); end component; ----------------------------------------------------------------------------- -- Bus interface (Master and Slave) ----------------------------------------------------------------------------- type bus_mst_in_type is record data : data_type; -- Data in end record; type bus_mst_out_type is record data : data_type; -- Data out addr : addr_type; -- Address out en : boolean; -- Enable wr : boolean; -- Write end record; type bus_slv_in_type is record data : data_type; -- Data in addr : addr_type; -- Address in en : boolean; -- Enable wr : boolean; -- Write end record; type bus_slv_out_type is record data : data_type; -- Data out end record; type bus_slv_in_vector is array (natural range <>) of bus_slv_in_type; type bus_slv_out_vector is array (natural range <>) of bus_slv_out_type;
---------------------------------------------------------------------------------------------------------------------------------------------------------- -- ROM (Bus Slave) ----------------------------------------------------------------------------- component rom generic ( depth : integer); port ( clk : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type); end component; ----------------------------------------------------------------------------- -- I/O and peripherals (Bus Slave) ----------------------------------------------------------------------------- type io_in_type is record switch : std_logic_vector(7 downto 0); -- External Switches end record; type io_out_type is record seg_low : std_logic_vector(6 downto 0); -- External 7-segment low seg_high : std_logic_vector(6 downto 0); -- External 7-segment high led : std_logic_vector(7 downto 0); -- External LEDs end record; component io generic ( depth : integer); port ( clk : in std_logic; rst : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type; ioi : in io_in_type; ioo : out io_out_type); end component; end proc_pack;
Sistema bus_mst_in_type -- data bus_mst_out_type -- addr -- data -- en -- wr Processador system.vhd Arbiter (arb.vhd) 8 Bit dados e 16 Bit endereço bus_slv_in_type -- addr -- data -- en -- wr -- data bus_slv_out_type -- data I/O ROM RAM io_in_type -- switch io_out_type -- led -- seg LEDs Switches
Processador O projecto: I/O ROM RAM use work.proc_pack.all; entity arb is generic ( slaves : integer := 3); port ( msti : out bus_mst_in_type; msto : in bus_mst_out_type; slvi : out bus_slv_in_vector(0 to slaves - 1); slvo : in bus_slv_out_vector(0 to slaves - 1)); end arb; Os pacotes: master slave slave slave
architecture rtl of arb is begin -- rtl comb : process (msto, slvo) variable slave : integer range 0 to slaves - 1; begin -- process comb -- Check the upper two address bits, and select a slave case msto.addr / (2 ** (addr_width - 2)) is when 0 => slave := 0; -- ROM : 0x0000 - 0x3FFF when 1 => slave := 1; -- RAM : 0x4000 - 0x7FFF when others => slave := 2; -- I/O : 0x8000 - 0xFFFF end case; -- Drive all slave inputs for i in 0 to slaves - 1 loop slvi(i).data <= msto.data; slvi(i).addr <= msto.addr; slvi(i).en <= msto.en and slave = i; slvi(i).wr <= msto.wr; end loop; -- i -- Drive master inputs msti.data <= slvo(slave).data; end process comb; end rtl;
O projecto: entity io is generic ( depth : integer); port ( clk : in std_logic; rst : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type; ioi : in io_in_type; ioo : out io_out_type); end io; architecture rtl of io is -- Registers type reg_type is record ioo : io_out_type; -- registered output buso : bus_slv_out_type;-- registered output end record; -- Signals to registers signal r, rin : reg_type; Os pacotes:
begin -- rtl ----------------------------------------------------------------------------- -- Combinational logic ----------------------------------------------------------------------------- comb: process (r, busi, ioi) variable v : reg_type; begin -- process comb v := r; --------------------------------------------------------------------------- -- Read access --------------------------------------------------------------------------- if busi.en and not busi.wr then case busi.addr mod depth is when ADDR_LED => v.buso.data := to_unsigned_integer(r.ioo.led); when ADDR_SWITCH => v.buso.data := to_unsigned_integer(ioi.switch); when others => null; end case; end if; Ler dados
--------------------------------------------------------------------------- -- Write access --------------------------------------------------------------------------- if busi.en and busi.wr then case busi.addr mod depth is when ADDR_LED => v.ioo.led := to_unsigned_std_logic_vector(busi.data, 8); when ADDR_SEG => v.ioo.seg_high := int2seg((busi.data / 16) mod 16); v.ioo.seg_low := int2seg(busi.data mod 16); when others => null; end case; end if; --------------------------------------------------------------------------- -- Drive registers and signals --------------------------------------------------------------------------- rin <= v; ioo <= r.ioo; buso <= r.buso; end process comb; Escrever dados
---------------------------------------------------------------------------------------------------------------------------------------------------------- -- Registers ----------------------------------------------------------------------------- regs: process (clk, rst) begin -- process regs if rising_edge(clk) then r <= rin; end if; if rst = '1' then r.ioo.seg_low <= (others => '1'); r.ioo.seg_high <= (others => '1'); r.ioo.led <= (others => '0'); end if; end process regs; end rtl;
O projecto: library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; --use IEEE.STD_LOGIC_ARITH.ALL; --use IEEE.STD_LOGIC_UNSIGNED.ALL; use work.macros.all; use work.proc_pack.all; entity proc is port ( clk : in std_logic; rst : in std_logic; en : in boolean; busi : in bus_mst_in_type; buso : out bus_mst_out_type); end proc; Os pacotes:
architecture rtl of proc is -- Processor states type state_type is (fetch_op, -- Fetch opcode fetch_addr_high, -- Fetch address high part fetch_addr_low, -- Fetch address low part execute); -- Execute operation -- Processor registers type reg_type is record state : state_type; -- Processor state pc : addr_type; -- Program counter opcode : data_type; -- Fetched opcode addr : addr_type; -- Fetched address accu : unsigned(data_width - 1 downto 0); -- Accumulator x : data_type; -- Index register flags : flags_type; -- Flags buso : bus_mst_out_type; -- Registered outputs end record; -- Register signals signal r, rin : reg_type; fetch op fetch addr_high execute Instruções de 1 e 2 Bytes fetch addr_low
begin -- rtl ----------------------------------------------------------------------------- -- Combinational Logic ----------------------------------------------------------------------------- comb: process (r, en, busi) -- Variable for register manipulation variable v : reg_type; -- Variable for accu with carry out variable vaccu : unsigned(data_widthdownto 0); begin -- process comb --------------------------------------------------------------------------- -- Default assignments --------------------------------------------------------------------------- v := r;
-- Do not access memory by default v.buso.en := false; -- Do not write by default v.buso.wr := false; if en then -- Access memory v.buso.en := true; -- Address out is mostly program counter value v.buso.addr := r.pc; -- Data out is mostly accumulator value v.buso.data := to_integer(r.accu); -- Program counter is incremented by default v.pc := (r.pc + 1) mod 2**addr_width; --------------------------------------------------------------------------- -- State machine ---------------------------------------------------------------------------
case r.state is when fetch_op => -- Fetch the op code v.opcode := busi.data; -- store the op code case v.opcode is -- and check it when RORi | DECXi | INCXi | NOPi => -- When single byte operation go to execute v.state := execute; -- and halt the program counter v.pc := r.pc; when LDCi | LDXi => -- When two byte operation go to execute v.state := execute; when others => -- otherwise fetch the address v.state := fetch_addr_high; end case; when fetch_addr_high => -- Fetch the high part of the address v.addr := busi.data; -- and store it in address register v.state := fetch_addr_low; when fetch_addr_low => -- Fetch the low part of the address v.addr := to_integer(to_unsigned(r.addr, data_width) & -- combine it with the high part to_unsigned(busi.data, data_width)); -- and store the result in address register v.buso.addr := v.addr; -- Put the address on the bus v.pc := r.pc; -- Halt the program counter case r.opcode is -- check the op code when STAi => -- write to Memory v.buso.wr := true; when JMPi => -- load the address to program counter v.pc := v.addr; when JCi => -- load the address to program counter when carry flag is set if r.flags.c then v.pc := v.addr; end if; when JNCi => -- load the address to program counter when carry flag is not set if not r.flags.c then v.pc := v.addr; end if; when JZi => -- load the address to program counter when zero flag is set if r.flags.z then v.pc := v.addr; end if; when JNZi => -- load the address to program counter when zero flag is not set if not r.flags.z then v.pc := v.addr; end if; when others => null; end case;
v.state := execute; -- go to execute when execute => -- Execute the instruction -- check opcode case r.opcode is when LDCi | LDAi => -- Load data to accumulator v.accu := to_unsigned(busi.data, data_width); when LDXi => -- Load data to index register v.x := busi.data; when ADDi => -- execute addition vaccu := '0' & r.accu + to_unsigned(busi.data, data_width + 1); v.accu := vaccu(data_width - 1 downto 0); -- Assign to accumulator v.flags.c := to_boolean(vaccu(data_width)); -- Assign flags v.flags.z := to_integer(v.accu) = 0; when SUBi => -- execute subtraction vaccu := '0' & r.accu - to_unsigned(busi.data, data_width + 1); v.accu := vaccu(data_width - 1 downto 0); -- Assign to accumulator v.flags.c := to_boolean(vaccu(data_width)); -- Assign flags v.flags.z := to_integer(v.accu) = 0; when ANDi => -- AND and assign to accumulator v.accu := r.accu and to_unsigned(busi.data, data_width); v.flags.z := to_integer(v.accu) = 0; -- Assign flags when RORi => -- Rotate through carry v.accu := to_std_logic(r.flags.c) & r.accu(data_width - 1 downto 1); v.flags.c := to_boolean(r.accu(0)); when DECXi => -- Decrement index register v.x := (r.x - 1) mod 2 ** data_width; v.flags.z := v.x = 0; -- Assign flags when INCXi => -- Increment index register v.x := (r.x + 1) mod 2 ** data_width; v.flags.z := v.x = 0; -- Assign flags when others => null; end case; v.state := fetch_op; -- go to fetch operand end case; end if;
-- Drive register in and signals rin <= v; buso <= r.buso; end process comb; ----------------------------------------------------------------------------- -- Registers FSM MEMORY ----------------------------------------------------------------------------- regs: process (clk, rst) begin -- process regs if rising_edge(clk) then r <= rin; end if; if rst = '1' then r.state <= execute; r.pc <= 0; r.opcode <= NOPi; r.accu <= (others => '0'); r.flags <= (others => false); end if; end process regs; end rtl;
O projecto: library ieee; use ieee.std_logic_1164.all; use work.proc_pack.all; entity rom is generic ( depth : integer := 256); port ( clk : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type); end rom; Os pacotes:
architecture rtl of rom is -- Define your ROM content here type mem_type is array (0 to depth - 1) of data_type; constant mem : mem_type := ( -- Exemplo LDCi, 1, -- load increment (0, 1) STAi, 64, 0, -- store it at 0x4000 (2, 3, 4) LDCi, 48, -- load the value 48 = 3016(5, 6) STAi, 128, ADDR_SEG, -- show on 7-segment (7, 8, 9) SUBi, 64, 0, -- decrement with value at 0x4000 (10, 11,12) JNZi, 0, 7, -- if no carry out repeat at address 7 (13,14,15) STAi, 128, ADDR_SEG, -- load the last value 0 (16,17,18) LDCi, 128, -- load the value 10000000 (19, 20) STAi, 128, ADDR_LED, -- turn on LED(7) (21,22,23) JMPi, 0, 21, -- endless loop to address 21(24,25,26) others => 0); ROM Accumulador 1 0 8000 4000 0000 RAM 64 RAM Accumulador I/O 1 128 0
--constant mem : mem_type := ( ---- load Switch to mem --LDAi, 128, ADDR_SWITCH, -- addr 0,1,2 Load switch to accumulator ---- Operator 1 --STAi, 64, 0, -- addr 3,4,5 ---- Operator 2 --STAi, 64, 1, -- addr 6,7,8 ---- Load mask to accu --LDCi, 240, -- addr 9,10 ---- apply mask to Op1 in order to extract Op1 --ANDi, 64, 0, -- addr 11,12,13 ---- Save OP1 --RORi, -- 14 --RORi, -- 15 --RORi, -- 16 --RORi, -- 17 --STAi, 64, 0, -- addr 18,19,20 0 keeps the most significant 4 bits of switch --LDCi, 15, -- addr 21,22 --ANDi, 64, 1, -- addr 23,24,25 Accumulator keeps the lest significant 4 bits of switch --ADDi, 64, 0, -- addr 26,27,28 Accumulator + register 0 --STAi, 128, ADDR_LED, --JMPi, 0, 0, --others => 0);
begin -- rtl rom_proc: process (clk) begin if rising_edge(clk) then if busi.en then buso.data <= mem(busi.addr mod depth); end if; end if; end process rom_proc; end rtl;
Library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity RAM is generic (AddressBits : positive; DataBits : positive); port (Clock : in STD_LOGIC; WriteAddress : in STD_LOGIC_VECTOR(AddressBits - 1 downto 0); WriteEnable : in STD_LOGIC; DataIn : in STD_LOGIC_VECTOR(DataBits - 1 downto 0); ReadAddress : in STD_LOGIC_VECTOR(AddressBits - 1 downto 0); DataOut : out STD_LOGIC_VECTOR(DataBits - 1 downto 0)); end RAM; architecture Behavioral of RAM is type MemMatrix is array (0 to 2**AddressBits - 1) of STD_LOGIC_VECTOR (DataBits - 1 downto 0); signal Memory : MemMatrix := (others => x"00"); begin process(Clock) begin if rising_edge (Clock) then if WriteEnable = '1' then Memory(conv_integer(WriteAddress)) <= DataIn; end if; DataOut <= Memory(conv_integer(ReadAddress)); end if; end process; end Behavioral; O projecto: Os pacotes:
Arbiter use work.proc_pack.all; entity arb is generic ( slaves : integer := 3); port ( msti : out bus_mst_in_type; msto : in bus_mst_out_type; slvi : out bus_slv_in_vector(0 to slaves - 1); slvo : in bus_slv_out_vector(0 to slaves - 1)); end arb; architecture rtl of arb is begin -- rtl
comb : process (msto, slvo) variable slave : integer range 0 to slaves - 1; begin -- process comb -- Check the the upper two address bits, and select a slave case msto.addr / (2 ** (addr_width - 2)) is when 0 => slave := 0; -- ROM : 0x0000 - 0x3FFF when 1 => slave := 1; -- RAM : 0x4000 - 0x7FFF when others => slave := 2; -- I/O : 0x8000 - 0xFFFF end case; -- Drive all slave inputs for i in 0 to slaves - 1 loop slvi(i).data <= msto.data; slvi(i).addr <= msto.addr; slvi(i).en <= msto.en and slave = i; slvi(i).wr <= msto.wr; end loop; -- i -- Drive master inputs msti.data <= slvo(slave).data; end process comb; end rtl; System
-- ROM, RAM, I/O (Bus slaves) signal slvi : bus_slv_in_vector(0 to 2); signal slvo : bus_slv_out_vector(0 to 2); -- I/O Signals signal ioi : io_in_type; signal ioo : io_out_type; begin -- str ----------------------------------------------------------------------------- -- Clock scaler to slow the processor down ----------------------------------------------------------------------------- scale_clk : process (clk, rst) variable counter : unsigned(log2_ceil(CLK_RATE / TICKS_PER_SECOND) downto 0); begin -- process scale_clk if rising_edge(clk) then counter := counter - 1; if counter(counter'high) = '1' then counter := to_unsigned(CLK_RATE / TICKS_PER_SECOND - 1, counter'length); tick <= true; else tick <= false; end if; end if; if rst = '1' then counter := (others => '0'); tick <= false; end if; end process scale_clk; library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.macros.all; use work.proc_pack.all; entity system is generic ( -- Adjust the "speed" of the processor here. Specifies the number of -- processor clock cycles per second. TICKS_PER_SECOND : integer := 16); port ( clk : in std_logic; rst : in std_logic; -- I/O -- seven-segment display seg_low : out std_logic_vector(6 downto 0); seg_high : out std_logic_vector(6 downto 0); -- LEDs led : out std_logic_vector(7 downto 0); -- Switches switch : in std_logic_vector(7 downto 0)); end system; architecture str of system is -- Processor tick signal tick : boolean; -- Processor (Bus master) signal msti : bus_mst_in_type; signal msto : bus_mst_out_type;
---------------------------------------------------------------------------------------------------------------------------------------------------------- -- Bus arbiter ----------------------------------------------------------------------------- arb_i: arb generic map ( slaves => 3) port map ( msti => msti, msto => msto, slvi => slvi, slvo => slvo); ----------------------------------------------------------------------------- -- Processor (Bus master) ----------------------------------------------------------------------------- proc_i : proc port map ( clk => clk, rst => rst, en => tick, busi => msti, buso => msto); ----------------------------------------------------------------------------- -- ROM (Bus slave 0) ----------------------------------------------------------------------------- rom_i : rom generic map ( depth => 256) port map ( clk => clk, busi => slvi(0), buso => slvo(0)); ----------------------------------------------------------------------------- -- RAM (Bus slave 1) ----------------------------------------------------------------------------- ram_i : ram generic map ( depth => 256) port map ( clk => clk, busi => slvi(1), buso => slvo(1)); ----------------------------------------------------------------------------- -- I/O module (Bus slave 2) ----------------------------------------------------------------------------- io_i : io generic map ( depth => 32) port map ( clk => clk, rst => rst, busi => slvi(2), buso => slvo(2), ioi => ioi, ioo => ioo); ----------------------------------------------------------------------------- -- I/O signals ----------------------------------------------------------------------------- -- LEDs led <= ioo.led; -- Seven-segment display seg_low <= ioo.seg_low; seg_high <= ioo.seg_high; -- Switches ioi.switch <= switch; end str;
ROM -- show on 7-segment STAi, 128, ADDR_SEG, -- increment with value at 0x4000 ADDi, 64, 0, -- if no carry out repeat at address 5 JNCi, 0, 5, -- turn on LED(7) LDCi, 128, STAi, 128, ADDR_LED, -- endless loop to address 19 JMPi, 0, 19, others => 0); begin -- rtl rom_proc: process (clk) begin -- process ram_proc if rising_edge(clk) then if busi.en then buso.data <= mem(busi.addr mod depth); end if; end if; end process rom_proc; end rtl; entity rom is generic ( depth : integer := 256); port ( clk : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type); end rom; architecture rtl of rom is -- Define your ROM content here. type mem_type is array (0 to depth - 1) of data_type; constant mem : mem_type := ( -- load increment LDCi, 1, -- store it at 0x4000 STAi, 64, 0,
RAM library ieee; use ieee.std_logic_1164.all; use work.proc_pack.all; entity ram is generic ( depth : integer := 256); port ( clk : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type); end ram; architecture rtl of ram is -- RAM storage signal type mem_type is array (0 to depth - 1) of data_type; signal mem : mem_type; -- Temporary read address, required for correct synthesis -- Refer to Xilinx XST User Guide for more information. signal addr, read_addr : integer range 0 to depth – 1; begin -- rtl addr <= busi.addr mod depth; ram_proc: process (clk) begin -- process ram_proc if rising_edge(clk) then if busi.en then if busi.wr then mem(addr) <= busi.data; end if; read_addr <= addr; end if; end if; end process ram_proc; buso.data <= mem(read_addr); end rtl;
I/O ----------------------------------------------------------------------------- -- Combinational logic ----------------------------------------------------------------------------- comb: process (r, busi, ioi) variable v : reg_type; begin -- process comb v := r; --------------------------------------------------------------------------- -- Read access --------------------------------------------------------------------------- if busi.en and not busi.wr then case busi.addr mod depth is when ADDR_LED => v.buso.data := to_unsigned_integer(r.ioo.led); when ADDR_SWITCH => v.buso.data := to_unsigned_integer(ioi.switch); when others => null; end case; end if; --------------------------------------------------------------------------- -- Write access --------------------------------------------------------------------------- if busi.en and busi.wr then case busi.addr mod depth is when ADDR_LED => v.ioo.led := to_unsigned_std_logic_vector(busi.data, 8); when ADDR_SEG => v.ioo.seg_high := int2seg((busi.data / 16) mod 16); v.ioo.seg_low := int2seg(busi.data mod 16); when others => null; end case; end if; library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.macros.all; use work.proc_pack.all; entity io is generic ( depth : integer); port ( clk : in std_logic; rst : in std_logic; busi : in bus_slv_in_type; buso : out bus_slv_out_type; ioi : in io_in_type; ioo : out io_out_type); end io; architecture rtl of io is -- Registers type reg_type is record ioo : io_out_type; -- registered output buso : bus_slv_out_type; -- registered output end record; -- Signals to registers signal r, rin : reg_type; begin -- rtl
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -- Drive registers and signals --------------------------------------------------------------------------- rin <= v; ioo <= r.ioo; buso <= r.buso; end process comb; ----------------------------------------------------------------------------- -- Registers ----------------------------------------------------------------------------- regs: process (clk, rst) begin -- process regs if rising_edge(clk) then r <= rin; end if; if rst = '1' then r.ioo.seg_low <= (others => '0'); r.ioo.seg_high <= (others => '0'); r.ioo.led <= (others => '0'); end if; end process regs; end rtl;
Processor fetch op fetch addr_high execute Instruções de 1 e 2 Bytes fetch addr_low
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.macros.all; use work.proc_pack.all; entity proc is port ( clk : in std_logic; rst : in std_logic; en : in boolean; busi : in bus_mst_in_type; buso : out bus_mst_out_type); end proc; architecture rtl of proc is -- Processor states type state_type is (fetch_op, -- Fetch opcode fetch_addr_high, -- Fetch address high part fetch_addr_low, -- Fetch address low part execute); -- Execute operation -- Processor registers type reg_type is record state : state_type; -- Processor state pc : addr_type; -- Program counter opcode : data_type; -- Fetched opcode addr : addr_type; -- Fetched address accu : unsigned(data_width - 1 downto 0); -- Accumulator x : data_type; -- Index register flags : flags_type; -- Flags buso : bus_mst_out_type; -- Registered outputs end record; -- Register signals signal r, rin : reg_type; begin -- rtl ----------------------------------------------------------------------------- -- Combinational Logic ----------------------------------------------------------------------------- comb: process (r, en, busi) -- Variable for register manipulation variable v : reg_type; -- Variable for accu with carry out variable vaccu : unsigned(data_width downto 0); begin -- process comb --------------------------------------------------------------------------- -- Default assignments --------------------------------------------------------------------------- v := r; -- Do not access memory by default v.buso.en := false; -- Do not write by default v.buso.wr := false; if en then -- Access memory v.buso.en := true; -- Address out is mostly program counter value v.buso.addr := r.pc; -- Data out is mostly accumulator value v.buso.data := to_integer(r.accu); -- Program counter is incremented by default v.pc := (r.pc + 1) mod 2**addr_width;
--------------------------------------------------------------------------- -- State machine --------------------------------------------------------------------------- case r.state is -- Fetch the opcode when fetch_op => -- store the opcode v.opcode := busi.data; -- and check it case v.opcode is when RORi | DECXi => -- When single byte operation go to execute v.state := execute; -- and halt the program counter v.pc := r.pc; when LDCi | LDXi => -- When two byte operation go to execute v.state := execute; when others => -- otherwise fetch the address v.state := fetch_addr_high; end case; -- Fetch the high part of the address when fetch_addr_high => -- and store it in address register v.addr := busi.data; v.state := fetch_addr_low; -- Fetch the low part of the address when fetch_addr_low => -- combine it with the high part -- and store the result in address register v.addr := to_integer(to_unsigned(r.addr, data_width) & to_unsigned(busi.data, data_width)) -- Put the address on the bus v.buso.addr := v.addr; -- Halt the program counter v.pc := r.pc; -- check the opcode case r.opcode is when STAi => -- write to Memory v.buso.wr := true; when JMPi => -- load the address to programm counter v.pc := v.addr; when JCi => -- load the address to programm counter when carry flag is set if r.flags.c then v.pc := v.addr; end if; when JNCi => -- load the address to programm counter when carry flag is not set if not r.flags.c then v.pc := v.addr; end if; when JZi => -- load the address to programm counter when zero flag is set if r.flags.z then v.pc := v.addr; end if; when JNZi => -- load the address to programm counter when zero flag is not set if not r.flags.z then v.pc := v.addr; end if; when others => null; end case; -- goto execute v.state := execute;
-- Execute the instruction when execute => -- check opcode case r.opcode is when LDCi | LDAi => -- Load data to accumulator v.accu := to_unsigned(busi.data, data_width); when LDXi => -- Load data to index register v.x := busi.data; when ADDi => vaccu := '0' & r.accu + to_unsigned(busi.data, data_width + 1); -- Assign to accumulator v.accu := vaccu(data_width - 1 downto 0); -- Assign flags v.flags.c := to_boolean(vaccu(data_width)); v.flags.z := to_integer(v.accu) = 0; when ANDi => -- AND and assign to accumulator v.accu := r.accu and to_unsigned(busi.data, data_width); -- Assign flags v.flags.z := to_integer(v.accu) = 0; when RORi => -- Rotate through carry v.accu := to_std_logic(r.flags.c) & r.accu(data_width - 1 downto 1); v.flags.c := to_boolean(r.accu(0)); when DECXi => -- Decrement index register v.x := (r.x - 1) mod 2 ** data_width; -- Assign flags v.flags.z := v.x = 0; when others => null; end case; -- goto fetch operand v.state := fetch_op; end case; end if; --------------------------------------------------------------------------- -- Drive register in and signals --------------------------------------------------------------------------- rin <= v; buso <= r.buso; end process comb; ----------------------------------------------------------------------------- -- Registers ----------------------------------------------------------------------------- regs: process (clk, rst) begin -- process regs if rising_edge(clk) then r <= rin; end if; if rst = '1' then r.state <= execute; r.pc <= 0; r.opcode <= NOPi; r.accu <= (others => '0'); r.flags <= (others => false); end if; end process regs; end rtl;
Testbench use ieee.std_logic_1164.all; use work.macros.all; use work.proc_pack.all; use work.syslog.all; entity system_tb is generic ( -- length of clock period PERIOD : time := 1 sec / CLK_RATE; -- Time after simulation is terminated DURATION : time := 10 sec; -- Processor ticks per second TICKS_PER_SECOND : integer := CLK_RATE / 2); end system_tb; architecture beh of system_tb is -- UUT component component system generic ( TICKS_PER_SECOND : integer); port ( clk : in std_logic; rst : in std_logic; seg_low : out std_logic_vector(6 downto 0); seg_high : out std_logic_vector(6 downto 0); led : out std_logic_vector(7 downto 0); switch : in std_logic_vector(7 downto 0)); end component; -- UUT signals signal clk : std_logic := '0'; signal rst : std_logic := '1'; signal seg_low : std_logic_vector(6 downto 0); signal seg_high : std_logic_vector(6 downto 0); signal led : std_logic_vector(7 downto 0); signal switch : std_logic_vector(7 downto 0) := (others => '0'); begin -- beh ----------------------------------------------------------------------------- -- UUT instance ----------------------------------------------------------------------------- UUT: system generic map ( TICKS_PER_SECOND => TICKS_PER_SECOND) port map ( clk => clk, rst => rst, seg_low => seg_low, seg_high => seg_high, led => led, switch => switch); ----------------------------------------------------------------------------- -- Generate clock ----------------------------------------------------------------------------- clk <= not clk after PERIOD / 2;
---------------------------------------------------------------------------------------------------------------------------------------------------------- -- The test process ----------------------------------------------------------------------------- test: process variable result : integer; begin -- process test -- Generate reset rst <= '1'; wait for 4 * PERIOD; rst <= '0'; -- Wait for LED(7) wait until rising_edge(clk) and led(7) = '1'; -- Terminate simulation syslog_terminate; end process test; ----------------------------------------------------------------------------- -- The time bomb ----------------------------------------------------------------------------- time_bomb: process begin -- process time_bomb -- Wait until the bomb explodes wait for DURATION; -- Give error message and terminate simulation syslog(error, "Program did not finish"); syslog_terminate; end process time_bomb; end beh;
Adicionar uma nova instrução LDA 0x1234, X ; Load value from (0x1234 + X) into accu • Três passos seguintes: • Definir o código de operação em proc_pack.vhd; • Se necessário adicionar um novo estado ao proc.vhd • Adicionar entradas case em estados do processador constant LDAIXi : data_type := 11; -- load from address + x Ver a próxima página -- Execute the instruction when execute => -- check opcode case r.opcode is when LDCi | LDAi | LDAIXi => -- Load data to accumulator v.accu := to_unsigned(busi.data, data_width);
-- Fetch the low part of the address when fetch_addr_low => -- combine it with the high part -- and store the result in address register v.addr := to_integer(to_unsigned(r.addr, data_width) & to_unsigned(busi.data, data_width)); -- Put the address on the bus v.buso.addr := v.addr; -- Halt the program counter v.pc := r.pc; -- check the opcode case r.opcode is when LDAIXi => -- add x to the address and put it on the bus v.buso.addr := v.addr + r.x; when STAi => -- write to Memory v.buso.wr := true;