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

print off
blanks off
;-----------------------------------------------
;
; Imported addresses
;
;-----------------------------------------------
IMPORT GAdrL
IMPORT GDataReg
IMPORT GStatReg
IMPORT GptrInc
IMPORT SysVol
IMPORT compute_envelope
IMPORT cubbyhole
IMPORT doc_addr
IMPORT doc_ctrl
IMPORT doc_size
IMPORT gcb_ID
IMPORT gcb_doc
IMPORT gcb_env_cur
IMPORT gcb_env_inc
IMPORT gcb_env_lim
IMPORT gcb_pitchbend
IMPORT gcb_semitone
IMPORT gcb_vcb
IMPORT gcb_vib_cur
IMPORT gcb_vib_depth
IMPORT gcb_vib_inc
IMPORT gcb_volume
IMPORT inst_Awavecount
IMPORT inst_envelope
IMPORT inst_pb_range
IMPORT inst_release_seg
IMPORT inst_size
IMPORT inst_vib_depth
IMPORT inst_vib_inc
IMPORT long
IMPORT my_ID
IMPORT osc_table
IMPORT pitch_out
IMPORT short
IMPORT vcb_Apitch
IMPORT vcb_Bpitch
IMPORT vcb_current_seg
IMPORT vcb_ram
IMPORT wp_addr
IMPORT wp_pitch
print on, NoGen, NoHdr, NoMdir
****************************************************************
*
* NoteOn Tool Call
*
* Inputs: GenNum, Semitone, Volume, Instrument ptr
*
* Output: none
*
* This routine is reentrant: thou shalt not use scratch RAM
*
****************************************************************
EXPORT NoteOn
NoteOn PROC
longi on
longa on
print push
print off
INCLUDE 'gcb.aii'
INCLUDE 'Note.Macros'
INCLUDE 'ns.equ'
INCLUDE 'E16.NoteSyn'
INCLUDE 'E16.MIDI'
print pop
SGenNum equ 15 * stack frame at entry
Semitone equ 13
Svolume equ 11 * ten bytes of arg
Sinstrument equ 7
* RTL 1 4
* RTL 2 1
* alternate definition of GCB while in this setup phase:
* gcb_ID equ 0 ; same
* gcb_gennum equ 1 ; same
table_ptr equ 2 ; ptr to priority table (2, uses DB)
inst_ptr equ 4 ; ptr in instrument (4)
Awaveptr equ 8 ; ptr to wave structure (3)
Bwaveptr equ 11 ; ptr to wave structure (3)
* gcb_vcb equ 14 ; same
****************************************************************
* This routine uses the DP to point directly to the GCB it is using.
* That means direct addressing takes an extra cycle, but its worth it.
* Compute the gcb adress so that we have some workspace:
* sei ; no irq just yet!
tax ; set flags.
bne @1 ; if not equal we were started up.
ldx #nsNotInit ; if equal we weren't started, report err.
jmp exit ; exit and return error.
@1 pha ; save my DP a moment
lda SGenNum+2,s
and #$000F ; qualify the gennum a bit
tax
asl a
asl a ; mul by 16 to get gcb offset
asl a
asl a
adc 1,s ; add offset to my DP
ply ; and fix stack
phd ; now push OLD DP
tcd ; and install mine
phb ; push user data bank too!
* The stack is now 3 up from entry level; gennum is in x.
* To prevent clashes, we will raise the priority level of this gen to
* 255, where it can't be stolen by AllocGen.
lda >cubbyhole+2
* bne OKmem ; calling me without init? bad dog!
* ; do something here
OKmem pha ; high word of data area becomes bank
plb ; (push word, pull byte... stack = +4
lda >cubbyhole
sta table_ptr
mem_short
txy
lda (table_ptr),y ; save real priority and
sta 1,s ; (kind of a push...)
lda #255 ; install a super high one.
sta (table_ptr),y
* The stack is now 4 up from entry level. Memory is short. x has gen num.
lda #my_ID ; label the GCB as mine - no touchy
sta gcb_ID
lda >osc_table,x ; and get the oscillator number
sta gcb_doc
mem_long
* We're safe from AllocGen, so allow interrupts to happen. Memory is long.
* cli
* Now we need to get the vcb and copy the instrument parameters over to it.
txa
asl a ; vcb offset is
asl a ; (gennum * 32 )
asl a
asl a
asl a
* clc
adc #vcb_ram ; add offset to correct section.
clc
adc MyRam_ptr ; add the address.
sta gcb_vcb
lda Sinstrument+4,s
sta inst_ptr ; get all 4 bytes of instrument
lda Sinstrument+6,s
sta inst_ptr+2
* BLOCK MOVE the envelope data and release segment point and
* the proirity inc (26 bytes)
ldy #inst_envelope
copy lda [inst_ptr],y
sta (gcb_vcb),y
iny
iny
cpy #inst_release_seg+2
blt copy
* Now the wierd stuff: track down the right waveform for eachs
* of the oscillators, a and b. When found, we
* 1) put the wave data stuff into the doc
* 2) put the pitch data into the vcb
* and 3) keep the mode bytes around until the last minute.
* (both long)
* Start by making pointers to the wavelists in DP
lda inst_ptr * A wave is easy, its a fixed
clc
adc #inst_size * offset from the beginning.
sta Awaveptr
ldy #inst_Awavecount * B is harder:
lda [inst_ptr],y * compute byte length of Awaves
and #$00FF
asl a
pha
asl a
adc 1,s * len = count * 6
ply
adc Awaveptr
sta Bwaveptr * and B starts at the end of A.
mem_short * and then get bank
lda inst_ptr+2
sta Awaveptr+2
sta Bwaveptr+2
* Now search the wavelists for a topkey higher than our keynum.
* memory short
lda Semitone+4,s
and #$7f * better safe than sorry
ldy #0
loopA cmp [Awaveptr],y
blt gotA
iny
iny
iny
iny * an 'leay 6,y' would have
iny * done nicely here
iny
bra loopA
gotA mem_long
tya
clc
adc Awaveptr
sta Awaveptr
* Now do the same thing for the B oscillator
mem_short
lda Semitone+4,s
and #$7f * better safe than sorry
ldy #0
loopB cmp [Bwaveptr],y
blt gotB
iny
iny
iny
iny * an 'leay 6,y' would have
iny * done nicely here
iny
bra loopB
gotB mem_long
tya
clc
adc Bwaveptr
sta Bwaveptr
eject
****************************************************************
* Now we have to distribute the data about these waveforms
****************************************************************
; First poll midi for the sequencer
jsl MIDIInputPoll
* The pitch goes to the vcb
lda Semitone+4-1,s ; get semitone in high byte
and #$7f00 ; and add the relative pitch offset
tax
ldy #wp_pitch
adc [Awaveptr],y ; carry should be clear...
and #$7FFF ; wrap to a legal pitch
ldy #vcb_Apitch
sta (gcb_vcb),y
txa ; retrieve semitone
ldy #wp_pitch
adc [Bwaveptr],y
and #$7FFF ; wrap to a legal pitch
ldy #vcb_Bpitch
sta (gcb_vcb),y
* the wave address and size go to the doc
mem_short
lda gcb_doc
clc
adc #doc_addr
php
sei ;********************************
sta >GAdrL ; We're taking control of DOC
lda >SysVol ; NO IRQ PLEASE
ora #GptrInc
sta >GStatReg
ldy #wp_addr
lda [Awaveptr],y ; transfer both wave adresses
sta >GDataReg
lda [Bwaveptr],y
sta >GDataReg
lda gcb_doc
adc #doc_size
sta >GAdrL
iny ; now point to wp_size
lda [Awaveptr],y
sta >GDataReg
lda [Bwaveptr],y
sta >GDataReg
plp ;********** All Clear *****************
iny
lda [Awaveptr],y ; now get the mode bytes
pha
lda [Bwaveptr],y ; and save them on the stack
pha
***************************************************************
* The stack is now 6 up from entry level:
* old dp (2)
* old db
* old priority
* wave A mode
* wave B mode
* memory is still short
* the vcb has envelope and pitch, but missing a few things
* the gcb is now freed up, since we don't need the A and B ptrs.
****************************************************************
* So clean a few things up: copy from the instrument
ldy #inst_pb_range
lda [inst_ptr],y
asl a
asl a
asl a ; pack pitch bend range into
asl a ; high byte of ID
ora #My_ID
sta gcb_ID
ldy #inst_vib_inc
lda [inst_ptr],y ;copy vibrato speed
* Hereby killing the AWaveptr and BWaveptr!!!!!!
sta gcb_vib_inc
ldy #inst_vib_depth
lda [inst_ptr],y ; copy vibrato depth
* Hereby killing the inst_ptr!!!!!!
sta gcb_vib_depth
stz gcb_vib_cur ; zero phase of LFO
* Now were done with all those pointers, so we can fill in the rest:
lda Semitone+6,s
sta gcb_semitone
lda SVolume+6,s
sta gcb_volume
lda #$40
sta gcb_pitchbend
eject
****************************************************************
* And that's that. Now to start up the envelopes:
* memory is still short, and the stack is up by 6.
lda (gcb_vcb) ; get breakpoint, the first
sta gcb_env_lim+1 ; byte in the vcb
stz gcb_env_lim
mem_long
lda #3 ; set pointer to
ldy #vcb_current_seg ; start with segment one
sta (gcb_vcb),y
ldy #1
lda (gcb_vcb),y ; get increment
sta gcb_env_inc
stz gcb_env_cur
jsr compute_envelope ; call with both long
* Now the vibrato always starts at 0, and the pitchbend has just been
* reset, so all thats left is to compute the pitch !
jsr pitch_out ; returns with mem short
* arguments:
* dp must be pointing to the gcb
* the gcb must has osc# and the pointer to the vcb
* the vcb has two words, Apitch and Bpitch, which will be used.
****************************************************************
* By the time we get here, everything is ready to go.
* just start the oscillators and clean up.
* The two mode bytes are on the stack; A at 2 and B and 1.
mem_short
lda gcb_doc
clc
adc #doc_ctrl
php ;save callers IRQ preference
sei ;********************************
sta >GAdrL ; We're taking control of DOC: NO IRQ
lda >SysVol
ora #GptrInc
sta >GStatReg
lda 3,s ; do osc A first
sta >GDataReg
lda 2,s
sta >GDataReg ; then osc B
plp ; tidy up
both long ;********************************
pla ; take two ctrl bytes off stack
* the stack frame is back to +4 momentarily.
* now we are done munging with the hardware and the data structures.
* Restore the gen to its normal priority.
pei gcb_vcb ; were up 6 again, saving this pointer
lda >cubbyhole ; get the priority table back
sta gcb_vcb
lda Sgennum+6,s
tay
mem_short
lda 3,s ; get the old priority back
sta (gcb_vcb),y ; and stick it in the table
mem_long
pla
sta gcb_vcb
****************************************************************
* restore the registers, fix the stack, and get out!
plb ; get rid of priority (1)
plb ; get old data bank (1)
pld ; get old direct reg (2)
* move the bottom 6 bytes up by ten.
ldx #0
exit pla
sta 9,s
pla
sta 9,s
pla
sta 9,s ; five pla's adjust s
pla
pla
txa ; get the error code.
cmp #1 ; set the carry bit.
rtl ; return happy
ENDP
END