diff --git a/dchip-8.vcxproj b/dchip-8.vcxproj
index 169c81f..0772fc9 100644
--- a/dchip-8.vcxproj
+++ b/dchip-8.vcxproj
@@ -73,7 +73,7 @@
$(SolutionDir)\bin\
- $(SolutionDir)\bin\
+ $(SolutionDir)
diff --git a/src/dchip8.cpp b/src/dchip8.cpp
index 1743284..e131dbf 100644
--- a/src/dchip8.cpp
+++ b/src/dchip8.cpp
@@ -1,8 +1,23 @@
+#ifndef _CRT_SECURE_NO_WARNINGS
+ #define _CRT_SECURE_NO_WARNINGS
+#endif
+
#include "dchip8_platform.h"
#include "dqnt.h"
+#include "stdio.h"
+
+enum Chip8State
+{
+ chip8state_init,
+ chip8state_load_file,
+ chip8state_running,
+ chip8state_off,
+};
typedef struct Chip8CPU
{
+ const u16 INIT_ADDRESS = 0x200;
+
union {
u8 registerArray[16];
struct
@@ -50,10 +65,12 @@ typedef struct Chip8CPU
u8 stackPointer;
u16 stack[16];
- bool isInit;
+ enum Chip8State state;
} Chip8CPU;
-FILE_SCOPE Chip8CPU cpu;
+FILE_SCOPE Chip8CPU cpu;
+FILE_SCOPE RandPCGState pcgState;
+
void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
PlatformMemory memory)
{
@@ -82,358 +99,383 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
bitmapBuffer[i] = color;
}
- if (!cpu.isInit)
+ u8 *mainMem = (u8 *)memory.permanentMem;
+ if (cpu.state == chip8state_init)
{
DQNT_ASSERT(memory.permanentMemSize == (4096 / 4));
- cpu.isInit = true;
// NOTE: Everything before 0x200 is reserved for the actual emulator
- const u32 INIT_ADDRESS = 0x200;
- cpu.programCounter = INIT_ADDRESS;
+ cpu.programCounter = cpu.INIT_ADDRESS;
cpu.I = 0;
cpu.stackPointer = 0;
- // TODO(doyle): Load rom
+ const u32 SEED = 0x8293A8DE;
+ dqnt_rnd_pcg_seed(&pcgState, SEED);
+
+ cpu.state = chip8state_load_file;
}
-#if 0
- u8 *mainMem = (u8 *)memory.permanentMem;
- u8 opHighByte = mainMem[cpu.programCounter++];
- u8 opLowByte = mainMem[cpu.programCounter++];
-
- u8 opFirstNibble = (opHighByte & 0xF0);
- switch (opFirstNibble)
+ if (cpu.state == chip8state_load_file)
{
- case 0x00:
+ PlatformFile file = {};
+ if (platform_open_file(L"roms/PONG", &file))
{
- // CLS - 00E0 - Clear the display
- if (opLowByte == 0xE0)
- {
- }
- // RET - 00EE - Return from subroutine
- else if (opLowByte == 0xEE)
- {
- cpu.programCounter = cpu.stack[cpu.stackPointer--];
- }
- }
- break;
+ DQNT_ASSERT((cpu.INIT_ADDRESS + file.size) <=
+ DQNT_ARRAY_COUNT(mainMem));
- case 0x10:
- case 0x20:
- {
- u16 loc = ((0x0F & opHighByte) << 8) | (0xFF & opLowByte);
- DQNT_ASSERT(loc <= 0x0FFF);
-
- // JP addr - 1nnn - Jump to location nnn
- if (opFirstNibble == 0x10)
+ void *loadToAddr = (void *)(&mainMem[cpu.INIT_ADDRESS]);
+ if (platform_read_file(file, loadToAddr, (u32)file.size))
{
- // NOTE: Jump to loc, as per below
+ cpu.state = chip8state_running;
}
- // Call addr - 2nnn - Call subroutine at nnn
else
{
- DQNT_ASSERT(opFirstNibble == 0x20);
-
- cpu.stackPointer++;
- DQNT_ASSERT(cpu.stackPointer < DQNT_ARRAY_COUNT(cpu.stack));
- cpu.stack[cpu.stackPointer] = cpu.programCounter;
+ cpu.state = chip8state_off;
}
- cpu.programCounter = loc;
+ platform_close_file(&file);
}
- break;
+ }
- case 0x30:
- case 0x40:
+ if (cpu.state == chip8state_running)
+ {
+ u8 opHighByte = mainMem[cpu.programCounter++];
+ u8 opLowByte = mainMem[cpu.programCounter++];
+
+ u8 opFirstNibble = (opHighByte & 0xF0);
+ switch (opFirstNibble)
{
- u8 regNum = (0x0F & opHighByte);
- DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
- u8 valToCheck = opLowByte;
-
- // SE Vx, byte - 3xkk - Skip next instruction if Vx == kk
- if (opFirstNibble == 0x30)
+ case 0x00:
{
- if (cpu.registerArray[regNum] == valToCheck)
- cpu.programCounter += 2;
- }
- // SNE Vx, byte - 4xkk - Skip next instruction if Vx == kk
- else
- {
- DQNT_ASSERT(opFirstNibble == 0x40);
- if (cpu.registerArray[regNum] != valToCheck)
- cpu.programCounter += 2;
- }
- }
- break;
-
- // SE Vx, Vy - 5xy0 - Skip next instruction if Vx = Vy
- case 0x50:
- {
- u8 firstRegNum = (0x0F & opHighByte);
- DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
-
- u8 secondRegNum = (0xF0 & opLowByte);
- DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
-
- if (cpu.registerArray[firstRegNum] ==
- cpu.registerArray[secondRegNum])
- {
- cpu.programCounter++;
- }
- }
- break;
-
- case 0x60:
- case 0x70:
- {
- u8 regNum = (0x0F & opHighByte);
- DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
- u8 valToOperateOn = opLowByte;
-
- // LD Vx, byte - 6xkk - Set Vx = kk
- if (opFirstNibble == 0x60)
- {
- cpu.registerArray[regNum] = valToOperateOn;
- }
- // ADD Vx, byte - 7xkk - Set Vx = Vx + kk
- else
- {
- DQNT_ASSERT(opFirstNibble == 0x70);
- cpu.registerArray[regNum] += valToOperateOn;
- }
-
- }
- break;
-
- case 0x80:
- {
- u8 firstRegNum = (0x0F & opHighByte);
- DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
-
- u8 secondRegNum = (0xF0 & opLowByte);
- DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
-
- u8 *vx = &cpu.registerArray[firstRegNum];
- u8 *vy = &cpu.registerArray[secondRegNum];
-
- // LD Vx, Vy - 8xy0 - Set Vx = Vy
- if (opLowByte == 0x00)
- {
- *vx = *vy;
- }
- // OR Vx, Vy - 8xy1 - Set Vx = Vx OR Vy
- else if (opLowByte == 0x01)
- {
- u8 result = (*vx | *vy);
- *vx = result;
- }
- // AND Vx, Vy - 8xy2 - Set Vx = Vx AND Vy
- else if (opLowByte == 0x02)
- {
- u8 result = (*vx & *vy);
- *vx = result;
- }
- // XOR Vx, Vy - 8xy3 - Set Vx = Vx XOR Vy
- else if (opLowByte == 0x03)
- {
- u8 result = (*vx & *vy);
- *vx = result;
- }
- // ADD Vx, Vy - 8xy4 - Set Vx = Vx + Vy, set VF = carry
- else if (opLowByte == 0x04)
- {
- u16 result = (*vx + *vy);
- *vx = (u8)result;
-
- if (result > 255) cpu.VF = (result > 255) ? 1 : 0;
-
- }
- // SUB Vx, Vy - 8xy5 - Set Vx = Vx - Vy, set VF = NOT borrow
- else if (opLowByte == 0x05)
- {
- if (*vx > *vy)
- cpu.VF = 1;
- else
- cpu.VF = 0;
-
- *vx -= *vy;
- }
- // SHR Vx {, Vy} - 8xy6 - Set Vx = Vx SHR 1
- else if (opLowByte == 0x06)
- {
- if (*vx & 1)
- cpu.VF = 1;
- else
- cpu.VF = 0;
-
- *vx >>= 1;
- }
- // SUBN Vx {, Vy} - 8xy7 - Set Vx = Vy - Vx, set VF = NOT borrow
- else if (opLowByte == 0x07)
- {
- if (*vy > *vx)
- cpu.VF = 1;
- else
- cpu.VF = 0;
-
- *vx = *vy - *vx;
- }
- // SHL Vx {, Vy} - 8xyE - Set Vx = SHL 1
- else
- {
- DQNT_ASSERT(opLowByte == 0x0E);
- if ((*vx >> 7) == 1)
- cpu.VF = 1;
- else
- cpu.VF = 0;
-
- *vx <<= 1;
- }
- }
- break;
-
- // SNE Vx, Vy - 9xy0 - Skip next instruction if Vx != Vy
- case 0x90:
- {
- u8 firstRegNum = (0x0F & opHighByte);
- DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
-
- u8 secondRegNum = (0xF0 & opLowByte);
- DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
-
- u8 *vx = &cpu.registerArray[firstRegNum];
- u8 *vy = &cpu.registerArray[secondRegNum];
-
- if (*vx != *vy) cpu.programCounter+= 2;
- }
- break;
-
- // LD I, addr - Annn - Set I = nnn
- case 0xA0:
- {
- u8 valToSet = opLowByte;
- cpu.indexRegister = valToSet;
- }
- break;
-
- // JP V0, addr - Bnnn - Jump to location (nnn + V0)
- case 0xB0:
- {
- u8 addr = opLowByte + cpu.V0;
- cpu.programCounter = addr;
- }
- break;
-
- // RND Vx, byte - Cxkk - Set Vx = random byte AND kk
- case 0xC0:
- {
- u8 firstRegNum = (0x0F & opHighByte);
- DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
-
- u8 andBits = opLowByte;
- u8 *vx = &cpu.registerArray[firstRegNum];
-
- // TODO(doyle): Random umber
- *vx = (28 & opLowByte);
- }
- break;
-
- // DRW Vx, Vy, nibble - Dxyn - Display n-byte sprite starting at mem
- // location I at (Vx, Vy), set VF = collision
- case 0xD0:
- {
- // TODO(doyle): Implement drawing
- }
- break;
-
- case 0xE0:
- {
- // TODO(doyle): Implement key checks
- u8 checkKey = (0x0F & opHighByte);
-
- // SKP Vx - Ex9E - Skip next instruction if key with the value of Vx
- // is pressed
- bool skipNextInstruction = false;
- if (opLowByte == 0x9E)
- {
- }
- // SKNP Vx - ExA1 - Skip next instruction if key with the value of
- // Vx is not pressed
- else
- {
- DQNT_ASSERT(opLowByte == 0xA1);
- }
-
- if (skipNextInstruction) cpu.programCounter += 2;
- }
- break;
-
- case 0xF0:
- {
- u8 regNum = (0x0F & opHighByte);
- DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
- u8 *vx = &cpu.registerArray[regNum];
-
- // LD Vx, DT - Fx07 - Set Vx = delay timer value
- if (opLowByte == 0x07)
- {
- *vx = cpu.delayTimer;
- }
- // LD Vx, K - Fx0A - Wait for a key press, store the value of the
- // key in Vx
- else if (opLowByte == 0x0A)
- {
- }
- // LD DT, Vx - Fx15 - Set delay timer = Vx
- else if (opLowByte == 0x15)
- {
- cpu.delayTimer = *vx;
- }
- // LD ST, Vx - Fx18 - Set sound timer = Vx
- else if (opLowByte == 0x18)
- {
- cpu.soundTimer = *vx;
- }
- // ADD I, Vx - Fx1E - Set I = I + Vx
- else if (opLowByte == 0x1E)
- {
- cpu.indexRegister += *vx;
- }
- // LD F, Vx - Fx29 - Set I = location of sprite for digit Vx
- else if (opLowByte == 0x29)
- {
- // TODO: Implement
- }
- // LD B, Vx - Fx33 - Store BCD representations of Vx in memory
- // locations I, I+1 and I+2
- else if (opLowByte == 0x33)
- {
- }
- // LD [I], Vx - Fx55 - Store register V0 through Vx in memory
- // starting at location I.
- else if (opLowByte == 0x55)
- {
- for (u32 regIndex = 0; regIndex <= regNum; regIndex++)
+ // CLS - 00E0 - Clear the display
+ if (opLowByte == 0xE0)
{
- u32 mem_offset = regIndex;
- mainMem[cpu.indexRegister + mem_offset] =
- cpu.registerArray[regIndex];
+ }
+ // RET - 00EE - Return from subroutine
+ else if (opLowByte == 0xEE)
+ {
+ cpu.programCounter = cpu.stack[cpu.stackPointer--];
}
}
- // LD [I], Vx - Fx65 - Read registers V0 through Vx from memory
- // starting at location I.
- else
+ break;
+
+ case 0x10:
+ case 0x20:
{
- DQNT_ASSERT(opLowByte == 0x65);
- for (u32 regIndex = 0; regIndex <= regNum; regIndex++)
+ u16 loc = ((0x0F & opHighByte) << 8) | (0xFF & opLowByte);
+ DQNT_ASSERT(loc <= 0x0FFF);
+
+ // JP addr - 1nnn - Jump to location nnn
+ if (opFirstNibble == 0x10)
{
- u32 mem_offset = regIndex;
- cpu.registerArray[regIndex] =
- mainMem[cpu.indexRegister + mem_offset];
+ // NOTE: Jump to loc, as per below
+ }
+ // Call addr - 2nnn - Call subroutine at nnn
+ else
+ {
+ DQNT_ASSERT(opFirstNibble == 0x20);
+
+ cpu.stackPointer++;
+ DQNT_ASSERT(cpu.stackPointer < DQNT_ARRAY_COUNT(cpu.stack));
+ cpu.stack[cpu.stackPointer] = cpu.programCounter;
+ }
+
+ cpu.programCounter = loc;
+ }
+ break;
+
+ case 0x30:
+ case 0x40:
+ {
+ u8 regNum = (0x0F & opHighByte);
+ DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+ u8 valToCheck = opLowByte;
+
+ // SE Vx, byte - 3xkk - Skip next instruction if Vx == kk
+ if (opFirstNibble == 0x30)
+ {
+ if (cpu.registerArray[regNum] == valToCheck)
+ cpu.programCounter += 2;
+ }
+ // SNE Vx, byte - 4xkk - Skip next instruction if Vx == kk
+ else
+ {
+ DQNT_ASSERT(opFirstNibble == 0x40);
+ if (cpu.registerArray[regNum] != valToCheck)
+ cpu.programCounter += 2;
}
}
- }
- break;
- };
-#endif
+ break;
+
+ // SE Vx, Vy - 5xy0 - Skip next instruction if Vx = Vy
+ case 0x50:
+ {
+ u8 firstRegNum = (0x0F & opHighByte);
+ DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+
+ u8 secondRegNum = (0xF0 & opLowByte);
+ DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+
+ if (cpu.registerArray[firstRegNum] ==
+ cpu.registerArray[secondRegNum])
+ {
+ cpu.programCounter++;
+ }
+ }
+ break;
+
+ case 0x60:
+ case 0x70:
+ {
+ u8 regNum = (0x0F & opHighByte);
+ DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+ u8 valToOperateOn = opLowByte;
+
+ // LD Vx, byte - 6xkk - Set Vx = kk
+ if (opFirstNibble == 0x60)
+ {
+ cpu.registerArray[regNum] = valToOperateOn;
+ }
+ // ADD Vx, byte - 7xkk - Set Vx = Vx + kk
+ else
+ {
+ DQNT_ASSERT(opFirstNibble == 0x70);
+ cpu.registerArray[regNum] += valToOperateOn;
+ }
+ }
+ break;
+
+ case 0x80:
+ {
+ u8 firstRegNum = (0x0F & opHighByte);
+ DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+
+ u8 secondRegNum = (0xF0 & opLowByte);
+ DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+
+ u8 *vx = &cpu.registerArray[firstRegNum];
+ u8 *vy = &cpu.registerArray[secondRegNum];
+
+ // LD Vx, Vy - 8xy0 - Set Vx = Vy
+ if (opLowByte == 0x00)
+ {
+ *vx = *vy;
+ }
+ // OR Vx, Vy - 8xy1 - Set Vx = Vx OR Vy
+ else if (opLowByte == 0x01)
+ {
+ u8 result = (*vx | *vy);
+ *vx = result;
+ }
+ // AND Vx, Vy - 8xy2 - Set Vx = Vx AND Vy
+ else if (opLowByte == 0x02)
+ {
+ u8 result = (*vx & *vy);
+ *vx = result;
+ }
+ // XOR Vx, Vy - 8xy3 - Set Vx = Vx XOR Vy
+ else if (opLowByte == 0x03)
+ {
+ u8 result = (*vx & *vy);
+ *vx = result;
+ }
+ // ADD Vx, Vy - 8xy4 - Set Vx = Vx + Vy, set VF = carry
+ else if (opLowByte == 0x04)
+ {
+ u16 result = (*vx + *vy);
+ *vx = (u8)result;
+
+ if (result > 255) cpu.VF = (result > 255) ? 1 : 0;
+ }
+ // SUB Vx, Vy - 8xy5 - Set Vx = Vx - Vy, set VF = NOT borrow
+ else if (opLowByte == 0x05)
+ {
+ if (*vx > *vy)
+ cpu.VF = 1;
+ else
+ cpu.VF = 0;
+
+ *vx -= *vy;
+ }
+ // SHR Vx {, Vy} - 8xy6 - Set Vx = Vx SHR 1
+ else if (opLowByte == 0x06)
+ {
+ if (*vx & 1)
+ cpu.VF = 1;
+ else
+ cpu.VF = 0;
+
+ *vx >>= 1;
+ }
+ // SUBN Vx {, Vy} - 8xy7 - Set Vx = Vy - Vx, set VF = NOT borrow
+ else if (opLowByte == 0x07)
+ {
+ if (*vy > *vx)
+ cpu.VF = 1;
+ else
+ cpu.VF = 0;
+
+ *vx = *vy - *vx;
+ }
+ // SHL Vx {, Vy} - 8xyE - Set Vx = SHL 1
+ else
+ {
+ DQNT_ASSERT(opLowByte == 0x0E);
+ if ((*vx >> 7) == 1)
+ cpu.VF = 1;
+ else
+ cpu.VF = 0;
+
+ *vx <<= 1;
+ }
+ }
+ break;
+
+ // SNE Vx, Vy - 9xy0 - Skip next instruction if Vx != Vy
+ case 0x90:
+ {
+ u8 firstRegNum = (0x0F & opHighByte);
+ DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+
+ u8 secondRegNum = (0xF0 & opLowByte);
+ DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+
+ u8 *vx = &cpu.registerArray[firstRegNum];
+ u8 *vy = &cpu.registerArray[secondRegNum];
+
+ if (*vx != *vy) cpu.programCounter += 2;
+ }
+ break;
+
+ // LD I, addr - Annn - Set I = nnn
+ case 0xA0:
+ {
+ u8 valToSet = opLowByte;
+ cpu.indexRegister = valToSet;
+ }
+ break;
+
+ // JP V0, addr - Bnnn - Jump to location (nnn + V0)
+ case 0xB0:
+ {
+ u8 addr = opLowByte + cpu.V0;
+ cpu.programCounter = addr;
+ }
+ break;
+
+ // RND Vx, byte - Cxkk - Set Vx = random byte AND kk
+ case 0xC0:
+ {
+ u8 firstRegNum = (0x0F & opHighByte);
+ DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+
+ u8 andBits = opLowByte;
+ u8 *vx = &cpu.registerArray[firstRegNum];
+
+ u8 randNum = (u8)dqnt_rnd_pcg_range(&pcgState, 0, 255);
+ *vx = (randNum & opLowByte);
+ }
+ break;
+
+ // DRW Vx, Vy, nibble - Dxyn - Display n-byte sprite starting at mem
+ // location I at (Vx, Vy), set VF = collision
+ case 0xD0:
+ {
+ // TODO(doyle): Implement drawing
+ }
+ break;
+
+ case 0xE0:
+ {
+ // TODO(doyle): Implement key checks
+ u8 checkKey = (0x0F & opHighByte);
+
+ // SKP Vx - Ex9E - Skip next instruction if key with the value
+ // of Vx
+ // is pressed
+ bool skipNextInstruction = false;
+ if (opLowByte == 0x9E)
+ {
+ }
+ // SKNP Vx - ExA1 - Skip next instruction if key with the value
+ // of
+ // Vx is not pressed
+ else
+ {
+ DQNT_ASSERT(opLowByte == 0xA1);
+ }
+
+ if (skipNextInstruction) cpu.programCounter += 2;
+ }
+ break;
+
+ case 0xF0:
+ {
+ u8 regNum = (0x0F & opHighByte);
+ DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
+ u8 *vx = &cpu.registerArray[regNum];
+
+ // LD Vx, DT - Fx07 - Set Vx = delay timer value
+ if (opLowByte == 0x07)
+ {
+ *vx = cpu.delayTimer;
+ }
+ // LD Vx, K - Fx0A - Wait for a key press, store the value of
+ // the key in Vx
+ else if (opLowByte == 0x0A)
+ {
+ }
+ // LD DT, Vx - Fx15 - Set delay timer = Vx
+ else if (opLowByte == 0x15)
+ {
+ cpu.delayTimer = *vx;
+ }
+ // LD ST, Vx - Fx18 - Set sound timer = Vx
+ else if (opLowByte == 0x18)
+ {
+ cpu.soundTimer = *vx;
+ }
+ // ADD I, Vx - Fx1E - Set I = I + Vx
+ else if (opLowByte == 0x1E)
+ {
+ cpu.indexRegister += *vx;
+ }
+ // LD F, Vx - Fx29 - Set I = location of sprite for digit Vx
+ else if (opLowByte == 0x29)
+ {
+ // TODO: Implement
+ }
+ // LD B, Vx - Fx33 - Store BCD representations of Vx in memory
+ // locations I, I+1 and I+2
+ else if (opLowByte == 0x33)
+ {
+ }
+ // LD [I], Vx - Fx55 - Store register V0 through Vx in memory
+ // starting at location I.
+ else if (opLowByte == 0x55)
+ {
+ for (u32 regIndex = 0; regIndex <= regNum; regIndex++)
+ {
+ u32 mem_offset = regIndex;
+ mainMem[cpu.indexRegister + mem_offset] =
+ cpu.registerArray[regIndex];
+ }
+ }
+ // LD [I], Vx - Fx65 - Read registers V0 through Vx from memory
+ // starting at location I.
+ else
+ {
+ DQNT_ASSERT(opLowByte == 0x65);
+ for (u32 regIndex = 0; regIndex <= regNum; regIndex++)
+ {
+ u32 mem_offset = regIndex;
+ cpu.registerArray[regIndex] =
+ mainMem[cpu.indexRegister + mem_offset];
+ }
+ }
+ }
+ break;
+ };
+ }
+
}
diff --git a/src/dchip8_platform.h b/src/dchip8_platform.h
index a71a5cd..1908822 100644
--- a/src/dchip8_platform.h
+++ b/src/dchip8_platform.h
@@ -53,4 +53,16 @@ typedef struct PlatformMemory
u32 transientMemSize;
} PlatformMemory;
+typedef struct PlatformFile
+{
+ void *handle;
+ u64 size;
+} PlatformFile;
+
+// Return true if successful, false if not
+bool platform_open_file (const wchar_t *const file, PlatformFile *platformFile);
+// Return the number of bytes read
+u32 platform_read_file (PlatformFile file, void *buffer, u32 numBytesToRead);
+void platform_close_file(PlatformFile *file);
+
#endif
diff --git a/src/dqnt.h b/src/dqnt.h
index 7db8c1e..8414e99 100644
--- a/src/dqnt.h
+++ b/src/dqnt.h
@@ -50,8 +50,17 @@ v2 V2i(i32 x, i32 y);
////////////////////////////////////////////////////////////////////////////////
// String Ops
////////////////////////////////////////////////////////////////////////////////
-i32 dqnt_strcmp(const char *a, const char *b);
-i32 dqnt_strlen(const char *a);
+bool dqnt_char_is_digit (char c);
+bool dqnt_char_is_alpha (char c);
+bool dqnt_char_is_alphanum(char c);
+
+i32 dqnt_strcmp (const char *a, const char *b);
+// Returns the length without the null terminator
+i32 dqnt_strlen (const char *a);
+char *dqnt_strncpy(char *dest, const char *src, i32 numChars);
+
+bool dqnt_str_reverse(char *const buf, const i32 bufSize);
+i32 dqnt_str_to_i32 (char *const buf, const i32 bufSize);
wchar_t dqnt_wchar_ascii_to_lower(wchar_t character);
i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b);
@@ -70,6 +79,8 @@ typedef struct RandPCGState
void dqnt_rnd_pcg_seed (RandPCGState *pcg, u32 seed);
// Returns a random number N between [0, 0xFFFFFFFF]
u32 dqnt_rnd_pcg_next (RandPCGState *pcg);
+// Returns a random float N between [0.0, 1.0f]
+f32 dqnt_rnd_pcg_nextf(RandPCGState *pcg);
// Returns a random integer N between [min, max]
i32 dqnt_rnd_pcg_range(RandPCGState *pcg, i32 min, i32 max);
@@ -98,6 +109,24 @@ v2 V2i(i32 x, i32 y)
////////////////////////////////////////////////////////////////////////////////
// String Ops
////////////////////////////////////////////////////////////////////////////////
+bool dqnt_char_is_digit(char c)
+{
+ if (c >= '0' && c <= '9') return true;
+ return false;
+}
+
+bool dqnt_char_is_alpha(char c)
+{
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) return true;
+ return false;
+}
+
+bool dqnt_char_is_alphanum(char c)
+{
+ if (dqnt_char_is_alpha(c) || dqnt_char_is_digit(c)) return true;
+ return false;
+}
+
i32 dqnt_strcmp(const char *a, const char *b)
{
while ((*a) == (*b))
@@ -110,6 +139,86 @@ i32 dqnt_strcmp(const char *a, const char *b)
return (((*a) < (*b)) ? -1 : 1);
}
+i32 dqnt_strlen(const char *a)
+{
+ i32 result = 0;
+ while (a[result]) result++;
+
+ return result;
+}
+
+char *dqnt_strncpy(char *dest, const char *src, i32 numChars)
+{
+ if (!dest) return NULL;
+ if (!src) return dest;
+
+ for (i32 i = 0; i < numChars; i++)
+ dest[i] = src[i];
+
+ return dest;
+}
+
+bool dqnt_str_reverse(char *const buf, const i32 bufSize)
+{
+ if (!buf) return false;
+ i32 mid = bufSize / 2;
+
+ for (i32 i = 0; i < mid; i++)
+ {
+ char tmp = buf[i];
+ buf[i] = buf[(bufSize - 1) - i];
+ buf[(bufSize - 1) - i] = tmp;
+ }
+
+ return true;
+}
+
+i32 dqnt_str_to_i32(char *const buf, const i32 bufSize)
+{
+ if (!buf || bufSize == 0) return 0;
+
+ i32 index = 0;
+ bool isNegative = false;
+ if (buf[index] == '-' || buf[index] == '+')
+ {
+ if (buf[index] == '-') isNegative = true;
+ index++;
+ }
+ else if (!dqnt_char_is_digit(buf[index]))
+ {
+ return 0;
+ }
+
+ i32 result = 0;
+ for (i32 i = index; i < bufSize; i++)
+ {
+ if (dqnt_char_is_digit(buf[i]))
+ {
+ result *= 10;
+ result += (buf[i] - '0');
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (isNegative) result *= -1;
+
+ return result;
+}
+
+wchar_t dqnt_wchar_ascii_to_lower(wchar_t character)
+{
+ if (character >= L'A' && character <= L'Z')
+ {
+ i32 shiftOffset = L'a' - L'A';
+ character += (wchar_t)shiftOffset;
+ }
+
+ return character;
+}
+
i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b)
{
while ((*a) == (*b))
@@ -137,17 +246,6 @@ void dqnt_wstrcat(const wchar_t *a, i32 lenA, const wchar_t *b, i32 lenB,
DQNT_ASSERT(outIndex <= outLen);
}
-wchar_t dqnt_wchar_ascii_to_lower(wchar_t character)
-{
- if (character >= L'A' && character <= L'Z')
- {
- i32 shiftOffset = L'a' - L'A';
- character += (wchar_t)shiftOffset;
- }
-
- return character;
-}
-
i32 dqnt_wstrlen(const wchar_t *a)
{
i32 result = 0;
@@ -160,18 +258,6 @@ i32 dqnt_wstrlen(const wchar_t *a)
return result;
}
-i32 dqnt_strlen(const char *a)
-{
- i32 result = 0;
- while ((*a))
- {
- result++;
- a++;
- }
-
- return result;
-}
-
////////////////////////////////////////////////////////////////////////////////
// PCG (Permuted Congruential Generator) Random Number Generator
////////////////////////////////////////////////////////////////////////////////
@@ -180,7 +266,7 @@ i32 dqnt_strlen(const char *a)
// Convert a randomized u32 value to a float value x in the range 0.0f <= x
// < 1.0f. Contributed by Jonatan Hedborg
-FILE_SCOPE f32 dqnt_rnd_f32_normalized_from_u32_(u32 value)
+FILE_SCOPE f32 dqnt_rnd_f32_normalized_from_u32_internal(u32 value)
{
u32 exponent = 127;
u32 mantissa = value >> 9;
@@ -189,7 +275,7 @@ FILE_SCOPE f32 dqnt_rnd_f32_normalized_from_u32_(u32 value)
return fresult - 1.0f;
}
-FILE_SCOPE u64 dqnt_rnd_murmur3_avalanche64_(u64 h)
+FILE_SCOPE u64 dqnt_rnd_murmur3_avalanche64_internal(u64 h)
{
h ^= h >> 33;
h *= 0xff51afd7ed558ccd;
@@ -202,11 +288,11 @@ FILE_SCOPE u64 dqnt_rnd_murmur3_avalanche64_(u64 h)
void dqnt_rnd_pcg_seed(RandPCGState *pcg, u32 seed)
{
u64 value = (((u64)seed) << 1ULL) | 1ULL;
- value = dqnt_rnd_murmur3_avalanche64_(value);
+ value = dqnt_rnd_murmur3_avalanche64_internal(value);
pcg->state[0] = 0U;
pcg->state[1] = (value << 1ULL) | 1ULL;
dqnt_rnd_pcg_next(pcg);
- pcg->state[0] += dqnt_rnd_murmur3_avalanche64_(value);
+ pcg->state[0] += dqnt_rnd_murmur3_avalanche64_internal(value);
dqnt_rnd_pcg_next(pcg);
}
@@ -221,7 +307,7 @@ u32 dqnt_rnd_pcg_next(RandPCGState *pcg)
f32 dqnt_rnd_pcg_nextf(RandPCGState *pcg)
{
- return dqnt_rnd_f32_normalized_from_u32_(dqnt_rnd_pcg_next(pcg));
+ return dqnt_rnd_f32_normalized_from_u32_internal(dqnt_rnd_pcg_next(pcg));
}
i32 dqnt_rnd_pcg_range(RandPCGState *pcg, i32 min, i32 max)
diff --git a/src/unity_build.cpp b/src/unity_build.cpp
index 0a805f4..256a00d 100644
--- a/src/unity_build.cpp
+++ b/src/unity_build.cpp
@@ -1,3 +1,5 @@
+#define _CRT_SECURE_NO_WARNINGS
+
#define DQNT_IMPLEMENTATION
#include "dqnt.h"
diff --git a/src/win32_dchip8.cpp b/src/win32_dchip8.cpp
index a6ce041..65e4733 100644
--- a/src/win32_dchip8.cpp
+++ b/src/win32_dchip8.cpp
@@ -300,3 +300,55 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
return 0;
}
+
+void platform_close_file(PlatformFile *file)
+{
+ CloseHandle(file->handle);
+ file->handle = NULL;
+ file->size = 0;
+}
+
+u32 platform_read_file(PlatformFile file, void *buffer, u32 numBytesToRead)
+{
+ DWORD numBytesRead = 0;
+ if (file.handle && buffer)
+ {
+ HANDLE win32Handle = file.handle;
+ BOOL result =
+ ReadFile(win32Handle, buffer, numBytesToRead, &numBytesRead, NULL);
+
+ // TODO(doyle): 0 also means it is completing async, but still valid
+ if (result == 0)
+ {
+ win32_error_box(L"ReadFile() failed.", nullptr);
+ }
+
+ }
+
+ return numBytesRead;
+}
+
+FILE_SCOPE u32 buffer[15000];
+bool platform_open_file(const wchar_t *const file, PlatformFile *platformFile)
+{
+ HANDLE handle = CreateFile(file, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win32_error_box(L"CreateFile() failed.", nullptr);
+ return false;
+ }
+
+ LARGE_INTEGER size;
+ if (GetFileSizeEx(handle, &size) == 0)
+ {
+ win32_error_box(L"GetFileSizeEx() failed.", nullptr);
+ return false;
+ }
+
+ platformFile->handle = handle;
+ platformFile->size = size.QuadPart;
+
+ return true;
+}