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
24 KiB
Plaintext

string asis
blanks off
print push
print off
include 'common.equ.src'
print pop,nogen,nopage,nohdr
;====================================================================================================
;
;Fast.Access: This setup file will speed up file writes to the console driver.
;
;Created: June 25, 1989
;Modified: June 28, 1989
;Author: Rob Turner
;
;Modified: August 7, 1989
;Modifier: Greg Branche
;
; At @call_console_fast, the code now checks whether it's handing a read call or a write
; call. If it's a read call, it skips the modification to the JSR SIGNAL instruction. In
; other words, the call to the signal handler only get's patched out during a driver write
; call. This allows Rob's improved console driver to continue working with this speed-up
; init file. (His modification to the User Input Routine (UIR) implemented a method of
; using the signal handler so that the CDA menu was still accessible while waiting for
; input in the UIR.)
;
;Modified: August 25, 1989
;Modifier: Greg Branche
;
; When verifying the device characteristics, the code masks the 'Fixed Name' bit, since
; it's not important, and the value of that bit has changed since System Disk 5.0.
;
;Modified: July 3, 1990
;Modifier Greg Branche
;
; Updated addresses, version numbers, and code for use with GS/OS version 3.03 (System
; disk 5.0.3).
;
;====================================================================================================
go_main proc
import main
jmp main
endp
;====================================================================================================
;equates used by fast access. The following address MUST be changed if GS/OS is changed!!!!
;====================================================================================================
OSVersNum equ $0303 ;OS Version number required
ConsVersNum equ $3010 ;Console driver version number
return_address equ $00D5BD ;address we return to after call.
return_check equ $2BAB
entry_type equ $00A025 ;Better be there
patch_address equ $00D5A0 ;address in Language card
patch_check1 equ $3A22 ;patch value = JSL 00B73A
patch_check2 equ $00B7
signal_patch equ $009EC9 ;Address of signal dispatch.
signal_check1 equ $AB20 ;"JSR $ECAB" SEP #$20
signal_check2 equ $E2EC
TwoNOPs equ $EAEA ;Two NOP instructions
INCBusyPatch equ $009E38 ;Address of INC Busy call in the OS
INCBusyCheck equ $6422 ;Part of JSL $E10064
DECBusyPatch equ $009EC0 ;Address of DEC Busy call in the OS!
DECBusyCheck equ $6822 ;Part of JSL $E10068
IncDecCommon equ $E100 ;High word of JSL $E10068 = 22 68 00 E1
UnlockPatch equ $00D5B9 ;Address in LC of call to Force Unlock.
UnlockCheck1 equ $4222 ;Part of JSL $00B742 = 22 42 B7 00
UnlockCheck2 equ $00B7 ;Second Part of above JSL
OSUnlockRoutine equ $00B742
OSLockRoutine equ $00B73A
inc_busy_flag equ $E10064 ;address of inc_busy_flag call
dec_busy_flag equ $E10068 ;address of dec_busy_flag call
call_block equ $D4
temp_error equ $00A02E ;error code returned to caller
do_Unlock equ $0000
do_DEC_Busy equ $0000
No_DEC_Busy equ $0001 ;BIT set = No DEC Busy flag
No_UnLock equ $8000 ;BIT set = No_Unlock memory
;====================================================================================================
;Macros used by FastAccess
;====================================================================================================
MACRO
&lab _GSOSCall &param1,&param2
&lab jsl $E100A8
DC.W &param1
DC.L &param2
MEND
open equ $2010
close equ $2014
DControl equ $202E
GetDevNum equ $2020
Version equ $202A
AddNotifyProc equ $2034
DInfo equ $202C
;====================================================================================================
;Local Data used by FastAccess
;====================================================================================================
Console_Dev_Num record
dc.w 00 ;Device number of the Console Driver
endr
;====================================================================================================
;entry_patch: This routine is called by GS/OS at the at the beginning of the OS call.
;
;Input: A = saved
; X = saved
; Y = saved
; P = saved
; ..000...
; b = k
;
;
;Output: A = restored
; X = restored
; Y = restored
; P = restored
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
entry_patch proc
user_stack equ $48
phb
lda >entry_type ;prepare to get call_num and parm_block
beq lc_stack_entry ;processing differs by inline vs. stack
entry lc_inline_entry
lc_inline_entry ldy #3 ;set up pointer to 1 byte below call_num
lda [<user_stack],y ;user return address in user stack ...
sta <call_block ;... is the proper value
iny
lda [<user_stack],y
sta <call_block+1
bra get_parms
entry lc_stack_entry
lc_stack_entry clc ;set up pointer to 1 byte below call_num
lda <user_stack
adc #5 ;address of location 5 bytes above user
sta <call_block ;... stack pointer is the right value
stz <call_block+2
get_parms ldy #1 ;call_number to GS/OS direct page
lda [<call_block],y
sta <call_number
tax
ldy #3 ;param_blk_ptr to GS/OS direct page
lda [<call_block],y
sta <param_blk_ptr
ldy #5
lda [<call_block],y
sta <param_blk_ptr+2 ;Now PUSH the Parameter block pointer BANK
;
;Set flag that says "Do not Call ForceUnlock and Do not call DEC Busy"
;
lda #No_Unlock+No_DEC_Busy
sta >LockFlag_and_DECFlag
;
;Now check for a CONSOLE write call.
;
ldy #$0002 ;setup for class 1 write call
txa
cmp #$2013 ;is the call a write call?
beq @chk_if_console
ldy #$0000 ;setup for class 0 write call
cmp #$0013
beq @chk_if_console
;
;Now check to see if we are doing a DRead or DWrite call. IF we are doing DRead or DWrite
;Then DO NOT do ForceLock/Unlock or INC/DEC busy flag.
;
@check_DRead
cmp #$202F
bne @check_DWrite
lda #drvr_read
sta drvr_call_num ;setup the call number
bra @dev_common ;see if the device is the CONSOLE
@check_DWrite
cmp #$2030
bne @chk_close ;see if a close call is being made.
lda #drvr_write
sta drvr_call_num ;setup for Device Write
@dev_common
lda [param_blk_ptr] ;Check the PCount
cmp #$0006
bne @call_os ;Punt
ldy #$0002 ;see if this is the console driver please
lda [param_blk_ptr],y ;get the device number
cmp >console_dev_num ;is it the console!
beq @do_fast_console ;yes so do it fast!
plb
rtl ;NOT .CONSOLE but skip Lock/Unlock and INC/DEC Busy.
;
;Now see if we are making a close call. If so then zero out our check reference number
;and call the OS!
@chk_close
and #$00FF
cmp #$0014
bne @call_os ;do a standard OS call.
lda #'RT'
sta >console_ref ;enable search please
@call_os
jsl inc_busy_flag ;Do INC Busy Flag
jsl OSLockRoutine ;Do a ForceHandleLock Call
lda #Do_DEC_busy+Do_Unlock ;set flag that indicates we should "unLockHandle" and
;do a DEC Busy Flag
sta >LockFlag_and_DECFlag
;
;Restore "JSR Signal_dispatch" code in GS/OS, We may have trashed on on Console Write.
;
lda #signal_check1 ;restore orignal GS/OS code
sta >signal_patch
lda #signal_check2
sta >signal_patch+2
plb
rtl
@chk_if_console
lda #drvr_write ;we only call on write calls.
sta drvr_call_num ;setup the call number
lda [param_blk_ptr],y ;get the reference number
tax
;
;Setup the drvr_buf_ptr
;
@do_fast_console
iny
iny
lda [param_blk_ptr],y
sta drvr_buf_ptr
iny
iny
lda [param_blk_ptr],y
sta drvr_buf_ptr+2
;
;Setup the request count please
;
iny
iny
lda [param_blk_ptr],y
sta drvr_req_cnt
iny
iny
lda [param_blk_ptr],y
sta drvr_req_cnt+2
stz drvr_blk_num
stz drvr_blk_num+2
stz drvr_tran_cnt
stz drvr_tran_cnt+2
stz drvr_blk_size
lda <call_number ;is this a file write call
cmp #$202F ;IF < DRead then Must be Write Call
bcc @do_FILE_stuff
;
;IF here then we need to verify that the Starting Block is zero and the block num is zero
;
iny
iny
lda [param_blk_ptr],y
iny
iny
ora [param_blk_ptr],y
bne @call_os ;let the OS fail
iny
iny
lda [param_blk_ptr],y ;check the block size
bne @call_os
;
;For DRead and DWrite we want the BUSY flag to work, so handle it here.
;
lda #do_DEC_Busy+No_Unlock ;Force DEC busy on exit.
sta >LockFlag_and_DECFlag
jsl inc_busy_flag ;Go ahead and do a INC busy
bra @call_console_fast
@do_FILE_stuff
txa ;get the reference number again
cmp >console_ref ;is it the console's reference number?
beq @call_console_fast ;Make this puppy fly!!!
jsl find_fcr ;get the file control record
bcs @call_os
jsl deref ;get me a real pointer please
stx call_block
sty call_block+2
ldy #fcr_fst_id
lda [call_block],y
cmp #$0009 ;character FST
bne @to_call_os ;cannot be console driver!
ldy #fcr_access+2
lda [call_block],y ;get the device number
cmp >console_dev_num
beq @get_ref
@to_call_os
brl @call_os ;it is not the console driver
@get_Ref
lda [call_block] ;get the reference number
sta >console_ref ;save for next time
@call_console_fast
;
;Replace "JSR Signal_Dispatch" with NOPs only if writing to the driver
;(reading from .CONSOLE requires the signal handler to be working properly)
;
ldx drvr_call_num ;get the call number
cpx #drvr_read ;reading?
beq @skip_signal_patch ;yes, skip the signal patching
lda #TwoNOPS ;Trash Signal Dispatch on exit please
sta >signal_patch
sta >signal_patch+1
@skip_signal_patch
lda >console_dev_num
sta drvr_dev_num
; lda drvr_call_num ;used as input to the console driver
txa ;drvr_call_num is still in X register
export console_address
console_address jsl $0000000 ;call the console driver please A=call number!!
bcs @oops ;had an error!
lda #$0000 ;else make sure the accumulator is clear
@oops
rol a ;save carry in low bit of temp_error
sta >temp_error
bcs @error
;
;Now we need to send the Transfer count to the caller.
;
ldy #$000A
lda <call_number ;is this a file write call
cmp #$0013 ;Class 0 write call.
beq @do_XFer_cnt
cmp #$2013 ;Write call
bne @DType_Call
ldy #$000C
lda [param_blk_ptr] ;Check the PCount for Class 1 write call
cmp #$0004
bcc @error ;Sorry the PCount DOES NOT include TRANSFER Count
bra @do_XFer_cnt
@DType_Call
ldy #$0012
@do_XFer_cnt
lda drvr_tran_cnt
sta [param_blk_ptr],y
iny
iny
lda drvr_tran_cnt+2
sta [param_blk_ptr],y
@error
plb ;fix the stack please
pla ;pull off the return address!!
sep #$20
pla
rep #$20
jml return_address ;return to SCM with error stuff.
;====================================================================================================
;This routine is called to do the DEC Busy Routine!!
;
; IF the LOW Bit of LockFlag_and_DECFlag is set then we just EXIT otherwise dec_Busy_Flag
;
;====================================================================================================
export DECBusyEntry
DECBusyEntry
lda >LockFlag_and_DECFlag ;see if we should do a DEC Busy Flag
lsr a
bcc @do_Dec_busy
rtl
@do_Dec_busy
jml dec_busy_flag ;returns to the OS
;====================================================================================================
;This routine is called to do the ForceUnlock Routine!!
;
; IF the HIGH Bit of LockFlag_and_DECFlag is set then we just EXIT otherwise UNLOCK
;
;====================================================================================================
export ForceUnlockEntry
ForceUnlockEntry
lda >LockFlag_and_DECFlag ;see if we should do a DEC Busy Flag
bpl @do_forceUnlock
rtl ;skip Unlock
@do_forceUnlock
jml OSUnlockRoutine ;Call original
console_ref dc.w 'RT'
LockFlag_and_DECFlag dc.w $00
endp ;return to GS/OS
;====================================================================================================
;resize_handle: This routine shrinks the handle size and returns to GS/OS
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
resize_handle proc
my_handle equ $00
php
sei ;Kill interrupts
pha ;space for result
pha
pea resize_handle>>16
pea resize_handle ;our own address
ldx #$1A02
jsl $e10000 ;FindHandle
plx
ply ;get the handle
bcs @exit
bne @have_handle
txa
beq @exit ;handle is NIL so exit.
@have_handle
stx my_handle
sty my_handle+2
ldy #$0004 ;unlock my handle
lda [my_handle],y
and #$7FFF
sta [my_handle],y
pea $0000 ;high word
lda new_size
pha
pei my_handle+2
pei my_handle
ldx #$1902
jsl $e10000 ;Set Handle Size
bcs @exit
ldy #$0004 ;unlock my handle
lda [my_handle],y
ora #$8000 ;lock the handle
sta [my_handle],y
@exit
plp ;restore interrupt state.
rtl
new_size dc.w resize_handle-go_main
endp
Console_Name record
dc.w $08
dc.b '.CONSOLE'
endr
;====================================================================================================
;check_os_version: This routine makes sure we are using GS/OS version 3.0 only.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = OS Version number
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = bad OS version
; b = k
;
;
;====================================================================================================
longa on
longi on
check_os_version proc
_GSOSCall Version,VersionList
bcs @error_exit
lda OSVersion
and #$7FFF ;clear the proto bit.
cmp #OSVersNum
bne @error_exit
clc
rts
@error_exit
sec
rts
;*************************************************************************************************
;************************ Local Variables used by this routine ***********************************
;*************************************************************************************************
VersionList dc.w $0001 ;PCount for the call
OSVersion dc.w 0000 ;The result
endp
;====================================================================================================
;trap_handler: This routine is called directly by the console driver!
;
;Input: A = call number
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = console driver bank.
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = console driver bank
;
;
;====================================================================================================
longa on
longi on
trap_handler proc
php
pha
;
;Picture of the stack:
;
; --------------
; A Register $0001
; --------------
; Process $0003
; --------------
; Return addr $0004
; --------------
;
sec
lda 4,s ;get the return address
sbc #$0003 ;get address of Vector call routine!
tax
lda 6,s
and #$00FF
sbc #$0000
;
;Console_Address jsl $000000 ;call console
;
; $22 00 00 00
;
xba ;put bank address in high byte of accum.
sta >console_address+2
txa ;low 16 bits of console address.
sta >console_address+1
pla ;restore A register and flags
plp
rtl
endp ;let the call continue please
;====================================================================================================
;get_console_entry: This routine will setup the console driver device Number and setup
; the console driver patch.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
get_console_entry proc
;
;Before we can use the console driver we must open it first
;
_GSOSCall open,OpenList
bcs @exit ;Holy Cow BatMan!
lda ref_num ;setup reference number for the close call.
sta close_ref
;
;Now lets get the device number setup please.
;
_GSOSCall GetDevNum,GetDevList
bcs @close_and_exit
lda ret_dev_num ;Device number returned by the call.
sta console_dev_num ;save number for Global use
sta ctrl_dev_num ;used for DControl Calls
sta DInfo_dev_num ;used for DInfo call to console!
;
;Lets make sure that the console driver we are using is the one we think it is.
;
jsr check_cons_version
bcs @close_and_exit
;
;Issue a reset_trap call to the console driver. This will nuke anyones installed handler
;
stz request_count ;zero request count for this call
lda #$8007 ;reset trap address
sta ctrl_code
_GSOSCall DControl,DCtrlList
bcs @close_and_exit ;This call should not fail
;
;Add in my console driver handling routine.
;
lda #$0004 ;setup the request count
sta request_count
lda #$8006 ;Add_Trap address
sta ctrl_code
_GSOSCall DControl,DCtrlList
bcs @close_and_exit
;
;Reset the handler again. Note: this call will cause our Trap_Handler to be called, then
; removed, hows that for trickyness!!
;
stz request_count ;zero request count for this call
lda #$8007 ;reset trap address
sta ctrl_code
_GSOSCall DControl,DCtrlList
@close_and_exit
php
pha ;save error code if any
_GSOSCall close,CloseList
pla
plp
@exit
rts
check_cons_version
_GSOSCall DInfo,DInfoList
bcs @error_out
lda dev_char ;check the characteristics
and #%1111101111111111 ;doesn't matter whether the name is fixed or not (gab)
cmp #$0B60
bne @error_out ;sorry I don't know this console
lda slot_num
cmp #$8003 ;fake slot 3
bne @error_out
lda unit_num
dec a
bne @error_out ;we want unit 1
lda con_version ;we patch only if console is version 3.01
and #$FFF0 ;don't care about alpha, beta, or whatever
cmp #ConsVersNum
bne @error_out
lda dev_id
cmp #$000A ;check the device ID as well.
bne @error_out
clc
rts
@error_out
sec
rts
;*************************************************************************************************
;************************ Local Variables used by this routine ***********************************
;*************************************************************************************************
DInfoList dc.w $0008 ;PCount
DInfo_dev_num dc.w 000
dc.l name_buffer
dev_char dc.w 00 ;device characteristics
dc.l 00 ;total blocks
slot_num dc.w 00
unit_num dc.w 00
con_version dc.w 00 ;Console Version Number
dev_id dc.w 00 ;Device ID
name_buffer dc.w $000C
name_size dc.w 0000
dc.b '.CONSOLE' ;This will get over written at runtime.
GetDevList dc.w $0002 ;PCount
dc.l console_name ;pointer to the name ".CONSOLE"
ret_dev_num dc.w 00 ;resulting device number
DCtrlList dc.w $0005 ;PCount
ctrl_dev_num dc.w 00 ;Device number of .CONSOLE
ctrl_code dc.w 00 ;Call I wish to make
dc.l control_list ;pointer to the control data
request_count dc.l 00 ;number of bytes used
dc.l 00 ;transfer count
Control_list dc.l trap_handler ;address of routine to get data
OpenList dc.w $0002 ;PCount
Ref_Num dc.w 000 ;ref num of console driver
dc.l console_name
CloseList dc.w $0001
close_ref dc.w 000
endp
;====================================================================================================
;patch_os: This routine sets up a patch in the OS. The patch will allow us to get control
; Before we have gone to far into an OS call
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000..1 = error
; b = k
;
;
;====================================================================================================
longa on
longi on
patch_os proc
statereg equ $c068 ;state register
lcbank2 equ $c083 ;sel LC ram bank2, 2 rds wrt enb LC ram
lcbank1 equ $c08b ;sel LC ram bank1, 2 rds wrt enb LC ram
longa off
sep #$20
lda >statereg ;save current language card state
sta lc_state
lda >lcbank1 ;select and write enable language ...
lda >lcbank1 ;... card RAM bank 1 (really 0)
longa on
rep #$20
lda >patch_address ;see if this is OK to patch
cmp #patch_check1
bne @error_exit
lda >patch_address+2
cmp #patch_check2
bne @error_exit
;
;Check the INC Busy Call
;
lda >INCBusyPatch ;is this right!
cmp #INCBusyCheck
bne @error_exit ;Sorry NO GO
;
;Check the DEC Busy routine.
;
lda >DECBusyPatch
cmp #DECBusyCheck
bne @error_exit ;Sorry NO GO
;
;Check the FORCEUNLOCK call
;
lda >UnLockPatch
cmp #UnlockCheck1
bne @error_exit
lda >UnlockPatch+2
cmp #UnlockCheck2
bne @error_exit
;
;Check the return address to make sure we are OK
;
lda >return_address ;make sure the return code is still there!!
cmp #$2BAB ;should be a PLB PLD
bne @error_exit ;we cannot patch it!
lda >signal_patch
cmp #signal_check1
bne @error_exit
lda >signal_patch+2
cmp #signal_check2
beq @patch_it
@error_exit
sec ;set error condition
bra @exit
@patch_it
;
;It all passes so lets patch the OS please.
;
lda patch1 ;install entry patch please
sta >patch_address
lda patch1+2
sta >patch_address+2
;
;Install ForceUnlock patch
;
lda UnlockJSL
sta >UnlockPatch
lda UnlockJSL+2
sta >UnlockPatch+2
;
;Install DECBusy Patch
;
lda DECBusyJSL
sta >DECBusyPatch
lda DECBusyJSL+2
sta >DECBusyPatch+2
;
;NOP out the JSL INCBusy
;
lda #TwoNOPS
sta >INCBusyPatch
sta >INCBusyPatch+2
clc
bra @exit
@exit
pha
php
lda lc_state
sep #$20
sta >statereg ;restore langauge card setting
rep #$20
plp
pla
rts
;*************************************************************************************************
;************************ Local Variables used by this routine ***********************************
;*************************************************************************************************
lc_state dc.w 00
patch1 jsl entry_patch ;put in patch to our code
UnlockJSL jsl ForceUnlockEntry
DECBusyJSL jsl DECBusyEntry
endp
;====================================================================================================
;main: This is the main entry point to the program, it is called when we get loaded.
; Note that it is NOT called on each OS call.
;
;Input: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;Output: A = undefined
; X = undefined
; Y = undefined
; P = nvmxdizc
; ..000...
; b = k
;
;
;====================================================================================================
longa on
longi on
main proc
phk ;you know the story here.
plb
jsr check_os_version ;are we running GS/OS version 3.0?
bcs @version_exit ;I cannot patch the OS.
jsr get_console_entry ;get the console driver's dev num and entry
bcs @unload_exit
jsr patch_os
bcs @unload_exit
jmp resize_handle ;Shrink and Exit!!!!
@version_exit
cmp #$0300
bcc @exit ;IF greater > 3.0 then purge me, else exit.
@unload_exit
lda #$0001
sta 4,s ;set the unload flag for GQuit
@exit
rtl ;return with Unload request!!
endp
end