-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSYM_VOX.asm
384 lines (345 loc) · 6 KB
/
SYM_VOX.asm
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
;SYM memory player (scans parts of memory and 'plays' through PB7)
processor 6502
* = $200
;--------- CONSTANTS
T2_VAL = $6000 ;Timer 2 interval (tempo timer)
;--------- 6532 (which includes system RAM)
DSPBUF = $A640 ;6532 System RAM: Display Buffer
;--------- PORTS
T1LL = $A806
T1CH = $A805
ACR = $A80B
IFR = $A80D
IER = $A80E
T2LL = $A808
T2CH = $A809
;--------- VARIABLES
VARS = $00
ADNBS3 = $00 ;Four address nibbles for scanning address
ADNBS2 = $01
ADNBS1 = $02
ADNBS0 = $03
RANGE = $04 ;'Pitch' range (upper byte of timer)
TEMPO = $05
RMASK = $06
STPFLG = $07
RSTFLG = $08
INDEX = $0A
SCANAD = $0B ;16-bt memory-scan address
;$0C
TCOUNT = $0D ;Timer interrupt count
RIFLEN = $0E ;16-bit riff length
;$0F
SCORE = $10 ;16-bit score pointer
;$11
SCRCTR = $12 ;16-bit score counter
;$13
;--------- MONITOR SUBROUTINES
RESALL = $81C4
SAVER = $8188
ASCNIB = $8275
GETKEY = $88AF
SCAND = $8906
KEYQ = $8923
LRNKEY = $892C
BEEP = $8972
NOBEEP = $899B
ACCESS = $8B86
SEGSM1 = $8C29 ; SYM display
USRBRK = $FFF6 ;User break vector
IRQVEC = $FFFE ;Interrupt vector
INIT SEI
JSR ACCESS
LDA #<IRQSRV
STA IRQVEC
LDA #>IRQSRV
STA IRQVEC+1
LDA #$C0 ;Set timer 1: free-running, output on PB7
STA ACR ; timer 2: one-shot (will trigger interrupt)
LDA #$A0
STA IER
LDA #$00
STA SCANAD+1
STA SCORE+1
STA SCANAD
STA SCORE
STA ADNBS0
STA ADNBS1
STA ADNBS2
STA ADNBS3
LDA #7
STA RANGE
LDA #$0E
STA TEMPO
LDA #$40
STA RMASK ;Arbitrary rest tester: try $04
LDA #16
STA RIFLEN ;Initial riff length = 16
STA SCRCTR
LDA #0
STA RIFLEN+1
STA SCRCTR+1
LDA #0
STA STPFLG
STA RSTFLG
LDA #1
STA TCOUNT
LDA #<T2_VAL ;Set Timer 2 (tempo) value
STA T2LL
LDA #>T2_VAL
STA T2CH ;and start it
CLI
; MAIN LOOP: scan keyboard
MLOOP JSR GETCMD
JMP MLOOP
;---------- Get pressed key (if any) and process it (scan display once)
GETCMD JSR SAVER
JSR SCAND ;Scan display once
JSR KEYQ
BNE GTKY
JMP RESALL ;No key down: restore regs. and return
GTKY JSR LRNKEY
PHA
DEBNCE JSR KEYQ
BNE DEBNCE ;Key still down? Wait longer.
JSR NOBEEP
JSR KEYQ
BNE DEBNCE
PARSE PLA
CMP #$0D ; < CR > = Currently does nothing
BNE NEXT1
NOP
JMP RESALL
NEXT1 CMP #$2D ; < - > = tempo
BNE NEXT2
LDX #TEMPO
JMP SETIDX
NEXT2 CMP #$3E ; < -> > = pitch range
BNE NEXT3
LDX #RANGE
JMP SETIDX
NEXT3 CMP #$47 ; < GO > = ADNBS1
BNE NEXT4
LDX #ADNBS1
JMP SETIDX
NEXT4 CMP #$52 ; < reg > = ADNBS0
BNE NEXT5
LDX #ADNBS0
JMP SETIDX
NEXT5 CMP #$13 ;< L2 > = ADNBS3
BNE NEXT6
LDX #ADNBS3
JMP SETIDX
NEXT6 CMP #$1E ;< S2 > = ADNBS2
BNE NEXT7
LDX #ADNBS2
JMP SETIDX
NEXT7 CMP #$4D ;< MEM > = RMASK
BNE NEXT8
LDX #RMASK ; (will require processing)
JMP SETIDX
NEXT8 CMP #$FF ;< SHIFT > = RIFLEN
BNE PARAM
LDX #RIFLEN ; (will require processing)
JMP SETIDX
PARAM JSR ASCNIB
LDX INDEX
CPX #TEMPO ; Tempo?
BNE P0
ADC #1
STA TEMPO
JMP RESALL
P0 CPX #RMASK ; Set rest mask?
BNE P1
TAX
BEQ STRM
CMP #8 ; If choice > 8, set mask to $FF (silence)
BCC SKX
LDA #$FF
BNE STRM
SKX LDA #1
SHFT ASL
DEX
BNE SHFT
STRM STA RMASK
JMP RESALL
P1 CPX #RIFLEN ; Shift key (set Riff length)
BNE P2
ASL ;double the index value
TAX
LDA RFLTAB,X
STA RIFLEN
LDA RFLTAB+1,X
STA RIFLEN+1
FORCE SEI
LDA #0 ; Force immediate riff reset
STA SCRCTR
LDA #0
STA SCRCTR+1
CLI
JMP RESALL
P2 STA VARS,X
CPX #ADNBS0+1 ;Address change?
BCS SETIDX
SEI
LDA ADNBS1 ; (re)build memory-scan pointer
ASL
ASL
ASL
ASL
ADC ADNBS0
STA SCANAD
LDA ADNBS3
ASL
ASL
ASL
ASL
ADC ADNBS2
STA SCANAD+1
JMP FORCE ; Force immediate riff reset
SETIDX STX INDEX
JMP RESALL
;---------- Display byte in Acc. on 2 lowest display positions
DSPBYT PHA
AND #$0F
TAY
LDA SEGSM1,Y
STA DSPBUF+5
PLA
PHA
LSR
LSR
LSR
LSR
TAY
LDA SEGSM1,Y
STA DSPBUF+4
PLA
RTS
;---------- Display memory pointer
DSPPTR LDA SCORE+1
PHA
AND #$F0
LSR
LSR
LSR
LSR
TAY
LDA SEGSM1,Y
STA DSPBUF
PLA
AND #$0F
TAY
LDA SEGSM1,Y
STA DSPBUF+1
LDA SCORE
PHA
AND #$F0
LSR
LSR
LSR
LSR
TAY
LDA SEGSM1,Y
STA DSPBUF+2
PLA
AND #$0F
TAY
LDA SEGSM1,Y
ORA #$80 ;light up decimal point
STA DSPBUF+3
RTS
;---------- Play one note
BOP STA T1LL ;Store low byte of freq. in timer lo latch
LDA RSTFLG
BEQ GOON
LDA #0
STA T1CH
STA RSTFLG
RTS
GOON LDA RANGE ;store upper byte of timer ('pitch' range), which
STA T1CH ;triggers the free-running counter output on PB7
RTS
;---------- Interrupt service routine -- called by timeout of TIMER 2 (tempo timer)
IRQSRV PHA
TXA
PHA
TYA
PHA
TSX
LDA $0104,X
AND #$10
BEQ NOBRK
PLA
TAY
PLA
TAX
PLA
JMP (USRBRK)
NOBRK LDA IFR
STA IFR ;Clear interrupt
LDA #<T2_VAL ;Reset (one-shot) Timer 2
STA T2LL
LDA #>T2_VAL
STA T2CH ;and re-start it
DEC TCOUNT
BNE IRQOUT
LDA TEMPO ;Reset the tempo value
STA TCOUNT
LDA SCRCTR ;Score counter at zero?
BNE PLAY
LDA SCRCTR+1
BNE PLAY
LDA SCANAD ;Yes: end of riff: loop back to start
STA SCORE
LDA SCANAD+1
STA SCORE+1
LDA RIFLEN
STA SCRCTR
LDA RIFLEN+1
STA SCRCTR+1
PLAY JSR DSPPTR
LDY #0
LDA (SCORE),Y ;Get next 'pitch'
JSR DSPBYT ;Display it
LDY RMASK
CPY #$FF ;Silence?
BEQ SHHH
BIT RMASK ;Arbitrary rest test
BEQ CONTIN
SHHH LDA #1
STA RSTFLG
LDA #0
CONTIN JSR BOP
INC SCORE
BNE DECCTR
INC SCORE+1
DECCTR DEC SCRCTR
LDA SCRCTR
CMP #$FF
BNE IRQOUT
DEC SCRCTR+1
IRQOUT PLA
TAY
PLA
TAX
PLA
RTI
;--------- Riff length table
RFLTAB .WORD 2
.WORD 3
.WORD 4
.WORD 5
.WORD 7
.WORD 8
.WORD 12
.WORD 16
.WORD 32
.WORD 64
.WORD 128
.WORD 256
.WORD 512
.WORD 2048
.WORD 4096
.WORD 8192
.END