diff options
Diffstat (limited to 'qtmips_machine')
| -rw-r--r-- | qtmips_machine/core.cpp | 82 | ||||
| -rw-r--r-- | qtmips_machine/core.h | 9 | ||||
| -rw-r--r-- | qtmips_machine/tests/testcore.cpp | 116 | ||||
| -rw-r--r-- | qtmips_machine/tests/testmemory.cpp | 58 | ||||
| -rw-r--r-- | qtmips_machine/tests/tst_machine.h | 10 | 
5 files changed, 236 insertions, 39 deletions
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp index 5f8321d..eba423f 100644 --- a/qtmips_machine/core.cpp +++ b/qtmips_machine/core.cpp @@ -2,41 +2,41 @@  #include "programloader.h"  #define DM_SUPPORTED (1L<<0) -#define DM_MEM2REG (1L<<1) -#define DM_MEMWRITE (1L<<2) +#define DM_MEMWRITE (1L<<1) +#define DM_MEMREAD (1L<<2)  #define DM_ALUSRC (1L<<3)  #define DM_REGD (1L<<4)  #define DM_REGWRITE (1L<<5) - struct DecodeMap { +struct DecodeMap {      long flags;      enum AluOp alu; +    enum MemoryAccess::AccessControl mem_ctl;  }; - -// This is temporally operation place holder  #define NOALU .alu = ALU_OP_SLL -#define NOPE { .flags = 0, NOALU } +#define NOMEM .mem_ctl = MemoryAccess::AC_NONE +#define NOPE { .flags = 0, NOALU, NOMEM }  #define FLAGS_ALU_I (DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE)  // This is map from opcode to signals.  static const struct DecodeMap dmap[]  = { -    { .flags = DM_SUPPORTED | DM_REGD | DM_REGWRITE, NOALU }, // Alu operations (aluop is decoded from function explicitly) -    { .flags = DM_SUPPORTED, NOALU }, // REGIMM (BLTZ, BGEZ, ) -    { .flags = DM_SUPPORTED, NOALU }, // J +    { .flags = DM_SUPPORTED | DM_REGD | DM_REGWRITE, NOALU, NOMEM }, // Alu operations (aluop is decoded from function explicitly) +    { .flags = DM_SUPPORTED, NOALU, NOMEM }, // REGIMM (BLTZ, BGEZ, ) +    { .flags = DM_SUPPORTED, NOALU, NOMEM }, // J      NOPE, // JAL -    { .flags = DM_SUPPORTED, NOALU }, // BEQ -    { .flags = DM_SUPPORTED, NOALU }, // BNE -    { .flags = DM_SUPPORTED, NOALU }, // BLEZ -    { .flags = DM_SUPPORTED, NOALU }, // BGTZ -    { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADD }, // ADDI -    { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADDU }, // ADDIU -    { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLT }, // SLTI -    { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLTU }, // SLTIU -    { .flags = FLAGS_ALU_I, .alu = ALU_OP_AND }, // ANDI -    { .flags = FLAGS_ALU_I, .alu = ALU_OP_OR }, // ORI -    { .flags = FLAGS_ALU_I, .alu = ALU_OP_XOR }, // XORI +    { .flags = DM_SUPPORTED, NOALU, NOMEM }, // BEQ +    { .flags = DM_SUPPORTED, NOALU, NOMEM }, // BNE +    { .flags = DM_SUPPORTED, NOALU, NOMEM }, // BLEZ +    { .flags = DM_SUPPORTED, NOALU, NOMEM }, // BGTZ +    { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADD, NOMEM }, // ADDI +    { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADDU, NOMEM }, // ADDIU +    { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLT, NOMEM }, // SLTI +    { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLTU, NOMEM }, // SLTIU +    { .flags = FLAGS_ALU_I, .alu = ALU_OP_AND, NOMEM }, // ANDI +    { .flags = FLAGS_ALU_I, .alu = ALU_OP_OR, NOMEM }, // ORI +    { .flags = FLAGS_ALU_I, .alu = ALU_OP_XOR, NOMEM }, // XORI      NOPE, // LUI      NOPE, // 16      NOPE, // 17 @@ -54,18 +54,18 @@ static const struct DecodeMap dmap[]  = {      NOPE, // 29      NOPE, // 30      NOPE, // 31 -    NOPE, // LB -    NOPE, // LH +    { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_BYTE }, // LB +    { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_HALFWORD }, // LH      NOPE, // LWL -    NOPE, // LW -    NOPE, // LBU -    NOPE, // LHU +    { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_WORD }, // LW +    { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_BYTE_UNSIGNED }, // LBU +    { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_HALFWORD_UNSIGNED }, // LHU      NOPE, // LWR      NOPE, // 39 -    NOPE, // SB -    NOPE, // SH +    { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_BYTE }, // SB +    { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_HALFWORD }, // SH      NOPE, // SWL -    NOPE, // SW +    { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_WORD }, // SW      NOPE, // 44      NOPE, // 45      NOPE, // SWR @@ -113,12 +113,13 @@ struct Core::dtDecode Core::decode(struct dtFetch dt) {      return {          .inst = dt.inst, -        .mem2reg = dec.flags & DM_MEM2REG, +        .memread = dec.flags & DM_MEMREAD,          .memwrite = dec.flags & DM_MEMWRITE,          .alusrc = dec.flags & DM_ALUSRC,          .regd = dec.flags & DM_REGD,          .regwrite = dec.flags & DM_REGWRITE,          .aluop = dt.inst.opcode() == 0 ? (enum AluOp)dt.inst.funct() : dec.alu, +        .memctl = dec.mem_ctl,          .val_rs = rs,          .val_rt = rt,      }; @@ -139,7 +140,11 @@ struct Core::dtExecute Core::execute(struct dtDecode dt) {          alu_sec = ((dt.inst.immediate() & 0x8000) << 16) | (dt.inst.immediate() & 0x7FFF); // Sign extend to 32bit      return { +        .memread = dt.memread, +        .memwrite = dt.memwrite,          .regwrite = regwrite, +        .memctl = dt.memctl, +        .val_rt = dt.val_rt,          .rwrite = dt.regd ? dt.inst.rd() : dt.inst.rt(),          .alu_val = alu_operate(dt.aluop, dt.val_rs, alu_sec, dt.inst.shamt(), regs),      }; @@ -147,16 +152,23 @@ struct Core::dtExecute Core::execute(struct dtDecode dt) {  struct Core::dtMemory Core::memory(struct dtExecute dt) {      // TODO signals +    std::uint32_t towrite_val = dt.alu_val; + +    if (dt.memwrite) +        mem->write_ctl(dt.memctl, dt.alu_val, dt.val_rt); +    else if (dt.memread) +        towrite_val = mem->read_ctl(dt.memctl, dt.alu_val); +      return {          .regwrite = dt.regwrite,          .rwrite = dt.rwrite, -        .alu_val = dt.alu_val, +        .towrite_val = towrite_val,      };  }  void Core::writeback(struct dtMemory dt) {      if (dt.regwrite) { -        regs->write_gp(dt.rwrite, dt.alu_val); +        regs->write_gp(dt.rwrite, dt.towrite_val);      }  } @@ -217,7 +229,7 @@ void Core::dtFetchInit(struct dtFetch &dt) {  void Core::dtDecodeInit(struct dtDecode &dt) {      dt.inst = Instruction(0x00); -    dt.mem2reg = false; +    dt.memread = false;      dt.memwrite = false;      dt.alusrc = false;      dt.regd = false; @@ -228,7 +240,11 @@ void Core::dtDecodeInit(struct dtDecode &dt) {  }  void Core::dtExecuteInit(struct dtExecute &dt) { +    dt.memread = false; +    dt.memwrite = false;      dt.regwrite = false; +    dt.memctl = MemoryAccess::AC_NONE; +    dt.val_rt = 0;      dt.rwrite = false;      dt.alu_val = 0;  } @@ -236,7 +252,7 @@ void Core::dtExecuteInit(struct dtExecute &dt) {  void Core::dtMemoryInit(struct dtMemory &dt) {      dt.regwrite = false;      dt.rwrite = false; -    dt.alu_val = 0; +    dt.towrite_val = 0;  }  CoreSingle::CoreSingle(Registers *regs, MemoryAccess *mem) : \ diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h index e583235..07933ab 100644 --- a/qtmips_machine/core.h +++ b/qtmips_machine/core.h @@ -26,24 +26,29 @@ protected:      };      struct dtDecode {          Instruction inst; -        bool mem2reg; // Write memory output to register (instead alu output) +        bool memread; // If memory should be read          bool memwrite; // If memory should write input          bool alusrc; // If second 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)          enum AluOp aluop; // Decoded ALU operation +        enum MemoryAccess::AccessControl memctl; // Decoded memory access type          std::uint32_t val_rs; // Value from register rs          std::uint32_t val_rt; // Value from register rt      };      struct dtExecute { +        bool memread; +        bool memwrite;          bool regwrite; +        enum MemoryAccess::AccessControl memctl; +        std::uint32_t val_rt;          std::uint8_t rwrite; // Writeback register (multiplexed between rt and rd according to regd)          std::uint32_t alu_val; // Result of ALU execution      };      struct dtMemory {          bool regwrite;          std::uint8_t rwrite; -        std::uint32_t alu_val; +        std::uint32_t towrite_val;      };      struct dtFetch fetch(); diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp index 593483a..c8f1a17 100644 --- a/qtmips_machine/tests/testcore.cpp +++ b/qtmips_machine/tests/testcore.cpp @@ -247,6 +247,7 @@ static void core_jmp_data() {                           << regs \                           << 0x80000000 + (24 << 2);      /* +     * TODO      QTest::newRow("JR") << Instruction(1, 15, 0, 61) \                           << regs \                           << regs.read_pc() + (24 << 2); @@ -305,10 +306,121 @@ void MachineTests::pipecore_jmp() {      QCOMPARE(regs, regs_used); // There should be no change in registers now (except pc)  } -void MachineTests::core_mem_data() { +static void core_mem_data() { +    QTest::addColumn<Instruction>("i"); +    QTest::addColumn<Registers>("regs_init"); +    QTest::addColumn<Registers>("regs_res"); +    QTest::addColumn<Memory>("mem_init"); +    QTest::addColumn<Memory>("mem_res"); + +    // Load +    { +    Memory mem; +    mem.write_word(0x24, 0xA3242526); +    Registers regs; +    regs.write_gp(1, 0x22); +    Registers regs_res(regs); +    regs_res.write_gp(21, 0x80000023); +    QTest::newRow("LB") << Instruction(32, 1, 21, 0x2) \ +                         << regs \ +                         << regs_res \ +                         << mem \ +                         << mem; +    regs_res.write_gp(21, 0x80002324); +    QTest::newRow("LH") << Instruction(33, 1, 21, 0x2) \ +                         << regs \ +                         << regs_res \ +                         << mem \ +                         << mem; +    regs_res.write_gp(21, 0xA3242526); +    QTest::newRow("LW") << Instruction(35, 1, 21, 0x2) \ +                         << regs \ +                         << regs_res \ +                         << mem \ +                         << mem; +    regs_res.write_gp(21, 0x000000A3); +    QTest::newRow("LBU") << Instruction(36, 1, 21, 0x2) \ +                         << regs \ +                         << regs_res \ +                         << mem \ +                         << mem; +    regs_res.write_gp(21, 0x0000A324); +    QTest::newRow("LHU") << Instruction(37, 1, 21, 0x2) \ +                         << regs \ +                         << regs_res \ +                         << mem \ +                         << mem; +    } +    // Store +    { +    Registers regs; +    regs.write_gp(1, 0x22); +    regs.write_gp(21, 0x23242526); +    Memory mem; +    mem.write_byte(0x24, 0x26); // Note: store least significant byte +    QTest::newRow("SB") << Instruction(40, 1, 21, 0x2) \ +                         << regs \ +                         << regs \ +                         << Memory() \ +                         << mem; +    mem.write_hword(0x24, 0x2526); +    QTest::newRow("SH") << Instruction(41, 1, 21, 0x2) \ +                         << regs \ +                         << regs \ +                         << Memory() \ +                         << mem; +    mem.write_word(0x24, 0x23242526); +    QTest::newRow("SH") << Instruction(43, 1, 21, 0x2) \ +                         << regs \ +                         << regs \ +                         << Memory() \ +                         << mem; +    } +} + +void MachineTests::singlecore_mem_data() { +    core_mem_data(); +} + +void MachineTests::pipecore_mem_data() { +    core_mem_data(); +} + +void MachineTests::singlecore_mem() { +    QFETCH(Instruction, i); +    QFETCH(Registers, regs_init); +    QFETCH(Registers, regs_res); +    QFETCH(Memory, mem_init); +    QFETCH(Memory, mem_res); + +    // Write instruction to both memories +    mem_init.write_word(regs_init.read_pc(), i.data()); +    mem_res.write_word(regs_init.read_pc(), i.data()); +    CoreSingle core(®s_init, &mem_init); +    core.step(); + +    regs_res.pc_inc(); +    QCOMPARE(regs_init, regs_res); +    QCOMPARE(mem_init, mem_res);  } -void MachineTests::core_mem() { +void MachineTests::pipecore_mem() { +    QFETCH(Instruction, i); +    QFETCH(Registers, regs_init); +    QFETCH(Registers, regs_res); +    QFETCH(Memory, mem_init); +    QFETCH(Memory, mem_res); + +    // Write instruction to both memories +    mem_init.write_word(regs_init.read_pc(), i.data()); +    mem_res.write_word(regs_init.read_pc(), i.data()); + +    CorePipelined core(®s_init, &mem_init); +    for (int i = 0; i < 5; i++) +        core.step(); // Fire steps for five pipelines stages +    regs_res.pc_jmp(20); +    QCOMPARE(regs_init, regs_res); +    QCOMPARE(mem_init, mem_res);  } diff --git a/qtmips_machine/tests/testmemory.cpp b/qtmips_machine/tests/testmemory.cpp index 091c26d..f1c6b80 100644 --- a/qtmips_machine/tests/testmemory.cpp +++ b/qtmips_machine/tests/testmemory.cpp @@ -103,3 +103,61 @@ void MachineTests::memory_compare() {      m3.write_byte(0x18, 0x22);      QVERIFY(m1 != m3);  } + +void MachineTests::memory_write_ctl_data() { +    QTest::addColumn<MemoryAccess::AccessControl>("ctl"); +    QTest::addColumn<Memory>("result"); + +    Memory mem; +    QTest::newRow("none") << MemoryAccess::AC_NONE \ +                          << mem; +    mem.write_byte(0x20, 0x26); +    QTest::newRow("byte") << MemoryAccess::AC_BYTE \ +                          << mem; +    QTest::newRow("byte-unsigned") << MemoryAccess::AC_BYTE_UNSIGNED \ +                          << mem; +    mem.write_hword(0x20, 0x2526); +    QTest::newRow("halfword") << MemoryAccess::AC_HALFWORD \ +                          << mem; +    QTest::newRow("haldword-unsigned") << MemoryAccess::AC_HALFWORD_UNSIGNED \ +                          << mem; +    mem.write_word(0x20, 0x23242526); +    QTest::newRow("word") << MemoryAccess::AC_WORD \ +                          << mem; +} + +void MachineTests::memory_write_ctl() { +    QFETCH(MemoryAccess::AccessControl, ctl); +    QFETCH(Memory, result); + +    Memory mem; +    mem.write_ctl(ctl, 0x20, 0x23242526); +    QCOMPARE(mem, result); +} + +void MachineTests::memory_read_ctl_data() { +    QTest::addColumn<MemoryAccess::AccessControl>("ctl"); +    QTest::addColumn<std::uint32_t>("result"); + +    QTest::newRow("none") << MemoryAccess::AC_NONE \ +                          << (std::uint32_t)0; +    QTest::newRow("byte") << MemoryAccess::AC_BYTE \ +                          << (std::uint32_t)0x80000023; +    QTest::newRow("halfword") << MemoryAccess::AC_HALFWORD \ +                          << (std::uint32_t)0x80002324; +    QTest::newRow("word") << MemoryAccess::AC_WORD \ +                          << (std::uint32_t)0xA3242526; +    QTest::newRow("byte-unsigned") << MemoryAccess::AC_BYTE_UNSIGNED \ +                          << (std::uint32_t)0xA3; +    QTest::newRow("halfword-unsigned") << MemoryAccess::AC_HALFWORD_UNSIGNED \ +                          << (std::uint32_t)0xA324; +} + +void MachineTests::memory_read_ctl() { +    QFETCH(MemoryAccess::AccessControl, ctl); +    QFETCH(std::uint32_t, result); + +    Memory mem; +    mem.write_word(0x20, 0xA3242526); +    QCOMPARE(mem.read_ctl(ctl, 0x20), result); +} diff --git a/qtmips_machine/tests/tst_machine.h b/qtmips_machine/tests/tst_machine.h index 9b33e68..ad3112c 100644 --- a/qtmips_machine/tests/tst_machine.h +++ b/qtmips_machine/tests/tst_machine.h @@ -19,6 +19,10 @@ private Q_SLOTS:      void memory_section_data();      void memory_endian();      void memory_compare(); +    void memory_write_ctl(); +    void memory_write_ctl_data(); +    void memory_read_ctl(); +    void memory_read_ctl_data();      // Program loader      void program_loader();      // Instruction @@ -38,8 +42,10 @@ private Q_SLOTS:      void singlecore_jmp_data();      void pipecore_jmp();      void pipecore_jmp_data(); -    void core_mem(); -    void core_mem_data(); +    void singlecore_mem(); +    void singlecore_mem_data(); +    void pipecore_mem(); +    void pipecore_mem_data();  };  #endif // TST_MACHINE_H  | 
