aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine
diff options
context:
space:
mode:
Diffstat (limited to 'qtmips_machine')
-rw-r--r--qtmips_machine/alu.cpp51
-rw-r--r--qtmips_machine/alu.h38
-rw-r--r--qtmips_machine/core.cpp161
-rw-r--r--qtmips_machine/core.h62
-rw-r--r--qtmips_machine/instruction.cpp148
-rw-r--r--qtmips_machine/instruction.h66
-rw-r--r--qtmips_machine/instructions/arithmetic.cpp174
-rw-r--r--qtmips_machine/instructions/arithmetic.h60
-rw-r--r--qtmips_machine/instructions/jumpbranch.cpp30
-rw-r--r--qtmips_machine/instructions/jumpbranch.h34
-rw-r--r--qtmips_machine/instructions/loadstore.cpp67
-rw-r--r--qtmips_machine/instructions/loadstore.h32
-rw-r--r--qtmips_machine/instructions/nop.cpp7
-rw-r--r--qtmips_machine/instructions/nop.h11
-rw-r--r--qtmips_machine/instructions/shift.cpp51
-rw-r--r--qtmips_machine/instructions/shift.h28
-rw-r--r--qtmips_machine/machineconfig.cpp43
-rw-r--r--qtmips_machine/machineconfig.h35
-rw-r--r--qtmips_machine/programloader.cpp41
-rw-r--r--qtmips_machine/programloader.h10
-rw-r--r--qtmips_machine/programmemory.h23
-rw-r--r--qtmips_machine/qtmips_machine.pro15
-rw-r--r--qtmips_machine/qtmipsexception.cpp12
-rw-r--r--qtmips_machine/qtmipsexception.h14
-rw-r--r--qtmips_machine/qtmipsmachine.cpp69
-rw-r--r--qtmips_machine/qtmipsmachine.h35
-rw-r--r--qtmips_machine/registers.cpp29
-rw-r--r--qtmips_machine/registers.h10
-rw-r--r--qtmips_machine/tests/testalu.cpp91
-rw-r--r--qtmips_machine/tests/testcore.cpp35
-rw-r--r--qtmips_machine/tests/testinstruction.cpp25
-rw-r--r--qtmips_machine/tests/testmemory.cpp58
-rw-r--r--qtmips_machine/tests/testprogramloader.cpp20
-rw-r--r--qtmips_machine/tests/tests.pro6
-rw-r--r--qtmips_machine/tests/tst_machine.h21
35 files changed, 872 insertions, 740 deletions
diff --git a/qtmips_machine/alu.cpp b/qtmips_machine/alu.cpp
index 5c74a5d..85bc804 100644
--- a/qtmips_machine/alu.cpp
+++ b/qtmips_machine/alu.cpp
@@ -1,6 +1,53 @@
#include "alu.h"
+#include "qtmipsexception.h"
-Alu::Alu()
-{
+std::uint32_t alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa) {
+ switch(operation) {
+ case ALU_OP_SLL:
+ return t << sa;
+ case ALU_OP_SRL:
+ return t >> sa;
+ case ALU_OP_SRA:
+ // TODO is this correct implementation? (Shouldn't we be masking top most bit?)
+ return (t >> sa) | (t & 0x80000000);
+ case ALU_OP_SLLV:
+ return t << s;
+ case ALU_OP_SRLV:
+ return t >> s;
+ case ALU_OP_SRAV:
+ // TODO is this correct implementation? (Shouldn't we be masking top most bit?)
+ return (t >> s) | (t & 0x80000000);
+ case ALU_OP_ADD:
+ if (s > (0xFFFFFFFF - t))
+ throw QTMIPS_EXCEPTION(Overflow, "ADD operation overflow/underflow", QString::number(s) + QString(" + ") + QString::number(t));
+ // Intentional falltrough
+ case ALU_OP_ADDU:
+ return s + t;
+ case ALU_OP_SUB:
+ if (s < t)
+ throw QTMIPS_EXCEPTION(Overflow, "SUB operation overflow/underflow", QString::number(s) + QString(" - ") + QString::number(t));
+ // Intentional falltrough
+ case ALU_OP_SUBU:
+ return s - t;
+ case ALU_OP_AND:
+ return s & t;
+ case ALU_OP_OR:
+ return s | t;
+ case ALU_OP_XOR:
+ return s ^ t;
+ case ALU_OP_NOR:
+ return ~(s | t);
+ case ALU_OP_SLTU:
+ // TODO is this correct implementation? (this is two's complement signed representation so do we care?)
+ // Intentional falltrough
+ case ALU_OP_SLT:
+ return (s < t) ? 1 : 0;
+ default:
+ throw QTMIPS_EXCEPTION(UnsupportedAluOperation, "Unknown ALU operation", QString::number(operation, 16));
+ }
+}
+QString alu_str(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa) {
+ // TODO
+ return QString("");
}
diff --git a/qtmips_machine/alu.h b/qtmips_machine/alu.h
index e913b0c..974b462 100644
--- a/qtmips_machine/alu.h
+++ b/qtmips_machine/alu.h
@@ -1,11 +1,39 @@
#ifndef ALU_H
#define ALU_H
+#include <cstdint>
+#include <QString>
-class Alu
-{
-public:
- Alu();
+// TODO Any other operations? We seems to be missing a lot of them.
+enum AluOp : std::uint8_t {
+ ALU_OP_SLL = 0,
+ ALU_OP_SRL = 2,
+ ALU_OP_SRA,
+ ALU_OP_SLLV,
+ ALU_OP_SRLV = 6,
+ ALU_OP_SRAV,
+ ALU_OP_ADD = 32,
+ ALU_OP_ADDU,
+ ALU_OP_SUB,
+ ALU_OP_SUBU,
+ ALU_OP_AND,
+ ALU_OP_OR,
+ ALU_OP_XOR,
+ ALU_OP_NOR,
+ ALU_OP_SLT = 42,
+ ALU_OP_SLTU,
+ ALU_OP_LAST = 64 // First impossible operation (just to be sure that we don't overflow)
};
-#endif // ALU_H \ No newline at end of file
+// Do ALU operation.
+// operation: This is function field from instruction or shifted opcode for immediate instructions
+// s: Loaded from rs. Also calles as source.
+// t: Loaded from rt or immediate field from instruction it self. Also called as target.
+// sa: This is value directly from instruction it self (sa section) used for shift operations
+// Returned value is commonly saved to rt/rd or any other way passed trough core
+std::uint32_t alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa);
+
+// Returns string representation of ALU instruction (internally used by Instruction::to_str)
+QString alu_str(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa);
+
+#endif // ALU_H
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp
index a6c92b5..1edcc97 100644
--- a/qtmips_machine/core.cpp
+++ b/qtmips_machine/core.cpp
@@ -1,5 +1,164 @@
#include "core.h"
+#include "programloader.h"
-Core::Core() {
+ struct DecodeMap {
+ bool supported, mem2reg, memwrite, alubimm, regd, regwrite, branch;
+};
+
+// This is temporally operation place holder
+#define NOPE { .supported = false }
+
+// This is map from opcode to signals.
+static const struct DecodeMap dmap[] = {
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = false, .regwrite = true, .branch = false }, // Alu operations and more
+ // TODO These are just copies of first one
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = false, .regwrite = false, .branch = true }, // Branch on alu operations
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // J
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // JAL
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BEQ
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BNE
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BLEZ
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BGTZ
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ADDI
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ADDIU
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SLTI
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SLTIU
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ANDI
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ORI
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // XORI
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LUI
+ NOPE, // 16
+ NOPE, // 17
+ NOPE, // 18
+ NOPE, // 19
+ NOPE, // 20
+ NOPE, // 21
+ NOPE, // 22
+ NOPE, // 23
+ NOPE, // 24
+ NOPE, // 25
+ NOPE, // 26
+ NOPE, // 27
+ NOPE, // 28
+ NOPE, // 29
+ NOPE, // 30
+ NOPE, // 31
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LB
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LH
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LWL
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LW
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LBU
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LHU
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LWR
+ NOPE, // 39
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SB
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SH
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SWL
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SW
+ NOPE, // 44
+ NOPE, // 45
+ { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SWR
+ NOPE, // 47
+ NOPE, // 48
+ NOPE, // 49
+ NOPE, // 50
+ NOPE, // 51
+ NOPE, // 52
+ NOPE, // 53
+ NOPE, // 54
+ NOPE, // 55
+ NOPE, // 56
+ NOPE, // 57
+ NOPE, // 58
+ NOPE, // 59
+ NOPE, // 60
+ NOPE, // 61
+ NOPE, // 62
+ NOPE // 63
+};
+
+Core::Core(Registers *regs, MemoryAccess *mem) {
+ this->regs = regs;
+ this->mem = mem;
+}
+
+struct Core::dtFetch Core::fetch() {
+ // TODO signals
+ Instruction inst(mem->read_word(regs->read_pc()));
+ regs->pc_inc();
+ return {
+ .inst = inst
+ };
+}
+
+struct Core::dtDecode Core::decode(struct dtFetch dt) {
+ struct DecodeMap dec = dmap[dt.inst.opcode()];
+ if (!dec.supported)
+ // TODO message
+ throw QTMIPS_EXCEPTION(UnsupportedInstruction, "", "");
+ enum AluOp d_alu = ALU_OP_SLL; // TODO decode for real
+ return {
+ .mem2reg = dec.mem2reg,
+ .memwrite = dec.memwrite,
+ .alubimm = dec.alubimm,
+ .regd = dec.regd,
+ .regwrite = dec.regwrite,
+ .branch = dec.branch,
+ .aluop = d_alu,
+ .val_rs = regs->read_gp(dt.inst.rs()),
+ .val_rt = regs->read_gp(dt.inst.rt()),
+ .val_sa = dt.inst.shamt(),
+ .val_immediate = dt.inst.immediate(),
+ };
+ // TODO on jump there should be delay slot. Does processor addes it or compiler. And do we care?
+}
+
+struct Core::dtExecute Core::execute(struct dtDecode dt) {
+ // TODO signals
+ return {
+ .mem2reg = dt.mem2reg,
+ .val = alu_operate(dt.aluop, dt.val_rs, dt.val_rt, dt.val_sa)
+ };
+}
+
+struct Core::dtMemory Core::memory(struct dtExecute dt) {
+ // TODO signals
+ return {
+ .mem2reg = dt.mem2reg,
+ .val = dt.val,
+ };
+}
+
+void Core::writeback(struct dtMemory dt) {
+ if (dt.mem2reg) {
+
+ }
+}
+
+CoreSingle::CoreSingle(Registers *regs, MemoryAccess *mem) : \
+ Core(regs, mem) {
+ // Nothing to do
+}
+
+void CoreSingle::step() {
+ struct dtFetch f = fetch();
+ struct dtDecode d = decode(f);
+ struct dtExecute e = execute(d);
+ struct dtMemory m = memory(e);
+ writeback(m);
+}
+
+CorePipelined::CorePipelined(Registers *regs, MemoryAccess *mem) : \
+ Core(regs, mem) {
+ // Nothing to do
+}
+
+void CorePipelined::step() {
+ // TODO implement pipelined
+ struct dtFetch f = fetch();
+ struct dtDecode d = decode(f);
+ struct dtExecute e = execute(d);
+ struct dtMemory m =memory(e);
+ writeback(m);
}
diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h
index 2fd0a40..d4523c3 100644
--- a/qtmips_machine/core.h
+++ b/qtmips_machine/core.h
@@ -2,20 +2,72 @@
#define CORE_H
#include <QObject>
-#include "instruction.h"
+#include "qtmipsexception.h"
#include "registers.h"
#include "memory.h"
-#include "programloader.h"
-#include "programmemory.h"
+#include "instruction.h"
+#include "alu.h"
class Core : public QObject {
Q_OBJECT
public:
- Core();
+ Core(Registers *regs, MemoryAccess *mem);
+
+ virtual void step() = 0; // Do single step
signals:
-public slots:
+protected:
+ Registers *regs;
+ MemoryAccess *mem;
+
+ struct dtFetch {
+ Instruction inst; // Loaded instruction
+ };
+ struct dtDecode {
+ bool mem2reg; // Write memory output to register (instead alu output)
+ bool memwrite; // If memory should write input
+ bool alubimm; // If b value to alu is immediate value (rt used otherwise)
+ bool regd; // If rd is used (otherwise rt is used for write target)
+ bool regwrite; // If output should be written back to register (which one depends on regd)
+ bool branch; // If this is branch instruction
+ enum AluOp aluop; // Decoded ALU operation
+ std::uint32_t val_rs; // Value from register rs
+ std::uint32_t val_rt; // Value from register rt
+ std::uint8_t val_sa; // Value of sa in instruction it self
+ std::uint16_t val_immediate; // Value of immediate in instruction it self
+ };
+ struct dtExecute {
+ bool mem2reg;
+ std::uint32_t val;
+ // TODO
+ };
+ struct dtMemory {
+ bool mem2reg;
+ // TODO
+ std::uint32_t val;
+ };
+
+ struct dtFetch fetch();
+ struct dtDecode decode(struct dtFetch);
+ struct dtExecute execute(struct dtDecode);
+ struct dtMemory memory(struct dtExecute);
+ void writeback(struct dtMemory);
+
+};
+
+class CoreSingle : public Core {
+public:
+ CoreSingle(Registers *regs, MemoryAccess *mem);
+
+ void step();
+};
+
+class CorePipelined : public Core {
+public:
+ CorePipelined(Registers *regs, MemoryAccess *mem);
+
+ void step();
};
#endif // CORE_H
diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp
index 1771afb..8591d93 100644
--- a/qtmips_machine/instruction.cpp
+++ b/qtmips_machine/instruction.cpp
@@ -1,102 +1,106 @@
#include "instruction.h"
#include "qtmipsexception.h"
-Instruction::Instruction() {
- this->st = IS_FETCH;
+struct InstructionMap {
+ const char *name;
+};
+
+#define IM_UNKNOWN {"UNKNOWN"}
+const struct InstructionMap instruction_map[] = {
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ {"ADDI"},
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN
+};
+
+Instruction::Instruction(std::uint32_t inst) {
+ this->dt = inst;
+}
+
+Instruction::Instruction(std::uint8_t opcode, std::uint8_t rs, std::uint8_t rt, std::uint8_t rd, std::uint8_t shamt, std::uint8_t funct) {
+ this->dt = 0;
+ this->dt |= opcode << 26;
+ this->dt |= rs << 21;
+ this->dt |= rt << 16;
+ this->dt |= rd << 11;
+ this->dt |= shamt << 6;
+ this->dt |= funct;
}
-void Instruction::decode(Registers *regs) {
- if (this->st != IS_FETCH)
- // TODO other exception
- throw std::exception();
- this->st = IS_DECODE;
+Instruction::Instruction(std::uint8_t opcode, std::uint8_t rs, std::uint8_t rt, std::uint16_t immediate) {
+ this->dt = 0;
+ this->dt |= opcode << 26;
+ this->dt |= rs << 21;
+ this->dt |= rt << 16;
+ this->dt |= immediate;
}
-void Instruction::execute() {
- if (this->st != IS_DECODE)
- // TODO other exception
- throw std::exception();
- this->st = IS_EXECUTE;
+Instruction::Instruction(std::uint8_t opcode, std::uint32_t address) {
+ this->dt = 0;
+ this->dt |= opcode << 26;
+ this->dt |= address;
}
-void Instruction::memory(Memory *mem) {
- if (this->st != IS_EXECUTE)
- // TODO other exception
- throw std::exception();
- this->st = IS_MEMORY;
+QString Instruction::to_str() {
+ if (this->opcode() >= sizeof(instruction_map))
+ return QString("UNKNOWN");
+ return QString(instruction_map[this->opcode()].name);
}
-void Instruction::write_back(Registers *regs) {
- if (this->st != IS_MEMORY)
- // TODO other exception
- throw std::exception();
- this->st = IS_WRITE_BACK;
+#define MASK(LEN,OFF) ((this->dt >> (OFF)) & ((1 << (LEN)) - 1))
+
+std::uint8_t Instruction::opcode() const {
+ return (std::uint8_t) MASK(6, 26);
}
-enum InstructionState Instruction::state() {
- return this->st;
+std::uint8_t Instruction::rs() const {
+ return (std::uint8_t) MASK(5, 21);
}
-bool Instruction::running() {
- return this->st > IS_FETCH && this->st < IS_WRITE_BACK;
+std::uint8_t Instruction::rt() const {
+ return (std::uint8_t) MASK(5, 16);
}
-bool Instruction::done() {
- return this->st >= IS_WRITE_BACK;
+std::uint8_t Instruction::rd() const {
+ return (std::uint8_t) MASK(5, 11);
}
-InstructionR::InstructionR(std::uint8_t rs, std::uint8_t rd, std::uint8_t rt, std::uint8_t sa) : Instruction() {
- this->rs = rs;
- this->rd = rd;
- this->rt = rt;
- this->sa = sa;
+std::uint8_t Instruction::shamt() const {
+ return (std::uint8_t) MASK(5, 6);
+
}
-// TODO for registers output as register ($0)!
-
-QVector<QString> InstructionR::to_strs() {
- QVector<QString> str;
- // Instruction name
- str << "unknown"; // unknown instruction, should be replaced by child
- // Source register
- str << QString::number((unsigned)this->rs, 10);
- // Target register
- str << QString::number((unsigned)this->rt, 10);
- // Destination register
- str << QString::number((unsigned)this->rd, 10);
- // Shift amount
- str << QString::number((unsigned)this->sa, 10);
- return str;
+std::uint8_t Instruction::funct() const {
+ return (std::uint8_t) MASK(6, 0);
}
-InstructionI::InstructionI(std::uint8_t rs, std::uint8_t rt, std::uint16_t immediate) : Instruction() {
- this->rs = rs;
- this->rt = rt;
- this->immediate = immediate;
+std::uint16_t Instruction::immediate() const {
+ return (std::uint16_t) MASK(16, 0);
}
-QVector<QString> InstructionI::to_strs() {
- QVector<QString> str;
- // Instruction name
- str << "unknown"; // unknown instruction, should be replaced by child
- // Source register
- str << QString::number((unsigned)this->rs, 10);
- // Target register
- str << QString::number((unsigned)this->rt, 10);
- // Immediate value
- str << QString::number((unsigned)this->immediate, 16);
- return str;
+std::uint32_t Instruction::address() const {
+ return (std::uint32_t) MASK(26, 0);
}
-InstructionJ::InstructionJ(std::uint32_t address) : Instruction() {
- this->address = address;
+std::uint32_t Instruction::data() const {
+ return this->dt;
}
-QVector<QString> InstructionJ::to_strs() {
- QVector<QString> str;
- // Instruction name
- str << "unknown"; // unknown instruction, should be replaced by child
- // Source register
- str << QString::number((unsigned)this->address, 16);
- return str;
+bool Instruction::operator ==(const Instruction &c) const {
+ return (this->data() == c.data());
}
diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h
index 8c5ede9..3b76fba 100644
--- a/qtmips_machine/instruction.h
+++ b/qtmips_machine/instruction.h
@@ -2,64 +2,30 @@
#define INSTRUCTION_H
#include <qstring.h>
-#include <qvector.h>
-#include "registers.h"
-#include "memory.h"
-
-enum InstructionState {
- IS_FETCH,
- IS_DECODE,
- IS_EXECUTE,
- IS_MEMORY,
- IS_WRITE_BACK,
-};
class Instruction {
public:
- Instruction();
+ Instruction(std::uint32_t inst);
+ Instruction(std::uint8_t opcode, std::uint8_t rs, std::uint8_t rt, std::uint8_t rd, std::uint8_t shamt, std::uint8_t funct); // Type R
+ Instruction(std::uint8_t opcode, std::uint8_t rs, std::uint8_t rt, std::uint16_t immediate); // Type I
+ Instruction(std::uint8_t opcode, std::uint32_t address); // Type J
- // TODO return some info for forwarding, stall, flush
- virtual void decode(Registers *regs); // Read and prepare instructions
- virtual void execute(); // ALU operations
- virtual void memory(Memory *mem); // Read or write to memory
- virtual void write_back(Registers *regs); // Write results to registers
+ QString to_str();
- enum InstructionState state();
- bool running();
- bool done();
+ std::uint8_t opcode() const;
+ std::uint8_t rs() const;
+ std::uint8_t rt() const;
+ std::uint8_t rd() const;
+ std::uint8_t shamt() const;
+ std::uint8_t funct() const;
+ std::uint16_t immediate() const;
+ std::uint32_t address() const;
+ std::uint32_t data() const;
- virtual QVector<QString> to_strs() = 0; // Returns all fields of instructions in string
+ bool operator ==(const Instruction &c) const;
private:
- enum InstructionState st;
-};
-
-class InstructionR : public Instruction {
-public:
- InstructionR(std::uint8_t rs, std::uint8_t rd, std::uint8_t rt, std::uint8_t sa);
-
- QVector<QString> to_strs();
-protected:
- std::uint8_t rs, rd, rt, sa;
-};
-
-class InstructionI : public Instruction {
-public:
- InstructionI(std::uint8_t rs, std::uint8_t rt, std::uint16_t immediate);
-
- QVector<QString> to_strs();
-protected:
- std::uint8_t rs, rt;
- std::uint16_t immediate;
-};
-
-class InstructionJ : public Instruction {
-public:
- InstructionJ(std::uint32_t address);
-
- QVector<QString> to_strs();
-protected:
- std::uint32_t address;
+ std::uint32_t dt;
};
#endif // INSTRUCTION_H
diff --git a/qtmips_machine/instructions/arithmetic.cpp b/qtmips_machine/instructions/arithmetic.cpp
deleted file mode 100644
index f3cad86..0000000
--- a/qtmips_machine/instructions/arithmetic.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "instructions/arithmetic.h"
-
-InstructionArithmetic::InstructionArithmetic(enum InstructionArithmeticT type, std::uint8_t rs, std::uint8_t rd, std::uint8_t rt)
- : InstructionR(rs, rd, rt, 0) {
- this->type = type;
-}
-
-void InstructionArithmetic::decode(Registers *regs) {
- Instruction::decode(regs);
- this->rs_d = regs->read_gp(this->rs);
- this->rd_d = regs->read_gp(this->rd);
-}
-
-void InstructionArithmetic::execute() {
- Instruction::execute();
- switch (this->type) {
- case IAT_ADD:
- this->rt_d = (std::uint32_t)((std::int32_t)this->rs_d + (std::int32_t)this->rd_d);
- break;
- case IAT_ADDU:
- this->rt_d = this->rs_d + this->rd_d;
- break;
- case IAT_SUB:
- this->rt_d = (std::uint32_t)((std::int32_t)this->rs_d - (std::int32_t)this->rd_d);
- break;
- case IAT_SUBU:
- this->rt_d = this->rs_d - this->rd_d;
- break;
- case IAT_AND:
- this->rt_d = this->rs_d & this->rd_d;
- break;
- case IAT_OR:
- this->rt_d = this->rs_d | this->rd_d;
- break;
- case IAT_XOR:
- this->rt_d = this->rs_d ^ this->rd_d;
- break;
- case IAT_NOR:
- // TODO
- break;
- case IAT_SLT:
- // TODO
- break;
- case IAT_SLTU:
- // TODO
- break;
- }
-}
-
-void InstructionArithmetic::memory(Memory *mem) {
- Instruction::memory(mem);
- // pass
-}
-
-void InstructionArithmetic::write_back(Registers *regs) {
- Instruction::write_back(regs);
- regs->write_gp(this->rt, this->rt_d);
-}
-
-QVector<QString> InstructionArithmetic::to_strs() {
- QVector<QString> str = this->InstructionR::to_strs();
- str.erase(str.begin() + 4); // Drop sa field
- switch (this->type) {
- case IAT_ADD:
- str[0] = "add";
- break;
- case IAT_ADDU:
- str[0] = "addu";
- break;
- case IAT_SUB:
- str[0] = "sub";
- break;
- case IAT_SUBU:
- str[0] = "subu";
- break;
- case IAT_AND:
- str[0] = "and";
- break;
- case IAT_OR:
- str[0] = "or";
- break;
- case IAT_XOR:
- str[0] = "xor";
- break;
- case IAT_NOR:
- str[0] = "nor";
- break;
- case IAT_SLT:
- str[0] = "slt";
- break;
- case IAT_SLTU:
- str[0] = "sltu";
- break;
- default:
- // TODO different exception
- throw std::exception();
- }
- return str;
-}
-
-InstructionArithmeticImmediate::InstructionArithmeticImmediate(enum InstructionArithmeticImmediateT type, std::uint8_t rs, std::uint8_t rt, std::uint16_t value)
- : InstructionI(rs, rt, value) {
- this->type = type;
-}
-
-void InstructionArithmeticImmediate::decode(Registers *regs) {
- Instruction::decode(regs);
- this->rs_d = regs->read_gp(this->rs);
-}
-
-void InstructionArithmeticImmediate::execute() {
- Instruction::execute();
- switch (this->type) {
- case IAT_ADDI:
- this->rt_d = (std::uint32_t)((std::int32_t)this->rs_d + (std::int32_t)this->immediate);
- break;
- case IAT_ADDIU:
- this->rt_d = this->rs_d + this->immediate;
- break;
- case IAT_ANDI:
- this->rt_d = (std::uint32_t)((std::int32_t)this->rs_d - (std::int32_t)this->immediate);
- break;
- case IAT_ORI:
- this->rt_d = this->rs_d - this->immediate;
- break;
- case IAT_XORI:
- this->rt_d = this->rs_d & this->immediate;
- break;
- }
-}
-
-void InstructionArithmeticImmediate::memory(Memory *mem) {
- Instruction::memory(mem);
- // pass
-}
-
-void InstructionArithmeticImmediate::write_back(Registers *regs) {
- Instruction::write_back(regs);
- regs->write_gp(this->rt, this->rt_d);
-}
-
-QVector<QString> InstructionArithmeticImmediate::to_strs() {
- QVector<QString> str = this->InstructionI::to_strs();
- switch (this->type) {
- case IAT_ADDI:
- str[0] = "addi";
- break;
- case IAT_ADDIU:
- str[0] = "addiu";
- break;
- case IAT_ANDI:
- str[0] = "andi";
- break;
- case IAT_ORI:
- str[0] = "ori";
- break;
- case IAT_XORI:
- str[0] = "xori";
- break;
- case IAT_SLTI:
- str[0] = "slti";
- break;
- case IAT_SLTIU:
- str[0] = "sltiu";
- break;
- case IAT_LUI:
- str[0] = "lui";
- break;
- default:
- // TODO different exception
- throw std::exception();
- }
- return str;
-}
diff --git a/qtmips_machine/instructions/arithmetic.h b/qtmips_machine/instructions/arithmetic.h
deleted file mode 100644
index 185ed95..0000000
--- a/qtmips_machine/instructions/arithmetic.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef ARITHMETIC_H
-#define ARITHMETIC_H
-
-#include "instruction.h"
-
-enum InstructionArithmeticT {
- IAT_ADD, // Add
- IAT_ADDU, // Add unsigned
- IAT_SUB, // Subtract
- IAT_SUBU, // Subtract unsigned
- IAT_AND,
- IAT_OR,
- IAT_XOR,
- IAT_NOR,
- IAT_SLT, // set on less than
- IAT_SLTU, // set on less than unsigned
-};
-
-class InstructionArithmetic : public InstructionR {
-public:
- InstructionArithmetic(enum InstructionArithmeticT type, std::uint8_t rs, std::uint8_t rd, std::uint8_t rt);
-
- void decode(Registers *regs);
- void execute();
- void memory(Memory *mem);
- void write_back(Registers *regs);
-
- QVector<QString> to_strs();
-private:
- enum InstructionArithmeticT type;
- std::uint32_t rs_d, rd_d, rt_d;
-};
-
-enum InstructionArithmeticImmediateT {
- IAT_ADDI,
- IAT_ADDIU,
- IAT_ANDI,
- IAT_ORI,
- IAT_XORI,
- IAT_SLTI,
- IAT_SLTIU,
- IAT_LUI
-};
-
-class InstructionArithmeticImmediate : public InstructionI {
-public:
- InstructionArithmeticImmediate(enum InstructionArithmeticImmediateT type, std::uint8_t rs, std::uint8_t rt, std::uint16_t value);
-
- void decode(Registers *regs);
- void execute();
- void memory(Memory *mem);
- void write_back(Registers *regs);
-
- QVector<QString> to_strs();
-private:
- enum InstructionArithmeticImmediateT type;
- std::uint32_t rs_d, rt_d;
-};
-
-#endif // ARITHMETIC_H
diff --git a/qtmips_machine/instructions/jumpbranch.cpp b/qtmips_machine/instructions/jumpbranch.cpp
deleted file mode 100644
index 6579c2b..0000000
--- a/qtmips_machine/instructions/jumpbranch.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "jumpbranch.h"
-
-InstructionJump::InstructionJump(bool link, std::uint32_t address)
- : InstructionJ(address) {
- this->link = link;
-}
-
-QVector<QString> InstructionJump::to_strs() {
- QVector<QString> str = this->InstructionJ::to_strs();
- if (link)
- str[0] = "j";
- else
- str[0] = "jal";
- return str;
-}
-
-InstructionJumpRegister::InstructionJumpRegister(bool link, std::uint8_t rs)
- : InstructionR(rs, 0, 0, 0) {
- this->link = link;
-}
-
-QVector<QString> InstructionJumpRegister::to_strs() {
- QVector<QString> str = this->InstructionR::to_strs();
- str.erase(str.begin() + 2, str.end()); // Drop every field after rs
- if (link)
- str[0] = "j";
- else
- str[0] = "jal";
- return str;
-}
diff --git a/qtmips_machine/instructions/jumpbranch.h b/qtmips_machine/instructions/jumpbranch.h
deleted file mode 100644
index 762ad95..0000000
--- a/qtmips_machine/instructions/jumpbranch.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef JUMPBRANCH_H
-#define JUMPBRANCH_H
-
-#include "instruction.h"
-
-class InstructionJump : InstructionJ {
-public:
- InstructionJump(bool link, std::uint32_t address);
- QVector<QString> to_strs();
-private:
- bool link;
-};
-
-class InstructionJumpRegister : InstructionR {
-public:
- InstructionJumpRegister(bool link, std::uint8_t rs);
- QVector<QString> to_strs();
-private:
- bool link;
-};
-
-enum InstructionBranchT {
-
-};
-
-class InstructionBranch : InstructionI {
-public:
- InstructionBranch();
- QVector<QString> to_strs();
-private:
- // TODO
-};
-
-#endif // JUMPBRANCH_H
diff --git a/qtmips_machine/instructions/loadstore.cpp b/qtmips_machine/instructions/loadstore.cpp
deleted file mode 100644
index 27c6402..0000000
--- a/qtmips_machine/instructions/loadstore.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "loadstore.h"
-
-InstructionLoad::InstructionLoad(enum InstructionLoadStoreT type, std::uint8_t rs, std::uint8_t rt, std::uint16_t offset)
- : InstructionI(rs, rt, offset) {
- this->type = type;
-}
-
-QVector<QString> InstructionLoad::to_strs() {
- QVector<QString> str = this->InstructionI::to_strs();
- switch (this->type) {
- case ILST_B:
- str[0] = "lb";
- break;
- case ILST_HW:
- str[0] = "lh";
- break;
- case ILST_WL:
- str[0] = "lwl";
- break;
- case ILST_W:
- str[0] = "lw";
- break;
- case ILST_BU:
- str[0] = "lbu";
- break;
- case ILST_HU:
- str[0] = "lhu";
- break;
- case ILST_WR:
- str[0] = "lwr";
- break;
- default:
- // TODO different exception
- throw std::exception();
- }
- return str;
-}
-
-InstructionStore::InstructionStore(enum InstructionLoadStoreT type, std::uint8_t rs, std::uint8_t rt, std::uint16_t offset)
- : InstructionI(rs, rt, offset) {
- this->type = type;
-}
-
-QVector<QString> InstructionStore::to_strs() {
- QVector<QString> str = this->InstructionI::to_strs();
- switch (this->type) {
- case ILST_B:
- str[0] = "sb";
- break;
- case ILST_HW:
- str[0] = "sh";
- break;
- case ILST_WL:
- str[0] = "swl";
- break;
- case ILST_W:
- str[0] = "sw";
- break;
- case ILST_WR:
- str[0] = "swr";
- break;
- default:
- // TODO different exception
- throw std::exception();
- }
- return str;
-}
diff --git a/qtmips_machine/instructions/loadstore.h b/qtmips_machine/instructions/loadstore.h
deleted file mode 100644
index 6f028fd..0000000
--- a/qtmips_machine/instructions/loadstore.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef LOADSTORE_H
-#define LOADSTORE_H
-
-#include "instruction.h"
-
-enum InstructionLoadStoreT {
- ILST_B, // Byte
- ILST_HW, // Half word
- ILST_WL, // Word left
- ILST_W, // Word
- ILST_BU, // Byte unsigned
- ILST_HU, // Half word unsigned
- ILST_WR // Word right
-};
-
-class InstructionLoad : public InstructionI {
-public:
- InstructionLoad(enum InstructionLoadStoreT type, std::uint8_t rs, std::uint8_t rt, std::uint16_t offset);
- QVector<QString> to_strs();
-private:
- enum InstructionLoadStoreT type;
-};
-
-class InstructionStore : public InstructionI {
-public:
- InstructionStore(enum InstructionLoadStoreT type, std::uint8_t rs, std::uint8_t rt, std::uint16_t offset);
- QVector<QString> to_strs();
-private:
- enum InstructionLoadStoreT type;
-};
-
-#endif // LOADSTORE_H
diff --git a/qtmips_machine/instructions/nop.cpp b/qtmips_machine/instructions/nop.cpp
deleted file mode 100644
index 7623dff..0000000
--- a/qtmips_machine/instructions/nop.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "nop.h"
-
-QVector<QString> InstructionNop::to_strs() {
- QVector<QString> str;
- str << QString("nop");
- return str;
-}
diff --git a/qtmips_machine/instructions/nop.h b/qtmips_machine/instructions/nop.h
deleted file mode 100644
index 5c019fd..0000000
--- a/qtmips_machine/instructions/nop.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef NOP_H
-#define NOP_H
-
-#include "instruction.h"
-
-class InstructionNop : public Instruction {
-public:
- QVector<QString> to_strs();
-};
-
-#endif // NOP_H
diff --git a/qtmips_machine/instructions/shift.cpp b/qtmips_machine/instructions/shift.cpp
deleted file mode 100644
index 34bc1c9..0000000
--- a/qtmips_machine/instructions/shift.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "shift.h"
-
-InstructionShift::InstructionShift(enum InstructionShiftT type, std::uint8_t rt, std::uint8_t rd, std::uint8_t sa)
- : InstructionR(0, rt, rd, sa) {
- this->type = type;
-}
-
-QVector<QString> InstructionShift::to_strs() {
- QVector<QString> str = this->InstructionR::to_strs();
- str.erase(str.begin() + 1); // Drop rs field
- switch (this->type) {
- case IST_LL:
- str[0] = "sll";
- break;
- case IST_RL:
- str[0] = "srl";
- break;
- case IST_RA:
- str[0] = "sra";
- break;
- default:
- // TODO different exception
- throw std::exception();
- }
- return str;
-}
-
-InstructionShiftVariable::InstructionShiftVariable(enum InstructionShiftT type, std::uint8_t rs, std::uint8_t rt, std::uint8_t rd)
- : InstructionR(rs, rt, rd, 0) {
- this->type = type;
-}
-
-QVector<QString> InstructionShiftVariable::to_strs() {
- QVector<QString> str = this->InstructionR::to_strs();
- str.erase(str.begin() + 4); // Drop sa field
- switch (this->type) {
- case IST_LL:
- str[0] = "sllv";
- break;
- case IST_RL:
- str[0] = "srlv";
- break;
- case IST_RA:
- str[0] = "srav";
- break;
- default:
- // TODO different exception
- throw std::exception();
- }
- return str;
-}
diff --git a/qtmips_machine/instructions/shift.h b/qtmips_machine/instructions/shift.h
deleted file mode 100644
index 69e2e1e..0000000
--- a/qtmips_machine/instructions/shift.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef SHIFT_H
-#define SHIFT_H
-
-#include "instruction.h"
-
-enum InstructionShiftT {
- IST_LL, // Left logical
- IST_RL, // Right logical
- IST_RA // Right arithmetic
-};
-
-class InstructionShift : public InstructionR {
-public:
- InstructionShift(enum InstructionShiftT type, std::uint8_t rt, std::uint8_t rd, std::uint8_t sa);
- QVector<QString> to_strs();
-private:
- enum InstructionShiftT type;
-};
-
-class InstructionShiftVariable : public InstructionR {
-public:
- InstructionShiftVariable(enum InstructionShiftT type, std::uint8_t rs, std::uint8_t rt, std::uint8_t rd);
- QVector<QString> to_strs();
-private:
- enum InstructionShiftT type;
-};
-
-#endif // SHIFT_H
diff --git a/qtmips_machine/machineconfig.cpp b/qtmips_machine/machineconfig.cpp
index 8562ab9..f23140f 100644
--- a/qtmips_machine/machineconfig.cpp
+++ b/qtmips_machine/machineconfig.cpp
@@ -1,6 +1,45 @@
#include "machineconfig.h"
-MachineConfig::MachineConfig()
-{
+MachineConfig::MachineConfig() {
+ pipeline = false;
+ jumppred = false;
+}
+
+MachineConfig::MachineConfig(MachineConfig *cc) {
+ pipeline = cc->pipelined();
+ jumppred = cc->jump_prediction();
+}
+
+void MachineConfig::set_pipelined(bool v) {
+ pipeline = v;
+}
+
+void MachineConfig::set_jump_prediction(bool v) {
+ jumppred = v;
+ if (jumppred)
+ pipeline = true;
+}
+
+void MachineConfig::set_cache(enum CacheType cc) {
+ cache_type = cc;
+}
+
+void MachineConfig::set_elf(QString path) {
+ elf_path = path;
+}
+
+bool MachineConfig::pipelined() const {
+ return pipeline;
+}
+
+bool MachineConfig::jump_prediction() const {
+ return jumppred;
+}
+
+enum MachineConfig::CacheType MachineConfig::cache() const {
+ return cache_type;
+}
+QString MachineConfig::elf() const {
+ return elf_path;
}
diff --git a/qtmips_machine/machineconfig.h b/qtmips_machine/machineconfig.h
index 58c2fc2..352e62b 100644
--- a/qtmips_machine/machineconfig.h
+++ b/qtmips_machine/machineconfig.h
@@ -1,11 +1,40 @@
#ifndef MACHINECONFIG_H
#define MACHINECONFIG_H
+#include <QString>
-class MachineConfig
-{
+class MachineConfig {
public:
MachineConfig();
+ MachineConfig(MachineConfig *cc);
+
+ enum CacheType {
+ CCT_NONE,
+ CCT_ASSOCIATIVE,
+ // TODO
+ };
+
+ // Configure if CPU is pipelined
+ // In default disabled.
+ void set_pipelined(bool);
+ // Configure if we want to do jump prediction
+ // In default disabled. When enabled it also automatically enables pipelining
+ void set_jump_prediction(bool);
+ // Configure cache type
+ // In default CCT_NONE is used.
+ void set_cache(enum CacheType);
+ // Set path to source elf file. This has to be set before core is initialized.
+ void set_elf(QString path);
+
+ bool pipelined() const;
+ bool jump_prediction() const;
+ enum CacheType cache() const;
+ QString elf() const;
+
+private:
+ bool pipeline, jumppred;
+ enum CacheType cache_type;
+ QString elf_path;
};
-#endif // MACHINECONFIG_H \ No newline at end of file
+#endif // MACHINECONFIG_H
diff --git a/qtmips_machine/programloader.cpp b/qtmips_machine/programloader.cpp
index 6eefa6c..f49fa3c 100644
--- a/qtmips_machine/programloader.cpp
+++ b/qtmips_machine/programloader.cpp
@@ -2,12 +2,11 @@
#include <exception>
#include <unistd.h>
#include <fcntl.h>
-#include <iostream>
#include <errno.h>
#include <cstring>
#include "qtmipsexception.h"
-ProgramLoader::ProgramLoader(char *file) {
+ProgramLoader::ProgramLoader(const char *file) {
// Initialize elf library
if (elf_version(EV_CURRENT) == EV_NONE)
throw QTMIPS_EXCEPTION(Input, "Elf library initialization failed", elf_errmsg(-1));
@@ -53,29 +52,35 @@ ProgramLoader::ProgramLoader(char *file) {
// TODO instead of direct access should we be using sections and elf_data? And if so how to link program header and section?
}
+ProgramLoader::ProgramLoader(QString file) : ProgramLoader(file.toStdString().c_str()) { }
+
ProgramLoader::~ProgramLoader() {
// Close elf
- elf_end(this->elf);
+ // TODO fix (this results to segfault, there is probably somethig passed to it on stack or something)
+ //elf_end(this->elf);
// Close file
close(this->fd);
}
-size_t ProgramLoader::get_nsec() {
- return this->map.size();
-}
-
-std::uint32_t ProgramLoader::get_address(size_t sec) {
- SANITY_ASSERT(sec > this->get_nsec(), "Requesting too big section");
- return this->phdrs[this->map[sec]].p_vaddr;
+void ProgramLoader::to_memory(Memory *mem) {
+ // Load program to memory (just dump it byte by byte)
+ for (int i = 0; i < this->map.size(); i++) {
+ std::uint32_t base_address = this->phdrs[this->map[i]].p_vaddr;
+ char *f = elf_rawfile(this->elf, NULL);
+ size_t phdrs_i = this->map[i];
+ for (unsigned y = 0; y < this->phdrs[phdrs_i].p_filesz; y++) {
+ mem->write_byte(base_address + y, (std::uint8_t) f[this->phdrs[phdrs_i].p_offset + y]);
+ }
+ }
}
-QVector<std::uint8_t> ProgramLoader::get_data(size_t sec) {
- SANITY_ASSERT(sec > this->get_nsec(), "Requesting too big section");
- QVector<std::uint8_t> d;
- char *f = elf_rawfile(this->elf, NULL);
- size_t phdrs_i = this->map[sec];
- for (unsigned i = 0; i < this->phdrs[phdrs_i].p_filesz; i++) {
- d << (std::uint8_t) f[this->phdrs[phdrs_i].p_offset + i];
+std::uint32_t ProgramLoader::end() {
+ std::uint32_t last = 0;
+ // Go trough all sections and found out last one
+ for (int i = 0; i < this->map.size(); i++) {
+ Elf32_Phdr *phdr = &(this->phdrs[this->map[i]]);
+ if ((phdr->p_vaddr + phdr->p_filesz) > last)
+ last = phdr->p_vaddr + phdr->p_filesz;
}
- return d;
+ return last + 0x10; // We add offset so we are sure that also pipeline is empty
}
diff --git a/qtmips_machine/programloader.h b/qtmips_machine/programloader.h
index 4d722d2..7da241c 100644
--- a/qtmips_machine/programloader.h
+++ b/qtmips_machine/programloader.h
@@ -6,16 +6,18 @@
#include <gelf.h>
#include <cstdint>
#include <qvector.h>
+#include <qstring.h>
+#include "memory.h"
class ProgramLoader {
public:
- ProgramLoader(char *file);
+ ProgramLoader(const char *file);
+ ProgramLoader(QString file);
~ProgramLoader();
- size_t get_nsec(); // Returns number of loadable sections
- std::uint32_t get_address(size_t sec); // Get target address for given section
- QVector<std::uint8_t> get_data(size_t sec); // Returns bytes of given section
+ void to_memory(Memory *mem); // Writes all loaded sections to memory
+ std::uint32_t end(); // Return address after which there is no more code for sure
private:
int fd;
Elf *elf;
diff --git a/qtmips_machine/programmemory.h b/qtmips_machine/programmemory.h
deleted file mode 100644
index 14187c5..0000000
--- a/qtmips_machine/programmemory.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef PROGRAMMEMORY_H
-#define PROGRAMMEMORY_H
-
-#include <vector>
-#include "programloader.h"
-#include "memory.h"
-#include "instruction.h"
-
-class ProgramMemory {
-public:
- ProgramMemory(MemoryAccess *memory);
-
- void load(ProgramLoader *l);
- Instruction *at(std::uint32_t address); // return instruction isntance for given address
-
-private:
- MemoryAccess *memory;
- Instruction *decode_r(std::uint32_t dt);
- Instruction *decode_j(std::uint32_t dt, std::uint8_t opcode);
- Instruction *decode_i(std::uint32_t dt, std::uint8_t opcode);
-};
-
-#endif // PROGRAMMEMORY_H
diff --git a/qtmips_machine/qtmips_machine.pro b/qtmips_machine/qtmips_machine.pro
index 213727d..a1edcaa 100644
--- a/qtmips_machine/qtmips_machine.pro
+++ b/qtmips_machine/qtmips_machine.pro
@@ -7,6 +7,7 @@ TEMPLATE = lib
LIBS += -lelf
QMAKE_CXXFLAGS += -std=c++0x
+QMAKE_CXXFLAGS += -ggdb
DEFINES += QTMIPS_MACHINE_LIBRARY
DEFINES += QT_DEPRECATED_WARNINGS
@@ -19,13 +20,9 @@ SOURCES += \
instruction.cpp \
registers.cpp \
programloader.cpp \
- programmemory.cpp \
- instructions/arithmetic.cpp \
- instructions/loadstore.cpp \
- instructions/shift.cpp \
- instructions/nop.cpp \
- instructions/jumpbranch.cpp \
- cache.cpp
+ cache.cpp \
+ alu.cpp \
+ machineconfig.cpp
HEADERS += \
qtmipsmachine.h \
@@ -41,4 +38,6 @@ HEADERS += \
instructions/shift.h \
instructions/nop.h \
instructions/jumpbranch.h \
- cache.h
+ cache.h \
+ alu.h \
+ machineconfig.h
diff --git a/qtmips_machine/qtmipsexception.cpp b/qtmips_machine/qtmipsexception.cpp
index 4cec6b0..02193cb 100644
--- a/qtmips_machine/qtmipsexception.cpp
+++ b/qtmips_machine/qtmipsexception.cpp
@@ -19,7 +19,7 @@ const char *QtMipsException::what() const throw() {
QString QtMipsException::msg(bool pos) const {
QString message;
if (pos)
- message += QString("(") + QString(this->file) + QString(":") + QString(this->line) + QString(") ");
+ message += QString("(") + QString(this->file) + QString(":") + QString::number(this->line) + QString(") ");
message += this->reason;
if (!this->ext.isEmpty()) {
message += QString(": ");
@@ -44,6 +44,16 @@ QtMipsExceptionUnsupportedInstruction::QtMipsExceptionUnsupportedInstruction(QTM
return;
}
+QtMipsExceptionUnsupportedAluOperation::QtMipsExceptionUnsupportedAluOperation(QTMIPS_ARGS_COMMON)
+ : QtMipsExceptionRuntime(reason, ext, file, line) {
+ return;
+}
+
+QtMipsExceptionOverflow::QtMipsExceptionOverflow(QTMIPS_ARGS_COMMON)
+ : QtMipsExceptionRuntime(reason, ext, file, line) {
+ return;
+}
+
QtMipsExceptionUnalignedJump::QtMipsExceptionUnalignedJump(QTMIPS_ARGS_COMMON)
: QtMipsExceptionRuntime(reason, ext, file, line) {
return;
diff --git a/qtmips_machine/qtmipsexception.h b/qtmips_machine/qtmipsexception.h
index 81895d6..b81f748 100644
--- a/qtmips_machine/qtmipsexception.h
+++ b/qtmips_machine/qtmipsexception.h
@@ -37,6 +37,20 @@ public:
QtMipsExceptionUnsupportedInstruction(QTMIPS_ARGS_COMMON);
};
+// Decoded ALU operation is not supported
+// This is basically same exception as QtMipsExceptionUnsupportedInstruction but it is emmited from ALU when executed and not before that.
+class QtMipsExceptionUnsupportedAluOperation : public QtMipsExceptionRuntime {
+public:
+ QtMipsExceptionUnsupportedAluOperation(QTMIPS_ARGS_COMMON);
+};
+
+// Integer operation resulted to overflow (or underflow as we are working with unsigned values)
+// This is for sure caused by program it self.
+class QtMipsExceptionOverflow : public QtMipsExceptionRuntime {
+public:
+ QtMipsExceptionOverflow(QTMIPS_ARGS_COMMON);
+};
+
// Instruction is jumping to unaligned address (ADDR%4!=0)
// This can be caused by bug or by user program as it can be jumping relative to register
// This shouldn't be happening with non-register jumps as those should be verified by compiler
diff --git a/qtmips_machine/qtmipsmachine.cpp b/qtmips_machine/qtmipsmachine.cpp
index 0fc207c..3d5ce98 100644
--- a/qtmips_machine/qtmipsmachine.cpp
+++ b/qtmips_machine/qtmipsmachine.cpp
@@ -1,5 +1,70 @@
#include "qtmipsmachine.h"
+#include "programloader.h"
-QtMipsMachine::QtMipsMachine(char *file) {
- this->loader = new ProgramLoader(file);
+QtMipsMachine::QtMipsMachine(const MachineConfig &cc) {
+ ProgramLoader program(cc.elf());
+
+ regs = new Registers();
+ mem = new Memory();
+
+ program.to_memory(mem);
+ program_end = program.end();
+
+ MemoryAccess *coremem;
+ switch (cc.cache()) {
+ case MachineConfig::CCT_NONE:
+ cch = nullptr;
+ coremem = mem;
+ break;
+ case MachineConfig::CCT_ASSOCIATIVE:
+ // TODO
+ coremem = mem;
+ //coremem = cch = new CacheAssociative();
+ break;
+ }
+
+ // TODO pipelined
+ cr = new CoreSingle(regs, coremem);
+
+ run_speed = 1;
+ run_t = new QTimer(this);
+ connect(run_t, SIGNAL(timeout()), this, SLOT(step()));
+}
+
+void QtMipsMachine::set_speed(unsigned val) {
+ run_speed = val;
+}
+
+const Registers *QtMipsMachine::registers() {
+ return regs;
+}
+
+const Memory *QtMipsMachine::memory() {
+ return mem;
+}
+
+const Cache *QtMipsMachine::cache() {
+ return cch;
+}
+
+const Core *QtMipsMachine::core() {
+ return cr;
+}
+
+void QtMipsMachine::play() {
+ run_t->start(run_speed);
+}
+
+void QtMipsMachine::pause() {
+ run_t->stop();
+}
+
+void QtMipsMachine::step() {
+ cr->step();
+ if (regs->read_pc() >= program_end)
+ emit program_exit();
+}
+
+void QtMipsMachine::restart() {
+ // TODO
}
diff --git a/qtmips_machine/qtmipsmachine.h b/qtmips_machine/qtmipsmachine.h
index af981b3..829e571 100644
--- a/qtmips_machine/qtmipsmachine.h
+++ b/qtmips_machine/qtmipsmachine.h
@@ -2,24 +2,47 @@
#define QTMIPSMACHINE_H
#include <QObject>
-
+#include <QTimer>
+#include <cstdint>
#include "qtmipsexception.h"
-#include "programloader.h"
+#include "machineconfig.h"
+#include "registers.h"
+#include "memory.h"
#include "core.h"
-// TODO piplined core
+#include "cache.h"
-class QtMipsMachine : QObject {
+class QtMipsMachine : public QObject {
Q_OBJECT
public:
- QtMipsMachine(char *file);
+ QtMipsMachine(const MachineConfig &cc);
+
+ void set_speed(unsigned);
+ const Registers *registers();
+ const Memory *memory();
+ const Cache *cache();
+ const Core *core();
+
+public slots:
// TODO handle speed
void play();
void pause();
void step();
void restart();
+
+signals:
+ void program_exit();
+
private:
- ProgramLoader *loader;
+ Registers *regs;
+ Memory *mem;
+ Cache *cch;
+ Core *cr;
+
+ unsigned run_speed;
+ QTimer *run_t;
+
+ std::uint32_t program_end;
};
#endif // QTMIPSMACHINE_H
diff --git a/qtmips_machine/registers.cpp b/qtmips_machine/registers.cpp
index 837f403..fa984fb 100644
--- a/qtmips_machine/registers.cpp
+++ b/qtmips_machine/registers.cpp
@@ -14,12 +14,21 @@ Registers::Registers() {
this->hi = this->lo = 0;
}
-std::uint32_t Registers::read_pc() {
+Registers::Registers(const Registers *orig) : Registers() {
+ this->pc = orig->read_pc();
+ for (int i = 0; i < 31; i++)
+ this->gp[i] = orig->read_gp(i);
+ this->lo = orig->read_hi_lo(false);
+ this->hi = orig->read_hi_lo(true);
+}
+
+std::uint32_t Registers::read_pc() const {
return this->pc;
}
std::uint32_t Registers::pc_inc() {
this->pc += 4;
+ emit pc_update(this->pc);
return this->pc;
}
@@ -27,6 +36,7 @@ std::uint32_t Registers::pc_jmp(std::int32_t offset) {
if (offset % 4)
throw QTMIPS_EXCEPTION(UnalignedJump, "Trying to jump by unaligned offset", QString::number(offset, 16));
this->pc += offset;
+ emit pc_update(this->pc);
return this->pc;
}
@@ -36,7 +46,7 @@ void Registers::pc_abs_jmp(std::uint32_t address) {
this->pc = address;
}
-std::uint32_t Registers::read_gp(std::uint8_t i) {
+std::uint32_t Registers::read_gp(std::uint8_t i) const {
SANITY_ASSERT(i < 32, QString("Trying to read from register ") + QString(i));
if (!i) // $0 always reads as 0
return 0;
@@ -50,7 +60,7 @@ void Registers::write_gp(std::uint8_t i, std::uint32_t value) {
this->gp[i - 1] = value;
}
-std::uint32_t Registers::read_hi_lo(bool hi) {
+std::uint32_t Registers::read_hi_lo(bool hi) const {
if (hi)
return this->hi;
else
@@ -63,3 +73,16 @@ void Registers::write_hi_lo(bool hi, std::uint32_t value) {
else
this->lo = value;
}
+
+bool Registers::operator ==(const Registers &c) const {
+ if (read_pc() != c.read_pc())
+ return false;
+ for (int i = 0; i < 31; i++)
+ if (read_gp(i) != c.read_gp(i))
+ return false;
+ if (read_hi_lo(false) != c.read_hi_lo(false))
+ return false;
+ if (read_hi_lo(true) != c.read_hi_lo(true))
+ return false;
+ return true;
+}
diff --git a/qtmips_machine/registers.h b/qtmips_machine/registers.h
index a550f4a..905a212 100644
--- a/qtmips_machine/registers.h
+++ b/qtmips_machine/registers.h
@@ -8,18 +8,22 @@ class Registers : public QObject {
Q_OBJECT
public:
Registers();
+ Registers(const Registers*);
- std::uint32_t read_pc(); // Return current value of program counter
+ std::uint32_t read_pc() const; // Return current value of program counter
std::uint32_t pc_inc(); // Increment program counter by four bytes
std::uint32_t pc_jmp(std::int32_t offset); // Relative jump from current location in program counter
void pc_abs_jmp(std::uint32_t address); // Absolute jump in program counter (write to pc)
- std::uint32_t read_gp(std::uint8_t i); // Read general-purpose register
+ std::uint32_t read_gp(std::uint8_t i) const; // Read general-purpose register
void write_gp(std::uint8_t i, std::uint32_t value); // Write general-purpose register
- std::uint32_t read_hi_lo(bool hi); // true - read HI / false - read LO
+ std::uint32_t read_hi_lo(bool hi) const; // true - read HI / false - read LO
void write_hi_lo(bool hi, std::uint32_t value);
+ bool operator ==(const Registers &c) const;
+
signals:
+ void pc_update(std::uint32_t val);
// TODO signals
private:
diff --git a/qtmips_machine/tests/testalu.cpp b/qtmips_machine/tests/testalu.cpp
index e69de29..37accdf 100644
--- a/qtmips_machine/tests/testalu.cpp
+++ b/qtmips_machine/tests/testalu.cpp
@@ -0,0 +1,91 @@
+#include "tst_machine.h"
+#include "alu.h"
+#include "qtmipsexception.h"
+
+void MachineTests::alu_data() {
+ QTest::addColumn<std::uint8_t>("op");
+ QTest::addColumn<std::uint32_t>("s");
+ QTest::addColumn<std::uint32_t>("t");
+ QTest::addColumn<std::uint8_t>("sa");
+ QTest::addColumn<std::uint32_t>("res");
+
+ // TODO SLL-SRAV
+ QTest::newRow("ADD") << (std::uint8_t)ALU_OP_ADD \
+ << (std::uint32_t)24 \
+ << (std::uint32_t)66 \
+ << (std::uint8_t)0 \
+ << (std::uint32_t)90;
+ QTest::newRow("ADDU") << (std::uint8_t)ALU_OP_ADDU \
+ << (std::uint32_t)24 \
+ << (std::uint32_t)66 \
+ << (std::uint8_t)0 \
+ << (std::uint32_t)90;
+ QTest::newRow("SUB") << (std::uint8_t)ALU_OP_SUB \
+ << (std::uint32_t)66 \
+ << (std::uint32_t)24 \
+ << (std::uint8_t)0 \
+ << (std::uint32_t)42;
+ QTest::newRow("SUBU") << (std::uint8_t)ALU_OP_SUBU \
+ << (std::uint32_t)24 \
+ << (std::uint32_t)66 \
+ << (std::uint8_t)0 \
+ << (std::uint32_t)-42;
+ QTest::newRow("AND") << (std::uint8_t)ALU_OP_AND \
+ << (std::uint32_t)0xA81 \
+ << (std::uint32_t)0x603 \
+ << (std::uint8_t)0 \
+ << (std::uint32_t)0x201;
+ QTest::newRow("OR") << (std::uint8_t)ALU_OP_OR \
+ << (std::uint32_t)0xA81 \
+ << (std::uint32_t)0x603 \
+ << (std::uint8_t)0 \
+ << (std::uint32_t)0xE83;
+ QTest::newRow("XOR") << (std::uint8_t)ALU_OP_XOR \
+ << (std::uint32_t)0xA81 \
+ << (std::uint32_t)0x603 \
+ << (std::uint8_t)0 \
+ << (std::uint32_t)0xC82;
+ QTest::newRow("NOR") << (std::uint8_t)ALU_OP_NOR \
+ << (std::uint32_t)0xA81 \
+ << (std::uint32_t)0x603 \
+ << (std::uint8_t)0 \
+ << (std::uint32_t)0xFFFFF17C;
+ // TODO SLT-SLTU
+}
+
+void MachineTests::alu() {
+ QFETCH(std::uint8_t, op);
+ QFETCH(std::uint32_t, s);
+ QFETCH(std::uint32_t, t);
+ QFETCH(std::uint8_t, sa);
+ QFETCH(std::uint32_t, res);
+
+ QCOMPARE(alu_operate((enum AluOp)op, s , t, sa), res);
+}
+
+void MachineTests::alu_except_data() {
+ QTest::addColumn<std::uint8_t>("op");
+ QTest::addColumn<std::uint32_t>("s");
+ QTest::addColumn<std::uint32_t>("t");
+ // Note no sa as shift unstruction has no exceptions
+
+ QTest::newRow("ADD") << (std::uint8_t)ALU_OP_ADD \
+ << (std::uint32_t)0x8fffffff \
+ << (std::uint32_t)0x90000000;
+ QTest::newRow("SUB") << (std::uint8_t)ALU_OP_SUB \
+ << (std::uint32_t)3 \
+ << (std::uint32_t)4;
+ // Just test that we can throw unsupported ALU operation
+ QTest::newRow("?") << (std::uint8_t)ALU_OP_LAST \
+ << (std::uint32_t)0 \
+ << (std::uint32_t)0;
+}
+
+void MachineTests::alu_except() {
+ QFETCH(std::uint8_t, op);
+ QFETCH(std::uint32_t, s);
+ QFETCH(std::uint32_t, t);
+
+ // Only runtime exception is expected as any other exception is a bug
+ QVERIFY_EXCEPTION_THROWN(alu_operate((enum AluOp)op, s , t, 0), QtMipsExceptionRuntime);
+}
diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp
index e69de29..bbf8086 100644
--- a/qtmips_machine/tests/testcore.cpp
+++ b/qtmips_machine/tests/testcore.cpp
@@ -0,0 +1,35 @@
+#include "tst_machine.h"
+#include "core.h"
+
+void MachineTests::core_regs_data() {
+ /*
+ QTest::addColumn<Instruction>("i");
+ QTest::addColumn<Registers>("init");
+ QTest::addColumn<Registers>("res");
+
+ // Test arithmetic instructions
+ {
+ Registers regs_init();
+ regs_init.write_gp(24, 12);
+ regs_init.write_gp(25, 24);
+ Registers regs_res(&regs_init);
+ regs_res.write_gp(26, 36);
+ QTest::newRow("ADD") << Instruction(0, 24, 25, 26, 0, 32) \
+ << regs_init \
+ << regs_res;
+ }
+ */
+ // TODO test other operations
+}
+
+void MachineTests::core_regs() {
+
+}
+
+void MachineTests::core_mem_data() {
+
+}
+
+void MachineTests::core_mem() {
+
+}
diff --git a/qtmips_machine/tests/testinstruction.cpp b/qtmips_machine/tests/testinstruction.cpp
index e69de29..4efedac 100644
--- a/qtmips_machine/tests/testinstruction.cpp
+++ b/qtmips_machine/tests/testinstruction.cpp
@@ -0,0 +1,25 @@
+#include "tst_machine.h"
+#include "instruction.h"
+
+// Test that we are correctly encoding instructions in constructor
+void MachineTests::instruction() {
+ QCOMPARE(Instruction(0x00), Instruction(0,0));
+ QCOMPARE(Instruction(0x4000002), Instruction(1, 2));
+ // QCOMPARE(Instruction(0x4000002), Instruction(1, 2, 3, 4));
+ // TODO other combinations
+}
+
+// Test that we are correctly decoding instruction fields
+void MachineTests::instruction_access() {
+ Instruction i(0xffffffff);
+
+ QCOMPARE(i.data(), (std::uint32_t) 0xffffffff);
+ QCOMPARE(i.opcode(), (std::uint8_t) 0x3f);
+ QCOMPARE(i.rs(), (std::uint8_t) 0x1f);
+ QCOMPARE(i.rt(), (std::uint8_t) 0x1f);
+ QCOMPARE(i.rd(), (std::uint8_t) 0x1f);
+ QCOMPARE(i.shamt(), (std::uint8_t) 0x1f);
+ QCOMPARE(i.funct(), (std::uint8_t) 0x3f);
+ QCOMPARE(i.immediate(), (std::uint16_t) 0xffff);
+ QCOMPARE(i.address(), (std::uint32_t) 0x3ffffff);
+}
diff --git a/qtmips_machine/tests/testmemory.cpp b/qtmips_machine/tests/testmemory.cpp
index eac7dd6..e450231 100644
--- a/qtmips_machine/tests/testmemory.cpp
+++ b/qtmips_machine/tests/testmemory.cpp
@@ -13,21 +13,21 @@ void MachineTests::memory_data() {
void MachineTests::memory() {
Memory m;
- QFETCH(std::uint32_t, address);
+ QFETCH(std::uint32_t, address);
- // Uninitialize memory should read as zero
- QCOMPARE(m.read_byte(address), (std::uint8_t)0);
- QCOMPARE(m.read_hword(address), (std::uint16_t)0);
- QCOMPARE(m.read_word(address), (std::uint32_t)0);
- // Just a byte
- m.write_byte(address, 0x42);
- QCOMPARE(m.read_byte(address), (std::uint8_t)0x42);
- // Half word
- m.write_hword(address, 0x4243);
- QCOMPARE(m.read_hword(address), (std::uint16_t)0x4243);
- // Word
- m.write_word(address, 0x42434445);
- QCOMPARE(m.read_word(address), (std::uint32_t)0x42434445);
+ // Uninitialize memory should read as zero
+ QCOMPARE(m.read_byte(address), (std::uint8_t)0);
+ QCOMPARE(m.read_hword(address), (std::uint16_t)0);
+ QCOMPARE(m.read_word(address), (std::uint32_t)0);
+ // Just a byte
+ m.write_byte(address, 0x42);
+ QCOMPARE(m.read_byte(address), (std::uint8_t)0x42);
+ // Half word
+ m.write_hword(address, 0x4243);
+ QCOMPARE(m.read_hword(address), (std::uint16_t)0x4243);
+ // Word
+ m.write_word(address, 0x42434445);
+ QCOMPARE(m.read_word(address), (std::uint32_t)0x42434445);
}
void MachineTests::memory_section_data() {
@@ -40,24 +40,24 @@ void MachineTests::memory_section_data() {
}
void MachineTests::memory_section() {
- Memory m;
+ Memory m;
- QFETCH(std::uint32_t, address);
+ QFETCH(std::uint32_t, address);
- // First section shouldn't exists
- QCOMPARE(m.get_section(address, false), (MemorySection*)nullptr);
- // Create section
- MemorySection *s = m.get_section(address, true);
- QVERIFY(s != nullptr);
+ // First section shouldn't exists
+ QCOMPARE(m.get_section(address, false), (MemorySection*)nullptr);
+ // Create section
+ MemorySection *s = m.get_section(address, true);
+ QVERIFY(s != nullptr);
- // Write some data to memory
- m.write_byte(address, 0x42);
- // Read it trough section (mask bits outside of the memory section)
- QCOMPARE(s->read_byte(address & ((1 << MEMORY_SECTION_BITS) - 1)), (std::uint8_t)0x42);
- // Write some other data trough section
- s->write_byte(address & ((1 << MEMORY_SECTION_BITS) - 1), 0x66);
- // Read trough memory
- QCOMPARE(m.read_byte(address), (std::uint8_t)0x66);
+ // Write some data to memory
+ m.write_byte(address, 0x42);
+ // Read it trough section (mask bits outside of the memory section)
+ QCOMPARE(s->read_byte(address & ((1 << MEMORY_SECTION_BITS) - 1)), (std::uint8_t)0x42);
+ // Write some other data trough section
+ s->write_byte(address & ((1 << MEMORY_SECTION_BITS) - 1), 0x66);
+ // Read trough memory
+ QCOMPARE(m.read_byte(address), (std::uint8_t)0x66);
}
void MachineTests::memory_endian() {
diff --git a/qtmips_machine/tests/testprogramloader.cpp b/qtmips_machine/tests/testprogramloader.cpp
index e69de29..7ff1c54 100644
--- a/qtmips_machine/tests/testprogramloader.cpp
+++ b/qtmips_machine/tests/testprogramloader.cpp
@@ -0,0 +1,20 @@
+#include <iostream>
+#include "tst_machine.h"
+#include "programloader.h"
+#include "instruction.h"
+
+// This is common program start (initial value of program counter)
+#define PC_INIT 0x80020000
+
+void MachineTests::program_loader() {
+ ProgramLoader pl("data");
+ Memory m;
+ pl.to_memory(&m);
+
+ // addi $1, $0, 6
+ QCOMPARE(Instruction(m.read_word(PC_INIT)), Instruction(8, 0, 1, 6));
+ // j 80020000
+ // TODO wtf to je relativni skok asi tady
+ //QCOMPARE(Instruction(m.read_word(PC_INIT + 4)), Instruction(2, PC_INIT));
+ // TODO add some more code to data and do more compares (for example more sections)
+}
diff --git a/qtmips_machine/tests/tests.pro b/qtmips_machine/tests/tests.pro
index 287d1e8..ffe75b7 100644
--- a/qtmips_machine/tests/tests.pro
+++ b/qtmips_machine/tests/tests.pro
@@ -18,8 +18,10 @@ DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += tst_machine.cpp \
testmemory.cpp \
testregisters.cpp \
- testprogrammemory.cpp \
- testinstruction.cpp
+ testprogramloader.cpp \
+ testinstruction.cpp \
+ testalu.cpp \
+ testcore.cpp
HEADERS += tst_machine.h
diff --git a/qtmips_machine/tests/tst_machine.h b/qtmips_machine/tests/tst_machine.h
index c05e8ad..da8082a 100644
--- a/qtmips_machine/tests/tst_machine.h
+++ b/qtmips_machine/tests/tst_machine.h
@@ -17,14 +17,21 @@ private Q_SLOTS:
void memory_section();
void memory_section_data();
void memory_endian();
- // ProgramMemory
- void program_memory();
- void program_memory_data();
+ // Program loader
+ void program_loader();
// Instruction
- void instruction_arithmetic();
- void instruction_arithmetic_data();
- void instruction_arithmetic_immediate();
- void instruction_arithmetic_immediate_data();
+ void instruction();
+ void instruction_access();
+ // Alu
+ void alu();
+ void alu_data();
+ void alu_except();
+ void alu_except_data();
+ // Core
+ void core_regs();
+ void core_regs_data();
+ void core_mem();
+ void core_mem_data();
};
#endif // TST_MACHINE_H