; AY+ DMA Player ; OffseT/Futurs' pour Iron ; Mai 2007 - Octobre 2007 ; -> Version initiale ; Mai 2009 ; -> Ajout d'une bufferisation dynamique ; -> Maitrise du temps CPU max du stream Org &9000 Nolist Let entry=$ jp start read"cave.cfg" ; Nom de la musique Bank Equ &c4 ; Bank de la musique StreamsStart Equ &4000 ; Adresse de la musique Buffers Equ &d000 ; Adresse des n buffers de &100 octets ; n d{pend de la musique, voir le fichier .cfg ; min=13 et max=17 (19 en th{orie maix bon...) BreakLine Equ 80 ; Num{ro de ligne limite pour le player ; ################################################################### ; Ici commencent les inits du programme principal ; ################################################################### Start ld a,tableint/256 ld i,a ld a,tableint mod 256 or 1 ld hl,&6805 ld bc,&7fb8 ld ix,&6c02 ld e,&a0 di im 2 out (c),c ld (hl),a ld (ix+0),0 ld (ix+4),0 ld (ix+8),0 out (c),e ei exx ex af,af' push af push bc push de push hl ld bc,&7f00+bank out (c),c ld c,&8e out (c),c call initplayer ; ################################################################### ; Ici commence le programme principal ; ################################################################### ; Boucle principale Loop ld bc,&f500 Synch in a,(c) rra jp nc,synch ld a,(alertbuffer) ; R{cup{ration du flag d'erreur buffer ld (&c000),a ld a,(prebufferingcount+1) ; Colorisation en fonction du buffer ld c,a ld a,prebuffers sub c ld bc,&7fb8 out (c),c sla a:sla a:sla a:sla a ld (&6400),a xor a ld (&6401),a ld bc,&7fa0 out (c),c ld bc,&7f10 out (c),c ld bc,&7fb8 ; On place une synchro pour appeler "runplayer" out (c),c ld a,1 ld (&6800),a ld bc,&7fa0 out (c),c halt ld bc,&7f00+74 out (c),c call runplayer ; Doit etre stable sur la frame ! ld bc,&7f00+76 out (c),c call getframeplayer ld bc,&7f00+79 out (c),c ld a,breakline ; Num{ro de ligne @ ne pas d{passer call getbuffersplayer ld bc,&7f00+84 out (c),c ; Test clavier ld bc,&f40e out (c),c ld bc,&f6c0 out (c),c xor a out (c),a ld bc,&f792 out (c),c ld bc,&f648 out (c),c ld b,&f4 in a,(c) ld bc,&f782 out (c),c ld bc,&f600 out (c),c rra rra rra jr nc,broken EndLoop jp loop ; ################################################################### ; Ici commence la fin du programme principal ; ################################################################### Broken di ld bc,&7fb8 out (c),c ld a,&f0 ld (&6c0f),a xor a ld (&6800),a ld bc,&7fa0 out (c),c ei ld bc,&7fc0 out (c),c pop hl pop de pop bc pop af exx ex af,af' call &bca7 im 1 ret ; ################################################################### ; A partir d'ici, on ne touche plus @ rien c'est le player ; ################################################################### ; ; Configuration du player ; let AutoSIDA=0 ; Calcul SID automatique (ne pas utiliser le timer ST) let AutoSIDB=0 let AutoSIDC=0 let SyncSID=0 ; Synchroniser l'attaque du SID avec le AY (exp{rimental) ; ; Flag d'alerte, doit toujours valoir z{ro ; AlertBuffer db 0 ; ; Initialisations globales ; StreamsCount Equ 11+hardenv+hardenv+sidona+sidona+sidonb+sidonb+sidonc+sidonc PreBuffers Equ 256/streamscount-1 ; ; Initialisation et pr{bufferisation des streams ; InitPlayer ld a,prebuffers ld (prebufferingcount+1),a xor a ld (alertbuffer),a ld (currentstreamcount+1),a ld (framebufferpointer+1),a ld hl,streamscontextadr ld (currentstreamcontextadr+2),hl ld hl,goprebuffering ld (pcstack),hl ld hl,regstack ld (workstack+1),hl ld hl,regsoldvalues ld de,regsoldvalues+1 ld (hl),&ff ld bc,31 ldir IF sidona xor a ld (whichdmalista+1),a ld hl,primarysidlistapredelay ld (dmalista+1),hl ld hl,primarysidlista ld de,primarysidlista+4 ld bc,312-4 ldir ld hl,secondarysidlista ld de,secondarysidlista+4 ld bc,312-4 ldir ENDIF IF sidonb xor a ld (whichdmalistb+1),a ld hl,primarysidlistbpredelay ld (dmalistb+1),hl ld hl,primarysidlistb ld de,primarysidlistb+4 ld bc,312-4 ldir ld hl,secondarysidlistb ld de,secondarysidlistb+4 ld bc,312-4 ldir ENDIF if sidonc xor a ld (whichdmalistc+1),a ld hl,primarysidlistcpredelay ld (dmalistc+1),hl ld hl,primarysidlistc ld de,primarysidlistc+4 ld bc,312-4 ldir ld hl,secondarysidlistc ld de,secondarysidlistc+4 ld bc,312-4 ldir ENDIF ld de,buffers ld hl,streamsstart ld ix,streamscontextadr ld iy,streamssize ld b,streamscount LoopInitStreams push bc push hl push de call initstream pop hl ld bc,bufferssize add hl,bc ex de,hl pop hl ld b,(iy+1) ld c,(iy+0) add hl,bc inc iy inc iy ld bc,streamscontextsize add ix,bc pop bc djnz loopinitstreams call getframeplayer ret ; ; Mise @ jour des buffers ; ds 8 RegStack dw 0,0,0,0,0,0 PCStack dw goprebuffering ; A = ligne max jusqu'@ laquelle travailler GetBuffersPlayer di ld bc,&7fb8 out (c),c ld (&6800),a ld bc,&7fa0 out (c),c ld hl,stopbufferinginterrupt ld (intdma0),hl ld (intrast),hl ld a,(prebufferingcount+1) dec a ; Soucis si a {tait @ z{ro ! (buffer vide) cp &ff jr nz,goonbuffersok ld (alertbuffer),a GoOnBuffersOK ld (prebufferingcount+1),a ld (restoresp+1),sp WorkStack ld sp,regstack pop af pop bc pop de pop hl pop ix pop iy ei ret StopBufferingInterrupt push iy push ix push hl push de push bc push af ld hl,rasterinterrupt ld (intdma0),hl ld (intrast),hl ld (workstack+1),sp RestoreSP ld sp,0 ei ret GoPreBuffering ei nop di PreBufferingCount ld a,prebuffers cp prebuffers jr z,goprebuffering ei ld a,(prebufferingcount+1) inc a ld (prebufferingcount+1),a CurrentStreamContextAdr ld ix,streamscontextadr call getnextbytes CurrentStreamCount ld a,0 inc a cp streamscount jr nz,updatetonextstream ResetToFirstStream xor a ld ix,streamscontextadr-streamscontextsize UpdateToNextStream ld (currentstreamcount+1),a ld bc,streamscontextsize add ix,bc ld (currentstreamcontextadr+2),ix jr goprebuffering ; ; R{cup{ration des donn{es du framedata courant dans les buffers ; GetFramePlayer ld hl,framedata ld d,buffers/256 FrameBufferPointer ld e,0 ld b,streamscount LoopGetFrameData ld a,(de) ld (hl),a inc hl inc d djnz loopgetframedata ; Mise @ jour du pointeur de buffer ld a,(framebufferpointer+1) inc a ld (framebufferpointer+1),a ; Construction de la table des regsvalues @ partir du framebuffer ld ix,framedata ld de,regsvalues ld bc,&8007 ld a,(ix+f_R0): ld (de),a:inc e ; R0 ld a,(ix+f_R1):and c: ld (de),a:inc e ; R1 ld a,(ix+f_R2): ld (de),a:inc e ; R2 ld a,(ix+f_R3):and c: ld (de),a:inc e ; R3 ld a,(ix+f_R4): ld (de),a:inc e ; R4 ld a,(ix+f_R5):and c: ld (de),a:inc e ; R5 ld a,(ix+f_R6): ld (de),a:inc e ; R6 ld a,(ix+f_R7): ld (de),a:inc e ; R7 ld a,(ix+f_R1):and b srl a:srl a:srl a:ld h,a ld a,(ix+f_R8):or h: ld (de),a:inc e ; R8 ld a,(ix+f_R3):and b srl a:srl a:srl a:ld h,a ld a,(ix+f_R9):or h: ld (de),a:inc e ; R9 ld a,(ix+f_R5):and b srl a:srl a:srl a:ld h,a ld a,(ix+f_R10):or h: ld (de),a:inc e ; R10 IF hardenv ld a,(ix+f_R11): ld (de),a:inc e ; R11 ld a,(ix+f_R12) ld h,a:and c: ld (de),a:inc e ; R12 ld a,h:and &f8 srl a:srl a:srl a:srl a:srl a ld c,a:ld b,0 ld hl,tablereg13:add hl,bc ld a,(hl): ld (de),a:inc e ; R13 ld c,&7 ENDIF ld a,(ix+f_R1):and &70: ld (de),a:inc e ; FXA IF sidona ld hl,putfxa_vol ; D{sactive volume A si SID A bit 6,a jr nz,skipr8 ld hl,putpsg2 SkipR8 ld (poker8+1),hl IF autosida ld a,(ix+f_R1):and c:ld h,a:ld l,(ix+f_R0) ld a,7:and l:ld b,a srl h:rr l:srl h:rr l:srl h:rr l ld a,l: ld (de),a:inc e ; FreqFXA High ld a,b sla a:sla a:sla a: ld (de),a:inc e ; FreqFXA Low ELSE ld a,(ix+f_FXA_H) ld (de),a:inc e ; FreqFXA High ld a,(ix+f_FXA_L) ld (de),a:inc e ; FreqFXA Low ENDIF ENDIF ld a,(ix+f_R3):and &70: ld (de),a:inc e ; FXB IF sidonb ld hl,putfxb_vol ; d{sactive volume B si SID B bit 6,a jr nz,skipr9 ld hl,putpsg2 SkipR9 ld (poker9+1),hl IF autosidb ld a,(ix+f_R3):and c:ld h,a:ld l,(ix+f_R2) ld a,7:and l:ld b,a srl h:rr l:srl h:rr l:srl h:rr l ld a,l: ld (de),a:inc e ; FreqFXB High ld a,b sla a:sla a:sla a: ld (de),a:inc e ; FreqFXB Low ELSE ld a,(ix+f_FXB_H) ld (de),a:inc e ; FreqFXB High ld a,(ix+f_FXB_L) ld (de),a:inc e ; FreqFXB Low ENDIF ENDIF ld a,(ix+f_R5):and &70: ld (de),a:inc e ; FXC IF sidonc ld hl,putfxc_vol ; d{sactive volume C si SID C bit 6,a jr nz,skipr10 ld hl,putpsg2 SkipR10 ld (poker10+1),hl IF autosidc ld a,(ix+f_R5):and c:ld h,a:ld l,(ix+f_R4) ld a,7:and l:ld b,a srl h:rr l:srl h:rr l:srl h:rr l ld a,l: ld (de),a:inc e ; FreqFXC High ld a,b sla a:sla a:sla a: ld (de),a:inc e ; FreqFXC Low ELSE ld a,(ix+f_FXC_H) ld (de),a:inc e ; FreqFXC High ld a,(ix+f_FXC_L) ld (de),a:inc e ; FrefFXC Low ENDIF ENDIF IF sidona ; appel de la routine de pr{paration de l'ay list sid A ld a,(regsvalues+FXA) bit 6,a ; Check SID call nz,createdmalista ENDIF IF sidonb ; appel de la routine de pr{paration de l'ay list sid B ld a,(regsvalues+FXB) bit 6,a ; Check SID call nz,createdmalistb ENDIF IF sidonc ; appel de la routine de pr{paration de l'ay list sid C ld a,(regsvalues+FXC) bit 6,a ; Check SID call nz,createdmalistc ENDIF ret ; ; Programmation du PSG et DMA @ partir des regsvalues ; RunPlayer ; appel de la routine de lancement de l'ay list sid di IF sidona ld a,(regsvalues+FXA) call putfxa ENDIF IF sidonb ld a,(regsvalues+FXB) call putfxb ENDIF IF sidonc ld a,(regsvalues+FXC) call putfxc ENDIF ei ld de,regsvalues ; DE=regvalues ld h,d ld l,regsoldvalues MOD 256 ; HL=oldregvalues ld a,(de):cp (hl):call nz,putpsg2 ; R0 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R1 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R2 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R3 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R4 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R5 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R6 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R7 inc e:inc l ld a,(de):cp (hl) ; R8 PokeR8 call nz,putpsg2:inc e:inc l ld a,(de):cp (hl) ; R9 PokeR9 call nz,putpsg2:inc e:inc l ld a,(de):cp (hl) ; R10 PokeR10 call nz,putpsg2:inc e:inc l IF hardenv ld a,(de):cp (hl):call nz,putpsg2 ; R11 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R12 inc e:inc l ld a,(de):cp (hl):call nz,putpsg2 ; R13 ENDIF ret ; E=Reg ; A=Val ; Sauve A dans (HL) PutPSG2 ld (hl),a ld b,&f4 di out (c),e ld bc,&f6c0 out (c),c ld c,0 out (c),c ld b,&f4 out (c),a ld a,&80 ld b,&f6 out (c),a out (c),c ei ret IF sidona PutFXA_Vol ld (hl),a ret ; E=FXA ; A=Val PutFXA bit 6,a ; Check SID, check reg7 ? jp nz,startdmalista StopFXA ld bc,&7fb8 IF sidonb+sidonc ; On compense en temps constant ds 25 ; uniquement si d'autres DMA viennent ENDIF ; apr}s out (c),c ld a,(&6c0f) ; Stop DMA0 and &fe ld (&6c0f),a ld c,&a0 out (c),c IF sidonb+sidonc ds 22 ENDIF ret ENDIF IF sidonb PutFXB_Vol ld (hl),a ret ; E=FXB ; A=Val PutFXB bit 6,a ; Check SID, check reg7 ? jp nz,startdmalistb StopFXB ld bc,&7fb8 IF sidonc ; On compense en temps constant ds 25 ; uniquement si d'autres DMA ENDIF ; viennent apr}s out (c),c ld a,(&6c0f) ; Stop DMA1 and &fd ld (&6c0f),a ld c,&a0 out (c),c IF sidonc ds 22 ENDIF ret ENDIF IF sidonc PutFXC_Vol ld (hl),a ret ; E=FXC ; A=Val PutFXC bit 6,a ; Check SID, check reg7 ? jp nz,startdmalistc StopFXC ld bc,&7fb8 ; Pas de compensation en temps constant comme pour out (c),c ; A et B car aucun autre DMA ne viendra apr}s ld a,(&6c0f) ; Stop DMA2 and &fb ld (&6c0f),a ld c,&a0 out (c),c ret ENDIF IF sidona ; Routines de creation des l'AYList ; A = volume SID ; DE = frequence SID CreateDMAListA ld a,(regsvalues+FXA_H) ld d,a ; D=nbre ligne periode sid IF syncsid ld a,(regsoldvalues+FXA_H) cp d jr z,nonewfxa_h ld a,d ld (regsoldvalues+FXA_H),a xor a ld (runtimeoffseta+1),a NoNewFXA_H ENDIF ld a,(regsvalues+FXA_L) ld e,a ; E=retenue en nops IF syncsid ld a,(regsoldvalues+FXA_L) cp e jr z,nonewfxa_l ld a,e ld (regsoldvalues+FXA_L),a xor a ld (runtimeoffseta+1),a NoNewFXA_L ENDIF ld a,(regsvalues+R8) ; On recupere le volume courant et ld (pokeswitchvolumea+1),a ; on le met en switch dans la dma loop ld b,a ; B=volume du canal DMAListA ld hl,primarysidlistapredelay ; AYList a utiliser PreDelayA ld a,255 ; On recupere le nombre de lignes qui restaient ld (hl),a ; a attendre de la frame precedente et on le inc hl ; poke dans la phase d'init de l'AYList inc hl inc a ex af,af' SIDVolumeA ; On recupere l'etat du volume SID et ld a,15 ; le poke dans la phase d'init de l'AYList ld (hl),a inc hl inc hl or a ; si le volume courant du canal a change depuis jr z,nonewvola ; la frame precedente on le RAZ ld a,b NoNewVolA ex af,af' ; A'=volume SID courant ; ; On cr{e l'AYList ; ; IN ; A'=volume SID courant ; ; A=nombre de lignes deja traitee en init ; ; D,E=periode SID en base 64 ; ; (pokeswichvolume+1)=volume canal courant ; ; (dmacarry+1)=retenue periode SID en cours ; OUT ; A=nombre de lignes SID debordant de la frame ; ; A'=volume SID courant MakeDMAListA exx ld h,0 ; HL'=compteur de ligne ld l,a ld b,h ; B'=0 (constante) ld e,56 ; E'=312 modulo 256 (constante) LoopDMA_A exx ld b,d ; B=nombre de lignes a attendre RunTimeOffsetA ld a,0 ; A=retenue du calcul precedent PokeA_1 add a,e ld c,a ; C=retenue globale and &3f ld (runtimeoffseta+1),a ; Est-ce qu'on a plus d'une cp c ; ligne de retenue ? jr z,nodmaoverflowa DMAOverflowA inc b NoDMAOverflowA ; a une ligne moins a attendre ld a,b dec b ld (hl),b ; Pokage de l'unite de pause inc hl ;ld (hl),&10 inc hl ex af,af' PokeSwitchVolumeA ; Calcul du volume SID courant xor 15 ld (hl),a ; Pokage du volume SID ex af,af' inc hl ;ld (hl),8 inc hl exx ld c,a ; Test de fin de frame add hl,bc bit 0,h jr z,loopdma_a ld a,l sub a,e jr c,loopdma_a exx ;ld (hl),&20 ;inc hl ;ld (hl),&40 dec a ; Correction du nombre de lignes ; en overflow (255=pas d'overflow) ld (predelaya+1),a ; On recupere le nombre de ligne qui debordent de ; la frame pour les mettre au debut de la suivante ex af,af' ; On recupere le volume SID courant pour ld (sidvolumea+1),a ; reprendre au bon etat a la frame suivante ret ; ; Routines de lancement des AYLists A ; StartDMAListA ld e,2 ld bc,4 ld hl,(dmalista+1) ; On ne lance l'AYList du debut ld a,(hl) ; que si on avait une pre-attente cp 255 ; sinon si on n'avait pas de pre-attente jr z,startwithnopredelaya ; alors on saute toute la phase d'init ; or a ; sinon si on avait juste une ligne de ; jr nz,startwithpredelaya ; pre-attente on saute uniquement ld c,e ; l'instruction de pause StartWithNoPredelayA add hl,bc StartWithPredelayA ; Ici HL=adresse AYList a lancer ld bc,&7fb8 out (c),c ld (&6c00),hl ; adr DMA0 ld a,(&6c0f) or 1 ld (&6c0f),a ; run DMA0 ld c,&a0 out (c),c ld hl,primarysidlistapredelay ; On switch les AYLists de travail ld de,secondarysidlistapredelay WhichDMAListA ld a,0 xor 1 ld (whichdmalista+1),a jp z,startwithprimarya StartWithSecondary ld (dmalista+1),de ret StartWithPrimaryA nop ld (dmalista+1),hl ret ENDIF IF sidonb ; Routines de creation des AYLists B ; A = volume SID ; DE = frequence SID CreateDMAListB ld a,(regsvalues+FXB_H) ld d,a ; D=nbre ligne periode sid IF syncsid ld a,(regsoldvalues+FXB_H) cp d jr z,nonewfxb_h ld a,d ld (regsoldvalues+FXB_H),a xor a ld (runtimeoffsetb+1),a NoNewFXB_H ENDIF ld a,(regsvalues+FXB_L) ld e,a ; E=retenue en nops IF syncsid ld a,(regsoldvalues+FXB_L) cp e jr z,nonewfxb_l ld a,e ld (regsoldvalues+FXB_L),a xor a ld (runtimeoffsetb+1),a NoNewFXB_L ENDIF ld a,(regsvalues+R9) ; On recupere le volume courant et ld (pokeswitchvolumeb+1),a ; on le met en switch dans la dma loop ld b,a ; B=volume du canal DMAListB ld hl,primarysidlistbpredelay ; AYList a utiliser PreDelayB ld a,255 ; On recupere le nombre de lignes qui restaient ld (hl),a ; a attendre de la frame precedente et on le inc hl ; poke dans la phase d'init de l'AYList inc hl inc a ex af,af' SIDVolumeB ; On recupere l'etat du volume SID et ld a,15 ; le poke dans la phase d'init de l'AYList ld (hl),a inc hl inc hl or a ; si le volume courant du canal a change depuis jr z,nonewvolb ; la frame precedente on le RAZ ld a,b NoNewVolB ex af,af' ; A'=volume SID courant ; ; On cr{e l'AYList B ; ; IN ; A'=volume SID courant ; ; A=nombre de lignes deja traitee en init ; ; D,E=periode SID en base 64 ; ; (pokeswichvolume+1)=volume canal courant ; ; (runtimeoffsetb+1)=retenue periode SID en cours ; OUT ; A=nombre de lignes SID debordant de la frame ; ; A'=volume SID courant MakeDMAListB exx ld h,0 ; HL'=compteur de ligne ld l,a ld b,h ; B'=0 (constante) ld e,56 ; E'=312 modulo 256 (constante) LoopDMA_B exx ld b,d ; B=nombre de lignes a attendre RunTimeOffsetB ld a,0 ; A=retenue du calcul precedent PokeB_1 add a,e ld c,a ; C=retenue globale and &3f ld (runtimeoffsetb+1),a ; Est-ce qu'on a plus d'une cp c ; ligne de retenue ? jr z,nodmaoverflowb DMAOverflowB inc b NoDMAOverflowB ; a une ligne moins a attendre ld a,b dec b ld (hl),b ; Pokage de l'unite de pause inc hl ld (hl),&10 inc hl ex af,af' PokeSwitchVolumeB ; Calcul du volume SID courant xor 15 ld (hl),a ; Pokage du volume SID ex af,af' inc hl ;ld (hl),9 inc hl exx ld c,a ; Test de fin de frame add hl,bc bit 0,h jr z,loopdma_b ld a,l sub a,e jr c,loopdma_b exx ld (hl),&20 inc hl ld (hl),&40 dec a ; Correction du nombre de lignes ; en overflow (255=pas d'overflow) ld (predelayb+1),a ; On recupere le nombre de ligne qui debordent de ; la frame pour les mettre au debut de la suivante ex af,af' ; On recupere le volume SID courant pour ld (sidvolumeb+1),a ; reprendre au bon etat a la frame suivante ret ; ; Routines de lancement des AYLists B ; StartDMAListB ld e,2 ld bc,4 ld hl,(dmalistb+1) ; On ne lance l'AYList du debut ld a,(hl) ; que si on avait une pre-attente cp 255 ; sinon si on n'avait pas de pre-attente jr z,startwithnopredelayb ; alors on saute toute la phase d'init ; or a ; sinon si on avait juste une ligne de ; jr nz,startwithpredelayb ; pre-attente on saute uniquement ld c,e ; l'instruction de pause StartWithNoPredelayB add hl,bc StartWithPredelayB ; Ici HL=adresse AYList a lancer ld bc,&7fb8 out (c),c ld (&6c04),hl ; adr DMA1 ld a,(&6c0f) or 2 ld (&6c0f),a ; run DMA1 ld c,&a0 out (c),c ld hl,primarysidlistbpredelay ; On switch les AYLists de travail ld de,secondarysidlistbpredelay WhichDMAListB ld a,0 xor 1 ld (whichdmalistb+1),a jp z,startwithprimaryb StartWithSecondaryB ld (dmalistb+1),de ret StartWithPrimaryB nop ld (dmalistb+1),hl ret ENDIF IF sidonc ; Routines de creation des AYLists C ; A = volume SID ; DE = frequence SID CreateDMAListC ld a,(regsvalues+FXC_H) ld d,a ; D=nbre ligne periode sid IF syncsid ld a,(regsoldvalues+FXC_H) cp d jr z,nonewfxc_h ld a,d ld (regsoldvalues+FXC_H),a xor a ld (runtimeoffsetc+1),a NoNewFXC_H ENDIF ld a,(regsvalues+FXC_L) ld e,a ; E=retenue en nops IF syncsid ld a,(regsoldvalues+FXC_L) cp e jr z,nonewfxc_l ld a,e ld (regsoldvalues+FXC_L),a xor a ld (runtimeoffsetc+1),a NoNewFXC_L ENDIF ld a,(regsvalues+R10) ; On recupere le volume courant et ld (pokeswitchvolumec+1),a ; on le met en switch dans la dma loop ld b,a ; B=volume du canal DMAListC ld hl,primarysidlistcpredelay ; AYList a utiliser PreDelayC ld a,255 ; On recupere le nombre de lignes qui restaient ld (hl),a ; a attendre de la frame precedente et on le inc hl ; poke dans la phase d'init de l'AYList inc hl inc a ex af,af' SIDVolumeC ; On recupere l'etat du volume SID et ld a,15 ; le poke dans la phase d'init de l'AYList ld (hl),a inc hl inc hl or a ; si le volume courant du canal a change depuis jr z,nonewvolc ; la frame precedente on le RAZ ld a,b NoNewVolC ex af,af' ; A'=volume SID courant ; ; On cr{e l'AYList C ; ; IN ; A'=volume SID courant ; ; A=nombre de lignes deja traitee en init ; ; D,E=periode SID en base 64 ; ; (pokeswichvolume+1)=volume canal courant ; ; (runtimeoffsetc+1)=retenue periode SID en cours ; OUT ; A=nombre de lignes SID debordant de la frame ; ; A'=volume SID courant MakeDMAListC exx ld h,0 ; HL'=compteur de ligne ld l,a ld b,h ; B'=0 (constante) ld e,56 ; E'=312 modulo 256 (constante) LoopDMA_C exx ld b,d ; B=nombre de lignes a attendre RunTimeOffsetC ld a,0 ; A=retenue du calcul precedent PokeC_1 add a,e ld c,a ; C=retenue globale and &3f ld (runtimeoffsetc+1),a ; Est-ce qu'on a plus d'une cp c ; ligne de retenue ? jr z,nodmaoverflowc DMAOverflowC inc b NoDMAOverflowC ; a une ligne moins a attendre ld a,b dec b ld (hl),b ; Pokage de l'unite de pause inc hl ;ld (hl),&10 inc hl ex af,af' PokeSwitchVolumeC ; Calcul du volume SID courant xor 15 ld (hl),a ; Pokage du volume SID ex af,af' inc hl ;ld (hl),10 inc hl exx ld c,a ; Test de fin de frame add hl,bc bit 0,h jr z,loopdma_c ld a,l sub a,e jr c,loopdma_c exx ;ld (hl),&20 ;inc hl ;ld (hl),&40 dec a ; Correction du nombre de lignes ; en overflow (255=pas d'overflow) ld (predelayc+1),a ; On recupere le nombre de ligne qui debordent de ; la frame pour les mettre au debut de la suivante ex af,af' ; On recupere le volume SID courant pour ld (sidvolumec+1),a ; reprendre au bon etat a la frame suivante ret ; ; Routines de lancement des AYLists C ; StartDMAListC ld e,2 ld bc,4 ld hl,(dmalistc+1) ; On ne lance l'AYList du debut ld a,(hl) ; que si on avait une pre-attente cp 255 ; sinon si on n'avait pas de pre-attente jr z,startwithnopredelayc ; alors on saute toute la phase d'init ; or a ; sinon si on avait juste une ligne de ; jr nz,startwithpredelayc ; pre-attente on saute uniquement ld c,e ; l'instruction de pause StartWithNoPredelayC add hl,bc StartWithPredelayC ; Ici HL=adresse AYList a lancer ld bc,&7fb8 out (c),c ld (&6c08),hl ; adr DMA2 ld a,(&6c0f) or 4 ld (&6c0f),a ; run DMA2 ld c,&a0 out (c),c ld hl,primarysidlistcpredelay ; On switch les AYLists de travail WhichDMAListC ; Ici pas besoin de temps constant ld a,0 ; comme les routines DMA A et B xor 1 ; car on ne lancera rien apr}s ld (whichdmalistc+1),a jr z,startwithprimaryc StartWithSecondaryC ld hl,secondarysidlistcpredelay StartWithPrimaryC ld (dmalistc+1),hl ret ENDIF IF hardenv TableReg13 db 0,4,8,12,10,14,11,13 ENDIF FrameDATA ds streamscount Let CurrentPC=$ Org 0:Nocode f_R1 db 0:f_R0 db 0 f_R3 db 0:f_R2 db 0 f_R5 db 0:f_R4 db 0 f_R6 db 0:f_R7 db 0 f_R8 db 0:f_R9 db 0:f_R10 db 0 IF hardenv:f_R12 db 0:f_R11 db 0:ENDIF IF sidona:f_FXA_H db 0:f_FXA_L db 0:ENDIF IF sidonb:f_FXB_H db 0:f_FXB_L db 0:ENDIF IF sidonc:f_FXC_H db 0:f_FXC_L db 0:ENDIF Org CurrentPC:Code Read"streamv4.inc" Let CurrentPC=$+1 Org CurrentPC and &fffe RasterInterrupt ei ret DMAInterrupt1 ; Sp{cifique DMA1 push af push bc ld bc,&7fb8 out (c),c ld a,(&6c0f) or &20 and &25 ; ack&stop DMA1 ld (&6c0f),a ld c,&a0 out (c),c pop bc pop af ei ret DMAInterrupt2 ; Sp{cifique DMA2 push af push bc ld bc,&7fb8 out (c),c ld a,(&6c0f) or &10 and &13 ; ack&stop DMA2 ld (&6c0f),a ld c,&a0 out (c),c pop bc pop af ei ret Let CurrentPC=$+&100 ; Multiple de &100 car E=num{ro de registre Org CurrentPC and &ff00 RegsValues ds 32 RegsOldValues ds 32,&aa Let CurrentPC=$ ; Offset des registres AY Org 0:NoCode R0 db 0:R1 db 0:R2 db 0:R3 db 0:R4 db 0:R5 db 0 R6 db 0:R7 db 0 R8 db 0:R9 db 0:R10 db 0 IF hardenv:R11 db 0:R12 db 0:R13 db 0:ENDIF FXA db 0:IF sidona:FXA_H db 0:FXA_L db 0:ENDIF FXB db 0:IF sidonb:FXB_H db 0:FXB_L db 0:ENDIF FXC db 0:IF sidonc:FXC_H db 0:FXC_L db 0:ENDIF Org CurrentPC:Code Let CurrentPC=$+8 ; Multiple de &8 car li{ @ IVR Org CurrentPC and &fff8 TableInt IntDMA2 dw dmainterrupt2 IntDMA1 dw dmainterrupt1 IntDMA0 dw rasterinterrupt IntRast dw rasterinterrupt Let CurrentPC=$+1 ; Multiple de 2 car AY List Org CurrentPC and &fffe ; SID AYLists IF sidona PrimarySIDListAPredelay dw &1000 ; Pause NN dw &080F ; LD VolA,NN PrimarySIDListA dw &1000 ; Pause NN dw &080F ; LD VolA,NN ds 312-4 dw &4020 ; STOP SecondarySIDListAPredelay dw &1000 ; Pause NN dw &080F ; LD VolA,NN SecondarySIDListA dw &1000 ; Pause NN dw &080F ; LD VolA,NN ds 312-4 dw &4020 ; STOP ENDIF IF sidonb PrimarySIDListBPredelay dw &1000 ; Pause NN dw &090F ; LD VolB,NN PrimarySIDListB dw &1000 ; Pause NN dw &090F ; LD VolB,NN ds 312-4 dw &4020 ; STOP SecondarySIDListBPredelay dw &1000 ; Pause NN dw &090F ; LD VolB,NN SecondarySIDListB dw &1000 ; Pause NN dw &090F ; LD VolB,NN ds 312-4 dw &4020 ; STOP ENDIF IF sidonc PrimarySIDListCPredelay dw &1000 ; Pause NN dw &0A0F ; LD VolC,NN PrimarySIDListC dw &1000 ; Pause NN dw &0A0F ; LD VolC,NN ds 312-4 dw &4020 ; STOP SecondarySIDListCPredelay dw &1000 ; Pause NN dw &0A0F ; LD VolC,NN SecondarySIDListC dw &1000 ; Pause NN dw &0A0F ; LD VolC,NN ds 312-4 dw &4020 ; STOP ENDIF List EndAdr Nolist Org entry  modifi{e du pucrunch ; pour pouvoir g{rer du streaming ; par packets de taille fixe ;