DAY of the WEEK

Started by BigDumbDinosaur, May 21, 2008, 02:40 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

BigDumbDinosaur

Here's an assembly language program that computes the day of the week for any Gregorian date from February 24, 1582 to December 31, 9999 inclusive.  Please read the comments to see how to pass a date into this program and what to expect as output.  Dates earlier than 1582/02/24 can be passed but will produce erroneous output, as the calendar system in general use prior to that date was the (less accurate) Julian system.  Note that the British Empire didn't switch to the Gregorian calendar until September 14, 1752.

You can also download the source file via the link below.

;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;*                                                                             *
;*                        CALCULATE THE DAY OF THE WEEK                        *
;*                                                                             *
;*                       by BigDumbDinosaur,  March 1997                       *
;*                                                                             *
;* This 6502 assembly language program calculates the day of the week for  any *
;* calendar date from February 24, 1582 to December 31, 9999 inclusive.        *
;*                                                                             *
;* --------------------------------------------------------------------------- *
;*                                                                             *
;* Copyright (C)1997 by BigDumbDinosaur.  All rights reserved.                 *
;*                                                                             *
;* Permission is granted to copy and redistribute this software, provided this *
;* copyright notice is retained and proper attribution is given.               *
;*                                                                             *
;* 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 1997 then this
;          value would be $07.
;
;   $01    Year LSB.  For example, if the year is 1997 then this
;          value would be $CD.
;
;   $02    Month, ranging from $01 to $0C.
;
;   $03    Date, ranging from $01 to $1F.
; --------------------------------------------------------------
;
; 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 performed.  A bogus  date  will
; produce a bogus result.
;
;===============================================================================
;
;DECLARATIONS
;
_origin_ =$02000               ;assembly address
;
zpptr    =$FA                  ;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
;
; ------------------------
; evaluate Y -= M < 3 (Y1)
; ------------------------
;
         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 Y2 (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 Y3 (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 Y4 (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 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,3,2,5,0,3,5,1,4,6,2,4
;
;===============================================================================
;
;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 can 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
;
;===============================================================================
x86?  We ain't got no x86.  We don't need no stinking x86!