-
Notifications
You must be signed in to change notification settings - Fork 8
/
6809_IOHDLR.s
455 lines (445 loc) · 11.7 KB
/
6809_IOHDLR.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
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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
;
; Title: I/O Device Table Handler
; Name: IOHDLR
; Purpose: Perform I/O in a device independent manner.
; This can be done by accessing all devices
; in the same way using an I/O Control Block (IOCB)
; and a device table.
;
; The routines here allow the following operations:
;
; Operation number Description
;
; 0 Initialize Device
; 1 Determine input status
; 2 Read 1 byte
; 3 Read N bytes
; 4 Determine output status
; 5 Write 1 byte
; 6 Write N bytes
;
; Adding operations such as Open, Close, Delete, Rename, and Append
; would allow for more complex devices such as floppy or hard disks.
;
; An IOCB is an array consisting of elements with the following form:
;
; IOCB + 0 = Device Number
; IOCB + 1 = Operation Number
; IOCB + 2 = Status
; IOCB + 3 = High byte of buffer address
; IOCB + 4 = Low byte of buffer address
; IOCB + 5 = High byte of buffer Length
; IOCB + 6 = Low byte of buffer length
;
; The device table is implemented as a Linked List.
;
; Two routines maintain the List:
; INITDL, which initializes it to empty, and
; INSDL, which inserts a device into it.
;
; A device table entry has the following form:
;
; DVTBL + 0 = High byte of link field
; DVTBL + 1 = Low byte of link field
; DVTBL + 2 = Device Number
; DVTBL + 3 = High byte of device initialization
; DVTBL + 4 = Low byte of device initialization
; DVTBL + 5 = High byte of input status routine
; DVTBL + 6 = Low byte of input status routine
; DVTBL + 7 = High byte of input 1 byte routine
; DVTBL + 8 = LOW BYTE of input 1 byte routine
; DVTBL + 9 = High byte of input N bytes routine
; DVTBL + 10= Low byte of input N bytes routine
; DVTBL + 11= High byte of output status routine
; DVTBL + 12= Low byte of output status routine
; DVTBL + 13= High byte of output 1 byte routine
; DVTBL + 14= Low byte of output 1 byte routine
; DVTBL + 15= High byte of output N bytes routine
; DVTBL + 16= Low byte of output N bytes routine
;
; Entry:
;
; Register X = Base address of IOCB
; Register A = For write 1 byte, contains the data (no buffer is used).
;
; Exit:
; Register A = Copy of the IOCB status byte
; Except contains the data for read 1 byte (no buffer is used).
; Status byte of IOCB is 0
; if the operation was completed successfully;
; otherwise, it contains the error number.
;
; Status value Description
;
; 0 No errors
; 1 Bad device number
; 2 Bad operation number
; 3 Input data available or output device ready
;
; Registers Used: All
;
; Time:
; 75 cycles overhead plus
; 23 cycles for each device in the list
; which is not the one requested
; Size:
; Program 78 bytes
; Data 5 bytes
;
; IOCB AND DEVICE TABLE EQUATES
IOCBDN EQU 0 ; IOCB DEVICE NUMBER
IOCBOP EQU 1 ; IOCB OPERATION NUMBER
IOCBST EQU 2 ; IOCB STATUS
IOCBBA EQU 3 ; IOCB BUFFER BASE ADDRESS
IGCBBL EQU 5 ; IOCB BUFFER LENGTH
DTLNK EQU 0 ; DEVICE TABLE LINK FIELD
DTDN EQU 2 ; DEVICE TABLE DEVICE NUMBER
DTSR EQU 3 ; BEGINNING OF DEVICE TABLE SUBROUTINES
;
; OPERATION NUMBERS
;
NUMOP EQU 7 ; NUMBER OF OPERATIONS
INIT EQU 0 ; INITIALIZATION
ISTAT EQU 1 ; INPUT STATUS
R1BYTE EQU 2 ; READ 1 BYTE
RNBYTE EQU 3 ; READ N BYTES
OSTAT EQU 4 ; OUTPUT STATUS
W1BYTE EQU 5 ; WRITE 1 BYTE
WNBYTE EQU 6 ; WRITE N BYTES
;
; STATUS VALUES
;
NOERR EQU 0 ; NO ERRORS
DEVERR EQU 1 ; BAD DEVICE NUMBER
OPERR EQU 2 ; BAD OPERATION NUMBER
DEVRDY EQU 3 ; INPUT DATA AVAILABLE OR OUTPUT DEVICE READY
;
IOHDLR:
; SAVE IOCB ADDRESS AND DATA (IF ANY)
;
STX IOCBA ; SAVE IOCB ADDRESS
STA BDATA ; SAVE DATA BYTE FOR WRITE 1 BYTE
;
; INITIALIZE STATUS BYTE TO INDICATE NO ERRORS
;
LDA #NOERR ; STATUS = NO ERRORS
STA IOCBST,X ; SAVE STATUS IN IOCB
;
; CHECK FOR VALID OPERATION NUMBER (WITHIN LIMIT)
;
LDB IOCBOP,X ; GET OPERATION NUMBER FROM IOCB
CMPB #NUMOP ; IS OPERATION NUMBER WITHIN LIMIT?
BCC BADOP ; JUMP IF OPERATION NUMBER TOO LARGE
;
; SEARCH DEVICE LIST FOR THIS DEVICE
;
LDA IOCBDN,X ; GET IOCB DEVICE NUMBER
LDX DVLST ; GET FIRST ENTRY IN DEVICE LIST
;
; X = POINTER TO DEVICE LIST
; B = OPERATION NUMBER
; A = REQUESTED DEVICE NUMBER
;
SRCHLP:
; CHECK IF AT END OF DEVICE LIST
; (LINK FIELD = 0000)
CMPX #0 ; TEST LINK FIELD
BEQ BADDN ; BRANCH IF NO MORE DEVICE ENTRIES
;
; CHECK IF CURRENT ENTRY IS DEVICE IN IDCB
;
CMPA DTDN,X ; COMPARE DEVICE NUMBER, REQUESTED DEVICE
BEQ FOUND ; BRANCH IF DEVICE FOUND
;
; DEVICE NOT FOUND, SO ADVANCE TO NEXT DEVICE
; TABLE ENTRY THROUGH LINK FIELD
; MAKE CURRENT DEVICE = LINK
;
LDX ,X ; CURRENT ENTRY = LINK
BRA SRCHLP ; CHECK NEXT ENTRY IN DEVICE TABLE
;
; FOUND DEVICE, SO VECTOR TO APPROPRIATE ROUTINE IF ANY
;
; B = OPERATION NUMBER IN IOCB
;
FOUND:
; GET ROUTINE ADDRESS (ZERO INDICATES INVALID OPERATION)
;
ASLB ; MULTIPLY OPERATION NUMBER TIMES 2 TO
; INDEX INTO TABLE OF ADDRESSES
ADDB #DTSR ; ADD OFFSET TO START OF SUBROUTINE
; ADDRESSES
LDX B,X ; GET SUBROUTINE ADDRESS
BEQ BADOP ; JUMP IF OPERATION INVALID (ADDRESS = 0)
PSHS X ; SAVE SUBROUTINE ADDRESS ON STACK
LDA BDATA ; A = DATA BYTE FOR WRITE 1 BYTE
LDX IOCBA ; GET BASE ADDRESS OF IOCB
RTS ; GOTO SUBROUTINE
;
BADDN:
LDA #DEVERR ; ERROR CODE - NO SUCH DEVICE
BRA EREXIT
BADOP: LDA #OPERR ; ERROR CODE - NO SUCH OPERATION
EREXIT:
LDX IOCBA ; POINT TO IOCB
STA IOCBST,X ; SET STATUS BYTE IN IOCB
RTS
;
;
; **************************************
; ROUTINE: INITDL
; PURPOSE: INITIALIZE DEVICE LIST TO EMPTY
; ENTRY: NONE
; EXIT: DEVICE LIST SET TO NO ITEMS
; REGISTERS USED: X
;
; ****************************************
INITDL:
; INITIALIZE DEVICE LIST HEADER TO 0 TO INDICATE NO DEVICES
LDX #0 ; HEADER = 0 (EMPTY LIST)
STX DVLST
RTS
;
; *****************************************
; ROUTINE: INSDL
; PURPOSE: INSERT DEVICE INTO DEVICE LIST
; ENTRY: REGISTER X = ADDRESS OF DEVICE TABLE ENTRY
; EXIT: DEVICE INSERTED INTO DEVICE LIST
; REGISTERS USED:
;
; *******************************************
INSDL:
LDU DVLST ; GET CURRENT HEAD OF DEVICE LIST
STU ,X ; STORE CURRENT HEAD OF DEVICE LIST
STX DVLST ; MAKE DVLST POINT TO NEW DEVICE
RTS
;
; DATA SECTION
;
IOCBA: RMB 2 ; BASE ADDRESS OF IOCB
DVLST: RMB 2 ; DEVICE LIST HEADER
BDATA: RMB 1 ; DATA BYTE FOR WRITE 1 BYTE
;
; SAMPLE EXECUTION:
;
; CHARACTER EQUATES
CR EQU $0D ; CARRIAGE RETURN CHARACTER
LF EQU $0A ; LINE FEED CHARACTER
;
; INITIALIZE DEVICE LIST
;
SC8E:
JSR INITDL ; CREATE EMPTY DEVICE LIST
;
; SET UP CONSOLE AS DEVICE 1 AND INITIALIZE IT
;
LDX #CONDV ; POINT TO CONSOLE DEVICE ENTRY
JSR INSDL ; ADD CONSOLE TO DEVICE LIST
LDA #INIT ; INITIALIZE OPERATION
STA IOCBOP,X
LDA #1 ; DEVICE NUMBER = 1
STA IOCBDN,X
LDX #IOCB ; INITIALIZE CONSOLE
JSR IOHDLR
;
; SET UP PRINTER AS DEVICE 2 AND INITIALIZE IT
;
LDX #PRTDV ; POINT TO PRINTER DEVICE ENTRY
JSR INSDL ; ADD PRINTER TO DEVICE LIST
LDA #INIT ; INITIALIZE OPERATION
STA IOCBOP,X
LDA #2 ; DEVICE NUMBER = 2
STA IOCBDN,X
LDX #IOCB ; INITIALIZE PRINTER
JSR IOHDLR
;
; LOOP READING LINES FROM CONSOLE, AND ECHOING THEM TO
; THE CONSOLE AND PRINTER UNTIL A BLANK LINE IS ENTERED
TSTLP:
LDX #IOCB ; POINT TO IOCB
LDY #BUFFER ; POINT TO BUFFER
STY IOCBBA,X ; SAVE BUFFER ADDRESS IN IOCB
LDA #1 ; DEVICE NUMBER = 1 (CONSOLE)
STA IOCBDN,X
LDA #RNBYTE ; OPERATION IS READ N BYTES
STA IOCBOP,X
LDY #LENBUF
STY IOCBBL,X ; SET BUFFER LENGTH TO LENBUF
JSR IOHDLR ; READ LINE FROM CONSOLE
;
; STOP IF LINE LENGTH IS 0
;
LDX #IOCB ; POINT TO IOCB
LDY IOCBBL,X ; GET LINE LENGTH
BEQ SC8END ; BRANCH (EXIT) IF LINE LENGTH IS 0
;
; SEND CARRIAGE RETURN TO CONSOLE
;
LDA #W1BYTE ; OPERATION IS WRITE 1 BYTE
STA IOCBOP,X ; SAVE IN IOCB
LDA #CR ; CHARACTER IS CARRIAGE RETURN
JSR IOHDLR ; WRITE 1 BYTE (LINE FEED)
;
; ECHO LINE TO CONSOLE
;
LDX #IOCB ; POINT TO IOCB
LDA #WNBYTE ; OPERATION = WRITE N BYTES
STA IOCBOP ; SAVE OPERATION NUMBER IN IOCB
LDA #1 ; DEVICE NUMBER = CONSOLE
STA IOCBDN ; SAVE DEVICE NUMBER IN IOCB
JSR IOHDLR ; WRITE N BYTES ON CONSOLE
;
; ECHO LINE TO PRINTER
;
LDX #IOCB ; POINT TO IOCB
LDA #WNBYTE ; OPERATION = WRITE N BYTES
STA IOCBOP ; SAVE OPERATION NUMBER IN IOCB
LDA #2 ; DEVICE NUMBER = PRINTER
STA IOCBDN ; SAVE DEVICE NUMBER IN IOCB
JSR IOHDLR ; WRITE N BYTES ON PRINTER
;
; SEND LINE FEED TO PRINTER
;
LDX #IOCB ; POINT TO IOCB
LDA #W1BYTE ; OPERATION = WRITE 1 BYTE
STA IOCBOP,X ; SAVE OPERATION NUMBER IN IOCB
LDA #LF ; CHARACTER IS LINE FEED
JSR IOHDLR ; SEND TO PRINTER
;
BRA TSTLP ; LOOP TO READ NEXT LINE
SC8END:
BRA SC8E ; REPEAT TEST
;
; DATA SECTION
;
LENBUF EQU 127 ; I/O BUFFER LENGTH
BUFFER RMB LENBUF ; I/O BUFFER
;
; IOCB FOR PERFORMING IO
;
IOCB:
RMB 1 ; DEVICE NUMBER
RMB 1 ; OPERATION NUMBER
RMB 1 ; STATUS
FDB BUFFER ; BUFFER ADDRESS
RMB 2 ; BUFFER LENGTH
;
; DEVICE TABLE ENTRIES
;
CONDV:
FDB 0 ; LINK FIELD
FCB 1 ; DEVICE 1
FDB CINIT ; CONSOLE INITIALIZE
FDB 0 ; NO CONSOLE INPUT STATUS
FDB 0 ; NO CONSOLE INPUT 1 BYTE
FDB CINN ; CONSOLE INPUT N BYTES
FDB 0 ; NO CONSOLE OUTPUT STATUS
FDB COUT ; CONSOLE OUTPUT 1 BYTE
FDB COUTN ; CONSOLE OUTPUT N BYTES
;
PRTDV:
FDB 0 ; LINK FIELD
FCB 2 ; DEVICE 2
FDB PINIT ; PRINTER INITIALIZE
FDB 0 ; NO PRINTER INPUT STATUS
FDB 0 ; NO PRINTER INPUT 1 BYTE
FDB 0 ; NO PRINTER INPUT N BYTES
FDB 0 ; NO PRINTER OUTPUT STATUS
FDB POUT ; PRINTER OUTPUT 1 BYTE
FDB POUTN ; PRINTER OUTPUT N BYTES
;
; RADIO SHACK COLOR COMPUTER EQUATES
;
BDRATE EQU $0096 ; MEMORY LOCATION CONTAINING OUTPUT
; BAUD RATE
B2400 EQU 18 ; VALUE CORRESPONDING TO 2400 BAUD
CLRSCN EQU $A928 ; STARTING ADDRESS FOR ROUTINE
; THAT CLEARS SCREEN
KBDPTR EQU $A000 ; POINTER TO KEYBOARD INPUT ROUTINE
; (CHARACTER ENDS UP IN REGISTER A)
; ZERO FLAG = 1 IF NO CHARACTER,
; 0 IF CHARACTER
OUTPTR EQU $A002 ; POINTER TO OUTPUT ROUTINE
; UNIT NUMBER GOES IN LOCATION (0 = SCREEN)
; CHARACTER GOES IN REGISTER A
PRDVNO EQU $FE ; PRINTER DEVICE NUMBER
UNITNO EQU $006F ; MEMORY LOCATION CONTAINING UNIT
; NUMBER FOR OUTPUT ROUTINE
; (0 = SCREEN)
;
; ***********************************
; CONSOLE I/O ROUTINES
; ***********************************
; CONSOLE INITIALIZE
;
CINIT:
JSR CLRSCN ; CLEAR SCREEN RTS RETURN
; CONSOLE READ 1 BYTE
CINN:
LDU IOCBBL,X ; GET BUFFER LENGTH
PSHS U ; SAVE BUFFER LENGTH IN STACK
LDU IOCBBA,X ; POINT TO DATA BUFFER
LDY #0 ; INITIALIZE BYTE COUNTER TO 0
;
; LOOP READING BYTES UNTIL DATA BUFFER IS FULL
;
CIN:
JSR [KBDPTR] ; POLL KEYBOARD
BEQ CIN ; LOOP UNTIL A KEY IS READ
CMPA #CR ; CHECK FOR CARRIAGE RETURN
BEQ CREXIT ; BRANCH (EXIT) IF CARRIAGE RETURN
STA ,U+ ; SAVE BYTE IN DATA BUFFER
LEAY 1,Y ; INCREMENT BYTE COUNT
CMPY ,S ; CHECK IF BUFFER FULL
BNE CIN ; BRANCH (LOOP) IF BUFFER NOT FULL
;
; CLEAN STACK AND EXIT
;
CREXIT:
STY IOCBBL,X ; SAVE NUMBER OF BYTES READ
LEAS 2,S ; CLEAN STACK
RTS ; EXIT
;
; CONSOLE WRITE 1 BYTE
;
COUT:
CLR UNITNO ; SET UNIT NUMBER FOR CONSOLE (0)
JSR [OUTPTR] ; WRITE BYTE
RTS
;
; CONSOLE WRITE N BYTES
;
COUTN:
CLR UNITNO ; SET UNIT NUMBER FOR CONSOLE (0)
OUTPUT:
LDY IOCBBL,X ; GET NUMBER OF BYTES TO WRITE
LDA IOCBBA,X ; POINT TO DATA BUFFER
CWLOOP:
LDA ,X+ ; GET NEXT DATA BYTE
JSR [OUTPTR] ; WRITE BYTE
LEAY -1,Y ; DECREMENT BYTE COUNT
BNE CWLOOP ; CONTINUE THROUGH N BYTES
RTS ; RETURN
; **************************************
; PRINTER ROUTINES
; **************************************
; PRINTER INITIALIZE
PINIT:
LDB #B2400 ; SET PRINTER TO 2400 BAUD
STB BDRATE ; SAVE BAUD RATE
RTS
; PRINTER OUTPUT 1 BYTE
POUT:
LDB #PRDVNO ; GET PRINTER DEVICE NUMBER
STB UNITNO ; SAVE AS UNIT NUMBER
JSR [OUTPTR] ; WRITE 1 BYTE
CLR UNITNO ; RESTORE UNIT NUMBER TO CONSOLE (0)
RTS
; PRINTER OUTPUT N BYTES
POUTN:
LDB #PRDVNO ; GET PRINTER DEVICE NUMBER
STB UNITNO ; SAVE AS UNIT NUMBER
JSR OUTPUT ; WRITE LINE
CLR UNITNO ; RESTORE UNIT NUMBER TO CONSOLE (0)
RTS
END