GD.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. * Copyright (c) 2011 by James Bowman <jamesb@excamera.com>
  3. * Gameduino library for arduino.
  4. *
  5. */
  6. #ifdef BOARD_maple
  7. #include "wirish.h"
  8. HardwareSPI SPI(1);
  9. #include "GD.h"
  10. #else
  11. #include "Arduino.h"
  12. #include <avr/pgmspace.h>
  13. #include <SPI.h>
  14. #include <GD.h>
  15. #endif
  16. static byte GD_SEL_PIN;
  17. GDClass GD;
  18. void GDClass::begin(int pin)
  19. {
  20. delay(250); // give Gameduino time to boot
  21. GD_SEL_PIN = pin;
  22. pinMode(GD_SEL_PIN, OUTPUT);
  23. #ifdef BOARD_maple
  24. SPI.begin(SPI_4_5MHZ, MSBFIRST, 0);
  25. #else
  26. SPI.begin();
  27. SPI.setClockDivider(SPI_CLOCK_DIV2);
  28. SPI.setBitOrder(MSBFIRST);
  29. SPI.setDataMode(SPI_MODE0);
  30. SPSR = (1 << SPI2X);
  31. #endif
  32. digitalWrite(GD_SEL_PIN, HIGH);
  33. GD.wr(J1_RESET, 1); // HALT coprocessor
  34. __wstart(RAM_SPR); // Hide all sprites
  35. for (int i = 0; i < 512; i++)
  36. GD.xhide();
  37. __end();
  38. fill(RAM_PIC, 0, 1024 * 10); // Zero all character RAM
  39. fill(RAM_SPRPAL, 0, 2048); // Sprite palletes black
  40. fill(RAM_SPRIMG, 0, 64 * 256); // Clear all sprite data
  41. fill(VOICES, 0, 256); // Silence
  42. fill(PALETTE16A, 0, 128); // Black 16-, 4-palletes and COMM
  43. GD.wr16(SCROLL_X, 0);
  44. GD.wr16(SCROLL_Y, 0);
  45. GD.wr(JK_MODE, 0);
  46. GD.wr(SPR_DISABLE, 0);
  47. GD.wr(SPR_PAGE, 0);
  48. GD.wr(IOMODE, 0);
  49. GD.wr16(BG_COLOR, 0);
  50. GD.wr16(SAMPLE_L, 0);
  51. GD.wr16(SAMPLE_R, 0);
  52. GD.wr16(SCREENSHOT_Y, 0);
  53. GD.wr(MODULATOR, 64);
  54. }
  55. void GDClass::end() {
  56. }
  57. void GDClass::__start(unsigned int addr) // start an SPI transaction to addr
  58. {
  59. digitalWrite(GD_SEL_PIN, LOW);
  60. SPI.transfer(highByte(addr));
  61. SPI.transfer(lowByte(addr));
  62. }
  63. void GDClass::__wstart(unsigned int addr) // start an SPI write transaction to addr
  64. {
  65. __start(0x8000|addr);
  66. }
  67. void GDClass::__wstartspr(unsigned int sprnum)
  68. {
  69. __start((0x8000 | RAM_SPR) + (sprnum << 2));
  70. spr = 0;
  71. }
  72. void GDClass::__end() // end the SPI transaction
  73. {
  74. digitalWrite(GD_SEL_PIN, HIGH);
  75. }
  76. byte GDClass::rd(unsigned int addr)
  77. {
  78. __start(addr);
  79. byte r = SPI.transfer(0);
  80. __end();
  81. return r;
  82. }
  83. void GDClass::wr(unsigned int addr, byte v)
  84. {
  85. __wstart(addr);
  86. SPI.transfer(v);
  87. __end();
  88. }
  89. unsigned int GDClass::rd16(unsigned int addr)
  90. {
  91. unsigned int r;
  92. __start(addr);
  93. r = SPI.transfer(0);
  94. r |= (SPI.transfer(0) << 8);
  95. __end();
  96. return r;
  97. }
  98. void GDClass::wr16(unsigned int addr, unsigned int v)
  99. {
  100. __wstart(addr);
  101. SPI.transfer(lowByte(v));
  102. SPI.transfer(highByte(v));
  103. __end();
  104. }
  105. void GDClass::fill(int addr, byte v, unsigned int count)
  106. {
  107. __wstart(addr);
  108. while (count--)
  109. SPI.transfer(v);
  110. __end();
  111. }
  112. void GDClass::copy(unsigned int addr, flash_uint8_t *src, int count)
  113. {
  114. __wstart(addr);
  115. while (count--) {
  116. SPI.transfer(pgm_read_byte_near(src));
  117. src++;
  118. }
  119. __end();
  120. }
  121. #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  122. void GDClass::copy(unsigned int addr, uint_farptr_t src, int count)
  123. {
  124. __wstart(addr);
  125. while (count--) {
  126. SPI.transfer(pgm_read_byte_far(src));
  127. src++;
  128. }
  129. __end();
  130. }
  131. #endif
  132. void GDClass::microcode(flash_uint8_t *src, int count)
  133. {
  134. wr(J1_RESET, 1);
  135. copy(J1_CODE, src, count);
  136. wr(J1_RESET, 0);
  137. }
  138. #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  139. void GDClass::microcode(uint_farptr_t src, int count)
  140. {
  141. wr(J1_RESET, 1);
  142. copy(J1_CODE, src, count);
  143. wr(J1_RESET, 0);
  144. }
  145. #endif
  146. void GDClass::setpal(int pal, unsigned int rgb)
  147. {
  148. wr16(RAM_PAL + (pal << 1), rgb);
  149. }
  150. void GDClass::sprite(int spr, int x, int y, byte image, byte palette, byte rot, byte jk)
  151. {
  152. __wstart(RAM_SPR + (spr << 2));
  153. SPI.transfer(lowByte(x));
  154. SPI.transfer((palette << 4) | (rot << 1) | (highByte(x) & 1));
  155. SPI.transfer(lowByte(y));
  156. SPI.transfer((jk << 7) | (image << 1) | (highByte(y) & 1));
  157. __end();
  158. }
  159. void GDClass::xsprite(int ox, int oy, char x, char y, byte image, byte palette, byte rot, byte jk)
  160. {
  161. if (rot & 2)
  162. x = -16-x;
  163. if (rot & 4)
  164. y = -16-y;
  165. if (rot & 1) {
  166. int s;
  167. s = x; x = y; y = s;
  168. }
  169. ox += x;
  170. oy += y;
  171. SPI.transfer(lowByte(ox));
  172. SPI.transfer((palette << 4) | (rot << 1) | (highByte(ox) & 1));
  173. SPI.transfer(lowByte(oy));
  174. SPI.transfer((jk << 7) | (image << 1) | (highByte(oy) & 1));
  175. spr++;
  176. }
  177. void GDClass::xhide()
  178. {
  179. SPI.transfer(lowByte(400));
  180. SPI.transfer(highByte(400));
  181. SPI.transfer(lowByte(400));
  182. SPI.transfer(highByte(400));
  183. spr++;
  184. }
  185. void GDClass::plots(int ox, int oy, const PROGMEM sprplot *psp, byte count, byte rot, byte jk)
  186. {
  187. while (count--) {
  188. struct sprplot sp;
  189. memcpy_P((void*)&sp, psp++, sizeof(sp));
  190. GD.xsprite(ox, oy, sp.x, sp.y, sp.image, sp.palette, rot, jk);
  191. }
  192. }
  193. void GDClass::sprite2x2(int spr, int x, int y, byte image, byte palette, byte rot, byte jk)
  194. {
  195. __wstart(0x3000 + (spr << 2));
  196. GD.xsprite(x, y, -16, -16, image + 0, palette, rot, jk);
  197. GD.xsprite(x, y, 0, -16, image + 1, palette, rot, jk);
  198. GD.xsprite(x, y, -16, 0, image + 2, palette, rot, jk);
  199. GD.xsprite(x, y, 0, 0, image + 3, palette, rot, jk);
  200. __end();
  201. }
  202. void GDClass::waitvblank()
  203. {
  204. // Wait for the VLANK to go from 0 to 1: this is the start
  205. // of the vertical blanking interval.
  206. while (rd(VBLANK) == 1)
  207. ;
  208. while (rd(VBLANK) == 0)
  209. ;
  210. }
  211. /* Fixed ascii font, useful for debug */
  212. #include "font8x8.h"
  213. static byte stretch[16] = {
  214. 0x00, 0x03, 0x0c, 0x0f,
  215. 0x30, 0x33, 0x3c, 0x3f,
  216. 0xc0, 0xc3, 0xcc, 0xcf,
  217. 0xf0, 0xf3, 0xfc, 0xff
  218. };
  219. void GDClass::ascii()
  220. {
  221. long i;
  222. for (i = 0; i < 768; i++) {
  223. #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  224. byte b = pgm_read_byte_far(GET_FAR_ADDRESS(font8x8) + i);
  225. #else
  226. byte b = pgm_read_byte(font8x8 + i);
  227. #endif
  228. byte h = stretch[b >> 4];
  229. byte l = stretch[b & 0xf];
  230. GD.wr(0x1000 + (16 * ' ') + (2 * i), h);
  231. GD.wr(0x1000 + (16 * ' ') + (2 * i) + 1, l);
  232. }
  233. for (i = 0x20; i < 0x80; i++) {
  234. GD.setpal(4 * i + 0, TRANSPARENT);
  235. GD.setpal(4 * i + 3, RGB(255,255,255));
  236. }
  237. GD.fill(RAM_PIC, ' ', 4096);
  238. }
  239. void GDClass::putstr(int x, int y, const char *s)
  240. {
  241. GD.__wstart((y << 6) + x);
  242. while (*s)
  243. SPI.transfer(*s++);
  244. GD.__end();
  245. }
  246. void GDClass::voice(int v, byte wave, unsigned int freq, byte lamp, byte ramp)
  247. {
  248. __wstart(VOICES + (v << 2));
  249. SPI.transfer(lowByte(freq));
  250. SPI.transfer(highByte(freq) | (wave << 7));
  251. SPI.transfer(lamp);
  252. SPI.transfer(ramp);
  253. __end();
  254. }
  255. void GDClass::screenshot(unsigned int frame)
  256. {
  257. int yy, xx;
  258. byte undone[38]; // 300-long bitmap of lines pending
  259. // initialize to 300 ones
  260. memset(undone, 0xff, 37);
  261. undone[37] = 0xf;
  262. int nundone = 300;
  263. Serial.write(0xa5); // sync byte
  264. Serial.write(lowByte(frame));
  265. Serial.write(highByte(frame));
  266. while (nundone) {
  267. // find a pending line a short distance ahead of the raster
  268. int hwline = GD.rd16(SCREENSHOT_Y) & 0x1ff;
  269. for (yy = (hwline + 7) % 300; ((undone[yy>>3] >> (yy&7)) & 1) == 0; yy = (yy + 1) % 300)
  270. ;
  271. GD.wr16(SCREENSHOT_Y, 0x8000 | yy); // ask for it
  272. // housekeeping while waiting: mark line done and send yy
  273. undone[yy>>3] ^= (1 << (yy&7));
  274. nundone--;
  275. Serial.write(lowByte(yy));
  276. Serial.write(highByte(yy));
  277. while ((GD.rd(SCREENSHOT_Y + 1) & 0x80) == 0)
  278. ;
  279. // Now send the line, compressing zero pixels
  280. uint16_t zeroes = 0;
  281. for (xx = 0; xx < 800; xx += 2) {
  282. uint16_t v = GD.rd16(SCREENSHOT + xx);
  283. if (v == 0) {
  284. zeroes++;
  285. } else {
  286. if (zeroes) {
  287. Serial.write(lowByte(zeroes));
  288. Serial.write(0x80 | highByte(zeroes));
  289. zeroes = 0;
  290. }
  291. Serial.write(lowByte(v));
  292. Serial.write(highByte(v));
  293. }
  294. }
  295. if (zeroes) {
  296. Serial.write(lowByte(zeroes));
  297. Serial.write(0x80 | highByte(zeroes));
  298. }
  299. }
  300. GD.wr16(SCREENSHOT_Y, 0); // restore screen to normal
  301. }
  302. // near ptr version
  303. class GDflashbits {
  304. public:
  305. void begin(flash_uint8_t *s) {
  306. src = s;
  307. mask = 0x01;
  308. }
  309. byte get1(void) {
  310. byte r = (pgm_read_byte_near(src) & mask) != 0;
  311. mask <<= 1;
  312. if (!mask) {
  313. mask = 1;
  314. src++;
  315. }
  316. return r;
  317. }
  318. unsigned short getn(byte n) {
  319. unsigned short r = 0;
  320. while (n--) {
  321. r <<= 1;
  322. r |= get1();
  323. }
  324. return r;
  325. }
  326. private:
  327. flash_uint8_t *src;
  328. byte mask;
  329. };
  330. static GDflashbits GDFB;
  331. void GDClass::uncompress(unsigned int addr, flash_uint8_t *src)
  332. {
  333. GDFB.begin(src);
  334. byte b_off = GDFB.getn(4);
  335. byte b_len = GDFB.getn(4);
  336. byte minlen = GDFB.getn(2);
  337. unsigned short items = GDFB.getn(16);
  338. while (items--) {
  339. if (GDFB.get1() == 0) {
  340. GD.wr(addr++, GDFB.getn(8));
  341. } else {
  342. int offset = -GDFB.getn(b_off) - 1;
  343. int l = GDFB.getn(b_len) + minlen;
  344. while (l--) {
  345. GD.wr(addr, GD.rd(addr + offset));
  346. addr++;
  347. }
  348. }
  349. }
  350. }
  351. #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  352. // far ptr version
  353. class GDflashbitsF {
  354. public:
  355. void begin(uint_farptr_t s) {
  356. src = s;
  357. mask = 0x01;
  358. }
  359. byte get1(void) {
  360. byte r = (pgm_read_byte_far(src) & mask) != 0;
  361. mask <<= 1;
  362. if (!mask) {
  363. mask = 1;
  364. src++;
  365. }
  366. return r;
  367. }
  368. unsigned short getn(byte n) {
  369. unsigned short r = 0;
  370. while (n--) {
  371. r <<= 1;
  372. r |= get1();
  373. }
  374. return r;
  375. }
  376. private:
  377. uint_farptr_t src;
  378. byte mask;
  379. };
  380. static GDflashbitsF GDFBF;
  381. void GDClass::uncompress(unsigned int addr, uint_farptr_t src)
  382. {
  383. GDFBF.begin(src);
  384. byte b_off = GDFBF.getn(4);
  385. byte b_len = GDFBF.getn(4);
  386. byte minlen = GDFBF.getn(2);
  387. unsigned short items = GDFBF.getn(16);
  388. while (items--) {
  389. if (GDFBF.get1() == 0) {
  390. GD.wr(addr++, GDFBF.getn(8));
  391. } else {
  392. int offset = -GDFBF.getn(b_off) - 1;
  393. int l = GDFBF.getn(b_len) + minlen;
  394. while (l--) {
  395. GD.wr(addr, GD.rd(addr + offset));
  396. addr++;
  397. }
  398. }
  399. }
  400. }
  401. #endif