diff --git a/include/decoder.h b/include/decoder.h index 68fa0f3..e81a3c8 100644 --- a/include/decoder.h +++ b/include/decoder.h @@ -111,11 +111,12 @@ namespace patmos /// has to point to an array of at least two elements. /// @param result A pointer to an array to store the data of the decoded /// instructions. - /// @param throw_error If true, throws an error instead of returning 0 + /// @param throw_error If true, when invalid bytes are encountered, return 0 + /// if false, returns the invalid instruction /// @return The number of words occupied by the decoded instructions, i.e., /// 1 or 2 if the instructions were decoded successfully, 0 in case of an /// error. - unsigned int decode(word_t *iwp, instruction_data_t *result, bool throw_error=false); + unsigned int decode(word_t *iwp, instruction_data_t *result, bool throw_error=true); /// Decode a stream of instructions provided by a binary loader. /// @return 0 on success, or any error code returned by the callback handler diff --git a/include/instruction.h b/include/instruction.h index 42468ae..baaaf89 100644 --- a/include/instruction.h +++ b/include/instruction.h @@ -160,10 +160,78 @@ namespace patmos virtual void MW(simulator_t &s, instruction_data_t &ops) const = 0; }; + /// An instruction representing fetched bytes that aren't an instruction + class i_invalid_t : public instruction_t + { + public: + /// Print the instruction to an output stream. + /// @param os The output stream to print to. + /// @param ops The operands of the instruction. + /// @param symbols A mapping of addresses to symbols. + virtual void print(std::ostream &os, const instruction_data_t &ops, + const symbol_map_t &symbols) const + { + os << "invalid"; + } + + /// Print the instruction to an output stream. + /// @param os The output stream to print to. + /// @param ops The operands of the instruction. + /// @param symbols A mapping of addresses to symbols. + virtual void print_operands(const simulator_t &s, std::ostream &os, + const instruction_data_t &ops, + const symbol_map_t &symbols) const + { } + + /// Returns false, nop is not a flow control instruction + virtual bool is_flow_control() const + { + return false; + } + + virtual unsigned get_delay_slots(const instruction_data_t &ops) const + { + return 0; + } + + virtual unsigned get_intr_delay_slots(const instruction_data_t &ops) const + { + + return 0; + } + + /// Pipeline function to simulate the behavior of the instruction in + /// the DR pipeline stage. + /// @param s The Patmos simulator executing the instruction. + /// @param ops The operands of the instruction. + virtual void DR(simulator_t &s, instruction_data_t &ops) const + { + } + + /// Pipeline function to simulate the behavior of the instruction in + /// the EX pipeline stage. + /// @param s The Patmos simulator executing the instruction. + /// @param ops The operands of the instruction. + virtual void EX(simulator_t &s, instruction_data_t &ops) const + { + } + + /// Pipeline function to simulate the behavior of the instruction in + /// the MW pipeline stage. + /// @param s The Patmos simulator executing the instruction. + /// @param ops The operands of the instruction. + virtual void MW(simulator_t &s, instruction_data_t &ops) const + { + } + }; + + /// Data structure to keep data of instructions while executing. class instruction_data_t { public: + /// The invalid instruction. (for use with I) + static i_invalid_t Invalid_Instr; /// The instruction class that implements the behavior. const instruction_t *I; @@ -380,6 +448,9 @@ namespace patmos // -------------------- CONSTRUCTOR FUNCTIONS ------------------------------ + /// Create an invalid instruction + static instruction_data_t mk_invalid(); + /// Create an ALUi or ALUl instruction with a register operands, an /// immediate, and a register destination. /// @param i The instruction. diff --git a/include/instructions.h b/include/instructions.h index 7f09f5d..3634eba 100755 --- a/include/instructions.h +++ b/include/instructions.h @@ -78,7 +78,7 @@ namespace patmos /// @param os The output stream to print to. /// @param ops The operands of the instruction. /// @param symbols A mapping of addresses to symbols. - virtual void print_operands(const simulator_t &s, std::ostream &os, + virtual void print_operands(const simulator_t &s, std::ostream &os, const instruction_data_t &ops, const symbol_map_t &symbols) const { } @@ -98,7 +98,7 @@ namespace patmos { return 0; } - + /// Pipeline function to simulate the behavior of the instruction in /// the DR pipeline stage. /// @param s The Patmos simulator executing the instruction. @@ -2087,7 +2087,7 @@ namespace patmos s.pipeline_flush(SMW); if (!ops.OPS.CFLi.D){ - // The above flush resets the execution stage's. + // The above flush resets the execution stages. // We reassign it here in case we are stalling, such that the repeated // calls to this function will get the right "ret_pc" every time. s.Pipeline[SEX][0].Address = ret_pc; @@ -2599,11 +2599,12 @@ namespace patmos if (ops.DR_Pred && ops.EX_Base == 0) { s.halt(); + s.pipeline_flush(SMW); } else if (ops.DR_Pred) { pop_dbgstack(s, ops, ops.DR_Pred, ops.EX_Base, ops.EX_Offset); - + fetch_and_dispatch(s, ops, ops.DR_Pred, ops.EX_Base, ops.EX_Address); if (!ops.OPS.CFLri.D && ops.DR_Pred) diff --git a/src/decoder.cc b/src/decoder.cc index fe535aa..611d038 100644 --- a/src/decoder.cc +++ b/src/decoder.cc @@ -99,9 +99,11 @@ namespace patmos { // unknown instruction -- report error if(throw_error) { - simulation_exception_t::illegal(from_big_endian(iwp[0])); + return 0; } else { - return 0; + result[0] = instruction_data_t::mk_invalid(); + result[1] = instruction_data_t(); + return 1; } } else if (size == 2) @@ -132,9 +134,10 @@ namespace patmos { // unknown instruction or invalid encoding? -- report error if(throw_error) { - simulation_exception_t::illegal(from_big_endian(iwp[1])); + return 0; } else { - return 0; + result[1] = instruction_data_t::mk_invalid(); + return 2; } } diff --git a/src/instruction.cc b/src/instruction.cc index 2fd3a92..c652df2 100644 --- a/src/instruction.cc +++ b/src/instruction.cc @@ -39,6 +39,10 @@ namespace patmos { + + + i_invalid_t instruction_data_t::Invalid_Instr; + instruction_data_t::instruction_data_t() : I(NULL), Address(0), Pred(pn0) { } @@ -48,6 +52,10 @@ namespace patmos { } + instruction_data_t instruction_data_t::mk_invalid() { + return instruction_data_t(instruction_data_t::Invalid_Instr, pn0); + } + instruction_data_t instruction_data_t::mk_ALUil(const instruction_t &i, PRR_e pred, GPR_e rd, GPR_e rs1, word_t imm2) diff --git a/src/simulation-core.cc b/src/simulation-core.cc index a483688..2457ed3 100644 --- a/src/simulation-core.cc +++ b/src/simulation-core.cc @@ -168,6 +168,15 @@ namespace patmos // invoke simulation functions for(unsigned int i = 0; i < NUM_SLOTS; i++) { + // If an invalid instruction reaches its execution stage, throw error + // This is because the predicate of preceding instructions may decide whether succeeding instruction + // execute. Predicates are only ready in the execution stage of preceding instruction, where + // invalids might be flushed. If not, then we are sure the invalid should have been executed + // and can therefore error + if(f == &instruction_data_t::EX && Pipeline[pst][i].I == &instruction_data_t::Invalid_Instr){ + patmos::simulation_exception_t::illegal("", Pipeline[pst][i]); + } + // debug output if (debug) { @@ -326,7 +335,7 @@ namespace patmos else { // decode the instruction word. - unsigned int iw_size = Decoder.decode(iw, instr_SIF, true); + unsigned int iw_size = Decoder.decode(iw, instr_SIF, false); assert(iw_size != 0); // First pipeline is special.. handle branches and loads. @@ -366,7 +375,6 @@ namespace patmos bool debug_nopc, uint64_t max_cycles, bool collect_instr_stats) { - // do some initializations before executing the first instruction. if (Cycle == 0) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 04a83d4..f567928 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -195,6 +195,12 @@ test_asm(72 "Errors : 0") test_asm(73 "Errors : 0") +test_asm(74 "Errors : 0") + +test_asm(75 "Errors : 0") + +test_asm(76 "Errors : 0") + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # SIMULATOR TESTS # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -381,13 +387,13 @@ test_elf_exit_sim(53 "r1 : 00000000") test_elf_exit_sim(54 "r1 : 0000007b r2 : 000001c8") -test_sim(55 "\\\\\\[Error\\\\\\] Illegal instruction: 12882180.*PC : 00000014") +test_sim(55 "\\\\\\[Error\\\\\\] Illegal instruction:.*00000018:.*invalid") test_sim_arg(55 "--permissive-dual-issue" "r3 : 0000007b r4 : 000001c8") test_sim_arg(56 "--permissive-dual-issue" "\\\\\\[Error\\\\\\] Illegal instruction: Two simultaneously enabled load/store.*\\\\\\( p1\\\\\\) lwm r3 = \\\\\\[r1 \\\\\\+ 0\\\\\\]") -test_sim(57 "\\\\\\[Error\\\\\\] Illegal instruction: 1ac62200.*PC : 00000024") +test_sim(57 "\\\\\\[Error\\\\\\] Illegal instruction:.*00000028:.*invalid") test_sim_arg(57 "--permissive-dual-issue" "r5 : 0000000c r6 : 00000022") @@ -395,19 +401,19 @@ test_sim_arg(58 "--permissive-dual-issue" "\\\\\\[Error\\\\\\] Illegal instructi test_sim_arg(59 "--permissive-dual-issue" "\\\\\\[Error\\\\\\] Illegal instruction: Two simultaneously enabled load/store.*\\\\\\( p7\\\\\\) lwc r3 = \\\\\\[r0 \\\\\\+ 0\\\\\\]") -test_sim(60 "\\\\\\[Error\\\\\\] Illegal instruction: 04c0000c.*PC : 00000014") +test_sim(60 "\\\\\\[Error\\\\\\] Illegal instruction:.*00000018:.*invalid") test_sim_arg(60 "--permissive-dual-issue" "r1 : 0000007b r2 : 000001c8 r3 : 0000009f r4 : 000002f1") test_sim_arg(61 "--permissive-dual-issue" "\\\\\\[Error\\\\\\] Illegal instruction: Two simultaneously enabled control-flow operations.*br 8") -test_sim(62 "\\\\\\[Error\\\\\\] Illegal instruction: 4440001e") +test_sim(62 "\\\\\\[Error\\\\\\] Illegal instruction:") test_sim_arg(62 "--permissive-dual-issue" "r1 : 0000006f.*r2 : 000000de.*r3 : 0000014d.*r4 : 000001bc.*r5 : 0000022b.*r6 : 0000029a.*r7 : 00000309.*r8 : 00000378") test_sim_arg(63 "--permissive-dual-issue" "\\\\\\[Error\\\\\\] Illegal instruction: Two simultaneously enabled control-flow operations.*br 8") -test_sim(64 "\\\\\\[Error\\\\\\] Illegal instruction: 02c00100") +test_sim(64 "\\\\\\[Error\\\\\\] Illegal instruction:") test_sim_arg(64 "--permissive-dual-issue" "r3 : 0000007b.*r4 : 000001c8.*r5 : 00000315") @@ -421,10 +427,16 @@ test_sim_arg(69 "--permissive-dual-issue" "\\\\\\[Error\\\\\\] Illegal instructi test_sim_arg(70 "--permissive-dual-issue" "r1 : 0000007b.*r3 : 000001c8") -test_sim(71 "\\\\\\[Error\\\\\\] Illegal instruction: 02001121") +test_sim(71 "\\\\\\[Error\\\\\\] Illegal instruction:") test_sim_arg(71 "--permissive-dual-issue" "r3 : 0000007b.*s2 : 00000002.*s3 : 00000001") test_sim_arg(72 "--permissive-dual-issue" "r4 : 00000006.*s2 : 00000000.*s3 : 00000003") test_sim_arg(73 "--permissive-dual-issue" "\\\\\\[Error\\\\\\] Illegal instruction: Two simultaneously enabled multiply operations") + +test_sim(74 "r1 : 00000539") + +test_sim(75 "\\\\\\[Error\\\\\\] Illegal instruction:.*00000008:.*invalid") + +test_sim(76 "r1 : 00000539") diff --git a/tests/test74.s b/tests/test74.s new file mode 100644 index 0000000..f08ec61 --- /dev/null +++ b/tests/test74.s @@ -0,0 +1,21 @@ +# +# Tests non-delayed return ignores following non-instruction bytes +# + + .word 100; + addi r1 = r0, 0; + brcfnd x; + nop; + nop; + nop; + halt; + nop; + nop; + nop; + .word 24; +x: addi r1 = r1, 1337; + retnd; + .word 2147483647; + .word 2147483647; + .word 2147483647; + diff --git a/tests/test75.s b/tests/test75.s new file mode 100644 index 0000000..312c6b6 --- /dev/null +++ b/tests/test75.s @@ -0,0 +1,10 @@ +# +# Tests non-instruction bytes after disabled retnd result in error +# + + .word 100; + (!p0) retnd ; + .word 2147483647; + .word 2147483647; + .word 2147483647; + diff --git a/tests/test76.s b/tests/test76.s new file mode 100644 index 0000000..64684d5 --- /dev/null +++ b/tests/test76.s @@ -0,0 +1,21 @@ +# +# Tests non-delayed return ignores following instructions +# + + .word 100; + addi r1 = r0, 0; + brcfnd x; + nop; + nop; + nop; + halt; + nop; + nop; + nop; + .word 24; +x: addi r1 = r1, 1337; + retnd; + addi r1 = r1, 1; + addi r1 = r1, 2; + addi r1 = r1, 3; +