module mmx ( instruction,clk,reset,
mem_addr,mem_data,mem_we,
mmx_addr,mmx_data,mmx_we );
 
input [17:0] instruction;
input clk,reset;
reg [63:0] result;
reg [8:0] destination;
 
// MMX REGISTER array (64x8)
output [2:0] mmx_addr;
inout [63:0] mmx_data;
output mmx_we;
wire [63:0] mmx_data;
wire [63:0] mmx_data_out;
wire [63:0] mmx_data_in;
wire mmx_we;
 
//MMX_MAIN MEMORY INTERFACE (64X64)
output [5:0] mem_addr;
inout [63:0] mem_data;
output mem_we;
wire [63:0] mem_data_out;
wire [63:0] mem_data_in;
wire mem_we;
wire [63:0] mem_data;
 
wire Lsign,Hsign;
wire [31:0] Lpart,Hpart,Lres1,Hres1,Lres2,Hres2,Lres,Hres,tempH,tempL;
wire sign3,sign2,sign1,sign0;
wire [15:0] aword3,aword2,aword1,aword0;
wire [15:0] bword3,bword2,bword1,bword0;
wire [31:0] tres3,tres2,tres1,tres0,tres3_1,tres2_1,tres1_1,tres0_1;
wire [15:0] bres3,bres2,bres1,bres0;
 
 
reg [63:0] opa, opb;
reg [2:0] mode;
reg [5:0] sourcea , sourceb;
 
reg [17:0] instructionout;
reg [2:0] fn_select_in;
 
reg [2:0] state, next_state;
 
parameter idle = 3'b000,
decode_inst = 3'b001,
get_opa = 3'b010,
get_opb = 3'b011,
inst_out = 3'b100,
delay1 = 3'b101,
write_rests = 3'b110;
 
//***********************************************************************************
//MAIN STATE MACHINE
always @(state) begin
case (state)
idle : next_state <= decode_inst;
decode_inst : next_state <= get_opa;
get_opa : next_state <= get_opb;
get_opb : next_state <= inst_out;
inst_out : next_state <= delay1;
delay1 : next_state <= write_rests;
write_rests : next_state <= idle;
default : next_state <= idle;
endcase
end
always @(posedge clk) begin
if (reset) begin
state <= idle;
end
else
state <= next_state;
end
 
//***********************************************************************************
//DECODING THE INSTRUCTION
always @(posedge clk) begin
if (reset) begin
sourcea [5:0] <= 6'b0;
sourceb [5:0] <= 6'b0;
mode <= 3'b0;
end
else begin
if (state == decode_inst) begin
sourcea [5:0] <= instruction[11:6];
sourceb [5:0] <= instruction[5:0];
mode <= instruction[14:12];
end
else begin
sourcea <= sourcea ;
mode <= mode ;
sourceb <= sourceb ;
end
end
end
//***********************************************************************************
//CALCULATING MEMORY ADDRESSES and DATA
 
