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

TITLE ', MISC.a - Get_TempBuff'
*
****************************************************************
*
* Get Temporary Buffer
*
* Inputs: A - Length of temporary buffer requested
*
* Outputs: TempBuff - Address of temporary buffer
* A - status
* C - set if error occurred
*
* Zero Page used: none
*
****************************************************************
*
Get_TempBuff PROC
with DirectPage
;
; get a temporary buffer
;
ldx #0 ;output Handle
phx
phx
phx
pha ;BlockSize
pea uTempBuff ;Owner
pea attrLocked ;Attributes
phx ;Location
phx
_NewHandle
plx ;Handle
ply
bcs error
;
; set TempBuff to address of temporary buffer
;
txa
jsr DeRef
sta TempBuff
sty TempBuff+2
return lda #0
clc
error rts
ENDP
TITLE ', MISC.a - Block_Move'
*
*************************************************************************
* BLOCK MOVE FOR NON-OVERLAPPING BLOCKS
* (converted from ProDOS code)
*
* Moves a block of data from a source location to a destination
* location. The source and destination blocks may overlap.
*
* Calling sequence:
* Place machine in full native mode (e=0, m=0, x=0)
* Push high order word of source pointer onto stack
* Push low order word of source pointer
* Push high order word of destination pointer
* Push low order word of destination pointer
* Push high order word of transfer count
* Push low order word of transfer count
* JSR Block_Move
* Outputs: None
* Side effects: Moves the block of data from source to destination
* Notes:
* The high byte of Source, Dest, and Count must be zero
* The Count may not be 0 or $FFFF.
* This routine contains self modifying code--it cannot run in ROM
*************************************************************************
*
Block_Move PROC
Source equ $0F ; 4-byte source address
Dest equ $0B ; 4-byte destination address
Count equ $07 ; 4-byte transfer count
ReturnMove equ $05 ; 3-byte return address
TempCount equ $03 ; 2-byte temporary transfer count
*
MoveBlock equ * ; main entry point
pha ; push two bytes on stack for TempCount
phd ; save D
tsc ; make direct page correspond to stack
tcd
*
* get ready to do the move
*
phb ; save DBR on stack (MVN trashes it)
phk ; set DBR to PBR
plb
ldx Source ; X = low word of Source
ldy Dest ; Y = low word of Dest
*
* set up the self modifying code to contain dst src
*
lda Dest+2 ; make sure high byte of Dest is 0
and #$00FF
sta Dest+2
lda Source+2 ; get source bank
and #$00FF ; make sure high byte of Source is 0
xba
ora Dest+2 ; or in destination bank (high byte must be zero)
sta DoMove+1 ; put bank values into MVN instruction (danger)
*
* check for illegal values of Count
*
lda Count
ora Count+2
beq exit
cmp #$FFFF
beq exit
*
* decrement Count because it contains actual transfer count whereas
* remainder of routine assumes it contains transfer count - 1
*
lda Count
bne @1
dec Count+2
@1
dec a
sta Count
*
* initialize TempCount
*
sta TempCount
bra mdFirst
*
* main move loop
*
mdMore sta Count+2 ; more bytes to move
lda >DoMove+1 ; A = SrcDst banks
cpx #1 ; bank cross? if X=0
bcs mdXNot0
adc #$0100 ; add 1 to source bank
mdXNot0 cpy #0 ; did destination cross bank?
bne mdYIs0
inc a
mdYIs0 sta >DoMove+1
mdFirst
txa ; if count > -X then bank cross
eor #$FFFF
cmp TempCount
bcs mdXOk
sta TempCount ; only move -X bytes
mdXOk tya ; will destination cross bank?
eor #$FFFF
cmp TempCount
bcs mdYOk
sta TempCount ; only move -Y bytes
mdYOk lda TempCount ; get the number of bytes to move
*
* the following 3 bytes are the actual move instruction
* this routine dynamically modifies the source and destination banks
*
DoMove DC.B $54 ; opcode for MVN
DS.B 1 ; destination bank
DS.B 1 ; source bank
*
lda Count ; Count = Count - bytes moved
clc ; actual bytes moved 1 more than count
sbc TempCount
sta Count
sta TempCount
lda Count+2
sbc #0
bpl mdMore
*
* clean up everything before returning
*
exit plb ; restore DBR
pld ; restore D
pla ; remove TempCount
*
lda #0
clc
Stack_Cleanup 12
rts ; go home
ENDP
TITLE ', MISC.a - MemMove'
****************************************************************
*
* pascal void MemMove(source, dest, n)
* char *source, *dest;
* int n;
*
* Description
* Copies 'n' characters from memory area 'source' to 'dest'.
* This function is the same as memcpy, except that can also
* work on overlapping objects.
*
* This was ripped off from the C library, and then modified
* to be somewhat call-compatible with BlockMove.
*
****************************************************************
MemMove Func
source equ $09
dest equ $05
n equ $03
tsc ;get current stack position
phd ;save current direct page
tcd ;set up local direct page
lda n ;check # of bytes to copy
beq exit ;if 0, don't bother!
bmi exit ;if negative, skip it
lda source ;get low word of source address
sec
sbc dest ;calculate difference
tax ;save in X for a bit
lda source+2 ;must do high word (to propogate carry)
sbc dest+2
bne normal ;if 'source' comes after 'dest', it doesn't matter
cpx n ;compare low word result against # of characters to move
bcs normal ;no overlap...
; use this block if 'source' starts in the midst of 'dest'
ldy #0 ;initialize index
sep #$20 ;8-bit accumulator
longa off
@loop
lda [source],y ;get a character
sta [dest],y ;store in destination
iny ;bump index
cpy n ;compare to # of characters to move
bcc @loop ;continue until done
bra done ;then exit
; use this block if there is no overlap or if 'dest' is higher in memory
; than 'source'
normal
ldy n ;get # of characters to move
sep #$20 ;shift into 8-bit accumulator
longa off
bra @do_it ;jump into loop
@loop
lda [source],y ;get a byte
sta [dest],y ;and copy it
@do_it
dey ;one less byte to move
bne @loop ;loop until at beginning of array
lda [source] ;copy the last (first) byte
sta [dest]
done
rep #$20 ;back to 16-bit accumulator
longa on
exit
pld
Stack_Cleanup 10
rts
endf
TITLE ', MISC.a - DeRefUse'
*
****************************************************************
*
* Combines DeRef and UsePtr
*
* Instead of:
*
* jsr DeRef
* jsr UsePtr
*
* call:
*
* jsr DeRefUse
*
****************************************************************
*
DeRefUse PROC
jsr UsePtr
lda |0,x
ldy |2,x
; jsr UsePtr
; rts
; fall into UsePtr
TITLE ', MISC.a - UsePtr'
*
****************************************************************
*
* Use Pointer setup
*
* Make a Pointer usable for indirect loading or storing
* without using Zero Page. Here is an example of how
* this routine is used. Suppose 'APtr' contains a Pointer
* to a Buffer and you want to extract the 1st 4 bytes
* out of the Buffer. Remember the Pointer and the Buffer
* can be anywhere in memory.
*
* lda APtr ;lo bytes of Pointer
* ldy APtr+2 ;hi bytes of Pointer
* phb ;save DBR
* jsr UsePtr ;call this routine
* lda |0,x ;get 1st two bytes
* ldy |2,x ;get 2nd two bytes
* plb ;restore DBR
*
* Inputs: A,Y - Pointer (Low bytes in A, High bytes in Y)
*
* Outputs: X - Low bytes of Pointer
* DBR - Bank of Pointer
*
****************************************************************
*
Entry UsePtr
UsePtr
tax ;move lo bytes into X
tya ;move hi bytes into A
xba ;get bank byte into B
pha ;bank + trash
plb ;remove trash
plb ;set bank to bank of Pointer
rts ;return
ENDP
TITLE ', MISC.a - DeRef'
*
****************************************************************
*
* Dereference a Handle
*
* Without using Zero Page
*
* Inputs: A,Y - Handle (Low bytes in A, High bytes in Y)
*
* Outputs: A,Y - Pointer (Low bytes in A, High bytes in Y)
* C - set if Pointer=0
*
****************************************************************
*
DeRef PROC
phb ;save DBR
phx ;save X
jsr UsePtr ;make Handle usable
clc
lda |0,x
ldy |2,x
pha ;save A
ora |2,x ;check whether pointer=0
bne cont
sec ;yes, set carry
cont pla ;restore A
plx ;restore X
plb ;restore DBR
rts ;return
ENDP
TITLE ', MISC.a - save_dp'
*
****************************************************************
*
* saves contents of direct page
*
* Inputs: none
*
* Outputs: C - set if problem allocating memory
* Handle to allocated memory is returned on stack
*
****************************************************************
*
save_dp Proc
ldx #256 ;allocate 256 bytes
ldy #0
lda #uTempDP ;UserID
jsr do_alloc ;allocate some memory
bcs @nfg
pla ;remove return address
phy ;save handle on stack
phx
pha ;put return address back on stack
txa ;put low word into accumulator
jsr DeRef ;deref the handle
pea 0 ;make source pointer on stack
phd
phy ;put destination pointer on stack
pha
pea 0 ;put count on stack
pea 256
jsr Block_Move ;copy the block
lda 5,s ;duplicate handle on stack
pha
lda 5,s
pha
_HUnlock ;let the block float around if necessary
@nfg
rts
EndP
TITLE ', MISC.a - restore_dp'
*
****************************************************************
*
* restores previously saved direct page
*
* Inputs: Handle to saved direct page (on stack)
*
* Outputs: C - set if Acc != 0 on entry
*
****************************************************************
*
restore_dp Proc
with Globals
sta save_a ;save possible error code
plx ;pull return address
pla ;retrieve DP buffer handle
ply
phx ;put return address back on stack
phy ;put handle on stack
pha ;for eventual _DisposeHandle call
jsr DeRef ;deref the handle
phy ;put on stack as source address
pha
pea 0 ;put address of direct page on stack
phd ;as destination address
pea 0 ;count = 256
pea 256
jsr Block_Move ;go restore the direct page
_DisposeHandle ;release the DP buffer
lda save_a ;restore accumulator
cmp #$0001 ;condition carry
rts
EndP