Obligatory newbie questions

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
tokumaru
Posts: 11749
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Mon Jun 13, 2011 9:35 pm

Bellum wrote:or should I be using jumping to a "subroutine" instead?
In my opinion it makes more sense to have a subroutine that writes strings rather than a macro, but both should work. The code you posted takes around 18 bytes, which means that for each string you print you are wasting 18 bytes (in the case of a small string like "hello word" the printing code is larger than the string itself!). As a subroutine the code would be a bit larger (because you'd have to process the arguments), but the same code would be used for ALL strings.

Bellum
Posts: 17
Joined: Sat Jun 04, 2011 8:04 pm

Post by Bellum » Mon Jun 13, 2011 9:42 pm

Woo, it worked! Sort of. The second time it looped infinitely for some reason and started storing garbage, so I'll have to work that out. :)
tokumaru wrote:
Bellum wrote:or should I be using jumping to a "subroutine" instead?
In my opinion it makes more sense to have a subroutine that writes strings rather than a macro, but both should work. The code you posted takes around 18 bytes, which means that for each string you print you are wasting 18 bytes (in the case of a small string like "hello word" the printing code is larger than the string itself!). As a subroutine the code would be a bit larger (because you'd have to process the arguments), but the same code would be used for ALL strings.
That makes a lot of sense. What sort of thing would macros be better used for?

User avatar
tokumaru
Posts: 11749
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Mon Jun 13, 2011 10:00 pm

Bellum wrote:What sort of thing would macros be better used for?
Hum... the most obvious I can think of are 16-bit math operations, because we need them often and they are so small that a subroutine would offer little (if any) gain of ROM space and would be much slower. Another thing I can think of are mapper writes, if they are short enough.

I don't see much sense in having large macros, unless they are meant to be used across different programs. If a piece of code is reasonably large and you have to use it in several places of the same program, it makes more sense to use a subroutine.

Bellum
Posts: 17
Joined: Sat Jun 04, 2011 8:04 pm

Post by Bellum » Mon Jun 13, 2011 10:05 pm

a subroutine would offer little (if any) gain of ROM space and would be much slower.
Are JMP statements particularly slow?

Shiru
Posts: 1161
Joined: Sat Jan 23, 2010 11:41 pm

Post by Shiru » Mon Jun 13, 2011 10:07 pm

Macros are needed when speed is imporant. Say, you have code like this:

Code: Select all

loop
 jsr a short subroutine
 ..
 jsr a short subroutine again
 ..

 go loop
If there is not much code in the loop and the subroutine, you can spend much time on jsr/rts. If you replace the subroutine with a macro, you'll save this time. It could be important for VRAM update code, when you have to fit many things into ~2200 CPU clocks, for example. One subroutine call is 12 extra clocks, one macro usage is 0 extra clocks, in exchange for larger code size.

User avatar
Kasumi
Posts: 1292
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi » Mon Jun 13, 2011 10:40 pm

Bellum wrote: Are JMP statements particularly slow?
Go here: http://www.obelisk.demon.co.uk/6502/reference.html

It has the cycle counts for every instruction. jmp is fairly fast at 3 cycles. The fastest instructions take 2 cycles. The slowest instructions take 7.

Both jsr and rts are 6 cycles which means every normal subroutine call* will take at least 12 cycles.

For reference, I believe an NTSC NES' frame is 29830 CPU cycles long.

*i.e. one that doesn't pull the rts location from the stack and return some different way or something crazy.

User avatar
Memblers
Site Admin
Posts: 3857
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers » Mon Jun 13, 2011 10:55 pm

Of course, a macro can also be handy to set things up for the JSR, with less typing.

Code: Select all

.macro writestring addr
  lda #<addr
  sta vram_addr_lo
  lda #>addr
  sta vram_addr_hi
  jsr string
.endmacro
And I use one like this all the time:

Code: Select all

.macro pointer addr1_zp,addr2
  lda #<addr2
  sta addr1_zp
  lda #>addr2
  sta addr1_zp+1
.endmacro
Using macros inside of macros can be fun too. :)

Code: Select all

.macro writestring addr
  pointer vram_addr_lo,addr 
  jsr string
.endmacro
more examples of what I thought macros were useful for, in general use:
http://www.parodius.com/~memblers/nes/macros.s
(the controller one is probably my favorite for making my programs readable)

User avatar
tokumaru
Posts: 11749
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Tue Jun 14, 2011 9:09 am

Bellum wrote:Are JMP statements particularly slow?
JMP (3 cycles) isn't slow, but JSR (6 cycles) is. JMP is not used for subroutines, because it doesn't save the return address. JSR saves the return address, so that you can RTS (also takes 6 cycles) when the subroutine is done. Since it takes 12 cycles to get in and out of a subroutine, it doesn't make sense to use one for very small and quick tasks.

Bellum
Posts: 17
Joined: Sat Jun 04, 2011 8:04 pm

Post by Bellum » Tue Jun 14, 2011 1:13 pm

Thanks, all. That clears up a lot. :)

Post Reply