summaryrefslogtreecommitdiff
path: root/python/openvino/runtime/coredla_device/mmd/system_console
diff options
context:
space:
mode:
authorEric Dao <eric@erickhangdao.com>2025-03-10 17:54:31 -0400
committerEric Dao <eric@erickhangdao.com>2025-03-10 17:54:31 -0400
commitab224e2e6ba65f5a369ec392f99cd8845ad06c98 (patch)
treea1e757e9341863ed52b8ad4c5a1c45933aab9da4 /python/openvino/runtime/coredla_device/mmd/system_console
parent40da1752f2c8639186b72f6838aa415e854d0b1d (diff)
downloadthesis-master.tar.gz
thesis-master.tar.bz2
thesis-master.zip
completed thesisHEADmaster
Diffstat (limited to 'python/openvino/runtime/coredla_device/mmd/system_console')
-rw-r--r--python/openvino/runtime/coredla_device/mmd/system_console/CMakeLists.txt2
-rw-r--r--python/openvino/runtime/coredla_device/mmd/system_console/mmd_wrapper.cpp320
-rw-r--r--python/openvino/runtime/coredla_device/mmd/system_console/system_console_script.tcl79
3 files changed, 401 insertions, 0 deletions
diff --git a/python/openvino/runtime/coredla_device/mmd/system_console/CMakeLists.txt b/python/openvino/runtime/coredla_device/mmd/system_console/CMakeLists.txt
new file mode 100644
index 0000000..d8be216
--- /dev/null
+++ b/python/openvino/runtime/coredla_device/mmd/system_console/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_library(system_console_mmd INTERFACE)
diff --git a/python/openvino/runtime/coredla_device/mmd/system_console/mmd_wrapper.cpp b/python/openvino/runtime/coredla_device/mmd/system_console/mmd_wrapper.cpp
new file mode 100644
index 0000000..64c6631
--- /dev/null
+++ b/python/openvino/runtime/coredla_device/mmd/system_console/mmd_wrapper.cpp
@@ -0,0 +1,320 @@
+// Copyright 2020-2024 Intel Corporation.
+//
+// This software and the related documents are Intel copyrighted materials,
+// and your use of them is governed by the express license under which they
+// were provided to you ("License"). Unless the License provides otherwise,
+// you may not use, modify, copy, publish, distribute, disclose or transmit
+// this software or the related documents without Intel's prior written
+// permission.
+//
+// This software and the related documents are provided as is, with no express
+// or implied warranties, other than those that are expressly stated in the
+// License.
+
+#include "mmd_wrapper.h"
+#include "dla_dma_constants.h" // DLA_DMA_CSR_OFFSET_***
+
+#include <cassert> // assert
+#include <cstddef> // size_t
+#include <iostream> // std::cerr
+#include <stdexcept> // std::runtime_error
+#include <string> // std::string
+
+#include <boost/process.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/format.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/process/environment.hpp>
+#include <string>
+#include <iostream>
+#include <string>
+#include <cstdio>
+#include <sstream>
+#include <ostream>
+
+#define xstr(s) _str(s)
+#define _str(s) #s
+
+// All board variants must obey the CoreDLA CSR spec, which says that all access must be
+// - 32 bits in size
+// - address must be 4 byte aligned
+// - within the address range, CSR size is 2048 bytes
+constexpr uint64_t DLA_CSR_ALIGNMENT = 4;
+constexpr uint64_t DLA_CSR_SIZE = 2048;
+namespace bp = boost::process; //we will assume this for all further examples
+
+constexpr auto max_size = std::numeric_limits<std::streamsize>::max();
+
+static const boost::filesystem::path system_console_path("/home/pmclean/intelfpga_pro/23.4/qprogrammer/syscon/bin/system-console");
+static boost::filesystem::path temp_file_path;
+static boost::filesystem::path tcl_file_path;
+static boost::filesystem::path sof_file_path;
+static uint32_t enable_pmon;
+static bool preserve_temp_files;
+
+const uint32_t DLA_CSR_BASE_ADDRESS = 0x80000000;
+const uint32_t DLA_DDR_BASE_ADDRESS = 0x0;
+
+
+static bp::opstream in;
+static bp::ipstream out;
+static bp::child subprocess;
+
+static int capture_till_prompt(bp::ipstream& out, std::ostream& capture)
+{
+ std::array<char, 4096> line_buffer;
+ if (out.fail()) {
+ std::cout << "EOF" << std::endl;
+ return 1;
+ }
+
+ do {
+ out.clear();
+ out.getline(&line_buffer[0], (std::streamsize)line_buffer.size(), '%');
+ capture.write(&line_buffer[0], out.gcount());
+ // If out.getline fills the line buffer without encountering the delimiter
+ // then the failbit of out will be set, causing out.fail() to return true.
+ // bp::ipstream indirectly inherits std::ios_base::iostate, which defines failbit/badbit
+ } while (out.fail() && (static_cast<long unsigned int> (out.gcount()) == line_buffer.size()-1));
+
+ if (out.fail()) {
+ std::cout << "EOF" << std::endl;
+ return 1;
+ }
+ return 0;
+}
+
+static int wait_for_prompt(bp::ipstream& out)
+{
+ return capture_till_prompt(out, std::cout);
+}
+
+std::string remove_non_alphanumeric(const std::string& input) {
+ std::string result = input;
+ result.erase(std::remove_if(result.begin(), result.end(), [](unsigned char c) {
+ return !std::isalnum(c);
+ }), result.end());
+ return result;
+}
+
+static void send_command(bp::opstream& in, std::string command)
+{
+ in << command << "\n";
+ in.flush();
+}
+
+static void write_to_csr(bp::opstream& in, bp::ipstream& out, uint32_t addr, uint32_t data) {
+ addr += DLA_CSR_BASE_ADDRESS;
+ send_command(in, "master_write_32 $::g_dla_csr_service " + str( boost::format("0x%|08x| 0x%|08x|") % addr % data));
+ if (0 != wait_for_prompt(out))
+ {
+ throw std::runtime_error("Unexpected EOF");
+ }
+}
+
+static uint32_t read_from_csr(bp::opstream& in, bp::ipstream& out, uint32_t addr) {
+ if (addr == DLA_DMA_CSR_OFFSET_INTERRUPT_MASK)
+ {
+ return 3;
+ }
+ if (addr == DLA_DMA_CSR_OFFSET_LICENSE_FLAG)
+ {
+ return 1;
+ }
+ addr += DLA_CSR_BASE_ADDRESS;
+ send_command(in, "master_read_32 $::g_dla_csr_service " + str( boost::format("0x%|08x|") % addr ) + " 1");
+ std::basic_stringstream<char> s1;
+ std::string captured;
+ do {
+ if (0 != capture_till_prompt(out, s1))
+ {
+ throw std::runtime_error("Unexpected EOF");
+ }
+ captured = s1.str();
+ } while (std::all_of(captured.begin(), captured.end(), [](unsigned char c){return (std::isspace(c) || std::iscntrl(c));}));
+ std::string trimmed = remove_non_alphanumeric(captured);
+
+ uint32_t data = std::stoul(trimmed, nullptr, 16);
+
+ return data;
+}
+
+static void read_from_ddr(bp::opstream& in, bp::ipstream& out, uint64_t addr, uint64_t length, void* data)
+{
+ if (data == nullptr)
+ {
+ throw std::runtime_error("null data");
+ }
+ boost::filesystem::path temp_file_name = boost::filesystem::unique_path();
+ boost::filesystem::path temppath = temp_file_path / temp_file_name;
+ send_command(in, "master_read_to_file $::g_emif_ddr_service " + temppath.generic_string() + str( boost::format(" 0x%|08x| 0x%|08x|") % addr % length ) );
+ if (0 != wait_for_prompt(out)) {
+ throw std::runtime_error("Unexpected EOF");
+ }
+ boost::filesystem::ifstream ifs(temppath, std::ios::in | std::ios::binary);
+ ifs.read(static_cast<char *>(data), length);
+ ifs.close();
+
+ if (!preserve_temp_files) {
+ try {
+ boost::filesystem::remove(temppath);
+ } catch (const boost::filesystem::filesystem_error& ex) {
+ std::cerr << "Error removing file: " << ex.what() << std::endl;
+ }
+ }
+}
+
+static void write_to_ddr(bp::opstream& in, bp::ipstream& out, uint64_t addr, uint64_t length, const void* data)
+{
+ boost::filesystem::path temp_file_name = boost::filesystem::unique_path();
+ boost::filesystem::path temppath = temp_file_path / temp_file_name;
+ boost::filesystem::ofstream ofs(temppath, std::ios::out | std::ios::binary);
+ if (ofs.fail()) {
+ throw std::runtime_error("Failed to access the temporary file " + temppath.generic_string());
+ }
+ ofs.write(static_cast<const char *>(data), length);
+ ofs.close();
+ send_command(in, "master_write_from_file $::g_emif_ddr_service " + temppath.generic_string() + str( boost::format(" 0x%|08x|") % addr ) );
+ if (0 != wait_for_prompt(out))
+ {
+ throw std::runtime_error("Unexpected EOF");
+ }
+
+ if (!preserve_temp_files) {
+ try {
+ boost::filesystem::remove(temppath);
+ } catch (const boost::filesystem::filesystem_error& ex) {
+ std::cerr << "Error removing file: " << ex.what() << std::endl;
+ }
+ }
+}
+
+MmdWrapper::MmdWrapper() {
+ // Check for the envrionment variable
+ auto env = boost::this_process::environment();
+ tcl_file_path = env.find("DLA_SYSCON_SOURCE_FILE") != env.end() ?
+ boost::filesystem::path(env["DLA_SYSCON_SOURCE_FILE"].to_string()) :
+ boost::filesystem::path(xstr(DLA_SYSCON_SOURCE_ROOT)) / "system_console_script.tcl";
+ if (!boost::filesystem::exists(tcl_file_path)) {
+ throw std::runtime_error("Cannot locate " + tcl_file_path.generic_string() + ". Please specify the path of the Tcl setup script by defining the environment variable DLA_SYSCON_SOURCE_FILE\n");
+ } else {
+ std::cout <<"Using the Tcl setup script at "<<tcl_file_path.generic_string()<<std::endl;
+ }
+
+ temp_file_path = env.find("DLA_TEMP_DIR") != env.end() ?
+ boost::filesystem::path(env["DLA_TEMP_DIR"].to_string()) :
+ boost::filesystem::current_path();
+ if (!boost::filesystem::exists(temp_file_path)) {
+ throw std::runtime_error("The temporary file storage directory specified via the environment variable DLA_TEMP_DIR does not exist.\n");
+ } else {
+ std::cout <<"Saving temporary files to "<<temp_file_path.generic_string()<<std::endl;
+ }
+
+ sof_file_path = env.find("DLA_SOF_PATH") != env.end() ?
+ boost::filesystem::path(env["DLA_SOF_PATH"].to_string()):
+ boost::filesystem::current_path() / "top.sof";
+ if (!boost::filesystem::exists(sof_file_path)) {
+ throw std::runtime_error("Cannot find the FPGA bitstream (.sof). Please specify its location via the environment variable DLA_SOF_PATH,"\
+ " or copy it as top.sof to the current working directory.\n");
+ } else {
+ std::cout <<"Using the FPGA bitstream at "<<sof_file_path.generic_string()<<" to configure the JTAG connection"<<std::endl;
+ }
+
+ boost::filesystem::path system_console_path = bp::search_path("system-console");
+ if (system_console_path.empty()) {
+ throw std::runtime_error("Cannot find system-console in system PATH!\n");
+
+ }
+ enable_pmon = env.find("DLA_ENABLE_PMON") != env.end() ? 1 : 0;
+
+ preserve_temp_files = env.find("DLA_PRESERVE_TEMP_FILES") != env.end() ? true : false;
+
+ subprocess = bp::child(system_console_path, "-cli", bp::std_out > out, bp::std_in < in);
+ if (wait_for_prompt(out))
+ {
+ throw std::runtime_error("Could not find initial prompt");
+ }
+ send_command(in, "set ::cl(sof) " + sof_file_path.generic_string());
+ if (enable_pmon == 1) {
+ send_command(in, "set ::cl(enable_pmon) 1");
+ }
+ send_command(in, "source " + tcl_file_path.generic_string());
+ std::basic_stringstream<char> s1;
+ if (0 != capture_till_prompt(out, s1))
+ {
+ throw std::runtime_error("Could not find prompt after source");
+ }
+ std::string captured(s1.str());
+
+ // Reset the IP
+ write_to_csr(in, out, DLA_DMA_CSR_OFFSET_IP_RESET, 1);
+ // Constants of the design
+ maxInstances_ = 1;
+ ddrSizePerInstance_ = 0x80000000;
+ // Need to change the frequencies below when their counterparts in the Qsys system are modified
+ coreDlaClockFreq_ = 200;
+ ddrClockFreq_ = 200;
+ // Initialize the handle_ object to a dummy value. It is not relevant to this MMD
+ handle_ = 0;
+}
+
+MmdWrapper::~MmdWrapper() {
+ send_command(in, "close_services");
+ if (wait_for_prompt(out))
+ {
+ std::cout << "Could not find prompt after attempting to close system console services\n";
+ }
+ send_command(in, "exit");
+ try {
+ subprocess.terminate();
+ std::cout << "Successfully closed JTAG services.\n";
+ } catch (const boost::process::process_error& e) {
+ std::cerr << "Failed to terminate the system-console process due to reason: " << e.what() << std::endl;
+ }
+}
+
+void MmdWrapper::RegisterISR(interrupt_service_routine_signature func, void *data) const {
+ throw std::runtime_error("System Console plugin requires polling");
+}
+
+void MmdWrapper::WriteToCsr(int instance, uint32_t addr, uint32_t data) const {
+ write_to_csr(in, out, addr, data);
+}
+
+uint32_t MmdWrapper::ReadFromCsr(int instance, uint32_t addr) const {
+ return read_from_csr(in, out, addr);
+}
+
+void MmdWrapper::WriteToDDR(int instance, uint64_t addr, uint64_t length, const void *data) const {
+ write_to_ddr(in, out, addr, length, data);
+}
+
+void MmdWrapper::ReadFromDDR(int instance, uint64_t addr, uint64_t length, void *data) const {
+ read_from_ddr(in, out, addr, length, data);
+}
+
+#ifndef STREAM_CONTROLLER_ACCESS
+// Stream controller access is not supported by the platform abstraction
+bool MmdWrapper::bIsStreamControllerValid(int instance) const { return false; }
+
+// 32-bit handshake with each Stream Controller CSR
+void MmdWrapper::WriteToStreamController(int instance, uint32_t addr, uint64_t length, const void *data) const {
+ assert(false);
+}
+
+void MmdWrapper::ReadFromStreamController(int instance, uint32_t addr, uint64_t length, void *data) const {
+ assert(false);
+}
+#else
+// If the mmd layer supports accesses to the Stream Controller
+bool MmdWrapper::bIsStreamControllerValid(int instance) const {
+ return false;
+}
+
+// 32-bit handshake with each Stream Controller CSR
+void MmdWrapper::WriteToStreamController(int instance, uint32_t addr, uint64_t length, const void *data) const {
+}
+
+void MmdWrapper::ReadFromStreamController(int instance, uint32_t addr, uint64_t length, void *data) const {
+}
+#endif
diff --git a/python/openvino/runtime/coredla_device/mmd/system_console/system_console_script.tcl b/python/openvino/runtime/coredla_device/mmd/system_console/system_console_script.tcl
new file mode 100644
index 0000000..9e0e386
--- /dev/null
+++ b/python/openvino/runtime/coredla_device/mmd/system_console/system_console_script.tcl
@@ -0,0 +1,79 @@
+# Author: linqiaol
+# Purpose: Perform write-read tests on external memory and CoreDLA CSR to make sure the registers can be accessed from host.
+
+# Declare and initialize CL arguments
+if {![info exists ::cl(sof)]} {
+ set ::cl(sof) "top.sof"
+}
+
+if {![info exists ::cl(enable_pmon)]} {
+ set ::cl(enable_pmon) 0
+}
+
+# Declare global variables
+set ::g_emif_calip_service ""
+set ::g_emif_ddr_service ""
+set ::g_dla_csr_service ""
+set ::g_pmon_service ""
+
+# Declare some contants
+set ::g_const_master_offset_emif 0x0
+set ::g_const_master_range_emif 0x080000000
+set ::g_const_master_offset_dla 0x080000000
+set ::g_const_master_range_dla 0x000001000
+
+#{{{ load_sof
+proc load_sof {} {
+ puts "loading sof: $::cl(sof)"
+ design_load $::cl(sof)
+}
+#}}}
+
+#{{{claim_emif_ddr_service
+proc claim_emif_ddr_service {} {
+ set all_master_paths [get_service_paths master]
+ set path [lindex $all_master_paths [lsearch -glob $all_master_paths *jtag*master*]]
+ set service [claim_service master $path {} "\{${::g_const_master_offset_emif} ${::g_const_master_range_emif} EXCLUSIVE\}"]
+ return $service
+}
+#}}}
+
+#{{{claim_dla_csr_service
+proc claim_dla_csr_service {} {
+ set all_master_paths [get_service_paths master]
+ set path [lindex $all_master_paths [lsearch -glob $all_master_paths *jtag*master*]]
+ set service [claim_service master $path {} "\{${::g_const_master_offset_dla} ${::g_const_master_range_dla} EXCLUSIVE\}"]
+ return $service
+}
+#}}}
+
+#{{{claim_pmon_service
+proc claim_pmon_service {} {
+ set all_master_paths [get_service_paths master]
+ set path [lindex $all_master_paths [lsearch -glob $all_master_paths *pmon*master*]]
+ set service [claim_service master $path {} {{0x0 0x00001000 EXCLUSIVE}}]
+ return $service
+}
+#}}}
+
+proc initialization {} {
+ load_sof
+ puts "Claim required services"
+ set ::g_dla_csr_service [claim_dla_csr_service]
+ set ::g_emif_ddr_service [claim_emif_ddr_service]
+ if {$::cl(enable_pmon) == 1} {
+ puts "Claiming JTAG service to the AXI4 performance monitor"
+ set ::g_pmon_service [claim_pmon_service]
+ }
+}
+
+proc close_services {} {
+ close_service master $::g_dla_csr_service
+ if {$::cl(enable_pmon) == 1} {
+ close_service master $::g_pmon_service
+ }
+ close_service master $::g_emif_ddr_service
+ puts "Closed DLA JTAG services"
+}
+
+initialization \ No newline at end of file