基于 AXI-Lite 實現可擴展的硬件函數 RPC 框架(附完整源碼)

AXI-Lite 實現RPC調用硬件函數服務

👋 本文介紹如何基于 AXI-Lite 總線設計一個通用的“硬件函數調用框架”。主機端(PS)只需通過寄存器寫入參數與啟動標志,即可觸發 PL 模塊執行指定算法邏輯,并將結果返回。

該機制本質上是一種硬件層的遠程過程調用(RPC),在嵌入式/FPGA 系統中具有廣泛應用價值,特別適用于:

  • 💡 自定義算法邏輯(如加法、乘法、查表)
  • ? 硬件加速模塊(如濾波、壓縮、比對)
  • 🧱 基于寄存器映射的服務型模塊自定義外設

AXI-Lite的原理和使用可參考我的另一篇文章:

👉 《Zynq AXI-Lite 總線原理與實現》


BD圖

在這里插入圖片描述


📦 系統結構

     ┌──────────────┐│   PS 主機    ││  (ARM/Linux) │└──────┬───────┘│AXI-Lite┌──────▼───────┐│ axi_lite_slave │ ← 提供寄存器讀寫接口└──────┬───────┘│┌──────▼──────────┐│  rpc_processor │ ← 執行“函數”調用(如加法)└────────────────┘

🧠 功能簡介

  • ? PS 主機通過 AXI-Lite 寫入參數、選擇方法、觸發執行
  • ? PL 模塊 rpc_processor 根據方法編號執行對應處理(如參數加法)
  • ? 支持多個返回值(最多 4 個)
  • ? 通過仿真 testbench + PS 代碼兩種方式調用與驗證

📐 寄存器定義

地址偏移名稱作用位說明
0x00REG_CTRL控制與狀態寄存器[0]=start,[1]=ready,[2]=done,[3]=valid
0x04REG_METHOD方法編號(功能碼)0 = 回顯(ECHO),1 = 加法(ADD)
0x08~0x14REG_ARG0~3輸入參數(共4個)32-bit 輸入
0x18~0x24REG_RES0~3輸出結果(共4個)32-bit 輸出

📌 所有寄存器均為 32-bit,支持通過 AXI-Lite 接口進行讀寫訪問。


寄存器映射表

mem索引地址偏移寄存器名稱說明
mem[0]0x00REG_CTRL控制/狀態
mem[1]0x04REG_METHOD方法編號
mem[2]0x08REG_ARG0請求參數0
mem[3]0x0CREG_ARG1請求參數1
mem[4]0x10REG_ARG2請求參數2
mem[5]0x14REG_ARG3請求參數3
mem[6]0x18REG_RES0響應結果0
mem[7]0x1CREG_RES1響應結果1
mem[8]0x20REG_RES2響應結果2
mem[9]0x24REG_RES3響應結果3

rpc_processor.v

