Jump to content



1

Coding tricks


57 replies to this topic

#51 ScumSoft OFFLINE  

ScumSoft

    Moonsweeper

  • 331 posts
  • Location:Polysorbate 60

Posted Sun Apr 17, 2011 4:11 PM

Thanks for the advice, I think I got it now thanks to your ideas:
P0slot = 0 through 11
FrameNum = 0 or 1 for Frame1 and Frame2
;********************************
;     [MASKING ROUTINE]
;********************************
MaskData:
    ldy P0shift             ;[]+3 Load player shift amount
    ldx MaskTable,Y         ;[]+4 Load mask into X
    ldy #15                 ;[]+2 Y will be our counter for 16-bytes 
    ;********************************
    ;Choose from 4 scenarios
    ;Slot / Frame
    ;0/0 = 0 .F1SE    
    ;0/1 = 1 .F1SO (no inc slot)
    ;1/0 = 1 .F1SO = Inc P0slot
    ;1/1 = 0 .F1SE
    ;********************************
    lda P0slot              ;[]+3 Load player GFXslot number
    and #1                  ;[]+2 Clear all but bit 0
    eor FrameNum            ;[]+3 Will result in truth table above    
    beq .doMask             ;[]+2/3 Scenarios 1 and 4
    ;In scenario 2 or 3 so invert mask
    txa                     ;[]+2
    eor #$FF                ;[]+2
    tax                     ;[]+2     
    lda FrameNum            ;[]+3 Test Scenario 2 or 3
    bne .doMask             ;[]+2/3 FrameNum = 1 = Scenario 2
    inc P0slot              ;[]+5 Scenario 3, INC P0slot
    
;[MASK BYTES]
.doMask              
    lda P0buffer,Y          ;[]+4
    sax P0buffer,Y          ;[]+4
    dey                     ;[]+2
    bpl .doMask             ;[]+2/3
    rts                     ;[]+6

;********************************
;     [TABLES]
;********************************    
MaskTable:
       ;$00,$01,$02,$03,$04,$05,$06,$07
  .byte $FF,$7F,$3F,$1F,$0F,$07,$03,$01 

What do you think? Greatly simplified from my initial posting Or did I miss something from your ideas?

I am still understanding the rotate method Thomas posted, I think I've come up with a faster way to do them, but I'll see once I complete it.

Edited by ScumSoft, Sun Apr 17, 2011 4:26 PM.


#52 ScumSoft OFFLINE  

ScumSoft

    Moonsweeper

  • 331 posts
  • Location:Polysorbate 60

Posted Sun Apr 17, 2011 8:08 PM

Okay here is the Rotate byte routine:
;********************************
;     [ROTATE ROUTINES]
;********************************
RotateBytes:
    lda #>Ror1              ;[]+3 Save high byte
    sta GENpoint+1          ;[]+3 Store in general pointer    
    ldy P0shift             ;[]+3 Load amount to rotate
    lda ROtableJmp,Y        ;[]+4 Use shift as index
    sta GENpoint            ;[]+3 Ready for jmp
    ldx #15                 ;[]+2 Use counter as byte index
.RORa
    lda P0buffer,X          ;[]+4 Load Sprite byte to be rotated
    jmp (GENpoint)          ;[]+5 Engage!
    
    ;Will have always branched by now, no need for further checks
Ror4:
    lsr                     ;[]+2
    bcc *+4                 ;[]+2/3
    ora #$80                ;[]+2
Ror3:
    lsr                     ;[]+2
    bcc *+4                 ;[]+2/3
    ora #$80                ;[]+2
Ror2:
    lsr                     ;[]+2
    bcc *+4                 ;[]+2/3
    ora #$80                ;[]+2
Ror1:
    lsr                     ;[]+2
    bcc *+4                 ;[]+2/3
    ora #$80                ;[]+2
    jmp .RotCont            ;[]+3
Rol5:
    asl                     ;[]+2
    adc #0                  ;[]+2
Rol6:
    asl                     ;[]+2
    adc #0                  ;[]+2
Rol7:
    asl                     ;[]+2
    adc #0                  ;[]+2 
.RotCont
    sta P0buffer,X          ;[]+4 Store Result into 16-byte SPRITE buffer
    dex                     ;[]+2 Decrement counter
    bpl .RORa               ;[]+2/3 Branch if more bytes to rotate
    rts

