Last active
April 6, 2022 21:58
-
-
Save ytmytm/265d6ae1f5b1df7bd7ef0ba67bdaa816 to your computer and use it in GitHub Desktop.
VDC setup for 256x200 bitmap mode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// VDC 256x200 modes | |
// by YTM/Elysium, 2022 | |
// | |
// in C64 mode (with cartridge or due to holding C= key) call VDC_Init first | |
// in C128 mode proper VDC timings are already initialized by Kernal | |
// | |
// (for KickAssembler) | |
// BasicUpstart128 macro from https://github.com/wiebow/examples.c128 | |
.macro BasicUpstart128(address) { | |
.pc = $1c01 "C128 Basic" | |
.word upstartEnd // link address | |
.word 10 // line num | |
.byte $9e // sys | |
.text toIntString(address) | |
.byte 0 | |
upstartEnd: | |
.word 0 // empty link signals the end of the program | |
.pc = $1c0e "Basic End" | |
} | |
/////////////////////////////////////////////////////////////////////////////////////// | |
// vdc.h | |
// I/O registers (available also in 64 mode) | |
.const VDC_REG = $d600 // VDC address/status register, bits on read: 7=status, 6=lightpen, 5=vblank | |
.const VDC_DATA_REG = $d601 // VDC data register | |
// VDC internal registers | |
.const VDC_HTOTAL =0 // horizontal total | |
.const VDC_HDISPLAYED =1 // horizontal displayed | |
.const VDC_HSYNCPOS =2 // horizontal sync position | |
.const VDC_VHSYNCW =3 // vertical/horizontal sync width | |
.const VDC_VTOTAL =4 // vertical total | |
.const VDC_VTOTALFINE =5 // vertical total fine adjustment | |
.const VDC_VDISPLAYED =6 // vertical displayed | |
.const VDC_VSYNCPOS =7 // vertical sync position | |
.const VDC_INTERLACE =8 // interlace mode | |
.const VDC_CVTOTAL =9 // character vertical total | |
.const VDC_CSRMODE =10 // cursor mode/start scanline | |
.const VDC_CSREND =11 // cursor end scanline | |
.const VDC_DSPHI =12 // display start (hi) | |
.const VDC_DSPLO =13 // display start (lo) | |
.const VDC_CSRHI =14 // cursor position (hi) | |
.const VDC_CSRLO =15 // cursor position (lo) | |
.const VDC_VLPEN =16 // light pen vertical | |
.const VDC_HLPEN =17 // light pen horizontal | |
.const VDC_DATAHI =18 // update address (hi) | |
.const VDC_DATALO =19 // update address (lo) | |
.const VDC_ATTHI =20 // attribute map address (hi) | |
.const VDC_ATTLO =21 // attribute map address (lo) | |
.const VDC_CHSIZE =22 // character horizontal size control | |
.const VDC_VCPSPC =23 // vertical character pixel space | |
.const VDC_VSCROLL =24 // block/rvs/vertical scroll | |
.const VDC_HSCROLL =25 // diff. mode sw./horizontal scroll | |
.const VDC_COLORS =26 // fore/background colors | |
.const VDC_ROWINC =27 // row address increment | |
.const VDC_CSET =28 // character set A13-15, ram size | |
.const VDC_ULINE =29 // underline scanline | |
.const VDC_COUNT =30 // word count (-1) | |
.const VDC_DATA =31 // data | |
.const VDC_SRCHI =32 // block copy source (hi) | |
.const VDC_SRCLO =33 // block copy source (lo) | |
.const VDC_DEBEGIN =34 // display enable begin | |
.const VDC_DEEND =35 // display enable end | |
.const VDC_REFRESH =36 // DRAM refresh rate | |
/////////////////////////////////////////////////////////////////////////////////////// | |
.const SCREEN_BASE =$0000 // screen base in VDC RAM | |
.const CPU_SCREEN_BASE =$0400 // screen buffer base in C128 RAM (for VDC_BlitBitmap_) | |
// C128 native | |
//BasicUpstart128(start) | |
// C128 in C64 mode | |
BasicUpstart2(start) | |
start: // jump tab to test things from BASIC - FAST:BANK15:SYSDEC("1C0F")+{0,3,6,9,...}:SLOW | |
// in C64 mode: SYS 2063+{0,3,6,9} | |
rts | |
jmp VDC_Init | |
jmp VDC_Start_256x200_Narrow | |
jmp VDC_Start_256x200_Wide | |
jmp VDC_BlitBitmap | |
/////////////////////////////////////////////////////////////////////////////////////// | |
// VDC support functions | |
VDC_WriteReg: // X = register # | |
stx VDC_REG | |
!: bit VDC_REG | |
bpl !- | |
sta VDC_DATA_REG | |
rts | |
VDC_WriteWordReg: // A=address HI, Y=address LO, X=VDC register of address HI (e.g. VDC_DSPHI) | |
stx VDC_REG | |
!: bit VDC_REG | |
bpl !- | |
sta VDC_DATA_REG | |
inx | |
stx VDC_REG | |
sty VDC_DATA_REG // no need to wait for status bit here | |
rts | |
.macro VDC_POKE(reg,value) { | |
ldx #reg | |
lda #value | |
jsr VDC_WriteReg | |
} | |
/////////////////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////////////////////////////////////////////////////////////// | |
/////////////////////////////////////////////////////////////////////////////////////// | |
// VDC init after power on | |
// this is needed only if booting directly into C64 mode (with cartridge or due to holding C= key) | |
// skipped font copying routine (can be extracted from ROM @ CE1C or from my LUnix Next Generation vdc_console_init.s) | |
VDC_Init: | |
ldx #0 | |
!: lda vdcinitab,x | |
cpx #VDC_COUNT // ignore this... | |
beq !+ | |
cpx #VDC_DATA // ...and that | |
beq !+ | |
jsr VDC_WriteReg | |
!: inx | |
cpx #VDC_REFRESH+1 | |
bne !-- | |
rts | |
vdcinitab: // default, power-on VDC register values for C128 08-column text mode, PAL | |
.byte $7e // 0 | |
.byte 80 // 1 - # of columns | |
.byte $66, $49, $26, $00// 2-5 | |
.byte 25 // 6 - # of lines | |
.byte $20 // 7 | |
.byte %00000000 // 8 - interlace - none | |
.byte %00000111 // 9 - 8 pixels for line | |
.byte %00100000 // 10 - cursor not visible, start 0 | |
.byte %00000111 // 11 - cursor end 7 (block cursor) | |
.byte 0,0 // 12/13 - current screen position | |
.byte 0,0 // 14/15 - current cursor position | |
.byte 0,0 // 16/17 - r/ - lightpen position | |
.byte 0,0 // 18/19 - current data address | |
.byte 0,0 // 20/21 - attribute map position | |
.byte $78, $08 // 22-23 | |
.byte %00000000 // 24 - block mode fill | |
// - non-reversed display | |
.byte %00000000 // 25 - text display | |
// - monochrome, w/o attribute map | |
// - pixel= 1dot clock | |
.byte %11110000 // 26 - colors (text/back) | |
.byte 0 // 27 | |
.byte $20 // 28 - A13-15 of font, bit 4 - ram size (0=16K, unreliable) | |
.byte $07 // 29 | |
.byte $4f, $20 // 30 - # of fill/copy cycles; 31 - data for write/fill | |
.byte 0,0 // 32/33 - source address of block copy | |
.byte $7d,$64 // 34/35 - start/end of display | |
.byte $05 // 36 - # of DRAM refresh cycles | |
vdcinitabend: | |
/////////////////////////////////////////////////////////////////////////////////////// | |
// 256x200 mode | |
VDC_Start_256x200_Narrow: | |
VDC_POKE(VDC_HSCROLL, %10000111) // gfx mode, monochrome, not stretched | |
VDC_POKE(VDC_HDISPLAYED,32) // 32 displayed columns | |
VDC_POKE(VDC_HTOTAL, 127) // all of total horizontal columns | |
VDC_POKE(VDC_HSYNCPOS, 78) // recenter at 102-(80-32)/2, 102 is the default | |
VDC_POKE(VDC_COLORS, $E0) // light gray (dark white) on black | |
VDC_POKE(VDC_CHSIZE, $78) // default character horizontal size (just to be sure if switching between standard and double-pixel mode) | |
VDC_POKE(VDC_REFRESH, 0) // reduce DRAM refresh rate | |
lda #>SCREEN_BASE | |
ldy #<SCREEN_BASE | |
ldx #VDC_DSPHI | |
jsr VDC_WriteWordReg | |
rts | |
/////////////////////////////////////////////////////////////////////////////////////// | |
// 256x200 double-pixel mode | |
VDC_Start_256x200_Wide: | |
VDC_POKE(VDC_HSCROLL, %10010111) // gfx mode, monochrome, stretched | |
VDC_POKE(VDC_HDISPLAYED,32) // 32 displayed columns | |
VDC_POKE(VDC_HTOTAL, 63) // half of total horizontal columns | |
VDC_POKE(VDC_HSYNCPOS, 51) // recenter screen | |
VDC_POKE(VDC_COLORS, $E0) // light gray (dark white) on black | |
VDC_POKE(VDC_CHSIZE, $89) // increase character horizontal size by 1 to make double pixel mode work | |
VDC_POKE(VDC_REFRESH, 0) // reduce DRAM refresh rate | |
lda #>SCREEN_BASE | |
ldy #<SCREEN_BASE | |
ldx #VDC_DSPHI | |
jsr VDC_WriteWordReg | |
rts | |
/////////////////////////////////////////////////////////////////////////////////////// | |
// copy bitmap (256x200=6400 bytes) from C128 RAM to VDC RAM | |
VDC_BlitBitmap: | |
// setup chip ram address | |
lda #>SCREEN_BASE | |
ldy #<SCREEN_BASE | |
ldx #VDC_DATAHI | |
jsr VDC_WriteWordReg | |
// setup write to VDC_DATA register | |
ldx #VDC_DATA | |
stx VDC_REG | |
// setup fast ram address | |
lda #<CPU_SCREEN_BASE | |
ldx #>CPU_SCREEN_BASE | |
sta loop+1 | |
stx loop+2 | |
ldx #0 | |
ldy #0 | |
loop: lda $0000,y | |
!: bit VDC_REG | |
bpl !- | |
sta VDC_DATA_REG | |
iny | |
bne loop | |
inc loop+2 | |
inx | |
cpx #$19 | |
bne loop | |
rts |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
VDC_Init
- initialize VDC video and timings, run this in C64 mode only; no need to do this in C128 native mode - Kernal does it for usVDC_Start_256x200_Narrow
- start monochrome bitmap mode 256x200 with narrow pixels (wrong aspect ratio); screen base is setup at $0000. Line 0 starts at SCREEN_BASE+0, line 1 at SCREEN_BASE+32VDC_Start_256x200_Wide
- same but in double-pixel mode; should look the same as VICVDC_BlitBitmap
- copy (200*32=) $1900 bytes fromCPU_SCREEN_BASE
into VDCSCREEN_BASE
Note: VICE doesn't emulate VDC synchronization properly. Sync code (bit / bpl !-) in
VDC_BlitBitmap
can be removed and the result remains a perfect memory copy. That is not possible on real hardware, VDC would drop some bytes.