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