]> Shamusworld >> Repos - virtualjaguar/blob - src/tom.cpp
88223c2e6dc639416e7cc4b6b50c013ba8970d57
[virtualjaguar] / 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 and endian wrongness amelioration by James Hammons
7 // (C) 2010 Underground Software
8 //
9 // JLH = James Hammons <jlhamm@acm.org>
10 //
11 // Who  When        What
12 // ---  ----------  -------------------------------------------------------------
13 // JLH  01/16/2010  Created this log ;-)
14 // JLH  01/20/2011  Change rendering to RGBA, removed unnecessary code
15 //
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. :-}
18 //
19 // Note: TOM has only a 16K memory space
20 //
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 //      ------------------------------------------------------------
148 //      BLITTER REGISTERS
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 //      ------------------------------------------------------------
255
256 #include "tom.h"
257
258 #include <string.h>                                                             // For memset()
259 #include <stdlib.h>                                                             // For rand()
260 #include "blitter.h"
261 #include "cry2rgb.h"
262 #include "event.h"
263 #include "gpu.h"
264 #include "jaguar.h"
265 #include "log.h"
266 #include "m68000/m68kinterface.h"
267 //#include "memory.h"
268 #include "op.h"
269 #include "settings.h"
270
271 #define NEW_TIMER_SYSTEM
272
273 // TOM registers (offset from $F00000)
274
275 #define MEMCON1         0x00
276 #define MEMCON2         0x02
277 #define HC                      0x04
278 #define VC                      0x06
279 #define OLP                     0x20            // Object list pointer
280 #define OBF                     0x26            // Object processor flag
281 #define VMODE           0x28
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
290 #define HBE                     0x32
291 #define HS                      0x34            // Horizontal sync
292 #define HVS                     0x36            // Horizontal vertical sync
293 #define HDB1            0x38            // Horizontal display begin 1
294 #define HDB2            0x3A
295 #define HDE                     0x3C
296 #define VP                      0x3E            // Value ranges from 1 - 2048 (value written + 1)
297 #define VBB                     0x40            // Vertical blank begin
298 #define VBE                     0x42
299 #define VS                      0x44            // Vertical sync
300 #define VDB                     0x46            // Vertical display begin
301 #define VDE                     0x48
302 #define VEB                     0x4A            // Vertical equalization begin
303 #define VEE                     0x4C            // Vertical equalization end
304 #define VI                      0x4E            // Vertical interrupt
305 #define PIT0            0x50
306 #define PIT1            0x52
307 #define HEQ                     0x54            // Horizontal equalization end
308 #define BG                      0x58            // Background color
309 #define INT1            0xE0
310
311 //NOTE: These arbitrary cutoffs are NOT taken into account for PAL jaguar screens. !!! FIX !!! [DONE]
312
313 // Arbitrary video cutoff values (i.e., first/last visible spots on a TV, in HC ticks)
314 // Also note that VC is in *half* lines, i.e. divide by 2 to get the scanline
315 /*#define LEFT_VISIBLE_HC                       208
316 #define RIGHT_VISIBLE_HC                1528//*/
317 // These were right for Rayman, but that one is offset on a real TV too.
318 //#define LEFT_VISIBLE_HC                       208
319 //#define RIGHT_VISIBLE_HC              1488
320 // This is more like a real TV display...
321 //#define LEFT_VISIBLE_HC                       (208 - 32)
322 //#define RIGHT_VISIBLE_HC              (1488 - 32)
323 // Split the difference? (Seems to be OK for the most part...)
324 #define LEFT_VISIBLE_HC                 (208 - 16)
325 #define RIGHT_VISIBLE_HC                (1488 - 16)
326 //#define TOP_VISIBLE_VC                25
327 //#define BOTTOM_VISIBLE_VC             503
328 #define TOP_VISIBLE_VC                  31
329 #define BOTTOM_VISIBLE_VC               511
330
331 //Are these PAL horizontals correct?
332 //They seem to be for the most part, but there are some games that seem to be
333 //shifted over to the right from this "window".
334 #define LEFT_VISIBLE_HC_PAL             (208 - 16)
335 #define RIGHT_VISIBLE_HC_PAL    (1488 - 16)
336 #define TOP_VISIBLE_VC_PAL              67
337 #define BOTTOM_VISIBLE_VC_PAL   579
338
339 //This can be defined in the makefile as well...
340 //(It's easier to do it here, though...)
341 //#define TOM_DEBUG
342
343 uint8 tomRam8[0x4000];
344 uint32 tomWidth, tomHeight;
345 uint32 tomTimerPrescaler;
346 uint32 tomTimerDivider;
347 int32 tomTimerCounter;
348 uint16 tom_jerry_int_pending, tom_timer_int_pending, tom_object_int_pending,
349         tom_gpu_int_pending, tom_video_int_pending;
350
351 // These are set by the "user" of the Jaguar core lib, since these are
352 // OS/system dependent.
353 uint32 * screenBuffer;
354 uint32 screenPitch;
355
356 static const char * videoMode_to_str[8] =
357         { "16 BPP CRY", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB",
358           "Mixed mode", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB" };
359
360 typedef void (render_xxx_scanline_fn)(uint32 *);
361
362 // Private function prototypes
363
364 void tom_render_16bpp_cry_scanline(uint32 * backbuffer);
365 void tom_render_24bpp_scanline(uint32 * backbuffer);
366 void tom_render_16bpp_direct_scanline(uint32 * backbuffer);
367 void tom_render_16bpp_rgb_scanline(uint32 * backbuffer);
368 void tom_render_16bpp_cry_rgb_mix_scanline(uint32 * backbuffer);
369
370 //render_xxx_scanline_fn * scanline_render_normal[] =
371 render_xxx_scanline_fn * scanline_render[] =
372 {
373         tom_render_16bpp_cry_scanline,
374         tom_render_24bpp_scanline,
375         tom_render_16bpp_direct_scanline,
376         tom_render_16bpp_rgb_scanline,
377         tom_render_16bpp_cry_rgb_mix_scanline,
378         tom_render_24bpp_scanline,
379         tom_render_16bpp_direct_scanline,
380         tom_render_16bpp_rgb_scanline
381 };
382
383 // Screen info for various games [PAL]...
384 /*
385 BIOS
386 TOM: Horizontal Period written by M68K: 850 (+1*2 = 1702)
387 TOM: Horizontal Blank Begin written by M68K: 1711
388 TOM: Horizontal Blank End written by M68K: 158
389 TOM: Horizontal Display End written by M68K: 1696
390 TOM: Horizontal Display Begin 1 written by M68K: 166
391 TOM: Vertical Period written by M68K: 623 (non-interlaced)
392 TOM: Vertical Blank End written by M68K: 34
393 TOM: Vertical Display Begin written by M68K: 46
394 TOM: Vertical Display End written by M68K: 526
395 TOM: Vertical Blank Begin written by M68K: 600
396 TOM: Vertical Sync written by M68K: 618
397 TOM: Horizontal Display End written by M68K: 1665
398 TOM: Horizontal Display Begin 1 written by M68K: 203
399 TOM: Vertical Display Begin written by M68K: 38
400 TOM: Vertical Display End written by M68K: 518
401 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 151)
402 TOM: Horizontal Display End written by M68K: 1713
403 TOM: Horizontal Display Begin 1 written by M68K: 157
404 TOM: Vertical Display Begin written by M68K: 35
405 TOM: Vertical Display End written by M68K: 2047
406 Horizontal range: 157 - 1713 (width: 1557 / 4 = 389.25, / 5 = 315.4)
407
408 Asteroid
409 TOM: Horizontal Period written by M68K: 845 (+1*2 = 1692)
410 TOM: Horizontal Blank Begin written by M68K: 1700
411 TOM: Horizontal Blank End written by M68K: 122
412 TOM: Horizontal Display End written by M68K: 1600
413 TOM: Horizontal Display Begin 1 written by M68K: 268
414 TOM: Vertical Period written by M68K: 523 (non-interlaced)
415 TOM: Vertical Blank End written by M68K: 40
416 TOM: Vertical Display Begin written by M68K: 44
417 TOM: Vertical Display End written by M68K: 492
418 TOM: Vertical Blank Begin written by M68K: 532
419 TOM: Vertical Sync written by M68K: 513
420 TOM: Video Mode written by M68K: 04C7. PWIDTH = 3, MODE = 16 BPP RGB, flags: BGEN (VC = 461)
421
422 Rayman
423 TOM: Horizontal Display End written by M68K: 1713
424 TOM: Horizontal Display Begin 1 written by M68K: 157
425 TOM: Vertical Display Begin written by M68K: 35
426 TOM: Vertical Display End written by M68K: 2047
427 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 89)
428 TOM: Horizontal Display Begin 1 written by M68K: 208
429 TOM: Horizontal Display End written by M68K: 1662
430 TOM: Vertical Display Begin written by M68K: 100
431 TOM: Vertical Display End written by M68K: 2047
432 TOM: Video Mode written by M68K: 07C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN VARMOD (VC = 205)
433 Horizontal range: 208 - 1662 (width: 1455 / 4 = 363.5)
434
435 Alien vs Predator
436 TOM: Vertical Display Begin written by M68K: 96
437 TOM: Vertical Display End written by M68K: 2047
438 TOM: Horizontal Display Begin 1 written by M68K: 239
439 TOM: Horizontal Display End written by M68K: 1692
440 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 378)
441 TOM: Vertical Display Begin written by M68K: 44
442 TOM: Vertical Display End written by M68K: 2047
443 TOM: Horizontal Display Begin 1 written by M68K: 239
444 TOM: Horizontal Display End written by M68K: 1692
445 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 559)
446 TOM: Vertical Display Begin written by M68K: 84
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: Vertical Display Begin written by M68K: 44
451 TOM: Vertical Display End written by M68K: 2047
452 TOM: Horizontal Display Begin 1 written by M68K: 239
453 TOM: Horizontal Display End written by M68K: 1692
454 Horizontal range: 239 - 1692 (width: 1454 / 4 = 363.5)
455
456 */
457
458 // Screen info for various games [NTSC]...
459 /*
460 Doom
461 TOM: Horizontal Display End written by M68K: 1727
462 TOM: Horizontal Display Begin 1 written by M68K: 123
463 TOM: Vertical Display Begin written by M68K: 25
464 TOM: Vertical Display End written by M68K: 2047
465 TOM: Video Mode written by M68K: 0EC1. PWIDTH = 8, MODE = 16 BPP CRY, flags: BGEN (VC = 5)
466 Also does PWIDTH = 4...
467 Vertical resolution: 238 lines
468
469 Rayman
470 TOM: Horizontal Display End written by M68K: 1727
471 TOM: Horizontal Display Begin 1 written by M68K: 123
472 TOM: Vertical Display Begin written by M68K: 25
473 TOM: Vertical Display End written by M68K: 2047
474 TOM: Vertical Interrupt written by M68K: 507
475 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 92)
476 TOM: Horizontal Display Begin 1 written by M68K: 208
477 TOM: Horizontal Display End written by M68K: 1670
478 Display starts at 31, then 52!
479 Vertical resolution: 238 lines
480
481 Atari Karts
482 TOM: Horizontal Display End written by M68K: 1727
483 TOM: Horizontal Display Begin 1 written by M68K: 123
484 TOM: Vertical Display Begin written by M68K: 25
485 TOM: Vertical Display End written by M68K: 2047
486 TOM: Video Mode written by GPU: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 4)
487 TOM: Video Mode written by GPU: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 508)
488 Display starts at 31 (PWIDTH = 4), 24 (PWIDTH = 5)
489
490 Iron Soldier
491 TOM: Vertical Interrupt written by M68K: 2047
492 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 0)
493 TOM: Horizontal Display End written by M68K: 1727
494 TOM: Horizontal Display Begin 1 written by M68K: 123
495 TOM: Vertical Display Begin written by M68K: 25
496 TOM: Vertical Display End written by M68K: 2047
497 TOM: Vertical Interrupt written by M68K: 507
498 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 369)
499 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 510)
500 TOM: Video Mode written by M68K: 06C3. PWIDTH = 4, MODE = 24 BPP RGB, flags: BGEN (VC = 510)
501 Display starts at 31
502 Vertical resolution: 238 lines
503 [Seems to be a problem between the horizontal positioning of the 16-bit CRY & 24-bit RGB]
504
505 JagMania
506 TOM: Horizontal Period written by M68K: 844 (+1*2 = 1690)
507 TOM: Horizontal Blank Begin written by M68K: 1713
508 TOM: Horizontal Blank End written by M68K: 125
509 TOM: Horizontal Display End written by M68K: 1696
510 TOM: Horizontal Display Begin 1 written by M68K: 166
511 TOM: Vertical Period written by M68K: 523 (non-interlaced)
512 TOM: Vertical Blank End written by M68K: 24
513 TOM: Vertical Display Begin written by M68K: 46
514 TOM: Vertical Display End written by M68K: 496
515 TOM: Vertical Blank Begin written by M68K: 500
516 TOM: Vertical Sync written by M68K: 517
517 TOM: Vertical Interrupt written by M68K: 497
518 TOM: Video Mode written by M68K: 04C1. PWIDTH = 3, MODE = 16 BPP CRY, flags: BGEN (VC = 270)
519 Display starts at 55
520
521 Double Dragon V
522 TOM: Horizontal Display End written by M68K: 1727
523 TOM: Horizontal Display Begin 1 written by M68K: 123
524 TOM: Vertical Display Begin written by M68K: 25
525 TOM: Vertical Display End written by M68K: 2047
526 TOM: Vertical Interrupt written by M68K: 507
527 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 9)
528
529 Dino Dudes
530 TOM: Horizontal Display End written by M68K: 1823
531 TOM: Horizontal Display Begin 1 written by M68K: 45
532 TOM: Vertical Display Begin written by M68K: 40
533 TOM: Vertical Display End written by M68K: 2047
534 TOM: Vertical Interrupt written by M68K: 491
535 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 398)
536 Display starts at 11 (123 - 45 = 78, 78 / 4 = 19 pixels to skip)
537 Width is 417, so maybe width of 379 would be good (starting at 123, ending at 1639)
538 Vertical resolution: 238 lines
539
540 Flashback
541 TOM: Horizontal Display End written by M68K: 1727
542 TOM: Horizontal Display Begin 1 written by M68K: 188
543 TOM: Vertical Display Begin written by M68K: 1
544 TOM: Vertical Display End written by M68K: 2047
545 TOM: Vertical Interrupt written by M68K: 483
546 TOM: Video Mode written by M68K: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 99)
547 Width would be 303 with above scheme, but border width would be 13 pixels
548
549 Trevor McFur
550 Vertical resolution: 238 lines
551 */
552
553 uint32 RGB16ToRGB32[0x10000];
554 uint32 CRY16ToRGB32[0x10000];
555 uint32 MIX16ToRGB32[0x10000];
556
557 #warning "This is not endian-safe. !!! FIX !!!"
558 void TOMFillLookupTables(void)
559 {
560         // NOTE: Jaguar 16-bit (non-CRY) color is RBG 556 like so:
561         //       RRRR RBBB BBGG GGGG
562         for(uint32 i=0; i<0x10000; i++)
563 //hm.           RGB16ToRGB32[i] = 0xFF000000
564 //                      | ((i & 0xF100) >> 8)  | ((i & 0xE000) >> 13)
565 //                      | ((i & 0x07C0) << 13) | ((i & 0x0700) << 8)
566 //                      | ((i & 0x003F) << 10) | ((i & 0x0030) << 4);
567                 RGB16ToRGB32[i] = 0x000000FF
568                         | ((i & 0xF100) << 16)                                  // Red
569                         | ((i & 0x003F) << 18)                                  // Green
570                         | ((i & 0x07C0) << 5);                                  // Blue
571
572         for(uint32 i=0; i<0x10000; i++)
573         {
574                 uint32 cyan = (i & 0xF000) >> 12,
575                         red = (i & 0x0F00) >> 8,
576                         intensity = (i & 0x00FF);
577
578                 uint32 r = (((uint32)redcv[cyan][red]) * intensity) >> 8,
579                         g = (((uint32)greencv[cyan][red]) * intensity) >> 8,
580                         b = (((uint32)bluecv[cyan][red]) * intensity) >> 8;
581
582 //hm.           CRY16ToRGB32[i] = 0xFF000000 | (b << 16) | (g << 8) | r;
583                 CRY16ToRGB32[i] = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
584                 MIX16ToRGB32[i] = (i & 0x01 ? RGB16ToRGB32[i] : CRY16ToRGB32[i]);
585         }
586 }
587
588 void TOMSetPendingJERRYInt(void)
589 {
590         tom_jerry_int_pending = 1;
591 }
592
593 void TOMSetPendingTimerInt(void)
594 {
595         tom_timer_int_pending = 1;
596 }
597
598 void TOMSetPendingObjectInt(void)
599 {
600         tom_object_int_pending = 1;
601 }
602
603 void TOMSetPendingGPUInt(void)
604 {
605         tom_gpu_int_pending = 1;
606 }
607
608 void TOMSetPendingVideoInt(void)
609 {
610         tom_video_int_pending = 1;
611 }
612
613 uint8 * TOMGetRamPointer(void)
614 {
615         return tomRam8;
616 }
617
618 uint8 TOMGetVideoMode(void)
619 {
620         uint16 vmode = GET16(tomRam8, VMODE);
621         return ((vmode & VARMOD) >> 6) | ((vmode & MODE) >> 1);
622 }
623
624 //Used in only one place (and for debug purposes): OBJECTP.CPP
625 #warning "Used in only one place (and for debug purposes): OBJECTP.CPP !!! FIX !!!"
626 uint16 TOMGetVDB(void)
627 {
628         return GET16(tomRam8, VDB);
629 }
630
631 //
632 // 16 BPP CRY/RGB mixed mode rendering
633 //
634 void tom_render_16bpp_cry_rgb_mix_scanline(uint32 * backbuffer)
635 {
636 //CHANGED TO 32BPP RENDERING
637         uint16 width = tomWidth;
638         uint8 * current_line_buffer = (uint8 *)&tomRam8[0x1800];
639
640         //New stuff--restrict our drawing...
641         uint8 pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
642         //NOTE: May have to check HDB2 as well!
643         // Get start position in HC ticks
644         int16 startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);
645         startPos /= pwidth;
646         if (startPos < 0)
647                 current_line_buffer += 2 * -startPos;
648         else
649 //This case doesn't properly handle the "start on the right side of virtual screen" case
650 //Dunno why--looks Ok...
651 //What *is* for sure wrong is that it doesn't copy the linebuffer's BG pixels...
652 //This should likely be 4 instead of 2 (?--not sure)
653                 backbuffer += 2 * startPos, width -= startPos;
654
655         while (width)
656         {
657                 uint16 color = (*current_line_buffer++) << 8;
658                 color |= *current_line_buffer++;
659                 *backbuffer++ = MIX16ToRGB32[color];
660                 width--;
661         }
662 }
663
664 //
665 // 16 BPP CRY mode rendering
666 //
667 void tom_render_16bpp_cry_scanline(uint32 * backbuffer)
668 {
669 //CHANGED TO 32BPP RENDERING
670         uint16 width = tomWidth;
671         uint8 * current_line_buffer = (uint8 *)&tomRam8[0x1800];
672
673         //New stuff--restrict our drawing...
674         uint8 pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
675         //NOTE: May have to check HDB2 as well!
676         int16 startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);// Get start position in HC ticks
677         startPos /= pwidth;
678         if (startPos < 0)
679                 current_line_buffer += 2 * -startPos;
680         else
681 //This should likely be 4 instead of 2 (?--not sure)
682                 backbuffer += 2 * startPos, width -= startPos;
683
684         while (width)
685         {
686                 uint16 color = (*current_line_buffer++) << 8;
687                 color |= *current_line_buffer++;
688                 *backbuffer++ = CRY16ToRGB32[color];
689                 width--;
690         }
691 }
692
693 //
694 // 24 BPP mode rendering
695 //
696 void tom_render_24bpp_scanline(uint32 * backbuffer)
697 {
698 //CHANGED TO 32BPP RENDERING
699         uint16 width = tomWidth;
700         uint8 * current_line_buffer = (uint8 *)&tomRam8[0x1800];
701
702         //New stuff--restrict our drawing...
703         uint8 pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
704         //NOTE: May have to check HDB2 as well!
705         int16 startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks
706         startPos /= pwidth;
707         if (startPos < 0)
708                 current_line_buffer += 4 * -startPos;
709         else
710 //This should likely be 4 instead of 2 (?--not sure)
711                 backbuffer += 2 * startPos, width -= startPos;
712
713         while (width)
714         {
715                 uint32 g = *current_line_buffer++;
716                 uint32 r = *current_line_buffer++;
717                 current_line_buffer++;
718                 uint32 b = *current_line_buffer++;
719 //hm.           *backbuffer++ = 0xFF000000 | (b << 16) | (g << 8) | r;
720                 *backbuffer++ = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
721                 width--;
722         }
723 }
724
725 //Seems to me that this is NOT a valid mode--the JTRM seems to imply that you would need
726 //extra hardware outside of the Jaguar console to support this!
727 //
728 // 16 BPP direct mode rendering
729 //
730 void tom_render_16bpp_direct_scanline(uint32 * backbuffer)
731 {
732         uint16 width = tomWidth;
733         uint8 * current_line_buffer = (uint8 *)&tomRam8[0x1800];
734
735         while (width)
736         {
737                 uint16 color = (*current_line_buffer++) << 8;
738                 color |= *current_line_buffer++;
739                 *backbuffer++ = color >> 1;
740                 width--;
741         }
742 }
743
744 //
745 // 16 BPP RGB mode rendering
746 //
747 void tom_render_16bpp_rgb_scanline(uint32 * backbuffer)
748 {
749 //CHANGED TO 32BPP RENDERING
750         // 16 BPP RGB: 0-5 green, 6-10 blue, 11-15 red
751
752         uint16 width = tomWidth;
753         uint8 * current_line_buffer = (uint8 *)&tomRam8[0x1800];
754
755         //New stuff--restrict our drawing...
756         uint8 pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
757         //NOTE: May have to check HDB2 as well!
758         int16 startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks
759         startPos /= pwidth;
760
761         if (startPos < 0)
762                 current_line_buffer += 2 * -startPos;
763         else
764 //This should likely be 4 instead of 2 (?--not sure)
765                 backbuffer += 2 * startPos, width -= startPos;
766
767         while (width)
768         {
769                 uint32 color = (*current_line_buffer++) << 8;
770                 color |= *current_line_buffer++;
771                 *backbuffer++ = RGB16ToRGB32[color];
772                 width--;
773         }
774 }
775
776
777 /*void TOMResetBackbuffer(uint32 * backbuffer)
778 {
779         TOMBackbuffer = backbuffer;
780 }*/
781
782 //
783 // Process a single scanline
784 // (this is bad terminology; each tick of the VC is actually a half-line)
785 //
786 void TOMExecHalfline(uint16 halfline, bool render)
787 {
788 #warning "!!! Need to handle multiple fields properly !!!"
789         // We ignore the problem for now
790         halfline &= 0x7FF;
791
792         bool inActiveDisplayArea = true;
793
794 //Interlacing is still not handled correctly here... !!! FIX !!!
795         if (halfline & 0x01)                                                    // Execute OP only on even halflines (non-interlaced only!)
796                 return;
797
798 //Hm, it seems that the OP needs to execute from zero, so let's try it:
799 // And it works! But need to do some optimizations in the OP to keep it from attempting
800 // to do a scanline render in the non-display area... [DONE]
801 //this seems to cause a regression in certain games, like rayman
802 //which means I have to dig thru the asic nets to see what's wrong...
803 /*
804 No, the OP doesn't start until VDB, that much is certain. The thing is, VDB is the
805 HALF line that the OP starts on--which means that it needs to start at VDB / 2!!!
806
807 Hrm, doesn't seem to be enough, though it should be... still sticks for 20 frames.
808
809
810 What triggers this is writing $FFFF to VDE. This causes the OP start signal in VID to 
811 latch on, which in effect sets VDB to zero. So that much is correct. But the thing with
812 Rayman is that it shouldn't cause the graphical glitches seen there, so still have to
813 investigate what's going on there. By all rights, it shouldn't glitch because:
814
815 00006C00: 0000000D 82008F73 (BRANCH) YPOS=494, CC=">", link=$00006C10
816 00006C08: 000003FF 00008173 (BRANCH) YPOS=46, CC=">", link=$001FF800
817 00006C10: 00000000 0000000C (STOP)
818 001FF800: 12FC2BFF 02380000 (BITMAP)
819           00008004 8180CFF1
820
821 Even if the OP is running all the time, the link should tell it to stop at the right
822 place (which it seems to do). But we still get glitchy screen.
823
824 Seems the glitchy screen went away... Maybe the GPU alignment fixes fixed it???
825 Just need to add the proper checking here then.
826
827 Some numbers, courtesy of the Jaguar BIOS:
828 // NTSC:
829 VP, 523                 // Vertical Period (1-based; in this case VP = 524)
830 VBE, 24                 // Vertical Blank End
831 VDB, 38                 // Vertical Display Begin
832 VDE, 518                // Vertical Display End
833 VBB, 500                // Vertical Blank Begin
834 VS, 517                 // Vertical Sync
835
836 // PAL Jaguar
837 VP, 623                 // Vertical Period (1-based; in this case VP = 624)
838 VBE, 34                 // Vertical Blank End
839 VDB, 38                 // Vertical Display Begin
840 VDE, 518                // Vertical Display End
841 VBB, 600                // Vertical Blank Begin
842 VS, 618                 // Vertical Sync
843
844 Numbers for KM, NTSC:
845 KM: (Note that with VDE <= 507, the OP starts at VDB as expected)
846 TOM: Vertical Display Begin written by M68K: 41
847 TOM: Vertical Display End written by M68K: 2047
848 TOM: Vertical Interrupt written by M68K: 491
849 */
850 #if 1
851         // Initial values that "well behaved" programs use
852         uint16 startingHalfline = GET16(tomRam8, VDB);
853         uint16 endingHalfline = GET16(tomRam8, VDE);
854
855         // Simulate the OP start bug here!
856         // Really, this value is somewhere around 507 for an NTSC Jaguar. But this
857         // should work in a majority of cases, at least until we can figure it out properly.
858         if (endingHalfline > GET16(tomRam8, VP))
859                 startingHalfline = 0;
860
861         if (halfline >= startingHalfline && halfline < endingHalfline)
862 //      if (halfline >= 0 && halfline < (uint16)GET16(tomRam8, VDE))
863 // 16 isn't enough, and neither is 32 for raptgun. 32 fucks up Rayman
864 //      if (halfline >= ((uint16)GET16(tomRam8, VDB) / 2) && halfline < ((uint16)GET16(tomRam8, VDE) / 2))
865 //      if (halfline >= ((uint16)GET16(tomRam8, VDB) - 16) && halfline < (uint16)GET16(tomRam8, VDE))
866 //      if (halfline >= 20 && halfline < (uint16)GET16(tomRam8, VDE))
867 //      if (halfline >= (uint16)GET16(tomRam8, VDB) && halfline < (uint16)GET16(tomRam8, VDE))
868         {
869                 if (render)
870                 {
871                         uint8 * current_line_buffer = (uint8 *)&tomRam8[0x1800];
872                         uint8 bgHI = tomRam8[BG], bgLO = tomRam8[BG + 1];
873
874                         // Clear line buffer with BG
875                         if (GET16(tomRam8, VMODE) & BGEN) // && (CRY or RGB16)...
876                                 for(uint32 i=0; i<720; i++)
877                                         *current_line_buffer++ = bgHI, *current_line_buffer++ = bgLO;
878
879                         OPProcessList(halfline, render);
880                 }
881         }
882         else
883                 inActiveDisplayArea = false;
884 #else
885         inActiveDisplayArea =
886                 (halfline >= (uint16)GET16(tomRam8, VDB) && halfline < (uint16)GET16(tomRam8, VDE)
887                         ? true : false);
888
889         if (halfline < (uint16)GET16(tomRam8, VDE))
890         {
891                 if (render)//With JaguarExecuteNew() this is always true...
892                 {
893                         uint8 * current_line_buffer = (uint8 *)&tomRam8[0x1800];
894                         uint8 bgHI = tomRam8[BG], bgLO = tomRam8[BG + 1];
895
896                         // Clear line buffer with BG
897                         if (GET16(tomRam8, VMODE) & BGEN) // && (CRY or RGB16)...
898                                 for(uint32 i=0; i<720; i++)
899                                         *current_line_buffer++ = bgHI, *current_line_buffer++ = bgLO;
900
901 //                      OPProcessList(halfline, render);
902 //This seems to take care of it...
903                         OPProcessList(halfline, inActiveDisplayArea);
904                 }
905         }
906 #endif
907
908         // Try to take PAL into account... [We do now!]
909
910         uint16 topVisible = (vjs.hardwareTypeNTSC ? TOP_VISIBLE_VC : TOP_VISIBLE_VC_PAL),
911                 bottomVisible = (vjs.hardwareTypeNTSC ? BOTTOM_VISIBLE_VC : BOTTOM_VISIBLE_VC_PAL);
912         uint32 * TOMCurrentLine = &(screenBuffer[((halfline - topVisible) / 2) * screenPitch]);
913
914         // Here's our virtualized scanline code...
915
916         if (halfline >= topVisible && halfline < bottomVisible)
917         {
918                 if (inActiveDisplayArea)
919                 {
920 //NOTE: The following doesn't put BORDER color on the sides... !!! FIX !!!
921 #warning "The following doesn't put BORDER color on the sides... !!! FIX !!!"
922                         if (vjs.renderType == RT_NORMAL)
923 //                              scanline_render[TOMGetVideoMode()](TOMBackbuffer);
924                                 scanline_render[TOMGetVideoMode()](TOMCurrentLine);
925                         else//TV type render
926                         {
927 /*
928         tom_render_16bpp_cry_scanline,
929         tom_render_24bpp_scanline,
930         tom_render_16bpp_direct_scanline,
931         tom_render_16bpp_rgb_scanline,
932         tom_render_16bpp_cry_rgb_mix_scanline,
933         tom_render_24bpp_scanline,
934         tom_render_16bpp_direct_scanline,
935         tom_render_16bpp_rgb_scanline
936 #define VMODE           0x28
937 #define   MODE          0x0006          // Line buffer to video generator mode
938 #define   VARMOD        0x0100          // Mixed CRY/RGB16 mode (only works in MODE 0!)
939 */
940                                 uint8 pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
941                                 uint8 mode = ((GET16(tomRam8, VMODE) & MODE) >> 1);
942                                 bool varmod = GET16(tomRam8, VMODE) & VARMOD;
943 //The video texture line buffer ranges from 0 to 1279, with its left edge starting at
944 //LEFT_VISIBLE_HC. So, we need to start writing into the backbuffer at HDB1, using pwidth
945 //as our scaling factor. The way it generates its image on a real TV!
946
947 //So, for example, if HDB1 is less than LEFT_VISIBLE_HC, then we have to figure out where
948 //in the VTLB that we start writing pixels from the Jaguar line buffer (VTLB start=0,
949 //JLB=something).
950 #if 0
951 //
952 // 24 BPP mode rendering
953 //
954 void tom_render_24bpp_scanline(uint32 * backbuffer)
955 {
956 //CHANGED TO 32BPP RENDERING
957         uint16 width = tomWidth;
958         uint8 * current_line_buffer = (uint8 *)&tomRam8[0x1800];
959
960         //New stuff--restrict our drawing...
961         uint8 pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
962         //NOTE: May have to check HDB2 as well!
963         int16 startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL); // Get start position in HC ticks
964         startPos /= pwidth;
965         if (startPos < 0)
966                 current_line_buffer += 4 * -startPos;
967         else
968 //This should likely be 4 instead of 2 (?--not sure)
969                 backbuffer += 2 * startPos, width -= startPos;
970
971         while (width)
972         {
973                 uint32 g = *current_line_buffer++;
974                 uint32 r = *current_line_buffer++;
975                 current_line_buffer++;
976                 uint32 b = *current_line_buffer++;
977                 *backbuffer++ = 0xFF000000 | (b << 16) | (g << 8) | r;
978                 width--;
979         }
980 }
981 #endif
982
983                         }
984                 }
985                 else
986                 {
987                         // If outside of VDB & VDE, then display the border color
988                         uint32 * currentLineBuffer = TOMCurrentLine;
989                         uint8 g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
990 //Hm.                   uint32 pixel = 0xFF000000 | (b << 16) | (g << 8) | r;
991                         uint32 pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
992
993                         for(uint32 i=0; i<tomWidth; i++)
994                                 *currentLineBuffer++ = pixel;
995                 }
996         }
997 }
998
999 //
1000 // TOM initialization
1001 //
1002 void TOMInit(void)
1003 {
1004         TOMFillLookupTables();
1005         OPInit();
1006         BlitterInit();
1007         TOMReset();
1008 }
1009
1010 void TOMDone(void)
1011 {
1012         OPDone();
1013         BlitterDone();
1014         WriteLog("TOM: Resolution %i x %i %s\n", TOMGetVideoModeWidth(), TOMGetVideoModeHeight(),
1015                 videoMode_to_str[TOMGetVideoMode()]);
1016 //      WriteLog("\ntom: object processor:\n");
1017 //      WriteLog("tom: pointer to object list: 0x%.8x\n",op_get_list_pointer());
1018 //      WriteLog("tom: INT1=0x%.2x%.2x\n",TOMReadByte(0xf000e0),TOMReadByte(0xf000e1));
1019 //      gpu_done();
1020 //      dsp_done();
1021 //      memory_free(tomRam8);
1022 //      memory_free(tom_cry_rgb_mix_lut);
1023 }
1024
1025 uint32 TOMGetVideoModeWidth(void)
1026 {
1027         //These widths are pretty bogus. Should use HDB1/2 & HDE/HBB & PWIDTH to calc the width...
1028 //      uint32 width[8] = { 1330, 665, 443, 332, 266, 222, 190, 166 };
1029 //Temporary, for testing Doom...
1030 //      uint32 width[8] = { 1330, 665, 443, 332, 266, 222, 190, 332 };
1031
1032         // Note that the following PWIDTH values have the following pixel aspect ratios:
1033         // PWIDTH = 1 -> 0.25:1 (1:4) pixels (X:Y ratio)
1034         // PWIDTH = 2 -> 0.50:1 (1:2) pixels
1035         // PWIDTH = 3 -> 0.75:1 (3:4) pixels
1036         // PWIDTH = 4 -> 1.00:1 (1:1) pixels
1037         // PWIDTH = 5 -> 1.25:1 (5:4) pixels
1038         // PWIDTH = 6 -> 1.50:1 (3:2) pixels
1039         // PWIDTH = 7 -> 1.75:1 (7:4) pixels
1040         // PWIDTH = 8 -> 2.00:1 (2:1) pixels
1041
1042         // Also note that the JTRM says that PWIDTH of 4 gives pixels that are "about" square--
1043         // this implies that the other modes have pixels that are *not* square!
1044         // Also, I seriously doubt that you will see any games that use PWIDTH = 1!
1045
1046         // NOTE: Even though the PWIDTH value is + 1, here we're using a zero-based index and
1047         //       so we don't bother to add one...
1048 //      return width[(GET16(tomRam8, VMODE) & PWIDTH) >> 9];
1049
1050         // Now, we just calculate it...
1051 /*      uint16 hdb1 = GET16(tomRam8, HDB1), hde = GET16(tomRam8, HDE),
1052                 hbb = GET16(tomRam8, HBB), pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1053 //      return ((hbb < hde ? hbb : hde) - hdb1) / pwidth;
1054 //Temporary, for testing Doom...
1055         return ((hbb < hde ? hbb : hde) - hdb1) / (pwidth == 8 ? 4 : pwidth);*/
1056
1057         // To make it easier to make a quasi-fixed display size, we restrict the viewing
1058         // area to an arbitrary range of the Horizontal Count.
1059         uint16 pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1060         return (vjs.hardwareTypeNTSC ? RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC : RIGHT_VISIBLE_HC_PAL - LEFT_VISIBLE_HC_PAL) / pwidth;
1061 //Temporary, for testing Doom...
1062 //      return (RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC) / (pwidth == 8 ? 4 : pwidth);
1063 ////    return (RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC) / (pwidth == 4 ? 8 : pwidth);
1064
1065 // More speculating...
1066 // According to the JTRM, the number of potential pixels across is given by the
1067 // Horizontal Period (HP - in NTSC this is 845). The Horizontal Count counts from
1068 // zero to this value twice per scanline (the high bit is set on the second count).
1069 // HBE and HBB define the absolute "black" limits of the screen, while HDB1/2 and
1070 // HDE determine the extent of the OP "on" time. I.e., when the OP is turned on by
1071 // HDB1, it starts fetching the line from position 0 in LBUF.
1072
1073 // The trick, it would seem, is to figure out how long the typical visible scanline
1074 // of a TV is in HP ticks and limit the visible area to that (divided by PWIDTH, of
1075 // course). Using that length, we can establish an "absolute left display limit" with
1076 // which to measure HBB & HDB1/2 against when rendering LBUF (i.e., if HDB1 is 20 ticks
1077 // to the right of the ALDL and PWIDTH is 4, then start writing the LBUF starting at
1078 // backbuffer + 5 pixels).
1079
1080 // That's basically what we're doing now...!
1081 }
1082
1083 // *** SPECULATION ***
1084 // It might work better to virtualize the height settings, i.e., set the vertical
1085 // height at 240 lines and clip using the VDB and VDE/VP registers...
1086 // Same with the width... [Width is pretty much virtualized now.]
1087
1088 // Now that that the width is virtualized, let's virtualize the height. :-)
1089 uint32 TOMGetVideoModeHeight(void)
1090 {
1091 //      uint16 vmode = GET16(tomRam8, VMODE);
1092 //      uint16 vbe = GET16(tomRam8, VBE);
1093 //      uint16 vbb = GET16(tomRam8, VBB);
1094 //      uint16 vdb = GET16(tomRam8, VDB);
1095 //      uint16 vde = GET16(tomRam8, VDE);
1096 //      uint16 vp = GET16(tomRam8, VP);
1097
1098 /*      if (vde == 0xFFFF)
1099                 vde = vbb;//*/
1100
1101 //      return 227;//WAS:(vde/*-vdb*/) >> 1;
1102         // The video mode height probably works this way:
1103         // VC counts from 0 to VP. VDB starts the OP. Either when
1104         // VDE is reached or VP, the OP is stopped. Let's try it...
1105         // Also note that we're conveniently ignoring interlaced display modes...!
1106 //      return ((vde > vp ? vp : vde) - vdb) >> 1;
1107 //      return ((vde > vbb ? vbb : vde) - vdb) >> 1;
1108 //Let's try from the Vertical Blank interval...
1109 //Seems to work OK!
1110 //      return (vbb - vbe) >> 1;        // Again, doesn't take interlacing into account...
1111 // This of course doesn't take interlacing into account. But I haven't seen any
1112 // Jaguar software that takes advantage of it either...
1113 //Also, doesn't reflect PAL Jaguar either... !!! FIX !!! [DONE]
1114 //      return 240;                                                                             // Set virtual screen height to 240 lines...
1115         return (vjs.hardwareTypeNTSC ? 240 : 256);
1116 }
1117
1118 //
1119 // TOM reset code
1120 // Now PAL friendly!
1121 //
1122 /*
1123 The values in TOMReset come from the Jaguar BIOS.
1124 These values are from BJL:
1125
1126 NSTC:
1127 CLK2     181
1128 HP               844
1129 HBB              1713
1130 HBE              125
1131 HS               1741
1132 HVS              651
1133 HEQ              784
1134 HDE              1696
1135 HDB1     166
1136 HDB2     166
1137 VP               523
1138 VEE              6
1139 VBE              24
1140 VDB              46
1141 VDE              496
1142 VBB              500
1143 VEB              511
1144 VS               517
1145
1146 PAL:
1147 CLK2     226
1148 HP               850
1149 HBB              1711
1150 HBE              158
1151 HS               1749
1152 HVS              601
1153 HEQ              787
1154 HDE              1696
1155 HDB1     166
1156 HDB2     166
1157 VP               625
1158 VEE              6
1159 VBE              34
1160 VDB              46
1161 VDE              429
1162 VBB              600
1163 VEB              613
1164 VS               618
1165 */
1166 void TOMReset(void)
1167 {
1168         OPReset();
1169         BlitterReset();
1170         memset(tomRam8, 0x00, 0x4000);
1171
1172         if (vjs.hardwareTypeNTSC)
1173         {
1174                 SET16(tomRam8, MEMCON1, 0x1861);
1175                 SET16(tomRam8, MEMCON2, 0x35CC);
1176                 SET16(tomRam8, HP, 844);                        // Horizontal Period (1-based; HP=845)
1177                 SET16(tomRam8, HBB, 1713);                      // Horizontal Blank Begin
1178                 SET16(tomRam8, HBE, 125);                       // Horizontal Blank End
1179                 SET16(tomRam8, HDE, 1665);                      // Horizontal Display End
1180                 SET16(tomRam8, HDB1, 203);                      // Horizontal Display Begin 1
1181                 SET16(tomRam8, VP, 523);                        // Vertical Period (1-based; in this case VP = 524)
1182                 SET16(tomRam8, VBE, 24);                        // Vertical Blank End
1183                 SET16(tomRam8, VDB, 38);                        // Vertical Display Begin
1184                 SET16(tomRam8, VDE, 518);                       // Vertical Display End
1185                 SET16(tomRam8, VBB, 500);                       // Vertical Blank Begin
1186                 SET16(tomRam8, VS, 517);                        // Vertical Sync
1187                 SET16(tomRam8, VMODE, 0x06C1);
1188         }
1189         else    // PAL Jaguar
1190         {
1191                 SET16(tomRam8, MEMCON1, 0x1861);
1192                 SET16(tomRam8, MEMCON2, 0x35CC);
1193                 SET16(tomRam8, HP, 850);                        // Horizontal Period
1194                 SET16(tomRam8, HBB, 1711);                      // Horizontal Blank Begin
1195                 SET16(tomRam8, HBE, 158);                       // Horizontal Blank End
1196                 SET16(tomRam8, HDE, 1665);                      // Horizontal Display End
1197                 SET16(tomRam8, HDB1, 203);                      // Horizontal Display Begin 1
1198                 SET16(tomRam8, VP, 623);                        // Vertical Period (1-based; in this case VP = 624)
1199                 SET16(tomRam8, VBE, 34);                        // Vertical Blank End
1200                 SET16(tomRam8, VDB, 38);                        // Vertical Display Begin
1201                 SET16(tomRam8, VDE, 518);                       // Vertical Display End
1202                 SET16(tomRam8, VBB, 600);                       // Vertical Blank Begin
1203                 SET16(tomRam8, VS, 618);                        // Vertical Sync
1204                 SET16(tomRam8, VMODE, 0x06C1);
1205         }
1206
1207         tomWidth = 0;
1208         tomHeight = 0;
1209
1210         tom_jerry_int_pending = 0;
1211         tom_timer_int_pending = 0;
1212         tom_object_int_pending = 0;
1213         tom_gpu_int_pending = 0;
1214         tom_video_int_pending = 0;
1215
1216         tomTimerPrescaler = 0;                                  // TOM PIT is disabled
1217         tomTimerDivider = 0;
1218         tomTimerCounter = 0;
1219 }
1220
1221 //
1222 // TOM byte access (read)
1223 //
1224 uint8 TOMReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
1225 {
1226 //???Is this needed???
1227 // It seems so. Perhaps it's the +$8000 offset being written to (32-bit interface)?
1228 // However, the 32-bit interface is WRITE ONLY, so that can't be it...
1229 // Also, the 68K CANNOT make use of the 32-bit interface, since its bus width is only 16-bits...
1230 //      offset &= 0xFF3FFF;
1231
1232 #ifdef TOM_DEBUG
1233         WriteLog("TOM: Reading byte at %06X for %s\n", offset, whoName[who]);
1234 #endif
1235
1236         if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1237                 return GPUReadByte(offset, who);
1238         else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1239                 return GPUReadByte(offset, who);
1240 /*      else if ((offset >= 0xF00010) && (offset < 0xF00028))
1241                 return OPReadByte(offset, who);*/
1242         else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1243                 return BlitterReadByte(offset, who);
1244         else if (offset == 0xF00050)
1245                 return tomTimerPrescaler >> 8;
1246         else if (offset == 0xF00051)
1247                 return tomTimerPrescaler & 0xFF;
1248         else if (offset == 0xF00052)
1249                 return tomTimerDivider >> 8;
1250         else if (offset == 0xF00053)
1251                 return tomTimerDivider & 0xFF;
1252
1253         return tomRam8[offset & 0x3FFF];
1254 }
1255
1256 //
1257 // TOM word access (read)
1258 //
1259 uint16 TOMReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
1260 {
1261 //???Is this needed???
1262 //      offset &= 0xFF3FFF;
1263 #ifdef TOM_DEBUG
1264         WriteLog("TOM: Reading word at %06X for %s\n", offset, whoName[who]);
1265 #endif
1266 if (offset >= 0xF02000 && offset <= 0xF020FF)
1267         WriteLog("TOM: Read attempted from GPU register file by %s (unimplemented)!\n", whoName[who]);
1268
1269         if (offset == 0xF000E0)
1270         {
1271                 // For reading, should only return the lower 5 bits...
1272                 uint16 data = (tom_jerry_int_pending << 4) | (tom_timer_int_pending << 3)
1273                         | (tom_object_int_pending << 2) | (tom_gpu_int_pending << 1)
1274                         | (tom_video_int_pending << 0);
1275                 //WriteLog("tom: interrupt status is 0x%.4x \n",data);
1276                 return data;
1277         }
1278 //Shoud be handled by the jaguar main loop now... And it is! ;-)
1279 /*      else if (offset == 0xF00006)    // VC
1280         // What if we're in interlaced mode?
1281         // According to docs, in non-interlace mode VC is ALWAYS even...
1282 //              return (tom_scanline << 1);// + 1;
1283 //But it's causing Rayman to be fucked up... Why???
1284 //Because VC is even in NI mode when calling the OP! That's why!
1285                 return (tom_scanline << 1) + 1;//*/
1286 /*
1287 //      F00004          R/W   -----xxx xxxxxxxx   HC - horizontal count
1288 //                            -----x-- --------      (which half of the display)
1289 //                            ------xx xxxxxxxx      (10-bit counter)
1290 */
1291 // This is a kludge to get the HC working somewhat... What we really should do here
1292 // is check what the global time is at the time of the read and calculate the correct HC...
1293 // !!! FIX !!!
1294         else if (offset == 0xF00004)
1295                 return rand() & 0x03FF;
1296         else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE + 0x20))
1297                 return GPUReadWord(offset, who);
1298         else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000))
1299                 return GPUReadWord(offset, who);
1300 /*      else if ((offset >= 0xF00010) && (offset < 0xF00028))
1301                 return OPReadWord(offset, who);*/
1302         else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1303                 return BlitterReadWord(offset, who);
1304         else if (offset == 0xF00050)
1305                 return tomTimerPrescaler;
1306         else if (offset == 0xF00052)
1307                 return tomTimerDivider;
1308
1309         offset &= 0x3FFF;
1310         return (TOMReadByte(offset, who) << 8) | TOMReadByte(offset + 1, who);
1311 }
1312
1313 #define TOM_STRICT_MEMORY_ACCESS
1314 //
1315 // TOM byte access (write)
1316 //
1317 void TOMWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
1318 {
1319 #ifdef TOM_DEBUG
1320         WriteLog("TOM: Writing byte %02X at %06X", data, offset);
1321 #endif
1322 //???Is this needed???
1323 // Perhaps on the writes--32-bit writes that is! And masked with FF7FFF...
1324 #ifndef TOM_STRICT_MEMORY_ACCESS
1325         offset &= 0xFF3FFF;
1326 #else
1327         // "Fast" (32-bit only) write access to the GPU
1328 //      if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF))
1329         if ((offset >= 0xF08000) && (offset <= 0xF0BFFF))
1330                 offset &= 0xFF7FFF;
1331 #endif
1332 #ifdef TOM_DEBUG
1333         WriteLog(" -->[%06X] by %s\n", offset, whoName[who]);
1334 #endif
1335
1336 #ifdef TOM_STRICT_MEMORY_ACCESS
1337         // Sanity check ("Aww, there ain't no Sanity Clause...")
1338         if ((offset < 0xF00000) || (offset > 0xF03FFF))
1339                 return;
1340 #endif
1341
1342         if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1343         {
1344                 GPUWriteByte(offset, data, who);
1345                 return;
1346         }
1347         else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1348         {
1349                 GPUWriteByte(offset, data, who);
1350                 return;
1351         }
1352 /*      else if ((offset >= 0xF00010) && (offset < 0xF00028))
1353         {
1354                 OPWriteByte(offset, data, who);
1355                 return;
1356         }*/
1357         else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1358         {
1359                 BlitterWriteByte(offset, data, who);
1360                 return;
1361         }
1362         else if (offset == 0xF00050)
1363         {
1364                 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | (data << 8);
1365                 TOMResetPIT();
1366                 return;
1367         }
1368         else if (offset == 0xF00051)
1369         {
1370                 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | data;
1371                 TOMResetPIT();
1372                 return;
1373         }
1374         else if (offset == 0xF00052)
1375         {
1376                 tomTimerDivider = (tomTimerDivider & 0x00FF) | (data << 8);
1377                 TOMResetPIT();
1378                 return;
1379         }
1380         else if (offset == 0xF00053)
1381         {
1382                 tomTimerDivider = (tomTimerDivider & 0xFF00) | data;
1383                 TOMResetPIT();
1384                 return;
1385         }
1386         else if (offset >= 0xF00400 && offset <= 0xF007FF)      // CLUT (A & B)
1387         {
1388                 // Writing to one CLUT writes to the other
1389                 offset &= 0x5FF;                // Mask out $F00600 (restrict to $F00400-5FF)
1390                 tomRam8[offset] = data, tomRam8[offset + 0x200] = data;
1391         }
1392
1393         tomRam8[offset & 0x3FFF] = data;
1394 }
1395
1396 //
1397 // TOM word access (write)
1398 //
1399 void TOMWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
1400 {
1401 #ifdef TOM_DEBUG
1402         WriteLog("TOM: Writing byte %04X at %06X", data, offset);
1403 #endif
1404 //???Is this needed??? Yes, but we need to be more vigilant than this.
1405 #ifndef TOM_STRICT_MEMORY_ACCESS
1406         offset &= 0xFF3FFF;
1407 #else
1408         // "Fast" (32-bit only) write access to the GPU
1409 //      if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF))
1410         if ((offset >= 0xF08000) && (offset <= 0xF0BFFF))
1411                 offset &= 0xFF7FFF;
1412 #endif
1413 #ifdef TOM_DEBUG
1414         WriteLog(" -->[%06X] by %s\n", offset, whoName[who]);
1415 #endif
1416
1417 #ifdef TOM_STRICT_MEMORY_ACCESS
1418         // Sanity check
1419         if ((offset < 0xF00000) || (offset > 0xF03FFF))
1420                 return;
1421 #endif
1422
1423 //if (offset == 0xF00000 + MEMCON1)
1424 //      WriteLog("TOM: Memory Configuration 1 written by %s: %04X\n", whoName[who], data);
1425 //if (offset == 0xF00000 + MEMCON2)
1426 //      WriteLog("TOM: Memory Configuration 2 written by %s: %04X\n", whoName[who], data);
1427 if (offset >= 0xF02000 && offset <= 0xF020FF)
1428         WriteLog("TOM: Write attempted to GPU register file by %s (unimplemented)!\n", whoName[who]);
1429
1430         if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1431         {
1432                 GPUWriteWord(offset, data, who);
1433                 return;
1434         }
1435         else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1436         {
1437                 GPUWriteWord(offset, data, who);
1438                 return;
1439         }
1440 //What's so special about this?
1441 /*      else if ((offset >= 0xF00000) && (offset < 0xF00002))
1442         {
1443                 TOMWriteByte(offset, data >> 8);
1444                 TOMWriteByte(offset+1, data & 0xFF);
1445         }*/
1446 /*      else if ((offset >= 0xF00010) && (offset < 0xF00028))
1447         {
1448                 OPWriteWord(offset, data, who);
1449                 return;
1450         }*/
1451         else if (offset == 0xF00050)
1452         {
1453                 tomTimerPrescaler = data;
1454                 TOMResetPIT();
1455                 return;
1456         }
1457         else if (offset == 0xF00052)
1458         {
1459                 tomTimerDivider = data;
1460                 TOMResetPIT();
1461                 return;
1462         }
1463         else if (offset == 0xF000E0)
1464         {
1465 //Check this out...
1466                 if (data & 0x0100)
1467                         tom_video_int_pending = 0;
1468                 if (data & 0x0200)
1469                         tom_gpu_int_pending = 0;
1470                 if (data & 0x0400)
1471                         tom_object_int_pending = 0;
1472                 if (data & 0x0800)
1473                         tom_timer_int_pending = 0;
1474                 if (data & 0x1000)
1475                         tom_jerry_int_pending = 0;
1476
1477 //              return;
1478         }
1479         else if ((offset >= 0xF02200) && (offset <= 0xF0229F))
1480         {
1481                 BlitterWriteWord(offset, data, who);
1482                 return;
1483         }
1484         else if (offset >= 0xF00400 && offset <= 0xF007FE)      // CLUT (A & B)
1485         {
1486                 // Writing to one CLUT writes to the other
1487                 offset &= 0x5FF;                // Mask out $F00600 (restrict to $F00400-5FF)
1488 // Watch out for unaligned writes here! (Not fixed yet)
1489 #warning "!!! Watch out for unaligned writes here !!! FIX !!!"
1490                 SET16(tomRam8, offset, data);
1491                 SET16(tomRam8, offset + 0x200, data);
1492         }
1493
1494         offset &= 0x3FFF;
1495         if (offset == 0x28)                     // VMODE (Why? Why not OBF?)
1496 //Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!
1497 #warning "Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!"
1498                 objectp_running = 1;
1499
1500         if (offset >= 0x30 && offset <= 0x4E)
1501                 data &= 0x07FF;                 // These are (mostly) 11-bit registers
1502         if (offset == 0x2E || offset == 0x36 || offset == 0x54)
1503                 data &= 0x03FF;                 // These are all 10-bit registers
1504
1505 // Fix a lockup bug... :-P
1506         TOMWriteByte(0xF00000 | offset, data >> 8, who);
1507         TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who);
1508
1509 if (offset == MEMCON1)
1510         WriteLog("TOM: Memory Config 1 written by %s: $%04X\n", whoName[who], data);
1511 if (offset == MEMCON2)
1512         WriteLog("TOM: Memory Config 2 written by %s: $%04X\n", whoName[who], data);
1513 //if (offset == OLP)
1514 //      WriteLog("TOM: Object List Pointer written by %s: $%04X\n", whoName[who], data);
1515 //if (offset == OLP + 2)
1516 //      WriteLog("TOM: Object List Pointer +2 written by %s: $%04X\n", whoName[who], data);
1517 //if (offset == OBF)
1518 //      WriteLog("TOM: Object Processor Flag written by %s: %u\n", whoName[who], data);
1519 if (offset == VMODE)
1520         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));
1521 if (offset == BORD1)
1522         WriteLog("TOM: Border 1 written by %s: $%04X\n", whoName[who], data);
1523 if (offset == BORD2)
1524         WriteLog("TOM: Border 2 written by %s: $%04X\n", whoName[who], data);
1525 if (offset == HP)
1526         WriteLog("TOM: Horizontal Period written by %s: %u (+1*2 = %u)\n", whoName[who], data, (data + 1) * 2);
1527 if (offset == HBB)
1528         WriteLog("TOM: Horizontal Blank Begin written by %s: %u\n", whoName[who], data);
1529 if (offset == HBE)
1530         WriteLog("TOM: Horizontal Blank End written by %s: %u\n", whoName[who], data);
1531 if (offset == HS)
1532         WriteLog("TOM: Horizontal Sync written by %s: %u\n", whoName[who], data);
1533 if (offset == HVS)
1534         WriteLog("TOM: Horizontal Vertical Sync written by %s: %u\n", whoName[who], data);
1535 if (offset == HDB1)
1536         WriteLog("TOM: Horizontal Display Begin 1 written by %s: %u\n", whoName[who], data);
1537 if (offset == HDB2)
1538         WriteLog("TOM: Horizontal Display Begin 2 written by %s: %u\n", whoName[who], data);
1539 if (offset == HDE)
1540         WriteLog("TOM: Horizontal Display End written by %s: %u\n", whoName[who], data);
1541 if (offset == VP)
1542         WriteLog("TOM: Vertical Period written by %s: %u (%sinterlaced)\n", whoName[who], data, (data & 0x01 ? "non-" : ""));
1543 if (offset == VBB)
1544         WriteLog("TOM: Vertical Blank Begin written by %s: %u\n", whoName[who], data);
1545 if (offset == VBE)
1546         WriteLog("TOM: Vertical Blank End written by %s: %u\n", whoName[who], data);
1547 if (offset == VS)
1548         WriteLog("TOM: Vertical Sync written by %s: %u\n", whoName[who], data);
1549 if (offset == VDB)
1550         WriteLog("TOM: Vertical Display Begin written by %s: %u\n", whoName[who], data);
1551 if (offset == VDE)
1552         WriteLog("TOM: Vertical Display End written by %s: %u\n", whoName[who], data);
1553 if (offset == VEB)
1554         WriteLog("TOM: Vertical Equalization Begin written by %s: %u\n", whoName[who], data);
1555 if (offset == VEE)
1556         WriteLog("TOM: Vertical Equalization End written by %s: %u\n", whoName[who], data);
1557 if (offset == VI)
1558         WriteLog("TOM: Vertical Interrupt written by %s: %u\n", whoName[who], data);
1559 if (offset == PIT0)
1560         WriteLog("TOM: PIT0 written by %s: %u\n", whoName[who], data);
1561 if (offset == PIT1)
1562         WriteLog("TOM: PIT1 written by %s: %u\n", whoName[who], data);
1563 if (offset == HEQ)
1564         WriteLog("TOM: Horizontal Equalization End written by %s: %u\n", whoName[who], data);
1565 //if (offset == BG)
1566 //      WriteLog("TOM: Background written by %s: %u\n", whoName[who], data);
1567 //if (offset == INT1)
1568 //      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" : ""));
1569
1570         // detect screen resolution changes
1571 //This may go away in the future, if we do the virtualized screen thing...
1572 //This may go away soon!
1573 // TOM Shouldn't be mucking around with this, it's up to the host system to properly
1574 // handle this kind of crap.
1575 // NOTE: This is needed somehow, need to get rid of the dependency on this crap.
1576 #warning "!!! Need to get rid of this dependency !!!"
1577 #if 1
1578         if ((offset >= 0x28) && (offset <= 0x4F))
1579         {
1580                 uint32 width = TOMGetVideoModeWidth(), height = TOMGetVideoModeHeight();
1581
1582                 if ((width != tomWidth) || (height != tomHeight))
1583                 {
1584                         tomWidth = width, tomHeight = height;
1585
1586 #warning "!!! TOM: ResizeScreen commented out !!!"
1587 // No need to resize anything, since we're prepared for this...
1588 //                      if (vjs.renderType == RT_NORMAL)
1589 //                              ResizeScreen(tomWidth, tomHeight);
1590                 }
1591         }
1592 #endif
1593 }
1594
1595 int TOMIRQEnabled(int irq)
1596 {
1597         // This is the correct byte in big endian... D'oh!
1598 //      return jaguar_byte_read(0xF000E1) & (1 << irq);
1599         return tomRam8[INT1 + 1/*0xE1*/] & (1 << irq);
1600 }
1601
1602 // NEW:
1603 // TOM Programmable Interrupt Timer handler
1604 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
1605 //       The PIT only generates an interrupt when it counts down to zero, not when loaded!
1606
1607 void TOMPITCallback(void);
1608
1609 void TOMResetPIT(void)
1610 {
1611 #ifndef NEW_TIMER_SYSTEM
1612 //Probably should *add* this amount to the counter to retain cycle accuracy! !!! FIX !!! [DONE]
1613 //Also, why +1??? 'Cause that's what it says in the JTRM...!
1614 //There is a small problem with this approach: If both the prescaler and the divider are equal
1615 //to $FFFF then the counter won't be large enough to handle it. !!! FIX !!!
1616         if (tom_timer_prescaler)
1617                 tom_timer_counter += (1 + tom_timer_prescaler) * (1 + tom_timer_divider);
1618 //      WriteLog("tom: reseting timer to 0x%.8x (%i)\n",tom_timer_counter,tom_timer_counter);
1619 #else
1620         // Need to remove previous timer from the queue, if it exists...
1621         RemoveCallback(TOMPITCallback);
1622
1623         if (tomTimerPrescaler)
1624         {
1625                 double usecs = (float)(tomTimerPrescaler + 1) * (float)(tomTimerDivider + 1) * RISC_CYCLE_IN_USEC;
1626                 SetCallbackTime(TOMPITCallback, usecs);
1627         }
1628 #endif
1629 }
1630
1631 //
1632 // TOM Programmable Interrupt Timer handler
1633 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
1634 //
1635 //NOTE: This is only used by the old execution code... Safe to remove
1636 //      once the timer system is stable.
1637 void TOMExecPIT(uint32 cycles)
1638 {
1639         if (tomTimerPrescaler)
1640         {
1641                 tomTimerCounter -= cycles;
1642
1643                 if (tomTimerCounter <= 0)
1644                 {
1645                         TOMSetPendingTimerInt();
1646                         GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE);       // GPUSetIRQLine does the 'IRQ enabled' checking
1647
1648                         if (TOMIRQEnabled(IRQ_TIMER))
1649                                 m68k_set_irq(2);                                // Cause a 68000 IPL 2...
1650
1651                         TOMResetPIT();
1652                 }
1653         }
1654 }
1655
1656 void TOMPITCallback(void)
1657 {
1658 //      INT1_RREG |= 0x08;                                                      // Set TOM PIT interrupt pending
1659         TOMSetPendingTimerInt();
1660     GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE);   // It does the 'IRQ enabled' checking
1661
1662 //      if (INT1_WREG & 0x08)
1663         if (TOMIRQEnabled(IRQ_TIMER))
1664                 m68k_set_irq(2);                                                // Generate a 68K IPL 2...
1665
1666         TOMResetPIT();
1667 }