2  * @file x393_tasks01.vh
     4  * @author Andrey Filippov     
     6  * @brief Simulation tasks for the x393 (low level)
     8  * @copyright Copyright (c) 2015 Elphel, Inc.
    12  * x393_tasks01.vh is free software; you can redistribute it and/or modify
    13  * it under the terms of the GNU General Public License as published by
    14  * the Free Software Foundation, either version 3 of the License, or
    15  * (at your option) any later version.
    17  * x393_tasks01.vh is distributed in the hope that it will be useful,
    18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20  * GNU General Public License for more details.
    22  * You should have received a copy of the GNU General Public License
    23  * along with this program.  If not, see <http://www.gnu.org/licenses/> .
    25  * Additional permission under GNU GPL version 3 section 7:
    26  * If you modify this Program, or any covered work, by linking or combining it
    27  * with independent modules provided by the FPGA vendor only (this permission
    28  * does not extend to any 3-rd party modules, "soft cores" or macros) under
    29  * different license terms solely for the purpose of generating binary "bitstream"
    30  * files and/or simulating the code, the copyright holders of this Program give
    31  * you the right to distribute the covered work without those independent modules
    32  * as long as the source code for them is available from the FPGA vendor free of
    33  * charge, and there is no dependence on any encrypted modules for simulating of
    34  * the combined code. This permission applies to you if the distributed code
    35  * contains all the components and scripts required to completely simulate it
    36  * with at least one of the Free Software programs.
    39 // alternative way to check for empty read queue (without a separate counter)
    41     task   write_contol_register;
    42         input [29:0] reg_addr;
    43 //        input integer reg_addr;
    46             axi_write_single_w(CONTROL_ADDR+reg_addr, data);
    50     task   read_contol_register;
    51         input [29:0] reg_addr;
    53             read_and_wait_w(CONTROL_RBACK_ADDR+reg_addr);
    57     task wait_read_queue_empty;
    59         wait (~rvalid && rready && (rid==LAST_ARID)); // nothing left in read queue?   
    82             read_and_wait ({address,2'b0});
    92             while (!MAIN_GO) begin
    98                 address & 32'hfffffffc, // addr
   100                 1     // burst type - increment
   102             GLOBAL_READ_ID <= GLOBAL_READ_ID+1;
   103             wait (!CLK && rvalid && rready);
   105             registered_rdata <= rdata;
   106             wait (!CLK); // registered_rdata should be valid on exit
   115     task axi_write_single_w; // address in dwords
   116         input [29:0] address;
   119 `ifdef DEBUG_WR_SINGLE
   120           $display("axi_write_single_w %h:%h @ %t",address,data,$time);
   122             axi_write_single ({address,2'b0},data);
   126     task axi_write_single; // address in bytes, not words
   127         input [31:0] address;
   131                     GLOBAL_WRITE_ID,    // id
   132 //                    address << 2, // addr
   133                     address & 32'hfffffffc, // addr
   135                     4'h0, // len - single
   136                     1,    // burst type - increment
   141           GLOBAL_WRITE_ID <= GLOBAL_WRITE_ID+1;
   142           #0.1; // without this delay axi_write_addr_data() used old value of GLOBAL_WRITE_ID
   146     task axi_write_addr_data;
   152         input        data_en; // if 0 - do not send data, only address
   158             while (!MAIN_GO) begin
   162             axi_write_addr_data_inner (id, addr, data, len, burst, data_en, wstrb, last);
   179             while (!MAIN_GO) begin
   183             axi_write_data_inner (id, data, wstrb, last);
   192 // Tasks called from ISR
   194     task   read_contol_register_irq;
   195         input  [29:0] reg_addr;
   198             read_and_wait_w_irq(CONTROL_RBACK_ADDR+reg_addr, rslt);
   202  task read_status_irq;
   203     input [STATUS_DEPTH-1:0] address;
   206         read_and_wait_w_irq(STATUS_ADDR + address , rslt);
   210     task read_and_wait_w_irq;
   211         input [29:0] address;
   214             read_and_wait_irq ({address,2'b0},rslt);
   218     task read_and_wait_irq;
   219         input      [31:0] address;
   220         output reg [31:0] rslt;
   223                 GLOBAL_READ_ID,    // id
   224                 address & 32'hfffffffc, // addr
   225                 4'h0, // len - single
   226                 1     // burst type - increment
   228             GLOBAL_READ_ID <= GLOBAL_READ_ID+1;
   229             wait (!CLK && rvalid && rready);
   232             wait (!CLK); // registered_rdata should be valid on exit
   236     task axi_read_addr_irq; // called ferom the main loop, not from interrupts
   244 //            while (!MAIN_GO) begin
   248             axi_read_addr_inner (id, addr, len, burst);
   253     task   write_contol_register_irq;
   254         input [29:0] reg_addr;
   255 //        input integer reg_addr;
   258             axi_write_single_w_irq(CONTROL_ADDR+reg_addr, data);
   262     task axi_write_single_w_irq; // address in dwords
   263         input [29:0] address;
   266 `ifdef DEBUG_WR_SINGLE
   267           $display("axi_write_single_w %h:%h @ %t",address,data,$time);
   269             axi_write_single_irq ({address,2'b0},data);
   273     task axi_write_single_irq; // address in bytes, not words
   274         input [31:0] address;
   277           axi_write_addr_data_irq(
   278                     GLOBAL_WRITE_ID,    // id
   279                     address & 32'hfffffffc, // addr
   281                     4'h0, // len - single
   282                     1,    // burst type - increment
   287           GLOBAL_WRITE_ID <= GLOBAL_WRITE_ID+1;
   288           #0.1; // without this delay axi_write_addr_data() used old value of GLOBAL_WRITE_ID
   292     task axi_write_addr_data_irq;
   298         input        data_en; // if 0 - do not send data, only address
   304 //            while (!MAIN_GO) begin
   308             axi_write_addr_data_inner (id, addr, data, len, burst, data_en, wstrb, last);
   314 // Tasks common for main ind ISR
   316     task axi_write_addr_data_inner;
   322         input        data_en; // if 0 - do not send data, only address
   327 //        assign #(.1) data_sent_d= data_sent;
   329             wait (!CLK && AW_READY);
   333             AWSIZE_IN_r  <= 2'b10;
   334             AWBURST_IN_r <= burst;
   335             AW_SET_CMD_r <= 1'b1;
   336             if (data_en && W_READY) begin
   354             AW_SET_CMD_r <= 1'b0;
   363 // Now sent data if it was not sent simultaneously with the address
   364             if (data_en && !data_sent) begin
   366                 wait (!CLK && W_READY);
   388     task axi_write_data_inner;
   394             wait (!CLK && W_READY);
   411     task axi_read_addr_inner; // regardless of main loop/interrupts
   417             wait (!CLK && AR_READY);
   421             ARSIZE_IN_r  <= 2'b10;
   422             ARBURST_IN_r <= burst;
   423             AR_SET_CMD_r <= 1'b1;
   429             ARBURST_IN_r <= 2'hz;
   430             AR_SET_CMD_r <= 1'b0;
   432             NUM_WORDS_EXPECTED <= NUM_WORDS_EXPECTED+len+1;