mirror of
https://github.com/libretro/Mu.git
synced 2026-02-13 21:24:19 +00:00
Compare commits
8 Commits
v1/3x3
...
finalCyclo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abb2e6526b | ||
|
|
d96c0ec8c4 | ||
|
|
6c37868055 | ||
|
|
b02fa8ba52 | ||
|
|
94b0baaf7f | ||
|
|
f8baa0eb85 | ||
|
|
538fd36c08 | ||
|
|
335997f19c |
@@ -1,9 +1,9 @@
|
||||
Lakka(needs makefile)
|
||||
classics/new haxchi(should work)
|
||||
xbox(don't know)
|
||||
xbox360(don't know)
|
||||
|
||||
Fixed:
|
||||
classics/new haxchi
|
||||
PSP
|
||||
msvc2010
|
||||
msvc2003
|
||||
|
||||
@@ -3,9 +3,9 @@ This is like unimplementedHardware.txt but only lists things that have functiona
|
||||
State manager goes bezerk and crashes when saving on android, also can't close the window or it won't open again(also only on Android)
|
||||
If there is no userdata-en-m515.ram on Android the emu won't create it(this is likely because theres no graceful exit being done on Android only goto home menu and kill process)
|
||||
app install hack needs to be removed when SD card works
|
||||
cyclone68k is broken on iOS
|
||||
|
||||
Fixed:
|
||||
cyclone68k is broken on iOS(not gonna happen, iOS supposedly has its own ASM syntax)
|
||||
double pressing power button issue(better without PDKBEN but still not correct)
|
||||
Holding the buttons emulates pressing them like a turbo button(may be caused by the lack of sound emulation(wrong, sound works now))(may be because the minimum length of a button press is a whole frame(wrong, increasing the framerate doesn't change this behavior))(port d doesn't seem to be documented properly)
|
||||
16 bpp mode is broken
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
cyclone68k is crasing again when you turn the Palm off then turn it back on
|
||||
|
||||
Fixed:
|
||||
Endian compatibility is broken(the CPU state needs to be standardized)(fixed again with musashi and the other 68k core isn't used right now)
|
||||
RetroArch port crashes on exit(needed to check if environ_cb returned true, switched to libretro-common filestreams too)
|
||||
|
||||
@@ -2,7 +2,6 @@ CPU:
|
||||
sysTrapPceNativeCall, ARM Emulator
|
||||
Trace T1 bit, should be unused by the OS and applications anyway
|
||||
Test what bits of IMR are writable
|
||||
On hardware PDIRQEG seems not to actually work at all(CPUID:0x57000000)
|
||||
SCR privilege violation doesnt trigger the same as on hardware(likely has to do with not emulating the unused chip selects)
|
||||
TCN2 is unimplemented and seems to be used by the same routines that turn the CPU off for sleep mode
|
||||
|
||||
@@ -14,23 +13,20 @@ Port M Infrared shutdown (PMDATA 0x20)
|
||||
some undocumented I/O might be on port e and port j
|
||||
SPI1, probably the SD card since SD cards use SPI for data transfer
|
||||
SPITEST SSTATUS is undocumented and therefore unemulated
|
||||
may need to trigger an interrupt if a IMR masked interrupt becomes unmasked and its bit is still set in IPR
|
||||
When SPICLK2, SPITXD or SPIRXD on port e is disabled ADS7846 functions should respond appropriately(not transmitting or receiving or blocking both for the clock)
|
||||
REFREQ clock frequency in RTCCTL should slow down the RTC when enabled
|
||||
Dont know if it possible to have the backlight on and the display off at the same time(theres no reason for it but it may be possible)
|
||||
SPI1 slave mode, should never be used
|
||||
port d data register INT* bits seem to have there data bits cleared when an edge triggered interrupt is cleared(according to MC68VZ328UM.pdf Page 10-15)
|
||||
RxOverflow on SPI1, don't know if back or front of FIFO is overwritten on overflow(currently losing oldest entry)
|
||||
ICR POL(1,2,3,6) may flip the pin value as well as the interrupt, POL5 does not flip the INT5 pin though, this was confirmed with a hardware test(it doesnt seem to but there is instability on the pin when the SD card is plugged in, this may have to do with card detect also being a data line on the SD pinout)
|
||||
edge triggered INT* don't clear on write to ISR when masked in IMR(at least that seems to be the reason)
|
||||
Cyclone will cause SIGSEGVs, don't know why yet
|
||||
PWM2 is not implemented
|
||||
don't know if flushing the PWM1 FIFO sets all the bytes to 0x00, or just sets the read pointer to the write pointer preserving the newest sample and making the size 0(readPtr = writePtr has significantly cleaner audio then 0ing it out though)
|
||||
while it is stated that the PLL is turned off "30 clocks" after the DISPLL bit is set, it doesnt state where the clocks come from, CLK32 or SYSCLK
|
||||
SPI1 SPISPC register
|
||||
UART1 USTCNT1
|
||||
PLLFSR has a hack that makes busy wait loops finish faster by toggling the CLK32 bit on read, for power button issue
|
||||
PDKBEN also has a hack for power on
|
||||
should also not transfer data to SD card when MOSI, MISO or SPICLK1 are disabled
|
||||
port d data register INT* bits seem to have there data bits cleared when an edge triggered interrupt is cleared(according to MC68VZ328UM.pdf Page 10-15)
|
||||
|
||||
Memory:
|
||||
SD card can't be read or written to by Palm OS
|
||||
@@ -57,6 +53,11 @@ MakePalmBitmap:
|
||||
|
||||
|
||||
Fixed:
|
||||
edge triggered INT* don't clear on write to ISR when masked in IMR(I needed to use (ints & ~IMR) not (ints & IMR) which only triggers disable interrupts while blocking active ones)
|
||||
PDKBEN also has a hack for power on(its been removed)
|
||||
On hardware PDIRQEG seems not to actually work at all(CPUID:0x57000000)(it does)
|
||||
may need to trigger an interrupt if a IMR masked interrupt becomes unmasked and its bit is still set in IPR(already doing that)
|
||||
Cyclone will cause SIGSEGVs, don't know why yet(seems to have been caused by compressed jumptable)
|
||||
power button must be pushed twice to turn the CPU back on(when debugging it works the first time, then must be pushed twice to turn off instead of on)(this also occurs in the RetroArch build)
|
||||
the power button double press issue may be because the button map I am using was taken from POSE source, the power button may be mapped to other locations on the button matrix than expected
|
||||
if a sound interrupt is triggered while the button interrupt is disabled the button interrupt will still trigger(in galax game)(seems to be an issue with FIFOAV always = true hack and how INT_PWM1 needed to be cleared on read or write)
|
||||
|
||||
@@ -28,15 +28,15 @@ else ifeq ($(platform), osx)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter qnx vita ctr rpi2 classic_armv7_a7,$(platform)))
|
||||
EMU_OPTIMIZE_FOR_ARM32 = 1
|
||||
else ifneq (,$(findstring armv7,$(platform)))
|
||||
EMU_OPTIMIZE_FOR_ARM32 = 1
|
||||
else ifneq (,$(findstring armv6,$(platform)))
|
||||
EMU_OPTIMIZE_FOR_ARM32 = 1
|
||||
else ifneq (,$(findstring armhf,$(platform)))
|
||||
EMU_OPTIMIZE_FOR_ARM32 = 1
|
||||
endif
|
||||
# ifneq (,$(filter qnx vita ctr rpi2 classic_armv7_a7,$(platform)))
|
||||
# EMU_OPTIMIZE_FOR_ARM32 = 1
|
||||
# else ifneq (,$(findstring armv7,$(platform)))
|
||||
# EMU_OPTIMIZE_FOR_ARM32 = 1
|
||||
# else ifneq (,$(findstring armv6,$(platform)))
|
||||
# EMU_OPTIMIZE_FOR_ARM32 = 1
|
||||
# else ifneq (,$(findstring armhf,$(platform)))
|
||||
# EMU_OPTIMIZE_FOR_ARM32 = 1
|
||||
# endif
|
||||
|
||||
include $(EMU_PATH)/makefile.all
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)"
|
||||
EMU_OPTIMIZE_FOR_ARM32 := 0
|
||||
|
||||
# set ASM CPU core, only use with ARMv4<->7, ARMv8 is its own architecture
|
||||
ifeq ($(TARGET_ARCH), arm)
|
||||
ifneq ($(TARGET_ARCH_ABI), arm64-v8a)
|
||||
EMU_OPTIMIZE_FOR_ARM32 := 1
|
||||
endif
|
||||
endif
|
||||
# ifeq ($(TARGET_ARCH), arm)
|
||||
# ifneq ($(TARGET_ARCH_ABI), arm64-v8a)
|
||||
# EMU_OPTIMIZE_FOR_ARM32 := 1
|
||||
# endif
|
||||
# endif
|
||||
|
||||
include $(CORE_DIR)/build/Makefile.common
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#define JOYSTICK_DEADZONE 4000
|
||||
#define JOYSTICK_MULTIPLIER 0.0001
|
||||
#define SCREEN_HIRES (!(palmFramebufferWidth == 160 && palmFramebufferHeight == 220))
|
||||
|
||||
|
||||
static retro_log_printf_t log_cb;
|
||||
@@ -28,10 +29,6 @@ static retro_environment_t environ_cb;
|
||||
static retro_input_poll_t input_poll_cb;
|
||||
static retro_input_state_t input_state_cb;
|
||||
|
||||
static bool screenHires;
|
||||
static uint16_t screenWidth;
|
||||
static uint16_t screenHeight;
|
||||
static uint16_t screenData[320 * 440];
|
||||
static uint32_t emuFeatures;
|
||||
static bool useJoystickAsMouse;
|
||||
static float touchCursorX;
|
||||
@@ -39,7 +36,7 @@ static float touchCursorY;
|
||||
|
||||
|
||||
static void renderMouseCursor(int16_t screenX, int16_t screenY){
|
||||
if(screenHires){
|
||||
if(SCREEN_HIRES){
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
|
||||
@@ -48,9 +45,9 @@ static void renderMouseCursor(int16_t screenX, int16_t screenY){
|
||||
|
||||
for(y = 0; y < 32; y++)
|
||||
for(x = 6; x < 26; x++)
|
||||
if(screenX + x >= 0 && screenY + y >= 0 && screenX + x < 320 && screenY + y < 440)
|
||||
if(screenX + x >= 0 && screenY + y >= 0 && screenX + x < palmFramebufferWidth && screenY + y < palmFramebufferHeight)
|
||||
if(cursor32x32[y * 32 + x] != 0xFFFF)
|
||||
screenData[(screenY + y) * 320 + screenX + x] = cursor32x32[y * 32 + x];
|
||||
palmFramebuffer[(screenY + y) * palmFramebufferWidth + screenX + x] = cursor32x32[y * 32 + x];
|
||||
}
|
||||
else{
|
||||
int8_t x;
|
||||
@@ -61,9 +58,9 @@ static void renderMouseCursor(int16_t screenX, int16_t screenY){
|
||||
|
||||
for(y = 0; y < 16; y++)
|
||||
for(x = 3; x < 13; x++)
|
||||
if(screenX + x >= 0 && screenY + y >= 0 && screenX + x < 160 && screenY + y < 220)
|
||||
if(screenX + x >= 0 && screenY + y >= 0 && screenX + x < palmFramebufferWidth && screenY + y < palmFramebufferHeight)
|
||||
if(cursor16x16[y * 16 + x] != 0xFFFF)
|
||||
screenData[(screenY + y) * 160 + screenX + x] = cursor16x16[y * 16 + x];
|
||||
palmFramebuffer[(screenY + y) * palmFramebufferWidth + screenX + x] = cursor16x16[y * 16 + x];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,10 +95,10 @@ static void check_variables(bool booting){
|
||||
if (!strcmp(var.value, "enabled"))
|
||||
emuFeatures |= FEATURE_HYBRID_CPU;
|
||||
|
||||
var.key = "palm_emu_feature_320x320";
|
||||
var.key = "palm_emu_feature_custom_fb";
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
if (!strcmp(var.value, "enabled"))
|
||||
emuFeatures |= FEATURE_320x320;
|
||||
emuFeatures |= FEATURE_CUSTOM_FB;
|
||||
|
||||
var.key = "palm_emu_feature_synced_rtc";
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
@@ -170,8 +167,8 @@ void retro_get_system_av_info(struct retro_system_av_info *info){
|
||||
|
||||
info->geometry.base_width = 160;
|
||||
info->geometry.base_height = 220;
|
||||
info->geometry.max_width = 320;
|
||||
info->geometry.max_height = 440;
|
||||
info->geometry.max_width = 480;
|
||||
info->geometry.max_height = 480;
|
||||
info->geometry.aspect_ratio = 160.0 / 220.0;
|
||||
}
|
||||
|
||||
@@ -182,7 +179,7 @@ void retro_set_environment(retro_environment_t cb){
|
||||
{ "palm_emu_feature_ram_huge", "Extra RAM Hack; disabled|enabled" },
|
||||
{ "palm_emu_feature_fast_cpu", "Overclock 2x; disabled|enabled" },
|
||||
{ "palm_emu_feature_hybrid_cpu", "Extra RAM Hack; disabled|enabled" },
|
||||
{ "palm_emu_feature_320x320", "Double Resolution; disabled|enabled" },
|
||||
{ "palm_emu_feature_custom_fb", "Custom Resolution; disabled|enabled" },
|
||||
{ "palm_emu_feature_synced_rtc", "Force Match System Clock; disabled|enabled" },
|
||||
{ "palm_emu_feature_hle_apis", "HLE API Implementations; disabled|enabled" },
|
||||
{ "palm_emu_feature_emu_honest", "Tell Programs They're In An Emulator(for test programs); disabled|enabled" },
|
||||
@@ -254,23 +251,23 @@ void retro_run(void){
|
||||
int16_t y = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
|
||||
|
||||
if(x < -JOYSTICK_DEADZONE || x > JOYSTICK_DEADZONE)
|
||||
touchCursorX += x * JOYSTICK_MULTIPLIER * (screenHires ? 2.0 : 1.0);
|
||||
touchCursorX += x * JOYSTICK_MULTIPLIER * (SCREEN_HIRES ? 2.0 : 1.0);
|
||||
|
||||
if(y < -JOYSTICK_DEADZONE || y > JOYSTICK_DEADZONE)
|
||||
touchCursorY += y * JOYSTICK_MULTIPLIER * (screenHires ? 2.0 : 1.0);
|
||||
touchCursorY += y * JOYSTICK_MULTIPLIER * (SCREEN_HIRES ? 2.0 : 1.0);
|
||||
|
||||
if(touchCursorX < 0)
|
||||
touchCursorX = 0;
|
||||
else if(touchCursorX > screenWidth - 1)
|
||||
touchCursorX = screenWidth - 1;
|
||||
else if(touchCursorX > palmFramebufferWidth - 1)
|
||||
touchCursorX = palmFramebufferWidth - 1;
|
||||
|
||||
if(touchCursorY < 0)
|
||||
touchCursorY = 0;
|
||||
else if(touchCursorY > screenHeight - 1)
|
||||
touchCursorY = screenHeight - 1;
|
||||
else if(touchCursorY > palmFramebufferHeight - 1)
|
||||
touchCursorY = palmFramebufferHeight - 1;
|
||||
|
||||
palmInput.touchscreenX = touchCursorX / (screenWidth - 1);
|
||||
palmInput.touchscreenY = touchCursorY / (screenHeight - 1);
|
||||
palmInput.touchscreenX = touchCursorX / (palmFramebufferWidth - 1);
|
||||
palmInput.touchscreenY = touchCursorY / (palmFramebufferHeight - 1);
|
||||
palmInput.touchscreenTouched = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2);
|
||||
}
|
||||
else{
|
||||
@@ -298,13 +295,12 @@ void retro_run(void){
|
||||
|
||||
//run emulator
|
||||
emulatorRunFrame();
|
||||
memcpy(screenData, screenHires ? palmExtendedFramebuffer : palmFramebuffer, screenWidth * screenHeight * sizeof(uint16_t));
|
||||
|
||||
//draw mouse
|
||||
if(useJoystickAsMouse)
|
||||
renderMouseCursor(touchCursorX, touchCursorY);
|
||||
|
||||
video_cb(screenData, screenWidth, screenHeight, screenWidth * sizeof(uint16_t));
|
||||
video_cb(palmFramebuffer, palmFramebufferWidth, palmFramebufferHeight, palmFramebufferWidth * sizeof(uint16_t));
|
||||
audio_cb(palmAudio, AUDIO_SAMPLES_PER_FRAME);
|
||||
}
|
||||
|
||||
@@ -378,11 +374,9 @@ bool retro_load_game(const struct retro_game_info *info){
|
||||
timeInfo = localtime(&rawTime);
|
||||
emulatorSetRtc(timeInfo->tm_yday, timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);
|
||||
|
||||
screenHires = emuFeatures & FEATURE_320x320;
|
||||
screenWidth = screenHires ? 320 : 160;
|
||||
screenHeight = screenHires ? 440 : 220;
|
||||
touchCursorX = screenWidth / 2;
|
||||
touchCursorY = screenHeight / 2;
|
||||
//set mouse position
|
||||
touchCursorX = palmFramebufferWidth / 2;
|
||||
touchCursorY = palmFramebufferHeight / 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ android{
|
||||
QMAKE_CXXFLAGS += -fopenmp
|
||||
QMAKE_LFLAGS += -fopenmp
|
||||
DEFINES += EMU_MULTITHREADED
|
||||
CONFIG += optimize_for_arm32 # for now, later this will check if building for ARMv4<->7
|
||||
# CONFIG += optimize_for_arm32 # for now, later this will check if building for ARMv4<->7
|
||||
}
|
||||
|
||||
ios{
|
||||
|
||||
@@ -67,8 +67,6 @@ EmuWrapper::EmuWrapper(){
|
||||
emuThreadJoin = false;
|
||||
emuRunning = false;
|
||||
emuPaused = false;
|
||||
emuVideoWidth = 0;
|
||||
emuVideoHeight = 0;
|
||||
emuNewFrameReady = false;
|
||||
|
||||
frontendDebugString = new char[200];
|
||||
@@ -189,15 +187,6 @@ uint32_t EmuWrapper::init(const QString& romPath, const QString& bootloaderPath,
|
||||
}
|
||||
}
|
||||
|
||||
if(features & FEATURE_320x320){
|
||||
emuVideoWidth = 320;
|
||||
emuVideoHeight = 320 + 120;
|
||||
}
|
||||
else{
|
||||
emuVideoWidth = 160;
|
||||
emuVideoHeight = 160 + 60;
|
||||
}
|
||||
|
||||
emuInput = palmInput;
|
||||
emuRamFilePath = ramPath;
|
||||
emuSdCardFilePath = sdCardPath;
|
||||
@@ -327,7 +316,7 @@ uint32_t EmuWrapper::loadState(const QString& path){
|
||||
return error;
|
||||
}
|
||||
|
||||
uint32_t EmuWrapper::installApplication(QString path){
|
||||
uint32_t EmuWrapper::installApplication(const QString& path){
|
||||
bool wasPaused = isPaused();
|
||||
uint32_t error = EMU_ERROR_INVALID_PARAMETER;
|
||||
QFile appFile(path);
|
||||
|
||||
@@ -21,8 +21,6 @@ private:
|
||||
std::atomic<bool> emuThreadJoin;
|
||||
std::atomic<bool> emuRunning;
|
||||
std::atomic<bool> emuPaused;
|
||||
uint16_t emuVideoWidth;
|
||||
uint16_t emuVideoHeight;
|
||||
std::atomic<bool> emuNewFrameReady;
|
||||
QString emuRamFilePath;
|
||||
QString emuSdCardFilePath;
|
||||
@@ -45,19 +43,19 @@ public:
|
||||
bool isRunning() const{return emuRunning;}
|
||||
bool isPaused() const{return emuPaused;}
|
||||
|
||||
uint32_t installApplication(QString path);
|
||||
uint32_t installApplication(const QString& path);
|
||||
|
||||
std::vector<QString>& getDebugStrings();
|
||||
std::vector<uint64_t>& getDuplicateCallCount();
|
||||
std::vector<uint32_t> getCpuRegisters();
|
||||
|
||||
uint16_t screenWidth() const{return emuVideoWidth;}
|
||||
uint16_t screenHeight() const{return emuVideoHeight;}
|
||||
uint16_t screenWidth() const{return palmFramebufferWidth;}
|
||||
uint16_t screenHeight() const{return palmFramebufferHeight;}
|
||||
bool newFrameReady() const{return emuNewFrameReady;}
|
||||
void frameHandled(){emuNewFrameReady = false;}
|
||||
|
||||
//calling these while newFrameReady() == false is undefined behavior, the other thread may be writing to them
|
||||
const QPixmap getFramebuffer(){return QPixmap::fromImage(QImage((uchar*)(emuVideoWidth == 320 ? palmExtendedFramebuffer : palmFramebuffer), emuVideoWidth, emuVideoHeight, emuVideoWidth * sizeof(uint16_t), QImage::Format_RGB16));}
|
||||
const QPixmap getFramebuffer(){return QPixmap::fromImage(QImage((uchar*)palmFramebuffer, palmFramebufferWidth, palmFramebufferHeight, palmFramebufferWidth * sizeof(uint16_t), QImage::Format_RGB16));}
|
||||
const int16_t* getAudioSamples() const{return palmAudio;}
|
||||
bool getPowerButtonLed() const{return palmMisc.powerButtonLed;}
|
||||
|
||||
|
||||
@@ -53,9 +53,10 @@ void printLastRun(){
|
||||
MainWindow::MainWindow(QWidget* parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow){
|
||||
ui->setupUi(this);
|
||||
|
||||
QAudioFormat format;
|
||||
QString resourceDirPath;
|
||||
|
||||
//audio output
|
||||
format.setSampleRate(AUDIO_SAMPLE_RATE);
|
||||
format.setChannelCount(2);
|
||||
format.setSampleSize(16);
|
||||
@@ -67,6 +68,7 @@ MainWindow::MainWindow(QWidget* parent) :
|
||||
#endif
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
|
||||
//submodules
|
||||
settings = new QSettings(QDir::homePath() + "/MuCfg.txt", QSettings::IniFormat);//settings is public, create it first
|
||||
stateManager = new StateManager(this);
|
||||
emuDebugger = new DebugViewer(this);
|
||||
@@ -74,6 +76,27 @@ MainWindow::MainWindow(QWidget* parent) :
|
||||
audioDevice = new QAudioOutput(format, this);
|
||||
audioOut = audioDevice->start();
|
||||
|
||||
//resource directory
|
||||
resourceDirPath = settings->value("resourceDirectory", "").toString();
|
||||
|
||||
//get default path if path not set
|
||||
if(resourceDirPath == ""){
|
||||
#if defined(Q_OS_ANDROID)
|
||||
resourceDirPath = "/sdcard/Mu";
|
||||
#elif defined(Q_OS_IOS)
|
||||
resourceDirPath = "/var/mobile/Media/Mu";
|
||||
#else
|
||||
resourceDirPath = QDir::homePath() + "/Mu";
|
||||
#endif
|
||||
settings->setValue("resourceDirectory", resourceDirPath);
|
||||
}
|
||||
|
||||
//create directory tree, in case someone deleted it since the emu was last run or it was never created
|
||||
createHomeDirectoryTree(resourceDirPath);
|
||||
|
||||
//GUI
|
||||
ui->setupUi(this);
|
||||
|
||||
//this makes the display window and button icons resize properly
|
||||
ui->centralWidget->installEventFilter(this);
|
||||
ui->centralWidget->setObjectName("centralWidget");
|
||||
@@ -97,29 +120,9 @@ MainWindow::MainWindow(QWidget* parent) :
|
||||
ui->screenshot->installEventFilter(this);
|
||||
ui->stateManager->installEventFilter(this);
|
||||
|
||||
|
||||
QString resourceDirPath = settings->value("resourceDirectory", "").toString();
|
||||
|
||||
//use default path if path not set
|
||||
if(resourceDirPath == ""){
|
||||
#if defined(Q_OS_ANDROID)
|
||||
resourceDirPath = "/sdcard/Mu";
|
||||
#elif defined(Q_OS_IOS)
|
||||
resourceDirPath = "/var/mobile/Media/Mu";
|
||||
#else
|
||||
resourceDirPath = QDir::homePath() + "/Mu";
|
||||
#endif
|
||||
settings->setValue("resourceDirectory", resourceDirPath);
|
||||
}
|
||||
|
||||
//create directory tree, in case someone deleted it since the emu was last run
|
||||
createHomeDirectoryTree(resourceDirPath);
|
||||
|
||||
|
||||
#if !defined(EMU_DEBUG) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
ui->debugger->hide();
|
||||
#endif
|
||||
|
||||
connect(refreshDisplay, SIGNAL(timeout()), this, SLOT(updateDisplay()));
|
||||
refreshDisplay->start(1000 / EMU_FPS);//update display every X milliseconds
|
||||
}
|
||||
@@ -290,7 +293,7 @@ void MainWindow::on_right_released(){
|
||||
void MainWindow::on_ctrlBtn_clicked(){
|
||||
if(!emu.isInited()){
|
||||
QString sysDir = settings->value("resourceDirectory", "").toString();
|
||||
uint32_t error = emu.init(sysDir + "/palmos41-en-m515.rom", QFile(sysDir + "/bootloader-en-m515.rom").exists() ? sysDir + "/bootloader-en-m515.rom" : "", sysDir + "/userdata-en-m515.ram", sysDir + "/sd-en-m515.img", FEATURE_320x320 | FEATURE_DEBUG);
|
||||
uint32_t error = emu.init(sysDir + "/palmos41-en-m515.rom", QFile(sysDir + "/bootloader-en-m515.rom").exists() ? sysDir + "/bootloader-en-m515.rom" : "", sysDir + "/userdata-en-m515.ram", sysDir + "/sd-en-m515.img", FEATURE_CUSTOM_FB | FEATURE_DEBUG);
|
||||
if(error == EMU_ERROR_NONE){
|
||||
ui->calendar->setEnabled(true);
|
||||
ui->addressBook->setEnabled(true);
|
||||
@@ -372,7 +375,6 @@ void MainWindow::on_stateManager_clicked(){
|
||||
if(!wasPaused)
|
||||
emu.pause();
|
||||
|
||||
stateManager->updateStateList();
|
||||
stateManager->exec();
|
||||
|
||||
if(!wasPaused)
|
||||
|
||||
@@ -20,12 +20,21 @@ StateManager::StateManager(QWidget* parent) :
|
||||
//this allows resizing the screenshot of the savestate
|
||||
ui->statePreview->installEventFilter(this);
|
||||
ui->statePreview->setObjectName("statePreview");
|
||||
|
||||
updateStateList();
|
||||
}
|
||||
|
||||
StateManager::~StateManager(){
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool StateManager::eventFilter(QObject* object, QEvent* event){
|
||||
if(object->objectName() == "statePreview" && event->type() == QEvent::Resize)
|
||||
updateStatePreview();
|
||||
|
||||
return QDialog::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void StateManager::updateStateList(){
|
||||
MainWindow* parent = (MainWindow*)parentWidget();
|
||||
QString saveDirPath = parent->settings->value("resourceDirectory", "").toString() + "/saveStates";
|
||||
@@ -47,21 +56,27 @@ void StateManager::updateStateList(){
|
||||
}
|
||||
}
|
||||
|
||||
bool StateManager::eventFilter(QObject* object, QEvent* event){
|
||||
if(object->objectName() == "statePreview" && event->type() == QEvent::Resize)
|
||||
updateStatePreview();
|
||||
|
||||
return QDialog::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void StateManager::updateStatePreview(){
|
||||
if(ui->states->currentItem()){
|
||||
MainWindow* parent = (MainWindow*)parentWidget();
|
||||
QString statePath = parent->settings->value("resourceDirectory", "").toString() + "/saveStates/" + ui->states->currentItem()->text();
|
||||
|
||||
ui->statePreview->setPixmap(QPixmap(statePath + ".png").scaled(ui->statePreview->width() * 0.98, ui->statePreview->height() * 0.98, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
ui->statePreview->update();
|
||||
}
|
||||
else{
|
||||
//remove outdated image
|
||||
ui->statePreview->clear();
|
||||
}
|
||||
|
||||
ui->statePreview->update();
|
||||
}
|
||||
|
||||
int StateManager::getStateIndexRowByName(const QString& name){
|
||||
for(int index = 0; index < ui->states->count(); index++)
|
||||
if(ui->states->item(index)->text() == name)
|
||||
return index;
|
||||
|
||||
return -1;//nothing by that name exists
|
||||
}
|
||||
|
||||
void StateManager::on_saveState_clicked(){
|
||||
@@ -72,6 +87,8 @@ void StateManager::on_saveState_clicked(){
|
||||
parent->emu.saveState(statePath + ".state");
|
||||
parent->emu.getFramebuffer().save(statePath + ".png");
|
||||
updateStateList();
|
||||
|
||||
ui->states->setCurrentRow(getStateIndexRowByName(ui->newStateName->text()));//this also updates the preview image
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +109,7 @@ void StateManager::on_deleteState_clicked(){
|
||||
QFile(statePath + ".state").remove();
|
||||
QFile(statePath + ".png").remove();
|
||||
updateStateList();
|
||||
|
||||
ui->states->setCurrentRow(0);//pick first valid entry since the old one is no longer valid
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ public:
|
||||
explicit StateManager(QWidget* parent = nullptr);
|
||||
~StateManager();
|
||||
|
||||
void updateStateList();
|
||||
|
||||
private slots:
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
|
||||
void updateStateList();
|
||||
void updateStatePreview();
|
||||
int getStateIndexRowByName(const QString& name);
|
||||
|
||||
void on_saveState_clicked();
|
||||
void on_loadState_clicked();
|
||||
|
||||
@@ -39,7 +39,8 @@ input_t palmInput;
|
||||
sd_card_t palmSdCard;
|
||||
misc_hw_t palmMisc;
|
||||
uint16_t* palmFramebuffer;
|
||||
uint16_t* palmExtendedFramebuffer;
|
||||
uint16_t palmFramebufferWidth;
|
||||
uint16_t palmFramebufferHeight;
|
||||
int16_t* palmAudio;
|
||||
blip_t* palmAudioResampler;
|
||||
uint32_t palmSpecialFeatures;
|
||||
@@ -61,21 +62,16 @@ uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t spec
|
||||
palmRam = malloc(((specialFeatures & FEATURE_RAM_HUGE) ? SUPERMASSIVE_RAM_SIZE : RAM_SIZE) + 4);
|
||||
palmRom = malloc(ROM_SIZE + 4);
|
||||
palmReg = malloc(REG_SIZE + 4);
|
||||
palmFramebuffer = malloc(160 * (160 + 60) * sizeof(uint16_t));//really 160*160, the extra pixels are the silkscreened digitizer area
|
||||
palmFramebuffer = malloc(480 * 480 * sizeof(uint16_t));
|
||||
palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t));
|
||||
palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples
|
||||
if(specialFeatures & FEATURE_320x320)
|
||||
palmExtendedFramebuffer = malloc(320 * (320 + 120) * sizeof(uint16_t));//really 320*320, the extra pixels are the silkscreened digitizer area
|
||||
else
|
||||
palmExtendedFramebuffer = NULL;
|
||||
if(!palmRam || !palmRom || !palmReg || !palmFramebuffer || !palmAudio || !palmAudioResampler || (!palmExtendedFramebuffer && (specialFeatures & FEATURE_320x320))){
|
||||
if(!palmRam || !palmRom || !palmReg || !palmFramebuffer || !palmAudio || !palmAudioResampler){
|
||||
free(palmRam);
|
||||
free(palmRom);
|
||||
free(palmReg);
|
||||
free(palmFramebuffer);
|
||||
free(palmAudio);
|
||||
blip_delete(palmAudioResampler);
|
||||
free(palmExtendedFramebuffer);
|
||||
return EMU_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
@@ -94,15 +90,11 @@ uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t spec
|
||||
else{
|
||||
memset(palmReg + REG_SIZE - 1 - BOOTLOADER_SIZE, 0x00, BOOTLOADER_SIZE);
|
||||
}
|
||||
memset(palmFramebuffer, 0x00, 160 * 160 * sizeof(uint16_t));
|
||||
memcpy(palmFramebuffer + 160 * 160, silkscreen160x60, 160 * 60 * sizeof(uint16_t));
|
||||
if(palmExtendedFramebuffer){
|
||||
memset(palmExtendedFramebuffer, 0x00, 320 * 320 * sizeof(uint16_t));
|
||||
memcpy(palmExtendedFramebuffer + 320 * 320, silkscreen320x120, 320 * 120 * sizeof(uint16_t));
|
||||
}
|
||||
memset(palmAudio, 0x00, AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
|
||||
memset(&palmInput, 0x00, sizeof(palmInput));
|
||||
memset(&palmMisc, 0x00, sizeof(palmMisc));
|
||||
palmFramebufferWidth = 160;
|
||||
palmFramebufferHeight = 220;
|
||||
palmMisc.batteryLevel = 100;
|
||||
palmCycleCounter = 0.0;
|
||||
palmClockMultiplier = (specialFeatures & FEATURE_FAST_CPU) ? 2.00 : 1.00;//overclock
|
||||
@@ -114,11 +106,11 @@ uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t spec
|
||||
sandboxInit();
|
||||
|
||||
//reset everything
|
||||
flx68000Reset();
|
||||
sed1376Reset();
|
||||
ads7846Reset();
|
||||
pdiUsbD12Reset();
|
||||
sdCardReset();
|
||||
flx68000Reset();
|
||||
setRtc(0, 0, 0, 0);//RTCTIME and DAYR are not cleared by reset, clear them manually in case the frontend doesnt set the RTC
|
||||
|
||||
emulatorInitialized = true;
|
||||
@@ -137,7 +129,6 @@ void emulatorExit(void){
|
||||
free(palmFramebuffer);
|
||||
free(palmAudio);
|
||||
blip_delete(palmAudioResampler);
|
||||
free(palmExtendedFramebuffer);
|
||||
free(palmSdCard.flashChip.data);
|
||||
emulatorInitialized = false;
|
||||
}
|
||||
@@ -146,24 +137,25 @@ void emulatorExit(void){
|
||||
void emulatorHardReset(void){
|
||||
//equivalent to taking the battery out and putting it back in
|
||||
memset(palmRam, 0x00, palmSpecialFeatures & FEATURE_RAM_HUGE ? SUPERMASSIVE_RAM_SIZE : RAM_SIZE);
|
||||
memset(palmFramebuffer, 0x00, 160 * 160 * sizeof(uint16_t));
|
||||
if(palmExtendedFramebuffer)
|
||||
memset(palmExtendedFramebuffer, 0x00, 320 * 320 * sizeof(uint16_t));
|
||||
flx68000Reset();
|
||||
palmFramebufferWidth = 160;
|
||||
palmFramebufferHeight = 220;
|
||||
sed1376Reset();
|
||||
ads7846Reset();
|
||||
pdiUsbD12Reset();
|
||||
sdCardReset();
|
||||
flx68000Reset();
|
||||
setRtc(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void emulatorSoftReset(void){
|
||||
//equivalent to pushing the reset button on the back of the device
|
||||
flx68000Reset();
|
||||
palmFramebufferWidth = 160;
|
||||
palmFramebufferHeight = 220;
|
||||
sed1376Reset();
|
||||
ads7846Reset();
|
||||
pdiUsbD12Reset();
|
||||
sdCardReset();
|
||||
flx68000Reset();
|
||||
}
|
||||
|
||||
void emulatorSetRtc(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds){
|
||||
@@ -176,6 +168,7 @@ uint64_t emulatorGetStateSize(void){
|
||||
size += sizeof(uint32_t);//save state version
|
||||
size += sizeof(uint32_t);//palmSpecialFeatures
|
||||
size += sizeof(uint64_t);//palmSdCard.flashChip.size, needs to be done first to verify the malloc worked
|
||||
size += sizeof(uint16_t) * 2;//palmFramebuffer(Width/Height)
|
||||
size += flx68000StateSize();
|
||||
size += sed1376StateSize();
|
||||
size += ads7846StateSize();
|
||||
@@ -203,7 +196,7 @@ uint64_t emulatorGetStateSize(void){
|
||||
size += sizeof(uint8_t) * 2;//pwm1(Read/Write)
|
||||
size += sizeof(uint8_t) * 7;//palmMisc
|
||||
size += sizeof(uint64_t) * 2;//palmSdCard.command / palmSdCard.responseState
|
||||
size += sizeof(uint8_t) * 2;//palmSdCard.commandBitsRemaining / palmSdCard.response
|
||||
size += sizeof(uint8_t) * 4;//palmSdCard.commandBitsRemaining / palmSdCard.response / palmSdCard.allowInvalidCrc / palmSdCard.chipSelect
|
||||
size += palmSdCard.flashChip.size;//palmSdCard.flashChip.data
|
||||
|
||||
return size;
|
||||
@@ -228,6 +221,12 @@ bool emulatorSaveState(buffer_t buffer){
|
||||
writeStateValue64(buffer.data + offset, palmSdCard.flashChip.size);
|
||||
offset += sizeof(uint64_t);
|
||||
|
||||
//screen state
|
||||
writeStateValue16(buffer.data + offset, palmFramebufferWidth);
|
||||
offset += sizeof(uint16_t);
|
||||
writeStateValue16(buffer.data + offset, palmFramebufferHeight);
|
||||
offset += sizeof(uint16_t);
|
||||
|
||||
//chips
|
||||
flx68000SaveState(buffer.data + offset);
|
||||
offset += flx68000StateSize();
|
||||
@@ -356,6 +355,10 @@ bool emulatorSaveState(buffer_t buffer){
|
||||
offset += sizeof(uint8_t);
|
||||
writeStateValue64(buffer.data + offset, palmSdCard.responseState);
|
||||
offset += sizeof(uint64_t);
|
||||
writeStateValue8(buffer.data + offset, palmSdCard.allowInvalidCrc);
|
||||
offset += sizeof(uint8_t);
|
||||
writeStateValue8(buffer.data + offset, palmSdCard.chipSelect);
|
||||
offset += sizeof(uint8_t);
|
||||
memcpy(buffer.data + offset, palmSdCard.flashChip.data, palmSdCard.flashChip.size);
|
||||
offset += palmSdCard.flashChip.size;
|
||||
|
||||
@@ -385,6 +388,12 @@ bool emulatorLoadState(buffer_t buffer){
|
||||
return false;
|
||||
offset += sizeof(uint64_t);
|
||||
|
||||
//screen state
|
||||
palmFramebufferWidth = readStateValue16(buffer.data + offset);
|
||||
offset += sizeof(uint16_t);
|
||||
palmFramebufferHeight = readStateValue16(buffer.data + offset);
|
||||
offset += sizeof(uint16_t);
|
||||
|
||||
//chips
|
||||
flx68000LoadState(buffer.data + offset);
|
||||
offset += flx68000StateSize();
|
||||
@@ -513,6 +522,10 @@ bool emulatorLoadState(buffer_t buffer){
|
||||
offset += sizeof(uint8_t);
|
||||
palmSdCard.responseState = readStateValue64(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
palmSdCard.allowInvalidCrc = readStateValue8(buffer.data + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
palmSdCard.chipSelect = readStateValue8(buffer.data + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
if(palmSdCard.flashChip.data)
|
||||
free(palmSdCard.flashChip.data);
|
||||
palmSdCard.flashChip.data = stateSdCardBuffer;
|
||||
@@ -609,27 +622,13 @@ void emulatorRunFrame(void){
|
||||
|
||||
//video
|
||||
sed1376Render();
|
||||
|
||||
//render in 320x320 mode
|
||||
if(palmExtendedFramebuffer){
|
||||
uint16_t pixCopyX;
|
||||
uint16_t pixCopyY;
|
||||
|
||||
//scale original framebuffer to large one if enabled, this alone doesnt increase resolution, that requires a driver
|
||||
//scale horizontal
|
||||
MULTITHREAD_DOUBLE_LOOP(pixCopyX, pixCopyY) for(pixCopyY = 0; pixCopyY < 160; pixCopyY++){
|
||||
for(pixCopyX = 0; pixCopyX < 160; pixCopyX++){
|
||||
palmExtendedFramebuffer[pixCopyY * 320 * 2 + pixCopyX * 2] = palmFramebuffer[pixCopyY * 160 + pixCopyX];
|
||||
palmExtendedFramebuffer[pixCopyY * 320 * 2 + pixCopyX * 2 + 1] = palmFramebuffer[pixCopyY * 160 + pixCopyX];
|
||||
}
|
||||
}
|
||||
//scale vertical
|
||||
MULTITHREAD_LOOP(pixCopyY) for(pixCopyY = 0; pixCopyY < 160; pixCopyY++)
|
||||
memcpy(palmExtendedFramebuffer + pixCopyY * 320 * 2 + 320, palmExtendedFramebuffer + pixCopyY * 320 * 2, 320 * sizeof(uint16_t));
|
||||
|
||||
|
||||
//replace all black pixels in 160x160 with those from 320x320 framebuffer memory, only if black in both buffers will the display color be black, this allows all the 160x160 APIs to work on the larger framebuffer seamlessly
|
||||
if(palmFramebufferWidth == 160 && palmFramebufferHeight == 220){
|
||||
//simple render
|
||||
memcpy(palmFramebuffer, sed1376Framebuffer, 160 * 160 * sizeof(uint16_t));
|
||||
memcpy(palmFramebuffer + 160 * 160, silkscreen160x60, 160 * 60 * sizeof(uint16_t));
|
||||
}
|
||||
else{
|
||||
//advanced render
|
||||
//DRIVER NEEDS TO BE WRITTEN STILL
|
||||
//the above was enabled early so using the hires silkscreen and mouse cursor was possible in RetroArch
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ typedef struct{
|
||||
uint8_t commandBitsRemaining;
|
||||
uint8_t response;
|
||||
uint64_t responseState;//this can contain many different types of data depending on the response type
|
||||
bool allowInvalidCrc;
|
||||
bool chipSelect;
|
||||
buffer_t flashChip;
|
||||
}sd_card_t;
|
||||
|
||||
@@ -124,8 +126,9 @@ extern uint8_t* palmReg;//dont touch
|
||||
extern input_t palmInput;//write allowed
|
||||
extern sd_card_t palmSdCard;//dont touch
|
||||
extern misc_hw_t palmMisc;//read/write allowed
|
||||
extern uint16_t* palmFramebuffer;//read allowed if FEATURE_320x320 is off, or else invalid data will be displayed
|
||||
extern uint16_t* palmExtendedFramebuffer;//read allowed if FEATURE_320x320 is on, or else SIGSEGV
|
||||
extern uint16_t* palmFramebuffer;//read allowed
|
||||
extern uint16_t palmFramebufferWidth;//read allowed
|
||||
extern uint16_t palmFramebufferHeight;//read allowed
|
||||
extern int16_t* palmAudio;//read allowed, 2 channel signed 16 bit audio
|
||||
extern blip_t* palmAudioResampler;//dont touch
|
||||
extern uint32_t palmSpecialFeatures;//read allowed
|
||||
|
||||
@@ -187,7 +187,7 @@ static void checkPortDInterrupts(void){
|
||||
uint8_t portDInterruptEdgeTriggered = icrEdgeTriggered | registerArrayRead8(PDIRQEG);
|
||||
uint8_t portDInterruptEnabled = (~registerArrayRead8(PDSEL) & 0xF0) | registerArrayRead8(PDIRQEN);
|
||||
uint8_t portDIsInput = ~registerArrayRead8(PDDIR);
|
||||
uint8_t portDInterruptTriggered = portDInterruptValue & portDInterruptEnabled & portDIsInput & (~portDInterruptEdgeTriggered | ~portDInterruptLastValue/* & (pllIsOn() ? 0xFF : 0xF0)*/);
|
||||
uint8_t portDInterruptTriggered = portDInterruptValue & portDInterruptEnabled & portDIsInput & (~portDInterruptEdgeTriggered | ~portDInterruptLastValue & (pllIsOn() ? 0xFF : 0xF0));
|
||||
|
||||
if(portDInterruptTriggered & 0x01)
|
||||
setIprIsrBit(INT_INT0);
|
||||
@@ -229,18 +229,13 @@ static void checkPortDInterrupts(void){
|
||||
else if(!(portDInterruptEdgeTriggered & 0x80))
|
||||
clearIprIsrBit(INT_IRQ6);
|
||||
|
||||
//active low/off level triggered interrupt
|
||||
//active low/off level triggered interrupt(triggers on 0, not a pull down resistor)
|
||||
//The SELx, POLx, IQENx, and IQEGx bits have no effect on the functionality of KBENx, 10.4.5.8 Port D Keyboard Enable Register MC68VZ328UM.pdf
|
||||
//the above seems like a lie, 10.4.4 Port D Operation MC68VZ328UM.pdf
|
||||
//completely removing PDKBEN is not accurate but makes the buttons function properly
|
||||
//I am fairly sure that port d is not documented properly by the data sheet so Im going with what works properly right now
|
||||
//the "!pllIsOn() &&" is a hack, it prevents rapid button presses, but allows INT_KB to turn the device back on
|
||||
/*
|
||||
if(!pllIsOn() && registerArrayRead8(PDKBEN) & getPortDValue() ^ registerArrayRead8(PDPOL))
|
||||
//the above has finally been verified to be correct!
|
||||
if(registerArrayRead8(PDKBEN) & ~(getPortDValue() ^ registerArrayRead8(PDPOL)) & portDIsInput)
|
||||
setIprIsrBit(INT_KB);
|
||||
else
|
||||
clearIprIsrBit(INT_KB);
|
||||
*/
|
||||
|
||||
//save to check against next time this function is called
|
||||
portDInterruptLastValue = portDInterruptTriggered;
|
||||
@@ -434,6 +429,7 @@ uint16_t getHwRegister16(uint32_t address){
|
||||
uint16_t fifoVal = spi1RxFifoRead();
|
||||
//check if SPI1 interrupts changed
|
||||
setSpiIntCs(registerArrayRead16(SPIINTCS));
|
||||
debugLog("SPIRXD read, FIFO value:0x%04X, SPIINTCS:0x%04X\n", fifoVal, registerArrayRead16(SPIINTCS));
|
||||
return fifoVal;
|
||||
}
|
||||
|
||||
@@ -600,6 +596,13 @@ void setHwRegister8(uint32_t address, uint8_t value){
|
||||
updateAds7846ChipSelectStatus();
|
||||
break;
|
||||
|
||||
case PJSEL:
|
||||
case PJDIR:
|
||||
case PJDATA:
|
||||
registerArrayWrite8(address, value);
|
||||
updateSdCardChipSelectStatus();
|
||||
break;
|
||||
|
||||
case PKSEL:
|
||||
case PKDIR:
|
||||
case PKDATA:
|
||||
@@ -626,7 +629,6 @@ void setHwRegister8(uint32_t address, uint8_t value){
|
||||
//select between GPIO or special function
|
||||
case PCSEL:
|
||||
case PESEL:
|
||||
case PJSEL:
|
||||
|
||||
//direction select
|
||||
case PADIR:
|
||||
@@ -634,7 +636,6 @@ void setHwRegister8(uint32_t address, uint8_t value){
|
||||
case PDDIR:
|
||||
case PEDIR:
|
||||
case PFDIR:
|
||||
case PJDIR:
|
||||
|
||||
//pull up/down enable
|
||||
case PAPUEN:
|
||||
@@ -650,7 +651,6 @@ void setHwRegister8(uint32_t address, uint8_t value){
|
||||
case PCDATA:
|
||||
case PEDATA:
|
||||
case PFDATA:
|
||||
case PJDATA:
|
||||
|
||||
//dragonball LCD controller, not attached to anything in Palm m515
|
||||
case LCKCON:
|
||||
@@ -690,13 +690,13 @@ void setHwRegister16(uint32_t address, uint16_t value){
|
||||
case IMR:
|
||||
//this is a 32 bit register but Palm OS writes to it as 16 bit chunks
|
||||
registerArrayWrite16(IMR, value & 0x00FF);
|
||||
registerArrayWrite16(ISR, registerArrayRead16(IPR) & registerArrayRead16(IMR));
|
||||
registerArrayWrite16(ISR, registerArrayRead16(IPR) & ~registerArrayRead16(IMR));
|
||||
checkInterrupts();
|
||||
break;
|
||||
case IMR + 2:
|
||||
//this is a 32 bit register but Palm OS writes to it as 16 bit chunks
|
||||
registerArrayWrite16(IMR + 2, value & 0xFFFF);//Palm OS writes to reserved bits 14 and 15
|
||||
registerArrayWrite16(ISR + 2, registerArrayRead16(IPR + 2) & registerArrayRead16(IMR + 2));
|
||||
registerArrayWrite16(ISR + 2, registerArrayRead16(IPR + 2) & ~registerArrayRead16(IMR + 2));
|
||||
checkInterrupts();
|
||||
break;
|
||||
|
||||
@@ -982,7 +982,7 @@ void setHwRegister32(uint32_t address, uint32_t value){
|
||||
|
||||
case IMR:
|
||||
registerArrayWrite32(IMR, value & 0x00FFFFFF);//Palm OS writes to reserved bits 14 and 15
|
||||
registerArrayWrite32(ISR, registerArrayRead32(IPR) & registerArrayRead32(IMR));
|
||||
registerArrayWrite32(ISR, registerArrayRead32(IPR) & ~registerArrayRead32(IMR));
|
||||
checkInterrupts();
|
||||
break;
|
||||
|
||||
@@ -1020,6 +1020,7 @@ void resetHwRegisters(void){
|
||||
memset(spi1TxFifo, 0x00, sizeof(spi1TxFifo));
|
||||
spi1RxReadPosition = 0;
|
||||
spi1RxWritePosition = 0;
|
||||
spi1RxOverflowed = false;
|
||||
spi1TxReadPosition = 0;
|
||||
spi1TxWritePosition = 0;
|
||||
pwm1ClocksToNextSample = 0;
|
||||
@@ -1146,6 +1147,7 @@ void resetHwRegisters(void){
|
||||
updatePowerButtonLedStatus();
|
||||
updateVibratorStatus();
|
||||
updateAds7846ChipSelectStatus();
|
||||
updateSdCardChipSelectStatus();
|
||||
updateBacklightAmplifierStatus();
|
||||
|
||||
palmSysclksPerClk32 = sysclksPerClk32();
|
||||
|
||||
@@ -40,21 +40,22 @@ static uint8_t spi1RxFifoEntrys(void){
|
||||
}
|
||||
|
||||
static uint16_t spi1RxFifoRead(void){
|
||||
uint16_t value = spi1RxFifo[spi1RxReadPosition];
|
||||
if(spi1RxFifoEntrys() > 0)
|
||||
spi1RxReadPosition = (spi1RxReadPosition + 1) % 9;
|
||||
spi1RxOverflowed = false;
|
||||
return value;
|
||||
|
||||
return spi1RxFifo[spi1RxReadPosition];
|
||||
}
|
||||
|
||||
static void spi1RxFifoWrite(uint16_t value){
|
||||
if(spi1RxFifoEntrys() < 8){
|
||||
spi1RxWritePosition = (spi1RxWritePosition + 1) % 9;
|
||||
spi1RxFifo[spi1RxWritePosition] = value;
|
||||
}
|
||||
else{
|
||||
spi1RxOverflowed = true;
|
||||
debugLog("SPI1 RX FIFO overflowed\n");
|
||||
}
|
||||
spi1RxFifo[spi1RxWritePosition] = value;
|
||||
}
|
||||
|
||||
static void spi1RxFifoFlush(void){
|
||||
@@ -69,10 +70,9 @@ static uint8_t spi1TxFifoEntrys(void){
|
||||
}
|
||||
|
||||
static uint16_t spi1TxFifoRead(void){
|
||||
uint16_t value = spi1TxFifo[spi1TxReadPosition];
|
||||
//dont need a safety check here, the emulator will always check that data is present before trying to access it
|
||||
spi1TxReadPosition = (spi1TxReadPosition + 1) % 9;
|
||||
return value;
|
||||
return spi1TxFifo[spi1TxReadPosition];
|
||||
}
|
||||
|
||||
static void spi1TxFifoWrite(uint16_t value){
|
||||
@@ -95,7 +95,6 @@ static uint8_t pwm1FifoEntrys(void){
|
||||
}
|
||||
|
||||
int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){
|
||||
uint8_t sample = pwm1Fifo[pwm1ReadPosition];
|
||||
uint16_t period = registerArrayRead8(PWMP1) + 2;
|
||||
uint16_t pwmc1 = registerArrayRead16(PWMC1);
|
||||
uint8_t prescaler = (pwmc1 >> 8 & 0x7F) + 1;
|
||||
@@ -103,9 +102,14 @@ int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){
|
||||
uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03);
|
||||
int32_t audioNow = now + clockOffset;
|
||||
int32_t audioSampleDuration = (pwmc1 & 0x8000)/*CLKSRC*/ ? audioGetFramePercentIncrementFromClk32s(period * prescaler * clockDivider) : audioGetFramePercentIncrementFromSysclks(period * prescaler * clockDivider);
|
||||
float dutyCycle = fMin((float)sample / period, 1.00);
|
||||
float dutyCycle;
|
||||
uint8_t index;
|
||||
|
||||
//try to get next sample, if none are available play old sample
|
||||
if(pwm1FifoEntrys() > 0)
|
||||
pwm1ReadPosition = (pwm1ReadPosition + 1) % 6;
|
||||
dutyCycle = fMin((float)pwm1Fifo[pwm1ReadPosition] / period, 1.00);
|
||||
|
||||
for(index = 0; index < repeat; index++){
|
||||
#if !defined(EMU_NO_SAFETY)
|
||||
if(audioNow + audioSampleDuration >= AUDIO_CLOCK_RATE)
|
||||
@@ -117,10 +121,6 @@ int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){
|
||||
audioNow += audioSampleDuration;
|
||||
}
|
||||
|
||||
//remove used entry
|
||||
if(pwm1FifoEntrys() > 0)
|
||||
pwm1ReadPosition = (pwm1ReadPosition + 1) % 6;
|
||||
|
||||
//check for interrupt
|
||||
if(pwm1FifoEntrys() < 2){
|
||||
//trigger interrupt if enabled
|
||||
@@ -336,7 +336,7 @@ static void setSpiIntCs(uint16_t value){
|
||||
newSpiIntCs |= (rxEntrys >= 4) << 4;//RH
|
||||
newSpiIntCs |= (rxEntrys > 0) << 3;//RR
|
||||
newSpiIntCs |= (txEntrys == 8) << 2;//TF
|
||||
newSpiIntCs |= (txEntrys >= 4) << 1;//TH
|
||||
newSpiIntCs |= (txEntrys >= 4) << 1;//TH, the datasheet contradicts itself on whether its more than or equal to 4 empty or full slots
|
||||
newSpiIntCs |= txEntrys == 0;//TE
|
||||
|
||||
//if interrupt state changed update interrupts too, top 8 bits are just the enable bits for the bottom 8
|
||||
@@ -358,7 +358,7 @@ static void setSpiCont1(uint16_t value){
|
||||
//debugLog("SPICONT1 write, old value:0x%04X, value:0x%04X\n", oldSpiCont1, value);
|
||||
|
||||
//SPI1 disabled
|
||||
if(oldSpiCont1 & 0x0200 && !(value & 0x2000)){
|
||||
if(oldSpiCont1 & 0x0200 && !(value & 0x0200)){
|
||||
spi1RxFifoFlush();
|
||||
spi1TxFifoFlush();
|
||||
}
|
||||
@@ -380,8 +380,8 @@ static void setSpiCont1(uint16_t value){
|
||||
|
||||
//The most significant bit is output when the CPU loads the transmitted data, 13.2.3 SPI 1 Phase and Polarity Configurations MC68VZ328UM.pdf
|
||||
for(bits = 0; bits < bitCount; bits++){
|
||||
newRxFifoEntry |= sdCardExchangeBit(!!(currentTxFifoEntry & startBit));
|
||||
newRxFifoEntry <<= 1;
|
||||
newRxFifoEntry |= sdCardExchangeBit(!!(currentTxFifoEntry & startBit));
|
||||
currentTxFifoEntry <<= 1;
|
||||
}
|
||||
|
||||
@@ -398,6 +398,8 @@ static void setSpiCont1(uint16_t value){
|
||||
//update SPIINTCS interrupt bits
|
||||
setSpiIntCs(registerArrayRead16(SPIINTCS));
|
||||
|
||||
//debugLog("Transfer complete, SPIINTCS:0x%04X\n", registerArrayRead16(SPIINTCS));
|
||||
|
||||
registerArrayWrite16(SPICONT1, value);
|
||||
}
|
||||
|
||||
@@ -725,6 +727,10 @@ static void updateAds7846ChipSelectStatus(void){
|
||||
ads7846SetChipSelect(!!(getPortGValue() & 0x04));
|
||||
}
|
||||
|
||||
static void updateSdCardChipSelectStatus(void){
|
||||
sdCardSetChipSelect(!!(getPortJValue() & 0x08));
|
||||
}
|
||||
|
||||
static void updateBacklightAmplifierStatus(void){
|
||||
palmMisc.backlightLevel = (palmMisc.backlightLevel > 0) ? (1 + backlightAmplifierState()) : 0;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ static uint8_t sed1376Read8(uint32_t address){
|
||||
return 0x00;
|
||||
#endif
|
||||
if(address & SED1376_MR_BIT)
|
||||
return BUFFER_READ_8_BIG_ENDIAN(sed1376Framebuffer, address, chips[CHIP_B0_SED].mask);
|
||||
return BUFFER_READ_8_BIG_ENDIAN(sed1376Ram, address, chips[CHIP_B0_SED].mask);
|
||||
else
|
||||
return sed1376GetRegister(address & chips[CHIP_B0_SED].mask);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ static uint16_t sed1376Read16(uint32_t address){
|
||||
return 0x0000;
|
||||
#endif
|
||||
if(address & SED1376_MR_BIT)
|
||||
return BUFFER_READ_16_BIG_ENDIAN(sed1376Framebuffer, address, chips[CHIP_B0_SED].mask);
|
||||
return BUFFER_READ_16_BIG_ENDIAN(sed1376Ram, address, chips[CHIP_B0_SED].mask);
|
||||
else
|
||||
return sed1376GetRegister(address & chips[CHIP_B0_SED].mask);
|
||||
}
|
||||
@@ -53,25 +53,25 @@ static uint32_t sed1376Read32(uint32_t address){
|
||||
return 0x00000000;
|
||||
#endif
|
||||
if(address & SED1376_MR_BIT)
|
||||
return BUFFER_READ_32_BIG_ENDIAN(sed1376Framebuffer, address, chips[CHIP_B0_SED].mask);
|
||||
return BUFFER_READ_32_BIG_ENDIAN(sed1376Ram, address, chips[CHIP_B0_SED].mask);
|
||||
else
|
||||
return sed1376GetRegister(address & chips[CHIP_B0_SED].mask);
|
||||
}
|
||||
static void sed1376Write8(uint32_t address, uint8_t value){
|
||||
if(address & SED1376_MR_BIT)
|
||||
BUFFER_WRITE_8_BIG_ENDIAN(sed1376Framebuffer, address, chips[CHIP_B0_SED].mask, value);
|
||||
BUFFER_WRITE_8_BIG_ENDIAN(sed1376Ram, address, chips[CHIP_B0_SED].mask, value);
|
||||
else
|
||||
sed1376SetRegister(address & chips[CHIP_B0_SED].mask, value);
|
||||
}
|
||||
static void sed1376Write16(uint32_t address, uint16_t value){
|
||||
if(address & SED1376_MR_BIT)
|
||||
BUFFER_WRITE_16_BIG_ENDIAN(sed1376Framebuffer, address, chips[CHIP_B0_SED].mask, value);
|
||||
BUFFER_WRITE_16_BIG_ENDIAN(sed1376Ram, address, chips[CHIP_B0_SED].mask, value);
|
||||
else
|
||||
sed1376SetRegister(address & chips[CHIP_B0_SED].mask, value);
|
||||
}
|
||||
static void sed1376Write32(uint32_t address, uint32_t value){
|
||||
if(address & SED1376_MR_BIT)
|
||||
BUFFER_WRITE_32_BIG_ENDIAN(sed1376Framebuffer, address, chips[CHIP_B0_SED].mask, value);
|
||||
BUFFER_WRITE_32_BIG_ENDIAN(sed1376Ram, address, chips[CHIP_B0_SED].mask, value);
|
||||
else
|
||||
sed1376SetRegister(address & chips[CHIP_B0_SED].mask, value);
|
||||
}
|
||||
|
||||
16
src/sdCard.c
16
src/sdCard.c
@@ -81,6 +81,17 @@ void sdCardReset(void){
|
||||
palmSdCard.commandBitsRemaining = 48;
|
||||
palmSdCard.responseState = 0;
|
||||
palmSdCard.response = SD_CARD_RESPONSE_NOTHING;
|
||||
palmSdCard.allowInvalidCrc = false;
|
||||
palmSdCard.chipSelect = false;
|
||||
}
|
||||
|
||||
void sdCardSetChipSelect(bool value){
|
||||
if(value != palmSdCard.chipSelect){
|
||||
//may need to perform other actions on chip select toggle too
|
||||
debugLog("SD card chip select set to:%s\n", value ? "true" : "false");
|
||||
|
||||
palmSdCard.chipSelect = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool sdCardExchangeBit(bool bit){
|
||||
@@ -155,11 +166,13 @@ bool sdCardExchangeBit(bool bit){
|
||||
#endif
|
||||
debugLog("SD command:cmd:0x%02X, arg:0x%08X, CRC:0x%02X\n", command, argument, crc);
|
||||
|
||||
if(sdCardCmdIsCrcValid(command, argument, crc)){
|
||||
if(palmSdCard.allowInvalidCrc || sdCardCmdIsCrcValid(command, argument, crc)){
|
||||
//respond with command value
|
||||
debugLog("SD valid CRC\n");
|
||||
|
||||
switch(command){
|
||||
case GO_IDLE_STATE:
|
||||
palmSdCard.allowInvalidCrc = true;
|
||||
sdCardDoResponseR1(0x01);//"idle state" bit set should be set
|
||||
break;
|
||||
|
||||
@@ -170,6 +183,7 @@ bool sdCardExchangeBit(bool bit){
|
||||
}
|
||||
else{
|
||||
//send back R1 response with CRC error set
|
||||
debugLog("SD invalid CRC\n");
|
||||
sdCardDoResponseR1(0x08);//"command CRC error" bit set
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
void sdCardReset(void);
|
||||
|
||||
void sdCardSetChipSelect(bool value);
|
||||
bool sdCardExchangeBit(bool bit);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,10 +25,11 @@
|
||||
|
||||
#define SED1376_REG_SIZE 0xB4
|
||||
#define SED1376_LUT_SIZE 0x100
|
||||
#define SED1376_FB_SIZE 0x20000//actual size is 0x14000, but that cant be masked off by address lines so size is increased to prevent buffer overflow
|
||||
#define SED1376_RAM_SIZE 0x20000//actual size is 0x14000, but that cant be masked off by address lines so size is increased to prevent buffer overflow
|
||||
|
||||
|
||||
uint8_t sed1376Framebuffer[SED1376_FB_SIZE];
|
||||
uint16_t sed1376Framebuffer[160 * 160];
|
||||
uint8_t sed1376Ram[SED1376_RAM_SIZE];
|
||||
|
||||
static uint8_t sed1376Registers[SED1376_REG_SIZE];
|
||||
static uint8_t sed1376RLut[SED1376_LUT_SIZE];
|
||||
@@ -112,7 +113,7 @@ void sed1376Reset(void){
|
||||
memset(sed1376RLut, 0x00, SED1376_LUT_SIZE);
|
||||
memset(sed1376GLut, 0x00, SED1376_LUT_SIZE);
|
||||
memset(sed1376BLut, 0x00, SED1376_LUT_SIZE);
|
||||
memset(sed1376Framebuffer, 0x00, SED1376_FB_SIZE);
|
||||
memset(sed1376Ram, 0x00, SED1376_RAM_SIZE);
|
||||
|
||||
palmMisc.backlightLevel = 0;
|
||||
palmMisc.lcdOn = false;
|
||||
@@ -131,7 +132,7 @@ uint64_t sed1376StateSize(void){
|
||||
|
||||
size += SED1376_REG_SIZE;
|
||||
size += SED1376_LUT_SIZE * 3;
|
||||
size += SED1376_FB_SIZE;
|
||||
size += SED1376_RAM_SIZE;
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -147,8 +148,8 @@ void sed1376SaveState(uint8_t* data){
|
||||
offset += SED1376_LUT_SIZE;
|
||||
memcpy(data + offset, sed1376BLut, SED1376_LUT_SIZE);
|
||||
offset += SED1376_LUT_SIZE;
|
||||
memcpy(data + offset, sed1376Framebuffer, SED1376_FB_SIZE);
|
||||
offset += SED1376_FB_SIZE;
|
||||
memcpy(data + offset, sed1376Ram, SED1376_RAM_SIZE);
|
||||
offset += SED1376_RAM_SIZE;
|
||||
}
|
||||
|
||||
void sed1376LoadState(uint8_t* data){
|
||||
@@ -163,8 +164,8 @@ void sed1376LoadState(uint8_t* data){
|
||||
offset += SED1376_LUT_SIZE;
|
||||
memcpy(sed1376BLut, data + offset, SED1376_LUT_SIZE);
|
||||
offset += SED1376_LUT_SIZE;
|
||||
memcpy(sed1376Framebuffer, data + offset, SED1376_FB_SIZE);
|
||||
offset += SED1376_FB_SIZE;
|
||||
memcpy(sed1376Ram, data + offset, SED1376_RAM_SIZE);
|
||||
offset += SED1376_RAM_SIZE;
|
||||
|
||||
//refresh LUT
|
||||
MULTITHREAD_LOOP(index) for(index = 0; index < SED1376_LUT_SIZE; index++)
|
||||
@@ -338,7 +339,7 @@ void sed1376Render(void){
|
||||
|
||||
MULTITHREAD_DOUBLE_LOOP(pixelX, pixelY) for(pixelY = 0; pixelY < 160; pixelY++)
|
||||
for(pixelX = 0; pixelX < 160; pixelX++)
|
||||
palmFramebuffer[pixelY * 160 + pixelX] = renderPixel(pixelX, pixelY);
|
||||
sed1376Framebuffer[pixelY * 160 + pixelX] = renderPixel(pixelX, pixelY);
|
||||
|
||||
//debugLog("Screen start address:0x%08X, buffer width:%d, swivel view:%d degrees\n", screenStartAddress, lineSize, rotation);
|
||||
//debugLog("Screen format, color:%s, BPP:%d\n", boolString(color), bitDepth);
|
||||
@@ -366,7 +367,7 @@ void sed1376Render(void){
|
||||
lineSize = (sed1376Registers[PIP_LINE_SZ_1] << 8 | sed1376Registers[PIP_LINE_SZ_0]) * 4;
|
||||
MULTITHREAD_DOUBLE_LOOP(pixelX, pixelY) for(pixelY = pipStartY; pixelY < pipEndY; pixelY++)
|
||||
for(pixelX = pipStartX; pixelX < pipEndX; pixelX++)
|
||||
palmFramebuffer[pixelY * 160 + pixelX] = renderPixel(pixelX, pixelY);
|
||||
sed1376Framebuffer[pixelY * 160 + pixelX] = renderPixel(pixelX, pixelY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,21 +377,21 @@ void sed1376Render(void){
|
||||
//display inversion
|
||||
if((sed1376Registers[DISP_MODE] & 0x30) == 0x10)
|
||||
MULTITHREAD_LOOP(index) for(index = 0; index < 160 * 160; index++)
|
||||
palmFramebuffer[index] = ~palmFramebuffer[index];
|
||||
sed1376Framebuffer[index] = ~sed1376Framebuffer[index];
|
||||
|
||||
|
||||
//backlight level, 0 = 1/4 color intensity, 1 = 1/2 color intensity, 2 = full color intensity
|
||||
switch(palmMisc.backlightLevel){
|
||||
case 0:
|
||||
MULTITHREAD_LOOP(index) for(index = 0; index < 160 * 160; index++){
|
||||
palmFramebuffer[index] >>= 2;
|
||||
palmFramebuffer[index] &= 0x39E7;
|
||||
sed1376Framebuffer[index] >>= 2;
|
||||
sed1376Framebuffer[index] &= 0x39E7;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
MULTITHREAD_LOOP(index) for(index = 0; index < 160 * 160; index++){
|
||||
palmFramebuffer[index] >>= 1;
|
||||
palmFramebuffer[index] &= 0x7BEF;
|
||||
sed1376Framebuffer[index] >>= 1;
|
||||
sed1376Framebuffer[index] &= 0x7BEF;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@@ -404,7 +405,7 @@ void sed1376Render(void){
|
||||
}
|
||||
else{
|
||||
//black screen
|
||||
memset(palmFramebuffer, 0x00, 160 * 160 * sizeof(uint16_t));
|
||||
memset(sed1376Framebuffer, 0x00, 160 * 160 * sizeof(uint16_t));
|
||||
debugLog("Cant draw screen, LCD on:%s, PLL on:%s, power save on:%s, forced blank on:%s\n", palmMisc.lcdOn ? "true" : "false", pllIsOn() ? "true" : "false", sed1376PowerSaveEnabled() ? "true" : "false", !!(sed1376Registers[DISP_MODE] & 0x80) ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern uint8_t sed1376Framebuffer[];
|
||||
extern uint16_t sed1376Framebuffer[];
|
||||
extern uint8_t sed1376Ram[];
|
||||
|
||||
void sed1376Reset(void);
|
||||
uint64_t sed1376StateSize(void);
|
||||
|
||||
@@ -31,38 +31,38 @@ static uint16_t lutMonochromeValue(uint8_t lutIndex){
|
||||
|
||||
//monochrome
|
||||
static uint16_t get1BppMonochrome(uint16_t x, uint16_t y){
|
||||
return lutMonochromeValue(sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 8)] >> (7 - x % 8) & 0x01);
|
||||
return lutMonochromeValue(sed1376Ram[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 8)] >> (7 - x % 8) & 0x01);
|
||||
}
|
||||
static uint16_t get2BppMonochrome(uint16_t x, uint16_t y){
|
||||
return lutMonochromeValue(sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 4)] >> (6 - x % 4 * 2) & 0x03);
|
||||
return lutMonochromeValue(sed1376Ram[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 4)] >> (6 - x % 4 * 2) & 0x03);
|
||||
}
|
||||
static uint16_t get4BppMonochrome(uint16_t x, uint16_t y){
|
||||
return lutMonochromeValue(sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 2)] >> (4 - x % 2 * 4) & 0x0F);
|
||||
return lutMonochromeValue(sed1376Ram[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 2)] >> (4 - x % 2 * 4) & 0x0F);
|
||||
}
|
||||
static uint16_t get8BppMonochrome(uint16_t x, uint16_t y){
|
||||
return lutMonochromeValue(sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + y * lineSize + x)]);
|
||||
return lutMonochromeValue(sed1376Ram[handlePanelDataSwaps(screenStartAddress + y * lineSize + x)]);
|
||||
}
|
||||
static uint16_t get16BppMonochrome(uint16_t x, uint16_t y){
|
||||
uint16_t pixelValue = sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + (y * lineSize + x) * 2)] << 8 | sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + (y * lineSize + x) * 2 + 1)];
|
||||
uint16_t pixelValue = sed1376Ram[handlePanelDataSwaps(screenStartAddress + (y * lineSize + x) * 2)] << 8 | sed1376Ram[handlePanelDataSwaps(screenStartAddress + (y * lineSize + x) * 2 + 1)];
|
||||
return makeRgb16FromGreenComponent(pixelValue);
|
||||
}
|
||||
|
||||
//color
|
||||
static uint16_t get1BppColor(uint16_t x, uint16_t y){
|
||||
return sed1376OutputLut[sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 8)] >> (7 - x % 8) & 0x01];
|
||||
return sed1376OutputLut[sed1376Ram[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 8)] >> (7 - x % 8) & 0x01];
|
||||
}
|
||||
static uint16_t get2BppColor(uint16_t x, uint16_t y){
|
||||
return sed1376OutputLut[sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 4)] >> (6 - x % 4 * 2) & 0x03];
|
||||
return sed1376OutputLut[sed1376Ram[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 4)] >> (6 - x % 4 * 2) & 0x03];
|
||||
}
|
||||
static uint16_t get4BppColor(uint16_t x, uint16_t y){
|
||||
return sed1376OutputLut[sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 2)] >> (4 - x % 2 * 4) & 0x0F];
|
||||
return sed1376OutputLut[sed1376Ram[handlePanelDataSwaps(screenStartAddress + y * lineSize + x / 2)] >> (4 - x % 2 * 4) & 0x0F];
|
||||
}
|
||||
static uint16_t get8BppColor(uint16_t x, uint16_t y){
|
||||
return sed1376OutputLut[sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + y * lineSize + x)]];
|
||||
return sed1376OutputLut[sed1376Ram[handlePanelDataSwaps(screenStartAddress + y * lineSize + x)]];
|
||||
}
|
||||
static uint16_t get16BppColor(uint16_t x, uint16_t y){
|
||||
//this format is little endian, to use big endian data sed1376Registers[SPECIAL_EFFECT] & 0x40 must be set
|
||||
return sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + (y * lineSize + x * 2) + 1)] << 8 | sed1376Framebuffer[handlePanelDataSwaps(screenStartAddress + (y * lineSize + x * 2))];
|
||||
return sed1376Ram[handlePanelDataSwaps(screenStartAddress + (y * lineSize + x * 2) + 1)] << 8 | sed1376Ram[handlePanelDataSwaps(screenStartAddress + (y * lineSize + x * 2))];
|
||||
}
|
||||
|
||||
static void selectRenderer(bool color, uint8_t bpp){
|
||||
|
||||
@@ -15,7 +15,7 @@ These registers will do nothing if their corresponding feature bit is not set on
|
||||
#define FEATURE_RAM_HUGE 0x00000001/*128mb RAM*/
|
||||
#define FEATURE_FAST_CPU 0x00000002/*doubles CPU speed*/
|
||||
#define FEATURE_HYBRID_CPU 0x00000004/*allows running ARM opcodes in an OS 4 enviroment*/
|
||||
#define FEATURE_320x320 0x00000008/*creates a 320x320 framebuffer for hires mode, the 160x160 framebuffer is a transparent overlay over the 320x320 framebuffer*/
|
||||
#define FEATURE_CUSTOM_FB 0x00000008/*creates a dynamicly sized framebuffer for hires mode, the 160x160 framebuffer is a transparent overlay over the extended framebuffer*/
|
||||
#define FEATURE_SYNCED_RTC 0x00000010/*RTC always equals host system time*/
|
||||
#define FEATURE_HLE_APIS 0x00000020/*memcpy, memcmp, wait on timer will be replaced with the hosts function*/
|
||||
#define FEATURE_EMU_HONEST 0x00000040/*tell the OS that its running in an emu, does nothing else*/
|
||||
@@ -27,7 +27,7 @@ These registers will do nothing if their corresponding feature bit is not set on
|
||||
|
||||
/*registers*/
|
||||
#define EMU_INFO 0x000/*gets the feature bits, read only*/
|
||||
#define EMU_HIRESFB 0x004/*sets the address of the 320x320 framebuffer, read/write*/
|
||||
#define EMU_HIRESFB 0x004/*sets the address of the dynamic framebuffer, read/write, EMU_SIZE must have width in the top 16 bits and height in the bottom 16 bits*/
|
||||
#define EMU_SRC 0x008/*write only*/
|
||||
#define EMU_DST 0x00C/*write only*/
|
||||
#define EMU_SIZE 0x010/*write only*/
|
||||
|
||||
@@ -15,7 +15,7 @@ These registers will do nothing if their corresponding feature bit is not set on
|
||||
#define FEATURE_RAM_HUGE 0x00000001/*128mb RAM*/
|
||||
#define FEATURE_FAST_CPU 0x00000002/*doubles CPU speed*/
|
||||
#define FEATURE_HYBRID_CPU 0x00000004/*allows running ARM opcodes in an OS 4 enviroment*/
|
||||
#define FEATURE_320x320 0x00000008/*creates a 320x320 framebuffer for hires mode, the 160x160 framebuffer is a transparent overlay over the 320x320 framebuffer*/
|
||||
#define FEATURE_CUSTOM_FB 0x00000008/*creates a dynamicly sized framebuffer for hires mode, the 160x160 framebuffer is a transparent overlay over the extended framebuffer*/
|
||||
#define FEATURE_SYNCED_RTC 0x00000010/*RTC always equals host system time*/
|
||||
#define FEATURE_HLE_APIS 0x00000020/*memcpy, memcmp, wait on timer will be replaced with the hosts function*/
|
||||
#define FEATURE_EMU_HONEST 0x00000040/*tell the OS that its running in an emu, does nothing else*/
|
||||
@@ -27,7 +27,7 @@ These registers will do nothing if their corresponding feature bit is not set on
|
||||
|
||||
/*registers*/
|
||||
#define EMU_INFO 0x000/*gets the feature bits, read only*/
|
||||
#define EMU_HIRESFB 0x004/*sets the address of the 320x320 framebuffer, read/write*/
|
||||
#define EMU_HIRESFB 0x004/*sets the address of the dynamic framebuffer, read/write, EMU_SIZE must have width in the top 16 bits and height in the bottom 16 bits*/
|
||||
#define EMU_SRC 0x008/*write only*/
|
||||
#define EMU_DST 0x00C/*write only*/
|
||||
#define EMU_SIZE 0x010/*write only*/
|
||||
|
||||
Reference in New Issue
Block a user