Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
//----------------------------------------------------------------------------
// Task
//----------------------------------------------------------------------------

module float_discriminant (
input clk,
input rst,

input arg_vld,
input [FLEN - 1:0] a,
input [FLEN - 1:0] b,
input [FLEN - 1:0] c,

output logic res_vld,
output logic [FLEN - 1:0] res,
output logic res_negative,
output logic err,

output logic busy
);

// Task:
// Implement a module that accepts three Floating-Point numbers and outputs their discriminant.
// The resulting value res should be calculated as a discriminant of the quadratic polynomial.
// That is, res = b^2 - 4ac == b*b - 4*a*c
//
// Note:
// If any argument is not a valid number, that is NaN or Inf, the "err" flag should be set.
//
// The FLEN parameter is defined in the "import/preprocessed/cvw/config-shared.vh" file
// and usually equal to the bit width of the double-precision floating-point number, FP64, 64 bits.



//------------------------------------------------------------------------
// вариант 2 FSM
//------------------------------------------------------------------------

// States
enum logic [2:0]
{
st_idle = 3'd0,
st_1 = 3'd1,
st_2 = 3'd2,
st_3 = 3'd3,
st_4 = 3'd4,
st_5 = 3'd5


}
state, next_state;

logic [FLEN - 1:0] f_mul_a, f_mul_b, f_mul_res; // connectors for multiplier
logic [FLEN - 1:0] b_b, ac; // tmp result;
logic [FLEN - 1:0] b_tmp; // b - lach
logic f_mul_busy, f_mul_error, f_mul_arg_vld;
//---------------------------------------------------------------------
f_mult f_mul_i( // module multiplier
.clk(clk),
.rst(rst),
.a(f_mul_a),
.b(f_mul_b),
.up_valid(f_mul_arg_vld),
.res(f_mul_res),
.down_valid(f_mul_res_vld),
.busy(f_mul_busy),
.error(f_mul_error)
);

//------------------------------------------------------------------------

logic f_sub_arg_vld, f_sub_res_vld, f_sub_error;

f_sub f_sub_i(
.clk(clk),
.rst(rst),
.a(b_b), // аргументы берем из предыдущих
.b(ac), // результатаов
.up_valid(f_sub_arg_vld),
.res(res), // подключаем к выходу модуля
.down_valid(f_sub_res_vld),
.busy(sub_busy),
.error(f_sub_error)
);

//------------------------------------------------------------------------

always_comb
begin
next_state = state;
err = '0; // ошибки не обнаружены

case (state)
st_idle:
begin
f_mul_a = a;
f_mul_b = c;
res_vld = '0;
if (arg_vld) begin
f_mul_arg_vld = '1 ; // если входные данные валидны запускаем вычисление a*c
busy = '1 ; // выставдяем флаг занятости
next_state = st_1 ; // и переходим к следующей стадии возведение в квадрат
b_tmp = b;
end

end
st_1:
begin // умножитель у нас конвейерный на следующий такт запускаем возведение в степень b^2
f_mul_a = b_tmp ; // загружаем умножитель значениями b
f_mul_b = b_tmp ; // и b
f_mul_arg_vld = '1 ; // запускаем вычисление
next_state = st_2 ; // на следующую стадию
end

st_2:
begin
f_mul_arg_vld = '0;
if (f_mul_error) begin
err = '1; // и выставляем флаг ошибки
end
if (f_mul_res_vld) begin // ждем окончания умножения a*c
f_mul_a = f_mul_res ; // загружаем умножитель значениями а*c
f_mul_b = $realtobits(4) ; // и 4
f_mul_arg_vld = '1 ; // запускаем умножение 4*(a*c)
next_state = st_3; // и на следующую стадию
end
end

st_3:
begin
f_mul_arg_vld = '0 ;
if (f_mul_error) begin
err = '1 ; // за одно выставляем флаг ошибки
end
// так как мы на втором такте загрузили b*b
// проверку на готовность можно пропустить
b_b = f_mul_res ; // сохраняем результат
next_state = st_4 ; // к следующей стадии
end

st_4:
begin
f_mul_arg_vld = '0 ;
if (f_mul_error) begin
err = '1 ; // и выставляем флаг ошибки
end
if (f_mul_res_vld) begin // умножение 4*ac закончилось
ac = f_mul_res ; // сохраняем результат
// аргументы к вычитателю подключены
f_sub_arg_vld = '1 ; // запускаем вычитание
next_state = st_5 ; // к следующей стадии
end
end

st_5:
begin
if (f_sub_error) begin
err = '1 ; // и выставляем флаг ошибки

end
if (f_sub_res_vld) begin // вычитание b^2 - 4ac закончилось
res_vld = '1 ; // выставляем флаг готовности
busy = '0 ; // сбрасываем флаг занятости
f_sub_arg_vld = '0 ; // данные на входе вычитателя не актуальны
next_state = st_idle ;
end
end
endcase
end

