don't click here

The Official ASM Tips Thread

Discussion in 'Engineering & Reverse Engineering' started by Tweaker, Nov 14, 2005.

Thread Status:
Not open for further replies.
  1. Tweaker

    Tweaker

    Banned
    12,387
    3
    0
    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. Ultima

    Ultima

    Games Publisher Tech Member
    2,398
    1
    18
    London, England
    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. LOst

    LOst

    Tech Member
    4,891
    8
    18
    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.
     
  4. LocalH

    LocalH

    roxoring your soxors Tech Member
    3,314
    37
    28
    Nunya
    Rock Band 3 Deluxe
    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.
     
  5. Quickman

    Quickman

    be attitude for gains Tech Member
    5,595
    18
    18
    :x
    omg porjcet
    Sinuses?

    [​IMG]

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

    LocalH

    roxoring your soxors Tech Member
    3,314
    37
    28
    Nunya
    Rock Band 3 Deluxe
    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
     
  7. Sonic Hachelle-Bee

    Sonic Hachelle-Bee

    Taking a Sand Shower Tech Member
    821
    218
    43
    Lyon, France
    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.
     
  8. Aurochs

    Aurochs

    Единый, могучий Советский Союз! Tech Member
    2,343
    0
    0
    Whatever catches my fancy
    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:
    Code (Text):
    1. movem.l d0-a6,-(sp)
    2. 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.
     
  9. Sonic Hachelle-Bee

    Sonic Hachelle-Bee

    Taking a Sand Shower Tech Member
    821
    218
    43
    Lyon, France
    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

    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)
     
  10. Quickman

    Quickman

    be attitude for gains Tech Member
    5,595
    18
    18
    :x
    omg porjcet
    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.
     
  11. Sonic Hachelle-Bee

    Sonic Hachelle-Bee

    Taking a Sand Shower Tech Member
    821
    218
    43
    Lyon, France
    Sonic 2 Long Version
    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. Aurochs

    Aurochs

    Единый, могучий Советский Союз! Tech Member
    2,343
    0
    0
    Whatever catches my fancy
    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:
    1. Copying the current stack pointer to another address register (this will be your base)
    2. Subtracting the necessary number of bytes from the stack pointer
    3. Using the base and a negative index to reference your variables
    4. 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. LOst

    LOst

    Tech Member
    4,891
    8
    18
    This is waht C++ do on Intel processors.
     
  14. Aurochs

    Aurochs

    Единый, могучий Советский Союз! Tech Member
    2,343
    0
    0
    Whatever catches my fancy
    Where do you think I learned it? =P

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

    LOst

    Tech Member
    4,891
    8
    18
    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.
     
  16. Aurochs

    Aurochs

    Единый, могучий Советский Союз! Tech Member
    2,343
    0
    0
    Whatever catches my fancy
    On the 68k, it usually isn't. Like I said, you should only use it if you have to keep track of a lot of data and you can't think of a way to simplify the algorithm so that you don't have to use main memory.
     
  17. LOst

    LOst

    Tech Member
    4,891
    8
    18
    The stack is main memory. You can simply just emulate D0 - D7 directly in main RAM accessing them with an address register. You get the same speed out of it. Base pointer is more of a dynamic function argument C++ way.

    I rather have a function taking arguments as registers rather than saving them on the stack, then copy a pointer, putting them back into a register for calculations during the function, and at last restoring the stack. Wow this was not really a shortcut or a tip was it?

    And sorry for sounding so hard.
     
  18. Aurochs

    Aurochs

    Единый, могучий Советский Союз! Tech Member
    2,343
    0
    0
    Whatever catches my fancy
    You do realize we're arguing on the same side here? =P
     
  19. LOst

    LOst

    Tech Member
    4,891
    8
    18
    Yea
     
  20. Tweaker

    Tweaker

    Banned
    12,387
    3
    0
    (drums)
     
Thread Status:
Not open for further replies.