News:

11 March 2016 - Forum Rules

Main Menu

Snes assembly, Where to begin?

Started by DelilahTw, March 30, 2021, 02:02:53 AM

Previous topic - Next topic

DelilahTw

Hi, I've been always fascinated for the hardware of the snes and how it works, specially for the graphics and the sound and I always wanted to know a little bit more. I tried to get into writing some little demos or code for the snes but there's like a barrier maybe because of the available info or the documentation. I coded in assembly in the past in msdos and i did some demos so I'm not completely new to assembly coding and I code in other languages like basic, C or recently I've doing just some bash scripts in linux.

The main problem that i have when it comes to code for the snes is to find a proper documentation with examples and all the available instructions when it comes to code. And maybe some little examples for example letting you know how to start the snes, how do you load graphics in which format are the graphics, how do you change a particular pixel colour on the screen, how do you move things on the screens, how to set a particular graphic to certain layer and so on... I have so many questions and I can't not find a good place with doc to start. I've got the basic installed notepad++ and WLA and xkas I don't know which one is better or if they support to assembly code for the music as well or the special snes chips... Thanks.

FAST6191

While you could learn every SNES instruction I am not sure most would. Far easier to start with a core set of the big three types (basic maths, program flow, hardware fiddling) and then incorporate more as needed. Though it is less silly than trying to learn every X86 instruction ( https://www.felixcloutier.com/x86/ ). It made more sense for the NES where the 6502 has so few but SNES... less convinced.
Around here most start with tracing in programs and maybe then subverting a program, adding a bit more code and thus having to learn about branching/jumps.

Few links that might help, though I don't have anything quite as nice as I have for the PC or GBA or DS.
https://www.copetti.org/writings/consoles/super-nintendo/
https://en.wikibooks.org/wiki/Super_NES_Programming
https://wiki.superfamicom.org/
http://problemkaputt.de/fullsnes.htm
http://www.romhacking.net/?page=documents&category=&platform=9&game=&author=&perpage=20&level=&title=&desc=&docsearch=Go

Raeven0

Quote from: DelilahTw on March 30, 2021, 02:02:53 AM
The main problem that i have when it comes to code for the snes is to find a proper documentation with examples and all the available instructions when it comes to code.
Indeed. You'd think after 30 years we'd have a solid base of lucid pedagogical material for SNES development, but, alas, no.

You might get value out of Ersanio's ASM Tutorial. It only has a couple of mistakes.

PinoBatch's LoROM "minimal working program" is all right. It uses the ca65 assembler and some Python scripts, and is nicely documented. The most interesting file is probably src/init.s, wherein a lot of thought goes into initializing the SNES hardware registers to a sane state.

The SNES development wiki is a treasure trove of technical detail, but also quite difficult to follow at times, on account of broken links and references to other material that no longer exists.

The 65C816 opcodes page is essentially a mandatory reference work, and good general reading too.

I'm aware of at least one complete disassembly of Super Mario World, which can provide some insight as to how code is written in practice.

DelilahTw

#3
Quote from: Raeven0 on March 30, 2021, 11:34:38 PM
Indeed. You'd think after 30 years we'd have a solid base of lucid pedagogical material for SNES development, but, alas, no.

You might get value out of Ersanio's ASM Tutorial. It only has a couple of mistakes.

PinoBatch's LoROM "minimal working program" is all right. It uses the ca65 assembler and some Python scripts, and is nicely documented. The most interesting file is probably src/init.s, wherein a lot of thought goes into initializing the SNES hardware registers to a sane state.

The SNES development wiki is a treasure trove of technical detail, but also quite difficult to follow at times, on account of broken links and references to other material that no longer exists.

The 65C816 opcodes page is essentially a mandatory reference work, and good general reading too.

I'm aware of at least one complete disassembly of Super Mario World, which can provide some insight as to how code is written in practice.

Thanks, hopefully this time I'll be able to jump in, maybe because of the lack of documentation, i don't know. I will say that with the rest of the coding languages there's a barrier of course specially when you start, assembly was hard when i did it back in the days, but i ended up learning a bit, it's been years since then and I forgot so much stuff but I always wanted to learn and know a little bit more of this system and try to do small tests or demos but it was always so hard to start and i didn't know where to begin, I'll take a look to the tutorial and the info.

Raeven0

Also possibly useful: the SNESdev forum, some 15 years and counting of discussion about development of original games and such for the SNES. romhacking.net is more about hacking existing games.

Chatterine

I'm also trying to learn assembly, and it seems that there's plently of material to work from... How do you guys memorize everything? The SNES has too many opcodes for me.

Raeven0

No need to memorize all 256 opcodes. Write your code in assembler mnemonics and let an assembler make the opcodes for you, or you can manually look up the opcodes for your instructions if you really want to. Many (most?) instructions just combine a basic action, an addressing mode, and a register or two. So you only need to remember the assembler mnemonics for various actions (arithmetic, load, store, etc.), the syntax for different addressing modes (direct, absolute, long, etc.), and what the registers are (chiefly A, X, and Y).

Chatterine

So basically out of all opcodes I'll only use a few ones, and in case I find one I don't know I can just look it up on reference material, right? Looks harder than it really is.

Another thing: how does the assembler "write" the opcodes to the ROM? Can't you simply open the ROM and edit the opcodes from there? As far as I know you can only view/edit opcodes in a debugger from the memory, but I could be wrong because I'm just a beginner.

FAST6191

Yeah for some older assembly instruction lists it is more reasonable to memorise them all. For the most part though trying to memorise everything is like trying to learn a human language by memorising its dictionary, would be an impressive feat but the one that learns spelling rules, grammar rules, everyday language and maybe their own specialist bit will probably do just fine (theoretically might even do better) if moving there tomorrow.

I do tend to break instructions into three major categories, in my case from assembly as a general concept shared between systems (this is the "basic maths, program flow, hardware fiddling" from my earlier reply) though probably defaulting to X86 for much terminology as it is more likely to be known by random other coders or have reference material.

Still whether you are using something that might scarcely be Turing complete or a modern cluster of supercomputer on a chip you still have the same three things to consider.
1) The maths. I won't say everything else is just getting to this but... it kind of is. Some things have more or less functionality than others but maths is maths. You will be adding, hopefully subtracting, multiplying, dividing, shifting, rotating, ceiling, floor, rounding, trigonometry, logarithms, doing masks, boolean logic, and maybe doing it on specialist data types or data sizes or masses of data in the case. Basically most systems by their processor, bios or otherwise will effect most of your average spreadsheet https://help.libreoffice.org/Calc/Mathematical_Functions but maybe limited to whole numbers, whole numbers of a given bit size, floats of various precisions or have to recreate that in software.

