From 3b43fe778fd435554c18263cda6de31ce121b2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20Andr=C3=A9s=20Obreg=C3=B3n=20Fonseca?= Date: Sun, 21 Jul 2024 23:39:04 -0600 Subject: [PATCH 1/8] Adding image to the VGA testbench to send the RGB pixels --- modules/vga/include/vga.hpp | 21 +++-- modules/vga/src/vga_tb.cpp | 166 +++++++++++++++++++++++++++++++----- 2 files changed, 160 insertions(+), 27 deletions(-) diff --git a/modules/vga/include/vga.hpp b/modules/vga/include/vga.hpp index 3155dd8..ff353a9 100644 --- a/modules/vga/include/vga.hpp +++ b/modules/vga/include/vga.hpp @@ -43,15 +43,21 @@ SC_MODULE(vga) public: // Input clock sc_core::sc_in clk; + // Input pixel + sc_core::sc_in > red; + sc_core::sc_in > green; + sc_core::sc_in > blue; // Output horizontal synch sc_core::sc_out o_hsync; // Output vertical synch sc_core::sc_out o_vsync; -#ifdef IPS_DEBUG_EN - // For debug - sc_core::sc_out o_h_count; - sc_core::sc_out o_v_count; -#endif // IPS_DEBUG_EN + // Counter outputs + sc_core::sc_out o_h_count; + sc_core::sc_out o_v_count; + // Output pixel + sc_core::sc_out > o_red; + sc_core::sc_out > o_green; + sc_core::sc_out > o_blue; SC_CTOR(vga) : o_hsync("o_hsync"), o_vsync("o_vsync") { @@ -126,10 +132,11 @@ SC_MODULE(vga) } } -#ifdef IPS_DEBUG_EN this->o_v_count.write(this->v_count); this->o_h_count.write(this->h_count); -#endif // IPS_DEBUG_EN + this->o_red.write(this->red.read()); + this->o_green.write(this->green.read()); + this->o_blue.write(this->blue.read()); } } }; diff --git a/modules/vga/src/vga_tb.cpp b/modules/vga/src/vga_tb.cpp index 80e0875..971e7a9 100644 --- a/modules/vga/src/vga_tb.cpp +++ b/modules/vga/src/vga_tb.cpp @@ -1,10 +1,22 @@ +#define int64 systemc_int64 +#define uint64 systemc_uint64 #include +#undef int64 +#undef uint64 +#define int64 opencv_int64 +#define uint64 opencv_uint64 +#include +#undef int64 +#undef uint64 + #include "vga.hpp" -// Main clock frequency in Hz - 120 MHz -#define CLK_FREQ 120000000 +// Image path +#define IPS_IMG_PATH_TB "../../tools/datagen/src/imgs/car_rgb_noisy_image.jpg" +// Main clock frequency in Hz - 25.175 MHz +#define CLK_FREQ 25175000 // VGA settings #define H_ACTIVE 640 #define H_FP 16 @@ -15,12 +27,53 @@ #define V_SYNC_PULSE 2 #define V_BP 33 // Compute the total number of pixels -#define TOTAL_PIXELES ((H_ACTIVE + H_FP + H_SYNC_PULSE + H_BP) *\ - (V_ACTIVE + V_FP + V_SYNC_PULSE + V_BP)) +#define TOTAL_VERTICAL (H_ACTIVE + H_FP + H_SYNC_PULSE + H_BP) +#define TOTAL_HORIZONTAL (V_ACTIVE + V_FP + V_SYNC_PULSE + V_BP) +#define TOTAL_PIXELES (TOTAL_VERTICAL * TOTAL_HORIZONTAL) int sc_main(int, char*[]) { + // Read image + const std::string img_path = IPS_IMG_PATH_TB; + + cv::Mat read_img = cv::imread(img_path, cv::IMREAD_COLOR); + + // CV_8UC3 Type: 8-bit unsigned, 3 channels (e.g., for a color image) + cv::Mat tx_img; + read_img.convertTo(tx_img, CV_8UC3); + + cv::Mat rx_data(TOTAL_HORIZONTAL, TOTAL_VERTICAL, CV_8UC3); + cv::Mat rx_img(tx_img.size(), CV_8UC3); + +#ifdef IPS_DEBUG_EN + std::cout << "Loading image: " << img_path << std::endl; +#endif // IPS_DEBUG_EN + + // Check if the image is loaded successfully + if (tx_img.empty()) + { + std::cerr << "Error: Could not open or find the image!" << std::endl; + exit(EXIT_FAILURE); + } + +#ifdef IPS_DEBUG_EN + std::cout << "TX image info: "; + std::cout << "rows = " << tx_img.rows; + std::cout << " cols = " << tx_img.cols; + std::cout << " channels = " << tx_img.channels() << std::endl; + + std::cout << "RX data info: "; + std::cout << "rows = " << rx_data.rows; + std::cout << " cols = " << rx_data.cols; + std::cout << " channels = " << rx_data.channels() << std::endl; + + std::cout << "RX image info: "; + std::cout << "rows = " << rx_img.rows; + std::cout << " cols = " << rx_img.cols; + std::cout << " channels = " << rx_img.channels() << std::endl; +#endif // IPS_DEBUG_EN + // Compute the clock time in seconds const double CLK_TIME = 1.0 / static_cast(CLK_FREQ); // Compute the total simulation based on the total amount of pixels in the @@ -28,13 +81,19 @@ int sc_main(int, char*[]) const double SIM_TIME = CLK_TIME * static_cast(TOTAL_PIXELES); // Signals to use + // -- Inputs sc_core::sc_clock clk("clk", CLK_TIME, sc_core::SC_SEC); + sc_core::sc_signal > s_tx_red; + sc_core::sc_signal > s_tx_green; + sc_core::sc_signal > s_tx_blue; + // -- Outputs sc_core::sc_signal s_hsync; sc_core::sc_signal s_vsync; -#ifdef IPS_DEBUG_EN - sc_core::sc_signal s_h_count; - sc_core::sc_signal s_v_count; -#endif // IPS_DEBUG_EN + sc_core::sc_signal s_h_count; + sc_core::sc_signal s_v_count; + sc_core::sc_signal > s_rx_red; + sc_core::sc_signal > s_rx_green; + sc_core::sc_signal > s_rx_blue; // VGA module instanciation and connections vga< @@ -42,37 +101,104 @@ int sc_main(int, char*[]) V_ACTIVE, V_FP, V_SYNC_PULSE, V_BP > ips_vga("ips_vga"); ips_vga.clk(clk); + ips_vga.red(s_tx_red); + ips_vga.green(s_tx_green); + ips_vga.blue(s_tx_blue); ips_vga.o_hsync(s_hsync); ips_vga.o_vsync(s_vsync); -#ifdef IPS_DEBUG_EN ips_vga.o_h_count(s_h_count); ips_vga.o_v_count(s_v_count); -#endif // IPS_DEBUG_EN + ips_vga.o_red(s_rx_red); + ips_vga.o_green(s_rx_green); + ips_vga.o_blue(s_rx_blue); // Signals to dump #ifdef IPS_DUMP_EN - sca_util::sca_trace_file* tf = sca_util::sca_create_vcd_trace_file("ips_vga"); + sc_trace_file* wf = sc_create_vcd_trace_file("ips_vga"); - sca_trace(tf, clk, "clk"); - sca_trace(tf, s_hsync, "hsync"); - sca_trace(tf, s_vsync, "vsync"); -#ifdef IPS_DEBUG_EN - sca_trace(tf, s_h_count, "h_count"); - sca_trace(tf, s_v_count, "v_count"); -#endif // IPS_DEBUG_EN + sc_trace(wf, clk, "clk"); + sc_trace(wf, s_tx_red, "tx_red"); + sc_trace(wf, s_tx_green, "tx_green"); + sc_trace(wf, s_tx_blue, "tx_blue"); + sc_trace(wf, s_hsync, "hsync"); + sc_trace(wf, s_vsync, "vsync"); + sc_trace(wf, s_h_count, "h_count"); + sc_trace(wf, s_v_count, "v_count"); + sc_trace(wf, s_rx_red, "rx_red"); + sc_trace(wf, s_rx_green, "rx_green"); + sc_trace(wf, s_rx_blue, "rx_blue"); #endif // IPS_DUMP_EN // Start time std::cout << "@" << sc_time_stamp() << std::endl; - sc_start(SIM_TIME, sc_core::SC_SEC); + double total_sim_time = 0.0; + + while (SIM_TIME > total_sim_time) + { + const int IMG_ROW = s_v_count.read() - (V_SYNC_PULSE + V_BP); + const int IMG_COL = s_h_count.read() - (H_SYNC_PULSE + H_BP); + +#ifdef IPS_DEBUG_EN + std::cout << "TX image: "; + std::cout << "row = " << IMG_ROW; + std::cout << " col = " << IMG_COL; +#endif // IPS_DEBUG_EN + + if ((IMG_ROW < 0) || (IMG_COL < 0) || (IMG_ROW >= V_ACTIVE) || (IMG_COL >= H_ACTIVE)) + { + s_tx_red.write(0); + s_tx_green.write(0); + s_tx_blue.write(0); + +#ifdef IPS_DEBUG_EN + std::cout << " dpixel = (0,0,0) " << std::endl; +#endif // IPS_DEBUG_EN + } + else + { + cv::Vec3b pixel = tx_img.at(IMG_ROW, IMG_COL, 0); + + s_tx_red.write(static_cast >(pixel[0])); + s_tx_green.write(static_cast >(pixel[1])); + s_tx_blue.write(static_cast >(pixel[2])); + +#ifdef IPS_DEBUG_EN + std::cout << " ipixel = (" << static_cast(pixel[0]) << "," + << static_cast(pixel[1]) << "," << static_cast(pixel[2]) + << ")" << std::endl; +#endif // IPS_DEBUG_EN + } + + total_sim_time += CLK_TIME; + sc_start(CLK_TIME, sc_core::SC_SEC); + + if ((IMG_ROW < 0) || (IMG_COL < 0) || (IMG_ROW >= V_ACTIVE) || (IMG_COL >= H_ACTIVE)) + { + cv::Vec3b pixel(0, 0, 0); + rx_data.at(s_v_count.read(), s_h_count.read()) = pixel; + } + else + { + cv::Vec3b pixel = cv::Vec3b(s_rx_red.read(), s_rx_green.read(), s_rx_blue.read()); + rx_data.at(s_v_count.read(), s_h_count.read()) = pixel; + rx_img.at(IMG_ROW, IMG_COL) = pixel; + } + } // End time std::cout << "@" << sc_time_stamp() << std::endl; #ifdef IPS_DUMP_EN - sca_util::sca_close_vcd_trace_file(tf); + sc_close_vcd_trace_file(wf); #endif // IPS_DUMP_EN + // Show the images in their respective windows + cv::imshow("TX image", tx_img); + cv::imshow("RX image", rx_img); + + // Wait for a key press indefinitely to keep the windows open + cv::waitKey(0); + return 0; } From 68bf28cac84db03a20fe4dd6dc16bdd1d8b68861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20Andr=C3=A9s=20Obreg=C3=B3n=20Fonseca?= Date: Mon, 22 Jul 2024 19:55:22 -0600 Subject: [PATCH 2/8] Fixing active and unactive zones of the VGA vsync and hsync --- modules/vga/include/vga.hpp | 13 ++++++------- modules/vga/src/vga_tb.cpp | 3 +++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/vga/include/vga.hpp b/modules/vga/include/vga.hpp index ff353a9..4c66a1a 100644 --- a/modules/vga/include/vga.hpp +++ b/modules/vga/include/vga.hpp @@ -24,6 +24,7 @@ * the next display period */ template < + unsigned int N = 8, unsigned int H_ACTIVE = 640, unsigned int H_FP = 16, unsigned int H_SYNC_PULSE = 96, @@ -89,21 +90,19 @@ SC_MODULE(vga) { this->o_hsync.write(IPS_VGA_ACTIVE); } - // End of H-sync pulse else if (this->h_count == (H_SYNC_PULSE + H_BP)) { this->o_hsync.write(IPS_VGA_ACTIVE); } - // H front porch else if (this->h_count == (H_SYNC_PULSE + H_BP + H_ACTIVE)) { - this->o_hsync.write(IPS_VGA_INACTIVE); + this->o_hsync.write(IPS_VGA_ACTIVE); } // End of HSYNC else if (this->h_count == (H_SYNC_PULSE + H_BP + H_ACTIVE + H_FP)) { // Restart H counter - this->o_hsync.write(IPS_VGA_ACTIVE); + this->o_hsync.write(IPS_VGA_INACTIVE); this->h_count = 0; // Increment H counter @@ -112,7 +111,7 @@ SC_MODULE(vga) // VSYNC pulse if (this->v_count == V_SYNC_PULSE) { - this->o_vsync.write(IPS_VGA_INACTIVE); + this->o_vsync.write(IPS_VGA_ACTIVE); } // End of V-sync pulse else if (this->v_count == (V_SYNC_PULSE + V_BP)) @@ -122,12 +121,12 @@ SC_MODULE(vga) // V front porch else if (this->v_count == (V_SYNC_PULSE + V_BP + V_ACTIVE)) { - this->o_vsync.write(IPS_VGA_INACTIVE); + this->o_vsync.write(IPS_VGA_ACTIVE); } // End of VSYNC else if (this->v_count == (V_SYNC_PULSE + V_BP + V_ACTIVE + V_FP)) { - this->o_vsync.write(IPS_VGA_ACTIVE); + this->o_vsync.write(IPS_VGA_INACTIVE); this->v_count = 0; } } diff --git a/modules/vga/src/vga_tb.cpp b/modules/vga/src/vga_tb.cpp index 971e7a9..f7a4a32 100644 --- a/modules/vga/src/vga_tb.cpp +++ b/modules/vga/src/vga_tb.cpp @@ -30,6 +30,8 @@ #define TOTAL_VERTICAL (H_ACTIVE + H_FP + H_SYNC_PULSE + H_BP) #define TOTAL_HORIZONTAL (V_ACTIVE + V_FP + V_SYNC_PULSE + V_BP) #define TOTAL_PIXELES (TOTAL_VERTICAL * TOTAL_HORIZONTAL) +// Number of bits for ADC, DAC and VGA +#define BITS 8 int sc_main(int, char*[]) @@ -97,6 +99,7 @@ int sc_main(int, char*[]) // VGA module instanciation and connections vga< + BITS, H_ACTIVE, H_FP, H_SYNC_PULSE, H_BP, V_ACTIVE, V_FP, V_SYNC_PULSE, V_BP > ips_vga("ips_vga"); From 4e470bb4721e35afa203e85a35c555a226c44876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20Andr=C3=A9s=20Obreg=C3=B3n=20Fonseca?= Date: Mon, 22 Jul 2024 19:56:37 -0600 Subject: [PATCH 3/8] Adding mapping technology params for the DAC --- modules/dac/include/dac.hpp | 2 +- modules/dac/include/seq_item_dac.hpp | 2 +- modules/dac/src/tb_dac.cpp | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/dac/include/dac.hpp b/modules/dac/include/dac.hpp index ce80f75..5058067 100644 --- a/modules/dac/include/dac.hpp +++ b/modules/dac/include/dac.hpp @@ -38,7 +38,7 @@ SCA_TDF_MODULE(dac) SCA_CTOR(dac) : in("in"), out("out") { // Propagation time from input to output - set_timestep(sca_core::sca_time(0.1, sc_core::SC_US)); + set_timestep(sca_core::sca_time(17, sc_core::SC_NS)); } /** diff --git a/modules/dac/include/seq_item_dac.hpp b/modules/dac/include/seq_item_dac.hpp index 07279f9..e4c20dc 100644 --- a/modules/dac/include/seq_item_dac.hpp +++ b/modules/dac/include/seq_item_dac.hpp @@ -17,7 +17,7 @@ SCA_TDF_MODULE(seq_item_dac) SCA_CTOR(seq_item_dac) { - set_timestep(sca_core::sca_time(0.1, sc_core::SC_US)); + set_timestep(sca_core::sca_time(17, sc_core::SC_NS)); } void processing() diff --git a/modules/dac/src/tb_dac.cpp b/modules/dac/src/tb_dac.cpp index d1c3f38..0311aa2 100644 --- a/modules/dac/src/tb_dac.cpp +++ b/modules/dac/src/tb_dac.cpp @@ -3,6 +3,8 @@ #include "seq_item_dac.hpp" #define N 8 +#define VOLTAGE_MIN 0 +#define VOLTAGE_MAX 3300 int sc_main(int, char*[]) @@ -15,7 +17,7 @@ int sc_main(int, char*[]) sca_tdf::sca_signal s_ana_out; // DUT - dac ips_dac("ips_dac"); + dac ips_dac("ips_dac"); ips_dac.in(s_dig); ips_dac.out(s_ana_out); @@ -32,7 +34,7 @@ int sc_main(int, char*[]) std::cout << "@" << sc_time_stamp() << std::endl; // Run test - sc_start(MAX_SEQ_ITEMS * 0.1, SC_US); + sc_start(MAX_SEQ_ITEMS * 30, SC_NS); // End time std::cout << "@" << sc_time_stamp() << std::endl; From fe6f43f3015fe200cb39d377b1f43d6394187277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20Andr=C3=A9s=20Obreg=C3=B3n=20Fonseca?= Date: Mon, 22 Jul 2024 19:56:52 -0600 Subject: [PATCH 4/8] Adding mapping technology params for the ADC --- modules/adc/include/adc.hpp | 2 +- modules/adc/include/seq_item_adc.hpp | 20 +++++++++++++++----- modules/adc/src/tb_adc.cpp | 8 +++++--- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/modules/adc/include/adc.hpp b/modules/adc/include/adc.hpp index ccfe06d..92d15f0 100644 --- a/modules/adc/include/adc.hpp +++ b/modules/adc/include/adc.hpp @@ -37,7 +37,7 @@ SCA_TDF_MODULE(adc) */ SCA_CTOR(adc) : in("in"), out("out") { // Propagation time from input to output - set_timestep(sca_core::sca_time(0.1, sc_core::SC_US)); + set_timestep(sca_core::sca_time(13, sc_core::SC_NS)); } /** diff --git a/modules/adc/include/seq_item_adc.hpp b/modules/adc/include/seq_item_adc.hpp index 78065e6..090950b 100644 --- a/modules/adc/include/seq_item_adc.hpp +++ b/modules/adc/include/seq_item_adc.hpp @@ -7,23 +7,33 @@ /** * @brief This class is used to generate the analog signal for the test * - * @tparam N + * @tparam N - the number of output bits of the digital code + * @tparam VMIN - lowest voltage value + * @tparam VMAX - highest voltage value + * @tparam VU - voltage unit based on VUnit */ -template +template SCA_TDF_MODULE(seq_item_adc) { +protected: + // Min voltage value based on the voltage units + const double V_MIN = static_cast(VMIN) / static_cast(VU); + // Max voltage value based on the voltage units + const double V_MAX = static_cast(VMAX) / static_cast(VU); + // Max digital output code + const int MAX_CODE = (1 << N); public: sca_tdf::sca_out o_ana; - const int MAX_CODE = (1 << N); SCA_CTOR(seq_item_adc) { - set_timestep(sca_core::sca_time(0.1, sc_core::SC_US)); + set_timestep(sca_core::sca_time(13, sc_core::SC_NS)); } void processing() { - this->o_ana.write(static_cast(rand() % MAX_CODE) / MAX_CODE); + const double NORM_ANA = static_cast(rand() % MAX_CODE) / MAX_CODE; + this->o_ana.write((V_MAX + V_MIN) * NORM_ANA + V_MIN); } }; diff --git a/modules/adc/src/tb_adc.cpp b/modules/adc/src/tb_adc.cpp index c87862d..7c27af5 100644 --- a/modules/adc/src/tb_adc.cpp +++ b/modules/adc/src/tb_adc.cpp @@ -3,6 +3,8 @@ #include "seq_item_adc.hpp" #define N 8 +#define VOLTAGE_MIN 0 +#define VOLTAGE_MAX 3300 int sc_main(int, char*[]) @@ -15,12 +17,12 @@ int sc_main(int, char*[]) sca_tdf::sca_signal > s_dig_out; // DUT - adc ips_adc("ips_adc"); + adc ips_adc("ips_adc"); ips_adc.in(s_ana); ips_adc.out(s_dig_out); // Sequence item generator for ADC - seq_item_adc ips_seq_item_adc("ips_seq_item_adc"); + seq_item_adc ips_seq_item_adc("ips_seq_item_adc"); ips_seq_item_adc.o_ana(s_ana); // Dump waveform @@ -32,7 +34,7 @@ int sc_main(int, char*[]) std::cout << "@" << sc_time_stamp() << std::endl; // Run test - sc_start(MAX_SEQ_ITEMS * 0.1, SC_US); + sc_start(MAX_SEQ_ITEMS * 13, SC_NS); // End time std::cout << "@" << sc_time_stamp() << std::endl; From c687c471ac7b90840ff580367a9f109b0b87aac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20Obreg=C3=B3n=20Fonseca?= Date: Mon, 22 Jul 2024 22:15:31 -0600 Subject: [PATCH 5/8] Fixing wrong indentation of the vga tb --- modules/vga/src/vga_tb.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/vga/src/vga_tb.cpp b/modules/vga/src/vga_tb.cpp index f7a4a32..9740c2c 100644 --- a/modules/vga/src/vga_tb.cpp +++ b/modules/vga/src/vga_tb.cpp @@ -196,12 +196,12 @@ int sc_main(int, char*[]) sc_close_vcd_trace_file(wf); #endif // IPS_DUMP_EN - // Show the images in their respective windows - cv::imshow("TX image", tx_img); - cv::imshow("RX image", rx_img); + // Show the images in their respective windows + cv::imshow("TX image", tx_img); + cv::imshow("RX image", rx_img); - // Wait for a key press indefinitely to keep the windows open - cv::waitKey(0); + // Wait for a key press indefinitely to keep the windows open + cv::waitKey(0); return 0; } From bd3ebff4ad56b32ef09aff453ee86ce252b2273c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20Andr=C3=A9s=20Obreg=C3=B3n=20Fonseca?= Date: Tue, 23 Jul 2024 16:43:34 -0600 Subject: [PATCH 6/8] Changing VGA model to support connection with AMS modules --- modules/vga/include/vga.hpp | 30 ++++++++++++++++++++++++++---- modules/vga/src/vga_tb.cpp | 2 ++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/modules/vga/include/vga.hpp b/modules/vga/include/vga.hpp index 4c66a1a..e59a0cd 100644 --- a/modules/vga/include/vga.hpp +++ b/modules/vga/include/vga.hpp @@ -2,6 +2,9 @@ #define IPS_VGA_MODEL_HPP #include +#ifdef IPS_AMS +#include +#endif // IPS_AMS #define IPS_VGA_ACTIVE true #define IPS_VGA_INACTIVE false @@ -9,7 +12,7 @@ /** * @brief VGA representation class * - * @tparam CLK_FREQ - clock frequency in HHz of the VGA + * @tparam N - the number of output bits of the digital pixel * @tparam H_ACTIVE - output horizontal active video pixels * @tparam H_FP - wait after the display period before the sync * horizontal pulse @@ -42,15 +45,16 @@ SC_MODULE(vga) // Vertical count int v_count; public: +#ifndef IPS_AMS // Input clock sc_core::sc_in clk; // Input pixel sc_core::sc_in > red; sc_core::sc_in > green; sc_core::sc_in > blue; - // Output horizontal synch + // Output horizontal sync sc_core::sc_out o_hsync; - // Output vertical synch + // Output vertical sync sc_core::sc_out o_vsync; // Counter outputs sc_core::sc_out o_h_count; @@ -59,7 +63,25 @@ SC_MODULE(vga) sc_core::sc_out > o_red; sc_core::sc_out > o_green; sc_core::sc_out > o_blue; - +#else + // Input clock + sc_core::sc_in clk; + // Input pixel + sca_tdf::sca_in > red; + sca_tdf::sca_in > green; + sca_tdf::sca_in > blue; + // Output horizontal sync + sca_tdf::sca_out o_hsync; + // Output vertical sync + sca_tdf::sca_out o_vsync; + // Counter outputs + sca_tdf::sca_out o_h_count; + sca_tdf::sca_out o_v_count; + // Output pixel + sca_tdf::sca_out > o_red; + sca_tdf::sca_out > o_green; + sca_tdf::sca_out > o_blue; +#endif // IPS_AMS SC_CTOR(vga) : o_hsync("o_hsync"), o_vsync("o_vsync") { this->h_count = 0; diff --git a/modules/vga/src/vga_tb.cpp b/modules/vga/src/vga_tb.cpp index 9740c2c..dda2667 100644 --- a/modules/vga/src/vga_tb.cpp +++ b/modules/vga/src/vga_tb.cpp @@ -196,12 +196,14 @@ int sc_main(int, char*[]) sc_close_vcd_trace_file(wf); #endif // IPS_DUMP_EN +#ifdef IPS_IMSHOW // Show the images in their respective windows cv::imshow("TX image", tx_img); cv::imshow("RX image", rx_img); // Wait for a key press indefinitely to keep the windows open cv::waitKey(0); +#endif // IPS_IMSHOW return 0; } From 7165d06cb235fbc65623682e564bf1af9adec723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20Andr=C3=A9s=20Obreg=C3=B3n=20Fonseca?= Date: Tue, 23 Jul 2024 16:44:41 -0600 Subject: [PATCH 7/8] Changing ADC and DAC models to support interface between DE and TDF --- modules/adc/include/adc.hpp | 12 +++++++++--- modules/dac/include/dac.hpp | 9 +++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/modules/adc/include/adc.hpp b/modules/adc/include/adc.hpp index 92d15f0..dc9874d 100644 --- a/modules/adc/include/adc.hpp +++ b/modules/adc/include/adc.hpp @@ -29,15 +29,21 @@ SCA_TDF_MODULE(adc) // Input analog voltage sca_tdf::sca_in in; // Output digital code - sca_tdf::sca_out > out; + sca_tdf::sca_de::sca_out > out; /** * @brief Construct a new adc object * */ - SCA_CTOR(adc) : in("in"), out("out") { + SCA_CTOR(adc) : in("in"), out("out") + { + } + + void set_attributes() + { // Propagation time from input to output - set_timestep(sca_core::sca_time(13, sc_core::SC_NS)); + set_timestep(sca_core::sca_time(1, sc_core::SC_NS)); + this->out.set_delay(13); } /** diff --git a/modules/dac/include/dac.hpp b/modules/dac/include/dac.hpp index 5058067..d5360c5 100644 --- a/modules/dac/include/dac.hpp +++ b/modules/dac/include/dac.hpp @@ -27,7 +27,7 @@ SCA_TDF_MODULE(dac) const double MAX_DIG = static_cast((1 << BITS) - 1); public: // Input digital code - sca_tdf::sca_in > in; + sca_tdf::sca_de::sca_in > in; // Output analog voltage sca_tdf::sca_out out; @@ -36,9 +36,14 @@ SCA_TDF_MODULE(dac) * */ SCA_CTOR(dac) : in("in"), out("out") + { + } + + void set_attributes() { // Propagation time from input to output - set_timestep(sca_core::sca_time(17, sc_core::SC_NS)); + set_timestep(sca_core::sca_time(1, sc_core::SC_NS)); + this->out.set_delay(17); } /** From 0603376d465ed46ae7c4ae44228d9204db858411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20Andr=C3=A9s=20Obreg=C3=B3n=20Fonseca?= Date: Tue, 23 Jul 2024 16:45:17 -0600 Subject: [PATCH 8/8] Adding connection between VGA, ADC, DAC, and memory --- modules/ams/Makefile | 30 ++++ modules/ams/include/memory.hpp | 42 ++++++ modules/ams/include/seq_item_ams.hpp | 136 ++++++++++++++++++ modules/ams/src/tb_ams.cpp | 203 +++++++++++++++++++++++++++ 4 files changed, 411 insertions(+) create mode 100644 modules/ams/Makefile create mode 100644 modules/ams/include/memory.hpp create mode 100644 modules/ams/include/seq_item_ams.hpp create mode 100644 modules/ams/src/tb_ams.cpp diff --git a/modules/ams/Makefile b/modules/ams/Makefile new file mode 100644 index 0000000..49c82b5 --- /dev/null +++ b/modules/ams/Makefile @@ -0,0 +1,30 @@ +# Include common Makefile +include ../Makefile + +SRCDIR+=../adc/src ../dac/src ../vga/src ../utils/src +INCDIR+=-I$(SYSTEMC_AMS_HOME)/include -I../adc/include -I../dac/include -I../vga/include -I../utils/include +LIBDIR+=-L$(SYSTEMC_AMS_HOME)/lib-linux64 +LIBS+=-lsystemc-ams + +SOURCES:=$(foreach DIR, $(SRCDIR), $(wildcard $(DIR)/*.cpp)) +INCLUDES:=$(foreach DIR, $(INCDIR), $(wildcard $(DIR)/*.hpp)) + +# Defining preprocessor directive for debug +ifdef IPS_DEBUG_EN +CFLAGS += -DIPS_DEBUG_EN +LFLAGS += -DIPS_DEBUG_EN +endif # IPS_DEBUG_EN + +# Defining preprocessor directive for dumping enable +ifdef IPS_DUMP_EN +CFLAGS += -DIPS_DUMP_EN +LFLAGS += -DIPS_DUMP_EN +endif # IPS_DUMP_EN + +# Run the compiled file +run: + @./$(TARGET) + +# Show waveform +waveform: + @gtkwave ips_ams.vcd diff --git a/modules/ams/include/memory.hpp b/modules/ams/include/memory.hpp new file mode 100644 index 0000000..b733dae --- /dev/null +++ b/modules/ams/include/memory.hpp @@ -0,0 +1,42 @@ +#ifndef IPS_MEMORY_HPP +#define IPS_MEMORY_HPP +#include + +template +SC_MODULE(memory) +{ +protected: + int *mem; + +public: + sc_core::sc_in clk; + sc_core::sc_in we; + sc_core::sc_in address; + sc_core::sc_in> wdata; + sc_core::sc_out> rdata; + + // Constructor for memory + SC_CTOR(memory) + { + this->mem = new int[SIZE]; + + SC_METHOD(run); + sensitive << clk.pos(); + } + + void run() + { + if (clk.read()) + { + const unsigned long long int ADDR = static_cast(this->address.read()); + + if (we.read()) + { + this->mem[ADDR] = this->wdata.read(); + } + + this->rdata.write(this->mem[ADDR]); + } + } +}; +#endif // IPS_MEMORY_HPP diff --git a/modules/ams/include/seq_item_ams.hpp b/modules/ams/include/seq_item_ams.hpp new file mode 100644 index 0000000..53829c9 --- /dev/null +++ b/modules/ams/include/seq_item_ams.hpp @@ -0,0 +1,136 @@ +#ifndef IPS_SEQ_ITEM_AMS_HPP +#define IPS_SEQ_ITEM_AMS_HPP + +#define int64 systemc_int64 +#define uint64 systemc_uint64 +#include +#include +#undef int64 +#undef uint64 +#define int64 opencv_int64 +#define uint64 opencv_uint64 +#include +#undef int64 +#undef uint64 + +// Image path +#define IPS_IMG_PATH_TB "../../tools/datagen/src/imgs/car_rgb_noisy_image.jpg" + +/** + * @brief This class is used to generate the data for the AMS test + * + * @tparam N - the number of output bits of the digital pixel + * @tparam H_ACTIVE - output horizontal active video pixels + * @tparam H_FP - wait after the display period before the sync + * horizontal pulse + * @tparam H_SYNC_PULSE - assert HSYNC + * @tparam H_BP - wait after the sync horizontal pulse before starting + * the next display period + * @tparam V_ACTIVE - output vertical active video pixels + * @tparam V_FP - wait after the display period before the sync + * vertical pulse + * @tparam V_SYNC_PULSE - assert VSYNC + * @tparam V_BP - wait after the sync vertical pulse before starting + * the next display period + */ +template < + unsigned int N = 8, + unsigned int H_ACTIVE = 640, + unsigned int H_FP = 16, + unsigned int H_SYNC_PULSE = 96, + unsigned int H_BP = 48, + unsigned int V_ACTIVE = 480, + unsigned int V_FP = 10, + unsigned int V_SYNC_PULSE = 2, + unsigned int V_BP = 33 +> +SC_MODULE(seq_item_ams) +{ +protected: + cv::Mat tx_img; + +public: + // Input clock + sc_core::sc_in clk; + // Counters + sc_core::sc_in hcount; + sc_core::sc_in vcount; + // Output pixel + sc_core::sc_out > o_red; + sc_core::sc_out > o_green; + sc_core::sc_out > o_blue; + + SC_CTOR(seq_item_ams) + { + // Read image + const std::string img_path = IPS_IMG_PATH_TB; + + cv::Mat read_img = cv::imread(img_path, cv::IMREAD_COLOR); + + // CV_8UC3 Type: 8-bit unsigned, 3 channels (e.g., for a color image) + read_img.convertTo(this->tx_img, CV_8UC3); + +#ifdef IPS_DEBUG_EN + std::cout << "Loading image: " << img_path << std::endl; +#endif // IPS_DEBUG_EN + + // Check if the image is loaded successfully + if (this->tx_img.empty()) + { + std::cerr << "Error: Could not open or find the image!" << std::endl; + exit(EXIT_FAILURE); + } + +#ifdef IPS_DEBUG_EN + std::cout << "TX image info: "; + std::cout << "rows = " << this->tx_img.rows; + std::cout << " cols = " << this->tx_img.cols; + std::cout << " channels = " << this->tx_img.channels() << std::endl; +#endif // IPS_DEBUG_EN + + SC_METHOD(run); + sensitive << clk.pos(); + } + + void run() + { + if (this->clk.read()) + { + const int IMG_ROW = static_cast(this->vcount.read()) - (V_SYNC_PULSE + V_BP); + const int IMG_COL = static_cast(this->hcount.read()) - (H_SYNC_PULSE + H_BP); + +#ifdef IPS_DEBUG_EN + std::cout << "TX image: "; + std::cout << "row = " << IMG_ROW; + std::cout << " col = " << IMG_COL; +#endif // IPS_DEBUG_EN + + if ((IMG_ROW < 0) || (IMG_COL < 0) || (IMG_ROW >= static_cast(V_ACTIVE)) || (IMG_COL >= static_cast(H_ACTIVE))) + { + this->o_red.write(0); + this->o_green.write(0); + this->o_blue.write(0); + +#ifdef IPS_DEBUG_EN + std::cout << " dpixel = (0,0,0) " << std::endl; +#endif // IPS_DEBUG_EN + } + else + { + cv::Vec3b pixel = tx_img.at(IMG_ROW, IMG_COL, 0); + + this->o_red.write(static_cast>(pixel[0])); + this->o_green.write(static_cast>(pixel[1])); + this->o_blue.write(static_cast>(pixel[2])); + +#ifdef IPS_DEBUG_EN + std::cout << " ipixel = (" << static_cast(pixel[0]) << "," + << static_cast(pixel[1]) << "," << static_cast(pixel[2]) + << ")" << std::endl; +#endif // IPS_DEBUG_EN + } + } + } +}; + +#endif // IPS_SEQ_ITEM_AMS_HPP diff --git a/modules/ams/src/tb_ams.cpp b/modules/ams/src/tb_ams.cpp new file mode 100644 index 0000000..dc006bc --- /dev/null +++ b/modules/ams/src/tb_ams.cpp @@ -0,0 +1,203 @@ +#include +#include + +// #ifndef IPS_AMS +// #define IPS_AMS +// #endif // IPS_AMS + +#include "adc.hpp" +#include "dac.hpp" +#include "memory.hpp" +#include "seq_item_ams.hpp" +#include "vga.hpp" + +// Main clock frequency in Hz - 25.175 MHz +#define CLK_FREQ 25175000 +// VGA settings +#define H_ACTIVE 640 +#define H_FP 16 +#define H_SYNC_PULSE 96 +#define H_BP 48 +#define V_ACTIVE 480 +#define V_FP 10 +#define V_SYNC_PULSE 2 +#define V_BP 33 +// Compute the total number of pixels +#define TOTAL_VERTICAL (H_ACTIVE + H_FP + H_SYNC_PULSE + H_BP) +#define TOTAL_HORIZONTAL (V_ACTIVE + V_FP + V_SYNC_PULSE + V_BP) +#define TOTAL_PIXELES (TOTAL_VERTICAL * TOTAL_HORIZONTAL) +// Number of bits for ADC, DAC and VGA +#define BITS 8 +#define VOLTAGE_MIN 0 +#define VOLTAGE_MAX 3300 +// Memory parameters +#define IMG_INPUT_ADDR 0x00000034u +#define MEM_SIZE 0x002A3034u + +int sc_main(int, char *[]) +{ + // Compute the clock time in seconds + const double CLK_TIME = 1.0 / static_cast(CLK_FREQ); + // Compute the total simulation based on the total amount of pixels in the + // screen + const double SIM_TIME = CLK_TIME * static_cast(TOTAL_PIXELES); + + // Signals to use + // -- Inputs of VGA + sc_core::sc_clock clk("clk", CLK_TIME, sc_core::SC_SEC); + sc_core::sc_signal> s_tx_red; + sc_core::sc_signal> s_tx_green; + sc_core::sc_signal> s_tx_blue; + // -- Outputs of VGA + sc_core::sc_signal s_hsync; + sc_core::sc_signal s_vsync; + sc_core::sc_signal s_h_count; + sc_core::sc_signal s_v_count; + sc_core::sc_signal> s_rx_red; + sc_core::sc_signal> s_rx_green; + sc_core::sc_signal> s_rx_blue; + // -- Outputs of DAC + sca_tdf::sca_signal s_ana_red; + sca_tdf::sca_signal s_ana_green; + sca_tdf::sca_signal s_ana_blue; + // -- Outputs of ADC + sc_core::sc_signal> s_dig_out_red; + sc_core::sc_signal> s_dig_out_green; + sc_core::sc_signal> s_dig_out_blue; + // -- Memory + sc_core::sc_signal s_we; + sc_core::sc_signal s_address; + sc_core::sc_signal> s_wdata; + sc_core::sc_signal> s_rdata; + + // Data generation for the VGA pixels + seq_item_ams< + BITS, + H_ACTIVE, H_FP, H_SYNC_PULSE, H_BP, + V_ACTIVE, V_FP, V_SYNC_PULSE, V_BP> + ips_seq_item_ams("ips_seq_item_ams"); + ips_seq_item_ams.clk(clk); + ips_seq_item_ams.hcount(s_h_count); + ips_seq_item_ams.vcount(s_v_count); + ips_seq_item_ams.o_red(s_tx_red); + ips_seq_item_ams.o_green(s_tx_green); + ips_seq_item_ams.o_blue(s_tx_blue); + + // VGA module instanciation and connections + vga< + BITS, + H_ACTIVE, H_FP, H_SYNC_PULSE, H_BP, + V_ACTIVE, V_FP, V_SYNC_PULSE, V_BP> + ips_vga("ips_vga"); + ips_vga.clk(clk); + ips_vga.red(s_tx_red); + ips_vga.green(s_tx_green); + ips_vga.blue(s_tx_blue); + ips_vga.o_hsync(s_hsync); + ips_vga.o_vsync(s_vsync); + ips_vga.o_h_count(s_h_count); + ips_vga.o_v_count(s_v_count); + ips_vga.o_red(s_rx_red); + ips_vga.o_green(s_rx_green); + ips_vga.o_blue(s_rx_blue); + + // DAC module instanciations and connections + dac ips_dac_red("ips_dac_red"); + ips_dac_red.in(s_rx_red); + ips_dac_red.out(s_ana_red); + + dac ips_dac_green("ips_dac_green"); + ips_dac_green.in(s_rx_green); + ips_dac_green.out(s_ana_green); + + dac ips_dac_blue("ips_dac_blue"); + ips_dac_blue.in(s_rx_blue); + ips_dac_blue.out(s_ana_blue); + + // ADC module instanciations and connections + adc ips_adc_red("ips_adc_red"); + ips_adc_red.in(s_ana_red); + ips_adc_red.out(s_dig_out_red); + + adc ips_adc_green("ips_adc_green"); + ips_adc_green.in(s_ana_green); + ips_adc_green.out(s_dig_out_green); + + adc ips_adc_blue("ips_adc_blue"); + ips_adc_blue.in(s_ana_blue); + ips_adc_blue.out(s_dig_out_blue); + + memory ips_memory("ips_memory"); + ips_memory.clk(clk); + ips_memory.address(s_address); + ips_memory.we(s_we); + ips_memory.wdata(s_wdata); + ips_memory.rdata(s_rdata); + + // Signals to dump +#ifdef IPS_DUMP_EN + sca_util::sca_trace_file *wf = sca_util::sca_create_vcd_trace_file("ips_ams"); + + sca_trace(wf, clk, "clk"); + sca_trace(wf, s_hsync, "hsync"); + sca_trace(wf, s_vsync, "vsync"); + sca_trace(wf, s_h_count, "h_count"); + sca_trace(wf, s_v_count, "v_count"); + sca_trace(wf, s_tx_red, "tx_red"); + sca_trace(wf, s_tx_green, "tx_green"); + sca_trace(wf, s_tx_blue, "tx_blue"); + sca_trace(wf, s_rx_red, "rx_red"); + sca_trace(wf, s_rx_green, "rx_green"); + sca_trace(wf, s_rx_blue, "rx_blue"); + sca_trace(wf, s_ana_red, "ana_red"); + sca_trace(wf, s_ana_green, "ana_green"); + sca_trace(wf, s_ana_blue, "ana_blue"); + sca_trace(wf, s_dig_out_red, "to_mem_red"); + sca_trace(wf, s_dig_out_green, "to_mem_green"); + sca_trace(wf, s_dig_out_blue, "to_mem_blue"); + sca_trace(wf, s_we, "we"); + sca_trace(wf, s_address, "address"); + sca_trace(wf, s_rdata, "rdata"); +#endif // IPS_DUMP_EN + + // Start time + std::cout << "@" << sc_time_stamp() << std::endl; + + double total_sim_time = 0.0; + + while (SIM_TIME > total_sim_time) + { + const int IMG_ROW = s_v_count.read() - (V_SYNC_PULSE + V_BP); + const int IMG_COL = s_h_count.read() - (H_SYNC_PULSE + H_BP); + + if ((IMG_ROW < 0) || (IMG_COL < 0) || (IMG_ROW >= V_ACTIVE) || (IMG_COL >= H_ACTIVE)) + { + s_we.write(false); + } + else + { + const unsigned long long ADDR = static_cast(IMG_INPUT_ADDR + IMG_ROW * V_ACTIVE + IMG_COL); + s_address.write(ADDR); + s_wdata.write((s_dig_out_red.read() << 16) + (s_dig_out_green.read() << 8) + s_dig_out_blue.read()); + s_we.write(true); + +#ifdef IPS_DEBUG_EN + std::cout << " MEM[" << ADDR << "] = " << s_dig_out_blue.read() << std::endl + << " MEM[" << (ADDR + 1) << "] = " << s_dig_out_green.read() << std::endl + << " MEM[" << (ADDR + 2) << "] = " << s_dig_out_red.read() << std::endl; +#endif // IPS_DEBUG_EN + } + + total_sim_time += CLK_TIME; + sc_start(CLK_TIME, sc_core::SC_SEC); + } + + // End time + std::cout << "@" << sc_time_stamp() << std::endl; + +#ifdef IPS_DUMP_EN + sca_util::sca_close_vcd_trace_file(wf); +#endif // IPS_DUMP_EN + + return 0; +}