SpinalHDL
  • 前言
    • 为什么要放弃传统的 HDL
      • VHDL/Verilog 不是硬件描述语言
      • 事件驱动范式对于 RTL 没有任何意义
      • VHDL 和 Verilog 的最新版本不可用
      • VHDL 结构记录(record),Verilog 结构(struct)已经破碎(SystemVerilog 在这方面很好,如果您可以使用它)
      • VHDL 和 Verilog 太冗长了
      • 元硬件描述能力
  • 简介
    • 关于 SpinalHDL
      • 什么是SpinalHDL?
      • SpinalHDL 不是什么
      • Spinal开发流程
      • SpinalHDL 相对于 VHDL / Verilog 的优势
    • 一个简单的例子
      • Component
      • 端口
      • 内部逻辑
    • 使用 SpinalHDL 的项目
      • 仓库
      • 公司
      • 大学
    • 联系方式
    • 许可证
    • 贡献
    • 常见问题
      • 与人工编写的 VHDL/Verilog 相比,SpinalHDL 生成的 RTL 的开销是多少?
      • 如果 SpinalHDL 将来没有支持了怎么办?
      • SpinalHDL 是否在生成的 VHDL/Verilog 中保留注释?
      • SpinalHDL 可以扩展到大型项目吗?
      • SpinalHDL 是如何诞生的
      • 既然有了VHDL/Verilog/SystemVerilog,为什么还要开发新的语言呢?
      • 如何使用 SpinalHDL 的未发布版本(但在 git 上提交)?
    • 其他学习资料
  • 入门
    • 安装和设置
      • 必需/推荐的工具
      • Linux安装
      • Mac OS X 安装
      • Windows安装
        • 用于仿真的 MSYS2 verilator工具
        • 用 MSYS2 实施形式化验证
      • OCI容器
      • 在无网络的 Linux 环境中安装 SBT
    • 创建第一个 SpinalHDL 项目
      • 项目的目录结构
      • 在 SpinalHDL 代码中使用 Spinal
    • 在 CLI (命令行)中结合 SBT 使用 Spinal
    • 在 VSCodium 中使用 Spinal
    • 从 IntelliJ IDEA 使用 Spinal
    • Scala 使用指南
      • 基础内容
        • 类型
        • 变量
        • 函数
        • 对象(Object)
        • 入口点(main)
        • 类
        • 模板/类型参数化
      • 编码规范
        • 简介
        • 类与样例类
      • 交互
        • 简介
        • SpinalHDL 在 API 隐藏后的工作原理
        • 一切都是引用
        • 硬件类型
        • 生成的 RTL 中的信号名称
        • Scala 用于实例细化,SpinalHDL 用于硬件描述
        • Scala 实例细化能力(if、for、函数式编程)
      • Scala 使用指南
        • 简介
    • VHDL 用户入门
      • 与VHDL对比
        • 简介
        • 过程(Process)
        • 隐式与显式定义对比
        • 时钟域
        • 组件的内部组织方式
        • 安全性
        • 功能与流程
        • 总线和接口
        • 信号声明
        • 组件实例化
        • 类型转换
        • 调整位宽
        • 参数化
        • 元硬件描述
      • VHDL 等效语法
        • 实体和架构
        • 数据类型
        • 信号
        • 赋值
        • 字面量(Literals)
        • 寄存器
        • 过程块
    • 快速参考
      • Core
      • Lib
      • Symbolic
  • 数据类型
    • Bool
      • 描述
      • 声明
      • 运算符
        • 逻辑运算
        • 边缘检测
        • 比较运算
        • 类型转换
        • 杂项
        • 掩码布尔值
    • 位
      • 声明
      • 运算符
        • 逻辑运算
        • 比较运算
        • 类型转换
        • 位提取
        • 杂项
      • 掩码字面量
    • UInt/SInt
      • 声明
      • 运算符
        • 逻辑运算
        • 算术运算
        • 比较运算
        • 类型转换
        • 位提取
        • 杂项
      • 定点小数操作
        • 低位运算
        • 高位操作
        • fixTo 函数
    • SpinalEnum
      • 描述
      • 声明
        • 编码
        • 示例
      • 运算符
        • 比较运算
        • 类型
        • 类型转换
    • Bundle
      • 描述
      • 声明
        • 条件信号
      • 运算符
        • 比较运算
        • 类型转换
        • 将位转换回线束
      • IO元件方向
        • in/out
        • master/slave
    • Vec
      • 描述
      • 声明
        • 示例
      • 运算符
        • 比较运算
        • 类型转换
        • 杂项
        • 库辅助函数
    • UFix/SFix
      • 描述
      • 声明
        • 无符号定点小数
        • 有符号定点小数
        • 格式
        • 示例
      • 赋值
        • 有效赋值
        • 来自 Scala 常量
      • 原始值
        • 示例
      • 运算符
        • 算术运算
        • 比较运算
        • 类型转换
        • 杂项
    • 浮点小数
      • 描述
        • IEEE-754 浮点小数格式
        • 重新编码的浮动小数格式
      • 声明
        • IEEE-754 编码数
        • 重新编码的浮点数
      • 运算符
        • 类型转换
    • AFix
      • 描述
      • 声明
      • 数学运算
      • 不等式运算
      • 位移操作
      • 饱和与舍入
      • 赋值
  • 结构设计
    • 组件和层次结构
      • 输入/输出定义
      • 裁剪信号
      • 参数化硬件(VHDL 中的“Generic”,Verilog 中的“Parameter”)
      • 综合后组件名称
    • Area
    • 函数
      • RGB信号转灰度信号
      • Valid Ready Payload 总线
    • 时钟域
      • 简介
      • 实例化
        • 配置
        • 内部时钟
        • 外部时钟
        • 生成 HDL 时的信号优先级
        • 语境
      • 跨时钟域设计
      • 特殊计时逻辑区
        • 慢时钟逻辑区
        • 启动复位
        • 复位时钟域
        • 时钟使能逻辑区
    • 实例化 VHDL 和 Verilog IP
      • 描述
      • 定义一个黑盒
      • 泛型
      • 实例化黑盒
      • 时钟和复位信号的映射
      • io前缀
      • 重命名黑盒中的所有io
      • 添加 RTL 源
      • VHDL - 无数值类型
    • 保留名称的方法
      • Nameable 基类
      • 从 Scala 中提取名称
      • 组件中的区域
      • 函数中的逻辑区
      • 函数中的复合区(Composite)
      • 复合区级联链
      • 在一个线束(Bundle)的函数中的复合区
      • 未命名信号处理
        • Verilog 表达式分割
        • Verilog 长表达式分割
        • When 语句条件
        • 最后一招
    • 参数化
      • 实例细化时参数
      • 可选硬件
  • 语义
    • 赋值
      • 位宽检查
      • 组合逻辑环(Combinatorial loops)
      • CombInit
    • When/Switch/Mux
      • When
      • WhenBuilder
      • Switch
        • 示例
        • 其他选项
      • 本地声明
      • Mux
      • 按位选择
        • 示例
    • 规则
      • 并发
      • 最后有效赋值生效
      • 信号和寄存器与 Scala 语言的协作(OOP 引用 + 函数)
  • 时序逻辑
    • 寄存器
      • 实例化
      • 复位值
      • 用于仿真目的的初始化值
      • 寄存器组
      • 将线缆/信号转换为寄存器
    • RAM/ROM存储器
      • 同步使能注意事项
      • 写入时读取策略
      • 混合位宽存储器
      • 自动黑盒化
        • 黑盒策略
        • 标准存储器黑盒
  • 设计错误
    • 赋值覆盖(Assignment overlap)
      • 简介
      • 示例
    • 跨时钟域违例(Clock crossing violation)
      • 简介
      • 示例
        • crossClockDomain标签
        • setSynchronousWith
        • BufferCC
    • 组合逻辑环(Combinatorial loop)
      • 简介
      • 示例
      • 误报
    • 层次违例(Hierarchy violation)
      • 简介
      • 示例
    • IO线束
      • 简介
      • 示例
    • 锁存器检测(Latch detected)
      • 简介
      • 示例
      • 因多路复用器产生的错误
    • 无驱动检测(No driver on)
      • 简介
      • 示例
    • 空指针异常(NullPointerException)
      • 简介
      • 示例
        • 问题说明
    • 超出范围的常数(Out of Range Constant)
      • 简介
      • 示例
      • 特殊情况
    • 定义为组件输入的寄存器(Register defined as component input)
      • 简介
      • 示例
    • 作用域违例(Scope violation)
      • 简介
      • 示例
    • Spinal无法克隆类(Spinal can’t clone class)
      • 简介
      • 例子1
      • 例子2
    • 未赋值的寄存器(Unassigned register)
      • 简介
      • 示例
      • 只有初始化(init)的寄存器
    • 无法访问的is语句(Unreachable is statement)
      • 简介
      • 示例
    • 位宽不匹配(Width mismatch)
      • 简介
      • 赋值示例
      • 运算操作示例
  • 其他语言功能
    • 实用工具
      • 介绍
        • Cat
      • 克隆硬件数据类型
      • 将数据类型作为构造函数参数传递
        • 老办法
        • 安全的方法
      • 频率和时间
      • 二进制前缀
    • 存根(Stub)
    • Assertions
    • Report
    • ScopeProperty
    • 模拟信号和输入输出
      • 简介
      • 模拟信号
      • 输入/出
      • 输入/出包装器
      • 手动驱动模拟线束
    • VHDL 和 Verilog 生成
      • 从 SpinalHDL 组件生成 VHDL 和 Verilog
        • Scala 的参数化
        • 来自 shell 的参数化
      • 生成的 VHDL 和 Verilog
        • 组织
        • 组合逻辑
        • 时序逻辑
      • VHDL 和 Verilog 属性
  • 模块库
    • 实用工具
      • 免状态工具
      • 全状态工具
        • 计数器
        • 超时
        • 复位控制
      • 特殊工具
    • Stream
      • 规范
      • 语义
      • 函数
      • 实用工具
        • StreamFifo
        • StreamFifoCC
        • StreamCCByToggle
        • StreamWidthAdapter(反压流位宽适应器)
        • StreamArbiter(反压流仲裁器)
        • StreamJoin
        • StreamFork
        • StreamMux
        • StreamDemux
        • StreamDispatcherSequencial
        • StreamTransactionExtender
      • 仿真支持
    • Flow
      • 规范
      • 函数
      • 代码示例
      • 仿真支持
    • Fragment
      • 规范
      • 函数
    • 状态机
      • 简介
      • StateMachine
        • 入口点
        • 转换
        • 状态编码
      • 状态
        • StateDelay(状态延迟)
        • StateFsm
        • StateParallelFsm
        • 关于入口状态的注释
    • VexRiscv(RV32IM CPU)
    • 总线从端生成器
      • 简介
      • 功能
    • 纤程框架
      • 简单的示例
      • Handle[T]
        • soon(handle)
    • 二进制系统
      • 规范
      • String转为Int/Long/BigInt
      • Int/Long/BigInt转为String
      • Int/Long/BigInt转为二进制列表
      • 二进制列表转为Int/Long/BigInt
      • BigInt放大器
    • RegIf
      • 自动分配
      • 28种访问类型
      • 自动生成文档
      • 特殊访问用途
      • 字节掩码
      • 典型例子
      • 中断生成器
        • IP级中断生成器
        • SYS级中断合并
        • Spinal的生成器
        • 示例
      • 默认读取值
      • 开发者区域
    • 总线
      • AHB-Lite3
        • 配置和实例化
        • 变体
      • Apb3
        • 配置和实例化
        • 函数和运算符
      • Axi4
        • 配置和实例化
        • 变体
        • 函数和运算符
      • AvalonMM
        • 配置和实例化
      • Tilelink
        • 配置和实例化
      • tilelink.fabric.Node
        • 顶层示例
        • GPIOFiber示例
        • RamFiber示例
        • CpuFiber示例
        • 位宽适配器(WidthAdapter)示例
    • 通信接口
      • SPI XDR
        • 配置
        • 软件驱动
      • 串口
        • 总线定义
        • UartCtrl
      • USB设备
        • 架构
        • 寄存器
        • 描述符
        • 用法
      • USB OHCI
        • 用法
    • IO口
      • 可读开漏IO(ReadableOpenDrain)
      • 三态
        • 三态
        • 三态阵列
    • 图形
      • 颜色
        • RGB
      • VGA
        • VGA总线
        • VGA时序
        • VGA控制器
    • 自动设计工具(EDA)
      • QSysify
        • 示例
        • 标签
        • 添加新的接口支持
      • QuartusFlow
        • 对于单个rtl文件
        • 对于一个现有项目
    • Pipeline
      • 简介
        • 简单示例
      • Payload
      • Node
      • Links
        • DirectLink
        • StageLink
        • S2mLink
        • CtrlLink
        • 其他链接
        • 您的自定义链接
      • Builder
      • 组合能力(Composability)
      • 重定时/可变长度
      • 简单的CPU示例
    • 杂项
      • Plic映射器
        • PlicMapper.apply
        • PlicMapping.sifive
        • PlicMapping.light
      • 插件
        • 简介
        • 执行顺序
        • 简单示例
        • 联锁/排序
  • 仿真
    • 用于仿真的 SBT 设置
      • 后台依赖的安装说明
        • GHDL 的设置和安装
        • Icarus Verilog 的设置和安装
        • VCS 仿真配置
        • Verilator 的设置和安装
    • 启动仿真器
      • 简介
      • 配置
      • 在同一硬件上运行多个测试
      • 从线程中抛出仿真成功或失败结果
      • 在失败之前捕获给定时间窗内的波形
    • 仿真过程中访问信号
      • 读写信号
      • 访问组件层次结构内部的信号
      • 仿真中内存的加载和存储
    • 时钟域
      • 激励函数API
      • 等待相关API
      • 回调函数API
      • 默认时钟域
      • 新时钟域
    • 全线程API
      • 分裂和合并仿真线程
      • 休眠和等待
    • 无线程API
    • 敏感API
    • 仿真器的具体细节
      • SpinalHDL 如何使用 Verilator 后端进行硬件仿真
      • SpinalHDL 如何使用 GHDL/Icarus Verilog 后端进行硬件仿真
      • SpinalHDL 如何使用 Synopsys VCS 后端进行硬件仿真
      • SpinalHDL 如何使用 Xilinx XSim 后端进行硬件仿真
      • 性能
    • 仿真引擎
    • 示例
      • 异步加法器
      • 双时钟域FIFO
      • 单时钟域FIFO
      • 同步加法器
      • 串口解码器
      • 串口编码器
  • 形式化验证
    • 介绍
    • 形式化验证后端
    • 安装要求
    • 示例
      • 外部断言
      • 内部断言
      • 外部激励
      • 更多关于断言/past(以前某个时钟内的状态)的例子
      • 假设内存中的内容
    • 实用工具和原语
      • 断言/时钟/复位
      • 指定信号的初始值
      • 指定初始假设
      • 内存内容(Mem)检查
      • 在复位的时候进行断言检查,可以这样做
      • 形式化验证的原语
    • 局限性
    • 命名策略
      • 对于组件
      • 对于实现 IMasterSlave的接口
  • 示例
    • 简单示例
      • APB3定义
        • 简介
        • 规范
        • 实现
        • 用法
      • 进位加法器
      • 颜色求和
      • 带清零的计数器
      • 锁相环黑盒和复位控制器
        • PLL BlackBox定义
        • TopLevel定义
      • RGB信号转灰度信号
      • 正弦rom
    • 中级示例
      • 分形计算器
        • 简介
        • 规范
        • 细化参数(泛型)
        • Bundle定义
        • 组件实现
      • 串口
        • 规范
        • 数据结构
        • 实现
        • 简单应用
        • 带TestBench的例子
        • 额外奖励:享受 Stream 带来的乐趣
      • VGA
        • 简介
        • 数据结构
        • VGA控制器
    • 高级示例
      • JTAG TAP
        • 简介
        • JTAG总线
        • JTAG状态机
        • JTAG TAP
        • Jtag指令
        • 用户友好型包装
        • 使用演示
      • 内存映射UART
        • 简介
        • 规范
        • 实现
      • Pinesec
      • 插槽(Slots)
        • 简介
      • 计时器
        • 简介
        • 计时器
        • 桥接函数
    • 入门
  • 历史遗留
    • RiscV
      • 特性
      • 基础FPGA项目
      • 如何生成CPU VHDL
      • 如何调试
      • Todo
    • pinsec
      • 简介
        • 简介
        • 板级支持
      • 硬件
        • 简介
        • RISCV
        • AXI4
        • APB3
        • 生成RTL
      • SoC顶层(Pinsec)
        • 简介
        • 定义所有IO
        • 时钟和复位
        • 主要组件
        • 外设
        • 总线互连
        • 杂项
      • 软件
        • RISCV工具链
        • OpenOCD/GDB/Eclipse配置
  • 杂项
    • 常见错误
    • “main”线程中异常 java.lang.NullPointerException
    • 层次违例(Hierarchy violation)
      • Signal X can’t be assigned by Y
      • Input signal X can’t be assigned by Y
      • Output signal X can’t be assigned by Y
    • spinal.core 组件
      • 时钟域定义
        • 时钟域语法
        • 时钟配置
        • 外部时钟
        • 跨时钟域设计
      • 赋值
      • When / Switch
      • 组件/层次结构
      • Area
      • 函数
        • RGB信号转灰度信号
        • Valid Ready Payload 总线
      • VHDL生成
      • 实例化 VHDL 和 Verilog IP
      • 实用工具
    • Element
    • 范围
  • 开发者专区
    • 总线从端(Factory)实现
      • 简介
      • 规范
      • 实现
        • BusSlaveFactory
        • BusSlaveFactoryDelayed
        • AvalonMMSlaveFactory
      • 结论
    • 如何修改本文档
      • 标题约定
      • Wavedrom 的集成
      • 新章节
        • 示例
    • 通过Mill构建(输出)
      • 编译SpinalHDL库
      • 运行所有测试套件
      • 运行指定的测试套件
      • 运行指定程序(App)
      • 本地发布
    • SpinalHDL 内部数据模型
      • 简介
      • 总体结构
      • 探索数据模型
      • 编译环节
      • 在不使用插件的情况下,以用户身份修改网表
      • 用户空间网表分析
      • 遍历、枚举正在使用的每个时钟域
    • 类型
      • 简介
      • Bool
        • 声明
        • 运算符
      • BitVector 系列 - (Bits, UInt, SInt)
        • 声明语法
        • 运算符
        • 掩码过滤结果比较
      • 位
      • UInt、SInt
      • Bool, Bits, UInt, SInt
      • Vec
      • Bundle
        • 简单示例(RGB/VGA)
        • 接口示例(APB)
      • Enum
      • Data (Bool, Bits, UInt, SInt, Enum, Bundle, Vec)
      • 使用字面量声明信号
      • 用连续赋值字面量作来声明信号
