bluejay Posted October 12, 2020 Share Posted October 12, 2020 I've figured out how to copy the character ROM into RAM then editing it to create simple graphics, and now I want to know how to create multicolor graphics using redefined text characters. Do I just set the computer to multicolor mode and use the 2-digits-per-pixel system to set what color I need the pixel to be, the poke the values into the character address in RAM like in normal graphics? Quote Link to comment Share on other sites More sharing options...
potatohead Posted October 12, 2020 Share Posted October 12, 2020 https://www.atarimagazines.com/compute/issue36/037_Programming_Multicolor_Characters_On_The_VIC.php Yes, poking the data in there should work. Quote Link to comment Share on other sites More sharing options...
bluejay Posted October 12, 2020 Author Share Posted October 12, 2020 (edited) Then I must load the character ROM into RAM, then redefine a certain character of my choice with the POKE commands using the two bit per pixel thing, define the screen, border, and auxiliary color with POKE commands, the set then POKE a value at 38400+X to simultaneously switch to multicolor mode on the wanted character cells and set the character color? Edited October 12, 2020 by bluejay Quote Link to comment Share on other sites More sharing options...
carlsson Posted October 12, 2020 Share Posted October 12, 2020 Yes. When you're working with an unexpanded VIC-20 (or with at most 3K expansion), you don't have to copy from ROM to RAM. By printing characters in reverse mode, those are magically read from ROM and displayed as normal characters. All the other parts are true though, that in multicolour mode you have one colour per cell (38400), and the other three fixed for the entire screen (background, border and auxillary colour, the upper nybble of the volume register 36878). In machine code, it is possible to sync the raster beam and change those last three colours at least once per scan line, perhaps even finer granularity depending on how much timing you want to invest into it. In BASIC, not so much. Quote Link to comment Share on other sites More sharing options...
bluejay Posted October 12, 2020 Author Share Posted October 12, 2020 (edited) @carlsson If I'm not to copy the char ROM to RAM, then how do I change it? You mean I can somehow exploit reverse mode to create a custom character set? I figured it'd be much simpler and easier to just copy the ROM into RAM. I have the code to copy the ROM to RAM on a disk so it only takes a few seconds. It took me a few attempts but I successfully drew this IBM PC using multicolor mode. It's not the most colorful thing but it was the only thing I could think of that's simple enough to be drawn using 4 redefined characters. It took a bunch of POKE commands and DATA stuff but I got it right on my 5th try. P.S. It doesn't look like it on the picture but the IBM logo is blue. Edited October 12, 2020 by bluejay 2 Quote Link to comment Share on other sites More sharing options...
carlsson Posted October 12, 2020 Share Posted October 12, 2020 (edited) You can POKE your custom graphics to RAM without copying the ROM font before doing that. The reason why you copy the ROM font is in order to display text and numbers on the screen, but you could as well redesign the font entirely with enough POKE statements. POKE 36869,255 will enable custom characters at 7168-7679. Use POKE 52,28:POKE 56,28:CLR to reserve memory so your graphics don't get overwritten with variable data. In this setting if you type something in reverse mode, the VIC chip will read from ROM due to a wrap-around effect. Your IBM PC looks good. 10 poke 52,28:poke 56,28:clr 20 for i=0 to 511:a=peek(32768+i) 30 poke 7168+i,a or a*2:next 40 poke 36869,255 Edited October 12, 2020 by carlsson 1 Quote Link to comment Share on other sites More sharing options...
bluejay Posted October 12, 2020 Author Share Posted October 12, 2020 Thanks! Yeah, the 36869,255 and POKE 52,28:POKE 56,28:CLR is part of my ROM-RAM copying program. You mean the 6560 will read from RAM? If reads from ROM to begin with, and I don't want that to happen, right? Then, freeing up the 7168-7679 space would somehow make the VIC read from RAM? Quote Link to comment Share on other sites More sharing options...
bluejay Posted October 12, 2020 Author Share Posted October 12, 2020 (edited) Thanks! Yeah, the 36869,255 and POKE 52,28:POKE 56,28:CLR is part of my ROM-RAM copying program. You mean the 6560 will read from RAM? It reads from ROM to begin with, and I don't want that to happen, right? Then, how does freeing up the 7168-7679 space would make the VIC read from RAM? Edited October 12, 2020 by bluejay Quote Link to comment Share on other sites More sharing options...
carlsson Posted October 12, 2020 Share Posted October 12, 2020 The VIC chip either reads from the ROM at 32768, or RAM in the range 0-1023 and 4096-7679. The POKE 36869,255 sets the character set to 7168, i.e. RAM. POKE 36869,240 reverts it to ROM. In a similar fashion you can move the screen memory from 7680 to any other address with a 512 byte boundary, though usually you don't want to fiddle with that. If you want more than 64 characters, it is easier to start the character set at e.g. 6144 (POKE 36869,253 IIRC) and adjust POKE 56,26 to reserve space. The numbers work like 28*256 = 7168, i.e. top byte+1 for variables. Quote Link to comment Share on other sites More sharing options...
carlsson Posted October 12, 2020 Share Posted October 12, 2020 (edited) Here is another fun one, if you want to copy the ROM font to RAM with a twist: 10 poke 52,28:poke 56,28:clr 20 for i=0 to 511:a=peek(32768+i):b=i and 7 30 poke 7168+i,a+(b<3)*a/2-(b>=6)*a:next 40 poke 36869,255 Edited October 12, 2020 by carlsson 1 Quote Link to comment Share on other sites More sharing options...
bluejay Posted October 12, 2020 Author Share Posted October 12, 2020 (edited) @carlsson Kinda off topic but do AND and OR commands in BASIC work like the AND and OR commands in machine language? Does the computer convert the value to binary then does the same thing as their 6502 assembly counterparts? Ah, nevermind. Found the answer while searching through the programmer's reference guide. Edited October 12, 2020 by bluejay Quote Link to comment Share on other sites More sharing options...
carlsson Posted October 12, 2020 Share Posted October 12, 2020 Yes, those are bitwise operators that also function as logical operators. Unfortunately not every BASIC dialect has bitwise operations, but the Microsoft/Commodore one does. 1 Quote Link to comment Share on other sites More sharing options...
bluejay Posted October 12, 2020 Author Share Posted October 12, 2020 I tried using without loading the character ROM, and typing in reverse mode. I could type letters but some things just didn't work. For example, LOAD"*",8 would say "PRESS PLAY ON TAPE". I think I'll be better off just copying the character ROM then editing that. Quote Link to comment Share on other sites More sharing options...
carlsson Posted October 12, 2020 Share Posted October 12, 2020 Hm. It should work the same way in reverse characters. If you don't copy from ROM, you can display all of @A-Z, numbers etc beyond the 64 custom characters. Mainly you would use this for in-game text displays, not as a way to operate the computer. 1 Quote Link to comment Share on other sites More sharing options...
potatohead Posted October 12, 2020 Share Posted October 12, 2020 2 hours ago, carlsson said: Yes, those are bitwise operators that also function as logical operators. Unfortunately not every BASIC dialect has bitwise operations, but the Microsoft/Commodore one does. And it is nice to have, IMHO. Quote Link to comment Share on other sites More sharing options...
imstarryeyed Posted November 19, 2020 Share Posted November 19, 2020 This is great information. Would anyone here happen to have a good example of the same thing in 6502 Assembly? Finding books that cover character redefining is very easy for BASIC but I cannot seem to find good information on assembly. I have been using the Chibi Akumas tutorials https://www.chibiakumas.com/6502/vic20.php which are great, but the Vic 20 graphics redefining parts still confuse me. Does anyone here have a very simple example of redefining characters in Assembly for the Vic 20? I would greatly appreciate any direction. 1 Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted November 20, 2020 Share Posted November 20, 2020 If you know 6502 fairly well, translating the BASIC concepts to assembly should not be unreasonably difficult. While I am out of practice, given a little time and thought I could whip up assembly/ML to do the work based upon BASIC code. Quote Link to comment Share on other sites More sharing options...
imstarryeyed Posted November 20, 2020 Share Posted November 20, 2020 I wish my 6502 skills were at the level of translating BASIC but I am not quite there yet. I just find it amazing that with all of the books out there, I cannot find one that digs into graphics redefine in asm. I however will keep looking as it seems this is missing from learning ASM on the Vic. I would love to write or read a book on just the Vic using modern tools and techniques that is written for just ASM for those folks who want to learn. Quote Link to comment Share on other sites More sharing options...
bluejay Posted November 20, 2020 Author Share Posted November 20, 2020 47 minutes ago, imstarryeyed said: I wish my 6502 skills were at the level of translating BASIC but I am not quite there yet. I just find it amazing that with all of the books out there, I cannot find one that digs into graphics redefine in asm. I however will keep looking as it seems this is missing from learning ASM on the Vic. I would love to write or read a book on just the Vic using modern tools and techniques that is written for just ASM for those folks who want to learn. It's just entering values into various memory locations. 10 POKE 52,28:POKE 56,28 20 FOR I=7168TO7679:POKE I,PEEK(I+25600):NEXT 30 POKE 36869,255 40 FOR C=7328 TO 7359:READ A:POKE C,A:NEXT 50 DATA 0,42,32,44,32,32,32,32 60 DATA 0,168,8,40,8,40,8,40 70 DATA 32,42,42,170,168,168,152,170 80 DATA 8,168,168,170,2,2,2,170 90 POKE 36878,90 100 POKE 36879,14 110 PRINT"TU":PRINT"VW" 120 POKE 38400,9:POKE38401,9:POKE38422,9:POKE38423,9 This draws the IBM PC. So you'd enter 1C into 34, 1C into 38 for line 10. Then value of 8000 into 1C00, 8001 into 1C01, and so on for line 20. FF into 9005. Enter the hex equivalents of numbers in the data statements above between 1CA0 and 1CBF. Enter 5A into 900E, E into 900F. Then, after that I don't know. I tried POKEing in the ASCII values of T, U, V, and W into screen RAM but all it would display is odd characters, so it must be reading off some location that doesn't contain the character information. Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted November 20, 2020 Share Posted November 20, 2020 1 hour ago, imstarryeyed said: I just find it amazing that with all of the books out there, I cannot find one that digs into graphics redefine in asm. I however will keep looking as it seems this is missing from learning ASM on the Vic. Lacking books, I would also think you should be able to find tutorials out there somewhere. Would be a shame if such resources are lacking. 1 hour ago, imstarryeyed said: I would love to write or read a book on just the Vic using modern tools and techniques that is written for just ASM for those folks who want to learn. I thought I had seen some kind of cross-development system or IDE which would generate binaries appropriate for the VIC-20. The VIC-20, let alone modern development tools (I am still using TSDS to assemble,) is not my wheelhouse so I have no specifics at which to point. Good luck! Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted November 20, 2020 Share Posted November 20, 2020 @imstarryeyed BTW, any tutorial on 6502 should help you out to get started. Blocks of data and routines to load data into other memory locations is nothing VIC-20 specific, you would just need to know the locations where to put the data. I have this to start. vicmemory.pdf Quote Link to comment Share on other sites More sharing options...
imstarryeyed Posted November 20, 2020 Share Posted November 20, 2020 Thank you BlueJay and OLD CS1, yeah I have downloaded (from Chibi Akumas site) his vic 20 graphics program, but it is not really simplified so its a bit hard to understand. I have been able to wrap my head around most of this source code, but separating what functions are supported via the assembler from one to another took me a while. For Example: lda #<(BitmapEnd-Bitmap);Source Bitmap Data Length sta z_C lda #>(BitmapEnd-Bitmap) These lines were completely throwing me for a loop as I could not figure out the logic they were using, and realized this was supported by DASM but not necessarily by CBM Program Studio or other Assemblers. These would have been easier if there was an easy way to step through code and see exactly what is happening, but again not all assemblers have step by step interactive debugging. Here is a listing I have been following: VIC_Bitmap.asm -=-=-=-=-=-=- z_Regs equ $20 z_HL equ z_Regs z_L equ z_Regs z_H equ z_Regs+1 z_BC equ z_Regs+2 ;Byte Count z_C equ z_Regs+2 z_B equ z_Regs+3 z_DE equ z_Regs+4 ;Destination z_E equ z_Regs+4 z_D equ z_Regs+5 * = $1001 ; BASIC program to boot the machine language code db $0b, $10, $0a, $00, $9e, $34, $31, $30, $39, $00, $00, $00 ;start of code $100A ;Screen Init ldx #16 ;We're going to copy 16 registers ScreenInitAgain: dex lda VicScreenSettings,x ;Get A parameter sta $9000,X ;Store to the video registers at $9000 txa bne ScreenInitAgain ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Define Tiles lda #<Bitmap ;Source Bitmap Data sta z_L lda #>Bitmap sta z_H lda #<(BitmapEnd-Bitmap);Source Bitmap Data Length sta z_C lda #>(BitmapEnd-Bitmap) sta z_B lda #<$1C00 ;Tile 0 in VIC Custom Characters sta z_E lda #>$1C00 sta z_D jsr DefineTiles ;Define the tile patterns ;Draw Bitmap lda #3 ;Start SX sta z_b lda #3 ;Start SY sta z_c jsr GetVDPScreenPos lda #0 ;Tile 0 (smiley) sta (z_hl),y ;Transfer Tile to ram lda z_h clc adc #$78 ;add Offset to Color Ram ($9600) sta z_h lda #4 ;Color sta (z_hl),y ;Set Tile Color jmp * ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Address= $1E00 + (Ypos * 22) + Xpos GetVDPScreenPos: ; BC=XYpos lda #$1e ;Screen base is $1E00 sta z_h ;Colors at $9600 (add $7800 offset) lda z_b ;Xpos sta z_l ldy z_c ;Ypos beq GetVDPScreenPos_YZero GetVDPScreenPos_Addagain: ;Repeatedly add screen width (22) Y times clc lda z_l adc #22 ;22 bytes per line sta z_l lda z_h adc #0 ;Add Carry sta z_h dey bne GetVDPScreenPos_Addagain GetVDPScreenPos_YZero: rts ;Copy Data to the Character Defs from ram/rom to char ram DefineTiles: ldy #0 DefineTiles2: lda (z_HL),Y ;Copy From z_HL sta (z_DE),Y ;To z_ DE iny ;Inc Byte BNE DefineTiles_SkipInc1 INC z_H ;Inc H bytes INC z_D DefineTiles_SkipInc1: DEC z_C ;Dec Counter BNE DefineTiles2 LDA z_B BEQ DefineTiles_Done DEC z_B jmp DefineTiles2 DefineTiles_Done: rts ;LLLL options ; 0000 ROM 8000 32768 ; 0001 8400 33792 ; 0010 8800 34816 ; 0011 8C00 35840 ; 1000 RAM 0000 0000 ; 1001 xxxx ; 1010 xxxx unavail. ; 1011 xxxx ; 1100 1000 4096 ; 1101 1400 5120 ; 1110 1800 6144 ; 1111 1C00 7168 <--- VicScreenSettings: db $0C ;$9000 - horizontal centering db $26 ;$9001 - vertical centering db $96 ;$9002 - set # of columns / ;Bit7 = screen base bit ($16 for screen at $1000) db $AE ;$9003 - set # of rows db $7A ;$9004 - TV raster beam line db $FF ;$9005 - bits 0-3 start of character memory / ;bits 4-7 is rest of video address ;$(CF for screen at $1000) db $57 ;$9006 - horizontal position of light pen db $EA ;$9007 - vertical position of light pen db $FF ;$9008 - Digitized value of paddle X db $FF ;$9009 - Digitized value of paddle Y db $00 ;$900A - Frequency for oscillator 1 (low) db $00 ;$900B - Frequency for oscillator 2 (medium) db $00 ;$900C - Frequency for oscillator 3 (high) db $00 ;$900D - Frequency of noise source db $00 ;$900E - bit 0-3 sets volume of all sound / ;bits 4-7 are auxiliary color information db $00+8 ;$900F - Screen and border color register Bitmap: DB %00111100 ; 0 DB %01111110 ; 1 DB %11011011 ; 2 DB %11111111 ; 3 DB %11111111 ; 4 DB %11011011 ; 5 DB %01100110 ; 6 DB %00111100 ; 7 BitmapEnd: =-=-=-=-=-=-=-=-=-=- As you all can see lots of overhead here to get the job done and he thinks along a VDP since he works on many systems and it is easier for him to think that way even if the Vic does not use it. For a beginner I was hoping more comments explaining the rationale for each line and why it is setup that way. In any case thank you all for the insight you have supplied. 1 Quote Link to comment Share on other sites More sharing options...
carlsson Posted November 20, 2020 Share Posted November 20, 2020 Ooh.. is this a ColecoVision to VIC-20 conversion going on since I see both Z80 nomenclature and VDP references? 1. Choice of zeropage registers. I would assume that $20 - $25 are OK. It is part of temporary string stack and some utility pointers used by BASIC but since you're working in machine code you probably can trash those registers. Personally I tend to use $F7 - $FE. The registers $F7 - $FA are reserved for RS232 communication (which almost never is used) and $FB - $FE are entirely free. You probably can use both sets of zeropage registers if you need a lot. However there are some you probably shouldn't touch, like those setting start of BASIC, end of memory, FAC and AFAC in case you want to use the BASIC functions for converting numbers, multiplication, printing strings etc. 2. Screen init. It looks fine, but DEX affects some flags which means you can optimize it slightly: ldx #15 ;We're going to copy 16 registers ScreenInitAgain: lda VicScreenSettings,x ;Get A parameter sta $9000,X ;Store to the video registers at $9000 dex bpl ScreenInitAgain This will loop until X = 255. Perhaps it is a bit more difficult to understand, but one instruction less. 3. DefineTiles. This approach works and is fairly dynamic, but as long as you have fewer than 256 bytes (32 characters) to define, you could simplify the loop. Either you hard code addresses or define a byte how many characters you're having: NumChars: db 1 DefineTiles: lda NumChars asl asl asl ; multiply by 8, or simply set NumChars to the amount of bytes instead tay ldx #0 DefineTiles2: lda Bitmap,x sta $1c00,x inx dey bne DefineTiles2 rts If you have more characters, either you would loop around $1c00 for the entire 256 times (inx / bne) and then decrease Y for a second loop that goes from Bitmap+256,x to $1d00,x. Or you would use the ($nn),Y syntax in combination with my approach of counting characters/bytes instead of using an entire 16-bit register (two zeropage locations) only to hold the end address in a somewhat complex loop. 4. GetVDPScreenPos: Ok routine, but you might want to learn about the various branch instructions. This should work as well: GetVDPScreenPos: lda #$1e sta z_h lda #0 ldy z_c beq GetVDPScreenPos_AddX GetVDPScreenPos_Addagain: clc adc #22 bcc GetVDPScreenPos_NoCarry ; branch if carry is cleared inc z_h ; instead of adding 0 + carry, just increase the register GetVDPScreenPos_NoCarry: dey bne GetVDPScreenPos_Addagain GetVDPScreenPos_AddX: clc adc z_b ; Xpos bcc GetVDPScreenPos_NoCarry2 inc z_h GetVDPScreenPos_NoCarry2: sta z_l rts It might be one instruction more, but I believe this will execute faster since STA is a bit expensive and you don't really need to store the results and load them back until you're done. On the C64 you can shorten the loop a little by taking advantage of that 40 columns = 32 + 8, i.e. first shift number of rows thrice, store the temporary value, shift twice more and add the temp value with taking care of the carry flag along the way. 22 is not quite as easy to divide, perhaps 16 + (8-2). 5. Draw bitmap. My recommendation here is to use two registers on the zeropage for the colour RAM location, instead of trashing z_h by adding #78 to it. In particular if you're plotting several characters after eachother, you would want to keep those separately. The idea to setup the colour RAM pointer based on the screen position you defined in the other routine is good though. Generally your code is fine, but not exactly as I would write it. Of course it depends on the scope and which optimizations you can do. I strongly see this is someone who knows their Z80 and have applied the skills on the 6502, but yet doesn't know all the instructions or how the flags and branches work. Personally I'm the opposite, trying to program in Z80 like it was a 6502 which is just as difficult to wrap my head around. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.