forked from MiSTer-devel/TurboGrafx16_MiSTer
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhuc6260.vhd
296 lines (253 loc) · 7.69 KB
/
huc6260.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_TEXTIO.all;
library STD;
use STD.TEXTIO.ALL;
entity huc6260 is
port (
CLK : in std_logic;
RESET_N : in std_logic;
HSIZE : out std_logic_vector(9 downto 0);
HSTART : out std_logic_vector(9 downto 0);
-- CPU Interface
A : in std_logic_vector(2 downto 0);
CE_N : in std_logic;
WR_N : in std_logic;
RD_N : in std_logic;
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0);
-- VDC Interface
COLNO : in std_logic_vector(8 downto 0);
CLKEN : out std_logic;
CLKEN_FS : out std_logic;
RVBL : in std_logic;
-- NTSC/RGB Video Output
R : out std_logic_vector(2 downto 0);
G : out std_logic_vector(2 downto 0);
B : out std_logic_vector(2 downto 0);
BW : out std_logic;
VS_N : out std_logic;
HS_N : out std_logic;
HBL : out std_logic;
VBL : out std_logic
);
end huc6260;
architecture rtl of huc6260 is
-- CPU Interface
signal PREV_A : std_logic_vector(2 downto 0);
type ctrl_t is ( CTRL_IDLE, CTRL_WAIT, CTRL_INCR );
signal CTRL : ctrl_t;
signal CR : std_logic_vector(7 downto 0);
-- VCE Registers
signal DOTCLOCK : std_logic_vector(1 downto 0);
signal DOTCLOCK_FS: std_logic_vector(1 downto 0);
-- CPU Color RAM Interface
signal RAM_A : std_logic_vector(8 downto 0);
signal RAM_DI : std_logic_vector(8 downto 0);
signal RAM_WE : std_logic := '0';
signal RAM_DO : std_logic_vector(8 downto 0);
-- Color RAM Output
signal COLOR : std_logic_vector(8 downto 0);
-- Video Counting. All horizontal constants should be divisible by 24! (LCM of 4, 6 and 8)
constant LEFT_BL_CLOCKS : integer := 432;
constant DISP_CLOCKS : integer := 2160;
constant LINE_CLOCKS : integer := 2736;
constant HS_CLOCKS : integer := 192;
constant TOTAL_LINES : integer := 263; -- 525
constant VS_LINES : integer := 3; -- pcetech.txt
constant TOP_BL_LINES_E : integer := 19; -- pcetech.txt (must include VS_LINES in current implementation)
constant DISP_LINES_E : integer := 242; -- same as in mednafen
signal TOP_BL_LINES : integer;
signal DISP_LINES : integer;
constant HSIZE0 : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(DISP_CLOCKS/8,10));
constant HSIZE1 : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(DISP_CLOCKS/6,10));
constant HSIZE2 : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(DISP_CLOCKS/4,10));
constant HSTART0 : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(LEFT_BL_CLOCKS/8,10));
constant HSTART1 : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(LEFT_BL_CLOCKS/6,10));
constant HSTART2 : std_logic_vector(9 downto 0) := std_logic_vector(to_unsigned(LEFT_BL_CLOCKS/4,10));
signal H_CNT : std_logic_vector(11 downto 0);
signal V_CNT : std_logic_vector(9 downto 0);
signal HBL_FF, HBL_FF2 : std_logic;
signal VBL_FF, VBL_FF2 : std_logic;
-- Clock generation
signal CLKEN_CNT : std_logic_vector(2 downto 0);
signal CLKEN_FS_CNT: std_logic_vector(2 downto 0);
signal CLKEN_FF : std_logic;
begin
TOP_BL_LINES <= TOP_BL_LINES_E when RVBL = '1' else TOP_BL_LINES_E+3;
DISP_LINES <= DISP_LINES_E when RVBL = '1' else DISP_LINES_E-10;
-- Color RAM
ram : entity work.dpram generic map (9,9)
port map(
clock => CLK,
address_a => RAM_A,
data_a => RAM_DI,
wren_a => RAM_WE,
q_a => RAM_DO,
address_b => COLNO,
q_b => COLOR
);
process( CLK )
begin
if rising_edge( CLK ) then
if RESET_N = '0' then
RAM_A <= (others => '0');
RAM_DI <= (others => '0');
RAM_WE <= '0';
CR <= x"00";
PREV_A <= (others => '0');
CTRL <= CTRL_IDLE;
else
case CTRL is
when CTRL_IDLE =>
RAM_WE <= '0';
if CE_N = '0' and WR_N = '0' then
-- CPU Write
PREV_A <= A;
CTRL <= CTRL_WAIT;
case A is
when "000" =>
CR <= DI;
when "010" =>
RAM_A(7 downto 0) <= DI;
when "011" =>
RAM_A(8) <= DI(0);
when "100" =>
RAM_WE <= '1';
RAM_DI <= RAM_DO(8) & DI;
when "101" =>
RAM_WE <= '1';
RAM_DI <= DI(0) & RAM_DO(7 downto 0);
CTRL <= CTRL_INCR;
when others => null;
end case;
elsif CE_N = '0' and RD_N = '0' then
-- CPU Read
PREV_A <= A;
CTRL <= CTRL_WAIT;
DO <= x"FF";
case A is
when "100" =>
DO <= RAM_DO(7 downto 0);
when "101" =>
DO <= "1111111" & RAM_DO(8);
CTRL <= CTRL_INCR;
when others => null;
end case;
end if;
when CTRL_INCR =>
RAM_WE <= '0';
RAM_A <= RAM_A + 1;
CTRL <= CTRL_WAIT;
when CTRL_WAIT =>
RAM_WE <= '0';
-- Wait for the CPU to "release" the VCE.
-- I don't know what happens in the case of an address change
-- however it can be achieved only with addresses read/write cycles,
-- so it seems unlikely. The case has been handled, though.
-- HuC6280 Rmw instructions are safe, as there is a "dummy cycle"
-- between the read cycle and the write cycle.
CTRL <= CTRL_IDLE;
if CE_N = '0' and (WR_N = '0' or RD_N = '0') and PREV_A = A then
CTRL <= CTRL_WAIT;
end if;
when others => null;
end case;
end if;
end if;
end process;
-- Video counting, register loading and clock generation
process( CLK )
begin
if rising_edge( CLK ) then
H_CNT <= H_CNT + 1;
CLKEN_FF <= '0';
CLKEN_CNT <= CLKEN_CNT + 1;
if DOTCLOCK = "00" and CLKEN_CNT = "111" then
CLKEN_CNT <= (others => '0');
CLKEN_FF <= '1';
elsif DOTCLOCK = "01" and CLKEN_CNT = "101" then
CLKEN_CNT <= (others => '0');
CLKEN_FF <= '1';
elsif DOTCLOCK(1) = '1' and CLKEN_CNT = "011" then
CLKEN_CNT <= (others => '0');
CLKEN_FF <= '1';
end if;
if H_CNT = LINE_CLOCKS-1 then
CLKEN_CNT <= (others => '0');
CLKEN_FF <= '1';
H_CNT <= (others => '0');
V_CNT <= V_CNT + 1;
if V_CNT = TOTAL_LINES-1 then
V_CNT <= (others => '0');
end if;
-- Reload registers
BW <= CR(7);
DOTCLOCK <= CR(1 downto 0);
end if;
end if;
end process;
process( CLK )
begin
if rising_edge( CLK ) then
CLKEN_FS <= '0';
CLKEN_FS_CNT <= CLKEN_FS_CNT + 1;
if DOTCLOCK_FS = "00" and CLKEN_FS_CNT = "111" then
CLKEN_FS_CNT <= (others => '0');
CLKEN_FS <= '1';
elsif DOTCLOCK_FS = "01" and CLKEN_FS_CNT = "101" then
CLKEN_FS_CNT <= (others => '0');
CLKEN_FS <= '1';
elsif DOTCLOCK_FS(1) = '1' and CLKEN_FS_CNT = "011" then
CLKEN_FS_CNT <= (others => '0');
CLKEN_FS <= '1';
end if;
if H_CNT = LEFT_BL_CLOCKS and V_CNT = TOP_BL_LINES then
CLKEN_FS_CNT <= (others => '0');
CLKEN_FS <= '1';
DOTCLOCK_FS <= CR(1 downto 0);
end if;
end if;
end process;
-- Sync
process( CLK )
begin
if rising_edge( CLK ) then
if H_CNT = 0 then HS_N <= '0'; end if;
if H_CNT = HS_CLOCKS-1 then HS_N <= '1'; end if;
if V_CNT = 0 then VS_N <= '0'; end if;
if V_CNT = VS_LINES-1 then VS_N <= '1'; end if;
end if;
end process;
-- Blank
process( CLK )
begin
if rising_edge( CLK ) then
if H_CNT = LEFT_BL_CLOCKS then HBL_FF <= '0'; end if;
if H_CNT = LEFT_BL_CLOCKS + DISP_CLOCKS then HBL_FF <= '1'; end if;
if V_CNT = TOP_BL_LINES then VBL_FF <= '0'; end if;
if V_CNT = TOP_BL_LINES + DISP_LINES then VBL_FF <= '1'; end if;
end if;
end process;
-- Final output
process( CLK )
begin
if rising_edge( CLK ) then
if CLKEN_FF = '1' then
-- compensate HUC6202 delay
VBL_FF2 <= VBL_FF;
HBL_FF2 <= HBL_FF;
VBL <= VBL_FF2;
HBL <= HBL_FF2;
G <= COLOR(8 downto 6);
R <= COLOR(5 downto 3);
B <= COLOR(2 downto 0);
end if;
end if;
end process;
CLKEN <= CLKEN_FF;
HSIZE <= HSIZE0 when DOTCLOCK = "00" else HSIZE1 when DOTCLOCK = "01" else HSIZE2;
HSTART <= HSTART0 when DOTCLOCK = "00" else HSTART1 when DOTCLOCK = "01" else HSTART2;
end rtl;