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 代碼兩種方式調用與驗證
📐 寄存器定義
地址偏移 | 名稱 | 作用 | 位說明 |
---|---|---|---|
0x00 | REG_CTRL | 控制與狀態寄存器 | [0]=start,[1]=ready,[2]=done,[3]=valid |
0x04 | REG_METHOD | 方法編號(功能碼) | 0 = 回顯(ECHO),1 = 加法(ADD) |
0x08~0x14 | REG_ARG0~3 | 輸入參數(共4個) | 32-bit 輸入 |
0x18~0x24 | REG_RES0~3 | 輸出結果(共4個) | 32-bit 輸出 |
📌 所有寄存器均為 32-bit,支持通過 AXI-Lite 接口進行讀寫訪問。
寄存器映射表
mem索引 | 地址偏移 | 寄存器名稱 | 說明 |
---|---|---|---|
mem[0] | 0x00 | REG_CTRL | 控制/狀態 |
mem[1] | 0x04 | REG_METHOD | 方法編號 |
mem[2] | 0x08 | REG_ARG0 | 請求參數0 |
mem[3] | 0x0C | REG_ARG1 | 請求參數1 |
mem[4] | 0x10 | REG_ARG2 | 請求參數2 |
mem[5] | 0x14 | REG_ARG3 | 請求參數3 |
mem[6] | 0x18 | REG_RES0 | 響應結果0 |
mem[7] | 0x1C | REG_RES1 | 響應結果1 |
mem[8] | 0x20 | REG_RES2 | 響應結果2 |
mem[9] | 0x24 | REG_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
>