Start using dqnt lib

This commit is contained in:
Doyle Thai 2017-04-05 00:10:13 +10:00
parent dff3495087
commit b415f4c237
6 changed files with 272 additions and 160 deletions

View File

@ -1,127 +0,0 @@
#ifndef COMMON_H
#define COMMON_H
#include "stdint.h"
#define LOCAL_PERSIST static
#define FILE_SCOPE static
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef int64_t i64;
typedef int32_t i32;
typedef int16_t i16;
typedef float f32;
#define INVALID_CODE_PATH 0
#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
#ifdef DEBUG_MODE
#define ASSERT(expr) if (!(expr)) { (*((int *)0)) = 0; }
#else
#define ASSERT(expr)
#endif
#define MATH_ABS(x) (((x) < 0) ? (-(x)) : (x))
typedef union v2 {
struct { f32 x, y; };
struct { f32 w, h; };
} v2;
inline FILE_SCOPE v2 V2(f32 x, f32 y)
{
v2 result = {};
result.x = x;
result.y = y;
return result;
}
inline FILE_SCOPE v2 V2i(i32 x, i32 y)
{
v2 result = V2((f32)x, (f32)y);
return result;
}
inline FILE_SCOPE i32 common_strcmp(const char *a, const char *b)
{
while ((*a) == (*b))
{
if (!(*a)) return 0;
a++;
b++;
}
return (((*a) < (*b)) ? -1 : 1);
}
inline FILE_SCOPE i32 common_wstrcmp(const wchar_t *a, const wchar_t *b)
{
while ((*a) == (*b))
{
if (!(*a)) return 0;
a++;
b++;
}
return (((*a) < (*b)) ? -1 : 1);
}
inline FILE_SCOPE void common_wstrcat(const wchar_t *a, i32 lenA,
const wchar_t *b, i32 lenB, wchar_t *out,
i32 outLen)
{
ASSERT((lenA + lenB) < outLen);
i32 outIndex = 0;
for (i32 i = 0; i < lenA; i++)
out[outIndex++] = a[i];
for (i32 i = 0; i < lenB; i++)
out[outIndex++] = b[i];
ASSERT(outIndex <= outLen);
}
inline FILE_SCOPE wchar_t common_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;
}
inline FILE_SCOPE i32 common_wstrlen(const wchar_t *a)
{
i32 result = 0;
while ((*a))
{
result++;
a++;
}
return result;
}
inline FILE_SCOPE i32 common_strlen(const char *a)
{
i32 result = 0;
while ((*a))
{
result++;
a++;
}
return result;
}
#endif

View File

