Can you store a scope/proc reference in a table?

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
bjones
Posts: 23
Joined: Mon Apr 29, 2019 4:34 pm

Can you store a scope/proc reference in a table?

Post by bjones »

So I’m trying to do some code optimizing.
I know I can store an address to a code jmp in a table but I do not see anything about scope/proc references.

But seeing as you can pass a scope reference through a macro I thought I’d ask if it was possible to store them in a table to cut down on having long lists of cmps?
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Can you store a scope/proc reference in a table?

Post by tokumaru »

Scopes have nothing to do with the CPU itself, they're constructs used during assembly time for the purpose of keeping code organized. The 6502 itself doesn't have any concept of scopes - all symbols/labels, regardless of their scopes, are simply converted to numbers when the code is assembled.

What exactly is it that you're trying to do? How would a table of scopes help reduce long lists of CMPs?
bjones
Posts: 23
Joined: Mon Apr 29, 2019 4:34 pm

Re: Can you store a scope/proc reference in a table?

Post by bjones »

It’s all to do with organization.

You could have your enemy updates all set to their own scopes/proc with each having a scope::update.
Instead of writing out multiple compares for an enemy type then branching to the correct subroutine you could just write a much smaller pull the reference for the scope based on a type and then a single enemyscope::update.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Can you store a scope/proc reference in a table?

Post by Quietust »

If I'm understanding you correctly, it sounds like you're trying specify pointers in a jump table where those pointers all exist within specific namespaces.

It would help to know which assembler you're using, since the answer will probably vary quite a lot.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Can you store a scope/proc reference in a table?

Post by tokumaru »

Looks like ca65 syntax. All labels are simply converted into addresses at assembly time, so there's nothing stopping you from doing this:

Code: Select all

ObjectUpdateTable:

  .word object0scope::update
  .word object1scope::update
  .word object2scope::update
  ;(...)
  .word object126scope::update
  .word object127scope::update
It's exactly the same as if you weren't using scopes at all.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Can you store a scope/proc reference in a table?

Post by tokumaru »

Another thing I sometimes do when I want to define the values that go in a table away from the table itself is something like this:

Code: Select all

ObjectUpdateTable:

  .word UpdatePlaceholder0
  .word UpdatePlaceholder1
  .word UpdatePlaceholder2
  ;(...)
Then, inside the object's own scope I can do:

Code: Select all

  .scope EvilEnemy

  ::UpdatePlaceholder5 := Update

Update:

  ;(...)
This way I get to decide each object's number inside the object's own file, instead of having to make sure that a table defined elsewhere has the object in the position I want.

The downside is that the assembler will throw errors if you try to assign multiple values to the same placeholder, or if you leave any placeholder uninitialized. You can write macros to help automate this task, though - a macro (e.g. "RegisterObject") could take INIT, UPDATE, DRAW, etc. addresses and the desired number for the object and automatically assign them to the respective placeholders, and another macro called at the end would verify which placeholders were left unused and assign some bogus value to them.
bjones
Posts: 23
Joined: Mon Apr 29, 2019 4:34 pm

Re: Can you store a scope/proc reference in a table?

Post by bjones »

I think I have found a solution.

instead of pulling a scope reference I can create 1 macro that takes a type ID and a sub routine name. Then just reuse that macro everytime I need to get a scope for a sub routine. The subroutine can be anything as long as the enemy scopes each have one named the same. So now if I need to add a new enemy type all i need to do is add the new scope and the cmp in the one macro.



example:

Code: Select all

.macro scopeCall typeid, sbr 

 lda  typeid
 
 cmp  #01
bne:+
  jsr ena::sbr
:

 cmp  #02
bne:+
  jsr enb::sbr
:

.endmacro



update: This works beautifully! in just a few short mins i have already knocked down all the enemy updates and sprite draws to a few lines of code instead of the long compare lists as before. :beer:
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Can you store a scope/proc reference in a table?

Post by Oziphantom »

if optimization is the aim

Code: Select all

ldx typeid
lda CallTableSBR_hi,x
pha
lda CallTableSBR_lo,x
pha
rts

CallTableSBR_lo .byte <(ena::sbr-1),<(enb::sbr-1)
CallTableSBR_hi .byte >(ena::sbr-1),>(enb::sbr-1)
less code, const dispatch time
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Can you store a scope/proc reference in a table?

Post by tokumaru »

bjones wrote: Sun Mar 19, 2023 3:58 pm

Code: Select all

.macro scopeCall typeid, sbr 

 lda  typeid
 
 cmp  #01
bne:+
  jsr ena::sbr
:

 cmp  #02
bne:+
  jsr enb::sbr
:

.endmacro

This is gonna get reaaaally slow after you've implemented dozens of objects... I though your goal was precisely to avoid large CMP chains. Jump tables are indeed much better in these situations.
bjones
Posts: 23
Joined: Mon Apr 29, 2019 4:34 pm

Re: Can you store a scope/proc reference in a table?

Post by bjones »

tokumaru wrote: Mon Mar 20, 2023 5:40 am
bjones wrote: Sun Mar 19, 2023 3:58 pm

Code: Select all

.macro scopeCall typeid, sbr 

 lda  typeid
 
 cmp  #01
bne:+
  jsr ena::sbr
:

 cmp  #02
bne:+
  jsr enb::sbr
:

.endmacro

This is gonna get reaaaally slow after you've implemented dozens of objects... I though your goal was precisely to avoid large CMP chains. Jump tables are indeed much better in these situations.
its actually not in many places and a total of 6 different eneamy types right now.

The main goal was to stream line having to manually add or take away enemies from multiple call lists. Human error and all that..
, but also I thought jump tables did not act as JSR just JMP? How would you retun to the loop?
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Can you store a scope/proc reference in a table?

Post by tokumaru »

bjones wrote: Mon Mar 20, 2023 7:48 amHow would you retun to the loop?
You JSR from where you want the return point to be to the code that will use the jump table (the code that Oziphantom posted).

You're not required to use the RTS trick for jump tables though... If you prefer, you can copy the address from the table to a temporary variable in RAM and do an indirect JMP (do use the exact addresses in the table if you do this - subtracting 1 is only for the RTS method). It's 1 cycle faster than the RTS way if you use zero page RAM.
Post Reply