From 19d138fb5f95c1e30c34e050d8f4c00a87fea152 Mon Sep 17 00:00:00 2001
From: Lauchmelder <robert.trololo@gmail.com>
Date: Sat, 23 Oct 2021 19:30:02 +0200
Subject: [PATCH] added ppu

---
 NES Emulator/CMakeLists.txt |   2 +-
 NES Emulator/bus.c          |  10 +++-
 NES Emulator/bus.h          |   2 +
 NES Emulator/log.c          |   9 +++-
 NES Emulator/ppu.c          | 101 ++++++++++++++++++++++++++++++++++++
 NES Emulator/ppu.h          |  95 +++++++++++++++++++++++++++++++++
 6 files changed, 216 insertions(+), 3 deletions(-)
 create mode 100644 NES Emulator/ppu.c
 create mode 100644 NES Emulator/ppu.h

diff --git a/NES Emulator/CMakeLists.txt b/NES Emulator/CMakeLists.txt
index 79888f4..f37c02f 100644
--- a/NES Emulator/CMakeLists.txt	
+++ b/NES Emulator/CMakeLists.txt	
@@ -1,6 +1,6 @@
 cmake_minimum_required (VERSION 3.8)
 
-add_executable (nesemu "main.c"  "cpu.h" "types.h" "bus.h" "bus.c" "cartridge.h" "cpu.c" "cartridge.c" "opcodes.c" "log.c")
+add_executable (nesemu "main.c"  "cpu.h" "types.h" "bus.h" "bus.c" "cartridge.h" "cpu.c" "cartridge.c" "opcodes.c" "log.c" "ppu.h" "ppu.c")
 
 if(MSVC)
 target_compile_definitions(nesemu PUBLIC _CRT_SECURE_NO_WARNINGS)
diff --git a/NES Emulator/bus.c b/NES Emulator/bus.c
index 9144e5a..19b8a63 100644
--- a/NES Emulator/bus.c	
+++ b/NES Emulator/bus.c	
@@ -4,6 +4,7 @@
 #include <memory.h>
 
 #include "cpu.h"
+#include "ppu.h"
 #include "cartridge.h"
 
 struct Bus* createBus()
@@ -35,6 +36,9 @@ struct Bus* createBus()
 	// Create CPU and attach it
 	bus->cpu = createCPU(bus);
 
+	// Create PPU and attack it
+	bus->ppu = createPPU(bus);
+
 	// Create and insert cartridge
 	bus->cartridge = createCartridge(bus, "roms/nestest.nes");
 
@@ -46,6 +50,7 @@ struct Bus* createBus()
 void destroyBus(struct Bus* bus)
 {
 	destroyCartridge(bus->cartridge);
+	destroyPPU(bus->ppu);
 	destroyCPU(bus->cpu);
 	
 	free(bus->io);
@@ -104,5 +109,8 @@ void writeBus(struct Bus* bus, Word addr, Byte val)
 
 void tick(struct Bus* bus)
 {
-	tickInstr(bus->cpu);
+	for (int i = 0; i < 3; i++)
+		tickPPU(bus->ppu);
+
+	tickCPU(bus->cpu);
 }
\ No newline at end of file
diff --git a/NES Emulator/bus.h b/NES Emulator/bus.h
index ceafd6a..e9b2d39 100644
--- a/NES Emulator/bus.h	
+++ b/NES Emulator/bus.h	
@@ -4,6 +4,7 @@
 #include "types.h"
 
 struct CPU;
+struct PPU;
 struct Cartridge;
 
 // Main communication path for devices and memory in the NES
@@ -13,6 +14,7 @@ struct Bus
 	Byte* io;
 
 	struct CPU* cpu;
+	struct PPU* ppu;
 	struct Cartridge* cartridge;
 };
 
diff --git a/NES Emulator/log.c b/NES Emulator/log.c
index eb96188..c373f88 100644
--- a/NES Emulator/log.c	
+++ b/NES Emulator/log.c	
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include "bus.h"
 #include "cpu.h"
+#include "ppu.h"
 
 void logBusState(struct Bus* bus)
 {
@@ -40,5 +41,11 @@ void logBusState(struct Bus* bus)
 
 	printf("%-28s", buffer);
 
-	printf("A:%02X X:%02X Y:%02X SP:%02X P:%02X CYC:%zu\n", bus->cpu->acc, bus->cpu->x, bus->cpu->y, bus->cpu->sp, bus->cpu->status.raw, bus->cpu->totalCycles);
+	printf("A:%02X X:%02X Y:%02X SP:%02X P:%02X PPU:%3d,%3d CYC:%zu\n", 
+		bus->cpu->acc, 
+		bus->cpu->x, bus->cpu->y, 
+		bus->cpu->sp, 
+		bus->cpu->status.raw, 
+		bus->ppu->y, bus->ppu->x,
+		bus->cpu->totalCycles);
 }
