// --------------------------------------------------------------------
//
// Major Functions: CALUCULATOR_TOP
//
// --------------------------------------------------------------------
//
// Revision History :
// --------------------------------------------------------------------
// Ver :| Author :| Mod. Date :| Changes Made:
// V1.0 :| Koh Johguchi :| 12/17/19 :| Shinshu Univ.
// --------------------------------------------------------------------
module CALUCULATOR_TOP(
iSTART, //press the button for transmitting instrucions to device;
iRST_n, //FSM reset signal;
iCLK_50, //clock source;
PS2_CLK, //ps2_clock signal inout;
PS2_DAT, //ps2_data signal inout;
oLEFBUT, //left button press display;
oRIGBUT, //right button press display;
oMIDBUT, //middle button press display;
oX_MOV1, //lower SEG of mouse displacement display for X axis.
oX_MOV2, //higher SEG of mouse displacement display for X axis.
oY_MOV1, //lower SEG of mouse displacement display for Y axis.
oY_MOV2, //higher SEG of mouse displacement display for Y axis.
oZ_MOV1, //lower SEG of mouse displacement display for Z axis.
oZ_MOV2 //higher SEG of mouse displacement display for Z axis.
);
//=======================================================
// PORT declarations
//=======================================================
input iSTART;
input iRST_n;
input iCLK_50;
inout PS2_CLK;
inout PS2_DAT;
output oLEFBUT;
output oRIGBUT;
output oMIDBUT;
output [6:0] oX_MOV1;
output [6:0] oX_MOV2;
output [6:0] oY_MOV1;
output [6:0] oY_MOV2;
output [6:0] oZ_MOV1;
output [6:0] oZ_MOV2;
wire PS2_READY;
wire [15:0] SCANCODE;
// すべてのlatchを統合し扱いやすくする。
// そのため[xyz]_latchをwireに変更。
reg [23:0] latches;
wire [7:0] x_latch, y_latch, z_latch;
assign x_latch = latches[7:0];
assign y_latch = latches[15:8];
assign z_latch = latches[23:16];
wire clk;
// 計算機で使用する変数定義
// 計算機のステータス 0=operand0, 1=operand1, 2=response
reg [1:0] status;
// 演算対象とその符号
reg [19:0] operand_0, operand_1;
reg operand_sign_0, operand_sign_1;
// 演算子
reg [3:0] operator;
// 演算子入力可能, イコール入力可能, エラー発生のフラグ
reg operator_allow, enter_allow, error_occurred;
// 演算結果の関数の戻り値用変数(sign,value)
reg [24:0] result_recv;
// 演算結果と割り算時の余り, その符号
reg [23:0] result, remainder;
reg result_sign;
// キーコード変換関数の戻り値用変数
reg [3:0] oNUM;
// キーコードを数値に置き換える関数
// 使用していない領域で記号もincrementな数値に変換
function [3:0] CODE2NUM;
input [15:0] CODE;
case(CODE)
16'hf070: CODE2NUM = 4'd0;
16'hf069: CODE2NUM = 4'd1;
16'hf072: CODE2NUM = 4'd2;
16'hf07a: CODE2NUM = 4'd3;
16'hf06b: CODE2NUM = 4'd4;
16'hf073: CODE2NUM = 4'd5;
16'hf074: CODE2NUM = 4'd6;
16'hf06c: CODE2NUM = 4'd7;
16'hf075: CODE2NUM = 4'd8;
16'hf07d: CODE2NUM = 4'd9;
16'hf079: CODE2NUM = 4'd10; // +
16'hf07b: CODE2NUM = 4'd11; // -
16'hf07c: CODE2NUM = 4'd12; // *
16'hf04a: CODE2NUM = 4'd13; // /
16'hf05a: CODE2NUM = 4'd14; // enter
default: CODE2NUM = 4'd15;
endcase
endfunction
// 数値をlatchに変換する関数
function [23:0] NUM2LATCHES;
input [23:0] NUM;
input SIGN;
// オーバーフロー確認
if (NUM > 24'd999999) begin
NUM2LATCHES = 24'hfedd00;
// マイナス時のオーバーフロー確認
end else if (SIGN == 1 && NUM > 24'd99999) begin
NUM2LATCHES = 24'hfedd00;
end else begin
// 数値を変換する
NUM2LATCHES[3:0] = NUM % 4'd10;
NUM2LATCHES[7:4] = (NUM / 4'd10) % 4'd10;
NUM2LATCHES[11:8] = (NUM / 8'd100) % 4'd10;
NUM2LATCHES[15:12] = (NUM / 12'd1000) % 4'd10;
NUM2LATCHES[19:16] = (NUM / 16'd10000) % 4'd10;
NUM2LATCHES[23:20] = (NUM / 20'd100000) % 4'd10;
// 先頭の0をblankに置き換え
if (NUM2LATCHES[23:20] == 0) NUM2LATCHES[23:20] = 4'hf;
if (NUM2LATCHES[19:16] == 0 && NUM2LATCHES[23:20] == 4'hf) NUM2LATCHES[19:16] = 4'hf;
if (NUM2LATCHES[15:12] == 0 && NUM2LATCHES[19:16] == 4'hf) NUM2LATCHES[15:12] = 4'hf;
if (NUM2LATCHES[11:8] == 0 && NUM2LATCHES[15:12] == 4'hf) NUM2LATCHES[11:8] = 4'hf;
if (NUM2LATCHES[7:4] == 0 && NUM2LATCHES[11:8] == 4'hf) NUM2LATCHES[7:4] = 4'hf;
// マイナスの場合、頭にハイフンをつける
if (SIGN == 1) begin
if (NUM2LATCHES[7:4] == 4'hf) NUM2LATCHES[7:4] = 4'ha;
else if (NUM2LATCHES[11:8] == 4'hf) NUM2LATCHES[11:8] = 4'ha;
else if (NUM2LATCHES[15:12] == 4'hf) NUM2LATCHES[15:12] = 4'ha;
else if (NUM2LATCHES[19:16] == 4'hf) NUM2LATCHES[19:16] = 4'ha;
else if (NUM2LATCHES[23:20] == 4'hf) NUM2LATCHES[23:20] = 4'ha;
end
end
endfunction
// 複数の数値をlatchに変換する関数
// 割り算の商と余りを表示する用 xxx_yyyのようにアンダーバーでsepする。
function [23:0] MNUM2LATCHES;
input [23:0] NUM0;
input SIGN;
input [23:0] NUM1;
reg [23:0] num0_latches, num1_latches;
reg [51:0] combined_latches;
// それぞれの数値をlatchに変換
num0_latches = NUM2LATCHES(NUM0, SIGN);
num1_latches = NUM2LATCHES(NUM1, 0);
// 余りの先端blankの数によって結合する場所を場合分け
if (num1_latches[23:20] != 4'hf) begin
combined_latches = {num0_latches, 4'hb, num1_latches[23:0]};
end else if (num1_latches[19:16] != 4'hf) begin
combined_latches = {4'hf, num0_latches, 4'hb, num1_latches[19:0]};
end else if (num1_latches[15:12] != 4'hf) begin
combined_latches = {8'hff, num0_latches, 4'hb, num1_latches[15:0]};
end else if (num1_latches[11:8] != 4'hf) begin
combined_latches = {12'hfff, num0_latches, 4'hb, num1_latches[11:0]};
end else if (num1_latches[7:4] != 4'hf) begin
combined_latches = {16'hffff, num0_latches, 4'hb, num1_latches[7:0]};
end else begin
combined_latches = {20'hfffff, num0_latches, 4'hb, num1_latches[3:0]};
end
// オーバーフロー確認
if (combined_latches < 52'hfffffff000000) combined_latches = 52'hfedd00;
MNUM2LATCHES = combined_latches[23:0];
endfunction
// 符号に対応した加算関数
function [24:0] ADDITION;
input [19:0] OP0;
input OPS0;
input [19:0] OP1;
input OPS1;
reg [23:0] RES;
// 符号によって場合分け
if (OPS0 == OPS1) begin
RES = OP0 + OP1;
ADDITION = {OPS0, RES};
end else if (OP0 > OP1) begin
RES = OP0 - OP1;
ADDITION = {OPS0, RES};
end else if (OP0 == OP1) begin
RES = OP0 - OP1;
ADDITION = {1'b0, RES};
end else begin
RES = OP1 - OP0;
ADDITION = {OPS1, RES};
end
endfunction
// 符号に対応した乗算関数
function [24:0] MULTIPLICATION;
input [19:0] OP0;
input OPS0;
input [19:0] OP1;
input OPS1;
reg [39:0] RES;
RES = OP0 * OP1;
if (RES > 40'hffffff) RES = 40'hffffff;
if (RES == 0) begin
MULTIPLICATION = {1'b0, 24'h000000};
end else begin
MULTIPLICATION = {OPS0 ^ OPS1, RES[23:0]};
end
endfunction
always @ (posedge clk or negedge iRST_n)
begin
if ( !iRST_n ) begin
// 初期化
latches <= 24'hffffff;
{
status, operand_0, operand_1, operand_sign_0, operand_sign_1,
operator, operator_allow, enter_allow, error_occurred,
result, remainder, result_sign
} <= 0;
end else if ( !PS2_READY ) begin
// キーコードを数値に変換
oNUM = CODE2NUM(SCANCODE);
// キーによって処理の場合分け
// 押されたキーが数値のとき
if (oNUM <= 4'd9) begin
case(status)
2'd0: begin
if ((operand_sign_0 == 0 && operand_0 * 4'd10 + oNUM <= 24'd999999) || (operand_sign_0 == 1 && operand_0 * 4'd10 + oNUM <= 24'd99999)) begin
operand_0 = operand_0 * 4'd10 + oNUM;
operator_allow = 1;
latches = NUM2LATCHES(operand_0, operand_sign_0);
end
end
2'd1: begin
if ((operand_sign_1 == 0 && operand_1 * 4'd10 + oNUM <= 24'd999999) || (operand_sign_1 == 1 && operand_1 * 4'd10 + oNUM <= 24'd99999)) begin
operand_1 = operand_1 * 4'd10 + oNUM;
latches = NUM2LATCHES(operand_1, operand_sign_1);
enter_allow = 1;
end
end
endcase
end else begin
// ハイフン(マイナス)かつ演算子入力でないとき
if (!operator_allow && !enter_allow && oNUM == 4'd11) begin
case(status)
2'd0: begin
operand_sign_0 = ~operand_sign_0;
latches = {20'hfffff, (operand_sign_0 == 1) ? 4'ha : 4'hf};
end
2'd1: begin
operand_sign_1 = ~operand_sign_1;
latches = {20'hfffff, (operand_sign_1 == 1) ? 4'ha : 4'hf};
end
endcase
// operator_allow時の演算子入力
end else if (status == 2'd0 && operator_allow && oNUM <= 4'd13) begin
operator = oNUM;
operator_allow = 0;
status = 2'd1;
latches = 24'hffffff;
// enter_allow時の演算子入力、イコール入力(演算実行)
end else if (status == 2'd1 && enter_allow && oNUM <= 4'd14) begin
// 演算子によって場合分け
case(operator)
4'd10: begin // +
result_recv = ADDITION(operand_0, operand_sign_0, operand_1, operand_sign_1);
result = result_recv[23:0];
result_sign = result_recv[24];
end
4'd11: begin // -
result_recv = ADDITION(operand_0, operand_sign_0, operand_1, operand_sign_1 ^ 1);
result = result_recv[23:0];
result_sign = result_recv[24];
end
4'd12: begin // *
result_recv = MULTIPLICATION(operand_0, operand_sign_0, operand_1, operand_sign_1);
result = result_recv[23:0];
result_sign = result_recv[24];
end
4'd13: begin // /
// ゼロ除算エラーを検知
if (operand_1 == 0) begin
error_occurred = 1;
end else begin
result = operand_0 / operand_1;
result_sign = operand_sign_0 ^ operand_sign_1;
remainder = operand_0 % operand_1;
if (operand_sign_0 == 1 && remainder != 0) begin
result = result + 1'b1;
remainder = operand_1 - remainder;
end
if (result == 24'd0) begin
result_sign = 0;
end
end
end
endcase
// ゼロ除算エラーが発生した場合
if (error_occurred == 1) begin
latches = 24'hfedd01;
// 割り算の場合
// 余りが0のときのみcontinuous-calcを可能に
end else if (operator == 4'd13) begin
latches = MNUM2LATCHES(result, result_sign, remainder);
if (remainder != 0) begin
status = 2'd2;
end
end else begin
latches = NUM2LATCHES(result, result_sign);
end
// エラーコードのときリザルト画面に
if (latches[23:8] == 16'hfedd) status = 2'd2;
// continuous-calcへの対応
else if (status == 2'd1) begin
// enter
if (oNUM == 4'd14) begin
status = 2'd0;
operator = 0;
operator_allow = 1;
// 演算子
end else begin
status = 2'd1;
operator = oNUM;
operator_allow = 0;
end
operand_0 = result[19:0];
operand_sign_0 = result_sign;
operand_1 = 0;
operand_sign_1 = 0;
end
enter_allow = 0;
// テンキーのDel入力(クリア)
end else if (SCANCODE == 16'hf071) begin
case(status)
2'd0: begin
operand_0 = 0;
operand_sign_0 = 0;
latches = NUM2LATCHES(operand_0, operand_sign_0);
operator_allow = 0;
latches = 24'hffffff;
end
2'd1: begin
operand_1 = 0;
operand_sign_1 = 0;
latches = NUM2LATCHES(operand_1, operand_sign_1);
enter_allow = 0;
latches = 24'hffffff;
end
endcase
// esc/テンキーのnumlock入力(オールクリア)
end else if (SCANCODE == 16'hf076 || SCANCODE == 16'hf077) begin
latches <= 24'hffffff;
{
status, operand_0, operand_1, operand_sign_0, operand_sign_1,
operator, operator_allow, enter_allow, error_occurred,
result, remainder, result_sign
} <= 0;
end
end
end else begin
latches <= latches;
end
end
PS2 U0(
.iSTART(iSTART), //press the button for transmitting instrucions to device;
.iRST_n(iRST_n), //FSM reset signal;
.iCLK(clk), //clock source;
.PS2_CLK(PS2_CLK), //ps2_clock signal inout;
.PS2_DAT(PS2_DAT), //ps2_data signal inout;
.oLEFBUT(oLEFBUT), //left button press display;
.oRIGBUT(oRIGBUT), //right button press display;
.oMIDBUT(oMIDBUT), //middle button press display;
.PS2_READY(PS2_READY), //ready signal for PS2;
.SCANCODE(SCANCODE) //scan-code for PS2;
);
CLKDIV U1(
.iCLK(iCLK_50), //clock source;
.RSTB(iRST_n), //reset signal;
.oCLK(clk) //clock signal out;
);
//instantiation
SEG7_LUT U2(.oSEG(oX_MOV1),.iDIG(x_latch[3:0]));
SEG7_LUT U3(.oSEG(oX_MOV2),.iDIG(x_latch[7:4]));
SEG7_LUT U4(.oSEG(oY_MOV1),.iDIG(y_latch[3:0]));
SEG7_LUT U5(.oSEG(oY_MOV2),.iDIG(y_latch[7:4]));
SEG7_LUT U6(.oSEG(oZ_MOV1),.iDIG(z_latch[3:0]));
SEG7_LUT U7(.oSEG(oZ_MOV2),.iDIG(z_latch[7:4]));
endmodule