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