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