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