Jump to content
IGNORED

Coding tricks


Recommended Posts

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
Link to comment
Share on other sites

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.

SpriteTest.bin

Link to comment
Share on other sites

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

Link to comment
Share on other sites

  • 2 weeks later...

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
Link to comment
Share on other sites

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

 

 

 

Link to comment
Share on other sites

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

Link to comment
Share on other sites

  • 1 month later...
  • 2 weeks later...
  • 2 years later...

Alright I give. How does one implement a Jump table in 6507 code? I'd like to hold an offset like such to a table of Jumps:

 

Offset = 0 through 3

 

JumpTable:

jmp doThis

jmp doThat

jmp doSomething

jmp DONTDOTHAT

 

And I'd like to call it via jmp JumpTable,Offset to land on the right bounce.

It's usually done by putting just the addresses in the table, putting one of them on the stack, and doing an RTS. Saves the jmp instruction in each entry, and it's also easier to multiply by 2 than 3.

Link to comment
Share on other sites

I got an email saying that someone replied to a posting I made over two years ago >_<

What I want to know is why Glade Swope is necrobumping old posts answering them.

Does this new member really think we never got an answer after all this time?

 

FYI I have a major real work deadline that is sucking all my time, otherwise I would be here working on my harmony projects.

So I haven't disappeared completely again. Be back later on after work settles down :)

Link to comment
Share on other sites

Not at all. It's way easier to scrounge for 2 bytes of ROM than 2 bytes of stack space. You can also LDA $hotspot,X and have a program bankswitch to a dedicated routine residing in each. 4 cycles and done. No ram, and no jump. Just make sure it banks to the same address in each block.

Edited by Nukey Shay
Link to comment
Share on other sites

I've been reusing stack RAM as temp variables ever since Medieval Mayhem; so for me, since the stack was already allocated, the 2 byte ROM savings is nice.

; $FE - $FF stack
; reuse of stack RAM - no JSRs can be called when these are used
TempInStack1 EQU $FE
TempInStack2 EQU $FF

For my current DPC+ with ARM projects it doesn't matter - Space Rocks uses 9 bytes of ZP RAM while Stay Frosty 2 uses 17.

Link to comment
Share on other sites

Just found this today, for details look here.

 

Here is the trick code:

  lda #$70
  sta HMM0
  sta HMM1
  sta HMBL
  lda #$c0
  sta WSYNC
;---------------------------------------
  sta HMOVE 
  SLEEP 5
  sta HMM0 
  sta HMM1 
  sta HMBL 

This will triple the Cosmic Ark stars effect.

Link to comment
Share on other sites

Good idea. I just tried and it works! Even with all 5 objects.



  lda #$70
  sta HMM0
  sta HMM1
  sta HMBL
  sta HMP0
  sta HMP1
  sta WSYNC
;---------------------------------------
  sta HMOVE
  SLEEP 10      ; works up to 18
  sta HMCLR

We should test with some critical consoles. Maybe higher SLEEP values will work there.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   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...