Update to v087r09 release.

byuu says:

Split apart necdsp: core is now in processor/upd96050 (wish I had
a better name for it, but there's no family name that is maskable.)
I would like to support the uPD7720 in the core as well, just for
completeness' sake, but I'll have to modify the decoder to drop one bit
from each mode.
So ... I'll do that later. Worst part is even if I do, I won't be able
to test it :(

Added all of Cydrak's changes. I also simplified LDMIA/STMIA and
PUSH/POP by merging the outer loops.
Probably infinitesimally slower, but less code is nicer. Maybe GCC
optimization will expand it, who knows.
This commit is contained in:
Tim Allen 2012-03-26 21:13:02 +11:00
parent 395e5a5639
commit e16dd58184
31 changed files with 547 additions and 478 deletions

View File

@ -92,7 +92,7 @@ sync:
rm -r phoenix/nall rm -r phoenix/nall
rm -r phoenix/test rm -r phoenix/test
archive-all: archive:
if [ -f bsnes.tar.bz2 ]; then rm bsnes.tar.bz2; fi if [ -f bsnes.tar.bz2 ]; then rm bsnes.tar.bz2; fi
tar -cjf bsnes.tar.bz2 `ls` tar -cjf bsnes.tar.bz2 `ls`

View File

@ -1,7 +1,7 @@
#ifndef BASE_HPP #ifndef BASE_HPP
#define BASE_HPP #define BASE_HPP
static const char Version[] = "087.08"; static const char Version[] = "087.09";
#include <nall/platform.hpp> #include <nall/platform.hpp>
#include <nall/algorithm.hpp> #include <nall/algorithm.hpp>

View File

@ -19,6 +19,11 @@ void APU::step(unsigned clocks) {
} }
uint32 APU::read(uint32 addr, uint32 size) { uint32 APU::read(uint32 addr, uint32 size) {
if(addr == 0x04000088) {
//SOUNDBIAS
return 0x0200;
}
return 0u; return 0u;
} }
@ -27,6 +32,8 @@ void APU::write(uint32 addr, uint32 size, uint32 word) {
void APU::power() { void APU::power() {
create(APU::Enter, 16777216); create(APU::Enter, 16777216);
bus.mmio[0x0088] = this;
} }
} }

View File

@ -50,7 +50,6 @@ void CPU::power() {
} }
uint32 CPU::read(uint32 addr, uint32 size) { uint32 CPU::read(uint32 addr, uint32 size) {
if(addr == 0x04000300) return prng() & 1;
return 0u; return 0u;
} }

View File

@ -5,8 +5,8 @@ namespace GBA {
Bus bus; Bus bus;
struct UnmappedMemory : Memory { struct UnmappedMemory : Memory {
uint32 read(uint32 addr, uint32 size) { return 0u; } uint32 read(uint32 addr, uint32 size) { print(hex<8>(addr), ":", decimal<2>(size), "\n"); return 0u; }
void write(uint32 addr, uint32 size, uint32 word) {} void write(uint32 addr, uint32 size, uint32 word) { print(hex<8>(addr), ":", decimal<2>(size), "=", hex<8>(word), "\n"); }
}; };
static UnmappedMemory unmappedMemory; static UnmappedMemory unmappedMemory;

View File

@ -27,7 +27,7 @@ struct map {
signed middle = (first + last) / 2; signed middle = (first + last) / 2;
if(name < list[middle].name) last = middle - 1; //search lower half if(name < list[middle].name) last = middle - 1; //search lower half
else if(list[middle].name < name) first = middle + 1; //search upper half else if(list[middle].name < name) first = middle + 1; //search upper half
else return { true, middle }; //match found else return { true, (unsigned)middle }; //match found
} }
return { false, 0u }; return { false, 0u };
} }

27
bsnes/nall/udl.hpp Executable file
View File

@ -0,0 +1,27 @@
#ifndef NALL_UDL_HPP
#define NALL_UDL_HPP
//user-defined literals
#include <nall/atoi.hpp>
namespace nall {
constexpr inline uintmax_t operator"" _b(const char *n) { return binary(n); }
//convert to bytes
constexpr inline uintmax_t operator"" _kb(unsigned long long n) { return 1024 * n; }
constexpr inline uintmax_t operator"" _mb(unsigned long long n) { return 1024 * 1024 * n; }
constexpr inline uintmax_t operator"" _gb(unsigned long long n) { return 1024 * 1024 * 1024 * n; }
//convert to bits
constexpr inline uintmax_t operator"" _kbit(unsigned long long n) { return 1024 * n / 8; }
constexpr inline uintmax_t operator"" _mbit(unsigned long long n) { return 1024 * 1024 * n / 8; }
constexpr inline uintmax_t operator"" _gbit(unsigned long long n) { return 1024 * 1024 * 1024 * n / 8; }
//convert to hz
constexpr inline uintmax_t operator"" _khz(long double n) { return n * 1000; }
constexpr inline uintmax_t operator"" _mhz(long double n) { return n * 1000000; }
constexpr inline uintmax_t operator"" _ghz(long double n) { return n * 1000000000; }
}
#endif

View File