`timescale 1ns/1ps// 宏定義:RPC方法(32位功能碼)
`define RPC_FUNC_ECHO    32'h00000000  // 回顯功能(返回輸入參數)
`define RPC_FUNC_ADD     32'h00000001  // 加法功能(參數相加)module rpc_processor (input  wire        i_clk,         // 時鐘信號input  wire        i_rst_n,       // 復位信號(低有效)// 寄存器接口(直接暴露)input  wire [31:0] i_method_reg,  // 方法選擇寄存器input  wire [31:0] i_req_reg_0,   // 請求參數0input  wire [31:0] i_req_reg_1,   // 請求參數1input  wire [31:0] i_req_reg_2,   // 請求參數2input  wire [31:0] i_req_reg_3,   // 請求參數3output reg  [31:0] o_res_reg_0,   // 響應結果0output reg  [31:0] o_res_reg_1,   // 響應結果1output reg  [31:0] o_res_reg_2,   // 響應結果2output reg  [31:0] o_res_reg_3,   // 響應結果3// RPC控制信號(含啟動信號)input  wire        i_rpc_start,   // RPC啟動信號(1=觸發處理,上升沿有效)output reg         o_rpc_valid,   // RPC請求有效(處理中保持高)input  wire        i_rpc_ready,   // 外部處理就緒(1=可接收請求)output reg         o_rpc_done     // RPC處理完成(1=結果有效)
);// --------------------------// 啟動信號邊沿檢測(防止持續觸發)// --------------------------reg r_rpc_start_dly;wire w_rpc_start_posedge;  // 啟動信號上升沿(真正的觸發點)always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) beginr_rpc_start_dly <= 1'b0;end else beginr_rpc_start_dly <= i_rpc_start;  // 延遲一拍用于邊沿檢測endendassign w_rpc_start_posedge = i_rpc_start && !r_rpc_start_dly;  // 上升沿檢測// --------------------------// 內部鎖存寄存器(處理期間保持參數穩定)// --------------------------reg [31:0] r_method_latch;reg [31:0] r_req_latch_0, r_req_latch_1, r_req_latch_2, r_req_latch_3;// --------------------------// RPC處理狀態機// --------------------------localparam S_IDLE      = 2'b00;localparam S_PROCESSING = 2'b01;localparam S_DONE      = 2'b10;reg [1:0] r_state;reg [3:0] r_proc_cnt;  // 模擬處理延遲(0~15周期)always @(posedge i_clk or negedge i_rst_n) beginif (!i_rst_n) beginr_state <= S_IDLE;r_proc_cnt <= 4'h0;o_rpc_valid <= 1'b0;o_rpc_done <= 1'b0;r_method_latch <= 32'h0;r_req_latch_0 <= 32'h0;r_req_latch_1 <= 32'h0;r_req_latch_2 <= 32'h0;r_req_latch_3 <= 32'h0;o_res_reg_0 <= 32'h0;o_res_reg_1 <= 32'h0;o_res_reg_2 <= 32'h0;o_res_reg_3 <= 32'h0;end else begincase (r_state)S_IDLE: begin// 檢測到啟動信號上升沿,且外部就緒時,啟動處理if (w_rpc_start_posedge && i_rpc_ready) begino_rpc_done <= 1'b0;  // 完成標志清0// 鎖存當前寄存器值(處理期間參數不變)r_method_latch <= i_method_reg;r_req_latch_0 <= i_req_reg_0;r_req_latch_1 <= i_req_reg_1;r_req_latch_2 <= i_req_reg_2;r_req_latch_3 <= i_req_reg_3;o_rpc_valid <= 1'b1;      // 置位請求有效r_state <= S_PROCESSING;    // 進入處理狀態r_proc_cnt <= 4'h0;       // 重置延遲計數器end else begino_rpc_valid <= 1'b0;r_state <= S_IDLE;endendS_PROCESSING: begin// 模擬處理延遲(例如10個時鐘周期,可修改)if (r_proc_cnt >= 4'd9) begin// 根據方法號執行不同處理(示例邏輯)case (r_method_latch)`RPC_FUNC_ECHO: begin  // 方法0:返回請求參數o_res_reg_0 <= r_req_latch_0;o_res_reg_1 <= r_req_latch_1;o_res_reg_2 <= r_req_latch_2;o_res_reg_3 <= r_req_latch_3;end`RPC_FUNC_ADD: begin  // 方法1:參數相加o_res_reg_0 <= r_req_latch_0 + r_req_latch_1;o_res_reg_1 <= r_req_latch_2 + r_req_latch_3;o_res_reg_2 <= r_req_latch_0 + r_req_latch_2;o_res_reg_3 <= r_req_latch_1 + r_req_latch_3;enddefault: begin  o_res_reg_0 <= 32'h0;o_res_reg_1 <= 32'h0;o_res_reg_2 <= 32'h0;o_res_reg_3 <= 32'h0;endendcaser_state <= S_DONE;end else beginr_proc_cnt <= r_proc_cnt + 1'b1;r_state <= S_PROCESSING;endendS_DONE: begino_rpc_valid <= 1'b0;      // 清除請求有效o_rpc_done <= 1'b1;       // 置位完成標志(通知結果就緒)r_state <= S_IDLE;          // 返回空閑狀態,等待下一次啟動enddefault: r_state <= S_IDLE;endcaseendendendmodule

tb_rpc_processor.sv

