From d8eb9866a0f29200cbc1607c9005572b7a219ca5 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 21 Aug 2019 18:49:48 -0600 Subject: [PATCH] refactored gate verilog generation --- .../fpga_x2p/base/link_arch_circuit_lib.cpp | 5 +- .../verilog/verilog_essential_gates.cpp | 225 +++++++++++++++++- .../verilog/verilog_submodule_utils.cpp | 11 +- .../fpga_x2p/verilog/verilog_writer_utils.cpp | 6 +- 4 files changed, 236 insertions(+), 11 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp index 8a78d734e..342524903 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/link_arch_circuit_lib.cpp @@ -234,8 +234,9 @@ t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type, case SPICE_MODEL_PORT_SRAM: break; default: - vpr_printf(TIO_MESSAGE_ERROR,"(File:%s, [LINE%d])Invalid type for circuit model port(%s)!\n", - __FILE__, __LINE__, circuit_lib.port_prefix(circuit_port)); + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid type for circuit model port(%s)!\n", + __FILE__, __LINE__, circuit_lib.port_prefix(circuit_port).c_str()); exit(1); } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp index 25010abd2..593da2889 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_essential_gates.cpp @@ -331,6 +331,222 @@ void print_verilog_passgate_module(std::fstream& fp, print_verilog_module_end(fp, circuit_lib.model_name(circuit_model)); } +/************************************************ + * Print Verilog body codes of an N-input AND gate + ***********************************************/ +static +void print_verilog_and_or_gate_body(std::fstream& fp, + const CircuitLibrary& circuit_lib, + const CircuitModelId& circuit_model, + const std::vector& input_ports, + const std::vector& output_ports) { + /* Ensure a valid file handler*/ + check_file_handler(fp); + + /* Find the logic operator for the gate */ + std::string gate_verilog_operator; + switch (circuit_lib.gate_type(circuit_model)) { + case SPICE_MODEL_GATE_AND: + gate_verilog_operator = "&"; + break; + case SPICE_MODEL_GATE_OR: + gate_verilog_operator = "|"; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid topology for circuit model (name=%s)!\n", + __FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str()); + exit(1); + } + + /* Output verilog codes */ + print_verilog_comment(fp, std::string("----- Verilog codes of a " + std::to_string(input_ports.size()) + "-input " + std::to_string(output_ports.size()) + "-output AND gate -----")); + + for (const auto& output_port : output_ports) { + for (const auto& output_pin : circuit_lib.pins(output_port)) { + BasicPort output_port_info(circuit_lib.port_lib_name(output_port), output_pin, output_pin); + fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, output_port_info); + fp << " = "; + + size_t port_cnt = 0; + for (const auto& input_port : input_ports) { + for (const auto& input_pin : circuit_lib.pins(input_port)) { + /* Do not output AND/OR operator for the first element in the loop */ + if (0 < port_cnt) { + fp << " " << gate_verilog_operator << " "; + } + + BasicPort input_port_info(circuit_lib.port_lib_name(input_port), input_pin, input_pin); + fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port_info); + + /* Increment the counter for port */ + port_cnt++; + } + } + fp << ";" << std::endl; + } + } +} + +/************************************************ + * Print Verilog body codes of an 2-input MUX gate + ***********************************************/ +static +void print_verilog_mux2_gate_body(std::fstream& fp, + const CircuitLibrary& circuit_lib, + const CircuitModelId& circuit_model, + const std::vector& input_ports, + const std::vector& output_ports) { + /* Ensure a valid file handler*/ + check_file_handler(fp); + + /* TODO: Move the check codes to check_circuit_library.cpp */ + size_t num_err = 0; + /* Check on the port sequence and map */ + /* MUX2 should only have 1 output port with size 1 */ + if (1 != output_ports.size()) { + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) MUX2 circuit model (%s) must have only 1 output!\n", + __FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str()); + num_err++; + } + for (const auto& output_port : output_ports) { + /* Bypass port size of 1 */ + if (1 == circuit_lib.port_size(output_port)) { + continue; + } + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Output port size of a MUX2 circuit model (%s) must be 1!\n", + __FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str()); + num_err++; + } + /* MUX2 should only have 3 output port, each of which has a port size of 1 */ + if (3 != input_ports.size()) { + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) MUX2 circuit model (%s) must have only 3 input!\n", + __FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str()); + num_err++; + } + + for (const auto& input_port : input_ports) { + /* Bypass port size of 1 */ + if (1 == circuit_lib.port_size(input_port)) { + continue; + } + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Input size MUX2 circuit model (%s) must be 1!\n", + __FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str()); + num_err++; + } + if (0 < num_err) { + exit(1); + } + + /* Now, we output the logic of MUX2 + * IMPORTANT Restriction: + * We always assum the first two inputs are data inputs + * the third input is the select port + */ + fp << "\tassign "; + BasicPort out_port_info(circuit_lib.port_lib_name(output_ports[0]), 0, 0); + BasicPort sel_port_info(circuit_lib.port_lib_name(input_ports[2]), 0, 0); + BasicPort in0_port_info(circuit_lib.port_lib_name(input_ports[0]), 0, 0); + BasicPort in1_port_info(circuit_lib.port_lib_name(input_ports[1]), 0, 0); + + fp << generate_verilog_port(VERILOG_PORT_CONKT, out_port_info); + fp << " = "; + fp << generate_verilog_port(VERILOG_PORT_CONKT, sel_port_info); + fp << " ? "; + fp << generate_verilog_port(VERILOG_PORT_CONKT, in0_port_info); + fp << " : "; + fp << generate_verilog_port(VERILOG_PORT_CONKT, in1_port_info); + fp << ";" << std::endl; +} + +/************************************************ + * Print a Verilog module of a logic gate + * which are standard cells + * Supported gate types: + * 1. N-input AND + * 2. N-input OR + * 3. 2-input MUX + ***********************************************/ +static +void print_verilog_gate_module(std::fstream& fp, + const CircuitLibrary& circuit_lib, + const CircuitModelId& circuit_model) { + /* Ensure a valid file handler*/ + check_file_handler(fp); + + /* Find the input port, output port*/ + std::vector input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true); + std::vector output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true); + std::vector global_ports = circuit_lib.model_global_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT); + + /* Make sure: + * There is only 1 output port, + * each size of which is 1 + */ + VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) ); + + /* Print Verilog module */ + print_verilog_module_definition(fp, circuit_lib.model_name(circuit_model)); + + /* TODO: print global ports, this should be handled by ModuleManager */ + for (const auto& port : global_ports) { + /* Configure each global port */ + BasicPort basic_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + /* Print port */ + fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, basic_port) << "," << std::endl; + } + + for (const auto& input_port : input_ports) { + /* Configure each global port */ + BasicPort basic_port(circuit_lib.port_lib_name(input_port), circuit_lib.port_size(input_port)); + /* Print port */ + fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, basic_port) << "," << std::endl; + } + + /* Configure each global port */ + for (const auto& output_port : output_ports) { + BasicPort basic_port(circuit_lib.port_lib_name(output_port), circuit_lib.port_size(output_port)); + /* Print port */ + fp << "\t" << generate_verilog_port(VERILOG_PORT_OUTPUT, basic_port); + /* Last port does not need a comma */ + if (output_port != output_ports.back()) { + fp << "," << std::endl; + } else { + fp << std::endl; + } + } + fp << ");" << std::endl; + + /* Dump logics */ + switch (circuit_lib.gate_type(circuit_model)) { + case SPICE_MODEL_GATE_AND: + case SPICE_MODEL_GATE_OR: + print_verilog_and_or_gate_body(fp, circuit_lib, circuit_model, input_ports, output_ports); + break; + case SPICE_MODEL_GATE_MUX2: + print_verilog_mux2_gate_body(fp, circuit_lib, circuit_model, input_ports, output_ports); + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid topology for circuit model (name=%s)!\n", + __FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str()); + exit(1); + } + + /* Print timing info */ + print_verilog_submodule_timing(fp, circuit_lib, circuit_model); + + /* Print signal initialization */ + print_verilog_submodule_signal_init(fp, circuit_lib, circuit_model); + + /* Put an end to the Verilog module */ + print_verilog_module_end(fp, circuit_lib.model_name(circuit_model)); +} + /************************************************ * Generate the Verilog netlist for essential gates * include inverters, buffers, transmission-gates, @@ -365,15 +581,16 @@ void print_verilog_submodule_essentials(const std::string& verilog_dir, } if (SPICE_MODEL_INVBUF == circuit_lib.model_type(circuit_model)) { print_verilog_invbuf_module(fp, circuit_lib, circuit_model); + continue; } if (SPICE_MODEL_PASSGATE == circuit_lib.model_type(circuit_model)) { print_verilog_passgate_module(fp, circuit_lib, circuit_model); + continue; } - /* - if (SPICE_MODEL_GATE == spice_models[imodel].type) { - dump_verilog_gate_module(fp, &(spice_models[imodel])); + if (SPICE_MODEL_GATE == circuit_lib.model_type(circuit_model)) { + print_verilog_gate_module(fp, circuit_lib, circuit_model); + continue; } - */ } /* Close file handler*/ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_utils.cpp index e587c1096..39ba45e46 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodule_utils.cpp @@ -95,13 +95,20 @@ void print_verilog_submodule_signal_init(std::fstream& fp, /* Only for formal verification: deposite a zero signal values */ /* Initialize each input port */ for (const auto& input_port : circuit_lib.model_input_ports(circuit_model)) { - fp << "\t\t$deposit(" << circuit_lib.port_lib_name(input_port) << ", 1'b0);" << std::endl; + BasicPort input_port_info(circuit_lib.port_lib_name(input_port), circuit_lib.port_size(input_port)); + fp << "\t\t$deposit("; + fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port_info); + fp << ", " << circuit_lib.port_size(input_port) << "'b" << std::string(circuit_lib.port_size(input_port), '0'); + fp << ");" << std::endl; } fp << "\t`else" << std::endl; /* Regular case: deposite initial signal values: a random value */ for (const auto& input_port : circuit_lib.model_input_ports(circuit_model)) { - fp << "\t\t$deposit(" << circuit_lib.port_lib_name(input_port) << ", $random);" << std::endl; + BasicPort input_port_info(circuit_lib.port_lib_name(input_port), circuit_lib.port_size(input_port)); + fp << "\t\t$deposit("; + fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port_info); + fp << ", $random);" << std::endl; } fp << "\t`endif\n" << std::endl; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp index 2743cdb6f..ec8dae1a1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_writer_utils.cpp @@ -33,7 +33,7 @@ void print_verilog_file_header(std::fstream& fp, fp << "//\tFPGA Synthesizable Verilog Netlist" << std::endl; fp << "//\tDescription: " << usage << std::endl; fp << "//\tAuthor: Xifan TANG" << std::endl; - fp << "//\t Organization: University of Utah" << std::endl; + fp << "//\tOrganization: University of Utah" << std::endl; fp << "//\tDate: " << std::ctime(&end_time) ; fp << "//-------------------------------------------" << std::endl; fp << "//----- Time scale -----" << std::endl; @@ -107,10 +107,10 @@ std::string generate_verilog_port(const enum e_dump_verilog_port_type& verilog_p * others require a format of [:] */ if (VERILOG_PORT_CONKT == verilog_port_type) { - verilog_line = port_info.get_name() + " " + size_str; + verilog_line = port_info.get_name() + size_str; } else { verilog_line = VERILOG_PORT_TYPE_STRING[verilog_port_type]; - verilog_line += "" + size_str + " " + port_info.get_name(); + verilog_line += " " + size_str + " " + port_info.get_name(); } return verilog_line;