diff options
Diffstat (limited to 'src/example/vcs.asm')
-rw-r--r-- | src/example/vcs.asm | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/src/example/vcs.asm b/src/example/vcs.asm new file mode 100644 index 0000000..379722c --- /dev/null +++ b/src/example/vcs.asm @@ -0,0 +1,533 @@ +;--------------------------------------------------------------------------- + +; * Subject: [stella] 2600 Digital Clock (source code) +; * From: crackers@hwcn.org +; * Date: Sun, 5 Oct 1997 14:31:50 -0400 (EDT) + +;--------------------------------------------------------------------------- + +; Here's the source code for that final digital clock programme. +; Feel free to employ and distribute this code however you may wish. +; Both the source code and the binary are public domain. + +; ----------------------------------------------------------------------------- + processor 6502 + + option output-file,vcs.bin + + option +list + option +list-hex + option +list-pc + +VSYNC equ $00 +VBLANK equ $01 +WSYNC equ $02 +NUSIZ0 equ $04 +NUSIZ1 equ $05 +COLUPF equ $08 +COLUBK equ $09 +PF0 equ $0D +PF1 equ $0E +PF2 equ $0F +SWCHA equ $280 +INTIM equ $284 +TIM64T equ $296 +CTRLPF equ $0A +COLUP0 equ $06 +COLUP1 equ $07 +GP0 equ $1B +GP1 equ $1C +HMOVE equ $2a +RESP0 equ $10 +RESP1 equ $11 + +;RAM + +TEMP equ $80 ;2 bytes for temporary data +SECS equ $82 ;seconds counter +MINS equ $83 ;minutes counter +HOURS equ $84 ;hours counter +JOYDEL equ $85 ;joystick delay variable +JOY1ST equ $86 ;joystick first move variable +SPRITEA equ $87 ;8 bytes for the first sprite +SPRITEB equ $8F ;8 bytes for the second sprite +RMINS equ $97 ;real minutes +RHOURS equ $98 ;real hours +FRAMES equ $99 ;frames counter + + org $F000 + +start SEI + CLD + LDX #$FF + TXS + LDA #$00 + +zero STA $00,X ;looks familiar, right? + DEX ;typical zeroing routine + BNE zero + + lda #$01 ;now we set up all our variables + sta CTRLPF + lda #$0C ;set our starting time at 12:00 + sta HOURS ;just like a VCR, eh? Except it doesn't blink + lda #$3C ;00 minutes + sta MINS + lda #$ca ;nice pretty green for our sprites + sta COLUP0 + sta COLUP1 + lda #$07 ;make them good and fat + sta NUSIZ0 + sta NUSIZ1 + lda #$3C ;initialize the frame and seconds counters + sta FRAMES + sta SECS + +main JSR vertb ;main loop + JSR time + JSR draw + JSR clear + JMP main + +vertb LDX #$00 ;vertical blank, We all know what this is about + LDA #$02 + STA WSYNC + STA WSYNC + STA WSYNC + STA VSYNC + STA WSYNC + STA WSYNC + LDA #$2C + STA TIM64T + LDA #$00 + STA WSYNC + STA VSYNC + RTS + +time ldy #06 ;just load Y ahead of time for #of sprite lines + lda #$3C ;60 + sec + sbc MINS ;subtract the clock minutes from 60 to get the + sta RMINS ;real minutes since clock counts down + cmp #$00 ;see if it's 00 minutes + beq min0 + cmp #$32 ;see if it's more than 50 minutes + bpl min5 + cmp #$28 ;see if it's more than 40 minutes + bpl min4 + cmp #$1E ;see if it's more than 30 minutes + bpl min3 + cmp #$14 ;see if it's more than 20 minutes + bpl min2 + cmp #$0A ;see if it's more than 10 minutes + bpl min1 + +min0 lda zeros,y ;minutes must be less than 10 so load 00 sprite + and #$F0 ;strip the first 4 bits + sta SPRITEA,y ;store it to sprite A memory + dey + bpl min0 ;get next sprite line + lda #$00 ;less than 10 minutes + jmp minload ;go to where we load the first 4 bits of sprite + +min5 lda fives,y ;minutes must be 50+ so load 55 sprite + and #$F0 ;strip 1st four bits + sta SPRITEA,y ;store it to sprite A memory + dey + bpl min5 ;get next sprite line + lda #$32 ;50+ minutes - you'll need this number later to + jmp minload ;load the second half the sprite data + +min4 lda fours,y ;minutes must be 40+ + and #$F0 + sta SPRITEA,y + dey + bpl min4 + lda #$28 ;40+ minutes + jmp minload + +min3 lda threes,y ;minutes must be 30+ + and #$F0 + sta SPRITEA,y + dey + bpl min3 + lda #$1E ;30+ minutes + jmp minload + +min2 lda twos,y ;minutes must be 20+ + and #$F0 + sta SPRITEA,y + dey + bpl min2 + lda #$14 + jmp minload ;20+ minutes + +min1 lda ones,y ;minutes must be 10+ + and #$F0 + sta SPRITEA,y + dey + bpl min1 + lda #$0A ;10+ minutes + +minload STA TEMP ;the accumulator had the 10s of minutes + LDA RMINS ;now we subtract the 10s minutes from the real + sec ;minutes to get the 1s minutes to act as a pointer + SBC TEMP ;for the data tables for 2nd half of sprite + ASL ;double the number + TAX + LDA numblk,x ;load the first half of the sprite data address + sta TEMP + lda numblk+1,x ;load the second half of the sprite table address + sta TEMP+1 + + ldy #$06 ;number of lines in the sprite (-1) +msload lda (TEMP),y ;get the sprite data + and #$0F ;strip off the last 4 bits + ora SPRITEA,y ;combine the 1st half with the 2nd half + sta SPRITEA,y ;put it back in the sprite memory + dey + bpl msload ;get the next line of data + + ldy #$06 ;preload number of sprite lines (-1) + lda #$18 ;24 hours + sec + SBC HOURS ;subtract the counter hours to get + STA RHOURS ;the real hours value + cmp #$00 ;see if it's 12:00 am + beq hour0 + cmp #$14 ;see if it's 20+ hours + bpl hour2 + cmp #$0A ;see if it's 10+ hours + bpl hour1 + +hour0 lda zeros,y ;load the zeros sprite data + and #$F0 ;strip the 1st four bits + sta SPRITEB,y ;store to the 2nd sprite memory + dey + bpl hour0 + lda #$00 ;same deal as with the minutes + jmp loadhrs ;but now we load the second half of the hours data + +hour1 lda ones,y + and #$F0 + sta SPRITEB,y + dey + bpl hour1 + lda #$0A + jmp loadhrs + +hour2 lda twos,y + and #$F0 + sta SPRITEB,y + dey + bpl hour2 + lda #$14 + jmp loadhrs + +loadhrs STA TEMP + LDA RHOURS + sec + SBC TEMP + asl + tax + lda numblk,x + sta TEMP + lda numblk+1,x + sta TEMP+1 + + ldy #$06 +hsload lda (TEMP),y + and #$0F + ora SPRITEB,y + sta SPRITEB,y + dey + bpl hsload + rts + +numblk .word zeros ;where all the sprites are at + .word ones + .word twos + .word threes + .word fours + .word fives + .word sixes + .word sevens + .word eights + .word nines + +draw LDA INTIM ;check to see if it's time to draw a frame + BNE draw + sta WSYNC + sta HMOVE + sta VBLANK ;turn the screen on! + +;insert display kernal + + ldx #$3F ;okay, this display kernal sucks, but I'm not doing +blow1 sta WSYNC ;much here so I didn't go for anything fancy since + dex ;this is just a demo. This wouldn't be the way you + bpl blow1 ;do things in a game, but it works for this. + sta WSYNC + nop ;See... you'd never do something weenie like this + nop ;in a real programme + nop ; + nop ; + nop ;but when I was experimenting with this programme + nop ;I just had a whole bunch of ";nop" lines here + nop ;and I removed the ";" until I got the spacing more + nop ;or less where I wanted it + nop + nop + nop + nop + nop + nop + nop + sta RESP0 + nop + nop + nop + nop + nop + nop + nop + sta RESP1 + + ldy #$06 +sload lda SPRITEB,y + sta GP0 + lda SPRITEA,y + sta GP1 + sta WSYNC ;you wouldn't do something weenie like this + sta WSYNC ;either in a real programme, but it was an + sta WSYNC ;easy way to make each sprite 8 lines high + sta WSYNC ;and I was more concerned with making a working + sta WSYNC ;and accurate clock than a nice display. + sta WSYNC + sta WSYNC + sta WSYNC + dey + bpl sload + lda #$00 + sta GP0 + sta GP1 + + ldx #$48 +blow2 sta WSYNC ;now we just blow the rest of the unused scanlines. + dex + bpl blow2 + rts + + +clear LDA #$24 ;set timer for overscan + STA TIM64T + LDA #$02 ;clear the screen and turn off the video + STA WSYNC + STA VBLANK + LDA #$00 + STA PF0 + STA PF1 + STA PF2 + sta COLUPF + sta COLUBK + + LDA #$3C ;this is the clock routine itself. it counts + DEC FRAMES ;down from 60 frames, and then decreases the + bne joy ;seconds, which count down the minutes and then + lda #$3C ;the hours.. etc. For whatever reason my 2600 + STA FRAMES ;wasn't running at exactly 60 frames a second + DEC SECS ;so there were two lines inserted to correct + bne joy ;timing accuracy problems + STA SECS + DEC SECS ;here's one. Kept me from losing a second every + DEC MINS ;minute + bne joy + STA MINS + LDA #$18 + INC SECS ;here's the other. It kept me from gaining a + DEC HOURS ;second every hour. + bne joy + STA HOURS + ;now my timing inaccuracies may have been caused + ;by either my V-blank, V-sync, Overscan, or + ;display being a few scanlines too long or short. + ;theoretically if all my lines were bang on, + ;I wouldn't have needed those two seconds counter + ;corrections. But with them inplace, it allows me + ;to be a little looser with my code which works for + ;me. It may still gain or lose a second every 60 + ;hours, but I can live with that. And since I'll + ;be employing this clock in a virtual pet game and + ;not a swiss made olympic time piece, a little + ;inaccuracy won't matter. + +joy lda SWCHA ;load joysticks + ora #$0f ;strip the data for player #2 joystick + cmp #$ef ;up + beq up + cmp #$df ;down + beq down + cmp #$bf ;left + beq left + cmp #$7f ;right + beq right + lda #$00 ;no movement + sta JOYDEL ;reset the joystick delay variable + lda #$01 ;reset the first move variable + sta JOY1ST + jmp oscan ;finish off the overscan + +up lda HOURS ;check to see if we've run out our hours + cmp #$01 + beq oscan ;yep, then ignore the movement + inc JOYDEL ;increase the joystick delay variable + lda JOY1ST ;check to see if this is the first move in this + cmp #$01 ;direction. + beq now1 ;if it is then change the variable now + lda #$1E ;nope then see if there's been enough of a delay + cmp JOYDEL ;to change the variable yet. + bne oscan +now1 lda #$00 ;reset the joystick delay and set the first move + sta JOY1ST ;indicator to "no" + sta JOYDEL + dec HOURS ;decrease the hours counter + jmp oscan + +down lda HOURS + cmp #$18 + beq oscan + inc JOYDEL + lda JOY1ST + cmp #$01 + beq now2 + lda JOYDEL + cmp #$1E + bne oscan +now2 lda #$00 + sta JOY1ST + sta JOYDEL + inc HOURS ;increase the hours counter + jmp oscan + +left lda MINS + cmp #$01 + beq oscan + inc JOYDEL + lda JOY1ST + cmp #$01 + beq now3 + lda #$1E + cmp JOYDEL + bne oscan +now3 lda #$00 + sta JOY1ST + sta JOYDEL + dec MINS ;decrease the minutes counter + jmp oscan + +right lda MINS + cmp #$3c + beq oscan + inc JOYDEL + lda JOY1ST + cmp #$01 + beq now4 + lda #$1E + cmp JOYDEL + bne oscan +now4 lda #$00 + sta JOY1ST + sta JOYDEL + inc MINS ;increase the minutes counter + +oscan lda INTIM ;see if the timer has run out + BNE oscan + STA WSYNC + RTS + +zeros .byte 11100111b ;sprites are stored upsidedown, and there + .byte 10100101b ;are two copies of each number in each sprite + .byte 10100101b ;location. The unwanted number is stripped + .byte 10100101b ;with the AND command (AND #$0F for the right + .byte 10100101b ;number stripped, AND #F0 for the left) + .byte 10100101b ;then any two numbers can be combined with an + .byte 11100111b ;OR command. Neat huh? + +ones .byte 11100111b + .byte 01000010b + .byte 01000010b + .byte 01000010b + .byte 01000010b + .byte 11000110b + .byte 01000010b + +twos .byte 11100111b + .byte 10000100b + .byte 10000100b + .byte 11100111b + .byte 00100001b + .byte 00100001b + .byte 11100111b + +threes .byte 11100111b + .byte 00100001b + .byte 00100001b + .byte 11100111b + .byte 00100001b + .byte 00100001b + .byte 11100111b + +fours .byte 00100001b + .byte 00100001b + .byte 00100001b + .byte 11100111b + .byte 10100101b + .byte 10100101b + .byte 10000100b + +fives .byte 11100111b + .byte 00100001b + .byte 00100001b + .byte 11100111b + .byte 10000100b + .byte 10000100b + .byte 11100111b + +sixes .byte 11100111b + .byte 10100101b + .byte 10100101b + .byte 11100111b + .byte 10000100b + .byte 10000100b + .byte 11000110b + +sevens .byte 10000100b + .byte 10000100b + .byte 10000100b + .byte 01000010b + .byte 00100001b + .byte 00100001b + .byte 11100111b + +eights .byte 11100111b ;This code is (c)1997 by Chris "Crackers" Cracknell + .byte 10100101b ;and is placed in the Public Domain by the author. + .byte 10100101b ;Anyone is free to employ and distribute this code + .byte 11100111b ;as they see fit. + .byte 10100101b ; + .byte 10100101b ; + .byte 11100111b ; + ; +nines .byte 00100001b ;Well... if you're going to use this code in a + .byte 00100001b ;"Doomsday Machine" to destroy the world, then + .byte 00100001b ;I would rather you didn't. But otherwise, knock + .byte 11100111b ;yourself out with it. + .byte 10100101b ; + .byte 10100101b ;Actually... if the "Doomsday Machine" is just in + .byte 11100111b ;a game, then it's okay to use the code. + ; + org $FFFC ;Unless it's like the movie "War Games" where the + .word start ;computer running the game is hooked up to a real + .word start ;"Doomsday Machine" then it wouldn't be a good idea. + + + |