@ -52,13 +52,13 @@ struct Color {
struct Position { struct Position {
signed x, y; signed x, y;
inline Position() : x(0), y(0) {} inline Position() : x(0), y(0) {}
inline Position(signed x, signed y) : x(x), y(y) {} template<typename X, typename Y> inline Position(X x, Y y) : x(x), y(y) {}
}; };
struct Size { struct Size {
unsigned width, height; unsigned width, height;
inline Size() : width(0), height(0) {} inline Size() : width(0), height(0) {}
inline Size(unsigned width, unsigned height) : width(width), height(height) {} template<typename W, typename H> inline Size(W width, H height) : width(width), height(height) {}
}; };
struct Geometry { struct Geometry {
@ -69,7 +69,7 @@ struct Geometry {
nall::string text() const; nall::string text() const;
inline Geometry() : x(0), y(0), width(0), height(0) {} inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(const Position& position, const Size& size) : x(position.x), y(position.y), width(size.width), height(size.height) {} inline Geometry(const Position& position, const Size& size) : x(position.x), y(position.y), width(size.width), height(size.height) {}
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {} template<typename X, typename Y, typename W, typename H> inline Geometry(X x, Y y, W width, H height) : x(x), y(y), width(width), height(height) {}
Geometry(const nall::string &text); Geometry(const nall::string &text);
}; };

View File

@ -100,7 +100,8 @@ struct pWindow : public pObject {
GtkWidget *statusContainer; GtkWidget *statusContainer;
GtkWidget *menu; GtkWidget *menu;
GtkWidget *status; GtkWidget *status;
GdkEventConfigure lastConfigure; GtkAllocation lastAllocation;
bool onSizePending;
void append(Layout &layout); void append(Layout &layout);
void append(Menu &menu); void append(Menu &menu);

View File

@ -53,36 +53,27 @@ static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *win
settings->save(); settings->save();
} }
Geometry geometry = {
client.x,
client.y + window->p.menuHeight(),
client.width,
client.height - window->p.menuHeight() - window->p.statusHeight()
};
//move //move
if(event->configure.x != window->p.lastConfigure.x if(geometry.x != window->state.geometry.x || geometry.y != window->state.geometry.y) {
|| event->configure.y != window->p.lastConfigure.y
) {
if(window->state.fullScreen == false) { if(window->state.fullScreen == false) {
window->state.geometry.x = client.x; window->state.geometry.x = geometry.x;
window->state.geometry.y = client.y + window->p.menuHeight(); window->state.geometry.y = geometry.y;
} }
if(window->p.locked == false && window->onMove) window->onMove(); if(window->p.locked == false && window->onMove) window->onMove();
} }
//size //size
if(event->configure.width != window->p.lastConfigure.width if(geometry.width != window->state.geometry.width || geometry.height != window->state.geometry.height) {
|| event->configure.height != window->p.lastConfigure.height window->p.onSizePending = true;
) {
if(window->state.fullScreen == false) {
window->state.geometry.width = client.width;
window->state.geometry.height = client.height - window->p.menuHeight() - window->p.statusHeight();
}
for(auto &layout : window->state.layout) {
Geometry geometry = window->geometry();
geometry.x = geometry.y = 0;
layout.setGeometry(geometry);
}
if(window->p.locked == false && window->onSize) window->onSize();
} }
window->p.lastConfigure = event->configure;
return false; return false;
} }
@ -98,6 +89,33 @@ static gboolean Window_keyReleaseEvent(GtkWidget *widget, GdkEventKey *event, Wi
return false; return false;
} }
static void Window_sizeAllocate(GtkWidget *widget, GtkAllocation *allocation, Window *window) {
//size-allocate sent from gtk_fixed_move(); detect if layout unchanged and return
if(allocation->width == window->p.lastAllocation.width
&& allocation->height == window->p.lastAllocation.height) return;
window->state.geometry.width = allocation->width;
window->state.geometry.height = allocation->height;
for(auto &layout : window->state.layout) {
Geometry geometry = window->geometry();
geometry.x = geometry.y = 0;
layout.setGeometry(geometry);
}
if(window->p.onSizePending && window->p.locked == false && window->onSize) {
window->p.onSizePending = false;
window->onSize();
}
window->p.lastAllocation = *allocation;
}
static void Window_sizeRequest(GtkWidget *widget, GtkRequisition *requisition, Window *window) {
requisition->width = window->state.geometry.width;
requisition->height = window->state.geometry.height;
}
void pWindow::append(Layout &layout) { void pWindow::append(Layout &layout) {
Geometry geometry = this->geometry(); Geometry geometry = this->geometry();
geometry.x = geometry.y = 0; geometry.x = geometry.y = 0;
@ -131,7 +149,13 @@ Color pWindow::backgroundColor() {
} }
Geometry pWindow::frameMargin() { Geometry pWindow::frameMargin() {
if(window.state.fullScreen) return { 0, menuHeight(), 0, menuHeight() + statusHeight() }; if(window.state.fullScreen) return {
0,
menuHeight(),
0,
menuHeight() + statusHeight()
};
return { return {
settings->frameGeometryX, settings->frameGeometryX,
settings->frameGeometryY + menuHeight(), settings->frameGeometryY + menuHeight(),
@ -145,9 +169,13 @@ bool pWindow::focused() {
} }
Geometry pWindow::geometry() { Geometry pWindow::geometry() {
if(window.state.fullScreen == true) { if(window.state.fullScreen == true) return {
return { 0, menuHeight(), Desktop::size().width, Desktop::size().height - menuHeight() - statusHeight() }; 0,
menuHeight(),
Desktop::size().width,
Desktop::size().height - menuHeight() - statusHeight()
}; };
return window.state.geometry; return window.state.geometry;
} }
@ -178,38 +206,23 @@ void pWindow::setFocused() {
void pWindow::setFullScreen(bool fullScreen) { void pWindow::setFullScreen(bool fullScreen) {
if(fullScreen == false) { if(fullScreen == false) {
gtk_window_unfullscreen(GTK_WINDOW(widget)); gtk_window_unfullscreen(GTK_WINDOW(widget));
gtk_window_set_resizable(GTK_WINDOW(widget), window.state.resizable);
gtk_widget_set_size_request(widget, -1, -1);
gdk_display_sync(gtk_widget_get_display(widget));
setGeometry(window.state.geometry);
} else { } else {
gtk_window_fullscreen(GTK_WINDOW(widget)); gtk_window_fullscreen(GTK_WINDOW(widget));
gtk_widget_set_size_request(widget, Desktop::size().width, Desktop::size().height);
gtk_window_set_resizable(GTK_WINDOW(widget), false);
} }
gdk_display_sync(gtk_widget_get_display(widget));
} }
void pWindow::setGeometry(const Geometry &geometry) { void pWindow::setGeometry(const Geometry &geometry) {
OS::processEvents();
Geometry margin = frameMargin(); Geometry margin = frameMargin();
gtk_window_move(GTK_WINDOW(widget), geometry.x - margin.x, geometry.y - margin.y); gtk_window_move(GTK_WINDOW(widget), geometry.x - margin.x, geometry.y - margin.y);
//GdkGeometry geom; GdkGeometry geom;
//geom.min_width = 1; geom.min_width = window.state.resizable ? 1 : window.state.geometry.width;
//geom.min_height = 1; geom.min_height = window.state.resizable ? 1 : window.state.geometry.height;
//gtk_window_set_geometry_hints(GTK_WINDOW(widget), GTK_WIDGET(widget), &geom, GDK_HINT_MIN_SIZE); gtk_window_set_geometry_hints(GTK_WINDOW(widget), GTK_WIDGET(widget), &geom, GDK_HINT_MIN_SIZE);
gtk_window_set_policy(GTK_WINDOW(widget), true, true, false); //gtk_window_set_policy(GTK_WINDOW(widget), true, true, false);
gtk_widget_set_size_request(formContainer, geometry.width, geometry.height); gtk_widget_set_size_request(formContainer, geometry.width, geometry.height);
gtk_window_resize(GTK_WINDOW(widget), geometry.width, geometry.height + menuHeight() + statusHeight()); gtk_window_resize(GTK_WINDOW(widget), geometry.width, geometry.height + menuHeight() + statusHeight());
for(auto &layout : window.state.layout) {
Geometry geometry = this->geometry();
geometry.x = geometry.y = 0;
layout.setGeometry(geometry);
}
} }
void pWindow::setMenuFont(const string &font) { void pWindow::setMenuFont(const string &font) {
@ -244,6 +257,19 @@ void pWindow::setTitle(const string &text) {
void pWindow::setVisible(bool visible) { void pWindow::setVisible(bool visible) {
gtk_widget_set_visible(widget, visible); gtk_widget_set_visible(widget, visible);
if(visible) {
if(gtk_widget_get_visible(menu)) {
GtkAllocation allocation;
gtk_widget_get_allocation(menu, &allocation);
settings->menuGeometryHeight = allocation.height;
}
if(gtk_widget_get_visible(status)) {
GtkAllocation allocation;
gtk_widget_get_allocation(status, &allocation);
settings->statusGeometryHeight = allocation.height;
}
}
} }
void pWindow::setWidgetFont(const string &font) { void pWindow::setWidgetFont(const string &font) {
@ -253,7 +279,10 @@ void pWindow::setWidgetFont(const string &font) {
} }
void pWindow::constructor() { void pWindow::constructor() {
memset(&lastConfigure, 0, sizeof(GdkEventConfigure)); lastAllocation.width = 0;
lastAllocation.height = 0;
onSizePending = false;
widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
if(gdk_screen_is_composited(gdk_screen_get_default())) { if(gdk_screen_is_composited(gdk_screen_get_default())) {
@ -289,6 +318,7 @@ void pWindow::constructor() {
gtk_widget_show(statusContainer); gtk_widget_show(statusContainer);
setTitle(""); setTitle("");
setResizable(window.state.resizable);
setGeometry(window.state.geometry); setGeometry(window.state.geometry);
setMenuFont("Sans, 8"); setMenuFont("Sans, 8");
setStatusFont("Sans, 8"); setStatusFont("Sans, 8");
@ -298,6 +328,9 @@ void pWindow::constructor() {
g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window); g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window); g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window); g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window);
g_signal_connect(G_OBJECT(formContainer), "size-allocate", G_CALLBACK(Window_sizeAllocate), (gpointer)&window);
g_signal_connect(G_OBJECT(formContainer), "size-request", G_CALLBACK(Window_sizeRequest), (gpointer)&window);
} }
unsigned pWindow::menuHeight() { unsigned pWindow::menuHeight() {

View File

@ -1,3 +1,9 @@
//Qt 4.8.0 and earlier improperly define the QLOCATION macro
//in C++11, it is detected as a malformed user-defined literal
//below is a workaround to fix compilation errors caused by this
#undef QLOCATION
#define QLOCATION "\0" __FILE__ ":" QTOSTRING(__LINE__)
#include "platform.moc.hpp" #include "platform.moc.hpp"
#include "platform.moc" #include "platform.moc"
#include "utility.cpp" #include "utility.cpp"

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp' ** Meta object code from reading C++ file 'platform.moc.hpp'
** **
** Created: Fri Feb 10 22:23:15 2012 ** Created: Thu Mar 22 11:27:37 2012
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3) ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!

View File

@ -1,8 +1,10 @@
processor_objects := processor_objects :=
processor_objects += $(if $(findstring arm,$(processors)),processor-arm) processor_objects += $(if $(findstring arm,$(processors)),processor-arm)
processor_objects += $(if $(findstring hg51b,$(processors)),processor-hg51b) processor_objects += $(if $(findstring hg51b,$(processors)),processor-hg51b)
processor_objects += $(if $(findstring upd96050,$(processors)),processor-upd96050)
objects += $(processor_objects) objects += $(processor_objects)
processor := processor processor := processor
obj/processor-arm.o: $(processor)/arm/arm.cpp $(call rwildcard,$(processor)/arm) obj/processor-arm.o: $(processor)/arm/arm.cpp $(call rwildcard,$(processor)/arm)
obj/processor-hg51b.o: $(processor)/hg51b/hg51b.cpp $(call rwildcard,$(processor)/hg51b) obj/processor-hg51b.o: $(processor)/hg51b/hg51b.cpp $(call rwildcard,$(processor)/hg51b)
obj/processor-upd96050.o: $(processor)/upd96050/upd96050.cpp $(call rwildcard,$(processor)/upd96050)

View File

@ -568,13 +568,13 @@ string ARM::disassemble_thumb_instruction(uint32 pc) {
} }
//move_multiple() //move_multiple()
//(ldmia,stmdb) rn,{r...} //(ldmia,stmia) rn,{r...}
if((instruction & 0xf000) == 0xc000) { if((instruction & 0xf000) == 0xc000) {
uint1 load = instruction >> 11; uint1 load = instruction >> 11;
uint3 rn = instruction >> 8; uint3 rn = instruction >> 8;
uint8 list = instruction; uint8 list = instruction;
output.append(load ? "ldmia " : "stmdb ", registers[rn], "!,{"); output.append(load ? "ldmia " : "stmia ", registers[rn], "!,{");
for(unsigned l = 0; l < 8; l++) { for(unsigned l = 0; l < 8; l++) {
if(list & (1 << l)) output.append(registers[l], ","); if(list & (1 << l)) output.append(registers[l], ",");
} }

View File

@ -30,7 +30,7 @@ void ARM::arm_step() {
if((instruction() & 0x0fb000f0) == 0x01000000) { arm_op_move_to_register_from_status(); return; } if((instruction() & 0x0fb000f0) == 0x01000000) { arm_op_move_to_register_from_status(); return; }
if((instruction() & 0x0fb000f0) == 0x01000090) { arm_op_memory_swap(); return; } if((instruction() & 0x0fb000f0) == 0x01000090) { arm_op_memory_swap(); return; }
if((instruction() & 0x0fb000f0) == 0x01200000) { arm_op_move_to_status_from_register(); return; } if((instruction() & 0x0fb000f0) == 0x01200000) { arm_op_move_to_status_from_register(); return; }
if((instruction() & 0x0ff000f0) == 0x01200010) { arm_op_branch_exchange_register(); return; } //ARMv4 if((instruction() & 0x0ff000f0) == 0x01200010) { arm_op_branch_exchange_register(); return; } //ARMv4+
if((instruction() & 0x0fb00000) == 0x03200000) { arm_op_move_to_status_from_immediate(); return; } if((instruction() & 0x0fb00000) == 0x03200000) { arm_op_move_to_status_from_immediate(); return; }
if((instruction() & 0x0e000010) == 0x00000000) { arm_op_data_immediate_shift(); return; } if((instruction() & 0x0e000010) == 0x00000000) { arm_op_data_immediate_shift(); return; }
@ -289,8 +289,8 @@ void ARM::arm_op_move_to_status_from_register() {
void ARM::arm_op_branch_exchange_register() { void ARM::arm_op_branch_exchange_register() {
uint4 m = instruction(); uint4 m = instruction();
r(15) = r(m);
cpsr().t = r(m) & 1; cpsr().t = r(m) & 1;
r(15) = r(m);
} }
//msr{condition} (c,s)psr:{fields},#immediate //msr{condition} (c,s)psr:{fields},#immediate

View File

@ -96,15 +96,6 @@ uint32 ARM::thumb_tst(uint32 modify) {
return modify; return modify;
} }
void ARM::thumb_cmp(uint32 source, uint32 modify) {
uint32 result = source - modify;
uint32 overflow = ~(source ^ modify) & (source ^ result);
cpsr().n = result >> 31;
cpsr().z = result == 0;
cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result);
cpsr().v = (1u << 31) & (overflow);
}
uint32 ARM::thumb_add(uint32 source, uint32 modify, bool carry) { uint32 ARM::thumb_add(uint32 source, uint32 modify, bool carry) {
uint32 result = source + modify + carry; uint32 result = source + modify + carry;
uint32 overflow = ~(source ^ modify) & (source ^ result); uint32 overflow = ~(source ^ modify) & (source ^ result);
@ -116,13 +107,7 @@ uint32 ARM::thumb_add(uint32 source, uint32 modify, bool carry) {
} }
uint32 ARM::thumb_sub(uint32 source, uint32 modify, bool carry) { uint32 ARM::thumb_sub(uint32 source, uint32 modify, bool carry) {
uint32 result = source - modify + carry; thumb_add(source, ~modify, carry);
uint32 overflow = ~(source ^ modify) & (source ^ result);
cpsr().n = result >> 31;
cpsr().z = result == 0;
cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result);
cpsr().v = (1u << 31) & (overflow);
return result;
} }
uint32 ARM::thumb_lsl(uint32 source, uint32 modify) { uint32 ARM::thumb_lsl(uint32 source, uint32 modify) {
@ -240,7 +225,7 @@ void ARM::thumb_op_immediate() {
switch(opcode) { switch(opcode) {
case 0: r(d) = thumb_tst( immediate); break; case 0: r(d) = thumb_tst( immediate); break;
case 1: thumb_cmp(r(d), immediate); break; case 1: thumb_sub(r(d), immediate); break;
case 2: r(d) = thumb_add(r(d), immediate); break; case 2: r(d) = thumb_add(r(d), immediate); break;
case 3: r(d) = thumb_sub(r(d), immediate); break; case 3: r(d) = thumb_sub(r(d), immediate); break;
} }
@ -265,8 +250,8 @@ void ARM::thumb_op_alu() {
void ARM::thumb_op_branch_exchange() { void ARM::thumb_op_branch_exchange() {
uint4 m = instruction() >> 3; uint4 m = instruction() >> 3;
r(15) = r(m);
cpsr().t = r(m) & 1; cpsr().t = r(m) & 1;
r(15) = r(m);
} }
//{opcode} rd,rm //{opcode} rd,rm
@ -423,34 +408,30 @@ void ARM::thumb_op_stack_multiple() {
uint1 branch = instruction() >> 8; uint1 branch = instruction() >> 8;
uint8 list = instruction(); uint8 list = instruction();
if(load == 1) { uint32 sp = 0;
for(unsigned l = 0; l < 8; l++) { if(load == 1) sp = r(13);
if(list & (1 << l)) { if(load == 0) sp = r(13) - (bit::count(list) + branch) * 4;
r(l) = bus_read(r(13), Word);
r(13) += 4; for(unsigned l = 0; l < 8; l++) {
} if(list & (1 << l)) {
} if(load == 1) r(l) = bus_read(sp, Word); //POP
if(branch) { if(load == 0) bus_write(sp, Word, r(l)); //PUSH
r(15) = bus_read(r(13), Word); sp += 4;
r(13) += 4;
} }
} }
if(load == 0) { if(branch) {
for(unsigned l = 0; l < 8; l++) { //note: ARMv5+ POP sets cpsr().t
if(list & (1 << l)) { if(load == 1) r(15) = bus_read(sp, Word); //POP
r(13) -= 4; if(load == 0) bus_write(sp, Word, r(14)); //PUSH
bus_write(r(13), Word, r(l)); sp += 4;
}
}
if(branch) {
r(13) -= 4;
bus_write(r(13), Word, r(14));
}
} }
if(load == 1) r(13) += (bit::count(list) + branch) * 4;
if(load == 0) r(13) -= (bit::count(list) + branch) * 4;
} }
//(ldmia,stmdb) rn!,{r...} //(ldmia,stmia) rn!,{r...}
//1100 lnnn llll llll //1100 lnnn llll llll
//l = load (0 = save) //l = load (0 = save)
//n = rn //n = rn
@ -460,21 +441,11 @@ void ARM::thumb_op_move_multiple() {
uint3 n = instruction() >> 8; uint3 n = instruction() >> 8;
uint8 list = instruction(); uint8 list = instruction();
if(load == 1) { for(unsigned l = 0; l < 8; l++) {
for(unsigned l = 0; l < 8; l++) { if(list & (1 << l)) {
if(list & (1 << l)) { if(load == 1) r(l) = bus_read(r(n), Word); //LDMIA
r(l) = bus_read(r(n), Word); if(load == 0) bus_write(r(n), Word, r(l)); //STMIA
r(n) += 4; r(n) += 4;
}
}
}
if(load == 0) {
for(unsigned l = 0; l < 8; l++) {
if(list & (1 << l)) {
r(n) -= 4;
bus_write(r(n), Word, r(l));
}
} }
} }
} }
@ -513,9 +484,9 @@ void ARM::thumb_op_branch_short() {
//1111 0ooo oooo oooo //1111 0ooo oooo oooo
//o = offset //o = offset
void ARM::thumb_op_branch_long_prefix() { void ARM::thumb_op_branch_long_prefix() {
uint11 offsethi = instruction(); int11 offsethi = instruction();
r(14) = offsethi; r(14) = r(15) + ((offsethi * 2) << 11);
} }
//bl address //bl address
@ -524,9 +495,8 @@ void ARM::thumb_op_branch_long_prefix() {
void ARM::thumb_op_branch_long_suffix() { void ARM::thumb_op_branch_long_suffix() {
uint11 offsetlo = instruction(); uint11 offsetlo = instruction();
int22 displacement = ((uint11)r(14) << 11) | offsetlo; r(15) = r(14) + (offsetlo * 2);
r(14) = r(15) | 1; r(14) = pipeline.decode.address | 1;
r(15) += displacement * 2;
} }
#endif #endif

View File

@ -4,7 +4,6 @@ bool thumb_condition(uint4 condition);
void thumb_opcode(uint4 opcode, uint4 d, uint4 s); void thumb_opcode(uint4 opcode, uint4 d, uint4 s);
uint32 thumb_tst(uint32 modify); uint32 thumb_tst(uint32 modify);
void thumb_cmp(uint32 source, uint32 modify);
uint32 thumb_add(uint32 source, uint32 modify, bool carry = 0); uint32 thumb_add(uint32 source, uint32 modify, bool carry = 0);
uint32 thumb_sub(uint32 source, uint32 modify, bool carry = 1); uint32 thumb_sub(uint32 source, uint32 modify, bool carry = 1);
uint32 thumb_lsl(uint32 source, uint32 modify); uint32 thumb_lsl(uint32 source, uint32 modify);

View File

@ -0,0 +1,222 @@
void uPD96050::exec() {
uint24 opcode = programROM[regs.pc++];
switch(opcode >> 22) {
case 0: exec_op(opcode); break;
case 1: exec_rt(opcode); break;
case 2: exec_jp(opcode); break;
case 3: exec_ld(opcode); break;
}
int32 result = (int32)regs.k * regs.l; //sign + 30-bit result
regs.m = result >> 15; //store sign + top 15-bits
regs.n = result << 1; //store low 15-bits + zero
}
void uPD96050::exec_op(uint24 opcode) {
uint2 pselect = opcode >> 20; //P select
uint4 alu = opcode >> 16; //ALU operation mode
uint1 asl = opcode >> 15; //accumulator select
uint2 dpl = opcode >> 13; //DP low modify
uint4 dphm = opcode >> 9; //DP high XOR modify
uint1 rpdcr = opcode >> 8; //RP decrement
uint4 src = opcode >> 4; //move source
uint4 dst = opcode >> 0; //move destination
uint16 idb;
switch(src) {
case 0: idb = regs.trb; break;
case 1: idb = regs.a; break;
case 2: idb = regs.b; break;
case 3: idb = regs.tr; break;
case 4: idb = regs.dp; break;
case 5: idb = regs.rp; break;
case 6: idb = dataROM[regs.rp]; break;
case 7: idb = 0x8000 - regs.flaga.s1; break;
case 8: idb = regs.dr; regs.sr.rqm = 1; break;
case 9: idb = regs.dr; break;
case 10: idb = regs.sr; break;
case 11: idb = regs.si; break; //MSB
case 12: idb = regs.si; break; //LSB
case 13: idb = regs.k; break;
case 14: idb = regs.l; break;
case 15: idb = dataRAM[regs.dp]; break;
}
if(alu) {
uint16 p, q, r;
Flag flag;
bool c;
switch(pselect) {
case 0: p = dataRAM[regs.dp]; break;
case 1: p = idb; break;
case 2: p = regs.m; break;
case 3: p = regs.n; break;
}
switch(asl) {
case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break;
case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break;
}
switch(alu) {
case 1: r = q | p; break; //OR
case 2: r = q & p; break; //AND
case 3: r = q ^ p; break; //XOR
case 4: r = q - p; break; //SUB
case 5: r = q + p; break; //ADD
case 6: r = q - p - c; break; //SBB
case 7: r = q + p + c; break; //ADC
case 8: r = q - 1; p = 1; break; //DEC
case 9: r = q + 1; p = 1; break; //INC
case 10: r = ~q; break; //CMP
case 11: r = (q >> 1) | (q & 0x8000); break; //SHR1 (ASR)
case 12: r = (q << 1) | c; break; //SHL1 (ROL)
case 13: r = (q << 2) | 3; break; //SHL2
case 14: r = (q << 4) | 15; break; //SHL4
case 15: r = (q << 8) | (q >> 8); break; //XCHG
}
flag.s0 = (r & 0x8000);
flag.z = (r == 0);
switch(alu) {
case 1: case 2: case 3: case 10: case 13: case 14: case 15: {
flag.c = 0;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
case 4: case 5: case 6: case 7: case 8: case 9: {
if(alu & 1) {
//addition
flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000;
flag.c = (r < q);
} else {
//subtraction
flag.ov0 = (q ^ r) & (q ^ p) & 0x8000;
flag.c = (r > q);
}
if(flag.ov0) {
flag.s1 = flag.ov1 ^ !(r & 0x8000);
flag.ov1 = !flag.ov1;
}
break;
}
case 11: {
flag.c = q & 1;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
case 12: {
flag.c = q >> 15;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
}
switch(asl) {
case 0: regs.a = r; regs.flaga = flag; break;
case 1: regs.b = r; regs.flagb = flag; break;
}
}
exec_ld((idb << 6) + dst);
switch(dpl) {
case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC
case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC
case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR
}
regs.dp ^= dphm << 4;
if(rpdcr) regs.rp--;
}
void uPD96050::exec_rt(uint24 opcode) {
exec_op(opcode);
regs.pc = regs.stack[--regs.sp];
}
void uPD96050::exec_jp(uint24 opcode) {
uint9 brch = opcode >> 13; //branch
uint11 na = opcode >> 2; //next address
uint2 bank = opcode >> 0; //bank address
uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0);
switch(brch) {
case 0x000: regs.pc = regs.so; return; //JMPSO
case 0x080: if(regs.flaga.c == 0) regs.pc = jp; return; //JNCA
case 0x082: if(regs.flaga.c == 1) regs.pc = jp; return; //JCA
case 0x084: if(regs.flagb.c == 0) regs.pc = jp; return; //JNCB
case 0x086: if(regs.flagb.c == 1) regs.pc = jp; return; //JCB
case 0x088: if(regs.flaga.z == 0) regs.pc = jp; return; //JNZA
case 0x08a: if(regs.flaga.z == 1) regs.pc = jp; return; //JZA
case 0x08c: if(regs.flagb.z == 0) regs.pc = jp; return; //JNZB
case 0x08e: if(regs.flagb.z == 1) regs.pc = jp; return; //JZB
case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jp; return; //JNOVA0
case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jp; return; //JOVA0
case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jp; return; //JNOVB0
case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jp; return; //JOVB0
case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jp; return; //JNOVA1
case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jp; return; //JOVA1
case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jp; return; //JNOVB1
case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jp; return; //JOVB1
case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jp; return; //JNSA0
case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jp; return; //JSA0
case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jp; return; //JNSB0
case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jp; return; //JSB0
case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jp; return; //JNSA1
case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jp; return; //JSA1
case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jp; return; //JNSB1
case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jp; return; //JSB1
case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jp; return; //JDPL0
case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jp; return; //JDPLN0
case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jp; return; //JDPLF
case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jp; return; //JDPLNF
case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jp; return; //JNRQM
case 0x0be: if(regs.sr.rqm == 1) regs.pc = jp; return; //JRQM
case 0x100: regs.pc = jp & ~0x2000; return; //LJMP
case 0x101: regs.pc = jp | 0x2000; return; //HJMP
case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = jp & ~0x2000; return; //LCALL
case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = jp | 0x2000; return; //HCALL
}
}
void uPD96050::exec_ld(uint24 opcode) {
uint16 id = opcode >> 6; //immediate data
uint4 dst = opcode >> 0; //destination
switch(dst) {
case 0: break;
case 1: regs.a = id; break;
case 2: regs.b = id; break;
case 3: regs.tr = id; break;
case 4: regs.dp = id; break;
case 5: regs.rp = id; break;
case 6: regs.dr = id; regs.sr.rqm = 1; break;
case 7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c); break;
case 8: regs.so = id; break; //LSB
case 9: regs.so = id; break; //MSB
case 10: regs.k = id; break;
case 11: regs.k = id; regs.l = dataROM[regs.rp]; break;
case 12: regs.l = id; regs.k = dataRAM[regs.dp | 0x40]; break;
case 13: regs.l = id; break;
case 14: regs.trb = id; break;
case 15: dataRAM[regs.dp] = id; break;
}
}

View File

@ -1,16 +1,11 @@
#ifdef NECDSP_CPP uint8 uPD96050::sr_read() {
uint8 NECDSP::sr_read(unsigned) {
cpu.synchronize_coprocessors();
return regs.sr >> 8; return regs.sr >> 8;
} }
void NECDSP::sr_write(unsigned, uint8 data) { void uPD96050::sr_write(uint8 data) {
cpu.synchronize_coprocessors();
} }
uint8 NECDSP::dr_read(unsigned) { uint8 uPD96050::dr_read() {
cpu.synchronize_coprocessors();
if(regs.sr.drc == 0) { if(regs.sr.drc == 0) {
//16-bit //16-bit
if(regs.sr.drs == 0) { if(regs.sr.drs == 0) {
@ -28,8 +23,7 @@ uint8 NECDSP::dr_read(unsigned) {
} }
} }
void NECDSP::dr_write(unsigned, uint8 data) { void uPD96050::dr_write(uint8 data) {
cpu.synchronize_coprocessors();
if(regs.sr.drc == 0) { if(regs.sr.drc == 0) {
//16-bit //16-bit
if(regs.sr.drs == 0) { if(regs.sr.drs == 0) {
@ -47,8 +41,7 @@ void NECDSP::dr_write(unsigned, uint8 data) {
} }
} }
uint8 NECDSP::dp_read(unsigned addr) { uint8 uPD96050::dp_read(uint12 addr) {
cpu.synchronize_coprocessors();
bool hi = addr & 1; bool hi = addr & 1;
addr = (addr >> 1) & 2047; addr = (addr >> 1) & 2047;
@ -59,8 +52,7 @@ uint8 NECDSP::dp_read(unsigned addr) {
} }
} }
void NECDSP::dp_write(unsigned addr, uint8 data) { void uPD96050::dp_write(uint12 addr, uint8 data) {
cpu.synchronize_coprocessors();
bool hi = addr & 1; bool hi = addr & 1;
addr = (addr >> 1) & 2047; addr = (addr >> 1) & 2047;
@ -70,5 +62,3 @@ void NECDSP::dp_write(unsigned addr, uint8 data) {
dataRAM[addr] = (dataRAM[addr] & 0x00ff) | (data << 8); dataRAM[addr] = (dataRAM[addr] & 0x00ff) | (data << 8);
} }
} }
#endif

View File

@ -0,0 +1,49 @@
void uPD96050::serialize(serializer &s) {
s.array(dataRAM);
s.array(regs.stack);
s.integer(regs.pc);
s.integer(regs.rp);
s.integer(regs.dp);
s.integer(regs.sp);
s.integer(regs.k);
s.integer(regs.l);
s.integer(regs.m);
s.integer(regs.n);
s.integer(regs.a);
s.integer(regs.b);
s.integer(regs.flaga.s1);
s.integer(regs.flaga.s0);
s.integer(regs.flaga.c);
s.integer(regs.flaga.z);
s.integer(regs.flaga.ov1);
s.integer(regs.flaga.ov0);
s.integer(regs.flagb.s1);
s.integer(regs.flagb.s0);
s.integer(regs.flagb.c);
s.integer(regs.flagb.z);
s.integer(regs.flagb.ov1);
s.integer(regs.flagb.ov0);
s.integer(regs.tr);
s.integer(regs.trb);
s.integer(regs.sr.rqm);
s.integer(regs.sr.usf1);
s.integer(regs.sr.usf0);
s.integer(regs.sr.drs);
s.integer(regs.sr.dma);
s.integer(regs.sr.drc);
s.integer(regs.sr.soc);
s.integer(regs.sr.sic);
s.integer(regs.sr.ei);
s.integer(regs.sr.p1);
s.integer(regs.sr.p0);
s.integer(regs.dr);
s.integer(regs.si);
s.integer(regs.so);
}

View File

@ -0,0 +1,45 @@
#include <processor/processor.hpp>
#include "upd96050.hpp"
namespace Processor {
#include "instructions.cpp"
#include "memory.cpp"
#include "disassembler.cpp"
#include "serialization.cpp"
void uPD96050::power() {
if(revision == Revision::uPD7725) {
regs.pc.bits(11);
regs.rp.bits(10);
regs.dp.bits( 8);
}
if(revision == Revision::uPD96050) {
regs.pc.bits(14);
regs.rp.bits(11);
regs.dp.bits(11);
}
for(unsigned n = 0; n < 16; n++) regs.stack[n] = 0x0000;
regs.pc = 0x0000;
regs.rp = 0x0000;
regs.dp = 0x0000;
regs.sp = 0x0;
regs.k = 0x0000;
regs.l = 0x0000;
regs.m = 0x0000;
regs.n = 0x0000;
regs.a = 0x0000;
regs.b = 0x0000;
regs.flaga = 0x00;
regs.flagb = 0x00;
regs.tr = 0x0000;
regs.trb = 0x0000;
regs.sr = 0x0000;
regs.dr = 0x0000;
regs.si = 0x0000;
regs.so = 0x0000;
}
}

View File

@ -0,0 +1,40 @@
#ifndef PROCESSOR_UPD96050_HPP
#define PROCESSOR_UPD96050_HPP
namespace Processor {
//NEC uPD7720 (not supported)
//NEC uPD7725
//NEC uPD96050
struct uPD96050 {
enum class Revision : unsigned { uPD7725, uPD96050 } revision;
uint24 programROM[16384];
uint16 dataROM[2048];
uint16 dataRAM[2048];
#include "registers.hpp"
void power();
void exec();
void serialize(serializer&);
void exec_op(uint24 opcode);
void exec_rt(uint24 opcode);
void exec_jp(uint24 opcode);
void exec_ld(uint24 opcode);
uint8 sr_read();
void sr_write(uint8 data);
uint8 dr_read();
void dr_write(uint8 data);
uint8 dp_read(uint12 addr);
void dp_write(uint12 addr, uint8 data);
string disassemble(uint14 ip);
};
}
#endif

View File

@ -164,8 +164,6 @@ public:
bool init() { bool init() {
term(); term();
// display = XOpenDisplay(0);
// screen = DefaultScreen(display);
glXQueryVersion(display, &glx.version_major, &glx.version_minor); glXQueryVersion(display, &glx.version_major, &glx.version_minor);
//require GLX 1.2+ API //require GLX 1.2+ API
if(glx.version_major < 1 || (glx.version_major == 1 && glx.version_minor < 2)) return false; if(glx.version_major < 1 || (glx.version_major == 1 && glx.version_minor < 2)) return false;
@ -179,9 +177,9 @@ public:
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DOUBLEBUFFER, True, GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, (settings.depth / 3), GLX_RED_SIZE, (signed)(settings.depth / 3),
GLX_GREEN_SIZE, (settings.depth / 3) + (settings.depth % 3), GLX_GREEN_SIZE, (signed)(settings.depth / 3) + (signed)(settings.depth % 3),
GLX_BLUE_SIZE, (settings.depth / 3), GLX_BLUE_SIZE, (signed)(settings.depth / 3),
None, None,
}; };

View File

@ -3,8 +3,6 @@
#define NECDSP_CPP #define NECDSP_CPP
namespace SNES { namespace SNES {
#include "memory.cpp"
#include "disassembler.cpp"
#include "serialization.cpp" #include "serialization.cpp"
NECDSP necdsp; NECDSP necdsp;
@ -16,231 +14,20 @@ void NECDSP::enter() {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
} }
uint24 opcode = programROM[regs.pc++]; exec();
switch(opcode >> 22) {
case 0: exec_op(opcode); break;
case 1: exec_rt(opcode); break;
case 2: exec_jp(opcode); break;
case 3: exec_ld(opcode); break;
}
int32 result = (int32)regs.k * regs.l; //sign + 30-bit result
regs.m = result >> 15; //store sign + top 15-bits
regs.n = result << 1; //store low 15-bits + zero
step(1); step(1);
synchronize_cpu(); synchronize_cpu();
} }
} }
void NECDSP::exec_op(uint24 opcode) { uint8 NECDSP::sr_read(unsigned) { cpu.synchronize_coprocessors(); return uPD96050::sr_read(); }
uint2 pselect = opcode >> 20; //P select void NECDSP::sr_write(unsigned, uint8 data) { cpu.synchronize_coprocessors(); return uPD96050::sr_write(data); }
uint4 alu = opcode >> 16; //ALU operation mode
uint1 asl = opcode >> 15; //accumulator select
uint2 dpl = opcode >> 13; //DP low modify
uint4 dphm = opcode >> 9; //DP high XOR modify
uint1 rpdcr = opcode >> 8; //RP decrement
uint4 src = opcode >> 4; //move source
uint4 dst = opcode >> 0; //move destination
uint16 idb; uint8 NECDSP::dr_read(unsigned) { cpu.synchronize_coprocessors(); return uPD96050::dr_read(); }
switch(src) { void NECDSP::dr_write(unsigned, uint8 data) { cpu.synchronize_coprocessors(); return uPD96050::dr_write(data); }
case 0: idb = regs.trb; break;
case 1: idb = regs.a; break;
case 2: idb = regs.b; break;
case 3: idb = regs.tr; break;
case 4: idb = regs.dp; break;
case 5: idb = regs.rp; break;
case 6: idb = dataROM[regs.rp]; break;
case 7: idb = 0x8000 - regs.flaga.s1; break;
case 8: idb = regs.dr; regs.sr.rqm = 1; break;
case 9: idb = regs.dr; break;
case 10: idb = regs.sr; break;
case 11: idb = regs.si; break; //MSB
case 12: idb = regs.si; break; //LSB
case 13: idb = regs.k; break;
case 14: idb = regs.l; break;
case 15: idb = dataRAM[regs.dp]; break;
}
if(alu) { uint8 NECDSP::dp_read(unsigned addr) { cpu.synchronize_coprocessors(); return uPD96050::dp_read(addr); }
uint16 p, q, r; void NECDSP::dp_write(unsigned addr, uint8 data) { cpu.synchronize_coprocessors(); return uPD96050::dp_write(addr, data); }
Flag flag;
bool c;
switch(pselect) {
case 0: p = dataRAM[regs.dp]; break;
case 1: p = idb; break;
case 2: p = regs.m; break;
case 3: p = regs.n; break;
}
switch(asl) {
case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break;
case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break;
}
switch(alu) {
case 1: r = q | p; break; //OR
case 2: r = q & p; break; //AND
case 3: r = q ^ p; break; //XOR
case 4: r = q - p; break; //SUB
case 5: r = q + p; break; //ADD
case 6: r = q - p - c; break; //SBB
case 7: r = q + p + c; break; //ADC
case 8: r = q - 1; p = 1; break; //DEC
case 9: r = q + 1; p = 1; break; //INC
case 10: r = ~q; break; //CMP
case 11: r = (q >> 1) | (q & 0x8000); break; //SHR1 (ASR)
case 12: r = (q << 1) | c; break; //SHL1 (ROL)
case 13: r = (q << 2) | 3; break; //SHL2
case 14: r = (q << 4) | 15; break; //SHL4
case 15: r = (q << 8) | (q >> 8); break; //XCHG
}
flag.s0 = (r & 0x8000);
flag.z = (r == 0);
switch(alu) {
case 1: case 2: case 3: case 10: case 13: case 14: case 15: {
flag.c = 0;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
case 4: case 5: case 6: case 7: case 8: case 9: {
if(alu & 1) {
//addition
flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000;
flag.c = (r < q);
} else {
//subtraction
flag.ov0 = (q ^ r) & (q ^ p) & 0x8000;
flag.c = (r > q);
}
if(flag.ov0) {
flag.s1 = flag.ov1 ^ !(r & 0x8000);
flag.ov1 = !flag.ov1;
}
break;
}
case 11: {
flag.c = q & 1;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
case 12: {
flag.c = q >> 15;
flag.ov0 = 0;
flag.ov1 = 0;
break;
}
}
switch(asl) {
case 0: regs.a = r; regs.flaga = flag; break;
case 1: regs.b = r; regs.flagb = flag; break;
}
}
exec_ld((idb << 6) + dst);
switch(dpl) {
case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC
case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC
case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR
}
regs.dp ^= dphm << 4;
if(rpdcr) regs.rp--;
}
void NECDSP::exec_rt(uint24 opcode) {
exec_op(opcode);
regs.pc = regs.stack[--regs.sp];
}
void NECDSP::exec_jp(uint24 opcode) {
uint9 brch = opcode >> 13; //branch
uint11 na = opcode >> 2; //next address
uint2 bank = opcode >> 0; //bank address
uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0);
switch(brch) {
case 0x000: regs.pc = regs.so; return; //JMPSO
case 0x080: if(regs.flaga.c == 0) regs.pc = jp; return; //JNCA
case 0x082: if(regs.flaga.c == 1) regs.pc = jp; return; //JCA
case 0x084: if(regs.flagb.c == 0) regs.pc = jp; return; //JNCB
case 0x086: if(regs.flagb.c == 1) regs.pc = jp; return; //JCB
case 0x088: if(regs.flaga.z == 0) regs.pc = jp; return; //JNZA
case 0x08a: if(regs.flaga.z == 1) regs.pc = jp; return; //JZA
case 0x08c: if(regs.flagb.z == 0) regs.pc = jp; return; //JNZB
case 0x08e: if(regs.flagb.z == 1) regs.pc = jp; return; //JZB
case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jp; return; //JNOVA0
case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jp; return; //JOVA0
case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jp; return; //JNOVB0
case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jp; return; //JOVB0
case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jp; return; //JNOVA1
case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jp; return; //JOVA1
case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jp; return; //JNOVB1
case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jp; return; //JOVB1
case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jp; return; //JNSA0
case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jp; return; //JSA0
case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jp; return; //JNSB0
case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jp; return; //JSB0
case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jp; return; //JNSA1
case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jp; return; //JSA1
case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jp; return; //JNSB1
case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jp; return; //JSB1
case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jp; return; //JDPL0
case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jp; return; //JDPLN0
case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jp; return; //JDPLF
case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jp; return; //JDPLNF
case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jp; return; //JNRQM
case 0x0be: if(regs.sr.rqm == 1) regs.pc = jp; return; //JRQM
case 0x100: regs.pc = jp & ~0x2000; return; //LJMP
case 0x101: regs.pc = jp | 0x2000; return; //HJMP
case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = jp & ~0x2000; return; //LCALL
case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = jp | 0x2000; return; //HCALL
}
}
void NECDSP::exec_ld(uint24 opcode) {
uint16 id = opcode >> 6; //immediate data
uint4 dst = opcode >> 0; //destination
switch(dst) {
case 0: break;
case 1: regs.a = id; break;
case 2: regs.b = id; break;
case 3: regs.tr = id; break;
case 4: regs.dp = id; break;
case 5: regs.rp = id; break;
case 6: regs.dr = id; regs.sr.rqm = 1; break;
case 7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c); break;
case 8: regs.so = id; break; //LSB
case 9: regs.so = id; break; //MSB
case 10: regs.k = id; break;
case 11: regs.k = id; regs.l = dataROM[regs.rp]; break;
case 12: regs.l = id; regs.k = dataRAM[regs.dp | 0x40]; break;
case 13: regs.l = id; break;
case 14: regs.trb = id; break;
case 15: dataRAM[regs.dp] = id; break;
}
}
void NECDSP::init() { void NECDSP::init() {
} }
@ -255,47 +42,11 @@ void NECDSP::unload() {
} }
void NECDSP::power() { void NECDSP::power() {
if(revision == Revision::uPD7725) {
regs.pc.bits(11);
regs.rp.bits(10);
regs.dp.bits( 8);
}
if(revision == Revision::uPD96050) {
regs.pc.bits(14);
regs.rp.bits(11);
regs.dp.bits(11);
}
} }
void NECDSP::reset() { void NECDSP::reset() {
create(NECDSP::Enter, frequency); create(NECDSP::Enter, frequency);
uPD96050::power();
for(unsigned n = 0; n < 16; n++) regs.stack[n] = 0x0000;
regs.pc = 0x0000;
regs.rp = 0x0000;
regs.dp = 0x0000;
regs.sp = 0x0;
regs.k = 0x0000;
regs.l = 0x0000;
regs.m = 0x0000;
regs.n = 0x0000;
regs.a = 0x0000;
regs.b = 0x0000;
regs.flaga = 0x00;
regs.flagb = 0x00;
regs.tr = 0x0000;
regs.trb = 0x0000;
regs.sr = 0x0000;
regs.dr = 0x0000;
regs.si = 0x0000;
regs.so = 0x0000;
}
NECDSP::NECDSP() {
}
NECDSP::~NECDSP() {
} }
} }

View File

@ -1,31 +1,7 @@
//NEC uPD7725 struct NECDSP : Processor::uPD96050, Coprocessor {
//NEC uPD96050
class NECDSP : public Coprocessor {
public:
enum class Revision : unsigned { uPD7725, uPD96050 } revision;
unsigned frequency;
#include "registers.hpp"
uint24 programROM[16384];
uint16 dataROM[2048];
uint16 dataRAM[2048];
unsigned programROMSize;
unsigned dataROMSize;
unsigned dataRAMSize;
static void Enter(); static void Enter();
void enter(); void enter();
void exec_op(uint24 opcode);
void exec_rt(uint24 opcode);
void exec_jp(uint24 opcode);
void exec_ld(uint24 opcode);
string disassemble(uint14 ip);
uint8 sr_read(unsigned); uint8 sr_read(unsigned);
void sr_write(unsigned, uint8 data); void sr_write(unsigned, uint8 data);
@ -42,8 +18,6 @@ public:
void reset(); void reset();
void serialize(serializer&); void serialize(serializer&);
NECDSP();
~NECDSP();
}; };
extern NECDSP necdsp; extern NECDSP necdsp;

View File

@ -1,55 +1,8 @@
#ifdef NECDSP_CPP #ifdef NECDSP_CPP
void NECDSP::serialize(serializer &s) { void NECDSP::serialize(serializer &s) {
uPD96050::serialize(s);
Thread::serialize(s); Thread::serialize(s);
s.array(dataRAM);
s.array(regs.stack);
s.integer(regs.pc);
s.integer(regs.rp);
s.integer(regs.dp);
s.integer(regs.sp);
s.integer(regs.k);
s.integer(regs.l);
s.integer(regs.m);
s.integer(regs.n);
s.integer(regs.a);
s.integer(regs.b);
s.integer(regs.flaga.s1);
s.integer(regs.flaga.s0);
s.integer(regs.flaga.c);
s.integer(regs.flaga.z);
s.integer(regs.flaga.ov1);
s.integer(regs.flaga.ov0);
s.integer(regs.flagb.s1);
s.integer(regs.flagb.s0);
s.integer(regs.flagb.c);
s.integer(regs.flagb.z);
s.integer(regs.flagb.ov1);
s.integer(regs.flagb.ov0);
s.integer(regs.tr);
s.integer(regs.trb);
s.integer(regs.sr.rqm);
s.integer(regs.sr.usf1);
s.integer(regs.sr.usf0);
s.integer(regs.sr.drs);
s.integer(regs.sr.dma);
s.integer(regs.sr.drc);
s.integer(regs.sr.soc);
s.integer(regs.sr.sic);
s.integer(regs.sr.ei);
s.integer(regs.sr.p1);
s.integer(regs.sr.p0);
s.integer(regs.dr);
s.integer(regs.si);
s.integer(regs.so);
} }
#endif #endif

View File

@ -4,11 +4,12 @@
#include <base/base.hpp> #include <base/base.hpp>
#include <processor/arm/arm.hpp> #include <processor/arm/arm.hpp>
#include <processor/hg51b/hg51b.hpp> #include <processor/hg51b/hg51b.hpp>
#include <processor/upd96050/upd96050.hpp>
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
static const unsigned SerializerVersion = 23; static const unsigned SerializerVersion = 24;
} }
} }

View File

@ -1,4 +1,4 @@
processors := arm hg51b processors := arm hg51b upd96050
include processor/Makefile include processor/Makefile
include $(nes)/Makefile include $(nes)/Makefile

View File

@ -123,6 +123,8 @@ Application::Application(int argc, char **argv) {
Application::run(); Application::run();
} }
if(GBA::cartridge.loaded()) print(GBA::cpu.disassemble_registers(), "\n");
interface->unloadCartridge(); interface->unloadCartridge();
windowManager->saveGeometry(); windowManager->saveGeometry();
windowManager->hideAll(); windowManager->hideAll();