├── .gitignore ├── LICENSE ├── README.md ├── doc ├── examples │ └── randomDot ├── screenshot.png ├── screenshot.svg ├── screenshot.txt ├── screenshot2.png └── screenshot2.svg ├── makefile ├── run └── src ├── comp.cpp ├── const.hpp ├── cpu.hpp ├── drawing.hpp ├── environment.c ├── environment.h ├── output.cpp ├── output.hpp ├── printer.hpp ├── ram.hpp ├── renderer.cpp ├── renderer.hpp ├── resources └── drawing ├── util.cpp └── util.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | comp 30 | 31 | # Dependency files 32 | *.d 33 | 34 | # Backup files 35 | *.bak 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jure Šorn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Comp 2 | ==== 3 | 4 | #### Simple 4-bit/1 Hz virtual computer for learning purposes 5 | 6 | ![screenshot](doc/screenshot.png) 7 | 8 | For quick start see [**HOW TO RUN**](#how-to-run-on). 9 | 10 | Memory 11 | ------ 12 | ``` 13 | instructions - 4 bits 14 | | +-- addresses - 4 bits 15 | v v 16 | ----***- <- 0 ---- 17 | --*-**-* <- 1 ---* 18 | ---***-- <- 2 --*- 19 | ---***** <- 3 --** 20 | ----***- <- 4 -*-- 21 | ---***-* <- 5 -*-* 22 | ----**-- <- 6 -**- 23 | ---****- <- 7 -*** 24 | -***---* <- 8 *--- 25 | -*--**** <- 9 *--* 26 | -------- <- 10 *-*- 27 | -------- <- 11 *-** 28 | -------- <- 12 **-- 29 | -------* <- 13 **-* 30 | -------* <- 14 ***- 31 | <- 15 **** 32 | ``` 33 | 34 | * Execution starts at the first address (0). 35 | * Execution stops when program reaches last address (15). 36 | * Whatever gets written to the last address is sent to the printer. 37 | * When reading from the last address (15), we get a random byte value. 38 | * CPU has one 8 bit register. 39 | 40 | Instruction set 41 | --------------- 42 | 43 | * `READ ----` - Copies the value at the specified address into register. 44 | * `WRITE ---*` - Copies value of the register to the specified address. 45 | * `ADD --*-` - Adds value at the specified address to the value of the register, and writes result to the register. If the result is bigger than the maximum possible value (255 = ********) then 255 gets written. 46 | * `SUBTRACT --**` - Subtracts value at the speicfied address from the value of the register, and writes result to the register. If the result is smaller than 0 then 0 gets written. 47 | * `JUMP -*--` - Changes the value of the program counter to the specified address, meaning that in the next cycle execution will continue at that address. 48 | * `IF MAX -*-*` - Jumps to the specified address if register has value 255 = `********`. 49 | * `IF MIN -**-` - Jumps to the specified address if register has value 0 = `--------`. 50 | * `SHIFT R -***` - Moves every bit of the register one spot to the right. This way rightmost bit gets lost, and a leftmost becomes '*-*'. This is the only instruction that doesn't use the address part, making the last four bits irrelevant. 51 | * Any instruction that is not defined above is interpreted as `READ ----` instruction. 52 | 53 | How to run on… 54 | -------------- 55 | 56 | ### Windows 57 | 58 | * Install *Tiny Core Linux* on *VirtualBox* using this [**instructions**](https://github.com/gto76/my-linux-setup/tree/gh-pages/conf-files/tiny-core-linux). 59 | * Run the *UNIX* commands. 60 | 61 | ### UNIX 62 | ``` 63 | $ git clone https://github.com/gto76/comp-cpp.git 64 | $ cd comp-cpp 65 | $ ./run 66 | ``` 67 | 68 | Other versions 69 | -------------- 70 | * [**Mark II**](https://github.com/gto76/comp-m2), model with separate address space for code and data, and with more instructions. Programs can be saved and loaded and it can run without the interface (instead of a printer, it then uses stdout). Also input can be piped in. 71 | 72 | ![screenshot](https://github.com/gto76/comp-m2/raw/master/doc/screenshot.png) 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /doc/examples/randomDot: -------------------------------------------------------------------------------- 1 | # RANDOM DOT 2 | # Single bit that jumps randomly one spot to the left or to the right every cycle. 3 | 4 | ----***- 5 | ---***** 6 | ----**** 7 | --*--**- 8 | -*-**--* 9 | ----***- 10 | -******* 11 | -**----- 12 | -*--**-- 13 | ----***- 14 | --*-***- 15 | -*-*---- 16 | ---****- 17 | -*------ 18 | ----*--- 19 | -------------------------------------------------------------------------------- /doc/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gto76/comp-cpp/40ab82ef4335e06b254424dc47a11a67ad604dd6/doc/screenshot.png -------------------------------------------------------------------------------- /doc/screenshot.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 18 | 19 | 21 | image/svg+xml 22 | 24 | 25 | 26 | 27 | 28 | 32 | RAM AD PC ADDR ________ _ _ ---- |----**-*|-|-| ---* |---*****|-|-| --*- |--*-***-|-|-| CPU --** |---***--|-|-| PRINTER ______________ -*-- |----**-*|-|-| ________________________ | | -*-* |---****-|-|-| | || [----**-*] | -**- |----**--|-|-| (| |=============[]=| |)|______________| INST -*** |---***-*|-|-| |__ _ ______________ _ __|| [-] READ | ---- *--- |--***-**|-|*| | |0| ----*--- 8 |0| || [-] WRITE | ---* *--* |-**-----|-|-| | |0| -----*-* 5 |0| || [-] ADD | --*- *-*- |-*--****|-|-| | |0| ------** 3 |0| || [*] SUBTRACT | --** *-** |---**---|*|-| | |0| ------*- 2 |0| || [-] JUMP | -*-- **-- |----**-*|-|-| | |0| -------* 1 |0| || [-] IF MAX | -*-* **-* |----**-*|-|-| | |0| -------* 1 |0| || [-] IF MIN | -**- ***- |----*---|-|-| | |0|______________|0| || [-] SHIFT R | -*** **** | OUTPUT |-|-| | | ############## ############ ###################### [] [] \____________/ [] [] \_______/ [] [] 98 | 99 | 100 | -------------------------------------------------------------------------------- /doc/screenshot.txt: -------------------------------------------------------------------------------- 1 | RAM AD PC 2 | ADDR ________ _ _ 3 | ---- |----**-*|-|-| 4 | ---* |---*****|-|-| 5 | --*- |--*-***-|-|-| 6 | CPU --** |---***--|-|-| PRINTER 7 | ______________ -*-- |----**-*|-|-| ________________________ 8 | | | -*-* |---****-|-|-| | | 9 | | [----**-*] | -**- |----**--|-|-| (| |=============[]=| |) 10 | |______________| INST -*** |---***-*|-|-| |__ _ ______________ _ __| 11 | | [-] READ | ---- *--- |--***-**|-|*| | |0| ----*--- 8 |0| | 12 | | [-] WRITE | ---* *--* |-**-----|-|-| | |0| -----*-* 5 |0| | 13 | | [-] ADD | --*- *-*- |-*--****|-|-| | |0| ------** 3 |0| | 14 | | [*] SUBTRACT | --** *-** |---**---|*|-| | |0| ------*- 2 |0| | 15 | | [-] JUMP | -*-- **-- |----**-*|-|-| | |0| -------* 1 |0| | 16 | | [-] IF MAX | -*-* **-* |----**-*|-|-| | |0| -------* 1 |0| | 17 | | [-] IF MIN | -**- ***- |----*---|-|-| | |0|______________|0| | 18 | | [-] SHIFT R | -*** **** | OUTPUT |-|-| | | 19 | ############## ############ ###################### 20 | [] [] \____________/ [] [] \_______/ [] [] 21 | -------------------------------------------------------------------------------- /doc/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gto76/comp-cpp/40ab82ef4335e06b254424dc47a11a67ad604dd6/doc/screenshot2.png -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-std=gnu11 -Wall -g -O3 2 | CPPFLAGS=-std=c++11 -Wall -g -O2 3 | 4 | SOURCES_CPP=$(wildcard src/*.cpp) 5 | SOURCES_C=$(wildcard src/*.c) 6 | 7 | OBJDIR=obj 8 | OBJECTS=$(addprefix $(OBJDIR)/,$(notdir $(SOURCES_CPP:.cpp=.o))) $(addprefix $(OBJDIR)/,$(notdir $(SOURCES_C:.c=.o))) 9 | 10 | EXECUTABLE=comp 11 | 12 | all: $(OBJDIR) $(SOURCES_CPP) $(SOURCES_C) $(EXECUTABLE) 13 | 14 | $(EXECUTABLE): $(OBJECTS) 15 | g++ -o $@ $^ 16 | 17 | # Including all .d files, that contain the make statements 18 | # describing depencencies of a files based on #include 19 | # statements. This is needed, so that changes to header files 20 | # get noticed, and apropriate files that depend on them get 21 | # recompiled. The dependencies get generated with compilers -MM 22 | # option. Is it just me or is this way too complicated. I just 23 | # want to compile a simple project for god sake, been 24 | # copypasting bits and pieces for whole day now. Don't you event 25 | # think about RTFMing me, I'll find where you live and burn your 26 | # house down :) 27 | -include $(OBJDIR)/*.d 28 | 29 | $(OBJDIR)/%.o: src/%.cpp 30 | g++ -c $(CPPFLAGS) -o $@ $< 31 | g++ -MM $(CPPFLAGS) -MT '$@' src/$*.cpp > $(OBJDIR)/$*.d 32 | 33 | $(OBJDIR)/%.o: src/%.c 34 | gcc -c $(CFLAGS) -o $@ $< 35 | gcc -MM $(CFLAGS) -MT '$@' src/$*.c > $(OBJDIR)/$*.d 36 | 37 | # Creates 'obj' directory if it doesent exist 38 | $(OBJDIR): 39 | mkdir -p $(OBJDIR) 40 | 41 | clean: 42 | rm -f $(OBJDIR)/* $(EXECUTABLE) 43 | 44 | # Convert a drawing textfile to a drawing.hpp, containing 45 | # that textfile in a string constant. 46 | src/drawing.hpp: src/resources/drawing 47 | sed '/Do not edit/q' src/drawing.hpp > /tmp/drawing.hpp 48 | printf "\nconst string drawing = {" >> /tmp/drawing.hpp 49 | xxd -i src/resources/drawing | tail -n+2 | head -n-1 >> /tmp/drawing.hpp 50 | printf "\n#endif" >> /tmp/drawing.hpp 51 | mv -f /tmp/drawing.hpp src/drawing.hpp 52 | 53 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | # Usage: run 2 | # Compiles and runs if no errors present. 3 | 4 | clear 5 | out=$(make 2>&1) 6 | rc=$? 7 | if [[ $rc -ne 0 ]]; then 8 | echo "$out" | head 9 | else 10 | ./comp 11 | fi 12 | 13 | -------------------------------------------------------------------------------- /src/comp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "const.hpp" 14 | #include "util.hpp" 15 | 16 | #include "printer.hpp" 17 | #include "ram.hpp" 18 | #include "cpu.hpp" 19 | #include "renderer.hpp" 20 | #include "drawing.hpp" 21 | #include "output.hpp" 22 | 23 | using namespace std; 24 | 25 | extern "C" { 26 | extern volatile sig_atomic_t pleaseExit; 27 | void setEnvironment(); 28 | void resetEnvironment(); 29 | } 30 | 31 | Printer printer; 32 | Ram ram; 33 | Cpu cpu; 34 | 35 | // Selected bit with the cursor 36 | int cursorX = 0; 37 | int cursorY = 0; 38 | 39 | // Graphic representation of the computer state 40 | vector buffer; 41 | 42 | // Saved state of a ram 43 | vector> savedRam; 44 | 45 | // Offset of first ram lightbulb in the asci drawing 46 | int ramX; 47 | int ramY; 48 | 49 | int executionCounter = 0; 50 | bool executionCanceled = false; 51 | 52 | void setRamOffset() { 53 | tuple t = Util::getLocationOfFirstRamLightbulb() ; 54 | ramX = get<0>(t); 55 | ramY = get<1>(t); 56 | } 57 | 58 | void drawScreen() { 59 | string out = Renderer::renderState(printer, ram, cpu); 60 | buffer = Util::splitString(out); 61 | int i = 0; 62 | for (string line : buffer) { 63 | printString(line.c_str(), 0, i++); 64 | } 65 | } 66 | 67 | void highlightCursor(bool highlight) { 68 | char c; 69 | try { 70 | c = buffer.at(cursorY+ramY).at(cursorX+ramX); 71 | } catch (int e) { 72 | cout << "Cursor out of bounds. Exception Nr. " << e << '\n'; 73 | return; 74 | } 75 | if (highlight) { 76 | printf("\e[%dm\e[%dm", 30, 47); 77 | } 78 | printCharImediately(c, cursorX+ramX, cursorY+ramY); 79 | if (highlight) { 80 | printf("\e[%dm\e[%dm", 37, 40); 81 | } 82 | fflush(stdout); 83 | } 84 | 85 | void switchBitUnderCursor() { 86 | bool newBitValue = !ram.state.at(cursorY).at(cursorX); 87 | ram.state.at(cursorY).at(cursorX) = newBitValue; 88 | // Only changes char of the buffer, as to avoid screen redraw. 89 | buffer.at(cursorY+ramY).at(cursorX+ramX) = Util::getChar(newBitValue); 90 | } 91 | 92 | void eraseByteUnderCursor() { 93 | ram.set(Util::getBoolNibb(cursorY), Util::getBoolByte(0)); 94 | redrawScreen(); 95 | } 96 | 97 | bool switchBytesInRam(int index1, int index2) { 98 | if (index1 < 0 || index2 < 0 || index1 >= RAM_SIZE || index2 >= RAM_SIZE) { 99 | return false; 100 | } 101 | vector addr1 = Util::getBoolNibb(index1); 102 | vector addr2 = Util::getBoolNibb(index2); 103 | vector temp = ram.get(addr1); 104 | ram.set(addr1, ram.get(addr2)); 105 | ram.set(addr2, temp); 106 | return true; 107 | } 108 | 109 | void moveByteFor(int delta) { 110 | bool failed = !switchBytesInRam(cursorY, cursorY+delta); 111 | if (failed) { 112 | return; 113 | } 114 | cursorY += delta; 115 | redrawScreen(); 116 | } 117 | 118 | void moveByteUnderCursorUp() { 119 | moveByteFor(-1); 120 | } 121 | 122 | void moveByteUnderCursorDown() { 123 | moveByteFor(1); 124 | } 125 | 126 | char readStdin(bool drawCursor) { 127 | char c = 0; 128 | errno = 0; 129 | ssize_t num = read(0, &c, 1); 130 | if (num == -1 && errno == EINTR) { 131 | // Exits if ctrl-c was pressed. 132 | if (pleaseExit) { 133 | exit(0); 134 | } 135 | redrawScreen(); 136 | if (drawCursor) { 137 | highlightCursor(true); 138 | } 139 | return readStdin(drawCursor); 140 | } 141 | return c; 142 | } 143 | 144 | /* 145 | * Saves the state of the ram and starts the execution of a program. 146 | * When execution stops, due to it reaching last address or user pressing 'esc', 147 | * it loads back the saved state of the ram, and resets the cpu. 148 | */ 149 | void run() { 150 | if (executionCounter > 0) { 151 | printer.print(" \n"); 152 | } 153 | savedRam = ram.state; 154 | cpu.exec(); 155 | // if 'esc' was pressed then it doesn't wait for keypress at the end. 156 | if (executionCanceled) { 157 | executionCanceled = false; 158 | } else { 159 | readStdin(false); 160 | } 161 | ram = Ram(); 162 | ram.state = savedRam; 163 | cpu = Cpu(); 164 | redrawScreen(); 165 | executionCounter++; 166 | } 167 | 168 | string getFreeFileName() { 169 | int i = 0; 170 | while (Util::fileExists(SAVE_FILE_NAME + to_string(++i))); 171 | return SAVE_FILE_NAME + to_string(i); 172 | } 173 | 174 | void saveRamToFile() { 175 | string fileName = getFreeFileName(); 176 | ofstream fileStream(fileName); 177 | fileStream << ram.getString(); 178 | fileStream.close(); 179 | } 180 | 181 | void userInput() { 182 | while(1) { 183 | char c = readStdin(true); 184 | 185 | highlightCursor(false); 186 | switch (c) { 187 | case 65: // up 188 | if (cursorY > 0) { 189 | cursorY--; 190 | } 191 | break; 192 | case 66: // down 193 | if (cursorY < RAM_SIZE-1) { 194 | cursorY++; 195 | } 196 | break; 197 | case 67: // right 198 | if (cursorX < WORD_SIZE-1) { 199 | cursorX++; 200 | } 201 | break; 202 | case 68: // left 203 | if (cursorX > 0) { 204 | cursorX--; 205 | } 206 | break; 207 | case 107: // k 208 | moveByteUnderCursorUp(); 209 | break; 210 | case 106: // j 211 | moveByteUnderCursorDown(); 212 | break; 213 | case 115: // s 214 | saveRamToFile(); 215 | break; 216 | case 32: // space 217 | case 102: // f 218 | switchBitUnderCursor(); 219 | break; 220 | case 100: // d 221 | eraseByteUnderCursor(); 222 | break; 223 | case 10: // enter 224 | run(); 225 | break; 226 | } 227 | highlightCursor(true); 228 | } 229 | } 230 | 231 | /* 232 | * Runs every cycle. 233 | */ 234 | void sleepAndCheckForKey() { 235 | usleep(FQ*1000); 236 | 237 | // Exits if ctrl-c was pressed. 238 | if (pleaseExit) { 239 | exit(0); 240 | } 241 | 242 | // Pauses execution if a key was hit, and waits for another key hit. 243 | int keyCode = Util::getKey(); 244 | if (keyCode) { 245 | // If escape was pressed. 246 | if (keyCode == 27) { 247 | executionCanceled = true; 248 | return; 249 | } 250 | // Press key to continue. 251 | keyCode = readStdin(false); 252 | // If the key was esc. 253 | if (keyCode == 27) { 254 | executionCanceled = true; 255 | } 256 | } 257 | } 258 | 259 | /* 260 | * Initializes 'output.c' by sending dimensions of a 'drawing' and a 'drawScreen' 261 | * callback function, that output.c will use on every screen redraw. 262 | */ 263 | void prepareOutput() { 264 | size_t drawingWidth = 0; 265 | size_t drawingHeight = 0; 266 | for (string line : Util::splitString(drawing)) { 267 | drawingWidth = std::max(drawingWidth, line.length()); 268 | drawingHeight++; 269 | } 270 | setOutput(&drawScreen, drawingWidth, drawingHeight); 271 | } 272 | 273 | bool getBool(char c) { 274 | return c == '*'; 275 | } 276 | 277 | void loadRamFromFileStream(ifstream* fileStream) { 278 | int address = 0; 279 | while (!fileStream->eof()) { 280 | int bitIndex = 0; 281 | string line; 282 | getline(*fileStream, line); 283 | // Ignores line if empty or a comment. 284 | if (line.empty() || line[0] == '#') { 285 | continue; 286 | } 287 | for (char c : line) { 288 | ram.state.at(address).at(bitIndex) = getBool(c); 289 | if (++bitIndex >= WORD_SIZE) { 290 | break; 291 | } 292 | } 293 | if (++address >= RAM_SIZE) { 294 | return; 295 | } 296 | } 297 | } 298 | 299 | 300 | void loadRamIfFileSpecified(int argc, const char* argv[]) { 301 | if (argc <= 1) { 302 | return; 303 | } 304 | ifstream fileStream; 305 | fileStream.open(argv[1]); 306 | if (fileStream.fail()) { 307 | fprintf(stderr, "Invalid filename '%s'. Aborting ram load.", argv[1]); 308 | } else { 309 | loadRamFromFileStream(&fileStream); 310 | fileStream.close(); 311 | } 312 | } 313 | 314 | /* 315 | * PRINTER 316 | */ 317 | 318 | void Printer::print(string sIn) { 319 | output += sIn; 320 | printerOutputUpdated = false; 321 | } 322 | 323 | string Printer::getOutput() { 324 | return output; 325 | } 326 | 327 | string Printer::getPrinterOutput() { 328 | if (!printerOutputUpdated) { 329 | printerOutput = renderPrinterOutput(); 330 | printerOutputUpdated = true; 331 | } 332 | return printerOutput; 333 | } 334 | 335 | void Printer::clear() { 336 | output = ""; 337 | printerOutputUpdated = false; 338 | } 339 | 340 | string Printer::renderPrinterOutput() { 341 | if (output.length() <= 0) { 342 | return "|0|______________|0|"; 343 | } 344 | vector lines = Util::splitString(output); 345 | reverse(lines.begin(), lines.end()); 346 | vector outputLines; 347 | for (string line : lines) { 348 | outputLines.push_back("|0| " + line + " |0|"); 349 | } 350 | outputLines.push_back("|0|______________|0|"); 351 | return Util::makeString(outputLines); 352 | } 353 | 354 | /* 355 | * RAM 356 | */ 357 | 358 | vector Ram::get(vector adr) { 359 | int address = Util::getInt(adr); 360 | // Returns random if last address (reserved for output). 361 | if (address == RAM_SIZE) { 362 | vector wordOut = Util::getRandomWord(); 363 | return wordOut; 364 | } 365 | vector wordOut(WORD_SIZE); 366 | for (int i = 0; i < WORD_SIZE; i++) { 367 | wordOut[i] = state[address][i]; 368 | } 369 | return wordOut; 370 | } 371 | 372 | void Ram::set(vector adr, vector wordIn) { 373 | int address = Util::getInt(adr); 374 | // Saves word. 375 | if (address < RAM_SIZE) { 376 | for (int i = 0; i < WORD_SIZE; i++) { 377 | state[address][i] = wordIn[i]; 378 | } 379 | // Sends word to printer. 380 | } else { 381 | char formatedInt [4]; 382 | sprintf(formatedInt, "%3d", Util::getInt(wordIn)); 383 | string outputLine = Util::getString(wordIn) + " " + formatedInt + "\n"; 384 | printer.print(outputLine); 385 | } 386 | } 387 | 388 | string Ram::getString() { 389 | string out; 390 | for (vector word : state) { 391 | out += Util::getString(word) + '\n'; 392 | } 393 | return out; 394 | } 395 | 396 | /* 397 | * CPU 398 | */ 399 | 400 | void Cpu::exec() { 401 | while(!executionCanceled) { 402 | bool shouldContinue = step(); 403 | redrawScreen(); // Always redraws. 404 | if(!shouldContinue) { 405 | return; 406 | } 407 | sleepAndCheckForKey(); 408 | } 409 | } 410 | 411 | bool Cpu::step() { 412 | cycle++; 413 | 414 | // Stops if reached last address. 415 | if (Util::getInt(pc) >= RAM_SIZE) { 416 | return false; 417 | } 418 | 419 | vector instruction = getInstruction(); 420 | int instCode = Util::getInt(instruction); 421 | vector adr = getAddress(); 422 | 423 | switch (instCode) { 424 | case 0: 425 | read(adr); 426 | break; 427 | case 1: 428 | write(adr); 429 | break; 430 | case 2: 431 | add(adr); 432 | break; 433 | case 3: 434 | sub(adr); 435 | break; 436 | case 4: 437 | jump(adr); 438 | break; 439 | case 5: 440 | jumpIfMax(adr); 441 | break; 442 | case 6: 443 | jumpIfMin(adr); 444 | break; 445 | case 7: 446 | shiftRight(); 447 | break; 448 | default: 449 | read(adr); 450 | } 451 | 452 | return true; 453 | } 454 | 455 | int Cpu::getCycle() { 456 | return cycle; 457 | } 458 | 459 | vector Cpu::getRegister() { 460 | return reg; 461 | } 462 | 463 | vector Cpu::getPc() { 464 | return pc; 465 | } 466 | 467 | vector Cpu::getInstruction() { 468 | vector instruction = Util::getFirstNibble(ram.get(pc)); 469 | // If instruction id is larger than the number of instructions then 470 | // the instruction with id 1 (write) gets executed. 471 | if (Util::getInt(instruction) >= NUM_OF_INSTRUCTIONS) { 472 | return Util::getBoolNibb(0); 473 | } 474 | return instruction; 475 | } 476 | 477 | vector Cpu::getAddress() { 478 | return Util::getSecondNibble(ram.get(pc)); 479 | } 480 | 481 | void Cpu::increasePc() { 482 | pc = Util::getBoolNibb(Util::getInt(pc) + 1); 483 | } 484 | 485 | void Cpu::read(vector adr) { 486 | reg = ram.get(adr); 487 | increasePc(); 488 | } 489 | 490 | void Cpu::write(vector adr) { 491 | ram.set(adr, reg); 492 | increasePc(); 493 | } 494 | 495 | void Cpu::add(vector adr) { 496 | reg = Util::getBoolByte(Util::getInt(reg) + Util::getInt(ram.get(adr))); 497 | increasePc(); 498 | } 499 | 500 | void Cpu::sub(vector adr) { 501 | reg = Util::getBoolByte(Util::getInt(reg) - Util::getInt(ram.get(adr))); 502 | increasePc(); 503 | } 504 | 505 | void Cpu::jump(vector adr) { 506 | pc = adr; 507 | } 508 | 509 | void Cpu::jumpIfMax(vector adr) { 510 | if (Util::getInt(reg) >= pow(2, WORD_SIZE)-1) { 511 | pc = adr; 512 | } else { 513 | increasePc(); 514 | } 515 | } 516 | 517 | void Cpu::jumpIfMin(vector adr) { 518 | if (Util::getInt(reg) <= 0) { 519 | pc = adr; 520 | } else { 521 | increasePc(); 522 | } 523 | } 524 | 525 | void Cpu::shiftRight() { 526 | reg = Util::getBoolByte(Util::getInt(reg) / 2); 527 | increasePc(); 528 | } 529 | 530 | /* 531 | * MAIN 532 | */ 533 | 534 | int main(int argc, const char* argv[]) { 535 | srand(time(NULL)); 536 | setRamOffset(); 537 | setEnvironment(); 538 | prepareOutput(); 539 | loadRamIfFileSpecified(argc, argv); 540 | clearScreen(); 541 | redrawScreen(); 542 | highlightCursor(true); 543 | userInput(); 544 | } 545 | 546 | -------------------------------------------------------------------------------- /src/const.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CONST_H 2 | #define CONST_H 3 | 4 | using namespace std; 5 | 6 | const int WORD_SIZE = 8; 7 | const int ADDR_SIZE = 4; 8 | const int RAM_SIZE = 15; 9 | 10 | const int NUM_OF_INSTRUCTIONS = 8; 11 | 12 | // Miliseconds between cycles (if automatic) 13 | const int FQ = 333; 14 | 15 | const string SAVE_FILE_NAME = "saved-ram-"; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/cpu.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CPU_H 2 | #define CPU_H 3 | 4 | #include "const.hpp" 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | class Cpu { 11 | public: 12 | void exec(); 13 | vector getRegister(); 14 | vector getPc(); 15 | vector getInstruction(); 16 | vector getAddress(); 17 | int getCycle(); 18 | private: 19 | vector reg = vector(WORD_SIZE); 20 | vector pc = vector(ADDR_SIZE); 21 | int cycle = 0; 22 | bool step(); 23 | void increasePc(); 24 | void read(vector adr); 25 | void write(vector adr); 26 | void add(vector adr); 27 | void sub(vector adr); 28 | void jump(vector adr); 29 | void jumpIfMax(vector adr); 30 | void jumpIfMin(vector adr); 31 | void shiftRight(); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/drawing.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DRAWING_H 2 | #define DRAWING_H 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Automaticaly generated file from resources/drawing textfile. 9 | // Do not edit this line. 10 | 11 | const string drawing = { 12 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 13 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 14 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x41, 0x4d, 0x20, 15 | 0x20, 0x41, 0x44, 0x20, 0x50, 0x43, 0x20, 0x20, 0x20, 0x20, 0x0d, 0x0a, 16 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 17 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 18 | 0x44, 0x44, 0x52, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 19 | 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0d, 20 | 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 21 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 22 | 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 0x7c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 23 | 0x30, 0x30, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x0d, 24 | 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 25 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 26 | 0x2d, 0x2d, 0x2d, 0x2a, 0x20, 0x7c, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 27 | 0x31, 0x31, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x0d, 28 | 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 29 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 30 | 0x2d, 0x2d, 0x2a, 0x2d, 0x20, 0x7c, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 31 | 0x32, 0x32, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x0d, 32 | 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x50, 0x55, 0x20, 0x20, 33 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 34 | 0x2d, 0x2d, 0x2a, 0x2a, 0x20, 0x7c, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 35 | 0x33, 0x33, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 36 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x52, 37 | 0x49, 0x4e, 0x54, 0x45, 0x52, 0x20, 0x20, 0x0d, 0x0a, 0x20, 0x5f, 0x5f, 38 | 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 39 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2a, 0x2d, 0x2d, 40 | 0x20, 0x7c, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x7c, 0x73, 41 | 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x5f, 42 | 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 43 | 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x0d, 44 | 0x0a, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 45 | 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 46 | 0x2d, 0x2a, 0x2d, 0x2a, 0x20, 0x7c, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 47 | 0x35, 0x35, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 48 | 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 49 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 50 | 0x20, 0x20, 0x7c, 0x0d, 0x0a, 0x7c, 0x20, 0x20, 0x5b, 0x72, 0x72, 0x72, 51 | 0x72, 0x72, 0x72, 0x72, 0x72, 0x5d, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x20, 52 | 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2a, 0x2a, 0x2d, 0x20, 0x7c, 0x36, 0x36, 53 | 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 54 | 0x20, 0x20, 0x20, 0x20, 0x28, 0x7c, 0x20, 0x20, 0x20, 0x7c, 0x3d, 0x3d, 55 | 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x5b, 56 | 0x5d, 0x3d, 0x7c, 0x20, 0x20, 0x20, 0x7c, 0x29, 0x0d, 0x0a, 0x7c, 0x5f, 57 | 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 58 | 0x5f, 0x7c, 0x20, 0x49, 0x4e, 0x53, 0x54, 0x20, 0x20, 0x2d, 0x2a, 0x2a, 59 | 0x2a, 0x20, 0x7c, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x7c, 60 | 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x5f, 61 | 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 62 | 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x7c, 63 | 0x0d, 0x0a, 0x7c, 0x20, 0x5b, 0x69, 0x5d, 0x20, 0x52, 0x45, 0x41, 0x44, 64 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x20, 65 | 0x20, 0x2a, 0x2d, 0x2d, 0x2d, 0x20, 0x7c, 0x38, 0x38, 0x38, 0x38, 0x38, 66 | 0x38, 0x38, 0x38, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 67 | 0x20, 0x20, 0x20, 0x7c, 0x20, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 68 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 69 | 0x6f, 0x20, 0x7c, 0x20, 0x0d, 0x0a, 0x7c, 0x20, 0x5b, 0x69, 0x5d, 0x20, 70 | 0x57, 0x52, 0x49, 0x54, 0x45, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x2d, 71 | 0x2d, 0x2d, 0x2a, 0x20, 0x20, 0x2a, 0x2d, 0x2d, 0x2a, 0x20, 0x7c, 0x39, 72 | 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 73 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x6f, 0x6f, 0x6f, 74 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 75 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x20, 0x7c, 0x0d, 0x0a, 0x7c, 0x20, 0x5b, 76 | 0x69, 0x5d, 0x20, 0x41, 0x44, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 77 | 0x7c, 0x20, 0x2d, 0x2d, 0x2a, 0x2d, 0x20, 0x20, 0x2a, 0x2d, 0x2a, 0x2d, 78 | 0x20, 0x7c, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x7c, 0x73, 79 | 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 80 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 81 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x20, 0x7c, 0x20, 0x0d, 82 | 0x0a, 0x7c, 0x20, 0x5b, 0x69, 0x5d, 0x20, 0x53, 0x55, 0x42, 0x54, 0x52, 83 | 0x41, 0x43, 0x54, 0x20, 0x7c, 0x20, 0x2d, 0x2d, 0x2a, 0x2a, 0x20, 0x20, 84 | 0x2a, 0x2d, 0x2a, 0x2a, 0x20, 0x7c, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 85 | 0x62, 0x62, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 86 | 0x20, 0x20, 0x7c, 0x20, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 87 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 88 | 0x20, 0x7c, 0x0d, 0x0a, 0x7c, 0x20, 0x5b, 0x69, 0x5d, 0x20, 0x4a, 0x55, 89 | 0x4d, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x2d, 0x2a, 0x2d, 90 | 0x2d, 0x20, 0x20, 0x2a, 0x2a, 0x2d, 0x2d, 0x20, 0x7c, 0x63, 0x63, 0x63, 91 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 92 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 93 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 94 | 0x6f, 0x6f, 0x6f, 0x20, 0x7c, 0x0d, 0x0a, 0x7c, 0x20, 0x5b, 0x69, 0x5d, 95 | 0x20, 0x49, 0x46, 0x20, 0x4d, 0x41, 0x58, 0x20, 0x20, 0x20, 0x7c, 0x20, 96 | 0x2d, 0x2a, 0x2d, 0x2a, 0x20, 0x20, 0x2a, 0x2a, 0x2d, 0x2a, 0x20, 0x7c, 97 | 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x7c, 0x73, 0x7c, 0x70, 98 | 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x6f, 0x6f, 99 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 100 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x20, 0x7c, 0x0d, 0x0a, 0x7c, 0x20, 101 | 0x5b, 0x69, 0x5d, 0x20, 0x49, 0x46, 0x20, 0x4d, 0x49, 0x4e, 0x20, 0x20, 102 | 0x20, 0x7c, 0x20, 0x2d, 0x2a, 0x2a, 0x2d, 0x20, 0x20, 0x2a, 0x2a, 0x2a, 103 | 0x2d, 0x20, 0x7c, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7c, 104 | 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 105 | 0x20, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 106 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x20, 0x7c, 0x0d, 107 | 0x0a, 0x7c, 0x20, 0x5b, 0x69, 0x5d, 0x20, 0x53, 0x48, 0x49, 0x46, 0x54, 108 | 0x20, 0x52, 0x20, 0x20, 0x7c, 0x20, 0x2d, 0x2a, 0x2a, 0x2a, 0x20, 0x20, 109 | 0x2a, 0x2a, 0x2a, 0x2a, 0x20, 0x7c, 0x20, 0x4f, 0x55, 0x54, 0x50, 0x55, 110 | 0x54, 0x20, 0x7c, 0x73, 0x7c, 0x70, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 111 | 0x20, 0x20, 0x7c, 0x20, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 112 | 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 113 | 0x20, 0x7c, 0x0d, 0x0a, 0x20, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 114 | 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 115 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, 0x23, 0x23, 116 | 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 117 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 118 | 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 119 | 0x23, 0x23, 0x23, 0x23, 0x20, 0x0d, 0x0a, 0x20, 0x20, 0x5b, 0x5d, 0x20, 120 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x20, 0x5c, 0x5f, 121 | 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f, 122 | 0x20, 0x5b, 0x5d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x20, 123 | 0x5c, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f, 0x20, 0x5b, 0x5d, 124 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 125 | 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x20, 0x0d, 0x0a 126 | }; 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /src/environment.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void setEnvironment(void); 10 | void checkTerminal(void); 11 | void saveAttributes(void); 12 | void setMenuMode(void); 13 | void setRaceMode(void); 14 | void setNoncanonicalMode(int vmin, int vtime); 15 | void registerSigIntCatcher(void); 16 | void sigIntCatcher(int signum); 17 | void disableRepeatAndCursor(void); 18 | void resetEnvironment(void); 19 | void resetInputMode(void); 20 | void enableRepeatAndCursor(void); 21 | void resetConsole(void); 22 | 23 | ////////////////////////////// 24 | 25 | int const DISABLE_REPEAT = 0; 26 | 27 | struct termios saved_attributes; 28 | volatile sig_atomic_t pleaseExit = 0; 29 | 30 | //////// AT START //////////// 31 | 32 | void setEnvironment() { 33 | checkTerminal(); 34 | saveAttributes(); 35 | setMenuMode(); 36 | registerSigIntCatcher(); 37 | disableRepeatAndCursor(); 38 | } 39 | 40 | void checkTerminal() { 41 | if (!~isatty(STDIN_FILENO)) { 42 | printf("Not a terminal: %d.\n", STDIN_FILENO); 43 | exit(EXIT_FAILURE); 44 | } 45 | } 46 | 47 | void saveAttributes() { 48 | tcgetattr(STDIN_FILENO, &saved_attributes); 49 | } 50 | 51 | // blocking mode (getc waits for input) 52 | void setMenuMode() { 53 | setNoncanonicalMode(1, 0); 54 | } 55 | 56 | // nonblocking mode (getc does not wait for input, it returns every 0.1 s) 57 | void setRaceMode() { 58 | setNoncanonicalMode(0, 1); 59 | } 60 | 61 | void setNoncanonicalMode(int vmin, int vtime) { 62 | struct termios tattr; 63 | // set noncanonical mode, disable echo 64 | atexit(resetEnvironment); 65 | tcgetattr(STDIN_FILENO, &tattr); 66 | tattr.c_lflag &= ~(ICANON|ECHO); 67 | tattr.c_cc[VMIN] = vmin; 68 | tattr.c_cc[VTIME] = vtime; 69 | tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr); 70 | } 71 | 72 | void registerSigIntCatcher() { 73 | struct sigaction action; 74 | // reset all members 75 | memset(&action, 0, sizeof(action)); 76 | action.sa_handler = sigIntCatcher; 77 | sigaction(SIGINT, &action, NULL); 78 | } 79 | 80 | // method that gets executed when ctrl-c is pressed. 81 | // necesary so that atexit method gets executed, 82 | // that sets terminal back to the original state. 83 | void sigIntCatcher(int signum) { 84 | //exit(0); 85 | pleaseExit = 1; 86 | } 87 | 88 | void checkRetVal(int retVal, char const errMsg[]) { 89 | if (retVal == -1) { 90 | fprintf(stderr, "%s", errMsg); 91 | } 92 | } 93 | 94 | void disableRepeatAndCursor() { 95 | if (DISABLE_REPEAT) { 96 | // disable repeat in xwindow console 97 | int retVal = system("xset -r"); 98 | checkRetVal(retVal, "Could disable key repeat."); 99 | // disable repeat in Linux console 100 | retVal = system("setterm --repeat off"); 101 | checkRetVal(retVal, "Could disable key repeat."); 102 | } 103 | // set cursor off. could also probably use system("setterm -cursor off); 104 | printf("\e[?25l"); 105 | fflush(stdout); 106 | } 107 | 108 | ///////// AT END //////////// 109 | 110 | void resetEnvironment() { 111 | resetInputMode(); 112 | enableRepeatAndCursor(); 113 | resetConsole(); 114 | } 115 | 116 | void resetConsole() { 117 | int retVal = system("reset"); 118 | checkRetVal(retVal, "Could not reset the screen."); 119 | } 120 | 121 | void resetInputMode() { 122 | // bring back canonical mode 123 | tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes); 124 | } 125 | 126 | void enableRepeatAndCursor() { 127 | if (DISABLE_REPEAT) { 128 | // enable repeat in Xwindow console 129 | int retVal = system("xset r"); 130 | checkRetVal(retVal, "Could not enable key repeat."); 131 | // disable repeat in Linux console 132 | retVal = system("setterm --repeat on"); 133 | checkRetVal(retVal, "Could not enable key repeat."); 134 | } 135 | int retVal = system("clear"); 136 | checkRetVal(retVal, "Could not clear the screen."); 137 | // bring back cursor 138 | printf("\e[?25h"); 139 | fflush(stdout) ; 140 | } 141 | 142 | -------------------------------------------------------------------------------- /src/environment.h: -------------------------------------------------------------------------------- 1 | #ifndef ENVIRONMENT_H 2 | #define ENVIRONMENT_H 3 | 4 | void setEnvironment(); 5 | extern volatile sig_atomic_t pleaseExit; 6 | 7 | #endif -------------------------------------------------------------------------------- /src/output.cpp: -------------------------------------------------------------------------------- 1 | #include "output.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //////////////////////////// 11 | 12 | int getAbsoluteX(int x); 13 | int getAbsoluteY(int y); 14 | int getAbsoluteCoordinate(int value, int console, int track); 15 | int coordinatesOutOfBounds(int x, int y); 16 | void clearScreen(void); 17 | void registerSigWinChCatcher(void); 18 | void sigWinChCatcher(int signum); 19 | void updateConsoleSize(void); 20 | void copyArray(char dest[], const char src[], int width); 21 | 22 | //////////////////////////// 23 | 24 | #define PRINT_IN_CENTER 1 25 | #define DEFAULT_WIDTH 80 26 | #define DEFAULT_HEIGHT 24 27 | 28 | int pictureWidth = DEFAULT_WIDTH; 29 | int pictureHeight = DEFAULT_HEIGHT; 30 | 31 | int columns = DEFAULT_WIDTH; 32 | int rows = DEFAULT_HEIGHT; 33 | 34 | callback_function drawScreen; 35 | volatile sig_atomic_t screenResized = 0; 36 | 37 | vector screenBuffer; 38 | vector onScreen; 39 | 40 | ////////// PUBLIC ////////// 41 | 42 | void setOutput(callback_function drawScreenThat, int width, int height) { 43 | drawScreen = drawScreenThat; 44 | pictureWidth = width; 45 | pictureHeight = height; 46 | registerSigWinChCatcher(); 47 | updateConsoleSize(); 48 | // Set colors. 49 | printf("\e[%dm\e[%dm", 37, 40); 50 | } 51 | 52 | void updateScreen() { 53 | for (size_t i = 0; i < screenBuffer.size(); i++) { 54 | if (onScreen.size() <= i) { 55 | onScreen.push_back(""); 56 | } 57 | if (screenBuffer.at(i) != onScreen.at(i)) { 58 | onScreen.at(i) = screenBuffer.at(i); 59 | printf("\033[%d;%dH%s", getAbsoluteY(i), getAbsoluteX(0), screenBuffer.at(i).c_str()); 60 | } 61 | } 62 | } 63 | 64 | void setBuffer(string s, int x, int y) { 65 | int size = screenBuffer.size(); 66 | if (size <= y) { 67 | for (int i = size; i <= y+1; i++) { 68 | screenBuffer.push_back(""); 69 | } 70 | } 71 | screenBuffer.at(y).replace(x, s.length(), s); 72 | } 73 | 74 | void printCharXY(char c, int x, int y) { 75 | if (coordinatesOutOfBounds(x, y)) { 76 | return; 77 | } 78 | setBuffer(string(1, c), x, y); 79 | //printf("\033[%d;%dH%c", getAbsoluteY(y), getAbsoluteX(x), c); 80 | } 81 | 82 | void printCharImediately(char c, int x, int y) { 83 | if (coordinatesOutOfBounds(x, y)) { 84 | return; 85 | } 86 | printf("\033[%d;%dH%c", getAbsoluteY(y), getAbsoluteX(x), c); 87 | } 88 | 89 | void printString(char const s[], int x, int y) { 90 | if (coordinatesOutOfBounds(x, y)) 91 | return; 92 | int itDoesntFitTheScreen = strlen(s) + (unsigned) x > (unsigned) columns; 93 | if (itDoesntFitTheScreen) { 94 | int distanceToTheRightEdge = columns - x - 1; 95 | char subArray[distanceToTheRightEdge+2]; 96 | copyArray(subArray, s, distanceToTheRightEdge+2); 97 | s = subArray; 98 | setBuffer(subArray, x, y); 99 | //printf("\033[%d;%dH%s", getAbsoluteY(y), getAbsoluteX(x), subArray); 100 | } else { 101 | setBuffer(s, x, y); 102 | //printf("\033[%d;%dH%s", getAbsoluteY(y), getAbsoluteX(x), s); 103 | } 104 | } 105 | 106 | int getAbsoluteX(int x) { 107 | return getAbsoluteCoordinate(x, columns, pictureWidth); 108 | } 109 | 110 | int getAbsoluteY(int y) { 111 | return getAbsoluteCoordinate(y, rows, pictureHeight); 112 | } 113 | 114 | int getAbsoluteCoordinate(int value, int console, int track) { 115 | int offset = 0; 116 | if (PRINT_IN_CENTER) { 117 | offset = ((console - track) / 2) + ((console - track) % 2); 118 | if (offset < 0) 119 | offset = 0; 120 | } 121 | return value + 1 + offset; 122 | } 123 | 124 | int coordinatesOutOfBounds(int x, int y) { 125 | return x >= columns || y >= rows || x < 0 || y < 0; 126 | } 127 | 128 | /////////// DRAW /////////// 129 | 130 | void refresh() { 131 | for (size_t i = 0; i < screenBuffer.size(); i++) { 132 | if (onScreen.size() <= i) { 133 | onScreen.push_back(""); 134 | } 135 | printf("\033[%d;%dH%s", getAbsoluteY(i), getAbsoluteX(0), screenBuffer.at(i).c_str()); 136 | if (screenBuffer.at(i) != onScreen.at(i)) { 137 | onScreen.at(i) = screenBuffer.at(i); 138 | } 139 | } 140 | } 141 | 142 | void clearScreen(void) { 143 | onScreen = {}; 144 | screenBuffer = {}; 145 | printf("\e[1;1H\e[2J"); 146 | } 147 | 148 | void refreshScreen() { 149 | screenResized = 0; 150 | updateConsoleSize(); 151 | clearScreen(); 152 | drawScreen(); 153 | refresh(); 154 | fflush(stdout); 155 | } 156 | 157 | 158 | void redrawScreen() { 159 | if (screenResized == 1) { 160 | refreshScreen(); 161 | } else { 162 | updateConsoleSize(); 163 | drawScreen(); 164 | updateScreen(); 165 | fflush(stdout); 166 | } 167 | } 168 | 169 | ///////// SIGNALS ////////// 170 | 171 | void registerSigWinChCatcher() { 172 | struct sigaction action; 173 | 174 | sigemptyset(&action.sa_mask); 175 | action.sa_flags = 0; 176 | 177 | action.sa_handler = sigWinChCatcher; 178 | sigaction(SIGWINCH, &action, NULL); 179 | } 180 | 181 | /* 182 | * Fires when window size changes. 183 | */ 184 | void sigWinChCatcher(int signum) { 185 | screenResized = 1; 186 | } 187 | 188 | /* 189 | * Asks system about window size. 190 | */ 191 | void updateConsoleSize() { 192 | struct winsize w; 193 | ioctl(0, TIOCGWINSZ, &w); 194 | columns = w.ws_col; 195 | rows = w.ws_row; 196 | } 197 | 198 | /////////// UTIL /////////// 199 | 200 | void copyArray(char dest[], const char src[], int width) { 201 | int i; 202 | for (i = 0; i < width-1; i++) { 203 | dest[i] = src[i]; 204 | } 205 | dest[width-1] = '\0'; 206 | } 207 | 208 | 209 | -------------------------------------------------------------------------------- /src/output.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OUTPUT_H 2 | #define OUTPUT_H 3 | 4 | //#include "const.hpp" 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | typedef void (*callback_function)(void); 11 | 12 | // Initializes the output 13 | void setOutput(callback_function drawScreen, int width, int height); 14 | 15 | // API 16 | void printCharXY(char c, int x, int y); 17 | void printString(const char s[], int x, int y); 18 | void redrawScreen(); 19 | void printCharImediately(char c, int x, int y); 20 | 21 | void clearScreen(void); 22 | 23 | extern volatile sig_atomic_t screenResized; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/printer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PRINTER_H 2 | #define PRINTER_H 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | class Printer { 9 | public: 10 | void print(string sIn); 11 | string getOutput(); 12 | string getPrinterOutput(); 13 | void clear(); 14 | private: 15 | string output = ""; 16 | string printerOutput; 17 | bool printerOutputUpdated = false; 18 | string renderPrinterOutput(); 19 | }; 20 | 21 | #endif -------------------------------------------------------------------------------- /src/ram.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RAM_H 2 | #define RAM_H 3 | 4 | #include 5 | 6 | #include "const.hpp" 7 | 8 | using namespace std; 9 | 10 | class Ram { 11 | public: 12 | vector> state = vector>(RAM_SIZE, vector(WORD_SIZE)); 13 | vector get(vector adr); 14 | void set(vector adr, vector wordIn); 15 | string getString(); 16 | }; 17 | 18 | #endif -------------------------------------------------------------------------------- /src/renderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "const.hpp" 7 | #include "renderer.hpp" 8 | #include "printer.hpp" 9 | #include "ram.hpp" 10 | #include "cpu.hpp" 11 | #include "util.hpp" 12 | #include "drawing.hpp" 13 | 14 | using namespace std; 15 | 16 | // STATIC PUBLIC: 17 | string Renderer::renderState(Printer printerIn, Ram ramIn, Cpu cpuIn) { 18 | Renderer instance(printerIn, ramIn, cpuIn); 19 | 20 | string out; 21 | for (string line : Util::splitString(drawing)) { 22 | string processedLine = instance.insertActualValues(line); 23 | out += processedLine + "\n"; 24 | } 25 | out.erase(out.end() - 1); 26 | return out; 27 | } 28 | 29 | // PRIVATE CONSTRUCTOR: 30 | Renderer::Renderer(Printer printerIn, Ram ramIn, Cpu cpuIn) { 31 | Renderer::printer = printerIn; 32 | Renderer::ram = ramIn; 33 | Renderer::cpu = cpuIn; 34 | switchIndex.clear(); 35 | } 36 | 37 | // DYNAMIC PRIVATE: 38 | string Renderer::insertActualValues(string lineIn) { 39 | string lineOut; 40 | 41 | for (char cIn : lineIn) { 42 | char cOut; 43 | 44 | // Regex: [0-9a-z]; 45 | bool charIsALightbulb = (cIn >= 'a' && cIn <= 'z') || (cIn >= '0' && cIn <= '9'); 46 | if (charIsALightbulb) { 47 | cOut = getLightbulb(cIn); 48 | } else { 49 | cOut = cIn; 50 | } 51 | lineOut += cOut; 52 | } 53 | return lineOut; 54 | } 55 | 56 | char Renderer::getLightbulb(char cIn) { 57 | int i = switchIndex[cIn]++; 58 | 59 | // Regex: [0-9a-e] 60 | bool charRepresentsRam = (cIn >= 'a' && cIn <= 'e') || (cIn >= '0' && cIn <= '9'); 61 | if (charRepresentsRam) { 62 | int j = Util::hexToInt(cIn); 63 | return getRamAt(j, i); 64 | } 65 | 66 | switch (cIn) { 67 | case 'p': 68 | return Util::getChar(pcIsPointingToAddress(i)); 69 | case 's': 70 | return Util::getChar(instructionIsPointingToAddress(i)); 71 | case 'r': 72 | return Util::getChar(cpu.getRegister().at(i)); 73 | case 'i': 74 | return Util::getChar(instructionHasId(i)); 75 | case 'o': 76 | return getFormattedOutput(i); 77 | } 78 | //There was an error parsing a drawing file. Problem with char cIn 79 | return ' '; 80 | } 81 | 82 | bool Renderer::pcIsPointingToAddress(int adr) { 83 | return Util::getInt(cpu.getPc()) == adr; 84 | } 85 | 86 | bool Renderer::instructionIsPointingToAddress(int adr) { 87 | // If execution did't yet start 88 | if (cpu.getCycle() == 0) { 89 | return false; 90 | } 91 | // If pc is pointing to the last addres (execution reached the end) 92 | if (Util::getInt(cpu.getPc()) == RAM_SIZE) { 93 | return false; 94 | } 95 | return Util::getInt(cpu.getAddress()) == adr; 96 | } 97 | 98 | bool Renderer::instructionHasId(int id) { 99 | // If execution did't yet start 100 | if (cpu.getCycle() == 0) { 101 | return false; 102 | } 103 | // If pc is pointing to the last addres (execution reached the end) 104 | if (Util::getInt(cpu.getPc()) == RAM_SIZE) { 105 | return false; 106 | } 107 | return Util::getInt(cpu.getInstruction()) == id; 108 | } 109 | 110 | char Renderer::getFormattedOutput(int i) { 111 | if (printer.getPrinterOutput().length() <= (unsigned) i) { 112 | return ' '; 113 | } else { 114 | return printer.getPrinterOutput().at(i); 115 | } 116 | } 117 | 118 | char Renderer::getRamAt(int j, int i) { 119 | return Util::getChar(ram.state.at(j).at(i)); 120 | } 121 | 122 | -------------------------------------------------------------------------------- /src/renderer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RENDERER_H 2 | #define RENDERER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "printer.hpp" 8 | #include "ram.hpp" 9 | #include "cpu.hpp" 10 | 11 | using namespace std; 12 | 13 | class Renderer { 14 | public: 15 | static string renderState(Printer printerIn, Ram ramIn, Cpu cpuIn); 16 | 17 | private: 18 | Renderer (Printer printerIn, Ram ramIn, Cpu cpuIn); 19 | Printer printer; 20 | Ram ram; 21 | Cpu cpu; 22 | map switchIndex; 23 | string insertActualValues(string lineIn); 24 | char getLightbulb(char cIn); 25 | bool pcIsPointingToAddress(int adr); 26 | bool instructionIsPointingToAddress(int adr); 27 | bool instructionHasId(int id); 28 | char getFormattedOutput(int i); 29 | char getRamAt(int j, int i); 30 | }; 31 | 32 | #endif -------------------------------------------------------------------------------- /src/resources/drawing: -------------------------------------------------------------------------------- 1 | RAM AD PC 2 | ADDR ________ _ _ 3 | ---- |00000000|s|p| 4 | ---* |11111111|s|p| 5 | --*- |22222222|s|p| 6 | CPU --** |33333333|s|p| PRINTER 7 | ______________ -*-- |44444444|s|p| ________________________ 8 | | | -*-* |55555555|s|p| | | 9 | | [rrrrrrrr] | -**- |66666666|s|p| (| |=============[]=| |) 10 | |______________| INST -*** |77777777|s|p| |__ _ ______________ _ __| 11 | | [i] READ | ---- *--- |88888888|s|p| | oooooooooooooooooooo | 12 | | [i] WRITE | ---* *--* |99999999|s|p| | oooooooooooooooooooo | 13 | | [i] ADD | --*- *-*- |aaaaaaaa|s|p| | oooooooooooooooooooo | 14 | | [i] SUBTRACT | --** *-** |bbbbbbbb|s|p| | oooooooooooooooooooo | 15 | | [i] JUMP | -*-- **-- |cccccccc|s|p| | oooooooooooooooooooo | 16 | | [i] IF MAX | -*-* **-* |dddddddd|s|p| | oooooooooooooooooooo | 17 | | [i] IF MIN | -**- ***- |eeeeeeee|s|p| | oooooooooooooooooooo | 18 | | [i] SHIFT R | -*** **** | OUTPUT |s|p| | oooooooooooooooooooo | 19 | ############## ############ ###################### 20 | [] [] \____________/ [] [] \_______/ [] [] 21 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "const.hpp" 14 | #include "util.hpp" 15 | #include "drawing.hpp" 16 | 17 | using namespace std; 18 | 19 | int Util::getInt(vector bbb) { 20 | int sum = 0; 21 | int power = 1; 22 | for (int i = bbb.size()-1; i >= 0; i--, power *= 2) { 23 | if (bbb[i] == true) { 24 | sum += power; 25 | } 26 | } 27 | return sum; 28 | } 29 | 30 | vector Util::getBoolByte(int num) { 31 | return getBool(num, 8); 32 | } 33 | 34 | vector Util::getBoolNibb(int num) { 35 | return getBool(num, 4); 36 | } 37 | 38 | vector Util::getBool(int num, int length) { 39 | if (num <= 0) { 40 | return vector(length, false); 41 | } 42 | if (num >= (int) pow(2, length)-1) { 43 | return vector(length, true); 44 | } 45 | vector out(length); 46 | int j = 0; 47 | for (int i = length-1; i >= 0; i--) { 48 | int divider = (int) pow(2, i); 49 | int res = num / divider; 50 | if (res > 0) { 51 | out[j++] = true; 52 | } else { 53 | out[j++] = false; 54 | } 55 | num = num % divider; 56 | } 57 | return out; 58 | } 59 | 60 | vector Util::getBoolByte(string sIn) { 61 | vector out(8); 62 | int i = 0; 63 | for (char c : sIn) { 64 | if (c == '-') { 65 | out.at(i++) = false; 66 | } else if (c == '*') { 67 | out.at(i++) = true; 68 | } else { 69 | cout << "Input Error 02 - Unrecognized char"; 70 | exit(2); 71 | } 72 | } 73 | return out; 74 | } 75 | 76 | vector Util::getFirstNibble(vector bbb) { 77 | return {bbb[0], bbb[1], bbb[2], bbb[3]}; 78 | } 79 | 80 | vector Util::getSecondNibble(vector bbb) { 81 | return {bbb[4], bbb[5], bbb[6], bbb[7]}; 82 | } 83 | 84 | string Util::getString(vector bbb) { 85 | string out = ""; 86 | for (bool b : bbb) { 87 | out += Util::getChar(b); 88 | } 89 | return out; 90 | } 91 | 92 | char Util::getChar(bool b) { 93 | if (b) { 94 | return '*'; 95 | } else { 96 | return '-'; 97 | } 98 | } 99 | 100 | vector Util::splitString(string stringIn) { 101 | vector out; 102 | stringstream stream (stringIn); 103 | string line; 104 | while (getline(stream, line)) { 105 | out.push_back(line); 106 | } 107 | return out; 108 | } 109 | 110 | string Util::makeString(vector lines) { 111 | string out; 112 | for (string line : lines) { 113 | out += line; 114 | } 115 | return out; 116 | } 117 | 118 | int Util::hexToInt(char cIn) { 119 | unsigned int out; 120 | stringstream ss; 121 | ss << cIn; 122 | ss >> std::hex >> out; 123 | return out; 124 | } 125 | 126 | string Util::getString(char cIn) { 127 | stringstream ss; 128 | string s; 129 | ss << cIn; 130 | ss >> s; 131 | return s; 132 | } 133 | 134 | vector> Util::getRamFromString(string ramString) { 135 | vector> data = vector>(RAM_SIZE, vector(WORD_SIZE)); 136 | int i = 0; 137 | for (string line : splitString(ramString)) { 138 | data[i++] = getBoolByte(line); 139 | } 140 | return data; 141 | } 142 | 143 | vector Util::getRandomWord() { 144 | vector wordOut(WORD_SIZE); 145 | for (int i = 0; i < WORD_SIZE; i++) { 146 | wordOut[i] = 0 == (rand() % 2); 147 | } 148 | return wordOut; 149 | } 150 | 151 | tuple Util::getLocationOfFirstRamLightbulb() { 152 | int i = 0; 153 | int j = 0; 154 | for (char c : drawing) { 155 | if (c == '0') { 156 | return tuple(i, j); 157 | } 158 | if (c == '\n') { 159 | i = 0; 160 | j++; 161 | } else { 162 | i++; 163 | } 164 | } 165 | printf("Could not find ram in drawing. Aborting"); 166 | exit(1); 167 | } 168 | 169 | /* 170 | * Returns the code of last pressed key, or 0 if none was pressed. 171 | */ 172 | int Util::getKey() { 173 | int c = 0; 174 | struct timeval tv = { 0L, 0L }; 175 | fd_set fds; 176 | FD_ZERO(&fds); 177 | FD_SET(STDIN_FILENO, &fds); 178 | select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); 179 | 180 | if (FD_ISSET(STDIN_FILENO, &fds)) { 181 | c = getchar(); 182 | } 183 | return c; 184 | } 185 | 186 | bool Util::fileExists(string filename) { 187 | struct stat buf; 188 | if (stat(filename.c_str(), &buf) != -1) { 189 | return true; 190 | } 191 | return false; 192 | } 193 | -------------------------------------------------------------------------------- /src/util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Util { 10 | public: 11 | static int getInt(vector bbb); 12 | static vector getBoolByte(int num); 13 | static vector getBoolNibb(int num); 14 | static vector getBoolByte(string sIn); 15 | static vector getFirstNibble(vector bbb); 16 | static vector getSecondNibble(vector bbb); 17 | static string getString(vector bbb); 18 | static vector splitString(string stringIn); 19 | static string makeString(vector lines); 20 | static int hexToInt(char cIn); 21 | static string getString(char cIn); 22 | static char getChar(bool b); 23 | static vector> getRamFromString(string ramString); 24 | static vector getRandomWord(); 25 | static tuple getLocationOfFirstRamLightbulb(); 26 | static int getKey(); 27 | static bool fileExists(string filename); 28 | 29 | private: 30 | static vector getBool(int num, int length); 31 | }; 32 | 33 | #endif --------------------------------------------------------------------------------