gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > shift registers?

#55239 - chrissieboy - Mon Sep 26, 2005 9:41 pm

Hi, im busy with learning how the hardware of ds works.
I want to emulate it.

I was starting to read tutorials about how cpu's works, now im busy with make an chip8 emulator.

But they talk alot about "shift registers" they put "<<1" or ">>1" in their code.

Why use this????

example :

10000000 when this is shifted ">>1" the the it becomes 01000000

Why should i use this????????

I realy dont understand why they use this???

I also learned how fixed point works, (because it can speed up the code) this i understand but shift registers why the hell should i use this??

Hope some people can help me because i need to now how all the hardware works!!

thanx in advance!!

chris

#55241 - Mr Snowflake - Mon Sep 26, 2005 10:44 pm

Doing 4 >> 1 is the same as 4/2. Why use this instead of 4/2: It is much faster to bitshift, I also believe the DS has no devision build in the cpu's, so deviding the normal way would require the DS to do a lot more operations, wich means even more preformance lost.
_________________
http://www.mrsnowflake.be

#55244 - agentq - Mon Sep 26, 2005 11:21 pm

Apart from dividing and multiplying very quickly, they can also be used to pack many smaller quantities into a larger value.

For instance, on the arm, 32-bit values are used internally so it is efficient to do:

char a = 0x12;
char b = 0x34;
char c = 0x56;
char d = 0x78;

unsigned int all = a | (b << 8) | (c << 16) | (d << 24);

This gives you:
0x78563412 in 'all'.

#55246 - furrykef - Tue Sep 27, 2005 12:42 am

To be frank, if you don't know the purpose of bitshifting, are you sure you can program an emulator? I don't mean to call you an idiot or anything, it just seems like you have a lot to learn... an emulator doesn't make a good first project, something I learned the hard way eight or so years ago (and didn't fully learn until a couple years later!)

Although I personally hate the bitshifting optimization myself. Compilers a decade old can optimize division into a bitshift. To quote Writing Solid Code by Steve Maguire:

Steve Maguire wrote:
Over the years, I have tracked down bugs in which programmers used shifts to divide signed values that weren't guaranteed to be positive. I've tracked down bugs in which programmers shifted in the wrong direction. I've tracked down bugs in which programmers used the wrong shift count. I've even tracked down bugs in which programmers introduced precedence errors by carelessly converting expressions such as a=b+c/4 to a=b+c>>2. I don't recall ever tracking down a bug in which a programmer meant to divide by 4 and made a mistake typing the characters / and 4.


As agentq pointed out, there are other uses of bitshifting, though, and it's a useful operation to have. I just don't like using it to multiply or divide by powers of two.

I haven't actually examined DevkitARM's output to see if it optimizes division of unsigned values into a bitshift, but since it's a form of GCC, I'd be very surprised if it doesn't.

- Kef


Last edited by furrykef on Tue Sep 27, 2005 5:05 am; edited 1 time in total

#55257 - sajiimori - Tue Sep 27, 2005 3:31 am

If you are dividing by an unknown power of 2, the compiler can't optimize it and you have to do the shift yourself.

#55258 - furrykef - Tue Sep 27, 2005 4:05 am

Yes, that's true, but that doesn't come up so often.

- Kef

#55259 - tepples - Tue Sep 27, 2005 4:26 am

In addition, >> on ARM and most other 32-bit platforms will always round signed values down (toward negative infinity), while the / operator rounds toward zero. Often rounding down is the desired behavior.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#55276 - agentq - Tue Sep 27, 2005 9:51 am

While we're on the subject of shifts, it's worth noticing that on the ARM, shifts are performed as part of an instruction and are therefore completely free.

So let's say you have an array with 4 bytes per element, and the start of the array is in r2, the array index in r3.

To find the address of the element, the CPU needs to do r2 + r3 * 4 and read the data there.

This can be done in a single instruction:

