//Assembly Language Instructions

`define STO 3'b001
`define ADD 3'b010
`define SUB 3'b011
`define AND 3'b100
`define OR 3'b101
`define XOR 3'b110
`define NOT 3'b111

`define STORE_DELAY 0
`define CLOCK_PERIOD 10
`define WRITE 1'b0
`define READ 1'b1
`define ON 1'b0
`define OFF 1'b1
`define FETCH_DELAY 0
`define ALU_DELAY 1 //redundant

`define ONEOP 3'b000

//--------------------------------------------------------
//	Decoder Module
//---------------------------------------------------------
//	Takes input from the processor module,decodes it,issues
//	instructions to the memory to fetch the operands or store
//	them,and sets the control lines of the ALU.
//--------------------------------------------------------


module Instruction_Decoder(dataout,addr,datain,chipsel,
			readwrite,
		ctrl_in,in1,in2,cin,alu_out,

		clk,reset,op1,op2,opcode, next_inst);

input clk, reset, op1, op2, opcode, next_inst;

output ctrl_in,in1,in2,cin;
input alu_out;

output chipsel,readwrite,addr,datain;
input dataout;

wire clk,reset;
wire [3:0] op1,op2;
wire [2:0] opcode;

wire [3:0] dataout;
reg [3:0] addr,datain;
wire [3:0] alu_out;
reg [3:0] in1,in2;
reg [2:0] ctrl_in;

reg [3:0] fetched_data,result;
reg [3:0] temp_data1,temp_data2;
wire cout, next_inst;
reg readwrite,chipsel,cin;

always @(posedge next_inst or negedge next_inst)
//always @(op1 or op2 or opcode ) 
begin
		$display($time," op1=%b, op2=%b, opcode=%b",op1,op2,opcode);
		case(opcode)
			`STO :
				begin
					addr = op1;
					datain = op2;
					readwrite = `WRITE;
					chipsel = `ON;
					#(`STORE_DELAY + `CLOCK_PERIOD)
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;
				end

			`ADD :
				begin
					addr = op1;
					readwrite = `READ;
					chipsel = `ON;
					#(`FETCH_DELAY + `CLOCK_PERIOD)
					fetched_data = dataout;
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;

					@ (negedge clk)
					ctrl_in = 3'b001;
					in1 = fetched_data;
					in2 = op2;
					cin = 0;
					#(`ALU_DELAY + `CLOCK_PERIOD)
					result = alu_out;
					ctrl_in = 3'bx;
					in1 = 4'bx;
					in2 = 4'bx;
					cin = 1'bx;

					@ (negedge clk)
					addr = op1;
					datain = result;
					readwrite = `WRITE;
					chipsel = `ON;
					#(`STORE_DELAY + `CLOCK_PERIOD)
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;
				end

			`SUB :
				begin
					addr = op1;
					readwrite = `READ;
					chipsel = `ON;
					#(`FETCH_DELAY + `CLOCK_PERIOD)
					fetched_data = dataout;
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;

					@ (negedge clk)
					ctrl_in = 3'b010;
					in1 = fetched_data;
					in2 = op2;
					cin = 1;
					#(`ALU_DELAY + `CLOCK_PERIOD)
					result = alu_out;
					ctrl_in = 3'bx;
					in1 = 4'bx;
					in2 = 4'bx;
					cin = 1'bx;

					@ (negedge clk)
					addr = op1;
					datain = result;
					readwrite = `WRITE;
					chipsel = `ON;
					#(`STORE_DELAY + `CLOCK_PERIOD)
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;
				end

			`AND :
				begin
					addr = op1;
					readwrite = `READ;
					chipsel = `ON;
					#(`FETCH_DELAY + `CLOCK_PERIOD)
					fetched_data = dataout;
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;

					@ (negedge clk)
					ctrl_in = 3'b110;
					in1 = fetched_data;
					in2 = op2;
					cin = 1'bx;
					#(`ALU_DELAY + `CLOCK_PERIOD)
					result = alu_out;
					ctrl_in = 3'bx;
					in1 = 4'bx;
					in2 = 4'bx;
					cin = 1'bx;

					@ (negedge clk)
					addr = op1;
					datain = result;
					readwrite = `WRITE;
					chipsel = `ON;
					#(`STORE_DELAY + `CLOCK_PERIOD)
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;
				end

			`OR :
				begin
					addr = op1;
					readwrite = `READ;
					chipsel = `ON;
					#(`FETCH_DELAY + `CLOCK_PERIOD)
					fetched_data = dataout;
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;

					@ (negedge clk)
					ctrl_in = 3'b100;
					in1 = fetched_data;
					in2 = op2;
					cin = 1'bx;
					#(`ALU_DELAY + `CLOCK_PERIOD)
					result = alu_out;
					ctrl_in = 3'bx;
					in1 = 4'bx;
					in2 = 4'bx;
					cin = 1'bx;

					@ (negedge clk)
					addr = op1;
					datain = result;
					readwrite = `WRITE;
					chipsel = `ON;
					#(`STORE_DELAY + `CLOCK_PERIOD)
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;
				end

			`XOR :
				begin
					addr = op1;
					readwrite = `READ;
					chipsel = `ON;
					#(`FETCH_DELAY + `CLOCK_PERIOD)
					fetched_data = dataout;
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;

					@ (negedge clk)
					ctrl_in = 3'b101;
					in1 = fetched_data;
					in2 = op2;
					cin = 1'bx;
					#(`ALU_DELAY + `CLOCK_PERIOD)
					result = alu_out;
					ctrl_in = 3'bx;
					in1 = 4'bx;
					in2 = 4'bx;
					cin = 1'bx;

					@ (negedge clk)
					addr = op1;
					datain = result;
					readwrite = `WRITE;
					chipsel = `ON;
					#(`STORE_DELAY + `CLOCK_PERIOD)
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;
				end

			`NOT :
				begin
					ctrl_in = 3'b111;
					in1 = op2;
					cin = 1'bx;
					#(`ALU_DELAY + `CLOCK_PERIOD)
					result = alu_out;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;

					@ (negedge clk)
					addr = op1;
					datain = result;
					readwrite = `WRITE;
					chipsel = `ON;
					#(`STORE_DELAY + `CLOCK_PERIOD)
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;
				end
			`ONEOP :
				begin
					addr = op2;
					readwrite = `READ;
					chipsel = `ON;
					#(`FETCH_DELAY + `CLOCK_PERIOD)
					fetched_data = dataout;
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;

					@ (negedge clk)
					ctrl_in = 3'b000;
					in1 = op1;
					in2 = fetched_data;
					cin = 1'bx;
					#(`ALU_DELAY + `CLOCK_PERIOD)
					result = alu_out;
					ctrl_in = 3'bx;
					in1 = 4'bx;
					in2 = 4'bx;
					cin = 1'bx;

					@ (negedge clk)
					addr = op2;
					datain = result;
					readwrite = `WRITE;
					chipsel = `ON;
					#(`STORE_DELAY + `CLOCK_PERIOD)
					chipsel = `OFF;
					addr = 4'bx;
					datain = 4'bx;
					readwrite = 1'bx;
				end
			default :
				;
	endcase
end
endmodule