`timescale 1ns/1ps// 接口定義:抽象DUT的所有信號
interface rpc_if;logic         i_clk;logic         i_rst_n;logic [31:0]  i_method_reg;logic [31:0]  i_req_reg_0;logic [31:0]  i_req_reg_1;logic [31:0]  i_req_reg_2;logic [31:0]  i_req_reg_3;logic         i_rpc_start;logic         i_rpc_ready;logic [31:0]  o_res_reg_0;logic [31:0]  o_res_reg_1;logic [31:0]  o_res_reg_2;logic [31:0]  o_res_reg_3;logic         o_rpc_valid;logic         o_rpc_done;// 時鐘生成(50MHz,周期20ns)initial begini_clk = 1'b0;forever #10 i_clk = ~i_clk;end
endinterface// RPC測試類:封裝所有測試邏輯
class rpc_tester;// 虛擬接口:用于連接DUTvirtual rpc_if vif;// 宏定義:RPC方法(與DUT保持一致)localparam RPC_FUNC_ECHO = 32'h00000000;localparam RPC_FUNC_ADD  = 32'h00000001;// 構造函數:綁定接口function new(virtual rpc_if ifc);vif = ifc;endfunction// 初始化所有信號task initialize();vif.i_rst_n = 1'b0;vif.i_method_reg = 32'h0;vif.i_req_reg_0 = 32'h0;vif.i_req_reg_1 = 32'h0;vif.i_req_reg_2 = 32'h0;vif.i_req_reg_3 = 32'h0;vif.i_rpc_start = 1'b0;vif.i_rpc_ready = 1'b0;endtask// 執行復位并等待穩定task reset();@(posedge vif.i_clk);vif.i_rst_n = 1'b0;#100;  // 保持復位100ns@(posedge vif.i_clk);vif.i_rst_n = 1'b1;  // 釋放復位#20;   // 等待復位釋放穩定endtask// 發送RPC請求并等待完成task send_rpc(input logic [31:0] method,input logic [31:0] req0,input logic [31:0] req1,input logic [31:0] req2,input logic [31:0] req3,input logic        ready);// 設置請求參數@(posedge vif.i_clk);vif.i_method_reg = method;vif.i_req_reg_0 = req0;vif.i_req_reg_1 = req1;vif.i_req_reg_2 = req2;vif.i_req_reg_3 = req3;vif.i_rpc_ready = ready;// 產生start上升沿@(posedge vif.i_clk);vif.i_rpc_start = 1'b1;@(posedge vif.i_clk);vif.i_rpc_start = 1'b0;// 等待處理完成(如果ready為1)if (ready) beginwait(vif.o_rpc_done == 1'b1);@(posedge vif.i_clk);endendtask// 驗證ADD方法結果task verify_add_result(input logic [31:0] exp0,input logic [31:0] exp1,input logic [31:0] exp2,input logic [31:0] exp3);@(posedge vif.i_clk);if (vif.o_res_reg_0 == exp0 && vif.o_res_reg_1 == exp1 &&vif.o_res_reg_2 == exp2 && vif.o_res_reg_3 == exp3) begin$display("ADD method test passed %d",exp0);end else begin$display("ADD method test failed, Expected: %h %h %h %h, Actual: %h %h %h %h",exp0, exp1, exp2, exp3,vif.o_res_reg_0, vif.o_res_reg_1, vif.o_res_reg_2, vif.o_res_reg_3);endendtask// 運行完整測試序列task run_test();// 初始化并復位initialize();reset();// 執行ADD方法測試send_rpc(RPC_FUNC_ADD,32'h00000001,  // req032'h00000002,  // req132'h00000003,  // req232'h00000004,  // req31'b1           // ready);// 驗證結果(1+2=3, 3+4=7, 1+3=4, 2+4=6)verify_add_result(32'h00000003,32'h00000007,32'h00000004,32'h00000006);// 執行ADD方法測試send_rpc(RPC_FUNC_ADD,32'h00000001,  // req032'h00000002,  // req132'h00000003,  // req232'h00000004,  // req31'b1           // ready);// 驗證結果(1+2=3, 3+4=7, 1+3=4, 2+4=6)verify_add_result(32'h00000003,32'h00000007,32'h00000004,32'h00000006);// 測試完成#100;$display("All tests completed");$finish;endtask
endclass// 頂層測試平臺
module tb;wire w_test;// 實例化接口rpc_if rpc_ifc();// 實例化DUT并連接接口rpc_processor uut (.i_clk         (rpc_ifc.i_clk),.i_rst_n       (rpc_ifc.i_rst_n),.i_method_reg  (rpc_ifc.i_method_reg),.i_req_reg_0   (rpc_ifc.i_req_reg_0),.i_req_reg_1   (rpc_ifc.i_req_reg_1),.i_req_reg_2   (rpc_ifc.i_req_reg_2),.i_req_reg_3   (rpc_ifc.i_req_reg_3),.o_res_reg_0   (rpc_ifc.o_res_reg_0),.o_res_reg_1   (rpc_ifc.o_res_reg_1),.o_res_reg_2   (rpc_ifc.o_res_reg_2),.o_res_reg_3   (rpc_ifc.o_res_reg_3),.i_rpc_start   (rpc_ifc.i_rpc_start),.o_rpc_valid   (rpc_ifc.o_rpc_valid),.i_rpc_ready   (rpc_ifc.i_rpc_ready),.o_rpc_done    (rpc_ifc.o_rpc_done));// 啟動測試initial begin// 創建測試實例并運行測試rpc_tester tester = new(rpc_ifc);tester.run_test();end
endmodule

axi_lite_slave.v

module axi_lite_slave #(parameter ADDR_WIDTH = 32,             // 地址總線位寬 Address widthparameter DATA_WIDTH = 32,             // 數據總線位寬 Data widthparameter MEM_SIZE   = 1024            // 內部存儲器大小(單位:字節) Memory size in bytes
)(input  wire                     clk,           // 時鐘 Clockinput  wire                     rst_n,         // 異步復位,低有效 Asynchronous reset, active-low// AXI 寫地址通道(Write Address Channel)input  wire [ADDR_WIDTH-1:0]    s_axi_awaddr,  // 寫地址 Write addressinput  wire                     s_axi_awvalid, // 寫地址有效 Write address validoutput reg                      s_axi_awready, // 寫地址就緒 Write address ready// AXI 寫數據通道(Write Data Channel)input  wire [DATA_WIDTH-1:0]    s_axi_wdata,   // 寫數據 Write datainput  wire [(DATA_WIDTH/8)-1:0] s_axi_wstrb,  // 寫字節使能 Byte enableinput  wire                     s_axi_wvalid,  // 寫數據有效 Write data validoutput reg                      s_axi_wready,  // 寫數據就緒 Write data ready// AXI 寫響應通道(Write Response Channel)output reg  [1:0]               s_axi_bresp,   // 寫響應 Write responseoutput reg                      s_axi_bvalid,  // 寫響應有效 Write response validinput  wire                     s_axi_bready,  // 寫響應就緒 Write response ready// AXI 讀地址通道(Read Address Channel)input  wire [ADDR_WIDTH-1:0]    s_axi_araddr,  // 讀地址 Read addressinput  wire                     s_axi_arvalid, // 讀地址有效 Read address validoutput reg                      s_axi_arready, // 讀地址就緒 Read address ready// AXI 讀數據通道(Read Data Channel)output reg  [DATA_WIDTH-1:0]    s_axi_rdata,   // 讀數據 Read dataoutput reg  [1:0]               s_axi_rresp,   // 讀響應 Read responseoutput reg                      s_axi_rvalid,  // 讀數據有效 Read data validinput  wire                     s_axi_rready   // 讀數據就緒 Read data ready
);// 內部寄存器(寄存器文件,32-bit對齊)reg [DATA_WIDTH-1:0] mem [0:(MEM_SIZE/DATA_WIDTH)-1];// RPC 處理器輸出端口連接線wire [31:0] w_res_reg_0, w_res_reg_1, w_res_reg_2, w_res_reg_3;wire        w_rpc_done, w_rpc_valid;// 狀態定義(State definitions)localparam IDLE        = 3'd0;localparam WRITE_ADDR  = 3'd1;localparam WRITE_DATA  = 3'd2;localparam WRITE_RESP  = 3'd3;localparam READ_ADDR   = 3'd4;localparam READ_DATA   = 3'd5;reg [2:0] state, next_state;              // 狀態寄存器reg [ADDR_WIDTH-1:0] write_addr;         // 寫地址寄存器reg [ADDR_WIDTH-1:0] read_addr;          // 讀地址寄存器// 狀態機:狀態跳轉邏輯always @(posedge clk or negedge rst_n) beginif (!rst_n)state <= IDLE;elsestate <= next_state;end// 狀態機:下一狀態邏輯always @(*) beginnext_state = state;case (state)IDLE: beginif (s_axi_awvalid)next_state = WRITE_ADDR;else if (s_axi_arvalid)next_state = READ_ADDR;endWRITE_ADDR: next_state = WRITE_DATA;WRITE_DATA: if (s_axi_wvalid) next_state = WRITE_RESP;WRITE_RESP: if (s_axi_bready) next_state = IDLE;READ_ADDR : next_state = READ_DATA;READ_DATA : if (s_axi_rready) next_state = IDLE;default   : next_state = IDLE;endcaseend// 輸出邏輯:AXI 信號 + 寄存器讀寫always @(posedge clk or negedge rst_n) beginif (!rst_n) begin// 所有輸出復位s_axi_awready <= 0;s_axi_wready  <= 0;s_axi_bresp   <= 0;s_axi_bvalid  <= 0;s_axi_arready <= 0;s_axi_rdata   <= 0;s_axi_rresp   <= 0;s_axi_rvalid  <= 0;write_addr    <= 0;read_addr     <= 0;//mem 初始化mem[0][0] <= 1'b0;mem[0][2] <= 1'b0;mem[0][3] <= 1'b0;mem[6]    <= 32'd0;mem[7]    <= 32'd0;mem[8]    <= 32'd0;mem[9]    <= 32'd0;// 模塊重編譯生效測試mem[20]   <= 7624;end else begincase (state)IDLE: begin// 清除所有 ready/valid 信號s_axi_awready <= 0;s_axi_wready  <= 0;s_axi_bvalid  <= 0;s_axi_arready <= 0;s_axi_rvalid  <= 0;// 接收寫地址或讀地址if (s_axi_awvalid) begins_axi_awready <= 1;write_addr    <= s_axi_awaddr;end else if (s_axi_arvalid) begins_axi_arready <= 1;read_addr     <= s_axi_araddr;endendWRITE_ADDR: begins_axi_awready <= 0;s_axi_wready  <= 1;   // 等待寫數據endWRITE_DATA: beginif (s_axi_wvalid) begins_axi_wready <= 0;mem[write_addr[8:2]] <= s_axi_wdata;  // 寫入數據s_axi_bresp  <= 2'b00;                // OKAYs_axi_bvalid <= 1;endendWRITE_RESP: beginif (s_axi_bready)s_axi_bvalid <= 0;endREAD_ADDR: begins_axi_arready <= 0;s_axi_rdata   <= mem[read_addr[8:2]];     // 讀取數據s_axi_rresp   <= 2'b00;                   // OKAYs_axi_rvalid  <= 1;endREAD_DATA: beginif (s_axi_rready)s_axi_rvalid <= 0;endendcase// 每個時鐘周期更新 RPC 輸出值到寄存器(6~9)mem[6] <= w_res_reg_0;mem[7] <= w_res_reg_1;mem[8] <= w_res_reg_2;mem[9] <= w_res_reg_3;mem[0][2] <= w_rpc_done;mem[0][3] <= w_rpc_valid;endend// 實例化 RPC 處理器模塊,連接輸入參數和輸出結果寄存器rpc_processor u_rpc (.i_clk        (clk),.i_rst_n      (rst_n),.i_method_reg (mem[1]),        // 功能號寄存器.i_req_reg_0  (mem[2]),        // 參數0.i_req_reg_1  (mem[3]),        // 參數1.i_req_reg_2  (mem[4]),        // 參數2.i_req_reg_3  (mem[5]),        // 參數3.o_res_reg_0  (w_res_reg_0),   // 返回值0.o_res_reg_1  (w_res_reg_1),   // 返回值1.o_res_reg_2  (w_res_reg_2),   // 返回值2.o_res_reg_3  (w_res_reg_3),   // 返回值3.i_rpc_start  (mem[0][0]),     // 啟動標志.i_rpc_ready  (mem[0][1]),     // RPC主機方法和參數準備好了.o_rpc_done   (w_rpc_done),    // RPC處理完成(1=結果有效).o_rpc_valid  (w_rpc_valid)    // RPC請求有效(處理中保持高));endmodule

PS 裸機測試

#include "xil_io.h"
#include "xil_printf.h"
#include <stdio.h>#define BASE_ADDR       0x43c00000
#define MAX_INDEX   30
#define REG_CTRL        (BASE_ADDR + 4*0)
#define REG_METHOD      (BASE_ADDR + 4*1)
#define REG_ARG0        (BASE_ADDR + 4*2)
#define REG_ARG1        (BASE_ADDR + 4*3)
#define REG_ARG2        (BASE_ADDR + 4*4)
#define REG_ARG3        (BASE_ADDR + 4*5)
#define REG_RES0        (BASE_ADDR + 4*6)
#define REG_RES1        (BASE_ADDR + 4*7)
#define REG_RES2        (BASE_ADDR + 4*8)
#define REG_RES3        (BASE_ADDR + 4*9)#define BIT_RPC_START   (1 << 0)
#define BIT_RPC_READY   (1 << 1)
#define BIT_RPC_DONE    (1 << 2)
#define BIT_RPC_VALID   (1 << 3)void rpc_call(u32 method, u32 a0, u32 a1, u32 a2, u32 a3) {Xil_Out32(REG_METHOD, method);Xil_Out32(REG_ARG0, a0);Xil_Out32(REG_ARG1, a1);Xil_Out32(REG_ARG2, a2);Xil_Out32(REG_ARG3, a3);Xil_Out32(REG_CTRL, BIT_RPC_READY | BIT_RPC_START);int timeout_cnt = 0;const int TIMEOUT_MAX = 100;while (Xil_In32(REG_CTRL) & BIT_RPC_DONE == 0) {if (++timeout_cnt > TIMEOUT_MAX) {xil_printf("Timeout: RPC method %d failed.\n", method);Xil_Out32(REG_CTRL, 0x00);return;}}Xil_Out32(REG_CTRL, 0x00);u32 r0 = Xil_In32(REG_RES0);u32 r1 = Xil_In32(REG_RES1);u32 r2 = Xil_In32(REG_RES2);u32 r3 = Xil_In32(REG_RES3);xil_printf("RPC method %d result:\n", method);xil_printf("  res0 : %d=%d+%d\n", r0,a0,a1);xil_printf("  res1 : %d=%d+%d\n", r1,a2,a3);xil_printf("  res2 : %d=%d+%d\n", r2,a0,a2);xil_printf("  res3 : %d=%d+%d\n", r3,a1,a3);
}void dump_registers() {u32 val;xil_printf("AXI Register Dump (HEX + DEC):\n");val = Xil_In32(REG_CTRL);xil_printf("  mem[0]  REG_CTRL   = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_METHOD);xil_printf("  mem[1]  REG_METHOD = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_ARG0);xil_printf("  mem[2]  REG_ARG0   = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_ARG1);xil_printf("  mem[3]  REG_ARG1   = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_ARG2);xil_printf("  mem[4]  REG_ARG2   = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_ARG3);xil_printf("  mem[5]  REG_ARG3   = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_RES0);xil_printf("  mem[6]  REG_RES0   = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_RES1);xil_printf("  mem[7]  REG_RES1   = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_RES2);xil_printf("  mem[8]  REG_RES2   = 0x%08X  (%10u)\n", val, val);val = Xil_In32(REG_RES3);xil_printf("  mem[9]  REG_RES3   = 0x%08X  (%10u)\n", val, val);
}int main() {xil_printf("AXI RPC Test Console. Type 't' and press Enter to test.\n");char cmd;int index;u32 value;static int p=0;while (1) {xil_printf("> ");if (scanf(" %c", &cmd) != 1)continue;if (cmd == 't' || cmd == 'T') {rpc_call(1, 1, 2, 3, 4);rpc_call(1, 10, 20, 30, 40);continue;}switch (cmd){case 'r':if (scanf("%d", &index) == 1){if (index < 0 || index > MAX_INDEX){xil_printf("Error: index out of range [0 ~ %d]\r\n", MAX_INDEX);while (getchar() != '\n');continue;}u32 read_val = Xil_In32(BASE_ADDR + 4 * index);xil_printf("[r %d] = 0x%08X / %u\r\n", index, read_val, read_val);}else{xil_printf("Invalid input. Use: r <index>\r\n");while (getchar() != '\n');}break;case 'w':if (scanf("%d %u", &index, &value) == 2){if (index < 0 || index > MAX_INDEX){xil_printf("Error: index out of range [0 ~ %d]\r\n", MAX_INDEX);while (getchar() != '\n');continue;}Xil_Out32(BASE_ADDR + 4 * index, value);xil_printf("[w %d] = 0x%08X / %u\r\n", index, value, value);}else{xil_printf("Invalid input. Use: w <index> <value>\r\n");while (getchar() != '\n');}break;case 'l':{dump_registers();break;}default:xil_printf("Unknown command '%c'. Use 'r' or 'w'.\r\n", cmd);while (getchar() != '\n');break;}}return 0;
}

測試結果

[16:27:01.812]發→◇t
□
[16:27:01.815]收←◆RPC method 1 result:res0 : 3=1+2res1 : 7=3+4res2 : 4=1+3res3 : 6=2+4
RPC method 1 result:res0 : 30=10+20res1 : 70=30+40res2 : 40=10+30res3 : 60=20+40
> 

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917657.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917657.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917657.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[spring-cloud: NamedContextFactory ClientFactoryObjectProvider]-源碼閱讀

依賴 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-commons</artifactId><version>4.3.0</version> </dependency>源碼 NamedContextFactory NamedContextFactory 類通過創建多個子…

HBase MOB技術特點及使用場景介紹

在 HBase 2.0 版本之前,雖然 HBase 能夠存儲從 1 字節到 10MB 大小的二進制對象 ,但其讀寫路徑主要針對小于 100KB 的值進行了優化。當面對大量大小在 100KB - 10MB 之間的數據時,傳統的存儲方式就會暴露出問題。例如,當存儲大量的圖片、文檔或短視頻等中等大小對象時,由于…

Ubuntu 配置密鑰+密碼登錄

目錄 1、密鑰生成 2、發送公鑰至 需要連接的服務器 3、選用私鑰登錄 1、密鑰生成 ssh-keygen -t rsa -b 4096 -C "angindem"2、發送公鑰至 需要連接的服務器 將.ssh中的id_rsa.pub 的密鑰&#xff0c;放在authorized_keys中 注意&#xff1a;.ssh 文件夾一定賦予…

谷歌瀏覽器Chrome 緩存遷移

步驟 1&#xff1a;準備數據遷移1. 關閉 Chrome 及所有后臺進程在任務管理器&#xff08;CtrlShiftEsc&#xff09;中結束所有 chrome.exe 進程。 2. 備份并移動原數據- 將 C:\Users\xxx\AppData\Local\Google\Chrome\User Data **整個文件夾**復制到新位置&#xff08;如 G:\…

Java中的RabbitMQ完全指南

Java中的RabbitMQ完全指南 1. 引言 什么是RabbitMQ RabbitMQ是一個開源的消息代理和隊列服務器&#xff0c;實現了高級消息隊列協議&#xff08;AMQP&#xff09;。它充當應用程序之間的消息中間件&#xff0c;允許分布式系統中的不同組件進行異步通信。RabbitMQ使用Erlang語言…

【MCAL】AUTOSAR架構下SPI數據異步DMA收發具體實現

目錄 前言 正文 1.依賴的硬件特性 1.1.SPI硬件特性 1.1.1. TXFIFO Single Move Mode 1.1.2. RXFIFO Single Move Mode 1.1.3. Move Counter模式 1.1.4. PT中斷 1.2.IR硬件特性 1.3.DMA硬件特性 1.3.1. DMA通道硬件請求 1.3.2. DMA循環Buffer 1.3.3. DMA Link List …

【Unity】協程 Async

協程 協程是 Unity 內置的異步機制&#xff0c;通過 yield 暫停執行&#xff0c;實現任務在多幀中分段執行。與普通函數不同&#xff0c;協程可在執行過程中掛起和恢復&#xff0c;呈現"并發"效果&#xff0c;但本質上仍運行于主線程。若在協程中進行耗時操作&#…

《揭秘!10 分鐘洞悉 Prompt、Function Calling、MCP 與 AI agent 奧秘》

Prompt、Function Calling、MCP、AI agent這些術語頻繁闖入我們的視野&#xff0c;它們到底都是什么、有啥關系。只需十分鐘&#xff0c;咱們抽絲剝繭&#xff0c;揭開它們的神秘面紗&#xff0c;輕松掌握這些關鍵概念 并了解AI agent 完整執行流程。 一、提示詞&#xff08;P…

決策樹(回歸樹)全解析:原理、實踐與應用

文章目錄一、概述1.1 介紹1.2 回歸樹和分類樹區別二、重要參數、屬性及接口2.1 criterion&#xff08;不純度衡量指標&#xff09;2.2 回歸樹如何工作&#xff08;核心流程拆解&#xff09;三、用回歸樹擬合正弦曲線&#xff08;實戰案例&#xff09;3.1 繪制正弦曲線3.2 為正弦…

【盤古100Pro+開發板實驗例程】FPGA學習 | HDMI 回環實驗

本原創文章由深圳市小眼睛科技有限公司創作&#xff0c;版權歸本公司所有&#xff0c;如需轉載&#xff0c;需授權并注明出處&#xff08;www.meyesemi.com) 1. 實驗簡介 實驗目的&#xff1a; 完成 HDMI 回環實驗 實驗環境&#xff1a; Window11 PDS2022.2-SP6.4 硬件環境…

鴻蒙系統PC安裝指南

鴻蒙系統PC安裝指南一、安裝DevEco Studio集成開發環境二、下載鴻蒙系統PC三、啟動鴻蒙系統及使用一、安裝DevEco Studio集成開發環境首先訪問華為官網上&#xff0c;注冊并登錄華為賬號&#xff0c;以開始下載所需的軟件。若尚未注冊&#xff0c;請先注冊一個。在官網頁面中&a…

三十九、【擴展工具篇】Allpairspy 組合用例生成器:智能設計高效測試集

三十九、【擴展工具篇】Allpairspy 組合用例生成器:智能設計高效測試集 前言 準備工作 第一部分:后端實現 - `allpairspy` API 1. 創建 `allpairspy` 服務 2. 創建 `allpairspy` API 視圖 3. 注冊 API 路由 第二部分:前端實現 - `Allpairspy` 工具界面 1. 創建 API 服務 (`s…

