don't click here

Basic Questions & Answers thread

Discussion in 'Engineering & Reverse Engineering' started by Tweaker, May 29, 2008.

  1. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber

    I believe it's to see what tiles are which plane. If it's highlighted, it's a high plane. If shadowed, it's a low plane. High planes go over Sonic and low planes go behind Sonic.

    I also beleive some games use it to get a few more colours for certain parts of the level.


    EDIT: Quoted post due to page break.
     
  2. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,201
    431
    63
    Japan
    Shadow & Highlight is a function of the hardware which can be enabled by VDP register 0x0C (0x8C), setting the 3rd bit:

    Code (ASM):
    1.         move.w  #$8C00|%????1???,($C00004).l
    I'd go into details, but these links are relevant enough to explain what you need to know:

    http://forums.sonicretro.org/index.php?showtopic=15628
    http://forums.sonicretro.org/index.php?showtopic=29603
     
  3. Jimmy Hedgehog

    Jimmy Hedgehog

    Member
    1,728
    8
    18
    England - Slough
    Getting the motivation to continue old projects
    Kinda stuck here. I'm not quite sure how to go about this properly. I've replaced the "S" in score's tiles with the "0" so now it shows that when I'm using the "S"'s place, like so:

    Code (ASM):
    1.         dc.b $90, $01, $80, 0, $20
    And a shot of that art showing in-game:

    [​IMG]

    However, I'm wondering how I would go about making that extra digit in the HUD actually update when the timer gets to 10+ minutes, rather than staying as a static 0. I for some reason get the feeling that I can't using the art tile from the compressed "hud" file and will need to find the VRAM elsewhere, but I was wondering anyway because while that "0" being functional isn't necessarily ESSENTIAL, (I could just have it there for visual reasons), it'd be great if I could get it working rather than being a "dummy digit" so to speak.
     
  4. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,201
    431
    63
    Japan
    Luckily for you, most of the coding is done:

    Code (Text):
    1. loc_1C734:
    2.         move.l  #$5E400003,d0
    3.         moveq   #0,d1
    4.         move.b  ($FFFFFE23).w,d1 ; load minutes
    5.         bsr.w   Hud_Mins
    6.         move.l  #$5EC00003,d0
    7.         moveq   #0,d1
    8.         move.b  ($FFFFFE24).w,d1 ; load seconds
    9.         bsr.w   Hud_Secs
    As you can see, each subroutine being called requires two inputs:

    1. A VRAM write address value in d0
    2. The counter (I.e. your 10 minute digit) in d1
    "Hud_Mins" and "Hud_Secs" are inaccurate as names:

    • "Hud_Mins" will write one double cell digit in decimal, to a VRAM address, and if that digit is 0, it will draw digit 0 art instead of blank like it does for rings/score.
    • "Hud_Secs" will write two double cell digits in decimal, to a VRAM address, and if any digits are 0, it will draw digit 0 art instead of blank like it does for rings/score.
    With this in mind, you may find that changing "Hud_Mins" in that routine above to "Hud_Secs" will write two digits out of the minute value, instead of one, however, it will NOT fit in the same VRAM space, you will need to move it to another location, you will need to decide where in VRAM you want to write this double digit to (4 cells/tiles), and change:

    Code (ASM):
    1.         move.l  #$5E400003,d0
    2.         moveq   #0,d1
    3.         move.b  ($FFFFFE23).w,d1 ; load minutes
    4.         bsr.w   Hud_Mins
    Into:

    Code (ASM):
    1.         move.l  #$VVVVVVVV,d0
    2.         moveq   #0,d1
    3.         move.b  ($FFFFFE23).w,d1 ; load minutes
    4.         bsr.w   Hud_Secs
    Where "VVVVVVVV" is your new VRAM write address value, to set this, you will need to have a VRAM address, I'll use 0xF020 as an example, break it up into bits:

    Code (Text):
    1. 1111 0000 0010 0000
    Take the two most significant bits (the two bits on the far left) and bring them over to the far right in long-word):

    Code (Text):
    1. ??11 0000 0010 0000 ???? ???? ???? ??11
    To set as VRAM write, the two most significant bits need to be set as 01, and bits 4 and 5 need to be set as 00:

    Code (Text):
    1. 0111 0000 0010 0000 ???? ???? ??00 ??11
    The DMA bits need to be off (set as 0, bits 6 and 7):

    Code (Text):
    1. 0111 0000 0010 0000 ???? ???? 0000 ??11
    And the rest are unknown/unused, and so are to be set as 0:

    Code (Text):
    1. 0111 0000 0010 0000 0000 0000 0000 0011
    Convert to hexadecimal gives you 0x70200003, and that will be the value to be written into d0, the subroutine "Hud_Secs" will write the minute digits to VRAM address 0xF020+ (Obviously you will need a different VRAM address). Due to this, you will need to change the sprites, because the minute digits need to be together (as part of the hex to decimal conversion), you need to split the seconds and minutes as seperate sprites, you currently should have:

    Code (ASM):
    1. byte_1C5BC:     dc.b $B
    2.                 dc.b $80, $D, $80, 0, 0
    3.                 dc.b $80, $D, $80, $18, $20
    4.                 dc.b $80, $D, $80, $20, $40
    5.                 dc.b $90, $D, $80, $10, 0
    6.                 dc.b $90, $D, $80, $28, $28
    7.                 dc.b $A0, $D, $80, 8, 0
    8.                 dc.b $A0, 1, $80, 0, $20
    9.                 dc.b $A0, 9, $80, $30, $30
    10.                 dc.b $40, 5, $81, $A, 0
    11.                 dc.b $40, $D, $81, $E, $10
    12.                 dc.b $90, $01, $80, 0, $20
    You will need it to be changed to:

    Code (ASM):
    1. byte_1C5BC:     dc.b $B
    2.                 dc.b $80, $D, $80, 0, 0
    3.                 dc.b $80, $D, $80, $18, $20
    4.                 dc.b $80, $D, $80, $20, $40
    5.                 dc.b $90, $D, $80, $10, 0
    6.                 dc.b $90, $9, $80, $2A, $30     ; <- This no longer displays the 1 minute counter, only the seconds
    7.                 dc.b $A0, $D, $80, 8, 0
    8.                 dc.b $A0, 1, $80, 0, $20
    9.                 dc.b $A0, 9, $80, $30, $30
    10.                 dc.b $40, 5, $81, $A, 0
    11.                 dc.b $40, $D, $81, $E, $10
    12.                 dc.b $90, $05, $VV, $VV, $20        ; <- This displays both minuts (10 and 1 digits) together
    Again, I've used VVVV because you need to decide on a VRAM address, find a free VRAM space of about 4 cells/tiles and you'll be laughing.
     
  5. Jimmy Hedgehog

    Jimmy Hedgehog

    Member
    1,728
    8
    18
    England - Slough
    Getting the motivation to continue old projects
    That makes a lot of sense actually. And realising I can do those conversions in calculator and noting things down makes it quite a neat process too. So let's say for experimentation's sake I was to use the 4 tiles from the "$80, 0" I was using before (so it'd overwrite both where S and C were now), would I do that conversion from "8000", breaking that into bits and going along the process, or is there another process beforehand? Just wanna make sure I fully understand what it is I'm doing XD
     
  6. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,742
    338
    63
    SonLVL
    This page can automatically convert VRAM addresses to VDP commands.
     
  7. Jimmy Hedgehog

    Jimmy Hedgehog

    Member
    1,728
    8
    18
    England - Slough
    Getting the motivation to continue old projects
    So would I input just "800" there, since it's laid out "$80, 0" in the mappings? Or is there some sort of difference between how it's shown in the hud mappings and the actual VRAM address itself? Also I've experimented with other VRAM addresses for the sake of seeing it in action. Used the Score numbers' address and the minutes counted up at the start of the score. However, while the seconds went on to 0 each time after 59 seconds past the 10 minute mark, the minutes counter itself stopped at 9, despite changing the branch from hud_mins to hud_secs.
     
  8. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,742
    338
    63
    SonLVL
    There is a difference, what you see in the mappings is actually more than just a VRAM address, it includes the palette number, x flip, y flip and priority flags. In this case, $80, 0 becomes the two byte value $8000, which is tile 0 with the priority bit set (see here for more details).
     
  9. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,201
    431
    63
    Japan
    Pretty much what MainMemory said.

    Technically it's 8000, as each byte in the list contains two digits, I.e. it should really be $80,$00, but of course, due to laziness, programmers do not care to fill in those digits and leave the assembler to do it for them, and the team who wrote the disassembler set up their disassembler with this laziness in mind, I find it stupid myself as it can cause a lot of confusion, but whatever floats their boat...

    You might find this usful:

    Code (Text):
    1. dc.b $90, $05, ($VVVV>>$0D)|$80, ($VVVV>>$05), $20
    Where VVVV is the VRAM address in raw style, I.e. if I were to use VRAM address 0xF020 as an example again, I'd put:

    Code (Text):
    1. dc.b $90, $05, ($F020>>$0D)|$80, ($F020>>$05), $20
    It will automatically arrange the address for you.

    As for why the time stops at 09:59, that may have something to do with the routine at "Hud_ChkTime:"

    Code (ASM):
    1.         lea ($FFFFFE22).w,a1
    2.         cmpi.l  #$93B3B,(a1)+   ; is the time 9.59?
    3.         beq.s   TimeOver    ; if yes, branch
    4.         addq.b  #1,-(a1)
    5.         cmpi.b  #60,(a1)
    6.         bcs.s   Hud_ChkLives
    7.         move.b  #0,(a1)
    8.         addq.b  #1,-(a1)
    9.         cmpi.b  #60,(a1)
    10.         bcs.s   loc_1C734
    11.         move.b  #0,(a1)
    12.         addq.b  #1,-(a1)
    13.         cmpi.b  #9,(a1)
    14.         bcs.s   loc_1C734
    15.         move.b  #9,(a1)
    Assuming you haven't made changes that we're unaware of.

    I apologise if anything above is incorrect, I couldn't concentrate with that halloween shit going on in the background, many times I had to stop and wait...
     
  10. Jimmy Hedgehog

    Jimmy Hedgehog

    Member
    1,728
    8
    18
    England - Slough
    Getting the motivation to continue old projects
    I've not tried the stuff above it yet and I'll update based on what happens, but in that "Hud_ChkTime:" routine I noticed the 9:59 thing, and bumped the "93B3B" to something like "E3B3B" to see if it'd go higher. Guessing I need to change those 9s at the lower part to a higher number too?

    EDIT: Right, so I realised since I have the points numbers object not in use, I could use that VRAM right? From the object pointers file I found the address was $F2E0, which when I put it in the mappings in the format the rest are, it'd be split to "$F2, $E0", am I right so far?

    Well anyways, using the formula you supplied I gathered that F2E0, after breaking it up and converting it becomes "72E00003". So I input that in the routine, and I end up with...Green Hill Zone tiles?

    [​IMG]
     
  11. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,201
    431
    63
    Japan
    The "72E00003" part is correct, you have that part right, but the sprite VRAM address "$F2, $E0" you have wrong, as MainMemory and I explained above.

    Instead of using "$F2, $E0", use "$87, $97" or use "($F2E0>>$0D)|$80, ($F2E0>>$05)".

    For 8797, the 797 is created by dividing F2E0 by 20 (in hexadecimal), and the 8 in bits 1000, is to set it as high plane (I.e. in front of everything else), again, see MainMemory's post for details.
     
  12. MainMemory

    MainMemory

    Kate the Wolf Tech Member
    4,742
    338
    63
    SonLVL
    Correct me if I'm wrong, but... aren't the art tiles in the HUD mappings relative to the start of the HUD's art? In that case, if you want to use tiles at $VVVV, you would have to put in ($VVVV-$WWWW), where $WWWW is the starting art block/art tile for the HUD object.
     
  13. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,201
    431
    63
    Japan
    As a matter of fact, yes, you're right, so that would be...

    F2E0 - D940 = 19A0 / 20 = CD

    So use "$80, $CD" or "(($F2E0-$D940)>>$0D)|$80, ($F2E0-$D940)>>$05)"
     
  14. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Can someone tell me the execution time in n(r/w) for the Push Effective Address (pea) if I used it in this sense:

    Code (ASM):
    1.     pea DisplaySprite
    2.     bra.w   LoadSonicDynPLC

    Cheers.
     
  15. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    The assembler may treat this as a word-sized absolute address or a long-sized absolute address, depending on where DisplaySprite is on the binary (before $8000 or in RAM it can be word-sized, otherwise it will be long-sized) and if the assembler decides to use word or long. So it may be 16(2/2) or 20(3/2).
     
  16. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,201
    431
    63
    Japan
    That entirely depends on the distance/location of "DisplaySprite", if for example, "DisplaySprite" is in the memory location between FFFF8000 and 00008000, then sign-extention can be used:

    Code (Text):
    1.         pea (Location02).w          ; 16
    2.         bra.w   Location01          ; 10
    VS

    Code (Text):
    1.         jsr (Location01).w          ; 18
    2.         bra.w   Location02          ; 10
    Note that bsr and jsr (pc) are the same in processing time and size, so regardless, the former would be quickest, thereas, if the address is not sign-extendable, and isn't close enough to be branched to via bsr or jsr (pc):

    Code (Text):
    1.         pea (Location02).l          ; 20
    2.         bra.w   Location01          ; 10
    VS

    Code (Text):
    1.         jsr (Location01).l          ; 20
    2.         bra.w   Location02          ; 10
    You would get the exact same time, thereas, if the address IS close enough to be branched to via bsr or jsr (pc):

    Code (Text):
    1.         pea (Location02).l          ; 20
    2.         bra.w   Location01          ; 10
    VS

    Code (Text):
    1.         jsr Location01(pc)          ; 18
    2.         bra.w   Location02          ; 10
    To note again, bsr and jsr (pc) are the same in processing time and size, so regardless, the latter would be the quickest.

    So, if the address is between FFFF8000 and 00008000, use the "pea" method for quickest processing time, if the address is not between FFFF8000 and 00008000 but is close enough for a relative branch/jump, then do not use the "pea" method, if the address is not between FFFF8000 and 00008000 and is not close enough for a relative branch/jump, then it does not matter which one you choose in terms of processing time.
     
  17. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Nicely detailed, great help, cheers mate.
     
  18. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    I'm going to sound like a right idiot, but

    Code (ASM):
    1.     pea (label).w
    Is never allowed, no matter how close or far the label is.


    Code (ASM):
    1.     pea (label).l
    is always allowed. Funny, I found the execution times for it on google:


    [​IMG]

    So (label).w is allowed. Have I missed the point anywhere?





    Anyway, I have tried this:

    Code (ASM):
    1.     pea DisplaySprite(pc)
    And this works. But only if close enough. So I am guessing, if the above command works, use it, otherwise, stick with bsr.w (or jsr[pc])?
     
  19. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,201
    431
    63
    Japan
    Please read carefully, I stated clearly that the address needs to be in the memory space ranging from FFFF8000 to 00008000 for the assembler to assemble as sign-extended, from a Mega Drive's point of view, that would be 00000000 up to 00008000 (00007FFF) on the Mega Drive ROM space, or FFFF8000 up to 00000000 (FFFFFFFF), where the Mega Drive will only read 24-bits of the address making it 00FF8000 - 01000000 (00FFFFFF) which would be the RAM space, if your location is not addressed in those spaces, you cannot use sign-extention.

    pea (pc) I had completely forgotten about, that would give you 16 cycles, that changes things a bit, lemmy rewrite:

    So, if the address is between FFFF8000 and 00008000, or if it is close enough for a relative branch/jump, then use the "pea" method for quickest processing time, if the address is not between FFFF8000 and 00008000 and is not close enough for a relative branch/jump, then it does not matter which one you choose in terms of processing time.
     
  20. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    10
    18
    United Kingdom
    YouTuber
    Sorry, I did mis-read at first. Thanks for clearing that up. I was bored yesterday and saw the "pea" command and decided to learn on it, just needed some things clearing up. Thanks for your assistance =)