; Christmas Star firmware (preliminary hack) Copyright 1999 by Mario Becroft $base !10 RAM EQU $0080 ROM EQU $EC00 Vectors EQU $FFDE $Include '../jl3regs.inc' ; ***** VARIABLES ***** org RAM led_data ds 40 led_counter ds 1 point_counter ds 1 adc_status ds 1 adc_data0 ds 1 adc_data1 ds 1 seq_pc ds 1 seq_a ds 1 seq_b ds 1 seq_flags ds 1 seq_delay ds 1 seq_math_temp ds 1 NEW_POINT_FLAG equ 0 ; seq_flags bit CARRY_FLAG equ 1 ; seq_flags bit ; ***** INITIALISATION ***** org ROM Start ; Disable the COP bset COPD,CONFIG1 ; Configure the timer mov #$01,TMODH mov #$00,TMODL mov #TOIE.,TSC ; Configure the analogue to digital converter mov #ADIV1.,ADCLK ; Clear variables clr led_counter clr point_counter clr adc_status clra jsr set_all_leds ; Make row and column pins outputs, driving HIGH by default ; (outputs are ACTIVE LOW) mov #$1F,PORTB mov #$1F,DDRB ;mov #$1E,DDRB ;******** FOR DEBUGGING mov #$FF,PORTA mov #$FF,DDRA bset 6,PORTD bset 7,PORTD bset 6,DDRD bset 7,DDRD ; Enable interrupts cli ; ***** MAIN PROGRAM ***** clra clrx mov #{AIEN.+ADCH2.+ADCH1.},ADSCR ; Enable first A/D conversion ; Initialise the sequencer clr seq_pc clr seq_a clr seq_b clr seq_delay clr seq_flags bra main_loop ; *** MISC INSTRUCTIONS *** _seq_all lda seq_a jsr set_all_leds jmp seq_end_instr _seq_led lda seq_b seq_led_2 cmp #40 blo seq_led_1 sub #40 bra seq_led_2 seq_led_1 tax lda seq_a sta led_data,x jmp seq_end_instr seq_all jmp _seq_all seq_led jmp _seq_led seq_jmp jsr seq_read sta seq_pc jmp seq_end_instr seq_an0 mov adc_data0,seq_a jmp seq_end_instr seq_an1 mov adc_data1,seq_a jmp seq_end_instr seq_dly mov seq_a,seq_delay seq_nop jmp seq_end_instr seq_lda jsr seq_read sta seq_a jmp seq_end_instr seq_ldb jsr seq_read sta seq_b jmp seq_end_instr seq_tab mov seq_a,seq_b jmp seq_end_instr seq_tba mov seq_b,seq_a jmp seq_end_instr seq_xab lda seq_a mov seq_b,seq_a sta seq_b jmp seq_end_instr seq_dcy bclr NEW_POINT_FLAG,seq_flags brclr NEW_POINT_FLAG,seq_flags,* jmp seq_end_instr seq_lle lda seq_b seq_lle_2 cmp #40 blo seq_lle_1 sub #40 bra seq_lle_2 seq_lle_1 tax lda led_data,x sta seq_a bra seq_end_instr ; *** MAIN LOOP *** main_loop ;brclr NEW_POINT_FLAG,seq_flags,* ;bclr NEW_POINT_FLAG,seq_flags lda seq_delay beq seq_fetch delay_1 bclr NEW_POINT_FLAG,seq_flags brclr NEW_POINT_FLAG,seq_flags,* dbnza delay_1 clr seq_delay seq_fetch jsr seq_read cbeqa #S_ALL,seq_all cbeqa #S_LED,seq_led cbeqa #S_JMP,seq_jmp cbeqa #S_DCY,seq_dcy cbeqa #S_LLE,seq_lle cbeqa #S_AN0,seq_an0 cbeqa #S_AN1,seq_an1 cbeqa #S_DLY,seq_dly cbeqa #S_NOP,seq_nop cbeqa #S_LZA,seq_lda cbeqa #S_LZB,seq_ldb cbeqa #S_TAB,seq_tab cbeqa #S_TBA,seq_tba cbeqa #S_XAB,seq_xab cbeqa #S_INA,seq_ina cbeqa #S_DEA,seq_dea cbeqa #S_INB,seq_inb cbeqa #S_DEB,seq_deb cbeqa #S_ADA,seq_ada cbeqa #S_SUA,seq_sua cbeqa #S_ADB,seq_adb cbeqa #S_SUB,seq_sub cbeqa #S_ABA,seq_aba cbeqa #S_SBA,seq_sba cbeqa #S_AAB,seq_aab cbeqa #S_SAB,seq_sab cbeqa #S_MAA,seq_maa cbeqa #S_MIA,seq_mia cbeqa #S_CZA,seq_cza cbeqa #S_WRA,seq_wra cbeqa #S_WRB,seq_wrb ; cbeqa #S_,seq_ ; No command, so treat as data for storage into A sta seq_a seq_end_instr bra main_loop seq_aab jmp _seq_aab seq_sab jmp _seq_sab seq_maa jmp _seq_maa seq_mia jmp _seq_mia seq_cza jmp _seq_cza seq_wrb jmp _seq_wrb seq_wra jmp _seq_wra ; *** MATH INSTRUCTIONS *** seq_ina inc seq_a bra seq_end_instr seq_dea dec seq_a bra seq_end_instr seq_inb inc seq_b bra seq_end_instr seq_deb dec seq_b bra seq_end_instr seq_ada jsr seq_read add seq_a sta seq_a bclr CARRY_FLAG,seq_flags bcc seq_ada_1 bset CARRY_FLAG,seq_flags seq_ada_1 bra seq_end_instr seq_sua jsr seq_read sta seq_math_temp lda seq_a sub seq_math_temp sta seq_a bclr CARRY_FLAG,seq_flags bcc seq_sua_1 bset CARRY_FLAG,seq_flags seq_sua_1 bra seq_end_instr seq_adb jsr seq_read add seq_b sta seq_b bra seq_end_instr seq_sub jsr seq_read sta seq_math_temp lda seq_b sub seq_math_temp sta seq_b bra seq_end_instr seq_aba lda seq_a add seq_b sta seq_a bra seq_end_instr seq_sba lda seq_a sub seq_b sta seq_a bra seq_end_instr _seq_aab lda seq_b add seq_a sta seq_b bra seq_end_instr _seq_sab lda seq_b sub seq_a sta seq_b bra seq_end_instr _seq_maa bsr seq_read cmp seq_a bls seq_maa_1 sta seq_a seq_maa_1 jmp seq_end_instr _seq_mia bsr seq_read cmp seq_a bhs seq_mia_1 sta seq_a seq_mia_1 jmp seq_end_instr _seq_cza brclr CARRY_FLAG,seq_flags,seq_cza_1 clr seq_a seq_cza_1 jmp seq_end_instr _seq_wra bsr seq_read cmp seq_a bhs seq_wra_1 clr seq_a seq_wra_1 jmp seq_end_instr _seq_wrb bsr seq_read cmp seq_b bhi seq_wrb_1 clr seq_b seq_wrb_1 jmp seq_end_instr S_LZA equ $80 ; Load A with immediate value S_LZB equ $81 ; Load B with immediate value S_TAB equ $82 ; Transfer A to B S_TBA equ $83 ; Transfer B to A S_XAB equ $84 ; Swap A and B S_JMP equ $90 ; Jump to immediate address S_AN0 equ $A0 ; Load A with analogue input 0 S_AN1 equ $A1 ; Load A with analogue input 1 S_LED equ $B0 ; Set LED B to value A S_ALL equ $B1 ; Set all LEDS to value A S_LLE equ $B2 ; Load A with current value of LED B S_NOP equ $C0 ; No operation S_DLY equ $C1 ; Delay for number of display cycles in A S_DCY equ $C2 ; Delay for one display cycle S_INA equ $D0 ; Increment A S_DEA equ $D1 ; Decrement A S_INB equ $D2 ; Increment B S_DEB equ $D3 ; Decrement B S_ADA equ $D4 ; Add immediate to A S_SUA equ $D5 ; Subtract immediate from A S_ADB equ $D6 ; Add immediate to B S_SUB equ $D7 ; Subtract immediate from B S_ABA equ $D8 ; Add B to A S_SBA equ $D9 ; Subtract B from A S_AAB equ $DA ; Add A to B S_SAB equ $DB ; Subtract A from B S_MAA equ $E0 ; A = max(A,immediate) S_MIA equ $E1 ; A = min(A,immediate) S_CZA equ $E2 ; If overflow from last op, make A = 0 S_WRA equ $E4 ; If A >= immediate then A = 0 S_WRB equ $E5 ; If B >= immediate then B = 0 SEQ_BASE db S_LLE db S_SUA,!1 db S_CZA db S_LED db S_INB db S_LLE db S_SUA,!1 db S_CZA db S_LED db S_INB db S_LLE db S_SUA,!4 db S_CZA db S_LED db S_INB db S_LLE db S_SUA,!20 db S_CZA db S_LED db S_INB db S_LLE db S_SUA,!37 db S_CZA db S_LED db S_INB db S_ADB,4 db S_LLE db S_ADA,!37 db S_LED db S_INB db S_LLE db S_ADA,!20 db S_LED db S_INB db S_LLE db S_ADA,!4 db S_LED db S_INB db S_LLE db S_ADA,!1 db S_LED db S_INB db S_LLE db S_ADA,!1 db S_LED db S_INB db S_SUB,13 db S_WRB,!40 db S_AN0 db S_DLY db S_JMP,0 ; ***** SUBROUTINES ***** ; Reads a byte from the sequencer control program into ACC, and increments PC ; MODIFIES X seq_read ldx seq_pc lda SEQ_BASE,x inc seq_pc rts ; Sets the value of all LEDs to value of ACC ; MODIFIES X set_all_leds ldx #40 set_all_leds_1 sta led_data-1,x dbnzx set_all_leds_1 rts ; Converts a byte in ACC 0-255 to the correct range for LED brightness byte2led lsra lsra rts ; Converts a byte in ACC 0-63 to the correct range for LED brightness half2led rts ; ***** INTERRUPT SERVICE ROUTINES ***** ; Handles ADC conversion complete interrupts Adc_isr brset 0,adc_status,adc_ch1 mov ADR,adc_data0 ; Store channel 0 mov #{AIEN.+ADCH2.+ADCH1.+ADCH0.},ADSCR ; Enable channel 1 bset 0,adc_status rti adc_ch1 mov ADR,adc_data1 ; Store channel 1 mov #{AIEN.+ADCH2.+ADCH1.},ADSCR ; Enable channel 0 bclr 0,adc_status rti ; Handles timer overflows Timer_isr ; Reset timer overflow flag bclr TOF,TSC ; Get led counter lda led_counter ; If 0 then a new point is to be displayed beq new_point ; Otherwise turn off any expired points ldx point_counter lslx lslx lslx ; Check each LED and turn it off if it has expired lda led_data+0,x cmp led_counter bhi led0_still_on bset 0,PORTA led0_still_on lda led_data+1,x cmp led_counter bhi led1_still_on bset 1,PORTA led1_still_on lda led_data+2,x cmp led_counter bhi led2_still_on bset 2,PORTA led2_still_on lda led_data+3,x cmp led_counter bhi led3_still_on bset 3,PORTA led3_still_on lda led_data+4,x cmp led_counter bhi led4_still_on bset 4,PORTA led4_still_on lda led_data+5,x cmp led_counter bhi led5_still_on bset 5,PORTA led5_still_on lda led_data+6,x cmp led_counter bhi led6_still_on bset 6,PORTD led6_still_on lda led_data+7,x cmp led_counter bhi led7_still_on bset 7,PORTD led7_still_on bra points_done new_point ; CHANGE TO A NEW POINT ; Turn off all point common outputs bset 0,PORTB bset 1,PORTB bset 2,PORTB bset 3,PORTB bset 4,PORTB ; Turn on LEDs that are enabled ldx point_counter lslx lslx lslx lda led_data+0,x beq led0_now_off bclr 0,PORTA led0_now_off lda led_data+1,x beq led1_now_off bclr 1,PORTA led1_now_off lda led_data+2,x beq led2_now_off bclr 2,PORTA led2_now_off lda led_data+3,x beq led3_now_off bclr 3,PORTA led3_now_off lda led_data+4,x beq led4_now_off bclr 4,PORTA led4_now_off lda led_data+5,x beq led5_now_off bclr 5,PORTA led5_now_off lda led_data+6,x beq led6_now_off bclr 6,PORTD led6_now_off lda led_data+7,x beq led7_now_off bclr 7,PORTD led7_now_off ; Enable the current point lda point_counter cbeqa #1,point_1 cbeqa #2,point_2 cbeqa #3,point_3 cbeqa #4,point_4 point_0 bclr 0,PORTB bra points_done point_1 bclr 1,PORTB bra points_done point_2 bclr 2,PORTB bra points_done point_3 bclr 3,PORTB bra points_done point_4 bclr 4,PORTB bset NEW_POINT_FLAG,seq_flags points_done ; Increment led & point counters inc led_counter lda led_counter cmp #64 bne led_counter_nz clr led_counter inc point_counter lda point_counter cmp #5 bne led_counter_nz clr point_counter led_counter_nz rti ; ***** VECTORS ***** org Vectors dw Adc_isr ; ADC Conversion Complete Vector dw Start ; Keyboard Vector dw Start ; (No Vector Assigned $FFE2-$FFE3) dw Start ; (No Vector Assigned $FFE4-$FFE5) dw Start ; (No Vector Assigned $FFE6-$FFE7) dw Start ; (No Vector Assigned $FFE8-$FFE9) dw Start ; (No Vector Assigned $FFEA-$FFEB) dw Start ; (No Vector Assigned $FFEC-$FFED) dw Start ; (No Vector Assigned $FFEE-$FFEF) dw Start ; (No Vector Assigned $FFF0-$FFF1) dw Timer_isr ; TIM1 Overflow Vector dw Start ; TIM1 Channel 1 Vector dw Start ; TIM1 Channel 0 Vector dw Start ; (No Vector Assigned $FFF8-$FFF9) dw Start ; ~IRQ1 dw Start ; SWI Vector dw Start ; Reset Vector