Subject: Standalone TOY clock setting program (#151) Index: sys/pdpstand/{Makefile,toyset.s} 2.11BSD Description: The TOY (Time Of Year) clock of a KDJ-11E (11/93 or 11/94) is difficult/confusing to change from the console monitor, especially if the manual is missing or not at hand. Repeat-By: Observation/experience. Fix: Below is a new program which can be loaded by /boot (or by the boot program on a bootable tape) and used to set the TOY clock. The TOY clock must be set according to GMT (well, UCT - same thing;-)). The /etc/zoneinfo files are used by the system to take into account the timezone and daylight savings time. The format of the date string expected by 'toyset' is the same as the date(1) command: YYMMDDHHmm[.ss] See the man page for date(1) for additional details. After unshar'ing the file below (which includes a patch to the pdpstand/Makefile as well as the source to the 'toyset' program) you should: cd /sys/pdpstand patch < /tmp/c make toyset install -s toyset /toyset To run the program you specify 'xx(dd,0)toyset' at the ':' prompt of 'boot': : ra(0,0)toyset The program prints out the current TOY setting and then prompts: Current TOY: 9112160736.19 Toyset> At this point you enter a string like this: 9308241330.45 which will set the TOY to "August 24, 1993 13:30:45" Any invalid input causes the program to reprompt. If the date string is accepted the 'toyset' program exits and returns control back to 'boot' at which point you can load the system. Only the 11/93 and 11/94 have the TOY clock. Running 'toyset' other pdp-11s simply gives the error message: Cputype is not 93 or 94. No TOY present and returns to 'boot'. Enjoy! ========================cut here========================================= #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # /tmp/c # /sys/pdpstand/toyset.s # This archive created: Tue Aug 24 20:46:24 1993 export PATH; PATH=/bin:/usr/bin:$PATH if test -f '/tmp/c' then echo shar: "will not over-write existing file '/tmp/c'" else sed 's/^X//' << \SHAR_EOF > '/tmp/c' X*** /sys/pdpstand/Makefile.old Wed Mar 18 00:21:44 1992 X--- /sys/pdpstand/Makefile Sat Aug 21 20:58:02 1993 X*************** X*** 31,37 **** X ht.o tm.o ts.o tmscp.o \ X xp.o rk.o rl.o br.o hk.o si.o ra.o X X! ALL= mtboot boot mkfs restor icheck maketape X X .c.o: X cc ${CFLAGS} -c $*.c X--- 31,37 ---- X ht.o tm.o ts.o tmscp.o \ X xp.o rk.o rl.o br.o hk.o si.o ra.o X X! ALL= mtboot boot mkfs restor icheck maketape toyset X X .c.o: X cc ${CFLAGS} -c $*.c X*************** X*** 119,127 **** X icheck: srt0.o conf.o libsa.a icheck.o X ld -o $@ srt0.o conf.o $@.o libsa.a -lc X X- X maketape: maketape.c X cc -o $@ maketape.c X X tags: FRC X rm -f tags X--- 119,129 ---- X icheck: srt0.o conf.o libsa.a icheck.o X ld -o $@ srt0.o conf.o $@.o libsa.a -lc X X maketape: maketape.c X cc -o $@ maketape.c X+ X+ toyset: toyset.o srt0.o conf.o libsa.a X+ ld -o $@ srt0.o conf.o $@.o libsa.a -lc X X tags: FRC X rm -f tags SHAR_EOF fi if test -f '/sys/pdpstand/toyset.s' then echo shar: "will not over-write existing file '/sys/pdpstand/toyset.s'" else sed 's/^X//' << \SHAR_EOF > '/sys/pdpstand/toyset.s' XTOYCSR = 177526 X X/ August 21, 1993 - Steven M. Schultz (sms@wlv.iipo.gtegsc.com) X/ This is a standalone program which is used to set the TOY (Time Of Year) X/ clock on a PDP-11/93 or 11/94. If this program is run on other than a X/ 93 or 94 an error is printed and the program 'exits' back to the boot X/ runtime. X/ X/ The current date is printed (in the same format used to enter the new date) X/ and the prompt "Toyset> " is displayed. At that time a string of the form: X/ YYMMDDHHMM[.SS]\n is entered. The seconds "SS" are optional, if not entered X/ the seconds will be set to 0. Any invalid input string simply loops back X/ to the top of the program. X/ X/ To not change the date and time simply hit a return and the program will X/ exit, returning control to 'boot'. X X .globl _main, csv, cret, _printf, _gets, _exit, _cputype, _module X X_main: Xmain: X jsr r5,csv / srt0.o sets up a C frame... X X jsr pc,init / check cpu type and display current TOY X X clrb line / init buffer X mov $line,-(sp) X jsr pc,_gets / get input from user X tst r0 X bgt 1f Xleave: X jsr pc,_exit / exit on error X1: X tstb line / did we get anything? X beq leave / nope - go exit X X clr r3 / clear '.' seen flag X mov $line,r4 / point to input data X2: X movb (r4)+,r0 X beq 1f / end of string - go validate it X cmpb r0,$'. / are there seconds present? X bne 2b / not yet - go try another byte X clrb -1(r4) / zap '.' - separating two parts of date X mov r4,r3 / set seconds present flag X tstb (r3)+ / must have two... X beq main / and only two... X tstb (r3)+ / characters after... X beq main / the '.'... X tstb (r3) / followed by a ... X bne main / null character. X1: X clrb seconds / assume no seconds (start of minute) X tst r3 / do we have seconds? X beq nosec / no - br X cmpb -(r3),-(r3) / back up to beginning of seconds string X mov r3,-(sp) X jsr pc,atoi2 / convert two digits to binary X tst (sp)+ X cmp r0,$59. / range check X bhi main / error - go back to top X movb r0,seconds / save for later Xnosec: X sub $line+1,r4 / number of characters in date string X cmp r4,$10. / _must_ have *exactly* "YYMMDDhhmm" X bne main / back to the top on error X mov $line,r4 / point to start of date string X mov r4,-(sp) X jsr pc,atoi2 / convert 2 digits to binary (year) X tst (sp)+ X cmp r4,$-1 / error? X beq main / yes - go back to top X cmp r0,$69. / before [19]69? X bgt 1f / no - it's a 1970-1999 year - br X add $100.,r0 / 21st century and 11s are still around! X1: X movb r0,year / save year for later X cmpb (r4)+,(r4)+ / skip two digits, move to month X mov r4,-(sp) X jsr pc,atoi2 / convert month to binary X tst (sp)+ X cmp r0,$12. / range check X bhi main / back to top on too high X cmpb (r4)+,(r4)+ / move on to day of month X movb r0,month / save month for later X beq main / can't have a month 0 X mov r4,-(sp) X jsr pc,atoi2 / convert day of month to binary X tst (sp)+ X movb month,r1 X cmpb r0,Mtab-1(r1) / crude check (no leap year case) X bhi main / on day of month X movb r0,day / save the day for later X cmpb (r4)+,(r4)+ / move along to hours of day X mov r4,-(sp) X jsr pc,atoi2 / convert hours of day to binary X tst (sp)+ X cmp r0,$23. / can't have more than 23 hours X bhi main / but 00 is ok (midnight) X movb r0,hours / save hours for later X cmpb (r4)+,(r4)+ / move over to minutes X mov r4,-(sp) X jsr pc,atoi2 / convert minutes to binary X tst (sp)+ X cmp r0,$59. / can't have more than 59 minutes X bhi main / back to top on out of range error X movb r0,minutes / save for later X X/ need to compute the "day of week". why the TOY clock couldn't figure X/ this out (or do without) itself i don't know. X X jsr pc,t2dow / find out "day of week" X movb r0,dow / save for later X X/ now we have to convert the binary data to BCD. We needed (or preferred) X/ the binary form for ease of range checking but the TOY wants BCD. Besides X/ i like to improve my typing skills ;-) X X movb seconds,r1 X jsr pc,tobcd X movb r0,bcd+1 / seconds X X movb minutes,r1 X jsr pc,tobcd X movb r0,bcd+2 / minutes X X movb hours,r1 X jsr pc,tobcd X movb r0,bcd+3 / hours X X movb dow,r1 X jsr pc,tobcd X movb r0,bcd+4 / day of week X X movb day,r1 X jsr pc,tobcd X movb r0,bcd+5 / day of month X X movb month,r1 X jsr pc,tobcd X movb r0,bcd+6 / month of year X X movb year,r1 X jsr pc,tobcd X movb r0,bcd+7 X X/ Now initialize the TOY by sending the 'recognition' sequence. We have X/ to inline this because immediately after the recognition sequence must X/ come the 'write' of data - a 'read' to save the contents of the CSR X/ would tell the TOY we're reading data. *sigh* X X tst *$TOYCSR / strobe the clock register X clr -(sp) / save previous high byte of register X movb *$TOYCSR+1,(sp) / only bit 8 belongs to TOY! X bic $1,(sp) / make sure bit 8 (TOY bit) is clear X mov $2,r2 / number of double words to send clock X1: X mov $35305,r0 / first word of recognition code X jsr pc,toyload / send it to clock X mov $56243,r0 / second word X jsr pc,toyload / send it X sob r2,1b / do the whole thing twice X X/ Now write the data to the TOY without an intervening 'tst' or 'movb' X/ to the CSR. X X mov bcd,r0 / first two bytes X jsr pc,toyload X mov bcd+2,r0 / bytes 3 and 4 X jsr pc,toyload X mov bcd+4,r0 X jsr pc,toyload / bytes 5 and 6 X mov bcd+6,r0 X jsr pc,toyload / bytes 7 and 8 X X tst (sp)+ / clean stack now, we're done X clr r0 / "exit" status. ha! ;-) X jsr pc,_exit X X/ Check the cpu type - only the 93 and 94 have a TOY. Then initialize X/ the TOY and read the current date. Convert the date into printable X/ form and print it out along with the prompt. X Xinit: X cmp _cputype,$93. X beq 1f X cmp _cputype,$94. X beq 1f X mov $errmsg1,-(sp) X jsr pc,_printf X mov $1,r0 X jsr pc,_exit X1: X jsr pc,initoy / init the TOY clock X mov $bcd,-(sp) / buffer for the date X jsr pc,_gettoy / read the TOY X tst (sp)+ X mov $timbuf,r3 / where to put printable form of date X clr r1 X bisb bcd+7,r1 / year in bcd X jsr pc,bcd2msg X movb bcd+6,r1 / month in bcd X jsr pc,bcd2msg X movb bcd+5,r1 / day of month in bcd X jsr pc,bcd2msg X movb bcd+3,r1 / hour of day in bcd X jsr pc,bcd2msg X movb bcd+2,r1 / minute of hour in bcd X jsr pc,bcd2msg X movb $'.,(r3)+ X movb bcd+1,r1 / seconds of minute in bcd X jsr pc,bcd2msg X mov $timmsg,-(sp) X jsr pc,_printf X tst (sp)+ X rts pc X X/ convert two bytes of ascii pointed to by 2(sp) into a binary number. X/ the return value is in r0. X Xatoi2: X movb *2(sp),r1 X inc 2(sp) X movb *2(sp),r0 X sub $'0,r1 X sub $'0,r0 X mul $10.,r1 X add r1,r0 X rts pc X X/ convert a byte of BCD (in r1) two to ascii digits and place those X/ at (r3)+ and (r3)+ respectively. X Xbcd2msg: X clr r0 X div $16.,r0 X add $'0,r0 X add $'0,r1 X movb r0,(r3)+ X movb r1,(r3)+ X rts pc X X/ convert a binary number (in r1) to a byte containing two bcd digits. X/ return result in r0. X Xtobcd: X clr r0 X div $100.,r0 / truncate to max of 99 X clr r0 X div $10.,r0 X ash $4,r0 X bis r1,r0 X rts pc X X/ To calculate the day of the week (Sunday = 1) an algorithm found in X/ "The Ready Reference (r) Weekly Planner 1986 ((c) 1986 Ready Reference)" X/ is used. X Xt2dow: X jsr r5,csv / save registers X movb year,r4 / low two digits (93) of year X mov r4,r0 X asr r0 / divide by 4 X asr r0 / ignoring any remainder X add r0,r4 / add to year X movb day,r0 X add r0,r4 / add day of month X movb month,r0 X movb m_magic-1(r0),r3 X cmp r0,$2 / February Or January? X bgt 1f / no - br X movb year,r0 X add $1900.,r0 X mov r0,-(sp) X jsr pc,isleap / are we in a leap year? X mov r0,(sp)+ X beq 1f / no - br X dec r3 / adjust number from magic month table X1: X add r3,r4 / add magic number to total X cmpb year,$69. / before 1969? X bgt 2f / no - br, we're in the 20th century X add $6,r4 / adjustment for 21st century X2: X mov r4,r1 X clr r0 X div $7,r0 / divide total by 7 X dec r1 / Sunday? X bne 3f / no - br X mov $7,r1 / yes - set it to day 7 X3: X mov r1,r0 / put return value in right place X jmp cret X X/ (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0) X Xisleap: X clr r0 X mov 2(sp),r1 / get year X bit $3,r1 / easy check for "mod 4" X bne 1f / can't be a leap - br X div $100.,r0 / % 100 X tst r1 / check remainder X bne 2f X bit $3,r0 / % 400 X beq 2f X1: X clr r0 X rts pc X2: X mov $1,r0 X rts pc X Xinitoy: X tst *$TOYCSR / strobe the clock register X clr -(sp) / save previous high byte of register X movb *$TOYCSR+1,(sp) / only bit 8 belongs to TOY! X bic $1,(sp) / make sure bit 8 (TOY bit) is clear X mov $2,r2 / number of double words to send clock X1: X mov $35305,r0 / first word of recognition code X jsr pc,toyload / send it to clock X mov $56243,r0 / second word X jsr pc,toyload / send it X sob r2,1b / do the whole thing twice X tst (sp)+ / clean stack X rts pc X X/ send contents of r0 to the TOY. 2(sp) has the old bits 9-15, bit 8 X/ has been cleared. X Xtoyload: X mov $16.,r1 / number of bits to send X1: X mov r0,r3 / scratch copy X bic $177776,r3 / clear all but bit being sent X bis 2(sp),r3 / merge in old_csr_bits X movb r3,*$TOYCSR+1 / send bit to clock X asr r0 / shift pattern down X sob r1,1b / do all 16 bits in the word X rts pc X X .globl _gettoy X_gettoy: / (void)gettoy(&char[8]); X jsr r5,csv / C callable X mov 4(r5),r2 / buffer address X mov $4,r3 / number of words in buffer X1: X mov $16.,r4 / number of bits in word X2: X movb *$TOYCSR+1,r0 / low bit of top byte is a clock bit X asr r0 / put it in carry X ror r1 / ripple in at top end of r1 X sob r4,2b / do all 16 bits X mov r1,(r2)+ / store the word in the buffer X sob r3,1b / do all 4 words X jmp cret / and return X X .data XMtab: X .byte 31.,29.,31.,30.,30.,30. X .byte 31.,31.,30.,31.,30.,31. Xm_magic: X .byte 1,4,4,0,2,5,0,3,6,1,4,6 Xerrmsg1: X Xtimmsg: X Xtimbuf: X .=.+13. / room for YYMMDDhhmm.ss X <\n> X \0> X_module: X X .even X .bss Xseconds: X .=.+1 Xminutes: X .=.+1 Xhours: X .=.+1 Xday: X .=.+1 Xmonth: X .=.+1 Xyear: X .=.+1 Xdow: X .=.+1 X .even Xbcd: X .=.+8. Xline: X .=.+64. SHAR_EOF fi exit 0 # End of shell archive