SpinalHDL
  • 模块库
  • 总线
  • tilelink.fabric.Node
  • 在 GitHub 上编辑

tilelink.fabric.Node

tilelink.fabric.Node是常规tilelink硬件实例之上的附加层,用于处理SoC级别的协调和参数传递。

它主要基于Fiber API,它允许创建精化时间纤程(用户空间线程),从而允许确定未来的参数传递/协调和硬件生成。

可以通过3种方式创建节点(Node):

  • tilelink.fabric.Node.down():创建一个可以向下连接(向从端)的节点,因此它将用于CPU/DMA/桥的代理

  • tilelink.fabric.Node():创建中间节点

  • tilelink.fabric.Node.up():创建一个可以向上连接(向主端)的节点,因此它将用于外设/存储器/桥的代理

节点大多具有以下属性:

  • bus : Handle[tilelink.Bus];总线的硬件实例

  • m2s.proposed : Handle[tilelink.M2sSupport];由向上连接提出的功能集

  • m2s.supported : Handle[tilelink.M2sSupport]: 向下连接支持的功能集

  • m2s.parameter : Handle[tilelink.M2sParameter]: 最终的总线参数

您可以注意到它们都是句柄。Handle是SpinalHDL中在纤程之间共享值的一种方式。如果一个纤程读取一个句柄,而这个句柄还没有值,它将阻止该纤程的执行,直到另一个纤程向该句柄提供一个值。

