6502 disassembler in hardware

Topics relating to PALs, CPLDs, FPGAs, and other PLDs used for the support or creation of 65-family processors, both hardware and HDL.
Post Reply
Cray Ze
Posts: 134
Joined: 02 May 2015

6502 disassembler in hardware

Post by Cray Ze »

Hi all.

It's been a while since I've posted anything here, I was sidetracked by a few *life hurdles*

One of the last FPGA projects I came up with was a 6502 disassembler written in VHDL, I thought it might be of interest to some members of the forum.

Features of note:

. Independent of host CPU
. Independent of host RAM
. Dynamic display (self modifying code and data changes show in real time)
. Disassembly and HexDump modes
. Small size

Currently just a proof of concept, I have it connected to a C64 ROM (and a PC font ROM for character output), though I plan to integrate it into a FPGA based 6502 system at a later date.
̶T̶h̶e̶r̶e̶ ̶a̶r̶e̶ ̶b̶a̶s̶i̶c̶a̶l̶l̶y̶ ̶n̶o̶ ̶c̶o̶m̶m̶e̶n̶t̶s̶ ̶i̶n̶ ̶t̶h̶e̶ ̶s̶o̶u̶r̶c̶e̶,̶ ̶I̶ ̶p̶l̶a̶n̶ ̶t̶o̶ ̶a̶d̶d̶r̶e̶s̶s̶ ̶t̶h̶i̶s̶ ̶s̶o̶o̶n̶.̶ * Source is now commented *
Currently only the 6502 is supported, though I'll add 65C02 support at a later date.

Disassembly of three random sections of the C64 BASIC ROM.
HardMon65-1.JPG
HardMon65-2.JPG
HardMon65-3.JPG
HexDump mode.
HardMon65-4.JPG
Source file:

Code: Select all

--
-- Copyright (c) 2018-2022 Dylan Wakefield (Cray Ze Ape)
--
--
-- This source file is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published
-- by the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This source file is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-- ------------------------------------------
--



library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity Test is
    port(CLOCK_24 : in std_logic;
         Vout:      out unsigned(10 downto 0) -- rrr,ggg,bbb,hsync,vsync
         );
end Test;

architecture Behavioral of Test is

type mnemonic_buffer_array   is array(3 downto 0) of STD_LOGIC_VECTOR(7 downto 0);
signal mnemonic_buffer      : mnemonic_buffer_array;

type address_text_array is array (3 downto 0) of std_logic_vector(7 downto 0);
signal address_text   : address_text_array;   

type line_text_array is array (39 downto 0) of std_logic_vector(7 downto 0);
signal line_text      : line_text_array;   

signal Pixel_Colour   : unsigned(8 DOWNTO 0) := "000000000";
signal VGAout         : unsigned(10 downto 0);
signal hcount         : unsigned(10 downto 0):="00000000000";
signal vcount         : unsigned(9 downto 0):="0000000000";
signal VGA            : unsigned(8 downto 0):="000000000";
signal videoon, videov, videoh, hsync, vsync      : std_ulogic:='0';
signal RST            : std_ulogic:='0';
signal CLOCK_50       : std_ulogic;
signal inslookAddr    : std_LOGIC_VECTOR(9 downto 0);
signal inslookData    : std_LOGIC_VECTOR(7 downto 0);
signal ROMAddr        : std_LOGIC_VECTOR(13 downto 0);
signal ROMData        : std_LOGIC_VECTOR(7 downto 0);
signal charAddr       : std_LOGIC_VECTOR(10 downto 0);
signal charData       : std_LOGIC_VECTOR(7 downto 0);
signal CharX          : unsigned (5 downto 0) := "000000";
signal CharY          : unsigned (5 downto 0) := "000000";
signal Opp1           : std_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
signal Opp2           : std_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
signal Opp3           : std_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
signal Opp4           : std_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
signal Opp5           : std_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
signal Opp6           : std_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
signal Opp7           : std_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";
signal Opp8           : std_LOGIC_VECTOR(7 DOWNTO 0) := "00000000";

begin

fontRom : work.CGAFontBold PORT MAP (
   address => charAddr,
   clock => CLOCK_50,
   q => charData
);

inslookupRom : work.inslookup PORT MAP (
   address => inslookAddr,
   clock => CLOCK_50,
   q => inslookData
);
   
C64ROM : work.C64ROM PORT MAP (
   address    => ROMAddr,
   clock    => CLOCK_50,
   q    => ROMData
);

vgapll : work.vgapll PORT MAP (
      inclk0    => CLOCK_24,
      c0    => CLOCK_50
   );

hcounter: process (CLOCK_50, RST)
begin
   if RST='1' then
      hcount <= "0000000000";
   elsif (rising_edge(CLOCK_50)) then
      hcount <= hcount + 1;
      if hcount=1039 then
         hcount <= "00000000000";
      end if;
   end if;
end process;

vcounter: process (CLOCK_50, RST)
begin
   if RST='1' then
      vcount <= "0000000001";
   elsif (rising_edge(CLOCK_50)) then
      if hcount = 1039 then
         vcount <= vcount + 1;
         if vcount = 665 then
            vcount <= "0000000000";
         end if;
      end if;
   end if;
end process;

