Skip to main content

信号组(Bundle)

创建 Bundle

使用 class 创建

Bundle 是一个 class,因此可以使用类似 class 的方式创建,例如:

local Bundle = require "verilua.handles.LuaBundle"

local bdl = Bundle(
{"valid", "ready", "opcode", "data"}, -- 1. <signals_table>
"some_prefix_", -- 2. <prefix>
"path.to.hier", -- 3. <hierarchy>
"name of bundle", -- 4. <name>
true, -- 5. <is_decoupled>
nil -- 6. <optional_signals>
)

Bundle 接收六个参数:

  1. signals_table — 信号名称列表(table)。

  2. prefix — 信号前缀字符串,无前缀传 ""

  3. hierarchy — 信号的完整 hierarchy 路径,必填。

  4. name — Bundle 名称,可选,默认 "Unknown"

  5. is_decoupled

    用来表示这个 Bundle 是否是 Decoupled 类型(和 Chisel 中的 Decoupled 定义一致),可选参数,默认为 false,可以传入 nil 来使用默认值。

    对于 Decoupled 类型的 Bundle,其中必须要在 signals_table 中包含 valid,而对于 ready 这个信号是可选的。针对 Decoupled 类型的 Bundle,有一个 <bdl>:fire() 的方法,用来判断信号的 valid 是否为 1(如果 ready 存在还会判断是否 ready 也为 1),例如:

    local bdl = Bundle({"valid", "ready", "opcode", "data"}, "some_prefix_", "path.to.hier", "name of bundle", true)
    local valid = bdl.valid:chdl()
    local ready = bdl.ready:chdl()

    assert(bdl:fire())
    assert(valid:get() == 1)
    assert(ready:get() == 1)

    如果 Bundle 被标记为是 Decoupled 的,那么除了 validready 之外,其他在 signals_table 中的信号都会被自动添加一个 bits_ 的前缀,例如上面的 bdl 会有这些信号:

    path.to.hier.some_prefix_valid
    path.to.hier.some_prefix_ready
    path.to.hier.some_prefix_bits_opcode
    path.to.hier.some_prefix_bits_data
    这样设计的目的是为了方便 Chisel 用户使用 Verilua 来创建 Bundle
  6. optional_signals

    用来标记 signals_table 中的信号哪些是可选的,如果一个信号被标记为可选的,那么在构建 Bundle 的时候如果发现这个信号不存在,就会忽略这个信号的报错,否则就会报错。

    推荐使用方括号语法

    除了通过 optional_signals 参数指定可选信号外,还可以在信号列表中使用方括号 [signal_name] 来标记可选信号(推荐):

    -- 使用 optional_signals 参数(旧方法,仍然有效)
    local bdl = ("valid | data | nonexistent"):bdl {
    hier = "tb_top",
    optional_signals = {"nonexistent"}
    }

    -- 使用方括号语法(推荐)
    local bdl = ("valid | data | [nonexistent]"):bdl {
    hier = "tb_top"
    }

上述代码会将下面的信号加入到 Bundle 中:

path.to.hier.some_prefix_valid
path.to.hier.some_prefix_ready
path.to.hier.some_prefix_bits_opcode
path.to.hier.some_prefix_bits_data

这里的每一个信号的访问方式如下:

local valid = bdl.valid
local ready = bdl.ready
local opcode = bdl.bits.opcode
local data = bdl.bits.data
这里的每一个信号都是一个 chdl

对于 Decoupled 类型的 Bundle,除了 validready 之外,其他信号的访问需要在 bits 下进行访问。

上面都是 Decoupled 类型的 Bundle,对于不是 Decoupled 类型的 Bundle,这里是另一个例子:

local bdl = Bundle({"data0", "data1", "data2"}, "some_prefix_", "path.to.hier", "name of bundle", false)

local data0 = bdl.data0
local data1 = bdl.data1
local data2 = bdl.data2

使用 string literal 创建(推荐)

CallableHDL 一样,Bundle 也可以使用 string literal 来创建,也就是 SLCP,详见 字符串字面量构造模式(SLCP),下面是一个例子:

local bdl = ([[
| valid
| ready
| opcode
| data
]]):bdl({hier = "path.to.hier", prefix = "some_prefix_", name = "name of bundle", is_decoupled = false})
Lua 的 [[ ]] 用来表示多行的字符串
Lua 中如果函数的参数只有一个,且这个参数的类型是 string 或者 table,那么就可以省略圆括号,因此上面的代码可以简化为:local bdl = ([[ | valid | ready | opcode | data ]]):bdl {...}

