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