NVC code coverage report

File:  /__w/ctu-can-regression/ctu-can-regression/test/main_tb/agents/memory_bus_agent/mem_bus_agent.vhd

     0:   -------------------------------------------------------------------------------- 
     1:   -- 
     2:   -- CTU CAN FD IP Core 
     3:   -- Copyright (C) 2021-2023 Ondrej Ille 
     4:   -- Copyright (C) 2023-     Logic Design Services Ltd.s 
     5:   -- 
     6:   -- Permission is hereby granted, free of charge, to any person obtaining a copy 
     7:   -- of this VHDL component and associated documentation files (the "Component"), 
     8:   -- to use, copy, modify, merge, publish, distribute the Component for 
     9:   -- non-commercial purposes. Using the Component for commercial purposes is 
    10:   -- forbidden unless previously agreed with Copyright holder. 
    11:   -- 
    12:   -- The above copyright notice and this permission notice shall be included in 
    13:   -- all copies or substantial portions of the Component. 
    14:   -- 
    15:   -- THE COMPONENT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    16:   -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    17:   -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
    18:   -- AUTHORS OR COPYRIGHTHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
    19:   -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    20:   -- FROM, OUT OF OR IN CONNECTION WITH THE COMPONENT OR THE USE OR OTHER DEALINGS 
    21:   -- IN THE COMPONENT. 
    22:   -- 
    23:   -- The CAN protocol is developed by Robert Bosch GmbH and protected by patents. 
    24:   -- Anybody who wants to implement this IP core on silicon has to obtain a CAN 
    25:   -- protocol license from Bosch. 
    26:   -- 
    27:   -- ------------------------------------------------------------------------------- 
    28:   -- 
    29:   -- CTU CAN FD IP Core 
    30:   -- Copyright (C) 2015-2020 MIT License 
    31:   -- 
    32:   -- Authors: 
    33:   --     Ondrej Ille <ondrej.ille@gmail.com> 
    34:   --     Martin Jerabek <martin.jerabek01@gmail.com> 
    35:   -- 
    36:   -- Project advisors: 
    37:   -- 	Jiri Novak <jnovak@fel.cvut.cz> 
    38:   -- 	Pavel Pisa <pisa@cmp.felk.cvut.cz> 
    39:   -- 
    40:   -- Department of Measurement         (http://meas.fel.cvut.cz/) 
    41:   -- Faculty of Electrical Engineering (http://www.fel.cvut.cz) 
    42:   -- Czech Technical University        (http://www.cvut.cz/) 
    43:   -- 
    44:   -- Permission is hereby granted, free of charge, to any person obtaining a copy 
    45:   -- of this VHDL component and associated documentation files (the "Component"), 
    46:   -- to deal in the Component without restriction, including without limitation 
    47:   -- the rights to use, copy, modify, merge, publish, distribute, sublicense, 
    48:   -- and/or sell copies of the Component, and to permit persons to whom the 
    49:   -- Component is furnished to do so, subject to the following conditions: 
    50:   -- 
    51:   -- The above copyright notice and this permission notice shall be included in 
    52:   -- all copies or substantial portions of the Component. 
    53:   -- 
    54:   -- THE COMPONENT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    55:   -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    56:   -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
    57:   -- AUTHORS OR COPYRIGHTHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
    58:   -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    59:   -- FROM, OUT OF OR IN CONNECTION WITH THE COMPONENT OR THE USE OR OTHER DEALINGS 
    60:   -- IN THE COMPONENT. 
    61:   -- 
    62:   -- The CAN protocol is developed by Robert Bosch GmbH and protected by patents. 
    63:   -- Anybody who wants to implement this IP core on silicon has to obtain a CAN 
    64:   -- protocol license from Bosch. 
    65:   -- 
    66:   -------------------------------------------------------------------------------- 
    67:    
    68:   -------------------------------------------------------------------------------- 
    69:   --  @Purpose: 
    70:   --    Memory bus agent. Configurable over Vunit Communication library. 
    71:   -- 
    72:   --    More on Vunit and its communication library can be found at: 
    73:   ---     https://vunit.github.io/documentation.html 
    74:   --      https://vunit.github.io/com/user_guide.html 
    75:   -- 
    76:   --    Memory bus agent executes accesses on simple RAM-like interface. It 
    77:   --    contains FIFO which buffers the accesses. Following types of accesses are 
    78:   --    supported: 
    79:   --      1. Non-blocking write access 
    80:   --      2. Blocking write access 
    81:   --      3. Read access (always blocking) 
    82:   -- 
    83:   --    This means that it is impossible to post several Read accesses and execute 
    84:   --    them at once, because read always has to return value, therefore its 
    85:   --    transaction must elapse. 
    86:   -- 
    87:   --    Memory bus agent supports two modes: 
    88:   --      normal mode 
    89:   --      X-mode 
    90:   --    In X-mode control signals are driven to X everywhere apart from setup + 
    91:   --    hold within rising edge of clock and read data are sampled with data 
    92:   --    output delay. 
    93:   -- 
    94:   --    Memory Bus agent can be started or stopped via Vunit Communication Library. 
    95:   --    When Memory Bus agent is started, it executes transactions from its 
    96:   --    internal FIFO. When it is stopped, transcations are buffered in FIFO and 
    97:   --    executed once Memory bus agent is started. 
    98:   -- 
    99:   -------------------------------------------------------------------------------- 
   100:   -- Revision History: 
   101:   --    19.1.2020   Created file 
   102:   --    04.2.2021   Adjusted to work without Vunits COM library. 
   103:   -------------------------------------------------------------------------------- 
   104:    
   105:   Library ctu_can_fd_tb; 
   106:   context ctu_can_fd_tb.ieee_context; 
   107:   context ctu_can_fd_tb.tb_common_context; 
   108:    
   109:   use ctu_can_fd_tb.mem_bus_agent_pkg.all; 
   110:   use ctu_can_fd_tb.tb_shared_vars_pkg.all; 
   111:    
   112:    
   113:   entity mem_bus_agent is 
   114:       generic( 
   115:           G_ACCESS_FIFO_DEPTH  : natural := 32; 
   116:           G_NUM_SLAVES         : natural := 2 
   117:       ); 
   118:       port ( 
   119:           -- Clock 
   120:           clk             : in    std_logic; 
   121:    
   122:           -- Memory bus interface 
   123:           scs             : out   std_logic_vector(G_NUM_SLAVES - 1 downto 0) := (OTHERS => '0'); 
   124:           swr             : out   std_logic := 'X'; 
   125:           srd             : out   std_logic := 'X'; 
   126:           sbe             : out   std_logic_vector(3 downto 0) := "XXXX"; 
   127:           write_data      : out   std_logic_vector(31 downto 0) := (others => '0'); 
   128:           read_data       : in    std_logic_vector(31 downto 0); 
   129:           address         : out   std_logic_vector(15 downto 0) := (others => '0') 
   130:       ); 
   131:   end entity; 
   132:    
   133:   architecture tb of mem_bus_agent is 
   134:    
   135:       type t_mem_bus_access_array is array (0 to G_ACCESS_FIFO_DEPTH - 1) 
   136:           of t_mem_bus_access_item; 
   137:    
   138:       signal mem_bus_access_fifo  :   t_mem_bus_access_array; 
   139:       signal fifo_wp              :   integer := 0; 
   140:       signal fifo_rp              :   integer := 0; 
   141:    
   142:       -------------------------------------------------------------------------- 
   143:       -- Configuration parameters 
   144:       --------------------------------------------------------------------------- 
   145:       signal mem_bus_agent_ena    :   boolean := false; 
   146:       signal is_x_mode            :   boolean := true; 
   147:    
   148:       -- Only single setup for all input signals 
   149:       signal x_mode_setup         :   time := 2 ns; 
   150:       signal x_mode_hold          :   time := 1 ns; 
   151:    
   152:       -- Output signal is output data only! 
   153:       signal data_out_delay       :   time := 3 ns; 
   154:    
   155:       signal period               :   time := 10 ns; 
   156:    
   157:       signal read_data_i          :   std_logic_vector(31 downto 0); 
   158:    
   159:       signal scs_i                :   std_logic := '0'; 
   160:    
   161:       -- By default, transactions go to first slave (DUT). This is used in compliance 
   162:       -- tests which only talk to DUT node via Memory bus agent. 
   163:       signal slave_index          :   natural := 0; 
   164:    
   165:       signal last_clk_re          :   time := 0 ns; 
   166:    
   167:       signal trans_report_en      :   boolean := true; 
   168:    
   169:   begin 
   170:    
   171:       -------------------------------------------------------------------------- 
   172:       -- Comunication receiver process 
   173:       --------------------------------------------------------------------------- 
   174:       receiver_proc : process 
   175:           variable cmd            : integer; 
   176:           variable reply_code     : integer; 
   177:           variable transaction    : t_mem_bus_access_item; 
   178:           variable tmp            : std_logic_vector(127 downto 0); 
   179:           variable tmp_int        : integer; 
   180:       begin 
   181:           receive_start(default_channel, C_MEM_BUS_AGENT_ID); 
   182:    
   183:           -- Command is sent as message type 
   184:           cmd := com_channel_data.get_msg_code; 
   185:           reply_code := C_REPLY_CODE_OK; 
   186:    
   187:           case cmd is 
   188:           when MEM_BUS_AGNT_CMD_START => 
   189:               mem_bus_agent_ena <= true; 
   190:           when MEM_BUS_AGNT_CMD_STOP => 
   191:               mem_bus_agent_ena <= false; 
   192:    
   193:           -- For non-blocking writes only post to FIFO, don't wait! 
   194:           when MEM_BUS_AGNT_CMD_WRITE_NON_BLOCKING => 
   195:               transaction.write := true; 
   196:               transaction.address := com_channel_data.get_param; 
   197:               tmp := com_channel_data.get_param; 
   198:               transaction.byte_enable := tmp(3 DOWNTO 0); 
   199:               transaction.write_data := tmp(35 DOWNTO 4); 
   200:    
   201:               mem_bus_access_fifo(fifo_wp) <= transaction; 
   202:               wait for 0 ns; 
   203:               fifo_wp <= (fifo_wp + 1) mod G_ACCESS_FIFO_DEPTH; 
   204:    
   205:           -- For blocking writes wait until FIFO is emptied. This will wait also if 
   206:           -- previous non-blocking transactions were pushed! 
   207:           when MEM_BUS_AGNT_CMD_WRITE_BLOCKING => 
   208:               transaction.write := true; 
   209:               transaction.address := com_channel_data.get_param; 
   210:               tmp := com_channel_data.get_param; 
   211:               transaction.byte_enable := tmp(3 DOWNTO 0); 
   212:               transaction.write_data := tmp(35 DOWNTO 4); 
   213:    
   214:               mem_bus_access_fifo(fifo_wp) <= transaction; 
   215:               wait for 0 ns; 
   216:               fifo_wp <= (fifo_wp + 1) mod G_ACCESS_FIFO_DEPTH; 
   217:               wait for 0 ns; 
   218:    
   219:               wait until (fifo_wp = fifo_rp); 
   220:    
   221:           -- Reads are always blocking 
   222:           when MEM_BUS_AGNT_CMD_READ => 
   223:               transaction.write := false; 
   224:               tmp_int := com_channel_data.get_param; 
   225:               transaction.address := com_channel_data.get_param; 
   226:               tmp := com_channel_data.get_param; 
   227:               transaction.byte_enable := tmp(3 DOWNTO 0); 
   228:    
   229:               mem_bus_access_fifo(fifo_wp) <= transaction; 
   230:               wait for 0 ns; 
   231:               fifo_wp <= (fifo_wp + 1) mod G_ACCESS_FIFO_DEPTH; 
   232:               wait for 0 ns; 
   233:    
   234:               wait until (fifo_wp = fifo_rp); 
   235:               --info_m("Read data when pushing response: " & to_hstring(read_data_i)); 
   236:               com_channel_data.set_param(read_data_i); 
   237:    
   238:           when MEM_BUS_AGNT_CMD_X_MODE_START => 
   239:               is_x_mode <= true; 
   240:    
   241:           when MEM_BUS_AGNT_CMD_X_MODE_STOP => 
   242:               is_x_mode <= false; 
   243:    
   244:           when MEM_BUS_AGNT_CMD_SET_X_MODE_SETUP => 
   245:               x_mode_setup <= com_channel_data.get_param; 
   246:    
   247:           when MEM_BUS_AGNT_CMD_SET_X_MODE_HOLD => 
   248:               x_mode_hold <= com_channel_data.get_param; 
   249:    
   250:           when MEM_BUS_AGNT_CMD_SET_OUTPUT_DELAY => 
   251:               data_out_delay <= com_channel_data.get_param; 
   252:    
   253:           when MEM_BUS_AGNT_CMD_WAIT_DONE => 
   254:               if (fifo_wp /= fifo_rp) then 
   255:                   wait until fifo_wp = fifo_rp; 
   256:               end if; 
   257:    
   258:           when MEM_BUS_AGNT_CMD_SET_SLAVE_INDEX => 
   259:               slave_index <= com_channel_data.get_param; 
   260:               wait for 0 ns; 
   261:    
   262:           when MEM_BUS_AGNT_CMD_ENABLE_TRANS_REPORT => 
   263:               trans_report_en <= true; 
   264:    
   265:           when MEM_BUS_AGNT_CMD_DISABLE_TRANS_REPORT => 
   266:               trans_report_en <= false; 
   267:    
   268:           when others => 
   269:               info_m("Invalid message type: " & integer'image(cmd)); 
   270:               reply_code := C_REPLY_CODE_ERR; 
   271:           end case; 
   272:    
   273:           receive_finish(default_channel, reply_code); 
   274:       end process; 
   275:    
   276:       --------------------------------------------------------------------------- 
   277:       -- Measuring period of input clock (for proper calculation in X mode) 
   278:       --------------------------------------------------------------------------- 
   279:       clk_period_meas_proc : process 
   280:       begin 
   281:           wait until rising_edge(clk); 
   282:           period <= NOW - last_clk_re; 
   283:           last_clk_re <= NOW; 
   284:       end process; 
   285:    
   286:    
   287:       --------------------------------------------------------------------------- 
   288:       -- Memory bus access process 
   289:       --------------------------------------------------------------------------- 
   290:       mem_bus_access_proc : process 
   291:           variable curr_access   : t_mem_bus_access_item; 
   292:    
   293:           procedure print_write_access( 
   294:               variable mem_access    : inout t_mem_bus_access_item 
   295:           ) is 
   296:               variable node_str  : string(1 to 10); 
   297:           begin 
   298:               if (slave_index = 0) then 
   299:                   node_str := "DUT Node  "; 
   300:               else 
   301:                   node_str := "TEST Node "; 
   302:               end if; 
   303:    
   304:               if (trans_report_en) then 
   305:                   info_m(MEM_BUS_AGENT_TAG & "Write to:  " & node_str & 
   306:                       "Address: 0x" & to_hstring(std_logic_vector(to_unsigned(curr_access.address, 32))) & 
   307:                       ", Write Data: 0x" & to_hstring(curr_access.write_data) & 
   308:                       ", Be: " & to_hstring(curr_access.byte_enable) 
   309:                      ); 
   310:               end if; 
   311:           end procedure; 
   312:    
   313:    
   314:           procedure print_read_access( 
   315:               variable mem_access    : inout t_mem_bus_access_item 
   316:           ) is 
   317:               variable node_str  : string(1 to 10); 
   318:           begin 
   319:               if (slave_index = 0) then 
   320:                   node_str := "DUT Node  "; 
   321:               else 
   322:                   node_str := "TEST Node "; 
   323:               end if; 
   324:    
   325:               if (trans_report_en) then 
   326:                   info_m(MEM_BUS_AGENT_TAG & "Read from: " & node_str & 
   327:                       "Address: 0x" & to_hstring(std_logic_vector(to_unsigned(curr_access.address, 32))) & 
   328:                       ", Read Data: 0x" & to_hstring(curr_access.read_data) & 
   329:                       ", Be: " & to_hstring(curr_access.byte_enable) 
   330:                       ); 
   331:               end if; 
   332:           end procedure; 
   333:    
   334:    
   335:    
   336:           procedure drive_access( 
   337:               variable mem_access    : inout t_mem_bus_access_item; 
   338:               signal   read_data_in  : out   std_logic_vector(31 downto 0) 
   339:           ) is 
   340:               variable post_re_time, post_re_time_2   : time; 
   341:           begin 
   342:               -- Chip select can't have Xs, otherwise we get dummy transactions! 
   343:               wait until falling_edge(clk); 
   344:               scs_i <= '1'; 
   345:    
   346:               if (is_x_mode) then 
   347:                   swr <= 'X'; 
   348:                   srd <= 'X'; 
   349:                   write_data <= (OTHERS => 'X'); 
   350:                   sbe <= "XXXX"; 
   351:                   address <= (OTHERS => 'X'); 
   352:                   wait for (period / 2) - x_mode_setup; 
   353:               end if; 
   354:    
   355:               if (mem_access.write) then 
   356:                   swr <= '1'; 
   357:                   srd <= '0'; 
   358:                   write_data <= mem_access.write_data; 
   359:               else 
   360:                   swr <= '0'; 
   361:                   srd <= '1'; 
   362:               end if; 
   363:    
   364:               address <= std_logic_vector(to_unsigned(mem_access.address, address'length)); 
   365:               sbe <= mem_access.byte_enable; 
   366:    
   367:               wait until rising_edge(clk); 
   368:    
   369:               -- If hold time is larger than data output time, first sample output data, 
   370:               -- otherwise first drive X due to end of hold! 
   371:               if (x_mode_hold > data_out_delay) then 
   372:                   post_re_time := data_out_delay; 
   373:                   post_re_time_2 := x_mode_hold - post_re_time; 
   374:               else 
   375:                   post_re_time := x_mode_hold; 
   376:                   post_re_time_2 := data_out_delay - post_re_time; 
   377:               end if; 
   378:    
   379:               if (is_x_mode) then 
   380:                   wait for post_re_time; 
   381:    
   382:                   if (post_re_time = x_mode_hold) then 
   383:                       scs_i <= '0'; 
   384:                       swr <= 'X'; 
   385:                       srd <= 'X'; 
   386:                       write_data <= (OTHERS => 'X'); 
   387:                       sbe <= "XXXX"; 
   388:                       address <= (OTHERS => 'X'); 
   389:                   else 
   390:                       read_data_in <= read_data; 
   391:                       wait for 0 ns; 
   392:                   end if; 
   393:    
   394:                   wait for post_re_time_2; 
   395:    
   396:                   if (post_re_time = x_mode_hold) then 
   397:                       read_data_in <= read_data; 
   398:                   else 
   399:                       scs_i <= '0'; 
   400:                       swr <= 'X'; 
   401:                       srd <= 'X'; 
   402:                       write_data <= (OTHERS => 'X'); 
   403:                       sbe <= "XXXX"; 
   404:                       address <= (OTHERS => 'X'); 
   405:                   end if; 
   406:    
   407:               -- Sample data without waiting, it should be available immediately! 
   408:               else 
   409:                   wait for 1 ps; -- To avoid possible delta cycles 
   410:                   read_data_in <= read_data; 
   411:                   wait for (period / 2) - 2 ps; -- This will end up just before next falling edge! 
   412:                   swr <= '0'; 
   413:                   srd <= '0'; 
   414:                   scs_i <= '0'; 
   415:                   address <= (OTHERS => '0'); 
   416:                   write_data <= (OTHERS => '0'); 
   417:                   sbe <= (OTHERS => '0'); 
   418:               end if; 
   419:           end procedure; 
   420:    
   421:       begin 
   422:           if (mem_bus_agent_ena) then 
   423:               while (true) loop 
   424:                   if (not mem_bus_agent_ena) then 
   425:                       exit; 
   426:                   end if; 
   427:    
   428:                   -- There is something in FIFO -> do memory access 
   429:                   if (fifo_rp /= fifo_wp) then 
   430:                       curr_access := mem_bus_access_fifo(fifo_rp); 
   431:    
   432:                       if (curr_access.write) then 
   433:                           print_write_access(curr_access); 
   434:                       end if; 
   435:                       drive_access(curr_access, read_data_i); 
   436:    
   437:                       wait for 0 ns; 
   438:                       curr_access.read_data := read_data_i; 
   439:                       if (curr_access.write = false) then 
   440:                           print_read_access(curr_access); 
   441:                       end if; 
   442:    
   443:                       fifo_rp <= (fifo_rp + 1) mod G_ACCESS_FIFO_DEPTH; 
   444:                       wait for 0 ns; 
   445:                   else 
   446:                       wait until fifo_rp /= fifo_wp or mem_bus_agent_ena=false; 
   447:                   end if; 
   448:               end loop; 
   449:           else 
   450:               wait until mem_bus_agent_ena; 
   451:           end if; 
   452:       end process; 
   453:    
   454:       --------------------------------------------------------------------------- 
   455:       -- Propagate chip select to slave which is selected 
   456:       --------------------------------------------------------------------------- 
   457:       cs_gen : for i in 0 to G_NUM_SLAVES - 1 generate 
   458:           scs(i) <= scs_i when (slave_index = i) else 
   459:                     '0'; 
   460:       end generate; 
   461:    
   462:   end architecture;