Appearance
question:N_MASTER가 4일 때, N_MASTER_LOG2의 값은 어떻게 되고, "[N_MASTER_LOG2-1:0]"는 결과적으로 어떻게 되는가? 아래 코드를 참조해서 대답해줘. <<StartOfFile:DMAC/SIMv2/DMAC_ARBITER.sv>> module DMAC_ARBITER #( N_MASTER = 4, DATA_SIZE = 32 ) ( input wire clk, input wire rst_n, // _n means active low // configuration registers input wire src_valid_i[N_MASTER], output reg src_ready_o[N_MASTER], input wire [DATA_SIZE-1:0] src_data_i[N_MASTER], output reg dst_valid_o, input wire dst_ready_i, output reg [DATA_SIZE-1:0] dst_data_o ); localparam N_MASTER_LOG2 = clog2(N_MASTER); reg dst_valid, dst_valid_n; reg [DATA_SIZE-1:0] dst_data, dst_data_n; reg [N_MASTER_LOG2-1:0] last_mst, last_mst_n; always_ff @(posedge clk) begin if (~rst_n) begin dst_valid <= 1'b0; dst_data <= 'd0; last_mst <= 'd0; end else begin dst_valid <= dst_valid_n; dst_data <= dst_data_n; last_mst <= last_mst_n; end end // round-robin arbiter always_comb begin dst_valid_n = dst_valid; dst_data_n = dst_data; last_mst_n = last_mst; for (int i=0; i<N_MASTER; i++) begin src_ready_o[i] = 1'b0; end if (!dst_valid | dst_ready_i) begin if (last_mst == 'd0) begin if (src_valid_i[1]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[1]; src_ready_o[1] = 1'b1; last_mst_n = 'd1; end else if (src_valid_i[2]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[2]; src_ready_o[2] = 1'b1; last_mst_n = 'd2; end else if (src_valid_i[3]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[3]; src_ready_o[3] = 1'b1; last_mst_n = 'd3; end else if (src_valid_i[0]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[0]; src_ready_o[0] = 1'b1; last_mst_n = 'd0; end else begin dst_valid_n = 1'b0; end end else if (last_mst == 'd1) begin if (src_valid_i[2]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[2]; src_ready_o[2] = 1'b1; last_mst_n = 'd2; end else if (src_valid_i[3]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[3]; src_ready_o[3] = 1'b1; last_mst_n = 'd3; end else if (src_valid_i[0]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[0]; src_ready_o[0] = 1'b1; last_mst_n = 'd0; end else if (src_valid_i[1]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[1]; src_ready_o[1] = 1'b1; last_mst_n = 'd1; end else begin dst_valid_n = 1'b0; end end else if (last_mst == 'd2) begin if (src_valid_i[3]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[3]; src_ready_o[3] = 1'b1; last_mst_n = 'd3; end else if (src_valid_i[0]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[0]; src_ready_o[0] = 1'b1; last_mst_n = 'd0; end else if (src_valid_i[1]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[1]; src_ready_o[1] = 1'b1; last_mst_n = 'd1; end else if (src_valid_i[2]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[2]; src_ready_o[2] = 1'b1; last_mst_n = 'd2; end else begin dst_valid_n = 1'b0; end end else if (last_mst == 'd3) begin if (src_valid_i[0]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[0]; src_ready_o[0] = 1'b1; last_mst_n = 'd0; end else if (src_valid_i[1]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[1]; src_ready_o[1] = 1'b1; last_mst_n = 'd1; end else if (src_valid_i[2]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[2]; src_ready_o[2] = 1'b1; last_mst_n = 'd2; end else if (src_valid_i[3]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[3]; src_ready_o[3] = 1'b1; last_mst_n = 'd3; end else begin dst_valid_n = 1'b0; end end end end assign dst_valid_o = dst_valid; assign dst_data_o = dst_data; endmodule <<EndOfFile:DMAC/SIMv2/DMAC_ARBITER.sv>> <<StartOfFile:DMAC/RTLv2/DMAC_CFG.sv>> module DMAC_CFG ( input wire clk, input wire rst_n, // _n means active low // AMBA APB interface input wire psel_i, input wire penable_i, input wire [11:0] paddr_i, input wire pwrite_i, input wire [31:0] pwdata_i, output reg pready_o, output reg [31:0] prdata_o, // configuration registers for CH0 output reg [31:0] ch0_src_addr_o, output reg [31:0] ch0_dst_addr_o, output reg [15:0] ch0_byte_len_o, output wire ch0_start_o, input wire ch0_done_i, // configuration registers for CH1 output reg [31:0] ch1_src_addr_o, output reg [31:0] ch1_dst_addr_o, output reg [15:0] ch1_byte_len_o, output wire ch1_start_o, input wire ch1_done_i, // configuration registers for CH2 output reg [31:0] ch2_src_addr_o, output reg [31:0] ch2_dst_addr_o, output reg [15:0] ch2_byte_len_o, output wire ch2_start_o, input wire ch2_done_i, // configuration registers for CH3 output reg [31:0] ch3_src_addr_o, output reg [31:0] ch3_dst_addr_o, output reg [15:0] ch3_byte_len_o, output wire ch3_start_o, input wire ch3_done_i ); // Configuration register for CH0 to read/write reg [31:0] ch0_src_addr; reg [31:0] ch0_dst_addr; reg [15:0] ch0_byte_len; // Configuration register for CH1 to read/write reg [31:0] ch1_src_addr; reg [31:0] ch1_dst_addr; reg [15:0] ch1_byte_len; // Configuration register for CH2 to read/write reg [31:0] ch2_src_addr; reg [31:0] ch2_dst_addr; reg [15:0] ch2_byte_len; // Configuration register for CH3 to read/write reg [31:0] ch3_src_addr; reg [31:0] ch3_dst_addr; reg [15:0] ch3_byte_len; //---------------------------------------------------------- // Write //---------------------------------------------------------- // an APB write occurs when PSEL & PENABLE & PWRITE // clk : __--__--__--__--__--__--__--__--__--__-- // psel : ___--------_____________________________ // penable : _______----_____________________________ // pwrite : ___--------_____________________________ // wren : _______----_____________________________ // // DMA start command must be asserted when APB writes 1 to the DMA_CMD // register // clk : __--__--__--__--__--__--__--__--__--__-- // psel : ___--------_____________________________ // penable : _______----_____________________________ // pwrite : ___--------_____________________________ // paddr : |DMA_CMD| // pwdata : | 1 | // start : _______----_____________________________ wire wren = penable_i & psel_i & pwrite_i; wire start = wren & pwdata_i[0]; always @(posedge clk) begin // Fill // your // code // here if (!rst_n) begin ch0_src_addr <= 'b0; ch0_dst_addr <= 'b0; ch0_byte_len <= 'b0; // ch0_start <= 'b0; ch1_src_addr <= 'b0; ch1_dst_addr <= 'b0; ch1_byte_len <= 'b0; // ch1_start <= 'b0; ch2_src_addr <= 'b0; ch2_dst_addr <= 'b0; ch2_byte_len <= 'b0; // ch2_start <= 'b0; ch3_src_addr <= 'b0; ch3_dst_addr <= 'b0; ch3_byte_len <= 'b0; // ch3_start <= 'b0; end else if (wren) begin if (paddr_i == 'h100) begin ch0_src_addr <= pwdata_i[31:0]; end else if (paddr_i == 'h104) begin ch0_dst_addr <= pwdata_i[31:0]; end else if (paddr_i == 'h108) begin ch0_byte_len <= pwdata_i[15:0]; end else if (paddr_i == 'h200) begin ch1_src_addr <= pwdata_i[31:0]; end else if (paddr_i == 'h204) begin ch1_dst_addr <= pwdata_i[31:0]; end else if (paddr_i == 'h208) begin ch1_byte_len <= pwdata_i[15:0]; end else if (paddr_i == 'h300) begin ch2_src_addr <= pwdata_i[31:0]; end else if (paddr_i == 'h304) begin ch2_dst_addr <= pwdata_i[31:0]; end else if (paddr_i == 'h308) begin ch2_byte_len <= pwdata_i[15:0]; end else if (paddr_i == 'h400) begin ch3_src_addr <= pwdata_i[31:0]; end else if (paddr_i == 'h404) begin ch3_dst_addr <= pwdata_i[31:0]; end else if (paddr_i == 'h408) begin ch3_byte_len <= pwdata_i[15:0]; end end end // Fill your code here (wren, ch0_start, ch1_start...) //---------------------------------------------------------- // READ //---------------------------------------------------------- // an APB read occurs when PSEL & PENABLE & !PWRITE // To make read data a direct output from register, // this code shall buffer the muxed read data into a register // in the SETUP cycle (PSEL & !PENABLE) // clk : __--__--__--__--__--__--__--__--__--__-- // psel : ___--------_____________________________ // penable : _______----_____________________________ // pwrite : ________________________________________ // reg update : ___----_________________________________ // prdata : |DATA reg [31:0] rdata; always @(posedge clk) begin // Fill // your // code // here if (!rst_n) begin rdata <= 'd0; end else if (!penable_i & psel_i & !pwrite_i) begin if (paddr_i == 'h000) begin rdata <= 32'h0002_0101; end else if (paddr_i == 'h100) begin rdata <= ch0_src_addr; end else if (paddr_i == 'h104) begin rdata <= ch0_dst_addr; end else if (paddr_i == 'h108) begin rdata <= {16'b0, ch0_byte_len}; end else if (paddr_i == 'h110) begin rdata <= {31'b0, ch0_done_i}; end else if (paddr_i == 'h200) begin rdata <= ch1_src_addr; end else if (paddr_i == 'h204) begin rdata <= ch1_dst_addr; end else if (paddr_i == 'h208) begin rdata <= {16'b0, ch1_byte_len}; end else if (paddr_i == 'h210) begin rdata <= {31'b0, ch1_done_i}; end else if (paddr_i == 'h300) begin rdata <= ch2_src_addr; end else if (paddr_i == 'h304) begin rdata <= ch2_dst_addr; end else if (paddr_i == 'h308) begin rdata <= {16'b0, ch2_byte_len}; end else if (paddr_i == 'h310) begin rdata <= {31'b0, ch2_done_i}; end else if (paddr_i == 'h400) begin rdata <= ch3_src_addr; end else if (paddr_i == 'h404) begin rdata <= ch3_dst_addr; end else if (paddr_i == 'h408) begin rdata <= {16'b0, ch3_byte_len}; end else if (paddr_i == 'h410) begin rdata <= {31'b0, ch3_done_i}; end else begin rdata <= 'd0; end end end // output assignments assign pready_o = 1'b1; assign prdata_o = rdata; assign ch0_src_addr_o = ch0_src_addr; assign ch0_dst_addr_o = ch0_dst_addr; assign ch0_byte_len_o = ch0_byte_len; assign ch0_start_o = start & (paddr_i=='h10C); assign ch1_src_addr_o = ch1_src_addr; assign ch1_dst_addr_o = ch1_dst_addr; assign ch1_byte_len_o = ch1_byte_len; assign ch1_start_o = start & (paddr_i=='h20C); assign ch2_src_addr_o = ch2_src_addr; assign ch2_dst_addr_o = ch2_dst_addr; assign ch2_byte_len_o = ch2_byte_len; assign ch2_start_o = start & (paddr_i=='h30C); assign ch3_src_addr_o = ch3_src_addr; assign ch3_dst_addr_o = ch3_dst_addr; assign ch3_byte_len_o = ch3_byte_len; assign ch3_start_o = start & (paddr_i=='h40C); endmodule <<EndOfFile:DMAC/RTLv2/DMAC_CFG.sv>> <<StartOfFile:DMAC/RTLv2/DMAC_ENGINE.sv>> module DMAC_ENGINE ( input wire clk, input wire rst_n, // _n means active low // configuration registers input wire [31:0] src_addr_i, input wire [31:0] dst_addr_i, input wire [15:0] byte_len_i, input wire start_i, output wire done_o, // AMBA AXI interface (AW channel) output wire [31:0] awaddr_o, output wire [3:0] awlen_o, output wire [2:0] awsize_o, output wire [1:0] awburst_o, output wire awvalid_o, input wire awready_i, // AMBA AXI interface (W channel) output wire [31:0] wdata_o, output wire [3:0] wstrb_o, output wire wlast_o, output wire wvalid_o, input wire wready_i, // AMBA AXI interface (B channel) input wire [1:0] bresp_i, input wire bvalid_i, output wire bready_o, // AMBA AXI interface (AR channel) output wire [31:0] araddr_o, output wire [3:0] arlen_o, output wire [2:0] arsize_o, output wire [1:0] arburst_o, output wire arvalid_o, input wire arready_i, // AMBA AXI interface (R channel) input wire [31:0] rdata_i, input wire [1:0] rresp_i, input wire rlast_i, input wire rvalid_i, output wire rready_o ); // mnemonics for state values localparam S_IDLE = 3'd0, S_RREQ = 3'd1, S_RDATA = 3'd2, S_WREQ = 3'd3, S_WDATA = 3'd4, S_WAIT = 3'd5; // new state for project 1 reg [2:0] state, state_n; reg [31:0] src_addr, src_addr_n; reg [31:0] dst_addr, dst_addr_n; reg [15:0] cnt, cnt_n; reg [3:0] wcnt, wcnt_n; reg arvalid, rready, awvalid, wvalid, wlast, done; wire fifo_full, fifo_empty; reg fifo_wren, fifo_rden; wire [31:0] fifo_rdata; reg [15:0] outstanding_wr_cnt; reg [15:0] outstanding_wr_cnt_n; // it's desirable to code registers in a simple way always_ff @(posedge clk) if (!rst_n) begin state <= S_IDLE; src_addr <= 32'd0; dst_addr <= 32'd0; cnt <= 16'd0; wcnt <= 4'd0; outstanding_wr_cnt <= 16'd0; end else begin state <= state_n; src_addr <= src_addr_n; dst_addr <= dst_addr_n; cnt <= cnt_n; wcnt <= wcnt_n; outstanding_wr_cnt <= outstanding_wr_cnt_n; end // this block programs output values and next register values // based on states. always_comb begin state_n = state; src_addr_n = src_addr; dst_addr_n = dst_addr; cnt_n = cnt; wcnt_n = wcnt; arvalid = 1'b0; rready = 1'b0; awvalid = 1'b0; wvalid = 1'b0; wlast = 1'b0; done = 1'b0; fifo_wren = 1'b0; fifo_rden = 1'b0; case (state) S_IDLE: begin done = 1'b1; if (start_i & byte_len_i!=16'd0) begin src_addr_n = src_addr_i; dst_addr_n = dst_addr_i; cnt_n = byte_len_i; state_n = S_RREQ; end end S_RREQ: begin arvalid = 1'b1; if (arready_i) begin state_n = S_RDATA; src_addr_n = src_addr + 'd64; end end S_RDATA: begin rready = 1'b1; if (rvalid_i) begin fifo_wren = 1'b1; if (rlast_i) begin state_n = S_WREQ; end end end S_WREQ: begin awvalid = 1'b1; if (awready_i) begin state_n = S_WDATA; dst_addr_n = dst_addr + 'd64; wcnt_n = awlen_o; if (cnt>='d64) begin cnt_n = cnt[15:0] - 32'h4 - (arlen_o<<2); end else begin cnt_n = 'd0; end end end S_WDATA: begin wvalid = 1'b1; wlast = (wcnt==4'd0); if (wready_i) begin fifo_rden = 1'b1; if (wlast) begin if (cnt==16'd0) begin state_n = S_IDLE; end else begin state_n = S_RREQ; end end else begin wcnt_n = wcnt - 4'd1; end end end // FIXME: implement S_WAIT state for project 1 S_WAIT: begin if (outstanding_wr_cnt == 'd0) begin state_n = S_IDLE; end end endcase end // FIXME: implement outstanding_wr_cnt wire outstanding_wr_pp = awready_i & awvalid_o; wire outstanding_wr_mm = bready_o & bvalid_i & (bresp_i == 'd0); always_comb begin outstanding_wr_cnt_n = outstanding_wr_cnt; if (outstanding_wr_pp & !outstanding_wr_mm) begin outstanding_wr_cnt_n = outstanding_wr_cnt + 'd1; end if (!outstanding_wr_pp & outstanding_wr_mm) begin outstanding_wr_cnt_n = outstanding_wr_cnt - 'd1; end end DMAC_FIFO u_fifo ( .clk (clk), .rst_n (rst_n), .full_o (fifo_full), .wren_i (fifo_wren), .wdata_i (rdata_i), .empty_o (fifo_empty), .rden_i (fifo_rden), .rdata_o (fifo_rdata) ); // Output assigments assign done_o = done; assign awaddr_o = dst_addr; assign awlen_o = (cnt >= 'd64) ? 4'hF: cnt[5:2]-4'h1; assign awsize_o = 3'b010; // 4 bytes per transfer assign awburst_o = 2'b01; // incremental assign awvalid_o = awvalid; assign wdata_o = fifo_rdata; assign wstrb_o = 4'b1111; // all bytes within 4 byte are valid assign wlast_o = wlast; assign wvalid_o = wvalid; assign bready_o = 1'b1; assign arvalid_o = arvalid; assign araddr_o = src_addr; assign arlen_o = (cnt >= 'd64) ? 4'hF: cnt[5:2]-4'h1; assign arsize_o = 3'b010; // 4 bytes per transfer assign arburst_o = 2'b01; // incremental assign arvalid_o = arvalid; assign rready_o = rready & !fifo_full; endmodule <<EndOfFile:DMAC/RTLv2/DMAC_ENGINE.sv>> <<StartOfFile:DMAC/RTLv2/DMAC_FIFO.sv>> module DMAC_FIFO #( parameter DEPTH_LG2 = 4, parameter DATA_WIDTH = 32 ) ( input wire clk, input wire rst_n, output wire full_o, input wire wren_i, input wire [DATA_WIDTH-1:0] wdata_i, output wire empty_o, input wire rden_i, output wire [DATA_WIDTH-1:0] rdata_o ); localparam FIFO_DEPTH = (1<<DEPTH_LG2); reg [DATA_WIDTH-1:0] mem[FIFO_DEPTH]; reg full, full_n, empty, empty_n; reg [DEPTH_LG2:0] wrptr, wrptr_n, rdptr, rdptr_n; always_ff @(posedge clk) if (!rst_n) begin for (int i=0; i<FIFO_DEPTH; i++) begin mem[i] <= {DATA_WIDTH{1'b0}}; end end else begin if (wren_i) begin mem[wrptr[DEPTH_LG2-1:0]] <= wdata_i; end end always_ff @(posedge clk) if (!rst_n) begin full <= 1'b0; empty <= 1'b1; // empty after as reset wrptr <= {(DEPTH_LG2+1){1'b0}}; rdptr <= {(DEPTH_LG2+1){1'b0}}; end else begin full <= full_n; empty <= empty_n; wrptr <= wrptr_n; rdptr <= rdptr_n; end always_comb begin wrptr_n = wrptr; rdptr_n = rdptr; if (wren_i) begin wrptr_n = wrptr + 'd1; end if (rden_i) begin rdptr_n = rdptr + 'd1; end empty_n = (wrptr_n == rdptr_n); full_n = (wrptr_n[DEPTH_LG2]!=rdptr_n[DEPTH_LG2]) &(wrptr_n[DEPTH_LG2-1:0]==rdptr_n[DEPTH_LG2-1:0]); end // synthesis translate_off always @(posedge clk) begin if (full_o & wren_i) begin display("FIFO overflow"); @(posedge clk); finish; end end always @(posedge clk) begin if (empty_o & rden_i) begin display("FIFO underflow"); @(posedge clk); finish; end end // synthesis translate_on assign full_o = full; assign empty_o = empty; assign rdata_o = mem[rdptr[DEPTH_LG2-1:0]]; endmodule <<EndOfFile:DMAC/RTLv2/DMAC_FIFO.sv>> <<StartOfFile:DMAC/RTLv2/DMAC_TOP.sv>> module DMAC_TOP ( input wire clk, input wire rst_n, // _n means active low // AMBA APB interface input wire psel_i, input wire penable_i, input wire [11:0] paddr_i, input wire pwrite_i, input wire [31:0] pwdata_i, output reg pready_o, output reg [31:0] prdata_o, output reg pslverr_o, // AMBA AXI interface (AW channel) output wire [3:0] awid_o, output wire [31:0] awaddr_o, output wire [3:0] awlen_o, output wire [2:0] awsize_o, output wire [1:0] awburst_o, output wire awvalid_o, input wire awready_i, // AMBA AXI interface (AW channel) output wire [3:0] wid_o, output wire [31:0] wdata_o, output wire [3:0] wstrb_o, output wire wlast_o, output wire wvalid_o, input wire wready_i, // AMBA AXI interface (B channel) input wire [3:0] bid_i, input wire [1:0] bresp_i, input wire bvalid_i, output wire bready_o, // AMBA AXI interface (AR channel) output wire [3:0] arid_o, output wire [31:0] araddr_o, output wire [3:0] arlen_o, output wire [2:0] arsize_o, output wire [1:0] arburst_o, output wire arvalid_o, input wire arready_i, // AMBA AXI interface (R channel) input wire [3:0] rid_i, input wire [31:0] rdata_i, input wire [1:0] rresp_i, input wire rlast_i, input wire rvalid_i, output wire rready_o ); localparam N_CH = 4; wire [31:0] src_addr_vec[N_CH]; wire [31:0] dst_addr_vec[N_CH]; wire [15:0] byte_len_vec[N_CH]; wire start_vec[N_CH]; wire done_vec[N_CH]; wire [3:0] awid_vec[N_CH]; wire [31:0] awaddr_vec[N_CH]; wire [3:0] awlen_vec[N_CH]; wire [2:0] awsize_vec[N_CH]; wire [1:0] awburst_vec[N_CH]; wire awvalid_vec[N_CH]; wire awready_vec[N_CH]; wire [3:0] wid_vec[N_CH]; wire [31:0] wdata_vec[N_CH]; wire [3:0] wstrb_vec[N_CH]; wire wlast_vec[N_CH]; wire wvalid_vec[N_CH]; wire wready_vec[N_CH]; wire bready_vec[N_CH]; wire [3:0] arid_vec[N_CH]; wire [31:0] araddr_vec[N_CH]; wire [3:0] arlen_vec[N_CH]; wire [2:0] arsize_vec[N_CH]; wire [1:0] arburst_vec[N_CH]; wire arvalid_vec[N_CH]; wire arready_vec[N_CH]; wire rready_vec[N_CH]; DMAC_CFG u_cfg( .clk (clk), .rst_n (rst_n), // AMBA APB interface .psel_i (psel_i), .penable_i (penable_i), .paddr_i (paddr_i), .pwrite_i (pwrite_i), .pwdata_i (pwdata_i), .pready_o (pready_o), .prdata_o (prdata_o), .ch0_src_addr_o (src_addr_vec[0]), .ch0_dst_addr_o (dst_addr_vec[0]), .ch0_byte_len_o (byte_len_vec[0]), .ch0_start_o (start_vec[0]), .ch0_done_i (done_vec[0]), .ch1_src_addr_o (src_addr_vec[1]), .ch1_dst_addr_o (dst_addr_vec[1]), .ch1_byte_len_o (byte_len_vec[1]), .ch1_start_o (start_vec[1]), .ch1_done_i (done_vec[1]), .ch2_src_addr_o (src_addr_vec[2]), .ch2_dst_addr_o (dst_addr_vec[2]), .ch2_byte_len_o (byte_len_vec[2]), .ch2_start_o (start_vec[2]), .ch2_done_i (done_vec[2]), .ch3_src_addr_o (src_addr_vec[3]), .ch3_dst_addr_o (dst_addr_vec[3]), .ch3_byte_len_o (byte_len_vec[3]), .ch3_start_o (start_vec[3]), .ch3_done_i (done_vec[3]) ); assign pslverr_o = 1'b0; DMAC_ARBITER #( .N_MASTER (N_CH), .DATA_SIZE (bits(arid_o)+bits(araddr_o)+bits(arlen_o)+bits(arsize_o)+bits(arburst_o)) ) u_ar_arbiter ( .clk (clk), .rst_n (rst_n), .src_valid_i (arvalid_vec), .src_ready_o (arready_vec), .src_data_i ({ {arid_vec[0], araddr_vec[0], arlen_vec[0], arsize_vec[0], arburst_vec[0]}, {arid_vec[1], araddr_vec[1], arlen_vec[1], arsize_vec[1], arburst_vec[1]}, {arid_vec[2], araddr_vec[2], arlen_vec[2], arsize_vec[2], arburst_vec[2]}, {arid_vec[3], araddr_vec[3], arlen_vec[3], arsize_vec[3], arburst_vec[3]}}), .dst_valid_o (arvalid_o), .dst_ready_i (arready_i), .dst_data_o ({arid_o, araddr_o, arlen_o, arsize_o, arburst_o}) ); DMAC_ARBITER #( .N_MASTER (N_CH), .DATA_SIZE (bits(awid_o)+bits(awaddr_o)+bits(awlen_o)+bits(awsize_o)+bits(awburst_o)) ) u_aw_arbiter ( .clk (clk), .rst_n (rst_n), .src_valid_i (awvalid_vec), .src_ready_o (awready_vec), .src_data_i ({ {awid_vec[0], awaddr_vec[0], awlen_vec[0], awsize_vec[0], awburst_vec[0]}, {awid_vec[1], awaddr_vec[1], awlen_vec[1], awsize_vec[1], awburst_vec[1]}, {awid_vec[2], awaddr_vec[2], awlen_vec[2], awsize_vec[2], awburst_vec[2]}, {awid_vec[3], awaddr_vec[3], awlen_vec[3], awsize_vec[3], awburst_vec[3]}}), .dst_valid_o (awvalid_o), .dst_ready_i (awready_i), .dst_data_o ({awid_o, awaddr_o, awlen_o, awsize_o, awburst_o}) ); DMAC_ARBITER #( .N_MASTER (N_CH), .DATA_SIZE (bits(wid_o)+bits(wdata_o)+bits(wstrb_o)+bits(wlast_o)) ) u_w_arbiter ( .clk (clk), .rst_n (rst_n), .src_valid_i (wvalid_vec), .src_ready_o (wready_vec), .src_data_i ({ {wid_vec[0], wdata_vec[0], wstrb_vec[0], wlast_vec[0]}, {wid_vec[1], wdata_vec[1], wstrb_vec[1], wlast_vec[1]}, {wid_vec[2], wdata_vec[2], wstrb_vec[2], wlast_vec[2]}, {wid_vec[3], wdata_vec[3], wstrb_vec[3], wlast_vec[3]}}), .dst_valid_o (wvalid_o), .dst_ready_i (wready_i), .dst_data_o ({wid_o, wdata_o, wstrb_o, wlast_o}) ); assign bready_o = (bid_i=='d0) ? bready_vec[0] : (bid_i=='d1) ? bready_vec[1] : (bid_i=='d2) ? bready_vec[2] : bready_vec[3]; assign rready_o = (rid_i=='d0) ? rready_vec[0] : (rid_i=='d1) ? rready_vec[1] : (rid_i=='d2) ? rready_vec[2] : rready_vec[3]; genvar ch; generate for (ch=0; ch<N_CH; ch++) begin: channel DMAC_ENGINE u_engine( .clk (clk), .rst_n (rst_n), // configuration registers .src_addr_i (src_addr_vec[ch]), .dst_addr_i (dst_addr_vec[ch]), .byte_len_i (byte_len_vec[ch]), .start_i (start_vec[ch]), .done_o (done_vec[ch]), // AMBA AXI interface (AW channel) .awaddr_o (awaddr_vec[ch]), .awlen_o (awlen_vec[ch]), .awsize_o (awsize_vec[ch]), .awburst_o (awburst_vec[ch]), .awvalid_o (awvalid_vec[ch]), .awready_i (awready_vec[ch]), // AMBA AXI interface (W channel) .wdata_o (wdata_vec[ch]), .wstrb_o (wstrb_vec[ch]), .wlast_o (wlast_vec[ch]), .wvalid_o (wvalid_vec[ch]), .wready_i (wready_vec[ch]), // AMBA AXI interface (B channel) .bresp_i (bresp_i), .bvalid_i (bvalid_i & (bid_i==ch)), .bready_o (bready_vec[ch]), // AMBA AXI interface (AR channel) .araddr_o (araddr_vec[ch]), .arlen_o (arlen_vec[ch]), .arsize_o (arsize_vec[ch]), .arburst_o (arburst_vec[ch]), .arvalid_o (arvalid_vec[ch]), .arready_i (arready_vec[ch]), // AMBA AXI interface (R channel) .rdata_i (rdata_i), .rresp_i (rresp_i), .rlast_i (rlast_i), .rvalid_i (rvalid_i & (rid_i==ch)), .rready_o (rready_vec[ch]) ); assign awid_vec[ch] = ch; assign wid_vec[ch] = ch; assign arid_vec[ch] = ch; end endgenerate endmodule <<EndOfFile:DMAC/RTLv2/DMAC_TOP.sv>> <<StartOfFile:DMAC/SIMv2/TB/DMAC_TOP_TB.sv>> `define IP_VER 32'h000 `define CH_SFR_SIZE 32'h100 `define SRC_OFFSET 32'h0 `define DST_OFFSET 32'h4 `define LEN_OFFSET 32'h8 `define CMD_OFFSET 32'hc `define STAT_OFFSET 32'h10 `define TIMEOUT_DELAY 99999999 `define SRC_REGION_START 32'h0000_0000 `define SRC_REGION_SIZE 32'h0000_2000 `define DST_REGION_STRIDE 32'h0000_2000 `define RANDOM_SEED 12123344 `define TEST_CNT 100 module DMAC_TOP_TB (); // inject random seed initial begin srandom(`RANDOM_SEED); end //---------------------------------------------------------- // clock and reset generation //---------------------------------------------------------- reg clk; reg rst_n; reg [3:0] data1, data2; initial begin data1 = 'b101x; data2 = 'b1010; display("Result: %d %d", data1===data2, data1!==data2); display("Result: %d %d", data1==data2, data1!=data2); data1 = 'b101x; data2 = 'b101x; display("Result: %d", data1===data2); display("Result: %d", data1==data2); end // clock generation initial begin clk = 1'b0; forever #10 clk = !clk; end // reset generation initial begin rst_n = 1'b0; // active at time 0 repeat (3) @(posedge clk); // after 3 cycles, rst_n = 1'b1; // release the reset end // timeout initial begin #`TIMEOUT_DELAY display("Timeout!"); finish; end // enable waveform dump initial begin dumpvars(0, u_DUT); dumpfile("dump.vcd"); end //---------------------------------------------------------- // Connection between DUT and test modules //---------------------------------------------------------- APB apb_if (.clk(clk)); AXI_AW_CH aw_ch (.clk(clk)); AXI_W_CH w_ch (.clk(clk)); AXI_B_CH b_ch (.clk(clk)); AXI_AR_CH ar_ch (.clk(clk)); AXI_R_CH r_ch (.clk(clk)); DMAC_TOP u_DUT ( .clk (clk), .rst_n (rst_n), // APB interface .psel_i (apb_if.psel), .penable_i (apb_if.penable), .paddr_i (apb_if.paddr[11:0]), .pwrite_i (apb_if.pwrite), .pwdata_i (apb_if.pwdata), .pready_o (apb_if.pready), .prdata_o (apb_if.prdata), .pslverr_o (apb_if.pslverr), // AXI AW channel .awid_o (aw_ch.awid), .awaddr_o (aw_ch.awaddr), .awlen_o (aw_ch.awlen), .awsize_o (aw_ch.awsize), .awburst_o (aw_ch.awburst), .awvalid_o (aw_ch.awvalid), .awready_i (aw_ch.awready), // AXI W channel .wid_o (w_ch.wid), .wdata_o (w_ch.wdata), .wstrb_o (w_ch.wstrb), .wlast_o (w_ch.wlast), .wvalid_o (w_ch.wvalid), .wready_i (w_ch.wready), // AXI B channel .bid_i (b_ch.bid), .bresp_i (b_ch.bresp), .bvalid_i (b_ch.bvalid), .bready_o (b_ch.bready), // AXI AR channel .arid_o (ar_ch.arid), .araddr_o (ar_ch.araddr), .arlen_o (ar_ch.arlen), .arsize_o (ar_ch.arsize), .arburst_o (ar_ch.arburst), .arvalid_o (ar_ch.arvalid), .arready_i (ar_ch.arready), // AXI R channel .rid_i (r_ch.rid), .rdata_i (r_ch.rdata), .rresp_i (r_ch.rresp), .rlast_i (r_ch.rlast), .rvalid_i (r_ch.rvalid), .rready_o (r_ch.rready) ); AXI_SLAVE u_mem ( .clk (clk), .rst_n (rst_n), .aw_ch (aw_ch), .w_ch (w_ch), .b_ch (b_ch), .ar_ch (ar_ch), .r_ch (r_ch) ); //---------------------------------------------------------- // Testbench starts //---------------------------------------------------------- task test_init(); int data; apb_if.init(); @(posedge rst_n); // wait for a release of the reset repeat (10) @(posedge clk); // wait another 10 cycles apb_if.read(`IP_VER, data); display("---------------------------------------------------"); display("IP version: %x", data); display("---------------------------------------------------"); display("---------------------------------------------------"); display("Load data to memory"); display("---------------------------------------------------"); for (int i=0; i<`SRC_REGION_SIZE; i=i+4) begin // write random data u_mem.write_word(`SRC_REGION_START+i, random); end endtask // this task must be declared automatic so that each invocation uses // different memories task automatic test_dma(input int ch, input int src, input int dst, input int len); int data; display("Ch[%d] DMA configure %x -> %x (%x)", ch, src, dst, len); apb_if.write((ch+1)*`CH_SFR_SIZE+`SRC_OFFSET, src); apb_if.read((ch+1)*`CH_SFR_SIZE+`SRC_OFFSET, data); if (data!==src) begin display("DMA_SRC[%d](fail): %x", ch, data); @(posedge clk); finish; end apb_if.write((ch+1)*`CH_SFR_SIZE+`DST_OFFSET, dst); apb_if.read((ch+1)*`CH_SFR_SIZE+`DST_OFFSET, data); if (data!==dst) begin display("DMA_DST[%d](fail): %x", ch, data); @(posedge clk); finish; end apb_if.write((ch+1)*`CH_SFR_SIZE+`LEN_OFFSET, len); apb_if.read((ch+1)*`CH_SFR_SIZE+`LEN_OFFSET, data); if (data!==len) begin display("DMA_LEN[%d](fail): %x", ch, data); @(posedge clk); finish; end display("Ch[%d] DMA start", ch); apb_if.write((ch+1)*`CH_SFR_SIZE+`CMD_OFFSET, 32'h1); data = 0; while (data!=1) begin apb_if.read((ch+1)*`CH_SFR_SIZE+`STAT_OFFSET, data); repeat (100) @(posedge clk); display("Ch[%d] Waiting for a DMA completion", ch); end @(posedge clk); display("Ch[%d] DMA completed", ch); for (int i=0; i<len; i=i+4) begin logic [31:0] src_word; logic [31:0] dst_word; src_word = u_mem.read_word(src+i); dst_word = u_mem.read_word(dst+i); if (src_word!==dst_word) begin display("Ch[%d] Mismatch! (src:%x @%x, dst:%x @%x", ch, src_word, src+i, dst_word, dst+i); @(posedge clk); finish; end end display("Ch[%d] DMA passed", ch); endtask // this task must be declared automatic so that each invocation uses // different memories task automatic test_channel(input int ch, input int test_cnt); int src_offset, dst_offset, len; src_offset = 0; dst_offset = 0; for (int i=0; i<test_cnt; i++) begin len = 'h0100; test_dma(ch, `SRC_REGION_START+src_offset, (ch+1)*`DST_REGION_STRIDE+dst_offset, len); src_offset = src_offset + len; dst_offset = dst_offset + len; end endtask // main initial begin test_init(); // run 4 channel tests simultaneously fork test_channel(0, `TEST_CNT); test_channel(1, `TEST_CNT); test_channel(2, `TEST_CNT); test_channel(3, `TEST_CNT); join finish; end endmodule <<EndOfFile:DMAC/SIMv2/TB/DMAC_TOP_TB.sv>> <<StartOfFile:DMAC/SIMv2/TB/AXI_INTF.sv>> `include "../TB/AXI_TYPEDEF.svh" interface AXI_AW_CH #( parameter ADDR_WIDTH = `AXI_ADDR_WIDTH, parameter ID_WIDTH = `AXI_ID_WIDTH ) ( input clk ); logic awvalid; logic awready; logic [ID_WIDTH-1:0] awid; logic [ADDR_WIDTH-1:0] awaddr; logic [3:0] awlen; logic [2:0] awsize; logic [1:0] awburst; endinterface interface AXI_W_CH #( parameter DATA_WIDTH = `AXI_DATA_WIDTH, parameter ID_WIDTH = `AXI_ID_WIDTH ) ( input clk ); logic wvalid; logic wready; logic [ID_WIDTH-1:0] wid; logic [DATA_WIDTH-1:0] wdata; logic [DATA_WIDTH/8-1:0] wstrb; logic wlast; endinterface interface AXI_B_CH #( parameter ID_WIDTH = `AXI_ID_WIDTH ) ( input clk ); logic bvalid; logic bready; logic [ID_WIDTH-1:0] bid; logic [1:0] bresp; endinterface interface AXI_AR_CH #( parameter ADDR_WIDTH = `AXI_ADDR_WIDTH, parameter ID_WIDTH = `AXI_ID_WIDTH ) ( input clk ); logic arvalid; logic arready; logic [ID_WIDTH-1:0] arid; logic [ADDR_WIDTH-1:0] araddr; logic [3:0] arlen; logic [2:0] arsize; logic [1:0] arburst; endinterface interface AXI_R_CH #( parameter DATA_WIDTH = `AXI_DATA_WIDTH, parameter ID_WIDTH = `AXI_ID_WIDTH ) ( input clk ); logic rvalid; logic rready; logic [ID_WIDTH-1:0] rid; logic [DATA_WIDTH-1:0] rdata; logic [1:0] rresp; logic rlast; endinterface interface APB ( input clk ); logic psel; logic penable; logic [31:0] paddr; logic pwrite; logic [31:0] pwdata; logic pready; logic [31:0] prdata; logic pslverr; // a semaphore to allow only one access at a time semaphore sema; initial begin sema = new(1); end modport master ( input clk, input pready, prdata, pslverr, output psel, penable, paddr, pwrite, pwdata ); task init(); psel = 1'b0; penable = 1'b0; paddr = 32'd0; pwrite = 1'b0; pwdata = 32'd0; endtask task automatic write(input int addr, input int data); // during a write, another threads cannot access APB sema.get(1); #1 psel = 1'b1; penable = 1'b0; paddr = addr; pwrite = 1'b1; pwdata = data; @(posedge clk); #1 penable = 1'b1; @(posedge clk); while (pready==1'b0) begin @(posedge clk); end psel = 1'b0; penable = 1'b0; paddr = 'hX; pwrite = 1'bx; pwdata = 'hX; // release the semaphore sema.put(1); endtask task automatic read(input int addr, output int data); // during a read, another threads cannot access APB sema.get(1); #1 psel = 1'b1; penable = 1'b0; paddr = addr; pwrite = 1'b0; pwdata = 'hX; @(posedge clk); #1 penable = 1'b1; @(posedge clk); while (pready==1'b0) begin @(posedge clk); end data = prdata; psel = 1'b0; penable = 1'b0; paddr = 'hX; pwrite = 1'bx; pwdata = 'hX; // release the semaphore sema.put(1); endtask endinterface <<EndOfFile:DMAC/SIMv2/TB/AXI_INTF.sv>> <<StartOfFile:DMAC/SIMv2/TB/AXI_SLAVE.sv>> `include "../TB/AXI_TYPEDEF.svh" module AXI_SLAVE #( parameter ADDR_WIDTH = 16, parameter DATA_WIDTH = `AXI_DATA_WIDTH, parameter ID_WIDTH = `AXI_ID_WIDTH, parameter AWREADY_DELAY = 1, parameter ARREADY_DELAY = 1, parameter AR2R_DELAY = 50 ) ( input wire clk, input wire rst_n, // _n means active low AXI_AW_CH aw_ch, AXI_W_CH w_ch, AXI_B_CH b_ch, AXI_AR_CH ar_ch, AXI_R_CH r_ch ); localparam DATA_DEPTH = 1<<ADDR_WIDTH; logic [7:0] mem[DATA_DEPTH]; function void write_byte(int addr, input bit [7:0] wdata); mem[addr] = wdata; endfunction function void write_word(int addr, input bit [31:0] wdata); for (int i=0; i<4; i++) begin write_byte(addr+i, wdata[8*i +: 8]); // [i*8+7:i*8] end endfunction function bit [7:0] read_byte(int addr); read_byte = mem[addr]; endfunction function bit [31:0] read_word(int addr); for (int i=0; i<4; i++) begin read_word[8*i +: 8] = read_byte(addr+i);// [i*8+7:i*8] end endfunction //---------------------------------------------------------- // write channels (AW, W, B) //---------------------------------------------------------- localparam logic [1:0] S_W_IDLE = 0, S_W_AWREADY = 1, S_W_BURST = 2, S_W_RESP = 3; logic [1:0] wstate, wstate_n; logic [7:0] wcnt, wcnt_n; logic [ADDR_WIDTH-1:0] waddr, waddr_n; logic [ID_WIDTH-1:0] wid, wid_n; logic [3:0] wlen, wlen_n; always_ff @(posedge clk) if (!rst_n) begin wstate <= S_W_IDLE; wcnt <= 8'd0; waddr <= {ADDR_WIDTH{1'b0}}; wid <= {ID_WIDTH{1'b0}}; wlen <= 4'd0; end else begin wstate <= wstate_n; wcnt <= wcnt_n; waddr <= waddr_n; wid <= wid_n; wlen <= wlen_n; end always @(*) begin wstate_n = wstate; wcnt_n = wcnt; waddr_n = waddr; wid_n = wid; wlen_n = wlen; aw_ch.awready = 1'b0; w_ch.wready = 1'b0; b_ch.bvalid = 1'b0; case (wstate) S_W_IDLE: begin if (aw_ch.awvalid) begin if (AWREADY_DELAY == 0) begin waddr_n = aw_ch.awaddr; wid_n = aw_ch.awid; wlen_n = aw_ch.awlen; aw_ch.awready = 1'b1; wstate_n = S_W_BURST; end else begin wcnt_n = AWREADY_DELAY-1; wstate_n = S_W_AWREADY; end end end S_W_AWREADY: begin if (wcnt==0) begin waddr_n = aw_ch.awaddr; wid_n = aw_ch.awid; wlen_n = aw_ch.awlen; aw_ch.awready = 1'b1; wstate_n = S_W_BURST; end else begin wcnt_n = wcnt - 8'd1; end end S_W_BURST: begin w_ch.wready = 1'b1; if (w_ch.wvalid) begin for (int i=0; i<DATA_WIDTH/8; i++) begin write_byte(waddr + i, w_ch.wdata[i*8 +: 8]); // [i*8+7:i*8] end waddr_n = waddr + (DATA_WIDTH/8); if (wlen==4'd0) begin wstate_n = S_W_RESP; end else begin wlen_n = wlen - 4'd1; end end end S_W_RESP: begin b_ch.bvalid = 1'b1; if (b_ch.bready) begin wstate_n = S_W_IDLE; end end endcase end //---------------------------------------------------------- // read channel (AR, R) //---------------------------------------------------------- localparam logic [1:0] S_R_IDLE = 0, S_R_ARREADY = 1, S_R_DELAY = 2, S_R_BURST = 3; logic [1:0] rstate, rstate_n; logic [7:0] rcnt, rcnt_n; logic [ADDR_WIDTH-1:0] raddr, raddr_n; logic [ID_WIDTH-1:0] rid, rid_n; logic [3:0] rlen, rlen_n; always_ff @(posedge clk) if (!rst_n) begin rstate <= S_R_IDLE; rcnt <= 8'd0; raddr <= {ADDR_WIDTH{1'b0}}; rid <= {ID_WIDTH{1'b0}}; rlen <= 4'd0; end else begin rstate <= rstate_n; rcnt <= rcnt_n; raddr <= raddr_n; rid <= rid_n; rlen <= rlen_n; end always_comb begin rstate_n = rstate; rcnt_n = rcnt; raddr_n = raddr; rid_n = rid; rlen_n = rlen; ar_ch.arready = 1'b0; r_ch.rvalid = 1'b0; r_ch.rlast = 1'b0; case (rstate) S_R_IDLE: begin if (ar_ch.arvalid) begin if (ARREADY_DELAY == 0) begin raddr_n = ar_ch.araddr; rid_n = ar_ch.arid; rlen_n = ar_ch.arlen; ar_ch.arready = 1'b1; rcnt_n = AR2R_DELAY - 1; rstate_n = S_R_DELAY; end else begin rcnt_n = ARREADY_DELAY-1; rstate_n = S_R_ARREADY; end end end S_R_ARREADY: begin if (rcnt==0) begin raddr_n = ar_ch.araddr; rid_n = ar_ch.arid; rlen_n = ar_ch.arlen; ar_ch.arready = 1'b1; rcnt_n = AR2R_DELAY - 1; rstate_n = S_R_DELAY; end else begin rcnt_n = rcnt - 8'd1; end end S_R_DELAY: begin if (rcnt==0) begin rstate_n = S_R_BURST; end else begin rcnt_n = rcnt - 8'd1; end end S_R_BURST: begin r_ch.rvalid = 1'b1; r_ch.rlast = (rlen==4'd0); for (int i=0; i<DATA_WIDTH/8; i++) begin r_ch.rdata[i*8 +: 8] = read_byte(raddr + i); // [i*8+7:i*8] end if (r_ch.rready) begin raddr_n = raddr + (DATA_WIDTH/8); if (rlen==4'd0) begin rstate_n = S_R_IDLE; end else begin rlen_n = rlen - 4'd1; end end end endcase end // output assignments assign b_ch.bid = wid; assign b_ch.bresp = 2'd0; assign r_ch.rid = rid; assign r_ch.rresp = 2'd0; endmodule <<EndOfFile:DMAC/SIMv2/TB/AXI_SLAVE.sv>> <<StartOfFile:DMAC/SIMv2/TB/AXI_TYPEDEF.svh>> `ifndef __AXI_TYPEDEF_SVH__ `define __AXI_TYPEDEF_SVH__ `define AXI_ADDR_WIDTH 32 `define AXI_DATA_WIDTH 32 `define AXI_ID_WIDTH 4 `endif /* __AXI_TYPEDEF_SVH__ */ <<EndOfFile:DMAC/SIMv2/TB/AXI_TYPEDEF.svh>>
answer:`N_MASTER`가 4일 때, `N_MASTER_LOG2`의 값은 로그 함수를 사용해 계산할 수 있습니다. `N_MASTER_LOG2`는 `N_MASTER`의 값이 2의 거듭제곱일 때, 해당 2의 거듭제곱수가 몇 번 곱해졌는지를 나타냅니다. 즉, `N_MASTER = 4`이므로 `N_MASTER_LOG2`의 값은 (log_2(4) = 2)가 됩니다. 따라서, `N_MASTER_LOG2`의 값은 2입니다. 그리고 "`[N_MASTER_LOG2-1:0]`"는 두 비트의 범위를 나타내며, 결국 "`[1:0]`"이 됩니다. 이는 2비트 범위를 의미하는데, 값으로는 00부터 11(이진수) 혹은 0부터 3(십진수)까지 가능한 값을 나타낼 수 있습니다. 요약하자면, `N_MASTER`가 4일 때, `N_MASTER_LOG2`는 2이며, "`[N_MASTER_LOG2-1:0]`"는 범위 `[1:0]`을 의미하고, 이는 2비트로 표현할 수 있는 모든 값의 범위입니다.
question:아래 코드를 더 깔끔하게 정리해줄 수 있나요? module DMAC_ARBITER #( N_MASTER = 4, DATA_SIZE = 32 ) ( input wire clk, input wire rst_n, // _n means active low // configuration registers input wire src_valid_i[N_MASTER], output reg src_ready_o[N_MASTER], input wire [DATA_SIZE-1:0] src_data_i[N_MASTER], output reg dst_valid_o, input wire dst_ready_i, output reg [DATA_SIZE-1:0] dst_data_o ); reg dst_valid, dst_valid_n; reg [DATA_SIZE-1:0] dst_data, dst_data_n; always_ff @(posedge clk) if (!rst_n) begin dst_valid <= 1'b0; dst_data <= 'd0; end else begin dst_valid <= dst_valid_n; dst_data <= dst_data_n; end always_comb begin dst_valid_n = dst_valid; dst_data_n = dst_data; for (int i = 0; i < N_MASTER; ++i) begin src_ready_o[i] = 1'b0; end if (!dst_valid | dst_ready_i) begin if (src_valid_i[0]) begin dst_valid_n = 1'b1; src_ready_o[0] = 1'b1; dst_data_n = src_data_i[0]; end else if (src_valid_i[1]) begin dst_valid_n = 1'b1; src_ready_o[1] = 1'b1; dst_data_n = src_data_i[1]; end else if (src_valid_i[2]) begin dst_valid_n = 1'b1; src_ready_o[2] = 1'b1; dst_data_n = src_data_i[2]; end else if (src_valid_i[3]) begin dst_valid_n = 1'b1; src_ready_o[3] = 1'b1; dst_data_n = src_data_i[3]; end else begin dst_valid_n = 1'b0; end end end assign dst_data_o = dst_data; assign dst_valid_o = dst_valid; endmodule
answer:아래는 제시한 코드를 더 간결하고 명확하게 정리한 버전입니다. 코드를 더 간결하게 만들기 위해 몇 가지 기본적인 최적화를 적용했습니다. 1. 불필요한 중복을 줄이고, 2. 루프 내에서의 선택 로직을 단순화하여 가독성을 향상시켰습니다. ```verilog module DMAC_ARBITER #( parameter N_MASTER = 4, parameter DATA_SIZE = 32 ) ( input wire clk, input wire rst_n, // _n means active low // Configuration registers input wire src_valid_i[N_MASTER], output reg src_ready_o[N_MASTER], input wire [DATA_SIZE-1:0] src_data_i[N_MASTER], output reg dst_valid_o, input wire dst_ready_i, output reg [DATA_SIZE-1:0] dst_data_o ); reg [DATA_SIZE-1:0] dst_data; integer i; always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin dst_valid_o <= 1'b0; dst_data_o <= {DATA_SIZE{1'b0}}; end else begin dst_valid_o <= 1'b0; // Default to not valid for (i = 0; i < N_MASTER; i++) begin src_ready_o[i] <= 1'b0; // Default to not ready if (src_valid_i[i] && (!dst_valid_o | dst_ready_i)) begin // Accept the first valid src_data_i dst_valid_o <= 1'b1; dst_data_o <= src_data_i[i]; src_ready_o[i] <= 1'b1; break; // Exit loop after accepting data end end end end endmodule ``` 변경사항 요약: - `dst_valid`과 `dst_data_n` 레지스터가 불필요하게 보여서 삭제하였습니다. 상태 기반의 업데이트가 아닌 즉각적 반응이 필요한 경우에만 내부 상태 변수를 사용하세요. - 반복문 내에서 첫 번째 유효한 소스를 확인하고 데이터를 전달한 뒤 반복문을 종료(`break` 문)합니다. 이는 확인 작업을 빠르게 수행하게 하여 효율성을 증가시킵니다. - 조건부 업데이트를 사용하여 코드를 간소화하였으며, 모든 `src_ready_o`를 기본적으로 0으로 설정하고, 유효한 소스 데이터가 있을 경우에만 해당 채널을 1로 설정합니다. - 상태 업데이트를 위한 별도의 조건부 블록 대신 항상 블록 내에서 직접 업데이트를 처리하여 불필요한 상태 변수 사용을 줄였습니다.
question:아래 코드의 중복 코드를 수정하고 싶다. 방법을 알려주세요. reg dst_valid, dst_valid_n; reg [DATA_SIZE-1:0] dst_data, dst_data_n; always_ff @(posedge clk) if (!rst_n) begin dst_valid <= 1'b0; dst_data <= 'd0; end else begin dst_valid <= dst_valid_n; dst_data <= dst_data_n; end always_comb begin dst_valid_n = dst_valid; dst_data_n = dst_data; for (int i = 0; i < N_MASTER; ++i) begin src_ready_o[i] = 1'b0; end if (!dst_valid | dst_ready_i) begin if (src_valid_i[0]) begin dst_valid_n = 1'b1; src_ready_o[0] = 1'b1; dst_data_n = src_data_i[0]; end else if (src_valid_i[1]) begin dst_valid_n = 1'b1; src_ready_o[1] = 1'b1; dst_data_n = src_data_i[1]; end else if (src_valid_i[2]) begin dst_valid_n = 1'b1; src_ready_o[2] = 1'b1; dst_data_n = src_data_i[2]; end else if (src_valid_i[3]) begin dst_valid_n = 1'b1; src_ready_o[3] = 1'b1; dst_data_n = src_data_i[3]; end else begin dst_valid_n = 1'b0; end end end assign dst_valid_o = dst_valid; assign dst_data_o = dst_data;
answer:중복 코드를 줄이기 위해, 당신이 주목할 수 있는 몇 가지 방법이 있습니다. 특히, 입력 `src_valid_i`를 확인하는 절차에서 반복되는 패턴을 단순화할 수 있습니다. 아래 코드는 이 개선을 보여줍니다: ```verilog reg dst_valid, dst_valid_n; reg [DATA_SIZE-1:0] dst_data, dst_data_n; always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin dst_valid <= 1'b0; dst_data <= 'd0; end else begin dst_valid <= dst_valid_n; dst_data <= dst_data_n; end end always_comb begin dst_valid_n = dst_valid; // Default retain the last state dst_data_n = dst_data; // Default retain the last data for (int i = 0; i < N_MASTER; ++i) begin src_ready_o[i] = 1'b0; // All sources not ready by default } if (!dst_valid || dst_ready_i) begin for (int i = 0; i < N_MASTER; ++i) { if (src_valid_i[i]) { dst_valid_n = 1'b1; dst_data_n = src_data_i[i]; src_ready_o[i] = 1'b1; break; // Once a valid source is found, accept and break } } end end assign dst_valid_o = dst_valid; assign dst_data_o = dst_data; ``` 변경 사항: - `dst_data_n`과 `dst_valid_n`은 필요에 따라 업데이트되고, 이 초기값은 이전 상태나 데이터를 유지하도록 설정되어 있습니다. 이는 불필요한 대입을 줄입니다. - 불필요하게 중복되는 조건을 제거하고, `for` 루프로 모든 마스터를 순회하면서 첫 번째 유효한 소스를 찾습니다. 해당 소스가 발견되면 `dst_data_n`과 `dst_valid_n`을 업데이트하고, 해당 소스의 `src_ready_o`를 세트하며, 루프에서 `break`를 사용하여 탈출합니다. 이는 코드의 반복 부분을 크게 줄여줍니다. - 모든 소스의 `src_ready_o`는 기본적으로 0으로 설정하고, 유효한 소스가 발견되면 해당 채널만 1로 설정합니다. 이 접근 방식은 불필요한 반복을 방지하고, 간결하게 로직을 표현합니다.
question:아래 중복 코드는 깔끔하게 합칠 수 없나? if (!dst_valid | dst_ready_i) begin if (src_valid_i[0]) begin dst_valid_n = 1'b1; src_ready_o[0] = 1'b1; dst_data_n = src_data_i[0]; end else if (src_valid_i[1]) begin dst_valid_n = 1'b1; src_ready_o[1] = 1'b1; dst_data_n = src_data_i[1]; end else if (src_valid_i[2]) begin dst_valid_n = 1'b1; src_ready_o[2] = 1'b1; dst_data_n = src_data_i[2]; end else if (src_valid_i[3]) begin dst_valid_n = 1'b1; src_ready_o[3] = 1'b1; dst_data_n = src_data_i[3]; end else begin dst_valid_n = 1'b0; end end
answer:네, 중복된 코드 조각을 깔끔하게 합치는 것이 가능합니다. 이러한 패턴의 복사 및 붙여넣기를 반복 구조로 전환하여 코드의 길이를 줄이고 유지 보수성을 향상시킬 수 있습니다. 한 가지 방법은 입력 `src_valid_i` 배열을 순회하는 반복문을 사용하는 것입니다. 아래는 그 방법을 적용한 코드 예시입니다: ```verilog if (!dst_valid | dst_ready_i) begin dst_valid_n = 1'b0; // Default to invalid if no valid src found for (int idx = 0; idx < N_MASTER; idx++) begin src_ready_o[idx] = 1'b0; // Initially, none of the sources are ready if (src_valid_i[idx]) begin dst_valid_n = 1'b1; dst_data_n = src_data_i[idx]; src_ready_o[idx] = 1'b1; break; // Exit the loop once a valid src is found end end end ``` 변경 사항을 요약하자면: - 모든 `src_ready_o`를 기본적으로 `0`으로 설정하고, 루프를 시작하기 전에 `dst_valid_n`도 '0'으로 초기화합니다. 이는 루프 실행 전에 기본 상태를 정의합니다. - `N_MASTER`만큼 반복문을 실행하면서 각 `src_valid_i[idx]`를 확인합니다. 유효한 소스를 발견한 경우(`if (src_valid_i[idx])`), `dst_valid_n`을 `1`로 설정하고, `dst_data_n`을 해당 소스의 데이터로 업데이트한 후 해당 소스의 `src_ready_o[idx]`도 `1`로 설정합니다. - 유효한 소스를 찾으면 즉시 반복문에서 `break`를 사용하여 탈출합니다. 이는 성능을 최적화하고 불필요한 반복을 방지합니다. 이 방식을 통해 코드의 중복을 제거하고 가독성을 높이며 유지 보수를 쉽게 만들 수 있습니다.