process (vcount)
begin
   videov <= '1';
   if vcount > 599 then
      videov <= '0';
   end if;
end process;

process (hcount)
begin
   videoh <= '1';
   if hcount > 799 then
      videoh <= '0';
   end if;
end process;

sync: process (CLOCK_50, RST)
begin
   if RST='1'  then
      hsync <= '0';
      vsync <= '0';
   elsif (rising_edge(CLOCK_50)) then
      hsync <= '1';
      if (hcount <= 987 and hcount >= 855) then
         hsync <= '0';
      end if;
      vsync <= '1';
      if (vcount <= 645 and vcount >= 636) then
         vsync <= '0';
      end if;
   end if;
end process;

DrawApp : PROCESS (CLOCK_50, RST)

   VARIABLE pixelh : unsigned(10 DOWNTO 0) := "00000000000";
   VARIABLE tttph : unsigned(10 DOWNTO 0) := "00000000000";
   VARIABLE tttph2 : unsigned(10 DOWNTO 0) := "00000000000";
   VARIABLE pixelv : unsigned(9 DOWNTO 0) := "0000000000";
   VARIABLE Xchar : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Xchar2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Ychar : unsigned(6 DOWNTO 0) := "0000000";
   VARIABLE address : unsigned(15 DOWNTO 0) := "0000000000000000";
   VARIABLE addressrel : unsigned(15 DOWNTO 0) := "0000000000000000";
   VARIABLE Address_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Address_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Address_ASCI_3 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Address_ASCI_4 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE RelAddress_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE RelAddress_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE RelAddress_ASCI_3 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE RelAddress_ASCI_4 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Opcode_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Opcode_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";

   VARIABLE Operand_1st_Byte_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_1st_Byte_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_2nd_Byte_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_2nd_Byte_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";

   VARIABLE Operand_3rd_Byte_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_3rd_Byte_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_4th_Byte_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_4th_Byte_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_5th_Byte_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_5th_Byte_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_6th_Byte_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_6th_Byte_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_7th_Byte_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_7th_Byte_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_8th_Byte_ASCI_1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Operand_8th_Byte_ASCI_2 : unsigned(7 DOWNTO 0) := "00000000";

   VARIABLE OpLen : unsigned(1 DOWNTO 0) := "00";
   VARIABLE InsMode : unsigned(3 DOWNTO 0) := "0000";

   VARIABLE DisplayMode : std_ulogic:='0';
   
   VARIABLE Op1 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Op2 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Op3 : unsigned(7 DOWNTO 0) := "00000000";

   VARIABLE Op4 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Op5 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Op6 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Op7 : unsigned(7 DOWNTO 0) := "00000000";
   VARIABLE Op8 : unsigned(7 DOWNTO 0) := "00000000";

BEGIN
   IF (rising_edge(CLOCK_50)) THEN

      pixelv := (vcount - 100)/2;
      pixelh := (hcount - 10)/2;

      Ychar := pixelv (9 DOWNTO 3);
      tttph := (hcount - 6)/2; --kludge
      tttph2 := (hcount - 8)/2; --kludge
      --Pixel_Colour <= "111111111";

      DisplayMode := '0';-- '0'=disassembly '1'=HexDump        pixelv (6) for test (synth resource count)

      IF vcount = "000000100" THEN
         address := x"AD1E";--:= x"AD1E";  --x"A3B8";
      END IF;


---------------------------------------------------------------------------------
-- Read 8 bytes from memory every text line (address increment is done elsewhere)
-- This will need to be adapted to suit a live system. A000 is start of ROM in
-- my proof of concept example and should be 0000 (removed) in a live system with
-- access to all of memory
---------------------------------------------------------------------------------
      
      IF vcount(3 DOWNTO 0) = "0100" THEN
         IF hcount = "0000000001" THEN
            ROMAddr <= std_logic_vector(address - x"A000" + (hcount - 1))(13 DOWNTO 0);
         END IF;
         IF hcount = "00000000010" THEN
            ROMAddr <= std_logic_vector(address - x"A000" + (hcount - 1))(13 DOWNTO 0);
         END IF;
         IF hcount = "00000000011" THEN
            ROMAddr <= std_logic_vector(address - x"A000" + (hcount - 1))(13 DOWNTO 0);
            Opp1 <= ROMData;
         END IF;
         IF hcount = "00000000100" THEN
            ROMAddr <= std_logic_vector(address - x"A000" + (hcount - 1))(13 DOWNTO 0);
            Opp2 <= ROMData;
         END IF;
         IF hcount = "00000000101" THEN
            ROMAddr <= std_logic_vector(address - x"A000" + (hcount - 1))(13 DOWNTO 0);
            Opp3 <= ROMData;
         END IF;
         IF hcount = "00000000110" THEN
            ROMAddr <= std_logic_vector(address - x"A000" + (hcount - 1))(13 DOWNTO 0);
            Opp4 <= ROMData;
         END IF;
         IF hcount = "00000000111" THEN
            ROMAddr <= std_logic_vector(address - x"A000" + (hcount - 1))(13 DOWNTO 0);
            Opp5 <= ROMData;
         END IF;
         IF hcount = "00000001000" THEN
            ROMAddr <= std_logic_vector(address - x"A000" + (hcount - 1))(13 DOWNTO 0);
            Opp6 <= ROMData;
         END IF;
         IF hcount = "00000001001" THEN
            Opp7 <= ROMData;
         END IF;
         IF hcount = "00000001010" THEN
            Opp8 <= ROMData;
         END IF;
      END IF;

