diff options
| -rw-r--r-- | inc/ex.h | 76 | ||||
| -rw-r--r-- | inc/id.h | 67 | ||||
| -rw-r--r-- | inc/instr.h | 11 | ||||
| -rw-r--r-- | inc/instrDTO.h | 17 | ||||
| -rw-r--r-- | inc/stage.h | 6 | ||||
| -rw-r--r-- | inc/wb.h | 9 | ||||
| -rw-r--r-- | src/controller.cc | 1 | ||||
| -rw-r--r-- | src/ex.cc | 211 | ||||
| -rw-r--r-- | src/id.cc | 159 | ||||
| -rw-r--r-- | src/instr.cc | 11 | ||||
| -rw-r--r-- | src/mm.cc | 52 | ||||
| -rw-r--r-- | src/stage.cc | 14 | ||||
| -rw-r--r-- | src/wb.cc | 38 | ||||
| -rw-r--r-- | tests/id.cc | 39 | 
14 files changed, 365 insertions, 346 deletions
| @@ -23,36 +23,28 @@  #include <exception>  #include <unordered_map> -#define ADDITION_OF_GUARD(a, b) \ -	(b >= 0) && (a > MAX_INT - b) +#define ADDITION_OF_GUARD(a, b) (b >= 0) && (a > MAX_INT - b) -#define ADDITION_UF_GUARD(a, b) \ -	(b < 0) && (a < (-(MAX_INT)-1) - b) +#define ADDITION_UF_GUARD(a, b) (b < 0) && (a < (-(MAX_INT)-1) - b) -#define SUBTRACTION_OF_GUARD(a, b) \ -	(b < 0) && (a > MAX_INT + b) +#define SUBTRACTION_OF_GUARD(a, b) (b < 0) && (a > MAX_INT + b) -#define SUBTRACTION_UF_GUARD(a, b) \ -	(b >= 0) && (a < (-(MAX_INT)-1) + b) +#define SUBTRACTION_UF_GUARD(a, b) (b >= 0) && (a < (-(MAX_INT)-1) + b) -#define MULTIPLICATION_OF_GUARD(a, b) \ -	(b != 0) && \ -	(((b > 0) && (a > 0) && (a > MAX_INT / b)) || \ -	 ((b < 0) && (a < 0) && (a < MAX_INT / b))) +#define MULTIPLICATION_OF_GUARD(a, b)                                          \ +	(b != 0) && (((b > 0) && (a > 0) && (a > MAX_INT / b)) ||                  \ +				 ((b < 0) && (a < 0) && (a < MAX_INT / b))) -#define MULTIPLICATION_UF_GUARD(a, b) \ -	(b != 0) && (b != -1) && \ -	(((b > 0) && (a < 0) && (a < (-(MAX_INT)-1) / b)) || \ -	 ((b < 0) && (a > 0) && (a > (-(MAX_INT)-1) / b))) +#define MULTIPLICATION_UF_GUARD(a, b)                                          \ +	(b != 0) && (b != -1) &&                                                   \ +		(((b > 0) && (a < 0) && (a < (-(MAX_INT)-1) / b)) ||                   \ +		 ((b < 0) && (a > 0) && (a > (-(MAX_INT)-1) / b))) -#define DIVISION_OF_GUARD(a, b) \ -	((a == -(MAX_INT) - 1) && (b == -1)) || (b == 0) +#define DIVISION_OF_GUARD(a, b) ((a == -(MAX_INT)-1) && (b == -1)) || (b == 0)  class HaltException : public std::exception  { -	const char *what() const noexcept override { -		return ""; -	} +	const char *what() const noexcept override { return ""; }  };  class EX : public Stage @@ -63,19 +55,57 @@ class EX : public Stage  	 * @param The next stage in the pipeline.  	 * @return A newly allocated EX object.  	 */ -	using Stage::Stage;  	using Stage::advance; +	using Stage::Stage;    private:  	void advance_helper();  	/** +	 * Handles operations involving three ints. +	 * @param slot 1, and later, the result of the mnemonic operation. +	 * @param slot 2 +	 * @param slot 3 +	 * @param the mnemonic +	 * @param the program counter +	 */ +	void handle_int_operations( +		signed int &s1, +		signed int s2, +		signed int s3, +		Mnemonic m, +		unsigned int pc); +	/** +	 * Handles operations involving three vector registers. +	 * @param slot 1, and later, the result of the mnemonic operation. +	 * @param slot 2 +	 * @param slot 3 +	 * @param the mnemonic +	 * @param the vector length register +	 */ +	void handle_vector_operations( +		std::array<signed int, V_R_LIMIT> &s1, +		std::array<signed int, V_R_LIMIT> s2, +		Mnemonic m, +		unsigned int v_len); + +	/** +	 * Handles operations involving a single vector register. +	 * Currently, this is LOADV and STOREV +	 * @param slot 1, and later, the result of the mnemonic operation. +	 * @param slot 2 +	 * @param the mnemonic +	 * @param the vector length register +	 */ +	void handle_i_vector_operations(signed int &s1, signed int s2, Mnemonic m); +	/**  	 * Wrapper for division functions, which detects HALT instructinos (division  	 * by 0).  	 * @param the numerator  	 * @param the denominator  	 * @param if the modulo operator should instead be used +	 * @return if the operation overflowed  	 */ -	void handle_divide(signed int &s1, signed int s2, bool is_mod); +	bool handle_divide(signed int &s1, signed int s2, bool is_mod);  };  #endif /* EX_H_INCLUDED */ @@ -25,35 +25,13 @@  class ID : public Stage  {    public: -	using Stage::Stage;  	using Stage::advance; +	using Stage::Stage;  	/* The following methods are made public so that they may be tested, and are  	 * not to be called from outside classes during standard execution.  	 */ -	/** -	 * Facilitates register checkout and data hazard management. -	 * It does this by checking that the register passed in is not currently -	 * checked out. If true, then replaces r with the value of the register and -	 * returns OK. If false, returns STALLED. -	 * -	 * @param the registers number, to be dereferenced. -	 * @return OK if `r` is not checked out, STALLED otherwise. -	 */ -	Response read_guard(signed int &r); -	/** -	 * Facilitates register checkout and data hazard management. -	 * Checks out a register and returns it. -	 * -	 * @param the registers number, to be dereferenced and checked out. -	 */ -	void write_guard(signed int &r); - -	Response read_vec_guard(signed int r, std::array<signed int, V_R_LIMIT> &v); - -	void write_vec_guard(signed int r, std::array<signed int, V_R_LIMIT> &v); -  	Response set_vlen();    private: @@ -82,7 +60,7 @@ class ID : public Stage  	 * @param the resulting third field, which varies per type.  	 * @param the resulting mnemonic.  	 */ -	void get_instr_fields(signed int &s1); +	void get_instr_fields(signed int instr_bits);  	void decode_R_type(signed int &s1);  	void decode_I_type(signed int &s1);  	void decode_J_type(signed int &s1); @@ -95,6 +73,47 @@ class ID : public Stage  	 * @param the resulting type.  	 */  	void split_instr(signed int &raw, unsigned int &type, Mnemonic &m); +	/** +	 * Facilitates register checkout and data hazard management. +	 * Checks out a register and returns it. +	 * +	 * @param the registers number, to be dereferenced and checked out. +	 */ +	template <typename T> T write_guard(int v) +	{ +		T r; +		// these registers shouldn't be written. +		if (v != 0 && v != 16) { +			// keep track in the instrDTO for displaying to user and writeback +			// keep track in checked_out so we can still access this +			// information! +			this->checked_out.push_back(v); +			this->curr_instr->checked_out = v; +		} +		r = this->dereference_register<T>(v); +		return r; +	} +	/** +	 * Facilitates register checkout and data hazard management. +	 * It does this by checking that the register passed in is not currently +	 * checked out. If true, then sets `result' with the value of the register +	 * and returns OK. If false, returns STALLED. +	 * +	 * @param the registers number +	 * @param the dereferenced register value +	 * @return OK if `reg` is not checked out, STALLED otherwise. +	 */ +	template <typename T> Response read_guard(int reg, T &result) +	{ +		Response response; +		if (this->is_checked_out(reg)) +			response = STALLED; +		else { +			response = OK; +			result = this->dereference_register<T>(reg); +		} +		return response; +	}  };  #endif /* ID_H_INCLUDED */ diff --git a/inc/instr.h b/inc/instr.h index 98a1f0e..0c49a79 100644 --- a/inc/instr.h +++ b/inc/instr.h @@ -61,9 +61,20 @@ enum Mnemonic {  	NOP,  }; +enum FieldType { +	SI_INT, +	R_VECT, +	I_VECT, +}; +  namespace instr  {  extern const std::unordered_map<unsigned int, Mnemonic> mnemonic_map; +/** + * @param a mnemonic + * @return an enum representing the types of the decoded instruction fields. + */ +FieldType get_field_types(Mnemonic m);  } // namespace instr  #endif /* INSTR_H_INCLUDED */ diff --git a/inc/instrDTO.h b/inc/instrDTO.h index f3d4597..ccc6ed9 100644 --- a/inc/instrDTO.h +++ b/inc/instrDTO.h @@ -19,7 +19,8 @@  #define INSTRDTO_H  #include "instr.h"  #include "pipe_spec.h" -#include<array> +#include <array> +  struct U_INT_TYPE {  	signed int slot_one; @@ -33,10 +34,10 @@ struct V_TYPE {  	std::array<signed int, V_R_LIMIT> slot_three;  }; -struct LOAD_STORE_V_TYPE{ -	signed int base_addr; -	signed int immediate; -	std::array<signed int, V_R_LIMIT> vector_register; +struct VI_TYPE { +	signed int slot_one; +	signed int slot_two; +	std::array<signed int, V_R_LIMIT> slot_three;  };  struct InstrDTO { @@ -60,10 +61,14 @@ struct InstrDTO {  	 * The register this instruction checks out.  	 */  	signed int checked_out; +	/** +	 * The currently active union member. +	 */ +	FieldType type;  	union {  		struct U_INT_TYPE integer;  		struct V_TYPE vector; -		struct LOAD_STORE_V_TYPE load_store_vector; +		struct VI_TYPE i_vector;  	} operands;  }; diff --git a/inc/stage.h b/inc/stage.h index 4e0c252..834b941 100644 --- a/inc/stage.h +++ b/inc/stage.h @@ -83,10 +83,6 @@ class Stage  	 */  	static std::deque<signed int> checked_out; -	bool is_vector_type(Mnemonic m); - -	bool is_logical(Mnemonic m); -    protected:  	/**  	 * The function expected to do the majority of the work. @@ -140,7 +136,7 @@ class Stage  		}  		else if constexpr (std::is_same_v<T, std::array<signed int, V_R_LIMIT>>) {  			if (v < GPR_NUM || v >= GPR_NUM + V_NUM) { -				throw std::out_of_range("Invalid vector register index"); +				throw std::out_of_range("Invalid VRS index");  			}  			return vrs[v % GPR_NUM];  		} @@ -24,8 +24,8 @@  class WB : public Stage  {    public: -	using Stage::Stage;  	using Stage::advance; +	using Stage::Stage;    private:  	void advance_helper() override; @@ -47,6 +47,13 @@ class WB : public Stage  	 * STORE.  	 */  	bool should_jump(); +	/** +	 * @return the vector register to be stored, obtained by copying the +	 * unfilled elements in the destination register to the source. This is +	 * required to ensure what is written back only changes VECTOR_LENGTH number +	 * of elements. +	 */ +	std::array<signed int, V_R_LIMIT> copy_extra_vector_elements();  };  #endif /* WB_H_INCLUDED */ diff --git a/src/controller.cc b/src/controller.cc index e439b30..190d3e2 100644 --- a/src/controller.cc +++ b/src/controller.cc @@ -32,6 +32,7 @@ Controller::Controller(Stage *stage, Storage *storage, bool is_pipelined)  	this->checked_out = {};  	this->gprs = {0};  	this->vrs.fill({0}); +	this->vrs.at(0).fill(1);      // constant 1 vector register  	this->gprs.at(2) = MEM_WORDS; // set the stack pointer  } @@ -16,80 +16,47 @@  // along with this program.  If not, see <https://www.gnu.org/licenses/>.  #include "ex.h" +#include "instr.h"  #include "instrDTO.h"  #include "pipe_spec.h"  #include "response.h"  #include "stage.h" +#include <stdexcept>  #include <unordered_map> -// Switch statements for each instruction -void EX::advance_helper() +void EX::handle_int_operations( +	signed int &s1, signed int s2, signed int s3, Mnemonic m, unsigned int pc)  { -	signed int s1, s2, s3; -	std::array<signed int, V_R_LIMIT> v1, v2, v3; -	signed int v_len, v_immediate, v_base_addr; -	unsigned int pc; -	Mnemonic m; - -	s1 = 0, s2 = 0, s3 = 0; -	v1 = {0}, v2 = {0}, v3 = {0}; -	v_len = 0, v_immediate = 0, v_base_addr = 0; -	m = this->curr_instr->mnemonic; -	pc = this->curr_instr->slot_B; - -	if (this->is_vector_type(m)) { -		if (this->curr_instr->mnemonic != LOADV && -			this->curr_instr->mnemonic != STOREV) { -			v1 = this->curr_instr->operands.vector.slot_one; -			v2 = this->curr_instr->operands.vector.slot_two; -			v3 = this->curr_instr->operands.vector.slot_three; -		} else { -			v_immediate = -				this->curr_instr->operands.load_store_vector.immediate; -			v_base_addr = -				this->curr_instr->operands.load_store_vector.base_addr; -		} -		v_len = this->curr_instr->slot_A; -		if (v_len == 0) { -			// clear destination vector reg -			v1.fill(0); -		} -	} else { -		s1 = this->curr_instr->operands.integer.slot_one; -		s2 = this->curr_instr->operands.integer.slot_two; -		s3 = this->curr_instr->operands.integer.slot_three; -	} - -	if (this->is_logical(m)) { -		this->set_condition(OF, false); -		this->set_condition(UF, false); -	} +	bool overflow, underflow; +	overflow = get_condition(OF), underflow = get_condition(UF);  	switch (m) {  	case ADD: -		this->set_condition(OF, ADDITION_OF_GUARD(s1, s2)); -		this->set_condition(UF, ADDITION_UF_GUARD(s1, s2)); +		overflow = ADDITION_OF_GUARD(s1, s2); +		underflow = ADDITION_UF_GUARD(s1, s2);  		s1 = s1 + s2;  		break;  	case SUB: -		this->set_condition(OF, SUBTRACTION_OF_GUARD(s1, s2)); -		this->set_condition(UF, SUBTRACTION_UF_GUARD(s1, s2)); +		overflow = SUBTRACTION_OF_GUARD(s1, s2); +		underflow = SUBTRACTION_UF_GUARD(s1, s2);  		s1 = s1 - s2;  		break;  	case MUL: -		this->set_condition(OF, MULTIPLICATION_OF_GUARD(s1, s2)); -		this->set_condition(UF, MULTIPLICATION_UF_GUARD(s1, s2)); +		overflow = MULTIPLICATION_OF_GUARD(s1, s2); +		underflow = MULTIPLICATION_UF_GUARD(s1, s2);  		s1 = s1 * s2;  		break;  	case QUOT: -		this->handle_divide(s1, s2, false); +		overflow = this->handle_divide(s1, s2, false); +		underflow = 0;  		break;  	case REM: -		this->handle_divide(s1, s2, true); +		overflow = this->handle_divide(s1, s2, true); +		underflow = 0;  		break;  	case SFTR: @@ -101,18 +68,26 @@ void EX::advance_helper()  		break;  	case AND: +		overflow = false; +		underflow = false;  		s1 = s1 & s2;  		break;  	case OR: +		overflow = false; +		underflow = false;  		s1 = s1 | s2;  		break;  	case XOR: +		overflow = false; +		underflow = false;  		s1 = s1 ^ s2;  		break;  	case NOT: +		overflow = false; +		underflow = false;  		s1 = ~s1;  		break; @@ -124,14 +99,14 @@ void EX::advance_helper()  		break;  	case ADDI: -		this->set_condition(OF, ADDITION_OF_GUARD(s1, s3)); -		this->set_condition(UF, ADDITION_UF_GUARD(s1, s3)); +		overflow = ADDITION_OF_GUARD(s1, s3); +		underflow = ADDITION_UF_GUARD(s1, s3);  		s1 = s1 + s3;  		break;  	case SUBI: -		this->set_condition(OF, SUBTRACTION_OF_GUARD(s1, s3)); -		this->set_condition(UF, SUBTRACTION_UF_GUARD(s1, s3)); +		overflow = SUBTRACTION_OF_GUARD(s1, s3); +		underflow = SUBTRACTION_UF_GUARD(s1, s3);  		s1 = s1 - s3;  		break; @@ -144,14 +119,20 @@ void EX::advance_helper()  		break;  	case ANDI: +		overflow = false; +		underflow = false;  		s1 = s1 & s3;  		break;  	case ORI: +		overflow = false; +		underflow = false;  		s1 = s1 | s3;  		break;  	case XORI: +		overflow = false; +		underflow = false;  		s1 = s1 ^ s3;  		break; @@ -187,72 +168,126 @@ void EX::advance_helper()  		(this->get_condition(OF)) ? s1 = pc + s2 : s1 = -1;  		break; +	case RET: +	case NOP: +		break; + +	default: +		throw std::invalid_argument( +			"handle_int_operations received a vector operation!"); +	} + +	this->set_condition(OF, overflow); +	this->set_condition(UF, underflow); +} + +void EX::handle_vector_operations( +	std::array<signed int, V_R_LIMIT> &s1, +	std::array<signed int, V_R_LIMIT> s2, +	Mnemonic m, +	unsigned int v_len) +{ +	unsigned int i; +	bool overflow, underflow; + +	overflow = 0, underflow = 0; + +	switch (m) {  	case ADDV: -		for (int i = 0; i < v_len; i++) { -			this->set_condition(OF, ADDITION_OF_GUARD(v1[i], v2[i])); -			this->set_condition(UF, ADDITION_UF_GUARD(v1[i], v2[i])); -			v1[i] = v1[i] + v2[i]; +		for (i = 0; i < v_len; i++) { +			overflow = overflow || (ADDITION_OF_GUARD(s1[i], s2[i])); +			underflow = underflow || (ADDITION_UF_GUARD(s1[i], s2[i])); +			s1[i] = s1[i] + s2[i];  		}  		break;  	case SUBV: -		for (int i = 0; i < v_len; i++) { -			this->set_condition(OF, SUBTRACTION_OF_GUARD(v1[i], v2[i])); -			this->set_condition(UF, SUBTRACTION_UF_GUARD(v1[i], v2[i])); -			v1[i] = v1[i] - v2[i]; +		for (i = 0; i < v_len; i++) { +			overflow = overflow || (SUBTRACTION_OF_GUARD(s1[i], s2[i])); +			underflow = underflow || (SUBTRACTION_UF_GUARD(s1[i], s2[i])); +			s1[i] = s1[i] - s2[i];  		}  		break;  	case MULV: -		for (int i = 0; i < v_len; i++) { -			this->set_condition(OF, MULTIPLICATION_OF_GUARD(v1[i], v2[i])); -			this->set_condition(UF, MULTIPLICATION_UF_GUARD(v1[i], v2[i])); -			v1[i] = v1[i] * v2[i]; +		for (i = 0; i < v_len; i++) { +			overflow = overflow || (MULTIPLICATION_OF_GUARD(s1[i], s2[i])); +			underflow = underflow || (MULTIPLICATION_UF_GUARD(s1[i], s2[i])); +			s1[i] = s1[i] * s2[i];  		}  		break;  	case DIVV: -		for (int i = 0; i < v_len; i++) { -			this->handle_divide(v1[i], v2[i], false); +		for (i = 0; i < v_len; i++) { +			// short-circuiting---this order required +			overflow = this->handle_divide(s1[i], s2[i], false) | overflow;  		}  		break;  	case CEV: -		int i; +		bool eq; +		eq = true;  		for (i = 0; i < v_len; i++) { -			if (v1[i] != v2[i]) { +			if (s1[i] != s2[i]) { +				eq = false;  				break;  			}  		} -		if (i == v_len) { -			this->set_condition(EQ, true); -		} else { -			this->set_condition(EQ, false); -		} +		this->set_condition(EQ, eq);  		break; +	default: +		throw std::invalid_argument( +			"handle_vector_operations received an integer operation!"); +	} + +	this->set_condition(OF, overflow); +	this->set_condition(UF, underflow); +} + +void EX::handle_i_vector_operations(signed int &s1, signed int s2, Mnemonic m) +{ +	switch (m) {  	case LOADV:  	case STOREV: -		v_base_addr = v_base_addr + v_immediate; +		s1 = s1 + s2;  		break;  	case RET:  	case NOP:  		break; + +	default: +		throw std::invalid_argument("handle_i_vector_operations did not " +									"receive a LOADV or STOREV operation!");  	} -	if (this->is_vector_type(m)) { -		if (this->curr_instr->mnemonic != LOADV && -			this->curr_instr->mnemonic != STOREV) { -			this->curr_instr->operands.vector.slot_one = v1; -		} else { -			this->curr_instr->operands.load_store_vector.base_addr = -				v_base_addr; -		} +} + +void EX::advance_helper() +{ +	unsigned int v_len_or_pc; +	Mnemonic m; +	m = this->curr_instr->mnemonic; +	v_len_or_pc = this->curr_instr->slot_B; + +	if (this->curr_instr->type == FieldType::SI_INT) { +		handle_int_operations( +			this->curr_instr->operands.integer.slot_one, +			this->curr_instr->operands.integer.slot_two, +			this->curr_instr->operands.integer.slot_three, m, v_len_or_pc); +	} else if (this->curr_instr->type == FieldType::R_VECT) { +		handle_vector_operations( +			this->curr_instr->operands.vector.slot_one, +			this->curr_instr->operands.vector.slot_two, m, v_len_or_pc);  	} else { -		this->curr_instr->operands.integer.slot_one = s1; +		handle_i_vector_operations( +			this->curr_instr->operands.i_vector.slot_one, +			this->curr_instr->operands.i_vector.slot_two, m);  	} +  	this->status = OK;  } -void EX::handle_divide(signed int &s1, signed int s2, bool is_mod) +bool EX::handle_divide(signed int &s1, signed int s2, bool is_mod)  { -	this->set_condition(OF, DIVISION_OF_GUARD(s1, s2)); -	this->set_condition(UF, false); +	bool ret; + +	ret = DIVISION_OF_GUARD(s1, s2);  	if (s2 == 0) {  		// handle everything here  		this->curr_instr->operands.integer.slot_one = MAX_INT; @@ -264,4 +299,6 @@ void EX::handle_divide(signed int &s1, signed int s2, bool is_mod)  	} else {  		s1 = (is_mod) ? (s1 % s2) : (s1 / s2);  	} + +	return ret;  } @@ -22,87 +22,34 @@  #include "response.h"  #include "stage.h" -Response ID::read_guard(signed int &v) -{ -	Response r; -	if (this->is_checked_out(v)) -		r = STALLED; -	else { -		r = OK; -		v = this->dereference_register<signed int>(v); -	} -	return r; -} - -Response -ID::read_vec_guard(signed int v, std::array<signed int, V_R_LIMIT> &vrs) -{ -	Response r; -	if (this->is_checked_out(v)) -		r = STALLED; -	else { -		r = OK; -		vrs = this->dereference_register<std::array<signed int, V_R_LIMIT>>(v); -	} -	return r; -} - -void ID::write_guard(signed int &v) -{ -	// zero register shouldn't be written. -	if (v != 0) { -		// keep track in the instrDTO for displaying to user and writeback -		// keep track in checked_out so we can still access this information! -		this->checked_out.push_back(v); -		this->curr_instr->checked_out = v; -	} -	v = this->dereference_register<signed int>(v); -} - -void ID::write_vec_guard(signed int v, std::array<signed int, V_R_LIMIT> &vrs) -{ - -	// zero register shouldn't be written. -	if (v != 0) { -		// keep track in the instrDTO for displaying to user and writeback -		// keep track in checked_out so we can still access this information! -		this->checked_out.push_back(v); -		this->curr_instr->checked_out = v; -	} -	vrs = this->dereference_register<std::array<signed int, V_R_LIMIT>>(v); -} -  void ID::advance_helper()  { -	signed int s1; -  	if (this->curr_instr->mnemonic == NOP)  		this->status = OK;  	else {  		// instuction in bits in s1 -		s1 = this->curr_instr->slot_A; -		get_instr_fields(s1); +		get_instr_fields(this->curr_instr->slot_A);  	}  } -void ID::get_instr_fields(signed int &s1) +void ID::get_instr_fields(signed int instr_bits)  {  	unsigned int type;  	Mnemonic m; -	this->split_instr(s1, type, m); +	this->split_instr(instr_bits, type, m);  	this->curr_instr->mnemonic = m; +	this->curr_instr->type = instr::get_field_types(m);  	switch (type) {  	case 0b00: -		this->decode_R_type(s1); +		this->decode_R_type(instr_bits);  		break;  	case 0b01: -		this->decode_I_type(s1); +		this->decode_I_type(instr_bits);  		break;  	case 0b10: -		this->decode_J_type(s1); +		this->decode_J_type(instr_bits);  		break;  	case 0b11: -		// not defined, m = NOP  		this->status = OK;  	}  } @@ -127,13 +74,13 @@ Response ID::set_vlen()  {  	signed int vlen_reg = 4;  	Response r; -	r = this->read_guard(vlen_reg); +	r = this->read_guard<signed int>(vlen_reg, vlen_reg);  	vlen_reg = vlen_reg & 0xf;  	if (r == OK) {  		if (vlen_reg > V_R_LIMIT) { -			this->curr_instr->slot_A = V_R_LIMIT; +			this->curr_instr->slot_B = V_R_LIMIT;  		} else { -			this->curr_instr->slot_A = vlen_reg; +			this->curr_instr->slot_B = vlen_reg;  		}  	}  	return r; @@ -143,8 +90,7 @@ void ID::decode_R_type(signed int &s1)  {  	unsigned int s0b, s1b, s2b;  	signed int s2, s3; -	Response r1, r2; -	Response r3 = OK; +	Response r1, r2, r3;  	s0b = REG_SIZE;  	s1b = s0b + REG_SIZE; @@ -153,17 +99,18 @@ void ID::decode_R_type(signed int &s1)  	s2 = GET_MID_BITS(s1, s0b, s1b);  	s1 = GET_LS_BITS(s1, s0b); -	if (this->is_vector_type(this->curr_instr->mnemonic)) { -		r1 = this->read_vec_guard( +	if (this->curr_instr->type == SI_INT) { +		r1 = this->read_guard<signed int>( +			s1, this->curr_instr->operands.integer.slot_one); +		r2 = this->read_guard<signed int>( +			s2, this->curr_instr->operands.integer.slot_two); +		r3 = OK; +	} else { +		r1 = this->read_guard<std::array<signed int, V_R_LIMIT>>(  			s1, this->curr_instr->operands.vector.slot_one); -		r2 = this->read_vec_guard( +		r2 = this->read_guard<std::array<signed int, V_R_LIMIT>>(  			s2, this->curr_instr->operands.vector.slot_two);  		r3 = this->set_vlen(); -	} else { -		r1 = this->read_guard(s1); -		this->curr_instr->operands.integer.slot_one = s1; -		r2 = this->read_guard(s2); -		this->curr_instr->operands.integer.slot_two = s2;  	}  	this->status = (r1 == OK && r2 == OK && r3 == OK) ? OK : STALLED; @@ -177,14 +124,14 @@ void ID::decode_R_type(signed int &s1)  	case MULV:  	case DIVV:  		if (this->status == OK) { -			this->write_vec_guard( -				s3, this->curr_instr->operands.vector.slot_three); +			this->curr_instr->operands.vector.slot_three = +				this->write_guard<std::array<signed int, V_R_LIMIT>>(s3);  		}  		break;  	default:  		if (this->status == OK) { -			this->write_guard(s3); -			this->curr_instr->operands.integer.slot_three = s3; +			this->curr_instr->operands.integer.slot_three = +				this->write_guard<signed int>(s3);  		}  	}  } @@ -199,7 +146,7 @@ void ID::decode_I_type(signed int &s1)  	s0b = REG_SIZE;  	s1b = s0b + REG_SIZE;  	s2b = WORD_SPEC - LINE_SPEC - OPCODE_SIZE; -	// s3 is immediate +	// s3 is slot_two  	s3 = GET_BITS_SIGN_EXTEND(s1, s1b, s2b);  	switch (this->curr_instr->mnemonic) { @@ -210,41 +157,40 @@ void ID::decode_I_type(signed int &s1)  		// both operands are read values  		// s1 is base address -		r1 = this->read_guard(s1); +		r1 = this->read_guard<signed int>(s1, s1);  		this->curr_instr->operands.integer.slot_one = s1;  		// s2 is value to be stored -		r2 = this->read_guard(s2); +		r2 = this->read_guard<signed int>(s2, s2);  		this->curr_instr->operands.integer.slot_two = s2;  		this->status = (r1 == OK && r2 == OK) ? OK : STALLED;  		return;  	case STOREV: -		this->curr_instr->operands.load_store_vector.immediate = s3; +		this->curr_instr->operands.i_vector.slot_two = s3;  		s2 = GET_MID_BITS(s1, s0b, s1b);  		s1 = GET_LS_BITS(s1, s0b);  		// base address -		r1 = this->read_guard(s1); -		this->curr_instr->operands.load_store_vector.base_addr = s1; +		r1 = this->read_guard<signed int>(s1, s1); +		this->curr_instr->operands.i_vector.slot_one = s1;  		// vector value to be stored -		r2 = this->read_vec_guard( -			s2, this->curr_instr->operands.load_store_vector.vector_register); +		r2 = this->read_guard<std::array<signed int, V_R_LIMIT>>( +			s2, this->curr_instr->operands.i_vector.slot_three);  		r3 = this->set_vlen();  		this->status = (r1 == OK && r2 == OK && r3 == OK) ? OK : STALLED;  		return;  	case LOADV: -		this->curr_instr->operands.load_store_vector.immediate = s3; +		this->curr_instr->operands.i_vector.slot_two = s3;  		s2 = GET_LS_BITS(s1, s0b);  		s1 = GET_MID_BITS(s1, s0b, s1b);  		// base address -		r1 = this->read_guard(s1); -		this->curr_instr->operands.load_store_vector.base_addr = s1; +		r1 = this->read_guard<signed int>(s1, s1); +		this->curr_instr->operands.i_vector.slot_one = s1;  		r3 = this->set_vlen();  		if (r1 == OK && r3 == OK)  			// vector destination -			this->write_vec_guard( -				s2, -				this->curr_instr->operands.load_store_vector.vector_register); +			this->curr_instr->operands.i_vector.slot_three = +				this->write_guard<std::array<signed int, V_R_LIMIT>>(s2);  		this->status = (r1 == OK && r3 == OK) ? OK : STALLED;  		return;  	case LOAD: @@ -258,11 +204,11 @@ void ID::decode_I_type(signed int &s1)  		s1 = GET_LS_BITS(s1, s0b);  	} -	r1 = this->read_guard(s1); +	r1 = this->read_guard<signed int>(s1, s1);  	this->curr_instr->operands.integer.slot_one = s1;  	if (r1 == OK) { -		this->write_guard(s2); -		this->curr_instr->operands.integer.slot_two = s2; +		this->curr_instr->operands.integer.slot_two = +			this->write_guard<int>(s2);  	}  	this->status = r1;  } @@ -284,14 +230,16 @@ void ID::decode_J_type(signed int &s1)  		s2 = s1; // source  		s3 = 2;	 // stack pointer  		s1 = -1; // increment amount -		r1 = this->read_guard(s2); +  		this->curr_instr->operands.integer.slot_one = s1; -		this->curr_instr->operands.integer.slot_two = s2; +		r1 = this->read_guard<signed int>( +			s2, this->curr_instr->operands.integer.slot_two);  		r2 = (this->is_checked_out(s3)) ? STALLED  										: OK; // we read the stack pointer  		if (r1 == OK && r2 == OK) { -			this->write_guard(s3); // we write the stack pointer -			this->curr_instr->operands.integer.slot_three = s3; +			// we write the stack pointer +			this->curr_instr->operands.integer.slot_three = +				this->write_guard<int>(s3);  		}  		this->status = (r1 == OK && r2 == OK) ? OK : STALLED;  		break; @@ -303,10 +251,11 @@ void ID::decode_J_type(signed int &s1)  		r1 = (this->is_checked_out(s3)) ? STALLED  										: OK; // we read the stack pointer  		if (r1 == OK) { -			this->write_guard(s2); -			this->curr_instr->operands.integer.slot_two = s2; -			this->write_guard(s3); // we write the stack pointer -			this->curr_instr->operands.integer.slot_three = s3; +			this->curr_instr->operands.integer.slot_two = +				this->write_guard<int>(s2); +			// we write the stack pointer +			this->curr_instr->operands.integer.slot_three = +				this->write_guard<int>(s3);  		}  		this->status = r1;  		break; @@ -314,9 +263,9 @@ void ID::decode_J_type(signed int &s1)  		s1 = 1; // link register  		[[fallthrough]];  	default: -		this->status = this->read_guard(s1); -		if(this->status == OK){ -			this->curr_instr->operands.integer.slot_one = s1; +		this->status = this->read_guard<signed int>( +			s1, this->curr_instr->operands.integer.slot_one); +		if (this->status == OK) {  			this->curr_instr->operands.integer.slot_two = s2;  			this->curr_instr->operands.integer.slot_three = s3;  		} diff --git a/src/instr.cc b/src/instr.cc index 9bd951b..ee2d37f 100644 --- a/src/instr.cc +++ b/src/instr.cc @@ -37,4 +37,15 @@ const std::unordered_map<unsigned int, Mnemonic> mnemonic_map = {  	{0b0011010, BUF},	 {0b0011110, BOF},	 {0b0100010, PUSH},  	{0b0100110, POP},	 {0b0101010, RET},  }; + +FieldType get_field_types(Mnemonic m) +{ +	if (m == ADDV || m == SUBV || m == MULV || m == DIVV || m == CEV) { +		return R_VECT; +	} else if (m == STOREV || m == LOADV) { +		return I_VECT; +	} else { +		return SI_INT; +	} +}  } // namespace instr @@ -24,7 +24,6 @@ void MM::advance_helper()  {  	signed int data;  	int i; -	int vector_delay = VECTOR_MEM_DELAY;  	switch (this->curr_instr->mnemonic) {  	case LOAD: @@ -36,32 +35,6 @@ void MM::advance_helper()  		} else  			this->status = STALLED;  		break; -	case LOADV: -		if (vector_delay == 0){ -			signed int word_address = this->curr_instr->operands.load_store_vector.base_addr; -			int j = 0; -			while(j < this->curr_instr->slot_A){ -				i = this->storage->read_word(this, word_address, data); -				this->status = i ? OK : STALLED; -				if (this->status == OK) { -					this->curr_instr->operands.load_store_vector.vector_register[j] = data; -					// +1 or +4? -					word_address += 1; -					j++; -				} else { -					break; -				} -			} -			if(this->status == OK){ -				// if vector is loaded, reset delay -				vector_delay = VECTOR_MEM_DELAY; -			} else { -				this->status = STALLED; -			} -		} else { -			vector_delay--; -		} -		break;  	case PUSH:  	case STORE: @@ -73,31 +46,6 @@ void MM::advance_helper()  			this->status = STALLED;  		}  		break; -	case STOREV: -	if (vector_delay == 0){ -		signed int word_address = this->curr_instr->operands.load_store_vector.base_addr; -		int j = 0; -		while(j < this->curr_instr->slot_A){ -			this->storage->write_word( -				this, this->curr_instr->operands.load_store_vector.vector_register[j], word_address); -			this->status = i ? OK : STALLED; -			if (this->status != OK) { -				break; -			} else { -				word_address += 1; -				j++; -			} -		} -		if(this->status == OK){ -			// if vector is stored , reset delay -			vector_delay = VECTOR_MEM_DELAY; -		} else { -			this->status = STALLED; -		} -	} else { -		vector_delay--; -	} -	break;  	case POP:  		i = this->storage->read_word(this, this->curr_instr->operands.integer.slot_three, data); diff --git a/src/stage.cc b/src/stage.cc index 4eab7d3..7db3539 100644 --- a/src/stage.cc +++ b/src/stage.cc @@ -71,20 +71,6 @@ InstrDTO *Stage::advance(Response p)  	return r;  } -bool Stage::is_vector_type(Mnemonic m) -{ -	return ( -		m == ADDV || m == SUBV || m == MULV || m == DIVV || m == CEV || -		m == LOADV || m == STOREV); -} - -bool Stage::is_logical(Mnemonic m) -{ -	return ( -		m == ANDI || m == ORI || m == XORI || m == AND || m == OR || m == XOR || -		m == NOT); -} -  InstrDTO *Stage::get_instr() { return this->curr_instr; }  void Stage::set_condition(CC c, bool v) @@ -16,6 +16,7 @@  // along with this program.  If not, see <https://www.gnu.org/licenses/>.  #include "wb.h" +#include "instr.h"  #include "instrDTO.h"  #include "response.h"  #include "stage.h" @@ -51,15 +52,21 @@ void WB::write_handler()  	this->checked_out.pop_front();  	reg = this->curr_instr->checked_out; -	 -	if(this->is_vector_type(this->curr_instr->mnemonic)) { -		if(this->curr_instr->mnemonic != STOREV && this->curr_instr->mnemonic != LOADV) { -			this->store_register<std::array<signed int, V_R_LIMIT>>(reg, this->curr_instr->operands.vector.slot_one); -		} else { -			this->store_register<std::array<signed int, V_R_LIMIT>>(reg, this->curr_instr->operands.load_store_vector.vector_register); -		} -	} else{ -		this->store_register<signed int>(reg, this->curr_instr->operands.integer.slot_one); + +	switch (this->curr_instr->type) { +	case SI_INT: +		this->store_register<signed int>( +			reg, this->curr_instr->operands.integer.slot_one); +		break; +	case R_VECT: +		this->store_register<std::array<signed int, V_R_LIMIT>>( +			reg, this->copy_extra_vector_elements()); +		break; +	case I_VECT: +		this->store_register<std::array<signed int, V_R_LIMIT>>( +			reg, this->curr_instr->operands.i_vector.slot_three); +		// todo, use copy_extra_vector_elements +		break;  	}  } @@ -68,7 +75,6 @@ void WB::jump_handler()  	if (this->curr_instr->operands.integer.slot_one > 0) {  		if (this->curr_instr->mnemonic == JAL)  			this->gprs[1] = this->curr_instr->slot_B + 1; -		;  		this->pc = this->curr_instr->operands.integer.slot_one;  		this->checked_out = {};  		this->next->squash(); @@ -85,3 +91,15 @@ bool WB::should_jump()  	else  		return false;  } + +std::array<signed int, V_R_LIMIT> WB::copy_extra_vector_elements() +{ +	int i; +	std::array<signed int, V_R_LIMIT> v; + +	v = this->curr_instr->operands.vector.slot_one; +	for (i = V_R_LIMIT - 1; i >= this->curr_instr->slot_B; --i) { +		v[i] = this->curr_instr->operands.vector.slot_three[i]; +	} +	return v; +} diff --git a/tests/id.cc b/tests/id.cc index a81e967..b52ad9c 100644 --- a/tests/id.cc +++ b/tests/id.cc @@ -118,7 +118,7 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # two", "[id]")  	signed int t;  	InstrDTO *i; -	t = this->encode_R_type(0b10000, 0b01000, 0b00100, 0b10, 0b0); +	t = this->encode_R_type(0b1000, 0b01000, 0b00100, 0b10, 0b0);  	i = this->decode_bits(t);  	CHECK(i->operands.integer.slot_one == 0x00000000); // registers are empty @@ -129,6 +129,22 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # two", "[id]")  	delete i;  } +TEST_CASE_METHOD(IDFixture, "Parse arbitrary r-type # three", "[id]") +{ +	signed int t; +	InstrDTO *i; + +	t = this->encode_R_type(0b10000, 0b10001, 0b10101, 0b1110, 0b0); +	i = this->decode_bits(t); + +	CHECK(i->operands.integer.slot_one == 0x00000000); // registers are empty +	CHECK(i->operands.integer.slot_two == 0x00000000); +	CHECK(i->operands.integer.slot_three == 0x00000000); +	CHECK(i->mnemonic == MULV); + +	delete i; +} +  TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # one", "[id]")  {  	signed int t; @@ -150,7 +166,7 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary i-type # two", "[id]")  	signed int t;  	InstrDTO *i; -	t = this->encode_I_type(0xCC, 0b101, 0b110, 0b1011, 0b1); +	t = this->encode_I_type(0xCC, 0b10101, 0b00110, 0b11011, 0b1);  	i = this->decode_bits(t);  	CHECK(i->operands.integer.slot_one == 0x00000000); // registers are empty @@ -166,7 +182,7 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # one", "[id]")  	signed int t;  	InstrDTO *i; -	t = this->encode_J_type(0x3456, 0b10101, 0b0111, 0b10); +	t = this->encode_J_type(0x3456, 0b101, 0b0111, 0b10);  	i = this->decode_bits(t);  	CHECK(i->operands.integer.slot_one == 0x00000000); // registers are empty @@ -181,7 +197,7 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # two", "[id]")  	signed int t;  	InstrDTO *i; -	t = this->encode_J_type(0xBBCCF, 0b10101, 0b0011, 0b10); +	t = this->encode_J_type(0xBBCCF, 0b00101, 0b0011, 0b10);  	i = this->decode_bits(t);  	t = 0xFFFBBCCF; @@ -191,18 +207,3 @@ TEST_CASE_METHOD(IDFixture, "Parse arbitrary j-type # two", "[id]")  	delete i;  } - -TEST_CASE_METHOD(IDFixture, "read does not conflict with read", "[id]") -{ -	signed int v; -	Response r; - -	v = 0b1; -	r = this->d->read_guard(v); -	CHECK(v == 0b0); -	REQUIRE(r == OK); - -	v = 0b1; -	this->d->read_guard(v); -	REQUIRE(v == 0b0); -} | 
