My first ASM (that works)

Go down

My first ASM (that works) Empty My first ASM (that works)

Post by Puzzledude Sun 26 Feb 2017 - 12:26

With some help of one of the Euclid's info documents I was able to make an ASM which actually works:
note Parallel Worlds and Conker hack are doing a similar thing, with the same result, however both of those hacks are using a different code (specially Conker) and a different hook location:

The code in question exploits the secondary entrances: which is suitable for a 7 crystal barrier or other barriers. Here's what I've made:

long jump version, 3 entrances with 3 different conditions (1 for each)
DBD5F:
BF 73 BB 1B 8D 0E 01-->
22 00 80 2A EA EA EA
(jump to 2A 80 00= 150000)

Hook is now 4 bytes earlier from what Euclid made, and now with the long jump instead of his short jump:
Conker made the same hook later, at byte 64, which is just after the store to 010E.

Code:
at 150000:
BF 73 BB 1B , repeat code
8D 0E 01    , repeat code
C9 03       , compare entrances to entrance 03 (Castle left)
F0 09       , branch $09 bytes if equal= to crystal check
C9 04       , if not equal, go to next compare= 04 (Castle center down)
F0 14       , branch $14 bytes if equal= to mirror check
C9 05       , if not equal, go to next compare= 05 (Castle right)
F0 1F       , branch 1F bytes if equal= to sword-4 check
6B          , if all compares are not equal, then return (and do nothing)
AF 7A F3 7E , crystal check
C9 7F       , check if all 7
F0 01       , branch 01 byte if equal
6B          , if not equal, return
A9 08       , if equal load entr 08 (east palace)
8D 0E 01    , store entr 08
6B          , return
AF 53 F3 7E , mirror check
C9 02       , check if you have mirror
F0 01       , branch 01 byte if equal
6B          , if not equal, return
A9 09       , if equal load entr 09 (desert palace)
8D 0E 01    , store entr 09
6B          , return
AF 59 F3 7E , sword-4 check
C9 04       , check if sword is 04
F0 01       , branch 01 byte if equal
6B          , if not equal, return
A9 33       , if equal load entr 33 (tower of hera)
8D 0E 01    , store entr 33
6B          , return


thus:
BF 73 BB 1B 8D 0E 01 C9 03 F0 09 C9 04 F0 14 C9 05 F0 1F 6B AF 7A F3 7E C9 7F F0 01 6B A9 08 8D 0E 01 6B AF 53 F3 7E C9 02 F0 01 6B A9 09 8D 0E 01 6B AF 59 F3 7E C9 04 F0 01 6B A9 33 8D 0E 01 6B


tested (works)

-----

effect of the upper code is thus:
entrances:
03 (castle left),
04 (castle center down),
05 (castle right)

will change to:

08 (east palace)= if you have 7 crystals (ie crystal barrier)
09 (desert palace)= if you have the mirror (ie mirror barrier)
33 (tower of hera)= if you have sword-4 (ie sword-4 barrier)

So if 08, 09 and 33 are not placed on the overworld, we have now achieved the 7 crystal barrier entrance, as well as another entrance which needs the mirror (or any other thing) and the third one needs the sword-4.
Puzzledude
Puzzledude

My first ASM (that works) Image213

Since : 2012-06-20

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Erockbrox Sun 26 Feb 2017 - 15:39

Were are all of the opcodes? It seems that you wrote this in little endian?
Erockbrox
Erockbrox

My first ASM (that works) Image211

Since : 2013-02-05

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Puzzledude Sun 26 Feb 2017 - 15:53

Erockbrox wrote:Were are all of the opcodes? It seems that you wrote this in little endian?
I already assigned the Opcodes as bytes, since this is how I see it.
So the opcodes are these:
BF= LDA long,X (load into accumulator)
8D= STA (store, absolute)
C9= CMP (compare, immediate)
F0= BEQ (branch if equal)
AF= LDA absolute long (load into accumulator)
6B= RTL (return)

