Enhanced Day of the Week by W.J. Brier
[Up to Source Code Repository]
Enhanced Day of the Week
This is an alternative to Paul Guertin's Day of the Week
program. It is longer but has the advantage of supporting a wider range of dates.
By W.J. Brier, 1 March 2008.
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;* *
;* COMPUTE THE DAY OF WEEK *
;* *
;* by W.J. Brier, March 2008 *
;* *
;* This 6502 assembly language program calculates the day of the week from any *
;* calendar date from September 14, 1752 to December 31, 9999. *
;* *
;* --------------------------------------------------------------------------- *
;* *
;* Copyright (C)2008 by W.J. Brier. All rights reserved. Permission is here- *
;* by granted to copy and redistribute this software, provided this copyright *
;* notice remains in the source code and proper attribution is given. Any re- *
;* distribution must be at no charge to the end user. This code MAY NOT be *
;* incorporated into any package intended for sale unless written permission *
;* has been given by the author. *
;* *
;* THERE IS NO WARRANTY OF ANY KIND WITH THIS SOFTWARE. It's free, so don't *
;* look a gift horse in the mouth. *
;* *
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;
; Calling Syntax:
;
; ldx #<date ;starting address of..,
; ldy #>date ;date data
; jsr cdow ;this subroutine
; sta dow ;day of week returned in .A
;
; .X and .Y are preserved.
;
; The information at DATE must be in the following format:
;
; Offset Data
; --------------------------------------------------------------
; $00 Year MSB. For example, if the year is 2008 then this
; value would be $07.
;
; $01 Year LSB. For example, if the year is 2008 then this
; value would be $D8.
;
; $02 Month, ranging from $01 to $0C (12).
;
; $03 Date, ranging from $01 to $1F (31).
; --------------------------------------------------------------
;
; Upon return, .A will contain the day of the week in the range $01-$07,
; with $01 being Sunday. Execution time will typically be 4150 clock
; cycles, depending on the supplied values. No range checking is perf-
; ormed. A bogus date will produce a bogus result.
;
;===============================================================================
;
;DECLARATIONS
;
_origin_ =$02000 ;assembly address
;
zpptr =$10 ;working ZP pointer
;
; --------------------------------------------------------
; Redefine the above assignments to suit your application.
; --------------------------------------------------------
;
dayswk =7 ;days in a week
march =$03 ;March in binary
s_bits =8 ;number of bits in a byte
s_byte =1 ;size of a byte or char
s_date =4 ;size of the input date
s_dword =4 ;size of a double word
s_word =2 ;size of a word
y2fac =4 ;Y2 computation factor
y3fac =100 ;Y3 computation factor
y4fac =400 ;Y4 computation factor
;
;===============================================================================
;
;COMPUTE DAY OF WEEK
;
*=_origin_ ;set program counter
;
cdow stx zpptr ;save pointer to...
sty zpptr+1 ;date info
ldy #s_date-1 ;bytes in date -1
;
cdow01 lda (zpptr),y ;copy user's date...
sta userdate,y ;into our storage
dey
bpl cdow01
;
lda month ;month
ldx yearlo ;year LSB
ldy yearhi ;year MSB
pha ;save month
cmp #march ;month March or later?
bcs cdow03 ;yes, no year adjustment
;
txa ;year LSB
sec
sbc #1 ;move back a year
bcs cdow02
;
dey ;adjust MSB
;
cdow02 tax ;hold LSB
;
cdow03 stx y1 ;save Y1
sty y1+1
;
; ------------
; compute Y1/4
; ------------
;
jsr stafaca ;store Y1 in accummulator #1
ldx #<y2fac ;4
ldy #>y2fac
jsr stafacb ;copy to accummulator #2
jsr dpdiv ;Y2=Y1/4
stx y2 ;store
sty y2+1
;
; ---------------
; compute Y1/100)
; ---------------
;
jsr stay1fac ;copy Y1 to accummulator #1
ldx #<y3fac
ldy #>y3fac
jsr stafacb ;copy to accummulator #2
jsr dpdiv ;Y3=Y1/100
stx y3 ;store
sty y3+1
;
; --------------
; compute Y1/400
; --------------
;
jsr stay1fac
ldx #<y4fac
ldy #>y4fac
jsr stafacb ;copy to accummulator #2
jsr dpdiv ;Y4=Y1/400
stx y4 ;store
sty y4+1
;
; -------------
; combine terms
; -------------
;
clc
lda y1 ;Y1
adc y2 ;Y2
sta acm1
lda y1+1
adc y2+1
sta acm1+1
sec
lda acm1
sbc y3 ;Y3
sta acm1
lda acm1+1
sbc y3+1
sta acm1+1
clc
lda acm1
adc y4 ;Y4
sta acm1
lda acm1+1
adc y4+1
sta acm1+1
pla ;get month
tax ;change 1-12 to...
dex ;0-11
clc
lda acm1 ;combined terms
adc dowmctab,x ;month comp factor
bcc cdow04
;
inc acm1+1
;
cdow04 sta acm1
clc
lda date ;date
adc acm1 ;last term
bcc cdow05
;
inc acm1+1
;
cdow05 sta acm1
ldx #<dayswk ;number of days in a week
ldy #>dayswk
jsr stafacb ;copy to accummulator #2
jsr dpdiv ;ACM1=ACM1 mod 7
adc #1 ;0-6 --> 1-7...
;
; -------------------------------------------------------
; remove the above ADC #1 instruction for a 0-6 DOW range
; -------------------------------------------------------
;
ldx zpptr ;restore
ldy zpptr+1 ;likewise
rts ;return day of week in .A
;
;================================================================================
;
;DOUBLE-PRECISION DIVISION
;
; -----------------------------------------
; acm1 = 16 bit dividend
; acm2 = 16 bit divisor
; -----------------------------------------
; acm1 = 16 bit quotient
; .A = remainder
; .X = quotient LSB
; .Y = quotient MSB
;
; The remainder is also available in acm1+2.
;
; No check is made for division by zero.
; ------------------------------------------
;
dpdiv lda #0
sta acm1+s_word ;clear dividend hi bits
sta acm1+s_word+s_byte
ldx #s_bits*s_word ;bits to process
clc
;
dpdiv01 rol acm1 ;rotate dividend
rol acm1+s_byte
rol acm1+s_word
rol acm1+s_word+s_byte
sec
lda acm1+s_word
sbc acm2 ;subtract divisor
tay
lda acm1+s_word+s_byte
sbc acm2+s_byte
bcc dpdiv02
;
sty acm1+s_word ;save partial quotient
sta acm1+s_word+s_byte
;
dpdiv02 dex
bne dpdiv01 ;next
;
rol acm1 ;rotate in last carry to...
rol acm1+s_byte ;finish quotient
lda acm1+s_word ;get remainder LSB
ldx acm1 ;get quotient LSB
ldy acm1+s_byte ;get quotient MSB
rts
;
;================================================================================
;
;STORE Y1 INTO ACCUMMULATOR #1
;
stay1fac ldx y1
ldy y1+1
;
;================================================================================
;
;STORE INTO ACCUMMULATOR #1
;
stafaca stx acm1
sty acm1+1
rts
;
;================================================================================
;
;STORE INTO ACCUMMULATOR #2
;
stafacb stx acm2
sty acm2+1
rts
;
;===============================================================================
;
;COMPENSATION TABLE
;
dowmctab .byte 0 ;January
.byte 3 ;February
.byte 2 ;March
.byte 5 ;April
.byte 0 ;May
.byte 3 ;June
.byte 5 ;July
.byte 1 ;August
.byte 4 ;September
.byte 6 ;October
.byte 2 ;November
.byte 4 ;December
;
;===============================================================================
;
;WORKING STORAGE
;
acm1 *=*+s_dword ;accummulator #1
acm2 *=*+s_word ;accummulator #2
y1 *=*+s_word ;adjusted year (Y1)
y2 *=*+s_word ;Y1/4
y3 *=*+s_word ;Y1/100
y4 *=*+s_word ;Y1/400
;
; -------------------------------------------------------------
; The above locations should be defined on page zero if room is
; available. Execution time will be reduced about 20 percent.
; -------------------------------------------------------------
;
userdate *=*+s_date ;input date storage...
;
yearhi =userdate ;year MSB
yearlo =yearhi+s_byte ;year LSB
month =yearlo+s_byte ;month
date =month+s_byte ;date
;
;===============================================================================
.end
Last page update: March 1, 2009.