ldr r1, [r2, r3 asl #2]

#55277 - chrissieboy - Tue Sep 27, 2005 11:20 am

agentq wrote:
Apart from dividing and multiplying very quickly, they can also be used to pack many smaller quantities into a larger value.

For instance, on the arm, 32-bit values are used internally so it is efficient to do:

char a = 0x12;
char b = 0x34;
char c = 0x56;
char d = 0x78;

unsigned int all = a | (b << 8) | (c << 16) | (d << 24);

This gives you:
0x78563412 in 'all'.


Sorry for my stupid question but whta does 0x12 mean? and 0x34??

Is this hex or something, because i still don't know how hex works??

#55278 - chrissieboy - Tue Sep 27, 2005 11:40 am

Thanx for helping anyway it makes a lot more sense to me now, but still a lot to learn i think?

im busy with a tutorial about chip8 , this must be the easiest chip to emulate but , im not getting it all.

Code:



 
A simple emulation project: Chip 8 
What is chip 8? 
Chip 8 was never a system as such, instead it was a virtual machine in the 1970s and resurrected in the 1990s on those powerful graphic calculators. Games could be written easily in the Chip 8 langauge, and then executed on any computer than had a Chip 8 interpreter. Therefore, it was kind of like a primitive Java. 
The games 
Chip 8 games are simple but there are many interpretations of classic games; pong, joust, breakout, space invaders and so on. There are also some more modern games such as tetris, and that game everyone has on their Nokia, with the worm chasing its tail. 
 
 
How can Chip 8 help me learn to emulate? 
Writing a Chip 8 emulator is one of the simplest emulation projects you could undertake. The instruction set is very small (about 30 instructions) and include many that you will find when you emulate CPUs for system emulators, such as:
load & store
arithmetic shift
bitwise instructions
jumps and subroutines
When you have written a chip 8 emulator, you could upgrage it to a SCHIP system, which has an extended instruction set and introduces more CPU architecure, such as a stack 
A word of caution 
Despite what i have said, there are some things to bear in mind. When you write a Chip 8 emulator, you are really writing an interpreter. The Chip 8 langauge has, for instance, an instruction that will draw a spite to the screen, and another which will point an addressing register to a built in font. These kind of commands you will not find in any other emulation (I think) but you can safely think of them as if they were just functions provided by a systems bios or graphics chips which is more realistic. There are some also slightly strange features of writing a Chip 8 emulator. For instance, the basic Chip 8 instruction set includes calls and returns, but there is no stack. This means you have to implement a stack as part of the interpreter to store return addresses. Well, its strange, but all good practice. 
Some Chip 8 Roms (freeware) 
tetris
breakout
tapeworm
pong 
Getting Started 
Typically starting to write an emulator, this is the sort of information you should seek to find:
how much memory does the system address? - Chip 8 address 4k, 0x000 to 0x200 are reserved for the interpreter, so will be empty in an emulator
the CPU registers - Chip 8 has 15 8-bit general purpose registers with equal status, named V0,V1...VE. How about making emulation simpler by using an array such as char V[16] to emulate these?
The 16th register VF is equal to the carry flag in other systems
There is also a memory address register, I, and a program counter. Both can be emulated as 16-bit, though they only 0 - 0xFFF.
The systems memory map; It is extremely simple for Chip 8:
0xF?? - 0xFFF built in 4x5 pixel font set, A-F, 1-9.
0x200 - 0xF?? Program Rom and work RAM
0x000 - 0x200 Chip 8 interpreter (see note above)
The graphics system. Chip 8 has 1 instruction which draws sprites to the screen Drawing is done is XOR mode and if a pixel is turned off as a result of drawing, the VF register is set, and this way the game knows there has been a collision on screen. How are you going to get this feedback? how about holding an array of all screen pixels, since the screen is only 64x32 pixels.
chip 8 graphics are black and white and 1-bit encoded.
interrupts and hardware registers. Chip 8 has none, but it does have two timer registers called delay and sound timers which count about 60 times a second when set above zero until they reach zero.
The sound delay register form the basis for a very simple sound system. The system's buzzer sounds whenever the timer is zero.
 
Stage 1 
Ok, so chip 8 addresses 4k of memory. In a more advanced emulator, where you may have mirroring, hardware registers, banked memory and so on, the most practical solution may be to split the different types of memory (ie. rom, ram, i/o, etc) into separately emulated memory regions and use memory read and write handlers (routines) to let the CPU access these areas as a continual memory space. You will also find it faster to allocate memory and reference it with pointers than to emulate memory with arrays.
However, with the simplicity of Chip 8, and its age (believe me, you will have to TRY to slow this thing down!), the simplest solution is to use a single array.

unsigned char memory[0xFFF];

I have set up the memory as the char variable type, that is, 1 byte. Why have I done this when all chip 8 instructions are two bytes long?? Well, if part of the code is data (ie. sprites) and there is not an even number of bytes, then instructions will become unaligned and you will not be able to read them properly if you allocate memory in two byte portions. This is a nice introduction to memory alignment; in 16/32/64...bit emulation having to accomodate unaligned memory accessing can have serious implications for emulation speed. 
Stage 2 
Now, you are essentially ready to write 'CPU' emulaton! Refer to the end of this page for information on where you can find the full Chip 8 instruction set. Lets take the instruction:

6XKK - register[X] = KK

now this is an opcode you will come accross in any CPU you emulate, it would normally be called something like 'load register with 8 bit immediate'. Since we are not concerned about speed in this emulator, how about the following to execute this opcode;

opcode = ((memory[PC]<<8) + memory[PC+1]); (this is just to form the full opcode)

V[((opcode&0x0F00)>>8)]=opcode&0x00FF;

Remember that we have emulated all the general register in an array, so we can write to the correct register by manipulating the opcode which contains information about the register affected. In this way, all the 6--- opcodes can be emulated in one line instead of 15. For a more demanding emulator you will want to trade compactness for speed, so this would not be a very good idea. Just to clarify the method used to find the registers concerned in an operation, say the opcode is 6XKK, X denotes the register, from 0 to E (maybe F, but I don't think writes to the that register are done). If, say, X=A, so the opcode is 6AKK, we must isolate X with a logical AND; opcode&0x0F00 gives us 0A00. But this would equal 2560, so we shift the figure 8 positions to the right to give us 000A, and thus V[000A] is the register we want. 
The general layout of your cpu could take the following form:

cpu(){
opcode = ((memory[PC]<<8) + memory[PC+1]);
switch (opcode&0xF000){
case 0x6000: ...code as above...PC+=2;break;
case:...break;
case:...break;
}
}
PC is a variable defined to emulate the system's program counter. As i said before, each chip 8 instruction is two bytes long, so that is why it is incremented by 2 after the opcode. 
Ok, lets take another instruction.
8XY6 - register[X] = register[X] shifted right 1 position, VF= carry
This is another extremely common CPU instruction. Binary shifting is used as a means of multiplication and division, especially before the modern CPUs which have specific instructions for multiplication and division. Shifting 1 position to the right is the same as dividing by 2, shifting 1 position to the left is the same as multiplying by 2.

V[F]=(V[((opcode&0x0F00)>>8)]&0x1);
V[((opcode&0x0F00)>>8)]>>=1;

Since the VF register is to take the carry, which is the displaced bit shifted out of the right hand side of the operand register, the most obvious thing to do is to find out what this bit is before the shift is done, otherwise it will be lost! This is what the first line above is doing. Then the register (again, we identify the correct register by shifting the opcode), is shifted 1 position right using the C >> syntax. simple huh? If you are lost at this point it is probably because a) i am bad at explaining myself, or b) you do not understand shifting and logic. Not only are these things essential to CPUs, a firm grasp of them is also essential for programming, especially emulator programming! 
Ok, one last instruction.