You might look to look up the basic "everything is adding" concept that is often taught to new electrical engineers or computer science types.
Adding is adding, subtraction is just another type of adding, multiplication is just a short form of adding, division is subtraction if you take it to logarithms, https://www.chilimath.com/lessons/advanced-algebra/logarithm-rules/ , and again that is a form of adding), shifting is short form multiplication/division, rotating is but a form of shifting...


2) Program flow. Maths is easy enough to do, it is the ability of computers to make choices depending upon previous conditions that make things interesting.
Branching, goto, jumps...
Some will compare it to higher level languages and loops in those where IF, ELSE, WHILE and so forth are the order of the day https://www.learnpython.org/en/Loops . Hence the if equal, if not equal, if greater than, if less than and maybe stacking a few up to get a if between this range, blindly jump back to here... type instructions.
Add in interrupts (basically checking to see if something has happened every go around/few instructions in a program is tedious, machine makers soon realised that the ability to have something external reach in and say "do this now" is quite useful) and you have this.

3) Hardware fiddling.
CPUs have registers which are small sections of memory that operate very fast, benefit from being able to reach out and touch memory elsewhere in the system (though there are also tools that spare the CPU having to do this, this is DMA aka direct memory access) and occasionally need to reset things back to a baseline. Space is not infinite at this level by any means so new space constantly needs to be made, old things put to the side for a moment or otherwise fiddled with.
To that end I usually learn whatever a given CPU's equivalent of MOV is (the instruction that copies data from one register to another, possibly copies to memory, and possibly is used to insert a simple number, aka an immediate, into a register so you can go on from there, sometimes these are separate concepts), whatever you need to do to fiddle with memory, whatever the push and pop is, whatever the NOP (no-operation, not necessary a dedicated instruction but there will usually be a convention used in a given game/assembler/system/style of an instruction that does nothing but waste a bit of time) and whatever is needed to reset flags (if the compare used in program flow does not immediately cause a branch to somewhere else it will tend to first set a flag in the CPU to say compare not equal that the instruction that actually does branch will check first and go from there, more for negative result, errors and whatever else).



