跳转至

流水线 CPU 的设计与实现 - 仲裁器

简介

在实现流水线 CPU 的时候,我们会遇到这样一个问题:IF 段和 MEM 段有可能会同时进行请求。

我们肯定不能把两个请求同时放到我们的 wishbone 总线上——这样肯定会冲突。

因此,我们需要一个新的功能部件——仲裁器来解决这个冲突问题。

有些同学可能想起,我们在实验 2——通过例子学硬件描述语言中曾经给出过两种仲裁器的实现:

请同学们先阅读上面两个例子的内容,再来看接下来的 wishbone 仲裁器的部分。

Wishbone 仲裁器

在这里,我们给出一个 wishbone 仲裁器的实现。

来源:verilog-wishbone

arbiter.v

/*
Copyright (c) 2014-2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Arbiter module
 */
module arbiter #
(
    parameter PORTS = 4,
    // select round robin arbitration
    parameter ARB_TYPE_ROUND_ROBIN = 0,
    // blocking arbiter enable
    parameter ARB_BLOCK = 0,
    // block on acknowledge assert when nonzero, request deassert when 0
    parameter ARB_BLOCK_ACK = 1,
    // LSB priority selection
    parameter ARB_LSB_HIGH_PRIORITY = 0
)
(
    input  wire                     clk,
    input  wire                     rst,

    input  wire [PORTS-1:0]         request,
    input  wire [PORTS-1:0]         acknowledge,

    output wire [PORTS-1:0]         grant,
    output wire                     grant_valid,
    output wire [$clog2(PORTS)-1:0] grant_encoded
);

reg [PORTS-1:0] grant_reg = 0, grant_next;
reg grant_valid_reg = 0, grant_valid_next;
reg [$clog2(PORTS)-1:0] grant_encoded_reg = 0, grant_encoded_next;

assign grant_valid = grant_valid_reg;
assign grant = grant_reg;
assign grant_encoded = grant_encoded_reg;

wire request_valid;
wire [$clog2(PORTS)-1:0] request_index;
wire [PORTS-1:0] request_mask;

priority_encoder #(
    .WIDTH(PORTS),
    .LSB_HIGH_PRIORITY(ARB_LSB_HIGH_PRIORITY)
)
priority_encoder_inst (
    .input_unencoded(request),
    .output_valid(request_valid),
    .output_encoded(request_index),
    .output_unencoded(request_mask)
);

reg [PORTS-1:0] mask_reg = 0, mask_next;

wire masked_request_valid;
wire [$clog2(PORTS)-1:0] masked_request_index;
wire [PORTS-1:0] masked_request_mask;

priority_encoder #(
    .WIDTH(PORTS),
    .LSB_HIGH_PRIORITY(ARB_LSB_HIGH_PRIORITY)
)
priority_encoder_masked (
    .input_unencoded(request & mask_reg),
    .output_valid(masked_request_valid),
    .output_encoded(masked_request_index),
    .output_unencoded(masked_request_mask)
);