-----------------------------------------------------------------
-- Type conversion from std_logic_vector to unsigned, we get this
-- for free and it makes the code below much simpler to read
-----------------------------------------------------------------

      Op1 := unsigned(Opp1);
      Op2 := unsigned(Opp2);
      Op3 := unsigned(Opp3);
      Op4 := unsigned(Opp4);
      Op5 := unsigned(Opp5);
      Op6 := unsigned(Opp6);
      Op7 := unsigned(Opp7);
      Op8 := unsigned(Opp8);
-----------------------------------------------------------------
   
      addressrel := address + 2;
      IF Op2(7) = '1' THEN
         addressrel (7 DOWNTO 0) := addressrel (7 DOWNTO 0) + Op2;
      ELSE addressrel := addressrel + Op2;
      END IF;
 
      IF pixelv >= 0 AND pixelv <= 199 AND pixelh >= 0 AND pixelh <= 320 THEN -- kludge - should be 319, but using 320 until after screen position changes (stops right hand char bleed in mem display).
         Pixel_Colour <= "000000111";
         Ychar := pixelv (9 DOWNTO 3);
         Xchar2 := tttph (10 DOWNTO 3);
         Xchar := tttph2 (10 DOWNTO 3);
         IF Xchar >= 1 AND Xchar <= 40 THEN                                                      -- If we are within the 40 char text line
            inslookAddr <= std_logic_vector(Op1) & std_logic_vector((Xchar(1 DOWNTO 0)) - 16);   -- look up the instruction information based on opcode
            IF Xchar = "00000011" THEN
               OpLen := unsigned(inslookData (1 DOWNTO 0));                                      -- Get instruction length
               InsMode := unsigned(inslookData (7 DOWNTO 4));                                    -- Get instruction mode (this is more for text formating than the actual instruction mode)
               IF hcount (3 DOWNTO 0) = "0100" AND vcount (3 DOWNTO 0) = "0011" THEN
                  IF   DisplayMode = '0' THEN
                     address := address + OpLen;                                                 -- Increment address to next opcode ( disassembly mode )
                     ELSIF DisplayMode = '1' THEN
                     address := address + 8;                                                     -- Increment address by 8 ( HexDump mode)
                  END IF;
               END IF;
            END IF;


 ---------------------------------------------------------
 --         Convert address to ASCII
 ---------------------------------------------------------

            Address_ASCI_1 := "0011" & address (15 DOWNTO 12);
            IF address (15 DOWNTO 12) > 9 THEN
               Address_ASCI_1 := "0100" & (address (15 DOWNTO 12) - 9);
            END IF;
            Address_ASCI_2 := "0011" & address (11 DOWNTO 8);
            IF address (11 DOWNTO 8) > 9 THEN
               Address_ASCI_2 := "0100" & (address (11 DOWNTO 8) - 9);
            END IF;
            Address_ASCI_3 := "0011" & address (7 DOWNTO 4);
            IF address (7 DOWNTO 4) > 9 THEN
               Address_ASCI_3 := "0100" & (address (7 DOWNTO 4) - 9);
            END IF;
            Address_ASCI_4 := "0011" & address (3 DOWNTO 0);
            IF address (3 DOWNTO 0) > 9 THEN
               Address_ASCI_4 := "0100" & (address (3 DOWNTO 0) - 9);
            END IF;


 ---------------------------------------------------------
 --         Convert Opcode to ASCII
 ---------------------------------------------------------

            Opcode_ASCI_1 := "0011" & Op1 (7 DOWNTO 4);
            IF Op1 (7 DOWNTO 4) > 9 THEN
               Opcode_ASCI_1 := "0100" & (Op1 (7 DOWNTO 4) - 9);
            END IF;
            Opcode_ASCI_2 := "0011" & Op1 (3 DOWNTO 0);
            IF Op1 (3 DOWNTO 0) > 9 THEN
               Opcode_ASCI_2 := "0100" & (Op1 (3 DOWNTO 0) - 9);
            END IF;


 ----------------------------------------------------------------------------------------------
 --         Convert 1st byte of operand to ASCII ( or space if none, when in disassembly mode )
 ----------------------------------------------------------------------------------------------

            IF DisplayMode = '0' THEN
               Operand_1st_Byte_ASCI_1 := "00100000";            -- Space
               Operand_1st_Byte_ASCI_2 := "00100000";            -- Space
            END IF;
            IF OpLen = 2 OR OpLen = 3 OR DisplayMode = '1' THEN
               Operand_1st_Byte_ASCI_1 := "0011" & Op2 (7 DOWNTO 4);
               IF Op2 (7 DOWNTO 4) > 9 THEN
                  Operand_1st_Byte_ASCI_1 := "0100" & (Op2 (7 DOWNTO 4) - 9);
               END IF;
               Operand_1st_Byte_ASCI_2 := "0011" & Op2 (3 DOWNTO 0);
               IF Op2 (3 DOWNTO 0) > 9 THEN
                  Operand_1st_Byte_ASCI_2 := "0100" & (Op2 (3 DOWNTO 0) - 9);
               END IF;
            END IF;


 ----------------------------------------------------------------------------------------------
 --         Convert 2nd byte of operand to ASCII ( or space if none, when in disassembly mode )
 ----------------------------------------------------------------------------------------------

            IF DisplayMode = '0' THEN
               Operand_2nd_Byte_ASCI_1 := "00100000";            -- Space
               Operand_2nd_Byte_ASCI_2 := "00100000";            -- Space
            END IF;
            IF OpLen = 3 OR DisplayMode = '1' THEN
               Operand_2nd_Byte_ASCI_1 := "0011" & Op3 (7 DOWNTO 4);
               IF Op3 (7 DOWNTO 4) > 9 THEN
                  Operand_2nd_Byte_ASCI_1 := "0100" & (Op3 (7 DOWNTO 4) - 9);
               END IF;
               Operand_2nd_Byte_ASCI_2 := "0011" & Op3 (3 DOWNTO 0);
               IF Op3 (3 DOWNTO 0) > 9 THEN
                  Operand_2nd_Byte_ASCI_2 := "0100" & (Op3 (3 DOWNTO 0) - 9);
               END IF;
            END IF;



 ---------------------------------------------------------------------
 --         Convert 5 more values to ASCII for HexDump mode
 ---------------------------------------------------------------------

               Operand_3rd_Byte_ASCI_1 := "0011" & Op4 (7 DOWNTO 4);
               IF Op4 (7 DOWNTO 4) > 9 THEN
                  Operand_3rd_Byte_ASCI_1 := "0100" & (Op4 (7 DOWNTO 4) - 9);
               END IF;
               Operand_3rd_Byte_ASCI_2 := "0011" & Op4 (3 DOWNTO 0);
               IF Op4 (3 DOWNTO 0) > 9 THEN
                  Operand_3rd_Byte_ASCI_2 := "0100" & (Op4 (3 DOWNTO 0) - 9);
               END IF;

               Operand_4th_Byte_ASCI_1 := "0011" & Op5 (7 DOWNTO 4);
               IF Op5 (7 DOWNTO 4) > 9 THEN
                  Operand_4th_Byte_ASCI_1 := "0100" & (Op5 (7 DOWNTO 4) - 9);
               END IF;
               Operand_4th_Byte_ASCI_2 := "0011" & Op5 (3 DOWNTO 0);
               IF Op5 (3 DOWNTO 0) > 9 THEN
                  Operand_4th_Byte_ASCI_2 := "0100" & (Op5 (3 DOWNTO 0) - 9);
               END IF;

               Operand_5th_Byte_ASCI_1 := "0011" & Op6 (7 DOWNTO 4);
               IF Op6 (7 DOWNTO 4) > 9 THEN
                  Operand_5th_Byte_ASCI_1 := "0100" & (Op6 (7 DOWNTO 4) - 9);
               END IF;
               Operand_5th_Byte_ASCI_2 := "0011" & Op6 (3 DOWNTO 0);
               IF Op6 (3 DOWNTO 0) > 9 THEN
                  Operand_5th_Byte_ASCI_2 := "0100" & (Op6 (3 DOWNTO 0) - 9);
               END IF;

               Operand_6th_Byte_ASCI_1 := "0011" & Op7 (7 DOWNTO 4);
               IF Op7 (7 DOWNTO 4) > 9 THEN
                  Operand_6th_Byte_ASCI_1 := "0100" & (Op7 (7 DOWNTO 4) - 9);
               END IF;
               Operand_6th_Byte_ASCI_2 := "0011" & Op7 (3 DOWNTO 0);
               IF Op7 (3 DOWNTO 0) > 9 THEN
                  Operand_6th_Byte_ASCI_2 := "0100" & (Op7 (3 DOWNTO 0) - 9);
               END IF;

               Operand_7th_Byte_ASCI_1 := "0011" & Op8 (7 DOWNTO 4);
               IF Op8 (7 DOWNTO 4) > 9 THEN
                  Operand_7th_Byte_ASCI_1 := "0100" & (Op8 (7 DOWNTO 4) - 9);
               END IF;
               Operand_7th_Byte_ASCI_2 := "0011" & Op8 (3 DOWNTO 0);
               IF Op8 (3 DOWNTO 0) > 9 THEN
                  Operand_7th_Byte_ASCI_2 := "0100" & (Op8 (3 DOWNTO 0) - 9);
               END IF;



 ---------------------------------------------------------
 --         Convert relative address to ASCII
 ---------------------------------------------------------
   
            RelAddress_ASCI_1 := "0011" & addressrel (15 DOWNTO 12);
            IF addressrel (15 DOWNTO 12) > 9 THEN
               RelAddress_ASCI_1 := "0100" & (addressrel (15 DOWNTO 12) - 9);
            END IF;
            RelAddress_ASCI_2 := "0011" & addressrel (11 DOWNTO 8);
            IF addressrel (11 DOWNTO 8) > 9 THEN
               RelAddress_ASCI_2 := "0100" & (addressrel (11 DOWNTO 8) - 9);
            END IF;
            RelAddress_ASCI_3 := "0011" & addressrel (7 DOWNTO 4);
            IF addressrel (7 DOWNTO 4) > 9 THEN
               RelAddress_ASCI_3 := "0100" & (addressrel (7 DOWNTO 4) - 9);
            END IF;
            RelAddress_ASCI_4 := "0011" & addressrel (3 DOWNTO 0);
            IF addressrel (3 DOWNTO 0) > 9 THEN
               RelAddress_ASCI_4 := "0100" & (addressrel (3 DOWNTO 0) - 9);
            END IF;
 
 
 ------------------------------------------------------------------------------------
 --         Generate 40 character line of output text in line_text_array
 ------------------------------------------------------------------------------------
 
            IF InsMode < 10 THEN
               line_text (20) <= "00101000";                                  -- (
               line_text (21) <= "00100100";                                  -- $
               line_text (22) <= std_logic_vector(Operand_1st_Byte_ASCI_1);   -- Indirect value byte 1   (X or Y is determined by InsMode 8 or 9 - see below)
               line_text (23) <= std_logic_vector(Operand_1st_Byte_ASCI_2);   -- Indirect value byte 2   (X or Y is determined by InsMode 8 or 9 - see below)
            END IF;

            IF InsMode < 8 THEN
               line_text (20) <= "00100100";                                  -- $
               line_text (21) <= std_logic_vector(Operand_2nd_Byte_ASCI_1);   -- Address byte 1
               line_text (22) <= std_logic_vector(Operand_2nd_Byte_ASCI_2);   -- Address byte 2
               line_text (23) <= std_logic_vector(Operand_1st_Byte_ASCI_1);   -- Address byte 3
               line_text (24) <= std_logic_vector(Operand_1st_Byte_ASCI_2);   -- Address byte 4
            END IF;

            IF InsMode = 8 THEN
               line_text (24) <= "00101100";                                  -- ,
               line_text (25) <= "01011000";                                  -- X
               line_text (26) <= "00101001";                                  -- )
            END IF;

            IF InsMode = 9 THEN
               line_text (24) <= "00101001";                                  -- )
               line_text (25) <= "00101100";                                  -- ,
               line_text (26) <= "01011001";                                  -- Y
            END IF;

            IF InsMode = 6 OR InsMode = 7 OR InsMode = 9 THEN
               line_text (25) <= "00101100";                                  -- ,
            END IF;

            IF InsMode = 6 THEN
               line_text (26) <= "01011000";                                  -- X
            END IF;

            IF InsMode = 7 THEN
               line_text (26) <= "01011001";                                  -- Y
            END IF;

            IF InsMode < 5 THEN
               line_text (20) <= "00100100";                                  -- $
               line_text (21) <= std_logic_vector(Operand_1st_Byte_ASCI_1);   -- Zero Page Address byte 1
               line_text (22) <= std_logic_vector(Operand_1st_Byte_ASCI_2);   -- Zero Page Address byte 2
               line_text (23) <= "00101100";                                  -- ,
               line_text (24) <= "01011000";                                  -- X
            END IF;

            IF InsMode = 5 THEN
               line_text (25) <= "00100000";                                  -- Space
               line_text (26) <= "00100000";                                  -- Space
            END IF;

            IF InsMode = 3 THEN
               line_text (24) <= "01011000";                                  -- X
               line_text (25) <= "00100000";                                  -- Space
               line_text (26) <= "00100000";                                  -- Space
            END IF;

            IF InsMode = 4 THEN
               line_text (24) <= "01011001";                                  -- Y
               line_text (25) <= "00100000";                                  -- Space
               line_text (26) <= "00100000";                                  -- Space
            END IF;

            IF InsMode = 2 THEN
               line_text (23) <= "00100000";                                  -- Space
               line_text (24) <= "00100000";                                  -- Space
               line_text (25) <= "00100000";                                  -- Space
               line_text (26) <= "00100000";                                  -- Space
            END IF;

            IF InsMode = 1 THEN
               line_text (20) <= "00100011";                                  -- #
               line_text (21) <= "00100100";                                  -- $
               line_text (22) <= std_logic_vector(Operand_1st_Byte_ASCI_1);   -- Immediate value byte 1
               line_text (23) <= std_logic_vector(Operand_1st_Byte_ASCI_2);   -- Immediate value byte 2
               line_text (24) <= "00100000";                                  -- Space
               line_text (25) <= "00100000";                                  -- Space
               line_text (26) <= "00100000";                                  -- Space
            END IF;

            IF InsMode = 0 THEN
               line_text (20) <= "00100000";                                  -- Space
               line_text (21) <= "00100000";                                  -- Space
               line_text (22) <= "00100000";                                  -- Space
               line_text (23) <= "00100000";                                  -- Space
               line_text (24) <= "00100000";                                  -- Space
               line_text (25) <= "00100000";                                  -- Space
               line_text (26) <= "00100000";                                  -- Space
            END IF;

            IF InsMode = 10 THEN
               line_text (20) <= "00100100";                                  -- $
               line_text (21) <= std_logic_vector(RelAddress_ASCI_1);         -- Address byte 1
               line_text (22) <= std_logic_vector(RelAddress_ASCI_2);         -- Address byte 2
               line_text (23) <= std_logic_vector(RelAddress_ASCI_3);         -- Address byte 3
               line_text (24) <= std_logic_vector(RelAddress_ASCI_4);         -- Address byte 4
               line_text (25) <= "00100000";                                  -- Space
               line_text (26) <= "00100000";                                  -- Space
            END IF;

            IF InsMode = 11 THEN
               line_text (20) <= "00101000";                                  -- (
               line_text (21) <= "00100100";                                  -- $
               line_text (22) <= std_logic_vector(Operand_2nd_Byte_ASCI_1);   -- Address byte 1
               line_text (23) <= std_logic_vector(Operand_2nd_Byte_ASCI_2);   -- Address byte 2
               line_text (24) <= std_logic_vector(Operand_1st_Byte_ASCI_1);   -- Address byte 3
               line_text (25) <= std_logic_vector(Operand_1st_Byte_ASCI_2);   -- Address byte 4
               line_text (26) <= "00101001";                                  -- )
            END IF;

            IF InsMode = 12 THEN
               line_text (20) <= "01000001";                                  -- A
               line_text (21) <= "00100000";                                  -- Space
               line_text (22) <= "00100000";                                  -- Space
               line_text (23) <= "00100000";                                  -- Space
               line_text (24) <= "00100000";                                  -- Space
               line_text (25) <= "00100000";                                  -- Space
               line_text (26) <= "00100000";                                  -- Space
            END IF;

            line_text (0) <= "00101110";                                      -- .
            line_text (1) <= "00101100";                                      -- ,
            line_text (2) <= std_logic_vector(Address_ASCI_1);                -- 1st char of Address
            line_text (3) <= std_logic_vector(Address_ASCI_2);                -- 2nd char of Address
            line_text (4) <= std_logic_vector(Address_ASCI_3);                -- 3rd char of Address
            line_text (5) <= std_logic_vector(Address_ASCI_4);                -- 4th char of Address
            line_text (6) <= "00100000";                                      -- Space
            line_text (7) <= std_logic_vector(Opcode_ASCI_1);                 -- 1st char of Opcode      ( 1st char of 1st byte in HexDump mode )
            line_text (8) <= std_logic_vector(Opcode_ASCI_2);                 -- 2nd char of Opcode      ( 2nd char of 1st byte in HexDump mode )
            line_text (9) <= "00100000";                                      -- Space
            line_text (10) <= std_logic_vector(Operand_1st_Byte_ASCI_1);      -- 1st char 1st Operand      ( 1st char of 2nd byte in HexDump mode )
            line_text (11) <= std_logic_vector(Operand_1st_Byte_ASCI_2);      -- 2nd char 1st Operand      ( 2nd char of 2nd byte in HexDump mode )
            line_text (12) <= "00100000";                                     -- Space
            line_text (13) <= std_logic_vector(Operand_2nd_Byte_ASCI_1);      -- 1st char 2nd Operand      ( 1st char of 3rd byte in HexDump mode )
            line_text (14) <= std_logic_vector(Operand_2nd_Byte_ASCI_2);      -- 2nd char 2nd Operand      ( 2nd char of 3rd byte in HexDump mode )
            line_text (15) <= "00100000";                                     -- Space
            line_text (to_integer(Xchar2)) <= inslookData;                    -- 3 char instruction mnemonic
            line_text (19) <= "00100000";                                     -- Space
            line_text (27) <= "00100000";                                     -- Space
            line_text (28) <= "00100000";                                     -- Space
            line_text (29) <= "00100000";                                     -- Space
            line_text (30) <= "00100000";                                     -- Space
            line_text (31) <= "00100000";                                     -- Space
            line_text (32) <= "00100000";                                     -- Space
            line_text (33) <= "00100000";                                     -- Space
            line_text (34) <= "00100000";                                     -- Space
            line_text (35) <= "00100000";                                     -- Space
            line_text (36) <= "00100000";                                     -- Space
            line_text (37) <= "00100000";                                     -- Space
            line_text (38) <= "00100000";                                     -- Space
            line_text (39) <= "00100000";                                     -- Space


            IF DisplayMode = '1' THEN

               line_text (1)  <= "00111010";                                  -- :
               line_text (15) <= "00100000";                                  -- Space
               line_text (16) <= std_logic_vector(Operand_3rd_Byte_ASCI_1);   -- 1st char of 4th byte in HexDump mode
               line_text (17) <= std_logic_vector(Operand_3rd_Byte_ASCI_2);   -- 2nd char of 4th byte in HexDump mode
               line_text (18) <= "00100000";                                  -- Space
               line_text (19) <= std_logic_vector(Operand_4th_Byte_ASCI_1);   -- 1st char of 5th byte in HexDump mode
               line_text (20) <= std_logic_vector(Operand_4th_Byte_ASCI_2);   -- 2nd char of 5th byte in HexDump mode
               line_text (21) <= "00100000";                                  -- Space
               line_text (22) <= std_logic_vector(Operand_5th_Byte_ASCI_1);   -- 1st char of 6th byte in HexDump mode
               line_text (23) <= std_logic_vector(Operand_5th_Byte_ASCI_2);   -- 2nd char of 6th byte in HexDump mode
               line_text (24) <= "00100000";                                  -- Space
               line_text (25) <= std_logic_vector(Operand_6th_Byte_ASCI_1);   -- 1st char of 7th byte in HexDump mode
               line_text (26) <= std_logic_vector(Operand_6th_Byte_ASCI_2);   -- 2nd char of 7th byte in HexDump mode
               line_text (27) <= "00100000";                                  -- Space
               line_text (28) <= std_logic_vector(Operand_7th_Byte_ASCI_1);   -- 1st char of 8th byte in HexDump mode
               line_text (29) <= std_logic_vector(Operand_7th_Byte_ASCI_2);   -- 2nd char of 8th byte in HexDump mode
               line_text (30) <= "00100000";                                  -- Space
               line_text (31) <= std_logic_vector(Op1);                       -- | 8 bytes of ASCII representation to right of hex values
               line_text (32) <= std_logic_vector(Op2);                       -- |
               line_text (33) <= std_logic_vector(Op3);                       -- |
               line_text (34) <= std_logic_vector(Op4);                       -- |
               line_text (35) <= std_logic_vector(Op5);                       -- |
               line_text (36) <= std_logic_vector(Op6);                       -- |
               line_text (37) <= std_logic_vector(Op7);                       -- |
               line_text (38) <= std_logic_vector(Op8);                       -- |
               line_text (39) <= "00100000";                                  -- Space
            END IF;
            
            
 ---------------------------------------------------------------------
 --         Display 40 character line from line_text_array
 ---------------------------------------------------------------------
            
            charAddr <= line_text(to_integer((Xchar) - 1)) & std_logic_vector(pixelv(2 DOWNTO 0));
            IF charData(to_integer(NOT pixelh(2 DOWNTO 0))) = '1' THEN
               Pixel_Colour <= "111111111";
            END IF;

