Commit 91b18075 authored by Felix Kopp's avatar Felix Kopp
Browse files

initial commit

parents
This diff is collapsed.
all:
gcc -Wall gameboy.c -o gameboy
make clean
clean:
rm -rf *.c *.o *.h
\ No newline at end of file
# GameBoy CLI Emulator
This piece of software is an emulator for the Nintendo GameBoy. I want to try to
make this executable inside of a console, where each pixel is one colored
character.
Further information will be published as the project progresses.
#ifndef CONST_H
#define CONST_H
/* The amount of clock cycles per second (clock speed in Hz) */
#define GAMEBOY_CLOCK_SPEED (double) 6000000
/* The amount of time (in nanoseconds) one cycle takes to execute */
#define GAMEBOY_CLOCK_DURATION (double) 1 / GAMEBOY_CLOCK_SPEED
#endif
\ No newline at end of file
/*
* This header files contains the APIs needed to draw the screen content to the terminal window.
*/
#ifndef DRAW_H
#define DRAH_H
#define HORIZONTAL_PIXELS 160
#define VERTICAL_PIXELS 144
#include <stdio.h>
#include <stdlib.h>
char *currentMatrix[160][144];
void clear()
{
system("cls");
}
void draw()
{
int i;
char *currentLine[160];
clear();
for(i = 0; i < 160; i++)
{
printf("%s\n", currentLine);
}
}
#endif
\ No newline at end of file
#ifndef EXECUTORS_H
#define EXECUTORS_H
#include <registers.h>
#include <stdio.h>
/* NOP | 0x00 */
void nop()
{
return;
}
/* LD BC,d16 | 0x01 */
void ld_bc_d16()
{
}
/* LD (BC),A | 0x02 */
void ld__bc_a()
{
}
/* INC BC | 0x03 */
void inc_bc()
{
reg->bc ++;
}
/* INC B | 0x04 */
void inc_b()
{
if(reg->b == 0b11111111)
{ // Check for overflow
reg->h = 0b00000001;
reg->b = 0b00000000;
return;
}
reg->b ++;
}
/* DEC B | 0x05 */
void dec_b()
{
if(reg->b == 0b00000000)
{
reg->h = 0b00000001;
reg->b = 0b11111111;
}
reg->b --;
}
/* LD B,d8 | 0x06 */
void ld_b_d8(unsigned char operand)
{
reg->b = operand;
}
/* RLCA | 0x07 */
void rlca()
{
printf("RLCA not implemented yet.");
}
/* LD (a16),SP | 0x08 */
void ld_a16_sp()
{
}
/* ADD HL,BC | 0x98 */
void add_hl_bc()
{
reg->hl += reg->bc;
}
/* LD A,(BC) | 0x0A */
void ld_a__bc()
{
}
#endif
\ No newline at end of file
#ifndef FILE_HANDLER_H
#define FILE_HANDLER_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
/* Reads the *.gb binary from the specified path and puts its content into buffer */
int read_file(char **buffer, unsigned int buffer_length, char const* path)
{
FILE *filep;
size_t filesize;
long off_end;
int rc;
filep = fopen(path, "rb");
if(filep == NULL)
return -1;
rc = fseek(filep, 0L, SEEK_END);
if(rc != 0)
return -2;
if(0 > (off_end = ftell(filep)))
return -3;
filesize = (size_t) off_end;
*buffer = malloc(filesize);
if(*buffer == NULL)
return -4;
rewind(filep);
if(filesize != fread(*buffer, 1, filesize, filep))
{
free(*buffer);
return -5;
}
if(fclose(filep) == EOF)
{
free(*buffer);
return -6;
}
return (int) filesize;
}
#endif
\ No newline at end of file
/*
* This is a GameBoy CLI Emulator.
*
* Copyright (c) 2017 Sandtler <dumsuf.sandtler@gmail.com>
*
* Return values:
* 0: The program terminated normally without errors.
* -1: There wasn't enough space to display the display.
* -2: The ROM file could not be found.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <windows.h>
#include <interpreter.h>
#include <draw.h>
#define PATH_BUFFER_LENGTH 2048
int main(int argc, char *argv[])
{
char *path[PATH_BUFFER_LENGTH];
CONSOLE_SCREEN_BUFFER_INFO csbi;
int cols, rows;
printf("GameBoy CLI Emulator by Sandtler v0.1\n");
// Check if there is enough space to display this shit
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
if(cols < VERTICAL_PIXELS | rows < HORIZONTAL_PIXELS)
{
printf("The terminal window can hold up to %i by %i characters, but we need %i by %i. Please make your console window bigger.\n",
cols, rows, VERTICAL_PIXELS, HORIZONTAL_PIXELS);
return -1;
}
if(argv[0] == '/')
{
if(strlen(argv) <= PATH_BUFFER_LENGTH)
strcpy(path, argv);
else
{
printf("Sorry, your specified path is longer than %i characters and would exceed the buffer.\n", PATH_BUFFER_LENGTH);
return;
}
}
else
{
}
return 0;
}
\ No newline at end of file
#ifndef INTERPRETER_H
#define INTERPRETER_H
#include <registers.h>
#include <const.h>
#include <time.h>
void op_execute(struct instruction* i)
{
static struct timespec *sleep_time; // The time that we have to sleep till the next operation
static clock_t last; // The time of the last emulation cycle
static double time_spent; // The amount of time since the last emulation cycle in seconds
static int cycles_last; // The amount of CPU cycles the last instruction took
static void (*operation) (); // A Pointer to the next operation method to call
time_spent = (double)(clock() - last) / CLOCKS_PER_SEC;
if(time_spent < (double) 1 / GAMEBOY_CLOCK_SPEED)
{
sleep_time->tv_nsec = (double) (time_spent / (double) 1000000000) - (double) (GAMEBOY_CLOCK_DURATION * (double) cycles_last);
sleep_time->tv_sec = 0;
nanosleep(sleep_time);
}
operation = i->execute;
operation();
cycles_last = i->cycles;
last = clock();
}
#endif
\ No newline at end of file
#ifndef REGISTERS_H
#define REGISTERS_H
#include <executors.h>
struct registers {
struct {
union {
struct {
unsigned char f;
unsigned char a;
};
unsigned short af;
};
};
struct {
union {
struct {
unsigned char c;
unsigned char b;
};
unsigned short bc;
};
};
struct {
union {
struct {
unsigned char e;
unsigned char d;
};
unsigned short de;
};
};
struct {
union {
struct {
unsigned char l;
unsigned char h;
};
unsigned short hl;
};
};
unsigned short sp;
unsigned short pc;
unsigned char z;
unsigned char n;
unsigned char h;
unsigned char c;
} extern reg;
char *rom[8000000000];
struct instruction {
char *disassembly;
unsigned char opLength;
void *execute;
int cycles;
} extern const instructions[256];
struct registers *reg;
const struct instruction instructions[256] = {
{ "NOP", 1, nop, 4 }, // 0x00
{ "LD BC,d16", 2, ld_bc_d16, 12 }, // 0x01
{ "LD (BC),A", 0, ld__bc_a, 8 }, // 0x02
{ "INC BC", 1, inc_bc, 8 }, // 0x03
{ "INC B", 1, inc_b, 4 }, // 0x04
{ "DEC B", 1, dec_b, 4 }, // 0x05
{ "LD 8,d8", 2, ld_b_d8, 8 }, // 0x06
{ "RLCA", 1, rlca, 4 }, // 0x07
{ "LD (a16),SP", 3, ld_a16_sp, 20 }, // 0x08
{ "ADD HL,BC", 1, add_hl_bc, 8 }, // 0x09
};
#endif
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment