summaryrefslogtreecommitdiff
path: root/rtl/core/mul/mul.sv
blob: 4b0d149afdf7d5a4e91376f8bbc613744287b67e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
module core_mul
#(parameter U=32)
(   // realiza la operación a * b + c = q
	input logic[U - 1:0]	a,		// primer sumando
							b,		// segundo sumando
	input logic[U - 1:0]	c_hi,	// parte más significativa de c
							c_lo,	// parte menos significativa de c
	input logic				c_size,	// 1 si c es de 2 words, cualquier otro valor si c es de 1 word
							clk,	// clock, ya que es una máquina de estados
							rst,	// reset
							add,	// 1 si c se suma
							sig,	// 1 si a y b son signed
							q_size,	// 1 si q es de 2 words, cualquier otro valor si es de 1 word
							start,	// 1 indica que se inicie la multiplicacion

	output  logic [U - 1:0] q_hi,	// parte más significativa del resultado
	output  logic [U - 1:0] q_lo,	// parte menos significativa del resultado
	output  logic [2*U-1:0] result,
	output  logic 			n,		// no hay C ni V, ya que se dejan unaffected
							z,
							q_sig,	// 1 si q es signed, cualquier otro valor si es unsigned
							rdy		// 1 cuando la multiplicación está lista
	
	//*Se asume lo siguiente:
	//	- Las señales de entrada son constantes desde el instante en el que start es 1 hasta que rdy sea 1
	//	- El valor de start puede cambiar durante la multiplicación, pero va a ser ignorado hasta que rdy sea 1
	//	- El valor de q es UNPREDICTABLE hasta que rdy sea 1
	//	- Las condiciones para iniciar una multiplicación son que rdy sea 1 y start sea 1
	//	- rdy solo no es 1 mientras la multiplicación se está realiresultando
);

	localparam W = U+1; //U=32 , W=33
	localparam IDLE = 1'b0;
	localparam START = 1'b1;

	logic signed [2*W - 1:0] result_ext, next_result, result_temp; //66
	logic next_state, current_state;
	logic [1:0] temp, next_temp; 	//temp es la concatenación de {Q0,Qres}
	logic [$clog2(U) - 1:0] count, next_count;
	logic [2*W - 1:0] c;	//66
	logic [2*W - 1:0] a_ext, b_ext;
	logic next_rdy;
	
	assign a_ext = {{(W+1){sig && a[W-1]}}, a}; //65
	assign b_ext = {{(W+1){sig && b[W-1]}}, b};

	always_comb
		if (!add)
			c = {(2*W){1'b0}};
		else if (c_size)
			c = {2'b0, c_hi, c_lo};
		else
			c = {{(W+1){sig && c_lo[W-1]}}, c_lo};

	always @ (posedge clk or negedge rst) begin
		if(!rst) begin
			result_ext      <= {(2*W){1'b0}};
			rdy      		<= 1'b0;
			current_state 	<= 1'b0;
			temp       		<= 2'd0;
			count      		<= {$clog2(U){1'b0}};
		end	
		else begin
			result_ext      <= next_result;
			rdy      		<= next_rdy;
			current_state 	<= next_state;
			temp       	   	<= next_temp;
			count      		<= next_count;
		end
	end

	always @ (*) begin 
		unique case(current_state)
			IDLE: begin
				next_count = {$clog2(U){1'b0}};
				next_rdy = 1'b0;
				if(start) begin
					next_state  = START;
					next_temp   = {a_ext[0],1'b0};
					next_result = {{(W/2){1'b0}},a_ext};
				end
				else begin
					next_state  = current_state;
					next_temp   = 2'd0;
					next_result = result_ext + c;
				end
			end

			START: begin
				unique case(temp)
					2'b10:   result_temp = {result_ext[2*W-1: U]-b_ext, result_ext[U-1:0]};
					2'b01:   result_temp = {result_ext[2*W-1: U]+b_ext, result_ext[U-1:0]};
					default: result_temp = result_ext;
				endcase
				next_temp  	= {a_ext[count+1],a_ext[count]};
				next_count 	= count + 1'b1;
				next_result	= result_temp >>> 1;
				next_rdy 	= (&count) ? 1'b1 : 1'b0; 
				next_state 	= (&count) ? IDLE : current_state;
				result 		= result_ext[2*U-1:0];	
				q_hi 		= result_ext[2*U-1: U];
				q_lo 		= result_ext[U-1: 0];
				n 			= result_ext[2*W-1];
				z 			= (|result_ext) ? 1'b0 : 1'b1; 
			end
		endcase
	end


endmodule


/*

module mul_tb();

	logic clk,rst,start;
	logic[7:0]X,Y;
	logic[15:0]Z;
	logic valid;

	always #5 clk = ~clk;

	core_mul_mul #(.W(8)) inst (.clk(clk),.rst(rst),.start(start),.a(X),.b(Y),.rdy(valid),.result(Z));

	initial
	$monitor($time,"a=%d, b=%d, ready=%d, Z=%d ",X,Y,valid,Z);
	initial
	begin
	X=255;Y=150;clk=1'b1;rst=1'b0;start=1'b0;
	#10 rst = 1'b1;
	#10 start = 1'b1;
	#10 start = 1'b0;
	@valid
	#10 X=-80;Y=-10;start = 1'b1;
	#10 start = 1'b0;
	end      
endmodule


*/