Hamming code, linked lists, https://docs.google.com/document/d/1iNSQIyNpVGHeak6isbP6AHdHD50gs8MNXF1GCf08efg/pub?embedded=true , https://web.archive.org/web/20160208024106/http://hci.usask.ca/uploads/332-aim-assist-cameraReady-v8-final.pdf , https://web.archive.org/web/20080309104350/http://etk.scener.org/?op=tutorial , https://www.pcgamer.com/how-hitboxes-work/ , what checksums are and why you care about them, https://ece.uwaterloo.ca/~ece611/LempelZiv.pdf , https://www.youtube.com/watch?v=bVJ-mWWL7cE (warning, rather advanced and far from necessary but might provide some insights) and much more* might serve to make you a more rounded coder able to recognise memory structures, programming ideas and more but building something from the ground up because you knew no better still leaves you understanding something at the end, possibly even more so than someone trying to fit it to preconceived notions of how things normally work.

*I often use the example of stats in games. Typically it will be one character with one stat after the other, or it will be one stat type after the other. Think how the naive stats thing would be done in a spreadsheet with character and stats in columns going, one of those is taking a column at a time and the other is a row at a time. Now what happens when you have generated stats (HP = 4xdef+2x constitution + 5x level number...) or maybe some kind of weird matrix maths. Items also have two main formats, that being each place on this table refers to how many you have, or this item identifier has a value for how many you have, though that breaks down a bit when you get a nice modern RPG with a whole bunch of specialist bits that might as well be a character all of its own and caked in XML.

As far "writing opcodes to the ROM"
Sometimes yeah you do. Various higher level disassemblers (think something like IDA) will have it all baked in such that you can find where you want to go, tap in a valid instruction and it will overwrite just like your hex editor would a hex value or in the text window.
Other times people will make instructions, assemble them with an assembler and manually overwrite the according instructions.
Though that might be getting ahead of things.
For the most part there are two approaches for the would be hacker
1) In place.
2) You find some free space somewhere and smack the game hard enough that it goes there, does your extras and goes back to what it would have been doing "normally".