----------------------------------------------------------------------

         END IF;
      END IF;
      -- Draw border
      IF vcount <= 10 OR vcount >= 590 OR
       hcount <= 10 OR hcount >= 790 THEN
         Pixel_Colour <= "111111111";
      END IF;

      END IF;
END PROCESS;

   videoon            <= videoh and videov;
   VGA               <= Pixel_Colour;
   Vout(10 downto 2)   <= VGA and videoon&videoon&videoon&videoon&videoon&videoon&videoon&videoon&videoon;
   Vout(1 downto 0)   <= hsync & vsync;

end Behavioral;
A small lookup ROM is also used, and can be created with the following .mif file.

Code: Select all

-- http://srecord.sourceforge.net/
--
-- Generated automatically by srec_cat -o --mif
--
DEPTH = 1024;
WIDTH = 8;
ADDRESS_RADIX = HEX;
DATA_RADIX = HEX;
CONTENT BEGIN
0000: 42 52 4B 01 4F 52 41 82 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 4F 52 41 22;
0018: 41 53 4C 22 3F 3F 3F 01 50 48 50 01 4F 52 41 12 41 53 4C C1 3F 3F 3F 01;
0030: 3F 3F 3F 01 4F 52 41 53 41 53 4C 53 3F 3F 3F 01 42 50 4C A2 4F 52 41 92;
0048: 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 4F 52 41 32 41 53 4C 32 3F 3F 3F 01;
0060: 43 4C 43 01 4F 52 41 73 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 4F 52 41 63;
0078: 41 53 4C 63 3F 3F 3F 01 4A 53 52 53 41 4E 44 82 3F 3F 3F 01 3F 3F 3F 01;
0090: 42 49 54 22 41 4E 44 22 52 4F 4C 22 3F 3F 3F 01 50 4C 50 01 41 4E 44 12;
00A8: 52 4F 4C C1 3F 3F 3F 01 42 49 54 53 41 4E 44 53 52 4F 4C 53 3F 3F 3F 01;
00C0: 42 4D 49 A2 41 4E 44 92 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 41 4E 44 32;
00D8: 52 4F 4C 32 3F 3F 3F 01 53 45 43 01 41 4E 44 73 3F 3F 3F 01 3F 3F 3F 01;
00F0: 3F 3F 3F 01 41 4E 44 63 52 4F 4C 63 3F 3F 3F 01 52 54 49 01 45 4F 52 82;
0108: 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 45 4F 52 22 4C 53 52 22 3F 3F 3F 01;
0120: 50 48 41 01 45 4F 52 12 4C 53 52 C1 3F 3F 3F 01 4A 4D 50 53 45 4F 52 53;
0138: 4C 53 52 53 3F 3F 3F 01 42 56 43 A2 45 4F 52 92 3F 3F 3F 01 3F 3F 3F 01;
0150: 3F 3F 3F 01 45 4F 52 32 4C 53 52 32 3F 3F 3F 01 43 4C 49 01 45 4F 52 73;
0168: 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 45 4F 52 63 4C 53 52 63 3F 3F 3F 01;
0180: 52 54 53 01 41 44 43 82 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 41 44 43 22;
0198: 52 4F 52 22 3F 3F 3F 01 50 4C 41 01 41 44 43 12 52 4F 52 C1 3F 3F 3F 01;
01B0: 4A 4D 50 B3 41 44 43 53 52 4F 52 53 3F 3F 3F 01 42 56 53 A2 41 44 43 92;
01C8: 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 41 44 43 32 52 4F 52 32 3F 3F 3F 01;
01E0: 53 45 49 01 41 44 43 73 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 41 44 43 63;
01F8: 52 4F 52 63 3F 3F 3F 01 3F 3F 3F 01 53 54 41 82 3F 3F 3F 01 3F 3F 3F 01;
0210: 53 54 59 22 53 54 41 22 53 54 58 22 3F 3F 3F 01 44 45 59 01 3F 3F 3F 01;
0228: 54 58 41 01 3F 3F 3F 01 53 54 59 53 53 54 41 53 53 54 58 53 3F 3F 3F 01;
0240: 42 43 43 A2 53 54 41 92 3F 3F 3F 01 3F 3F 3F 01 53 54 59 32 53 54 41 32;
0258: 53 54 58 42 3F 3F 3F 01 54 59 41 01 53 54 41 73 54 58 53 01 3F 3F 3F 01;
0270: 3F 3F 3F 01 53 54 41 63 3F 3F 3F 01 3F 3F 3F 01 4C 44 59 12 4C 44 41 82;
0288: 4C 44 58 12 3F 3F 3F 01 4C 44 59 22 4C 44 41 22 4C 44 58 22 3F 3F 3F 01;
02A0: 54 41 59 01 4C 44 41 12 54 41 58 01 3F 3F 3F 01 4C 44 59 53 4C 44 41 53;
02B8: 4C 44 58 53 3F 3F 3F 01 42 43 53 A2 4C 44 41 92 3F 3F 3F 01 3F 3F 3F 01;
02D0: 4C 44 59 32 4C 44 41 32 4C 44 58 42 3F 3F 3F 01 43 4C 56 01 4C 44 41 73;
02E8: 54 53 58 01 3F 3F 3F 01 4C 44 59 63 4C 44 41 63 4C 44 58 73 3F 3F 3F 01;
0300: 43 50 59 12 43 4D 50 82 3F 3F 3F 01 3F 3F 3F 01 43 50 59 22 43 4D 50 22;
0318: 44 45 43 22 3F 3F 3F 01 49 4E 59 01 43 4D 50 12 44 45 58 01 3F 3F 3F 01;
0330: 43 50 59 53 43 4D 50 53 44 45 43 53 3F 3F 3F 01 42 4E 45 A2 43 4D 50 92;
0348: 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 43 4D 50 32 44 45 43 32 3F 3F 3F 01;
0360: 43 4C 44 01 43 4D 50 73 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 43 4D 50 63;
0378: 44 45 43 63 3F 3F 3F 01 43 50 58 12 53 42 43 82 3F 3F 3F 01 3F 3F 3F 01;
0390: 43 50 58 22 53 42 43 22 49 4E 43 22 3F 3F 3F 01 49 4E 58 01 53 42 43 12;
03A8: 4E 4F 50 01 3F 3F 3F 01 43 50 58 53 53 42 43 53 49 4E 43 53 3F 3F 3F 01;
03C0: 42 45 51 A2 53 42 43 92 3F 3F 3F 01 3F 3F 3F 01 3F 3F 3F 01 53 42 43 32;
03D8: 49 4E 43 32 3F 3F 3F 01 53 45 44 01 53 42 43 73 3F 3F 3F 01 3F 3F 3F 01;
03F0: 3F 3F 3F 01 53 42 43 63 49 4E 43 63 3F 3F 3F 01;
END;
Last edited by Cray Ze on Fri Jan 28, 2022 12:27 am, edited 2 times in total.
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: 6502 disassembler in hardware