\ No newline at end of file
diff --git a/NES Emulator/ppu.c b/NES Emulator/ppu.c
new file mode 100644
index 0000000..c9a1cbd
--- /dev/null
+++ b/NES Emulator/ppu.c	
@@ -0,0 +1,101 @@
+#include "ppu.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "bus.h"
+
+struct PPU* createPPU(struct Bus* parent)
+{
+	struct PPU* ppu = (struct PPU*)malloc(sizeof(struct PPU));
+	if (ppu == NULL)
+	{
+		fprintf(stderr, "Failed to allocate memory for PPU object.\n");
+		exit(1);
+	}
+
+	ppu->bus = parent;
+
+	for (int i = 0; i < 2; i++)
+	{
+		ppu->patternTables[i] = (Byte*)malloc(0x1000);
+		if (ppu->patternTables[i] == NULL)
+		{
+			fprintf(stderr, "Failed to allocate memory for PPU pattern table #%d object.\n", i);
+			exit(1);
+		}
+
+		memset(ppu->patternTables[i], 0, 0x1000);
+	}
+
+	for (int i = 0; i < 4; i++)
+	{
+		ppu->nametables[i] = (Byte*)malloc(0x0400);
+		if (ppu->nametables[i] == NULL)
+		{
+			fprintf(stderr, "Failed to allocate memory for PPU nametable #%d object.\n", i);
+			exit(1);
+		}
+
+		memset(ppu->nametables[i], 0, 0x0400);
+	}
+
+	ppu->paletteIndexes = (Byte*)malloc(0x20);
+	if (ppu->paletteIndexes == NULL)
+	{
+		fprintf(stderr, "Failed to allocate memory for PPU palette RAM indexes.\n");
+		exit(1);
+	}
+
+	ppu->oam = (Byte*)malloc(0x100);
+	if (ppu->oam == NULL)
+	{
+		fprintf(stderr, "Failed to allocate memory for PPU OAM.\n");
+		exit(1);
+	}
+
+	ppu->ppuctrl.raw = 0b00000000;
+	ppu->ppumask.raw = 0b00000000;
+	ppu->ppustatus.raw = 0b10100000;
+	ppu->oamaddr = 0x00;
+	ppu->ppuAddr = 0x00;
+	ppu->ppuData = 0x00;
+
+	ppu->x = 0;
+	ppu->y = 0;
+
+	return ppu;
+}
+
+void destroyPPU(struct PPU* ppu)
+{
+	free(ppu->oam);
+	free(ppu->paletteIndexes);
+	free(ppu->nametables);
+	free(ppu->patternTables);
+
+	free(ppu);
+}
+
+Byte ppuRead(struct PPU* ppu, Word addr)
+{
+	return 0x00;
+}
+
+void ppuWrite(struct PPU* ppu, Word addr, Byte val)
+{
+}
+
+void tickPPU(struct PPU* ppu)
+{
+	ppu->x++;
+
+	if (ppu->x == 341)
+	{
+		ppu->x = 0;
+		ppu->y++;
+
+		if (ppu->y == 261)
+			ppu->y = 0;
+	}
+}
diff --git a/NES Emulator/ppu.h b/NES Emulator/ppu.h
new file mode 100644
index 0000000..91ee4dd
--- /dev/null
+++ b/NES Emulator/ppu.h	
@@ -0,0 +1,95 @@
+#ifndef _PPU_H_
+#define _PPU_H_
+
+#include "types.h"
+
+struct Bus;
+
+struct PPU
+{
+	// REGISTERS
+	union
+	{
+		struct 
+		{
+			Byte nametable : 2;
+			Byte increment : 1;
+			Byte spriteTile : 1;
+			Byte bgTile : 1;
+			Byte spriteHeight : 1;
+			Byte master : 1;
+			Byte nmiEnable : 1;
+		};
+
+		Byte raw;
+
+	} ppuctrl;
+
+	union
+	{
+		struct
+		{
+			Byte greyscale : 1;
+			Byte bgLeftColumn : 1;
+			Byte spriteLeftColumn : 1;
+			Byte bgEnable : 1;
+			Byte spriteEnable : 1;
+			Byte colorEmphasis : 3;
+		};
+
+		Byte raw;
+
+	} ppumask;
+
+	union
+	{
+		struct
+		{
+			Byte padding : 5;
+			Byte overflow : 1;
+			Byte spriteZeroHit : 1;
+			Byte vBlank : 1;
+		};
+
+		Byte raw;
+
+	} ppustatus;
+
+	Byte oamaddr;
+	Byte oamdata;
+	Byte ppuScroll;
+	Byte ppuAddr;
+	Byte ppuData;
+	Byte oamdma;
+
+	Byte* patternTables[2];
+	Byte* nametables[4];
+	Byte* paletteIndexes;
+
+	union
+	{
+		struct
+		{
+			Byte y;
+			Byte tile;
+			Byte attr;
+			Byte x;
+		};
+
+		DWord raw;
+	}* oam;
+
+	Word x, y;
+
+	struct Bus* bus;
+};
+
+struct PPU* createPPU(struct Bus* parent);
+void destroyPPU(struct PPU* ppu);
+
+Byte ppuRead(struct PPU* ppu, Word addr);
+void ppuWrite(struct PPU* ppu, Word addr, Byte val);
+
+void tickPPU(struct PPU* ppu);
+
+#endif // _PPU_H_
\ No newline at end of file