NVC code coverage report

File:  /__w/ctu-can-regression/ctu-can-regression/test/main_tb/agents/can_agent/can_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:   --    CAN 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:   --    CAN Bus agent is connected to can_tx and can_rx signals of DUT. It drives 
    77:   --    can_rx via driver and it monitors_can_tx via monitor. 
    78:   -- 
    79:   --    Driver contains FIFO of items to be driven. Each item contains value and 
    80:   --    a time for which to drive the value. When driving of 1 item finishes it 
    81:   --    is immediately followed by next one until driver FIFO is empty. Driver 
    82:   --    can be started by a command over Communication library (this is intended 
    83:   --    for sending frame by CAN agent), or simultaneously with Monitor (this is 
    84:   --    intended for receiving frame by CAN Agent from DUT). 
    85:   -- 
    86:   --    Monitor contains a FIFO of items to be monitored. Each item contains 
    87:   --    value, time and sample period for which to monitor the value. When 
    88:   --    Monitoring of 1 item finishes, it is immediately followed by next one 
    89:   --    until monitor FIFO is empty. Monitor does not check for the value 
    90:   --    constantly, but it samples can_tx output with configurable sampling 
    91:   --    period. If monitored value is not equal to expected value when it is 
    92:   --    sampled, internal mismatch counter is incremented and warning is printed. 
    93:   -- 
    94:   --    Monitor can be in one of five states: "Idle", "Waiting for Trigger", 
    95:   --    "Running", "Passed" and "Failed". When it is "Idle", no monitoring is 
    96:   --    progress. When it is started via communication library, it moves to 
    97:   --    "Waiting for Trigger". In this state it waits until trigger event occurs 
    98:   --    (Type of trigger event is also configurable over Communication library) 
    99:   --    and moves to "Running". When it is running, it monitors items from Monitor 
   100:   --    FIFO one after another. After all items were monitored, monitor transfers to 
   101:   --    "Passed" when no mismatch between can_tx and monitored values occured 
   102:   --    during monitoring. Otherwise it transfers to failed. 
   103:   -- 
   104:   --    Trigger functionality of monitor is a way how to synchronize its operation 
   105:   --    with driver. Monitor can be configured to start at the same time as 
   106:   --    driver starts. 
   107:   -- 
   108:   --    When Monitor operation starts its internal error counter is erased. When 
   109:   --    its ends, succesfull monitoring (no errors) can be checked via 
   110:   --    Communication library. 
   111:   -- 
   112:   ------------------------------------------------------------------------------- 
   113:   --    MONITORING of an ITEM (examples): 
   114:   -- 
   115:   --    Lets suppose that monitor is about to monitor logic 1 for 100 ns with 
   116:   --    sample period of 20 ns. Following figure shows where can_tx will be 
   117:   --    checked: 
   118:   -- 
   119:   --               _______________________________________________________ 
   120:   --  can_tx  _____|                                                      |____ 
   121:   -- 
   122:   --  Check:                 O           O           O           O 
   123:   --               |         |           |           |           |        | 
   124:   --              0ns       20ns        40ns        60 ns       80ns     100ns 
   125:   -- 
   126:   --  Note that monitor will NOT execute check of can_tx less than sample_time 
   127:   --  after start of monitoring item, and less than sample time before the end of 
   128:   --  monitoring of an item! This behaviour is intentional! 
   129:   -- 
   130:   --  The intention is, to set sample time to value of Time Quanta. This allows 
   131:   --  checking with granularity of time quanta. 
   132:   -- 
   133:   --  When DUT is configured e.g with BRP = 4, and Driver is not synchronized 
   134:   --  with DUT, then shift between Driver and DUT can up to 1 TQ! Therefore, the 
   135:   --  value of edge coming from DUT can be floating in range between 0 ns and 
   136:   --  1 TQ! (DUT does not operate on lower granularity than time quanta). 
   137:   -- 
   138:   ------------------------------------------------------------------------------- 
   139:   --    API for work with CAN agent is implemented in "can_agent_pkg" package. 
   140:   -- 
   141:   -------------------------------------------------------------------------------- 
   142:   -- Revision History: 
   143:   --    25.1.2020   Created file 
   144:   --    04.2.2021   Adjusted to work without Vunits COM library. 
   145:   -------------------------------------------------------------------------------- 
   146:    
   147:   Library ctu_can_fd_tb; 
   148:   context ctu_can_fd_tb.ieee_context; 
   149:   context ctu_can_fd_tb.tb_common_context; 
   150:    
   151:   use ctu_can_fd_tb.can_agent_pkg.all; 
   152:   use ctu_can_fd_tb.tb_shared_vars_pkg.all; 
   153:    
   154:   entity can_agent is 
   155:       generic( 
   156:           G_DRIVER_FIFO_DEPTH : natural := 128; 
   157:           G_MONITOR_FIFO_DEPTH : natural := 128 
   158:       ); 
   159:       port ( 
   160:           -- CAN bus connections 
   161:           can_tx   :   in     std_logic; 
   162:           can_rx   :   out    std_logic := '1' 
   163:       ); 
   164:   end entity; 
   165:    
   166:   architecture tb of can_agent is 
   167:    
   168:       type t_driver_fifo_mem is array (0 to G_DRIVER_FIFO_DEPTH - 1) of 
   169:           t_can_driver_entry; 
   170:    
   171:       type t_monitor_fifo_mem is array (0 to G_MONITOR_FIFO_DEPTH - 1) of 
   172:           t_can_monitor_entry; 
   173:    
   174:       -- Driver signals 
   175:       signal driver_mem               :   t_driver_fifo_mem; 
   176:       signal driver_wp                :   natural := 0; 
   177:       signal driver_rp                :   natural := 0; 
   178:       signal driver_ena               :   boolean := false; 
   179:       signal driving_in_progress      :   boolean := false; 
   180:       signal driver_wait_for_monitor  :   boolean := false; 
   181:    
   182:       -- Monitor signals 
   183:       signal monitor_mem              :   t_monitor_fifo_mem; 
   184:       signal monitor_wp               :   natural := 0; 
   185:       signal monitor_rp               :   natural := 0; 
   186:       signal monitor_ena              :   boolean := false; 
   187:       signal monitor_in_progress      :   boolean := false; 
   188:       signal monitor_state            :   t_can_monitor_state := mon_disabled; 
   189:    
   190:       --------------------------------------------------------------------------- 
   191:       -- Parameters configured over communication library 
   192:       --------------------------------------------------------------------------- 
   193:    
   194:       -- Driver 
   195:       signal driver_wait_timeout      :   time := 10 ms; 
   196:       signal driven_item              :   t_can_driver_entry := ( 
   197:           value           => 'Z', 
   198:           drive_time      => 0 ns, 
   199:           print_msg       => false, 
   200:           msg             => C_EMPTY_STRING 
   201:       ); 
   202:    
   203:       -- Monitor 
   204:       signal monitor_wait_timeout     :   time := 10 ms; 
   205:       signal monitored_item           :   t_can_monitor_entry := ( 
   206:           value           => 'Z', 
   207:           monitor_time    => 0 ns, 
   208:           sample_rate     => 0 ns, 
   209:           print_msg       => false, 
   210:           msg             => C_EMPTY_STRING 
   211:       ); 
   212:    
   213:       signal monitor_trigger          :   t_can_monitor_trigger := trig_immediately; 
   214:       signal monitor_trig_wait_time   :   time := 100 ns; 
   215:    
   216:       -- Debug signal only, shows where can_rx is sampled! 
   217:       signal monitor_sample           :   std_logic := '0'; 
   218:    
   219:       -- Debug signal only, shows mismatch (by an X) 
   220:       signal monitor_mismatch         :   std_logic := '0'; 
   221:    
   222:       -- Mismatch counter 
   223:       signal mon_mismatch_ctr         :   integer := 0; 
   224:    
   225:       -- Input delay 
   226:       signal mon_input_delay          :   time := 0 ns; 
   227:    
   228:       -- can_tx to can_rx feedback 
   229:       signal tx_to_rx_feedback_enable :   boolean := false; 
   230:    
   231:       -- Internal value of can_rx 
   232:       signal can_rx_i                 :   std_logic := '1'; 
   233:    
   234:   begin 
   235:    
   236:       --------------------------------------------------------------------------- 
   237:       -- Comunication receiver process 
   238:       --------------------------------------------------------------------------- 
   239:       receiver_proc : process 
   240:           variable cmd            : integer; 
   241:           variable reply_code     : integer; 
   242:           variable push_item      : t_can_driver_entry; 
   243:           variable push_mon_item  : t_can_monitor_entry; 
   244:           variable tmp            : boolean := false; 
   245:           variable tmp_int        : integer := 0; 
   246:    
   247:           procedure driver_fifo_push is 
   248:           begin 
   249:               driver_mem(driver_wp) <= push_item; 
   250:               driver_wp <= (driver_wp + 1) mod G_DRIVER_FIFO_DEPTH; 
   251:               wait for 0 ns; 
   252:           end procedure; 
   253:    
   254:           procedure monitor_fifo_push is 
   255:           begin 
   256:               monitor_mem(monitor_wp) <= push_mon_item; 
   257:               monitor_wp <= (monitor_wp + 1) mod G_MONITOR_FIFO_DEPTH; 
   258:               wait for 0 ns; 
   259:           end procedure; 
   260:    
   261:       begin 
   262:           receive_start(default_channel, C_CAN_AGENT_ID); 
   263:    
   264:           -- Command is sent as message type 
   265:           cmd := com_channel_data.get_msg_code; 
   266:           reply_code := C_REPLY_CODE_OK; 
   267:    
   268:           case cmd is 
   269:           when CAN_AGNT_CMD_DRIVER_START => 
   270:               driver_ena <= true; 
   271:    
   272:           when CAN_AGNT_CMD_DRIVER_STOP => 
   273:               driver_ena <= false; 
   274:    
   275:           when CAN_AGNT_CMD_DRIVER_FLUSH => 
   276:               -- Just move to position of acutally driven item (Read pointer). 
   277:               -- This will efectively stash all written items and only current 
   278:               -- driven item will be finished! 
   279:               driver_wp <= driver_rp; 
   280:    
   281:           when CAN_AGNT_CMD_DRIVER_GET_PROGRESS => 
   282:               com_channel_data.set_param(driving_in_progress); 
   283:    
   284:           when CAN_AGNT_CMD_DRIVER_GET_DRIVEN_VAL => 
   285:               com_channel_data.set_param(can_rx); 
   286:    
   287:           when CAN_AGNT_CMD_DRIVER_PUSH_ITEM => 
   288:               push_item.value := com_channel_data.get_param; 
   289:               push_item.drive_time := com_channel_data.get_param; 
   290:               push_item.print_msg := com_channel_data.get_param; 
   291:               if (push_item.print_msg) then 
   292:                   push_item.msg := com_channel_data.get_param; 
   293:               else 
   294:                   push_item.msg := (OTHERS => ' '); 
   295:               end if; 
   296:    
   297:               -- Check for overflow, keep one item empty so that we don't have to 
   298:               -- handle pointers 
   299:               if ((driver_wp + 1) mod G_DRIVER_FIFO_DEPTH = driver_rp) then 
   300:                   reply_code := C_REPLY_CODE_ERR; 
   301:                   error_m(CAN_AGENT_TAG & "Driver FIFO overflow! -> Skipping"); 
   302:               else 
   303:                   driver_fifo_push; 
   304:               end if; 
   305:    
   306:           when CAN_AGNT_CMD_DRIVER_SET_WAIT_TIMEOUT => 
   307:               driver_wait_timeout <= com_channel_data.get_param; 
   308:    
   309:           when CAN_AGNT_CMD_DRIVER_WAIT_FINISH => 
   310:               wait for 0 ns; 
   311:               if (driving_in_progress) then 
   312:                   wait until (driving_in_progress = false) for driver_wait_timeout; 
   313:               end if; 
   314:    
   315:           when CAN_AGNT_CMD_DRIVER_DRIVE_SINGLE_ITEM => 
   316:               if (not driver_ena) then 
   317:                   driver_ena <= true; 
   318:                   tmp := true; 
   319:               end if; 
   320:    
   321:               push_item.value := com_channel_data.get_param; 
   322:               push_item.drive_time := com_channel_data.get_param; 
   323:               push_item.print_msg := com_channel_data.get_param; 
   324:               if (push_item.print_msg) then 
   325:                   push_item.msg := com_channel_data.get_param; 
   326:               else 
   327:                   push_item.msg := (OTHERS => ' '); 
   328:               end if; 
   329:    
   330:               if (driver_wp /= driver_rp) then 
   331:                   warning_m(CAN_AGENT_TAG & 
   332:                           "Driver FIFO not empty, other items will be driven first..."); 
   333:               end if; 
   334:    
   335:               if ((driver_wp + 1) mod G_DRIVER_FIFO_DEPTH = driver_rp) then 
   336:                   reply_code := C_REPLY_CODE_ERR; 
   337:                   error_m(CAN_AGENT_TAG & "Driver FIFO overflow -> Skipping"); 
   338:               else 
   339:                   driver_fifo_push; 
   340:                   wait until (driver_wp = driver_rp) for driver_wait_timeout; 
   341:    
   342:                   if (driver_wp /= driver_rp) then 
   343:                       warning_m(CAN_AGENT_TAG & " Drive_single_item timeout!"); 
   344:                   end if; 
   345:               end if; 
   346:    
   347:               -- If driver was previously disabled, put it back into the same state! 
   348:               if (tmp) then 
   349:                   driver_ena <= false; 
   350:               end if; 
   351:    
   352:           when CAN_AGNT_CMD_DRIVER_DRIVE_ALL_ITEMS => 
   353:               if (not driver_ena) then 
   354:                   driver_ena <= true; 
   355:                   tmp := true; 
   356:               end if; 
   357:    
   358:               if (driver_wp = driver_rp) then 
   359:                   warning_m(CAN_AGENT_TAG & "Driver FIFO empty, no items will be driven"); 
   360:               else 
   361:                   wait until (driver_wp = driver_rp) for driver_wait_timeout; 
   362:               end if; 
   363:    
   364:               if (driver_wp /= driver_rp) then 
   365:                   warning_m(CAN_AGENT_TAG & " Drive_all_items timeout!"); 
   366:               end if; 
   367:    
   368:               -- If driver was previously disabled, put it back into the same state! 
   369:               if (tmp) then 
   370:                   driver_ena <= false; 
   371:               end if; 
   372:    
   373:           when CAN_AGNT_CMD_SET_WAIT_FOR_MONITOR => 
   374:               driver_wait_for_monitor <= com_channel_data.get_param; 
   375:    
   376:           when CAN_AGNT_CMD_MONITOR_START => 
   377:               monitor_ena <= true; 
   378:    
   379:           when CAN_AGNT_CMD_MONITOR_STOP => 
   380:               monitor_ena <= false; 
   381:    
   382:           when CAN_AGNT_CMD_MONITOR_FLUSH => 
   383:               -- Just move to position of acutally driven item (Read pointer). 
   384:               -- This will efectively stash all written items and only current 
   385:               -- driven item will be finished! 
   386:               monitor_wp <= monitor_rp; 
   387:    
   388:           when CAN_AGNT_CMD_MONITOR_GET_STATE => 
   389:               com_channel_data.set_param(t_can_monitor_state'pos(monitor_state)); 
   390:    
   391:           when CAN_AGNT_CMD_MONITOR_GET_MONITORED_VAL => 
   392:               com_channel_data.set_param(monitored_item.value); 
   393:    
   394:           when CAN_AGNT_CMD_MONITOR_PUSH_ITEM => 
   395:               push_mon_item.value := com_channel_data.get_param; 
   396:               push_mon_item.monitor_time := com_channel_data.get_param; 
   397:               push_mon_item.print_msg := com_channel_data.get_param; 
   398:               if (push_mon_item.print_msg) then 
   399:                   push_mon_item.msg := com_channel_data.get_param; 
   400:               else 
   401:                   push_mon_item.msg := (OTHERS => ' '); 
   402:               end if; 
   403:               push_mon_item.sample_rate := com_channel_data.get_param2; 
   404:    
   405:               monitor_fifo_push; 
   406:    
   407:           when CAN_AGNT_CMD_MONITOR_SET_WAIT_TIMEOUT => 
   408:               monitor_wait_timeout <= com_channel_data.get_param; 
   409:    
   410:           when CAN_AGNT_CMD_MONITOR_WAIT_FINISH => 
   411:               wait for 0 ns; 
   412:               wait until (monitor_in_progress = false) for monitor_wait_timeout; 
   413:    
   414:           when CAN_AGNT_CMD_MONITOR_MONITOR_SINGLE_ITEM => 
   415:               if (not monitor_ena) then 
   416:                   monitor_ena <= true; 
   417:                   tmp := true; 
   418:               end if; 
   419:    
   420:               push_mon_item.value := com_channel_data.get_param; 
   421:               push_mon_item.monitor_time := com_channel_data.get_param; 
   422:               push_mon_item.print_msg := com_channel_data.get_param; 
   423:               if (push_mon_item.print_msg) then 
   424:                   push_mon_item.msg := com_channel_data.get_param; 
   425:               else 
   426:                   push_mon_item.msg := (OTHERS => ' '); 
   427:               end if; 
   428:               push_mon_item.sample_rate := com_channel_data.get_param2; 
   429:    
   430:               if (monitor_wp /= monitor_rp) then 
   431:                   warning_m(CAN_AGENT_TAG & 
   432:                           "Monitor FIFO not empty, other items will be monitored first..."); 
   433:               end if; 
   434:    
   435:               if ((monitor_wp + 1) mod G_MONITOR_FIFO_DEPTH = monitor_rp) then 
   436:                   reply_code := C_REPLY_CODE_ERR; 
   437:                   error_m(CAN_AGENT_TAG & "Monitor FIFO overflow -> Skipping"); 
   438:               else 
   439:                   monitor_fifo_push; 
   440:                   wait until (monitor_wp = monitor_rp) for monitor_wait_timeout; 
   441:    
   442:                   if (monitor_wp /= monitor_rp) then 
   443:                       warning_m(CAN_AGENT_TAG & " Monitor_single_item timeout!"); 
   444:                   end if; 
   445:               end if; 
   446:    
   447:               -- If monitor was previously disabled, put it back into the same state! 
   448:               if (tmp) then 
   449:                   monitor_ena <= false; 
   450:               end if; 
   451:    
   452:           when CAN_AGNT_CMD_MONITOR_MONITOR_ALL_ITEMS => 
   453:               if (not monitor_ena) then 
   454:                   monitor_ena <= true; 
   455:                   tmp := true; 
   456:               end if; 
   457:    
   458:               if (monitor_wp = monitor_rp) then 
   459:                   warning_m(CAN_AGENT_TAG & "Monitor FIFO empty, no items will be driven"); 
   460:               else 
   461:                   wait until (monitor_wp = monitor_rp) for monitor_wait_timeout; 
   462:               end if; 
   463:    
   464:               if (monitor_wp /= monitor_rp) then 
   465:                   warning_m(CAN_AGENT_TAG & " Monitor_all_items timeout!"); 
   466:               end if; 
   467:    
   468:               -- If monitor was previously disabled, put it back into the same state! 
   469:               if (tmp) then 
   470:                   monitor_ena <= false; 
   471:               end if; 
   472:    
   473:           when CAN_AGNT_CMD_MONITOR_SET_TRIGGER => 
   474:               tmp_int := com_channel_data.get_param; 
   475:               monitor_trigger <= t_can_monitor_trigger'val(tmp_int); 
   476:    
   477:           when CAN_AGNT_CMD_MONITOR_GET_TRIGGER => 
   478:               com_channel_data.set_param(t_can_monitor_trigger'pos(monitor_trigger)); 
   479:    
   480:           when CAN_AGNT_CMD_MONITOR_CHECK_RESULT => 
   481:               check_m(mon_mismatch_ctr = 0, CAN_AGENT_TAG & "Mismatches in monitor!"); 
   482:    
   483:           when CAN_AGNT_CMD_MONITOR_SET_INPUT_DELAY => 
   484:               mon_input_delay <= com_channel_data.get_param; 
   485:    
   486:           when CAN_AGNT_CMD_TX_RX_FEEDBACK_ENABLE => 
   487:               tx_to_rx_feedback_enable <= true; 
   488:               wait for 0 ns; 
   489:    
   490:           when CAN_AGNT_CMD_TX_RX_FEEDBACK_DISABLE => 
   491:               tx_to_rx_feedback_enable <= false; 
   492:               wait for 0 ns; 
   493:    
   494:           when others => 
   495:               warning_m(CAN_AGENT_TAG & "Invalid message type: " & integer'image(cmd)); 
   496:               reply_code := C_REPLY_CODE_ERR; 
   497:           end case; 
   498:    
   499:           receive_finish(default_channel, reply_code); 
   500:       end process; 
   501:    
   502:       --------------------------------------------------------------------------- 
   503:       --------------------------------------------------------------------------- 
   504:       -- Driver process (reading from Driver FIFO) 
   505:       --------------------------------------------------------------------------- 
   506:       --------------------------------------------------------------------------- 
   507:       driver_proc : process 
   508:       begin 
   509:           if (driver_ena) then 
   510:               if (driver_wait_for_monitor = true) then 
   511:                   wait until (monitor_state = mon_running); 
   512:               end if; 
   513:               while (true) loop 
   514:                   if (not driver_ena) then 
   515:                       driving_in_progress <= false; 
   516:                       exit; 
   517:                   end if; 
   518:    
   519:                   -- There is something in FIFO -> drive it! 
   520:                   if (driver_rp /= driver_wp) then 
   521:                       driving_in_progress <= true; 
   522:                       driven_item <= driver_mem(driver_rp); 
   523:                       wait for 0 ns; 
   524:    
   525:                       --debug_m(CAN_AGENT_TAG & 
   526:                       --      "Driving: " & std_logic'image(driven_item.value) & 
   527:                       --      " for time: " & time'image(driven_item.drive_time)); 
   528:                       --if (driven_item.print_msg) then 
   529:                       --    info_m("Driving item: " & driven_item.msg); 
   530:                       --end if; 
   531:    
   532:                       can_rx_i <= driven_item.value; 
   533:                       wait for driven_item.drive_time; 
   534:                       driver_rp <= (driver_rp + 1) mod G_DRIVER_FIFO_DEPTH; 
   535:                       wait for 0 ns; 
   536:                   else 
   537:                       driving_in_progress <= false; 
   538:                       wait until driver_rp /= driver_wp or driver_ena=false; 
   539:                   end if; 
   540:               end loop; 
   541:           else 
   542:               driving_in_progress <= false; 
   543:               wait until driver_ena; 
   544:           end if; 
   545:       end process; 
   546:    
   547:       --------------------------------------------------------------------------- 
   548:       --------------------------------------------------------------------------- 
   549:       -- Monitor process (FSM) 
   550:       --------------------------------------------------------------------------- 
   551:       --------------------------------------------------------------------------- 
   552:       monitor_proc : process 
   553:           variable mon_count          : integer := 0; 
   554:           variable monitored_time     : time := 0 fs; 
   555:    
   556:           ----------------------------------------------------------------------- 
   557:           -- Comparison procedure for monitor. Simple "=" operator is not enough 
   558:           -- since GHDL might improprely handle don't care values. Also, compare 
   559:           -- is not symmetrical (can_tx is now allowed to have "don't care" 
   560:           ----------------------------------------------------------------------- 
   561:           impure function monitor_compare return boolean is 
   562:           begin 
   563:               if (can_tx = 'X' or 
   564:                   can_tx = 'U' or 
   565:                   can_tx = '-' or 
   566:                   can_tx = 'W' or 
   567:                   can_tx = 'Z') 
   568:               then 
   569:                   return false; 
   570:               end if; 
   571:    
   572:               if (monitored_item.value = '-' and (can_tx = '1' or can_rx = '0')) 
   573:               then 
   574:                   return true; 
   575:               end if; 
   576:    
   577:               if (can_tx = '0' and monitored_item.value = '0') then 
   578:                   return true; 
   579:               elsif (can_tx = '1' and monitored_item.value = '1') then 
   580:                   return true; 
   581:               end if; 
   582:    
   583:               return false; 
   584:           end function; 
   585:    
   586:       begin 
   587:           case monitor_state is 
   588:           when mon_disabled => 
   589:               if (monitor_ena) then 
   590:                   if (monitor_trigger = trig_immediately) then 
   591:                       monitor_state <= mon_running; 
   592:                   else 
   593:                       monitor_state <= mon_waiting_for_trigger; 
   594:                   end if; 
   595:                   wait for 0 ns; 
   596:               else 
   597:                   wait until monitor_ena; 
   598:               end if; 
   599:    
   600:           when mon_waiting_for_trigger => 
   601:               if (monitor_ena = false)then 
   602:                   monitor_state <= mon_disabled; 
   603:                   wait for 0 ns; 
   604:               else 
   605:                   case monitor_trigger is 
   606:                   when trig_immediately => 
   607:                   when trig_can_rx_rising_edge => 
   608:                       wait until rising_edge(can_rx) or (monitor_ena = false); 
   609:                   when trig_can_rx_falling_edge => 
   610:                       wait until falling_edge(can_rx) or (monitor_ena = false); 
   611:                   when trig_can_tx_rising_edge => 
   612:                       wait until rising_edge(can_tx) or (monitor_ena = false); 
   613:                   when trig_can_tx_falling_edge => 
   614:                       wait until falling_edge(can_tx) or (monitor_ena = false); 
   615:    
   616:                   when trig_time_elapsed => 
   617:                       wait until (monitor_ena = false) for monitor_trig_wait_time; 
   618:    
   619:                   -- Note: This triggers also when driver is started but its 
   620:                   --       FIFO is empty so it does not drive anything! 
   621:                   when trig_driver_start => 
   622:                       wait until (driver_ena = true) or (monitor_ena = false); 
   623:    
   624:                   when trig_driver_stop => 
   625:                       wait until (driver_ena = false) or (monitor_ena = false); 
   626:                   end case; 
   627:    
   628:                   if (monitor_ena = false) then 
   629:                       monitor_state <= mon_disabled; 
   630:                   else 
   631:                       -- Wait additional monitor delay 
   632:                       wait for mon_input_delay; 
   633:    
   634:                       monitor_state <= mon_running; 
   635:                   end if; 
   636:                   wait for 0 ns; 
   637:               end if; 
   638:    
   639:           when mon_running => 
   640:               mon_mismatch_ctr <= 0; 
   641:               while (true) loop 
   642:                   if (monitor_ena = false) then 
   643:                       monitor_state <= mon_disabled; 
   644:                       monitor_in_progress <= false; 
   645:                       wait for 0 ns; 
   646:                       exit; 
   647:                   end if; 
   648:    
   649:                   if (monitor_wp = monitor_rp) then 
   650:    
   651:                       if (mon_mismatch_ctr = 0) then 
   652:                           monitor_state <= mon_passed; 
   653:                       else 
   654:                           monitor_state <= mon_failed; 
   655:                       end if; 
   656:                       monitor_in_progress <= false; 
   657:                       monitor_mismatch <= '0'; 
   658:                       wait for 0 ns; 
   659:                       exit; 
   660:                   end if; 
   661:    
   662:                   monitor_in_progress <= true; 
   663:    
   664:                   -- Read value from FIFO and start monitoring it! 
   665:                   monitored_item <= monitor_mem(monitor_rp); 
   666:                   wait for 0 ns; 
   667:    
   668:                   --debug_m(CAN_AGENT_TAG & 
   669:                   --      "Monitoring: " & std_logic'image(monitored_item.value) & 
   670:                   --      " for time: " & time'image(monitored_item.monitor_time)); 
   671:    
   672:                   --if (monitored_item.print_msg) then 
   673:                   --    info_m("Monitoring item: " & monitored_item.msg); 
   674:                   --end if; 
   675:    
   676:                   mon_count := monitored_item.monitor_time / monitored_item.sample_rate; 
   677:                   monitored_time := 0 ns; 
   678:                   debug_m("Number of samples: " & integer'image(mon_count)); 
   679:    
   680:                   ------------------------------------------------------------------------ 
   681:                   -- Monitor until we are not closer than sample rate from the end. This 
   682:                   -- will truncate the last sample so that we dont compare too close to 
   683:                   -- the end! 
   684:                   ------------------------------------------------------------------------ 
   685:                   while (monitored_time < monitored_item.monitor_time - monitored_item.sample_rate) loop 
   686:                       wait for (monitored_item.sample_rate - 1 ps); 
   687:                       monitor_sample <= '1'; 
   688:                       wait for 1 ps; 
   689:                       monitor_sample <= '0'; 
   690:                       wait for 0 ns; 
   691:    
   692:                       if (monitor_compare = false) then 
   693:                           monitor_mismatch <= 'X'; 
   694:                           mon_mismatch_ctr <= mon_mismatch_ctr + 1; 
   695:    
   696:                           warning_m(CAN_AGENT_TAG & 
   697:                                   "Monitor mismatch! Expected: " & 
   698:                                   std_logic'image(monitored_item.value) & 
   699:                                   " Monitored: " & std_logic'image(can_tx)); 
   700:                       else 
   701:                           monitor_mismatch <= '0'; 
   702:                       end if; 
   703:                       monitored_time := monitored_time + monitored_item.sample_rate; 
   704:                   end loop; 
   705:    
   706:                   -- We must wait the rest so that monitor item lasts proper time! 
   707:                   wait for monitored_item.monitor_time - monitored_time; 
   708:    
   709:                   monitor_mismatch <= '0'; 
   710:    
   711:                   monitor_rp <= (monitor_rp + 1) mod G_MONITOR_FIFO_DEPTH; 
   712:                   wait for 0 ns; 
   713:               end loop; 
   714:    
   715:           when mon_passed => 
   716:               info_m("*****************************************************"); 
   717:               info_m (" Monitor sequence PASSED"); 
   718:               info_m ("*****************************************************"); 
   719:               monitor_state <= mon_disabled; 
   720:               wait for 0 ns; 
   721:    
   722:           when mon_failed => 
   723:               info_m ("*****************************************************"); 
   724:               info_m (" Monitor sequence FAILED"); 
   725:               info_m ("*****************************************************"); 
   726:               monitor_state <= mon_disabled; 
   727:               wait for 0 ns; 
   728:    
   729:           end case; 
   730:       end process; 
   731:    
   732:       ----------------------------------------------------------------------------- 
   733:       -- CAN tx to CAN rx feedback. This corresponds to CAN bus realization! 
   734:       ----------------------------------------------------------------------------- 
   735:       can_rx <= can_rx_i when (tx_to_rx_feedback_enable = false) else 
   736:                 can_rx_i and can_tx; 
   737:    
   738:   end architecture;