aboutsummaryrefslogtreecommitdiffstats
path: root/bbc_micro_de1.vhd
diff options
context:
space:
mode:
authorMike Stirling <opensource@mikestirling.co.uk>2011-07-29 21:14:17 +0100
committerMike Stirling <opensource@mikestirling.co.uk>2011-07-29 21:14:17 +0100
commitabb341bccf06bca03f56d2bc7612b2f81721b454 (patch)
tree5724ccb6d2321e7c58140779f81207aea0311bec /bbc_micro_de1.vhd
parent3ea54eb8b11e87333ad809c7bbfd9537c2fc8250 (diff)
downloadfpga-bbc-abb341bccf06bca03f56d2bc7612b2f81721b454.tar.gz
fpga-bbc-abb341bccf06bca03f56d2bc7612b2f81721b454.tar.bz2
fpga-bbc-abb341bccf06bca03f56d2bc7612b2f81721b454.zip
Work in progress. Added PS/2 keyboard interface, hardware debugger. Interrupt test output to 6522 (remove later). Fixed error in pin assignments that blocked access to Flash chip select. Added reading sideways ROMs from external Flash (all but BASIC masked off for now).
Diffstat (limited to 'bbc_micro_de1.vhd')
-rw-r--r--bbc_micro_de1.vhd257
1 files changed, 186 insertions, 71 deletions
diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd
index 0d29726..3e53add 100644
--- a/bbc_micro_de1.vhd
+++ b/bbc_micro_de1.vhd
@@ -85,9 +85,10 @@ port (
-- Flash
FL_ADDR : out std_logic_vector(21 downto 0);
FL_DQ : inout std_logic_vector(7 downto 0);
- FL_RST_N : in std_logic;
- FL_OE_N : in std_logic;
- FL_WE_N : in std_logic;
+ FL_RST_N : out std_logic;
+ FL_OE_N : out std_logic;
+ FL_WE_N : out std_logic;
+ FL_CE_N : out std_logic;
-- GPIO
GPIO_0 : inout std_logic_vector(35 downto 0);
@@ -111,17 +112,6 @@ component pll32 IS
);
end component;
------------------------
--- 7 segment display
------------------------
-
-component seg7 is
-port (
- D : in std_logic_vector(3 downto 0);
- Q : out std_logic_vector(6 downto 0)
-);
-end component;
-
------------------------------
-- Test UART for custom ROM
------------------------------
@@ -320,10 +310,86 @@ component M6522 is
I_P2_H : in std_logic; -- high for phase 2 clock ____----__
RESET_L : in std_logic;
ENA_4 : in std_logic; -- clk enable (4x system clock rate)
- CLK : in std_logic
+ CLK : in std_logic;
+ testout : out std_logic_vector(7 downto 0)
);
end component;
+-----------------------------
+-- PS/2 Keyboard Emulation
+-----------------------------
+
+component keyboard is
+port (
+ CLOCK : in std_logic;
+ nRESET : in std_logic;
+ CLKEN_1MHZ : in std_logic;
+
+ -- PS/2 interface
+ PS2_CLK : in std_logic;
+ PS2_DATA : in std_logic;
+
+ -- If 1 then column is incremented automatically at
+ -- 1 MHz rate
+ AUTOSCAN : in std_logic;
+
+ COLUMN : in std_logic_vector(3 downto 0);
+ ROW : in std_logic_vector(2 downto 0);
+
+ -- 1 when currently selected key is down (AUTOSCAN disabled)
+ KEYPRESS : out std_logic;
+ -- 1 when any key is down (except row 0)
+ INT : out std_logic;
+ -- BREAK key output - 1 when pressed
+ BREAK_OUT : out std_logic;
+
+ -- DIP switch inputs
+ DIP_SWITCH : in std_logic_vector(7 downto 0)
+ );
+end component;
+
+component 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
+ A_CPU : in std_logic_vector(15 downto 0);
+ R_nW : in std_logic;
+ SYNC : in std_logic;
+
+ -- 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 component;
+
-------------
-- Signals
-------------
@@ -332,16 +398,17 @@ end component;
signal pll_reset : std_logic;
signal pll_locked : std_logic;
signal clock : std_logic;
+signal hard_reset_n : std_logic;
signal reset_n : std_logic;
-- Clock enable counter
-- CPU and video cycles are interleaved. The CPU runs at 2 MHz (every 16th
-- cycle) and the video subsystem is enabled on every odd cycle.
signal clken_counter : unsigned(4 downto 0);
-signal slomo_counter : unsigned(17 downto 0);
signal cpu_cycle : std_logic; -- Qualifies all 2 MHz cycles
signal cpu_cycle_mask : std_logic; -- Set to mask CPU cycles until 1 MHz cycle is complete
signal cpu_clken : std_logic; -- 2 MHz cycles in which the CPU is enabled
+signal cpu_debug_clken : std_logic; -- CPU clken return from hardware debugger
-- IO cycles are out of phase with the CPU
signal vid_clken : std_logic; -- 16 MHz video cycles
signal mhz4_clken : std_logic; -- Used by 6522
@@ -418,6 +485,7 @@ signal sys_via_cb2_oe_n : std_logic;
signal sys_via_pb_in : std_logic_vector(7 downto 0);
signal sys_via_pb_out : std_logic_vector(7 downto 0);
signal sys_via_pb_oe_n : std_logic_vector(7 downto 0);
+signal sys_via_testout : std_logic_vector(7 downto 0);
-- User VIA signals
signal user_via_do : std_logic_vector(7 downto 0);
@@ -439,6 +507,7 @@ signal user_via_cb2_oe_n : std_logic;
signal user_via_pb_in : std_logic_vector(7 downto 0);
signal user_via_pb_out : std_logic_vector(7 downto 0);
signal user_via_pb_oe_n : std_logic_vector(7 downto 0);
+signal user_via_testout : std_logic_vector(7 downto 0);
-- IC32 latch on System VIA
signal ic32 : std_logic_vector(7 downto 0);
@@ -450,6 +519,13 @@ signal disp_addr_offs : std_logic_vector(1 downto 0);
signal caps_lock_led_n : std_logic;
signal shift_lock_led_n : std_logic;
+-- Keyboard
+signal keyb_column : std_logic_vector(3 downto 0);
+signal keyb_row : std_logic_vector(2 downto 0);
+signal keyb_out : std_logic;
+signal keyb_int : std_logic;
+signal keyb_break : std_logic;
+
-- Memory enables
signal ram_enable : std_logic; -- 0x0000
signal rom_enable : std_logic; -- 0x8000 (BASIC/sideways ROMs)
@@ -471,6 +547,9 @@ signal adlc_enable : std_logic; -- 0xFEA0-FEBF (Econet)
signal adc_enable : std_logic; -- 0xFEC0-FEDF
signal tube_enable : std_logic; -- 0xFEE0-FEFF
+-- ROM select latch
+signal romsel : std_logic_vector(3 downto 0);
+
signal mhz1_enable : std_logic; -- Set for access to any 1 MHz peripheral
begin
@@ -484,15 +563,25 @@ begin
CLOCK_24(0),
clock,
pll_locked );
-
- -- Display of address bus
- addr3 : seg7 port map (cpu_a(15 downto 12), HEX3);
- addr2 : seg7 port map (cpu_a(11 downto 8), HEX2);
- addr1 : seg7 port map (cpu_a(7 downto 4), HEX1);
- addr0 : seg7 port map (cpu_a(3 downto 0), HEX0);
+
+ -- Hardware debugger block (single-step, breakpoints)
+ debug: debugger port map (
+ clock,
+ hard_reset_n,
+ cpu_clken,
+ cpu_debug_clken,
+ cpu_a(15 downto 0), cpu_r_nw, cpu_sync,
+ SW(8), -- RUN
+ KEY(3), -- STEP
+ KEY(2), -- MODE
+ KEY(1), -- DIGIT
+ KEY(0), -- SET
+ HEX3, HEX2, HEX1, HEX0,
+ LEDR(3), -- BREAKPOINT
+ LEDR(2) -- WATCHPOINT
+ );
-- Test UART
-
test_uart : simple_uart port map (
clock,
reset_n,
@@ -509,7 +598,7 @@ begin
cpu : T65 port map (
cpu_mode,
reset_n,
- cpu_clken,
+ cpu_debug_clken,
clock,
cpu_ready,
cpu_abort_n,
@@ -598,9 +687,9 @@ begin
sys_via_pb_out,
sys_via_pb_oe_n,
mhz1_clken,
- reset_n,
+ hard_reset_n, -- System VIA is reset by power on reset only
mhz4_clken,
- clock
+ clock, sys_via_testout
);
-- User VIA
@@ -632,12 +721,29 @@ begin
mhz1_clken,
reset_n,
mhz4_clken,
- clock
+ clock, user_via_testout
+ );
+
+ -- Keyboard
+ keyb : keyboard port map (
+ clock, hard_reset_n, mhz1_clken,
+ PS2_CLK, PS2_DAT,
+ keyb_enable_n,
+ keyb_column,
+ keyb_row,
+ keyb_out,
+ keyb_int,
+ keyb_break,
+ SW(7 downto 0)
);
-- Asynchronous reset
+ -- PLL is reset by external reset switch
pll_reset <= not SW(9);
- reset_n <= not (pll_reset or not pll_locked);
+ -- Keyboard and System VIA are reset by external reset switch or PLL being out of lock
+ hard_reset_n <= not (pll_reset or not pll_locked);
+ -- Rest of system is reset by all of the above plus the keyboard BREAK key
+ reset_n <= hard_reset_n and not keyb_break;
-- Clock enable generation - 32 MHz clock split into 32 cycles
-- CPU is on 0 and 16 (but can be masked by 1 MHz bus accesses)
@@ -647,21 +753,15 @@ begin
mhz4_clken <= clken_counter(0) and clken_counter(1) and clken_counter(2); -- 7/15/23/31
mhz2_clken <= mhz4_clken and clken_counter(3); -- 15/31
mhz1_clken <= mhz2_clken and clken_counter(4); -- 31
- cpu_cycle <=
- not (clken_counter(0) or clken_counter(1) or clken_counter(2) or clken_counter(3))
- when (SW(8) = '1' or slomo_counter = 0) else '0'; -- 0/16
+ cpu_cycle <= not (clken_counter(0) or clken_counter(1) or clken_counter(2) or clken_counter(3)); -- 0/16
cpu_clken <= cpu_cycle and not cpu_cycle_mask;
clk_gen: process(clock,reset_n)
begin
if reset_n = '0' then
clken_counter <= (others => '0');
- slomo_counter <= (others => '0');
elsif rising_edge(clock) then
clken_counter <= clken_counter + 1;
- if clken_counter = 0 then
- slomo_counter <= slomo_counter + 1;
- end if;
end if;
end process;
@@ -778,15 +878,31 @@ begin
-- CPU data bus mux and interrupts
cpu_di <=
+ SRAM_DQ(7 downto 0) when ram_enable = '1' else
+ FL_DQ when rom_enable = '1' else
mos_d when mos_enable = '1' else
- "11111111" when rom_enable = '1' else
crtc_do when crtc_enable = '1' else
+ "00000010" when acia_enable = '1' else
sys_via_do when sys_via_enable = '1' else
user_via_do when user_via_enable = '1' else
test_uart_do when io_fred = '1' else
- SRAM_DQ(7 downto 0);
- --cpu_irq_n <= sys_via_irq_n; -- and user_via_irq_n;
- cpu_irq_n <= '1';
+ (others => '0'); -- un-decoded locations are pulled down by RP1
+ cpu_irq_n <= sys_via_irq_n; -- and user_via_irq_n;
+ --cpu_irq_n <= '1';
+
+ -- ROMs are in external flash
+ FL_RST_N <= reset_n;
+ FL_CE_N <= '0';
+ FL_OE_N <= '0';
+ FL_WE_N <= '1';
+ FL_ADDR(13 downto 0) <= cpu_a(13 downto 0);
+ FL_ADDR(21 downto 16) <= (others => '0');
+ FL_ADDR(15 downto 14) <=
+ "00" when mos_enable = '1' else
+ "01" when rom_enable = '1' and romsel(1 downto 0) = "11" else -- BASIC
+ --"10" when rom_enable = '1' and romsel(1 downto 0) = "00" else
+ "11";
+
-- SRAM bus
SRAM_UB_N <= '1';
@@ -863,14 +979,14 @@ begin
-- VIDPROC
vidproc_invert_n <= '1';
- r_in <= '0';
+ r_in <= '0'; -- FIXME: From SAA5050
g_in <= '0';
b_in <= '0';
- GPIO_0(0) <= not (crtc_hsync xor crtc_vsync);
- GPIO_0(1) <= cpu_clken;
- GPIO_0(2) <= cpu_cycle_mask;
- GPIO_0(3) <= mhz1_enable;
+ GPIO_0(0) <= cpu_irq_n;
+ GPIO_0(1) <= keyb_out;
+ GPIO_0(2) <= keyb_enable_n;
+ GPIO_0(3) <= sys_via_testout(6); -- timer 1
-- CRTC drives video out (CSYNC on HSYNC output, VSYNC high)
VGA_HS <= not (crtc_hsync xor crtc_vsync);
@@ -880,13 +996,35 @@ begin
VGA_B <= b_out & b_out & b_out & b_out;
-- Connections to System VIA
+ -- ADC
+ sys_via_cb1_in <= '1'; -- /EOC
+ -- CRTC
sys_via_ca1_in <= crtc_vsync;
- sys_via_ca2_in <= '0'; -- Keyboard interrupt
- sys_via_cb1_in <= '0'; -- /EOC
sys_via_cb2_in <= crtc_lpstb;
+ -- Keyboard
+ sys_via_ca2_in <= keyb_int;
+ sys_via_pa_in(7) <= keyb_out;
+ keyb_column <= sys_via_pa_out(3 downto 0);
+ keyb_row <= sys_via_pa_out(6 downto 4);
+ -- Others (idle until missing bits implemented)
+ sys_via_pa_in(6 downto 0) <= (others => '0');
+ sys_via_pb_in(7 downto 4) <= (others => '1');
-- Connections to User VIA (user port is output on green LEDs)
- LEDG <= user_via_pb_out;
+ --LEDG <= user_via_pb_out;
+ LEDG <= sys_via_testout;
+
+ -- ROM select latch
+ process(clock,reset_n)
+ begin
+ if reset_n = '0' then
+ romsel <= (others => '0');
+ elsif rising_edge(clock) then
+ if romsel_enable = '1' and cpu_r_nw = '0' then
+ romsel <= cpu_do(3 downto 0);
+ end if;
+ end if;
+ end process;
-- IC32 latch
sound_enable_n <= ic32(0);
@@ -912,28 +1050,5 @@ begin
-- Keyboard LEDs
LEDR(0) <= not caps_lock_led_n;
LEDR(1) <= not shift_lock_led_n;
-
- -- Hack for jumper links
- process(sys_via_pa_out)
- begin
- sys_via_pa_in <= sys_via_pa_out;
-
- if sys_via_pa_out(6 downto 4) = "000" then
- case to_integer(unsigned(sys_via_pa_out(3 downto 0))) is
- when 2 => sys_via_pa_in(7) <= SW(7);
- when 3 => sys_via_pa_in(7) <= SW(6);
- when 4 => sys_via_pa_in(7) <= SW(5);
- when 5 => sys_via_pa_in(7) <= SW(4);
- when 6 => sys_via_pa_in(7) <= SW(3);
- when 7 => sys_via_pa_in(7) <= SW(2);
- when 8 => sys_via_pa_in(7) <= SW(1);
- when 9 => sys_via_pa_in(7) <= SW(0);
- when others => sys_via_pa_in(7) <= '0';
- end case;
- else
- -- 'W' output of keyboard IC2 is inverse data, so 0 is no key pressed
- sys_via_pa_in(7) <= '0';
- end if;
- end process;
-
+
end architecture;