基于verilog的轮询调度器
代码参考这一期视频,博主提供的代码感觉不好综合,改了一版如下所示:
// Round-robin arbiter (combinational index output, no comb loops, low resources)
module EASYAXI_ARB #(parameter DEEP_NUM = 8
)(input wire clk, // System clockinput wire rst_n, // Asynchronous active-low resetinput wire [DEEP_NUM -1:0] queue_i, // Request queue inputinput wire sche_en, // Scheduling enable signaloutput wire [$clog2(DEEP_NUM)-1:0] pointer_o // Grant output (index, combinational)
);// 记录“下一次从谁后面开始找”的优先掩码:// 授权在 k 位,则更新为 ~((1<<(k+1))-1),即仅高于 k 的位为 1,低位全 0reg [DEEP_NUM-1:0] req_power;// 先尝试从当前优先起点之后找;若没有,则从头找wire [DEEP_NUM-1:0] req_after_power = queue_i & req_power;wire old_grant_work = |req_after_power;// 提取最低位 1(one-hot),资源很省:x & (-x) 等价于 x & (~x + 1)wire [DEEP_NUM-1:0] old_first = req_after_power & (~req_after_power + {{(DEEP_NUM-1){1'b0}},1'b1});wire [DEEP_NUM-1:0] new_first = queue_i & (~queue_i + {{(DEEP_NUM-1){1'b0}},1'b1});wire [DEEP_NUM-1:0] grant = old_grant_work ? old_first : new_first; // one-hot 仲裁结果// one-hot -> index(组合)function automatic [$clog2(DEEP_NUM)-1:0] onehot_to_index;input [DEEP_NUM-1:0] onehot;integer i;beginonehot_to_index = {($clog2(DEEP_NUM)){1'b0}};for (i = 0; i < DEEP_NUM; i = i + 1) beginif (onehot[i]) onehot_to_index = i[$clog2(DEEP_NUM)-1:0];endendendfunction// 组合输出:有请求则输出当前仲裁索引,否则为 0assign pointer_o = (|queue_i) ? onehot_to_index(grant): {($clog2(DEEP_NUM)){1'b0}};// 时序:仅在需要调度时更新优先掩码(轮询)// 授权 one-hot = grant;下一轮起点掩码 = ~((grant<<1) - 1)// 当 grant 在最高位时,(grant<<1) 为 0,减 1 生成全 1,取反得全 0,从而下轮会从头(new_first)开始 —— 符合轮询语义always @(posedge clk or negedge rst_n) beginif (~rst_n) beginreq_power <= {DEEP_NUM{1'b1}}; // 复位为“允许从任何位置开始”end else if (sche_en) beginif (|queue_i) beginreq_power <= ~(((grant << 1)) - {{(DEEP_NUM-1){1'b0}},1'b1});end// 若无请求,不更新 req_power(保持当前起点)endendendmodule