Jump to content
IGNORED

Help with math please.


Recommended Posts

I been reading through several of the resources and learning as much as I can but I have having some trouble with the math. I suck at math, that's all there is to it. But I learn fast.

 

I'm not sure what all I need to know, so is there a list or sorts?

 

Anyway my current problem is this:

 

From Changing Atari VCS Graphics- The Easy Way

By Adam Trionfo

 

Each row of X's represents one byte.

In order to get the byte’s value, we have to add up

each X and the placeholder it represents. For

example, in step 10, address $FC0A looks like this:

Total bits

128 64 32 16 8 4 2 1= 255

X X X X X = 124 decimal

7C in hex

 

Now how do I do that? I know about bits, but how did he get 124 from X X X X X ? And how did he convert it to hex?

 

Am I just missing something or what?

Link to comment
Share on other sites

128 64 32 16 8 4 2 1= 255

X X X X X = 124 decimal

7C in hex

 

Now how do I do that? I know about bits, but how did he get 124 from X X X X X ? And how did he convert it to hex?

 

Am I just missing something or what?

If you want to pass a link to that article, it'd help if I could read it with the original formatting - it appears to have lost it.

 

Anyway, rather than this X business, it's better to think of each pixel in the graphics as being a 1 if it's on, and a 0 (zero) if it's off.

 

124 is 01111100, which has 5 ones, which presumably corresponds to the 5 Xs above.

 

You'd do well to read up on binary arithmetic. If you're running Windows, the built-in calculator in Scientific mode (under the View menu) allows for easy decimal-binary-hexadecimal conversion, which is very handy when programming and learning this stuff.

Link to comment
Share on other sites

Each row of X's represents one byte.

In order to get the byte’s value, we have to add up

each X and the placeholder it represents. For

example, in step 10, address $FC0A looks like this:

Total bits

128 64 32 16 8 4 2 1= 255

X X X X X = 124 decimal

7C in hex

 

Now how do I do that? I know about bits, but how did he get 124 from X X X X X ?

 

I would assume the X was aligned under each of the values, and there was an X for 64, 32, 16, 8, and 4. That would total 124. Your message said 'add up each X and the placeholder it represents'.

 

 

And how did he convert it to hex?

 

 

The hex equivalent of 124 is 7C. See the link below for a hex conversion chart. He is not converting the X's to 7C, he is converting 124 which is the total value of the placeholders the X's represent.

 

http://www.jaworski.com/htmlbook/dec-hex.htm

 

Troy

Link to comment
Share on other sites

You might know that the smallest unit to a computer is referred to as a "Bit". The computer's memory is composed to thousands of these...and each one is like a miniature switch...or gate. The gate can be open, or the gate can be closed. When the gate is open, no electricity can travel from one side of the "fence" to the other side...and the computer considers this bit to have no value (zero). When closed, it has a value of 1. This is referred to as "Binary"...and everything that happens within a computer is really just those gates opening and closing. So the entire memory space is really just a collection of 0's and 1's.

 

Since just saying "1" or "0" isn't very useful (as if the English language only had 2 words)...the bits are grouped in smaller collections of 8 each in a 6502 chip...and each one of these groupings is referred to as a memory address, as if each address were a section of fence with 8 gates (i.e. the bits). So if all of the gates were open, the contents would look like 00000000. In binary counting, the rightmost bit is the lowest digit (the same way that decimal counting works). So...

00000000 = 0 decimal

00000001 = 1 decimal

 

So what happens when we increase 00000001? We can't use 00000002...because each bit an only hold a zero or one. What happens is nearly the same as what happens in decimal. If you have 9 and you add 1 it becomes 10. The lowest digit is zeroed and a 1 is added to the next higher decimal place. This is exactly what happens in binary...the lowest digit is zeroed and a 1 is added to the next position to the left. So...

00000000 = 0 decmal

00000001 = 1 decimal

00000010 = 2 decimal

 