5XY0 - skip next instruction if register[X] = register[Y]
Not a totally authodox instruction, but similar to a conditional branch which you will find all the time. Again, both registers concerned are contained in the opcode, so;

if (V[((opcode&0x0F00)>>8)]==V[((opcode&0x00F0)>>4)])PC+=4;else PC+=2;

got that?. If the condition is true, we skip the next instruction, which means skipping 4 bytes, otherwise, we move two bytes forward to the next instruction as usual. 
Stage 3 
A small note before we preceed: normally, you would try to emulate the timings of your CPU, usually in terms of machine cycles. This is generally so that you can draw the screen and emulate sound at the correct relative intervals. However, there is no information on the timings for the Chip 8 instruction set (and remember, it was never a real machine!). Therefore, don't worry about timings, In my emulator i just ignored timing altogether with no obvious ill effects. 
So you now have you complete CPU emulation, with perhaps the exception of the sprite drawing opcode. Usually it is possible to completely separate the emulation of the CPU from the emulation of the system, and combine the two when you feel ready, though in the case of Chip 8 they are inter-connected.
So we need to think about the chip 8 graphics. The display is 64x32, so you will probably not want to plot pixels at this resolution becuase the display will look tiny. In addition to this you need to think about how you will emulation the XORing nature of the graphics. If you do not know what XOR means, you will need to find out about this and other logic instructions. However, to explain here, XOR means exclusively or. Thus, take the following 8 bit binary numbers;