ZooKeeper 深度實踐:從原理到 Spring Boot 全棧落地

在 Kubernetes 為主流注冊發現的今天&#xff0c;給出如何在 Spring Boot 中基于 ZooKeeper 實現服務注冊/發現、分布式鎖、配置中心以及集群協調的完整代碼與最佳實踐。所有示例均可直接復制運行。 1. ZooKeeper 架構與核心原理 1.1 角色 Leader&#xff1a;處理寫請求&…

可驗證隨機函數-VRF

可驗證隨機函數&#xff08;Verifiable Random Function, VRF&#xff09;是一種結合密碼學技術的偽隨機數生成器&#xff0c;其核心特點是生成的隨機數可被公開驗證&#xff0c;且具有不可預測性和唯一性。以下是VRF的詳細解析&#xff1a;1. 基本定義與核心特性 可驗證性&…

極客大挑戰2020(部分wp)

Roamphp1-Welcome 405請求方法不允許&#xff0c;改一下請求方法 數組繞過&#xff0c;在頁面搜索flag即可&#xff01;本題&#xff1a;就是知道了405是請求方法不允許&#xff01; Roamphp2-Myblog&#xff08;zip協議加文件包含&#xff09; 首先進來就是一個博客頁面&…

ESP32 外設驅動開發指南 (ESP-IDF框架)——GPIO篇:基礎配置、外部中斷與PWM(LEDC模塊)應用

