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

TITLE ', RELOCATION.a - Do_LCONST'
*
****************************************************************
*
* Process LCONST record
*
* This is NOT a subroutine. It is entered with a JMP
* and exits to either: RELOC_LOOP, RELOC_ERROR or
* RELOC_RETURN which are in 'Do_Segment'.
*
****************************************************************
*
Do_LCONST PROC
with DirectPage, Globals
;
; read rest of record header
;
ldx #4
jsr Read_Record
bcs to_reloc_error
;
; read record into memory
;
cont1 pei CAddress+2
pei CAddress
lda |Record+2
pha
lda |Record
pha
jsr Read_File
bcs to_reloc_error
;
; if Pathname Segment, add pathnames to Pathname Table
;
lda Header.Kind
and #%11111
cmp #Path_Segment
bne cont2
pei Handle+2
pei Handle
pei CAddress+2
pei CAddress
jsr Do_Path_Segment
bcc cont3
to_reloc_error
jmp Reloc_Error
;
; if Jump Table Segment, chain to existing Tables
;
cont2 cmp #Jump_Segment
bne cont3
pei Handle+2
pei Handle
pei CAddress+2
pei CAddress
jsr Do_Jump_Segment
bcs to_reloc_error
;
; bump address of memory by the # of bytes read
;
entry update_cAddress
update_cAddress
cont3 lda |Record
clc
adc CAddress
sta CAddress
lda |Record+2
adc CAddress+2
sta CAddress+2
jmp Reloc_Loop
ENDP
TITLE ', RELOCATION.a - Do_DS'
*
****************************************************************
*
* Process DS record
*
* This is NOT a subroutine. It is entered with a JMP
* and exits to either: RELOC_LOOP, RELOC_ERROR or
* RELOC_RETURN which are in 'Do_Segment'.
*
****************************************************************
*
Do_DS PROC
with DirectPage, Globals
;
; read rest of record
;
ldx #4
jsr Read_Record
bcc @1
jmp Reloc_Error
@1
;
; memory does not have to be zeroed by this subroutine
; because the whole memory segment was zeroed by
; 'Allocate_Segment'
;
; bump address of memory by the # of bytes zeroed
;
bra update_cAddress
ENDP
TITLE ', RELOCATION.a - Do_RELOC'
*
****************************************************************
*
* Process RELOC record
*
* This is NOT a subroutine. It is entered with a JMP
* and exits to either: RELOC_LOOP, RELOC_ERROR or
* RELOC_RETURN which are in 'Do_Segment'.
*
* Inputs: CAddress - Segment Address
* Outputs: TempZero - Address to be patched
* TempZero+4 - Value of patch
*
****************************************************************
*
Do_RELOC PROC
with DirectPage, Globals
Bytes equ 0 ;# of bytes in patch
Shift equ 1 ;shift count
Offset equ 2 ;offset of patch in segment
Value equ 6 ;offset of reference in segment
ldx #10
jsr Common_Pass1_Check
;
; calculate address of patch = Load Address + Offset
;
lda CAddress
clc
adc |Record+Offset
sta TempZero
lda CAddress+2
adc |Record+Offset+2
sta TempZero+2
;
; calculate patch = Load Address + Value
;
lda CAddress
clc
adc |Record+Value
sta TempZero+4
lda CAddress+2
adc |Record+Value+2
sta TempZero+6
jmp Common_Reloc
ENDP
TITLE ', RELOCATION.a - Do_cRELOC'
*
****************************************************************
*
* Process compressed RELOC record
*
* This is NOT a subroutine. It is entered with a JMP
* and exits to either: RELOC_LOOP, RELOC_ERROR or
* RELOC_RETURN which are in 'Do_Segment'.
*
* Inputs: CAddress - Segment Address
* Outputs: TempZero - Address to be patched
* TempZero+4 - Value of patch
*
****************************************************************
*
Do_cRELOC PROC
with DirectPage, Globals
Bytes equ 0 ;# of bytes in patch
Shift equ 1 ;shift count
Offset equ 2 ;offset of patch in segment
Value equ 4 ;offset of reference in segment
ldx #6
jsr Common_Pass1_Check
;
; calculate address of patch = Load Address + Offset
;
lda |Record+Offset
clc
adc CAddress
sta TempZero
lda #0
adc CAddress+2
sta TempZero+2
;
; calculate patch = Load Address + Value
;
lda |Record+Value
clc
adc CAddress
sta TempZero+4
lda #0
adc CAddress+2
sta TempZero+6
jmp Common_Reloc ;do common relocation logic
ENDP
TITLE ', RELOCATION.a - Do_INTERSEG'
*
****************************************************************
*
* Process INTERSEG record
*
* This is NOT a subroutine. It is entered with a JMP
* and exits to either: RELOC_LOOP, RELOC_ERROR or
* RELOC_RETURN which are in 'Do_Segment'.
*
* Inputs: CAddress - Segment Address
* Outputs: TempZero - Address to be patched
* TempZero+4 - Value of patch
*
****************************************************************
*
Do_INTERSEG PROC
with DirectPage, Globals
Bytes equ 0 ;# of bytes in patch
Shift equ 1 ;shift count
Offset equ 2 ;offset of patch in segment
FileNum equ 6 ;File Number
SegNum equ 8 ;Segment Number
SegOffset equ 10 ;Segment Offset
ldx #14
jsr Common_Pass1_Check
;
; do common INTERSEG logic
;
jsr Common_INTERSEG
;
; calculate address of patch = Load Address + Offset
;
lda CAddress
clc
adc |Record+Offset
sta TempZero
lda CAddress+2
adc |Record+Offset+2
sta TempZero+2
;
; calculate patch = Load Address of Segment + Segment Offset
;
lda TempZero+4
clc
adc |Record+SegOffset
sta TempZero+4
lda TempZero+6
adc |Record+SegOffset+2
sta TempZero+6
jmp Common_Reloc
ENDP
TITLE ', RELOCATION.a - Do_cINTERSEG'
*
****************************************************************
*
* Process compressed INTERSEG record
*
* This is NOT a subroutine. It is entered with a JMP
* and exits to either: RELOC_LOOP, RELOC_ERROR or
* RELOC_RETURN which are in 'Do_Segment'.
*
* Inputs: CAddress - Segment Address
* Outputs: TempZero - Address to be patched
* TempZero+4 - Value of patch
*
****************************************************************
*
Do_cINTERSEG PROC
with DirectPage, Globals
Bytes equ 0 ;# of bytes in patch
Shift equ 1 ;shift count
Offset equ 2 ;offset of patch in segment
SegNum equ 4 ;Segment Number
SegOffset equ 5 ;Segment Offset
ldx #7
jsr Common_Pass1_Check
;
; set Handle to handle of first Memory Segment Table entry for the
; current UserID
;
lda FirstMemSeg
sta Handle
lda FirstMemSeg+2
sta Handle+2
;
; find entry in Memory Segment Table corresponding to
; FileNum and SegNum in INTERSEG record
;
lda #0
pha ;output Handle
pha
lda |USERID ;current UserID
pha
pei CFileNum ;File Number
lda |Record+SegNum ;Segment Number
and #$FF
pha
jsr Next_MemSeg
pla
sta Handle ;output Handle
pla
sta Handle+2
lda #NoFind
bcc @1
jmp Reloc_Error
@1
;
; get handle of Memory Segment out of Memory Segment Table
; and get Load Address
;
lda |MS_Handle,x
ldy |MS_Handle+2,x
jsr DeRef ;deference handle
sta TempZero+4 ;save
sty TempZero+6
phk ;restore DBR
plb
;
; calculate address of patch = Load Address + Offset
;
lda |Record+Offset
clc
adc CAddress
sta TempZero
lda #0
adc CAddress+2
sta TempZero+2
;
; calculate patch = Load Address of Segment + Segment Offset
;
lda |Record+SegOffset
clc
adc TempZero+4
sta TempZero+4
bcc @2
inc TempZero+6
@2
jmp Common_Reloc
ENDP
TITLE ', RELOCATION.a - Do_SUPER'
*
****************************************************************
*
* Process super compressed records
*
* This is NOT a subroutine. It is entered with a JMP
* and exits to either: RELOC_LOOP, RELOC_ERROR or
* RELOC_RETURN which are in 'Do_Segment'.
*
* Inputs: CAddress - Segment Address
* Outputs: TempZero - Address to be patched
* TempZero+4 - Value of patch
*
****************************************************************
*
Do_SUPER PROC
with DirectPage, Globals
;
; offsets in Record (only the 1st 2 fields are actually read from file)
;
Length equ 0 ;length of SUPER record
Type equ 4 ;type of SUPER record
Byte equ 5 ;next byte in record
FileNum equ 6 ;file number of patch
SegNum equ 8 ;segment number of patch
Offset equ 10 ;segment offset of patch
PatchLoc equ 12 ;relative address to be patched
Bytes equ 14 ;number of bytes to patch
ldx #5
jsr Common_Pass1_Check
;
; set current patch page to 0
;
stz |Record+PatchLoc
;
; decrement record length (for Type)
;
jsr dec_rec_len
;
; get next byte in record
;
loop1 pea Record+Byte>>16
pea |Record+Byte
pea 0
pea 1
jsr Read_File
bcs to_reloc_error
;
; decrement record length
;
jsr dec_rec_len
;
; is byte a skip count or patch count ?
;
lda #0 ;clear high byte of accumulator
sep #$30
longa off
longi off
lda |Record+Byte
rep #$30
longa on
longi on
bpl cont1
;
; byte is skip count, set A to count
;
and #$FF7F
jmp eloop1
;
; byte is a patch count, set Counter to patch count
;
cont1 sta Counter
;
; read and process (patch count+1) bytes
;
loop2 pea Record+PatchLoc>>16
pea |Record+PatchLoc
pea 0
pea 1
jsr Read_File
bcc _1
to_reloc_error
jmp Reloc_Error
_1
;
; decrement record length
;
jsr dec_rec_len
;
; set TempZero to actual address to be patched = relative location +
; address of current segment
;
lda |Record+PatchLoc
clc
adc CAddress
sta TempZero
lda #0
adc CAddress+2
sta TempZero+2
;
; extract segment offset and segment number (even if not there) of patch
; from memory
;
lda [TempZero]
sta |Record+Offset
ldy #2
lda [TempZero],y
and #$FF
sta |Record+SegNum
;
; RELOC2 and RELOC3 records correspond to types 0 and 1
; INTERSEG1-36 records correspond to types 2-37
;
lda |Record+Type
and #$FF
;
; check for illegal SUPER record
;
cmp #38
bcc cont1aa
lda #Illegal
bra to_reloc_error
;
; is SUPER record is of type INTERSEGn ?
;
cont1aa ldx #3
cmp #2
bcc cont2
;
; SUPER record is of type INTERSEGn, check for different categories
;
cmp #26
bcc cont1a
;
; n is 25-36
; ----------
; Number of bytes in patch = 2
; File Number = 1
; Segment Number = n-24 (type-25)
; Shift Count = -16
;
sec
sbc #25
bra cont1b
cont1a cmp #14
bcc cont1c
;
; n is 13-24
; ----------
; Number of bytes in patch = 2
; File Number = 1
; Segment Number = n-12 (type-13)
; Shift Count = 0
;
sec
sbc #13
cont1b sta |Record+SegNum
lda #2
tax
sta |Record+Bytes
; fall through to decrement Acc to 1
;
; n is 1-12
; ----------
; Number of bytes in patch = 3
; File Number = n (type-1)
; Segment Number = in patch
; Shift Count = 0
;
cont1c dec a
cont1d sta |Record+FileNum
stx |Record+Bytes
;
; do common INTERSEG logic
;
jsr Common_INTERSEG
;
; get record type
;
lda |Record+Type
and #$FF
tax
;
; calculate patch = Segment Address + Segment Offset
;
lda |Record+Offset
clc
adc TempZero+4
sta TempZero+4
bcc cont3
inc TempZero+6
bra cont3
;
; SUPER record is a RELOC2 or RELOC3, set Bytes to 2 or 3
;
cont2 inc a
inc a
sta |Record+Bytes
;
; calculate patch = Load Segment Address + Segment Offset
;
lda |Record+Offset
clc
adc CAddress
sta TempZero+4
lda #0
adc CAddress+2
sta TempZero+6
;
; do actual patch - TempZero = Patch Location
; TempZero+4 = Patch
;
cont3 lda TempZero+4
;
; if INTERSEG25-36, use high word for Patch (equivalent to shifting
; the patch by -16)
;
cpx #26
bcc cont3a
lda TempZero+6
cont3a sta [TempZero]
lda |Record+Bytes
cmp #2
beq eloop2
sep #$30
longa off
longi off
lda TempZero+6
ldy #2
sta [TempZero],y
rep #$30
longa on
longi on
;
; finished single patch
;
eloop2 dec Counter
bmi cont4
jmp loop2
cont4 lda #1
;
; finished page, increment to next page (A=page increment)
;
eloop1 xba
clc
adc |Record+PatchLoc
sta |Record+PatchLoc
lda |Record+Length ;is record length=0?
ora |Record+Length+2
beq done ;yes, done
jmp loop1
done jmp Reloc_Loop
dec_rec_len
lda |Record+Length
bne @1
dec |Record+Length+2
@1
dec |Record+Length
rts
ENDP
TITLE ', RELOCATION.a - Common_Pass1_Check'
*
****************************************************************
*
* Common Pass1 check
*
* Inputs: X - # of bytes left in record
*
* Outputs: none
*
* Zero Page used: none
****************************************************************
*
Common_Pass1_Check PROC
with DirectPage, Globals
;
; if segment is an Initialization Segment, process even if Pass 1
;
lda Header.Kind
and #%11111
cmp #Init_Segment
bne cont1
lda Header.Org
sta CAddress ;reset load address
lda Header.Org+2
sta CAddress+2
bra cont2
;
; if pass 1, save Op Mark in Mark List and skip rest of Segment
;
cont1 lda Pass
bne cont2
jsr Save_Mark
lda #1
sta Pass2_Needed
pla ;remove return address
lda #0 ;signify no error
jmp Reloc_Return
;
; read rest of record
;
cont2 jsr Read_Record
bcs Common_Error
rts
entry Common_Error
Common_Error
plx ;remove return address
jmp Reloc_Error
ENDP
TITLE ', RELOCATION.a - Common_INTERSEG'
*
****************************************************************
*
* Common INTERSEG logic
*
* Inputs: CAddress - Segment Address
* Outputs: TempZero - Address to be patched
* TempZero+4 - Value of patch
*
****************************************************************
*
Common_INTERSEG PROC
with DirectPage, Globals
FileNum equ 6 ;File Number
SegNum equ 8 ;Segment Number
;
; set Handle to handle of first Memory Segment Table entry for the
; current UserID
;
lda FirstMemSeg
sta Handle
lda FirstMemSeg+2
sta Handle+2
;
; find entry in Memory Segment Table corresponding to
; FileNum and SegNum in Record
;
lda #0 ;output Handle
pha
pha
lda |USERID ;current UserID
pha
lda |Record+FileNum ;File Number
cmp #1 ;if = 1,
bne cont ; use current File Number instead
lda CFileNum
cont pha
lda |Record+SegNum ;Segment Number
pha
jsr Next_MemSeg
pla
sta Handle ;output Handle
pla
sta Handle+2
lda #NoFind
bcs Common_Error
;
; get handle of Memory Segment out of Memory Segment Table
; and get Load Address
;
lda |MS_Handle,x
ldy |MS_Handle+2,x
jsr DeRef ;deference handle
sta TempZero+4 ;save
sty TempZero+6
phk ;restore DBR
plb
rts
ENDP
TITLE ', RELOCATION.a - Common_Reloc'
*
****************************************************************
*
* Common relocation logic
*
* This is NOT a subroutine. It is entered with a JML
* and exits to RELOC_LOOP.
*
* Inputs: CAddress - Segment Address
* Outputs: TempZero - Address to be patched
* TempZero+4 - Value of patch
*
****************************************************************
*
Common_Reloc PROC
with DirectPage, Globals
Bytes equ 0 ;# of bytes in patch
Shift equ 1 ;shift count
;
; shift patch using Shift count
;
lda #0 ;make sure upper byte is 0
sep #$30 ;go into 8 bit mode so that negative flag
longa off
longi off
lda |Record+Shift ; is set on the lda
rep #$30
longa on
longi on
beq cont3 ;if zero skip shift logic
bmi cont1 ;if negative, do right shift
tax
lda TempZero+4 ;do logical left shift of 4 bytes
@loop
asl a
rol TempZero+6
dex
bne @loop
sta TempZero+4
bra cont3 ;done
cont1 cmp #$F0 ;check for special case of -16
bne cont2
lda TempZero+6 ;set low word to high word and zero high word
sta TempZero+4
stz TempZero+6
bra cont3
cont2 ora #$FF00 ;do arithmetic right shift of 4 bytes
tax ;X is two's complimented shift count here
lda TempZero+4
@loop
lsr TempZero+6
ror a
inx
bne @loop
sta TempZero+4
;
; store patch (Bytes only)
;
cont3 lda |Record+Bytes ;check for special case of 2 bytes
cmp #2
bne cont3a
lda TempZero+4 ;move word directly
sta [TempZero]
jmp Reloc_Loop
cont3a ldx #0 ;move 1 byte at a time
txy
sep #$30
longa off
longi off
loop lda TempZero+4,x
sta [TempZero],y
iny
inx
cpx |Record+Bytes
bne loop
cont4 rep #$30
longa on
longi on
jmp Reloc_Loop
ENDP