还有一组属性,类似于m2s,但是反向的(名为s2m),它们指定了由互连的从端发起的事务的参数(例如内存一致性)。

有两个演讲介绍了tilelink.fabric.Node。这两个演讲可能并不完全遵循实际语法,它们仍然遵循以下概念:

  • 介绍:https://youtu.be/hVi9xOGuuek

  • 深入:https://peertube.f-si.org/videos/watch/bcf49c84-d21d-4571-a73e-96d7eb89e907

顶层示例

以下是一个简单的虚拟SoC顶层设计示例:

val cpu = new CpuFiber()

val ram = new RamFiber()
ram.up at(0x10000, 0x200) of cpu.down // map the ram at [0x10000-0x101FF], the ram will infer its own size from it

val gpio = new GpioFiber()
gpio.up at 0x20000 of cpu.down // map the gpio at [0x20000-0x20FFF], its range of 4KB being fixed internally

您还可以定义互连中的中间节点,如下所示:

val cpu = new CpuFiber()

val ram = new RamFiber()
ram.up at(0x10000, 0x200) of cpu.down

// Create a peripherals namespace to keep things clean
val peripherals = new Area{
  // Create a intermediate node in the interconnect
  val access = tilelink.fabric.Node()
  access at 0x20000 of cpu.down

  val gpioA = new GpioFiber()
  gpioA.up at 0x0000 of access

  val gpioB = new GpioFiber()
  gpioB.up at 0x1000 of access
}