10011011
01111100 XOR =
--------
11100111
--------
Thus, for a given position in the result, if either or both binary digits are a 1, then the result will have a 1, but if both are 1, the result will be zero. In terms of the screen, this means that pixels are toggled on and off by drawing to the screen. That is, writing to a pixel that is off will turn it on, but writing to a pixel that is already on will turn it off.
Before going on to explain the screen emulation, we need to think about how screen information is encoded. Chip 8 graphics are 1 bit encoded, which means each pixel is represented by one bit in a byte. Bit encoding is extremely common, but typically, at least two bits (as in gameboy) will be associated with each pixel to achieve a greater colour range.
With one bit encoding, take the byte
10011110
Each bit that is 1 represents a pixel turned on, (ie. white), and each bit that is 0 represents a pixel that is off (black). Several bytes are used to diplay an image; e.g.
1111000,0001000,0001111 would result in a spite which looks like this:


   ****   
      *
      ****
   
Which you may recognise as a tetris shape (sort of).
I am not going to spend a lot of time on Chip 8 graphics because they are not particularly representitive of general emulation, but as I will eleborate a litlle. 
If we set up an array to represent the screen;
unsigned char screen[60*32];

Now the CPU sprite drawing opcode can be written so that the sprite is drawn into the array. This way it is easy to test for collisions on the screen and set the VF register accordingly. You can write a routine that draws the actual screen from the array, and you will probably want to expand each pixel into a primitive (ie. a square) to make the screen more visible.
 
Decoding bit encoded graphics 
How can this be done?. The sprite opcode takes the following form

DXYN - draw sprite starting at coordinates held in register[X] (x axis), and register [Y] (y axis). The sprite data begins at location pointed to by the I register which will have been set by the game before this opcode is called. The sprite is 8 pixels by N pixels. So that N is 3, and starting at I we have the information give previously, which drew the tetris shape.Consider the following simplified routine

for (yline=0;yline<(opcode&0x000F);yline++){
data = memory[I+yline]; //this retreives the byte for a give line of pixels
for(xpix=0;xpix<8;xpix++){
if ((data&(0x80>>xpix))!=0){
if (screen[V[X] +(V[Y]*64)]==1) V[F]=1 //there has been a collision
screen[V[X] +(V[Y]*64)]^=1; //note: coordinate registers from opcode
}
}
}

With any luck this routine should draw sprites into your screen array!. You may wonder about the data&(0x80>>xpix) test. Well this tests the 'data' variable against 0x80 (bit 7) then 0x40 (bit 6), then 0x20(bit 5) and so on, so each bit is being evaluated from left to right. This happens because the AND operand, 0x80, gets shifted right on each loop.

 
In case you have not noticed, all chip 8 graphics are sprite based. In just about any other emulator you will also have at the very least one background layer, often more. Thinking about some of the peculiarities of Chip 8 opcodes, I believe the Atari 2600 does have some similar things. I believe there are register specifically for tracking missile spites accross the screen!!

Since graphics are only sprite based, after a sprite has been plotted to the screen array, it would be ok to then draw the whole screen. As I said before, I am not going to discuss this because it is simply a case of reading through the screen array and plotting pixels according to whatever graphics system you are using. 
Step 4 
We are now ready to emulate user input. The Chip 8 system uses a hex keypad, so only accepts 0 to F. In general emulation you will need to identify the registers which deal with input devices, and these will typically need to be updated constantly, such as once per screen refresh. This is not necessary for chip 8, because there are specific opcodes which wait for a screen press and store it in a given register. When you program these opcodes, create a loop which checks the keys you havce decided to map to the Chip 8 keypad. When a key is found to be pressed, store the number it represents (i.e. 0-F) in the register identified by the opcode, then break the loop. 
Step 5 
Finally, I think you have everything readty to make the emulators main emulation loop.
Once again, speed is not at all crucial in this project. In my emulator I have had to put in several delay mechansims to slow it down to a playable speed. However, we still want to learn some good practices, so make the main loop along these lines;

for (;;){
//call cpu to execute instructions, etc
}

Although this is an infinite loop and might generate compiler warnings because any code following the loop is unreachable, but this is the most effective thing to do. Why? Well this unconditional loop does not have to perform checks on each pass of the loop, so in theory is faster than say


