; ELF Clock ; Hardware by Lee Hart, Dec 2012 ; Software by Josh Bensadon, Dec 2012 ; Modified by Chuck Yakym for A18 assembler and ELF Clock Rev.A PCB, 8/6/17 ; ; Input: EF1 = TIME SET button: Fast Forward Display (advances slowly ; 64 minutes, then switches to quickly advance hours) ; EF2 = 60Hz ; EF3 = not used ; EF4 = ALARM button: Alarm/Time Display & Alarm ON/OFF ; (Also serves to cancel the Alarm) ; ; Output Port 4: ; bit 0 = \ ; bit 1 = 74LS145 decodes bits 0-2 to drive A-G and DP cathodes ; bit 2 = / ; bit 3 = 10's hours digit anodes ; bit 4 = hours digit anodes ; bit 5 = 10's minutes anodes ; bit 6 = minutes digit anodes ; bit 7 = LED 19,20 AND 49 THRU 62 anodes ; ; To set time, ; press and hold SET until hours count fast to correct hour ; press and hold SET again until minutes count to right minute ; ; To set ALARM time, ; press and hold ALARM, then Press and hold SET as it was done ; to set the time. ; ; To view Alarm time, press and hold ALARM ; ; To turn Alarm ON/OFF, press and release ALARM until LED 59 AND 60 is ON ; ; To cancel Alarm, press and release ALARM ; ; ;Version 1.0 -Initial Release ASAP for production ; (White Sound Generator Still Required) ;Version 1.1 -Added ALARM-ON test prior to testing for ALARM time. ; -Worked out correct sequence & setting for AC Fail surogate ; pulses to keep clock running (on 1.78 Mhz system) ; -Added 16 bit White Noise ; -Added Lee's trick to XOR and Output without RAM ; ; Ideas for future releases: ; - Save bytes to shrink program for the purpose of executing faster. ; - Change Prescaler time out detection by adding 256 to prescaler ; and testing for R.1 = 0 (Saves 1 shift operation) ; - Prevent Alarm Time from showing indefinitely when EF4 is pressed, ; Time it out. ; ;Outline of program: ; -Init Time & Alarm to 12:00AM ;Loop for New minute ; -Reload the 60Hz Line Prescaler ; -Advance CLOCK by 1 Minute ; -IF ALARM-ON THEN ; Test for ALARM TIME (activate Steps Counter when ALARM=CLOCK) ;Loop to Refresh Display ; -Create Bit Maps of all the Segments based on value of CLOCK ; (& R6 for LED's 19,20 AND 49 THRU 62) ;Loop to Scan LEDs ; -Output Scanned ROW & Columns (activate all digits for which ; that segment is to be illuminated) ; -Track 60Hz Line input (EF2) ; -Decrement Prescaler on AC pulses ; -Decrement AC Fail Time out on LACK of AC Pulses ; -IF Prescaler underflows (A minute has elapsed), ; GOTO "Loop for New Minute" ; -IF AC Fail times out, ; GOTO "Decrement Prescaler on AC Pulses" ; -On every 64 AC Cycles (~1 Second), Trigger STEP Sounds ; -Track Alarm Button (EF4) ; -Advance Alarm Display & Alarm ON/OFF Status ; -Exchange Alarm Time with Clock Time ; -GOTO "Loop to Refresh Display" ; -Track Time Set Button (EF1) ; -Decrement Rate Counter ; -At Selected RATE, GOTO "Loop for New minute" ; -GOTO "Loop to Scan LEDs" ; ; register usage ; ; R0 = PC ; R1 = X ; R2 = TABLE LOOK UP, ROW SCANNER, Temp Register for ALARM Check ; R3 = BIT MAP OF SEGMENTS FOR HH:__ ; R4 = BIT MAP OF SEGMENTS FOR __:MM ; R5.0 BIT MAP OF SEGMENTS FOR LEDS 19,20 AND 49 THRU 62 ; R5.1 Accumulator of Column Bits (preloaded with ROW# so it is ; ready for OUTPUT) ; R6.1 LEDs 19,20 AND 49 THRU 62 ; bit 0: 1=Alarm displayed (LED 61,62) ; bit 1: 1=Alarm is set (LED 59,60) ; bit 2: unused (LED 57,58) ; bit 3: 1=Step sound on (LED 55,56) ; bit 4: 1=White noise sound on (LED 53,54) ; bit 5: 1=PM (LED 51,52) ; bit 6: 1=AM (LED 49,50) ; bit 7: 1=colon on (LED 19,20) ; R6.0 ; R7 = Time Set Rate Counter ; R8 = White Noise Register ; R9.0 State of EF inputs ; R9.1 Temp for swapping ALARM/CLOCK Time ; RA = ALARM ; RB = Steps Count Down ; RC = Clock HH:MM (BCD coded) ; RD = Sound Routine ; RE.0 AC FAIL TIMER ; RF = PRESCALER 7200 COUNT = 1C20h ; REGISTER EQUIVALENTS FOR A18 R0 EQU 0 R1 EQU 1 R2 EQU 2 R3 EQU 3 R4 EQU 4 R5 EQU 5 R6 EQU 6 R7 EQU 7 R8 EQU 8 R9 EQU 9 RA EQU 10 RB EQU 11 RC EQU 12 RD EQU 13 RE EQU 14 RF EQU 15 ; CPU 1802 ; ACTO EQU 20 ;Timeout reload value for AC Fail Timer. ;At VELF's clock of 3.579545 / 2, "20" is slightly ;faster than 1 seconds worth of surogate "AC" pulses STEPCNT EQU 60 ;60 STEPS (once per second) until full alarm ORG 0000h DIS ;; disable interrupts DB 00 ;; LDI HIGH LEES_TRICK ;point R1 to 256-byte table with address PHI R1 ;low byte in each address. Allows RAM-less use of SEX R1 ;OUT, math, and logic instructions LDI 0FFh ;Pseudo Random Bit generator PHI R8 ;16 bits, taps at 4, 13, 15, 16 PLO R8 ;initialize R8 to a non-zero seed LDI HIGH NOSOUND PHI RD ;initialize with Sound OFF LDI LOW NOSOUND PLO RD LDI 12h PHI RC PHI RA GHI R0 PLO RC ;set Time = 12:00 PLO RA ;set Alarm = 12:00 LDI 40H ;SET AM LED ON PHI R6 ;ALL OTHER LEDs OFF GHI R0 PLO R9 ;States OFF MINUTE_TIC ;---------------------------------- LDI 1Ch ;Reload Prescaler with 7200 (60Hz * 60 ;Seconds * 2 phases) ;GHI R0 ;DEBUG, prescaler set to 31 for debuging ;purposes. REMOVE on production firmware PHI RF LDI 1Fh ;Scaler loaded with 7199 because we test ;for underflow (<0) instead of equal to zero PLO RF SEP RD ; call sound ;---------------------------------- ;Advance clock to next minute INC RC ;Add 1 to minutes GLO RC ANI 0Fh SMI 0Ah ;Test for BCD overflow BNZ ADVTIME_END SEP RD GLO RC ;Adjust for BCD overflow ADI 6 PLO RC SMI 060h ;Test for Minutes over flow BNZ ADVTIME_END SEP RD HOUR_TIC GHI R0 ;Reset Minutes to 00 PLO RC GHI RC ;Advance Hours ADI 1 PHI RC ;am/pm switch at 12:00 SMI 12H BZ AM_PM_CK AM_PM_RET GHI RC SMI 13h ;Test for Midnight BNZ ADVTIME_NOV SEP RD LDI 01H ;Reset to 1 o'clock PHI RC ;Time=01:00 LDI 00H PLO RC BR ADVTIME_END AM_PM_CK GHI R6 SHL SHL ;AM BIT IN DF BDF AM_PM PM_AM ;change from PM to AM GHI R6 ANI 9FH ORI 40H ;SET PM ON BR AM_PM_DONE AM_PM ;change from AM to PM GHI R6 ANI 9FH ORI 20H AM_PM_DONE PHI R6 BR AM_PM_RET ADVTIME_NOV ANI 0Fh SMI 06h ;Test for BCD overflow ( 0A - 04 - 06 = 00 ) BNZ ADVTIME_END SEP RD GHI RC ;Adjust for BCD overflow ADI 6 PHI RC ADVTIME_END ;---------------------------------- GHI R6 ;Skip Alarm Check when ALARM not ON ANI 2 BZ CHK_ALARM_END SEP RD ;TEST NEW TIME FOR MATCH WITH ALARM TIME GHI RA ;Fetch Alarm Hour PLO R1 ;Set M(RX) = D GHI RC ;Get Clock Hour XOR BNZ CHK_ALARM_END SEP RD GLO RA ;Fetch Alarm Minute PLO R1 ;Set M(RX) = D GLO RC ;Get Clock Minute XOR BNZ CHK_ALARM_END SEP RD ;ALARM TIME = CLOCK !!! LDI STEPCNT ;Start the 60 Steps PLO RB GHI R6 ;Set LED 55,56 ORI 8 PHI R6 ; CHK_ALARM_END DISPLAY_REFRESH ;Convert BCD TIME to Bit Map of LED Segments to turn on SEP RD LDI 3h PHI R2 ;R2 = segment pattern LOOK UP TABLE GHI RC ;Get H_:__ (10's of hours) SHR SHR ; in lower 4 bits SHR SHR ; BNZ TEN_HOUR LDI 0Ch ;shut off tens of hour segment TEN_HOUR PLO R2 ; use R2 to convert to segment pattern SEP RD LDN R2 PLO R3 ; R3.0 = H_:__ pattern GHI RC ;Get _H:__ (1's of hours) ANI 0Fh PLO R2 ; convert to pattern SEP RD LDN R2 PHI R3 ; R3.1 = _H:__ pattern GLO RC ;Get __:M_ (10's of minutes) SHR SHR SHR SHR PLO R2 ; convert to pattern SEP RD LDN R2 PLO R4 ; R4.0 = __:M_ pattern GLO RC ;Get __:_M ANI 0Fh PLO R2 ; convert to pattern SEP RD LDN R2 PHI R4 ; R4.1 = __:_M pattern SEP RD ;KEEP LEDS OFF FOR DEBUGGING ; LDI 00H GHI R6 PLO R5 ;Scan LEDs GHI R0 ;Init ROW counter to 0 PLO R2 SCAN_LOOP GLO R2 ;Start accumulated column bits with Select Row PHI R5 SEP RD GLO R3 ;Fetch LSB to shift back into MSB RSHR GLO R3 RSHR ;Shift H_:__ to get an LED segment bit PLO R3 ; LSB now in DF GHI R5 ;Accumulate the 5 column bits RSHL ; LSB now in LSB of R5.1 PHI R5 ; R5.1=pattern 0 0 0 0 0 0 0 bit7 SEP RD GHI R3 ;Fetch LSB to shift back into MSB RSHR GHI R3 RSHR ;Shift _H:__ to get an LED segment bit PHI R3 GHI R5 ;Accumulate the 5 column bits RSHL PHI R5 ; R5.1=pattern 0 0 0 0 0 0 bit7 bit6 SEP RD GLO R4 ;Fetch LSB to shift back into MSB RSHR GLO R4 RSHR ;Shift __:M_ to get an LED segment bit PLO R4 GHI R5 ;Accumulate the 5 column bits RSHL PHI R5 ; R5.1=pattern 0 0 0 0 0 bit7 bit6 bit5 SEP RD GHI R4 ;Fetch LSB to shift back into MSB RSHR GHI R4 RSHR ;Shift __:_M to get an LED segment bit PHI R4 GHI R5 ;Accumulate the 5 column bits RSHL PHI R5 ; R5.1=pattern 0 0 0 0 bit7 bit6 bit5 bit4 SEP RD GLO R5 ;Fetch LSB to shift back into MSB RSHR GLO R5 RSHR ;Shift LEDS 19-20, 49-62 to get an LED segment bit PLO R5 GHI R5 ;Accumulate the 5 column bits RSHL PHI R5 ;R5.1 bit 0 1 2 3 4 5 6 7 ; LEDs digit digit digit digit 0 0 0 ; 19-20 __:_M __:M_ _H:__ H_:__ segment.a ; 49-62 ;ADDED LBR CORRECT_R ;ADDED LABEL CORRECT_DONE GHI R5 PLO R1 ;no need to save accumulated bits further, since ;OUT follows with segment "a" selected by bits 2-0, OUT 4 ;and highs on all digits with their segment "a" lit DEC R1 ;Undo the rolling over to next Page SEP RD INC R2 ;ADVANCE TO NEXT SCAN ROW SEP RD LBR PG1 ;***** WARNING: PAGE BREAK OCCURS HERE PG1 ORG 100h ;CHECK LINE FREQUENCY INPUT GLO RF ;Fetch phase we are looking for HIGH/LOW SHR ;Last flagged phase shifted into DF B2 LINE_HIGH ;LINE FREQUENCY ON EF2 LINE_LOW BNF TIC_DC_CHK BR TIC_DOWN LINE_HIGH BDF TIC_DC_CHK TIC_DOWN LDI ACTO * 2 ;AC Time Out Refresh (Double the normal time ; before surrogate pulses begin) TIC_DOWN1 PLO RE SEP RD DEC RF ;Toggle Phase (bit 0) & Count Down GHI RF ;Fetch High Byte to check for underflow SHL ;DF=Underflow BNF TIC_0 LBR MINUTE_TIC ;Go Count the MINUTE Change TIC_0 GLO RF SHL ;Faster way of masking out MSB (ANI 7FH) BNZ TIC_END ;~1 Second Events Occur here *************** SEP RD GHI R6 ;Flash Colon XRI 80h PHI R6 SEP RD GLO RB ;Check if alarm is running, play steps or run the ;full alarm at end of count BZ TIC_STEP_END DEC RB LDI LOW Steps ;Activate Step sound PLO RD GLO RB BNZ TIC_STEP_END LDI LOW White ;After X number of STEPS kick in White Noise PLO RD ;Could save a byte here by just doing TWO INC RD's GHI R6 ;Set LED 53,54 ORI 10h PHI R6 ; TIC_STEP_END LBR DISPLAY_REFRESH TIC_DC_CHK DEC RE ;When the AC phase expected is not there yet, GLO RE ;Count down backup plan (For DC operation) BNZ TIC_END DEC RF ;Pre-Toggle Phase (bit 0) to prevent "TIC_DOWN" ;to execute & Load RE with ACTO * 2 LDI ACTO ;AC Time Out Refresh BR TIC_DOWN1 TIC_END SEP RD GLO R9 ;Fetch EF4 Last State SHR ;Last State shifted into DF B4 EF4_HIGH EF4_LOW BNF EF4_END SEP RD DEC R9 ;Update status REQ BR EF4_SWAP EF4_HIGH BDF EF4_END SEP RD INC R9 ;Update status SEQ EF4_SWAP GHI RA ;Swap Clock/Alarm PHI R9 GHI RC PHI RA LDI LOW ALM_RESET ;Cancel any Sound PLO RD SEP RD GHI R9 PHI RC GLO RA PHI R9 GLO RC PLO RA GHI R9 PLO RC ;Update Display LED 61,62 & 59,60 (ALARM DISPLAY, ALARM ON/OFF) GHI R6 ADI 1 ANI 0FBh PHI R6 LBR DISPLAY_REFRESH EF4_END SEP RD B1 EF1_HIGH EF1_LOW SEP RD LDI 0 ;Reset Rate Counter PLO R7 PHI R7 BR EF1_END EF1_HIGH SEP RD DEC R7 GHI R7 ANI 040h BZ EF1_FAST GLO R7 BNZ EF1_END LDI LOW Steps ;Activate Step sound PLO RD LBR MINUTE_TIC EF1_FAST LDI 3Fh PHI R7 ;LOCK IN FAST RATE GLO R7 BNZ EF1_END LDI LOW Steps ;Activate Step sound PLO RD LBR HOUR_TIC EF1_END SEP RD LBR SCAN_LOOP TEMP DB 00 ;Output Byte ;*************************************************************************** ;Page 2 for Sound Routines ORG 200h ;No Sound ALM_RESET GHI R6 ;Clear LEDs 59,60,61,62 ANI 0E7h PHI R6 ; LDI 0 ;Cancel Alarm PLO RB NOSOUND REQ SOUND_NOP SEP R0 ;Return PC to R0, without White Noise BR SOUND_NOP Steps SEQ ;Toggle Q on/off twice for a Step SEP R0 REQ SEP R0 SEQ SEP R0 REQ BR NOSOUND White_ret SEP R0 ; XOR BITS 4,13,15,16 White GHI R8 ; ...X.... _ SHR ; ....X... _ ANI 8 PLO R1 GLO R8 ; ....X.XX _ XOR ; ....*.XX _ PLO R1 SHR ; .....*.X _ SHR ; ......*. _ XOR SHR ; .......* _ XOR SHR ;Fetch bit out of LSB GHI R8 SHRC ;Shift bit into R8 Register PHI R8 GLO R8 SHRC ;Shift bit into R8 Register PLO R8 ; LSNF ;Have Q follow DF on/off SEQ SKP REQ BR White_ret ;*************************************************************************** ; Page 3 for Character Look Up table ; MSB LSB ;bits 7 6 5 4 3 2 1 0 ;segments DP G F E D C B A ORG 300h DB 00111111b ;0 DB 00000110b ;1 DB 01011011b ;2 DB 01001111b ;3 DB 01100110b ;4 DB 01101101b ;5 DB 01111101b ;6 DB 00000111b ;7 DB 01111111b ;8 DB 01100111b ;9 DB 01110111b ;A DB 01111100b ;b DB 00111001b ;C DB 01011110b ;d DB 01111001b ;E ; DB 01110001b ;F DB 01100111b ;9 ;*************************************************************************** ; ;Page 4 for Lee's Trick - Table in ROM returns low byte of its address in D. ;Allows instructions that read from M(R(X)) to work (OUT, math, logical). ; ORG 400h LEES_TRICK DB 000h,001h,002h,003h,004h,005h,006h,007h,008h,009h,00Ah,00Bh,00Ch,00Dh,00Eh,00Fh DB 010h,011h,012h,013h,014h,015h,016h,017h,018h,019h,01Ah,01Bh,01Ch,01Dh,01Eh,01Fh DB 020h,021h,022h,023h,024h,025h,026h,027h,028h,029h,02Ah,02Bh,02Ch,02Dh,02Eh,02Fh DB 030h,031h,032h,033h,034h,035h,036h,037h,038h,039h,03Ah,03Bh,03Ch,03Dh,03Eh,03Fh DB 040h,041h,042h,043h,044h,045h,046h,047h,048h,049h,04Ah,04Bh,04Ch,04Dh,04Eh,04Fh DB 050h,051h,052h,053h,054h,055h,056h,057h,058h,059h,05Ah,05Bh,05Ch,05Dh,05Eh,05Fh DB 060h,061h,062h,063h,064h,065h,066h,067h,068h,069h,06Ah,06Bh,06Ch,06Dh,06Eh,06Fh DB 070h,071h,072h,073h,074h,075h,076h,077h,078h,079h,07Ah,07Bh,07Ch,07Dh,07Eh,07Fh DB 080h,081h,082h,083h,084h,085h,086h,087h,088h,089h,08Ah,08Bh,08Ch,08Dh,08Eh,08Fh DB 090h,091h,092h,093h,094h,095h,096h,097h,098h,099h,09Ah,09Bh,09Ch,09Dh,09Eh,09Fh DB 0A0h,0A1h,0A2h,0A3h,0A4h,0A5h,0A6h,0A7h,0A8h,0A9h,0AAh,0ABh,0ACh,0ADh,0AEh,0AFh DB 0B0h,0B1h,0B2h,0B3h,0B4h,0B5h,0B6h,0B7h,0B8h,0B9h,0BAh,0BBh,0BCh,0BDh,0BEh,0BFh DB 0C0h,0C1h,0C2h,0C3h,0C4h,0C5h,0C6h,0C7h,0C8h,0C9h,0CAh,0CBh,0CCh,0CDh,0CEh,0CFh DB 0D0h,0D1h,0D2h,0D3h,0D4h,0D5h,0D6h,0D7h,0D8h,0D9h,0DAh,0DBh,0DCh,0DDh,0DEh,0DFh DB 0E0h,0E1h,0E2h,0E3h,0E4h,0E5h,0E6h,0E7h,0E8h,0E9h,0EAh,0EBh,0ECh,0EDh,0EEh,0EFh DB 0F0h,0F1h,0F2h,0F3h,0F4h,0F5h,0F6h,0F7h,0F8h,0F9h,0FAh,0FBh,0FCh,0FDh,0FEh,0FFh ;*************************************************************************** ; ;Page 5 for R5 correction for the ELF Clock Rev. A PCB. ;The following routine converts R5.1 from the Output Port 4 to work on the ELF Clock PCB ; ;Converts the following: ; ; ; ;From R5.1: ; Output Port 4: ; bit 0 = LED 19-20 and 49-62 anodes ; bit 1 = minutes digit anodes ; bit 2 = 10's minutes anodes ; bit 3 = hours digit anodes ; bit 4 = 10's hours digit anodes ; bit 5 = \ ; bit 6 = 74LS145 decodes bits 0-2 to drive A-G and DP cathodes ; bit 7 = / ; ;Converted to R5.1: ; Output Port 4: ; bit 0 = \ ; bit 1 = 74LS145 decodes bits 0-2 to drive A-G and DP cathodes ; bit 2 = / ; bit 3 = 10's hours digit anodes ; bit 4 = hours digit anodes ; bit 5 = 10's minutes anodes ; bit 6 = minutes digit anodes ; bit 7 = LED 19-20 and 49-62 anodes ; ORG 500h CORRECT_R LDI 00H PLO R6 ;CLEARS R6.0 GHI R5 SHR ;LED BIT0 OF R5.1 IN DF GLO R6 RSHL PLO R6 ;R6.0 = 0 0 0 0 0 0 0 BIT7 GHI R5 SHR SHR ;BIT1 OF R5.1 IN DF PLO R1 ;TEMP STORGE OF SHIFTED R5.1 GLO R6 RSHL PLO R6 ;R6.0 = 0 0 0 0 0 0 BIT7 BIT6 GLO R1 ;GET SHIFTED R5.1 SAVED IN R1.0 SHR ;BIT2 OF R5.1 IN DF PLO R1 ;TEMP STORAGE OF SHIFTED R5.1 GLO R6 RSHL PLO R6 ;R6.0 = 0 0 0 0 0 BIT7 BIT6 BIT5 GLO R1 SHR ;BIT3 OF R5.1 IN DF PLO R1 GLO R6 RSHL PLO R6 ;R6.0 = 0 0 0 0 BIT7 BIT6 BIT5 BIT4 GLO R1 SHR ;BIT4 OF R5.1 IN DF PLO R1 GLO R6 RSHL PLO R6 ;R6.0 = 0 0 0 BIT7 BIT6 BIT5 BIT4 BIT3 GHI R5 SHL ;BIT7 OF R5.1 IN DF GLO R6 RSHL PLO R6 ;R6.0 = 0 0 BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 GHI R5 SHL SHL ;BIT6 OF R5.1 IN DF GLO R6 RSHL PLO R6 ;R6.0 = BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 0 GHI R5 SHL SHL SHL ;BIT5 OF R5.1 IN DF GLO R6 RSHL PHI R5 ;R5.1 = BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0 ; ;Below is a chart of the conversion of the original R5.1 to the converted R5.1 register ;org converted ;bit5 -> bit0 ;bit6 -> bit1 ;bit7 -> bit2 ;bit4 -> bit3 ;bit3 -> bit4 ;bit2 -> bit5 ;bit1 -> bit6 ;bit0 -> bit7 ; LBR CORRECT_DONE END