680 likes | 789 Views
未经作者允许,请勿发布该文档! yingqichen@sjtu.edu.cn. VHDL. Simulation & Synthesis. CPU.vhd (Simple Behavior Model).
E N D
未经作者允许,请勿发布该文档!yingqichen@sjtu.edu.cn 未经作者允许,请勿发布该文档!yingqichen@sjtu.edu.cn
VHDL Simulation & Synthesis
CPU.vhd (Simple Behavior Model) LIBRARY ieee;USE ieee.std_logic_1164.ALL;USE work.bv_math.ALL;USE work.cpu8pac.ALL;ENTITY cpu IS...END cpu;ARCHITECTURE version1 OF cpu ISBEGINclock_gen : PROCESS BEGIN ... END PROCESS; main_sequence : PROCESS BEGIN IF reset = '1' THEN --initialisation ... ELSE --fetchinstruction ... --incrementprogramcounter ... --execute CASE inst_reg IS WHEN add => acca := acca + accb; WHEN subr => acca := acca - accb; ... ... END CASE; END IF; END PROCESS main_sequence; END version1; this Model Cannot Be Synthesis
CPU.vhd (Diagram) memrd memwr CPU Program counter reset pc Register of ALU pc address acca accb data acca accb Store Instruction inst_reg inst_reg Store Operator mar mar
CPU • Clock Generate • Reset • Instruction Processing • Fetch Instruction From Memory • Analysis & Execute Instruction • Simple Arithmetic Operation • Data Transfer Operation • Jump Instruction
LIBRARY ieee;USE ieee.std_logic_1164.ALL;USE work.bv_math.ALL;USE work.cpu8pac.ALL;ENTITY cpu IS...END cpu;ARCHITECTURE version1 OF cpu ISBEGINclock_gen : PROCESS BEGIN ... END PROCESS; main_sequence : PROCESS BEGIN IF reset = '1' THEN --initialisation ... ELSE --fetchinstruction ... --incrementprogramcounter ... --execute CASE inst_reg IS WHEN add => acca := acca + accb; WHEN subr => acca := acca - accb; ... ... END CASE; END IF; END PROCESS main_sequence; END version1; CPU Structure • Clock Generate • Reset • Instruction Processing • Fetch Instruction From Memory • Incensement Program Counter • Analysis & Execute Instruction • Simple Arithmetic Operation • Data Transfer Operation • Jump Instruction
Clock Generator clock_gen : PROCESS BEGIN clock <= '1','0' AFTER cycle_time/2; WAIT FOR cycle_time; ENDPROCESS; cycle_time/2 cycle_time/2
Reset IF reset = '1' THENmemrd <= '1';memwr <= '1';pc := (OTHERS => '0');address <= (OTHERS => 'Z');data <= (OTHERS => 'Z'); WAIT UNTIL rising_edge(clock);ELSE …
Fetch Instruction & increase PC clock --fetch phase address <= To_StdlogicVector(pc); WAIT FOR cycle_time/4; memrd <= '0'; WAIT FOR cycle_time/2; memrd <= '1'; --read instruction inst_reg := To_bitvector(data(7 DOWNTO 4)); --load page address mar(11 DOWNTO 8) := To_bitvector(data(3 DOWNTO 0)); --increment program counter pc := inc_bv(pc); --wait until end of cycle WAIT UNTIL rising_edge(clock); address data memrd Read inst_reg, mar(11~8), increase pc at this monent Page address (will be used in load/store instruction)
Execute Instruction (Arithmetic Instruction) --execute CASE inst_reg IS WHEN add => acca := acca + accb; -- add WHEN subr => acca := acca - accb; -- subtraction WHEN inc => acca := inc_bv(acca); -- increment WHEN dec => acca := dec_bv(acca); -- decrement WHEN land => acca := acca AND accb; -- logical and WHEN lor => acca := acca OR accb; -- logical or WHEN cmp => acca := NOT acca; -- complement WHEN lxor => acca := acca XOR accb; -- logical xor WHEN lita => acca := acca; -- ??? WHEN litb => acca := accb; -- WHEN clra => acca := (OTHERS => '0'); -- Clear to acca 0 WHEN …
ELSE WAIT FOR cycle_time/8; IF inst_reg = sta THEN --ouput data data <= To_StdlogicVector(acca); ELSE --ouput data data <= To_StdlogicVector(accb); END IF; WAIT FOR cycle_time/8; memwr <= '0'; WAIT FOR cycle_time/2; memwr <= '1'; WAIT FOR cycle_time/8; data <= (OTHERS => 'Z'); --wait until end of cycle WAIT UNTIL rising_edge(clock); END IF; WHEN jmp => … Execute Instruction (Load & Store Instruction) WHEN lda|ldb|sta|stb => address <= To_StdlogicVector(pc); WAIT FOR cycle_time/4; memrd <= '0'; WAIT FOR cycle_time/2; memrd <= '1'; --read page offset address mar(7 DOWNTO 0) := To_bitvector(data); --increment program counter pc := inc_bv(pc); --wait until end of cycle WAIT UNTIL rising_edge(clock); --output address of operand address <= To_StdlogicVector(mar); IF ((inst_reg = lda) OR (inst_reg = ldb)) THEN WAIT FOR cycle_time/4; memrd <= '0'; WAIT FOR cycle_time/2; memrd <= '1'; IF inst_reg = lda THEN --load accumulator a from bus acca := To_bitvector(data); ELSE --load accumulator b from bus accb := To_bitvector(data); END IF; --wait until end of cycle WAIT UNTIL rising_edge(clock); Get address offset(page address mar(8~11) is got in the fetching instruction step)
Execute Instruction (Load & Store Instruction Waveform) clock Addressdatamemrd clock Addressdatamemrd accabcca accabcca pc mar mar pc Load Store
Jump Instruction WHEN jmp => address <= To_StdlogicVector(pc); --transfer page address to pc from mar pc(11 DOWNTO 8) := mar(11 DOWNTO 8); --read in offset address WAIT FOR cycle_time/4; memrd <= '0'; WAIT FOR cycle_time/2; memrd <= '1'; pc(7 DOWNTO 0) := To_bitvector(data); --wait until end of cycle WAIT UNTIL rising_edge(clock); END CASE; END IF; Update high 4 bits using mar (value in mar is the jump page address) Update low 8 bits using the value on the data bus
8051 • Design File Origination • Top File • Test Platform • 8051 Modules
Key Feature • Fully synchronous design • Instruction set compatible to the industry standard8051microcontroller • Optimized architecture enables fast onetofourclocksperOPcode • Up to 10timesfaster due to completely newarchitecture • User selectablenumberoftimers/counters as well as serialinterface units • Active timer/counter and serial interface units selectable via additional special • function register • Optional implementation of the multiplycommand (MUL) using a parallel multiplierunit • Optional implementation of the dividecommand (DIV) using a paralleldivider unit • Optional implementation of the decimal adjustment command (DA) • NomultiplexedI/O ports • 256 bytes internal RAM, up to 64 Kbytes ROM and up to 64 Kbytes RAM • Source code available freeofcharge under the GNU LGPL license • Technologyindependent, clearstructured, wellcommentedVHDLsourcecode • Easily expandable by adapting/changing VHDL source code • Parameterizeable via VHDL constants
Directory • Docu document • Mism Modelsim Files • Mc8051_compile.do Script to compile vhdl code under Modelsim • Mc8051_sim.do Script to simulate the model in Modelsim • Synpl • Mc8051_core.prj Project file for Synpilfy • Tb Test bench files • Vhdl vhdl design files
File Name in dir ‘vhdl’ • Xxxxxxxx_.vhd Entity definition • Xxxxxxxx_struc.vhd Structure architecture model, all “port map” clauses • Xxxxxxxx_rtl.vhd RTL architecture model • Xxxxxxxx_cfg.vhd Configuration file
mc8051_top_struc.vhd architecture struc of mc8051_top is begin i_mc8051_core : mc8051_core port map( ... ); i_mc8051_ram : mc8051_ram port map ( ... ); i_mc8051_rom : mc8051_rom port map ( ... ); i_mc8051_ramx : mc8051_ramx port map ( ... ); end struc;
mc8051_top_struc.vhd (Block Diagram) i_mc8051_alu i_mc8051_core i_mc8051_tmrcnt i_mc8051_siu
mc8051_control_struc.vhd i_control_mem i_control_fsm
Ram (Entity) library IEEE;use IEEE.std_logic_1164.all;use IEEE.std_logic_arith.all;------------------------ ENTITY DECLARATION -------------------------entity mc8051_ram is port (clk : in std_logic; -- clock signal reset : in std_logic; -- reset signal ram_data_i : in std_logic_vector(7 downto 0); -- data input ram_data_o : out std_logic_vector(7 downto 0); -- data output ram_adr_i : in std_logic_vector(6 downto 0); -- adresses ram_wr_i : in std_logic; -- read=0, write=1 ram_en_i : in std_logic); -- inactive=0;active=1 end mc8051_ram;
clk reset Ram Block Diagram ram_adr_i integer ram_adr_i ram_data_o … ram_data_i ram_wr_i ram_en_i
Ram (Read) architecture sim of mc8051_ram is type ram_type is array (127 downto 0) of unsigned(7 downto 0); signal gpram: ram_type; -- general purpose RAM begin ---------- ram_read ---------- p_read : process (clk, reset) begin if reset='1' then ram_data_o <= "00000000"; else if Rising_Edge(clk) then ram_data_o <= std_logic_vector(gpram(conv_integer(unsigned(ram_adr_i)))); end if; end if; end process p_read;
Ram (Write) ---------- ram_write ---------- p_write : process (clk, reset, ram_en_i) begin if reset='1' then gpram <= (others => (others =>'0')); -- reset every bit else if Rising_Edge(clk) then if ((ram_en_i='1') and (ram_wr_i='1')) then gpram(conv_integer(unsigned(ram_adr_i))) <= unsigned(ram_data_i); end if; end if; end if; end process p_write; end sim;
Ramx (Entity) library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; ------------------------ ENTITY DECLARATION ------------------------- entity mc8051_ramx is port (clk : in std_logic; -- clock signal reset : in std_logic; -- reset signal ram_data_i : in std_logic_vector(7 downto 0); -- data input ram_data_o : out std_logic_vector(7 downto 0); -- data output ram_adr_i : in std_logic_vector(15 downto 0); -- adresses ram_wr_i : in std_logic); -- read=0, write=1 end mc8051_ramx;
Ramx (Architecture) architecture sim of mc8051_ramx is type ram_type is array (65535 downto 0) of bit_vector(7 downto 0); begin p_readwrite : process (clk, reset) variable gpram: ram_type; -- general purpose RAM begin if reset='1' then ram_data_o <= "00000000"; gpram := (others => (others =>'0')); -- reset every bit else if Rising_Edge(clk) then ram_data_o <= to_stdlogicvector(gpram(conv_integer(unsigned(ram_adr_i)))); if ram_wr_i='1' then gpram(conv_integer(unsigned(ram_adr_i))) := to_bitvector(ram_data_i); end if; end if; end if; end process p_readwrite; end sim;
Rom (Entity) library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_textio.all; library STD; use STD.textio.all; ------------------------ ENTITY DECLARATION ------------------------- entity mc8051_rom is generic (c_init_file : string := "mc8051_rom.dua"); port (clk : in std_logic; -- clock signal reset : in std_logic; -- reset signal rom_data_o : out std_logic_vector(7 downto 0); -- data output rom_adr_i : in std_logic_vector(15 downto 0)); -- adresses end mc8051_rom;
clk reset Ram Block Diagram rom_adr_i integer rom_adr_i rom_data_o … rom_en_i
Rom (Architecture) architecture sim of mc8051_rom is type rom_type is array (65535 downto 0) of bit_vector(7 downto 0); signal s_init : boolean := false;Begin---------- rom_read ----------p_read : process (clk, reset, rom_adr_i) variable v_loop : integer; variable v_line : line; variable v_rom_data : rom_type;file f_initfile : text is in c_init_file; begin if (not s_init) thenv_loop := 0; while ((not endfile(f_initfile) and (v_loop < 65535))) loop readline(f_initfile,v_line); read(v_line,v_rom_data(v_loop)); v_loop := v_loop + 1; end loop; s_init <= true; end if;if (clk'event and (clk = '1')) then -- rising clock edge rom_data_o <= to_stdlogicvector(v_rom_data(conv_integer(unsigned(rom_adr_i)))); end if; end process p_read; end sim;
Testbench -- system clock definition p_clock : process variable v_loop1 : integer; begin clk <= '0'; wait for one_period/2; while true loop clk <= not clk; wait for one_period/2; end loop; end process p_clock; -------------------------------------- end sim; architecture sim of tb_mc8051_top is function FUNC_PULLUP (signal s_bidir_line : in std_logic) return std_logic is …end FUNC_PULLUP; begin i_mc8051_top : mc8051_top portmap (…); gen_portmodel : for i in 0 to 7 generate … endgenerate; p_run : process begin … reset <= '1'; wait for one_period + one_period/2 + 5 ns; reset <= '0'; wait for one_period * 5000; wait for one_period / 2; assert false report "END OF SIMULATION" severity failure; endprocess p_run;
Test Bench ROM CPU RAM Reset Clock
Configurable Mudules mc8051_p.vhd ------------------------------------------------------------------------------- Select how many timer/counter units should be implemented-- Default: 1constant C_IMPL_N_TMR : integer := 1;------------------------------------------------------------------------------------------------------------------------------------------------------------ Select how many serial interface units should be implemented-- Default: C_IMPL_N_TMR ---(DO NOT CHANGE!)---constant C_IMPL_N_SIU : integer := C_IMPL_N_TMR;------------------------------------------------------------------------------------------------------------------------------------------------------------ Select how many external interrupt-inputs should be implemented-- Default: C_IMPL_N_TMR ---(DO NOT CHANGE!)---constant C_IMPL_N_EXT : integer := C_IMPL_N_TMR;-----------------------------------------------------------------------------
Configurable Modules (contd.) entity control_mem is port { … all_tcon_tr0_o : out std_logic_vector(C_IMPL_N_TMR-1 downto 0); };…architecture rtl of control_mem is… for_tmr: for i in 0 to C_IMPL_N_TMR-1 generate … end generate for_tmr;end rtl; Use constant instead of Generic
Configurable Modules (contd.) for i in 0 to C_IMPL_N_TMR-1 loop … end loop; type t_tmr_lv is array(C_IMPL_N_TMR-1 downto 0) of std_logic_vector(7 downto 0);
Select Timer / Counter Using TSEL to select which module to use
mc8051_alu_struc.vhd ADDSUB_CORE ALUMUX ALUCORE DCML_ADJUST COMB_DIVIDER COMB_MUTPLR
ADDSUB_CORE one carry, one auxiliary-carry Half carry bit, so the 8-bit adder will e implemented by 2 4-bit adder
0/1 Module addsub_cy cy_i opa_i opb_i architecture rtl of addsub_cy isbegin p_addsub: process (opa_i, opb_i, addsub_i, cy_i) variable v_a : unsigned(DWIDTH downto 0); variable v_b : unsigned(DWIDTH downto 0); variable v_result : std_logic_vector(DWIDTH+1 downto 0); begin -- process p_addsub v_a(DWIDTH downto 1) := unsigned(opa_i); v_b(DWIDTH downto 1) := unsigned(opb_i);if addsub_i = '1' then -- add or sub v_a(0) := '1'; v_b(0) := cy_i; v_result := conv_unsigned(v_a,DWIDTH+2) + v_b; -- add operation else v_a(0) := '0'; v_b(0) := cy_i; v_result := conv_unsigned(v_a,DWIDTH+2) - v_b; -- sub operation end if; cy_o <= v_result(DWIDTH+1); rslt_o <= v_result(DWIDTH downto 1); end process p_addsub; end rtl; cy_o rslt_o So that the “+” function will get a sum 1 bit longer Append an extra bit to handle carry
Module sddsub_ovcy else v_a(0) := '0'; v_b(0) := cy_i; v_result := conv_unsigned(v_a,DWIDTH+1) - unsigned(v_b); v_la(0) := '0'; v_lb(0) := v_result(DWIDTH); v_lresult := conv_unsigned(v_la,3) - unsigned(v_lb); end if; cy_o <= v_lresult(2); ov_o <= (v_result(DWIDTH) and not(v_lresult(2))) or (v_lresult(2) and not(v_result(DWIDTH))); rslt_o(DWIDTH-2 downto 0) <= v_result(DWIDTH-1 downto 1); rslt_o(DWIDTH-1) <= v_lresult(1); end process p_addsub_ov; end generate gen_greater_one; end rtl; The add operation is separate into 2, add of bit2~0 and add of bit 3. The separation of add operation help find overflow architecture rtl of addsub_ovcy is begin gen_greater_one: if (DWIDTH > 1) generate p_addsub_ov: process (opa_i, opb_i, addsub_i, cy_i) variable v_a : unsigned(DWIDTH-1 downto 0); variable v_b : unsigned(DWIDTH-1 downto 0); variable v_result : std_logic_vector(DWIDTH downto 0); variable v_la : unsigned(1 downto 0); variable v_lb : unsigned(1 downto 0); variable v_lresult : std_logic_vector(2 downto 0); begin -- process p_addsub v_a(DWIDTH-1 downto 1) := unsigned(opa_i(DWIDTH-2 downto 0)); v_b(DWIDTH-1 downto 1) := unsigned(opb_i(DWIDTH-2 downto 0)); v_la(1) := opa_i(DWIDTH-1); v_lb(1) := opb_i(DWIDTH-1); if addsub_i = '1' then v_a(0) := '1'; v_b(0) := cy_i; v_result := conv_unsigned(v_a,DWIDTH+1) + unsigned(v_b); v_la(0) := '1'; v_lb(0) := v_result(DWIDTH); v_lresult := conv_unsigned(v_la,3) + unsigned(v_lb); opa_i(2:0) opb_i (2:0) 0/1cy_i opa_i(3) opb_i (3) Carry out from bit 7 Carry out from bit 6
ALU Module architecture rtl of alucore is constant LAND : std_logic_vector(3 downto 0) := "0011"; constant LOR : std_logic_vector(3 downto 0) := "0101"; constant LXOR : std_logic_vector(3 downto 0) := "0110"; constant RL : std_logic_vector(3 downto 0) := "0111"; … …begin -- architecture structural p_alu: process (alu_cmd_i, op_a_i, op_b_i, cy_i) begin case alu_cmd_i is----------------------------------------------------------- when LAND => -- op_a_i and op_b_i result_o <= op_a_i and op_b_i; cy_o <= cy_i; ----------------------------------------------------------- when LOR => -- op_a_i or op_b_i result_o <= op_a_i or op_b_i; cy_o <= cy_i; ----------------------------------------------------------- when LXOR => -- op_a_i xor op_b_i result_o <= op_a_i xor op_b_i; cy_o <= cy_i; ----------------------------------------------------------- … end case; end process p_alu;end rtl;
ALUMUX ALUMUX Module Connect wires according to different input instruction addsub_core alucore dcml_adjust comb_divider comb_mltplr
architecture rtl of alumux is constant DA : std_logic_vector(5 downto 0) := "100000"; constant ADD_ACC_RAM : std_logic_vector(5 downto 0) := "100001"; constant AND_ACC_RAM : std_logic_vector(5 downto 0) := "100101"; ...Beginprocess (…) begin case cmd_i is when AND_ACC_RAM => alu_cmd_o <= LAND; op_a_o <= acc_i; op_b_o <= ram_data_i; when AND_ACC_ROM => ...; end case; … end process;end rtl; ALUMUX Module (VHDL)
Clk/16 Falling Edge Detection & Synchronize Timer/Counter 0 Falling Edge Detection & Synchronize Timer/Counter 1 Mode 0 Timer/Counter 0 Mode 0 Timer/Counter 1 Mode 1 Timer/Counter 0 Mode 1 Timer/Counter 1 Mode 2 Timer/Counter 0 Mode 2 Timer/Counter 1 Mode 3 Timer/Counter 0 Mode 3 Timer/Counter 1 Timer / Counter Mc8051_tmrctr_rtl.vhd Code structure
Timer / Counter (clock) Clk16 s_count_enable <= '1' when s_pre_count = conv_unsigned(15,4) else '0'; p_divide_clk: process (clk, reset) begin if reset = '1' then s_pre_count <= conv_unsigned(0,4); else if clk'event and clk='1' then s_pre_count <= s_pre_count + conv_unsigned(1,1); end if; end if; end process p_divide_clk; Conv_unsigned(value, bit_length)
Timer / Counter (edge detection) s_ext_edge0 <= '1' when (s_t0ff1 = '0' and s_t0ff2 = '1') else '0'; p_sample_t0: process (clk, reset) begin if reset = '1' then s_t0ff0 <= '0'; s_t0ff1 <= '0'; s_t0ff2 <= '0'; else if clk'event and clk = '1' then if s_pre_count = conv_unsigned(6,3) then if s_c_t0 = '1' thens_t0ff0 <= t0_i; s_t0ff1 <= s_t0ff0; s_t0ff2 <= s_t0ff1; end if; end if; end if; end if; end process p_sample_t0; s_ext_edge0 t0_i s_t0ff0 s_t0ff1 s_t0ff2 D Q CLK D Q CLK D Q CLK
Timer / Counter (VHDL Structure) Mode 0 case s_mode0 is when "00" => ...; when "01" => ...; when "10" => ...; when "11" => ...; when others => null; end case; Mode 1 Mode 2 Mode 3