summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rtl/core/mul/core_mul.sv.tmp103
-rw-r--r--rtl/core/mul/mul.sv141
-rw-r--r--rtl/top/mul_test.sv33
-rw-r--r--tb/top/mul_test.cpp101
4 files changed, 378 insertions, 0 deletions
diff --git a/rtl/core/mul/core_mul.sv.tmp b/rtl/core/mul/core_mul.sv.tmp
new file mode 100644
index 0000000..111e7ce
--- /dev/null
+++ b/rtl/core/mul/core_mul.sv.tmp
@@ -0,0 +1,103 @@
+module core_mul
+#(parameter W=32)
+( // realiza la operación a * b + c = q
+ input logic[W - 1:0] a, // primer sumando
+ b, // segundo sumando
+ input logic[W - 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,
+ 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 word q_hi, // parte más significa tiva del resultado
+ output word q_lo, // parte menos significativa del resultado
+ output logic z,
+ n, // no hay C ni V, ya que se dejan unaffected
+ q_sig // 1 si q es signed, cualquier otr 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á realizando
+);
+
+ //! TODO:
+ //! Testear que el algoritmo sirva bien @julian
+
+module BoothMul(clk,rst,start,a,b,rdy,p);
+
+ input rst;
+ input signed [3:0]a,b;
+ output signed [7:0]p;
+ output rdy;
+
+ logic signed [7:0] p,next_p,p_temp;
+ logic next_state, pres_state;
+ logic [1:0] temp,next_temp;
+ logic [1:0] count,next_count;
+ logic rdy, next_rdy;
+
+ parameter IDLE = 1'b0;
+ parameter START = 1'b1;
+
+ always @ (posedge clk or negedge rst) begin
+ if(!rst) begin
+ p <= 8'd0;
+ rdy <= 1'b0;
+ pres_state <= 1'b0;
+ temp <= 2'd0;
+ count <= 2'd0;
+ end
+ else begin
+ p <= next_p;
+ rdy <= next_rdy;
+ pres_state <= next_state;
+ temp <= next_temp;
+ count <= next_count;
+ end
+ end
+
+ always @ (*) begin
+ case(pres_state)
+ IDLE:
+ begin
+ next_count = 2'b0;
+ next_rdy = 1'b0;
+ if(start) begin
+ next_state = START;
+ next_temp = {a[0],1'b0};
+ next_p = {4'd0,a};
+ end
+ else begin
+ next_state = pres_state;
+ next_temp = 2'd0;
+ next_p = 8'd0;
+ end
+ end
+
+ START:
+ begin
+ case(temp)
+ 2'b10: p_temp = {p[7:4]-b,p[3:0]};
+ 2'b01: p_temp = {p[7:4]+b,p[3:0]};
+ default: p_temp = {p[7:4],p[3:0]};
+ endcase
+ next_temp = {a[count+1],a[count]};
+ next_count = count + 1'b1;
+ next_p = p_temp >>> 1;
+ next_rdy = (&count) ? 1'b1 : 1'b0;
+ next_state = (&count) ? IDLE : pres_state;
+ end
+ endcase
+ end
+endmodule
+
+
+endmodule
diff --git a/rtl/core/mul/mul.sv b/rtl/core/mul/mul.sv
new file mode 100644
index 0000000..4b0d149
--- /dev/null
+++ b/rtl/core/mul/mul.sv
@@ -0,0 +1,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
+
+
+*/
diff --git a/rtl/top/mul_test.sv b/rtl/top/mul_test.sv
new file mode 100644
index 0000000..1395772
--- /dev/null
+++ b/rtl/top/mul_test.sv
@@ -0,0 +1,33 @@
+`timescale 1 ns / 1 ps
+
+module mul_test
+#(parameter U=32)
+(
+ 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
+
+
+);
+ core_mul #(.U(U)) DUT (.*);
+
+endmodule
+
+
+
diff --git a/tb/top/mul_test.cpp b/tb/top/mul_test.cpp
new file mode 100644
index 0000000..1dcebdc
--- /dev/null
+++ b/tb/top/mul_test.cpp
@@ -0,0 +1,101 @@
+#include <cstdio>
+
+#include <verilated.h>
+#include <verilated_vcd_c.h>
+
+#include "Vmul_test.h" // From Verilating "top.v"
+
+int main(int argc, char** argv) {
+ Verilated::commandArgs(argc, argv); // Remember args
+ Verilated::traceEverOn(true);
+
+ Vmul_test top;
+ VerilatedVcdC trace;
+
+ top.trace(&trace, 0);
+ trace.open("mul_test.vcd");
+
+ top.a = 6;
+ top.b = 5;
+ top.clk = 0;
+ top.rst = 0;
+ top.start = 0;
+ top.result = 0;
+ top.rdy = 0;
+ top.c_hi = 0;
+ top.c_lo = 0;
+
+
+ int clk_tick = 0;
+ int time = 0;
+
+ for(int i = 0; i < 100; ++i)
+ {
+ if(++clk_tick == 5)
+ {
+ clk_tick = 0;
+ top.clk = !top.clk;
+ }
+
+
+ if(++clk_tick == 10)
+ {
+ top.rst = 1;
+ }
+
+ if(++clk_tick == 20)
+ {
+ top.start = 1;
+ }
+
+ if(++clk_tick == 30)
+ {
+ top.start = 0;
+ }
+
+ top.eval();
+ trace.dump(time++);
+
+ std::printf(" [%c%c%c%c]\n",
+ top.n ? 'N' : 'n',
+ top.z ? 'Z' : 'z',
+ top.c ? 'C' : 'c',
+ top.v ? 'V' : 'v');
+
+ std::printf("a=%d, b=%d, ready=%d, result=%d, [N=%d, Z=%d]",
+ top.a, top.b, top.rdy, top.result, top.n, top.z);
+ }
+
+ trace.close();
+ top.final(); // Done simulating
+}
+
+/*
+
+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
+
+
+*/ \ No newline at end of file