each line starts with an opcode.


So basically it is already assembled for the CPU to understand.
Addresses are thus written in little endian.

Like this:
AF 7A F3 7E
converts/same as LDA $7EF37A.
Puzzledude
Puzzledude

My first ASM (that works) Image213

Since : 2012-06-20

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Conn Sun 26 Feb 2017 - 16:44

Congrats Puzz, I see you become the next zeldix great coder Very Happy

Your method is like mine, quick&dirty Wink better is to make yourself familiar with xkas compiling and writing asm files for it to generate clean, well documented code.
It has also many advantages, like instead counting the bytes like F0 14 you can simple write
BEQ loop
*14 bytes code here
loop:
the branched code here
This makes things much easier if you want to correct some stuff and other people have less problems to read your code.

However, knowing the opcode mechanics is always great! And as said, I mostly also write directly the hex in the rom as it is way faster Razz
Conn
Conn

My first ASM (that works) Image212

Since : 2013-06-30

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Puzzledude Sun 26 Feb 2017 - 18:55

better is to make yourself familiar with xkas compiling and writing asm files for it to generate clean, well documented code.
It has also many advantages, like instead counting the bytes like F0 14 you can simple write
BEQ loop
*14 bytes code here
loop:
the branched code here
This makes things much easier if you want to correct some stuff and other people have less problems to read your code.
Yes, I had to calculate each branch manually and count the bytes. The intended way is much more logical.

However, knowing the opcode mechanics is always great! And as said, I mostly also write directly the hex in the rom as it is way faster
Like said, if the code would be written the proper way, the assembler should be giving out the same thing. But I suspect that there might be some minor differences in more complex codes.

Your method is like mine, quick&dirty
Indeed, that's why I tested it, and it works, so... I had some initial attempts which crashed the game though, or simply didn't work.
I wonder what the assembler would be giving out, if this was written the attended way - I'm assuming it should be the same.
Puzzledude
Puzzledude

My first ASM (that works) Image213

Since : 2012-06-20

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Conn Sun 26 Feb 2017 - 19:25

I wonder what the assembler would be giving out, if this was written the attended way - I'm assuming it should be the same.

You can try Razz
Code:

;@xkas
; first asm by Puzz

lorom

org $1BBD5F; pc DBD5F
JSL $2A8000; BF 73 BB 1B 8D 0E 01--> 22 00 80 2A
NOP ;EA
NOP ;EA
NOP ;EA

