URL
https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk
Subversion Repositories forth-cpu
[/] [forth-cpu/] [trunk/] [top.vhd] - Rev 4
Go to most recent revision | Compare with Previous | Blame | View Log
--------------------------------------------------------------------------------- --| @file top.vhd --| @brief This file is the top level of the project. --| It presents an interface between the CPU, --| RAM, and all the I/O modules. --| --| @author Richard James Howe. --| @copyright Copyright 2017 Richard James Howe. --| @license MIT --| @email howe.r.j.89@gmail.com --| --------------------------------------------------------------------------------- library ieee,work; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.core_pkg.all; use work.vga_pkg.all; use work.led_pkg.all; use work.kbd_pkg.ps2_kbd_top; use work.uart_pkg.uart_core; use work.util.state_block_changed; entity top is generic( clock_frequency: positive := 100_000_000; uart_baud_rate: positive := 115200; uart_fifo_depth: positive := 8); port ( -- synthesis translate_off debug: out cpu_debug_interface; -- synthesis translate_on clk: in std_ulogic := 'X'; -- clock -- Buttons btnu: in std_ulogic := 'X'; -- button up btnd: in std_ulogic := 'X'; -- button down btnc: in std_ulogic := 'X'; -- button centre btnl: in std_ulogic := 'X'; -- button left btnr: in std_ulogic := 'X'; -- button right -- Switches sw: in std_ulogic_vector(7 downto 0) := (others => 'X'); -- switches -- Simple LED outputs an: out std_ulogic_vector(3 downto 0) := (others => '0'); -- anodes 7 segment display ka: out std_ulogic_vector(7 downto 0) := (others => '0'); -- cathodes 7 segment display ld: out std_ulogic_vector(7 downto 0) := (others => '0'); -- leds -- UART rx: in std_ulogic := 'X'; -- uart rx tx: out std_ulogic := '0'; -- uart tx -- VGA o_vga: out vga_physical_interface; -- PS/2 Interface ps2_keyboard_data: in std_ulogic := '0'; ps2_keyboard_clk: in std_ulogic := '0'; -- Memory Interface RamCS: out std_ulogic := '1'; MemOE: out std_ulogic := '0'; -- negative logic MemWR: out std_ulogic := '0'; -- negative logic MemAdv: out std_ulogic := '0'; -- negative logic MemWait: out std_ulogic := '0'; -- positive! FlashCS: out std_ulogic := '0'; FlashRp: out std_ulogic := '1'; MemAdr: out std_ulogic_vector(26 downto 1) := (others => '0'); MemDB: inout std_logic_vector(15 downto 0) := (others => 'Z')); end; architecture behav of top is constant timer_length: positive := 16; constant number_of_interrupts: positive := 8; constant number_of_led_displays: positive := 4; constant timer_period_us: positive := 20000; -- Signals signal rst: std_ulogic := '0'; -- CPU H2 IO interface signals. signal cpu_wait: std_ulogic := '0'; signal io_wr: std_ulogic := '0'; signal io_re: std_ulogic := '0'; signal io_din: std_ulogic_vector(15 downto 0) := (others => '0'); signal io_dout: std_ulogic_vector(15 downto 0) := (others => '0'); signal io_daddr: std_ulogic_vector(15 downto 0) := (others => '0'); -- CPU H2 Interrupts signal cpu_irq: std_ulogic := '0'; signal cpu_irc: std_ulogic_vector(number_of_interrupts - 1 downto 0) := (others => '0'); signal cpu_irc_mask_we: std_ulogic := '0'; signal clk25MHz: std_ulogic:= '0'; signal clk50MHz: std_ulogic:= '0'; attribute buffer_type: string; attribute buffer_type of clk50MHz: signal is "BUFG"; attribute buffer_type of clk25MHz: signal is "BUFG"; -- Basic IO register ---- LEDs/Switches signal ld_we: std_ulogic := '0'; ---- VGA signal vga_data: std_ulogic_vector(7 downto 0) := (others => '0'); signal vga_data_we: std_ulogic := '0'; signal vga_data_busy: std_ulogic := '0'; ---- UART signal rx_data: std_ulogic_vector(7 downto 0) := (others => '0'); signal rx_data_n: std_ulogic_vector(7 downto 0) := (others => '0'); signal rx_fifo_empty: std_ulogic := '0'; signal rx_fifo_full: std_ulogic := '0'; signal rx_data_re: std_ulogic := '0'; signal rx_data_re_n: std_ulogic := '0'; signal tx_data: std_ulogic_vector(7 downto 0) := (others => '0'); signal tx_fifo_full: std_ulogic := '0'; signal tx_fifo_empty: std_ulogic := '0'; signal tx_data_we: std_ulogic := '0'; ---- Timer signal timer_control_we: std_ulogic := '0'; signal timer_counter_o: std_ulogic_vector(timer_length - 4 downto 0) := (others =>'0'); signal timer_irq: std_ulogic; ---- PS/2 signal kbd_char_buf_new: std_ulogic := '0'; signal kbd_char_buf: std_ulogic_vector(6 downto 0) := (others => '0'); -- ASCII char signal kbd_char_re: std_ulogic := '0'; ---- 8 Segment Display signal leds_reg_we: std_ulogic := '0'; ---- Buttons signal btnu_d: std_ulogic := '0'; -- button up signal btnd_d: std_ulogic := '0'; -- button down signal btnc_d: std_ulogic := '0'; -- button centre signal btnl_d: std_ulogic := '0'; -- button left signal btnr_d: std_ulogic := '0'; -- button right signal button_changed: std_ulogic := '0'; -- Any of the buttons have changed state -- Switches signal sw_d: std_ulogic_vector(sw'range) := (others => '0'); -- Memory signal mem_addr_26_17_we: std_ulogic := '0'; signal mem_addr_16_1_we: std_ulogic := '0'; signal mem_data_i_we: std_ulogic := '0'; signal mem_data_o: std_ulogic_vector(15 downto 0) := (others => '0'); signal mem_control_we: std_ulogic := '0'; signal mem_we: std_ulogic := '0'; signal mem_oe: std_ulogic := '0'; begin ------------------------------------------------------------------------------- -- The Main components ------------------------------------------------------------------------------- ------- Output assignments (Not in a process) --------------------------------- -- @warning These are both temporary measures for testing only! -- rst <= btnu_d; cpu_wait <= btnc_d; irq_block: block signal rx_fifo_not_empty: std_ulogic := '0'; signal tx_fifo_not_empty: std_ulogic := '0'; signal rx_fifo_not_empty_edge: std_ulogic := '0'; signal rx_fifo_full_edge: std_ulogic := '0'; signal tx_fifo_not_empty_edge: std_ulogic := '0'; signal tx_fifo_full_edge: std_ulogic := '0'; signal kbd_char_buf_new_edge: std_ulogic := '0'; begin rx_fifo_not_empty <= not rx_fifo_empty; tx_fifo_not_empty <= not rx_fifo_empty; -- @note It might be best to move this into the IRQ handler, -- to ensure all inputs are edge triggered. irq_edges: work.util.rising_edge_detectors generic map(N => 5) port map( clk => clk, rst => rst, di(0) => rx_fifo_not_empty, di(1) => rx_fifo_full, di(2) => tx_fifo_not_empty, di(3) => tx_fifo_full, di(4) => kbd_char_buf_new, do(0) => rx_fifo_not_empty_edge, do(1) => rx_fifo_full_edge, do(2) => tx_fifo_not_empty_edge, do(3) => tx_fifo_full_edge, do(4) => kbd_char_buf_new_edge); cpu_irc(0) <= '0'; cpu_irc(1) <= rx_fifo_not_empty_edge; cpu_irc(2) <= rx_fifo_full_edge; cpu_irc(3) <= tx_fifo_not_empty_edge; cpu_irc(4) <= tx_fifo_full_edge; cpu_irc(5) <= kbd_char_buf_new_edge; cpu_irc(6) <= timer_irq; cpu_irc(7) <= button_changed; cpu_irq <= '1' when timer_irq = '1' or rx_fifo_not_empty_edge = '1' or rx_fifo_full_edge = '1' or tx_fifo_not_empty_edge = '1' or tx_fifo_full_edge = '1' or kbd_char_buf_new_edge = '1' or button_changed = '1' else '0'; end block; core_0: entity work.core generic map(number_of_interrupts => number_of_interrupts) port map( -- synthesis translate_off debug => debug, -- synthesis translate_on clk => clk, rst => rst, stop => cpu_wait, io_wr => io_wr, io_re => io_re, io_din => io_din, io_dout => io_dout, io_daddr => io_daddr, cpu_irq => cpu_irq, cpu_irc => cpu_irc, cpu_irc_mask => io_dout(number_of_interrupts - 1 downto 0), cpu_irc_mask_we => cpu_irc_mask_we); ------------------------------------------------------------------------------- -- IO ------------------------------------------------------------------------------- -- Xilinx Application Note: -- It seems like it buffers the clock correctly here, so no need to -- use a DCM. However, see: -- http://electronics.stackexchange.com/questions/112534/using-digital-clock-manager-with-verilog-to-generate-25mhz-clock-from-32mhz-inte ---- Clock divider /2. clk50MHz <= '0' when rst = '1' else not clk50MHz when rising_edge(clk); ---- Clock divider /2. Pixel clock is 25MHz clk25MHz <= '0' when rst = '1' else not clk25MHz when rising_edge(clk50MHz); assert not(io_wr = '1' and io_re = '1') report "IO Read/Write issued at same time" severity error; -- assert not(io_wr = '1' or io_re = '1') or not io_daddr(0) = '1' report "Unaligned register access" severity error; vga_data <= io_dout(vga_data'range); tx_data <= io_dout(tx_data'range); io_write: block signal selector: std_ulogic_vector(3 downto 0) := (others => '0'); signal is_write: boolean := false; begin selector <= io_daddr(4 downto 1); is_write <= true when io_wr = '1' else false; tx_data_we <= io_dout(13) when is_write and selector = x"0" else '0'; rx_data_re <= io_dout(10) when is_write and selector = x"0" else '0'; vga_data_we <= io_dout(13) when is_write and selector = x"1" else '0'; kbd_char_re <= io_dout(10) when is_write and selector = x"1" else '0'; timer_control_we <= '1' when is_write and selector = x"2" else '0'; ld_we <= '1' when is_write and selector = x"3" else '0'; mem_data_i_we <= '1' when is_write and selector = x"4" else '0'; mem_addr_26_17_we <= '1' when is_write and selector = x"5" else '0'; mem_control_we <= '1' when is_write and selector = x"5" else '0'; mem_addr_16_1_we <= '1' when is_write and selector = x"6" else '0'; leds_reg_we <= '1' when is_write and selector = x"7" else '0'; cpu_irc_mask_we <= '1' when is_write and selector = x"8" else '0'; end block; io_read: process( io_wr, io_re, io_daddr, sw_d, btnu_d, btnd_d, btnl_d, btnr_d, btnc_d, kbd_char_buf_new, kbd_char_buf, rx_data_n, rx_fifo_empty, rx_fifo_full, tx_fifo_full, tx_fifo_empty, timer_counter_o, vga_data_busy, mem_data_o) begin io_din <= (others => '0'); -- The signal io_re is not needed as none of the reads have -- any side effects case io_daddr(3 downto 1) is when "000" => -- buttons, plus direct access to UART bit. io_din(7 downto 0) <= rx_data_n; io_din(8) <= rx_fifo_empty; io_din(9) <= rx_fifo_full; io_din(11) <= tx_fifo_empty; io_din(12) <= tx_fifo_full; when "001" => -- VT100 status and Keyboard io_din(6 downto 0) <= kbd_char_buf; io_din(8) <= not kbd_char_buf_new; io_din(9) <= kbd_char_buf_new; io_din(11) <= not vga_data_busy; io_din(12) <= vga_data_busy; when "010" => -- Timer in io_din(timer_counter_o'range) <= timer_counter_o; when "011" => -- Switches and buttons io_din <= "000" & btnu_d & btnd_d & btnl_d & btnr_d & btnc_d & sw_d; when "100" => io_din <= mem_data_o; when others => io_din <= (others => '0'); end case; end process; --- UART ---------------------------------------------------------- -- @todo Move registers inside UART module uart_rx_data_reg_we_0: work.util.reg generic map( N => 1) port map( clk => clk, rst => rst, we => '1', di(0) => rx_data_re, do(0) => rx_data_re_n); uart_rx_data_reg_0: work.util.reg generic map( N => rx_data_n'high + 1) port map( clk => clk, rst => rst, we => rx_data_re_n, di => rx_data, do => rx_data_n); uart_0: work.uart_pkg.uart_top generic map( baud_rate => uart_baud_rate, clock_frequency => clock_frequency, fifo_depth => uart_fifo_depth) port map( clk => clk, rst => rst, rx_data => rx_data, rx_fifo_empty => rx_fifo_empty, rx_fifo_full => rx_fifo_full, rx_data_re => rx_data_re, tx_data => tx_data, tx_fifo_full => tx_fifo_full, tx_fifo_empty => tx_fifo_empty, tx_data_we => tx_data_we, tx => tx, rx => rx); --- UART ---------------------------------------------------------- --- LED Output ---------------------------------------------------- led_output_reg_0: entity work.reg generic map(N => ld'high + 1) port map( clk => clk, rst => rst, we => ld_we, di => io_dout(ld'range), do => ld); --- LED Output ---------------------------------------------------- --- Timer --------------------------------------------------------- timer_0: entity work.timer generic map(timer_length => timer_length) port map( clk => clk, rst => rst, we => timer_control_we, control_i => io_dout, counter_o => timer_counter_o, irq => timer_irq); --- Timer --------------------------------------------------------- --- VGA ----------------------------------------------------------- vt100_0: work.vga_pkg.vt100 port map( clk => clk, clk25MHz => clk25MHz, rst => rst, we => vga_data_we, char => vga_data, busy => vga_data_busy, o_vga => o_vga); --- VGA ----------------------------------------------------------- --- Keyboard ------------------------------------------------------ keyboard_0: work.kbd_pkg.keyboard generic map( clock_frequency => clock_frequency, ps2_debounce_counter_size => 8) port map( clk => clk, rst => rst, ps2_clk => ps2_keyboard_clk, ps2_data => ps2_keyboard_data, kbd_char_re => kbd_char_re, kbd_char_buf_new => kbd_char_buf_new, kbd_char_buf => kbd_char_buf); --- Keyboard ------------------------------------------------------ --- LED 8 Segment display ----------------------------------------- ledseg_0: entity work.led_8_segment_display generic map( number_of_led_displays => number_of_led_displays, clock_frequency => clock_frequency, use_bcd_not_hex => false) port map( clk => clk, rst => rst, leds_we => leds_reg_we, leds => io_dout, an => an, ka => ka); --- LED 8 Segment display ----------------------------------------- --- Buttons ------------------------------------------------------- button_debouncer: work.util.debounce_block_us generic map( N => 5, clock_frequency => clock_frequency, timer_period_us => timer_period_us) port map( clk => clk, di(0) => btnu, di(1) => btnd, di(2) => btnc, di(3) => btnl, di(4) => btnr, do(0) => btnu_d, do(1) => btnd_d, do(2) => btnc_d, do(3) => btnl_d, do(4) => btnr_d); dpad_changed: block signal changed_signals: std_ulogic_vector(4 downto 0) := (others => '0'); signal any_changed_signals: std_ulogic := '0'; begin state_changed: work.util.state_block_changed generic map(N => changed_signals'length) port map( clk => clk, rst => rst, di(0) => btnu_d, di(1) => btnd_d, di(2) => btnc_d, di(3) => btnl_d, di(4) => btnr_d, do => changed_signals); any_changed_signals <= '1' when changed_signals /= "00000" else '0'; state_changed_reg: work.util.reg generic map(N => 1) port map( clk => clk, rst => rst, di(0) => any_changed_signals, we => '1', do(0) => button_changed); end block; --- Buttons ------------------------------------------------------- --- Switches ------------------------------------------------------ sw_debouncer: work.util.debounce_block_us generic map( N => sw'high+1, clock_frequency => clock_frequency, timer_period_us => timer_period_us) port map(clk => clk, di => sw, do => sw_d); --- Switches ------------------------------------------------------ --- Memory Interface ---------------------------------------------- ram_interface_0: entity work.ram_interface port map( clk => clk, rst => rst, mem_addr_16_1 => io_dout, mem_addr_16_1_we => mem_addr_16_1_we, mem_addr_26_17 => io_dout(9 downto 0), mem_addr_26_17_we => mem_addr_26_17_we, mem_control_i => io_dout(15 downto 10), mem_control_we => mem_control_we, mem_data_i => io_dout, mem_data_i_we => mem_data_i_we, mem_data_o => mem_data_o, RamCS => RamCS, MemOE => MemOE, MemWR => MemWR, MemAdv => MemAdv, MemWait => MemWait, FlashCS => FlashCS, FlashRp => FlashRp, MemAdr => MemAdr, MemDB => MemDB); --- Memory Interface ---------------------------------------------- ------------------------------------------------------------------------------- end architecture;
Go to most recent revision | Compare with Previous | Blame | View Log