1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-26 05:29:30 +00:00

Cleanup and preparation for the new design

git-svn-id: svn://svn.cc65.org/cc65/trunk@2839 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2003-12-26 21:43:18 +00:00
parent b9327d23f8
commit 8636914964
12 changed files with 533 additions and 794 deletions

View File

@ -158,6 +158,7 @@ cbm510lib:
mv cbm510/crt0.o cbm510.o
cp cbm510/*.emd .
cp cbm510/*.joy .
cp cbm510/cbm510-stdser.ser cbm510-std.ser
#-----------------------------------------------------------------------------
# PET-II series

View File

@ -1,4 +1,5 @@
*.emd
*.joy
*.ser
*.tgi

View File

@ -20,6 +20,9 @@
%.joy: %.o ../runtime/zeropage.o extzp.o
@$(LD) -t module -o $@ $^
%.ser: %.o ../runtime/zeropage.o extzp.o
@$(LD) -t module -o $@ $^
%.tgi: %.o ../runtime/zeropage.o extzp.o
@$(LD) -t module -o $@ $^
@ -54,7 +57,6 @@ OBJS = _scrsize.o \
pokesys.o \
randomize.o \
revers.o \
rs232.o \
sysuname.o \
tgi_mode_table.o
@ -65,6 +67,8 @@ EMDS = cbm510-ram.emd
JOYS = cbm510-stdjoy.joy
SERS = cbm510-stdser.ser
TGIS =
#--------------------------------------------------------------------------
@ -72,14 +76,14 @@ TGIS =
.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)

View File

@ -95,13 +95,13 @@ READ: ldx #$0F ; Switch to the system bank
; Get the direction bits
ldy #CIA_PRB
ldy #CIA::PRB
lda (cia2),y ; Read joystick inputs
sta tmp1
; Get the fire bits
ldy #CIA_PRA
ldy #CIA::PRA
lda (cia2),y
; Make the result value

View File

@ -0,0 +1,454 @@
;
; Serial driver for the builtin 6551 ACIA of the Commodore 510.
;
; Ullrich von Bassewitz, 2003-12-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 "extzp.inc"
.include "ser-kernel.inc"
.include "ser-error.inc"
.include "cbm510.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
.word IRQ
;----------------------------------------------------------------------------
;
; Global variables
;
.bss
RecvHead: .res 1 ; Head of receive buffer
RecvTail: .res 1 ; Tail of receive buffer
RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
SendHead: .res 1 ; Head of send buffer
SendTail: .res 1 ; Tail of send buffer
SendFreeCnt: .res 1 ; Number of bytes in send buffer
Stopped: .res 1 ; Flow-stopped flag
RtsOff: .res 1 ;
; Send and receive buffers: 256 bytes each
RecvBuf: .res 256
SendBuf: .res 256
.rodata
; Tables used to translate RS232 params into register values
BaudTable: ; bit7 = 1 means setting is invalid
.byte $FF ; SER_BAUD_45_5
.byte $01 ; SER_BAUD_50
.byte $02 ; SER_BAUD_75
.byte $03 ; SER_BAUD_110
.byte $04 ; SER_BAUD_134_5
.byte $05 ; SER_BAUD_150
.byte $06 ; SER_BAUD_300
.byte $07 ; SER_BAUD_600
.byte $08 ; SER_BAUD_1200
.byte $09 ; SER_BAUD_1800
.byte $0A ; SER_BAUD_2400
.byte $0B ; SER_BAUD_3600
.byte $0C ; SER_BAUD_4800
.byte $0D ; SER_BAUD_7200
.byte $0E ; SER_BAUD_9600
.byte $0F ; SER_BAUD_19200
.byte $FF ; 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
;----------------------------------------------------------------------------
; 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.
;
; Since we don't have to manage the IRQ vector on the Plus/4, this is actually
; the same as:
;
; UNINSTALL routine. Is called before the driver is removed from memory.
; Must return an SER_ERR_xx code in a/x.
INSTALL:
UNINSTALL:
; Deactivate DTR and disable 6551 interrupts
lda #%00001010
jsr write_cmd
; Done, return an error code
lda #<SER_ERR_OK
tax ; A is zero
rts
;----------------------------------------------------------------------------
; PARAMS routine. A pointer to a ser_params structure is passed in ptr1.
; Must return an SER_ERR_xx code in a/x.
OPEN:
; Check if the handshake setting is valid
ldy #SER_PARAMS::HANDSHAKE ; Handshake
lda (ptr1),y
cmp #SER_HS_HW ; This is all we support
bne InvParam
; Initialize buffers
jsr InitBuffers
; Set the value for the control register, which contains stop bits, word
; length and the baud rate.
ldy #SER_PARAMS::BAUDRATE
lda (ptr1),y ; Baudrate index
tay
lda BaudTable,y ; Get 6551 value
bmi InvBaud ; Branch if rate not supported
sta tmp1
ldy #SER_PARAMS::DATABITS ; Databits
lda (ptr1),y
tay
lda BitTable,y
ora tmp1
sta tmp1
ldy #SER_PARAMS::STOPBITS ; Stopbits
lda (ptr1),y
tay
lda StopTable,y
ora tmp1
ora #%00010000 ; Receiver clock source = baudrate
ldy #ACIA::CTRL
jsr write
; Set the value for the command register. We remember the base value in
; RtsOff, since we will have to manipulate ACIA_CMD often.
ldy #SER_PARAMS::PARITY ; Parity
lda (ptr1),y
tay
lda ParityTable,y
ora #%00000001 ; DTR active
sta RtsOff
ora #%00001000 ; Enable receive interrupts
jsr write_cmd
; Done
lda #<SER_ERR_OK
tax ; A is zero
rts
; Invalid parameter
InvParam:
lda #<SER_ERR_INIT_FAILED
ldx #>SER_ERR_INIT_FAILED
rts
; Baud rate not available
InvBaud:
lda #<SER_ERR_BAUD_UNAVAIL
ldx #>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
jsr write_cmd
; Initalize buffers.
jsr InitBuffers
; Return OK
lda #<SER_ERR_OK
tax ; A is zero
rts
;----------------------------------------------------------------------------
; GET: Will fetch a character from the receive buffer and store it into the
; variable pointer to by ptr1. If no data is available, SER_ERR_NO_DATA is
; return.
;
GET: ldx SendFreeCnt ; Send data if necessary
inx ; X == $FF?
beq @L1
lda #$00
jsr TryToSend
; Check for buffer empty
@L1: lda RecvFreeCnt
cmp #$ff
bne @L2
lda #<SER_ERR_NO_DATA
ldx #>SER_ERR_NO_DATA
rts
; Check for flow stopped & enough free: release flow control
@L2: ldx Stopped
beq @L3
cmp #63
bcc @L3
lda #$00
sta Stopped
lda RtsOff
ora #%00001000
jsr write_cmd
; Get byte from buffer
@L3: ldx RecvHead
lda RecvBuf,x
inc RecvHead
inc RecvFreeCnt
ldx #$00
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_OVERFLOW ; X is already zero
rts
@L3: ldx SendTail
sta SendBuf,x
inc SendTail
dec SendFreeCnt
lda #$ff
jsr TryToSend
lda #<SER_ERR_OK
tax
rts
;----------------------------------------------------------------------------
; STATUS: Return the status in the variable pointed to by ptr1.
; Must return an error code in a/x.
;
STATUS: lda #$0F
sta IndReg
ldy #ACIA::STATUS
lda (acia),y
ldx #0
sta (ptr1,x)
lda IndReg
sta ExecReg
txa ; SER_ERR_OK
rts
;----------------------------------------------------------------------------
; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
; specific data in ptr1, and the ioctl code in A.
; Must return an error code in a/x.
;
IOCTL: lda #<SER_ERR_INV_IOCTL ; We don't support ioclts for now
ldx #>SER_ERR_INV_IOCTL
rts
;----------------------------------------------------------------------------
; IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
; registers are already save, no parameters are passed and no return code
; is expected.
;
IRQ: lda #$0F
sta IndReg ; Switch to the system bank
ldy #ACIA::STATUS
lda (acia),y ; Check ACIA status for receive interrupt
and #$08
beq @L9 ; Jump if no ACIA interrupt
ldy #ACIA::DATA
lda (acia),y ; Get byte from ACIA
ldx RecvFreeCnt ; Check if we have free space left
beq @L1 ; Jump if no space in receive buffer
ldy RecvTail ; Load buffer pointer
sta RecvBuf,y ; Store received byte in buffer
inc RecvTail ; Increment buffer pointer
dec RecvFreeCnt ; Decrement free space counter
cpx #33 ; Check for buffer space low
bcs @L9 ; Assert flow control if buffer space low
; Assert flow control if buffer space too low
@L1: lda RtsOff
ldy #ACIA::CMD
sta (acia),y
sta Stopped
; Done, switch back to the execution segment
@L9: lda ExecReg
sta IndReg
rts
;----------------------------------------------------------------------------
; Try to send a byte. Internal routine. A = TryHard
.proc TryToSend
sta tmp1 ; Remember tryHard flag
lda #$0F
sta IndReg ; Switch to the system bank
@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: ldy #ACIA::STATUS
lda (acia),y
and #$10
bne @L4
bit tmp1 ; Keep trying if must try hard
bmi @L0
; Switch back the bank and return
@L3: lda ExecReg
sta IndReg
rts
; Send byte and try again
@L4: ldx SendHead
lda SendBuf,x
ldy #ACIA::DATA
sta (acia),y
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
;----------------------------------------------------------------------------
; Write to the ACIA changing the indirect segment. Offset is in Y, value in A.
write_cmd:
ldy #ACIA::CMD
write: pha
lda #$0F
sta IndReg
pla
sta (acia),y
lda ExecReg
sta IndReg
rts

View File

@ -16,60 +16,15 @@ IndReg = $0001
; -----------------------------------
KbdScanBuf = $20 ; Intermediate for keyboard scan
; RS232 stuff
RecvHead = $21 ; Head of receive buffer
RecvTail = $22 ; Tail of receive buffer
RecvFreeCnt = $23 ; Number of bytes in receive buffer
SendHead = $24 ; Head of send buffer
SendTail = $25 ; Tail of send buffer
SendFreeCnt = $26 ; Number of bytes free in send buffer
FileNameAdrLo = $90
FileNameAdrHi = $91
FileNameAdrSeg = $92
SaveAdrLow = $93
SaveAdrHi = $94
SaveAdrSeg = $95
EndAdrLow = $96
EndAdrHi = $97
EndAdrSeg = $98
StartAdrLow = $99
StartAdrHi = $9A
StartAdrSeg = $9B
Status = $9C
FileNameLen = $9D
LogicalAdr = $9E
FirstAdr = $9F
SecondAdr = $A0
DefInpDev = $A1
DefOutDev = $A2
TapeBufPtr = $A3
TapeBufPtrSeg = $A5
rs232BufPtr = $A6
rs232BufPtrSeg = $A8
StopKeyFlag = $A9
CTemp = $AA
snsw1 = $AB
SegChgPtr = $AC
PChighSave = $AE
PClowSave = $AF
SRSave = $B0
ACSave = $B1
XRSave = $B2
YRSave = $B3
SPSave = $B4
IndSegSave = $B5
IRQSaveHi = $B7
IRQSaveLo = $B8
Adr1 = $B9
Adr2 = $BB
MoniCntr = $BD
MoniTmp = $BE
MoniDevNr = $BF
PgmKeyBuf = $C0
PgmKeyPtr = $C2
sedsal = $C4
sedeal = $C6
SCREEN_PTR = $C8
CURS_Y = $CA
CURS_X = $CB
@ -86,25 +41,14 @@ LastLinePos = $D5
PgmKeyIndex = $D6
RepeatCount = $D7
RepeatDelay = $D8
sedt1 = $D9 ; Temp
sedt2 = $DA ; Temp, frequently used
PrtData = $DB
ScreenTop = $DC
ScreenBot = $DD
ScreenLeft = $DE
ScreenRight = $DF
ModKey = $E0
NorKey = $E1
BitTable = $E2
CURS_FLAG = $E6 ; 1 = no cursor
CURS_BLINK = $E7 ; cursor blink counter
CRAM_PTR = $E8
TempColor = $EA
CURS_STATE = $EB ; Cursor blink state
CHARCOLOR = $EC
CURS_COLOR = $ED ; Color behind cursor
OutCharTmp = $EE
ScreenSeq = $EF ; Segment of video RAM
;-----------------------------------------------------------------------------
; Page 3 variables
@ -116,29 +60,6 @@ ScreenSeq = $EF ; Segment of video RAM
IRQVec = $0300
BRKVec = $0302
NMIVec = $0304
openVec = $0306
closeVec = $0308
chkinVec = $030A
ckoutVec = $030C
clrchVec = $030E
basinVec = $0310
bsoutVec = $0312
stopVec = $0314
getinVec = $0316
clallVec = $0318
loadVec = $031A
saveVec = $031C
usrcmd = $031E
escvec = $0320
ctrlvec = $0322
secndVec = $0324
tksaVec = $0326
acptrVec = $0328
cioutVec = $032A
untlkVec = $032C
unlsnVec = $032E
listnVec = $0330
talkVec = $0332
;
;
@ -151,46 +72,19 @@ SysMemBot = $0352
SysMemTop = $0355
UsrMemBot = $0358
UsrMemTop = $035B
TimOut = $035E
VerifyFlag = $035F
DevTabIndex = $0360
MsgFlag = $0361
CassBufPtr = $0362
t1 = $0363
t2 = $0364
XSave = $0365
SaveX = $0366
SaveXt = $0367
temp = $0368
alarm = $0369
TapeVec = $036A
LoadStAdr = $036F
CassMotFlag = $0375
m6551Ctrl = $0376
m6551Cmd = $0377
rs232status = $037A
dcddsr = $037B
rs232head = $037C
rs232tail = $037D
PgmKeyEnd = $0380
PgmKeySeg = $0382
RVS = $0383
linetmp = $0398
LastPrtChar = $0399
InsertFlag = $039A
ScrollFlag = $039B
FktTemp = $039C
PgmKeyIdx = $039D
LogScrollFlag = $039E
BellMode = $039F ; Bell on/off 00 = an
SegSave = $03A0
TabStopTable = $03A1 ; 80 bits for tabstops
KeyBuf = $03AB ; Keyboard buffer
funvec = $03B5 ; Vector for function key handline
sedt3 = $03B9
MoniSegSave = $03f0
wstvec = $03F8
WstFlag = $03FA ; Warm start flag
; ---------------------------------------------------------------------------
; Screen size
@ -295,47 +189,65 @@ SID_Read3 = $1C
; I/O $db00: CIA 6526 Inter Process Communication
; I/O $dc00: CIA 6526
CIA_PRA = $00
CIA_PRB = $01
CIA_DDRA = $02
CIA_DDRB = $03
CIA_ICR = $0D
CIA_CRA = $0E
CIA_CRB = $0F
.struct CIA
PRA .byte
PRB .byte
DDRA .byte
DDRB .byte
.union
.struct
TALO .byte
TAHI .byte
.endstruct
TA .word
.endunion
.union
.struct
TBLO .byte
TBHI .byte
.endstruct
TB .word
.endunion
TOD10 .byte
TODSEC .byte
TODMIN .byte
TODHR .byte
SDR .byte
ICR .byte
CRA .byte
CRB .byte
.endstruct
; I/O $dd00: ACIA 6551
; acia = $dd00
ADataReg = $00
AStatusReg = $01
ACmdReg = $02
ACtrlReg = $03
.struct ACIA
DATA .byte
STATUS .byte
CMD .byte
CTRL .BYTE
.endstruct
; I/O $de00: Triport #1 6525
; tpi1 = $de00
tpiPortA = $00
tpiPortB = $01
tpiPortC = $02
tpiIntLatch = $02
tpiDDRA = $03
tpiDDRB = $04
tpiDDRC = $05
tpiIntMask = $05
tpiCtrlReg = $06
tpiActIntReg = $07
; I/O $df00: Triport #2 6525
; tpi2 = $df00
.struct TPI
PRA .byte
PRB .byte
.union
PRC .byte
INT .byte
.endunion
DDRA .byte
DDRB .byte
.union
DDRC .byte
IMR .byte
.endunion
CR .byte
AIR .byte
.endstruct
; Out video memory address

View File

@ -244,7 +244,7 @@ ccopy2: lda __VIDRAM_START__,y
; CA (STATVID) = 0
; CB (VICDOTSEL) = 0
ldy #tpiCtrlReg
ldy #TPI::CR
lda (tpi1),y
sta vidsave+0
and #%00001111
@ -254,7 +254,7 @@ ccopy2: lda __VIDRAM_START__,y
; Set bit 14/15 of the VIC address range to the high bits of __VIDRAM_START__
; PC6/PC7 (VICBANKSEL 0/1) = 11
ldy #tpiPortC
ldy #TPI::PRC
lda (tpi2),y
sta vidsave+1
and #$3F
@ -388,11 +388,11 @@ _exit: jsr donelib ; Run module destructors
; Switch back the video to the system bank
ldy #tpiCtrlReg
ldy #TPI::CR
lda vidsave+0
sta (tpi1),y
ldy #tpiPortC
ldy #TPI::PRC
lda vidsave+1
sta (tpi2),y

View File

@ -7,5 +7,5 @@
; ------------------------------------------------------------------------
.globalzp vic, sid, cia1, cia2, acia, tpi1, tpi2, ktab1
.globalzp ktab2, ktab3, ktab4, time, RecvBuf, SendBuf
.globalzp ktab2, ktab3, ktab4, time

View File

@ -25,6 +25,4 @@ ktab2: .res 2
ktab3: .res 2
ktab4: .res 2
time: .res 4
RecvBuf: .res 2 ; RS232 receive buffer
SendBuf: .res 2 ; RS232 transmit buffer

View File

@ -63,7 +63,7 @@ k_irq:
cld
lda #$0F
sta IndReg
ldy #tpiActIntReg
ldy #TPI::AIR
lda (tpi1),y ; Interrupt Register 6525
beq noirq
@ -96,7 +96,7 @@ irq1: cmp #%00010000 ; interrupt from uart?
; -------------------------------------------------------------------------
; Done
irqend: ldy #tpiActIntReg
irqend: ldy #TPI::AIR
sta (tpi1),y ; Clear interrupt
noirq: pla

View File

@ -1,4 +1,4 @@
;
;
; Ullrich von Bassewitz, 13.09.2001
;
; Keyboard polling stuff for the 510.
@ -17,9 +17,9 @@
sta NorKey
lda #$00
sta KbdScanBuf
ldy #tpiPortB
ldy #TPI::PRB
sta (tpi2),y
ldy #tpiPortA
ldy #TPI::PRA
sta (tpi2),y
jsr Poll
and #$3F
@ -28,10 +28,10 @@
jmp NoKey
L1: lda #$FF
ldy #tpiPortA
ldy #TPI::PRA
sta (tpi2),y
asl a
ldy #tpiPortB
ldy #TPI::PRB
sta (tpi2),y
jsr Poll
pha
@ -48,11 +48,11 @@ L4: lsr a
dex
bpl L4
sec
ldy #tpiPortB
ldy TPI::PRB
lda (tpi2),y
rol a
sta (tpi2),y
ldy #tpiPortA
ldy #TPI::PRA
lda (tpi2),y
rol a
sta (tpi2),y
@ -98,9 +98,9 @@ L8: tax
NoKey: ldy #$FF
Done: sty LastIndex
End: lda #$7F
ldy #tpiPortA
ldy #TPI::PRA
sta (tpi2),y
ldy #tpiPortB
ldy #TPI::PRB
lda #$FF
sta (tpi2),y
rts
@ -127,7 +127,7 @@ PutKey: sta KeyBuf,x
; Poll the keyboard port until it's stable
.proc Poll
ldy #tpiPortC
ldy TPI::PRC
L1: lda (tpi2),y
sta KeySave
lda (tpi2),y

View File

@ -1,631 +0,0 @@
;
; 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.
;
;--------------------------------------------------------------------------
;
; Adapted for the use with the cc65 runtime library by
; Ullrich von Bassewitz (uz@musoftware.de) 02-May-1999.
;
; All external functions are C callable, the return value is an error code.
;
.importzp ptr1, ptr2, tmp1, tmp2
.importzp acia, RecvBuf, SendBuf
.import popa, popax
.import sys_bank, restore_bank
.export _rs232_init, _rs232_params, _rs232_done, _rs232_get
.export _rs232_put, _rs232_pause, _rs232_unpause, _rs232_status
.export k_rs232
.include "cbm510.inc"
;----------------------------------------------------------------------------
;
; Global variables
;
.bss
DropCnt: .res 4 ; Number of bytes lost from rx buffer full
Initialized: .res 1 ; Flag indicating driver is initialized
Stopped: .res 1 ; Flow-stopped flag
RtsOff: .res 1 ;
Errors: .res 1 ; Number of bytes received in error, low byte
BaudCode: .res 1 ; Current baud in effect
; Segment, the RS232 buffers are in
BufferSeg = 2
; UART register offsets
RegData = 0 ; Data register
RegStatus = 1 ; Status register
RegCommand = 2 ; Command register
RegControl = 3 ; Control register
; Error codes. Beware: The codes must match the codes in the C header file
ErrNotInitialized = $01
ErrBaudTooFast = $02
ErrBaudNotAvail = $03
ErrNoData = $04
ErrOverflow = $05
.code
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_init (char hacked);
; /* Initialize the serial port, install the interrupt handler. The parameter
; * must be true (non zero) for a hacked swiftlink and false (zero) otherwise.
; */
;
_rs232_init:
bit Initialized ;** shut down if started
bpl @L1
pha
jsr _rs232_done
pla
; Initialize buffers & control
@L1: lda #0
sta RecvHead
sta SendHead
sta RecvTail
sta SendTail
sta Errors
sta Stopped
lda #255
sta RecvFreeCnt
sta SendFreeCnt
; Set default to 2400-8N1, enable interrupts
jsr sys_bank ; Switch indirect to system bank
ldy #RegData
lda (acia),y
ldy #RegStatus
lda (acia),y
lda #$18
ldy #RegControl
sta (acia),y
lda #$01
sta RtsOff
ora #$08
ldy #RegCommand
sta (acia),y
lda #$06
sta BaudCode
jsr restore_bank
lda #$ff
sta Initialized
lda #$00
tax
rts
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
; /* Set the port parameters. Use a combination of the #defined values above. */
;
; Set communication parameters.
;
; baud rates stops word | parity
; --------------------- ----- ----- | ---------
; $00=50 $08=9600 $00=1 $00=8 | $00=none
; $01=110 $09=19200 $80=2 $20=7 | $20=odd
; $02=134.5 $0a=38400 $40=6 | $60=even
; $03=300 $0b=57600 $60=5 | $A0=mark
; $04=600 $0c=115200 | $E0=space
; $05=1200 $0d=230400
; $06=2400 $0e=future
; $07=4800 $0f=future
;
_rs232_params:
jsr CheckInitialized ;** check initialized
bcc @L1
rts
; Save new parity
@L1: and #%11100000
ora #%00000001
sta tmp2
; Set baud/parameters
jsr popa
sta tmp1
and #$0f
tax
lda Bauds,x
cmp #$ff
bne @L5
lda #ErrBaudNotAvail
bne @L9
@L5: jsr sys_bank ; Indirect segment to system bank
tax
lda tmp1
and #$0f
sta BaudCode
lda tmp1
and #%11100000
ora #%00010000
sta tmp1
txa
and #$0f
ora tmp1
ldy #RegControl
sta (acia),y
; Set new parity
@L7: lda tmp2
sta RtsOff
ora #%00001000
ldy #RegCommand
sta (acia),y
jsr restore_bank ; Restore indirect bank
lda #0
@L9: ldx #0
rts
.rodata
Bauds:
.byte $01,$03,$04,$06,$07,$08,$0a,$0c,$0e,$0f,$ff,$ff,$ff,$ff,$ff,$ff
;in: 0 1 2 3 4 5 6 7 8 9 a b c d e f
;baud50 110 134 3 6 12 24 48 96 19 38 57 115 230 exp exp
;out masks: $0F=Baud, val$FF=err
.code
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_done (void);
; /* Close the port, deinstall the interrupt hander. You MUST call this function
; * before terminating the program, otherwise the machine may crash later. If
; * in doubt, install an exit handler using atexit(). The function will do
; * nothing, if it was already called.
; */
;
_rs232_done:
bit Initialized ;** check initialized
bpl @L9
; Stop interrupts, drop DTR
lda RtsOff
and #%11100010
ora #%00000010
ldx IndReg
ldy #$0F
sty IndReg ; Set indirect to system bank
ldy #RegCommand
sta (acia),y
stx IndReg ; Restore old indirect bank
; Flag uninitialized
@L9: lda #$00
sta Initialized
tax
rts
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_get (char* B);
; /* Get a character from the serial port. If no characters are available, the
; * function will return RS_ERR_NO_DATA, so this is not a fatal error.
; */
;
_rs232_get:
jsr CheckInitialized ; Check if initialized
bcc @L1
rts
; Check for bytes to send
@L1: sta ptr1
stx ptr1+1 ; Store pointer to received char
ldx SendFreeCnt
cpx #$ff
beq @L2
lda #$00
jsr TryToSend
; Check for buffer empty
@L2: lda RecvFreeCnt
cmp #$ff
bne @L3
lda #ErrNoData
ldx #0
rts
; Check for flow stopped & enough free: release flow control
@L3: ldx Stopped
beq @L4
cmp #63
bcc @L4
lda #$00
sta Stopped
lda RtsOff
ora #%00001000
ldx IndReg
ldy #$0F ; Set indirect to system bank
sty IndReg
ldy #RegCommand
sta (acia),y
stx IndReg
; Get byte from buffer
@L4: ldx IndReg
lda #BufferSeg ; Set indirect to buffer bank
sta IndReg
ldy RecvHead
lda (RecvBuf),y
stx IndReg ; Restore indirect bank
inc RecvHead
inc RecvFreeCnt
ldx #$00
sta (ptr1,x)
txa ; Return code = 0
rts
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_put (char B);
; /* Send a character via the serial port. There is a transmit buffer, but
; * transmitting is not done via interrupt. The function returns
; * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
; */
;
_rs232_put:
jsr CheckInitialized ; Check initialized
bcc @L1
rts
; Try to send
@L1: ldx SendFreeCnt
cpx #$ff
beq @L2
pha
lda #$00
jsr TryToSend
pla
; Put byte into send buffer & send
@L2: ldx SendFreeCnt
bne @L3
lda #ErrOverflow
ldx #$00
rts
; There is enough room (character still in A)
@L3: ldx IndReg
ldy #BufferSeg ; Set indirect to buffer segment
sty IndReg
ldy SendTail
sta (SendBuf),y
stx IndReg ; Restore indirect bank
inc SendTail
dec SendFreeCnt
lda #$ff
jsr TryToSend
lda #$00
tax
rts
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_pause (void);
; /* Assert flow control and disable interrupts. */
;
_rs232_pause:
; Check initialized
jsr CheckInitialized
bcc @L1
rts
; Assert flow control
@L1: lda RtsOff
sta Stopped
jsr sys_bank ; Set indirect to system bank
ldy #RegCommand
sta (acia),y
; Delay for flow stop to be received
ldx BaudCode
lda PauseTimes,x
jsr DelayMs
; Stop rx interrupts
lda RtsOff
ora #$02
ldy #RegCommand
sta (acia),y
jsr restore_bank ; Restore indirect segment
lda #0
tax
rts
.rodata
; Delay times: 32 byte-receive times in milliseconds, or 100 max.
; Formula = 320,000 / baud
PauseTimes:
.byte 100,100,100,100,100,100,100,067,034,017,009,006,003,002,001,001
;in: 0 1 2 3 4 5 6 7 8 9 a b c d e f
;baud50 110 134 3 6 12 24 48 96 19 38 57 115 230 exp exp
.code
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_unpause (void);
; /* Re-enable interrupts and release flow control */
;
_rs232_unpause:
; Check initialized
jsr CheckInitialized
bcc @L1
rts
; Re-enable rx interrupts & release flow control
@L1: lda #$00
sta Stopped
lda RtsOff
ora #%00001000
ldx IndReg
ldy #$0F
sty IndReg ; Set indirect to system bank
ldy #RegCommand
sta (acia),y
stx IndReg ; Restore indirect bank
; Poll for stalled char & exit
jsr PollReceive
lda #0
tax
rts
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_status (unsigned char* status,
; unsigned char* errors);
; /* Return the serial port status. */
;
_rs232_status:
sta ptr2
stx ptr2+1
jsr popax
sta ptr1
stx ptr1+1
jsr CheckInitialized
bcs @L9
; Get status
ldx IndReg ; Save indirect segment
lda #$0F
sta IndReg ; Set system bank as indirect segment
ldy #RegStatus
lda (acia),y ; Read status register
stx IndReg
ldy #0
sta (ptr1),y
jsr PollReceive ; bug-recovery hack
lda Errors
ldy #0
sta (ptr2),y
tya
tax
@L9: rts
;----------------------------------------------------------------------------
;
; RS232 interrupt handler.
; The RS232 handler will be called with the system bank as indirect bank
; and all registers saved.
;
k_rs232:
ldy #RegStatus
lda (acia),y ; check for byte received
and #$08
beq @L9 ; Nothing to receive
lda (acia),y ; check for receive errors
and #$07
beq @L1
inc Errors
@L1: ldy #RegData
lda (acia),y ; get byte and put into receive buffer
ldx RecvFreeCnt
beq @L3
ldy #BufferSeg
sty IndReg
ldy RecvTail
sta (RecvBuf),y ; Store received character
lda #$0F
sta IndReg ; Restore indirect segment
inc RecvTail
dec RecvFreeCnt
cpx #33 ; check for buffer space low
bcs @L9
; Assert flow control
@L2: lda RtsOff ; assert flow control if buffer space too low
ldy #RegCommand
sta (acia),y
sta Stopped
rts
; Drop this char
@L3: inc DropCnt+0 ;not time-critical
bne @L9
inc DropCnt+1
bne @L9
inc DropCnt+2
bne @L9
inc DropCnt+3
@L9: rts
;----------------------------------------------------------------------------
;
; CheckInitialized - internal check if initialized
; Set carry and an error code if not initialized, clear carry and do not
; change any registers if initialized.
;
CheckInitialized:
bit Initialized
bmi @L1
lda #ErrNotInitialized
ldx #0
sec
rts
@L1: clc
rts
;----------------------------------------------------------------------------
; Try to send a byte. Internal routine. A = TryHard
TryToSend:
sta tmp1 ; Remember tryHard flag
ldx IndReg ; Save indirect segment
lda #$0F
sta IndReg ; Set system segment as indirect segment
@L0: lda SendFreeCnt
cmp #$ff
beq @L3 ; Bail out
; Check for flow stopped
@L1: lda Stopped
bne @L3 ; Bail out
; Check that the UART is ready to send
@L2: ldy #RegStatus
lda (acia),y
and #$10
bne @L4
bit tmp1 ; Keep trying if must try hard
bmi @L0
@L3: stx IndReg ; Restore indirect segment
rts
; Send byte and try again
@L4: lda #BufferSeg
sta IndReg
ldy SendHead
lda (SendBuf),y
ldy #$0F
sty IndReg
ldy #RegData
sta (acia),y
inc SendHead
inc SendFreeCnt
jmp @L0
;----------------------------------------------------------------------------
;
; PollReceive - poll for rx char
; This function is useful in odd cases where the 6551 has a character in
; it but it fails to raise an NMI. It might be edge-triggering conditions?
; Actually, I'm not entirely sure that this condition can still arrise, but
; calling this function does no harm.
;
PollReceive:
ldx IndReg ; Save indirect segment
lda #$0F
sta IndReg ; Set system bank as indirect segment
ldy #RegStatus
lda (acia),y
and #$08
beq @L9
lda (acia),y ; Read a second time? ###
and #$08
beq @L9
ldy #RegData
lda (acia),y
ldy RecvFreeCnt
beq @L9
ldy #BufferSeg
sty IndReg
ldy RecvTail
sta (RecvBuf),y
inc RecvTail
dec RecvFreeCnt
@L9: stx IndReg ; Restore indirect segment
rts
;----------------------------------------------------------------------------
;
; DelayMs : delay for given number of milliseconds
; This implementation isn't very rigerous; it merely delays for the
; approximate number of clock cycles for the processor speed.
; Algorithm:
; repeat for number of milliseconds:
; repeat for number of MHz of cpu speed:
; delay for 1017 clock cycles
;
DelayMs: ;( .A=milliseconds )
@L1: ldy #1 ; 1MHz
@L2: ldx #203 ;(2)
@L3: dex ;(2)
bne @L3 ;(3) // 1017 cycles
dey
bne @L2
sec
sbc #1
bne @L1
rts
.end