目錄 一、前言 二、GPIO 2.1 GPIO簡介 2.2 GPIO函數解析 2.3 LED驅動 2.4 KEY驅動 三、EXIT 3.1 EXIT簡介 3.2 EXIT函數解析 3.3 EXIT驅動 四、LEDC 4.1 PWM原理解析 4.2 ESP32的LED PWM控制器介紹 4.3 LEDC函數解析 4.3.1 SW_PWM 4.3.2 HW_PWM 4.4 LEDC驅動 …

鴻蒙 ArkWeb 加載優化方案詳解(2025 最佳實踐)

適用平臺&#xff1a;HarmonyOS NEXT / API 10 關鍵詞&#xff1a;ArkWeb、WebviewController、NodeController、預加載、預連接、預渲染、性能優化一、前言&#xff1a;為什么必須優化 ArkWeb 加載&#xff1f;在鴻蒙生態中&#xff0c;ArkWeb 是系統級的 Web 容器引擎&#x…

JavaScript案例(乘法答題游戲)

項目概述 使用原生JavaScript實現一個乘法答題游戲&#xff0c;隨機生成乘法題目&#xff0c;判斷答案正誤并記錄分數&#xff0c;通過localStorage實現分數持久化存儲。 核心功能需求 隨機題目生成&#xff1a;動態生成1-10之間的乘法題答題交互&#xff1a;輸入答案并提交…

EXCEL刪除數據透視表

wps版 點擊紅框內任意區域 在頂部工具欄選擇刪除Excel 版 1.點擊紅框內任意區域2. 點擊Enable Selection,再按住鍵盤上的Delete鍵&#xff0c;記住不是Backspace鍵

Python 飛機大戰:從零開發經典 2D 射擊游戲

引言&#xff1a;重溫經典游戲開發 飛機大戰作為經典的 2D 射擊游戲&#xff0c;承載了許多人的童年回憶。使用 Python 和 Pygame 開發這樣一款游戲不僅能重溫經典&#xff0c;更是學習游戲開發絕佳的實踐項目。本文將帶你從零開始&#xff0c;一步步實現一個完整的飛機大戰游…