cozag
module complex_mul (
input wire CLK,
input wire RST,
input wire I_STB,
input wire [31:0] I_ARE,
input wire [31:0] I_AIM,
input wire [31:0] I_BRE,
input wire [31:0] I_BIM,
output reg O_STB,
output reg [31:0] O_CRE,
output reg [31:0] O_CIM
);
// Stany FSM do kontroli sekwencji operacji mnożenia i dodawania
localparam IDLE = 0, MUL1 = 1, MUL2 = 2, MUL3 = 3, MUL4 = 4, ADD1 = 5, ADD2 = 6, DONE = 7;
reg [2:0] state, next_state;
// Wartości pośrednie
reg [31:0] a, b, c, d;
reg [31:0] mult_a, mult_b;
wire mult_stb;
wire [63:0] mult_result; // bo multiplier daje szerokość sumy A_WIDTH+B_WIDTH
wire add_stb;
wire [31:0] add_result;
// Flagi potwierdzenia handshake
reg mult_ack, add_ack;
// Instancje modułów mnożenia i dodawania
// Zakładam, że multiplier i adder mają I_STB/I_ACK handshake, wynik i flagi
multiplier #(.A_WIDTH(32), .B_WIDTH(32)) mul_inst (
.CLK(CLK),
.RST(RST),
.I_STB(mult_stb),
.I_ACK(mult_ack),
.I_DAT_A(mult_a),
.I_DAT_B(mult_b),
.O_STB(),
.O_DAT(mult_result),
.O_ACK(1'b1) // zakładam, że odbiorca zawsze gotowy
);
adder #(.A_WIDTH(32), .B_WIDTH(32)) add_inst (
.CLK(CLK),
.RST(RST),
.I_STB(add_stb),
.I_ACK(add_ack),
.I_DAT_A(a),
.I_DAT_B(b),
.O_STB(),
.O_DAT(add_result),
.O_ACK(1'b1)
);
// Rejestry do wyników mnożeń (32 bitów, bierzemy dolne 32 bity wyniku 64 bitowego mnożenia)
reg [31:0] mul_ac, mul_bd, mul_ad, mul_bc;
assign mult_stb = (state == MUL1) || (state == MUL2) || (state == MUL3) || (state == MUL4);
assign add_stb = (state == ADD1) || (state == ADD2);
always @(posedge CLK or posedge RST) begin
if (RST) begin
state <= IDLE;
O_STB <= 0;
O_CRE <= 0;
O_CIM <= 0;
mult_ack <= 0;
add_ack <= 0;
end else begin
state <= next_state;
case (state)
IDLE: begin
O_STB <= 0;
if (I_STB) begin
// startujemy obliczenia
a <= 0; b <= 0; c <= 0; d <= 0;
end
mult_ack <= 0;
add_ack <= 0;
end
MUL1: begin
mult_a <= I_ARE;
mult_b <= I_BRE;
mult_ack <= 1;
end
MUL2: begin
mult_a <= I_AIM;
mult_b <= I_BIM;
mult_ack <= 1;
end
MUL3: begin
mult_a <= I_ARE;
mult_b <= I_BIM;
mult_ack <= 1;
end
MUL4: begin
mult_a <= I_AIM;
mult_b <= I_BRE;
mult_ack <= 1;
end
ADD1: begin
// dodawanie wyników MUL1 i MUL2 (mul_ac i mul_bd)
a <= mul_ac;
b <= mul_bd;
add_ack <= 1;
end
ADD2: begin
// odejmowanie (mul_ad i mul_bc) => a - b
// tutaj trzeba zmienić na odejmowanie, więc podamy a = mul_ad, b = mul_bc i zrobimy dodanie z dopełnieniem do 2
a <= mul_ad;
b <= (~mul_bc) + 1; // dopełnienie do 2 = -b
add_ack <= 1;
end
DONE: begin
O_CRE <= add_result; // wynik z ADD1
O_CIM <= add_result; // wynik z ADD2
O_STB <= 1;
mult_ack <= 0;
add_ack <= 0;
end
endcase
end
end
// Logika przejścia stanów (prosta wersja, w prawdziwym projekcie warto synchronizować handshaki)
always @(*) begin
next_state = state;
case (state)
IDLE: if (I_STB) next_state = MUL1;
MUL1: next_state = MUL2;
MUL2: next_state = MUL3;
MUL3: next_state = MUL4;
MUL4: next_state = ADD1;
ADD1: next_state = ADD2;
ADD2: next_state = DONE;
DONE: if (!I_STB) next_state = IDLE;
endcase
end
// Zapisywanie wyników mnożeń do rejestrów
always @(posedge CLK) begin
if (state == MUL1) mul_ac <= mult_result[31:0];
else if (state == MUL2) mul_bd <= mult_result[31:0];
else if (state == MUL3) mul_ad <= mult_result[31:0];
else if (state == MUL4) mul_bc <= mult_result[31:0];
end
endmodule