;*************************************************************************** ; MODEMLIB.INC ; ; Donahe, Brendan D. Parks, Jerome C. ; ; Final Project ; EE490 Section 4 ; Copyright (C) December 4, 1996 ;*************************************************************************** ; produce_sample: Sample sine wave in memory y:$0100 at a frequency ; specified in the dat file as: FREQ ; ; Inputs: x:int_delta - integer delta pointing in sine table ; r4 - ptr to beginning of sine table ; n4 - current integer ptr into sine table ; ; Alters: n4 - (need not be maintained) ; b - (need not be maintained) ; y0 - (need not be maintained) ; y1 - (output) ; ; Outputs: y1 - sampled sine value ; produce_sample: move y:(r4+n4),y1 ; copy sine value -> y1 move x:int_delta,b ; restore delta -> b move n4,y0 add y0,b ; add offset plus delta for next time move #>MASK,y0 and y0,b ; see if outside 256 range move b,n4 ; set up offset for next time through rts ; return from produce_sample ; transmit_sample Determine which channel to output signal depending on ; if ORIGINATE or ANSWER mode, and set up control words ; ; Inputs: y1 - signal to be tranmitted ; x:mode - mode flag, ORIGINATE or ANSWER ; ; Alters: y0 - (need not be maintained) ; x:TX_BUFF_BASE - (must be maintained) ; x:TX_BUFF_BASE+1- (must be maintained) ; ; Outputs: none ; transmit_sample jset #0,x:mode,answer_mode_tx ; transmits on correct channel move y1,x:TX_BUFF_BASE ; transmit left jmp control_words answer_mode_tx move y1,x:TX_BUFF_BASE+1 ; transmit right control_words move #TONE_OUTPUT,y0 ; set up control words move y0,x:TX_BUFF_BASE+2 move #TONE_INPUT,y0 move y0,x:TX_BUFF_BASE+3 rts ; return from transmit_sample ; receive_sample Wait for frame sync and determine which channel to ; receive signal depending on if ORIGINATE or ANSWER ; mode ; ; Inputs: x:RX_BUFF_BASE - left channel ; x:RX_BUFF_BASE+1- right channel ; r5 - ptr to recv_queue ; ; Alters: r5 - (must be maintained) ; y0 - (need not be maintained) ; x:RX_BUFF_BASE - (must be maintained) ; x:RX_BUFF_BASE+1- (must be maintained) ; ; Outputs: y:recv_queue - holds input sample ; y1 - ALSO holds input sample ; receive_sample jset #2,x:SSISR,* ; wait for frame sync to pass jclr #2,x:SSISR,* ; wait for frame sync jset #0,x:mode,answer_mode_rx ; receive on correct channel move x:RX_BUFF_BASE+1,y1 ; receive right: TWO BOARDS ; move x:RX_BUFF_BASE,y1 ; receive left: SINGLE BOARD, ORIGINATE jmp originate_mode answer_mode_rx move x:RX_BUFF_BASE,y1 ; receive left originate_mode move y1,y:(r5)+ ; store current sample into recv_queue rts ; return from receive_sample ;************************* MODE 1: negotiation_tx **************************** ; check_pwr Verify if a signal is received from the ANSWER ; modem. It will verify power against some threshold. ; ; Inputs: r5 - pointer to recv_queue ; ; Alters: r5 - (must exit unchanged) ; x:txrx_mode - (must be maintained) ; x0 - (need not be maintained) ; y0 - (need not be maintained) ; a - (need not be maintained) ; ; Outputs: x:txrx_mode ; check_pwr clr a y:(r5)+,x0 ; get oldest input sample move #>RECV_BUFSIZ,y0 ; get number of times to loop rep y0 mac x0,x0,a y:(r5)+,x0 ; calculate L2NORM move #PWR_THRESH,x0 ; move PWR_THRESH -> x0 to verify ; power against cmp x0,a (r5)- ; r5-- so it leaves where it started jlt no_mode_change_1 ; if PWR_THRESH > PWR, no mode change move x:txrx_mode,a0 ; o.w. change modes to negotiation_rx asl a move a0,x:txrx_mode no_mode_change_1 rts ; return from check_pwr ;************************* MODE 2: negotiation_rx **************************** ; negotiate_filter Takes in newest input sample and copies it to filter ; coefficient bank. Also chages modes after RECV_BUFSIZ ; times. ; ; Inputs: r5 - pointer to recv_queue ; n5 - offset of newest sample in r5 ; r1 - pointer to recv_filter ; ; Alters: r1 - (must be maintained) ; x:txrx_mode - (must be maintained) ; x:negotiation_count - (must be maintained) ; a - (need not be maintained) ; y1 - (need not be maintained) ; ; Outputs: x:txrx_mode ; negotiate_filter clr a move x:negotiation_count,a0 ; restore negotiation counter dec a jne no_mode_change_2 ; when negotiation_count expires, move x:txrx_mode,a0 ; change modes to txrx asl a (r1)+ ; need to increase r1 by 2 move x:(r1)+,y1 ; this is the second r1++ move a0,x:txrx_mode move #>RECV_BUFSIZ+1,y1 move y1,x:negotiation_count jmp end_negotiate_filter no_mode_change_2 move a0,x:negotiation_count ; store negotiation counter move y:(r5+n5),y1 ; and get newest input sample move y1,a asl a ; double before saving as filter coef. move a,x:(r1)+ ; store as filter coefficient end_negotiate_filter rts ; return from negotiate_filter ;***************************** MODE 3: txrx ********************************** ; filter_bits Multiplies corresponding input with filter coef, ; and sums them all RECV_BUFSIZ times, then returns ; the signed magnitude of the power output. ; ; Inputs: r5 - pointer to recv_queue ; r1 - pointer to recv_filter ; ; Alters: r1 - (must be maintained) ; r5 - (must be maintained) ; a - (need not be maintained) ; x0 - (need not be maintained) ; y1 - (need not be maintained) ; y:temp_dibit - must be 0 on enterance ; ; Outputs: a - holds signed magnitude correlation ; filter_bits clr a do #RECV_BUFSIZ,end_pwr_calc move x:(r1)+,x0 y:(r5)+,y1 ; multiply filter coefs with mac x0,y1,a ; sampled values and add end_pwr_calc asr a ; scale signed power magnitude by 1/4 asr a (r1)+ ; r1++ rts ; return from filter_bits ; decode_decision Take in a signed power magnitude and determine what ; the corresponding dibit to return should be ; ; Inputs: a - holds signed power magnitude ; r2 - pointer to recv_correlation ; ; Alters: r2 - (must be maintained) ; a - (need not be maintained) ; b - (need not be maintained) ; x0 - (need not be maintained) ; y1 - (need not be maintained) ; y:prev_dibit - (must be maintained) ; ; Outputs: y:prev_dibit - holds dibit that has been received ; y1 - ALSO holds received dibit ; decode_decision move a,x:temp_correlation_pwr ; allows for keeping track of ; the input values to verify what ; the threshold should be move #0,y1 cmp y1,a ; compare to see if + or - jgt positive_phase move #>1,y1 ; if -, phase bit=1 jmp check_amplitude positive_phase move #0,y1 ; else, phase bit=0 check_amplitude move a,x0 ; copy magnitude of power, a -> x0 mpy x0,x0,a ; square magnitude move #>MAG_THRESH,x0 ; compare squared magnitude aginst cmp x0,a ; MAG_THRESH jlt half_magnitude ; if threshold < correlation, mag=1 clr a jmp end_decode half_magnitude clr a move #>16,a1 ; makes $10 end_decode or y1,a ; forces nibble separated boundaries move a,x:(r2)+ ; store output decision -> r2 move x:(r2)+,x0 rep #RECV_BUFSIZ-1 ; a will hold the summed value of the add x0,a x:(r2)+,x0 ; previous 4 outputs ; for 00, a looks like $000000 ; for 01, a looks like $000004 ; for 10, a looks like $000040 ; for 11, a looks like $000044 ; for anything else, use prev_dibit move a,b ; store a copy in b move #>$0f,x0 and x0,a ; mask off everything but lsn jeq correct_lsn ; if 0 good, jump to next test move #>1,x0 ; if not 0 in lsn, then maybe it's move x0,y:temp_dibit ; 4... store 1 in lsb of temp_dibit move #>$04,x0 ; check to see if 4 is in lsn cmp x0,a jne failed_test ; if not 4, use prev_dibit correct_lsn move #>$f0,x0 and x0,b ; mask off everything but 2nd lsn jeq correct_msn ; jump if 0, else test for 4 move #>2,y1 ; if not 0 in msn, then maybe 4 move #>$40,x0 cmp x0,b jne failed_test ; if not 4, then use prev_dibit move y:temp_dibit,a ; restore decision of lsn or y1,a ; or lsn with 2nd lsn and store out move a,y:temp_dibit ; in temp_dibit correct_msn move y:temp_dibit,y1 ; use temp_dibit for decision move y1,y:prev_dibit ; and save in y1 and prev_dibit jmp end_decode_decision failed_test move y:prev_dibit,y1 ; else use prev_dibit for decision end_decode_decision move #0,x0 ; 0 out temp_dibit on exit move x0,y:temp_dibit rts ; return from decode_decision ; resync_filter If 00 dibit, recalculate filter coefficients ; ; Inputs: y:dibit_counter - which dibit currently transmitting ; y:filter_dibit_count - temp counter for dibit_counter ; r1 - pointer to x:recv_filter ; r5 - pointer to y:recv_queue ; ; Alters: b - (need not be maintained) ; x0 - (must be maintained) ; ; Outputs: x:recv_filter - holds new filter coefficients ; resync_filter clr b cmp y1,b ; see if decoded dibit is a 0 jne no_filter_sync ; if yes, then re-sync boards move y:filter_dibit_count,x0 ; check to see if at same dibit move y:dibit_counter,b ; position... if so, the sync cmp x0,b ; has already been performed jeq no_filter_sync ; so exit move b,y:filter_dibit_count ; otherwise, save out that sync is done clr b move #>RECV_BUFSIZ,x0 ; repeat RECV_BUFSIZ times the ; refilling of the filters do x0,end_resync move y:(r5)+,b ; copy out previous 4 samples asl b ; double value move b,x:(r1)+ ; store as new coefs end_resync move x:(r1)+,x0 ; update r1 properly no_filter_sync ; end the sync phase rts ; return from resync_filter ; frame_decoder Decode the frame and store the data followed by ; parity and stop bits in memory ; ; Inputs: y:dibit_counter - which dibit currently transmitting ; y:interval_count -how long to transmit data bits ; y:startbit_count -how long to transmit start dibit ; y:prev_dibit - previous dibit transmitted ; r7 - pointer to y:frame_out ; ; Alters: a - (need not be maintained) ; b - (need not be maintained) ; x1 - (must be maintained) ; y0 - (must be maintained) ; y1 - (must be maintained) ; r7 - (must be maintained) ; ; Outputs: y:frame_out - data and parity/stop circular queue ; frame_decoder clr a move y:dibit_counter,y0 cmp y0,a ; if dibit_counter == 0, we're waiting jne not_start_bits ; for start bits move #>3,y0 ; transmit a 11b for start dibit move y:prev_dibit,a cmp y0,a ; if prev_dibit = 3, we have a start jne exit_frame_decoder ; bit clr a move y:startbit_count,a0 dec a ; need to wait so many samples before jne store_startbit_count ; storing value in memory move #>MAX_DIBIT_COUNTER,y0 move y0,y:dibit_counter ; reset dibit_counter move #>INTERVAL,y0 move y0,y:interval_count ; reset interval_count move #0,y0 move y0,y:(r7) ; zero out y:(r7) move #>MAX_STARTBIT_COUNT,a0 ; reset startbit_count jmp store_startbit_count not_start_bits clr a move y:interval_count,a0 dec a ; if interval_count = 0, store out data jne store_interval_count ; in memory move y:dibit_counter,a0 dec a ; if dibit_counter != 0, store out data jeq store_parity_stop ; o.w. it's in parity mode move a0,y:dibit_counter clr a move y:(r7),a ; move data -> a asl a ; shift data left 2 positions asl a y:prev_dibit,y0 or y0,a ; add in next dibit of data move a,y:(r7) ; store data back out jmp reset_interval_count store_parity_stop move a0,y:dibit_counter move y:(r7)+,y0 ; r7++ move y:prev_dibit,y0 ; load prev_dibit move y0,y:(r7)+ ; store parity/stop bits, r7++ reset_interval_count move #>INTERVAL,a0 store_interval_count move a0,y:interval_count jmp exit_frame_decoder store_startbit_count move a0,y:startbit_count exit_frame_decoder rts ; return from frame_decoder ; frame_encoder Determine if a new frame needs to be built and output ; the correct dibit ; ; Inputs: y:frame_mode - tells what should be built: ; 001 -> start bits ; 010 -> data bits ; 100 -> parity/stop bits ; - y:frame_counter ; - y:parity ; - y:data_dibit ; - y:data_byte ; ; Alters: a - (need not be maintained) ; b - (need not be maintained) ; x1 - (must be maintained) ; y0 - (must be maintained) ; y1 - (must be maintained) ; ; Outputs: x0 - holds binary output signal ; frame_encoder jset #0,y:frame_mode,start_bits_mode ; determine current mode jset #1,y:frame_mode,data_bits_mode jset #2,y:frame_mode,parity_stop_mode frame_error jmp frame_error ; circular loop if error start_bits_mode ; START BIT MODE clr a #>3,x0 ; transmit 11b for start bits move y:frame_counter,a0 dec a jne same_start_bit move #>DATA_BITS,y0 ; Change modes to data byte mode move y0,y:frame_mode move #>INTERVAL,a0 move x:(r0)+,y0 ; Load the next byte of data to be move y0,y:data_byte ; transmitted same_start_bit move a0,y:frame_counter jmp end_frame_encoder data_bits_mode ; DATA BIT MODE clr a y:frame_counter,y0 move #>INTERVAL,a cmp y0,a jne same_data_bit clr a jclr #7,y:data_byte,skip_parity_1 ; check if current bit is clear move y:parity,b0 ; if no, increment parity bit inc b move b0,y:parity move #>2,a ; and fill ms bit of 2 bit value skip_parity_1 jclr #6,y:data_byte,skip_parity_2 ; check if next bit is clear move y:parity,b0 ; if no, increment parity bit inc b move b0,y:parity move #>1,y0 add y0,a skip_parity_2 move y:data_byte,b0 ; force the current byte left two asl b ; positions to set the next dibit in asl b ; bits 7 and 6 position move b0,y:data_byte move a,y:data_dibit ; store out next dibit same_data_bit clr a move y:frame_counter,a0 dec a ; check frame counter jne store_frame_count ; if 0, check which dibit clr b move y:data_count,b0 dec b ; decrement dibit counter jne store_data_count move #>PARITY_STOP,b0 ; change modes to Stop and Parity mode move b0,y:frame_mode store_data_count move b0,y:data_count ; store out dibit counter move #>INTERVAL,a0 store_frame_count move a0,y:frame_counter ; store out frame counter move y:data_dibit,x0 ; x0 holds data_dibit on exit jmp end_frame_encoder parity_stop_mode ; PARITY and STOP BIT MODE jset #0,y:parity,set_parity ; if the parity bit is NOT set, move #0,x0 ; transmit 00 - 0 parity, 0 stop jmp end_parity set_parity ; othwerwise transmit 10 - 1 parity move #>2,x0 ; 0 stop end_parity clr a move y:frame_counter,a0 dec a ; see if still transmitting stop/parity jne store_parity_count ; if yes, then jump move #>START_BITS,a0 ; otherwise reset mode to START BIT move a0,y:frame_mode ; and reset the counter for the next move #0,a0 move a0,y:parity ; clear parity bit move #>INTERVAL,a0 ; dibit to be transmitted store_parity_count move a0,y:frame_counter end_frame_encoder rts ; return from frame_encoder ; encode_dibit Takes in dibit and makes it ready for transmission ; ; Inputs: x0 - holds binary dibit to be transmitted ; ; Alters: a - (need not be maintained) ; b - (need not be maintained) ; x1 - (need not be maintained) ; y0 - (need not be maintained) ; y1 - (must be maintained) ; ; Outputs: y1 - holds output signal to be transmitted ; encode_dibit jsr produce_sample ; x0 enters and exits with dibit ; y1 exits with output sample clr b move x0,b ; copy dibit into b move #>1,x1 and x1,b ; mask off amplitude (leave phase) jeq skip_phase ; if equal, no change clr b move y1,b ; create a 180 degree phase shift neg b ; by negating the ouput move b,y1 skip_phase clr a clr b move #>1,b ; if the dibit is > 1, then magnitude cmp x0,b ; must be scaled jge no_scale_amplitude ; o.w. 0, and no scaling necessary move y1,a asr a ; scale amplitude by 1/2 move a,y1 no_scale_amplitude rts ; return from encode_dibit ; output_hostport Handshakes with host computer and transmit data to ; to host computer ; ; Inputs: r7 - pointer to frame_out ; ; Alters: a - (need not be maintained) ; x0 - (need not be maintained) ; r7 - (must be maintained) ; ; Outputs: x:PBD - contains control signals and data ; for hostport ; output_hostport move #>frame_out,x0 ; copy beginning of data output -> x0 move r7,a ; move current pointer location -> a cmp x0,a ; are they equal? jeq no_new_recv_data ; if so, no data to output yet move x0,r7 ; o.w reset data pointer jclr #INI,x:PBD,* ; wait for INI~ to go high bclr #ACK,x:PBD ; clear ACK~ to signal sync jset #INI,x:PBD,* ; wait for INI~ to return low bset #ACK,x:PBD ; return ACK~ to quiescent move y:(r7),x0 ; copy and send data movep x0,x:PBD jclr #STR,x:PBD,* ; wait for strobe low jset #STR,x:PBD,* ; wait for strobe high psd_loop movep #$2000,x:PBD no_new_recv_data rts ; return from output_hostport