Files
Shawn Quick dfcaae62dd Add qlink, the disk tools, and a bootable ProDOS 8 image.
Move the assembler to src/qasm. qlink links OMF 1.0 and 2.0 from a script. makeBin flattens a load file, qomf dumps OMF, and qpro builds ProDOS volumes. APW and MPW assemble through the ORCA front end. Relocatable modules emit OMF objects. Listings stay off unless -l is set.

make boot assembles the GS/OS 6.0.1 ProDOS 8 kernel and BASIC.SYSTEM into an 800K volume. BASIC.SYSTEM accepts ls and pfx, and its splash reports PRODOS BASIC 2.0, copyright 1983-2026. IIGS.601.SRC is the source and the BASIC.SYSTEM oracle that image is built from.
2026-10-16 14:41:55 -07:00

1 line
130 KiB
NASM

title 'Misc Tools GS ROM 3.0'
**********************************************************************
*
* Misc Tools
*
*
* Copyright (C) 1985-1988
* All Rights Reserved
* Apple Computer, Inc.
*
*
* Change History
*
* Revision Date Description Who
* Alpha1.0 02-17-86 Initial ALPHA release RBM
* 02-27-86 Implemented IDTAG MGR RBM
* Corrected error codes
* Math Divide/0 error reporting
* Fixed MAINSIDE dispatcher
* 03-07-86 Build NEW miscellaneous tools RBM
* Beta 1.0 03-26-86 Psuedo keyboard IRQ task. RBM
* Beta 2.0 04-23-86 More parms for get address. RBM
* 04-29-86 No calls to system death from RBM
* mouse tools. Added absolute
* device clamp support. The get
* address call has more parms.
* Rom 0.1 10-27-86 Fixed endcall in SetAbsClamps. RBM
* ID manager now reassigns tags.
* Fixed WrBram & RdBram so that
* buffer may be in any bank.
* Rom 0.1 10-29-86 Added SysBeep RBM
*
* For ROM 3.0
*
* 06 May 88 Joe Bo
*
* Implemented mouse hardware interfaces to mouse calling routines.
*
*
* 09 May 88 Joe Bo
*
* Added a new entry point for BASIC to initialize mouse.
*
*
* 26 Jul 88 Steven Glass
*
* Get and SetVector disable interrupts during access to the vectors.
*
* DelHeartbeat and ClearHeartbeat try and turn off vbl interrupts
* if it is safe to do so.
*
* 10 Sep 88 Steven Glass
*
* Entry in call table for BasicInit did not include -1.
*
* Added calls AddToQueue and DeleteFromQueue.
*
* 30 Sep 88 Joe Bo
*
* GetMouseClamp: Saved and restored dbr around internal calls.
*
* 03 Sep 88 Steven Glass
*
* GetMouseClamp: Changed equates to account for saving and restoring dbr.
*
* 17 Oct 88 Steven Glass
*
* The bParam table entry for slot one (address $21) is not offset
* to $58. This is to make appletalk work in the new configuration.
*
* 17 Nov 88 Konstantin Othmer
*
* Added slot arbiter stuff to fwentry. A call to _FWEntry (which really goes
* through MonEntry) will set the slots to the default configuration if the call
* is in the Cn00 space. Using fwentry directly (which only the text tools do)
* will not change the slot configuration.
*
* 08 Dec 88 Steven Glass
*
* Change to DeathMgr in way it checks for NIL ptr.
*
* 04 Jan 89 Mensch
*
* Added ReadMouse2 Call. and changed ReadMouse call, The new read mouse is
* identical to old read mouse read mouse, except that
* it will allow journaling to occur. ReadMouse2 is the old readmouse call
* should only be used by the event manager. Everyone else should stick with
* the old readmouse
*
* 12 Jan 89 Mensch
* Fix bug introduced on jan 4 that caused infinite loop in readmouse.
*
* 17 Jan 89 Mensch
* Added GetROMResource and ReleaseROMResource to Misc Tools
*
* 26-Sep-90 Dave Lyons
*
* Changed _SysDeath to _SysFailMgr so it builds.
*
* 4-Mar-91 Dave Lyons
*
* Adding new call $3B03 StringToText to translate 8-bit "Shaston 8" style
* text into the nearest equivalent Text-screen text (allowing for mousetext,
* etc). (Code is really in the ROM 3 patch file.)
*
**********************************************************************
include 'all.macros'
include '::sys.equs.asm'
;-----------------------------------------------------------
;
; Global Version Number
;
Version equ $0300 ; version number
;-----------------------------------------------------------
;
; from e16.misctool
;
vblDisable EQU $0003 ; Interrupt Ref Number - Parameter to IntSource
;-----------------------------------------------------------
;
; Slot Arbiter Entry point
;
Slot_arbiter equ $E10208
;-----------------------------------------------------------
;
; Definition of Record used by Queue Routines
;
DSect 0
HeaderLink LONG
HeaderReserved WORD
HeaderSignature WORD
HeaderRoutine LONG
QueueSignature equ $A55A
;-----------------------------------------------------------
;
; Misc tools Errors
;
BadInputErr equ $0301 ; bad input
noDevParamErr equ $0302 ; no device for input paramter
taskInstlErr equ $0303 ; specified task already in queue
noSigTaskErr equ $0304 ; no signature detected in task header
queueDmgdErr equ $0305 ; damaged heartbeat queue detected (fatal)
taskNtFdErr equ $0306 ; specified task not in queue
firmTaskErr equ $0307 ; Unsuccessful fw task
hbQueueBadErr equ $0308 ; damaged heartbeat queue detected (fatal)
unCnctdDevErr equ $0309 ; dispatch to unconnect device
idTagNtAvlErr equ $030B ; no id tag available
RecordNotFound equ $0380
BadSignature equ $0381
;-----------------------------------------------
;
; Imported addresses
;
;-----------------------------------------------
IMPORT EndCall0
IMPORT EndCall2
IMPORT EndCall4
IMPORT EndCall8
IMPORT ErrOut2
IMPORT ErrOut4
IMPORT FFEntry
IMPORT LastTag
IMPORT LongDiv
IMPORT Multiply
IMPORT SpecialNewHandle
IMPORT UDivide
IMPORT oEndCall0
IMPORT oEndCall2
IMPORT oEndCall4
IMPORT oEndCall6
IMPORT oEndCall8
IMPORT oErrOut0
IMPORT oErrOut2
IMPORT oErrOut4
IMPORT oErrOut6
IMPORT oErrOut8
;-----------------------------------------------
;
; Forward addresses and entries
;
;-----------------------------------------------
ENTRY ClearGlue
ENTRY ClrHeart
ENTRY DelHeart
ENTRY DeleteID
ENTRY GetAbsClamp
ENTRY GetAddr
ENTRY GetIRQenbl
ENTRY GetNewID
ENTRY GetTick
ENTRY GetVector
ENTRY HexToAscii
ENTRY HomeGlue
ENTRY ISIT44
ENTRY InitGlue
ENTRY IntSrc
ENTRY Irq_Heart
ENTRY LOOKAT4
ENTRY MTCallTable
ENTRY MTDeref
ENTRY MTInit
ENTRY MTRes7
ENTRY MTRes8
ENTRY MTReset
ENTRY MTShutDown
ENTRY MTStartup
ENTRY MTStatus
ENTRY MTVer
ENTRY MonEntry
ENTRY Munger
ENTRY PackBytes
ENTRY RdATime
ENTRY ReadBParam
ENTRY ReadBRam
ENTRY ReadMouseJ
ENTRY RdTimeHex
ENTRY SetAbsClamp
ENTRY SetHeart
ENTRY SetVector
ENTRY StatusID
ENTRY SysBeep
ENTRY SysDeathMgr
ENTRY TClmpMou
ENTRY TGetClamp
ENTRY TPosMou
ENTRY TRdMou
ENTRY TServMou
ENTRY TSetMou
ENTRY ToLDivide
ENTRY ToMainSide
ENTRY ToMult
ENTRY ToUDivide
ENTRY UnPackBytes
ENTRY WriteBParam
ENTRY WriteBRam
ENTRY WrTimeHex
ENTRY GetMData
ENTRY setdbtoe1
ENTRY MYBasicInit
ENTRY InitFlag
import AddToQueue
import DeleteFromQueue
Import ReleaseROMResource
Import GetROMResource
title 'Call Table'
****************************************************************
*
MTCallTable PROC EXPORT
*
* Call table for the tool
*
*
* Inputs:
* none
*
* Outputs:
* none
*
* External Refs:
import SetInterruptState
import GetInterruptState
import GetIntStateRecSize
import GetCodeResConverter
import ConvSeconds
import SysBeep2
import VersionString
import WaitUntil
import StringToText
*
* Entry Points:
* none
*
longa on ; mode
longi on
*
****************************************************************
Here
DC.L (TheEnd-Here)/4 ; num calls +1
DC.L MTInit-1 ; PowerUp Initialization
DC.L MTStartup-1 ; application startup
DC.L MTShutDown-1 ; application shutdown
DC.L MTVer-1 ; version number
DC.L MTReset-1 ; Misc. Tools Reset
DC.L MTStatus-1 ; Reserved
DC.L MTRes7-1 ; Reserved
DC.L MTRes8-1 ; Reserved
DC.L WriteBRam-1 ; Write battery ram
DC.L ReadBRam-1 ; Read battery ram
DC.L WriteBParam-1 ; Write battery ram parameter
DC.L ReadBParam-1 ; Read battery ram parameter
DC.L RdTimeHex-1 ; read clock w/ hex format
DC.L WrTimeHex-1 ; write clock w/ hex format
DC.L RdATime-1 ; read clock w/ ascii format
DC.L SetVector-1 ; set interrupt vector
DC.L GetVector-1 ; get interrupt vector
DC.L SetHeart-1 ; insert procedure in Heartbeat chain
DC.L DelHeart-1 ; delete procedure from heartbeat chai
DC.L ClrHeart-1 ; clear heartbeat chain
DC.L SysDeathMgr-1 ; system death manager
DC.L GetAddr-1 ; ???
DC.L ReadMouseJ-1 ; Read Mouse (Was TRdMou)
DC.L InitGlue-1 ; initialize mouse
DC.L TSetMou-1 ; set mouse mode
DC.L HomeGlue-1 ; home mouse position to min. clamp
DC.L ClearGlue-1 ; clear mouse position to 0
DC.L TClmpMou-1 ; set both X and Y clamps
DC.L TGetClamp-1 ; get both X and Y clamps
DC.L TPosMou-1 ; set mouse position
DC.L TServMou-1 ; service mouse interrupt
DC.L GetNewID-1 ; get ID tag
DC.L DeleteID-1 ; delete ID tag
DC.L StatusID-1 ; get ID tag status
DC.L IntSrc-1 ; enable interrupt source
DC.L MonEntry-1 ; Firmware entry points
DC.L GetTick-1 ; get tick counter contents
DC.L PackBytes-1 ; Pack bytes
DC.L UnPackBytes-1 ; UnPack dem dere bytes
DC.L Munger-1 ; This routine munges strings
DC.L GetIRQenbl-1 ; returns IRQ enble status
DC.L SetAbsClamp-1 ; set absolute device clamps
DC.L GetAbsClamp-1 ; get absolute device clamps
DC.L SysBeep-1 ; system beep
DC.L MyBasicInit-1 ; mouse init for BASIC from $c4xx
DC.L AddToQueue-1 ; added 10 sep 88
DC.L DeleteFromQueue-1 ; added 10 sep 88
dc.L SetInterruptState-1 ; added 24 Nov 88
dc.L GetInterruptState-1 ; added 24 Nov 88
dc.L GetIntStateRecSize-1 ; added 24 Nov 88
dc.L TRdMou-1 ; added 03 jan 89 {$3303}
dc.L GetCodeResConverter-1 ; added 12 Jan 89 {$3403}
dc.L GetROMResource-1 ; Added 17 Jan 89 {$3503}
dc.L ReleaseROMResource-1 ; Added 17 Jan 89 {$3603}
dc.l ConvSeconds-1 ; $3703
dc.l SysBeep2-1 ; $3803
dc.l VersionString-1 ; $3903
dc.l WaitUntil-1 ; $3A03
dc.l StringToText-1 ; $3B03
TheEnd
ENDP
title 'Init Routines'
****************************************************************
*
* BOOTINIT: Clears heartbeat queue. Sets no slot flags.
* Clears tick counter. Allocates IDtag memory.
* STARTUPINIT: Does nothing
* SHUTDOWN: Does nothing
* RESET: Clears heartbeat queue. Sets no slot flags.
*
****************************************************************
MTInit PROC ; Tool Boot Initialization
phb ; save the dbr on stack
IF RAMVersion THEN
bra SkipNewHandle
ENDIF
lda #0 ; Init HeartBeat chain
sta >HBptr
sta >HBptr+2
sta >TickCnt ; initialize tick counter
sta >TickCnt+2
sep #$20 ; 8 bit 'm'
sta >KBDIRQFLAG ; clear interrupt flag
dec a ; assume no Slot I/O
sta >SIOFlag
sta >MouseSlot ; assume no mouse either
rep #$20 ; 16 bit 'm'
lda #0 ; size
ldx #$4101
ldy #$0008 ; no special memory
jsr SpecialNewHandle
bcc MTInit0 ; if got block
pea $0000 ; no message
pea $0000
pea $0025 ; cant allocate IDTAG queue
_SysFailMgr ; SYSTEM DEATH
MTInit0 ;
txa ; save handle
sta >MThandle
tya
sta >MThandle+2
SkipNewHandle
plb ; restore data bank reg
ENTRY MTStartup
MTStartup ; ; Tool Startup Initialization
ENTRY MTShutdown
MTShutdown ; ; Tool Shut Down
ENTRY MTRes7
MTRes7 ; ; Reserved function #7
ENTRY MTRes8
MTRes8 ; ; Reserved function #8
jmp oEndCall0
ENTRY MTReset
MTReset ;
lda #0 ; clear HeartBeat queue
sta >HBptr
sta >HBptr+2
sep #$20 ; 8 bit 'm'
dec a ; assume no Slot I/O
sta >SIOFlag
sta >MouseSlot ; no mouse either
rep #$20 ; 16 bit 'm'
jmp oEndCall0
ENDP
****************************************************************
*
* Return with miscellaneous tools version #
*
****************************************************************
MTVer PROC
RTL1 equ 1
RTL2 equ RTL1+3
Result equ RTL2+3
lda #version ; get MT version #
sta Result,s ; pass to caller
jmp oEndCall0
ENDP
****************************************************************
*
* Return with status that indicates the tool is active
*
****************************************************************
MTStatus PROC
rtl1 equ 1
rtl2 equ rtl1+3
ThisStatus equ rtl2+3
lda #$FFFF ; status = tool active
sta ThisStatus,s
jmp oEndCall0
ENDP
****************************************************************
*
* Dereference a Handle, and return with pointer in X and DBR.
*
* Inputs : MThandle contains handle to IDTAG block
* Output : DBR = Block addr (high), X=Block addr (low)
*
* NOTE : this trashes A, X, Y and D
*
****************************************************************
MTderef PROC
lda >MThandle ; get handle into X and A
tax
lda >MThandle+2
xba ; get bank into B
pha
plb ; remove trash
plb ; set bank to bank of pointer
lda |0,x ; get pointer (low)
ldy |2,x ; get pointer (high)
tax
tya
xba ; get bank into B
pha ; push bank + trash
plb ; remove trash
plb ; set bank = ptr (high)
rts
ENDP
****************************************************************
*
MTHandleStuff PROC
*
*
* Sets or returns the size of the MT handle.
*
*
* Inputs:
* none
*
* Outputs:
* a-reg Size of MTHandle
*
* External Refs:
* none
*
* Entry Points:
ENTRY GetMTHandleSize
ENTRY SetMTHandleSize
*
longa on ; mode
longi on
*
****************************************************************
GetMTHandleSize
pha
pha
lda >MThandle+2
pha
lda >MThandle
pha
_GetHandleSize
pla
plx
rts
SetMTHandleSize
pea 0000
pha
lda >MThandle+2
pha
lda >MThandle
pha
_SetHandleSize
rts
ENDP
title 'Battery Ram Routines'
****************************************************************
*
* Write battery ram
*
* Input LongWord Address
*
* Change History
*
* 29 January 87 Ray Montagne
*
* Since firmware cannot generate error on write we don't
* look for one to return
*
****************************************************************
WriteBRam PROC
OrigDir equ 1
rtl1 equ OrigDir+2
rtl2 equ rtl1+3
buffer equ rtl2+3
phd ; turn stack into zp
tsc
tcd
sep #$30 ; 8 bit 'm' & 'x'
longi off
ldy #0
ldx #0
MovLoop ;
lda [buffer],y ; get application data
sta >BramBuffer,x ; move to our buffer
dex
dey
bne movloop
sep #$30 ; 8 bit m/x
jsl ToWriteBram
rep #$30
longa on
longi on
jmp EndCall4
BramErr ;
ldx #firmTaskErr ; BRAM call failed
jmp ErrOut4
ENDP
****************************************************************
*
ReadBRam PROC
*
* Reads the page of battery RAM into the callers buffer.
*
*
* Inputs:
* BufferPtr : Long
*
* Outputs:
* none
*
* External Refs:
* none
*
* Entry Points:
* none
*
longa on ; mode
longi on
*
* Change History
*
* 17 Jun 88 Steven Glass
*
* This routine had always called the routine which did an actual
* read of the battery RAM. This is not necessary since the
* battery ram buffer is always correct before the read.
*
* Making this change we save the read time (1/10 second with
* interrupts off).
*
****************************************************************
OrigDir equ 1
rtl1 equ OrigDir+2
rtl2 equ rtl1+3
buffer equ rtl2+3
phd ; turn stack into zp
tsc
tcd
sep #$30 ; 8 bit 'm' and 'x'
longi off
longa off
ldx #0
ldy #0
movloop lda >BramBuffer,x ; data from bram buffer
sta [buffer],y ; to user buffer
dex
dey
bne movloop
rep #$30 ; 16 bit 'm' and 'x'
longa on
longi on
jmp EndCall4
ENDP
****************************************************************
*
WriteBParam PROC
*
* Takes the value from the stack, puts it into the BRam buffer
* and writes to the battery.
*
*
* Input word Data
* Input word Parameter #
*
* Outputs none
*
* External Refs:
import BParamIndexToTable
*
* Entry Points:
* none
*
longa on ; mode
longi on
*
* Change History
*
* 29 January 87 Ray Montagne
*
* Since firmware cannot generate error on write we don't
* look for one to return
*
* 10 Sep 88 Steven Glass
*
* Index number is directed through table, rather than being
* actual memory location in the BRAM.
*
* 14 Sep 88 Steven Glass
*
* Table index is only one byte wide so I mask result
*
****************************************************************
sep #$30
longa off
longi off
jsl ToReadBram ; read ram first
lda 7,s ; get parm index
and #$00FF
tax ; Turn index into buffer address
lda >BParamIndexToTable,x
and #$00FF
tax
lda 9,s ; get data
sta >BramBuffer,x ; move to BRAM buffer
jsl ToWriteBram ; now write ram
rep #$30
longa on
longi on
jmp oEndCall4
ENDP
****************************************************************
*
ReadBParam PROC
*
* Returns the specified byte from the battery RAM on the stack.
*
*
* Inputs:
* Space for result : word
* ID of Parameter to read : word
*
* Outputs:
* Parameter value : word
*
* External Refs:
import BParamIndexToTable
*
* Entry Points:
* none
*
longa on ; mode
longi on
*
* Change History
*
* 17 Jun 88 Steven Glass
*
* This routine had always called the routine which did an actual
* read of the battery RAM. This is not necessary since the
* battery ram buffer is always correct before the read.
*
* Making this change we save the read time (1/10 second with
* interrupts off).
*
* 10 Sep 88 Steven Glass
*
* Index number is directed through table, rather than being
* actual memory location in the BRAM
*
*
* 14 Sep 88 Steven Glass
*
* Table index is only one byte wide so I mask result
*
*
****************************************************************
DefineStack
RTL1 block 3
RTL2 block 3
ParamID word
ResultValue word
lda ParamID,s ; get parm index
and #$00FF
tax ; Turn index into buffer address
lda >BParamIndexToTable,x
and #$00FF
tax
lda >BramBuffer,x ; move from BRAM buffer
and #$00FF
sta ResultValue,s
jmp oEndCall2
ENDP
****************************************************************
*
BParamIndexToTable PROC
*
* This is a table of addresses in the battery RAM. The
* zeroth entry gives the address of item 0 in the RAM. The
* next entry gives the address of the next item, etc.
*
****************************************************************
dc.b $00 ; $00 Port Type for Port 1
dc.b $01 ; $01 Line Length
dc.b $02 ; $02 Delete First LF after CR
dc.b $03 ; $03 Add LF after CR
dc.b $04 ; $04 Echo
dc.b $05 ; $05 Buffering
dc.b $06 ; $06 Baud
dc.b $07 ; $07 Parity
dc.b $08 ; $08 Data/Stop Bits
dc.b $09 ; $09 DCD Handshake
dc.b $0A ; $0A DSR/DTR Handshake
dc.b $0B ; $0B XON/XOFF Handshake
dc.b $0C ; $0C Port Type for Port 2
dc.b $0D ; $0D Line Length
dc.b $0E ; $0E Delete First LF after CR
dc.b $0F ; $0F Add LF after CR
dc.b $10 ; $10 Echo
dc.b $11 ; $11 Buffering
dc.b $12 ; $12 Baud
dc.b $13 ; $13 Parity
dc.b $14 ; $14 Data/Stop Bits
dc.b $15 ; $15 DCD Handshake
dc.b $16 ; $16 DSR/DTR Handshake
dc.b $17 ; $17 XON/XOFF Handshake
dc.b $18 ; $18 Display Type
dc.b $19 ; $19 Columns
dc.b $1A ; $1A Text Color
dc.b $1B ; $1B Background Color
dc.b $1C ; $1C Border Color
dc.b $1D ; $1D Display Cycle Rate (Hertz)
dc.b $1E ; $1E Volume
dc.b $1F ; $1F Pitch
dc.b $20 ; $20 Speed
dc.b $58 ; $21 Fake Slot 1
dc.b $22 ; $22 Slot 2
dc.b $23 ; $23 Slot 3
dc.b $24 ; $24 Slot 4
dc.b $25 ; $25 Slot 5
dc.b $26 ; $26 Slot 6
dc.b $27 ; $27 Slot 7
dc.b $28 ; $28 Startup Slot
dc.b $29 ; $29 Display Language
dc.b $2A ; $2A Keyboard Layout
dc.b $2B ; $2B Keyboard Buffering
dc.b $2C ; $2C Repeat Speed
dc.b $2D ; $2D Repeat Delay
dc.b $3A ; $2E Double Click
dc.b $2E ; $2F Cursor Flash
dc.b $2F ; $30 Shift Caps/Lower Case
dc.b $30 ; $31 Fast Space & Delete keys
dc.b $31 ; $32 Dual Speed Keys
dc.b $39 ; $33 Mouse Tracking
dc.b $34 ; $34 Date Format
dc.b $35 ; $35 Time Format
dc.b $36 ; $36 Min Ram Disk Size
dc.b $37 ; $37 Max Ram Disk Size
dc.b $3E ; $38 Number of Languages
dc.b $3F ; $39 First Language
dc.b $40 ; $3A Second Language
dc.b $41 ; $3B Third Language
dc.b $42 ; $3C Fourth Language
dc.b $43 ; $3D Fifth Language
dc.b $44 ; $3E Sixth Language
dc.b $45 ; $3F Seventh Language
dc.b $46 ; $40 Eightth Language
dc.b $47 ; $41 Number of Layouts
dc.b $48 ; $42 First Layout
dc.b $49 ; $43 Second Layout
dc.b $4A ; $44 Third Layout
dc.b $4B ; $45 Fourth Layout
dc.b $4C ; $46 Fifth Layout
dc.b $4D ; $47 Sixth Layout
dc.b $4E ; $48 Seventh Layout
dc.b $4F ; $49 Eightth Layout
dc.b $50 ; $4A Ninth Layout
dc.b $51 ; $4B Tenth Layout
dc.b $52 ; $4C Eleventh Layout
dc.b $53 ; $4D Twelvth Layout
dc.b $54 ; $4E Thirteenth Layout
dc.b $55 ; $4F Fourteenth Layout
dc.b $56 ; $50 Fifteenth Layout
dc.b $57 ; $51 Sixteenth Layout
dc.b $32 ; $52 Disk Eject 1
dc.b $33 ; $53 Disk Eject 2
dc.b $38 ; $54 Reset RAM at next Reset
dc.b $3B ; $55 Delay To Start
dc.b $3C ; $56 Acceleration
dc.b $3D ; $57 Maximum Speed
dc.b $58 ; $58 new Slot 1
dc.b $59 ; $59
dc.b $5A ; $5A
dc.b $5B ; $5B
dc.b $5C ; $5C
dc.b $5D ; $5D
dc.b $5E ; $5E
dc.b $5F ; $5F
dc.b $60 ; $60
dc.b $61 ; $61
dc.b $62 ; $62
dc.b $63 ; $63
dc.b $64 ; $64
dc.b $65 ; $65
dc.b $66 ; $66
dc.b $67 ; $67
dc.b $68 ; $68
dc.b $69 ; $69
dc.b $6A ; $6A
dc.b $6B ; $6B
dc.b $6C ; $6C
dc.b $6D ; $6D
dc.b $6E ; $6E
dc.b $6F ; $6F
dc.b $70 ; $70
dc.b $71 ; $71
dc.b $72 ; $72
dc.b $73 ; $73
dc.b $74 ; $74
dc.b $75 ; $75
dc.b $76 ; $76
dc.b $77 ; $77 Reserved
dc.b $78 ; $78 PassWord
dc.b $79 ; $79 PassWord
dc.b $7A ; $7A PassWord
dc.b $7B ; $7B PassWord
dc.b $7C ; $7C PassWord
dc.b $7D ; $7D PassWord
dc.b $7E ; $7E PassWord
dc.b $7F ; $7F PassWord
dc.b $80 ; $80 AppleTalk Node Number
dc.b $81 ; $81 OS Variables
dc.b $82 ; $82
dc.b $83 ; $83
dc.b $84 ; $84
dc.b $85 ; $85
dc.b $86 ; $86
dc.b $87 ; $87
dc.b $88 ; $88
dc.b $89 ; $89
dc.b $8A ; $8A
dc.b $8B ; $8B
dc.b $8C ; $8C
dc.b $8D ; $8D
dc.b $8E ; $8E
dc.b $8F ; $8F
dc.b $90 ; $90
dc.b $91 ; $91
dc.b $92 ; $92
dc.b $93 ; $93
dc.b $94 ; $94
dc.b $95 ; $95
dc.b $96 ; $96
dc.b $97 ; $97
dc.b $98 ; $98
dc.b $99 ; $99
dc.b $9A ; $9A
dc.b $9B ; $9B
dc.b $9C ; $9C
dc.b $9D ; $9D
dc.b $9E ; $9E
dc.b $9F ; $9F
dc.b $A0 ; $A0
dc.b $A1 ; $A1
dc.b $A2 ; $A2
dc.b $A3 ; $A3
dc.b $A4 ; $A4
dc.b $A5 ; $A5
dc.b $A6 ; $A6
dc.b $A7 ; $A7
dc.b $A8 ; $A8
dc.b $A9 ; $A9
dc.b $AA ; $AA
dc.b $AB ; $AB
dc.b $AC ; $AC
dc.b $AD ; $AD
dc.b $AE ; $AE
dc.b $AF ; $AF
dc.b $B0 ; $B0
dc.b $B1 ; $B1
dc.b $B2 ; $B2
dc.b $B3 ; $B3
dc.b $B4 ; $B4
dc.b $B5 ; $B5
dc.b $B6 ; $B6
dc.b $B7 ; $B7
dc.b $B8 ; $B8
dc.b $B9 ; $B9
dc.b $BA ; $BA
dc.b $BB ; $BB
dc.b $BC ; $BC
dc.b $BD ; $BD
dc.b $BE ; $BE
dc.b $BF ; $BF OS Variables
dc.b $C0 ; $C0 Reserved
dc.b $C1 ; $C1
dc.b $C2 ; $C2
dc.b $C3 ; $C3
dc.b $C4 ; $C4
dc.b $C5 ; $C5
dc.b $C6 ; $C6
dc.b $C7 ; $C7
dc.b $C8 ; $C8
dc.b $C9 ; $C9
dc.b $CA ; $CA
dc.b $CB ; $CB
dc.b $CC ; $CC
dc.b $CD ; $CD
dc.b $CE ; $CE
dc.b $CF ; $CF
dc.b $D0 ; $D0
dc.b $D1 ; $D1
dc.b $D2 ; $D2
dc.b $D3 ; $D3
dc.b $D4 ; $D4
dc.b $D5 ; $D5
dc.b $D6 ; $D6
dc.b $D7 ; $D7
dc.b $D8 ; $D8
dc.b $D9 ; $D9
dc.b $DA ; $DA
dc.b $DB ; $DB
dc.b $DC ; $DC
dc.b $DD ; $DD
dc.b $DE ; $DE
dc.b $DF ; $DF
dc.b $E0 ; $E0
dc.b $E1 ; $E1
dc.b $E2 ; $E2
dc.b $E3 ; $E3
dc.b $E4 ; $E4
dc.b $E5 ; $E5
dc.b $E6 ; $E6
dc.b $E7 ; $E7
dc.b $E8 ; $E8
dc.b $E9 ; $E9
dc.b $EA ; $EA
dc.b $EB ; $EB
dc.b $EC ; $EC
dc.b $ED ; $ED
dc.b $EE ; $EE
dc.b $EF ; $EF
dc.b $F0 ; $F0
dc.b $F1 ; $F1
dc.b $F2 ; $F2
dc.b $F3 ; $F3
dc.b $F4 ; $F4
dc.b $F5 ; $F5
dc.b $F6 ; $F6
dc.b $F7 ; $F7
dc.b $F8 ; $F8
dc.b $F9 ; $F9
dc.b $FA ; $FA
dc.b $FB ; $FB Reserved
dc.b $FC ; $FC Check Sum
dc.b $FD ; $FD Check Sum
dc.b $FE ; $FE Check Sum
dc.b $FF ; $FF Check Sum
ENDP
title 'Time Routines'
****************************************************************
*
* RdTimeHex:
* Input Word Space for result
* Input Word Space for result
* Input Word Space for result
* Input Word Space for result
* Output Byte Year
* Output Byte Month (0...11)
* Output Byte Day (0...30)
* Output Byte Hour (0...23)
* Output Byte Minute (0...59)
* Output Byte Second (0...59)
* Output Byte Null
* Output Byte Day of Week (0....6)
*
****************************************************************
RdTimeHex PROC
D0 equ $E103E9
D1 equ D0+4
D2 equ D1+4
D3 equ D2+4
D4 equ D3+4
OrigDir equ 1
OrigDBR equ OrigDir+2
OrigP equ OrigDBR+1
rtl1 equ OrigP+1
rtl2 equ rtl1+3
Second equ rtl2+3
Minute equ Second+1
Hour equ Minute+1
Year equ Hour+1
Day equ Year+1
Month equ Day+1
null equ Month+1
WkDay equ Null+1
WSsize equ 10 ; 10 words - DUMMY !!!
sep #$30 ; off to 8 bit land
jsl ToReadTime ; read clock
rep #$30 ; then back to 16 bit land
bcc GotTimeOK ; if read clock
ldx #firmTaskErr ; set error flag
jmp oErrOut0
*
* now convert Binary time to Hex time format
*
GotTimeOK ;
php ; save interrupt state
sei ; and disable interrupts
phb ; save data bank
pea $E1E1 ; and set to our data area
plb
plb
phd ; save direct page
tsc ; turn stack into zp
tcd
*
* Have number of seconds N 1984 in ClkRData.
* DN = number of days elapsed = N div 86400
* HMS = number of seconds in last day = N mod 86400
*
pea $0000 ; space for result
pea $0000
pea $0000
pea $0000
lda |ClkRData+2 ; numerator = N
pha
lda |ClkRData
pha
pea $0001 ; Denom = 86400
pea $5180
jsl ToLDivide ; want DN
pla ; DN = quotient
sta |D0
sta |D2 ; and make a copy in D2
pla
sta |D0+2
sta |D2+2
pla ; HMS = remainder
sta |D1
pla
sta |D1+2
*
* YearsGone = (DN * 4) div 1461 where 1461 is 4 * 365 + 1
* Formula depends on leap year being the first of the four.
*
asl |D2 ; DN * 4
rol |D2+2
asl |D2
rol |D2+2
pea $0000 ; space for result
pea $0000
pea $0000
pea $0000
lda |D2+2 ; YearsGone = (DN*4) div 1461
pha
lda |D2
pha
pea $0000 ; 1461 = $000005B5
pea $05B5
jsl ToLDivide
clc ; YG referenced to 1904
pla
sta |D2
adc #0004
sep #$20 ; 8 bit 'm'
sta year
rep #$20 ; 16 bit 'm'
clc
lda |D2
adc #1904
sta |D2 ; hex year
pla
sta |D2+2
*
* Need number of days in Jan+Feb just below.
* Take YEAR mod 3 before clearing year.
*
lda #59 ; assume not leap year
sta |D3
stz |D3+2
lda #3 ; Year MOD 3
and |D2
bne NotLeap
inc |D3
NotLeap ;
pla ; DOY * 4 in D2
sta |D2
pla
sta |D2+2 ; DOY = D2 div 4
lsr |D2+2
ror |D2
lsr |D2+2
ror |D2 ; DOY in D2
*
* Computing Month/Day from DOY is an exercise in interpolation.
* As a function of DOY, Month is a step function. Because of
* the leap year glitch, convenient to restart function at March
*
* DOY MONTH
*--------------------------------------------------------------
* 0-31 1 January
* 31-58 2 February for non leap year
* 31-59 2 February for leap year
* 0-30 3 March
* 31-60 4 April
* 61-91 5 May
* 92-121 6 June
* 122-152 7 July
* 153-183 8 August
* 184-213 9 September
* 214-244 10 October
* 245-274 11 November
* 275-305 12 December
*
* The linear interpolator is ((DOY * 128) + 71) div 3919
*
lda #1 ; month offset, 1 or 3
sta |D4
lda |D2 ; 59/60 versus DOY
cmp |D3
blt JanFeb ; less than means Jan or Feb
inc |D4 ; else adjust month offset
inc |D4
sec ; start DOY at march
lda |D2
sbc |D3
sta |D2
lda |D2+2
sbc |D3+2
sta |D2+2
JanFeb ;
ldy #7 ; DOY * 128
MultDOY ;
asl |D2
rol |D2+2
dey
bne MultDOY
pea $0000 ; space for result
pea $0000
clc ; (DOY * 128) + 71
lda #71
adc |D2
sta |D2
pha ; NUM = (DOY * 128) + 71
lda #0
adc |D2+2
sta |D2+2
pea $0F4F ; DEN = 3919
jsl ToUDivide
clc
pla ; month = Quot + MOffset
adc |D4
sta |D2+2 ; D2 (MSB) = Month (1..12)
sep #$20 ; 8 bit 'm'
dec a ; make month (0.....11)
sta Month
rep #$20 ; 16 bit 'm'
pla ; divide by 128 to get DOM
ldy #7
DivDOM ;
lsr a
dey
bne DivDOM
sep #$20 ; 8 bit 'm'
sta Day ; day (0....30)
rep #$20
*
* Hours = HMS div 3600
* MS = HMS mod 3600
* Minutes = MS div 60
* Seconds = MS mod 60
*
pea $0000 ; space for result
pea $0000
pea $0000
pea $0000
lda |D1+2 ; Numerator = HMS
pha
lda |D1
pha
pea $0000 ; Denominator = 3600
pea $0E10
jsl ToLDivide
pla
plx ; Hours = Quot
sep #$20 ; 8 bit 'm'
sta Hour
rep #$20
pla ; MS = remainder
plx
pea $0000 ; space for result
pea $0000
pha ; Numerator = MS
pea $003C ; Denominator = 60
jsl ToUDivide
pla ; Minutes = Quot
sep #$20 ; 8 bit 'm'
sta Minute
pla
sta Second
pla ; clean up
rep #$30 ; 16 bit 'm'
*
* Finally get the day of week = ((DN + 5) mod 7) + 1
* The 5 is added since 1 Jan 1904 was a Friday.
*
pea $0000 ; space for divide
pea $0000
pea $0000
pea $0000
clc
lda #5 ; DN+5
adc D0
tax
lda #0
adc D0+2
pha
phx
pea $0000
pea $0007
jsl ToLDivide ; ((DN + 5) mod 7)
pla
pla
pla ; Get DOW-1
inc a ; ((DN + 5) mod 7) + 1
plx
sep #$20 ; 8 bit 'm'
sta WkDay ; store day of week
rep #$20 ; 16 bit 'm'
pld ; restore direct page
plb ; restore data area
plp ; restore interrupt state
jmp oEndCall0 ; all done
ENTRY ToLDivide
ToLDivide ;
jsl LongDiv
rtl
ENTRY ToUDivide
ToUDivide ;
jsl UDivide
rtl
ENDP
****************************************************************
*
* WrTimeHex:
*
* Input Byte second (0.....59)
* Input Byte Minute (0.....59)
* Input Byte Hour (0.....23)
* Input Byte Day (0.....30)
* Input Byte Month (0.....11)
* Input Byte Year
*
* Change History
*
* February 18, 1987 Ray Montagne
*
* Wrong error code was being returned.
*
****************************************************************
WrTimeHex PROC
D0 equ $E103E9
D1 equ D0+4
D2 equ D1+4
D3 equ D2+4
D4 equ D3+4
OrigDir equ 1
OrigDBR equ OrigDir+2
OrigP equ OrigDBR+1
rtl1 equ OrigP+1
rtl2 equ rtl1+3
Second equ rtl2+3
Minute equ Second+1
Hour equ Minute+1
Year equ Hour+1
Day equ Year+1
Month equ Day+1
WSsize equ 10 ; is 20 bytes workspace area
php ; save interrupt state
sei ; and disable IRQ
phb ; save data area
pea $E1E1 ; set our own
plb
plb
phd ; save direct page
tsc ; set stack = zp
tcd
sep #$30 ; 8 bit 'm' and 'x'
longa off
longi off
phb ; save DBR for bounds chk
phk ; set DBR to code segment
plb
ldy Month ; get month
lda Year ; get year
and #3 ; leap year?
bne DayCheck ; no
cpy #1 ; if yes, is it February?
bne DayCheck ; no
ldy #12 ; if February & leap year
DayCheck ;
lda Day ; and day
cmp MonthLen,y ; check valid day ?
rep #$30 ; 16 bit 'm' and 'x'
longa on
longi on
bcc DayOK ; if valid
plb
pld ; restore direct page
plb ; and data bank
plp ; restore interrupt state
ldx #badInputErr ; bad input parm error changed 18 Feb
; ; 87 by RBM
jmp oErrOut6
DayOK ;
plb ; restore DBR
*
* Have Year/Month/Day/Hour/Minute/Second in a sequence of words
* in direct page.
*
* DAYSGONE * 86400 + HOURS * 3600 + MINUTES * 60 + SECONDS
*
* Do the easy part with HOURS, MINUTES, and SECONDS.
*
pea $0000 ; space for result
pea $0000
pea $0000
pea $0000
lda Hour ; Convert hour to minutes
and #$00FF
pha
pea $003C ; Hour * 60
jsl ToMult
clc
lda Minute ; (Hour * 60) + Minute
and #$00FF
adc 1,s
sta 1,s
lda #0
adc 3,s
sta 3,s
pla
plx
pha
pea $003C ; ((Hour * 60) + Minute) * 60
jsl ToMult
clc
lda Second ; now add in seconds
and #$00FF
adc 1,s
sta 1,s
lda #0
adc 3,s
sta 3,s
pla ; and store in D0
sta |D0
pla
sta |D0+2
*
* Compute DAYSGONE in D1
*
lda Day ; Days
and #$00FF ; have day (0.......30)
sta |D1
stz |D1+2
lda Month ; get Month
and #$00FF ; have Month (0.....11)
inc a ; make Month (1.....12)
sta |D2
stz |D2+2
lda Year ; and Year
and #$00FF
clc
adc #1900
sta |D3
sta |D4 ; copy year for LEAP test
stz |D3+2
stz |D4+2
*
* To find number of days in elapsed years use:
* ((YEARSGONE * 1461) + 3) div 4
* Formula depends on leap year being the first of 4.
*
sec ; years gone
lda |D3
sbc #1904
sta |D3
pea $0000 ; space for result
pea $0000
pha ; YearsGone * 1461
pea $05B5
jsl ToMult
clc
lda #3 ; (YearsGone * 1461) + 3
adc 1,s
sta 1,s
lda #0
adc 3,s
lsr a ; ((YG * 1461) + 3) div 4
sta 3,s
lda 1,s
ror a
sta 1,s
lda 3,s
lsr a
sta 3,s
sta |D3+2
lda 1,s
ror a
sta 1,s
sta |D3
pla ; accumulate days gone
clc
adc |D1
sta |D1
pla
adc |D1+2
sta |D1+2 ; D1 = DAYSGONE
*
* As above, the tough part is finding the number of days in
* elapsed months.
*
dec |D2 ; month-1 (ranges 0..11)
lda |D2 ; 2 or more is March
cmp #2
blt DSJanFeb
dec |D2 ; Month-3 (Restart at March)
dec |D2
lda #59 ; Days in Jan + Feb
sta |D3
lda |D4 ; Check for leap year, MOD 3
and #3
bne DSNotLeap ; if not leap year
inc |D3 ; Leap Days in Jan + Feb
DSNotLeap ;
clc
lda |D3 ; some more elapsed days
adc |D1
sta |D1
DSJanFeb ;
pea $0000 ; space for result
pea $0000
lda |D2 ; Month * 3917
pha
lda #3917
pha
jsl ToMult
clc
lda #52 ; (Month * 3917) + 52
adc 1,s
sta 1,s
lda #0
adc 3,s
sta 3,s
pla
sta |D2
pla
sta |D2+2
ldy #7 ; ((Month * 3917) + 52 div 128
Div128 ;
lsr |D2+2
ror |D2
dey
bne Div128
clc
lda |D1 ; more elapsed days
adc |D2
sta |D1
lda |D1+2
adc |D2+2
sta |D1+2
*
* Finally multiply the number of days elapsed by
* 24 * 60 * 60 = 86400 = 43200 * 2
*
pea $0000 ; space for result
pea $0000
pea $A8C0 ; (43200)
lda |D1
pha
jsl ToMult
lda 1,s ; (43200 * 2)
asl a
sta 1,s
lda 3,s
rol a
sta 3,s
clc
pla
adc |D0
sta |ClkWData ; store to set time
pla
adc |D0+2
sta |ClkWData+2
sep #$30 ; off to 8 bit land
jsl ToWriteTime ; set the clock
rep #$30 ; back to 16 bit land
pld ; restore direct page
plb ; restore data area
rol a ; save carry
plp ; restore interrupt state
ror a ; and restore carry
bcs WrHexErr ; if can't write time
jmp oEndCall6 ; else cleanup & return
WrHexErr ;
ldx #firmTaskErr ; set error flag
jmp oErrOut6 ; and return with error
ENTRY ToMult
ToMult ;
jsl Multiply
rtl
MonthLen ;
DC.B 31 ; days in January
DC.B 28 ; days in Febuary (non-leap)
DC.B 31 ; days in March
DC.B 30 ; days in April
DC.B 31 ; days in May
DC.B 30 ; days in June
DC.B 31 ; days in July
DC.B 31 ; days in August
DC.B 30 ; days in September
DC.B 31 ; days in October
DC.B 30 ; days in November
DC.B 31 ; days in December
DC.B 29 ; days in February (leap)
ENDP
****************************************************************
*
* RdATime:
*
* Input LongWord Buffer address
*
* Format of data in buffer is dependent on the values set
* in the battery ram for time and date format.
*
* Date Format Time Format ASCII Format
* ----------- ----------- -----------------------
* 0 0 mm/dd/yy HH:MM:SS AM-PM
* 1 0 dd/mm/yy HH:MM:SS AM-PM
* 2 0 yy/mm/dd HH:MM:SS AM-PM
* 0 1 mm/dd/yy HH:MM:SS
* 1 1 dd/mm/yy HH:MM:SS
* 2 1 yy/mm/dd HH:MM:SS
*
* where : HH = Hour
* MM = Minute
* SS = Second
* mm = Month
* dd = Day
* yy = Year
*
****************************************************************
RdATime PROC
OrigDir equ 1
OrigDBR equ OrigDir+2
rtl1 equ OrigDBR+1
rtl2 equ rtl1+3
pointer equ rtl2+3
NewDir equ 1
Second equ NewDir+2
Minute equ Second+1
Hour equ Minute+1
Year equ Hour+1
Day equ Year+1
Month equ Day+1
Null equ Month+1
WkDay equ Null+1
phb ; save data area
phd ; save direct page
tsc ; turn stack into zp
tcd
pea $0000 ; setup for RdHexTime
pea $0000
pea $0000
pea $0000
jsl ToRdHexT ; now go get it
bcc NoAtimeErr ; if no error
jmp ATimeErr ; if can't get it
*
* Now convert HEX time to ascii time and send to buffer
*
NoAtimeErr ;
ldx Pointer ; get pointer to App. Buffer
sep #$20 ; 8 bit 'm'
longa off
lda Pointer+2
pha ; set App. Buffer bank
plb
phd ; save new dir
tsc ; and make stack into zp
tcd
lda #$A0 ; time/date delimiter
sta |8,x
sta |17,x
lda >UserAMPM ; get time format
rep #$20 ; 16 bit 'm'
longa on
php ; time format in Z flag
ldy #$A0A0 ; assume 24 hour format
lda Hour ; get hour
plp ; Z=1 says 12 hour format
bne Fmt24 ; else 24 hour format
ldy #$CDC1 ; assume AM
and #$00FF ; truncate hour
cmp #12 ; hour less than 12?
blt StillAM ; if yes, then still AM
ldy #$CDD0 ; else set PM
StillAM ;
cmp #13 ; if > 13:00 then subtract 12
blt H0TO12 ; yes
sec ; else hour=hour-12
sbc #12
bra Fmt24
H0TO12 ;
cmp #0 ; if zero, make it 12
bne Fmt24 ; but if its not, dont
lda #12 ;
Fmt24 ;
jsr HexToAscii ; convert hour to ascii
sta |9,x ; stuff into App. Buffer
tya ; now set time format
sta |18,x
lda Minute ; convert minute
jsr HexToAscii
sta |12,x ; stuff into App. buffer
lda Second ; convert seconds
jsr HexToAscii
sta |15,x ; stuff into app. buffer
lda Month ; convert month
inc a ; 0=Jan
jsr HexToAscii
sta |0,x ; stuff into app. buffer
lda Day ; convert day
inc a ; 0=first day of month
jsr HexToAscii
sta |3,x ; stuff into app. buffer
lda Year ; convert Year
jsr HexToAscii
sta |6,x ; stuff into app. buffer
sep #$20 ; 8 bit 'm'
longa off
lda #$BA ; time delimiter
sta |11,x
sta |14,x
lda #$AF ; date delimiter
sta |2,x
sta |5,x
*
* Now blank all leading zeros
*
ldy #$A0 ; Yreg = ' '
lda |9,x ; first check hours
cmp #$B0 ; is it a zero ?
bne NoHrsZ ; no
tya
sta |9,x ; blank leading zero
NoHrsZ ;
lda |0,x ; now check month
cmp #$B0 ; is it a zero ?
bne NoMoZ ; no
tya
sta |0,x ; else blank leading zero
NoMoZ ;
lda |3,x ; now check day
cmp #$B0 ; is it a zero ?
bne NoDayZ ; no
tya ; else blank leading zero
sta |3,x
NoDayZ ;
lda >UserDATE ; get DATE format
rep #$20 ; 16 bit 'm'
longa on
beq DateFmt0 ; mm/dd/yy HH:MM:SS
and #$00FF ; limit options
pha
lda |3,x ; swap month and year
tay ; Yreg = dd
lda |0,x
sta |3,x
tya
sta |0,x ; dd/mm/yy
pla
dec a ; format 2?
beq DateFmt0 ; no
lda |6,x ; now swap year and day
sta |0,x
tya
sta |6,x
DateFmt0 ;
pld ; clean up stack
pla
pla
pla
pla
pld ; restore direct page
plb ; and data area
jmp oEndCall4 ; clean up and return
ATimeErr ;
pla ; clean up stack
pla
pla
pla
pld ; restore direct page
plb ; restore DBR
ldx #firmTaskErr ; set error flag
jmp oErrOut4 ; and return with error
ToRdHexT ;
jsl RdTimeHex ; go read HEX time
rtl
ENDP
****************************************************************
*
* Convert Hex to Ascii
*
* Input passed in low byte of 16 bit A register
* Output returned in 16 bit A register (Most significant in
* digit is in low byte of register. Both the X and Y registers
* are preserved.
*
****************************************************************
HexToAscii PROC
OrigDir equ 1
OrigY equ OrigDir+2
OrigX equ OrigY+2
Decimal equ OrigX+2
pha ; input data to convert
phx ; save App. buffer pointer
phy ; and this too!!!
phd ; save direct page
tsc ; turn stack into zp
tcd
sep #$30 ; 8 bit 'm' and 'x'
longa off
longi off
ldy #$02 ; number of times through loop
DecAsc1 ;
ldx #9 ; 8 bit and 1st time do nothing
lda #0
clc ; C=0 so 1st ROL leaves A=0
DecAsc2 ;
rol a
cmp #10 ; A >= 10 ?
blt DecAsc4 ; if <
sbc #10 ; C=1 from CMP and is left set
DecAsc4 ;
rol Decimal
dex
bne DecAsc2
ora #$B0 ; make an ASCII character
pha ; preserve on stack
dey
bne DecAsc1
rep #$30 ; 16 bit 'm' and 'x'
longa on
longi on
pla ; returned data
sta Decimal
pld ; clean up and r
ply ; restore pointer
plx ; restore App. buffer pointer
pla ; returned data in A reg
rts
ENDP
title 'Vector Routines'
****************************************************************
*
* SetVector (RefNum : integer; NewAdr : Long);
*
* Change History
*
* 26 Jul 88 Steven Glass
*
* Interrupts disabled during access.
*
* 23 Feb 89 Mensch
*
* Removed error checking.
****************************************************************
SetVector PROC
RTL1 equ 1
RTL2 equ RTL1+3
NewAdr equ RTL2+3
RefNum equ NewAdr+4
VTblLen equ $002D
lda RefNum,s ;get reference
and #$00FF ;mask excess
; Error checking removed 2/23/89
; cmp #VTblLen
; bge AnError ;if out of bounds
asl a ;and make index
asl a
tax
php
sei
lda NewAdr-1+1,s ;get vector addr 0-7
and #$FF00 ;patch 'JML' opcode in low byte
ora #$005C
sta >Dispatch1,x ;set A0-7 & op
lda NewAdr+1+1,s ;get addr 8-23
sta >Dispatch1+2,x ;set addr 8-23
plp
jmp oEndCall6
AnError ldx #badInputErr
jmp oErrOut6
ENDP
****************************************************************
*
* GetVector (RefNum : integer; NewAdr : Long);
*
* Change History
*
* 26 Jul 88 Steven Glass
*
* Interrupts disabled during access.
*
* 23 Feb 89 Mensch
*
* Removed error checking.
****************************************************************
GetVector PROC
RTL1 equ 1
RTL2 equ RTL1+3
RefNum equ RTL2+3
Result equ RefNum+2
VTblLen equ $002D
lda RefNum,s ;get reference
and #$00FF ;mask excess
; Error checking removed 2/23/89
; cmp #VTblLen
; bge AnError ;if out of bounds
asl a ;and make index
asl a
tax
php
sei
lda >Dispatch1+1,x
sta Result+1,s
lda >Dispatch1+3,x
and #$00FF
sta Result+2+1,s
plp
jmp oEndCall2
AnError ldx #badInputErr
jmp oErrOut2
ENDP
title 'Heartbeat Routines'
****************************************************************
*
* Set System Heartbeat Vector
* Input LongWord Address
*
* Possible errors are :
* 3 = Task error (task already in queue)
* 4 = Header error (no signature in new task)
* 5 = Queue error (queue got trashed - system fatal)
* 6 = Task Not Found
*
****************************************************************
SetHeart PROC
OrigD equ 1
RTL1 equ OrigD+2
RTL2 equ RTL1+3
VPtr equ RTL2+3
phd
tsc ; make stack into zp
tcd
php ; save IRQ enbl status
sei ; 'cuz no interrupts for now !
lda #Irq_Heart ; install heartbeat handler
pha
xba
and #$FF00
ora #$005C ; opcode = jmp al
sta >Irq_VBL ; install JMP opcode and addrl
pla
and #$FF00
ora #^Irq_Heart
xba
sta >Irq_VBL+2 ; install addrm & addrh
phb
Sep #$20 ; 8 bit 'm'
lda Vptr+2 ; make pointer to task header
pha
plb
rep #$30 ; 16 bit 'm'
lda Vptr
tax
lda |6,x ; check task header signature
cmp #$A55A
beq QueOK ; no problem with new task
BadQue ;
ldx #$0304 ; flag bad queue signature
brl HdrErr
QueOK ;
lda >HBptr ; check if task in queue
cmp Vptr
bne DoFirst ; if not, install it
lda >HBptr+2
cmp Vptr+2
bne DoFirst
ldx #taskInstlErr ; else flag task error
bra HdrErr
DoFirst ;
lda >HBptr ; get heartbeat vector
ora >HBptr+2 ; is it the first one
bne GrowChain ; nope
lda VPtr ; get addrl
sta >HBptr ; set the first one
lda VPtr+2
sta >HBptr+2
sep #$20 ; 8 bit m
lda >HBptr+2 ; point at next entry
pha
plb
rep #$20 ; 16 bit m
lda >HBptr
tax
SetLast ;
lda #0
sta |0,x ; set last link flag
sta |2,x
ExitHB ;
plb
plp ;
jmp EndCall4
GrowChain ;
sep #$20 ; 8 bit m
lda >HBptr+2 ; point at first entry
pha
plb
rep #$20 ; 16 bit m
lda >HBptr
tax
ChkChain ;
lda |6,x ; check queue signature
cmp #$A55A
beq QueueOK ; no problem
ldx #5 ; else flag queue trashed
bra HdrErr
QueueOK ;
lda |0,x ; check if task already exists
cmp vptr
bne taskok ; it's not the same task
lda |2,x
cmp vptr+2
bne taskok ; it's not the same task
ldx #taskInstlErr ; task error
HdrErr ;
plb ; clean up stack
plp
jmp ErrOut4
TaskOK ;
lda |0,x ; is this the end of the queue
ora |2,x
beq GrowHere ; yes, now insert next task
sep #$20 ; 8 bit 'm' to move down queue
lda |2,x ; point at next one
pha
rep #$20 ; 16 bit m
lda |0,x
tax
plb
bra ChkChain ; search for last one
GrowHere ;
lda vptr+2 ; insert link address
sta |2,x
lda vptr
sta |0,x
tax ; point at next link
sep #$20 ; 8 bit m
longa off
lda Vptr+2
pha
plb
rep #$20 ; 16 bit m
longa on
bra SetLast ; set last link flag
ENDP
****************************************************************
*
* Delete System Heartbeat Vector
* Input LongWord Address
*
* Change History
*
* 26 Jul 88 Steven Glass
*
* Try and turn off vbl interrupts.
*
****************************************************************
DelHeart PROC
import KillIntsIfCan
OrigDir equ 1
RTL1 equ OrigDir+2
RTL2 equ RTL1+3
Vptr equ RTL2+3
phd
tsc ; turn stack into zp
tcd
php ; save interrupt enable status
sei ; no interrupts for now
phb
sep #$20 ; 8 bit m
longa off
lda #^HBptr ; point at link addr
pha
plb
rep #$20 ; 16 bit m
longa on
ldx #HBptr**$FFFF
lda |0,x ; is queue empty ?
ora |2,x
beq DelErr0
rep #$20 ; 16 bit 'm'
lda |0,x ; is the first one it ?
cmp vptr
bne notfirst
sep #$20 ; 8 bit 'm'
lda |2,x
cmp vptr+2
bne notfirst
phb ; save current queue pointer
phx
pha
rep #$20 ; 16 bit 'm'
lda |0,x ; point at task
tax
plb
lda |2,x ; get task's link pointer
tay
lda |0,x
plx ; restore queue pointer
plb
sta |0,x ; make new first link
tya
sta |2,x
bra DelDone ; all done
DelErr0 ;
bra DelErr
notfirst ;
sep #$20 ; 8 bit 'm'
lda |2,x
pha ; point at first link
rep #$20
lda |0,x
tax
plb
DelSrch ;
lda |6,x ; check task signature
cmp #$A55A
beq QueueOK ; no problem
ldx #queueDmgdErr ; else queue error
plb
plp
jmp ErrOut4
QueueOK ;
lda |0,x ; is this the last link ?
ora |2,x
beq DelErr ; yes, didnt find kaka
lda |0,x ; is the next link the target
cmp Vptr
bne DelSrch0 ; no
lda |2,x
cmp Vptr+2
bne DelSrch0 ; no
phb ; save current link ptr
phx
sep #$20 ; 8 bit m
longa off
lda |2,x ; get next link addr
pha
rep #$20 ; 16 bit m
longa on
lda |0,x
tax
plb
lda |0,x ; now get 2nd like addr
sta Vptr ; stuff on stack
lda |2,x
sta Vptr+2
plx ; restore link ptr
plb
lda Vptr ; now patch over previous link
sta |0,x
lda Vptr+2
sta |2,x
DelDone ;
jsr KillIntsIfCan
plb
plp ; restore interrupt enble
jmp EndCall4
DelSrch0 ;
sep #$20 ; 8 bit m
longa off
lda |2,x ; get next link addr
pha
rep #$20 ; 16 bit m
longa on
lda |0,x
tax
plb
bra DelSrch ; continue search
DelErr ;
plb
plp
ldx #taskNtFdErr ; task not found error
jmp ErrOut4
ENDP
****************************************************************
*
* Clear Heartbeat Interrupt chain
*
* Change History
*
* 26 Jul 88 Steven Glass
*
* Try and turn off vbl interrupts.
*
****************************************************************
ClrHeart PROC
import KillIntsIfCan
lda #0
sta >HBptr ; clear out the links
sta >HBptr+2
jsr KillIntsIfCan
jmp oEndCall0
ENDP
****************************************************************
*
KillIntsIfCan PROC
*
* This routine turns off VBL interrupts if it is safe to do so.
* It is safe to turn them off under the following conditions:
*
* 1) No heartbeat tasks are installed.
* 2) The heartbeat interrupt vector points to our interrupt
* handler.
* 3) the mouse is not running in vbl interrupt mode.
*
*
* Inputs:
* none
*
* Outputs:
* none
*
* External Refs:
import IRQ_Heart
*
* Entry Points:
* none
*
longa on ; mode
longi on
*
****************************************************************
lda >HBPtr
ora >HBPtr+2
bne CannotTurnOff
lda >IRQ_VBL+1
cmp #IRQ_Heart
bne CannotTurnOff
lda >IRQ_VBL+2
cmp #>IRQ_Heart
bne CannotTurnOff
pha
pha
pha
_ReadMouse
pla
plx
plx
bcs CanTurnOff
and #%0000000000001000
bne CannotTurnOff
CanTurnOff
PushWord #vblDisable
_IntSource
CannotTurnOff rts
ENDP
****************************************************************
*
* HeartBeat Interrupt Handler
*
* Dispatches to this handler are made in response to VBL
* interrupts. This handler will increment the Tick Counter,
* and then each task in the heartbeat interrupt queue will
* have its counter decremented. If a zero value results, the
* associated handler will be called. It is the task's
* responsibility to reset the count each time it is called.
*
* Chain looks like.....
*
* HBptr --> link address --> link address --> $0000
* Counter Counter counter
* Signature Signature Signature
* (code) (code) (code)
*
*
* Change History
*
* 31 March 88 Steven Glass
*
* Moved the clearing of the interrupt source from the last
* thing done to the first thing done. This is to prevent
* this interrupt from clearing other interrupts that are
* cleared at the same address.
*
****************************************************************
IRQ_Heart PROC EXPORT
;-----------------------------------------------------------
;
; Start by turning off the interrupt source. Then we can
; go on and run all the installed tasks.
;
;
sta >ClrVBLint ; turn off interrupt source
rep #$30 ; off to 16 bit land
lda >TickCnt ; increment tick counter
inc a
sta >TickCnt
bne TickDone
lda >TickCnt+2
inc a
sta >TickCnt+2
TickDone ;
rep #$30 ; off to 16 bit land
lda >HBptr ; is heart beat chain empty
tax
ora >HBptr+2
beq NoChain1 ; yes
phb
sep #$20 ; 8 bit m
lda >HBptr+2 ; point at link
pha
plb
rep #$20 ; 16 bit m
NextHB ;
phx ;
_MidiInputPoll ; Poll Midi before each task.
plx
lda |6,x ; check task signature
cmp #$A55A
beq QueueOK ; looks ok to me
pea hbQueueBadErr ; heartbeat queue error
pea $0000 ; Heartbeat queue death message
pea $0000
_SysFailMgr ; off to the system death handler
QueueOK ;
lda |4,x ; if cnt = 0, ignore this task
beq NextQueue
dec |4,x ; else decrement task counter
bne NextQueue ; if task cnt not zero, don't execute
phb ; save environment prior to dispatch
phx
phk ; here's where we come back to
pea HBentry-1
phb ; and here's where were going to
clc
txa
adc #7
pha
sep #$30 ; dispatch is native, 8 bit m/x
rtl ; and this does the dispatch
HBentry ;
clc ; native mode, 16 bit m/x
xce
rep #$30
plx ; restore queue pointer
plb
NextQueue ;
lda |0,x ; is this the last link ?
ora |2,x
beq NoChain ; yes
sep #$20 ; 8 bit m
lda |2,x ; get next link addr
pha
rep #$20
lda |0,x
tax
plb
bra NextHB ; traverse the chain
NoChain ;
_MIDIInputPoll ; Poll one last time just to be safe.
plb
NoChain1 ;
sep #$30 ; off to 8 bit land
clc ; flag that interrupt was handled !
rtl
ENDP
title 'System Death Manager'
****************************************************************
*
* System Death Manager (ErrCode : integer; MsgPtr : long)
* Input Word Error Code
* Input LongWord Pointer to ascii
*
* Change History
*
* 08 Dec 88 Steven Glass
*
* Check for NIL pointer to string was wrong, ored low word with
* low word to see if nil. If string was at beginning of bank,
* it would not have worked.
*
****************************************************************
SysDeathMgr PROC
RTL1 equ 1
RTL2 equ RTL1+3
Ptr equ RTL2+3
ErrCode equ Ptr+4
clc
lda Ptr,s
ora Ptr+2,s ; Default
bne DSysD ; yes
sec ; else user msg
DSysD ;
phb ; clean 3 bytes of stack
pla
pla
jmp >SysDMgrV ; off through SysDeath vector
; and never come back.
ENDP
title 'GetAddress'
****************************************************************
*
* Return Interrupt Status Address
*
* Input word refnum
* Input LongWord Don't care
*
* Output LongWord Pointer
*
* Modification History
*
* May 6, 1986 See 5 lines changed below.
*
****************************************************************
GetAddr PROC
RTL1 equ 1
RTL2 equ RTL1+3
RefNum equ RTL2+3
Ptr equ RefNum+2
lda RefNum,s ; get ref #
asl a ; and make an index
asl a
cmp #MaxRef ; index out of range ?
bcc GetAddr0 ; nope
ldx #badInputErr ; error is bad input parm.
jmp oErrOut2 ; uses oErrOut SEG 6 May 86
GetAddr0 ;
tax ; get param. addr
lda >Ptbl,x ; abs long,x addressing SEG 6 May 86
sta Ptr,s
lda >Ptbl+2,x ; abs long,x addressing SEG 6 May 86
sta Ptr+2,s ; missing +2 SEG 6 May 86
jmp oEndCall2 ; uses oEndCall SEG 6 May 86
Ptbl ;
DC.L irq_intflag ; status of INTFLAG at IRQ
DC.L irq_datareg ; status of DATREG at IRQ
DC.L irq_ser1 ; user interrupt info
DC.L irq_ser2 ; user interrupt info
DC.L irq_aptlkhi ; user interrupt info
DC.L TickCnt ; longword tick count value
DC.L irq_volume ; volume used during IRQ time
DC.L irq_active ; <> 0 if called during IRQ
DC.L irq_soundd ; sound data at irq
DC.L irq_a ; registers at break
DC.L evmgrdata ; event manager data
DC.L mouseslot ; the little squeeker is here
DC.L LowXClamp ; 8 bytes of mouse clamp data
DC.L AbsClamps ; 8 bytes of absolute device clamp
DC.L SerFlag ; something for mike/fern
; ; added 6 Mar 87 by Ray, Mike, Steve
; ; fern and witnessed by Dan O.
PtblEnd ;
MaxRef equ PtblEnd-Ptbl
ENDP
title 'Mouse Tools'
****************************************************************
*
* Mouse Tool Sets for Mars
*
****************************************************************
*
* Copyright (C) 1985-1987
* Apple Computer, Inc.
* All Rights Reserved
*
****************************************************************
****************************************************************
;
setdbtoe1 PROC
;
pea $e1e1 ;change data bank to $e1
plb ;dummy pull
plb ;set data bank to $e1
rts
ENDP
EJECT
*******************************************************************************
*
ReadMouseJ PROC
*
* Description: This call will function identically to read mouse except that
* it will allow journaling to take place.
*
* Screen holes, buttons and movement status
* bits updated; interrupt status bits are cleared
* If data not contaminated, then first read $c024
* return X position data (ADB low byte), second
* reads return Y position data (ADB high byte)
*
* |MseStat ($077c): bit7, previously but1 was up/down (0/1)
* bit6, movement interrupt
* bit5, button 0/1 interrupt
* bit4, vbl interrupt
* bit3, currently but1 is up/down (0/1)
* bit2, x/y moved since last READMOUSE
* bit1, previously but0 was up/down (0/1)
* bit0, currently but0 is up/down (0/1)
*
* Input word: don't care
* Input word: don't care
* Input word: don't care
* Output word: X position
* Output word: Y position
* Output word: Status & Mode
*
* External Refs:
Import AltTRdMouse
*
*******************************************************************************
*
longa on
longi on
;
; stack structure
;
DBreg equ 1
Preg equ DBreg+1
RTL1 equ Preg+1
RTL2 equ RTL1+3
StatMode equ RTL2+3
YPos equ StatMode+2
XPos equ YPos+2
;
php ;save interrupt status
sei ;disable interrupt
phb ;save data bank
jsr setdbtoe1 ;change data bank to $00
;
; First, check the journaling flag, if its zero, then simply call ReadMouse direct
; and go no further.
lda >JournalFlag
bne rm2010
brl AltTRdMouse ; if its zero, then let read mouse handle this
;
; Next, check to see if the event manager is active, if it is, then we can continue,
; if it isn't well, just exit...
rm2010
pha ; room for result
_EMStatus
pla
bne rm2OK ; if its true, then its ok to go on
brl AltTRdMouse ; if the event manager is off then let ReadMouse handle this
;
rm2OK
; If we get this far, we know that the event manager is active and that journaling is turned on.
pha ; call the real read mouse to get the current mouse data
pha
pha
_ReadMouse2
pla ; get the current mouse data from the call
ply
plx
sta StatMode,s ; and save them into our record
tya
sta yPos,s ; on the stack for journaling to use.
txa
sta xPos,s
;
; Now that our result is set properly, we must call the journaling routine so that it will save
; these new bytes for us. Or load in whatever it should be for playback
; First create the address of our data on the stack so we can pass it
tsc ; get the current stack pointer
clc
adc #StatMode ; add in the proper offset
tax ; and save it in <X> for later
lda >JournalFlag ; first push the flag on the stack
pha
pea $0006 ; journal code for ReadMouse (Also the data size...hmmm...)
pea $0000 ; now push the address of our data, (its on the stack...)
phx ; push low word of data buffer
jsl JournalPtr ; and call the journaling routine
;
; Journaling is all finished, and so should we be... so simply exit
plb ;restore data bank
plp ;restore interrupt state during entry
jmp oEndCall0 ;exit tool with good MouseRead
EndP
****************************************************************
*
* ReadMouse - Read Mouse Position
* Screen holes, buttons and movement status
* bits updated; interrupt status bits are cleared
* If data not contaminated, then first read $c024
* return X position data (ADB low byte), second
* reads return Y position data (ADB high byte)
*
* |MseStat ($077c): bit7, previously but1 was up/down (0/1)
* bit6, movement interrupt
* bit5, button 0/1 interrupt
* bit4, vbl interrupt
* bit3, currently but1 is up/down (0/1)
* bit2, x/y moved since last READMOUSE
* bit1, previously but0 was up/down (0/1)
* bit0, currently but0 is up/down (0/1)
*
* Input word: don't care
* Input word: don't care
* Input word: don't care
* Output word: X position
* Output word: Y position
* Output word: Status & Mode
*
****************************************************************
*
TRdMou PROC
Export AltTRdMouse
longa on
longi on
;
; stack structure
;
DBreg equ 1
Preg equ DBreg+1
RTL1 equ Preg+1
RTL2 equ RTL1+3
StatMode equ RTL2+3
YPos equ StatMode+2
XPos equ YPos+2
;
php ;save interrupt status
sei ;disable interrupt
phb ;save data bank
jsr setdbtoe1 ;change data bank to $00
;
AltTRdMouse
longa off
longi off
sep #$30 ;off to 8-bit land
jsr GetMdata ;read in mouse data from keygloo
bcc RealData ;'c' = 0 if real live data
lda |MseStat ;Fake data if here to get state history
eor #$90 ;was 0=up -- after eor then 0=down
tax ;save in 'x'
and #$80 ;mask for current button0 state
tay
txa
and #$10 ;
asl a ;move to msb
asl a
asl a
tax
RealData ;
lda #$20 ;anticipate no movement
trb |MseStat ;reset to no movement first
tya ;get back y data from GetMdata
and #$3f ;mask off but0 and direction bit
pha ;save in stack
txa ;get back x data from GetMdata
and #$3f ;mask off but1 and direction bit
ora 1,s ;ora together x/y data byte
beq NoMove ;both x/y =0, no movement
lda #$20 ;else set movement bit
tsb |MseStat ;set movement status bit
;
Nomove ;movement status bit already reset
pla ;clean up stack
lda |MseStat ;get current buttons status
pha ;save temporarily
and #$2e ;reset bits 7,6,4,1, buttons bits
sta |MseStat ; i.e. button 1/0 all up first
pla ;recall current buttons status
and #$90 ;mask for last current buto/but1
asl a ;shift last current but0 to 'c'
bcc LstBut0Off ;bra if last current but0 is off
beq But0on1off ;bra here for last current but0 on
; ; and but1 off
lda #$41 ;get here if both last current buttons
; ; state were1, i.e. buttons pressed
SetHole ;
tsb |MseStat ;set it for screen hole
bra NewData ;bra to update for new states being
; ; read in by GetMdata
;
LstBut0Off ;
beq NewData ;bra for both off
lda #$01 ;else but1 on, down
bra SetHole ;update screen hole but1 stat
;
But0on1off ;
lda #$40 ;set but0 on
bra SetHole ;update screen hole but0 stat
;
NewData ;
tya ;get new but0 back
rol a ;save but0 status in 'c'
txa ;get new but1 back, bit7
;
; enter here with new buttons status, but0 = c, but1 = N (bit7)
; on=down=0, off=up=1, same to ADB spev but opposite to |MseStat !!!
;
bcs But0off ;bra if new but0 stat = 1, off
bmi But1off ;bra here for but0 = on, but1 = off
lda #$90 ;get here for both on, update it
UpdateHole ;
tsb |MseStat ;update screen holes with newly stat
bra AnyMove ;continue to handler any new movement
;
But0off ;
bmi AnyMove ;bra if both buttons off
lda #$10 ;get here for but1 on only
bra UpdateHole ;update it
;
But1off ;
lda #$80 ;get here for but0 on only
bra UpdateHole ;update it
;
AnyMove ;Handling mouse movements
txa ;get back x-pos new detla
and #$7f ;mask off button1 status, already done
tax ;temp store direction and movement
asl a ;direction bit to msb
bpl PosXmov ;bra for positive x direction move
txa ;else neg x move, make 2's
ora #$80 ;set 2's data
ldx #$ff ;set high byte to 2's also
bra NegXMov ;bra to handle this neg move
;
PosXmov ;
txa ;pos x move, make high byte also +
ldx #$00
;
NegXMov ;
PosNeg ;
phx ;push hi byte of delta x (word) on stk
pha ;push lo byte of delta x on stack
tya ;process delta y stuff
and #$7f ;ignore button0 status, already handled
tay ;store delta y without but0 status
asl a ;shift direction bit to msb
bpl PosYMov ;bra for pos y movement
tya ;get back delta y
ora #$80 ;negative y movement, make 2's
ldy #$ff ;set high byte also
bra NegYMOv ;
PosYMov ;
tya ;pos y movement, then make hi byte '+'
ldy #$00
;
NegYMov ;
phy ;push hi byte of delta y on stack
pha ;push lo byte of delta y on stack
;
lda |HighAbsy ;read back previous value and
; ; update with the current value
sta |MseSpare ;save the previous value temporarily
; ; for 'YclampTest'
pla ;get back lo byte of delta y from stack
clc ;clear carry for the following adding
adc |LowAbsy ;add in new value for low byte abs y
sta |LowAbsy ;update the screen hole also
;
pla ;get back high byte of delta y
adc |HighAbsy ;add in new value for high byte abs y
sta |HighAbsy ;update screen hole also
jsr YclampTest ;test y against clamp
;
lda |HighAbsx ;process delta x stuff
sta |MseSpare
;
pla ;get back lo byte of delta x from stack
clc ;make sure 'c'=0
adc |LowAbsx ;add in new value for low byte of x
sta |LowAbsx ;update screen hole also
;
pla ;get back high byte of delat x
adc |HighAbsx ;add in new value for high byte of x
sta |HighAbsx ;update screen hole also
jsr XclampTest ;test x against clamp
;
lda |HighAbsx ;after proper clamps testing, read
; ; it and set properly for the toos call
sta Xpos+1,s
lda |LowAbsx
sta Xpos,s
lda |HighAbsy
sta Ypos+1,s
lda |LowAbsy
sta Ypos,s
lda |MseStat ;get status
sta StatMode+1,s ;move status to stack for tools call
lda |MseMode ;get mouse mode
sta StatMode,s ;move mode to stack
;
rep #$30 ;must exit with 16-bit m/x
plb ;restore data bank
plp ;restore interrupt state during entry
jmp oEndCall0 ;exit tool with good MouseRead
;
; How about error reading ?????????? ErrorCode ???????
;
ENTRY GetMData
GetMdata ;
lda kmstatus ;test if data available
bpl NotAvail ;bra if not available, set 'c'
ror a ;set 'c'=0, if data ok bit1=0
ror a ; i.e. data not contaminated
lda MouseData ;read in mouse data register, $c024
tax
bcs NotAvail ;c=1 if data is contaminated
lda kmstatus ;verify Y ardware has X data ready
and #$02 ;bit1=1, Y pos data available
beq NotAVail
lda MouseData ;read in Y position data
tay ;store for calling routine
clc ;good reading of mouse data
rts ;return to caller
NotAvail ;
sec ;not a good reading
rts
;
**************************************************************************
*
* Clamping is done after the delta has been added to the absolute value.
* The new absolute values are tested against the current clamp values.
*
**************************************************************************
*
XclampTest ;
ldy #$00 ;y=0 for Xdata, y=$01 for Ydata
tyx ;x=0 for Xdata, x=$02 for Ydata
xba ;high byte of data to hi byte of 'A'
lda |LowAbsx,y ;read lo byte of data to lo byte of 'A'
xba ;swap hi and low byte of 'A'
tay ;y=high byte of data
bvc NoOverflow ;no overflow then all's fine
bit |MseMode ;chk which test flag in use
bra YclampTst0 ;continue this way
NoOverflow ;
bit |MseMode ;set up N and V for later
bra ClampTest ;continue this way
;
YclampTest ;
ldy #$01 ;y=0 for Xdata, y=$01 for Ydata
ldx #$02 ;x=0 for Xdata, y=$02 for Ydata
xba ;high byte of y data to hi byte of 'A'
lda |LowAbsx,y ;read lo byte of y data to lo byte 'A'
xba ;swap hi and low byte of 'A'
tay ;y=high byte of y data
bvc YclampTst2 ;No overflow then all's fine
bit |MseInfo ;chk which test flag in use, Info set
; ; in InitTool
YclampTst0 ;
bmi Chk2or3 ;either 2 or 3 if -
bvc MaxClamp ;Test 0 if v=0
tya ;test 1 if v=1
bmi MaxClamp ;if - was + before
bpl MinClamp ;if + was - before
Chk2or3 ;
bvc MinClamp ;test 2 if v=0
YclampTst2 ;
bit |MseInfo ;setup N and V for later
;
ClampTest ;
php ;save status
tya ;is it + or -
bmi NegNum ;bra if -
plp ;value is +
bmi Must2or3 ;must be 2 or 3
bvc MinMax ;must be test 0]
longa on
longi on
rep #$30 ;off to 16-bit land
xba ;put high data back to hi byte of 'A'
cmp |HiXclamp,x ;test against high clamp
longa off
longi off
sep #$30 ;back of 8-bit land
beq OkValue ;bra if equal to max clamp, ok
bcs MaxClamp ;> maxclamp is not ok
OkValue ;
rts ;back to caller
Must2or3 ;
bvs MinMax ;do regular min/max test
;
MaxClamp ;
txy ;test whether x or y data change
beq XChange ;bra for Xdata, x=y=0
ldy #$01 ;else set for Ydata, y=$01
Xchange ;
lda |HiXclamp,x
sta |LowAbsx,y ;Modify user data to max clamp value
lda |HiXclamp+1,x
MaxClamp2 ;
sta |HighAbsx,y ;save as new abs hi value
rts ;back to caller
;
NegNum ;
plp ;bit7 to N / bit6 to V
bmi MinMax ;must be 2 or 3
bvs Testm1 ;must be test 1
;
MinClamp ;must be test 0
txy ;test whether x or y data change
beq XChange1 ;x=y=0 for Xdata
ldy #$01 ;else set for Ydata
Xchange1 ;
lda |LowXclamp,x
sta |LowAbsx,y ;Modify user data to min clamp value
lda |LowXclamp+1,x
bra Maxclamp2 ;exit this way
;
Testm1 ;
xba ;put high byte in hi byte of 'A'
longa on
longi on
rep #$30 ;off to 16 bit land
cmp |LowXclamp,x ;test against min clamp
longa off
longi off
sep #$30 ;back to 8 bit land
bcc MinClamp ;< min clamp then use min clamp
rts ;ok value, back to caller
;
MinMax ;do regular min/max testing
tya ;pick up value to test
bmi MinMax0 ;current valur is -
lda |MseSpare ;what was previous abs sign
bpl MinMax1 ;previous was +
SpecTest ;
sec ;set carry to subtract
txy ;make proper y index
beq Xxdata
ldy #$01 ;set for ydata
Xxdata ;
sbc |HighAbsx,y ;subtract current abs hi byte
bvs MinMax1 ;v=1 then all's fine
bit |MseSpare ;test sign
bpl MinClamp ;+ then use min clamp
bmi MaxClamp ;- then use max clamp
MinMax0 ;
lda |MseSpare ;test previous bi byte for sign
bpl SpecTest ;previous was +
;
MinMax1 ;
txy ;make proper y index
beq Xxxdata
ldy #$01
Xxxdata ;
lda |HighAbsx,y ;get current abs hi byte
longa on
longi on
rep #$30 ;off to 16 bit land
xba ;put high byte into hi byte of 'A'
cmp |HiXclamp,x
longa off
longi off
sep #$30 ;back to 8 bit land
beq OkValue2 ;= is ok
bcs MaxClamp ;> than max then use max clamp value
OkValue2 ;
rep #$30 ;off to 16 bit land
cmp |LowXclamp,x ;test against min clamp
sep #$30 ;back to 8 bit land
bcc MinClamp ;< min clamp then use min clamp value
rts ;back to caller
ENDP
*************************************************************
*
* InitMouse - init mouse clamp values to $0000 and $03ff,
* set mouse position to 0,0 and also clear
* mouse mode and status
*
* Input : word, mouseslot (miscellaneous tool)
* If mouse is going to be always active, then there
* is not necessary to have such input, the following
* routine doesn't take care of this input word but
* maintain compatibility with miscellaneous tool and
* therefore exits with oEndCall02
*
*************************************************************
*
InitGlue PROC
longa on
longi on
;
; The stack is not affected by this call
;
php ;save interrupt state
sei ;disable interrupt
phb ;save data bank
jsr setdbtoe1 ;change data bank to $00
;
lda #$0000 ;16 bit land
sta |LowXclamp ;reset low clamps to 00
sta |LowYclamp ;
lda #$03ff ;reset high clamps to$3ff
sta |HiXclamp
sta |HiYclamp
longa off
longi off
sep #$30 ;off to 8 bit land
stz |LowAbsx ;set screen holes to 00
stz |LowAbsy
stz |HighAbsx
stz |HighAbsy
lda #$04 ;??? assume mouse at slot4
sta mouseslot
jsl InitFlag ;must set up clamp flags
longa on ;exit with 16 bit land a must
longi on
rep #$30
plb ;restore data bank
plp ;restore interrupt state
jmp oEndcall2
ENDP
***********************************************************
*
* SetMouse - set mouse mode, |MseMode
*
* Input word: |MseMode
*
* bit7/6, for X clmaping flags
* bit5/4, reserved
* bit3, Interrupt on VBL
* bit2, Interrupt on next VBL if button pressed
* bit1, Interrupt on next CBL if mouse is moved
* bit0, Mouse button off/on (0/1)
*
***********************************************************
*
TSetMou PROC
longa on
longi on
;
; stack structure
;
DBreg equ 1
Preg equ DBreg+1
RTL1 equ Preg+3 ;rtl for tool dispatcher
RTL2 equ RTL1+3 ;rtl for application caller
ModeUser equ RTL2+1 ;mode set by application
;
ErrMode equ $1d01 ;Illegal mode error code
;
php ;save interrupt status
sei ;disable interrupt
phb ;save data bank
jsr setdbtoe1 ;change data bank to $00
lda ModeUser,s ;get input mode
;
longa off
longi off
sep #$30 ;8-bit m/x
tay ;temp store the mode
and #$f0 ;chk for legal mode
bne BadMode ;bra if illegal mode
tya ;get back mode
ror a ;test mouse on/off bit
php ;c=1=enable mouse and z=0=turn ints on
lda #$0f ;reset bits 0,1,2,3
trb |MseMode
tya ;recall user mode nibble
tsb |MseMode ;put new mode in lo nibble
and #$08 ;make irq.mousvbl=0 if no VBL to user
sta |irq_MousVbl ;make irq.mousvbl <>0 if VBL to user
plp ;what should be done?
bcc DisMouse ;bra to disable mouse
tya ;recall mode byte
and #$06 ;bit2=button int, bit1=movement bit
beq DisMouse ;if =0 then no mouse ints except VBL
lda #$40 ;else only bit3<>0, alter it in gloo
tsb |kmstatus ;alter the interrupt bit in keygloo
bra EndSet
;
DisMouse ;
lda #$40 ;alter the bit in Kmstatus
trb |kmstatus
;
EndSet ;
tya ;see if we should turn on VBL ints too
and #$08 ;bit3, interrupt on VBL
beq EndSet1 ;exit if not enabled
tsb |inten ;enable VBL interrupt
;
EndSet1 ;
jsr GetMdata ;reset keygloo mouse information
longa on
longi on
rep #$30 ;16-bit m/x exits a must
plb ;restore data bank register
plp ;restore interrupt state
jmp oEndcall2 ;exit tool by adjusting stack ptr
;
BadMode ;
longa on
longi on
rep #$30 ;16 bit m/x exits a must
lda #ErrMode
plb
plp
sec ;c=1 error mode
jmp oErrout2
;
ENDP
********************************************************************
*
* HomeMouse - set mouse to upper-left corner of clamping window
* or saying position mouse at minimum clamp position
*
********************************************************************
*
HomeGlue PROC
longa on
longi on
;
; The stack is not affected by this call, from toolcall point of view
;
php ;save interrupt state on entry
sei ;disable interrupt
phb ;save data bank register
jsr setdbtoe1 ;change data bank register to $00
longa off
longi off
sep #$30 ;off to 8 bit land
lda |LowXclamp
sta |HighAbsx
lda |LowXclamp+1
sta |LowAbsx
lda |LowYclamp
sta |HighAbsy
lda |LowYclamp+1
sta |LowAbsy
;
HomeExit ;
jsr GetMdata ;exit via reset keygloo mouse info
longa on
longi on
rep #$30 ;off to 16 bit land
plb ;restore data bank
plp ;restore interrupt state
jmp oEndCall0 ;exit the tool
ENDP
*******************************************************************
*
* ClearMouse - Reset buttons, movement and interrupt status to 0.
* Set screen holes to $0000.
*
********************************************************************
*
ClearGlue PROC
longa on
longi on
;
; stacks from the tool call are not affected
; no input or output parameters are required
;
php ;save interrupt state
sei ;disable interrupt
phb ;save data bank
jsr setdbtoe1 ;change data bank to $00
;
longa off
longi off
sep #$30 ;off to 8 bit land
stz |LowAbsx ;clear screen holes
stz |LowAbsy
stz |HighAbsx
stz |HighAbsy
stz |MseStat ;clear mouse status also
jsr GetMdata ;reset keygloo mouse information also
;
longa on
longi on
rep #$30 ;off to 16 bit land
plb ;restore data bank
plp ;restore interrupt state
jmp oEndCall0 ;exit with c=0, A=0
ENDP
***************************************************************
*
* ClampMouse - set mouse bounds in a window and then set
* mouse positions to the minimum clamp values
*
* Input word: X axis minimum clamp
* Input word: X axis maximum clamp
* Input word: Y axis minimum clamp
* Input word: Y axis maximum clamp
*
***************************************************************
*
TClmpMou PROC
longa on
longi on
;
; stack structure
;
DBreg equ 1
Preg equ DBreg+1
RTL1 equ Preg+1
RTL2 equ RTL1+3
YMaxLo equ RTL2+3
YMaxHi equ YMaxLo+1
YMinLo equ YMaxHi+1
YMinHi equ YMinLo+1
XMaxLo equ YMinHi+1
XMaxHi equ XMaxLo+1
XMinLo equ XMaxHi+1
XMinHi equ XMinLo+1
;
php ;save interrupt state
sei
phb ;save data bank register
jsr setdbtoe1 ;change data bank reg to $00
;
lda YMaxLo,s ;move clamp values from stack to clamp
; ; locations in RAM $e1 bank for event
; ; manager
sta |HiYclamp ; 16 bit land
lda YMinLo,s
sta |LowYclamp
lda XMaxLo,s
sta |HiXclamp
lda XMinLo,s
sta |LowXclamp
jsl InitFlag ;update clamp flags
longa on
longi on
rep #$30 ;off to 16 bit land
pea $0000
pea $0000
pea $0000
phk ;dummy 3 bytes
per clmpxit-1 ;part of 3 dummy bytes
jsl >TRdMou ;execute ReadMouse to reflect new clmps
rtl ;remove 3 dummy bytes and go to next
clmpxit ;
pla ;remove 3 more words from ReadMouse
pla
pla
plb ;restore data bank
plp ;restore interrupt state during entry
jmp oEndCall8 ;exit the tool
ENDP
******************************************************************
*
* GetClamp - Read the current clamp values
*
* Input word: don't care
* Input word: don't care
* Input word: don't care
* Input word: don't care
* Output word: Y maximum clamp
* Output word: Y mimimum clamp
* Output word: X Maximum clamp
* Output word: X minimum clamp
*
******************************************************************
*
TGetClamp PROC
longa on
longi on
;
; stack structure
; no change for data bank register
;
DefineStack
Preg byte
Breg byte
RTL1 block 3
RTL2 block 3
MaxY word
MinY word
MaxX word
MinX word
;
php ;save interrupt state
sei ;disable interrupt
phb ;save data bank register
jsr setdbtoe1
lda |HiYclamp ;move clamp values to stack
sta MaxY,s
lda |LowYclamp
sta MinY,s
lda |HiXclamp
sta MaxX,s
lda |LowXclamp
sta MinX,s
plb ;restore data bank register
plp ;restore interrupt
jmp oEndCall0 ;exit tool
ENDP
************************************************************
*
* PosMouse - set mouse position to user-defined position
*
* Input word: X position
* Input word: Y position
*
************************************************************
*
TPosMou PROC
longa on
longi on
;
; stack structure
;
DBreg equ 1
Preg equ DBreg+1
RTL1 equ Preg+1
RTL2 equ RTL1+3
Ypos equ RTL2+3
Xpos equ Ypos+2
;
php ;save interrupt state
sei ;disable interrupt
phb ;save data bank register
jsr setdbtoe1
longa off
longi off
sep #$30 ;off to 8 bit land
lda Xpos+1,s ;move position to screen holes
sta |HighAbsx
lda Xpos,s
sta |LowAbsx
lda Ypos+1,s
sta |HighAbsy
lda Ypos,s
sta |LowAbsy
jsr GetMdata ;also reset keygloo mouse information
longa on
longi on
rep #$30 ;back to 16 bit land for exit
plb ;restore data bank
plp ;restore interrupt state
jmp oEndCall4
ENDP
**************************************************************
*
* ServeMouse - Service mouse interrupt
* Update interrupt status bit at screen hole ($077c)
* to show current status
*
* Input word: Space, don't care
* Output word: Interrupt status
**************************************************************
*
TServMou PROC
longa on
longi on
;
; stack structure
;
DBreg equ 1
Preg equ DBreg+1
RTL1 equ Preg+1
RTL2 equ RTL1+3
IntStat equ RTL2+3
php ;save interrupt status on entry
sei ;disable interrupt
phb ;save data bank
jsr setdbtoe1 ;change data bank to $00
longa off
longi off
sep #$30 ;off to 8-bit land
lda #$0e ;reset bit3, VBL interrupt
; ; bit2, Button 0/1 interrupt
; ; bit1, Movement interrupt
trb |MseStat ;cause to reset
lda |irq_Intflag ;test VBL enabled/active status flag
tay ;temp store
and #$08 ;bit3 = 1, if vbl interrupted
beq NotVbl ;bra if not vbl interrupt, don't reset
sta |ClrVblint ;else disable vbl interrupt, $c047
tya ;get back intflag
and #$f7 ; to clr the vbl interrupt stat
sta |irq_Intflag ; clear it
lda #$08 ;prepare bit to update |MseStat
NotVbl ;
tay ;save status
tsb |MseStat ;update mouse state screen hole
bit |kmstatus ;chk for mouse info in gloo
bvc MseIntdis ;bra if mouse interrupts noe enabled
bpl MseIntdis ;bra if ints enabled but mse didn't int
lda #$0e ;chk what's ints status
tay ; set 'y' non-zero for exit from here
tsb |MseStat ;Update |MseStat, $077c
MseIntdis ;
tya ;test if mousey interrupt or not
lda |MseStat ;finally read back the new status
sta IntStat,s ;store to proper location in stack
; for application to read it
plb ;restore data bank register
plp ;restore interrupt status
tya ;test if mousey interrupt or not
beq NotMseInt ;bra for not mousey type interrupt
clc ;maintain compatibility for firmware call
bra ExitSerMse
NotMseInt ;
sec ;maintain compatibility for firmware call
ExitSerMse ;
longa on
longi on
rep #$30 ;off to 16-bit land a must
jmp oEndcall0 ;exit the tool
ENDP
****************************************************************
*
* GetAbsclamp - get absolute clamp values
*
* Input word: Space for result
* Input word: Space for result
* Input word: Space for result
* Input word: Space for result
* <----- sp
* Output word: X minimum clamp
* Output word: X maximum clamp
* Output word: Y minimum clamp
* Output word: Y maximum clamp
* <----- sp
*
***************************************************************
;
GetAbsClamp PROC
longa on
longi on
;
; stack structure
;
RTL1 equ 1
RTL2 equ RTL1+3
MaxY equ RTL2+3
MinY equ MaxY+2
MaxX equ MinY+2
MinX equ MaxX+2
lda >AbsClamps ;move clamps to stack
sta MinX,s
lda >AbsClamps+2
sta MinY,s
lda >AbsClamps+4
sta MaxX,s
lda >AbsClamps+6
sta MaxY,s
jmp oEndCall0
ENDP
********************************************************************
*
* SetAbsclamp - set absolute device clamp values
*
* Input word: X axis minimum clamp
* Input word: X axis maximum clamp
* Input word: Y axis minimum clamp
* Input word: Y axis maximum clamp
* <----- sp
*
********************************************************************
*
SetAbsClamp PROC
longa on
longi on
;
; stack structure
;
RTL1 equ 1
RTL2 equ RTL1+3
Ymax equ RTL2+3
Ymin equ Ymax+2
Xmax equ Ymin+2
Xmin equ Xmax+2
lda Xmin,s ;move clamps from stack to its area
sta >AbsClamps
lda Ymin,s
sta >AbsClamps+2
lda Xmax,s
sta >AbsClamps+4
lda Ymax,s
sta >AbsClamps+6
jmp oEndCall8 ;exit tool by adjusting stack ptr
ENDP
*********************************************************************
*
* BasicInit - An unofficial tool to set up the clamp flags when
* calling from BASICMOUSE.
* InitFlag - The flags are returned in bits 6, 7 of 'A'.
* Called during power up, InitMouse, ClampMouse and
* BASICMOUSE (firmware).
*
* The following is a break down of what the clamping flags mean. The
* X flag is in bits 6, 7 of |MseMode byte and the Y flag is in bits 6, 7
* of the Info byte.
*
* Hi nibble Lo nibble Comments
*--------------------------------------------------------------------
* for X
* A: 00xx xxxx both x clamps are +
* 01xx xxxx min is - / max is +
* 10xx xxxx both x clamps are -
* 11xx xxxx min is + / max is -
* absolute clamping
*
* for Y
* A: 00xx xxxx both y clamps are +
* 01xx xxxx min is - / max is +
* 10xx xxxx both y clamps are -
* 11xx xxxx min is + / max is -
* absolute clamping
*
***********************************************************************
*
MyBasicInit PROC ;support entry for BASICMOUSE
longa on
longi on
;
; The stack is not affected by this call. Only BASICMOUSE is an external
; call to this tool, all others are internal call in the tool.
;
phb ;save data bank register
jsr setdbtoe1 ;change data bank to $00
longa off
longi off
sep #$30 ;off to 8 bit land
jsl >InitFlag
;
longa on
longi on
plb
rep #$30 ;exit with 16 bit land
jmp oEndCall0 ;exit from BASICMOUSE call
InitFlag PROC
;
longa off
longi off ;enter w/ 8 bit mode
sep #$30
;
ldx #$00 ;$00 for x-axis clamping
lda #$c0 ;ready to clear bits 6, 7
trb |MseMode ;reset it
trb |MseInfo ;reset it
jsr TstSwap4 ;go set a flag, return in 'A'
tsb |MseMode ;set appropriate bits
jsr TstClampVal8 ;do hi byte test
bcs XOK ;x ok now test y
bit |MseMode ;pick up flags in N and V
jsl >TstSwap ;go test it
;
XOK ;
ldx #$02 ;$02 for y-axis clamping
jsr TstSwap4 ;go set a flag
tsb |MseInfo ;set appropriate bits
jsr TstClampVal8 ;do hi byte test
bcs Tstclrts ;exit with 'c'=1
bit |MseInfo ;else pick up flags and test
;
TstSwap ;swap clamp values
bvs Tstclrts ;no swap if flag = 0 or 1
bpl PosNegnum ;'+' only if 2 pos # entered
sep #$40 ;'v'=1 if 2 neg # entered
PosNegnum ;
longa on
longi on
rep #$30 ;off to 16 bit land
lda |LowXclamp,x
bvs JustSwap ;'v'=0 then just swap
bit #$ff00 ;else test if illegal '-' number
bne JustSwap ;do regular swap
bit #$0080 ;test for illegal '-' number
beq JustSwap ;do regular swap
ora #$ff00 ;else extend sign to hi byte
sta |LowXclamp,x ;resave modified clamp
;
longa off
longi off
sep #$30 ;back to 8 bit land
lda #$40 ;change bit 6,7 (00) to (01)
cpx #$02 ;2 if change info else change |MseMode
bne ChMseMode ;
tsb |MseInfo ;set bit 6
rtl
;
ChMseMode ;
tsb |MseMode ;set bit 6
rtl
;
JustSwap ;
longa on
longi on ;enter with 16 bit m/x
tay ;save in y
lda |HiXclamp,x ;high clamp swap with low clamp
sta |LowXclamp,x
tya ;for indirect, bridge...
sta |HiXclamp,x
longa off
longi off
sep #$30 ;back to 8 bit land
;
Tstclrts ;
rtl ;back to caller
;
TstSwap4 ;
lda |HiXclamp+1,x ;get hi clamp hi byte
php ;save for later
lda |LowXclamp+1,x ;get low clamp hi byte
bmi LowclampNeg ;bra if low clamp -
plp ;what about hi clamp hi byte
bmi Flag3 ;if - set flag 3
lda #$00 ;must set flag to 0
rts ;return to internal call
;
Flag3 ;
lda #$c0 ;flag = 3
rts
;
LowclampNeg ;
plp ;what was sign of hi byte
bmi Flag2 ;if - then use flag 2
lda #$40 ;flag = 1
rts
;
Flag2 ;
lda #$80 ;flag = 2
rts
;
TstClampval8 ;
longa on
longi on
rep #$30 ;off to 16 bit land
lda |HiXclamp,x ;test hi clamp
cmp |LowXclamp,x ; against low clamp
longa off
longi off
sep #$30 ;back to 8 bit land
rts
;
ENDP
title 'FWEntry'
****************************************************************
*
* Full Native Dispatch to Firmware
*
* Input Word Entry point - 1
*
* This routine dispatches from full native mode to an emulation
* mode entry point. The 8 bit A,X and Y registers will be
* passed through to the target routine. A,X and Y will also
* be returned to the application from the target routine.
* If the dispatch is in the address range of $C0xx-$C7xx, then
* the dispatcher must determine if the slot to be accessed is
* internal or external. If external, then the system speed is
* kicked down to slow mode.
*
****************************************************************
FwEntry PROC EXPORT
DirReg equ 1
OrigState equ DirReg+2
OrigCya equ OrigState+1
OrigDbr equ OrigCya+1
OrigAReg equ OrigDbr+1
EntryWord equ OrigAReg+1
RetAddr1 equ EntryWord+2
sep #$30 ; 8 bit m/x
longa off
longi off
pha ; save processor environment
phb
lda #0
pha
plb
lda |CyaReg ; save current system speed
pha
lda |StateReg
pha
lda #%00001000
sta |StateReg
phd
tsc
tcd
phx ; save $Cn
rep #$20 ; 16 bit 'm'
lda EntryWord ; get dispatch page
inc a ; adjust to absolute entry point
xba ; get high byte entry point
sep #$20 ; 8 bit 'm'
cmp #$C8 ; $C000 < EntryPoint < $C800 ?
bge NotIO ; no
and #$F0
cmp #$C0
bne NotIO ; if not in $Cxxx space
rep #$20 ; 16 bit 'm'
lda EntryWord ; get dispatch page
inc a ; adjust to absolute entry point
xba ; want $Cn
sep #$20 ; 8 bit 'm'
and #$07 ; determine the slot were going to
cmp #$03 ; is it slot 3?
bne NotSlot3 ; no
lda >RDC3ROM ; is slot 3 internal or external ?
and #%10000000 ; mask excess bits
bra SetSpeed ; if external, set slow!
NotSlot3 ;
tax
lda |SltRomSel ; now get slot rom selection
SlowChk ;
ror a ; get internal/external to 'c'
dex
bpl SlowChk
lda #0 ; get ready to set system speed
ror a ; bit 7 = not speed
SetSpeed ;
trb |CyaReg ; set the system speed
NotIO ;
plx ; restore $Cn
rep #$30 ; 16 bit m/x
longa on
longi on
****************************************************************
*
* This saves the states of the 8 bit X and Y while
* we play around with switching the stack from native
* mode to emulation mode. If the native stack is not in
* page $01, then the 16 bit stack pointer must be saved while
* the stack pointer is reset to Main memory stack page $01XX.
* Then the 16 bit native mode stack pointer is saved on the
* emulation mode stack. It's strange, but neccessary.
*
****************************************************************
txa ; get 8 bit X
xba ; save it
sep #$20 ; 8 bit 'm'
tya ; now get 8 bit Y
rep #$20 ; 16 bit 'm'
tax ; now X really has both X and Y
tsc ; get current stack pointer
tay ; and save in Y register
sep #$20 ; 8 bit 'm'
longa off
xba ; check if stack is in page $01
dec a
beq AlreadyPG1 ; if page 1, then don't get it
lda #1 ; stack will be in page 1
xba
lda >MNEMSTKPTR ; get low byte of stack pointer
rep #$20 ; 16 bit 'm'
longa on
tcs ; set the page 1 stack pointer
AlreadyPG1 ;
phy ; and save the 16 bit stack pointer
rep #$20 ; 16 bit 'm'
txa ; get back both X and Y
sep #$30 ; 8 bit 'm' & 'x'
tay ; now restore Y
xba ; and then restore X
tax
phd ; save current direct register
pea FWRET-1 ; save return address
lda |RDCXROM ; save FE bank evironment
pha
rep #$20 ; 16 bit 'm'
lda EntryWord ; save dispatch address
pha
sep #$30 ; 8 bit m/x
longa off
longi off
lda OrigAReg ; get entry 'A' reg
pea $0000 ; set direct register to $0000
pld
brl ToMainSide ; here we go
FWRET ;
pld ; restore direct page
sta EntryWord ; save 'A' on return from firmware
php ; save 'P' on return from firmware
pla
sta EntryWord+1
rep #$30 ; 16 bit 'x' and 'm'
pla ; get native mode stack pointer
tcs ; and reset the stack pointer
sep #$30 ; 8 bit 'm' and 'x'
pld ; restore direct register
pla ; restore state
sta |StateReg
pla ; restore system speed
sta |CyaReg
plb ; restore Data Bank Register
sep #$30 ; 8 bit 'm' and 'x'
longa on
longi on
pla ; clean entry acc. off stack
pla ; A reg = value from firmware call
plp ; P reg = value from firmware call
rep #$30 ; back to 16 bit land
rts
ENDP
****************************************************************
*
* This routine used to dispatch to mainside
*
* ENTRY : Rom Enabled
* Native Mode
* 8 Bit m/x
* Stack = RDSLOTCXROM
* Dispatch Address-1 (MSB)
* Dispatch Address-1 (LSB)
*
* EXIT : Fast Mode
*
*
****************************************************************
ToMainSide PROC
longa off ; start off in 8 bit mode
longi off
xba ;Preserve 'A' in 'B'
txa ;preserve 'X' in 'A'
rep #$30 ;off to 16 bit land
longa on
longi on
plx ;save routine address in 'X'
phk ;Return bank
pea FEBankRts-1 ;Return address in bank FE
pea MainExit-1 ;Exit point in main monitor ROM
phx ;Routine to execute back to stack
sep #$30 ;back to 8 bit land
longa off
longi off
tax ;Restore 'X' from 'A'
xba ;Restore 'A' from 'B'
ToMainSid2 ;
xba ;Save 'A' value
lda >CyaReg ;save speed
and #$7F ;slow down system
ora >SystemSpd ;System speed mask
sta >CyaReg ;
xba ;Restore user 'A' value
phb ;Data bank register is new program bank
pea MainSide-1 ;Main ROM area entry point
sta >SetSlotCXRom ;disable internal CxROM
rtl ;go to mainside
FEBankRts ;
sep #$30
xba ;save user's 'A' value
phb
pea 0
plb
plb
lda #$80 ;go fast in here
tsb |CyaReg ;
lda 2,s ; get rom select
bpl SetExtRom ; if external
sta |SetIntCxROM ;Restore bank FE operating environment
OKforExit ;
plb
pla
xba
rts ;Back to bank $FF caller
SetExtRom ;
sta |SetSlotCXROM
bra OKforExit
ENDP
title 'ID Tag Manager'
*********************************************************************
*
* This tool is used to insert, delete and inquire status
* regarding an ID tag. The ID tag is used to mark segments
* as belonging to a specific application.
*
* GetNewID
* Input Word Space for result
* Input Word ID tag (Type and Aux)
* Output Word ID tag (Full tag returned)
*
* DeleteID
* Input Word ID tag (Type and Main)
*
* StatusID
* Input Word ID tag (Type and Main)
*
* ID tag structure is shown below.....
* ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
* | | | | | | | | | | | | | | | | |
* | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* |___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|
* |___|___|___| |___|___|___| |___|___|___|___|___|___|___|
* | | |
* Type Field Aux ID Field Main ID Field
*
* Type = 0 Memory Manager
* 1 Application
* 2 Controlling Program (Finder, Shell, etc.)
* 3 ProDOS
* 4 Tool Kits..................Not managed here.
* 5 Desk Accessories
* 6 Run Time Libraries
* 7 System loader..............Not managed here
* 8 Firmware / System Function
* 9 Tool Locator...............Not managed here.
* A Setup File
* B Undefined
* C Undefined
* D Undefined
* E Undefined
* F Undefined
*
* Change History
*
* 13 Nov 88 Steven Glass
*
* No longer manage ID 4000, 7000 or 9000. (These are used
* throughout the system without anyone reserving them. so we
* return error when someone trys to reserve them).
*
* Also removed unnecessary Hlock and hUnlock calls.
*
*
*********************************************************************
GetNewID PROC
longa on
longi on
taglist equ 1
size equ taglist+4
SrchTag equ size+2
SrchCnt equ SrchTag+2
OrigDBR equ SrchCnt+2
OrigDir equ OrigDBR+1
rtl1 equ OrigDir+2
rtl2 equ rtl1+3
UserTag equ rtl2+3
IDTag equ UserTag+2
Bounds equ LastTag
DefineStack
s_Rtl1 block 3
s_Rtl2 block 3
s_UserTag word
s_result word
lda s_UserTag,s
and #$F000
cmp #$4000
beq NoCanDo
cmp #$7000
beq NoCanDo
cmp #$9000
bne CanDo
NoCanDo ldx #BadInputErr
jmp oErrOut2
CanDo
phd ; environment
phb
lda #0 ; init space to 0
pha ; space for search counter
pha ; space for search tag
pha ; space for list size
pha ; space for list address
pha
tsc ; and turn stack into zp
tcd
jsr GetMTHandleSize
sta size ; save current size
sta srchcnt ; initialize search counter
ina ; grow for a word entry in list
ina
jsr SetMTHandleSize
jsr MTderef ; dereference the handle
stx taglist ; set tag list address
sty taglist+2 ; ready for direct-indirect-indexed
*
* Search for a hole in the tag list with the requested type.
* The search routine ignores the AUX field. Post processing
* of the IDTAG returned from the search must check for a
* nonzero MAIN field before returning the tag to the requestor.
* Only the TYPE and MAIN fields in the IDTAG are maintained in
* the IDTAG list. IDTAGS with a MAIN field set to zero are
* invalid and not maintained in the list. IDTAGS with a TYPE
* field of zero are not maintained in the list. This means that
* the maximum number of tags maintained in the list is 3825 IDTAGS
* or 15*255. Since tags are word wide, the maximum length of the
* list is 7650 bytes ($1DE2).
*
ldy size ; decrement remaining list size
beq emptylist
dey ; to point at last entry
dey
sty size ; point at top of list
emptylist ;
lda UserTag ; get callers ID
and #$F000 ; keep only relevant parms
inc a ; make initial tag = $NX01
sta SrchTag ; set search tag
and #$F000 ; and check requested type
bne TypeOK
ldx #badInputErr ; bad input parm
bra NoParmErr
TypeOK ;
lda UserTag ; get callers ID
and #$0F00 ; preserve AUX
sta UserTag
cpy #0 ; any tags in list?
beq NewTag ; no
FindLast ;
lda [taglist],y ; else get tag from list
and #$F0FF ; is it same as search tag
cmp SrchTag
beq SameTag ; yes
cpy #0 ; was this the last list entry?
beq NewTag ; yes
dey ; point at next list entry
dey
bra findlast ; and loop to check
SameTag ;
inc SrchTag ; set next possibility
ldy size ; point at last list entry
dec SrchCnt ; how many more searches
dec SrchCnt
bne FindLast ; at least this one
NewTag ;
lda SrchTag ; Get unassigned tag
ora UserTag ; add in the AUX
sta IDtag ; save for caller
ldy size ; point at top of tag list
iny
iny
sta [taglist],y ; store into list
ldx #0 ; assume no error
and #$00FF ; check tag in bounds
bne NoParmErr ; assumed right !
ldx #idTagNtAvlErr ; else tag not available
NoParmErr ;
pla ; clean off tag list address
pla
pla ; clean off size
pla ; clean off search tag
pla ; clean off search count
plb ; restore data bank
pld ; restore direct page
cpx #$0000
bne TagError ; if out of bounds
jmp oEndCall2
TagError ;
phx ; save error code
jsr GetMTHandleSize
dec a ; reduce size by a word
dec a
jsr SetMTHandleSize
plx ; restore error code
jmp oErrOut2
ENDP
****************************************************************
*
DeleteID PROC
*
* Removes the specified ID from the IDTagList
*
*
* Inputs:
* word : id to remove
*
* Outputs:
* none
*
* External Refs:
* none
*
* Entry Points:
* none
*
longa on ; mode
longi on
*
****************************************************************
longa on
longi on
TagList equ 1 ; tag list address
size equ taglist+4 ; ID list size
DeleteCnt equ size+2 ; list size
OrigDBR equ DeleteCnt+2 ; saved data bank reg
OrigDir equ OrigDBR+1 ; saved direct reg
rtl1 equ OrigDir+2
rtl2 equ rtl1+3
IDtag equ rtl2+3 ; ID tag (type and aux)
phd ; save direct page
phb ; save data bank
lda #0 ; init space with zero
pha ; space for tag list address
pha
pha ; space for size
pha ; delete counter
tsc ; turn stack into zp
tcd
lda IDtag ; get ID tag
and #$F0FF ; Type and Main parms only
sta IDtag
jsr GetMTHandleSize
sta size
jsr MTderef ; dereference the handle
stx taglist ; set tag list address
sty taglist+2
*
* search for and delete the requested tag
*
lda size ; any list entries?
beq deletedone ; no
ldy #0 ; point at base of list
FindID ;
lda [taglist],y ; get id from list
and #$F0FF ; Type and Main parms only
cmp IDtag ; check against target
beq FoundIt
iny ; point at next list entry
iny
cpy size ; done all entries?
bne FindID ; no, keep looking
beq deletedone ; yes, no id found
FoundIt ;
inc DeleteCnt ; bump deleted counter
DeleteIt ;
cpy size ; done ?
beq DeleteDone ; yes
iny
iny
lda [taglist],y ; move remaining list down
dey
dey
sta [taglist],y
iny ; point at next list entry
iny
bra DeleteIt ; move entire list
DeleteDone ;
asl DeleteCnt ; count bytes not words
jsr GetMTHandleSize
sec
sbc DeleteCnt ; word wide entries that were
jsr SetMTHandleSize
pla ; clean off tag list address
pla
pla ; clean up size
pla ; clean up delete count
plb
jmp EndCall2
ENDP
****************************************************************
*
StatusID PROC
*
* Indicates whether or not the specified user id is active.
* If the ID is in the list of reserved ID's, no error is
* returned. If the ID is not in the list, the idTagNtAvlErr is
* returned.
*
* This seems kind of silly I know, but what can I say. I
* have to maintain this code, not justify it.
*
*
* Inputs:
* word : UserID to check.
*
* Outputs:
* none
*
* External Refs:
* none
*
* Entry Points:
* none
*
longa on ; mode
longi on
*
****************************************************************
longa on
longi on
taglist equ 1
size equ taglist+4
OrigDBR equ size+2
OrigDir equ OrigDBR+1
rtl1 equ OrigDir+2
rtl2 equ rtl1+3
IDtag equ rtl2+3
phd ; save direct page
phb ; save DBR
lda #0 ; start by getting local space on stack and zeroing it
pha ; space for tag list ptr
pha
pha ; space for size
tsc ; turn stack into zp
tcd
jsr GetMTHandleSize
sta size
jsr MTderef ; dereference the handle
stx taglist ; set tag list address
sty taglist+2
*
* now search for ID tag
*
lda IDtag ; get search tag
and #$F0FF ; Main & Type only
sta IDtag
ldy #0 ; point at base of list
FindID ;
cpy size ; done ?
beq SrchDone ; no ID tag found
lda [taglist],y ; check for tag
and #$F0FF ; type and main only
cmp IDtag
beq FoundIt ; ID is active
iny ; point at next list entry
iny
bra FindID ; and keep looking
SrchDone ;
stz size ; set not found flag
FoundIt ;
pla ; clean up tag list address
pla
pla ; clean off size
plb
cmp #0 ; was ID found?
beq IDinact ; if did not find tag
jmp EndCall2
IDinact ;
ldx #idTagNtAvlErr ; no id for input parm
jmp ErrOut2
ENDP
title 'IRQ Stuff'
****************************************************************
*
* This tool call is used to enable interrupt sources or other
* special functions such as keyboard buffering
*
* Change History
*
* 13 Feb 87 Ray Montagne
*
* Keyboard interrupts did not enable the VBL interrupt
* source. Now it does!
*
****************************************************************
IntSrc PROC
KeyTaskHdr equ $E1014C
KeyTaskCnt equ KeyTaskHdr+4
KeyTaskSig equ KeyTaskCnt+2
KeyTaskJmp equ KeyTaskSig+2
longa on
longi on
lda 7,s ; get reference #
asl a ; make index
tax
cpx #$0020 ; check tool reference
bge DsptchErr ; oops!!!
pea DsptchRet-1 ; push return address
lda >Disptch,x ; and then dispatch address
pha
sep #$30 ; off to 8 bit land for dispatch
longa off
longi off
rts ; do dispatch
DsptchRet ;
rep #$30 ;back to 16 bit land
longa on
longi on
bcs DsptchErr ; if error, then go here
jmp oEndCall2 ; all done
DsptchErr ;
ldx #badInputErr ; Parameter error occured
jmp oErrOut2 ; error exit
Disptch ;
DC.W EnblKbd-1 ; enable keyboard interrupts
DC.W DsblKbd-1 ; disable keyboart int
DC.W EnblVbl-1 ; enable vertical blanking interrupts
DC.W DsblVbl-1 ; disable VBL int
DC.W EnblQtr-1 ; enable quarter second interrupt
DC.W DsblQtr-1 ; disable quarter second int
DC.W EnblSec-1 ; enable 1 second int
DC.W DsblSec-1 ; disable 1 second int
DC.W EnblBuf-1 ; enable keyboard buffering
DC.W DsblBuf-1 ; disable keyboard buffering
DC.W EnblDat-1 ; enable keymicro data int
DC.W DsblDat-1 ; disable keymicro data int
DC.W EnblScan-1 ; enable scan line int
DC.W DsblScan-1 ; disable scan line int
DC.W EnblExt-1 ; enable external VGC int
DC.W DsblExt-1 ; disable external VGC int
EnblKbd ;
longa off
lda #%10000000 ; set KBD IRQ flag
sta >KBDIRQFLAG
rep #$30 ; to 16 bit land
longa on
longi on
lda #1 ; initialize task count
sta >KeyTaskCnt
lda #$A55A ; and set task signature
sta >KeyTaskSig
lda #KeyTask ; now set up jump to task
pha
xba
and #$FF00
ora #$005C
sta >KeyTaskJmp
pla
and #$FF00
ora #^KeyTask
xba
sta >KeyTaskJmp+2
pea $00E1 ; pointer to KBD task
pea $014C
_SetHeartBeat ; install keyboard task
sep #$30
clc
bra ENBLVbl ; changed 13 Feb 87 RBM
KeyTask ;
longa off
longi off
lda #$01 ; reset task count
sta >KeyTaskCnt
lda >KBD ; read keyboard data
bpl NoKBDirq ; if no key, no dispatch
jmp >IRQ_KBD
NoKBDirq ;
rtl
DsblKbd ;
longa off
lda #%00000000 ; clear KBD IRQ flag
sta >KBDIRQFLAG
rep #$30 ; to 16 bit land
longa on
longi on
pea $00E1 ; pointer to KBD task
pea $014C
_DelHeartBeat
rts
EnblVbl ;
longa off
longi off
lda >INTEN ; get mega interrupt reg
ora #%00001000 ; enable VBL interrupts
sta >INTEN
rts
DsblVbl ;
lda >INTEN ; get mega interrupt reg
and #%11110111 ; disable VBL interrupts
sta >INTEN
rts
EnblQtr ;
lda >INTEN ; get mega interrupt reg
ora #%00010000 ; enable 1/4 sec interrupt
sta >INTEN
rts
DsblQtr ;
lda >INTEN ; get mega interrupt reg
and #%11101111 ; disable 1/4 sec interrupt
sta >INTEN
rts
EnblSec ;
lda >VGCINT ; get VGC interrupt reg
ora #%00000100 ; enable 1 sec interrupt
sta >VGCINT
rts
DsblSec ;
lda >VGCINT ; get VGC interrupt reg
and #%11111011 ; disable 1 sec interrupt
sta >VGCINT
rts
EnblScan ;
lda >VGCINT ; get VGC interrupt reg
ora #%00000010 ; enable scan line interrupt
sta >VGCINT
rts
DsblScan ;
lda >VGCINT ; get VGC interrupt reg
and #%11111101 ; disable scan line interrupt
sta >VGCINT
rts
EnblExt ;
lda >VGCINT ; get VGC interrupt reg
ora #%00000001 ; enable external VGC interrupt
sta >VGCINT
rts
DsblExt ;
lda >VGCINT ; get VGC interrupt reg
and #%11111110 ; disable external VGC interrupt
sta >VGCINT
rts
EnblBuf ;
rts
DsblBuf ;
rts
EnblDat ;
lda >KMStatus ; get Keyboard u cmd/status
ora #%00010000 ; enable data interrupts
sta >KMStatus
rts
DsblDat ;
lda >KMStatus ; get Keyboard u cmd/status
and #%11101111 ; disable data interrupts
sta >KMStatus
rts
ENDP
title 'GetTick'
**************************************************************
*
* Returns current tick count value
*
****************************************************************
GetTick PROC
longa on
longi on
IRQstate equ 1
rtl1 equ IRQstate+1
rtl2 equ rtl1+3
LowTick equ rtl2+3
HiTick equ LowTick+2
php ; save interrupt status
sei ; and disable for now
lda >TickCnt ; move tick count to stack
sta LowTick,s
lda >TickCnt+2
sta HiTick,s
plp ; restore interrupt status
jmp oEndCall0
ENDP
title 'FWEntry'
****************************************************************
*
* Firmware Entry Points
*
* This function requires two words of input as follows
*
* Input Word Room for result
* Input Word Room for result
* Input Word Room for result
* Input Word Room for result
* Input Word Accumulator value (low byte)
* Input Word X register value (low byte)
* Input Word Y register value (low byte)
* Input Word Address of Apple// entry point
* Output Word Y register (low byte)
* Output Word X register (low byte)
* Output Word A register (low byte)
* Output Word 6502 status (low byte)
*
* Modification History
*
* 9 Mar 87 Ray Montagne
*
* Processor status was comming off stack in wrong byte of word.
*
* 12 Mar 87 Ray Montagne
*
* Steve buggered my code by puting an and #$00CF in the wrong
* spot. So I fixed it!!!
*
* 17 Nov 88 Konstantin Othmer
*
* Added calls to slot arbiter so that the default slot configuration
* is selected anytime a call is made to the Cn00 space.
* NOTE: This does not effect the text tools since they call fwentry directly.
*
****************************************************************
MonEntry PROC
dir equ 1
ret1 equ dir+2
ret2 equ ret1+3
fwep equ ret2+3
yin equ fwep+2
xin equ yin+2
ain equ xin+2
yout equ ain+2
xout equ yout+2
aout equ xout+2
pout equ aout+2
longa on
longi on
phd ; turn stack into zp
tsc
tcd
;
; Are we in Cn00 Space?
;
lda fwep
cmp #$C000
bcc NotInC000
cmp #$C7FF
bcs NotInC000
;
; Set slots to default configuration and put old config. on stack
;
InC000
lda #$0200 ;request default configuration
jsl slot_arbiter ;
phx ;save original configuration
bra SlotDone
;
; Don't change configuration. Get current and put on stack to be symmetrical with
; above case.
;
NotInC000
lda #$8000 ;Get current configuration but don't change
jsl slot_arbiter ;anything.
phx ;save original configuration
SlotDone
lda fwep ; get fw entry point address
dec a ; adjust for dispatch to FW
pea fwdsptch-1 ; push return address
pha ; push dispatch address
ldy yin ; set up register inputs
ldx xin
lda ain
brl fwentry ; do dispatch
fwdsptch ;
php ; save returned parameters
and #$00FF ; truncate to byte
sta aout ; store output parmeters
stx xout
sty yout
lda 1,s ; get FW 6502 status
and #$00C7 ; truncate to byte
xba ; put processor status in high byte
sta pout ; and store as output parm
rep #$20 ; 16 bit 'm'
plp ; clean up stack
plx ;get old configuration
php ;
;
; Restore old slot configuration which is stored on stack
;
lda #$0300 ;restore to configuration in x reg
jsl slot_arbiter
plp
jmp EndCall8 ; pulls d and cleans up stack
ENDP
title 'Pack and Unpack bytes'
************************************************************************
* *
* FUNCION PackBytes(VAR PicPtr : POINTER; *
* VAR PicSize: INTEGER; *
* BufPtr : POINTER; *
* BufSize: INTEGER) : INTEGER; *
* *
* Params: PicPtr - Pointer to start of picture area to be packed *
* PicSize- Total size to be packed *
* BufPtr - Start of output buffer to pack into *
* BufSize- Maximum space available for packed picture *
* *
* Returns: PackBytes return value: Number of packed bytes generated *
* PicPtr: updated to end of last byte used from picture *
* PicSize: reduced by number of bytes of picture processed *
* *
* FUNCTION UnPackBytes( BufPtr : POINTER; *
* BufSize: INTEGER; *
* VAR PicPtr : POINTER; *
* VAR PicSize: INTEGER) : INTEGER; *
* *
* Params: BufPtr - pointer to area containing packed data *
* BufSize- max size of area containing packed data *
* PicPtr - Pointer to start of area to unpack into *
* PicSize- Maximum space available for unpacked picture *
* *
* Returns: UnPackBytes return Value: Actual number of bytes unpacked *
* PicPtr: Updated to one past end of last byte unpacked *
* PicSize: reduced by number of bytes of picture generated *
* *
* ------------------------------------------------------ *
* *
* Sample Calls: *
* *
* picsize:=$7d00; *
* bufsize:=$400; *
* REPEAT *
* HowMuch:=PackBytes(PicPtr,PicSize,BufPtr,BufSize); *
* Write(f,bufptr,howmuch); *
* UNTIL picsize=0; *
* *
* *
* {***} *
* *
* *
* OpenFile; *
* Mark:=StartofFile; *
* PicSize:=$7d00; *
* BufSize:=$400; *
* REPEAT *
* SetFileMark(Mark); *
* Read(f,BufPtr,Bufsize); *
* HowMuch:=UnPackBytes(BufPtr,BufSize,PicPtr,PicSize); *
* Mark:=Mark+HowMuch; *
* UNTIL ( (PicSize=0) OR EOF(f) ); *
* *
* ----------------------------------------------------------- *
* *
* Packed data incription format: *
* *
* %00xxxxxx : (xxxxxx : 0->63) = 1 to 64 bytes follow - *
* All Different *
* *
* %01xxxxxx : (xxxxxx : 1,2,3,5,6,7) = 1,2,3,5,6,7 repeats - *
* of next byte *
* *
* %10xxxxxx : (xxxxxx : 0->63) = 1 to 64 repeats - *
* of next 4 bytes *
* *
* %11xxxxxx : (xxxxxx : 0->63) = 1 to 64 times 4 repeats - *
* of next byte *
* *
* ----------------------------------------------------------- *
* *
* Written By: Eagle I. Berns *
* *
* Modification History: *
* *
* 10-DEC-85 EIB First coding begun *
* 5-Mar-87 SEG Error code returned is now 0 *
* in both Pack and Unpack *
* *
************************************************************************
************************************************************************
* Main Packbits entry *
************************************************************************
PACKBYTES PROC
from EQU 1
to EQU from+4
endbuf EQU TO+4
prev EQU endbuf+4
count EQU prev+4
lf EQU count+2
Origdrct EQU lf+2
rtl1 EQU origdrct+2
rtl2 EQU rtl1+3
Bufsize EQU rtl2+3
BufPtr EQU Bufsize+2
PicsizeP EQU BufPtr+4
PicPtrP EQU PicSizeP+4
Result EQU PicPtrP+4
; -> +2
PHD ; SET UP STACK AS ZERO PAGE +PARMS
TSC
SEC
SBC #ORIGDRCT-1
TCS
TCD
LDA [PICPTRP] ; GET THE ARGS.
TAX ; (PICPTRP NEEDS DE-REFERANCE)
LDY #2
LDA [PICPTRP],Y
STA FROM+2
STX FROM
LDA [PICSIZEP]
STA COUNT
LDA BUFSIZE
SEC
SBC #5 ;END LESS FIVE FOR ENDING TEST
CLC
ADC BUFPTR
STA ENDBUF
LDA BUFPTR+2
STA TO+2
ADC #0
STA ENDBUF+2
LDA BUFPTR
STA TO
LDA #0
TAY
STA [TO],Y
STA LF
INC LF ; MAKE LAST<>FIRST TO BEGIN
LDA #$FFFF ; SET PREV TO INVALID
STA PREV
STA PREV+2
MAINLOOP JSR ISIT44 ; CHECK IF MULTI-4 MATCH
BCC CNT4S ; YES, OUNT THEM
JMP MORECL ; NO, MOVE ALONG FOR MORE CHECKS
*****************************************
* *
* Now, count 4's grouping on the *
* input and store the results in the *
* output and adjusts all necessary *
* pointers. NOTE: this routine will *
* assume at least one match got you *
* in here, thus one match assumed. *
* *
*****************************************
CNT4S LDX #1 ; X COUNTS HOW MANY PAIRS
CLOOP JSR ISIT44 ; DO IT DO THE 4 4 MATCH
BCS CDONE ; NO IT DON'T - GO FINISH UP
CPX #64 ; REMEMBER, $3F MAX
BEQ CDONE
LDA COUNT ; DON'T GO PAST END
BEQ CDONE
SEC
SBC #4
BLT CDONE
LDA FROM
CLC
ADC #4
STA FROM
LDA FROM+2
ADC #0
STA FROM+2
INX ; BUMP THE COUNT
LDA COUNT
SEC
SBC #4
STA COUNT
BRA CLOOP
CDONE DEX ; LESS ONE FOR CMD.
PHX ; SAVE COUNT AWHILE
JSR LOOKAT4
BEQ CMAT4 ; GOT 4'S AND THEY'RE ALL THE SAME
PLA ; GET COUNT BACK FOR THIS CASE
ORA #$80 ; SET APPROPRIATE FLAGS
LDY #0
STA [TO],Y ; STORE COMPRESSIION TYPE WORD+COUNT
LDA [FROM],Y ; GET 1ST TWO BYTES TO STORE
INY
STA [TO],Y ; STORE 1ST TWO AFTER COMMAND
INY
LDA [FROM],Y ; GET NEXT 2 INPUTS (Y IS NEATLY OK!)
STA LF
INY
STA [TO],Y ; NOW DATA IS STORED CORRECTLY
LDA TO ; 'TO' LOC BUMPS BY 5
STA PREV
CLC
ADC #5
STA TO
LDA TO+2
STA PREV+2
ADC #0
STA TO+2
BRA CJOIN ;GO FINISH UP
CMAT4 PLA ;GET THE COUNT
ORA #$C0
STA [TO] ;STORE CONTROL INFO+COUNT
LDY #3
LDA [FROM],Y ;GET THE BYTE THAT MATCHES
STA LF
LDY #1
STA [TO],Y ; STORE 2 BUT COUNT ONLY 1
LDA TO ; 'TO' LOC BUMPS BY 2
STA PREV
CLC
ADC #2
STA TO
LDA TO+2
STA PREV+2
ADC #0
STA TO+2
CJOIN LDX #4 ;'FROM' AND 'COUNT' NEED 4 BUMP STILL
JMP BMPF
MORECL JSR ISIT44 ; DO WE HAVE 4-4 MATCH FROM HERE
BCC DOSTR2 ; YES, GO HANDLE IT
INY
CPY #4 ; HAVE WE MOVED THROUGH 4
BCC MORECL
DOSTR2 PHY
LDY #0
JSR LOOKAT4 ; CHECK FOR SOME MATCHES
TXA ; NUMBER OF THEM TO A
PLX ; NO. TO DEAL WITH TO X
*****************************************
* *
* Now, add into the output stream *
* a spec for consecutive bytes of *
* from 1 to 4 (all matching) and will *
* modify previous spec if necessary *
* A reg. contains max no. of the *
* chars we may consider. *
* X reg. has 1,2,3 or 4 for the num. *
* of matched chars. *
*****************************************
LDY #0
PHA
TXA
SEC
SBC 1,S ; A NOW HAS REG. X - REG Y
BLT STU1
LDA 1,S
TAX ; NOW, X HAS MAX REALLY TO CONSIDER
STU1 PLA ; FROM EXTRA PUSH FOR ARITH.
TXA ; STORE IT FOR CHECK ON END
CMP COUNT
BLT STU2
LDX COUNT ; IF PAST END, USE LOWER COUNT
STU2 LDA LF ; CHECK IF LAST=FIRST
XBA
CMP LF
BNE DIFF ; NO, SO GO STORE DIFF. DATA
LDA PREV+2 ; IS THERE A PREV
CMP #$FFFF
BEQ DIFF ; NOPE, SO NO MATCH
LDA [PREV],Y ; GET LAST COMMAND TO SE WHAT TO DO
AND #$FF ; CHECK FOR COMMAND 'C0',BYTE
CMP #$C0
BNE DIFF ; NOPE, SO JUST DO THESE ALONE
TXA ; GOOD ONE, SO X+4 WILL STORE TO PREV
CLC
ADC #3 ; 4 - 1 FOR CMD. OFFSET
ORA #$40 ; SET FLAGS INTO CMD
PHA ; TEMP.
LDA [PREV],Y ; GET PREVIOUS
AND #$FF00 ; DATA ONLY
STA [PREV],Y
PLA
ORA [PREV],Y ; WITH NEW COUNT & DATA
STA [PREV],Y ; SAVE IT
BMPF TXA ; GET COUNT
CLC
ADC FROM
STA FROM ;BUMP FROM BY X (AMT.)
LDA FROM+2
ADC #0
STA FROM+2
PHX
LDA COUNT
SEC
SBC 1,S
PLX
STA COUNT
CMP #0
BNE MORCHK
JMP ALLDONE
MORCHK LDA TO+2 ; CHECK IF PAST END OF BUFFER
CMP ENDBUF+2
BNE NOTDON
LDA TO
CMP ENDBUF
BLT NOTDON
JMP ALLDONE
NOTDON LDY #0 ; BE SURE Y=0 WHEN WE GO BACK
JMP MAINLOOP ; ALL DONE, BACK TO MAIN LOOP
DIFF CPX #3 ;IF 1 OR 2, JUST ADD
BLT DO12
BEQ DO3 ; IF 3, GO SET UP IT'S COMMAND
LDA #$C0 ; FOR 4, SET IT'S COMMAND
BRA JDO
DO3 LDA #$42
JDO PHA ; SAVE IT
LDA [FROM],Y ; GET THE CHAR.
AND #$FF ; -JUST THE CHAR
XBA
STA [TO],Y
PLA
ORA [TO],Y ; NOW HAVE CMD & COUNT
STA [TO],Y
TXY ;FOLLOWING IS TO GET LF RIGHT
DEY
LDA [FROM],Y
STA LF
LDY #0 ;RESET Y
BMPT2 LDA TO ; TO:=TO+2;
STA PREV
CLC
ADC #2
STA TO
LDA TO+2
STA PREV+2
ADC #0
STA TO+2
BRA BMPF
DO12 LDA PREV+2 ; CHECK FOR A PREV
CMP #$FFFF
BEQ NEW1
LDA [PREV],Y ; CHECK PREV CMD.
AND #$C0 ; IF WAS ADD 1 CHAR, JUST ADD 1 OR 2 IN
CMP #00
BNE NEW1 ; NO, GO DO NEW 1 OR 2
LDA [PREV],Y ; CHECK IF>MAX- MAKE NEW 1 OR 2 IF SO
AND #$FF
CMP #$3F
BEQ NEW1
CPX #2 ; IF 2, & AT $3E JUST ADD 1
BNE OKADDIN
CMP #$3E
BNE OKADDIN
LDX #1 ; JUST 1, GET NEXT ONE NEXT TIME AROUND
OKADDIN TXA ; YES, ADD IN 1 OR 2
CLC
ADC [PREV],Y ; YES, ADD 1 OR 2 IN
STA [PREV],Y
LDA [FROM],Y
STA LF
STA [TO],Y
TXA
CLC
ADC TO
STA TO
LDA TO+2
ADC #0
STA TO+2
JMP BMPF ; GO BUMP FROM
NEW1 LDA [FROM],Y ; GET THE DATA
STA LF
AND #$FF ; JUST 1 CHAR
XBA
STA [TO],Y
LDX #1 ; DO ONLY ONE, IF 2 GET IT NEXT TIME
BRA BMPT2 ; GO ADJUST POINTERS
ALLDONE LDA TO
SEC
SBC BUFPTR
STA RESULT ; SET RESULT LENGTH
LDA FROM
SEC
SBC [PICPTRP]
PHA ; HOLD IT, NEED SIZE - IT
LDA [PICSIZEP]
SEC
SBC 1,S
STA [PICSIZEP]
PLA
LDA FROM
STA [PICPTRP]
LDA FROM+2
LDY #2
STA [PICPTRP],Y
LDA ORIGDRCT
TCD
LDA RTL1,S ;FIX STACK UP CORRECTLY
STA RESULT-6,S
LDA RTL1+2,S
STA RESULT-4,S
LDA RTL1+4,S
STA RESULT-2,S
TSC
CLC
ADC #RESULT-7
TCS
LDA #0 ; fix by SEG on 5 March 87
CLC ; fix by SEG on 5 March 87
RTL
ENDP
************************************************************************
* Support routines called by packbits *
************************************************************************
*****************************************
* *
* Lookat4: looks at 4 bytes at [FROM],Y *
* and returns in X : *
* *
* X=4 => XXXX (i.e 4 same bytes) *
* X=3 => XXX- *
* X=2 => XX-- *
* x=1 => x--- *
* *
* RETURN ALSO: CONDITION = IF X=4 *
* CONDITION <> IF NOT *
* *
*****************************************
Lookat4 PROC
from EQU 1
to EQU from+4
endbuf EQU to+4
prev EQU endbuf+4
count EQU prev+4
lf EQU count+2
LDX #1 ; INIT X TO DEFAULT NO MATCHES
LDA [FROM],Y ; GET TWO BYTES TO COMPARE
XBA ; SWITCH FOR COMPARE
CMP [FROM],Y
BNE LDONE ; NOT =, RETURN (X=1)
INX
INY ; CHECK FOR 2ND AND 3RD MATCHING
CMP [FROM],Y
BNE LDONE ; NOT =, RETURN (X=2)
INX
INY
CMP [FROM],Y
BNE LDONE ; NOT =, RETURN (X=3)
INX ; ELSE, X=4 ALL 4 MATCH
CPX #4 ; (JUST TO SET COND. TO =)
LDONE RTS
ENDP
*****************************************
* *
* ISIT44 - Checks for two consecutive *
* sets of 4 matching bytes. *
* Returns Carry Set for no match and *
* Carry Clear for match. *
* NOTE: X register is not changed. *
* *
*****************************************
ISIT44 PROC
from EQU 1
to EQU from+4
endbuf EQU to+4
prev EQU endbuf+4
count EQU prev+4
lf EQU count+2
PHY ;MUST PRESERVE
LDA [FROM],Y ;1ST 2 BYTES OF FIRST 4
INY ;BUMP BY 4
INY
INY ;NOTE: CHECK IF PAST END ONLY IF WE
INY ; GET THE MATCH, ELSE, WHO CARES
CMP [FROM],Y ; 1ST 2 BYES OF NEXT 4
BNE NOT44
DEY
DEY ;BACK UP TO 2ND 2 OF 1ST 4
LDA [FROM],Y
INY
INY
INY
INY
CMP [FROM],Y ;COMPARE TO 2ND 2 OF 2ND 4
BNE NOT44 ;NOPE, GET OUT
*
* HERE, WE GOT THE MATCH, BUT BE SURE 8 BYTES REMAIN SO WE CAN DO IT
*
LDA COUNT
SEC
SBC #8
BMI NOT44 ; LESS THAN 8 , WE CANT COUNT IT
PLY ; RESTORE Y
CLC ; ALLS WELL, RETURN CLEAR CARRY
RTS
NOT44 PLY
SEC ; NO MATCH
RTS
ENDP
************************************************************************
* Main UnPackbits entry *
************************************************************************
UNPACKBYTES PROC
from EQU 1
to EQU from+4
endbuf EQU to+4
temp EQU endbuf+4
count EQU temp+4
lf EQU count+2
Origdrct EQU lf+2
rtl1 EQU origdrct+2
rtl2 EQU rtl1+3
PicSizeP EQU rtl2+3
PicPtrP EQU PicSizeP+4
Bufsize EQU PicPtrP+4
BufPtr EQU BufSize+2
Result EQU BufPtr+4
; -> +2
PHD ; SET UP STACK AS ZERO PAGE +PARMS
TSC
SEC
SBC #ORIGDRCT-1
TCS
TCD
LDA [PICPTRP] ; GET THE ARGS.
TAX ; (PICPTRP NEEDS DE-REFERANCE)
LDY #2
LDA [PICPTRP],Y
STA TO+2
STX TO
LDA [PICSIZEP]
STA COUNT
LDA BUFPTR
STA FROM
CLC
ADC BUFSIZE
STA ENDBUF
LDA BUFPTR+2
STA FROM+2
ADC #0
STA ENDBUF+2
DOUNPACK LDY #0
LDA [FROM],Y ; GET THE COMMAND
STA TEMP
AND #$3F
TAX ; GET COUNT ONLY INTO X
INC FROM ; BUMP TO FIRST BYTE TO TRANSFER
BNE M1
INC FROM+2
M1 BIT TEMP-1 ; V & C BITS GIVE COMMAND
BMI REP4
BVS REP1 ; 01xxxxxx -> REPEAT NEXT 1 BYTE
BRA DIFF ; 00xxxxxx -> ALL DIFFERENT
REP4 BVS REP41 ; 11xxxxxx -> REPEAT 4 OF NEXT 1 BYTE
BRA REP44 ; 10xxxxxx -> REPEAT OF NEXT 4 BYTES
OUTP PLA
JMP UDONE ; GO FINISH UP
*****************************************
* *
* DIFF : 0 ->63 IN A MEANS 1->64 *
* DIFFERENT BYTES FOLLOW TO BE MOVED *
* *
*****************************************
DIFF PHA ; WHEN WE GO TO COMMON CODE, WE NEED
; SOMETHING STACKED (OTHER CALLS USE IT)
BRA JOIN
*****************************************
* *
* REP1 : 1,2,3,5,6,7 REPEATS OF FOLLOW- *
* ING BYTE. *
* *
*****************************************
REP1 LDA TEMP ; PUT BYTE IF LOW & HIGH & ON STACK
AND #$FF00
PHA
XBA
ORA 1,S
STA 1,S
BRA JOIN ; JOIN UP, X=LEN IS CORRECT STILL
*****************************************
* *
* REP41 : IS SAME AS REP1 ABOVE, EXCEPT *
* COUNT IN X MUST BE 4 TIMES > *
* *
*****************************************
REP41 INX
TXA
ASL A
ASL A
TAX
DEX
BRA REP1
*****************************************
* *
* REP44 : MUST SET UP FOR 2 STORES I.E. *
* 4 BYTES WORTH, AND COUNT IS *
* DOUBLED (2 STORES EACH TIME) *
* *
*****************************************
REP44 INX
TXA
ASL A
TAX ; FIRST DOUBLE X
DEX
PHA ; MUST PUT SOMETHING ON STACK FOR
; OTHER CASES
* BRA JOIN ; WE FIND 4 BYTES AT [FROM],
* (FALL THROUGH TO JOIN) ; SO MUST REMEMBER TO FIND IT THERE
*****************************************
* *
* JOIN : HERE, THE LOAD STORE SEQUENCE *
* OF DATA TRANSFER TAKES PLACE *
* *
*****************************************
JOIN CPX COUNT ; BE SURE THERE'S ROOM
BGE OUTP ; NO - DONE (BUT PULL OFF EXTRA PUSH)
LDA #1 ; CHECK IF LENGTH WOULD GO OVER
BIT TEMP-1 ; DEPENDS ON TYPE OF CMD.
BVS L1 ; LEN=1 FOR %01 & %11
BMI L4 ; LEN=4 FOR %10
TXA
INC A ; LEN=N+1 FOR %00..N...
BRA L1
L4 LDA #4
L1 CLC ; FROM+LEN .LT. ENDBUF MEANS NOT DONE
ADC FROM
PHA ; SAVE FOR COMPARE
LDA FROM+2
ADC #0
CMP ENDBUF+2
BCC NOTDONP
PLA
CMP ENDBUF
BLT NOTDON
BEQ NOTDON
BRA OUTP
NOTDONP PLA
NOTDON CPX #0 ; (NEEDED FOR 1ST ENTRY IN LOOP)
LOOP BMI DOUPD ; YES
*****************************************
* *
* MOVEIT : USED LOCALLY TO FETCH PROPER *
* INPUT, DEPENDING ON TYPE OF *
* CMD. BEING PROCESSED *
* NOTE: X<0 MEANS STORE 1 BYTE ONLY *
*****************************************
BIT TEMP-1 ; THIS HAS THE FLAGS
BMI MREP4
BVS MREP1
CPX #0 ; IF NEG. IT'S ONE BYTE ONLY
BEQ MSPEC
LDA [FROM],Y
STA [TO],Y
INY
INY
JMP NDMOV
MSPEC SEP #%00100000
LDA [FROM],Y
STA [TO],Y
REP #%00100000
INY
JMP NDMOV
MREP1 CPX #0
BEQ M2SPEC
LDA 1,S
STA [TO],Y
INY
INY
JMP NDMOV
M2SPEC SEP #%00100000
LDA 1,S
STA [TO],Y
REP #%00100000
INY
JMP NDMOV
MREP4 BVS MREP1 ;REP41 SAME AS REP1 BUT LARGER COUNT
LDA [FROM]
STA [TO],Y
PHY ; HOLD Y A SEC
LDY #2
LDA [FROM],Y
PLY
INY
INY
STA [TO],Y
INY
INY
******
NDMOV DEX
DEX
BRA LOOP ; GO DO NEXT ONES
DOUPD PLA ; GET RID OF EXTRA PUSH
LDA TEMP ; UPDATE APPROPRIATE POINTERS
AND #$3F
INC A
BIT TEMP-1
BMI XREP4 ; FROM DEPENDS ON TYPE
BVC XDIFF ; FOR 00xxxxxx ADD LENGTH
FP1 LDA #1 ; FOR 01xxxxxx ADD 1
XDIFF CLC
ADC FROM
STA FROM
LDA FROM+2
ADC #0
STA FROM+2
BRA DOTO
XREP4 BVS FP1 ; FOR 11xxxxxx ALSO ADD 1
LDA #4 ; FOR 10xxxxxx ADD 4
BRA XDIFF
DOTO TYA ; Y IS OUTPUT COUNT
CLC
ADC TO
STA TO
LDA TO+2
ADC #0
STA TO+2
TYA
STA TEMP
LDA COUNT
SEC
SBC TEMP
STA COUNT
JMP DOUNPACK
UDONE LDA FROM
SEC
SBC BUFPTR
DEC A
STA RESULT ; SET RESULT LENGTH
LDA TO
SEC
SBC [PICPTRP]
PHA ; HOLD IT, NEED SIZE - IT
LDA [PICSIZEP]
SEC
SBC 1,S
STA [PICSIZEP]
PLA
LDA TO
STA [PICPTRP]
LDA TO+2
LDY #2
STA [PICPTRP],Y
LDA ORIGDRCT
TCD
LDA RTL1,S ;FIX STACK UP CORRECTLY
STA RESULT-6,S
LDA RTL1+2,S
STA RESULT-4,S
LDA RTL1+4,S
STA RESULT-2,S
TSC
CLC
ADC #RESULT-7
TCS
LDA #0 ; fix by SEG 5 March 87
CLC ; fix by SEG 5 March 87
RTL
ENDP
title 'Munger'
************************************************************************
* *
* FUNCION Munger (VAR DestPtr : POINTER; *
* VAR DestLen : INTEGER; *
* TargPtr : POINTER; *
* TargLen : INTEGER; *
* ReplPtr : POINTER; *
* ReplLen : INTEGER; *
* VAR Pad : INTEGER) : INTEGER; *
* *
* Params: DestPtr - Pointer to text to be manipulated *
* DestLen - Number of bytes to be included in manipulation *
* TargPtr - String to be searched for in above text *
* TargLen - its length *
* ReplPtr - string to replace with when target string found *
* ReplLen - its length *
* Pad - <on entry> : character to pad with stored as int.*
* Pad - <returned value> : pad amount *
* *
* Returns: Munger returns a negative value if target not found *
* *
* Pad returns the net effect of the replacement. If data is *
* truncated, a negative value, and if blanks are padded in *
* at the end, a positive value count *
* *
* DestPtr is updated to one past the replacement *
* DestLen is reduced by amount of data passed over *
* *
* *
* Special considerations: *
* *
* - If TargPtr is 0, the substring of length TargLen is *
* replaced by ReplPtr's string *
* *
* - If TargLen is 0, ReplPtr's string is inserted at DestPtr *
* *
* - If ReplPtr is 0, DestPtr is updated to past the end of the *
* TargPtr's string *
* *
* - If ReplLen is 0, (and ReplPtr is NOT 0) TargPtr's string is *
* deleted rather than replaced (since the replacement string *
* is empty) *
* *
* There is one case in which munger performs a replacement even *
* if it doesn't find all of the target string. If DestPtr's *
* entire string is at the begining of TargPtr's string, then *
* the entire DestPtr string is replaced with ReplPtr's string *
* *
* ------------------------------------------------------ *
* *
* Sample Calls: *
* *
* {***} *
* *
* *
* ----------------------------------------------------------- *
* *
* *
* Written By: Eagle I. Berns *
* *
* Modification History: *
* *
* 01-JAN-86 EIB First coding begun *
* 01-AUG-86 EIB fixed targptr=0 bug *
* 02-AUG-86 EIB fixed delete (repllen=0) *
* 05-Mar-87 EIB fixed one byte compare problem for targe string of *
* length one. *
* SEG Routine now clears carry and puts zero in A-reg *
* on exit *
* *
************************************************************************
************************************************************************
* Main munger entry *
************************************************************************
MUNGER PROC
search EQU 1
find EQU search+4
destptr EQU find+4
destlen EQU destptr+4
temp EQU destlen+2
padchar EQU temp+4
Origdrct EQU padchar+2
rtl1 EQU origdrct+2
rtl2 EQU rtl1+3
padP EQU rtl2+3
repllen EQU padP+4
replptr EQU repllen+2
targlen EQU replptr+4
targptr EQU targlen+2
destlenP EQU targptr+4
destptrP EQU destlenP+4
result EQU destptrP+4
; -> +2
PHD ; SET UP STACK AS ZERO PAGE +PARMS
TSC
SEC
SBC #ORIGDRCT-1
TCS
TCD
LDA [DESTPTRP] ; GET THE ARGS.
STA DESTPTR
STA SEARCH
LDY #2
LDA [DESTPTRP],Y
STA DESTPTR+2
STA SEARCH+2
LDA [DESTLENP]
STA DESTLEN
CMP REPLLEN ; IF REPLLEN >, SHORTEN IT
BGE MLBZ
STA REPLLEN
MLBZ CMP TARGLEN ; TARGLEN ALSO
BGE MLB0
STA TARGLEN
MLB0 LDA [PADP]
STA PADCHAR
LDA TARGPTR ; SAVE LOCAL TARGET PTR.,CHECK FOR ZERO
STA FIND
TAX
LDA TARGPTR+2
STA FIND+2 ; IF ZERO - SPECIAL CASE - INSERT
BNE MLB1
CPX #0
BNE MLB1
*===> bug fix: next line deleted EIB 1-AUG-86
* STA DESTLEN ; SET TO 0 , DO REPLACE - (INSERT)
BRA MUNGREP ; (ARGS ARE 'SEARCH' AND 'DESTLEN')
MLB1 LDA DESTLEN ; DESTLEN<=TARGLEN SPECIAL - CHECK @ CHAR 1
SEC
SBC TARGLEN
BEQ MLB2
BLT MLB2
JMP MUNGGNRL
MLB2 LDA DESTLEN ; CALL COMPARE (DESTLEN,SEARCH,FIND)
STA TARGLEN ; FORCE SAME LEN. FOR PTR. ADJ. LATER
JSR MUNGCMPR
BEQ MUNGREP ; MATCH, GO REPL. FULL DEST. STRING
MUNGOUT LDA #0 ; DONE, RETURN 0 PAD
STA [PADP]
STA RESULT
DEC RESULT ; NEGATIVE RESULT
JMP MUNGXIT
MUNGGNRL TAX ; X HOLDS HOW FAR DOWN 'SEARCH' WE GO
MLB4 LDA TARGLEN ; CALL COMPARE (TARGLEN,SEARCH,FIND)
JSR MUNGCMPR
BEQ MUNGREP ; GOT IT, GO DO REPLACE
INC SEARCH ; NO, MOVE ALONG SEARCH
BNE MLB5
INC SEARCH+2
MLB5 DEX
BPL MLB4 ; BACK IF WE CAN SEARC MORE
BRA MUNGOUT ; NO MATCH, GO QUIT
*****
*
* HERE, MOVE destlen CHARS FROM replptr TO search
* AFTER VERIFYING replptr & repllen & SPECIAL CASES
*
****
MUNGREP LDA REPLPTR ; SIMPLE CASE - UPDATE destptr
BNE MLB6 ; IF replptr 0
LDA REPLPTR+2
BNE MLB6
*===> bug fix: next 2 lines not needed any longer EIB 1-AUG-86
* LDA [DESTLENP] ; IN CASE WE CHANGED IT BEFORE
* STA DESTLEN
LDA TARGLEN ; IF TARGLEN ALSO 0, MAKE DESTLEN 0
BNE MUNGRP2
STA DESTLEN
MUNGRP2 JSR MUNGPMOV ; UPDATE destptr & destlen
LDA #0 ; ALL DONE - RETURN 0
STA RESULT
STA [PADP] ; PAD ALSO 0 - NO CHANGE
JMP MGD2OUT
MLB6 JSR MUNGPMOV ; HAVE REPLPTR - SO ADJUST PTRS FIRST
***
*
* MOVE FROM DESTPTR TO SEARCH+REPLLEN FOR LENGTH DESTLEN
* AND ADJUST PAD BY TARGLEN-REPLLEN
*
***
LDY #2
LDA [DESTPTRP] ; COMPUTE TRUE END OF INPUT
CLC
ADC [DESTLENP]
STA FIND ; (USE 'FIND' TO HOLD IT IN)
LDA [DESTPTRP],Y
ADC #0
STA FIND+2
LDA DESTLEN ; CHECK IF PAST END AND ADJUST
PHA ; SAVE FOR LATER
LDA TARGLEN
SEC
SBC REPLLEN
STA [PADP] ; THATS PAD AMOUNT, WILL NEED LATER
LDA SEARCH
CLC
ADC REPLLEN
STA TEMP
LDA SEARCH+2
ADC #0
STA TEMP+2 ; TEMP:=SEARCH+REPLLEN
CMP FIND+2 ; CHECK IF TEMP>FIND (I.E. END OF INPUT)
BGE CHKMOR
DSTGRTR LDA [PADP]
BPL MGD1 ; POS. SO CAN DO FULL MOVE
CLC
ADC DESTLEN ; ADD NEG. (SUBT.) FOR CORRECT LEN
DSTGT2 STA DESTLEN
STA 1,S
BRA MGD1
CHKMOR BNE DSTSMLR
LDA FIND
CMP TEMP
BGE DSTGRTR
DSTSMLR LDA FIND ; TOO BIG, ADJ. REPLLEN & REPLACE ONLY
SEC
SBC SEARCH
STA REPLLEN
PLA ; DON'T FORGET TO GET RID OF THIS
JMP MGDOUT
************************************************************************
* *
* MEMORY MANAGER BLOCKMOVE PROCEEDURE WITH SRC = <DESTPTR> , *
* DEST = <TEMP> , AND LENGTH ON THE STACK (DO THE PULL) *
* *
************************************************************************
MGD1 PLX
PUSHLONG DESTPTR
PUSHLONG TEMP
PEA 0
PHX
_BLOCKMOVE
MGDS LDA TARGLEN ; TARGLEN>REPLLEN - MUST PAD
SEC
SBC REPLLEN ; TARGLEN BLANKS FROM DESTPTR+DESTLEN
BEQ MGDOUT
BLT MGDOUT
PHA ; SAVE FOR COMPUTATION
LDA DESTPTR
CLC
ADC DESTLEN
STA TEMP
TAX ; SRC - FOR RIPPLE MOVE
LDA DESTPTR+2
ADC #0
STA TEMP+2
TXA
SEC ; TEMP:=TEMP-<DIFF. IN COUNT>
SBC 1,S
STA TEMP
LDA TEMP+2
SBC #0
STA TEMP+2
LDA [TEMP]
AND #$FF00 ; STORE 1 BLANK BYTE
ORA PADCHAR ; OR IN PAD CHARACTER
STA [TEMP]
LDA PADCHAR ; GET TWO BYE PAD
XBA
ORA PADCHAR
TAX ; HOLD IN X AWHILE
LDA 1,S ; WAS COUNT ODD OR EVEN
AND #$01
BEQ MGD2 ; EVEN, GO DO IT
PLA
DEC A ; MAKE EVEN IF WASN'T
BEQ MGDOUT ; BUT DONE IF WAS 1
PHA
INC TEMP ; BUMP ADDRESS 1 ALSO
BNE MGD2
INC TEMP+1
MGD2 PLY ; Y NOW HAS COUNT OF STORES
TXA ; A NOW HAS PAD TO FILL WITH
MGD3 DEY ; DO THE TIGHT STORE LOOP
DEY
STA [TEMP],Y
BNE MGD3
****
*
* NOW MOVE REPLLEN CHARS. FROM REPLPTR TO SEARCH
*
***
* ===> bug fix: PUSHLONGS must be AFTER test below - EIB 2-AUG-86
MGDOUT LDA REPLLEN ;LEN
BEQ MGD2OUT
PUSHLONG REPLPTR ;SRC
PUSHLONG SEARCH ;DEST
PEA 0
LDA REPLLEN
PHA
_BLOCKMOVE
MGD2OUT LDY #2
LDA SEARCH
CLC
ADC REPLLEN
STA [DESTPTRP]
LDA SEARCH+2
ADC #0
STA [DESTPTRP],Y
LDA DESTLEN
STA [DESTLENP]
MUNGXIT LDA ORIGDRCT
TCD
LDA RTL1,S ;FIX STACK UP CORRECTLY
STA RESULT-6,S
LDA RTL1+2,S
STA RESULT-4,S
LDA RTL1+4,S
STA RESULT-2,S
TSC
CLC
ADC #RESULT-7
TCS
lda #0 ; fixed 5 March 87 SEG
clc ; fixed 5 March 87 SEG
RTL
*****************************************
* *
* MUNGPMOV - UPDATE DESTPTR & DESTLEN *
* BY TARGLEN AMOUNT *
* *
*****************************************
MUNGPMOV LDA SEARCH ; TEMP:=SEARCH+TARGLEN (WHERE TO WIND UP)
CLC
ADC TARGLEN
STA TEMP
LDA SEARCH+2
ADC #0
STA TEMP+2
LDA TEMP ; FIND := TEMP-DESTPTR (DIST. MOVED)
SEC
SBC DESTPTR
STA FIND
LDA DESTLEN ; DESTLEN:=DESTLEN-FIND (LEFT TO SCAN)
SEC
SBC FIND
STA DESTLEN
LDA TEMP ; DESTPTR:=TEMP (WHERE TO GO NEXT)
STA DESTPTR
LDA TEMP+2
STA DESTPTR+2
RTS
*****************************************
* *
* MUNGCMPR - COMPARE REG. A BYTES *
* @ SEARCH *
* & FIND *
* *
*****************************************
MUNGCMPR LDY #0 ; (USUALLY)
PHX ;MUST PRESERVE X REG.
CMP #0 ; 0 LENGTH ALWAYS =
BNE MGC1
LDA #0 ; SET FOR RETURN = CONDITION
BRA MGCOND
MGC1 PHA
AND #01 ; ODD OR EVEN COMPARE LENGTH
BEQ MGCLP ; IF EVEN, JUST DO COMPARES
LDA [SEARCH]
AND #$FF ; ODD, DO FIRST BYTE - THEN EVEN AMT.
PHA
LDA [FIND]
AND #$FF
CMP 1,S
BEQ MGONE
PLA
PLA ; GET RID OF PUSH
MGCNO LDA #1
MGCOND PLX ; RESTORE X
CMP #0 ; SET COND. CODE
MGCOUT RTS
MGONE PLA ; EXTRA
PLA ; GET LENGTH
DEC A ; LESS 1 TO MAKE EVEN
BEQ MGCEQU ; patch on 5 March 87 by EIB
PHA ; BACK ON
LDY #1 ; MOVE FORWARD 1
MGCLP PLX ; GUARENTEED EVEN
MGCLP1 LDA [SEARCH],Y
CMP [FIND],Y
BNE MGCNO
INY
INY
DEX
DEX
BNE MGCLP1
MGCEQU LDA #0 ; SET EQUAL RETURN
BRA MGCOND ; GO QUIT
ENDP
title 'IRQ Stuff'
****************************************************************
*
* This tool returns the state of hardware interrupt enables
* under the control of the miscellaneous tool set.
*
* D8-15 Undefined
* D7 1 = Keyboard interrupts enabled
* D6 1 = Vertical blanking interrupts enabled
* D5 1 = Quarter second interrupts enabled
* D4 1 = One second interrupts enabled
* D3 RESERVED
* D2 1 = Front desk bus data interrupts enabled
* D1 1 = Scan line interrupts enabled
* D0 1 = External VGC interrupts enabled
*
****************************************************************
GetIRQenbl PROC
longa on
longi on
OrigDir equ 1
rtl1 equ OrigDir+2
rtl2 equ rtl1+3
irqstate equ rtl2+3
phd ; turn stack into zp
tsc
tcd
stz irqstate ; assume no sources enbl
sep #$20 ; 8 bit 'm'
longa off
lda >KBDIRQFLAG ; if KBD interrupts, set flag
tsb irqstate
nokbden ;
lda >inten ; get mega irq reg
pha
and #%00001000 ; vbl on?
beq novblen ; set flag bit if on
lda #%01000000
tsb irqstate
novblen ;
pla ; get mega irq reg
and #%00010000 ; 1/4 sec on?
asl a ; set flag bit if enabled
tsb irqstate
lda >vgcint ; get VGC irq reg
pha
and #%00000100 ; 1 sec on?
asl a
asl a ; set flag bit if enabled
tsb irqstate
lda >kmstatus ; get KBDu status
and #%00010000 ; fdb data irq on?
lsr a ; set flag bit if enabled
lsr a
tsb irqstate
pla ; get VGC irq reg
and #%00000011 ; scan lines or ext on?
tsb irqstate ; set flag bit if on
rep #$30 ; 16 bit 'm' & 'x'
longa on
longi on
jmp EndCall0
ENDP
title 'SysBeep'
SysBeep PROC
****************************************************************
*
* There are no input parameters to this tool call.
* No output parameters will be returned on this tool call.
* This call will dispatch to the Apple// entry point 'BELL1'.
* The bell routine may be patched out by using the setvector
* call with a parameter reference number of $001B. Any routine
* installed into the bellvector will be called in native mode
* with 8 bit 'm' and 'x'.
*
****************************************************************
ldx #8 ; 8 words to push
lda #$FBDD ; BELL1 entry in rom
here ;
pha
dex
bne here
_FWEntry
pla ; clean off stack
pla
pla
pla
jmp oEndcall0 ; return to application
ENDP
END