assign mem_addr = (state == get_opa) ? sourcea :
(state == get_opb) ? sourceb :
destination[5:0] ;
assign mem_data_in = result;
assign mem_we = ((state == write_rests) &&
((destination[8:6] == 3'b011) ||
(destination[8:6] == 3'b100)))? 1'b1: 1'b0;
assign mem_data = (mem_we)? mem_data_in :64'hZZZZ_ZZZZ_ZZZZ_ZZZZ;
assign mem_data_out = mem_data;
 
//***********************************************************************************
//CALCULATING MMX ADDRESSES and DATA
 
assign mmx_addr = (state == get_opa) ? sourcea[2:0] :
(state == get_opb) ? sourceb[2:0] :
destination[2:0] ;
assign mmx_data_in = result;
assign mmx_we = ((state == write_rests) &&
((destination[8:6] == 3'b001) ||
(destination[8:6] == 3'b010)))? 1'b1:1'b0;
assign mmx_data = (mmx_we)? mmx_data_in :64'hZZZZ_ZZZZ_ZZZZ_ZZZZ;
assign mmx_data_out = mmx_data;
 
//***********************************************************************************
//GETTING THE FIRST OPERAND
always @(posedge clk) begin
if (reset ) begin
opa <= 64'b0;
end
else begin
if (state == get_opa) begin
if (mode == 3'b001 | mode == 3'b010) begin
opa <= mmx_data_out;
end
else begin
if (mode == 3'b011 | mode == 3'b100) begin
opa <= mem_data_out;
end
else
opa <= opa ;
end
end
else
opa <= opa;
end
end
 
//**********************************************************************************
// GETTING THE SECOND OPERAND
always @(posedge clk) begin
if (reset ) begin
opb <= 64'b0;
end
else begin
if (state == get_opb) begin
if (mode == 3'b001 | mode == 3'b011) begin
opb <= mmx_data_out;
end
else begin
if (mode == 3'b010 | mode == 3'b100) begin
opb <= mem_data_out;
end
else
opb <= opb ;
end
end
else
opb <= opb;
end
end
 
//************************************************************************************
//SENDING THE INSTRUCTION OUT TO THE FUNCTIONAL UNIT
always @(posedge clk) begin
if (reset) begin
instructionout <= 18'b0;
end
else begin
if (state == inst_out) begin
instructionout <= instruction;
end
else begin
instructionout <= instructionout;
end
end
end
 
//_____________________________________________________________________________________
 
//*************************** FUNCTIONAL UNIT *****************************************
 
always @(posedge clk) begin
if (reset) begin
fn_select_in = 3'b0;
end
else begin
fn_select_in = instructionout[17:15];
end
end
always @(fn_select_in or opa or opb or instructionout) begin
case (fn_select_in)
 
/* Instruction : NOP */
3'b000: begin
destination <= 9'b0;
result <=64'b0;
$display("result = %x",result);
$display("NOP : no operation");
end
 
/* Instruction : PACKSSDW */
3'b001: begin
result <= {bres3,bres2,bres1,bres0};
$display("result = %x",result);
destination <= instruction[14:6];
end
/* Instruction : PSRAD */
3'b010: begin
result <= {Hres1,Lres1};
$display("result = %x",result);
destination <= instruction[14:6];
end
 
/* Instruction : PMADDW */
3'b011: begin
result <= {Hres,Lres};
$display("result = %x",result);
destination <= instruction[14:6];
end
 
/* Instruction : PXOR */
3'b100: begin
result <= opa^opb;
$display("result = %x",result);
destination <= instruction[14:6];
end
 
/* Instruction : MOVQ */
3'b101: begin
result <= opb;
destination <= instruction[14:6];
end
 
/* Instruction : PADD */
3'b110: begin
result <= {(opa[63:32]+opb[63:32]),(opa[31:0]+opb[31:0])};
$display("result = %x",result);
destination <= instruction[14:6];
end
 
/* Instruction : MOVD */
3'b111: begin
result <= {32'h00000000,opb[31:0]};
$display("result = %x",result);
destination <= instruction[14:6];
end
endcase
end
 
assign bres0 = (!opa[31])? ((opa[31:0]>32'h7FFF)?16'h7FFF:opa[15:0]) :((opa[31:0]>=32'hFFFF8000)?opa[15:0]:16'h8000);
assign bres1 = (!opa[63])? ((opa[63:32]>32'h7FFF)?16'h7FFF:opa[47:32]):((opa[63:32]>=32'hFFFF8000)?opa[47:32]:16'h8000);
assign bres2 = (!opb[31])? ((opb[31:0]>32'h7FFF)?16'h7FFF:opb[15:0]) :((opb[31:0]>=32'hFFFF8000)?opb[15:0]:16'h8000);
assign bres3 = (!opb[63])? ((opb[63:32]>32'h7FFF)?16'h7FFF:opb[47:32]):((opb[63:32]>=32'hFFFF8000)?opb[47:32]:16'h8000);
assign Lsign = opa[31];
assign Hsign = opa[63];
assign Lpart = opa[31:0];
assign Hpart = opa[63:32];
assign tempH = (Hsign==1)? 32'hffffffff ^ (32'hffffffff >> opb):32'h0;
assign tempL = (Lsign==1)? 32'hffffffff ^ (32'hffffffff >> opb):32'h0;
assign Hres1 = tempH | (Hpart >> opb);
assign Lres1 = tempL | (Lpart >> opb);
assign sign3 = opa[63]^opb[63];
assign sign2 = opa[47]^opb[47];
assign aword3 = (opa[63]==1)? (~opa[63:48]+1):opa[63:48];
assign aword2 = (opa[47]==1)? (~opa[47:32]+1):opa[47:32];
assign bword3 = (opb[63]==1)? (~opb[63:48]+1):opb[63:48];
assign bword2 = (opb[47]==1)? (~opb[47:32]+1):opb[47:32];
assign tres3 = aword3 * bword3;
assign tres2 = aword2 * bword2;
assign tres3_1= (sign3==1)? (~tres3 + 1) : tres3;
assign tres2_1= (sign2==1)? (~tres2 + 1) : tres2;
assign Hres2 = tres3_1 + tres2_1;
assign sign1 = opa[31]^opb[31];
assign sign0 = opa[15]^opb[15];
assign aword1 = (opa[31]==1)? (~opa[31:16]+1):opa[31:16];
assign aword0 = (opa[15]==1)? (~opa[15:0]+1) :opa[15:0] ;
assign bword1 = (opb[31]==1)? (~opb[31:16]+1):opb[31:16];
assign bword0 = (opb[15]==1)? (~opb[15:0]+1) :opb[15:0] ;
assign tres1 = aword1 * bword1;
assign tres0 = aword0 * bword0;
assign tres1_1= (sign1==1)? (~tres1 + 1) : tres1;
assign tres0_1= (sign0==1)? (~tres0 + 1) : tres0;
assign Lres2 = tres1_1 + tres0_1;
assign Hres = (opa[63:32]==64'h80008000 && opb[63:32]==64'h80008000)? 32'h80000000 :Hres2;
assign Lres = (opa[31:0] ==64'h80008000 && opb[31:0] ==64'h80008000)? 32'h80000000 :Lres2;
 
endmodule