summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2022-11-06 12:22:37 -0600
committerAlejandro Soto <alejandro@34project.org>2022-11-06 12:34:25 -0600
commit044d2d73f0fbe6e1e42934f01b0f339776881b55 (patch)
tree358703da80e67f09e8d7824b35af13accaaa676f
parentff5f2a94c06ce3af9cc04033220dcd0f6c8826e3 (diff)
Add multiplier unit
Diffstat (limited to '')
-rw-r--r--rtl/core/arm810.sv22
-rw-r--r--rtl/core/mul.sv182
-rw-r--r--rtl/core/uarch.sv1
-rw-r--r--tb/dsp_mul.sv45
4 files changed, 117 insertions, 133 deletions
diff --git a/rtl/core/arm810.sv b/rtl/core/arm810.sv
index 3bc2769..b3dd92e 100644
--- a/rtl/core/arm810.sv
+++ b/rtl/core/arm810.sv
@@ -125,9 +125,27 @@ module arm810
.c(c_shifter)
);
- //TODO
logic mul, mul_add, mul_long, mul_signed, mul_ready;
- assign mul_ready = 1;
+ word mul_a, mul_b, mul_c_hi, mul_c_lo, mul_q_hi, mul_q_lo;
+ psr_flags mul_flags;
+
+ core_mul mult
+ (
+ .a(mul_a),
+ .b(mul_b),
+ .c_hi(mul_c_hi),
+ .c_lo(mul_c_lo),
+ .long_mul(mul_long),
+ .add(mul_add),
+ .sig(mul_signed),
+ .start(mul),
+ .q_hi(mul_q_hi),
+ .q_lo(mul_q_lo),
+ .n(mul_flags.n),
+ .z(mul_flags.z),
+ .ready(mul_ready),
+ .*
+ );
ptr data_addr;
logic data_start, data_write, data_ready, insn_ready;
diff --git a/rtl/core/mul.sv b/rtl/core/mul.sv
index 4b0d149..616905f 100644
--- a/rtl/core/mul.sv
+++ b/rtl/core/mul.sv
@@ -1,141 +1,61 @@
-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
+`include "core/uarch.sv"
- 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
+// Realiza la operación a * b + c = q
+module core_mul
+(
+ input logic clk, // clock, ya que es una máquina de estados
+ input word a, // primer sumando
+ b, // segundo sumando
+ c_hi, // parte más significativa de c
+ c_lo, // parte menos significativa de c
+ input logic long_mul, // 1 si c es de 2 words, cualquier otro valor si c es de 1 word
+ add, // 1 si c se suma
+ sig, // 1 si a y b son signed
+ start, // 1 indica que se inicie la multiplicacion
+
+ output word q_hi, // parte más significativa del resultado
+ q_lo, // parte menos significativa del resultado
+ output logic n, // no hay C ni V, ya que se dejan unaffected
+ z,
+ ready // 1 cuando la multiplicación está lista
);
- 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};
+ logic wait_state;
+ dword c, q;
+
+ assign ready = wait_state == {$bits(wait_state){1'b0}};
+ assign {q_hi, q_lo} = q;
+ assign n = long_mul ? q_hi[$bits(q_hi) - 1] : q_lo[$bits(q_lo) - 1];
+ assign z = q_lo == 0 && (!long_mul || q_hi == 0);
+
+ dsp_mul ip
+ (
+ .clock0(clk),
+ .aclr0(0), //TODO
+ .ena0(start || !ready),
+ .dataa_0(a),
+ .datab_0(b),
+ .chainin(c),
+ .signa(sig),
+ .signb(sig),
+ .result(q)
+ );
always_comb
- if (!add)
- c = {(2*W){1'b0}};
- else if (c_size)
- c = {2'b0, c_hi, c_lo};
+ if(!add)
+ c = {$bits(c){1'b0}};
+ else if(long_mul)
+ c = {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
+ c = {{$bits(word){sig && c_lo[$bits(c_lo) - 1]}}, c_lo};
-
-/*
-
-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));
+ always_ff @(posedge clk)
+ if(wait_state > {$bits(wait_state){1'b0}})
+ wait_state <= wait_state - 1;
+ else if(start)
+ wait_state <= 1;
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
+ wait_state = 0;
-
-*/
+endmodule
diff --git a/rtl/core/uarch.sv b/rtl/core/uarch.sv
index b6dfc76..4162272 100644
--- a/rtl/core/uarch.sv
+++ b/rtl/core/uarch.sv
@@ -8,6 +8,7 @@ typedef logic[3:0] reg_num;
typedef logic[2:0] cp_opcode;
typedef logic[15:0] reg_list;
typedef logic[31:0] word;
+typedef logic[63:0] dword;
typedef logic[29:0] ptr;
`define R14 4'b1110
diff --git a/tb/dsp_mul.sv b/tb/dsp_mul.sv
new file mode 100644
index 0000000..d6fcb6a
--- /dev/null
+++ b/tb/dsp_mul.sv
@@ -0,0 +1,45 @@
+module dsp_mul
+(
+ output logic [63:0] result, // result.result
+ input logic [31:0] dataa_0, // dataa_0.dataa_0
+ input logic [31:0] datab_0, // datab_0.datab_0
+ input logic signa, // signa.signa
+ input logic signb, // signb.signb
+ input logic clock0, // clock0.clock0
+ input logic ena0, // ena0.ena0
+ input logic aclr0, // aclr0.aclr0
+ input logic [63:0] chainin // chainin.chainin
+);
+
+ logic[31:0] hold_a, hold_b;
+ logic[63:0] hold_chainin, ext_a, ext_b, product;
+ logic hold_signa, hold_signb;
+
+ assign ext_a = {{32{hold_signa && hold_a[31]}}, hold_a};
+ assign ext_b = {{32{hold_signb && hold_b[31]}}, hold_b};
+
+ always_comb
+ unique case({hold_signa, hold_signb})
+ 2'b00: product = ext_a * ext_b;
+ 2'b01: product = ext_a * $signed(ext_b);
+ 2'b10: product = $signed(ext_a) * ext_b;
+ 2'b11: product = $signed(ext_a) * $signed(ext_b);
+ endcase
+
+ always @(posedge clock0 or negedge aclr0)
+ if(!aclr0) begin
+ result <= {64{1'bx}};
+ hold_a <= {32{1'bx}};
+ hold_b <= {32{1'bx}};
+ hold_signa <= 1'bx;
+ hold_signb <= 1'bx;
+ end else if(ena0) begin
+ hold_a <= dataa_0;
+ hold_b <= datab_0;
+ hold_chainin <= chainin;
+ hold_signa <= signa;
+ hold_signb <= signb;
+ result <= hold_chainin + product;
+ end
+
+endmodule