Renamed HuExpress to PCE-GO.
Someone looking for huexpress stumbled on my repo and was confused by my code. Not sure about the new name... I guess it is a PCE to GO... I might also have to think about renaming the other emulators that I very heavily modified (nofrendo and gnuboy).
This commit is contained in:
parent
f19cdfd636
commit
1aec677753
@ -162,7 +162,7 @@ I don't want to maintain non-ESP32 ports in this repository but let me know if I
|
||||
# Acknowledgements
|
||||
- The design of the launcher was inspired (copied) from [pelle7's go-emu](https://github.com/pelle7/odroid-go-emu-launcher).
|
||||
- The NES/GBC/SMS emulators and base library were originally from the "Triforce" fork of the [official Go-Play firmware](https://github.com/othercrashoverride/go-play) by crashoverride, Nemo1984, and many others.
|
||||
- The PCE emulator is a port of [HuExpress](https://github.com/kallisti5/huexpress) and [pelle7's port](https://github.com/pelle7/odroid-go-pcengine-huexpress/) was used as reference.
|
||||
- PCE-GO is a fork of [HuExpress](https://github.com/kallisti5/huexpress) and [pelle7's port](https://github.com/pelle7/odroid-go-pcengine-huexpress/) was used as reference.
|
||||
- The Lynx emulator is a port of [libretro-handy](https://github.com/libretro/libretro-handy).
|
||||
- The SNES emulator is a port of [Snes9x](https://github.com/snes9xgit/snes9x/).
|
||||
- PNG support is provided by [luPng](https://github.com/jansol/LuPng) and [zlib](http://zlib.net).
|
||||
|
||||
@ -15,7 +15,7 @@ PROJECT_APPS = {
|
||||
'nofrendo-go': [0, 393216],
|
||||
'gnuboy-go': [0, 393216],
|
||||
'smsplusgx-go': [0, 393216],
|
||||
'huexpress-go': [0, 393216],
|
||||
'pce-go': [0, 393216],
|
||||
'handy-go': [0, 393216],
|
||||
'snes9x-go': [0, 851968], # 1048576
|
||||
}
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
set(COMPONENTS "main retro-go huexpress app_trace bootloader esptool_py")
|
||||
include(../base.cmake)
|
||||
project(huexpress-go)
|
||||
@ -1,72 +0,0 @@
|
||||
#ifndef _GFX_H_
|
||||
#define _GFX_H_
|
||||
|
||||
typedef struct {
|
||||
/* Vertical position */
|
||||
uint16_t y;
|
||||
|
||||
/* Horizontal position */
|
||||
uint16_t x;
|
||||
|
||||
/* Offset in VRAM */
|
||||
uint16_t no;
|
||||
|
||||
/* Attributes */
|
||||
uint16_t attr;
|
||||
/*
|
||||
* bit 0-4 : number of the palette to be used
|
||||
* bit 7 : background sprite
|
||||
* 0 -> must be drawn behind tiles
|
||||
* 1 -> must be drawn in front of tiles
|
||||
* bit 8 : width
|
||||
* 0 -> 16 pixels
|
||||
* 1 -> 32 pixels
|
||||
* bit 11 : horizontal flip
|
||||
* 0 -> normal shape
|
||||
* 1 -> must be draw horizontally flipped
|
||||
* bit 13-12 : height
|
||||
* 00 -> 16 pixels
|
||||
* 01 -> 32 pixels
|
||||
* 10 -> 48 pixels
|
||||
* 11 -> 64 pixels
|
||||
* bit 15 : vertical flip
|
||||
* 0 -> normal shape
|
||||
* 1 -> must be drawn vertically flipped
|
||||
*/
|
||||
} sprite_t;
|
||||
|
||||
typedef struct {
|
||||
short scroll_x;
|
||||
short scroll_y;
|
||||
short control;
|
||||
short latched;
|
||||
} gfx_context_t;
|
||||
|
||||
extern bool TILE_CACHE[2048];
|
||||
extern bool SPR_CACHE[512];
|
||||
|
||||
extern int scroll_y_diff;
|
||||
|
||||
#define OBJ_CACHE_INVALIDATE(x) { \
|
||||
TILE_CACHE[((x) / 16) & 0x7FF] = 0; \
|
||||
SPR_CACHE[((x) / 64) & 0x1FF] = 0; \
|
||||
}
|
||||
|
||||
#define V_FLIP 0x8000
|
||||
#define H_FLIP 0x0800
|
||||
|
||||
// The extra 32's are linked to the way the sprite are drawn on screen, which can overlap to near memory
|
||||
// If only one pixel is drawn in the screen, the whole sprite is written, which can eventually overlap unexpected area
|
||||
// This could be fixed at the cost of performance but we don't need the extra memory
|
||||
#define XBUF_WIDTH (352 + 32)
|
||||
#define XBUF_HEIGHT (242 + 32)
|
||||
|
||||
int gfx_init(void);
|
||||
void gfx_run(void);
|
||||
void gfx_term(void);
|
||||
void gfx_irq(int type);
|
||||
void gfx_reset(bool hard);
|
||||
void gfx_latch_context(int slot_number);
|
||||
void gfx_set_scroll_diff(void);
|
||||
|
||||
#endif
|
||||
@ -1,90 +0,0 @@
|
||||
#ifndef H6280_H_
|
||||
#define H6280_H_
|
||||
|
||||
#include "hard_pce.h"
|
||||
|
||||
extern void h6280_reset(void);
|
||||
extern void h6280_run(void);
|
||||
extern void h6280_irq(int);
|
||||
extern void h6280_debug(void);
|
||||
extern void h6280_print_state(void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t addr_mode;
|
||||
const char name[6];
|
||||
} h6280_opcode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Registers */
|
||||
uint16_t PC;
|
||||
uint8_t A;
|
||||
uint8_t X;
|
||||
uint8_t Y;
|
||||
uint8_t P;
|
||||
uint8_t S;
|
||||
|
||||
/* Interrupts */
|
||||
uint8_t irq_mask;
|
||||
uint8_t irq_lines;
|
||||
|
||||
/* Misc */
|
||||
uint32_t cycles;
|
||||
uint32_t halted;
|
||||
} h6280_t;
|
||||
|
||||
// CPU Flags:
|
||||
#define FL_N 0x80
|
||||
#define FL_V 0x40
|
||||
#define FL_T 0x20
|
||||
#define FL_B 0x10
|
||||
#define FL_D 0x08
|
||||
#define FL_I 0x04
|
||||
#define FL_Z 0x02
|
||||
#define FL_C 0x01
|
||||
|
||||
// Interrupts
|
||||
#define INT_IRQ2 0x01
|
||||
#define INT_IRQ1 0x02
|
||||
#define INT_TIMER 0x04
|
||||
#define INT_MASK 0x07
|
||||
|
||||
// Vectors
|
||||
#define VEC_RESET 0xFFFE
|
||||
#define VEC_NMI 0xFFFC
|
||||
#define VEC_TIMER 0xFFFA
|
||||
#define VEC_IRQ1 0xFFF8
|
||||
#define VEC_IRQ2 0xFFF6
|
||||
#define VEC_BRK 0xFFF6
|
||||
|
||||
// Addressing modes
|
||||
#define AM_IMPL 0 /* implicit */
|
||||
#define AM_IMMED 1 /* immediate */
|
||||
#define AM_REL 2 /* relative */
|
||||
#define AM_ZP 3 /* zero page */
|
||||
#define AM_ZPX 4 /* zero page, x */
|
||||
#define AM_ZPY 5 /* zero page, y */
|
||||
#define AM_ZPIND 6 /* zero page indirect */
|
||||
#define AM_ZPINDX 7 /* zero page indirect, x */
|
||||
#define AM_ZPINDY 8 /* zero page indirect, y */
|
||||
#define AM_ABS 9 /* absolute */
|
||||
#define AM_ABSX 10 /* absolute, x */
|
||||
#define AM_ABSY 11 /* absolute, y */
|
||||
#define AM_ABSIND 12 /* absolute indirect */
|
||||
#define AM_ABSINDX 13 /* absolute indirect */
|
||||
#define AM_PSREL 14 /* pseudo-relative */
|
||||
#define AM_TST_ZP 15 /* special 'TST' addressing mode */
|
||||
#define AM_TST_ABS 16 /* special 'TST' addressing mode */
|
||||
#define AM_TST_ZPX 17 /* special 'TST' addressing mode */
|
||||
#define AM_TST_ABSX 18 /* special 'TST' addressing mode */
|
||||
#define AM_XFER 19 /* special 7-byte transfer addressing mode */
|
||||
|
||||
typedef signed char SBYTE;
|
||||
typedef unsigned char UBYTE;
|
||||
typedef signed short SWORD;
|
||||
typedef unsigned short UWORD;
|
||||
|
||||
extern h6280_t CPU;
|
||||
|
||||
#endif
|
||||
@ -1 +0,0 @@
|
||||
#include <osd.h>
|
||||
@ -686,7 +686,7 @@ void emulators_init()
|
||||
add_emulator("Sega Master System", "sms", "sms", "smsplusgx-go", 0, &logo_sms, &header_sms);
|
||||
add_emulator("Sega Game Gear", "gg", "gg", "smsplusgx-go", 0, &logo_gg, &header_gg);
|
||||
add_emulator("ColecoVision", "col", "col", "smsplusgx-go", 0, &logo_col, &header_col);
|
||||
add_emulator("PC Engine", "pce", "pce", "huexpress-go", 0, &logo_pce, &header_pce);
|
||||
add_emulator("PC Engine", "pce", "pce", "pce-go", 0, &logo_pce, &header_pce);
|
||||
add_emulator("Atari Lynx", "lnx", "lnx", "handy-go", 64, &logo_lnx, &header_lnx);
|
||||
add_emulator("Atari 2600", "a26", "a26", "stella-go", 0, NULL, NULL);
|
||||
add_emulator("Super Nintendo", "snes", "smc sfc", "snes9x-go", 0, &logo_snes, &header_snes);
|
||||
|
||||
4
pce-go/CMakeLists.txt
Normal file
4
pce-go/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
set(COMPONENTS "main retro-go pce-go app_trace bootloader esptool_py")
|
||||
include(../base.cmake)
|
||||
project(pce-go)
|
||||
@ -1,5 +1,5 @@
|
||||
set(COMPONENT_SRCDIRS "engine ports")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ". engine")
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
set(COMPONENT_REQUIRES "retro-go")
|
||||
register_component()
|
||||
rg_setup_compile_options(-Wno-sequence-point -Wno-unused)
|
||||
@ -1,11 +1,11 @@
|
||||
|
||||
HuExpress-GO
|
||||
PCE-GO
|
||||
|
||||
PC Engine / TurboGrafx-16 Emulator
|
||||
|
||||
--[ INTRODUCTION ]-----------------------------------------------------------
|
||||
|
||||
HuExpress-GO is a PCE emulator for constrained systems such as microcontrollers.
|
||||
PCE-GO is a PCE emulator for constrained systems such as microcontrollers.
|
||||
It is derived from the great HuExpress (https://github.com/kallisti5/huexpress).
|
||||
|
||||
HuExpress itself is a fork/rewrite of Hu-Go! (https://www.zeograd.com/parse.php?src=hugof&path=0,1,).
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
--[ CREDITS ]-------------------------------------------------
|
||||
|
||||
HuExpress-GO authors:
|
||||
PCE-GO authors:
|
||||
- Alex Duchesne (ducalex)
|
||||
|
||||
HuExpress authors:
|
||||
1
pce-go/components/pce-go/docs/example.c
Normal file
1
pce-go/components/pce-go/docs/example.c
Normal file
@ -0,0 +1 @@
|
||||
#include <pce-go.h>
|
||||
@ -1,23 +1,58 @@
|
||||
// gfx.c - VDC/VCE Emulation
|
||||
//
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "osd.h"
|
||||
#include "pce.h"
|
||||
#include "gfx.h"
|
||||
|
||||
static gfx_context_t gfx_context;
|
||||
typedef struct
|
||||
{
|
||||
uint16_t y; /* Vertical position */
|
||||
uint16_t x; /* Horizontal position */
|
||||
uint16_t no; /* Offset in VRAM */
|
||||
uint16_t attr; /* Attributes */
|
||||
/*
|
||||
* bit 0-4 : number of the palette to be used
|
||||
* bit 7 : background sprite
|
||||
* 0 -> must be drawn behind tiles
|
||||
* 1 -> must be drawn in front of tiles
|
||||
* bit 8 : width
|
||||
* 0 -> 16 pixels
|
||||
* 1 -> 32 pixels
|
||||
* bit 11 : horizontal flip
|
||||
* 0 -> normal shape
|
||||
* 1 -> must be draw horizontally flipped
|
||||
* bit 13-12 : height
|
||||
* 00 -> 16 pixels
|
||||
* 01 -> 32 pixels
|
||||
* 10 -> 48 pixels
|
||||
* 11 -> 64 pixels
|
||||
* bit 15 : vertical flip
|
||||
* 0 -> normal shape
|
||||
* 1 -> must be drawn vertically flipped
|
||||
*/
|
||||
} sprite_t;
|
||||
|
||||
// Active screen buffer
|
||||
static uint8_t *screen_buffer;
|
||||
#define PAL(nibble) (PAL[(L >> ((nibble) * 4)) & 15])
|
||||
|
||||
#define V_FLIP 0x8000
|
||||
#define H_FLIP 0x0800
|
||||
|
||||
// Cache for linear tiles and sprites. This is basically a decoded VRAM
|
||||
static uint32_t *OBJ_CACHE;
|
||||
bool TILE_CACHE[2048];
|
||||
bool SPR_CACHE[512];
|
||||
static bool TILE_CACHE[2048];
|
||||
static bool SPR_CACHE[512];
|
||||
|
||||
//
|
||||
static int line_counter = 0;
|
||||
static int last_line_counter = 0;
|
||||
int scroll_y_diff = 0;
|
||||
static int line_counter = 0;
|
||||
|
||||
#define PAL(nibble) (PAL[(L >> ((nibble) * 4)) & 15])
|
||||
static struct {
|
||||
int scroll_x;
|
||||
int scroll_y;
|
||||
int control;
|
||||
int latched;
|
||||
} gfx_context;
|
||||
|
||||
|
||||
/*
|
||||
@ -77,7 +112,7 @@ tile2pixel(int no)
|
||||
Draw background tiles between two lines
|
||||
*/
|
||||
static void // Do not inline
|
||||
draw_tiles(int Y1, int Y2, int scroll_x, int scroll_y)
|
||||
draw_tiles(uint8_t *screen_buffer, int Y1, int Y2, int scroll_x, int scroll_y)
|
||||
{
|
||||
const uint8_t _bg_w[] = { 32, 64, 128, 128 };
|
||||
const uint8_t _bg_h[] = { 32, 64 };
|
||||
@ -224,7 +259,7 @@ draw_sprite(uint8_t *P, uint16_t *C, uint32_t *C2, int height, uint16_t attr)
|
||||
Draw sprites between two lines
|
||||
*/
|
||||
static void // Do not inline
|
||||
draw_sprites(int Y1, int Y2, int priority)
|
||||
draw_sprites(uint8_t *screen_buffer, int Y1, int Y2, int priority)
|
||||
{
|
||||
// NOTE: At this time we do not respect bg sprites priority over top sprites.
|
||||
// Example: Assume that sprite #2 is priority=0 and sprite #5 is priority=1. If they
|
||||
@ -341,12 +376,23 @@ gfx_latch_context(int force)
|
||||
{
|
||||
if (!gfx_context.latched || force) { // Context is already saved + we haven't render the line using it
|
||||
gfx_context.scroll_x = IO_VDC_REG[BXR].W;
|
||||
gfx_context.scroll_y = IO_VDC_REG[BYR].W - scroll_y_diff;
|
||||
gfx_context.scroll_y = IO_VDC_REG[BYR].W - PCE.ScrollYDiff;
|
||||
gfx_context.control = IO_VDC_REG[CR].W;
|
||||
gfx_context.latched = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
In my testing this function is called between 0 and 400 times per frame.
|
||||
Having TILE/SPR globals was slightly faster but it seems negligible right now...
|
||||
*/
|
||||
void
|
||||
gfx_obj_cache_invalidate(int num)
|
||||
{
|
||||
TILE_CACHE[((num) / 16) & 0x7FF] = 0;
|
||||
SPR_CACHE[((num) / 64) & 0x1FF] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Render lines into the buffer from min_line to max_line (inclusive)
|
||||
@ -356,24 +402,31 @@ render_lines(int min_line, int max_line)
|
||||
{
|
||||
gfx_context.latched = 0;
|
||||
|
||||
screen_buffer = osd_gfx_framebuffer();
|
||||
uint8_t *screen_buffer = osd_gfx_framebuffer();
|
||||
if (!screen_buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We must fill the region with color 0 first
|
||||
// memset(screen_buffer + (min_line * XBUF_WIDTH), PCE.Palette[0], XBUF_WIDTH * (max_line - min_line + 1));
|
||||
size_t screen_width = IO_VDC_SCREEN_WIDTH;
|
||||
for (int y = min_line; y <= max_line; y++) {
|
||||
memset(screen_buffer + (y * XBUF_WIDTH), PCE.Palette[0], screen_width);
|
||||
}
|
||||
|
||||
// Sprites with priority 0 are drawn behind the tiles
|
||||
if (gfx_context.control & 0x40) {
|
||||
draw_sprites(min_line, max_line, 0);
|
||||
draw_sprites(screen_buffer, min_line, max_line, 0);
|
||||
}
|
||||
|
||||
// Draw the background tiles
|
||||
if (gfx_context.control & 0x80) {
|
||||
draw_tiles(min_line, max_line, gfx_context.scroll_x, gfx_context.scroll_y);
|
||||
draw_tiles(screen_buffer, min_line, max_line, gfx_context.scroll_x, gfx_context.scroll_y);
|
||||
}
|
||||
|
||||
// Draw regular sprites
|
||||
if (gfx_context.control & 0x40) {
|
||||
draw_sprites(min_line, max_line, 1);
|
||||
draw_sprites(screen_buffer, min_line, max_line, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,7 +567,7 @@ gfx_run(void)
|
||||
gfx_context.latched = 0;
|
||||
last_line_counter = 0;
|
||||
line_counter = 0;
|
||||
scroll_y_diff = 0;
|
||||
PCE.ScrollYDiff = 0;
|
||||
}
|
||||
|
||||
/* Always call at least once (to handle pending IRQs) */
|
||||
17
pce-go/components/pce-go/gfx.h
Normal file
17
pce-go/components/pce-go/gfx.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// The extra 32's are linked to the way the sprite are drawn on screen, which can overlap to near memory
|
||||
// If only one pixel is drawn in the screen, the whole sprite is written, which can eventually overlap unexpected area
|
||||
// This could be fixed at the cost of performance but we don't need the extra memory
|
||||
#define XBUF_WIDTH (352 + 32)
|
||||
#define XBUF_HEIGHT (242 + 32)
|
||||
|
||||
int gfx_init(void);
|
||||
void gfx_run(void);
|
||||
void gfx_term(void);
|
||||
void gfx_irq(int type);
|
||||
void gfx_reset(bool hard);
|
||||
void gfx_latch_context(int force);
|
||||
void gfx_obj_cache_invalidate(int num);
|
||||
@ -3,11 +3,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hard_pce.h"
|
||||
#include "gfx.h"
|
||||
#include "pce.h"
|
||||
#include "osd.h"
|
||||
|
||||
#include "h6280_instr.h"
|
||||
#include "h6280_dbg.h"
|
||||
|
||||
#define OPCODE(n, f) case n: f; break;
|
||||
|
||||
@ -333,38 +333,3 @@ h6280_run(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
h6280_print_state()
|
||||
{
|
||||
MESSAGE_INFO("Current h6280 status:\n");
|
||||
|
||||
MESSAGE_INFO("PC = 0x%04x\n", CPU.PC);
|
||||
MESSAGE_INFO("A = 0x%02x\n", CPU.A);
|
||||
MESSAGE_INFO("X = 0x%02x\n", CPU.X);
|
||||
MESSAGE_INFO("Y = 0x%02x\n", CPU.Y);
|
||||
MESSAGE_INFO("P = 0x%02x\n", CPU.P);
|
||||
MESSAGE_INFO("S = 0x%02x\n", CPU.S);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
MESSAGE_INFO("MMR[%d] = 0x%02x\n", i, PCE.MMR[i]);
|
||||
}
|
||||
|
||||
// TODO: Add zero page dump
|
||||
|
||||
for (int i = 0x2000; i < 0xFFFF; i++) {
|
||||
|
||||
if ((i & 0xF) == 0) {
|
||||
MESSAGE_INFO("%04X: ", i);
|
||||
}
|
||||
|
||||
MESSAGE_INFO("%02x ", pce_read8(i));
|
||||
if ((i & 0xF) == 0xF) {
|
||||
MESSAGE_INFO("\n");
|
||||
}
|
||||
if ((i & 0x1FFF) == 0x1FFF) {
|
||||
MESSAGE_INFO("\n-------------------------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
54
pce-go/components/pce-go/h6280.h
Normal file
54
pce-go/components/pce-go/h6280.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void h6280_reset(void);
|
||||
void h6280_run(void);
|
||||
void h6280_irq(int);
|
||||
void h6280_dump_state(void);
|
||||
void h6280_disassemble(void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Registers */
|
||||
uint16_t PC;
|
||||
uint8_t A;
|
||||
uint8_t X;
|
||||
uint8_t Y;
|
||||
uint8_t P;
|
||||
uint8_t S;
|
||||
|
||||
/* Interrupts */
|
||||
uint8_t irq_mask;
|
||||
uint8_t irq_lines;
|
||||
|
||||
/* Misc */
|
||||
uint32_t cycles;
|
||||
uint32_t halted;
|
||||
} h6280_t;
|
||||
|
||||
// CPU Flags:
|
||||
#define FL_N 0x80
|
||||
#define FL_V 0x40
|
||||
#define FL_T 0x20
|
||||
#define FL_B 0x10
|
||||
#define FL_D 0x08
|
||||
#define FL_I 0x04
|
||||
#define FL_Z 0x02
|
||||
#define FL_C 0x01
|
||||
|
||||
// Interrupts
|
||||
#define INT_IRQ2 0x01
|
||||
#define INT_IRQ1 0x02
|
||||
#define INT_TIMER 0x04
|
||||
#define INT_MASK 0x07
|
||||
|
||||
// Vectors
|
||||
#define VEC_RESET 0xFFFE
|
||||
#define VEC_NMI 0xFFFC
|
||||
#define VEC_TIMER 0xFFFA
|
||||
#define VEC_IRQ1 0xFFF8
|
||||
#define VEC_IRQ2 0xFFF6
|
||||
#define VEC_BRK 0xFFF6
|
||||
|
||||
extern h6280_t CPU;
|
||||
329
pce-go/components/pce-go/h6280_dbg.h
Normal file
329
pce-go/components/pce-go/h6280_dbg.h
Normal file
@ -0,0 +1,329 @@
|
||||
#include "h6280.h"
|
||||
#include "pce.h"
|
||||
|
||||
// Addressing modes
|
||||
#define AM_IMPL 0 /* implicit */
|
||||
#define AM_IMMED 1 /* immediate */
|
||||
#define AM_REL 2 /* relative */
|
||||
#define AM_ZP 3 /* zero page */
|
||||
#define AM_ZPX 4 /* zero page, x */
|
||||
#define AM_ZPY 5 /* zero page, y */
|
||||
#define AM_ZPIND 6 /* zero page indirect */
|
||||
#define AM_ZPINDX 7 /* zero page indirect, x */
|
||||
#define AM_ZPINDY 8 /* zero page indirect, y */
|
||||
#define AM_ABS 9 /* absolute */
|
||||
#define AM_ABSX 10 /* absolute, x */
|
||||
#define AM_ABSY 11 /* absolute, y */
|
||||
#define AM_ABSIND 12 /* absolute indirect */
|
||||
#define AM_ABSINDX 13 /* absolute indirect */
|
||||
#define AM_PSREL 14 /* pseudo-relative */
|
||||
#define AM_TST_ZP 15 /* special 'TST' addressing mode */
|
||||
#define AM_TST_ABS 16 /* special 'TST' addressing mode */
|
||||
#define AM_TST_ZPX 17 /* special 'TST' addressing mode */
|
||||
#define AM_TST_ABSX 18 /* special 'TST' addressing mode */
|
||||
#define AM_XFER 19 /* special 7-byte transfer addressing mode */
|
||||
|
||||
// OpCodes
|
||||
static const struct
|
||||
{
|
||||
uint32_t addr_mode;
|
||||
const char name[6];
|
||||
} opcodes[0x100] = {
|
||||
{AM_IMMED, "BRK"}, /* $00 */
|
||||
{AM_ZPINDX, "ORA"}, /* $01 */
|
||||
{AM_IMPL, "SXY"}, /* $02 */
|
||||
{AM_IMMED, "ST0"}, /* $03 */
|
||||
{AM_ZP, "TSB"}, /* $04 */
|
||||
{AM_ZP, "ORA"}, /* $05 */
|
||||
{AM_ZP, "ASL"}, /* $06 */
|
||||
{AM_ZP, "RMB0"}, /* $07 */
|
||||
{AM_IMPL, "PHP"}, /* $08 */
|
||||
{AM_IMMED, "ORA"}, /* $09 */
|
||||
{AM_IMPL, "ASL"}, /* $0A */
|
||||
{AM_IMPL, "BP0"}, /* $0B */
|
||||
{AM_ABS, "TSB"}, /* $0C */
|
||||
{AM_ABS, "ORA"}, /* $0D */
|
||||
{AM_ABS, "ASL"}, /* $0E */
|
||||
{AM_PSREL, "BBR0"}, /* $0F */
|
||||
{AM_REL, "BPL"}, /* $10 */
|
||||
{AM_ZPINDY, "ORA"}, /* $11 */
|
||||
{AM_ZPIND, "ORA"}, /* $12 */
|
||||
{AM_IMMED, "ST1"}, /* $13 */
|
||||
{AM_ZP, "TRB"}, /* $14 */
|
||||
{AM_ZPX, "ORA"}, /* $15 */
|
||||
{AM_ZPX, "ASL"}, /* $16 */
|
||||
{AM_ZP, "RMB1"}, /* $17 */
|
||||
{AM_IMPL, "CLC"}, /* $18 */
|
||||
{AM_ABSY, "ORA"}, /* $19 */
|
||||
{AM_IMPL, "INC"}, /* $1A */
|
||||
{AM_IMPL, "BP1"}, /* $1B */
|
||||
{AM_ABS, "TRB"}, /* $1C */
|
||||
{AM_ABSX, "ORA"}, /* $1D */
|
||||
{AM_ABSX, "ASL"}, /* $1E */
|
||||
{AM_PSREL, "BBR1"}, /* $1F */
|
||||
{AM_ABS, "JSR"}, /* $20 */
|
||||
{AM_ZPINDX, "AND"}, /* $21 */
|
||||
{AM_IMPL, "SAX"}, /* $22 */
|
||||
{AM_IMMED, "ST2"}, /* $23 */
|
||||
{AM_ZP, "BIT"}, /* $24 */
|
||||
{AM_ZP, "AND"}, /* $25 */
|
||||
{AM_ZP, "ROL"}, /* $26 */
|
||||
{AM_ZP, "RMB2"}, /* $27 */
|
||||
{AM_IMPL, "PLP"}, /* $28 */
|
||||
{AM_IMMED, "AND"}, /* $29 */
|
||||
{AM_IMPL, "ROL"}, /* $2A */
|
||||
{AM_IMPL, "BP2"}, /* $2B */
|
||||
{AM_ABS, "BIT"}, /* $2C */
|
||||
{AM_ABS, "AND"}, /* $2D */
|
||||
{AM_ABS, "ROL"}, /* $2E */
|
||||
{AM_PSREL, "BBR2"}, /* $2F */
|
||||
{AM_REL, "BMI"}, /* $30 */
|
||||
{AM_ZPINDY, "AND"}, /* $31 */
|
||||
{AM_ZPIND, "AND"}, /* $32 */
|
||||
{AM_IMPL, "???"}, /* $33 */
|
||||
{AM_ZPX, "BIT"}, /* $34 */
|
||||
{AM_ZPX, "AND"}, /* $35 */
|
||||
{AM_ZPX, "ROL"}, /* $36 */
|
||||
{AM_ZP, "RMB3"}, /* $37 */
|
||||
{AM_IMPL, "SEC"}, /* $38 */
|
||||
{AM_ABSY, "AND"}, /* $39 */
|
||||
{AM_IMPL, "DEC"}, /* $3A */
|
||||
{AM_IMPL, "BP3"}, /* $3B */
|
||||
{AM_ABSX, "BIT"}, /* $3C */
|
||||
{AM_ABSX, "AND"}, /* $3D */
|
||||
{AM_ABSX, "ROL"}, /* $3E */
|
||||
{AM_PSREL, "BBR3"}, /* $3F */
|
||||
{AM_IMPL, "RTI"}, /* $40 */
|
||||
{AM_ZPINDX, "EOR"}, /* $41 */
|
||||
{AM_IMPL, "SAY"}, /* $42 */
|
||||
{AM_IMMED, "TMA"}, /* $43 */
|
||||
{AM_REL, "BSR"}, /* $44 */
|
||||
{AM_ZP, "EOR"}, /* $45 */
|
||||
{AM_ZP, "LSR"}, /* $46 */
|
||||
{AM_ZP, "RMB4"}, /* $47 */
|
||||
{AM_IMPL, "PHA"}, /* $48 */
|
||||
{AM_IMMED, "EOR"}, /* $49 */
|
||||
{AM_IMPL, "LSR"}, /* $4A */
|
||||
{AM_IMPL, "BP4"}, /* $4B */
|
||||
{AM_ABS, "JMP"}, /* $4C */
|
||||
{AM_ABS, "EOR"}, /* $4D */
|
||||
{AM_ABS, "LSR"}, /* $4E */
|
||||
{AM_PSREL, "BBR4"}, /* $4F */
|
||||
{AM_REL, "BVC"}, /* $50 */
|
||||
{AM_ZPINDY, "EOR"}, /* $51 */
|
||||
{AM_ZPIND, "EOR"}, /* $52 */
|
||||
{AM_IMMED, "TAM"}, /* $53 */
|
||||
{AM_IMPL, "CSL"}, /* $54 */
|
||||
{AM_ZPX, "EOR"}, /* $55 */
|
||||
{AM_ZPX, "LSR"}, /* $56 */
|
||||
{AM_ZP, "RMB5"}, /* $57 */
|
||||
{AM_IMPL, "CLI"}, /* $58 */
|
||||
{AM_ABSY, "EOR"}, /* $59 */
|
||||
{AM_IMPL, "PHY"}, /* $5A */
|
||||
{AM_IMPL, "BP5"}, /* $5B */
|
||||
{AM_IMPL, "???"}, /* $5C */
|
||||
{AM_ABSX, "EOR"}, /* $5D */
|
||||
{AM_ABSX, "LSR"}, /* $5E */
|
||||
{AM_PSREL, "BBR5"}, /* $5F */
|
||||
{AM_IMPL, "RTS"}, /* $60 */
|
||||
{AM_ZPINDX, "ADC"}, /* $61 */
|
||||
{AM_IMPL, "CLA"}, /* $62 */
|
||||
{AM_IMPL, "???"}, /* $63 */
|
||||
{AM_ZP, "STZ"}, /* $64 */
|
||||
{AM_ZP, "ADC"}, /* $65 */
|
||||
{AM_ZP, "ROR"}, /* $66 */
|
||||
{AM_ZP, "RMB6"}, /* $67 */
|
||||
{AM_IMPL, "PLA"}, /* $68 */
|
||||
{AM_IMMED, "ADC"}, /* $69 */
|
||||
{AM_IMPL, "ROR"}, /* $6A */
|
||||
{AM_IMPL, "BP6"}, /* $6B */
|
||||
{AM_ABSIND, "JMP"}, /* $6C */
|
||||
{AM_ABS, "ADC"}, /* $6D */
|
||||
{AM_ABS, "ROR"}, /* $6E */
|
||||
{AM_PSREL, "BBR6"}, /* $6F */
|
||||
{AM_REL, "BVS"}, /* $70 */
|
||||
{AM_ZPINDY, "ADC"}, /* $71 */
|
||||
{AM_ZPIND, "ADC"}, /* $72 */
|
||||
{AM_XFER, "TII"}, /* $73 */
|
||||
{AM_ZPX, "STZ"}, /* $74 */
|
||||
{AM_ZPX, "ADC"}, /* $75 */
|
||||
{AM_ZPX, "ROR"}, /* $76 */
|
||||
{AM_ZP, "RMB7"}, /* $77 */
|
||||
{AM_IMPL, "SEI"}, /* $78 */
|
||||
{AM_ABSY, "ADC"}, /* $79 */
|
||||
{AM_IMPL, "PLY"}, /* $7A */
|
||||
{AM_IMPL, "BP7"}, /* $7B */
|
||||
{AM_ABSINDX, "JMP"}, /* $7C */
|
||||
{AM_ABSX, "ADC"}, /* $7D */
|
||||
{AM_ABSX, "ROR"}, /* $7E */
|
||||
{AM_PSREL, "BBR7"}, /* $7F */
|
||||
{AM_REL, "BRA"}, /* $80 */
|
||||
{AM_ZPINDX, "STA"}, /* $81 */
|
||||
{AM_IMPL, "CLX"}, /* $82 */
|
||||
{AM_TST_ZP, "TST"}, /* $83 */
|
||||
{AM_ZP, "STY"}, /* $84 */
|
||||
{AM_ZP, "STA"}, /* $85 */
|
||||
{AM_ZP, "STX"}, /* $86 */
|
||||
{AM_ZP, "SMB0"}, /* $87 */
|
||||
{AM_IMPL, "DEY"}, /* $88 */
|
||||
{AM_IMMED, "BIT"}, /* $89 */
|
||||
{AM_IMPL, "TXA"}, /* $8A */
|
||||
{AM_IMPL, "BP8"}, /* $8B */
|
||||
{AM_ABS, "STY"}, /* $8C */
|
||||
{AM_ABS, "STA"}, /* $8D */
|
||||
{AM_ABS, "STX"}, /* $8E */
|
||||
{AM_PSREL, "BBS0"}, /* $8F */
|
||||
{AM_REL, "BCC"}, /* $90 */
|
||||
{AM_ZPINDY, "STA"}, /* $91 */
|
||||
{AM_ZPIND, "STA"}, /* $92 */
|
||||
{AM_TST_ABS, "TST"}, /* $93 */
|
||||
{AM_ZPX, "STY"}, /* $94 */
|
||||
{AM_ZPX, "STA"}, /* $95 */
|
||||
{AM_ZPY, "STX"}, /* $96 */
|
||||
{AM_ZP, "SMB1"}, /* $97 */
|
||||
{AM_IMPL, "TYA"}, /* $98 */
|
||||
{AM_ABSY, "STA"}, /* $99 */
|
||||
{AM_IMPL, "TXS"}, /* $9A */
|
||||
{AM_IMPL, "BP9"}, /* $9B */
|
||||
{AM_ABS, "STZ"}, /* $9C */
|
||||
{AM_ABSX, "STA"}, /* $9D */
|
||||
{AM_ABSX, "STZ"}, /* $9E */
|
||||
{AM_PSREL, "BBS1"}, /* $9F */
|
||||
{AM_IMMED, "LDY"}, /* $A0 */
|
||||
{AM_ZPINDX, "LDA"}, /* $A1 */
|
||||
{AM_IMMED, "LDX"}, /* $A2 */
|
||||
{AM_TST_ZPX, "TST"}, /* $A3 */
|
||||
{AM_ZP, "LDY"}, /* $A4 */
|
||||
{AM_ZP, "LDA"}, /* $A5 */
|
||||
{AM_ZP, "LDX"}, /* $A6 */
|
||||
{AM_ZP, "SMB2"}, /* $A7 */
|
||||
{AM_IMPL, "TAY"}, /* $A8 */
|
||||
{AM_IMMED, "LDA"}, /* $A9 */
|
||||
{AM_IMPL, "TAX"}, /* $AA */
|
||||
{AM_IMPL, "BPA"}, /* $AB */
|
||||
{AM_ABS, "LDY"}, /* $AC */
|
||||
{AM_ABS, "LDA"}, /* $AD */
|
||||
{AM_ABS, "LDX"}, /* $AE */
|
||||
{AM_PSREL, "BBS2"}, /* $AF */
|
||||
{AM_REL, "BCS"}, /* $B0 */
|
||||
{AM_ZPINDY, "LDA"}, /* $B1 */
|
||||
{AM_ZPIND, "LDA"}, /* $B2 */
|
||||
{AM_TST_ABSX, "TST"}, /* $B3 */
|
||||
{AM_ZPX, "LDY"}, /* $B4 */
|
||||
{AM_ZPX, "LDA"}, /* $B5 */
|
||||
{AM_ZPY, "LDX"}, /* $B6 */
|
||||
{AM_ZP, "SMB3"}, /* $B7 */
|
||||
{AM_IMPL, "CLV"}, /* $B8 */
|
||||
{AM_ABSY, "LDA"}, /* $B9 */
|
||||
{AM_IMPL, "TSX"}, /* $BA */
|
||||
{AM_IMPL, "BPB"}, /* $BB */
|
||||
{AM_ABSX, "LDY"}, /* $BC */
|
||||
{AM_ABSX, "LDA"}, /* $BD */
|
||||
{AM_ABSY, "LDX"}, /* $BE */
|
||||
{AM_PSREL, "BBS3"}, /* $BF */
|
||||
{AM_IMMED, "CPY"}, /* $C0 */
|
||||
{AM_ZPINDX, "CMP"}, /* $C1 */
|
||||
{AM_IMPL, "CLY"}, /* $C2 */
|
||||
{AM_XFER, "TDD"}, /* $C3 */
|
||||
{AM_ZP, "CPY"}, /* $C4 */
|
||||
{AM_ZP, "CMP"}, /* $C5 */
|
||||
{AM_ZP, "DEC"}, /* $C6 */
|
||||
{AM_ZP, "SMB4"}, /* $C7 */
|
||||
{AM_IMPL, "INY"}, /* $C8 */
|
||||
{AM_IMMED, "CMP"}, /* $C9 */
|
||||
{AM_IMPL, "DEX"}, /* $CA */
|
||||
{AM_IMPL, "BPC"}, /* $CB */
|
||||
{AM_ABS, "CPY"}, /* $CC */
|
||||
{AM_ABS, "CMP"}, /* $CD */
|
||||
{AM_ABS, "DEC"}, /* $CE */
|
||||
{AM_PSREL, "BBS4"}, /* $CF */
|
||||
{AM_REL, "BNE"}, /* $D0 */
|
||||
{AM_ZPINDY, "CMP"}, /* $D1 */
|
||||
{AM_ZPIND, "CMP"}, /* $D2 */
|
||||
{AM_XFER, "TIN"}, /* $D3 */
|
||||
{AM_IMPL, "CSH"}, /* $D4 */
|
||||
{AM_ZPX, "CMP"}, /* $D5 */
|
||||
{AM_ZPX, "DEC"}, /* $D6 */
|
||||
{AM_ZP, "SMB5"}, /* $D7 */
|
||||
{AM_IMPL, "CLD"}, /* $D8 */
|
||||
{AM_ABSY, "CMP"}, /* $D9 */
|
||||
{AM_IMPL, "PHX"}, /* $DA */
|
||||
{AM_IMPL, "BPD"}, /* $DB */
|
||||
{AM_IMPL, "???"}, /* $DC */
|
||||
{AM_ABSX, "CMP"}, /* $DD */
|
||||
{AM_ABSX, "DEC"}, /* $DE */
|
||||
{AM_PSREL, "BBS5"}, /* $DF */
|
||||
{AM_IMMED, "CPX"}, /* $E0 */
|
||||
{AM_ZPINDX, "SBC"}, /* $E1 */
|
||||
{AM_IMPL, "???"}, /* $E2 */
|
||||
{AM_XFER, "TIA"}, /* $E3 */
|
||||
{AM_ZP, "CPX"}, /* $E4 */
|
||||
{AM_ZP, "SBC"}, /* $E5 */
|
||||
{AM_ZP, "INC"}, /* $E6 */
|
||||
{AM_ZP, "SMB6"}, /* $E7 */
|
||||
{AM_IMPL, "INX"}, /* $E8 */
|
||||
{AM_IMMED, "SBC"}, /* $E9 */
|
||||
{AM_IMPL, "NOP"}, /* $EA */
|
||||
{AM_IMPL, "BPE"}, /* $EB */
|
||||
{AM_ABS, "CPX"}, /* $EC */
|
||||
{AM_ABS, "SBC"}, /* $ED */
|
||||
{AM_ABS, "INC"}, /* $EE */
|
||||
{AM_PSREL, "BBS6"}, /* $EF */
|
||||
{AM_REL, "BEQ"}, /* $F0 */
|
||||
{AM_ZPINDY, "SBC"}, /* $F1 */
|
||||
{AM_ZPIND, "SBC"}, /* $F2 */
|
||||
{AM_XFER, "TAI"}, /* $F3 */
|
||||
{AM_IMPL, "SET"}, /* $F4 */
|
||||
{AM_ZPX, "SBC"}, /* $F5 */
|
||||
{AM_ZPX, "INC"}, /* $F6 */
|
||||
{AM_ZP, "SMB7"}, /* $F7 */
|
||||
{AM_IMPL, "SED"}, /* $F8 */
|
||||
{AM_ABSY, "SBC"}, /* $F9 */
|
||||
{AM_IMPL, "PLX"}, /* $FA */
|
||||
{AM_IMPL, "BPF"}, /* $FB */
|
||||
{AM_IMPL, "???"}, /* $FC */
|
||||
{AM_ABSX, "SBC"}, /* $FD */
|
||||
{AM_ABSX, "INC"}, /* $FE */
|
||||
{AM_PSREL, "BBS7"} /* $FF */
|
||||
};
|
||||
|
||||
|
||||
void h6280_dump_state(void)
|
||||
{
|
||||
MESSAGE_INFO("Current h6280 status:\n");
|
||||
|
||||
MESSAGE_INFO("PC = 0x%04x\n", CPU.PC);
|
||||
MESSAGE_INFO("A = 0x%02x\n", CPU.A);
|
||||
MESSAGE_INFO("X = 0x%02x\n", CPU.X);
|
||||
MESSAGE_INFO("Y = 0x%02x\n", CPU.Y);
|
||||
MESSAGE_INFO("P = 0x%02x\n", CPU.P);
|
||||
MESSAGE_INFO("S = 0x%02x\n", CPU.S);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
MESSAGE_INFO("MMR[%d] = 0x%02x\n", i, PCE.MMR[i]);
|
||||
}
|
||||
|
||||
// TODO: Add zero page dump
|
||||
|
||||
for (int i = 0x2000; i < 0xFFFF; i++) {
|
||||
|
||||
if ((i & 0xF) == 0) {
|
||||
MESSAGE_INFO("%04X: ", i);
|
||||
}
|
||||
|
||||
MESSAGE_INFO("%02x ", pce_read8(i));
|
||||
if ((i & 0xF) == 0xF) {
|
||||
MESSAGE_INFO("\n");
|
||||
}
|
||||
if ((i & 0x1FFF) == 0x1FFF) {
|
||||
MESSAGE_INFO("\n-------------------------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Disassemble one instruction at PC
|
||||
void h6280_disassemble(void)
|
||||
{
|
||||
|
||||
}
|
||||
@ -1,5 +1,10 @@
|
||||
#include "h6280.h"
|
||||
|
||||
typedef signed char SBYTE;
|
||||
typedef unsigned char UBYTE;
|
||||
typedef signed short SWORD;
|
||||
typedef unsigned short UWORD;
|
||||
|
||||
static const UBYTE bin2bcd[0x100] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
|
||||
@ -1968,7 +1973,7 @@ OPCODE_FUNC smb(UBYTE bit)
|
||||
OPCODE_FUNC st0(void)
|
||||
{
|
||||
CPU.P &= ~FL_T;
|
||||
IO_write(0, imm_operand(CPU.PC + 1));
|
||||
pce_writeIO(0, imm_operand(CPU.PC + 1));
|
||||
CPU.PC += 2;
|
||||
Cycles += 4;
|
||||
}
|
||||
@ -1976,7 +1981,7 @@ OPCODE_FUNC st0(void)
|
||||
OPCODE_FUNC st1(void)
|
||||
{
|
||||
CPU.P &= ~FL_T;
|
||||
IO_write(2, imm_operand(CPU.PC + 1));
|
||||
pce_writeIO(2, imm_operand(CPU.PC + 1));
|
||||
CPU.PC += 2;
|
||||
Cycles += 4;
|
||||
}
|
||||
@ -1984,7 +1989,7 @@ OPCODE_FUNC st1(void)
|
||||
OPCODE_FUNC st2(void)
|
||||
{
|
||||
CPU.P &= ~FL_T;
|
||||
IO_write(3, imm_operand(CPU.PC + 1));
|
||||
pce_writeIO(3, imm_operand(CPU.PC + 1));
|
||||
CPU.PC += 2;
|
||||
Cycles += 4;
|
||||
}
|
||||
@ -2413,262 +2418,3 @@ OPCODE_FUNC interrupt(int type)
|
||||
}
|
||||
Cycles += 7;
|
||||
}
|
||||
|
||||
static h6280_opcode_t opcodes[0x100] = {
|
||||
{AM_IMMED, "BRK"}, /* $00 */
|
||||
{AM_ZPINDX, "ORA"}, /* $01 */
|
||||
{AM_IMPL, "SXY"}, /* $02 */
|
||||
{AM_IMMED, "ST0"}, /* $03 */
|
||||
{AM_ZP, "TSB"}, /* $04 */
|
||||
{AM_ZP, "ORA"}, /* $05 */
|
||||
{AM_ZP, "ASL"}, /* $06 */
|
||||
{AM_ZP, "RMB0"}, /* $07 */
|
||||
{AM_IMPL, "PHP"}, /* $08 */
|
||||
{AM_IMMED, "ORA"}, /* $09 */
|
||||
{AM_IMPL, "ASL"}, /* $0A */
|
||||
{AM_IMPL, "BP0"}, /* $0B */
|
||||
{AM_ABS, "TSB"}, /* $0C */
|
||||
{AM_ABS, "ORA"}, /* $0D */
|
||||
{AM_ABS, "ASL"}, /* $0E */
|
||||
{AM_PSREL, "BBR0"}, /* $0F */
|
||||
{AM_REL, "BPL"}, /* $10 */
|
||||
{AM_ZPINDY, "ORA"}, /* $11 */
|
||||
{AM_ZPIND, "ORA"}, /* $12 */
|
||||
{AM_IMMED, "ST1"}, /* $13 */
|
||||
{AM_ZP, "TRB"}, /* $14 */
|
||||
{AM_ZPX, "ORA"}, /* $15 */
|
||||
{AM_ZPX, "ASL"}, /* $16 */
|
||||
{AM_ZP, "RMB1"}, /* $17 */
|
||||
{AM_IMPL, "CLC"}, /* $18 */
|
||||
{AM_ABSY, "ORA"}, /* $19 */
|
||||
{AM_IMPL, "INC"}, /* $1A */
|
||||
{AM_IMPL, "BP1"}, /* $1B */
|
||||
{AM_ABS, "TRB"}, /* $1C */
|
||||
{AM_ABSX, "ORA"}, /* $1D */
|
||||
{AM_ABSX, "ASL"}, /* $1E */
|
||||
{AM_PSREL, "BBR1"}, /* $1F */
|
||||
{AM_ABS, "JSR"}, /* $20 */
|
||||
{AM_ZPINDX, "AND"}, /* $21 */
|
||||
{AM_IMPL, "SAX"}, /* $22 */
|
||||
{AM_IMMED, "ST2"}, /* $23 */
|
||||
{AM_ZP, "BIT"}, /* $24 */
|
||||
{AM_ZP, "AND"}, /* $25 */
|
||||
{AM_ZP, "ROL"}, /* $26 */
|
||||
{AM_ZP, "RMB2"}, /* $27 */
|
||||
{AM_IMPL, "PLP"}, /* $28 */
|
||||
{AM_IMMED, "AND"}, /* $29 */
|
||||
{AM_IMPL, "ROL"}, /* $2A */
|
||||
{AM_IMPL, "BP2"}, /* $2B */
|
||||
{AM_ABS, "BIT"}, /* $2C */
|
||||
{AM_ABS, "AND"}, /* $2D */
|
||||
{AM_ABS, "ROL"}, /* $2E */
|
||||
{AM_PSREL, "BBR2"}, /* $2F */
|
||||
{AM_REL, "BMI"}, /* $30 */
|
||||
{AM_ZPINDY, "AND"}, /* $31 */
|
||||
{AM_ZPIND, "AND"}, /* $32 */
|
||||
{AM_IMPL, "???"}, /* $33 */
|
||||
{AM_ZPX, "BIT"}, /* $34 */
|
||||
{AM_ZPX, "AND"}, /* $35 */
|
||||
{AM_ZPX, "ROL"}, /* $36 */
|
||||
{AM_ZP, "RMB3"}, /* $37 */
|
||||
{AM_IMPL, "SEC"}, /* $38 */
|
||||
{AM_ABSY, "AND"}, /* $39 */
|
||||
{AM_IMPL, "DEC"}, /* $3A */
|
||||
{AM_IMPL, "BP3"}, /* $3B */
|
||||
{AM_ABSX, "BIT"}, /* $3C */
|
||||
{AM_ABSX, "AND"}, /* $3D */
|
||||
{AM_ABSX, "ROL"}, /* $3E */
|
||||
{AM_PSREL, "BBR3"}, /* $3F */
|
||||
{AM_IMPL, "RTI"}, /* $40 */
|
||||
{AM_ZPINDX, "EOR"}, /* $41 */
|
||||
{AM_IMPL, "SAY"}, /* $42 */
|
||||
{AM_IMMED, "TMA"}, /* $43 */
|
||||
{AM_REL, "BSR"}, /* $44 */
|
||||
{AM_ZP, "EOR"}, /* $45 */
|
||||
{AM_ZP, "LSR"}, /* $46 */
|
||||
{AM_ZP, "RMB4"}, /* $47 */
|
||||
{AM_IMPL, "PHA"}, /* $48 */
|
||||
{AM_IMMED, "EOR"}, /* $49 */
|
||||
{AM_IMPL, "LSR"}, /* $4A */
|
||||
{AM_IMPL, "BP4"}, /* $4B */
|
||||
{AM_ABS, "JMP"}, /* $4C */
|
||||
{AM_ABS, "EOR"}, /* $4D */
|
||||
{AM_ABS, "LSR"}, /* $4E */
|
||||
{AM_PSREL, "BBR4"}, /* $4F */
|
||||
{AM_REL, "BVC"}, /* $50 */
|
||||
{AM_ZPINDY, "EOR"}, /* $51 */
|
||||
{AM_ZPIND, "EOR"}, /* $52 */
|
||||
{AM_IMMED, "TAM"}, /* $53 */
|
||||
{AM_IMPL, "CSL"}, /* $54 */
|
||||
{AM_ZPX, "EOR"}, /* $55 */
|
||||
{AM_ZPX, "LSR"}, /* $56 */
|
||||
{AM_ZP, "RMB5"}, /* $57 */
|
||||
{AM_IMPL, "CLI"}, /* $58 */
|
||||
{AM_ABSY, "EOR"}, /* $59 */
|
||||
{AM_IMPL, "PHY"}, /* $5A */
|
||||
{AM_IMPL, "BP5"}, /* $5B */
|
||||
{AM_IMPL, "???"}, /* $5C */
|
||||
{AM_ABSX, "EOR"}, /* $5D */
|
||||
{AM_ABSX, "LSR"}, /* $5E */
|
||||
{AM_PSREL, "BBR5"}, /* $5F */
|
||||
{AM_IMPL, "RTS"}, /* $60 */
|
||||
{AM_ZPINDX, "ADC"}, /* $61 */
|
||||
{AM_IMPL, "CLA"}, /* $62 */
|
||||
{AM_IMPL, "???"}, /* $63 */
|
||||
{AM_ZP, "STZ"}, /* $64 */
|
||||
{AM_ZP, "ADC"}, /* $65 */
|
||||
{AM_ZP, "ROR"}, /* $66 */
|
||||
{AM_ZP, "RMB6"}, /* $67 */
|
||||
{AM_IMPL, "PLA"}, /* $68 */
|
||||
{AM_IMMED, "ADC"}, /* $69 */
|
||||
{AM_IMPL, "ROR"}, /* $6A */
|
||||
{AM_IMPL, "BP6"}, /* $6B */
|
||||
{AM_ABSIND, "JMP"}, /* $6C */
|
||||
{AM_ABS, "ADC"}, /* $6D */
|
||||
{AM_ABS, "ROR"}, /* $6E */
|
||||
{AM_PSREL, "BBR6"}, /* $6F */
|
||||
{AM_REL, "BVS"}, /* $70 */
|
||||
{AM_ZPINDY, "ADC"}, /* $71 */
|
||||
{AM_ZPIND, "ADC"}, /* $72 */
|
||||
{AM_XFER, "TII"}, /* $73 */
|
||||
{AM_ZPX, "STZ"}, /* $74 */
|
||||
{AM_ZPX, "ADC"}, /* $75 */
|
||||
{AM_ZPX, "ROR"}, /* $76 */
|
||||
{AM_ZP, "RMB7"}, /* $77 */
|
||||
{AM_IMPL, "SEI"}, /* $78 */
|
||||
{AM_ABSY, "ADC"}, /* $79 */
|
||||
{AM_IMPL, "PLY"}, /* $7A */
|
||||
{AM_IMPL, "BP7"}, /* $7B */
|
||||
{AM_ABSINDX, "JMP"}, /* $7C */
|
||||
{AM_ABSX, "ADC"}, /* $7D */
|
||||
{AM_ABSX, "ROR"}, /* $7E */
|
||||
{AM_PSREL, "BBR7"}, /* $7F */
|
||||
{AM_REL, "BRA"}, /* $80 */
|
||||
{AM_ZPINDX, "STA"}, /* $81 */
|
||||
{AM_IMPL, "CLX"}, /* $82 */
|
||||
{AM_TST_ZP, "TST"}, /* $83 */
|
||||
{AM_ZP, "STY"}, /* $84 */
|
||||
{AM_ZP, "STA"}, /* $85 */
|
||||
{AM_ZP, "STX"}, /* $86 */
|
||||
{AM_ZP, "SMB0"}, /* $87 */
|
||||
{AM_IMPL, "DEY"}, /* $88 */
|
||||
{AM_IMMED, "BIT"}, /* $89 */
|
||||
{AM_IMPL, "TXA"}, /* $8A */
|
||||
{AM_IMPL, "BP8"}, /* $8B */
|
||||
{AM_ABS, "STY"}, /* $8C */
|
||||
{AM_ABS, "STA"}, /* $8D */
|
||||
{AM_ABS, "STX"}, /* $8E */
|
||||
{AM_PSREL, "BBS0"}, /* $8F */
|
||||
{AM_REL, "BCC"}, /* $90 */
|
||||
{AM_ZPINDY, "STA"}, /* $91 */
|
||||
{AM_ZPIND, "STA"}, /* $92 */
|
||||
{AM_TST_ABS, "TST"}, /* $93 */
|
||||
{AM_ZPX, "STY"}, /* $94 */
|
||||
{AM_ZPX, "STA"}, /* $95 */
|
||||
{AM_ZPY, "STX"}, /* $96 */
|
||||
{AM_ZP, "SMB1"}, /* $97 */
|
||||
{AM_IMPL, "TYA"}, /* $98 */
|
||||
{AM_ABSY, "STA"}, /* $99 */
|
||||
{AM_IMPL, "TXS"}, /* $9A */
|
||||
{AM_IMPL, "BP9"}, /* $9B */
|
||||
{AM_ABS, "STZ"}, /* $9C */
|
||||
{AM_ABSX, "STA"}, /* $9D */
|
||||
{AM_ABSX, "STZ"}, /* $9E */
|
||||
{AM_PSREL, "BBS1"}, /* $9F */
|
||||
{AM_IMMED, "LDY"}, /* $A0 */
|
||||
{AM_ZPINDX, "LDA"}, /* $A1 */
|
||||
{AM_IMMED, "LDX"}, /* $A2 */
|
||||
{AM_TST_ZPX, "TST"}, /* $A3 */
|
||||
{AM_ZP, "LDY"}, /* $A4 */
|
||||
{AM_ZP, "LDA"}, /* $A5 */
|
||||
{AM_ZP, "LDX"}, /* $A6 */
|
||||
{AM_ZP, "SMB2"}, /* $A7 */
|
||||
{AM_IMPL, "TAY"}, /* $A8 */
|
||||
{AM_IMMED, "LDA"}, /* $A9 */
|
||||
{AM_IMPL, "TAX"}, /* $AA */
|
||||
{AM_IMPL, "BPA"}, /* $AB */
|
||||
{AM_ABS, "LDY"}, /* $AC */
|
||||
{AM_ABS, "LDA"}, /* $AD */
|
||||
{AM_ABS, "LDX"}, /* $AE */
|
||||
{AM_PSREL, "BBS2"}, /* $AF */
|
||||
{AM_REL, "BCS"}, /* $B0 */
|
||||
{AM_ZPINDY, "LDA"}, /* $B1 */
|
||||
{AM_ZPIND, "LDA"}, /* $B2 */
|
||||
{AM_TST_ABSX, "TST"}, /* $B3 */
|
||||
{AM_ZPX, "LDY"}, /* $B4 */
|
||||
{AM_ZPX, "LDA"}, /* $B5 */
|
||||
{AM_ZPY, "LDX"}, /* $B6 */
|
||||
{AM_ZP, "SMB3"}, /* $B7 */
|
||||
{AM_IMPL, "CLV"}, /* $B8 */
|
||||
{AM_ABSY, "LDA"}, /* $B9 */
|
||||
{AM_IMPL, "TSX"}, /* $BA */
|
||||
{AM_IMPL, "BPB"}, /* $BB */
|
||||
{AM_ABSX, "LDY"}, /* $BC */
|
||||
{AM_ABSX, "LDA"}, /* $BD */
|
||||
{AM_ABSY, "LDX"}, /* $BE */
|
||||
{AM_PSREL, "BBS3"}, /* $BF */
|
||||
{AM_IMMED, "CPY"}, /* $C0 */
|
||||
{AM_ZPINDX, "CMP"}, /* $C1 */
|
||||
{AM_IMPL, "CLY"}, /* $C2 */
|
||||
{AM_XFER, "TDD"}, /* $C3 */
|
||||
{AM_ZP, "CPY"}, /* $C4 */
|
||||
{AM_ZP, "CMP"}, /* $C5 */
|
||||
{AM_ZP, "DEC"}, /* $C6 */
|
||||
{AM_ZP, "SMB4"}, /* $C7 */
|
||||
{AM_IMPL, "INY"}, /* $C8 */
|
||||
{AM_IMMED, "CMP"}, /* $C9 */
|
||||
{AM_IMPL, "DEX"}, /* $CA */
|
||||
{AM_IMPL, "BPC"}, /* $CB */
|
||||
{AM_ABS, "CPY"}, /* $CC */
|
||||
{AM_ABS, "CMP"}, /* $CD */
|
||||
{AM_ABS, "DEC"}, /* $CE */
|
||||
{AM_PSREL, "BBS4"}, /* $CF */
|
||||
{AM_REL, "BNE"}, /* $D0 */
|
||||
{AM_ZPINDY, "CMP"}, /* $D1 */
|
||||
{AM_ZPIND, "CMP"}, /* $D2 */
|
||||
{AM_XFER, "TIN"}, /* $D3 */
|
||||
{AM_IMPL, "CSH"}, /* $D4 */
|
||||
{AM_ZPX, "CMP"}, /* $D5 */
|
||||
{AM_ZPX, "DEC"}, /* $D6 */
|
||||
{AM_ZP, "SMB5"}, /* $D7 */
|
||||
{AM_IMPL, "CLD"}, /* $D8 */
|
||||
{AM_ABSY, "CMP"}, /* $D9 */
|
||||
{AM_IMPL, "PHX"}, /* $DA */
|
||||
{AM_IMPL, "BPD"}, /* $DB */
|
||||
{AM_IMPL, "???"}, /* $DC */
|
||||
{AM_ABSX, "CMP"}, /* $DD */
|
||||
{AM_ABSX, "DEC"}, /* $DE */
|
||||
{AM_PSREL, "BBS5"}, /* $DF */
|
||||
{AM_IMMED, "CPX"}, /* $E0 */
|
||||
{AM_ZPINDX, "SBC"}, /* $E1 */
|
||||
{AM_IMPL, "???"}, /* $E2 */
|
||||
{AM_XFER, "TIA"}, /* $E3 */
|
||||
{AM_ZP, "CPX"}, /* $E4 */
|
||||
{AM_ZP, "SBC"}, /* $E5 */
|
||||
{AM_ZP, "INC"}, /* $E6 */
|
||||
{AM_ZP, "SMB6"}, /* $E7 */
|
||||
{AM_IMPL, "INX"}, /* $E8 */
|
||||
{AM_IMMED, "SBC"}, /* $E9 */
|
||||
{AM_IMPL, "NOP"}, /* $EA */
|
||||
{AM_IMPL, "BPE"}, /* $EB */
|
||||
{AM_ABS, "CPX"}, /* $EC */
|
||||
{AM_ABS, "SBC"}, /* $ED */
|
||||
{AM_ABS, "INC"}, /* $EE */
|
||||
{AM_PSREL, "BBS6"}, /* $EF */
|
||||
{AM_REL, "BEQ"}, /* $F0 */
|
||||
{AM_ZPINDY, "SBC"}, /* $F1 */
|
||||
{AM_ZPIND, "SBC"}, /* $F2 */
|
||||
{AM_XFER, "TAI"}, /* $F3 */
|
||||
{AM_IMPL, "SET"}, /* $F4 */
|
||||
{AM_ZPX, "SBC"}, /* $F5 */
|
||||
{AM_ZPX, "INC"}, /* $F6 */
|
||||
{AM_ZP, "SMB7"}, /* $F7 */
|
||||
{AM_IMPL, "SED"}, /* $F8 */
|
||||
{AM_ABSY, "SBC"}, /* $F9 */
|
||||
{AM_IMPL, "PLX"}, /* $FA */
|
||||
{AM_IMPL, "BPF"}, /* $FB */
|
||||
{AM_IMPL, "???"}, /* $FC */
|
||||
{AM_ABSX, "SBC"}, /* $FD */
|
||||
{AM_ABSX, "INC"}, /* $FE */
|
||||
{AM_PSREL, "BBS7"} /* $FF */
|
||||
};
|
||||
@ -2,7 +2,8 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "pce.h"
|
||||
#include <stdarg.h>
|
||||
#include "pce-go.h"
|
||||
|
||||
#define JOY_A 0x01
|
||||
#define JOY_B 0x02
|
||||
@ -1,18 +1,35 @@
|
||||
// pce.c - Entry file to start/stop/reset/save emulation
|
||||
// pce-go.c - Entry file to start/stop/reset/save emulation
|
||||
//
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pce-go.h"
|
||||
#include "gfx.h"
|
||||
#include "psg.h"
|
||||
#include "pce.h"
|
||||
|
||||
host_machine_t host;
|
||||
|
||||
const char SAVESTATE_HEADER[8] = "PCE_V004";
|
||||
|
||||
/**
|
||||
* Describes what is saved in a save state. Changing the order will break
|
||||
* previous saves so add a place holder if necessary. Eventually we could use
|
||||
* the keys to make order irrelevant...
|
||||
*/
|
||||
#define SVAR_1(k, v) { 1, k, &v }
|
||||
#define SVAR_2(k, v) { 2, k, &v }
|
||||
#define SVAR_4(k, v) { 4, k, &v }
|
||||
#define SVAR_A(k, v) { sizeof(v), k, &v }
|
||||
#define SVAR_N(k, v, n) { n, k, &v }
|
||||
#define SVAR_END { 0, "\0\0\0\0", 0 }
|
||||
|
||||
const svar_t SaveStateVars[] =
|
||||
static const char SAVESTATE_HEADER[8] = "PCE_V004";
|
||||
static const struct
|
||||
{
|
||||
size_t len;
|
||||
char key[16];
|
||||
void *ptr;
|
||||
} SaveStateVars[] =
|
||||
{
|
||||
// Arrays
|
||||
SVAR_A("RAM", PCE.RAM), SVAR_A("VRAM", PCE.VRAM), SVAR_A("SPRAM", PCE.SPRAM),
|
||||
@ -237,6 +254,48 @@ InitPCE(const char *name)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a 256 colors palette in the chosen depth
|
||||
*/
|
||||
void *
|
||||
PalettePCE(int colordepth)
|
||||
{
|
||||
if (colordepth == 15) {
|
||||
uint16_t *palette = osd_alloc(256 * 2);
|
||||
// ...
|
||||
return palette;
|
||||
}
|
||||
|
||||
if (colordepth == 16) {
|
||||
uint16_t *palette = osd_alloc(256 * 2);
|
||||
for (int i = 0; i < 255; i++) {
|
||||
int r = (i & 0x1C) >> 1;
|
||||
int g = (i & 0xe0) >> 4;
|
||||
int b = (i & 0x03) << 2;
|
||||
palette[i] = (((r << 12) & 0xf800) + ((g << 7) & 0x07e0) + ((b << 1) & 0x001f));
|
||||
}
|
||||
palette[255] = 0xFFFF;
|
||||
return palette;
|
||||
}
|
||||
|
||||
if (colordepth == 24) {
|
||||
uint8_t *palette = osd_alloc(256 * 3);
|
||||
uint8_t *ptr = palette;
|
||||
for (int i = 0; i < 255; i++) {
|
||||
*ptr++ = (i & 0x1C) << 2;
|
||||
*ptr++ = (i & 0xe0) >> 1;
|
||||
*ptr++ = (i & 0x03) << 4;
|
||||
}
|
||||
*ptr++ = 0xFF;
|
||||
*ptr++ = 0xFF;
|
||||
*ptr++ = 0xFF;
|
||||
return palette;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start the emulation
|
||||
*/
|
||||
@ -1,19 +1,14 @@
|
||||
#ifndef _INCLUDE_PCE_H
|
||||
#define _INCLUDE_PCE_H
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "osd.h"
|
||||
#include "hard_pce.h"
|
||||
#include "h6280.h"
|
||||
#include "psg.h"
|
||||
#include "gfx.h"
|
||||
#include "pce.h"
|
||||
#include "psg.h"
|
||||
|
||||
#include <rg_system.h>
|
||||
|
||||
@ -24,6 +19,7 @@ void RunPCE(void);
|
||||
void ShutdownPCE();
|
||||
int InitPCE(const char *name);
|
||||
int LoadCard(const char *name);
|
||||
void *PalettePCE(int colordepth);
|
||||
|
||||
typedef struct {
|
||||
bool paused;
|
||||
@ -47,19 +43,3 @@ typedef struct {
|
||||
} host_machine_t;
|
||||
|
||||
extern host_machine_t host;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t len;
|
||||
char key[16];
|
||||
void *ptr;
|
||||
} svar_t;
|
||||
|
||||
#define SVAR_1(k, v) { 1, k, &v }
|
||||
#define SVAR_2(k, v) { 2, k, &v }
|
||||
#define SVAR_4(k, v) { 4, k, &v }
|
||||
#define SVAR_A(k, v) { sizeof(v), k, &v }
|
||||
#define SVAR_N(k, v, n) { n, k, &v }
|
||||
#define SVAR_END { 0, "\0\0\0\0", 0 }
|
||||
|
||||
#endif
|
||||
@ -1,7 +1,11 @@
|
||||
// hard_pce.c - Memory/IO/Timer emulation
|
||||
// pce.c - Machine emulation (Memory/IO/Timer)
|
||||
//
|
||||
#include "hard_pce.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pce-go.h"
|
||||
#include "pce.h"
|
||||
#include "gfx.h"
|
||||
|
||||
// Global struct containing our emulated hardware status
|
||||
PCE_t PCE;
|
||||
@ -126,20 +130,20 @@ pce_run(void)
|
||||
static inline void
|
||||
timer_run(void)
|
||||
{
|
||||
PCE.Timer.cycles_counter -= CYCLES_PER_LINE;
|
||||
PCE.Timer.cycles_counter -= CYCLES_PER_LINE;
|
||||
|
||||
// Trigger when it underflows
|
||||
if (PCE.Timer.cycles_counter > CYCLES_PER_TIMER_TICK) {
|
||||
PCE.Timer.cycles_counter += CYCLES_PER_TIMER_TICK;
|
||||
if (PCE.Timer.running) {
|
||||
// Trigger when it underflows from 0
|
||||
if (PCE.Timer.counter > 0x7F) {
|
||||
PCE.Timer.counter = PCE.Timer.reload;
|
||||
CPU.irq_lines |= INT_TIMER;
|
||||
}
|
||||
PCE.Timer.counter--;
|
||||
}
|
||||
}
|
||||
// Trigger when it underflows
|
||||
if (PCE.Timer.cycles_counter > CYCLES_PER_TIMER_TICK) {
|
||||
PCE.Timer.cycles_counter += CYCLES_PER_TIMER_TICK;
|
||||
if (PCE.Timer.running) {
|
||||
// Trigger when it underflows from 0
|
||||
if (PCE.Timer.counter > 0x7F) {
|
||||
PCE.Timer.counter = PCE.Timer.reload;
|
||||
CPU.irq_lines |= INT_TIMER;
|
||||
}
|
||||
PCE.Timer.counter--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -170,7 +174,7 @@ cart_write(uint16_t A, uint8_t V)
|
||||
|
||||
|
||||
IRAM_ATTR inline uint8_t
|
||||
IO_read(uint16_t A)
|
||||
pce_readIO(uint16_t A)
|
||||
{
|
||||
uint8_t ret = 0xFF; // Open Bus
|
||||
|
||||
@ -281,7 +285,7 @@ IO_read(uint16_t A)
|
||||
|
||||
|
||||
IRAM_ATTR inline void
|
||||
IO_write(uint16_t A, uint8_t V)
|
||||
pce_writeIO(uint16_t A, uint8_t V)
|
||||
{
|
||||
TRACE_IO("IO Write %02x at %04x\n", V, A);
|
||||
|
||||
@ -338,7 +342,7 @@ IO_write(uint16_t A, uint8_t V)
|
||||
return;
|
||||
*/
|
||||
gfx_latch_context(0);
|
||||
scroll_y_diff = PCE.Scanline - 1 - IO_VDC_MINLINE;
|
||||
PCE.ScrollYDiff = PCE.Scanline - 1 - IO_VDC_MINLINE;
|
||||
break;
|
||||
|
||||
case MWR: // Memory Width Register
|
||||
@ -390,7 +394,7 @@ IO_write(uint16_t A, uint8_t V)
|
||||
// I am not 100% sure if MAWR should wrap instead, eg IO_VDC_REG[MAWR].W & 0x7FFF
|
||||
if (IO_VDC_REG[MAWR].W < 0x8000) {
|
||||
PCE.VRAM[IO_VDC_REG[MAWR].W] = (V << 8) | IO_VDC_REG_ACTIVE.B.l;
|
||||
OBJ_CACHE_INVALIDATE(IO_VDC_REG[MAWR].W);
|
||||
gfx_obj_cache_invalidate(IO_VDC_REG[MAWR].W);
|
||||
}
|
||||
IO_VDC_REG_INC(MAWR);
|
||||
break;
|
||||
@ -419,9 +423,9 @@ IO_write(uint16_t A, uint8_t V)
|
||||
|
||||
case BYR: // Vertical screen offset
|
||||
gfx_latch_context(0);
|
||||
scroll_y_diff = PCE.Scanline - 1 - IO_VDC_MINLINE;
|
||||
if (scroll_y_diff < 0) {
|
||||
MESSAGE_DEBUG("scroll_y_diff went negative when substraction VPR.h/.l (%d,%d)\n",
|
||||
PCE.ScrollYDiff = PCE.Scanline - 1 - IO_VDC_MINLINE;
|
||||
if (PCE.ScrollYDiff < 0) {
|
||||
MESSAGE_DEBUG("PCE.ScrollYDiff went negative when substraction VPR.h/.l (%d,%d)\n",
|
||||
IO_VDC_REG[VPR].B.h, IO_VDC_REG[VPR].B.l);
|
||||
}
|
||||
break;
|
||||
@ -461,7 +465,7 @@ IO_write(uint16_t A, uint8_t V)
|
||||
while (IO_VDC_REG[LENR].W != 0xFFFF) {
|
||||
if (IO_VDC_REG[DISTR].W < 0x8000) {
|
||||
PCE.VRAM[IO_VDC_REG[DISTR].W] = PCE.VRAM[IO_VDC_REG[SOUR].W];
|
||||
OBJ_CACHE_INVALIDATE(IO_VDC_REG[DISTR].W);
|
||||
gfx_obj_cache_invalidate(IO_VDC_REG[DISTR].W);
|
||||
}
|
||||
IO_VDC_REG[SOUR].W += src_inc;
|
||||
IO_VDC_REG[DISTR].W += dst_inc;
|
||||
@ -1,8 +1,7 @@
|
||||
#ifndef _INCLUDE_HARD_PCE_H
|
||||
#define _INCLUDE_HARD_PCE_H
|
||||
#pragma once
|
||||
|
||||
#include "../config.h"
|
||||
#include "stddef.h"
|
||||
#include <stddef.h>
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
|
||||
// System clocks (hz)
|
||||
@ -85,7 +84,10 @@ typedef struct {
|
||||
uint32_t dda_index;
|
||||
|
||||
uint32_t wave_accum;
|
||||
uint32_t noise_accum;
|
||||
|
||||
int32_t noise_accum;
|
||||
int32_t noise_level;
|
||||
int32_t noise_rand;
|
||||
} psg_chan_t;
|
||||
|
||||
typedef struct {
|
||||
@ -122,6 +124,9 @@ typedef struct {
|
||||
// The current rendered line on screen
|
||||
uint32_t Scanline;
|
||||
|
||||
//
|
||||
int ScrollYDiff;
|
||||
|
||||
// Number of executed CPU cycles
|
||||
uint32_t Cycles;
|
||||
|
||||
@ -226,9 +231,9 @@ int pce_init(void);
|
||||
void pce_reset(bool hard);
|
||||
void pce_term(void);
|
||||
void pce_run(void);
|
||||
|
||||
void IO_write(uint16_t A, uint8_t V);
|
||||
uint8_t IO_read(uint16_t A);
|
||||
void pce_pause(void);
|
||||
void pce_writeIO(uint16_t A, uint8_t V);
|
||||
uint8_t pce_readIO(uint16_t A);
|
||||
|
||||
|
||||
/**
|
||||
@ -240,13 +245,13 @@ uint8_t IO_read(uint16_t A);
|
||||
#define pce_read8(addr) ({ \
|
||||
uint32_t a = (addr); \
|
||||
uint8_t *page = PageR[a >> 13]; \
|
||||
(page == PCE.IOAREA) ? IO_read(a) : page[a]; \
|
||||
(page == PCE.IOAREA) ? pce_readIO(a) : page[a]; \
|
||||
})
|
||||
|
||||
#define pce_write8(addr, byte) { \
|
||||
uint32_t a = (addr), b = (byte); \
|
||||
uint8_t *page = PageW[a >> 13]; \
|
||||
if (page == PCE.IOAREA) IO_write(a, b); \
|
||||
if (page == PCE.IOAREA) pce_writeIO(a, b); \
|
||||
else page[a] = b; \
|
||||
}
|
||||
|
||||
@ -268,7 +273,7 @@ pce_read8(uint16_t addr)
|
||||
uint8_t *page = PageR[addr >> 13];
|
||||
|
||||
if (page == PCE.IOAREA)
|
||||
return IO_read(addr);
|
||||
return pce_readIO(addr);
|
||||
else
|
||||
return page[addr];
|
||||
}
|
||||
@ -279,7 +284,7 @@ pce_write8(uint16_t addr, uint8_t byte)
|
||||
uint8_t *page = PageW[addr >> 13];
|
||||
|
||||
if (page == PCE.IOAREA)
|
||||
IO_write(addr, byte);
|
||||
pce_writeIO(addr, byte);
|
||||
else
|
||||
page[addr] = byte;
|
||||
}
|
||||
@ -308,5 +313,3 @@ pce_bank_set(uint8_t P, uint8_t V)
|
||||
PageR[P] = (MemoryMapR[V] == PCE.IOAREA) ? (PCE.IOAREA) : (MemoryMapR[V] - P * 0x2000);
|
||||
PageW[P] = (MemoryMapW[V] == PCE.IOAREA) ? (PCE.IOAREA) : (MemoryMapW[V] - P * 0x2000);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,7 +1,10 @@
|
||||
// psg.c - Programmable Sound Generator
|
||||
//
|
||||
#include "psg.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "osd.h"
|
||||
#include "pce.h"
|
||||
#include "psg.h"
|
||||
|
||||
static const uint8_t vol_tbl[32] = {
|
||||
100 >> 8, 451 >> 8, 508 >> 8, 573 >> 8, 646 >> 8, 728 >> 8, 821 >> 8, 925 >> 8,
|
||||
@ -16,10 +19,6 @@ static const uint8_t vol_tbl[32] = {
|
||||
// typedef uint8_t sample_t;
|
||||
typedef int16_t sample_t;
|
||||
|
||||
static uint32_t noise_rand[PSG_CHANNELS];
|
||||
static int32_t noise_level[PSG_CHANNELS];
|
||||
static sample_t mix_buffer[44100 / 60 * 2];
|
||||
|
||||
|
||||
static inline void
|
||||
psg_update_chan(sample_t *buf, int ch, size_t dwSize)
|
||||
@ -98,20 +97,20 @@ psg_update_chan(sample_t *buf, int ch, size_t dwSize)
|
||||
chan->noise_accum += 3000 + Np * 512;
|
||||
|
||||
if ((Tp = (chan->noise_accum / host.sound.sample_freq)) >= 1) {
|
||||
if (noise_rand[ch] & 0x00080000) {
|
||||
noise_rand[ch] = ((noise_rand[ch] ^ 0x0004) << 1) + 1;
|
||||
noise_level[ch] = -15;
|
||||
if (chan->noise_rand & 0x00080000) {
|
||||
chan->noise_rand = ((chan->noise_rand ^ 0x0004) << 1) + 1;
|
||||
chan->noise_level = -15;
|
||||
} else {
|
||||
noise_rand[ch] <<= 1;
|
||||
noise_level[ch] = 15;
|
||||
chan->noise_rand <<= 1;
|
||||
chan->noise_level = 15;
|
||||
}
|
||||
chan->noise_accum -= host.sound.sample_freq * Tp;
|
||||
}
|
||||
|
||||
*buf++ = (noise_level[ch] * lvol);
|
||||
*buf++ = (chan->noise_level * lvol);
|
||||
|
||||
if (host.sound.stereo) {
|
||||
*buf++ = (noise_level[ch] * rvol);
|
||||
*buf++ = (chan->noise_level * rvol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,8 +174,8 @@ psg_update_chan(sample_t *buf, int ch, size_t dwSize)
|
||||
int
|
||||
psg_init(void)
|
||||
{
|
||||
noise_rand[4] = 0x51F63101;
|
||||
noise_rand[5] = 0x1F631042;
|
||||
PCE.PSG.chan[4].noise_rand = 0x51F63101;
|
||||
PCE.PSG.chan[5].noise_rand = 0x1F631042;
|
||||
|
||||
osd_snd_init();
|
||||
|
||||
@ -205,6 +204,8 @@ psg_update(int16_t *output, size_t length)
|
||||
|
||||
for (int i = 0; i < PSG_CHANNELS; i++)
|
||||
{
|
||||
sample_t mix_buffer[length];
|
||||
|
||||
psg_update_chan((void*)mix_buffer, i, length);
|
||||
|
||||
if (host.sound.sample_uint8) {
|
||||
@ -1,5 +1,4 @@
|
||||
#ifndef _INCLUDE_PSG_H
|
||||
#define _INCLUDE_PSG_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
@ -7,5 +6,3 @@
|
||||
int psg_init(void);
|
||||
void psg_term(void);
|
||||
void psg_update(int16_t *output, size_t length);
|
||||
|
||||
#endif
|
||||
@ -19,6 +19,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define MESSAGE_ERROR(x...) osd_log(1, "!! " x)
|
||||
#define MESSAGE_WARN(x...) osd_log(2, " ! " x)
|
||||
#define MESSAGE_INFO(x...) osd_log(3, " * " x)
|
||||
@ -16,15 +16,14 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../components/huexpress/engine/osd.h"
|
||||
#include <osd.h>
|
||||
|
||||
#define AUDIO_SAMPLE_RATE 22050
|
||||
// #define AUDIO_BUFFER_LENGTH (AUDIO_SAMPLE_RATE / 60)
|
||||
#define AUDIO_BUFFER_LENGTH (AUDIO_SAMPLE_RATE / 60 / 5)
|
||||
|
||||
static short audiobuffer[AUDIO_BUFFER_LENGTH * 2];
|
||||
|
||||
static uint16_t mypalette[256];
|
||||
static int16_t audiobuffer[AUDIO_BUFFER_LENGTH * 2];
|
||||
static uint16_t *mypalette;
|
||||
static uint8_t *framebuffers[2];
|
||||
static rg_video_frame_t frames[2];
|
||||
static rg_video_frame_t *currentUpdate = &frames[0];
|
||||
@ -43,29 +42,6 @@ static const char *SETTING_OVERSCAN = "overscan";
|
||||
// --- MAIN
|
||||
|
||||
|
||||
static inline void clear_buffer(rg_video_frame_t *update)
|
||||
{
|
||||
void *buffer = update->buffer;
|
||||
for (int i = 0; i < update->height; ++i)
|
||||
{
|
||||
memset(buffer, PCE.Palette[0], update->width);
|
||||
buffer += update->stride;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_color(int index, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
#define COLOR_RGB(r, g, b) ((((r) << 12) & 0xf800) + (((g) << 7) & 0x07e0) + (((b) << 1) & 0x001f))
|
||||
|
||||
uint16_t col = 0xffff;
|
||||
if (index != 255)
|
||||
{
|
||||
col = COLOR_RGB(r >> 2, g >> 2, b >> 2);
|
||||
col = (col << 8) | (col >> 8);
|
||||
}
|
||||
mypalette[index] = col;
|
||||
}
|
||||
|
||||
uint8_t *osd_gfx_framebuffer(void)
|
||||
{
|
||||
if (skipFrames > 0)
|
||||
@ -80,12 +56,10 @@ void osd_gfx_init(void)
|
||||
|
||||
overscan = rg_settings_get_app_int32(SETTING_OVERSCAN, 1);
|
||||
|
||||
// Build palette
|
||||
for (int i = 0; i < 255; i++)
|
||||
{
|
||||
set_color(i, (i & 0x1C) << 1, (i & 0xe0) >> 2, (i & 0x03) << 4);
|
||||
mypalette = PalettePCE(16);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
mypalette[i] = (mypalette[i] << 8) | (mypalette[i] >> 8);
|
||||
}
|
||||
set_color(255, 0x3f, 0x3f, 0x3f);
|
||||
|
||||
osd_gfx_set_mode(256, 240);
|
||||
}
|
||||
@ -103,7 +77,7 @@ void osd_gfx_set_mode(int width, int height)
|
||||
current_width = width;
|
||||
current_height = height;
|
||||
|
||||
MESSAGE_INFO("[GFX] Resolution: %dx%d / Cropping: H: %d V: %d\n", width, height, crop_h, crop_v);
|
||||
RG_LOGI("Resolution: %dx%d / Cropping: H: %d V: %d\n", width, height, crop_h, crop_v);
|
||||
|
||||
frames[0].flags = RG_PIXEL_PAL|RG_PIXEL_565|RG_PIXEL_BE;
|
||||
frames[0].width = width - crop_h;
|
||||
@ -120,7 +94,6 @@ void osd_gfx_set_mode(int width, int height)
|
||||
frames[1].my_arg = framebuffers[1] + offset_center;
|
||||
|
||||
currentUpdate = &frames[0];
|
||||
clear_buffer(currentUpdate);
|
||||
}
|
||||
|
||||
void osd_gfx_blit(void)
|
||||
@ -133,7 +106,6 @@ void osd_gfx_blit(void)
|
||||
rg_display_queue_update(currentUpdate, NULL);
|
||||
|
||||
currentUpdate = previousUpdate;
|
||||
clear_buffer(currentUpdate);
|
||||
}
|
||||
|
||||
// See if we need to skip a frame to keep up
|
||||
@ -152,7 +124,7 @@ void osd_gfx_blit(void)
|
||||
|
||||
void osd_gfx_shutdown(void)
|
||||
{
|
||||
MESSAGE_INFO("Goodbye...\n");
|
||||
RG_LOGI("Goodbye...\n");
|
||||
}
|
||||
|
||||
static dialog_return_t overscan_update_cb(dialog_option_t *option, dialog_event_t event)
|
||||
@ -231,7 +203,7 @@ void osd_input_read(void)
|
||||
|
||||
static void audioTask(void *arg)
|
||||
{
|
||||
MESSAGE_INFO("[PSG] task started.\n");
|
||||
RG_LOGI("task started.\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
@ -274,7 +246,7 @@ void osd_vsync(void)
|
||||
|
||||
if (sleep > frametime)
|
||||
{
|
||||
MESSAGE_ERROR("Our vsync timer seems to have overflowed! (%dus)\n", sleep);
|
||||
RG_LOGE("Our vsync timer seems to have overflowed! (%dus)\n", sleep);
|
||||
}
|
||||
else if (sleep > 0)
|
||||
{
|
||||
@ -338,10 +310,6 @@ void app_main(void)
|
||||
|
||||
app = rg_system_init(AUDIO_SAMPLE_RATE, &handlers);
|
||||
|
||||
// Clearing the buffer on the display core is somewhat faster, but it
|
||||
// prevents us from doing partial updates and screenshots.
|
||||
// rg_display_set_callback(clear_buffer);
|
||||
|
||||
InitPCE(app->romPath);
|
||||
|
||||
if (app->startAction == RG_START_ACTION_RESUME)
|
||||
@ -351,5 +319,5 @@ void app_main(void)
|
||||
|
||||
RunPCE();
|
||||
|
||||
RG_PANIC("HuExpress-GO died.");
|
||||
RG_PANIC("PCE-GO died.");
|
||||
}
|
||||
@ -9,15 +9,15 @@
|
||||
{
|
||||
"path": "handy-go"
|
||||
},
|
||||
{
|
||||
"path": "huexpress-go"
|
||||
},
|
||||
{
|
||||
"path": "launcher"
|
||||
},
|
||||
{
|
||||
"path": "nofrendo-go"
|
||||
},
|
||||
{
|
||||
"path": "pce-go"
|
||||
},
|
||||
{
|
||||
"path": "smsplusgx-go"
|
||||
},
|
||||
@ -56,7 +56,6 @@
|
||||
"C_Cpp.default.cppStandard": "c++11",
|
||||
"C_Cpp.default.intelliSenseMode": "gcc-x86",
|
||||
"cSpell.words": [
|
||||
"huexpress",
|
||||
"nofrendo",
|
||||
"smsplusgx",
|
||||
"supergraphx"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user