org $2A8000 ; at pc 150000?
LDA $1bbb73,x ; BF 73 BB 1B , repeat code
STA $010e; 8D 0E 01    , repeat code
CMP #$03; C9 03       , compare entrances to entrance 03 (Castle left)
BEQ branch1  ;F0 09       , branch $09 bytes if equal= to crystal check
CMP #$04; C9 04       , if not equal, go to next compare= 04 (Castle center down)
BEQ branch2 ; F0 14       , branch $14 bytes if equal= to mirror check
CMP #$05; C9 05       , if not equal, go to next compare= 05 (Castle right)
BEQ branch3 ; F0 1F       , branch 1F bytes if equal= to sword-4 check
RTL ; 6B          , if all compares are not equal, then return (and do nothing)
branch1:
LDA $7EF37A ;AF 7A F3 7E , crystal check
CMP #$7F ;C9 7F       , check if all 7
BEQ $01 ; F0 01       , branch 01 byte if equal
RTL; 6B          , if not equal, return
LDA #$08; A9 08       , if equal load entr 08 (east palace)
STA $010e; 8D 0E 01    , store entr 08
RTL; 6B          , return
branch2:
LDA $7EF353; AF 53 F3 7E , mirror check
CMP #$02 ; C9 02       , check if you have mirror
BEQ $01; F0 01       , branch 01 byte if equal
RTL ; 6B          , if not equal, return
LDA #$09; A9 09       , if equal load entr 09 (desert palace)
STA $010e ; 8D 0E 01    , store entr 09
RTL ; 6B          , return
branch3:
LDA $7EF359 ;AF 59 F3 7E , sword-4 check
CMP #$04 ;C9 04       , check if sword is 04
BEQ $01 ;F0 01       , branch 01 byte if equal
RTL; 6B          , if not equal, return
LDA #$33; A9 33       , if equal load entr 33 (tower of hera)
STA $010e ; 8D 0E 01    , store entr 33
RTL; 6B          , return
Didn't test it and hope I didn't make a mistake. Usually you can translate the hex 1:1 into asm. I added some branch marks where you have to count, if it is only one byte I'd stick to beq $01 instead of beq label.
Semicolons comment the documentation out, so you can try above asm without any change and should do the same as your hand written hex to the rom (if I didn't make a mistake that is of course Wink )


Last edited by Conn on Mon 27 Feb 2017 - 9:14; edited 2 times in total
Conn
Conn

My first ASM (that works) Image212

Since : 2013-06-30

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Euclid Mon 27 Feb 2017 - 6:14

The only thing to keep in mind of using an assembler is making sure you don't splat over useful code.

Though that being said - the entire PW menu was done via opcodes and hex edits - because I was literally recoding the same rom region as the lttp HUD/subscreen (which is pretty badly copy and pasted code, resulting in lots of redundancies). So there's a big the lack of a reusable .asm file for others to enjoy unlike most of the stuff I did for conker.

Though keep in mind that an easy mistake like missing the org $2A8000 = borked rom, so before you apply .asm files, keep backups!

Also the other major thing which makes your rom bonkers are the MX flags - you'll learn that it's the major reason why any ASM would "break" aside from being splat over

@conn: you missed the all important
lorom

line above the first ORGs - otherwise the assembler will throw those into weird spots.
Euclid
Euclid

My first ASM (that works) Image212

Since : 2012-06-21

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Puzzledude Mon 27 Feb 2017 - 6:27

Didn't test it and hope I didn't make a mistake. Usually you can translate the hex 1:1 into asm. I added some branch marks where you have to count, if it is only one byte I'd stick to beq $01 instead of beq label.
Thank you. It is interesting to see it in the actual ASM.

you missed the all important
lorom
This is also interesting. I'm assuming it is different if ALTTP would be hirom. (I have to say I don't fully understand the difference between lorom and hirom).

org $2A8000 ; at pc 150000?
Yes this is correct, I used 00 80 2A, which is pc 150000.

; MSU1 asm
I don't know why this was titled MSU, as this is not music at all, but rather the "entrances" ASM, which lets you change which entrance is loading on condition. So basically you can change the default entrance into another one (which is not placed on the overworld). This is trivial though as it has the ; anyway.
Puzzledude
Puzzledude

My first ASM (that works) Image213

Since : 2012-06-20

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Conn Mon 27 Feb 2017 - 9:36

lol, I had to correct it twice already (forgot once the JSL and the second time the nop outs), now I corrected it the third time with lorom (thanks Euclid) and the msu1 (took a template asm and forgot this to correct) ^^''

pfff, hirom and lorom... hirom is faster, but addressing is more difficult as far I remember (or easier as you do not need to calculate the lorom addresses). But e.g., you can address in lorom like lda $010e and the cpu knows that it needs to look into ram, since rom addresses start always at xx:8000. In hirom adresses start at xx:0000 already, thus it isn't possible to make lda $010e, you need to write lda $7e010e to point to ram. This way you can save some code and cpu runtime in lorom.
!This could be completely wrong, it's just out of my memory, I am sure Euclid can explain better.

Also, you may want to get familiar with geiger debugger and setting breakpoints. If you set a breakpoint in your code at 2a/8000 and play to the point where your routine is called, Geiger will disassemble it and shows all useful information like CPU flags, stack pointers, x,y,a registers and so on Smile

