What's new

Chip 8

GbaGuy

New member
char ucBCD1 = m_pMemory->getRegister(ucRegister)/100;
char ucBCD2 = (m_pMemory->getRegister(ucRegister) - (100*ucBCD1))/10;
char ucBCD3 = (m_pMemory->getRegister(ucRegister) - (10 *ucBCD2));


shouldn't that last one be:
char ucBCD3 = (m_pMemory->getRegister(ucRegister) - (100*ucBDC1) - (10 *ucBCD2));
?

otherwise, say getRegister returns 253:

BCD1 = 2
BCD2 = 5
BCD3 = 253 - ((10*5)==50) = 203...

Did I miss something? I never use BCD so I could be completely off here...
 

refraction

PCSX2 Coder
zenogais said:
Hehe, well I've just fixed the BCD encoding for NeoChip8, and I figured I'd share the solution as this is a common problem:

Code:
        //==================================================
	// Write BCD Encoded Value Of Register To Memory
	//==================================================
	case 0x33:
		{
			unsigned char ucRegister = (m_cpuContext.opcode&0x0F00)>>8;
			// Calculate BCD Encoding
			char ucBCD1 = m_pMemory->getRegister(ucRegister)/100;
			char ucBCD2 = (m_pMemory->getRegister(ucRegister) - (100*ucBCD1))/10;
			char ucBCD3 = (m_pMemory->getRegister(ucRegister) - (10 *ucBCD2));
			// Write BCD Encoded Values
			m_pMemory->writeByte(m_cpuContext.I    , ucBCD1);
			m_pMemory->writeByte(m_cpuContext.I + 1, ucBCD2);
			m_pMemory->writeByte(m_cpuContext.I + 2, ucBCD3);
		}
		break;

umm that makes the p2 score dissapear in pong when P1 reaches 10.

this code seems to work the best, as i had when i gave you the code :p


Code:
case 0x33:
		{
			unsigned char ucRegister = (m_cpuContext.opcode&0x0F00)>>8;
			m_pMemory->writeByte(m_cpuContext.I,     (m_pMemory->getRegister(ucRegister)/100));
			m_pMemory->writeByte(m_cpuContext.I + 1, ((m_pMemory->getRegister(ucRegister)%100)/10));
			m_pMemory->writeByte(m_cpuContext.I + 2, (m_pMemory->getRegister(ucRegister)%10));
		}
		break;

altho there is aproblem with the scores, the source of pong says it checks V3 to see if it should add 10 or 1 to the score.. but it doesnt do it properly. oh well :p
 

Doomulation

?????????????????????????
aprentice said:
are you doing any pixel enlargements? if you are, you lose your speed down to playable because of it :p

My chip8 emu would be lightening fast if i wasnt doing any pixel enlargements in the video core due to my cpu core being highly optimized (to make up for the speed loss in the pixel enlarger).

A solution would be to use quads, which would bring it back up on speed.
Yes, I use enlargment. I use two traingles for every pixel, because I can't see how to use quads. As far as I can see, d3d doesn't support them, even though the hardware does.

The time is wasted in pDevice->DrawPrimitive.

Btw zenogais, refraction has pretty much worked on that system 24 hours a day without ANY work on any other project :p He's like... possessed :evil:
 
Last edited:

zenogais

New member
Doomulation said:
Yes, I use enlargment. I use two traingles for every pixel, because I can't see how to use quads. As far as I can see, d3d doesn't support them, even though the hardware does.

The time is wasted in pDevice->DrawPrimitive.

Btw zenogais, refraction has pretty much worked on that system 24 hours a day without ANY work on any other project :p He's like... possessed :evil:

I dunno, it works very well here. But BCD encoding is only used for storing of scores as far as I can tell.

EDIT: Whoops, there was a math error in the old BCD encoding, heres the new technique, works exactly as it should (refraction tested it mmm k :p )

