2017-10-26 00:47:50 +02:00

186 lines
4.8 KiB
Verilog

//
// 16bit x 10bit signed serial/parallel multiplier.
//
// Niels Moseley - Moseley Instruments 2017
// http://www.moseleyinstruments.com
//
//
//
module SPMUL (
clk,
rst_an,
sig_in,
coef_in,
result_out,
start,
done
);
//////////// CLOCK //////////
input clk;
//////////// RESET, ACTIVE LOW //////////
input rst_an;
//////////// MULTIPLIER INPUTS //////////
input signed [15:0] sig_in;
input signed [9:0] coef_in;
input start;
//////////// MULTIPLIER OUTPUT //////////
output reg signed [15:0] result_out;
output reg done;
//////////// internal signals //////////
reg signed [24:0] accumulator;
reg signed [9:0] coefreg;
reg signed [15:0] sigreg;
reg push_result;
reg load_operands;
reg [3:0] cur_state; // cur_state machine cur_state
reg [3:0] next_state;
reg domulcycle, accu_clr;
// clocked process
always @(posedge clk or negedge rst_an)
begin
if (rst_an == 0)
begin
accumulator <= 0;
coefreg <= 0;
cur_state <= 0;
end
else
begin
if (accu_clr == 1)
begin
accumulator <= 0;
end
if (load_operands == 1)
begin
coefreg <= coef_in;
sigreg <= sig_in;
end
if (domulcycle == 1)
begin
// note: leave coefreg[9] untouched
// as this is the sign bit...
if (coefreg[8] == 1'b1)
accumulator <= $signed({accumulator[23:0], 1'b0}) + sigreg;
else
accumulator <= {accumulator[23:0], 1'b0};
coefreg[8:0] <= {coefreg[7:0], 1'b0};
end
if (push_result == 1)
begin
if (coefreg[9] == 0)
result_out <= accumulator[24:9];
else
result_out <= $signed(~accumulator[24:9]) + 1;
end
cur_state <= next_state;
end
end
parameter S_IDLE = 4'b0000,
S_CYCLE1 = 4'b0001,
S_CYCLE2 = 4'b0010,
S_CYCLE3 = 4'b0011,
S_CYCLE4 = 4'b0100,
S_CYCLE5 = 4'b0101,
S_CYCLE6 = 4'b0110,
S_CYCLE7 = 4'b0111,
S_CYCLE8 = 4'b1000,
S_CYCLE9 = 4'b1001,
S_CYCLE10 = 4'b1010;
// FSM combinational process
always @(*)
begin
// FSM defaults
done <= 0;
next_state <= cur_state;
accu_clr <= 0;
domulcycle <= 0;
push_result <= 0;
load_operands <= 0;
case(cur_state)
S_IDLE: // IDLE cur_state
begin
accu_clr <= 1;
if (start == 1)
begin
load_operands <= 1;
next_state <= S_CYCLE1;
end
else
begin
done <= 1;
next_state <= S_IDLE;
end
end
S_CYCLE1:
begin
domulcycle <= 1;
next_state <= S_CYCLE2;
end
S_CYCLE2:
begin
domulcycle <= 1;
next_state <= S_CYCLE3;
end
S_CYCLE3:
begin
domulcycle <= 1;
next_state <= S_CYCLE4;
end
S_CYCLE4:
begin
domulcycle <= 1;
next_state <= S_CYCLE5;
end
S_CYCLE5:
begin
domulcycle <= 1;
next_state <= S_CYCLE6;
end
S_CYCLE6:
begin
domulcycle <= 1;
next_state <= S_CYCLE7;
end
S_CYCLE7:
begin
domulcycle <= 1;
next_state <= S_CYCLE8;
end
S_CYCLE8:
begin
domulcycle <= 1;
next_state <= S_CYCLE9;
end
S_CYCLE9:
begin
domulcycle <= 1;
next_state <= S_CYCLE10;
end
S_CYCLE10:
begin
push_result <= 1;
next_state <= S_IDLE;
end
default:
cur_state <= 0;
endcase
end
endmodule