Code:

$2A/8000 BF 73 BB 1B LDA $1BBB73,x[$1B:BB75] A:0101 X:0002 Y:000C P:envMXdizC
$2A/8004 8D 0E 01    STA $010E  [$06:010E]   A:0101 X:0002 Y:000C P:envMXdizC
$2A/8007 C9 03       CMP #$03                A:0101 X:0002 Y:000C P:envMXdizC
$2A/8009 F0 09       BEQ $09    [$8014]      A:0101 X:0002 Y:000C P:envMXdizC
Conn
Conn

My first ASM (that works) Image212

Since : 2013-06-30

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Euclid Tue 28 Feb 2017 - 6:12

The lorom and hirom changes how rom file addressing is done for the assembler, lttp is lorom - Conn got confused with fastrom which is using banks 80-E0 vs 00-70 + some cpu flag (PS it doesn't matter if you write org $808123 vs org $000123 in the assembler, you'll get the same result)

You can probably get away with using hirom in the assembler as the addressing space is similar for most of the program banks, but it's good to keep in mind as some rom data is mapped to different spots in hirom - especially important when it comes to reading CPU registers or needing to find a chunk of unused ram.
Euclid
Euclid

My first ASM (that works) Image212

Since : 2012-06-21

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Conn Tue 28 Feb 2017 - 6:52

I think I read it somewhere that speed is higher in hirom (you cannot set fastrom when you have a hirom!).

Edit:
I have found this phrase:
But in SNES's architecture Nintendo had to compromise on speed for allowing cartridges with slower ROM speeds to work (thus reducing cartridge production costs) so they went with a variable clock, from 1.79MHz (for cheaper memory LoROM cartridges) to 2.68MHz (for costlier HiROM cartridges) to 3.58MHz (for code in the main SRAM).
Source:
https://www.quora.com/Was-the-Sega-Genesis-faster-than-the-Super-NES
(but no technical source so I am unsure).

As far I understand it, lorom (Zelda) is at 2.68 MHz, Fastrom (e.g., AST or our patch) is the same speed as hirom (e.g., bszelda) at 3.58 MHz (the highest speed the snes CPU can reach).

Conn
Conn

My first ASM (that works) Image212

Since : 2013-06-30

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Mr.x Tue 28 Feb 2017 - 11:43

Congrats, puzz!

Yes, the Sega Genesis was faster than the Super Nintendo, remember blast processing? I recall that the SNES was very reliant on the carts for more technically impressive things, such as Star Fox.

Here's a word from RHDN's admin, of all people,about the subject from 2005:

With LoROM, you can have FastROM or SloROM. This means that data accessed in $8x:xxxx banks and above run the SNES CPU at 3.58Mhz because ROM access is faster there. The SNES CPU runs in SloROM mode for ROM access below those locations and the SNES CPU runs at 2.68Mhz.

And then anomie countering:

HiROM, LoROM, or whatever has nothing to do with FastROM/SlowROM (although it does require that the cart have ROM chips with fast enough access speeds). The speed is completely a function of the SNES: if you set bit 1 of the MEMSEL register, then accesses to $8000-$ffff in banks $80-$BF and all of banks $C0-$FF are FastROM, otherwise they're SlowROM. Note BTW that other regions ($2000-$3FFF and $4200-$5FFF in banks $00-$3F and $80-$BF) are always FastROM.

Mr.x
Fluteboy
Fluteboy

Since : 2014-04-10

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Puzzledude Tue 28 Feb 2017 - 13:15

Congrats, puzz!
Yes, I looked into this, since with this code you can actually make the most simple 7 crystal barrier (original is far too complex to port to hacks - well you can, but again with further coding).