//------------------------------------------------------------------------
// Assigning next state

always_ff @ (posedge clk)
if (rst)
state <= st_idle;
else
state <= next_state;

//------------------------------------------------------------------------

// конец 2 варианта FSM

endmodule
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
localparam LATENCY = 10 ; // латентность конвейера перенести в svh файл

// модуль имитируюший работу конвейера путем импементации нескольких N=LATENCY
// вычислителей с латентностью = LATENCY

// вижу несколько вариантов оформления решения
// первый выбор входов вычислителя идет через функцию "И" сигнала arg_vld и n-ного разряда one_hot
// регистра-селектора. При активном arg_vld, в каждом такте регистр-селектор сдвигается на 1 разряд
// выходы вычислителей через мультиплексор подключены к выходу модуля. При наличии сигнала res_vld
// каждый такт инкрементирует регистр-селектор выходов n_out. Сигнал res_vld формируется из входного

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так как по условию задачи латентность модуля фиксирована, и при этом есть вывод res_vld, который тем самым находится в фиксированном отношении с arg_vld, то нам не нужно протаскивать arg_vld, не так ли? Достаточно использовать res_vld_o[n_out]?

Завтра посмотрю внимательнее

@32FedorovAlexey 32FedorovAlexey Jan 7, 2025

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вы правы, можно легко обойтись без сдвигового регистра delay_vld. Можно еще упростить код если на выходе вычислителей использовать регистры с Z состоянием. Если есть на выходе корректные данные, то модуль выдает их на шину, если нет то отключается от шины. Тогда код сведется к двум строчкам, загрузить 1 в регистр-селектор, и сдвинуть его если на входе есть данные.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не, Z на внутренних сигналах в дизайнах не используется

// сигнала arg_vld c задержкой в LATENCY тактов, в этом задержка реализуется на сдвиговом регистре
// delay_vld. Модули вычислителей могут быть подключены прямым текстом (copy - paste LATENCY раз),
// а могут через generate.

module distributor
(
input clk,
input rst,

input arg_vld,
input [FLEN - 1:0] a,
input [FLEN - 1:0] b,
input [FLEN - 1:0] c,

output logic res_vld,
output logic [FLEN - 1:0] res,
output logic res_negative,
output logic err,

output logic busy
);

logic [LATENCY-1:0] ptr_in; // one-hot registre
logic [$clog2(LATENCY-1):0] n_out; // регистр хранения номера вычислителя с валидным результатом
logic [LATENCY-1 :0] delay_vld; // сдвиговый регистр для сигнала vld
logic [FLEN - 1:0] res_0, res_1, res_2, res_3, res_4, res_5, res_6, res_7, res_8, res_9;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А зачем эти переменные? Они же не используются

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Переменные забыл удалить, я их использовал в промежуточном варианте.

logic start_0, start_1, start_2, start_3, start_4, start_5, start_6, start_7, start_8, start_9;

logic [LATENCY-1:0] res_vld_o, res_negative_o, err_o, busy_o; // векторы для подключения выходных сигналов вычислителей
logic [FLEN - 1:0] res_o [LATENCY-1:0];

always_ff @ (posedge clk) begin
if (rst) begin
ptr_in <= 1; // загружаем "1" в one-hot регистр селектор
n_out <='0; // "0" в регистр-селектор выходов вычислителей
delay_vld <='0;
end
else begin
delay_vld <= {delay_vld[LATENCY-1:0],arg_vld}; // передаем данные arg_vld с задержкой в LATENCY тактов на выход модуля
if (arg_vld) begin
ptr_in <= {ptr_in[LATENCY-2:0],ptr_in[LATENCY-1]}; // пришли данные - сдвигаем входной регистр-селектор маски
end

if (delay_vld[LATENCY-1]) begin // если на выходе готовы данные то
if (n_out == (LATENCY-1 )) n_out <= '0; // и если дошли до последнего вычислителя то сбрасываем номер вычислителя
else n_out <= n_out + 1 ; // иначе увеличиваем номер вычислителя подключенного к выходу
end

end
end

genvar i;


// создаем модули вычислителей в количестве LATENCY
generate
for(i = 0; i < LATENCY; i = i + 1) begin:calc

float_discriminant inst (
.clk(clk),
.rst(rst),
.arg_vld(arg_vld & ptr_in[i]),
.a(a),
.b(b),
.c(c),

.res_vld(res_vld_o[i]),
.res(res_o[i]),
.res_negative(res_negative_o[i]),
.err(err_o[i]),
.busy(busy_o[i])
);

end
endgenerate


always_comb begin
res = res_o[n_out] ;
res_negative = res_negative_o[n_out];
err = err_o[n_out];
res_vld = delay_vld[LATENCY-1];
end


endmodule
Binary file not shown.
Loading