Post by BigEd »

How very unexpected - so the idea is that it reads a chunk of memory and disassembles what it finds? (As opposed to disassembling a trace of execution.)
Cray Ze
Posts: 134
Joined: 02 May 2015

Re: 6502 disassembler in hardware

Post by Cray Ze »

BigEd wrote:
How very unexpected - so the idea is that it reads a chunk of memory and disassembles what it finds? (As opposed to disassembling a trace of execution.)
Yes, in fact, there isn't even a CPU in my example. You could wire it up to monitor the address bus in a complete system to track access and follow along in real time.
John West
Posts: 383
Joined: 03 Sep 2002

Re: 6502 disassembler in hardware

Post by John West »

That's pretty cool. It puts my 'debugger' to shame.

(On the left is a list of the addresses of the last few instructions. On the right is the current values of the user-visible registers. In binary. There's a button to execute the next instruction. It's been a lot better than nothing)
Attachments
C640 'debugger'
C640 'debugger'
Cray Ze
Posts: 134
Joined: 02 May 2015

Re: 6502 disassembler in hardware

Post by Cray Ze »

Your debugger is keeping track of a lot of useful information though, and there's certainly nothing wrong with that.
I'm only disassembling memory at present, though will add some more bells and whistles when it's incorporated into a design with an actual CPU to keep track of.
Cray Ze
Posts: 134
Joined: 02 May 2015

Re: 6502 disassembler in hardware

Post by Cray Ze »

I've added some comments to the source, renamed a couple signals/variables to better names, and done some general clean up.
I also found an optimization that saved 151 logic elements while making the code a little more clear.
Post Reply