diff options
Diffstat (limited to '')
| -rw-r--r-- | rtl/core/mul/core_mul.sv.tmp | 103 | ||||
| -rw-r--r-- | rtl/core/mul/mul.sv | 141 | ||||
| -rw-r--r-- | rtl/top/mul_test.sv | 33 | ||||
| -rw-r--r-- | tb/top/mul_test.cpp | 101 |
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 |