ROtableJmp:
    .byte <.RORa, <Ror1, <Ror2, <Ror3, <Ror4, <Rol5, <Rol6, <Rol7  

I haven't traced out the best/worst case scenarios for this yet, so it may be slower/same/faster.
Just wanted to show that I am taking what was posted and learning from it.

Thanks again guys as always!

Here is a demo of it in action, nothing special just a 8x16 sprite you can move around of my guy with a sword.
White color is drawn on Frame1
Red is drawn on Frame2

96x96 software controlled pixel playfield.

Attached Files



#53 bogax OFFLINE  

bogax

    Star Raider

  • 61 posts

Posted Mon Apr 18, 2011 9:05 PM

it appears there's a zp version of sax so ...

 ldx #$0F
 clc

 ror           ;abcdefgh 0
 ror
 ror
 ror
 sax temp      ;fgh0abcd e  0000abcd
 adc temp      ;fghabcde 0  carry zeroed for the next round
14 cycles for a 3 bit rotate plus the ldx, clc overhead

probably as fast or faster to do something else for other
rotates.

even numbers
RIGHT_4     ;12 cycles
 asl
 adc #$80
 rol
RIGHT_6     ; 6 cycles
 asl
 adc #$80
 rol
odd numbers
RIGHT_5     ;10 cycles
 asl
 adc #$80 
 rol
RIGHT_7     ; 4 cycles
 cmp #$80
 rol


#54 ScumSoft OFFLINE  

ScumSoft

    Moonsweeper

  • 331 posts
  • Location:Polysorbate 60

Posted Sat Apr 30, 2011 1:46 AM

Since I've switched over to using the DPC+ for now, I've run into a whole slew of new issues :D I mean fun challenges to overcome.

How do I run a subroutine from another bank? I've looked around but don't understand the procedure.

Switch banks then jump to routine you need? and to switch banks I have to just access the $1FFx slot the bank table has it set to?
Does the bank start at the beginning, or does it continue on the same instruction count as when it was switched, e.g on PC#00E2 -> switch bank -> PC#00E2 ?
Or will the PC reset to 00 and start at the top of the bank.

I'm confused!

[edit]Hmm found This Link which seems to have explained it pretty well.

So if I wanted to access a 2k table from another bank, how would that work? Would I have to switch banks to read from it?

Edited by ScumSoft, Sat Apr 30, 2011 2:29 AM.


#55 SeaGtGruff ONLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Sat Apr 30, 2011 6:06 PM

View PostScumSoft, on Sat Apr 30, 2011 1:46 AM, said:

Since I've switched over to using the DPC+ for now, I've run into a whole slew of new issues :D I mean fun challenges to overcome.

How do I run a subroutine from another bank? I've looked around but don't understand the procedure.

Switch banks then jump to routine you need? and to switch banks I have to just access the $1FFx slot the bank table has it set to?
Does the bank start at the beginning, or does it continue on the same instruction count as when it was switched, e.g on PC#00E2 -> switch bank -> PC#00E2 ?
Or will the PC reset to 00 and start at the top of the bank.

I'm confused!

[edit]Hmm found This Link which seems to have explained it pretty well.

So if I wanted to access a 2k table from another bank, how would that work? Would I have to switch banks to read from it?
DPC+ switches the cart's entire 4K memory space, so you'll need one or more bankswitching routines, and they'll need to be replicated at the same locations in all banks.

I know Fred (batari) likes to use a stack/RTS method to switch banks. If you look at the "banksw.asm" code (shown below), you can see how he does it.

; every bank has this stuff at the same place
; this code can switch to/from any bank at any entry point
; and can preserve register values
; note: lines not starting with a space are not placed in all banks
;
; line below tells the compiler how long this is - do not remove
;size=32
begin_bscode
 ldx #$ff
 ifconst FASTFETCH ; using DPC+
 stx FASTFETCH
 endif 
 txs
 lda #>(start-1)
 pha
 lda #<(start-1)
 pha
BS_return
 pha
 txa
 pha
 tsx
 lda 4,x ; get high byte of return address
 rol   
 rol
 rol
 rol
 and #bs_mask ;1 3 or 7 for F8/F6/F4
 tax
 inx
