Update the breakpoint feature
[clinton/Virtual-Jaguar-Rx.git] / src / tom.cpp
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