So how do we keep track of which numbers are written in decimal and which are binary? That's where special characters come in. When you are reading a page with numbers on it...numbers just by themselves are assumed to be decimal (base 10). Numbers that are preceded by a percent character are assumed to be binary (base 2). And numbers that are preceded by a dollar sign character are (no...not money) assumed to be hex (base 16). I'll get to hex values later...but I'll start using those characters immediately to be clear on what type of value I'm referring to.

 

Anyway...I got a little ahead of what your question is.

Because %00000001 is equal to 1, and the rightmost bit cannot go higher, we can deduce that the rightmost bit (by itself) has a value of 1 when switched on. If the number were %00000010, that bit next in line can also go no higher...so we can deduce that bit has a value of 2 when switched on.

 

Increasing %00000010 would become %00000011...and now it is a value of 3 decimal. So what happens if we increased that? In this case, both of those 1's would flip to zero and a 1 would appear in the next position to the left.

%00000000 = 0 decimal

%00000001 = 1 decimal

%00000010 = 2 decimal

%00000011 = 3 decimal

%00000100 = 4 decimal

 

You probably guessed...but that next bit has a value of 4 when the bit is switched on. Each time you move to the left, the value of the bit DOUBLES.

Therefore, the bits have values of...

%00000001 = 1 decimal

%00000010 = 2 decimal

%00000100 = 4 decimal

%00001000 = 8 decimal

%00010000 = 16 decimal

%00100000 = 32 decimal

%01000000 = 64 decimal

%10000000 = 128 decimal

 

So if the leftmost bit is on, that value will be at least 128 decimal (depending on the state of the other 7 bits in that group (or address).

 

Therefore, the maximum value that an 8-bit address can hold is:

128+64+32+16+8+4+2+1

That would be if all of the bits were turned on. And that has a total of 255 decimal.

 

%11111111 = 255 decimal

 

In describing graphic patterns like sprites, X's are sometimes used to indicate which pixels (i.e. bits) are turned on. And spaces or dashes are used to indicate which pixels are turned off. So a sprite line of X-X-X-X- is equal to %10101010...which is equal to 128+32+8+4 (or 172) decimal. It's the same as using 1's and 0's...just using X's and -'s instead to make the picture clearer to the human reading the grouping on his or her screen. :)

 

 

Hex values:

Programmers would go funny in the head (more than they already are) if they had to stare at nothing but 0's or 1's all day...so a system was devised to make those binary values more easily readable. Each byte is divided into 2 halves...4 bits each. So the group of 00000000 now becomes the subgroups 0000 and 0000. These subgroups are referred to as "nybbles" (half of a byte). So we have bits (which are 1 digit), nybbles (4 digits), and bytes (8 digits). All very nice, but 1111 1111 doesn't look much more readable than %11111111 :P

Looking back up top, you might see that the rightmost 4 bits (when all turned on) have a value of 8+4+2+1...or 15 decimal. Much closer to the decimal numbers that we humans are used to...except that 6 additional digits are needed to fill in the missing ones. To solve this problem, the first 6 letters of the alphabet are used for the missing digits in hex.

Decimal has 10 digits, 0 1 2 3 4 5 6 7 8 9...binary has 2 digits, 0 1 and hex has 16 digits, 0 1 2 3 4 5 6 7 8 9 A B C D E F. A single hex digit has a maximum value of 15...just like a single nybble has a maximum value of 15. So the translation goes...

%0000 binary = $0 hex = 0 decimal

%0001 binary = $1 hex = 1 decimal

%0010 binary = $2 hex = 2 decimal

%0011 binary = $3 hex = 3 decimal

%0100 binary = $4 hex = 4 decimal

%0101 binary = $5 hex = 5 decimal

%0110 binary = $6 hex = 6 decimal

%0111 binary = $7 hex = 7 decimal

%1000 binary = $8 hex = 8 decimal

%1001 binary = $9 hex = 9 decimal

