blob: 7364380327687d120f48c191453671639068559d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001;.lib "axm"
2;
3;begin
4;title "A2232 serial board driver"
5;
6;set modules "2232"
7;set executable "2232.bin"
8;
9;;;;set nolink
10;
11;set temporary directory "t:"
12;
13;set assembly options "-m6502 -l60:t:list"
14;set link options "bin"; loadadr"
15;;;bin2c 2232.bin msc6502.h msc6502code
16;end
17;
18;
19; ### Commodore A2232 serial board driver for NetBSD by JM v1.3 ###
20;
21; - Created 950501 by JM -
22;
23;
24; Serial board driver software.
25;
26;
27% Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>.
28% All rights reserved.
29%
30% Redistribution and use in source and binary forms, with or without
31% modification, are permitted provided that the following conditions
32% are met:
33% 1. Redistributions of source code must retain the above copyright
34% notice, and the entire permission notice in its entirety,
35% including the disclaimer of warranties.
36% 2. Redistributions in binary form must reproduce the above copyright
37% notice, this list of conditions and the following disclaimer in the
38% documentation and/or other materials provided with the distribution.
39% 3. The name of the author may not be used to endorse or promote
40% products derived from this software without specific prior
41% written permission.
42%
43% ALTERNATIVELY, this product may be distributed under the terms of
44% the GNU General Public License, in which case the provisions of the
45% GPL are required INSTEAD OF the above restrictions. (This clause is
46% necessary due to a potential bad interaction between the GPL and
47% the restrictions contained in a BSD-style copyright.)
48%
49% THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
50% WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51% OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
52% DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
53% INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
54% (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
55% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
57% STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
58% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
59% OF THE POSSIBILITY OF SUCH DAMAGE.
60;
61;
62; Bugs:
63;
64; - Can't send a break yet
65;
66;
67;
68; Edited:
69;
70; - 950501 by JM -> v0.1 - Created this file.
71; - 951029 by JM -> v1.3 - Carrier Detect events now queued in a separate
72; queue.
73;
74;
75
76
77CODE equ $3800 ; start address for program code
78
79
80CTL_CHAR equ $00 ; byte in ibuf is a character
81CTL_EVENT equ $01 ; byte in ibuf is an event
82
83EVENT_BREAK equ $01
84EVENT_CDON equ $02
85EVENT_CDOFF equ $03
86EVENT_SYNC equ $04
87
88XON equ $11
89XOFF equ $13
90
91
92VARBASE macro *starting_address ; was VARINIT
93_varbase set \1
94 endm
95
96VARDEF macro *name space_needs
97\1 equ _varbase
98_varbase set _varbase+\2
99 endm
100
101
102stz macro * address
103 db $64,\1
104 endm
105
106stzax macro * address
107 db $9e,<\1,>\1
108 endm
109
110
111biti macro * immediate value
112 db $89,\1
113 endm
114
115smb0 macro * address
116 db $87,\1
117 endm
118smb1 macro * address
119 db $97,\1
120 endm
121smb2 macro * address
122 db $a7,\1
123 endm
124smb3 macro * address
125 db $b7,\1
126 endm
127smb4 macro * address
128 db $c7,\1
129 endm
130smb5 macro * address
131 db $d7,\1
132 endm
133smb6 macro * address
134 db $e7,\1
135 endm
136smb7 macro * address
137 db $f7,\1
138 endm
139
140
141
142;-----------------------------------------------------------------------;
143; ;
144; stuff common for all ports, non-critical (run once / loop) ;
145; ;
146DO_SLOW macro * port_number ;
147 .local ; ;
148 lda CIA+C_PA ; check all CD inputs ;
149 cmp CommonCDo ; changed from previous accptd? ;
150 beq =over ; nope, do nothing else here ;
151 ; ;
152 cmp CommonCDb ; bouncing? ;
153 beq =nobounce ; nope -> ;
154 ; ;
155 sta CommonCDb ; save current state ;
156 lda #64 ; reinitialize counter ;
157 sta CommonCDc ; ;
158 jmp =over ; skip CD save ;
159 ; ;
160=nobounce dec CommonCDc ; no, decrement bounce counter ;
161 bpl =over ; not done yet, so skip CD save ;
162 ; ;
163=saveCD ldx CDHead ; get write index ;
164 sta cdbuf,x ; save status in buffer ;
165 inx ; ;
166 cpx CDTail ; buffer full? ;
167 .if ne ; no: preserve status: ;
168 stx CDHead ; update index in RAM ;
169 sta CommonCDo ; save state for the next check ;
170 .end ; ;
171=over .end local ;
172 endm ;
173 ;
174;-----------------------------------------------------------------------;
175
176
177; port specific stuff (no data transfer)
178
179DO_PORT macro * port_number
180 .local ; ;
181 lda SetUp\1 ; reconfiguration request? ;
182 .if ne ; yes: ;
183 lda SoftFlow\1 ; get XON/XOFF flag ;
184 sta XonOff\1 ; save it ;
185 lda Param\1 ; get parameter ;
186 ora #%00010000 ; use baud generator for Rx ;
187 sta ACIA\1+A_CTRL ; store in control register ;
188 stz OutDisable\1 ; enable transmit output ;
189 stz SetUp\1 ; no reconfiguration no more ;
190 .end ; ;
191 ; ;
192 lda InHead\1 ; get write index ;
193 sbc InTail\1 ; buffer full soon? ;
194 cmp #200 ; 200 chars or more in buffer? ;
195 lda Command\1 ; get Command reg value ;
196 and #%11110011 ; turn RTS OFF by default ;
197 .if cc ; still room in buffer: ;
198 ora #%00001000 ; turn RTS ON ;
199 .end ; ;
200 sta ACIA\1+A_CMD ; set/clear RTS ;
201 ; ;
202 lda OutFlush\1 ; request to flush output buffer;
203 .if ne ; yessh! ;
204 lda OutHead\1 ; get head ;
205 sta OutTail\1 ; save as tail ;
206 stz OutDisable\1 ; enable transmit output ;
207 stz OutFlush\1 ; clear request ;
208 .end
209 .end local
210 endm
211
212
213DO_DATA macro * port number
214 .local
215 lda ACIA\1+A_SR ; read ACIA status register ;
216 biti [1<<3] ; something received? ;
217 .if ne ; yes: ;
218 biti [1<<1] ; framing error? ;
219 .if ne ; yes: ;
220 lda ACIA\1+A_DATA ; read received character ;
221 bne =SEND ; not break -> ignore it ;
222 ldx InHead\1 ; get write pointer ;
223 lda #CTL_EVENT ; get type of byte ;
224 sta ictl\1,x ; save it in InCtl buffer ;
225 lda #EVENT_BREAK ; event code ;
226 sta ibuf\1,x ; save it as well ;
227 inx ; ;
228 cpx InTail\1 ; still room in buffer? ;
229 .if ne ; absolutely: ;
230 stx InHead\1 ; update index in memory ;
231 .end ; ;
232 jmp =SEND ; go check if anything to send ;
233 .end ; ;
234 ; normal char received: ;
235 ldx InHead\1 ; get write index ;
236 lda ACIA\1+A_DATA ; read received character ;
237 sta ibuf\1,x ; save char in buffer ;
238 stzax ictl\1 ; set type to CTL_CHAR ;
239 inx ; ;
240 cpx InTail\1 ; buffer full? ;
241 .if ne ; no: preserve character: ;
242 stx InHead\1 ; update index in RAM ;
243 .end ; ;
244 and #$7f ; mask off parity if any ;
245 cmp #XOFF ; XOFF from remote host? ;
246 .if eq ; yes: ;
247 lda XonOff\1 ; if XON/XOFF handshaking.. ;
248 sta OutDisable\1 ; ..disable transmitter ;
249 .end ; ;
250 .end ; ;
251 ; ;
252 ; BUFFER FULL CHECK WAS HERE ;
253 ; ;
254=SEND lda ACIA\1+A_SR ; transmit register empty? ;
255 and #[1<<4] ; ;
256 .if ne ; yes: ;
257 ldx OutCtrl\1 ; sending out XON/XOFF? ;
258 .if ne ; yes: ;
259 lda CIA+C_PB ; check CTS signal ;
260 and #[1<<\1] ; (for this port only) ;
261 bne =DONE ; not allowed to send -> done ;
262 stx ACIA\1+A_DATA ; transmit control char ;
263 stz OutCtrl\1 ; clear flag ;
264 jmp =DONE ; and we're done ;
265 .end ; ;
266 ; ;
267 ldx OutTail\1 ; anything to transmit? ;
268 cpx OutHead\1 ; ;
269 .if ne ; yes: ;
270 lda OutDisable\1 ; allowed to transmit? ;
271 .if eq ; yes: ;
272 lda CIA+C_PB ; check CTS signal ;
273 and #[1<<\1] ; (for this port only) ;
274 bne =DONE ; not allowed to send -> done ;
275 lda obuf\1,x ; get a char from buffer ;
276 sta ACIA\1+A_DATA ; send it away ;
277 inc OutTail\1 ; update read index ;
278 .end ; ;
279 .end ; ;
280 .end ; ;
281=DONE .end local
282 endm
283
284
285
286PORTVAR macro * port number
287 VARDEF InHead\1 1
288 VARDEF InTail\1 1
289 VARDEF OutDisable\1 1
290 VARDEF OutHead\1 1
291 VARDEF OutTail\1 1
292 VARDEF OutCtrl\1 1
293 VARDEF OutFlush\1 1
294 VARDEF SetUp\1 1
295 VARDEF Param\1 1
296 VARDEF Command\1 1
297 VARDEF SoftFlow\1 1
298 ; private:
299 VARDEF XonOff\1 1
300 endm
301
302
303 VARBASE 0 ; start variables at address $0000
304 PORTVAR 0 ; define variables for port 0
305 PORTVAR 1 ; define variables for port 1
306 PORTVAR 2 ; define variables for port 2
307 PORTVAR 3 ; define variables for port 3
308 PORTVAR 4 ; define variables for port 4
309 PORTVAR 5 ; define variables for port 5
310 PORTVAR 6 ; define variables for port 6
311
312
313
314 VARDEF Crystal 1 ; 0 = unknown, 1 = normal, 2 = turbo
315 VARDEF Pad_a 1
316 VARDEF TimerH 1
317 VARDEF TimerL 1
318 VARDEF CDHead 1
319 VARDEF CDTail 1
320 VARDEF CDStatus 1
321 VARDEF Pad_b 1
322
323 VARDEF CommonCDo 1 ; for carrier detect optimization
324 VARDEF CommonCDc 1 ; for carrier detect debouncing
325 VARDEF CommonCDb 1 ; for carrier detect debouncing
326
327
328 VARBASE $0200
329 VARDEF obuf0 256 ; output data (characters only)
330 VARDEF obuf1 256
331 VARDEF obuf2 256
332 VARDEF obuf3 256
333 VARDEF obuf4 256
334 VARDEF obuf5 256
335 VARDEF obuf6 256
336
337 VARDEF ibuf0 256 ; input data (characters, events etc - see ictl)
338 VARDEF ibuf1 256
339 VARDEF ibuf2 256
340 VARDEF ibuf3 256
341 VARDEF ibuf4 256
342 VARDEF ibuf5 256
343 VARDEF ibuf6 256
344
345 VARDEF ictl0 256 ; input control information (type of data in ibuf)
346 VARDEF ictl1 256
347 VARDEF ictl2 256
348 VARDEF ictl3 256
349 VARDEF ictl4 256
350 VARDEF ictl5 256
351 VARDEF ictl6 256
352
353 VARDEF cdbuf 256 ; CD event queue
354
355
356ACIA0 equ $4400
357ACIA1 equ $4c00
358ACIA2 equ $5400
359ACIA3 equ $5c00
360ACIA4 equ $6400
361ACIA5 equ $6c00
362ACIA6 equ $7400
363
364A_DATA equ $00
365A_SR equ $02
366A_CMD equ $04
367A_CTRL equ $06
368; 00 write transmit data read received data
369; 02 reset ACIA read status register
370; 04 write command register read command register
371; 06 write control register read control register
372
373CIA equ $7c00 ; 8520 CIA
374C_PA equ $00 ; port A data register
375C_PB equ $02 ; port B data register
376C_DDRA equ $04 ; data direction register for port A
377C_DDRB equ $06 ; data direction register for port B
378C_TAL equ $08 ; timer A
379C_TAH equ $0a
380C_TBL equ $0c ; timer B
381C_TBH equ $0e
382C_TODL equ $10 ; TOD LSB
383C_TODM equ $12 ; TOD middle byte
384C_TODH equ $14 ; TOD MSB
385C_DATA equ $18 ; serial data register
386C_INTCTRL equ $1a ; interrupt control register
387C_CTRLA equ $1c ; control register A
388C_CTRLB equ $1e ; control register B
389
390
391
392
393
394 section main,code,CODE-2
395
396 db >CODE,<CODE
397
398;-----------------------------------------------------------------------;
399; here's the initialization code: ;
400; ;
401R_RESET ldx #$ff ;
402 txs ; initialize stack pointer ;
403 cld ; in case a 6502 is used... ;
404 ldx #0 ; ;
405 lda #0 ; ;
406 ldy #Crystal ; this many bytes to clear ;
407clr_loop sta 0,x ; clear zero page variables ;
408 inx ; ;
409 dey ; ;
410 bne clr_loop ; ;
411 ; ;
412 stz CommonCDo ; force CD test at boot ;
413 stz CommonCDb ; ;
414 stz CDHead ; clear queue ;
415 stz CDTail ; ;
416 ; ;
417 lda #0 ; ;
418 sta Pad_a ; ;
419 lda #170 ; test cmp ;
420 cmp #100 ; ;
421 .if cs ; ;
422 inc Pad_a ; C was set ;
423 .end ; ;
424 ;
425;-----------------------------------------------------------------------;
426; Speed check ;
427;-----------------------------------------------------------------------;
428 ;
429 lda Crystal ; speed already set? ;
430 beq DoSpeedy ; ;
431 jmp LOOP ; yes, skip speed test ;
432 ; ;
433DoSpeedy lda #%10011000 ; 8N1, 1200/2400 bps ;
434 sta ACIA0+A_CTRL ; ;
435 lda #%00001011 ; enable DTR ;
436 sta ACIA0+A_CMD ; ;
437 lda ACIA0+A_SR ; read status register ;
438 ; ;
439 lda #%10000000 ; disable all ints (unnecessary);
440 sta CIA+C_INTCTRL ; ;
441 lda #255 ; program the timer ;
442 sta CIA+C_TAL ; ;
443 sta CIA+C_TAH ; ;
444 ; ;
445 ldx #0 ; ;
446 stx ACIA0+A_DATA ; transmit a zero ;
447 nop ; ;
448 nop ; ;
449 lda ACIA0+A_SR ; read status ;
450 nop ; ;
451 nop ; ;
452 stx ACIA0+A_DATA ; transmit a zero ;
453Speedy1 lda ACIA0+A_SR ; read status ;
454 and #[1<<4] ; transmit data reg empty? ;
455 beq Speedy1 ; not yet, wait more ;
456 ; ;
457 lda #%00010001 ; load & start the timer ;
458 stx ACIA0+A_DATA ; transmit one more zero ;
459 sta CIA+C_CTRLA ; ;
460Speedy2 lda ACIA0+A_SR ; read status ;
461 and #[1<<4] ; transmit data reg empty? ;
462 beq Speedy2 ; not yet, wait more ;
463 stx CIA+C_CTRLA ; stop the timer ;
464 ; ;
465 lda CIA+C_TAL ; copy timer value for 68k ;
466 sta TimerL ; ;
467 lda CIA+C_TAH ; ;
468 sta TimerH ; ;
469 cmp #$d0 ; turbo or normal? ;
470 .if cs ; ;
471 lda #2 ; turbo! :-) ;
472 .else ; ;
473 lda #1 ; normal :-( ;
474 .end ; ;
475 sta Crystal ; ;
476 lda #0 ; ;
477 sta ACIA0+A_SR ; ;
478 sta ACIA0+A_CTRL ; reset UART ;
479 sta ACIA0+A_CMD ; ;
480 ;
481 jmp LOOP ;
482 ;
483; ;
484;-----------------------------------------------------------------------;
485; ;
486; The Real Thing: ;
487; ;
488LOOP DO_SLOW ; do non-critical things ;
489 jsr do_input ; check for received data
490 DO_PORT 0
491 jsr do_input
492 DO_PORT 1
493 jsr do_input
494 DO_PORT 2
495 jsr do_input
496 DO_PORT 3
497 jsr do_input
498 DO_PORT 4
499 jsr do_input
500 DO_PORT 5
501 jsr do_input
502 DO_PORT 6
503 jsr do_input
504 jmp LOOP
505
506
507do_input DO_DATA 0
508 DO_DATA 1
509 DO_DATA 2
510 DO_DATA 3
511 DO_DATA 4
512 DO_DATA 5
513 DO_DATA 6
514 rts
515
516
517;-----------------------------------------------------------------------;
518 section vectors,data,$3ffa
519 dw $d0d0
520 dw R_RESET
521 dw $c0ce
522;-----------------------------------------------------------------------;
523
524
525
526 end
527
528
529