Files
erkyrath.infocom-zcode-terps/st/pumpsnd.old
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

316 lines
9.3 KiB
Plaintext

; This File: PUMPSND.S
; Author: Glyn H. Anderson; modified by Duncan Blanchard
; Created: 10-Nov-87 12:53
; Last Edit: 23-Nov-87 14:13; 23-Feb-88
; register conventions: in interrupt code, must preserve everything,
; elsewhere, preserve all except a0/d0
BIOS equ 1 ;BIOS trap number
GISelect equ $FFFF8800 ;GI sound chip register select
GIRead equ GISelect ;GI sound chip register read
GIWrite equ GISelect+2 ;GI sound chip register write
CLKFRQ equ 8000000 ;ST clock freq (8 MHz)
LOOPLEN equ 220 ;was 286, 214, 238-5
WASTELEN equ 10 ;length of waste loop
bss
*-----------------------
* interrupt globals
*-----------------------
i_samp ds.l 1 ;address of sound samples
i_reps ds.w 1 ;repeat count
i_p ds.l 1 ;pointer to next sample
i_n ds.w 1 ;number of samples remaining in buffer
i_waste ds.w 1 ;tens of cycles to waste
i_done ds.w 1 ;end-of-sound flag
oldSSP ds.l 1 ;saved supervisor stack pointer
oldSR ds.w 1 ;saved status register
text
xdef pump_sound
*-----------------------
* pump_sound
*-----------------------
pump_sound
move.l 4(a7),a0 ;get pointer to data buffer
move.w 8+2(a7),d0 ;get caller's repeat count
bsr ps_init
bsr ps_loop
bsr ps_cleanup
rts ;from pump_sound
*-----------------------
* ps_init
*-----------------------
; setup for sound; a0 -> buffer, d0.w = reps
ps_init
move.l a0,i_samp ;store
*** clr.w d0
*** move.b 2(a0),d0 ;get data's repeat count (byte)
move.w d0,i_reps ;store
move.l #CLKFRQ,d0 ;ST clock freq
divu 4(a0),d0 ;over sample freq -> ticks per sample
sub.w #LOOPLEN,d0 ;take out loop's length
bpl.s psix1 ;branch if we've got time to waste...
moveq #0,d0 ;else don't waste any
psix1 and.l #$0000FFFF,d0 ;clear upper bits
divu #WASTELEN,d0 ;length of waste loop
move.w d0,i_waste ;save waste count
; enter Super mode, disable interrupts
clr.l -(sp) ;arg is 0L
move.w #$20,-(sp) ;routine no. is $20
trap #BIOS ;call Super( 0L )
addq.l #6,sp ;fix stack
move.l d0,oldSSP ;save SSP
move sr,d0 ;get SR
move.w d0,oldSR ;save it
or.w #$0700,d0 ;disable interrupts
move d0,sr
; atomically adjust mixer control bits (don't disturb I/O control bits)
move.l #GISelect,a0
move.b #$07,(a0) ;request mixer controls
move.b (a0),d0 ;get controls
ori.b #$3F,d0 ;disable all noise and tones
move.b d0,2(a0) ;set controls
clr.w i_done ;reset flag, and fall thru ...
*-----------------------
* rep_init
*-----------------------
rep_init
move.l i_samp,a0
move.w 8(a0),d0
addq.w #1,d0
move.w d0,i_n ;setup length counter (+1)
adda.w #10,a0
move.l a0,i_p ;setup pointer to start of data
rts
*-----------------------
* ps_loop
*-----------------------
; interrupts come here.
; Each pass through the critical section uses 282 ticks, so an 18k sample
; rate (one every 434 ticks at 8 MHz) consumes 65 percent of total cpu time,
; plus interrupt overhead. Careful.
ps_loop
movem.l d0/a0-a1,-(sp) ;[38]
subq.w #1,i_n ;[16] [20?] ;reached end of cycle?
beq.s pslx3 ;[ 8] [10 tk] ;yes ;[[ 62]]
pslx1 move.l i_p,a0 ;[16] [?] ;pointer to next sample
move.b (a0)+,d0 ; [8] ;get it
ext.w d0 ; [4] ;signed byte
move.l a0,i_p ;[16] [?] ;update pointer
lea volmap(pc),a1 ; [8] ;address of conversion table
adda.w d0,a1 ; [8]
add.w d0,d0 ; [4]
adda.w d0,a1 ; [8] ;offset x3 ;[[ 72]]
; update volume on each channel (as simultaneously as possible)
move.l #GISelect,a0 ;[12]
move.b #8,(a0) ;[12]
move.b (a1)+,2(a0) ;[16] ;write A vol
move.b #9,(a0) ;[12]
move.b (a1)+,2(a0) ;[16] ;write B vol
move.b #10,(a0) ;[12]
move.b (a1)+,2(a0) ;[16] ;write C vol ;[[ 96]]
pslx2 movem.l (sp)+,d0/a0-a1 ;[36] ;exit
rts ;[16] ;total 282 ;[[ 52]]
; handle end of cycle. This code runs in parallel with the above, and so
; consumes no more interrupt cycles than usual.
pslx3 tst.w i_done ;been here before?
bne.s pslx2 ;just waiting until ints disabled
subq.w #1,i_reps ;any more reps?
beq.s pslx4 ;no
bsr rep_init ;yes, set up next cycle
bra.s pslx2
pslx4 move.w #1,i_done ;done, raise flag
bra.s pslx2
*-----------------------
* ps_cleanup
*-----------------------
ps_cleanup
move oldSR,sr ;restore interrupt level
move.l oldSSP,-(sp) ;push old SSP
move.w #$20,-(sp) ;function #$20
trap #BIOS ;call Super( SSP )
addq.l #6,sp ;fix stack
rts
text
; keep read-only data in code seg for quick access
; This table maps signed bytes (-128..127) into amplitude inputs for the
; sound chip. Each digit is the 4-bit amplitude for one channel.
; In the Atari ST the three channels are not weighted equally; the values
; in the table were determined empirically.
; the table's entry point is in the middle, corresponding to signed '0'
dc.b $01,$1,$1,$01,$1,$2,$01,$1,$3,$00,$3,$3 ;4 groups per line
dc.b $01,$1,$4,$01,$2,$4,$01,$4,$2,$01,$4,$3
dc.b $01,$5,$2,$03,$3,$4,$04,$3,$3,$05,$3,$2
dc.b $05,$3,$3,$05,$4,$2,$05,$3,$4,$03,$6,$2
dc.b $03,$6,$3,$03,$4,$6,$03,$6,$4,$03,$5,$6
dc.b $04,$6,$4,$05,$6,$3,$04,$6,$5,$04,$7,$3
dc.b $05,$7,$2,$05,$7,$3,$04,$7,$5,$05,$7,$4
dc.b $05,$6,$6,$05,$7,$5,$04,$7,$6,$03,$7,$7
dc.b $05,$7,$6,$05,$8,$3,$04,$8,$5,$03,$8,$6
dc.b $07,$6,$6,$07,$7,$5,$07,$8,$0,$05,$9,$0
dc.b $05,$9,$1,$05,$9,$2,$05,$9,$3,$04,$9,$5
dc.b $06,$9,$1,$06,$9,$2,$06,$9,$3,$07,$9,$0
dc.b $08,$8,$2,$08,$8,$3,$09,$6,$5,$09,$0,$8
dc.b $09,$7,$4,$09,$6,$6,$09,$7,$5,$09,$8,$0
dc.b $08,$9,$1,$08,$9,$2,$08,$9,$3,$08,$8,$7
dc.b $07,$9,$7,$08,$9,$5,$06,$A,$3,$09,$6,$8
dc.b $09,$4,$9,$08,$7,$9,$09,$5,$9,$09,$9,$3
dc.b $09,$9,$4,$0A,$6,$6,$0A,$7,$5,$0A,$3,$8
dc.b $08,$A,$1,$08,$A,$2,$04,$B,$2,$04,$B,$3
dc.b $03,$B,$5,$03,$A,$9,$02,$B,$6,$03,$B,$6
dc.b $06,$B,$2,$06,$B,$3,$06,$B,$4,$07,$B,$1
dc.b $07,$B,$2,$07,$B,$3,$07,$B,$4,$07,$B,$5
dc.b $07,$A,$9,$02,$A,$A,$03,$A,$A,$09,$2,$B
dc.b $09,$3,$B,$08,$9,$A,$08,$7,$B,$05,$9,$B
dc.b $03,$3,$C,$03,$4,$C,$05,$2,$C,$05,$3,$C
dc.b $06,$1,$C,$07,$9,$B,$06,$3,$C,$04,$6,$C
dc.b $06,$4,$C,$07,$2,$C,$07,$3,$C,$07,$4,$C
dc.b $07,$5,$C,$05,$B,$A,$08,$B,$9,$0A,$6,$B
dc.b $09,$B,$8,$09,$A,$A,$09,$9,$B,$08,$5,$C
dc.b $06,$C,$5,$07,$C,$3,$05,$C,$7,$03,$C,$8
dc.b $03,$B,$B,$08,$7,$C,$04,$B,$B,$05,$C,$8
dc.b $05,$B,$B,$06,$9,$C,$06,$C,$8,$06,$B,$B
volmap
dc.b $0A,$9,$B,$09,$B,$A,$0B,$9,$A,$0B,$B,$2
dc.b $0B,$A,$9,$09,$C,$4,$09,$C,$5,$0A,$4,$C
dc.b $0A,$5,$C,$0B,$8,$B,$0C,$1,$A,$0C,$2,$A
dc.b $0C,$3,$A,$0C,$4,$A,$0C,$5,$A,$0C,$8,$9
dc.b $0C,$9,$8,$0C,$6,$A,$0C,$A,$1,$0C,$A,$3
dc.b $0C,$A,$5,$0C,$9,$9,$0C,$A,$6,$0C,$1,$B
dc.b $0C,$A,$7,$0D,$2,$5,$0D,$3,$5,$0D,$5,$3
dc.b $0D,$5,$4,$0D,$5,$5,$0D,$6,$3,$0D,$6,$4
dc.b $0D,$6,$5,$0D,$7,$2,$0D,$6,$6,$0D,$7,$4
dc.b $0D,$7,$5,$0D,$7,$6,$0D,$8,$0,$0D,$7,$7
dc.b $0D,$6,$8,$0D,$8,$5,$0D,$8,$6,$0D,$8,$7
dc.b $0D,$9,$0,$0D,$9,$2,$0D,$9,$4,$0D,$9,$5
dc.b $0D,$9,$6,$0D,$3,$A,$0D,$4,$A,$0D,$5,$A
dc.b $0D,$6,$A,$0B,$3,$D,$0B,$4,$D,$0B,$5,$D
dc.b $0D,$A,$1,$0D,$A,$3,$0D,$A,$5,$0D,$A,$6
dc.b $0D,$A,$7,$0D,$4,$B,$0D,$5,$B,$0D,$A,$8
dc.b $0D,$6,$B,$0D,$7,$B,$0D,$A,$9,$0D,$8,$B
dc.b $0D,$B,$3,$0D,$B,$5,$0D,$B,$6,$0D,$B,$7
dc.b $0D,$9,$B,$0D,$B,$8,$0B,$A,$D,$0C,$0,$D
dc.b $0C,$2,$D,$0C,$4,$D,$0C,$5,$D,$0D,$0,$C
dc.b $0D,$2,$C,$0D,$3,$C,$0D,$4,$C,$0D,$5,$C
dc.b $0D,$6,$C,$0D,$B,$A,$0D,$7,$C,$0D,$8,$C
dc.b $0C,$9,$D,$0D,$9,$C,$0D,$B,$B,$0C,$D,$3
dc.b $0C,$D,$6,$0C,$D,$7,$0D,$C,$7,$0C,$D,$8
dc.b $0D,$C,$8,$0A,$D,$C,$0A,$1,$E,$0A,$3,$E
dc.b $0A,$5,$E,$0A,$6,$E,$0A,$7,$E,$0C,$D,$A
dc.b $06,$D,$D,$07,$D,$D,$08,$E,$6,$0A,$9,$E
dc.b $08,$D,$D,$0C,$D,$B,$0E,$7,$8,$09,$D,$D
dc.b $0A,$7,$E,$0C,$D,$A,$0D,$C,$A,$0B,$C,$D
dc.b $0C,$B,$D,$05,$D,$D,$07,$E,$8,$0B,$D,$C
dc.b $0D,$5,$D,$0E,$4,$8,$0D,$6,$D,$0E,$7,$6
dc.b $0D,$7,$D,$0D,$C,$B,$0D,$8,$D,$09,$D,$D
end ;of assembly
text
*-----------------------
* DEAD CODE
*-----------------------
LLEN2 equ 106
SYNCCNT equ 100 ;resync every n samples
; from setup ...
sub.w #LLEN2/10,d0 ;reduced waste after sync section
bpl.s psx2
moveq #0,d0
psx2 move.w d0,w2
clr.w sync ;resync first time thru
; synchronize with beginning of a new square wave
; For smoother sq wave (and reduced cpu load), do this only every nth pass
subq.w #1,sync ;[16] ;time to resync?
bgt.s plx2 ;[10] ;no [8 if not taken] ;[[ 26]]
move.w #SYNCCNT,sync ;[16]
move.w w2,w_use ;[20] ;adjust waste val
; move.b #0,(a2) ;chan A period = longest poss
; move.b #$FF,(a3) ;(ignore 8 ls period bits)
move.b #1,(a2) ;[12]
move.b #$0F,(a3) ;[12]
; move.b #2,(a2) ;chan B period = longest poss
; move.b #$FF,(a3)
move.b #3,(a2) ;[12]
move.b #$0F,(a3) ;[12]
; move.b #4,(a2) ;chan C period = longest poss
; move.b #$FF,(a3)
move.b #5,(a2) ;[12]
move.b #$0F,(a3) ;[12] ;72+36-2 ;[[106]]
; fetch and unpack 3 amplitude values
clr.w d0
move.b (a0)+,d0 ; [8] ;get sample
eor.b #$80,d0 ; [8] ;offset the sample
lsl.w #1,d0 ; [8] ;index into WORDs
move.w 0(a1,d0.w),d0 ;[14] ;get 12-bit version
move.w d0,d1 ; [4] ;copy it
move.w d0,d2 ; [4] ;twice
lsr.w #8,d0 ;[22] ;get A
lsr.b #4,d1 ;[14] ;get B
and.b #$0F,d2 ; [8] ;get C [66]
;; move.w 0(a1,d0.w),d2 ;[14] ;get 12-bit version
;; move.w d2,d1 ; [4]
;; and.b #$0F,d2 ; [8] ;extract C
;; lsr.b #4,d1 ;[14] ;shift B into position
;; move.w d1,d0 ; [4]
;; and.b #$0F,d1 ; [8] ;extract B
;; lsr.b #4,d0 ;[14] ;shift A into position [66]
; (after pump_next)
move.b #$07,GISelect ;done -- disable all tone and noise [dbb]
move.b GIRead,d0
or.b #$3F,d0
move.b d0,GIWrite
end