[stella] 2600 Digital Clock (source code)

Subject: [stella] 2600 Digital Clock (source code)
From: crackers@xxxxxxxx
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

VSYNC	=	$00
VBLANK	=	$01
WSYNC	=	$02
NUSIZ0	=	$04
NUSIZ1	=	$05
COLUPF 	=	$08
COLUBK	=	$09
PF0	=	$0D
PF1	=	$0E
PF2	=	$0F
SWCHA	=	$280
INTIM	=	$284
TIM64T	=	$296
CTRLPF	=	$0A
COLUP0	=	$06
COLUP1	=	$07
GP0	=	$1B
GP1	=	$1C
HMOVE	=	$2a
RESP0	=	$10
RESP1	=	$11

;RAM

TEMP	=	$80	;2 bytes for temporary data
SECS	=	$82	;seconds counter
MINS	=	$83	;minutes counter
HOURS	=	$84	;hours counter
JOYDEL	=	$85	;joystick delay variable
JOY1ST	=	$86	;joystick first move variable
SPRITEA	=	$87	;8 bytes for the first sprite
SPRITEB	=	$8F	;8 bytes for the second sprite
RMINS	=	$97	;real minutes
RHOURS	=	$98	;real hours
FRAMES	=	$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 %11100111	;sprites are stored upsidedown, and there
	.byte %10100101	;are two copies of each number in each sprite
	.byte %10100101	;location. The unwanted number is stripped
	.byte %10100101	;with the AND command (AND #$0F for the right
	.byte %10100101	;number stripped, AND #F0 for the left)
	.byte %10100101	;then any two numbers can be combined with an 
	.byte %11100111	;OR command. Neat huh?

ones	.byte %11100111
	.byte %01000010
	.byte %01000010
	.byte %01000010
	.byte %01000010
	.byte %11000110
	.byte %01000010

twos	.byte %11100111
	.byte %10000100
	.byte %10000100
	.byte %11100111
	.byte %00100001
	.byte %00100001
	.byte %11100111

threes	.byte %11100111
	.byte %00100001
	.byte %00100001
	.byte %11100111
	.byte %00100001
	.byte %00100001
	.byte %11100111

fours	.byte %00100001
	.byte %00100001
	.byte %00100001
	.byte %11100111
	.byte %10100101
	.byte %10100101
	.byte %10000100

fives	.byte %11100111
	.byte %00100001
	.byte %00100001
	.byte %11100111
	.byte %10000100
	.byte %10000100
	.byte %11100111

sixes	.byte %11100111
	.byte %10100101
	.byte %10100101
	.byte %11100111
	.byte %10000100
	.byte %10000100
	.byte %11000110

sevens	.byte %10000100
	.byte %10000100
	.byte %10000100
	.byte %01000010
	.byte %00100001
	.byte %00100001
	.byte %11100111

eights	.byte %11100111	;This code is (c)1997 by Chris "Crackers" Cracknell
	.byte %10100101	;and is placed in the Public Domain by the author.
	.byte %10100101	;Anyone is free to employ and distribute this code
	.byte %11100111	;as they see fit.
	.byte %10100101	;
	.byte %10100101	;
	.byte %11100111	;
			;
nines	.byte %00100001	;Well... if you're going to use this code in a
	.byte %00100001	;"Doomsday Machine" to destroy the world, then
	.byte %00100001	;I would rather you didn't. But otherwise, knock
	.byte %11100111	;yourself out with it.
	.byte %10100101	;
	.byte %10100101	;Actually... if the "Doomsday Machine" is just in 
	.byte %11100111	;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.

----------------------------------------------------------------------------


                                  CRACKERS
                      (Anti-Doomsday Machine from hell!!!)

 




-- 

Accordionist - Wethifl Musician - Atari 2600 Collector | /\/\
*NEW CrAB URL* http://www.hwcn.org/~ad329/crab.html ***| \^^/
Bira Bira Devotee - FES Member - Samurai Pizza Cats Fan| =\/=


--
Archives updated once/day at http://www.biglist.com/lists/stella/archives/
Unsubscribing and other info at http://www.biglist.com/lists/stella/stella.html

Current Thread