GPIOFiber示例

GpioFiber是一个简单的tilelink外设,可以读取/驱动32位三态阵列。

import spinal.lib._
import spinal.lib.bus.tilelink
import spinal.core.fiber.Fiber
class GpioFiber extends Area {
  // Define a node facing upward (toward masters only)
  val up = tilelink.fabric.Node.up()

  // Define a elaboration thread to specify the "up" parameters and generate the hardware
  val fiber = Fiber build new Area {
    // Here we first define what our up node support. m2s mean master to slave requests
    up.m2s.supported load tilelink.M2sSupport(
      addressWidth = 12,
      dataWidth = 32,
      // Transfers define which kind of memory transactions our up node will support.
      // Here it only support 4 bytes get/putfull
      transfers = tilelink.M2sTransfers(
        get = tilelink.SizeRange(4),
        putFull = tilelink.SizeRange(4)
      )
    )
    // s2m mean slave to master requests, those are only use for memory coherency purpose
    // So here we specify we do not need any
    up.s2m.none()

    // Then we can finally generate some hardware
    // Starting by defining a 32 bits TriStateArray (Array meaning that each pin has its own writeEnable bit
    val pins = master(TriStateArray(32 bits))

    // tilelink.SlaveFactory is a utility allowing to easily generate the logic required
    // to control some hardware from a tilelink bus.
    val factory = new tilelink.SlaveFactory(up.bus, allowBurst = false)

    // Use the SlaveFactory API to generate some hardware to read / drive the pins
    val writeEnableReg = factory.drive(pins.writeEnable, 0x0) init (0)
    val writeReg = factory.drive(pins.write, 0x4) init(0)
    factory.read(pins.read, 0x8)
  }
}

