Skip to content

Commit a6af762

Browse files
author
Multimodcrafter
committed
Merge branch 'release/2.0'
2 parents 4324463 + 915158e commit a6af762

File tree

11 files changed

+178
-51
lines changed

11 files changed

+178
-51
lines changed

LALWE.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ CONFIG += c++11
3636

3737
RC_ICONS = Lalwe_icon.ico
3838

39-
VERSION = 1.2
39+
VERSION = 2.0
4040

4141
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
4242

assembler.cpp

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Assembler::Assembler() {
1616
void Assembler::assemble(std::string code, RAM* mem) {
1717
Logger::loggerInst->info("Assembly process started...");
1818
std::vector<std::string> lines = splitString(code,'\n');
19+
std::map<sint,sint> datablock;
1920
varbel_names.clear();
2021
subroutines.clear();
2122

@@ -78,6 +79,7 @@ void Assembler::assemble(std::string code, RAM* mem) {
7879
int state = 0; //where in the code are we? 0 = main code, 1 = subroutine
7980
subroutine* curr_s = nullptr; //stores the current subroutine information
8081
std::string curr_s_name = "";
82+
bool curr_s_ret = false;
8183
int globalvarcount = 0; //how many global vars have been defined so far
8284
// how many local vars have been defined so far (in case of state == 1)
8385
// start value of 2 is necessary because 0=return-address, 1=previous frame pointer and 2=previous stack pointer
@@ -94,6 +96,13 @@ void Assembler::assemble(std::string code, RAM* mem) {
9496
if(state == 0) {
9597
if(words.size() > 1 && checkIdentifier(words.at(1))) {
9698
varbel_names.insert(std::make_pair(words.at(1),globalvarcount));
99+
if(words.size() > 2) {
100+
for(int i = 2; i < words.size(); ++i) {
101+
datablock.insert(std::make_pair(globalvarcount,isNumeric(words.at(i))));
102+
++globalvarcount;
103+
}
104+
--globalvarcount;
105+
}
97106
++globalvarcount; //global vars are zero basedly indexed since the data pointer points to the first available ram slot
98107
} else if(words.size() == 1) {
99108
Logger::loggerInst->error("Missing identifier after keyword 'define' on line ", i + 1);
@@ -122,6 +131,7 @@ void Assembler::assemble(std::string code, RAM* mem) {
122131
}
123132
} else if(words.at(0) == "endfunction") {
124133
//reset everything to state 0
134+
if(!curr_s_ret) Logger::loggerInst->warning("Function '" + curr_s_name + "' has no return statement! This will most likely cause dangling pointers!");
125135
localvarcount = 2;
126136
curr_s = nullptr;
127137
curr_s_name = "";
@@ -131,6 +141,7 @@ void Assembler::assemble(std::string code, RAM* mem) {
131141
state = 1;
132142
curr_s = &subroutines.at(words.at(1));
133143
curr_s_name = words.at(1);
144+
curr_s_ret = false;
134145
} else if(words.at(0) == "entrypoint") {
135146
//set the entrypoint address
136147
mem->setValueAt(0,address + 1);
@@ -176,6 +187,7 @@ void Assembler::assemble(std::string code, RAM* mem) {
176187
return;
177188
}
178189
} else if(words.size() == 1) {
190+
if(words.at(0) == "ret") curr_s_ret = true;
179191
//if mnemonic has no arguments, store the apropriate op-code and a null argument
180192
if(Constants::OP_CODES.find(words.at(0)) != Constants::OP_CODES.end()) {
181193
mem->setValueAt(address + 1, Constants::OP_CODES.at(words.at(0)));
@@ -193,6 +205,7 @@ void Assembler::assemble(std::string code, RAM* mem) {
193205
if(adcp.valid) {
194206
mem->setValueAt(address + 1, Constants::OP_CODES.at(words.at(0)) + adcp.op_add);
195207
mem->setValueAt(address + 2, adcp.address);
208+
if(words.at(0) == "ldi" && adcp.op_add == Constants::ADR_REG) Logger::loggerInst->warning("Using register-address as argument for indirect load 'LDI', which most likely won't have the expected result, on line ", i + 1);
196209
} else {
197210
Logger::loggerInst->info("Assembly process aborted!");
198211
emit assemblyDone();
@@ -219,6 +232,23 @@ void Assembler::assemble(std::string code, RAM* mem) {
219232
emit assemblyDone();
220233
return;
221234
}
235+
} else if(words.at(0) == "ld" || words.at(0) == "ldi") {
236+
addressCompound adcp = getAddress(words.at(1), state, curr_s_name);
237+
addressCompound target_reg = getAddress(words.at(2),state,curr_s_name);
238+
if(adcp.valid && target_reg.valid && target_reg.op_add == Constants::ADR_REG) {
239+
sint reg_number = 0;
240+
while(target_reg.address > 0) {
241+
++reg_number;
242+
target_reg.address >>= 1;
243+
}
244+
mem->setValueAt(address + 1, Constants::OP_CODES.at(words.at(0)) + adcp.op_add + (reg_number << 24));
245+
mem->setValueAt(address + 2, adcp.address);
246+
if(words.at(0) == "ldi" && adcp.op_add == Constants::ADR_REG) Logger::loggerInst->warning("Using register-address as argument for indirect load 'LDI', which most likely won't have the expected result, on line ", i + 1);
247+
} else {
248+
Logger::loggerInst->info("Assembly process aborted!");
249+
emit assemblyDone();
250+
return;
251+
}
222252
} else {
223253
Logger::loggerInst->error("Too many arguments for mnemonic '" + words.at(0) + "' on line ", i + 1);
224254
Logger::loggerInst->info("Assembly process aborted!");
@@ -242,6 +272,9 @@ void Assembler::assemble(std::string code, RAM* mem) {
242272
&& Constants::OP_CODES.find(words.at(0)) != Constants::OP_CODES.end()) address += 2; //normal op code requires two memory slots (OP-Code + Argument)
243273
}
244274
mem->setValueAt(1,address + 1); //set the value the datapointer should be set to
275+
for(std::pair<sint,sint> datavalue : datablock) {
276+
mem->setValueAt(address + 1 + datavalue.first,datavalue.second);
277+
}
245278
Logger::loggerInst->info("Assembly process done!");
246279
emit assemblyDone();
247280
}
@@ -275,11 +308,13 @@ void Assembler::verify(std::string code) {
275308
if(w == "function") isFunctionDef = true; //curent line is a function def
276309
else if(isFunctionDef) {
277310
if(i == 1) { //first word after "function" is equal to the name of the subroutine
278-
if(checkIdentifier(w)) name = w;
311+
checkIdentifier(w);
312+
name = w;
279313
paramcount = 0;
280314
} else if(i > 1) {
281315
++paramcount;
282-
if(checkIdentifier(w)) s.param_names.insert(std::make_pair(w,paramcount)); //map param_name to position of parameter
316+
checkIdentifier(w);
317+
s.param_names.insert(std::make_pair(w,paramcount)); //map param_name to position of parameter
283318
}
284319
} else if(w.at(0) == ':') {
285320
varbel_names.insert(std::make_pair(w.substr(1),address + 2));
@@ -296,6 +331,7 @@ void Assembler::verify(std::string code) {
296331
int state = 0; //where in the code are we? 0 = main code, 1 = subroutine
297332
subroutine* curr_s = nullptr; //stores the current subroutine information
298333
std::string curr_s_name = "";
334+
bool curr_s_ret = false;
299335
int globalvarcount = 0; //how many global vars have been defined so far
300336
// how many local vars have been defined so far (in case of state == 1)
301337
// start value of 2 is necessary because 0=return-address, 1=previous frame pointer and 2=previous stack pointer
@@ -324,15 +360,22 @@ void Assembler::verify(std::string code) {
324360
}
325361
} else if(words.at(0) == "endfunction") {
326362
//reset everything to state 0
363+
if(!curr_s_ret) Logger::loggerInst->warning("Function '" + curr_s_name + "' has no return statement! This will most likely cause dangling pointers!");
327364
localvarcount = 2;
328365
curr_s = nullptr;
329366
curr_s_name = "";
330367
state = 0;
331368
} else if(words.at(0) == "function") {
332369
//init everything necessary for state 1
333-
state = 1;
334-
curr_s = &subroutines.at(words.at(1));
335-
curr_s_name = words.at(1);
370+
if(words.size() > 1) {
371+
if(state == 1) Logger::loggerInst->error("Function '" + curr_s_name + "'' is missing terminator ('endfunction')");
372+
state = 1;
373+
curr_s_ret = false;
374+
curr_s = &subroutines.at(words.at(1));
375+
curr_s_name = words.at(1);
376+
} else {
377+
Logger::loggerInst->error("Function definition is missing identifier on line ", i + 1);
378+
}
336379
} else if(words.at(0) == "entrypoint") {
337380
} else {
338381
if(words.at(0).at(0) == '#' || words.at(0).at(0) == ':') {
@@ -357,6 +400,7 @@ void Assembler::verify(std::string code) {
357400
Logger::loggerInst->error("Missing function-identifier after mnemonic 'call' on line ", i + 1);
358401
}
359402
} else if(words.size() == 1) {
403+
if(words.at(0) == "ret") curr_s_ret = true;
360404
//if mnemonic has no arguments, store the apropriate op-code and a null argument
361405
if(Constants::OP_CODES.find(words.at(0)) == Constants::OP_CODES.end()) {
362406
Logger::loggerInst->error("Unrecognized mnemonic on line ", i + 1);
@@ -392,6 +436,7 @@ void Assembler::verify(std::string code) {
392436
&& Constants::ASSEMBLY_INST.find(words.at(0)) == Constants::ASSEMBLY_INST.end()
393437
&& Constants::OP_CODES.find(words.at(0)) != Constants::OP_CODES.end()) address += 2; //normal op code requires two memory slots (OP-Code + Argument)
394438
}
439+
if(state == 1) Logger::loggerInst->error("Function '" + curr_s_name + "'' is missing terminator ('endfunction')");
395440
Logger::loggerInst->info("Code verification done! If no error messages showed up, your code(-syntax) should be fine.");
396441
}
397442

@@ -437,8 +482,16 @@ Assembler::addressCompound Assembler::getAddress(std::string idf, int state, std
437482
if(std::regex_match(idf,std::regex("^-?[0-9]+")) || std::regex_match(idf,std::regex("^-?0x[a-f0-9]+"))) {
438483
//if identifier is a number, it serves as the effective address/value
439484
Logger::loggerInst->debug("Identifier is numeric, absolute");
440-
sint effective_address = std::stoi(idf,0,0);
441-
result.address = effective_address;
485+
try {
486+
sint effective_address = std::stoi(idf,0,0);
487+
result.address = effective_address;
488+
} catch (const std::out_of_range& e) {
489+
Logger::loggerInst->debug(e.what());
490+
Logger::loggerInst->error("Number is too big to fit in a 32-Bit Integer. " + idf);
491+
result.address = 0;
492+
return result;
493+
}
494+
442495
result.op_add = isValue ? Constants::ADR_ABSOLUTE : Constants::VAL_ABSOLUTE;
443496
result.valid = true;
444497
} else if(idf.find('[') != std::string::npos) {
@@ -505,8 +558,14 @@ Assembler::addressCompound Assembler::getAddress(std::string idf, int state, std
505558

506559
sint Assembler::isNumeric(std::string idf) {
507560
if(std::regex_match(idf,std::regex("^-?[0-9]+")) || std::regex_match(idf,std::regex("^-?0x[a-f0-9]+"))) {
508-
sint effective_address = std::stoi(idf,0,0);;
509-
return effective_address;
561+
try {
562+
sint effective_address = std::stoi(idf,0,0);
563+
return effective_address;
564+
} catch (const std::out_of_range& e) {
565+
Logger::loggerInst->debug(e.what());
566+
Logger::loggerInst->error("Number is too big to fit in a 32-Bit Integer. " + idf);
567+
return -1;
568+
}
510569
}
511570
return -1;
512571
}

constants.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,14 @@ class Constants
7676
static const std::set<std::string> ASSEMBLY_INST;
7777

7878
/** constants used to determine if a numeric value is a variable, register or parameter*/
79-
static const int ADR_ABSOLUTE = 5;
80-
static const int ADR_GLOBAL = 1;
81-
static const int ADR_LOCAL = 2;
82-
static const int ADR_REG = 3;
83-
static const int ADR_PARAMETER = 4;
84-
static const int VAL_ABSOLUTE = 0;
85-
static const int VAL_GLOBAL = 6;
86-
static const int VAL_LOCAL = 7;
79+
static const int ADR_ABSOLUTE = 6;
80+
static const int ADR_GLOBAL = 2;
81+
static const int ADR_LOCAL = 3;
82+
static const int ADR_REG = 4;
83+
static const int ADR_PARAMETER = 5;
84+
static const int VAL_ABSOLUTE = 1;
85+
static const int VAL_GLOBAL = 7;
86+
static const int VAL_LOCAL = 8;
8787
static const int VAL_REG = 9;
8888
static const int VAL_PARAMETER = 10;
8989

controller.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ Controller::Controller(QObject &appMgr)
2828
}
2929

3030
sint Controller::getRegisterVal(sint reg) {
31-
for(int i = 0; i <= 10; ++i) {
32-
if((reg & (1 << i)) != 0) return registers.at(i)->getValue();
31+
for(int i = 0; i <= 10 && reg != 0; ++i) {
32+
if((reg & (1 << i)) == reg) return registers.at(i)->getValue();
3333
}
3434
Logger::loggerInst->error("Inexistent register dereferenced!");
3535
return 0;
3636
}
3737

3838
void Controller::setRegisterVal(sint reg, sint val) {
39-
for(int i = 0; i <= 10; ++i) {
40-
if((reg & (1 << i)) != 0) {
39+
for(int i = 0; i <= 10 && reg != 0; ++i) {
40+
if((reg & (1 << i)) == reg) {
4141
registers.at(i)->setValue(val);
4242
return;
4343
}
@@ -46,8 +46,8 @@ void Controller::setRegisterVal(sint reg, sint val) {
4646
}
4747

4848
void Controller::decRegister(sint reg) {
49-
for(int i = 0; i <= 10; ++i) {
50-
if((reg & (1 << i)) != 0) {
49+
for(int i = 0; i <= 10 && reg != 0; ++i) {
50+
if((reg & (1 << i)) == reg) {
5151
sint val = registers.at(i)->getValue();
5252
registers.at(i)->setValue(val - 1);
5353
return;
@@ -57,8 +57,8 @@ void Controller::decRegister(sint reg) {
5757
}
5858

5959
void Controller::incRegister(sint reg) {
60-
for(int i = 0; i <= 10; ++i) {
61-
if((reg & (1 << i)) != 0) {
60+
for(int i = 0; i <= 10 && reg != 0; ++i) {
61+
if((reg & (1 << i)) == reg) {
6262
sint val = registers.at(i)->getValue();
6363
registers.at(i)->setValue(val + 1);
6464
return;
@@ -68,8 +68,8 @@ void Controller::incRegister(sint reg) {
6868
}
6969

7070
void Controller::negRegister(sint reg) {
71-
for(int i = 0; i <= 10; ++i) {
72-
if((reg & (1 << i)) != 0) {
71+
for(int i = 0; i <= 10 && reg != 0; ++i) {
72+
if((reg & (1 << i)) == reg) {
7373
sint val = registers.at(i)->getValue();
7474
registers.at(i)->setValue(-val);
7575
return;
@@ -79,8 +79,8 @@ void Controller::negRegister(sint reg) {
7979
}
8080

8181
void Controller::notRegister(sint reg) {
82-
for(int i = 0; i <= 10; ++i) {
83-
if((reg & (1 << i)) != 0) {
82+
for(int i = 0; i <= 10 && reg != 0; ++i) {
83+
if((reg & (1 << i)) == reg) {
8484
sint val = registers.at(i)->getValue();
8585
registers.at(i)->setValue(~val);
8686
return;
@@ -161,7 +161,13 @@ sint Controller::calcActualValue(sint addr, sint mode, bool indirect) {
161161
}
162162
return ram->getValueAt(addr);
163163
case Constants::VAL_ABSOLUTE:
164-
setAddressMode("Absolute value");
164+
if(indirect) {
165+
setAddressMode("Indirect absolute value");
166+
this->setRegisterVal(Constants::REG_IND2, addr);
167+
return ram->getValueAt(this->getRegisterVal(Constants::REG_IND2));
168+
} else {
169+
setAddressMode("Absolute value");
170+
}
165171
return addr;
166172
case Constants::VAL_GLOBAL:
167173
if(indirect) {

lalwe_appmanager.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ LALWE_AppManager::LALWE_AppManager(QQmlContext* ctxt, QObject* obj) {
2020
setGuiProperty("addressRam2",Constants::ARRAYSIZE - Constants::RAM_VIEW_CELL_AMOUNT);
2121
}
2222

23+
bool LALWE_AppManager::getSimulationRunning() {
24+
return programRunning && programHandle.isRunning() && animationTicker.isActive();
25+
}
26+
2327
void LALWE_AppManager::assembleSlot(const QString &code) {
2428
if((!assemblyRunning || assembleHandle.isFinished()) && (!programRunning || programHandle.isFinished())) {
2529
setGuiProperty("status","Assembling...");
@@ -60,6 +64,7 @@ void LALWE_AppManager::openProgramSlot(const QString &path) {
6064

6165
void LALWE_AppManager::playProgramSlot() {
6266
if((!programRunning || programHandle.isFinished())&&(!assemblyRunning || assembleHandle.isFinished())) {
67+
processor.at(0)->cancelTermination();
6368
setGuiProperty("status","Simulation running...");
6469
Logger::loggerInst->info("Simulation started...");
6570
programRunning = true;
@@ -69,10 +74,25 @@ void LALWE_AppManager::playProgramSlot() {
6974
if(animationTicker.isActive()) {
7075
animationTicker.stop();
7176
setGuiProperty("status","Simulation paused");
77+
emit toggleAnimPlaying(false);
7278
} else {
7379
animationTicker.start(Constants::ANIM_DELAY_MILIS);
7480
setGuiProperty("status","Simulation running...");
81+
emit toggleAnimPlaying(true);
82+
}
83+
}
84+
}
85+
86+
void LALWE_AppManager::abortProgramSlot() {
87+
if((programRunning && programHandle.isRunning()) || (assemblyRunning && assembleHandle.isRunning())) {
88+
processor.at(0)->toggleAnimations(false);
89+
emit stepAnimation();
90+
processor.at(0)->requestTermination();
91+
if(animationTicker.isActive()) {
92+
processor.at(0)->toggleAnimations(true);
93+
animationTicker.stop();
7594
}
95+
setGuiProperty("status","Ready");
7696
}
7797
}
7898

lalwe_appmanager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class LALWE_AppManager : public QObject
1414
Q_OBJECT
1515
signals:
1616
void stepAnimation();
17+
void toggleAnimPlaying(bool newstate);
1718

1819
private:
1920
QQmlContext* ctxt;
@@ -34,6 +35,7 @@ public slots:
3435
void saveProgramSlot(const QString &code, const QString & path, const int &mode);
3536
void openProgramSlot(const QString &path);
3637
void playProgramSlot();
38+
void abortProgramSlot();
3739
void toggleAnimationsSlot(const bool &newState);
3840
void toggleRamHex(const bool &newState);
3941
void verifySlot(const QString &code);
@@ -50,5 +52,6 @@ public slots:
5052

5153
public:
5254
LALWE_AppManager(QQmlContext* ctxt, QObject* obj);
55+
bool getSimulationRunning();
5356
};
5457
#endif // LALWE_APPMANAGER_H

main.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ int main(int argc, char *argv[])
3232
QObject::connect(root ,SIGNAL(playProgram()),
3333
appMngr, SLOT(playProgramSlot()));
3434

35+
QObject::connect(root, SIGNAL(abortProgram()),
36+
appMngr, SLOT(abortProgramSlot()));
37+
3538
QObject::connect(root ,SIGNAL(toggleAnimations(bool)),
3639
appMngr, SLOT(toggleAnimationsSlot(bool)));
3740

0 commit comments

Comments
 (0)