上述的代码中,每一个信号需要用 | 分隔开,换行不是必须的,因此下面的做法也是可以的:

local bdl = ("valid | ready | opcode | data"):bdl {...}
local bdl = ("| valid | ready | opcode | data"):bdl {...}
local bdl = ("| valid | ready | opcode | data |"):bdl {...}
local bdl = ([[ valid | ready
| opcode
| data
]]):bdl {...}

使用 SLCP 进行构建的时候,参数用 table 的形式传入(key-value 的形式),因此这些参数名和使用 class 构建的时候的参数名一致。

Bundle 接口

Bundle 的对于每一个信号的成员变量仍然还是一个 CallableHDL

如果要访问对应信号的值,和 CallableHDL 一样操作即可,例如:

local bdl = ("valid | ready | opcode | data"):bdl {hier = "path.to.hier", prefix = "some_prefix_", is_decoupled = true}
local valid_value = bdl.valid:get()
local ready_value = bdl.ready:get()

bdl.bits.opcode:set(0x123)
bdl.bits.data:set(0x456)
  1. <bdl>:fire()

    判断信号的 valid 是否为 1(如果 ready 存在还会判断是否 ready 也为 1),例如:

    local bdl = ("valid | ready | opcode | data"):bdl {hier = "path.to.hier", prefix = "some_prefix_", is_decoupled = true}
    local valid = bdl.valid:chdl()
    local ready = bdl.ready:chdl()

    assert(bdl:fire())
    assert(valid:get() == 1)
    assert(ready:get() == 1)
    只有 is_decoupled 为 trueBundle 才有这个方法
  2. <bdl>:get_all()

    获得所有的信号,并以 Lua table 的形式返回,例如:

    local bdl = ("opcode | data "):bdl {hier = "path.to.hier", prefix = "some_prefix_", is_decoupled = false}
    local signals = bdl:get_all()
    local opcode_value = signals[1]
    local data_value = signals[2]
    只有 is_decoupled 为 falseBundle 才有这个方法
  3. <bdl>:set_all(values_tbl)

    设置所有的信号,并以 Lua table 的形式返回,例如:

    local bdl = ("opcode | data"):bdl {hier = "path.to.hier", prefix = "some_prefix_", is_decoupled = false}
    local signals = bdl:set_all({0x123, 0x456})
    只有 is_decoupled 为 falseBundle 才有这个方法
  4. <bdl>:dump()

    Bundle 中所有的信号当前的数值输出到控制台,可以用于查看信号的值,打印的内容如下所示:

    Terminal
    [name of bundle] | valid: 0x1 | ready: 0x1 | opcode: 0x123 | data: 0x456
  5. <bdl>:dump_str()

    返回 dump() 的输出字符串,等价于 print(<bdl>:dump_str())

  6. <bdl>:format_dump(format_func)

    带自定义格式的 dump(),接受可选的 format_func: fun(chdl, name: string): string。若 format_func 返回非 nil 字符串,则替换该信号的默认输出,例如:

    local bdl = ("valid | value0 | value1 | other"):bdl {hier = "path.to.hier", prefix = "some_prefix_", is_decoupled = false, name = "name of bundle"}

    bdl:format_dump(function(chdl, name)
    if chdl.width == 1 and name:contains(value) then
    return name .. " is " .. chdl:get_hex_str()
    end
    end)

    输出结果:

    Terminal
    [name of bundle] | valid: 0x1 | value0 is 0x1 | value1 is 0x0 | other: 0x0
  7. <bdl>:format_dump_str(format_func)

    返回 format_dump() 的输出字符串。

Bundle vs AliasBundle 选型

如果你不确定该用 Bundle 还是 AliasBundle,参考下表:

BundleAliasBundle
信号列表只有信号名:"valid | data"信号名 + 可选别名:"origin => alias"
访问方式用原始信号名:bdl.valid用别名:abdl.alias_name
Decoupled 支持is_decoupled + fire() / get_all() / set_all()❌ 不支持
适用场景信号名本身就是你想要的访问名,或需要 ready/valid 握手语义RTL 信号名冗长/不直观,想用更短或更有语义的别名

选型建议:

  • 大部分情况下推荐使用 AliasBundle,因为它是 Bundle 的超集:不指定别名时行为与 Bundle 完全一致,需要别名时又能直接扩展,不必重构代码
  • 只有在需要 Decoupled 握手语义(fire() / get_all() / set_all())时才必须用 Bundle
  • 如果 AliasBundle 中所有信号都不指定别名,它就退化为和 Bundle 等价的行为

详见 别名信号组(AliasBundle)