RamFiber示例

RamFiber是常规tilelink Ram组件的集成层。

import spinal.lib.bus.tilelink
import spinal.core.fiber.Fiber
class RamFiber() extends Area {
  val up = tilelink.fabric.Node.up()

  val thread = Fiber build new Area {
    // Here the supported parameters are function of what the master would like us to idealy support.
    // The tilelink.Ram support all addressWidth / dataWidth / burst length / get / put accesses
    // but doesn't support atomic / coherency. So we take what is proposed to use and restrict it to
    // all sorts of get / put request
    up.m2s.supported load up.m2s.proposed.intersect(M2sTransfers.allGetPut)
    up.s2m.none()

    // Here we infer how many bytes our ram need to be, by looking at the memory mapping of the connected masters
    val bytes = up.ups.map(e => e.mapping.value.highestBound - e.mapping.value.lowerBound + 1).max.toInt

    // Then we finaly generate the regular hardware
    val logic = new tilelink.Ram(up.bus.p.node, bytes)
    logic.io.up << up.bus
  }
}

CpuFiber示例

CpuFiber是一个虚拟的主端集成的示例。

import spinal.lib.bus.tilelink
import spinal.core.fiber.Fiber

class CpuFiber extends Area {
  // Define a node facing downward (toward slaves only)
  val down = tilelink.fabric.Node.down()

  val fiber = Fiber build new Area {
    // Here we force the bus parameters to a specific configurations
    down.m2s forceParameters tilelink.M2sParameters(
      addressWidth = 32,
      dataWidth = 64,
      // We define the traffic of each master using this node. (one master => one M2sAgent)
      // In our case, there is only the CpuFiber.
      masters = List(
        tilelink.M2sAgent(
          name = CpuFiber.this, // Reference to the original agent.
          // A agent can use multiple sets of source ID for different purposes
          // Here we define the usage of every sets of source ID
          // In our case, let's say we use ID [0-3] to emit get/putFull requests
          mapping = List(
            tilelink.M2sSource(
              id = SizeMapping(0, 4),
              emits = M2sTransfers(
                get = tilelink.SizeRange(1, 64), //Meaning the get access can be any power of 2 size in [1, 64]
                putFull = tilelink.SizeRange(1, 64)
              )
            )
          )
        )
      )
    )

    // Lets say the CPU doesn't support any slave initiated requests (memory coherency)
    down.s2m.supported load tilelink.S2mSupport.none()

    // Then we can generate some hardware (nothing usefull in this example)
    down.bus.a.setIdle()
    down.bus.d.ready := True
  }
}

Tilelink的一个特殊性是,它假设主端不会向未映射的内存空间发出请求。为了让主机识别允许访问哪些内存,您可以使用spinal.lib.system.tag.MemoryConnection.getMemoryTransfers工具,如下所示:

