diff options
Diffstat (limited to 'qtmips_machine')
| -rw-r--r-- | qtmips_machine/alu.h | 3 | ||||
| -rw-r--r-- | qtmips_machine/instruction.cpp | 8 | ||||
| -rw-r--r-- | qtmips_machine/instruction.h | 8 | ||||
| -rw-r--r-- | qtmips_machine/memory.cpp | 123 | ||||
| -rw-r--r-- | qtmips_machine/memory.h | 33 | ||||
| -rw-r--r-- | qtmips_machine/registers.cpp | 10 | ||||
| -rw-r--r-- | qtmips_machine/registers.h | 4 | ||||
| -rw-r--r-- | qtmips_machine/tests/testalu.cpp | 22 | ||||
| -rw-r--r-- | qtmips_machine/tests/testcore.cpp | 23 | ||||
| -rw-r--r-- | qtmips_machine/tests/testmemory.cpp | 28 | ||||
| -rw-r--r-- | qtmips_machine/tests/tst_machine.h | 1 | 
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(®s_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  | 
