Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tong

An SD card emulator implemented using FPGA for debugging embedded bootloaders or bare-metal programs.

FPGA SD 卡模拟器(SDHC 只读,UART 加载)

用于嵌入式 bootloader 开发/调试的 FPGA SD 卡模拟器。支持 SDHC v2 只读卡, 1 位和 4 位数据总线;镜像数据通过 UART 从 PC 预先加载到 FPGA 内部 RAM, 再由 SD 主机接口读出。纯 Verilog 实现,无厂商原语,可在任意主流 FPGA 上综合。

功能

  • SDHC v2 只读卡协议仿真(参考 ref/sd_fake.v):
    • CMD0 / CMD2 / CMD3 / CMD6 / CMD7 / CMD8 / CMD9 / CMD10 / CMD12 / CMD13 / CMD15 / CMD16 / CMD17 / CMD18 / CMD55 + ACMD6 / ACMD13 / ACMD41 / ACMD42 / ACMD51 等,未定义命令返回 illegal command
    • R1 / R2 (CID/CSD) / R3 (OCR) / R6 (RCA) / R7 响应,CRC7 校验
    • 单块读(CMD17)、多块连续读(CMD18 + CMD12)、停止传输
    • 1 位模式与 4 位模式(ACMD6 切换),数据 CRC16 校验
    • SCR / SD_STATUS / CMD6 状态寄存器回读
  • 通过 UART 加载扇区数据(ASCII 与二进制两种协议,参考 ref/uart2bus-master
  • 镜像存放在系统时钟域写、SD 时钟域读的双时钟 RAM 中;按约定 “数据先加载完、再由 SD 接口读取”,不处理读写竞争
  • 只读卡:不实现任何 SD 写命令

目录结构

rtl/
  sd_fake_top.v    顶层:SD 协议 + RAM + UART 加载链路集成
  sd_fake.v        SDHC 只读卡协议仿真(自 ref/ 拷贝,含 1 处时序修正)
  sd_ram.v         双时钟 RAM(UART 写口 + SD 读口,字节写使能)
  uart_ram_bridge.v uart2bus 内部总线 <-> RAM 写口/读回
  uart2bus_top.v   UART 总线封装(自 ref/ 拷贝,参数传递修正)
  uart_parser.v    UART 命令解析器(自 ref/ 拷贝,新增扩展帧支持)
  uart_top.v       UART 收发器(自 ref/ 拷贝,TX 数据接错修正)
sim/
  tb_sd_fake_top.v 完整 testbench(UART 上位机模型 + SD 主机模型)
tools/
  load_sd_image.py 上位机镜像加载/校验脚本

系统结构

                ┌──────────────────────────────────────────────┐
  PC ──UART──▶  │ uart2bus_top ──int bus──▶ uart_ram_bridge ──▶│
                │                              │                │
                │                              ▼                │
                │                          sd_ram 双时钟 RAM     │
                │                        ┌─────▲──────┐         │
                │                        │ port A     │ port B   │
                │                        │ (sysclk)   │ (sdclk)  │
                │                        └────────────┘         │
                │                               ▲               │
                │                          rdreq/rdaddr/rddata  │
                │                               │               │
                │                           sd_fake             │
  SD 主机 ◀───sdclk/sdcmd/sddat──▶         (SD 协议仿真)        │
                └──────────────────────────────────────────────┘

参数

顶层 sd_fake_top

参数 默认值 说明
SYSCLK_HZ 50_000_000 系统时钟(UART 与 RAM 写口)
UART_BAUD 115200 UART 波特率
NUM_SECTORS 128 扇区数(512 B/扇区)。受片上 BRAM 容量限制(Zynq-7010 约 270 KB,留出逻辑占用后约 400 扇区);扩展协议可寻址 16 MB(32768 扇区),超出部分回绕

顶层端口

端口 方向 说明
clk in 系统时钟
rstn in 异步复位,低有效
uart_rx / uart_tx in / out 与 PC 相连的 UART
sdclk in SD 时钟(来自主机)
sdcmd inout SD 命令线(PCB 上需上拉)
sddat[3:0] inout SD 数据线(PCB 上需上拉)
status[7:0] out 调试状态 {resp_end, widebus, ready_for_data, app_cmd, state[3:0]}

UART 协议与地址映射

地址是字节地址:扇区 N 的 512 字节位于 N*512 .. N*512+511

二进制模式(推荐,速度快)

进入二进制模式:发送 0x00,随后:

00  <cmd>  <addr_hi>  <addr_lo>  <len>  [<data>...]              (legacy)
00  <cmd>  <addrH>  <addrM>  <addrL>  <lenH>  <lenL>  [<data>...] (extended)
  • 写:cmd = 0x20(旧格式)/ 0x24(扩展格式);bit[1]=0 地址自动加 1
  • 读:cmd = 0x10(旧格式)/ 0x14(扩展格式)
  • 命令字节 bit[2] 选择帧格式:
    • 旧格式(bit[2]=0):16 位地址 + 8 位长度,len 1..255 字节/命令 (len=0 表示 256 字节)
    • 扩展格式(bit[2]=1):24 位地址 + 16 位长度,单命令最多 65535 字节 (len=0 表示 65536 字节),可寻址 16 MB
  • cmd bit0 = 1 时命令结束后返回一个状态字节 0x5A

扩展格式是推荐格式(加载快、可寻址全镜像空间),旧格式保留兼容。

ASCII 模式

w <2位十六进制数据> <4位十六进制地址><CR>     写 1 字节
r <4位十六进制地址><CR>                      读 1 字节,回显 "XX<CR><LF>"

上位机工具

python tools\load_sd_image.py COM3 boot.bin --baud 115200 --verify

boot.bin(原始扇区数据,bootloader 镜像)加载进模拟卡;--verify 会再读回全部数据并逐字节比对。完整命令行参数如下(也可用 python tools\load_sd_image.py --help 查看):

参数 默认值 说明
port 必填 串口名,如 COM3/dev/ttyUSB0
image 必填 原始镜像文件(扇区数据,如 bootloader 的 bin)
--baud 115200 UART 波特率
--base 0 镜像在 SD 镜像空间中的起始字节地址(0x 十六进制或十进制均可)。加载与 --verify 回读都从该地址开始
--verify 加载后读回全部数据并逐字节比对;不一致时报 VERIFY FAILED 并以非零退出
--status 每条写命令结束后要求返回一个状态字节 0x5A(对应命令字节 bit0=1),校验失败即中止
--legacy 改用旧 16 位地址 / 8 位长度命令(默认使用扩展 24 位地址 / 16 位长度格式)
--timeout 5.0 串口读超时(秒);读回超时即报错退出
-h, --help - 显示帮助并退出

默认的扩展格式单命令最多 65535 字节(len=0 表示 65536),可寻址 16 MB; --legacy 切换为旧格式,单命令最多 255 字节(len=0 表示 256)。legacy 模式下若 --base + 镜像大小 超过 64 KiB,脚本会打印地址回绕警告。实际 RAM 容量由 NUM_SECTORS 决定,超出 NUM_SECTORS*512 的字节地址会回绕 到 RAM 起始处。

仿真验证

需要 Icarus Verilog。testbench 内含完整的 PC 模型(ASCII + 二进制 UART 收发)和 SD 主机模型(初始化序列、 R1/R2/R3/R6/R7 校验、CRC7/CRC16 校验、1 位/4 位/多块读、SCR 检查)。

快速模式(UART 每时钟 1 位,覆盖全部用例,约 2 秒):

iverilog -g2005 -DSIMULATION -o sim\tb_fast.vvp -s tb_sd_fake_top `
  rtl\sd_fake.v rtl\uart_parser.v rtl\uart2bus_top.v rtl\uart_top.v `
  rtl\sd_ram.v rtl\uart_ram_bridge.v rtl\sd_fake_top.v sim\tb_sd_fake_top.v
vvp sim\tb_fast.vvp

真实波特率模式(115200,加载 1 个扇区,约 1.5 分钟):

iverilog -g2005 -DSMOKE -o sim\tb_smoke.vvp -s tb_sd_fake_top `
  rtl\sd_fake.v rtl\uart_parser.v rtl\uart2bus_top.v rtl\uart_top.v `
  rtl\sd_ram.v rtl\uart_ram_bridge.v rtl\sd_fake_top.v sim\tb_sd_fake_top.v
vvp sim\tb_smoke.vvp

两者均应输出 *** ALL TESTS PASSED ***

已知限制与注意事项

  • 只读卡:SD 写命令(CMD24/25/27 等)会返回 illegal command,不实现写入。
  • 加载与读取不竞争:UART 把数据全部写完后,SD 主机再开始读。若边写边读, 数据一致性不做保证。
  • 扩展协议地址空间 24 位(16 MB),但实际容量由片上 BRAM 决定 (NUM_SECTORS),超出 NUM_SECTORS*512 的地址会回绕到 RAM 起始处; 旧 16 位命令只能访问低 64 KiB。
  • 扩展命令(0x24/0x14)需要本工程的新版解析器,旧版固件不识别。
  • SD 时钟由主机提供并自由运行;主机停止 sdclk 时读口冻结,属正常。
  • sdcmd/sddat 为开漏/三态,PCB 上必须加上拉(典型 10kΩ)。
  • 卡固定响应 RCA=0x0013;CSD 为 25 MHz SD-ROM 配置,若 bootloader 要求 更高速度等级可在 sd_fake.v 中调整 CSD_REG/OCR_REG

本项目重度依赖下列开源项目,特此鸣谢

FPGA-SDfake

uart2bus

About

An SD card emulator implemented using FPGA for debugging embedded bootloaders or bare-metal programs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages