]> git.sur5r.net Git - cc65/blob - libsrc/cbm610/ser/cbm610-std.s
Fixed _textcolor definition.
[cc65] / libsrc / cbm610 / ser / cbm610-std.s
1 ;
2 ; Serial driver for the builtin 6551 ACIA of the Commodore 610.
3 ;
4 ; Ullrich von Bassewitz, 2003-12-18
5 ;
6 ; The driver is based on the cc65 rs232 module, which in turn is based on
7 ; Craig Bruce device driver for the Switftlink/Turbo-232.
8 ;
9 ; SwiftLink/Turbo-232 v0.90 device driver, by Craig Bruce, 14-Apr-1998.
10 ;
11 ; This software is Public Domain.  It is in Buddy assembler format.
12 ;
13 ; This device driver uses the SwiftLink RS-232 Serial Cartridge, available from
14 ; Creative Micro Designs, Inc, and also supports the extensions of the Turbo232
15 ; Serial Cartridge.  Both devices are based on the 6551 ACIA chip.  It also
16 ; supports the "hacked" SwiftLink with a 1.8432 MHz crystal.
17 ;
18 ; The code assumes that the kernal + I/O are in context.  On the C128, call
19 ; it from Bank 15.  On the C64, don't flip out the Kernal unless a suitable
20 ; NMI catcher is put into the RAM under then Kernal.  For the SuperCPU, the
21 ; interrupt handling assumes that the 65816 is in 6502-emulation mode.
22 ;
23
24         .include        "zeropage.inc"
25         .include        "../extzp.inc"
26         .include        "ser-kernel.inc"
27         .include        "ser-error.inc"
28         .include        "cbm610.inc"
29
30         .macpack        module
31
32
33 ; ------------------------------------------------------------------------
34 ; Header. Includes jump table
35
36         module_header   _cbm610_std_ser
37
38 ; Driver signature
39
40         .byte   $73, $65, $72           ; "ser"
41         .byte   SER_API_VERSION         ; Serial API version number
42
43 ; Library reference
44
45         .addr   $0000
46
47 ; Jump table
48
49         .word   SER_INSTALL
50         .word   SER_UNINSTALL
51         .word   SER_OPEN
52         .word   SER_CLOSE
53         .word   SER_GET
54         .word   SER_PUT
55         .word   SER_STATUS
56         .word   SER_IOCTL
57         .word   SER_IRQ
58
59 ;----------------------------------------------------------------------------
60 ;
61 ; Global variables
62 ;
63
64 .bss
65 RecvHead:       .res    1       ; Head of receive buffer
66 RecvTail:       .res    1       ; Tail of receive buffer
67 RecvFreeCnt:    .res    1       ; Number of bytes in receive buffer
68 SendHead:       .res    1       ; Head of send buffer
69 SendTail:       .res    1       ; Tail of send buffer
70 SendFreeCnt:    .res    1       ; Number of bytes in send buffer
71
72 Stopped:        .res    1       ; Flow-stopped flag
73 RtsOff:         .res    1       ;
74
75 ; Send and receive buffers: 256 bytes each
76 RecvBuf:        .res    256
77 SendBuf:        .res    256
78
79 .rodata
80
81 ; Tables used to translate RS232 params into register values
82
83 BaudTable:                      ; bit7 = 1 means setting is invalid
84         .byte   $FF             ; SER_BAUD_45_5
85         .byte   $01             ; SER_BAUD_50
86         .byte   $02             ; SER_BAUD_75
87         .byte   $03             ; SER_BAUD_110
88         .byte   $04             ; SER_BAUD_134_5
89         .byte   $05             ; SER_BAUD_150
90         .byte   $06             ; SER_BAUD_300
91         .byte   $07             ; SER_BAUD_600
92         .byte   $08             ; SER_BAUD_1200
93         .byte   $09             ; SER_BAUD_1800
94         .byte   $0A             ; SER_BAUD_2400
95         .byte   $0B             ; SER_BAUD_3600
96         .byte   $0C             ; SER_BAUD_4800
97         .byte   $0D             ; SER_BAUD_7200
98         .byte   $0E             ; SER_BAUD_9600
99         .byte   $0F             ; SER_BAUD_19200
100         .byte   $FF             ; SER_BAUD_38400
101         .byte   $FF             ; SER_BAUD_57600
102         .byte   $FF             ; SER_BAUD_115200
103         .byte   $FF             ; SER_BAUD_230400
104
105 BitTable:
106         .byte   $60             ; SER_BITS_5
107         .byte   $40             ; SER_BITS_6
108         .byte   $20             ; SER_BITS_7
109         .byte   $00             ; SER_BITS_8
110
111 StopTable:
112         .byte   $00             ; SER_STOP_1
113         .byte   $80             ; SER_STOP_2
114
115 ParityTable:
116         .byte   $00             ; SER_PAR_NONE
117         .byte   $20             ; SER_PAR_ODD
118         .byte   $60             ; SER_PAR_EVEN
119         .byte   $A0             ; SER_PAR_MARK
120         .byte   $E0             ; SER_PAR_SPACE
121
122 .code
123
124 ;----------------------------------------------------------------------------
125 ; SER_INSTALL routine. Is called after the driver is loaded into memory. If
126 ; possible, check if the hardware is present.
127 ; Must return an SER_ERR_xx code in a/x.
128 ;
129 ; Since we don't have to manage the IRQ vector on the Plus/4, this is actually
130 ; the same as:
131 ;
132 ; SER_UNINSTALL routine. Is called before the driver is removed from memory.
133 ; Must return an SER_ERR_xx code in a/x.
134 ;
135 ; and:
136 ;
137 ; SER_CLOSE: Close the port, disable interrupts and flush the buffer. Called
138 ; without parameters. Must return an error code in a/x.
139 ;
140
141 SER_INSTALL:
142 SER_UNINSTALL:
143 SER_CLOSE:
144
145 ; Deactivate DTR and disable 6551 interrupts
146
147         lda     #%00001010
148         jsr     write_cmd
149
150 ; Done, return an error code
151
152         lda     #<SER_ERR_OK
153         tax                     ; A is zero
154         rts
155
156 ;----------------------------------------------------------------------------
157 ; PARAMS routine. A pointer to a ser_params structure is passed in ptr1.
158 ; Must return an SER_ERR_xx code in a/x.
159
160 SER_OPEN:
161
162 ; Check if the handshake setting is valid
163
164         ldy     #SER_PARAMS::HANDSHAKE  ; Handshake
165         lda     (ptr1),y
166         cmp     #SER_HS_HW              ; This is all we support
167         bne     InvParam
168
169 ; Initialize buffers
170
171         ldx     #0
172         stx     Stopped
173         stx     RecvHead
174         stx     RecvTail
175         stx     SendHead
176         stx     SendTail
177         dex                             ; X = 255
178         stx     RecvFreeCnt
179         stx     SendFreeCnt
180
181 ; Set the value for the control register, which contains stop bits, word
182 ; length and the baud rate.
183
184         ldy     #SER_PARAMS::BAUDRATE
185         lda     (ptr1),y                ; Baudrate index
186         tay
187         lda     BaudTable,y             ; Get 6551 value
188         bmi     InvBaud                 ; Branch if rate not supported
189         sta     tmp1
190
191         ldy     #SER_PARAMS::DATABITS   ; Databits
192         lda     (ptr1),y
193         tay
194         lda     BitTable,y
195         ora     tmp1
196         sta     tmp1
197
198         ldy     #SER_PARAMS::STOPBITS   ; Stopbits
199         lda     (ptr1),y
200         tay
201         lda     StopTable,y
202         ora     tmp1
203         ora     #%00010000              ; Receiver clock source = baudrate
204         ldy     #ACIA::CTRL
205         jsr     write
206
207 ; Set the value for the command register. We remember the base value in
208 ; RtsOff, since we will have to manipulate ACIA_CMD often.
209
210         ldy     #SER_PARAMS::PARITY     ; Parity
211         lda     (ptr1),y
212         tay
213         lda     ParityTable,y
214         ora     #%00000001              ; DTR active
215         sta     RtsOff
216         ora     #%00001000              ; Enable receive interrupts
217         jsr     write_cmd
218
219 ; Done
220
221         lda     #<SER_ERR_OK
222         tax                             ; A is zero
223         rts
224
225 ; Invalid parameter
226
227 InvParam:
228         lda     #<SER_ERR_INIT_FAILED
229         ldx     #>SER_ERR_INIT_FAILED
230         rts
231
232 ; Baud rate not available
233
234 InvBaud:
235         lda     #<SER_ERR_BAUD_UNAVAIL
236         ldx     #>SER_ERR_BAUD_UNAVAIL
237         rts
238
239 ;----------------------------------------------------------------------------
240 ; SER_GET: Will fetch a character from the receive buffer and store it into the
241 ; variable pointer to by ptr1. If no data is available, SER_ERR_NO_DATA is
242 ; return.
243 ;
244
245 SER_GET:
246         ldx     SendFreeCnt             ; Send data if necessary
247         inx                             ; X == $FF?
248         beq     @L1
249         lda     #$00
250         jsr     TryToSend
251
252 ; Check for buffer empty
253
254 @L1:    lda     RecvFreeCnt
255         cmp     #$ff
256         bne     @L2
257         lda     #<SER_ERR_NO_DATA
258         ldx     #>SER_ERR_NO_DATA
259         rts
260
261 ; Check for flow stopped & enough free: release flow control
262
263 @L2:    ldx     Stopped
264         beq     @L3
265         cmp     #63
266         bcc     @L3
267         lda     #$00
268         sta     Stopped
269         lda     RtsOff
270         ora     #%00001000
271         jsr     write_cmd
272
273 ; Get byte from buffer
274
275 @L3:    ldx     RecvHead
276         lda     RecvBuf,x
277         inc     RecvHead
278         inc     RecvFreeCnt
279         ldx     #$00
280         sta     (ptr1,x)
281         txa                             ; Return code = 0
282         rts
283
284 ;----------------------------------------------------------------------------
285 ; SER_PUT: Output character in A.
286 ; Must return an error code in a/x.
287 ;
288
289 SER_PUT:
290
291 ; Try to send
292
293         ldx     SendFreeCnt
294         inx                             ; X = $ff?
295         beq     @L2
296         pha
297         lda     #$00
298         jsr     TryToSend
299         pla
300
301 ; Put byte into send buffer & send
302
303 @L2:    ldx     SendFreeCnt
304         bne     @L3
305         lda     #<SER_ERR_OVERFLOW      ; X is already zero
306         rts
307
308 @L3:    ldx     SendTail
309         sta     SendBuf,x
310         inc     SendTail
311         dec     SendFreeCnt
312         lda     #$ff
313         jsr     TryToSend
314         lda     #<SER_ERR_OK
315         tax
316         rts
317
318 ;----------------------------------------------------------------------------
319 ; SER_STATUS: Return the status in the variable pointed to by ptr1.
320 ; Must return an error code in a/x.
321 ;
322
323 SER_STATUS:
324         lda     #$0F
325         sta     IndReg
326         ldy     #ACIA::STATUS
327         lda     (acia),y
328         ldx     #0
329         sta     (ptr1,x)
330         lda     IndReg
331         sta     ExecReg
332         txa                             ; SER_ERR_OK
333         rts
334
335 ;----------------------------------------------------------------------------
336 ; SER_IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
337 ; specific data in ptr1, and the ioctl code in A.
338 ; Must return an error code in a/x.
339 ;
340
341 SER_IOCTL:
342         lda     #<SER_ERR_INV_IOCTL     ; We don't support ioclts for now
343         ldx     #>SER_ERR_INV_IOCTL
344         rts
345
346 ;----------------------------------------------------------------------------
347 ; SER_IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
348 ; registers are already save, no parameters are passed, but the carry flag
349 ; is clear on entry. The routine must return with carry set if the interrupt
350 ; was handled, otherwise with carry clear.
351 ;
352
353 SER_IRQ:
354         lda     #$0F
355         sta     IndReg          ; Switch to the system bank
356         ldy     #ACIA::STATUS
357         lda     (acia),y        ; Check ACIA status for receive interrupt
358         and     #$08
359         beq     @L9             ; Jump if no ACIA interrupt (carry still clear)
360         ldy     #ACIA::DATA
361         lda     (acia),y        ; Get byte from ACIA
362         ldx     RecvFreeCnt     ; Check if we have free space left
363         beq     @L1             ; Jump if no space in receive buffer
364         ldy     RecvTail        ; Load buffer pointer
365         sta     RecvBuf,y       ; Store received byte in buffer
366         inc     RecvTail        ; Increment buffer pointer
367         dec     RecvFreeCnt     ; Decrement free space counter
368         cpx     #33             ; Check for buffer space low
369         bcs     @L9             ; Assert flow control if buffer space low
370
371 ; Assert flow control if buffer space too low
372
373 @L1:    lda     RtsOff
374         ldy     #ACIA::CMD
375         sta     (acia),y
376         sta     Stopped
377         sec                     ; Interrupt handled
378
379 ; Done, switch back to the execution segment
380
381 @L9:    lda     ExecReg
382         sta     IndReg
383         rts
384
385 ;----------------------------------------------------------------------------
386 ; Try to send a byte. Internal routine. A = TryHard
387
388 .proc   TryToSend
389
390         sta     tmp1            ; Remember tryHard flag
391         lda     #$0F
392         sta     IndReg          ; Switch to the system bank
393 @L0:    lda     SendFreeCnt
394         cmp     #$ff
395         beq     @L3             ; Bail out
396
397 ; Check for flow stopped
398
399 @L1:    lda     Stopped
400         bne     @L3             ; Bail out
401
402 ; Check that swiftlink is ready to send
403
404 @L2:    ldy     #ACIA::STATUS
405         lda     (acia),y
406         and     #$10
407         bne     @L4
408         bit     tmp1            ; Keep trying if must try hard
409         bmi     @L0
410
411 ; Switch back the bank and return
412
413 @L3:    lda     ExecReg
414         sta     IndReg
415         rts
416
417 ; Send byte and try again
418
419 @L4:    ldx     SendHead
420         lda     SendBuf,x
421         ldy     #ACIA::DATA
422         sta     (acia),y
423         inc     SendHead
424         inc     SendFreeCnt
425         jmp     @L0
426
427 .endproc
428
429
430 ;----------------------------------------------------------------------------
431 ; Write to the ACIA changing the indirect segment. Offset is in Y, value in A.
432
433 write_cmd:
434         ldy     #ACIA::CMD
435 write:  pha
436         lda     #$0F
437         sta     IndReg
438         pla
439         sta     (acia),y
440         lda     ExecReg
441         sta     IndReg
442         rts