val mappings = spinal.lib.system.tag.MemoryConnection.getMemoryTransfers(down)
// Here we just print the values out in stdout, but instead you can generate some hardware from it.
for(mapping <- mappings){
  println(s"- ${mapping.where} -> ${mapping.transfers}")
}

如果您在CPU的纤程中运行此命令,在下面的soc中:

val cpu = new CpuFiber()

val ram = new RamFiber()
ram.up at(0x10000, 0x200) of cpu.down

// Create a peripherals namespace to keep things clean
val peripherals = new Area{
  // Create a intermediate node in the interconnect
  val access = tilelink.fabric.Node()
  access at 0x20000 of cpu.down

  val gpioA = new GpioFiber()
  gpioA.up at 0x0000 of access

  val gpioB = new GpioFiber()
  gpioB.up at 0x1000 of access
}

你会得到 :

- toplevel/ram_up mapped=SM(0x10000, 0x200) through=List(OT(0x10000))  -> GF
- toplevel/peripherals_gpioA_up mapped=SM(0x20000, 0x1000) through=List(OT(0x20000), OT(0x0))  -> GF
- toplevel/peripherals_gpioB_up mapped=SM(0x21000, 0x1000) through=List(OT(0x20000), OT(0x1000))  -> GF
  • “through=” 指定了到达目标所需的地址转换链。

  • “SM” 表示SizeMapping(address, size)

  • “OT” 表示OffsetTransformer(offset)