Code:
        //==================================================
	// Opcode: 0xFX33 - Store BCD Encoding Of VX At I
	// Write BCD Encoded Value Of Register To Memory
	//==================================================
	case 0x33:
		{
			unsigned char ucRegister = (m_cpuContext.opcode&0x0F00)>>8;
			// Calculate BCD Encoding
			unsigned char ucBCD1 = ((m_pMemory->getRegister(ucRegister)/100));
			unsigned char ucBCD2 = ((m_pMemory->getRegister(ucRegister) - (ucBCD1*100))/10);
			unsigned char ucBCD3 = ((m_pMemory->getRegister(ucRegister) - ((ucBCD1*100) + (ucBCD2*10))));
			// Write BCD Encoded Values
			m_pMemory->writeByte(m_cpuContext.I    , ucBCD1);
			m_pMemory->writeByte(m_cpuContext.I + 1, ucBCD2);
			m_pMemory->writeByte(m_cpuContext.I + 2, ucBCD3);
		}
		break;

Also, sometimes DrawPrimitiveUP can be faster than DrawPrimitive.
 
Last edited:

Doomulation

?????????????????????????
Indeed, it was faster. Thanks for the tip zenogais.
But I'd want to speed it up more! :p After all, this is an ancient machine!
 

zenogais

New member
Run a profiler, unless you've got a really poorly designed drawing routine, Direct3D shouldn't be the bottleneck.
 

Doomulation

?????????????????????????
I have. I've pretty much optimized all my code. I made a lot of functions inline... removed some code... and such. The profiler shows almost all cpu power spent in the draw function.
And even so, when I comment out the drawprimitive functions, I gain a big noticeable speedup.
Now this is truly a mystery to me.
I tried to look for a way to disable all the passes done in the pipeline to no avail. I mean, it pretty much just has to show the damn contents on the screen!
 

zenogais

New member
If you could send me the source ([email protected]) code or post it, I can have a look and try to speed it up. Also inlining alot of functions isn't necessarily the best idea, as it just bloats the executable and may even slow the program down. I would only inline functions that have a high hit rate(called very often i.e. >= 40% of all calls), everything else would not benefit from inlining.

