315 lines
13 KiB
C++
315 lines
13 KiB
C++
|
#ifndef SDC_H
|
||
|
#define SDC_H
|
||
|
/*
|
||
|
* libsdcparse - Kevin E. Murray 2014
|
||
|
*
|
||
|
* Released under MIT License see LICENSE.txt for details.
|
||
|
*
|
||
|
* OVERVIEW
|
||
|
* --------------------------
|
||
|
* This library provides basic parsing capabilities for a subset of commands in
|
||
|
* Synopsys Design Constraint (SDC) files. SDC files are typically used to
|
||
|
* set timing constraints on digital circuits.
|
||
|
*
|
||
|
* USING THIS LIBRARY
|
||
|
* --------------------------
|
||
|
* Since this is NOT a full TCL interpreter, 'function calls' to get_ports or
|
||
|
* get_clocks, are converted to string_group, with the group_type field set
|
||
|
* to either StringType::CLOCK or StringType::SDC_PORT respectively. That is,
|
||
|
* they are represented as the sets of the strings passed to those functions.
|
||
|
* It is left up to the application to interpret them.
|
||
|
*
|
||
|
* After parsing, each SDC command is represented as a C struct. Typically each
|
||
|
* command is parsed into a unique type of struct, however some closely related commands
|
||
|
* (such as set_input_delay and set_output_delay) may share a struct and be identified
|
||
|
* by a 'type' field in the struct.
|
||
|
*
|
||
|
* All supported SDC commands are collected into a commands struct which
|
||
|
* represents the entire SDC file.
|
||
|
*
|
||
|
* See the associated main.c for example usage.
|
||
|
*
|
||
|
* EXTENDING THE LIBRARY
|
||
|
* --------------------------
|
||
|
* The parser uses a lexer generated by 'flex' (see sdc_parse.l), and a parser
|
||
|
* generated by 'bison' (see sdc_parse.y).
|
||
|
*
|
||
|
* While the parser currently supports only a subset of the full SDC specification,
|
||
|
* it should be relatively straightforward to extend it as follows:
|
||
|
*
|
||
|
* 1) To add a new option to an existing command
|
||
|
* a) Add the new token definition to sdc_parse.y (e.g. ARG_HOLD)
|
||
|
* b) Add a pattern to sdc_parse.l which returns the token (e.g. '-hold')
|
||
|
* c) Add a new (optional) rule to the appropriate command in sdc_parse.y
|
||
|
* d) Add an action for the added rule which makes the appropriate
|
||
|
* modifications to the command's struct. It likely that you will
|
||
|
* want to do this as a function call and put the function definition
|
||
|
* in sdc_common.c. If the option may conflict with others it is
|
||
|
* typically checked at this point, with errors reported using sdc_error().
|
||
|
* e) Command is automatically added using the appropriate add_sdc*()
|
||
|
* function, which also verifies the options. Command level consistency
|
||
|
* checks (e.g. option required) typically go here.
|
||
|
*
|
||
|
* 2) To add a new command
|
||
|
* a) Add the new token definition to sdc_parse.y (e.g. CMD_SET_TIME_FORMAT)
|
||
|
* b) Add a pattern to sdc_parse.l which returns the token (e.g. 'set_time_format')
|
||
|
* c) Add a new rule for the command to sdc_parse.y e.g.:
|
||
|
* cmd_set_time_format: CMD_SET_TIME_FORMAT
|
||
|
* d) Create a new C struct to represent the command, and write an alloc function
|
||
|
* (in sdc_common.c) that is called by the first rule e.g.:
|
||
|
* cmd_set_time_format: CMD_SET_TIME_FORMAT {$$ = alloc_sdc_set_time_units();}
|
||
|
* c) Add options to the command as outlined in (1)
|
||
|
* d) Create an add_sdc*() command and extend the s_sdc_commands struct to include
|
||
|
* the new command. Call it in the top level sdc_commands rule e.g.:
|
||
|
*
|
||
|
* sdc_commands: ...
|
||
|
* | ... //Other commands
|
||
|
* | sdc_commands cmd_set_time_format EOL {$$ = add_sdc_set_time_format($1, $2); }
|
||
|
*
|
||
|
*/
|
||
|
#include <vector>
|
||
|
#include <string>
|
||
|
#include <memory>
|
||
|
#include <limits>
|
||
|
#include <functional>
|
||
|
|
||
|
namespace sdcparse {
|
||
|
/*
|
||
|
* Forward declarations
|
||
|
*/
|
||
|
enum class IoDelayType;
|
||
|
enum class ClockGroupsType;
|
||
|
enum class FromToType;
|
||
|
enum class McpType;
|
||
|
enum class StringGroupType;
|
||
|
|
||
|
struct CreateClock;
|
||
|
struct SetIoDelay;
|
||
|
struct SetClockGroups;
|
||
|
struct SetFalsePath;
|
||
|
struct SetMinMaxDelay;
|
||
|
struct SetMulticyclePath;
|
||
|
struct SetClockUncertainty;
|
||
|
struct SetClockLatency;
|
||
|
struct SetDisableTiming;
|
||
|
struct SetTimingDerate;
|
||
|
|
||
|
struct StringGroup;
|
||
|
|
||
|
|
||
|
class Callback {
|
||
|
|
||
|
public:
|
||
|
virtual ~Callback() {}
|
||
|
|
||
|
//Start of parsing
|
||
|
virtual void start_parse() = 0;
|
||
|
|
||
|
//Sets current filename
|
||
|
virtual void filename(std::string fname) = 0;
|
||
|
|
||
|
//Sets current line number
|
||
|
virtual void lineno(int line_num) = 0;
|
||
|
|
||
|
virtual void create_clock(const CreateClock& cmd) = 0;
|
||
|
virtual void set_io_delay(const SetIoDelay& cmd) = 0;
|
||
|
virtual void set_clock_groups(const SetClockGroups& cmd) = 0;
|
||
|
virtual void set_false_path(const SetFalsePath& cmd) = 0;
|
||
|
virtual void set_min_max_delay(const SetMinMaxDelay& cmd) = 0;
|
||
|
virtual void set_multicycle_path(const SetMulticyclePath& cmd) = 0;
|
||
|
virtual void set_clock_uncertainty(const SetClockUncertainty& cmd) = 0;
|
||
|
virtual void set_clock_latency(const SetClockLatency& cmd) = 0;
|
||
|
virtual void set_disable_timing(const SetDisableTiming& cmd) = 0;
|
||
|
virtual void set_timing_derate(const SetTimingDerate& cmd) = 0;
|
||
|
|
||
|
//End of parsing
|
||
|
virtual void finish_parse() = 0;
|
||
|
|
||
|
//Error during parsing
|
||
|
virtual void parse_error(const int curr_lineno, const std::string& near_text, const std::string& msg) = 0;
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* External functions for loading an SDC file
|
||
|
*/
|
||
|
void sdc_parse_filename(std::string filename, Callback& callback);
|
||
|
void sdc_parse_filename(const char* filename, Callback& callback);
|
||
|
|
||
|
//Loads from 'sdc'. 'filename' only used to pass a filename to callback and can be left unspecified
|
||
|
void sdc_parse_file(FILE* sdc, Callback& callback, const char* filename="");
|
||
|
|
||
|
/*
|
||
|
* Sentinal values
|
||
|
*/
|
||
|
constexpr double UNINITIALIZED_FLOAT = std::numeric_limits<double>::quiet_NaN();
|
||
|
constexpr int UNINITIALIZED_INT = -1;
|
||
|
|
||
|
/*
|
||
|
* Enumerations to describe specific SDC command types and attributes
|
||
|
*/
|
||
|
enum class IoDelayType {
|
||
|
INPUT,
|
||
|
OUTPUT
|
||
|
};
|
||
|
|
||
|
enum class MinMaxType {
|
||
|
MIN,
|
||
|
MAX,
|
||
|
NONE
|
||
|
};
|
||
|
|
||
|
enum class ClockGroupsType {
|
||
|
NONE,
|
||
|
EXCLUSIVE
|
||
|
};
|
||
|
|
||
|
enum class FromToType {
|
||
|
FROM,
|
||
|
TO
|
||
|
};
|
||
|
|
||
|
enum class ClockLatencyType {
|
||
|
SOURCE,
|
||
|
NONE
|
||
|
};
|
||
|
|
||
|
enum class StringGroupType {
|
||
|
STRING,
|
||
|
PORT,
|
||
|
CLOCK,
|
||
|
CELL,
|
||
|
PIN
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Common SDC data structures
|
||
|
*/
|
||
|
|
||
|
struct StringGroup {
|
||
|
StringGroup() = default;
|
||
|
StringGroup(StringGroupType group_type)
|
||
|
: type(group_type) {}
|
||
|
|
||
|
StringGroupType type = StringGroupType::STRING; //The type of the string group, default is STRING.
|
||
|
// Groups derived from 'calls' to [get_clocks {...}]
|
||
|
// and [get_ports {...}] will have types SDC_CLOCK
|
||
|
// and SDC_PORT respectively.
|
||
|
std::vector<std::string> strings; //The strings in the group
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Structures defining different SDC commands
|
||
|
*/
|
||
|
struct CreateClock {
|
||
|
std::string name = ""; //Name of the clock
|
||
|
double period = UNINITIALIZED_FLOAT; //Clock period
|
||
|
double rise_edge = UNINITIALIZED_FLOAT; //Rise time from waveform definition
|
||
|
double fall_edge = UNINITIALIZED_FLOAT; //Fall time from waveform definition
|
||
|
StringGroup targets; //The set of strings indicating clock sources.
|
||
|
// May be explicit strings or regexs.
|
||
|
bool is_virtual = false; //Identifies this as a virtual (non-netlist) clock
|
||
|
};
|
||
|
|
||
|
struct SetIoDelay {
|
||
|
SetIoDelay() = default;
|
||
|
SetIoDelay(IoDelayType io_type)
|
||
|
: type(io_type) {}
|
||
|
|
||
|
IoDelayType type = IoDelayType::INPUT; //Identifies whether this represents a
|
||
|
// set_input_delay or set_output delay
|
||
|
// command.
|
||
|
bool is_min = false; //Does delay apply for maximum delays?
|
||
|
bool is_max = false; //Does delay apply for minimum delays?
|
||
|
// Note: is_min/is_max correspond to whether the option was
|
||
|
// provided, it is up to the application to handle the case
|
||
|
// where both are left unspecified (which SDC treats as
|
||
|
// implicitly specifying both)
|
||
|
std::string clock_name = ""; //Name of the clock this constraint is associated with
|
||
|
double delay = UNINITIALIZED_FLOAT; //The maximum input delay allowed on the target ports
|
||
|
StringGroup target_ports; //The target ports
|
||
|
};
|
||
|
|
||
|
struct SetClockGroups {
|
||
|
ClockGroupsType type = ClockGroupsType::NONE; //The type of clock group relation being specified
|
||
|
std::vector<StringGroup> clock_groups; //The groups of clocks
|
||
|
};
|
||
|
|
||
|
struct SetFalsePath {
|
||
|
StringGroup from; //The source list of startpoints or clocks
|
||
|
StringGroup to; //The target list of endpoints or clocks
|
||
|
};
|
||
|
|
||
|
struct SetMinMaxDelay {
|
||
|
SetMinMaxDelay() = default;
|
||
|
SetMinMaxDelay(MinMaxType delay_type)
|
||
|
: type(delay_type) {}
|
||
|
MinMaxType type = MinMaxType::NONE; //Whether this is a min or max delay
|
||
|
double value = UNINITIALIZED_FLOAT; //The maximum/minimum allowed delay between the from
|
||
|
// and to clocks
|
||
|
StringGroup from; //The source list of startpoints or clocks
|
||
|
StringGroup to; //The target list of endpoints or clocks
|
||
|
};
|
||
|
|
||
|
struct SetMulticyclePath {
|
||
|
bool is_setup = false; //Does mcp_value apply for setup?
|
||
|
bool is_hold = false; //Does mcp_value apply for hold?
|
||
|
// Note: is_setup/is_hold correspond to whether the option was
|
||
|
// provided, it is up to the application to handle the case
|
||
|
// where both are left unspecified (which SDC treats as
|
||
|
// applying mcp_value for the setup mcp, and 0 for the hold
|
||
|
// mcp)
|
||
|
int mcp_value = UNINITIALIZED_INT; //The number of cycles specifed
|
||
|
StringGroup from; //The source list of startpoints or clocks
|
||
|
StringGroup to; //The target list of endpoints or clocks
|
||
|
};
|
||
|
|
||
|
struct SetClockUncertainty {
|
||
|
bool is_setup = false; //Does value apply for setup?
|
||
|
bool is_hold = false; //Does value apply for hold?
|
||
|
// Note: is_setup/is_hold correspond to whether the option was
|
||
|
// provided, it is up to the application to handle the case
|
||
|
// where both are left unspecified (which SDC treats as
|
||
|
// implicitly specifying both)
|
||
|
float value = UNINITIALIZED_FLOAT; //The uncertainty value
|
||
|
|
||
|
StringGroup from; //Launch clock domain(s)
|
||
|
StringGroup to; //Capture clock domain(s)
|
||
|
};
|
||
|
|
||
|
struct SetClockLatency {
|
||
|
ClockLatencyType type = ClockLatencyType::NONE;//Latency type
|
||
|
bool is_early = false; //Does value apply for early transitions?
|
||
|
bool is_late = false; //Does value apply for late transitions?
|
||
|
// Note: is_early/is_late correspond to whether the option was
|
||
|
// provided, it is up to the application to handle the case
|
||
|
// where both are left unspecified (which SDC treats as
|
||
|
// implicitly specifying both)
|
||
|
float value = UNINITIALIZED_FLOAT; //The latency value
|
||
|
|
||
|
StringGroup target_clocks; //The target clocks
|
||
|
};
|
||
|
|
||
|
struct SetDisableTiming {
|
||
|
StringGroup from; //The source pins
|
||
|
StringGroup to; //The sink pins
|
||
|
};
|
||
|
|
||
|
struct SetTimingDerate {
|
||
|
bool is_early = false; //Does value apply for early transitions?
|
||
|
bool is_late = false; //Does value apply for late transitions?
|
||
|
// Note: is_early/is_late correspond to whether the option was
|
||
|
// provided, it is up to the application to handle the case
|
||
|
// where both are left unspecified (which SDC treats as
|
||
|
// implicitly specifying both)
|
||
|
bool derate_nets = false; //Should nets be derated?
|
||
|
bool derate_cells = false; //Should cells be derated?
|
||
|
|
||
|
float value = UNINITIALIZED_FLOAT; //The derate value
|
||
|
|
||
|
StringGroup cell_targets; //The (possibly empty) set of target cells
|
||
|
};
|
||
|
|
||
|
} //namespace
|
||
|
|
||
|
#endif
|