What's new

Chip 8

aprentice

Moderator
nice job, all you need to do is just include msvcp71.dll and everyone without the 2003 ide can run it :p

so you say you are using a dynarec? are you going to release a document explaining what you have done and how it works?
 

zenogais

New member
Shouldn't need msvcp71.dll, but just in case I've completely recompiled it with no debug functionality whatsoever. I've attached a new version to the last post.

As for the dynarec. I didn't say I was using one, only that I was planning on adding the functionality and ability to use one. And yes I will be releasing a document explaining how the dynarec works.
 

RipNLa

New member
sammyboy said:
ripnla - I only thought that chip8 was black and white, or did you just change the colours on certain roms.

I put in an option to change the color to whatever you want other than white, so black background and whatever color pixels you want. =p Black and white makes me feel old!


Zenogais: Waiting for that Dynarec doc man!
 
Last edited:

zenogais

New member
RipNLa said:
I put in an option to change the color to whatever you want other than white, so black background and whatever color pixels you want. =p Black and white makes me feel old!


Zenogais: Waiting for that Dynarec doc man!

I've already written one, though it was very basic and alot sloppier than my current implementation.

Dynarec Document

My Projects & Tutorials
 
Last edited:

RipNLa

New member
Hmm, that Dynarec document is a good introduction for people like me who have no idea how it works. A suggestion for your next document though. If you could explain the second half more, like purpose/function of the buffer and the emitter functions. I know you did vaguely go over it, but I think something like documentation in the code on the 2nd half would've been helpful. Seriously, I was reading along fine, then the 2nd half came and I just had to stop, and say "...What?"

I'm missing how this is so much faster than an interperter though (which is what I've read everywhere for years it seems). Don't you still have to parse the individual opcodes to find some block of code, function or switch-case, to execute it? And in that case, isn't this basically the same as writing all your switch-cases as assembly instructions? Or am I thinking too high level?

I see the asm call to execute the buffer (and I'm assuming the emitter functions as they are setup, would fill the buffer so it could be executed with a call statement from asm). But if the buffer has to be filled each opcode, that seems like more work than an interperter would have to do.

Yeah..I don't even know if I'm making sense anymore, someone explain por favor =D
 

zenogais

New member
RipNLa said:
Hmm, that Dynarec document is a good introduction for people like me who have no idea how it works. A suggestion for your next document though. If you could explain the second half more, like purpose/function of the buffer and the emitter functions. I know you did vaguely go over it, but I think something like documentation in the code on the 2nd half would've been helpful. Seriously, I was reading along fine, then the 2nd half came and I just had to stop, and say "...What?"

I'm missing how this is so much faster than an interperter though (which is what I've read everywhere for years it seems). Don't you still have to parse the individual opcodes to find some block of code, function or switch-case, to execute it? And in that case, isn't this basically the same as writing all your switch-cases as assembly instructions? Or am I thinking too high level?

