Add file loading to platform layer
This commit is contained in:
parent
b415f4c237
commit
dc8afe349a
@ -73,7 +73,7 @@
|
|||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
<OutDir>$(SolutionDir)\bin\</OutDir>
|
||||||
<IntDir>$(SolutionDir)\bin\</IntDir>
|
<IntDir>$(SolutionDir)</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
|
696
src/dchip8.cpp
696
src/dchip8.cpp
@ -1,8 +1,23 @@
|
|||||||
|
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "dchip8_platform.h"
|
#include "dchip8_platform.h"
|
||||||
#include "dqnt.h"
|
#include "dqnt.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
enum Chip8State
|
||||||
|
{
|
||||||
|
chip8state_init,
|
||||||
|
chip8state_load_file,
|
||||||
|
chip8state_running,
|
||||||
|
chip8state_off,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct Chip8CPU
|
typedef struct Chip8CPU
|
||||||
{
|
{
|
||||||
|
const u16 INIT_ADDRESS = 0x200;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
u8 registerArray[16];
|
u8 registerArray[16];
|
||||||
struct
|
struct
|
||||||
@ -50,10 +65,12 @@ typedef struct Chip8CPU
|
|||||||
u8 stackPointer;
|
u8 stackPointer;
|
||||||
u16 stack[16];
|
u16 stack[16];
|
||||||
|
|
||||||
bool isInit;
|
enum Chip8State state;
|
||||||
} Chip8CPU;
|
} Chip8CPU;
|
||||||
|
|
||||||
FILE_SCOPE Chip8CPU cpu;
|
FILE_SCOPE Chip8CPU cpu;
|
||||||
|
FILE_SCOPE RandPCGState pcgState;
|
||||||
|
|
||||||
void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
||||||
PlatformMemory memory)
|
PlatformMemory memory)
|
||||||
{
|
{
|
||||||
@ -82,358 +99,383 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
bitmapBuffer[i] = color;
|
bitmapBuffer[i] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cpu.isInit)
|
u8 *mainMem = (u8 *)memory.permanentMem;
|
||||||
|
if (cpu.state == chip8state_init)
|
||||||
{
|
{
|
||||||
DQNT_ASSERT(memory.permanentMemSize == (4096 / 4));
|
DQNT_ASSERT(memory.permanentMemSize == (4096 / 4));
|
||||||
cpu.isInit = true;
|
|
||||||
|
|
||||||
// NOTE: Everything before 0x200 is reserved for the actual emulator
|
// NOTE: Everything before 0x200 is reserved for the actual emulator
|
||||||
const u32 INIT_ADDRESS = 0x200;
|
cpu.programCounter = cpu.INIT_ADDRESS;
|
||||||
cpu.programCounter = INIT_ADDRESS;
|
|
||||||
cpu.I = 0;
|
cpu.I = 0;
|
||||||
cpu.stackPointer = 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
|
if (cpu.state == chip8state_load_file)
|
||||||
u8 *mainMem = (u8 *)memory.permanentMem;
|
|
||||||
u8 opHighByte = mainMem[cpu.programCounter++];
|
|
||||||
u8 opLowByte = mainMem[cpu.programCounter++];
|
|
||||||
|
|
||||||
u8 opFirstNibble = (opHighByte & 0xF0);
|
|
||||||
switch (opFirstNibble)
|
|
||||||
{
|
{
|
||||||
case 0x00:
|
PlatformFile file = {};
|
||||||
|
if (platform_open_file(L"roms/PONG", &file))
|
||||||
{
|
{
|
||||||
// CLS - 00E0 - Clear the display
|
DQNT_ASSERT((cpu.INIT_ADDRESS + file.size) <=
|
||||||
if (opLowByte == 0xE0)
|
DQNT_ARRAY_COUNT(mainMem));
|
||||||
{
|
|
||||||
}
|
|
||||||
// RET - 00EE - Return from subroutine
|
|
||||||
else if (opLowByte == 0xEE)
|
|
||||||
{
|
|
||||||
cpu.programCounter = cpu.stack[cpu.stackPointer--];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x10:
|
void *loadToAddr = (void *)(&mainMem[cpu.INIT_ADDRESS]);
|
||||||
case 0x20:
|
if (platform_read_file(file, loadToAddr, (u32)file.size))
|
||||||
{
|
|
||||||
u16 loc = ((0x0F & opHighByte) << 8) | (0xFF & opLowByte);
|
|
||||||
DQNT_ASSERT(loc <= 0x0FFF);
|
|
||||||
|
|
||||||
// JP addr - 1nnn - Jump to location nnn
|
|
||||||
if (opFirstNibble == 0x10)
|
|
||||||
{
|
{
|
||||||
// NOTE: Jump to loc, as per below
|
cpu.state = chip8state_running;
|
||||||
}
|
}
|
||||||
// Call addr - 2nnn - Call subroutine at nnn
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DQNT_ASSERT(opFirstNibble == 0x20);
|
cpu.state = chip8state_off;
|
||||||
|
|
||||||
cpu.stackPointer++;
|
|
||||||
DQNT_ASSERT(cpu.stackPointer < DQNT_ARRAY_COUNT(cpu.stack));
|
|
||||||
cpu.stack[cpu.stackPointer] = cpu.programCounter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu.programCounter = loc;
|
platform_close_file(&file);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
|
||||||
case 0x30:
|
if (cpu.state == chip8state_running)
|
||||||
case 0x40:
|
{
|
||||||
|
u8 opHighByte = mainMem[cpu.programCounter++];
|
||||||
|
u8 opLowByte = mainMem[cpu.programCounter++];
|
||||||
|
|
||||||
|
u8 opFirstNibble = (opHighByte & 0xF0);
|
||||||
|
switch (opFirstNibble)
|
||||||
{
|
{
|
||||||
u8 regNum = (0x0F & opHighByte);
|
case 0x00:
|
||||||
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)
|
// CLS - 00E0 - Clear the display
|
||||||
cpu.programCounter += 2;
|
if (opLowByte == 0xE0)
|
||||||
}
|
|
||||||
// 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++)
|
|
||||||
{
|
{
|
||||||
u32 mem_offset = regIndex;
|
}
|
||||||
mainMem[cpu.indexRegister + mem_offset] =
|
// RET - 00EE - Return from subroutine
|
||||||
cpu.registerArray[regIndex];
|
else if (opLowByte == 0xEE)
|
||||||
|
{
|
||||||
|
cpu.programCounter = cpu.stack[cpu.stackPointer--];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// LD [I], Vx - Fx65 - Read registers V0 through Vx from memory
|
break;
|
||||||
// starting at location I.
|
|
||||||
else
|
case 0x10:
|
||||||
|
case 0x20:
|
||||||
{
|
{
|
||||||
DQNT_ASSERT(opLowByte == 0x65);
|
u16 loc = ((0x0F & opHighByte) << 8) | (0xFF & opLowByte);
|
||||||
for (u32 regIndex = 0; regIndex <= regNum; regIndex++)
|
DQNT_ASSERT(loc <= 0x0FFF);
|
||||||
|
|
||||||
|
// JP addr - 1nnn - Jump to location nnn
|
||||||
|
if (opFirstNibble == 0x10)
|
||||||
{
|
{
|
||||||
u32 mem_offset = regIndex;
|
// NOTE: Jump to loc, as per below
|
||||||
cpu.registerArray[regIndex] =
|
}
|
||||||
mainMem[cpu.indexRegister + mem_offset];
|
// 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;
|
||||||
break;
|
|
||||||
};
|
// SE Vx, Vy - 5xy0 - Skip next instruction if Vx = Vy
|
||||||
#endif
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -53,4 +53,16 @@ typedef struct PlatformMemory
|
|||||||
u32 transientMemSize;
|
u32 transientMemSize;
|
||||||
} PlatformMemory;
|
} 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
|
#endif
|
||||||
|
146
src/dqnt.h
146
src/dqnt.h
@ -50,8 +50,17 @@ v2 V2i(i32 x, i32 y);
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// String Ops
|
// String Ops
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
i32 dqnt_strcmp(const char *a, const char *b);
|
bool dqnt_char_is_digit (char c);
|
||||||
i32 dqnt_strlen(const char *a);
|
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);
|
wchar_t dqnt_wchar_ascii_to_lower(wchar_t character);
|
||||||
i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b);
|
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);
|
void dqnt_rnd_pcg_seed (RandPCGState *pcg, u32 seed);
|
||||||
// Returns a random number N between [0, 0xFFFFFFFF]
|
// Returns a random number N between [0, 0xFFFFFFFF]
|
||||||
u32 dqnt_rnd_pcg_next (RandPCGState *pcg);
|
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]
|
// Returns a random integer N between [min, max]
|
||||||
i32 dqnt_rnd_pcg_range(RandPCGState *pcg, i32 min, i32 max);
|
i32 dqnt_rnd_pcg_range(RandPCGState *pcg, i32 min, i32 max);
|
||||||
|
|
||||||
@ -98,6 +109,24 @@ v2 V2i(i32 x, i32 y)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// String Ops
|
// 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)
|
i32 dqnt_strcmp(const char *a, const char *b)
|
||||||
{
|
{
|
||||||
while ((*a) == (*b))
|
while ((*a) == (*b))
|
||||||
@ -110,6 +139,86 @@ i32 dqnt_strcmp(const char *a, const char *b)
|
|||||||
return (((*a) < (*b)) ? -1 : 1);
|
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)
|
i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b)
|
||||||
{
|
{
|
||||||
while ((*a) == (*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);
|
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 dqnt_wstrlen(const wchar_t *a)
|
||||||
{
|
{
|
||||||
i32 result = 0;
|
i32 result = 0;
|
||||||
@ -160,18 +258,6 @@ i32 dqnt_wstrlen(const wchar_t *a)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 dqnt_strlen(const char *a)
|
|
||||||
{
|
|
||||||
i32 result = 0;
|
|
||||||
while ((*a))
|
|
||||||
{
|
|
||||||
result++;
|
|
||||||
a++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// PCG (Permuted Congruential Generator) Random Number Generator
|
// 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
|
// Convert a randomized u32 value to a float value x in the range 0.0f <= x
|
||||||
// < 1.0f. Contributed by Jonatan Hedborg
|
// < 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 exponent = 127;
|
||||||
u32 mantissa = value >> 9;
|
u32 mantissa = value >> 9;
|
||||||
@ -189,7 +275,7 @@ FILE_SCOPE f32 dqnt_rnd_f32_normalized_from_u32_(u32 value)
|
|||||||
return fresult - 1.0f;
|
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 ^= h >> 33;
|
||||||
h *= 0xff51afd7ed558ccd;
|
h *= 0xff51afd7ed558ccd;
|
||||||
@ -202,11 +288,11 @@ FILE_SCOPE u64 dqnt_rnd_murmur3_avalanche64_(u64 h)
|
|||||||
void dqnt_rnd_pcg_seed(RandPCGState *pcg, u32 seed)
|
void dqnt_rnd_pcg_seed(RandPCGState *pcg, u32 seed)
|
||||||
{
|
{
|
||||||
u64 value = (((u64)seed) << 1ULL) | 1ULL;
|
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[0] = 0U;
|
||||||
pcg->state[1] = (value << 1ULL) | 1ULL;
|
pcg->state[1] = (value << 1ULL) | 1ULL;
|
||||||
dqnt_rnd_pcg_next(pcg);
|
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);
|
dqnt_rnd_pcg_next(pcg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +307,7 @@ u32 dqnt_rnd_pcg_next(RandPCGState *pcg)
|
|||||||
|
|
||||||
f32 dqnt_rnd_pcg_nextf(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)
|
i32 dqnt_rnd_pcg_range(RandPCGState *pcg, i32 min, i32 max)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
#define DQNT_IMPLEMENTATION
|
#define DQNT_IMPLEMENTATION
|
||||||
#include "dqnt.h"
|
#include "dqnt.h"
|
||||||
|
|
||||||
|
@ -300,3 +300,55 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user