mirror of
https://github.com/marketideas/qasm.git
synced 2026-10-25 13:02:45 +00:00
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.
1 line
14 KiB
Plaintext
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 |