From 8e49e9b08708f1a5a9711e89a9424b4295773225 Mon Sep 17 00:00:00 2001 From: the great greene arkleseizure Date: Sat, 12 Oct 2013 08:17:43 +0100 Subject: fish --- debugger.vhd | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 debugger.vhd (limited to 'debugger.vhd') diff --git a/debugger.vhd b/debugger.vhd new file mode 100644 index 0000000..1d78bd5 --- /dev/null +++ b/debugger.vhd @@ -0,0 +1,300 @@ +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- +-- General purpose hardware debugger +-- +-- (C) 2011 Mike Stirling +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity debugger is +generic ( + -- Set this for a reasonable half flash duration relative to the + -- clock frequency + flash_divider : natural := 24 + ); +port ( + CLOCK : in std_logic; + nRESET : in std_logic; + -- CPU clock enable in + CLKEN_IN : in std_logic; + -- Gated clock enable back out to CPU + CLKEN_OUT : out std_logic; + -- CPU IRQ in + nIRQ_IN : in std_logic; + -- Gated IRQ back out to CPU (no interrupts when single stepping) + nIRQ_OUT : out std_logic; + + -- CPU + A_CPU : in std_logic_vector(15 downto 0); + R_nW : in std_logic; + SYNC : in std_logic; + + -- Aux bus input for display in hex + AUX_BUS : in std_logic_vector(15 downto 0); + + -- Controls + -- RUN or HALT CPU + RUN : in std_logic; + -- Push button to single-step in HALT mode + nSTEP : in std_logic; + -- Push button to cycle display mode + nMODE : in std_logic; + -- Push button to cycle display digit in edit mode + nDIGIT : in std_logic; + -- Push button to cycle digit value in edit mode + nSET : in std_logic; + + -- Output to display + DIGIT3 : out std_logic_vector(6 downto 0); + DIGIT2 : out std_logic_vector(6 downto 0); + DIGIT1 : out std_logic_vector(6 downto 0); + DIGIT0 : out std_logic_vector(6 downto 0); + + LED_BREAKPOINT : out std_logic; + LED_WATCHPOINT : out std_logic + ); +end entity; + +architecture rtl of debugger is + +component seg7 is +port ( + D : in std_logic_vector(3 downto 0); + Q : out std_logic_vector(6 downto 0) +); +end component; + +-- Current display mode +type mode_t is (modeAddress,modeBreak,modeWatch,modeAux); +signal mode : mode_t; +-- Current edit digit +signal digit : unsigned(1 downto 0); +-- For flashing selected digit +signal counter : unsigned(flash_divider-1 downto 0); +signal flash : std_logic; +-- Selected breakpoint address (stop on instruction fetch) +signal breakpoint : std_logic_vector(15 downto 0); +-- Selected watchpoint address (stop on write) +signal watchpoint : std_logic_vector(15 downto 0); +-- Address of last instruction fetch +signal instr_addr : std_logic_vector(15 downto 0); +-- Break flags +signal halt : std_logic; +-- Set when a request to resume has been received but before +-- the CPU has run +signal resuming : std_logic; + +-- Display interface +signal a_display : std_logic_vector(15 downto 0); +signal d3_display : std_logic_vector(6 downto 0); +signal d2_display : std_logic_vector(6 downto 0); +signal d1_display : std_logic_vector(6 downto 0); +signal d0_display : std_logic_vector(6 downto 0); + +-- Registered button inputs +signal r_step_n : std_logic; +signal r_mode_n : std_logic; +signal r_digit_n : std_logic; +signal r_set_n : std_logic; + +begin + -- Mask CPU clock enable + CLKEN_OUT <= CLKEN_IN and not halt; + -- Mask interrupt + nIRQ_OUT <= nIRQ_IN or not RUN; + + -- Route selected address to display + a_display <= instr_addr when mode = modeAddress else + breakpoint when mode = modeBreak else + watchpoint when mode = modeWatch else + AUX_BUS when mode = modeAux else + (others => '0'); + + -- Generate display digits from binary + d3 : seg7 port map (a_display(15 downto 12),d3_display); + d2 : seg7 port map (a_display(11 downto 8),d2_display); + d1 : seg7 port map (a_display(7 downto 4),d1_display); + d0 : seg7 port map (a_display(3 downto 0),d0_display); + + -- Flash selected digit in edit modes + DIGIT3 <= d3_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "11") else "1111111"; + DIGIT2 <= d2_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "10") else "1111111"; + DIGIT1 <= d1_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "01") else "1111111"; + DIGIT0 <= d0_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "00") else "1111111"; + + -- Show mode on LEDs + LED_BREAKPOINT <= '1' when mode = modeBreak or mode = modeAux else '0'; + LED_WATCHPOINT <= '1' when mode = modeWatch or mode = modeAux else '0'; + + -- Flash counter + process(CLOCK,nRESET) + begin + if nRESET = '0' then + counter <= (others => '0'); + flash <= '0'; + elsif rising_edge(CLOCK) then + counter <= counter + 1; + if counter = 0 then + flash <= not flash; + end if; + end if; + end process; + + -- Register buttons, select input mode and digit + process(CLOCK,nRESET) + begin + if nRESET = '0' then + r_mode_n <= '1'; + r_digit_n <= '1'; + r_set_n <= '1'; + mode <= modeAddress; + digit <= (others => '0'); + elsif rising_edge(CLOCK) then + -- Register buttons + r_mode_n <= nMODE; + r_digit_n <= nDIGIT; + r_set_n <= nSET; + + if r_mode_n = '1' and nMODE = '0' then + -- Increment mode + if mode = modeAddress then + mode <= modeBreak; + elsif mode = modeBreak then + mode <= modeWatch; + elsif mode = modeWatch then + mode <= modeAux; + else + mode <= modeAddress; + end if; + end if; + if r_digit_n = '1' and nDIGIT = '0' then + -- Increment digit + digit <= digit + 1; + end if; + end if; + end process; + + -- Set watchpoint address + process(CLOCK,nRESET) + begin + if nRESET = '0' then + watchpoint <= (others => '1'); + elsif rising_edge(CLOCK) and mode = modeWatch then + if r_set_n = '1' and nSET = '0' then + -- Increment selected digit on each button press + case digit is + when "00" => watchpoint(3 downto 0) <= std_logic_vector(unsigned(watchpoint(3 downto 0)) + 1); + when "01" => watchpoint(7 downto 4) <= std_logic_vector(unsigned(watchpoint(7 downto 4)) + 1); + when "10" => watchpoint(11 downto 8) <= std_logic_vector(unsigned(watchpoint(11 downto 8)) + 1); + when "11" => watchpoint(15 downto 12) <= std_logic_vector(unsigned(watchpoint(15 downto 12)) + 1); + when others => null; + end case; + end if; + end if; + end process; + + -- Set breakpoint address + process(CLOCK,nRESET) + begin + if nRESET = '0' then + breakpoint <= (others => '1'); + elsif rising_edge(CLOCK) and mode = modeBreak then + if r_set_n = '1' and nSET = '0' then + -- Increment selected digit on each button press + case digit is + when "00" => breakpoint(3 downto 0) <= std_logic_vector(unsigned(breakpoint(3 downto 0)) + 1); + when "01" => breakpoint(7 downto 4) <= std_logic_vector(unsigned(breakpoint(7 downto 4)) + 1); + when "10" => breakpoint(11 downto 8) <= std_logic_vector(unsigned(breakpoint(11 downto 8)) + 1); + when "11" => breakpoint(15 downto 12) <= std_logic_vector(unsigned(breakpoint(15 downto 12)) + 1); + + when others => null; + end case; + end if; + end if; + end process; + + -- CPU control logic + process(CLOCK,nRESET) + begin + if nRESET = '0' then + r_step_n <= '1'; + halt <= '0'; + resuming <= '0'; + instr_addr <= (others => '0'); + elsif rising_edge(CLOCK) then + -- Register single-step button + r_step_n <= nSTEP; + + -- Once the CPU has run we can trigger a new halt + if CLKEN_IN = '1' then + resuming <= '0'; + end if; + + if SYNC = '1' then + -- Latch address of instruction fetch + instr_addr <= A_CPU; + end if; + + -- Check for halt conditions if we are not resuming from a previous halt + if resuming = '0' then + if RUN = '0' and SYNC = '1' then + -- If not in RUN mode then halt on any instruction fetch + -- (single-step) + halt <= '1'; + end if; + if A_CPU = breakpoint and SYNC = '1' then + -- Halt CPU when instruction fetched from breakpoint address + halt <= '1'; + end if; + if A_CPU = watchpoint and SYNC = '0' and R_nW = '0' then + -- Halt CPU when data write to watchpoint address + halt <= '1'; + end if; + end if; + + -- Resume or single step when user presses "STEP" button + if r_step_n = '1' and nSTEP = '0' then + resuming <= '1'; + halt <= '0'; + end if; + end if; + end process; +end architecture; -- cgit v1.2.3