I see the asm call to execute the buffer (and I'm assuming the emitter functions as they are setup, would fill the buffer so it could be executed with a call statement from asm). But if the buffer has to be filled each opcode, that seems like more work than an interperter would have to do.

Yeah..I don't even know if I'm making sense anymore, someone explain por favor =D

The implementation in that tutorial wouldn't necessarily be faster. But we're talking about recompiling an entire program into blocks, a block being the number of instructions between successive jump/branches. These recompiled blocks are then "cached", meaning they only need to be recompiled once. Then next time they are arrived upon in the code, the block has already been recompiled and can be executed with no need to interpret the instructions ever again. As for the exact details of how this is done, I'll explain in my next document, but you can figure it out by looking at ChipAssembler.h/.cpp in the NeoChip8 source code.

Basically, it would be like having a precompiled, optimized version, of the Chip8 game in memory generated on the fly. You compile it once and thats it. And you can get as fancy with the optimizations as you like.
 
Last edited:

Doomulation

?????????????????????????
zenogais said:
Here's my scrolling code, it doesn't deal with allocating memory on the heap every call, so it is probably slightly more efficient than your method Doomulation. Although I'm still getting an error with ANT, where after the ground is scrolled completely to the left, the ant is created on the ground so the game shuts down.

EDIT: Fixed the ANT problem.

Code:
void ChipVideo::scrollHorizontal(bool bScrollRight)
{
	//===================================================
	// Calculate The Scrolling Amount
	//===================================================
	unsigned short sScrollAmount = m_fSChipModeOn ? 4 : 2;

	//===================================================
	// Using Scrolling Amount, Scroll Screen Right
	//===================================================
	if(bScrollRight == true)
	{
		for(unsigned int y = 0; y < m_usMaxY; y++)
		{
			for(unsigned int x = 0; x < m_usMaxX; x++)
			{
				if(m_pVideoMemory[(x + (y*m_usMaxX))] && x < sScrollAmount)
				{
					m_pVideoMemory[ ((x + (y*m_usMaxX)) + sScrollAmount) ] = 1;
				} else {
					m_pVideoMemory[(x + (y*m_usMaxX))] = 0;
				}
			}
		}
	} 

	//===================================================
	// Using Scrolling Amount, Scroll Screen Left
	//===================================================
	if(bScrollRight == false) 
	{
		for(unsigned int y = 0; y < m_usMaxY; y++)
		{
			for(unsigned int x = 0; x < m_usMaxX; x++)
			{
				if(m_pVideoMemory[(x + (y*m_usMaxX))] && x >= sScrollAmount)
				{
					m_pVideoMemory[ ((x + (y*m_usMaxX)) - sScrollAmount) ] = 1;
				} else {
					m_pVideoMemory[(x + (y*m_usMaxX))] = 0;
				}
			}
		}
	}
}

Also, finally completed the emulator, should work on almost every game (I haven't tried them all :p ) I've attached the binary, but the source code and everything else is here
It's certainly true that my method was bad concidering the amount of heap allocation. However, I saw no big means to optimize it since the real amount of cpu power was spent elsewhere.


The time has come! Chuit has reached its competion! Almost every game is emulated perfecly. Thus, I'm releasing the latest binary AND the source. I'm now putting down this project. Finished and discontinued.
It has been fun writing this emulator, and I hope it will be fun with the gb emulator I'm working on with some others. I'm releasing the source as-is, without any license. Do whatever you want with it. Take code to your project, make changes to it and compile a new version... it's all up to you. But remember it's lame to steal someone's source and claiming it your own.

To all those who are trying to write their own chip8 emulator out there... I can only say, good luck! And may the source of my emulator help you if you get stuck on something!

Lastly, thanks goes to refraction for all his hard work on fixing the opcodes. Without him, Chuit would still have some way to go :)

All other chip8 emu writers out there... good luck on your emulators!
Remember: the source includes the source files and the libs; not the external libraries. Nor, will the source of those be provided. This should be all you need to compile and run the emulator.

Have phun! :)

EDIT: I just recently figured out how to use colors in labels :O So I added the feature I wanted to have--to be able to change the pixel color! I also found a bug. So I'm re-uploading the source and binary.
Of course, I will still fix bugs if found, as I won't delete my source.
 
Last edited:

zenogais

New member
Ok, I spent a little bit of time revamping my projects website to make it less of an eyesore. I've also added the latest source code for NeoPSX, my Playstation emulator. I just started rewrites last night but I've already got a bit done. Check it out!
 

bcrew1375

New member
Okay, first post here, so let me introduce myself. I'm bcrew1375, I'm a regular at Emuforums, I'm a pretty easy going person, and I've already read the rules :p. Also, hi to refraction, zenogais, and anyone else I know out there. I realize the thread is about a week old, sorry for not posting sooner.