请注意,您还可以将PMA(物理内存属性)添加到节点,并通过此getMemoryTransfers工具检索它们。

当前PMA的定义是:

object MAIN          extends PMA
object IO            extends PMA
object CACHABLE      extends PMA // an intermediate agent may have cached a copy of the region for you
object TRACEABLE     extends PMA // the region may have been cached by another master, but coherence is being provided
object UNCACHABLE    extends PMA // the region has not been cached yet, but should be cached when possible
object IDEMPOTENT    extends PMA // reads return most recently put content, but content should not be cached
object EXECUTABLE    extends PMA // Allows an agent to fetch code from this region
object VOLATILE      extends PMA // content may change without a write
object WRITE_EFFECTS extends PMA // writes produce side effects and so must not be combined/delayed
object READ_EFFECTS  extends PMA // reads produce side effects and so must not be issued speculatively

getMemoryTransfers工具依赖于专用的SpinalTag:

trait MemoryConnection extends SpinalTag {
  def up : Nameable with SpinalTagReady // Side toward the masters of the system
  def down : Nameable with SpinalTagReady // Side toward the slaves of the system
  def mapping : AddressMapping //Specify the memory mapping of the slave from the master address (before transformers are applied)
  def transformers : List[AddressTransformer]  //List of alteration done to the address on this connection (ex offset, interleaving, ...)
  def sToM(downs : MemoryTransfers, args : MappedNode) : MemoryTransfers = downs //Convert the slave MemoryTransfers capabilities into the master ones
}

该SpinalTag可以应用于给定内存总线连接的两端,以保持该连接在生成时可被发现,从而创建内存连接(MemoryConnection)图。它的一个优点是它与总线无关,这意味着它不是tilelink特有的。

位宽适配器(WidthAdapter)示例

位宽适配器是桥的一个简单例子。

class WidthAdapterFiber() extends Area{
  val up = Node.up()
  val down = Node.down()

  // Populate the MemoryConnection graph
  new MemoryConnection {
    override def up = up
    override def down = down
    override def transformers = Nil
    override def mapping = SizeMapping(0, BigInt(1) << WidthAdapterFiber.this.up.m2s.parameters.addressWidth)
    populate()
  }

  // Fiber in which we will negociate the data width parameters and generate the hardware
  val logic = Fiber build new Area{
    // First, we propagate downward the parameter proposal, hopping that the downward side will agree
    down.m2s.proposed.load(up.m2s.proposed)

    // Second, we will propagate upward what is actualy supported, but will take care of any dataWidth missmatch
    up.m2s.supported load down.m2s.supported.copy(
      dataWidth = up.m2s.proposed.dataWidth
    )

    // Third, we propagate downward the final bus parameter, but will take care of any dataWidth missmatch
    down.m2s.parameters load up.m2s.parameters.copy(
      dataWidth = down.m2s.supported.dataWidth
    )

    // No alteration on s2m parameters
    up.s2m.from(down.s2m)

    // Finaly, we generate the hardware
    val bridge = new tilelink.WidthAdapter(up.bus.p, down.bus.p)
    bridge.io.up << up.bus
    bridge.io.down >> down.bus
  }
}
上一页 下一页

© 版权所有 2018 - 2024, SpinalHDL.

利用 Sphinx 构建,使用的 主题 由 Read the Docs 开发.