Придумал как вкрячить в АЛУ сдвиг вправо, чтобы не делать отдельное устройство
Изначально я для выбора текущей операции АЛУ вместо логики на AND (как в микросхеме 74181) сделал в логической схеме сумматора мультиплексор на 4 входа (см. картинку) - просто так понятнее: берём сигналы с generate, propagate и с AND между ними и переключаем их. А ещё была надежда что выходной XNOR (который из 2-х гейтов состоит на самом деле: ~(A ^ B)) как в 74181 в DCTL удастся заменить на какой-то более дешёвый DCTL-трюк (не удалось) и поэтому оставил пока более понятный мультиплексор.
В результате остался один неиспользованный вход этого мультиплексора. А ведь его можно использовать для того чтобы отдать правый бит от текущего бита операнда напрямую на выход. Получается почти бесплатное устройство битового сдвига вправо! Оно будет дешевле чем отдельное устройство сдвига и XNORы на каждый бит как в обычном АЛУ.
Code: Select all
typedef enum logic[4:0] {
ADD =5'b00000, // also left shift if A=B, AKA SLL
SUB =5'b11000, // carry_out is inverted for SUB operations
XOR =5'bx0100,
XNOR =5'bx1100, // also NOT, if A=0
COMP =5'b01000, // A-B-1 operation, if A!=B then established carry out bit means A>B, otherwise A<B
AND =5'bx0101,
OR =5'bx0110,
RSHFT=5'b00111 // moves data2 bits to right (SLR), data1 is ignored
} AluCmd;
typedef struct packed
{
logic carry_in; // carry input (for example, from prev stage)
logic b_inv; // invert second operand?
logic carry_disable;
logic[1:0] cmd; // cmd for full adder mux switch
} AluCtrlInternal;
typedef union packed
{
AluCmd cmd;
AluCtrlInternal ctrl;
} AluCtrl;
module alu
(
input[3:0] d1,
input[3:0] d2,
input AluCtrl ctrl,
output[3:0] res,
output carry_out
);
wire[3:0] gen;
wire[3:0] propagate;
wire[3:0] d2_possible_inverted;
wire[4:0] carry;
wire carry_in = ctrl.ctrl.carry_in;
assign carry[0] = carry_in;
assign carry_out = carry[4];
for(genvar i = 0; i < 4; i++) begin
wire right_bit = (i < 3) ? d2_possible_inverted[i+1] : carry_in;
full_adder fa(d1[i], d2[i], carry[i], right_bit, ctrl, res[i], gen[i], propagate[i], d2_possible_inverted[i]);
end
assign carry[1] = gen[0] ||
(carry_in && propagate[0]);
assign carry[2] = gen[1] || (
(carry_in && propagate[0] && propagate[1]) ||
(gen[0] && propagate[1])
);
assign carry[3] = gen[2] || (
(carry_in && propagate[0] && propagate[1] && propagate[2]) ||
(gen[0] && propagate[1] && propagate[2]) ||
(gen[1] && propagate[2])
);
assign carry[4] = gen[3] || (
(carry_in && propagate[0] && propagate[1] && propagate[2] && propagate[3]) ||
(gen[0] && propagate[1] && propagate[2] && propagate[3]) ||
(gen[1] && propagate[2] && propagate[3]) ||
(gen[2] && propagate[3])
);
endmodule
module full_adder
(
input data1, data2, carry_in, direct_in /*can be bypassed to output*/,
input AluCtrlInternal ctrl,
output ret, gen, propagate, d2_possible_inverted
);
assign d2_possible_inverted = data2 ^ ctrl.b_inv; // optionally inverts data2
wire carry = carry_in & ~ctrl.carry_disable;
assign gen = data1 & d2_possible_inverted;
assign propagate = data1 | d2_possible_inverted;
wire i;
AND_gate_with_mux mux(gen, propagate, direct_in, ctrl.cmd, i);
assign ret = i ^ carry;
endmodule
// MUX used here to utilize 3-level DCTL logic
module AND_gate_with_mux
(
input from_AND, from_OR, direct_in,
input[1:0] ctrl,
output result
);
wire interm = ~from_AND & from_OR;
mux_4to1 m(result, interm, from_AND, from_OR, direct_in, ctrl);
endmodule
module mux_4to1 (
output r,
input a,
input b,
input c,
input d,
input[1:0] sel
);
assign r = sel[1] ? (sel[0] ? d : c) : (sel[0] ? b : a);
endmodule