EDIT: Here's the official NeoChip8 website I started last week. You can find doxygen documentation, the latest sources, and an image of Space Invaders working. I've managed to get sound working as well (Thats the executable I've attached).
 
Last edited:

RipNLa

New member
Hey Doomulation, this might be a stupid suggestion, but are you calling the Render function after every op? I was doing that before I realized I only really have to call it on the drawsprite op
 

refraction

PCSX2 Coder
RipNLa said:
Hey Doomulation, this might be a stupid suggestion, but are you calling the Render function after every op? I was doing that before I realized I only really have to call it on the drawsprite op


yeh i realised that as well, only call it on the drawing command and scroll commands if you have SChip8 implemented.
 

refraction

PCSX2 Coder
zenogais: cheers for that bit of code mate! i didnt quite have my shift right correct that was causing my problem in Blinky!!! so now every game works, plus i implamented sound on it from your source, and the sound triggers almost everytime its suppose to ;p altho on occasion it sounds a bit retarded.
 

Doomulation

?????????????????????????
RipNLa said:
Hey Doomulation, this might be a stupid suggestion, but are you calling the Render function after every op? I was doing that before I realized I only really have to call it on the drawsprite op
It doesn't. It only draws on the draw op and the scroll ones.
Zenogais: I found that your suggestion took away all load from the draw function. In my profiler, it takes 0% of the cpu time. The slow code lies elsewhere now... mostly, it seems th cpu takes about 75% of the time. Maybe some ops could be optimized, but those heavily called are mostly the scrolls and draw (I've mostly tried car).

Actually, I think I'll try to merge some of the ops of neochip8 first. Then I'll update my documentation. Then I can post the source.
I'll probably re-write this emulator from scratch later, as copying off others ops aren't fun.


EDIT: Here's the new source. Just watch out, some games run darned fast =)
I also updated the DirectInput library for more speed. So be sure to grab this as well. And don't forget you still need the d3dfont.dll library found in the previous build (I haven't touched it).

EDIT2: You probably want the lib headers too so you can compile the source.
 
Last edited:

zenogais

New member
I've tried to make my version of NeoChip8 as portable as possible, which is why I am also working on writing a function similar to Beep() for Linux users. I've found a way and am currently implementing it into my source code. Here's the Linux version of Beep:

EDIT: Whoops, made some mistakes, here ya go:

Code:
#if defined(__LINUX__) || defined(__MACOSX__)

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kd.h>

#define DWORD unsigned long

void Beep(DWORD dwFreq, DWORD dwDuration)
{
	int fd, arg;

	fd = open("/dev/tty0", O_RDONLY);

	arg = (dwDuration<<16)+(1193180/dwFreq);
	ioctl(fd,KDMKTONE,arg);
	usleep(dwDuration * 1000);
}

#endif
 
Last edited:

Doomulation

?????????????????????????
I noticed in refraction's source, your scroll op isn't perfect. This is noticeable in spacefic. Don't know if it's in others.
You need to check so that it doesn't wrap to another line when it goes outside the screen.
Here's mine so far which seems to work:

Code:
case 0x000B: // Scroll screen 4 pixels right
	byte temp_screenr[128*64];
	int scroll_right; scroll_right = bExtendedScreen ? 4 : 2;
	ZeroMemory(temp_screenr,sizeof(temp_screenr));
	for (int i=0; i<64; i++)
	{
		for (int j=0; j<128; j++)
		{
			if (screen[i*128+j])
				if ( ( (i*128+j) + scroll_right ) < ( (i+1)*128 ) )
					temp_screenr[(i*128+j)+scroll_right] = 1;
		}
	}
	memcpy(screen,temp_screenr,sizeof(screen));
	RenderScreen();
	return;
case 0x000C: // Scroll screen 4 pixels left
	byte temp_screenl[128*64];
	int scroll_left; scroll_left = bExtendedScreen ? 4 : 2;
	ZeroMemory(temp_screenl,sizeof(temp_screenl));
	for (int i=0; i<64; i++)
	{
		for (int j=0; j<128; j++)
		{
			if (screen[i*128+j])
				if ( ( (i*128+j) - scroll_left ) >= (i*128) )
					temp_screenl[(i*128+j)-scroll_left] = 1;
		}
	}
	memcpy(screen,temp_screenl,sizeof(screen));
	RenderScreen();
	break;
 

RipNLa

New member
Hey, quick question.. I put the SCHIP stuff into my emulator today and have a few little problems to iron out. On the game ALIEN, right as the actual game is going to start, my emu hangs on opcode 0xF030..and in CAR, if I beat the level (cross finish line) my emu hangs on that same opcode, 0xF030. As far as I can tell, that opcode isn't documented... I put in a skip call for it, and ALIEN went on with the game =\ I forgot what other games, but one or two other games hit the same problem eventually as well =\ Any idea anyone?
 

refraction

PCSX2 Coder
try getting the document for VChip8, it has opcodes that arent in the david winter document, FX30 is set I to the SChip8 font sprite in VX.
 

RipNLa

New member
Damn it! Can't decide which thread to post in! SO THIS ONE IT IS! Thanks for the info Refraction. Stupid me, I had the documentation, I just didnt look at it! I was hooked on the Winter document. BTW, Doomulation, awesome debugger I just saw on the PotatoChip thread! Crazy cool!

SO THEN! I "finished" my RIPxSCHIP8 emulator. Some stuff is still a little weird (like Spacefig and Dragon2) , but most works prretty good! I even made a webpage for it with screenshots blahblah
car2.jpg

alien.jpg

worm3.jpg

dragon1.jpg

uboat.jpg


You can download the all the latest stuff from here now.
http://www.reepal.com/RIPxSCHIP8.htm
 
OP
sammyboy

sammyboy

Certified SuperHero
Just out of interest can anyone tell me a chip 8 emulator developed using vb. People say that you can do it but noone here has tried it.

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

Talking of chip 8 roms, is there such thing as a chip 8 pd rom, normal chip 8 games are ususally the same as most pd games.
 
Last edited:

zenogais

New member
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
 
Last edited:

Top