mirror of https://github.com/bsnes-emu/bsnes.git
Update to v095r11 release.
byuu says: Changelog: - SFC: "uint8 read(uint addr)" -> "uint8 read(uint addr, uint8 data)" - hiro: mHorizontalLayout::setGeometry() return value - hiro/GTK: ListView,TreeView::setFocused() does not grab focus of first item Notes: - nall/windows/utf8.hpp needs using uint = unsigned; at the top to compile - sfc/balanced, sfc/performance won't compile yet Seems Cx4 games broke a while back. Not from this WIP, either. I'll go back and find out what's wrong now.
This commit is contained in:
parent
78d49d3873
commit
f2a416aea9
|
@ -7,7 +7,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "095.10";
|
static const string Version = "095.11";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
#if defined(Hiro_Object)
|
#if defined(Hiro_Object)
|
||||||
struct Object : sObject {
|
struct Object : sObject {
|
||||||
DeclareSharedObject(Object)
|
DeclareSharedObject(Object)
|
||||||
|
using internalType = mObject;
|
||||||
|
|
||||||
template<typename T> auto cast() -> T {
|
template<typename T> auto cast() -> T {
|
||||||
if(auto pointer = dynamic_cast<typename T::internalType*>(data())) {
|
if(auto pointer = dynamic_cast<typename T::internalType*>(data())) {
|
||||||
|
@ -73,14 +74,23 @@ struct Object : sObject {
|
||||||
#if defined(Hiro_Group)
|
#if defined(Hiro_Group)
|
||||||
struct Group : sGroup {
|
struct Group : sGroup {
|
||||||
DeclareShared(Group)
|
DeclareShared(Group)
|
||||||
|
using internalType = mGroup;
|
||||||
template<typename... P> Group(P&&... p) : Group() { _append(std::forward<P>(p)...); }
|
template<typename... P> Group(P&&... p) : Group() { _append(std::forward<P>(p)...); }
|
||||||
|
|
||||||
auto append(sObject object) -> type& { return self().append(object), *this; }
|
auto append(sObject object) -> type& { return self().append(object), *this; }
|
||||||
auto object(unsigned position) const { return self().object(position); }
|
auto object(unsigned position) const { return self().object(position); }
|
||||||
auto objectCount() const { return self().objectCount(); }
|
auto objectCount() const { return self().objectCount(); }
|
||||||
auto objects() const { return self().objects(); }
|
//auto objects() const { return self().objects(); }
|
||||||
auto remove(sObject object) -> type& { return self().remove(object), *this; }
|
auto remove(sObject object) -> type& { return self().remove(object), *this; }
|
||||||
|
|
||||||
|
template<typename T = Object> auto objects() const -> vector<T> {
|
||||||
|
vector<T> objects;
|
||||||
|
for(auto object : self().objects()) {
|
||||||
|
if(auto cast = object.cast<T>()) objects.append(cast);
|
||||||
|
}
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto _append() {}
|
auto _append() {}
|
||||||
template<typename T, typename... P> auto _append(T* object, P&&... p) {
|
template<typename T, typename... P> auto _append(T* object, P&&... p) {
|
||||||
|
@ -93,6 +103,7 @@ private:
|
||||||
#if defined(Hiro_Timer)
|
#if defined(Hiro_Timer)
|
||||||
struct Timer : sTimer {
|
struct Timer : sTimer {
|
||||||
DeclareSharedObject(Timer)
|
DeclareSharedObject(Timer)
|
||||||
|
using internalType = mTimer;
|
||||||
|
|
||||||
auto doActivate() const { return self().doActivate(); }
|
auto doActivate() const { return self().doActivate(); }
|
||||||
auto interval() const { return self().interval(); }
|
auto interval() const { return self().interval(); }
|
||||||
|
@ -104,12 +115,14 @@ struct Timer : sTimer {
|
||||||
#if defined(Hiro_Action)
|
#if defined(Hiro_Action)
|
||||||
struct Action : sAction {
|
struct Action : sAction {
|
||||||
DeclareSharedAction(Action)
|
DeclareSharedAction(Action)
|
||||||
|
using internalType = mAction;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Hiro_Menu)
|
#if defined(Hiro_Menu)
|
||||||
struct Menu : sMenu {
|
struct Menu : sMenu {
|
||||||
DeclareSharedAction(Menu)
|
DeclareSharedAction(Menu)
|
||||||
|
using internalType = mMenu;
|
||||||
|
|
||||||
auto action(unsigned position) const { return self().action(position); }
|
auto action(unsigned position) const { return self().action(position); }
|
||||||
auto actionCount() const { return self().actionCount(); }
|
auto actionCount() const { return self().actionCount(); }
|
||||||
|
@ -127,12 +140,14 @@ struct Menu : sMenu {
|
||||||
#if defined(Hiro_MenuSeparator)
|
#if defined(Hiro_MenuSeparator)
|
||||||
struct MenuSeparator : sMenuSeparator {
|
struct MenuSeparator : sMenuSeparator {
|
||||||
DeclareSharedAction(MenuSeparator)
|
DeclareSharedAction(MenuSeparator)
|
||||||
|
using internalType = mMenuSeparator;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Hiro_MenuItem)
|
#if defined(Hiro_MenuItem)
|
||||||
struct MenuItem : sMenuItem {
|
struct MenuItem : sMenuItem {
|
||||||
DeclareSharedAction(MenuItem)
|
DeclareSharedAction(MenuItem)
|
||||||
|
using internalType = mMenuItem;
|
||||||
|
|
||||||
auto doActivate() const { return self().doActivate(); }
|
auto doActivate() const { return self().doActivate(); }
|
||||||
auto image() const { return self().image(); }
|
auto image() const { return self().image(); }
|
||||||
|
@ -146,6 +161,7 @@ struct MenuItem : sMenuItem {
|
||||||
#if defined(Hiro_MenuCheckItem)
|
#if defined(Hiro_MenuCheckItem)
|
||||||
struct MenuCheckItem : sMenuCheckItem {
|
struct MenuCheckItem : sMenuCheckItem {
|
||||||
DeclareSharedAction(MenuCheckItem)
|
DeclareSharedAction(MenuCheckItem)
|
||||||
|
using internalType = mMenuCheckItem;
|
||||||
|
|
||||||
auto checked() const { return self().checked(); }
|
auto checked() const { return self().checked(); }
|
||||||
auto doToggle() const { return self().doToggle(); }
|
auto doToggle() const { return self().doToggle(); }
|
||||||
|
@ -174,24 +190,28 @@ struct MenuRadioItem : sMenuRadioItem {
|
||||||
#if defined(Hiro_Sizable)
|
#if defined(Hiro_Sizable)
|
||||||
struct Sizable : sSizable {
|
struct Sizable : sSizable {
|
||||||
DeclareSharedSizable(Sizable)
|
DeclareSharedSizable(Sizable)
|
||||||
|
using internalType = mSizable;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Hiro_Layout)
|
#if defined(Hiro_Layout)
|
||||||
struct Layout : sLayout {
|
struct Layout : sLayout {
|
||||||
DeclareSharedLayout(Layout)
|
DeclareSharedLayout(Layout)
|
||||||
|
using internalType = mLayout;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Hiro_Widget)
|
#if defined(Hiro_Widget)
|
||||||
struct Widget : sWidget {
|
struct Widget : sWidget {
|
||||||
DeclareSharedWidget(Widget)
|
DeclareSharedWidget(Widget)
|
||||||
|
using internalType = mWidget;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Hiro_Button)
|
#if defined(Hiro_Button)
|
||||||
struct Button : sButton {
|
struct Button : sButton {
|
||||||
DeclareSharedWidget(Button)
|
DeclareSharedWidget(Button)
|
||||||
|
using internalType = mButton;
|
||||||
|
|
||||||
auto bordered() const { return self().bordered(); }
|
auto bordered() const { return self().bordered(); }
|
||||||
auto doActivate() const { return self().doActivate(); }
|
auto doActivate() const { return self().doActivate(); }
|
||||||
|
@ -209,6 +229,7 @@ struct Button : sButton {
|
||||||
#if defined(Hiro_Canvas)
|
#if defined(Hiro_Canvas)
|
||||||
struct Canvas : sCanvas {
|
struct Canvas : sCanvas {
|
||||||
DeclareSharedWidget(Canvas)
|
DeclareSharedWidget(Canvas)
|
||||||
|
using internalType = mCanvas;
|
||||||
|
|
||||||
auto color() const { return self().color(); }
|
auto color() const { return self().color(); }
|
||||||
auto data() { return self().data(); }
|
auto data() { return self().data(); }
|
||||||
|
@ -237,6 +258,7 @@ struct Canvas : sCanvas {
|
||||||
#if defined(Hiro_CheckButton)
|
#if defined(Hiro_CheckButton)
|
||||||
struct CheckButton : sCheckButton {
|
struct CheckButton : sCheckButton {
|
||||||
DeclareSharedWidget(CheckButton)
|
DeclareSharedWidget(CheckButton)
|
||||||
|
using internalType = mCheckButton;
|
||||||
|
|
||||||
auto bordered() const { return self().bordered(); }
|
auto bordered() const { return self().bordered(); }
|
||||||
auto checked() const { return self().checked(); }
|
auto checked() const { return self().checked(); }
|
||||||
|
@ -256,6 +278,7 @@ struct CheckButton : sCheckButton {
|
||||||
#if defined(Hiro_CheckLabel)
|
#if defined(Hiro_CheckLabel)
|
||||||
struct CheckLabel : sCheckLabel {
|
struct CheckLabel : sCheckLabel {
|
||||||
DeclareSharedWidget(CheckLabel)
|
DeclareSharedWidget(CheckLabel)
|
||||||
|
using internalType = mCheckLabel;
|
||||||
|
|
||||||
auto checked() const { return self().checked(); }
|
auto checked() const { return self().checked(); }
|
||||||
auto doToggle() const { return self().doToggle(); }
|
auto doToggle() const { return self().doToggle(); }
|
||||||
|
@ -269,6 +292,7 @@ struct CheckLabel : sCheckLabel {
|
||||||
#if defined(Hiro_ComboButton)
|
#if defined(Hiro_ComboButton)
|
||||||
struct ComboButtonItem : sComboButtonItem {
|
struct ComboButtonItem : sComboButtonItem {
|
||||||
DeclareSharedObject(ComboButtonItem)
|
DeclareSharedObject(ComboButtonItem)
|
||||||
|
using internalType = mComboButtonItem;
|
||||||
|
|
||||||
auto image() const { return self().image(); }
|
auto image() const { return self().image(); }
|
||||||
auto selected() const { return self().selected(); }
|
auto selected() const { return self().selected(); }
|
||||||
|
@ -282,6 +306,7 @@ struct ComboButtonItem : sComboButtonItem {
|
||||||
#if defined(Hiro_ComboButton)
|
#if defined(Hiro_ComboButton)
|
||||||
struct ComboButton : sComboButton {
|
struct ComboButton : sComboButton {
|
||||||
DeclareSharedWidget(ComboButton)
|
DeclareSharedWidget(ComboButton)
|
||||||
|
using internalType = mComboButton;
|
||||||
|
|
||||||
auto append(sComboButtonItem item) { return self().append(item), *this; }
|
auto append(sComboButtonItem item) { return self().append(item), *this; }
|
||||||
auto doChange() const { return self().doChange(); }
|
auto doChange() const { return self().doChange(); }
|
||||||
|
@ -299,6 +324,7 @@ struct ComboButton : sComboButton {
|
||||||
#if defined(Hiro_Console)
|
#if defined(Hiro_Console)
|
||||||
struct Console : sConsole {
|
struct Console : sConsole {
|
||||||
DeclareSharedWidget(Console)
|
DeclareSharedWidget(Console)
|
||||||
|
using internalType = mConsole;
|
||||||
|
|
||||||
auto backgroundColor() const { return self().backgroundColor(); }
|
auto backgroundColor() const { return self().backgroundColor(); }
|
||||||
auto doActivate(string command) const { return self().doActivate(command); }
|
auto doActivate(string command) const { return self().doActivate(command); }
|
||||||
|
@ -316,6 +342,7 @@ struct Console : sConsole {
|
||||||
#if defined(Hiro_Frame)
|
#if defined(Hiro_Frame)
|
||||||
struct Frame : sFrame {
|
struct Frame : sFrame {
|
||||||
DeclareSharedWidget(Frame)
|
DeclareSharedWidget(Frame)
|
||||||
|
using internalType = mFrame;
|
||||||
|
|
||||||
auto append(sLayout layout) { return self().append(layout), *this; }
|
auto append(sLayout layout) { return self().append(layout), *this; }
|
||||||
auto layout() const { return self().layout(); }
|
auto layout() const { return self().layout(); }
|
||||||
|
@ -329,6 +356,7 @@ struct Frame : sFrame {
|
||||||
#if defined(Hiro_HexEdit)
|
#if defined(Hiro_HexEdit)
|
||||||
struct HexEdit : sHexEdit {
|
struct HexEdit : sHexEdit {
|
||||||
DeclareSharedWidget(HexEdit)
|
DeclareSharedWidget(HexEdit)
|
||||||
|
using internalType = mHexEdit;
|
||||||
|
|
||||||
auto address() const { return self().address(); }
|
auto address() const { return self().address(); }
|
||||||
auto backgroundColor() const { return self().backgroundColor(); }
|
auto backgroundColor() const { return self().backgroundColor(); }
|
||||||
|
@ -353,6 +381,7 @@ struct HexEdit : sHexEdit {
|
||||||
#if defined(Hiro_HorizontalScrollBar)
|
#if defined(Hiro_HorizontalScrollBar)
|
||||||
struct HorizontalScrollBar : sHorizontalScrollBar {
|
struct HorizontalScrollBar : sHorizontalScrollBar {
|
||||||
DeclareSharedWidget(HorizontalScrollBar)
|
DeclareSharedWidget(HorizontalScrollBar)
|
||||||
|
using internalType = mHorizontalScrollBar;
|
||||||
|
|
||||||
auto doChange() const { return self().doChange(); }
|
auto doChange() const { return self().doChange(); }
|
||||||
auto length() const { return self().length(); }
|
auto length() const { return self().length(); }
|
||||||
|
@ -366,6 +395,7 @@ struct HorizontalScrollBar : sHorizontalScrollBar {
|
||||||
#if defined(Hiro_HorizontalSlider)
|
#if defined(Hiro_HorizontalSlider)
|
||||||
struct HorizontalSlider : sHorizontalSlider {
|
struct HorizontalSlider : sHorizontalSlider {
|
||||||
DeclareSharedWidget(HorizontalSlider)
|
DeclareSharedWidget(HorizontalSlider)
|
||||||
|
using internalType = mHorizontalSlider;
|
||||||
|
|
||||||
auto doChange() const { return self().doChange(); }
|
auto doChange() const { return self().doChange(); }
|
||||||
auto length() const { return self().length(); }
|
auto length() const { return self().length(); }
|
||||||
|
@ -379,6 +409,7 @@ struct HorizontalSlider : sHorizontalSlider {
|
||||||
#if defined(Hiro_IconView)
|
#if defined(Hiro_IconView)
|
||||||
struct IconViewItem : sIconViewItem {
|
struct IconViewItem : sIconViewItem {
|
||||||
DeclareSharedObject(IconViewItem)
|
DeclareSharedObject(IconViewItem)
|
||||||
|
using internalType = mIconViewItem;
|
||||||
|
|
||||||
auto image() const { return self().image(); }
|
auto image() const { return self().image(); }
|
||||||
auto selected() const { return self().selected(); }
|
auto selected() const { return self().selected(); }
|
||||||
|
@ -392,6 +423,7 @@ struct IconViewItem : sIconViewItem {
|
||||||
#if defined(Hiro_IconView)
|
#if defined(Hiro_IconView)
|
||||||
struct IconView : sIconView {
|
struct IconView : sIconView {
|
||||||
DeclareSharedWidget(IconView)
|
DeclareSharedWidget(IconView)
|
||||||
|
using internalType = mIconView;
|
||||||
|
|
||||||
auto append(sIconViewItem item) { return self().append(item), *this; }
|
auto append(sIconViewItem item) { return self().append(item), *this; }
|
||||||
auto backgroundColor() const { return self().backgroundColor(); }
|
auto backgroundColor() const { return self().backgroundColor(); }
|
||||||
|
@ -424,6 +456,7 @@ struct IconView : sIconView {
|
||||||
#if defined(Hiro_Label)
|
#if defined(Hiro_Label)
|
||||||
struct Label : sLabel {
|
struct Label : sLabel {
|
||||||
DeclareSharedWidget(Label)
|
DeclareSharedWidget(Label)
|
||||||
|
using internalType = mLabel;
|
||||||
|
|
||||||
auto alignment() const { return self().alignment(); }
|
auto alignment() const { return self().alignment(); }
|
||||||
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
|
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
|
||||||
|
@ -435,6 +468,7 @@ struct Label : sLabel {
|
||||||
#if defined(Hiro_LineEdit)
|
#if defined(Hiro_LineEdit)
|
||||||
struct LineEdit : sLineEdit {
|
struct LineEdit : sLineEdit {
|
||||||
DeclareSharedWidget(LineEdit)
|
DeclareSharedWidget(LineEdit)
|
||||||
|
using internalType = mLineEdit;
|
||||||
|
|
||||||
auto backgroundColor() const { return self().backgroundColor(); }
|
auto backgroundColor() const { return self().backgroundColor(); }
|
||||||
auto doActivate() const { return self().doActivate(); }
|
auto doActivate() const { return self().doActivate(); }
|
||||||
|
@ -454,6 +488,7 @@ struct LineEdit : sLineEdit {
|
||||||
#if defined(Hiro_ListView)
|
#if defined(Hiro_ListView)
|
||||||
struct ListViewColumn : sListViewColumn {
|
struct ListViewColumn : sListViewColumn {
|
||||||
DeclareSharedObject(ListViewColumn)
|
DeclareSharedObject(ListViewColumn)
|
||||||
|
using internalType = mListViewColumn;
|
||||||
|
|
||||||
auto active() const { return self().active(); }
|
auto active() const { return self().active(); }
|
||||||
auto alignment() const { return self().alignment(); }
|
auto alignment() const { return self().alignment(); }
|
||||||
|
@ -485,6 +520,7 @@ struct ListViewColumn : sListViewColumn {
|
||||||
#if defined(Hiro_ListView)
|
#if defined(Hiro_ListView)
|
||||||
struct ListViewHeader : sListViewHeader {
|
struct ListViewHeader : sListViewHeader {
|
||||||
DeclareSharedObject(ListViewHeader)
|
DeclareSharedObject(ListViewHeader)
|
||||||
|
using internalType = mListViewHeader;
|
||||||
|
|
||||||
auto append(sListViewColumn column) { return self().append(column), *this; }
|
auto append(sListViewColumn column) { return self().append(column), *this; }
|
||||||
auto column(unsigned position) const { return self().column(position); }
|
auto column(unsigned position) const { return self().column(position); }
|
||||||
|
@ -497,6 +533,7 @@ struct ListViewHeader : sListViewHeader {
|
||||||
#if defined(Hiro_ListView)
|
#if defined(Hiro_ListView)
|
||||||
struct ListViewCell : sListViewCell {
|
struct ListViewCell : sListViewCell {
|
||||||
DeclareSharedObject(ListViewCell)
|
DeclareSharedObject(ListViewCell)
|
||||||
|
using internalType = mListViewCell;
|
||||||
|
|
||||||
auto alignment() const { return self().alignment(); }
|
auto alignment() const { return self().alignment(); }
|
||||||
auto backgroundColor() const { return self().backgroundColor(); }
|
auto backgroundColor() const { return self().backgroundColor(); }
|
||||||
|
@ -518,6 +555,7 @@ struct ListViewCell : sListViewCell {
|
||||||
#if defined(Hiro_ListView)
|
#if defined(Hiro_ListView)
|
||||||
struct ListViewItem : sListViewItem {
|
struct ListViewItem : sListViewItem {
|
||||||
DeclareSharedObject(ListViewItem)
|
DeclareSharedObject(ListViewItem)
|
||||||
|
using internalType = mListViewItem;
|
||||||
|
|
||||||
auto alignment() const { return self().alignment(); }
|
auto alignment() const { return self().alignment(); }
|
||||||
auto append(sListViewCell cell) { return self().append(cell), *this; }
|
auto append(sListViewCell cell) { return self().append(cell), *this; }
|
||||||
|
@ -538,6 +576,7 @@ struct ListViewItem : sListViewItem {
|
||||||
#if defined(Hiro_ListView)
|
#if defined(Hiro_ListView)
|
||||||
struct ListView : sListView {
|
struct ListView : sListView {
|
||||||
DeclareSharedWidget(ListView)
|
DeclareSharedWidget(ListView)
|
||||||
|
using internalType = mListView;
|
||||||
|
|
||||||
auto alignment() const { return self().alignment(); }
|
auto alignment() const { return self().alignment(); }
|
||||||
auto append(sListViewHeader header) { return self().append(header), *this; }
|
auto append(sListViewHeader header) { return self().append(header), *this; }
|
||||||
|
@ -579,6 +618,7 @@ struct ListView : sListView {
|
||||||
#if defined(Hiro_ProgressBar)
|
#if defined(Hiro_ProgressBar)
|
||||||
struct ProgressBar : sProgressBar {
|
struct ProgressBar : sProgressBar {
|
||||||
DeclareSharedWidget(ProgressBar)
|
DeclareSharedWidget(ProgressBar)
|
||||||
|
using internalType = mProgressBar;
|
||||||
|
|
||||||
auto position() const { return self().position(); }
|
auto position() const { return self().position(); }
|
||||||
auto setPosition(unsigned position = 0) { return self().setPosition(position), *this; }
|
auto setPosition(unsigned position = 0) { return self().setPosition(position), *this; }
|
||||||
|
@ -624,6 +664,7 @@ struct RadioLabel : sRadioLabel {
|
||||||
#if defined(Hiro_SourceEdit)
|
#if defined(Hiro_SourceEdit)
|
||||||
struct SourceEdit : sSourceEdit {
|
struct SourceEdit : sSourceEdit {
|
||||||
DeclareSharedWidget(SourceEdit)
|
DeclareSharedWidget(SourceEdit)
|
||||||
|
using internalType = mSourceEdit;
|
||||||
|
|
||||||
auto cursor() const { return self().cursor(); }
|
auto cursor() const { return self().cursor(); }
|
||||||
auto doChange() const { return self().doChange(); }
|
auto doChange() const { return self().doChange(); }
|
||||||
|
@ -639,6 +680,7 @@ struct SourceEdit : sSourceEdit {
|
||||||
#if defined(Hiro_TabFrame)
|
#if defined(Hiro_TabFrame)
|
||||||
struct TabFrameItem : sTabFrameItem {
|
struct TabFrameItem : sTabFrameItem {
|
||||||
DeclareSharedObject(TabFrameItem)
|
DeclareSharedObject(TabFrameItem)
|
||||||
|
using internalType = mTabFrameItem;
|
||||||
|
|
||||||
auto append(sLayout layout) { return self().append(layout), *this; }
|
auto append(sLayout layout) { return self().append(layout), *this; }
|
||||||
auto closable() const { return self().closable(); }
|
auto closable() const { return self().closable(); }
|
||||||
|
@ -660,6 +702,7 @@ struct TabFrameItem : sTabFrameItem {
|
||||||
#if defined(Hiro_TabFrame)
|
#if defined(Hiro_TabFrame)
|
||||||
struct TabFrame : sTabFrame {
|
struct TabFrame : sTabFrame {
|
||||||
DeclareSharedWidget(TabFrame)
|
DeclareSharedWidget(TabFrame)
|
||||||
|
using internalType = mTabFrame;
|
||||||
|
|
||||||
auto append(sTabFrameItem item) { return self().append(item), *this; }
|
auto append(sTabFrameItem item) { return self().append(item), *this; }
|
||||||
auto doChange() const { return self().doChange(); }
|
auto doChange() const { return self().doChange(); }
|
||||||
|
@ -682,6 +725,7 @@ struct TabFrame : sTabFrame {
|
||||||
#if defined(Hiro_TextEdit)
|
#if defined(Hiro_TextEdit)
|
||||||
struct TextEdit : sTextEdit {
|
struct TextEdit : sTextEdit {
|
||||||
DeclareSharedWidget(TextEdit)
|
DeclareSharedWidget(TextEdit)
|
||||||
|
using internalType = mTextEdit;
|
||||||
|
|
||||||
auto backgroundColor() const { return self().backgroundColor(); }
|
auto backgroundColor() const { return self().backgroundColor(); }
|
||||||
auto cursor() const { return self().cursor(); }
|
auto cursor() const { return self().cursor(); }
|
||||||
|
@ -705,6 +749,7 @@ struct TextEdit : sTextEdit {
|
||||||
#if defined(Hiro_TreeView)
|
#if defined(Hiro_TreeView)
|
||||||
struct TreeViewItem : sTreeViewItem {
|
struct TreeViewItem : sTreeViewItem {
|
||||||
DeclareSharedObject(TreeViewItem)
|
DeclareSharedObject(TreeViewItem)
|
||||||
|
using internalType = mTreeViewItem;
|
||||||
|
|
||||||
auto append(sTreeViewItem item) { return self().append(item), *this; }
|
auto append(sTreeViewItem item) { return self().append(item), *this; }
|
||||||
auto backgroundColor() const { return self().backgroundColor(); }
|
auto backgroundColor() const { return self().backgroundColor(); }
|
||||||
|
@ -733,6 +778,7 @@ struct TreeViewItem : sTreeViewItem {
|
||||||
#if defined(Hiro_TreeView)
|
#if defined(Hiro_TreeView)
|
||||||
struct TreeView : sTreeView {
|
struct TreeView : sTreeView {
|
||||||
DeclareSharedWidget(TreeView)
|
DeclareSharedWidget(TreeView)
|
||||||
|
using internalType = mTreeView;
|
||||||
|
|
||||||
auto append(sTreeViewItem item) { return self().append(item), *this; }
|
auto append(sTreeViewItem item) { return self().append(item), *this; }
|
||||||
auto backgroundColor() const { return self().backgroundColor(); }
|
auto backgroundColor() const { return self().backgroundColor(); }
|
||||||
|
@ -759,6 +805,7 @@ struct TreeView : sTreeView {
|
||||||
#if defined(Hiro_VerticalScrollBar)
|
#if defined(Hiro_VerticalScrollBar)
|
||||||
struct VerticalScrollBar : sVerticalScrollBar {
|
struct VerticalScrollBar : sVerticalScrollBar {
|
||||||
DeclareSharedWidget(VerticalScrollBar)
|
DeclareSharedWidget(VerticalScrollBar)
|
||||||
|
using internalType = mVerticalScrollBar;
|
||||||
|
|
||||||
auto doChange() const { return self().doChange(); }
|
auto doChange() const { return self().doChange(); }
|
||||||
auto length() const { return self().length(); }
|
auto length() const { return self().length(); }
|
||||||
|
@ -772,6 +819,7 @@ struct VerticalScrollBar : sVerticalScrollBar {
|
||||||
#if defined(Hiro_VerticalSlider)
|
#if defined(Hiro_VerticalSlider)
|
||||||
struct VerticalSlider : sVerticalSlider {
|
struct VerticalSlider : sVerticalSlider {
|
||||||
DeclareSharedWidget(VerticalSlider)
|
DeclareSharedWidget(VerticalSlider)
|
||||||
|
using internalType = mVerticalSlider;
|
||||||
|
|
||||||
auto doChange() const { return self().doChange(); }
|
auto doChange() const { return self().doChange(); }
|
||||||
auto length() const { return self().length(); }
|
auto length() const { return self().length(); }
|
||||||
|
@ -785,6 +833,7 @@ struct VerticalSlider : sVerticalSlider {
|
||||||
#if defined(Hiro_Viewport)
|
#if defined(Hiro_Viewport)
|
||||||
struct Viewport : sViewport {
|
struct Viewport : sViewport {
|
||||||
DeclareSharedWidget(Viewport)
|
DeclareSharedWidget(Viewport)
|
||||||
|
using internalType = mViewport;
|
||||||
|
|
||||||
auto doDrop(lstring names) const { return self().doDrop(names); }
|
auto doDrop(lstring names) const { return self().doDrop(names); }
|
||||||
auto doMouseLeave() const { return self().doMouseLeave(); }
|
auto doMouseLeave() const { return self().doMouseLeave(); }
|
||||||
|
@ -805,6 +854,7 @@ struct Viewport : sViewport {
|
||||||
#if defined(Hiro_StatusBar)
|
#if defined(Hiro_StatusBar)
|
||||||
struct StatusBar : sStatusBar {
|
struct StatusBar : sStatusBar {
|
||||||
DeclareSharedObject(StatusBar)
|
DeclareSharedObject(StatusBar)
|
||||||
|
using internalType = mStatusBar;
|
||||||
|
|
||||||
auto setText(const string& text = "") { return self().setText(text), *this; }
|
auto setText(const string& text = "") { return self().setText(text), *this; }
|
||||||
auto text() const { return self().text(); }
|
auto text() const { return self().text(); }
|
||||||
|
@ -814,6 +864,7 @@ struct StatusBar : sStatusBar {
|
||||||
#if defined(Hiro_PopupMenu)
|
#if defined(Hiro_PopupMenu)
|
||||||
struct PopupMenu : sPopupMenu {
|
struct PopupMenu : sPopupMenu {
|
||||||
DeclareSharedObject(PopupMenu)
|
DeclareSharedObject(PopupMenu)
|
||||||
|
using internalType = mPopupMenu;
|
||||||
|
|
||||||
auto action(unsigned position) const { return self().action(position); }
|
auto action(unsigned position) const { return self().action(position); }
|
||||||
auto actionCount() const { return self().actionCount(); }
|
auto actionCount() const { return self().actionCount(); }
|
||||||
|
@ -827,6 +878,7 @@ struct PopupMenu : sPopupMenu {
|
||||||
#if defined(Hiro_MenuBar)
|
#if defined(Hiro_MenuBar)
|
||||||
struct MenuBar : sMenuBar {
|
struct MenuBar : sMenuBar {
|
||||||
DeclareSharedObject(MenuBar)
|
DeclareSharedObject(MenuBar)
|
||||||
|
using internalType = mMenuBar;
|
||||||
|
|
||||||
auto append(sMenu menu) { return self().append(menu), *this; }
|
auto append(sMenu menu) { return self().append(menu), *this; }
|
||||||
auto menu(unsigned position) const { return self().menu(position); }
|
auto menu(unsigned position) const { return self().menu(position); }
|
||||||
|
@ -840,6 +892,7 @@ struct MenuBar : sMenuBar {
|
||||||
#if defined(Hiro_Window)
|
#if defined(Hiro_Window)
|
||||||
struct Window : sWindow {
|
struct Window : sWindow {
|
||||||
DeclareSharedObject(Window)
|
DeclareSharedObject(Window)
|
||||||
|
using internalType = mWindow;
|
||||||
|
|
||||||
auto append(sLayout layout) { return self().append(layout), *this; }
|
auto append(sLayout layout) { return self().append(layout), *this; }
|
||||||
auto append(sMenuBar menuBar) { return self().append(menuBar), *this; }
|
auto append(sMenuBar menuBar) { return self().append(menuBar), *this; }
|
||||||
|
|
|
@ -189,7 +189,6 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(view.items()) view.item(0)->setSelected();
|
|
||||||
Application::processEvents();
|
Application::processEvents();
|
||||||
view.resizeColumns().setFocused().doChange();
|
view.resizeColumns().setFocused().doChange();
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,8 @@ auto mHorizontalLayout::setGeometry(Geometry containerGeometry) -> type& {
|
||||||
geometry.setX (geometry.x() + child.width + child.spacing);
|
geometry.setX (geometry.x() + child.width + child.spacing);
|
||||||
geometry.setWidth(geometry.width() - child.width + child.spacing);
|
geometry.setWidth(geometry.width() - child.width + child.spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mHorizontalLayout::setMargin(signed margin) -> type& {
|
auto mHorizontalLayout::setMargin(signed margin) -> type& {
|
||||||
|
|
|
@ -119,7 +119,13 @@ auto pListView::setBordered(bool bordered) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pListView::setFocused() -> void {
|
auto pListView::setFocused() -> void {
|
||||||
|
//gtk_widget_grab_focus() will select the first item if nothing is currently selected
|
||||||
|
//this behavior is undesirable. detect selection state first, and restore if required
|
||||||
|
lock();
|
||||||
|
bool selected = gtk_tree_selection_get_selected(gtkTreeSelection, nullptr, nullptr);
|
||||||
gtk_widget_grab_focus(gtkWidgetChild);
|
gtk_widget_grab_focus(gtkWidgetChild);
|
||||||
|
if(!selected) gtk_tree_selection_unselect_all(gtkTreeSelection);
|
||||||
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pListView::setFont(const Font& font) -> void {
|
auto pListView::setFont(const Font& font) -> void {
|
||||||
|
|
|
@ -79,6 +79,16 @@ auto pTreeView::setBackgroundColor(Color color) -> void {
|
||||||
gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
|
gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto pTreeView::setFocused() -> void {
|
||||||
|
//gtk_widget_grab_focus() will select the first item if nothing is currently selected
|
||||||
|
//this behavior is undesirable. detect selection state first, and restore if required
|
||||||
|
lock();
|
||||||
|
bool selected = gtk_tree_selection_get_selected(gtkTreeSelection, nullptr, nullptr);
|
||||||
|
gtk_widget_grab_focus(gtkWidgetChild);
|
||||||
|
if(!selected) gtk_tree_selection_unselect_all(gtkTreeSelection);
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
auto pTreeView::setForegroundColor(Color color) -> void {
|
auto pTreeView::setForegroundColor(Color color) -> void {
|
||||||
auto gdkColor = CreateColor(color);
|
auto gdkColor = CreateColor(color);
|
||||||
gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
|
gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
|
||||||
|
|
|
@ -8,6 +8,7 @@ struct pTreeView : pWidget {
|
||||||
auto append(sTreeViewItem item) -> void;
|
auto append(sTreeViewItem item) -> void;
|
||||||
auto remove(sTreeViewItem item) -> void;
|
auto remove(sTreeViewItem item) -> void;
|
||||||
auto setBackgroundColor(Color color) -> void;
|
auto setBackgroundColor(Color color) -> void;
|
||||||
|
auto setFocused() -> void override;
|
||||||
auto setForegroundColor(Color color) -> void;
|
auto setForegroundColor(Color color) -> void;
|
||||||
|
|
||||||
auto _activatePath(GtkTreePath* gtkPath) -> void;
|
auto _activatePath(GtkTreePath* gtkPath) -> void;
|
||||||
|
|
|
@ -9,70 +9,70 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct bpsdelta {
|
struct bpsdelta {
|
||||||
inline void source(const uint8_t* data, unsigned size);
|
inline auto source(const uint8* data, uint size) -> void;
|
||||||
inline void target(const uint8_t* data, unsigned size);
|
inline auto target(const uint8* data, uint size) -> void;
|
||||||
|
|
||||||
inline bool source(const string& filename);
|
inline auto source(const string& filename) -> bool;
|
||||||
inline bool target(const string& filename);
|
inline auto target(const string& filename) -> bool;
|
||||||
inline bool create(const string& filename, const string& metadata = "");
|
inline auto create(const string& filename, const string& metadata = "") -> bool;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||||
enum : unsigned { Granularity = 1 };
|
enum : uint { Granularity = 1 };
|
||||||
|
|
||||||
struct Node {
|
struct Node {
|
||||||
unsigned offset = 0;
|
|
||||||
Node* next = nullptr;
|
|
||||||
Node() = default;
|
Node() = default;
|
||||||
~Node() { if(next) delete next; }
|
~Node() { if(next) delete next; }
|
||||||
|
uint offset = 0;
|
||||||
|
Node* next = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
filemap sourceFile;
|
filemap sourceFile;
|
||||||
const uint8_t* sourceData;
|
const uint8* sourceData;
|
||||||
unsigned sourceSize;
|
uint sourceSize;
|
||||||
|
|
||||||
filemap targetFile;
|
filemap targetFile;
|
||||||
const uint8_t* targetData;
|
const uint8* targetData;
|
||||||
unsigned targetSize;
|
uint targetSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
void bpsdelta::source(const uint8_t* data, unsigned size) {
|
auto bpsdelta::source(const uint8* data, uint size) -> void {
|
||||||
sourceData = data;
|
sourceData = data;
|
||||||
sourceSize = size;
|
sourceSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bpsdelta::target(const uint8_t* data, unsigned size) {
|
auto bpsdelta::target(const uint8* data, uint size) -> void {
|
||||||
targetData = data;
|
targetData = data;
|
||||||
targetSize = size;
|
targetSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpsdelta::source(const string& filename) {
|
auto bpsdelta::source(const string& filename) -> bool {
|
||||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
||||||
source(sourceFile.data(), sourceFile.size());
|
source(sourceFile.data(), sourceFile.size());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpsdelta::target(const string& filename) {
|
auto bpsdelta::target(const string& filename) -> bool {
|
||||||
if(targetFile.open(filename, filemap::mode::read) == false) return false;
|
if(targetFile.open(filename, filemap::mode::read) == false) return false;
|
||||||
target(targetFile.data(), targetFile.size());
|
target(targetFile.data(), targetFile.size());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpsdelta::create(const string& filename, const string& metadata) {
|
auto bpsdelta::create(const string& filename, const string& metadata) -> bool {
|
||||||
file modifyFile;
|
file modifyFile;
|
||||||
if(modifyFile.open(filename, file::mode::write) == false) return false;
|
if(modifyFile.open(filename, file::mode::write) == false) return false;
|
||||||
|
|
||||||
Hash::CRC32 sourceChecksum, modifyChecksum;
|
Hash::CRC32 sourceChecksum, modifyChecksum;
|
||||||
unsigned sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
uint sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
||||||
|
|
||||||
auto write = [&](uint8_t data) {
|
auto write = [&](uint8 data) {
|
||||||
modifyFile.write(data);
|
modifyFile.write(data);
|
||||||
modifyChecksum.data(data);
|
modifyChecksum.data(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto encode = [&](uint64_t data) {
|
auto encode = [&](uint64 data) {
|
||||||
while(true) {
|
while(true) {
|
||||||
uint64_t x = data & 0x7f;
|
uint64 x = data & 0x7f;
|
||||||
data >>= 7;
|
data >>= 7;
|
||||||
if(data == 0) {
|
if(data == 0) {
|
||||||
write(0x80 | x);
|
write(0x80 | x);
|
||||||
|
@ -91,17 +91,17 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
||||||
encode(sourceSize);
|
encode(sourceSize);
|
||||||
encode(targetSize);
|
encode(targetSize);
|
||||||
|
|
||||||
unsigned markupSize = metadata.length();
|
uint markupSize = metadata.length();
|
||||||
encode(markupSize);
|
encode(markupSize);
|
||||||
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
|
for(uint n = 0; n < markupSize; n++) write(metadata[n]);
|
||||||
|
|
||||||
Node* sourceTree[65536];
|
Node* sourceTree[65536];
|
||||||
Node* targetTree[65536];
|
Node* targetTree[65536];
|
||||||
for(unsigned n = 0; n < 65536; n++) sourceTree[n] = nullptr, targetTree[n] = nullptr;
|
for(uint n = 0; n < 65536; n++) sourceTree[n] = nullptr, targetTree[n] = nullptr;
|
||||||
|
|
||||||
//source tree creation
|
//source tree creation
|
||||||
for(unsigned offset = 0; offset < sourceSize; offset++) {
|
for(uint offset = 0; offset < sourceSize; offset++) {
|
||||||
uint16_t symbol = sourceData[offset + 0];
|
uint16 symbol = sourceData[offset + 0];
|
||||||
sourceChecksum.data(symbol);
|
sourceChecksum.data(symbol);
|
||||||
if(offset < sourceSize - 1) symbol |= sourceData[offset + 1] << 8;
|
if(offset < sourceSize - 1) symbol |= sourceData[offset + 1] << 8;
|
||||||
Node *node = new Node;
|
Node *node = new Node;
|
||||||
|
@ -110,24 +110,24 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
||||||
sourceTree[symbol] = node;
|
sourceTree[symbol] = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned targetReadLength = 0;
|
uint targetReadLength = 0;
|
||||||
|
|
||||||
auto targetReadFlush = [&]() {
|
auto targetReadFlush = [&]() {
|
||||||
if(targetReadLength) {
|
if(targetReadLength) {
|
||||||
encode(TargetRead | ((targetReadLength - 1) << 2));
|
encode(TargetRead | ((targetReadLength - 1) << 2));
|
||||||
unsigned offset = outputOffset - targetReadLength;
|
uint offset = outputOffset - targetReadLength;
|
||||||
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
|
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
while(outputOffset < targetSize) {
|
while(outputOffset < targetSize) {
|
||||||
unsigned maxLength = 0, maxOffset = 0, mode = TargetRead;
|
uint maxLength = 0, maxOffset = 0, mode = TargetRead;
|
||||||
|
|
||||||
uint16_t symbol = targetData[outputOffset + 0];
|
uint16 symbol = targetData[outputOffset + 0];
|
||||||
if(outputOffset < targetSize - 1) symbol |= targetData[outputOffset + 1] << 8;
|
if(outputOffset < targetSize - 1) symbol |= targetData[outputOffset + 1] << 8;
|
||||||
|
|
||||||
{ //source read
|
{ //source read
|
||||||
unsigned length = 0, offset = outputOffset;
|
uint length = 0, offset = outputOffset;
|
||||||
while(offset < sourceSize && offset < targetSize && sourceData[offset] == targetData[offset]) {
|
while(offset < sourceSize && offset < targetSize && sourceData[offset] == targetData[offset]) {
|
||||||
length++;
|
length++;
|
||||||
offset++;
|
offset++;
|
||||||
|
@ -138,7 +138,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
||||||
{ //source copy
|
{ //source copy
|
||||||
Node* node = sourceTree[symbol];
|
Node* node = sourceTree[symbol];
|
||||||
while(node) {
|
while(node) {
|
||||||
unsigned length = 0, x = node->offset, y = outputOffset;
|
uint length = 0, x = node->offset, y = outputOffset;
|
||||||
while(x < sourceSize && y < targetSize && sourceData[x++] == targetData[y++]) length++;
|
while(x < sourceSize && y < targetSize && sourceData[x++] == targetData[y++]) length++;
|
||||||
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = SourceCopy;
|
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = SourceCopy;
|
||||||
node = node->next;
|
node = node->next;
|
||||||
|
@ -148,7 +148,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
||||||
{ //target copy
|
{ //target copy
|
||||||
Node* node = targetTree[symbol];
|
Node* node = targetTree[symbol];
|
||||||
while(node) {
|
while(node) {
|
||||||
unsigned length = 0, x = node->offset, y = outputOffset;
|
uint length = 0, x = node->offset, y = outputOffset;
|
||||||
while(y < targetSize && targetData[x++] == targetData[y++]) length++;
|
while(y < targetSize && targetData[x++] == targetData[y++]) length++;
|
||||||
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = TargetCopy;
|
if(length > maxLength) maxLength = length, maxOffset = node->offset, mode = TargetCopy;
|
||||||
node = node->next;
|
node = node->next;
|
||||||
|
@ -163,7 +163,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
||||||
|
|
||||||
{ //target read
|
{ //target read
|
||||||
if(maxLength < 4) {
|
if(maxLength < 4) {
|
||||||
maxLength = min((unsigned)Granularity, targetSize - outputOffset);
|
maxLength = min((uint)Granularity, targetSize - outputOffset);
|
||||||
mode = TargetRead;
|
mode = TargetRead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
||||||
case SourceCopy:
|
case SourceCopy:
|
||||||
case TargetCopy:
|
case TargetCopy:
|
||||||
encode(mode | ((maxLength - 1) << 2));
|
encode(mode | ((maxLength - 1) << 2));
|
||||||
signed relativeOffset;
|
int relativeOffset;
|
||||||
if(mode == SourceCopy) {
|
if(mode == SourceCopy) {
|
||||||
relativeOffset = maxOffset - sourceRelativeOffset;
|
relativeOffset = maxOffset - sourceRelativeOffset;
|
||||||
sourceRelativeOffset = maxOffset + maxLength;
|
sourceRelativeOffset = maxOffset + maxLength;
|
||||||
|
@ -198,11 +198,11 @@ bool bpsdelta::create(const string& filename, const string& metadata) {
|
||||||
|
|
||||||
targetReadFlush();
|
targetReadFlush();
|
||||||
|
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum.value() >> n);
|
for(uint n = 0; n < 32; n += 8) write(sourceChecksum.value() >> n);
|
||||||
uint32_t targetChecksum = Hash::CRC32(targetData, targetSize).value();
|
uint32 targetChecksum = Hash::CRC32(targetData, targetSize).value();
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
for(uint n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
||||||
uint32_t outputChecksum = modifyChecksum.value();
|
uint32 outputChecksum = modifyChecksum.value();
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
for(uint n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||||
|
|
||||||
modifyFile.close();
|
modifyFile.close();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -9,63 +9,63 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct bpslinear {
|
struct bpslinear {
|
||||||
inline void source(const uint8_t* data, unsigned size);
|
inline auto source(const uint8* data, uint size) -> void;
|
||||||
inline void target(const uint8_t* data, unsigned size);
|
inline auto target(const uint8* data, uint size) -> void;
|
||||||
|
|
||||||
inline bool source(const string& filename);
|
inline auto source(const string& filename) -> bool;
|
||||||
inline bool target(const string& filename);
|
inline auto target(const string& filename) -> bool;
|
||||||
inline bool create(const string& filename, const string& metadata = "");
|
inline auto create(const string& filename, const string& metadata = "") -> bool;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||||
enum : unsigned { Granularity = 1 };
|
enum : uint { Granularity = 1 };
|
||||||
|
|
||||||
filemap sourceFile;
|
filemap sourceFile;
|
||||||
const uint8_t* sourceData;
|
const uint8* sourceData;
|
||||||
unsigned sourceSize;
|
uint sourceSize;
|
||||||
|
|
||||||
filemap targetFile;
|
filemap targetFile;
|
||||||
const uint8_t* targetData;
|
const uint8* targetData;
|
||||||
unsigned targetSize;
|
uint targetSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
void bpslinear::source(const uint8_t* data, unsigned size) {
|
auto bpslinear::source(const uint8* data, uint size) -> void {
|
||||||
sourceData = data;
|
sourceData = data;
|
||||||
sourceSize = size;
|
sourceSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bpslinear::target(const uint8_t* data, unsigned size) {
|
auto bpslinear::target(const uint8* data, uint size) -> void {
|
||||||
targetData = data;
|
targetData = data;
|
||||||
targetSize = size;
|
targetSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpslinear::source(const string& filename) {
|
auto bpslinear::source(const string& filename) -> bool {
|
||||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
||||||
source(sourceFile.data(), sourceFile.size());
|
source(sourceFile.data(), sourceFile.size());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpslinear::target(const string& filename) {
|
auto bpslinear::target(const string& filename) -> bool {
|
||||||
if(targetFile.open(filename, filemap::mode::read) == false) return false;
|
if(targetFile.open(filename, filemap::mode::read) == false) return false;
|
||||||
target(targetFile.data(), targetFile.size());
|
target(targetFile.data(), targetFile.size());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpslinear::create(const string& filename, const string& metadata) {
|
auto bpslinear::create(const string& filename, const string& metadata) -> bool {
|
||||||
file modifyFile;
|
file modifyFile;
|
||||||
if(modifyFile.open(filename, file::mode::write) == false) return false;
|
if(modifyFile.open(filename, file::mode::write) == false) return false;
|
||||||
|
|
||||||
Hash::CRC32 modifyChecksum;
|
Hash::CRC32 modifyChecksum;
|
||||||
unsigned targetRelativeOffset = 0, outputOffset = 0;
|
uint targetRelativeOffset = 0, outputOffset = 0;
|
||||||
|
|
||||||
auto write = [&](uint8_t data) {
|
auto write = [&](uint8 data) {
|
||||||
modifyFile.write(data);
|
modifyFile.write(data);
|
||||||
modifyChecksum.data(data);
|
modifyChecksum.data(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto encode = [&](uint64_t data) {
|
auto encode = [&](uint64 data) {
|
||||||
while(true) {
|
while(true) {
|
||||||
uint64_t x = data & 0x7f;
|
uint64 x = data & 0x7f;
|
||||||
data >>= 7;
|
data >>= 7;
|
||||||
if(data == 0) {
|
if(data == 0) {
|
||||||
write(0x80 | x);
|
write(0x80 | x);
|
||||||
|
@ -76,12 +76,12 @@ bool bpslinear::create(const string& filename, const string& metadata) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned targetReadLength = 0;
|
uint targetReadLength = 0;
|
||||||
|
|
||||||
auto targetReadFlush = [&]() {
|
auto targetReadFlush = [&]() {
|
||||||
if(targetReadLength) {
|
if(targetReadLength) {
|
||||||
encode(TargetRead | ((targetReadLength - 1) << 2));
|
encode(TargetRead | ((targetReadLength - 1) << 2));
|
||||||
unsigned offset = outputOffset - targetReadLength;
|
uint offset = outputOffset - targetReadLength;
|
||||||
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
|
while(targetReadLength) write(targetData[offset++]), targetReadLength--;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -94,19 +94,19 @@ bool bpslinear::create(const string& filename, const string& metadata) {
|
||||||
encode(sourceSize);
|
encode(sourceSize);
|
||||||
encode(targetSize);
|
encode(targetSize);
|
||||||
|
|
||||||
unsigned markupSize = metadata.length();
|
uint markupSize = metadata.length();
|
||||||
encode(markupSize);
|
encode(markupSize);
|
||||||
for(unsigned n = 0; n < markupSize; n++) write(metadata[n]);
|
for(uint n = 0; n < markupSize; n++) write(metadata[n]);
|
||||||
|
|
||||||
while(outputOffset < targetSize) {
|
while(outputOffset < targetSize) {
|
||||||
unsigned sourceLength = 0;
|
uint sourceLength = 0;
|
||||||
for(unsigned n = 0; outputOffset + n < min(sourceSize, targetSize); n++) {
|
for(uint n = 0; outputOffset + n < min(sourceSize, targetSize); n++) {
|
||||||
if(sourceData[outputOffset + n] != targetData[outputOffset + n]) break;
|
if(sourceData[outputOffset + n] != targetData[outputOffset + n]) break;
|
||||||
sourceLength++;
|
sourceLength++;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned rleLength = 0;
|
uint rleLength = 0;
|
||||||
for(unsigned n = 1; outputOffset + n < targetSize; n++) {
|
for(uint n = 1; outputOffset + n < targetSize; n++) {
|
||||||
if(targetData[outputOffset] != targetData[outputOffset + n]) break;
|
if(targetData[outputOffset] != targetData[outputOffset + n]) break;
|
||||||
rleLength++;
|
rleLength++;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ bool bpslinear::create(const string& filename, const string& metadata) {
|
||||||
|
|
||||||
//copy starting from repetition byte
|
//copy starting from repetition byte
|
||||||
encode(TargetCopy | ((rleLength - 1) << 2));
|
encode(TargetCopy | ((rleLength - 1) << 2));
|
||||||
unsigned relativeOffset = (outputOffset - 1) - targetRelativeOffset;
|
uint relativeOffset = (outputOffset - 1) - targetRelativeOffset;
|
||||||
encode(relativeOffset << 1);
|
encode(relativeOffset << 1);
|
||||||
outputOffset += rleLength;
|
outputOffset += rleLength;
|
||||||
targetRelativeOffset = outputOffset - 1;
|
targetRelativeOffset = outputOffset - 1;
|
||||||
|
@ -135,12 +135,12 @@ bool bpslinear::create(const string& filename, const string& metadata) {
|
||||||
|
|
||||||
targetReadFlush();
|
targetReadFlush();
|
||||||
|
|
||||||
uint32_t sourceChecksum = Hash::CRC32(sourceData, sourceSize).value();
|
uint32 sourceChecksum = Hash::CRC32(sourceData, sourceSize).value();
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n);
|
for(uint n = 0; n < 32; n += 8) write(sourceChecksum >> n);
|
||||||
uint32_t targetChecksum = Hash::CRC32(targetData, targetSize).value();
|
uint32 targetChecksum = Hash::CRC32(targetData, targetSize).value();
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
for(uint n = 0; n < 32; n += 8) write(targetChecksum >> n);
|
||||||
uint32_t outputChecksum = modifyChecksum.value();
|
uint32 outputChecksum = modifyChecksum.value();
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
for(uint n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||||
|
|
||||||
modifyFile.close();
|
modifyFile.close();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -9,26 +9,26 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct bpsmetadata {
|
struct bpsmetadata {
|
||||||
inline bool load(const string& filename);
|
inline auto load(const string& filename) -> bool;
|
||||||
inline bool save(const string& filename, const string& metadata);
|
inline auto save(const string& filename, const string& metadata) -> bool;
|
||||||
inline string metadata() const;
|
inline auto metadata() const -> string;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
file sourceFile;
|
file sourceFile;
|
||||||
string metadataString;
|
string metadataString;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool bpsmetadata::load(const string& filename) {
|
auto bpsmetadata::load(const string& filename) -> bool {
|
||||||
if(sourceFile.open(filename, file::mode::read) == false) return false;
|
if(sourceFile.open(filename, file::mode::read) == false) return false;
|
||||||
|
|
||||||
auto read = [&]() -> uint8_t {
|
auto read = [&]() -> uint8_t {
|
||||||
return sourceFile.read();
|
return sourceFile.read();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto decode = [&]() -> uint64_t {
|
auto decode = [&]() -> uint64 {
|
||||||
uint64_t data = 0, shift = 1;
|
uint64 data = 0, shift = 1;
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = read();
|
uint8 x = read();
|
||||||
data += (x & 0x7f) * shift;
|
data += (x & 0x7f) * shift;
|
||||||
if(x & 0x80) break;
|
if(x & 0x80) break;
|
||||||
shift <<= 7;
|
shift <<= 7;
|
||||||
|
@ -43,29 +43,29 @@ bool bpsmetadata::load(const string& filename) {
|
||||||
if(read() != '1') return false;
|
if(read() != '1') return false;
|
||||||
decode();
|
decode();
|
||||||
decode();
|
decode();
|
||||||
unsigned metadataSize = decode();
|
uint metadataSize = decode();
|
||||||
char data[metadataSize + 1];
|
char data[metadataSize + 1];
|
||||||
for(unsigned n = 0; n < metadataSize; n++) data[n] = read();
|
for(uint n = 0; n < metadataSize; n++) data[n] = read();
|
||||||
data[metadataSize] = 0;
|
data[metadataSize] = 0;
|
||||||
metadataString = (const char*)data;
|
metadataString = (const char*)data;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpsmetadata::save(const string& filename, const string& metadata) {
|
auto bpsmetadata::save(const string& filename, const string& metadata) -> bool {
|
||||||
file targetFile;
|
file targetFile;
|
||||||
if(targetFile.open(filename, file::mode::write) == false) return false;
|
if(targetFile.open(filename, file::mode::write) == false) return false;
|
||||||
if(sourceFile.open() == false) return false;
|
if(sourceFile.open() == false) return false;
|
||||||
sourceFile.seek(0);
|
sourceFile.seek(0);
|
||||||
|
|
||||||
auto read = [&]() -> uint8_t {
|
auto read = [&]() -> uint8 {
|
||||||
return sourceFile.read();
|
return sourceFile.read();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto decode = [&]() -> uint64_t {
|
auto decode = [&]() -> uint64 {
|
||||||
uint64_t data = 0, shift = 1;
|
uint64 data = 0, shift = 1;
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = read();
|
uint8 x = read();
|
||||||
data += (x & 0x7f) * shift;
|
data += (x & 0x7f) * shift;
|
||||||
if(x & 0x80) break;
|
if(x & 0x80) break;
|
||||||
shift <<= 7;
|
shift <<= 7;
|
||||||
|
@ -76,14 +76,14 @@ bool bpsmetadata::save(const string& filename, const string& metadata) {
|
||||||
|
|
||||||
Hash::CRC32 checksum;
|
Hash::CRC32 checksum;
|
||||||
|
|
||||||
auto write = [&](uint8_t data) {
|
auto write = [&](uint8 data) {
|
||||||
targetFile.write(data);
|
targetFile.write(data);
|
||||||
checksum.data(data);
|
checksum.data(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto encode = [&](uint64_t data) {
|
auto encode = [&](uint64 data) {
|
||||||
while(true) {
|
while(true) {
|
||||||
uint64_t x = data & 0x7f;
|
uint64 x = data & 0x7f;
|
||||||
data >>= 7;
|
data >>= 7;
|
||||||
if(data == 0) {
|
if(data == 0) {
|
||||||
write(0x80 | x);
|
write(0x80 | x);
|
||||||
|
@ -94,24 +94,24 @@ bool bpsmetadata::save(const string& filename, const string& metadata) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for(unsigned n = 0; n < 4; n++) write(read());
|
for(uint n = 0; n < 4; n++) write(read());
|
||||||
encode(decode());
|
encode(decode());
|
||||||
encode(decode());
|
encode(decode());
|
||||||
unsigned sourceLength = decode();
|
uint sourceLength = decode();
|
||||||
unsigned targetLength = metadata.length();
|
uint targetLength = metadata.length();
|
||||||
encode(targetLength);
|
encode(targetLength);
|
||||||
sourceFile.seek(sourceLength, file::index::relative);
|
sourceFile.seek(sourceLength, file::index::relative);
|
||||||
for(unsigned n = 0; n < targetLength; n++) write(metadata[n]);
|
for(uint n = 0; n < targetLength; n++) write(metadata[n]);
|
||||||
unsigned length = sourceFile.size() - sourceFile.offset() - 4;
|
uint length = sourceFile.size() - sourceFile.offset() - 4;
|
||||||
for(unsigned n = 0; n < length; n++) write(read());
|
for(uint n = 0; n < length; n++) write(read());
|
||||||
uint32_t outputChecksum = checksum.value();
|
uint32 outputChecksum = checksum.value();
|
||||||
for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
for(uint n = 0; n < 32; n += 8) write(outputChecksum >> n);
|
||||||
|
|
||||||
targetFile.close();
|
targetFile.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string bpsmetadata::metadata() const {
|
auto bpsmetadata::metadata() const -> string {
|
||||||
return metadataString;
|
return metadataString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,19 +8,19 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct bpsmulti {
|
struct bpsmulti {
|
||||||
enum : unsigned {
|
enum : uint {
|
||||||
CreatePath = 0,
|
CreatePath = 0,
|
||||||
CreateFile = 1,
|
CreateFile = 1,
|
||||||
ModifyFile = 2,
|
ModifyFile = 2,
|
||||||
MirrorFile = 3,
|
MirrorFile = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum : unsigned {
|
enum : uint {
|
||||||
OriginSource = 0,
|
OriginSource = 0,
|
||||||
OriginTarget = 1,
|
OriginTarget = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool create(const string& patchName, const string& sourcePath, const string& targetPath, bool delta = false, const string& metadata = "") {
|
auto create(const string& patchName, const string& sourcePath, const string& targetPath, bool delta = false, const string& metadata = "") -> bool {
|
||||||
if(fp.open()) fp.close();
|
if(fp.open()) fp.close();
|
||||||
fp.open(patchName, file::mode::write);
|
fp.open(patchName, file::mode::write);
|
||||||
checksum.reset();
|
checksum.reset();
|
||||||
|
@ -46,8 +46,8 @@ struct bpsmulti {
|
||||||
bool identical = sp.size() == dp.size();
|
bool identical = sp.size() == dp.size();
|
||||||
Hash::CRC32 cksum;
|
Hash::CRC32 cksum;
|
||||||
|
|
||||||
for(unsigned n = 0; n < sp.size(); n++) {
|
for(uint n = 0; n < sp.size(); n++) {
|
||||||
uint8_t byte = sp.read();
|
uint8 byte = sp.read();
|
||||||
if(identical && byte != dp.read()) identical = false;
|
if(identical && byte != dp.read()) identical = false;
|
||||||
cksum.data(byte);
|
cksum.data(byte);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ struct bpsmulti {
|
||||||
writeString(targetName);
|
writeString(targetName);
|
||||||
auto buffer = file::read({targetPath, targetName});
|
auto buffer = file::read({targetPath, targetName});
|
||||||
writeNumber(buffer.size());
|
writeNumber(buffer.size());
|
||||||
for(auto &byte : buffer) write(byte);
|
for(auto& byte : buffer) write(byte);
|
||||||
writeChecksum(Hash::CRC32(buffer.data(), buffer.size()).value());
|
writeChecksum(Hash::CRC32(buffer.data(), buffer.size()).value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ struct bpsmulti {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool apply(const string& patchName, const string& sourcePath, const string& targetPath) {
|
auto apply(const string& patchName, const string& sourcePath, const string& targetPath) -> bool {
|
||||||
directory::remove(targetPath); //start with a clean directory
|
directory::remove(targetPath); //start with a clean directory
|
||||||
directory::create(targetPath);
|
directory::create(targetPath);
|
||||||
|
|
||||||
|
@ -108,8 +108,8 @@ struct bpsmulti {
|
||||||
|
|
||||||
while(fp.offset() < fp.size() - 4) {
|
while(fp.offset() < fp.size() - 4) {
|
||||||
auto encoding = readNumber();
|
auto encoding = readNumber();
|
||||||
unsigned action = encoding & 3;
|
uint action = encoding & 3;
|
||||||
unsigned targetLength = (encoding >> 2) + 1;
|
uint targetLength = (encoding >> 2) + 1;
|
||||||
string targetName = readString(targetLength);
|
string targetName = readString(targetLength);
|
||||||
|
|
||||||
if(action == CreatePath) {
|
if(action == CreatePath) {
|
||||||
|
@ -119,15 +119,15 @@ struct bpsmulti {
|
||||||
fp.open({targetPath, targetName}, file::mode::write);
|
fp.open({targetPath, targetName}, file::mode::write);
|
||||||
auto fileSize = readNumber();
|
auto fileSize = readNumber();
|
||||||
while(fileSize--) fp.write(read());
|
while(fileSize--) fp.write(read());
|
||||||
uint32_t cksum = readChecksum();
|
uint32 cksum = readChecksum();
|
||||||
} else if(action == ModifyFile) {
|
} else if(action == ModifyFile) {
|
||||||
auto encoding = readNumber();
|
auto encoding = readNumber();
|
||||||
string originPath = encoding & 1 ? targetPath : sourcePath;
|
string originPath = encoding & 1 ? targetPath : sourcePath;
|
||||||
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
||||||
auto patchSize = readNumber();
|
auto patchSize = readNumber();
|
||||||
vector<uint8_t> buffer;
|
vector<uint8> buffer;
|
||||||
buffer.resize(patchSize);
|
buffer.resize(patchSize);
|
||||||
for(unsigned n = 0; n < patchSize; n++) buffer[n] = read();
|
for(uint n = 0; n < patchSize; n++) buffer[n] = read();
|
||||||
bpspatch patch;
|
bpspatch patch;
|
||||||
patch.modify(buffer.data(), buffer.size());
|
patch.modify(buffer.data(), buffer.size());
|
||||||
patch.source({originPath, sourceName});
|
patch.source({originPath, sourceName});
|
||||||
|
@ -138,15 +138,15 @@ struct bpsmulti {
|
||||||
string originPath = encoding & 1 ? targetPath : sourcePath;
|
string originPath = encoding & 1 ? targetPath : sourcePath;
|
||||||
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
||||||
file::copy({originPath, sourceName}, {targetPath, targetName});
|
file::copy({originPath, sourceName}, {targetPath, targetName});
|
||||||
uint32_t cksum = readChecksum();
|
uint32 cksum = readChecksum();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cksum = checksum.value();
|
uint32 cksum = checksum.value();
|
||||||
if(read() != (uint8_t)(cksum >> 0)) return false;
|
if(read() != (uint8)(cksum >> 0)) return false;
|
||||||
if(read() != (uint8_t)(cksum >> 8)) return false;
|
if(read() != (uint8)(cksum >> 8)) return false;
|
||||||
if(read() != (uint8_t)(cksum >> 16)) return false;
|
if(read() != (uint8)(cksum >> 16)) return false;
|
||||||
if(read() != (uint8_t)(cksum >> 24)) return false;
|
if(read() != (uint8)(cksum >> 24)) return false;
|
||||||
|
|
||||||
fp.close();
|
fp.close();
|
||||||
return true;
|
return true;
|
||||||
|
@ -157,7 +157,7 @@ protected:
|
||||||
Hash::CRC32 checksum;
|
Hash::CRC32 checksum;
|
||||||
|
|
||||||
//create() functions
|
//create() functions
|
||||||
void ls(lstring& list, const string& path, const string& basepath) {
|
auto ls(lstring& list, const string& path, const string& basepath) -> void {
|
||||||
lstring paths = directory::folders(path);
|
lstring paths = directory::folders(path);
|
||||||
for(auto& pathname : paths) {
|
for(auto& pathname : paths) {
|
||||||
list.append(string{path, pathname}.ltrim(basepath, 1L));
|
list.append(string{path, pathname}.ltrim(basepath, 1L));
|
||||||
|
@ -170,14 +170,14 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(uint8_t data) {
|
auto write(uint8 data) -> void {
|
||||||
fp.write(data);
|
fp.write(data);
|
||||||
checksum.data(data);
|
checksum.data(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeNumber(uint64_t data) {
|
auto writeNumber(uint64 data) -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
uint64_t x = data & 0x7f;
|
uint64 x = data & 0x7f;
|
||||||
data >>= 7;
|
data >>= 7;
|
||||||
if(data == 0) {
|
if(data == 0) {
|
||||||
write(0x80 | x);
|
write(0x80 | x);
|
||||||
|
@ -188,12 +188,12 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeString(const string& text) {
|
auto writeString(const string& text) -> void {
|
||||||
unsigned length = text.length();
|
uint length = text.length();
|
||||||
for(unsigned n = 0; n < length; n++) write(text[n]);
|
for(uint n = 0; n < length; n++) write(text[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeChecksum(uint32_t cksum) {
|
auto writeChecksum(uint32 cksum) -> void {
|
||||||
write(cksum >> 0);
|
write(cksum >> 0);
|
||||||
write(cksum >> 8);
|
write(cksum >> 8);
|
||||||
write(cksum >> 16);
|
write(cksum >> 16);
|
||||||
|
@ -201,16 +201,16 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
//apply() functions
|
//apply() functions
|
||||||
uint8_t read() {
|
auto read() -> uint8 {
|
||||||
uint8_t data = fp.read();
|
uint8 data = fp.read();
|
||||||
checksum.data(data);
|
checksum.data(data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t readNumber() {
|
auto readNumber() -> uint64 {
|
||||||
uint64_t data = 0, shift = 1;
|
uint64 data = 0, shift = 1;
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = read();
|
uint8 x = read();
|
||||||
data += (x & 0x7f) * shift;
|
data += (x & 0x7f) * shift;
|
||||||
if(x & 0x80) break;
|
if(x & 0x80) break;
|
||||||
shift <<= 7;
|
shift <<= 7;
|
||||||
|
@ -219,7 +219,7 @@ protected:
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
string readString(unsigned length) {
|
auto readString(uint length) -> string {
|
||||||
string text;
|
string text;
|
||||||
text.resize(length + 1);
|
text.resize(length + 1);
|
||||||
char* p = text.get();
|
char* p = text.get();
|
||||||
|
@ -227,8 +227,8 @@ protected:
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t readChecksum() {
|
auto readChecksum() -> uint32 {
|
||||||
uint32_t checksum = 0;
|
uint32 checksum = 0;
|
||||||
checksum |= read() << 0;
|
checksum |= read() << 0;
|
||||||
checksum |= read() << 8;
|
checksum |= read() << 8;
|
||||||
checksum |= read() << 16;
|
checksum |= read() << 16;
|
||||||
|
|
|
@ -9,18 +9,18 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct bpspatch {
|
struct bpspatch {
|
||||||
inline bool modify(const uint8_t* data, unsigned size);
|
inline auto modify(const uint8* data, uint size) -> bool;
|
||||||
inline void source(const uint8_t* data, unsigned size);
|
inline auto source(const uint8* data, uint size) -> void;
|
||||||
inline void target(uint8_t* data, unsigned size);
|
inline auto target(uint8* data, uint size) -> void;
|
||||||
|
|
||||||
inline bool modify(const string& filename);
|
inline auto modify(const string& filename) -> bool;
|
||||||
inline bool source(const string& filename);
|
inline auto source(const string& filename) -> bool;
|
||||||
inline bool target(const string& filename);
|
inline auto target(const string& filename) -> bool;
|
||||||
|
|
||||||
inline string metadata() const;
|
inline auto metadata() const -> string;
|
||||||
inline unsigned size() const;
|
inline auto size() const -> uint;
|
||||||
|
|
||||||
enum result : unsigned {
|
enum result : uint {
|
||||||
unknown,
|
unknown,
|
||||||
success,
|
success,
|
||||||
patch_too_small,
|
patch_too_small,
|
||||||
|
@ -32,39 +32,39 @@ struct bpspatch {
|
||||||
patch_checksum_invalid,
|
patch_checksum_invalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline result apply();
|
inline auto apply() -> result;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum : unsigned { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
enum : uint { SourceRead, TargetRead, SourceCopy, TargetCopy };
|
||||||
|
|
||||||
filemap modifyFile;
|
filemap modifyFile;
|
||||||
const uint8_t* modifyData;
|
const uint8* modifyData;
|
||||||
unsigned modifySize;
|
uint modifySize;
|
||||||
|
|
||||||
filemap sourceFile;
|
filemap sourceFile;
|
||||||
const uint8_t* sourceData;
|
const uint8* sourceData;
|
||||||
unsigned sourceSize;
|
uint sourceSize;
|
||||||
|
|
||||||
filemap targetFile;
|
filemap targetFile;
|
||||||
uint8_t* targetData;
|
uint8* targetData;
|
||||||
unsigned targetSize;
|
uint targetSize;
|
||||||
|
|
||||||
unsigned modifySourceSize;
|
uint modifySourceSize;
|
||||||
unsigned modifyTargetSize;
|
uint modifyTargetSize;
|
||||||
unsigned modifyMarkupSize;
|
uint modifyMarkupSize;
|
||||||
string metadataString;
|
string metadataString;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool bpspatch::modify(const uint8_t* data, unsigned size) {
|
auto bpspatch::modify(const uint8* data, uint size) -> bool {
|
||||||
if(size < 19) return false;
|
if(size < 19) return false;
|
||||||
modifyData = data;
|
modifyData = data;
|
||||||
modifySize = size;
|
modifySize = size;
|
||||||
|
|
||||||
unsigned offset = 4;
|
uint offset = 4;
|
||||||
auto decode = [&]() -> uint64_t {
|
auto decode = [&]() -> uint64 {
|
||||||
uint64_t data = 0, shift = 1;
|
uint64 data = 0, shift = 1;
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = modifyData[offset++];
|
uint8 x = modifyData[offset++];
|
||||||
data += (x & 0x7f) * shift;
|
data += (x & 0x7f) * shift;
|
||||||
if(x & 0x80) break;
|
if(x & 0x80) break;
|
||||||
shift <<= 7;
|
shift <<= 7;
|
||||||
|
@ -78,35 +78,35 @@ bool bpspatch::modify(const uint8_t* data, unsigned size) {
|
||||||
modifyMarkupSize = decode();
|
modifyMarkupSize = decode();
|
||||||
|
|
||||||
char buffer[modifyMarkupSize + 1];
|
char buffer[modifyMarkupSize + 1];
|
||||||
for(unsigned n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++];
|
for(uint n = 0; n < modifyMarkupSize; n++) buffer[n] = modifyData[offset++];
|
||||||
buffer[modifyMarkupSize] = 0;
|
buffer[modifyMarkupSize] = 0;
|
||||||
metadataString = (const char*)buffer;
|
metadataString = (const char*)buffer;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bpspatch::source(const uint8_t* data, unsigned size) {
|
auto bpspatch::source(const uint8* data, uint size) -> void {
|
||||||
sourceData = data;
|
sourceData = data;
|
||||||
sourceSize = size;
|
sourceSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bpspatch::target(uint8_t* data, unsigned size) {
|
auto bpspatch::target(uint8* data, uint size) -> void {
|
||||||
targetData = data;
|
targetData = data;
|
||||||
targetSize = size;
|
targetSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpspatch::modify(const string& filename) {
|
auto bpspatch::modify(const string& filename) -> bool {
|
||||||
if(modifyFile.open(filename, filemap::mode::read) == false) return false;
|
if(modifyFile.open(filename, filemap::mode::read) == false) return false;
|
||||||
return modify(modifyFile.data(), modifyFile.size());
|
return modify(modifyFile.data(), modifyFile.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpspatch::source(const string& filename) {
|
auto bpspatch::source(const string& filename) -> bool {
|
||||||
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
if(sourceFile.open(filename, filemap::mode::read) == false) return false;
|
||||||
source(sourceFile.data(), sourceFile.size());
|
source(sourceFile.data(), sourceFile.size());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bpspatch::target(const string& filename) {
|
auto bpspatch::target(const string& filename) -> bool {
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, file::mode::write) == false) return false;
|
if(fp.open(filename, file::mode::write) == false) return false;
|
||||||
fp.truncate(modifyTargetSize);
|
fp.truncate(modifyTargetSize);
|
||||||
|
@ -117,30 +117,30 @@ bool bpspatch::target(const string& filename) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string bpspatch::metadata() const {
|
auto bpspatch::metadata() const -> string {
|
||||||
return metadataString;
|
return metadataString;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned bpspatch::size() const {
|
auto bpspatch::size() const -> uint {
|
||||||
return modifyTargetSize;
|
return modifyTargetSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
bpspatch::result bpspatch::apply() {
|
auto bpspatch::apply() -> result {
|
||||||
if(modifySize < 19) return result::patch_too_small;
|
if(modifySize < 19) return result::patch_too_small;
|
||||||
|
|
||||||
Hash::CRC32 modifyChecksum, targetChecksum;
|
Hash::CRC32 modifyChecksum, targetChecksum;
|
||||||
unsigned modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
uint modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0;
|
||||||
|
|
||||||
auto read = [&]() -> uint8_t {
|
auto read = [&]() -> uint8 {
|
||||||
uint8_t data = modifyData[modifyOffset++];
|
uint8 data = modifyData[modifyOffset++];
|
||||||
modifyChecksum.data(data);
|
modifyChecksum.data(data);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto decode = [&]() -> uint64_t {
|
auto decode = [&]() -> uint64 {
|
||||||
uint64_t data = 0, shift = 1;
|
uint64 data = 0, shift = 1;
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = read();
|
uint8 x = read();
|
||||||
data += (x & 0x7f) * shift;
|
data += (x & 0x7f) * shift;
|
||||||
if(x & 0x80) break;
|
if(x & 0x80) break;
|
||||||
shift <<= 7;
|
shift <<= 7;
|
||||||
|
@ -149,7 +149,7 @@ bpspatch::result bpspatch::apply() {
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto write = [&](uint8_t data) {
|
auto write = [&](uint8 data) {
|
||||||
targetData[outputOffset++] = data;
|
targetData[outputOffset++] = data;
|
||||||
targetChecksum.data(data);
|
targetChecksum.data(data);
|
||||||
};
|
};
|
||||||
|
@ -162,14 +162,14 @@ bpspatch::result bpspatch::apply() {
|
||||||
modifySourceSize = decode();
|
modifySourceSize = decode();
|
||||||
modifyTargetSize = decode();
|
modifyTargetSize = decode();
|
||||||
modifyMarkupSize = decode();
|
modifyMarkupSize = decode();
|
||||||
for(unsigned n = 0; n < modifyMarkupSize; n++) read();
|
for(uint n = 0; n < modifyMarkupSize; n++) read();
|
||||||
|
|
||||||
if(modifySourceSize > sourceSize) return result::source_too_small;
|
if(modifySourceSize > sourceSize) return result::source_too_small;
|
||||||
if(modifyTargetSize > targetSize) return result::target_too_small;
|
if(modifyTargetSize > targetSize) return result::target_too_small;
|
||||||
|
|
||||||
while(modifyOffset < modifySize - 12) {
|
while(modifyOffset < modifySize - 12) {
|
||||||
unsigned length = decode();
|
uint length = decode();
|
||||||
unsigned mode = length & 3;
|
uint mode = length & 3;
|
||||||
length = (length >> 2) + 1;
|
length = (length >> 2) + 1;
|
||||||
|
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
|
@ -181,7 +181,7 @@ bpspatch::result bpspatch::apply() {
|
||||||
break;
|
break;
|
||||||
case SourceCopy:
|
case SourceCopy:
|
||||||
case TargetCopy:
|
case TargetCopy:
|
||||||
signed offset = decode();
|
int offset = decode();
|
||||||
bool negative = offset & 1;
|
bool negative = offset & 1;
|
||||||
offset >>= 1;
|
offset >>= 1;
|
||||||
if(negative) offset = -offset;
|
if(negative) offset = -offset;
|
||||||
|
@ -197,13 +197,13 @@ bpspatch::result bpspatch::apply() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0;
|
uint32 modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0;
|
||||||
for(unsigned n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n;
|
for(uint n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n;
|
||||||
for(unsigned n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n;
|
for(uint n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n;
|
||||||
uint32_t checksum = modifyChecksum.value();
|
uint32 checksum = modifyChecksum.value();
|
||||||
for(unsigned n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n;
|
for(uint n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n;
|
||||||
|
|
||||||
uint32_t sourceChecksum = Hash::CRC32(sourceData, modifySourceSize).value();
|
uint32 sourceChecksum = Hash::CRC32(sourceData, modifySourceSize).value();
|
||||||
|
|
||||||
if(sourceChecksum != modifySourceChecksum) return result::source_checksum_invalid;
|
if(sourceChecksum != modifySourceChecksum) return result::source_checksum_invalid;
|
||||||
if(targetChecksum.value() != modifyTargetChecksum) return result::target_checksum_invalid;
|
if(targetChecksum.value() != modifyTargetChecksum) return result::target_checksum_invalid;
|
||||||
|
|
|
@ -7,14 +7,14 @@ namespace nall {
|
||||||
|
|
||||||
struct bitvector {
|
struct bitvector {
|
||||||
bitvector() = default;
|
bitvector() = default;
|
||||||
bitvector(unsigned size) { resize(size); }
|
bitvector(uint size) { resize(size); }
|
||||||
bitvector(const bitvector& source) { operator=(source); }
|
bitvector(const bitvector& source) { operator=(source); }
|
||||||
bitvector(bitvector&& source) { operator=(move(source)); }
|
bitvector(bitvector&& source) { operator=(move(source)); }
|
||||||
~bitvector() { reset(); }
|
~bitvector() { reset(); }
|
||||||
|
|
||||||
auto operator=(const bitvector& source) -> bitvector& {
|
auto operator=(const bitvector& source) -> bitvector& {
|
||||||
bits = source.bits;
|
bits = source.bits;
|
||||||
pool = (uint8_t*)memory::resize(pool, bytes());
|
pool = (uint8*)memory::resize(pool, bytes());
|
||||||
memory::copy(pool, source.pool, bytes());
|
memory::copy(pool, source.pool, bytes());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,10 @@ struct bitvector {
|
||||||
|
|
||||||
explicit operator bool() const { return bits > 0; }
|
explicit operator bool() const { return bits > 0; }
|
||||||
auto empty() const -> bool { return bits == 0; }
|
auto empty() const -> bool { return bits == 0; }
|
||||||
auto size() const -> unsigned { return bits; }
|
auto size() const -> uint { return bits; }
|
||||||
auto bytes() const -> unsigned { return (bits + 7) / 8; }
|
auto bytes() const -> uint { return (bits + 7) / 8; }
|
||||||
auto data() -> uint8_t* { return pool; }
|
auto data() -> uint8* { return pool; }
|
||||||
auto data() const -> const uint8_t* { return pool; }
|
auto data() const -> const uint8* { return pool; }
|
||||||
|
|
||||||
auto reset() -> void {
|
auto reset() -> void {
|
||||||
if(pool) free(pool);
|
if(pool) free(pool);
|
||||||
|
@ -40,15 +40,15 @@ struct bitvector {
|
||||||
bits = 0;
|
bits = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resize(unsigned size) -> void {
|
auto resize(uint size) -> void {
|
||||||
unsigned from = bits;
|
uint from = bits;
|
||||||
bits = size;
|
bits = size;
|
||||||
for(unsigned n = size; n < from; n++) clear(n); //on reduce
|
for(uint n = size; n < from; n++) clear(n); //on reduce
|
||||||
pool = (uint8_t*)memory::resize(pool, bytes());
|
pool = (uint8*)memory::resize(pool, bytes());
|
||||||
for(unsigned n = from; n < size; n++) clear(n); //on expand
|
for(uint n = from; n < size; n++) clear(n); //on expand
|
||||||
}
|
}
|
||||||
|
|
||||||
auto get(unsigned position) const -> bool {
|
auto get(uint position) const -> bool {
|
||||||
return pool[position >> 3] & (0x80 >> (position & 7));
|
return pool[position >> 3] & (0x80 >> (position & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,60 +58,60 @@ struct bitvector {
|
||||||
|
|
||||||
auto set() -> void {
|
auto set() -> void {
|
||||||
memory::fill(pool, bytes(), 0xff);
|
memory::fill(pool, bytes(), 0xff);
|
||||||
for(unsigned n = bits; n < bytes() * 8; n++) clear(n);
|
for(uint n = bits; n < bytes() * 8; n++) clear(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto clear(unsigned position) -> void {
|
auto clear(uint position) -> void {
|
||||||
pool[position >> 3] &= ~(0x80 >> (position & 7));
|
pool[position >> 3] &= ~(0x80 >> (position & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto set(unsigned position) -> void {
|
auto set(uint position) -> void {
|
||||||
pool[position >> 3] |= (0x80 >> (position & 7));
|
pool[position >> 3] |= (0x80 >> (position & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto invert(unsigned position) -> void {
|
auto invert(uint position) -> void {
|
||||||
get(position) ? clear(position) : set(position);
|
get(position) ? clear(position) : set(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto set(unsigned position, bool value) -> void {
|
auto set(uint position, bool value) -> void {
|
||||||
value ? set(position) : clear(position);
|
value ? set(position) : clear(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct reference {
|
struct reference {
|
||||||
reference(bitvector& self, unsigned position) : self(self), position(position) {}
|
reference(bitvector& self, uint position) : self(self), position(position) {}
|
||||||
operator bool() const { return self.get(position); }
|
operator bool() const { return self.get(position); }
|
||||||
auto operator=(bool value) -> reference& { self.set(position, value); return *this; }
|
auto operator=(bool value) -> reference& { self.set(position, value); return *this; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bitvector& self;
|
bitvector& self;
|
||||||
unsigned position;
|
uint position;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto operator[](unsigned position) -> reference {
|
auto operator[](uint position) -> reference {
|
||||||
return reference(*this, position);
|
return reference(*this, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator[](unsigned position) const -> bool {
|
auto operator[](uint position) const -> bool {
|
||||||
return get(position);
|
return get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iterator {
|
struct iterator {
|
||||||
iterator(bitvector& self, unsigned position) : self(self), position(position) {}
|
iterator(bitvector& self, uint position) : self(self), position(position) {}
|
||||||
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
|
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
|
||||||
auto operator++() -> iterator& { position++; return *this; }
|
auto operator++() -> iterator& { position++; return *this; }
|
||||||
auto operator*() -> reference { return self.operator[](position); }
|
auto operator*() -> reference { return self.operator[](position); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bitvector& self;
|
bitvector& self;
|
||||||
unsigned position;
|
uint position;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto begin() -> iterator { return iterator(*this, 0); }
|
auto begin() -> iterator { return iterator(*this, 0); }
|
||||||
auto end() -> iterator { return iterator(*this, bits); }
|
auto end() -> iterator { return iterator(*this, bits); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint8_t* pool = nullptr;
|
uint8* pool = nullptr;
|
||||||
unsigned bits = 0;
|
uint bits = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,52 +7,55 @@
|
||||||
namespace nall { namespace Decode {
|
namespace nall { namespace Decode {
|
||||||
|
|
||||||
struct GZIP {
|
struct GZIP {
|
||||||
string filename;
|
|
||||||
uint8_t* data = nullptr;
|
|
||||||
unsigned size = 0;
|
|
||||||
|
|
||||||
inline bool decompress(const string& filename);
|
|
||||||
inline bool decompress(const uint8_t* data, unsigned size);
|
|
||||||
|
|
||||||
inline GZIP();
|
|
||||||
inline ~GZIP();
|
inline ~GZIP();
|
||||||
|
|
||||||
|
inline auto decompress(const string& filename) -> bool;
|
||||||
|
inline auto decompress(const uint8* data, uint size) -> bool;
|
||||||
|
|
||||||
|
string filename;
|
||||||
|
uint8* data = nullptr;
|
||||||
|
uint size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool GZIP::decompress(const string& filename) {
|
GZIP::~GZIP() {
|
||||||
|
if(data) delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GZIP::decompress(const string& filename) -> bool {
|
||||||
if(auto memory = file::read(filename)) {
|
if(auto memory = file::read(filename)) {
|
||||||
return decompress(memory.data(), memory.size());
|
return decompress(memory.data(), memory.size());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GZIP::decompress(const uint8_t* data, unsigned size) {
|
auto GZIP::decompress(const uint8* data, uint size) -> bool {
|
||||||
if(size < 18) return false;
|
if(size < 18) return false;
|
||||||
if(data[0] != 0x1f) return false;
|
if(data[0] != 0x1f) return false;
|
||||||
if(data[1] != 0x8b) return false;
|
if(data[1] != 0x8b) return false;
|
||||||
unsigned cm = data[2];
|
uint cm = data[2];
|
||||||
unsigned flg = data[3];
|
uint flg = data[3];
|
||||||
unsigned mtime = data[4];
|
uint mtime = data[4];
|
||||||
mtime |= data[5] << 8;
|
mtime |= data[5] << 8;
|
||||||
mtime |= data[6] << 16;
|
mtime |= data[6] << 16;
|
||||||
mtime |= data[7] << 24;
|
mtime |= data[7] << 24;
|
||||||
unsigned xfl = data[8];
|
uint xfl = data[8];
|
||||||
unsigned os = data[9];
|
uint os = data[9];
|
||||||
unsigned p = 10;
|
uint p = 10;
|
||||||
unsigned isize = data[size - 4];
|
uint isize = data[size - 4];
|
||||||
isize |= data[size - 3] << 8;
|
isize |= data[size - 3] << 8;
|
||||||
isize |= data[size - 2] << 16;
|
isize |= data[size - 2] << 16;
|
||||||
isize |= data[size - 1] << 24;
|
isize |= data[size - 1] << 24;
|
||||||
filename = "";
|
filename = "";
|
||||||
|
|
||||||
if(flg & 0x04) { //FEXTRA
|
if(flg & 0x04) { //FEXTRA
|
||||||
unsigned xlen = data[p + 0];
|
uint xlen = data[p + 0];
|
||||||
xlen |= data[p + 1] << 8;
|
xlen |= data[p + 1] << 8;
|
||||||
p += 2 + xlen;
|
p += 2 + xlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(flg & 0x08) { //FNAME
|
if(flg & 0x08) { //FNAME
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
for(unsigned n = 0; n < PATH_MAX; n++, p++) {
|
for(uint n = 0; n < PATH_MAX; n++, p++) {
|
||||||
buffer[n] = data[p];
|
buffer[n] = data[p];
|
||||||
if(data[p] == 0) break;
|
if(data[p] == 0) break;
|
||||||
}
|
}
|
||||||
|
@ -73,13 +76,6 @@ bool GZIP::decompress(const uint8_t* data, unsigned size) {
|
||||||
return inflate(this->data, this->size, data + p, size - p - 8);
|
return inflate(this->data, this->size, data + p, size - p - 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
GZIP::GZIP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
GZIP::~GZIP() {
|
|
||||||
if(data) delete[] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,16 +6,16 @@
|
||||||
namespace nall { namespace Decode {
|
namespace nall { namespace Decode {
|
||||||
|
|
||||||
namespace puff {
|
namespace puff {
|
||||||
inline int puff(
|
inline auto puff(
|
||||||
unsigned char* dest, unsigned long* destlen,
|
unsigned char* dest, unsigned long* destlen,
|
||||||
unsigned char* source, unsigned long* sourcelen
|
unsigned char* source, unsigned long* sourcelen
|
||||||
);
|
) -> int;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool inflate(
|
inline auto inflate(
|
||||||
uint8_t* target, unsigned targetLength,
|
uint8* target, uint targetLength,
|
||||||
const uint8_t* source, unsigned sourceLength
|
const uint8* source, uint sourceLength
|
||||||
) {
|
) -> bool {
|
||||||
unsigned long tl = targetLength, sl = sourceLength;
|
unsigned long tl = targetLength, sl = sourceLength;
|
||||||
int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl);
|
int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl);
|
||||||
return result == 0;
|
return result == 0;
|
||||||
|
@ -23,7 +23,7 @@ inline bool inflate(
|
||||||
|
|
||||||
namespace puff {
|
namespace puff {
|
||||||
|
|
||||||
enum {
|
enum : uint {
|
||||||
MAXBITS = 15,
|
MAXBITS = 15,
|
||||||
MAXLCODES = 286,
|
MAXLCODES = 286,
|
||||||
MAXDCODES = 30,
|
MAXDCODES = 30,
|
||||||
|
@ -50,7 +50,7 @@ struct huffman {
|
||||||
short* symbol;
|
short* symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int bits(state* s, int need) {
|
inline auto bits(state* s, int need) -> int {
|
||||||
long val;
|
long val;
|
||||||
|
|
||||||
val = s->bitbuf;
|
val = s->bitbuf;
|
||||||
|
@ -66,8 +66,8 @@ inline int bits(state* s, int need) {
|
||||||
return (int)(val & ((1L << need) - 1));
|
return (int)(val & ((1L << need) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int stored(state* s) {
|
inline auto stored(state* s) -> int {
|
||||||
unsigned len;
|
uint len;
|
||||||
|
|
||||||
s->bitbuf = 0;
|
s->bitbuf = 0;
|
||||||
s->bitcnt = 0;
|
s->bitcnt = 0;
|
||||||
|
@ -91,7 +91,7 @@ inline int stored(state* s) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int decode(state* s, huffman* h) {
|
inline auto decode(state* s, huffman* h) -> int {
|
||||||
int len, code, first, count, index, bitbuf, left;
|
int len, code, first, count, index, bitbuf, left;
|
||||||
short* next;
|
short* next;
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ inline int decode(state* s, huffman* h) {
|
||||||
return -10;
|
return -10;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int construct(huffman* h, short* length, int n) {
|
inline auto construct(huffman* h, short* length, int n) -> int {
|
||||||
int symbol, len, left;
|
int symbol, len, left;
|
||||||
short offs[MAXBITS + 1];
|
short offs[MAXBITS + 1];
|
||||||
|
|
||||||
|
@ -151,9 +151,9 @@ inline int construct(huffman* h, short* length, int n) {
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int codes(state* s, huffman* lencode, huffman* distcode) {
|
inline auto codes(state* s, huffman* lencode, huffman* distcode) -> int {
|
||||||
int symbol, len;
|
int symbol, len;
|
||||||
unsigned dist;
|
uint dist;
|
||||||
static const short lens[29] = {
|
static const short lens[29] = {
|
||||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
|
||||||
|
@ -213,7 +213,7 @@ inline int codes(state* s, huffman* lencode, huffman* distcode) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int fixed(state* s) {
|
inline auto fixed(state* s) -> int {
|
||||||
static int virgin = 1;
|
static int virgin = 1;
|
||||||
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
|
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
|
||||||
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
|
||||||
|
@ -243,7 +243,7 @@ inline int fixed(state* s) {
|
||||||
return codes(s, &lencode, &distcode);
|
return codes(s, &lencode, &distcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int dynamic(state* s) {
|
inline auto dynamic(state* s) -> int {
|
||||||
int nlen, ndist, ncode, index, err;
|
int nlen, ndist, ncode, index, err;
|
||||||
short lengths[MAXCODES];
|
short lengths[MAXCODES];
|
||||||
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
|
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
|
||||||
|
@ -303,10 +303,10 @@ inline int dynamic(state* s) {
|
||||||
return codes(s, &lencode, &distcode);
|
return codes(s, &lencode, &distcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int puff(
|
inline auto puff(
|
||||||
unsigned char* dest, unsigned long* destlen,
|
unsigned char* dest, unsigned long* destlen,
|
||||||
unsigned char* source, unsigned long* sourcelen
|
unsigned char* source, unsigned long* sourcelen
|
||||||
) {
|
) -> int {
|
||||||
state s;
|
state s;
|
||||||
int last, type, err;
|
int last, type, err;
|
||||||
|
|
||||||
|
|
|
@ -7,75 +7,83 @@
|
||||||
namespace nall { namespace Decode {
|
namespace nall { namespace Decode {
|
||||||
|
|
||||||
struct PNG {
|
struct PNG {
|
||||||
|
inline PNG();
|
||||||
|
inline ~PNG();
|
||||||
|
|
||||||
|
inline auto load(const string& filename) -> bool;
|
||||||
|
inline auto load(const uint8* sourceData, uint sourceSize) -> bool;
|
||||||
|
inline auto readbits(const uint8*& data) -> uint;
|
||||||
|
|
||||||
struct Info {
|
struct Info {
|
||||||
unsigned width;
|
uint width;
|
||||||
unsigned height;
|
uint height;
|
||||||
unsigned bitDepth;
|
uint bitDepth;
|
||||||
//colorType:
|
//colorType:
|
||||||
//0 = L (luma)
|
//0 = L (luma)
|
||||||
//2 = R,G,B
|
//2 = R,G,B
|
||||||
//3 = P (palette)
|
//3 = P (palette)
|
||||||
//4 = L,A
|
//4 = L,A
|
||||||
//6 = R,G,B,A
|
//6 = R,G,B,A
|
||||||
unsigned colorType;
|
uint colorType;
|
||||||
unsigned compressionMethod;
|
uint compressionMethod;
|
||||||
unsigned filterType;
|
uint filterType;
|
||||||
unsigned interlaceMethod;
|
uint interlaceMethod;
|
||||||
|
|
||||||
unsigned bytesPerPixel;
|
uint bytesPerPixel;
|
||||||
unsigned pitch;
|
uint pitch;
|
||||||
|
|
||||||
uint8_t palette[256][3];
|
uint8 palette[256][3];
|
||||||
} info;
|
} info;
|
||||||
|
|
||||||
uint8_t* data = nullptr;
|
uint8* data = nullptr;
|
||||||
unsigned size = 0;
|
uint size = 0;
|
||||||
|
|
||||||
inline bool load(const string& filename);
|
uint bitpos = 0;
|
||||||
inline bool load(const uint8_t* sourceData, unsigned sourceSize);
|
|
||||||
inline unsigned readbits(const uint8_t*& data);
|
|
||||||
unsigned bitpos = 0;
|
|
||||||
|
|
||||||
inline PNG();
|
|
||||||
inline ~PNG();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum class FourCC : unsigned {
|
enum class FourCC : uint {
|
||||||
IHDR = 0x49484452,
|
IHDR = 0x49484452,
|
||||||
PLTE = 0x504c5445,
|
PLTE = 0x504c5445,
|
||||||
IDAT = 0x49444154,
|
IDAT = 0x49444154,
|
||||||
IEND = 0x49454e44,
|
IEND = 0x49454e44,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline unsigned interlace(unsigned pass, unsigned index);
|
inline auto interlace(uint pass, uint index) -> uint;
|
||||||
inline unsigned inflateSize();
|
inline auto inflateSize() -> uint;
|
||||||
inline bool deinterlace(const uint8_t*& inputData, unsigned pass);
|
inline auto deinterlace(const uint8*& inputData, uint pass) -> bool;
|
||||||
inline bool filter(uint8_t* outputData, const uint8_t* inputData, unsigned width, unsigned height);
|
inline auto filter(uint8* outputData, const uint8* inputData, uint width, uint height) -> bool;
|
||||||
inline unsigned read(const uint8_t* data, unsigned length);
|
inline auto read(const uint8* data, uint length) -> uint;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool PNG::load(const string& filename) {
|
PNG::PNG() {
|
||||||
|
}
|
||||||
|
|
||||||
|
PNG::~PNG() {
|
||||||
|
if(data) delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PNG::load(const string& filename) -> bool {
|
||||||
if(auto memory = file::read(filename)) {
|
if(auto memory = file::read(filename)) {
|
||||||
return load(memory.data(), memory.size());
|
return load(memory.data(), memory.size());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
auto PNG::load(const uint8* sourceData, uint sourceSize) -> bool {
|
||||||
if(sourceSize < 8) return false;
|
if(sourceSize < 8) return false;
|
||||||
if(read(sourceData + 0, 4) != 0x89504e47) return false;
|
if(read(sourceData + 0, 4) != 0x89504e47) return false;
|
||||||
if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false;
|
if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false;
|
||||||
|
|
||||||
uint8_t* compressedData = nullptr;
|
uint8* compressedData = nullptr;
|
||||||
unsigned compressedSize = 0;
|
uint compressedSize = 0;
|
||||||
|
|
||||||
unsigned offset = 8;
|
uint offset = 8;
|
||||||
while(offset < sourceSize) {
|
while(offset < sourceSize) {
|
||||||
unsigned length = read(sourceData + offset + 0, 4);
|
uint length = read(sourceData + offset + 0, 4);
|
||||||
unsigned fourCC = read(sourceData + offset + 4, 4);
|
uint fourCC = read(sourceData + offset + 4, 4);
|
||||||
unsigned checksum = read(sourceData + offset + 8 + length, 4);
|
uint checksum = read(sourceData + offset + 8 + length, 4);
|
||||||
|
|
||||||
if(fourCC == (unsigned)FourCC::IHDR) {
|
if(fourCC == (uint)FourCC::IHDR) {
|
||||||
info.width = read(sourceData + offset + 8, 4);
|
info.width = read(sourceData + offset + 8, 4);
|
||||||
info.height = read(sourceData + offset + 12, 4);
|
info.height = read(sourceData + offset + 12, 4);
|
||||||
info.bitDepth = read(sourceData + offset + 16, 1);
|
info.bitDepth = read(sourceData + offset + 16, 1);
|
||||||
|
@ -108,30 +116,30 @@ bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
||||||
info.pitch = (int)info.width * info.bytesPerPixel;
|
info.pitch = (int)info.width * info.bytesPerPixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fourCC == (unsigned)FourCC::PLTE) {
|
if(fourCC == (uint)FourCC::PLTE) {
|
||||||
if(length % 3) return false;
|
if(length % 3) return false;
|
||||||
for(unsigned n = 0, p = offset + 8; n < length / 3; n++) {
|
for(uint n = 0, p = offset + 8; n < length / 3; n++) {
|
||||||
info.palette[n][0] = sourceData[p++];
|
info.palette[n][0] = sourceData[p++];
|
||||||
info.palette[n][1] = sourceData[p++];
|
info.palette[n][1] = sourceData[p++];
|
||||||
info.palette[n][2] = sourceData[p++];
|
info.palette[n][2] = sourceData[p++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fourCC == (unsigned)FourCC::IDAT) {
|
if(fourCC == (uint)FourCC::IDAT) {
|
||||||
compressedData = (uint8_t*)realloc(compressedData, compressedSize + length);
|
compressedData = (uint8*)realloc(compressedData, compressedSize + length);
|
||||||
memcpy(compressedData + compressedSize, sourceData + offset + 8, length);
|
memcpy(compressedData + compressedSize, sourceData + offset + 8, length);
|
||||||
compressedSize += length;
|
compressedSize += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fourCC == (unsigned)FourCC::IEND) {
|
if(fourCC == (uint)FourCC::IEND) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += 4 + 4 + length + 4;
|
offset += 4 + 4 + length + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned interlacedSize = inflateSize();
|
uint interlacedSize = inflateSize();
|
||||||
uint8_t *interlacedData = new uint8_t[interlacedSize];
|
uint8 *interlacedData = new uint8[interlacedSize];
|
||||||
|
|
||||||
bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6);
|
bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6);
|
||||||
free(compressedData);
|
free(compressedData);
|
||||||
|
@ -142,7 +150,7 @@ bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size = info.width * info.height * info.bytesPerPixel;
|
size = info.width * info.height * info.bytesPerPixel;
|
||||||
data = new uint8_t[size];
|
data = new uint8[size];
|
||||||
|
|
||||||
if(info.interlaceMethod == 0) {
|
if(info.interlaceMethod == 0) {
|
||||||
if(filter(data, interlacedData, info.width, info.height) == false) {
|
if(filter(data, interlacedData, info.width, info.height) == false) {
|
||||||
|
@ -152,8 +160,8 @@ bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const uint8_t *passData = interlacedData;
|
const uint8* passData = interlacedData;
|
||||||
for(unsigned pass = 0; pass < 7; pass++) {
|
for(uint pass = 0; pass < 7; pass++) {
|
||||||
if(deinterlace(passData, pass) == false) {
|
if(deinterlace(passData, pass) == false) {
|
||||||
delete[] interlacedData;
|
delete[] interlacedData;
|
||||||
delete[] data;
|
delete[] data;
|
||||||
|
@ -167,8 +175,8 @@ bool PNG::load(const uint8_t* sourceData, unsigned sourceSize) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned PNG::interlace(unsigned pass, unsigned index) {
|
auto PNG::interlace(uint pass, uint index) -> uint {
|
||||||
static const unsigned data[7][4] = {
|
static const uint data[7][4] = {
|
||||||
//x-distance, y-distance, x-origin, y-origin
|
//x-distance, y-distance, x-origin, y-origin
|
||||||
{8, 8, 0, 0},
|
{8, 8, 0, 0},
|
||||||
{8, 8, 4, 0},
|
{8, 8, 4, 0},
|
||||||
|
@ -181,39 +189,39 @@ unsigned PNG::interlace(unsigned pass, unsigned index) {
|
||||||
return data[pass][index];
|
return data[pass][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned PNG::inflateSize() {
|
auto PNG::inflateSize() -> uint {
|
||||||
if(info.interlaceMethod == 0) {
|
if(info.interlaceMethod == 0) {
|
||||||
return info.width * info.height * info.bytesPerPixel + info.height;
|
return info.width * info.height * info.bytesPerPixel + info.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned size = 0;
|
uint size = 0;
|
||||||
for(unsigned pass = 0; pass < 7; pass++) {
|
for(uint pass = 0; pass < 7; pass++) {
|
||||||
unsigned xd = interlace(pass, 0), yd = interlace(pass, 1);
|
uint xd = interlace(pass, 0), yd = interlace(pass, 1);
|
||||||
unsigned xo = interlace(pass, 2), yo = interlace(pass, 3);
|
uint xo = interlace(pass, 2), yo = interlace(pass, 3);
|
||||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
uint width = (info.width + (xd - xo - 1)) / xd;
|
||||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
uint height = (info.height + (yd - yo - 1)) / yd;
|
||||||
if(width == 0 || height == 0) continue;
|
if(width == 0 || height == 0) continue;
|
||||||
size += width * height * info.bytesPerPixel + height;
|
size += width * height * info.bytesPerPixel + height;
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PNG::deinterlace(const uint8_t*& inputData, unsigned pass) {
|
auto PNG::deinterlace(const uint8*& inputData, uint pass) -> bool {
|
||||||
unsigned xd = interlace(pass, 0), yd = interlace(pass, 1);
|
uint xd = interlace(pass, 0), yd = interlace(pass, 1);
|
||||||
unsigned xo = interlace(pass, 2), yo = interlace(pass, 3);
|
uint xo = interlace(pass, 2), yo = interlace(pass, 3);
|
||||||
unsigned width = (info.width + (xd - xo - 1)) / xd;
|
uint width = (info.width + (xd - xo - 1)) / xd;
|
||||||
unsigned height = (info.height + (yd - yo - 1)) / yd;
|
uint height = (info.height + (yd - yo - 1)) / yd;
|
||||||
if(width == 0 || height == 0) return true;
|
if(width == 0 || height == 0) return true;
|
||||||
|
|
||||||
unsigned outputSize = width * height * info.bytesPerPixel;
|
uint outputSize = width * height * info.bytesPerPixel;
|
||||||
uint8_t* outputData = new uint8_t[outputSize];
|
uint8* outputData = new uint8[outputSize];
|
||||||
bool result = filter(outputData, inputData, width, height);
|
bool result = filter(outputData, inputData, width, height);
|
||||||
|
|
||||||
const uint8_t* rd = outputData;
|
const uint8* rd = outputData;
|
||||||
for(unsigned y = yo; y < info.height; y += yd) {
|
for(uint y = yo; y < info.height; y += yd) {
|
||||||
uint8_t* wr = data + y * info.pitch;
|
uint8* wr = data + y * info.pitch;
|
||||||
for(unsigned x = xo; x < info.width; x += xd) {
|
for(uint x = xo; x < info.width; x += xd) {
|
||||||
for(unsigned b = 0; b < info.bytesPerPixel; b++) {
|
for(uint b = 0; b < info.bytesPerPixel; b++) {
|
||||||
wr[x * info.bytesPerPixel + b] = *rd++;
|
wr[x * info.bytesPerPixel + b] = *rd++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,12 +232,12 @@ bool PNG::deinterlace(const uint8_t*& inputData, unsigned pass) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width, unsigned height) {
|
auto PNG::filter(uint8* outputData, const uint8* inputData, uint width, uint height) -> bool {
|
||||||
uint8_t* wr = outputData;
|
uint8* wr = outputData;
|
||||||
const uint8_t* rd = inputData;
|
const uint8* rd = inputData;
|
||||||
int bpp = info.bytesPerPixel, pitch = width * bpp;
|
int bpp = info.bytesPerPixel, pitch = width * bpp;
|
||||||
for(int y = 0; y < height; y++) {
|
for(int y = 0; y < height; y++) {
|
||||||
uint8_t filter = *rd++;
|
uint8 filter = *rd++;
|
||||||
|
|
||||||
switch(filter) {
|
switch(filter) {
|
||||||
case 0x00: //None
|
case 0x00: //None
|
||||||
|
@ -255,7 +263,7 @@ bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width,
|
||||||
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
short a = x - bpp < 0 ? 0 : wr[x - bpp];
|
||||||
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
short b = y - 1 < 0 ? 0 : wr[x - pitch];
|
||||||
|
|
||||||
wr[x] = rd[x] + (uint8_t)((a + b) / 2);
|
wr[x] = rd[x] + (uint8)((a + b) / 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -270,7 +278,7 @@ bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width,
|
||||||
short pb = p > b ? p - b : b - p;
|
short pb = p > b ? p - b : b - p;
|
||||||
short pc = p > c ? p - c : c - p;
|
short pc = p > c ? p - c : c - p;
|
||||||
|
|
||||||
uint8_t paeth = (uint8_t)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
|
uint8 paeth = (uint8)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
|
||||||
|
|
||||||
wr[x] = rd[x] + paeth;
|
wr[x] = rd[x] + paeth;
|
||||||
}
|
}
|
||||||
|
@ -287,14 +295,14 @@ bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned PNG::read(const uint8_t* data, unsigned length) {
|
auto PNG::read(const uint8* data, uint length) -> uint {
|
||||||
unsigned result = 0;
|
uint result = 0;
|
||||||
while(length--) result = (result << 8) | (*data++);
|
while(length--) result = (result << 8) | (*data++);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned PNG::readbits(const uint8_t*& data) {
|
auto PNG::readbits(const uint8*& data) -> uint {
|
||||||
unsigned result = 0;
|
uint result = 0;
|
||||||
switch(info.bitDepth) {
|
switch(info.bitDepth) {
|
||||||
case 1:
|
case 1:
|
||||||
result = (*data >> bitpos) & 1;
|
result = (*data >> bitpos) & 1;
|
||||||
|
@ -322,13 +330,6 @@ unsigned PNG::readbits(const uint8_t*& data) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PNG::PNG() {
|
|
||||||
}
|
|
||||||
|
|
||||||
PNG::~PNG() {
|
|
||||||
if(data) delete[] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,14 +11,18 @@ namespace nall { namespace Decode {
|
||||||
struct ZIP {
|
struct ZIP {
|
||||||
struct File {
|
struct File {
|
||||||
string name;
|
string name;
|
||||||
const uint8_t* data;
|
const uint8* data;
|
||||||
unsigned size;
|
uint size;
|
||||||
unsigned csize;
|
uint csize;
|
||||||
unsigned cmode; //0 = uncompressed, 8 = deflate
|
uint cmode; //0 = uncompressed, 8 = deflate
|
||||||
unsigned crc32;
|
uint crc32;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool open(const string& filename) {
|
~ZIP() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto open(const string& filename) -> bool {
|
||||||
close();
|
close();
|
||||||
if(fm.open(filename, filemap::mode::read) == false) return false;
|
if(fm.open(filename, filemap::mode::read) == false) return false;
|
||||||
if(open(fm.data(), fm.size()) == false) {
|
if(open(fm.data(), fm.size()) == false) {
|
||||||
|
@ -28,7 +32,7 @@ struct ZIP {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool open(const uint8_t* data, unsigned size) {
|
auto open(const uint8* data, uint size) -> bool {
|
||||||
if(size < 22) return false;
|
if(size < 22) return false;
|
||||||
|
|
||||||
filedata = data;
|
filedata = data;
|
||||||
|
@ -36,19 +40,19 @@ struct ZIP {
|
||||||
|
|
||||||
file.reset();
|
file.reset();
|
||||||
|
|
||||||
const uint8_t* footer = data + size - 22;
|
const uint8* footer = data + size - 22;
|
||||||
while(true) {
|
while(true) {
|
||||||
if(footer <= data + 22) return false;
|
if(footer <= data + 22) return false;
|
||||||
if(read(footer, 4) == 0x06054b50) {
|
if(read(footer, 4) == 0x06054b50) {
|
||||||
unsigned commentlength = read(footer + 20, 2);
|
uint commentlength = read(footer + 20, 2);
|
||||||
if(footer + 22 + commentlength == data + size) break;
|
if(footer + 22 + commentlength == data + size) break;
|
||||||
}
|
}
|
||||||
footer--;
|
footer--;
|
||||||
}
|
}
|
||||||
const uint8_t* directory = data + read(footer + 16, 4);
|
const uint8* directory = data + read(footer + 16, 4);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
unsigned signature = read(directory + 0, 4);
|
uint signature = read(directory + 0, 4);
|
||||||
if(signature != 0x02014b50) break;
|
if(signature != 0x02014b50) break;
|
||||||
|
|
||||||
File file;
|
File file;
|
||||||
|
@ -57,9 +61,9 @@ struct ZIP {
|
||||||
file.csize = read(directory + 20, 4);
|
file.csize = read(directory + 20, 4);
|
||||||
file.size = read(directory + 24, 4);
|
file.size = read(directory + 24, 4);
|
||||||
|
|
||||||
unsigned namelength = read(directory + 28, 2);
|
uint namelength = read(directory + 28, 2);
|
||||||
unsigned extralength = read(directory + 30, 2);
|
uint extralength = read(directory + 30, 2);
|
||||||
unsigned commentlength = read(directory + 32, 2);
|
uint commentlength = read(directory + 32, 2);
|
||||||
|
|
||||||
char* filename = new char[namelength + 1];
|
char* filename = new char[namelength + 1];
|
||||||
memcpy(filename, directory + 46, namelength);
|
memcpy(filename, directory + 46, namelength);
|
||||||
|
@ -67,9 +71,9 @@ struct ZIP {
|
||||||
file.name = filename;
|
file.name = filename;
|
||||||
delete[] filename;
|
delete[] filename;
|
||||||
|
|
||||||
unsigned offset = read(directory + 42, 4);
|
uint offset = read(directory + 42, 4);
|
||||||
unsigned offsetNL = read(data + offset + 26, 2);
|
uint offsetNL = read(data + offset + 26, 2);
|
||||||
unsigned offsetEL = read(data + offset + 28, 2);
|
uint offsetEL = read(data + offset + 28, 2);
|
||||||
file.data = data + offset + 30 + offsetNL + offsetEL;
|
file.data = data + offset + 30 + offsetNL + offsetEL;
|
||||||
|
|
||||||
directory += 46 + namelength + extralength + commentlength;
|
directory += 46 + namelength + extralength + commentlength;
|
||||||
|
@ -80,8 +84,8 @@ struct ZIP {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline vector<uint8_t> extract(File& file) {
|
auto extract(File& file) -> vector<uint8> {
|
||||||
vector<uint8_t> buffer;
|
vector<uint8> buffer;
|
||||||
|
|
||||||
if(file.cmode == 0) {
|
if(file.cmode == 0) {
|
||||||
buffer.resize(file.size);
|
buffer.resize(file.size);
|
||||||
|
@ -98,21 +102,17 @@ struct ZIP {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void close() {
|
auto close() -> void {
|
||||||
if(fm.open()) fm.close();
|
if(fm.open()) fm.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
~ZIP() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
filemap fm;
|
filemap fm;
|
||||||
const uint8_t* filedata;
|
const uint8* filedata;
|
||||||
unsigned filesize;
|
uint filesize;
|
||||||
|
|
||||||
unsigned read(const uint8_t* data, unsigned size) {
|
auto read(const uint8* data, uint size) -> uint {
|
||||||
unsigned result = 0, shift = 0;
|
uint result = 0, shift = 0;
|
||||||
while(size--) { result |= *data++ << shift; shift += 8; }
|
while(size--) { result |= *data++ << shift; shift += 8; }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace nall {
|
||||||
|
|
||||||
template<typename T> struct function;
|
template<typename T> struct function;
|
||||||
|
|
||||||
template<typename R, typename... P> struct function<R (P...)> {
|
template<typename R, typename... P> struct function<auto (P...) -> R> {
|
||||||
//value = true if auto L::operator()(P...) -> R exists
|
//value = true if auto L::operator()(P...) -> R exists
|
||||||
template<typename L> struct is_compatible {
|
template<typename L> struct is_compatible {
|
||||||
template<typename T> static auto exists(T*) -> const typename is_same<R, decltype(declval<T>().operator()(declval<P>()...))>::type;
|
template<typename T> static auto exists(T*) -> const typename is_same<R, decltype(declval<T>().operator()(declval<P>()...))>::type;
|
||||||
|
|
|
@ -4,26 +4,24 @@ namespace nall {
|
||||||
namespace mosaic {
|
namespace mosaic {
|
||||||
|
|
||||||
struct bitstream {
|
struct bitstream {
|
||||||
filemap fp;
|
~bitstream() {
|
||||||
uint8_t* data = nullptr;
|
close();
|
||||||
unsigned size = 0;
|
}
|
||||||
bool readonly = false;
|
|
||||||
bool endian = 1;
|
|
||||||
|
|
||||||
bool read(uint64_t addr) const {
|
auto read(uint64 addr) const -> bool {
|
||||||
if(data == nullptr || (addr >> 3) >= size) return 0;
|
if(data == nullptr || (addr >> 3) >= size) return 0;
|
||||||
unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
uint mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
||||||
return data[addr >> 3] & mask;
|
return data[addr >> 3] & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(uint64_t addr, bool value) {
|
auto write(uint64 addr, bool value) -> void {
|
||||||
if(data == nullptr || readonly == true || (addr >> 3) >= size) return;
|
if(data == nullptr || readonly == true || (addr >> 3) >= size) return;
|
||||||
unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
uint mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
||||||
if(value == 0) data[addr >> 3] &= ~mask;
|
if(value == 0) data[addr >> 3] &= ~mask;
|
||||||
if(value == 1) data[addr >> 3] |= mask;
|
if(value == 1) data[addr >> 3] |= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open(const string& filename) {
|
auto open(const string& filename) -> bool {
|
||||||
readonly = false;
|
readonly = false;
|
||||||
if(fp.open(filename, filemap::mode::readwrite) == false) {
|
if(fp.open(filename, filemap::mode::readwrite) == false) {
|
||||||
readonly = true;
|
readonly = true;
|
||||||
|
@ -36,17 +34,16 @@ struct bitstream {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void close() {
|
auto close() -> void {
|
||||||
fp.close();
|
fp.close();
|
||||||
data = nullptr;
|
data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitstream() {
|
filemap fp;
|
||||||
}
|
uint8* data = nullptr;
|
||||||
|
uint size = 0;
|
||||||
~bitstream() {
|
bool readonly = false;
|
||||||
close();
|
bool endian = 1;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,54 +4,60 @@ namespace nall {
|
||||||
namespace mosaic {
|
namespace mosaic {
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
unsigned offset;
|
context() {
|
||||||
unsigned width;
|
reset();
|
||||||
unsigned height;
|
}
|
||||||
unsigned count;
|
|
||||||
|
|
||||||
bool endian; //0 = lsb, 1 = msb
|
auto objectWidth() const -> uint { return blockWidth * tileWidth * mosaicWidth + paddingWidth; }
|
||||||
bool order; //0 = linear, 1 = planar
|
auto objectHeight() const -> uint { return blockHeight * tileHeight * mosaicHeight + paddingHeight; }
|
||||||
unsigned depth; //1 - 24bpp
|
auto objectSize() const -> uint {
|
||||||
|
uint size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight
|
||||||
unsigned blockWidth;
|
+ blockOffset * tileHeight * mosaicWidth * mosaicHeight
|
||||||
unsigned blockHeight;
|
+ tileStride * mosaicWidth * mosaicHeight
|
||||||
unsigned blockStride;
|
+ tileOffset * mosaicHeight;
|
||||||
unsigned blockOffset;
|
|
||||||
vector<unsigned> block;
|
|
||||||
|
|
||||||
unsigned tileWidth;
|
|
||||||
unsigned tileHeight;
|
|
||||||
unsigned tileStride;
|
|
||||||
unsigned tileOffset;
|
|
||||||
vector<unsigned> tile;
|
|
||||||
|
|
||||||
unsigned mosaicWidth;
|
|
||||||
unsigned mosaicHeight;
|
|
||||||
unsigned mosaicStride;
|
|
||||||
unsigned mosaicOffset;
|
|
||||||
vector<unsigned> mosaic;
|
|
||||||
|
|
||||||
unsigned paddingWidth;
|
|
||||||
unsigned paddingHeight;
|
|
||||||
unsigned paddingColor;
|
|
||||||
vector<unsigned> palette;
|
|
||||||
|
|
||||||
unsigned objectWidth() const { return blockWidth * tileWidth * mosaicWidth + paddingWidth; }
|
|
||||||
unsigned objectHeight() const { return blockHeight * tileHeight * mosaicHeight + paddingHeight; }
|
|
||||||
unsigned objectSize() const {
|
|
||||||
unsigned size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight
|
|
||||||
+ blockOffset * tileHeight * mosaicWidth * mosaicHeight
|
|
||||||
+ tileStride * mosaicWidth * mosaicHeight
|
|
||||||
+ tileOffset * mosaicHeight;
|
|
||||||
return max(1u, size);
|
return max(1u, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned eval(const string& expression) {
|
auto reset() -> void {
|
||||||
|
offset = 0;
|
||||||
|
width = 0;
|
||||||
|
height = 0;
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
endian = 1;
|
||||||
|
order = 0;
|
||||||
|
depth = 1;
|
||||||
|
|
||||||
|
blockWidth = 1;
|
||||||
|
blockHeight = 1;
|
||||||
|
blockStride = 0;
|
||||||
|
blockOffset = 0;
|
||||||
|
block.reset();
|
||||||
|
|
||||||
|
tileWidth = 1;
|
||||||
|
tileHeight = 1;
|
||||||
|
tileStride = 0;
|
||||||
|
tileOffset = 0;
|
||||||
|
tile.reset();
|
||||||
|
|
||||||
|
mosaicWidth = 1;
|
||||||
|
mosaicHeight = 1;
|
||||||
|
mosaicStride = 0;
|
||||||
|
mosaicOffset = 0;
|
||||||
|
mosaic.reset();
|
||||||
|
|
||||||
|
paddingWidth = 0;
|
||||||
|
paddingHeight = 0;
|
||||||
|
paddingColor = 0;
|
||||||
|
palette.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eval(const string& expression) -> uint {
|
||||||
if(auto result = Eval::integer(expression)) return result();
|
if(auto result = Eval::integer(expression)) return result();
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void eval(vector<unsigned>& buffer, const string& expression_) {
|
auto eval(vector<uint>& buffer, const string& expression_) -> void {
|
||||||
string expression = expression_;
|
string expression = expression_;
|
||||||
bool function = false;
|
bool function = false;
|
||||||
for(auto& c : expression) {
|
for(auto& c : expression) {
|
||||||
|
@ -68,13 +74,13 @@ struct context {
|
||||||
lstring part = item.split(") ", 1L);
|
lstring part = item.split(") ", 1L);
|
||||||
lstring args = part[0].split(";", 3L).strip();
|
lstring args = part[0].split(";", 3L).strip();
|
||||||
|
|
||||||
unsigned length = eval(args(0, "0"));
|
uint length = eval(args(0, "0"));
|
||||||
unsigned offset = eval(args(1, "0"));
|
uint offset = eval(args(1, "0"));
|
||||||
unsigned stride = eval(args(2, "0"));
|
uint stride = eval(args(2, "0"));
|
||||||
if(args.size() < 2) offset = buffer.size();
|
if(args.size() < 2) offset = buffer.size();
|
||||||
if(args.size() < 3) stride = 1;
|
if(args.size() < 3) stride = 1;
|
||||||
|
|
||||||
for(unsigned n = 0; n < length; n++) {
|
for(uint n = 0; n < length; n++) {
|
||||||
string fn = part[1];
|
string fn = part[1];
|
||||||
fn.replace("n", string{n});
|
fn.replace("n", string{n});
|
||||||
fn.replace("o", string{offset});
|
fn.replace("o", string{offset});
|
||||||
|
@ -84,7 +90,7 @@ struct context {
|
||||||
offset += stride;
|
offset += stride;
|
||||||
}
|
}
|
||||||
} else if(item.match("base64*")) {
|
} else if(item.match("base64*")) {
|
||||||
unsigned offset = 0;
|
uint offset = 0;
|
||||||
item.ltrim("base64", 1L);
|
item.ltrim("base64", 1L);
|
||||||
if(item.match("(?*) *")) {
|
if(item.match("(?*) *")) {
|
||||||
item.ltrim("(", 1L);
|
item.ltrim("(", 1L);
|
||||||
|
@ -110,7 +116,7 @@ struct context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse(const string& data) {
|
auto parse(const string& data) -> void {
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
lstring lines = data.split("\n");
|
lstring lines = data.split("\n");
|
||||||
|
@ -154,14 +160,15 @@ struct context {
|
||||||
sanitize();
|
sanitize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load(const string& filename) {
|
auto load(const string& filename) -> bool {
|
||||||
string filedata = string::read(filename);
|
if(auto filedata = string::read(filename)) {
|
||||||
if(filedata.empty()) return false;
|
parse(filedata);
|
||||||
parse(filedata);
|
return true;
|
||||||
return true;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sanitize() {
|
auto sanitize() -> void {
|
||||||
if(depth < 1) depth = 1;
|
if(depth < 1) depth = 1;
|
||||||
if(depth > 24) depth = 24;
|
if(depth > 24) depth = 24;
|
||||||
|
|
||||||
|
@ -179,43 +186,37 @@ struct context {
|
||||||
for(auto& color : palette) color |= 255u << 24;
|
for(auto& color : palette) color |= 255u << 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
uint offset;
|
||||||
offset = 0;
|
uint width;
|
||||||
width = 0;
|
uint height;
|
||||||
height = 0;
|
uint count;
|
||||||
count = 0;
|
|
||||||
|
|
||||||
endian = 1;
|
bool endian; //0 = lsb, 1 = msb
|
||||||
order = 0;
|
bool order; //0 = linear, 1 = planar
|
||||||
depth = 1;
|
uint depth; //1 - 24bpp
|
||||||
|
|
||||||
blockWidth = 1;
|
uint blockWidth;
|
||||||
blockHeight = 1;
|
uint blockHeight;
|
||||||
blockStride = 0;
|
uint blockStride;
|
||||||
blockOffset = 0;
|
uint blockOffset;
|
||||||
block.reset();
|
vector<uint> block;
|
||||||
|
|
||||||
tileWidth = 1;
|
uint tileWidth;
|
||||||
tileHeight = 1;
|
uint tileHeight;
|
||||||
tileStride = 0;
|
uint tileStride;
|
||||||
tileOffset = 0;
|
uint tileOffset;
|
||||||
tile.reset();
|
vector<uint> tile;
|
||||||
|
|
||||||
mosaicWidth = 1;
|
uint mosaicWidth;
|
||||||
mosaicHeight = 1;
|
uint mosaicHeight;
|
||||||
mosaicStride = 0;
|
uint mosaicStride;
|
||||||
mosaicOffset = 0;
|
uint mosaicOffset;
|
||||||
mosaic.reset();
|
vector<uint> mosaic;
|
||||||
|
|
||||||
paddingWidth = 0;
|
uint paddingWidth;
|
||||||
paddingHeight = 0;
|
uint paddingHeight;
|
||||||
paddingColor = 0;
|
uint paddingColor;
|
||||||
palette.reset();
|
vector<uint> palette;
|
||||||
}
|
|
||||||
|
|
||||||
context() {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,77 +4,72 @@ namespace nall {
|
||||||
namespace mosaic {
|
namespace mosaic {
|
||||||
|
|
||||||
struct parser {
|
struct parser {
|
||||||
image canvas;
|
|
||||||
|
|
||||||
//export from bitstream to canvas
|
//export from bitstream to canvas
|
||||||
void load(bitstream& stream, uint64_t offset, context& ctx, unsigned width, unsigned height) {
|
auto load(bitstream& stream, uint64 offset, context& ctx, uint width, uint height) -> void {
|
||||||
canvas.allocate(width, height);
|
canvas.allocate(width, height);
|
||||||
canvas.fill(ctx.paddingColor);
|
canvas.fill(ctx.paddingColor);
|
||||||
parse(1, stream, offset, ctx, width, height);
|
parse(1, stream, offset, ctx, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
//import from canvas to bitstream
|
//import from canvas to bitstream
|
||||||
bool save(bitstream& stream, uint64_t offset, context& ctx) {
|
auto save(bitstream& stream, uint64_t offset, context& ctx) -> bool {
|
||||||
if(stream.readonly) return false;
|
if(stream.readonly) return false;
|
||||||
parse(0, stream, offset, ctx, canvas.width(), canvas.height());
|
parse(0, stream, offset, ctx, canvas.width(), canvas.height());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline parser() : canvas(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t read(unsigned x, unsigned y) const {
|
auto read(uint x, uint y) const -> uint32 {
|
||||||
unsigned addr = y * canvas.width() + x;
|
uint addr = y * canvas.width() + x;
|
||||||
if(addr >= canvas.width() * canvas.height()) return 0u;
|
if(addr >= canvas.width() * canvas.height()) return 0u;
|
||||||
uint32_t *buffer = (uint32_t*)canvas.data();
|
auto buffer = (uint32*)canvas.data();
|
||||||
return buffer[addr];
|
return buffer[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(unsigned x, unsigned y, uint32_t data) {
|
auto write(uint x, uint y, uint32_t data) -> void {
|
||||||
unsigned addr = y * canvas.width() + x;
|
uint addr = y * canvas.width() + x;
|
||||||
if(addr >= canvas.width() * canvas.height()) return;
|
if(addr >= canvas.width() * canvas.height()) return;
|
||||||
uint32_t *buffer = (uint32_t*)canvas.data();
|
auto buffer = (uint32*)canvas.data();
|
||||||
buffer[addr] = data;
|
buffer[addr] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse(bool load, bitstream& stream, uint64_t offset, context& ctx, unsigned width, unsigned height) {
|
auto parse(bool load, bitstream& stream, uint64 offset, context& ctx, uint width, uint height) -> void {
|
||||||
stream.endian = ctx.endian;
|
stream.endian = ctx.endian;
|
||||||
unsigned canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
|
uint canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
|
||||||
unsigned canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
|
uint canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
|
||||||
unsigned bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
|
uint bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
|
||||||
|
|
||||||
unsigned objectOffset = 0;
|
uint objectOffset = 0;
|
||||||
for(unsigned objectY = 0; objectY < canvasHeight; objectY++) {
|
for(uint objectY = 0; objectY < canvasHeight; objectY++) {
|
||||||
for(unsigned objectX = 0; objectX < canvasWidth; objectX++) {
|
for(uint objectX = 0; objectX < canvasWidth; objectX++) {
|
||||||
if(objectOffset >= ctx.count && ctx.count > 0) break;
|
if(objectOffset >= ctx.count && ctx.count > 0) break;
|
||||||
unsigned objectIX = objectX * ctx.objectWidth();
|
uint objectIX = objectX * ctx.objectWidth();
|
||||||
unsigned objectIY = objectY * ctx.objectHeight();
|
uint objectIY = objectY * ctx.objectHeight();
|
||||||
objectOffset++;
|
objectOffset++;
|
||||||
|
|
||||||
unsigned mosaicOffset = 0;
|
uint mosaicOffset = 0;
|
||||||
for(unsigned mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
|
for(uint mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
|
||||||
for(unsigned mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
|
for(uint mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
|
||||||
unsigned mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
|
uint mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
|
||||||
unsigned mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
|
uint mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
|
||||||
unsigned mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
|
uint mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
|
||||||
mosaicOffset++;
|
mosaicOffset++;
|
||||||
|
|
||||||
unsigned tileOffset = 0;
|
uint tileOffset = 0;
|
||||||
for(unsigned tileY = 0; tileY < ctx.tileHeight; tileY++) {
|
for(uint tileY = 0; tileY < ctx.tileHeight; tileY++) {
|
||||||
for(unsigned tileX = 0; tileX < ctx.tileWidth; tileX++) {
|
for(uint tileX = 0; tileX < ctx.tileWidth; tileX++) {
|
||||||
unsigned tileData = ctx.tile(tileOffset, tileOffset);
|
uint tileData = ctx.tile(tileOffset, tileOffset);
|
||||||
unsigned tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
|
uint tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
|
||||||
unsigned tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
|
uint tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
|
||||||
tileOffset++;
|
tileOffset++;
|
||||||
|
|
||||||
unsigned blockOffset = 0;
|
uint blockOffset = 0;
|
||||||
for(unsigned blockY = 0; blockY < ctx.blockHeight; blockY++) {
|
for(uint blockY = 0; blockY < ctx.blockHeight; blockY++) {
|
||||||
for(unsigned blockX = 0; blockX < ctx.blockWidth; blockX++) {
|
for(uint blockX = 0; blockX < ctx.blockWidth; blockX++) {
|
||||||
if(load) {
|
if(load) {
|
||||||
unsigned palette = 0;
|
uint palette = 0;
|
||||||
for(unsigned n = 0; n < ctx.depth; n++) {
|
for(uint n = 0; n < ctx.depth; n++) {
|
||||||
unsigned index = blockOffset++;
|
uint index = blockOffset++;
|
||||||
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
||||||
palette |= stream.read(offset + ctx.block(index, index)) << n;
|
palette |= stream.read(offset + ctx.block(index, index)) << n;
|
||||||
}
|
}
|
||||||
|
@ -90,8 +85,8 @@ private:
|
||||||
objectIY + mosaicIY + tileIY + blockY
|
objectIY + mosaicIY + tileIY + blockY
|
||||||
);
|
);
|
||||||
|
|
||||||
for(unsigned n = 0; n < ctx.depth; n++) {
|
for(uint n = 0; n < ctx.depth; n++) {
|
||||||
unsigned index = blockOffset++;
|
uint index = blockOffset++;
|
||||||
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
||||||
stream.write(offset + ctx.block(index, index), palette & 1);
|
stream.write(offset + ctx.block(index, index), palette & 1);
|
||||||
palette >>= 1;
|
palette >>= 1;
|
||||||
|
@ -118,6 +113,8 @@ private:
|
||||||
offset += ctx.mosaicOffset;
|
offset += ctx.mosaicOffset;
|
||||||
} //objectY
|
} //objectY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
image canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,17 @@ namespace nall {
|
||||||
|
|
||||||
#define autostream(...) (*makestream(__VA_ARGS__))
|
#define autostream(...) (*makestream(__VA_ARGS__))
|
||||||
|
|
||||||
inline std::unique_ptr<stream> makestream(const string& path) {
|
inline auto makestream(const string& path) -> std::unique_ptr<stream> {
|
||||||
if(path.iendsWith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path}));
|
if(path.iendsWith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path}));
|
||||||
if(path.iendsWith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path}));
|
if(path.iendsWith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path}));
|
||||||
return std::unique_ptr<stream>(new mmapstream(path));
|
return std::unique_ptr<stream>(new mmapstream(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<stream> makestream(uint8_t* data, unsigned size) {
|
inline auto makestream(uint8* data, uint size) -> std::unique_ptr<stream> {
|
||||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
return std::unique_ptr<stream>(new memorystream(data, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<stream> makestream(const uint8_t* data, unsigned size) {
|
inline auto makestream(const uint8* data, uint size) -> std::unique_ptr<stream> {
|
||||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
return std::unique_ptr<stream>(new memorystream(data, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,18 +9,6 @@ struct filestream : stream {
|
||||||
using stream::read;
|
using stream::read;
|
||||||
using stream::write;
|
using stream::write;
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
|
||||||
bool readable() const { return true; }
|
|
||||||
bool writable() const { return pwritable; }
|
|
||||||
bool randomaccess() const { return false; }
|
|
||||||
|
|
||||||
unsigned size() const { return pfile.size(); }
|
|
||||||
unsigned offset() const { return pfile.offset(); }
|
|
||||||
void seek(unsigned offset) const { pfile.seek(offset); }
|
|
||||||
|
|
||||||
uint8_t read() const { return pfile.read(); }
|
|
||||||
void write(uint8_t data) const { pfile.write(data); }
|
|
||||||
|
|
||||||
filestream(const string& filename) {
|
filestream(const string& filename) {
|
||||||
pfile.open(filename, file::mode::readwrite);
|
pfile.open(filename, file::mode::readwrite);
|
||||||
pwritable = pfile.open();
|
pwritable = pfile.open();
|
||||||
|
@ -32,6 +20,18 @@ struct filestream : stream {
|
||||||
pwritable = mode == file::mode::write || mode == file::mode::readwrite;
|
pwritable = mode == file::mode::write || mode == file::mode::readwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto seekable() const -> bool { return true; }
|
||||||
|
auto readable() const -> bool { return true; }
|
||||||
|
auto writable() const -> bool { return pwritable; }
|
||||||
|
auto randomaccess() const -> bool { return false; }
|
||||||
|
|
||||||
|
auto size() const -> uint { return pfile.size(); }
|
||||||
|
auto offset() const -> uint { return pfile.offset(); }
|
||||||
|
auto seek(unsigned offset) const -> void { pfile.seek(offset); }
|
||||||
|
|
||||||
|
auto read() const -> uint8 { return pfile.read(); }
|
||||||
|
auto write(uint8_t data) const -> void { pfile.write(data); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable file pfile;
|
mutable file pfile;
|
||||||
bool pwritable;
|
bool pwritable;
|
||||||
|
|
|
@ -10,14 +10,14 @@ struct gzipstream : memorystream {
|
||||||
using stream::write;
|
using stream::write;
|
||||||
|
|
||||||
gzipstream(const stream& stream) {
|
gzipstream(const stream& stream) {
|
||||||
unsigned size = stream.size();
|
uint size = stream.size();
|
||||||
uint8_t *data = new uint8_t[size];
|
auto data = new uint8[size];
|
||||||
stream.read(data, size);
|
stream.read(data, size);
|
||||||
|
|
||||||
Decode::GZIP archive;
|
Decode::GZIP archive;
|
||||||
bool result = archive.decompress(data, size);
|
bool result = archive.decompress(data, size);
|
||||||
delete[] data;
|
delete[] data;
|
||||||
if(result == false) return;
|
if(!result) return;
|
||||||
|
|
||||||
psize = archive.size;
|
psize = archive.size;
|
||||||
pdata = new uint8_t[psize];
|
pdata = new uint8_t[psize];
|
||||||
|
|
|
@ -9,37 +9,41 @@ struct memorystream : stream {
|
||||||
using stream::read;
|
using stream::read;
|
||||||
using stream::write;
|
using stream::write;
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
memorystream() = default;
|
||||||
bool readable() const { return true; }
|
|
||||||
bool writable() const { return pwritable; }
|
|
||||||
bool randomaccess() const { return true; }
|
|
||||||
|
|
||||||
uint8_t* data() const { return pdata; }
|
memorystream(uint8* data, uint size) {
|
||||||
unsigned size() const { return psize; }
|
pdata = data;
|
||||||
unsigned offset() const { return poffset; }
|
psize = size;
|
||||||
void seek(unsigned offset) const { poffset = offset; }
|
|
||||||
|
|
||||||
uint8_t read() const { return pdata[poffset++]; }
|
|
||||||
void write(uint8_t data) const { pdata[poffset++] = data; }
|
|
||||||
|
|
||||||
uint8_t read(unsigned offset) const { return pdata[offset]; }
|
|
||||||
void write(unsigned offset, uint8_t data) const { pdata[offset] = data; }
|
|
||||||
|
|
||||||
memorystream() : pdata(nullptr), psize(0), poffset(0), pwritable(true) {}
|
|
||||||
|
|
||||||
memorystream(uint8_t* data, unsigned size) {
|
|
||||||
pdata = data, psize = size, poffset = 0;
|
|
||||||
pwritable = true;
|
pwritable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystream(const uint8_t* data, unsigned size) {
|
memorystream(const uint8* data, uint size) {
|
||||||
pdata = (uint8_t*)data, psize = size, poffset = 0;
|
pdata = (uint8*)data;
|
||||||
|
psize = size;
|
||||||
pwritable = false;
|
pwritable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto seekable() const -> bool { return true; }
|
||||||
|
auto readable() const -> bool { return true; }
|
||||||
|
auto writable() const -> bool { return pwritable; }
|
||||||
|
auto randomaccess() const -> bool { return true; }
|
||||||
|
|
||||||
|
auto data() const -> uint8* { return pdata; }
|
||||||
|
auto size() const -> uint { return psize; }
|
||||||
|
auto offset() const -> uint { return poffset; }
|
||||||
|
auto seek(uint offset) const -> void { poffset = offset; }
|
||||||
|
|
||||||
|
auto read() const -> uint8 { return pdata[poffset++]; }
|
||||||
|
auto write(uint8 data) const -> void { pdata[poffset++] = data; }
|
||||||
|
|
||||||
|
auto read(uint offset) const -> uint8 { return pdata[offset]; }
|
||||||
|
auto write(uint offset, uint8 data) const -> void { pdata[offset] = data; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable uint8_t* pdata;
|
mutable uint8* pdata = nullptr;
|
||||||
mutable unsigned psize, poffset, pwritable;
|
mutable uint psize = 0;
|
||||||
|
mutable uint poffset = 0;
|
||||||
|
mutable bool pwritable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,32 +9,34 @@ struct mmapstream : stream {
|
||||||
using stream::read;
|
using stream::read;
|
||||||
using stream::write;
|
using stream::write;
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
|
||||||
bool readable() const { return true; }
|
|
||||||
bool writable() const { return pwritable; }
|
|
||||||
bool randomaccess() const { return true; }
|
|
||||||
|
|
||||||
unsigned size() const { return pmmap.size(); }
|
|
||||||
unsigned offset() const { return poffset; }
|
|
||||||
void seek(unsigned offset) const { poffset = offset; }
|
|
||||||
|
|
||||||
uint8_t read() const { return pdata[poffset++]; }
|
|
||||||
void write(uint8_t data) const { pdata[poffset++] = data; }
|
|
||||||
|
|
||||||
uint8_t read(unsigned offset) const { return pdata[offset]; }
|
|
||||||
void write(unsigned offset, uint8_t data) const { pdata[offset] = data; }
|
|
||||||
|
|
||||||
mmapstream(const string& filename) {
|
mmapstream(const string& filename) {
|
||||||
pmmap.open(filename, filemap::mode::readwrite);
|
pmmap.open(filename, filemap::mode::readwrite);
|
||||||
pwritable = pmmap.open();
|
pwritable = pmmap.open();
|
||||||
if(!pwritable) pmmap.open(filename, filemap::mode::read);
|
if(!pwritable) pmmap.open(filename, filemap::mode::read);
|
||||||
pdata = pmmap.data(), poffset = 0;
|
pdata = pmmap.data();
|
||||||
|
poffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto seekable() const -> bool { return true; }
|
||||||
|
auto readable() const -> bool { return true; }
|
||||||
|
auto writable() const -> bool { return pwritable; }
|
||||||
|
auto randomaccess() const -> bool { return true; }
|
||||||
|
|
||||||
|
auto size() const -> uint { return pmmap.size(); }
|
||||||
|
auto offset() const -> uint { return poffset; }
|
||||||
|
auto seek(unsigned offset) const -> void { poffset = offset; }
|
||||||
|
|
||||||
|
auto read() const -> uint8 { return pdata[poffset++]; }
|
||||||
|
auto write(uint8 data) const -> void { pdata[poffset++] = data; }
|
||||||
|
|
||||||
|
auto read(uint offset) const -> uint8 { return pdata[offset]; }
|
||||||
|
auto write(uint offset, uint8 data) const -> void { pdata[offset] = data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable filemap pmmap;
|
mutable filemap pmmap;
|
||||||
mutable uint8_t* pdata;
|
mutable uint8* pdata = nullptr;
|
||||||
mutable unsigned pwritable, poffset;
|
mutable uint poffset = 0;
|
||||||
|
mutable bool pwritable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,95 +4,96 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct stream {
|
struct stream {
|
||||||
virtual bool seekable() const = 0;
|
stream() = default;
|
||||||
virtual bool readable() const = 0;
|
virtual ~stream() = default;
|
||||||
virtual bool writable() const = 0;
|
|
||||||
virtual bool randomaccess() const = 0;
|
|
||||||
|
|
||||||
virtual uint8_t* data() const { return nullptr; }
|
stream(const stream&) = delete;
|
||||||
virtual unsigned size() const = 0;
|
auto operator=(const stream&) -> stream& = delete;
|
||||||
virtual unsigned offset() const = 0;
|
|
||||||
virtual void seek(unsigned offset) const = 0;
|
|
||||||
|
|
||||||
virtual uint8_t read() const = 0;
|
virtual auto seekable() const -> bool = 0;
|
||||||
virtual void write(uint8_t data) const = 0;
|
virtual auto readable() const -> bool = 0;
|
||||||
|
virtual auto writable() const -> bool = 0;
|
||||||
|
virtual auto randomaccess() const -> bool = 0;
|
||||||
|
|
||||||
virtual uint8_t read(unsigned) const { return 0; }
|
virtual auto data() const -> uint8* { return nullptr; }
|
||||||
virtual void write(unsigned, uint8_t) const {}
|
virtual auto size() const -> uint = 0;
|
||||||
|
virtual auto offset() const -> uint = 0;
|
||||||
|
virtual auto seek(unsigned offset) const -> void = 0;
|
||||||
|
|
||||||
operator bool() const {
|
virtual auto read() const -> uint8 = 0;
|
||||||
|
virtual auto write(uint8_t data) const -> void = 0;
|
||||||
|
|
||||||
|
virtual auto read(uint) const -> uint8 { return 0; }
|
||||||
|
virtual auto write(uint, uint8) const -> void {}
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
return size();
|
return size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
auto empty() const -> bool {
|
||||||
return size() == 0;
|
return size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool end() const {
|
auto end() const -> bool {
|
||||||
return offset() >= size();
|
return offset() >= size();
|
||||||
}
|
}
|
||||||
|
|
||||||
uintmax_t readl(unsigned length = 1) const {
|
auto readl(uint length = 1) const -> uintmax {
|
||||||
uintmax_t data = 0, shift = 0;
|
uintmax data = 0, shift = 0;
|
||||||
while(length--) { data |= read() << shift; shift += 8; }
|
while(length--) { data |= read() << shift; shift += 8; }
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintmax_t readm(unsigned length = 1) const {
|
auto readm(uint length = 1) const -> uintmax {
|
||||||
uintmax_t data = 0;
|
uintmax data = 0;
|
||||||
while(length--) data = (data << 8) | read();
|
while(length--) data = (data << 8) | read();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read(uint8_t* data, unsigned length) const {
|
auto read(uint8* data, uint length) const -> void {
|
||||||
while(length--) *data++ = read();
|
while(length--) *data++ = read();
|
||||||
}
|
}
|
||||||
|
|
||||||
string text() const {
|
auto text() const -> string {
|
||||||
string buffer;
|
string buffer;
|
||||||
buffer.resize(size());
|
buffer.resize(size());
|
||||||
seek(0);
|
seek(0);
|
||||||
read((uint8_t*)buffer.data(), size());
|
read((uint8*)buffer.get(), size());
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writel(uintmax_t data, unsigned length = 1) const {
|
auto writel(uintmax data, uint length = 1) const -> void {
|
||||||
while(length--) {
|
while(length--) {
|
||||||
write(data);
|
write(data);
|
||||||
data >>= 8;
|
data >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writem(uintmax_t data, unsigned length = 1) const {
|
auto writem(uintmax data, uint length = 1) const -> void {
|
||||||
uintmax_t shift = 8 * length;
|
uintmax shift = 8 * length;
|
||||||
while(length--) {
|
while(length--) {
|
||||||
shift -= 8;
|
shift -= 8;
|
||||||
write(data >> shift);
|
write(data >> shift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const uint8_t* data, unsigned length) const {
|
auto write(const uint8* data, uint length) const -> void {
|
||||||
while(length--) write(*data++);
|
while(length--) write(*data++);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct byte {
|
struct byte {
|
||||||
operator uint8_t() const { return s.read(offset); }
|
byte(const stream& s, uint offset) : s(s), offset(offset) {}
|
||||||
byte& operator=(uint8_t data) { s.write(offset, data); return *this; }
|
operator uint8() const { return s.read(offset); }
|
||||||
byte(const stream& s, unsigned offset) : s(s), offset(offset) {}
|
auto operator=(uint8_t data) -> byte& { s.write(offset, data); return *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const stream& s;
|
const stream& s;
|
||||||
const unsigned offset;
|
const uint offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
byte operator[](unsigned offset) const {
|
auto operator[](uint offset) const -> byte {
|
||||||
return byte(*this, offset);
|
return byte(*this, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream() {}
|
|
||||||
virtual ~stream() {}
|
|
||||||
stream(const stream&) = delete;
|
|
||||||
stream& operator=(const stream&) = delete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,28 +10,29 @@ struct vectorstream : stream {
|
||||||
using stream::read;
|
using stream::read;
|
||||||
using stream::write;
|
using stream::write;
|
||||||
|
|
||||||
bool seekable() const { return true; }
|
vectorstream(vector<uint8>& memory) : memory(memory), pwritable(true) {}
|
||||||
bool readable() const { return true; }
|
vectorstream(const vector<uint8>& memory) : memory((vector<uint8>&)memory), pwritable(false) {}
|
||||||
bool writable() const { return pwritable; }
|
|
||||||
bool randomaccess() const { return true; }
|
|
||||||
|
|
||||||
uint8_t* data() const { return memory.data(); }
|
auto seekable() const -> bool { return true; }
|
||||||
unsigned size() const { return memory.size(); }
|
auto readable() const -> bool { return true; }
|
||||||
unsigned offset() const { return poffset; }
|
auto writable() const -> bool { return pwritable; }
|
||||||
void seek(unsigned offset) const { poffset = offset; }
|
auto randomaccess() const -> bool { return true; }
|
||||||
|
|
||||||
uint8_t read() const { return memory[poffset++]; }
|
auto data() const -> uint8* { return memory.data(); }
|
||||||
void write(uint8_t data) const { memory[poffset++] = data; }
|
auto size() const -> uint { return memory.size(); }
|
||||||
|
auto offset() const -> uint { return poffset; }
|
||||||
|
auto seek(unsigned offset) const -> void { poffset = offset; }
|
||||||
|
|
||||||
uint8_t read(unsigned offset) const { return memory[offset]; }
|
auto read() const -> uint8 { return memory[poffset++]; }
|
||||||
void write(unsigned offset, uint8_t data) const { memory[offset] = data; }
|
auto write(uint8 data) const -> void { memory[poffset++] = data; }
|
||||||
|
|
||||||
vectorstream(vector<uint8_t>& memory) : memory(memory), poffset(0), pwritable(true) {}
|
auto read(uint offset) const -> uint8 { return memory[offset]; }
|
||||||
vectorstream(const vector<uint8_t>& memory) : memory((vector<uint8_t>&)memory), poffset(0), pwritable(false) {}
|
auto write(uint offset, uint8 data) const -> void { memory[offset] = data; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
vector<uint8_t>& memory;
|
vector<uint8>& memory;
|
||||||
mutable unsigned poffset, pwritable;
|
mutable uint poffset = 0;
|
||||||
|
mutable bool pwritable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ struct zipstream : memorystream {
|
||||||
using stream::write;
|
using stream::write;
|
||||||
|
|
||||||
zipstream(const stream& stream, const string& filter = "*") {
|
zipstream(const stream& stream, const string& filter = "*") {
|
||||||
unsigned size = stream.size();
|
uint size = stream.size();
|
||||||
uint8_t* data = new uint8_t[size];
|
auto data = new uint8[size];
|
||||||
stream.read(data, size);
|
stream.read(data, size);
|
||||||
|
|
||||||
Decode::ZIP archive;
|
Decode::ZIP archive;
|
||||||
|
|
|
@ -13,18 +13,18 @@ namespace nall {
|
||||||
#define RelNear 1
|
#define RelNear 1
|
||||||
|
|
||||||
struct detour {
|
struct detour {
|
||||||
static bool insert(const string& moduleName, const string& functionName, void*& source, void* target);
|
static auto insert(const string& moduleName, const string& functionName, void*& source, void* target) -> bool;
|
||||||
static bool remove(const string& moduleName, const string& functionName, void*& source);
|
static auto remove(const string& moduleName, const string& functionName, void*& source) -> bool;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static unsigned length(const uint8_t* function);
|
static auto length(const uint8* function) -> uint;
|
||||||
static unsigned mirror(uint8_t* target, const uint8_t* source);
|
static auto mirror(uint8* target, const uint8* source) -> uint;
|
||||||
|
|
||||||
struct opcode {
|
struct opcode {
|
||||||
uint16_t prefix;
|
uint16 prefix;
|
||||||
unsigned length;
|
uint length;
|
||||||
unsigned mode;
|
uint mode;
|
||||||
uint16_t modify;
|
uint16 modify;
|
||||||
};
|
};
|
||||||
static opcode opcodes[];
|
static opcode opcodes[];
|
||||||
};
|
};
|
||||||
|
@ -33,61 +33,61 @@ protected:
|
||||||
//* fs:, gs: should force another opcode copy
|
//* fs:, gs: should force another opcode copy
|
||||||
//* conditional branches within +5-byte range should fail
|
//* conditional branches within +5-byte range should fail
|
||||||
detour::opcode detour::opcodes[] = {
|
detour::opcode detour::opcodes[] = {
|
||||||
{ 0x50, 1 }, //push eax
|
{0x50, 1}, //push eax
|
||||||
{ 0x51, 1 }, //push ecx
|
{0x51, 1}, //push ecx
|
||||||
{ 0x52, 1 }, //push edx
|
{0x52, 1}, //push edx
|
||||||
{ 0x53, 1 }, //push ebx
|
{0x53, 1}, //push ebx
|
||||||
{ 0x54, 1 }, //push esp
|
{0x54, 1}, //push esp
|
||||||
{ 0x55, 1 }, //push ebp
|
{0x55, 1}, //push ebp
|
||||||
{ 0x56, 1 }, //push esi
|
{0x56, 1}, //push esi
|
||||||
{ 0x57, 1 }, //push edi
|
{0x57, 1}, //push edi
|
||||||
{ 0x58, 1 }, //pop eax
|
{0x58, 1}, //pop eax
|
||||||
{ 0x59, 1 }, //pop ecx
|
{0x59, 1}, //pop ecx
|
||||||
{ 0x5a, 1 }, //pop edx
|
{0x5a, 1}, //pop edx
|
||||||
{ 0x5b, 1 }, //pop ebx
|
{0x5b, 1}, //pop ebx
|
||||||
{ 0x5c, 1 }, //pop esp
|
{0x5c, 1}, //pop esp
|
||||||
{ 0x5d, 1 }, //pop ebp
|
{0x5d, 1}, //pop ebp
|
||||||
{ 0x5e, 1 }, //pop esi
|
{0x5e, 1}, //pop esi
|
||||||
{ 0x5f, 1 }, //pop edi
|
{0x5f, 1}, //pop edi
|
||||||
{ 0x64, 1 }, //fs:
|
{0x64, 1}, //fs:
|
||||||
{ 0x65, 1 }, //gs:
|
{0x65, 1}, //gs:
|
||||||
{ 0x68, 5 }, //push dword
|
{0x68, 5}, //push dword
|
||||||
{ 0x6a, 2 }, //push byte
|
{0x6a, 2}, //push byte
|
||||||
{ 0x74, 2, RelNear, 0x0f84 }, //je near -> je far
|
{0x74, 2, RelNear, 0x0f84}, //je near -> je far
|
||||||
{ 0x75, 2, RelNear, 0x0f85 }, //jne near -> jne far
|
{0x75, 2, RelNear, 0x0f85}, //jne near -> jne far
|
||||||
{ 0x89, 2 }, //mov reg,reg
|
{0x89, 2}, //mov reg,reg
|
||||||
{ 0x8b, 2 }, //mov reg,reg
|
{0x8b, 2}, //mov reg,reg
|
||||||
{ 0x90, 1 }, //nop
|
{0x90, 1}, //nop
|
||||||
{ 0xa1, 5 }, //mov eax,[dword]
|
{0xa1, 5}, //mov eax,[dword]
|
||||||
{ 0xeb, 2, RelNear, 0xe9 }, //jmp near -> jmp far
|
{0xeb, 2, RelNear, 0xe9}, //jmp near -> jmp far
|
||||||
};
|
};
|
||||||
|
|
||||||
bool detour::insert(const string& moduleName, const string& functionName, void*& source, void* target) {
|
auto detour::insert(const string& moduleName, const string& functionName, void*& source, void* target) -> bool {
|
||||||
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
||||||
if(!module) return false;
|
if(!module) return false;
|
||||||
|
|
||||||
uint8_t* sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
uint8* sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
||||||
if(!sourceData) return false;
|
if(!sourceData) return false;
|
||||||
|
|
||||||
unsigned sourceLength = detour::length(sourceData);
|
uint sourceLength = detour::length(sourceData);
|
||||||
if(sourceLength < 5) {
|
if(sourceLength < 5) {
|
||||||
//unable to clone enough bytes to insert hook
|
//unable to clone enough bytes to insert hook
|
||||||
#if 1
|
#if 1
|
||||||
string output = { "detour::insert(", moduleName, "::", functionName, ") failed: " };
|
string output = {"detour::insert(", moduleName, "::", functionName, ") failed: "};
|
||||||
for(unsigned n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " ");
|
for(uint n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " ");
|
||||||
output.rtrim(" ", 1L);
|
output.rtrim(" ", 1L);
|
||||||
MessageBoxA(0, output, "nall::detour", MB_OK);
|
MessageBoxA(0, output, "nall::detour", MB_OK);
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* mirrorData = new uint8_t[512]();
|
auto mirrorData = new uint8[512]();
|
||||||
detour::mirror(mirrorData, sourceData);
|
detour::mirror(mirrorData, sourceData);
|
||||||
|
|
||||||
DWORD privileges;
|
DWORD privileges;
|
||||||
VirtualProtect((void*)mirrorData, 512, PAGE_EXECUTE_READWRITE, &privileges);
|
VirtualProtect((void*)mirrorData, 512, PAGE_EXECUTE_READWRITE, &privileges);
|
||||||
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
||||||
uintmax_t address = (uintmax_t)target - ((uintmax_t)sourceData + 5);
|
uintmax address = (uintmax)target - ((uintmax)sourceData + 5);
|
||||||
sourceData[0] = 0xe9; //jmp target
|
sourceData[0] = 0xe9; //jmp target
|
||||||
sourceData[1] = address >> 0;
|
sourceData[1] = address >> 0;
|
||||||
sourceData[2] = address >> 8;
|
sourceData[2] = address >> 8;
|
||||||
|
@ -99,22 +99,22 @@ bool detour::insert(const string& moduleName, const string& functionName, void*&
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool detour::remove(const string& moduleName, const string& functionName, void*& source) {
|
auto detour::remove(const string& moduleName, const string& functionName, void*& source) -> bool {
|
||||||
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
|
||||||
if(!module) return false;
|
if(!module) return false;
|
||||||
|
|
||||||
uint8_t* sourceData = (uint8_t*)GetProcAddress(module, functionName);
|
auto sourceData = (uint8*)GetProcAddress(module, functionName);
|
||||||
if(!sourceData) return false;
|
if(!sourceData) return false;
|
||||||
|
|
||||||
uint8_t* mirrorData = (uint8_t*)source;
|
auto mirrorData = (uint8*)source;
|
||||||
if(mirrorData == sourceData) return false; //hook was never installed
|
if(mirrorData == sourceData) return false; //hook was never installed
|
||||||
|
|
||||||
unsigned length = detour::length(256 + mirrorData);
|
uint length = detour::length(256 + mirrorData);
|
||||||
if(length < 5) return false;
|
if(length < 5) return false;
|
||||||
|
|
||||||
DWORD privileges;
|
DWORD privileges;
|
||||||
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
|
||||||
for(unsigned n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n];
|
for(uint n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n];
|
||||||
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
|
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
|
||||||
|
|
||||||
source = (void*)sourceData;
|
source = (void*)sourceData;
|
||||||
|
@ -122,8 +122,8 @@ bool detour::remove(const string& moduleName, const string& functionName, void*&
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned detour::length(const uint8_t* function) {
|
auto detour::length(const uint8* function) -> uint {
|
||||||
unsigned length = 0;
|
uint length = 0;
|
||||||
while(length < 5) {
|
while(length < 5) {
|
||||||
detour::opcode *opcode = 0;
|
detour::opcode *opcode = 0;
|
||||||
foreach(op, detour::opcodes) {
|
foreach(op, detour::opcodes) {
|
||||||
|
@ -138,13 +138,13 @@ unsigned detour::length(const uint8_t* function) {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned detour::mirror(uint8_t* target, const uint8_t* source) {
|
auto detour::mirror(uint8* target, const uint8* source) -> uint {
|
||||||
const uint8_t *entryPoint = source;
|
const uint8* entryPoint = source;
|
||||||
for(unsigned n = 0; n < 256; n++) target[256 + n] = source[n];
|
for(uint n = 0; n < 256; n++) target[256 + n] = source[n];
|
||||||
|
|
||||||
unsigned size = detour::length(source);
|
uint size = detour::length(source);
|
||||||
while(size) {
|
while(size) {
|
||||||
detour::opcode *opcode = 0;
|
detour::opcode* opcode = nullptr;
|
||||||
foreach(op, detour::opcodes) {
|
foreach(op, detour::opcodes) {
|
||||||
if(*source == op.prefix) {
|
if(*source == op.prefix) {
|
||||||
opcode = &op;
|
opcode = &op;
|
||||||
|
@ -154,15 +154,15 @@ unsigned detour::mirror(uint8_t* target, const uint8_t* source) {
|
||||||
|
|
||||||
switch(opcode->mode) {
|
switch(opcode->mode) {
|
||||||
case Copy:
|
case Copy:
|
||||||
for(unsigned n = 0; n < opcode->length; n++) *target++ = *source++;
|
for(uint n = 0; n < opcode->length; n++) *target++ = *source++;
|
||||||
break;
|
break;
|
||||||
case RelNear: {
|
case RelNear: {
|
||||||
source++;
|
source++;
|
||||||
uintmax_t sourceAddress = (uintmax_t)source + 1 + (int8_t)*source;
|
uintmax sourceAddress = (uintmax)source + 1 + (int8)*source;
|
||||||
*target++ = opcode->modify;
|
*target++ = opcode->modify;
|
||||||
if(opcode->modify >> 8) *target++ = opcode->modify >> 8;
|
if(opcode->modify >> 8) *target++ = opcode->modify >> 8;
|
||||||
uintmax_t targetAddress = (uintmax_t)target + 4;
|
uintmax targetAddress = (uintmax)target + 4;
|
||||||
uintmax_t address = sourceAddress - targetAddress;
|
uintmax address = sourceAddress - targetAddress;
|
||||||
*target++ = address >> 0;
|
*target++ = address >> 0;
|
||||||
*target++ = address >> 8;
|
*target++ = address >> 8;
|
||||||
*target++ = address >> 16;
|
*target++ = address >> 16;
|
||||||
|
@ -174,7 +174,7 @@ unsigned detour::mirror(uint8_t* target, const uint8_t* source) {
|
||||||
size -= opcode->length;
|
size -= opcode->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintmax_t address = (entryPoint + detour::length(entryPoint)) - (target + 5);
|
uintmax address = (entryPoint + detour::length(entryPoint)) - (target + 5);
|
||||||
*target++ = 0xe9; //jmp entryPoint
|
*target++ = 0xe9; //jmp entryPoint
|
||||||
*target++ = address >> 0;
|
*target++ = address >> 0;
|
||||||
*target++ = address >> 8;
|
*target++ = address >> 8;
|
||||||
|
|
|
@ -7,21 +7,21 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
//generate unique GUID
|
//generate unique GUID
|
||||||
inline string guid() {
|
inline auto guid() -> string {
|
||||||
LinearFeedbackShiftRegisterGenerator lfsr;
|
LinearFeedbackShiftRegisterGenerator lfsr;
|
||||||
lfsr.seed(time(nullptr));
|
lfsr.seed(time(nullptr));
|
||||||
for(unsigned n = 0; n < 256; n++) lfsr();
|
for(uint n = 0; n < 256; n++) lfsr();
|
||||||
|
|
||||||
string output;
|
string output;
|
||||||
for(unsigned n = 0; n < 4; n++) output.append(hex(lfsr(), 2L));
|
for(uint n = 0; n < 4; n++) output.append(hex(lfsr(), 2L));
|
||||||
output.append("-");
|
output.append("-");
|
||||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||||
output.append("-");
|
output.append("-");
|
||||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||||
output.append("-");
|
output.append("-");
|
||||||
for(unsigned n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L));
|
||||||
output.append("-");
|
output.append("-");
|
||||||
for(unsigned n = 0; n < 6; n++) output.append(hex(lfsr(), 2L));
|
for(uint n = 0; n < 6; n++) output.append(hex(lfsr(), 2L));
|
||||||
return {"{", output, "}"};
|
return {"{", output, "}"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace nall {
|
||||||
|
|
||||||
//launch a new process and inject specified DLL into it
|
//launch a new process and inject specified DLL into it
|
||||||
|
|
||||||
bool launch(const char* applicationName, const char* libraryName, uint32_t entryPoint) {
|
auto launch(const char* applicationName, const char* libraryName, uint32 entryPoint) -> bool {
|
||||||
//if a launcher does not send at least one message, a wait cursor will appear
|
//if a launcher does not send at least one message, a wait cursor will appear
|
||||||
PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
|
PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
@ -22,19 +22,19 @@ bool launch(const char* applicationName, const char* libraryName, uint32_t entry
|
||||||
);
|
);
|
||||||
if(result == false) return false;
|
if(result == false) return false;
|
||||||
|
|
||||||
uint8_t entryData[1024], entryHook[1024] = {
|
uint8 entryData[1024], entryHook[1024] = {
|
||||||
0x68, 0x00, 0x00, 0x00, 0x00, //push libraryName
|
0x68, 0x00, 0x00, 0x00, 0x00, //push libraryName
|
||||||
0xb8, 0x00, 0x00, 0x00, 0x00, //mov eax,LoadLibraryW
|
0xb8, 0x00, 0x00, 0x00, 0x00, //mov eax,LoadLibraryW
|
||||||
0xff, 0xd0, //call eax
|
0xff, 0xd0, //call eax
|
||||||
0xcd, 0x03, //int 3
|
0xcd, 0x03, //int 3
|
||||||
};
|
};
|
||||||
|
|
||||||
entryHook[1] = (uint8_t)((entryPoint + 14) >> 0);
|
entryHook[1] = (uint8)((entryPoint + 14) >> 0);
|
||||||
entryHook[2] = (uint8_t)((entryPoint + 14) >> 8);
|
entryHook[2] = (uint8)((entryPoint + 14) >> 8);
|
||||||
entryHook[3] = (uint8_t)((entryPoint + 14) >> 16);
|
entryHook[3] = (uint8)((entryPoint + 14) >> 16);
|
||||||
entryHook[4] = (uint8_t)((entryPoint + 14) >> 24);
|
entryHook[4] = (uint8)((entryPoint + 14) >> 24);
|
||||||
|
|
||||||
uint32_t pLoadLibraryW = (uint32_t)GetProcAddress(GetModuleHandleW(L"kernel32"), "LoadLibraryW");
|
auto pLoadLibraryW = (uint32)GetProcAddress(GetModuleHandleW(L"kernel32"), "LoadLibraryW");
|
||||||
entryHook[6] = pLoadLibraryW >> 0;
|
entryHook[6] = pLoadLibraryW >> 0;
|
||||||
entryHook[7] = pLoadLibraryW >> 8;
|
entryHook[7] = pLoadLibraryW >> 8;
|
||||||
entryHook[8] = pLoadLibraryW >> 16;
|
entryHook[8] = pLoadLibraryW >> 16;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct registry {
|
struct registry {
|
||||||
static bool exists(const string& name) {
|
static auto exists(const string& name) -> bool {
|
||||||
lstring part = name.split("/");
|
lstring part = name.split("/");
|
||||||
HKEY handle, rootKey = root(part.take(0));
|
HKEY handle, rootKey = root(part.take(0));
|
||||||
string node = part.take();
|
string node = part.take();
|
||||||
|
@ -39,7 +39,7 @@ struct registry {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string read(const string& name) {
|
static auto read(const string& name) -> string {
|
||||||
lstring part = name.split("/");
|
lstring part = name.split("/");
|
||||||
HKEY handle, rootKey = root(part.take(0));
|
HKEY handle, rootKey = root(part.take(0));
|
||||||
string node = part.take();
|
string node = part.take();
|
||||||
|
@ -54,12 +54,12 @@ struct registry {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write(const string& name, const string& data = "") {
|
static auto write(const string& name, const string& data = "") -> void {
|
||||||
lstring part = name.split("/");
|
lstring part = name.split("/");
|
||||||
HKEY handle, rootKey = root(part.take(0));
|
HKEY handle, rootKey = root(part.take(0));
|
||||||
string node = part.take(), path;
|
string node = part.take(), path;
|
||||||
DWORD disposition;
|
DWORD disposition;
|
||||||
for(unsigned n = 0; n < part.size(); n++) {
|
for(uint n = 0; n < part.size(); n++) {
|
||||||
path.append(part[n]);
|
path.append(part[n]);
|
||||||
if(RegCreateKeyExW(rootKey, utf16_t(path), 0, nullptr, 0, NWR_FLAGS | KEY_ALL_ACCESS, nullptr, &handle, &disposition) == ERROR_SUCCESS) {
|
if(RegCreateKeyExW(rootKey, utf16_t(path), 0, nullptr, 0, NWR_FLAGS | KEY_ALL_ACCESS, nullptr, &handle, &disposition) == ERROR_SUCCESS) {
|
||||||
if(n == part.size() - 1) {
|
if(n == part.size() - 1) {
|
||||||
|
@ -71,7 +71,7 @@ struct registry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool remove(const string& name) {
|
static auto remove(const string& name) -> bool {
|
||||||
lstring part = name.split("/");
|
lstring part = name.split("/");
|
||||||
HKEY rootKey = root(part.take(0));
|
HKEY rootKey = root(part.take(0));
|
||||||
string node = part.take();
|
string node = part.take();
|
||||||
|
@ -80,7 +80,7 @@ struct registry {
|
||||||
return SHDeleteValueW(rootKey, utf16_t(path), utf16_t(node)) == ERROR_SUCCESS;
|
return SHDeleteValueW(rootKey, utf16_t(path), utf16_t(node)) == ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static lstring contents(const string& name) {
|
static auto contents(const string& name) -> lstring {
|
||||||
lstring part = name.split("/"), result;
|
lstring part = name.split("/"), result;
|
||||||
HKEY handle, rootKey = root(part.take(0));
|
HKEY handle, rootKey = root(part.take(0));
|
||||||
part.remove();
|
part.remove();
|
||||||
|
@ -88,13 +88,13 @@ struct registry {
|
||||||
if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) {
|
if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) {
|
||||||
DWORD folders, nodes;
|
DWORD folders, nodes;
|
||||||
RegQueryInfoKey(handle, nullptr, nullptr, nullptr, &folders, nullptr, nullptr, &nodes, nullptr, nullptr, nullptr, nullptr);
|
RegQueryInfoKey(handle, nullptr, nullptr, nullptr, &folders, nullptr, nullptr, &nodes, nullptr, nullptr, nullptr, nullptr);
|
||||||
for(unsigned n = 0; n < folders; n++) {
|
for(uint n = 0; n < folders; n++) {
|
||||||
wchar_t name[NWR_SIZE] = L"";
|
wchar_t name[NWR_SIZE] = L"";
|
||||||
DWORD size = NWR_SIZE * sizeof(wchar_t);
|
DWORD size = NWR_SIZE * sizeof(wchar_t);
|
||||||
RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr);
|
RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr);
|
||||||
result.append(string{(const char*)utf8_t(name), "/"});
|
result.append(string{(const char*)utf8_t(name), "/"});
|
||||||
}
|
}
|
||||||
for(unsigned n = 0; n < nodes; n++) {
|
for(uint n = 0; n < nodes; n++) {
|
||||||
wchar_t name[NWR_SIZE] = L"";
|
wchar_t name[NWR_SIZE] = L"";
|
||||||
DWORD size = NWR_SIZE * sizeof(wchar_t);
|
DWORD size = NWR_SIZE * sizeof(wchar_t);
|
||||||
RegEnumValueW(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr);
|
RegEnumValueW(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr);
|
||||||
|
@ -106,7 +106,7 @@ struct registry {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static HKEY root(const string& name) {
|
static auto root(const string& name) -> HKEY {
|
||||||
if(name == "HKCR") return HKEY_CLASSES_ROOT;
|
if(name == "HKCR") return HKEY_CLASSES_ROOT;
|
||||||
if(name == "HKCC") return HKEY_CURRENT_CONFIG;
|
if(name == "HKCC") return HKEY_CURRENT_CONFIG;
|
||||||
if(name == "HKCU") return HKEY_CURRENT_USER;
|
if(name == "HKCU") return HKEY_CURRENT_USER;
|
||||||
|
|
|
@ -14,14 +14,14 @@ struct shared_memory {
|
||||||
|
|
||||||
explicit operator bool() const { return false; }
|
explicit operator bool() const { return false; }
|
||||||
auto empty() const -> bool { return true; }
|
auto empty() const -> bool { return true; }
|
||||||
auto size() const -> unsigned { return 0; }
|
auto size() const -> uint { return 0; }
|
||||||
auto acquired() const -> bool { return false; }
|
auto acquired() const -> bool { return false; }
|
||||||
auto acquire() -> uint8_t* { return nullptr; }
|
auto acquire() -> uint8* { return nullptr; }
|
||||||
auto release() -> void {}
|
auto release() -> void {}
|
||||||
auto reset() -> void {}
|
auto reset() -> void {}
|
||||||
auto create(const string& name, unsigned size) -> bool { return false; }
|
auto create(const string& name, uint size) -> bool { return false; }
|
||||||
auto remove() -> void {}
|
auto remove() -> void {}
|
||||||
auto open(const string& name, unsigned size) -> bool { return false; }
|
auto open(const string& name, uint size) -> bool { return false; }
|
||||||
auto close() -> void {}
|
auto close() -> void {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define NALL_UTF8_HPP
|
#define NALL_UTF8_HPP
|
||||||
|
|
||||||
//UTF-8 <> UTF-16 conversion
|
//UTF-8 <> UTF-16 conversion
|
||||||
//used only for Win32; Linux, etc use UTF-8 internally
|
//used only for Win32; every other OS uses UTF-8 internally
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
@ -21,17 +21,9 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
//UTF-8 to UTF-16
|
//UTF-8 to UTF-16
|
||||||
struct utf16_t {
|
struct utf16_t {
|
||||||
operator wchar_t*() {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator const wchar_t*() const {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
utf16_t(const char* s = "") {
|
utf16_t(const char* s = "") {
|
||||||
if(!s) s = "";
|
if(!s) s = "";
|
||||||
unsigned length = MultiByteToWideChar(CP_UTF8, 0, s, -1, nullptr, 0);
|
uint length = MultiByteToWideChar(CP_UTF8, 0, s, -1, nullptr, 0);
|
||||||
buffer = new wchar_t[length + 1]();
|
buffer = new wchar_t[length + 1]();
|
||||||
MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length);
|
MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length);
|
||||||
}
|
}
|
||||||
|
@ -40,23 +32,23 @@ namespace nall {
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator wchar_t*() {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator const wchar_t*() const {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wchar_t* buffer;
|
wchar_t* buffer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
//UTF-16 to UTF-8
|
//UTF-16 to UTF-8
|
||||||
struct utf8_t {
|
struct utf8_t {
|
||||||
operator char*() {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator const char*() const {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
utf8_t(const wchar_t* s = L"") {
|
utf8_t(const wchar_t* s = L"") {
|
||||||
if(!s) s = L"";
|
if(!s) s = L"";
|
||||||
unsigned length = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, nullptr, nullptr);
|
uint length = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, nullptr, nullptr);
|
||||||
buffer = new char[length + 1]();
|
buffer = new char[length + 1]();
|
||||||
WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, nullptr, nullptr);
|
WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -68,14 +60,22 @@ namespace nall {
|
||||||
utf8_t(const utf8_t&) = delete;
|
utf8_t(const utf8_t&) = delete;
|
||||||
utf8_t& operator=(const utf8_t&) = delete;
|
utf8_t& operator=(const utf8_t&) = delete;
|
||||||
|
|
||||||
|
operator char*() {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator const char*() const {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* buffer;
|
char* buffer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void utf8_args(int& argc, char**& argv) {
|
inline auto utf8_args(int& argc, char**& argv) -> void {
|
||||||
wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||||
argv = new char*[argc];
|
argv = new char*[argc];
|
||||||
for(unsigned i = 0; i < argc; i++) {
|
for(uint i = 0; i < argc; i++) {
|
||||||
argv[i] = new char[PATH_MAX];
|
argv[i] = new char[PATH_MAX];
|
||||||
strcpy(argv[i], nall::utf8_t(wargv[i]));
|
strcpy(argv[i], nall::utf8_t(wargv[i]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,15 +29,15 @@ struct Cartridge : property<Cartridge> {
|
||||||
readonly<bool> hasSufamiTurboSlots;
|
readonly<bool> hasSufamiTurboSlots;
|
||||||
|
|
||||||
struct Mapping {
|
struct Mapping {
|
||||||
function<uint8 (unsigned)> reader;
|
function<auto (uint, uint8) -> uint8> reader;
|
||||||
function<void (unsigned, uint8)> writer;
|
function<auto (uint, uint8) -> void> writer;
|
||||||
string addr;
|
string addr;
|
||||||
unsigned size = 0;
|
uint size = 0;
|
||||||
unsigned base = 0;
|
uint base = 0;
|
||||||
unsigned mask = 0;
|
uint mask = 0;
|
||||||
|
|
||||||
Mapping() = default;
|
Mapping() = default;
|
||||||
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
|
Mapping(const function<uint8 (uint, uint8)>&, const function<void (uint, uint8)>&);
|
||||||
Mapping(SuperFamicom::Memory&);
|
Mapping(SuperFamicom::Memory&);
|
||||||
};
|
};
|
||||||
vector<Mapping> mapping;
|
vector<Mapping> mapping;
|
||||||
|
|
|
@ -3,7 +3,7 @@ Cartridge::Mapping::Mapping(SuperFamicom::Memory& memory) {
|
||||||
this->writer = {&SuperFamicom::Memory::write, &memory};
|
this->writer = {&SuperFamicom::Memory::write, &memory};
|
||||||
}
|
}
|
||||||
|
|
||||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)>& reader, const function<void (unsigned, uint8)>& writer) {
|
Cartridge::Mapping::Mapping(const function<uint8 (uint, uint8)>& reader, const function<void (uint, uint8)>& writer) {
|
||||||
this->reader = reader;
|
this->reader = reader;
|
||||||
this->writer = writer;
|
this->writer = writer;
|
||||||
}
|
}
|
||||||
|
@ -217,13 +217,13 @@ auto Cartridge::parseMarkupEvent(Markup::Node root) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].text() == "dr") {
|
if(node["id"].text() == "dr") {
|
||||||
Mapping m([](unsigned) -> uint8 { return cpu.regs.mdr; }, {&Event::dr, &event});
|
Mapping m([](uint, uint8 data) -> uint8 { return data; }, {&Event::dr, &event});
|
||||||
parseMarkupMap(m, node);
|
parseMarkupMap(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node["id"].text() == "sr") {
|
if(node["id"].text() == "sr") {
|
||||||
Mapping m({&Event::sr, &event}, [](unsigned, uint8) {});
|
Mapping m({&Event::sr, &event}, [](uint, uint8) {});
|
||||||
parseMarkupMap(m, node);
|
parseMarkupMap(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
@ -326,7 +326,7 @@ auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, unsigned roms) -> void {
|
auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, uint roms) -> void {
|
||||||
hasHitachiDSP = true;
|
hasHitachiDSP = true;
|
||||||
|
|
||||||
auto rom = root.find("rom");
|
auto rom = root.find("rom");
|
||||||
|
|
|
@ -52,14 +52,14 @@ auto ArmDSP::enter() -> void {
|
||||||
auto ArmDSP::step(uint clocks) -> void {
|
auto ArmDSP::step(uint clocks) -> void {
|
||||||
if(bridge.timer && --bridge.timer == 0);
|
if(bridge.timer && --bridge.timer == 0);
|
||||||
Coprocessor::step(clocks);
|
Coprocessor::step(clocks);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
|
|
||||||
//MMIO: $00-3f|80-bf:3800-38ff
|
//MMIO: $00-3f|80-bf:3800-38ff
|
||||||
//3800-3807 mirrored throughout
|
//3800-3807 mirrored throughout
|
||||||
//a0 ignored
|
//a0 ignored
|
||||||
|
|
||||||
auto ArmDSP::mmio_read(uint addr) -> uint8 {
|
auto ArmDSP::mmio_read(uint addr, uint8) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
|
|
||||||
uint8 data = 0x00;
|
uint8 data = 0x00;
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct ArmDSP : Processor::ARM, Coprocessor {
|
||||||
auto bus_read(uint mode, uint32 addr) -> uint32 override;
|
auto bus_read(uint mode, uint32 addr) -> uint32 override;
|
||||||
auto bus_write(uint mode, uint32 addr, uint32 word) -> void override;
|
auto bus_write(uint mode, uint32 addr, uint32 word) -> void override;
|
||||||
|
|
||||||
auto mmio_read(uint addr) -> uint8;
|
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmio_write(uint addr, uint8 data) -> void;
|
auto mmio_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto init() -> void;
|
auto init() -> void;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
struct Coprocessor : Thread {
|
struct Coprocessor : Thread {
|
||||||
alwaysinline auto step(uint clocks) -> void;
|
alwaysinline auto step(uint clocks) -> void;
|
||||||
alwaysinline auto synchronize_cpu() -> void;
|
alwaysinline auto synchronizeCPU() -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <sfc/coprocessor/icd2/icd2.hpp>
|
#include <sfc/coprocessor/icd2/icd2.hpp>
|
||||||
|
@ -28,6 +28,6 @@ auto Coprocessor::step(uint clocks) -> void {
|
||||||
clock += clocks * (uint64)cpu.frequency;
|
clock += clocks * (uint64)cpu.frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Coprocessor::synchronize_cpu() -> void {
|
auto Coprocessor::synchronizeCPU() -> void {
|
||||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ auto EpsonRTC::enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
step(1);
|
step(1);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ auto EpsonRTC::sync() -> void {
|
||||||
resync = true; //alert program that time has changed
|
resync = true; //alert program that time has changed
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EpsonRTC::read(uint addr) -> uint8 {
|
auto EpsonRTC::read(uint addr, uint8 data) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
addr &= 3;
|
addr &= 3;
|
||||||
|
|
||||||
|
@ -162,6 +162,8 @@ auto EpsonRTC::read(uint addr) -> uint8 {
|
||||||
if(addr == 2) {
|
if(addr == 2) {
|
||||||
return ready << 7;
|
return ready << 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EpsonRTC::write(uint addr, uint8 data) -> void {
|
auto EpsonRTC::write(uint addr, uint8 data) -> void {
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct EpsonRTC : Coprocessor {
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
auto sync() -> void;
|
auto sync() -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -28,7 +28,7 @@ auto Event::enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
step(1);
|
step(1);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ auto Event::reset() -> void {
|
||||||
scoreSecondsRemaining = 0;
|
scoreSecondsRemaining = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Event::sr(uint) -> uint8 {
|
auto Event::sr(uint, uint8) -> uint8 {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ auto Event::dr(uint, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Event::rom_read(uint addr) -> uint8 {
|
auto Event::rom_read(uint addr, uint8 data) -> uint8 {
|
||||||
if(board == Board::CampusChallenge92) {
|
if(board == Board::CampusChallenge92) {
|
||||||
uint id = 0;
|
uint id = 0;
|
||||||
if(select == 0x09) id = 1;
|
if(select == 0x09) id = 1;
|
||||||
|
@ -82,7 +82,7 @@ auto Event::rom_read(uint addr) -> uint8 {
|
||||||
|
|
||||||
if(addr & 0x008000) {
|
if(addr & 0x008000) {
|
||||||
addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
||||||
return rom[id].read(bus.mirror(addr, rom[id].size()));
|
return rom[id].read(bus.mirror(addr, rom[id].size()), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,21 +95,21 @@ auto Event::rom_read(uint addr) -> uint8 {
|
||||||
|
|
||||||
if(addr & 0x400000) {
|
if(addr & 0x400000) {
|
||||||
addr &= 0x3fffff;
|
addr &= 0x3fffff;
|
||||||
return rom[id].read(bus.mirror(addr, rom[id].size()));
|
return rom[id].read(bus.mirror(addr, rom[id].size()), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(addr & 0x008000) {
|
if(addr & 0x008000) {
|
||||||
addr &= 0x1fffff;
|
addr &= 0x1fffff;
|
||||||
if(id != 2) addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
|
if(id != 2) addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
|
||||||
return rom[id].read(bus.mirror(addr, rom[id].size()));
|
return rom[id].read(bus.mirror(addr, rom[id].size()), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Event::ram_read(uint addr) -> uint8 {
|
auto Event::ram_read(uint addr, uint8 data) -> uint8 {
|
||||||
return ram.read(bus.mirror(addr, ram.size()));
|
return ram.read(bus.mirror(addr, ram.size()), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Event::ram_write(uint addr, uint8 data) -> void {
|
auto Event::ram_write(uint addr, uint8 data) -> void {
|
||||||
|
|
|
@ -13,10 +13,10 @@ struct Event : Coprocessor {
|
||||||
|
|
||||||
auto submitScore() -> void;
|
auto submitScore() -> void;
|
||||||
|
|
||||||
auto sr(uint) -> uint8;
|
auto sr(uint, uint8) -> uint8;
|
||||||
auto dr(uint, uint8 data) -> void;
|
auto dr(uint, uint8 data) -> void;
|
||||||
auto rom_read(uint addr) -> uint8;
|
auto rom_read(uint addr, uint8) -> uint8;
|
||||||
auto ram_read(uint addr) -> uint8;
|
auto ram_read(uint addr, uint8) -> uint8;
|
||||||
auto ram_write(uint addr, uint8 data) -> void;
|
auto ram_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -16,7 +16,8 @@ auto HitachiDSP::enter() -> void {
|
||||||
|
|
||||||
if(mmio.dma) {
|
if(mmio.dma) {
|
||||||
for(auto n : range(mmio.dma_length)) {
|
for(auto n : range(mmio.dma_length)) {
|
||||||
bus.write(mmio.dma_target + n, bus.read(mmio.dma_source + n));
|
//todo: access internally, not from Bus
|
||||||
|
bus.write(mmio.dma_target + n, bus.read(mmio.dma_source + n, 0));
|
||||||
step(2);
|
step(2);
|
||||||
}
|
}
|
||||||
mmio.dma = false;
|
mmio.dma = false;
|
||||||
|
@ -25,7 +26,7 @@ auto HitachiDSP::enter() -> void {
|
||||||
exec(mmio.program_offset);
|
exec(mmio.program_offset);
|
||||||
step(1);
|
step(1);
|
||||||
|
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,15 +18,15 @@ struct HitachiDSP : Processor::HG51B, Coprocessor {
|
||||||
auto bus_write(uint24 addr, uint8 data) -> void;
|
auto bus_write(uint24 addr, uint8 data) -> void;
|
||||||
|
|
||||||
//CPU ROM read/write
|
//CPU ROM read/write
|
||||||
auto rom_read(uint addr) -> uint8;
|
auto rom_read(uint addr, uint8 data) -> uint8;
|
||||||
auto rom_write(uint addr, uint8 data) -> void;
|
auto rom_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
//CPU RAM read/write
|
//CPU RAM read/write
|
||||||
auto ram_read(uint addr) -> uint8;
|
auto ram_read(uint addr, uint8 data) -> uint8;
|
||||||
auto ram_write(uint addr, uint8 data) -> void;
|
auto ram_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
//CPU MMIO read/write
|
//CPU MMIO read/write
|
||||||
auto dsp_read(uint addr) -> uint8;
|
auto dsp_read(uint addr, uint8 data) -> uint8;
|
||||||
auto dsp_write(uint addr, uint8 data) -> void;
|
auto dsp_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto firmware() const -> vector<uint8>;
|
auto firmware() const -> vector<uint8>;
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
auto HitachiDSP::bus_read(uint24 addr) -> uint8 {
|
auto HitachiDSP::bus_read(uint24 addr) -> uint8 {
|
||||||
if((addr & 0x408000) == 0x008000) return bus.read(addr); //$00-3f,80-bf:6000-7fff
|
//todo: read internally, not from Bus
|
||||||
if((addr & 0xf88000) == 0x700000) return bus.read(addr); //$70-77:0000-7fff
|
if((addr & 0x408000) == 0x008000) return bus.read(addr, 0); //$00-3f,80-bf:6000-7fff
|
||||||
|
if((addr & 0xf88000) == 0x700000) return bus.read(addr, 0); //$70-77:0000-7fff
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HitachiDSP::bus_write(uint24 addr, uint8 data) -> void {
|
auto HitachiDSP::bus_write(uint24 addr, uint8 data) -> void {
|
||||||
|
//todo: write internally, not to Bus
|
||||||
if((addr & 0x40e000) == 0x006000) return bus.write(addr, data); //$00-3f,80-bf:6000-7fff
|
if((addr & 0x40e000) == 0x006000) return bus.write(addr, data); //$00-3f,80-bf:6000-7fff
|
||||||
if((addr & 0xf88000) == 0x700000) return bus.write(addr, data); //$70-77:0000-7fff
|
if((addr & 0xf88000) == 0x700000) return bus.write(addr, data); //$70-77:0000-7fff
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HitachiDSP::rom_read(uint addr) -> uint8 {
|
auto HitachiDSP::rom_read(uint addr, uint8 data) -> uint8 {
|
||||||
if(co_active() == hitachidsp.thread || regs.halt) {
|
if(co_active() == hitachidsp.thread || regs.halt) {
|
||||||
addr = bus.mirror(addr, rom.size());
|
addr = bus.mirror(addr, rom.size());
|
||||||
//if(Roms == 2 && mmio.r1f52 == 1 && addr >= (bit::round(rom.size()) >> 1)) return 0x00;
|
//if(Roms == 2 && mmio.r1f52 == 1 && addr >= (bit::round(rom.size()) >> 1)) return 0x00;
|
||||||
return rom.read(addr);
|
return rom.read(addr, data);
|
||||||
}
|
}
|
||||||
if((addr & 0x40ffe0) == 0x00ffe0) return mmio.vector[addr & 0x1f];
|
if((addr & 0x40ffe0) == 0x00ffe0) return mmio.vector[addr & 0x1f];
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HitachiDSP::rom_write(uint addr, uint8 data) -> void {
|
auto HitachiDSP::rom_write(uint addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HitachiDSP::ram_read(uint addr) -> uint8 {
|
auto HitachiDSP::ram_read(uint addr, uint8 data) -> uint8 {
|
||||||
if(ram.size() == 0) return 0x00; //not open bus
|
if(ram.size() == 0) return 0x00; //not open bus
|
||||||
return ram.read(bus.mirror(addr, ram.size()));
|
return ram.read(bus.mirror(addr, ram.size()), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HitachiDSP::ram_write(uint addr, uint8 data) -> void {
|
auto HitachiDSP::ram_write(uint addr, uint8 data) -> void {
|
||||||
|
@ -32,7 +34,7 @@ auto HitachiDSP::ram_write(uint addr, uint8 data) -> void {
|
||||||
return ram.write(bus.mirror(addr, ram.size()), data);
|
return ram.write(bus.mirror(addr, ram.size()), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HitachiDSP::dsp_read(uint addr) -> uint8 {
|
auto HitachiDSP::dsp_read(uint addr, uint8) -> uint8 {
|
||||||
addr &= 0x1fff;
|
addr &= 0x1fff;
|
||||||
|
|
||||||
//Data RAM
|
//Data RAM
|
||||||
|
|
|
@ -24,7 +24,7 @@ auto ICD2::enter() -> void {
|
||||||
audio.coprocessor_sample(0x0000, 0x0000);
|
audio.coprocessor_sample(0x0000, 0x0000);
|
||||||
step(1);
|
step(1);
|
||||||
}
|
}
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Coprocessor {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
auto ICD2::read(uint addr) -> uint8 {
|
auto ICD2::read(uint addr, uint8 data) -> uint8 {
|
||||||
addr &= 0xffff;
|
addr &= 0x40ffff;
|
||||||
|
|
||||||
//LY counter
|
//LY counter
|
||||||
if(addr == 0x6000) {
|
if(addr == 0x6000) {
|
||||||
|
@ -9,7 +9,7 @@ auto ICD2::read(uint addr) -> uint8 {
|
||||||
|
|
||||||
//command ready port
|
//command ready port
|
||||||
if(addr == 0x6002) {
|
if(addr == 0x6002) {
|
||||||
bool data = packetsize > 0;
|
data = packetsize > 0;
|
||||||
if(data) {
|
if(data) {
|
||||||
for(auto n : range(16)) r7000[n] = packet[0][n];
|
for(auto n : range(16)) r7000[n] = packet[0][n];
|
||||||
packetsize--;
|
packetsize--;
|
||||||
|
@ -24,13 +24,13 @@ auto ICD2::read(uint addr) -> uint8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
//command port
|
//command port
|
||||||
if((addr & 0xfff0) == 0x7000) {
|
if((addr & 0x40fff0) == 0x7000) {
|
||||||
return r7000[addr & 15];
|
return r7000[addr & 15];
|
||||||
}
|
}
|
||||||
|
|
||||||
//VRAM port
|
//VRAM port
|
||||||
if(addr == 0x7800) {
|
if(addr == 0x7800) {
|
||||||
uint8 data = output[read_bank * 512 + read_addr];
|
data = output[read_bank * 512 + read_addr];
|
||||||
read_addr = (read_addr + 1) & 511;
|
read_addr = (read_addr + 1) & 511;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,13 +28,13 @@ auto MCC::reset() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MCC::memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8 {
|
auto MCC::memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8 {
|
||||||
if(write == 0) return memory_read(memory, addr);
|
if(write == 0) return memory_read(memory, addr, data);
|
||||||
memory_write(memory, addr, data);
|
memory_write(memory, addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MCC::memory_read(Memory& memory, uint addr) -> uint8 {
|
auto MCC::memory_read(Memory& memory, uint addr, uint8 data) -> uint8 {
|
||||||
addr = bus.mirror(addr, memory.size());
|
addr = bus.mirror(addr, memory.size());
|
||||||
return memory.read(addr);
|
return memory.read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MCC::memory_write(Memory& memory, uint addr, uint8 data) -> void {
|
auto MCC::memory_write(Memory& memory, uint addr, uint8 data) -> void {
|
||||||
|
@ -86,25 +86,25 @@ auto MCC::mcu_access(bool write, uint addr, uint8 data) -> uint8 {
|
||||||
return memory_access(write, memory, addr & 0x7fffff, data);
|
return memory_access(write, memory, addr & 0x7fffff, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MCC::mcu_read(uint addr) -> uint8 {
|
auto MCC::mcu_read(uint addr, uint8 data) -> uint8 {
|
||||||
return mcu_access(0, addr);
|
return mcu_access(0, addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MCC::mcu_write(uint addr, uint8 data) -> void {
|
auto MCC::mcu_write(uint addr, uint8 data) -> void {
|
||||||
mcu_access(1, addr, data);
|
mcu_access(1, addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MCC::mmio_read(uint addr) -> uint8 {
|
auto MCC::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||||
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
|
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
|
||||||
uint8 n = (addr >> 16) & 15;
|
uint8 n = (addr >> 16) & 15;
|
||||||
return r[n];
|
return r[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
|
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
|
||||||
return memory_read(ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
|
return memory_read(ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0x00;
|
return 0x00;
|
||||||
|
|
|
@ -12,14 +12,14 @@ struct MCC {
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8;
|
auto memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8;
|
||||||
auto memory_read(Memory& memory, uint addr) -> uint8;
|
auto memory_read(Memory& memory, uint addr, uint8 data) -> uint8;
|
||||||
auto memory_write(Memory& memory, uint addr, uint8 data) -> void;
|
auto memory_write(Memory& memory, uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mcu_access(bool write, uint addr, uint8 data = 0x00) -> uint8;
|
auto mcu_access(bool write, uint addr, uint8 data) -> uint8;
|
||||||
auto mcu_read(uint addr) -> uint8;
|
auto mcu_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mcu_write(uint addr, uint8 data) -> void;
|
auto mcu_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mmio_read(uint addr) -> uint8;
|
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmio_write(uint addr, uint8 data) -> void;
|
auto mmio_write(uint addr, uint8 data) -> void;
|
||||||
auto mmio_commit() -> void;
|
auto mmio_commit() -> void;
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ auto MSU1::enter() -> void {
|
||||||
|
|
||||||
audio.coprocessor_sample(left, right);
|
audio.coprocessor_sample(left, right);
|
||||||
step(1);
|
step(1);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ auto MSU1::audioOpen() -> void {
|
||||||
mmio.audioError = true;
|
mmio.audioError = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MSU1::mmioRead(uint addr) -> uint8 {
|
auto MSU1::mmioRead(uint addr, uint8) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
addr = 0x2000 | (addr & 7);
|
addr = 0x2000 | (addr & 7);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct MSU1 : Coprocessor {
|
||||||
auto dataOpen() -> void;
|
auto dataOpen() -> void;
|
||||||
auto audioOpen() -> void;
|
auto audioOpen() -> void;
|
||||||
|
|
||||||
auto mmioRead(uint addr) -> uint8;
|
auto mmioRead(uint addr, uint8 data) -> uint8;
|
||||||
auto mmioWrite(uint addr, uint8 data) -> void;
|
auto mmioWrite(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -15,11 +15,11 @@ auto NECDSP::enter() -> void {
|
||||||
|
|
||||||
exec();
|
exec();
|
||||||
step(1);
|
step(1);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto NECDSP::read(uint addr) -> uint8 {
|
auto NECDSP::read(uint addr, uint8) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
if(addr & Select) {
|
if(addr & Select) {
|
||||||
return uPD96050::readSR();
|
return uPD96050::readSR();
|
||||||
|
@ -37,7 +37,7 @@ auto NECDSP::write(uint addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto NECDSP::readRAM(uint addr) -> uint8 {
|
auto NECDSP::readRAM(uint addr, uint8) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
return uPD96050::readDP(addr);
|
return uPD96050::readDP(addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@ struct NECDSP : Processor::uPD96050, Coprocessor {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto enter() -> void;
|
auto enter() -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto readRAM(uint addr) -> uint8;
|
auto readRAM(uint addr, uint8 data) -> uint8;
|
||||||
auto writeRAM(uint addr, uint8 data) -> void;
|
auto writeRAM(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto init() -> void;
|
auto init() -> void;
|
||||||
|
|
|
@ -23,11 +23,11 @@ auto NSS::set_dip(uint16 dip) -> void {
|
||||||
this->dip = dip;
|
this->dip = dip;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto NSS::read(uint addr) -> uint8 {
|
auto NSS::read(uint, uint8) -> uint8 {
|
||||||
return dip;
|
return dip;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto NSS::write(uint addr, uint8 data) -> void {
|
auto NSS::write(uint, uint8) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ struct NSS {
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto set_dip(uint16 dip) -> void;
|
auto set_dip(uint16 dip) -> void;
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
uint8 dip = 0x00;
|
uint8 dip = 0x00;
|
||||||
|
|
|
@ -24,7 +24,7 @@ auto OBC1::reset() -> void {
|
||||||
status.shift = (ramRead(0x1ff6) & 3) << 1;
|
status.shift = (ramRead(0x1ff6) & 3) << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto OBC1::read(uint addr) -> uint8 {
|
auto OBC1::read(uint addr, uint8) -> uint8 {
|
||||||
addr &= 0x1fff;
|
addr &= 0x1fff;
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ struct OBC1 {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -4,7 +4,7 @@ auto SA1::CPUIRAM::size() const -> uint {
|
||||||
return sa1.iram.size();
|
return sa1.iram.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::CPUIRAM::read(uint addr) -> uint8 {
|
auto SA1::CPUIRAM::read(uint addr, uint8) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
return sa1.iram.read(addr & 0x07ff);
|
return sa1.iram.read(addr & 0x07ff);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ auto SA1::CPUBWRAM::size() const -> uint {
|
||||||
return sa1.bwram.size();
|
return sa1.bwram.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::CPUBWRAM::read(uint addr) -> uint8 {
|
auto SA1::CPUBWRAM::read(uint addr, uint8) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
if(dma) return sa1.dma_cc1_read(addr);
|
if(dma) return sa1.dma_cc1_read(addr);
|
||||||
return sa1.bwram.read(addr);
|
return sa1.bwram.read(addr);
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
struct CPUIRAM : Memory {
|
struct CPUIRAM : Memory {
|
||||||
auto size() const -> uint;
|
auto size() const -> uint;
|
||||||
alwaysinline auto read(uint) -> uint8;
|
alwaysinline auto read(uint, uint8 = 0) -> uint8;
|
||||||
alwaysinline auto write(uint, uint8) -> void;
|
alwaysinline auto write(uint, uint8) -> void;
|
||||||
} cpuiram;
|
} cpuiram;
|
||||||
|
|
||||||
struct CPUBWRAM : Memory {
|
struct CPUBWRAM : Memory {
|
||||||
auto size() const -> uint;
|
auto size() const -> uint;
|
||||||
alwaysinline auto read(uint) -> uint8;
|
alwaysinline auto read(uint, uint8 = 0) -> uint8;
|
||||||
alwaysinline auto write(uint, uint8) -> void;
|
alwaysinline auto write(uint, uint8) -> void;
|
||||||
bool dma;
|
bool dma;
|
||||||
} cpubwram;
|
} cpubwram;
|
||||||
|
|
|
@ -15,13 +15,13 @@ auto SA1::dma_normal() -> void {
|
||||||
switch(mmio.sd) {
|
switch(mmio.sd) {
|
||||||
case DMA::SourceROM:
|
case DMA::SourceROM:
|
||||||
if((dsa & 0x408000) == 0x008000 || (dsa & 0xc00000) == 0xc00000) {
|
if((dsa & 0x408000) == 0x008000 || (dsa & 0xc00000) == 0xc00000) {
|
||||||
data = bus_read(dsa);
|
data = bus_read(dsa, data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DMA::SourceBWRAM:
|
case DMA::SourceBWRAM:
|
||||||
if((dsa & 0x40e000) == 0x006000 || (dsa & 0xf00000) == 0x400000) {
|
if((dsa & 0x40e000) == 0x006000 || (dsa & 0xf00000) == 0x400000) {
|
||||||
data = bus_read(dsa);
|
data = bus_read(dsa, data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,42 @@
|
||||||
auto SA1::bus_read(uint addr) -> uint8 {
|
auto SA1::bus_read(uint addr, uint8 data) -> uint8 {
|
||||||
if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff
|
if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff
|
||||||
return mmio_read(addr);
|
return mmio_read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
||||||
return mmcrom_read(addr);
|
return mmcrom_read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
|
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
|
||||||
return mmcrom_read(addr);
|
return mmcrom_read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||||
return mmc_sa1_read(addr);
|
return mmc_sa1_read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return iram.read(addr & 2047);
|
return iram.read(addr & 2047, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return iram.read(addr & 2047);
|
return iram.read(addr & 2047, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return bwram.read(addr & (bwram.size() - 1));
|
return bwram.read(addr & (bwram.size() - 1), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
|
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return bitmap_read(addr & 0x0fffff);
|
return bitmap_read(addr & 0x0fffff, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//unmapped region
|
//unmapped region
|
||||||
return regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::bus_write(uint addr, uint8 data) -> void {
|
auto SA1::bus_write(uint addr, uint8 data) -> void {
|
||||||
|
@ -49,22 +49,22 @@ auto SA1::bus_write(uint addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return iram.write(addr & 2047, data);
|
return iram.write(addr & 2047, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return iram.write(addr & 2047, data);
|
return iram.write(addr & 2047, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return bwram.write(addr & (bwram.size() - 1), data);
|
return bwram.write(addr & (bwram.size() - 1), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
|
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
return bitmap_write(addr & 0x0fffff, data);
|
return bitmap_write(addr & 0x0fffff, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,29 +73,29 @@ auto SA1::bus_write(uint addr, uint8 data) -> void {
|
||||||
//this is used both to keep VBR-reads from accessing MMIO registers, and
|
//this is used both to keep VBR-reads from accessing MMIO registers, and
|
||||||
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
|
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
|
||||||
//these ports.
|
//these ports.
|
||||||
auto SA1::vbr_read(uint addr) -> uint8 {
|
auto SA1::vbr_read(uint addr, uint8 data) -> uint8 {
|
||||||
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
||||||
return mmcrom_read(addr);
|
return mmcrom_read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
|
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
|
||||||
return mmcrom_read(addr);
|
return mmcrom_read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||||
return bwram.read(addr & (bwram.size() - 1));
|
return bwram.read(addr & (bwram.size() - 1), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||||
return bwram.read(addr & (bwram.size() - 1));
|
return bwram.read(addr & (bwram.size() - 1), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||||
return iram.read(addr & 2047);
|
return iram.read(addr & 2047, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||||
return iram.read(addr & 2047);
|
return iram.read(addr & 2047, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0x00;
|
return 0x00;
|
||||||
|
@ -113,7 +113,7 @@ auto SA1::op_io() -> void {
|
||||||
auto SA1::op_read(uint addr) -> uint8 {
|
auto SA1::op_read(uint addr) -> uint8 {
|
||||||
tick();
|
tick();
|
||||||
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
|
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
|
||||||
return bus_read(addr);
|
return bus_read(addr, regs.mdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::op_write(uint addr, uint8 data) -> void {
|
auto SA1::op_write(uint addr, uint8 data) -> void {
|
||||||
|
@ -122,7 +122,7 @@ auto SA1::op_write(uint addr, uint8 data) -> void {
|
||||||
bus_write(addr, regs.mdr = data);
|
bus_write(addr, regs.mdr = data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::mmcrom_read(uint addr) -> uint8 {
|
auto SA1::mmcrom_read(uint addr, uint8) -> uint8 {
|
||||||
if((addr & 0xffffe0) == 0x00ffe0) {
|
if((addr & 0xffffe0) == 0x00ffe0) {
|
||||||
if(addr == 0xffea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
|
if(addr == 0xffea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
|
||||||
if(addr == 0xffeb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
|
if(addr == 0xffeb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
|
||||||
|
@ -180,7 +180,7 @@ auto SA1::mmcrom_read(uint addr) -> uint8 {
|
||||||
auto SA1::mmcrom_write(uint addr, uint8 data) -> void {
|
auto SA1::mmcrom_write(uint addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::mmcbwram_read(uint addr) -> uint8 {
|
auto SA1::mmcbwram_read(uint addr, uint8 data) -> uint8 {
|
||||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
|
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
|
||||||
|
@ -191,7 +191,7 @@ auto SA1::mmcbwram_read(uint addr) -> uint8 {
|
||||||
return cpubwram.read(addr & 0x0fffff);
|
return cpubwram.read(addr & 0x0fffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::mmcbwram_write(uint addr, uint8 data) -> void {
|
auto SA1::mmcbwram_write(uint addr, uint8 data) -> void {
|
||||||
|
@ -206,21 +206,21 @@ auto SA1::mmcbwram_write(uint addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::mmc_sa1_read(uint addr) -> uint8 {
|
auto SA1::mmc_sa1_read(uint addr, uint8 data) -> uint8 {
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
if(mmio.sw46 == 0) {
|
if(mmio.sw46 == 0) {
|
||||||
//$40-43:0000-ffff x 32 projection
|
//$40-43:0000-ffff x 32 projection
|
||||||
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), bwram.size());
|
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), bwram.size());
|
||||||
return bwram.read(addr);
|
return bwram.read(addr, data);
|
||||||
} else {
|
} else {
|
||||||
//$60-6f:0000-ffff x 128 projection
|
//$60-6f:0000-ffff x 128 projection
|
||||||
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000);
|
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000);
|
||||||
return bitmap_read(addr);
|
return bitmap_read(addr, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::mmc_sa1_write(uint addr, uint8 data) -> void {
|
auto SA1::mmc_sa1_write(uint addr, uint8 data) -> void {
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
if(mmio.sw46 == 0) {
|
if(mmio.sw46 == 0) {
|
||||||
//$40-43:0000-ffff x 32 projection
|
//$40-43:0000-ffff x 32 projection
|
||||||
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), bwram.size());
|
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), bwram.size());
|
||||||
|
@ -232,7 +232,7 @@ auto SA1::mmc_sa1_write(uint addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::bitmap_read(uint addr) -> uint8 {
|
auto SA1::bitmap_read(uint addr, uint8 data) -> uint8 {
|
||||||
if(mmio.bbf == 0) {
|
if(mmio.bbf == 0) {
|
||||||
//4bpp
|
//4bpp
|
||||||
uint shift = addr & 1;
|
uint shift = addr & 1;
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
auto bus_read(uint addr) -> uint8;
|
auto bus_read(uint addr, uint8 data) -> uint8;
|
||||||
auto bus_write(uint addr, uint8 data) -> void;
|
auto bus_write(uint addr, uint8 data) -> void;
|
||||||
auto vbr_read(uint addr) -> uint8;
|
auto vbr_read(uint addr, uint8 data = 0) -> uint8;
|
||||||
|
|
||||||
alwaysinline auto op_io() -> void;
|
alwaysinline auto op_io() -> void;
|
||||||
alwaysinline auto op_read(uint addr) -> uint8;
|
alwaysinline auto op_read(uint addr) -> uint8;
|
||||||
alwaysinline auto op_write(uint addr, uint8 data) -> void;
|
alwaysinline auto op_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mmcrom_read(uint addr) -> uint8;
|
auto mmcrom_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmcrom_write(uint addr, uint8 data) -> void;
|
auto mmcrom_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mmcbwram_read(uint addr) -> uint8;
|
auto mmcbwram_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmcbwram_write(uint addr, uint8 data) -> void;
|
auto mmcbwram_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mmc_sa1_read(uint addr) -> uint8;
|
auto mmc_sa1_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmc_sa1_write(uint addr, uint8 data) -> void;
|
auto mmc_sa1_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto bitmap_read(uint addr) -> uint8;
|
auto bitmap_read(uint addr, uint8 data) -> uint8;
|
||||||
auto bitmap_write(uint addr, uint8 data) -> void;
|
auto bitmap_write(uint addr, uint8 data) -> void;
|
||||||
|
|
|
@ -445,8 +445,8 @@ auto SA1::mmio_r230e() -> uint8 {
|
||||||
return 0x01; //true value unknown
|
return 0x01; //true value unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::mmio_read(uint addr) -> uint8 {
|
auto SA1::mmio_read(uint addr, uint8) -> uint8 {
|
||||||
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronize_cpu());
|
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronizeCPU());
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
|
@ -471,7 +471,7 @@ auto SA1::mmio_read(uint addr) -> uint8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::mmio_write(uint addr, uint8 data) -> void {
|
auto SA1::mmio_write(uint addr, uint8 data) -> void {
|
||||||
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronize_cpu());
|
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronizeCPU());
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
auto mmio_read(uint addr) -> uint8;
|
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmio_write(uint addr, uint8 data) -> void;
|
auto mmio_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
struct MMIO {
|
struct MMIO {
|
||||||
|
|
|
@ -21,7 +21,7 @@ auto SA1::enter() -> void {
|
||||||
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||||
//SA-1 co-processor is asleep
|
//SA-1 co-processor is asleep
|
||||||
tick();
|
tick();
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ auto SA1::interrupt_pending() -> bool {
|
||||||
|
|
||||||
auto SA1::tick() -> void {
|
auto SA1::tick() -> void {
|
||||||
step(2);
|
step(2);
|
||||||
if(++status.tick_counter == 0) synchronize_cpu();
|
if(++status.tick_counter == 0) synchronizeCPU();
|
||||||
|
|
||||||
//adjust counters:
|
//adjust counters:
|
||||||
//note that internally, status counters are in clocks;
|
//note that internally, status counters are in clocks;
|
||||||
|
|
|
@ -41,11 +41,11 @@ auto SDD1::reset() -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SDD1::read(uint addr) -> uint8 {
|
auto SDD1::read(uint addr, uint8 data) -> uint8 {
|
||||||
addr &= 0xffff;
|
addr &= 0x40ffff;
|
||||||
|
|
||||||
if((addr & 0x4380) == 0x4300) {
|
if((addr & 0x404380) == 0x4300) {
|
||||||
return cpu.mmio_read(addr);
|
return cpu.mmio_read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
|
@ -55,7 +55,7 @@ auto SDD1::read(uint addr) -> uint8 {
|
||||||
case 0x4807: return mmc[3] >> 20;
|
case 0x4807: return mmc[3] >> 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SDD1::write(uint addr, uint8 data) -> void {
|
auto SDD1::write(uint addr, uint8 data) -> void {
|
||||||
|
@ -107,7 +107,7 @@ auto SDD1::mmc_read(uint addr) -> uint8 {
|
||||||
//
|
//
|
||||||
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
|
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
|
||||||
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
|
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
|
||||||
auto SDD1::mcurom_read(uint addr) -> uint8 {
|
auto SDD1::mcurom_read(uint addr, uint8) -> uint8 {
|
||||||
if(addr < 0x400000) { //(addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
if(addr < 0x400000) { //(addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
||||||
return rom.read(addr);
|
return rom.read(addr);
|
||||||
//addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
//addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
|
||||||
|
@ -147,16 +147,16 @@ auto SDD1::mcurom_read(uint addr) -> uint8 {
|
||||||
auto SDD1::mcurom_write(uint addr, uint8 data) -> void {
|
auto SDD1::mcurom_write(uint addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SDD1::mcuram_read(uint addr) -> uint8 {
|
auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 {
|
||||||
if((addr & 0x60e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
if((addr & 0x60e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||||
return ram.read(addr & 0x1fff);
|
return ram.read(addr & 0x1fff, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff
|
if((addr & 0xf08000) == 0x700000) { //$70-7f:0000-7fff
|
||||||
return ram.read(addr & 0x1fff);
|
return ram.read(addr & 0x1fff, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SDD1::mcuram_write(uint addr, uint8 data) -> void {
|
auto SDD1::mcuram_write(uint addr, uint8 data) -> void {
|
||||||
|
|
|
@ -5,15 +5,15 @@ struct SDD1 {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mmc_read(uint addr) -> uint8;
|
auto mmc_read(uint addr) -> uint8;
|
||||||
|
|
||||||
auto mcurom_read(uint addr) -> uint8;
|
auto mcurom_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mcurom_write(uint addr, uint8 data) -> void;
|
auto mcurom_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mcuram_read(uint addr) -> uint8;
|
auto mcuram_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mcuram_write(uint addr, uint8 data) -> void;
|
auto mcuram_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -7,11 +7,11 @@ namespace SuperFamicom {
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
SharpRTC sharprtc;
|
SharpRTC sharprtc;
|
||||||
|
|
||||||
void SharpRTC::Enter() {
|
auto SharpRTC::Enter() -> void {
|
||||||
sharprtc.enter();
|
sharprtc.enter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::enter() {
|
auto SharpRTC::enter() -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
@ -20,14 +20,14 @@ void SharpRTC::enter() {
|
||||||
tick_second();
|
tick_second();
|
||||||
|
|
||||||
step(1);
|
step(1);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::init() {
|
auto SharpRTC::init() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::load() {
|
auto SharpRTC::load() -> void {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
second = 0;
|
second = 0;
|
||||||
|
@ -39,20 +39,20 @@ void SharpRTC::load() {
|
||||||
weekday = 0;
|
weekday = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::unload() {
|
auto SharpRTC::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::power() {
|
auto SharpRTC::power() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::reset() {
|
auto SharpRTC::reset() -> void {
|
||||||
create(SharpRTC::Enter, 1);
|
create(SharpRTC::Enter, 1);
|
||||||
|
|
||||||
rtc_state = State::Read;
|
rtc_state = State::Read;
|
||||||
rtc_index = -1;
|
rtc_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::sync() {
|
auto SharpRTC::sync() -> void {
|
||||||
time_t systime = time(0);
|
time_t systime = time(0);
|
||||||
tm* timeinfo = localtime(&systime);
|
tm* timeinfo = localtime(&systime);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ void SharpRTC::sync() {
|
||||||
weekday = timeinfo->tm_wday;
|
weekday = timeinfo->tm_wday;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 SharpRTC::read(unsigned addr) {
|
auto SharpRTC::read(uint addr, uint8 data) -> uint8 {
|
||||||
addr &= 1;
|
addr &= 1;
|
||||||
|
|
||||||
if(addr == 0) {
|
if(addr == 0) {
|
||||||
|
@ -82,10 +82,10 @@ uint8 SharpRTC::read(unsigned addr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::write(unsigned addr, uint8 data) {
|
auto SharpRTC::write(uint addr, uint8 data) -> void {
|
||||||
addr &= 1, data &= 15;
|
addr &= 1, data &= 15;
|
||||||
|
|
||||||
if(addr == 1) {
|
if(addr == 1) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ struct SharpRTC : Coprocessor {
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
auto sync() -> void;
|
auto sync() -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -34,7 +34,7 @@ auto SPC7110::enter() -> void {
|
||||||
|
|
||||||
auto SPC7110::add_clocks(uint clocks) -> void {
|
auto SPC7110::add_clocks(uint clocks) -> void {
|
||||||
step(clocks);
|
step(clocks);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC7110::init() -> void {
|
auto SPC7110::init() -> void {
|
||||||
|
@ -109,7 +109,7 @@ auto SPC7110::reset() -> void {
|
||||||
r4834 = 0x00;
|
r4834 = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC7110::read(uint addr) -> uint8 {
|
auto SPC7110::read(uint addr, uint8 data) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
if((addr & 0xff0000) == 0x500000) addr = 0x4800;
|
if((addr & 0xff0000) == 0x500000) addr = 0x4800;
|
||||||
addr = 0x4800 | (addr & 0x3f);
|
addr = 0x4800 | (addr & 0x3f);
|
||||||
|
@ -145,7 +145,7 @@ auto SPC7110::read(uint addr) -> uint8 {
|
||||||
//==============
|
//==============
|
||||||
|
|
||||||
case 0x4810: {
|
case 0x4810: {
|
||||||
uint8 data = r4810;
|
data = r4810;
|
||||||
data_port_increment_4810();
|
data_port_increment_4810();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ auto SPC7110::read(uint addr) -> uint8 {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC7110::write(uint addr, uint8 data) -> void {
|
auto SPC7110::write(uint addr, uint8 data) -> void {
|
||||||
|
@ -264,7 +264,7 @@ auto SPC7110::write(uint addr, uint8 data) -> void {
|
||||||
//SPC7110::MCUROM
|
//SPC7110::MCUROM
|
||||||
//===============
|
//===============
|
||||||
|
|
||||||
auto SPC7110::mcurom_read(uint addr) -> uint8 {
|
auto SPC7110::mcurom_read(uint addr, uint8 data) -> uint8 {
|
||||||
uint mask = (1 << (r4834 & 3)) - 1; //8mbit, 16mbit, 32mbit, 64mbit DROM
|
uint mask = (1 << (r4834 & 3)) - 1; //8mbit, 16mbit, 32mbit, 64mbit DROM
|
||||||
|
|
||||||
if((addr & 0x708000) == 0x008000 //$00-0f|80-8f:8000-ffff
|
if((addr & 0x708000) == 0x008000 //$00-0f|80-8f:8000-ffff
|
||||||
|
@ -305,7 +305,7 @@ auto SPC7110::mcurom_read(uint addr) -> uint8 {
|
||||||
return datarom_read(addr);
|
return datarom_read(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SPC7110::mcurom_write(uint addr, uint8 data) -> void {
|
auto SPC7110::mcurom_write(uint addr, uint8 data) -> void {
|
||||||
|
@ -315,7 +315,7 @@ auto SPC7110::mcurom_write(uint addr, uint8 data) -> void {
|
||||||
//SPC7110::MCURAM
|
//SPC7110::MCURAM
|
||||||
//===============
|
//===============
|
||||||
|
|
||||||
auto SPC7110::mcuram_read(uint addr) -> uint8 {
|
auto SPC7110::mcuram_read(uint addr, uint8) -> uint8 {
|
||||||
//$00-3f|80-bf:6000-7fff
|
//$00-3f|80-bf:6000-7fff
|
||||||
if(r4830 & 0x80) {
|
if(r4830 & 0x80) {
|
||||||
uint bank = (addr >> 16) & 0x3f;
|
uint bank = (addr >> 16) & 0x3f;
|
||||||
|
|
|
@ -14,13 +14,13 @@ struct SPC7110 : Coprocessor {
|
||||||
|
|
||||||
auto add_clocks(uint clocks) -> void;
|
auto add_clocks(uint clocks) -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mcurom_read(uint addr) -> uint8;
|
auto mcurom_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mcurom_write(uint addr, uint8 data) -> void;
|
auto mcurom_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto mcuram_read(uint addr) -> uint8;
|
auto mcuram_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mcuram_write(uint addr, uint8 data) -> void;
|
auto mcuram_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
//ROM / RAM access from the S-CPU
|
//ROM / RAM access from the S-CPU
|
||||||
|
|
||||||
auto SuperFX::CPUROM::size() const -> unsigned {
|
auto SuperFX::CPUROM::size() const -> uint {
|
||||||
return superfx.rom.size();
|
return superfx.rom.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFX::CPUROM::read(unsigned addr) -> uint8 {
|
auto SuperFX::CPUROM::read(uint addr, uint8 data) -> uint8 {
|
||||||
if(superfx.regs.sfr.g && superfx.regs.scmr.ron) {
|
if(superfx.regs.sfr.g && superfx.regs.scmr.ron) {
|
||||||
static const uint8_t data[16] = {
|
static const uint8 vector[16] = {
|
||||||
0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01,
|
0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01,
|
||||||
0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01,
|
0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01,
|
||||||
};
|
};
|
||||||
return data[addr & 15];
|
return vector[addr & 15];
|
||||||
}
|
}
|
||||||
return superfx.rom.read(addr);
|
return superfx.rom.read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFX::CPUROM::write(unsigned addr, uint8 data) -> void {
|
auto SuperFX::CPUROM::write(uint addr, uint8 data) -> void {
|
||||||
superfx.rom.write(addr, data);
|
superfx.rom.write(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFX::CPURAM::size() const -> unsigned {
|
auto SuperFX::CPURAM::size() const -> uint {
|
||||||
return superfx.ram.size();
|
return superfx.ram.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFX::CPURAM::read(unsigned addr) -> uint8 {
|
auto SuperFX::CPURAM::read(uint addr, uint8 data) -> uint8 {
|
||||||
if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return cpu.regs.mdr;
|
if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return data;
|
||||||
return superfx.ram.read(addr);
|
return superfx.ram.read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFX::CPURAM::write(unsigned addr, uint8 data) -> void {
|
auto SuperFX::CPURAM::write(uint addr, uint8 data) -> void {
|
||||||
superfx.ram.write(addr, data);
|
superfx.ram.write(addr, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
struct CPUROM : Memory {
|
struct CPUROM : Memory {
|
||||||
auto size() const -> unsigned;
|
auto size() const -> uint;
|
||||||
auto read(unsigned) -> uint8;
|
auto read(uint, uint8) -> uint8;
|
||||||
auto write(unsigned, uint8) -> void;
|
auto write(uint, uint8) -> void;
|
||||||
} cpurom;
|
} cpurom;
|
||||||
|
|
||||||
struct CPURAM : Memory {
|
struct CPURAM : Memory {
|
||||||
auto size() const -> unsigned;
|
auto size() const -> uint;
|
||||||
auto read(unsigned) -> uint8;
|
auto read(uint, uint8) -> uint8;
|
||||||
auto write(unsigned, uint8) -> void;
|
auto write(uint, uint8) -> void;
|
||||||
} cpuram;
|
} cpuram;
|
||||||
|
|
|
@ -2,7 +2,7 @@ auto SuperFX::bus_read(unsigned addr) -> uint8 {
|
||||||
if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff, $00-3f:8000-ffff
|
if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff, $00-3f:8000-ffff
|
||||||
while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
step(6);
|
step(6);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
return rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & rom_mask);
|
return rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & rom_mask);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ auto SuperFX::bus_read(unsigned addr) -> uint8 {
|
||||||
if((addr & 0xe00000) == 0x400000) { //$40-5f:0000-ffff
|
if((addr & 0xe00000) == 0x400000) { //$40-5f:0000-ffff
|
||||||
while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
step(6);
|
step(6);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
return rom.read(addr & rom_mask);
|
return rom.read(addr & rom_mask);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ auto SuperFX::bus_read(unsigned addr) -> uint8 {
|
||||||
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
|
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
|
||||||
while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
step(6);
|
step(6);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
return ram.read(addr & ram_mask);
|
return ram.read(addr & ram_mask);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ auto SuperFX::bus_write(unsigned addr, uint8 data) -> void {
|
||||||
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
|
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
|
||||||
while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||||
step(6);
|
step(6);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
return ram.write(addr & ram_mask, data);
|
return ram.write(addr & ram_mask, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
auto SuperFX::mmio_read(unsigned addr) -> uint8 {
|
auto SuperFX::mmio_read(uint addr, uint8) -> uint8 {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ auto SuperFX::mmio_read(unsigned addr) -> uint8 {
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFX::mmio_write(unsigned addr, uint8 data) -> void {
|
auto SuperFX::mmio_write(uint addr, uint8 data) -> void {
|
||||||
cpu.synchronizeCoprocessors();
|
cpu.synchronizeCoprocessors();
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ auto SuperFX::mmio_write(unsigned addr, uint8 data) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(addr >= 0x3000 && addr <= 0x301f) {
|
if(addr >= 0x3000 && addr <= 0x301f) {
|
||||||
unsigned n = (addr >> 1) & 15;
|
uint n = (addr >> 1) & 15;
|
||||||
if((addr & 1) == 0) {
|
if((addr & 1) == 0) {
|
||||||
regs.r[n] = (regs.r[n] & 0xff00) | data;
|
regs.r[n] = (regs.r[n] & 0xff00) | data;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
auto mmio_read(unsigned addr) -> uint8;
|
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmio_write(unsigned addr, uint8 data) -> void;
|
auto mmio_write(uint addr, uint8 data) -> void;
|
||||||
|
|
|
@ -15,7 +15,7 @@ auto SuperFX::step(unsigned clocks) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
Coprocessor::step(clocks);
|
Coprocessor::step(clocks);
|
||||||
synchronize_cpu();
|
synchronizeCPU();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFX::rombuffer_sync() -> void {
|
auto SuperFX::rombuffer_sync() -> void {
|
||||||
|
|
|
@ -78,8 +78,8 @@ auto CPU::enter() -> void {
|
||||||
} else if(status.reset_pending) {
|
} else if(status.reset_pending) {
|
||||||
status.reset_pending = false;
|
status.reset_pending = false;
|
||||||
add_clocks(186);
|
add_clocks(186);
|
||||||
regs.pc.l = bus.read(0xfffc);
|
regs.pc.l = bus.read(0xfffc, regs.mdr);
|
||||||
regs.pc.h = bus.read(0xfffd);
|
regs.pc.h = bus.read(0xfffd, regs.mdr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,8 +93,8 @@ auto CPU::op_step() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::enable() -> void {
|
auto CPU::enable() -> void {
|
||||||
function<uint8 (unsigned)> reader{&CPU::mmio_read, (CPU*)&cpu};
|
function<auto (uint, uint8) -> uint8> reader{&CPU::mmio_read, (CPU*)&cpu};
|
||||||
function<void (unsigned, uint8)> writer{&CPU::mmio_write, (CPU*)&cpu};
|
function<auto (uint, uint8) -> void> writer{&CPU::mmio_write, (CPU*)&cpu};
|
||||||
|
|
||||||
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
|
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
|
||||||
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
|
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
|
||||||
|
@ -108,8 +108,8 @@ auto CPU::enable() -> void {
|
||||||
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
|
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
|
||||||
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
|
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
|
||||||
|
|
||||||
reader = [](unsigned addr) { return cpu.wram[addr]; };
|
reader = [](uint addr, uint8) -> uint8 { return cpu.wram[addr]; };
|
||||||
writer = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
writer = [](uint addr, uint8 data) -> void { cpu.wram[addr] = data; };
|
||||||
|
|
||||||
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
|
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
|
||||||
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
|
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
|
||||||
|
|
|
@ -24,7 +24,7 @@ auto CPU::dma_addr_valid(uint32 abus) -> bool {
|
||||||
|
|
||||||
auto CPU::dma_read(uint32 abus) -> uint8 {
|
auto CPU::dma_read(uint32 abus) -> uint8 {
|
||||||
if(dma_addr_valid(abus) == false) return 0x00;
|
if(dma_addr_valid(abus) == false) return 0x00;
|
||||||
return bus.read(abus);
|
return bus.read(abus, regs.mdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//simulate two-stage pipeline for DMA transfers; example:
|
//simulate two-stage pipeline for DMA transfers; example:
|
||||||
|
@ -47,7 +47,7 @@ auto CPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) -> void {
|
||||||
dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, regs.mdr);
|
dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, regs.mdr);
|
||||||
} else {
|
} else {
|
||||||
dma_add_clocks(4);
|
dma_add_clocks(4);
|
||||||
regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus) : 0x00;
|
regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus, regs.mdr) : 0x00;
|
||||||
dma_add_clocks(4);
|
dma_add_clocks(4);
|
||||||
dma_write(dma_addr_valid(abus), abus, regs.mdr);
|
dma_write(dma_addr_valid(abus), abus, regs.mdr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ auto CPU::op_read(uint32 addr) -> uint8 {
|
||||||
status.clock_count = speed(addr);
|
status.clock_count = speed(addr);
|
||||||
dma_edge();
|
dma_edge();
|
||||||
add_clocks(status.clock_count - 4);
|
add_clocks(status.clock_count - 4);
|
||||||
regs.mdr = bus.read(addr);
|
regs.mdr = bus.read(addr, regs.mdr);
|
||||||
add_clocks(4);
|
add_clocks(4);
|
||||||
alu_edge();
|
alu_edge();
|
||||||
debugger.op_read(addr, regs.mdr);
|
debugger.op_read(addr, regs.mdr);
|
||||||
|
@ -44,5 +44,5 @@ auto CPU::speed(uint addr) const -> uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::disassembler_read(uint32 addr) -> uint8 {
|
auto CPU::disassembler_read(uint32 addr) -> uint8 {
|
||||||
return bus.read(addr);
|
return bus.read(addr, regs.mdr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ auto CPU::joylatch() -> bool {
|
||||||
|
|
||||||
//WMDATA
|
//WMDATA
|
||||||
auto CPU::mmio_r2180() -> uint8 {
|
auto CPU::mmio_r2180() -> uint8 {
|
||||||
return bus.read(0x7e0000 | status.wram_addr++);
|
return bus.read(0x7e0000 | status.wram_addr++, regs.mdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//WMDATA
|
//WMDATA
|
||||||
|
@ -405,7 +405,7 @@ auto CPU::mmio_reset() -> void {
|
||||||
alu.shift = 0;
|
alu.shift = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::mmio_read(uint addr) -> uint8 {
|
auto CPU::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
//APU
|
//APU
|
||||||
|
@ -416,7 +416,7 @@ auto CPU::mmio_read(uint addr) -> uint8 {
|
||||||
|
|
||||||
//DMA
|
//DMA
|
||||||
if((addr & 0xff80) == 0x4300) { //$4300-$437f
|
if((addr & 0xff80) == 0x4300) { //$4300-$437f
|
||||||
unsigned i = (addr >> 4) & 7;
|
uint i = (addr >> 4) & 7;
|
||||||
switch(addr & 0xf) {
|
switch(addr & 0xf) {
|
||||||
case 0x0: return mmio_r43x0(i);
|
case 0x0: return mmio_r43x0(i);
|
||||||
case 0x1: return mmio_r43x1(i);
|
case 0x1: return mmio_r43x1(i);
|
||||||
|
@ -459,7 +459,7 @@ auto CPU::mmio_read(uint addr) -> uint8 {
|
||||||
case 0x421f: return mmio_r421f();
|
case 0x421f: return mmio_r421f();
|
||||||
}
|
}
|
||||||
|
|
||||||
return regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::mmio_write(uint addr, uint8 data) -> void {
|
auto CPU::mmio_write(uint addr, uint8 data) -> void {
|
||||||
|
@ -474,7 +474,7 @@ auto CPU::mmio_write(uint addr, uint8 data) -> void {
|
||||||
|
|
||||||
//DMA
|
//DMA
|
||||||
if((addr & 0xff80) == 0x4300) { //$4300-$437f
|
if((addr & 0xff80) == 0x4300) { //$4300-$437f
|
||||||
unsigned i = (addr >> 4) & 7;
|
uint i = (addr >> 4) & 7;
|
||||||
switch(addr & 0xf) {
|
switch(addr & 0xf) {
|
||||||
case 0x0: mmio_w43x0(i, data); return;
|
case 0x0: mmio_w43x0(i, data); return;
|
||||||
case 0x1: mmio_w43x1(i, data); return;
|
case 0x1: mmio_w43x1(i, data); return;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
public:
|
public:
|
||||||
auto mmio_read(uint addr) -> uint8;
|
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmio_write(uint addr, uint8 data) -> void;
|
auto mmio_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
privileged:
|
privileged:
|
||||||
|
|
|
@ -8,8 +8,8 @@ auto eBoot::init() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eBoot::load() -> void {
|
auto eBoot::load() -> void {
|
||||||
resetVector = bus.read(0xfffc) << 0;
|
resetVector = bus.read(0xfffc, 0x00) << 0;
|
||||||
resetVector |= bus.read(0xfffd) << 8;
|
resetVector |= bus.read(0xfffd, 0x00) << 8;
|
||||||
|
|
||||||
for(auto& byte : ram) byte = 0xdb;
|
for(auto& byte : ram) byte = 0xdb;
|
||||||
ram[0] = 0x6c; //jmp ($fffc)
|
ram[0] = 0x6c; //jmp ($fffc)
|
||||||
|
@ -35,12 +35,12 @@ auto eBoot::reset() -> void {
|
||||||
booted = false;
|
booted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eBoot::read(uint addr) -> uint8 {
|
auto eBoot::read(uint addr, uint8 data) -> uint8 {
|
||||||
addr &= 0xffff;
|
addr &= 0x40ffff;
|
||||||
if(addr == 0xfffc) return booted ? resetVector >> 0 : 0x84;
|
if(addr == 0xfffc) return booted ? resetVector >> 0 : 0x84;
|
||||||
if(addr == 0xfffd) return booted ? resetVector >> 8 : (booted = true, 0x21);
|
if(addr == 0xfffd) return booted ? resetVector >> 8 : (booted = true, 0x21);
|
||||||
if(addr >= 0x2184 && addr <= 0x21ff) return ram[addr - 0x2184];
|
if(addr >= 0x2184 && addr <= 0x21ff) return ram[addr - 0x2184];
|
||||||
return 0xdb; //should never occur
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eBoot::write(uint addr, uint8 data) -> void {
|
auto eBoot::write(uint addr, uint8 data) -> void {
|
||||||
|
|
|
@ -5,7 +5,7 @@ struct eBoot : Memory {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -22,7 +22,7 @@ auto Satellaview::reset() -> void {
|
||||||
memory::fill(®s, sizeof regs);
|
memory::fill(®s, sizeof regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Satellaview::read(uint addr) -> uint8 {
|
auto Satellaview::read(uint addr, uint8 data) -> uint8 {
|
||||||
addr &= 0xffff;
|
addr &= 0xffff;
|
||||||
|
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
|
@ -77,7 +77,7 @@ auto Satellaview::read(uint addr) -> uint8 {
|
||||||
case 0x2199: return regs.r2199;
|
case 0x2199: return regs.r2199;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Satellaview::write(uint addr, uint8 data) -> void {
|
auto Satellaview::write(uint addr, uint8 data) -> void {
|
||||||
|
|
|
@ -5,7 +5,7 @@ struct Satellaview : Memory {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto read(uint addr) -> uint8;
|
auto read(uint addr, uint8 data) -> uint8;
|
||||||
auto write(uint addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
//Memory
|
//Memory
|
||||||
|
|
||||||
auto Memory::size() const -> unsigned { return 0; }
|
auto Memory::size() const -> uint { return 0; }
|
||||||
|
|
||||||
//StaticRAM
|
//StaticRAM
|
||||||
|
|
||||||
StaticRAM::StaticRAM(unsigned n) : size_(n) { data_ = new uint8[size_]; }
|
StaticRAM::StaticRAM(uint n) : size_(n) { data_ = new uint8[size_]; }
|
||||||
StaticRAM::~StaticRAM() { delete[] data_; }
|
StaticRAM::~StaticRAM() { delete[] data_; }
|
||||||
|
|
||||||
auto StaticRAM::data() -> uint8* { return data_; }
|
auto StaticRAM::data() -> uint8* { return data_; }
|
||||||
auto StaticRAM::size() const -> unsigned { return size_; }
|
auto StaticRAM::size() const -> uint { return size_; }
|
||||||
|
|
||||||
auto StaticRAM::read(unsigned addr) -> uint8 { return data_[addr]; }
|
auto StaticRAM::read(uint addr, uint8) -> uint8 { return data_[addr]; }
|
||||||
auto StaticRAM::write(unsigned addr, uint8 n) -> void { data_[addr] = n; }
|
auto StaticRAM::write(uint addr, uint8 data) -> void { data_[addr] = data; }
|
||||||
auto StaticRAM::operator[](unsigned addr) -> uint8& { return data_[addr]; }
|
auto StaticRAM::operator[](uint addr) -> uint8& { return data_[addr]; }
|
||||||
auto StaticRAM::operator[](unsigned addr) const -> const uint8& { return data_[addr]; }
|
auto StaticRAM::operator[](uint addr) const -> const uint8& { return data_[addr]; }
|
||||||
|
|
||||||
//MappedRAM
|
//MappedRAM
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ auto MappedRAM::reset() -> void {
|
||||||
write_protect_ = false;
|
write_protect_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MappedRAM::map(uint8* source, unsigned length) -> void {
|
auto MappedRAM::map(uint8* source, uint length) -> void {
|
||||||
reset();
|
reset();
|
||||||
data_ = source;
|
data_ = source;
|
||||||
size_ = data_ ? length : 0;
|
size_ = data_ ? length : 0;
|
||||||
|
@ -46,18 +46,18 @@ auto MappedRAM::read(const stream& memory) -> void {
|
||||||
|
|
||||||
auto MappedRAM::write_protect(bool status) -> void { write_protect_ = status; }
|
auto MappedRAM::write_protect(bool status) -> void { write_protect_ = status; }
|
||||||
auto MappedRAM::data() -> uint8* { return data_; }
|
auto MappedRAM::data() -> uint8* { return data_; }
|
||||||
auto MappedRAM::size() const -> unsigned { return size_; }
|
auto MappedRAM::size() const -> uint { return size_; }
|
||||||
|
|
||||||
auto MappedRAM::read(unsigned addr) -> uint8 { return data_[addr]; }
|
auto MappedRAM::read(uint addr, uint8) -> uint8 { return data_[addr]; }
|
||||||
auto MappedRAM::write(unsigned addr, uint8 n) -> void { if(!write_protect_) data_[addr] = n; }
|
auto MappedRAM::write(uint addr, uint8 data) -> void { if(!write_protect_) data_[addr] = data; }
|
||||||
auto MappedRAM::operator[](unsigned addr) const -> const uint8& { return data_[addr]; }
|
auto MappedRAM::operator[](uint addr) const -> const uint8& { return data_[addr]; }
|
||||||
|
|
||||||
//Bus
|
//Bus
|
||||||
|
|
||||||
auto Bus::mirror(unsigned addr, unsigned size) -> unsigned {
|
auto Bus::mirror(uint addr, uint size) -> uint {
|
||||||
if(size == 0) return 0;
|
if(size == 0) return 0;
|
||||||
unsigned base = 0;
|
uint base = 0;
|
||||||
unsigned mask = 1 << 23;
|
uint mask = 1 << 23;
|
||||||
while(addr >= size) {
|
while(addr >= size) {
|
||||||
while(!(addr & mask)) mask >>= 1;
|
while(!(addr & mask)) mask >>= 1;
|
||||||
addr -= mask;
|
addr -= mask;
|
||||||
|
@ -70,17 +70,17 @@ auto Bus::mirror(unsigned addr, unsigned size) -> unsigned {
|
||||||
return base + addr;
|
return base + addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::reduce(unsigned addr, unsigned mask) -> unsigned {
|
auto Bus::reduce(uint addr, uint mask) -> uint {
|
||||||
while(mask) {
|
while(mask) {
|
||||||
unsigned bits = (mask & -mask) - 1;
|
uint bits = (mask & -mask) - 1;
|
||||||
addr = ((addr >> 1) & ~bits) | (addr & bits);
|
addr = ((addr >> 1) & ~bits) | (addr & bits);
|
||||||
mask = (mask & (mask - 1)) >> 1;
|
mask = (mask & (mask - 1)) >> 1;
|
||||||
}
|
}
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::read(unsigned addr) -> uint8 {
|
auto Bus::read(uint addr, uint8 data) -> uint8 {
|
||||||
uint8 data = reader[lookup[addr]](target[addr]);
|
data = reader[lookup[addr]](target[addr], data);
|
||||||
|
|
||||||
if(cheat.enable()) {
|
if(cheat.enable()) {
|
||||||
if(auto result = cheat.find(addr, data)) return result();
|
if(auto result = cheat.find(addr, data)) return result();
|
||||||
|
@ -89,6 +89,6 @@ auto Bus::read(unsigned addr) -> uint8 {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::write(unsigned addr, uint8 data) -> void {
|
auto Bus::write(uint addr, uint8 data) -> void {
|
||||||
return writer[lookup[addr]](target[addr], data);
|
return writer[lookup[addr]](target[addr], data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@ Bus::~Bus() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::reset() -> void {
|
auto Bus::reset() -> void {
|
||||||
function<uint8 (unsigned)> reader = [](unsigned) { return cpu.regs.mdr; };
|
function<auto (uint, uint8) -> uint8> reader = [](uint, uint8 data) { return data; };
|
||||||
function<void (unsigned, uint8)> writer = [](unsigned, uint8) {};
|
function<auto (uint, uint8) -> void> writer = [](uint, uint8) {};
|
||||||
|
|
||||||
idcount = 0;
|
idcount = 0;
|
||||||
map(reader, writer, 0x00, 0xff, 0x0000, 0xffff);
|
map(reader, writer, 0x00, 0xff, 0x0000, 0xffff);
|
||||||
|
@ -31,10 +31,10 @@ auto Bus::map() -> void {
|
||||||
for(auto& addr : addrs) {
|
for(auto& addr : addrs) {
|
||||||
lstring bankpart = bank.split("-", 1L);
|
lstring bankpart = bank.split("-", 1L);
|
||||||
lstring addrpart = addr.split("-", 1L);
|
lstring addrpart = addr.split("-", 1L);
|
||||||
unsigned banklo = hex(bankpart(0));
|
uint banklo = hex(bankpart(0));
|
||||||
unsigned bankhi = hex(bankpart(1, bankpart(0)));
|
uint bankhi = hex(bankpart(1, bankpart(0)));
|
||||||
unsigned addrlo = hex(addrpart(0));
|
uint addrlo = hex(addrpart(0));
|
||||||
unsigned addrhi = hex(addrpart(1, addrpart(0)));
|
uint addrhi = hex(addrpart(1, addrpart(0)));
|
||||||
map(m.reader, m.writer, banklo, bankhi, addrlo, addrhi, m.size, m.base, m.mask);
|
map(m.reader, m.writer, banklo, bankhi, addrlo, addrhi, m.size, m.base, m.mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,23 +42,22 @@ auto Bus::map() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::map(
|
auto Bus::map(
|
||||||
const function<uint8 (unsigned)>& reader,
|
const function<uint8 (uint, uint8)>& reader,
|
||||||
const function<void (unsigned, uint8)>& writer,
|
const function<void (uint, uint8)>& writer,
|
||||||
unsigned banklo, unsigned bankhi,
|
uint banklo, uint bankhi, uint addrlo, uint addrhi,
|
||||||
unsigned addrlo, unsigned addrhi,
|
uint size, uint base, uint mask
|
||||||
unsigned size, unsigned base, unsigned mask
|
|
||||||
) -> void {
|
) -> void {
|
||||||
assert(banklo <= bankhi && banklo <= 0xff);
|
assert(banklo <= bankhi && bankhi <= 0xff);
|
||||||
assert(addrlo <= addrhi && addrlo <= 0xffff);
|
assert(addrlo <= addrhi && addrhi <= 0xffff);
|
||||||
assert(idcount < 255);
|
assert(idcount < 255);
|
||||||
|
|
||||||
unsigned id = idcount++;
|
uint id = idcount++;
|
||||||
this->reader[id] = reader;
|
this->reader[id] = reader;
|
||||||
this->writer[id] = writer;
|
this->writer[id] = writer;
|
||||||
|
|
||||||
for(unsigned bank = banklo; bank <= bankhi; bank++) {
|
for(uint bank = banklo; bank <= bankhi; bank++) {
|
||||||
for(unsigned addr = addrlo; addr <= addrhi; addr++) {
|
for(uint addr = addrlo; addr <= addrhi; addr++) {
|
||||||
unsigned offset = reduce(bank << 16 | addr, mask);
|
uint offset = reduce(bank << 16 | addr, mask);
|
||||||
if(size) offset = base + mirror(offset, size - base);
|
if(size) offset = base + mirror(offset, size - base);
|
||||||
lookup[bank << 16 | addr] = id;
|
lookup[bank << 16 | addr] = id;
|
||||||
target[bank << 16 | addr] = offset;
|
target[bank << 16 | addr] = offset;
|
||||||
|
|
|
@ -1,72 +1,71 @@
|
||||||
struct Memory {
|
struct Memory {
|
||||||
virtual inline auto size() const -> unsigned;
|
virtual inline auto size() const -> uint;
|
||||||
virtual auto read(unsigned addr) -> uint8 = 0;
|
virtual auto read(uint addr, uint8 data = 0) -> uint8 = 0;
|
||||||
virtual auto write(unsigned addr, uint8 data) -> void = 0;
|
virtual auto write(uint addr, uint8 data) -> void = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StaticRAM : Memory {
|
struct StaticRAM : Memory {
|
||||||
inline StaticRAM(unsigned size);
|
inline StaticRAM(uint size);
|
||||||
inline ~StaticRAM();
|
inline ~StaticRAM();
|
||||||
|
|
||||||
inline auto data() -> uint8*;
|
inline auto data() -> uint8*;
|
||||||
inline auto size() const -> unsigned;
|
inline auto size() const -> uint;
|
||||||
|
|
||||||
inline auto read(unsigned addr) -> uint8;
|
inline auto read(uint addr, uint8 data = 0) -> uint8;
|
||||||
inline auto write(unsigned addr, uint8 n) -> void;
|
inline auto write(uint addr, uint8 data) -> void;
|
||||||
inline auto operator[](unsigned addr) -> uint8&;
|
inline auto operator[](uint addr) -> uint8&;
|
||||||
inline auto operator[](unsigned addr) const -> const uint8&;
|
inline auto operator[](uint addr) const -> const uint8&;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8* data_ = nullptr;
|
uint8* data_ = nullptr;
|
||||||
unsigned size_ = 0;
|
uint size_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MappedRAM : Memory {
|
struct MappedRAM : Memory {
|
||||||
inline auto reset() -> void;
|
inline auto reset() -> void;
|
||||||
inline auto map(uint8*, unsigned) -> void;
|
inline auto map(uint8*, uint) -> void;
|
||||||
inline auto copy(const stream& memory) -> void;
|
inline auto copy(const stream& memory) -> void;
|
||||||
inline auto read(const stream& memory) -> void;
|
inline auto read(const stream& memory) -> void;
|
||||||
|
|
||||||
inline auto write_protect(bool status) -> void;
|
inline auto write_protect(bool status) -> void;
|
||||||
inline auto data() -> uint8*;
|
inline auto data() -> uint8*;
|
||||||
inline auto size() const -> unsigned;
|
inline auto size() const -> uint;
|
||||||
|
|
||||||
inline auto read(unsigned addr) -> uint8;
|
inline auto read(uint addr, uint8 data = 0) -> uint8;
|
||||||
inline auto write(unsigned addr, uint8 n) -> void;
|
inline auto write(uint addr, uint8 data) -> void;
|
||||||
inline auto operator[](unsigned addr) const -> const uint8&;
|
inline auto operator[](uint addr) const -> const uint8&;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8* data_ = nullptr;
|
uint8* data_ = nullptr;
|
||||||
unsigned size_ = 0;
|
uint size_ = 0;
|
||||||
bool write_protect_ = false;
|
bool write_protect_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bus {
|
struct Bus {
|
||||||
alwaysinline static auto mirror(unsigned addr, unsigned size) -> unsigned;
|
alwaysinline static auto mirror(uint addr, uint size) -> uint;
|
||||||
alwaysinline static auto reduce(unsigned addr, unsigned mask) -> unsigned;
|
alwaysinline static auto reduce(uint addr, uint mask) -> uint;
|
||||||
|
|
||||||
Bus();
|
Bus();
|
||||||
~Bus();
|
~Bus();
|
||||||
|
|
||||||
alwaysinline auto read(unsigned addr) -> uint8;
|
alwaysinline auto read(uint addr, uint8 data) -> uint8;
|
||||||
alwaysinline auto write(unsigned addr, uint8 data) -> void;
|
alwaysinline auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
auto map() -> void;
|
auto map() -> void;
|
||||||
auto map(
|
auto map(
|
||||||
const function<uint8 (unsigned)>& reader,
|
const function<uint8 (uint, uint8)>& reader,
|
||||||
const function<void (unsigned, uint8)>& writer,
|
const function<void (uint, uint8)>& writer,
|
||||||
unsigned banklo, unsigned bankhi,
|
uint banklo, uint bankhi, uint addrlo, uint addrhi,
|
||||||
unsigned addrlo, unsigned addrhi,
|
uint size = 0, uint base = 0, uint mask = 0
|
||||||
unsigned size = 0, unsigned base = 0, unsigned mask = 0
|
|
||||||
) -> void;
|
) -> void;
|
||||||
|
|
||||||
uint8* lookup = nullptr;
|
uint8* lookup = nullptr;
|
||||||
uint32* target = nullptr;
|
uint32* target = nullptr;
|
||||||
|
|
||||||
unsigned idcount = 0;
|
uint idcount = 0;
|
||||||
function<uint8 (unsigned)> reader[256];
|
function<auto (uint, uint8) -> uint8> reader[256];
|
||||||
function<void (unsigned, uint8)> writer[256];
|
function<auto (uint, uint8) -> void> writer[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Bus bus;
|
extern Bus bus;
|
||||||
|
|
|
@ -788,7 +788,7 @@ auto PPU::mmio_reset() -> void {
|
||||||
regs.vcounter = 0;
|
regs.vcounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::mmio_read(uint addr) -> uint8 {
|
auto PPU::mmio_read(uint addr, uint8 data) -> uint8 {
|
||||||
cpu.synchronizePPU();
|
cpu.synchronizePPU();
|
||||||
|
|
||||||
switch(addr & 0xffff) {
|
switch(addr & 0xffff) {
|
||||||
|
@ -824,7 +824,7 @@ auto PPU::mmio_read(uint addr) -> uint8 {
|
||||||
case 0x213f: return mmio_r213f(); //STAT78
|
case 0x213f: return mmio_r213f(); //STAT78
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpu.regs.mdr;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::mmio_write(uint addr, uint8 data) -> void {
|
auto PPU::mmio_write(uint addr, uint8 data) -> void {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
public:
|
public:
|
||||||
auto mmio_read(uint addr) -> uint8;
|
auto mmio_read(uint addr, uint8 data) -> uint8;
|
||||||
auto mmio_write(uint addr, uint8 data) -> void;
|
auto mmio_write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
privileged:
|
privileged:
|
||||||
|
|
|
@ -94,8 +94,8 @@ auto PPU::add_clocks(uint clocks) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::enable() -> void {
|
auto PPU::enable() -> void {
|
||||||
function<uint8 (unsigned)> reader{&PPU::mmio_read, (PPU*)&ppu};
|
function<auto (uint, uint8) -> uint8> reader{&PPU::mmio_read, (PPU*)&ppu};
|
||||||
function<void (unsigned, uint8)> writer{&PPU::mmio_write, (PPU*)&ppu};
|
function<auto (uint, uint8) -> void> writer{&PPU::mmio_write, (PPU*)&ppu};
|
||||||
|
|
||||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||||
|
|
|
@ -31,12 +31,12 @@ auto SatellaviewCartridge::reset() -> void {
|
||||||
memory.write_protect(!regs.write_enable);
|
memory.write_protect(!regs.write_enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SatellaviewCartridge::size() const -> unsigned {
|
auto SatellaviewCartridge::size() const -> uint {
|
||||||
return memory.size();
|
return memory.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SatellaviewCartridge::read(unsigned addr) -> uint8 {
|
auto SatellaviewCartridge::read(uint addr, uint8 data) -> uint8 {
|
||||||
if(readonly) return memory.read(bus.mirror(addr, memory.size()));
|
if(readonly) return memory.read(bus.mirror(addr, memory.size()), data);
|
||||||
|
|
||||||
if(addr == 0x0002) {
|
if(addr == 0x0002) {
|
||||||
if(regs.flash_enable) return 0x80;
|
if(regs.flash_enable) return 0x80;
|
||||||
|
@ -61,10 +61,10 @@ auto SatellaviewCartridge::read(unsigned addr) -> uint8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return memory.read(addr);
|
return memory.read(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SatellaviewCartridge::write(unsigned addr, uint8 data) -> void {
|
auto SatellaviewCartridge::write(uint addr, uint8 data) -> void {
|
||||||
if(readonly) return;
|
if(readonly) return;
|
||||||
|
|
||||||
if((addr & 0xff0000) == 0) {
|
if((addr & 0xff0000) == 0) {
|
||||||
|
|
|
@ -5,16 +5,16 @@ struct SatellaviewCartridge : Memory {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto size() const -> unsigned;
|
auto size() const -> uint;
|
||||||
auto read(unsigned addr) -> uint8;
|
auto read(uint addr, uint8) -> uint8;
|
||||||
auto write(unsigned addr, uint8 data) -> void;
|
auto write(uint addr, uint8 data) -> void;
|
||||||
|
|
||||||
MappedRAM memory;
|
MappedRAM memory;
|
||||||
bool readonly;
|
bool readonly;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct {
|
struct {
|
||||||
unsigned command;
|
uint command;
|
||||||
uint8 write_old;
|
uint8 write_old;
|
||||||
uint8 write_new;
|
uint8 write_new;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue