You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RISC-V软核GPIO(内存映射)仅输出首个值后续失败问题排查

问题描述

基于PICO-SoC搭建的运行在PYNQ FPGA板上的RISC-V软核SoC,实现了地址为0x00000090的内存映射输出端口。通过软核的Python笔记本编译执行C程序时,仅第一个值7能输出到端口,后续9、15无输出,且程序返回值错误,测试失败;注释GPIO写入代码后程序正常执行。相关代码如下:

C程序代码

%%riscvc test overlay.tutorialProcessor

#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>   

#define reg_outp (*(volatile int*)0x00000090) 

int main(int argc, char ** argv)
{
    unsigned int * arr = (unsigned int *)argv[1];

    reg_outp = 7;           
    reg_outp = 9;            
    reg_outp = 15;

    return arr[2];           
}  

Python执行代码

import numpy as np

arg1 = np.array([4,2,3], np.uint32)
retval = overlay.tutorialProcessor.run(test, arg1)
if (retval != arg1[2]):
    print("Test failed!")
else:
    print("Test passed!") 

Verilog实现代码

always @(posedge clk) begin
        if (!resetn) begin
            gpio <= 0;
        end else begin
            rmem_ready <= 0;
            if (mem_valid && !mem_ready && mem_addr[31:0] == 32'h 00000090) begin
                rmem_ready <= 1;
                if (mem_wstrb[0]) gpio[ 7: 0] <= mem_wdata[ 7: 0];
                if (mem_wstrb[1]) gpio[15: 8] <= mem_wdata[15: 8];
                if (mem_wstrb[2]) gpio[23:16] <= mem_wdata[23:16];
                if (mem_wstrb[3]) gpio[31:24] <= mem_wdata[31:24];
            end
        end
    end

疑问点

  • 是否因程序触发异常提前退出导致后续值无法输出?
  • 可能的故障原因是什么?
  • 0x00000090是否属于代码区域?
  • 该到哪里查看内存映射?
  • 输出端口应映射到哪个内存区域?

问题解答

1. 是否因异常提前退出?

是。从现象看,第一次写端口后程序大概率触发了总线错误、地址非法之类的异常,导致后续代码完全没执行,返回值也出错——毕竟注释GPIO写入逻辑后程序能正常跑,说明问题根源就在端口访问操作上。

2. 可能的故障原因

  • 地址冲突:0x00000090属于低地址段,大概率和SoC的代码/数据内存区域重叠,直接写这个地址会覆盖程序指令或触发内存访问保护,引发异常。
  • 总线响应不完整:Verilog代码只处理了对0x00000090的写请求并拉rmem_ready,但如果CPU因异常处理或其他操作发起对该地址的读请求,模块没有返回rmem_ready,会导致总线挂死或超时异常。
  • 内存属性不匹配:该地址未被配置为IO专用区域,CPU默认按普通内存访问,可能存在缓存、访问顺序等问题,而IO端口需要非缓存、强顺序的访问属性(虽然C代码加了volatile,但硬件端的内存映射配置也要对应)。

3. 0x00000090是否属于代码区域?

大概率是。PICO-SoC的默认内存映射中,起始地址0x0开始的区域是ROM/RAM,用于存放程序代码和数据。0x00000090处于低地址段,肯定在代码/数据内存的范围内,把IO端口映射到这里必然会和程序的指令、数据重叠,访问时触发异常。

4. 查看内存映射的位置

  • 查阅PICO-SoC官方文档或你搭建SoC时的内存规划表,里面会明确ROM、RAM、外设IO等各个区域的地址范围。
  • 查看PYNQ软核的链接脚本(如linker.ld),脚本里会定义代码段、数据段、外设段的具体地址分配。
  • 检查FPGA工程中的地址解码模块,看外设地址的分配规则和映射范围。

5. 输出端口应映射到的内存区域

必须映射到外设专用的MMIO(内存映射IO)地址段,也就是SoC规划中专门留给外设的区域,一般是高地址段(比如0x80000000及以上,具体以PICO-SoC的配置为准)。这个区域不会和代码、数据内存重叠,且硬件会配置对应的非缓存、允许IO访问的总线属性。

比如可以把端口地址改成0x80000000,同时修改Verilog中的地址判断条件,确保CPU访问该地址时能正确响应。


内容的提问来源于stack exchange,提问作者karthik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 17:01:19