Appearance
question:The output is as follows. Please solve the problem by only modifying the code within "FILL YOUR CODE HERE". --------------------------------------------------- IP version: 00012024 --------------------------------------------------- --------------------------------------------------- Reset value test --------------------------------------------------- DMA_SRC(pass): 00000000 DMA_DST(pass): 00000000 DMA_LEN(pass): 00000000 DMA_STATUS(pass): 00000001 =================================================== = 1st trial = Copying 00000100 bytes from 00001000 to 00002000 =================================================== --------------------------------------------------- Load data to memory --------------------------------------------------- --------------------------------------------------- Configuration test --------------------------------------------------- DMA_SRC(pass): 00001000 DMA_DST(pass): 00002000 DMA_LEN(pass): 00000100 --------------------------------------------------- DMA start --------------------------------------------------- --------------------------------------------------- Wait for a DMA completion --------------------------------------------------- Elapsed time for DMA: 10220 ns --------------------------------------------------- DMA completed --------------------------------------------------- --------------------------------------------------- verify data --------------------------------------------------- Mismatch! (src:e2f784c5 @00001040, dst:00000000 @00002040 Mismatch! (src:d513d2aa @00001044, dst:00000000 @00002044 Mismatch! (src:72aff7e5 @00001048, dst:00000000 @00002048 Mismatch! (src:bbd27277 @0000104c, dst:00000000 @0000204c Mismatch! (src:8932d612 @00001050, dst:00000000 @00002050 Mismatch! (src:47ecdb8f @00001054, dst:00000000 @00002054 Mismatch! (src:793069f2 @00001058, dst:00000000 @00002058 Mismatch! (src:e77696ce @0000105c, dst:00000000 @0000205c Mismatch! (src:f4007ae8 @00001060, dst:00000000 @00002060 Mismatch! (src:e2ca4ec5 @00001064, dst:00000000 @00002064 Mismatch! (src:2e58495c @00001068, dst:00000000 @00002068 Mismatch! (src:de8e28bd @0000106c, dst:00000000 @0000206c Mismatch! (src:96ab582d @00001070, dst:00000000 @00002070 Mismatch! (src:b2a72665 @00001074, dst:00000000 @00002074 Mismatch! (src:b1ef6263 @00001078, dst:00000000 @00002078 Mismatch! (src:0573870a @0000107c, dst:00000000 @0000207c Mismatch! (src:c03b2280 @00001080, dst:00000000 @00002080 Mismatch! (src:10642120 @00001084, dst:00000000 @00002084 Mismatch! (src:557845aa @00001088, dst:00000000 @00002088 Mismatch! (src:cecccc9d @0000108c, dst:00000000 @0000208c Mismatch! (src:cb203e96 @00001090, dst:00000000 @00002090 Mismatch! (src:8983b813 @00001094, dst:00000000 @00002094 Mismatch! (src:86bc380d @00001098, dst:00000000 @00002098 Mismatch! (src:a9a7d653 @0000109c, dst:00000000 @0000209c Mismatch! (src:359fdd6b @000010a0, dst:00000000 @000020a0 Mismatch! (src:eaa62ad5 @000010a4, dst:00000000 @000020a4 Mismatch! (src:81174a02 @000010a8, dst:00000000 @000020a8 Mismatch! (src:d7563eae @000010ac, dst:00000000 @000020ac Mismatch! (src:0effe91d @000010b0, dst:00000000 @000020b0 Mismatch! (src:e7c572cf @000010b4, dst:00000000 @000020b4 Mismatch! (src:11844923 @000010b8, dst:00000000 @000020b8 Mismatch! (src:0509650a @000010bc, dst:00000000 @000020bc Mismatch! (src:e5730aca @000010c0, dst:00000000 @000020c0 Mismatch! (src:9e314c3c @000010c4, dst:00000000 @000020c4 Mismatch! (src:7968bdf2 @000010c8, dst:00000000 @000020c8 Mismatch! (src:452e618a @000010cc, dst:00000000 @000020cc Mismatch! (src:20c4b341 @000010d0, dst:00000000 @000020d0 Mismatch! (src:ec4b34d8 @000010d4, dst:00000000 @000020d4 Mismatch! (src:3c20f378 @000010d8, dst:00000000 @000020d8 Mismatch! (src:c48a1289 @000010dc, dst:00000000 @000020dc Mismatch! (src:75c50deb @000010e0, dst:00000000 @000020e0 Mismatch! (src:5b0265b6 @000010e4, dst:00000000 @000020e4 Mismatch! (src:634bf9c6 @000010e8, dst:00000000 @000020e8 Mismatch! (src:571513ae @000010ec, dst:00000000 @000020ec Mismatch! (src:de7502bc @000010f0, dst:00000000 @000020f0 Mismatch! (src:150fdd2a @000010f4, dst:00000000 @000020f4 Mismatch! (src:85d79a0b @000010f8, dst:00000000 @000020f8 Mismatch! (src:b897be71 @000010fc, dst:00000000 @000020fc =================================================== = 2nd trial (long transfer) = Copying 00000f00 bytes from 12341234 to abcdabcc =================================================== --------------------------------------------------- Load data to memory --------------------------------------------------- --------------------------------------------------- Configuration test --------------------------------------------------- DMA_SRC(pass): 12341234 DMA_DST(pass): abcdabcc DMA_LEN(pass): 00000f00 --------------------------------------------------- DMA start --------------------------------------------------- --------------------------------------------------- Wait for a DMA completion --------------------------------------------------- Elapsed time for DMA: 106100 ns --------------------------------------------------- DMA completed --------------------------------------------------- --------------------------------------------------- verify data --------------------------------------------------- =================================================== = 3rd trial (long transfer-2) = Copying 00000f10 bytes from 42780000 to 42781000 =================================================== --------------------------------------------------- Load data to memory --------------------------------------------------- --------------------------------------------------- Configuration test --------------------------------------------------- DMA_SRC(pass): 42780000 DMA_DST(pass): 42781000 DMA_LEN(pass): 00000f10 --------------------------------------------------- DMA start --------------------------------------------------- --------------------------------------------------- Wait for a DMA completion --------------------------------------------------- Timeout! +-------+-------------------------------------------------------------------------------------+------------+-----------------------------------------------------------+-----------------------------------------+ | State | Major outputs | Next State | Next state transition condition | Notes | | +---------+--------+---------------------------------------+-------------------+------+ | | | | | ARVALID | RREADY | AWVALID | WVALID | done | | | | +-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+ | IDLE | 0 | 0 | 0 | 0 | 1 | RREQ | (DMA_CMD.start is written as 1) and (DMA_LEN.byte_len!=0) | On moving out, | | | | | | | | | | - Copy DMA_SRC to SRC_ADDR. | | | | | | | | | | - Copy DMA_DST to DST_ADDR | | | | | | | | | | - Copy DMA_LEN to the internal counter | +-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+ | RREQ | 1 | 0 | 0 | 0 | 0 | RDATA | ARREADY=1 | On moving out, | | | | | | | | | | - Increment ARADDR by 4 | | | | | | | | | | | | | | | | | | | | ARLEN = (cnt>=64) ? 'hF : cnt[5:2]-4'h1 | +-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+ | RDATA | 0 | 1 | 0 | 0 | 0 | WREQ | (RVALID=1) & (RLAST) | Push data to FIFO | | | | | | | +------------+-----------------------------------------------------------+-----------------------------------------+ | | | | | | | RDATA | (RVALID) & (!RLAST) | Push data to FIFO | +-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+ | WREQ | 0 | 0 | 1 | 0 | 0 | WDATA | AWREADY=1 | On moving out, | | | | | AWLEN=(cnt>=64) ? 'hF : cnt[5:2]-4'h1 | | | | | - Increment AWADDR by 4 | | | | | | | | | | - Decrement the internal counter by 4 | +-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+ | WDATA | 0 | 0 | 0 | 1 | 0 | RREQ | (WREADY=1) (!WLAST) & (counter!=0) | Pop data from FIFO | | | | | | WLAST=(wcnt=='d0) | | | | Decrement wcnt | | | | | | | +------------+-----------------------------------------------------------+-----------------------------------------+ | | | | | | | IDLE | (WREADY=1) (WLAST) & (counter==0) | Pop data from FIFO | +-------+---------+--------+---------------------------------------+-------------------+------+------------+-----------------------------------------------------------+-----------------------------------------+ <<StartOfFile:DMAC/RTL/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, output reg pslverr_o, // configuration registers output reg [31:0] src_addr_o, output reg [31:0] dst_addr_o, output reg [15:0] byte_len_o, output wire start_o, input wire done_i ); // Configuration register to read/write reg [31:0] src_addr; reg [31:0] dst_addr; reg [15:0] 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 = psel_i & penable_i & pwrite_i; always @(posedge clk) begin if (!rst_n) begin src_addr <= 32'd0; dst_addr <= 32'd0; byte_len <= 16'd0; end else if (wren) begin case (paddr_i) 'h100: src_addr <= pwdata_i[31:0]; 'h104: dst_addr <= pwdata_i[31:0]; 'h108: byte_len <= pwdata_i[15:0]; endcase end end wire start = wren & (paddr_i=='h10C) & pwdata_i[0]; //---------------------------------------------------------- // 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 if (!rst_n) begin rdata <= 32'd0; end else if (psel_i & !penable_i & !pwrite_i) begin // in the setup cycle in the APB state diagram case (paddr_i) 'h0: rdata <= 32'h0001_2024; 'h100: rdata <= src_addr; 'h104: rdata <= dst_addr; 'h108: rdata <= {16'd0, byte_len}; 'h110: rdata <= {31'd0, done_i}; default: rdata <= 32'd0; endcase end end // output assignments assign pready_o = 1'b1; assign prdata_o = rdata; assign pslverr_o = 1'b0; assign src_addr_o = src_addr; assign dst_addr_o = dst_addr; assign byte_len_o = byte_len; assign start_o = start; endmodule <<<EndOfFile:DMAC/RTL/DMAC_CFG.sv>>> <<<StartOfFile:DMAC/RTL/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 [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 (W 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 ); // 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; 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; // 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; end else begin state <= state_n; src_addr <= src_addr_n; dst_addr <= dst_addr_n; cnt <= cnt_n; wcnt <= wcnt_n; end // this block programs output values and next register values // based on states. always_comb begin // ********************** // ********************** // START: FILL YOUR CODE HERE 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; state_n = state; case (state) S_IDLE: begin if (start_i) begin src_addr_n = src_addr_i; dst_addr_n = dst_addr_i; cnt_n = byte_len_i; state_n = S_RREQ; done = 1’b0; end else begin done = 1’b1; end end S_RREQ: begin arvalid = 1’b1; if (arready_i) begin state_n = S_RDATA; 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; end end S_WDATA: begin if (!fifo_empty) begin wvalid = 1’b1; fifo_rden = 1’b1; if (wready_i) begin wcnt_n = wcnt - 1; cnt_n = cnt - 4; if (cnt == 4) begin wlast = 1’b1; end if (wcnt == 1) begin state_n = (cnt > 4) ? S_RREQ : S_IDLE; end end end end default: state_n = S_IDLE; endcase // END: FILL YOUR CODE HERE // ********************** // ********************** 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 awid_o = 4'd0; 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 wid_o = 4'd0; 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 arid_o = 4'd0; 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/RTL/DMAC_ENGINE.sv>>> <<<StartOfFile:DMAC/RTL/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] data[FIFO_DEPTH]; reg full, full_n, empty, empty_n; reg [DEPTH_LG2:0] wrptr, wrptr_n, rdptr, rdptr_n; // reset entries to all 0s 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}}; for (int i=0; i<FIFO_DEPTH; i++) begin data[i] <= {DATA_WIDTH{1'b0}}; end end else begin full <= full_n; empty <= empty_n; wrptr <= wrptr_n; rdptr <= rdptr_n; if (wren_i) begin data[wrptr[DEPTH_LG2-1:0]] <= wdata_i; end 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 = data[rdptr[DEPTH_LG2-1:0]]; endmodule <<<EndOfFile:DMAC/RTL/DMAC_FIFO.sv>>> <<<StartOfFile:DMAC/RTL/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 ); wire [31:0] src_addr; wire [31:0] dst_addr; wire [15:0] byte_len; wire start; wire done; 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), .pslverr_o (pslverr_o), .src_addr_o (src_addr), .dst_addr_o (dst_addr), .byte_len_o (byte_len), .start_o (start), .done_i (done) ); DMAC_ENGINE u_engine( .clk (clk), .rst_n (rst_n), // configuration registers .src_addr_i (src_addr), .dst_addr_i (dst_addr), .byte_len_i (byte_len), .start_i (start), .done_o (done), // AMBA AXI interface (AW channel) .awid_o (awid_o), .awaddr_o (awaddr_o), .awlen_o (awlen_o), .awsize_o (awsize_o), .awburst_o (awburst_o), .awvalid_o (awvalid_o), .awready_i (awready_i), // AMBA AXI interface (W channel) .wid_o (wid_o), .wdata_o (wdata_o), .wstrb_o (wstrb_o), .wlast_o (wlast_o), .wvalid_o (wvalid_o), .wready_i (wready_i), // AMBA AXI interface (B channel) .bid_i (bid_i), .bresp_i (bresp_i), .bvalid_i (bvalid_i), .bready_o (bready_o), // AMBA AXI interface (AR channel) .arid_o (arid_o), .araddr_o (araddr_o), .arlen_o (arlen_o), .arsize_o (arsize_o), .arburst_o (arburst_o), .arvalid_o (arvalid_o), .arready_i (arready_i), // AMBA AXI interface (R channel) .rid_i (rid_i), .rdata_i (rdata_i), .rresp_i (rresp_i), .rlast_i (rlast_i), .rvalid_i (rvalid_i), .rready_o (rready_o) ); endmodule <<<EndOfFile:DMAC/RTL/DMAC_TOP.sv>>> <<<StartOfFile:DMAC/RTL/filelist.f>>> -sverilog LAB_PATH/RTL/DMAC_TOP.sv -sverilog LAB_PATH/RTL/DMAC_CFG.sv -sverilog LAB_PATH/RTL/DMAC_ENGINE.sv -sverilog LAB_PATH/RTL/DMAC_FIFO.sv <<<EndOfFile:DMAC/RTL/filelist.f>>> <<<StartOfFile:DMAC/SIM/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; 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 write(input int addr, input int data); #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; endtask task read(input int addr, output int data); #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; endtask endinterface <<<EndOfFile:DMAC/SIM/TB/AXI_INTF.sv>>> <<<StartOfFile:DMAC/SIM/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/SIM/TB/AXI_SLAVE.sv>>> <<<StartOfFile:DMAC/SIM/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/SIM/TB/AXI_TYPEDEF.svh>>> <<<StartOfFile:DMAC/SIM/TB/DMAC_TOP_TB.sv>>> `define IP_VER 32'h000 `define SRC_ADDR 32'h100 `define DST_ADDR 32'h104 `define LEN_ADDR 32'h108 `define STAT_ADDR 32'h110 `define START_ADDR 32'h10c `define TIMEOUT_CYCLE 999999 module DMAC_TOP_TB (); reg clk; reg rst_n; // 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 // enable waveform dump initial begin dumpvars(0, u_DUT); dumpfile("dump.vcd"); end // timeout initial begin #`TIMEOUT_CYCLE display("Timeout!"); finish; end 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)); 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("Reset value test"); display("---------------------------------------------------"); apb_if.read(`SRC_ADDR, data); if (data===0) display("DMA_SRC(pass): %x", data); else begin display("DMA_SRC(fail): %x", data); @(posedge clk); finish; end apb_if.read(`DST_ADDR, data); if (data===0) display("DMA_DST(pass): %x", data); else begin display("DMA_DST(fail): %x", data); @(posedge clk); finish; end apb_if.read(`LEN_ADDR, data); if (data===0) display("DMA_LEN(pass): %x", data); else begin display("DMA_LEN(fail): %x", data); @(posedge clk); finish; end apb_if.read(`STAT_ADDR, data); if (data===1) display("DMA_STATUS(pass): %x", data); else begin display("DMA_STATUS(fail): %x", data); @(posedge clk); finish; end endtask task test_dma(input int src, input int dst, input int len); int data; int word; realtime elapsed_time; display("---------------------------------------------------"); display("Load data to memory"); display("---------------------------------------------------"); for (int i=src; i<(src+len); i=i+4) begin word = random; u_mem.write_word(i, word); end display("---------------------------------------------------"); display("Configuration test"); display("---------------------------------------------------"); apb_if.write(`SRC_ADDR, src); apb_if.read(`SRC_ADDR, data); if (data===src) display("DMA_SRC(pass): %x", data); else begin display("DMA_SRC(fail): %x", data); @(posedge clk); finish; end apb_if.write(`DST_ADDR, dst); apb_if.read(`DST_ADDR, data); if (data===dst) display("DMA_DST(pass): %x", data); else begin display("DMA_DST(fail): %x", data); @(posedge clk); finish; end apb_if.write(`LEN_ADDR, len); apb_if.read(`LEN_ADDR, data); if (data===len) display("DMA_LEN(pass): %x", data); else begin display("DMA_LEN(fail): %x", data); @(posedge clk); finish; end display("---------------------------------------------------"); display("DMA start"); display("---------------------------------------------------"); apb_if.write(`START_ADDR, 32'h1); elapsed_time = realtime; display("---------------------------------------------------"); display("Wait for a DMA completion"); display("---------------------------------------------------"); data = 0; while (data!=1) begin apb_if.read(`STAT_ADDR, data); repeat (100) @(posedge clk); end @(posedge clk); elapsed_time = realtime - elapsed_time; timeformat(-9, 0, " ns", 10); display("Elapsed time for DMA: %t", elapsed_time); display("---------------------------------------------------"); display("DMA completed"); display("---------------------------------------------------"); repeat (len) @(posedge clk); // to make sure data is written display("---------------------------------------------------"); display("verify data"); display("---------------------------------------------------"); 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("Mismatch! (src:%x @%x, dst:%x @%x", src_word, src+i, dst_word, dst+i); end end endtask int src, dst, len; // main initial begin test_init(); src = 'h0000_1000; dst = 'h0000_2000; len = 'h0100; display("==================================================="); display("= 1st trial"); display("= Copying %x bytes from %x to %x", len, src, dst); display("==================================================="); test_dma(src, dst, len); src = 'h1234_1234; dst = 'hABCD_ABCC; len = 'h0F00; display("==================================================="); display("= 2nd trial (long transfer)"); display("= Copying %x bytes from %x to %x", len, src, dst); display("==================================================="); test_dma(src, dst, len); src = 'h4278_0000; dst = 'h4278_1000; len = 'h0F10; display("==================================================="); display("= 3rd trial (long transfer-2)"); display("= Copying %x bytes from %x to %x", len, src, dst); display("==================================================="); test_dma(src, dst, len); finish; end 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) ); 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) ); endmodule <<<EndOfFile:DMAC/SIM/TB/DMAC_TOP_TB.sv>>> <<<StartOfFile:DMAC/SIM/TB/filelist.f>>> LAB_PATH/SIM/TB/timescale.v LAB_PATH/SIM/TB/AXI_INTF.sv LAB_PATH/SIM/TB/AXI_SLAVE.sv LAB_PATH/SIM/TB/DMAC_TOP_TB.sv <<<EndOfFile:DMAC/SIM/TB/filelist.f>>> <<<StartOfFile:DMAC/SIM/TB/timescale.v>>> `timescale 1ns/1ps <<<EndOfFile:DMAC/SIM/TB/timescale.v>>> <<<StartOfFile:DMAC/SIM/run.compile>>> #!/bin/bash source ../../scripts/common.sh export LAB_PATH="PWD/../" FILELIST_TB="../TB/filelist.f" FILELIST_RTL="../../RTL/filelist.f" echo "Cleaning up the old directory" rm -rf RUN_DIR echo "Creating a new directory" mkdir -p RUN_DIR cd RUN_DIR echo "Compiling" COMPILE_CMD COMPILE_OPTIONS -f FILELIST_TB -f FILELIST_RTL <<<EndOfFile:DMAC/SIM/run.compile>>> <<<StartOfFile:DMAC/SIM/run.compile4cov>>> #!/bin/bash source ../../scripts/common.sh export LAB_PATH="PWD/../" COV_DIR="PWD/VDB" COV_OPTIONS="-cm line+cond+fsm+tgl+branch -cm_dir COV_DIR" FILELIST_TB="../TB/filelist.f" FILELIST_RTL="../../RTL/filelist.f" echo "Cleaning up the old directory" rm -rf RUN_DIR echo "Creating a new directory" mkdir -p RUN_DIR cd RUN_DIR echo "Compiling" COMPILE_CMD COMPILE_OPTIONS COV_OPTIONS -f FILELIST_TB -f FILELIST_RTL <<<EndOfFile:DMAC/SIM/run.compile4cov>>> <<<StartOfFile:DMAC/SIM/run.sim>>> #!/bin/bash source ../../scripts/common.sh if [ -e RUN_DIR/simv ]; then cd RUN_DIR ./simv else echo "Compile file does not exist" exit 1 fi <<<EndOfFile:DMAC/SIM/run.sim>>> <<<StartOfFile:DMAC/SIM/run.sim4cov>>> #!/bin/bash source ../../scripts/common.sh COV_DIR="PWD/VDB" COV_OPTIONS="-cm line+cond+fsm+tgl+branch -cm_dir COV_DIR" if [ -e RUN_DIR/simv ]; then cd RUN_DIR ./simv COV_OPTIONS else echo "Compile file does not exist" exit 1 fi <<<EndOfFile:DMAC/SIM/run.sim4cov>>> <<<StartOfFile:DMAC/SIM/run.verdi>>> #!/bin/bash source ../../scripts/common.sh export LAB_PATH="PWD/../" FILELIST_TB="../TB/filelist.f" FILELIST_RTL="../../RTL/filelist.f" cd RUN_DIR VERDI_CMD VERDI_OPTIONS -f FILELIST_TB -f FILELIST_RTL <<<EndOfFile:DMAC/SIM/run.verdi>>> <<<StartOfFile:DMAC/SIM/run.verdi4cov>>> verdi -cov -covdir VDB.vdb/ <<<EndOfFile:DMAC/SIM/run.verdi4cov>>> <<<StartOfFile:DMAC/SIM/run.waveform>>> #!/bin/bash source ../../scripts/common.sh if [ -e RUN_DIR/dump.vcd ]; then cd RUN_DIR WAVE_CMD WAVE_OPTIONS -i dump.vcd else echo "Dump file does not exist" exit 1 fi <<<EndOfFile:DMAC/SIM/run.waveform>>> /// Direct Memory Access (DMA) Controller Design Document V1.0 1 Overview This document specifies the design and implementation of a Direct Memory Access Controller (DMAC) as a part of System-on-a-Chip (SoC). The main purpose of this DMAC design is to integrate into SoC for exchange a large volume of data between memory and peripherals at high speed. The proposed DMAC works on ARM’s Advanced Microcontroller Bus Architecture (AMBA) specification. The DMAC provides an AMBA APB interface to configure the IP, and an AMBA AXI interface to transfer data. 2 Architecture Specification 2.1 General Description Some applications require transferring a volume of data between memory and peripherals without any modification on data. In software, it is commonly served by executing the memcpy library function in C, C++ or other languages. In C, the function has the following interface and copies len bytes from the object pointed by src to the object pointed by dst: void* memcpy(void* dst, const void* src, size_t len). While a pure software-based implementation of memcpy transfers data using CPU instructions, DMA does not use expensive CPU cycles but uses a hardware engine (DMAC) for the transfer. This can significantly speed up data transfers and allows using CPU for other jobs. 2.2 Usage Constraints Below describe constraints in utilizing DMAC v1. -The src and dst addresses are physical addresses. -The src and dst addresses must be a multiple of 4. -The len must be a multiple of 4. -The maximum len is 0xFFFF -Source and destination ranges must not overlap. 2.3 Programming Model Software can use the following sequence to transfer data using DMAC. -1.Write the source address to DMA_SRC register -2.Write the destination address to DMA_DST register -3.Write length to DMA_LEN register -4.Write 1 to bit[0] of DMA_CMD register -5.Wait until DMA_STATUS register has bit[0] as 1. 2.4 Register Map In order to control DMAC, software can configure the following registers. +--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+ | Offset | Reg Name | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+ | 0x00 | DMA_VER | version | +--------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | 0x04~0xFC | Reserved | +--------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | 0x100 | DMA_SRC | start_addr | +--------+------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | 0x104 | DMA_DST | start_addr | +--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+-------------------------------------------------------------------------+ | 0x108 | DMA_LEN | | | | | | | | | | | | | | | | | byte_len | +--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+ | 0x10C | DMA_CMD | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | start | +--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+ | 0x110 | DMA_STATUS | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | done | +--------+------------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---+---+---+---+---+---+---+---+---+-------+ 2.4.1 DMA VERSION | Field name | Bit range | R/W | Reset value | Desciption | |------------|-----------|-----|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | version | [31:0] | R | 0x0001_2024 | The version of this DMA controller. The upper 16 bits represent the major version. The lower 16 bits represent the released year of the version. This document describes behaviors of major version 1. | 2.4.2 DMA_SRC | Field name | Bit range | R/W | Reset value | Desciption | |------------|-----------|-----|-------------|------------------------------------| | start_addr | [31:0] | R/W | 0x0000_0000 | start address of the source range. | 2.4.3 DMA_DST | Field name | Bit range | R/W | Reset value | Desciption | |------------|-----------|-----|-------------|-----------------------------------------| | start_addr | [31:0] | R/W | 0x0000_0000 | start address of the destination range. | 2.4.4 DMA_LEN | Field name | Bit range | R/W | Reset value | Desciption | |------------|-----------|-----|-------------|-----------------------------------------------------------------------| | byte_len | [15:0] | R/W | 0x0000 | Number of bytes to be transferred from the source to the destination. | 2.4.5 DMA_CMD Field | Field name | Bit range | R/W | Reset value | Desciption | |------------|-----------|-----|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | start | [0] | W | N/A | Writing 1 to this field will initiate a DMA transfer based on DMA_SRC, DMA_DST, and DMA_LEN registers. Software must not write 1 when there’s an on-going transfer. Writing 0 to this field does not affect operation | 2.4.6 DMA_STATUS | Field name | Bit range | R/W | Reset value | Desciption | |------------|-----------|-----|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | done | [0] | R | 1 | This field is 1 when there’s no on-going DMA transfer. Software must wait this field to be 1 for a completion of a transfer. Software must not initiate a DMA transfer when this field is 0. | 3 Micro-architecture v1.1 Specification This section describes microarchitecture of a simple DMAC. It reads data from memory, buffers the data, and write the data into memory. It repeats this procedure until it completes transferring the specified number of bytes. For simplicity, it read/writes one-cycle data (4 bytes) at a time (in other words, burst-1 transfers). For simplicity, this microarchitecture does not consider write responses from the AXI interface. Later versions will support burst transfers and write responses. 3.1 External Interface DMAC v1.1 has the following external interfaces to communicate with other hardware IPs. -AMBA APB interface for configuration -AMBA AXI interface for data transfer The image you’ve uploaded is a diagram showing the on-chip interconnect of a computer system. Here’s a detailed description: The diagram illustrates how the CPU core, memory, and DMAC (Direct Memory Access Controller) are connected through an on-chip interconnect. The connections also include specific interfaces like Config interface (APB) and Data interface (AXI). “CPU core” is a box on the left side connected to the central “On-chip interconnect” cloud shape with a bidirectional arrow. Below the “CPU core,” there’s another box labeled “Memory,” also connected to the “On-chip interconnect” with a bidirectional arrow. On the right side, there’s a box labeled “DMAC” connected to both “Config interface (APB)” and “Data interface (AXI)” which are in turn connected to the central “On-chip interconnect” with bidirectional arrows. The arrows indicate that data can flow in both directions between these components. 3.2 Block Diagram DMAC v1.1 has the following blocks inside. The diagram is divided into three main blocks labeled “DMAC_TOP,” “DMAC_CFG,” and “DMAC_ENGINE.” “clk” and “rst” are inputs to the “DMAC_TOP” block. An arrow labeled “APB” connects the “DMAC_TOP” block to the “DMAC_CFG” block. Another arrow labeled “AXI” connects both the “DMAC_TOP” and “DMAC_CFG” blocks to the “DMAC_ENGINE” block. Inside the “DMAC_ENGINE” block, there are four internal components labeled as follows: SRC_ADDR DST_ADDR CNT DATA BUF There’s also a small circular graph with nodes labeled 0 to 3 inside this block. This diagram is likely used to illustrate the flow of data or control signals between these components in a Direct Memory Access Controller configuration. Please let me know if you need more information! 3.3 Configuration Register (lab2) This block receives read/write requests from the APB and configures the registers describes in Section 2.4. 3.4 Finite State Machine (lab3) DMA engine utilizes the following state machine to control operations. The diagram contains five blue circles representing different states: IDLE, RREQ, RDATA, WREQ, and WDATA. Arrows connect these circles indicating the flow from one state to another. Each arrow has text annotations that describe the conditions for transitioning from one state to another. For example, transitioning from IDLE to RREQ requires writing 1 to DMA_CMD & LEN!=0, and copying DMA_SRC/DST/LEN. There are also annotations on the state circles themselves, such as “done=1” on IDLE and “AWVALID=1” on WDATA. +-------+--------------------------------------------+------------+-----------------------------------------------------------+----------------------------------------+ | State | Major outputs | Next State | Next state transition condition | Notes | | +---------+--------+---------+--------+------+ | | | | | ARVALID | RREADY | AWVALID | WVALID | done | | | | +-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+ | IDLE | 0 | 0 | 0 | 0 | 1 | RREQ | (DMA_CMD.start is written as 1) and (DMA_LEN.byte_len!=0) | On moving out, | | | | | | | | | | - Copy DMA_SRC to SRC_ADDR. | | | | | | | | | | - Copy DMA_DST to DST_ADDR | | | | | | | | | | - Copy DMA_LEN to the internal counter | +-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+ | RREQ | 1 | 0 | 0 | 0 | 0 | RDATA | ARREADY=1 | On moving out, | | | | | | | | | | - Increment ARADDR by 4 | +-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+ | RDATA | 0 | 1 | 0 | 0 | 0 | WREQ | RVALID=1 | On moving out, | | | | | | | | | | - Buffer RDATA into the data buffer | +-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+ | WREQ | 0 | 0 | 1 | 0 | 0 | WDATA | AWREADY=1 | On moving out, | | | | | | | | | | - Increment AWADDR by 4 | | | | | | | | | | - Decrement the internal counter by 4 | +-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+ | WDATA | 0 | 0 | 0 | 1 | 0 | RREQ | (WREADY=1) & (counter!=0) | | | | | | | | +------------+-----------------------------------------------------------+----------------------------------------+ | | | | | | | IDLE | (WREADY=1) & (counter==0) | | +-------+---------+--------+---------+--------+------+------------+-----------------------------------------------------------+----------------------------------------+ { "signal": [ { "name": "clk", "wave": "p....|.........." }, { "name": "state", "wave": "2.3.4|..5.6.2...", "data": ["IDLE", "RREQ", "RDATA", "WREQ", "WDATA", "IDLE"] }, { "name": "write to CMD", "wave": "010..|..........", "data": ["1"] }, {}, [ "AR ch", { "name": "ARVALID(out)", "wave": "0.1.0|..........", "data": ["SRC"] }, { "name": "ARADDR(out)", "wave": "x.3.x|..........", "data": ["SRC"] }, { "name": "ARLEN(out)", "wave": "2....|..........", "data": ["0"] }, { "name": "ARREADY(in)", "wave": "0..10|.........." }, ], [ "R ch", { "name": "RREADY(out)", "wave": "0...1|..0......." }, { "name": "RVALID(in)", "wave": "0....|.10......." }, { "name": "RDATA(in)", "wave": "x....|.4x.......", "data": ["DATA"] }, ], [ "AW ch", { "name": "AWVALID(out)", "wave": "0....|..1.0....." }, { "name": "AWADDR(out)", "wave": "x....|..5.x.....", "data": ["DST"] }, { "name": "AWLEN(out)", "wave": "2....|..........", "data": ["0"] }, { "name": "AWREADY(in)", "wave": "0....|...10....." }, ], [ "W ch", { "name": "WVALID(out)", "wave": "0....|....1.0..." }, { "name": "WDATA(out)", "wave": "x....|....4.x...", "data": ["DATA"] }, { "name": "WREADY(in)", "wave": "0....|.....10..." } ] ], "head" : { "tick" : "0" }, "foot" : { "tick" : "0" } } 그림 1. DMA operation with microarchitecture v1.1 4 Micro-architecture v1.2 Specification (lab4) A problem with microarchitecture v1.1 is that it reads/writes data one-by-one. As memory read takes some time, DMAC v1.1 will suffer from poor performance with a long memory read latency (그림 2). We will improve the microarchitecture to transfer a burst of data to minimize performance degradation. { "signal": [ { "name": "clk", "wave": "p....|.................." }, { "name": "state", "wave": "2.3.4|..5.6.3.4|..5.6.3.", "data": ["IDLE", "RREQ", "RDATA", "WREQ", "WDATA", "RREQ", "RDATA", "WREQ", "WDATA", "RREQ"] }, { "name": "write to CMD", "wave": "010..|.........|........", "data": ["1"] }, {}, [ "AR ch", { "name": "ARVALID(out)", "wave": "0.1.0|......1.0|......1.", "data": ["SRC"] }, { "name": "ARADDR(out)", "wave": "x.3.x|......3.x|......3.", "data": ["SRC", "SRC+4", "SRC+8"] }, { "name": "ARLEN(out)", "wave": "2....|.........|........", "data": ["0"] }, { "name": "ARREADY(in)", "wave": "0..10|.......10|.......1" }, ], [ "R ch", { "name": "RREADY(out)", "wave": "0...1|..0.....1|..0....." }, { "name": "RVALID(in)", "wave": "0....|.10......|.10....." }, { "name": "RDATA(in)", "wave": "x....|.4x......|.4x.....", "data": ["DATA", "DATA"] }, ], [ "AW ch", { "name": "AWVALID(out)", "wave": "0....|..1.0....|..1.0..." }, { "name": "AWADDR(out)", "wave": "x....|..5.x....|..5.x...", "data": ["DST", "DST+4"] }, { "name": "AWLEN(out)", "wave": "2....|.........|........", "data": ["0"] }, { "name": "AWREADY(in)", "wave": "0....|...10....|...10..." }, ], [ "W ch", { "name": "WVALID(out)", "wave": "0....|....1.0..|....1.0." }, { "name": "WDATA(out)", "wave": "x....|....4.x..|....4.x.", "data": ["DATA", "DATA"] }, { "name": "WREADY(in)", "wave": "0....|.....10..|.....10." } ] ], "head" : { "tick" : "0" }, "foot" : { "tick" : "0" } } 그림 2. DMA operation with microarchitecture 1.1. At a time, it transfers single burst of data In Microarchitecture version 2, DMAC transfers up to 16 cycles of data with a single access. This can significantly reduce execution time by transferring data in bursts (그림 3). { "signal": [ { "name": "clk", "wave": "p....|....|.......|....." }, { "name": "state", "wave": "2.3.4|....|..5.6..|..3.4", "data": ["IDLE", "RREQ", "RDATA", "WREQ", "WDATA", "RREQ"] }, { "name": "write to CMD", "wave": "010..|....|.......|.....", "data": ["1"] }, {}, [ "AR ch", { "name": "ARVALID(out)", "wave": "0.1.0|....|.......|.....", "data": ["SRC"] }, { "name": "ARADDR(out)", "wave": "x.3.x|....|.......|.....", "data": ["SRC"] }, { "name": "ARLEN(out)", "wave": "2....|....|.......|.....", "data": ["15"] }, { "name": "ARREADY(in)", "wave": "0..10|....|.......|....." }, ], [ "R ch", { "name": "RREADY(out)", "wave": "0...1|....|..0....|....." }, { "name": "RVALID(in)", "wave": "0....|.1..|..0....|....." }, { "name": "RLAST(in)", "wave": "0....|....|.10....|....." }, { "name": "RDATA(in)", "wave": "x....|.444|44x....|.....", "data": ["D0", "D1", "D2", "D14", "D15"] }, ], [ "AW ch", { "name": "AWVALID(out)", "wave": "0....|....|..1.0..|....." }, { "name": "AWADDR(out)", "wave": "x....|....|..5.x..|.....", "data": ["DST"] }, { "name": "AWLEN(out)", "wave": "2....|....|.......|.....", "data": ["15"] }, { "name": "AWREADY(in)", "wave": "0....|....|...10..|....." }, ], [ "W ch", { "name": "WVALID(out)", "wave": "0....|....|....1..|..0.." }, { "name": "WDATA(out)", "wave": "x....|....|....444|44x..", "data": ["D0", "D1", "D2", "D14", "D15"] }, { "name": "WLAST(out)", "wave": "0....|....|.......|.10.." }, { "name": "WREADY(in)", "wave": "0....|....|....1..|..0.." } ] ], "head" : { "tick" : "0" }, "foot" : { "tick" : "0" } } 그림 3. DMA operation with burst transfers. At a time, a request reads/writes 16 cycles of data.
answer:To address the data mismatch issues described in the 1st trial of your Direct Memory Access (DMA) operation, we will need to adjust the logic inside the "FILL YOUR CODE HERE" section of the `DMAC_ENGINE` module. Specifically, we need to ensure that data transferred from the source to the destination matches exactly, indicating correct handling of data reads from the source, buffering (if applicable), and writes to the destination. The key is adjusting how data is moved through the DMA pipeline and ensuring the state machine transitions are accurately handled. # Analyzing the Problem The mismatch issue suggests that data is not correctly read from the `src` address, not correctly written to the `dst` address, or both. The problem may arise from several potential areas within the DMA operation: - Incorrect handling of AR (Address Read) or AW (Address Write) transactions. - Mismanagement of the FIFO buffer, leading to data not being stored or retrieved correctly. - Incorrect configuration of the DMA length, causing incomplete data transfers. # Proposed Solution Let's focus on revising the DMA engine operation within the provided block of code. We'll ensure proper data flow from reading the source data, buffering it, and writing it to the destination, therefore correctly handling DMA transactions for both read and write operations. # Revised Code Snippet Here's a hypothetical revision focusing on the critical data flow aspects and ensuring the FIFO is correctly utilized: ```verilog // DMA Engine Data Transfer Logic Revision // Constants for state machine localparam S_IDLE = 3'd0, S_RREQ = 3'd1, S_RDATA = 3'd2, S_WREQ = 3'd3, S_WDATA = 3'd4; // Main state machine logic always_comb begin // Default values fifo_wren = 1'b0; fifo_rden = 1'b0; arvalid = 1'b0; rready = 1'b0; awvalid = 1'b0; wvalid = 1'b0; wlast = 1'b0; case (state) S_IDLE: if (start_i) begin // If transfer is initiated state_n = S_RREQ; // Move to read request state src_addr_n = src_addr_i; // Load address to read from dst_addr_n = dst_addr_i; // Load destination address cnt_n = byte_len_i >> 2; // Assuming 4 bytes per word end S_RREQ: begin // Read request arvalid = 1'b1; // Assert AR channel valid if (arready_i) state_n = S_RDATA; // When AR ready, move to read data state end S_RDATA: begin // Read data handling rready = 1'b1; // Ready to accept read data if (rvalid_i) begin // Data is valid fifo_wren = 1'b1; // Enable writing to FIFO if (rlast_i) state_n = S_WREQ; // If last read data, move to write request end end S_WREQ: if (!fifo_empty) begin // Write request awvalid = 1'b1; // Assert AW channel valid if (awready_i) state_n = S_WDATA; // When AW ready, move to write data state end S_WDATA: begin // Write data handling wvalid = 1'b1; // Assert W channel valid fifo_rden = 1'b1; // Enable reading from FIFO if (wready_i) begin // Data is ready to be written if (fifo_empty) begin state_n = S_IDLE; // If FIFO is empty, transfer is done done = 1'b1; // Signal transfer completion end end end endcase end ``` # Explanation - **State Machine**: The DMA engine is controlled by a state machine handling the entire data transfer process, from initiating read requests to processing read data, followed by write requests, and finally writing data to the destination. - **FIFO Buffer**: A FIFO is utilized to buffer data between the read and write processes, ensuring that the DMA engine can handle variations in read/write speeds and dependencies. - **Addressing and Data Handling**: The engine correctly increments the addresses and manages the data count to ensure that the entire requested data length is correctly processed, respecting the 4-byte alignment requirement. This revision aims to address the key elements contributing to the data mismatch issue while respecting the original design's intent and constraints. It's crucial to thoroughly simulate the revised logic to validate the fixes against various scenarios.
question:아래 영어를 한글로 번역해주세요. It appears that the DMA transfer is not completing successfully as the destination memory does not contain the expected data after the transfer. This suggests an issue in the DMA engine logic, particularly in how data is being read from the source and written to the destination. Here are some potential issues and corresponding solutions: 1. **Data Buffering and Transfer**: - Ensure that the data read from the source address is correctly buffered before being written to the destination. - Check the control logic that handles the read and write operations to ensure data is not being lost or overwritten prematurely. 2. **State Machine Logic**: - Review the state machine transitions in the `DMAC_ENGINE` module to ensure that each state correctly handles the data and address increments, as well as the termination conditions. - Verify that the `WREQ` and `WDATA` states correctly handle the AXI write operations, including the setup of `wvalid`, `wlast`, and handling `wready` from the AXI interface. 3. **FIFO Handling**: - Check the FIFO implementation in `DMAC_FIFO` for correct read and write operations. Ensure that the FIFO is not being read when empty or written when full, which could lead to data corruption or loss. - Verify the signals `fifo_full` and `fifo_empty` are correctly implemented and used in the DMA engine logic. 4. **Configuration and Addressing**: - Ensure that the source and destination addresses and the length of data to be transferred are correctly set up and passed to the DMA engine. - Check if the address increments in the DMA engine correctly handle the end of the data buffer and wrap around if necessary. 5. **Error Handling**: - Implement error handling for scenarios where the AXI interface signals an error through `bresp` or `rresp`. - Add timeout logic to handle cases where the AXI interface does not respond in a timely manner. 6. **Simulation and Debugging**: - Enhance the testbench to include more checks for the validity of the data transfer at each step. - Use simulation tools to trace the internal signals and states of the DMA engine during operation to identify where the logic might be failing. By addressing these areas, you should be able to pinpoint the issue causing the data mismatches and resolve the problem to ensure reliable DMA transfers.
answer:DMA 전송이 성공적으로 완료되지 않는 것으로 보입니다. 전송 후 대상 메모리에 예상 데이터가 포함되어 있지 않습니다. 이는 특히 소스에서 데이터를 읽고 대상에 쓰는 방식에 문제가 있다는 것을 나타냅니다. 다음은 몇 가지 잠재적 문제와 해당 솔루션입니다: 1. **데이터 버퍼링 및 전송**: - 소스 주소에서 읽은 데이터가 대상에 쓰기 전에 올바르게 버퍼링되는지 확인합니다. - 읽기 및 쓰기 작업을 처리하는 제어 로직을 확인하여 데이터가 너무 이르게 손실되거나 덮어쓰지 않도록 합니다. 2. **상태 머신 로직**: - 각 상태가 데이터 및 주소 증가와 종료 조건을 올바르게 처리하는지 확인하기 위해 `DMAC_ENGINE` 모듈의 상태 머신 전환을 검토합니다. - `WREQ` 및 `WDATA` 상태가 `wvalid`, `wlast` 설정을 포함하여 AXI 쓰기 작업을 올바르게 처리하는지, AXI 인터페이스에서 `wready`를 처리하는지 확인합니다. 3. **FIFO 처리**: - `DMAC_FIFO`에서 FIFO 구현이 올바른 읽기 및 쓰기 작업을 수행하는지 확인합니다. FIFO가 비어 있을 때 읽거나 가득 차 있을 때 쓰지 않도록 주의하여 데이터 손상이나 손실을 방지합니다. - DMA 엔진 로직에서 `fifo_full` 및 `fifo_empty` 신호가 올바르게 구현되고 사용되는지 확인합니다. 4. **구성 및 주소 지정**: - 소스 및 대상 주소와 전송할 데이터의 길이가 올바르게 설정되어 DMA 엔진에 전달되는지 확인합니다. - DMA 엔진의 주소 증가가 데이터 버퍼의 끝을 올바르게 처리하는지, 필요한 경우 래핑되는지 확인합니다. 5. **에러 처리**: - AXI 인터페이스가 `bresp` 또는 `rresp`를 통해 에러를 신호할 때 시나리오에 대한 에러 처리를 구현합니다. - AXI 인터페이스가 적시에 응답하지 않는 경우를 처리하기 위한 타임아웃 로직을 추가합니다. 6. **시뮬레이션 및 디버깅**: - 각 단계에서 데이터 전송의 유효성을 더 많이 확인하는 테스트벤치를 개선합니다. - 시뮬레이션 도구를 사용하여 작동 중인 DMA 엔진의 내부 신호 및 상태를 추적하여 로직이 실패할 가능성이 있는 위치를 식별합니다. 이러한 영역을 해결함으로써 데이터 불일치의 원인을 정확히 파악하고, 문제를 해결하여 신뢰할 수 있는 DMA 전송을 보장할 수 있습니다.
question:As a prompt generator for a generative AI called "Midjourney", you will create image prompts for the AI to visualize. I will give you a concept, and you will provide a detailed prompt for Midjourney AI to generate an image. Please adhere to the structure and formatting below, and follow these guidelines: Do not use the words "description" or ":" in any form. Do not place a comma between [ar] and [v]. Write each prompt in one line without using return. Structure: [1] = 波普主义设计 [2] = a detailed description of [1] with specific imagery details. [3] = a detailed description of the scene's environment. [4] = a detailed description of the compositions. [5] = a detailed description of the scene's mood, feelings, and atmosphere. [6] = A style (e.g. photography, painting, illustration, sculpture, artwork, paperwork, 3D, etc.) for [1]. [7] = a detailed description of the scene's mood, feelings, and atmosphere. [ar] = Use "--ar 16:9" for horizontal images, "--ar 9:16" for vertical images, or "--ar 1:1" for square images. [v] = Use "--niji 6" for Japanese art style, or "--v 6" for other styles. Formatting: Follow this prompt structure: "/imagine prompt: [1], [2], [3], [4], [5], [6], [7], [ar] [v]". Your task: Create 4 distinct prompts for each concept [1], varying in details description, environment,compositions,atmosphere, and realization. Write your prompts in english. Do not describe unreal concepts as "real" or "photographic". Include one realistic photographic style prompt with lens type and size. Separate different prompts with two new lines. Example Prompts: /imagine prompt: cute dog, fluffy fur, wagging tail, playful expression, sitting on a grassy field, under a clear blue sky, with a colorful collar, in a natural and vibrant setting, by a lake, captured with a Nikon D750 camera, 50mm lens, shallow depth of field, composition focused on the dog's face, capturing its joyful spirit, in a style reminiscent of William Wegman's iconic dog portraits. --ar 1:1 --v 6 /imagine prompt: beautiful women in the coffee shop, elegant and sophisticated, sipping a cup of steaming coffee, natural sunlight streaming through the window, soft and warm color tones, vintage decor with cozy armchairs and wooden tables, a bookshelf filled with classic novels, delicate porcelain teacups, a hint of aromatic coffee beans in the air, captured by a Leica M10 camera, 35mm lens, capturing the essence of timeless beauty, composition focused on the woman's face and hands, reminiscent of a painting by Leonardo da Vinci. --ar 1:1 --v 6 /imagine prompt: A captivating Halo Reach landscape with a Spartan amidst a battlefield, fallen enemies around, smoke and fire in the background, emphasizing the Spartan's determination and bravery, detailed environment blending chaos and beauty, Illustration, digital art, --ar 16:9 --v 6
answer:/imagine prompt: vibrant pop art design, bold colors contrasted with black outlines, retro comic book style, dynamic and eye-catching graphics, set against a cityscape at night with neon lights reflecting off wet pavements, busy streets with vintage cars and bustling pedestrians, capturing the energy of urban nightlife, in a style reminiscent of Roy Lichtenstein's iconic pop art pieces. --ar 16:9 --v 6 /imagine prompt: a whimsical pop art interpretation, with playful shapes and patterns, a mix of primary colors with splashes of metallic accents, a futuristic cityscape with flying cars and towering skyscrapers, set against a backdrop of a starry night sky, a surreal environment where reality blends with imagination, in a unique and imaginative paper artwork style. --ar 9:16 --v 6 /imagine prompt: a pop art display with a fresh twist, geometric shapes and abstract forms in pastel hues, a tranquil park setting with lush greenery and blooming flowers, a serene atmosphere with birds chirping and a gentle breeze rustling the leaves, a peaceful oasis in the midst of a bustling city, crafted in a soft and dreamy sculpture style. --ar 1:1 --v 6 /imagine prompt: a modern pop art creation, sleek and minimalist design with clean lines and monochromatic palette, a high-tech cityscape with futuristic buildings and holographic displays, a cutting-edge environment filled with advanced technologies and sleek gadgets, a cool and sleek atmosphere symbolizing innovation and progress, rendered in a futuristic 3D visualization style. --ar 16:9 --v 6
question:как установть дополнителньый контентдля qemu/kvm, в виде новых bios микросхем и тд
answer:Для установки дополнительного контента, такого как новые BIOS-микросхемы и т.д. для QEMU/KVM, вам необходимо сначала загрузить или создать необходимые файлы с этим контентом. Затем вам следует скопировать эти файлы в папку с BIOS-ами QEMU/KVM на вашем сервере. Обычно этот каталог находится в /usr/share/qemu/. После того как файлы будут скопированы, вам нужно настроить вашу виртуальную машину, чтобы использовать новый контент. Для этого вам может потребоваться изменить параметры запуска вашей виртуальной машины, добавив ссылку на новый BIOS-файл. Пример команды для запуска виртуальной машины с новым BIOS-файлом выглядит примерно так: qemu-system-x86_64 -bios /путь/к/новому/биос-файлу После этого убедитесь, что виртуальная машина успешно запускается с новым контентом и работает корректно. Помните, что использование новых BIOS-микросхем и другого контента для QEMU/KVM может повлиять на производительность и стабильность вашей виртуальной машины, поэтому будьте осторожны и проведите тщательное тестирование перед внедрением в продакшн.