Jump to content
  • entries
    657
  • comments
    2,702
  • views
    902,444

The Story of Stay Frosty 2, Part 5


SpiceWare

1,956 views

Next I started to work out how to update AUDV0, for the 3 voice music, once per scanline while the ARM code was running. batari suggested just running short routines in ARM that would take less than a scanline each. I thought that would be overly complicated, so thought I might be able to pre-fetch the AUDV0 values, stash them in ZP (Zero Page) RAM, then have the 6507 run the following routine in RAM while the ARM code ran:

        MAC ZP_ROUTINE
        SUBROUTINE
        ; X holds how many Cache values-1
.ZP     ldy #$FF                ; 2 67
        sty CALLFUNCTION        ; 4 69
.ZPloop
        lda CachedAMPLITUDE,x   ; 4 73
        sta WSYNC               ; 3 76/0    
        sta AUDV0               ; 3  3  
        dex                     ; 2  5  
        bpl .ZPloop             ; 3  8 - branch taken
.checkARMstate                  ; 2  7 - branch not taken
        ldx PosObject           ; 4 11
        cpx #$38                ; 2 13 - check that we see a SEC command
        beq .BCcountdown        ; 3 16 - branch taken
        ldx #$80                ; 2 18 - error color since ARM still running
        stx BackgroundColor     ; 3 21
        ldx #120                ; 2 23 - show error color for 2 seconds
        stx BCcount             ; 3 26
.BCcountdown
        ldx BCcount             ; 3 29
        beq .ZPexit             ; 2 31
        dex                     ; 2 33
        stx BCcount             ; 3 36
        bne .ZPexit             ; 2 38
        ldx #0                  ; 2 40 - black
        stx BackgroundColor     ; 3 43
.ZPexit
        rts                     ; 6 49 - 49 = worse case path   
        ENDM       
 

The routine will run for a predefined number of scanlines, updating AUDV0 for the 3-voice music using cached values. Once the values are used up, the routine then checks a ROM location to see if it has the expected value of $38 (the SEC command located at the start of the PosObject function) which would tell us if the ARM code has finished running or not. This works because while ARM code is executing $EA, a NOP instruction, is put on the bus so the 6507 doesn't do anything. If the SEC command wasn't found, the background color is changed so I could tell if the ARM code ran too long (remember, at this time Stella didn't run ARM code, so the routines only worked on real hardware).

 

The routine is defined as a Macro because it needs to be compiled in the RAM block (to allocate space):

CACHE_COUNT = 6
       
        SEG.U VARS
        ORG $80
BackgroundColor ds 1    ; background color to show - normally black
            ; but will have a color to denote which ARM routine
            ; exceeded expected run time
BCcount     ds 1    ; error color countdown

CachedAMPLITUDE:    ; must be before ZProutineRAM
    ds CACHE_COUNT

ZProutineRAM:
    ZP_ROUTINE
 

as well as in ROM

ZProutineROM:
	ZP_ROUTINE
ZPsize = *-ZProutineROM

 

 

so it can be copied into RAM during system initialization.

; Init system, copies ROM version of ZP_ROUTINE to RAM
InitSystem:
    CLEAN_START
    
    ldy #ZPsize
InitZP  
    lda ZProutineROM,y
    sta ZProutineRAM,y
    dey
    bpl InitZP
 

Whenever ARM code is called, a set number of AMPLITUDE values are read and stored into CachedAmplitude, then ZProutineRAM is called:

CallARM:
    lda #<AMPLITUDE
    sta WSYNC
    sta AUDV0
    lda #<AMPLITUDE
    sta CachedAMPLITUDE+5
    lda #<AMPLITUDE
    sta CachedAMPLITUDE+4
    lda #<AMPLITUDE
    sta CachedAMPLITUDE+3
    lda #<AMPLITUDE
    sta CachedAMPLITUDE+2
    lda #<AMPLITUDE
    sta CachedAMPLITUDE+1
    lda #<AMPLITUDE
    sta CachedAMPLITUDE+0
    ldx #[CACHE_COUNT-1]
    jmp ZProutineRAM
 

The routine worked, but the sound was awful. Turns out you can't prefetch AMPLITUDE values because the DPC+ driver uses an internal timer when calculating the values. batari thought about changing DPC+ to allow prefetched values, but he ultimately decided:

On 10/11/2010 at 9:40 PM, batari said:

It might actually be easier to interrupt with a timer set for approximately one scanline, and have the ARM feed STA AUDV0, then NOP and return.

 

Which is how we ended up with DPC+ support for interrupt driven music when running ARM code.

 

Blog entry covers October 6 - 12, 2010

  • Like 1

4 Comments


Recommended Comments

This is a little late, but congratulations on the release of Stay Frosty 2, Darrell! Also congratulations go to Nathan and everyone else involved in the project.

  • Like 2
Link to comment

Do you know a good way to get the assembler to label the ZProutineROM routine once

its loaded into RAM? For example, if you had lda #%10011001 somewhere in ZPRoutineRAM,

and wanted to change it on the fly to lda #%11111111 could you:

 

lda #%11111111

sta MySpecialRAMLabel+1 ;(the operand portion of that load)

 

I think this could be figured out manually, but while writing, it would be great if a labelled location could be figured by the assembler.

Link to comment

Untested, but something like:

        MAC ZP_ROUTINE
        SUBROUTINE
        ; X holds how many Cache values-1
.ZP     ldy #$FF                ; 2 67
        sty CALLFUNCTION        ; 4 69
.ZPloop
        lda CachedAMPLITUDE,x   ; 4 73
        sta WSYNC               ; 3 76/0    
        sta AUDV0               ; 3  3  
        dex                     ; 2  5  
        bpl .ZPloop             ; 3  8 - branch taken
.checkARMstate                  ; 2  7 - branch not taken
        ldx PosObject           ; 4 11
        cpx #$38                ; 2 13 - check that we see a SEC command
        beq .BCcountdown        ; 3 16 - branch taken
        ldx #$80                ; 2 18 - error color since ARM still running
ECoffset = *-.ZP-1
        stx BackgroundColor     ; 3 21
        ldx #120                ; 2 23 - show error color for 2 seconds
        stx BCcount             ; 3 26
.BCcountdown
        ldx BCcount             ; 3 29
        beq .ZPexit             ; 2 31
        dex                     ; 2 33
        stx BCcount             ; 3 36
        bne .ZPexit             ; 2 38
        ldx #0                  ; 2 40 - black
        stx BackgroundColor     ; 3 43
.ZPexit
        rts                     ; 6 49 - 49 = worse case path   
        ENDM       

 

Then to change the error color:

    lda #$40
    sta ZProutineRAM + ECoffset

 

Link to comment
Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...