OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [top.vhd] - Rev 5

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.kbd_pkg.ps2_kbd_top;
use work.util.all;
use work.uart_pkg.all;
 
entity top is
	generic(
		g: common_generics         := default_settings;
		reset_period_us:  natural  := 100;
		uart_baud:        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
		ram_cs:    out   std_ulogic := '1';
		mem_oe:    out   std_ulogic := '0'; -- negative logic
		mem_wr:    out   std_ulogic := '0'; -- negative logic
		mem_adv:   out   std_ulogic := '0'; -- negative logic
		mem_wait:  out   std_ulogic := '0'; -- positive logic!
		flash_cs:  out   std_ulogic := '0';
		flash_rp:  out   std_ulogic := '1';
		mem_addr:  out   std_ulogic_vector(26 downto 1) := (others => '0');
		mem_data:  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;
	constant use_sine:               boolean  := false;
 
	-- 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_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_fifo_empty:     std_ulogic := '0';
	signal rx_fifo_full:      std_ulogic := '0';
	signal rx_data_re:        std_ulogic := '0';
 
	signal tx_fifo_full:      std_ulogic := '0';
	signal tx_fifo_empty:     std_ulogic := '0';
	signal tx_data_we:        std_ulogic := '0';
 
	signal uart_clock_tx_we:  std_ulogic := '0';
	signal uart_clock_rx_we:  std_ulogic := '0';
	signal uart_control_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 sine_we: std_ulogic := '0';
	signal sine: std_ulogic_vector(15 downto 0) := (others => '0');
 
begin
-------------------------------------------------------------------------------
-- The Main components
-------------------------------------------------------------------------------
 
	cpu_wait   <= btnc_d; -- temporary testing measure only!
 
	system_reset: work.util.reset_generator
	generic map (g => g, reset_period_us => reset_period_us)
	port map (
		clk        => clk,
		rst        => rst);
 
	-- NB. Video blanking interrupts would be useful for writing
	-- graphics code (if the VGA module had a graphics mode, which it
	-- currently does not).
	cpu_irc(0) <= btnu_d; -- configurable CPU reset (can mask this)
	cpu_irc(1) <= not rx_fifo_empty;
	cpu_irc(2) <= rx_fifo_full;
	cpu_irc(3) <= not tx_fifo_empty;
	cpu_irc(4) <= tx_fifo_full;
	cpu_irc(5) <= kbd_char_buf_new;
	cpu_irc(6) <= timer_irq;
	cpu_irc(7) <= button_changed;
 
	core_0: entity work.core
	generic map (g => g, 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_irc          => cpu_irc,
		cpu_irc_mask     => io_dout(number_of_interrupts - 1 downto 0),
		cpu_irc_mask_we  => cpu_irc_mask_we);
 
	-------------------------------------------------------------------------------
	-- IO
	-------------------------------------------------------------------------------
 
	-- NOTE: A Wishbone Interface on each of the components would simplify the
	-- system overall. However, each peripheral would need an interface
	-- specifying. This module could be made to be much smaller.
	-- See: <https://en.wikipedia.org/wiki/Wishbone_(computer_bus)>
	-- And: <http://cdn.opencores.org/downloads/wbspec_b4.pdf>
 
	-- 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);
 
	-- It possible for CPU to issue both signals at the same time, but it should
	-- not happen with a standard instruction.
	assert not(io_wr = '1' and io_re = '1') report "IO Read/Write issued at same time" severity error;
 
	vga_data <= io_dout(vga_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';
 
		uart_clock_tx_we  <= '1'         when is_write and selector = x"9" else '0';
		uart_clock_rx_we  <= '1'         when is_write and selector = x"A" else '0';
		uart_control_we   <= '1'         when is_write and selector = x"B" else '0';
 
		sine_o: if use_sine generate
		sine_we           <= '1'         when is_write and selector = x"C" else '0';
		end generate;
	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,
		rx_fifo_empty,
		rx_fifo_full,
 
		tx_fifo_full,
		tx_fifo_empty,
 
		timer_counter_o,
 
		vga_data_busy,
		sine,
 
		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;
			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 "101" =>
			if use_sine then
				io_din <= sine;
			end if;
		when others => io_din <= (others => '0');
		end case;
	end process;
 
	--- Sine ----------------------------------------------------------
	sine_gen_0: if use_sine generate
		sine_0: work.util.sine
			generic map(g => g)
			port map(clk => clk, rst => rst, xwe => sine_we, x => io_dout, s => sine);
	end generate;
	--- Sine ----------------------------------------------------------
 
	--- UART ----------------------------------------------------------
	uart_fifo_0: work.uart_pkg.uart_top
		generic map (g => g, baud => uart_baud, use_fifo => true)
		port map (
			clk => clk,
			rst => rst,
 
			tx            => tx,
			tx_fifo_full  => tx_fifo_full,
			tx_fifo_empty => tx_fifo_empty,
			tx_fifo_we    => tx_data_we,
			tx_fifo_data  => io_dout(7 downto 0),
 
			rx            => rx,
			rx_fifo_re    => rx_data_re,
			rx_fifo_data  => rx_data,
			rx_fifo_full  => rx_fifo_full,
			rx_fifo_empty => rx_fifo_empty,
 
			reg             => io_dout,
			clock_reg_tx_we => uart_clock_tx_we,
			clock_reg_rx_we => uart_clock_rx_we,
			control_reg_we  => uart_control_we);
	--- UART ----------------------------------------------------------
 
	--- LED Output ----------------------------------------------------
	led_output_reg_0: entity work.reg
		generic map (g => g, N => ld'length)
		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 (g => g, 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 -----------------------------------------------------------
	vga_selector: block
		constant use_vt100: boolean := true;
	begin
		gen_vt100_0: if use_vt100 generate
		vt100_0: work.vga_pkg.vt100
			generic map (g => g)
			port map (
				clk         =>  clk,
				clk25MHz    =>  clk25MHz,
				rst         =>  rst,
				we          =>  vga_data_we,
				char        =>  vga_data,
				busy        =>  vga_data_busy,
				o_vga       =>  o_vga);
		end generate;
 
		-- Test code
		-- NOTE: Timing is not the best, VGA monitor loses synchronization
		-- every so often with this module.
		vga_gen_c1: if not use_vt100 generate
		vga_c1: block
			signal row, column: integer := 0;
			signal h_blank, v_blank, draw: std_ulogic := '0';
		begin
			draw <= not h_blank and not v_blank;
			vga_c: work.util.vga_controller
			generic map (
				g => g,
				pixel_clock_frequency => 25_000_000,
				cfg => work.util.vga_640x480)
			port map (
				clk    => clk25MHz,
				rst    => rst,
				row    => row,
				column => column,
				h_blank => h_blank,
				v_blank => v_blank,
				h_sync => o_vga.hsync,
				v_sync => o_vga.vsync);
			o_vga.red   <= "111" when draw = '1' else "000";
			o_vga.green <= "111" when (draw = '1' and row < 100 and column < 100) else "000";
			o_vga.blue  <= "11";
		end block;
		end generate;
	end block;
	--- VGA -----------------------------------------------------------
 
	--- Keyboard ------------------------------------------------------
	keyboard_0: work.kbd_pkg.keyboard
	generic map (g => g, 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_7_segment_display
	generic map (
		g                      => g,
		number_of_led_displays => number_of_led_displays,
		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 (g => g, N => 5, 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 (g => g, 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 (g => g, 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 (g => g, N => sw'length, 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
	generic map (g => g)
	port map (
		clk               =>  clk,
		rst               =>  rst,
		mem_addr_16_1     =>  io_dout(io_dout'high downto 1),
		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,
		ram_cs            =>  ram_cs,
		mem_oe            =>  mem_oe,
		mem_wr            =>  mem_wr,
		mem_adv           =>  mem_adv,
		mem_wait          =>  mem_wait,
		flash_cs          =>  flash_cs,
		flash_rp          =>  flash_rp,
		mem_addr          =>  mem_addr,
		mem_data          =>  mem_data);
	--- Memory Interface ----------------------------------------------
 
-------------------------------------------------------------------------------
end architecture;
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.