Framebuffer now drawing 1/8 of the boot logo on the left side

For some reason Palm uses the picture in picture registers for the bootlogo.

HexViewer can now dump memory to .bin files.
This commit is contained in:
meepingsnesroms
2018-04-23 17:30:15 -07:00
parent 0936503cc1
commit 450a317cd7
14 changed files with 271 additions and 85 deletions

View File

@@ -48,7 +48,8 @@ SOURCES += \
src/sed1376.c \
src/silkscreen.c \
src/trapNumToName.c \
hexviewer.cpp
hexviewer.cpp \
fileaccess.cpp
HEADERS += \
qt-common/include/boolean.h \
@@ -77,7 +78,8 @@ HEADERS += \
hexviewer.h \
src/hardwareRegistersTiming.c.h \
src/sed1376Accessors.c.h \
src/hardwareRegistersAccessors.c.h
src/hardwareRegistersAccessors.c.h \
fileaccess.h
FORMS += \
mainwindow.ui \

View File

@@ -0,0 +1,90 @@
#include <QtGlobal>
#include <new>
#include <string>
#include <stdint.h>
#include <ctype.h>
#include <sys/stat.h>
#include "fileaccess.h"
uint8_t* getFileBuffer(std::string filePath, size_t& size, uint32_t& error){
uint8_t* rawData = NULL;
if(filePath != ""){
struct stat st;
int doesntExist = stat(filePath.c_str(), &st);
if(doesntExist == 0 && st.st_size){
FILE* dataFile = fopen(filePath.c_str(), "rb");
if(dataFile != NULL){
rawData = new (std::nothrow) uint8_t[st.st_size];
if(rawData){
size_t bytesRead = fread(rawData, 1, st.st_size, dataFile);
if(bytesRead == (size_t)st.st_size){
size = bytesRead;
error = FRONTEND_ERR_NONE;
}
else{
error = FRONTEND_FILE_UNFINISHED;
}
}
else{
error = FRONTEND_OUT_OF_MEMORY;
}
fclose(dataFile);
}
else{
error = FRONTEND_FILE_PROTECTED;
}
}
else{
error = FRONTEND_FILE_DOESNT_EXIST;
}
}
else{
error = FRONTEND_FILE_EMPTY_PATH;
}
if(error != FRONTEND_ERR_NONE){
if(rawData)
delete[] rawData;
rawData = NULL;
size = 0;
}
return rawData;
}
uint32_t setFileBuffer(std::string filePath, uint8_t* data, size_t size){
uint32_t error = FRONTEND_ERR_NONE;
if(filePath != ""){
FILE* dataFile = fopen(filePath.c_str(), "wb");
if(dataFile != NULL){
size_t bytesWritten = fwrite(data, 1, size, dataFile);
if(bytesWritten != size)
error = FRONTEND_FILE_UNFINISHED;
fclose(dataFile);
}
else{
error = FRONTEND_FILE_PROTECTED;
}
}
else{
error = FRONTEND_FILE_EMPTY_PATH;
}
return error;
}
bool validFilePath(std::string path){
#ifdef Q_OS_WIN
if(path.length() < 3 || !isalpha(path[0]) || path[1] != ':' || (path[2] != '/' && path[2] != '\\'))
return false;
#else
if(path.length() < 1 || path[0] != '/')
return false;
#endif
for(uint32_t count = 0; count < path.length(); count++){
if(!isalnum(path[count]) && !ispunct(path[count]))
return false;
}
return true;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <string>
#include <stdint.h>
enum{
FRONTEND_ERR_NONE,
FRONTEND_FILE_DOESNT_EXIST,
FRONTEND_FILE_EMPTY_PATH,
FRONTEND_FILE_UNFINISHED,
FRONTEND_FILE_MODIFYED,
FRONTEND_FILE_INVALID_TYPE,
FRONTEND_FILE_PROTECTED,
FRONTEND_OUT_OF_MEMORY
};
uint8_t* getFileBuffer(std::string filePath, size_t& size, uint32_t& error);
uint32_t setFileBuffer(std::string filePath, uint8_t* data, size_t size);
bool validFilePath(std::string path);

View File

@@ -3,6 +3,8 @@
#include <QString>
#include "fileaccess.h"
extern "C" {
#include "src/m68k/m68k.h"
#include "src/hardwareRegisters.h"
@@ -13,7 +15,7 @@ extern "C" {
#define INVALID_NUMBER (int64_t)0x8000000000000000//the biggest negative 64bit number
uint32_t getEmulatorMemorySafe(uint32_t address, uint8_t size){
int64_t getEmulatorMemorySafe(uint32_t address, uint8_t size){
//until SPI and UART destructive reads are implemented all reads to mapped addresses are safe
if(bankType[START_BANK(address)] != CHIP_NONE){
uint16_t m68kSr = m68k_get_reg(NULL, M68K_REG_SR);
@@ -31,7 +33,7 @@ uint32_t getEmulatorMemorySafe(uint32_t address, uint8_t size){
}
m68k_set_reg(M68K_REG_SR, m68kSr);
}
return 0x00000000;
return INVALID_NUMBER;
}
@@ -116,10 +118,14 @@ void HexViewer::on_hexUpdate_clicked(){
if(address != INVALID_NUMBER && length != INVALID_NUMBER && length != 0 && address + bits / 8 * length - 1 <= 0xFFFFFFFF){
for(int64_t count = 0; count < length; count++){
int64_t data = getEmulatorMemorySafe(address, bits);
QString value;
value += stringFromNumber(address, true, 8);
value += ":";
value += stringFromNumber(getEmulatorMemorySafe(address, bits), true, bits / 8 * 2);
if(data != INVALID_NUMBER)
value += stringFromNumber(data, true, bits / 8 * 2);
else
value += "Unsafe Access";
ui->hexValueList->addItem(value);
address += bits / 8;
}
@@ -143,3 +149,19 @@ void HexViewer::on_hex32Bit_clicked(){
bitsPerEntry = 32;
hexRadioButtonHandler();
}
void HexViewer::on_hexDump_clicked()
{
int64_t address = numberFromString(ui->hexAddress->text(), false/*negative allowed*/);
int64_t length = numberFromString(ui->hexLength->text(), false/*negative allowed*/);
uint8_t bits = bitsPerEntry;
std::string filePath = ui->hexFilePath->text().toStdString();
if(validFilePath(filePath) && address != INVALID_NUMBER && length != INVALID_NUMBER && length != 0 && address + bits / 8 * length - 1 <= 0xFFFFFFFF){
length *= bits / 8;
uint8_t* dumpBuffer = new uint8_t[length];
for(int64_t count = 0; count < length; count++)
dumpBuffer[count] = getEmulatorMemorySafe(address + count, 8);
setFileBuffer(filePath, dumpBuffer, length);
delete[] dumpBuffer;
}
}

View File

@@ -29,6 +29,8 @@ private slots:
void on_hex32Bit_clicked();
void on_hexDump_clicked();
private:
uint8_t bitsPerEntry;
Ui::HexViewer *ui;

View File

@@ -174,6 +174,42 @@
</rect>
</property>
</widget>
<widget class="QPushButton" name="hexDump">
<property name="geometry">
<rect>
<x>272</x>
<y>180</y>
<width>161</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string>Dump</string>
</property>
</widget>
<widget class="QLineEdit" name="hexFilePath">
<property name="geometry">
<rect>
<x>272</x>
<y>160</y>
<width>161</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_7">
<property name="geometry">
<rect>
<x>270</x>
<y>140</y>
<width>60</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>File Path</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="graphics">
<property name="sizePolicy">
@@ -295,7 +331,7 @@
</rect>
</property>
</widget>
<widget class="QCheckBox" name="checkBox">
<widget class="QCheckBox" name="gfxColor">
<property name="geometry">
<rect>
<x>110</x>

View File

@@ -10,17 +10,15 @@
#include <QFont>
#include <QKeyEvent>
#include <new>
#include <atomic>
#include <mutex>
#include <cstdint>
#include <unistd.h>
#include <sys/stat.h>
#include <stdint.h>
#include "hexviewer.h"
#include "fileaccess.h"
#include "src/emulator.h"
uint32_t screenWidth;
uint32_t screenHeight;
@@ -34,53 +32,6 @@ static std::atomic<bool> emuInited;
static uint8_t romBuffer[ROM_SIZE];
uint8_t* getFileBuffer(std::string filePath, size_t& size, uint32_t& error){
uint8_t* rawData = NULL;
if(filePath != ""){
struct stat st;
int doesntExist = stat(filePath.c_str(), &st);
if(doesntExist == 0 && st.st_size){
FILE* dataFile = fopen(filePath.c_str(), "rb");
if(dataFile != NULL){
rawData = new (std::nothrow) uint8_t[st.st_size];
if(rawData){
size_t bytesRead = fread(rawData, 1, st.st_size, dataFile);
if(bytesRead == (size_t)st.st_size){
size = bytesRead;
error = FRONTEND_ERR_NONE;
}
else{
error = FRONTEND_FILE_UNFINISHED;
}
}
else{
error = FRONTEND_OUT_OF_MEMORY;
}
fclose(dataFile);
}
else{
error = FRONTEND_FILE_PROTECTED;
}
}
else{
error = FRONTEND_FILE_DOESNT_EXIST;
}
}
else{
error = FRONTEND_FILE_EMPTY_PATH;
}
if(error != FRONTEND_ERR_NONE){
if(rawData)
delete[] rawData;
rawData = NULL;
size = 0;
}
return rawData;
}
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MainWindow){

View File

@@ -7,17 +7,6 @@
extern uint32_t screenWidth;
extern uint32_t screenHeight;
enum{
FRONTEND_ERR_NONE,
FRONTEND_FILE_DOESNT_EXIST,
FRONTEND_FILE_EMPTY_PATH,
FRONTEND_FILE_UNFINISHED,
FRONTEND_FILE_MODIFYED,
FRONTEND_FILE_INVALID_TYPE,
FRONTEND_FILE_PROTECTED,
FRONTEND_OUT_OF_MEMORY
};
namespace Ui {
class MainWindow;
}

View File

@@ -530,10 +530,6 @@ void emulateFrame(){
palmCycleCounter -= CPU_FREQUENCY / EMU_FPS;
sed1376Render();
//memcpy(palmFramebuffer, sed1376Framebuffer, 160 * 160 * sizeof(uint16_t));
//debugLog("Ran frame, executed %f cycles.\n", palmCycleCounter + CPU_FREQUENCY / EMU_FPS);
}
bool emulateUntilDebugEventOrFrameEnd(){

View File

@@ -629,11 +629,13 @@ void setHwRegister16(unsigned int address, unsigned int value){
//this is a 32 bit register but Palm OS writes it as 16 bit chunks
registerArrayWrite16(IPR, registerArrayRead16(IPR) & ~(value & 0x001F/*external hardware int mask*/));
registerArrayWrite16(ISR, registerArrayRead16(ISR) & ~(value & 0x001F/*external hardware int mask*/));
checkInterrupts();
break;
case ISR + 2:
//this is a 32 bit register but Palm OS writes it as 16 bit chunks
registerArrayWrite16(IPR + 2, registerArrayRead16(IPR + 2) & ~(value & 0x0F00/*external hardware int mask*/));
registerArrayWrite16(ISR + 2, registerArrayRead16(ISR + 2) & ~(value & 0x0F00/*external hardware int mask*/));
checkInterrupts();
break;
case TCTL1:
@@ -652,6 +654,7 @@ void setHwRegister16(unsigned int address, unsigned int value){
clearIprIsrBit(INT_RTI);
if(!(registerArrayRead16(RTCISR) & 0x003F))
clearIprIsrBit(INT_RTC);
checkInterrupts();
break;
case PLLFSR:

View File

@@ -70,6 +70,39 @@ static inline uint32_t getBufferStartAddress(){
return screenStartAddress;
}
static inline uint32_t getPipStartAddress(){
uint32_t pipStartAddress = sed1376Registers[PIP_ADDR_2] << 16 | sed1376Registers[PIP_ADDR_1] << 8 | sed1376Registers[PIP_ADDR_0];
switch((sed1376Registers[SPECIAL_EFFECT] & 0x03) * 90){
case 0:
//desired byte address / 4.
pipStartAddress *= 4;
break;
case 90:
//((desired byte address + (panel height * bpp / 8)) / 4) - 1.
pipStartAddress += 1;
pipStartAddress *= 4;
//pipStartAddress - (panelHeight * bpp / 8);
break;
case 180:
//((desired byte address + (panel width * panel height * bpp / 8)) / 4) - 1.
pipStartAddress += 1;
pipStartAddress *= 4;
//pipStartAddress - (panelWidth * panelHeight * bpp / 8);
break;
case 270:
//(desired byte address + ((panel width - 1) * panel height * bpp / 8)) / 4.
pipStartAddress *= 4;
//pipStartAddress -= ((panelWidth - 1) * panelHeight * bpp / 8);
break;
}
return pipStartAddress;
}
static inline void updateLcdStatus(){
palmMisc.lcdOn = CAST_TO_BOOL(sed1376Registers[GPIO_CONT_0] & sed1376Registers[GPIO_CONF_0] & 0x20);
palmMisc.backlightOn = CAST_TO_BOOL(sed1376Registers[GPIO_CONT_0] & sed1376Registers[GPIO_CONF_0] & 0x10);
@@ -87,10 +120,19 @@ uint8_t sed1376GetRegister(uint8_t address){
#endif
switch(address){
case PWR_SAVE_CFG://may need to attach "Vertical Non- Display Period Status" to RNG
debugLog("Read SED1376 power save config, PC 0x%08X.\n", m68k_get_reg(NULL, M68K_REG_PC));
return sed1376Registers[address] | 0x80;//pretend where in a non dispaly period
case LUT_READ_LOC:
case LUT_WRITE_LOC:
case LUT_R_WRITE:
case LUT_G_WRITE:
case LUT_B_WRITE:
//write only
return 0x00;
case PWR_SAVE_CFG:
case SPECIAL_EFFECT:
case PIP_ADDR_0:
case PIP_ADDR_1:
case PIP_ADDR_2:
case SCRATCH_0:
case SCRATCH_1:
case GPIO_CONF_0:
@@ -116,22 +158,33 @@ void sed1376SetRegister(uint8_t address, uint8_t value){
switch(address){
case PWR_SAVE_CFG:
sed1376Registers[address] = value & 0x8E;
//bit 7 must always be set, timing hack
sed1376Registers[address] = (value & 0x01) | 0x80;
break;
case DISP_MODE:
sed1376Registers[address] = value & 0xF7;
break;
case PANEL_TYPE:
sed1376Registers[address] = value & 0xFB;
break;
case SPECIAL_EFFECT:
sed1376Registers[address] = value & 0xD3;
break;
case DISP_ADDR_2:
case PIP_ADDR_2:
sed1376Registers[address] = value & 0x01;
break;
case LINE_SIZE_1:
case PIP_LINE_SZ_1:
case PIP_X_START_1:
case PIP_X_END_1:
case PIP_Y_START_1:
case PIP_Y_END_1:
sed1376Registers[address] = value & 0x03;
break;
@@ -139,7 +192,10 @@ void sed1376SetRegister(uint8_t address, uint8_t value){
sed1376RLut[value] = sed1376Registers[LUT_R_WRITE];
sed1376GLut[value] = sed1376Registers[LUT_G_WRITE];
sed1376BLut[value] = sed1376Registers[LUT_B_WRITE];
sed1376OutputLut[value] = makeRgb16FromRgb666(sed1376Registers[LUT_R_WRITE], sed1376Registers[LUT_G_WRITE], sed1376Registers[LUT_B_WRITE]);
sed1376Registers[LUT_R_READ] = sed1376RLut[value];
sed1376Registers[LUT_G_READ] = sed1376GLut[value];
sed1376Registers[LUT_B_READ] = sed1376BLut[value];
sed1376OutputLut[value] = makeRgb16FromRgb666(sed1376RLut[value], sed1376GLut[value], sed1376BLut[value]);
break;
case LUT_READ_LOC:
@@ -171,7 +227,14 @@ void sed1376SetRegister(uint8_t address, uint8_t value){
case SCRATCH_1:
case DISP_ADDR_0:
case DISP_ADDR_1:
case PIP_ADDR_0:
case PIP_ADDR_1:
case LINE_SIZE_0:
case PIP_LINE_SZ_0:
case PIP_X_START_0:
case PIP_X_END_0:
case PIP_Y_START_0:
case PIP_Y_END_0:
case LUT_R_WRITE:
case LUT_G_WRITE:
case LUT_B_WRITE:
@@ -202,6 +265,9 @@ void sed1376Reset(){
sed1376Registers[REV_CODE] = 0x28;
sed1376Registers[DISP_BUFF_SIZE] = 0x14;
//timing hack
sed1376Registers[PWR_SAVE_CFG] = 0x80;
}
void sed1376RefreshLut(){
@@ -226,15 +292,25 @@ void sed1376Render(){
for(uint16_t pixelX = 0; pixelX < 160; pixelX++)
palmFramebuffer[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 start address:0x%08X, buffer width:%d, swivel view:%d degrees\n", screenStartAddress, lineSize, rotation);
//debugLog("Screen format, monochrome:%s, BPP:%d\n", monochrome ? "true" : "false", bitDepth);
/*
if(pictureInPictureEnabled){
screenStartAddress = getBufferStartAddress();
lineSize = (sed1376Registers[PIP_LINE_SZ_1] << 8 | sed1376Registers[PIP_LINE_SZ_0]) * 4;
//not done yet
uint16_t pipStartX = sed1376Registers[PIP_X_START_1] << 8 | sed1376Registers[PIP_X_START_0];
uint16_t pipStartY = sed1376Registers[PIP_Y_START_1] << 8 | sed1376Registers[PIP_Y_START_0];
uint16_t pipEndX = sed1376Registers[PIP_X_END_1] << 8 | sed1376Registers[PIP_X_END_0];
uint16_t pipEndY = sed1376Registers[PIP_Y_END_1] << 8 | sed1376Registers[PIP_Y_END_0];
debugLog("PIP state, start x:%d, end x:%d, start y:%d, end y:%d\n", pipStartX, pipEndX, pipStartY, pipEndY);
if(pipStartX < 160 && pipStartY < 160){
pipEndX = pipEndX < 160 ? pipEndX : 160;
pipEndY = pipEndY < 160 ? pipEndY : 160;
screenStartAddress = getPipStartAddress();
lineSize = (sed1376Registers[PIP_LINE_SZ_1] << 8 | sed1376Registers[PIP_LINE_SZ_0]) * 4;
for(uint16_t pixelY = pipStartY; pixelY < pipEndY; pixelY++)
for(uint16_t pixelX = pipStartX; pixelX < pipEndX; pixelX++)
palmFramebuffer[pixelY * 160 + pixelX] = renderPixel(pixelX, pixelY);
}
}
*/
//rotation
//later

View File

@@ -13,7 +13,7 @@ static inline uint32_t handlePanelDataSwaps(uint32_t address){
static inline uint16_t makeRgb16FromRgb666(uint8_t r, uint8_t g, uint8_t b){
uint16_t color = r << 10 & 0xF800;
color |= g << 5 & 0x07E0;
color |= b >> 1 & 0x008F;
color |= b >> 1 & 0x001F;
return color;
}
static inline void makeRgb666FromRgb16(uint16_t color, uint8_t* r, uint8_t* g, uint8_t* b){

BIN
tests/screenMem.bin Normal file

Binary file not shown.

BIN
tests/screenMem2.bin Normal file

Binary file not shown.