我对 HD 描述语言相当陌生。我发现改变我的 C-ish 编程技能有点困难,我正在寻找一些 guaidance 来帮助我抛出以下问题。
我想实现一个完整的树,它的内部节点不同于它的叶子叶子的数量是通用(asuming 有 2 ^ k 叶子,所以树可以是满的)
每个内部节点都是由简单的组合电路组成的组件。
叶子与时钟同步,并连接到下一个叶子(打破树结构-并形成类似移位寄存器的东西)
这意味着我的设计必须有一个通用数量的组件,根据叶子的数量连接。
虽然这可以在基于 C 的语言中立即递归解决。我无法掌握用 HDL 解决它的想法,因为这种通用形式与 n 位输入信号不同...
我的实现必须是可合成的,因此 SystemVerilog 不能在这方面大放异彩:(
是否有可能实现所描述的问题,同时保持我的代码可合成?任何人都可以指导我抛出这个或指向我关于这个主题的一个很好的参考?
您可以在 VHDL 中编写一个递归算法,该算法在详细说明期间执行,然后通过generate
语句定义要合成的硬件结构。您几乎可以在 Verilog 中做到这一点,Verilog 自 2001 年以来就具有自动功能,但是它们不是完全自动的,而且我认为我在 Verilog 中没有看到任何可用的可合成示例。
张贴一些伪 C,这样我们就可以看到你想要什么。
EDIT参见this :它描述了 VHDL 中胖树结构的递归生成。这完全由递归组件实例化处理,而不是使用递归算法来预定义结构。
您可能想看看如何在 VHDL 中使用generate
语句。将 generate 语句与for
语句一起使用将根据需要生成尽可能多的组件。
但是,在构建 FPGA 时必须知道叶子的总数。您不能动态创建叶子。
我将尝试提供一个答案,它允许您构建一个泛型树,而无需递归,仅基于在编译时作为泛型提供的树高。对于我的口味来说,代码本身看起来有点棘手;但是,解决方案背后的原则是直截了当的。
想象一下,你的节点将被放置在一个网格上,尺寸为 V = TREE_HEIGHT + 1 和 H = 2 * * TREE_HEIGHT(参见下面的 ASCII-gram)。
要将树的一个级别连接到下一个级别,可以使用大小为 TREE_HEIGHT x 2 * * TREE_HEIGHT 的二维数组(请参见下面代码示例中的第 63 行)。
要实例化节点,请使用两个嵌套循环(VHDL 中的for-generate
,请参见第 68-69 行)。您不会填充所有节点;对于 depth =i处的给定行,只需要 2 * * (i-1) 个节点(第 71 行)。
您可以为内部和叶节点实例化不同的实体,只需检查i的当前值是否等于 TREE_HEIGHT(第 74 和 84 行)。
最后,你只需要连接树的各层。算术有点棘手,但是一旦你做对了,你就完成了(第 78-80 行)。
依靠您的合成工具来删除未使用的导线。
这是高度 = 2 的“网格”的糟糕表现:
j = 1 j = 2 j = 3 j = 4
+---------------+---------------+---------------+---------------+
i = 1 | Root Node | (empty) | (empty) | (empty) |
+---------------+---------------+---------------+---------------+
i = 2 | Internal Node | Internal Node | (empty) | (empty) |
+---------------+---------------+---------------+---------------+
i = 3 | Internal Node | Internal Node | Internal Node | Internal Node |
+---------------+---------------+---------------+---------------+
下面是代码示例:
/* 1 */ package tree_types_pkg is
/* 2 */ -- define a data type for the input and output values at each node
/* 3 */ subtype tree_data_type is integer range 0 to 255;
/* 4 */ -- define a vector type to propagate the output of a tree level to the next
/* 5 */ type layer_to_layer_channel_type is array (natural range <>) of tree_data_type;
/* 6 */ end;
/* 7 */ --------------------------------------------------------------------------------
/* 8 */ use work.tree_types_pkg.all;
/* 9 */
/* 10 */ eny internal_node is
/* 11 */ generic (
/* 12 */ TREE_HEIGHT: integer := 3
/* 13 */ );
/* 14 */ port (
/* 15 */ x: in integer range 1 to 2**TREE_HEIGHT;
/* 16 */ y: in integer range 1 to TREE_HEIGHT;
/* 17 */ input: in tree_data_type;
/* 18 */ output_left: out tree_data_type;
/* 19 */ output_right: out tree_data_type
/* 20 */ );
/* 21 */ end;
/* 22 */
/* 23 */ architecture rtl of internal_node is begin
/* 24 */ -- perform some calculation at the node
/* 25 */ output_left <= input + x * y;
/* 26 */ output_right <= input - x * y;
/* 27 */ end;
/* 28 */ --------------------------------------------------------------------------------
/* 29 */ use work.tree_types_pkg.all;
/* 20 */
/* 31 */ eny leaf_node is
/* 32 */ generic (
/* 33 */ TREE_HEIGHT: integer := 3
/* 34 */ );
/* 35 */ port (
/* 36 */ x: in integer range 1 to 2**TREE_HEIGHT;
/* 37 */ y: in integer range 1 to TREE_HEIGHT;
/* 38 */ input: in tree_data_type;
/* 39 */ output: out tree_data_type
/* 30 */ );
/* 41 */ end;
/* 42 */
/* 43 */ architecture rtl of leaf_node is begin
/* 44 */ -- perform some calculation at the node
/* 45 */ output <= input + x * y;
/* 46 */ end;
/* 47 */ --------------------------------------------------------------------------------
/* 48 */ use work.tree_types_pkg.all;
/* 49 */
/* 50 */ eny dirtybit_binary_tree is
/* 51 */ generic (
/* 52 */ TREE_HEIGHT: integer := 4
/* 53 */ );
/* 54 */ port (
/* 55 */ tree_input: in tree_data_type;
/* 56 */ tree_outputs: out layer_to_layer_channel_type(1 to 2**TREE_HEIGHT)
/* 57 */ );
/* 58 */ end;
/* 59 */
/* 60 */ architecture behavior of dirtybit_binary_tree is
/* 61 */ constant LEAF_NODES_COUNT: integer := 2**TREE_HEIGHT;
/* 62 */ type channel_array_type is array (natural range <>) of layer_to_layer_channel_type;
/* 63 */ signal connections: channel_array_type(1 to TREE_HEIGHT)(1 to LEAF_NODES_COUNT);
/* 64 */ begin
/* 65 */
/* 66 */ connections(1)(1) <= tree_input;
/* 67 */
/* 68 */ grid_y: for i in 1 to TREE_HEIGHT generate
/* 69 */ grid_x: for j in 1 to LEAF_NODES_COUNT generate
/* 70 */
/* 71 */ instantiate_nodes: if j <= 2**(i-1) generate
/* 72 */
/* 73 */ internal_nodes: if (i /= TREE_HEIGHT) generate
/* 74 */ internal_node: eny work.internal_node
/* 75 */ generic map (TREE_HEIGHT => TREE_HEIGHT)
/* 76 */ port map (
/* 77 */ x => j,
/* 78 */ y => i,
/* 79 */ input => connections(i)(j),
/* 80 */ output_left => connections(i+1)((j-1)*i+1),
/* 81 */ output_right => connections(i+1)((j-1)*i+2)
/* 82 */ );
/* 83 */ end generate;
/* 84 */
/* 85 */ leaf_nodes: if (i = TREE_HEIGHT) generate
/* 86 */ leaf_node: eny work.leaf_node
/* 87 */ generic map (TREE_HEIGHT => TREE_HEIGHT)
/* 88 */ port map (
/* 89 */ x => j,
/* 90 */ y => i,
/* 91 */ input => connections(i)(j),
/* 92 */ output => tree_outputs(j)
/* 93 */ );
/* 94 */ end generate;
/* 95 */
/* 96 */ end generate;
/* 97 */
/* 98 */ end generate;
/* 99 */ end generate;
/* 100 */
/* 101 */ end;
最后,以下是 Quartus 12.1(RTL Viewer)上的合成电路:
Verilog(或 VHDL)generate
语句可用于创建可伸缩系统,但隐含的硬件数量在编译时是固定的。您不能即时更改有多少硬件。Verilog 的链接生成one,two。
简短示例,将多条电线连接到逆变器
parameter DATA_W = 4;
parameter DEPTH = 8;
wire [DATA_W-1:0] data [0:DEPTH-1];
wire [DATA_W-1:0] data_n [0:DEPTH-1];
genvar index;
generate
for (index=0; index < DEPTH; index=index+1) begin: gen_code_label
inv #(
.WIDTH ( DATA_W )
) inv_i0 (
.rx ( data[index] ), // input
.tx ( data_n[index] ), // output
);
end
endgenerate
我发现生成有时很难遵循,特别是如果使用连接了很多硬件,他们还引入了另一个层次,这往往是不可取的。
对于可伸缩的模板代码,我使用 erb(ruby),使用 gemruby-it。
免责声明我编写了 gem 以使其更容易。
本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处
评论列表(27条)