External Memory Interface Handbook Volume 3: Reference Material: For UniPHY-based Device Families

ID 683841
Date 3/06/2023
Public
Document Table of Contents

13.6.5. Example C Code for Accessing Debug Data

A typical use of the EMIF On-Chip Debug Port might be to recalibrate the external memory interface, and then access the reports directly using the summary_report_ptr, cal_report_ptr, and margin_report_ptr pointers, which are part of the debug data structure.

The following code sample illustrates:

/*
 * DDR3 UniPHY sequencer core access example
*/

#include <stdio.h>
#include <unistd.h>
#include <io.h>
#include "core_debug_defines.h"

int send_command(volatile debug_data_t* debug_data_ptr, int command, int args[], int num_args)
{
volatile int i, response;

// Wait until command_status is ready
do {
  response = IORD_32DIRECT(&(debug_data_ptr->command_status), 0);
} while(response != TCLDBG_TX_STATUS_CMD_READY);

// Load arguments
if(num_args > COMMAND_PARAM_WORDS)
{
// Too many arguments
return 0;
}
for(i = 0; i < num_args; i++)
{
IOWR_32DIRECT(&(debug_data_ptr->command_parameters[i]), 0, args[i]);
}
// Send command code
IOWR_32DIRECT(&(debug_data_ptr->requested_command), 0, command);
// Wait for acknowledgment
do {
  response = IORD_32DIRECT(&(debug_data_ptr->command_status), 0);
} while(response != TCLDBG_TX_STATUS_RESPOSE_READY && response != TCLDBG_TX_STATUS_ILLEGAL_CMD);
// Acknowledge response
IOWR_32DIRECT(&(debug_data_ptr->requested_command), 0, TCLDBG_CMD_RESPONSE_ACK);
// Return 1 on success, 0 on illegal command
return (response != TCLDBG_TX_STATUS_ILLEGAL_CMD);
}
int main()
{
  volatile debug_data_t* my_debug_data_ptr;
  volatile debug_summary_report_t* my_summary_report_ptr;
  volatile debug_cal_report_t* my_cal_report_ptr;
  volatile debug_margin_report_t* my_margin_report_ptr;
volatile debug_cal_observed_dq_margins_t* cal_observed_dq_margins_ptr;
  int i, j, size;
  int args[COMMAND_PARAM_WORDS];
  // Initialize pointers to the debug reports
  my_debug_data_ptr = (debug_data_t*)SEQ_CORE_DEBUG_BASE;
  my_summary_report_ptr = (debug_summary_report_t*)(IORD_32DIRECT(&(my_debug_data_ptr->summary_report_ptr), 0));
  my_cal_report_ptr = (debug_cal_report_t*)(IORD_32DIRECT(&(my_debug_data_ptr->cal_report_ptr), 0));
  my_margin_report_ptr = (debug_margin_report_t*)(IORD_32DIRECT(&(my_debug_data_ptr->margin_report_ptr), 0));

  // Activate all groups and ranks
  send_command(my_debug_data_ptr, TCLDBG_MARK_ALL_DQS_GROUPS_AS_VALID, 0, 0);
  send_command(my_debug_data_ptr, TCLDBG_MARK_ALL_RANKS_AS_VALID, 0, 0);
  send_command(my_debug_data_ptr, TCLDBG_ENABLE_MARGIN_REPORT, 0, 0);

  // Mask group 4
args[0] = 4; 
  send_command(my_debug_data_ptr, TCLDBG_MARK_GROUP_AS_SKIP, args, 1);
  send_command(my_debug_data_ptr, TCLDBG_RUN_MEM_CALIBRATE, 0, 0);

  // SUMMARY
  printf("SUMMARY REPORT\n");
  printf("mem_address_width: %u\n", IORD_32DIRECT(&(my_summary_report_ptr->mem_address_width), 0));
  printf("mem_bank_width: %u\n", IORD_32DIRECT(&(my_summary_report_ptr->mem_bank_width), 0));
  // etc...

  // CAL REPORT
  printf("CALIBRATION REPORT\n");
  // DQ read margins
  for(i = 0; i < RW_MGR_MEM_DATA_WIDTH; i++)
  {
  cal_observed_dq_margins_ptr = &(my_cal_report_ptr->cal_dq_in_margins[i]);
  printf("0x%x DQ %d Read Margin (taps): -%d : %d\n", (unsigned int)cal_observed_dq_margins_ptr, i,
  IORD_32DIRECT(&(cal_observed_dq_margins_ptr->left_edge), 0),
  IORD_32DIRECT(&(cal_observed_dq_margins_ptr->right_edge), 0));
  }
  // etc...
  return 0;
}