aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2019-02-15 15:03:12 +0100
committerPavel Pisa <pisa@cmp.felk.cvut.cz>2019-02-15 15:03:12 +0100
commitab9ddf2beb8a266dd31e31178c53616b79ce4428 (patch)
tree8f07e33893e6489e646000f98705306b33c2e39a
parent8f2b5459c4fc32bd4890b89b9309a2c6d24e61f9 (diff)
downloadqtmips-ab9ddf2beb8a266dd31e31178c53616b79ce4428.tar.gz
qtmips-ab9ddf2beb8a266dd31e31178c53616b79ce4428.tar.bz2
qtmips-ab9ddf2beb8a266dd31e31178c53616b79ce4428.zip
Core: move complex memory operation to own function and implement LWL, LWR, SWL, SWR.
The move makes basic memory stage processing more readable. Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
-rw-r--r--qtmips_machine/core.cpp91
-rw-r--r--qtmips_machine/core.h5
-rw-r--r--qtmips_machine/instruction.cpp16
-rw-r--r--qtmips_machine/machinedefs.h5
4 files changed, 92 insertions, 25 deletions
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp
index a276b3b..b80e297 100644
--- a/qtmips_machine/core.cpp
+++ b/qtmips_machine/core.cpp
@@ -139,6 +139,67 @@ void Core::set_c0_userlocal(std::uint32_t address) {
hwr_userlocal = address;
}
+enum ExceptionCause Core::memory_special(enum AccessControl memctl,
+ int mode, bool memread, bool memwrite,
+ std::uint32_t &towrite_val,
+ std::uint32_t rt_value, std::uint32_t mem_addr) {
+ std::uint32_t mask;
+ std::uint32_t shift;
+ std::uint32_t temp;
+ (void)mode;
+
+ switch (memctl) {
+ case AC_CACHE_OP:
+ mem_data->sync();
+ mem_program->sync();
+ break;
+ case AC_STORE_CONDITIONAL:
+ if (!memwrite)
+ break;
+ mem_data->write_ctl(AC_WORD, mem_addr, rt_value);
+ towrite_val = 1;
+ break;
+ case AC_LOAD_LINKED:
+ if (!memread)
+ break;
+ towrite_val = mem_data->read_ctl(AC_WORD, mem_addr);
+ break;
+ case AC_WORD_RIGHT:
+ if (memwrite) {
+ shift = (3 - (mem_addr & 3)) << 3;
+ mask = 0xffffffff << shift;
+ temp = mem_data->read_ctl(AC_WORD, mem_addr & ~3);
+ temp = (temp & ~mask) | (rt_value << shift);
+ mem_data->write_ctl(AC_WORD, mem_addr & ~3, temp);
+ } else {
+ shift = (3 - (mem_addr & 3)) << 3;
+ mask = 0xffffffff >> shift;
+ towrite_val = mem_data->read_ctl(AC_WORD, mem_addr & ~3);
+ towrite_val = (towrite_val >> shift) | (rt_value & ~mask);
+ }
+ break;
+ case AC_WORD_LEFT:
+ if (memwrite) {
+ shift = (mem_addr & 3) << 3;
+ mask = 0xffffffff >> shift;
+ temp = mem_data->read_ctl(AC_WORD, mem_addr & ~3);
+ temp = (temp & ~mask) | (rt_value >> shift);
+ mem_data->write_ctl(AC_WORD, mem_addr & ~3, temp);
+ } else {
+ shift = (mem_addr & 3) << 3;
+ mask = 0xffffffff << shift;
+ towrite_val = mem_data->read_ctl(AC_WORD, mem_addr & ~3);
+ towrite_val = (towrite_val << shift) | (rt_value & ~mask);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return EXCAUSE_NONE;
+}
+
+
struct Core::dtFetch Core::fetch(bool skip_break) {
enum ExceptionCause excause = EXCAUSE_NONE;
std::uint32_t inst_addr = regs->read_pc();
@@ -321,31 +382,27 @@ struct Core::dtExecute Core::execute(const struct dtDecode &dt) {
struct Core::dtMemory Core::memory(const struct dtExecute &dt) {
std::uint32_t towrite_val = dt.alu_val;
std::uint32_t mem_addr = dt.alu_val;
+ enum ExceptionCause excause = dt.excause;
bool memread = dt.memread;
bool memwrite = dt.memwrite;
bool regwrite = dt.regwrite;
+ if (excause == EXCAUSE_NONE) {
+ if (dt.memctl > AC_LAST_REGULAR) {
+ excause = memory_special(dt.memctl, dt.inst.rt(), memread, memwrite,
+ towrite_val, dt.val_rt, mem_addr);
+ } else {
+ if (memwrite)
+ mem_data->write_ctl(dt.memctl, mem_addr, dt.val_rt);
+ if (memread)
+ towrite_val = mem_data->read_ctl(dt.memctl, mem_addr);
+ }
+ }
+
if (dt.excause != EXCAUSE_NONE) {
memread = false;
memwrite = false;
regwrite = false;
- } else {
- if (dt.memctl == AC_CACHE_OP) {
- mem_data->sync();
- mem_program->sync();
- } else if (memwrite) {
- if (dt.memctl == AC_STORE_CONDITIONAL) {
- mem_data->write_ctl(AC_WORD, mem_addr, dt.val_rt);
- towrite_val = 1;
- } else {
- mem_data->write_ctl(dt.memctl, mem_addr, dt.val_rt);
- }
- } else if (memread) {
- if (dt.memctl == AC_LOAD_LINKED)
- towrite_val = mem_data->read_ctl(AC_WORD, mem_addr);
- else
- towrite_val = mem_data->read_ctl(dt.memctl, mem_addr);
- }
}
emit memory_inst_addr_value(dt.inst_addr);
diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h
index 889a30c..7784797 100644
--- a/qtmips_machine/core.h
+++ b/qtmips_machine/core.h
@@ -234,6 +234,11 @@ protected:
void writeback(const struct dtMemory&);
bool handle_pc(const struct dtDecode&);
+ enum ExceptionCause memory_special(enum AccessControl memctl,
+ int mode, bool memread, bool memwrite,
+ std::uint32_t &towrite_val,
+ std::uint32_t rt_value, std::uint32_t mem_addr);
+
// Initialize structures to NOPE instruction
void dtFetchInit(struct dtFetch &dt);
void dtDecodeInit(struct dtDecode &dt);
diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp
index 0788eac..417d940 100644
--- a/qtmips_machine/instruction.cpp
+++ b/qtmips_machine/instruction.cpp
@@ -432,29 +432,29 @@ static const struct InstructionMap instruction_map[] = {
.flags = FLAGS_ALU_I_LOAD},
{"LH", IT_I, ALU_OP_ADDU, AC_HALFWORD, nullptr, // LH
.flags = FLAGS_ALU_I_LOAD},
- {"LWL", IT_I, ALU_OP_ADDU, NOMEM, nullptr, // LWL - unsupported
- .flags = IMF_MEM},
+ {"LWL", IT_I, ALU_OP_ADDU, AC_WORD_LEFT, nullptr, // LWL - unsupported
+ .flags = FLAGS_ALU_I_LOAD | IMF_ALU_REQ_RT},
{"LW", IT_I, ALU_OP_ADDU, AC_WORD, nullptr, // LW
.flags = FLAGS_ALU_I_LOAD},
{"LBU", IT_I, ALU_OP_ADDU, AC_BYTE_UNSIGNED, nullptr, // LBU
.flags = FLAGS_ALU_I_LOAD},
{"LHU", IT_I, ALU_OP_ADDU, AC_HALFWORD_UNSIGNED, nullptr, // LHU
.flags = FLAGS_ALU_I_LOAD},
- {"LWR", IT_I, ALU_OP_ADDU, NOMEM, nullptr, // LWR - unsupported
- .flags = IMF_MEM},
+ {"LWR", IT_I, ALU_OP_ADDU, AC_WORD_RIGHT, nullptr, // LWR - unsupported
+ .flags = FLAGS_ALU_I_LOAD | IMF_ALU_REQ_RT},
IM_UNKNOWN, // 39
{"SB", IT_I, ALU_OP_ADDU, AC_BYTE, nullptr, // SB
.flags = FLAGS_ALU_I_STORE},
{"SH", IT_I, ALU_OP_ADDU, AC_HALFWORD, nullptr, // SH
.flags = FLAGS_ALU_I_STORE},
- {"SWL", IT_I, ALU_OP_ADDU, NOMEM, nullptr, // SWL
- .flags = IMF_MEM | IMF_MEMWRITE},
+ {"SWL", IT_I, ALU_OP_ADDU, AC_WORD_LEFT, nullptr, // SWL
+ .flags = FLAGS_ALU_I_STORE},
{"SW", IT_I, ALU_OP_ADDU, AC_WORD, nullptr, // SW
.flags = FLAGS_ALU_I_STORE},
IM_UNKNOWN, // 44
IM_UNKNOWN, // 45
- {"SWR", IT_I, ALU_OP_ADDU, NOMEM, nullptr, // SWR
- .flags = IMF_MEM | IMF_MEMWRITE},
+ {"SWR", IT_I, ALU_OP_ADDU, AC_WORD_RIGHT, nullptr, // SWR
+ .flags = FLAGS_ALU_I_STORE},
{"CACHE", IT_I, ALU_OP_ADDU, AC_CACHE_OP, nullptr, // CACHE
.flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_MEM},
{"LL", IT_I, ALU_OP_ADDU, AC_LOAD_LINKED, nullptr, // LL
diff --git a/qtmips_machine/machinedefs.h b/qtmips_machine/machinedefs.h
index ef9ec0d..362bda2 100644
--- a/qtmips_machine/machinedefs.h
+++ b/qtmips_machine/machinedefs.h
@@ -49,7 +49,12 @@ enum AccessControl {
AC_HALFWORD_UNSIGNED,
AC_LOAD_LINKED,
AC_STORE_CONDITIONAL,
+ AC_WORD_RIGHT,
+ AC_WORD_LEFT,
AC_CACHE_OP,
+
+ AC_FIRST_REGULAR = AC_BYTE,
+ AC_LAST_REGULAR = AC_HALFWORD_UNSIGNED,
};
enum ExceptionCause {