What's new

Chip 8

bronxbomber92

New member
Hey, I finally got this thing up and running! ^_^... It goes through with the filebrowser, but then once the path is selected it doens't display anything... I won't post the code. But if you would like to see it then I will post it... I just don't wan't bug you guys any more if you don't want to be :p
 

SG57

New member
Can anyone tell me why nothing displays here?

http://jordansg57.googlepages.com/main.c

Im using double buffering (what doesnt?), changeBuffer = flip the dispaly and draw buffers, Print does what it says, RECT is a structure:

top, left, right, bottom

That determines where on the screen to draw it... 0,0,10,10 would draw from 0,0 to 10,10 a square when calling Fillrect... I absoluetly CANT fnd what is wrong here... Why WOULDNT anything display? I can understand scrambled garbage, but why nothing? does this mean Im loading the ROM wrong, resulting in nothing displayed since.. .well.. thers no data telling it to? Please, someone have a clue?

Thx for everythng.
 

bcrew1375

New member
There's an easy enough way to check if the data is correct. Load the ROM, print out the data, and check it against the actual ROM data in a hex editor. I noticed you used my CPU. You do plan on giving me credit, right? :p
 

Kronox!

New member
Please help with Chip8 Drawing routine

Well my name is Kronox and i'm finally writing a Chip8 Emu...
The main core ---> opcodes , memory etc it's currently done.. the only thing i lack are the graphics [rofl] --> the most important thing though..

I really wanted to know.. How should i code my drawing routine?
I'm currently learning SDL .. but i don't really get how to "Combine" the graphics with the emu itself..

Any help will be apreciated [with examples :bouncy: ^^ ] AHhahah =]

