mirror of
https://git.code.sf.net/p/newrpl/sources
synced 2024-11-16 19:51:25 +01:00
663 lines
16 KiB
C++
663 lines
16 KiB
C++
/*
|
|
* Copyright (c) 2014-2015, Claudio Lapilli and the newRPL Team
|
|
* All rights reserved.
|
|
* This file is released under the 3-clause BSD license.
|
|
* See the file LICENSE.txt that shipped with this distribution.
|
|
*/
|
|
|
|
#include <QtGui>
|
|
#include <QtCore>
|
|
#include <QFileDialog>
|
|
#include <QFile>
|
|
#include <QMessageBox>
|
|
#include "mainwindow.h"
|
|
#include "ui_mainwindow.h"
|
|
|
|
#define takemax(a,b) (((a)>(b))? (a):(b))
|
|
|
|
MainWindow *myMainWindow;
|
|
|
|
|
|
// CAN'T INCLUDE THE HEADERS DIRECTLY DUE TO CONFLICTING TYPES ON WINDOWS ONLY...
|
|
|
|
extern unsigned long long __pckeymatrix;
|
|
extern int __pc_terminate;
|
|
extern int __memmap_intact;
|
|
extern "C" void __keyb_update();
|
|
// BACKUP/RESTORE
|
|
extern "C" int rplBackup(void (*writefunc)(unsigned int));
|
|
extern "C" int rplRestoreBackup(unsigned int (*readfunc)());
|
|
extern "C" int rplRestoreBackupMessedup(unsigned int (*readfunc)()); // DEBUG ONLY
|
|
extern "C" void __SD_irqeventinsert();
|
|
|
|
|
|
extern int __sd_inserted;
|
|
extern int __sd_nsectors; // TOTAL SIZE OF SD CARD IN 512-BYTE SECTORS
|
|
extern int __sd_RCA;
|
|
extern unsigned char *__sd_buffer; // BUFFER WITH THE ENTIRE CONTENTS OF THE SD CARD
|
|
|
|
|
|
MainWindow::MainWindow(QWidget *parent) :
|
|
QMainWindow(parent),
|
|
rpl(this),
|
|
ui(new Ui::MainWindow)
|
|
{
|
|
myMainWindow=this;
|
|
|
|
ui->setupUi(this);
|
|
screentmr=new QTimer(this);
|
|
ui->EmuScreen->connect(screentmr,SIGNAL(timeout()),ui->EmuScreen,SLOT(update()));
|
|
maintmr=new QTimer(this);
|
|
connect(maintmr,SIGNAL(timeout()),this,SLOT(domaintimer()));
|
|
__memmap_intact=0;
|
|
__sd_inserted=0;
|
|
__sd_RCA=0;
|
|
__sd_nsectors=0;
|
|
__sd_buffer=NULL;
|
|
ui->actionEject_SD_Card_Image->setEnabled(false);
|
|
ui->actionInsert_SD_Card_Image->setEnabled(true);
|
|
|
|
rpl.start();
|
|
maintmr->start(1);
|
|
screentmr->start(50);
|
|
setWindowTitle("newRPL - [Unnamed]");
|
|
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
delete maintmr;
|
|
delete screentmr;
|
|
delete ui;
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
on_actionExit_triggered();
|
|
|
|
event->accept();
|
|
|
|
}
|
|
|
|
|
|
void MainWindow::on_EmuScreen_destroyed()
|
|
{
|
|
if(rpl.isRunning()) rpl.terminate();
|
|
QMainWindow::close();
|
|
}
|
|
|
|
extern volatile long long __pcsystmr;
|
|
int __tmr_singleshot_running=0;
|
|
volatile unsigned long long __tmr1_msec;
|
|
|
|
extern "C" void __tmr_newirqeventsvc();
|
|
|
|
|
|
void MainWindow::domaintimer()
|
|
{
|
|
// THE CLOCK IS FIXED AT 100 KHZ, SO ADD 1 msec
|
|
__pcsystmr+=100;
|
|
if(__tmr_singleshot_running) {
|
|
__tmr1_msec--;
|
|
if(!__tmr1_msec) {
|
|
__tmr_singleshot_running=0;
|
|
__tmr_newirqeventsvc();
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void stop_singleshot()
|
|
{
|
|
__tmr_singleshot_running=0;
|
|
}
|
|
|
|
|
|
extern "C" void timer_singleshot(int msec)
|
|
{
|
|
__tmr1_msec=msec;
|
|
__tmr_singleshot_running=1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const int keyMap[] = {
|
|
/*
|
|
|
|
KEYBOARD BIT MAP
|
|
----------------
|
|
This is the bit number in the 64-bit keymatrix.
|
|
Bit set means key is pressed.
|
|
|
|
A]-+ B]-+ C]-+ D]-+ E]-+ F]-+
|
|
|41| |42| |43| |44| |45| |46|
|
|
+--+ +--+ +--+ +--+ +--+ +--+
|
|
|
|
G]-+ H]-+ I]-+ UP]+
|
|
|47| |53| |54| |49|
|
|
+--+ +--+ +--+ LF]+ +--+ RT]+
|
|
|50| DN]+ |52|
|
|
J]-+ K]-+ L]-+ +--+ |51| +--+
|
|
|55| |57| |58| +--+
|
|
+--+ +--+ +--+
|
|
|
|
M]--+ N]--+ O]--+ P]--+ BKS]+
|
|
| 33| | 25| | 17| | 09| | 01|
|
|
+---+ +---+ +---+ +---+ +---+
|
|
|
|
Q]--+ R]--+ S]--+ T]--+ U]--+
|
|
| 34| | 26| | 18| | 10| | 02|
|
|
+---+ +---+ +---+ +---+ +---+
|
|
|
|
V]--+ W]--+ X]--+ Y]--+ /]--+
|
|
| 35| | 27| | 19| | 11| | 03|
|
|
+---+ +---+ +---+ +---+ +---+
|
|
|
|
AL]-+ 7]--+ 8]--+ 9]--+ *]--+
|
|
| 60| | 28| | 20| | 12| | 04|
|
|
+---+ +---+ +---+ +---+ +---+
|
|
|
|
LS]-+ 4]--+ 5]--+ 6]--+ -]--+
|
|
| 61| | 29| | 21| | 13| | 05|
|
|
+---+ +---+ +---+ +---+ +---+
|
|
|
|
RS]-+ 1]--+ 2]--+ 3]--+ +]--+
|
|
| 62| | 30| | 22| | 14| | 06|
|
|
+---+ +---+ +---+ +---+ +---+
|
|
|
|
ON]-+ 0]--+ .]--+ SP]-+ EN]-+
|
|
| 63| | 31| | 23| | 15| | 07|
|
|
+---+ +---+ +---+ +---+ +---+
|
|
|
|
*/
|
|
Qt::Key_Backspace, 1,
|
|
Qt::Key_U, 2,
|
|
Qt::Key_Slash, 3,
|
|
Qt::Key_Z, 3,
|
|
Qt::Key_Asterisk, 4,
|
|
Qt::Key_Minus, 5,
|
|
Qt::Key_Plus, 6,
|
|
Qt::Key_Return, 7,
|
|
Qt::Key_Enter, 7,
|
|
Qt::Key_P, 9,
|
|
Qt::Key_T, 10,
|
|
Qt::Key_Y, 11,
|
|
Qt::Key_9, 12,
|
|
Qt::Key_6, 13,
|
|
Qt::Key_3, 14,
|
|
Qt::Key_Space, 15,
|
|
Qt::Key_O, 17,
|
|
Qt::Key_S, 18,
|
|
Qt::Key_X, 19,
|
|
Qt::Key_8, 20,
|
|
Qt::Key_5, 21,
|
|
Qt::Key_2, 22,
|
|
Qt::Key_Period, 23,
|
|
Qt::Key_N, 25,
|
|
Qt::Key_R, 26,
|
|
Qt::Key_W, 27,
|
|
Qt::Key_7, 28,
|
|
Qt::Key_4, 29,
|
|
Qt::Key_1, 30,
|
|
Qt::Key_0, 31,
|
|
Qt::Key_M, 33,
|
|
Qt::Key_Q, 34,
|
|
Qt::Key_V, 35,
|
|
Qt::Key_A, 41,
|
|
Qt::Key_F1, 41,
|
|
Qt::Key_B, 42,
|
|
Qt::Key_F2, 42,
|
|
Qt::Key_C, 43,
|
|
Qt::Key_F3, 43,
|
|
Qt::Key_D, 44,
|
|
Qt::Key_F4, 44,
|
|
Qt::Key_E, 45,
|
|
Qt::Key_F5, 45,
|
|
Qt::Key_F, 46,
|
|
Qt::Key_F6, 46,
|
|
Qt::Key_G, 47,
|
|
Qt::Key_Up, 49,
|
|
Qt::Key_Left, 50,
|
|
Qt::Key_Down, 51,
|
|
Qt::Key_Right, 52,
|
|
Qt::Key_H, 53,
|
|
Qt::Key_I, 54,
|
|
Qt::Key_J, 55,
|
|
Qt::Key_K, 57,
|
|
Qt::Key_L, 58,
|
|
Qt::Key_Tab, 60,
|
|
Qt::Key_CapsLock, 61,
|
|
Qt::Key_Control, 62,
|
|
Qt::Key_Escape, 63
|
|
|
|
// ADD MORE KEYS HERE
|
|
|
|
,0,0
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::keyPressEvent(QKeyEvent *ev)
|
|
{
|
|
|
|
int i;
|
|
|
|
if(ev->isAutoRepeat()) { ev->accept(); return; }
|
|
|
|
if(ev->key()==Qt::Key_F12) {
|
|
__pckeymatrix=(1ULL<<63) | (1ULL<<41) | (1ULL<<43);
|
|
__keyb_update();
|
|
ev->accept();
|
|
return;
|
|
}
|
|
|
|
|
|
for(i=0;keyMap[i]!=0;i+=2) {
|
|
if(ev->key()==keyMap[i]) {
|
|
__pckeymatrix|=1ULL<<(keyMap[i+1]);
|
|
__keyb_update();
|
|
ev->accept();
|
|
return;
|
|
}
|
|
}
|
|
|
|
QMainWindow::keyPressEvent(ev);
|
|
}
|
|
|
|
void MainWindow::keyReleaseEvent(QKeyEvent *ev)
|
|
{
|
|
|
|
int i;
|
|
if(ev->isAutoRepeat()) { ev->accept(); return; }
|
|
|
|
if(ev->key()==Qt::Key_F12) {
|
|
__pckeymatrix&=~((1ULL<<63) | (1ULL<<41) | (1ULL<<43));
|
|
__keyb_update();
|
|
ev->accept();
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
for(i=0;keyMap[i]!=0;i+=2) {
|
|
if(ev->key()==keyMap[i]) {
|
|
__pckeymatrix&=~(1ULL<<(keyMap[i+1]));
|
|
__keyb_update();
|
|
ev->accept();
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
QMainWindow::keyReleaseEvent(ev);
|
|
}
|
|
|
|
extern "C" void thread_processevents()
|
|
{
|
|
QCoreApplication::processEvents();
|
|
}
|
|
|
|
void MainWindow::on_actionExit_triggered()
|
|
{
|
|
maintmr->stop();
|
|
screentmr->stop();
|
|
if(rpl.isRunning()) {
|
|
__pc_terminate=1;
|
|
__pckeymatrix^=(1ULL<<63);
|
|
__keyb_update();
|
|
while(rpl.isRunning());
|
|
}
|
|
|
|
// CLEANUP SD CARD EMULATION
|
|
if(__sd_inserted) on_actionEject_SD_Card_Image_triggered();
|
|
|
|
}
|
|
|
|
void MainWindow::WriteWord(unsigned int word)
|
|
{
|
|
myMainWindow->fileptr->write((const char *)&word,4);
|
|
}
|
|
|
|
unsigned int MainWindow::ReadWord()
|
|
{
|
|
unsigned int w;
|
|
myMainWindow->fileptr->read((char *)&w,4);
|
|
return w;
|
|
}
|
|
|
|
|
|
extern "C" void write_data(unsigned int word)
|
|
{
|
|
MainWindow::WriteWord(word);
|
|
}
|
|
extern "C" unsigned int read_data()
|
|
{
|
|
return MainWindow::ReadWord();
|
|
}
|
|
|
|
|
|
void MainWindow::on_actionSave_triggered()
|
|
{
|
|
QString fname;
|
|
|
|
if(currentfile.isEmpty()) fname=QFileDialog::getSaveFileName(this,"Select File Name",QString(),"*.nrpl");
|
|
else fname=currentfile;
|
|
if(!fname.isEmpty()) {
|
|
// GOT A NAME, APPEND EXTENSION IF NOT GIVEN
|
|
|
|
if(!fname.endsWith(".nrpl")) fname+=".nrpl";
|
|
|
|
QFile file(fname);
|
|
|
|
if(!file.open(QIODevice::WriteOnly)) {
|
|
QMessageBox a(QMessageBox::Warning,"Error while saving","Cannot write to file "+ fname,QMessageBox::Ok,this);
|
|
a.exec();
|
|
return;
|
|
}
|
|
|
|
// FILE IS OPEN AND READY FOR WRITING
|
|
|
|
// STOP RPL ENGINE
|
|
maintmr->stop();
|
|
screentmr->stop();
|
|
if(rpl.isRunning()) {
|
|
__pc_terminate=1;
|
|
__pckeymatrix^=(1ULL<<63);
|
|
__keyb_update();
|
|
while(rpl.isRunning());
|
|
}
|
|
|
|
// PERFORM BACKUP
|
|
myMainWindow=this;
|
|
fileptr=&file;
|
|
rplBackup(&write_data);
|
|
|
|
file.close();
|
|
|
|
__memmap_intact=1;
|
|
// RESTART RPL ENGINE
|
|
__pc_terminate=0;
|
|
__pckeymatrix=0;
|
|
rpl.start();
|
|
maintmr->start(1);
|
|
screentmr->start(50);
|
|
}
|
|
|
|
}
|
|
|
|
void MainWindow::on_actionOpen_triggered()
|
|
{
|
|
QString fname=QFileDialog::getOpenFileName(this,"Open File Name",QString(),"*.nrpl");
|
|
|
|
if(!fname.isEmpty()) {
|
|
QFile file(fname);
|
|
|
|
if(!file.open(QIODevice::ReadOnly)) {
|
|
QMessageBox a(QMessageBox::Warning,"Error while opening","Cannot open file "+ fname,QMessageBox::Ok,this);
|
|
a.exec();
|
|
return;
|
|
}
|
|
|
|
// FILE IS OPEN AND READY FOR READING
|
|
|
|
// STOP RPL ENGINE
|
|
maintmr->stop();
|
|
screentmr->stop();
|
|
if(rpl.isRunning()) {
|
|
__pc_terminate=1;
|
|
__pckeymatrix^=(1ULL<<63);
|
|
__keyb_update();
|
|
while(rpl.isRunning());
|
|
}
|
|
|
|
// PERFORM RESTORE PROCEDURE
|
|
myMainWindow=this;
|
|
fileptr=&file;
|
|
int result=rplRestoreBackup(&read_data);
|
|
|
|
file.close();
|
|
|
|
|
|
switch(result)
|
|
{
|
|
case -1:
|
|
{
|
|
QMessageBox a(QMessageBox::Warning,"Error while opening","File "+ fname + " is corrupt or incompatible.\nCan't recover and memory was destroyed.",QMessageBox::Ok,this);
|
|
a.exec();
|
|
currentfile.clear();
|
|
setWindowTitle("newRPL - [Unnamed]");
|
|
__memmap_intact=0;
|
|
break;
|
|
}
|
|
case 0:
|
|
{
|
|
QMessageBox a(QMessageBox::Warning,"Error while opening","File "+ fname + " is corrupt or incompatible.\nCan't recover but memory was left intact.",QMessageBox::Ok,this);
|
|
a.exec();
|
|
__memmap_intact=1;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
QMessageBox a(QMessageBox::Warning,"Recovery success","File "+ fname + " was sucessfully recovered.",QMessageBox::Ok,this);
|
|
a.exec();
|
|
currentfile=fname;
|
|
QString nameonly=currentfile.right(currentfile.length()-1-takemax(currentfile.lastIndexOf("/"),currentfile.lastIndexOf("\\")));
|
|
setWindowTitle("newRPL - ["+ nameonly + "]");
|
|
|
|
__memmap_intact=1;
|
|
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
QMessageBox a(QMessageBox::Warning,"Recovery success","File "+ fname + " was recovered with minor errors.\nRun MEMFIX to correct them.",QMessageBox::Ok,this);
|
|
a.exec();
|
|
currentfile=fname;
|
|
QString nameonly=currentfile.right(currentfile.length()-1-takemax(currentfile.lastIndexOf("/"),currentfile.lastIndexOf("\\")));
|
|
setWindowTitle("newRPL - ["+ nameonly + "]");
|
|
|
|
__memmap_intact=1;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// RESTART RPL ENGINE
|
|
__pc_terminate=0;
|
|
__pckeymatrix=0;
|
|
|
|
rpl.start();
|
|
maintmr->start(1);
|
|
screentmr->start(50);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void MainWindow::on_actionSaveAs_triggered()
|
|
{
|
|
QString fname=QFileDialog::getSaveFileName(this,"Select File Name",QString(),"*.nrpl");
|
|
|
|
if(!fname.isEmpty()) {
|
|
// GOT A NAME, APPEND EXTENSION IF NOT GIVEN
|
|
|
|
if(!fname.endsWith(".nrpl")) fname+=".nrpl";
|
|
|
|
QFile file(fname);
|
|
|
|
if(!file.open(QIODevice::WriteOnly)) {
|
|
QMessageBox a(QMessageBox::Warning,"Error while saving","Cannot write to file "+ fname,QMessageBox::Ok,this);
|
|
a.exec();
|
|
return;
|
|
}
|
|
|
|
// FILE IS OPEN AND READY FOR WRITING
|
|
|
|
// STOP RPL ENGINE
|
|
maintmr->stop();
|
|
screentmr->stop();
|
|
if(rpl.isRunning()) {
|
|
__pc_terminate=1;
|
|
__pckeymatrix^=(1ULL<<63);
|
|
__keyb_update();
|
|
while(rpl.isRunning());
|
|
}
|
|
|
|
// PERFORM BACKUP
|
|
myMainWindow=this;
|
|
fileptr=&file;
|
|
rplBackup(&write_data);
|
|
|
|
file.close();
|
|
|
|
// RESTART RPL ENGINE
|
|
__memmap_intact=1;
|
|
__pc_terminate=0;
|
|
__pckeymatrix=0;
|
|
rpl.start();
|
|
maintmr->start(1);
|
|
screentmr->start(50);
|
|
}
|
|
|
|
}
|
|
|
|
void MainWindow::on_actionNew_triggered()
|
|
{
|
|
|
|
|
|
// STOP RPL ENGINE
|
|
maintmr->stop();
|
|
screentmr->stop();
|
|
if(rpl.isRunning()) {
|
|
__pc_terminate=1;
|
|
__pckeymatrix^=(1ULL<<63);
|
|
__keyb_update();
|
|
while(rpl.isRunning());
|
|
}
|
|
|
|
currentfile.clear();
|
|
setWindowTitle("newRPL - [Unnamed]");
|
|
__memmap_intact=0;
|
|
|
|
// RESTART RPL ENGINE
|
|
__pc_terminate=0;
|
|
__pckeymatrix=0;
|
|
|
|
rpl.start();
|
|
maintmr->start(1);
|
|
screentmr->start(50);
|
|
|
|
|
|
}
|
|
|
|
void MainWindow::on_actionInsert_SD_Card_Image_triggered()
|
|
{
|
|
QString fname=QFileDialog::getOpenFileName(this,"Open SD Card Image",QString(),"*.img");
|
|
if(!fname.isEmpty()) {
|
|
sdcard.setFileName(fname);
|
|
|
|
if(!sdcard.open(QIODevice::ReadOnly)) {
|
|
QMessageBox a(QMessageBox::Warning,"Error while opening","Cannot open file "+ fname,QMessageBox::Ok,this);
|
|
a.exec();
|
|
return;
|
|
}
|
|
|
|
__sd_inserted=0;
|
|
__sd_RCA=0;
|
|
__sd_nsectors=0;
|
|
if(__sd_buffer!=NULL) free(__sd_buffer);
|
|
|
|
|
|
// FILE IS OPEN AND READY FOR READING
|
|
__sd_buffer=(unsigned char *)malloc(sdcard.size());
|
|
if(__sd_buffer==NULL) {
|
|
QMessageBox a(QMessageBox::Warning,"Error while opening","Not enough memory to read SD Image",QMessageBox::Ok,this);
|
|
a.exec();
|
|
return;
|
|
}
|
|
|
|
if(sdcard.read((char *)__sd_buffer,sdcard.size())!=sdcard.size()) {
|
|
QMessageBox a(QMessageBox::Warning,"Error while opening","Can't read SD Image",QMessageBox::Ok,this);
|
|
a.exec();
|
|
return;
|
|
}
|
|
|
|
__sd_nsectors=sdcard.size()/512;
|
|
__sd_inserted=1;
|
|
sdcard.close();
|
|
// SIMULATE AN IRQ
|
|
__SD_irqeventinsert();
|
|
|
|
|
|
|
|
ui->actionEject_SD_Card_Image->setEnabled(true);
|
|
ui->actionInsert_SD_Card_Image->setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
// NOTHING TO MOUNT, KEEP THE PREVIOUS STATUS
|
|
|
|
}
|
|
|
|
void MainWindow::on_actionEject_SD_Card_Image_triggered()
|
|
{
|
|
if(__sd_inserted) {
|
|
// SAVE THE CONTENTS BACK BEFORE EJECTING
|
|
if(!sdcard.open(QIODevice::WriteOnly)) {
|
|
QMessageBox a(QMessageBox::Warning,"Error while saving SD Card contents","Cannot open file "+ sdcard.fileName(),QMessageBox::Ok,this);
|
|
a.exec();
|
|
}
|
|
else {
|
|
sdcard.write((char *)__sd_buffer,(qint64)__sd_nsectors*512LL);
|
|
sdcard.close();
|
|
}
|
|
}
|
|
__sd_inserted=0;
|
|
__sd_RCA=0;
|
|
__sd_nsectors=0;
|
|
if(__sd_buffer!=NULL) { free(__sd_buffer); __sd_buffer=NULL; }
|
|
|
|
// SIMULATE AN IRQ
|
|
__SD_irqeventinsert();
|
|
|
|
|
|
ui->actionEject_SD_Card_Image->setEnabled(false);
|
|
ui->actionInsert_SD_Card_Image->setEnabled(true);
|
|
|
|
}
|
|
|
|
void MainWindow::on_actionPower_ON_triggered()
|
|
{
|
|
|
|
// STOP RPL ENGINE
|
|
maintmr->stop();
|
|
screentmr->stop();
|
|
if(rpl.isRunning()) {
|
|
__pc_terminate=1;
|
|
__pckeymatrix^=(1ULL<<63);
|
|
__keyb_update();
|
|
while(rpl.isRunning());
|
|
}
|
|
|
|
if(__pc_terminate==2) {
|
|
// IT WAS POWERED OFF
|
|
__memmap_intact=2;
|
|
}
|
|
else __memmap_intact=1;
|
|
|
|
// RESTART RPL ENGINE
|
|
__pc_terminate=0;
|
|
__pckeymatrix=0;
|
|
|
|
rpl.start();
|
|
maintmr->start(1);
|
|
screentmr->start(50);
|
|
|
|
}
|