Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mux/demux modules to std library #1148

Merged
merged 1 commit into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
36 changes: 36 additions & 0 deletions crates/std/veryl/src/selector/demux.veryl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import selector_pkg::*;

pub module demux #(
param WIDTH : u32 = 1 ,
param DATA_TYPE : type = logic<WIDTH> ,
param DEFUALT_DATA: u32 = 0 as DATA_TYPE ,
param ENTRIES : u32 = 2 ,
param KIND : selector_kind = selector_kind::BINARY ,
param SELECT_WIDTH: u32 = calc_select_width(ENTRIES, KIND),
) (
i_select: input logic <SELECT_WIDTH>,
i_data : input DATA_TYPE ,
o_data : output DATA_TYPE<ENTRIES> ,
) {
if KIND == selector_kind::BINARY :g_demux {
always_comb {
for i: u32 in 0..ENTRIES {
o_data[i] = if i_select == i as SELECT_WIDTH {
i_data
} else {
DEFUALT_DATA
};
}
}
} else {
always_comb {
for i: u32 in 0..ENTRIES {
o_data[i] = if i_select[i] {
i_data
} else {
DEFUALT_DATA
};
}
}
}
}
99 changes: 99 additions & 0 deletions crates/std/veryl/src/selector/mux.veryl
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import selector_pkg::*;

pub module mux #(
param WIDTH : u32 = 1 ,
param DATA_TYPE : type = logic<WIDTH> ,
param ENTRIES : u32 = 2 ,
param KIND : selector_kind = selector_kind::BINARY ,
const SELECT_WIDTH: u32 = calc_select_width(ENTRIES, KIND),
) (
i_select: input logic <SELECT_WIDTH>,
i_data : input DATA_TYPE<ENTRIES> ,
o_data : output DATA_TYPE ,
) {
const BINARY_SELECT_WIDTH: u32 = calc_binary_select_width(ENTRIES);
const MAX_DEPTH : u32 = $clog2(ENTRIES);

function binary_mux (
select: input logic <BINARY_SELECT_WIDTH>,
data : input DATA_TYPE<ENTRIES> ,
) -> DATA_TYPE {
return data[select];
}

function vector_mux (
select: input logic <ENTRIES>,
data : input DATA_TYPE<ENTRIES>,
) -> DATA_TYPE {
var current_n : u32 ;
var current_select: logic <ENTRIES>;
var current_data : DATA_TYPE<ENTRIES>;
var next_n : u32 ;
var next_select : logic <ENTRIES>;
var next_data : DATA_TYPE<ENTRIES>;

next_n = ENTRIES;
next_select = select;
next_data = data;
for _i: u32 in 0..MAX_DEPTH {
current_n = next_n;
current_select = next_select;
current_data = next_data;

next_n = (current_n / 2) + (current_n % 2);
for j: u32 in 0..next_n {
let select_even: logic = current_select[2 * j + 0] || ((j + 1) == next_n && (current_n % 2) == 1);
if select_even {
next_select[j] = current_select[2 * j + 0];
next_data[j] = current_data[2 * j + 0];
} else {
next_select[j] = current_select[2 * j + 1];
next_data[j] = current_data[2 * j + 1];
}
}
}

return next_data[0];
}

function onehot_mux (
select: input logic <ENTRIES>,
data : input DATA_TYPE<ENTRIES>,
) -> DATA_TYPE {
var current_n : u32 ;
var current_data: DATA_TYPE<ENTRIES>;
var next_n : u32 ;
var next_data : DATA_TYPE<ENTRIES>;

next_n = ENTRIES;
for i: u32 in 0..ENTRIES {
next_data[i] = {select[i] repeat $bits(DATA_TYPE)} & data[i];
}

for _i: u32 in 0..MAX_DEPTH {
current_n = next_n;
current_data = next_data;

next_n = (current_n / 2) + (current_n % 2);
for j: u32 in 0..current_n {
if (j + 1) == next_n && ((current_n % 2) == 1) {
next_data[j] = current_data[2 * j + 0];
} else {
next_data[j] = current_data[2 * j + 0] | current_data[2 * j + 1];
}
}
}

return next_data[0];
}

if ENTRIES <= 1 :g_mux {
assign o_data = i_data[0];
} else if KIND == selector_kind::BINARY {
assign o_data = binary_mux(i_select, i_data);
} else if KIND == selector_kind::VECTOR {
assign o_data = vector_mux(i_select, i_data);
} else {
assign o_data = onehot_mux(i_select, i_data);
}
}
28 changes: 28 additions & 0 deletions crates/std/veryl/src/selector/selector_pkg.veryl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
pub package selector_pkg {
enum selector_kind {
BINARY,
VECTOR,
ONEHOT,
}

function calc_binary_select_width (
entries: input u32,
) -> u32 {
return if entries >= 2 {
$clog2(entries)
} else {
1
};
}

function calc_select_width (
entries: input u32 ,
kind : input selector_kind,
) -> u32 {
if kind == selector_kind::BINARY {
return calc_binary_select_width(entries);
} else {
return entries;
}
}
}
178 changes: 178 additions & 0 deletions crates/std/veryl/src/selector/test_selector.veryl
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#[test(test_binary_mux)]
embed (inline) sv{{{
module test_binary_mux;
import std_selector_pkg::*;

logic [3:0] select;
logic [15:0][3:0] input_data;
logic [3:0] mux_data;
logic [15:0][3:0] output_data;

std_mux #(
.WIDTH (4 ),
.ENTRIES (16 ),
.KIND (selector_kind_BINARY )
) u_mux (
.i_select (select ),
.i_data (input_data ),
.o_data (mux_data )
);

std_demux #(
.WIDTH (4 ),
.ENTRIES (16 ),
.KIND (selector_kind_BINARY )
) u_demux (
.i_select (select ),
.i_data (mux_data ),
.o_data (output_data )
);

initial begin
for (int i = 0;i < 16;++i) begin
input_data[i] = i;
end

for (int i = 0;i < 16;++i) begin
select = i;
#1;
for (int j = 0;j < 16;++j) begin
logic [3:0] expected_data;

if (j == i) begin
expected_data = input_data[j];
end else begin
expected_data = 0;
end

assert (output_data[j] == expected_data)
else $error("output_data[%0d]: %h expected_data: %h", j, output_data[j], expected_data);
end
end

$finish;
end
endmodule
}}}