[as you may notice i'm not a native english writer .. so please forgive my crappy english..]

Thanks hehe

Kronox!
 

Doomulation

?????????????????????????
There are good docs that explains how it's done and there is source code and there is a huge chip8 thread. You could probably find a lot of good information there. Why don't you take a look, or search for some docs?
 

Garstyciuks

New member
Code:
case 0xD:
//draw
if (memory.videoMode==0)
{
	x = memory.reg[(opcode&0x0F00)>>8];
	y = memory.reg[(opcode&0x00F0)>>4];
	memory.reg[15] = 0;
	height = opcode&0x000F;
	if (height==0) height = 16;
	memory.Push(memory.I);
	for (j=0; j<height; j++)
	{
		for (i=0; i<8; i++)
		{
			xt = x % 64;
			yt = y % 32;
			if (memory.HWrap)
				if (xt+i>=64) xt-=64;
			if (memory.VWrap)
				if (yt+j>=32) yt-=32;

			if (xt+i<64 && yt+j<32)
			{
				if (memory.vram[(xt+i)<<1][(yt+j)<<1] && ((memory.ram[memory.I]&(128>>i))>>(7-i))) memory.reg[15]=1;
				memory.vram[((xt+i)<<1)+0][((yt+j)<<1)+0] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
				memory.vram[((xt+i)<<1)+1][((yt+j)<<1)+0] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
				memory.vram[((xt+i)<<1)+1][((yt+j)<<1)+1] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
				memory.vram[((xt+i)<<1)+0][((yt+j)<<1)+1] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
			}
		}
		memory.I++;
	}
	memory.I = memory.Pop();
}
else
{
	if ((opcode&0x000F)>0)
	{
		x = memory.reg[(opcode&0x0F00)>>8];
		y = memory.reg[(opcode&0x00F0)>>4];
		memory.reg[15] = 0;
		height = opcode&0x000F;
		memory.Push(memory.I);

		for (j=0; j<height; j++)
		{
			for (i=0; i<8; i++)
			{
				xt = x % 128;
				yt = y % 64;
				if (memory.HWrap)
					if (xt+i>=128) xt-=128;
				if (memory.VWrap)
					if (yt+j>=64) yt-=64;
				if (xt+i<128 && yt+j<64)
				{
					if (memory.vram[xt+i][yt+j] && ((memory.ram[memory.I]&(128>>i))>>(7-i))) memory.reg[15]=1;
					memory.vram[xt+i][yt+j] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
				}
			}
			memory.I++;
		}
			memory.I = memory.Pop();
	}
	else
	{
		x = memory.reg[(opcode&0x0F00)>>8];
		y = memory.reg[(opcode&0x00F0)>>4];
		memory.reg[15] = 0;

		memory.Push(memory.I);

		for (j=0; j<16; j++)
		{
			for (i=0; i<8; i++)
			{
				xt = x % 128;
				yt = y % 64;
				if (memory.HWrap)
					if (xt+i>=128) xt-=128;
				if (memory.VWrap)
					if (yt+j>=64) yt-=64;
				if (yt+j<64)
				{
					if (xt+i<128)
					{
						if (memory.vram[xt+i][yt+j] && ((memory.ram[memory.I]&(128>>i))>>(7-i))) memory.reg[15]=1;
						memory.vram[xt+i][yt+j] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
					}
					if (xt+i+8>=128) xt-=128					{
						if (memory.vram[xt+i+8][yt+j] && ((memory.ram[memory.I+1]&(128>>i))>>(7-i))) memory.reg[15]=1;
						memory.vram[xt+i+8][yt+j] ^= (memory.ram[memory.I+1]&(128>>i))>>(7-i);
					}
				}
			}
			memory.I+=2;
		}
		memory.I = memory.Pop();
	}
}

memory.pos+=2;
break;
This is my drawing function. I think that it can be optimized a lot, etc... This was written almost a year ago :p First it checks if the current video mode is chip 8, or schip. If the video mode is 0, then it's chip8. I'll comment about the chip8 part.
Code:
x = memory.reg[(opcode&0x0F00)>>8];
y = memory.reg[(opcode&0x00F0)>>4];
memory.reg[15] = 0;
height = opcode&0x000F;
if (height==0) height = 16;

memory.Push(memory.I);
This piece of code first finds all the arguments for the opcode, and stores Index register (because it will change in later code). It may be saved in a different place than the stack (0xDxxx instruction shouldn't change the stack), but I just liked this approach better. (the stack isn't changed, because the same value is popped to Index after done drawing).
Code:
for (j=0; j<height; j++)
{
	for (i=0; i<8; i++)
	{
		xt = x % 64;
		yt = y % 32;
		if (memory.HWrap)
			if (xt+i>=64) xt-=64;
		if (memory.VWrap)
			if (yt+j>=32) yt-=32;
xt and yt are transformed x and y positions. This piece starts the loops for drawing the image and makes sure that the sprite won't be drawn offscreen. If some pixels don't fit inside, and if my emulator specific wrapping options are set, the sprite will wrap around the other side of the screen. I found out that some games assumes that the graphics are drawn wrapped, others not. So I made a setting to select whether to wrap or not.
Code:
for (j=0; j<16; j++)
{
	for (i=0; i<8; i++)
	{
		xt = x % 128;
		yt = y % 64;
		if (xt+i<64 && yt+j<32)
		{
			if (memory.vram[(xt+i)<<1][(yt+j)<<1] && ((memory.ram[memory.I]&(128>>i))>>(7-i))) memory.reg[15]=1;
			memory.vram[((xt+i)<<1)+0][((yt+j)<<1)+0] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
			memory.vram[((xt+i)<<1)+1][((yt+j)<<1)+0] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
			memory.vram[((xt+i)<<1)+1][((yt+j)<<1)+1] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
			memory.vram[((xt+i)<<1)+0][((yt+j)<<1)+1] ^= (memory.ram[memory.I]&(128>>i))>>(7-i);
		}
	}
	memory.I++;
}
memory.I = memory.Pop();
This final piece of code updates the screen data (which is stored in memory.vram array). The chip8 images are 8xn size. It means that one row of pixels fit into one byte. And there are n rows. n maximum value is 8. If n value is 0, then the image height is 16. So this piece of code cycles through every bit of image data and updates the vram correspondingly. if (memory.vram[(xt+i)<<1][(yt+j)<<1] && ((memory.ram[memory.I]&(128>>i))>>(7-i))) memory.reg[15]=1; checks for collision. If there is collision, it sets 0xF register to 1. The other four lines update the screen data using xor. In my emulator vram dimmensions are 128x64. So in chip8 mode, to get 64x32 resolution, I had to set 4 pixels.

And once the vram is updated, you can draw the contents of it with any api you like. In my emulator, each value of the array stores the state of the screen pixel. So if vram[5][6] is 1, then you need to display a pixel at x=5, y=6.
 
Last edited:

Cyberman

Moderator
Moderator
Ahem

Well my name is Kronox and i'm finally writing a Chip8 Emu...
The main core ---> opcodes , memory etc it's currently done.. the only thing i lack are the graphics [rofl] --> the most important thing though..

I really wanted to know.. How should i code my drawing routine?
I'm currently learning SDL .. but i don't really get how to "Combine" the graphics with the emu itself..

Any help will be apreciated [with examples :bouncy: ^^ ] AHhahah =]

[as you may notice i'm not a native english writer .. so please forgive my crappy english..]

Thanks hehe

Kronox!
Ummm good question, your english is fine by comparison to some English people. :D
Please do not create new threads when an existing active thread already discuses the topic, if your question is not answered in that topic ask, in that topic. Otherwise there will be 50 threads about the same thing. I'm merging this thread with the Chip8 thread.

Enjoy.

Cyb
 

Kronox!

New member
Garstyciuks: Thanks for all your help .. that was exactly what i was looking for :bouncy:

now!.. finally i can finish my emu :party:

Ahh And Cyberman as for creating a new thread.. Sorry it won't happen again.
And thanks for merging my thread with this one.

Good NIghts and thanks for all your help
Kronox!

-----
Saludos desde Chile ^^ jeje --> greetings from Chile hehe
P.S ---> As for my english... i feel flatered ^^ it all comes from games and emutalk hehe. so as long as you guys write well, i can improve it:bouncy:
 

doomangel

New member
Chip8 - MOV wont change register

I'm quite new to emulation, and i decided to start making one.

I'm already done with making a disassembler, and the renderer has been initialized, but there are bugs:cry:

On 0x60 0x00 which is MOV i've made this code:

V[memory[pc]&0x0F]=memory[pc+1];

The code should move the value of memory[pc+1] to V[x], but it doesn't..

If someone could modify my code so that it would work, i'd be thankful:(
 

Cyberman

Moderator
Moderator
Welcome to emutalk!

I'm merging this to the Chip8 thread since this is related to the chip8.


There may already be an answer somewhere in that thread as well so if you search it maybe you will find it?

However on casual observation I believe that you should instead of reading the 'current PC' information for your opcode, you should store it as a local value.

IE instead of this (which not only is expensive it obfuscates what you are doing, a very BAD practice)
Code:
v[mem[PC] & 0x0f] = mem[PC + 1];
You should extract both the register location AND the value to store in it first.
IE
Code:
#define REGISTER(X) ((X) & 0x0F)
// fetch opcode
OpCode = ProgramMem[PC];
// advance program counter
PC++;
// for this opcode we need to extract a value to store
Value = ProgramMem[PC];
// advance program counter
PC++;
// compute the registerID/variable location
RegisterID = REGISTER(OpCode);
// move the Value into RegisterID memory location
VariableMem[RegisterID] = Value;
This makes your code VERY readable, it could save your job sometime.

By the way what is v? Vector Variable Register space? It's not obvious maybe you should try a less implicite approach to your variable naming?
I'm assuming you have program memory and Variable memory, I could be wrong. I suggest you make your code clear, to find mistakes easier. From personal experience you will spend more time debugging than writting code otherwise.


Cyb
 
Last edited:

hap

New member
What Cyb said, but fetch instructions 2 bytes at a time, and use a mask to figure out what it means, eg. if ((opcode&0xf000)==0x6000) { do_stuff_with_it(); } (for speed, use a switch/case method). From a hardware point of view, some of these don't make much sense, but that's OK, since you're not emulating a CPU: you're handling an interpreted low-level programming language.

(V=CHIP-8 variable, official id for it)
 

virror

New member
Hello, i have been visiting the Chip8 forum for quite some time now. And now i have started on my own emulator. Most stuff is working, but i have problem with fonts and some other stuff, can anyone check my draw function? I know its not the best draw around...

Code:
void draw(void)
{
        char n = 7,a,b;
        char antal = opcode&0xF;
        V[15]=0;
        for(b=V[((opcode&0xF0)>>4)];b<(antal+V[((opcode&0xF0)>>4)]);b++)
        {
                for(a=V[(opcode&0xF00)>>8];a<(8+V[((opcode&0xF00)>>8)]);a++)
                {
                        if((screen[a][b]==1)&&(((mem[i]&(0x80>>a-V[(opcode&0xF00)>>8]))>>n) >= 1))
                                V[15]=1;
                        screen[a%64][b%32] ^= ((mem[i]&(0x80>>a-V[((opcode&0xF00)>>8)]))>>n);
                        n--;
                }
        }

        for(b=0;b<32;b++)
        {
                for(a=0;a<64;a++)
                {
                        if(screen[a][b]>=1)
                        {
                                Form1->Canvas->Pen->Color = 0;
                                Form1->Canvas->Rectangle((150+(a%64*4)),(100+(b%32*4)),(154+(a%64*4)),(104+(b%32*4)));
                        }
                        else
                        {
                                Form1->Canvas->Pen->Color = 15923696;
                                Form1->Canvas->Rectangle((150+(a*4)),(100+(b*4)),(154+(a*4)),(104+(b*4)));
                        }
                }
        }
}
 

Garstyciuks

New member
If other graphics is being drawn alright, then everything is fine with the drawing function (although I haven't checked it :p), the problem with the text drawing may be in the BCD instruction or the instruction which sets index register to correct memory location which contains the graphical representation of some number.

Edit: I looked a bit at your drawing routine.

I found this mistake: you forgot to reset n to 7 after the for (a=.............) loop execution. It should be set above the for (a=........) loop.

And I wanted to give you some advices:

I think that

Code:
if((screen[a][b]==1)&&(((mem[i]&(0x80>>a-V[(opcode&0xF00)>>8]))>>n) >= 1)) V[15]=1;

should be screen[a%64][b%32]. And if I am not mistaking, && operator only returns true or false. So there's no need for >=1. It would be needed if you used & operator only. Also in the if (screen[a]>=1) >=1 is not needed, because the condition is always true when screen[a] has some other value than 0. You should also use some more variables, because it performs more calculations, than it should be doing. And it would be more readable and look nicer :). Here is some common calculations, which could be calculated once per cycle and stored in a variable:

Code:
V[((opcode&0xF0)>>4)]
V[(opcode&0xF00)>>8]
0x80>>a-V[(opcode&0xF00)>>8]))>>n

And in line Form1->Canvas->Rectangle((150+(a%64*4)),(100+(b%32*4)),(154+(a%64*4)),(104+(b%32*4))); %64 and %32 for a and b variables are not needed, because they never exceed those values.
 
Last edited:

virror

New member
I know my draw code is ugly, but i cleaned it up a bit now, but dont get it when you say i have to reset the n variable. I only use it in the (a=...) for loop....

But thanx for the great tips.
 

Garstyciuks

New member
What I meant to say is that n is never set back to 7. It should be reset to 7 here:

Code:
...
for(b=V[((opcode&0xF0)>>4)];b<(antal+V[((opcode&0xF0)>>4)]);b++)
        {
                n = 7;
                for(a=V[(opcode&0xF00)>>8];a<(8+V[((opcode&0xF00)>>8)]);a++)
...
 

virror

New member
Thanx alot! Now i get it, stupid mistake : p Now alot of graphical bugs are gone, and scores are slightly better, but still not good....

Edit: Are the two sub instructions going to give carry? The documents say no, but my emu are working alot better with them...
 
Last edited:

Garstyciuks

New member
I think it should set it. Which documentation are you refering to? The one on wikipedia and on David Winters' documentation both say that it sets carry. From wikipedia:

8XY5 VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
8XY7 Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
 

virror

New member
Found another error in my draw code, i forgot to increase I, so i keept reading from the same place in memory when i was going to draw many lines. This fixed my font problem, but now collision detection is broke instead....
 

Doomulation

?????????????????????????
I think it should set it. Which documentation are you refering to? The one on wikipedia and on David Winters' documentation both say that it sets carry. From wikipedia:

Set carry. The proiblem is that different docs say different, but the opcode should set VF if carry.
 

Top