do{
//call cpu to execute instructions, etc
}while(exit==0);

because 'exit' must be tested on every loop. The main emulation loop is running thousand of times a second and unneccesary tests on each pass are not efficient. Instead, when we want to exit the loop we will explicitly breakout of it rather than officially terminate the loop.
What goes in the loop? Well since we are not really bothering with proper timing, you will have to play around a little, but in general, an inbeded loop should run the CPU for a given number of executions, then the keyboard can be checked for exit commands, and a function to draw the screen can be called (although you may decide to draw the screen after each sprite is drawn). Experiment with the size of this imbeded loop untill the emulator is sufficiently responsive to the exit command.

One other thing to take into account is the delay and sound registers which I mentioned earlier. These need to be counted down if non zero, so this can be done in the main loop, and again the inner cpu loop should be made the correct size so that the timers count down roughly at the right speed, which is 60 times a second.

for(;;){
for(cpu=0;cpu<5000;cpu++){ //some arbitrary number of loops
cpu();
}
if (delay_register>0)delay_register-=1;
if (sound_register>0)sound-register-=1;
if exit key pressed, exit(0);
}

One thing to bear in mind for a larger emulation project; in the case above, the CPU function executes only one instruction. However, you could minimise the number of function calls by programming the CPU function to emulate a given number of instructions itself. The number will be based on the timing of the emulator which is not being discussed hear, but typically it may be equivalent to the number of machine cycles the real machine takes to draw one line to the screen, because this is typically the smallest common divisor and all other counters and timed events can be based around multiplies of this amount of time. 
Step 6 
Perhaps this stage should have come much earlier, as it regards loading a Chip 8 rom. As we know, the first 0x200 bytes of the Chip 8 memory map would contain the interpreter, so the game should be loaded starting from 0x200 onwards. Simply open a rom file in binary reading mode and copy the whole file into the memory array. Be very careful the rom is not loaded even 1 byte out of line, because then all jump instructions will land at the wrong place. 
Conclusion 
Hopefully you have everything you need here, and in the document available at the link below, to program your own Chip 8 emulator, and get playing Pong!. If you manage to do this, you will be equiped to start a bigger project, though you will find lots of complexities to deal with! Good luck. 
Confession Time 
Ok, despite everything I have said, there is one opcode in Chip 8 which I have not been able to get right. It is meant to store a binary coded decimal representation of a value held in a specified register, at memory locations I, I+1, and I+2. I take this to mean a non packed binary decimal representation, in which three bytes would be needed to represent a number above hex 99. Well, this does not seem to work. Don't worry too much about this though, you will find it is generally only used to calculate the scores in the games, and is not very crucial. 
Documentation 
For more details of the Chip 8 instruction set and how to emulate the Chip 8 'system' David Winter's Chip 8 doc has everything you need. In order to regard his wishes, I have not split the document from his Chip 8 emulation package. You can download it instead from his homepage 
 


the whole bit things i think i understand , but the hex thing i think i don't understand

they wrote a line like this one : unsigned char memory[0xFFF];
What does 0xFFF means? because i only know bits like : 01000100
and they talk about 0xF?? - 0xFFF ??

what is 0xF??
this doesn't make any sense to me?

I know that hex is 1,2,3,4,5,6,7,8,9,a,b,c,d,e,f

But the ? i doesn't know in the hex system?

Why they doesn't only use bits?

Maybe it's simple but i doesn't understand Please HELP!

#55280 - NoMis - Tue Sep 27, 2005 12:25 pm

0x Means that the following numbers will be specified in hex. So a value of 0xFFF for example means that you are specifing the hex value FFF.

FFF hex would be 4095 dec

Therefor a line like this:

Code:
unsigned char memory[0xFFF];


would specify an array with 4095 items and be the same as this

Code:
unsigned char memory[4095];

_________________
www.gamedev.at - The austrian gamedev site
hde.gamedev.at - The Handheld Dev Env plugins for Eclipse

#55283 - chrissieboy - Tue Sep 27, 2005 12:53 pm

so if it is :

unsigned char memory[0xFFFF];

then it becomes : unsigned char memory[65536];

This is to make an array with 65536 items?


can i also make it smaller like this ? :

unsigned char memory[0xFF];

then it becomes : unsigned char memory[256];


so they do this to emulate the memory in an array of the chip8 i think?

#55284 - chrissieboy - Tue Sep 27, 2005 1:21 pm

