---------------------------------------------------------------- -- Chapter 22 Case Study: System Design Using the Gumnut Core ---------------------------------------------------------------- ---------------------------------------------------------------- -- 22.1 Overview of the Gumnut ---------------------------------------------------------------- ---------------------------------------------------------------- -- 22.1.1 Instruction Set Architecture ---------------------------------------------------------------- ---------------------------------------------------------------- -- 22.1.2 External Interface ---------------------------------------------------------------- ---------------------------------------------------------------- -- The Gumnut Entity Declaration ---------------------------------------------------------------- -- Page 676 library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; entity gumnut is generic ( debug : boolean := false ); port ( clk_i : in std_ulogic; rst_i : in std_ulogic; -- Instruction memory bus inst_cyc_o : out std_ulogic; inst_stb_o : out std_ulogic; inst_ack_i : in std_ulogic; inst_adr_o : out unsigned(11 downto 0); inst_dat_i : in std_ulogic_vector(17 downto 0); -- Data memory bus data_cyc_o : out std_ulogic; data_stb_o : out std_ulogic; data_we_o : out std_ulogic; data_ack_i : in std_ulogic; data_adr_o : out unsigned(7 downto 0); data_dat_o : out std_ulogic_vector(7 downto 0); data_dat_i : in std_ulogic_vector(7 downto 0); -- I/O port bus port_cyc_o : out std_ulogic; port_stb_o : out std_ulogic; port_we_o : out std_ulogic; port_ack_i : in std_ulogic; port_adr_o : out unsigned(7 downto 0); port_dat_o : out std_ulogic_vector(7 downto 0); port_dat_i : in std_ulogic_vector(7 downto 0); -- Interrupts int_req : in std_ulogic; int_ack : out std_ulogic ); end entity gumnut; ---------------------------------------------------------------- -- Instruction and Data Memories ---------------------------------------------------------------- -- Page 677 library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; entity inst_mem is generic ( IMem_file_name : string := "gasm_text.dat" ); port ( clk_i : in std_ulogic; cyc_i : in std_ulogic; stb_i : in std_ulogic; ack_o : out std_ulogic; adr_i : in unsigned(11 downto 0); dat_o : out std_ulogic_vector(17 downto 0) ); end entity inst_mem; library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; entity data_mem is generic ( DMem_file_name : string := "gasm_data.dat" ); port ( clk_i : in std_ulogic; cyc_i : in std_ulogic; stb_i : in std_ulogic; we_i : in std_ulogic; ack_o : out std_ulogic; adr_i : in unsigned(7 downto 0); dat_i : in std_ulogic_vector(7 downto 0); dat_o : out std_ulogic_vector(7 downto 0) ); end entity data_mem; -- Page 678 library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; entity gumnut_with_mem is generic ( IMem_file_name : string := "gasm_text.dat"; DMem_file_name : string := "gasm_data.dat"; debug : boolean := false ); port ( clk_i : in std_ulogic; rst_i : in std_ulogic; -- I/O port bus port_cyc_o : out std_ulogic; port_stb_o : out std_ulogic; port_we_o : out std_ulogic; port_ack_i : in std_ulogic; port_adr_o : out unsigned(7 downto 0); port_dat_o : out std_ulogic_vector(7 downto 0); port_dat_i : in std_ulogic_vector(7 downto 0); -- Interrupts int_req : in std_ulogic; int_ack : out std_ulogic ); end entity gumnut_with_mem; -- Page 678 - 681 library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; architecture struct of gumnut_with_mem is -- Instruction memory bus signal inst_cyc_o : std_ulogic; signal inst_stb_o : std_ulogic; signal inst_ack_i : std_ulogic; signal inst_adr_o : unsigned(11 downto 0); signal inst_dat_i : std_ulogic_vector(17 downto 0); -- Data memory bus signal data_cyc_o : std_ulogic; signal data_stb_o : std_ulogic; signal data_we_o : std_ulogic; signal data_ack_i : std_ulogic; signal data_adr_o : unsigned(7 downto 0); signal data_dat_o : std_ulogic_vector(7 downto 0); signal data_dat_i : std_ulogic_vector(7 downto 0); component gumnut is generic ( debug : boolean ); port ( clk_i : in std_ulogic; rst_i : in std_ulogic; -- Instruction memory bus inst_cyc_o : out std_ulogic; inst_stb_o : out std_ulogic; inst_ack_i : in std_ulogic; inst_adr_o : out unsigned(11 downto 0); inst_dat_i : in std_ulogic_vector(17 downto 0); -- Data memory bus data_cyc_o : out std_ulogic; data_stb_o : out std_ulogic; data_we_o : out std_ulogic; data_ack_i : in std_ulogic; data_adr_o : out unsigned(7 downto 0); data_dat_o : out std_ulogic_vector(7 downto 0); data_dat_i : in std_ulogic_vector(7 downto 0); -- I/O port bus port_cyc_o : out std_ulogic; port_stb_o : out std_ulogic; port_we_o : out std_ulogic; port_ack_i : in std_ulogic; port_adr_o : out unsigned(7 downto 0); port_dat_o : out std_ulogic_vector(7 downto 0); port_dat_i : in std_ulogic_vector(7 downto 0); -- Interrupts int_req : in std_ulogic; int_ack : out std_ulogic ); end component gumnut; component inst_mem is generic ( IMem_file_name : string ); port ( clk_i : in std_ulogic; cyc_i : in std_ulogic; stb_i : in std_ulogic; ack_o : out std_ulogic; adr_i : in unsigned(11 downto 0); dat_o : out std_ulogic_vector(17 downto 0) ); end component inst_mem; component data_mem is generic ( DMem_file_name : string ); port ( clk_i : in std_ulogic; cyc_i : in std_ulogic; stb_i : in std_ulogic; we_i : in std_ulogic; ack_o : out std_ulogic; adr_i : in unsigned(7 downto 0); dat_i : in std_ulogic_vector(7 downto 0); dat_o : out std_ulogic_vector(7 downto 0) ); end component data_mem; begin core : component gumnut generic map ( debug => debug ) port map ( clk_i => clk_i, rst_i => rst_i, inst_cyc_o => inst_cyc_o, inst_stb_o => inst_stb_o, inst_ack_i => inst_ack_i, inst_adr_o => inst_adr_o, inst_dat_i => inst_dat_i, data_cyc_o => data_cyc_o, data_stb_o => data_stb_o, data_we_o => data_we_o, data_ack_i => data_ack_i, data_adr_o => data_adr_o, data_dat_o => data_dat_o, data_dat_i => data_dat_i, port_cyc_o => port_cyc_o, port_stb_o => port_stb_o, port_we_o => port_we_o, port_ack_i => port_ack_i, port_adr_o => port_adr_o, port_dat_o => port_dat_o, port_dat_i => port_dat_i, int_req => int_req, int_ack => int_ack ); core_inst_mem : component inst_mem generic map ( IMem_file_name => IMem_file_name ) port map ( clk_i => clk_i, cyc_i => inst_cyc_o, stb_i => inst_stb_o, ack_o => inst_ack_i, adr_i => inst_adr_o, dat_o => inst_dat_i ); core_data_mem : component data_mem generic map ( DMem_file_name => DMem_file_name ) port map ( clk_i => clk_i, cyc_i => data_cyc_o, stb_i => data_stb_o, we_i => data_we_o, ack_o => data_ack_i, adr_i => data_adr_o, dat_i => data_dat_o, dat_o => data_dat_i ); end architecture struct; ---------------------------------------------------------------- -- 22.2 A Behavioral Model ---------------------------------------------------------------- ---------------------------------------------------------------- -- 22.2.1 The Gumnut Definitions Package ---------------------------------------------------------------- -- Pages 681 - 682 library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; package gumnut_defs is constant IMem_addr_width : positive := 12; constant IMem_size : positive := 2**IMem_addr_width; subtype IMem_addr is unsigned(IMem_addr_width - 1 downto 0); subtype instruction is unsigned(17 downto 0); type instruction_array is array (natural range <>) of instruction; subtype IMem_array is instruction_array(0 to IMem_size - 1); constant DMem_size : positive := 256; subtype unsigned_byte is unsigned(7 downto 0); type unsigned_byte_array is array (natural range <>) of unsigned_byte; subtype DMem_array is unsigned_byte_array(0 to DMem_size - 1); subtype signed_byte is signed(7 downto 0); type signed_byte_array is array (natural range <>) of signed_byte; subtype reg_addr is unsigned(2 downto 0); subtype immed is unsigned(7 downto 0); subtype offset is unsigned(7 downto 0); subtype disp is unsigned(7 downto 0); subtype shift_count is unsigned(2 downto 0); subtype alu_fn_code is unsigned(2 downto 0); subtype shift_fn_code is unsigned(1 downto 0); subtype mem_fn_code is unsigned(1 downto 0); subtype branch_fn_code is unsigned(1 downto 0); subtype jump_fn_code is unsigned(0 downto 0); subtype misc_fn_code is unsigned(2 downto 0); constant alu_fn_add : alu_fn_code := "000"; constant alu_fn_addc : alu_fn_code := "001"; constant alu_fn_sub : alu_fn_code := "010"; constant alu_fn_subc : alu_fn_code := "011"; constant alu_fn_and : alu_fn_code := "100"; constant alu_fn_or : alu_fn_code := "101"; constant alu_fn_xor : alu_fn_code := "110"; constant alu_fn_mask : alu_fn_code := "111"; constant shift_fn_shl : shift_fn_code := "00"; constant shift_fn_shr : shift_fn_code := "01"; constant shift_fn_rol : shift_fn_code := "10"; constant shift_fn_ror : shift_fn_code := "11"; constant mem_fn_ldm : mem_fn_code := "00"; constant mem_fn_stm : mem_fn_code := "01"; constant mem_fn_inp : mem_fn_code := "10"; constant mem_fn_out : mem_fn_code := "11"; constant branch_fn_bz : branch_fn_code := "00"; constant branch_fn_bnz : branch_fn_code := "01"; constant branch_fn_bc : branch_fn_code := "10"; constant branch_fn_bnc : branch_fn_code := "11"; constant jump_fn_jmp : jump_fn_code := "0"; constant jump_fn_jsb : jump_fn_code := "1"; constant misc_fn_ret : misc_fn_code := "000"; constant misc_fn_reti : misc_fn_code := "001"; constant misc_fn_enai : misc_fn_code := "010"; constant misc_fn_disi : misc_fn_code := "011"; constant misc_fn_wait : misc_fn_code := "100"; constant misc_fn_stby : misc_fn_code := "101"; constant misc_fn_undef_6 : misc_fn_code := "110"; constant misc_fn_undef_7 : misc_fn_code := "111"; subtype disassembled_instruction is string(1 to 30); procedure disassemble ( instr : instruction; result : out disassembled_instruction ); end package gumnut_defs; -- Page 683 - 686 package body gumnut_defs is procedure disassemble ( instr : instruction; result : out disassembled_instruction ) is subtype name is string(1 to 4); type name_table is array (natural range <>) of name; constant alu_name_table : name_table(0 to 7) := ( 0 => "add ", 1 => "addc", 2 => "sub ", 3 => "subc", 4 => "and ", 5 => "or ", 6 => "xor ", 7 => "msk " ); constant shift_name_table : name_table(0 to 3) := ( 0 => "shl ", 1 => "shr ", 2 => "rol ", 3 => "ror " ); constant mem_name_table : name_table(0 to 3) := ( 0 => "ldm ", 1 => "stm ", 2 => "inp ", 3 => "out " ); constant branch_name_table : name_table(0 to 3) := ( 0 => "bz ", 1 => "bnz ", 2 => "bc ", 3 => "bnc " ); constant jump_name_table : name_table(0 to 1) := ( 0 => "jmp ", 1 => "jsb " ); constant misc_name_table : name_table(0 to 7) := ( 0 => "ret ", 1 => "reti", 2 => "enai", 3 => "disi", 4 => "wait", 5 => "stby", 6 => "um_6", 7 => "um_7" ); variable instr_01 : instruction := to_01(instr); alias instr_alu_reg_fn : alu_fn_code is instr_01(2 downto 0); alias instr_alu_immed_fn : alu_fn_code is instr_01(16 downto 14); alias instr_shift_fn : shift_fn_code is instr_01(1 downto 0); alias instr_mem_fn : mem_fn_code is instr_01(15 downto 14); alias instr_branch_fn : branch_fn_code is instr_01(11 downto 10); alias instr_jump_fn : jump_fn_code is instr_01(12 downto 12); alias instr_misc_fn : misc_fn_code is instr_01(10 downto 8); alias instr_rd : reg_addr is instr_01(13 downto 11); alias instr_rs : reg_addr is instr_01(10 downto 8); alias instr_r2 : reg_addr is instr_01(7 downto 5); alias instr_immed : immed is instr_01(7 downto 0); alias instr_count : shift_count is instr_01(7 downto 5); alias instr_offset : offset is instr_01(7 downto 0); alias instr_disp : disp is instr_01(7 downto 0); alias instr_addr : IMem_addr is instr_01(11 downto 0); procedure disassemble_reg ( reg : reg_addr; index : positive ) is constant str : string := to_string(to_integer(reg)); begin result(index) := str(str'left); end procedure disassemble_reg; procedure disassemble_unsigned ( n : unsigned; index : positive ) is constant str : string := to_string(to_integer(n)); begin result(index to index + str'length - 1) := str; end procedure disassemble_unsigned; procedure disassemble_signed ( n : signed; index : positive ) is constant str : string := to_string(to_integer(n)); begin result(index to index + str'length - 1) := str; end procedure disassemble_signed; procedure disassemble_effective_addr ( r : reg_addr; d : offset; index : positive ) is constant signed_str : string := to_string(to_integer(signed(d))); constant unsigned_str : string := to_string(to_integer(d)); begin if r = 0 then result(index to index + unsigned_str'length - 1) := unsigned_str; else result(index to index + 3) := "(r )"; disassemble_reg(r, index + 2); result(index + 4 to index + 4 + signed_str'length - 1) := signed_str; end if; end procedure disassemble_effective_addr; begin if is_X(instr) then report "disassemble: metalogical value in instruction word" severity error; result := (others => 'X'); return; end if; result := (others => ' '); if instr_01(17) = '0' then -- Arithmetic/Logical Immediate result(1 to name'length) := alu_name_table(to_integer(instr_alu_immed_fn)); result(name'length + 2 to name'length + 8) := "R , R ,"; disassemble_reg(instr_rd, name'length + 3); disassemble_reg(instr_rs, name'length + 7); disassemble_unsigned(instr_immed, name'length + 10); elsif instr_01(16) = '0' then -- Memory I/O result(1 to name'length) := mem_name_table(to_integer(instr_mem_fn)); result(name'length + 2 to name'length + 4) := "R ,"; disassemble_reg(instr_rd, name'length + 3); disassemble_effective_addr(instr_rs, instr_offset, name'length + 6); elsif instr_01(15) = '0' then -- Shift result(1 to name'length) := shift_name_table(to_integer(instr_shift_fn)); result(name'length + 2 to name'length + 8) := "R , R ,"; disassemble_reg(instr_rd, name'length + 3); disassemble_reg(instr_rs, name'length + 7); disassemble_unsigned(instr_count, name'length + 10); elsif instr_01(14) = '0' then -- Arithmetic/Logical Register result(1 to name'length) := alu_name_table(to_integer(instr_alu_reg_fn)); result(name'length + 2 to name'length + 10) := "R , R , R"; disassemble_reg(instr_rd, name'length + 3); disassemble_reg(instr_rs, name'length + 7); disassemble_reg(instr_r2, name'length + 11); elsif instr_01(13) = '0' then -- Jump result(1 to name'length) := jump_name_table(to_integer(instr_jump_fn)); disassemble_unsigned(instr_addr, name'length + 2); elsif instr_01(12) = '0' then -- Branch result(1 to name'length) := branch_name_table(to_integer(instr_branch_fn)); disassemble_signed(signed(instr_disp), name'length + 2); elsif instr_01(11) = '0' then -- Miscellaneous result(1 to name'length) := misc_name_table(to_integer(instr_misc_fn)); else result(1 to 19) := "Illegal Instruction"; end if; end procedure disassemble; end package body gumnut_defs; ---------------------------------------------------------------- -- 22.2.2 The Gumnut Behavioral Architecture Body ---------------------------------------------------------------- -- Pages 687 - 699 library ieee; use ieee.numeric_std.all; use work.gumnut_defs.all; use std.textio.all; architecture behavior of gumnut is begin interpreter : process variable PC : IMem_addr; variable IR : instruction; alias IR_alu_reg_fn : alu_fn_code is IR(2 downto 0); alias IR_alu_immed_fn : alu_fn_code is IR(16 downto 14); alias IR_shift_fn : shift_fn_code is IR(1 downto 0); alias IR_mem_fn : mem_fn_code is IR(15 downto 14); alias IR_branch_fn : branch_fn_code is IR(11 downto 10); alias IR_jump_fn : jump_fn_code is IR(12 downto 12); alias IR_misc_fn : misc_fn_code is IR(10 downto 8); alias IR_rd : reg_addr is IR(13 downto 11); alias IR_rs : reg_addr is IR(10 downto 8); alias IR_r2 : reg_addr is IR(7 downto 5); alias IR_immed : immed is IR(7 downto 0); alias IR_count : shift_count is IR(7 downto 5); alias IR_offset : disp is IR(7 downto 0); alias IR_disp : disp is IR(7 downto 0); alias IR_addr : IMem_addr is IR(11 downto 0); constant stack_depth : positive := 8; subtype stack_index is natural range 0 to stack_depth - 1; type stack_array is array (stack_index) of IMem_addr; variable stack : stack_array; variable SP : stack_index; subtype reg_index is natural range 0 to 7; variable GPR : unsigned_byte_array(reg_index); variable ALU_result : unsigned_byte; variable cc_Z : std_ulogic; variable cc_C : std_ulogic; variable int_en : std_ulogic; variable int_PC : IMem_addr; variable int_Z, int_C : std_ulogic; variable disassembled_instr : disassembled_instruction; variable debug_line : line; -- local procedures for use within the interpreter ... procedure perform_reset is begin -- Reset internal state PC := (others => '0'); SP := 0; GPR := (others => X"00"); cc_Z := '0'; cc_C := '0'; int_en := '0'; -- Reset bus signals inst_cyc_o <= '0'; inst_stb_o <= '0'; data_cyc_o <= '0'; data_stb_o <= '0'; data_we_o <= '0'; port_cyc_o <= '0'; port_stb_o <= '0'; port_we_o <= '0'; int_ack <= '0'; end perform_reset; procedure perform_interrupt is variable PC_num : natural; begin PC_num := to_integer(PC); int_PC := PC; int_Z := cc_Z; int_C := cc_C; int_en := '0'; PC := to_unsigned(1, PC'length); int_ack <= '1'; wait until rising_edge(clk_i); int_ack <= '0'; if debug then swrite(debug_line, "Interrupt acknowledged at PC = "); write(debug_line, PC_num, field => 4, justified => right); writeline(output, debug_line); end if; end procedure perform_interrupt; procedure fetch_instruction is variable PC_num : natural; begin PC_num := to_integer(PC); inst_cyc_o <= '1'; inst_stb_o <= '1'; inst_adr_o <= PC; loop wait until rising_edge(clk_i); if rst_i then return; end if; exit when inst_ack_i; end loop; IR := unsigned(inst_dat_i); PC := PC + 1; inst_cyc_o <= '0'; inst_stb_o <= '0'; if debug then disassemble(IR, disassembled_instr); write(debug_line, PC_num, field => 4, justified => right); swrite(debug_line, ": "); write(debug_line, disassembled_instr); writeline(output, debug_line); end if; end procedure fetch_instruction; procedure perform_alu_op ( fn : in alu_fn_code; a, b : in unsigned_byte; C_in : in std_ulogic; result : out unsigned_byte; Z_out, C_out : out std_ulogic ) is begin case fn is when alu_fn_add => (C_out, result) := ('0' & a) + ('0' & b); when alu_fn_addc => (C_out, result) := ('0' & a) + ('0' & b) + C_in; when alu_fn_sub => (C_out, result) := ('0' & a) - ('0' & b); when alu_fn_subc => (C_out, result) := ('0' & a) - ('0' & b) - C_in; when alu_fn_and => (C_out, result) := ('0' & a) and ('0' & b); when alu_fn_or => (C_out, result) := ('0' & a) or ('0' & b); when alu_fn_xor => (C_out, result) := ('0' & a) xor ('0' & b); when alu_fn_mask => (C_out, result) := ('0' & a) and not ('0' & b); when others => report "Program logic error in interpreter" severity failure; end case; Z_out := result ?= X"00"; end procedure perform_alu_op; procedure perform_shift_op ( fn : in shift_fn_code; a : in unsigned_byte; count : in shift_count; result : out unsigned_byte; Z_out, C_out : out std_ulogic ) is begin case fn is when shift_fn_shl => (C_out, result) := ('0' & a) sll to_integer(count); when shift_fn_shr => (result, C_out) := (a & '0') srl to_integer(count); when shift_fn_rol => result := a rol to_integer(count); C_out := result(unsigned_byte'right); when shift_fn_ror => result := a ror to_integer(count); C_out := result(unsigned_byte'left); when others => report "Program logic error in interpreter" severity failure; end case; Z_out := result ?= X"00"; end procedure perform_shift_op; procedure perform_mem is variable mem_addr : unsigned_byte; variable tmp_Z, tmp_C : std_ulogic; begin perform_alu_op(fn => alu_fn_add, a => GPR(to_integer(IR_rs)), b => IR_offset, C_in => '0', result => mem_addr, Z_out => tmp_Z, C_out => tmp_C); case IR_mem_fn is when mem_fn_ldm => data_cyc_o <= '1'; data_stb_o <= '1'; data_we_o <= '0'; data_adr_o <= mem_addr; ldm_loop : loop wait until rising_edge(clk_i); if rst_i then return; end if; exit ldm_loop when data_ack_i; end loop ldm_loop; if IR_rd /= 0 then GPR(to_integer(IR_rd)) := unsigned(data_dat_i); end if; data_cyc_o <= '0'; data_stb_o <= '0'; when mem_fn_stm => data_cyc_o <= '1'; data_stb_o <= '1'; data_we_o <= '1'; data_adr_o <= mem_addr; data_dat_o <= std_ulogic_vector(GPR(to_integer(IR_rd))); stm_loop : loop wait until rising_edge(clk_i); if rst_i then return; end if; exit stm_loop when data_ack_i; end loop stm_loop; data_cyc_o <= '0'; data_stb_o <= '0'; when mem_fn_inp => port_cyc_o <= '1'; port_stb_o <= '1'; port_we_o <= '0'; port_adr_o <= mem_addr; inp_loop : loop wait until rising_edge(clk_i); if rst_i then return; end if; exit inp_loop when port_ack_i; end loop inp_loop; if IR_rd /= 0 then GPR(to_integer(IR_rd)) := unsigned(port_dat_i); end if; port_cyc_o <= '0'; port_stb_o <= '0'; when mem_fn_out => port_cyc_o <= '1'; port_stb_o <= '1'; port_we_o <= '1'; port_adr_o <= mem_addr; port_dat_o <= std_ulogic_vector(GPR(to_integer(IR_rd))); out_loop : loop wait until rising_edge(clk_i); if rst_i then return; end if; exit out_loop when port_ack_i; end loop out_loop; port_cyc_o <= '0'; port_stb_o <= '0'; when others => report "Program logic error in interpreter" severity failure; end case; end procedure perform_mem; procedure perform_branch is variable branch_taken : std_ulogic; begin case IR_branch_fn is when branch_fn_bz => branch_taken := cc_Z; when branch_fn_bnz => branch_taken := not cc_Z; when branch_fn_bc => branch_taken := cc_C; when branch_fn_bnc => branch_taken := not cc_C; when others => report "Program logic error in interpreter" severity failure; end case; if branch_taken then PC := unsigned(signed(PC) + signed(IR_disp)); end if; end procedure perform_branch; procedure perform_jump is begin case IR_jump_fn is when jump_fn_jmp => PC := IR_addr; when jump_fn_jsb => stack(SP) := PC; SP := (SP + 1) mod stack_depth; PC := IR_addr; when others => report "Program logic error in interpreter" severity failure; end case; end procedure perform_jump; procedure perform_misc is begin case IR_misc_fn is when misc_fn_ret => SP := (SP - 1) mod stack_depth; PC := stack(SP); when misc_fn_reti => PC := int_PC; cc_Z := int_Z; cc_C := int_C; int_en := '1'; when misc_fn_enai => int_en := '1'; when misc_fn_disi => int_en := '0'; when misc_fn_wait | misc_fn_stby => wait_loop : loop wait until rising_edge(clk_i); if rst_i then return; end if; exit wait_loop when int_en and int_req; end loop wait_loop; perform_interrupt; when misc_fn_undef_6 | misc_fn_undef_7 => null; when others => report "Program logic error in interpreter" severity failure; end case; end procedure perform_misc; begin -- interpreter perform_reset; wait until rising_edge(clk_i) and rst_i = '0'; -- fetch/decode/execute loop fetch_execute_loop : loop -- check for interrupts if int_en and int_req then perform_interrupt; exit fetch_execute_loop when rst_i; next fetch_execute_loop; end if; -- fetch next instruction fetch_instruction; exit fetch_execute_loop when rst_i; next fetch_execute_loop when is_X(IR); -- decode and execute the instruction if IR(17) = '0' then -- Arithmetic/Logical Immediate perform_alu_op(fn => IR_alu_immed_fn, a => GPR(to_integer(IR_rs)), b => IR_immed, C_in => cc_C, result => ALU_result, Z_out => cc_Z, C_out => cc_C); if IR_rd /= 0 then GPR(to_integer(IR_rd)) := ALU_result; end if; elsif IR(16) = '0' then -- Memory I/O perform_mem; exit fetch_execute_loop when rst_i; elsif IR(15) = '0' then -- Shift perform_shift_op(fn => IR_shift_fn, a => GPR(to_integer(IR_rs)), count => IR_count, result => ALU_result, Z_out => cc_Z, C_out => cc_C); if IR_rd /= 0 then GPR(to_integer(IR_rd)) := ALU_result; end if; elsif IR(14) = '0' then -- Arithmetic/Logical Register perform_alu_op(fn => IR_alu_reg_fn, a => GPR(to_integer(IR_rs)), b => GPR(to_integer(IR_r2)), C_in => cc_C, result => ALU_result, Z_out => cc_Z, C_out => cc_C); if IR_rd /= 0 then GPR(to_integer(IR_rd)) := ALU_result; end if; elsif IR(13) = '0' then -- Jump perform_jump; elsif IR(12) = '0' then -- Branch perform_branch; elsif IR(11) = '0' then -- Miscellaneous perform_misc; exit fetch_execute_loop when rst_i; else -- Illegal instruction null; end if; end loop fetch_execute_loop; end process interpreter; end architecture behavior; ---------------------------------------------------------------- -- 22.2.3 Verifying the Behavioral Model ---------------------------------------------------------------- -- Page 699 entity test is end test; -- Pages 699 - 702 library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; use work.gumnut_defs.all; use std.textio.all; architecture gumnut of test is signal syscon_clk_o : std_ulogic; signal syscon_rst_o : std_ulogic; -- I/O port bus signal gumnut_port_cyc_o : std_ulogic; signal gumnut_port_stb_o : std_ulogic; signal gumnut_port_we_o : std_ulogic; signal gumnut_port_ack_i : std_ulogic; signal gumnut_port_adr_o : unsigned(7 downto 0); signal gumnut_port_dat_o : std_ulogic_vector(7 downto 0); signal gumnut_port_dat_i : std_ulogic_vector(7 downto 0); -- Interrupts signal gumnut_int_req : std_ulogic; signal gumnut_int_ack : std_ulogic; component gumnut_with_mem is port ( clk_i : in std_ulogic; rst_i : in std_ulogic; -- I/O port bus port_cyc_o : out std_ulogic; port_stb_o : out std_ulogic; port_we_o : out std_ulogic; port_ack_i : in std_ulogic; port_adr_o : out unsigned(7 downto 0); port_dat_o : out std_ulogic_vector(7 downto 0); port_dat_i : in std_ulogic_vector(7 downto 0); -- Interrupts int_req : in std_ulogic; int_ack : out std_ulogic ); end component gumnut_with_mem; begin reset_gen : syscon_rst_o <= '0', '1' after 5 ns, '0' after 25 ns; clk_gen : process begin syscon_clk_o <= '0'; wait for 10 ns; loop syscon_clk_o <= '1', '0' after 5 ns; wait for 10 ns; end loop; end process clk_gen; int_gen : process begin gumnut_int_req <= '0'; for int_count in 1 to 10 loop for cycle_count in 1 to 25 loop wait until falling_edge(syscon_clk_o); end loop; gumnut_int_req <= '1'; wait until falling_edge(syscon_clk_o) and gumnut_int_ack = '1'; gumnut_int_req <= '0'; end loop; wait; end process int_gen; io_control : process -- Hard-wired input stream constant input_data : unsigned_byte_array := ( X"00", X"01", X"02", X"03", X"04", X"05", X"06", X"07", X"08", X"09", X"0A", X"0B", X"0C", X"0D", X"0E", X"0F", X"10", X"11", X"12", X"13", X"14", X"15", X"16", X"17", X"18", X"19", X"1A", X"1B", X"1C", X"1D", X"1E", X"1F" ); variable next_input : integer := 0; variable debug_line : line; constant show_actions : boolean := true; begin gumnut_port_ack_i <= '0'; loop wait until falling_edge(syscon_clk_o); if gumnut_port_cyc_o and gumnut_port_stb_o then if to_X01(gumnut_port_we_o) = '0' then if show_actions then swrite(debug_line, "IO: port read; address = "); hwrite(debug_line, gumnut_port_adr_o); swrite(debug_line, ", data = "); hwrite(debug_line, input_data(next_input) ); writeline(output, debug_line); end if; gumnut_port_dat_i <= std_ulogic_vector(input_data(next_input)); next_input := (next_input + 1) mod input_data'length; gumnut_port_ack_i <= '1'; else if show_actions then swrite(debug_line, "IO: port write; address = "); hwrite(debug_line, gumnut_port_adr_o ); swrite(debug_line, ", data = "); hwrite(debug_line, gumnut_port_dat_o ); writeline(output, debug_line); end if; gumnut_port_ack_i <= '1'; end if; else gumnut_port_ack_i <= '0'; end if; end loop; end process io_control; dut : component gumnut_with_mem port map ( clk_i => syscon_clk_o, rst_i => syscon_rst_o, port_cyc_o => gumnut_port_cyc_o, port_stb_o => gumnut_port_stb_o, port_we_o => gumnut_port_we_o, port_ack_i => gumnut_port_ack_i, port_adr_o => gumnut_port_adr_o, port_dat_o => gumnut_port_dat_o, port_dat_i => gumnut_port_dat_i, int_req => gumnut_int_req, int_ack => gumnut_int_ack ); end architecture gumnut; -- Pages 702 - 703 configuration test_gumnut_behavior of test is for gumnut for dut : gumnut_with_mem use entity work.gumnut_with_mem(struct); for struct for core : gumnut use entity work.gumnut(behavior) generic map ( debug => true ); end for; end for; end for; end for; end configuration test_gumnut_behavior; ---------------------------------------------------------------- -- 22.3 A Register-Transfer-Level Model ---------------------------------------------------------------- ---------------------------------------------------------------- -- 22.3.1 The Architecture Body ---------------------------------------------------------------- -- Pages 707 - 720 library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all; use work.gumnut_defs.all; architecture rtl_unpipelined of gumnut is signal PC : IMem_addr; signal branch_taken : std_ulogic; signal IR : instruction; alias IR_alu_reg_fn : alu_fn_code is IR(2 downto 0); alias IR_alu_immed_fn : alu_fn_code is IR(16 downto 14); alias IR_shift_fn : shift_fn_code is IR(1 downto 0); alias IR_mem_fn : mem_fn_code is IR(15 downto 14); alias IR_branch_fn : branch_fn_code is IR(11 downto 10); alias IR_jump_fn : jump_fn_code is IR(12 downto 12); alias IR_misc_fn : misc_fn_code is IR(10 downto 8); alias IR_rd : reg_addr is IR(13 downto 11); alias IR_rs : reg_addr is IR(10 downto 8); alias IR_r2 : reg_addr is IR(7 downto 5); alias IR_immed : immed is IR(7 downto 0); alias IR_count : shift_count is IR(7 downto 5); alias IR_offset : disp is IR(7 downto 0); alias IR_disp : disp is IR(7 downto 0); alias IR_addr : IMem_addr is IR(11 downto 0); signal IR_decode_alu_immed, IR_decode_mem, IR_decode_shift, IR_decode_alu_reg, IR_decode_jump, IR_decode_branch, IR_decode_misc : std_ulogic; signal D_state : std_ulogic; signal int_PC : IMem_addr; signal int_Z : std_ulogic; signal int_C : std_ulogic; signal int_en : std_ulogic; constant SP_length : positive := 3; signal SP : unsigned(SP_length - 1 downto 0); signal stack_top : IMem_addr; signal GPR_rs : unsigned_byte; signal GPR_r2 : unsigned_byte; signal ALU_result : unsigned_byte; signal ALU_Z : std_ulogic; signal ALU_C : std_ulogic; signal ALU_out : unsigned_byte; signal cc_Z : std_ulogic; signal cc_C : std_ulogic; signal D : unsigned_byte; type control_state is (fetch_state, decode_state, execute_state, mem_state, write_back_state, int_state); signal state, next_state : control_state; begin IR_decode_alu_immed <= IR(17) ?= '0'; IR_decode_mem <= IR(17 downto 16) ?= "10"; IR_decode_shift <= IR(17 downto 15) ?= "110"; IR_decode_alu_reg <= IR(17 downto 14) ?= "1110"; IR_decode_jump <= IR(17 downto 13) ?= "11110"; IR_decode_branch <= IR(17 downto 12) ?= "111110"; IR_decode_misc <= IR(17 downto 11) ?= "1111110"; control : process (all) begin case state is when fetch_state => if not inst_ack_i then next_state <= fetch_state; else next_state <= decode_state; end if; when decode_state => if IR_decode_branch or IR_decode_jump or IR_decode_misc then if IR_decode_misc and (IR_misc_fn ?= misc_fn_wait or IR_misc_fn ?= misc_fn_stby) and not (int_en and int_req) then next_state <= decode_state; elsif int_en and int_req then next_state <= int_state; else next_state <= fetch_state; end if; else next_state <= execute_state; end if; when execute_state => if IR_decode_mem then if (IR_mem_fn ?= mem_fn_ldm or IR_mem_fn ?= mem_fn_stm) and not data_ack_i then next_state <= mem_state; elsif (IR_mem_fn ?= mem_fn_inp or IR_mem_fn ?= mem_fn_out) and not port_ack_i then next_state <= mem_state; elsif IR_mem_fn ?= mem_fn_ldm or IR_mem_fn ?= mem_fn_inp then next_state <= write_back_state; else if int_en and int_req then next_state <= int_state; else next_state <= fetch_state; end if; end if; else next_state <= write_back_state; end if; when mem_state => if (IR_mem_fn ?= mem_fn_ldm or IR_mem_fn ?= mem_fn_stm) and not data_ack_i then next_state <= mem_state; elsif (IR_mem_fn ?= mem_fn_inp or IR_mem_fn ?= mem_fn_out) and not port_ack_i then next_state <= mem_state; elsif IR_mem_fn ?= mem_fn_ldm or IR_mem_fn ?= mem_fn_inp then next_state <= write_back_state; else if int_en and int_req then next_state <= int_state; else next_state <= fetch_state; end if; end if; when write_back_state => if int_en and int_req then next_state <= int_state; else next_state <= fetch_state; end if; when int_state => next_state <= fetch_state; end case; end process control; state_reg : process (clk_i) begin if rising_edge(clk_i) then if rst_i then state <= fetch_state; else state <= next_state; end if; end if; end process state_reg; with IR_branch_fn select branch_taken <= cc_Z when branch_fn_bz, not cc_Z when branch_fn_bnz, cc_C when branch_fn_bc, not cc_C when branch_fn_bnc, 'X' when others; PC_reg : process (clk_i) begin if rising_edge(clk_i) then if rst_i then PC <= (others => '0'); elsif state = fetch_state and inst_ack_i = '1' then PC <= PC + 1; elsif state = decode_state then if IR_decode_branch and branch_taken then PC <= unsigned(signed(PC) + signed(IR_disp)); elsif IR_decode_jump then PC <= IR_addr; elsif IR_decode_misc and IR_misc_fn ?= misc_fn_ret then PC <= stack_top; elsif IR_decode_misc and IR_misc_fn ?= misc_fn_reti then PC <= int_PC; end if; elsif state = int_state then PC <= to_unsigned(1, PC'length); end if; end if; end process PC_reg; int_ack <= '1' when state = int_state else '0'; int_reg : process (clk_i) begin if rising_edge(clk_i) then if rst_i then int_en <= '0'; elsif state = int_state then int_PC <= PC; int_Z <= cc_Z; int_C <= cc_C; int_en <= '0'; elsif state = decode_state and IR_decode_misc = '1' then case IR_misc_fn is when misc_fn_reti | misc_fn_enai => int_en <= '1'; when misc_fn_disi => int_en <= '0'; when others => null; end case; end if; end if; end process int_reg; inst_cyc_o <= '1' when state = fetch_state else '0'; inst_stb_o <= '1' when state = fetch_state else '0'; inst_adr_o <= PC; instr_reg : process (clk_i) begin if rising_edge(clk_i) then if state = fetch_state and inst_ack_i = '1' then IR <= unsigned(to_X01(inst_dat_i)); end if; end if; end process instr_reg; stack_mem : process (clk_i) constant stack_depth : positive := 2**SP_length; subtype stack_index is natural range 0 to stack_depth - 1; type stack_array is array (stack_index) of IMem_addr; variable stack : stack_array; begin if rising_edge(clk_i) then if rst_i then SP <= (others => '0'); elsif state = decode_state then if IR_decode_jump and IR_jump_fn ?= jump_fn_jsb then stack(to_integer(SP)) := PC; SP <= SP + 1; elsif IR_decode_misc and IR_misc_fn ?= misc_fn_ret then SP <= SP - 1; end if; end if; stack_top <= stack(to_integer(SP - 1)); end if; end process stack_mem; GPR_mem : process (clk_i) subtype reg_index is natural range 0 to 7; variable r2_addr : reg_addr; variable write_data : unsigned_byte; variable GPR : unsigned_byte_array(reg_index) := (others => X"00"); begin if rising_edge(clk_i) then if rst_i then GPR := (others => (others => '0')); else if state = write_back_state and IR_rd /= 0 then if IR_decode_alu_reg or IR_decode_alu_immed or IR_decode_shift then write_data := ALU_out; elsif IR_decode_mem and (IR_mem_fn ?= mem_fn_ldm or IR_mem_fn ?= mem_fn_inp) then write_data := D; end if; GPR(to_integer(IR_rd)) := write_data; end if; if state = decode_state then if IR_decode_mem and (IR_mem_fn ?= mem_fn_stm or IR_mem_fn ?= mem_fn_out) then r2_addr := IR_rd; else r2_addr := IR_r2; end if; GPR_rs <= GPR(to_integer(IR_rs)); GPR_r2 <= GPR(to_integer(r2_addr)); end if; end if; end if; end process GPR_mem; ALU : process (all) variable fn : alu_fn_code; variable right_operand : unsigned_byte; variable shift_result : unsigned_byte; begin if IR_decode_alu_reg or IR_decode_alu_immed or IR_decode_mem then if IR_decode_alu_reg then fn := IR_alu_reg_fn; right_operand := GPR_r2; elsif IR_decode_alu_immed then fn := IR_alu_immed_fn; right_operand := IR_immed; else fn := alu_fn_add; right_operand := IR_offset; end if; case fn is when alu_fn_add => (ALU_C, ALU_result) <= ('0' & GPR_rs) + ('0' & right_operand); when alu_fn_addc => (ALU_C, ALU_result) <= ('0' & GPR_rs) + ('0' & right_operand) + cc_C; when alu_fn_sub => (ALU_C, ALU_result) <= ('0' & GPR_rs) - ('0' & right_operand); when alu_fn_subc => (ALU_C, ALU_result) <= ('0' & GPR_rs) - ('0' & right_operand) - cc_C; when alu_fn_and => (ALU_C, ALU_result) <= ('0' & GPR_rs) and ('0' & right_operand); when alu_fn_or => (ALU_C, ALU_result) <= ('0' & GPR_rs) or ('0' & right_operand); when alu_fn_xor => (ALU_C, ALU_result) <= ('0' & GPR_rs) xor ('0' & right_operand); when alu_fn_mask => (ALU_C, ALU_result) <= ('0' & GPR_rs) and not ('0' & right_operand); when others => (ALU_C, ALU_result) <= 'X' & unsigned_byte'(others => 'X'); end case; else case IR_shift_fn is when shift_fn_shl => (ALU_C, ALU_result) <= ('0' & GPR_rs) sll to_integer(IR_count); when shift_fn_shr => (ALU_result, ALU_C) <= (GPR_rs & '0') srl to_integer(IR_count); when shift_fn_rol => shift_result := GPR_rs rol to_integer(IR_count); ALU_result <= shift_result; ALU_C <= shift_result(unsigned_byte'right); when shift_fn_ror => shift_result := GPR_rs ror to_integer(IR_count); ALU_result <= shift_result; ALU_C <= shift_result(unsigned_byte'left); when others => (ALU_C, ALU_result) <= 'X' & unsigned_byte'(others => 'X'); end case; end if; end process ALU; ALU_Z <= ALU_result ?= unsigned_byte'(others => '0'); ALU_reg : process (clk_i) begin if rising_edge(clk_i) then if state = execute_state then ALU_out <= ALU_result; end if; end if; end process ALU_reg; cc_reg : process (clk_i) begin if rising_edge(clk_i) then if rst_i then cc_Z <= '0'; cc_C <= '0'; elsif state = execute_state and (IR_decode_alu_reg = '1' or IR_decode_alu_immed = '1' or IR_decode_shift = '1') then cc_Z <= ALU_Z; cc_C <= ALU_C; elsif state = decode_state and IR_decode_misc = '1' and IR_misc_fn = misc_fn_reti then cc_Z <= int_Z; cc_C <= int_C; end if; end if; end process cc_reg; D_state <= '1' when (state = execute_state or state = mem_state) and IR_decode_mem = '1' else '0'; D_reg : process (clk_i) begin if rising_edge(clk_i) then if D_state and IR_mem_fn ?= mem_fn_ldm and data_ack_i then D <= unsigned(data_dat_i); elsif D_state and IR_mem_fn ?= mem_fn_inp and port_ack_i then D <= unsigned(port_dat_i); end if; end if; end process D_reg; data_cyc_o <= D_state and (IR_mem_fn ?= mem_fn_stm or IR_mem_fn ?= mem_fn_ldm); data_stb_o <= D_state and (IR_mem_fn ?= mem_fn_stm or IR_mem_fn ?= mem_fn_ldm); data_we_o <= D_state and IR_mem_fn ?= mem_fn_stm; data_adr_o <= ALU_result; data_dat_o <= std_ulogic_vector(GPR_r2); port_cyc_o <= D_state and (IR_mem_fn ?= mem_fn_inp or IR_mem_fn ?= mem_fn_out); port_stb_o <= D_state and (IR_mem_fn ?= mem_fn_inp or IR_mem_fn ?= mem_fn_out); port_we_o <= D_state and IR_mem_fn ?= mem_fn_out; port_adr_o <= ALU_result; port_dat_o <= std_ulogic_vector(GPR_r2); debug_monitor : if debug generate debugger : process use std.textio.all; variable disassembled_instr : disassembled_instruction; variable debug_line : line; variable PC_num : natural; begin wait until rising_edge(clk_i); loop if rst_i then swrite(debug_line, "Resetting"); writeline(output, debug_line); wait until rising_edge(clk_i) and rst_i = '0'; next; elsif state = fetch_state then PC_num := to_integer(PC); elsif state = decode_state then disassemble(IR, disassembled_instr); write(debug_line, PC_num, field => 4, justified => right); swrite(debug_line, ": "); write(debug_line, disassembled_instr); writeline(output, debug_line); wait until rising_edge(clk_i) and (rst_i ='1' or state /= decode_state); next; elsif state = int_state then PC_num := to_integer(PC); swrite(debug_line, "Interrupt acknowledged at PC = "); write(debug_line, PC_num, field => 4, justified => right); writeline(output, debug_line); end if; wait until rising_edge(clk_i); end loop; end process debugger; end generate debug_monitor; end architecture rtl_unpipelined; ---------------------------------------------------------------- -- 22.3.2 Verifying the RTL Model ---------------------------------------------------------------- -- Page 720 - 721 configuration test_gumnut_rtl_unpipelined of test is for gumnut for dut : gumnut_with_mem use entity work.gumnut_with_mem(struct); for struct for core : gumnut use entity work.gumnut(rtl_unpipelined) generic map ( debug => true ); end for; end for; end for; end for; end configuration test_gumnut_rtl_unpipelined; ---------------------------------------------------------------- -- 22.4 A Digital Alarm Clock ---------------------------------------------------------------- ---------------------------------------------------------------- -- 22.4.1 System Design ---------------------------------------------------------------- -- Page 723 library ieee; use ieee.std_logic_1164.all; entity alarm_clock is generic ( debug : boolean := false ); port ( clk : in std_ulogic; pb : in std_ulogic_vector(3 downto 0); sw : in std_ulogic_vector(7 downto 0); led : out std_ulogic_vector(7 downto 0); digit : out std_ulogic_vector(3 downto 0); seg : out std_ulogic_vector(7 downto 0) ); end entity alarm_clock ; -- Pages 723 - 726 library ieee; use ieee.numeric_std.all; architecture synth of alarm_clock is component gumnut_with_mem is generic ( debug : boolean := false ); port ( clk_i : in std_ulogic; rst_i : in std_ulogic; port_cyc_o : out std_ulogic; port_stb_o : out std_ulogic; port_we_o : out std_ulogic; port_ack_i : in std_ulogic; port_adr_o : out unsigned(7 downto 0); port_dat_o : out std_ulogic_vector(7 downto 0); port_dat_i : in std_ulogic_vector(7 downto 0); int_req : in std_ulogic; int_ack : out std_ulogic ); end component gumnut_with_mem; signal reset : std_ulogic; signal port_cyc_o : std_ulogic; signal port_stb_o : std_ulogic; signal port_we_o : std_ulogic; signal port_ack_i : std_ulogic; signal port_adr_o : unsigned(7 downto 0); signal port_dat_o : std_ulogic_vector(7 downto 0); signal port_dat_i : std_ulogic_vector(7 downto 0); signal int_req : std_ulogic; signal int_ack : std_ulogic; signal pb_synch : std_ulogic_vector(pb'range); signal sw_synch : std_ulogic_vector(sw'range); signal clk_1MHz : std_ulogic; begin -- reset generation reset_gen : reset <= '0'; -- processor core core : gumnut_with_mem generic map ( debug => debug ) port map ( clk_i => clk, rst_i => reset, port_cyc_o => port_cyc_o, port_stb_o => port_stb_o, port_we_o => port_we_o, port_ack_i => port_ack_i, port_adr_o => port_adr_o, port_dat_o => port_dat_o, port_dat_i => port_dat_i, int_req => int_req, int_ack => int_ack ); port_ack_i <= '1'; -- input port: -- push buttons 1 and 0 when port_addr = "-------0" -- switches when port_addr = "-------1" synch : process ( clk ) variable pb_tmp : std_ulogic_vector(pb'range); variable sw_tmp : std_ulogic_vector(sw'range); begin if rising_edge(clk) then pb_synch <= pb_tmp; sw_synch <= sw_tmp; pb_tmp := pb; sw_tmp := sw; end if; end process synch; with port_adr_o(0) select port_dat_i <= "0000" & pb_synch when '0', sw_synch when '1', "XXXXXXXX" when others; -- digit output port register (port_addr = "-------1") digit_reg : process (clk) begin if rising_edge(clk) then if reset = '1' then digit <= "1111"; elsif port_cyc_o = '1' and port_stb_o = '1' and port_we_o = '1' and port_adr_o(0) = '1' then digit <= not port_dat_o(3 downto 0); end if; end if; end process digit_reg; -- segment output port register (port_addr = "------1-") seg_reg : process (clk) begin if rising_edge(clk) then if reset = '1' then seg <= "11111111"; elsif port_cyc_o = '1' and port_stb_o = '1' and port_we_o = '1' and port_adr_o(1) = '1' then seg <= not port_dat_o; end if; end if; end process seg_reg; -- led output port register (port_addr = "-----1--") led_reg : process (clk, reset) begin if rising_edge(clk) then if reset = '1' then led <= "00000000"; elsif port_cyc_o = '1' and port_stb_o = '1' and port_we_o = '1' and port_adr_o(2) = '1' then led <= port_dat_o; end if; end if; end process led_reg; -- divide 50MHz clock down to 1MHz div_50 : process (clk) variable count : integer range 0 to 49; begin if rising_edge(clk) then if reset = '1' then clk_1MHz <= '0'; count := 49; elsif count = 0 then count := 49; clk_1Mhz <= '1'; else count := count - 1; clk_1Mhz <= '0'; end if; end if; end process div_50; -- timer (port_addr = "----1---") timer : process (clk) variable divisor, count : unsigned(7 downto 0); begin if rising_edge(clk) then if reset = '1' then divisor := X"00"; count := X"00"; int_req <= '0'; elsif port_cyc_o = '1' and port_stb_o = '1' and port_we_o = '1' and port_adr_o(3) = '1' then divisor := unsigned(port_dat_o); count := divisor; elsif clk_1MHz = '1' then if count = 0 then int_req <= '1'; count := divisor; else count := count - 1; end if; end if; if int_ack = '1' then int_req <= '0'; end if; end if; end process timer; end architecture synth; -- Pages 727 - 729 library ieee; use ieee.std_logic_1164.all; entity alarm_clock_top is generic ( debug : boolean := false ); port ( clk50in : in std_ulogic; pb_in : in std_ulogic_vector(3 downto 0); sw_in : in std_ulogic_vector(7 downto 0); led_out : out std_ulogic_vector(7 downto 0); digit_out : out std_ulogic_vector(3 downto 0); seg_out : out std_ulogic_vector(7 downto 0) ); end entity alarm_clock_top ; ---------------------------------------------------------------- library unisim; use unisim.vcomponents.all ; architecture struct of alarm_clock_top is signal clkint : std_ulogic; signal clk : std_ulogic; signal pb : std_ulogic_vector(pb_in'range); signal sw : std_ulogic_vector(sw_in'range); signal led : std_ulogic_vector(led_out'range); signal digit : std_ulogic_vector(digit_out'range); signal seg : std_ulogic_vector(seg_out'range); component alarm_clock is generic ( debug : boolean := false ); port ( clk : in std_ulogic; pb : in std_ulogic_vector(3 downto 0); sw : in std_ulogic_vector(7 downto 0); led : out std_ulogic_vector(7 downto 0); digit : out std_ulogic_vector(3 downto 0); seg : out std_ulogic_vector(7 downto 0) ); end component alarm_clock ; begin -- input/output and clock buffers clkin_ibuf : component ibufg_lvcmos33 port map ( i => clk50in, o => clkint ); clk_bufg : component bufg port map ( i => clkint, o => clk ) ; pb_buf_gen : for i in 0 to 3 generate pb_buf : component ibuf_lvcmos33 port map ( i => pb_in(i), o => pb(i) ); end generate pb_buf_gen; sw_buf_gen : for i in 0 to 7 generate sw_buf : component ibuf_lvcmos33 port map ( i => sw_in(i), o => sw(i) ); end generate sw_buf_gen; led_buf_gen : for i in 0 to 7 generate led_buf : component obuf_lvcmos33 port map ( i => led(i), o => led_out(i) ); end generate led_buf_gen; digit_buf_gen : for i in 0 to 3 generate digit_buf : component obuf_lvcmos33 port map ( i => digit(i), o => digit_out(i) ); end generate digit_buf_gen; seg_buf_gen : for i in 0 to 7 generate seg_buf : component obuf_lvcmos33 port map ( i => seg(i), o => seg_out(i) ); end generate seg_buf_gen; -- the alarm clock core alarm_clock_core : alarm_clock generic map ( debug => debug ) port map ( clk => clk, pb => pb, sw => sw, led => led, digit => digit, seg => seg ); end architecture struct; ---------------------------------------------------------------- -- 22.4.2 Synthesizing and Implementing the Alarm Clock ---------------------------------------------------------------- ---------------------------------------------------------------- -- Exercises ----------------------------------------------------------------