gfx.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /***************************************************************************************
  2. * Genesis Plus
  3. * CD graphics processor
  4. *
  5. * Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
  6. *
  7. * Redistribution and use of this code or any derivative works are permitted
  8. * provided that the following conditions are met:
  9. *
  10. * - Redistributions may not be sold, nor may they be used in a commercial
  11. * product or activity.
  12. *
  13. * - Redistributions that are modified from the original source must include the
  14. * complete source code, including the source code for all components used by a
  15. * binary built from the modified sources. However, as a special exception, the
  16. * source code distributed need not include anything that is normally distributed
  17. * (in either source or binary form) with the major components (compiler, kernel,
  18. * and so on) of the operating system on which the executable runs, unless that
  19. * component itself accompanies the executable.
  20. *
  21. * - Redistributions must reproduce the above copyright notice, this list of
  22. * conditions and the following disclaimer in the documentation and/or other
  23. * materials provided with the distribution.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  26. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  29. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  30. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  31. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  32. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  33. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  34. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  35. * POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. ****************************************************************************************/
  38. #include "../pico_int.h"
  39. #include "genplus_macros.h"
  40. typedef struct
  41. {
  42. //uint32 cycles; /* current cycles count for graphics operation */
  43. //uint32 cyclesPerLine; /* current graphics operation timings */
  44. uint32 dotMask; /* stamp map size mask */
  45. uint16 *tracePtr; /* trace vector pointer */
  46. uint16 *mapPtr; /* stamp map table base address */
  47. uint8 stampShift; /* stamp pixel shift value (related to stamp size) */
  48. uint8 mapShift; /* stamp map table shift value (related to stamp map size) */
  49. uint16 bufferOffset; /* image buffer column offset */
  50. uint32 bufferStart; /* image buffer start index */
  51. uint32 y_step; /* pico: render line step */
  52. uint8 lut_prio[4][0x10][0x10]; /* WORD-RAM data writes priority lookup table */
  53. uint8 lut_pixel[0x200]; /* Graphics operation dot offset lookup table */
  54. uint8 lut_cell[0x100]; /* Graphics operation stamp offset lookup table */
  55. } gfx_t;
  56. static gfx_t gfx;
  57. static void gfx_schedule(void);
  58. /***************************************************************/
  59. /* Rotation / Scaling operation (2M Mode) */
  60. /***************************************************************/
  61. void gfx_init(void)
  62. {
  63. int i, j;
  64. uint8 mask, row, col, temp;
  65. memset(&gfx, 0, sizeof(gfx));
  66. /* Initialize priority modes lookup table */
  67. for (i = 0; i < 0x10; i++)
  68. {
  69. for (j = 0; j < 0x10; j++)
  70. {
  71. /* normal */
  72. gfx.lut_prio[0][i][j] = j;
  73. /* underwrite */
  74. gfx.lut_prio[1][i][j] = i ? i : j;
  75. /* overwrite */
  76. gfx.lut_prio[2][i][j] = j ? j : i;
  77. /* invalid */
  78. gfx.lut_prio[3][i][j] = i;
  79. }
  80. }
  81. /* Initialize cell lookup table */
  82. /* table entry = yyxxshrr (8 bits) */
  83. /* with: yy = cell row (0-3) */
  84. /* xx = cell column (0-3) */
  85. /* s = stamp size (0=16x16, 1=32x32) */
  86. /* hrr = HFLIP & ROTATION bits */
  87. for (i=0; i<0x100; i++)
  88. {
  89. /* one stamp = 2x2 cells (16x16) or 4x4 cells (32x32) */
  90. mask = (i & 8) ? 3 : 1;
  91. row = (i >> 6) & mask;
  92. col = (i >> 4) & mask;
  93. if (i & 4) { col = col ^ mask; } /* HFLIP (always first) */
  94. if (i & 2) { col = col ^ mask; row = row ^ mask; } /* ROLL1 */
  95. if (i & 1) { temp = col; col = row ^ mask; row = temp; } /* ROLL0 */
  96. /* cell offset (0-3 or 0-15) */
  97. gfx.lut_cell[i] = row + col * (mask + 1);
  98. }
  99. /* Initialize pixel lookup table */
  100. /* table entry = yyyxxxhrr (9 bits) */
  101. /* with: yyy = pixel row (0-7) */
  102. /* xxx = pixel column (0-7) */
  103. /* hrr = HFLIP & ROTATION bits */
  104. for (i=0; i<0x200; i++)
  105. {
  106. /* one cell = 8x8 pixels */
  107. row = (i >> 6) & 7;
  108. col = (i >> 3) & 7;
  109. if (i & 4) { col = col ^ 7; } /* HFLIP (always first) */
  110. if (i & 2) { col = col ^ 7; row = row ^ 7; } /* ROLL1 */
  111. if (i & 1) { temp = col; col = row ^ 7; row = temp; } /* ROLL0 */
  112. /* pixel offset (0-63) */
  113. gfx.lut_pixel[i] = col + row * 8;
  114. }
  115. }
  116. int gfx_context_save(uint8 *state)
  117. {
  118. uint32 tmp32;
  119. int bufferptr = 0;
  120. //save_param(&gfx.cycles, sizeof(gfx.cycles));
  121. //save_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
  122. save_param(&gfx.dotMask, sizeof(gfx.dotMask));
  123. save_param(&gfx.stampShift, sizeof(gfx.stampShift));
  124. save_param(&gfx.mapShift, sizeof(gfx.mapShift));
  125. save_param(&gfx.bufferOffset, sizeof(gfx.bufferOffset));
  126. save_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
  127. tmp32 = (uint8 *)(gfx.tracePtr) - Pico_mcd->word_ram2M;
  128. save_param(&tmp32, 4);
  129. tmp32 = (uint8 *)(gfx.mapPtr) - Pico_mcd->word_ram2M;
  130. save_param(&tmp32, 4);
  131. save_param(&gfx.y_step, sizeof(gfx.y_step));
  132. return bufferptr;
  133. }
  134. int gfx_context_load(const uint8 *state)
  135. {
  136. uint32 tmp32;
  137. int bufferptr = 0;
  138. //load_param(&gfx.cycles, sizeof(gfx.cycles));
  139. //load_param(&gfx.cyclesPerLine, sizeof(gfx.cyclesPerLine));
  140. load_param(&gfx.dotMask, sizeof(gfx.dotMask));
  141. load_param(&gfx.stampShift, sizeof(gfx.stampShift));
  142. load_param(&gfx.mapShift, sizeof(gfx.mapShift));
  143. load_param(&gfx.bufferOffset, sizeof(gfx.bufferOffset));
  144. load_param(&gfx.bufferStart, sizeof(gfx.bufferStart));
  145. load_param(&tmp32, 4);
  146. gfx.tracePtr = (uint16 *)(Pico_mcd->word_ram2M + tmp32);
  147. load_param(&tmp32, 4);
  148. gfx.mapPtr = (uint16 *)(Pico_mcd->word_ram2M + tmp32);
  149. load_param(&gfx.y_step, sizeof(gfx.y_step));
  150. return bufferptr;
  151. }
  152. static void gfx_render(uint32 bufferIndex, uint32 width)
  153. {
  154. uint8 pixel_in, pixel_out;
  155. uint16 stamp_data;
  156. uint32 stamp_index;
  157. uint32 priority;
  158. /* pixel map start position for current line (13.3 format converted to 13.11) */
  159. uint32 xpos = *gfx.tracePtr++ << 8;
  160. uint32 ypos = *gfx.tracePtr++ << 8;
  161. /* pixel map offset values for current line (5.11 format) */
  162. uint32 xoffset = (int16) *gfx.tracePtr++;
  163. uint32 yoffset = (int16) *gfx.tracePtr++;
  164. priority = (Pico_mcd->s68k_regs[2] << 8) | Pico_mcd->s68k_regs[3];
  165. priority = (priority >> 3) & 0x03;
  166. /* process all dots */
  167. while (width--)
  168. {
  169. /* check if stamp map is repeated */
  170. if (Pico_mcd->s68k_regs[0x58+1] & 0x01)
  171. {
  172. /* stamp map range */
  173. xpos &= gfx.dotMask;
  174. ypos &= gfx.dotMask;
  175. }
  176. else
  177. {
  178. /* 24-bit range */
  179. xpos &= 0xffffff;
  180. ypos &= 0xffffff;
  181. }
  182. /* check if pixel is outside stamp map */
  183. if ((xpos | ypos) & ~gfx.dotMask)
  184. {
  185. /* force pixel output to 0 */
  186. pixel_out = 0x00;
  187. }
  188. else
  189. {
  190. /* read stamp map table data */
  191. stamp_data = gfx.mapPtr[(xpos >> gfx.stampShift) | ((ypos >> gfx.stampShift) << gfx.mapShift)];
  192. /* stamp generator base index */
  193. /* sss ssssssss ccyyyxxx (16x16) or sss sssssscc ccyyyxxx (32x32) */
  194. /* with: s = stamp number (1 stamp = 16x16 or 32x32 pixels) */
  195. /* c = cell offset (0-3 for 16x16, 0-15 for 32x32) */
  196. /* yyy = line offset (0-7) */
  197. /* xxx = pixel offset (0-7) */
  198. stamp_index = (stamp_data & 0x7ff) << 8;
  199. if (stamp_index)
  200. {
  201. /* extract HFLIP & ROTATION bits */
  202. stamp_data = (stamp_data >> 13) & 7;
  203. /* cell offset (0-3 or 0-15) */
  204. /* table entry = yyxxshrr (8 bits) */
  205. /* with: yy = cell row (0-3) = (ypos >> (11 + 3)) & 3 */
  206. /* xx = cell column (0-3) = (xpos >> (11 + 3)) & 3 */
  207. /* s = stamp size (0=16x16, 1=32x32) */
  208. /* hrr = HFLIP & ROTATION bits */
  209. stamp_index |= gfx.lut_cell[
  210. stamp_data | ((Pico_mcd->s68k_regs[0x58+1] & 0x02) << 2 )
  211. | ((ypos >> 8) & 0xc0) | ((xpos >> 10) & 0x30)] << 6;
  212. /* pixel offset (0-63) */
  213. /* table entry = yyyxxxhrr (9 bits) */
  214. /* with: yyy = pixel row (0-7) = (ypos >> 11) & 7 */
  215. /* xxx = pixel column (0-7) = (xpos >> 11) & 7 */
  216. /* hrr = HFLIP & ROTATION bits */
  217. stamp_index |= gfx.lut_pixel[stamp_data | ((xpos >> 8) & 0x38) | ((ypos >> 5) & 0x1c0)];
  218. /* read pixel pair (2 pixels/byte) */
  219. pixel_out = READ_BYTE(Pico_mcd->word_ram2M, stamp_index >> 1);
  220. /* extract left or rigth pixel */
  221. if (stamp_index & 1)
  222. {
  223. pixel_out &= 0x0f;
  224. }
  225. else
  226. {
  227. pixel_out >>= 4;
  228. }
  229. }
  230. else
  231. {
  232. /* stamp 0 is not used: force pixel output to 0 */
  233. pixel_out = 0x00;
  234. }
  235. }
  236. /* read out paired pixel data */
  237. pixel_in = READ_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1);
  238. /* update left or rigth pixel */
  239. if (bufferIndex & 1)
  240. {
  241. /* priority mode write */
  242. pixel_out = gfx.lut_prio[priority][pixel_in & 0x0f][pixel_out];
  243. pixel_out |= (pixel_in & 0xf0);
  244. }
  245. else
  246. {
  247. /* priority mode write */
  248. pixel_out = gfx.lut_prio[priority][pixel_in >> 4][pixel_out];
  249. pixel_out = (pixel_out << 4) | (pixel_in & 0x0f);
  250. }
  251. /* write data to image buffer */
  252. WRITE_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1, pixel_out);
  253. /* check current pixel position */
  254. if ((bufferIndex & 7) != 7)
  255. {
  256. /* next pixel */
  257. bufferIndex++;
  258. }
  259. else
  260. {
  261. /* next cell: increment image buffer offset by one column (minus 7 pixels) */
  262. bufferIndex += gfx.bufferOffset;
  263. }
  264. /* increment pixel position */
  265. xpos += xoffset;
  266. ypos += yoffset;
  267. }
  268. }
  269. void gfx_start(uint32 base)
  270. {
  271. /* make sure 2M mode is enabled */
  272. if (!(Pico_mcd->s68k_regs[3] & 0x04))
  273. {
  274. uint32 mask = 0;
  275. uint32 reg;
  276. /* trace vector pointer */
  277. gfx.tracePtr = (uint16 *)(Pico_mcd->word_ram2M + ((base << 2) & 0x3fff8));
  278. /* stamps & stamp map size */
  279. switch ((Pico_mcd->s68k_regs[0x58+1] >> 1) & 0x03)
  280. {
  281. case 0:
  282. gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
  283. gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
  284. gfx.mapShift = 4; /* 16x16 stamps/map */
  285. mask = 0x3fe00; /* 512 bytes/table */
  286. break;
  287. case 1:
  288. gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
  289. gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
  290. gfx.mapShift = 3; /* 8x8 stamps/map */
  291. mask = 0x3ff80; /* 128 bytes/table */
  292. break;
  293. case 2:
  294. gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
  295. gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
  296. gfx.mapShift = 8; /* 256x256 stamps/map */
  297. mask = 0x20000; /* 131072 bytes/table */
  298. break;
  299. case 3:
  300. gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
  301. gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
  302. gfx.mapShift = 7; /* 128x128 stamps/map */
  303. mask = 0x38000; /* 32768 bytes/table */
  304. break;
  305. }
  306. /* stamp map table base address */
  307. reg = (Pico_mcd->s68k_regs[0x5a] << 8) | Pico_mcd->s68k_regs[0x5b];
  308. gfx.mapPtr = (uint16 *)(Pico_mcd->word_ram2M + ((reg << 2) & mask));
  309. /* image buffer column offset (64 pixels/cell, minus 7 pixels to restart at cell beginning) */
  310. gfx.bufferOffset = (((Pico_mcd->s68k_regs[0x5c+1] & 0x1f) + 1) << 6) - 7;
  311. /* image buffer start index in dot units (2 pixels/byte) */
  312. reg = (Pico_mcd->s68k_regs[0x5e] << 8) | Pico_mcd->s68k_regs[0x5f];
  313. gfx.bufferStart = (reg << 3) & 0x7ffc0;
  314. /* add image buffer horizontal dot offset */
  315. gfx.bufferStart += (Pico_mcd->s68k_regs[0x60+1] & 0x3f);
  316. /* reset GFX chip cycle counter */
  317. //gfx.cycles = cycles;
  318. /* update GFX chip timings (see AC3:Thunderhawk / Thunderstrike) */
  319. //gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
  320. /* start graphics operation */
  321. Pico_mcd->s68k_regs[0x58] = 0x80;
  322. gfx_schedule();
  323. }
  324. }
  325. /* PicoDrive specific */
  326. #define UPDATE_CYCLES 20000
  327. static void gfx_schedule(void)
  328. {
  329. int w, h, cycles;
  330. int y_step;
  331. w = (Pico_mcd->s68k_regs[0x62] << 8) | Pico_mcd->s68k_regs[0x63];
  332. h = (Pico_mcd->s68k_regs[0x64] << 8) | Pico_mcd->s68k_regs[0x65];
  333. cycles = 5 * w * h;
  334. if (cycles > UPDATE_CYCLES)
  335. y_step = (UPDATE_CYCLES + 5 * w - 1) / (5 * w);
  336. else
  337. y_step = h;
  338. gfx.y_step = y_step;
  339. pcd_event_schedule_s68k(PCD_EVENT_GFX, 5 * w * y_step);
  340. }
  341. void gfx_update(unsigned int cycles)
  342. {
  343. int lines, lines_reg;
  344. int w;
  345. if (!(Pico_mcd->s68k_regs[0x58] & 0x80))
  346. return;
  347. w = (Pico_mcd->s68k_regs[0x62] << 8) | Pico_mcd->s68k_regs[0x63];
  348. lines = (Pico_mcd->s68k_regs[0x64] << 8) | Pico_mcd->s68k_regs[0x65];
  349. lines_reg = lines - gfx.y_step;
  350. if (lines_reg <= 0) {
  351. Pico_mcd->s68k_regs[0x58] = 0;
  352. Pico_mcd->s68k_regs[0x64] =
  353. Pico_mcd->s68k_regs[0x65] = 0;
  354. if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
  355. elprintf(EL_INTS|EL_CD, "s68k: gfx_cd irq 1");
  356. pcd_irq_s68k(1, 1);
  357. }
  358. }
  359. else {
  360. Pico_mcd->s68k_regs[0x64] = lines_reg >> 8;
  361. Pico_mcd->s68k_regs[0x65] = lines_reg;
  362. if (lines > gfx.y_step)
  363. lines = gfx.y_step;
  364. pcd_event_schedule(cycles, PCD_EVENT_GFX, 5 * w * lines);
  365. }
  366. if (PicoIn.opt & POPT_EN_MCD_GFX)
  367. {
  368. /* render lines */
  369. while (lines--)
  370. {
  371. /* process dots to image buffer */
  372. gfx_render(gfx.bufferStart, w);
  373. /* increment image buffer start index for next line (8 pixels/line) */
  374. gfx.bufferStart += 8;
  375. }
  376. }
  377. }
  378. // vim:shiftwidth=2:ts=2:expandtab