以前对着各种教程手戳过轮子,不过由于架构各种看起来都不爽,然后一年多前其实移植过大佬的verilog-ethernet,但是跑完echo就放一边了,最近有一个实际要干的事情,所以又拿起来了.
这个主要是介绍,工程自己下载.
**图片很大,可以自行右键看原图**

我这里实现了很多功能,PicoRV32作为软核,软核主要和这4个外设通信.
其中BRAM是程序储存和运行内存,UART就是打印日志,定时器提供毫秒时间,MDIO就是网卡控制不用多解释.

MDIO通信是为了确定插入状态等,软核上实现函数.
static void mdio_write(uint32_t reg, uint32_t val16)
{
uint32_t reg5 = reg & 0x1Fu;
uint32_t val = val16 & 0xFFFFu;
// clear DONE/ERR (按你 Tcl)
mmio_wr32(MDIO_REG0, 0x00008000u);
uint32_t cmd =
(val << 16) |
(1u << 14) |
(reg5 << 8) |
(1u << 3);
mmio_wr32(MDIO_REG0, cmd);
// 原 Tcl after 1:等 1ms
delay_ms(1);
}
static uint32_t mdio_read(uint32_t reg)
{
uint32_t reg5 = reg & 0x1Fu;
mmio_wr32(MDIO_REG0, 0x00008000u);
uint32_t cmd =
(1u << 14) |
(1u << 13) |
(reg5 << 8) |
(1u << 3);
mmio_wr32(MDIO_REG0, cmd);
delay_ms(1);
uint32_t w = mmio_rd32(MDIO_REG0);
return (w >> 16) & 0xFFFFu;
}
```
软核完整实现,C和RTL在这里,不多说.
<a href="https://github.com/nickfox-taterli/picorv32_full">https://github.com/nickfox-taterli/picorv32_full</a>
网络这里,netcore是对接verilog-ethernet,中间插入fifo是为了不背压以太网,以及过滤坏包.udp_write_to_ddr是具体协议实现.协议在收包后ACK,COMMIT到DDR后再ACK.

当PC把包发送到后,软核可以读到内容.
#define DDR_BASE_ADDR 0x80000000
static void print_ddr_memory(void)
{
volatile uint8_t *ddr_ptr = (volatile uint8_t*)DDR_BASE_ADDR;
for (int i = 0; i < 16; i++) {
uint8_t byte_val = ddr_ptr[i];
// 打印高4位
uint8_t high_nibble = (byte_val >> 4) & 0x0F;
if (high_nibble < 10) {
putc('0' + high_nibble);
} else {
putc('a' + (high_nibble - 10));
}
// 打印低4位
uint8_t low_nibble = byte_val & 0x0F;
if (low_nibble < 10) {
putc('0' + low_nibble);
} else {
putc('a' + (low_nibble - 10));
}
// 打印空格(除了最后一个字节)
if (i < 15) {
putc(' ');
}
}
putc('\r');
putc('\n');
}
可见写入成功,内容对的上.