i just red that an unsigned char is a letter, so if i give an usigned char number 65 it prints the letter : A because this is the ascii code.

With this :
unsigned char memory[0xFFF];

so it makes an array from memory[0x0 to 0xFFF] ? Right?

but i just red that an unsigned char is a letter? it makes a number 65 an ascii character : A

So if it becomes memory[0x65] ?
in the theory of me it makes memory[0xA]

Hex A is 10 in decimal or am im stupid?

So it makes in my theory an item in an array memory[10]

So then it goes the wrong way???


Maybe im very stupid but i need to understand it

thanx for all your help anyway guys!!

#55288 - NoMis - Tue Sep 27, 2005 2:04 pm

Right the unsigned char memory[0xFFF] is used to emulat the chip 8 memory that is 4kb. Thats why they make an array of 4048 items and use the char datatype.

Quote:
so it makes an array from memory[0x0 to 0xFFF] ? Right?


It just creates an array of 4048 char items on the stack.

Quote:
but i just red that an unsigned char is a letter? it makes a number 65 an ascii character : A


Char is also used for ASCII codes thats why it will be printed out as the letter representation but it's really just representing 1 byte of memory and you can work with it as it were a number from 0 to 255.

Quote:
So if it becomes memory[0x65] ?
in the theory of me it makes memory[0xA]


Maybe I don't understand the question but memory[0x65] and memory[0xA] are referencing 2 different locations of memory.

Quote:
Hex A is 10 in decimal or am im stupid?


Yes, a Hex value of A is 10. So memory[0xA] is referencing the 11th Item in the memory array (because it starts with 0).

NoMis
_________________
www.gamedev.at - The austrian gamedev site
hde.gamedev.at - The Handheld Dev Env plugins for Eclipse

#55294 - Zerot - Tue Sep 27, 2005 3:09 pm

For more info on numbers and bases: http://en.wikipedia.org/wiki/Numeral_system#Bases_used

#55332 - tepples - Tue Sep 27, 2005 8:01 pm

chrissieboy wrote:
iWith this :
unsigned char memory[0xFFF];

so it makes an array from memory[0x0 to 0xFFF] ? Right?

No. It makes an array from memory[0x0 to 0xFFE]. When specifying an array, you must specify one more than the number of the highest-numbered element.

Quote:
but i just red that an unsigned char is a letter? it makes a number 65 an ascii character : A

So if it becomes memory[0x65] ?
in the theory of me it makes memory[0xA]

Hex A is 10 in decimal or am im stupid?

'A' and 0x0A are completely different:
  • 'A' (character codepoint) = 65 = 0x41
  • 0x0A (number) = 10
Likewise with '1' and 0x01:
  • '1' (character codepoint) = 49 = 0x31
  • 0x01 (number) = 1

_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#55336 - TheChuckster - Tue Sep 27, 2005 8:35 pm

Generally ?s mean that someone is unsure about something.

Quote:
What does 0xFFF means?


You said you knew hex.

#55337 - chrissieboy - Tue Sep 27, 2005 8:55 pm

cool it al starting to make sense for me right now!!

the only i don't understand is why they use now hex?? first they all talked about bits and bytes and now they start talking about hex?

Is this because the chip8 specs talk about hex? So they use the same as the chip8 specs?

and another thing :

Code:

opcode = ((memory[PC]<<8) + memory[PC+1]); (this is just to form the full opcode)

V[((opcode&0x0F00)>>8)]=opcode&0x00FF;


im going to translate this code for my self

lets say memory[pc] = 2 right now

the code becomes :

Code:

opcode = ((memory[2]<<8) + memory[2+1]); (this is just to form the full opcode)


so the opcode is for me now : 2<<8 = 2x2x2x2x2x2x2x2 this is 256

and 2+1 = 3

the sum of this is : 256+3 = 259
so the opcode is now259 ? right?

Code:

V[((opcode&0x0F00)>>8)]=opcode&0x00FF;


becomes :

Code:

V[((259&0x0F00)>>8)]=259&0x00FF;


0f00 = 3840
00ff = 255

then it becomes :

259&3840 = 4099
4099 >>8 = 4099/2 /2 /2 /2 /2 /2 /2 /2 = 16.01171875

and

259 + 255 = 513

this makes the code :

Code:

V[16.01171875]=513;



but what is the meaning of first shifting 8 left , and then they shift 8 right?