Now, since all of you have been programming Chip8 interpreters, I was wondering if someone could help with a little problem I'm having. In the game "BLITZ", all the building bottoms are wrapping around and ending up on the top. I cannot for the life of me figure out why. I checked the results of all my opcodes, they all are giving the results I expect them to. I've also disassembled the code for the game. The building drawing routine seems to be doing this intentionally! I know the game is not supposed to run this way, so either I'm doing something wrong with one or more opcodes that I've overlooked, or my understanding of the system is flawed. I can post the source if need be. Anyone help with this would be greatly appreciated.

Oh, I have also tested the other Chip8 games and they all run flawlessly.
 

RipNLa

New member
Sounds to me like your DXY0 opcode is flawed. I think Blitz draws all the way to the very bottom (possibly one below the bottom?). You'll have to debug through it to see. I remember when I first moved to SCHIP8 and was drawing an extended view of the screen that when you drop a bomb on a tower, it leaves one block at the bottom, which I didnt see in my Chip8 emu since it was probably out of range. All I can say is to make sure you're checking the screen boundaries, and not just throwing out of range values back through the top of the screen.
 

bcrew1375

New member
Here is my draw sprite routine:

Code:
void DrawSprite()
{
	int j;
	int i;
	unsigned char plotX, plotY;
	unsigned char data;

	// If no collision, default VF to 0.
	V[0xF] = 0;
	
	for(j = 0; j < opcode4; j++)
	{
		data = romBuffer[Index + j];

		for (i = 0; i < 8; i++)
		{
			plotX = (V[opcode2] + i) & 63;
			plotY = (V[opcode3] + j) & 31;

			if ((data & (0x80 >> i)) != 0)
			{
				if (screenData[plotY * 64 + plotX] == 1)
					V[0xF] = 1;

				screenData[plotY * 64 + plotX] ^= 1;
			}
		}
	}
}

The way I handle opcodes is a little strange compared to everyone else. I pretty much split the opcode into 4 nibbles.

Code:
opcode1 = (*(romBuffer + PC) & 0xF0) >> 4;
opcode2 = *(romBuffer + PC) & 0x0F;
opcode3 = (*(romBuffer + (PC + 1)) & 0xF0) >> 4;
opcode4 = *(romBuffer + (PC + 1)) & 0x0F;

I also attached the Blitz source I made. I'm not through documenting it, but it should be pretty easy to understand.
 

refraction

PCSX2 Coder
hmm it may be looking at your code wrong, you need to put in some brackets as it might be seeing the code like PlotY * (64 + PlotX)

try doing this on the lines for collisions and drawing the pixel

Code:
if (screenData[plotX  + (plotY* 64)] == 1)
V[0xF] = 1;

screenData[plotX  + (plotY* 64)] ^= 1;

also this bit i think might be causing problems...

Code:
plotX = (V[opcode2] + i) & 63;
plotY = (V[opcode3] + j) & 31;

The number needs to be modulated, it think it does the same thing but try it as

Code:
plotX = (V[opcode2] + i)%63;
plotY = (V[opcode3] + j)%31;

if that doesnt work try changing the 63 and 31 to 64 and 32.
 

bcrew1375

New member
Tried all 3 of those suggestions. None of them worked. Like I said, maybe my understanding of the system is flawed. When I looked at the BLITZ source, it seems that my interpreter is executing it perfectly.
 

refraction

PCSX2 Coder
hmm its an odd one, i had the same problem, which i fixed by putting the module code in a different place..

try taking it off the plotX = and plotY = lines and putting it here

Code:
if (screenData[(plotY%32) * 64 + (plotX%64)] == 1)
V[0xF] = 1;

screenData[(plotY%32) * 64 + (plotX%64)] ^= 1;
 

bcrew1375

New member
Tried that too, still seems to be no effect. At any rate, I'll post the source here.

Oh, and don't ask about the name :p.
 

refraction

PCSX2 Coder
Right ive had a look and the code seems to work without the module on the plot's, so it would be an idea to leave it off for them, the only place you should need that is on a 16x16 sprite on Field (schip8 game) so that would be seperate code anyway.
 

bcrew1375

New member
If I don't modulate the coordinates, it screws up other games like UFO. I think that also makes it go out of its memory range.
 

Top