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 "event.h"
262 #include "gpu.h"
263 #include "jaguar.h"
264 #include "log.h"
265 #include "m68000/m68kinterface.h"
266 #include "op.h"
267 #include "settings.h"
268 
269 // Red Color Values for CrY<->RGB Color Conversion
270 uint8_t redcv[16][16] = {
271    //  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
272    // ----------------------------------------------------------------------
273 	{  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},    // 0
274 	{  34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 19, 0},    // 1
275 	{  68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 64, 43, 21, 0},    // 2
276 	{  102,102,102,102,102,102,102,102,102,102,102,95, 71, 47, 23, 0},    // 3
277 	{  135,135,135,135,135,135,135,135,135,135,130,104,78, 52, 26, 0},    // 4
278 	{  169,169,169,169,169,169,169,169,169,170,141,113,85, 56, 28, 0},    // 5
279 	{  203,203,203,203,203,203,203,203,203,183,153,122,91, 61, 30, 0},    // 6
280 	{  237,237,237,237,237,237,237,237,230,197,164,131,98, 65, 32, 0},    // 7
281 	{  255,255,255,255,255,255,255,255,247,214,181,148,15, 82, 49, 7},    // 8
282 	{  255,255,255,255,255,255,255,255,255,235,204,173,143,112,81, 51},   // 9
283 	{  255,255,255,255,255,255,255,255,255,255,227,198,170,141,113,85},   // A
284 	{  255,255,255,255,255,255,255,255,255,255,249,223,197,171,145,119},  // B
285 	{  255,255,255,255,255,255,255,255,255,255,255,248,224,200,177,153},  // C
286 	{  255,255,255,255,255,255,255,255,255,255,255,255,252,230,208,187},  // D
287 	{  255,255,255,255,255,255,255,255,255,255,255,255,255,255,240,221},  // E
288 	{  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}   // F
289 };
290 
291 // Green Color Values for CrY<->RGB Color Conversion
292 uint8_t greencv[16][16] = {
293    //  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
294    // ----------------------------------------------------------------------
295 	{  0,  17, 34, 51,68, 85, 102,119,136,153,170,187,204,221,238,255},   // 0
296 	{  0,  19, 38, 57,77, 96, 115,134,154,173,192,211,231,250,255,255},   // 1
297 	{  0,  21, 43, 64,86, 107,129,150,172,193,215,236,255,255,255,255},   // 2
298 	{  0,  23, 47, 71,95, 119,142,166,190,214,238,255,255,255,255,255},   // 3
299 	{  0,  26, 52, 78,104,130,156,182,208,234,255,255,255,255,255,255},   // 4
300 	{  0,  28, 56, 85,113,141,170,198,226,255,255,255,255,255,255,255},   // 5
301 	{  0,  30, 61, 91,122,153,183,214,244,255,255,255,255,255,255,255},   // 6
302 	{  0,  32, 65, 98,131,164,197,230,255,255,255,255,255,255,255,255},   // 7
303 	{  0,  32, 65, 98,131,164,197,230,255,255,255,255,255,255,255,255},   // 8
304 	{  0,  30, 61, 91,122,153,183,214,244,255,255,255,255,255,255,255},   // 9
305 	{  0,  28, 56, 85,113,141,170,198,226,255,255,255,255,255,255,255},   // A
306 	{  0,  26, 52, 78,104,130,156,182,208,234,255,255,255,255,255,255},   // B
307 	{  0,  23, 47, 71,95, 119,142,166,190,214,238,255,255,255,255,255},   // C
308 	{  0,  21, 43, 64,86, 107,129,150,172,193,215,236,255,255,255,255},   // D
309 	{  0,  19, 38, 57,77, 96, 115,134,154,173,192,211,231,250,255,255},   // E
310 	{  0,  17, 34, 51,68, 85, 102,119,136,153,170,187,204,221,238,255}    // F
311 };
312 
313 // Blue Color Values for CrY<->RGB Color Conversion
314 uint8_t bluecv[16][16] = {
315    //  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
316    // ----------------------------------------------------------------------
317 	{  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255},  // 0
318 	{  255,255,255,255,255,255,255,255,255,255,255,255,255,255,240,221},  // 1
319 	{  255,255,255,255,255,255,255,255,255,255,255,255,252,230,208,187},  // 2
320 	{  255,255,255,255,255,255,255,255,255,255,255,248,224,200,177,153},  // 3
321 	{  255,255,255,255,255,255,255,255,255,255,249,223,197,171,145,119},  // 4
322 	{  255,255,255,255,255,255,255,255,255,255,227,198,170,141,113,85},   // 5
323 	{  255,255,255,255,255,255,255,255,255,235,204,173,143,112,81, 51},   // 6
324 	{  255,255,255,255,255,255,255,255,247,214,181,148,115,82, 49, 17},   // 7
325 	{  237,237,237,237,237,237,237,237,230,197,164,131,98, 65, 32, 0},    // 8
326 	{  203,203,203,203,203,203,203,203,203,183,153,122,91, 61, 30, 0},    // 9
327 	{  169,169,169,169,169,169,169,169,169,170,141,113,85, 56, 28, 0},    // A
328 	{  135,135,135,135,135,135,135,135,135,135,130,104,78, 52, 26, 0},    // B
329 	{  102,102,102,102,102,102,102,102,102,102,102,95, 71, 47, 23, 0},    // C
330 	{  68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 64, 43, 21, 0},    // D
331 	{  34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 19, 0},    // E
332 	{  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0}     // F
333 };
334 
335 #define NEW_TIMER_SYSTEM
336 
337 // TOM registers (offset from $F00000)
338 
339 #define MEMCON1		0x00
340 #define MEMCON2		0x02
341 #define HC			0x04
342 #define VC			0x06
343 #define OLP			0x20		// Object list pointer
344 #define OBF			0x26		// Object processor flag
345 #define VMODE		0x28
346 #define   MODE		0x0006		// Line buffer to video generator mode
347 #define   BGEN		0x0080		// Background enable (CRY & RGB16 only)
348 #define   VARMOD	0x0100		// Mixed CRY/RGB16 mode (only works in MODE 0!)
349 #define   PWIDTH	0x0E00		// Pixel width in video clock cycles (value written + 1)
350 #define BORD1		0x2A		// Border green/red values (8 BPP)
351 #define BORD2		0x2C		// Border blue value (8 BPP)
352 #define HP			0x2E		// Values range from 1 - 1024 (value written + 1)
353 #define HBB			0x30		// Horizontal blank begin
354 #define HBE			0x32
355 #define HS			0x34		// Horizontal sync
356 #define HVS			0x36		// Horizontal vertical sync
357 #define HDB1		0x38		// Horizontal display begin 1
358 #define HDB2		0x3A
359 #define HDE			0x3C
360 #define VP			0x3E		// Value ranges from 1 - 2048 (value written + 1)
361 #define VBB			0x40		// Vertical blank begin
362 #define VBE			0x42
363 #define VS			0x44		// Vertical sync
364 #define VDB			0x46		// Vertical display begin
365 #define VDE			0x48
366 #define VEB			0x4A		// Vertical equalization begin
367 #define VEE			0x4C		// Vertical equalization end
368 #define VI			0x4E		// Vertical interrupt
369 #define PIT0		0x50
370 #define PIT1		0x52
371 #define HEQ			0x54		// Horizontal equalization end
372 #define BG			0x58		// Background color
373 #define INT1		0xE0
374 
375 //NOTE: These arbitrary cutoffs are NOT taken into account for PAL jaguar screens. !!! FIX !!! [DONE]
376 
377 #define LEFT_VISIBLE_HC			(208 - 16 - (1 * 4))
378 #define RIGHT_VISIBLE_HC		(LEFT_VISIBLE_HC + (VIRTUAL_SCREEN_WIDTH * 4))
379 #define TOP_VISIBLE_VC			31
380 #define BOTTOM_VISIBLE_VC		511
381 
382 //Are these PAL horizontals correct?
383 //They seem to be for the most part, but there are some games that seem to be
384 //shifted over to the right from this "window".
385 #define LEFT_VISIBLE_HC_PAL	(208 - 16 - (-3 * 4))
386 #define RIGHT_VISIBLE_HC_PAL	(LEFT_VISIBLE_HC_PAL + (VIRTUAL_SCREEN_WIDTH * 4))
387 #define TOP_VISIBLE_VC_PAL		67
388 #define BOTTOM_VISIBLE_VC_PAL	579
389 
390 #ifdef __LIBRETRO__
391 extern int doom_res_hack;
392 #endif
393 
394 uint8_t tomRam8[0x4000];
395 uint32_t tomWidth, tomHeight;
396 uint32_t tomTimerPrescaler;
397 uint32_t tomTimerDivider;
398 int32_t tomTimerCounter;
399 uint16_t tom_jerry_int_pending, tom_timer_int_pending, tom_object_int_pending,
400          tom_gpu_int_pending, tom_video_int_pending;
401 
402 // These are set by the "user" of the Jaguar core lib, since these are
403 // OS/system dependent.
404 uint32_t * screenBuffer;
405 uint32_t screenPitch;
406 
407 static const char * videoMode_to_str[8] =
408 { "16 BPP CRY", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB",
409    "Mixed mode", "24 BPP RGB", "16 BPP DIRECT", "16 BPP RGB" };
410 
411 typedef void (render_xxx_scanline_fn)(uint32_t *);
412 
413 // Private function prototypes
414 
415 void tom_render_16bpp_cry_scanline(uint32_t * backbuffer);
416 void tom_render_24bpp_scanline(uint32_t * backbuffer);
417 void tom_render_16bpp_direct_scanline(uint32_t * backbuffer);
418 void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer);
419 void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer);
420 
421 render_xxx_scanline_fn * scanline_render[] =
422 {
423    tom_render_16bpp_cry_scanline,
424    tom_render_24bpp_scanline,
425    tom_render_16bpp_direct_scanline,
426    tom_render_16bpp_rgb_scanline,
427    tom_render_16bpp_cry_rgb_mix_scanline,
428    tom_render_24bpp_scanline,
429    tom_render_16bpp_direct_scanline,
430    tom_render_16bpp_rgb_scanline
431 };
432 
433 uint32_t RGB16ToRGB32[0x10000];
434 uint32_t CRY16ToRGB32[0x10000];
435 uint32_t MIX16ToRGB32[0x10000];
436 
437 //#warning "This is not endian-safe. !!! FIX !!!"
TOMFillLookupTables(void)438 void TOMFillLookupTables(void)
439 {
440    // NOTE: Jaguar 16-bit (non-CRY) color is RBG 556 like so:
441    //       RRRR RBBB BBGG GGGG
442 
443    unsigned i;
444    for(i=0; i<0x10000; i++)
445       RGB16ToRGB32[i] = 0xFF000000
446          | ((i & 0xF800) << 8)					// Red
447          | ((i & 0x003F) << 10)					// Green
448          | ((i & 0x07C0) >> 3);					// Blue
449 
450    for(i=0; i<0x10000; i++)
451    {
452       uint32_t cyan = (i & 0xF000) >> 12,
453                red = (i & 0x0F00) >> 8,
454                intensity = (i & 0x00FF);
455 
456       uint32_t r = (((uint32_t)redcv[cyan][red]) * intensity) >> 8,
457                g = (((uint32_t)greencv[cyan][red]) * intensity) >> 8,
458                b = (((uint32_t)bluecv[cyan][red]) * intensity) >> 8;
459 
460       CRY16ToRGB32[i] = 0xFF000000 | (r << 16) | (g << 8) | (b << 0);
461       MIX16ToRGB32[i] = ((i & 0x01) ? RGB16ToRGB32[i] : CRY16ToRGB32[i]);
462    }
463 }
464 
465 
TOMSetPendingJERRYInt(void)466 void TOMSetPendingJERRYInt(void)
467 {
468    tom_jerry_int_pending = 1;
469 }
470 
471 
TOMSetPendingTimerInt(void)472 void TOMSetPendingTimerInt(void)
473 {
474    tom_timer_int_pending = 1;
475 }
476 
477 
TOMSetPendingObjectInt(void)478 void TOMSetPendingObjectInt(void)
479 {
480    tom_object_int_pending = 1;
481 }
482 
483 
TOMSetPendingGPUInt(void)484 void TOMSetPendingGPUInt(void)
485 {
486    tom_gpu_int_pending = 1;
487 }
488 
489 
TOMSetPendingVideoInt(void)490 void TOMSetPendingVideoInt(void)
491 {
492    tom_video_int_pending = 1;
493 }
494 
495 
TOMGetRamPointer(void)496 uint8_t * TOMGetRamPointer(void)
497 {
498    return tomRam8;
499 }
500 
501 
TOMGetVideoMode(void)502 uint8_t TOMGetVideoMode(void)
503 {
504    uint16_t vmode = GET16(tomRam8, VMODE);
505    return ((vmode & VARMOD) >> 6) | ((vmode & MODE) >> 1);
506 }
507 
TOMGetVDB(void)508 uint16_t TOMGetVDB(void)
509 {
510    return GET16(tomRam8, VDB);
511 }
512 
TOMGetHC(void)513 uint16_t TOMGetHC(void)
514 {
515    return GET16(tomRam8, HC);
516 }
517 
518 
TOMGetVP(void)519 uint16_t TOMGetVP(void)
520 {
521    return GET16(tomRam8, VP);
522 }
523 
TOMGetMEMCON1(void)524 uint16_t TOMGetMEMCON1(void)
525 {
526    return GET16(tomRam8, MEMCON1);
527 }
528 
529 #define LEFT_BG_FIX
530 // 16 BPP CRY/RGB mixed mode rendering
tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer)531 void tom_render_16bpp_cry_rgb_mix_scanline(uint32_t * backbuffer)
532 {
533    //CHANGED TO 32BPP RENDERING
534    uint16_t width = tomWidth;
535    uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
536 
537    //New stuff--restrict our drawing...
538    uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
539    //NOTE: May have to check HDB2 as well!
540    // Get start position in HC ticks
541    int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);
542    // Convert to pixels
543    startPos /= pwidth;
544 
545    if (startPos < 0)
546       // This is x2 because current_line_buffer is uint8_t & we're in a 16bpp mode
547       current_line_buffer += 2 * -startPos;
548    else
549       //This case doesn't properly handle the "start on the right side of virtual screen" case
550       //Dunno why--looks Ok...
551       //What *is* for sure wrong is that it doesn't copy the linebuffer's BG pixels... [FIXED NOW]
552       //This should likely be 4 instead of 2 (?--not sure)
553       // Actually, there should be NO multiplier, as startPos is expressed in PIXELS
554       // and so is the backbuffer.
555 #ifdef LEFT_BG_FIX
556    {
557       unsigned i;
558       uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
559       uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | (b << 0);
560 
561       for(i=0; i<startPos; i++)
562          *backbuffer++ = pixel;
563 
564       width -= startPos;
565    }
566 #else
567    backbuffer += 2 * startPos, width -= startPos;
568 #endif
569 
570    while (width)
571    {
572       uint16_t color = (*current_line_buffer++) << 8;
573       color |= *current_line_buffer++;
574       *backbuffer++ = MIX16ToRGB32[color];
575       width--;
576    }
577 }
578 
579 // 16 BPP CRY mode rendering
tom_render_16bpp_cry_scanline(uint32_t * backbuffer)580 void tom_render_16bpp_cry_scanline(uint32_t * backbuffer)
581 {
582    unsigned i;
583    //CHANGED TO 32BPP RENDERING
584    uint16_t width = tomWidth;
585    uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
586 
587    //New stuff--restrict our drawing...
588    uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
589    //NOTE: May have to check HDB2 as well!
590    int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);// Get start position in HC ticks
591    startPos /= pwidth;
592    if (startPos < 0)
593       current_line_buffer += 2 * -startPos;
594    else
595 #ifdef LEFT_BG_FIX
596    {
597       uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
598       uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | (b << 0);
599 
600       for(i=0; i<startPos; i++)
601          *backbuffer++ = pixel;
602 
603       width -= startPos;
604    }
605 #else
606    //This should likely be 4 instead of 2 (?--not sure)
607    backbuffer += 2 * startPos, width -= startPos;
608 #endif
609 
610    while (width)
611    {
612       uint16_t color = (*current_line_buffer++) << 8;
613       color |= *current_line_buffer++;
614       *backbuffer++ = CRY16ToRGB32[color];
615 #ifdef __LIBRETRO__
616       //Double pixel screen on doom if pwidth=8 -> (163*2)
617       if(doom_res_hack==1)
618          if(pwidth==8)*backbuffer++ = CRY16ToRGB32[color];
619 #endif
620       width--;
621    }
622 }
623 
624 // 24 BPP mode rendering
tom_render_24bpp_scanline(uint32_t * backbuffer)625 void tom_render_24bpp_scanline(uint32_t * backbuffer)
626 {
627    unsigned i;
628    //CHANGED TO 32BPP RENDERING
629    uint16_t width = tomWidth;
630    uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
631 
632    //New stuff--restrict our drawing...
633    uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
634    //NOTE: May have to check HDB2 as well!
635    int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);	// Get start position in HC ticks
636    startPos /= pwidth;
637    if (startPos < 0)
638       current_line_buffer += 4 * -startPos;
639    else
640 #ifdef LEFT_BG_FIX
641    {
642       uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
643       uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | (b << 0);
644 
645       for(i=0; i<startPos; i++)
646          *backbuffer++ = pixel;
647 
648       width -= startPos;
649    }
650 #else
651    //This should likely be 4 instead of 2 (?--not sure)
652    backbuffer += 2 * startPos, width -= startPos;
653 #endif
654 
655    while (width)
656    {
657       uint32_t b;
658       uint32_t g = *current_line_buffer++;
659       uint32_t r = *current_line_buffer++;
660       current_line_buffer++;
661       b = *current_line_buffer++;
662       //hm.		*backbuffer++ = 0xFF000000 | (b << 16) | (g << 8) | r;
663       *backbuffer++ = 0xFF000000 | (r << 16) | (g << 8) | (b << 0);
664       width--;
665    }
666 }
667 
668 //Seems to me that this is NOT a valid mode--the JTRM seems to imply that you would need
669 //extra hardware outside of the Jaguar console to support this!
670 // 16 BPP direct mode rendering
tom_render_16bpp_direct_scanline(uint32_t * backbuffer)671 void tom_render_16bpp_direct_scanline(uint32_t * backbuffer)
672 {
673    uint16_t width = tomWidth;
674    uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
675 
676    while (width)
677    {
678       uint16_t color = (*current_line_buffer++) << 8;
679       color |= *current_line_buffer++;
680       *backbuffer++ = color >> 1;
681       width--;
682    }
683 }
684 
685 
686 // 16 BPP RGB mode rendering
tom_render_16bpp_rgb_scanline(uint32_t * backbuffer)687 void tom_render_16bpp_rgb_scanline(uint32_t * backbuffer)
688 {
689    unsigned i;
690    //CHANGED TO 32BPP RENDERING
691    // 16 BPP RGB: 0-5 green, 6-10 blue, 11-15 red
692 
693    uint16_t width = tomWidth;
694    uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
695 
696    //New stuff--restrict our drawing...
697    uint8_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
698    //NOTE: May have to check HDB2 as well!
699    int16_t startPos = GET16(tomRam8, HDB1) - (vjs.hardwareTypeNTSC ? LEFT_VISIBLE_HC : LEFT_VISIBLE_HC_PAL);	// Get start position in HC ticks
700    startPos /= pwidth;
701 
702    if (startPos < 0)
703       current_line_buffer += 2 * -startPos;
704    else
705 #ifdef LEFT_BG_FIX
706    {
707       uint8_t g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
708       uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | (b << 0);
709 
710       for(i=0; i<startPos; i++)
711          *backbuffer++ = pixel;
712 
713       width -= startPos;
714    }
715 #else
716    //This should likely be 4 instead of 2 (?--not sure)
717    backbuffer += 2 * startPos, width -= startPos;
718 #endif
719 
720    while (width)
721    {
722       uint32_t color = (*current_line_buffer++) << 8;
723       color |= *current_line_buffer++;
724       *backbuffer++ = RGB16ToRGB32[color];
725       width--;
726    }
727 }
728 
729 // Process a single scanline
TOMExecHalfline(uint16_t halfline,bool render)730 void TOMExecHalfline(uint16_t halfline, bool render)
731 {
732    unsigned i;
733    uint16_t field2 = halfline & 0x0800;
734    bool inActiveDisplayArea = true;
735    uint16_t startingHalfline;
736    uint16_t endingHalfline;
737    uint32_t * TOMCurrentLine = 0;
738    uint16_t topVisible;
739    uint16_t bottomVisible;
740 
741    halfline &= 0x07FF;
742 
743    if (halfline & 0x01)							// Execute OP only on even halflines (non-interlaced only!)
744       // Execute OP only on even halflines (skip higher resolutions for now...)
745       return;
746 
747    // Initial values that "well behaved" programs use
748    startingHalfline = GET16(tomRam8, VDB);
749    endingHalfline = GET16(tomRam8, VDE);
750 
751    // Simulate the OP start bug here!
752    // Really, this value is somewhere around 507 for an NTSC Jaguar. But this
753    // should work in a majority of cases, at least until we can figure it out properly.
754    if (endingHalfline > GET16(tomRam8, VP))
755       startingHalfline = 0;
756 
757    if ((halfline >= startingHalfline) && (halfline < endingHalfline))
758    {
759       if (render)
760       {
761          uint8_t * current_line_buffer = (uint8_t *)&tomRam8[0x1800];
762          uint8_t bgHI = tomRam8[BG], bgLO = tomRam8[BG + 1];
763 
764          // Clear line buffer with BG
765          if (GET16(tomRam8, VMODE) & BGEN) // && (CRY or RGB16)...
766             for(i=0; i<720; i++)
767                *current_line_buffer++ = bgHI, *current_line_buffer++ = bgLO;
768 
769          OPProcessList(halfline, render);
770       }
771    }
772    else
773       inActiveDisplayArea = false;
774 
775    // Take PAL into account...
776 
777    topVisible = (vjs.hardwareTypeNTSC ? TOP_VISIBLE_VC : TOP_VISIBLE_VC_PAL);
778    bottomVisible = (vjs.hardwareTypeNTSC ? BOTTOM_VISIBLE_VC : BOTTOM_VISIBLE_VC_PAL);
779 
780    // Bit 0 in VP is interlace flag. 0 = interlace, 1 = non-interlaced
781    if (tomRam8[VP + 1] & 0x01)
782       TOMCurrentLine = &(screenBuffer[((halfline - topVisible) / 2) * screenPitch]);//non-interlace
783    else
784       TOMCurrentLine = &(screenBuffer[(((halfline - topVisible) / 2) * screenPitch * 2) + (field2 ? 0 : screenPitch)]);//interlace
785 
786    // Here's our virtualized scanline code...
787 
788    if ((halfline >= topVisible) && (halfline < bottomVisible))
789    {
790       if (inActiveDisplayArea)
791          scanline_render[TOMGetVideoMode()](TOMCurrentLine);
792       else
793       {
794          // If outside of VDB & VDE, then display the border color
795          uint32_t * currentLineBuffer = TOMCurrentLine;
796          uint8_t      g = tomRam8[BORD1], r = tomRam8[BORD1 + 1], b = tomRam8[BORD2 + 1];
797          uint32_t pixel = 0xFF000000 | (r << 16) | (g << 8) | (b << 0);
798 
799          for(i=0; i<tomWidth; i++)
800             *currentLineBuffer++ = pixel;
801       }
802    }
803 }
804 
805 // TOM initialization
TOMInit(void)806 void TOMInit(void)
807 {
808    TOMFillLookupTables();
809    OPInit();
810    BlitterInit();
811    TOMReset();
812 }
813 
814 
TOMDone(void)815 void TOMDone(void)
816 {
817    OPDone();
818    BlitterDone();
819    WriteLog("TOM: Resolution %i x %i %s\n", TOMGetVideoModeWidth(), TOMGetVideoModeHeight(),
820          videoMode_to_str[TOMGetVideoMode()]);
821 }
822 
823 
TOMGetVideoModeWidth(void)824 uint32_t TOMGetVideoModeWidth(void)
825 {
826    uint16_t pwidth = ((GET16(tomRam8, VMODE) & PWIDTH) >> 9) + 1;
827    return (vjs.hardwareTypeNTSC ? RIGHT_VISIBLE_HC - LEFT_VISIBLE_HC : RIGHT_VISIBLE_HC_PAL - LEFT_VISIBLE_HC_PAL) / pwidth;
828 }
829 
TOMGetVideoModeHeight(void)830 uint32_t TOMGetVideoModeHeight(void)
831 {
832    return (vjs.hardwareTypeNTSC ? 240 : 256);
833 }
834 
TOMReset(void)835 void TOMReset(void)
836 {
837    OPReset();
838    BlitterReset();
839    memset(tomRam8, 0x00, 0x4000);
840 
841    if (vjs.hardwareTypeNTSC)
842    {
843       SET16(tomRam8, MEMCON1, 0x1861);
844       SET16(tomRam8, MEMCON2, 0x35CC);
845       SET16(tomRam8, HP, 844);			// Horizontal Period (1-based; HP=845)
846       SET16(tomRam8, HBB, 1713);			// Horizontal Blank Begin
847       SET16(tomRam8, HBE, 125);			// Horizontal Blank End
848       SET16(tomRam8, HDE, 1665);			// Horizontal Display End
849       SET16(tomRam8, HDB1, 203);			// Horizontal Display Begin 1
850       SET16(tomRam8, VP, 523);			// Vertical Period (1-based; in this case VP = 524)
851       SET16(tomRam8, VBE, 24);			// Vertical Blank End
852       SET16(tomRam8, VDB, 38);			// Vertical Display Begin
853       SET16(tomRam8, VDE, 518);			// Vertical Display End
854       SET16(tomRam8, VBB, 500);			// Vertical Blank Begin
855       SET16(tomRam8, VS, 517);			// Vertical Sync
856       SET16(tomRam8, VMODE, 0x06C1);
857    }
858    else	// PAL Jaguar
859    {
860       SET16(tomRam8, MEMCON1, 0x1861);
861       SET16(tomRam8, MEMCON2, 0x35CC);
862       SET16(tomRam8, HP, 850);			// Horizontal Period
863       SET16(tomRam8, HBB, 1711);			// Horizontal Blank Begin
864       SET16(tomRam8, HBE, 158);			// Horizontal Blank End
865       SET16(tomRam8, HDE, 1665);			// Horizontal Display End
866       SET16(tomRam8, HDB1, 203);			// Horizontal Display Begin 1
867       SET16(tomRam8, VP, 623);			// Vertical Period (1-based; in this case VP = 624)
868       SET16(tomRam8, VBE, 34);			// Vertical Blank End
869       SET16(tomRam8, VDB, 38);			// Vertical Display Begin
870       SET16(tomRam8, VDE, 518);			// Vertical Display End
871       SET16(tomRam8, VBB, 600);			// Vertical Blank Begin
872       SET16(tomRam8, VS, 618);			// Vertical Sync
873       SET16(tomRam8, VMODE, 0x06C1);
874    }
875 
876    tomWidth = 0;
877    tomHeight = 0;
878 
879    tom_jerry_int_pending = 0;
880    tom_timer_int_pending = 0;
881    tom_object_int_pending = 0;
882    tom_gpu_int_pending = 0;
883    tom_video_int_pending = 0;
884 
885    tomTimerPrescaler = 0;					// TOM PIT is disabled
886    tomTimerDivider = 0;
887    tomTimerCounter = 0;
888 }
889 
TOMReadByte(uint32_t offset,uint32_t who)890 uint8_t TOMReadByte(uint32_t offset, uint32_t who)
891 {
892    //???Is this needed???
893    // It seems so. Perhaps it's the +$8000 offset being written to (32-bit interface)?
894    // However, the 32-bit interface is WRITE ONLY, so that can't be it...
895    // Also, the 68K CANNOT make use of the 32-bit interface, since its bus width is only 16-bits...
896    //	offset &= 0xFF3FFF;
897 
898    if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
899       return GPUReadByte(offset, who);
900    else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
901       return GPUReadByte(offset, who);
902    else if ((offset >= 0xF02200) && (offset < 0xF022A0))
903       return BlitterReadByte(offset, who);
904    else if (offset == 0xF00050)
905       return tomTimerPrescaler >> 8;
906    else if (offset == 0xF00051)
907       return tomTimerPrescaler & 0xFF;
908    else if (offset == 0xF00052)
909       return tomTimerDivider >> 8;
910    else if (offset == 0xF00053)
911       return tomTimerDivider & 0xFF;
912 
913    return tomRam8[offset & 0x3FFF];
914 }
915 
916 
917 // TOM word access (read)
TOMReadWord(uint32_t offset,uint32_t who)918 uint16_t TOMReadWord(uint32_t offset, uint32_t who)
919 {
920    if (offset == 0xF000E0)
921    {
922       // For reading, should only return the lower 5 bits...
923       uint16_t data = (tom_jerry_int_pending << 4) | (tom_timer_int_pending << 3)
924          | (tom_object_int_pending << 2) | (tom_gpu_int_pending << 1)
925          | (tom_video_int_pending << 0);
926       return data;
927    }
928    else if (offset == 0xF00004)
929       return rand() & 0x03FF;
930    else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE + 0x20))
931       return GPUReadWord(offset, who);
932    else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000))
933       return GPUReadWord(offset, who);
934    else if ((offset >= 0xF02200) && (offset < 0xF022A0))
935       return BlitterReadWord(offset, who);
936    else if (offset == 0xF00050)
937       return tomTimerPrescaler;
938    else if (offset == 0xF00052)
939       return tomTimerDivider;
940 
941    offset &= 0x3FFF;
942    return (TOMReadByte(offset, who) << 8) | TOMReadByte(offset + 1, who);
943 }
944 
945 
946 #define TOM_STRICT_MEMORY_ACCESS
947 // TOM byte access (write)
TOMWriteByte(uint32_t offset,uint8_t data,uint32_t who)948 void TOMWriteByte(uint32_t offset, uint8_t data, uint32_t who)
949 {
950    //???Is this needed???
951    // Perhaps on the writes--32-bit writes that is! And masked with FF7FFF...
952 #ifndef TOM_STRICT_MEMORY_ACCESS
953    offset &= 0xFF3FFF;
954 #else
955    // "Fast" (32-bit only) write access to the GPU
956    //	if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF))
957    if ((offset >= 0xF08000) && (offset <= 0xF0BFFF))
958       offset &= 0xFF7FFF;
959 #endif
960 
961 #ifdef TOM_STRICT_MEMORY_ACCESS
962    // Sanity check ("Aww, there ain't no Sanity Clause...")
963    if ((offset < 0xF00000) || (offset > 0xF03FFF))
964       return;
965 #endif
966 
967    if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
968    {
969       GPUWriteByte(offset, data, who);
970       return;
971    }
972    else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
973    {
974       GPUWriteByte(offset, data, who);
975       return;
976    }
977    else if ((offset >= 0xF02200) && (offset < 0xF022A0))
978    {
979       BlitterWriteByte(offset, data, who);
980       return;
981    }
982    else if (offset == 0xF00050)
983    {
984       tomTimerPrescaler = (tomTimerPrescaler & 0x00FF) | (data << 8);
985       TOMResetPIT();
986       return;
987    }
988    else if (offset == 0xF00051)
989    {
990       tomTimerPrescaler = (tomTimerPrescaler & 0xFF00) | data;
991       TOMResetPIT();
992       return;
993    }
994    else if (offset == 0xF00052)
995    {
996       tomTimerDivider = (tomTimerDivider & 0x00FF) | (data << 8);
997       TOMResetPIT();
998       return;
999    }
1000    else if (offset == 0xF00053)
1001    {
1002       tomTimerDivider = (tomTimerDivider & 0xFF00) | data;
1003       TOMResetPIT();
1004       return;
1005    }
1006    else if (offset >= 0xF00400 && offset <= 0xF007FF)	// CLUT (A & B)
1007    {
1008       // Writing to one CLUT writes to the other
1009       offset &= 0x5FF;		// Mask out $F00600 (restrict to $F00400-5FF)
1010       tomRam8[offset] = data, tomRam8[offset + 0x200] = data;
1011    }
1012 
1013    tomRam8[offset & 0x3FFF] = data;
1014 }
1015 
1016 // TOM word access (write)
TOMWriteWord(uint32_t offset,uint16_t data,uint32_t who)1017 void TOMWriteWord(uint32_t offset, uint16_t data, uint32_t who)
1018 {
1019    //???Is this needed??? Yes, but we need to be more vigilant than this.
1020 #ifndef TOM_STRICT_MEMORY_ACCESS
1021    offset &= 0xFF3FFF;
1022 #else
1023    // "Fast" (32-bit only) write access to the GPU
1024    //	if ((offset >= 0xF0A100) && (offset <= 0xF0BFFF))
1025    if ((offset >= 0xF08000) && (offset <= 0xF0BFFF))
1026       offset &= 0xFF7FFF;
1027 #endif
1028 
1029 #ifdef TOM_STRICT_MEMORY_ACCESS
1030    // Sanity check
1031    if ((offset < 0xF00000) || (offset > 0xF03FFF))
1032       return;
1033 #endif
1034 
1035    if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
1036    {
1037       GPUWriteWord(offset, data, who);
1038       return;
1039    }
1040    else if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
1041    {
1042       GPUWriteWord(offset, data, who);
1043       return;
1044    }
1045    else if (offset == 0xF00050)
1046    {
1047       tomTimerPrescaler = data;
1048       TOMResetPIT();
1049       return;
1050    }
1051    else if (offset == 0xF00052)
1052    {
1053       tomTimerDivider = data;
1054       TOMResetPIT();
1055       return;
1056    }
1057    else if (offset == 0xF000E0)
1058    {
1059       //Check this out...
1060       if (data & 0x0100)
1061          tom_video_int_pending = 0;
1062       if (data & 0x0200)
1063          tom_gpu_int_pending = 0;
1064       if (data & 0x0400)
1065          tom_object_int_pending = 0;
1066       if (data & 0x0800)
1067          tom_timer_int_pending = 0;
1068       if (data & 0x1000)
1069          tom_jerry_int_pending = 0;
1070    }
1071    else if ((offset >= 0xF02200) && (offset <= 0xF0229F))
1072    {
1073       BlitterWriteWord(offset, data, who);
1074       return;
1075    }
1076    else if (offset >= 0xF00400 && offset <= 0xF007FE)	// CLUT (A & B)
1077    {
1078       // Writing to one CLUT writes to the other
1079       offset &= 0x5FF;		// Mask out $F00600 (restrict to $F00400-5FF)
1080       // Watch out for unaligned writes here! (Not fixed yet)
1081 //#warning "!!! Watch out for unaligned writes here !!! FIX !!!"
1082       SET16(tomRam8, offset, data);
1083       SET16(tomRam8, offset + 0x200, data);
1084    }
1085 
1086    offset &= 0x3FFF;
1087    if (offset == 0x28)			// VMODE (Why? Why not OBF?)
1088       //Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!
1089 //#warning "Actually, we should check to see if the Enable bit of VMODE is set before doing this... !!! FIX !!!"
1090       objectp_running = 1;
1091 
1092    if (offset >= 0x30 && offset <= 0x4E)
1093       data &= 0x07FF;			// These are (mostly) 11-bit registers
1094    if (offset == 0x2E || offset == 0x36 || offset == 0x54)
1095       data &= 0x03FF;			// These are all 10-bit registers
1096 
1097    // Fix a lockup bug... :-P
1098    TOMWriteByte(0xF00000 | offset, data >> 8, who);
1099    TOMWriteByte(0xF00000 | (offset+1), data & 0xFF, who);
1100 
1101    // detect screen resolution changes
1102    //This may go away in the future, if we do the virtualized screen thing...
1103    //This may go away soon!
1104    // TOM Shouldn't be mucking around with this, it's up to the host system to properly
1105    // handle this kind of crap.
1106    // NOTE: This is needed somehow, need to get rid of the dependency on this crap.
1107 //#warning "!!! Need to get rid of this dependency !!!"
1108    if ((offset >= 0x28) && (offset <= 0x4F))
1109    {
1110       uint32_t width = TOMGetVideoModeWidth(), height = TOMGetVideoModeHeight();
1111 
1112       if ((width != tomWidth) || (height != tomHeight))
1113       {
1114          tomWidth = width, tomHeight = height;
1115       }
1116    }
1117 }
1118 
1119 
TOMIRQEnabled(int irq)1120 int TOMIRQEnabled(int irq)
1121 {
1122    // This is the correct byte in big endian... D'oh!
1123    //	return jaguar_byte_read(0xF000E1) & (1 << irq);
1124    return tomRam8[INT1 + 1] & (1 << irq);
1125 }
1126 
1127 
1128 // NEW:
1129 // TOM Programmable Interrupt Timer handler
1130 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
1131 //       The PIT only generates an interrupt when it counts down to zero, not when loaded!
1132 
1133 void TOMPITCallback(void);
1134 
1135 
TOMResetPIT(void)1136 void TOMResetPIT(void)
1137 {
1138 #ifndef NEW_TIMER_SYSTEM
1139    //Probably should *add* this amount to the counter to retain cycle accuracy! !!! FIX !!! [DONE]
1140    //Also, why +1??? 'Cause that's what it says in the JTRM...!
1141    //There is a small problem with this approach: If both the prescaler and the divider are equal
1142    //to $FFFF then the counter won't be large enough to handle it. !!! FIX !!!
1143    if (tom_timer_prescaler)
1144       tom_timer_counter += (1 + tom_timer_prescaler) * (1 + tom_timer_divider);
1145 #else
1146    // Need to remove previous timer from the queue, if it exists...
1147    RemoveCallback(TOMPITCallback);
1148 
1149    if (tomTimerPrescaler)
1150    {
1151       double usecs = (float)(tomTimerPrescaler + 1) * (float)(tomTimerDivider + 1) * RISC_CYCLE_IN_USEC;
1152       SetCallbackTime(TOMPITCallback, usecs, EVENT_MAIN);
1153    }
1154 #endif
1155 }
1156 
1157 // TOM Programmable Interrupt Timer handler
1158 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
1159 //
1160 //NOTE: This is only used by the old execution code... Safe to remove
1161 //      once the timer system is stable.
TOMExecPIT(uint32_t cycles)1162 void TOMExecPIT(uint32_t cycles)
1163 {
1164    if (tomTimerPrescaler)
1165    {
1166       tomTimerCounter -= cycles;
1167 
1168       if (tomTimerCounter <= 0)
1169       {
1170          TOMSetPendingTimerInt();
1171          GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE);	// GPUSetIRQLine does the 'IRQ enabled' checking
1172 
1173          if (TOMIRQEnabled(IRQ_TIMER))
1174             m68k_set_irq(2);				// Cause a 68000 IPL 2...
1175 
1176          TOMResetPIT();
1177       }
1178    }
1179 }
1180 
1181 
TOMPITCallback(void)1182 void TOMPITCallback(void)
1183 {
1184    TOMSetPendingTimerInt();                  // Set TOM PIT interrupt pending
1185    GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE);	// It does the 'IRQ enabled' checking
1186 
1187    if (TOMIRQEnabled(IRQ_TIMER))
1188       m68k_set_irq(2);						// Generate a 68K IPL 2...
1189 
1190    TOMResetPIT();
1191 }
1192