BS_jsr
 lda bankswitch_hotspot-1,x
 pla
 tax
 pla
 rts
 if ((* & $1FFF) > ((bankswitch_hotspot & $1FFF) - 1))
   echo "WARNING: size parameter in banksw.asm too small - the program probably will not work."
   echo "Change to",[(*-begin_bscode+1)&$FF]d,"and try again."
 endif
I like to use a simpler approach, and I recently created some macros to simplify the process of calling my routines:

   MAC SKIP

   REPEAT {1}
   HEX 00
   REPEND

   ENDM

   MAC GOTO

   LDY #[(>{0} & $F0) - $10] / $20
   LDX #<{0}
   LDA #>{0}

   JMP Switch_and_Go

   ENDM

   MAC GOSUB

   LDY #[(>. & $F0) - $10] / $20
   STY Return_Bank

   LDY #[(>{0} & $F0) - $10] / $20
   LDX #<{0}
   LDA #>{0}

   JSR Switch_and_Go

   ENDM

   MAC RETURN

   JMP Switch_and_Return

   ENDM

   ORG  $6FE6
   RORG $BFE6

Switch_and_Go

   STX Target_Lo
   STA Target_Hi

   LDA Select_Bank,Y

   JMP (Target)

Switch_and_Return

   LDY Return_Bank
   LDA Select_Bank,Y

   RTS
"Target" is a two-byte variable in zero-page RAM. "Target_Lo" and "Target_Hi" simply redefine the two bytes of "Target."

"Return_Bank" is a one-byte variable in zero-page RAM.

So if I want to switch banks, and the routine I'm jumping to does *not* need to return to where it was called from, I can use "GOTO routine" to switch banks and jump to that routine.

But if I want to switch banks and *return* later, I can use "GOSUB routine" to do that, and then use "RETURN" when I'm ready to return.

The macro code assumes you've got each bank defined with its own logical address space as follows:

   ORG  $0400
   RORG $0000
   INCBIN DPCplus.arm

   ORG  $1000
   RORG $1000
   SKIP 128
Bank_0 ; User Code

   ORG  $2000
   RORG $3000
   SKIP 128
Bank_1 ; User Code

   ORG  $3000
   RORG $5000
   SKIP 128
Bank_2 ; User Code

   ORG  $4000
   RORG $7000
   SKIP 128
Bank_3 ; User Code

   ORG  $5000
   RORG $9000
   SKIP 128
Bank_4 ; User Code

   ORG  $6000
   RORG $B000
   SKIP 128
Bank_5 ; User Code

   ORG  $7000
   RORG $D000
   SKIP 128
Bank_6 ; DPC+ Display Data

   ORG  $8000
   RORG $1000
Bank_7 ; DPC+ Frequency Table
   ; Goes up through $83FF
(The "SKIP 128" statement after each "RORG" uses the "SKIP" macro to set aside the first 128 bytes of each user ROM bank, since those bytes are used for the DPC+ registers.)

Note that when you use my method, the original values of the A, X, and Y registers will be lost, so be sure to store them first if you want to get them back later. However, my "Switch_and_Return" routine leaves the X register untouched, so you could "GOSUB" to some subroutine in a given bank, store some return value in the X register, and "RETURN" to the calling location with the return value intact.

Michael




#56 ScumSoft OFFLINE  

ScumSoft

    Moonsweeper

  • 331 posts
  • Location:Polysorbate 60

Posted Sat Apr 30, 2011 7:31 PM

Darn I was hoping it wasn't going to be like this. Well what I wanted to do was parse a 2k table I store in another bank that holds index addresses to my framebuffer, which would realign the data linearly and simplify things. But if I have to switch banks to access the data and duplicate the parsing code, then it defeats the purpose of having this table in the first place.

So I'll just sacrifice cycles and avoid the bankswitches for now. When I do bankswitch, your routines will come as a good reference.

Thanks for the help :D

#57 ScumSoft OFFLINE  

ScumSoft

    Moonsweeper

  • 331 posts
  • Location:Polysorbate 60

Posted Sat Jun 18, 2011 6:29 PM

Can I get the DPCFRACINC to increment twice per read so that it skips a byte?

If not, can I get a custom DPC+.arm file that increments them twice per read?
This would GREATLY simplify my custom kernals display output.

#58 ScumSoft OFFLINE  

ScumSoft

    Moonsweeper

  • 331 posts
  • Location:Polysorbate 60

Posted Wed Jun 29, 2011 4:23 PM

Yes? No?




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users