Sonic and Sega Retro Message Board: The Official ASM Tips Thread - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
  • 2 Pages +
  • 1
  • 2
    Locked
    Locked Forum

The Official ASM Tips Thread

#1 User is offline Tweaker 

Posted 14 November 2005 - 03:26 PM

  • Posts: 12389
  • Joined: 27-June 04
  • Gender:Male
Post some handy ASM tips here for those just starting out, or beginners who could use a handy reference.
  • Remember to tab after each instruction. In addition to being proper, it'll prevent errors during the compiling process.
  • Comments need to be tabbed as well. This can cause serious errors if neglected.
  • Always try to use smaller instructions for byte based instructions. moveq, addq, subq, and tst are better than move, add, sub, and cmp.b #$0. In addition to saving a byte of space each in ROM, it'll shave a millisecond off your processing time. It may not seem like much, but every bit of time counts; You want to make the best of each instruction you write.
  • Always remember to use registers before using RAM. They're much faster, and good for storing quick reference addresses.
This is just a few, of course. I'll post more as I think of them.

#2 User is offline Ultima 

Posted 14 November 2005 - 03:28 PM

  • Games Publisher
  • Posts: 2394
  • Joined: 26-January 03
  • Gender:Male
  • Location:London, England
  • Project:Publishing mobile games!
Remember that it's procedural; if you don't interrupt it, it will go down your code. This is good for conditionals =P

#3 User is offline LOst 

Posted 14 November 2005 - 09:22 PM

  • Posts: 4879
  • Joined: 10-January 03
  • Gender:Male
  • Wiki edits:2
Avoid MUL and DIV instructions as much as possible. Do bit shifts when multiplying or dividing by the power of 2.

When using a word or long word index, use the ADD instruction to multiply the index instead of LSL or MUL instructions. This is the fastest way.
This post has been edited by LOst: 14 November 2005 - 09:25 PM

#4 User is offline LocalH 

Posted 16 November 2005 - 01:42 AM

  • roxoring your soxors
  • Posts: 3147
  • Joined: 11-January 03
  • Gender:Male
  • Location:wouldn't you like to know
  • Project:MDEM - Genesis programming stufz
  • Wiki edits:3
If you're going for an optimized cycle count, use precalced lookup tables instead of realtime calculation. It takes more memory, but it's much faster, especially with more complex math. Sinuses are excellent candidates for tables.

Always, always, ALWAYS hook your main display code into the Vint if your project is of a substantial size. This will ensure that your output is perfectly smooth. Vint hits at line $E0. If your code is small and only for testing a routine, then feel free to busywait. But know that, if you get too much code running in a frame, then you're bound to hit your display code late sooner or later. If you hook into Vint, then even if your main program loop takes a bit too long, then at least your display code will hit at line $E0 consistently.

Access to VDP RAM during the visible screen is extremely slow, whether you're using DMA or making the 68k do the dirty work - for example, while you can make 205 accesses to VDP RAM during Vblank, you can only make 20 accesses during active scan. Also note that VRAM accesses are byte-wide, while CRAM and VSRAM accesses are word-wide. If the screen is disabled via VDP register $02.6, then you can access VDP RAM like you would be able to during Vblank.
This post has been edited by LocalH: 16 November 2005 - 01:44 AM

#5 User is offline Quickman 

Posted 16 November 2005 - 02:55 AM

  • Posts: 5584
  • Joined: 03-December 03
  • Gender:Male
  • Location::x
  • Project:omg porjcet
  • Wiki edits:10
Sinuses?

Posted Image

I think you mean sine waves. If you're using precalculated sine tables remember that cosine is just sine of whatever you're looking for plus half-pi.

#6 User is offline LocalH 

Posted 16 November 2005 - 01:17 PM

  • roxoring your soxors
  • Posts: 3147
  • Joined: 11-January 03
  • Gender:Male
  • Location:wouldn't you like to know
  • Project:MDEM - Genesis programming stufz
  • Wiki edits:3
