0001 0000 .TITLE "Precision Radio Clock for Station WWV/H Transmissions" 0002 0000 ; 0003 0000 ; See readme.txt file in this distribution for copyright notice, setup 0004 0000 ; instructions and command summary. 0005 0000 ; 0006 0000 ; Include files 0007 0000 ; 0012 0000 .LIST 0013 0000 ; 0014 0000 ; Program memory map 0015 0000 ; 0016 0000 ; External 1000-7fff program 0017 0000 ; 0018 0000 ; Data memory map 0019 0000 ; 0020 0000 ; Block B2 0060-007f interrupt variables and stack 0021 0000 ; Block B0 0200-02ff filter coefficients (mapped to prog mem) 0022 0000 ; Block B1 0300-03ff filter delay lines 0023 0000 ; External 0400-7fff program variables 0024 0000 ; 0025 0000 ; Auxiliary register usage 0026 0000 ; 0027 0000 ; AR0 utility compare and temporary register 0028 0000 ; AR1 utility pointer 0029 0000 ; AR2 utility counter/pointer 0030 0000 ; AR3 reserved for interrupt routines 0031 0000 ; AR4 reserved for interrupt routines 0032 0000 ; AR5 interrupt stack pointer 0033 0000 ; AR6 AIO buffer pointer 0034 0000 ; AR7 AIO buffer pointer 0035 0000 ; 0036 0000 ; General purpose status bits (STATUS) 0037 0000 ; 0038 0000 SSYNC .EQU 0 ; second sync 0039 0000 MSYNC .EQU 1 ; minute sync 0040 0000 DGATE .EQU 2 ; data gate 0041 0000 BGATE .EQU 3 ; data bit error 0042 0000 INSYNC .EQU 4 ; clock is synchronized 0043 0000 LEPSEC .EQU 5 ; leap second in progress 0044 0000 WWVH .EQU 6 ; WWV (0) WWVH (1) select 0045 0000 ERRSTA .EQU 8 ; error condition (buffer overrun) 0046 0000 LEAPYR .EQU 9 ; leap year flag 0047 0000 DGSYNC .EQU 10 ; digit compare error 0048 0000 POPOFF .EQU 11 ; frequency popoff 0049 0000 ; 0050 0000 ; Miscellaneous status bits (MISC) 0051 0000 ; 0052 0000 ; These bits correspond to designated bits in the IRIG timecode. The bit 0053 0000 ; probabilities are exponentially averaged over several minutes and 0054 0000 ; processed by a integrator and decision circuit. 0055 0000 ; 0056 0000 DUT1 .EQU 0 ; 56 DUT .1 0057 0000 DUT2 .EQU 1 ; 57 DUT .2 0058 0000 DUT4 .EQU 2 ; 58 DUT .4 0059 0000 DUTS .EQU 3 ; 50 DUT sign 0060 0000 DST1 .EQU 4 ; 55 DST1 DST in progress 0061 0000 DST2 .EQU 5 ; 2 DST2 DST change warning 0062 0000 SECWAR .EQU 6 ; 3 leap second warning 0063 0000 ; 0064 0000 ; Alarm status bits (ALARM) 0065 0000 ; 0066 0000 ; These bits indicate various alarm conditions, which are decoded to 0067 0000 ; form the quality character included in the timecode. There are four 0068 0000 ; four-bit nibble fields in the word, each corresponding to a specific 0069 0000 ; alarm condition. At the end of each minute, the word is shifted left 0070 0000 ; one position and the two least significant bits of each nibble 0071 0000 ; cleared. The least significant two bits are set if the associated 0072 0000 ; alarm condition is raised during the minute. The least significant bit 0073 0000 ; is cleared at the end of each second. The least significant bit of 0074 0000 ; some nibbles is indicated by a panel LED; the most significant bits 0075 0000 ; are decoded for the quality character. 0076 0000 ; 0077 0000 DECERR .EQU 0 ; BCD digit decoding error 0078 0000 SYMERR .EQU 4 ; low symbol probability 0079 0000 MODERR .EQU 8 ; too many data bit errors 0080 0000 SYNERR .EQU 12 ; low 1-s or 1-m sync pulse amplitude 0081 0000 ; 0082 0000 ; AIO Configuration constants: HPF out, sync, 3-V half scale, sin x/x. 0083 0000 ; RA is chosen to get the SCF as close to 288 kHz as possible; RB is 0084 0000 ; chosen to get the sample frequency as close to 8000 Hz as possible. 0085 0000 ; This results in a nominal A/D sample frequency of 7949 Hz and 3-dB 0086 0000 ; bandwidth of about 10-3700 Hz at the A/D input. 0087 0000 ; 0088 0000 CFGA .EQU CMDA_VAL(17) ; AIO load RA=TA=17 for SCF 294.1 kHz 0089 0000 CFGB .EQU CMDB_VAL(37) ; AIO load RB=TB=37 for 7949 Hz 0090 0000 AIO_GAIN .EQU AIO_GAIND60|AIO_GAIND70 ; AIO gain 0091 0000 CFGC .EQU AIO_CONFIG|AIO_SYNC|AIO_GAIN|AIO_INSSINX 0092 0000 ; 0093 0000 ; Tone frequency definitions. Note the nominal sample frequency of 7949 0094 0000 ; Hz must be corrected to 8000 Hz by replicating samples at intervals of 0095 0000 ; about 157 samples, which is equivalent to adding about 420 to the low 0096 0000 ; order word of the epoch counter for each sample. 0097 0000 ; 0098 0000 COMSIZ .EQU 8000 ; Sample clock frequency (Hz) 0099 0000 INCR2 .EQU 420 ; LSW 420.47248 sample clock adjust 0100 0000 MS .EQU 8 ; actual samples per millisecond 0101 0000 IN1000 .EQU 10 ; 1000 Hz increment, 4.5-deg sin table 0102 0000 IN1200 .EQU 12 ; 1200 Hz increment, 4.5-deg sin table 0103 0000 ; 0104 0000 ; Sizes of arrays 0105 0000 ; 0106 0000 OUTSIZ .EQU 1000 ; size of character circular buffers 0107 0000 BUFSIZ .EQU 50 ; size of AIO buffer (6.25 ms) 0108 0000 MEDSIZ .EQU 5 ; size of sync median filter (5 ms) 0109 0000 IGRSIZ .EQU 170*MS ; size of data matched filter 0110 0000 DATSIZ .EQU 60 ; size of index/data second buffers 0111 0000 BCDSIZ .EQU 4*10 ; size of BCD coefficient table 0112 0000 ; 0113 0000 ; Odds and ends 0114 0000 ; 0115 0000 P1_MSK .EQU PTT_R1+FREQ_UP_R1+FREQ_DN_R1 ; RADIO_CTRL port 1 mask 0116 0000 FIRLEN .EQU 41 ; number of FIR coefficients 0117 0000 P15 .EQU 32767 ; max positive number 0118 0000 M15 .EQU -P15 ; max negative number 0119 0000 LIMIT .EQU 10000 ; limiter threshold (LED 1) 0120 0000 MAXAVG .EQU 8-1 ; max time constant (8 = 256 s) 0121 0000 AVGINC .EQU 4000h ; LSW averaging interval increment 0122 0000 PDELAY .EQU 188 ; default propagation delay (23.5 ms) 0123 0000 TCONST .EQU 4-1 ; log2 time constant (about 16 minutes) 0124 0000 ; 0125 0000 ; Thresholds. These establish the minimum signal level, minimum SNR and 0126 0000 ; maximum jitter thresholds which establish the error and false alarm 0127 0000 ; rates of the receiver. The values defined here may be on the 0128 0000 ; adventurous side in the interest of the highest sensitivity. 0129 0000 ; 0130 0000 CTHR .EQU 10 ; 1-s synch compare threshold 0131 0000 STHR .EQU 1500 ; 1-s sync threshold 0132 0000 MTHR .EQU 500 ; 1-m sync threshold 0133 0000 DTHR .EQU 1000 ; data amplitude threshold 0134 0000 NTHR .EQU 100 ; data SNR threshold (dB * 10) 0135 0000 ETHR .EQU 1000 ; digit correlator threshold 0136 0000 TTHR .EQU 30 ; digit SNR threshold (dB * 10) 0137 0000 BTHR .EQU 30 ; max bit error count in second 0138 0000 ; 0139 0000 ; Nonprinting and special character codes 0140 0000 ; 0141 0000 LF .EQU 0Ah ; ASCII line feed 0142 0000 CR .EQU 0Dh ; ASCII carriage return 0143 0000 ; 0144 0000 ; Interesting block addresses and memory page pointers 0145 0000 ; 0146 0000 B_PAGE .EQU 0h ; base page pointer 0147 0000 U_PAGE .EQU 8h ; user page pointer 0148 0000 U_ADDR .EQU U_PAGE<<7 ; user page address 0149 0000 B0P .EQU 0FF00h ; block B0 program address 0150 0000 B0D .EQU 0200h ; block B0 data address 0151 0000 B1D .EQU 0300h ; block B1 data address 0152 0000 0153 0000 ; 0154 0000 ; Following are variables accessed by either absolute or indirect 0155 0000 ; addressing modes. 0156 0000 ; 0157 0000 ; Program variables in internal memory (block B0) initialized by 0158 0000 ; program. Addresses ending in P are valid following a CNFP 0159 0000 ; instructuion, which maps block B0 to program memory. Other addresses 0160 0000 ; are valid following a CNFD instruction, which maps block B0 to data 0161 0000 ; memory. 0162 0000 ; 0163 0000 BCDDLD .EQU B0D ; matched filter coefficients 0164 0000 BCDDLP .EQU BCDDLD+B0P-B0D ; ibid in program memory 0165 0000 DELBPF .EQU BCDDLD+BCDSIZ ; bandpass filter delay line 0166 0000 DELLPF .EQU DELBPF+FIRLEN+1 ; lowpass filter delay line 0167 0000 DELMF .EQU DELLPF+FIRLEN+1 ; matched filter delay line 0168 0000 B0DEND .EQU DELMF+FIRLEN+1 ; end of block B0 0169 0000 ; 0170 0000 ; Program variables in internal memory (block B1) cleared at reset. 0171 0000 ; 0172 0000 ; The decoding matrix consists of nine row vectors, one for each digit 0173 0000 ; of the timecode. Each vector includes (1) the current clock digit, (2) 0174 0000 ; an 11-stage shift register used to save the current probabilities for 0175 0000 ; each of the ten possible digit values plus a carry value, (3) the most 0176 0000 ; recent maximum-likelihood digit decoded and (4) a compare counter. The 0177 0000 ; digits are stored from least to most significant order. The timecode 0178 0000 ; is formed from the digits of maximum value reading in the opposite 0179 0000 ; order: yy ddd hh:mm. 0180 0000 ; 0181 0000 ; Decoding vector format 0182 0000 ; 0183 0000 DECVEC .EQU 0 ; current clock digit 0184 0000 DECTMP .EQU DECVEC+1 ; temporary for shift 0185 0000 DECINT .EQU DECTMP+1 ; digit integrator 0-9 0186 0000 DECLST .EQU DECINT+10 ; (2) last digit decode and count 0187 0000 DECSIZ .EQU DECLST+2 ; end of vector 0188 0000 ; 0189 0000 MNPROB .EQU B1D ; minutes (2 digits) 0190 0000 HRPROB .EQU MNPROB+(2*DECSIZ) ; hours (2 digits) 0191 0000 DAPROB .EQU HRPROB+(2*DECSIZ) ; days (3 digits) 0192 0000 YRPROB .EQU DAPROB+(3*DECSIZ) ; years (2 digits) 0193 0000 EDPROB .EQU YRPROB+(2*DECSIZ) ; end of decoding table 0194 0000 STACK .EQU B1D+100h ; interrupt stack (grows down) 0195 0000 B1DEND .EQU STACK ; end of block B1 0196 0000 ; 0197 0000 ; Program variables in external memory (U_PAGE) cleared at reset. We 0198 0000 ; protect one location at the beginning for I/O status. 0199 0000 ; 0200 0000 USRBGN .EQU U_ADDR+1 ; beginning of clear region 0201 0000 ; 0202 0000 ; The AIO buffer is a circular structure indexed by AR6 and AR7. AR6 is 0203 0000 ; used only by interrupt routines. The receive interrupt routine stores 0204 0000 ; the sample at AR6 and then increments AR6. The transmit interrupt 0205 0000 ; routine loads the sample at AR6, which is the oldest in the circular 0206 0000 ; buffer. The main program loops until AR7 is not equal to AR6, then 0207 0000 ; loads the sample found at AR7, which is the oldest sample not yet 0208 0000 ; processed. The program loads the output at AR7 and then increments 0209 0000 ; AR7. Since input and output interrupts are synchronous, no data are 0210 0000 ; lost or duplicated. 0211 0000 ; 0212 0000 INTBUF .EQU U_ADDR+100h ; AIO buffer 0213 0000 ; 0214 0000 ; Circular buffers and buffer structures are used for character I/O, one 0215 0000 ; set each for input (modem and echo to UART) and output (UART to 0216 0000 ; modem). 0217 0000 ; 0218 0000 ; Buffer structure format 0219 0000 ; 0 address of first word beyond buffer 0220 0000 ; 1 address of first word of buffer 0221 0000 ; 2 put pointer 0222 0000 ; 4 get pointer 0223 0000 ; 0224 0000 INPBCB .EQU INTBUF+BUFSIZ ; input buffer structure 0225 0000 OUTBCB .EQU INPBCB+4 ; output buffer structure 0226 0000 INPBUF .EQU OUTBCB+4 ; input circular buffer 0227 0000 OUTBUF .EQU INPBUF+OUTSIZ ; output circular buffer 0228 0000 ; 0229 0000 ; Filter structures 0230 0000 ; 0231 0000 COMB .EQU OUTBUF+OUTSIZ ; 1000/1200-Hz comb filter 0232 0000 IGRTAB .EQU COMB+COMSIZ ; matched filter for timecode modulation 0233 0000 PPITAB .EQU IGRTAB+(IGRSIZ*2) ; minute buffer for 1-m sync 0234 0000 SECTAB .EQU PPITAB+(DATSIZ*2) ; minute buffer for data values 0235 0000 BCDCOD .EQU SECTAB+DATSIZ ; matched filter coefficients 0236 0000 USREND .EQU BCDCOD+BCDSIZ ; end of clear region 0237 0000 ; 0238 0000 ; Following are variables accessed by direct addressing mode. These are 0239 0000 ; offsets relative the the data page pointer. 0240 0000 ; 0241 0000 : Program variable offsets in block B2 (B_PAGE) initialized at startup. 0242 0000 ; 0243 0000 TNC_BUF .EQU 60h ; TNC_OUTPUT port status 0244 0000 PDC_BUF .EQU 61h ; RADIO_CTRL port status 0245 0000 ; 0246 0000 ; Program variable offsets in block B2 (B_PAGE) uninitialized. 0247 0000 ; 0248 0000 UARTI .EQU 62h ; UART input buffer 0249 0000 UARTO .EQU 63h ; UART output buffer 0250 0000 UARTC .EQU 64h ; UART modem control buffer 0251 0000 UARTL .EQU 65h ; UART divisor latch 0252 0000 XTMP .EQU 66h ; temp 0253 0000 ; 0254 0000 ; Program variable offsets in external memory (U_PAGE) initialized at 0255 0000 ; startup. 0256 0000 ; 0257 0000 PIO_BUF .EQU 00h ; RADIO_GAIN port status 0258 0000 ; 0259 0000 ; Program variable offsets in external memory (U_PAGE) cleared at reset. 0260 0000 ; 0261 0000 ; Analog signal variables 0262 0000 ; 0263 0000 INPSIG .EQU 01h ; AIO input buffer 0264 0000 F400 .EQU 02h ; 400-Hz bandpass filter 0265 0000 F150 .EQU 03h ; 150-Hz lowpass filter 0266 0000 SYNC .EQU 04h ; 1-s sync signal 0267 0000 IRIG .EQU 05h ; (2) 100-Hz I phase integrator 0268 0000 QRIG .EQU 07h ; (2) 100-Hz Q phase integrator 0269 0000 IGRPTR .EQU 09h ; 100-Hz integrator pointer 0270 0000 IGRATE .EQU 0Ah ; (2) 1000/1200-Hz I phase integrator 0271 0000 QGRATE .EQU 0Ch ; (2) 1000/1200-Hz Q phase integrator 0272 0000 PPIPTR .EQU 0Eh ; 1000/1200-Hz integrator pointer 0273 0000 ; 0274 0000 ; Variables used to establish 1-s sync epoch within the second and 0275 0000 ; discipline master oscillator frequency 0276 0000 ; 0277 0000 SYNPTR .EQU 10h ; 1-s sync integrator pointer 0278 0000 MAX .EQU 11h ; 1-s sync max amplitude 0279 0000 TEPOCH .EQU 12h ; 1-s sync epoch at max amplitude 0280 0000 TREG .EQU 13h ; (3) 1-s sync epoch median filter 0281 0000 XEPOCH .EQU 16h ; 1-s sync epoch (for compare) 0282 0000 YEPOCH .EQU 17h ; 1-s sync epoch 0283 0000 ZEPOCH .EQU 18h ; 1-s sync saved last interval 0284 0000 SYNCNT .EQU 19h ; 1-s sync run-length counter 0285 0000 JITCNT .EQU 1Ah ; 1-s sync run-length counter 0286 0000 AVGCNT .EQU 1Bh ; averaging interval counter 0287 0000 AVGINT .EQU 1Ch ; (2) log2 averaging time 0288 0000 PPIMAX .EQU 1Eh ; 1-m sync max amplitude 0289 0000 PPIPOS .EQU 1Fh ; 1-m sync epoch at max amplitude 0290 0000 ; 0291 0000 ; Variables used to establish basic system timing 0292 0000 ; 0293 0000 EPOCH .EQU 20h ; epoch ramp 0294 0000 FUDGE .EQU 21h ; (2) epoch phase 0295 0000 INCRX .EQU 23h ; (2) epoch frequency 0296 0000 MILLI .EQU 25h ; 1000/1200-Hz ramp 0297 0000 CYCLE .EQU 26h ; (2) 100-Hz ramp 0298 0000 RPHASE .EQU 28h ; 1-s ramp at receiver 0299 0000 RSEC .EQU 29h ; receiver seconds counter 0300 0000 ; 0301 0000 ; Variables used to establish the second, minute and day 0302 0000 ; 0303 0000 CDELAY .EQU 30h ; WWV propagation delay 0304 0000 HDELAY .EQU 31h ; WWVH propagation delay 0305 0000 TPHASE .EQU 32h ; 1-s ramp at transmitter 0306 0000 TSEC .EQU 33h ; second of minute (0-59/60) 0307 0000 MINUTE .EQU 34h ; minute of day (0-1439) 0308 0000 DAY .EQU 35h ; day of year (1-365/366) 0309 0000 MINSET .EQU 36h ; minutes since last set 0310 0000 ONE .EQU 37h ; the one and only one 0311 0000 ; 0312 0000 ; Variables used for data bit decoding and threshold correction 0313 0000 ; 0314 0000 DPULSE .EQU 40h ; data bit pulse length 0315 0000 P0 .EQU 41h ; P(0) probability 0316 0000 P1 .EQU 42h ; P(1) probability 0317 0000 P2 .EQU 43h ; P(2) probability 0318 0000 BIT .EQU 44h ; most recent bit value (P1-P0) 0319 0000 ; 0320 0000 ; Variables used to estimate signal levels and bit/digit probabilities 0321 0000 ; 0322 0000 SECAMP .EQU 45h ; 1-s sync amplitude (for debug) 0323 0000 MINAMP .EQU 46h ; 1-m sync amplitude 0324 0000 DATAMP .EQU 47h ; max signal amplitude 0325 0000 NOIAMP .EQU 48h ; average noise amplitude 0326 0000 DATSNR .EQU 49h ; data SNR (dB * 10) 0327 0000 DIGAMP .EQU 4Ah ; max digit amplitude 0328 0000 DIGSNR .EQU 4Bh ; digit SNR (dB * 10) 0329 0000 ; 0330 0000 ; Variables used to establish status and alarm conditions 0331 0000 ; 0332 0000 STATUS .EQU 50h ; status bits 0333 0000 MISC .EQU 51h ; miscellaneous timecode bits 0334 0000 ALARM .EQU 52h ; alarm flashers 0335 0000 ERRCNT .EQU 53h ; data bit error counter 0336 0000 ; 0337 0000 ; Signal generators for AIO output 0338 0000 ; 0339 0000 AIOPTR .EQU 55h ; AIO output pointer 0340 0000 SECRMP .EQU 56h ; 1-m ramp (AIO only) 0341 0000 HZ1000 .EQU 57h ; 1000/1200-Hz sinewave (AIO only) 0342 0000 HZ100 .EQU 58h ; 100-Hz sinewave (AIO only) 0343 0000 ; 0344 0000 ; Command interpreter variables and temporaries 0345 0000 ; 0346 0000 UTMP1 .EQU 60h ; user temp 1 0347 0000 UTMP2 .EQU 61h ; user temp 2 0348 0000 UCHAR .EQU 62h ; character temp 0349 0000 UPTR .EQU 63h ; pointer temp 0350 0000 UADR .EQU 64h ; address temp 0351 0000 UCMD .EQU 65h ; command table pointer 0352 0000 UMOD .EQU 66h ; saved command table pointer 0353 0000 DEBUG .EQU 67h ; debug mode 0354 0000 CLKPTR .EQU 68h ; clock pointer for s command 0355 0000 ACCUM .EQU 69h ; accumulator for c and h commands 0356 0000 ; 0357 0000 ; Local temporaries. These are not preserved by any routine. 0358 0000 ; 0359 0000 TMP .EQU 70h ; global temp 1 0360 0000 TMP2 .EQU 71h ; global temp 2 0361 0000 TMP3 .EQU 72h ; global temp 3 0362 0000 TMP4 .EQU 73h ; global temp 4 0363 0000 ITMP .EQU 74h ; reserved for interrupt routines 0364 0000 ; 0365 0000 ; Program transfer vector 0366 0000 ; 0367 1000 .ORG 1000h ; monitor origin 0368 1000 FF 80 10 77 B TINT ; timer interrupt 0369 1002 FF 80 10 0A B RINT ; AIO receive interrupt 0370 1004 FF 80 10 21 XIN10 B XINT ; AIO transmit interrupt 0371 1006 FF 80 10 34 B IINT ; TRAP instruction interrupt 0372 1008 FF 80 10 79 B GO ; program starting address 0373 100A 0374 100A ; 0375 100A ; AIO receive interrupt. This is designed for minimal intrusion on 0376 100A ; variables used by interruptable code. AIO rx interrupt is enabled when 0377 100A ; tx initialization is complete. 0378 100A ; 0379 100A ; Note: This is the only place where AR6 is incremented. Immediately 0380 100A ; after increment, AR6 is checked for overflow and wrapped. 0381 100A ; 0382 100A ; Variables 0383 100A ; AR6 AIO buffer pointer 0384 100A ; DRR AIO input buffer 0385 100A ; 0386 100A 55 8D RINT LARP AR5 ; save context 0387 100B 55 90 MAR *- 0388 100C 79 90 SST1 *- 0389 100D 78 90 SST *- 0390 100E 70 8E SAR AR0,*,AR6 ; AR6 is AIO buffer pointer 0391 100F C8 00 LDPK B_PAGE 0392 1010 30 00 LAR AR0,DRR ; read AIO input buffer 0393 1011 70 A0 SAR AR0,*+ 0394 1012 D0 00 05 32 LRLK AR0,INTBUF+BUFSIZ ; is pointer at buffer end 0395 1014 CE 50 CMPR 0396 1015 F8 80 10 19 BBZ RIN10 ; branch if no 0397 1017 D6 00 05 00 LRLK AR6,INTBUF ; yes. reset pointer 0398 1019 55 8D RIN10 LARP AR5 0399 101A FE 80 10 68 CALL DUMP ; dump status 0400 101C 30 A0 LAR AR0,*+ ; restore context 0401 101D 50 A0 LST *+ 0402 101E 51 A0 LST1 *+ 0403 101F CE 00 EINT ; enable interrupts 0404 1020 CE 26 RET 0405 1021 0406 1021 ; 0407 1021 ; AIO transmit interrupt used in normal processing 0408 1021 ; 0409 1021 ; Variables 0410 1021 ; AR6 AIO buffer pointer 0411 1021 ; DXR AIO output buffer 0412 1021 ; 0413 1021 55 8D XINT LARP AR5 ; save context 0414 1022 55 90 MAR *- 0415 1023 79 90 SST1 *- 0416 1024 78 90 SST *- 0417 1025 70 8E SAR AR0,*,AR6 ; AR6 is AIO buffer pointer 0418 1026 C8 00 LDPK B_PAGE 0419 1027 30 8D LAR AR0,*,AR5 ; write AIO output buffer 0420 1028 70 01 SAR AR0,DXR 0421 1029 FE 80 10 68 CALL DUMP ; dump status 0422 102B 30 A0 LAR AR0,*+ ; restore context 0423 102C 50 A0 LST *+ 0424 102D 51 A0 LST1 *+ 0425 102E CE 00 EINT ; enable interrupts 0426 102F CE 26 RET 0427 1030 0428 1030 ; 0429 1030 ; AIO transmit interrupt routine used only during AIO configuration. 0430 1030 ; Note that the ARP and designated AR point to configuration data. 0431 1030 ; 0432 1030 ; Variables 0433 1030 ; DXR AIO output buffer 0434 1030 ; 0435 1030 20 A0 XINT2 LAC *+ ; this has to be quick and ugly 0436 1031 60 01 SACL DXR 0437 1032 CE 00 EINT 0438 1033 CE 26 RET 0439 1034 0440 1034 ; 0441 1034 ; Trap interrupt (for debug). TRAP instructions can be sprinkled in the 0442 1034 ; code to watch critical sections and leave tracks useful for debugging. 0443 1034 ; 0444 1034 CE 01 IINT DINT ; avoid interrupts here 0445 1035 55 8D LARP AR5 ; save context 0446 1036 55 90 MAR *- 0447 1037 79 90 SST1 *- 0448 1038 78 90 SST *- 0449 1039 70 80 SAR AR0,* 0450 103A C8 00 LDPK B_PAGE 0451 103B FE 80 10 68 CALL DUMP ; dump status 0452 103D 30 A0 LAR AR0,*+ ; restore context 0453 103E 50 A0 LST *+ 0454 103F 51 A0 LST1 *+ 0455 1040 CE 00 EINT ; enable interrupts 0456 1041 CE 26 RET 0457 1042 0458 1042 ; 0459 1042 ; UART output interrupt routine. Preserved context includes AC. 0460 1042 ; 0461 1042 55 8D URTINT LARP AR5 ; save context 0462 1043 55 90 MAR *- 0463 1044 79 90 SST1 *- 0464 1045 78 90 SST *- 0465 1046 60 90 SACL *- 0466 1047 68 90 SACH *- 0467 1048 70 8B SAR AR0,*,AR3 0468 1049 C8 08 LDPK U_PAGE 0469 104A D3 00 05 32 LRLK AR3,INPBCB ; are characters hiding in the buffer 0470 104C FE 80 18 FC CALL GETBUF 0471 104E C8 00 LDPK B_PAGE 0472 104F F6 80 10 59 BZ URT10 ; branch if no 0473 1051 60 63 SACL UARTO ; yes. output character 0474 1052 D0 01 00 00 LALK UART_SEL_RX 0475 1054 60 66 SACL XTMP 0476 1055 E3 66 OUT XTMP,UART_CTRL 0477 1056 E1 63 OUT UARTO,UART_WRITE 0478 1057 FF 80 10 60 B URT11 0479 1059 ; 0480 1059 D0 01 01 00 URT10 LALK UART_SEL_IER ; disable transmit interrrupt 0481 105B 60 66 SACL XTMP 0482 105C E3 66 OUT XTMP,UART_CTRL 0483 105D CA 00 ZAC 0484 105E 60 66 SACL XTMP 0485 105F E1 66 OUT XTMP,UART_WRITE 0486 1060 55 8D URT11 LARP AR5 ; restore context 0487 1061 30 A0 LAR AR0,*+ 0488 1062 40 A0 ZALH *+ 0489 1063 49 A0 ADDS *+ 0490 1064 50 A0 LST *+ 0491 1065 51 A0 LST1 *+ 0492 1066 CE 00 EINT ; enable interrupts 0493 1067 CE 26 RET 0494 1068 0495 1068 ; 0496 1068 ; Routine to dump trace data for debug. This is done on every I/O and 0497 1068 ; TRAP interrupt. At this point, SS1, SS0 and AR0 are already on the 0498 1068 ; stack (AR5) and the data page pointer set to B_PAGE (0). The remaining 0499 1068 ; registers and top two words on the internal CPU stack are saved. 0500 1068 ; 0501 1068 75 66 DUMP SAR AR5,XTMP ; save stack pointer 0502 1069 55 90 MAR *- 0503 106A 71 90 SAR AR1,*- ; save aux registers AR1-AR7 0504 106B 72 90 SAR AR2,*- 0505 106C 73 90 SAR AR3,*- 0506 106D 74 90 SAR AR4,*- 0507 106E 75 90 SAR AR5,*- 0508 106F 76 90 SAR AR6,*- 0509 1070 77 90 SAR AR7,*- 0510 1071 7A 90 POPD *- ; save calling address 0511 1072 7A 80 POPD * ; save interrupting address 0512 1073 54 A0 PSHD *+ 0513 1074 54 90 PSHD *- 0514 1075 35 66 LAR AR5,XTMP ; restore stack pointer 0515 1076 CE 26 RET 0516 1077 0517 1077 ; 0518 1077 ; Timer interrupt (not used) 0519 1077 ; 0520 1077 CE 00 TINT EINT ; enable interrupts 0521 1078 CE 26 RET 0522 1079 0523 1079 ; 0524 1079 ; Initialize processor configuration. These set the options as does the 0525 1079 ; CPU upon first coming up; they are here in case the monitor screws up. 0526 1079 ; 0527 1079 CE 04 GO CNFD ; configure block B0 as data 0528 107A CE 07 SSXM ; set sign extension mode 0529 107B CE 03 SOVM ; set overflow mode 0530 107C CE 09 SPM 1 ; set P register output shift for q15 0531 107D CE 0E FORT 0 ; set AIO 16-bit mode 0532 107E CE 37 SFSM ; set FSM (1) frame sync mode 0533 107F CE 20 RTXM ; set TXM (0) transmit mode 0534 1080 C8 08 LDPK U_PAGE 0535 1081 D0 01 80 25 LALK AIO_RESET+GAIN4+REC_IN_1 ; reset AIO 0536 1083 60 00 SACL PIO_BUF 0537 1084 E7 00 OUT PIO_BUF,RADIO_GAIN 0538 1085 FE 80 19 B0 CALL WAIT4 0539 1087 D0 01 00 65 LALK LED_202+GAIN4+REC_IN_1 ; disable AIO; LED 2 on (debug) 0540 1089 60 00 SACL PIO_BUF 0541 108A E7 00 OUT PIO_BUF,RADIO_GAIN 0542 108B FE 80 19 B0 CALL WAIT4 0543 108D D0 01 40 25 LALK AIO_ENABLE+GAIN4+REC_IN_1 ;enable AIO 0544 108F 60 00 SACL PIO_BUF 0545 1090 E7 00 OUT PIO_BUF,RADIO_GAIN 0546 1091 FE 80 19 B0 CALL WAIT4 0547 1093 C8 00 LDPK B_PAGE 0548 1094 CB 07 RPTK 8-1 ; flush stack 0549 1095 CE 1D POP 0550 1096 D5 00 04 00 LRLK AR5,STACK ; initialize stack pointer 0551 1098 D6 00 05 00 LRLK AR6,INTBUF ; initialize AIO buffer pointers 0552 109A D7 00 05 00 LRLK AR7,INTBUF 0553 109C ; 0554 109C ; Set up for AIO initialization. Keep this a deep dark secret and don't 0555 109C ; tell anybody the transmit interrupt routines are switched on-the-wing 0556 109C ; for configuration. This is because the AIO rascal has unreal latency 0557 109C ; requirements only during initialization. There seems to be no way for 0558 109C ; an interrupt routine to satisfy these without appearing non- 0559 109C ; transparent for general purpose processing. 0560 109C ; 0561 109C CE 01 DINT ; turn out the lights 0562 109D D0 01 10 30 LALK XINT2 0563 109F 60 66 SACL XTMP 0564 10A0 D0 01 10 05 LALK XIN10+1 ; clobber transmit vector 0565 10A2 59 66 TBLW XTMP 0566 10A3 55 8F LARP AR7 ; copy AIO initialization vector 0567 10A4 CB 06 RPTK 7-1 0568 10A5 FC A0 1A AC BLKP INITAB,*+ 0569 10A7 CA 20 LACK IMR_XINT ; enable AIO tx interrupt only 0570 10A8 60 04 SACL IMR 0571 10A9 CA 00 ZAC ; flush AIO tx buffer 0572 10AA 60 01 SACL DXR 0573 10AB CE 00 EINT ; turn on the lights 0574 10AC 55 8E LARP AR6 ; load initialization word 0575 10AD CE 1F INI10 IDLE ; wait for interrupt and AC 0576 10AE F5 80 10 AD BNZ INI10 ; branch if more 0577 10B0 CE 01 DINT ; done. darkness again 0578 10B1 D0 01 10 21 LALK XINT ; unclobber transmit vector 0579 10B3 60 66 SACL XTMP 0580 10B4 D0 01 10 05 LALK XIN10+1 0581 10B6 59 66 TBLW XTMP 0582 10B7 D0 01 FF 80 LALK 0FF80h ; (B) plant INT1 interrupt for UART 0583 10B9 60 66 SACL XTMP 0584 10BA D0 01 00 04 LALK 4 0585 10BC 59 66 TBLW XTMP 0586 10BD D0 01 10 42 LALK URTINT 0587 10BF 60 66 SACL XTMP 0588 10C0 D0 01 00 05 LALK 4+1 0589 10C2 59 66 TBLW XTMP 0590 10C3 CA 32 LACK IMR_XINT+IMR_RINT+IMR_INT1 ; enable interrupts 0591 10C4 60 04 SACL IMR 0592 10C5 C8 08 LDPK U_PAGE 0593 10C6 FE 80 19 80 CALL RESET ; initialize program variables 0594 10C8 CE 00 EINT ; enable interrupts 0595 10C9 ; 0596 10C9 ; Loop looking for a AIO input sample. When found, the RF input 0597 10C9 ; processing routine is called to filter and limit the input signal. 0598 10C9 ; 0599 10C9 ; Note: This is the only place where AR6 is compared to AR7. The CMPR 0600 10C9 ; insruction represents the atomic interaction in order to determine 0601 10C9 ; whether data are in the buffer or not; thus, there are no races. Even 0602 10C9 ; if there were, unread data would get caught on the next cycle through 0603 10C9 ; the loop. 0604 10C9 ; 0605 10C9 55 8F LOOP LARP AR7 ; AR7 is AIO buffer pointer 0606 10CA 76 70 SAR AR6,TMP ; are there data in the buffer 0607 10CB 30 70 LAR AR0,TMP 0608 10CC CE 50 CMPR 0609 10CD F8 80 10 E0 BBZ LOP10 ; branch if yes 0610 10CF 55 89 LARP AR1 ; no. preserve convention 0611 10D0 D0 01 00 40 LALK LED_202 ; LED 2 on 0612 10D2 FE 80 19 78 CALL LEDON 0613 10D4 FE 80 16 E2 CALL GETCH ; UART input processing 0614 10D6 FE 80 18 A6 CALL URTCTL ; UART control registers 0615 10D8 D0 01 00 40 LALK LED_202 ; LED 2 off 0616 10DA FE 80 19 7B CALL LEDOFF 0617 10DC FE 80 19 2F CALL LIGHTS ; panel display/control 0618 10DE FF 80 10 C9 B LOOP 0619 10E0 ; 0620 10E0 ; Save the AIO input buffer and call the RF input routines to filter the 0621 10E0 ; input signal and extract the sync and data signals. Also call the RF 0622 10E0 ; output routine to generate various test and monitoring signals. 0623 10E0 ; 0624 10E0 22 89 LOP10 LAC *,2,AR1 ; load sample in q15 format 0625 10E1 60 01 SACL INPSIG 0626 10E2 FE 80 16 BD CALL RFOUT ; call RF output routine 0627 10E4 FE 80 15 FD LOP17 CALL RFINP ; call RF input routine 0628 10E6 0629 10E6 ; 0630 10E6 ; There are three 1-s epoches used by this program, all spanning the 0631 10E6 ; range 0-7999 sample ticks and all repeating at intervals of exactly 0632 10E6 ; one second. The receiver epoch begins upon arrival of the 1-s sync 0633 10E6 ; pulse; while the transmitter epoch begins before it by the propagation 0634 10E6 ; delay specified by the C or H commands. The third epoch, called simply 0635 10E6 ; that in the comments, begins at an arbitrary time, depending on when 0636 10E6 ; this program actually starts up. 0637 10E6 ; 0638 10E6 ; This section scans the epoch looking for seconds sync and establishes 0639 10E6 ; the transmitter and receiver epoch. The seconds sync relative to the 0640 10E6 ; epoch is determined by the 1-s sync pulse detected in the RF input 0641 10E6 ; routine. The actual A/D sample frequency is determined by the hardware 0642 10E6 ; at 7949 samples/s, but this is stuffed to create 8000 samples/s for 0643 10E6 ; the actual sample clock. The phase and frequency of the sample clock 0644 10E6 ; are adjusted to match the 1-s sync pulse as broadcast. The receiver 0645 10E6 ; epoch establishes the modulation maxima, minima and data sample time. 0646 10E6 ; The transmitter epoch leads the receiver epoch by the propagation 0647 10E6 ; delay. It establishes the clock time and implements the sometimes 0648 10E6 ; idiosyncratic conventional clock time and civil calendar. 0649 10E6 ; 0650 10E6 ; Each receiver epoch contains one of three data signals at 100 Hz, a 0651 10E6 ; 200-ms pulse (P0), 500-ms pulse (P1) or 800-ms pulse (P2), but the 0652 10E6 ; first 30 ms of every pusle is punched out for the 1-s sync pulse. The 0653 10E6 ; data are filtered by a 170-ms synchronous matched filter in the RF 0654 10E6 ; input routine. The noise reference level is the averaged in-phase 0655 10E6 ; filter output at the end of the first 30-ms segment, while the signal 0656 10E6 ; reference level is at the end of the first 200-ms segment. The slice 0657 10E6 ; level is midway between the signal and noise reference levels. The 0658 10E6 ; length of the data bit pulse is determined from the reciever epoch at 0659 10E6 ; the first negative-going crossing of the slice level following the 0660 10E6 ; first 200-ms segment. The probabilities of P0, P1 and P2 are 0661 10E6 ; determined from the signal crossing time, delayed by one-half the 0662 10E6 ; matched filter delay. 0663 10E6 ; 0664 10E6 ; Most communications radios use a lowpass filter in the audio stages, 0665 10E6 ; which can do nasty things to the 100-Hz subcarrier phase relative to 0666 10E6 ; the 1-s sync pulse. Therefore, the 100-Hz signal is disciplined to the 0667 10E6 ; averaged quadrature-phase filter output at the end of the first 200-ms 0668 10E6 ; segment. 0669 10E6 ; 0670 10E6 ; Epoch 30 ms - bottom fisher. Save the min for later. 0671 10E6 ; 0672 10E6 20 28 LAC RPHASE ; is epoch 30 ms 0673 10E7 D0 03 00 F0 SBLK 30*MS 0674 10E9 F3 80 11 2E BLZ LOP20 ; branch if no 0675 10EB F1 80 10 F6 BGZ LOP12 ; branch if no 0676 10ED 7B 05 ZALR IRIG ; average noise amplitude 0677 10EE CE 1B ABS 0678 10EF 44 48 SUBH NOIAMP 0679 10F0 CB 03 RPTK TCONST 0680 10F1 CE 19 SFR 0681 10F2 48 48 ADDH NOIAMP 0682 10F3 68 48 SACH NOIAMP 0683 10F4 FF 80 11 2E B LOP20 0684 10F6 ; 0685 10F6 ; Epoch 200 ms - top fisher. Save the max for later. 0686 10F6 ; 0687 10F6 D0 03 05 50 LOP12 SBLK 170*MS ; is epoch 200 ms 0688 10F8 F3 80 11 2E BLZ LOP20 ; branch if no 0689 10FA F1 80 11 23 BGZ LOP13 ; branch if no 0690 10FC 20 05 LAC IRIG ; yes. latch maximum amplitudes 0691 10FD F4 80 11 00 BGEZ LOP11 0692 10FF CA 00 ZAC 0693 1100 60 47 LOP11 SACL DATAMP ; compute data SNR 0694 1101 20 48 LAC NOIAMP 0695 1102 FE 80 16 CC CALL LOG10 0696 1104 60 49 SACL DATSNR 0697 1105 20 47 LAC DATAMP ; latch peak envelope amplitude 0698 1106 FE 80 16 CC CALL LOG10 0699 1108 10 49 SUB DATSNR 0700 1109 F4 80 11 0C BGEZ LOP20A 0701 110B CA 00 ZAC 0702 110C CE 18 LOP20A SFL ; 20 * log10() 0703 110D 60 49 SACL DATSNR 0704 110E 9F 50 BIT STATUS,SSYNC ; is second in synch 0705 110F F8 80 11 23 BBZ LOP13 ; branch if no 0706 1111 20 1C LAC AVGINT ; yes. compute loop gain 0707 1112 CC 0A ADDK 10 0708 1113 60 73 SACL TMP4 0709 1114 40 07 ZALH QRIG ; adjust subcarrier phase 0710 1115 49 08 ADDS QRIG+1 0711 1116 CE 23 NEG 0712 1117 4B 73 RPT TMP4 ; match the gain to the pain 0713 1118 CE 19 SFR 0714 1119 48 26 ADDH CYCLE 0715 111A 49 27 ADDS CYCLE+1 0716 111B 68 26 SACH CYCLE 0717 111C 60 27 SACL CYCLE+1 0718 111D 20 26 LAC CYCLE ; mod 80 0719 111E CD 50 SUBK 80 0720 111F F4 80 11 22 BGEZ LOP16A 0721 1121 CC 50 ADDK 80 0722 1122 60 26 LOP16A SACL CYCLE 0723 1123 ; 0724 1123 ; Epoch 200-999 ms - data fisher. Save the zero crossing. 0725 1123 ; 0726 1123 20 47 LOP13 LAC DATAMP ; compute slice level 0727 1124 00 48 ADD NOIAMP 0728 1125 CE 19 SFR 0729 1126 10 05 SUB IRIG ; is transmitter key down 0730 1127 F3 80 11 2E BLZ LOP20 ; branch if yes 0731 1129 20 40 LAC DPULSE ; no. has epoch been stored 0732 112A F5 80 11 2E BNZ LOP20 ; branch if yes 0733 112C 20 28 LAC RPHASE ; no. latch epoch 0734 112D 60 40 SACL DPULSE 0735 112E LOP20 0736 112E ; 0737 112E ; At the end of the transmitter second, tick the clock and update the 0738 112E ; time of century. 0739 112E ; 0740 112E 20 32 LAC TPHASE ; advance transmitter epoch 0741 112F CC 01 ADDK 1 0742 1130 60 32 SACL TPHASE 0743 1131 99 50 BIT STATUS,WWVH ; determine propagation delay 0744 1132 F9 80 11 37 BBNZ LOP44 0745 1134 20 30 LAC CDELAY ; Ft. Collins 0746 1135 FF 80 11 38 B LOP47 0747 1137 ; 0748 1137 20 31 LOP44 LAC HDELAY ; Kaui 0749 1138 00 28 LOP47 ADD RPHASE 0750 1139 D0 03 1F 40 SBLK COMSIZ ; mod 8000 0751 113B F4 80 11 3F BGEZ LOP48 ; is this end of transmitter second 0752 113D D0 02 1F 40 ADLK COMSIZ 0753 113F F5 80 11 45 LOP48 BNZ LOP46 ; branch if no 0754 1141 FE 80 15 34 CALL TOCK ; yes. process epoch data 0755 1143 CA 00 ZAC ; reset for next second 0756 1144 60 32 SACL TPHASE 0757 1145 LOP46 0758 1145 ; 0759 1145 ; At the end of the receiver second, process the data bit and update the 0760 1145 ; decoding matrix probabilities. 0761 1145 ; 0762 1145 20 28 LAC RPHASE ; advance receiver epoch 0763 1146 CC 01 ADDK 1 0764 1147 60 28 SACL RPHASE 0765 1148 20 20 LAC EPOCH ; is this end of receiver second 0766 1149 10 17 SUB YEPOCH 0767 114A F5 80 11 53 BNZ LOP19 ; branch if no 0768 114C FE 80 12 82 CALL DATA ; yes. process epoch data 0769 114E FE 80 13 16 CALL VSEC 0770 1150 CA 00 ZAC ; reset for next second 0771 1151 60 28 SACL RPHASE 0772 1152 60 40 SACL DPULSE 0773 1153 LOP19 0774 1153 ; 0775 1153 ; Advance 1-ms and 10-ms ramps, and determine if stuffing cycle is 0776 1153 ; needed. We don't care about the 1000/1200-Hz phase, but we do care 0777 1153 ; about the 100-Hz phase, since that has been fiddled above. 0778 1153 ; 0779 1153 CA 0A LACK IN1000 ; select ramp increment 0780 1154 99 50 BIT STATUS,WWVH 0781 1155 F8 80 11 58 BBZ LOP18 0782 1157 CA 0C LACK IN1200 0783 1158 00 25 LOP18 ADD MILLI ; advance 1000/1200-Hz ramp 0784 1159 CD 50 SUBK 80 0785 115A F4 80 11 5D BGEZ LOP15 0786 115C CC 50 ADDK 80 0787 115D 60 25 LOP15 SACL MILLI 0788 115E CA 01 LACK 1 ; advance 100-Hz ramp 0789 115F 00 26 ADD CYCLE 0790 1160 CD 50 SUBK 80 0791 1161 F4 80 11 64 BGEZ LOP16 0792 1163 CC 50 ADDK 80 0793 1164 60 26 LOP16 SACL CYCLE 0794 1165 20 21 LAC FUDGE ; is a stuffing cycle needed 0795 1166 F3 80 10 C9 BLZ LOOP ; branch if no 0796 1168 90 22 BIT FUDGE+1,15 0797 1169 F9 80 10 C9 BBNZ LOOP ; branch if no 0798 116B CD 01 SUBK 1 ; yes. run through all this again 0799 116C 60 21 SACL FUDGE 0800 116D FF 80 10 E4 B LOP17 0801 116F 0802 116F ; 0803 116F ; This routine is called at the end of the epoch. It determines scan 0804 116F ; phase and adjusts frequency using a frequency-lock loop. 0805 116F ; 0806 116F ; Seconds sync is determined in the RF input routine as the maximum over 0807 116F ; all 8000 samples in the seconds comb filter. To assure accurate and 0808 116F ; reliable time and frequency discipline, this routine performs a great 0809 116F ; deal of heavy-handed data filtering and conditioning. 0810 116F ; 0811 116F 20 14 ENDPOC LAC TREG+1 ; shift new sample in median filter 0812 1170 60 15 SACL TREG+2 0813 1171 20 13 LAC TREG 0814 1172 60 14 SACL TREG+1 0815 1173 20 12 LAC TEPOCH 0816 1174 60 13 SACL TREG 0817 1175 ; 0818 1175 ; Use a three-stage median filter to toss outlyers 0819 1175 ; 0820 1175 20 13 LAC TREG ; 0>1 0821 1176 10 14 SUB TREG+1 0822 1177 FE 80 15 EC CALL MOD8K 0823 1179 F3 80 11 99 BLZ EPC52 ; branch if no 0824 117B 20 14 LAC TREG+1 ; 1<2 0825 117C 10 15 SUB TREG+2 0826 117D FE 80 15 EC CALL MOD8K 0827 117F F1 80 11 93 BGZ EPC51 ; branch if no 0828 1181 20 15 LAC TREG+2 ; 2<0 0829 1182 10 13 SUB TREG 0830 1183 FE 80 15 EC CALL MOD8K 0831 1185 F1 80 11 8D BGZ EPC50 ; branch if no 0832 1187 20 13 LAC TREG ; 0>1, 1<2, 2<0 => 2 0833 1188 10 14 SUB TREG+1 0834 1189 60 72 SACL TMP3 0835 118A 20 15 LAC TREG+2 0836 118B FF 80 11 B7 B EPC55 0837 118D ; 0838 118D 20 15 EPC50 LAC TREG+2 ; 0>1, 1<2, 2>0 => 0 0839 118E 10 14 SUB TREG+1 0840 118F 60 72 SACL TMP3 0841 1190 20 13 LAC TREG 0842 1191 FF 80 11 B7 B EPC55 0843 1193 ; 0844 1193 20 13 EPC51 LAC TREG ; 0>1, 1>2, 2<0 => 1 0845 1194 10 15 SUB TREG+2 0846 1195 60 72 SACL TMP3 0847 1196 20 14 LAC TREG+1 0848 1197 FF 80 11 B7 B EPC55 0849 1199 ; 0850 1199 20 14 EPC52 LAC TREG+1 ; 1>2 0851 119A 10 15 SUB TREG+2 0852 119B FE 80 15 EC CALL MOD8K 0853 119D F3 80 11 B1 BLZ EPC54 ; branch if no 0854 119F 20 15 LAC TREG+2 ; 2<0 0855 11A0 10 13 SUB TREG 0856 11A1 FE 80 15 EC CALL MOD8K 0857 11A3 F1 80 11 AB BGZ EPC53 ; branch if no 0858 11A5 20 14 LAC TREG+1 ; 0<1, 1>2, 2<0 => 0 0859 11A6 10 15 SUB TREG+2 0860 11A7 60 72 SACL TMP3 0861 11A8 20 13 LAC TREG 0862 11A9 FF 80 11 B7 B EPC55 0863 11AB ; 0864 11AB 20 14 EPC53 LAC TREG+1 ; 0<1, 1>2, 2>0 => 2 0865 11AC 10 13 SUB TREG 0866 11AD 60 72 SACL TMP3 0867 11AE 20 15 LAC TREG+2 0868 11AF FF 80 11 B7 B EPC55 0869 11B1 ; 0870 11B1 20 15 EPC54 LAC TREG+2 ; 0<1, 1<2, 2>0 => 1 0871 11B2 10 13 SUB TREG 0872 11B3 60 72 SACL TMP3 0873 11B4 20 14 LAC TREG+1 0874 11B5 FF 80 11 B7 B EPC55 0875 11B7 ; 0876 11B7 60 12 EPC55 SACL TEPOCH ; update median 0877 11B8 ; 0878 11B8 ; The sample is discarded if the median filter span is greater than 1 ms 0879 11B8 ; or if the 1-s sync pulse amplitude is less than the decision 0880 11B8 ; threshold. If the difference between the current and the last sample 0881 11B8 ; is less than 1 ms, the sample is considered valid and the jitter 0882 11B8 ; counter is reset to zero; otherwise, the sample is ignored and the 0883 11B8 ; jitter counter is incremented. If the jitter counter exceeds the 0884 11B8 ; frequency averaging interval, the new sample is considered valid 0885 11B8 ; anyway and replaces the old one. The compare counter is incremented if 0886 11B8 ; the current sample is identical to the last one; otherwise, it is 0887 11B8 ; forced to zero. If the compare counter increments to 10, the receiver 0888 11B8 ; epoch is reset to the 1-s pulse epoch as broadcast. 0889 11B8 ; 0890 11B8 20 11 LAC MAX ; is sync above threshold 0891 11B9 60 45 SACL SECAMP 0892 11BA D0 03 05 DC SBLK STHR 0893 11BC F3 80 11 C2 BLZ EPC22 ; branch if no 0894 11BE 20 72 LAC TMP3 ; yes. is span less than 1 ms 0895 11BF CD 08 SUBK MS 0896 11C0 F3 80 11 CF BLZ EPC27 ; branch if yes 0897 11C2 CA 00 EPC22 ZAC ; no. reset counters 0898 11C3 60 19 SACL SYNCNT 0899 11C4 60 1A SACL JITCNT 0900 11C5 D0 01 FF FE LALK ~(1< [0, 3999], [-4000, 3999] -> [-4000, 3999], 1857 15EC ; [4000, 7999] -> [-4000, -1] 1858 15EC ; 1859 15EC D0 03 0F A0 MOD8K SBLK COMSIZ/2 ; is it [4000, 7999] 1860 15EE F3 80 15 F4 BLZ MOD10 ; branch if no 1861 15F0 D0 03 0F A0 SBLK COMSIZ/2 ; yes. [-4000, -1] 1862 15F2 FF 80 15 FC B MOD20 1863 15F4 ; 1864 15F4 D0 02 1F 40 MOD10 ADLK COMSIZ ; no. is it [-8000, -4001] 1865 15F6 F1 80 15 FA BGZ MOD30 ; branch if no 1866 15F8 D0 02 1F 40 ADLK COMSIZ ; yes. [0, 3999] 1867 15FA D0 03 0F A0 MOD30 SBLK COMSIZ/2 1868 15FC CE 26 MOD20 RET 1869 15FD 1870 15FD ; 1871 15FD ; RF input processing 1872 15FD ; 1873 15FD ; Clip signals with energy above an arbitrary threshold (LIMIT). This 1874 15FD ; helps to reduce errors due to noise spikes and static crashes, etc. 1875 15FD ; The threshold is chosen rather arbitrary at 10 dB below overload. LED1 1876 15FD ; is lit when in limiting condition. 1877 15FD ; 1878 15FD 20 01 RFINP LAC INPSIG ; is signal above threshold 1879 15FE CE 1B ABS 1880 15FF D0 03 27 10 SBLK LIMIT 1881 1601 F3 80 16 09 BLZ INP10 ; branch if no 1882 1603 D0 01 00 80 LALK LED_201 ; yes. LED 1 on 1883 1605 FE 80 19 78 CALL LEDON 1884 1607 FF 80 16 0D B INP11 1885 1609 ; 1886 1609 D0 01 00 80 INP10 LALK LED_201 ; signal below threshold. LED 1 off 1887 160B FE 80 19 7B CALL LEDOFF 1888 160D 20 01 INP11 LAC INPSIG ; clip signal at max 1889 160E D0 03 27 10 SBLK LIMIT 1890 1610 F3 80 16 13 BLZ INP12 1891 1612 CA 00 ZAC 1892 1613 D0 02 4E 20 INP12 ADLK 2*LIMIT ; clip signal at min 1893 1615 F1 80 16 18 BGZ INP13 1894 1617 CA 00 ZAC 1895 1618 D0 03 27 10 INP13 SBLK LIMIT 1896 161A 60 72 SACL TMP3 1897 161B 20 10 LAC SYNPTR ; determine epoch 1898 161C D0 03 0D 0A SBLK COMB 1899 161E 60 20 SACL EPOCH 1900 161F ; 1901 161F ; For the data signal, use a 150-Hz lowpass filter to avoid aliasing. 1902 161F ; 1903 161F D1 00 02 52 INP29 LRLK AR1,DELLPF ; AR1->z^-0 1904 1621 20 72 LAC TMP3 ; initialize sum and product registers 1905 1622 60 80 SACL * 1906 1623 7E 28 ADRK FIRLEN-1 ; AR1->z^n 1907 1624 A0 00 MPYK 0 1908 1625 CA 00 ZAC 1909 1626 CB 28 RPTK FIRLEN-1 ; multiply and accumulate (q15) 1910 1627 5C 90 1B DA MACD LPF150,*- 1911 1629 CE 15 APAC ; include last product 1912 162A 68 03 SACH F150 1913 162B ; 1914 162B ; Extract the data using a 170-ms matched filter at 100 Hz. We need both 1915 162B ; the I and Q phases in order to correct for the low frequency phase 1916 162B ; delay in some radios. 1917 162B ; 1918 162B 20 26 LAC CYCLE ; get sin table pointer 1919 162C D0 02 1C 55 ADLK SINTAB 1920 162E 58 58 TBLR HZ100 ; multiply signal by sin 1921 162F 3C 58 LT HZ100 1922 1630 38 03 MPY F150 1923 1631 CE 14 PAC 1924 1632 6A 70 SACH TMP,2 1925 1633 31 09 LAR AR1,IGRPTR ; get circular buffer pointer 1926 1634 40 05 ZALH IRIG ; add new sample 1927 1635 49 06 ADDS IRIG+1 1928 1636 09 70 ADD TMP,16-7 ; note normalization 1/128 approximate 1929 1637 19 80 SUB *,16-7 ; subtract old sample 1930 1638 68 05 SACH IRIG 1931 1639 60 06 SACL IRIG+1 1932 163A 20 70 LAC TMP ; save new sample 1933 163B 60 A0 SACL *+ 1934 163C 20 26 LAC CYCLE ; get cos table pointer 1935 163D CD 14 SUBK 20 1936 163E F4 80 16 41 BGEZ INP31 1937 1640 CC 50 ADDK 80 1938 1641 D0 02 1C 55 INP31 ADLK SINTAB 1939 1643 58 70 TBLR TMP 1940 1644 3C 70 LT TMP ; multiply signal by cos 1941 1645 38 03 MPY F150 1942 1646 CE 14 PAC 1943 1647 6A 70 SACH TMP,2 1944 1648 40 07 ZALH QRIG ; add new sample 1945 1649 49 08 ADDS QRIG+1 1946 164A 09 70 ADD TMP,16-7 ; note normalization 1/128 approximate 1947 164B 19 80 SUB *,16-7 ; subtract old sample 1948 164C 68 07 SACH QRIG 1949 164D 60 08 SACL QRIG+1 1950 164E 20 70 LAC TMP ; save new sample 1951 164F 60 A0 SACL *+ 1952 1650 D0 00 36 EA LRLK AR0,IGRTAB+(IGRSIZ*2) ; update delay line pointer 1953 1652 CE 50 CMPR 1954 1653 F8 80 16 57 BBZ INP30 1955 1655 D1 00 2C 4A LRLK AR1,IGRTAB 1956 1657 71 09 INP30 SAR AR1,IGRPTR 1957 1658 ; 1958 1658 ; For the 1-s and 1-m sync signals, use a 400-Hz bandpass filter at 1959 1658 ; 1100-Hz to avoid aliasing. 1960 1658 ; 1961 1658 D1 00 02 28 LRLK AR1,DELBPF ; AR1->z^-0 1962 165A 20 72 LAC TMP3 ; initialize sum and product registers 1963 165B 60 80 SACL * 1964 165C 7E 28 ADRK FIRLEN-1 ; AR1->z^n 1965 165D A0 00 MPYK 0 1966 165E CA 00 ZAC 1967 165F CB 28 RPTK FIRLEN-1 ; multiply and accumulate (q15) 1968 1660 5C 90 1B B1 MACD BPF400,*- 1969 1662 CE 15 APAC ; include last product 1970 1663 68 02 SACH F400 1971 1664 ; 1972 1664 ; Extract the 1-m sync signal using a 800-ms noncoherent integrator at 1973 1664 ; 1000/1200 Hz. 1974 1664 ; 1975 1664 20 25 LAC MILLI ; get sin table pointer 1976 1665 D0 02 1C 55 ADLK SINTAB 1977 1667 58 57 TBLR HZ1000 1978 1668 3C 02 LT F400 ; multiply signal by sin 1979 1669 38 57 MPY HZ1000 1980 166A CE 14 PAC 1981 166B 68 70 SACH TMP 1982 166C 40 0A ZALH IGRATE ; add to I channel integrator 1983 166D 49 0B ADDS IGRATE+1 1984 166E 07 70 ADD TMP,16-9 ; note normalization 1/512 approximate 1985 166F 68 0A SACH IGRATE 1986 1670 60 0B SACL IGRATE+1 1987 1671 20 25 LAC MILLI ; get cos table pointer 1988 1672 CD 14 SUBK 20 1989 1673 F4 80 16 76 BGEZ INP27 1990 1675 CC 50 ADDK 80 1991 1676 D0 02 1C 55 INP27 ADLK SINTAB 1992 1678 58 70 TBLR TMP 1993 1679 3C 02 LT F400 ; multiply signal by cos 1994 167A 38 70 MPY TMP 1995 167B CE 14 PAC 1996 167C 68 70 SACH TMP 1997 167D 40 0C ZALH QGRATE ; add to Q channel integrator 1998 167E 49 0D ADDS QGRATE+1 1999 167F 07 70 ADD TMP,16-9 ; note normalization 1/512 approximate 2000 1680 68 0C SACH QGRATE 2001 1681 60 0D SACL QGRATE+1 2002 1682 ; 2003 1682 ; Extract the 1-s sync signal using a 5-ms matched filter and 1-s comb 2004 1682 ; filter at 1000/1200 Hz. Note that the averaging constant is 1/8 the 2005 1682 ; averaging interval, which is a somewhat arbitrary choice. 2006 1682 ; 2007 1682 D1 00 02 7C LRLK AR1,DELMF ; AR1->z^-0 2008 1684 20 02 LAC F400 ; initialize sum and product registers 2009 1685 60 80 SACL * 2010 1686 7E 28 ADRK FIRLEN-1 ; AR1->z^n 2011 1687 A0 00 MPYK 0 2012 1688 CA 00 ZAC 2013 1689 99 50 BIT STATUS,WWVH ; is this Hawaii 2014 168A F5 80 16 91 BNZ INP21 ; branch if yes 2015 168C CB 28 RPTK FIRLEN-1 ; no. WWV multiply and accumulate (q15) 2016 168D 5C 90 1C 03 MACD MF1000,*- 2017 168F FF 80 16 94 B INP22 2018 1691 2019 1691 CB 28 INP21 RPTK FIRLEN-1 ; WWVH multiply and accumulate (q15) 2020 1692 5C 90 1C 2C MACD MF1200,*- 2021 1694 CE 15 INP22 APAC ; include last product 2022 1695 31 10 LAR AR1,SYNPTR ; get comb filter pointer 2023 1696 44 80 SUBH * 2024 1697 4B 1C RPT AVGINT ; right shift for time constant 2025 1698 CE 19 SFR 2026 1699 48 80 ADDH * ; update comb filter 2027 169A 68 A0 SACH *+ 2028 169B 68 04 SACH SYNC 2029 169C 20 04 LAC SYNC ; is this max signal 2030 169D 10 11 SUB MAX 2031 169E F2 80 16 A4 BLEZ INP25 ; branch if no 2032 16A0 00 11 ADD MAX ; yes. save max 2033 16A1 60 11 SACL MAX 2034 16A2 20 20 LAC EPOCH ; save tentative epoch phase 2035 16A3 60 12 SACL TEPOCH 2036 16A4 40 21 INP25 ZALH FUDGE ; adjust for sample clock offset (51 Hz) 2037 16A5 D0 05 01 A4 ORK INCR2 2038 16A7 49 22 ADDS FUDGE+1 2039 16A8 68 21 SACH FUDGE 2040 16A9 60 22 SACL FUDGE+1 2041 16AA D0 00 2C 4A LRLK AR0,COMB+COMSIZ ; is this end of epoch 2042 16AC CE 50 CMPR 2043 16AD F8 80 16 BB BBZ INP23 ; branch if no 2044 16AF FE 80 11 6F CALL ENDPOC ; yes. process epoch data 2045 16B1 40 21 ZALH FUDGE ; adjust frequency 2046 16B2 49 22 ADDS FUDGE+1 2047 16B3 48 23 ADDH INCRX 2048 16B4 49 24 ADDS INCRX+1 2049 16B5 68 21 SACH FUDGE 2050 16B6 60 22 SACL FUDGE+1 2051 16B7 CA 00 ZAC ; reset for next second 2052 16B8 60 11 SACL MAX 2053 16B9 D1 00 0D 0A LRLK AR1,COMB 2054 16BB 71 10 INP23 SAR AR1,SYNPTR 2055 16BC CE 26 RET 2056 16BD 2057 16BD ; 2058 16BD ; RF output processing 2059 16BD ; 2060 16BD ; Note: This is the only place where AR7 is incremented. Immediately 2061 16BD ; after increment, AR7 is checked for overflow and wrapped. 2062 16BD ; 2063 16BD 31 55 RFOUT LAR AR1,AIOPTR ; fetch source signal in q15 format 2064 16BE 20 80 LAC * 2065 16BF D0 04 FF FC ANDK 0FFFCh 2066 16C1 55 8F LARP AR7 ; AR7 is AIO buffer pointer 2067 16C2 60 A0 SACL *+ ; store output sample in q15 format 2068 16C3 D0 00 05 32 LRLK AR0,INTBUF+BUFSIZ ; is pointer at buffer end 2069 16C5 CE 50 CMPR 2070 16C6 F8 80 16 CA BBZ OUT13 ; branch if no 2071 16C8 D7 00 05 00 LRLK AR7,INTBUF ; yes. reset pointer 2072 16CA 55 89 OUT13 LARP AR1 2073 16CB CE 26 RET 2074 16CC 2075 16CC ; 2076 16CC ; This routine returns 10 * log10(AC). It first normalizes the argument 2077 16CC ; and counts the shifts, adding 3 dB for each one. Then, it appends the 2078 16CC ; low order four bits from a table. Worst-case accuracy is within 0.3 2079 16CC ; dB. 2080 16CC ; 2081 16CC F6 80 16 E1 LOG10 BZ LOG11 ; no nonsense here 2082 16CE 60 70 SACL TMP ; save argument 2083 16CF 40 70 ZALH TMP ; normalize 2084 16D0 C1 0E LARK AR1,14 2085 16D1 CB 0E RPTK 15-1 2086 16D2 CE 92 NORM *- 2087 16D3 71 71 SAR AR1,TMP2 ; save shift count 2088 16D4 68 70 SACH TMP 2089 16D5 20 70 LAC TMP 2090 16D6 CB 09 RPTK 10-1 ; fetch dB value 2091 16D7 CE 19 SFR 2092 16D8 D0 04 00 0F ANDK 0Fh 2093 16DA D0 02 1B 31 ADLK LOGTAB 2094 16DC 58 70 TBLR TMP 2095 16DD 20 70 LAC TMP 2096 16DE 3C 71 LT TMP2 ; 3 dB for each shift 2097 16DF A0 0F MPYK 30/2 2098 16E0 CE 15 APAC 2099 16E1 CE 26 LOG11 RET 2100 16E2 2101 16E2 ; 2102 16E2 ; This routine decodes keyboard input and interprets simple commands. It 2103 16E2 ; consists of a crude, table-driven command decoder and routines to 2104 16E2 ; select various system parameters, such as station select, baud rate, 2105 16E2 ; timecode format, debug mode, etc. It operates in polling mode by 2106 16E2 ; sampling the UART receive-done bit. 2107 16E2 ; 2108 16E2 CE 01 GETCH DINT ; bolt the windows 2109 16E3 C8 00 LDPK B_PAGE 2110 16E4 D0 01 05 00 LALK UART_SEL_LSR ; select line status register 2111 16E6 60 62 SACL UARTI 2112 16E7 E3 62 OUT UARTI,UART_CTRL 2113 16E8 85 62 IN UARTI,UART_READ 2114 16E9 D0 01 00 01 LALK UART_LSR_RBF ; is input buffer full 2115 16EB 4E 62 AND UARTI 2116 16EC F5 80 16 F1 BNZ GET14 ; branch if yes 2117 16EE C8 08 LDPK U_PAGE ; no. allow fresh air 2118 16EF CE 00 EINT 2119 16F0 CE 26 RET 2120 16F1 ; 2121 16F1 D0 01 00 00 GET14 LALK UART_SEL_RX ; select input buffer 2122 16F3 60 62 SACL UARTI 2123 16F4 E3 62 OUT UARTI,UART_CTRL 2124 16F5 85 62 IN UARTI,UART_READ ; input character 2125 16F6 20 62 LAC UARTI 2126 16F7 C8 08 LDPK U_PAGE 2127 16F8 CE 00 EINT ; allow fresh air 2128 16F9 D0 04 00 7F ANDK 07Fh ; unparity it 2129 16FB 60 61 SACL UTMP2 2130 16FC CD 60 SUBK 060h ; uncase it 2131 16FD F3 80 17 00 BLZ GET15 2132 16FF CD 20 SUBK 020h 2133 1700 CC 60 GET15 ADDK 060h 2134 1701 60 60 SACL UTMP1 2135 1702 20 65 GET13 LAC UCMD ; initialize table pointer 2136 1703 60 63 SACL UPTR 2137 1704 20 63 GET10 LAC UPTR ; get next routine address 2138 1705 58 64 TBLR UADR 2139 1706 CC 01 ADDK 1 ; get argument 2140 1707 58 61 TBLR UTMP2 2141 1708 CC 01 ADDK 1 ; get next command character 2142 1709 58 62 TBLR UCHAR 2143 170A CC 01 ADDK 1 2144 170B 60 63 SACL UPTR 2145 170C 20 62 LAC UCHAR ; is this last entry 2146 170D F6 80 17 12 BZ GET11 ; branch if yes 2147 170F 10 60 SUB UTMP1 ; no. does character match 2148 1710 F5 80 17 04 BNZ GET10 ; branch if no 2149 1712 20 64 GET11 LAC UADR ; yes. call routine 2150 1713 CE 24 CALA 2151 1714 CE 26 GET12 RET 2152 1715 ; 2153 1715 ; Housekeeping staff 2154 1715 ; 2155 1715 20 65 GETPSH LAC UCMD ; save command table pointer 2156 1716 60 66 SACL UMOD 2157 1717 20 61 LAC UTMP2 2158 1718 60 65 SACL UCMD 2159 1719 CE 26 RET 2160 171A ; 2161 171A 20 66 GETPOP LAC UMOD ; restore command table pointer 2162 171B 60 65 SACL UCMD 2163 171C FF 80 17 02 B GET13 ; continue in command decode 2164 171E ; 2165 171E ; Following are command execution segments. 2166 171E ; 2167 171E ; Select WWV and propagation delay c{0-9...} 2168 171E ; Select WWVH and propagation delay h{0-9...} 2169 171E ; 2170 171E 20 69 CMD22 LAC ACCUM ; multiply previous digits by ten 2171 171F CE 18 SFL 2172 1720 60 70 SACL TMP 2173 1721 CE 18 SFL 2174 1722 CE 18 SFL 2175 1723 00 70 ADD TMP 2176 1724 00 61 ADD UTMP2 ; add present digit 2177 1725 60 69 SACL ACCUM 2178 1726 CE 26 RET 2179 1727 ; 2180 1727 D0 01 FF BF CMD23 LALK ~(1<