aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine/programmemory.cpp
diff options
context:
space:
mode:
authorKarel Kočí <cynerd@email.cz>2017-08-30 21:37:53 +0200
committerKarel Kočí <cynerd@email.cz>2017-08-30 21:42:02 +0200
commit9cf92379d5fcf0076c25dae0935daab446c992cd (patch)
treedd09a2e996db1e5a8117f01bec76f1e93eaca6e1 /qtmips_machine/programmemory.cpp
downloadqtmips-9cf92379d5fcf0076c25dae0935daab446c992cd.tar.gz
qtmips-9cf92379d5fcf0076c25dae0935daab446c992cd.tar.bz2
qtmips-9cf92379d5fcf0076c25dae0935daab446c992cd.zip
Initial commit
Adding work done so far.
Diffstat (limited to 'qtmips_machine/programmemory.cpp')
-rw-r--r--qtmips_machine/programmemory.cpp111
1 files changed, 111 insertions, 0 deletions
diff --git a/qtmips_machine/programmemory.cpp b/qtmips_machine/programmemory.cpp
new file mode 100644
index 0000000..c5ef53a
--- /dev/null
+++ b/qtmips_machine/programmemory.cpp
@@ -0,0 +1,111 @@
+#include "programmemory.h"
+#include <sstream>
+#include "qtmipsexception.h"
+#include "instructions/arithmetic.h"
+#include "instructions/loadstore.h"
+#include "instructions/nop.h"
+#include "instructions/shift.h"
+
+ProgramMemory::ProgramMemory(ProgramLoader *loader, MemoryAccess *memory) {
+ this->memory = memory;
+ // Load program to memory (just dump it byte by byte, decode is done on demand)
+ for (int i = 0; i < loader->get_nsec(); i++) {
+ std::uint32_t base_address = loader->get_address(i);
+ std::vector<std::uint8_t> data = loader->get_data(i);
+ for (auto it = data.begin(); it < data.end(); it++) {
+ memory->write_byte(base_address + i, *it);
+ }
+ }
+}
+
+#define MASKSUB(VAR, LEN, OFFSET) ((VAR & ~((1 << (LEN+OFFSET+1)) - 1)) >> OFFSET)
+
+Instruction *ProgramMemory::at(std::uint32_t address) {
+ if (address % 4)
+ // TODO different exception (unaligned address)
+ throw std::exception();
+ // Read instruction from memory
+ std::uint32_t dt = this->memory->read_word(address);
+
+ // Decode instruction
+ Instruction *inst;
+ std::uint8_t opcode = dt >> 26; // upper 6 bits
+ if (opcode == 0) { // Arithmetic and shift instructions
+ return this->decode_r(dt);
+ } else if (opcode == 2 || opcode == 3) { // Jump instructions
+ return decode_j(dt);
+ } else {
+ return decode_i(dt);
+ }
+}
+
+// TODO implement
+#define I_UNKNOWN(DATA) do { std::stringstream ss; ss << std::hex << DATA; throw QTMIPS_EXCEPTION(UnsupportedInstruction, "Unknown instruction, can't decode", ss.str()); } while(false);
+#define I_UNSUPPORTED(INST) throw QTMIPS_EXCEPTION(UnsupportedInstruction, "Decoded unsupported unstruction", #INST)
+
+Instruction *ProgramMemory::decode_r(std::uint32_t dt) {
+ std::uint8_t func = MASKSUB(dt, 6, 0);
+ if (!func)
+ return new InstructionNop();
+
+ std::uint8_t rs, rt, rd, sa;
+ rs = MASKSUB(dt, 5, 21);
+ rt = MASKSUB(dt, 5, 16);
+ rd = MASKSUB(dt, 5, 11);
+ sa = MASKSUB(dt, 5, 6);
+
+ if (func < 8) { // Shift instructions
+ bool variable = false;
+ enum InstructionShiftT t;
+ switch (func) {
+ case 0:
+ t = IST_LL;
+ break;
+ case 2:
+ t = IST_RL;
+ break;
+ case 3:
+ t = IST_RA;
+ break;
+ case 4:
+ t = IST_LL;
+ variable = true;
+ break;
+ case 6:
+ t = IST_RL;
+ variable = true;
+ break;
+ case 7:
+ t = IST_RA;
+ variable = true;
+ break;
+ default:
+ I_UNKNOWN(dt);
+ }
+ if (variable)
+ return new InstructionShiftVariable(t, rs, rt, rd);
+ else
+ return new InstructionShift(t, rt, rd, sa);
+ } else if (func < 10) { // Jump instructions
+ // TODO
+ I_UNKNOWN(dt);
+ } else { // TODO filter rest
+ I_UNKNOWN(dt);
+ }
+}
+
+Instruction *ProgramMemory::decode_j(std::uint32_t dt) {
+ std::uint32_t address = MASKSUB(dt, 26, 0);
+ // TODO
+ I_UNKNOWN(dt);
+}
+
+Instruction *ProgramMemory::decode_i(std::uint32_t dt) {
+ // InstructionI
+ std::uint8_t rs, rt;
+ rs = MASKSUB(dt, 5, 21);
+ rt = MASKSUB(dt, 5, 16);
+ std::uint16_t immediate = MASKSUB(dt, 16, 0);
+ // TODO
+ I_UNKNOWN(dt);
+}