***************************************************************** * * * Time display/set program for Thinker Toys Mult/IO board. * * * * Bobby Dale Gifford. * * 9/25/80 * * * ***************************************************************** rev equ 10 ;Revision # x.x base equ 48h ;Base of Mult I/O ports grpsel equ base+7 ;Group select clk equ base+2 ;Clock port clkclk equ 2 ;Clock clk bit clkc1 equ 8 ;Clock c1 bit rclk equ 0ch ;Read clock command cstb equ 20h ;Clock strobe bit shft equ 4 ;Shift bits command tp64 equ 10h ;Output tick pulse at 64 hz reghld equ 0 ;Register hold command wclk equ 8 ;Write clock command bdos equ 5 ;Bdos entry point cbuff equ 81h ;Command buffer string clen equ 80h ;Command length byte wboot equ 0 ;Warm boot location const equ 11 ;Get constat function # pstr equ 9 ;Print string function # readcon equ 10 ;Read console buffer acr equ 0dh ;Carriage return alf equ 0ah ;Line feed org 100h ;Transient program area start lhld bdos+1 ;Set up stack sphl call skipb ;Skip command line blanks jz display ;No command line sett lxi h,days ;Array of string pointers to match call match3 ;Look for match jz exit ;No match lxi d,-days ;Form index dad d mov a,l ;Get low byte stc ;Clear the carry cmc rar ;Divide index by 2 sta mthday ;Day of week finished lxi h,months ;Array of string pointers to match call match3 ;Look for match jz exit ;No match lxi d,-months ;Form index dad d mov a,l ;Get low byte stc ;Clear the carry cmc ral ral ral mov b,a ;Save in B lda mthday ;Or in with day ora b sta mthday call bcd2 ;Scan for two valid bcd digits jc exit sta date ;New date call bcd2 ;Scan for two more valid bcd digits jc exit sta hour ;New hour call bcd2 ;Scan for two more valid bcd digits jc exit sta minutes ;New minutes call bcd2 ;Scan for last valid bcd digits jc exit sta seconds ;New seconds call skipb ;Skip trailing blanks jz noap call scan cpi 'P' ;Check for AM or PM push psw cz uphrs pop psw cpi 'A' cz dwnhrs call skipc call skipb jnz exit ;If anything remaining, then error noap xra a out grpsel mvi a,reghld ;Issue register hold command call setup mvi a,tp64 ;Set up clock pulse call setup lxi d,waitmsg ;Wait for carriage return call pmsg lxi d,ibuff ;Read console mvi c,readcon call bdos call writec ;Write the time lxi d,acralf call pmsg call displ1 ;Display the current time jmp wboot ;All done ***************************************************************** * * * Writec does the actual clock time writing. This routine must * * not be interrupted. * * * ***************************************************************** writec di ;Make sure we have no interruptions xra a ;Select group 0 out grpsel mvi a,shft ;Shift command call setup push h ;Save clock data address wbyte mvi e,8 ;Bit shift counter inx h ;Bump to next byte of data wbit mov a,m ;Get current byte of data rar ;LSB into carry mov m,a ;Save current byte ral ;Carry into LSB ani 1 ;Through away useless bits xthl ;Recover address of clock data ora m ;Get current state xthl ;Recover current byte counter call clkstb ;Strobe in one bit dcr e ;Update bit counter jnz wbit ;Same byte ? dcr d ;Update bye counter jnz wbyte ;All done ? pop h ;Recover address of clock data mov a,m ;Get current state ori wclk ;Set write clock bit call clkcmd ;Issue write time command xri wclk ;Turn off write time command jmp clkcmd ***************************************************************** * * * Bcd2 scans the command line for up to two valid ascii digits * * and returns the result as a packed bcd byte in reg A. * * * ***************************************************************** bcd2 call skipb ;Skip any preceeding blanks call scan ;Get first char of day of month stc ;Carry is error rz cpi ':' jz bcd2 cpi ',' jz bcd2 call digit ;Check for valid decimal digit rc mov b,a ;Save in B call scan jz okd cpi ',' ;Check for end of day of month jz okd cpi ' ' jz okd cpi ':' jz okd call digit rc stc ;Clear the carry cmc push psw ;Save low nibble mov a,b ral ;Put previous digit into high nibble ral ral ral mov b,a ;Save in B pop psw ;Recover low digit ora b ;Form byte mov b,a ;Save in B okd mov a,b ;Recover day of month stc ;No error cmc ret ***************************************************************** * * * Digit checks if the char in reg A is a valid ascii digit. * * * ***************************************************************** digit cpi '0' ;Less than 0 rc cpi '9'+1 ;Greater than 9 cmc rc sui '0' ;Strip off ascii bias ret ***************************************************************** * * * Match3 guarantees that at least three characters are matched * * with the command line. * * * ***************************************************************** match3 mvi a,3 ;Clear match count sta mcnt mov e,m ;Get current string pointer inx h mov d,m inx h mov a,e ;Check if all done ora d rz ;No match push h ;Save current array pointer lhld scanpnt ;Save current scan pointer push h lda clen ;Save current command length push psw mtchmo call scan ;Scan and convert to upper case jz nomatch ;No match if out of chars call toupper mov b,a ;Save in B ldax d ;Get next char in string inx d ;Bump string pointer call toupper ;Convert to upper case cmp b ;Does it match ? jnz nomatch ;No match lda mcnt ;Get match count dcr a ;Matched three ? sta mcnt ;Save match count jnz mtchmo ;Match more ? call skipc ;Skip rest of characters pop h ;Throw away old scan pointer pop h ;Throw away old command length pop h ;Recover array pointer dcx h ;Backup array pointer dcx h rnz ;No error return inr a ;No error return ret nomatch pop psw ;Recover command length sta clen ;Restore command length pop h ;Recover scan pointer shld scanpnt ;Restore scan pointer pop h ;Recover array pointer jmp match3 ;Try again ***************************************************************** * * * Display continually displays the time as long as nothing is * * typed on the console. * * * ***************************************************************** display call displ1 ;Display one time line mvi c,const ;Check console for char call bdos ana a ;If anything typed then reboot jnz wboot lxi d,acrmsg ;Print carriage return only call pmsg jmp display ;Go print the time again ***************************************************************** * * * Displ1 displays the current time once. * * * ***************************************************************** displ1 call readc ;Read the clock - watch out if interrupts on lda mthday ;Get the day of the week ani 7 ;Through away irrelevent bits okday ral ;Multiply by 2 mov e,a ;Form 16 bit offset mvi d,0 lxi h,days ;Array of string pointers dad d ;Form absolute address of string mov e,m ;Get low string address byte inx h ;Point to high byte mov d,m ;Get high byte mov a,e ;Check for invalid day ora d jz displ1 ;Start over again if invalid call pmsg ;Print the day lda mthday ;Get the month rar ;Adjust for proper offset rar rar ani 1eh ;Multiply by two and throw out ; irrelevent bits mov e,a ;Form 16 bit offset mvi d,0 lxi h,months ;Array of string pointers dad d ;Form absolute address of string mov e,m ;Get low string address byte inx h ;Point to high byte mov d,m ;Get high byte mov a,d ;Check for invalid month ora e jz displ1 ;Start over again if invalid call pmsg ;Print the month lxi h,tbuff ;Pointer to temporary storage push h ;Save for printing lda date ;Convert the date to ascii rar ;Get high digit into low nibble rar rar rar ani 0fh cnz putlow ;Don't print leading zero lda date ;Get the low digit call putlow ;Stuff it in the buffer mvi a,',' ;And the comma and space call put mvi a,' ' call put lda hour ;Get the hour cpi 13h ;Check for AM or PM cnc subhr ;Convert PM from 13-24 into 0-12 ora a ;Check for 12 midnight cz mak12 call puthi ;Put both digits into the buffer mvi a,':' ;Put the colon in the buffer call put lda minutes ;Get the minutes call puthi ;Put both minutes digits in the buffer mvi a,':' ;Put another colon in the buffer call put lda seconds ;Get the seconds call puthi ;Put both second digits in the buffer mvi a,' ' ;One space into the buffer call put lda hour ;Check hours for AM or PM cpi 12h mvi a,'a' ;Print 'A' or 'P' jc isam mvi a,'p' isam call put ;Put the 'A' or 'P' in the buffer mvi a,'m' ;Put the 'M' in the buffer call put sploop mov a,m ;Get the next char in the buffer cpi '$' ;Is it the end ? jz endsp ;All done mvi a,' ' ;Get a space call put ;Put it in the buffer jmp sploop ;Finish padding with spaces endsp pop d ;Recover the Buffer address jmp pmsg ;Print the buffer ***************************************************************** * * * Readc does the actual clock reading (40 bits) from the * * hardware. If interrupts are enabled, then care must be taken * * to assure that this routine is not interrupted until it * * completes. * * * ***************************************************************** readc xra a ;Select group zero out grpsel mvi a,rclk ;Read clock into 40 bit shift register call setup push h ;Save address of clkdata xri clkc1 ;Issue shift command call clkcmd rbyte mvi e,8 ;Prep for 8 bits inx h ;Bump to next address of clock data rbit in clk ;Read one bit rar ;Put bit into carry mov a,m ;Get partially assembled byte rar ;Shift in the bit just read mov m,a ;Save partially assembled byte xthl ;Get address of clkdata mov a,m ;Get clock data xthl ;Save address of clock data call clkstb ;Strobe the shift register dcr e ;All done with this byte ? jnz rbit ;Read another bit if not dcr d ;Completely done ? jnz rbyte ;Read another byte if not pop h ;Recover address of clkdata clkcmd mvi c,cstb ;Get clock strobe bit clkstb out clk ;Output strobe low call delay ;Wait for chip to see the strobe low xra c ;Turn strobe high out clk ;Output strobe high call delay ;Wait for chip to see the strobe high xra c ;Turn strobe low out clk ;Output strobe low call delay mvi c,clkclk ;Clock clk bit ret setup mvi d,5 ;Count of bytes to read lxi h,clkdata ;Address of clock data ora m ;Get current bit state jmp clkcmd ;Issue the command delay mvi b,0 ;Worst case is 700 usec delay1 dcr b jnz delay1 ret ***************************************************************** * * * Puthi puts the high and low nibbles of the bcd number in * * the a reg in the temporary buffer. * * * ***************************************************************** puthi push psw ;Save low nibble rar ;Put high nibble into low nibble rar rar rar call putlow ;Print the low nibble of a reg pop psw ;Recover the low nibble putlow ani 0fh ;Strip off irrelevent bits adi '0' ;Form Ascii character put mov m,a ;Put char in buffer inx h ;Bump buffer pointer ret ***************************************************************** * * * Exit is the standard error message for invalid command. * * * ***************************************************************** exit lxi d,badtmsg call pmsg jmp wboot ***************************************************************** * * * Pmsg is the CP/M print string function. * * * ***************************************************************** pmsg mvi c,pstr jmp bdos subhr adi 88h ;Subhr adjusts the BCD number to daa ; be between 1 and 12 ret mak12 mvi a,12h ret uphrs lda hour cpi 12h rz adi 12h sta hour ret dwnhrs lda hour cpi 12h rnz xra a sta hour ret skipc call scan ;Get next char rz ;Return if no more chars cpi ' ' ;Check for space jnz skipc ;Continue if not ret skipb call scan ;Get next char rz ;Return if no characters left cpi ' ' ;Is it a space jz skipb ;Skip it unscan push h ;Save HL lhld scanpnt ;Get command scan pointer dcx h ;Back it up shld scanpnt ;Save updated char lda clen ;Update length inr a sta clen ;Save updated length pop h ;Restore HL ret scan lda clen ;Check if anything left ana a rz ;Return with Z set if no more dcr a ;Update length sta clen push h ;Save HL lhld scanpnt ;Get command pointer mov a,m inx h ;Update command pointer shld scanpnt pop h ora a ;Clear Z flag ret toupper cpi 'a' ;Is it lower case ? rc cpi 'z'+1 rnc sui ' ' ret ***************************************************************** * * * The following are data used within the program. * * * ***************************************************************** clkdata: db 0 ;Current state of clk port seconds: db 0 ;Seconds read minutes: db 0 ;Minutes read hour db 0 ;Hours read date db 0 ;Date read mthday db 0 ;Week day and month read ***************************************************************** * * * Days is an array of pointers to strings, used to print the * * english version of the day of the week. * * * ***************************************************************** days dw sun dw mon dw tue dw wed dw thu dw fri dw sat dw 0 ;Illegal day sun db 'Sunday, $' mon db 'Monday, $' tue db 'Tuesday, $' wed db 'Wednesday, $' thu db 'Thursday, $' fri db 'Friday, $' sat db 'Saturday, $' ***************************************************************** * * * Months is an array of pointers to strings, used to print the * * english version of the month of the year. * * * ***************************************************************** months dw bad dw jan dw feb dw mar dw apr dw may dw jun dw jul dw aug dw sep dw oct dw nov dw dec dw 0,0,0 ;Illegal months bad db '$' ;January is month 1 not 0 jan db 'January $' feb db 'February $' mar db 'March $' apr db 'April $' may db 'May $' jun db 'June $' jul db 'July $' aug db 'August $' sep db 'September $' oct db 'October $' nov db 'November $' dec db 'December $' acrmsg db acr,'$' acralf db acr,alf,'$' ***************************************************************** * * * Tbuff is used to prepare the day of the month, hours, minutes,* * and seconds prior to printing. * * * ***************************************************************** tbuff db '00, 00:00:00 am $' badtmsg db acr,alf db 'Invalid Time specified.$' waitmsg db acr,alf db 'Press return to set the time: $' ibuff db 10,10 ds 10 scanpnt dw cbuff mcnt db 0 end