Regarding Hi and Lorom. Here's what Wikipedia has to say:
In LoROM mode, the ROM is always mapped in the upper half of each bank, thus 32 Kilobytes per chunk. The banks $00 - $7D (address: $8000 - $FFFF) hold continuous data, as well as banks $80 - $FF. SRAM on the cartridge is mapped continuously and repeatedly - 8 Kilobyte of SRAM are mapped at $0000 - $1FFF, $2000 - $3FFF, $4000 - $5FFF and so on. Because the WRAM of the SNES is mapped at bank $7E - $7F, these banks do not map to the last SRAM/ROM chunks. This memory has to be accessed via the banks $80 - $FF. There is no other way of accessing this memory both in LoROM and HiROM mode.

LoROM was established to make sure that the system banks ($00 - $3F) higher pages (>7) are actually used. This is done by loading the entire ROM only in higher pages and in 32 Kilobyte chunks. 32 KB * $80 banks == 4 Megabyte.



HiROM is a bit more complex to understand. Unlike LoROM, it does not use $80 (128) banks to map the ROM into the address space of the SNES, but only $40 (64) banks. Also unlike LoROM, these banks are used to their full extend, that is, 64 KB per chunk. 64 KB * $40 banks == 4 Megabytes. The banks $40 - $7D (address: $0000 - $FFFF) hold continuous data, as well as banks $C0 - $FF. Beware that HiROM also creates mappings for banks $00 - $3F and $80 - $BF. As those are system banks, their lower pages (<8) are already mapped - but the higher pages are free, so that many portions of the ROM are mirrored four times into the address space of the SNES. SRAM on the cartridge is mapped into the banks $20 - $3F, in 8 Kilobyte chunks. As there are only 32 banks reserved for this, the possible SRAM amount accessible in HiROM is theoretically lower than in LoROM (256 KB vs. 512 KB). Because the WRAM of the SNES is mapped at bank $7E - $7F, these banks do not map to the last ROM chunks. This memory has to be accessed via the $80 - $FF banks

Banks $80 - $FF can also be used for faster memory access. Many portions of memory <$80 are accessed at 2.68 MHz (200 ns). Accessing memory >$80 is done at 3.58 MHz (120 ns) if the value at address $420d (hardware register) is set to 1.

LoROM basically means that the address line A15 is ignored by the cartridge, so the cartridge doesn't distinguish between $0000-$7FFF and $8000-$FFFF in any bank. Smaller ROMs use this model to prevent wasted space in banks $00-$3F.
Puzzledude
Puzzledude

My first ASM (that works) Image213

Since : 2012-06-20

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Mr.x Tue 28 Feb 2017 - 17:17

I wouldn't trust something like Wikipedia for something as niche as SNES hardware information. Try following the cited sources. On the other hand, the page knows more than I do.

Mr.x
Fluteboy
Fluteboy

Since : 2014-04-10

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Founder Tue 28 Feb 2017 - 23:42

Trovsky wrote:I wouldn't trust something like Wikipedia for something as niche as SNES hardware information.
What about those?

https://wiki.superfamicom.org/snes/show/HomePage
https://en.wikibooks.org/wiki/Super_NES_Programming
https://github.com/PeterLemon/SNES

I'm pretty sure there's plenty of things that could be helpful in there.

Founder

My first ASM (that works) Image212

Since : 2012-06-19

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Puzzledude Fri 3 Mar 2017 - 13:44

Here another ASM which I wrote as testing/learning (now also using "branch if plus" and "branch if minus" opcodes):

The idea was to change the time in which Link starts running to different values on condition:

Code:

hook
at 3B299,
A9 1D 8D 74 03   change to
22 00 80 2C EA
jump to 160000


