mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-04-30 21:58:59 +00:00
523 lines
15 KiB
VHDL
523 lines
15 KiB
VHDL
--------------------------------------------------------------------------------
|
|
-- Fairchild Channel F console
|
|
--------------------------------------------------------------------------------
|
|
-- DO 8/2020
|
|
--------------------------------------------------------------------------------
|
|
-- With help from MAME F8 model
|
|
|
|
-- 0000 : ROM : sl90025.rom ou sl31253.rom
|
|
-- 0400 : ROM : sl31254.rom
|
|
-- 0800+ : CART
|
|
|
|
-- COLOR = P[126 + Y*128][2] & P[125 + Y*128][2] & P[X + Y*128][1:0]
|
|
|
|
-- F3850 : PORT 0 : 7 : NC
|
|
-- 6 : OUT : ENABLE IN BTN
|
|
-- 5 : OUT : ARM WRT
|
|
-- 4 : NC
|
|
-- 3 : IN : "START"
|
|
-- 2 : IN : "HOLD"
|
|
-- 1 : IN : "MODE"
|
|
-- 0 : IN : "TIME"
|
|
-- PORT 1 : 7 : IN : "RIGHT G.DOWN" OUT : WRITE DATA1
|
|
-- 6 : IN : "RIGHT G.UP OUT : WRITE DATA0
|
|
-- 5 : IN : "RIGHT CW" OUT :
|
|
-- 4 : IN : "RIGHT CCW" OUT :
|
|
-- 3 : IN : "RIGHT UP" OUT :
|
|
-- 2 : IN : "RIGHT DOWN" OUT :
|
|
-- 1 : IN : "RIGHT LEFT" OUT :
|
|
-- 0 : IN : "RIGHT RIGHT" OUT :
|
|
|
|
-- F3851 : PORT 4 : 7 : IN : "LEFT G.DOWN" OUT :
|
|
-- SL31253 6 : IN : "LEFT G.UP" OUT : HORIZ BUS 6
|
|
-- 5 : IN : "LEFT CW" OUT : HORIZ BUS 5
|
|
-- 4 : IN : "LEFT CCW" OUT : HORIZ BUS 4
|
|
-- 3 : IN : "LEFT UP" OUT : HORIZ BUS 3
|
|
-- 2 : IN : "LEFT DOWN" OUT : HORIZ BUS 2
|
|
-- 1 : IN : "LEFT LEFT" OUT : HORIZ BUS 1
|
|
-- 0 : IN : "LEFT RIGHT" OUT : HORIZ BUS 0
|
|
-- PORT 5 : 7 : IN : OUT : TONE BN
|
|
-- 6 : IN : OUT : TONE AN
|
|
-- 5 : IN : OUT : VERT BUS 5
|
|
-- 4 : IN : OUT : VERT BUS 4
|
|
-- 3 : IN : OUT : VERT BUS 3
|
|
-- 2 : IN : OUT : VERT BUS 2
|
|
-- 1 : IN : OUT : VERT BUS 1
|
|
-- 0 : IN : OUT : VERT BUS 0
|
|
--
|
|
-- F3851 : No IO
|
|
-- SL31254
|
|
|
|
LIBRARY IEEE;
|
|
USE IEEE.std_logic_1164.all;
|
|
USE IEEE.numeric_std.all;
|
|
|
|
--USE std.textio.ALL;
|
|
|
|
LIBRARY work;
|
|
USE work.base_pack.ALL;
|
|
USE work.rom_pack.ALL;
|
|
|
|
ENTITY channel_f IS
|
|
PORT (
|
|
clk : IN std_logic;
|
|
pll_locked : IN std_logic;
|
|
reset : IN std_logic;
|
|
-- VGA
|
|
vga_clk : OUT std_logic;
|
|
vga_ce : OUT std_logic;
|
|
vga_r : OUT std_logic_vector(7 DOWNTO 0);
|
|
vga_g : OUT std_logic_vector(7 DOWNTO 0);
|
|
vga_b : OUT std_logic_vector(7 DOWNTO 0);
|
|
vga_hs : OUT std_logic; -- positive pulse!
|
|
vga_vs : OUT std_logic; -- positive pulse!
|
|
vga_de : OUT std_logic; -- = not (VBlank or HBlank)
|
|
-- HPS IO
|
|
Keys : IN unsigned(3 DOWNTO 0);
|
|
joystick_0 : IN unsigned(7 DOWNTO 0);
|
|
joystick_1 : IN unsigned(7 DOWNTO 0);
|
|
--ROM LOAD
|
|
ioctl_download : IN std_logic;
|
|
ioctl_index : IN std_logic_vector(7 DOWNTO 0);
|
|
ioctl_wr : IN std_logic;
|
|
ioctl_addr : IN std_logic_vector(24 DOWNTO 0);
|
|
ioctl_dout : IN std_logic_vector(7 DOWNTO 0);
|
|
ioctl_wait : OUT std_logic;
|
|
-- AUDIO
|
|
audio : OUT std_logic_vector(15 DOWNTO 0)
|
|
);
|
|
|
|
END channel_f;
|
|
|
|
ARCHITECTURE struct OF channel_f IS
|
|
|
|
SIGNAL ioctl_wait_l,ioctl_download2,ioctl_wr2 : std_logic;
|
|
SIGNAL adrs : uv17;
|
|
|
|
----------------------------------------------------------
|
|
SIGNAL dr,dr0,dr1,dr2,dr3,dr4,dr5,dw_cpu : uv8;
|
|
SIGNAL dv0,dv1,dv2,dv3,dv4,dv5,dv_cpu : std_logic;
|
|
SIGNAL romc : uv5;
|
|
SIGNAL phase : uint4;
|
|
SIGNAL ce : std_logic :='0';
|
|
|
|
SIGNAL pi0,po0,pi1,po1,pi1i,pi4,po4,pi4i,pi5,po5 : uv8;
|
|
SIGNAL rdena : std_logic;
|
|
SIGNAL load_a : uv10;
|
|
SIGNAL load_d : uv8;
|
|
SIGNAL load_wr0,load_wr1,load_wr2,load_wr3 : std_logic;
|
|
SIGNAL tick : std_logic;
|
|
SIGNAL reset_na,areset_na : std_logic;
|
|
SIGNAL vreset_na : unsigned(0 TO 15);
|
|
|
|
----------------------------------------------------------
|
|
CONSTANT INIT_ZERO : arr_uv8(0 TO 1023) := (OTHERS => x"00");
|
|
|
|
CONSTANT HDISP : natural :=208;
|
|
CONSTANT HSYNCSTART : natural :=212;
|
|
CONSTANT HSYNCEND : natural :=220;
|
|
CONSTANT HTOTAL : natural :=228;
|
|
|
|
CONSTANT VDISP : natural :=232;
|
|
CONSTANT VSYNCSTART : natural :=242;
|
|
CONSTANT VSYNCEND : natural :=246;
|
|
CONSTANT VTOTAL : natural :=262;
|
|
|
|
-- BLACK WHITE RED GREEN BLUE LTGRAY LTGREEN LTBLUE
|
|
CONSTANT PAL_R : arr_uv8(0 TO 7) :=
|
|
(x"10",x"FD",x"FF",x"02",x"4B",x"E0",x"91",x"CE");
|
|
CONSTANT PAL_G : arr_uv8(0 TO 7) :=
|
|
(x"10",x"FD",x"31",x"CC",x"3F",x"E0",x"FF",x"D0");
|
|
CONSTANT PAL_B : arr_uv8(0 TO 7) :=
|
|
(x"10",x"FD",x"53",x"5D",x"F3",x"E0",x"A6",x"FF");
|
|
|
|
TYPE arr_uint3 IS ARRAY(natural RANGE <>) OF uint3;
|
|
CONSTANT CMAP : arr_uint3(0 TO 15) :=
|
|
(0,1,1,1,7,4,2,3,5,4,2,3,6,4,2,3);
|
|
|
|
TYPE arr_uv2 IS ARRAY(natural RANGE <>) OF uv2;
|
|
SIGNAL vram : arr_uv2(0 TO 128*64-1); -- Pixels
|
|
|
|
SIGNAL vram_a : uint13;
|
|
SIGNAL vram_h : uint7;
|
|
SIGNAL vram_v : uint6;
|
|
SIGNAL vram_dw : uv2;
|
|
SIGNAL vram_wr : std_logic;
|
|
|
|
SIGNAL v125 : std_logic_vector(0 TO 63);
|
|
SIGNAL v126 : std_logic_vector(0 TO 63);
|
|
|
|
SIGNAL p125,p125p,p126,p126p : std_logic;
|
|
SIGNAL hpos,hposp : uint8;
|
|
SIGNAL vpos,vposp : uint9;
|
|
SIGNAL pos : uint13;
|
|
SIGNAL pix : uv2;
|
|
|
|
SIGNAL vdiv : uv16;
|
|
SIGNAL tone : uv2;
|
|
SIGNAL dc0,pc0,pc1 : uv16;
|
|
SIGNAL acc : uv8;
|
|
SIGNAL visar : uv6;
|
|
SIGNAL iozcs : uv5;
|
|
BEGIN
|
|
|
|
----------------------------------------------------------
|
|
-- CPU
|
|
|
|
-- CPUCLK = VIDEOCLK / 2
|
|
ce <='1'; --NOT ce WHEN rising_edge(clk);
|
|
|
|
i_cpu: ENTITY work.f8_cpu
|
|
PORT MAP (
|
|
dr => dr,
|
|
dw => dw_cpu,
|
|
dv => dv_cpu,
|
|
romc => romc,
|
|
tick => tick,
|
|
phase => phase,
|
|
po_a => po0,
|
|
pi_a => pi0,
|
|
po_b => po1,
|
|
pi_b => pi1,
|
|
clk => clk,
|
|
ce => ce,
|
|
reset_na => reset_na,
|
|
acco => acc,
|
|
visaro => visar,
|
|
iozcso => iozcs
|
|
);
|
|
|
|
-- PSU SL31253
|
|
i_psu0:ENTITY work.f8_psu
|
|
GENERIC MAP (
|
|
PAGE => "000000", -- 0x0000
|
|
IOPAGE => "000001", -- Not used
|
|
IVEC => x"FFFF", -- Not used
|
|
ROM => arr_uv8(INIT_SL31253))
|
|
PORT MAP (
|
|
dw => dr,
|
|
dr => dr0,
|
|
dv => dv0,
|
|
romc => romc,
|
|
tick => tick,
|
|
phase => phase,
|
|
ext_int => '0',
|
|
int_req => OPEN,
|
|
pri_o => OPEN,
|
|
pri_i => '1',
|
|
po_a => po4,
|
|
pi_a => pi4,
|
|
po_b => po5,
|
|
pi_b => pi5,
|
|
load_a => load_a,
|
|
load_d => load_d,
|
|
load_wr => '0',
|
|
clk => clk,
|
|
ce => ce,
|
|
reset_na => reset_na,
|
|
pc0o => pc0,
|
|
pc1o => pc1,
|
|
dc0o => dc0
|
|
);
|
|
|
|
-- PSU SL31254
|
|
i_psu1:ENTITY work.f8_psu
|
|
GENERIC MAP (
|
|
PAGE => "000001", -- 0x0400
|
|
IOPAGE => "111111", -- Not used
|
|
IVEC => x"FFFF", -- Not used
|
|
ROM => arr_uv8(INIT_SL31254))
|
|
PORT MAP (
|
|
dw => dr,
|
|
dr => dr1,
|
|
dv => dv1,
|
|
romc => romc,
|
|
tick => tick,
|
|
phase => phase,
|
|
ext_int => '0',
|
|
int_req => OPEN,
|
|
pri_o => OPEN,
|
|
pri_i => '1',
|
|
po_a => OPEN,
|
|
pi_a => x"FF",
|
|
po_b => OPEN,
|
|
pi_b => x"FF",
|
|
load_a => load_a,
|
|
load_d => load_d,
|
|
load_wr => '0',
|
|
clk => clk,
|
|
ce => ce,
|
|
reset_na => reset_na
|
|
);
|
|
|
|
-- CARTRIDGE
|
|
i_psu2:ENTITY work.f8_psu
|
|
GENERIC MAP (
|
|
PAGE => "000010", -- 0x0800
|
|
IOPAGE => "111110", -- Not used
|
|
IVEC => x"FFFF", -- Not used
|
|
ROM => INIT_ZERO)
|
|
PORT MAP (
|
|
dw => dr,
|
|
dr => dr2,
|
|
dv => dv2,
|
|
romc => romc,
|
|
tick => tick,
|
|
phase => phase,
|
|
ext_int => '0',
|
|
int_req => OPEN,
|
|
pri_o => OPEN,
|
|
pri_i => '1',
|
|
po_a => OPEN,
|
|
pi_a => x"FF",
|
|
po_b => OPEN,
|
|
pi_b => x"FF",
|
|
load_a => load_a,
|
|
load_d => load_d,
|
|
load_wr => load_wr0,
|
|
clk => clk,
|
|
ce => ce,
|
|
reset_na => reset_na
|
|
);
|
|
|
|
-- CARTRIDGE
|
|
i_psu3:ENTITY work.f8_psu
|
|
GENERIC MAP (
|
|
PAGE => "000011", -- 0x0C00
|
|
IOPAGE => "111101", -- Not used
|
|
IVEC => x"FFFF", -- Not used
|
|
ROM => INIT_ZERO)
|
|
PORT MAP (
|
|
dw => dr,
|
|
dr => dr3,
|
|
dv => dv3,
|
|
romc => romc,
|
|
tick => tick,
|
|
phase => phase,
|
|
ext_int => '0',
|
|
int_req => OPEN,
|
|
pri_o => OPEN,
|
|
pri_i => '1',
|
|
po_a => OPEN,
|
|
pi_a => x"FF",
|
|
po_b => OPEN,
|
|
pi_b => x"FF",
|
|
load_a => load_a,
|
|
load_d => load_d,
|
|
load_wr => load_wr1,
|
|
clk => clk,
|
|
ce => ce,
|
|
reset_na => reset_na
|
|
);
|
|
|
|
-- CARTRIDGE
|
|
i_psu4:ENTITY work.f8_psu
|
|
GENERIC MAP (
|
|
PAGE => "000100", -- 0x1000
|
|
IOPAGE => "111100", -- Not used
|
|
IVEC => x"FFFF", -- Not used
|
|
ROM => INIT_ZERO)
|
|
PORT MAP (
|
|
dw => dr,
|
|
dr => dr4,
|
|
dv => dv4,
|
|
romc => romc,
|
|
tick => tick,
|
|
phase => phase,
|
|
ext_int => '0',
|
|
int_req => OPEN,
|
|
pri_o => OPEN,
|
|
pri_i => '1',
|
|
po_a => OPEN,
|
|
pi_a => x"FF",
|
|
po_b => OPEN,
|
|
pi_b => x"FF",
|
|
load_a => load_a,
|
|
load_d => load_d,
|
|
load_wr => load_wr2,
|
|
clk => clk,
|
|
ce => ce,
|
|
reset_na => reset_na
|
|
);
|
|
|
|
-- CARTRIDGE
|
|
i_psu5:ENTITY work.f8_psu
|
|
GENERIC MAP (
|
|
PAGE => "000101", -- 0x1400
|
|
IOPAGE => "111011", -- Not used
|
|
IVEC => x"FFFF", -- Not used
|
|
ROM => INIT_ZERO)
|
|
PORT MAP (
|
|
dw => dr,
|
|
dr => dr5,
|
|
dv => dv5,
|
|
romc => romc,
|
|
tick => tick,
|
|
phase => phase,
|
|
ext_int => '0',
|
|
int_req => OPEN,
|
|
pri_o => OPEN,
|
|
pri_i => '1',
|
|
po_a => OPEN,
|
|
pi_a => x"FF",
|
|
po_b => OPEN,
|
|
pi_b => x"FF",
|
|
load_a => load_a,
|
|
load_d => load_d,
|
|
load_wr => load_wr3,
|
|
clk => clk,
|
|
ce => ce,
|
|
reset_na => reset_na);
|
|
|
|
dr <= dr0 WHEN dv0='1' ELSE
|
|
dr1 WHEN dv1='1' ELSE
|
|
dr2 WHEN dv2='1' ELSE
|
|
dr3 WHEN dv3='1' ELSE
|
|
dr4 WHEN dv4='1' ELSE
|
|
dr5 WHEN dv5='1' ELSE
|
|
dw_cpu;
|
|
|
|
----------------------------------------------------------
|
|
-- CARTRIDGE LOAD
|
|
|
|
PROCESS (clk) IS
|
|
BEGIN
|
|
IF rising_edge(clk) THEN
|
|
load_a <=unsigned(ioctl_addr(9 DOWNTO 0));
|
|
load_wr0<=NOT ioctl_addr(10) AND NOT ioctl_addr(11) AND ioctl_wr;
|
|
load_wr1<= ioctl_addr(10) AND NOT ioctl_addr(11) AND ioctl_wr;
|
|
load_wr2<=NOT ioctl_addr(10) AND ioctl_addr(11) AND ioctl_wr;
|
|
load_wr3<= ioctl_addr(10) AND ioctl_addr(11) AND ioctl_wr;
|
|
load_d <=unsigned(ioctl_dout);
|
|
ioctl_wait<='0';
|
|
END IF;
|
|
END PROCESS;
|
|
|
|
rdena<=NOT po0(6);
|
|
|
|
----------------------------------------------------------
|
|
-- VIDEO
|
|
vram_h <= to_integer(NOT po4(6 DOWNTO 0));
|
|
vram_v <= to_integer(NOT po5(5 DOWNTO 0));
|
|
vram_dw<= NOT po1(7 DOWNTO 6);
|
|
vram_wr<= po0(5);
|
|
|
|
vram_a <= vram_h + vram_v * 128;
|
|
|
|
PROCESS(clk) IS
|
|
BEGIN
|
|
IF rising_edge(clk) THEN
|
|
IF vram_wr='1' THEN
|
|
vram(vram_a)<=vram_dw;
|
|
END IF;
|
|
IF vram_wr='1' AND vram_h=125 THEN
|
|
v125(vram_v)<=vram_dw(1);
|
|
END IF;
|
|
IF vram_wr='1' AND vram_h=126 THEN
|
|
v126(vram_v)<=vram_dw(1);
|
|
END IF;
|
|
END IF;
|
|
END PROCESS;
|
|
|
|
-- VIDEO SWEEP
|
|
PROCESS (clk) IS
|
|
BEGIN
|
|
IF rising_edge(clk) THEN
|
|
IF ce='1' THEN
|
|
hpos<=hpos+1;
|
|
IF hpos=HTOTAL-1 THEN
|
|
hpos<=0;
|
|
vpos<=vpos+1;
|
|
IF vpos=VTOTAL-1 THEN
|
|
vpos<=0;
|
|
END IF;
|
|
END IF;
|
|
|
|
pos<=((vpos/4) MOD 64) * 128 + ((hpos/2) MOD 128);
|
|
vposp<=vpos;
|
|
hposp<=hpos;
|
|
|
|
pix <=vram(pos);
|
|
p125<=v125((vposp/4) MOD 64);
|
|
p126<=v126((vposp/4) MOD 64);
|
|
|
|
vga_r<=std_logic_vector(PAL_R(CMAP(to_integer(p125 & p126 & pix))));
|
|
vga_g<=std_logic_vector(PAL_G(CMAP(to_integer(p125 & p126 & pix))));
|
|
vga_b<=std_logic_vector(PAL_B(CMAP(to_integer(p125 & p126 & pix))));
|
|
vga_de<=to_std_logic(vposp<=VDISP AND hposp<HDISP);
|
|
|
|
vga_hs<=to_std_logic(hposp>=HSYNCSTART AND hposp<=HSYNCEND);
|
|
vga_vs<=to_std_logic(vposp>=VSYNCSTART AND vposp<=VSYNCEND);
|
|
END IF;
|
|
END IF;
|
|
END PROCESS;
|
|
|
|
vga_clk<=clk;
|
|
vga_ce<=ce;
|
|
|
|
-- 128 x 64 pixels => 102 x 58 visible => 95 x 58 visible
|
|
-- CPU : F video / 2
|
|
-- 1.7897725MHz (NTSC)
|
|
-- 2.0000000MHz (PAL GEN 1)
|
|
-- 1.7734475MHz (PAL GEN 2)
|
|
|
|
----------------------------------------------------------
|
|
-- Joysticks / Buttons
|
|
pi0(7 DOWNTO 4)<=po0(7 DOWNTO 4);
|
|
pi0(0) <= NOT Keys(0); -- TIME
|
|
pi0(1) <= NOT Keys(1); -- MODE
|
|
pi0(2) <= NOT Keys(2); -- HOLD
|
|
pi0(3) <= NOT Keys(3); -- START
|
|
|
|
pi1i(7) <= NOT joystick_0(4); -- RIGHT G.DOWN
|
|
pi1i(6) <= NOT joystick_0(5); -- RIGHT G.UP
|
|
pi1i(5) <= NOT joystick_0(6); -- RIGHT CW
|
|
pi1i(4) <= NOT joystick_0(7); -- RIGHT CCW
|
|
pi1i(3) <= NOT joystick_0(3); -- RIGHT UP
|
|
pi1i(2) <= NOT joystick_0(2); -- RIGHT DOWN
|
|
pi1i(1) <= NOT joystick_0(1); -- RIGHT LEFT
|
|
pi1i(0) <= NOT joystick_0(0); -- RIGHT RIGHT
|
|
|
|
pi4i(7) <= NOT joystick_1(4); -- LEFT G.DOWN
|
|
pi4i(6) <= NOT joystick_1(5); -- LEFT G.UP
|
|
pi4i(5) <= NOT joystick_1(6); -- LEFT CW
|
|
pi4i(4) <= NOT joystick_1(7); -- LEFT CCW
|
|
pi4i(3) <= NOT joystick_1(3); -- LEFT UP
|
|
pi4i(2) <= NOT joystick_1(2); -- LEFT DOWN
|
|
pi4i(1) <= NOT joystick_1(1); -- LEFT LEFT
|
|
pi4i(0) <= NOT joystick_1(0); -- LEFT RIGHT
|
|
|
|
pi1<=pi1i OR po1 WHEN rdena='1' ELSE po1;
|
|
pi4<=pi4i OR po4 WHEN rdena='1' ELSE po4;
|
|
|
|
pi5<=po5;
|
|
|
|
----------------------------------------------------------
|
|
-- Audio
|
|
-- 00 : Silence
|
|
-- 01 : 1kHz
|
|
-- 10 : 500Hz
|
|
-- 11 : 120Hz
|
|
|
|
tone <=po5(7 DOWNTO 6);
|
|
PROCESS (clk) IS
|
|
VARIABLE s_v : std_logic;
|
|
BEGIN
|
|
IF rising_edge(clk) THEN
|
|
vdiv<=vdiv + 1;
|
|
CASE tone IS
|
|
WHEN "00" => s_v:='0';
|
|
WHEN "01" => s_v:=vdiv(10);
|
|
WHEN "10" => s_v:=vdiv(9);
|
|
WHEN OTHERS => s_v:=vdiv(7);
|
|
END CASE;
|
|
audio<=(OTHERS =>s_v);
|
|
END IF;
|
|
END PROCESS;
|
|
|
|
areset_na<=NOT reset AND pll_locked AND NOT ioctl_download;
|
|
vreset_na<=x"0000" WHEN areset_na='0' ELSE
|
|
'1' & vreset_na(0 TO 14) WHEN rising_edge(clk);
|
|
reset_na<=vreset_na(15);
|
|
|
|
END struct; |