Only because the code becomes faster? and makes less cpu cycles because of shifting, then when it is not done?

Can you guys also tell me if my translation of the code is good or bad?

and : V[16.01171875] does the code make this v[16] by rounding? or not?

Sorry for all the questions but im dutch, and some things in english does not make sense in english for me.

#55350 - agentq - Tue Sep 27, 2005 10:23 pm

I think you're missing quite a few important points here, but I'll try an explain what your piece of code means.

A number can be written in any number format. Decimal, hex, binary, it all means the same. Binary is useful because it represents well the wires inside a computer that carry the number. Each wire has voltage on it or not, so a 1 and 0 can represent this.

Hex is useful because each hex digit represents four binary numbers. So

F = 1111
E = 1110
D = 1101
C = 1100
B = 1011
A = 1010
...
3 = 0011
2 = 0010
1 = 0001
0 = 0000

So if I have a hex number 0xAB12 it is the same as 1010101100010010 in binary, but a lot easier to read!

This means 0x12 is an 8-bit number and will have 8 binary digits, 0x1234 is 16-bit, 0x12345678 is 32-bit and so on.

Now I'm going to have a go at explaining the code you mentioned.

Code:
opcode = ((memory[PC] << 8) + memory[PC + 1]);


'memory' is an array with 0xFF (255) elements. That means that there are 255 numbers inside memory. As the array contains chars, this means each element is 8-bits. So we might have this:

memory[0] = 0x23;
memory[1] = 0x78;
memory[2] = 0x9A;
...
memory[255] = 0x10;

The code looks at memory[PC] and memory[PC + 1]. So if the variable PC is equal to 1, we have memory[1] and memory[2].

Looking at 'memory[PC] << 8', we're using a binary shift to shift the number left by 8 bits. In the example above, we have memory[1] being 0x78. Shifting left by 8 bits gives us 0x7800. Numerically, we have just multiplied the number by 256. In hex, this means we add two zeros onto the end of the number, as each hex digit represents four binary digits (remember?).

Now we add on memory[PC + 1], or memory[2] in this example. That's equal to 0x9A, so now we have 0x7800 + 0x9A = 0x789A. So what we've done is stick the two values together into a 16-bit number and stored that in a variable called 'opcode'.

This is because the opcode is 16-bits long and stored in two memory locations. We need to stick it together so we can process it.

So, the next line:
Code:
V[((opcode&0x0F00)>>8)]=opcode&0x00FF;


This one is a bit harder.

Here we have V, another array, this one can hold 16 numbers, in v[0] to v[15]. We are calculating which number we are storing using this:
Code:
((opcode&0x0F00)>>8)


So we have opcode, which is 0x789A & 0x0F00. The & here isn't an add. It's a logical AND. This is an operation where each binary digit is compared with the same digit in the other number. The result is a 1 when both numbers contained a 1 in that position.

So, to take a random example:
Code:

 10101100 (or 0xAC)
&11001011 (or 0xCB)
=10001000 (or 0x88)


In our case, 0x789A & 0x0F00 = 0x0800. The F in the number is used to mask out all the other digits and left only the second 4 bits. These four bits are then shifted right 8 bits. So 0x0800 >> 8 = 0x0008. So we are storing to V[8].

Next we have 'opcode & 0x00FF'. This is much the same. 0x789A & 0x00FF = 0x009A.

So our completed line is:
Code:
V[8] = 0x9A;


And we have now translated the opcode.

I hope I have made this clear. There may be a lot to learn but don't be put off! It's not all that hard really. There will be lots of places on the next to learn this stuff, but I don't really know of any myself. Try a search for 'computer architecture'. I had great fun when I learnt this stuff and hopefully so should you!

#55401 - joewandy - Wed Sep 28, 2005 6:48 am

I have to compliment everybody (agentq, tepples, etc) who patiently explained basic concepts like bitshifting, array addressing, etc. :)

#55409 - chrissieboy - Wed Sep 28, 2005 10:45 am

agentq!!!!! thank you very very much, it was fun to read.
And almost all the questions i had with this are answered!!!!!

Now i understand it almost!! This makes me very happy, now i don't have to think the whole time : am i doing it right or completly wrong??

I want to thank you for your knowlegde and time!

It's also a lot easier if some explains than when i must read it with minimum of text.

Hope this is also usefull for other devolopers, but i'm sure it is!!