GD.cpp 9.6 KB

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