1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-23 02:37:52 +00:00
2019-07-22 23:42:05 +02:00

376 lines
10 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity mc6883 is
port
(
clk : in std_logic;
clk_ena : in std_logic;
reset : in std_logic;
-- input
a : in std_logic_vector(15 downto 0);
rw_n : in std_logic;
-- vdg signals
da0 : in std_logic;
hs_n : in std_logic;
vclk : out std_logic;
-- peripheral address selects
s : out std_logic_vector(2 downto 0);
-- clock generation
e : out std_logic;
q : out std_logic;
-- dynamic addresses
z : out std_logic_vector(7 downto 0);
-- ram
ras0_n : out std_logic;
cas_n : out std_logic;
we_n : out std_logic;
-- debug
dbg : out std_logic_vector(15 downto 0)
);
end mc6883;
architecture SYN of mc6883 is
subtype DivisorType is integer range 0 to 11;
type DivisorArrayType is array (natural range <>) of DivisorType;
-- Division variables for V0=0, V2..V1=sel
--constant y_divisor : DivisorArrayType(0 to 3) := (12, 3, 2, 1);
-- Division variable for V0=1, v2..V1=sel
--constant x_divisor : DivisorArrayType(0 to 3) := (3, 2, 1, 1);
constant mode_rows : DivisorArrayType(0 to 7) := (12-1, 3-1, 3-1, 2-1, 2-1, 1-1, 1-1, 1-1);
-- clocks
signal clk_7M15909 : std_logic;
signal clk_3M579545 : std_logic;
signal clk_1M769772 : std_logic;
signal clk_0M894866 : std_logic;
-- some rising_edge pulses
signal rising_edge_hs : std_logic;
signal rising_edge_q : std_logic;
signal rising_edge_e : std_logic;
-- internal versions of pin signals
signal we_n_s : std_logic;
-- video counter
signal b_int : std_logic_vector(15 downto 0);
-- control register (CR)
signal cr : std_logic_vector(15 downto 0);
signal sel_cr : std_logic;
alias ty : std_logic is cr(15);
alias m : std_logic_vector(1 downto 0) is cr(14 downto 13);
alias r : std_logic_vector(1 downto 0) is cr(12 downto 11);
alias p : std_logic is cr(10);
alias f : std_logic_vector(6 downto 0) is cr(9 downto 3);
alias v : std_logic_vector(2 downto 0) is cr(2 downto 0);
alias flag : std_logic is a(0);
-- internal chipselect vectors
signal s_ty0 : std_logic_vector(2 downto 0);
signal s_ty1 : std_logic_vector(2 downto 0);
signal debug : std_logic_vector(1 downto 0);
shared variable yscale : integer;
begin
--
-- CPU Address is valid tAD after falling edge of E
-- CPU Read Data latched at falling edge of E
-- CPU Write Data valid tDDW after rising edge of Q,
-- - until tDHW (short) after falling edge E
--
-- clock generation, ras/cas generation
PROC_MAIN : process (clk, reset, rw_n)
variable count : std_logic_vector(3 downto 0);
begin
if reset = '1' then
--count := (others => '0');
count := "0000";
z <= (others => '0');
q <= '0';
e <= '0';
ras0_n <= '1';
cas_n <= '1';
we_n_s <= '1';
elsif rising_edge (clk) then
if clk_ena = '1' then
we_n_s <= '1'; -- default
clk_7M15909 <= count(0);
clk_3M579545 <= count(1);
clk_1M769772 <= count(2);
clk_0M894866 <= count(3);
vclk <= not clk_3M579545;
case count is
when "0000" =>
-- valid VDG address (row)
-- z(7) is RAS1# or B(7)
z <= b_int(7 downto 0);
ras0_n <= '0';
when "0001" =>
when "0010" =>
-- valid VDG address (col)
--case m is
-- when "00" =>
-- z <= "00" & b_int(11 downto 6);
-- when "01" =>
-- z <= '0' & b_int(13 downto 7);
-- when others =>
z <= b_int(15 downto 8);
--end case;
cas_n <= '0';
when "0011" =>
q <= '1';
when "0100" =>
when "0101" =>
ras0_n <= '1';
when "0110" =>
when "0111" =>
cas_n <= '1';
e <= '1';
when "1000" =>
-- valid MPU address (row)
-- z(7) is RAS1# or A(7)
z <= a(7 downto 0);
ras0_n <= '0';
when "1001" =>
when "1010" =>
-- valid MPU address (col)
-- no need to munge any signal with RAS/CAS
--case m is
-- when "00" =>
-- z <= "00" & a(11 downto 6);
-- when "01" =>
-- z(7) is P or don't care
-- z <= p & a(13 downto 7);
-- when others =>
-- if ty = '0' then
-- z <= p & a(14 downto 8);
-- else
z <= a(15 downto 8);
-- end if;
--end case;
cas_n <= '0';
when "1011" =>
q <= '0';
when "1100" =>
when "1101" =>
ras0_n <= '1';
-- drive WEn some time after mpu address is latched
-- on the falling edge of cas_n above
-- but in plenty of time before falling edge of E
we_n_s <= rw_n;
when "1110" =>
when "1111" =>
cas_n <= '1';
e <= '0';
when others =>
null;
end case;
count := count + 1;
end if; -- clk_ena
end if;
end process PROC_MAIN;
-- assign outputs
we_n <= we_n_s;
-- rising edge pulses
process (clk, reset)
variable old_hs : std_logic;
variable old_q : std_logic;
variable old_e : std_logic;
begin
if reset = '1' then
old_hs := '0';
rising_edge_hs <= '0';
old_q := '0';
rising_edge_q <= '0';
old_e := '0';
rising_edge_e <= '0';
elsif rising_edge (clk) then
if clk_ena = '1' then
rising_edge_hs <= '0';
if old_hs = '0' and hs_n = '1' then
rising_edge_hs <= '1';
end if;
old_hs := hs_n;
end if; -- clk_ena
end if;
end process;
-- video address generation
-- normally, da0 clocks the internal counter
-- but we want a synchronous design
-- so sample da0 each internal clock
process (clk, reset, da0, hs_n)
variable old_hs : std_logic;
variable old_da0 : std_logic;
--variable yscale : integer;
variable saved_b : std_logic_vector(15 downto 0);
begin
if reset = '1' then
b_int <= (others => '0');
old_hs := '1';
old_da0 := '1';
yscale := 0;
saved_b := (others => '0');
elsif rising_edge (clk) then
if clk_ena = '1' then
-- vertical blanking - HS rises when DA0 is high
-- resets bits B9-15, clear B1-B8
if rising_edge_hs = '1' and da0 = '1' then
b_int(15 downto 9) <= f(6 downto 0);
b_int(8 downto 0) <= (others => '0');
yscale := mode_rows(conv_integer(v(2 downto 0)));
saved_b := f(6 downto 0) & "000000000";
-- horizontal blanking - HS low
-- resets bits B1-B3/4
elsif hs_n = '0' then
if v(0) = '0' then
b_int(4) <= '0';
end if;
b_int(3 downto 1) <= (others => '0');
-- coming out of HS?
if old_hs = '1' then
if yscale = mode_rows(conv_integer(v(2 downto 0))) then
yscale := 0;
saved_b := b_int;
else
yscale := yscale + 1;
b_int <= saved_b;
end if;
end if;
-- transition on da is the video clock
elsif da0 /= old_da0 then
b_int <= b_int + 1;
end if;
old_hs := hs_n;
old_da0 := da0;
debug <= old_hs & old_da0;
end if; -- clk_ena
end if;
end process;
-- select control register (CR)
sel_cr <= '1' when a(15 downto 5) = "11111111110" else '0';
--
-- Memory decode logic
-- - combinatorial - needs to be gated
--
s_ty0 <= "010" when -- $FFF2-$FFFF (6809 vectors)
-- $FFE0-$FFF1 (reserved)
a(15 downto 5) = "11111111111"
else
"111" when -- $FFC0-$FFDF (SAM control register)
-- $FF60-$FFBF (reserved)
sel_cr = '1' or
(a(15 downto 8) = "11111111" and (a(7) = '1' or a(6 downto 5) = "11"))
else
"110" when -- $FF40-$FF5F (IO2)
a(15 downto 5) = "11111111010"
else
"101" when -- $FF20-$FF3F (IO1)
a(15 downto 5) = "11111111001"
else
"100" when -- $FF00-$FF1F (IO0)
a(15 downto 5) = "11111111000"
else
"011" when -- $C000-$FEFF (rom2)
a(15 downto 14) = "11"
else
"010" when -- $A000-$BFFF (rom1)
a(15 downto 13) = "101"
else
"001" when -- $8000-$9FFF (rom0)
a(15 downto 13) = "100"
else
"000" when -- $0000-$7FFF (32K) RW_N=1
a(15) = '0' and rw_n = '1'
else
"111" when -- $0000-$7FFF (32K) RW_N=0
a(15) = '0' and rw_n = '0';
s_ty1 <= s_ty0 when -- $FF00-$FFFF
a(15 downto 8) = X"FF"
else
"000" when -- $0000-$FEFF (32K) RW_N=1
rw_n = '1'
else
"111" when -- $0000-$FEFF (32K) RW_N=0
rw_n = '0';
s <= s_ty0 when ty = '0' else
s_ty1;
--
-- Handle update of the control register (CR)
--
WRITE_CR : process (clk, reset, a, rw_n)
begin
if reset = '1' then
cr <= (others => '0');
elsif falling_edge (clk) then
if clk_ena = '1' then
if sel_cr = '1' and we_n_s = '0' then
case a(4 downto 1) is
when "0000" =>
v(0) <= flag;
when "0001" =>
v(1) <= flag;
when "0010" =>
v(2) <= flag;
when "0011" =>
f(0) <= flag;
when "0100" =>
f(1) <= flag;
when "0101" =>
f(2) <= flag;
when "0110" =>
f(3) <= flag;
when "0111" =>
f(4) <= flag;
when "1000" =>
f(5) <= flag;
when "1001" =>
f(6) <= flag;
when "1010" =>
p <= flag;
when "1011" =>
r(0) <= flag;
when "1100" =>
r(1) <= flag;
when "1101" =>
m(0) <= flag;
when "1110" =>
m(1) <= flag;
when others => -- "1111"
ty <= flag;
end case;
end if;
end if; -- clk_ena
end if;
end process WRITE_CR;
-- for hexy display, for example
dbg <= cr;
end SYN;