aboutsummaryrefslogtreecommitdiff
path: root/src/tb
diff options
context:
space:
mode:
authorClément Zrounba <6691770+clement-z@users.noreply.github.com>2023-09-30 23:06:01 +0200
committerClément Zrounba <6691770+clement-z@users.noreply.github.com>2023-09-30 23:26:46 +0200
commitff9b8bb838ecdfbfc1dc81038fcf3b2a87636982 (patch)
tree21f27be782ce11c6d00b96ce100a2bff88141b2e /src/tb
downloadspecs-ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982.tar.gz
specs-ff9b8bb838ecdfbfc1dc81038fcf3b2a87636982.zip
Initial release
Diffstat (limited to 'src/tb')
-rw-r--r--src/tb/alltestbenches.cpp28
-rw-r--r--src/tb/alltestbenches.h22
-rw-r--r--src/tb/crow_tb.cpp216
-rw-r--r--src/tb/crow_tb.h30
-rw-r--r--src/tb/detector_tb.cpp127
-rw-r--r--src/tb/detector_tb.h30
-rw-r--r--src/tb/directional_coupler_tb.cpp150
-rw-r--r--src/tb/directional_coupler_tb.h31
-rw-r--r--src/tb/freqsweep_tb.cpp213
-rw-r--r--src/tb/freqsweep_tb.h33
-rw-r--r--src/tb/lambda_tb.cpp102
-rw-r--r--src/tb/lambda_tb.h31
-rw-r--r--src/tb/merger_tb.cpp126
-rw-r--r--src/tb/merger_tb.h30
-rw-r--r--src/tb/mesh_tb.cpp130
-rw-r--r--src/tb/mesh_tb.h29
-rw-r--r--src/tb/mzi_tb.cpp86
-rw-r--r--src/tb/mzi_tb.h31
-rw-r--r--src/tb/pcm_device_tb.cpp129
-rw-r--r--src/tb/pcm_device_tb.h29
-rw-r--r--src/tb/phase_shifter_tb.cpp129
-rw-r--r--src/tb/phase_shifter_tb.h32
-rw-r--r--src/tb/ring_tb.cpp85
-rw-r--r--src/tb/ring_tb.h29
-rw-r--r--src/tb/splitter_tb.cpp123
-rw-r--r--src/tb/splitter_tb.h29
-rw-r--r--src/tb/wg_tb.cpp143
-rw-r--r--src/tb/wg_tb.h28
28 files changed, 2201 insertions, 0 deletions
diff --git a/src/tb/alltestbenches.cpp b/src/tb/alltestbenches.cpp
new file mode 100644
index 0000000..107dfdc
--- /dev/null
+++ b/src/tb/alltestbenches.cpp
@@ -0,0 +1,28 @@
+#include <map>
+#include <tb/alltestbenches.h>
+
+#if defined(BUILD_TB) && BUILD_TB == 1
+std::map<std::string, tb_func_t> tb_map = {
+ { "wg", wg_tb_run },
+ { "waveguide", wg_tb_run },
+ { "merg", Merger_tb_run },
+ { "merger", Merger_tb_run },
+ { "dc", DirectionalCoupler_tb_run },
+ { "directional_coupler", DirectionalCoupler_tb_run },
+ { "spli", Splitter_tb_run },
+ { "splitter", Splitter_tb_run },
+ { "det", Detector_tb_run },
+ { "detector", Detector_tb_run },
+ { "pcm", PCMElement_tb_run },
+ { "mzi", MZI_tb_run },
+ { "ring", Ring_tb_run },
+ { "ac_add_drop", freqsweep_tb_run_add_drop },
+ { "ac_crow", crow_tb_run },
+ { "lambda", lambda_tb_run },
+ { "phaseshifter", ps_tb_run },
+ { "ps", ps_tb_run },
+ { "mesh", mesh_tb_run },
+};
+#else
+std::map<std::string, tb_func_t> tb_map = {};
+#endif
diff --git a/src/tb/alltestbenches.h b/src/tb/alltestbenches.h
new file mode 100644
index 0000000..49043bb
--- /dev/null
+++ b/src/tb/alltestbenches.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <tb/detector_tb.h>
+#include <tb/directional_coupler_tb.h>
+#include <tb/merger_tb.h>
+#include <tb/pcm_device_tb.h>
+#include <tb/splitter_tb.h>
+#include <tb/wg_tb.h>
+#include "tb/mzi_tb.h"
+#include "tb/ring_tb.h"
+#include "tb/freqsweep_tb.h"
+#include "tb/crow_tb.h"
+#include "tb/lambda_tb.h"
+#include "tb/phase_shifter_tb.h"
+#include "mesh_tb.h"
+
+#include <map>
+#include <string>
+
+typedef void (*tb_func_t)();
+
+extern std::map<std::string, tb_func_t> tb_map;
diff --git a/src/tb/crow_tb.cpp b/src/tb/crow_tb.cpp
new file mode 100644
index 0000000..91a816c
--- /dev/null
+++ b/src/tb/crow_tb.cpp
@@ -0,0 +1,216 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/crow_tb.h>
+
+#include <cstdlib>
+#include <unistd.h>
+#include <chrono>
+
+#include <waveguide.h>
+#include <directional_coupler.h>
+#include <probe.h>
+#include <crow.h>
+#include <specs.h>
+#include "time_monitor.h"
+
+#include "general_utils.h"
+
+using namespace std;
+using namespace std::chrono;
+
+
+/* ----------------------------------------------------------------------------- *
+ This testbench is called freqsweep because it is capable of this
+ type of simulation, but it is also possible to set it as a time-domain
+ simulation depending on the mode chosen when calling SPECS. Example:
+
+ specs -t ac_add_drop -m fd -> will perform the frequency sweep
+ specs -t ac_add_drop -m td -> will perform the time domain simulation
+
+/ ----------------------------------------------------------------------------- */
+
+// ---------------- Use this variable to change the size of the CROW -----------
+ size_t nrings_crow = 3;
+// -----------------------------------------------------------------------------
+
+void crow_tb::run_td()
+{
+ bool verbose = true;
+ if (specsGlobalConfig.simulation_mode == OpticalOutputPortMode::TIME_DOMAIN)
+ {
+ int npulses = 4;
+ double lambda = 1554.3719e-9;
+ lambda = 1.561931948453715e-6;
+ lambda = 1538.3277504e-9;
+ lambda = 1543e-9;
+ lambda = 1556.5742279e-9;
+ lambda = 1556.32782563158025368466e-9;
+ lambda = 1556e-9;
+ lambda = 1553e-9;
+ //lambda = 1550e-9;
+ double tpulse = 1e-9;
+ double deadtime = tpulse;
+
+
+ // Wait one tick that all sc_threads are started and on their first `wait` call
+ wait(SC_ZERO_TIME);
+
+ if (verbose)
+ {
+ cout << "----------------------------" <<endl;
+ cout << "Starting time-domain simulation" << endl;
+ }
+ for (int i = 0; i < npulses; ++i)
+ {
+ IN->write(OpticalSignal(1, lambda));
+ wait(tpulse, SC_SEC);
+ // //ADD.write(OpticalSignal(polar<double>(1, M_PI_2), lambda));
+ // //ADD.write(OpticalSignal(polar<double>(0,0), lambda));
+ IN->write(OpticalSignal(0, lambda));
+ // ADD.write(OpticalSignal(0, lambda));
+ wait(deadtime, SC_SEC);
+ }
+ }
+
+ while (true) { wait(); }
+}
+
+void crow_tb::run_fd()
+{
+ bool verbose = true;
+ if (specsGlobalConfig.simulation_mode == OpticalOutputPortMode::FREQUENCY_DOMAIN)
+ {
+ auto lambda_center = 1550e-9;
+ auto lambda_span = 2e-9;
+ auto dlambda = 0.001e-9;
+ auto lambda_min = lambda_center - lambda_span/2;
+ auto lambda_max = lambda_center + lambda_span/2;
+ // lambda_min = 1545e-9;
+ // lambda_max = 1569e-9;
+ lambda_min = 299792458.0/195e12;
+ lambda_max = 299792458.0/190e12;
+ lambda_min = 1556e-9;
+ lambda_span = lambda_max - lambda_min;
+ dlambda = lambda_span / 10000;
+
+ // Wait one tick that all sc_threads are started and on their first `wait` call
+ wait(SC_ZERO_TIME);
+ //wait(lambda_min, SC_SEC);
+
+ auto tic = high_resolution_clock::now();
+ auto toc = high_resolution_clock::now();
+
+ if (verbose)
+ {
+ cout << "----------------------------" <<endl;
+ cout << "Starting sweep" << endl;
+ }
+ int i = 0;
+ int n = ceil(lambda_span / dlambda);
+ for (auto lambda = lambda_min; lambda < lambda_max + dlambda; lambda += dlambda)
+ {
+ ++i;
+ if (true || (verbose && i % (int)(n/20) == 0))
+ {
+ toc = high_resolution_clock::now();
+ auto duration = duration_cast<microseconds>(toc - tic);
+ tic = toc;
+ cout << duration.count()/1000.0 << "ms" << endl;
+ cout << endl;
+ cout << fixed << setprecision(1) << (lambda-lambda_min)/lambda_span * 100.0 << "%" << endl;
+ cout << setprecision(20) << lambda * 1e9 << "nm" << endl;
+ }
+ IN->write(OpticalSignal(sqrt(1), lambda));
+ ADD->write(OpticalSignal(0, lambda));
+ //ADD.write(OpticalSignal(polar<double>(0, 0), lambda));
+ //ADD.write(OpticalSignal(polar<double>(sqrt(0.5), -M_PI_2), lambda));
+ wait(dlambda, SC_SEC);
+ }
+ if (verbose)
+ {
+ cout << "----------------------------" <<endl;
+ cout << "Sweep over (" << n << " points)" << endl;
+ }
+ }
+ while (true) { wait(); }
+}
+
+void crow_tb::monitor()
+{
+ unsigned long long event_counter = 0;
+ while(true)
+ {
+ wait();
+ continue;
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN: " << IN->read() << std::endl
+ << "\tADD: " << ADD->read() << std::endl
+ << "\tTHROUGH: " << THROUGH->read() << std::endl
+ << "\tDROP: " << DROP->read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+ }
+
+}
+
+void crow_tb_run()
+{
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type IN("IN"), THROUGH("THROUGH"), DROP("DROP"), ADD("ADD");
+
+ crow_tb tb1("tb1");
+ tb1.IN(IN);
+ tb1.ADD(ADD);
+ tb1.THROUGH(THROUGH);
+ tb1.DROP(DROP);
+
+ // pid_t pid = fork();
+ CROW *pc;
+ // if(pid)
+ pc = new CROW("crow", nrings_crow);
+ // else
+ // pc = new Crow("crow", 5);
+ pc->p_in(IN);
+ pc->p_add(ADD);
+ pc->p_out_t(THROUGH);
+ pc->p_out_d(DROP);
+
+ pc->setRingLength(2*30e-6);
+ pc->m_loss_db_cm = 2.0;
+ pc->m_coupling_through = 1 - pow(0.83645, 2.0);
+ // pc->m_coupling_through = 0.5;
+ pc->m_neff = 2.6391;
+ pc->m_ng = 4.3416;
+
+ pc->m_ring_length = 500.0*1.55e-6 + 1.55e-6/2.0;
+ pc->m_loss_db_cm = 2.0;
+ pc->m_coupling_through = 1 - 0.2;
+ pc->m_neff = 1;
+ pc->m_ng = 2;
+
+ pc->init(); //instantiating all nets
+
+ Probe pthrough("pthrough", true, true, false, true);
+ pthrough.p_in(THROUGH);
+ //
+ Probe pcross("pcross", true, true, false, false);
+ pcross.p_in(DROP);
+
+ specsGlobalConfig.trace_filename = "traces/crow_tb";
+
+ // Apply SPECS options specific to the testbench
+ // specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start(50e-9, SC_SEC);
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/crow_tb.h b/src/tb/crow_tb.h
new file mode 100644
index 0000000..473708d
--- /dev/null
+++ b/src/tb/crow_tb.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <specs.h>
+#include <systemc.h>
+
+class crow_tb : public sc_module {
+public:
+ spx::oa_port_out_type IN;
+ spx::oa_port_out_type ADD;
+ spx::oa_port_in_type THROUGH;
+ spx::oa_port_in_type DROP;
+
+ void run_fd();
+ void run_td();
+ void monitor();
+
+ SC_CTOR(crow_tb)
+ {
+ SC_THREAD(run_fd);
+ SC_THREAD(run_td);
+ SC_THREAD(monitor);
+ if (false)
+ sensitive << IN << ADD << THROUGH << DROP;
+ }
+};
+
+void crow_tb_run();
+
+extern size_t nrings_crow;
diff --git a/src/tb/detector_tb.cpp b/src/tb/detector_tb.cpp
new file mode 100644
index 0000000..e296d26
--- /dev/null
+++ b/src/tb/detector_tb.cpp
@@ -0,0 +1,127 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/detector_tb.h>
+
+#include "general_utils.h"
+
+void Detector_tb::run_1()
+{
+ IN->write(OpticalSignal(sqrt(1.0), 1550e-9));
+ wait(100, SC_MS);
+ IN->write(OpticalSignal(0, 1550e-9));
+ wait(100, SC_MS);
+ IN->write(OpticalSignal(sqrt(1.0), 1551e-9));
+
+
+
+ while (true) { wait(); }
+}
+
+void Detector_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 3;
+ while(true)
+ {
+ wait();
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN: " << IN->read() << std::endl
+ << "\tREADOUT: " << READOUT.read() << std::endl
+ << "\tREADOUT2: " << READOUT2.read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+
+ if(event_counter == 2)
+ {
+ if ((is_close(READOUT.read(), 1, 1e-3)) && (is_close(READOUT2.read(), 1, 1e-3)))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 1A as both output currents!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 4)
+ {
+ if ((is_close(READOUT.read(), 0, 1e-4)) && (is_close(READOUT2.read(), 0, 1e-4)))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0A as output currents!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 6)
+ {
+ if (!is_close(READOUT.read(), READOUT2.read(), 1e-7))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected slightly different currents (different noise seed)!" << std::endl;
+ std::cout << "Is the noise ON?" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Test finished!" << std::endl;
+ std::cout << "Success rate: " << success_counter << "/" << test_number << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ }
+}
+
+void Detector_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type IN;
+ sc_signal<double> READOUT, READOUT2;
+
+ Detector uut("uut", 1, 100e-12, false);
+ uut.p_in(IN);
+ uut.p_readout(READOUT);
+
+ Detector uut2("uut2", 1, 100e-12, false);
+ uut2.p_in(IN);
+ uut2.p_readout(READOUT2);
+
+ Detector_tb tb("tb");
+ tb.IN(IN);
+ tb.READOUT(READOUT);
+ tb.READOUT2(READOUT2);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "detector_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ Probe probe_detector("probe_detector",specsGlobalConfig.default_trace_file);
+ probe_detector.p_in(IN);
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // custom traces should come after prepareSimulation !!
+ sc_trace(specsGlobalConfig.default_trace_file, READOUT, "READOUT");
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/detector_tb.h b/src/tb/detector_tb.h
new file mode 100644
index 0000000..39b05dc
--- /dev/null
+++ b/src/tb/detector_tb.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <detector.h>
+#include <optical_signal.h>
+#include <systemc.h>
+#include <probe.h>
+#include <specs.h>
+#include <waveguide.h>
+
+SC_MODULE(Detector_tb)
+{
+public:
+ spx::oa_port_out_type IN;
+ sc_in<double> READOUT, READOUT2;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(Detector_tb)
+ {
+ SC_HAS_PROCESS(Detector_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN << READOUT << READOUT2;
+ }
+};
+
+void Detector_tb_run();
+
diff --git a/src/tb/directional_coupler_tb.cpp b/src/tb/directional_coupler_tb.cpp
new file mode 100644
index 0000000..1954414
--- /dev/null
+++ b/src/tb/directional_coupler_tb.cpp
@@ -0,0 +1,150 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/directional_coupler_tb.h>
+
+#include "general_utils.h"
+#include "generic_2x2_coupler.h"
+
+void DirectionalCoupler_tb::run_1()
+{
+ IN1->write(OpticalSignal(1.0, 1550e-9));
+ wait(100, SC_MS);
+ IN2->write(OpticalSignal(1.0, 1550e-9));
+ wait(100, SC_MS);
+
+ while (true) { wait(); }
+}
+
+void DirectionalCoupler_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 3;
+
+ while(true)
+ {
+ wait();
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN1: " << IN1->read() << std::endl
+ << "\tIN2: " << IN2->read() << std::endl
+ << "\tOUT1: " << OUT1->read() << std::endl
+ << "\tOUT2: " << OUT2->read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+
+ if(event_counter == 2)
+ {
+ if (is_close(norm(OUT1->read().m_field), 0.05, 1e-4) && is_close(norm(OUT2->read().m_field), 0.45, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0.05W/0.45 as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ if (is_close(arg(OUT2->read().m_field), 1.5708, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected pi/2 as phase in OUT2!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 4)
+ {
+ if (is_close(arg(OUT1->read().m_field), 1.2490, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 1.2490 as phase in OUT1!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Test finished!" << std::endl;
+ std::cout << "Success rate: " << success_counter << "/" << test_number << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+}
+
+void DirectionalCoupler_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+
+ spx::oa_signal_type IN1, IN2, IN3, IN4, OUT1, OUT2;
+ spx::oa_signal_type TERM_r, TERM_w;
+
+ // Unidirectional variant
+ // DirectionalCoupler uut("uut", 0.5, 0);
+ // uut.m_dc_through_coupling_power = 0.1;
+ // uut.m_dc_loss = 3.0103;
+
+ // uut.p_in1(IN1);
+ // uut.p_in2(IN2);
+ // uut.p_out1(OUT1);
+ // uut.p_out2(OUT2);
+
+ // Bidirectional variant
+ DirectionalCouplerBi uut("uut", 0.5, 0);
+ uut.m_dc_through_coupling_power = 0.1;
+ uut.m_dc_loss = 3.0103;
+
+ uut.p0_in(IN1);
+ uut.p0_out(TERM_w);
+ uut.p1_in(IN2);
+ uut.p1_out(TERM_w);
+ uut.p2_in(TERM_r);
+ uut.p2_out(OUT1);
+ uut.p3_in(TERM_r);
+ uut.p3_out(OUT2);
+
+ // Generic bidirectional variant
+ // Generic2x2Coupler uut("uut", 1-0.1, 3.0103);
+ // uut.ports_in[0]->bind(IN1);
+ // uut.ports_in[1]->bind(IN2);
+ // uut.ports_in[2]->bind(TERM_r);
+ // uut.ports_in[3]->bind(TERM_r);
+ // uut.ports_out[0]->bind(TERM_w);
+ // uut.ports_out[1]->bind(TERM_w);
+ // uut.ports_out[2]->bind(OUT1);
+ // uut.ports_out[3]->bind(OUT2);
+
+ DirectionalCoupler_tb tb("tb");
+ tb.IN1(IN1);
+ tb.IN2(IN2);
+ tb.OUT1(OUT1);
+ tb.OUT2(OUT2);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "directional_coupler_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ Probe probe_dc_1("probe_dc_1",specsGlobalConfig.default_trace_file);
+ probe_dc_1.p_in(OUT1);
+ Probe probe_dc_2("probe_dc_2",specsGlobalConfig.default_trace_file);
+ probe_dc_2.p_in(OUT2);
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/directional_coupler_tb.h b/src/tb/directional_coupler_tb.h
new file mode 100644
index 0000000..c137b31
--- /dev/null
+++ b/src/tb/directional_coupler_tb.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <directional_coupler.h>
+#include <optical_signal.h>
+#include <systemc.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(DirectionalCoupler_tb)
+{
+public:
+ spx::oa_port_out_type IN1;
+ spx::oa_port_out_type IN2;
+ spx::oa_port_in_type OUT1;
+ spx::oa_port_in_type OUT2;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(DirectionalCoupler_tb)
+ {
+ SC_HAS_PROCESS(DirectionalCoupler_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN1 << IN2 << OUT1 << OUT2;
+ }
+};
+
+void DirectionalCoupler_tb_run();
+
diff --git a/src/tb/freqsweep_tb.cpp b/src/tb/freqsweep_tb.cpp
new file mode 100644
index 0000000..f44aa34
--- /dev/null
+++ b/src/tb/freqsweep_tb.cpp
@@ -0,0 +1,213 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/freqsweep_tb.h>
+
+#include <cstdlib>
+#include <unistd.h>
+
+#include "time_monitor.h"
+
+#include "general_utils.h"
+
+/* ----------------------------------------------------------------------------- *
+ This testbench is called freqsweep because it is capable of this
+ type of simulation, but it is also possible to set it as a time-domain
+ simulation depending on the mode chosen when calling SPECS. Example:
+
+ specs -t ac_add_drop -m fd -> will perform the frequency sweep
+ specs -t ac_add_drop -m td -> will perform the time domain simulation
+
+/ ----------------------------------------------------------------------------- */
+
+void freqsweep_tb::run_1()
+{
+ if (specsGlobalConfig.simulation_mode == OpticalOutputPortMode::FREQUENCY_DOMAIN)
+ {
+ auto lambda_center = 1550.3e-9;
+ auto lambda_span = 1e-9;
+ auto dlambda = 0.002e-9;
+ auto lambda_min = lambda_center - lambda_span/2;
+ auto lambda_max = lambda_center + lambda_span/2;
+ // lambda_min = 1550.250e-9;
+ // lambda_max = 1550.303e-9;
+ //wait(lambda_min * 1e9, SC_SEC);
+
+ wait(SC_ZERO_TIME);
+ cout << "----------------------------" <<endl;
+ cout << "Starting sweep" << endl;
+ for (auto lambda = lambda_min; lambda < lambda_max + dlambda; lambda += dlambda)
+ {
+ cout << setprecision(7) << lambda * 1e9 << "nm" << endl;
+ IN->write(OpticalSignal(1, lambda));
+ wait(dlambda, SC_SEC);
+ }
+ } else {
+ for (int i = 0; i < 1; ++i)
+ {
+ auto lambda = 1550.302e-9;
+ IN->write(OpticalSignal(1,lambda));
+ wait(1, SC_NS);
+ IN->write(OpticalSignal(0, lambda));
+ wait(1, SC_NS);
+ }
+ }
+
+ while (true) { wait(); }
+}
+
+void freqsweep_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 3;
+ while(true)
+ {
+ wait();
+ continue;
+ }
+}
+
+void freqsweep_tb_run_add_drop()
+{
+ specsGlobalConfig.applyEngineResolution();
+ //specsGlobalConfig.oop_configs[0]->m_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ //specsGlobalConfig.oop_configs[0]->m_mode = OpticalOutputPortMode::FREQUENCY_DOMAIN;
+
+ // First test for the LBR paper to DAC
+ // Single ring resonator, compare the response to theoretical
+ // Also compare time of simulation wrt photontorch for same ring.
+
+ // Characteristics:
+ // Add-drop ring
+ // Internal wg length (cm):
+ // Internal wg loss (dB/cm):
+ // Internal wg neff:
+ // Internal wg ng:
+ // DC ratio : 0.15 cross, 0.85 through
+ // DC coupling loss (dB) : 0
+ // Total length for resonance: lambda/2neff
+ double neff = 1.0;
+ double loss_db_cm = 1.0;
+ double coupling_through = 0.85;
+
+ spx::oa_signal_type IN, T_OUT, X_OUT, X_TERM;
+ spx::oa_signal_type INNER_RING[4];
+
+ freqsweep_tb tb1("tb1");
+ tb1.IN(IN);
+ tb1.OUT(X_OUT);
+
+ DirectionalCoupler dc1("dc1", coupling_through, 0);
+ dc1.p_in1(INNER_RING[0]);
+ dc1.p_out1(INNER_RING[1]);
+ dc1.p_in2(IN);
+ dc1.p_out2(T_OUT);
+
+ Waveguide wg1("wg1", 100.0*1550.0e-6/(2*neff), loss_db_cm, neff, neff);
+ wg1.p_in(INNER_RING[1]);
+ wg1.p_out(INNER_RING[2]);
+
+ Waveguide wg2("wg2", 100.0*1550.0e-6/(2*neff), loss_db_cm, neff, neff);
+ wg2.p_in(INNER_RING[3]);
+ wg2.p_out(INNER_RING[0]);
+
+ DirectionalCoupler dc2("dc2", coupling_through, 0);
+ dc2.p_in1(X_TERM);
+ dc2.p_out1(X_OUT);
+ dc2.p_in2(INNER_RING[2]);
+ dc2.p_out2(INNER_RING[3]);
+
+ Probe pthrough("ptrough");
+ pthrough.p_in(T_OUT);
+
+ Probe pcross("pcross");
+ pcross.p_in(X_OUT);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "freqsweep_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ // could have forced frequency domain like this, but taking command line input instead
+ // specsGlobalConfig.simulation_mode = OpticalOutputPortMode::FREQUENCY_DOMAIN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
+
+// void freqsweep_tb_run_crow()
+// {
+// if (specsGlobalConfig.oop_configs[0]->m_mode == OpticalOutputPortMode::FREQUENCY_DOMAIN)
+// specsGlobalConfig.engine_timescale = SPECSConfig::ONE_FS;
+
+// specsGlobalConfig.applyEngineResolution();
+
+// sc_signal<OpticalSignal> IN("IN"), T_OUT("T_OUT"), X_OUT("X_OUT"), ADD("ADD");
+
+// freqsweep_tb tb1("tb1");
+// tb1.IN(IN);
+// tb1.IN(IN);
+// tb1.OUT(T_OUT);
+
+// // pid_t pid = fork();
+// CROW *pc;
+// // if(pid)
+// pc = new CROW("crow", nrings);
+// // else
+// // pc = new CROW("crow", 5);
+// pc->p_in(IN);
+// pc->p_add(ADD);
+// pc->p_out_t(T_OUT);
+// pc->p_out_d(X_OUT);
+
+// Probe pthrough("ptrough");
+// pthrough.p_in(T_OUT);
+// //
+// Probe pcross("pcross");
+// pcross.p_in(X_OUT);
+
+// // shared_ptr<TimeMonitor> tm;
+// // if (specsGlobalConfig.oop_configs[0]->m_mode == OpticalOutputPortMode::FREQUENCY_DOMAIN)
+// // tm = make_shared<TimeMonitor>("TM", 0, 0.01);
+// // else
+// // tm = make_shared<TimeMonitor>("TM", 1e-14, 0.5);
+
+// // // Open Trace file
+// // sc_trace_file *Tf;
+// // std::time_t now = std::time(nullptr);
+// // char mbstr[100];
+// // std::strftime(mbstr, sizeof(mbstr), "%F-%H-%M-%S-", std::localtime(&now));
+// //
+// // std::string trace_filename = "traces/";
+// // //trace_filename += mbstr;
+// // trace_filename += "freqsweep_tb";
+
+// // auto engineTime = std::pow(10, 15+specsGlobalConfig.engine_timescale);
+// // Tf = sc_create_vcd_trace_file(trace_filename.c_str());
+// // ((sc_trace_file *)Tf)->set_time_unit(engineTime, SC_FS);
+// // sc_trace(Tf, IN, "IN");
+// // sc_trace(Tf, X_OUT, "X_OUT");
+// // sc_trace(Tf, T_OUT, "T_OUT");
+
+// if (specsGlobalConfig.trace_filename.empty())
+// specsGlobalConfig.trace_filename = "traces/crow_tb";
+
+// // Start simulation
+// specsGlobalConfig.prepareSimulation();
+// sc_start(); // run until sc_stop()
+
+// std::cout << std::endl << std::endl;
+// std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+// sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+// }
diff --git a/src/tb/freqsweep_tb.h b/src/tb/freqsweep_tb.h
new file mode 100644
index 0000000..d5a328c
--- /dev/null
+++ b/src/tb/freqsweep_tb.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <systemc.h>
+#include <waveguide.h>
+#include <directional_coupler.h>
+#include <probe.h>
+#include <crow.h>
+#include <specs.h>
+
+SC_MODULE(freqsweep_tb)
+{
+public:
+ spx::oa_port_out_type IN;
+ spx::oa_port_in_type OUT;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(freqsweep_tb)
+ {
+ SC_HAS_PROCESS(freqsweep_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN << OUT;
+ }
+};
+
+//void freqsweep_tb_run();
+void freqsweep_tb_run_add_drop();
+void freqsweep_tb_run_crow();
+
diff --git a/src/tb/lambda_tb.cpp b/src/tb/lambda_tb.cpp
new file mode 100644
index 0000000..96a5084
--- /dev/null
+++ b/src/tb/lambda_tb.cpp
@@ -0,0 +1,102 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/lambda_tb.h>
+
+#include "general_utils.h"
+#include "devices/generic_waveguide.h"
+
+void lambda_tb::run_1()
+{
+ // IN1.write(OpticalSignal(sqrt(2.0), 1550e-9));
+ // wait(0, SC_FS);
+ // IN2.write(OpticalSignal(sqrt(2.0), 1660e-9));
+ // while(true) {wait();}
+ wait(1,SC_SEC);
+ sc_stop();
+}
+
+void lambda_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 0;
+ while(true)
+ {
+ wait();
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tOUT: " << OUT.read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+ }
+
+}
+
+void lambda_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type I1, I2, YOUT, WGOUT;
+ spx::oa_signal_type DCO1, DCO2, DCI1, DCI2;
+
+ CWSource cw1("cw1");
+ cw1.setWavelength(1550e-9);
+ cw1.setPower(2);
+ cw1.enable.write(SC_LOGIC_1);
+ cw1.p_out(I1);
+
+ CWSource cw2("cw2");
+ cw2.setWavelength(1660e-9);
+ cw2.setPower(2);
+ cw2.enable.write(SC_LOGIC_1);
+ cw2.p_out(I2);
+
+ Merger merg1("merg1");
+ merg1.p_in1(I1);
+ merg1.p_in2(I2);
+ merg1.p_out(YOUT);
+
+ Waveguide wg1("wg1", 0.1, 0, 1, 1);
+ wg1.m_attenuation_dB_cm = 0;
+ wg1.p_in(YOUT);
+ wg1.p_out(DCI1);
+
+ DirectionalCoupler dc1("dc1");
+ dc1.p_in1(DCI1);
+ dc1.p_in2(DCI2);
+ dc1.p_out1(DCO1);
+ dc1.p_out2(DCO2);
+
+ Waveguide wg2("wg2", 100*1001*1550e-9/(2), 0, 1, 1);
+ wg2.p_in(DCO2);
+ wg2.p_out(DCI2);
+
+ lambda_tb tb("tb");
+ tb.OUT(DCO1);
+ // tb.IN1(I1);
+ // tb.IN2(I2);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "lambda_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ MLambdaProbe probe("probe_lambda", {1550e-9, 1650e-9, 1660e-9});
+ // Probe probe("test_probe",specsGlobalConfig.default_trace_file);
+ probe.p_in(DCO1);
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/lambda_tb.h b/src/tb/lambda_tb.h
new file mode 100644
index 0000000..a5dc203
--- /dev/null
+++ b/src/tb/lambda_tb.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <systemc.h>
+#include <waveguide.h>
+#include <merger.h>
+#include <directional_coupler.h>
+#include <cw_source.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(lambda_tb)
+{
+public:
+ sc_in<OpticalSignal> OUT;
+ // sc_out<OpticalSignal> IN1, IN2;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(lambda_tb)
+ {
+ SC_HAS_PROCESS(lambda_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << OUT;
+ }
+};
+
+void lambda_tb_run();
diff --git a/src/tb/merger_tb.cpp b/src/tb/merger_tb.cpp
new file mode 100644
index 0000000..1c86643
--- /dev/null
+++ b/src/tb/merger_tb.cpp
@@ -0,0 +1,126 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/merger_tb.h>
+
+#include "general_utils.h"
+
+void Merger_tb::run_1()
+{
+ IN1->write(OpticalSignal(1.0, 1550e-9));
+ wait(100, SC_MS);
+ IN2->write(OpticalSignal(1.0, 1550e-9));
+ wait(100, SC_MS);
+ IN1->write(OpticalSignal(sqrt(2.0), 1550e-9));
+ IN2->write(OpticalSignal(sqrt(2.0), 1550e-9));
+ wait(100, SC_MS);
+}
+
+void Merger_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 4;
+ while(true)
+ {
+ wait();
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN1: " << IN1->read() << std::endl
+ << "\tIN2: " << IN2->read() << std::endl
+ << "\tOUT: " << OUT->read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+ if(event_counter == 2)
+ {
+ if (is_close(norm(OUT->read().m_field), 0.5, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0.5W as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ if (is_close(arg(OUT->read().m_field), 0, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0 as output phase!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 4)
+ {
+ if (is_close(norm(OUT->read().m_field), 2, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 2W as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 6)
+ {
+ if (is_close(norm(OUT->read().m_field), 4, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 2W as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Test finished!" << std::endl;
+ std::cout << "Success rate: " << success_counter << "/" << test_number << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+}
+
+void Merger_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type IN1, IN2, OUT;
+
+ Merger uut("uut", 3.0103);
+ uut.m_attenuation_dB = 0;
+ uut.p_in1(IN1);
+ uut.p_in2(IN2);
+ uut.p_out(OUT);
+
+ Merger_tb tb("tb");
+ tb.IN1(IN1);
+ tb.IN2(IN2);
+ tb.OUT(OUT);
+
+ // Open Trace file
+ // sc_trace_file *Tf;
+ std::string trace_filename = "traces/";
+ trace_filename += "merger_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ Probe probe_merger("probe_merger",specsGlobalConfig.default_trace_file);
+ probe_merger.p_in(OUT);
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/merger_tb.h b/src/tb/merger_tb.h
new file mode 100644
index 0000000..a71fd2a
--- /dev/null
+++ b/src/tb/merger_tb.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <merger.h>
+#include <optical_signal.h>
+#include <systemc.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(Merger_tb)
+{
+public:
+ spx::oa_port_out_type IN1;
+ spx::oa_port_out_type IN2;
+ spx::oa_port_in_type OUT;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(Merger_tb)
+ {
+ SC_HAS_PROCESS(Merger_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN1 << IN2 << OUT;
+ }
+};
+
+void Merger_tb_run();
+
diff --git a/src/tb/mesh_tb.cpp b/src/tb/mesh_tb.cpp
new file mode 100644
index 0000000..9effd11
--- /dev/null
+++ b/src/tb/mesh_tb.cpp
@@ -0,0 +1,130 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/mesh_tb.h>
+
+#include "general_utils.h"
+
+void mesh_tb::run_1()
+{
+ IN->write(OpticalSignal(sqrt(1.0), 1550e-9));
+ vtheta.write(M_PI);
+ vphi.write(1);
+ wait(1, SC_NS);
+ // vtheta.write(M_PI_2);
+ // wait(1, SC_NS);
+ // vtheta.write(M_PI);
+ // wait(1, SC_NS);
+ // vphi.write(1);
+ // wait(1, SC_NS);
+
+ while (true) { wait(); }
+}
+
+void mesh_tb::monitor()
+{
+ while(true)
+ {
+ wait();
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN: " << IN->read() << std::endl
+ << "\tPHI: " << vphi.read() << std::endl
+ << "\tTHETA: " << vtheta.read() << std::endl
+ << "\tOUT1: " << OUT1->read() << std::endl
+ << "\tOUT2: " << OUT2->read() << std::endl
+ << "\tOUT3: " << OUT3->read() << std::endl
+ << "\tOUT4: " << OUT4->read() << std::endl
+ << "\tOUT5: " << OUT5->read() << std::endl;
+ }
+
+}
+
+void mesh_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type SIG, ZERO, OUT1, OUT2, OUT3, OUT4, OUT5;
+ sc_signal<double> vphi,vtheta,e_zero;
+
+ Clements mesh1("mesh1", 5, 1, 0, 0, 0, 0, 1);
+ mesh1.p_in[0]->bind(SIG);
+ mesh1.p_in[1]->bind(SIG);
+ mesh1.p_in[2]->bind(SIG);
+ mesh1.p_in[3]->bind(SIG);
+ mesh1.p_in[4]->bind(SIG);
+ mesh1.p_out[0]->bind(OUT1);
+ mesh1.p_out[1]->bind(OUT2);
+ mesh1.p_out[2]->bind(OUT3);
+ mesh1.p_out[3]->bind(OUT4);
+ mesh1.p_out[4]->bind(OUT5);
+
+ mesh1.p_vphi[0]->bind(e_zero);
+ mesh1.p_vtheta[0]->bind(vtheta);
+
+ mesh1.p_vphi[1]->bind(e_zero);
+ mesh1.p_vtheta[1]->bind(e_zero);
+
+ mesh1.p_vphi[2]->bind(e_zero);
+ mesh1.p_vtheta[2]->bind(vtheta);
+
+ mesh1.p_vphi[3]->bind(e_zero);
+ mesh1.p_vtheta[3]->bind(e_zero);
+
+ mesh1.p_vphi[4]->bind(e_zero);
+ mesh1.p_vtheta[4]->bind(e_zero);
+
+ mesh1.p_vphi[5]->bind(e_zero);
+ mesh1.p_vtheta[5]->bind(e_zero);
+
+ mesh1.p_vphi[6]->bind(e_zero);
+ mesh1.p_vtheta[6]->bind(e_zero);
+
+ mesh1.p_vphi[7]->bind(e_zero);
+ mesh1.p_vtheta[7]->bind(e_zero);
+
+ mesh1.p_vphi[8]->bind(e_zero);
+ mesh1.p_vtheta[8]->bind(e_zero);
+
+ mesh1.p_vphi[9]->bind(e_zero);
+ mesh1.p_vtheta[9]->bind(e_zero);
+
+ mesh1.init();
+
+ mesh_tb tb("tb");
+ tb.IN(SIG);
+ tb.OUT1(OUT1);
+ tb.OUT2(OUT2);
+ tb.OUT3(OUT3);
+ tb.OUT4(OUT4);
+ tb.OUT5(OUT5);
+ tb.vphi(vphi);
+ tb.vtheta(vtheta);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "mesh_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+
+ Probe probe_mzi_1("probe_mzi_1",specsGlobalConfig.default_trace_file);
+ probe_mzi_1.p_in(OUT1);
+ Probe probe_mzi_2("probe_mzi_2",specsGlobalConfig.default_trace_file);
+ probe_mzi_2.p_in(OUT2);
+ Probe probe_in("probe_in",specsGlobalConfig.default_trace_file);
+ probe_in.p_in(SIG);
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/mesh_tb.h b/src/tb/mesh_tb.h
new file mode 100644
index 0000000..1e7e3dd
--- /dev/null
+++ b/src/tb/mesh_tb.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <systemc.h>
+#include <probe.h>
+#include <specs.h>
+#include <clements.h>
+
+SC_MODULE(mesh_tb)
+{
+public:
+ spx::oa_port_out_type IN;
+ spx::oa_port_in_type OUT1, OUT2, OUT3, OUT4, OUT5;
+ sc_out<double> vphi,vtheta;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(mesh_tb)
+ {
+ SC_HAS_PROCESS(mesh_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN << OUT1 << OUT2 << OUT3 << OUT4 << OUT5 << vphi << vtheta;
+ }
+};
+
+void mesh_tb_run();
diff --git a/src/tb/mzi_tb.cpp b/src/tb/mzi_tb.cpp
new file mode 100644
index 0000000..2b9905a
--- /dev/null
+++ b/src/tb/mzi_tb.cpp
@@ -0,0 +1,86 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/mzi_tb.h>
+
+#include "general_utils.h"
+
+void mzi_tb::run_1()
+{
+ IN->write(OpticalSignal(sqrt(1.0), 1550e-9));
+ wait(1, SC_NS);
+ vtheta.write(M_PI_2);
+ wait(1, SC_NS);
+ vtheta.write(M_PI);
+ wait(1, SC_NS);
+ vphi.write(1);
+ wait(1, SC_NS);
+
+ while (true) { wait(); }
+}
+
+void mzi_tb::monitor()
+{
+ while(true)
+ {
+ wait();
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN: " << IN->read() << std::endl
+ << "\tPHI: " << vphi.read() << std::endl
+ << "\tTHETA: " << vtheta.read() << std::endl
+ << "\tOUT1: " << OUT1->read() << std::endl
+ << "\tOUT2: " << OUT2->read() << std::endl;
+ }
+
+}
+
+void MZI_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type IN1, IN2, OUT1, OUT2;
+ spx::ea_signal_type vphi,vtheta;
+
+ MZI mzi1("mzi1",0,0,0,0,0,1);
+ mzi1.p_in1(IN1);
+ mzi1.p_in2(IN2);
+ mzi1.p_out1(OUT1);
+ mzi1.p_out2(OUT2);
+ mzi1.p_vphi(vphi);
+ mzi1.p_vtheta(vtheta);
+
+ mzi_tb tb("tb");
+ tb.IN(IN1);
+ tb.OUT1(OUT1);
+ tb.OUT2(OUT2);
+ tb.vphi(vphi);
+ tb.vtheta(vtheta);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "mzi_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+
+ Probe probe_mzi_1("probe_mzi_1",specsGlobalConfig.default_trace_file);
+ probe_mzi_1.p_in(OUT1);
+ Probe probe_mzi_2("probe_mzi_2",specsGlobalConfig.default_trace_file);
+ probe_mzi_2.p_in(OUT2);
+ Probe probe_in("probe_in",specsGlobalConfig.default_trace_file);
+ probe_in.p_in(IN1);
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/mzi_tb.h b/src/tb/mzi_tb.h
new file mode 100644
index 0000000..16ed624
--- /dev/null
+++ b/src/tb/mzi_tb.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <systemc.h>
+#include <waveguide.h>
+#include <directional_coupler.h>
+#include <mzi.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(mzi_tb)
+{
+public:
+ spx::oa_port_out_type IN;
+ spx::oa_port_in_type OUT1, OUT2;
+ sc_out<double> vphi,vtheta;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(mzi_tb)
+ {
+ SC_HAS_PROCESS(mzi_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN << OUT1 << OUT2 << vphi << vtheta;
+ }
+};
+
+void MZI_tb_run();
diff --git a/src/tb/pcm_device_tb.cpp b/src/tb/pcm_device_tb.cpp
new file mode 100644
index 0000000..b279e6c
--- /dev/null
+++ b/src/tb/pcm_device_tb.cpp
@@ -0,0 +1,129 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/pcm_device_tb.h>
+
+#include "general_utils.h"
+
+void PCMElement_tb::run_1()
+{
+ IN->write(OpticalSignal(sqrt(1.0e-3), 1.55e-6));
+ wait(10, SC_MS);
+ IN->write(OpticalSignal(sqrt(2*1e-3), 1.55e-6)); // to 2W
+ wait(10, SC_MS);
+ IN->write(OpticalSignal(0, 1.55e-6));
+ wait(10, SC_MS);
+ IN->write(OpticalSignal(sqrt(1.0e-3), 1.55e-6));
+ wait(10, SC_MS);
+ IN->write(OpticalSignal(sqrt(2*1.0e-3), 1.55e-6));
+ wait(10, SC_MS);
+ IN->write(OpticalSignal(0, 1.55e-6));
+ wait(10, SC_MS);
+ IN->write(OpticalSignal(sqrt(1.0e-3), 1.55e-6));
+
+
+ while (true) { wait(); }
+}
+
+void PCMElement_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 3;
+ while(true)
+ {
+ wait();
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN: " << IN->read() << std::endl
+ << "\tOUT: " << OUT->read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+
+ if(event_counter == 2)
+ {
+ if (is_close(norm(OUT->read().m_field), 0.000850, 1e-8))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0.850mW as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 8)
+ {
+ if (is_close(norm(OUT->read().m_field), 0.000854758, 1e-8))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0.854mW as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 14)
+ {
+ if (is_close(norm(OUT->read().m_field), 0.000859495, 1e-8))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0.859mW as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Test finished!" << std::endl;
+ std::cout << "Success rate: " << success_counter << "/" << test_number << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+}
+
+void PCMElement_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type IN, OUT;
+
+ PCMElement pcm("pcm", 25e-6, 63, 0);
+ pcm.p_in(IN);
+ pcm.p_out(OUT);
+
+ PCMElement_tb tb("tb");
+ tb.IN(IN);
+ tb.OUT(OUT);
+
+ // Open Trace file
+
+ std::string trace_filename = "traces/";
+ trace_filename += "pcm_device_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ Probe probe_in("in",specsGlobalConfig.default_trace_file);
+ probe_in.p_in(IN);
+
+ Probe probe_out("out",specsGlobalConfig.default_trace_file);
+ probe_out.p_in(OUT);
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // extra traces should come after prepareSimulation
+ sc_trace(specsGlobalConfig.default_trace_file, pcm.m_state, "STATE");
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/pcm_device_tb.h b/src/tb/pcm_device_tb.h
new file mode 100644
index 0000000..a9b7195
--- /dev/null
+++ b/src/tb/pcm_device_tb.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <systemc.h>
+
+#include <optical_signal.h>
+#include <pcm_device.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(PCMElement_tb)
+{
+public:
+ spx::oa_port_out_type IN;
+ spx::oa_port_in_type OUT;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(PCMElement_tb)
+ {
+ SC_HAS_PROCESS(PCMElement_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN << OUT;
+ }
+};
+
+void PCMElement_tb_run();
diff --git a/src/tb/phase_shifter_tb.cpp b/src/tb/phase_shifter_tb.cpp
new file mode 100644
index 0000000..5369e7c
--- /dev/null
+++ b/src/tb/phase_shifter_tb.cpp
@@ -0,0 +1,129 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/phase_shifter_tb.h>
+
+#include "general_utils.h"
+#include "specs.h"
+
+void ps_tb::run_1()
+{
+ V_PS.write(1.0);
+ wait(SC_ZERO_TIME);
+ IN1->write(OpticalSignal(sqrt(1.0), 1550e-9));
+ IN2->write(OpticalSignal(sqrt(1.0), 1660e-9));
+ wait(100,SC_MS);
+ V_PS.write(2.0);
+ wait(100, SC_MS);
+
+ while (true) { wait(); }
+}
+
+void ps_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 3;
+ while(true)
+ {
+ wait();
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN1: " << IN1->read() << std::endl
+ << "\tIN2: " << IN2->read() << std::endl
+ << "\tOUT: " << OUT->read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+
+ if(event_counter == 2)
+ {
+ if (is_close(abs(OUT->read().m_field), 0.630210, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0.630210W as output field!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 4)
+ {
+ if (is_close(arg(OUT->read().m_field), 2, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 2 rad as output phase!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 5)
+ {
+ if (is_close(arg(OUT->read().m_field), 2, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 2 as output phase!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Test finished!" << std::endl;
+ std::cout << "Success rate: " << success_counter << "/" << test_number << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+
+}
+
+void ps_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type IN1, IN2, OUT, YOUT;
+ spx::ea_signal_type V_PS;
+
+ Merger merg1("merg1");
+ merg1.p_in1(IN1);
+ merg1.p_in2(IN2);
+ merg1.p_out(YOUT);
+
+ PhaseShifter ps1("ps1", 1);
+ ps1.p_in(YOUT);
+ ps1.p_vin(V_PS);
+ ps1.p_out(OUT);
+
+ // Connect testbench to uut
+ ps_tb tb("tb");
+ tb.IN1(IN1);
+ tb.IN2(IN2);
+ tb.OUT(OUT);
+ tb.V_PS(V_PS);
+
+ // Attach probes
+ MLambdaProbe probe_out("out", {1550e-9, 1660e-9});
+ probe_out.p_in(OUT);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "ps_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/phase_shifter_tb.h b/src/tb/phase_shifter_tb.h
new file mode 100644
index 0000000..a59538d
--- /dev/null
+++ b/src/tb/phase_shifter_tb.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <systemc.h>
+#include <waveguide.h>
+#include <phaseshifter.h>
+#include <merger.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(ps_tb)
+{
+public:
+ spx::oa_port_out_type IN1;
+ spx::oa_port_out_type IN2;
+ sc_out<double> V_PS;
+ spx::oa_port_in_type OUT;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(ps_tb)
+ {
+ SC_HAS_PROCESS(ps_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN1 << IN2 << OUT;
+ }
+};
+
+void ps_tb_run();
diff --git a/src/tb/ring_tb.cpp b/src/tb/ring_tb.cpp
new file mode 100644
index 0000000..cc3aaf2
--- /dev/null
+++ b/src/tb/ring_tb.cpp
@@ -0,0 +1,85 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/ring_tb.h>
+
+#include "general_utils.h"
+
+void ring_tb::run_1()
+{
+ IN.write(OpticalSignal(sqrt(1.0), 1550e-9));
+ wait(10, SC_NS);
+ IN.write(OpticalSignal(0, 1550e-9));
+ wait(10, SC_NS);
+
+ IN.write(OpticalSignal(sqrt(1.0), 1550e-9));
+ wait(10, SC_NS);
+ IN.write(OpticalSignal(0, 1550e-9));
+ wait(10, SC_NS);
+
+ while(true)
+ {
+ wait();
+ }
+}
+
+void ring_tb::monitor()
+{
+ while(true)
+ {
+ wait();
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN: " << IN.read() << std::endl
+ << "\tOUT: " << OUT.read() << std::endl;
+ }
+
+}
+
+void Ring_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ double neff = 1.0;
+ double loss_db_cm = 0;
+ double coupling_through = 0.85;
+
+ spx::oa_signal_type IN, OUT;
+ spx::oa_signal_type RING1, RING2;
+
+ DirectionalCoupler dc1("dc1", coupling_through, 0);
+ dc1.p_in1(IN);
+ dc1.p_out1(OUT);
+ dc1.p_in2(RING1);
+ dc1.p_out2(RING2);
+
+ Waveguide wg1("wg1", 1*100.0*1550.0e-6/(2*neff), loss_db_cm, neff, neff);
+ wg1.p_in(RING2);
+ wg1.p_out(RING1);
+
+ ring_tb tb("tb");
+ tb.IN(IN);
+ tb.OUT(OUT);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "ring_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ Probe probe_ring("probe_ring",specsGlobalConfig.default_trace_file);
+ probe_ring.p_in(OUT);
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/ring_tb.h b/src/tb/ring_tb.h
new file mode 100644
index 0000000..b995513
--- /dev/null
+++ b/src/tb/ring_tb.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <systemc.h>
+#include <waveguide.h>
+#include <directional_coupler.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(ring_tb)
+{
+public:
+ sc_out<OpticalSignal> IN;
+ sc_in<OpticalSignal> OUT;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(ring_tb)
+ {
+ SC_HAS_PROCESS(ring_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN << OUT;
+ }
+};
+
+void Ring_tb_run();
diff --git a/src/tb/splitter_tb.cpp b/src/tb/splitter_tb.cpp
new file mode 100644
index 0000000..eeb3420
--- /dev/null
+++ b/src/tb/splitter_tb.cpp
@@ -0,0 +1,123 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/splitter_tb.h>
+
+#include "general_utils.h"
+
+void Splitter_tb::run_1()
+{
+ IN->write(OpticalSignal(sqrt(1.0), 1550e-9));
+ wait(100, SC_MS);
+ IN->write(OpticalSignal(-sqrt(1.0), 1550e-9));
+ wait(100, SC_MS);
+ IN->write(OpticalSignal(sqrt(2.0), 1550e-9));
+ wait(100, SC_MS);
+ IN->write(OpticalSignal(-sqrt(2.0), 1550e-9));
+ wait(10, SC_PS);
+ IN->write(OpticalSignal(sqrt(3.0), 1550e-9));
+ wait(100, SC_MS);
+
+ wait(OUT1->value_changed_event());
+ wait(1, SC_SEC);
+ sc_stop();
+}
+
+void Splitter_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 3;
+ while(true)
+ {
+ wait();
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN: " << IN->read() << std::endl
+ << "\tOUT1: " << OUT1->read() << std::endl
+ << "\tOUT2: " << OUT2->read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+
+ if(event_counter == 10)
+ {
+ if (is_close(norm(OUT1->read().m_field), 0.75, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0.75W as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ if (is_close(norm(OUT1->read().m_field), norm(OUT2->read().m_field), 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected same power in both ends!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ if (is_close(arg(OUT1->read().m_field), 0, 1e-4) && is_close(arg(OUT2->read().m_field), 0, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected zero phase in both ends!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Test finished!" << std::endl;
+ std::cout << "Success rate: " << success_counter << "/" << test_number << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+}
+
+void Splitter_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type IN, OUT1, OUT2;
+
+ Splitter uut("uut");
+ uut.m_attenuation_dB = 3.0103;
+ uut.p_in(IN);
+ uut.p_out1(OUT1);
+ uut.p_out2(OUT2);
+
+ Splitter_tb tb("tb");
+ tb.IN(IN);
+ tb.OUT1(OUT1);
+ tb.OUT2(OUT2);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "splitter_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ Probe probe_splitter_1("probe_splitter_1",specsGlobalConfig.default_trace_file);
+ probe_splitter_1.p_in(OUT1);
+
+ Probe probe_splitter_2("probe_splitter_2",specsGlobalConfig.default_trace_file);
+ probe_splitter_2.p_in(OUT2);
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/splitter_tb.h b/src/tb/splitter_tb.h
new file mode 100644
index 0000000..68d2a8d
--- /dev/null
+++ b/src/tb/splitter_tb.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <splitter.h>
+#include <systemc.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(Splitter_tb)
+{
+public:
+ spx::oa_port_out_type IN;
+ spx::oa_port_in_type OUT1;
+ spx::oa_port_in_type OUT2;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(Splitter_tb)
+ {
+ SC_HAS_PROCESS(Splitter_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN << OUT1 << OUT2;
+ }
+};
+
+void Splitter_tb_run();
diff --git a/src/tb/wg_tb.cpp b/src/tb/wg_tb.cpp
new file mode 100644
index 0000000..7ccebf5
--- /dev/null
+++ b/src/tb/wg_tb.cpp
@@ -0,0 +1,143 @@
+#include <ctime>
+#include <iomanip>
+#include <tb/wg_tb.h>
+
+#include "general_utils.h"
+#include "devices/generic_waveguide.h"
+#include "specs.h"
+
+void wg_tb::run_1()
+{
+ IN->write(OpticalSignal(sqrt(1.0), 1550e-9));
+ wait(100, SC_MS);
+ IN->write(OpticalSignal(0, 1550e-9));
+ wait(100, SC_MS);
+ IN->write(OpticalSignal(sqrt(2.0), 1550e-9));
+ wait(100, SC_MS);
+ IN->write(OpticalSignal(0, 1550e-9));
+ wait(10, SC_PS);
+ IN->write(OpticalSignal(sqrt(3.0), 1550e-9));
+ wait(100, SC_MS);
+
+ while (true) { wait(); }
+}
+
+void wg_tb::monitor()
+{
+ unsigned int event_counter = 0;
+ unsigned int success_counter = 0;
+ const unsigned int test_number = 3;
+ while(true)
+ {
+ wait();
+ event_counter++;
+ std::cout << sc_time_stamp() << ":" << std::endl
+ << "\tIN: " << IN->read() << std::endl
+ << "\tOUT: " << OUT->read() << std::endl
+ << "\tCOUNT: " << event_counter << std::endl;
+
+ if(event_counter == 2)
+ {
+ if (is_close(norm(OUT->read().m_field), 0.5, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 0.5W as output power!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 6)
+ {
+ if (is_close(arg(OUT->read().m_field), -2.4322, 1e-4))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected -2.4322 rad as output phase!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+ if(event_counter == 10)
+ {
+ if (is_close(norm(OUT->read().m_field), 1.5, 1e-4) && (is_close(arg(OUT->read().m_field), -2.4322, 1e-4)))
+ success_counter++;
+ else
+ {
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Failure!" << std::endl;
+ std::cout << "Expected 1.5W as output power and -2.4322 as output phase!" << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ std::cout << "Test finished!" << std::endl;
+ std::cout << "Success rate: " << success_counter << "/" << test_number << std::endl;
+ std::cout << "-----------------/! \\---------------" << std::endl;
+ }
+ }
+
+}
+
+void wg_tb_run()
+{
+ // Apply SPECS resolution before creating any device
+ specsGlobalConfig.applyEngineResolution();
+
+ spx::oa_signal_type IN("sig_in"), OUT("sig_out");
+ spx::oa_signal_type TERM_r, TERM_w;
+
+ // Unidirectional variant
+ // Waveguide uut("uut", 1, 0, 1, 1);
+ // uut.m_attenuation_dB_cm = 3.0103;
+ // uut.p_in(IN);
+ // uut.p_out(OUT);
+
+ // Bidirectional variant
+ WaveguideBi uut("uut", 1, 0, 1, 1);
+ uut.m_attenuation_dB_cm = 3.0103;
+ uut.p0_in(IN);
+ uut.p0_out(TERM_w);
+ uut.p1_in(TERM_r);
+ uut.p1_out(OUT);
+
+ // GenericWaveguide uut("uut",3.0103*100,1,1,0.01);
+ // uut.ports_in[0]->bind(IN);
+ // uut.ports_in[1]->bind(TERM_r);
+ // uut.ports_out[0]->bind(TERM_w);
+ // uut.ports_out[1]->bind(OUT);
+
+ // Connect testbench to uut
+ wg_tb tb("tb");
+ tb.IN(IN);
+ tb.OUT(OUT);
+
+ // Attach probes
+ Probe probe_in("in");
+ probe_in.p_in(IN);
+
+ Probe probe_out("out");
+ probe_out.p_in(OUT);
+
+ // Open Trace file
+ std::string trace_filename = "traces/";
+ trace_filename += "waveguide_tb";
+ specsGlobalConfig.trace_filename = trace_filename;
+
+ // Apply SPECS options specific to the testbench
+ specsGlobalConfig.simulation_mode = OpticalOutputPortMode::EVENT_DRIVEN;
+ specsGlobalConfig.trace_all_optical_nets = 0;
+
+ // Run SPECS pre-simulation code
+ specsGlobalConfig.prepareSimulation();
+
+ // Start simulation
+ sc_start();
+
+ std::cout << std::endl << std::endl;
+ std::cout << ".vcd trace file: " << specsGlobalConfig.trace_filename << std::endl;
+
+ sc_close_vcd_trace_file(specsGlobalConfig.default_trace_file);
+}
diff --git a/src/tb/wg_tb.h b/src/tb/wg_tb.h
new file mode 100644
index 0000000..5d0a84f
--- /dev/null
+++ b/src/tb/wg_tb.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <optical_signal.h>
+#include <systemc.h>
+#include <waveguide.h>
+#include <probe.h>
+#include <specs.h>
+
+SC_MODULE(wg_tb)
+{
+public:
+ spx::oa_port_out_type IN;
+ spx::oa_port_in_type OUT;
+
+ void run_1();
+ void monitor();
+ SC_CTOR(wg_tb)
+ {
+ SC_HAS_PROCESS(wg_tb);
+
+ SC_THREAD(run_1);
+
+ SC_THREAD(monitor);
+ sensitive << IN << OUT;
+ }
+};
+
+void wg_tb_run();