From fb09db833e0787ecc4c8cc0a9a1546eccffd7a39 Mon Sep 17 00:00:00 2001 From: cuz Date: Sat, 13 Dec 2003 11:02:48 +0000 Subject: [PATCH] Added C128 swiftlink driver git-svn-id: svn://svn.cc65.org/cc65/trunk@2738 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- libsrc/Makefile | 3 +- libsrc/c128/Makefile | 13 +- libsrc/c128/c128-swlink.s | 492 ++++++++++++++++++++++++++++++++++++++ libsrc/c128/c128.inc | 1 + 4 files changed, 505 insertions(+), 4 deletions(-) create mode 100644 libsrc/c128/c128-swlink.s diff --git a/libsrc/Makefile b/libsrc/Makefile index 8e1995a75..567d3911d 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -123,7 +123,7 @@ c64lib: # C128 c128lib: - for i in c128 cbm common runtime conio dbg em joystick tgi zlib; do \ + for i in c128 cbm common runtime conio dbg em joystick serial tgi zlib; do \ AS=$(AS) \ CC=$(CC) \ LD=$(LD) \ @@ -135,6 +135,7 @@ c128lib: mv c128/crt0.o c128.o cp c128/*.emd . cp c128/*.joy . + cp c128/*.ser . cp c128/c128-640-200-2.tgi c128-vdc.tgi cp c128/c128-640-480-2.tgi c128-vdc2.tgi diff --git a/libsrc/c128/Makefile b/libsrc/c128/Makefile index 2c80aaf57..e8b53bf95 100644 --- a/libsrc/c128/Makefile +++ b/libsrc/c128/Makefile @@ -20,6 +20,9 @@ %.joy: %.o ../runtime/zeropage.o @$(LD) -t module -o $@ $^ +%.ser: %.o ../runtime/zeropage.o + @$(LD) -t module -o $@ $^ + %.tgi: %.o ../runtime/zeropage.o @$(LD) -t module -o $@ $^ @@ -57,6 +60,8 @@ EMDS = c128-georam.emd c128-ram.emd c128-ramcart.emd c128-reu.emd c128-vdc.emd JOYS = c128-ptvjoy.joy c128-stdjoy.joy +SERS = c128-swlink.ser + TGIS = c128-640-200-2.tgi c128-640-480-2.tgi #-------------------------------------------------------------------------- @@ -64,14 +69,16 @@ TGIS = c128-640-200-2.tgi c128-640-480-2.tgi .PHONY: all clean zap -all: $(OBJS) $(EMDS) $(JOYS) $(TGIS) +all: $(OBJS) $(EMDS) $(JOYS) $(SERS) $(TGIS) ../runtime/zeropage.o: $(MAKE) -C $(dir $@) $(notdir $@) clean: - @$(RM) $(OBJS) $(EMDS:.emd=.o) $(JOYS:.joy=.o) $(TGIS:.tgi=.o) + @$(RM) $(OBJS) $(EMDS:.emd=.o) $(JOYS:.joy=.o) $(SERS:.ser=.o) $(TGIS:.tgi=.o) + zap: clean - @$(RM) $(EMDS) $(JOYS) $(TGIS) + @$(RM) $(EMDS) $(JOYS) $(SERS) $(TGIS) + diff --git a/libsrc/c128/c128-swlink.s b/libsrc/c128/c128-swlink.s new file mode 100644 index 000000000..3194cf02d --- /dev/null +++ b/libsrc/c128/c128-swlink.s @@ -0,0 +1,492 @@ +; +; Serial driver for the C128 using a Swiftlink or Turbo-232 cartridge. +; +; Ullrich von Bassewitz, 2003-04-18 +; +; The driver is based on the cc65 rs232 module, which in turn is based on +; Craig Bruce device driver for the Switftlink/Turbo-232. +; +; SwiftLink/Turbo-232 v0.90 device driver, by Craig Bruce, 14-Apr-1998. +; +; This software is Public Domain. It is in Buddy assembler format. +; +; This device driver uses the SwiftLink RS-232 Serial Cartridge, available from +; Creative Micro Designs, Inc, and also supports the extensions of the Turbo232 +; Serial Cartridge. Both devices are based on the 6551 ACIA chip. It also +; supports the "hacked" SwiftLink with a 1.8432 MHz crystal. +; +; The code assumes that the kernal + I/O are in context. On the C128, call +; it from Bank 15. On the C64, don't flip out the Kernal unless a suitable +; NMI catcher is put into the RAM under then Kernal. For the SuperCPU, the +; interrupt handling assumes that the 65816 is in 6502-emulation mode. +; + + .include "zeropage.inc" + .include "ser-kernel.inc" + .include "ser-error.inc" + .include "c128.inc" + + +; ------------------------------------------------------------------------ +; Header. Includes jump table + +.segment "JUMPTABLE" + +; Driver signature + + .byte $73, $65, $72 ; "ser" + .byte SER_API_VERSION ; Serial API version number + +; Jump table. + + .word INSTALL + .word UNINSTALL + .word OPEN + .word CLOSE + .word GET + .word PUT + .word STATUS + .word IOCTL + +;---------------------------------------------------------------------------- +; I/O definitions + +ACIA = $DE00 +ACIA_DATA = ACIA+0 ; Data register +ACIA_STATUS = ACIA+1 ; Status register +ACIA_CMD = ACIA+2 ; Command register +ACIA_CTRL = ACIA+3 ; Control register +ACIA_CLOCK = ACIA+7 ; Turbo232 external baud-rate generator + +;---------------------------------------------------------------------------- +; +; Global variables +; + +; We reuse the RS232 zero page variables for the driver, since the ROM +; routines cannot be used together with this driver (may also use $A0F +; and following in case of problems). +RecvHead := $A7 ; Head of receive buffer +RecvTail := $A8 ; Tail of receive buffer +RecvFreeCnt := $A9 ; Number of bytes in receive buffer +SendHead := $AA ; Head of send buffer +SendTail := $AB ; Tail of send buffer +SendFreeCnt := $B4 ; Number of bytes free in send buffer +Stopped := $B5 ; Flow-stopped flag +RtsOff := $B6 ; + +; Send and receive buffers: 256 bytes each +RecvBuf := $0C00 ; Use the ROM buffers +SendBuf := $0D00 + +.rodata + +; Tables used to translate RS232 params into register values + +BaudTable: ; bit7 = 1 means setting is invalid + .byte $FF ; SER_BAUD_45_5 + .byte $FF ; SER_BAUD_50 + .byte $FF ; SER_BAUD_75 + .byte $FF ; SER_BAUD_110 + .byte $FF ; SER_BAUD_134_5 + .byte $02 ; SER_BAUD_150 + .byte $05 ; SER_BAUD_300 + .byte $06 ; SER_BAUD_600 + .byte $07 ; SER_BAUD_1200 + .byte $FF ; SER_BAUD_1800 + .byte $08 ; SER_BAUD_2400 + .byte $09 ; SER_BAUD_3600 + .byte $0A ; SER_BAUD_4800 + .byte $0B ; SER_BAUD_7200 + .byte $0C ; SER_BAUD_9600 + .byte $0E ; SER_BAUD_19200 + .byte $0F ; SER_BAUD_38400 + .byte $FF ; SER_BAUD_57600 + .byte $FF ; SER_BAUD_115200 + .byte $FF ; SER_BAUD_230400 + +BitTable: + .byte $60 ; SER_BITS_5 + .byte $40 ; SER_BITS_6 + .byte $20 ; SER_BITS_7 + .byte $00 ; SER_BITS_8 + +StopTable: + .byte $00 ; SER_STOP_1 + .byte $80 ; SER_STOP_2 + +ParityTable: + .byte $00 ; SER_PAR_NONE + .byte $20 ; SER_PAR_ODD + .byte $60 ; SER_PAR_EVEN + .byte $A0 ; SER_PAR_MARK + .byte $E0 ; SER_PAR_SPACE + +.code + +;---------------------------------------------------------------------------- +; Interrupt stub that is copied into low RAM. The startup code uses a special +; memory configuration with just kernal and I/O enabled (anything else is RAM). +; The NMI handler in ROM will switch back to a configuration where just the +; low 16K RAM are accessible. So we have to copy a smal piece of code into +; low RAM that enables the cc65 configuration and then jumps to the real NMI +; handler. + +NmiStubOrig := * + +.org $1150 ; BASIC graphics area +.proc NmiStub + + lda #MMU_CFG_CC65 ; Bank 0 with kernal ROM... + sta MMU_CR ; ...enable + jsr NmiHandler ; Call the actual NMI handler + lda #$00 ; Get ROM config... + sta MMU_CR ; ...and enable it +Vector := *+1 + .byte $4C ; Jump to the saved IRQ vector + +.endproc +.reloc + +;---------------------------------------------------------------------------- +; INSTALL routine. Is called after the driver is loaded into memory. If +; possible, check if the hardware is present. +; Must return an SER_ERR_xx code in a/x. + +INSTALL: + +; Deactivate DTR and disable 6551 interrupts + + lda #%00001010 + sta ACIA_CMD + +; Copy the NMI stub into low memory + + ldy #.sizeof (NmiStub)-1 +@L1: lda NmiStubOrig,y + sta NmiStub,y + dey + bpl @L1 + +; Set up the nmi vector + + lda NMIVec + ldy NMIVec+1 + sta NmiStub::Vector+0 + sty NmiStub::Vector+1 + lda #NmiStub +SetNMI: sta NMIVec + sty NMIVec+1 + +; Done, return an error code + + lda #SER_ERR_INIT_FAILED + rts + +; Baud rate not available + +InvBaud: + lda #SER_ERR_BAUD_UNAVAIL + rts + +;---------------------------------------------------------------------------- +; CLOSE: Close the port, disable interrupts and flush the buffer. Called +; without parameters. Must return an error code in a/x. +; + +CLOSE: + +; Stop interrupts, drop DTR + + lda #%00001010 + sta ACIA_CMD + +; Initalize buffers. Returns zero in a + + jsr InitBuffers + +; Return OK + + lda #SER_ERR_NO_DATA + rts + +; Check for flow stopped & enough free: release flow control + +@L2: ldx Stopped ; (34) + beq @L3 + cmp #63 + bcc @L3 + lda #$00 + sta Stopped + lda RtsOff + ora #%00001000 + sta ACIA_CMD + +; Get byte from buffer + +@L3: ldx RecvHead ; (41) + lda RecvBuf,x + inc RecvHead + inc RecvFreeCnt + ldx #$00 ; (59) + sta (ptr1,x) + txa ; Return code = 0 + rts + +;---------------------------------------------------------------------------- +; PUT: Output character in A. +; Must return an error code in a/x. +; + +PUT: + +; Try to send + + ldx SendFreeCnt + inx ; X = $ff? + beq @L2 + pha + lda #$00 + jsr TryToSend + pla + +; Put byte into send buffer & send + +@L2: ldx SendFreeCnt + bne @L3 + lda #SER_ERR_INV_IOCTL + rts + +;---------------------------------------------------------------------------- +; +; NMI handler +; C128 NMI overhead=76 cycles: int=7, maxLatency=6, ROMenter=33, ROMexit=30 +; C64 NMI overhead=76 cycles: int=7, maxLatency=6, ROMenter=34, ROMexit=29 +; +; timing: normal=76+43+9=128 cycles, assertFlow=76+52+9=137 cycles +; +; C128 @ 115.2k: 177 cycles avail (fast) +; C64 @ 57.6k: 177 cycles avail, worstAvail=177-43? = 134 +; SCPU @ 230.4k: 868 cycles avail: for a joke! +; +; Note: Because of the C128 banking, a small stub has to go into low memory, +; since the ROM NMI entry point switches to a configuration, where only the +; low 16K of RAM are visible. The entry code switches into the standard cc65 +; configuration (I/O + 16K kernal) and then jumps here. Registers are already +; saved by the ROM code. + +NmiHandler: + lda ACIA_STATUS ;(4) ;status ;check for byte received + and #$08 ;(2) + beq @L9 ;(2*) + cld + lda ACIA_DATA ;(4) data ;get byte and put into receive buffer + ldy RecvTail ;(4) + ldx RecvFreeCnt ;(4) + beq @L9 ;(2*) Jump if no space in receive buffer + sta RecvBuf,y ;(5) + inc RecvTail ;(6) + dec RecvFreeCnt ;(6) + cpx #33 ;(2) check for buffer space low + bcc @L2 ;(2*) + rts + +; Assert flow control + +@L2: lda RtsOff ;(3) assert flow control if buffer space too low + sta ACIA_CMD ;(4) command + sta Stopped ;(3) +@L9: rts + +;---------------------------------------------------------------------------- +; Try to send a byte. Internal routine. A = TryHard + +.proc TryToSend + + sta tmp1 ; Remember tryHard flag +@L0: lda SendFreeCnt + cmp #$ff + beq @L3 ; Bail out + +; Check for flow stopped + +@L1: lda Stopped + bne @L3 ; Bail out + +; Check that swiftlink is ready to send + +@L2: lda ACIA_STATUS + and #$10 + bne @L4 + bit tmp1 ;keep trying if must try hard + bmi @L0 +@L3: rts + +; Send byte and try again + +@L4: ldx SendHead + lda SendBuf,x + sta ACIA_DATA + inc SendHead + inc SendFreeCnt + jmp @L0 + +.endproc + + +;---------------------------------------------------------------------------- +; Initialize buffers + +InitBuffers: + ldx #0 + stx Stopped + stx RecvHead + stx RecvTail + stx SendHead + stx SendTail + dex ; X = 255 + stx RecvFreeCnt + stx SendFreeCnt + rts + + diff --git a/libsrc/c128/c128.inc b/libsrc/c128/c128.inc index 69c18e09c..688b210a4 100644 --- a/libsrc/c128/c128.inc +++ b/libsrc/c128/c128.inc @@ -46,6 +46,7 @@ CLRSCR = $C142 KBDREAD = $C006 NEWLINE = $C363 PRINT = $C322 +NMIEXIT = $FF33 ; --------------------------------------------------------------------------- ; Vectors