Well, I'm used to hearing them called sinuses or sinustables. Google for "sinustable" or "sinus generator" and you'll see I'm not the only one =P
This post has been edited by LocalH: 16 November 2005 - 01:19 PM

#7 User is offline Sonic Hachelle-Bee 

Posted 16 November 2005 - 02:50 PM

  • Lost in Wood zone
  • Posts: 716
  • Joined: 03-March 04
  • Gender:Male
  • Location:Paris, France
  • Project:Sonic 2 Long Version
- Learn how to use AND and OR properly. Some easy tricks with these ones can allow you to store several small counters in only one single data register, instead of RAM. Limit the use of the SWAP instruction: it's useful but you are easily and fastly lost in what you are doing. Then, to debug your program (if there is any problem), I say you "Good night"... XP

- Always cut your program in several small parts. Try to make a max use of offset indexes if you can, especially if your code can be executed on several frames.

- Never overwrite anything in RAM without being sure of what you are doing. Beware that some levels use several parts of the RAM that some others don't. A good way to have a large amount of RAM is to use the part where the level mappings are stored. If you are drawing yourself your level, and making the mapping yourself, you can easily keep some 16x16 or 128x128 tiles only for your ASM needs...

- Besides this, always store ALL registers into RAM before your main program (unless you are sure of what you are doing). The MOVEM instruction can be, for once, useful here. This ensures that you aren't erasing an important value that still in a register, and that can be used by the Sonic Engine, even far later your program. This also allow you to use all registers without any unexpected problems. Don't forget to retrieve all registers at the end.

- Limit the use of absolute pointers. Always use relative pointers when you can, so that you can copy and paste fastly your program everywhere in your ROM file, with a single hex editor.

- Be careful of your stack level (a7). The level of the stack should be the same at the start and at the end of your inserted ASM code.

- You can really "play" a bit with the stack, after all, it's only a pointer in RAM. You can for example, calculate "manually" an absolute address with the help of a condition, and write that address on the stack. Then, you can "RTS" your code to jump to different places, depending of the condition (others ways do the same thing)... You can also write that address at (a7) plus one long, by accessing the RAM directly, overwriting the last long pushed on the stack, or simply updating it a bit... It all depends of the effect you want to do.
This post has been edited by Sonic Hachelle-Bee: 16 November 2005 - 03:17 PM

#8 User is offline Aurochs 

Posted 16 November 2005 - 04:38 PM

  • Единый, могучий Советский Союз!
  • Posts: 2343
  • Joined: 09-January 05
  • Gender:Male
  • Project:Whatever catches my fancy
  • Wiki edits:325
Since the 68000 doesn't have any push or pop instructions, you'll have to use the move instruction with predecrement for pushing and move with postincerment for popping. Saving and retreiving the registers, for example, should be done by:
movem.l d0-a6,-(sp)
movem.l (sp)+,d0-a6

