Address decoding

3 minute read

Before writing any software for Y Ddraig the CPLD will need to be programmed. The CPLD being used here is a Xilinx XC95108 and it is responsible for the address decoding for the peripherals and will eventually be used for controlling the DRAM but that isn’t going to be used in the inital stages of getting the computer up and running.

Clock generator

The clock signal for the 68000 is generated by CPLD so the first step is to create a clock signal for the 68000. The 10Mhz output clock is derived from the 40Mhz clock input to the CPLD.

architecture Behavioral of Clock is
	signal clk_divider : std_logic_vector(1 downto 0) := (others => '0');
		if (rising_edge(clk)) then
			clk_divider <= clk_divider + 1;
		end if;
	end process;
	clk10 <= clk_divider(1);
end Behavioral;

Address decoding

The memory map that is going to be used for Y Ddraig is as follows:

Device Start Address End Address
Static Ram 0x000000 0x0FFFFF
Dynamic RAM 0x100000 0x900000
DUART 0xF7F000 0xF7F0FF
YM2151 0xF7F100 0xF7F1FF
PIT 0xF7F200 0xF7F2FF
KBD 0xF7F300 0xF7F3FF
IDE 0xF7F400 0xF7F4FF
RTC 0xF7F600 0xF7F6FF
VDP 0xF7F700 0xF7F7FF
ROM 0xF80000 0xFFFFFF

On startup the 68000 fetches two long word vectors from address 0x000000 for the stack pointer and start address for the code. As the ROM is set at address 0xF80000 this has to map the first four reads to the ROM.

This is handled by a 74LS164 8 bit shift register (U11) which sets the bootrom signal low for the first 4 address accesses (/AS) and then the bootrom signal is high until the next reset.

Boot ROM selection

With this information the address decoding module is defined as follows:

entity AddressDecode is
    Port ( a          : in  STD_LOGIC_VECTOR (23 downto 8);
           clk        : in  STD_LOGIC;
           as         : in  STD_LOGIC;
           bootrom    : in  STD_LOGIC;
           reset      : in  STD_LOGIC;
           dtack      : out  STD_LOGIC;
           cs_rom     : out  STD_LOGIC;
           cs_sram    : out  STD_LOGIC;
           cs_duart   : out  STD_LOGIC;
           cs_pit     : out  STD_LOGIC;
           cs_kbd     : out  STD_LOGIC;
           cs_rtc     : out  STD_LOGIC;
           cs_ym2151  : out  STD_LOGIC;
           cs_eth     : out  STD_LOGIC;
           cs_vdp     : out  STD_LOGIC;
           cs_ide     : out  STD_LOGIC);
end AddressDecode;

ROM access is selected when the bootrom signal is 0 or the address range is in the ROM area. RAM access is similarly defined except that it expects the bootrom signal to be 1.

Peripheral access defined in 256 byte address blocks in the defined address ranges.

-- $F80000 - $FFFFFF
cs_rom    <= '0' WHEN as = '0'
    AND (bootrom = '0' OR std_match(a, "11111-----------"))
    ELSE '1';

-- $000000 - $0FFFFF
cs_sram   <= '0' WHEN as = '0'
    AND bootrom = '1' AND std_match(a, "0000------------")
    ELSE '1';

-- $F7F000 - $F7F0FF
cs_duart    <= '0' WHEN as = '0' AND std_match(a, "1111011111110000") ELSE '1';
-- $F7F100 - $F7F1FF
cs_ym2151   <= '0' WHEN as = '0' AND std_match(a, "1111011111110001") ELSE '1';
-- $F7F200 - $F7F2FF
cs_pit      <= '0' WHEN as = '0' AND std_match(a, "1111011111110010") ELSE '1';
-- $F7F300 - $F7F3FF
cs_kbd      <= '0' WHEN as = '0' AND std_match(a, "1111011111110011") ELSE '1';
-- $F7F400 - $F7F4FF
cs_ide      <= '0' WHEN as = '0' AND std_match(a, "1111011111110100") ELSE '1';
-- $F7F500 - $F7F5FF
cs_eth      <= '0' WHEN as = '0' AND std_match(a, "1111011111110101") ELSE '1';
-- $F7F600 - $F7F6FF
cs_rtc      <= '0' WHEN as = '0' AND std_match(a, "1111011111110110") ELSE '1';
-- $F7F700 - $F7F7FF
cs_vdp      <= '0' WHEN as = '0' AND std_match(a, "1111011111111111") ELSE '1';

For some of the peripherals the DTACK signal is automatically handled. These include the ROM (in hardware), the DUART and The PIT. For the others then the DTACK signal must be generated.

The DTACK generator:

signal dtack_s  : std_logic_vector(3 downto 0);

process (clk, reset, as)
	if (reset = '0' or as = '1') then
		dtack_s <= (others => '0');
	elsif (rising_edge(clk)) then
		if (dtack_s < "1111") then
			dtack_s <= dtack_s + 1;
		end if;
	end if;
end process;

Check if we need to generate the DTACK signal:

-- Check the chip select signals to see if one is low
ack <= cs_sram AND cs_kbd AND cs_rtc AND cs_ym2151 AND cs_vdp AND cs_eth;

-- Generate the DTACK
dtack <= '0' WHEN ack = '0' AND dtack_s > "0101" ELSE '1';

This should provide the address decoding needed to be able be able to start writing some code to test the hardware is working as expected.