@ -1,5 +1,5 @@
#include "common.h"
#include "dchip8_platform.h"
#include "dqnt.h"
typedef struct Chip8CPU
{
@ -54,15 +54,13 @@ typedef struct Chip8CPU
} Chip8CPU;
FILE_SCOPE Chip8CPU cpu;
FILE_SCOPE u16 opCodes[35];
void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
PlatformMemory memory)
{
ASSERT(indexRegister >= 0 && indexRegister <= 0xFFF);
ASSERT(programCounter >= 0 && programCounter <= 0xFFF);
DQNT_ASSERT(indexRegister >= 0 && indexRegister <= 0xFFF);
DQNT_ASSERT(programCounter >= 0 && programCounter <= 0xFFF);
ASSERT(renderBuffer.bytesPerPixel == 4);
DQNT_ASSERT(renderBuffer.bytesPerPixel == 4);
const i32 numPixels = renderBuffer.width * renderBuffer.height;
u32 *bitmapBuffer = (u32 *)renderBuffer.memory;
@ -86,7 +84,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
if (!cpu.isInit)
{
ASSERT(memory.permanentMemSize == (4096 / 4));
DQNT_ASSERT(memory.permanentMemSize == (4096 / 4));
cpu.isInit = true;
// NOTE: Everything before 0x200 is reserved for the actual emulator
@ -94,8 +92,11 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
cpu.programCounter = INIT_ADDRESS;
cpu.I = 0;
cpu.stackPointer = 0;
// TODO(doyle): Load rom
}
#if 0
u8 *mainMem = (u8 *)memory.permanentMem;
u8 opHighByte = mainMem[cpu.programCounter++];
u8 opLowByte = mainMem[cpu.programCounter++];
@ -121,7 +122,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
case 0x20:
{
u16 loc = ((0x0F & opHighByte) << 8) | (0xFF & opLowByte);
ASSERT(loc <= 0x0FFF);
DQNT_ASSERT(loc <= 0x0FFF);
// JP addr - 1nnn - Jump to location nnn
if (opFirstNibble == 0x10)
@ -131,10 +132,10 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
// Call addr - 2nnn - Call subroutine at nnn
else
{
ASSERT(opFirstNibble == 0x20);
DQNT_ASSERT(opFirstNibble == 0x20);
cpu.stackPointer++;
ASSERT(cpu.stackPointer < ARRAY_COUNT(cpu.stack));
DQNT_ASSERT(cpu.stackPointer < DQNT_ARRAY_COUNT(cpu.stack));
cpu.stack[cpu.stackPointer] = cpu.programCounter;
}
@ -146,7 +147,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
case 0x40:
{
u8 regNum = (0x0F & opHighByte);
ASSERT(regNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 valToCheck = opLowByte;
// SE Vx, byte - 3xkk - Skip next instruction if Vx == kk
@ -158,7 +159,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
// SNE Vx, byte - 4xkk - Skip next instruction if Vx == kk
else
{
ASSERT(opFirstNibble == 0x40);
DQNT_ASSERT(opFirstNibble == 0x40);
if (cpu.registerArray[regNum] != valToCheck)
cpu.programCounter += 2;
}
@ -169,10 +170,10 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
case 0x50:
{
u8 firstRegNum = (0x0F & opHighByte);
ASSERT(firstRegNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 secondRegNum = (0xF0 & opLowByte);
ASSERT(secondRegNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
if (cpu.registerArray[firstRegNum] ==
cpu.registerArray[secondRegNum])
@ -186,7 +187,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
case 0x70:
{
u8 regNum = (0x0F & opHighByte);
ASSERT(regNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 valToOperateOn = opLowByte;
// LD Vx, byte - 6xkk - Set Vx = kk
@ -197,7 +198,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
// ADD Vx, byte - 7xkk - Set Vx = Vx + kk
else
{
ASSERT(opFirstNibble == 0x70);
DQNT_ASSERT(opFirstNibble == 0x70);
cpu.registerArray[regNum] += valToOperateOn;
}
@ -207,10 +208,10 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
case 0x80:
{
u8 firstRegNum = (0x0F & opHighByte);
ASSERT(firstRegNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 secondRegNum = (0xF0 & opLowByte);
ASSERT(secondRegNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 *vx = &cpu.registerArray[firstRegNum];
u8 *vy = &cpu.registerArray[secondRegNum];
@ -280,7 +281,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
// SHL Vx {, Vy} - 8xyE - Set Vx = SHL 1
else
{
ASSERT(opLowByte == 0x0E);
DQNT_ASSERT(opLowByte == 0x0E);
if ((*vx >> 7) == 1)
cpu.VF = 1;
else
@ -295,10 +296,10 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
case 0x90:
{
u8 firstRegNum = (0x0F & opHighByte);
ASSERT(firstRegNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 secondRegNum = (0xF0 & opLowByte);
ASSERT(secondRegNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 *vx = &cpu.registerArray[firstRegNum];
u8 *vy = &cpu.registerArray[secondRegNum];
@ -327,7 +328,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
case 0xC0:
{
u8 firstRegNum = (0x0F & opHighByte);
ASSERT(firstRegNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 andBits = opLowByte;
u8 *vx = &cpu.registerArray[firstRegNum];
@ -360,7 +361,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
// Vx is not pressed
else
{
ASSERT(opLowByte == 0xA1);
DQNT_ASSERT(opLowByte == 0xA1);
}
if (skipNextInstruction) cpu.programCounter += 2;
@ -370,7 +371,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
case 0xF0:
{
u8 regNum = (0x0F & opHighByte);
ASSERT(regNum < ARRAY_COUNT(cpu.registerArray));
DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
u8 *vx = &cpu.registerArray[regNum];
// LD Vx, DT - Fx07 - Set Vx = delay timer value
@ -423,7 +424,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
// starting at location I.
else
{
ASSERT(opLowByte == 0x65);
DQNT_ASSERT(opLowByte == 0x65);
for (u32 regIndex = 0; regIndex <= regNum; regIndex++)
{
u32 mem_offset = regIndex;
@ -434,4 +435,5 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
}
break;
};
#endif
}

View File

@ -1,7 +1,7 @@
#ifndef DCHIP_8_PLATFORM
#define DCHIP_8_PLATFORM
#include "Common.h"
#include "dqnt.h"
typedef struct PlatformRenderBuffer
{

235
src/dqnt.h Normal file
View File

@ -0,0 +1,235 @@
#ifndef DQNT_H
#define DQNT_H
/*
#define DQNT_IMPLEMENTATION
#include "dqnt.h"
*/
////////////////////////////////////////////////////////////////////////////////
// General Purpose Operations
////////////////////////////////////////////////////////////////////////////////
#include "stdint.h"
#define LOCAL_PERSIST static
#define FILE_SCOPE static
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef int32_t i64;
typedef int32_t i32;
typedef int64_t i16;
typedef float f32;
#define DQNT_INVALID_CODE_PATH 0
#define DQNT_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
#ifdef DEBUG_MODE
#define DQNT_ASSERT(expr) if (!(expr)) { (*((i32 *)0)) = 0; }
#else
#define DQNT_ASSERT(expr)
#endif
#define DQNT_MATH_ABS(x) (((x) < 0) ? (-(x)) : (x))
////////////////////////////////////////////////////////////////////////////////
// Vec2
////////////////////////////////////////////////////////////////////////////////
typedef union v2 {
struct { f32 x, y; };
struct { f32 w, h; };
} v2;
v2 V2(f32 x, f32 y);
// Create a 2d-vector using ints and typecast to floats
v2 V2i(i32 x, i32 y);
////////////////////////////////////////////////////////////////////////////////
// String Ops
////////////////////////////////////////////////////////////////////////////////
i32 dqnt_strcmp(const char *a, const char *b);
i32 dqnt_strlen(const char *a);
wchar_t dqnt_wchar_ascii_to_lower(wchar_t character);
i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b);
void dqnt_wstrcat(const wchar_t *a, i32 lenA, const wchar_t *b, i32 lenB, wchar_t *out, i32 outLen);
i32 dqnt_wstrlen(const wchar_t *a);
////////////////////////////////////////////////////////////////////////////////
// PCG (Permuted Congruential Generator) Random Number Generator
////////////////////////////////////////////////////////////////////////////////
typedef struct RandPCGState
{
u64 state[2];
} RandPCGState;
// Init generator with seed. The generator is not valid until it's been seeded.
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 integer N between [min, max]
i32 dqnt_rnd_pcg_range(RandPCGState *pcg, i32 min, i32 max);
#endif /* DQNT_H */
#ifdef DQNT_IMPLEMENTATION
#undef DQNT_IMPLEMENTATION
////////////////////////////////////////////////////////////////////////////////
// Vec2
////////////////////////////////////////////////////////////////////////////////
v2 V2(f32 x, f32 y)
{
v2 result = {};
result.x = x;
result.y = y;
return result;
}
v2 V2i(i32 x, i32 y)
{
v2 result = V2((f32)x, (f32)y);
return result;
}
////////////////////////////////////////////////////////////////////////////////
// String Ops
////////////////////////////////////////////////////////////////////////////////
i32 dqnt_strcmp(const char *a, const char *b)
{
while ((*a) == (*b))
{
if (!(*a)) return 0;
a++;
b++;
}
return (((*a) < (*b)) ? -1 : 1);
}
i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b)
{
while ((*a) == (*b))
{
if (!(*a)) return 0;
a++;
b++;
}
return (((*a) < (*b)) ? -1 : 1);
}
void dqnt_wstrcat(const wchar_t *a, i32 lenA, const wchar_t *b, i32 lenB,
wchar_t *out, i32 outLen)
{
DQNT_ASSERT((lenA + lenB) < outLen);
i32 outIndex = 0;
for (i32 i = 0; i < lenA; i++)
out[outIndex++] = a[i];
for (i32 i = 0; i < lenB; i++)
out[outIndex++] = b[i];
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;
while ((*a))
{
result++;
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
////////////////////////////////////////////////////////////////////////////////
// Public Domain library with thanks to Mattias Gustavsson
// https://github.com/mattiasgustavsson/libs/blob/master/docs/rnd.md
// 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)
{
u32 exponent = 127;
u32 mantissa = value >> 9;
u32 result = (exponent << 23) | mantissa;
f32 fresult = *(f32 *)(&result);
return fresult - 1.0f;
}
FILE_SCOPE u64 dqnt_rnd_murmur3_avalanche64_(u64 h)
{
h ^= h >> 33;
h *= 0xff51afd7ed558ccd;
h ^= h >> 33;
h *= 0xc4ceb9fe1a85ec53;
h ^= h >> 33;
return h;
}
void dqnt_rnd_pcg_seed(RandPCGState *pcg, u32 seed)
{
u64 value = (((u64)seed) << 1ULL) | 1ULL;
value = dqnt_rnd_murmur3_avalanche64_(value);
pcg->state[0] = 0U;
pcg->state[1] = (value << 1ULL) | 1ULL;
dqnt_rnd_pcg_next(pcg);
pcg->state[0] += dqnt_rnd_murmur3_avalanche64_(value);
dqnt_rnd_pcg_next(pcg);
}
u32 dqnt_rnd_pcg_next(RandPCGState *pcg)
{
u64 oldstate = pcg->state[0];
pcg->state[0] = oldstate * 0x5851f42d4c957f2dULL + pcg->state[1];
u32 xorshifted = (u32)(((oldstate >> 18ULL) ^ oldstate) >> 27ULL);
u32 rot = (u32)(oldstate >> 59ULL);
return (xorshifted >> rot) | (xorshifted << ((-(i32)rot) & 31));
}
f32 dqnt_rnd_pcg_nextf(RandPCGState *pcg)
{
return dqnt_rnd_f32_normalized_from_u32_(dqnt_rnd_pcg_next(pcg));
}
i32 dqnt_rnd_pcg_range(RandPCGState *pcg, i32 min, i32 max)
{
i32 const range = (max - min) + 1;
if (range <= 0) return min;
i32 const value = (i32)(dqnt_rnd_pcg_nextf(pcg) * range);
return min + value;
}
#endif /* DQNT_IMPLEMENTATION */

View File

@ -1,3 +1,5 @@
#include "win32_dchip8.cpp"
#define DQNT_IMPLEMENTATION
#include "dqnt.h"
#include "win32_dchip8.cpp"
#include "dchip8.cpp"

View File

@ -9,9 +9,9 @@
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "dchip8.h"
#include "dchip8_platform.h"
#include "dqnt.h"
FILE_SCOPE bool globalRunning = false;
FILE_SCOPE LARGE_INTEGER globalQueryPerformanceFrequency;
@ -209,7 +209,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
renderBitmap.width = header.biWidth;
renderBitmap.height = header.biHeight;
renderBitmap.bytesPerPixel = header.biBitCount / 8;
ASSERT(renderBitmap.bytesPerPixel >= 1);
DQNT_ASSERT(renderBitmap.bytesPerPixel >= 1);
HDC deviceContext = GetDC(mainWindow);
renderBitmap.handle =
@ -230,7 +230,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
u8 stackMemory[4096] = {};
PlatformMemory platformMemory = {};
platformMemory.permanentMem = &stackMemory;
platformMemory.permanentMemSize = (ARRAY_COUNT(stackMemory) / 4);
platformMemory.permanentMemSize = (DQNT_ARRAY_COUNT(stackMemory) / 4);
QueryPerformanceFrequency(&globalQueryPerformanceFrequency);
const f32 TARGET_FRAMES_PER_S = 60.0f;
@ -292,9 +292,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
f32 msPerFrame = 1000.0f * frameTimeInS;
wchar_t windowTitleBuffer[128] = {};
_snwprintf_s(windowTitleBuffer, ARRAY_COUNT(windowTitleBuffer),
ARRAY_COUNT(windowTitleBuffer), L"dchip-8 | %5.2f ms/f",
msPerFrame);
_snwprintf_s(windowTitleBuffer, DQNT_ARRAY_COUNT(windowTitleBuffer),
DQNT_ARRAY_COUNT(windowTitleBuffer),
L"dchip-8 | %5.2f ms/f", msPerFrame);
SetWindowText(mainWindow, windowTitleBuffer);
}