mirror of
https://github.com/antoinevignau/source.git
synced 2026-10-25 02:02:22 +00:00
562 lines
11 KiB
ArmAsm
562 lines
11 KiB
ArmAsm
* Sample IIGS source code by Jim Ferr.
|
|
* I hereby place this code in the public domain.
|
|
* March 19, 1992.
|
|
*
|
|
* Made relocatable in 2026
|
|
* Brutal Deluxe Software
|
|
*
|
|
|
|
mx %00
|
|
lst off
|
|
|
|
*-------------------------------
|
|
* ROUTINES
|
|
*
|
|
* 1.ALLOCATE Install the new IM
|
|
* 2.INITGS Inits the SCC
|
|
* 3.DOBAUD Set baud rate with A = 0..8
|
|
* 4.MOUT Send character in A to modem
|
|
* 4.REMOVE Remove the new IM
|
|
* CLRMBUF Clears the buffer
|
|
*
|
|
* When a command is sent to the SCC,
|
|
* result is expected in the 256-byte buffer
|
|
|
|
|
|
*-----------------------------------------------
|
|
* Apple IIgs Z8530 registers and constants
|
|
|
|
GSCMDB = $C038
|
|
GSCMDA = $C039
|
|
GSDATAB = $C03A
|
|
GSDATAA = $C03B
|
|
|
|
WR11A = %11010000 ;init wr11 in Ch A
|
|
WR11B = %01010000 ;init wr11 in Ch B
|
|
;crystal not used by Ch B
|
|
;3.6864MHz external crystal
|
|
;Rx/Tx clock source = BRG
|
|
;TRxC is an input (tied to cts)
|
|
;bits 1 and 0 insignificant
|
|
|
|
RESETCHA = %11010001 ;constant to reset Ch A
|
|
RESETCHB = %01010001 ;constant to reset Ch B
|
|
|
|
*-----------------------------------------------
|
|
* This little routine intercepts the Interrupt
|
|
* Manager vector at $E1/0010 or wherever it may
|
|
* be in the future, pointing it to our IRQIN
|
|
* routine. We save the original manager's address
|
|
* so we can pass interrupts that aren't ours to
|
|
* the slow-poke firmware.
|
|
|
|
mx %00
|
|
|
|
ALLOCATE pha
|
|
pha
|
|
PushWord #4 ; Interrupt Manager
|
|
_GetVector
|
|
PullLong ORGMGR
|
|
|
|
lda #5 ; 19200 by default
|
|
sta BAUD
|
|
stz idxBUFFER ; reset buffer index
|
|
|
|
PushWord #4 ; Interrupt Manager
|
|
PushLong #IRQIN
|
|
_SetVector
|
|
rts
|
|
|
|
*-----------------------------------------------
|
|
* This routine removes our intercept of the vector
|
|
* and restores the original firmware vector.
|
|
|
|
mx %00
|
|
|
|
REMOVE php
|
|
sei
|
|
jsr DISABLE ;disable modem port!
|
|
;and put it back in state
|
|
;the serial port firmware
|
|
;can handle.
|
|
clc
|
|
xce
|
|
rep #$30 ;full 16-bit mode
|
|
|
|
PushWord #4
|
|
PushLong ORGMGR
|
|
_SetVector
|
|
|
|
plp
|
|
rts
|
|
|
|
*-----------------------------------------------
|
|
* Data carrier detect flag for main program
|
|
|
|
DCDSTATE DS 1 ;flag. Non-zero means no DCD.
|
|
|
|
* Default baud rate
|
|
|
|
BAUD dw 5 ;1=300, 2=1200, 3=2400
|
|
;4=4800, 5=9600, 6=19200
|
|
;7=38400, 8=57600.
|
|
|
|
mx %11 ; set Merlin 16+ to 8-bit mode
|
|
|
|
*-----------------------------------------------
|
|
* Interrupt Manager
|
|
*
|
|
* Here is where we get the irqs and steal ours from
|
|
* the teeth of the firmware, as it were. If the irq
|
|
* isn't ours, we exit to the firmware. If it is ours,
|
|
* we process it and RTI (Return from interrupt).
|
|
|
|
IRQIN clc ;emulation or native mode?
|
|
xce ;enter native mode
|
|
bcc :NATIVE ;was already in native mode
|
|
|
|
* Emulation mode entry
|
|
|
|
sec ;was in emulation mode, so
|
|
xce ;lets go back to it.
|
|
|
|
php ;save status for firmware
|
|
pha ;save registers
|
|
phx
|
|
phy
|
|
|
|
lda #$FF
|
|
stal :FIRST ;first time through flag
|
|
stal :EMULATE ;emulation mode flag
|
|
bra :IRQTEST ;check if our irq
|
|
|
|
* Native mode entry
|
|
|
|
:NATIVE php ;save status for firmware
|
|
rep #$30 ;16-bit mode
|
|
mx %00
|
|
|
|
pha ;save all registers
|
|
phx
|
|
phy
|
|
phb ;save DBR
|
|
|
|
* PEA $0000
|
|
* PLB ;switch in data bank zero
|
|
* PLB ;pull 16 bits
|
|
|
|
phk
|
|
plb
|
|
|
|
sep #$30 ;8-bit mode
|
|
mx %11
|
|
|
|
lda #$FF
|
|
sta :FIRST ;first time through flag
|
|
stz :EMULATE ;kill emulation mode flag
|
|
;fall through to :IRQTEST
|
|
|
|
* Test if irq pending on SCC Channel B
|
|
|
|
:IRQTEST lda #3
|
|
stal GSCMDA
|
|
ldal GSCMDA ;read rr3 ch A ip bits
|
|
and #%00000101 ;check for Rx and ext/stat
|
|
;in Ch B only.
|
|
bne :GETINT
|
|
jmp :EXIT
|
|
|
|
:GETINT stz :FIRST ;is definitely our irq
|
|
lda #2
|
|
stal GSCMDB
|
|
ldal GSCMDB ;get vector from rr2B
|
|
|
|
and #%01110000 ;examine bits 6-5-4
|
|
|
|
cmp #%00100000 ;Rx?
|
|
beq :RX
|
|
|
|
cmp #%01100000 ;special?
|
|
beq :SPECIAL
|
|
;if not, must be exint.
|
|
|
|
* Handle external status interrupts
|
|
|
|
:EXINT lda #%00010000 ;reset exint pending
|
|
stal GSCMDB
|
|
|
|
ldal GSCMDB
|
|
|
|
* The two lines below are commented out because this
|
|
* driver assumes carrier detect is in GPi.
|
|
|
|
* AND #%00100000 ;get CTS/HSKi bit
|
|
* EOR #%00100000 ;flip the CTS/HSKi bit
|
|
|
|
and #%00001000 ;get DCD/GPi bit
|
|
eor #%00001000 ;flip the DCD/GPi bit
|
|
|
|
sta DCDSTATE ;non-zero means offline
|
|
bra :IRQTEST
|
|
|
|
* Special condition (error)
|
|
|
|
:SPECIAL lda #1 ;rr1
|
|
stal GSCMDB
|
|
ldal GSCMDB
|
|
tax
|
|
and #%01000000 ;framing error?
|
|
bne :BAD
|
|
txa
|
|
and #%00100000 ;overrun? (latched)
|
|
beq :BAD
|
|
|
|
lda #%00110000 ;error reset command
|
|
stal GSCMDB ;to clear latched error.
|
|
bra :IRQTEST
|
|
|
|
:BAD ldal GSDATAB ;eat bad character!
|
|
bra :IRQTEST
|
|
|
|
* Get received character
|
|
|
|
:RX ldy idxBUFFER
|
|
ldal GSDATAB ;get good char
|
|
sta myBUFFER,y
|
|
iny
|
|
sty idxBUFFER
|
|
bra :IRQTEST ;test for more!
|
|
|
|
*---
|
|
|
|
:FIRST DS 1 ;flag for first time thru
|
|
|
|
:EMULATE DS 1 ;flag/ were we in emulation
|
|
;mode or native mode.
|
|
|
|
* The ONLY exit (from IRQIN)
|
|
|
|
:EXIT bit :EMULATE
|
|
bpl :EXIT3
|
|
|
|
* Emulation mode; irq exit routine
|
|
|
|
:EXIT1 bit :FIRST ;first time through?
|
|
bmi :EXIT2 ;if so, not our irq
|
|
ply
|
|
plx
|
|
pla
|
|
plp ;restore status
|
|
rti ;was ours.
|
|
|
|
:EXIT2 ply
|
|
plx
|
|
pla
|
|
plp
|
|
bra :JUMP ;go to the firmware
|
|
|
|
* Native mode, irq exit routine
|
|
|
|
:EXIT3 bit :FIRST ;first time through?
|
|
bmi :EXIT4 ;if so, not our irq
|
|
|
|
rep #$30 ;16-bit mode
|
|
mx %00
|
|
plb ;restore data bank register
|
|
ply ;restore Y
|
|
plx ;restore X
|
|
pla ;restore A
|
|
plp ;restore original status
|
|
rti ;return from interrupt
|
|
|
|
:EXIT4 rep #$30 ;16-bit mode
|
|
plb ;restore data bank register
|
|
ply ;restore Y
|
|
plx ;restore X
|
|
pla ;restore A
|
|
plp ;restore original status
|
|
|
|
mx %11
|
|
|
|
* JML to firmware's handler (and let it worry about
|
|
* this interrupt.)
|
|
|
|
:JUMP DFB $5C ;JML
|
|
ORGMGR DS 4 ;to original manager address
|
|
|
|
*-----------------------------------------------
|
|
* INITGS: initialize the Modem Port
|
|
* (Channel B is modem port, A is printer port)
|
|
|
|
mx %00
|
|
|
|
INITGS php
|
|
sei
|
|
sep #$30
|
|
|
|
ldal GSCMDB ;hit rr0 once to sync up
|
|
|
|
lda #9 ;wr9
|
|
stal GSCMDB
|
|
lda #RESETCHB ;load constant to reset Ch B
|
|
;for Ch A, use RESETCHA
|
|
stal GSCMDB
|
|
nop ;SCC needs 11 pclck to recover
|
|
|
|
lda #4 ;wr4
|
|
stal GSCMDB ;1 stop bit, no parity
|
|
lda #%01000100 ;X16 clock mode,
|
|
stal GSCMDB ;could be 1.5 or 2 stop bits
|
|
;1.5 set bits 3,2 to 1,0
|
|
;2 set bits 3,2 to 1,1
|
|
lda #3 ;wr3
|
|
stal GSCMDB ;could be 7 or 6 or 5 data bits
|
|
lda #%11000000 ;8 data bits, receiver disabled
|
|
stal GSCMDB ;for 8 bits, bits 7,6 = 1,1
|
|
|
|
lda #5 ;wr5
|
|
stal GSCMDB ;no BRK, xmit disabled, no SDLC
|
|
lda #%01100010 ;DTR enabled 0=/HIGH, 8 data bits
|
|
stal GSCMDB ;RTS *MUST* be disabled, no crc
|
|
lda #11 ;wr11
|
|
stal GSCMDB
|
|
lda #WR11B ;load constant to write
|
|
;use #WR11A for channel A
|
|
stal GSCMDB
|
|
|
|
jsr TIMECON ;set up wr12 and wr13
|
|
;to set baud rate.
|
|
lda #14 ;wr14
|
|
stal GSCMDB ;no echo, /DTR follows wr5
|
|
lda #%00000000 ;null cmd, no loopback
|
|
stal GSCMDB ;BRG source is XTAL or RTxC
|
|
|
|
* Enables
|
|
|
|
lda #14 ;wr14
|
|
stal GSCMDB
|
|
lda #%00000001 ;enable baud rate gen
|
|
stal GSCMDB ;write value
|
|
|
|
lda #3
|
|
stal GSCMDB
|
|
lda #%11000001 ;8 data bits, Rx enable
|
|
stal GSCMDB ;write value
|
|
|
|
lda #5
|
|
stal GSCMDB
|
|
lda #%01101010 ;DTR enabled; Tx enable
|
|
stal GSCMDB ;write value
|
|
|
|
* Enable Interrupts
|
|
|
|
lda #15 ;wr15
|
|
stal GSCMDB
|
|
|
|
* The next line is commented out. This driver wants
|
|
* interrupts when GPi changes state, ie. the user
|
|
* on the BBS may have hung up. You can write a 0
|
|
* to this register if you don't need any external
|
|
* status interrupts. Then in the IRQIN routine you
|
|
* won't need handling for overruns; they won't be
|
|
* latched. See the Zilog Tech Ref. for details.
|
|
|
|
* LDA #%00100000 ;allow ext. int. on CTS/HSKi
|
|
|
|
lda #%00001000 ;allow ext. int. on DCD/GPi
|
|
stal GSCMDB
|
|
|
|
lda #0
|
|
stal GSCMDB
|
|
lda #%00010000 ;reset ext. stat. ints.
|
|
stal GSCMDB ;write it twice
|
|
|
|
lda #0
|
|
stal GSCMDB
|
|
lda #%00010000 ;reset ext. stat. ints.
|
|
stal GSCMDB ;write it twice
|
|
|
|
lda #1 ;wr1
|
|
stal GSCMDB ;allow IRQs on Rx all & ext. stat
|
|
lda #%00010001 ;Wait Request disabled
|
|
stal GSCMDB ;No transmit interrupts (b1)
|
|
|
|
lda #9 ;re-write wr9
|
|
stal GSCMDB ;this value gives us vector
|
|
lda #%00011001 ;set Master Interrupt Enable
|
|
stal GSCMDB ;information with each irq,
|
|
;in vector bits 6-5-4,
|
|
;also including status.
|
|
|
|
* The vector bits are not used by firmware and IIGS
|
|
* TechNote #18. But they make irq handling easier.
|
|
|
|
rep #$30 ;(See IRQIN routine.)
|
|
plp
|
|
rts ;we're done!
|
|
|
|
*-----------------------------------------------
|
|
* DISABLE: ensure serial port IRQ's turned off
|
|
* (DTR unaffected; use HANGUP or GSDTR)
|
|
* This routine puts the port in normal firmware
|
|
* state, with no interrupts possible.
|
|
|
|
DISABLE php
|
|
sei
|
|
sep #$20
|
|
|
|
lda #9
|
|
stal GSCMDB
|
|
lda #%00000010 ;disable MIE temporarily
|
|
stal GSCMDB
|
|
|
|
* Interrupt Status
|
|
|
|
lda #1 ;wr1
|
|
stal GSCMDB
|
|
lda #%00000000 ;no DMA, no interrupts
|
|
stal GSCMDB
|
|
|
|
ldal GSDATAB ;eat any character waiting
|
|
|
|
lda #0 ;wr0
|
|
stal GSCMDB
|
|
lda #%00010000 ;clear any ext ints
|
|
stal GSCMDB
|
|
|
|
lda #0 ;wr0
|
|
stal GSCMDB ;write it twice
|
|
lda #%00010000 ;clear any ext ints
|
|
stal GSCMDB
|
|
|
|
lda #9
|
|
stal GSCMDB
|
|
lda #%00001010 ;reset MIE for firmware use
|
|
stal GSCMDB
|
|
|
|
rep #$20
|
|
plp
|
|
rts
|
|
|
|
*-----------------------------------------------
|
|
* TIMECON: Set time constant bytes in wr12 & wr13
|
|
* (In other words, set the baud rate.)
|
|
|
|
mx %11
|
|
|
|
TIMECON ldy BAUD
|
|
lda #12
|
|
stal GSCMDB
|
|
lda BAUDL-1,Y ;load time constant low
|
|
stal GSCMDB
|
|
|
|
lda #13
|
|
stal GSCMDB
|
|
lda BAUDH-1,Y ;load time constant high
|
|
stal GSCMDB
|
|
rts
|
|
|
|
* Table of values for different baud rates. There is
|
|
* a low byte and a high byte table.
|
|
|
|
BAUDL DFB 126 ;300 bps (1)
|
|
DFB 94 ;1200 (2)
|
|
DFB 46 ;2400 (3)
|
|
DFB 22 ;4800 (4)
|
|
DFB 10 ;9600 (5)
|
|
DFB 4 ;19200 (6)
|
|
DFB 1 ;38400 (7)
|
|
DFB 0 ;57600 (8)
|
|
|
|
BAUDH DFB 1 ;300 bps (1)
|
|
DFB 0 ;1200 (2)
|
|
DFB 0 ;2400 (3)
|
|
DFB 0 ;4800 (4)
|
|
DFB 0 ;9600 (5)
|
|
DFB 0 ;19200 (6)
|
|
DFB 0 ;38400 (7)
|
|
DFB 0 ;57600 (8)
|
|
|
|
*-----------------------------------------------
|
|
* DOBAUD: Set baud rate without resetting entire 8530
|
|
* (Stop clock, set time constant, restart clock)
|
|
|
|
mx %00
|
|
|
|
DOBAUD php
|
|
sei
|
|
sep #$20
|
|
|
|
sta BAUD ; save baud speed
|
|
|
|
lda #14 ;wr14
|
|
stal GSCMDB
|
|
lda #0 ;disable BRG (stop clock)
|
|
stal GSCMDB ;write it
|
|
|
|
jsr TIMECON ;set time constant bytes
|
|
|
|
lda #14
|
|
stal GSCMDB
|
|
lda #%00000001 ;re-enable BRG
|
|
stal GSCMDB
|
|
|
|
rep #$20
|
|
plp
|
|
rts
|
|
|
|
*-----------------------------------------------
|
|
* MOUT: send character in A to modem, regardless of
|
|
* carrier state. Preserves all registers.
|
|
|
|
mx %00
|
|
|
|
MOUT sta :TEMPA
|
|
stx :TEMPX
|
|
sep #$30
|
|
|
|
:SEND ldal GSCMDB ;rr0
|
|
|
|
tax
|
|
and #%00000100 ;test bit 2 (hardware handshaking)
|
|
beq :SEND
|
|
txa
|
|
and #%00100000 ;test bit 5 (ready to send?)
|
|
beq :SEND
|
|
|
|
lda :TEMPA ;get char to send
|
|
stal GSDATAB ;send the character
|
|
|
|
rep #$30
|
|
ldx :TEMPX
|
|
lda :TEMPA
|
|
rts
|
|
|
|
:TEMPA ds 2
|
|
:TEMPX ds 2
|
|
|
|
*-----------------------------------------------
|
|
* Code for checking if data in buffer deleted
|
|
|
|
* CLRMBUF: clear mbuf.
|
|
|
|
mx %00
|
|
|
|
CLRMBUF php ;stuff deleted (fix buffer pointers)
|
|
sei
|
|
sep #$20
|
|
ldal GSDATAB ;ensure no data in SCC
|
|
ldal GSDATAB ;by reading data 3 times
|
|
ldal GSDATAB ;(it has a 3 byte fifo)
|
|
|
|
rep #$20
|
|
plp
|
|
rts
|
|
|
|
*-----------------------------------------------
|
|
* Buffer area
|
|
|
|
idxBUFFER ds 2 ; 0..255 but init'ed in 16 bits
|
|
myBUFFER ds 256 ; a rolling buffer
|
|
|