TOYCSR = 177526 / April 6, 2000 - sms@moe.2bsd.com / Remove the cpu type (93 or 94) restriction and probe for the TOY register. / Some systems have clock boards added _and_ P11 (Begemot Computer Associates' / PDP-11 emulator) have support for the TOY clock. / / April 10, 1997 - sms@moe.2bsd.com / The day of week calculation was incorrect and would return -1 for Saturday / rather than 6. Alan Sieving spotted this one too (toyset.s must be favorite / reading material ;-)) / / February 6, 1997 - sms@moe.2bsd.com / Forgot that May has 31 days. Thanks to Alan Sieving (ars@quickware.com) for / spotting this. / / August 21, 1993 - Steven M. Schultz (sms@wlv.iipo.gtegsc.com) / This is a standalone program which is used to set the TOY (Time Of Year) / clock on a PDP-11/93 or 11/94. If this program is run on other than a / 93 or 94 an error is printed and the program 'exits' back to the boot / runtime. / / The current date is printed (in the same format used to enter the new date) / and the prompt "Toyset> " is displayed. At that time a string of the form: / YYMMDDHHMM[.SS]\n is entered. The seconds "SS" are optional, if not entered / the seconds will be set to 0. Any invalid input string simply loops back / to the top of the program. / / To not change the date and time simply hit a return and the program will / exit, returning control to 'boot'. .globl _main, csv, cret, _printf, _gets, _exit, _module .globl nofault _main: main: jsr r5,csv / srt0.o sets up a C frame... jsr pc,init / probe for clock, display current TOY clrb line / init buffer mov $line,-(sp) jsr pc,_gets / get input from user tst r0 bgt 1f leave: jsr pc,_exit / exit on error 1: tstb line / did we get anything? beq leave / nope - go exit clr r3 / clear '.' seen flag mov $line,r4 / point to input data 2: movb (r4)+,r0 beq 1f / end of string - go validate it cmpb r0,$'. / are there seconds present? bne 2b / not yet - go try another byte clrb -1(r4) / zap '.' - separating two parts of date mov r4,r3 / set seconds present flag tstb (r3)+ / must have two... beq main / and only two... tstb (r3)+ / characters after... beq main / the '.'... tstb (r3) / followed by a ... bne main / null character. 1: clrb seconds / assume no seconds (start of minute) tst r3 / do we have seconds? beq nosec / no - br cmpb -(r3),-(r3) / back up to beginning of seconds string mov r3,-(sp) jsr pc,atoi2 / convert two digits to binary tst (sp)+ cmp r0,$59. / range check bhi main / error - go back to top movb r0,seconds / save for later nosec: sub $line+1,r4 / number of characters in date string cmp r4,$10. / _must_ have *exactly* "YYMMDDhhmm" bne main / back to the top on error mov $line,r4 / point to start of date string mov r4,-(sp) jsr pc,atoi2 / convert 2 digits to binary (year) tst (sp)+ cmp r4,$-1 / error? beq main / yes - go back to top cmp r0,$69. / before [19]69? bgt 1f / no - it's a 1970-1999 year - br add $100.,r0 / 21st century and 11s are still around! 1: movb r0,year / save year for later cmpb (r4)+,(r4)+ / skip two digits, move to month mov r4,-(sp) jsr pc,atoi2 / convert month to binary tst (sp)+ cmp r0,$12. / range check bhi main / back to top on too high cmpb (r4)+,(r4)+ / move on to day of month movb r0,month / save month for later beq main / can't have a month 0 mov r4,-(sp) jsr pc,atoi2 / convert day of month to binary tst (sp)+ movb month,r1 cmpb r0,Mtab-1(r1) / crude check (no leap year case) bhi main / on day of month movb r0,day / save the day for later cmpb (r4)+,(r4)+ / move along to hours of day mov r4,-(sp) jsr pc,atoi2 / convert hours of day to binary tst (sp)+ cmp r0,$23. / can't have more than 23 hours bhi main / but 00 is ok (midnight) movb r0,hours / save hours for later cmpb (r4)+,(r4)+ / move over to minutes mov r4,-(sp) jsr pc,atoi2 / convert minutes to binary tst (sp)+ cmp r0,$59. / can't have more than 59 minutes bhi main / back to top on out of range error movb r0,minutes / save for later / need to compute the "day of week". why the TOY clock couldn't figure / this out (or do without) itself i don't know. jsr pc,t2dow / find out "day of week" movb r0,dow / save for later / now we have to convert the binary data to BCD. We needed (or preferred) / the binary form for ease of range checking but the TOY wants BCD. Besides / i like to improve my typing skills ;-) movb seconds,r1 jsr pc,tobcd movb r0,bcd+1 / seconds movb minutes,r1 jsr pc,tobcd movb r0,bcd+2 / minutes movb hours,r1 jsr pc,tobcd movb r0,bcd+3 / hours movb dow,r1 jsr pc,tobcd movb r0,bcd+4 / day of week movb day,r1 jsr pc,tobcd movb r0,bcd+5 / day of month movb month,r1 jsr pc,tobcd movb r0,bcd+6 / month of year movb year,r1 jsr pc,tobcd movb r0,bcd+7 / Now initialize the TOY by sending the 'recognition' sequence. We have / to inline this because immediately after the recognition sequence must / come the 'write' of data - a 'read' to save the contents of the CSR / would tell the TOY we're reading data. *sigh* tst *$TOYCSR / strobe the clock register clr -(sp) / save previous high byte of register movb *$TOYCSR+1,(sp) / only bit 8 belongs to TOY! bic $1,(sp) / make sure bit 8 (TOY bit) is clear mov $2,r2 / number of double words to send clock 1: mov $35305,r0 / first word of recognition code jsr pc,toyload / send it to clock mov $56243,r0 / second word jsr pc,toyload / send it sob r2,1b / do the whole thing twice / Now write the data to the TOY without an intervening 'tst' or 'movb' / to the CSR. mov bcd,r0 / first two bytes jsr pc,toyload mov bcd+2,r0 / bytes 3 and 4 jsr pc,toyload mov bcd+4,r0 jsr pc,toyload / bytes 5 and 6 mov bcd+6,r0 jsr pc,toyload / bytes 7 and 8 tst (sp)+ / clean stack now, we're done clr r0 / "exit" status. ha! ;-) jsr pc,_exit / Probe for the TOY register. If present initialize the TOY and read the / current date otherwise print an error message and exit. Convert the date / into printable form and print it out along with the prompt. init: mov $1f, nofault / catch fault if no TOY clock tst *$TOYCSR br 2f / we have a clock 1: mov $errmsg1,-(sp) jsr pc,_printf mov $1,r0 jsr pc,_exit 2: clr nofault / faults are serious again jsr pc,initoy / init the TOY clock mov $bcd,-(sp) / buffer for the date jsr pc,_gettoy / read the TOY tst (sp)+ mov $timbuf,r3 / where to put printable form of date clr r1 bisb bcd+7,r1 / year in bcd jsr pc,bcd2msg movb bcd+6,r1 / month in bcd jsr pc,bcd2msg movb bcd+5,r1 / day of month in bcd jsr pc,bcd2msg movb bcd+3,r1 / hour of day in bcd jsr pc,bcd2msg movb bcd+2,r1 / minute of hour in bcd jsr pc,bcd2msg movb $'.,(r3)+ movb bcd+1,r1 / seconds of minute in bcd jsr pc,bcd2msg mov $timmsg,-(sp) jsr pc,_printf tst (sp)+ rts pc / convert two bytes of ascii pointed to by 2(sp) into a binary number. / the return value is in r0. atoi2: movb *2(sp),r1 inc 2(sp) movb *2(sp),r0 sub $'0,r1 sub $'0,r0 mul $10.,r1 add r1,r0 rts pc / convert a byte of BCD (in r1) two to ascii digits and place those / at (r3)+ and (r3)+ respectively. bcd2msg: clr r0 div $16.,r0 add $'0,r0 add $'0,r1 movb r0,(r3)+ movb r1,(r3)+ rts pc / convert a binary number (in r1) to a byte containing two bcd digits. / return result in r0. tobcd: clr r0 div $100.,r0 / truncate to max of 99 clr r0 div $10.,r0 ash $4,r0 bis r1,r0 rts pc / To calculate the day of the week (Sunday = 1) an algorithm found in / "The Ready Reference (r) Weekly Planner 1986 ((c) 1986 Ready Reference)" / is used. t2dow: jsr r5,csv / save registers movb year,r4 / low two digits (93) of year mov r4,r0 asr r0 / divide by 4 asr r0 / ignoring any remainder add r0,r4 / add to year movb day,r0 add r0,r4 / add day of month movb month,r0 movb m_magic-1(r0),r3 cmp r0,$2 / February Or January? bgt 1f / no - br movb year,r0 add $1900.,r0 mov r0,-(sp) jsr pc,isleap / are we in a leap year? mov r0,(sp)+ beq 1f / no - br dec r3 / adjust number from magic month table 1: add r3,r4 / add magic number to total cmpb year,$69. / before 1969? bgt 2f / no - br, we're in the 20th century add $6,r4 / adjustment for 21st century 2: mov r4,r1 clr r0 div $7,r0 / divide total by 7 dec r1 / Saturday or Sunday? bgt 3f / no - br add $7,r1 / yes - set Saturday to 6, Sunday to 7 3: mov r1,r0 / put return value in right place jmp cret / 1 = Monday ... 7 = Sunday / (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0) isleap: clr r0 mov 2(sp),r1 / get year bit $3,r1 / easy check for "mod 4" bne 1f / can't be a leap - br div $100.,r0 / % 100 tst r1 / check remainder bne 2f bit $3,r0 / % 400 beq 2f 1: clr r0 rts pc 2: mov $1,r0 rts pc initoy: tst *$TOYCSR / strobe the clock register clr -(sp) / save previous high byte of register movb *$TOYCSR+1,(sp) / only bit 8 belongs to TOY! bic $1,(sp) / make sure bit 8 (TOY bit) is clear mov $2,r2 / number of double words to send clock 1: mov $35305,r0 / first word of recognition code jsr pc,toyload / send it to clock mov $56243,r0 / second word jsr pc,toyload / send it sob r2,1b / do the whole thing twice tst (sp)+ / clean stack rts pc / send contents of r0 to the TOY. 2(sp) has the old bits 9-15, bit 8 / has been cleared. toyload: mov $16.,r1 / number of bits to send 1: mov r0,r3 / scratch copy bic $177776,r3 / clear all but bit being sent bis 2(sp),r3 / merge in old_csr_bits movb r3,*$TOYCSR+1 / send bit to clock asr r0 / shift pattern down sob r1,1b / do all 16 bits in the word rts pc .globl _gettoy _gettoy: / (void)gettoy(&char[8]); jsr r5,csv / C callable mov 4(r5),r2 / buffer address mov $4,r3 / number of words in buffer 1: mov $16.,r4 / number of bits in word 2: movb *$TOYCSR+1,r0 / low bit of top byte is a clock bit asr r0 / put it in carry ror r1 / ripple in at top end of r1 sob r4,2b / do all 16 bits mov r1,(r2)+ / store the word in the buffer sob r3,1b / do all 4 words jmp cret / and return .data Mtab: .byte 31.,29.,31.,30.,31.,30. .byte 31.,31.,30.,31.,30.,31. m_magic: .byte 1,4,4,0,2,5,0,3,6,1,4,6 errmsg1: timmsg: timbuf: .=.+13. / room for YYMMDDhhmm.ss <\n> \0> _module: .even .bss seconds: .=.+1 minutes: .=.+1 hours: .=.+1 day: .=.+1 month: .=.+1 year: .=.+1 dow: .=.+1 .even bcd: .=.+8. line: .=.+64.