; Laser Harp Stuff - December 9, 1998 ; Andrew Kilpatrick ; ; RB0 - MIDI output ; RB1 - whole tone scale LED ; RB2 - chromatic scale LED ; RB3 - diatonic scale LED ; RB4 - blues scale LED ; RB5 - pentatonic scale LED ; RB6 - transpose up LED ; RB7 - transpose down LED ; RA0-3 - multiplexer address pins ; RA4 - multiplexer data out ; ; MULTIPLEXER INPUTS ; ; 0 - beam 0 ; 1 - beam 1 ; 2 - beam 2 ; 3 - beam 3 ; 4 - beam 4 ; 5 - beam 5 ; 6 - beam 6 ; 7 - beam 7 ; 8 - beam 8 ; 9 - beam 9 ; 10 - beam 10 ; 11 - beam 11 ; 12 - scale change switch ; 13 - transpose up ; 14 - transpose down ; 15 - unused ; ; LIST p=16c84 #include ; registers and bits definitions SNOOZE_A EQU 0CH ; delay variable SNOOZE_B EQU 0DH ; delay variable WASTE EQU 0EH ; delay variable MIDI_BYTE EQU 0FH ; midi variable MIDI_BIT EQU 10H ; midi variable MIDI_COUNT EQU 11H ; midi variable NOTE EQU 12H ; the note to turn on or off NEW_A EQU 13H ; new inputs (0-7) NEW_B EQU 14H ; new inputs (8-15) OLD_A EQU 15H ; old inputs (0-7) OLD_B EQU 16H ; old inputs (8-15) LOOP_COUNT_A EQU 17H ; loop counter LOOP_COUNT_B EQU 18H ; loop counter 2 ADDRESS_COUNT EQU 19H ; address counter CHANGED_A EQU 1AH ; change between new and old reads for A CHANGED_B EQU 1BH ; change between new and old reads for B TEMP_SHIFTER EQU 1CH ; temp byte for manipulating bits SCALE_OFFSET EQU 1DH ; offset to add to get the scale we want SCALE_LEDS EQU 1EH ; indicator status for scale LEDs TRANSPOSE EQU 1FH ; transpose status ;***************************************************************** ; Chip Configuration ;***************************************************************** _CP_ON EQU 0x3FEF ; PIC16C84 configuration macros _CP_OFF EQU 0x3FFF _PWRTE_ON EQU 0x3FFF _PWRTE_OFF EQU 0x3FF7 _WDT_ON EQU 0x3FFF _WDT_OFF EQU 0x3FFB ; PIC16C84 CONFIGURATION WORD: _LP_OSC EQU 0x3FFC ; OSC selection: XT _XT_OSC EQU 0x3FFD ; WDT: disabled _HS_OSC EQU 0x3FFE ; Power-up timer: enabled _RC_OSC EQU 0x3FFF ; Code protection: OFF __CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF ;***************************************************************** ; EEPROM Data Allocation - scale lookup tables ;***************************************************************** ORG 0x2100 ; move to EEPROM block and write level lookup table DE .60, .62, .64, .66, .68, .70, .72, .74, .76, .78, .80, .82 ; whole tone DE .60, .61, .62, .63, .64, .65, .66, .67, .68, .69, .70, .71 ; chromatic DE .55, .57, .59, .60, .62, .64, .66, .67, .69, .71, .72, .74 ; diatonic DE .58, .60, .63, .65, .66, .67, .70, .72, .75, .77, .78, .79 ; blues DE .57, .60, .62, .64, .67, .69, .72, .74, .76, .79, .81, .84 ; pentatonic ;***************************************************************** ; Start of Main program stuff ;***************************************************************** ; reset the PC ORG 000H ; start the program at 000H ; set the status bits BCF STATUS, IRP ; clear the IRP bit (not used on PIC16C84) BCF STATUS, RP1 ; clear RP1 (not used on PIC16C84) BSF STATUS, RP0 ; change to bank 1 CLRF TRISB ; make PORTB outputs CLRF TRISA ; make PORTA outputs BSF TRISA, 4 ; except bit 4 BCF STATUS, RP0 ; go back to bank 0 MOVLW 0 ; set default scale offset MOVWF SCALE_OFFSET ; into the scale offset byte MOVLW 1 ; set the default scale indicator MOVWF SCALE_LEDS ; into the scale indicator byte MOVLW .16 ; set the default transposition MOVWF TRANSPOSE ; into the transpose byte ; 4=0, 3=-12, 2=-24, 1=-36, 0=-48 ; 5=+12, 6=+24, 7=+36 (these are bits) CLRF PORTB BSF PORTB, 0 BSF PORTB, 1 CALL LONG_WAIT ; delay a bit CALL MIDI_TEST ; send the midi test CALL POLL_INPUT ; poll the 16 input lines CALL MAKE_OLD ; copy the new values to the old values TOP CALL POLL_INPUT ; poll the 16 input lines CALL COMPARE_BITS ; compares new to old input CALL MAKE_OLD ; copy the new values to the old values GOTO TOP ;***************************************************************** ; Beam Lo Decode - decode the first 8 beams ;***************************************************************** BEAM_LO_DECODE MOVLW 90H ; note on, channel 1 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send status byte ; eeprom lookup of note MOVF ADDRESS_COUNT, W ; choose which channel to look up ADDWF SCALE_OFFSET, W ; add the scale offset MOVWF EEADR ; put it in the EEADR register BSF STATUS, RP0 ; switch to BANK 1 BSF EECON1, RD ; set the RD bit BCF STATUS, RP0 ; switch to BANK 0 MOVF EEDATA, 0 ; get the data to the W register MOVWF MIDI_BYTE ; put it in NOTE MOVLW .48 BTFSC TRANSPOSE, 0 ; subtract 48 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .36 BTFSC TRANSPOSE, 1 ; subtract 36 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .24 BTFSC TRANSPOSE, 2 ; subtract 24 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .12 BTFSC TRANSPOSE, 3 ; subtract 12 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .12 BTFSC TRANSPOSE, 5 ; add 12 if we're in that octave ADDWF MIDI_BYTE, F MOVLW .24 BTFSC TRANSPOSE, 6 ; add 24 if we're in that octave ADDWF MIDI_BYTE, F MOVLW .36 BTFSC TRANSPOSE, 7 ; add 36 if we're in that octave ADDWF MIDI_BYTE, F CALL MIDI_OUT_BYTE ; send the note MOVF ADDRESS_COUNT, W ; get the bit number MOVWF LOOP_COUNT_B ; put it in the loop counter INCF LOOP_COUNT_B, F ; increment the loop counter MOVF NEW_A, W ; get the current data MOVWF TEMP_SHIFTER ; put it in the temp shifter GET_BIT RRF TEMP_SHIFTER, F ; rotate TEMP_SHIFTER into STATUS, C DECFSZ LOOP_COUNT_B, F ; keep loop until we have the bit GOTO GET_BIT ; keep looping BTFSS STATUS, C ; note on MOVLW .100 ; set the velocity to 100 BTFSC STATUS, C ; note off MOVLW .0 ; set the velocity to 0 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send the velocity RETURN ;***************************************************************** ; Beam Hi Decode - does an on or off for beams 9-12 ;***************************************************************** BEAM_HI_DECODE MOVLW 90H ; note on, channel 1 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send status byte ; eeprom lookup of note MOVF ADDRESS_COUNT, W ; choose which channel to look up ADDWF SCALE_OFFSET, W ; add the scale offset ADDLW .8 ; move up to the top 4 notes MOVWF EEADR ; put it in the EEADR register BSF STATUS, RP0 ; switch to BANK 1 BSF EECON1, RD ; set the RD bit BCF STATUS, RP0 ; switch to BANK 0 MOVF EEDATA, 0 ; get the data to the W register MOVWF MIDI_BYTE ; put it in NOTE MOVLW .48 BTFSC TRANSPOSE, 0 ; subtract 48 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .36 BTFSC TRANSPOSE, 1 ; subtract 36 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .24 BTFSC TRANSPOSE, 2 ; subtract 24 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .12 BTFSC TRANSPOSE, 3 ; subtract 12 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .12 BTFSC TRANSPOSE, 5 ; add 12 if we're in that octave ADDWF MIDI_BYTE, F MOVLW .24 BTFSC TRANSPOSE, 6 ; add 24 if we're in that octave ADDWF MIDI_BYTE, F MOVLW .36 BTFSC TRANSPOSE, 7 ; add 36 if we're in that octave ADDWF MIDI_BYTE, F CALL MIDI_OUT_BYTE ; send the note MOVF ADDRESS_COUNT, W ; get the bit number MOVWF LOOP_COUNT_B ; put it in the loop counter INCF LOOP_COUNT_B, F ; increment the loop counter MOVF NEW_B, W ; get the current data MOVWF TEMP_SHIFTER ; put it in the temp shifter GET_BIT_HI RRF TEMP_SHIFTER, F ; rotate TEMP_SHIFTER into STATUS, C DECFSZ LOOP_COUNT_B, F ; keep loop until we have the bit GOTO GET_BIT_HI ; keep looping BTFSS STATUS, C ; note on MOVLW .100 ; set the velocity to 100 BTFSC STATUS, C ; note off MOVLW .0 ; set the velocity to 0 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send the velocity RETURN ;***************************************************************** ; Scale Change - if the scale change switch is pressed ;***************************************************************** SCALE_CHANGE BCF STATUS, C BTFSC NEW_B, 4 ; return if it's not pressed RETURN ; exit prematurely CALL MIDI_CLEAR_NOTES ; turn off all notes in current scale MOVF SCALE_OFFSET, W ; get the current scale offset ADDLW .12 ; add 12 MOVWF SCALE_OFFSET ; put the result back in SCALE OFFSET ADDLW .12 ; add 12 more to W MOVWF TEMP_SHIFTER ; put it in a temp byte BTFSC TEMP_SHIFTER, 6 ; test to see if we're over 64 now MOVLW 0 ; put 0 in W BTFSC TEMP_SHIFTER, 6 ; test to see if we're over 64 now MOVWF SCALE_OFFSET ; cause rollover to 0 again RLF SCALE_LEDS, F ; rotate the scale LEDS left BCF SCALE_LEDS, 0 ; turn off the 0th one BTFSC TEMP_SHIFTER, 6 ; if we're rolling over... turn on the 0th LED BSF SCALE_LEDS, 0 ; turn on LED 0 ; copy data to leds BCF PORTB, 1 ; clear the LEDS BCF PORTB, 2 ; clear the LEDS BCF PORTB, 3 ; clear the LEDS BCF PORTB, 4 ; clear the LEDS BCF PORTB, 5 ; clear the LEDS BTFSC SCALE_LEDS, 0 ; turn on led 0? BSF PORTB, 1 ; okay! BTFSC SCALE_LEDS, 1 ; turn on led 1? BSF PORTB, 2 ; okay! BTFSC SCALE_LEDS, 2 ; turn on led 2? BSF PORTB, 3 ; okay! BTFSC SCALE_LEDS, 3 ; turn on led 3? BSF PORTB, 4 ; okay! BTFSC SCALE_LEDS, 4 ; turn on led 4? BSF PORTB, 5 ; okay! RETURN ;***************************************************************** ; Transpose Up - if transpose up is pressed ;***************************************************************** TRANSPOSE_UP BCF STATUS, C BTFSC NEW_B, 5 ; leave if up isn't pressed RETURN CALL MIDI_CLEAR_NOTES ; turn off all notes in current scale BTFSS TRANSPOSE, 7 ; don't shift if we're already at 7 RLF TRANSPOSE, F ; rotate to higher octave ; clear transpose LEDs BCF PORTB, 6 ; clear the up led BCF PORTB, 7 ; clear the down led BTFSC TRANSPOSE, 5 ; turn on up led BSF PORTB, 6 BTFSC TRANSPOSE, 6 ; turn on up led BSF PORTB, 6 BTFSC TRANSPOSE, 7 ; turn on up led BSF PORTB, 6 BTFSC TRANSPOSE, 3 ; turn on down led BSF PORTB, 7 BTFSC TRANSPOSE, 2 ; turn on down led BSF PORTB, 7 BTFSC TRANSPOSE, 1 ; turn on down led BSF PORTB, 7 BTFSC TRANSPOSE, 0 ; turn on down led BSF PORTB, 7 RETURN ;***************************************************************** ; Transpose Down - if transpose down is pressed ;***************************************************************** TRANSPOSE_DOWN BTFSC NEW_B, 6 ; leave if up isn't pressed RETURN CALL MIDI_CLEAR_NOTES ; turn off all notes in current scale BTFSS TRANSPOSE, 0 ; don't shift if we're already at 0 RRF TRANSPOSE, F ; rotate to lower octave ; clear transpose LEDs BCF PORTB, 6 ; clear the up led BCF PORTB, 7 ; clear the down led BTFSC TRANSPOSE, 5 ; turn on up led BSF PORTB, 6 BTFSC TRANSPOSE, 6 ; turn on up led BSF PORTB, 6 BTFSC TRANSPOSE, 7 ; turn on up led BSF PORTB, 6 BTFSC TRANSPOSE, 3 ; turn on down led BSF PORTB, 7 BTFSC TRANSPOSE, 2 ; turn on down led BSF PORTB, 7 BTFSC TRANSPOSE, 1 ; turn on down led BSF PORTB, 7 BTFSC TRANSPOSE, 0 ; turn on down led BSF PORTB, 7 RETURN ;***************************************************************** ; Compare Bits - compares new and old input ;***************************************************************** COMPARE_BITS ; XOR the new and old input data MOVF NEW_A, W ; copy NEW_A to the W register XORWF OLD_A, W ; XOR the 2 bytes MOVWF CHANGED_A ; put the result in CHANGED_A MOVF NEW_B, W ; copy NEW_B to the W register XORWF OLD_B, W ; XOR the 2 bytes MOVWF CHANGED_B ; put the result in CHANGED_B ; handle beam lo bits that have changed MOVLW 8 ; loop 8 times MOVWF LOOP_COUNT_A ; set the loop counter MOVLW 0 ; reset the counter MOVWF ADDRESS_COUNT ; temp counter of which output we are seeing CHANGED_BEAMS_LO ; decode the lo beams RRF CHANGED_A, F ; rotate the next bit into C BTFSC STATUS, C ; if C is set (changed) then CALL BEAM_LO_DECODE ; call the beam decoder INCF ADDRESS_COUNT, F ; increment the address counter DECFSZ LOOP_COUNT_A, F ; keep looping until done GOTO CHANGED_BEAMS_LO ; handle beam hi bits that have changed MOVLW 4 ; loop 4 times MOVWF LOOP_COUNT_A ; set the loop counter MOVLW 0 ; reset the counter MOVWF ADDRESS_COUNT ; temp counter of which output we are seeing CHANGED_BEAMS_HI ; decode the lo beams RRF CHANGED_B, F ; rotate the next bit into C BTFSC STATUS, C ; if C is set (changed) then CALL BEAM_HI_DECODE ; call the beam decoder INCF ADDRESS_COUNT, F ; increment the address counter DECFSZ LOOP_COUNT_A, F ; keep looping until done GOTO CHANGED_BEAMS_HI ; handle the switch changes BTFSC CHANGED_B, 0 ; test scale change switch (stuff has been rotated) CALL SCALE_CHANGE ; check to see if scale change is pressed BTFSC CHANGED_B, 1 ; test transpose up switch CALL TRANSPOSE_UP ; check to see if transpose up is pressed BTFSC CHANGED_B, 2 ; test transpose down switch CALL TRANSPOSE_DOWN ; check to see if transpose down is pressed RETURN ;***************************************************************** ; Poll Input - reads the 16 inputs to NEW_A and NEW_B ;***************************************************************** POLL_INPUT ; first set of 8 MOVLW 8 ; loop 8 times MOVWF LOOP_COUNT_A ; put the value there MOVLW 0 ; start with address 0 MOVWF ADDRESS_COUNT ; put the value there POLLING_LOOP ; do the first 8 bits MOVF ADDRESS_COUNT, W ; get the address to use INCF ADDRESS_COUNT, F ; increment the address counter MOVWF PORTA ; put it on the address pins of the 74C150 CALL WAIT_6 ; allow for setting time BTFSS PORTA, 4 ; if the output is clear BSF STATUS, C ; set STATUS C bit BTFSC PORTA, 4 ; if the output is set BCF STATUS, C ; clear STATUS C bit RRF NEW_A, F ; rotate NEW_A right DECFSZ LOOP_COUNT_A, F ; loop until done 8 times GOTO POLLING_LOOP ; loop until done ; second set of 8 MOVLW 8 ; loop 7 times MOVWF LOOP_COUNT_A ; put the value there MOVLW 0 ; start with address 0 MOVWF ADDRESS_COUNT ; put the value there POLLING_LOOP_2 ; do the second 8 bits MOVF ADDRESS_COUNT, W ; get the address to use INCF ADDRESS_COUNT, F ; increment the address counter MOVWF PORTA ; put it on the address pins of the 74C150 BSF PORTA, 3 ; make it the high 8 bits CALL WAIT_6 ; allow settling time BTFSS PORTA, 4 ; if the output is clear BSF STATUS, C ; set STATUS, C BTFSC PORTA, 4 ; if the output is set BCF STATUS, C ; clear STATUS, C RRF NEW_B, F ; rotate NEW_B right DECFSZ LOOP_COUNT_A, F ; loop until done 8 times GOTO POLLING_LOOP_2 ; loop until done RETURN ;***************************************************************** ; Make Old - copy the new input values to the old registers ;***************************************************************** MAKE_OLD ; make the new values old MOVF NEW_A, W ; copy NEW_A to the W register MOVWF OLD_A ; put W into OLD_A MOVF NEW_B, W ; copy NEW_B to the W register MOVWF OLD_B ; put W into OLD_B RETURN ;***************************************************************** ; Midi Clear Notes - turns off all notes in current scale ;***************************************************************** MIDI_CLEAR_NOTES MOVLW .12 ; set up a loop for 12 times MOVWF LOOP_COUNT_A ; put it in the loop counter MOVLW 0 ; start at note 0 MOVWF ADDRESS_COUNT ; put it in address count CLEAR_LOOP MOVLW 90H ; note on, channel 1 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send status byte ; eeprom lookup of note MOVF ADDRESS_COUNT, W ; choose which channel to look up ADDWF SCALE_OFFSET, W ; add the scale offset MOVWF EEADR ; put it in the EEADR register BSF STATUS, RP0 ; switch to BANK 1 BSF EECON1, RD ; set the RD bit BCF STATUS, RP0 ; switch to BANK 0 MOVF EEDATA, 0 ; get the data to the W register MOVWF MIDI_BYTE ; put it in NOTE MOVLW .48 BTFSC TRANSPOSE, 0 ; subtract 48 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .36 BTFSC TRANSPOSE, 1 ; subtract 36 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .24 BTFSC TRANSPOSE, 2 ; subtract 24 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .12 BTFSC TRANSPOSE, 3 ; subtract 12 if we're in that octave SUBWF MIDI_BYTE, F MOVLW .12 BTFSC TRANSPOSE, 5 ; add 12 if we're in that octave ADDWF MIDI_BYTE, F MOVLW .24 BTFSC TRANSPOSE, 6 ; add 24 if we're in that octave ADDWF MIDI_BYTE, F MOVLW .36 BTFSC TRANSPOSE, 7 ; add 36 if we're in that octave ADDWF MIDI_BYTE, F CALL MIDI_OUT_BYTE ; send the note MOVLW .0 ; set the velocity to 0 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send the velocity INCF ADDRESS_COUNT, F ; move to the next note DECFSZ LOOP_COUNT_A, F ; loop until done GOTO CLEAR_LOOP ; loop again RETURN ;***************************************************************** ; Midi Out Byte - the byte in MIDI_BYTE will be sent out ;***************************************************************** MIDI_OUT_BYTE ; outputs the value of MIDI_BYTE to midi out BCF PORTB, 0 ; send the start bit NOP NOP MOVLW .8 ; repeat the loop 8 times MOVWF MIDI_COUNT ; 5 cycles CALL WAIT_22 ; call the short delay (waste 22 cycles) ; 5 more cycles until first data write SHIFT_MIDI BTFSS MIDI_BYTE, 0 ; test the bit - skip if set BCF PORTB, 0 ; clear the temp midi bit BTFSC MIDI_BYTE, 0 ; test the bit - skip if clear BSF PORTB, 0 ; set the temp midi bit MOVF MIDI_BIT, 0 ; load the midi bit into W NOP CALL WAIT_22 ; call the short delay (waste 22 cycles) RRF MIDI_BYTE, 1 ; rotate MIDI_BYTE to reveal the next bit DECFSZ MIDI_COUNT, F ; decrement MIDI_COUNT - leave if 0 GOTO SHIFT_MIDI ; repeat the data bits some more CALL WAIT_6 ; wait 6 cycles BSF PORTB, 0 ; set the stop bit CALL WAIT_22 ; waste 22 cycles CALL WAIT_4 ; waste 4 cycles RETURN ; get out of here ;***************************************************************** ; Midi Test - sends a few notes to see if midi is working ;***************************************************************** MIDI_TEST ; plays a short midi test (C, F) ; status MOVLW 90H ; note on, channel 1 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send status byte MOVLW .50 MOVWF MIDI_BYTE ; put it in NOTE CALL MIDI_OUT_BYTE ; send the note MOVLW .100 ; set the velocity to 100 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send the velocity CALL LONG_WAIT ; delay MOVLW 90H ; note on, channel 1 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send status byte MOVLW .50 MOVWF MIDI_BYTE ; put it in NOTE CALL MIDI_OUT_BYTE ; send the note MOVLW .0 ; set the velocity to 0 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send the velocity MOVLW 90H ; note on, channel 1 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send status byte MOVLW .65 MOVWF MIDI_BYTE ; put it in NOTE CALL MIDI_OUT_BYTE ; send the note MOVLW .100 ; set the velocity to 100 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send the velocity CALL LONG_WAIT ; delay MOVLW 90H ; note on, channel 1 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send status byte MOVLW .65 MOVWF MIDI_BYTE ; put it in NOTE CALL MIDI_OUT_BYTE ; send the note MOVLW .0 ; set the velocity to 0 MOVWF MIDI_BYTE CALL MIDI_OUT_BYTE ; send the velocity RETURN ;***************************************************************** ; Wait 4 - wastes 4 cycles ;***************************************************************** WAIT_4 RETURN ;***************************************************************** ; Wait 6 - wastes 6 cycles ;***************************************************************** WAIT_6 NOP NOP RETURN ;***************************************************************** ; Wait 22 - wastes 22 cycles ;***************************************************************** WAIT_22 ; (including call and return) MOVLW .4 MOVWF WASTE DA_LOOP NOP DECFSZ WASTE, F ; decrement WASTE and leave if 0 GOTO DA_LOOP NOP RETURN ;***************************************************************** ; LONG_WAIT - wastes a perceivable amount of time ;***************************************************************** LONG_WAIT ; a long delay routine to hold notes on MOVLW .250 ; put 250 in the W register (delay time) MOVWF SNOOZE_A ; move the W register to our SNOOZE address OUTTER MOVLW .250 ; put 250 in the W register (delay time) MOVWF SNOOZE_B ; load the W register into SNOOZE_B INNER NOP NOP DECFSZ SNOOZE_B, F ; decrement SNOOZE_B and leave if 0 GOTO INNER ; go back to INNER DECFSZ SNOOZE_A, F ; decrement SNOOZE_A and leave if 0 GOTO OUTTER ; go back to OUTTER RETURN ; go back to the calling function END