/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2019-2024 by Lattice Semiconductor Corporation ALL RIGHTS RESERVED ------------------------------------------------------------------ DISCLAIMER: LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE 'S REQUIREMENTS, OR THAT LICENSEE' S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED. LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM. LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE.IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE 'S SOLE LIABILITY, AND LICENSEE' S SOLE REMEDY, IS SET FORTH ABOVE. LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER' S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS. ------------------------------------------------------------------ ================================================================== */ #include "imgui.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" #include "implot.h" #include "implot_internal.h" #include #define GL_SILENCE_DEPRECATION #include // Will drag system OpenGL headers #include #include #include #include #include #include #include #include #include #include #include #include "PCIEDMA_IF.h" #include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" using namespace std; #define ARRAY_COUNT_OF(array) (sizeof(array) / sizeof(array[0])) #define TIMEOUT 1000 PCIEDMA_IF *pDrvr; struct dma_h2f_tpt dma_h2f_tpt; struct dma_f2h_tpt dma_f2h_tpt; bool test_run = false; bool run_test = false; bool run_once = false; bool f2h_desc_select = false; bool h2f_desc_select = false; bool buffers_ready = false; float global_f2h_tpt = 0; float global_h2f_tpt = 0; uint8_t f2h_desc_mode; uint8_t h2f_desc_mode; uint32_t read_value = 0; uint32_t f2h_total_entry_ret = 1; //initialize to 1 because there should always be at least 1 entry uint32_t h2f_total_entry_ret = 1; //initialize to 1 because there should always be at least 1 entry struct dma_h2f_ubuf_ioctl_arg h2f_userptr_arg; struct dma_f2h_ubuf_ioctl_arg f2h_userptr_arg; uint32_t f2h_desc_comp_curr = 0; uint32_t f2h_desc_comp_prev = 0; uint32_t f2h_desc_comp_delta = 0; uint32_t h2f_desc_comp_curr = 0; uint32_t h2f_desc_comp_prev = 0; uint32_t h2f_desc_comp_delta = 0; int stored_num_desc = 1; int stored_size = 256; std::vector h2fbuf; std::vector f2hbuf; std::vector prev_h2fbuf; std::vector prev_f2hbuf; std::vector global_h2f_tpt_values; std::vector global_f2h_tpt_values; char offset_str[32] = ""; char write_value_str[32] = ""; static void signal_handler(int sig); static inline bool status_is_success(int status) { return (0 == status); } static void print_pci_cfg(void) { ImGui::BeginChild("PCI Config Space Dump"); int i; uint32_t pci_read_val; for (i = 0; i < 256; i += 4) { pci_read_val = pDrvr->readPCI(i); ImGui::Text("Address Offset:\t 0x%x", i); ImGui::Text("Value:\t\t\t\t\t\t 0x%08x\n", pci_read_val); } ImGui::EndChild(); } static void fill_buffer(void* buffer, size_t size, size_t iterator) { int* intBuf = (int*)buffer; // Cast directly to int pointer const size_t numInts = size / 32; for (size_t i = 0; i < numInts; i++) { intBuf[i] = 0x10000000 + ((i + 1 + iterator) * 10); } for (size_t i = 0; i < 6; i++) { printf("Initializing DMA H2F Buffer at Address %p with: 0x%x\n", (void*)&intBuf[i], intBuf[i]); } printf("Initializing DMA H2F Buffer at Address %p with: 0x%x\n",(void*)&intBuf[(numInts-1)], intBuf[(numInts-1)]); } static void fill_buffer_f2h(void* buffer, size_t size) { int* intBuf = (int*)buffer; // Cast directly to int pointer const size_t numInts = size / 32; for (size_t i = 0; i < numInts; i++) { intBuf[i] = 0xdeadbeef; } for (size_t i = 0; i < 6; i++) { printf("Initializing DMA F2H Buffer at Address %p with: 0x%x\n", (void*)&intBuf[i], intBuf[i]); } printf("Initializing DMA F2H Buffer at Address %p with: 0x%x\n",(void*)&intBuf[(numInts-1)], intBuf[(numInts-1)]); } static uint64_t time_get_ns(void) { struct timespec tp; uint64_t time_val; int ret; ret = clock_gettime(CLOCK_MONOTONIC, &tp); time_val = (uint64_t)tp.tv_sec * 1000000000 + tp.tv_nsec; (void)ret; return time_val; } static void dma_dump_regs() { ImGui::BeginChild("DMA Register Info"); uint32_t read_val; read_val = pDrvr->read32(H2F_DMA_CTRL); ImGui::TextWrapped("H2F_DMA_CTRL 0x%x", read_val); read_val = pDrvr->read32(H2F_DMA_STS); ImGui::TextWrapped("H2F_DMA_STS 0x%x", read_val); read_val = pDrvr->read32(H2F_CPLT_DESC_COUNT); ImGui::TextWrapped("H2F_CPLT_DESC_COUNT 0x%x", read_val); read_val = pDrvr->read32(F2H_DMA_CTRL); ImGui::TextWrapped("F2H_DMA_CTRL 0x%x", read_val); read_val = pDrvr->read32(F2H_DMA_STS); ImGui::TextWrapped("F2H_DMA_STS 0x%x", read_val); read_val = pDrvr->read32(F2H_CPLT_DESC_COUNT); ImGui::TextWrapped("F2H_CPLT_DESC_COUNT 0x%x", read_val); ImGui::EndChild(); } static int dma_init(size_t size, int num_desc, uint8_t h2f_desc_mode, uint8_t f2h_desc_mode) { int status = 0; //only free buffers if buffers were not previously freed // if (buffers_ready) { // for (void* buf : h2fbuf) { // free(buf); // } // for (void* buf : f2hbuf) { // free(buf); // } // } for (size_t i = 0; i < h2fbuf.size(); i++) { free(h2fbuf[i]); } for (size_t i = 0; i < f2hbuf.size(); i++) { free(f2hbuf[i]); } h2fbuf.resize(num_desc); f2hbuf.resize(num_desc); for (size_t i = 0; i < num_desc; i++) { h2fbuf[i] = aligned_alloc(4096, size); if (NULL == h2fbuf[i]) { std::cerr << "H2F: Error no memory!\n"; return -1; } } for (size_t i = 0; i < num_desc; i++) { f2hbuf[i] = aligned_alloc(4096, size); if (NULL == f2hbuf[i]) { std::cerr << "F2H: Error no memory!\n"; return -1; } } for (size_t i = 0; i < num_desc; i++) { printf("H2F Descriptor %ld\n", i); fill_buffer(h2fbuf[i], size, i); } for (size_t i = 0; i < num_desc; i++) { printf("F2H Descriptor %ld\n", i); fill_buffer_f2h(f2hbuf[i], size); } h2f_userptr_arg.addr = h2fbuf.data(); h2f_userptr_arg.len = size; h2f_userptr_arg.desc_cnt = num_desc; h2f_userptr_arg.descriptor_mode = h2f_desc_mode; f2h_userptr_arg.addr = f2hbuf.data(); f2h_userptr_arg.len = size; f2h_userptr_arg.desc_cnt = num_desc; f2h_userptr_arg.descriptor_mode = f2h_desc_mode; status = pDrvr->PcieDmaH2fDescGen(&h2f_userptr_arg); if (!status_is_success(status)) { ERRORSTR("Can't perform H2F Descriptor Generation!\n"); return -3; } status = pDrvr->PcieDmaF2hDescGen(&f2h_userptr_arg); if (!status_is_success(status)) { ERRORSTR("Can't perform F2H Descriptor Generation!\n"); return -4; } buffers_ready = true; return 0; } static int dma_stop() { int status = 0; if (buffers_ready) { status = pDrvr->PcieDmaH2fStartCtrl(DMA_OFF); if (!status_is_success(status)) { ERRORSTR("Cannot stop H2F DMA!\n"); return -2; } status = pDrvr->PcieDmaF2hStartCtrl(DMA_OFF); if (!status_is_success(status)) { ERRORSTR("Cannot stop F2H DMA!\n"); return -3; } // for (void* buf : h2fbuf) { // free(buf); // } // for (void* buf : f2hbuf) { // free(buf); // } buffers_ready = false; //test_run = false; } else if (!buffers_ready) { ERRORSTR("Buffers and descriptors not generated!\n"); return -1; } return 0; } static int dma_f2h_transfer(uint8_t desc_mode) { int timeout = 0; int status = 0; uint32_t cur_dma_sts; if (!buffers_ready) { ERRORSTR("Buffers and descriptors not generated!\n"); return -1; } status = pDrvr->PcieDmaF2hStartCtrl(DMA_ON); if (!status_is_success(status)) { ERRORSTR("Can't start F2H PCIE SGDMA!\n"); return -4; } dma_f2h_tpt.f2h_timestamp_start = time_get_ns(); if (desc_mode == DESC_MODE_SINGLE) { do { status = pDrvr->PcieDmaF2hCheckDone(&cur_dma_sts, TIMEOUT); timeout+=1; if (timeout == 20) { printf("Timeout while checking F2H DMA DONE!\n"); return -4; } } while (cur_dma_sts == 0); if (status_is_success(status)) { dma_f2h_tpt.f2h_timestamp_end = time_get_ns(); } else{ ERRORSTR("Can't check DMA Completion Status!\n"); dma_f2h_tpt.f2h_timestamp_end = 0; return -4; } printf("DMA DONE Indicator: 0x%x\n",cur_dma_sts); } return 0; } static int dma_h2f_transfer(uint8_t desc_mode) { int timeout = 0; int status = 0; uint32_t cur_dma_sts; if (!buffers_ready) { ERRORSTR("Buffers and descriptors not generated!\n"); return -1; } status = pDrvr->PcieDmaH2fStartCtrl(DMA_ON); if (!status_is_success(status)) { ERRORSTR("Can't start H2F PCIE SGDMA!\n"); return -4; } dma_h2f_tpt.h2f_timestamp_start = time_get_ns(); if (desc_mode == DESC_MODE_SINGLE) { do { status = pDrvr->PcieDmaH2fCheckDone(&cur_dma_sts, TIMEOUT); timeout+=1; if (timeout == 20) { printf("Timeout while checking H2F DMA DONE!\n"); return -4; } } while (cur_dma_sts == 0); printf("DMA DONE Indicator: 0x%x\n",cur_dma_sts); if (status_is_success(status)) { dma_h2f_tpt.h2f_timestamp_end = time_get_ns(); } else{ ERRORSTR("Can't check DMA Completion Status!\n"); dma_h2f_tpt.h2f_timestamp_end = 0; return -4; } } return 0; } static void dma_regs_window() { ImGui::Begin("DMA Register Dump"); ImGui::Text("DMA Registers After Test Start"); dma_dump_regs(); ImGui::End(); } void F2hUpdateDescCount() { f2h_desc_comp_curr = pDrvr->read32(F2H_CPLT_DESC_COUNT); f2h_desc_comp_delta = f2h_desc_comp_curr - f2h_desc_comp_prev; f2h_desc_comp_prev = pDrvr->read32(F2H_CPLT_DESC_COUNT); } void H2fUpdateDescCount() { h2f_desc_comp_curr = pDrvr->read32(H2F_CPLT_DESC_COUNT); h2f_desc_comp_delta = h2f_desc_comp_curr - h2f_desc_comp_prev; h2f_desc_comp_prev = pDrvr->read32(H2F_CPLT_DESC_COUNT); } static void h2f_tpt_window(bool test_run, uint8_t desc_mode, uint64_t timestamp_1, uint64_t timestamp_2, size_t size, int num_desc) { uint32_t total_size = 0; float h2f_tpt_1 = 0; float h2f_tpt_2 = 0; float throughput = 0; uint64_t time_delta = 0; float deltaTime = ImGui::GetIO().DeltaTime; char h2f_overlay[32]; ImGui::Begin("DMA H2F Throughput"); if (test_run == false) { ImGui::Text("DMA H2F Throughput: 0"); } else if ((test_run == true) && (desc_mode == DESC_MODE_SINGLE)) { time_delta = timestamp_2-timestamp_1; if(time_delta <= 0) { time_delta = 1; ImGui::Text("Time Delta detected as 0 so changing it to 1"); } global_h2f_tpt = (size*num_desc)*(1000)/time_delta; sprintf(h2f_overlay, "H2F Throughput %0.2fMBps", global_h2f_tpt); float progress = global_h2f_tpt / 4000.0f; ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), h2f_overlay); } else if ((test_run == true) && (desc_mode == DESC_MODE_RING)) { h2f_tpt_1 = h2f_desc_comp_delta/h2f_total_entry_ret; h2f_tpt_2 = (total_size*h2f_tpt_1)/deltaTime; global_h2f_tpt = (h2f_tpt_2)/(MEGABYTE); sprintf(h2f_overlay, "H2F Ring Throughput %0.2fMBps", global_h2f_tpt); float progress = global_h2f_tpt / 4000.0f; ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), h2f_overlay); } ImGui::End(); } static void f2h_tpt_window(bool test_run, uint8_t desc_mode, uint64_t timestamp_1, uint64_t timestamp_2, size_t size, int num_desc) { uint32_t total_size = 0; float f2h_tpt_1 = 0; float f2h_tpt_2 = 0; float throughput = 0; float deltaTime = ImGui::GetIO().DeltaTime; uint64_t time_delta = 0; char f2h_overlay[32]; ImGui::Begin("DMA F2H Throughput"); if (test_run == false) { ImGui::Text("DMA F2H Throughput: 0"); } else if ((test_run == true) && (desc_mode == DESC_MODE_SINGLE)) { time_delta = timestamp_2-timestamp_1; if(time_delta <= 0) { time_delta = 1; ImGui::Text("Time Delta detected as 0 so changing it to 1"); } global_f2h_tpt = (size*num_desc)*(1000)/time_delta; sprintf(f2h_overlay, "F2H Throughput %0.2fMBps", global_f2h_tpt); float progress = global_f2h_tpt / 4000.0f; ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), f2h_overlay); } else if ((test_run == true) && (desc_mode == DESC_MODE_RING)) { f2h_tpt_1 = f2h_desc_comp_delta/f2h_total_entry_ret; f2h_tpt_2 = (total_size*f2h_tpt_1)/deltaTime; global_f2h_tpt = (f2h_tpt_2)/(MEGABYTE); sprintf(f2h_overlay, "F2H Ring Throughput %0.2fMBps", global_f2h_tpt); float progress = global_f2h_tpt / 4000.0f; ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f), f2h_overlay); } ImGui::End(); } static void h2f_buffer_window() { ImGui::BeginChild("H2F Buffer Dump"); if (!h2fbuf.empty()) { for (size_t i = 0; i < h2fbuf.size(); i++) { int* h2f_disp_buf = static_cast(h2fbuf[i]); size_t numInts = stored_size/32; ImGui::Text("Buffer %zu:", i); for (size_t j = 0; j < 4; j++) { ImGui::Text(" Element %zu: 0x%x", j, h2f_disp_buf[j]); } if ((numInts - 3) >= 4) { for (size_t k = (numInts - 3); k < numInts; k++) { ImGui::Text(" Element %zu: 0x%x", k, h2f_disp_buf[k]); } } } } ImGui::EndChild(); } static void f2h_buffer_window() { ImGui::BeginChild("F2H Buffer Dump"); if (!f2hbuf.empty()) { for (size_t i = 0; i < f2hbuf.size(); i++) { int* f2h_disp_buf = static_cast(f2hbuf[i]); size_t numInts = stored_size/32; ImGui::Text("Buffer %zu:", i); for (size_t j = 0; j < 4; j++) { ImGui::Text(" Element %zu: 0x%x", j, f2h_disp_buf[j]); } if ((numInts - 3) >= 4) { for (size_t k = (numInts - 3); k < numInts; k++) { ImGui::Text(" Element %zu: 0x%x", k, f2h_disp_buf[k]); } } } } ImGui::EndChild(); } static void buffer_compare_window() { ImGui::BeginChild("Buffer Comparison"); if (!h2fbuf.empty() && !f2hbuf.empty()) { size_t matches = 0; size_t mismatches = 0; for (size_t i = 0; i < h2fbuf.size() && i < f2hbuf.size(); i++) { int* h2f_disp_buf = static_cast(h2fbuf[i]); int* f2h_disp_buf = static_cast(f2hbuf[i]); size_t numInts = stored_size / 32; for (size_t j = 0; j < numInts; j++) { if (h2f_disp_buf[j] == f2h_disp_buf[j]) { matches++; } else { mismatches++; ImGui::Text("Mismatch at Descriptor %zu: F2H Buffer[%zu]", i, j); ImGui::Text("Expected: 0x%x | Received:0x%x", h2f_disp_buf[j], f2h_disp_buf[j]); } } } ImGui::Text("Matches: %zu", matches); ImGui::Text("Mismatches: %zu", mismatches); } ImGui::EndChild(); } void SetCustomTitleBarStyle() { ImGui::PushStyleColor(ImGuiCol_TitleBg, IM_COL32(255, 196, 36, 255)); // Yellow background ImGui::PushStyleColor(ImGuiCol_TitleBgActive, IM_COL32(255, 196, 36, 255)); // Yellow background when active ImGui::PushStyleColor(ImGuiCol_TitleBgCollapsed, IM_COL32(255, 196, 36, 255)); // Yellow background when collapsed ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 0, 0, 255)); // Black text } void ResetCustomTitleBarStyle() { ImGui::PopStyleColor(4); } static void glfw_error_callback(int error, const char* description) { fprintf(stderr, "GLFW Error %d: %s\n", error, description); } // Main code int main(int, char**) { char boardName[256]; char demoName[256]; uint32_t boardNum, maj, min; int status = 0; int ring_run_count = 0; int num_desc = 1; int size = 256; int total_size; int offset = 0; int write_value = 0; std::vector messages; #ifdef _LOG_FILE FILE* fp, *afp; #endif strcpy(boardName, "LSC"); strcpy(demoName, "DMA"); boardNum = 1; try { pDrvr = new PCIEDMA_IF(boardName, demoName, boardNum); } catch(std::exception &e) { ERRORSTR(e.what()); exit(-1); } glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) return 1; // GL 3.0 + GLSL 130 const char* glsl_version = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); // Create window with graphics context GLFWwindow* window = glfwCreateWindow(1440, 1000, "PCIE DMA DEMO", nullptr, nullptr); if (window == nullptr) return 1; glfwMakeContextCurrent(window); glfwSwapInterval(1); // Enable vsync // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImPlot::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style ImGui::StyleColorsDark(); // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init(glsl_version); io.Fonts->AddFontFromFileTTF("/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc", 20.0f); //todo: add handle for loading default font if this font not found int logo_width, logo_height, logo_channels; unsigned char* logo_data = stbi_load("../logo/LSCC_BIG.png", &logo_width, &logo_height, &logo_channels, 4); GLuint logo_texture; glGenTextures(1, &logo_texture); glBindTexture(GL_TEXTURE_2D, logo_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, logo_width, logo_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, logo_data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(logo_data); bool show_demo_window = false; bool show_mmio_dump = false; bool show_pci_cfg = false; bool show_debug_console = false; bool show_timestamps = false; ImVec4 clear_color = ImVec4(0.1f, 0.1f, 0.1f, 1.00f); // Main loop while (!glfwWindowShouldClose(window)) { glfwPollEvents(); if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) { ImGui_ImplGlfw_Sleep(10); continue; } ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); { static float f = 0.0f; static int counter = 0; ImGui::SetNextWindowPos(ImVec2(20, 60), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(650, 400), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("PCIE DMA Demo", nullptr, ImGuiWindowFlags_NoResize| ImGuiWindowFlags_NoMove); ResetCustomTitleBarStyle(); ImGui::InputInt("Number of Descriptors", &num_desc); ImGui::InputInt("Size", &size); total_size = num_desc * size; if (total_size > 0x20000) { size = 0x20000/num_desc; ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Maximum Total Size Allowed is 131072 or 0x20000"); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Setting Size To: %d", size); } // ImGui::Checkbox("Select to enable F2H Ring Buffer Mode", &f2h_desc_select); // if(f2h_desc_select == true) { // f2h_desc_mode = DESC_MODE_RING; // } // else { // f2h_desc_mode = DESC_MODE_SINGLE; // } // ImGui::Checkbox("Select to enable H2F Ring Buffer Mode", &h2f_desc_select); // if(h2f_desc_select == true) { // h2f_desc_mode = DESC_MODE_RING; // } // else { // h2f_desc_mode = DESC_MODE_SINGLE; // } f2h_desc_mode = DESC_MODE_SINGLE; h2f_desc_mode = DESC_MODE_SINGLE; ImGui::Checkbox("PCI Config Space Dump", &show_pci_cfg); ImGui::Checkbox("DMA Register Dump", &show_mmio_dump); ImGui::Checkbox("MMIO R/W Debug Console", &show_debug_console); ImGui::Checkbox("Show Timestamps", &show_timestamps); if (ImGui::Button("Start DMA Transfer")) { run_test = true; ring_run_count = 0; } if (run_test == true) { if (ring_run_count == 0) { stored_num_desc = num_desc; stored_size = size; status = dma_init(stored_size, stored_num_desc, h2f_desc_mode, f2h_desc_mode); if (status == -1) { messages.push_back("Error in Memory Allocation!"); run_test = false; } else if (status == -3) { messages.push_back("Error in H2F Descriptor Generation!"); run_test = false; } else if (status == -4) { messages.push_back("Error in F2H Descriptor Generation!"); run_test = false; } h2f_total_entry_ret = pDrvr->PcieDmaH2fEntriesRet(); f2h_total_entry_ret = pDrvr->PcieDmaF2hEntriesRet(); status = dma_h2f_transfer(h2f_desc_mode ? 1 : 0); if (!status_is_success(status)) { messages.push_back("Error in H2F Transfer!"); run_test = false; return -4; } messages.push_back("H2F DMA Transfer Completed Successfully"); status = dma_f2h_transfer(f2h_desc_mode ? 1 : 0); if (!status_is_success(status)) { messages.push_back("Error in F2H Transfer!"); run_test = false; return -4; } messages.push_back("F2H DMA Transfer Completed Successfully"); test_run = true; } if ((h2f_desc_mode == DESC_MODE_RING) || (f2h_desc_mode == DESC_MODE_RING)) { ring_run_count += 1; } if (ring_run_count == 0){ status = dma_stop(); if (status == -1) { messages.push_back("Buffers haven't been allocated yet!"); run_test = false; } else if (status == -2) { messages.push_back("Unable to Stop H2F DMA!"); run_test = false; } else if (status == -3) { messages.push_back("Unable to Stop F2H DMA!"); run_test = false; } run_test = false; } else if (ring_run_count == 300) { status = dma_stop(); if (status == -1) { messages.push_back("Buffers haven't been allocated yet!"); run_test = false; } else if (status == -2) { messages.push_back("Unable to Stop H2F DMA!"); run_test = false; } else if (status == -3) { messages.push_back("Unable to Stop F2H DMA!"); run_test = false; } } } ImGui::End(); } if (h2f_desc_mode == DESC_MODE_RING) { H2fUpdateDescCount(); } if (f2h_desc_mode == DESC_MODE_RING) { F2hUpdateDescCount(); } //Create Window to show H2F TPT ImGui::SetNextWindowPos(ImVec2(20, 460), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(325, 120), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("DMA H2F Throughput", nullptr, ImGuiWindowFlags_NoResize| ImGuiWindowFlags_NoMove); ResetCustomTitleBarStyle(); h2f_tpt_window(test_run, h2f_desc_mode ? 1 : 0, dma_h2f_tpt.h2f_timestamp_start, dma_h2f_tpt.h2f_timestamp_end, stored_size, stored_num_desc); ImGui::End(); //Create Window to show F2H TPT ImGui::SetNextWindowPos(ImVec2(345, 460), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(325, 120), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("DMA F2H Throughput", nullptr, ImGuiWindowFlags_NoResize| ImGuiWindowFlags_NoMove); ResetCustomTitleBarStyle(); f2h_tpt_window(test_run, f2h_desc_mode ? 1 : 0, dma_f2h_tpt.f2h_timestamp_start, dma_f2h_tpt.f2h_timestamp_end, stored_size, stored_num_desc); ImGui::End(); //Messages Window ImGui::SetNextWindowPos(ImVec2(20, 580), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(650, 150), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("Messages", nullptr, ImGuiWindowFlags_NoResize); ResetCustomTitleBarStyle(); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Messages:"); for (const auto& message : messages) { ImGui::Text("%s", message.c_str()); } ImGui::End(); //Creates Window with print out of current H2F Buffer ImGui::SetNextWindowPos(ImVec2(670, 60), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(650, 470), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("H2F Buffer Dump", nullptr, ImGuiWindowFlags_NoResize| ImGuiWindowFlags_NoMove); ResetCustomTitleBarStyle(); h2f_buffer_window(); ImGui::End(); //Creates Window with print out of current F2H Buffer ImGui::SetNextWindowPos(ImVec2(670, 530), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(650, 470), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("F2H Buffer Dump", nullptr, ImGuiWindowFlags_NoResize| ImGuiWindowFlags_NoMove); ResetCustomTitleBarStyle(); f2h_buffer_window(); ImGui::End(); //Creates Window which compares the H2F Buffer and F2H Buffer ImGui::SetNextWindowPos(ImVec2(20, 730), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(650, 270), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("Buffer Comparison", nullptr, ImGuiWindowFlags_NoResize| ImGuiWindowFlags_NoMove); ResetCustomTitleBarStyle(); buffer_compare_window(); ImGui::End(); //Company Logo ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - 1440, 0), ImGuiCond_Always); ImGui::SetNextWindowSize(ImVec2(1440, 60)); ImGui::Begin("LSCC Logo", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs); ImGui::Image((void*)(intptr_t)logo_texture, ImVec2(320, 40)); ImGui::End(); //Create Window to show DMA Register Dump if (show_mmio_dump) { ImGui::SetNextWindowPos(ImVec2(370, 25), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(650, 350), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("DMA Register Dump", nullptr, ImGuiWindowFlags_NoResize| ImGuiWindowFlags_NoMove); ResetCustomTitleBarStyle(); dma_regs_window(); if (ImGui::Button("Close Window")) show_mmio_dump = false; ImGui::End(); } //Creates Window which shows PCI CFG registers if checkbox is selected if (show_pci_cfg) { ImGui::SetNextWindowPos(ImVec2(370, 25), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(600, 350), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("PCI Config Space Dump", &show_pci_cfg); ResetCustomTitleBarStyle(); ImGui::Text("Reading PCI Config Space"); print_pci_cfg(); if (ImGui::Button("Close Window")) show_pci_cfg = false; ImGui::End(); } //Creates Window which allows users to read/write DMA registers if checkbox is selected if (show_debug_console) { ImGui::SetNextWindowPos(ImVec2(370, 375), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(600, 300), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("MMIO R/W Debug Console", &show_debug_console); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) ResetCustomTitleBarStyle(); ImGui::Text("Enter MMIO Offset (In Hex) to Read"); ImGui::InputText("MMIO Offset", offset_str, IM_ARRAYSIZE(offset_str), ImGuiInputTextFlags_CharsHexadecimal); ImGui::Text("Enter Data to Write"); ImGui::InputText("Write Data", write_value_str, IM_ARRAYSIZE(write_value_str), ImGuiInputTextFlags_CharsHexadecimal); // Convert hex strings to integers int offset = strtol(offset_str, nullptr, 16); int write_value = strtol(write_value_str, nullptr, 16); if (ImGui::Button("Read from Register")) { read_value = pDrvr->read32(offset); } if (ImGui::Button("Write to Register")) { pDrvr->write32(offset, write_value); read_value = pDrvr->read32(offset); } ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Offset 0x%x: Read Value: 0x%x", offset, read_value); if (ImGui::Button("Close Debug Console")) show_debug_console = false; ImGui::End(); } //Creates Window which shows the current Start and End Timestamps of H2F and F2H if checkbox is selected if (show_timestamps) { ImGui::SetNextWindowPos(ImVec2(370, 675), ImGuiCond_None); ImGui::SetNextWindowSize(ImVec2(600, 200), ImGuiCond_None); SetCustomTitleBarStyle(); ImGui::Begin("DMA Transfer Timestamps", &show_timestamps); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) ResetCustomTitleBarStyle(); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "DMA H2F Timestamp Start: %ldns",dma_h2f_tpt.h2f_timestamp_start); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "DMA H2F Timestamp End: %ldns",dma_h2f_tpt.h2f_timestamp_end); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "DMA F2H Timestamp Start: %ldns",dma_f2h_tpt.f2h_timestamp_start); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "DMA F2H Timestamp End: %ldns",dma_f2h_tpt.f2h_timestamp_end); if (ImGui::Button("Close Timestamp Window")) show_timestamps = false; ImGui::End(); } // Rendering ImGui::Render(); int display_w, display_h; glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); } if (buffers_ready) { for (size_t i = 0; i < h2fbuf.size(); i++) { free(h2fbuf[i]); } for (size_t i = 0; i < f2hbuf.size(); i++) { free(f2hbuf[i]); } } // Cleanup ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImPlot::DestroyContext(); ImGui::DestroyContext(); glfwDestroyWindow(window); glfwTerminate(); return 0; } static void signal_handler(int sig) { if (SIGINT == sig) { cout<<"EXIT!" <