Ciriciao folks!
Another feature that VIC has (I'm talking of the graphics chip of the VIC-20) and VIC-II hasn't is the ability to point to charsets at 1K boundaries.
Charset are 2K big both for VIC-20 and C64, but VIC-20 can place them in memory at 1K boundaries while C64 must place them at 2K boundaries.
One reason VIC-20 needed that is the low amount of memory accessible by the VIC, that theoretically is 16K but pratically it's only 9K, 4K are ROM
(two charsets, both in plain and reverse versions), 5K are RAM, but of those 5K 256 bytes are shared with the zero page and another 256 bytes are shared with the stack,
then some of the next 512 bytes are used by the kernal, leaving little more than 4K of RAM available for the programs.
So how the 1K boundary of the charset comes into play?
Let's suppose you wanted to write a game, you need your charset, containing the shapes of your background and sprites,
to point to RAM, but you also need to print messages and scores, so you also copy some of the characters from ROM to RAM,
what a waste!
Instead you point your charset to be 1K in RAM and 1K in ROM, so you'll have 128 tiles for your graphics and 128 standard characters.
Plain/reverse charactes will be swapped, but the RV bit might come to the rescue! (More on this in another article may be)
Register $05 of VIC, mapped at $9005, looks like register $18 of VIC-II, mapped at $D018
VIC |Bt7|Bt6|Bt5|Bt4|Bt3|Bt2|Bt1|Bt0|Function ----+---+---+---+---+---+---+---+---+--------------- 9005|V13|V12|V11|V10|C13|C12|C11|C10|Memory pointers ----+---+---+---+---+---+---+---+---+---------------
VIC2|Bt7|Bt6|Bt5|Bt4|Bt3|Bt2|Bt1|Bt0|Function ----+---+---+---+---+---+---+---+---+--------------- D018|V13|V12|V11|V10|C13|C12|C11| - |Memory pointers ----+---+---+---+---+---+---+---+---+---------------
The difference is the CB10 bit (C10 in my table), bit #10 of the address of character data.
Why?
Look at chaper 3.7.3.1 of the Vic-II Article, how the g-access address is composed:
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+ |C13|C12|C11| D7| D6| D5| D4| D3| D2| D1| D0|RC2|RC1|RC0| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
If we want to put bit C10 into the picture then we need to add it to D7, and propagate the carry up to C13, that is, instead of a simple juxtaposition of data coming from different sources, wee need to add some of them, and when dealing with circuits juxtaposition is free and immediate, while an adder has a cost in terms of space (number of gates) and time (will it introduce delays?).
That's about characters, what about bitmaps?
Same and worse. VIC-II uses only CB13 bit, the other bits come from the video counter VC and row counter RC:
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+ |C13|VC9|VC8|VC7|VC6|VC5|VC4|VC3|VC2|VC1|VC0|RC2|RC1|RC0| +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Here we need to put 3 more bits of CB into the picture, added to 3 bits of VC, with carry added to CB13.
Implementation in Vice
In Vice we may not worry too much of the 'performance loss' that a sum will introduce with respect to a bitwise or.
As usual a new macro is defined in file vice/src/viciisc/viciitypes.h
/* VIC-II WIV flags */ ... #define WIV_XMP (vicii.regs[0x13] & 0x02) /* eXtended Memory Pointers: enable all bits of register $18 */
Reading register $18 will give the lowest bit only of XMP is set, file vice/src/viciisc/vic-mem.c
case 0x18: /* $D018: Video and char matrix base address */ VICII_DEBUG_REGISTER(("Video memory address register: $%02X", vicii.regs[addr])); value = vicii.regs[addr] | (IS_WIV && WIV_XMP ? 0x0 : 0x1); break;
And finally in file vice/src/viciisc/vic-fetch.c when the memory address is built, a sum takes place instead of a bitwise or:
inline static uint16_t g_fetch_addr(uint8_t mode) { ... /* BMM */ if (mode & 0x20) { a = (vicii.vc << 3) | vicii.rc; if (IS_WIV) { a += (vicii.regs[0x18] & (WIV_XMP ? 0xf : 0x8)) << 10; a &= 0x3fff; } else { a |= (vicii.regs[0x18] & 0x8) << 10; } } else { a = (vicii.vbuf[vicii.vmli] << 3) | vicii.rc; if (IS_WIV) { a += (vicii.regs[0x18] & (WIV_XMP ? 0xf : 0xe)) << 10; a &= 0x3fff; } else { a |= (vicii.regs[0x18] & 0xe) << 10; } } ... }
Implementation in VIC-II Kawari
In file hdl/registers.v the output cb (characters base) is expanded from 3 to 4 bits:
`ifdef WIV_EXTENSIONS output reg [3:0] cb, `else output reg [2:0] cb, `endif
A new flag wiv_xmp is added to register CR3:
output reg wiv_cre = 1'b0, // VIC-WIV control registers read enable output reg wiv_xmp = 1'b0, // VIC-WIV extended memory pointers: enable all bits of register $18 output reg wiv_dvb = 1'b0, // VIC-WIV disable vertical border output reg wiv_dmb = 1'b0, // VIC-WIV disable main border
Read and written to:
dbo[0] <= wiv_cre; dbo[1] <= wiv_xmp; dbo[2] <= wiv_dvb; dbo[3] <= wiv_dmb; ... wiv_cre <= dbi[0]; wiv_xmp <= dbi[1]; wiv_dvb <= dbi[2]; wiv_dmb <= dbi[3];
Used to enable reading the least significant bit of the expanded cb:
/* 0x18 */ `REG_MEMORY_SETUP: begin `ifdef WIV_EXTENSIONS dbo[0] <= cb[0] | ~wiv_xmp; dbo[3:1] <= cb[3:1]; `else dbo[0] <= 1'b1; dbo[3:1] <= cb[2:0]; `endif dbo[7:4] <= vm[3:0]; end
While writing always goes through:
/* 0x18 */ `REG_MEMORY_SETUP: begin `ifdef WIV_EXTENSIONS cb[3:0] <= dbi[3:0]; `else cb[2:0] <= dbi[3:1]; `endif vm[3:0] <= dbi[7:4]; end
The new flag is used in file hdl/addressgen.v where a sum is used when XMP is set:
`ifdef WIV_EXTENSIONS if (wiv_xmp) vic_addr = {cb + { 1'b0, vc[9:7]}, vc[6:0], rc}; // bitmap data else vic_addr = {cb[3], vc, rc}; // bitmap data `else vic_addr = {cb[2], vc, rc}; // bitmap data `endif else `ifdef WIV_EXTENSIONS if (wiv_xmp) vic_addr = {cb + { 3'b000, char_ptr[7]}, char_ptr[6:0], rc}; // character pixels else vic_addr = {cb[3:1], char_ptr, rc}; // character pixels `else vic_addr = {cb, char_ptr, rc}; // character pixels `endif
BASIC example
Text mode example
The first example shows how to use the new feature in text mode: the charset points to the second half of the lowercase ROM font, so thet the upper 128 chars are in RAM and free to be redefined and displayed.
10 rem ** half charset from rom 11 rem ** and half charset from ram 20 poke 53267,2:poke 53272,23 30 rem ** smiley face 40 data 129,36,36,0,66,66,60,129 50 for i=0to7:read a:poke 8192+i,a:next 60 print"smile! "chr$(18)+"@@@"
Output:
Bitmap mode example
The second example shows how the bitmap buffer can now be set at 1K boundaries.
10 rem ** move start of bitmap 11 rem ** with 1kb steps 20 print chr$(147) 30 poke 53267,2:poke 53265,55 40 for i=0to15 50 poke 53272,16+i 60 for p=0to1000:next 70 next 80 goto 40
Output:
No comments:
Post a Comment