int Initialise1802Cpu(void)
{
int i;
//FILE fp;
//fp=fopen("debuglog.txt","w");
ZeroMemory(&CpuContext,sizeof(i1802Context)); // Clear the context struct before using it
CpuContext.CodeIndex=PROGRAM_ENTRY; // Set the code index to point to the rom's
// program entry point.
for(i=0;i<80;i++) // Set up the chip-8 font
{
CpuContext.ProgramMemory[i]=font[i];
}
memset(screen,0,sizeof(unsigned char)*64*32);
bCpuHasBeenInitialised=TRUE;
LoadControls();
//fclose(fp);
return TRUE;
}
void Render(void)
{
int x,y;
for(y=0;y<32;y++)
{
for(x=0;x<64;x++)
{
if(screen[x+(y*64)]==1)
{
gpuPutPixelWhite(x*3,y*3);
}
else
{
gpuPutPixelBlack(x*3,y*3);
}
}
}
}
void ExecuteCpu(void)
{
unsigned short Op=CpuContext.ProgramMemory[CpuContext.CodeIndex];
unsigned char Opcode;
Op=((Op<<8)|CpuContext.ProgramMemory[CpuContext.CodeIndex+1]);
Opcode=(Op&0xF000)>>12;
// NOTE: almost every opcode we will increment the code index
// by 2. We increment by 2 in order to reach the next opcode.
// If we skip something, we increment by 4 instead. When
// jumping, we don't need to (I think).
switch(Opcode)
{
case 0x00:
{
switch(Op&0x00FF)
{
case 0xE0: // Clear the screen
gpuClearScreen();
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
case 0xEE: // Return from subroutine
CpuContext.StackPointer--; // Decrement the stack pointer
// Pop the value off the stack.
CpuContext.CodeIndex=CpuContext.Stack[CpuContext.StackPointer];
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
case 0xFB: // The remaining are schip-8 opcodes
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
case 0xFC:
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
case 0xFE:
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
case 0xFF:
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
default:
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
}
break;
case 0x01: // Jump instruction
{
// There is no need to mess with the stack here
CpuContext.CodeIndex=(Op&0x0FFF);
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x02:
{
CpuContext.Stack[++CpuContext.StackPointer]=CpuContext.CodeIndex;
CpuContext.CodeIndex=(Op&0x0FFF);
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x03:
{
if(GetRegister1(Op)==(Op&0x00FF))
CpuContext.CodeIndex+=4;
else
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x04:
{
if(GetRegister1(Op)!=(Op&0x00FF))
CpuContext.CodeIndex+=4;
else
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x05:
{
if(GetRegister1(Op)==GetRegister2(Op))
CpuContext.CodeIndex+=4;
else
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x06:
{
GetRegister1(Op)=Op&0x00FF;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x07:
{
GetRegister1(Op)+=Op&0x00FF;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x08:
{
switch(Op&0x000F)
{
case 0x00: // mov vx,vy
{
GetRegister1(Op)=GetRegister2(Op);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x01: // or vx,vy
{
GetRegister1(Op) |=GetRegister2(Op);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x02: // and vx,vy
{
GetRegister1(Op) &=GetRegister2(Op);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x03: // xor vx,vy
{
GetRegister1(Op) ^=GetRegister2(Op);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x04:
{
/*
if(GetRegister2(Op) > (0xFF-GetRegister1(Op)))
CpuContext.regs.v[0xF]=1;
else
CpuContext.regs.v[0xF]=0;
*/
// previsously in wrong order
GetRegister1(Op)+=GetRegister2(Op);
CpuContext.regs.v[0xF]=GetRegister1(Op)&0x01;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x05:
{
// previously in wrong order
GetRegister1(Op)-=GetRegister2(Op);
if(GetRegister1(Op) >= GetRegister2(Op))
CpuContext.regs.v[0xF]=1;
else
CpuContext.regs.v[0xF]=0;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x06: // Fixed ?
{
/*
CpuContext.regs.v[0xF]=Op&0x1;
GetRegister1(Op)>>=1;
*/
GetRegister1(Op) /= 2;
CpuContext.regs.v[0xF] >>= 1;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x07:
{
GetRegister1(Op)=GetRegister2(Op)-GetRegister1(Op);
if(GetRegister2(Op) >= GetRegister1(Op))
CpuContext.regs.v[0xF]=1;
else
CpuContext.regs.v[0xF]=0;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x0E: // Fixed ?
{
CpuContext.regs.v[0xF]=(GetRegister1(Op)>>7)&0x01;
GetRegister1(Op)<<=1;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
default:
{
Log(Opcode,&CpuContext,No);
break;
}
}
}
break;
case 0x09:
{
if(GetRegister1(Op) != GetRegister2(Op))
CpuContext.CodeIndex+=4;
else
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x0A:
{
CpuContext.regs.I=Op&0x0FFF;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x0B:
{
CpuContext.CodeIndex+=CpuContext.regs.v[0]+(Op&0x0FFF);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x0C:
{
GetRegister1(Op)=rand()&(Op&0x00FF);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x0D:
{
switch(Op&0x00FF) // Fixed
{
case 0x00:
{
x=GetRegister1(Op);y=GetRegister2(Op);
for(row=0;row<16;row++)
{
pixel=CpuContext.ProgramMemory[CpuContext.regs.I+row];
for(line=0;line<16;line++)
{
if((pixel & (line >> 0x80))==1)
{
if(screen[(line+x+((y+row)*64))]==1)
{
CpuContext.regs.v[0xf]=1;
}
screen[(line+x+((y+row)*64))]^=1;
}
}
}
CpuContext.CodeIndex+=2;
Render();
Log(Opcode,&CpuContext,Yes);
}
break;
default:
{
x=GetRegister1(Op);
y=GetRegister2(Op);
height=Op&0x000F;
for(row=0;row<height;row++)
{
pixel=CpuContext.ProgramMemory[CpuContext.regs.I+row];
for(line=0;line<8;line++)
{
if((pixel & (line >> 0x80))!=0)
{
if(screen[(line+x+((y+row)*64))]==1)
{
CpuContext.regs.v[0xf]=1;
}
screen[(line+x+((y+row)*64))]^=1;
}
}
}
CpuContext.CodeIndex+=2;
Render();
Log(Opcode,&CpuContext,Yes);
}
break;
}
//break;
}
case 0x0E:
{
switch(Op&0x00FF)
{
case 0x9E:
{
if(GetRegister1(Op)==GetKey())
CpuContext.CodeIndex+=4;
else
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0xA1:
{
if(GetRegister1(Op)!=GetKey())
CpuContext.CodeIndex+=4;
else
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
default:
{
Log(Opcode,&CpuContext,No);
break;
}
}
}
break;
case 0x0F:
{
switch(Op&0x00FF)
{
case 0x07:
{
GetRegister1(Op)=CpuContext.DelayTimer;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x0A:
{
do
{
GetRegister1(Op)=GetKey();
}while(GetKey()!=(-1));
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x15:
{
CpuContext.DelayTimer=GetRegister1(Op);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x18:
{
CpuContext.SoundTimer=GetRegister1(Op);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x1E:
{
CpuContext.regs.I+=GetRegister1(Op);
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x29:
{
CpuContext.regs.I=GetRegister1(Op)*5;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x30:
{
CpuContext.regs.I=GetRegister1(Op)*10;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x33:
{
unsigned short i=GetRegister1(Op);
CpuContext.ProgramMemory[CpuContext.regs.I]=i/100;
CpuContext.ProgramMemory[CpuContext.regs.I+1]=(i/10)%100;
CpuContext.ProgramMemory[CpuContext.regs.I+2]=(i%100)%10;
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x55:
{
int i;
//for(i=0;i<=GetRegister1(Op);i++)
for(i=0;i<=((Op&0x0F00)>>8);i++)
{
CpuContext.ProgramMemory[CpuContext.regs.I+i]=CpuContext.regs.v[i];
}
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x65:
{
int i;
//for(i=0;i<=GetRegister1(Op);i++)
for(i=0;i<=((Op&0x0F00)>>8);i++)
{
CpuContext.regs.v[i]=CpuContext.ProgramMemory[CpuContext.regs.I+i];
}
CpuContext.CodeIndex+=2;
Log(Opcode,&CpuContext,Yes);
break;
}
case 0x75:
case 0x85:
// SCHIP8 opcodes
Log(Opcode,&CpuContext,Yes);
break;
default:
{
Log(Opcode,&CpuContext,No);
break;
}
}
}
default:
{
Log(Opcode,&CpuContext,No);
break;
}
}
}
int LoadRom(char* filename)
{
FILE fpRom; // File handle to the rom
//FILE fp; // File handle to hex dump file
int i;
fpRom=fopen(filename,PSP_O_RDONLY); // Attempt to open the rom file
// We are only going to read from
// the memory so we specify "rb"
if(!fpRom) return FALSE; // If the rom did not exist, return
dwRomSize=fseek(fpRom,0,PSP_SEEK_END); // Determine the size of the rom
if(!dwRomSize) return FALSE; // If we can't determine the rom's
// size, then exit.
fseek(fpRom,0,PSP_SEEK_SET); // Read the rom memory from the
// PROGRAM_ENTRY (0x200). The locations
// 0x000-0x1FF are reserved, and I rec-
// comend not trifling with it unless
// you really have to.
fread(CpuContext.ProgramMemory+PROGRAM_ENTRY,1,dwRomSize-PROGRAM_ENTRY,fpRom);
fclose(fpRom); // We got loaded
bRomWasLoaded=TRUE;
return TRUE;
}