Comments (5)
main.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "nes.h"
#include "emulator.h"
int main(void)
{
//注意文件路径格式,不然会出现找不到文件
char game_name[] = "D:\mario.nes";
int tmp;
tmp = nes_loadrom(game_name);
if (tmp != 0) {
printf("NES rom load failed, error code: %d\n", tmp);
exit(tmp);
}
return 0;
}
from response3.
nes.h
#pragma once
#ifndef NES_H
#define NES_H
#include <stdint.h>
#define FPS 60
#define WIDTH 256
#define HEIGHT 240
#define FILE_NOT_EXIST 1
#define FILE_HEADER_READ_FAILED 2
#define NOT_IS_NES_FORMAT 3
#define MEMORY_ALLOCATE_FAILED 4
#define PRG_ROM_LOAD_FAILED 5
#define CHR_ROM_LOAD_FAILED 6
int nes_loadrom(char* rom);
#endif
from response3.
nes.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include "nes.h"
#include "cartridge.h"
cartridge_t cartridge;
int nes_loadrom(char* rom)
{
FILE* file;
file = fopen(rom, "rb+");
if (file == NULL)
{
return FILE_NOT_EXIST;
}
if (fread(cartridge.header,sizeof(uint8_t),16,file)!=16)
{
return FILE_HEADER_READ_FAILED;
}
else if (cartridge.header[0] != 0x4e || cartridge.header[1] != 0x45 || cartridge.header[2] != 0x53 || cartridge.header[3] != 0x1a)
{
return NOT_IS_NES_FORMAT;
}
else
{
/* 读取 ROM 信息 */
cartridge.prg_rom_size = 16 * 1024 * cartridge.header[4];
cartridge.chr_rom_size = 8 * 1024 * cartridge.header[5];
cartridge.prg_ram_size = 8 * 1024 * cartridge.header[8];
if (cartridge.chr_rom_size == 0)
{
cartridge.chr_rom_size = 8 * 1024;
}
if (cartridge.prg_ram_size == 0)
{
cartridge.prg_ram_size = 8 * 1024;
}
}
return 0;
}
from response3.
cartridge.h
#pragma once
#include <stdint.h>
typedef struct Cartridge
{
/**
* NES ROM 的 header
* 一共有 16 字节, 每个字节定义如下:
* 0-3 字节: 固定值, $4E $45 $53 $1A (前三字节即为 "NES")
* 4: PRG ROM 大小, 单位为 16KB 的倍数
* 5: CHR ROM 大小, 单位为 8KB 的倍数, 0 代表 8KB
* 6: Flag 6
* 7: Flag 7
* 8: PRG RAM 大小, 单位为 8KB 的倍数, 0 代表 8KB
* 9: Flag 9
* 10: Flag 10
* 11-15: 统一用 0 填充
* 对于任天堂第一方游戏, 无需考虑 Flag 6, Flag 7, Flag 9, Flag 10
*
* 参考资料: http://ewind.us/2015/nes-emu-3-rom-assembly/
* http://wiki.nesdev.com/w/index.php/INES
/
//unsigned char uint8_t
uint8_t header[16];
int prg_rom_size; // PRG ROM 大小 (Byte)
int chr_rom_size; // CHR ROM 大小 (Byte)
int prg_ram_size; // PRG RAM 大小 (Byte)
uint8_t prg_rom;
uint8_t* chr_rom;
}cartridge_t;
from response3.
//CPU复位
void cpu_resrt() {
cpu.reg_sp -= 3;
cpu.reg_p |= FLAG_INTERRUPT;
memory_write_byte(0x4015, 0);
cpu.reg_pc = memory_read_word(0xfffc);
}
//检查并设置zero flag与negative flag
void cpu_checknz(uint8_t n) {
if ((n >> 7) & 1)
{
cpu.reg_p |= FLAG_NEGATIVE;
}
else
{
cpu.reg_p &= ~FLAG_NEGATIVE;
}
if (n == 0)
{
cpu.reg_p = FLAG_ZERO;
}
else
{
cpu.reg_p &= ~FLAG_ZERO;
}
}
//修改flag
void cpu_modify_flag(uint8_t flag, int value) {
if (value)
{
cpu.reg_p |= flag;
}
else
{
cpu.reg_p &= ~flag;
}
}
//栈操作
void cpu_stack_push_byte(uint8_t data) {
memory_write_byte(0x100 + cpu.reg_sp, data);
cpu.reg_sp -= 1;
}
void cpu_stack_push_word(uint16_t data) {
memory_write_word(0x0ff + cpu.reg_sp, data);
cpu.reg_sp -= 2;
}
uint8_t cpu_stack_pop_byte() {
cpu.reg_sp += 1;
return memory_read_byte(0x100 + cpu.reg_sp);
}
uint16_t cpu_stack_pop_word() {
cpu.reg_sp += 2;
return memory_read_word(0x0ff + cpu.reg_sp);
}
/* 存储 CPU 经过寻址后得到的地址和该地址对应的值 */
uint16_t op_address;
uint8_t op_value;
uint8_t additional_cycles; // 对于某些寻址方式, 如果跨页访问, 需要多使用一个 CPU Cycle
/* implied (1 字节)
- 隐含寻址. 与累加器寻址类似, 不过指令所需的操作数不在 A 中, 而在其他寄存器中
*/
void cpu_addressing_implied() {
additional_cycles = 0;
}
/* accumulator (1 字节)
- 缩写: A
- 累加器寻址. 指令所需操作数在累加器 A 中, 无需操作数
*/
void cpu_addressing_accumulator() {
additional_cycles = 0;
}
/* immediate (2 字节)
- 缩写: #v
- 立即数寻址. 后面跟一个 8 位的立即数
*/
void cpu_addressing_immediate() {
op_value = memory_read_byte(cpu.reg_pc);
cpu.reg_pc++;
additional_cycles = 0;
}
/* zeropage (2 字节)
- 缩写: d
- 零页寻址. 地址 00 ~ FF 为零页地址
*/
void cpu_addressing_zerppage() {
op_address = memory_read_byte(cpu.reg_pc);
op_value = memory_read_byte(op_address);
cpu.reg_pc++;
additional_cycles = 0;
}
/* zeropage, X-indexed (2 字节)
- 缩写: d,x
- 使用寄存器 X 的零页寻址. 在零页寻址的基础上, 地址与 X 中的值相加
*/
void cpu_addressing_zeropage_x() {
op_address = (memory_read_byte(cpu.reg_pc) + cpu.reg_x) & 0xff;
op_value = memory_read_byte(op_address);
cpu.reg_pc++;
additional_cycles = 0;
}
/* zeropage, Y-indexed (2 字节)
- 缩写: d,y
- 使用寄存器 Y 的零页寻址. 在零页寻址的基础上, 地址与 Y 中的值相加
*/
void cpu_addressing_zeropage_y() {
op_address = (memory_read_byte(cpu.reg_pc) + cpu.reg_y) & 0xff;
op_value = memory_read_byte(op_address);
cpu.reg_pc++;
additional_cycles = 0;
}
/* absolute (3 字节)
- 缩写: a
- 直接寻址. 操作数即为内存地址, 低位在前, 高位在后
*/
void cpu_addressing_absolute() {
op_address = memory_read_word(cpu.reg_pc);
op_value = memory_read_byte(op_address);
cpu.reg_pc += 2;
additional_cycles = 0;
}
/* absolute, X-indexed (3 字节)
- 缩写: a,x
- 使用寄存器 X 的直接变址寻址. 16 位地址做为基地址, 与寄存器 X 的内容相加
*/
void cpu_addressing_absolute_x() {
op_address = memory_read_word(cpu.reg_pc) + cpu.reg_x;
op_value = memory_read_byte(op_address);
cpu.reg_pc += 2;
if ((op_address >> 8) != (cpu.reg_pc >> 8))
{
additional_cycles = 1;
}
else
{
additional_cycles = 0;
}
}
/* absolute, Y-indexed (3 字节)
- 缩写: a,y
- 使用寄存器 Y 的直接变址寻址. 16 位地址做为基地址, 与寄存器 Y 的内容相加
*/
void cpu_addressing_absolute_y() {
op_address = (memory_read_word(cpu.reg_pc) + cpu.reg_y) & 0xffff;
op_value = memory_read_byte(op_address);
cpu.reg_pc += 2;
if ((op_address >> 8) != (cpu.reg_pc >> 8))
{
additional_cycles = 1;
}
else
{
additional_cycles = 0;
}
}
/* relative (2 字节)
- 缩写: label
- 相对寻址. 用于条件转移指令. 指令第二字节为偏移量, 可正可负.
*/
void cpu_addressing_relative() {
op_address = memory_read_byte(cpu.reg_pc);
cpu.reg_pc++;
if (op_address & 0x80)
{
op_address -= 0x100;
}
op_address += cpu.reg_pc;
if ((op_address >> 8) != (cpu.reg_pc >> 8))
{
additional_cycles = 1;
}
else
{
additional_cycles = 0;
}
}
/* indirect (3 字节)
-
缩写: (a)
-
间接寻址. 对应地址内存单元中的数做为地址.
*/
void cpu_addressing_indirect() {
uint16_t arg_addr = memory_read_word(cpu.reg_pc);/* 据说这是 6502 的 Bug */
if ((arg_addr & 0xff) == 0xff) {
// 有 Bug 的情况下
op_address = (memory_read_byte(arg_addr & 0xff00) << 8) + memory_read_byte(arg_addr);
}
else {
// 正常情况下
op_address = memory_read_word(arg_addr);
}
cpu.reg_pc += 2;
additional_cycles = 0;
}
/* indirect, X-indexed (2 字节)
- 缩写: (d,x)
- 先变址 X 后间接寻址. 以 X 做为变址, 与基地址相加, 然后间接寻址
*/
void cpu_addressing_indirect_x() {
uint8_t arg_addr = memory_read_byte(cpu.reg_pc);
op_address = (memory_read_byte((arg_addr + cpu.reg_x + 1) & 0xff) << 8) | memory_read_byte((arg_addr + cpu.reg_x) & 0xff);
op_value = memory_read_byte(op_address);
cpu.reg_pc++;
additional_cycles = 0;
}
/* indirect, Y-indexed (2 字节)
- 缩写: (d),y
- 后变址 Y 间接寻址. 对操作数中的零页地址先做一次间接寻址, 得到 16 位地址, 再与 Y 相加, 对相加后得到的地址进行直接寻址.
*/
void cpu_addressing_indirect_y() {
uint8_t arg_addr = memory_read_byte(cpu.reg_pc);
op_address = (((memory_read_byte((arg_addr + 1) & 0xff) << 8) | memory_read_byte(arg_addr)) + cpu.reg_y) & 0xffff;
op_value = memory_read_byte(op_address);
cpu.reg_pc++;
if ((op_address >> 8) != (cpu.reg_pc >> 8))
{
additional_cycles = 1;
}
else
{
additional_cycles = 0;
}
}
//56种常规指令集
//ALU: 算术逻辑单元
void cpu_ora() {
cpu.reg_a |= op_value;
cpu_checknz(cpu.reg_a);
}
from response3.
Related Issues (20)
- Morning Commute Radio
- School Assignment HOT 2
- Umbrella Warehouse HOT 1
- Seat Reservation HOT 1
- Producing Machines HOT 1
- Block Stacking Game HOT 1
- Announcement For Workers
- Instant Calculator
- Producing Machines HOT 1
- intsant
- xy
- new HOT 2
- https://www.gravitech.us/arpromi5v.html
- gene HOT 5
- hahhahh HOT 17
- 1225 HOT 1
- nes HOT 19
- swm341 HOT 1
- daily plan HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from response3.