at 160000,
AF 44 F3 7E      ,load ram for mushroom/powder
C9 02            ,compare to 02= have powder
F0 06            ,if equal (have powder), branch 06 bytes
A9 80 8D 74 03   ,if no powder, start after 80
6B               ,rtl
AF 6E F3 7E      ,load ram for green magic
C9 20            ,cmp to 1/4 green
10 06            ,branch 06 bytes, if plus
A9 6D 8D 74 03   ,if not, start after 6D
6B               ,rtl
AF 6E F3 7E      ,load ram for green magic
C9 40            ,cmp to 1/2 green
10 06            ,branch 06 bytes, if plus
A9 4D 8D 74 03   ,if not, start after 4D
6B               ,rtl
AF 6E F3 7E      ,load ram for green magic
C9 60            ,cmp to 3/4 green
10 06            ,branch 06 bytes, if plus
A9 2D 8D 74 03   ,if not, start after 2D
6B               ,rtl
AF 6E F3 7E      ,load ram for green magic
C9 80            ,cmp to full green
F0 06            ,branch 06 bytes, if equal
A9 1D 8D 74 03   ,if not, start after 1D
6B               ,rtl
A9 01 8D 74 03   ,if full, start after 01 (instant)
6B               ,rtl


Basically the result is this:
-if no powder: if A is pressed and shoes, start running after 5 seconds
-if powder+ magic from 0 to 1/4: start running after 4 seconds
-if powder+ magic above 1/4 to 1/2: start running after 3 seconds
-if powder+ magic above 1/2 to 3/4: start running after 2 seconds
-if powder+ magic above 3/4 to 127/128: start running after 1 seconds
-if powder+ full magic (128/128): start running after 0 seconds (this one is interesting to watch, as he just starts sprinting instantly with no delay).


separate thing (this one is not on condition here):
3E237,
optimal running speed is 2D
ALTTP has it 40 (too fast), since 2D is twice as fast as walking, 40 is too fast (almost 3 times faster than walking).
Puzzledude
Puzzledude

My first ASM (that works) Image213

Since : 2012-06-20

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Conn Fri 3 Mar 2017 - 20:21

That is already advanced asm Smile
You see when you make a compare instruction, it actually subtract the value you compare from that in the accumulator.
Means A:0007, cmp #$07 is 07 -07 = 00
The zero flag is set (big Z)
P:envmxdiZc
and you can branch on beq, bne.

At the same time the negative flag is set as well, if the outcome is between 80 and FF:
A:0007, cmp #$08 is 07-08 = FF
So the negative flag is set (big N)
P:eNvmxdizc
and you can branch on bmi, bpl.
Values between 00 and 7F are positive, small n, while values between 80 and FF are negative, big N.

More important is the carry flag as it allows comparisons >= (bcs)  and < (bcc)
P:envmxdizC
In your case you are lucky that your code is bugfree: you actually can branch with bmi and bpl, because (and only because) the highest magic meter level is 80, right the value where the N flag starts, so it does in this case the same as the carry flag.
But imagine you have
A:0001 and cmp #$82 (82 is a value the magic meter cannot have so you're safe with your code).
The outcome is 01-82 = 7F
So the negative flag isn't set and you won't branch on bmi, as 7F is positive, however, the carry flag is always set right and you can branch in this case on bcc.

So never branch on bmi, bpl unless you make arithmetic sbc, adc operations, if you make >= and < comparisons, always! branch on bcs, bcc.
Conn
Conn

My first ASM (that works) Image212

Since : 2013-06-30

Back to top Go down

My first ASM (that works) Empty Re: My first ASM (that works)

Post by Puzzledude Sat 4 Mar 2017 - 6:22

Yes, I know I was lucky here, as the 80 can not be higher and I used that feature. I looked into all branch commands and found the ones you were discribing, but still need to figuere out how the "flags" work. (I also apparently misunderstood the "plus" and "minus", but got lucky here as well; as I understood it as "higher" and "lower").
Puzzledude
Puzzledude

My first ASM (that works) Image213

Since : 2012-06-20

Back to top Go down

Back to top

- Similar topics

 
Permissions in this forum:
You cannot reply to topics in this forum