gbufToLCD_speed.z80 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. #define lcd_delay() ex (sp),hl \ ex (sp),hl
  2. GraphToLCD_:
  3. ld hl,(BufPtr)
  4. ld ix,(GrayBufPtr)
  5. BufferToLCD_:
  6. ;Input:
  7. ; HL points to the buffer to copy to the LCD
  8. ; IX points to a secondary buffer to use in grayscale
  9. ; (graymask) has the gray mask
  10. ; (graymask+1) is the method
  11. ; expects the LCD to be in X-increment mode
  12. ; (If you don't know what this means, you probably don't have to worry!)
  13. ;Outputs:
  14. ; HL is incremented by 12
  15. ; DE is incremented by 12
  16. ;Destroys:
  17. ; AF,BC,IX
  18. ; This might change in the future, but A and C are the gray mask, B is 0,
  19. ; and IX points to the routine that mixes the pixels from two layers
  20. ; Don't want interrupts interfering
  21. di
  22. ; Expect that the LCD increment mode is already set to increment down
  23. ;
  24. ; We shouldn't need a delay here!
  25. ; in a,(16) \ rla \ jr c,$-3
  26. ; Set the LCD pointer to the top row
  27. ld a,$80
  28. out (16),a
  29. lcd_delay() ;new calcs seem to ignore the LCD busy bit
  30. ;we'll need to increment HL by 12 each iteration anyways, so may as well make
  31. ;DE useful
  32. ld de,12
  33. ld a,(graymode)
  34. or a
  35. jr z,gray2
  36. dec a
  37. jp z,gray3
  38. dec a
  39. jp z,gray4
  40. sub 14
  41. jp z,LCD_buf_OR
  42. dec a
  43. jp z,mask_buffer_to_LCD
  44. gray2:
  45. ld c,16
  46. ; Set the LCD pointer to the left-most column of 8 pixels
  47. ld a,$20
  48. gray2_col:
  49. lcd_delay() ;new calcs seem to ignore the LCD busy bit
  50. ;Wait for the LCD to be ready for new data
  51. in f,(c) \ jp m,$-2
  52. ;Set the column
  53. out (10h),a
  54. ;Save the column number
  55. push af
  56. ;Set B to 64, we'll be writing a whole column, so 64 writes.
  57. ld b,64
  58. _:
  59. ;Now wait for the LCD to be ready
  60. ld a,(hl)
  61. add hl,de
  62. bit InvertLCDFlag,(iy+userflags)
  63. jr z,$+3
  64. cpl
  65. in f,(c) \ jp m,$-2
  66. out (17),a
  67. djnz -_
  68. dec h
  69. dec h
  70. dec h
  71. inc hl
  72. ;Restore A to the column number, then increment. If it hits $2C, we've drawn all
  73. ;12 columns, so no more looping. Otherwise, draw the next column.
  74. pop af
  75. inc a
  76. cp $2C
  77. jp nz,gray2_col
  78. ret
  79. gray3:
  80. ;We have to wait for the LCD anyways, so may as well do something useful.
  81. ;Get the gray mask and put it in C
  82. ld a,(graymask)
  83. ld c,a
  84. ;Wait for the LCD to be ready for new data
  85. in a,(16) \ rla \ jr c,$-3
  86. ; Set the LCD pointer to the left-most column of 8 pixels
  87. ld a,$20
  88. gray3_col:
  89. ;Set the column
  90. out (10h),a
  91. ;Save the column number
  92. push af
  93. ;Set B to 64, we'll be writing a whole column, so 64 writes.
  94. ld b,64
  95. _:
  96. ;Toggles the mask between %10101010 and %01010101.
  97. rlc c
  98. ;Now wait for the LCD to be ready
  99. in a,(16) \ rla \ jr c,$-3
  100. ; Now we use C to select pixels from either (IX), or (HL).
  101. ; If a bit in C is 0, the corresponding bit in the output is from (HL),
  102. ; else it is from (IX). There is an explaination of this at the bottom.
  103. ld a,(ix)
  104. xor (hl)
  105. and c
  106. xor (hl)
  107. add hl,de
  108. add ix,de
  109. bit InvertLCDFlag,(iy+userflags)
  110. jr z,$+3
  111. cpl
  112. out (17),a
  113. djnz -_
  114. ;Now point to HL to the start of the next column.
  115. ;If we subtract 768, it is where it started, so we'd need to increment 1 more.
  116. ;Basically, HL-(3*256)+1
  117. dec h
  118. dec h
  119. dec h
  120. inc hl
  121. ;Same with IX
  122. dec ixh
  123. dec ixh
  124. dec ixh
  125. inc ix
  126. ;Now wait for the LCD to be ready
  127. in a,(16) \ rla \ jr c,$-3
  128. ;Restore A to the column number, then increment. If it hits $2C, we've drawn all
  129. ;12 columns, so no more looping. Otherwise, draw the next column.
  130. pop af
  131. inc a
  132. cp $2C
  133. jp nz,gray3_col
  134. ;Rotate the mask one final time. Our masks are either 2- or 3-cycles, and we
  135. ;want to avoid a static image if possible!
  136. ld a,c
  137. rlca
  138. ld (graymask),a
  139. ret
  140. gray4:
  141. ;We have to wait for the LCD anyways, so may as well do something useful.
  142. ;Get the gray mask and put it in C
  143. ld a,(graymask)
  144. ld c,a
  145. ;Wait for the LCD to be ready for new data
  146. in a,(16) \ rla \ jr c,$-3
  147. ; Set the LCD pointer to the left-most column of 8 pixels
  148. ld a,$20
  149. gray4_col:
  150. ;Set the column
  151. out (10h),a
  152. ;Save the column number
  153. push af
  154. ;Set B to 64, we'll be writing a whole column, so 64 writes.
  155. ld b,64
  156. _:
  157. ;Now wait for the LCD to be ready
  158. in a,(16) \ rla \ jr c,$-3
  159. ld a,c ;\
  160. cp $C0 ; | Rotate the graymask
  161. rra ; | Can be efficiently done by rotating left while
  162. ld c,a ;/ shifting in the XOR of the top two bits.
  163. ; Now we use C to select pixels from either (IX), or (HL).
  164. ; If a bit in C is 0, the corresponding bit in the output is from (HL),
  165. ; else it is from (IX). There is an explaination of this at the end.
  166. ld a,(ix)
  167. xor (hl)
  168. and c
  169. xor (hl)
  170. add hl,de
  171. add ix,de
  172. bit InvertLCDFlag,(iy+userflags)
  173. jr z,$+3
  174. cpl
  175. out (17),a
  176. djnz -_
  177. ;Now point to HL to the start of the next column.
  178. ;If we subtract 768, it is where it started, so we'd need to increment 1 more.
  179. ;Basically, HL-(3*256)+1
  180. dec h
  181. dec h
  182. dec h
  183. inc hl
  184. ;Same with IX
  185. dec ixh
  186. dec ixh
  187. dec ixh
  188. inc ix
  189. ;Now wait for the LCD to be ready
  190. in a,(16) \ rla \ jr c,$-3
  191. ;Restore A to the column number, then increment. If it hits $2C, we've drawn all
  192. ;12 columns, so no more looping. Otherwise, draw the next column.
  193. pop af
  194. inc a
  195. cp $2C
  196. jp nz,gray4_col
  197. ;Rotate the mask one final time. Our masks are either 2- or 3-cycles, and we
  198. ;want to avoid a static image if possible!
  199. ld a,c
  200. cp $C0
  201. rra
  202. ld (graymask),a
  203. ret
  204. LCD_buf_OR:
  205. ld c,16
  206. ; Set the LCD pointer to the left-most column of 8 pixels
  207. ld a,$20
  208. LCD_buf_OR_col:
  209. ;Wait for the LCD to be ready for new data
  210. in f,(c) \ jp m,$-2
  211. ;Set the column
  212. out (10h),a
  213. ;Save the column number
  214. push af
  215. ;Set B to 64, we'll be writing a whole column, so 64 writes.
  216. ld b,64
  217. _:
  218. ;Now wait for the LCD to be ready
  219. ld a,(hl)
  220. or (ix)
  221. add hl,de
  222. add ix,de
  223. bit InvertLCDFlag,(iy+userflags)
  224. jr z,$+3
  225. cpl
  226. in f,(c) \ jp m,$-2
  227. out (17),a
  228. djnz -_
  229. dec h
  230. dec h
  231. dec h
  232. inc hl
  233. dec ixh
  234. dec ixh
  235. dec ixh
  236. inc ix
  237. in f,(c) \ jp m,$-2
  238. ;Restore A to the column number, then increment. If it hits $2C, we've drawn all
  239. ;12 columns, so no more looping. Otherwise, draw the next column.
  240. pop af
  241. inc a
  242. cp $2C
  243. jp nz,LCD_buf_OR_col
  244. ret
  245. mask_buffer_to_LCD:
  246. ;This will AND the secondary buf on to the tilemap_buf, then OR the primary buf
  247. ;on to that.
  248. ld de,(tilemap_buf)
  249. ; Expect that the LCD increment mode is already set to increment down
  250. ;
  251. ; We shouldn't need a delay here!
  252. ; in a,(16) \ rla \ jr c,$-3
  253. ; ; Set the LCD pointer to the top row
  254. ; ld a,$80
  255. ; out (16),a
  256. ;Wait for the LCD to be ready for new data
  257. in a,(16) \ rla \ jr c,$-3
  258. ; Set the LCD pointer to the left-most column of 8 pixels
  259. ld a,$20
  260. maskcol:
  261. ;Set the column
  262. out (10h),a
  263. ;Save the column number
  264. push af
  265. ;Set B to 64, we'll be writing a whole column, so 64 writes.
  266. ld bc,$400C
  267. _:
  268. push bc
  269. ld a,(de)
  270. and (ix)
  271. xor (hl)
  272. bit InvertLCDFlag,(iy+userflags)
  273. jr z,$+3
  274. cpl
  275. push af
  276. ld b,0
  277. add hl,bc
  278. ex de,hl
  279. add hl,bc
  280. ex de,hl
  281. add ix,bc
  282. ;Now wait for the LCD to be ready
  283. in a,(16) \ rla \ jr c,$-3
  284. pop af
  285. out (17),a
  286. pop bc
  287. djnz -_
  288. ;Now point to HL to the start of the next column.
  289. ;If we subtract 768, it is where it started, so we'd need to increment 1 more.
  290. ;Basically, HL-(3*256)+1
  291. dec h
  292. dec h
  293. dec h
  294. inc hl
  295. ;Same with DE
  296. dec d
  297. dec d
  298. dec d
  299. inc de
  300. ;Same with IX
  301. dec ixh
  302. dec ixh
  303. dec ixh
  304. inc ix
  305. ;Restore A to the column number, then increment. If it hits $2C, we've drawn all
  306. ;12 columns, so no more looping. Otherwise, draw the next column.
  307. pop af
  308. inc a
  309. cp $2C
  310. jp nz,maskcol
  311. ret
  312. ; How C can select from two different buffers
  313. ;
  314. ;
  315. ;We'll use this magical formula:
  316. ; ((x^y)&m)^y
  317. ;
  318. ;When m is 0:
  319. ; ((x^y)&m)^y
  320. ; = ((x^y)&0)^y
  321. ; = (0)^y
  322. ; = y
  323. ;
  324. ;When m is 1:
  325. ; ((x^y)&m)^y
  326. ; = ((x^y)&1)^y
  327. ; = (x^y)^y
  328. ; = x^(y^y) ;We can do this when all operations are XOR
  329. ; = x
  330. ;
  331. ;So a 0 in the mask will choose the pixel from (HL) (primary buffer),
  332. ;and a 1 will choose a pixel from (IX) (gray/back/secondary buffer).