In place is nicer and more desirable if you can do it. However space is always at a premium and you might want to actually do something more fancy. Overwriting code next to what you did tends to break a game (though not always) so do that at your peril, you might optimise the code to do what it needs to do in less instructions (yours and the original) as not all devs have to be the best or foresee everything (or maybe they tried to and don't need to**).
To that end you will soon be off finding space (observations of things that never run in the game, simple blank space in a ROM, space clawed back from something else, something the dev left in that might otherwise only have been seen on https://tcrf.net/The_Cutting_Room_Floor ), overwriting an instruction (or maybe adding something to a vblank routine -- if you are hardcoding a cheat that only needs to write this area of memory once a frame...) to tell it to jump to your new code's location, have the code do all it needs to do and then jump back, return if you will, to where it needs to go.

**most programmers will soon run into bounds checking, sometimes only after something bad though https://hackaday.com/2015/10/26/killed-by-a-machine-the-therac-25/ . If the original devs included a bunch that other parts of the game ensure will never happen then arguably it is redundant. This does not happen so much on older systems like the SNES -- every instruction and every byte tends to be treated as valuable so no wasting it double checking answers when you could be having more functionality the player cares about.


I normally recommend learning to hardcode a cheat in as a first project. You can try altering opcodes (there might be more than one compared to a single memory address***), inserting something in a vblank or doing something else entirely.

***death in something like mario might be from time, mushroom, pits, enemies, hazards, crushing... and all do their own thing.

Quote from: Raeven0 on April 02, 2021, 07:14:13 PM
Also possibly useful: the SNESdev forum, some 15 years and counting of discussion about development of original games and such for the SNES. romhacking.net is more about hacking existing games.
snesdev/nesdev is certainly a valuable resource, and oversight of mine to not include it earlier. As far as here being about existing games then sure, however those that style themselves as the ultimate form of the craft being that of someone able to rock up to any game and make a dent in understanding how it works or make it conform to their actions. They can probably still manage the basic form of a program and introduction to the practical realities of a system.

Chatterine

Thanks @Raeven0 and @FAST6191, now I think I know where I'm supposed to start. I heard SMW Central also has good materials even if it's more centered towards the hacking of one specific game and not romhacking in general, no?

Raeven0

Quote from: Lusofonia on April 02, 2021, 08:33:04 PMAnother thing: how does the assembler "write" the opcodes to the ROM? Can't you simply open the ROM and edit the opcodes from there? As far as I know you can only view/edit opcodes in a debugger from the memory, but I could be wrong because I'm just a beginner.
Self-plug: I included the assembly source with my Illusion of Gaia hack. It's the file ending in .asr and requires Asar. Given a ROM file called say IOG.sfc, the assembler is invoked by asar.exe "hack.asr" "IOG.sfc" which assembles my code and writes it to the ROM.

Somewhere in that code is this (lightly edited) snippet: org $80FD00
tyx
lda [$0a] : sta $1000
inc $0a : inc $0a
lda [$0a] : sta $1002
inc $0a
stz $1008
lda $0a : sta $02,s
rti
The effect of which is that at the ROM address corresponding to SNES address $80fd00, the correct bytes are written to represent those instructions. I don't know or need to know what those bytes are. I do need to know what data I'm manipulating and how I want to alter it, so that I can write the right instructions to do so, but that's true of all programming.

SMWCentral has some okay material and some not-so-okay material. There's a tendency to assume that SMW code is representative of all SNES code, leading e.g. this otherwise fine tutorial to say some silly things about direct-page addressing and the brk and cop instructions.

Chatterine

Oh, ok. I guess I gotta be careful when looking at that website's material. Also, why so many assemblers? xkas, asar... Can't there be simply one and only assembler?

Raeven0

Quote from: Lusofonia on April 03, 2021, 09:15:19 AMAlso, why so many assemblers? xkas, asar... Can't there be simply one and only assembler?
There are differing opinions as to what syntax and features are most useful. One important high-level distinction is between program assemblers and so-called "patching" assemblers. Asar and xkas are patching assemblers: you supply an address and some code to patch into a pre-existing file, and the syntax is optimized for this process. When writing a complete program, it's more productive to write modules of code and let the assembler decide how to order them, and the syntax of whole-program assemblers like ca65 is tuned for that workflow.

Asar itself is a derivative of xkas and a product of the SMW community. It fixes bugs and adds syntax features to make programming faster and easier. A couple of interesting notes:

  • direct,y is not a valid 65816 addressing mode, so what should happen if the programmer writes say lda $14,y? xkas throws an error, but Asar parses this as lda $0014,y -- consistent with what a SMW hacker would expect, since in SMW the direct page is at $0000.
  • For MVN (and MVP), the CPU developer prescribed the assembler syntax MVN src,dest but the machine code order $54 dest src. The xkas developer (incorrectly) interpreted dest src as a 2-byte (little-endian) word, so programmed xkas with the syntax MVN SrcDest (no comma). Later developers, thinking this looked strange, allowed the word to be written as two bytes instead, giving the syntax MVN dest,src -- precisely the opposite of what the CPU developer intended. This will never be fixed in Asar, because doing so would break all SMW patches that use MVN/MVP.

pianohombre

I've been hacking for awhile, and still only done very basic stuff. Some people are very good at finding tables of valuable data to hack, then going at it. You should learn how to use a debugger and step through lines of assembly, but most of it will seem like egyptian heiroglyphics. The whole vram thing and registers is way beyond me. It's too bad we bring it down to "hex" and can't get actual useful code out of most roms. Start with games that have been hacked to death since there will be troves of useful info about every part of the rom that's already been translated and commented, rather than trying to do something from scratch.
"Programming in itself is beauty,
whether or not the operating system actually functions." - Steve Wozniak

KingMike

Quote from: Raeven0 on April 03, 2021, 01:52:52 PM

Asar itself is a derivative of xkas and a product of the SMW community. It fixes bugs and adds syntax features to make programming faster and easier. A couple of interesting notes:

  • direct,y is not a valid 65816 addressing mode, so what should happen if the programmer writes say lda $14,y? xkas throws an error, but Asar parses this as lda $0014,y -- consistent with what a SMW hacker would expect, since in SMW the direct page is at $0000.
  • For MVN (and MVP), the CPU developer prescribed the assembler syntax MVN src,dest but the machine code order $54 dest src. The xkas developer (incorrectly) interpreted dest src as a 2-byte (little-endian) word, so programmed xkas with the syntax MVN SrcDest (no comma). Later developers, thinking this looked strange, allowed the word to be written as two bytes instead, giving the syntax MVN dest,src -- precisely the opposite of what the CPU developer intended. This will never be fixed in Asar, because doing so would break all SMW patches that use MVN/MVP.

So those are both SMW-optimized changes?
If LDA $14,y is not a valid opcode, it should be an error since other SNES games can (and I'm sure do) move the Direct Page.
"My watch says 30 chickens" Google, 2018