-
Notifications
You must be signed in to change notification settings - Fork 8
/
6809_PINTIO.s
327 lines (318 loc) · 8.34 KB
/
6809_PINTIO.s
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
.macro CLI
ANDCC #$EF
.endm
.macro SEI
ORCC #$10
.endm
; Title Simple interrupt input and output using a
; 6821 Peripheral Interface Adapter
; and single character buffers.
;
; Name: PINTIO
;
; Purpose: This program consists of 5 subroutines that
; perform interrupt driven input and output
; using a 6821 PIA.
;
; INCH Read a character.
; INST Determine input status (whether input buffer is empty).
; OUTCH Write a character.
; OUTST Determine output status (whether output buffer is full).
; INIT Initialize 6821 PIA and interrupt system.
;
; Entry:
;
; INCH No parameters.
; INST No parameters.
; OUTCH Register A = character to transmit
; OUTST No parameters.
; INIT No parameters.
;
; Exit:
; INST Carry = 0 if input buffer is empty,
; 1 if character is available.
;
; OUTCH No parameters
;
; OUTST Carry = 0 if output buffer is empty,
; 1 if it is full.
;
; INIT No parameters.
;
; Registers Used:
;
; INCH A,CC
; INST A,CC
; OUTCH A,CC
; OUTST A,CC
; INIT A
;
; Time:
; INCH 40 cycles if a character is available
; INST 12 cycles
; OUTCH 98 cycles if output buffer is not full
; and output interrupt is expected
; OUTST 12 cycles
; INIT 99 cycles
; IOSRVC 45 cycles minimum if the interrupt is not ours
; 61 cycles to service an input interrupt
; 97 cycles to service an output interrupt
;
; These include the 21 cycles required for
; the processor to respond to an interrupt.
;
; Size:
;
; Program 158 bytes
;
; Data 7 bytes
;
; 6821 PIA EQUATES
; ARBITRARY 6821 PIA MEMORY ADDRESSES
;
PIADRA EQU $A400 ; PIA DATA REGISTER A
PIADDA EQU $A400 ; PIA DATA DIRECTION REGISTER A
PIACRA EQU $A401 ; PIA CONTROL REGISTER A
PIADRB EQU $A402 ; PIA DATA REGISTER B
PIADDB EQU $A402 ; PIA DATA DIRECTION REGISTER B
PIACRB EQU $A403 ; PIA CONTROL REGISTER B
;
; COLOR COMPUTER INTERRUPT VECTOR
;
INTVEC EQU $0100 ; VECTOR TO INTERRUPT SERVICE ROUTINE
;
; READ A CHARACTER FROM INPUT BUFFER
;
INCH:
JSR INST ; GET INPUT STATUS
BCC INCH ; HALT IF NO CHARACTER AVAILABLE
CLR RECDF ; INDICATE INPUT BUFFER EMPTY
LDA RECDAT ; GET CHARACTER FROM INPUT BUFFER
RTS
;
; DETERMINE INPUT STATUS (CARRY = 1 IF DATA AVAILABLE)
;
INST:
LDA RECDF ; GET DATA READY FLAG
LSRA ; SET CARRY FROM DATA READY FLAG
; CARRY = 1 IF CHARACTER AVAILABLE
RTS
;
; WRITE A CHARACTER INTO OUTPUT BUFFER
;
OUTCH:
PSHS A ; SAVE CHARACTER TO WRITE
;
; WAIT FOR OUTPUT BUFFER TO EMPTY,
; STORE NEXT CHARACTER
;
WAITOC:
JSR OUTST ; GET OUTPUT STATUS
BCS WAITOC ; WAIT IF GUTPUT BUFFER FULL
PULS A ; GET CHARACTER
STA TRNDAT ; STORE CHARACTER IN OUTPUT BUFFER
LDA #$FF ; INDICATE OUTPUT BUFFER FULL
STA TRNDF
TST OIE ; TEST OUTPUT INTERRUPT EXPECTED FLAG
BNE EXITOT ; EXIT IF 0UTPUT INTERRUPT EXPECTED
JSR OUTDAT ; SEND CHARACTER IMMEDIATELY IF
; NO OUTPUT INTERRUPT EXPECTED
EXITOT:
RTS
;
; DETERMINE OUTPUT STATUS (CARRY 1 IF OUTPUT BUFFER FULL)
;
OUTST:
LDA TRNDF ; GET TRANSMIT FLAG
LSRA ; SET CARRY FROM TRANSMIT FLAG
RTS ; CARRY = 1 IF BUFFER FULL
;
; INITIALIZE INTERRUPT SYSTEM AND 6821 PIA
;
INIT:
;
; DISABLE INTERRUPTS DURING INITIALIZATION BUT SAVE
; PREVIOUS STATE OF INTERRUPT FLAG
;
PSHS CC ; SAVE CURRENT FLAGS (PARTICULARLY I FLAG)
SEI ; DISABLE INTERRUPTS DURING
; INITIALIZATION
;
; INITIALIZE COLOR COMPUTER INTERRUPT VECTOR
;
LDX INTVEC ; GET CURRENT INTERRUPT VECTOR
STX NEXTSR ; SAVE IT AS ADDRESS OF NEXT SERVICE
; ROUTINE
LDX #IOSRVC ; GET ADDRESS OF OUR SERVICE ROUTINE
STX INTVEC ; SAVE IT AS INTERRUPT VECTOR
;
; INITIALIZE SOFTWARE FLAGS
;
CLRA
STA RECDF ; NO INPUT DATA AVAILABLE
STA TRNDF ; OUTPUT BUFFER EMPTY
STA OIE ; INDICATE NO OUTPUT INTERRUPT NEEDED
; 6821 READY TO TRANSMIT INITIALLY
;
; INITIALIZE 6821 PIA (PARALLEL INTERFACE)
;
CLR PIACRA ; ADDRESS DATA DIRECTION REGISTERS
CLR PIACRB
CLR PIADDA ; MAKE PORT A INPUT
LDA #$FF ; MAKE PORT B OUTPUT
STA PIADDB
LDA #00101111b
STA PIACRA ; SET PORT A AS FOLLOWS:
; BITS 7,6 NOT USED
; BIT 5 = 1 TO MAKE CA2 OUTPUT
; BIT 4 = 0 TO MAKE CA2 A PULSE
; BIT 3 = 1 TO MAKE CA2 A BRIEF INPUT
; ACKNOWLEDGE
; BIT 2 = 1 TO ADDRESS DATA REGISTER
; BIT 1 = 1 TO MAKE CA1 ACTIVE HIGH
; BIT 0 = 1 TO ENABLE CA1 INTERRUPTS
LDA #00100111b
STA PIACRB ; SET PORT B AS FOLLOWS:
; BITS 7, 6 NOT USED
; BIT 5 = 1 TO MAKE CB2 OUTPUT
; BIT 4 = 0 TO MAKE CB2 A PULSE
; BIT 3 = 0 TO MAKE CB2 A LONG OUTPUT
; BUFFER FULL
; BIT 2 = 1 TO ADDRESS DATA REGISTER
; BIT 1 = 1 TO MAKE CB1 ACTIVE HIGH
; BIT 0 = 1 TO ENABLE CB1 INTERRUPTS
PULS CC ; RESTORE FLAGS (THIS REENABLES INTERRUPTS
; IF THEY WERE ENABLED WHEN INIT WAS
; CALLED)
;
; INTERRUPT MANAGER
;
; DETERMINES WHETHER INPUT OR OUTPUT INTERRUPT OCCURRED
;
IOSRVC:
;
; INPUT INTERRUPT FLAG IS BIT 7 OF CONTROL REGISTER A
; OUTPUT INTERRUPT FLAG IS BIT 7 OF CONTROL REGISTER B
;
LDA PIACRA ; CHECK FOR INPUT INTERRUPT
BMI RDHDLR ; BRANCH IF INPUT INTERRUPT
LDA PIACRB ; CHECK FOR OUTPUT INTERRUPT
BMI WRHDLR ; BRANCH IF OUTPUT INTERRUPT
JMP [NEXTSR] ; INTERRUPT IS FROM ANOTHER SOURCE
;
; INPUT (READ) INTERRUPT HANDLER
;
RDHDLR:
LDA PIADRA ; READ DATA FROM 6821 PIA
STA RECDAT ; SAVE DATA IN INPUT BUFFER
LDA #$FF
STA RECDF ; INDICATE CHARACTER AVAILABLE
RTI
;
; OUTPUT (WRITE) INTERRUPT HANDLER
;
WRHDLR: LDA TRNDF ; TEST DATA AVAILABLE FLAG
BEQ NODATA ; JUMP IF NO DATA TO TRANSMIT
JSR OUTDAT ; SEND DATA TO 6821 PIA RTI
;
; IF AN OUTPUT INTERRUPT OCCURS WHEN NO DATA IS AVAILABLE,
; WE MUST CLEAR IT (IN THE 6821) TO AVOID AN ENDLESS LOOP. LATER,
; HHEN A CHARACTER BECOMES AVAILABLE, WE NEED TO KNOW THAT AN
; OUTPUT INTERRUPT HAS OCCURRED WITHOUT BEING SERVICED. THE KEY
; TO DOING THIS IS THE OUTPUT INTERRUPT EXPECTED FLAG OIE. THIS FLAG IS
; CLEARED WHEN AN OUTPUT INTERRUPT HAS OCCURRED BUT HAS NOT BEEN
; SERVICED. IT IS ALSO CLEARED INITIALLY SINCE THE 6821 PIA STARTS
; OUT READY. OIE IS SET WHENEVER DATA IS ACTUALLY SENT TO THE PIA.
; THUS THE OUTPUT ROUTINE OUTCH CAN CHECK OIE TO DETERMINE WHETHER
; TO SEND THE DATA IMMEDIATELY OR WAIT FOR AN OUTPUT INTERRUPT.
; THE PROBLEM IS THAT AN OUTPUT DEVICE MAY REQUEST SERVICE BEFORE
; THE COMPUTER HAS ANYTHING TO SEND (UNLIKE AN INPUT DEVICE THAT
; HAS DATA WHEN IT REQUESTS SERVICE). THE OIE FLAG SOLVES THE
; PROBLEM OF AN UNSERVICED OUTPUT INTERRUPT ASSERTING ITSELF
; REPEATEDLY, WHILE STILL ENSURING THE RECOGNITION OF OUTPUT
; INTERRUPTS.
;
NODATA:
LDA PIADRB ; READ PORT B DATA REGISTER TO CLEAR
; INTERRUPT
CLR OIE ; DO NOT EXPECT AN INTERRUPT
WRDONE:
RTI
; ***************************************
; ROUTINE: OUTDAT
; PURPOSE: SEND CHARACTER TO 6821 PIA
; ENTRY: TRNDAT = CHARACTER TO SEND
; EXIT: NONE
; REGISTERS USED: A,CC
; ***************************************
OUTDAT:
LDA TRNDAT ; GET DATA FROM OUTPUT BUFFER
STA PIADRB ; SEND DATA TO 6821 PIA
CLR TRNDF ; INDICATE OUTPUT BUFFER EMPTY
LDA #$FF ; INDICATE OUTPUT INTERRUPT EXPECTED
STA OIE ; OIE = FF HEX
RTS
;
; DATA SECTION
;
RECDAT RMB 1 ; RECEIVE DATA
RECDF RMB 1 ; RECEIVE DATA FLAG (0 = NO DATA,
; FF = DATA)
TRNDAT RMB 1 ; TRANSMIT DATA
TRNDF RMB 1 ; TRANSMIT DATA FLAG
; (0 = BUFFER EMPTY, FF = BUFFER FULL)
OIE RMB 1 ; OUTPUT INTERRUPT EXPECTED
; (0 = INTERRUPT OCCURRED WITHOUT
; BEING SERVICED,
; FF = INTERRUPT SERVICED)
NEXTSR RMB 2 ; ADDRESS OF NEXT INTERRUPT SERVICE
; ROUTINE
;
; SAMPLE EXECUTION:
;
; CHARACTER EQUATES
;
ESCAPE EQU $1B ; ASCII ESCAPE CHARACTER
TESTCH EQU 'A' ; TEST CHARACTER = A
SC9B:
JSR INIT ; INITIALIZE 6821 PIA, INTERRUPT SYSTEM
CLI ; ENABLE INTERRUPTS
;
; SIMPLE EXAMPLE READ AND ECHO CHARACTERS
; UNTIL AN ESC IS RECEIVED
;
LOOP:
JSR INCH
PSHS A ; READ CHARACTER
JSR OUTCH ; ECHO CHARACTER
PULS A
CMPA #ESCAPE ; IS CHARACTER AN ESCAPE?
BNE LOOP ; STAY IN LOOP IF NOT
;
; AN ASYNCHRONOUS EXAMPLE
;
; OUTPUT "A" TO CONSOLE CONTINUOUSLY
; BUT ALSO LOOK AT INPUT SIDE,
; READING AND ECHOING INPUT CHARACTERS.
;
ASYNLP:
; OUTPUT AN "A" IF OUTPUT IS NOT BUSY
JSR OUTST ; IS OUTPUT BUSY?
BCS ASYNLP ; BRANCH (WAIT) IF IT IS
LDA #TESTCH
JSR OUTCH ; OUTPUT TEST CHARACTER
;
; CHECK INPUT PORT
; ECHO CHARACTER IF ONE IS AVAILABLE
; EXIT ON ESCAPE CHARACTER
;
JSR INST ; IS INPUT DATA AVAILABLE?
BCS ASYNLP ; BRANCH IF NOT (SEND ANOTHER "A")
JSR INCH ; GET CHARACTER
CMPA #ESCAPE ; IS IT AN ESCAPE?
BEQ DONE ; BRANCH IF IT IS
JSR OUTCH ; ELSE ECHO CHARACTER
BRA ASYNLP ; AND CONTINUE
DONE:
BRA SC9B ; REPEAT TEST
END