/* ----------------------------------------------------------------------------- * Project Name : Architectures of Processor Systems (APS) lab work * Organization : National Research University of Electronic Technology (MIET) * Department : Institute of Microdevices and Control Systems * Author(s) : Alexander Kharlamov * Email(s) : sasha_xarlamov@org.miet.ru See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details. * ------------------------------------------------------------------------------ */ module nexys_alu( input logic clk_i, input logic arstn_i, input logic [15:0] sw_i, output logic [15:0] led_o, output logic ca_o, output logic cb_o, output logic cc_o, output logic cd_o, output logic ce_o, output logic cf_o, output logic cg_o, output logic dp_o, output logic [ 7:0] an_o ); logic sign_on; assign sign_on = sw_i[5]; logic sext_operand_a; assign sext_operand_a = sign_on; logic sext_operand_b; assign sext_operand_b = sign_on; import alu_opcodes_pkg::*; logic [4:0] operator; assign operator = sw_i[4:0]; logic [31:0] operand_b; assign operand_b = {(sext_operand_b ? {27{sw_i[10]}} : 27'b0), sw_i[10: 6]}; logic [31:0] operand_a; assign operand_a = {(sext_operand_a ? {27{sw_i[15]}} : 27'b0), sw_i[15:11]}; logic [31:0] result; logic flag; alu alu_riscv ( .alu_op_i (operator), .a_i (operand_a), .b_i (operand_b), .result_o (result), .flag_o (flag) ); localparam int COUNTER_WIDTH = 10; logic [COUNTER_WIDTH-1:0] counter_next; logic [COUNTER_WIDTH-1:0] counter_ff; assign counter_next = counter_ff + COUNTER_WIDTH'('b1); always_ff @(posedge clk_i or negedge arstn_i) begin if (!arstn_i) counter_ff <= '0; else counter_ff <= counter_next; end logic [7:0] an_ff; logic [7:0] an_next; logic an_en; assign an_next = {an_ff[$left(an_ff)-1:0], an_ff[$left(an_ff)]}; assign an_en = ~|counter_ff; always_ff @(posedge clk_i or negedge arstn_i) begin if (!arstn_i) an_ff <= ~8'b1; else if (an_en) an_ff <= an_next; end function automatic logic [6:0] hex2semseg(input logic [3:0] hex); unique case (hex) 4'h0: return 7'b0000001; 4'h1: return 7'b1001111; 4'h2: return 7'b0010010; 4'h3: return 7'b0000110; 4'h4: return 7'b1001100; 4'h5: return 7'b0100100; 4'h6: return 7'b0100000; 4'h7: return 7'b0001111; 4'h8: return 7'b0000000; 4'h9: return 7'b0000100; 4'hA: return 7'b0001000; 4'hB: return 7'b1100000; 4'hC: return 7'b0110001; 4'hD: return 7'b1000010; 4'hE: return 7'b0110000; 4'hF: return 7'b0111000; endcase endfunction logic is_result_negative; assign is_result_negative = result[$left(result)] & sign_on; logic is_operand_a_negative; assign is_operand_a_negative = operand_a[$left(operand_a)]; logic is_operand_b_negative; assign is_operand_b_negative = operand_b[$left(operand_b)]; logic [31:0] result_sign_regard; assign result_sign_regard = is_result_negative ? (~result + 32'b1) : result; logic [4:0] operand_a_sign_regard; assign operand_a_sign_regard = is_operand_a_negative ? (~operand_a[4:0] + 5'b1) : (operand_a[4:0]); logic [4:0] operand_b_sign_regard; assign operand_b_sign_regard = is_operand_b_negative ? (~operand_b[4:0] + 5'b1) : (operand_b[4:0]); logic [63:0] bcd_result; logic [11:0] bcd_operand_a; logic [11:0] bcd_operand_b; bin2bcd #($bits(result_sign_regard)) bin2bcd_result ( .bin_i (result_sign_regard), .bcd_o (bcd_result ) ); bin2bcd #($bits(operand_a_sign_regard)) bin2bcd_operand_a ( .bin_i (operand_a_sign_regard), .bcd_o (bcd_operand_a ) ); bin2bcd #($bits(operand_b_sign_regard)) bin2bcd_operand_b ( .bin_i (operand_b_sign_regard), .bcd_o (bcd_operand_b ) ); localparam bit [6:0] MINUS = 7'b1111110; localparam bit [6:0] BLANK = 7'b1111111; logic [ 6:0] semseg; always_comb begin semseg = BLANK; unique case (1'b0) an_ff[0]: semseg = hex2semseg(bcd_result[ 3:0]); an_ff[1]: semseg = hex2semseg(bcd_result[ 7:4]); an_ff[2]: semseg = hex2semseg(bcd_result[11:8]); an_ff[3]: semseg = is_result_negative ? MINUS : BLANK; an_ff[4]: semseg = hex2semseg(bcd_operand_b[3:0]); an_ff[5]: semseg = (is_operand_b_negative ? MINUS : BLANK) & (|bcd_operand_b[5:4] ? hex2semseg({2'b0, bcd_operand_b[5:4]}) : BLANK); an_ff[6]: semseg = hex2semseg(bcd_operand_a[3:0]); an_ff[7]: semseg = (is_operand_a_negative ? MINUS : BLANK) & (|bcd_operand_a[5:4] ? hex2semseg({2'b0, bcd_operand_a[5:4]}) : BLANK); endcase end assign {ca_o, cb_o, cc_o, cd_o, ce_o, cf_o, cg_o} = semseg; assign dp_o = an_ff[6] ? 1'b1 : 1'b0; assign led_o[14:0] = result[14:0]; assign led_o[15] = flag; assign an_o = an_ff; endmodule module bin2bcd #( parameter int IN_WIDTH = 32, localparam int OUT_WIDTH_DIGITS = (2 * IN_WIDTH + 3) / 4, // each byte is represented as 2 digits. // And ceiling localparam int OUT_WIDTH = 4 * OUT_WIDTH_DIGITS ) ( input logic [IN_WIDTH -1:0] bin_i, output logic [OUT_WIDTH-1:0] bcd_o ); always @(bin_i) begin bcd_o = '0; for (int unsigned bit_number = 0; bit_number < IN_WIDTH; ++bit_number) begin // Iterate once for each bit in input number for (int unsigned digit_num = 0; digit_num < OUT_WIDTH_DIGITS; ++digit_num) begin if (bcd_o[4*digit_num+:4] >= 4'd5) bcd_o[4*digit_num+:4] = bcd_o[4*digit_num+:4] + 4'd3; // If any BCD digit is >= 5, add three end bcd_o = {bcd_o[$left(bcd_o)-1:0], bin_i[$left(bin_i)-bit_number]}; // Shift one bit, and shift in proper bit from input end end endmodule