]> Shamusworld >> Repos - virtualjaguar/blob - src/tom.cpp
Added Memory Track support. One small step towards full CD-ROM support.
[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, endian wrongness amelioration, and extensive fixes 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: TOM has only a 16K memory space
17 //
18 //      ------------------------------------------------------------
19 //      TOM REGISTERS (Mapped by Aaron Giles)
20 //      ------------------------------------------------------------
21 //      F00000-F0FFFF   R/W   xxxxxxxx xxxxxxxx   Internal Registers
22 //      F00000          R/W   -x-xx--- xxxxxxxx   MEMCON1 - memory config reg 1
23 //                            -x------ --------      (CPU32 - is the CPU 32bits?)
24 //                            ---xx--- --------      (IOSPEED - external I/O clock cycles)
25 //                            -------- x-------      (FASTROM - reduces ROM clock cycles)
26 //                            -------- -xx-----      (DRAMSPEED - sets RAM clock cycles)
27 //                            -------- ---xx---      (ROMSPEED - sets ROM clock cycles)
28 //                            -------- -----xx-      (ROMWIDTH - sets width of ROM: 8,16,32,64 bits)
29 //                            -------- -------x      (ROMHI - controls ROM mapping)
30 //      F00002          R/W   --xxxxxx xxxxxxxx   MEMCON2 - memory config reg 2
31 //                            --x----- --------      (HILO - image display bit order)
32 //                            ---x---- --------      (BIGEND - big endian addressing?)
33 //                            ----xxxx --------      (REFRATE - DRAM refresh rate)
34 //                            -------- xx------      (DWIDTH1 - DRAM1 width: 8,16,32,64 bits)
35 //                            -------- --xx----      (COLS1 - DRAM1 columns: 256,512,1024,2048)
36 //                            -------- ----xx--      (DWIDTH0 - DRAM0 width: 8,16,32,64 bits)
37 //                            -------- ------xx      (COLS0 - DRAM0 columns: 256,512,1024,2048)
38 //      F00004          R/W   -----xxx xxxxxxxx   HC - horizontal count
39 //                            -----x-- --------      (which half of the display)
40 //                            ------xx xxxxxxxx      (10-bit counter)
41 //      F00006          R/W   ----xxxx xxxxxxxx   VC - vertical count
42 //                            ----x--- --------      (which field is being generated)
43 //                            -----xxx xxxxxxxx      (11-bit counter)
44 //      F00008          R     -----xxx xxxxxxxx   LPH - light pen horizontal position
45 //      F0000A          R     -----xxx xxxxxxxx   LPV - light pen vertical position
46 //      F00010-F00017   R     xxxxxxxx xxxxxxxx   OB - current object code from the graphics processor
47 //      F00020-F00023     W   xxxxxxxx xxxxxxxx   OLP - start of the object list
48 //      F00026            W   -------- -------x   OBF - object processor flag
49 //      F00028            W   ----xxxx xxxxxxxx   VMODE - video mode
50 //                        W   ----xxx- --------      (PWIDTH1-8 - width of pixel in video clock cycles)
51 //                        W   -------x --------      (VARMOD - enable variable color resolution)
52 //                        W   -------- x-------      (BGEN - clear line buffer to BG color)
53 //                        W   -------- -x------      (CSYNC - enable composite sync on VSYNC)
54 //                        W   -------- --x-----      (BINC - local border color if INCEN)
55 //                        W   -------- ---x----      (INCEN - encrustation enable)
56 //                        W   -------- ----x---      (GENLOCK - enable genlock)
57 //                        W   -------- -----xx-      (MODE - CRY16,RGB24,DIRECT16,RGB16)
58 //                        W   -------- -------x      (VIDEN - enables video)
59 //      F0002A            W   xxxxxxxx xxxxxxxx   BORD1 - border color (red/green)
60 //      F0002C            W   -------- xxxxxxxx   BORD2 - border color (blue)
61 //      F0002E            W   ------xx xxxxxxxx   HP - horizontal period
62 //      F00030            W   -----xxx xxxxxxxx   HBB - horizontal blanking begin
63 //      F00032            W   -----xxx xxxxxxxx   HBE - horizontal blanking end
64 //      F00034            W   -----xxx xxxxxxxx   HSYNC - horizontal sync
65 //      F00036            W   ------xx xxxxxxxx   HVS - horizontal vertical sync
66 //      F00038            W   -----xxx xxxxxxxx   HDB1 - horizontal display begin 1
67 //      F0003A            W   -----xxx xxxxxxxx   HDB2 - horizontal display begin 2
68 //      F0003C            W   -----xxx xxxxxxxx   HDE - horizontal display end
69 //      F0003E            W   -----xxx xxxxxxxx   VP - vertical period
70 //      F00040            W   -----xxx xxxxxxxx   VBB - vertical blanking begin
71 //      F00042            W   -----xxx xxxxxxxx   VBE - vertical blanking end
72 //      F00044            W   -----xxx xxxxxxxx   VS - vertical sync
73 //      F00046            W   -----xxx xxxxxxxx   VDB - vertical display begin
74 //      F00048            W   -----xxx xxxxxxxx   VDE - vertical display end
75 //      F0004A            W   -----xxx xxxxxxxx   VEB - vertical equalization begin
76 //      F0004C            W   -----xxx xxxxxxxx   VEE - vertical equalization end
77 //      F0004E            W   -----xxx xxxxxxxx   VI - vertical interrupt
78 //      F00050            W   xxxxxxxx xxxxxxxx   PIT0 - programmable interrupt timer 0
79 //      F00052            W   xxxxxxxx xxxxxxxx   PIT1 - programmable interrupt timer 1
80 //      F00054            W   ------xx xxxxxxxx   HEQ - horizontal equalization end
81 //      F00058            W   xxxxxxxx xxxxxxxx   BG - background color
82 //      F000E0          R/W   ---xxxxx ---xxxxx   INT1 - CPU interrupt control register
83 //                            ---x---- --------      (C_JERCLR - clear pending Jerry ints)
84 //                            ----x--- --------      (C_PITCLR - clear pending PIT ints)
85 //                            -----x-- --------      (C_OPCLR - clear pending object processor ints)
86 //                            ------x- --------      (C_GPUCLR - clear pending graphics processor ints)
87 //                            -------x --------      (C_VIDCLR - clear pending video timebase ints)
88 //                            -------- ---x----      (C_JERENA - enable Jerry ints)
89 //                            -------- ----x---      (C_PITENA - enable PIT ints)
90 //                            -------- -----x--      (C_OPENA - enable object processor ints)
91 //                            -------- ------x-      (C_GPUENA - enable graphics processor ints)
92 //                            -------- -------x      (C_VIDENA - enable video timebase ints)
93 //      F000E2            W   -------- --------   INT2 - CPU interrupt resume register
94 //      F00400-F005FF   R/W   xxxxxxxx xxxxxxxx   CLUT - color lookup table A
95 //      F00600-F007FF   R/W   xxxxxxxx xxxxxxxx   CLUT - color lookup table B
96 //      F00800-F00D9F   R/W   xxxxxxxx xxxxxxxx   LBUF - line buffer A
97 //      F01000-F0159F   R/W   xxxxxxxx xxxxxxxx   LBUF - line buffer B
98 //      F01800-F01D9F   R/W   xxxxxxxx xxxxxxxx   LBUF - line buffer currently selected
99 //      ------------------------------------------------------------
100 //      F02000-F021FF   R/W   xxxxxxxx xxxxxxxx   GPU control registers
101 //      F02100          R/W   xxxxxxxx xxxxxxxx   G_FLAGS - GPU flags register
102 //                      R/W   x------- --------      (DMAEN - DMA enable)
103 //                      R/W   -x------ --------      (REGPAGE - register page)
104 //                        W   --x----- --------      (G_BLITCLR - clear blitter interrupt)
105 //                        W   ---x---- --------      (G_OPCLR - clear object processor int)
106 //                        W   ----x--- --------      (G_PITCLR - clear PIT interrupt)
107 //                        W   -----x-- --------      (G_JERCLR - clear Jerry interrupt)
108 //                        W   ------x- --------      (G_CPUCLR - clear CPU interrupt)
109 //                      R/W   -------x --------      (G_BLITENA - enable blitter interrupt)
110 //                      R/W   -------- x-------      (G_OPENA - enable object processor int)
111 //                      R/W   -------- -x------      (G_PITENA - enable PIT interrupt)
112 //                      R/W   -------- --x-----      (G_JERENA - enable Jerry interrupt)
113 //                      R/W   -------- ---x----      (G_CPUENA - enable CPU interrupt)
114 //                      R/W   -------- ----x---      (IMASK - interrupt mask)
115 //                      R/W   -------- -----x--      (NEGA_FLAG - ALU negative)
116 //                      R/W   -------- ------x-      (CARRY_FLAG - ALU carry)
117 //                      R/W   -------- -------x      (ZERO_FLAG - ALU zero)
118 //      F02104            W   -------- ----xxxx   G_MTXC - matrix control register
119 //                        W   -------- ----x---      (MATCOL - column/row major)
120 //                        W   -------- -----xxx      (MATRIX3-15 - matrix width)
121 //      F02108            W   ----xxxx xxxxxx--   G_MTXA - matrix address register
122 //      F0210C            W   -------- -----xxx   G_END - data organization register
123 //                        W   -------- -----x--      (BIG_INST - big endian instruction fetch)
124 //                        W   -------- ------x-      (BIG_PIX - big endian pixels)
125 //                        W   -------- -------x      (BIG_IO - big endian I/O)
126 //      F02110          R/W   xxxxxxxx xxxxxxxx   G_PC - GPU program counter
127 //      F02114          R/W   xxxxxxxx xx-xxxxx   G_CTRL - GPU control/status register
128 //                      R     xxxx---- --------      (VERSION - GPU version code)
129 //                      R/W   ----x--- --------      (BUS_HOG - hog the bus!)
130 //                      R/W   -----x-- --------      (G_BLITLAT - blitter interrupt latch)
131 //                      R/W   ------x- --------      (G_OPLAT - object processor int latch)
132 //                      R/W   -------x --------      (G_PITLAT - PIT interrupt latch)
133 //                      R/W   -------- x-------      (G_JERLAT - Jerry interrupt latch)
134 //                      R/W   -------- -x------      (G_CPULAT - CPU interrupt latch)
135 //                      R/W   -------- ---x----      (SINGLE_GO - single step one instruction)
136 //                      R/W   -------- ----x---      (SINGLE_STEP - single step mode)
137 //                      R/W   -------- -----x--      (FORCEINT0 - cause interrupt 0 on GPU)
138 //                      R/W   -------- ------x-      (CPUINT - send GPU interrupt to CPU)
139 //                      R/W   -------- -------x      (GPUGO - enable GPU execution)
140 //      F02118-F0211B   R/W   xxxxxxxx xxxxxxxx   G_HIDATA - high data register
141 //      F0211C-F0211F   R     xxxxxxxx xxxxxxxx   G_REMAIN - divide unit remainder
142 //      F0211C            W   -------- -------x   G_DIVCTRL - divide unit control
143 //                        W   -------- -------x      (DIV_OFFSET - 1=16.16 divide, 0=32-bit divide)
144 //      ------------------------------------------------------------
145 //      BLITTER REGISTERS
146 //      ------------------------------------------------------------
147 //      F02200-F022FF   R/W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   Blitter registers
148 //      F02200            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A1_BASE - A1 base register
149 //      F02204            W   -------- ---xxxxx -xxxxxxx xxxxx-xx   A1_FLAGS - A1 flags register
150 //                        W   -------- ---x---- -------- --------      (YSIGNSUB - invert sign of Y delta)
151 //                        W   -------- ----x--- -------- --------      (XSIGNSUB - invert sign of X delta)
152 //                        W   -------- -----x-- -------- --------      (Y add control)
153 //                        W   -------- ------xx -------- --------      (X add control)
154 //                        W   -------- -------- -xxxxxx- --------      (width in 6-bit floating point)
155 //                        W   -------- -------- -------x xx------      (ZOFFS1-6 - Z data offset)
156 //                        W   -------- -------- -------- --xxx---      (PIXEL - pixel size)
157 //                        W   -------- -------- -------- ------xx      (PITCH1-4 - data phrase pitch)
158 //      F02208            W   -xxxxxxx xxxxxxxx -xxxxxxx xxxxxxxx   A1_CLIP - A1 clipping size
159 //                        W   -xxxxxxx xxxxxxxx -------- --------      (height)
160 //                        W   -------- -------- -xxxxxxx xxxxxxxx      (width)
161 //      F0220C          R/W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A1_PIXEL - A1 pixel pointer
162 //                      R/W   xxxxxxxx xxxxxxxx -------- --------      (Y pixel value)
163 //                      R/W   -------- -------- xxxxxxxx xxxxxxxx      (X pixel value)
164 //      F02210            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A1_STEP - A1 step value
165 //                        W   xxxxxxxx xxxxxxxx -------- --------      (Y step value)
166 //                        W   -------- -------- xxxxxxxx xxxxxxxx      (X step value)
167 //      F02214            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A1_FSTEP - A1 step fraction value
168 //                        W   xxxxxxxx xxxxxxxx -------- --------      (Y step fraction value)
169 //                        W   -------- -------- xxxxxxxx xxxxxxxx      (X step fraction value)
170 //      F02218          R/W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A1_FPIXEL - A1 pixel pointer fraction
171 //                      R/W   xxxxxxxx xxxxxxxx -------- --------      (Y pixel fraction value)
172 //                      R/W   -------- -------- xxxxxxxx xxxxxxxx      (X pixel fraction value)
173 //      F0221C            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A1_INC - A1 increment
174 //                        W   xxxxxxxx xxxxxxxx -------- --------      (Y increment)
175 //                        W   -------- -------- xxxxxxxx xxxxxxxx      (X increment)
176 //      F02220            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A1_FINC - A1 increment fraction
177 //                        W   xxxxxxxx xxxxxxxx -------- --------      (Y increment fraction)
178 //                        W   -------- -------- xxxxxxxx xxxxxxxx      (X increment fraction)
179 //      F02224            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A2_BASE - A2 base register
180 //      F02228            W   -------- ---xxxxx -xxxxxxx xxxxx-xx   A2_FLAGS - A2 flags register
181 //                        W   -------- ---x---- -------- --------      (YSIGNSUB - invert sign of Y delta)
182 //                        W   -------- ----x--- -------- --------      (XSIGNSUB - invert sign of X delta)
183 //                        W   -------- -----x-- -------- --------      (Y add control)
184 //                        W   -------- ------xx -------- --------      (X add control)
185 //                        W   -------- -------- -xxxxxx- --------      (width in 6-bit floating point)
186 //                        W   -------- -------- -------x xx------      (ZOFFS1-6 - Z data offset)
187 //                        W   -------- -------- -------- --xxx---      (PIXEL - pixel size)
188 //                        W   -------- -------- -------- ------xx      (PITCH1-4 - data phrase pitch)
189 //      F0222C            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A2_MASK - A2 window mask
190 //      F02230          R/W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A2_PIXEL - A2 pixel pointer
191 //                      R/W   xxxxxxxx xxxxxxxx -------- --------      (Y pixel value)
192 //                      R/W   -------- -------- xxxxxxxx xxxxxxxx      (X pixel value)
193 //      F02234            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   A2_STEP - A2 step value
194 //                        W   xxxxxxxx xxxxxxxx -------- --------      (Y step value)
195 //                        W   -------- -------- xxxxxxxx xxxxxxxx      (X step value)
196 //      F02238            W   -xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_CMD - command register
197 //                        W   -x------ -------- -------- --------      (SRCSHADE - modify source intensity)
198 //                        W   --x----- -------- -------- --------      (BUSHI - hi priority bus)
199 //                        W   ---x---- -------- -------- --------      (BKGWREN - writeback destination)
200 //                        W   ----x--- -------- -------- --------      (DCOMPEN - write inhibit from data comparator)
201 //                        W   -----x-- -------- -------- --------      (BCOMPEN - write inhibit from bit coparator)
202 //                        W   ------x- -------- -------- --------      (CMPDST - compare dest instead of src)
203 //                        W   -------x xxx----- -------- --------      (logical operation)
204 //                        W   -------- ---xxx-- -------- --------      (ZMODE - Z comparator mode)
205 //                        W   -------- ------x- -------- --------      (ADDDSEL - select sum of src & dst)
206 //                        W   -------- -------x -------- --------      (PATDSEL - select pattern data)
207 //                        W   -------- -------- x------- --------      (TOPNEN - enable carry into top intensity nibble)
208 //                        W   -------- -------- -x------ --------      (TOPBEN - enable carry into top intensity byte)
209 //                        W   -------- -------- --x----- --------      (ZBUFF - enable Z updates in inner loop)
210 //                        W   -------- -------- ---x---- --------      (GOURD - enable gouraud shading in inner loop)
211 //                        W   -------- -------- ----x--- --------      (DSTA2 - reverses A2/A1 roles)
212 //                        W   -------- -------- -----x-- --------      (UPDA2 - add A2 step to A2 in outer loop)
213 //                        W   -------- -------- ------x- --------      (UPDA1 - add A1 step to A1 in outer loop)
214 //                        W   -------- -------- -------x --------      (UPDA1F - add A1 fraction step to A1 in outer loop)
215 //                        W   -------- -------- -------- x-------      (diagnostic use)
216 //                        W   -------- -------- -------- -x------      (CLIP_A1 - clip A1 to window)
217 //                        W   -------- -------- -------- --x-----      (DSTWRZ - enable dest Z write in inner loop)
218 //                        W   -------- -------- -------- ---x----      (DSTENZ - enable dest Z read in inner loop)
219 //                        W   -------- -------- -------- ----x---      (DSTEN - enables dest data read in inner loop)
220 //                        W   -------- -------- -------- -----x--      (SRCENX - enable extra src read at start of inner)
221 //                        W   -------- -------- -------- ------x-      (SRCENZ - enables source Z read in inner loop)
222 //                        W   -------- -------- -------- -------x      (SRCEN - enables source data read in inner loop)
223 //      F02238          R     xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_CMD - status register
224 //                      R     xxxxxxxx xxxxxxxx -------- --------      (inner count)
225 //                      R     -------- -------- xxxxxxxx xxxxxx--      (diagnostics)
226 //                      R     -------- -------- -------- ------x-      (STOPPED - when stopped in collision detect)
227 //                      R     -------- -------- -------- -------x      (IDLE - when idle)
228 //      F0223C            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_COUNT - counters register
229 //                        W   xxxxxxxx xxxxxxxx -------- --------      (outer loop count)
230 //                        W   -------- -------- xxxxxxxx xxxxxxxx      (inner loop count)
231 //      F02240-F02247     W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_SRCD - source data register
232 //      F02248-F0224F     W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_DSTD - destination data register
233 //      F02250-F02257     W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_DSTZ - destination Z register
234 //      F02258-F0225F     W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_SRCZ1 - source Z register 1
235 //      F02260-F02267     W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_SRCZ2 - source Z register 2
236 //      F02268-F0226F     W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_PATD - pattern data register
237 //      F02270            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_IINC - intensity increment
238 //      F02274            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_ZINC - Z increment
239 //      F02278            W   -------- -------- -------- -----xxx   B_STOP - collision control
240 //                        W   -------- -------- -------- -----x--      (STOPEN - enable blitter collision stops)
241 //                        W   -------- -------- -------- ------x-      (ABORT - abort after stop)
242 //                        W   -------- -------- -------- -------x      (RESUME - resume after stop)
243 //      F0227C            W   -------- xxxxxxxx xxxxxxxx xxxxxxxx   B_I3 - intensity 3
244 //      F02280            W   -------- xxxxxxxx xxxxxxxx xxxxxxxx   B_I2 - intensity 2
245 //      F02284            W   -------- xxxxxxxx xxxxxxxx xxxxxxxx   B_I1 - intensity 1
246 //      F02288            W   -------- xxxxxxxx xxxxxxxx xxxxxxxx   B_I0 - intensity 0
247 //      F0228C            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_Z3 - Z3
248 //      F02290            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_Z2 - Z2
249 //      F02294            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_Z1 - Z1
250 //      F02298            W   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx   B_Z0 - Z0
251 //      ------------------------------------------------------------
252
253 #include "tom.h"
254
255 #include <string.h>                                                             // For memset()
256 #include <stdlib.h>                                                             // For rand()
257 #include "blitter.h"
258 #include "cry2rgb.h"
259 #include "event.h"
260 #include "gpu.h"
261 #include "jaguar.h"
262 #include "log.h"
263 #include "m68000/m68kinterface.h"
264 //#include "memory.h"
265 #include "op.h"
266 #include "settings.h"
267
268 #define NEW_TIMER_SYSTEM
269
270 // TOM registers (offset from $F00000)
271
272 #define MEMCON1         0x00
273 #define MEMCON2         0x02
274 #define HC                      0x04
275 #define VC                      0x06
276 #define OLP                     0x20    // Object list pointer
277 #define OBF                     0x26    // Object processor flag
278 #define VMODE           0x28
279 #define   MODE          0x0006  // Line buffer to video generator mode
280 #define   BGEN          0x0080  // Background enable (CRY & RGB16 only)
281 #define   VARMOD        0x0100  // Mixed CRY/RGB16 mode (only works in MODE 0!)
282 #define   PWIDTH        0x0E00  // Pixel width in video clock cycles (value written + 1)
283 #define BORD1           0x2A    // Border green/red values (8 BPP)
284 #define BORD2           0x2C    // Border blue value (8 BPP)
285 #define HP                      0x2E    // Values range from 1 - 1024 (value written + 1)
286 #define HBB                     0x30    // Horizontal blank begin
287 #define HBE                     0x32
288 #define HS                      0x34    // Horizontal sync
289 #define HVS                     0x36    // Horizontal vertical sync
290 #define HDB1            0x38    // Horizontal display begin 1
291 #define HDB2            0x3A
292 #define HDE                     0x3C
293 #define VP                      0x3E    // Value ranges from 1 - 2048 (value written + 1)
294 #define VBB                     0x40    // Vertical blank begin
295 #define VBE                     0x42
296 #define VS                      0x44    // Vertical sync
297 #define VDB                     0x46    // Vertical display begin
298 #define VDE                     0x48
299 #define VEB                     0x4A    // Vertical equalization begin
300 #define VEE                     0x4C    // Vertical equalization end
301 #define VI                      0x4E    // Vertical interrupt
302 #define PIT0            0x50
303 #define PIT1            0x52
304 #define HEQ                     0x54    // Horizontal equalization end
305 #define BG                      0x58    // Background color
306 #define INT1            0xE0
307 #define INT2            0xE2
308
309 // Arbitrary video cutoff values (i.e., first/last visible spots on a TV, in HC
310 // ticks)
311 // Also note that VC is in *half* lines, i.e. divide by 2 to get the scanline
312 /*#define LEFT_VISIBLE_HC                       208
313 #define RIGHT_VISIBLE_HC                1528//*/
314 // These were right for Rayman, but that one is offset on a real TV too.
315 //#define LEFT_VISIBLE_HC                       208
316 //#define RIGHT_VISIBLE_HC              1488
317 // This is more like a real TV display...
318 //#define LEFT_VISIBLE_HC                       (208 - 32)
319 //#define RIGHT_VISIBLE_HC              (1488 - 32)
320 // Split the difference? (Seems to be OK for the most part...)
321
322 // (-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).
323 //NB: Went back to 330. May shrink more. :-)
324 //#define LEFT_VISIBLE_HC                       (208 - 16 - (8 * 4))
325 //#define LEFT_VISIBLE_HC                       (208 - 16 - (3 * 4))
326 #define LEFT_VISIBLE_HC                 (208 - 16 - (1 * 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 LEFT_VISIBLE_HC_PAL           (208 - 16 - (-1 * 4))
339 #define LEFT_VISIBLE_HC_PAL             (208 - 16 - (-3 * 4))
340 //#define RIGHT_VISIBLE_HC_PAL  (1488 - 16 + (10 * 4))
341 #define RIGHT_VISIBLE_HC_PAL    (LEFT_VISIBLE_HC_PAL + (VIRTUAL_SCREEN_WIDTH * 4))
342 #define TOP_VISIBLE_VC_PAL              67
343 #define BOTTOM_VISIBLE_VC_PAL   579
344
345 //This can be defined in the makefile as well...
346 //(It's easier to do it here, though...)
347 //#define TOM_DEBUG
348
349 uint8_t tomRam8[0x4000];
350 uint32_t tomWidth, tomHeight;
351 uint32_t tomTimerPrescaler;
352 uint32_t tomTimerDivider;
353 int32_t tomTimerCounter;
354 uint16_t tom_jerry_int_pending, tom_timer_int_pending, tom_object_int_pending,
355         tom_gpu_int_pending, tom_video_int_pending;
356
357 // These are set by the "user" of the Jaguar core lib, since these are
358 // OS/system dependent.
359 uint32_t * screenBuffer;
360 uint32_t screenPitch;
361
362 static const char * videoMode_to_str[8] =
363         { "16 BPP CRY", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB",
364           "Mixed mode", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB" };
365
366 typedef void (render_xxx_scanline_fn)(uint32_t *);
367
368 // Private function prototypes
369
370 void tom_render_16bpp_cry_scanline(uint32_t * backbuffer);
371 void tom_render_24bpp_scanline(uint32_t * backbuffer);
372 void tom_render_16bpp_direct_scanline(uint32_t * backbuffer);
373 void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer);
374 void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer);
375
376 //render_xxx_scanline_fn * scanline_render_normal[] =
377 render_xxx_scanline_fn * scanline_render[] =
378 {
379         tom_render_16bpp_cry_scanline,
380         tom_render_24bpp_scanline,
381         tom_render_16bpp_direct_scanline,
382         tom_render_16bpp_rgb_scanline,
383         tom_render_16bpp_cry_rgb_mix_scanline,
384         tom_render_24bpp_scanline,
385         tom_render_16bpp_direct_scanline,
386         tom_render_16bpp_rgb_scanline
387 };
388
389 // Screen info for various games [PAL]...
390 /*
391 BIOS
392 TOM: Horizontal Period written by M68K: 850 (+1*2 = 1702)
393 TOM: Horizontal Blank Begin written by M68K: 1711
394 TOM: Horizontal Blank End written by M68K: 158
395 TOM: Horizontal Display End written by M68K: 1696
396 TOM: Horizontal Display Begin 1 written by M68K: 166
397 TOM: Vertical Period written by M68K: 623 (non-interlaced)
398 TOM: Vertical Blank End written by M68K: 34
399 TOM: Vertical Display Begin written by M68K: 46
400 TOM: Vertical Display End written by M68K: 526
401 TOM: Vertical Blank Begin written by M68K: 600
402 TOM: Vertical Sync written by M68K: 618
403 TOM: Horizontal Display End written by M68K: 1665
404 TOM: Horizontal Display Begin 1 written by M68K: 203
405 TOM: Vertical Display Begin written by M68K: 38
406 TOM: Vertical Display End written by M68K: 518
407 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 151)
408 TOM: Horizontal Display End written by M68K: 1713
409 TOM: Horizontal Display Begin 1 written by M68K: 157
410 TOM: Vertical Display Begin written by M68K: 35
411 TOM: Vertical Display End written by M68K: 2047
412 Horizontal range: 157 - 1713 (width: 1557 / 4 = 389.25, / 5 = 315.4)
413
414 Asteroid
415 TOM: Horizontal Period written by M68K: 845 (+1*2 = 1692)
416 TOM: Horizontal Blank Begin written by M68K: 1700
417 TOM: Horizontal Blank End written by M68K: 122
418 TOM: Horizontal Display End written by M68K: 1600
419 TOM: Horizontal Display Begin 1 written by M68K: 268
420 TOM: Vertical Period written by M68K: 523 (non-interlaced)
421 TOM: Vertical Blank End written by M68K: 40
422 TOM: Vertical Display Begin written by M68K: 44
423 TOM: Vertical Display End written by M68K: 492
424 TOM: Vertical Blank Begin written by M68K: 532
425 TOM: Vertical Sync written by M68K: 513
426 TOM: Video Mode written by M68K: 04C7. PWIDTH = 3, MODE = 16 BPP RGB, flags: BGEN (VC = 461)
427
428 Rayman
429 TOM: Horizontal Display End written by M68K: 1713
430 TOM: Horizontal Display Begin 1 written by M68K: 157
431 TOM: Vertical Display Begin written by M68K: 35
432 TOM: Vertical Display End written by M68K: 2047
433 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 89)
434 TOM: Horizontal Display Begin 1 written by M68K: 208
435 TOM: Horizontal Display End written by M68K: 1662
436 TOM: Vertical Display Begin written by M68K: 100
437 TOM: Vertical Display End written by M68K: 2047
438 TOM: Video Mode written by M68K: 07C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN VARMOD (VC = 205)
439 Horizontal range: 208 - 1662 (width: 1455 / 4 = 363.5)
440
441 Alien vs Predator
442 TOM: Vertical Display Begin written by M68K: 96
443 TOM: Vertical Display End written by M68K: 2047
444 TOM: Horizontal Display Begin 1 written by M68K: 239
445 TOM: Horizontal Display End written by M68K: 1692
446 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 378)
447 TOM: Vertical Display Begin written by M68K: 44
448 TOM: Vertical Display End written by M68K: 2047
449 TOM: Horizontal Display Begin 1 written by M68K: 239
450 TOM: Horizontal Display End written by M68K: 1692
451 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 559)
452 TOM: Vertical Display Begin written by M68K: 84
453 TOM: Vertical Display End written by M68K: 2047
454 TOM: Horizontal Display Begin 1 written by M68K: 239
455 TOM: Horizontal Display End written by M68K: 1692
456 TOM: Vertical Display Begin written by M68K: 44
457 TOM: Vertical Display End written by M68K: 2047
458 TOM: Horizontal Display Begin 1 written by M68K: 239
459 TOM: Horizontal Display End written by M68K: 1692
460 Horizontal range: 239 - 1692 (width: 1454 / 4 = 363.5)
461
462 */
463
464 // Screen info for various games [NTSC]...
465 /*
466 Doom
467 TOM: Horizontal Display End written by M68K: 1727
468 TOM: Horizontal Display Begin 1 written by M68K: 123
469 TOM: Vertical Display Begin written by M68K: 25
470 TOM: Vertical Display End written by M68K: 2047
471 TOM: Video Mode written by M68K: 0EC1. PWIDTH = 8, MODE = 16 BPP CRY, flags: BGEN (VC = 5)
472 Also does PWIDTH = 4...
473 Vertical resolution: 238 lines
474
475 Rayman
476 TOM: Horizontal Display End written by M68K: 1727
477 TOM: Horizontal Display Begin 1 written by M68K: 123
478 TOM: Vertical Display Begin written by M68K: 25
479 TOM: Vertical Display End written by M68K: 2047
480 TOM: Vertical Interrupt written by M68K: 507
481 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 92)
482 TOM: Horizontal Display Begin 1 written by M68K: 208
483 TOM: Horizontal Display End written by M68K: 1670
484 Display starts at 31, then 52!
485 Vertical resolution: 238 lines
486
487 Atari Karts
488 TOM: Horizontal Display End written by M68K: 1727
489 TOM: Horizontal Display Begin 1 written by M68K: 123
490 TOM: Vertical Display Begin written by M68K: 25
491 TOM: Vertical Display End written by M68K: 2047
492 TOM: Video Mode written by GPU: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 4)
493 TOM: Video Mode written by GPU: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 508)
494 Display starts at 31 (PWIDTH = 4), 24 (PWIDTH = 5)
495
496 Iron Soldier
497 TOM: Vertical Interrupt written by M68K: 2047
498 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 0)
499 TOM: Horizontal Display End written by M68K: 1727
500 TOM: Horizontal Display Begin 1 written by M68K: 123
501 TOM: Vertical Display Begin written by M68K: 25
502 TOM: Vertical Display End written by M68K: 2047
503 TOM: Vertical Interrupt written by M68K: 507
504 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 369)
505 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 510)
506 TOM: Video Mode written by M68K: 06C3. PWIDTH = 4, MODE = 24 BPP RGB, flags: BGEN (VC = 510)
507 Display starts at 31
508 Vertical resolution: 238 lines
509 [Seems to be a problem between the horizontal positioning of the 16-bit CRY & 24-bit RGB]
510
511 JagMania
512 TOM: Horizontal Period written by M68K: 844 (+1*2 = 1690)
513 TOM: Horizontal Blank Begin written by M68K: 1713
514 TOM: Horizontal Blank End written by M68K: 125
515 TOM: Horizontal Display End written by M68K: 1696
516 TOM: Horizontal Display Begin 1 written by M68K: 166
517 TOM: Vertical Period written by M68K: 523 (non-interlaced)
518 TOM: Vertical Blank End written by M68K: 24
519 TOM: Vertical Display Begin written by M68K: 46
520 TOM: Vertical Display End written by M68K: 496
521 TOM: Vertical Blank Begin written by M68K: 500
522 TOM: Vertical Sync written by M68K: 517
523 TOM: Vertical Interrupt written by M68K: 497
524 TOM: Video Mode written by M68K: 04C1. PWIDTH = 3, MODE = 16 BPP CRY, flags: BGEN (VC = 270)
525 Display starts at 55
526
527 Double Dragon V
528 TOM: Horizontal Display End written by M68K: 1727
529 TOM: Horizontal Display Begin 1 written by M68K: 123
530 TOM: Vertical Display Begin written by M68K: 25
531 TOM: Vertical Display End written by M68K: 2047
532 TOM: Vertical Interrupt written by M68K: 507
533 TOM: Video Mode written by M68K: 06C7. PWIDTH = 4, MODE = 16 BPP RGB, flags: BGEN (VC = 9)
534
535 Dino Dudes
536 TOM: Horizontal Display End written by M68K: 1823
537 TOM: Horizontal Display Begin 1 written by M68K: 45
538 TOM: Vertical Display Begin written by M68K: 40
539 TOM: Vertical Display End written by M68K: 2047
540 TOM: Vertical Interrupt written by M68K: 491
541 TOM: Video Mode written by M68K: 06C1. PWIDTH = 4, MODE = 16 BPP CRY, flags: BGEN (VC = 398)
542 Display starts at 11 (123 - 45 = 78, 78 / 4 = 19 pixels to skip)
543 Width is 417, so maybe width of 379 would be good (starting at 123, ending at 1639)
544 Vertical resolution: 238 lines
545
546 Flashback
547 TOM: Horizontal Display End written by M68K: 1727
548 TOM: Horizontal Display Begin 1 written by M68K: 188
549 TOM: Vertical Display Begin written by M68K: 1
550 TOM: Vertical Display End written by M68K: 2047
551 TOM: Vertical Interrupt written by M68K: 483
552 TOM: Video Mode written by M68K: 08C7. PWIDTH = 5, MODE = 16 BPP RGB, flags: BGEN (VC = 99)
553 Width would be 303 with above scheme, but border width would be 13 pixels
554
555 Trevor McFur
556 Vertical resolution: 238 lines
557 */
558
559 // 16-bit color lookup tables
560 uint32_t RGB16ToRGB32[0x10000];
561 uint32_t CRY16ToRGB32[0x10000];
562 uint32_t MIX16ToRGB32[0x10000];
563
564
565 #warning "This is not endian-safe. !!! FIX !!!"
566 void TOMFillLookupTables(void)
567 {
568         // NOTE: Jaguar 16-bit (non-CRY) color is RBG 556 like so:
569         //       RRRR RBBB BBGG GGGG
570         for(uint32_t i=0; i<0x10000; i++)
571                 RGB16ToRGB32[i] = 0x000000FF
572                         | ((i & 0xF800) << 16)                                  // Red
573                         | ((i & 0x003F) << 18)                                  // Green
574                         | ((i & 0x07C0) << 5);                                  // Blue
575
576         for(uint32_t i=0; i<0x10000; i++)
577         {
578                 uint32_t cyan = (i & 0xF000) >> 12,
579                         red = (i & 0x0F00) >> 8,
580                         intensity = (i & 0x00FF);
581
582                 uint32_t r = (((uint32_t)redcv[cyan][red]) * intensity) >> 8,
583                         g = (((uint32_t)greencv[cyan][red]) * intensity) >> 8,
584                         b = (((uint32_t)bluecv[cyan][red]) * intensity) >> 8;
585
586                 CRY16ToRGB32[i] = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
587                 MIX16ToRGB32[i] = (i & 0x01 ? RGB16ToRGB32[i] : CRY16ToRGB32[i]);
588         }
589 }
590
591
592 void TOMSetPendingJERRYInt(void)
593 {
594         tom_jerry_int_pending = 1;
595 }
596
597
598 void TOMSetPendingTimerInt(void)
599 {
600         tom_timer_int_pending = 1;
601 }
602
603
604 void TOMSetPendingObjectInt(void)
605 {
606         tom_object_int_pending = 1;
607 }
608
609
610 void TOMSetPendingGPUInt(void)
611 {
612         tom_gpu_int_pending = 1;
613 }
614
615
616 void TOMSetPendingVideoInt(void)
617 {
618         tom_video_int_pending = 1;
619 }
620
621
622 uint8_t * TOMGetRamPointer(void)
623 {
624         return tomRam8;
625 }
626
627
628 uint8_t TOMGetVideoMode(void)
629 {
630         uint16_t vmode = GET16(tomRam8, VMODE);
631         return ((vmode & VARMOD) >> 6) | ((vmode & MODE) >> 1);
632 }
633
634
635 //Used in only one place (and for debug purposes): OBJECTP.CPP
636 #warning "Used in only one place (and for debug purposes): OBJECTP.CPP !!! FIX !!!"
637 uint16_t TOMGetVDB(void)
638 {
639         return GET16(tomRam8, VDB);
640 }
641
642
643 uint16_t TOMGetHC(void)
644 {
645         return GET16(tomRam8, HC);
646 }
647
648
649 uint16_t TOMGetVP(void)
650 {
651         return GET16(tomRam8, VP);
652 }
653
654
655 uint16_t TOMGetMEMCON1(void)
656 {
657         return GET16(tomRam8, MEMCON1);
658 }
659
660
661 #define LEFT_BG_FIX
662 //
663 // 16 BPP CRY/RGB mixed mode rendering
664 //
665 void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer)
666 {
667 //CHANGED TO 32BPP RENDERING
668         uint16_t width = tomWidth;
669         uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
670
671         //New stuff--restrict our drawing...
672         uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
673         //NOTE: May have to check HDB2 as well!
674         // Get start position in HC ticks
675         int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);
676         // Convert to pixels
677         startPos /= pwidth;
678
679         if (startPos < 0)
680                 // This is x2 because current_line_buffer is uint8_t & we're in a 16bpp mode
681                 current_line_buffer += 2 * -startPos;
682         else
683 //This case doesn't properly handle the "start on the right side of virtual screen" case
684 //Dunno why--looks Ok...
685 //What *is* for sure wrong is that it doesn't copy the linebuffer's BG pixels... [FIXED NOW]
686 //This should likely be 4 instead of 2 (?--not sure)
687 // Actually, there should be NO multiplier, as startPos is expressed in PIXELS
688 // and so is the backbuffer.
689 #ifdef LEFT_BG_FIX
690         {
691                 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
692                 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
693
694                 for(int16_t i=0; i<startPos; i++)
695                         *backbuffer++ = pixel;
696
697                 width -= startPos;
698         }
699 #else
700                 backbuffer += 2 * startPos, width -= startPos;
701 #endif
702
703         while (width)
704         {
705                 uint16_t color = (*current_line_buffer++) << 8;
706                 color |= *current_line_buffer++;
707                 *backbuffer++ = MIX16ToRGB32[color];
708                 width--;
709         }
710 }
711
712
713 //
714 // 16 BPP CRY mode rendering
715 //
716 void tom_render_16bpp_cry_scanline(uint32_t * backbuffer)
717 {
718 //CHANGED TO 32BPP RENDERING
719         uint16_t width = tomWidth;
720         uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
721
722         //New stuff--restrict our drawing...
723         uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
724         //NOTE: May have to check HDB2 as well!
725         int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);// Get start position in HC ticks
726         startPos /= pwidth;
727
728         if (startPos < 0)
729                 current_line_buffer += 2 * -startPos;
730         else
731 #ifdef LEFT_BG_FIX
732         {
733                 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
734                 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
735
736                 for(int16_t i=0; i<startPos; i++)
737                         *backbuffer++ = pixel;
738
739                 width -= startPos;
740         }
741 #else
742 //This should likely be 4 instead of 2 (?--not sure)
743                 backbuffer += 2 * startPos, width -= startPos;
744 #endif
745
746         while (width)
747         {
748                 uint16_t color = (*current_line_buffer++) << 8;
749                 color |= *current_line_buffer++;
750                 *backbuffer++ = CRY16ToRGB32[color];
751                 width--;
752         }
753 }
754
755
756 //
757 // 24 BPP mode rendering
758 //
759 void tom_render_24bpp_scanline(uint32_t * backbuffer)
760 {
761 //CHANGED TO 32BPP RENDERING
762         uint16_t width = tomWidth;
763         uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
764
765         //New stuff--restrict our drawing...
766         uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
767         //NOTE: May have to check HDB2 as well!
768         int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);       // Get start position in HC ticks
769         startPos /= pwidth;
770
771         if (startPos < 0)
772                 current_line_buffer += 4 * -startPos;
773         else
774 #ifdef LEFT_BG_FIX
775         {
776                 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
777                 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
778
779                 for(int16_t i=0; i<startPos; i++)
780                         *backbuffer++ = pixel;
781
782                 width -= startPos;
783         }
784 #else
785 //This should likely be 4 instead of 2 (?--not sure)
786                 backbuffer += 2 * startPos, width -= startPos;
787 #endif
788
789         while (width)
790         {
791                 uint32_t g = *current_line_buffer++;
792                 uint32_t r = *current_line_buffer++;
793                 current_line_buffer++;
794                 uint32_t b = *current_line_buffer++;
795                 *backbuffer++ = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
796                 width--;
797         }
798 }
799
800
801 // Seems to me that this is NOT a valid mode--the JTRM seems to imply that you
802 // would need extra hardware outside of the Jaguar console to support this!
803 //
804 // 16 BPP direct mode rendering
805 //
806 void tom_render_16bpp_direct_scanline(uint32_t * backbuffer)
807 {
808         uint16_t width = tomWidth;
809         uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
810
811         while (width)
812         {
813                 uint16_t color = (*current_line_buffer++) << 8;
814                 color |= *current_line_buffer++;
815                 *backbuffer++ = color >> 1;
816                 width--;
817         }
818 }
819
820
821 //
822 // 16 BPP RGB mode rendering
823 //
824 void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer)
825 {
826 //CHANGED TO 32BPP RENDERING
827         // 16 BPP RGB: 0-5 green, 6-10 blue, 11-15 red
828
829         uint16_t width = tomWidth;
830         uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
831
832         //New stuff--restrict our drawing...
833         uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
834         //NOTE: May have to check HDB2 as well!
835         int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);       // Get start position in HC ticks
836         startPos /= pwidth;
837
838         if (startPos < 0)
839                 current_line_buffer += 2 * -startPos;
840         else
841 #ifdef LEFT_BG_FIX
842         {
843                 uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
844                 uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
845
846                 for(int16_t i=0; i<startPos; i++)
847                         *backbuffer++ = pixel;
848
849                 width -= startPos;
850         }
851 #else
852 //This should likely be 4 instead of 2 (?--not sure)
853                 backbuffer += 2 * startPos, width -= startPos;
854 #endif
855
856         while (width)
857         {
858                 uint32_t color = (*current_line_buffer++) << 8;
859                 color |= *current_line_buffer++;
860                 *backbuffer++ = RGB16ToRGB32[color];
861                 width--;
862         }
863 }
864
865
866 //
867 // Process a single halfline
868 //
869 void TOMExecHalfline(uint16_t halfline, bool render)
870 {
871         uint16_t field2 = halfline & 0x0800;
872         halfline &= 0x07FF;
873         bool inActiveDisplayArea = true;
874
875         // Execute OP only on even halflines (skip higher resolutions for now...)
876         if (halfline & 0x01)
877                 return;
878
879 //Hm, it seems that the OP needs to execute from zero, so let's try it:
880 // And it works! But need to do some optimizations in the OP to keep it from
881 // attempting to do a scanline render in the non-display area... [DONE]
882 //this seems to cause a regression in certain games, like rayman
883 //which means I have to dig thru the asic nets to see what's wrong...
884 /*
885 No, the OP doesn't start until VDB, that much is certain. The thing is, VDB is
886 the HALF line that the OP starts on--which means that it needs to start at
887 VDB / 2!!!
888
889 Hrm, doesn't seem to be enough, though it should be... still sticks for 20
890 frames.
891
892 What triggers this is writing $FFFF to VDE. This causes the OP start signal in VID to latch on, which in effect sets VDB to zero. So that much is correct. But
893 the thing with Rayman is that it shouldn't cause the graphical glitches seen
894 there, so still have to investigate what's going on there. By all rights, it
895 shouldn't glitch because:
896
897 00006C00: 0000000D 82008F73 (BRANCH) YPOS=494, CC=">", link=$00006C10
898 00006C08: 000003FF 00008173 (BRANCH) YPOS=46, CC=">", link=$001FF800
899 00006C10: 00000000 0000000C (STOP)
900 001FF800: 12FC2BFF 02380000 (BITMAP)
901           00008004 8180CFF1
902
903 Even if the OP is running all the time, the link should tell it to stop at the
904 right place (which it seems to do). But we still get glitchy screen.
905
906 Seems the glitchy screen went away... Maybe the GPU alignment fixes fixed it???
907 Just need to add the proper checking here then.
908
909 Some numbers, courtesy of the Jaguar BIOS:
910 // NTSC:
911 VP, 523                 // Vertical Period (1-based; in this case VP = 524)
912 VBE, 24                 // Vertical Blank End
913 VDB, 38                 // Vertical Display Begin
914 VDE, 518                // Vertical Display End
915 VBB, 500                // Vertical Blank Begin
916 VS, 517                 // Vertical Sync
917
918 // PAL Jaguar
919 VP, 623                 // Vertical Period (1-based; in this case VP = 624)
920 VBE, 34                 // Vertical Blank End
921 VDB, 38                 // Vertical Display Begin
922 VDE, 518                // Vertical Display End
923 VBB, 600                // Vertical Blank Begin
924 VS, 618                 // Vertical Sync
925
926 Numbers for KM, NTSC:
927 KM: (Note that with VDE <= 507, the OP starts at VDB as expected)
928 TOM: Vertical Display Begin written by M68K: 41
929 TOM: Vertical Display End written by M68K: 2047
930 TOM: Vertical Interrupt written by M68K: 491
931 */
932
933         // Initial values that "well behaved" programs use
934         uint16_t startingHalfline = GET16(tomRam8, VDB);
935         uint16_t endingHalfline = GET16(tomRam8, VDE);
936
937         // Simulate the OP start bug here!
938         // Really, this value is somewhere around 507 for an NTSC Jaguar. But this
939         // should work in a majority of cases, at least until we can figure it out
940         // properly.
941         if (endingHalfline > GET16(tomRam8, VP))
942                 startingHalfline = 0;
943
944         if ((halfline >= startingHalfline) && (halfline < endingHalfline))
945         {
946                 if (render)
947                 {
948                         uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
949                         uint8_t bgHI = tomRam8[BG], bgLO = tomRam8[BG + 1];
950
951                         // Clear line buffer with BG
952                         if (GET16(tomRam8, VMODE) & BGEN) // && (CRY or RGB16)...
953                                 for(uint32_t i=0; i<720; i++)
954                                         *current_line_buffer++ = bgHI, *current_line_buffer++ = bgLO;
955
956                         OPProcessList(halfline, render);
957                 }
958         }
959         else
960                 inActiveDisplayArea = false;
961
962         // Take PAL into account...
963
964         uint16_t topVisible = (vjs.hardwareTypeNTSC ? TOP_VISIBLE_VC : TOP_VISIBLE_VC_PAL),
965                 bottomVisible = (vjs.hardwareTypeNTSC ? BOTTOM_VISIBLE_VC : BOTTOM_VISIBLE_VC_PAL);
966         uint32_t * TOMCurrentLine = 0;
967
968         // Bit 0 in VP is interlace flag. 0 = interlace, 1 = non-interlaced
969         if (tomRam8[VP + 1] & 0x01)
970                 TOMCurrentLine = &(screenBuffer[((halfline - topVisible) / 2) * screenPitch]);//non-interlace
971         else
972                 TOMCurrentLine = &(screenBuffer[(((halfline - topVisible) / 2) * screenPitch * 2) + (field2 ? 0 : screenPitch)]);//interlace
973
974         // Here's our virtualized scanline code...
975
976         if ((halfline >= topVisible) && (halfline < bottomVisible))
977         {
978                 if (inActiveDisplayArea)
979                 {
980 #warning "The following doesn't put BORDER color on the sides... !!! FIX !!!"
981                         if (vjs.renderType == RT_NORMAL)
982                         {
983                                 scanline_render[TOMGetVideoMode()](TOMCurrentLine);
984                         }
985                         else
986                         {
987                                 // TV type render
988 /*
989         tom_render_16bpp_cry_scanline,
990         tom_render_24bpp_scanline,
991         tom_render_16bpp_direct_scanline,
992         tom_render_16bpp_rgb_scanline,
993         tom_render_16bpp_cry_rgb_mix_scanline,
994         tom_render_24bpp_scanline,
995         tom_render_16bpp_direct_scanline,
996         tom_render_16bpp_rgb_scanline
997 #define VMODE           0x28
998 #define   MODE          0x0006          // Line buffer to video generator mode
999 #define   VARMOD        0x0100          // Mixed CRY/RGB16 mode (only works in MODE 0!)
1000 */
1001                                 uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1002                                 uint8_t mode = ((GET16(tomRam8, VMODE) & MODE) >> 1);
1003                                 bool varmod = GET16(tomRam8, VMODE) & VARMOD;
1004 //The video texture line buffer ranges from 0 to 1279, with its left edge
1005 //starting at LEFT_VISIBLE_HC. So, we need to start writing into the backbuffer
1006 //at HDB1, using pwidth as our scaling factor. The way it generates its image
1007 //on a real TV!
1008
1009 //So, for example, if HDB1 is less than LEFT_VISIBLE_HC, then we have to figure
1010 //out where in the VTLB that we start writing pixels from the Jaguar line
1011 //buffer (VTLB start=0, JLB=something).
1012 #if 0
1013 //
1014 // 24 BPP mode rendering
1015 //
1016 void tom_render_24bpp_scanline(uint32_t * backbuffer)
1017 {
1018 //CHANGED TO 32BPP RENDERING
1019         uint16_t width = tomWidth;
1020         uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
1021
1022         //New stuff--restrict our drawing...
1023         uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1024         //NOTE: May have to check HDB2 as well!
1025         int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);       // Get start position in HC ticks
1026         startPos /= pwidth;
1027         if (startPos < 0)
1028                 current_line_buffer += 4 * -startPos;
1029         else
1030 //This should likely be 4 instead of 2 (?--not sure)
1031                 backbuffer += 2 * startPos, width -= startPos;
1032
1033         while (width)
1034         {
1035                 uint32_t g = *current_line_buffer++;
1036                 uint32_t r = *current_line_buffer++;
1037                 current_line_buffer++;
1038                 uint32_t b = *current_line_buffer++;
1039                 *backbuffer++ = 0xFF000000 | (b << 16) | (g << 8) | r;
1040                 width--;
1041         }
1042 }
1043 #endif
1044
1045                         }
1046                 }
1047                 else
1048                 {
1049                         // If outside of VDB & VDE, then display the border color
1050                         uint32_t * currentLineBuffer = TOMCurrentLine;
1051                         uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
1052 //Hm.                   uint32_t pixel = 0xFF000000 | (b << 16) | (g << 8) | r;
1053                         uint32_t pixel = 0x000000FF | (r << 24) | (g << 16) | (b << 8);
1054
1055                         for(uint32_t i=0; i<tomWidth; i++)
1056                                 *currentLineBuffer++ = pixel;
1057                 }
1058         }
1059 }
1060
1061
1062 //
1063 // TOM initialization
1064 //
1065 void TOMInit(void)
1066 {
1067         TOMFillLookupTables();
1068         OPInit();
1069         BlitterInit();
1070         TOMReset();
1071 }
1072
1073
1074 void TOMDone(void)
1075 {
1076         TOMDumpIORegistersToLog();
1077         OPDone();
1078         BlitterDone();
1079         WriteLog("TOM: Resolution %i x %i %s\n", TOMGetVideoModeWidth(),
1080                 TOMGetVideoModeHeight(), videoMode_to_str[TOMGetVideoMode()]);
1081 }
1082
1083
1084 uint32_t TOMGetVideoModeWidth(void)
1085 {
1086         // Note that the following PWIDTH values have the following pixel aspect
1087         // ratios:
1088         // PWIDTH = 1 -> 0.25:1 (1:4) pixels (X:Y ratio)
1089         // PWIDTH = 2 -> 0.50:1 (1:2) pixels
1090         // PWIDTH = 3 -> 0.75:1 (3:4) pixels
1091         // PWIDTH = 4 -> 1.00:1 (1:1) pixels
1092         // PWIDTH = 5 -> 1.25:1 (5:4) pixels
1093         // PWIDTH = 6 -> 1.50:1 (3:2) pixels
1094         // PWIDTH = 7 -> 1.75:1 (7:4) pixels
1095         // PWIDTH = 8 -> 2.00:1 (2:1) pixels
1096
1097         // Also note that the JTRM says that PWIDTH of 4 gives pixels that are
1098         // "about" square--this implies that the other modes have pixels that are
1099         // *not* square (and they aren't)!
1100         // Also, I seriously doubt that you will see any games that use PWIDTH = 1!
1101
1102         // To make it easier to make a quasi-fixed display size, we restrict the
1103         // viewing area to an arbitrary range of the Horizontal Count.
1104         uint16_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
1105         return (vjs.hardwareTypeNTSC ? RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC : RIGHT_VISIBLE_HC_PAL - LEFT_VISIBLE_HC_PAL) / pwidth;
1106 }
1107
1108
1109 uint32_t TOMGetVideoModeHeight(void)
1110 {
1111         // Set virtual screen height to 240 (NTSC) or 256 (PAL) lines...
1112         return (vjs.hardwareTypeNTSC ? 240 : 256);
1113 }
1114
1115
1116 //
1117 // TOM reset code
1118 // Now PAL friendly!
1119 //
1120 /*
1121 The values in TOMReset come from the Jaguar BIOS.
1122 These values are from BJL:
1123
1124 NSTC:
1125 CLK2     181
1126 HP               844
1127 HBB              1713
1128 HBE              125
1129 HS               1741
1130 HVS              651
1131 HEQ              784
1132 HDE              1696
1133 HDB1     166
1134 HDB2     166
1135 VP               523
1136 VEE              6
1137 VBE              24
1138 VDB              46
1139 VDE              496
1140 VBB              500
1141 VEB              511
1142 VS               517
1143
1144 PAL:
1145 CLK2     226
1146 HP               850
1147 HBB              1711
1148 HBE              158
1149 HS               1749
1150 HVS              601
1151 HEQ              787
1152 HDE              1696
1153 HDB1     166
1154 HDB2     166
1155 VP               625
1156 VEE              6
1157 VBE              34
1158 VDB              46
1159 VDE              429
1160 VBB              600
1161 VEB              613
1162 VS               618
1163 */
1164 void TOMReset(void)
1165 {
1166         OPReset();
1167         BlitterReset();
1168         memset(tomRam8, 0x00, 0x4000);
1169
1170         if (vjs.hardwareTypeNTSC)
1171         {
1172                 SET16(tomRam8, MEMCON1, 0x1861);
1173 //              SET16(tomRam8, MEMCON1, 0x1865);//Bunch of BS
1174                 SET16(tomRam8, MEMCON2, 0x35CC);
1175                 SET16(tomRam8, HP, 844);                        // Horizontal Period (1-based; HP=845)
1176                 SET16(tomRam8, HBB, 1713);                      // Horizontal Blank Begin
1177                 SET16(tomRam8, HBE, 125);                       // Horizontal Blank End
1178                 SET16(tomRam8, HDE, 1665);                      // Horizontal Display End
1179                 SET16(tomRam8, HDB1, 203);                      // Horizontal Display Begin 1
1180                 SET16(tomRam8, VP, 523);                        // Vertical Period (1-based; in this case VP = 524)
1181                 SET16(tomRam8, VBE, 24);                        // Vertical Blank End
1182                 SET16(tomRam8, VDB, 38);                        // Vertical Display Begin
1183                 SET16(tomRam8, VDE, 518);                       // Vertical Display End
1184                 SET16(tomRam8, VBB, 500);                       // Vertical Blank Begin
1185                 SET16(tomRam8, VS, 517);                        // Vertical Sync
1186                 SET16(tomRam8, VMODE, 0x06C1);
1187         }
1188         else    // PAL Jaguar
1189         {
1190                 SET16(tomRam8, MEMCON1, 0x1861);
1191                 SET16(tomRam8, MEMCON2, 0x35CC);
1192                 SET16(tomRam8, HP, 850);                        // Horizontal Period
1193                 SET16(tomRam8, HBB, 1711);                      // Horizontal Blank Begin
1194                 SET16(tomRam8, HBE, 158);                       // Horizontal Blank End
1195                 SET16(tomRam8, HDE, 1665);                      // Horizontal Display End
1196                 SET16(tomRam8, HDB1, 203);                      // Horizontal Display Begin 1
1197                 SET16(tomRam8, VP, 623);                        // Vertical Period (1-based; in this case VP = 624)
1198                 SET16(tomRam8, VBE, 34);                        // Vertical Blank End
1199                 SET16(tomRam8, VDB, 38);                        // Vertical Display Begin
1200                 SET16(tomRam8, VDE, 518);                       // Vertical Display End
1201                 SET16(tomRam8, VBB, 600);                       // Vertical Blank Begin
1202                 SET16(tomRam8, VS, 618);                        // Vertical Sync
1203                 SET16(tomRam8, VMODE, 0x06C1);
1204         }
1205
1206         tomWidth = 0;
1207         tomHeight = 0;
1208
1209         tom_jerry_int_pending = 0;
1210         tom_timer_int_pending = 0;
1211         tom_object_int_pending = 0;
1212         tom_gpu_int_pending = 0;
1213         tom_video_int_pending = 0;
1214
1215         tomTimerPrescaler = 0;                                  // TOM PIT is disabled
1216         tomTimerDivider = 0;
1217         tomTimerCounter = 0;
1218 }
1219
1220
1221 //
1222 // Dump all TOM register values to the log
1223 //
1224 void TOMDumpIORegistersToLog(void)
1225 {
1226         WriteLog("\n\n---------------------------------------------------------------------\n");
1227         WriteLog("TOM I/O Registers\n");
1228         WriteLog("---------------------------------------------------------------------\n");
1229         WriteLog("F000%02X (MEMCON1): $%04X\n", MEMCON1, GET16(tomRam8, MEMCON1));
1230         WriteLog("F000%02X (MEMCON2): $%04X\n", MEMCON2, GET16(tomRam8, MEMCON2));
1231         WriteLog("F000%02X      (HC): $%04X\n", HC,      GET16(tomRam8, HC));
1232         WriteLog("F000%02X      (VC): $%04X\n", VC,      GET16(tomRam8, VC));
1233         WriteLog("F000%02X     (OLP): $%08X\n", OLP,     GET32(tomRam8, OLP));
1234         WriteLog("F000%02X     (OBF): $%04X\n", OBF,     GET16(tomRam8, OBF));
1235         WriteLog("F000%02X   (VMODE): $%04X\n", VMODE,   GET16(tomRam8, VMODE));
1236         WriteLog("F000%02X   (BORD1): $%04X\n", BORD1,   GET16(tomRam8, BORD1));
1237         WriteLog("F000%02X   (BORD2): $%04X\n", BORD2,   GET16(tomRam8, BORD2));
1238         WriteLog("F000%02X      (HP): $%04X\n", HP,      GET16(tomRam8, HP));
1239         WriteLog("F000%02X     (HBB): $%04X\n", HBB,     GET16(tomRam8, HBB));
1240         WriteLog("F000%02X     (HBE): $%04X\n", HBE,     GET16(tomRam8, HBE));
1241         WriteLog("F000%02X      (HS): $%04X\n", HS,      GET16(tomRam8, HS));
1242         WriteLog("F000%02X     (HVS): $%04X\n", HVS,     GET16(tomRam8, HVS));
1243         WriteLog("F000%02X    (HDB1): $%04X\n", HDB1,    GET16(tomRam8, HDB1));
1244         WriteLog("F000%02X    (HDB2): $%04X\n", HDB2,    GET16(tomRam8, HDB2));
1245         WriteLog("F000%02X     (HDE): $%04X\n", HDE,     GET16(tomRam8, HDE));
1246         WriteLog("F000%02X      (VP): $%04X\n", VP,      GET16(tomRam8, VP));
1247         WriteLog("F000%02X     (VBB): $%04X\n", VBB,     GET16(tomRam8, VBB));
1248         WriteLog("F000%02X     (VBE): $%04X\n", VBE,     GET16(tomRam8, VBE));
1249         WriteLog("F000%02X      (VS): $%04X\n", VS,      GET16(tomRam8, VS));
1250         WriteLog("F000%02X     (VDB): $%04X\n", VDB,     GET16(tomRam8, VDB));
1251         WriteLog("F000%02X     (VDE): $%04X\n", VDE,     GET16(tomRam8, VDE));
1252         WriteLog("F000%02X     (VEB): $%04X\n", VEB,     GET16(tomRam8, VEB));
1253         WriteLog("F000%02X     (VEE): $%04X\n", VEE,     GET16(tomRam8, VEE));
1254         WriteLog("F000%02X      (VI): $%04X\n", VI,      GET16(tomRam8, VI));
1255         WriteLog("F000%02X    (PIT0): $%04X\n", PIT0,    GET16(tomRam8, PIT0));
1256         WriteLog("F000%02X    (PIT1): $%04X\n", PIT1,    GET16(tomRam8, PIT1));
1257         WriteLog("F000%02X     (HEQ): $%04X\n", HEQ,     GET16(tomRam8, HEQ));
1258         WriteLog("F000%02X      (BG): $%04X\n", BG,      GET16(tomRam8, BG));
1259         WriteLog("F000%02X    (INT1): $%04X\n", INT1,    GET16(tomRam8, INT1));
1260         WriteLog("F000%02X    (INT2): $%04X\n", INT2,    GET16(tomRam8, INT2));
1261         WriteLog("---------------------------------------------------------------------\n\n\n");
1262 }
1263
1264
1265 //
1266 // TOM byte access (read)
1267 //
1268 uint8_t TOMReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1269 {
1270 //???Is this needed???
1271 // It seems so. Perhaps it's the +$8000 offset being written to (32-bit interface)?
1272 // However, the 32-bit interface is WRITE ONLY, so that can't be it...
1273 // Also, the 68K CANNOT make use of the 32-bit interface, since its bus width is only 16-bits...
1274 //      offset &= 0xFF3FFF;
1275
1276 #ifdef TOM_DEBUG
1277         WriteLog("TOM: Reading byte at %06X for %s\n", offset, whoName[who]);
1278 #endif
1279
1280         if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1281                 return GPUReadByte(offset, who);
1282         else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1283                 return GPUReadByte(offset, who);
1284 /*      else if ((offset >= 0xF00010) && (offset < 0xF00028))
1285                 return OPReadByte(offset, who);*/
1286         else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1287                 return BlitterReadByte(offset, who);
1288         else if (offset == 0xF00050)
1289                 return tomTimerPrescaler >> 8;
1290         else if (offset == 0xF00051)
1291                 return tomTimerPrescaler & 0xFF;
1292         else if (offset == 0xF00052)
1293                 return tomTimerDivider >> 8;
1294         else if (offset == 0xF00053)
1295                 return tomTimerDivider & 0xFF;
1296
1297         return tomRam8[offset & 0x3FFF];
1298 }
1299
1300
1301 //
1302 // TOM word access (read)
1303 //
1304 uint16_t TOMReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
1305 {
1306 //???Is this needed???
1307 //      offset &= 0xFF3FFF;
1308 #ifdef TOM_DEBUG
1309         WriteLog("TOM: Reading word at %06X for %s\n", offset, whoName[who]);
1310 #endif
1311 if (offset >= 0xF02000 && offset <= 0xF020FF)
1312         WriteLog("TOM: ReadWord attempted from GPU register file by %s (unimplemented)!\n", whoName[who]);
1313
1314         if (offset == 0xF000E0)
1315         {
1316                 // For reading, should only return the lower 5 bits...
1317                 uint16_t data = (tom_jerry_int_pending << 4) | (tom_timer_int_pending << 3)
1318                         | (tom_object_int_pending << 2) | (tom_gpu_int_pending << 1)
1319                         | (tom_video_int_pending << 0);
1320                 //WriteLog("tom: interrupt status is 0x%.4x \n",data);
1321                 return data;
1322         }
1323 //Shoud be handled by the jaguar main loop now... And it is! ;-)
1324 /*      else if (offset == 0xF00006)    // VC
1325         // What if we're in interlaced mode?
1326         // According to docs, in non-interlace mode VC is ALWAYS even...
1327 //              return (tom_scanline << 1);// + 1;
1328 //But it's causing Rayman to be fucked up... Why???
1329 //Because VC is even in NI mode when calling the OP! That's why!
1330                 return (tom_scanline << 1) + 1;//*/
1331 /*
1332 //      F00004          R/W   -----xxx xxxxxxxx   HC - horizontal count
1333 //                            -----x-- --------      (which half of the display)
1334 //                            ------xx xxxxxxxx      (10-bit counter)
1335 */
1336 // This is a kludge to get the HC working somewhat... What we really should do here
1337 // is check what the global time is at the time of the read and calculate the correct HC...
1338 // !!! FIX !!!
1339         else if (offset == 0xF00004)
1340                 return rand() & 0x03FF;
1341         else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE + 0x20))
1342                 return GPUReadWord(offset, who);
1343         else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000))
1344                 return GPUReadWord(offset, who);
1345 /*      else if ((offset >= 0xF00010) && (offset < 0xF00028))
1346                 return OPReadWord(offset, who);*/
1347         else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1348                 return BlitterReadWord(offset, who);
1349         else if (offset == 0xF00050)
1350                 return tomTimerPrescaler;
1351         else if (offset == 0xF00052)
1352                 return tomTimerDivider;
1353
1354         offset &= 0x3FFF;
1355         return (TOMReadByte(offset, who) << 8) | TOMReadByte(offset + 1, who);
1356 }
1357
1358
1359 #define TOM_STRICT_MEMORY_ACCESS
1360 //
1361 // TOM byte access (write)
1362 //
1363 void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
1364 {
1365         // Moved here tentatively, so we can see everything written to TOM.
1366         tomRam8[offset & 0x3FFF] = data;
1367
1368 #ifdef TOM_DEBUG
1369         WriteLog("TOM: Writing byte %02X at %06X", data, offset);
1370 #endif
1371 //???Is this needed???
1372 // Perhaps on the writes--32-bit writes that is! And masked with FF7FFF...
1373 #ifndef TOM_STRICT_MEMORY_ACCESS
1374         offset &= 0xFF3FFF;
1375 #else
1376         // "Fast" (32-bit only) write access to the GPU
1377 //      if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF))
1378         if ((offset >= 0xF08000) && (offset <= 0xF0BFFF))
1379                 offset &= 0xFF7FFF;
1380 #endif
1381 #ifdef TOM_DEBUG
1382         WriteLog(" -->[%06X] by %s\n", offset, whoName[who]);
1383 #endif
1384
1385 #ifdef TOM_STRICT_MEMORY_ACCESS
1386         // Sanity check ("Aww, there ain't no Sanity Clause...")
1387         if ((offset < 0xF00000) || (offset > 0xF03FFF))
1388                 return;
1389 #endif
1390
1391         if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1392         {
1393                 GPUWriteByte(offset, data, who);
1394                 return;
1395         }
1396         else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1397         {
1398                 GPUWriteByte(offset, data, who);
1399                 return;
1400         }
1401 /*      else if ((offset >= 0xF00010) && (offset < 0xF00028))
1402         {
1403                 OPWriteByte(offset, data, who);
1404                 return;
1405         }*/
1406         else if ((offset >= 0xF02200) && (offset < 0xF022A0))
1407         {
1408                 BlitterWriteByte(offset, data, who);
1409                 return;
1410         }
1411         else if (offset == 0xF00050)
1412         {
1413                 tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | (data << 8);
1414                 TOMResetPIT();
1415                 return;
1416         }
1417         else if (offset == 0xF00051)
1418         {
1419                 tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | data;
1420                 TOMResetPIT();
1421                 return;
1422         }
1423         else if (offset == 0xF00052)
1424         {
1425                 tomTimerDivider = (tomTimerDivider & 0x00FF) | (data << 8);
1426                 TOMResetPIT();
1427                 return;
1428         }
1429         else if (offset == 0xF00053)
1430         {
1431                 tomTimerDivider = (tomTimerDivider & 0xFF00) | data;
1432                 TOMResetPIT();
1433                 return;
1434         }
1435         else if (offset >= 0xF00400 && offset <= 0xF007FF)      // CLUT (A & B)
1436         {
1437                 // Writing to one CLUT writes to the other
1438                 offset &= 0x5FF;                // Mask out $F00600 (restrict to $F00400-5FF)
1439                 tomRam8[offset] = data, tomRam8[offset + 0x200] = data;
1440         }
1441
1442 //      tomRam8[offset & 0x3FFF] = data;
1443 }
1444
1445
1446 //
1447 // TOM word access (write)
1448 //
1449 void TOMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
1450 {
1451         // Moved here tentatively, so we can see everything written to TOM.
1452         tomRam8[(offset + 0) & 0x3FFF] = data >> 8;
1453         tomRam8[(offset + 1) & 0x3FFF] = data & 0xFF;
1454
1455 #ifdef TOM_DEBUG
1456         WriteLog("TOM: Writing byte %04X at %06X", data, offset);
1457 #endif
1458 //???Is this needed??? Yes, but we need to be more vigilant than this.
1459 #ifndef TOM_STRICT_MEMORY_ACCESS
1460         offset &= 0xFF3FFF;
1461 #else
1462         // "Fast" (32-bit only) write access to the GPU
1463 //      if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF))
1464         if ((offset >= 0xF08000) && (offset <= 0xF0BFFF))
1465                 offset &= 0xFF7FFF;
1466 #endif
1467 #ifdef TOM_DEBUG
1468         WriteLog(" -->[%06X] by %s\n", offset, whoName[who]);
1469 #endif
1470
1471 #ifdef TOM_STRICT_MEMORY_ACCESS
1472         // Sanity check
1473         if ((offset < 0xF00000) || (offset > 0xF03FFF))
1474                 return;
1475 #endif
1476
1477 //if (offset == 0xF00000 + MEMCON1)
1478 //      WriteLog("TOM: Memory Configuration 1 written by %s: %04X\n", whoName[who], data);
1479 //if (offset == 0xF00000 + MEMCON2)
1480 //      WriteLog("TOM: Memory Configuration 2 written by %s: %04X\n", whoName[who], data);
1481 if (offset >= 0xF02000 && offset <= 0xF020FF)
1482         WriteLog("TOM: WriteWord attempted to GPU register file by %s (unimplemented)!\n", whoName[who]);
1483
1484         if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1485         {
1486                 GPUWriteWord(offset, data, who);
1487                 return;
1488         }
1489         else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1490         {
1491                 GPUWriteWord(offset, data, who);
1492                 return;
1493         }
1494 //What's so special about this?
1495 /*      else if ((offset >= 0xF00000) && (offset < 0xF00002))
1496         {
1497                 TOMWriteByte(offset, data >> 8);
1498                 TOMWriteByte(offset+1, data & 0xFF);
1499         }*/
1500 /*      else if ((offset >= 0xF00010) && (offset < 0xF00028))
1501         {
1502                 OPWriteWord(offset, data, who);
1503                 return;
1504         }*/
1505         else if (offset == 0xF00050)
1506         {
1507                 tomTimerPrescaler = data;
1508                 TOMResetPIT();
1509                 return;
1510         }
1511         else if (offset == 0xF00052)
1512         {
1513                 tomTimerDivider = data;
1514                 TOMResetPIT();
1515                 return;
1516         }
1517         else if (offset == 0xF000E0)
1518         {
1519 //Check this out...
1520                 if (data & 0x0100)
1521                         tom_video_int_pending = 0;
1522                 if (data & 0x0200)
1523                         tom_gpu_int_pending = 0;
1524                 if (data & 0x0400)
1525                         tom_object_int_pending = 0;
1526                 if (data & 0x0800)
1527                         tom_timer_int_pending = 0;
1528                 if (data & 0x1000)
1529                         tom_jerry_int_pending = 0;
1530
1531 //              return;
1532         }
1533         else if ((offset >= 0xF02200) && (offset <= 0xF0229F))
1534         {
1535                 BlitterWriteWord(offset, data, who);
1536                 return;
1537         }
1538         else if (offset >= 0xF00400 && offset <= 0xF007FE)      // CLUT (A & B)
1539         {
1540                 // Writing to one CLUT writes to the other
1541                 offset &= 0x5FF;                // Mask out $F00600 (restrict to $F00400-5FF)
1542 // Watch out for unaligned writes here! (Not fixed yet)
1543 #warning "!!! Watch out for unaligned writes here !!! FIX !!!"
1544                 SET16(tomRam8, offset, data);
1545                 SET16(tomRam8, offset + 0x200, data);
1546         }
1547
1548         offset &= 0x3FFF;
1549         if (offset == 0x28)                     // VMODE (Why? Why not OBF?)
1550 //Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!
1551 #warning "Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!"
1552                 objectp_running = 1;
1553
1554         if (offset >= 0x30 && offset <= 0x4E)
1555                 data &= 0x07FF;                 // These are (mostly) 11-bit registers
1556         if (offset == 0x2E || offset == 0x36 || offset == 0x54)
1557                 data &= 0x03FF;                 // These are all 10-bit registers
1558
1559 // Fix a lockup bug... :-P
1560 //      TOMWriteByte(0xF00000 | offset, data >> 8, who);
1561 //      TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who);
1562
1563 if (offset == MEMCON1)
1564         WriteLog("TOM: Memory Config 1 written by %s: $%04X\n", whoName[who], data);
1565 if (offset == MEMCON2)
1566         WriteLog("TOM: Memory Config 2 written by %s: $%04X\n", whoName[who], data);
1567 //if (offset == OLP)
1568 //      WriteLog("TOM: Object List Pointer written by %s: $%04X\n", whoName[who], data);
1569 //if (offset == OLP + 2)
1570 //      WriteLog("TOM: Object List Pointer +2 written by %s: $%04X\n", whoName[who], data);
1571 //if (offset == OBF)
1572 //      WriteLog("TOM: Object Processor Flag written by %s: %u\n", whoName[who], data);
1573 if (offset == VMODE)
1574         WriteLog("TOM: Video Mode written by %s: %04X. PWIDTH = %u, MODE = %s, flags:%s%s (VC = %u) (M68K PC = %06X)\n", whoName[who], data, ((data >> 9) & 0x07) + 1, videoMode_to_str[(data & MODE) >> 1], (data & BGEN ? " BGEN" : ""), (data & VARMOD ? " VARMOD" : ""), GET16(tomRam8, VC), m68k_get_reg(NULL, M68K_REG_PC));
1575 if (offset == BORD1)
1576         WriteLog("TOM: Border 1 written by %s: $%04X\n", whoName[who], data);
1577 if (offset == BORD2)
1578         WriteLog("TOM: Border 2 written by %s: $%04X\n", whoName[who], data);
1579 if (offset == HP)
1580         WriteLog("TOM: Horizontal Period written by %s: %u (+1*2 = %u)\n", whoName[who], data, (data + 1) * 2);
1581 if (offset == HBB)
1582         WriteLog("TOM: Horizontal Blank Begin written by %s: %u\n", whoName[who], data);
1583 if (offset == HBE)
1584         WriteLog("TOM: Horizontal Blank End written by %s: %u\n", whoName[who], data);
1585 if (offset == HS)
1586         WriteLog("TOM: Horizontal Sync written by %s: %u\n", whoName[who], data);
1587 if (offset == HVS)
1588         WriteLog("TOM: Horizontal Vertical Sync written by %s: %u\n", whoName[who], data);
1589 if (offset == HDB1)
1590         WriteLog("TOM: Horizontal Display Begin 1 written by %s: %u\n", whoName[who], data);
1591 if (offset == HDB2)
1592         WriteLog("TOM: Horizontal Display Begin 2 written by %s: %u\n", whoName[who], data);
1593 if (offset == HDE)
1594         WriteLog("TOM: Horizontal Display End written by %s: %u\n", whoName[who], data);
1595 if (offset == VP)
1596         WriteLog("TOM: Vertical Period written by %s: %u (%sinterlaced)\n", whoName[who], data, (data & 0x01 ? "non-" : ""));
1597 if (offset == VBB)
1598         WriteLog("TOM: Vertical Blank Begin written by %s: %u\n", whoName[who], data);
1599 if (offset == VBE)
1600         WriteLog("TOM: Vertical Blank End written by %s: %u\n", whoName[who], data);
1601 if (offset == VS)
1602         WriteLog("TOM: Vertical Sync written by %s: %u\n", whoName[who], data);
1603 if (offset == VDB)
1604         WriteLog("TOM: Vertical Display Begin written by %s: %u\n", whoName[who], data);
1605 if (offset == VDE)
1606         WriteLog("TOM: Vertical Display End written by %s: %u\n", whoName[who], data);
1607 if (offset == VEB)
1608         WriteLog("TOM: Vertical Equalization Begin written by %s: %u\n", whoName[who], data);
1609 if (offset == VEE)
1610         WriteLog("TOM: Vertical Equalization End written by %s: %u\n", whoName[who], data);
1611 if (offset == VI)
1612         WriteLog("TOM: Vertical Interrupt written by %s: %u\n", whoName[who], data);
1613 if (offset == PIT0)
1614         WriteLog("TOM: PIT0 written by %s: %u\n", whoName[who], data);
1615 if (offset == PIT1)
1616         WriteLog("TOM: PIT1 written by %s: %u\n", whoName[who], data);
1617 if (offset == HEQ)
1618         WriteLog("TOM: Horizontal Equalization End written by %s: %u\n", whoName[who], data);
1619 //if (offset == BG)
1620 //      WriteLog("TOM: Background written by %s: %u\n", whoName[who], data);
1621 //if (offset == INT1)
1622 //      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" : ""));
1623
1624         // detect screen resolution changes
1625 //This may go away in the future, if we do the virtualized screen thing...
1626 //This may go away soon!
1627 // TOM Shouldn't be mucking around with this, it's up to the host system to properly
1628 // handle this kind of crap.
1629 // NOTE: This is needed somehow, need to get rid of the dependency on this crap.
1630 //       N.B.: It's used in the rendering functions... So...
1631 #warning "!!! Need to get rid of this dependency !!!"
1632 #if 1
1633         if ((offset >= 0x28) && (offset <= 0x4F))
1634         {
1635                 uint32_t width = TOMGetVideoModeWidth(), height = TOMGetVideoModeHeight();
1636
1637                 if ((width != tomWidth) || (height != tomHeight))
1638                 {
1639                         tomWidth = width, tomHeight = height;
1640
1641 #warning "!!! TOM: ResizeScreen commented out !!!"
1642 // No need to resize anything, since we're prepared for this...
1643 //                      if (vjs.renderType == RT_NORMAL)
1644 //                              ResizeScreen(tomWidth, tomHeight);
1645                 }
1646         }
1647 #endif
1648 }
1649
1650
1651 int TOMIRQEnabled(int irq)
1652 {
1653         // This is the correct byte in big endian... D'oh!
1654 //      return jaguar_byte_read(0xF000E1) & (1 << irq);
1655         return tomRam8[INT1 + 1/*0xE1*/] & (1 << irq);
1656 }
1657
1658
1659 // NEW:
1660 // TOM Programmable Interrupt Timer handler
1661 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
1662 //       The PIT only generates an interrupt when it counts down to zero, not when loaded!
1663
1664 void TOMPITCallback(void);
1665
1666
1667 void TOMResetPIT(void)
1668 {
1669 #ifndef NEW_TIMER_SYSTEM
1670 //Probably should *add* this amount to the counter to retain cycle accuracy! !!! FIX !!! [DONE]
1671 //Also, why +1??? 'Cause that's what it says in the JTRM...!
1672 //There is a small problem with this approach: If both the prescaler and the divider are equal
1673 //to $FFFF then the counter won't be large enough to handle it. !!! FIX !!!
1674         if (tom_timer_prescaler)
1675                 tom_timer_counter += (1 + tom_timer_prescaler) * (1 + tom_timer_divider);
1676 //      WriteLog("tom: reseting timer to 0x%.8x (%i)\n",tom_timer_counter,tom_timer_counter);
1677 #else
1678         // Need to remove previous timer from the queue, if it exists...
1679         RemoveCallback(TOMPITCallback);
1680
1681         if (tomTimerPrescaler)
1682         {
1683                 double usecs = (float)(tomTimerPrescaler + 1) * (float)(tomTimerDivider + 1) * RISC_CYCLE_IN_USEC;
1684                 SetCallbackTime(TOMPITCallback, usecs);
1685         }
1686 #endif
1687 }
1688
1689
1690 //
1691 // TOM Programmable Interrupt Timer handler
1692 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
1693 //
1694 //NOTE: This is only used by the old execution code... Safe to remove
1695 //      once the timer system is stable.
1696 void TOMExecPIT(uint32_t cycles)
1697 {
1698         if (tomTimerPrescaler)
1699         {
1700                 tomTimerCounter -= cycles;
1701
1702                 if (tomTimerCounter <= 0)
1703                 {
1704                         TOMSetPendingTimerInt();
1705                         GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE);       // GPUSetIRQLine does the 'IRQ enabled' checking
1706
1707                         if (TOMIRQEnabled(IRQ_TIMER))
1708                                 m68k_set_irq(2);                                // Cause a 68000 IPL 2...
1709
1710                         TOMResetPIT();
1711                 }
1712         }
1713 }
1714
1715
1716 void TOMPITCallback(void)
1717 {
1718 //      INT1_RREG |= 0x08;                                                      // Set TOM PIT interrupt pending
1719         TOMSetPendingTimerInt();
1720     GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE);   // It does the 'IRQ enabled' checking
1721
1722 //      if (INT1_WREG & 0x08)
1723         if (TOMIRQEnabled(IRQ_TIMER))
1724                 m68k_set_irq(2);                                                // Generate a 68K IPL 2...
1725
1726         TOMResetPIT();
1727 }
1728