always @* begin
    grant_next = 0;
    grant_valid_next = 0;
    grant_encoded_next = 0;
    mask_next = mask_reg;

    if (ARB_BLOCK && !ARB_BLOCK_ACK && grant_reg & request) begin
        // granted request still asserted; hold it
        grant_valid_next = grant_valid_reg;
        grant_next = grant_reg;
        grant_encoded_next = grant_encoded_reg;
    end else if (ARB_BLOCK && ARB_BLOCK_ACK && grant_valid && !(grant_reg & acknowledge)) begin
        // granted request not yet acknowledged; hold it
        grant_valid_next = grant_valid_reg;
        grant_next = grant_reg;
        grant_encoded_next = grant_encoded_reg;
    end else if (request_valid) begin
        if (ARB_TYPE_ROUND_ROBIN) begin
            if (masked_request_valid) begin
                grant_valid_next = 1;
                grant_next = masked_request_mask;
                grant_encoded_next = masked_request_index;
                if (ARB_LSB_HIGH_PRIORITY) begin
                    mask_next = {PORTS{1'b1}} << (masked_request_index + 1);
                end else begin
                    mask_next = {PORTS{1'b1}} >> (PORTS - masked_request_index);
                end
            end else begin
                grant_valid_next = 1;
                grant_next = request_mask;
                grant_encoded_next = request_index;
                if (ARB_LSB_HIGH_PRIORITY) begin
                    mask_next = {PORTS{1'b1}} << (request_index + 1);
                end else begin
                    mask_next = {PORTS{1'b1}} >> (PORTS - request_index);
                end
            end
        end else begin
            grant_valid_next = 1;
            grant_next = request_mask;
            grant_encoded_next = request_index;
        end
    end
end

always @(posedge clk) begin
    if (rst) begin
        grant_reg <= 0;
        grant_valid_reg <= 0;
        grant_encoded_reg <= 0;
        mask_reg <= 0;
    end else begin
        grant_reg <= grant_next;
        grant_valid_reg <= grant_valid_next;
        grant_encoded_reg <= grant_encoded_next;
        mask_reg <= mask_next;
    end
end

endmodule

priority_encoder.v

/*
Copyright (c) 2014-2021 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

// Language: Verilog 2001

`timescale 1ns / 1ps

/*
 * Priority encoder module
 */
module priority_encoder #
(
    parameter WIDTH = 4,
    // LSB priority selection
    parameter LSB_HIGH_PRIORITY = 0
)
(
    input  wire [WIDTH-1:0]         input_unencoded,
    output wire                     output_valid,
    output wire [$clog2(WIDTH)-1:0] output_encoded,
    output wire [WIDTH-1:0]         output_unencoded
);

parameter LEVELS = WIDTH > 2 ? $clog2(WIDTH) : 1;
parameter W = 2**LEVELS;

// pad input to even power of two
wire [W-1:0] input_padded = {{W-WIDTH{1'b0}}, input_unencoded};

wire [W/2-1:0] stage_valid[LEVELS-1:0];
wire [W/2-1:0] stage_enc[LEVELS-1:0];

generate
    genvar l, n;

    // process input bits; generate valid bit and encoded bit for each pair
    for (n = 0; n < W/2; n = n + 1) begin : loop_in
        assign stage_valid[0][n] = |input_padded[n*2+1:n*2];
        if (LSB_HIGH_PRIORITY) begin
            // bit 0 is highest priority
            assign stage_enc[0][n] = !input_padded[n*2+0];
        end else begin
            // bit 0 is lowest priority
            assign stage_enc[0][n] = input_padded[n*2+1];
        end
    end

    // compress down to single valid bit and encoded bus
    for (l = 1; l < LEVELS; l = l + 1) begin : loop_levels
        for (n = 0; n < W/(2*2**l); n = n + 1) begin : loop_compress
            assign stage_valid[l][n] = |stage_valid[l-1][n*2+1:n*2];
            if (LSB_HIGH_PRIORITY) begin
                // bit 0 is highest priority
                assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+0] ? {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]} : {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]};
            end else begin
                // bit 0 is lowest priority
                assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+1] ? {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]} : {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]};
            end
        end
    end
endgenerate

assign output_valid = stage_valid[LEVELS-1];
assign output_encoded = stage_enc[LEVELS-1];
assign output_unencoded = 1 << output_encoded;

endmodule

wb_arbiter_2.v

/*
Copyright (c) 2015-2016 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

// Language: Verilog 2001

`timescale 1 ns / 1 ps

/*
 * Wishbone 2 port arbiter
 */
module wb_arbiter_2 #
(
    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
    parameter SELECT_WIDTH = (DATA_WIDTH/8),      // width of word select bus (1, 2, 4, or 8)
    parameter ARB_TYPE_ROUND_ROBIN = 0,           // select round robin arbitration
    parameter ARB_LSB_HIGH_PRIORITY = 1           // LSB priority selection
)
(
    input  wire                    clk,
    input  wire                    rst,

    /*
     * Wishbone master 0 input
     */
    input  wire [ADDR_WIDTH-1:0]   wbm0_adr_i,    // ADR_I() address input
    input  wire [DATA_WIDTH-1:0]   wbm0_dat_i,    // DAT_I() data in
    output wire [DATA_WIDTH-1:0]   wbm0_dat_o,    // DAT_O() data out
    input  wire                    wbm0_we_i,     // WE_I write enable input
    input  wire [SELECT_WIDTH-1:0] wbm0_sel_i,    // SEL_I() select input
    input  wire                    wbm0_stb_i,    // STB_I strobe input
    output wire                    wbm0_ack_o,    // ACK_O acknowledge output
    output wire                    wbm0_err_o,    // ERR_O error output
    output wire                    wbm0_rty_o,    // RTY_O retry output
    input  wire                    wbm0_cyc_i,    // CYC_I cycle input

    /*
     * Wishbone master 1 input
     */
    input  wire [ADDR_WIDTH-1:0]   wbm1_adr_i,    // ADR_I() address input
    input  wire [DATA_WIDTH-1:0]   wbm1_dat_i,    // DAT_I() data in
    output wire [DATA_WIDTH-1:0]   wbm1_dat_o,    // DAT_O() data out
    input  wire                    wbm1_we_i,     // WE_I write enable input
    input  wire [SELECT_WIDTH-1:0] wbm1_sel_i,    // SEL_I() select input
    input  wire                    wbm1_stb_i,    // STB_I strobe input
    output wire                    wbm1_ack_o,    // ACK_O acknowledge output
    output wire                    wbm1_err_o,    // ERR_O error output
    output wire                    wbm1_rty_o,    // RTY_O retry output
    input  wire                    wbm1_cyc_i,    // CYC_I cycle input

    /*
     * Wishbone slave output
     */
    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,     // ADR_O() address output
    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
    output wire [DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
    output wire                    wbs_we_o,      // WE_O write enable output
    output wire [SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
    output wire                    wbs_stb_o,     // STB_O strobe output
    input  wire                    wbs_ack_i,     // ACK_I acknowledge input
    input  wire                    wbs_err_i,     // ERR_I error input
    input  wire                    wbs_rty_i,     // RTY_I retry input
    output wire                    wbs_cyc_o      // CYC_O cycle output
);

wire [1:0] request;
wire [1:0] grant;
wire grant_valid;

assign request[0] = wbm0_cyc_i;
assign request[1] = wbm1_cyc_i;

wire wbm0_sel = grant[0] & grant_valid;
wire wbm1_sel = grant[1] & grant_valid;

// master 0
assign wbm0_dat_o = wbs_dat_i;
assign wbm0_ack_o = wbs_ack_i & wbm0_sel;
assign wbm0_err_o = wbs_err_i & wbm0_sel;
assign wbm0_rty_o = wbs_rty_i & wbm0_sel;

// master 1
assign wbm1_dat_o = wbs_dat_i;
assign wbm1_ack_o = wbs_ack_i & wbm1_sel;
assign wbm1_err_o = wbs_err_i & wbm1_sel;
assign wbm1_rty_o = wbs_rty_i & wbm1_sel;

// slave
assign wbs_adr_o = wbm0_sel ? wbm0_adr_i :
                   wbm1_sel ? wbm1_adr_i :
                   {ADDR_WIDTH{1'b0}};

assign wbs_dat_o = wbm0_sel ? wbm0_dat_i :
                   wbm1_sel ? wbm1_dat_i :
                   {DATA_WIDTH{1'b0}};

assign wbs_we_o = wbm0_sel ? wbm0_we_i :
                  wbm1_sel ? wbm1_we_i :
                  1'b0;

assign wbs_sel_o = wbm0_sel ? wbm0_sel_i :
                   wbm1_sel ? wbm1_sel_i :
                   {SELECT_WIDTH{1'b0}};

assign wbs_stb_o = wbm0_sel ? wbm0_stb_i :
                   wbm1_sel ? wbm1_stb_i :
                   1'b0;

assign wbs_cyc_o = wbm0_sel ? 1'b1 :
                   wbm1_sel ? 1'b1 :
                   1'b0;

// arbiter instance
arbiter #(
    .PORTS(2),
    .ARB_TYPE_ROUND_ROBIN(ARB_TYPE_ROUND_ROBIN),
    .ARB_BLOCK(1),
    .ARB_BLOCK_ACK(0),
    .ARB_LSB_HIGH_PRIORITY(ARB_LSB_HIGH_PRIORITY)
)
arb_inst (
    .clk(clk),
    .rst(rst),
    .request(request),
    .acknowledge(),
    .grant(grant),
    .grant_valid(grant_valid),
    .grant_encoded()
);

endmodule

使用说明

请同学们将这 3 个文件加入到你的工程当中,然后例化 wb_arbiter_2 即可。

接线时将 wishbone 总线的对应信号接上就可以正常使用仲裁器了。

请注意 arbiter 中优先级的处理。

ARB_TYPE_ROUND_ROBIN为是否使用循环优先级仲裁,实验中请不要使用循环优先级,因此请设置为 0

ARB_LSB_HIGH_PRIORITY为是否让小端(0)为高优先级。由于我们这里是一个双口的 arbiter,而且不使用循环优先级。因此设置为 0 的时候 1 号口的优先级更高,设置为 1 的时候 0 号口的优先级会更高。同学们可以按需设置每个口的优先级进行连线。

如果觉得这个仲裁器太过复杂,同学们也可以根据 lab2 中仲裁器的相关内容自己设计 wishbone 仲裁器。

如果希望使用拥有更多 master 接口的 arbiter,则请参考 SoC 设计 一节有关 wb_mux 的内容使用下面的 python 脚本生成 verilog 并加入项目即可。

wb_arbiter.py

wb_arbiter.py

#!/usr/bin/env python
"""
Generates a Wishbone arbiter with the specified number of ports
"""

from __future__ import print_function

import argparse
import math
from jinja2 import Template

def main():
    parser = argparse.ArgumentParser(description=__doc__.strip())
    parser.add_argument('-p', '--ports',  type=int, default=2, help="number of ports")
    parser.add_argument('-n', '--name',   type=str, help="module name")
    parser.add_argument('-o', '--output', type=str, help="output file name")

    args = parser.parse_args()

    try:
        generate(**args.__dict__)
    except IOError as ex:
        print(ex)
        exit(1)

def generate(ports=2, name=None, output=None):
    if name is None:
        name = "wb_arbiter_{0}".format(ports)

    if output is None:
        output = name + ".v"

    print("Opening file '{0}'...".format(output))

    output_file = open(output, 'w')

    print("Generating {0} port Wishbone arbiter {1}...".format(ports, name))

    select_width = int(math.ceil(math.log(ports, 2)))

    t = Template(u"""/*
Copyright (c) 2015-2016 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1 ns / 1 ps
/*
 * Wishbone {{n}} port arbiter
 */
module {{name}} #
(
    parameter DATA_WIDTH = 32,                    // width of data bus in bits (8, 16, 32, or 64)
    parameter ADDR_WIDTH = 32,                    // width of address bus in bits
    parameter SELECT_WIDTH = (DATA_WIDTH/8),      // width of word select bus (1, 2, 4, or 8)
    parameter ARB_TYPE_ROUND_ROBIN = 0,           // select round robin arbitration
    parameter ARB_LSB_HIGH_PRIORITY = 1           // LSB priority selection
)
(
    input  wire                    clk,
    input  wire                    rst,
{%- for p in ports %}
    /*
     * Wishbone master {{p}} input
     */
    input  wire [ADDR_WIDTH-1:0]   wbm{{p}}_adr_i,    // ADR_I() address input
    input  wire [DATA_WIDTH-1:0]   wbm{{p}}_dat_i,    // DAT_I() data in
    output wire [DATA_WIDTH-1:0]   wbm{{p}}_dat_o,    // DAT_O() data out
    input  wire                    wbm{{p}}_we_i,     // WE_I write enable input
    input  wire [SELECT_WIDTH-1:0] wbm{{p}}_sel_i,    // SEL_I() select input
    input  wire                    wbm{{p}}_stb_i,    // STB_I strobe input
    output wire                    wbm{{p}}_ack_o,    // ACK_O acknowledge output
    output wire                    wbm{{p}}_err_o,    // ERR_O error output
    output wire                    wbm{{p}}_rty_o,    // RTY_O retry output
    input  wire                    wbm{{p}}_cyc_i,    // CYC_I cycle input
{%- endfor %}
    /*
     * Wishbone slave output
     */
    output wire [ADDR_WIDTH-1:0]   wbs_adr_o,     // ADR_O() address output
    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,     // DAT_I() data in
    output wire [DATA_WIDTH-1:0]   wbs_dat_o,     // DAT_O() data out
    output wire                    wbs_we_o,      // WE_O write enable output
    output wire [SELECT_WIDTH-1:0] wbs_sel_o,     // SEL_O() select output
    output wire                    wbs_stb_o,     // STB_O strobe output
    input  wire                    wbs_ack_i,     // ACK_I acknowledge input
    input  wire                    wbs_err_i,     // ERR_I error input
    input  wire                    wbs_rty_i,     // RTY_I retry input
    output wire                    wbs_cyc_o      // CYC_O cycle output
);
wire [{{n-1}}:0] request;
wire [{{n-1}}:0] grant;
{% for p in ports %}
assign request[{{p}}] = wbm{{p}}_cyc_i;
{%- endfor %}
{% for p in ports %}
wire wbm{{p}}_sel = grant[{{p}}] & grant_valid;
{%- endfor %}
{%- for p in ports %}
// master {{p}}
assign wbm{{p}}_dat_o = wbs_dat_i;
assign wbm{{p}}_ack_o = wbs_ack_i & wbm{{p}}_sel;
assign wbm{{p}}_err_o = wbs_err_i & wbm{{p}}_sel;
assign wbm{{p}}_rty_o = wbs_rty_i & wbm{{p}}_sel;
{%- endfor %}
// slave
assign wbs_adr_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_adr_i :
                   {% endfor %}{ADDR_WIDTH{1'b0}};
assign wbs_dat_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_dat_i :
                   {% endfor %}{DATA_WIDTH{1'b0}};
assign wbs_we_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_we_i :
                  {% endfor %}1'b0;
assign wbs_sel_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_sel_i :
                   {% endfor %}{SELECT_WIDTH{1'b0}};
assign wbs_stb_o = {% for p in ports %}wbm{{p}}_sel ? wbm{{p}}_stb_i :
                   {% endfor %}1'b0;
assign wbs_cyc_o = {% for p in ports %}wbm{{p}}_sel ? 1'b1 :
                   {% endfor %}1'b0;
// arbiter instance
arbiter #(
    .PORTS({{n}}),
    .ARB_TYPE_ROUND_ROBIN(ARB_TYPE_ROUND_ROBIN),
    .ARB_BLOCK(1),
    .ARB_BLOCK_ACK(0),
    .ARB_LSB_HIGH_PRIORITY(ARB_LSB_HIGH_PRIORITY)
)
arb_inst (
    .clk(clk),
    .rst(rst),
    .request(request),
    .acknowledge(),
    .grant(grant),
    .grant_valid(grant_valid),
    .grant_encoded()
);
endmodule
""")

    output_file.write(t.render(
        n=ports,
        w=select_width,
        name=name,
        ports=range(ports)
    ))

    print("Done")

if __name__ == "__main__":
    main()

最后更新: 2023年8月31日
作者:Jiajie Chen (99.34%), cuibst (0.66%)