PORTA = $6001 DDRA = $6003 T1LCL = $6004 T1LCH = $6005 ACR = $600b PCR = $600c IFR = $600d IER = $600e SER = %00000001 RCLK = %00000010 SRCLK = %00000100 INTERVAL = 33 ; increase counter 3 times per scond WAIT_INTERVAL = 99 ; wait one second on button press CURRENT = $0 ; current counter VISIBLE = $1 ; visible counter (as last printed to the 7-segment display) TICKS = $2 ; internal ticks counter (on overflow increment counter) RUNNING = $3 ; if counter is running or stopped COUNTER = $4 ; counter, increment on button press, show only shortly when button pressed .org #$f800 reset: sei ; disallow interrupts during initialization ldx #$FF ; initialize call stack to $1FF txs lda #%11000010 ; enable CA1 and timer1 interrupts sta IER lda #$0 ; negative edge triggering sta PCR lda ACR and #$7F ora #%01000000 ; setup timer for free running timer1, no PB7 sta ACR lda #%00000111 ; set output on 7seg control pins of PORTA sta DDRA lda #$0 ; initialize 8-bit counter and tick counter sta CURRENT lda #$FF ; the visible counter is different at init, so we force sta VISIBLE ; the drawing of the initial value lda #INTERVAL sta TICKS lda #$FF sta RUNNING lda #$0 ; initialize button press counter sta COUNTER lda #$0F ; initialize counter of VIA timer1 ($270f = 9999 at 1MHz) sta T1LCL lda #$27 sta T1LCH cli ; allow interrupts now mainloop: ; main loop, just print value of counter sei lda CURRENT cmp VISIBLE cli beq mainloop jsr print7seg ; update value sei lda CURRENT sta VISIBLE cli jmp mainloop print7seg: ldy #$8 ; 8 bits to shift loop7seg: rol a bcc zerobit ; C=0, bang a zero to SER onebit: ldx #(SER) ; C=1, bang a one to SER stx PORTA ldx #(SER | SRCLK) stx PORTA ldx #(SER) stx PORTA jmp next zerobit: ldx #$0 ; C=0, bang a zero to SER stx PORTA ldx #SRCLK stx PORTA ldx #$0 stx PORTA jmp next next: dey bne loop7seg rol a ; restore A register output: ldx #0 ; bang RCLK to store output in latch stx PORTA ldx #RCLK stx PORTA ldx #0 stx PORTA rts nmi: rti irq: pha ; save state txa pha tya pha lda IFR ; check interrupt register of VIA bpl irq_done ; bit 7 set? if not, not an interrupt of the VIA asl ; bit 6 in sign (timer1) bmi timer1 asl ; bit 5 in sign (timer2, unused) asl ; bit 4 in sign (cb1, unused) asl ; bit 3 in sign (cb2, unused) asl ; bit 2 in sign (shift, unused) asl ; bit 1 in sign (CA1) bmi ca1 asl ; bit 0 in sign (CA2, unused) jmp irq_done ; no more interrupt to handle from VIA timer1: bit T1LCL ; clear timer1 interrupt lda #$FF cmp RUNNING bne irq_done tick: dec TICKS bne irq_done lda #INTERVAL sta TICKS inc CURRENT ; increment internal counter jmp irq_done ca1: lda RUNNING ; toggle running flag eor #$FF sta RUNNING inc COUNTER lda COUNTER sta CURRENT lda #WAIT_INTERVAL sta TICKS bit PORTA ; clear CA1 interrupt (button press) jmp irq_done irq_done: pla tay pla tax pla cli rti .org #$fffa .word nmi .word reset .word irq