#[test(test_binary_vector)]
embed (inline) sv{{{
module test_vector_mux;
import std_selector_pkg::*;

logic [15:0] select_mux;
logic [15:0] select_demux;
logic [15:0][3:0] input_data;
logic [3:0] mux_data;
logic [15:0][3:0] output_data;

std_mux #(
.WIDTH (4 ),
.ENTRIES (16 ),
.KIND (selector_kind_VECTOR )
) u_mux (
.i_select (select_mux ),
.i_data (input_data ),
.o_data (mux_data )
);

std_demux #(
.WIDTH (4 ),
.ENTRIES (16 ),
.KIND (selector_kind_VECTOR )
) u_demux (
.i_select (select_demux ),
.i_data (mux_data ),
.o_data (output_data )
);

initial begin
for (int i = 0;i < 16;++i) begin
input_data[i] = i;
end

select_mux = '1;
for (int i = 0;i < 16;++i) begin
select_demux = '0;
select_demux[i] = '1;

#1;
for (int j = 0;j < 16;++j) begin
logic [3:0] expected_data;

if (j == i) begin
expected_data = input_data[j];
end else begin
expected_data = 0;
end

assert (output_data[j] == expected_data)
else $error("output_data[%0d]: %h expected_data: %h", j, output_data[j], expected_data);
end

select_mux[i] = '0;
end

$finish;
end
endmodule
}}}

#[test(test_onehot_mux)]
embed (inline) sv{{{
module test_onehot_mux;
import std_selector_pkg::*;

logic [15:0] select;
logic [15:0][3:0] input_data;
logic [3:0] mux_data;
logic [15:0][3:0] output_data;

std_mux #(
.WIDTH (4 ),
.ENTRIES (16 ),
.KIND (selector_kind_ONEHOT )
) u_mux (
.i_select (select ),
.i_data (input_data ),
.o_data (mux_data )
);

std_demux #(
.WIDTH (4 ),
.ENTRIES (16 ),
.KIND (selector_kind_ONEHOT )
) u_demux (
.i_select (select ),
.i_data (mux_data ),
.o_data (output_data )
);

initial begin
for (int i = 0;i < 16;++i) begin
input_data[i] = i;
end

for (int i = 0;i < 16;++i) begin
select = '0;
select[i] = '1;

#1;
for (int j = 0;j < 16;++j) begin
logic [3:0] expected_data;

if (j == i) begin
expected_data = input_data[j];
end else begin
expected_data = 0;
end

assert (output_data[j] == expected_data)
else $error("output_data[%0d]: %h expected_data: %h", j, output_data[j], expected_data);
end
end

$finish;
end
endmodule
}}}
Loading