Commit | Line | Data |
---|---|---|
cf76e892 JPM |
1 | // |
2 | // TOM Processing | |
3 | // | |
4 | // Originally by David Raingeard (cal2) | |
5 | // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS) | |
6 | // Cleanups, endian wrongness amelioration, and extensive fixes by James Hammons | |
7 | // (C) 2010 Underground Software | |
8 | // | |
9 | // JLH = James Hammons <jlhamm@acm.org> | |
10 | // JPM = Jean-Paul Mari <djipi.mari@gmail.com> | |
11 | // | |
12 | // Who When What | |
13 | // --- ---------- ----------------------------------------------------------- | |
14 | // JLH 01/16/2010 Created this log ;-) | |
15 | // JLH 01/20/2011 Change rendering to RGBA, removed unnecessary code | |
16 | // JPM 06/06/2016 Visual Studio support | |
17 | // | |
18 | // Note: TOM has only a 16K memory space | |
19 | // | |
20 | // ------------------------------------------------------------ | |
21 | // TOM REGISTERS (Mapped by Aaron Giles) | |
22 | // ------------------------------------------------------------ | |
23 | // F00000-F0FFFF R/W xxxxxxxx xxxxxxxx Internal Registers | |
24 | // F00000 R/W -x-xx--- xxxxxxxx MEMCON1 - memory config reg 1 | |
25 | // -x------ -------- (CPU32 - is the CPU 32bits?) | |
26 | // ---xx--- -------- (IOSPEED - external I/O clock cycles) | |
27 | // -------- x------- (FASTROM - reduces ROM clock cycles) | |
28 | // -------- -xx----- (DRAMSPEED - sets RAM clock cycles) | |
29 | // -------- ---xx--- (ROMSPEED - sets ROM clock cycles) | |
30 | // -------- -----xx- (ROMWIDTH - sets width of ROM: 8,16,32,64 bits) | |
31 | // -------- -------x (ROMHI - controls ROM mapping) | |
32 | // F00002 R/W --xxxxxx xxxxxxxx MEMCON2 - memory config reg 2 | |
33 | // --x----- -------- (HILO - image display bit order) | |
34 | // ---x---- -------- (BIGEND - big endian addressing?) | |
35 | // ----xxxx -------- (REFRATE - DRAM refresh rate) | |
36 | // -------- xx------ (DWIDTH1 - DRAM1 width: 8,16,32,64 bits) | |
37 | // -------- --xx---- (COLS1 - DRAM1 columns: 256,512,1024,2048) | |
38 | // -------- ----xx-- (DWIDTH0 - DRAM0 width: 8,16,32,64 bits) | |
39 | // -------- ------xx (COLS0 - DRAM0 columns: 256,512,1024,2048) | |
40 | // F00004 R/W -----xxx xxxxxxxx HC - horizontal count | |
41 | // -----x-- -------- (which half of the display) | |
42 | // ------xx xxxxxxxx (10-bit counter) | |
43 | // F00006 R/W ----xxxx xxxxxxxx VC - vertical count | |
44 | // ----x--- -------- (which field is being generated) | |
45 | // -----xxx xxxxxxxx (11-bit counter) | |
46 | // F00008 R -----xxx xxxxxxxx LPH - light pen horizontal position | |
47 | // F0000A R -----xxx xxxxxxxx LPV - light pen vertical position | |
48 | // F00010-F00017 R xxxxxxxx xxxxxxxx OB - current object code from the graphics processor | |
49 | // F00020-F00023 W xxxxxxxx xxxxxxxx OLP - start of the object list | |
50 | // F00026 W -------- -------x OBF - object processor flag | |
51 | // F00028 W ----xxxx xxxxxxxx VMODE - video mode | |
52 | // W ----xxx- -------- (PWIDTH1-8 - width of pixel in video clock cycles) | |
53 | // W -------x -------- (VARMOD - enable variable color resolution) | |
54 | // W -------- x------- (BGEN - clear line buffer to BG color) | |
55 | // W -------- -x------ (CSYNC - enable composite sync on VSYNC) | |
56 | // W -------- --x----- (BINC - local border color if INCEN) | |
57 | // W -------- ---x---- (INCEN - encrustation enable) | |
58 | // W -------- ----x--- (GENLOCK - enable genlock) | |
59 | // W -------- -----xx- (MODE - CRY16,RGB24,DIRECT16,RGB16) | |
60 | // W -------- -------x (VIDEN - enables video) | |
61 | // F0002A W xxxxxxxx xxxxxxxx BORD1 - border color (red/green) | |
62 | // F0002C W -------- xxxxxxxx BORD2 - border color (blue) | |
63 | // F0002E W ------xx xxxxxxxx HP - horizontal period | |
64 | // F00030 W -----xxx xxxxxxxx HBB - horizontal blanking begin | |
65 | // F00032 W -----xxx xxxxxxxx HBE - horizontal blanking end | |
66 | // F00034 W -----xxx xxxxxxxx HSYNC - horizontal sync | |
67 | // F00036 W ------xx xxxxxxxx HVS - horizontal vertical sync | |
68 | // F00038 W -----xxx xxxxxxxx HDB1 - horizontal display begin 1 | |
69 | // F0003A W -----xxx xxxxxxxx HDB2 - horizontal display begin 2 | |
70 | // F0003C W -----xxx xxxxxxxx HDE - horizontal display end | |
71 | // F0003E W -----xxx xxxxxxxx VP - vertical period | |
72 | // F00040 W -----xxx xxxxxxxx VBB - vertical blanking begin | |
73 | // F00042 W -----xxx xxxxxxxx VBE - vertical blanking end | |
74 | // F00044 W -----xxx xxxxxxxx VS - vertical sync | |
75 | // F00046 W -----xxx xxxxxxxx VDB - vertical display begin | |
76 | // F00048 W -----xxx xxxxxxxx VDE - vertical display end | |
77 | // F0004A W -----xxx xxxxxxxx VEB - vertical equalization begin | |
78 | // F0004C W -----xxx xxxxxxxx VEE - vertical equalization end | |
79 | // F0004E W -----xxx xxxxxxxx VI - vertical interrupt | |
80 | // F00050 W xxxxxxxx xxxxxxxx PIT0 - programmable interrupt timer 0 | |
81 | // F00052 W xxxxxxxx xxxxxxxx PIT1 - programmable interrupt timer 1 | |
82 | // F00054 W ------xx xxxxxxxx HEQ - horizontal equalization end | |
83 | // F00058 W xxxxxxxx xxxxxxxx BG - background color | |
84 | // F000E0 R/W ---xxxxx ---xxxxx INT1 - CPU interrupt control register | |
85 | // ---x---- -------- (C_JERCLR - clear pending Jerry ints) | |
86 | // ----x--- -------- (C_PITCLR - clear pending PIT ints) | |
87 | // -----x-- -------- (C_OPCLR - clear pending object processor ints) | |
88 | // ------x- -------- (C_GPUCLR - clear pending graphics processor ints) | |
89 | // -------x -------- (C_VIDCLR - clear pending video timebase ints) | |
90 | // -------- ---x---- (C_JERENA - enable Jerry ints) | |
91 | // -------- ----x--- (C_PITENA - enable PIT ints) | |
92 | // -------- -----x-- (C_OPENA - enable object processor ints) | |
93 | // -------- ------x- (C_GPUENA - enable graphics processor ints) | |
94 | // -------- -------x (C_VIDENA - enable video timebase ints) | |
95 | // F000E2 W -------- -------- INT2 - CPU interrupt resume register | |
96 | // F00400-F005FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table A | |
97 | // F00600-F007FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table B | |
98 | // F00800-F00D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer A | |
99 | // F01000-F0159F R/W xxxxxxxx xxxxxxxx LBUF - line buffer B | |
100 | // F01800-F01D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer currently selected | |
101 | // ------------------------------------------------------------ | |
102 | // F02000-F021FF R/W xxxxxxxx xxxxxxxx GPU control registers | |
103 | // F02100 R/W xxxxxxxx xxxxxxxx G_FLAGS - GPU flags register | |
104 | // R/W x------- -------- (DMAEN - DMA enable) | |
105 | // R/W -x------ -------- (REGPAGE - register page) | |
106 | // W --x----- -------- (G_BLITCLR - clear blitter interrupt) | |
107 | // W ---x---- -------- (G_OPCLR - clear object processor int) | |
108 | // W ----x--- -------- (G_PITCLR - clear PIT interrupt) | |
109 | // W -----x-- -------- (G_JERCLR - clear Jerry interrupt) | |
110 | // W ------x- -------- (G_CPUCLR - clear CPU interrupt) | |
111 | // R/W -------x -------- (G_BLITENA - enable blitter interrupt) | |
112 | // R/W -------- x------- (G_OPENA - enable object processor int) | |
113 | // R/W -------- -x------ (G_PITENA - enable PIT interrupt) | |
114 | // R/W -------- --x----- (G_JERENA - enable Jerry interrupt) | |
115 | // R/W -------- ---x---- (G_CPUENA - enable CPU interrupt) | |
116 | // R/W -------- ----x--- (IMASK - interrupt mask) | |
117 | // R/W -------- -----x-- (NEGA_FLAG - ALU negative) | |
118 | // R/W -------- ------x- (CARRY_FLAG - ALU carry) | |
119 | // R/W -------- -------x (ZERO_FLAG - ALU zero) | |
120 | // F02104 W -------- ----xxxx G_MTXC - matrix control register | |
121 | // W -------- ----x--- (MATCOL - column/row major) | |
122 | // W -------- -----xxx (MATRIX3-15 - matrix width) | |
123 | // F02108 W ----xxxx xxxxxx-- G_MTXA - matrix address register | |
124 | // F0210C W -------- -----xxx G_END - data organization register | |
125 | // W -------- -----x-- (BIG_INST - big endian instruction fetch) | |
126 | // W -------- ------x- (BIG_PIX - big endian pixels) | |
127 | // W -------- -------x (BIG_IO - big endian I/O) | |
128 | // F02110 R/W xxxxxxxx xxxxxxxx G_PC - GPU program counter | |
129 | // F02114 R/W xxxxxxxx xx-xxxxx G_CTRL - GPU control/status register | |
130 | // R xxxx---- -------- (VERSION - GPU version code) | |
131 | // R/W ----x--- -------- (BUS_HOG - hog the bus!) | |
132 | // R/W -----x-- -------- (G_BLITLAT - blitter interrupt latch) | |
133 | // R/W ------x- -------- (G_OPLAT - object processor int latch) | |
134 | // R/W -------x -------- (G_PITLAT - PIT interrupt latch) | |
135 | // R/W -------- x------- (G_JERLAT - Jerry interrupt latch) | |
136 | // R/W -------- -x------ (G_CPULAT - CPU interrupt latch) | |
137 | // R/W -------- ---x---- (SINGLE_GO - single step one instruction) | |
138 | // R/W -------- ----x--- (SINGLE_STEP - single step mode) | |
139 | // R/W -------- -----x-- (FORCEINT0 - cause interrupt 0 on GPU) | |
140 | // R/W -------- ------x- (CPUINT - send GPU interrupt to CPU) | |
141 | // R/W -------- -------x (GPUGO - enable GPU execution) | |
142 | // F02118-F0211B R/W xxxxxxxx xxxxxxxx G_HIDATA - high data register | |
143 | // F0211C-F0211F R xxxxxxxx xxxxxxxx G_REMAIN - divide unit remainder | |
144 | // F0211C W -------- -------x G_DIVCTRL - divide unit control | |
145 | // W -------- -------x (DIV_OFFSET - 1=16.16 divide, 0=32-bit divide) | |
146 | // ------------------------------------------------------------ | |
147 | // BLITTER REGISTERS | |
148 | // ------------------------------------------------------------ | |
149 | // F02200-F022FF R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Blitter registers | |
150 | // F02200 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_BASE - A1 base register | |
151 | // F02204 W -------- ---xxxxx -xxxxxxx xxxxx-xx A1_FLAGS - A1 flags register | |
152 | // W -------- ---x---- -------- -------- (YSIGNSUB - invert sign of Y delta) | |
153 | // W -------- ----x--- -------- -------- (XSIGNSUB - invert sign of X delta) | |
154 | // W -------- -----x-- -------- -------- (Y add control) | |
155 | // W -------- ------xx -------- -------- (X add control) | |
156 | // W -------- -------- -xxxxxx- -------- (width in 6-bit floating point) | |
157 | // W -------- -------- -------x xx------ (ZOFFS1-6 - Z data offset) | |
158 | // W -------- -------- -------- --xxx--- (PIXEL - pixel size) | |
159 | // W -------- -------- -------- ------xx (PITCH1-4 - data phrase pitch) | |
160 | // F02208 W -xxxxxxx xxxxxxxx -xxxxxxx xxxxxxxx A1_CLIP - A1 clipping size | |
161 | // W -xxxxxxx xxxxxxxx -------- -------- (height) | |
162 | // W -------- -------- -xxxxxxx xxxxxxxx (width) | |
163 | // F0220C R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_PIXEL - A1 pixel pointer | |
164 | // R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel value) | |
165 | // R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel value) | |
166 | // F02210 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_STEP - A1 step value | |
167 | // W xxxxxxxx xxxxxxxx -------- -------- (Y step value) | |
168 | // W -------- -------- xxxxxxxx xxxxxxxx (X step value) | |
169 | // F02214 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FSTEP - A1 step fraction value | |
170 | // W xxxxxxxx xxxxxxxx -------- -------- (Y step fraction value) | |
171 | // W -------- -------- xxxxxxxx xxxxxxxx (X step fraction value) | |
172 | // F02218 R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FPIXEL - A1 pixel pointer fraction | |
173 | // R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel fraction value) | |
174 | // R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel fraction value) | |
175 | // F0221C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_INC - A1 increment | |
176 | // W xxxxxxxx xxxxxxxx -------- -------- (Y increment) | |
177 | // W -------- -------- xxxxxxxx xxxxxxxx (X increment) | |
178 | // F02220 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FINC - A1 increment fraction | |
179 | // W xxxxxxxx xxxxxxxx -------- -------- (Y increment fraction) | |
180 | // W -------- -------- xxxxxxxx xxxxxxxx (X increment fraction) | |
181 | // F02224 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_BASE - A2 base register | |
182 | // F02228 W -------- ---xxxxx -xxxxxxx xxxxx-xx A2_FLAGS - A2 flags register | |
183 | // W -------- ---x---- -------- -------- (YSIGNSUB - invert sign of Y delta) | |
184 | // W -------- ----x--- -------- -------- (XSIGNSUB - invert sign of X delta) | |
185 | // W -------- -----x-- -------- -------- (Y add control) | |
186 | // W -------- ------xx -------- -------- (X add control) | |
187 | // W -------- -------- -xxxxxx- -------- (width in 6-bit floating point) | |
188 | // W -------- -------- -------x xx------ (ZOFFS1-6 - Z data offset) | |
189 | // W -------- -------- -------- --xxx--- (PIXEL - pixel size) | |
190 | // W -------- -------- -------- ------xx (PITCH1-4 - data phrase pitch) | |
191 | // F0222C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_MASK - A2 window mask | |
192 | // F02230 R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_PIXEL - A2 pixel pointer | |
193 | // R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel value) | |
194 | // R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel value) | |
195 | // F02234 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_STEP - A2 step value | |
196 | // W xxxxxxxx xxxxxxxx -------- -------- (Y step value) | |
197 | // W -------- -------- xxxxxxxx xxxxxxxx (X step value) | |
198 | // F02238 W -xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_CMD - command register | |
199 | // W -x------ -------- -------- -------- (SRCSHADE - modify source intensity) | |
200 | // W --x----- -------- -------- -------- (BUSHI - hi priority bus) | |
201 | // W ---x---- -------- -------- -------- (BKGWREN - writeback destination) | |
202 | // W ----x--- -------- -------- -------- (DCOMPEN - write inhibit from data comparator) | |
203 | // W -----x-- -------- -------- -------- (BCOMPEN - write inhibit from bit coparator) | |
204 | // W ------x- -------- -------- -------- (CMPDST - compare dest instead of src) | |
205 | // W -------x xxx----- -------- -------- (logical operation) | |
206 | // W -------- ---xxx-- -------- -------- (ZMODE - Z comparator mode) | |
207 | // W -------- ------x- -------- -------- (ADDDSEL - select sum of src & dst) | |
208 | // W -------- -------x -------- -------- (PATDSEL - select pattern data) | |
209 | // W -------- -------- x------- -------- (TOPNEN - enable carry into top intensity nibble) | |
210 | // W -------- -------- -x------ -------- (TOPBEN - enable carry into top intensity byte) | |
211 | // W -------- -------- --x----- -------- (ZBUFF - enable Z updates in inner loop) | |
212 | // W -------- -------- ---x---- -------- (GOURD - enable gouraud shading in inner loop) | |
213 | // W -------- -------- ----x--- -------- (DSTA2 - reverses A2/A1 roles) | |
214 | // W -------- -------- -----x-- -------- (UPDA2 - add A2 step to A2 in outer loop) | |
215 | // W -------- -------- ------x- -------- (UPDA1 - add A1 step to A1 in outer loop) | |
216 | // W -------- -------- -------x -------- (UPDA1F - add A1 fraction step to A1 in outer loop) | |
217 | // W -------- -------- -------- x------- (diagnostic use) | |
218 | // W -------- -------- -------- -x------ (CLIP_A1 - clip A1 to window) | |
219 | // W -------- -------- -------- --x----- (DSTWRZ - enable dest Z write in inner loop) | |
220 | // W -------- -------- -------- ---x---- (DSTENZ - enable dest Z read in inner loop) | |
221 | // W -------- -------- -------- ----x--- (DSTEN - enables dest data read in inner loop) | |
222 | // W -------- -------- -------- -----x-- (SRCENX - enable extra src read at start of inner) | |
223 | // W -------- -------- -------- ------x- (SRCENZ - enables source Z read in inner loop) | |
224 | // W -------- -------- -------- -------x (SRCEN - enables source data read in inner loop) | |
225 | // F02238 R xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_CMD - status register | |
226 | // R xxxxxxxx xxxxxxxx -------- -------- (inner count) | |
227 | // R -------- -------- xxxxxxxx xxxxxx-- (diagnostics) | |
228 | // R -------- -------- -------- ------x- (STOPPED - when stopped in collision detect) | |
229 | // R -------- -------- -------- -------x (IDLE - when idle) | |
230 | // F0223C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_COUNT - counters register | |
231 | // W xxxxxxxx xxxxxxxx -------- -------- (outer loop count) | |
232 | // W -------- -------- xxxxxxxx xxxxxxxx (inner loop count) | |
233 | // F02240-F02247 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCD - source data register | |
234 | // F02248-F0224F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_DSTD - destination data register | |
235 | // F02250-F02257 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_DSTZ - destination Z register | |
236 | // F02258-F0225F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCZ1 - source Z register 1 | |
237 | // F02260-F02267 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCZ2 - source Z register 2 | |
238 | // F02268-F0226F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_PATD - pattern data register | |
239 | // F02270 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_IINC - intensity increment | |
240 | // F02274 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_ZINC - Z increment | |
241 | // F02278 W -------- -------- -------- -----xxx B_STOP - collision control | |
242 | // W -------- -------- -------- -----x-- (STOPEN - enable blitter collision stops) | |
243 | // W -------- -------- -------- ------x- (ABORT - abort after stop) | |
244 | // W -------- -------- -------- -------x (RESUME - resume after stop) | |
245 | // F0227C W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I3 - intensity 3 | |
246 | // F02280 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I2 - intensity 2 | |
247 | // F02284 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I1 - intensity 1 | |
248 | // F02288 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I0 - intensity 0 | |
249 | // F0228C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z3 - Z3 | |
250 | // F02290 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z2 - Z2 | |
251 | // F02294 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z1 - Z1 | |
252 | // F02298 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z0 - Z0 | |
253 | // ------------------------------------------------------------ | |
254 | ||
255 | #include "tom.h" | |
256 | ||
257 | #include <string.h> // For memset() | |
258 | #include <stdlib.h> // For rand() | |
259 | #include "blitter.h" | |
260 | #include "cry2rgb.h" | |
261 | #include "event.h" | |
262 | #include "gpu.h" | |
263 | #include "jaguar.h" | |
264 | #include "log.h" | |
265 | #include "m68000/m68kinterface.h" | |
266 | //#include "memory.h" | |
267 | #include "op.h" | |
268 | #include "settings.h" | |
269 | ||
270 | #define NEW_TIMER_SYSTEM | |
271 | ||
272 | // TOM registers (offset from $F00000) | |
273 | ||
274 | #define MEMCON1 0x00 | |
275 | #define MEMCON2 0x02 | |
276 | #define HC 0x04 | |
277 | #define VC 0x06 | |
278 | #define OLP 0x20 // Object list pointer | |
279 | #define OBF 0x26 // Object processor flag | |
280 | #define VMODE 0x28 | |
281 | #define MODE 0x0006 // Line buffer to video generator mode | |
282 | #define BGEN 0x0080 // Background enable (CRY & RGB16 only) | |
283 | #define VARMOD 0x0100 // Mixed CRY/RGB16 mode (only works in MODE 0!) | |
284 | #define PWIDTH 0x0E00 // Pixel width in video clock cycles (value written + 1) | |
285 | #define BORD1 0x2A // Border green/red values (8 BPP) | |
286 | #define BORD2 0x2C // Border blue value (8 BPP) | |
287 | #define HP 0x2E // Values range from 1 - 1024 (value written + 1) | |
288 | #define HBB 0x30 // Horizontal blank begin | |
289 | #define HBE 0x32 | |
290 | #define HS 0x34 // Horizontal sync | |
291 | #define HVS 0x36 // Horizontal vertical sync | |
292 | #define HDB1 0x38 // Horizontal display begin 1 | |
293 | #define HDB2 0x3A | |
294 | #define HDE 0x3C | |
295 | #define VP 0x3E // Value ranges from 1 - 2048 (value written + 1) | |
296 | #define VBB 0x40 // Vertical blank begin | |
297 | #define VBE 0x42 | |
298 | #define VS 0x44 // Vertical sync | |
299 | #define VDB 0x46 // Vertical display begin | |
300 | #define VDE 0x48 | |
301 | #define VEB 0x4A // Vertical equalization begin | |
302 | #define VEE 0x4C // Vertical equalization end | |
303 | #define VI 0x4E // Vertical interrupt | |
304 | #define PIT0 0x50 | |
305 | #define PIT1 0x52 | |
306 | #define HEQ 0x54 // Horizontal equalization end | |
307 | #define BG 0x58 // Background color | |
308 | #define INT1 0xE0 | |
309 | #define INT2 0xE2 | |
310 | ||
311 | // Arbitrary video cutoff values (i.e., first/last visible spots on a TV, in HC | |
312 | // ticks) | |
313 | // Also note that VC is in *half* lines, i.e. divide by 2 to get the scanline | |
314 | /*#define LEFT_VISIBLE_HC 208 | |
315 | #define RIGHT_VISIBLE_HC 1528//*/ | |
316 | // These were right for Rayman, but that one is offset on a real TV too. | |
317 | //#define LEFT_VISIBLE_HC 208 | |
318 | //#define RIGHT_VISIBLE_HC 1488 | |
319 | // This is more like a real TV display... | |
320 | //#define LEFT_VISIBLE_HC (208 - 32) | |
321 | //#define RIGHT_VISIBLE_HC (1488 - 32) | |
322 | // Split the difference? (Seems to be OK for the most part...) | |
323 | ||
324 | // (-10 +10)*4 is for opening up the display by 16 pixels (may go to 20). Need to change VIRTUAL_SCREEN_WIDTH to match this as well (went from 320 to 340; this is 4 HCs per one of those pixels). | |
325 | //NB: Went back to 330. May shrink more. :-) | |
326 | //#define LEFT_VISIBLE_HC (208 - 16 - (8 * 4)) | |
327 | //#define LEFT_VISIBLE_HC (208 - 16 - (3 * 4)) | |
328 | #define LEFT_VISIBLE_HC (208 - 16 - (1 * 4)) | |
329 | //#define RIGHT_VISIBLE_HC (1488 - 16 + (10 * 4)) | |
330 | #define RIGHT_VISIBLE_HC (LEFT_VISIBLE_HC + (VIRTUAL_SCREEN_WIDTH * 4)) | |
331 | //#define TOP_VISIBLE_VC 25 | |
332 | //#define BOTTOM_VISIBLE_VC 503 | |
333 | #define TOP_VISIBLE_VC 31 | |
334 | #define BOTTOM_VISIBLE_VC 511 | |
335 | ||
336 | //Are these PAL horizontals correct? | |
337 | //They seem to be for the most part, but there are some games that seem to be | |
338 | //shifted over to the right from this "window". | |
339 | //#define LEFT_VISIBLE_HC_PAL (208 - 16 - (4 * 4)) | |
340 | //#define LEFT_VISIBLE_HC_PAL (208 - 16 - (-1 * 4)) | |
341 | #define LEFT_VISIBLE_HC_PAL (208 - 16 - (-3 * 4)) | |
342 | //#define RIGHT_VISIBLE_HC_PAL (1488 - 16 + (10 * 4)) | |
343 | #define RIGHT_VISIBLE_HC_PAL (LEFT_VISIBLE_HC_PAL + (VIRTUAL_SCREEN_WIDTH * 4)) | |
344 | #define TOP_VISIBLE_VC_PAL 67 | |
345 | #define BOTTOM_VISIBLE_VC_PAL 579 | |
346 | ||
347 | //This can be defined in the makefile as well... | |
348 | //(It's easier to do it here, though...) | |
349 | //#define TOM_DEBUG | |
350 | ||
351 | uint8_t tomRam8[0x4000]; | |
352 | uint32_t tomWidth, tomHeight; | |
353 | uint32_t tomTimerPrescaler; | |
354 | uint32_t tomTimerDivider; | |
355 | int32_t tomTimerCounter; | |
356 | uint16_t tom_jerry_int_pending, tom_timer_int_pending, tom_object_int_pending, | |
357 | tom_gpu_int_pending, tom_video_int_pending; | |
358 | ||
359 | // These are set by the "user" of the Jaguar core lib, since these are | |
360 | // OS/system dependent. | |
361 | uint32_t * screenBuffer; | |
362 | uint32_t screenPitch; | |
363 | ||
364 | static const char * videoMode_to_str[8] = | |
365 | { "16 BPP CRY", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB", | |
366 | "Mixed mode", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB" }; | |
367 | ||
368 | typedef void (render_xxx_scanline_fn)(uint32_t *); | |
369 | ||
370 | // Private function prototypes | |
371 | ||
372 | void tom_render_16bpp_cry_scanline(uint32_t * backbuffer); | |
373 | void tom_render_24bpp_scanline(uint32_t * backbuffer); | |
374 | void tom_render_16bpp_direct_scanline(uint32_t * backbuffer); | |
375 | void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer); | |
376 | void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer); | |
377 | ||
378 | //render_xxx_scanline_fn * scanline_render_normal[] = | |
379 | render_xxx_scanline_fn * scanline_render[] = | |
380 | { | |
381 | tom_render_16bpp_cry_scanline, | |
382 | tom_render_24bpp_scanline, | |
383 | tom_render_16bpp_direct_scanline, | |
384 | tom_render_16bpp_rgb_scanline, | |
385 | tom_render_16bpp_cry_rgb_mix_scanline, | |
386 | tom_render_24bpp_scanline, | |
387 | tom_render_16bpp_direct_scanline, | |
388 | tom_render_16bpp_rgb_scanline | |
389 | }; | |
390 | ||
391 | // Screen info for various games [PAL]... | |
392 | /* | |
393 | BIOS | |
394 | TOM: Horizontal Period written by M68K: 850 (+1*2 = 1702) | |
395 | TOM: Horizontal Blank Begin written by M68K: 1711 | |
396 | TOM: Horizontal Blank End written by M68K: 158 | |
397 | TOM: Horizontal Display End written by M68K: 1696 | |
398 | TOM: Horizontal Display Begin 1 written by M68K: 166 | |
399 | TOM: Vertical Period written by M68K: 623 (non-interlaced) | |
400 | TOM: Vertical Blank End written by M68K: 34 | |
401 | TOM: Vertical Display Begin written by M68K: 46 | |
402 | TOM: Vertical Display End written by M68K: 526 | |
403 | TOM: Vertical Blank Begin written by M68K: 600 | |
404 | TOM: Vertical Sync written by M68K: 618 | |
405 | TOM: Horizontal Display End written by M68K: 1665 | |
406 | TOM: Horizontal Display Begin 1 written by M68K: 203 | |
407 | TOM: Vertical Display Begin written by M68K: 38 | |
408 | TOM: Vertical Display End written by M68K: 518 | |
409 | TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 151) | |
410 | TOM: Horizontal Display End written by M68K: 1713 | |
411 | TOM: Horizontal Display Begin 1 written by M68K: 157 | |
412 | TOM: Vertical Display Begin written by M68K: 35 | |
413 | TOM: Vertical Display End written by M68K: 2047 | |
414 | Horizontal range: 157 - 1713 (width: 1557 / 4 = 389.25, / 5 = 315.4) | |
415 | ||
416 | Asteroid | |
417 | TOM: Horizontal Period written by M68K: 845 (+1*2 = 1692) | |
418 | TOM: Horizontal Blank Begin written by M68K: 1700 | |
419 | TOM: Horizontal Blank End written by M68K: 122 | |
420 | TOM: Horizontal Display End written by M68K: 1600 | |
421 | TOM: Horizontal Display Begin 1 written by M68K: 268 | |
422 | TOM: Vertical Period written by M68K: 523 (non-interlaced) | |
423 | TOM: Vertical Blank End written by M68K: 40 | |
424 | TOM: Vertical Display Begin written by M68K: 44 | |
425 | TOM: Vertical Display End written by M68K: 492 | |
426 | TOM: Vertical Blank Begin written by M68K: 532 | |
427 | TOM: Vertical Sync written by M68K: 513 | |
428 | TOM: Video Mode written by M68K: 04C7. PWIDTH = 3, MODE = 16 BPP RGB, flags: BGEN (VC = 461) | |
429 | ||
430 | Rayman | |
431 | TOM: Horizontal Display End written by M68K: 1713 | |
432 | TOM: Horizontal Display Begin 1 written by M68K: 157 | |
433 | TOM: Vertical Display Begin written by M68K: 35 | |
434 | TOM: Vertical Display End written by M68K: 2047 | |
435 | TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 89) | |
436 | TOM: Horizontal Display Begin 1 written by M68K: 208 | |
437 | TOM: Horizontal Display End written by M68K: 1662 | |
438 | TOM: Vertical Display Begin written by M68K: 100 | |
439 | TOM: Vertical Display End written by M68K: 2047 | |
440 | TOM: Video Mode written by M68K: 07C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN VARMOD (VC = 205) | |
441 | Horizontal range: 208 - 1662 (width: 1455 / 4 = 363.5) | |
442 | ||
443 | Alien vs Predator | |
444 | TOM: Vertical Display Begin written by M68K: 96 | |
445 | TOM: Vertical Display End written by M68K: 2047 | |
446 | TOM: Horizontal Display Begin 1 written by M68K: 239 | |
447 | TOM: Horizontal Display End written by M68K: 1692 | |
448 | TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 378) | |
449 | TOM: Vertical Display Begin written by M68K: 44 | |
450 | TOM: Vertical Display End written by M68K: 2047 | |
451 | TOM: Horizontal Display Begin 1 written by M68K: 239 | |
452 | TOM: Horizontal Display End written by M68K: 1692 | |
453 | TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 559) | |
454 | TOM: Vertical Display Begin written by M68K: 84 | |
455 | TOM: Vertical Display End written by M68K: 2047 | |
456 | TOM: Horizontal Display Begin 1 written by M68K: 239 | |
457 | TOM: Horizontal Display End written by M68K: 1692 | |
458 | TOM: Vertical Display Begin written by M68K: 44 | |
459 | TOM: Vertical Display End written by M68K: 2047 | |
460 | TOM: Horizontal Display Begin 1 written by M68K: 239 | |
461 | TOM: Horizontal Display End written by M68K: 1692 | |
462 | Horizontal range: 239 - 1692 (width: 1454 / 4 = 363.5) | |
463 | ||
464 | */ | |
465 | ||
466 | // Screen info for various games [NTSC]... | |
467 | /* | |
468 | Doom | |
469 | TOM: Horizontal Display End written by M68K: 1727 | |
470 | TOM: Horizontal Display Begin 1 written by M68K: 123 | |
471 | TOM: Vertical Display Begin written by M68K: 25 | |
472 | TOM: Vertical Display End written by M68K: 2047 | |
473 | TOM: Video Mode written by M68K: 0EC1. PWIDTH = 8, MODE = 16 BPP CRY, flags: BGEN (VC = 5) | |
474 | Also does PWIDTH = 4... | |
475 | Vertical resolution: 238 lines | |
476 | ||
477 | Rayman | |
478 | TOM: Horizontal Display End written by M68K: 1727 | |
479 | TOM: Horizontal Display Begin 1 written by M68K: 123 | |
480 | TOM: Vertical Display Begin written by M68K: 25 | |
481 | TOM: Vertical Display End written by M68K: 2047 | |
482 | TOM: Vertical Interrupt written by M68K: 507 | |
483 | TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 92) | |
484 | TOM: Horizontal Display Begin 1 written by M68K: 208 | |
485 | TOM: Horizontal Display End written by M68K: 1670 | |
486 | Display starts at 31, then 52! | |
487 | Vertical resolution: 238 lines | |
488 | ||
489 | Atari Karts | |
490 | TOM: Horizontal Display End written by M68K: 1727 | |
491 | TOM: Horizontal Display Begin 1 written by M68K: 123 | |
492 | TOM: Vertical Display Begin written by M68K: 25 | |
493 | TOM: Vertical Display End written by M68K: 2047 | |
494 | TOM: Video Mode written by GPU: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 4) | |
495 | TOM: Video Mode written by GPU: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 508) | |
496 | Display starts at 31 (PWIDTH = 4), 24 (PWIDTH = 5) | |
497 | ||
498 | Iron Soldier | |
499 | TOM: Vertical Interrupt written by M68K: 2047 | |
500 | TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 0) | |
501 | TOM: Horizontal Display End written by M68K: 1727 | |
502 | TOM: Horizontal Display Begin 1 written by M68K: 123 | |
503 | TOM: Vertical Display Begin written by M68K: 25 | |
504 | TOM: Vertical Display End written by M68K: 2047 | |
505 | TOM: Vertical Interrupt written by M68K: 507 | |
506 | TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 369) | |
507 | TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 510) | |
508 | TOM: Video Mode written by M68K: 06C3. PWIDTH = 4, MODE = 24 BPP RGB, flags: BGEN (VC = 510) | |
509 | Display starts at 31 | |
510 | Vertical resolution: 238 lines | |
511 | [Seems to be a problem between the horizontal positioning of the 16-bit CRY & 24-bit RGB] | |
512 | ||
513 | JagMania | |
514 | TOM: Horizontal Period written by M68K: 844 (+1*2 = 1690) | |
515 | TOM: Horizontal Blank Begin written by M68K: 1713 | |
516 | TOM: Horizontal Blank End written by M68K: 125 | |
517 | TOM: Horizontal Display End written by M68K: 1696 | |
518 | TOM: Horizontal Display Begin 1 written by M68K: 166 | |
519 | TOM: Vertical Period written by M68K: 523 (non-interlaced) | |
520 | TOM: Vertical Blank End written by M68K: 24 | |
521 | TOM: Vertical Display Begin written by M68K: 46 | |
522 | TOM: Vertical Display End written by M68K: 496 | |
523 | TOM: Vertical Blank Begin written by M68K: 500 | |
524 | TOM: Vertical Sync written by M68K: 517 | |
525 | TOM: Vertical Interrupt written by M68K: 497 | |
526 | TOM: Video Mode written by M68K: 04C1. PWIDTH = 3, MODE = 16 BPP CRY, flags: BGEN (VC = 270) | |
527 | Display starts at 55 | |
528 | ||
529 | Double Dragon V | |
530 | TOM: Horizontal Display End written by M68K: 1727 | |
531 | TOM: Horizontal Display Begin 1 written by M68K: 123 | |
532 | TOM: Vertical Display Begin written by M68K: 25 | |
533 | TOM: Vertical Display End written by M68K: 2047 | |
534 | TOM: Vertical Interrupt written by M68K: 507 | |
535 | TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 9) | |
536 | ||
537 | Dino Dudes | |
538 | TOM: Horizontal Display End written by M68K: 1823 | |
539 | TOM: Horizontal Display Begin 1 written by M68K: 45 | |
540 | TOM: Vertical Display Begin written by M68K: 40 | |
541 | TOM: Vertical Display End written by M68K: 2047 | |
542 | TOM: Vertical Interrupt written by M68K: 491 | |
543 | TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 398) | |
544 | Display starts at 11 (123 - 45 = 78, 78 / 4 = 19 pixels to skip) | |
545 | Width is 417, so maybe width of 379 would be good (starting at 123, ending at 1639) | |
546 | Vertical resolution: 238 lines | |
547 | ||
548 | Flashback | |
549 | TOM: Horizontal Display End written by M68K: 1727 | |
550 | TOM: Horizontal Display Begin 1 written by M68K: 188 | |
551 | TOM: Vertical Display Begin written by M68K: 1 | |
552 | TOM: Vertical Display End written by M68K: 2047 | |
553 | TOM: Vertical Interrupt written by M68K: 483 | |
554 | TOM: Video Mode written by M68K: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 99) | |
555 | Width would be 303 with above scheme, but border width would be 13 pixels | |
556 | ||
557 | Trevor McFur | |
558 | Vertical resolution: 238 lines | |
559 | */ | |
560 | ||
561 | // 16-bit color lookup tables | |
562 | uint32_t RGB16ToRGB32[0x10000]; | |
563 | uint32_t CRY16ToRGB32[0x10000]; | |
564 | uint32_t MIX16ToRGB32[0x10000]; | |
565 | ||
566 | ||
567 | #ifdef _MSC_VER | |
568 | #pragma message("Warning: This is not endian-safe. !!! FIX !!!") | |
569 | #else | |
570 | #warning "This is not endian-safe. !!! FIX !!!" | |
571 | #endif // _MSC_VER | |
572 | void TOMFillLookupTables(void) | |
573 | { | |
574 | // NOTE: Jaguar 16-bit (non-CRY) color is RBG 556 like so: | |
575 | // RRRR RBBB BBGG GGGG | |
576 | for(uint32_t i=0; i<0x10000; i++) | |
577 | RGB16ToRGB32[i] = 0x000000FF | |
578 | | ((i & 0xF800) << 16) // Red | |
579 | | ((i & 0x003F) << 18) // Green | |
580 | | ((i & 0x07C0) << 5); // Blue | |
581 | ||
582 | for(uint32_t i=0; i<0x10000; i++) | |
583 | { | |
584 | uint32_t cyan = (i & 0xF000) >> 12, | |
585 | red = (i & 0x0F00) >> 8, | |
586 | intensity = (i & 0x00FF); | |
587 | ||
588 | uint32_t r = (((uint32_t)redcv[cyan][red]) * intensity) >> 8, | |
589 | g = (((uint32_t)greencv[cyan][red]) * intensity) >> 8, | |
590 | b = (((uint32_t)bluecv[cyan][red]) * intensity) >> 8; | |
591 | ||
592 | CRY16ToRGB32[i] = 0x000000FF | (r << 24) | (g << 16) | (b << 8); | |
593 | MIX16ToRGB32[i] = (i & 0x01 ? RGB16ToRGB32[i] : CRY16ToRGB32[i]); | |
594 | } | |
595 | } | |
596 | ||
597 | ||
598 | void TOMSetPendingJERRYInt(void) | |
599 | { | |
600 | tom_jerry_int_pending = 1; | |
601 | } | |
602 | ||
603 | ||
604 | void TOMSetPendingTimerInt(void) | |
605 | { | |
606 | tom_timer_int_pending = 1; | |
607 | } | |
608 | ||
609 | ||
610 | void TOMSetPendingObjectInt(void) | |
611 | { | |
612 | tom_object_int_pending = 1; | |
613 | } | |
614 | ||
615 | ||
616 | void TOMSetPendingGPUInt(void) | |
617 | { | |
618 | tom_gpu_int_pending = 1; | |
619 | } | |
620 | ||
621 | ||
622 | void TOMSetPendingVideoInt(void) | |
623 | { | |
624 | tom_video_int_pending = 1; | |
625 | } | |
626 | ||
627 | ||
628 | uint8_t * TOMGetRamPointer(void) | |
629 | { | |
630 | return tomRam8; | |
631 | } | |
632 | ||
633 | ||
634 | uint8_t TOMGetVideoMode(void) | |
635 | { | |
636 | uint16_t vmode = GET16(tomRam8, VMODE); | |
637 | return ((vmode & VARMOD) >> 6) | ((vmode & MODE) >> 1); | |
638 | } | |
639 | ||
640 | ||
641 | //Used in only one place (and for debug purposes): OBJECTP.CPP | |
642 | #ifdef _MSC_VER | |
643 | #pragma message("Warning: Used in only one place (and for debug purposes): OBJECTP.CPP !!! FIX !!!") | |
644 | #else | |
645 | #warning "Used in only one place (and for debug purposes): OBJECTP.CPP !!! FIX !!!" | |
646 | #endif // _MSC_VER | |
647 | uint16_t TOMGetVDB(void) | |
648 | { | |
649 | return GET16(tomRam8, VDB); | |
650 | } | |
651 | ||
652 | ||
653 | uint16_t TOMGetHC(void) | |
654 | { | |
655 | return GET16(tomRam8, HC); | |
656 | } | |
657 | ||
658 | ||
659 | uint16_t TOMGetVP(void) | |
660 | { | |
661 | return GET16(tomRam8, VP); | |
662 | } | |
663 | ||
664 | ||
665 | uint16_t TOMGetMEMCON1(void) | |
666 | { | |
667 | return GET16(tomRam8, MEMCON1); | |
668 | } | |
669 | ||
670 | ||
671 | #define LEFT_BG_FIX | |
672 | // | |
673 | // 16 BPP CRY/RGB mixed mode rendering | |
674 | // | |
675 | void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer) | |
676 | { | |
677 | //CHANGED TO 32BPP RENDERING | |
678 | uint16_t width = tomWidth; | |
679 | uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; | |
680 | ||
681 | //New stuff--restrict our drawing... | |
682 | uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; | |
683 | //NOTE: May have to check HDB2 as well! | |
684 | // Get start position in HC ticks | |
685 | int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); | |
686 | // Convert to pixels | |
687 | startPos /= pwidth; | |
688 | ||
689 | if (startPos < 0) | |
690 | // This is x2 because current_line_buffer is uint8_t & we're in a 16bpp mode | |
691 | current_line_buffer += 2 * -startPos; | |
692 | else | |
693 | //This case doesn't properly handle the "start on the right side of virtual screen" case | |
694 | //Dunno why--looks Ok... | |
695 | //What *is* for sure wrong is that it doesn't copy the linebuffer's BG pixels... [FIXED NOW] | |
696 | //This should likely be 4 instead of 2 (?--not sure) | |
697 | // Actually, there should be NO multiplier, as startPos is expressed in PIXELS | |
698 | // and so is the backbuffer. | |
699 | #ifdef LEFT_BG_FIX | |
700 | { | |
701 | uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; | |
702 | uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8); | |
703 | ||
704 | for(int16_t i=0; i<startPos; i++) | |
705 | *backbuffer++ = pixel; | |
706 | ||
707 | width -= startPos; | |
708 | } | |
709 | #else | |
710 | backbuffer += 2 * startPos, width -= startPos; | |
711 | #endif | |
712 | ||
713 | while (width) | |
714 | { | |
715 | uint16_t color = (*current_line_buffer++) << 8; | |
716 | color |= *current_line_buffer++; | |
717 | *backbuffer++ = MIX16ToRGB32[color]; | |
718 | width--; | |
719 | } | |
720 | } | |
721 | ||
722 | ||
723 | // | |
724 | // 16 BPP CRY mode rendering | |
725 | // | |
726 | void tom_render_16bpp_cry_scanline(uint32_t * backbuffer) | |
727 | { | |
728 | //CHANGED TO 32BPP RENDERING | |
729 | uint16_t width = tomWidth; | |
730 | uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; | |
731 | ||
732 | //New stuff--restrict our drawing... | |
733 | uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; | |
734 | //NOTE: May have to check HDB2 as well! | |
735 | int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);// Get start position in HC ticks | |
736 | startPos /= pwidth; | |
737 | ||
738 | if (startPos < 0) | |
739 | current_line_buffer += 2 * -startPos; | |
740 | else | |
741 | #ifdef LEFT_BG_FIX | |
742 | { | |
743 | uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; | |
744 | uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8); | |
745 | ||
746 | for(int16_t i=0; i<startPos; i++) | |
747 | *backbuffer++ = pixel; | |
748 | ||
749 | width -= startPos; | |
750 | } | |
751 | #else | |
752 | //This should likely be 4 instead of 2 (?--not sure) | |
753 | backbuffer += 2 * startPos, width -= startPos; | |
754 | #endif | |
755 | ||
756 | while (width) | |
757 | { | |
758 | uint16_t color = (*current_line_buffer++) << 8; | |
759 | color |= *current_line_buffer++; | |
760 | *backbuffer++ = CRY16ToRGB32[color]; | |
761 | width--; | |
762 | } | |
763 | } | |
764 | ||
765 | ||
766 | // | |
767 | // 24 BPP mode rendering | |
768 | // | |
769 | void tom_render_24bpp_scanline(uint32_t * backbuffer) | |
770 | { | |
771 | //CHANGED TO 32BPP RENDERING | |
772 | uint16_t width = tomWidth; | |
773 | uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; | |
774 | ||
775 | //New stuff--restrict our drawing... | |
776 | uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; | |
777 | //NOTE: May have to check HDB2 as well! | |
778 | int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks | |
779 | startPos /= pwidth; | |
780 | ||
781 | if (startPos < 0) | |
782 | current_line_buffer += 4 * -startPos; | |
783 | else | |
784 | #ifdef LEFT_BG_FIX | |
785 | { | |
786 | uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; | |
787 | uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8); | |
788 | ||
789 | for(int16_t i=0; i<startPos; i++) | |
790 | *backbuffer++ = pixel; | |
791 | ||
792 | width -= startPos; | |
793 | } | |
794 | #else | |
795 | //This should likely be 4 instead of 2 (?--not sure) | |
796 | backbuffer += 2 * startPos, width -= startPos; | |
797 | #endif | |
798 | ||
799 | while (width) | |
800 | { | |
801 | uint32_t g = *current_line_buffer++; | |
802 | uint32_t r = *current_line_buffer++; | |
803 | current_line_buffer++; | |
804 | uint32_t b = *current_line_buffer++; | |
805 | *backbuffer++ = 0x000000FF | (r << 24) | (g << 16) | (b << 8); | |
806 | width--; | |
807 | } | |
808 | } | |
809 | ||
810 | ||
811 | // Seems to me that this is NOT a valid mode--the JTRM seems to imply that you | |
812 | // would need extra hardware outside of the Jaguar console to support this! | |
813 | // | |
814 | // 16 BPP direct mode rendering | |
815 | // | |
816 | void tom_render_16bpp_direct_scanline(uint32_t * backbuffer) | |
817 | { | |
818 | uint16_t width = tomWidth; | |
819 | uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; | |
820 | ||
821 | while (width) | |
822 | { | |
823 | uint16_t color = (*current_line_buffer++) << 8; | |
824 | color |= *current_line_buffer++; | |
825 | *backbuffer++ = color >> 1; | |
826 | width--; | |
827 | } | |
828 | } | |
829 | ||
830 | ||
831 | // | |
832 | // 16 BPP RGB mode rendering | |
833 | // | |
834 | void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer) | |
835 | { | |
836 | //CHANGED TO 32BPP RENDERING | |
837 | // 16 BPP RGB: 0-5 green, 6-10 blue, 11-15 red | |
838 | ||
839 | uint16_t width = tomWidth; | |
840 | uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; | |
841 | ||
842 | //New stuff--restrict our drawing... | |
843 | uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; | |
844 | //NOTE: May have to check HDB2 as well! | |
845 | int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks | |
846 | startPos /= pwidth; | |
847 | ||
848 | if (startPos < 0) | |
849 | current_line_buffer += 2 * -startPos; | |
850 | else | |
851 | #ifdef LEFT_BG_FIX | |
852 | { | |
853 | uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; | |
854 | uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8); | |
855 | ||
856 | for(int16_t i=0; i<startPos; i++) | |
857 | *backbuffer++ = pixel; | |
858 | ||
859 | width -= startPos; | |
860 | } | |
861 | #else | |
862 | //This should likely be 4 instead of 2 (?--not sure) | |
863 | backbuffer += 2 * startPos, width -= startPos; | |
864 | #endif | |
865 | ||
866 | while (width) | |
867 | { | |
868 | uint32_t color = (*current_line_buffer++) << 8; | |
869 | color |= *current_line_buffer++; | |
870 | *backbuffer++ = RGB16ToRGB32[color]; | |
871 | width--; | |
872 | } | |
873 | } | |
874 | ||
875 | ||
876 | // | |
877 | // Process a single halfline | |
878 | // | |
879 | void TOMExecHalfline(uint16_t halfline, bool render) | |
880 | { | |
881 | uint16_t field2 = halfline & 0x0800; | |
882 | halfline &= 0x07FF; | |
883 | bool inActiveDisplayArea = true; | |
884 | ||
885 | // Execute OP only on even halflines (skip higher resolutions for now...) | |
886 | if (halfline & 0x01) | |
887 | return; | |
888 | ||
889 | //Hm, it seems that the OP needs to execute from zero, so let's try it: | |
890 | // And it works! But need to do some optimizations in the OP to keep it from | |
891 | // attempting to do a scanline render in the non-display area... [DONE] | |
892 | //this seems to cause a regression in certain games, like rayman | |
893 | //which means I have to dig thru the asic nets to see what's wrong... | |
894 | /* | |
895 | No, the OP doesn't start until VDB, that much is certain. The thing is, VDB is | |
896 | the HALF line that the OP starts on--which means that it needs to start at | |
897 | VDB / 2!!! | |
898 | ||
899 | Hrm, doesn't seem to be enough, though it should be... still sticks for 20 | |
900 | frames. | |
901 | ||
902 | What triggers this is writing $FFFF to VDE. This causes the OP start signal in VID to latch on, which in effect sets VDB to zero. So that much is correct. But | |
903 | the thing with Rayman is that it shouldn't cause the graphical glitches seen | |
904 | there, so still have to investigate what's going on there. By all rights, it | |
905 | shouldn't glitch because: | |
906 | ||
907 | 00006C00: 0000000D 82008F73 (BRANCH) YPOS=494, CC=">", link=$00006C10 | |
908 | 00006C08: 000003FF 00008173 (BRANCH) YPOS=46, CC=">", link=$001FF800 | |
909 | 00006C10: 00000000 0000000C (STOP) | |
910 | 001FF800: 12FC2BFF 02380000 (BITMAP) | |
911 | 00008004 8180CFF1 | |
912 | ||
913 | Even if the OP is running all the time, the link should tell it to stop at the | |
914 | right place (which it seems to do). But we still get glitchy screen. | |
915 | ||
916 | Seems the glitchy screen went away... Maybe the GPU alignment fixes fixed it??? | |
917 | Just need to add the proper checking here then. | |
918 | ||
919 | Some numbers, courtesy of the Jaguar BIOS: | |
920 | // NTSC: | |
921 | VP, 523 // Vertical Period (1-based; in this case VP = 524) | |
922 | VBE, 24 // Vertical Blank End | |
923 | VDB, 38 // Vertical Display Begin | |
924 | VDE, 518 // Vertical Display End | |
925 | VBB, 500 // Vertical Blank Begin | |
926 | VS, 517 // Vertical Sync | |
927 | ||
928 | // PAL Jaguar | |
929 | VP, 623 // Vertical Period (1-based; in this case VP = 624) | |
930 | VBE, 34 // Vertical Blank End | |
931 | VDB, 38 // Vertical Display Begin | |
932 | VDE, 518 // Vertical Display End | |
933 | VBB, 600 // Vertical Blank Begin | |
934 | VS, 618 // Vertical Sync | |
935 | ||
936 | Numbers for KM, NTSC: | |
937 | KM: (Note that with VDE <= 507, the OP starts at VDB as expected) | |
938 | TOM: Vertical Display Begin written by M68K: 41 | |
939 | TOM: Vertical Display End written by M68K: 2047 | |
940 | TOM: Vertical Interrupt written by M68K: 491 | |
941 | */ | |
942 | ||
943 | // Initial values that "well behaved" programs use | |
944 | uint16_t startingHalfline = GET16(tomRam8, VDB); | |
945 | uint16_t endingHalfline = GET16(tomRam8, VDE); | |
946 | ||
947 | // Simulate the OP start bug here! | |
948 | // Really, this value is somewhere around 507 for an NTSC Jaguar. But this | |
949 | // should work in a majority of cases, at least until we can figure it out | |
950 | // properly. | |
951 | if (endingHalfline > GET16(tomRam8, VP)) | |
952 | startingHalfline = 0; | |
953 | ||
954 | if ((halfline >= startingHalfline) && (halfline < endingHalfline)) | |
955 | { | |
956 | if (render) | |
957 | { | |
958 | uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; | |
959 | uint8_t bgHI = tomRam8[BG], bgLO = tomRam8[BG + 1]; | |
960 | ||
961 | // Clear line buffer with BG | |
962 | if (GET16(tomRam8, VMODE) & BGEN) // && (CRY or RGB16)... | |
963 | for(uint32_t i=0; i<720; i++) | |
964 | *current_line_buffer++ = bgHI, *current_line_buffer++ = bgLO; | |
965 | ||
966 | OPProcessList(halfline, render); | |
967 | } | |
968 | } | |
969 | else | |
970 | inActiveDisplayArea = false; | |
971 | ||
972 | // Take PAL into account... | |
973 | ||
974 | uint16_t topVisible = (vjs.hardwareTypeNTSC ? TOP_VISIBLE_VC : TOP_VISIBLE_VC_PAL), | |
975 | bottomVisible = (vjs.hardwareTypeNTSC ? BOTTOM_VISIBLE_VC : BOTTOM_VISIBLE_VC_PAL); | |
976 | uint32_t * TOMCurrentLine = 0; | |
977 | ||
978 | // Bit 0 in VP is interlace flag. 0 = interlace, 1 = non-interlaced | |
979 | if (tomRam8[VP + 1] & 0x01) | |
980 | TOMCurrentLine = &(screenBuffer[((halfline - topVisible) / 2) * screenPitch]);//non-interlace | |
981 | else | |
982 | TOMCurrentLine = &(screenBuffer[(((halfline - topVisible) / 2) * screenPitch * 2) + (field2 ? 0 : screenPitch)]);//interlace | |
983 | ||
984 | // Here's our virtualized scanline code... | |
985 | ||
986 | if ((halfline >= topVisible) && (halfline < bottomVisible)) | |
987 | { | |
988 | if (inActiveDisplayArea) | |
989 | { | |
990 | //NOTE: The following doesn't put BORDER color on the sides... !!! FIX !!! | |
991 | #ifdef _MSC_VER | |
992 | #pragma message("Warning: The following doesn't put BORDER color on the sides... !!! FIX !!!") | |
993 | #else | |
994 | #warning "The following doesn't put BORDER color on the sides... !!! FIX !!!" | |
995 | #endif // _MSC_VER | |
996 | if (vjs.renderType == RT_NORMAL) | |
997 | { | |
998 | scanline_render[TOMGetVideoMode()](TOMCurrentLine); | |
999 | } | |
1000 | else | |
1001 | { | |
1002 | // TV type render | |
1003 | /* | |
1004 | tom_render_16bpp_cry_scanline, | |
1005 | tom_render_24bpp_scanline, | |
1006 | tom_render_16bpp_direct_scanline, | |
1007 | tom_render_16bpp_rgb_scanline, | |
1008 | tom_render_16bpp_cry_rgb_mix_scanline, | |
1009 | tom_render_24bpp_scanline, | |
1010 | tom_render_16bpp_direct_scanline, | |
1011 | tom_render_16bpp_rgb_scanline | |
1012 | #define VMODE 0x28 | |
1013 | #define MODE 0x0006 // Line buffer to video generator mode | |
1014 | #define VARMOD 0x0100 // Mixed CRY/RGB16 mode (only works in MODE 0!) | |
1015 | */ | |
1016 | uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; | |
1017 | uint8_t mode = ((GET16(tomRam8, VMODE) & MODE) >> 1); | |
1018 | bool varmod = GET16(tomRam8, VMODE) & VARMOD; | |
1019 | //The video texture line buffer ranges from 0 to 1279, with its left edge | |
1020 | //starting at LEFT_VISIBLE_HC. So, we need to start writing into the backbuffer | |
1021 | //at HDB1, using pwidth as our scaling factor. The way it generates its image | |
1022 | //on a real TV! | |
1023 | ||
1024 | //So, for example, if HDB1 is less than LEFT_VISIBLE_HC, then we have to figure | |
1025 | //out where in the VTLB that we start writing pixels from the Jaguar line | |
1026 | //buffer (VTLB start=0, JLB=something). | |
1027 | #if 0 | |
1028 | // | |
1029 | // 24 BPP mode rendering | |
1030 | // | |
1031 | void tom_render_24bpp_scanline(uint32_t * backbuffer) | |
1032 | { | |
1033 | //CHANGED TO 32BPP RENDERING | |
1034 | uint16_t width = tomWidth; | |
1035 | uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800]; | |
1036 | ||
1037 | //New stuff--restrict our drawing... | |
1038 | uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; | |
1039 | //NOTE: May have to check HDB2 as well! | |
1040 | int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks | |
1041 | startPos /= pwidth; | |
1042 | if (startPos < 0) | |
1043 | current_line_buffer += 4 * -startPos; | |
1044 | else | |
1045 | //This should likely be 4 instead of 2 (?--not sure) | |
1046 | backbuffer += 2 * startPos, width -= startPos; | |
1047 | ||
1048 | while (width) | |
1049 | { | |
1050 | uint32_t g = *current_line_buffer++; | |
1051 | uint32_t r = *current_line_buffer++; | |
1052 | current_line_buffer++; | |
1053 | uint32_t b = *current_line_buffer++; | |
1054 | *backbuffer++ = 0xFF000000 | (b << 16) | (g << 8) | r; | |
1055 | width--; | |
1056 | } | |
1057 | } | |
1058 | #endif | |
1059 | ||
1060 | } | |
1061 | } | |
1062 | else | |
1063 | { | |
1064 | // If outside of VDB & VDE, then display the border color | |
1065 | uint32_t * currentLineBuffer = TOMCurrentLine; | |
1066 | uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1]; | |
1067 | //Hm. uint32_t pixel = 0xFF000000 | (b << 16) | (g << 8) | r; | |
1068 | uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8); | |
1069 | ||
1070 | for(uint32_t i=0; i<tomWidth; i++) | |
1071 | *currentLineBuffer++ = pixel; | |
1072 | } | |
1073 | } | |
1074 | } | |
1075 | ||
1076 | ||
1077 | // | |
1078 | // TOM initialization | |
1079 | // | |
1080 | void TOMInit(void) | |
1081 | { | |
1082 | TOMFillLookupTables(); | |
1083 | OPInit(); | |
1084 | BlitterInit(); | |
1085 | TOMReset(); | |
1086 | } | |
1087 | ||
1088 | ||
1089 | void TOMDone(void) | |
1090 | { | |
1091 | TOMDumpIORegistersToLog(); | |
1092 | OPDone(); | |
1093 | BlitterDone(); | |
1094 | WriteLog("TOM: Resolution %i x %i %s\n", TOMGetVideoModeWidth(), | |
1095 | TOMGetVideoModeHeight(), videoMode_to_str[TOMGetVideoMode()]); | |
1096 | } | |
1097 | ||
1098 | ||
1099 | uint32_t TOMGetVideoModeWidth(void) | |
1100 | { | |
1101 | // Note that the following PWIDTH values have the following pixel aspect | |
1102 | // ratios: | |
1103 | // PWIDTH = 1 -> 0.25:1 (1:4) pixels (X:Y ratio) | |
1104 | // PWIDTH = 2 -> 0.50:1 (1:2) pixels | |
1105 | // PWIDTH = 3 -> 0.75:1 (3:4) pixels | |
1106 | // PWIDTH = 4 -> 1.00:1 (1:1) pixels | |
1107 | // PWIDTH = 5 -> 1.25:1 (5:4) pixels | |
1108 | // PWIDTH = 6 -> 1.50:1 (3:2) pixels | |
1109 | // PWIDTH = 7 -> 1.75:1 (7:4) pixels | |
1110 | // PWIDTH = 8 -> 2.00:1 (2:1) pixels | |
1111 | ||
1112 | // Also note that the JTRM says that PWIDTH of 4 gives pixels that are | |
1113 | // "about" square--this implies that the other modes have pixels that are | |
1114 | // *not* square (and they aren't)! | |
1115 | // Also, I seriously doubt that you will see any games that use PWIDTH = 1! | |
1116 | ||
1117 | // To make it easier to make a quasi-fixed display size, we restrict the | |
1118 | // viewing area to an arbitrary range of the Horizontal Count. | |
1119 | uint16_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1; | |
1120 | return (vjs.hardwareTypeNTSC ? RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC : RIGHT_VISIBLE_HC_PAL - LEFT_VISIBLE_HC_PAL) / pwidth; | |
1121 | } | |
1122 | ||
1123 | ||
1124 | uint32_t TOMGetVideoModeHeight(void) | |
1125 | { | |
1126 | // Set virtual screen height to 240 (NTSC) or 256 (PAL) lines... | |
1127 | return (vjs.hardwareTypeNTSC ? 240 : 256); | |
1128 | } | |
1129 | ||
1130 | ||
1131 | // | |
1132 | // TOM reset code | |
1133 | // Now PAL friendly! | |
1134 | // | |
1135 | /* | |
1136 | The values in TOMReset come from the Jaguar BIOS. | |
1137 | These values are from BJL: | |
1138 | ||
1139 | NSTC: | |
1140 | CLK2 181 | |
1141 | HP 844 | |
1142 | HBB 1713 | |
1143 | HBE 125 | |
1144 | HS 1741 | |
1145 | HVS 651 | |
1146 | HEQ 784 | |
1147 | HDE 1696 | |
1148 | HDB1 166 | |
1149 | HDB2 166 | |
1150 | VP 523 | |
1151 | VEE 6 | |
1152 | VBE 24 | |
1153 | VDB 46 | |
1154 | VDE 496 | |
1155 | VBB 500 | |
1156 | VEB 511 | |
1157 | VS 517 | |
1158 | ||
1159 | PAL: | |
1160 | CLK2 226 | |
1161 | HP 850 | |
1162 | HBB 1711 | |
1163 | HBE 158 | |
1164 | HS 1749 | |
1165 | HVS 601 | |
1166 | HEQ 787 | |
1167 | HDE 1696 | |
1168 | HDB1 166 | |
1169 | HDB2 166 | |
1170 | VP 625 | |
1171 | VEE 6 | |
1172 | VBE 34 | |
1173 | VDB 46 | |
1174 | VDE 429 | |
1175 | VBB 600 | |
1176 | VEB 613 | |
1177 | VS 618 | |
1178 | */ | |
1179 | void TOMReset(void) | |
1180 | { | |
1181 | OPReset(); | |
1182 | BlitterReset(); | |
1183 | memset(tomRam8, 0x00, 0x4000); | |
1184 | ||
1185 | if (vjs.hardwareTypeNTSC) | |
1186 | { | |
1187 | SET16(tomRam8, MEMCON1, 0x1861); | |
1188 | // SET16(tomRam8, MEMCON1, 0x1865);//Bunch of BS | |
1189 | SET16(tomRam8, MEMCON2, 0x35CC); | |
1190 | SET16(tomRam8, HP, 844); // Horizontal Period (1-based; HP=845) | |
1191 | SET16(tomRam8, HBB, 1713); // Horizontal Blank Begin | |
1192 | SET16(tomRam8, HBE, 125); // Horizontal Blank End | |
1193 | SET16(tomRam8, HDE, 1665); // Horizontal Display End | |
1194 | SET16(tomRam8, HDB1, 203); // Horizontal Display Begin 1 | |
1195 | SET16(tomRam8, VP, 523); // Vertical Period (1-based; in this case VP = 524) | |
1196 | SET16(tomRam8, VBE, 24); // Vertical Blank End | |
1197 | SET16(tomRam8, VDB, 38); // Vertical Display Begin | |
1198 | SET16(tomRam8, VDE, 518); // Vertical Display End | |
1199 | SET16(tomRam8, VBB, 500); // Vertical Blank Begin | |
1200 | SET16(tomRam8, VS, 517); // Vertical Sync | |
1201 | SET16(tomRam8, VMODE, 0x06C1); | |
1202 | } | |
1203 | else // PAL Jaguar | |
1204 | { | |
1205 | SET16(tomRam8, MEMCON1, 0x1861); | |
1206 | SET16(tomRam8, MEMCON2, 0x35CC); | |
1207 | SET16(tomRam8, HP, 850); // Horizontal Period | |
1208 | SET16(tomRam8, HBB, 1711); // Horizontal Blank Begin | |
1209 | SET16(tomRam8, HBE, 158); // Horizontal Blank End | |
1210 | SET16(tomRam8, HDE, 1665); // Horizontal Display End | |
1211 | SET16(tomRam8, HDB1, 203); // Horizontal Display Begin 1 | |
1212 | SET16(tomRam8, VP, 623); // Vertical Period (1-based; in this case VP = 624) | |
1213 | SET16(tomRam8, VBE, 34); // Vertical Blank End | |
1214 | SET16(tomRam8, VDB, 38); // Vertical Display Begin | |
1215 | SET16(tomRam8, VDE, 518); // Vertical Display End | |
1216 | SET16(tomRam8, VBB, 600); // Vertical Blank Begin | |
1217 | SET16(tomRam8, VS, 618); // Vertical Sync | |
1218 | SET16(tomRam8, VMODE, 0x06C1); | |
1219 | } | |
1220 | ||
1221 | tomWidth = 0; | |
1222 | tomHeight = 0; | |
1223 | ||
1224 | tom_jerry_int_pending = 0; | |
1225 | tom_timer_int_pending = 0; | |
1226 | tom_object_int_pending = 0; | |
1227 | tom_gpu_int_pending = 0; | |
1228 | tom_video_int_pending = 0; | |
1229 | ||
1230 | tomTimerPrescaler = 0; // TOM PIT is disabled | |
1231 | tomTimerDivider = 0; | |
1232 | tomTimerCounter = 0; | |
1233 | } | |
1234 | ||
1235 | ||
1236 | // | |
1237 | // Dump all TOM register values to the log | |
1238 | // | |
1239 | void TOMDumpIORegistersToLog(void) | |
1240 | { | |
1241 | WriteLog("\n\n---------------------------------------------------------------------\n"); | |
1242 | WriteLog("TOM I/O Registers\n"); | |
1243 | WriteLog("---------------------------------------------------------------------\n"); | |
1244 | WriteLog("F000%02X (MEMCON1): $%04X\n", MEMCON1, GET16(tomRam8, MEMCON1)); | |
1245 | WriteLog("F000%02X (MEMCON2): $%04X\n", MEMCON2, GET16(tomRam8, MEMCON2)); | |
1246 | WriteLog("F000%02X (HC): $%04X\n", HC, GET16(tomRam8, HC)); | |
1247 | WriteLog("F000%02X (VC): $%04X\n", VC, GET16(tomRam8, VC)); | |
1248 | WriteLog("F000%02X (OLP): $%08X\n", OLP, GET32(tomRam8, OLP)); | |
1249 | WriteLog("F000%02X (OBF): $%04X\n", OBF, GET16(tomRam8, OBF)); | |
1250 | WriteLog("F000%02X (VMODE): $%04X\n", VMODE, GET16(tomRam8, VMODE)); | |
1251 | WriteLog("F000%02X (BORD1): $%04X\n", BORD1, GET16(tomRam8, BORD1)); | |
1252 | WriteLog("F000%02X (BORD2): $%04X\n", BORD2, GET16(tomRam8, BORD2)); | |
1253 | WriteLog("F000%02X (HP): $%04X\n", HP, GET16(tomRam8, HP)); | |
1254 | WriteLog("F000%02X (HBB): $%04X\n", HBB, GET16(tomRam8, HBB)); | |
1255 | WriteLog("F000%02X (HBE): $%04X\n", HBE, GET16(tomRam8, HBE)); | |
1256 | WriteLog("F000%02X (HS): $%04X\n", HS, GET16(tomRam8, HS)); | |
1257 | WriteLog("F000%02X (HVS): $%04X\n", HVS, GET16(tomRam8, HVS)); | |
1258 | WriteLog("F000%02X (HDB1): $%04X\n", HDB1, GET16(tomRam8, HDB1)); | |
1259 | WriteLog("F000%02X (HDB2): $%04X\n", HDB2, GET16(tomRam8, HDB2)); | |
1260 | WriteLog("F000%02X (HDE): $%04X\n", HDE, GET16(tomRam8, HDE)); | |
1261 | WriteLog("F000%02X (VP): $%04X\n", VP, GET16(tomRam8, VP)); | |
1262 | WriteLog("F000%02X (VBB): $%04X\n", VBB, GET16(tomRam8, VBB)); | |
1263 | WriteLog("F000%02X (VBE): $%04X\n", VBE, GET16(tomRam8, VBE)); | |
1264 | WriteLog("F000%02X (VS): $%04X\n", VS, GET16(tomRam8, VS)); | |
1265 | WriteLog("F000%02X (VDB): $%04X\n", VDB, GET16(tomRam8, VDB)); | |
1266 | WriteLog("F000%02X (VDE): $%04X\n", VDE, GET16(tomRam8, VDE)); | |
1267 | WriteLog("F000%02X (VEB): $%04X\n", VEB, GET16(tomRam8, VEB)); | |
1268 | WriteLog("F000%02X (VEE): $%04X\n", VEE, GET16(tomRam8, VEE)); | |
1269 | WriteLog("F000%02X (VI): $%04X\n", VI, GET16(tomRam8, VI)); | |
1270 | WriteLog("F000%02X (PIT0): $%04X\n", PIT0, GET16(tomRam8, PIT0)); | |
1271 | WriteLog("F000%02X (PIT1): $%04X\n", PIT1, GET16(tomRam8, PIT1)); | |
1272 | WriteLog("F000%02X (HEQ): $%04X\n", HEQ, GET16(tomRam8, HEQ)); | |
1273 | WriteLog("F000%02X (BG): $%04X\n", BG, GET16(tomRam8, BG)); | |
1274 | WriteLog("F000%02X (INT1): $%04X\n", INT1, GET16(tomRam8, INT1)); | |
1275 | WriteLog("F000%02X (INT2): $%04X\n", INT2, GET16(tomRam8, INT2)); | |
1276 | WriteLog("---------------------------------------------------------------------\n\n\n"); | |
1277 | } | |
1278 | ||
1279 | ||
1280 | // | |
1281 | // TOM byte access (read) | |
1282 | // | |
1283 | uint8_t TOMReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/) | |
1284 | { | |
1285 | //???Is this needed??? | |
1286 | // It seems so. Perhaps it's the +$8000 offset being written to (32-bit interface)? | |
1287 | // However, the 32-bit interface is WRITE ONLY, so that can't be it... | |
1288 | // Also, the 68K CANNOT make use of the 32-bit interface, since its bus width is only 16-bits... | |
1289 | // offset &= 0xFF3FFF; | |
1290 | ||
1291 | #ifdef TOM_DEBUG | |
1292 | WriteLog("TOM: Reading byte at %06X for %s\n", offset, whoName[who]); | |
1293 | #endif | |
1294 | ||
1295 | if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) | |
1296 | return GPUReadByte(offset, who); | |
1297 | else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000)) | |
1298 | return GPUReadByte(offset, who); | |
1299 | /* else if ((offset >= 0xF00010) && (offset < 0xF00028)) | |
1300 | return OPReadByte(offset, who);*/ | |
1301 | else if ((offset >= 0xF02200) && (offset < 0xF022A0)) | |
1302 | return BlitterReadByte(offset, who); | |
1303 | else if (offset == 0xF00050) | |
1304 | return tomTimerPrescaler >> 8; | |
1305 | else if (offset == 0xF00051) | |
1306 | return tomTimerPrescaler & 0xFF; | |
1307 | else if (offset == 0xF00052) | |
1308 | return tomTimerDivider >> 8; | |
1309 | else if (offset == 0xF00053) | |
1310 | return tomTimerDivider & 0xFF; | |
1311 | ||
1312 | return tomRam8[offset & 0x3FFF]; | |
1313 | } | |
1314 | ||
1315 | ||
1316 | // | |
1317 | // TOM word access (read) | |
1318 | // | |
1319 | uint16_t TOMReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/) | |
1320 | { | |
1321 | //???Is this needed??? | |
1322 | // offset &= 0xFF3FFF; | |
1323 | #ifdef TOM_DEBUG | |
1324 | WriteLog("TOM: Reading word at %06X for %s\n", offset, whoName[who]); | |
1325 | #endif | |
1326 | if (offset >= 0xF02000 && offset <= 0xF020FF) | |
1327 | WriteLog("TOM: ReadWord attempted from GPU register file by %s (unimplemented)!\n", whoName[who]); | |
1328 | ||
1329 | if (offset == 0xF000E0) | |
1330 | { | |
1331 | // For reading, should only return the lower 5 bits... | |
1332 | uint16_t data = (tom_jerry_int_pending << 4) | (tom_timer_int_pending << 3) | |
1333 | | (tom_object_int_pending << 2) | (tom_gpu_int_pending << 1) | |
1334 | | (tom_video_int_pending << 0); | |
1335 | //WriteLog("tom: interrupt status is 0x%.4x \n",data); | |
1336 | return data; | |
1337 | } | |
1338 | //Shoud be handled by the jaguar main loop now... And it is! ;-) | |
1339 | /* else if (offset == 0xF00006) // VC | |
1340 | // What if we're in interlaced mode? | |
1341 | // According to docs, in non-interlace mode VC is ALWAYS even... | |
1342 | // return (tom_scanline << 1);// + 1; | |
1343 | //But it's causing Rayman to be fucked up... Why??? | |
1344 | //Because VC is even in NI mode when calling the OP! That's why! | |
1345 | return (tom_scanline << 1) + 1;//*/ | |
1346 | /* | |
1347 | // F00004 R/W -----xxx xxxxxxxx HC - horizontal count | |
1348 | // -----x-- -------- (which half of the display) | |
1349 | // ------xx xxxxxxxx (10-bit counter) | |
1350 | */ | |
1351 | // This is a kludge to get the HC working somewhat... What we really should do here | |
1352 | // is check what the global time is at the time of the read and calculate the correct HC... | |
1353 | // !!! FIX !!! | |
1354 | else if (offset == 0xF00004) | |
1355 | return rand() & 0x03FF; | |
1356 | else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE + 0x20)) | |
1357 | return GPUReadWord(offset, who); | |
1358 | else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000)) | |
1359 | return GPUReadWord(offset, who); | |
1360 | /* else if ((offset >= 0xF00010) && (offset < 0xF00028)) | |
1361 | return OPReadWord(offset, who);*/ | |
1362 | else if ((offset >= 0xF02200) && (offset < 0xF022A0)) | |
1363 | return BlitterReadWord(offset, who); | |
1364 | else if (offset == 0xF00050) | |
1365 | return tomTimerPrescaler; | |
1366 | else if (offset == 0xF00052) | |
1367 | return tomTimerDivider; | |
1368 | ||
1369 | offset &= 0x3FFF; | |
1370 | return (TOMReadByte(offset, who) << 8) | TOMReadByte(offset + 1, who); | |
1371 | } | |
1372 | ||
1373 | ||
1374 | #define TOM_STRICT_MEMORY_ACCESS | |
1375 | // | |
1376 | // TOM byte access (write) | |
1377 | // | |
1378 | void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/) | |
1379 | { | |
1380 | // Moved here tentatively, so we can see everything written to TOM. | |
1381 | tomRam8[offset & 0x3FFF] = data; | |
1382 | ||
1383 | #ifdef TOM_DEBUG | |
1384 | WriteLog("TOM: Writing byte %02X at %06X", data, offset); | |
1385 | #endif | |
1386 | //???Is this needed??? | |
1387 | // Perhaps on the writes--32-bit writes that is! And masked with FF7FFF... | |
1388 | #ifndef TOM_STRICT_MEMORY_ACCESS | |
1389 | offset &= 0xFF3FFF; | |
1390 | #else | |
1391 | // "Fast" (32-bit only) write access to the GPU | |
1392 | // if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF)) | |
1393 | if ((offset >= 0xF08000) && (offset <= 0xF0BFFF)) | |
1394 | offset &= 0xFF7FFF; | |
1395 | #endif | |
1396 | #ifdef TOM_DEBUG | |
1397 | WriteLog(" -->[%06X] by %s\n", offset, whoName[who]); | |
1398 | #endif | |
1399 | ||
1400 | #ifdef TOM_STRICT_MEMORY_ACCESS | |
1401 | // Sanity check ("Aww, there ain't no Sanity Clause...") | |
1402 | if ((offset < 0xF00000) || (offset > 0xF03FFF)) | |
1403 | return; | |
1404 | #endif | |
1405 | ||
1406 | if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) | |
1407 | { | |
1408 | GPUWriteByte(offset, data, who); | |
1409 | return; | |
1410 | } | |
1411 | else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000)) | |
1412 | { | |
1413 | GPUWriteByte(offset, data, who); | |
1414 | return; | |
1415 | } | |
1416 | /* else if ((offset >= 0xF00010) && (offset < 0xF00028)) | |
1417 | { | |
1418 | OPWriteByte(offset, data, who); | |
1419 | return; | |
1420 | }*/ | |
1421 | else if ((offset >= 0xF02200) && (offset < 0xF022A0)) | |
1422 | { | |
1423 | BlitterWriteByte(offset, data, who); | |
1424 | return; | |
1425 | } | |
1426 | else if (offset == 0xF00050) | |
1427 | { | |
1428 | tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | (data << 8); | |
1429 | TOMResetPIT(); | |
1430 | return; | |
1431 | } | |
1432 | else if (offset == 0xF00051) | |
1433 | { | |
1434 | tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | data; | |
1435 | TOMResetPIT(); | |
1436 | return; | |
1437 | } | |
1438 | else if (offset == 0xF00052) | |
1439 | { | |
1440 | tomTimerDivider = (tomTimerDivider & 0x00FF) | (data << 8); | |
1441 | TOMResetPIT(); | |
1442 | return; | |
1443 | } | |
1444 | else if (offset == 0xF00053) | |
1445 | { | |
1446 | tomTimerDivider = (tomTimerDivider & 0xFF00) | data; | |
1447 | TOMResetPIT(); | |
1448 | return; | |
1449 | } | |
1450 | else if (offset >= 0xF00400 && offset <= 0xF007FF) // CLUT (A & B) | |
1451 | { | |
1452 | // Writing to one CLUT writes to the other | |
1453 | offset &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF) | |
1454 | tomRam8[offset] = data, tomRam8[offset + 0x200] = data; | |
1455 | } | |
1456 | ||
1457 | // tomRam8[offset & 0x3FFF] = data; | |
1458 | } | |
1459 | ||
1460 | ||
1461 | // | |
1462 | // TOM word access (write) | |
1463 | // | |
1464 | void TOMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/) | |
1465 | { | |
1466 | // Moved here tentatively, so we can see everything written to TOM. | |
1467 | tomRam8[(offset + 0) & 0x3FFF] = data >> 8; | |
1468 | tomRam8[(offset + 1) & 0x3FFF] = data & 0xFF; | |
1469 | ||
1470 | #ifdef TOM_DEBUG | |
1471 | WriteLog("TOM: Writing byte %04X at %06X", data, offset); | |
1472 | #endif | |
1473 | //???Is this needed??? Yes, but we need to be more vigilant than this. | |
1474 | #ifndef TOM_STRICT_MEMORY_ACCESS | |
1475 | offset &= 0xFF3FFF; | |
1476 | #else | |
1477 | // "Fast" (32-bit only) write access to the GPU | |
1478 | // if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF)) | |
1479 | if ((offset >= 0xF08000) && (offset <= 0xF0BFFF)) | |
1480 | offset &= 0xFF7FFF; | |
1481 | #endif | |
1482 | #ifdef TOM_DEBUG | |
1483 | WriteLog(" -->[%06X] by %s\n", offset, whoName[who]); | |
1484 | #endif | |
1485 | ||
1486 | #ifdef TOM_STRICT_MEMORY_ACCESS | |
1487 | // Sanity check | |
1488 | if ((offset < 0xF00000) || (offset > 0xF03FFF)) | |
1489 | return; | |
1490 | #endif | |
1491 | ||
1492 | //if (offset == 0xF00000 + MEMCON1) | |
1493 | // WriteLog("TOM: Memory Configuration 1 written by %s: %04X\n", whoName[who], data); | |
1494 | //if (offset == 0xF00000 + MEMCON2) | |
1495 | // WriteLog("TOM: Memory Configuration 2 written by %s: %04X\n", whoName[who], data); | |
1496 | if (offset >= 0xF02000 && offset <= 0xF020FF) | |
1497 | WriteLog("TOM: WriteWord attempted to GPU register file by %s (unimplemented)!\n", whoName[who]); | |
1498 | ||
1499 | if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20)) | |
1500 | { | |
1501 | GPUWriteWord(offset, data, who); | |
1502 | return; | |
1503 | } | |
1504 | else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000)) | |
1505 | { | |
1506 | GPUWriteWord(offset, data, who); | |
1507 | return; | |
1508 | } | |
1509 | //What's so special about this? | |
1510 | /* else if ((offset >= 0xF00000) && (offset < 0xF00002)) | |
1511 | { | |
1512 | TOMWriteByte(offset, data >> 8); | |
1513 | TOMWriteByte(offset+1, data & 0xFF); | |
1514 | }*/ | |
1515 | /* else if ((offset >= 0xF00010) && (offset < 0xF00028)) | |
1516 | { | |
1517 | OPWriteWord(offset, data, who); | |
1518 | return; | |
1519 | }*/ | |
1520 | else if (offset == 0xF00050) | |
1521 | { | |
1522 | tomTimerPrescaler = data; | |
1523 | TOMResetPIT(); | |
1524 | return; | |
1525 | } | |
1526 | else if (offset == 0xF00052) | |
1527 | { | |
1528 | tomTimerDivider = data; | |
1529 | TOMResetPIT(); | |
1530 | return; | |
1531 | } | |
1532 | else if (offset == 0xF000E0) | |
1533 | { | |
1534 | //Check this out... | |
1535 | if (data & 0x0100) | |
1536 | tom_video_int_pending = 0; | |
1537 | if (data & 0x0200) | |
1538 | tom_gpu_int_pending = 0; | |
1539 | if (data & 0x0400) | |
1540 | tom_object_int_pending = 0; | |
1541 | if (data & 0x0800) | |
1542 | tom_timer_int_pending = 0; | |
1543 | if (data & 0x1000) | |
1544 | tom_jerry_int_pending = 0; | |
1545 | ||
1546 | // return; | |
1547 | } | |
1548 | else if ((offset >= 0xF02200) && (offset <= 0xF0229F)) | |
1549 | { | |
1550 | BlitterWriteWord(offset, data, who); | |
1551 | return; | |
1552 | } | |
1553 | else if (offset >= 0xF00400 && offset <= 0xF007FE) // CLUT (A & B) | |
1554 | { | |
1555 | // Writing to one CLUT writes to the other | |
1556 | offset &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF) | |
1557 | // Watch out for unaligned writes here! (Not fixed yet) | |
1558 | #ifdef _MSC_VER | |
1559 | #pragma message("Warning: !!! Watch out for unaligned writes here !!! FIX !!!") | |
1560 | #else | |
1561 | #warning "!!! Watch out for unaligned writes here !!! FIX !!!" | |
1562 | #endif // _MSC_VER | |
1563 | SET16(tomRam8, offset, data); | |
1564 | SET16(tomRam8, offset + 0x200, data); | |
1565 | } | |
1566 | ||
1567 | offset &= 0x3FFF; | |
1568 | if (offset == 0x28) // VMODE (Why? Why not OBF?) | |
1569 | //Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!! | |
1570 | #ifdef _MSC_VER | |
1571 | #pragma message("Warning: Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!") | |
1572 | #else | |
1573 | #warning "Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!" | |
1574 | #endif // _MSC_VER | |
1575 | objectp_running = 1; | |
1576 | ||
1577 | if (offset >= 0x30 && offset <= 0x4E) | |
1578 | data &= 0x07FF; // These are (mostly) 11-bit registers | |
1579 | if (offset == 0x2E || offset == 0x36 || offset == 0x54) | |
1580 | data &= 0x03FF; // These are all 10-bit registers | |
1581 | ||
1582 | // Fix a lockup bug... :-P | |
1583 | // TOMWriteByte(0xF00000 | offset, data >> 8, who); | |
1584 | // TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who); | |
1585 | ||
1586 | if (offset == MEMCON1) | |
1587 | WriteLog("TOM: Memory Config 1 written by %s: $%04X\n", whoName[who], data); | |
1588 | if (offset == MEMCON2) | |
1589 | WriteLog("TOM: Memory Config 2 written by %s: $%04X\n", whoName[who], data); | |
1590 | //if (offset == OLP) | |
1591 | // WriteLog("TOM: Object List Pointer written by %s: $%04X\n", whoName[who], data); | |
1592 | //if (offset == OLP + 2) | |
1593 | // WriteLog("TOM: Object List Pointer +2 written by %s: $%04X\n", whoName[who], data); | |
1594 | //if (offset == OBF) | |
1595 | // WriteLog("TOM: Object Processor Flag written by %s: %u\n", whoName[who], data); | |
1596 | if (offset == VMODE) | |
1597 | WriteLog("TOM: Video Mode written by %s: %04X. PWIDTH = %u, MODE = %s, flags:%s%s (VC = %u) (M68K PC = %06X)\n", whoName[who], data, ((data >> 9) & 0x07) + 1, videoMode_to_str[(data & MODE) >> 1], (data & BGEN ? " BGEN" : ""), (data & VARMOD ? " VARMOD" : ""), GET16(tomRam8, VC), m68k_get_reg(NULL, M68K_REG_PC)); | |
1598 | if (offset == BORD1) | |
1599 | WriteLog("TOM: Border 1 written by %s: $%04X\n", whoName[who], data); | |
1600 | if (offset == BORD2) | |
1601 | WriteLog("TOM: Border 2 written by %s: $%04X\n", whoName[who], data); | |
1602 | if (offset == HP) | |
1603 | WriteLog("TOM: Horizontal Period written by %s: %u (+1*2 = %u)\n", whoName[who], data, (data + 1) * 2); | |
1604 | if (offset == HBB) | |
1605 | WriteLog("TOM: Horizontal Blank Begin written by %s: %u\n", whoName[who], data); | |
1606 | if (offset == HBE) | |
1607 | WriteLog("TOM: Horizontal Blank End written by %s: %u\n", whoName[who], data); | |
1608 | if (offset == HS) | |
1609 | WriteLog("TOM: Horizontal Sync written by %s: %u\n", whoName[who], data); | |
1610 | if (offset == HVS) | |
1611 | WriteLog("TOM: Horizontal Vertical Sync written by %s: %u\n", whoName[who], data); | |
1612 | if (offset == HDB1) | |
1613 | WriteLog("TOM: Horizontal Display Begin 1 written by %s: %u\n", whoName[who], data); | |
1614 | if (offset == HDB2) | |
1615 | WriteLog("TOM: Horizontal Display Begin 2 written by %s: %u\n", whoName[who], data); | |
1616 | if (offset == HDE) | |
1617 | WriteLog("TOM: Horizontal Display End written by %s: %u\n", whoName[who], data); | |
1618 | if (offset == VP) | |
1619 | WriteLog("TOM: Vertical Period written by %s: %u (%sinterlaced)\n", whoName[who], data, (data & 0x01 ? "non-" : "")); | |
1620 | if (offset == VBB) | |
1621 | WriteLog("TOM: Vertical Blank Begin written by %s: %u\n", whoName[who], data); | |
1622 | if (offset == VBE) | |
1623 | WriteLog("TOM: Vertical Blank End written by %s: %u\n", whoName[who], data); | |
1624 | if (offset == VS) | |
1625 | WriteLog("TOM: Vertical Sync written by %s: %u\n", whoName[who], data); | |
1626 | if (offset == VDB) | |
1627 | WriteLog("TOM: Vertical Display Begin written by %s: %u\n", whoName[who], data); | |
1628 | if (offset == VDE) | |
1629 | WriteLog("TOM: Vertical Display End written by %s: %u\n", whoName[who], data); | |
1630 | if (offset == VEB) | |
1631 | WriteLog("TOM: Vertical Equalization Begin written by %s: %u\n", whoName[who], data); | |
1632 | if (offset == VEE) | |
1633 | WriteLog("TOM: Vertical Equalization End written by %s: %u\n", whoName[who], data); | |
1634 | if (offset == VI) | |
1635 | WriteLog("TOM: Vertical Interrupt written by %s: %u\n", whoName[who], data); | |
1636 | if (offset == PIT0) | |
1637 | WriteLog("TOM: PIT0 written by %s: %u\n", whoName[who], data); | |
1638 | if (offset == PIT1) | |
1639 | WriteLog("TOM: PIT1 written by %s: %u\n", whoName[who], data); | |
1640 | if (offset == HEQ) | |
1641 | WriteLog("TOM: Horizontal Equalization End written by %s: %u\n", whoName[who], data); | |
1642 | //if (offset == BG) | |
1643 | // WriteLog("TOM: Background written by %s: %u\n", whoName[who], data); | |
1644 | //if (offset == INT1) | |
1645 | // WriteLog("TOM: CPU Interrupt Control written by %s: $%04X (%s%s%s%s%s)\n", whoName[who], data, (data & 0x01 ? "Video" : ""), (data & 0x02 ? " GPU" : ""), (data & 0x04 ? " OP" : ""), (data & 0x08 ? " TOMPIT" : ""), (data & 0x10 ? " Jerry" : "")); | |
1646 | ||
1647 | // detect screen resolution changes | |
1648 | //This may go away in the future, if we do the virtualized screen thing... | |
1649 | //This may go away soon! | |
1650 | // TOM Shouldn't be mucking around with this, it's up to the host system to properly | |
1651 | // handle this kind of crap. | |
1652 | // NOTE: This is needed somehow, need to get rid of the dependency on this crap. | |
1653 | // N.B.: It's used in the rendering functions... So... | |
1654 | #ifdef _MSC_VER | |
1655 | #pragma message("Warning: !!! Need to get rid of this dependency !!!") | |
1656 | #else | |
1657 | #warning "!!! Need to get rid of this dependency !!!" | |
1658 | #endif // _MSC_VER | |
1659 | #if 1 | |
1660 | if ((offset >= 0x28) && (offset <= 0x4F)) | |
1661 | { | |
1662 | uint32_t width = TOMGetVideoModeWidth(), height = TOMGetVideoModeHeight(); | |
1663 | ||
1664 | if ((width != tomWidth) || (height != tomHeight)) | |
1665 | { | |
1666 | tomWidth = width, tomHeight = height; | |
1667 | ||
1668 | #ifdef _MSC_VER | |
1669 | #pragma message("Warning: !!! TOM: ResizeScreen commented out !!!") | |
1670 | #else | |
1671 | #warning "!!! TOM: ResizeScreen commented out !!!" | |
1672 | #endif // _MSC_VER | |
1673 | // No need to resize anything, since we're prepared for this... | |
1674 | // if (vjs.renderType == RT_NORMAL) | |
1675 | // ResizeScreen(tomWidth, tomHeight); | |
1676 | } | |
1677 | } | |
1678 | #endif | |
1679 | } | |
1680 | ||
1681 | ||
1682 | int TOMIRQEnabled(int irq) | |
1683 | { | |
1684 | // This is the correct byte in big endian... D'oh! | |
1685 | // return jaguar_byte_read(0xF000E1) & (1 << irq); | |
1686 | return tomRam8[INT1 + 1/*0xE1*/] & (1 << irq); | |
1687 | } | |
1688 | ||
1689 | ||
1690 | // NEW: | |
1691 | // TOM Programmable Interrupt Timer handler | |
1692 | // NOTE: TOM's PIT is only enabled if the prescaler is != 0 | |
1693 | // The PIT only generates an interrupt when it counts down to zero, not when loaded! | |
1694 | ||
1695 | void TOMPITCallback(void); | |
1696 | ||
1697 | ||
1698 | void TOMResetPIT(void) | |
1699 | { | |
1700 | #ifndef NEW_TIMER_SYSTEM | |
1701 | //Probably should *add* this amount to the counter to retain cycle accuracy! !!! FIX !!! [DONE] | |
1702 | //Also, why +1??? 'Cause that's what it says in the JTRM...! | |
1703 | //There is a small problem with this approach: If both the prescaler and the divider are equal | |
1704 | //to $FFFF then the counter won't be large enough to handle it. !!! FIX !!! | |
1705 | if (tom_timer_prescaler) | |
1706 | tom_timer_counter += (1 + tom_timer_prescaler) * (1 + tom_timer_divider); | |
1707 | // WriteLog("tom: reseting timer to 0x%.8x (%i)\n",tom_timer_counter,tom_timer_counter); | |
1708 | #else | |
1709 | // Need to remove previous timer from the queue, if it exists... | |
1710 | RemoveCallback(TOMPITCallback); | |
1711 | ||
1712 | if (tomTimerPrescaler) | |
1713 | { | |
1714 | double usecs = (float)(tomTimerPrescaler + 1) * (float)(tomTimerDivider + 1) * RISC_CYCLE_IN_USEC; | |
1715 | SetCallbackTime(TOMPITCallback, usecs); | |
1716 | } | |
1717 | #endif | |
1718 | } | |
1719 | ||
1720 | ||
1721 | // | |
1722 | // TOM Programmable Interrupt Timer handler | |
1723 | // NOTE: TOM's PIT is only enabled if the prescaler is != 0 | |
1724 | // | |
1725 | //NOTE: This is only used by the old execution code... Safe to remove | |
1726 | // once the timer system is stable. | |
1727 | void TOMExecPIT(uint32_t cycles) | |
1728 | { | |
1729 | if (tomTimerPrescaler) | |
1730 | { | |
1731 | tomTimerCounter -= cycles; | |
1732 | ||
1733 | if (tomTimerCounter <= 0) | |
1734 | { | |
1735 | TOMSetPendingTimerInt(); | |
1736 | GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // GPUSetIRQLine does the 'IRQ enabled' checking | |
1737 | ||
1738 | if (TOMIRQEnabled(IRQ_TIMER)) | |
1739 | m68k_set_irq(2); // Cause a 68000 IPL 2... | |
1740 | ||
1741 | TOMResetPIT(); | |
1742 | } | |
1743 | } | |
1744 | } | |
1745 | ||
1746 | ||
1747 | void TOMPITCallback(void) | |
1748 | { | |
1749 | // INT1_RREG |= 0x08; // Set TOM PIT interrupt pending | |
1750 | TOMSetPendingTimerInt(); | |
1751 | GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking | |
1752 | ||
1753 | // if (INT1_WREG & 0x08) | |
1754 | if (TOMIRQEnabled(IRQ_TIMER)) | |
1755 | m68k_set_irq(2); // Generate a 68K IPL 2... | |
1756 | ||
1757 | TOMResetPIT(); | |
1758 | } | |
1759 |