Advertisement
Guest User

Untitled

a guest
May 6th, 2013
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.99 KB | None | 0 0
  1.  
  2.  
  3.  
  4. Chapter 3: The Video Hardware
  5. =============================
  6.  
  7.  
  8. VDC
  9. ---
  10.  
  11. Oh boy. Here we go. Where to start? The simplest registers I guess. The VDC has 3 ports mapped to
  12. the hardware bank. The first port is the register select port. Writing to this port selects which
  13. register you want to access. The other two ports are DATA ports. When you select a register, these
  14. ports are what you use to write to those registers. Now, the VDC is a 16bit device and takes 16bit
  15. values for parameters. The first data port is the LSB or lower 8bit and the second data port is the
  16. MSB or the upper 8bit half. The second port also contains the latch. When the second port is written
  17. to, the latch is activated and both 8bit value are paired as a 16bit value and sent to whatever
  18. internal place it's supposed to go in the VDC. Here are the addresses for the ports:
  19.  
  20.  
  21. $0000 = Register select port
  22. $0001 = upper have of the register select port, but the VDC doesn't have that many registers
  23. $0002 = Data port: lower 8bit/LSB
  24. $0003 = Data port: upper 8bit/MSB + latch
  25.  
  26.  
  27. You can safely ignore $0001 as it has no purpose in this revision of the VDC. The VDC is a 16bit
  28. device and can operate in a 16bit data bus mode, but since the main CPU has an 8bit data bus, the
  29. is in split bus mode. Yeah, I made that 'split bus' term up 'cause I don't remember the real name
  30. of the term off hand, so deal with it ;) Anyway, so the data ports are both readable and writeable.
  31. But that doesn't mean you'll actually be able to read the data from every register. Very little
  32. number of registers have read functionality, actually. Let's go down the register list order.
  33.  
  34. Register $00 is the VRAM write pointer register. You need to tell the VDC where in VRAM you want
  35. to write to, so this register needs to be setup first before doing so.
  36.  
  37.  
  38. lda #$00
  39. sta $0000
  40.  
  41. There. Now we have selected the register. Let's assign an address to the pointer.
  42.  
  43. lda #$00
  44. sta $0002
  45. lda #$10
  46. sta $0003
  47.  
  48. We wrote $00 and then $10 for a combined address of $1000. That's great. The vram pointer register
  49. is setup and all ready to go. Now we need to tell the VDC we want to actually read to *write* to
  50. VRAM. We use the $02 register.
  51.  
  52. lda #$02
  53. sta $0000
  54.  
  55. Now we can write to the data ports and it will transfer that content to VRAM. The VDC will also
  56. automatically 'increment' the VRAM pointer for us, so we don't have to keep putting in a new VRAM
  57. address after every write. How thoughtful. Thanks, VDC ;)
  58.  
  59.  
  60. lda #$ff
  61. sta $0002
  62. lda #$ee
  63. sta $0003
  64.  
  65. We wrote our first 'WORD' to vram. Yeah! Feels good, don't it? I bet you have dreams of grandeur
  66. already, don't you? Put those on hold, we've got lots more to cover.
  67.  
  68.  
  69. We setup the vram write pointer and wrote to vram, now let's try and read from vram. The vram read
  70. register is $01.
  71.  
  72.  
  73. lda #$01
  74. sta $0000
  75. lda #$00
  76. sta $0002
  77. lda #$10
  78. sta $0003
  79.  
  80. $01 selected the vram read pointer and we changed it to $1000. Now to select the register to we can
  81. actually read from that address.
  82.  
  83.  
  84. lda #$02
  85. sta $0000
  86.  
  87.  
  88. Now you might be thinking, "Didn't we already use register $02 so we could write to vram?". Correct.
  89. It's the same register if we want to read *or* write vram. You see, reading from the vram interface
  90. register has a separate internal read pointer then writing to it. Register $02 is a read / write
  91. register the interfaces with VRAM. Example:
  92.  
  93.  
  94. lda #$00 ;//select the write pointer register
  95. sta $0000
  96. lda #$00
  97. sta $0002
  98. lda #$10
  99. sta $0003 ;//write $1000 to the pointer
  100. lda #$01 ;//select the read pointer register
  101. sta $0000
  102. lda #$20
  103. sta $0002
  104. lda #$33
  105. sta $0003 ;//write $3320 to the pointer
  106. lda #$02 ;//select vram interface register
  107. sta $0000
  108.  
  109. lda #$ff
  110. sta $0002
  111. lda #$ee
  112. sta $0003 ;//write $eeff to $1000, now write pointer is $1001
  113.  
  114. lda $0002
  115. sta $3f00
  116. lda $0003
  117. sta $3f01 ;//read some 16bit value from $3320, now read pointer is $3321
  118.  
  119.  
  120. The read and write pointers are independent of each other and register $02 is a read/write register.
  121. If you look closely, you'll see that we wrote two bytes but the pointer was only incremented by 1.
  122. Like I said previously, the VDC is a 16bit device. This also means the smallest data element is 16bit
  123. wide. And the address range? It's given in WORDS, not bytes. The VDC might indeed have 64kbyte, but
  124. as far as its concerned, it has 32kwords. Haha.
  125.  
  126. Not bad. We covered 3 registers to far; 00-02. Registers 03 and 04 are reserved so we'll skip past
  127. them. So that leaves us on register 05. Oh, lucky you ;)
  128.  
  129.  
  130. Register $05 is the 'control' register. This is where to you turn on and off the BG layer, the sprite
  131. layer, and all 4 interrupts generated by the VDC. This register isn't as simlple to configure because
  132. we need to set or clear certain bits for these features. This is a write only register, so you'll need
  133. to keep a spare copy of what you wrote in cpu ram.
  134.  
  135. A layout of the CONTROL register:
  136.  
  137. bit 15-13: N/A (set to zero)
  138. bit 12-11: VRAM pointer increment amount
  139.  
  140. 00 = +1 word
  141. 01 = +32 words
  142. 10 = +64 words
  143. 11 = +128 words
  144.  
  145. bit 10-08: Reserved (set to zero)
  146. bit 07: BG enable (1=enable)
  147. bit 06: Sprite enable (1=enable)
  148. bit 03-00: Interrupt flags
  149.  
  150. bit 03: vertical blanking (1=enable)
  151. bit 02: horizontal blanking (1=enable)
  152. bit 01: sprite overflow (1=enable)
  153. bit 00: sprite #0 collision (1=enable)
  154.  
  155.  
  156. Some things are self explanatory like BG and sprite bits. Bits 12-11 set the auto-increment value
  157. for the vram interface register ($02). If enabled, the vertical blanking flag will trigger once the
  158. screen has reached end of active display. Normally this happens 60 times a second, but the VDC allows
  159. you to setup 'multiple screens' within a single frame. If you do, this will trigger more often. That
  160. is not to be confused with Hsync interrupts. The horizontal blanking flag happens at whatever line
  161. you assign it to (with another register). Any scanline can be assigned an hsync interrupt regardless
  162. of the screen status or even if the scanline is *not* in active display. That's definitely a plus.
  163.  
  164. The sprite overflow flag happens, if enabled, when more than 256 sprite pixels are on a *scanline*.
  165. Now, just note that this doesn't mean 'active' scanline. This mean the whole damn thing till the end
  166. of the internal BAT width. Like with other systems, it doesn't matter if the pixels are opaque or not.
  167. Those invisible pixels still count. This interrupt is used for when the program needs to know if there
  168. are too many sprites to be shown on that *scanline*. The program can then shift the order to create
  169. 'flicker'. Flicker is an alternative to *not* seeing the sprites at all. You can see in some games
  170. where the programmers took no measure against this, and the sprites just simply disappear. Definitely
  171. not good when they're small bullets coming straight at you. I'm looking at you, Rtype!
  172.  
  173. Finally, the last flag. The collision flag. An interrupt is generated when an opaque pixel (any
  174. pixel other than color slot 0) collides with any other opaque pixel of any other sprite. This might
  175. sound pretty good. Let me put those hopes to rest right now. One, you have no idea *what* sprite
  176. collided with sprite 0, and second you almost-always-never want a collision box as the same shape
  177. as the sprite. Imagine of the sprite 0 was the player ship. If an enemy or bullet grazes just one
  178. pixel of the outside of the ship? People will be more than angry with you. It has a limited use.
  179.  
  180. Let's see some control register action in... action:
  181.  
  182. lda #$05 ;//select the control register
  183. sta $0000
  184. lda #$c0 ;// enable bits 7 and 8 only
  185. sta $0002
  186. lda #$00
  187. sta $0003
  188.  
  189.  
  190. The sprites and BG tiles are now viewable. I should inform you of something now that we're not
  191. dealing with the vram read/write register(02). Only a few register actually have a latch on the MSB
  192. access. Each 'register' had its own buffer for the data ports. And registers that don't have a latch,
  193. you can freely update just one half if you want. This will become clearer later on (the buffer part).
  194.  
  195.  
  196. Register $06. The RCR reg-ist-er. This is where magic happens. This little register is where you define
  197. which scanline you're going to attach an hsync interrupt to. What's so good about that? Well, for one
  198. thing you can change some VDC registers for that line. You could change the X and Y scroll registers,
  199. the BG or Sprite enable flags for clipping, the horizontal resolution, the palette, etc. All sorts of
  200. stuff. You can also use it to drive a finer resolution timer than the 7khz one. I.e. play some 16khz
  201. samples jitter free ;)
  202.  
  203.  
  204. lda #$06 ;//select the RCR register
  205. sta $0000
  206. lda #$43
  207. sta $0002
  208. lda #$01
  209. sta $0003 ;//write $143 to the register
  210.  
  211.  
  212. Two things to note here. 1) You have to add $40 to the scanline number before writing it to the reg-
  213. ister ports. Scanline 0 starts at $40. If you write something smaller than $40, it will never trigger.
  214. If you write something larger than than what a frame is capable of displaying**, it won't trigger. 2)
  215. If you want to trigger on more than one scanline in a frame, then you need to reupdate the register
  216. with the next scanline number (don't forget the +$40). If you're doing it for *every* scanline, then
  217. you might want to optimize that routine ;) This register has no latch.
  218.  
  219.  
  220.  
  221. Register $07, the BXR register. Sets of the X position of the BAT. The value ranges from 0-1023
  222. regardless of the map size.
  223.  
  224.  
  225. lda #$07 ;//Select the BXR register
  226. sta $0000
  227. lda #$22
  228. sta $0002
  229. lda #$00
  230. sta $0003 ;//Update the BAT X position
  231.  
  232.  
  233. The register is pretty straight foreward. The BXR register has no write latch.
  234.  
  235.  
  236. Register $08, the BYR register. Same as BXR, except it sets the Y position of the BAT. The range is
  237. 0-512.
  238.  
  239.  
  240. lda #$08 ;//Select the BYR register
  241. sta $0000
  242. lda #$22
  243. sta $0002
  244. lda #$00
  245. sta $0003 ;//Update the BAT Y position
  246.  
  247.  
  248. As with the BXR register, this has no write latch. Both registers you can write either the upper port
  249. or the lower port without worrying about a latch system. The VDC reads the contents of the both register
  250. buffers at a specific point every scanline. This only happens once. This eases up timing requirements for
  251. scanline interrupt changes to either regs. But this also means you *can't* do 'column' scrolling. Another
  252. important thing to note, is that changes made on the currently scaline interrupt will take effect on the
  253. *next* scanline. This is true for a lot of register changes. With some registers, the VDC will reread
  254. from register buffer every scanline, and other registers the VDC will read once an 'internal frame'. I say
  255. internal frame because the VDC can have several display frames within a single NTSC frame. It's pretty
  256. non standard game wise, but it's good to know.
  257.  
  258.  
  259. MAWR! No, it's not a sound. It's the Memory Access Width Register. Totally misleading name. This register
  260. (for what we need to know at the moment) only controls the BAT size.
  261.  
  262.  
  263. Bit 15-07: Set to zero
  264. Bit 06-04: BG map size
  265.  
  266. 000 = 32x32
  267. 001 = 64x32
  268. 010 = 128x32
  269. 011 = 128x32
  270. 100 = 32x64
  271. 101 = 64x64
  272. 110 = 128x64
  273. 111 = 128x64
  274.  
  275. Bit 03-00: Set to zero
  276.  
  277.  
  278. Setting the size of the BAT also effects how the BAT format is laid out in vram. In 32 width mode,
  279. you have a row of 32 words before the next row begins. In 64 width mode, you have 64 words per row.
  280. And 128 width for 128 words per row. If you have the BAT formatted as 64x32 in vram, but the MAWR
  281. register is setup for 32x32 BAT size, then you'll see a vertical interleave of both halves of the
  282. map, because it's interpreting the second half of the 64 words as the next row. Like so
  283.  
  284.  
  285. BAT reg set to 32x32 and BAT setup as 64x32:
  286.  
  287. screen output BAT in VRAM
  288. ____________ ________________
  289. | 00000000 | 0000000011111111
  290. | 11111111 | 2222222233333333
  291. | 22222222 | 4444444455555555
  292. | 33333333 | 6666666677777777
  293. ------------
  294.  
  295.  
  296. From the ascii graphics, you can see that the second half of the 64 wide tilemap is being interpreted
  297. as the next row because the BAT was set to the incorrect size. '0' is the first line, but '2' *should*
  298. be the second line, not '1'. Not much more to say about that.
  299.  
  300. If you're clever, you can switch between a 64x32 setting and a 32x32 setting without reformatting the
  301. BAT in vram, if you reposition the BG on the appropriate scanlines but that'll only work for vertical
  302. scrolling. The MAWR register has no latch and is read once per 'VDC' frame.
  303.  
  304.  
  305. These next few registers are for setting up the VDC display frame that's inside the VCE frame (NTSC).
  306. I'm not going to go into much detail about these at this time. I'll give a brief description and the
  307. default values for 256x240 display mode.
  308.  
  309. Register $0A (HSR):
  310.  
  311. Bit 14-08 is the HDS reg. Default is $02
  312. Horizontal active start position (value-1)
  313.  
  314. Bit 04-00 is the HSW reg. Default is $02
  315. Horizontal sync width (value-1)
  316.  
  317. Note: both values represent increments of 8 pixels.
  318.  
  319. Register $0B (HDR):
  320.  
  321. Bit 14-08 is the HDE reg. Default is $03
  322. Horizontal active end position (value-1)
  323.  
  324. Bit 06-00 is the HDW reg. Default is $1f
  325. Horizontal active width (value-1)
  326.  
  327. Note: both values represent increments of 8 pixels.
  328.  
  329.  
  330. Register $0C (VPR):
  331.  
  332. Bit 14-08 is the VDS reg. Default is $0f
  333. Vertical active start position (value-2)
  334.  
  335. Bit 04-00 is the VSW reg. Default is $02
  336. Vertical sync width
  337.  
  338. Note: both values represent increments of 1 pixel.
  339.  
  340.  
  341. Register $0D (VDW):
  342.  
  343. Bit 08-00 is the VDW reg. Default is $ef
  344. Vertical active width (value-1)
  345.  
  346. Note: value represent increments of 1 pixel.
  347.  
  348.  
  349.  
  350. Register $0E (VCR):
  351.  
  352. Bit 07-00 is the VCR reg. Default is $03
  353. Vertical active end position
  354.  
  355. Note: value represent increments of 1 pixel.
  356.  
  357.  
  358. The horizontal registers are updated once per scanline, while the vertical registers are updated
  359. once per VDC frame. The default values given are for a 256x240 window setup. The VDC doesn't define
  360. the output resolution, only the displayable frame within the final output. The VCE handles the
  361. actual resolution settings. A side note, the VDC is capable of creating the display signal all by
  362. itselft, but for the PCE it is setup to work in conjunction with the VCE.
  363.  
  364.  
  365. Now onto the last set of registers. The DMA control registers. These registers, as you guessed it,
  366. control the DMA of the VDC. What does that exactly mean? The VDC has a number of DMA channels, but
  367. only two are available to the interfacer (you). The first is VRAM to VRAM DMA. It copies blocks of
  368. data, in words lengths, to and frow. The second DMA is the SATB DMA. The SATB DMA updates the sprite
  369. attributes. We'll get to more on that near the end of this section.
  370.  
  371. Register $0F (DCR):
  372.  
  373. Bit 15-05: N/A
  374. Bit 04: SATB auto-DMA flag (1=on)
  375. Bit 03: VDMA destination increment flag (1=dec, 0=inc)
  376. Bit 02: VDMA source increment flag (1=dec, 0=inc)
  377. Bit 01: VDMA 'complete' interrupt flag (1=enable)
  378. Bit 00: SATB DMA 'complete' interrupt flag (1=enable)
  379.  
  380.  
  381. Bit 04. When this is set, the VDC will update the sprite attributes every VDC frame. That's why it
  382. has the word 'auto' in there ;)
  383.  
  384. Bit 03. When doing a VRAM to VRAM DMA copy, you can select whether the to increment or decrement
  385. the destination address. Upon every word copy, the desitination address will be updated.
  386.  
  387. Bit 02. Same as above, but this effect the source address.
  388.  
  389. Bit 01. If you enable this flag, the VDC will generate an interrupt when the transfer is complete.
  390.  
  391. Bit 00. Same as above, but for the SATB DMA.
  392.  
  393. Remember the register select port, $0000? We've covered writing to the port to select which register
  394. we wanted to use, but at any time you can read from the port to get the status of the VDC. This is
  395. how you would check which DMA complete flag as set by the VDC. We'll cover that in a littel bit. You
  396. are also probably wondering about the SATB DMA. We'll also go over that shortly.
  397.  
  398.  
  399. Registers $10, $11, and $12 are for the VMDA controller. Register $10 is the source address in VRAM.
  400. Register $11 is the destination address in VRAM. And finally register $12 is the copy legnth. We can
  401. write to registers $10 and $11 as much as we want, but the DMA won't trigger until we write to the
  402. length register.
  403.  
  404.  
  405. lda #$10
  406. sta $0000 ;//select the VDMA source register
  407. lda #$11
  408. sta $0002
  409. lda #$50
  410. sta $0003 ;//change the source address to $5011
  411.  
  412. lda #$11
  413. sta $0000 ;//select the VDMA destination register
  414. lda #$00
  415. sta $0002
  416. lda #$05
  417. sta $0003 ;//change the destination address to $0500
  418.  
  419. lda #$12
  420. sta $0000 ;//select the VDMA length register
  421. lda #$00
  422. sta $0002
  423. lda #$02
  424. sta $0003 ;//change the length to $0200
  425.  
  426.  
  427. Writing to the upper port for the length register triggers the VDMA. The VDMA can only run during
  428. 'vblank' (not to be confused with vsync). Vblank is the non active scanlines of the VDC. And that's
  429. vblank of a VDC frame, not necessarily a VCE frame. If the VDMA is happening while the VDC goes into
  430. active display, it will be halted.
  431.  
  432.  
  433. Register $13. The SATB-DMA register. This register holds the source address of the SATB in VRAM. Now,
  434. you can make as many changes as you like to the SATB(Sprite attribute table buffer), but it will
  435. only take effect when the SATB in VRAM is *copied* to the internal SAT (sprite attribute table). Not
  436. so great if you want to make changes to sprite positions mid-screen, because you can't within a VDC
  437. frame. The SATB DMA auto flag in the DCR register effects whether the SATB is fetch on every VDC frame
  438. or not. If the flag is enabled, SATB DMA happens immediately when active display ends on the VDC. If
  439. you have the flag disabled but you write to register $13, it will update the SATB only once on the
  440. first encountered 'end of active display' state.
  441.  
  442. The good side to having a two buffer sprite table system is that you can make changes to the sprite's
  443. attributes during active display without worrying about causing graphical glitches onscreen. The VDC
  444. allows you to write and read from VRAM during active display. The SATB itself is $100 WORDs in length.
  445. This allows for 64 different sprite entries.
  446.  
  447. Now for the last register. The VDC status register. Reading from port $0000 will always give you the
  448. status of the VDC, regardless of which register you currently have selected.
  449.  
  450. Register $0000 (r): The VDC status reg.
  451.  
  452. Bit 15-07: N/A
  453. Bit: 06: VDMA or SATB DMA in progress flag (1=true)
  454. Bit: 05: Vertical blanking flag (1=true)
  455. Bit: 04: VDMA complete flag (1=true)
  456. Bit: 03: SATB DMA complete flag (1=true)
  457. Bit: 02: Horizontal blanking flag (1=true)
  458. Bit: 01: Sprite overflow flat (1=true)
  459. Bit: 00: Sprite #0 collision flag (1=true)
  460.  
  461.  
  462. And there you have it. All the status flags. When the VDC generates an interrupt for the CPU, it
  463. must be acknowledged by reading the VDC status register. If you don't, you'll go into an endless
  464. interrupt call loop. This isn't a bug, this is so you don't miss an interrupt if multple happen at
  465. the same time from other devices, etc. Another thing: DON'T POLL THE STATUS PORT. If you poll the
  466. the status port looking for 1 or 2 flag states in particular, you can cause an interrupt call miss
  467. for another VDC flag. It's best to have the interrupt handler pass the status of the port to a
  468. variable in ram and poll that variable if need be.
  469.  
  470.  
  471.  
  472. VCE
  473. ---
  474.  
  475. The VCE's job is to generate an NTSC frame and output pixels. The VCE also houses the palette ram.
  476. The VCE generates an NTSC frame of 242 active scanlines high out of 262(or 263) total scanlines,
  477. provides the hsync and vsync signals, and converts the incomming pixels from the VDC to the output
  478. signal. The VCE is driven by the 21mhz master clock and divides this downwards to feed to the VDC.
  479. The VCE controls the speed of the VDC. This in effect changes the size of the pixels because the VDC
  480. can write more pixels in a give active scanline width, the faster it operates.
  481.  
  482. On the technical side, the VDC sends pixel information in a 9bit format to the VCE via the pixel bus.
  483. The VCE takes this pixel bus data and uses it for the palette lookup table, then outputs that color's
  484. RGB value. Since the VDC is working in passive mode, the VCE sends the vsync and hsync triggers that
  485. the VDC needs to keep it in sync with the VCE.
  486.  
  487. Meet the VCE control register (CR), port $400. Let's take a look at a break down, shall we?
  488.  
  489.  
  490. Bit: 15-08: Unused and/or reserved
  491. Bit: 07: Color busrt enable/disable
  492. Bit: 06-03: Unused and/or reserved
  493. Bit: 02: The filter Bit
  494. Bit: 01-00: Frequency clock to the VDC
  495.  
  496. 00= 5.369mhz
  497. 01= 7.159mhz
  498. 10= 10.737mhz
  499. 11= 10.737mhz
  500.  
  501.  
  502. Bits 01-00 control the speed of the VDC, thus the overall resoluton. You need to adjust for this on
  503. the VDC side so as not to have large black horizontal borders on either sides of the screen. Bit 7
  504. controls whether the VCE outputs the colors busrt signal at hsync. If you disable this, you'll get a
  505. black and white display output. But take note, that the color subcarrier will still be generated in
  506. the output signal. You can use this to your advantage to get a much wider grey scale mode. This also
  507. only works for composite/RF/NTSC output. Enabling this bit *removes* the color burst signal. This has
  508. no effect on the RGB output of the VCE.
  509.  
  510. Bit 2 is a type of filter for composite/RF/NTSC output. Enabling this causes every other scanline to
  511. shift by *half* a pixel. On the next frame, it will do this on the alternate set of interleaved scan
  512. lines. It only shifts one interleave set at a time. This smooths the screen a tad and removes some
  513. color artifacting for still pictures. When this bit is enabled, the frame increases to 263 scanlines.
  514. The frame is 262 scanlines when this filter is disabled. Switching back and fourth between these two
  515. modes nets you a nice 'illegal' interlaced display ;) Mind your timings though.
  516.  
  517. These register take effect almost immediately. I say almost as it looks like there is a 16-20 pixel
  518. gap betweening re-reading this reg by the VCE. Disabling the color burst signal *mid* screen causes
  519. the TVs HUE to drift because there's nothing to re-sync it to. Giving a nice rainbow hue going down
  520. the screen :D Of course if left disabled, the TV will check it during vblank period and adjust the
  521. set to either B&W or Color signal. So you have to enable it and then disable it again each frame.
  522. We're talking *millions* of colors on screen! Yeah! Woohoo! Let's move on..
  523.  
  524.  
  525. The VCE has three more registers on its list. Those would be CTA, CTW, and CTR. All registers are
  526. 16bit wide like with the VDC (the VCE being another 16bit device). The CTA register selects which
  527. color slot you want to access. There are a total of 512 color slots. Because of how the VDC sends out
  528. the pixel data, this is divided into 256 for tiles and 256 for sprites. Of the 9bit pixel data being
  529. sent to the VCE, the VDC sets the most significant bit to 1 if the pixel is from a sprite and 0 if
  530. the pixel if from a tile.
  531.  
  532.  
  533. The pixel format looks like this:
  534.  
  535. bit: 8 = tile(0) or sprite(1)
  536. Bit: 7-0 = the (tile/sprite) 4bit pixel multiplied by the 4bit palette number.
  537.  
  538.  
  539. Bit 7-0 is an 8bit color number, but since it's the result of two 4bit multiply, every 16th color is
  540. going to equal 0... because any number times 0 equals 0 ;). This gives you and me a total of 241 unique
  541. possible colors for tiles, and 240 unique and separate posibble colors for sprites.
  542.  
  543. So there you have how the whole 512 color slot bank is divided up. CTA is located at port $402. The port
  544. is auto incremented by 1 color slot.
  545.  
  546.  
  547. lda #$03
  548. sta $402
  549. lda #$00
  550. sta $403 ;// now we've select color slot #3 of the CTA port
  551.  
  552.  
  553. Fairly straight foreward stuff. Now to write a color to slot #3 via the CTW port.
  554.  
  555. lda #$ff
  556. sta $404
  557. lda #$01
  558. sta $405 ;// Color slot 3 = $01ff, and now CTA is color slot #4
  559.  
  560.  
  561. More straight foreward stuff. The upper port of CTW contains the latch, if you haven't guessed.
  562. When the latch is activated, the port buffer contents transfer to the internal color bank, and the
  563. color slot is incremented by 1. If the color clot is $1ff and you write to CTW, the color slot will
  564. wrap on increment. That's right, it's a 9bit counter.
  565.  
  566. Alternatively, you can write to the upper port multiple times without writing to the lower port of
  567. CTW, and it will latch on each write. Since CTW lower port wasn't changed, it will keep using that
  568. value for the transfer. Pretty nift, huh?
  569.  
  570. The CTR register ($406) works in the same way, except for reading. The latch is on the upper port of
  571. CTR. And of course reading the upper port of CTR increments the color slot #. There is only one pointer
  572. for both CTR and CTW and it's shared, unlike the VDC vram read/write port.
  573.  
  574.  
  575. Now, for the last bit of info for the VCE. On the VDC, the internal registers have priority over the
  576. cpu, so if there's a conflict writing to vram, the VDC wins over the CPU. And the CPU is just stalled
  577. for a fraction of a cpu cycle with /RDY. And few case like SATB DMA and such where the CPU is stalled
  578. for the whole length. But on the VCE, it doesn't assert /RDY to stall the CPU. Instead, it gives the
  579. CPU priority over it's own internal registers/processes.
  580.  
  581. This can and does leave an interesting artifact on screen when accessing the palette bank. Since the
  582. VCE can not access it at the same time as the CPU, it outputs the last color it fetched to the scan
  583. line. You can use this trick to your advantage to draw solid lines over the top of the 'display'.
  584.  
  585.  
  586. Lastly, is the color format itself. The VCE takes a 16bit value for the color slot entry, but only
  587. the lower 9bits are used. The format is GRB.
  588.  
  589. (MSB) (LSB)
  590. -------G GGRRRBBB
  591.  
  592. There you have it. The tile or sprite pixel goes through two palette systems before finally reaching
  593. the true color definition.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement