/*
 Режимы работы АЛУ
 ---------------------------------------------------------------------
 0 LDI    9  EOR      11 LSR      19 MULSU
 1 CPC    A  OR       12 ROR
 2 SBC    B  <SREG>   13 DEC
 3 ADD    C  COM      14 ADIW
 5 CP     D  NEG      15 SBIW
 6 SUB    E  SWAP     16 BLD
 7 ADC    F  INC      17 MUL
 8 AND    10 ASR      18 MULS
 ---------------------------------------------------------------------
*/

module avralu
(
    // Входные данные на обработку
    input      [ 4:0] mode,         // режим
    input      [ 7:0] dst,          // dst
    input      [ 7:0] src,          // src
    input      [15:0] src16,        // src (16 бит)
    input      [ 7:0] si,           // sreg

    // Результат
    output reg [ 7:0] so,           // Исходящие флаги
    output reg [ 7:0] resb,         // Результат 8 бит
    output reg [15:0] resw          // Результат 16 бит
);

// Вычисления
wire [7:0] sub  = dst - src;            // Вычитание
wire [7:0] add  = dst + src;            // Сложение
wire [8:0] sbc  = dst - src - si[0];    // Вычитание с заемом
wire [7:0] adc  = dst + src + si[0];    // Сложение с заемом
wire [7:0] lsr  = {  1'b0, dst[7:1]};   // Логический сдвиг вправо
wire [7:0] ror  = { si[0], dst[7:1]};   // Сдвиг вправо с заемом
wire [7:0] asr  = {dst[7], dst[7:1]};   // Арифметический сдвиг вправо
wire [7:0] neg  = -dst;                 // Отрицательное значение
wire [7:0] inc  = dst + 1;              // Инкремент
wire [7:0] dec  = dst - 1;              // Декремент
wire [7:0] com  = dst ^ 8'hFF;          // Комплементация
wire [7:0] swap = {dst[3:0], dst[7:4]}; // Обмен нибблами
reg        carry;

// 16 битные вычисления
wire [15:0] adiw  = src16 + src;
wire [15:0] sbiw  = src16 - src;
wire [15:0] mul   = dst[7:0] * src[7:0];
wire [15:0] mulsu = {{8{dst[7]}}, dst[7:0]} * src[7:0];
wire [15:0] muls  = {{8{dst[7]}}, dst[7:0]} * {{8{src[7]}}, src[7:0]};

// Флаги переполнения после сложения и вычитания
wire add_flag_v = (dst[7] &  src[7] & !resb[7]) | (!dst[7] & !src[7] & resb[7]);
wire sub_flag_v = (dst[7] & !src[7] & !resb[7]) | (!dst[7] &  src[7] & resb[7]);
wire neg_flag_v = (resb == 8'h80);

// Флаги половинного переполнения после сложения и вычитания
wire add_flag_h = ( dst[3] & src[3]) | (src[3] & !resb[3]) | (!resb[3] &  dst[3]);
wire sub_flag_h = (!dst[3] & src[3]) | (src[3] &  resb[3]) | ( resb[3] & !dst[3]);
wire neg_flag_h = dst[3] | (dst[3] & resb[3]) | resb[3];

// Флаги ADIW, SBIW
wire adiw_v = !src16[15] & resw [15];
wire adiw_c = !resw [15] & src16[15];

// Логические флаги
wire [7:0] set_logic_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ si[5],
    /* s */ resb[7],
    /* v */ 1'b0,
    /* n */ resb[7],
    /* z */ resb[7:0] == 0,
    /* c */ si[0]
};

// Флаги после вычитания с переносом
wire [7:0] set_subcarry_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ sub_flag_h,
    /* s */ sub_flag_v ^ resb[7],
    /* v */ sub_flag_v,
    /* n */ resb[7],
    /* z */ (resb[7:0] == 0) & si[1],
    /* c */ sbc[8]
};

// Флаги после вычитания
wire [7:0] set_subtract_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ sub_flag_h,
    /* s */ sub_flag_v ^ resb[7],
    /* v */ sub_flag_v,
    /* n */ resb[7],
    /* z */ (resb[7:0] == 0),
    /* c */ dst < src
};

// Флаги после COM
wire [7:0] set_com_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ si[5],
    /* s */ resb[7],
    /* v */ 1'b0,
    /* n */ resb[7],
    /* z */ (resb[7:0] == 0),
    /* c */ 1'b1
};

// Флаги после NEG
wire [7:0] set_neg_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ neg_flag_h,
    /* s */ neg_flag_v ^ resb[7],
    /* v */ neg_flag_v,
    /* n */ resb[7],
    /* z */ (resb[7:0] == 0),
    /* c */ dst != 0
};

// Флаги после сложения с переносом
wire [7:0] set_add_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ add_flag_h,
    /* s */ add_flag_v ^ resb[7],
    /* v */ add_flag_v,
    /* n */ resb[7],
    /* z */ (resb[7:0] == 0),
    /* c */ dst + src + carry >= 9'h100
};

// Флаги после логической операции сдвига вправо
wire [7:0] set_lsr_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ si[5],
    /* s */ dst[0],
    /* v */ resb[7] ^ dst[0],
    /* n */ resb[7],
    /* z */ (resb[7:0] == 0),
    /* c */ dst[0]
};

// Флаги после INC
wire [7:0] set_inc_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ si[5],
    /* s */ (resb == 8'h80) ^ resb[7],
    /* v */ (resb == 8'h80),
    /* n */ resb[7],
    /* z */ (resb[7:0] == 0),
    /* c */ si[0]
};

// Флаги после DEC
wire [7:0] set_dec_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ si[5],
    /* s */ (resb == 8'h7F) ^ resb[7],
    /* v */ (resb == 8'h7F),
    /* n */ resb[7],
    /* z */ (resb[7:0] == 0),
    /* c */ si[0]
};

// Флаги после ADIW
wire [7:0] set_adiw_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ si[5],
    /* s */ adiw_v ^ resw[15],
    /* v */ adiw_v,
    /* n */ resw[15],
    /* z */ (resw[15:0] == 0),
    /* c */ adiw_c
};

// Флаги после SBIW
wire [7:0] set_sbiw_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ si[5],
    /* s */ adiw_v ^ resw[15],
    /* v */ adiw_v,
    /* n */ resw[15],
    /* z */ (resw[15:0] == 0),
    /* c */ adiw_v
};

// Флаги после MUL
wire [7:0] set_mul_flag = {

    /* i */ si[7],
    /* t */ si[6],
    /* h */ si[5],
    /* s */ si[7],
    /* v */ si[7],
    /* n */ si[7],
    /* z */ (mul[15:0] == 0),
    /* c */ mul[15]
};

always @(*) begin

    so    = si;
    carry = 0;

    case (mode)

        /* LDI   */ 0:  begin resb = src; end
        /* CPC   */ 1:  begin resb = sbc[7:0];   so = set_subcarry_flag; end
        /* SBC   */ 2:  begin resb = sbc[7:0];   so = set_subcarry_flag; end
        /* ADD   */ 3:  begin resb = add;        so = set_add_flag;      carry = 0; end
        /* CP    */ 5:  begin resb = sub;        so = set_subtract_flag; end
        /* SUB   */ 6:  begin resb = sub;        so = set_subtract_flag; end
        /* ADC   */ 7:  begin resb = adc;        so = set_add_flag;      carry = si[0]; end
        /* AND   */ 8:  begin resb = dst & src;  so = set_logic_flag;   end
        /* EOR   */ 9:  begin resb = dst ^ src;  so = set_logic_flag;   end
        /* OR    */ 10: begin resb = dst | src;  so = set_logic_flag;   end
        /* SREG  */ 11: begin                    so = src;              end
        /* COM   */ 12: begin resb = com;        so = set_com_flag;     end
        /* NEG   */ 13: begin resb = neg;        so = set_neg_flag;     end
        /* SWAP  */ 14: begin resb = swap;       end
        /* INC   */ 15: begin resb = inc;        so = set_inc_flag;     end
        /* ASR   */ 16: begin resb = asr;        so = set_lsr_flag;     end
        /* LSR   */ 17: begin resb = lsr;        so = set_lsr_flag;     end
        /* ROR   */ 18: begin resb = ror;        so = set_lsr_flag;     end
        /* DEC   */ 19: begin resb = dec;        so = set_dec_flag;     end
        /* ADIW  */ 20: begin resw = adiw;       so = set_adiw_flag;    end
        /* SBIW  */ 21: begin resw = sbiw;       so = set_sbiw_flag;    end
        /* BLD   */ 22: case (src[2:0])

            0: resb = {dst[7:1], si[6]};
            1: resb = {dst[7:2], si[6], dst[  0]};
            2: resb = {dst[7:3], si[6], dst[1:0]};
            3: resb = {dst[7:4], si[6], dst[2:0]};
            4: resb = {dst[7:5], si[6], dst[3:0]};
            5: resb = {dst[7:6], si[6], dst[4:0]};
            6: resb = {dst[  7], si[6], dst[5:0]};
            7: resb = {          si[6], dst[6:0]};

        endcase
        /* MUL   */ 23: begin resw = mul;   so = set_mul_flag; end
        /* MULS  */ 24: begin resw = muls;  so = set_mul_flag; end
        /* MULSU */ 25: begin resw = mulsu; so = set_mul_flag; end

        default: resb = 8'hFF;

    endcase

end

endmodule
9 сен, 2021
© 2007-2022 Отличная хрень сидела