aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qtmips_machine/alu.h3
-rw-r--r--qtmips_machine/instruction.cpp8
-rw-r--r--qtmips_machine/instruction.h8
-rw-r--r--qtmips_machine/memory.cpp123
-rw-r--r--qtmips_machine/memory.h33
-rw-r--r--qtmips_machine/registers.cpp10
-rw-r--r--qtmips_machine/registers.h4
-rw-r--r--qtmips_machine/tests/testalu.cpp22
-rw-r--r--qtmips_machine/tests/testcore.cpp23
-rw-r--r--qtmips_machine/tests/testmemory.cpp28
-rw-r--r--qtmips_machine/tests/tst_machine.h1
11 files changed, 216 insertions, 47 deletions
diff --git a/qtmips_machine/alu.h b/qtmips_machine/alu.h
index 974b462..2e30ee9 100644
--- a/qtmips_machine/alu.h
+++ b/qtmips_machine/alu.h
@@ -3,6 +3,7 @@
#include <cstdint>
#include <QString>
+#include <QObject>
// TODO Any other operations? We seems to be missing a lot of them.
enum AluOp : std::uint8_t {
@@ -36,4 +37,6 @@ std::uint32_t alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t
// 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);
+Q_DECLARE_METATYPE(AluOp)
+
#endif // ALU_H
diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp
index 8591d93..91bd1c8 100644
--- a/qtmips_machine/instruction.cpp
+++ b/qtmips_machine/instruction.cpp
@@ -28,6 +28,10 @@ const struct InstructionMap instruction_map[] = {
IM_UNKNOWN
};
+Instruction::Instruction() {
+ this->dt = 0;
+}
+
Instruction::Instruction(std::uint32_t inst) {
this->dt = inst;
}
@@ -56,6 +60,10 @@ Instruction::Instruction(std::uint8_t opcode, std::uint32_t address) {
this->dt |= address;
}
+Instruction::Instruction(const Instruction &i) {
+ this->dt = i.data();
+}
+
QString Instruction::to_str() {
if (this->opcode() >= sizeof(instruction_map))
return QString("UNKNOWN");
diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h
index 3b76fba..921d9b0 100644
--- a/qtmips_machine/instruction.h
+++ b/qtmips_machine/instruction.h
@@ -1,14 +1,18 @@
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
+#include <QObject>
#include <qstring.h>
-class Instruction {
+class Instruction : public QObject {
+ Q_OBJECT
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
+ Instruction(const Instruction&);
QString to_str();
@@ -28,4 +32,6 @@ private:
std::uint32_t dt;
};
+Q_DECLARE_METATYPE(Instruction)
+
#endif // INSTRUCTION_H
diff --git a/qtmips_machine/memory.cpp b/qtmips_machine/memory.cpp
index 21ca03f..a9cc055 100644
--- a/qtmips_machine/memory.cpp
+++ b/qtmips_machine/memory.cpp
@@ -56,28 +56,47 @@ std::uint32_t MemoryAccess::read_word(std::uint32_t offset) {
}
MemorySection::MemorySection(std::uint32_t length) {
- this->length = length;
+ this->len = length;
this->dt = new std::uint8_t[length];
+ memset(this->dt, 0, sizeof *this->dt * length);
+}
+
+MemorySection::MemorySection(const MemorySection &ms) : MemorySection(ms.length()) {
+ memcpy(this->dt, ms.data(), sizeof *this->dt * this->len);
}
MemorySection::~MemorySection() {
delete this->dt;
}
-using namespace std;
-
void MemorySection::write_byte(std::uint32_t offset, std::uint8_t value) {
- if (offset >= this->length)
+ if (offset >= this->len)
throw QTMIPS_EXCEPTION(OutOfMemoryAccess, "Trying to write outside of the memory section", QString("Accessing using offset: ") + QString(offset));
this->dt[offset] = value;
}
-std::uint8_t MemorySection::read_byte(std::uint32_t offset) {
- if (offset >= this->length)
+std::uint8_t MemorySection::read_byte(std::uint32_t offset) const {
+ if (offset >= this->len)
throw QTMIPS_EXCEPTION(OutOfMemoryAccess, "Trying to read outside of the memory section", QString("Accessing using offset: ") + QString(offset));
return this->dt[offset];
}
+std::uint32_t MemorySection::length() const {
+ return len;
+}
+
+const std::uint8_t* MemorySection::data() const {
+ return this->dt;
+}
+
+bool MemorySection::operator==(const MemorySection &ms) const {
+ return ! memcmp(this->dt, ms.data(), sizeof *this->dt * this->len);
+}
+
+bool MemorySection::operator!=(const MemorySection &ms) const {
+ return ! this->operator ==(ms);
+}
+
// Number of bites per row on lookup tree
#define MEMORY_TREE_ROW ((32 - MEMORY_SECTION_BITS) / MEMORY_TREE_H)
// Size of row in memory lookup tree
@@ -102,17 +121,12 @@ Memory::Memory() {
this->mt_root = allocate_section_tree();
}
-Memory::~Memory() {
- // Free up memory tree
- // TODO
+Memory::Memory(const Memory &m) {
+ this->mt_root = copy_section_tree(m.get_memorytree_root(), 0);
}
-union MemoryTree *Memory::allocate_section_tree() {
- union MemoryTree *mt = new union MemoryTree[MEMORY_TREE_LEN];
- for (size_t i = 0; i < MEMORY_TREE_LEN; i++)
- // Note that this also nulls sec pointer as those are both pointers and so they have same size
- mt[i].mt = nullptr;
- return mt;
+Memory::~Memory() {
+ free_section_tree(this->mt_root, 0);
}
// Create address mask with section length
@@ -123,7 +137,7 @@ union MemoryTree *Memory::allocate_section_tree() {
#define ADDRESS_TREE_INDEX(DEPTH, ADDR) ((ADDR >> (DEPTH * MEMORY_TREE_ROW)) & ADDRESS_MASK(MEMORY_TREE_ROW))
-MemorySection *Memory::get_section(std::uint32_t address, bool create) {
+MemorySection *Memory::get_section(std::uint32_t address, bool create) const {
std::uint32_t addr = address >> MEMORY_SECTION_BITS; // drop all bits for addressing inside of the section
union MemoryTree *w = this->mt_root;
size_t ii;
@@ -155,10 +169,85 @@ void Memory::write_byte(std::uint32_t address, std::uint8_t value) {
section->write_byte(SECTION_ADDRESS(address), value);
}
-std::uint8_t Memory::read_byte(std::uint32_t address) {
+std::uint8_t Memory::read_byte(std::uint32_t address) const {
MemorySection *section = this->get_section(address, true);
if (section == nullptr)
return 0;
else
return section->read_byte(SECTION_ADDRESS(address));
}
+
+bool Memory::operator==(const Memory&m) const {
+ return compare_section_tree(this->mt_root, m.get_memorytree_root(), 0);
+}
+
+bool Memory::operator!=(const Memory&m) const {
+ return ! this->operator ==(m);
+}
+
+const union MemoryTree *Memory::get_memorytree_root() const {
+ return this->mt_root;
+}
+
+union MemoryTree *Memory::allocate_section_tree() {
+ union MemoryTree *mt = new union MemoryTree[MEMORY_TREE_LEN];
+ for (size_t i = 0; i < MEMORY_TREE_LEN; i++)
+ // Note that this also nulls sec pointer as those are both pointers and so they have same size
+ mt[i].mt = nullptr;
+ return mt;
+}
+
+void Memory::free_section_tree(union MemoryTree *mt, size_t depth) {
+ if (depth < (MEMORY_TREE_H - 1)) { // Following level is memory tree
+ for (int i = 0; i < MEMORY_TREE_LEN; i++) {
+ if (mt[i].mt != nullptr)
+ free_section_tree(mt[i].mt, depth + 1);
+ }
+ } else { // Following level is memory section
+ for (int i = 0; i < MEMORY_TREE_LEN; i++) {
+ if (mt[i].sec != nullptr)
+ delete mt[i].sec;
+ }
+ }
+}
+
+bool Memory::compare_section_tree(const union MemoryTree *mt1, const union MemoryTree *mt2, size_t depth) {
+ if (depth < (MEMORY_TREE_H - 1)) { // Following level is memory tree
+ for (int i = 0; i < MEMORY_TREE_LEN; i++) {
+ if (
+ ((mt1[i].mt == nullptr || mt2[i].mt == nullptr) && mt1[i].mt != mt2[i].mt)
+ ||
+ (mt1[i].mt != nullptr && mt2[i].mt != nullptr && !compare_section_tree(mt1[i].mt, mt2[i].mt, depth + 1))
+ ) {
+ return false;
+ }
+ }
+ } else { // Following level is memory section
+ for (int i = 0; i < MEMORY_TREE_LEN; i++) {
+ if (
+ ((mt1[i].sec == nullptr || mt2[i].sec == nullptr) && mt1[i].sec != mt2[i].sec)
+ ||
+ (mt1[i].sec != nullptr && mt2[i].sec != nullptr && *mt1[i].sec != *mt2[i].sec)
+ ) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+union MemoryTree *Memory::copy_section_tree(const union MemoryTree *mt, size_t depth) {
+ union MemoryTree *nmt = allocate_section_tree();
+ if (depth < (MEMORY_TREE_H - 1)) { // Following level is memory tree
+ for (int i = 0; i < MEMORY_TREE_LEN; i++) {
+ if (mt[i].mt != nullptr)
+ nmt[i].mt = copy_section_tree(mt[i].mt, depth + 1);
+ }
+ } else { // Following level is memory section
+ for (int i = 0; i < MEMORY_TREE_LEN; i++) {
+ if (mt[i].sec != nullptr)
+ nmt[i].sec = new MemorySection(*mt[i].sec);
+ }
+ }
+ return nmt;
+}
diff --git a/qtmips_machine/memory.h b/qtmips_machine/memory.h
index 1df23ae..1b56d7c 100644
--- a/qtmips_machine/memory.h
+++ b/qtmips_machine/memory.h
@@ -14,7 +14,7 @@ public:
void write_hword(std::uint32_t offset, std::uint16_t value);
void write_word(std::uint32_t offset, std::uint32_t value);
- virtual std::uint8_t read_byte(std::uint32_t offset) = 0;
+ virtual std::uint8_t read_byte(std::uint32_t offset) const = 0;
std::uint16_t read_hword(std::uint32_t offset);
std::uint32_t read_word(std::uint32_t offset);
@@ -26,11 +26,20 @@ signals:
class MemorySection : public MemoryAccess {
public:
MemorySection(std::uint32_t length);
+ MemorySection(const MemorySection&);
~MemorySection();
+
void write_byte(std::uint32_t offset, std::uint8_t value);
- std::uint8_t read_byte(std::uint32_t offset);
+ std::uint8_t read_byte(std::uint32_t offset) const;
+
+ std::uint32_t length() const;
+ const std::uint8_t* data() const;
+
+ bool operator==(const MemorySection&) const;
+ bool operator!=(const MemorySection&) const;
+
private:
- std::uint32_t length;
+ std::uint32_t len;
std::uint8_t *dt;
};
@@ -48,13 +57,27 @@ class Memory : public MemoryAccess {
Q_OBJECT
public:
Memory();
+ Memory(const Memory&);
~Memory();
- MemorySection *get_section(std::uint32_t address, bool create); // returns section containing given address
+
+ MemorySection *get_section(std::uint32_t address, bool create) const; // returns section containing given address
void write_byte(std::uint32_t address, std::uint8_t value);
- std::uint8_t read_byte(std::uint32_t address);
+ std::uint8_t read_byte(std::uint32_t address) const;
+
+ bool operator==(const Memory&) const;
+ bool operator!=(const Memory&) const;
+
+ const union MemoryTree *get_memorytree_root() const;
+
private:
union MemoryTree *mt_root;
static union MemoryTree *allocate_section_tree();
+ static void free_section_tree(union MemoryTree*, size_t depth);
+ static bool compare_section_tree(const union MemoryTree*, const union MemoryTree*, size_t depth);
+ static bool is_zero_section_tree(const union MemoryTree*, size_t depth);
+ static union MemoryTree *copy_section_tree(const union MemoryTree*, size_t depth);
};
+Q_DECLARE_METATYPE(Memory)
+
#endif // MEMORY_H
diff --git a/qtmips_machine/registers.cpp b/qtmips_machine/registers.cpp
index fa984fb..6b4ddd3 100644
--- a/qtmips_machine/registers.cpp
+++ b/qtmips_machine/registers.cpp
@@ -14,12 +14,12 @@ Registers::Registers() {
this->hi = this->lo = 0;
}
-Registers::Registers(const Registers *orig) : Registers() {
- this->pc = orig->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);
+ 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 {
diff --git a/qtmips_machine/registers.h b/qtmips_machine/registers.h
index 905a212..49b4cad 100644
--- a/qtmips_machine/registers.h
+++ b/qtmips_machine/registers.h
@@ -8,7 +8,7 @@ class Registers : public QObject {
Q_OBJECT
public:
Registers();
- Registers(const Registers*);
+ Registers(const Registers&);
std::uint32_t read_pc() const; // Return current value of program counter
std::uint32_t pc_inc(); // Increment program counter by four bytes
@@ -32,4 +32,6 @@ private:
std::uint32_t pc; // program counter
};
+Q_DECLARE_METATYPE(Registers)
+
#endif // REGISTERS_H
diff --git a/qtmips_machine/tests/testalu.cpp b/qtmips_machine/tests/testalu.cpp
index 37accdf..2943906 100644
--- a/qtmips_machine/tests/testalu.cpp
+++ b/qtmips_machine/tests/testalu.cpp
@@ -3,49 +3,49 @@
#include "qtmipsexception.h"
void MachineTests::alu_data() {
- QTest::addColumn<std::uint8_t>("op");
+ QTest::addColumn<AluOp>("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 \
+ QTest::newRow("ADD") << 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 \
+ QTest::newRow("ADDU") << 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 \
+ QTest::newRow("SUB") << 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 \
+ QTest::newRow("SUBU") << 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 \
+ QTest::newRow("AND") << 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 \
+ QTest::newRow("OR") << 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 \
+ QTest::newRow("XOR") << 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 \
+ QTest::newRow("NOR") << ALU_OP_NOR \
<< (std::uint32_t)0xA81 \
<< (std::uint32_t)0x603 \
<< (std::uint8_t)0 \
@@ -54,13 +54,13 @@ void MachineTests::alu_data() {
}
void MachineTests::alu() {
- QFETCH(std::uint8_t, op);
+ QFETCH(AluOp, 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);
+ QCOMPARE(alu_operate(op, s , t, sa), res);
}
void MachineTests::alu_except_data() {
diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp
index bbf8086..33bf07e 100644
--- a/qtmips_machine/tests/testcore.cpp
+++ b/qtmips_machine/tests/testcore.cpp
@@ -2,28 +2,43 @@
#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();
+ Registers regs_init;
regs_init.write_gp(24, 12);
regs_init.write_gp(25, 24);
- Registers regs_res(&regs_init);
+ 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() {
+ QTest::addColumn<Instruction>("i");
+ QTest::addColumn<Registers>("init");
+ QTest::addColumn<Registers>("res");
+ QFETCH(Instruction, i);
+ QFETCH(Registers, init);
+ QFETCH(Registers, res);
+
+ Memory mem; // Just memory (it shouldn't be used here except instruction)
+ mem.write_word(res.read_pc(), i.data()); // Store single instruction (anything else should be 0 so NOP effectively)
+
+ // Test on non-piplined
+ Memory mem_single(mem); // Create memory copy
+ CoreSingle core_single(&init, &mem_single);
+ core_single.step(); // Single step should be enought as this is risc without pipeline
+ //QCOMPARE(init, res); // After doing changes from initial state this should be same state as in case of passed expected result
+ QCOMPARE(mem, mem_single); // There should be no change in memory
+ // TODO on pipelined core
}
void MachineTests::core_mem_data() {
diff --git a/qtmips_machine/tests/testmemory.cpp b/qtmips_machine/tests/testmemory.cpp
index e450231..091c26d 100644
--- a/qtmips_machine/tests/testmemory.cpp
+++ b/qtmips_machine/tests/testmemory.cpp
@@ -44,8 +44,7 @@ void MachineTests::memory_section() {
QFETCH(std::uint32_t, address);
- // First section shouldn't exists
- QCOMPARE(m.get_section(address, false), (MemorySection*)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);
@@ -63,7 +62,7 @@ void MachineTests::memory_section() {
void MachineTests::memory_endian() {
Memory m;
- // Memory should be bit endian so write bytes from most significant byte
+ // Memory should be little endian so write bytes from most significant byte
m.write_byte(0x00, 0x12);
m.write_byte(0x01, 0x34);
m.write_byte(0x02, 0x56);
@@ -81,3 +80,26 @@ void MachineTests::memory_endian() {
QCOMPARE(m.read_byte(0xF2), (std::uint8_t)0x56);
QCOMPARE(m.read_byte(0xF3), (std::uint8_t)0x78);
}
+
+void MachineTests::memory_compare() {
+ Memory m1, m2;
+ QCOMPARE(m1, m2);
+ m1.write_byte(0x20,0x0);
+ QVERIFY(m1 != m2); // This should not be equal as this identifies also memory write (difference between no write and zero write)
+ m1.write_byte(0x20,0x24);
+ QVERIFY(m1 != m2);
+ m2.write_byte(0x20,0x23);
+ QVERIFY(m1 != m2);
+ m2.write_byte(0x20,0x24);
+ QCOMPARE(m1, m2);
+ // Do the same with some other section
+ m1.write_byte(0xFFFF20, 0x24);
+ QVERIFY(m1 != m2);
+ m2.write_byte(0xFFFF20, 0x24);
+ QCOMPARE(m1, m2);
+ // And also check memory copy
+ Memory m3(m1);
+ QCOMPARE(m1, m3);
+ m3.write_byte(0x18, 0x22);
+ QVERIFY(m1 != m3);
+}
diff --git a/qtmips_machine/tests/tst_machine.h b/qtmips_machine/tests/tst_machine.h
index da8082a..b509bed 100644
--- a/qtmips_machine/tests/tst_machine.h
+++ b/qtmips_machine/tests/tst_machine.h
@@ -17,6 +17,7 @@ private Q_SLOTS:
void memory_section();
void memory_section_data();
void memory_endian();
+ void memory_compare();
// Program loader
void program_loader();
// Instruction