Jump to content
IGNORED

Redefining text as multicolor graphics on VIC-20


bluejay

Recommended Posts

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?

Link to comment
Share on other sites

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 by bluejay
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

@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.

Screenshot (71).png

Edited by bluejay
  • Like 2
Link to comment
Share on other sites

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 by carlsson
  • Like 1
Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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 by bluejay
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

@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 by bluejay
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 1 month later...

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.

 

 

  • Like 1
Link to comment
Share on other sites

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.

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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.

 

 

 

 

  • Like 1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...