1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
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
|