`include "global.v"
/*
`define STAT_RESET 3'b000
`define STAT_FIRST_INPUT 3'b001
`define STAT_SECOND_INPUT 3'b010
`define STAT_THIRD_INPUT 3'b011
`define STAT_FOURTH_INPUT 3'b100
`define STAT_RESULT_PLUS 3'b101
`define STAT_RESULT_MINUS 3'b110
`define STAT_RESULT_MULTIPLY 3'b111
`define BCD_NUM 4'd10
`define PLUS 4'd11
`define MINUS 4'd12
`define MULTIPLY 4'd13
`define ENTER 4'd14
`define OTHER_INPUT 4'd15
*/
module add_minus_multiply(
output reg [3:0] out1, // num1, dig2
output reg [3:0] out2, // num1, dig1
output reg [3:0] out3, // num2, dig2
output reg [3:0] out4, // num2, dig1
input [2:0] state,
input [3:0] in,
input clk,
input rst_n
);
reg [3:0] in_delay;
reg [2 * 4 - 1:0] in_window; // 2 * BCD_BID_WIDTH
wire [3:0] in_delay_next;
reg [3:0] out1_next;
reg [3:0] out2_next;
reg [3:0] out3_next;
reg [3:0] out4_next;
reg [7:0] sum; // 0~198, smaller than 2 ^^ 8
reg [7:0] difference; // -99~99 -> 0~198(plus 99), smaller than 2 ^^ 8
reg [13:0] product; // 0~9801, smaller than 2 ^^ 14
reg [7:0] sum_next; // 0~198, smaller than 2 ^^ 8
reg [7:0] difference_next; // -99~99 -> 0~198(plus 99), smaller than 2 ^^ 8
reg [13:0] product_next; // 0~9801, smaller than 2 ^^ 14
// sum, difference, product combinational
always @* begin
if (state == `STAT_FOURTH_INPUT) begin
sum_next = (10 * out1 + out2) + (10 * out3 + out4);
difference_next = (10 * out1 + out2) - (10 * out3 + out4) + 8'd99;
product_next = (10 * out1 + out2) * (10 * out3 + out4);
end else begin
sum_next = sum;
difference_next = difference;
product = product;
end
end
// sum, difference, product sequential
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
sum <= 8'd0;
difference <= 8'd0;
product <= 14'd0;
end else begin
sum <= sum_next;
difference <= difference_next;
product <= product_next;
end
end
// in_window shift register
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
in_window = 8'b0; // 2 * BCD_BID_WIDTH
end else begin
in_window = {in_window[3:0], in};
end
end
// in_delay_next
assign in_delay_next = in_window[7:4];
// in_delay (delay 1 clk pulse)
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
in_delay <= 4'd0;
end else begin
in_delay <= in_delay_next;
end
end
// combinational
always @* begin
case (state)
`STAT_RESET: begin
out1_next = 4'd0;
out2_next = 4'd0;
out3_next = 4'd0;
out4_next = 4'd0;
end
`STAT_FIRST_INPUT: begin
out1_next = in_delay;
out2_next = out2;
out3_next = out3;
out4_next = out4;
end
`STAT_SECOND_INPUT: begin
out1_next = out1;
out2_next = in_delay;
out3_next = out3;
out4_next = out4;
end
`STAT_THIRD_INPUT: begin
out1_next = out1;
out2_next = out2;
out3_next = in_delay;
out4_next = out4;
end
`STAT_FOURTH_INPUT: begin
out1_next = out1;
out2_next = out2;
out3_next = out3;
out4_next = in_delay;
end
`STAT_RESULT_PLUS: begin
out1_next = 4'd0;
out2_next = sum / 100;
out3_next = sum / 10 % 10;
out4_next = sum % 10;
end
`STAT_RESULT_MINUS: begin
out1_next = (difference < 8'd99) ? `MINUS : 4'd0;
out2_next = 4'd0;
out3_next = (difference < 8'd99) ? (8'd99 - difference) / 10
: (difference - 8'd99) / 10 ;
out4_next = (difference < 8'd99) ? (8'd99 - difference) % 10
: (difference - 8'd99) % 10 ;
end
`STAT_RESULT_MULTIPLY: begin
out1_next = product / 1000;
out2_next = product / 100 % 10;
out3_next = product / 10 % 10;
out4_next = product % 10;
end
default: begin
out1_next = 4'd0;
out2_next = 4'd0;
out3_next = 4'd0;
out4_next = 4'd0;
end
endcase
end
// sequential
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
out1 <= 4'd0;
out2 <= 4'd0;
out3 <= 4'd0;
out4 <= 4'd0;
end else begin
out1 <= out1_next;
out2 <= out2_next;
out3 <= out3_next;
out4 <= out4_next;
end
end
endmodule