%1010 binary = $A hex = 10 decimal

%1011 binary = $B hex = 11 decimal

%1100 binary = $C hex = 12 decimal

%1101 binary = $D hex = 13 decimal

%1110 binary = $E hex = 14 decimal

%1111 binary = $F hex = 15 decimal

 

That makes things a bit more readable when using hex. The 2 nybbles 0000 0000 are now more easly read as $00. A lot shorter and easier on the eyes. And the pattern above is used for each digit in the hex number. So if the byte held a value of %10101011 binary, that would be 1010 1011 when seperated into nybbles...and using the pattern above, it would translate into the hex value of A for the first nybble and B for the second...for a hex value of $AB.

 

Does it make sense? I can go on if you are lost so far :)

Link to comment
Share on other sites

I want to thank you so MUCH! :D That made a hell of a lot more sense then anything I have read so far. I really appreciate you taking the time to write all that out. You answered all my questions one right after another. :)

 

By all means continue if you like. :)

 

Just for reference here is the link to the original article:

http://www.gooddealgames.com/articles/chan...he_easy_way.pdf

 

Thanks everyone![/url]

Link to comment
Share on other sites

No prob. If you understood all that, there is no reason to break it down any further :)

 

Moving along...

For an example of what a nightmare it WOULD be if programmers were only allowed to use 1's and 0's, imagine an entire disassembly for a game written in them. The thing would be unreadable to humans. The computer would have no problems tho...since it's only interested in whether the gates are open or shut in the collection of 8 that it's looking at. So hex, decimal, binary notation is really kind of irrelivant to the computer. Those only exist to benefit YOU - the reader - trying to make sense out of what gets fed into the computer.

 

EDIT for previous post:

I mentioned addresses above in a couple of spots, when I really should have used the word "byte". The computer deals with all sorts of numbers, and a few of them have no address. They are called the registers...and keep track of what is currently happening. Skip ahead if you aren't interested in hacking the very instructions of games...because this might get a bit deep.

Three of the registers of them are used by the program to hold values that are currently being manipulated (the accumulator, X, and Y registers). Variables, in other words. And everything that happens in a program is dependant upon what those variables hold. The accumulator is the real workhorse...most everything that happens does so because of a value passing through this register (or variable). It's also called just "A". And the X and Y registers are secondary...either holding values that we want to work with while keeping the accumulator intact, or assisting the accumulator to do it's job.

Another register (the status register) contains 8 bits that change depending upon the results of the manipulations happening to those 3 variables. For example...if 2 values are being compared, a bit will be turned on in the status register if they are of equal value.

Still another register (the program counter) exists to keep track of WHERE the program is when running the program. This allows the computer to be able to move to the next instruction in memory once the current one has been dealt with...as well as jump away from it's current position to a new area.

 

 

Getting back from all of that:

"Addresses" are just like the name implies. When you go to somebody's house, you are going to their address. Similarly, when the computer is moving values from a register to memory or from memory to the register, it's copying the value from register to the address or visa-versa.

The superb book Machine Language For Beginners describes the computer's memory as a long street...which has 65536 houses along it. Each of those houses is an address...and can hold exactly 8 bits (which "live" inside it). The value in each address is the combination of those 8 bits.

