4 // Originally by David Raingeard (cal2)
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Cleanups and endian wrongness amelioration by James Hammons
7 // (C) 2010 Underground Software
9 // JLH = James Hammons <jlhamm@acm.org>
12 // --- ---------- -------------------------------------------------------------
13 // JLH 01/16/2010 Created this log ;-)
14 // JLH 01/20/2011 Change rendering to RGBA, removed unnecessary code
16 // Note: Endian wrongness probably stems from the MAME origins of this emu and
17 // the braindead way in which MAME used to handle memory. :-}
19 // Note: TOM has only a 16K memory space
21 // ------------------------------------------------------------
22 // TOM REGISTERS (Mapped by Aaron Giles)
23 // ------------------------------------------------------------
24 // F00000-F0FFFF R/W xxxxxxxx xxxxxxxx Internal Registers
25 // F00000 R/W -x-xx--- xxxxxxxx MEMCON1 - memory config reg 1
26 // -x------ -------- (CPU32 - is the CPU 32bits?)
27 // ---xx--- -------- (IOSPEED - external I/O clock cycles)
28 // -------- x------- (FASTROM - reduces ROM clock cycles)
29 // -------- -xx----- (DRAMSPEED - sets RAM clock cycles)
30 // -------- ---xx--- (ROMSPEED - sets ROM clock cycles)
31 // -------- -----xx- (ROMWIDTH - sets width of ROM: 8,16,32,64 bits)
32 // -------- -------x (ROMHI - controls ROM mapping)
33 // F00002 R/W --xxxxxx xxxxxxxx MEMCON2 - memory config reg 2
34 // --x----- -------- (HILO - image display bit order)
35 // ---x---- -------- (BIGEND - big endian addressing?)
36 // ----xxxx -------- (REFRATE - DRAM refresh rate)
37 // -------- xx------ (DWIDTH1 - DRAM1 width: 8,16,32,64 bits)
38 // -------- --xx---- (COLS1 - DRAM1 columns: 256,512,1024,2048)
39 // -------- ----xx-- (DWIDTH0 - DRAM0 width: 8,16,32,64 bits)
40 // -------- ------xx (COLS0 - DRAM0 columns: 256,512,1024,2048)
41 // F00004 R/W -----xxx xxxxxxxx HC - horizontal count
42 // -----x-- -------- (which half of the display)
43 // ------xx xxxxxxxx (10-bit counter)
44 // F00006 R/W ----xxxx xxxxxxxx VC - vertical count
45 // ----x--- -------- (which field is being generated)
46 // -----xxx xxxxxxxx (11-bit counter)
47 // F00008 R -----xxx xxxxxxxx LPH - light pen horizontal position
48 // F0000A R -----xxx xxxxxxxx LPV - light pen vertical position
49 // F00010-F00017 R xxxxxxxx xxxxxxxx OB - current object code from the graphics processor
50 // F00020-F00023 W xxxxxxxx xxxxxxxx OLP - start of the object list
51 // F00026 W -------- -------x OBF - object processor flag
52 // F00028 W ----xxxx xxxxxxxx VMODE - video mode
53 // W ----xxx- -------- (PWIDTH1-8 - width of pixel in video clock cycles)
54 // W -------x -------- (VARMOD - enable variable color resolution)
55 // W -------- x------- (BGEN - clear line buffer to BG color)
56 // W -------- -x------ (CSYNC - enable composite sync on VSYNC)
57 // W -------- --x----- (BINC - local border color if INCEN)
58 // W -------- ---x---- (INCEN - encrustation enable)
59 // W -------- ----x--- (GENLOCK - enable genlock)
60 // W -------- -----xx- (MODE - CRY16,RGB24,DIRECT16,RGB16)
61 // W -------- -------x (VIDEN - enables video)
62 // F0002A W xxxxxxxx xxxxxxxx BORD1 - border color (red/green)
63 // F0002C W -------- xxxxxxxx BORD2 - border color (blue)
64 // F0002E W ------xx xxxxxxxx HP - horizontal period
65 // F00030 W -----xxx xxxxxxxx HBB - horizontal blanking begin
66 // F00032 W -----xxx xxxxxxxx HBE - horizontal blanking end
67 // F00034 W -----xxx xxxxxxxx HSYNC - horizontal sync
68 // F00036 W ------xx xxxxxxxx HVS - horizontal vertical sync
69 // F00038 W -----xxx xxxxxxxx HDB1 - horizontal display begin 1
70 // F0003A W -----xxx xxxxxxxx HDB2 - horizontal display begin 2
71 // F0003C W -----xxx xxxxxxxx HDE - horizontal display end
72 // F0003E W -----xxx xxxxxxxx VP - vertical period
73 // F00040 W -----xxx xxxxxxxx VBB - vertical blanking begin
74 // F00042 W -----xxx xxxxxxxx VBE - vertical blanking end
75 // F00044 W -----xxx xxxxxxxx VS - vertical sync
76 // F00046 W -----xxx xxxxxxxx VDB - vertical display begin
77 // F00048 W -----xxx xxxxxxxx VDE - vertical display end
78 // F0004A W -----xxx xxxxxxxx VEB - vertical equalization begin
79 // F0004C W -----xxx xxxxxxxx VEE - vertical equalization end
80 // F0004E W -----xxx xxxxxxxx VI - vertical interrupt
81 // F00050 W xxxxxxxx xxxxxxxx PIT0 - programmable interrupt timer 0
82 // F00052 W xxxxxxxx xxxxxxxx PIT1 - programmable interrupt timer 1
83 // F00054 W ------xx xxxxxxxx HEQ - horizontal equalization end
84 // F00058 W xxxxxxxx xxxxxxxx BG - background color
85 // F000E0 R/W ---xxxxx ---xxxxx INT1 - CPU interrupt control register
86 // ---x---- -------- (C_JERCLR - clear pending Jerry ints)
87 // ----x--- -------- (C_PITCLR - clear pending PIT ints)
88 // -----x-- -------- (C_OPCLR - clear pending object processor ints)
89 // ------x- -------- (C_GPUCLR - clear pending graphics processor ints)
90 // -------x -------- (C_VIDCLR - clear pending video timebase ints)
91 // -------- ---x---- (C_JERENA - enable Jerry ints)
92 // -------- ----x--- (C_PITENA - enable PIT ints)
93 // -------- -----x-- (C_OPENA - enable object processor ints)
94 // -------- ------x- (C_GPUENA - enable graphics processor ints)
95 // -------- -------x (C_VIDENA - enable video timebase ints)
96 // F000E2 W -------- -------- INT2 - CPU interrupt resume register
97 // F00400-F005FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table A
98 // F00600-F007FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table B
99 // F00800-F00D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer A
100 // F01000-F0159F R/W xxxxxxxx xxxxxxxx LBUF - line buffer B
101 // F01800-F01D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer currently selected
102 // ------------------------------------------------------------
103 // F02000-F021FF R/W xxxxxxxx xxxxxxxx GPU control registers
104 // F02100 R/W xxxxxxxx xxxxxxxx G_FLAGS - GPU flags register
105 // R/W x------- -------- (DMAEN - DMA enable)
106 // R/W -x------ -------- (REGPAGE - register page)
107 // W --x----- -------- (G_BLITCLR - clear blitter interrupt)
108 // W ---x---- -------- (G_OPCLR - clear object processor int)
109 // W ----x--- -------- (G_PITCLR - clear PIT interrupt)
110 // W -----x-- -------- (G_JERCLR - clear Jerry interrupt)
111 // W ------x- -------- (G_CPUCLR - clear CPU interrupt)
112 // R/W -------x -------- (G_BLITENA - enable blitter interrupt)
113 // R/W -------- x------- (G_OPENA - enable object processor int)
114 // R/W -------- -x------ (G_PITENA - enable PIT interrupt)
115 // R/W -------- --x----- (G_JERENA - enable Jerry interrupt)
116 // R/W -------- ---x---- (G_CPUENA - enable CPU interrupt)
117 // R/W -------- ----x--- (IMASK - interrupt mask)
118 // R/W -------- -----x-- (NEGA_FLAG - ALU negative)
119 // R/W -------- ------x- (CARRY_FLAG - ALU carry)
120 // R/W -------- -------x (ZERO_FLAG - ALU zero)
121 // F02104 W -------- ----xxxx G_MTXC - matrix control register
122 // W -------- ----x--- (MATCOL - column/row major)
123 // W -------- -----xxx (MATRIX3-15 - matrix width)
124 // F02108 W ----xxxx xxxxxx-- G_MTXA - matrix address register
125 // F0210C W -------- -----xxx G_END - data organization register
126 // W -------- -----x-- (BIG_INST - big endian instruction fetch)
127 // W -------- ------x- (BIG_PIX - big endian pixels)
128 // W -------- -------x (BIG_IO - big endian I/O)
129 // F02110 R/W xxxxxxxx xxxxxxxx G_PC - GPU program counter
130 // F02114 R/W xxxxxxxx xx-xxxxx G_CTRL - GPU control/status register
131 // R xxxx---- -------- (VERSION - GPU version code)
132 // R/W ----x--- -------- (BUS_HOG - hog the bus!)
133 // R/W -----x-- -------- (G_BLITLAT - blitter interrupt latch)
134 // R/W ------x- -------- (G_OPLAT - object processor int latch)
135 // R/W -------x -------- (G_PITLAT - PIT interrupt latch)
136 // R/W -------- x------- (G_JERLAT - Jerry interrupt latch)
137 // R/W -------- -x------ (G_CPULAT - CPU interrupt latch)
138 // R/W -------- ---x---- (SINGLE_GO - single step one instruction)
139 // R/W -------- ----x--- (SINGLE_STEP - single step mode)
140 // R/W -------- -----x-- (FORCEINT0 - cause interrupt 0 on GPU)
141 // R/W -------- ------x- (CPUINT - send GPU interrupt to CPU)
142 // R/W -------- -------x (GPUGO - enable GPU execution)
143 // F02118-F0211B R/W xxxxxxxx xxxxxxxx G_HIDATA - high data register
144 // F0211C-F0211F R xxxxxxxx xxxxxxxx G_REMAIN - divide unit remainder
145 // F0211C W -------- -------x G_DIVCTRL - divide unit control
146 // W -------- -------x (DIV_OFFSET - 1=16.16 divide, 0=32-bit divide)
147 // ------------------------------------------------------------
149 // ------------------------------------------------------------
150 // F02200-F022FF R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Blitter registers
151 // F02200 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_BASE - A1 base register
152 // F02204 W -------- ---xxxxx -xxxxxxx xxxxx-xx A1_FLAGS - A1 flags register
153 // W -------- ---x---- -------- -------- (YSIGNSUB - invert sign of Y delta)
154 // W -------- ----x--- -------- -------- (XSIGNSUB - invert sign of X delta)
155 // W -------- -----x-- -------- -------- (Y add control)
156 // W -------- ------xx -------- -------- (X add control)
157 // W -------- -------- -xxxxxx- -------- (width in 6-bit floating point)
158 // W -------- -------- -------x xx------ (ZOFFS1-6 - Z data offset)
159 // W -------- -------- -------- --xxx--- (PIXEL - pixel size)
160 // W -------- -------- -------- ------xx (PITCH1-4 - data phrase pitch)
161 // F02208 W -xxxxxxx xxxxxxxx -xxxxxxx xxxxxxxx A1_CLIP - A1 clipping size
162 // W -xxxxxxx xxxxxxxx -------- -------- (height)
163 // W -------- -------- -xxxxxxx xxxxxxxx (width)
164 // F0220C R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_PIXEL - A1 pixel pointer
165 // R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel value)
166 // R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel value)
167 // F02210 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_STEP - A1 step value
168 // W xxxxxxxx xxxxxxxx -------- -------- (Y step value)
169 // W -------- -------- xxxxxxxx xxxxxxxx (X step value)
170 // F02214 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FSTEP - A1 step fraction value
171 // W xxxxxxxx xxxxxxxx -------- -------- (Y step fraction value)
172 // W -------- -------- xxxxxxxx xxxxxxxx (X step fraction value)
173 // F02218 R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FPIXEL - A1 pixel pointer fraction
174 // R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel fraction value)
175 // R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel fraction value)
176 // F0221C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_INC - A1 increment
177 // W xxxxxxxx xxxxxxxx -------- -------- (Y increment)
178 // W -------- -------- xxxxxxxx xxxxxxxx (X increment)
179 // F02220 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A1_FINC - A1 increment fraction
180 // W xxxxxxxx xxxxxxxx -------- -------- (Y increment fraction)
181 // W -------- -------- xxxxxxxx xxxxxxxx (X increment fraction)
182 // F02224 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_BASE - A2 base register
183 // F02228 W -------- ---xxxxx -xxxxxxx xxxxx-xx A2_FLAGS - A2 flags register
184 // W -------- ---x---- -------- -------- (YSIGNSUB - invert sign of Y delta)
185 // W -------- ----x--- -------- -------- (XSIGNSUB - invert sign of X delta)
186 // W -------- -----x-- -------- -------- (Y add control)
187 // W -------- ------xx -------- -------- (X add control)
188 // W -------- -------- -xxxxxx- -------- (width in 6-bit floating point)
189 // W -------- -------- -------x xx------ (ZOFFS1-6 - Z data offset)
190 // W -------- -------- -------- --xxx--- (PIXEL - pixel size)
191 // W -------- -------- -------- ------xx (PITCH1-4 - data phrase pitch)
192 // F0222C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_MASK - A2 window mask
193 // F02230 R/W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_PIXEL - A2 pixel pointer
194 // R/W xxxxxxxx xxxxxxxx -------- -------- (Y pixel value)
195 // R/W -------- -------- xxxxxxxx xxxxxxxx (X pixel value)
196 // F02234 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx A2_STEP - A2 step value
197 // W xxxxxxxx xxxxxxxx -------- -------- (Y step value)
198 // W -------- -------- xxxxxxxx xxxxxxxx (X step value)
199 // F02238 W -xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_CMD - command register
200 // W -x------ -------- -------- -------- (SRCSHADE - modify source intensity)
201 // W --x----- -------- -------- -------- (BUSHI - hi priority bus)
202 // W ---x---- -------- -------- -------- (BKGWREN - writeback destination)
203 // W ----x--- -------- -------- -------- (DCOMPEN - write inhibit from data comparator)
204 // W -----x-- -------- -------- -------- (BCOMPEN - write inhibit from bit coparator)
205 // W ------x- -------- -------- -------- (CMPDST - compare dest instead of src)
206 // W -------x xxx----- -------- -------- (logical operation)
207 // W -------- ---xxx-- -------- -------- (ZMODE - Z comparator mode)
208 // W -------- ------x- -------- -------- (ADDDSEL - select sum of src & dst)
209 // W -------- -------x -------- -------- (PATDSEL - select pattern data)
210 // W -------- -------- x------- -------- (TOPNEN - enable carry into top intensity nibble)
211 // W -------- -------- -x------ -------- (TOPBEN - enable carry into top intensity byte)
212 // W -------- -------- --x----- -------- (ZBUFF - enable Z updates in inner loop)
213 // W -------- -------- ---x---- -------- (GOURD - enable gouraud shading in inner loop)
214 // W -------- -------- ----x--- -------- (DSTA2 - reverses A2/A1 roles)
215 // W -------- -------- -----x-- -------- (UPDA2 - add A2 step to A2 in outer loop)
216 // W -------- -------- ------x- -------- (UPDA1 - add A1 step to A1 in outer loop)
217 // W -------- -------- -------x -------- (UPDA1F - add A1 fraction step to A1 in outer loop)
218 // W -------- -------- -------- x------- (diagnostic use)
219 // W -------- -------- -------- -x------ (CLIP_A1 - clip A1 to window)
220 // W -------- -------- -------- --x----- (DSTWRZ - enable dest Z write in inner loop)
221 // W -------- -------- -------- ---x---- (DSTENZ - enable dest Z read in inner loop)
222 // W -------- -------- -------- ----x--- (DSTEN - enables dest data read in inner loop)
223 // W -------- -------- -------- -----x-- (SRCENX - enable extra src read at start of inner)
224 // W -------- -------- -------- ------x- (SRCENZ - enables source Z read in inner loop)
225 // W -------- -------- -------- -------x (SRCEN - enables source data read in inner loop)
226 // F02238 R xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_CMD - status register
227 // R xxxxxxxx xxxxxxxx -------- -------- (inner count)
228 // R -------- -------- xxxxxxxx xxxxxx-- (diagnostics)
229 // R -------- -------- -------- ------x- (STOPPED - when stopped in collision detect)
230 // R -------- -------- -------- -------x (IDLE - when idle)
231 // F0223C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_COUNT - counters register
232 // W xxxxxxxx xxxxxxxx -------- -------- (outer loop count)
233 // W -------- -------- xxxxxxxx xxxxxxxx (inner loop count)
234 // F02240-F02247 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCD - source data register
235 // F02248-F0224F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_DSTD - destination data register
236 // F02250-F02257 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_DSTZ - destination Z register
237 // F02258-F0225F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCZ1 - source Z register 1
238 // F02260-F02267 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_SRCZ2 - source Z register 2
239 // F02268-F0226F W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_PATD - pattern data register
240 // F02270 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_IINC - intensity increment
241 // F02274 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_ZINC - Z increment
242 // F02278 W -------- -------- -------- -----xxx B_STOP - collision control
243 // W -------- -------- -------- -----x-- (STOPEN - enable blitter collision stops)
244 // W -------- -------- -------- ------x- (ABORT - abort after stop)
245 // W -------- -------- -------- -------x (RESUME - resume after stop)
246 // F0227C W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I3 - intensity 3
247 // F02280 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I2 - intensity 2
248 // F02284 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I1 - intensity 1
249 // F02288 W -------- xxxxxxxx xxxxxxxx xxxxxxxx B_I0 - intensity 0
250 // F0228C W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z3 - Z3
251 // F02290 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z2 - Z2
252 // F02294 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z1 - Z1
253 // F02298 W xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx B_Z0 - Z0
254 // ------------------------------------------------------------
258 #include <string.h> // For memset()
259 #include <stdlib.h> // For rand()
266 #include "m68000/m68kinterface.h"
267 //#include "memory.h"
269 #include "settings.h"
271 #define NEW_TIMER_SYSTEM
273 // TOM registers (offset from $F00000)
279 #define OLP 0x20 // Object list pointer
280 #define OBF 0x26 // Object processor flag
282 #define MODE 0x0006 // Line buffer to video generator mode
283 #define BGEN 0x0080 // Background enable (CRY & RGB16 only)
284 #define VARMOD 0x0100 // Mixed CRY/RGB16 mode (only works in MODE 0!)
285 #define PWIDTH 0x0E00 // Pixel width in video clock cycles (value written + 1)
286 #define BORD1 0x2A // Border green/red values (8 BPP)
287 #define BORD2 0x2C // Border blue value (8 BPP)
288 #define HP 0x2E // Values range from 1 - 1024 (value written + 1)
289 #define HBB 0x30 // Horizontal blank begin
291 #define HS 0x34 // Horizontal sync
292 #define HVS 0x36 // Horizontal vertical sync
293 #define HDB1 0x38 // Horizontal display begin 1
296 #define VP 0x3E // Value ranges from 1 - 2048 (value written + 1)
297 #define VBB 0x40 // Vertical blank begin
299 #define VS 0x44 // Vertical sync
300 #define VDB 0x46 // Vertical display begin
302 #define VEB 0x4A // Vertical equalization begin
303 #define VEE 0x4C // Vertical equalization end
304 #define VI 0x4E // Vertical interrupt
307 #define HEQ 0x54 // Horizontal equalization end
308 #define BG 0x58 // Background color
312 //NOTE: These arbitrary cutoffs are NOT taken into account for PAL jaguar screens. !!! FIX !!! [DONE]
314 // Arbitrary video cutoff values (i.e., first/last visible spots on a TV, in HC ticks)
315 // Also note that VC is in *half* lines, i.e. divide by 2 to get the scanline
316 /*#define LEFT_VISIBLE_HC 208
317 #define RIGHT_VISIBLE_HC 1528//*/
318 // These were right for Rayman, but that one is offset on a real TV too.
319 //#define LEFT_VISIBLE_HC 208
320 //#define RIGHT_VISIBLE_HC 1488
321 // This is more like a real TV display...
322 //#define LEFT_VISIBLE_HC (208 - 32)
323 //#define RIGHT_VISIBLE_HC (1488 - 32)
324 // Split the difference? (Seems to be OK for the most part...)
326 // (-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).
327 //NB: Went back to 330. May shrink more. :-)
328 //#define LEFT_VISIBLE_HC (208 - 16 - (8 * 4))
329 //#define LEFT_VISIBLE_HC (208 - 16 - (3 * 4))
330 #define LEFT_VISIBLE_HC (208 - 16 - (1 * 4))
331 //#define RIGHT_VISIBLE_HC (1488 - 16 + (10 * 4))
332 #define RIGHT_VISIBLE_HC (LEFT_VISIBLE_HC + (VIRTUAL_SCREEN_WIDTH * 4))
333 //#define TOP_VISIBLE_VC 25
334 //#define BOTTOM_VISIBLE_VC 503
335 #define TOP_VISIBLE_VC 31
336 #define BOTTOM_VISIBLE_VC 511
338 //Are these PAL horizontals correct?
339 //They seem to be for the most part, but there are some games that seem to be
340 //shifted over to the right from this "window".
341 //#define LEFT_VISIBLE_HC_PAL (208 - 16 - (4 * 4))
342 //#define LEFT_VISIBLE_HC_PAL (208 - 16 - (-1 * 4))
343 #define LEFT_VISIBLE_HC_PAL (208 - 16 - (-3 * 4))
344 //#define RIGHT_VISIBLE_HC_PAL (1488 - 16 + (10 * 4))
345 #define RIGHT_VISIBLE_HC_PAL (LEFT_VISIBLE_HC_PAL + (VIRTUAL_SCREEN_WIDTH * 4))
346 #define TOP_VISIBLE_VC_PAL 67
347 #define BOTTOM_VISIBLE_VC_PAL 579
349 //This can be defined in the makefile as well...
350 //(It's easier to do it here, though...)
353 uint8_t tomRam8[0x4000];
354 uint32_t tomWidth, tomHeight;
355 uint32_t tomTimerPrescaler;
356 uint32_t tomTimerDivider;
357 int32_t tomTimerCounter;
358 uint16_t tom_jerry_int_pending, tom_timer_int_pending, tom_object_int_pending,
359 tom_gpu_int_pending, tom_video_int_pending;
361 // These are set by the "user" of the Jaguar core lib, since these are
362 // OS/system dependent.
363 uint32_t * screenBuffer;
364 uint32_t screenPitch;
366 static const char * videoMode_to_str[8] =
367 { "16 BPP CRY", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB",
368 "Mixed mode", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB" };
370 typedef void (render_xxx_scanline_fn)(uint32_t *);
372 // Private function prototypes
374 void tom_render_16bpp_cry_scanline(uint32_t * backbuffer);
375 void tom_render_24bpp_scanline(uint32_t * backbuffer);
376 void tom_render_16bpp_direct_scanline(uint32_t * backbuffer);
377 void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer);
378 void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer);
380 //render_xxx_scanline_fn * scanline_render_normal[] =
381 render_xxx_scanline_fn * scanline_render[] =
383 tom_render_16bpp_cry_scanline,
384 tom_render_24bpp_scanline,
385 tom_render_16bpp_direct_scanline,
386 tom_render_16bpp_rgb_scanline,
387 tom_render_16bpp_cry_rgb_mix_scanline,
388 tom_render_24bpp_scanline,
389 tom_render_16bpp_direct_scanline,
390 tom_render_16bpp_rgb_scanline
393 // Screen info for various games [PAL]...
396 TOM: Horizontal Period written by M68K: 850 (+1*2 = 1702)
397 TOM: Horizontal Blank Begin written by M68K: 1711
398 TOM: Horizontal Blank End written by M68K: 158
399 TOM: Horizontal Display End written by M68K: 1696
400 TOM: Horizontal Display Begin 1 written by M68K: 166
401 TOM: Vertical Period written by M68K: 623 (non-interlaced)
402 TOM: Vertical Blank End written by M68K: 34
403 TOM: Vertical Display Begin written by M68K: 46
404 TOM: Vertical Display End written by M68K: 526
405 TOM: Vertical Blank Begin written by M68K: 600
406 TOM: Vertical Sync written by M68K: 618
407 TOM: Horizontal Display End written by M68K: 1665
408 TOM: Horizontal Display Begin 1 written by M68K: 203
409 TOM: Vertical Display Begin written by M68K: 38
410 TOM: Vertical Display End written by M68K: 518
411 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 151)
412 TOM: Horizontal Display End written by M68K: 1713
413 TOM: Horizontal Display Begin 1 written by M68K: 157
414 TOM: Vertical Display Begin written by M68K: 35
415 TOM: Vertical Display End written by M68K: 2047
416 Horizontal range: 157 - 1713 (width: 1557 / 4 = 389.25, / 5 = 315.4)
419 TOM: Horizontal Period written by M68K: 845 (+1*2 = 1692)
420 TOM: Horizontal Blank Begin written by M68K: 1700
421 TOM: Horizontal Blank End written by M68K: 122
422 TOM: Horizontal Display End written by M68K: 1600
423 TOM: Horizontal Display Begin 1 written by M68K: 268
424 TOM: Vertical Period written by M68K: 523 (non-interlaced)
425 TOM: Vertical Blank End written by M68K: 40
426 TOM: Vertical Display Begin written by M68K: 44
427 TOM: Vertical Display End written by M68K: 492
428 TOM: Vertical Blank Begin written by M68K: 532
429 TOM: Vertical Sync written by M68K: 513
430 TOM: Video Mode written by M68K: 04C7. PWIDTH = 3, MODE = 16 BPP RGB, flags: BGEN (VC = 461)
433 TOM: Horizontal Display End written by M68K: 1713
434 TOM: Horizontal Display Begin 1 written by M68K: 157
435 TOM: Vertical Display Begin written by M68K: 35
436 TOM: Vertical Display End written by M68K: 2047
437 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 89)
438 TOM: Horizontal Display Begin 1 written by M68K: 208
439 TOM: Horizontal Display End written by M68K: 1662
440 TOM: Vertical Display Begin written by M68K: 100
441 TOM: Vertical Display End written by M68K: 2047
442 TOM: Video Mode written by M68K: 07C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN VARMOD (VC = 205)
443 Horizontal range: 208 - 1662 (width: 1455 / 4 = 363.5)
446 TOM: Vertical Display Begin written by M68K: 96
447 TOM: Vertical Display End written by M68K: 2047
448 TOM: Horizontal Display Begin 1 written by M68K: 239
449 TOM: Horizontal Display End written by M68K: 1692
450 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 378)
451 TOM: Vertical Display Begin written by M68K: 44
452 TOM: Vertical Display End written by M68K: 2047
453 TOM: Horizontal Display Begin 1 written by M68K: 239
454 TOM: Horizontal Display End written by M68K: 1692
455 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 559)
456 TOM: Vertical Display Begin written by M68K: 84
457 TOM: Vertical Display End written by M68K: 2047
458 TOM: Horizontal Display Begin 1 written by M68K: 239
459 TOM: Horizontal Display End written by M68K: 1692
460 TOM: Vertical Display Begin written by M68K: 44
461 TOM: Vertical Display End written by M68K: 2047
462 TOM: Horizontal Display Begin 1 written by M68K: 239
463 TOM: Horizontal Display End written by M68K: 1692
464 Horizontal range: 239 - 1692 (width: 1454 / 4 = 363.5)
468 // Screen info for various games [NTSC]...
471 TOM: Horizontal Display End written by M68K: 1727
472 TOM: Horizontal Display Begin 1 written by M68K: 123
473 TOM: Vertical Display Begin written by M68K: 25
474 TOM: Vertical Display End written by M68K: 2047
475 TOM: Video Mode written by M68K: 0EC1. PWIDTH = 8, MODE = 16 BPP CRY, flags: BGEN (VC = 5)
476 Also does PWIDTH = 4...
477 Vertical resolution: 238 lines
480 TOM: Horizontal Display End written by M68K: 1727
481 TOM: Horizontal Display Begin 1 written by M68K: 123
482 TOM: Vertical Display Begin written by M68K: 25
483 TOM: Vertical Display End written by M68K: 2047
484 TOM: Vertical Interrupt written by M68K: 507
485 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 92)
486 TOM: Horizontal Display Begin 1 written by M68K: 208
487 TOM: Horizontal Display End written by M68K: 1670
488 Display starts at 31, then 52!
489 Vertical resolution: 238 lines
492 TOM: Horizontal Display End written by M68K: 1727
493 TOM: Horizontal Display Begin 1 written by M68K: 123
494 TOM: Vertical Display Begin written by M68K: 25
495 TOM: Vertical Display End written by M68K: 2047
496 TOM: Video Mode written by GPU: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 4)
497 TOM: Video Mode written by GPU: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 508)
498 Display starts at 31 (PWIDTH = 4), 24 (PWIDTH = 5)
501 TOM: Vertical Interrupt written by M68K: 2047
502 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 0)
503 TOM: Horizontal Display End written by M68K: 1727
504 TOM: Horizontal Display Begin 1 written by M68K: 123
505 TOM: Vertical Display Begin written by M68K: 25
506 TOM: Vertical Display End written by M68K: 2047
507 TOM: Vertical Interrupt written by M68K: 507
508 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 369)
509 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 510)
510 TOM: Video Mode written by M68K: 06C3. PWIDTH = 4, MODE = 24 BPP RGB, flags: BGEN (VC = 510)
512 Vertical resolution: 238 lines
513 [Seems to be a problem between the horizontal positioning of the 16-bit CRY & 24-bit RGB]
516 TOM: Horizontal Period written by M68K: 844 (+1*2 = 1690)
517 TOM: Horizontal Blank Begin written by M68K: 1713
518 TOM: Horizontal Blank End written by M68K: 125
519 TOM: Horizontal Display End written by M68K: 1696
520 TOM: Horizontal Display Begin 1 written by M68K: 166
521 TOM: Vertical Period written by M68K: 523 (non-interlaced)
522 TOM: Vertical Blank End written by M68K: 24
523 TOM: Vertical Display Begin written by M68K: 46
524 TOM: Vertical Display End written by M68K: 496
525 TOM: Vertical Blank Begin written by M68K: 500
526 TOM: Vertical Sync written by M68K: 517
527 TOM: Vertical Interrupt written by M68K: 497
528 TOM: Video Mode written by M68K: 04C1. PWIDTH = 3, MODE = 16 BPP CRY, flags: BGEN (VC = 270)
532 TOM: Horizontal Display End written by M68K: 1727
533 TOM: Horizontal Display Begin 1 written by M68K: 123
534 TOM: Vertical Display Begin written by M68K: 25
535 TOM: Vertical Display End written by M68K: 2047
536 TOM: Vertical Interrupt written by M68K: 507
537 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 9)
540 TOM: Horizontal Display End written by M68K: 1823
541 TOM: Horizontal Display Begin 1 written by M68K: 45
542 TOM: Vertical Display Begin written by M68K: 40
543 TOM: Vertical Display End written by M68K: 2047
544 TOM: Vertical Interrupt written by M68K: 491
545 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 398)
546 Display starts at 11 (123 - 45 = 78, 78 / 4 = 19 pixels to skip)
547 Width is 417, so maybe width of 379 would be good (starting at 123, ending at 1639)
548 Vertical resolution: 238 lines
551 TOM: Horizontal Display End written by M68K: 1727
552 TOM: Horizontal Display Begin 1 written by M68K: 188
553 TOM: Vertical Display Begin written by M68K: 1
554 TOM: Vertical Display End written by M68K: 2047
555 TOM: Vertical Interrupt written by M68K: 483
556 TOM: Video Mode written by M68K: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 99)
557 Width would be 303 with above scheme, but border width would be 13 pixels
560 Vertical resolution: 238 lines
563 uint32_t RGB16ToRGB32[0x10000];
564 uint32_t CRY16ToRGB32[0x10000];
565 uint32_t MIX16ToRGB32[0x10000];
568 #warning "This is not endian-safe. !!! FIX !!!"
569 void TOMFillLookupTables(void)
571 // NOTE: Jaguar 16-bit (non-CRY) color is RBG 556 like so:
572 // RRRR RBBB BBGG GGGG
573 for(uint32_t i=0; i<0x10000; i++)
574 //hm. RGB16ToRGB32[i] = 0xFF000000
575 // | ((i & 0xF100) >> 8) | ((i & 0xE000) >> 13)
576 // | ((i & 0x07C0) << 13) | ((i & 0x0700) << 8)
577 // | ((i & 0x003F) << 10) | ((i & 0x0030) << 4);
578 RGB16ToRGB32[i] = 0x000000FF
579 // | ((i & 0xF100) << 16) // Red
580 | ((i & 0xF800) << 16) // Red
581 | ((i & 0x003F) << 18) // Green
582 | ((i & 0x07C0) << 5); // Blue
584 for(uint32_t i=0; i<0x10000; i++)
586 uint32_t cyan = (i & 0xF000) >> 12,
587 red = (i & 0x0F00) >> 8,
588 intensity = (i & 0x00FF);
590 uint32_t r = (((uint32_t)redcv[cyan][red]) * intensity) >> 8,
591 g = (((uint32_t)greencv[cyan][red]) * intensity) >> 8,
592 b = (((uint32_t)bluecv[cyan][red]) * intensity) >> 8;
594 //hm. CRY16ToRGB32[i] = 0xFF000000 | (b << 16) | (g << 8) | r;
595 CRY16ToRGB32[i] = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
596 MIX16ToRGB32[i] = (i & 0x01 ? RGB16ToRGB32[i] : CRY16ToRGB32[i]);
601 void TOMSetPendingJERRYInt(void)
603 tom_jerry_int_pending = 1;
607 void TOMSetPendingTimerInt(void)
609 tom_timer_int_pending = 1;
613 void TOMSetPendingObjectInt(void)
615 tom_object_int_pending = 1;
619 void TOMSetPendingGPUInt(void)
621 tom_gpu_int_pending = 1;
625 void TOMSetPendingVideoInt(void)
627 tom_video_int_pending = 1;
631 uint8_t * TOMGetRamPointer(void)
637 uint8_t TOMGetVideoMode(void)
639 uint16_t vmode = GET16(tomRam8, VMODE);
640 return ((vmode & VARMOD) >> 6) | ((vmode & MODE) >> 1);
644 //Used in only one place (and for debug purposes): OBJECTP.CPP
645 #warning "Used in only one place (and for debug purposes): OBJECTP.CPP !!! FIX !!!"
646 uint16_t TOMGetVDB(void)
648 return GET16(tomRam8, VDB);
654 // 16 BPP CRY/RGB mixed mode rendering
656 void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer)
658 //CHANGED TO 32BPP RENDERING
659 uint16_t width = tomWidth;
660 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
662 //New stuff--restrict our drawing...
663 uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
664 //NOTE: May have to check HDB2 as well!
665 // Get start position in HC ticks
666 int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);
671 // This is x2 because current_line_buffer is uint8_t & we're in a 16bpp mode
672 current_line_buffer += 2 * -startPos;
674 //This case doesn't properly handle the "start on the right side of virtual screen" case
675 //Dunno why--looks Ok...
676 //What *is* for sure wrong is that it doesn't copy the linebuffer's BG pixels... [FIXED NOW]
677 //This should likely be 4 instead of 2 (?--not sure)
678 // Actually, there should be NO multiplier, as startPos is expressed in PIXELS
679 // and so is the backbuffer.
682 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
683 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
685 for(int16_t i=0; i<startPos; i++)
686 *backbuffer++ = pixel;
691 backbuffer += 2 * startPos, width -= startPos;
696 uint16_t color = (*current_line_buffer++) << 8;
697 color |= *current_line_buffer++;
698 *backbuffer++ = MIX16ToRGB32[color];
705 // 16 BPP CRY mode rendering
707 void tom_render_16bpp_cry_scanline(uint32_t * backbuffer)
709 //CHANGED TO 32BPP RENDERING
710 uint16_t width = tomWidth;
711 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
713 //New stuff--restrict our drawing...
714 uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
715 //NOTE: May have to check HDB2 as well!
716 int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);// Get start position in HC ticks
719 current_line_buffer += 2 * -startPos;
723 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
724 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
726 for(int16_t i=0; i<startPos; i++)
727 *backbuffer++ = pixel;
732 //This should likely be 4 instead of 2 (?--not sure)
733 backbuffer += 2 * startPos, width -= startPos;
738 uint16_t color = (*current_line_buffer++) << 8;
739 color |= *current_line_buffer++;
740 *backbuffer++ = CRY16ToRGB32[color];
747 // 24 BPP mode rendering
749 void tom_render_24bpp_scanline(uint32_t * backbuffer)
751 //CHANGED TO 32BPP RENDERING
752 uint16_t width = tomWidth;
753 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
755 //New stuff--restrict our drawing...
756 uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
757 //NOTE: May have to check HDB2 as well!
758 int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks
761 current_line_buffer += 4 * -startPos;
765 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
766 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
768 for(int16_t i=0; i<startPos; i++)
769 *backbuffer++ = pixel;
774 //This should likely be 4 instead of 2 (?--not sure)
775 backbuffer += 2 * startPos, width -= startPos;
780 uint32_t g = *current_line_buffer++;
781 uint32_t r = *current_line_buffer++;
782 current_line_buffer++;
783 uint32_t b = *current_line_buffer++;
784 //hm. *backbuffer++ = 0xFF000000 | (b << 16) | (g << 8) | r;
785 *backbuffer++ = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
791 //Seems to me that this is NOT a valid mode--the JTRM seems to imply that you would need
792 //extra hardware outside of the Jaguar console to support this!
794 // 16 BPP direct mode rendering
796 void tom_render_16bpp_direct_scanline(uint32_t * backbuffer)
798 uint16_t width = tomWidth;
799 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
803 uint16_t color = (*current_line_buffer++) << 8;
804 color |= *current_line_buffer++;
805 *backbuffer++ = color >> 1;
812 // 16 BPP RGB mode rendering
814 void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer)
816 //CHANGED TO 32BPP RENDERING
817 // 16 BPP RGB: 0-5 green, 6-10 blue, 11-15 red
819 uint16_t width = tomWidth;
820 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
822 //New stuff--restrict our drawing...
823 uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
824 //NOTE: May have to check HDB2 as well!
825 int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks
829 current_line_buffer += 2 * -startPos;
833 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
834 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
836 for(int16_t i=0; i<startPos; i++)
837 *backbuffer++ = pixel;
842 //This should likely be 4 instead of 2 (?--not sure)
843 backbuffer += 2 * startPos, width -= startPos;
848 uint32_t color = (*current_line_buffer++) << 8;
849 color |= *current_line_buffer++;
850 *backbuffer++ = RGB16ToRGB32[color];
857 // Process a single scanline
858 // (this is bad terminology; each tick of the VC is actually a half-line)
860 void TOMExecHalfline(uint16_t halfline, bool render)
862 #warning "!!! Need to handle multiple fields properly !!!"
863 // We ignore the problem for now
866 bool inActiveDisplayArea = true;
868 //Interlacing is still not handled correctly here... !!! FIX !!!
869 if (halfline & 0x01) // Execute OP only on even halflines (non-interlaced only!)
872 //Hm, it seems that the OP needs to execute from zero, so let's try it:
873 // And it works! But need to do some optimizations in the OP to keep it from attempting
874 // to do a scanline render in the non-display area... [DONE]
875 //this seems to cause a regression in certain games, like rayman
876 //which means I have to dig thru the asic nets to see what's wrong...
878 No, the OP doesn't start until VDB, that much is certain. The thing is, VDB is the
879 HALF line that the OP starts on--which means that it needs to start at VDB / 2!!!
881 Hrm, doesn't seem to be enough, though it should be... still sticks for 20 frames.
884 What triggers this is writing $FFFF to VDE. This causes the OP start signal in VID to
885 latch on, which in effect sets VDB to zero. So that much is correct. But the thing with
886 Rayman is that it shouldn't cause the graphical glitches seen there, so still have to
887 investigate what's going on there. By all rights, it shouldn't glitch because:
889 00006C00: 0000000D 82008F73 (BRANCH) YPOS=494, CC=">", link=$00006C10
890 00006C08: 000003FF 00008173 (BRANCH) YPOS=46, CC=">", link=$001FF800
891 00006C10: 00000000 0000000C (STOP)
892 001FF800: 12FC2BFF 02380000 (BITMAP)
895 Even if the OP is running all the time, the link should tell it to stop at the right
896 place (which it seems to do). But we still get glitchy screen.
898 Seems the glitchy screen went away... Maybe the GPU alignment fixes fixed it???
899 Just need to add the proper checking here then.
901 Some numbers, courtesy of the Jaguar BIOS:
903 VP, 523 // Vertical Period (1-based; in this case VP = 524)
904 VBE, 24 // Vertical Blank End
905 VDB, 38 // Vertical Display Begin
906 VDE, 518 // Vertical Display End
907 VBB, 500 // Vertical Blank Begin
908 VS, 517 // Vertical Sync
911 VP, 623 // Vertical Period (1-based; in this case VP = 624)
912 VBE, 34 // Vertical Blank End
913 VDB, 38 // Vertical Display Begin
914 VDE, 518 // Vertical Display End
915 VBB, 600 // Vertical Blank Begin
916 VS, 618 // Vertical Sync
918 Numbers for KM, NTSC:
919 KM: (Note that with VDE <= 507, the OP starts at VDB as expected)
920 TOM: Vertical Display Begin written by M68K: 41
921 TOM: Vertical Display End written by M68K: 2047
922 TOM: Vertical Interrupt written by M68K: 491
925 // Initial values that "well behaved" programs use
926 uint16_t startingHalfline = GET16(tomRam8, VDB);
927 uint16_t endingHalfline = GET16(tomRam8, VDE);
929 // Simulate the OP start bug here!
930 // Really, this value is somewhere around 507 for an NTSC Jaguar. But this
931 // should work in a majority of cases, at least until we can figure it out properly.
932 if (endingHalfline > GET16(tomRam8, VP))
933 startingHalfline = 0;
935 if (halfline >= startingHalfline && halfline < endingHalfline)
936 // if (halfline >= 0 && halfline < (uint16_t)GET16(tomRam8, VDE))
937 // 16 isn't enough, and neither is 32 for raptgun. 32 fucks up Rayman
938 // if (halfline >= ((uint16_t)GET16(tomRam8, VDB) / 2) && halfline < ((uint16_t)GET16(tomRam8, VDE) / 2))
939 // if (halfline >= ((uint16_t)GET16(tomRam8, VDB) - 16) && halfline < (uint16_t)GET16(tomRam8, VDE))
940 // if (halfline >= 20 && halfline < (uint16_t)GET16(tomRam8, VDE))
941 // if (halfline >= (uint16_t)GET16(tomRam8, VDB) && halfline < (uint16_t)GET16(tomRam8, VDE))
945 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
946 uint8_t bgHI = tomRam8[BG], bgLO = tomRam8[BG + 1];
948 // Clear line buffer with BG
949 if (GET16(tomRam8, VMODE) & BGEN) // && (CRY or RGB16)...
950 for(uint32_t i=0; i<720; i++)
951 *current_line_buffer++ = bgHI, *current_line_buffer++ = bgLO;
953 OPProcessList(halfline, render);
957 inActiveDisplayArea = false;
959 inActiveDisplayArea =
960 (halfline >= (uint16_t)GET16(tomRam8, VDB) && halfline < (uint16_t)GET16(tomRam8, VDE)
963 if (halfline < (uint16_t)GET16(tomRam8, VDE))
965 if (render)//With JaguarExecuteNew() this is always true...
967 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
968 uint8_t bgHI = tomRam8[BG], bgLO = tomRam8[BG + 1];
970 // Clear line buffer with BG
971 if (GET16(tomRam8, VMODE) & BGEN) // && (CRY or RGB16)...
972 for(uint32_t i=0; i<720; i++)
973 *current_line_buffer++ = bgHI, *current_line_buffer++ = bgLO;
975 // OPProcessList(halfline, render);
976 //This seems to take care of it...
977 OPProcessList(halfline, inActiveDisplayArea);
982 // Try to take PAL into account... [We do now!]
984 uint16_t topVisible = (vjs.hardwareTypeNTSC ? TOP_VISIBLE_VC : TOP_VISIBLE_VC_PAL),
985 bottomVisible = (vjs.hardwareTypeNTSC ? BOTTOM_VISIBLE_VC : BOTTOM_VISIBLE_VC_PAL);
986 uint32_t * TOMCurrentLine = &(screenBuffer[((halfline - topVisible) / 2) * screenPitch]);
988 // Here's our virtualized scanline code...
990 if (halfline >= topVisible && halfline < bottomVisible)
992 if (inActiveDisplayArea)
994 //NOTE: The following doesn't put BORDER color on the sides... !!! FIX !!!
995 #warning "The following doesn't put BORDER color on the sides... !!! FIX !!!"
996 if (vjs.renderType == RT_NORMAL)
997 // scanline_render[TOMGetVideoMode()](TOMBackbuffer);
998 scanline_render[TOMGetVideoMode()](TOMCurrentLine);
1002 tom_render_16bpp_cry_scanline,
1003 tom_render_24bpp_scanline,
1004 tom_render_16bpp_direct_scanline,
1005 tom_render_16bpp_rgb_scanline,
1006 tom_render_16bpp_cry_rgb_mix_scanline,
1007 tom_render_24bpp_scanline,
1008 tom_render_16bpp_direct_scanline,
1009 tom_render_16bpp_rgb_scanline
1011 #define MODE 0x0006 // Line buffer to video generator mode
1012 #define VARMOD 0x0100 // Mixed CRY/RGB16 mode (only works in MODE 0!)
1014 uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1015 uint8_t mode = ((GET16(tomRam8, VMODE) & MODE) >> 1);
1016 bool varmod = GET16(tomRam8, VMODE) & VARMOD;
1017 //The video texture line buffer ranges from 0 to 1279, with its left edge starting at
1018 //LEFT_VISIBLE_HC. So, we need to start writing into the backbuffer at HDB1, using pwidth
1019 //as our scaling factor. The way it generates its image on a real TV!
1021 //So, for example, if HDB1 is less than LEFT_VISIBLE_HC, then we have to figure out where
1022 //in the VTLB that we start writing pixels from the Jaguar line buffer (VTLB start=0,
1026 // 24 BPP mode rendering
1028 void tom_render_24bpp_scanline(uint32_t * backbuffer)
1030 //CHANGED TO 32BPP RENDERING
1031 uint16_t width = tomWidth;
1032 uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
1034 //New stuff--restrict our drawing...
1035 uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1036 //NOTE: May have to check HDB2 as well!
1037 int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks
1040 current_line_buffer += 4 * -startPos;
1042 //This should likely be 4 instead of 2 (?--not sure)
1043 backbuffer += 2 * startPos, width -= startPos;
1047 uint32_t g = *current_line_buffer++;
1048 uint32_t r = *current_line_buffer++;
1049 current_line_buffer++;
1050 uint32_t b = *current_line_buffer++;
1051 *backbuffer++ = 0xFF000000 | (b << 16) | (g << 8) | r;
1061 // If outside of VDB & VDE, then display the border color
1062 uint32_t * currentLineBuffer = TOMCurrentLine;
1063 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
1064 //Hm. uint32_t pixel = 0xFF000000 | (b << 16) | (g << 8) | r;
1065 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
1067 for(uint32_t i=0; i<tomWidth; i++)
1068 *currentLineBuffer++ = pixel;
1075 // TOM initialization
1079 TOMFillLookupTables();
1088 TOMDumpIORegistersToLog();
1091 WriteLog("TOM: Resolution %i x %i %s\n", TOMGetVideoModeWidth(), TOMGetVideoModeHeight(),
1092 videoMode_to_str[TOMGetVideoMode()]);
1093 // WriteLog("\ntom: object processor:\n");
1094 // WriteLog("tom: pointer to object list: 0x%.8x\n",op_get_list_pointer());
1095 // WriteLog("tom: INT1=0x%.2x%.2x\n",TOMReadByte(0xf000e0),TOMReadByte(0xf000e1));
1099 uint32_t TOMGetVideoModeWidth(void)
1101 //These widths are pretty bogus. Should use HDB1/2 & HDE/HBB & PWIDTH to calc the width...
1102 // uint32_t width[8] = { 1330, 665, 443, 332, 266, 222, 190, 166 };
1103 //Temporary, for testing Doom...
1104 // uint32_t width[8] = { 1330, 665, 443, 332, 266, 222, 190, 332 };
1106 // Note that the following PWIDTH values have the following pixel aspect ratios:
1107 // PWIDTH = 1 -> 0.25:1 (1:4) pixels (X:Y ratio)
1108 // PWIDTH = 2 -> 0.50:1 (1:2) pixels
1109 // PWIDTH = 3 -> 0.75:1 (3:4) pixels
1110 // PWIDTH = 4 -> 1.00:1 (1:1) pixels
1111 // PWIDTH = 5 -> 1.25:1 (5:4) pixels
1112 // PWIDTH = 6 -> 1.50:1 (3:2) pixels
1113 // PWIDTH = 7 -> 1.75:1 (7:4) pixels
1114 // PWIDTH = 8 -> 2.00:1 (2:1) pixels
1116 // Also note that the JTRM says that PWIDTH of 4 gives pixels that are "about" square--
1117 // this implies that the other modes have pixels that are *not* square!
1118 // Also, I seriously doubt that you will see any games that use PWIDTH = 1!
1120 // NOTE: Even though the PWIDTH value is + 1, here we're using a zero-based index and
1121 // so we don't bother to add one...
1122 // return width[(GET16(tomRam8, VMODE) & PWIDTH) >> 9];
1124 // Now, we just calculate it...
1125 /* uint16_t hdb1 = GET16(tomRam8, HDB1), hde = GET16(tomRam8, HDE),
1126 hbb = GET16(tomRam8, HBB), pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1127 // return ((hbb < hde ? hbb : hde) - hdb1) / pwidth;
1128 //Temporary, for testing Doom...
1129 return ((hbb < hde ? hbb : hde) - hdb1) / (pwidth == 8 ? 4 : pwidth);*/
1131 // To make it easier to make a quasi-fixed display size, we restrict the viewing
1132 // area to an arbitrary range of the Horizontal Count.
1133 uint16_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1134 return (vjs.hardwareTypeNTSC ? RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC : RIGHT_VISIBLE_HC_PAL - LEFT_VISIBLE_HC_PAL) / pwidth;
1135 //Temporary, for testing Doom...
1136 // return (RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC) / (pwidth == 8 ? 4 : pwidth);
1137 //// return (RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC) / (pwidth == 4 ? 8 : pwidth);
1139 // More speculating...
1140 // According to the JTRM, the number of potential pixels across is given by the
1141 // Horizontal Period (HP - in NTSC this is 845). The Horizontal Count counts from
1142 // zero to this value twice per scanline (the high bit is set on the second count).
1143 // HBE and HBB define the absolute "black" limits of the screen, while HDB1/2 and
1144 // HDE determine the extent of the OP "on" time. I.e., when the OP is turned on by
1145 // HDB1, it starts fetching the line from position 0 in LBUF.
1147 // The trick, it would seem, is to figure out how long the typical visible scanline
1148 // of a TV is in HP ticks and limit the visible area to that (divided by PWIDTH, of
1149 // course). Using that length, we can establish an "absolute left display limit" with
1150 // which to measure HBB & HDB1/2 against when rendering LBUF (i.e., if HDB1 is 20 ticks
1151 // to the right of the ALDL and PWIDTH is 4, then start writing the LBUF starting at
1152 // backbuffer + 5 pixels).
1154 // That's basically what we're doing now...!
1158 // *** SPECULATION ***
1159 // It might work better to virtualize the height settings, i.e., set the vertical
1160 // height at 240 lines and clip using the VDB and VDE/VP registers...
1161 // Same with the width... [Width is pretty much virtualized now.]
1163 // Now that that the width is virtualized, let's virtualize the height. :-)
1164 uint32_t TOMGetVideoModeHeight(void)
1166 // uint16_t vmode = GET16(tomRam8, VMODE);
1167 // uint16_t vbe = GET16(tomRam8, VBE);
1168 // uint16_t vbb = GET16(tomRam8, VBB);
1169 // uint16_t vdb = GET16(tomRam8, VDB);
1170 // uint16_t vde = GET16(tomRam8, VDE);
1171 // uint16_t vp = GET16(tomRam8, VP);
1173 /* if (vde == 0xFFFF)
1176 // return 227;//WAS:(vde/*-vdb*/) >> 1;
1177 // The video mode height probably works this way:
1178 // VC counts from 0 to VP. VDB starts the OP. Either when
1179 // VDE is reached or VP, the OP is stopped. Let's try it...
1180 // Also note that we're conveniently ignoring interlaced display modes...!
1181 // return ((vde > vp ? vp : vde) - vdb) >> 1;
1182 // return ((vde > vbb ? vbb : vde) - vdb) >> 1;
1183 //Let's try from the Vertical Blank interval...
1185 // return (vbb - vbe) >> 1; // Again, doesn't take interlacing into account...
1186 // This of course doesn't take interlacing into account. But I haven't seen any
1187 // Jaguar software that takes advantage of it either...
1188 //Also, doesn't reflect PAL Jaguar either... !!! FIX !!! [DONE]
1189 // return 240; // Set virtual screen height to 240 lines...
1190 return (vjs.hardwareTypeNTSC ? 240 : 256);
1196 // Now PAL friendly!
1199 The values in TOMReset come from the Jaguar BIOS.
1200 These values are from BJL:
1246 memset(tomRam8, 0x00, 0x4000);
1248 if (vjs.hardwareTypeNTSC)
1250 SET16(tomRam8, MEMCON1, 0x1861);
1251 // SET16(tomRam8, MEMCON1, 0x1865);//Bunch of BS
1252 SET16(tomRam8, MEMCON2, 0x35CC);
1253 SET16(tomRam8, HP, 844); // Horizontal Period (1-based; HP=845)
1254 SET16(tomRam8, HBB, 1713); // Horizontal Blank Begin
1255 SET16(tomRam8, HBE, 125); // Horizontal Blank End
1256 SET16(tomRam8, HDE, 1665); // Horizontal Display End
1257 SET16(tomRam8, HDB1, 203); // Horizontal Display Begin 1
1258 SET16(tomRam8, VP, 523); // Vertical Period (1-based; in this case VP = 524)
1259 SET16(tomRam8, VBE, 24); // Vertical Blank End
1260 SET16(tomRam8, VDB, 38); // Vertical Display Begin
1261 SET16(tomRam8, VDE, 518); // Vertical Display End
1262 SET16(tomRam8, VBB, 500); // Vertical Blank Begin
1263 SET16(tomRam8, VS, 517); // Vertical Sync
1264 SET16(tomRam8, VMODE, 0x06C1);
1268 SET16(tomRam8, MEMCON1, 0x1861);
1269 SET16(tomRam8, MEMCON2, 0x35CC);
1270 SET16(tomRam8, HP, 850); // Horizontal Period
1271 SET16(tomRam8, HBB, 1711); // Horizontal Blank Begin
1272 SET16(tomRam8, HBE, 158); // Horizontal Blank End
1273 SET16(tomRam8, HDE, 1665); // Horizontal Display End
1274 SET16(tomRam8, HDB1, 203); // Horizontal Display Begin 1
1275 SET16(tomRam8, VP, 623); // Vertical Period (1-based; in this case VP = 624)
1276 SET16(tomRam8, VBE, 34); // Vertical Blank End
1277 SET16(tomRam8, VDB, 38); // Vertical Display Begin
1278 SET16(tomRam8, VDE, 518); // Vertical Display End
1279 SET16(tomRam8, VBB, 600); // Vertical Blank Begin
1280 SET16(tomRam8, VS, 618); // Vertical Sync
1281 SET16(tomRam8, VMODE, 0x06C1);
1287 tom_jerry_int_pending = 0;
1288 tom_timer_int_pending = 0;
1289 tom_object_int_pending = 0;
1290 tom_gpu_int_pending = 0;
1291 tom_video_int_pending = 0;
1293 tomTimerPrescaler = 0; // TOM PIT is disabled
1294 tomTimerDivider = 0;
1295 tomTimerCounter = 0;
1300 // Dump all TOM register values to the log
1302 void TOMDumpIORegistersToLog(void)
1304 WriteLog("\n\n---------------------------------------------------------------------\n");
1305 WriteLog("TOM I/O Registers\n");
1306 WriteLog("---------------------------------------------------------------------\n");
1307 WriteLog("F000%02X (MEMCON1): $%04X\n", MEMCON1, GET16(tomRam8, MEMCON1));
1308 WriteLog("F000%02X (MEMCON2): $%04X\n", MEMCON2, GET16(tomRam8, MEMCON2));
1309 WriteLog("F000%02X (HC): $%04X\n", HC, GET16(tomRam8, HC));
1310 WriteLog("F000%02X (VC): $%04X\n", VC, GET16(tomRam8, VC));
1311 WriteLog("F000%02X (OLP): $%08X\n", OLP, GET32(tomRam8, OLP));
1312 WriteLog("F000%02X (OBF): $%04X\n", OBF, GET16(tomRam8, OBF));
1313 WriteLog("F000%02X (VMODE): $%04X\n", VMODE, GET16(tomRam8, VMODE));
1314 WriteLog("F000%02X (BORD1): $%04X\n", BORD1, GET16(tomRam8, BORD1));
1315 WriteLog("F000%02X (BORD2): $%04X\n", BORD2, GET16(tomRam8, BORD2));
1316 WriteLog("F000%02X (HP): $%04X\n", HP, GET16(tomRam8, HP));
1317 WriteLog("F000%02X (HBB): $%04X\n", HBB, GET16(tomRam8, HBB));
1318 WriteLog("F000%02X (HBE): $%04X\n", HBE, GET16(tomRam8, HBE));
1319 WriteLog("F000%02X (HS): $%04X\n", HS, GET16(tomRam8, HS));
1320 WriteLog("F000%02X (HVS): $%04X\n", HVS, GET16(tomRam8, HVS));
1321 WriteLog("F000%02X (HDB1): $%04X\n", HDB1, GET16(tomRam8, HDB1));
1322 WriteLog("F000%02X (HDB2): $%04X\n", HDB2, GET16(tomRam8, HDB2));
1323 WriteLog("F000%02X (HDE): $%04X\n", HDE, GET16(tomRam8, HDE));
1324 WriteLog("F000%02X (VP): $%04X\n", VP, GET16(tomRam8, VP));
1325 WriteLog("F000%02X (VBB): $%04X\n", VBB, GET16(tomRam8, VBB));
1326 WriteLog("F000%02X (VBE): $%04X\n", VBE, GET16(tomRam8, VBE));
1327 WriteLog("F000%02X (VS): $%04X\n", VS, GET16(tomRam8, VS));
1328 WriteLog("F000%02X (VDB): $%04X\n", VDB, GET16(tomRam8, VDB));
1329 WriteLog("F000%02X (VDE): $%04X\n", VDE, GET16(tomRam8, VDE));
1330 WriteLog("F000%02X (VEB): $%04X\n", VEB, GET16(tomRam8, VEB));
1331 WriteLog("F000%02X (VEE): $%04X\n", VEE, GET16(tomRam8, VEE));
1332 WriteLog("F000%02X (VI): $%04X\n", VI, GET16(tomRam8, VI));
1333 WriteLog("F000%02X (PIT0): $%04X\n", PIT0, GET16(tomRam8, PIT0));
1334 WriteLog("F000%02X (PIT1): $%04X\n", PIT1, GET16(tomRam8, PIT1));
1335 WriteLog("F000%02X (HEQ): $%04X\n", HEQ, GET16(tomRam8, HEQ));
1336 WriteLog("F000%02X (BG): $%04X\n", BG, GET16(tomRam8, BG));
1337 WriteLog("F000%02X (INT1): $%04X\n", INT1, GET16(tomRam8, INT1));
1338 WriteLog("F000%02X (INT2): $%04X\n", INT2, GET16(tomRam8, INT2));
1339 WriteLog("---------------------------------------------------------------------\n\n\n");
1344 // TOM byte access (read)
1346 uint8_t TOMReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1348 //???Is this needed???
1349 // It seems so. Perhaps it's the +$8000 offset being written to (32-bit interface)?
1350 // However, the 32-bit interface is WRITE ONLY, so that can't be it...
1351 // Also, the 68K CANNOT make use of the 32-bit interface, since its bus width is only 16-bits...
1352 // offset &= 0xFF3FFF;
1355 WriteLog("TOM: Reading byte at %06X for %s\n", offset, whoName[who]);
1358 if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1359 return GPUReadByte(offset, who);
1360 else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1361 return GPUReadByte(offset, who);
1362 /* else if ((offset >= 0xF00010) && (offset < 0xF00028))
1363 return OPReadByte(offset, who);*/
1364 else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1365 return BlitterReadByte(offset, who);
1366 else if (offset == 0xF00050)
1367 return tomTimerPrescaler >> 8;
1368 else if (offset == 0xF00051)
1369 return tomTimerPrescaler & 0xFF;
1370 else if (offset == 0xF00052)
1371 return tomTimerDivider >> 8;
1372 else if (offset == 0xF00053)
1373 return tomTimerDivider & 0xFF;
1375 return tomRam8[offset & 0x3FFF];
1380 // TOM word access (read)
1382 uint16_t TOMReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1384 //???Is this needed???
1385 // offset &= 0xFF3FFF;
1387 WriteLog("TOM: Reading word at %06X for %s\n", offset, whoName[who]);
1389 if (offset >= 0xF02000 && offset <= 0xF020FF)
1390 WriteLog("TOM: ReadWord attempted from GPU register file by %s (unimplemented)!\n", whoName[who]);
1392 if (offset == 0xF000E0)
1394 // For reading, should only return the lower 5 bits...
1395 uint16_t data = (tom_jerry_int_pending << 4) | (tom_timer_int_pending << 3)
1396 | (tom_object_int_pending << 2) | (tom_gpu_int_pending << 1)
1397 | (tom_video_int_pending << 0);
1398 //WriteLog("tom: interrupt status is 0x%.4x \n",data);
1401 //Shoud be handled by the jaguar main loop now... And it is! ;-)
1402 /* else if (offset == 0xF00006) // VC
1403 // What if we're in interlaced mode?
1404 // According to docs, in non-interlace mode VC is ALWAYS even...
1405 // return (tom_scanline << 1);// + 1;
1406 //But it's causing Rayman to be fucked up... Why???
1407 //Because VC is even in NI mode when calling the OP! That's why!
1408 return (tom_scanline << 1) + 1;//*/
1410 // F00004 R/W -----xxx xxxxxxxx HC - horizontal count
1411 // -----x-- -------- (which half of the display)
1412 // ------xx xxxxxxxx (10-bit counter)
1414 // This is a kludge to get the HC working somewhat... What we really should do here
1415 // is check what the global time is at the time of the read and calculate the correct HC...
1417 else if (offset == 0xF00004)
1418 return rand() & 0x03FF;
1419 else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE + 0x20))
1420 return GPUReadWord(offset, who);
1421 else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000))
1422 return GPUReadWord(offset, who);
1423 /* else if ((offset >= 0xF00010) && (offset < 0xF00028))
1424 return OPReadWord(offset, who);*/
1425 else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1426 return BlitterReadWord(offset, who);
1427 else if (offset == 0xF00050)
1428 return tomTimerPrescaler;
1429 else if (offset == 0xF00052)
1430 return tomTimerDivider;
1433 return (TOMReadByte(offset, who) << 8) | TOMReadByte(offset + 1, who);
1437 #define TOM_STRICT_MEMORY_ACCESS
1439 // TOM byte access (write)
1441 void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
1443 // Moved here tentatively, so we can see everything written to TOM.
1444 tomRam8[offset & 0x3FFF] = data;
1447 WriteLog("TOM: Writing byte %02X at %06X", data, offset);
1449 //???Is this needed???
1450 // Perhaps on the writes--32-bit writes that is! And masked with FF7FFF...
1451 #ifndef TOM_STRICT_MEMORY_ACCESS
1454 // "Fast" (32-bit only) write access to the GPU
1455 // if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF))
1456 if ((offset >= 0xF08000) && (offset <= 0xF0BFFF))
1460 WriteLog(" -->[%06X] by %s\n", offset, whoName[who]);
1463 #ifdef TOM_STRICT_MEMORY_ACCESS
1464 // Sanity check ("Aww, there ain't no Sanity Clause...")
1465 if ((offset < 0xF00000) || (offset > 0xF03FFF))
1469 if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1471 GPUWriteByte(offset, data, who);
1474 else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1476 GPUWriteByte(offset, data, who);
1479 /* else if ((offset >= 0xF00010) && (offset < 0xF00028))
1481 OPWriteByte(offset, data, who);
1484 else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1486 BlitterWriteByte(offset, data, who);
1489 else if (offset == 0xF00050)
1491 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | (data << 8);
1495 else if (offset == 0xF00051)
1497 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | data;
1501 else if (offset == 0xF00052)
1503 tomTimerDivider = (tomTimerDivider & 0x00FF) | (data << 8);
1507 else if (offset == 0xF00053)
1509 tomTimerDivider = (tomTimerDivider & 0xFF00) | data;
1513 else if (offset >= 0xF00400 && offset <= 0xF007FF) // CLUT (A & B)
1515 // Writing to one CLUT writes to the other
1516 offset &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
1517 tomRam8[offset] = data, tomRam8[offset + 0x200] = data;
1520 // tomRam8[offset & 0x3FFF] = data;
1525 // TOM word access (write)
1527 void TOMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
1529 // Moved here tentatively, so we can see everything written to TOM.
1530 tomRam8[(offset + 0) & 0x3FFF] = data >> 8;
1531 tomRam8[(offset + 1) & 0x3FFF] = data & 0xFF;
1534 WriteLog("TOM: Writing byte %04X at %06X", data, offset);
1536 //???Is this needed??? Yes, but we need to be more vigilant than this.
1537 #ifndef TOM_STRICT_MEMORY_ACCESS
1540 // "Fast" (32-bit only) write access to the GPU
1541 // if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF))
1542 if ((offset >= 0xF08000) && (offset <= 0xF0BFFF))
1546 WriteLog(" -->[%06X] by %s\n", offset, whoName[who]);
1549 #ifdef TOM_STRICT_MEMORY_ACCESS
1551 if ((offset < 0xF00000) || (offset > 0xF03FFF))
1555 //if (offset == 0xF00000 + MEMCON1)
1556 // WriteLog("TOM: Memory Configuration 1 written by %s: %04X\n", whoName[who], data);
1557 //if (offset == 0xF00000 + MEMCON2)
1558 // WriteLog("TOM: Memory Configuration 2 written by %s: %04X\n", whoName[who], data);
1559 if (offset >= 0xF02000 && offset <= 0xF020FF)
1560 WriteLog("TOM: WriteWord attempted to GPU register file by %s (unimplemented)!\n", whoName[who]);
1562 if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1564 GPUWriteWord(offset, data, who);
1567 else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1569 GPUWriteWord(offset, data, who);
1572 //What's so special about this?
1573 /* else if ((offset >= 0xF00000) && (offset < 0xF00002))
1575 TOMWriteByte(offset, data >> 8);
1576 TOMWriteByte(offset+1, data & 0xFF);
1578 /* else if ((offset >= 0xF00010) && (offset < 0xF00028))
1580 OPWriteWord(offset, data, who);
1583 else if (offset == 0xF00050)
1585 tomTimerPrescaler = data;
1589 else if (offset == 0xF00052)
1591 tomTimerDivider = data;
1595 else if (offset == 0xF000E0)
1599 tom_video_int_pending = 0;
1601 tom_gpu_int_pending = 0;
1603 tom_object_int_pending = 0;
1605 tom_timer_int_pending = 0;
1607 tom_jerry_int_pending = 0;
1611 else if ((offset >= 0xF02200) && (offset <= 0xF0229F))
1613 BlitterWriteWord(offset, data, who);
1616 else if (offset >= 0xF00400 && offset <= 0xF007FE) // CLUT (A & B)
1618 // Writing to one CLUT writes to the other
1619 offset &= 0x5FF; // Mask out $F00600 (restrict to $F00400-5FF)
1620 // Watch out for unaligned writes here! (Not fixed yet)
1621 #warning "!!! Watch out for unaligned writes here !!! FIX !!!"
1622 SET16(tomRam8, offset, data);
1623 SET16(tomRam8, offset + 0x200, data);
1627 if (offset == 0x28) // VMODE (Why? Why not OBF?)
1628 //Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!
1629 #warning "Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!"
1630 objectp_running = 1;
1632 if (offset >= 0x30 && offset <= 0x4E)
1633 data &= 0x07FF; // These are (mostly) 11-bit registers
1634 if (offset == 0x2E || offset == 0x36 || offset == 0x54)
1635 data &= 0x03FF; // These are all 10-bit registers
1637 // Fix a lockup bug... :-P
1638 // TOMWriteByte(0xF00000 | offset, data >> 8, who);
1639 // TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who);
1641 if (offset == MEMCON1)
1642 WriteLog("TOM: Memory Config 1 written by %s: $%04X\n", whoName[who], data);
1643 if (offset == MEMCON2)
1644 WriteLog("TOM: Memory Config 2 written by %s: $%04X\n", whoName[who], data);
1645 //if (offset == OLP)
1646 // WriteLog("TOM: Object List Pointer written by %s: $%04X\n", whoName[who], data);
1647 //if (offset == OLP + 2)
1648 // WriteLog("TOM: Object List Pointer +2 written by %s: $%04X\n", whoName[who], data);
1649 //if (offset == OBF)
1650 // WriteLog("TOM: Object Processor Flag written by %s: %u\n", whoName[who], data);
1651 if (offset == VMODE)
1652 WriteLog("TOM: Video Mode written by %s: %04X. PWIDTH = %u, MODE = %s, flags:%s%s (VC = %u)\n", whoName[who], data, ((data >> 9) & 0x07) + 1, videoMode_to_str[(data & MODE) >> 1], (data & BGEN ? " BGEN" : ""), (data & VARMOD ? " VARMOD" : ""), GET16(tomRam8, VC));
1653 if (offset == BORD1)
1654 WriteLog("TOM: Border 1 written by %s: $%04X\n", whoName[who], data);
1655 if (offset == BORD2)
1656 WriteLog("TOM: Border 2 written by %s: $%04X\n", whoName[who], data);
1658 WriteLog("TOM: Horizontal Period written by %s: %u (+1*2 = %u)\n", whoName[who], data, (data + 1) * 2);
1660 WriteLog("TOM: Horizontal Blank Begin written by %s: %u\n", whoName[who], data);
1662 WriteLog("TOM: Horizontal Blank End written by %s: %u\n", whoName[who], data);
1664 WriteLog("TOM: Horizontal Sync written by %s: %u\n", whoName[who], data);
1666 WriteLog("TOM: Horizontal Vertical Sync written by %s: %u\n", whoName[who], data);
1668 WriteLog("TOM: Horizontal Display Begin 1 written by %s: %u\n", whoName[who], data);
1670 WriteLog("TOM: Horizontal Display Begin 2 written by %s: %u\n", whoName[who], data);
1672 WriteLog("TOM: Horizontal Display End written by %s: %u\n", whoName[who], data);
1674 WriteLog("TOM: Vertical Period written by %s: %u (%sinterlaced)\n", whoName[who], data, (data & 0x01 ? "non-" : ""));
1676 WriteLog("TOM: Vertical Blank Begin written by %s: %u\n", whoName[who], data);
1678 WriteLog("TOM: Vertical Blank End written by %s: %u\n", whoName[who], data);
1680 WriteLog("TOM: Vertical Sync written by %s: %u\n", whoName[who], data);
1682 WriteLog("TOM: Vertical Display Begin written by %s: %u\n", whoName[who], data);
1684 WriteLog("TOM: Vertical Display End written by %s: %u\n", whoName[who], data);
1686 WriteLog("TOM: Vertical Equalization Begin written by %s: %u\n", whoName[who], data);
1688 WriteLog("TOM: Vertical Equalization End written by %s: %u\n", whoName[who], data);
1690 WriteLog("TOM: Vertical Interrupt written by %s: %u\n", whoName[who], data);
1692 WriteLog("TOM: PIT0 written by %s: %u\n", whoName[who], data);
1694 WriteLog("TOM: PIT1 written by %s: %u\n", whoName[who], data);
1696 WriteLog("TOM: Horizontal Equalization End written by %s: %u\n", whoName[who], data);
1698 // WriteLog("TOM: Background written by %s: %u\n", whoName[who], data);
1699 //if (offset == INT1)
1700 // 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" : ""));
1702 // detect screen resolution changes
1703 //This may go away in the future, if we do the virtualized screen thing...
1704 //This may go away soon!
1705 // TOM Shouldn't be mucking around with this, it's up to the host system to properly
1706 // handle this kind of crap.
1707 // NOTE: This is needed somehow, need to get rid of the dependency on this crap.
1708 // N.B.: It's used in the rendering functions... So...
1709 #warning "!!! Need to get rid of this dependency !!!"
1711 if ((offset >= 0x28) && (offset <= 0x4F))
1713 uint32_t width = TOMGetVideoModeWidth(), height = TOMGetVideoModeHeight();
1715 if ((width != tomWidth) || (height != tomHeight))
1717 tomWidth = width, tomHeight = height;
1719 #warning "!!! TOM: ResizeScreen commented out !!!"
1720 // No need to resize anything, since we're prepared for this...
1721 // if (vjs.renderType == RT_NORMAL)
1722 // ResizeScreen(tomWidth, tomHeight);
1729 int TOMIRQEnabled(int irq)
1731 // This is the correct byte in big endian... D'oh!
1732 // return jaguar_byte_read(0xF000E1) & (1 << irq);
1733 return tomRam8[INT1 + 1/*0xE1*/] & (1 << irq);
1738 // TOM Programmable Interrupt Timer handler
1739 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
1740 // The PIT only generates an interrupt when it counts down to zero, not when loaded!
1742 void TOMPITCallback(void);
1745 void TOMResetPIT(void)
1747 #ifndef NEW_TIMER_SYSTEM
1748 //Probably should *add* this amount to the counter to retain cycle accuracy! !!! FIX !!! [DONE]
1749 //Also, why +1??? 'Cause that's what it says in the JTRM...!
1750 //There is a small problem with this approach: If both the prescaler and the divider are equal
1751 //to $FFFF then the counter won't be large enough to handle it. !!! FIX !!!
1752 if (tom_timer_prescaler)
1753 tom_timer_counter += (1 + tom_timer_prescaler) * (1 + tom_timer_divider);
1754 // WriteLog("tom: reseting timer to 0x%.8x (%i)\n",tom_timer_counter,tom_timer_counter);
1756 // Need to remove previous timer from the queue, if it exists...
1757 RemoveCallback(TOMPITCallback);
1759 if (tomTimerPrescaler)
1761 double usecs = (float)(tomTimerPrescaler + 1) * (float)(tomTimerDivider + 1) * RISC_CYCLE_IN_USEC;
1762 SetCallbackTime(TOMPITCallback, usecs);
1769 // TOM Programmable Interrupt Timer handler
1770 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
1772 //NOTE: This is only used by the old execution code... Safe to remove
1773 // once the timer system is stable.
1774 void TOMExecPIT(uint32_t cycles)
1776 if (tomTimerPrescaler)
1778 tomTimerCounter -= cycles;
1780 if (tomTimerCounter <= 0)
1782 TOMSetPendingTimerInt();
1783 GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // GPUSetIRQLine does the 'IRQ enabled' checking
1785 if (TOMIRQEnabled(IRQ_TIMER))
1786 m68k_set_irq(2); // Cause a 68000 IPL 2...
1794 void TOMPITCallback(void)
1796 // INT1_RREG |= 0x08; // Set TOM PIT interrupt pending
1797 TOMSetPendingTimerInt();
1798 GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking
1800 // if (INT1_WREG & 0x08)
1801 if (TOMIRQEnabled(IRQ_TIMER))
1802 m68k_set_irq(2); // Generate a 68K IPL 2...