(I've never used the movem instruction before, so the list syntax may not be accurate...)

EDIT: Oops, fixed destination error.
This post has been edited by Aurochs: 16 November 2005 - 06:17 PM

#9 User is offline Sonic Hachelle-Bee 

Posted 16 November 2005 - 06:13 PM

  • Lost in Wood zone
  • Posts: 716
  • Joined: 03-March 04
  • Gender:Male
  • Location:Paris, France
  • Project:Sonic 2 Long Version
Aurochs>
This instruction is invalid: MOVEM.L d0/a6,(a7)+
As well as a similar one: MOVEM.L -(a7),d0/a6

"68k guide" said:

In the case that the register list is the destination, register indirect with predecrement is not a valid source mode. If the register list is the source, then the destination may not be register indirect with postincrement.


The registers are stored in consecutive memory locations at the specified address. For example, a valid instruction is this one:
MOVEM.L d0/d1/a6,(a2)
This post has been edited by Sonic Hachelle-Bee: 16 November 2005 - 06:14 PM

#10 User is offline Quickman 

Posted 16 November 2005 - 06:37 PM

  • Posts: 5584
  • Joined: 03-December 03
  • Gender:Male
  • Location::x
  • Project:omg porjcet
  • Wiki edits:10
But the stack pointer automatically updates after each access, so my understanding is that you'd space them out too much. In any case the real thing uses the predecrement and postincrement opmodes so that's what is correct.
This post has been edited by Quick Man: 16 November 2005 - 06:37 PM

#11 User is offline Sonic Hachelle-Bee 

Posted 17 November 2005 - 02:36 AM

  • Lost in Wood zone
  • Posts: 716
  • Joined: 03-March 04
  • Gender:Male
  • Location:Paris, France
  • Project:Sonic 2 Long Version

Quote

But the stack pointer automatically updates after each access

No... Address register a7 is just like the others address registers. It's only especially used to simulate a stack, nothing more. That's why I prefer speaking about a7 rather than sp, which refers to exactly the same thing.

#12 User is offline Aurochs 

Posted 21 November 2005 - 03:04 PM

  • Единый, могучий Советский Союз!
  • Posts: 2343
  • Joined: 09-January 05
  • Gender:Male
  • Project:Whatever catches my fancy
  • Wiki edits:325
The stack can be used quite effectively to make local variables. This isn't as necessary on the 68000 due to the large number of registers, but if you have a lot of stuff to keep track of, you can make a stack frame for it. You do that by:
  • Copying the current stack pointer to another address register (this will be your base)
  • Subtracting the necessary number of bytes from the stack pointer
  • Using the base and a negative index to reference your variables
  • When you're ready to return or discard your variables, move the base back into the stack pointer
You can also pass variables between functions with the same method. Again, only do that if you have a lot of variables to pass, and make sure to keep the base in an address register.

#13 User is offline LOst 

Posted 21 November 2005 - 10:27 PM

  • Posts: 4879
  • Joined: 10-January 03
  • Gender:Male
  • Wiki edits:2

Aurochs, on Nov 21 2005, 11:04 PM, said:

The stack can be used quite effectively to make local variables. This isn't as necessary on the 68000 due to the large number of registers, but if you have a lot of stuff to keep track of, you can make a stack frame for it. You do that by:
  • Copying the current stack pointer to another address register (this will be your base)
  • Subtracting the necessary number of bytes from the stack pointer
  • Using the base and a negative index to reference your variables
  • When you're ready to return or discard your variables, move the base back into the stack pointer
You can also pass variables between functions with the same method. Again, only do that if you have a lot of variables to pass, and make sure to keep the base in an address register.

This is waht C++ do on Intel processors.

#14 User is offline Aurochs 

Posted 21 November 2005 - 10:29 PM

  • Единый, могучий Советский Союз!
  • Posts: 2343
  • Joined: 09-January 05
  • Gender:Male
  • Project:Whatever catches my fancy
  • Wiki edits:325

LOst, on Nov 21 2005, 11:27 PM, said:

This is waht C++ do on Intel processors.

Where do you think I learned it? =P

Actually, Pascal does this too. I can't vouch for other languages, though.

#15 User is offline LOst 

Posted 21 November 2005 - 10:34 PM

  • Posts: 4879
  • Joined: 10-January 03
  • Gender:Male
  • Wiki edits:2

Aurochs, on Nov 22 2005, 06:29 AM, said:

LOst, on Nov 21 2005, 11:27 PM, said:

This is waht C++ do on Intel processors.

Where do you think I learned it? =P

Actually, Pascal does this too. I can't vouch for other languages, though.

Like you said, 68k processors has a lot of data registers already. The base pointer is a register on the Intel 80x86 processors because there are only 4 16 bit (8 bit bus) registers to work with. Remember that accessing the stack is much slower than having the values in a register. I don't think emulating the base pointer behaivour is a good advice when you have six to seven 32 bit registers to play with.

  • 2 Pages +
  • 1
  • 2
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users