Skip to content

Commit

Permalink
Instructions after 'retnd' are now properly ignored
Browse files Browse the repository at this point in the history
Also no longer throws an error if 'retnd' is followed by
non-instruction bytes.
  • Loading branch information
Emoun committed Oct 23, 2023
1 parent 0006fb6 commit d62a305
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 18 deletions.
5 changes: 3 additions & 2 deletions include/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
71 changes: 71 additions & 0 deletions include/instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand Down
9 changes: 5 additions & 4 deletions include/instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{ }
Expand All @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
11 changes: 7 additions & 4 deletions src/decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,11 @@ namespace patmos
{
// unknown instruction -- report error
if(throw_error) {
simulation_exception_t::illegal(from_big_endian<big_word_t>(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)
Expand Down Expand Up @@ -132,9 +134,10 @@ namespace patmos
{
// unknown instruction or invalid encoding? -- report error
if(throw_error) {
simulation_exception_t::illegal(from_big_endian<big_word_t>(iwp[1]));
return 0;
} else {
return 0;
result[1] = instruction_data_t::mk_invalid();
return 2;
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/instruction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
}
Expand All @@ -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)
Expand Down
12 changes: 10 additions & 2 deletions src/simulation-core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
{
Expand Down
24 changes: 18 additions & 6 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Expand Down Expand Up @@ -381,33 +387,33 @@ 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")

test_sim_arg(58 "--permissive-dual-issue" "\\\\\\[Error\\\\\\] Illegal instruction: Two simultaneously enabled load/store.*\\\\\\( p1\\\\\\) swm \\\\\\[r1 \\\\\\+ 0\\\\\\] = r3")

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")

Expand All @@ -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")
21 changes: 21 additions & 0 deletions tests/test74.s
Original file line number Diff line number Diff line change
@@ -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;

10 changes: 10 additions & 0 deletions tests/test75.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#
# Tests non-instruction bytes after disabled retnd result in error
#

.word 100;
(!p0) retnd ;
.word 2147483647;
.word 2147483647;
.word 2147483647;

21 changes: 21 additions & 0 deletions tests/test76.s
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit d62a305

Please sign in to comment.