+SpiceWare Posted February 19, 2022 Share Posted February 19, 2022 Note: a copy of Part 2 - CDFJ Details with addition of the Fast Fetchers section towards the bottom CDFJ+ is built around data streams. A data stream is a sequence of data elements made available over time - basically a list of values such as: 10 55 20 25 ... The data stream will auto-advance so that the first time you read it you'd get 10, the next time you'd get 55, then 20 and so on. Data streams are very helpful during the kernel as you can update any TIA register in just 5 cycles: LDA #DS0DATA STA GRP0 General Purpose Data Streams There are 32 general purpose data streams named DS0DATA thru DS31DATA. Each data stream has an increment value associated with it for the auto-advance feature. Example increments: 1.0 for 1LK player graphics 0.20 to repeat chunky playfield graphics over 5 scanlines 2.0 to skip every other value. This is extremely useful for interlaced bitmap graphics, which are typical seen as 96 or 128 pixels across. Communication Data Stream There is a dedicated communication data stream named DSCOMM used for transferring data between the 6507 and ARM processors. Jump Data Streams There are 2 data streams for jumps named DSJMP1 and DSJMP2. These override JMP $0000 and JMP $0001 respectively, providing 3 cycle flow control within the kernel. This means instead of counting scanlines and branching your kernel would look something like this kernel from Draconian: ; data stream usage for game screen DS_GRP0 = DS0DATA DS_GRP1 = DS1DATA DS_HMP0 = DS2DATA DS_HMP1 = DS3DATA DS_MISSILE0 = DS4DATA ; HMM0 and ENAM0 DS_MISSILE1 = DS5DATA ; HMM1 and ENAM1 DS_BALL = DS6DATA ; HMBL and ENABL DS_COLOR = DS7DATA ; color change for players and ball only DS_SIZE = DS8DATA ; size change for all objects NormalKernel: ; 20 lda #DS_SIZE ; 2 22 <- just to keep stream in sync nk1: lda #DS_COLOR ; 2 24 2 33 from Resm0Strobe28 <- just to keep stream in sync lda #DS_HMP0 ; 2 26 sta HMP0 ; 3 29 lda #DS_HMP1 ; 2 31 sta HMP1 ; 3 34 lda #DS_MISSILE0 ; 2 36 tax ; 2 38 stx HMM0 ; 3 41 lda #DS_MISSILE1 ; 2 43 tay ; 2 45 sty HMM1 ; 3 48 lda #DS_BALL ; 2 50 sta HMBL ; 3 53 sta ENABL ; 3 56 lda #DS_GRP0 ; 2 58 sta GRP0 ; 3 61 lda #DS_GRP1 ; 2 63 sta WSYNC ; 3 66/0 sta HMOVE ; 3 3 sta GRP1 ; 3 6 <- also updates GRP0 and BL DIGITAL_AUDIO ; 5 11 stx ENAM0 ; 3 14 sty ENAM1 ; 3 17 jmp FASTJMP1 ; 3 20 ExitKernel: ... Resm0Strobe23: ; 20 sta RESM0 ; 3 23 lda #DS_SIZE ; 2 25 sta NUSIZ0 ; 3 28 <- changes missile size jmp nk1 ; 3 31 Resm0Strobe28: ... The data stream DSJMP1 is initially filled with addresses for NormalKernel, and ends with the address for ExitKernel. The player, missile and ball reuse routines will change individual values in DSJMP1 to jump to reposition kernels such as Resm0Strobe23. Audio Data Stream Lastly there's an audio data stream named AMPLITUDE. It will return a stream of data to play back a digital sample, or to play back 3 voice music with custom waveforms. The macro DIGIT_AUDIO in the above Draconian kernel is defined as: MAC DIGITAL_AUDIO lda #AMPLITUDE sta AUDV0 ENDM 6507 Interface From the Atari's point of view CDFJ only has 4 registers defined in the cartridge space. DSWRITE at $1FF0 DSPTR at $1FF1 SETMODE at $1FF2 CALLFN at $1FF3 DSPTR is used to set the Display Data address for the DSCOMM data stream - basically setting the RAM location the 6507 code wishes to write to. Write the low byte of the address first, then the high byte. DSWRITE writes to the address set by DSPTR. After writing, DSPTR advances to the next RAM location in preparation for the next write: ; define storage in Display Data _DS_TO_ARM: _SWCHA: ds 1 ; controller state to ARM code _SWCHB: ds 1 ; console switches state to ARM code _INPT4: ds 1 ; firebutton state to ARM code _INPT5: ds 1 ; firebutton state to ARM code ... ldx #<_DS_TO_ARM stx DSPTR ldx #>_DS_TO_ARM stx DSPTR ldx SWCHA ; read state of both joysticks stx DSWRITE ; written to _SWCHA ldx SWCHB ; read state of console switches stx DSWRITE ; written to _SWCHB ldx INPT4 ; read state of left joystick firebutton stx DSWRITE ; written to _INPT4 ldx INPT5 ; read state of right joystick firebutton stx DSWRITE ; written to _INPT5 SETMODE controls Fast Fetch Mode and Audio Mode. Fast Fetch mode overrides the LDA #immediate mode instruction and must be turned on to read from the data streams. Audio Mode selects between digital sample mode or 3-voice music mode. CALLFN is used to call the function main() in your C code. The value written to CALLFN determines if an interrupt will run to periodically update AUDV0. The interrupt is needed when playing back digital samples or 3-voice music. ldy #$FE ; generate interrupt to update AUDV0 while running ARM code sty CALLFN ldy #$FF ; do not update AUDV0 sty CALLFN Fast Fetchers Fast Fetchers in CDFJ+ have seen 2 optional updates from CDFJ. 1) Besides LDA #, you can optionally use LDX # and/or LDY # for Fast Fetch mode. This would free up 4 cycles in the NormalKernel from above, look for the <*==-- comments: NormalKernel: ; 20 lda #DS_SIZE ; 2 22 <- just to keep stream in sync nk1: lda #DS_COLOR ; 2 24 2 33 from Resm0Strobe28 <- just to keep stream in sync lda #DS_HMP0 ; 2 26 sta HMP0 ; 3 29 lda #DS_HMP1 ; 2 31 sta HMP1 ; 3 34 ldx #DS_MISSILE0 ; 2 36 <*==-- no longer need to use TAX for the deferred STX ENAM1 nop ; 2 38 <*==-- 2 freed up cycles stx HMM0 ; 3 41 ldy #DS_MISSILE1 ; 2 43 <*==-- no longer need to use TAY for the deferred STY ENAM0 nop ; 2 45 <*==-- 2 freed up cycles sty HMM1 ; 3 48 lda #DS_BALL ; 2 50 sta HMBL ; 3 53 sta ENABL ; 3 56 lda #DS_GRP0 ; 2 58 sta GRP0 ; 3 61 lda #DS_GRP1 ; 2 63 sta WSYNC ; 3 66/0 sta HMOVE ; 3 3 sta GRP1 ; 3 6 <- also updates GRP0 and BL DIGITAL_AUDIO ; 5 11 stx ENAM0 ; 3 14 sty ENAM1 ; 3 17 jmp FASTJMP1 ; 3 20 2) You can now set a Fast Fetcher offset. By default the offset is 0 so only LDA #DS0DATA thru LDA #AMPLITUDE are overridden, while LDA #$24 thru LDA #$FF would put the normal value of #$24 thru $FF into the Accumulator. If you change the offset to $80 then LDA #DS0DATA + $80 thru LDA #AMPLITUDE + $80 are overridden, while LDA #$00 thru LDA #$7F and LDA #$84 thru LDA #$FF would put the normal value of $00 thru $7F and $84 thru $ff into the Accumulator. Macros are provided to make it easier to use the offset and LDA/X/Y # immediate mode instructions: FFA - Fast Fetch using LDA # FFX - Fast Fetch using LDX # FFY - Fast Fetch using LDY # FFSTA - Fast Fetch plus Store using LDA # / STA FFSTX - Fast Fetch plus Store using LDX # / STX FFSTY - Fast Fetch plus Store using LDY # / STY SLDA - Safe LDA # - validates that value is not overridden for data stream usage. SLDX - Safe LDX # - validates that value is not overridden for data stream usage. SLDY - Safe LDY # - validates that value is not overridden for data stream usage. ; macro FFA DS0DATA ; becomes LDA #(DS0DATA + OFFSET) ; macro FFSTX AMPLITUDE, AUDV0 ; becomes LDX #$AMPLITUDE STX AUDV0 ; macro SLDY 10 ; If offset is 0 a compile time error will occur: LDY # $a is within Fast Fetcher range of 0 and $23 ; If OFFSET is > 10 becomes LDY #10 C Interface From the C code a number of functions have been defined to interact with CDFJ and Display Data: setPointer() setPointerFrac() setIncrement() setWaveform() setSamplePtr() setNote() resetWave() getWavePtr() getWavePtr() getPitch() getRandom32() myMemset() myMemcpy() myMemsetInt() myMemcpyInt() This section will be expanded upon later. 2 Link to comment Share on other sites More sharing options...
Recommended Posts