Besides the registers (which don't "live" at any address), there are 2 types of computer memory...Ram and Rom.

ROM (Read-Only) Memory is the entire contents of the program cartridge, and it's size and values NEVER change. They are burned right into the chip itself, and none of the values can be altered. They contain every instruction, every sprite, and every piece of data that it "knows" when it is powered up. And it's size is also unchanging...a Rom chip that holds 4096 bytes (i.e. "houses") of memory will always hold 4096 bytes. No more. No less. And the values within will remain in the chip...even if the computer is off power.

RAM (Random-Access) Memory are similar to the registers. The values in each of those addresses can be overwritten. They can be "looked at" by the program...and values from registers can be copied to them. The number of Ram addresses ("houses") is usually unchanging. I use the word "usually" because the Atari console itself holds a static number of them...but some cartridges or hardware include Ram memory of their own. Ram memory will be cleared or corrupted when the system is getting no power.

 

When hacking graphics, one of the first things you might be wondering is why you cannot make sprite shapes larger than what they already are. This is due to the cartridge chip size...it never changes...as well as the way the program is written (if the program's Rom instruction is only reading 10 addresses, it will always only read those 10 addresses). So if you try making a sprite larger, it will be overwriting the values of what existed above and below it. Those are Rom addresses too...and the program might be expecting specific values to "live" there. Some games might be a bit forgiving...like reading in a group of 20 addresses even though only 10 of them hold non-zero values. But for the most part, you should expect that the sprites must be kept at the same size it was originally or less. To make them larger, you usually need to change the program instructions themselves to account for the additional lines. And that leaves one method...

 

Disassembly:

Programs like HOM and 2600GFX work well to change things that are instantly recognisable...like sprite shapes...but to get farther than that and be able to change the program instructions themselves, you'll need to have a program DISASSEMBLE the contents of the program and translate it into a file that is read at your leisure. The disassembler will translate all of those bytes into the program instructions and data values into a format that is decypherable by lowly humans like us...who have problems seeing the difference between %10111010 and %10011010 in a few nanoseconds.

Instead, the program code will be translated into 3-letter instructions (called menomics...or "memory aids")...as well as any value needed to perform that instruction (called "arguments"). The reason that they are "memory aids" is because it's quite easy to see a difference between STX $8D and STY $8D. Moreso than $86 $8D and $84 8D. In that example instruction, the contents of the X or Y register is being copied to Ram address $8D. STX/STY is the instruction, $8D is the argument. So all of those seemingly random values from the Rom code are translated (or rather, interpreted) to something that we can read more easily. Remember, it makes no difference to the computer. The menomics and hex values exist only to help you read it. So once a program is disassembled, it will no longer run on the computer. The disassembly exists for humans alone. In order to run on the computer, the program would have to be ASSEMBLED...interpreted from all of those instructions and arguments back into the 0's and 1's that the computer can read.

 

Problems with disassembly:

There is one major problem during this automatic interpreting to get a readable disassembly. And that is that the program instructions use the same values that the arguments and data do. $88 is the value of the menominc DEY...but how will the disassembling program know when it's not referring to a data value of $88? How will it know when to insert the letters "DEY" instead of "$88" into the disassembly? Fortunately, all Atari game programs start from a known location. This is listed right near the end of the Rom cartridge memory...and the disassember knows this and begins translating menomics from the address given (and following). When the program branches off to a new address, so does the disassembler...and it converts the values there to menomics also. Anything NOT branched to will be left as values only...listed as ".byte XX" in the disassembly (where XX is the value). In that sense, the disassembler at least tries to do it on it's own. Problems crop up due to the way that some instructions work...

Some instructions' arguments are not literally given in the program code, but rely on the Ram memory to assist (this is called indirect addressing). For example, instead of loading a value FROM ram address $A8, it might be loading the value from the address GIVEN at ram address $A8. This is way too much complexity for a disassembler to handle...and it will miss out on labelling that line. Ram addresses can also be used to hold addresses JUMPED TO! In that sense, entire sections of program code will fail to be interpreted into menomics! Fortunately, there is a solution...

 

Configuration files:

These small files are created by a person PRIOR TO disassembly. In it, all the address portions that the disassembler should interpret as coded menomics are listed, as well as portions to be interpreted as data or graphics. You can add as many portions as there are Rom addresses...and also list where in memory that disassembly is to begin at "on paper". Usually what people do is let the disassember run an automatic version of the listing...and then create a config file after looking though it to check for missed areas. Then the final version of the disassembly is run with the aid of that configuration file.

 

 

 

More? :D

Link to comment
Share on other sites

Correction:

Another register (the status register) contains 8 bits that change depending upon the results of the manipulations happening to those 3 variables. For example...if 2 values are being compared, a bit will be turned on in the status register if they are of equal value.

 

The highlighted should read "off" :P

Link to comment
Share on other sites

Color:

Regarding colors of sprites/gfx, that seems to be one of the most-asked questions when hacking games using a pixel-editor. The simple answer to that method is...you can't. Not unless you already know the specific address of where those values are stored. And the ONLY way to get those addresses is through disassembly...examining where registers are copied to the hardware color locations (those that begin with the letters "COL" in the disassembly). There is no set way of doing it. A game might be reading color values from a table in Rom...for example. Or it might be copying a table to a table stored in Ram (this method is kind of popular...since those ram locations can also include aspects such as if the color/b&w switch is toggled...or the "attract mode" - when colors shift over time when controls are not pressed for a while). Others might be calculating the color value based on some other value (like having the sprite shape itself define the color register value).

To track down where colors are given, the first thing to do is to search for the string "COL". That will point out where colors are saved...and which register is used. STA COLUBK for example is SToring the Accumulator (or "A" register) to the background color register. So then, you would backtrack to find where a value is transferred into the A register. It might be something simple...like LDA #$90 (LoaD Accumulator with a value of $90)...or slightly more complex...like LDA $90 (LoaD Accumulator with the value FROM ram location $90). Notice the difference between those two? That little # symbol means the difference between an actual (immediate) value and a memory location that holds a value. So in the case of the latter, you would have to search the disassembly for areas of the program that is SToring values to that ram location $90.

 

Addressing:

As you look through the program, you might notice that some of the menomic instructions have more than one way of being used. Just like the above example...where that little # symbol spelled the difference between getting a value right away or having to look at some other memory location for it. This is referred to as the addressing mode. If you look at the instruction itself, it doesn't look different between the two (they are both LDA's)...but they are different in the program code. Same instruction, but handling their argument differently. LDA $ramlocation translates to the hex code $A5...but LDA #$thisvalue translates to the hex code $A9. So when the disassembler is creating the text file for you, LDA # is put in whenever it runs into an $A9 (and then the byte that follows gets put next to it as the argument).

I don't want to get too heavily into explaining 6502 coding...since there are already tutorials that do a much better job at that. Just keep in mind that there are a number of 3-letter menomics...and a number of ways that those menomics can be used (i.e. the addressing modes).

 

Here's a link that shows a description of what each menomic attempts to do (click the link in the next thread) and the addressing modes they follow...scroll down a few posts.

http://atariage.com/forums/viewtopic.php?t=5726

[/plug :D]

 

Remember when I said that the computer's memory is like a street with 65536 addresses (the description from MLFB)? With the 2600, that is not quite true...because the 2600 does not use a 6502 chip. It uses a 6507...which is slightly different. The instruction set menomics are all the same...but some of the addressing modes don't operate the same as they do on a 6502-based computer. The biggest difference is that the address bus is not a full 16-bit register. In regular computers, you can LDA $D40F and be confident that the value that will be put into the accumulator is coming from the address $D40F. Not quite the same on the 2600...because the first letter (D in this case) is basically irrelivant. In the Rom code, $D40F is basically the same as saying $40F. The address register only has enough room to deal with 13 bits. Each digit in the hex number takes 4 bits (1 nybble for 4, 1 nybble for 0, and 1 nybble for F). Since the "unused" letter D is not zero, the remaining 13th bit is set and the address becomes one from Rom memory instead of ram. Sorry if that sounds really confusing, but as long as you keep your rom addresses using the same first letter as in the ORG statement, the assembler should have no problems. All this really boils down to is that the 2600 can only deal with 4k of memory instead of the full 64k that is usually standard in most 6502 computers. To work with more than that, the 2600 needs to employ a hardware "trick" known as bankswitching.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...