├── .gitignore ├── CMakeLists.txt ├── README.md ├── antlr ├── Antlr4cpp.cmake └── antlr-4.7-complete.jar ├── grammar ├── STIL.g └── stil.config ├── src ├── interpreter │ ├── STILCustomVisitor.cpp │ ├── STILCustomVisitor.h │ ├── STILInterpreter.cpp │ ├── STILInterpreter.h │ ├── STILState.cpp │ ├── STILState.h │ ├── stil │ │ ├── STILProgramVisitor.cpp │ │ ├── STILProgramVisitor.h │ │ └── definitions │ │ │ ├── Identifiable.cpp │ │ │ ├── Identifiable.h │ │ │ ├── PatternBurst.cpp │ │ │ ├── PatternBurst.h │ │ │ ├── STILProgram.h │ │ │ ├── Signal.cpp │ │ │ ├── Signal.h │ │ │ ├── SignalGroup.cpp │ │ │ ├── SignalGroup.h │ │ │ ├── WaveFormTable.cpp │ │ │ └── WaveFormTable.h │ └── teradyne │ │ ├── STILConfig.cpp │ │ ├── STILConfig.h │ │ ├── STILPatternGenerator.cpp │ │ ├── STILPatternGenerator.h │ │ ├── STILTimingGenerator.cpp │ │ ├── STILTimingGenerator.h │ │ └── definitions │ │ ├── DefaultConfig.h │ │ ├── PatternContext.cpp │ │ ├── PatternContext.h │ │ ├── TimeSet.cpp │ │ ├── TimeSet.h │ │ ├── TimeSetHasher.cpp │ │ ├── TimeSetHasher.h │ │ ├── WaveDescription.cpp │ │ ├── WaveDescription.h │ │ ├── WaveForm.cpp │ │ ├── WaveForm.h │ │ ├── WaveSet.cpp │ │ ├── WaveSet.h │ │ ├── WaveTranslation.cpp │ │ └── WaveTranslation.h ├── main.cpp └── parser │ ├── STILFilePreprocessor.cpp │ └── STILFilePreprocessor.h └── test ├── .gitignore └── test_driver.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Build 35 | cmake-build-* 36 | build 37 | bld 38 | CMakeFiles 39 | CMakeCache.txt 40 | antlr4cpp 41 | cmake_install.cmake 42 | Makefile 43 | src/parser/* 44 | src/interpreter/teradyne/DefaultConfig.h 45 | stil_inter 46 | 47 | # IDE 48 | .idea 49 | 50 | # MACOS 51 | .DS_Store 52 | 53 | # Output 54 | *.pat 55 | *.atp 56 | 57 | # Examples 58 | grammar/examples -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7) 2 | project(STIL_Converter) 3 | enable_testing() 4 | 5 | # Add Antlr runtime 6 | set(ANTLR4CPP_JAR_LOCATION ${PROJECT_SOURCE_DIR}/antlr/antlr-4.7-complete.jar) 7 | set(ANTLR4CPP_GENERATED_SRC_DIR ${PROJECT_SOURCE_DIR}/src/parser) 8 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/antlr) 9 | include(Antlr4cpp) 10 | 11 | # Generate parser source code for STIL grammar 12 | set(PARSER_NAMESPACE parser) 13 | antlr4cpp_process_grammar(generate_parser ${PARSER_NAMESPACE} STIL ${PROJECT_SOURCE_DIR}/grammar/STIL.g) 14 | 15 | # Default config 16 | add_custom_command( 17 | OUTPUT 18 | src/interpreter/teradyne/definitions/DefaultConfig.h 19 | COMMAND 20 | xxd -i grammar/stil.config src/interpreter/teradyne/definitions/DefaultConfig.h 21 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 22 | DEPENDS ${PROJECT_SOURCE_DIR}/grammar/stil.config 23 | ) 24 | 25 | add_custom_target( 26 | generate_default_config 27 | DEPENDS src/interpreter/teradyne/definitions/DefaultConfig.h 28 | ) 29 | 30 | # Compiler settings 31 | set(CMAKE_CXX_STANDARD 11) 32 | #set(GCC_COVERAGE_COMPILE_FLAGS "-v") 33 | 34 | if(NOT CMAKE_BUILD_TYPE) 35 | set(CMAKE_BUILD_TYPE ReleaseWithAsserts) 36 | endif(NOT CMAKE_BUILD_TYPE) 37 | 38 | set(CMAKE_CXX_FLAGS_RELEASEWITHASSERTS "-Wall -O3") 39 | 40 | # Source files 41 | set(SOURCE_FILES 42 | src/main.cpp 43 | src/parser/STILBaseVisitor.h src/parser/STILFilePreprocessor.h src/parser/STILLexer.h src/parser/STILParser.h src/parser/STILVisitor.h src/parser/STILParser.cpp src/parser/STILVisitor.cpp src/parser/STILBaseVisitor.cpp src/parser/STILFilePreprocessor.cpp src/parser/STILLexer.cpp 44 | src/interpreter/stil/STILProgramVisitor.cpp src/interpreter/stil/STILProgramVisitor.h src/interpreter/stil/definitions/STILProgram.h src/interpreter/stil/definitions/Signal.cpp src/interpreter/stil/definitions/Signal.h src/interpreter/STILInterpreter.cpp src/interpreter/STILInterpreter.h src/interpreter/stil/definitions/PatternBurst.cpp src/interpreter/stil/definitions/PatternBurst.h src/interpreter/teradyne/definitions/PatternContext.cpp src/interpreter/teradyne/definitions/PatternContext.h src/interpreter/stil/definitions/SignalGroup.cpp src/interpreter/stil/definitions/SignalGroup.h src/interpreter/stil/definitions/Identifiable.h src/interpreter/stil/definitions/Identifiable.cpp src/interpreter/stil/definitions/WaveFormTable.cpp src/interpreter/stil/definitions/WaveFormTable.h src/interpreter/STILCustomVisitor.cpp src/interpreter/STILCustomVisitor.h src/interpreter/teradyne/definitions/WaveForm.cpp src/interpreter/teradyne/definitions/WaveForm.h src/interpreter/STILState.cpp src/interpreter/STILState.h src/interpreter/teradyne/STILConfig.cpp src/interpreter/teradyne/STILConfig.h src/parser/STILFilePreprocessor.cpp src/parser/STILFilePreprocessor.h src/interpreter/teradyne/STILTimingGenerator.cpp src/interpreter/teradyne/STILTimingGenerator.h src/interpreter/teradyne/definitions/TimeSet.cpp src/interpreter/teradyne/definitions/TimeSet.h src/interpreter/teradyne/STILPatternGenerator.cpp src/interpreter/teradyne/STILPatternGenerator.h src/interpreter/teradyne/definitions/WaveDescription.cpp src/interpreter/teradyne/definitions/WaveDescription.h src/interpreter/teradyne/definitions/WaveSet.cpp src/interpreter/teradyne/definitions/WaveSet.h src/interpreter/teradyne/definitions/WaveTranslation.cpp src/interpreter/teradyne/definitions/WaveTranslation.h src/interpreter/teradyne/definitions/TimeSetHasher.cpp src/interpreter/teradyne/definitions/TimeSetHasher.h) 45 | include_directories( 46 | ${ANTLR4CPP_INCLUDE_DIRS} 47 | ${antlr4cpp_include_dirs_${PARSER_NAMESPACE}}) 48 | link_directories( 49 | ${ANTLR4CPP_LIBS}) 50 | 51 | # Target 52 | add_executable(stil_converter ${SOURCE_FILES}) 53 | add_dependencies(stil_converter generate_parser generate_default_config antlr4cpp) 54 | target_link_libraries(stil_converter ${antlr4_static}) 55 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 56 | 57 | # Install stil_converter 58 | install(TARGETS stil_converter 59 | RUNTIME DESTINATION bin) 60 | message(STATUS "To install stil_converter under /usr/local/bin, type: make install") 61 | 62 | # Tests 63 | # Make sure you install the executable before (make install) 64 | # Make sure all the tests were when you run cmake. 65 | # To run the tests, type "make test" 66 | file(GLOB input_test_files "${PROJECT_SOURCE_DIR}/test/input_files/*.stil") 67 | foreach(file ${input_test_files}) 68 | get_filename_component(name ${file} NAME) 69 | add_test( 70 | NAME 71 | ${name} 72 | COMMAND 73 | python3 test_driver.py $ ${name} 74 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test 75 | ) 76 | endforeach() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # STIL_Interpreter 2 | Tool for parsing an integrated circuit test file from STIL to the particular file format of a Teradyne tester. 3 | 4 | It includes the parsing, interpretation of the STIL input and the output files generation of the Teradyne particular format. 5 | 6 | ----------------------------------------------- 7 | 8 | To build: 9 | 10 | mkdir build && cd build 11 | 12 | cmake ../ 13 | 14 | make 15 | 16 | ----------------------------------------------- 17 | 18 | To install: 19 | 20 | cd build 21 | 22 | make install 23 | 24 | If you don't want to install it in the default path: 25 | 26 | mkdir build && cd build 27 | 28 | cmake -DCMAKE_INSTALL_PREFIX=YOUR_PATH 29 | 30 | make install 31 | 32 | ----------------------------------------------- 33 | 34 | To run tests: 35 | 36 | cd build 37 | ctest [-R stil_file_name_in_test/input_files] 38 | 39 | ----------------------------------------------- 40 | 41 | To run: 42 | 43 | stil_converter input_file.stil [-v] [-c config_file.config] [-p pattern_exec_name] 44 | -------------------------------------------------------------------------------- /antlr/Antlr4cpp.cmake: -------------------------------------------------------------------------------- 1 | # -*- mode:cmake -*- 2 | # 3 | # This Cmake file is for those using a superbuild Cmake Pattern, it 4 | # will download the tools and build locally 5 | # 6 | # use the antlr4cpp_process_grammar to support multiple grammars in the 7 | # same project 8 | # 9 | # - Getting quicky started with Antlr4cpp 10 | # 11 | # Here is how you can use this external project to create the antlr4cpp 12 | # demo to start your project off. 13 | # 14 | # create your project source folder somewhere. e.g. ~/srcfolder/ 15 | # + make a subfolder cmake 16 | # + Copy this file to srcfolder/cmake 17 | # + cut below and use it to create srcfolder/CMakeLists.txt, 18 | # + from https://github.com/DanMcLaughlin/antlr4/tree/master/runtime/Cpp/demo Copy main.cpp, TLexer.g4 and TParser.g4 to ./srcfolder/ 19 | # 20 | # next make a build folder e.g. ~/buildfolder/ 21 | # from the buildfolder, run cmake ~/srcfolder; make 22 | # 23 | ############################################################### 24 | # # minimum required CMAKE version 25 | # CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12.2 FATAL_ERROR) 26 | # 27 | # LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ) 28 | # 29 | # # compiler must be 11 or 14 30 | # SET (CMAKE_CXX_STANDARD 11) 31 | # 32 | # # set variable pointing to the antlr tool that supports C++ 33 | # set(ANTLR4CPP_JAR_LOCATION /home/user/antlr4-4.5.4-SNAPSHOT.jar) 34 | # # add external build for antlrcpp 35 | # include( ExternalAntlr4Cpp ) 36 | # # add antrl4cpp artifacts to project environment 37 | # include_directories( ${ANTLR4CPP_INCLUDE_DIRS} ) 38 | # link_directories( ${ANTLR4CPP_LIBS} ) 39 | # message(STATUS "Found antlr4cpp libs: ${ANTLR4CPP_LIBS} and includes: ${ANTLR4CPP_INCLUDE_DIRS} ") 40 | 41 | 42 | CMAKE_MINIMUM_REQUIRED(VERSION 3.7) 43 | INCLUDE(ExternalProject) 44 | FIND_PACKAGE(Git REQUIRED) 45 | 46 | # only JRE required 47 | FIND_PACKAGE(Java COMPONENTS Runtime REQUIRED) 48 | 49 | ############ Download and Generate runtime ################# 50 | set(ANTLR4CPP_EXTERNAL_ROOT ${CMAKE_BINARY_DIR}/antlr4cpp) 51 | set(ANTLR4CPP_EXTERNAL_REPO "https://github.com/antlr/antlr4.git") 52 | set(ANTLR4CPP_EXTERNAL_TAG "4.7") 53 | 54 | if(NOT EXISTS "${ANTLR4CPP_JAR_LOCATION}") 55 | message(FATAL_ERROR "Unable to find antlr tool. ANTLR4CPP_JAR_LOCATION:${ANTLR4CPP_JAR_LOCATION}") 56 | endif() 57 | 58 | # download runtime environment 59 | ExternalProject_ADD( 60 | #--External-project-name------ 61 | antlr4cpp 62 | #--Depend-on-antrl-tool----------- 63 | # DEPENDS antlrtool 64 | #--Core-directories----------- 65 | PREFIX ${ANTLR4CPP_EXTERNAL_ROOT} 66 | #--Download step-------------- 67 | GIT_REPOSITORY ${ANTLR4CPP_EXTERNAL_REPO} 68 | # GIT_TAG ${ANTLR4CPP_EXTERNAL_TAG} 69 | TIMEOUT 10 70 | LOG_DOWNLOAD ON 71 | #--Update step---------- 72 | UPDATE_COMMAND ${GIT_EXECUTABLE} pull 73 | #--Patch step---------- 74 | # PATCH_COMMAND sh -c "cp /scripts/CMakeLists.txt " 75 | #--Configure step------------- 76 | CONFIGURE_COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release -DANTLR4CPP_JAR_LOCATION=${ANTLR4CPP_JAR_LOCATION} -DBUILD_SHARED_LIBS=ON -BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_SOURCE_DIR:PATH=/runtime/Cpp /runtime/Cpp 77 | LOG_CONFIGURE ON 78 | #--Build step----------------- 79 | # BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} 80 | LOG_BUILD ON 81 | #--Install step--------------- 82 | # INSTALL_COMMAND "" 83 | # INSTALL_DIR ${CMAKE_BINARY_DIR}/ 84 | #--Install step--------------- 85 | # INSTALL_COMMAND "" 86 | ) 87 | 88 | ExternalProject_Get_Property(antlr4cpp INSTALL_DIR) 89 | 90 | list(APPEND ANTLR4CPP_INCLUDE_DIRS ${INSTALL_DIR}/include/antlr4-runtime) 91 | foreach(src_path misc atn dfa tree support) 92 | list(APPEND ANTLR4CPP_INCLUDE_DIRS ${INSTALL_DIR}/include/antlr4-runtime/${src_path}) 93 | endforeach(src_path) 94 | 95 | set(ANTLR4CPP_LIBS "${INSTALL_DIR}/lib") 96 | set(antlr4_static ${ANTLR4CPP_LIBS}/libantlr4-runtime.a) 97 | 98 | macro(antlr4cpp_process_grammar 99 | antlr4cpp_target_name 100 | antlr4cpp_project_namespace 101 | antlr4cpp_grammar_name 102 | antlr4cpp_grammar) 103 | 104 | if(EXISTS "${ANTLR4CPP_JAR_LOCATION}") 105 | message(STATUS "Found antlr tool: ${ANTLR4CPP_JAR_LOCATION}") 106 | else() 107 | message(FATAL_ERROR "Unable to find antlr tool. ANTLR4CPP_JAR_LOCATION:${ANTLR4CPP_JAR_LOCATION}") 108 | endif() 109 | 110 | 111 | add_custom_command( 112 | OUTPUT 113 | ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_grammar_name}Parser.h 114 | COMMAND 115 | ${CMAKE_COMMAND} -E make_directory ${ANTLR4CPP_GENERATED_SRC_DIR} 116 | COMMAND 117 | "${Java_JAVA_EXECUTABLE}" -jar "${ANTLR4CPP_JAR_LOCATION}" -Werror -Dlanguage=Cpp -no-listener -visitor -o "${ANTLR4CPP_GENERATED_SRC_DIR}" -package ${antlr4cpp_project_namespace} "${antlr4cpp_grammar}" 118 | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" 119 | DEPENDS ${antlr4cpp_grammar} 120 | ) 121 | 122 | add_custom_target( 123 | "${antlr4cpp_target_name}" 124 | DEPENDS ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_grammar_name}Parser.h 125 | ) 126 | 127 | # Find all the input files 128 | FILE(GLOB generated_files ${ANTLR4CPP_GENERATED_SRC_DIR}/*.cpp) 129 | 130 | # export generated cpp files into list 131 | foreach(generated_file ${generated_files}) 132 | list(APPEND antlr4cpp_src_files_${antlr4cpp_project_namespace} ${generated_file}) 133 | set_source_files_properties( 134 | ${generated_file} 135 | PROPERTIES 136 | GENERATED TRUE 137 | COMPILE_FLAGS -Wno-overloaded-virtual 138 | ) 139 | endforeach(generated_file) 140 | message(STATUS "Antlr4Cpp ${antlr4cpp_project_namespace} Generated: ${generated_files}") 141 | 142 | # export generated include directory 143 | set(antlr4cpp_include_dirs_${antlr4cpp_project_namespace} ${ANTLR4CPP_GENERATED_SRC_DIR}) 144 | 145 | endmacro() -------------------------------------------------------------------------------- /antlr/antlr-4.7-complete.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gonsp/STIL_Interpreter/39bb075f8a352bbdc5669edc33497eb75de457ed/antlr/antlr-4.7-complete.jar -------------------------------------------------------------------------------- /grammar/STIL.g: -------------------------------------------------------------------------------- 1 | grammar STIL; 2 | 3 | /////////////////////////////////////////////////////////////////////// 4 | // RULES 5 | /////////////////////////////////////////////////////////////////////// 6 | 7 | program : format? header? signals signal_groups timing scan_structures_l 8 | pattern_burst_l pattern_exec_l procedures_l macros_l pattern_l EOF; 9 | 10 | /////////////////////////////////////////////////////////////////////// 11 | 12 | format : 'STIL' float_t (L_BRACKET design R_BRACKET)?; 13 | design : 'Design' int_t; 14 | 15 | /////////////////////////////////////////////////////////////////////// 16 | 17 | header : 'Header' L_BRACKET title? date? source? history? R_BRACKET; 18 | title : 'Title' STRING; 19 | date : 'Date' STRING; 20 | source : 'Source' STRING; 21 | history : 'History' L_BRACKET R_BRACKET; 22 | 23 | /////////////////////////////////////////////////////////////////////// 24 | 25 | signals : 'Signals' L_BRACKET signal* R_BRACKET; 26 | signal : id signal_dir signal_attributes?; 27 | signal_dir : 'In' | 'Out' | 'InOut' | 'Pseudo'; 28 | signal_attributes : L_BRACKET signal_scan? wfc_map? R_BRACKET; 29 | signal_scan : 'ScanIn' | 'ScanOut'; 30 | wfc_map : 'WFCMap' L_BRACKET map_rule* R_BRACKET; 31 | map_rule : wfc_seq '->' wfc_seq; 32 | 33 | /////////////////////////////////////////////////////////////////////// 34 | 35 | signal_groups : 'SignalGroups' L_BRACKET signal_group* R_BRACKET; 36 | signal_group : id EQ QUOTE signal_list QUOTE signal_attributes?; 37 | signal_list : id (SUM id)*; 38 | 39 | /////////////////////////////////////////////////////////////////////// 40 | 41 | timing : 'Timing' L_BRACKET waveform_table* R_BRACKET; 42 | waveform_table : 'WaveformTable' id L_BRACKET period waveforms R_BRACKET; 43 | period : 'Period' time_expr; 44 | waveforms : 'Waveforms' L_BRACKET waveform* R_BRACKET; 45 | waveform : id L_BRACKET wfc_seq L_BRACKET event+ R_BRACKET R_BRACKET; 46 | event : time_expr event_code; 47 | 48 | /////////////////////////////////////////////////////////////////////// 49 | 50 | scan_structures_l : scan_structures*; 51 | scan_structures : 'ScanStructures' id? L_BRACKET scan_chain* R_BRACKET; 52 | scan_chain : 'ScanChain' id L_BRACKET scan_length scan_in scan_out 53 | scan_inversion scan_cells scan_clock R_BRACKET; 54 | scan_length : 'ScanLength' int_t; 55 | scan_in : 'ScanIn' id; 56 | scan_out : 'ScanOut' id; 57 | scan_inversion : 'ScanInversion' int_t; 58 | scan_cells : 'ScanCells' (id EXCLAMATION?)+; 59 | scan_clock : 'ScanMasterClock' id?; 60 | 61 | /////////////////////////////////////////////////////////////////////// 62 | 63 | pattern_burst_l : pattern_burst+; 64 | pattern_burst : 'PatternBurst' id L_BRACKET context pattern_list R_BRACKET; 65 | context : macro_context? proced_context?; 66 | macro_context : 'MacroDefs' id; 67 | proced_context : 'Procedures' id; 68 | pattern_list : 'PatList' L_BRACKET (pattern_call)* R_BRACKET; 69 | pattern_call : id (L_BRACKET context R_BRACKET)?; 70 | 71 | /////////////////////////////////////////////////////////////////////// 72 | 73 | pattern_exec_l : pattern_exec+; 74 | pattern_exec : 'PatternExec' id? L_BRACKET pattern_burst_call* R_BRACKET; 75 | pattern_burst_call : 'PatternBurst' id; 76 | 77 | /////////////////////////////////////////////////////////////////////// 78 | 79 | procedures_l : procedures*; 80 | procedures : 'Procedures' id? L_BRACKET procedure* R_BRACKET; 81 | procedure : id L_BRACKET inst_list R_BRACKET; 82 | 83 | /////////////////////////////////////////////////////////////////////// 84 | 85 | macros_l : macros*; 86 | macros : 'MacroDefs' id? L_BRACKET macro* R_BRACKET; 87 | macro : id L_BRACKET inst_list R_BRACKET; 88 | 89 | /////////////////////////////////////////////////////////////////////// 90 | 91 | pattern_l : pattern*; 92 | pattern : 'Pattern' id L_BRACKET inst_list R_BRACKET; 93 | 94 | 95 | /////////////////////////////////////////////////////////////////////// 96 | 97 | inst_list : inst*; 98 | inst : label? (loop | shift | w_inst | c_inst | f_inst | v_inst 99 | | call_inst | macro_inst | stop_inst | iddq_inst); 100 | label : id ':'; 101 | loop : 'Loop' int_t L_BRACKET inst_list R_BRACKET; 102 | shift : 'Shift' L_BRACKET inst_list R_BRACKET; 103 | w_inst : 'W' id; 104 | c_inst : 'C' L_BRACKET assigs R_BRACKET; 105 | f_inst : 'F' L_BRACKET assigs R_BRACKET; 106 | v_inst : 'V' L_BRACKET assigs R_BRACKET; 107 | call_inst : 'Call' id (L_BRACKET assigs R_BRACKET)?; 108 | macro_inst : 'Macro' id (L_BRACKET assigs R_BRACKET)?; 109 | stop_inst : 'Stop'; 110 | iddq_inst : 'IddqTestPoint'; 111 | 112 | assigs : assig*; 113 | assig : id EQ assig_expr; 114 | assig_expr : JOIN? (repeat | wfc_seq)*; 115 | repeat : REPEAT int_t wfc_seq; 116 | 117 | /////////////////////////////////////////////////////////////////////// 118 | // This is ugly but necessary, since the lexer doesn't know how to differentiate 119 | // different tokens with some intersection. For example, the lexical definition 120 | // of ID intersects with the definition of WFC, or events... Depending on the 121 | // context there isn't ambiguity, but in the lexical analysis there isn't any context. 122 | // To simplify and avoid some cases, we're going to consider that ALL ids are strings 123 | 124 | id : STRING; 125 | num : int_t | float_t; 126 | int_t : INT; 127 | float_t : FLOAT; 128 | wfc_seq : (CHARS | INT | WFC_SEQ); 129 | event_code : CHARS; 130 | time_expr : TIME_EXPR; 131 | 132 | /////////////////////////////////////////////////////////////////////// 133 | // TOKENS 134 | /////////////////////////////////////////////////////////////////////// 135 | 136 | SUM : '+'; 137 | EQ : '='; 138 | SEMICOLON : ';'; 139 | L_BRACKET : '{'; 140 | R_BRACKET : '}'; 141 | L_PAR : '('; 142 | R_PAR : ')'; 143 | EXCLAMATION : '!'; 144 | QUOTE : '\''; 145 | JOIN : '\\j'; 146 | REPEAT : '\\r'; 147 | 148 | FLOAT : INT'.'INT; 149 | INT : DIG+; 150 | CHARS : LETTER+; 151 | STRING : '"' ~('\r' | '\n' | '"')* '"'; 152 | WFC_SEQ : (DIG | LETTER | '#' | '%')+; 153 | 154 | TIME_EXPR : QUOTE (INT | FLOAT) UNIT QUOTE; 155 | fragment UNIT : 'ns' | 'ms' | 's'; 156 | 157 | fragment DIG : [0-9]; 158 | fragment NUM : INT | FLOAT; 159 | fragment LETTER : [a-zA-Z]; 160 | 161 | // Ignored tokens (Order is important) 162 | WHITE_SPACES : [ \t\r\n;]+ -> skip; 163 | COMMENT : '//' ~('\r' | '\n')* -> skip; 164 | ANNOTATION : 'Ann ' L_BRACKET '*' ([ \p{S}\p{P}\p{M}\p{L}\p{N}])* '*' R_BRACKET -> skip; -------------------------------------------------------------------------------- /grammar/stil.config: -------------------------------------------------------------------------------- 1 | // Default config file for STIL conversion 2 | // Comments are allowed (and ignored) outside the blocks 3 | // Block order and format very sensitive! 4 | // Whitespaces ignored 5 | 6 | 7 | // Here you must specify for each event sequence on the 8 | // waveforms to what "tester event" it should be translated 9 | // 10 | // If a rule is not defined by an used waveform (event sequence) 11 | // an error will be displayed and the conversion will fail 12 | 13 | event_map { 14 | D -> 0, (NR, D0 = 0, D1 = E0, D2 = -, D3 = 1), (RL, D0 = 0, D1 = E0, D2 = ?, D3 = 1), (RH, D0 = 0, D1 = E0, D2 = 1, D3 = 1), (SBL, D0 = E0, D1 = ?, D2 = ?, D3 = 1) 15 | U -> 1, (NR, D0 = 0, D1 = E0, D2 = -, D3 = 1), (RL, D0 = 0, D1 = E0, D2 = 1, D3 = 1), (RH, D0 = 0, D1 = E0, D2 = ?, D3 = 1), (SBH, D0 = E0, D1 = ?, D2 = ?, D3 = 1) 16 | Z -> X, (Off, R0 = ?), (Edge, R0 = ?) 17 | H -> H, (Edge, R0 = E0) 18 | L -> L, (Edge, R0 = E0) 19 | T -> M, (Edge, R0 = E0) 20 | X -> X, (Off, R0 = ?), (Edge, R0 = ?) 21 | 22 | XH -> H, (Edge, R0 = E1) 23 | XL -> L, (Edge, R0 = E1) 24 | XT -> M, (Edge, R0 = E1) 25 | XX -> X, (Off, R0 = ?), (Edge, R0 = ?) 26 | 27 | ZH -> H, (Edge, R0 = E1) 28 | ZL -> L, (Edge, R0 = E1) 29 | ZT -> M, (Edge, R0 = E1) 30 | ZX -> X, (Off, R0 = ?), (Edge, R0 = ?) 31 | 32 | DUD -> 1, (SBL, D0 = E0, D1 = E1, D2 = E2, D3 = 1), (SBC, D0 = E0, D1 = E1, D2 = E2, D3 = 1) 33 | UDU -> 0, (SBH, D0 = E0, D1 = E1, D2 = E2, D3 = 1), (SBC, D0 = E0, D1 = E1, D2 = E2, D3 = 1) 34 | } 35 | 36 | // Here you must specify the signal's name translation from 37 | // STIL definitions to the output signal names. 38 | // By default, all signals are quoted, and the output 39 | // will take them off. 40 | // 41 | // If a rule is not defined for a signal name, the signal 42 | // won't change its name. 43 | // If it's defined but the target name is void, the signal 44 | // will be removed from the output. 45 | // The special rule "[] -> _" will change the "[X]" and put 46 | // a "_X" since this format is used in the examples I've seen 47 | 48 | signal_name_map { 49 | 50 | "unused_signal" -> "Unused_Signal" 51 | 52 | "GCFG[3]" -> 53 | "GCFG[4]" -> 54 | "GCFG[5]" -> 55 | "GCFG[6]" -> 56 | 57 | [] -> _ 58 | } 59 | 60 | // Here you specify what tester event must be used for the scan 61 | // chains padding. This value will be inserted at the beginning 62 | // of the scan in signals which length is less than the max. 63 | // The same goes for the scan out signals, but inserting at the 64 | // end. 65 | // They are not wfc to be translated, they are definitive 66 | // events. (Order sensitive) 67 | 68 | scan_padding { 69 | scan_in -> 0 70 | scan_out -> X 71 | } 72 | 73 | // Here you specify for what the IddqTestPoint instruction 74 | // should be replaced in the pattern file. 75 | // This multiline string must not have the '}' character 76 | 77 | iddq_action { 78 | call_iddq; 79 | } 80 | -------------------------------------------------------------------------------- /src/interpreter/STILCustomVisitor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #include "STILCustomVisitor.h" 6 | #include "teradyne/definitions/PatternContext.h" 7 | #include "stil/definitions/STILProgram.h" 8 | #include "STILState.h" 9 | 10 | antlrcpp::Any STILCustomVisitor::visitTerminal(tree::TerminalNode* node) { 11 | return node->getText(); 12 | } 13 | 14 | antlrcpp::Any STILCustomVisitor::visitFloat_t(STILParser::Float_tContext* ctx) { 15 | string num = visit(ctx->FLOAT()); 16 | float value = stof(num); 17 | return value; 18 | } 19 | 20 | antlrcpp::Any STILCustomVisitor::visitInt_t(STILParser::Int_tContext* ctx) { 21 | string num = visit(ctx->INT()); 22 | int value = stoi(num); 23 | return value; 24 | } 25 | 26 | antlrcpp::Any STILCustomVisitor::visitNum(STILParser::NumContext* ctx) { 27 | if(ctx->int_t() != NULL) { 28 | int num = visit(ctx->int_t()); 29 | return (float) num; 30 | } else { 31 | float num = visit(ctx->float_t()); 32 | return num; 33 | } 34 | } 35 | 36 | antlrcpp::Any STILCustomVisitor::visitPeriod(STILParser::PeriodContext* ctx) { 37 | return visit(ctx->time_expr()); 38 | } 39 | 40 | antlrcpp::Any STILCustomVisitor::visitTime_expr(STILParser::Time_exprContext* ctx) { 41 | string s = visit(ctx->TIME_EXPR()); 42 | s.erase(0, 1); // Deleting quotes 43 | s.pop_back(); 44 | assert(s.back() == 's'); 45 | int scale = 1000000; // Units are seconds 46 | char prefix = s[s.size()-2]; 47 | if(prefix < '0' || prefix > '9') { // Units have a prefix 48 | assert(prefix == 'n' || prefix == 'm'); 49 | if(prefix == 'n') { // Nanoseconds 50 | scale = 1; 51 | } else if(prefix == 'm') { // Miliseconds 52 | scale = 1000; 53 | } 54 | s.pop_back(); 55 | } 56 | float time = stof(s); 57 | return time * scale; // Time in nanoseconds 58 | } 59 | 60 | antlrcpp::Any STILCustomVisitor::visitWfc_seq(STILParser::Wfc_seqContext* ctx) { 61 | return ctx->getText(); 62 | } 63 | 64 | antlrcpp::Any STILCustomVisitor::visitContext(STILParser::ContextContext* ctx) { 65 | string proceds_id = GLOBAL_DEF; 66 | string macros_id = GLOBAL_DEF; 67 | if(ctx->proced_context() != NULL) { 68 | string aux = visit(ctx->proced_context()->id()); 69 | proceds_id = aux; 70 | } 71 | if(ctx->macro_context() != NULL) { 72 | string aux = visit(ctx->macro_context()->id()); 73 | macros_id = aux; 74 | } 75 | return PatternContext(proceds_id, macros_id); 76 | } 77 | 78 | antlrcpp::Any STILCustomVisitor::visitAssigs(STILParser::AssigsContext* ctx) { 79 | list assigs; 80 | for(int i = 0; i < ctx->assig().size(); ++i) { 81 | string signal_group_id = visit(ctx->assig(i)->id()); 82 | string value = visit(ctx->assig(i)->assig_expr()); 83 | assigs.push_back(STILState::Assig(signal_group_id, value)); 84 | } 85 | return assigs; 86 | } 87 | 88 | antlrcpp::Any STILCustomVisitor::visitAssig_expr(STILParser::Assig_exprContext* ctx) { 89 | string value; 90 | for(int i = 0; i < ctx->children.size(); ++i) { 91 | if(i != 0 || ctx->JOIN() == NULL) { // Ignoring the \j token 92 | string seq = visit(ctx->children[i]); 93 | value += seq; 94 | } 95 | } 96 | return value; 97 | } 98 | 99 | antlrcpp::Any STILCustomVisitor::visitRepeat(STILParser::RepeatContext* ctx) { 100 | int times = visit(ctx->int_t()); 101 | string wfc = visit(ctx->wfc_seq()); 102 | string result; 103 | while(times-- > 0) { 104 | result += wfc; 105 | } 106 | return result; 107 | } 108 | -------------------------------------------------------------------------------- /src/interpreter/STILCustomVisitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_STILCUSTOMVISITOR_H 6 | #define STIL_INTERPRETER_STILCUSTOMVISITOR_H 7 | 8 | #include 9 | 10 | using namespace std; 11 | using namespace antlr4; 12 | using namespace parser; 13 | 14 | class STILCustomVisitor : public STILBaseVisitor { 15 | 16 | private: 17 | 18 | virtual antlrcpp::Any visitTerminal(tree::TerminalNode* node) override; 19 | 20 | virtual antlrcpp::Any visitFloat_t(STILParser::Float_tContext* ctx) override; 21 | 22 | virtual antlrcpp::Any visitInt_t(STILParser::Int_tContext* ctx) override; 23 | 24 | virtual antlrcpp::Any visitNum(STILParser::NumContext* ctx) override; 25 | 26 | virtual antlrcpp::Any visitPeriod(STILParser::PeriodContext* ctx) override; 27 | 28 | virtual antlrcpp::Any visitTime_expr(STILParser::Time_exprContext* ctx) override; 29 | 30 | virtual antlrcpp::Any visitWfc_seq(STILParser::Wfc_seqContext* ctx) override; 31 | 32 | virtual antlrcpp::Any visitContext(STILParser::ContextContext* ctx) override; 33 | 34 | virtual antlrcpp::Any visitAssigs(STILParser::AssigsContext* ctx) override; 35 | 36 | virtual antlrcpp::Any visitAssig_expr(STILParser::Assig_exprContext* ctx) override; 37 | 38 | virtual antlrcpp::Any visitRepeat(STILParser::RepeatContext* ctx) override; 39 | 40 | }; 41 | 42 | 43 | #endif //STIL_INTERPRETER_STILCUSTOMVISITOR_H 44 | -------------------------------------------------------------------------------- /src/interpreter/STILInterpreter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/08/2017. 3 | // 4 | 5 | #include 6 | #include 7 | #include "STILInterpreter.h" 8 | #include "stil/STILProgramVisitor.h" 9 | 10 | STILInterpreter::STILInterpreter(string stil_file, string pattern_file, string timing_file, STILConfig& config) : program(config) { 11 | this->stil_file = stil_file; 12 | this->pattern_file = pattern_file; 13 | this->timing_file = timing_file; 14 | 15 | STILFilePreprocessor::preprocess(stil_file); 16 | 17 | stil_input.open(stil_file + ".tmp"); 18 | } 19 | 20 | void STILInterpreter::run() { 21 | cout << "Running default pattern_exec block" << endl; 22 | cout << "(You can specify the pattern_exec block with an additional argument)" << endl; 23 | run(GLOBAL_DEF); 24 | } 25 | 26 | void STILInterpreter::run(string pattern_exec) { 27 | 28 | cout << "--------------------------------------" << endl; 29 | 30 | cout << "Starting file parsing" << endl; 31 | ANTLRInputStream input(stil_input); 32 | STILLexer lexer(&input); 33 | CommonTokenStream tokens(&lexer); 34 | tokens.fill(); 35 | 36 | STILParser parser(&tokens); 37 | ParseTree* ast = parser.program(); 38 | cout << "File parsed successfully" << endl; 39 | 40 | cout << "--------------------------------------" << endl; 41 | 42 | cout << "Generating internal representation of the program" << endl; 43 | STILProgramVisitor programVisitor(program); 44 | programVisitor.visit(ast); 45 | cout << "Generation successful" << endl; 46 | 47 | cout << "--------------------------------------" << endl; 48 | 49 | cout << "Starting interpretation" << endl; 50 | actual_line = 0; 51 | signalState = STILState(&program, &actual_line); 52 | patternGenerator = STILPatternGenerator(pattern_file, &program, &actual_line); 53 | timingGenerator = STILTimingGenerator(timing_file); 54 | 55 | visit(program.patternExecs[pattern_exec]); 56 | 57 | patternGenerator.finish(); 58 | timingGenerator.finish(program.get_formatted_signal_names()); 59 | 60 | string aux = stil_file + ".tmp"; 61 | remove(aux.c_str()); // Removing the temporal preprocessed file 62 | cout << "Done" << endl; 63 | } 64 | 65 | antlrcpp::Any STILInterpreter::visitPattern_exec(STILParser::Pattern_execContext* ctx) { 66 | patternGenerator.print_headers(); 67 | contextStack.push(PatternContext()); // Base context 68 | for(int i = 0; i < ctx->pattern_burst_call().size(); ++i) { 69 | visit(ctx->pattern_burst_call(i)); 70 | assert(contextStack.size() == 1); // Needs to remain just the base context 71 | } 72 | return NULL; 73 | } 74 | 75 | antlrcpp::Any STILInterpreter::visitPattern_burst_call(STILParser::Pattern_burst_callContext* ctx) { 76 | string id = visit(ctx->id()); 77 | cout << "Executing pattern_burst: " << id << endl; 78 | cout << "Merging new context" << endl; 79 | contextStack.push(program.patternBursts[id].context); 80 | visit(program.patternBursts[id].ast); 81 | cout << "Executed pattern_burst: " << id << endl; 82 | contextStack.pop(); 83 | return NULL; 84 | } 85 | 86 | antlrcpp::Any STILInterpreter::visitPattern_list(STILParser::Pattern_listContext* ctx) { 87 | for(int i = 0; i < ctx->pattern_call().size(); ++i) { 88 | string id = visit(ctx->pattern_call(i)->id()); 89 | bool explicit_context = ctx->pattern_call(i)->context() != NULL; 90 | if(explicit_context) { 91 | PatternContext context = visit(ctx->pattern_call(i)->context()); 92 | contextStack.push(context); 93 | } 94 | if(program.patternBursts.find(id) != program.patternBursts.end()) { 95 | cout << "Calling pattern_burst: " << id << endl; 96 | visit(program.patternBursts[id].ast); 97 | } else { 98 | cout << "Calling pattern: " << id << endl; 99 | visit(program.patterns[id]); 100 | } 101 | if(explicit_context) { 102 | contextStack.pop(); 103 | } 104 | } 105 | return NULL; 106 | } 107 | 108 | antlrcpp::Any STILInterpreter::visitInst(STILParser::InstContext* ctx) { 109 | actual_line = (int) ctx->getStart()->getLine(); 110 | visitChildren(ctx); 111 | return NULL; 112 | } 113 | 114 | antlrcpp::Any STILInterpreter::visitLoop(STILParser::LoopContext* ctx) { 115 | cout << actual_line << ": " << "Executing loop" << endl; 116 | int times = visit(ctx->int_t()); 117 | if(ctx->inst_list()->children.size() == 1) { 118 | string s = "repeat " + to_string(times); 119 | patternGenerator.print_tester_inst(s); 120 | visit(ctx->inst_list()); 121 | } else { 122 | while(times > 0) { 123 | visit(ctx->inst_list()); 124 | --times; 125 | } 126 | } 127 | return NULL; 128 | } 129 | 130 | antlrcpp::Any STILInterpreter::visitShift(STILParser::ShiftContext* ctx) { 131 | cout << actual_line << ": " << "Executing shift" << endl; 132 | int times = signalState.max_param_size; 133 | signalState.set_padding_to_params(times); 134 | while(times > 0) { 135 | visit(ctx->inst_list()); 136 | --times; 137 | } 138 | return NULL; 139 | } 140 | 141 | antlrcpp::Any STILInterpreter::visitW_inst(STILParser::W_instContext* ctx) { 142 | string id = visit(ctx->id()); 143 | if(id != signalState.active_table) { 144 | cout << "Changing active waveform_table to: " << id << endl; 145 | } 146 | signalState.active_table = id; 147 | return NULL; 148 | } 149 | 150 | antlrcpp::Any STILInterpreter::visitV_inst(STILParser::V_instContext* ctx) { 151 | list assigs = visit(ctx->assigs()); 152 | signalState.execute_assigs(assigs); 153 | patternGenerator.clock_cycle(signalState, timingGenerator); 154 | return NULL; 155 | } 156 | 157 | antlrcpp::Any STILInterpreter::visitC_inst(STILParser::C_instContext* ctx) { 158 | list assigs = visit(ctx->assigs()); 159 | signalState.execute_assigs(assigs); 160 | return NULL; 161 | } 162 | 163 | antlrcpp::Any STILInterpreter::visitF_inst(STILParser::F_instContext* ctx) { 164 | // We suposse that the STIL program is correct and we just need to 165 | // treat this instruction as a Condition 166 | list assigs = visit(ctx->assigs()); 167 | signalState.execute_assigs(assigs); 168 | return NULL; 169 | } 170 | 171 | antlrcpp::Any STILInterpreter::visitCall_inst(STILParser::Call_instContext* ctx) { 172 | string id = visit(ctx->id()); 173 | cout << actual_line << ": " << "Calling procedure: " << id << " from block " << contextStack.top().proceds_id << endl; 174 | 175 | cout << "Saving entire previous state" << endl; 176 | STILState prev_signalState = signalState; 177 | signalState.clear_params(); // We clear the possible params from the previous call in the new state (they will be restored on the call's return) 178 | 179 | if(ctx->assigs() != NULL) { 180 | list assigs = visit(ctx->assigs()); 181 | signalState.set_params(assigs); 182 | } 183 | 184 | visit(program.procedures[contextStack.top().proceds_id][id]); 185 | 186 | cout << "Procedure executed. Restoring previous state" << endl; 187 | signalState = prev_signalState; 188 | return NULL; 189 | } 190 | 191 | antlrcpp::Any STILInterpreter::visitMacro_inst(STILParser::Macro_instContext* ctx) { 192 | string id = visit(ctx->id()); 193 | cout << actual_line << ": " << "Calling macro: " << id << " from block " << contextStack.top().macros_id << endl; 194 | 195 | STILState prev_signalState; 196 | 197 | if(ctx->assigs() != NULL) { 198 | cout << "Saving previous params state" << endl; 199 | 200 | prev_signalState = signalState; // We store the previous state in order to be able to restore the params status 201 | signalState.clear_params(); 202 | 203 | list assigs = visit(ctx->assigs()); 204 | signalState.set_params(assigs); 205 | } 206 | 207 | visit(program.macros[contextStack.top().macros_id][id]); 208 | 209 | cout << "Macro executed. Restoring previous params state" << endl; 210 | if(ctx->assigs() != NULL) { 211 | signalState.restore_params(prev_signalState); 212 | } 213 | return NULL; 214 | } 215 | 216 | antlrcpp::Any STILInterpreter::visitStop_inst(STILParser::Stop_instContext* ctx) { 217 | cout << actual_line << ": " << "Stopping test" << endl; 218 | exit(1); 219 | return NULL; 220 | } 221 | 222 | antlrcpp::Any STILInterpreter::visitIddq_inst(STILParser::Iddq_instContext* ctx) { 223 | cout << actual_line << ": " << "Executing Iddq instruction. Replacing it by the string defined in config" << endl; 224 | patternGenerator.print_iddq(); 225 | return NULL; 226 | } -------------------------------------------------------------------------------- /src/interpreter/STILInterpreter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_STILINTERPRETER_H 6 | #define STIL_INTERPRETER_STILINTERPRETER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "stil/definitions/STILProgram.h" 13 | #include "STILCustomVisitor.h" 14 | #include "STILState.h" 15 | #include "teradyne/STILConfig.h" 16 | #include "teradyne/STILPatternGenerator.h" 17 | #include "teradyne/STILTimingGenerator.h" 18 | 19 | using namespace std; 20 | using namespace antlr4; 21 | using namespace parser; 22 | 23 | class STILInterpreter : public STILCustomVisitor { 24 | 25 | private: 26 | STILProgram program; 27 | 28 | string stil_file; 29 | string pattern_file; 30 | string timing_file; 31 | 32 | ifstream stil_input; 33 | 34 | ContextStack contextStack; 35 | STILState signalState; 36 | STILPatternGenerator patternGenerator; 37 | STILTimingGenerator timingGenerator; 38 | 39 | int actual_line; 40 | 41 | virtual antlrcpp::Any visitPattern_exec(STILParser::Pattern_execContext* ctx) override; 42 | 43 | virtual antlrcpp::Any visitPattern_burst_call(STILParser::Pattern_burst_callContext* ctx) override; 44 | 45 | virtual antlrcpp::Any visitPattern_list(STILParser::Pattern_listContext* ctx) override; 46 | 47 | virtual antlrcpp::Any visitInst(STILParser::InstContext* ctx) override; 48 | 49 | virtual antlrcpp::Any visitLoop(STILParser::LoopContext* ctx) override; 50 | 51 | virtual antlrcpp::Any visitShift(STILParser::ShiftContext* ctx) override; 52 | 53 | virtual antlrcpp::Any visitW_inst(STILParser::W_instContext* ctx) override; 54 | 55 | virtual antlrcpp::Any visitV_inst(STILParser::V_instContext* ctx) override; 56 | 57 | virtual antlrcpp::Any visitC_inst(STILParser::C_instContext* ctx) override; 58 | 59 | virtual antlrcpp::Any visitF_inst(STILParser::F_instContext* ctx) override; 60 | 61 | virtual antlrcpp::Any visitCall_inst(STILParser::Call_instContext* ctx) override; 62 | 63 | virtual antlrcpp::Any visitMacro_inst(STILParser::Macro_instContext* ctx) override; 64 | 65 | virtual antlrcpp::Any visitStop_inst(STILParser::Stop_instContext* ctx) override; 66 | 67 | virtual antlrcpp::Any visitIddq_inst(STILParser::Iddq_instContext* ctx) override; 68 | 69 | // virtual antlrcpp::Any visitAssig(STILParser::AssigContext* ctx) override; 70 | 71 | public: 72 | STILInterpreter(string stil_file, string pattern_file, string timing_file, STILConfig& config); 73 | 74 | void run(); 75 | 76 | void run(string pattern_exec); 77 | }; 78 | 79 | 80 | #endif //STIL_INTERPRETER_STILINTERPRETER_H 81 | -------------------------------------------------------------------------------- /src/interpreter/STILState.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 08/08/2017. 3 | // 4 | 5 | #include "STILState.h" 6 | 7 | using namespace std; 8 | 9 | STILState::STILState(STILProgram* program, int* stil_line) { 10 | this->program = program; 11 | next_vector = program->signals; 12 | this->stil_line = stil_line; 13 | } 14 | 15 | void STILState::execute_assigs(list assigs) { 16 | Signals assig_result; 17 | for(auto it = assigs.begin(); it != assigs.end(); ++it) { 18 | 19 | SignalGroup& signalGroup = program->signalGroups[it->first]; 20 | vector& signals = signalGroup.signals; 21 | 22 | assert(it->second.size() == signals.size()); 23 | 24 | for(int i = 0; i < signals.size(); ++i) { 25 | 26 | char wfc = it->second[i]; 27 | if(wfc == '#' || wfc == '%') { 28 | wfc = next_vector[signals[i]].solve_param_ref(it->first, wfc); 29 | } 30 | 31 | if(assig_result.find(signals[i]) == assig_result.end()) { 32 | assig_result[signals[i]].value = wfc; 33 | } else { 34 | char wfc1 = assig_result[signals[i]].value; 35 | char wfc2 = wfc; 36 | if(wfc1 != wfc2) { 37 | string from = {wfc1, wfc2}; 38 | if(signalGroup.wfcmaps[from] == 0) { 39 | cerr << "Error at line: " << *stil_line << endl; 40 | cerr << "WFC map not defined for the char join of: " << from << " at signal: " << signals[i] << endl; 41 | cerr << "In one instruction (V/C/F) you can only assign the same value " 42 | << "to each signal in each assignation, or assign 2 different values " 43 | << "but having a WFCMap defined for that SignalGroup and that combination of wfc" << endl; 44 | exit(1); 45 | }; 46 | assig_result[signals[i]].value = signalGroup.wfcmaps[from]; 47 | } 48 | } 49 | } 50 | } 51 | for(auto it = assig_result.begin(); it != assig_result.end(); ++it) { 52 | next_vector[it->first].value = it->second.value; 53 | next_vector[it->first].refresh_params(); 54 | } 55 | } 56 | 57 | void STILState::set_params(list params) { 58 | for(auto it = params.begin(); it != params.end(); ++it) { 59 | SignalGroup& signalGroup = program->signalGroups[it->first]; 60 | if(signalGroup.signals.size() == 1) { 61 | Signal& signal = next_vector[signalGroup.signals[0]]; 62 | signal.params[signalGroup] = Signal::Param(it->first, it->second); 63 | max_param_size = max(max_param_size, (int) it->second.size()); 64 | } else { 65 | for(int s = 0; s < signalGroup.signals.size(); ++s) { 66 | Signal& signal = next_vector[signalGroup.signals[s]]; 67 | string aux = {it->second[s]}; 68 | signal.params[signalGroup] = Signal::Param(it->first, aux); 69 | } 70 | max_param_size = max(max_param_size, 1); 71 | } 72 | } 73 | } 74 | 75 | void STILState::clear_params() { 76 | max_param_size = 0; 77 | for(auto it = next_vector.begin(); it != next_vector.end(); ++it) { 78 | it->second.params.clear(); 79 | } 80 | } 81 | 82 | void STILState::restore_params(STILState& prev_state) { 83 | max_param_size = prev_state.max_param_size; 84 | for(auto it = next_vector.begin(); it != next_vector.end(); ++it) { 85 | it->second.params = prev_state.next_vector[it->second].params; 86 | } 87 | } 88 | 89 | void STILState::set_padding_to_params(int max_size) { 90 | for(auto it = next_vector.begin(); it != next_vector.end(); ++it) { 91 | it->second.set_padding_to_params(max_size); 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/interpreter/STILState.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 08/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_SIGNALSTATE_H 6 | #define STIL_INTERPRETER_SIGNALSTATE_H 7 | 8 | #include 9 | #include 10 | #include "stil/definitions/STILProgram.h" 11 | 12 | using namespace std; 13 | 14 | class STILState { 15 | 16 | private: 17 | STILProgram* program; 18 | 19 | public: 20 | typedef pair Assig; 21 | 22 | Signals next_vector; 23 | Identifiable active_table; 24 | 25 | int max_param_size = 0; 26 | int* stil_line; 27 | 28 | STILState() {} 29 | 30 | STILState(STILProgram* program, int* stil_line); 31 | 32 | void set_params(list params); 33 | 34 | void clear_params(); 35 | 36 | void restore_params(STILState& prev_state); 37 | 38 | void execute_assigs(list assigs); 39 | 40 | void set_padding_to_params(int max_size); 41 | }; 42 | 43 | 44 | #endif //STIL_INTERPRETER_SIGNALSTATE_H 45 | -------------------------------------------------------------------------------- /src/interpreter/stil/STILProgramVisitor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/08/2017. 3 | // 4 | 5 | #include "STILProgramVisitor.h" 6 | 7 | antlrcpp::Any STILProgramVisitor::visitProgram(STILParser::ProgramContext* ctx) { 8 | visit(ctx->signals()); 9 | visit(ctx->signal_groups()); 10 | visit(ctx->timing()); 11 | visit(ctx->pattern_burst_l()); 12 | visit(ctx->pattern_exec_l()); 13 | visit(ctx->pattern_burst_l()); 14 | visit(ctx->pattern_l()); 15 | visit(ctx->procedures_l()); 16 | visit(ctx->macros_l()); 17 | return NULL; 18 | } 19 | 20 | antlrcpp::Any STILProgramVisitor::visitSignals(STILParser::SignalsContext* ctx) { 21 | for(int i = 0; i < ctx->signal().size(); ++i) { 22 | visit(ctx->signal(i)); 23 | } 24 | return NULL; 25 | } 26 | 27 | antlrcpp::Any STILProgramVisitor::visitSignal(STILParser::SignalContext* ctx) { 28 | string id = visit(ctx->id()); 29 | Signal::signal_dir dir = visit(ctx->signal_dir()); 30 | if(dir != Signal::PSEUDO) { 31 | Signal::signal_scan_dir scan_dir = Signal::NONE; 32 | if(ctx->signal_attributes() != NULL && ctx->signal_attributes()->signal_scan() != NULL) { 33 | Signal::signal_scan_dir aux = visit(ctx->signal_attributes()->signal_scan()); 34 | scan_dir = aux; 35 | } 36 | program.signals[id] = Signal(id, dir, scan_dir); 37 | program.signalGroups[id] = SignalGroup(program.signals[id]); // Adding a default signalgroup 38 | } 39 | return NULL; 40 | } 41 | 42 | antlrcpp::Any STILProgramVisitor::visitSignal_dir(STILParser::Signal_dirContext* ctx) { 43 | if(ctx->getText() == "In") { 44 | return Signal::IN; 45 | } else if(ctx->getText() == "Out") { 46 | return Signal::OUT; 47 | } else if(ctx->getText() == "InOut") { 48 | return Signal::INOUT; 49 | } else { 50 | return Signal::PSEUDO; 51 | } 52 | } 53 | 54 | antlrcpp::Any STILProgramVisitor::visitSignal_scan(STILParser::Signal_scanContext* ctx) { 55 | if(ctx->getText() == "ScanIn") { 56 | return Signal::SCAN_IN; 57 | } else if(ctx->getText() == "ScanOut") { 58 | return Signal::SCAN_OUT; 59 | } else { 60 | return NULL; 61 | } 62 | } 63 | 64 | antlrcpp::Any STILProgramVisitor::visitSignal_groups(STILParser::Signal_groupsContext* ctx) { 65 | for(int i = 0; i < ctx->signal_group().size(); ++i) { 66 | visit(ctx->signal_group(i)); 67 | } 68 | return NULL; 69 | } 70 | 71 | antlrcpp::Any STILProgramVisitor::visitSignal_group(STILParser::Signal_groupContext* ctx) { 72 | string id = visit(ctx->id()); 73 | vector signals = visit(ctx->signal_list()); 74 | SignalGroup::WFCMaps wfcmaps; 75 | if(ctx->signal_attributes() != NULL && ctx->signal_attributes()->wfc_map() != NULL) { 76 | SignalGroup::WFCMaps aux = visit(ctx->signal_attributes()->wfc_map()); 77 | wfcmaps = aux; 78 | } 79 | program.signalGroups[id] = SignalGroup(id, signals, wfcmaps); 80 | return NULL; 81 | } 82 | 83 | antlrcpp::Any STILProgramVisitor::visitSignal_list(STILParser::Signal_listContext* ctx) { 84 | vector signal_list; 85 | for(int i = 0; i < ctx->id().size(); ++i) { 86 | string id = visit(ctx->id(i)); 87 | signal_list.push_back(id); 88 | } 89 | return signal_list; 90 | } 91 | 92 | antlrcpp::Any STILProgramVisitor::visitWfc_map(STILParser::Wfc_mapContext* ctx) { 93 | SignalGroup::WFCMaps wfcmaps; 94 | for(int i = 0; i < ctx->map_rule().size(); ++i) { 95 | MapRule map_rule = visit(ctx->map_rule(i)); 96 | wfcmaps[map_rule.first] = map_rule.second; 97 | if(map_rule.first.size() == 2) { 98 | // If the WFC are assigned in the inverted order 99 | char aux = map_rule.first[0]; 100 | map_rule.first[0] = map_rule.first[1]; 101 | map_rule.first[1] = aux; 102 | wfcmaps[map_rule.first] = map_rule.second; 103 | } 104 | } 105 | return wfcmaps; 106 | } 107 | 108 | antlrcpp::Any STILProgramVisitor::visitMap_rule(STILParser::Map_ruleContext* ctx) { 109 | string from = visit(ctx->wfc_seq(0)); 110 | string to = visit(ctx->wfc_seq(1)); 111 | assert(from.size() == 2 && from[0] != from[1]); 112 | assert(to.size() == 1); 113 | return MapRule(from, to[0]); 114 | } 115 | 116 | antlrcpp::Any STILProgramVisitor::visitTiming(STILParser::TimingContext* ctx) { 117 | for(int i = 0; i < ctx->waveform_table().size(); ++i) { 118 | visit(ctx->waveform_table(i)); 119 | } 120 | return NULL; 121 | } 122 | 123 | antlrcpp::Any STILProgramVisitor::visitWaveform_table(STILParser::Waveform_tableContext* ctx) { 124 | string id = visit(ctx->id()); 125 | float period = visit(ctx->period()); 126 | WaveForms waveforms = visit(ctx->waveforms()); 127 | program.waveFormTables[id] = WaveFormTable(id, period, waveforms); 128 | return NULL; 129 | } 130 | 131 | antlrcpp::Any STILProgramVisitor::visitWaveforms(STILParser::WaveformsContext* ctx) { 132 | WaveForms waveforms; 133 | for(int i = 0; i < ctx->waveform().size(); ++i) { 134 | WaveForm waveform = visit(ctx->waveform(i)); 135 | waveforms.push_back(waveform); 136 | } 137 | return waveforms; 138 | } 139 | 140 | antlrcpp::Any STILProgramVisitor::visitWaveform(STILParser::WaveformContext* ctx) { 141 | string id = visit(ctx->id()); 142 | string wfc = visit(ctx->wfc_seq()); 143 | vector events; 144 | for(int i = 0; i < ctx->event().size(); ++i) { 145 | WaveForm::WaveFormEvent event = visit(ctx->event(i)); 146 | events.push_back(event); 147 | } 148 | return WaveForm(id, wfc[0], events); 149 | } 150 | 151 | antlrcpp::Any STILProgramVisitor::visitEvent(STILParser::EventContext* ctx) { 152 | float time = visit(ctx->time_expr()); 153 | char event_code = visit(ctx->event_code()); 154 | return WaveForm::WaveFormEvent(time, event_code); 155 | } 156 | 157 | antlrcpp::Any STILProgramVisitor::visitEvent_code(STILParser::Event_codeContext* ctx) { 158 | string event_code = visit(ctx->CHARS()); 159 | return event_code[0]; 160 | } 161 | 162 | antlrcpp::Any STILProgramVisitor::visitPattern_exec(STILParser::Pattern_execContext* ctx) { 163 | string id = GLOBAL_DEF; 164 | if(ctx->id() != NULL) { 165 | string aux = visit(ctx->id()); 166 | id = aux; 167 | // If there's only one pattern_exec, we create a global alias 168 | if(((STILParser::Pattern_exec_lContext*) ctx->parent)->pattern_exec().size() == 1) { 169 | program.patternExecs[GLOBAL_DEF] = ctx; 170 | } 171 | } 172 | program.patternExecs[id] = ctx; 173 | return NULL; 174 | } 175 | 176 | antlrcpp::Any STILProgramVisitor::visitPattern_burst(STILParser::Pattern_burstContext* ctx) { 177 | string id = visit(ctx->id()); 178 | PatternContext context = visit(ctx->context()); 179 | program.patternBursts[id] = PatternBurst(id, ctx->pattern_list(), context); 180 | return NULL; 181 | } 182 | 183 | antlrcpp::Any STILProgramVisitor::visitPattern(STILParser::PatternContext* ctx) { 184 | string id = visit(ctx->id()); 185 | program.patterns[id] = ctx->inst_list(); 186 | return NULL; 187 | } 188 | 189 | antlrcpp::Any STILProgramVisitor::visitProcedures(STILParser::ProceduresContext* ctx) { 190 | string id = GLOBAL_DEF; 191 | if(ctx->id() != NULL) { 192 | string aux = visit(ctx->id()); 193 | id = aux; 194 | } 195 | for(int i = 0; i < ctx->procedure().size(); ++i) { 196 | string proced_id = visit(ctx->procedure(i)->id()); 197 | program.procedures[id][proced_id] = ctx->procedure(i)->inst_list(); 198 | } 199 | return NULL; 200 | } 201 | 202 | antlrcpp::Any STILProgramVisitor::visitMacros(STILParser::MacrosContext* ctx) { 203 | string id = GLOBAL_DEF; 204 | if(ctx->id() != NULL) { 205 | string aux = visit(ctx->id()); 206 | id = aux; 207 | } 208 | for(int i = 0; i < ctx->macro().size(); ++i) { 209 | string macro_id = visit(ctx->macro(i)->id()); 210 | program.macros[id][macro_id] = ctx->macro(i)->inst_list(); 211 | } 212 | return NULL; 213 | } -------------------------------------------------------------------------------- /src/interpreter/stil/STILProgramVisitor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_STILPROGRAMVISITOR_H 6 | #define STIL_INTERPRETER_STILPROGRAMVISITOR_H 7 | 8 | 9 | #include "definitions/STILProgram.h" 10 | #include "../STILCustomVisitor.h" 11 | 12 | using namespace std; 13 | using namespace antlr4; 14 | using namespace parser; 15 | 16 | class STILProgramVisitor : public STILCustomVisitor { 17 | 18 | private: 19 | 20 | typedef pair MapRule; 21 | 22 | STILProgram& program; 23 | 24 | virtual antlrcpp::Any visitProgram(STILParser::ProgramContext* ctx) override; 25 | 26 | virtual antlrcpp::Any visitSignals(STILParser::SignalsContext* ctx) override; 27 | 28 | virtual antlrcpp::Any visitSignal(STILParser::SignalContext* ctx) override; 29 | 30 | virtual antlrcpp::Any visitSignal_dir(STILParser::Signal_dirContext* ctx) override; 31 | 32 | virtual antlrcpp::Any visitSignal_scan(STILParser::Signal_scanContext* ctx) override; 33 | 34 | virtual antlrcpp::Any visitSignal_groups(STILParser::Signal_groupsContext* ctx) override; 35 | 36 | virtual antlrcpp::Any visitSignal_group(STILParser::Signal_groupContext* ctx) override; 37 | 38 | virtual antlrcpp::Any visitSignal_list(STILParser::Signal_listContext* ctx) override; 39 | 40 | virtual antlrcpp::Any visitWfc_map(STILParser::Wfc_mapContext* ctx) override; 41 | 42 | virtual antlrcpp::Any visitMap_rule(STILParser::Map_ruleContext* ctx) override; 43 | 44 | virtual antlrcpp::Any visitTiming(STILParser::TimingContext* ctx) override; 45 | 46 | virtual antlrcpp::Any visitWaveform_table(STILParser::Waveform_tableContext* ctx) override; 47 | 48 | virtual antlrcpp::Any visitWaveforms(STILParser::WaveformsContext* ctx) override; 49 | 50 | virtual antlrcpp::Any visitWaveform(STILParser::WaveformContext* ctx) override; 51 | 52 | virtual antlrcpp::Any visitEvent(STILParser::EventContext* ctx) override; 53 | 54 | virtual antlrcpp::Any visitEvent_code(STILParser::Event_codeContext* ctx) override; 55 | 56 | virtual antlrcpp::Any visitPattern_exec(STILParser::Pattern_execContext* ctx) override; 57 | 58 | virtual antlrcpp::Any visitPattern_burst(STILParser::Pattern_burstContext* ctx) override; 59 | 60 | virtual antlrcpp::Any visitPattern(STILParser::PatternContext* ctx) override; 61 | 62 | virtual antlrcpp::Any visitProcedures(STILParser::ProceduresContext* ctx) override; 63 | 64 | virtual antlrcpp::Any visitMacros(STILParser::MacrosContext* ctx) override; 65 | 66 | public: 67 | 68 | STILProgramVisitor(STILProgram& program) : program(program) {} 69 | }; 70 | 71 | 72 | #endif //STIL_INTERPRETER_STILPROGRAMVISITOR_H 73 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/Identifiable.cpp: -------------------------------------------------------------------------------- 1 | #include "Identifiable.h" 2 | 3 | Identifiable::Identifiable(string id) : string(id) {} 4 | 5 | Identifiable::Identifiable() : string("_unitialized_") {} 6 | 7 | string Identifiable::format(STILConfig& config) const { 8 | string id = *this; 9 | 10 | if(config.namesMap.find(id) != config.namesMap.end()) { 11 | return config.namesMap[id]; 12 | } 13 | 14 | id.erase(0, 1); 15 | id.pop_back(); 16 | 17 | if(config.removeBrackets) { 18 | for(int i = 0; i < id.size(); ++i) { 19 | if(id[i] == '[') { 20 | for(int j = i+1; j < id.size(); ++j) { 21 | if(id[j] == ']') { 22 | string name = id.substr(0, i); 23 | string index = id.substr(i+1, j-i-1); 24 | return name + "_" + index; 25 | } 26 | } 27 | } 28 | } 29 | } 30 | return id; 31 | } 32 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/Identifiable.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_IDENTIFIABLE_H 6 | #define STIL_INTERPRETER_IDENTIFIABLE_H 7 | 8 | #include 9 | #include 10 | #include "../../teradyne/STILConfig.h" 11 | 12 | using namespace std; 13 | 14 | class Identifiable : public string { 15 | 16 | public: 17 | 18 | Identifiable(string id); 19 | 20 | Identifiable(); 21 | 22 | string format(STILConfig& config) const; 23 | 24 | }; 25 | 26 | 27 | #endif //STIL_INTERPRETER_IDENTIFIABLE_H 28 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/PatternBurst.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #include "PatternBurst.h" 6 | 7 | PatternBurst::PatternBurst(string id, STILParser::Pattern_listContext* ast, PatternContext& context) : Identifiable(id) { 8 | this->ast = ast; 9 | this->context = context; 10 | } -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/PatternBurst.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_PATTERNBURST_H 6 | #define STIL_INTERPRETER_PATTERNBURST_H 7 | 8 | #include 9 | #include 10 | #include "Identifiable.h" 11 | #include "../../teradyne/definitions/PatternContext.h" 12 | 13 | using namespace std; 14 | using namespace parser; 15 | 16 | class PatternBurst : public Identifiable { 17 | 18 | public: 19 | 20 | STILParser::Pattern_listContext* ast; 21 | PatternContext context; 22 | 23 | PatternBurst() : Identifiable() {} 24 | 25 | PatternBurst(string id, STILParser::Pattern_listContext* ast, PatternContext& context); 26 | 27 | }; 28 | 29 | typedef unordered_map PatternBursts; 30 | 31 | #endif //STIL_INTERPRETER_PATTERNBURST_H 32 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/STILProgram.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_STILPROGRAM_H 6 | #define STIL_INTERPRETER_STILPROGRAM_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "Signal.h" 13 | #include "SignalGroup.h" 14 | #include "PatternBurst.h" 15 | #include "WaveFormTable.h" 16 | #include "../../teradyne/STILConfig.h" 17 | 18 | using namespace std; 19 | using namespace antlr4; 20 | using namespace tree; 21 | using namespace parser; 22 | 23 | #define GLOBAL_DEF "global" 24 | 25 | typedef unordered_map PatternExecs; 26 | typedef unordered_map Patterns; 27 | typedef unordered_map Procedures; 28 | typedef unordered_map Macros; 29 | typedef unordered_map ProcedureBlocks; 30 | typedef unordered_map MacroBlocks; 31 | 32 | class STILProgram { 33 | 34 | public: 35 | PatternExecs patternExecs; 36 | PatternBursts patternBursts; 37 | Patterns patterns; 38 | ProcedureBlocks procedures; 39 | MacroBlocks macros; 40 | Signals signals; 41 | SignalGroups signalGroups; 42 | WaveFormTables waveFormTables; 43 | 44 | STILConfig config; 45 | 46 | STILProgram(STILConfig config) : config(config) {} 47 | 48 | vector get_formatted_signal_names() { 49 | vector signal_names; 50 | for(auto it = signals.begin(); it != signals.end(); ++it) { 51 | string formatted_id = it->second.format(config); 52 | if(formatted_id != "") { 53 | signal_names.push_back(formatted_id); 54 | } 55 | } 56 | return signal_names; 57 | } 58 | }; 59 | 60 | 61 | #endif //STIL_INTERPRETER_STILPROGRAM_H 62 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/Signal.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/08/2017. 3 | // 4 | 5 | #include 6 | #include "Signal.h" 7 | 8 | Signal::Signal(string id, signal_dir dir) : Identifiable(id) { 9 | this->dir = dir; 10 | } 11 | 12 | Signal::Signal(string id, signal_dir dir, signal_scan_dir scan_dir) : Signal(id, dir) { 13 | this->scan_dir = scan_dir; 14 | } 15 | 16 | char Signal::solve_param_ref(string ref_id, char type) { 17 | auto it = params.find(ref_id); 18 | if(it == params.end()) { // There is no param by name 19 | it = params.begin(); // Retrieving param by content (any other param) 20 | if(it == params.end()) { // There is no other param, return last assigned value 21 | return value; 22 | } 23 | } 24 | 25 | string& s = it->second.values; 26 | if(s.size() == 0) { 27 | cerr << "There's a void string in a signal parameter!" << endl; 28 | cerr << "Signal: " << *this << ", parameter name: " << it->second << endl; 29 | exit(1); 30 | } 31 | 32 | char wfc = s.front(); 33 | if(type == '#') { 34 | it->second.needs_refresh = true; 35 | } 36 | return wfc; 37 | } 38 | 39 | void Signal::set_padding_to_params(int max_size) { 40 | if(scan_dir != NONE) { 41 | for(auto it = params.begin(); it != params.end(); ++it) { 42 | string& values = it->second.values; 43 | if(values.size() > 1) { // Avoid modifying used params + signalgroups params 44 | if(values.size() != max_size) { 45 | if(scan_dir == SCAN_IN) { 46 | string padding(max_size - values.size(), '$'); 47 | values = padding + values; 48 | } else if(scan_dir == SCAN_OUT) { 49 | string padding(max_size - values.size(), '@'); 50 | values = values + padding; 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | void Signal::refresh_params() { 59 | auto it = params.begin(); 60 | while(it != params.end()) { 61 | bool is_empty = it->second.refresh(); 62 | if(is_empty) { 63 | it = params.erase(it); 64 | } else { 65 | ++it; 66 | } 67 | } 68 | } 69 | 70 | Signal::Param::Param(string id, string& values) : Identifiable(id) { 71 | this->values = values; 72 | needs_refresh = false; 73 | assert(values.size() != 0); 74 | } 75 | 76 | bool Signal::Param::refresh() { 77 | if(needs_refresh) { 78 | needs_refresh = false; 79 | values.erase(0, 1); 80 | if(values.size() == 0) { 81 | return true; 82 | } 83 | } 84 | return false; 85 | } 86 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/Signal.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_SIGNAL_H 6 | #define STIL_INTERPRETER_SIGNAL_H 7 | 8 | #include 9 | #include 10 | #include "Identifiable.h" 11 | 12 | using namespace std; 13 | 14 | class Signal : public Identifiable { 15 | 16 | public: 17 | enum signal_dir { 18 | IN, OUT, INOUT, PSEUDO 19 | }; 20 | 21 | enum signal_scan_dir { 22 | NONE, SCAN_IN, SCAN_OUT 23 | }; 24 | 25 | class Param : public Identifiable { 26 | 27 | public: 28 | string values; 29 | bool needs_refresh = false; 30 | 31 | Param() : Identifiable() {} 32 | 33 | Param(string id, string& values); 34 | 35 | bool refresh(); 36 | }; 37 | 38 | typedef unordered_map Params; 39 | 40 | signal_dir dir; 41 | signal_scan_dir scan_dir = NONE; 42 | char value = '?'; 43 | Params params; 44 | 45 | Signal() : Identifiable() {} 46 | 47 | Signal(string id, signal_dir dir); 48 | 49 | Signal(string id, signal_dir dir, signal_scan_dir scan_dir); 50 | 51 | char solve_param_ref(string ref_id, char type); 52 | 53 | void set_padding_to_params(int max_size); 54 | 55 | void refresh_params(); 56 | }; 57 | 58 | typedef map Signals; 59 | 60 | 61 | #endif //STIL_INTERPRETER_SIGNAL_H 62 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/SignalGroup.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #include "SignalGroup.h" 6 | 7 | SignalGroup::SignalGroup(string id, vector& signals, WFCMaps& wfcmaps) : Identifiable(id) { 8 | this->signals = signals; 9 | this->wfcmaps = wfcmaps; 10 | } 11 | 12 | SignalGroup::SignalGroup(const Signal &signal) : Identifiable(signal) { 13 | this->signals = vector(1, signal); 14 | } 15 | 16 | bool SignalGroup::contains(string signal_id) { 17 | for(int i = 0; i < signals.size(); ++i) { 18 | if(signals[i] == signal_id) { 19 | return true; 20 | } 21 | } 22 | return false; 23 | } 24 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/SignalGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_SIGNALGROUP_H 6 | #define STIL_INTERPRETER_SIGNALGROUP_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include "Identifiable.h" 12 | #include "Signal.h" 13 | 14 | using namespace std; 15 | 16 | class SignalGroup : public Identifiable { 17 | 18 | public: 19 | 20 | typedef unordered_map WFCMaps; 21 | 22 | vector signals; 23 | WFCMaps wfcmaps; 24 | 25 | SignalGroup() : Identifiable() {} 26 | 27 | SignalGroup(string id, vector& signals, WFCMaps& wfcMaps); 28 | 29 | SignalGroup(const Signal& signal); 30 | 31 | bool contains(string signal_id); 32 | 33 | }; 34 | 35 | typedef unordered_map SignalGroups; 36 | 37 | 38 | #endif //STIL_INTERPRETER_SIGNALGROUP_H 39 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/WaveFormTable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #include 6 | #include "WaveFormTable.h" 7 | 8 | WaveFormTable::WaveFormTable(string id, float period, WaveForms& waveforms) : Identifiable(id) { 9 | this->period = period; 10 | this->waveforms = waveforms; 11 | } 12 | 13 | WaveForm& WaveFormTable::get_waveform(string signal_id, char wfc, SignalGroups& signalGroups) { 14 | bool found = false; 15 | int waveform = 0; 16 | while(waveform < waveforms.size() && !found) { 17 | if(signalGroups[waveforms[waveform]].contains(signal_id) && wfc == waveforms[waveform].wfc) { 18 | found = true; 19 | } else { 20 | ++waveform; 21 | } 22 | } 23 | 24 | if(!found) { 25 | cerr << "Waveform not found for signal: " << signal_id << " and WFC: " << wfc << endl; 26 | exit(1); 27 | } 28 | 29 | return waveforms[waveform]; 30 | } 31 | -------------------------------------------------------------------------------- /src/interpreter/stil/definitions/WaveFormTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_WAVEFORMTABLE_H 6 | #define STIL_INTERPRETER_WAVEFORMTABLE_H 7 | 8 | #include 9 | #include 10 | #include "Identifiable.h" 11 | #include "../../teradyne/definitions/WaveForm.h" 12 | #include "SignalGroup.h" 13 | 14 | typedef vector WaveForms; 15 | 16 | class WaveFormTable : public Identifiable { 17 | 18 | public: 19 | 20 | float period; 21 | WaveForms waveforms; 22 | 23 | WaveFormTable() : Identifiable() {} 24 | 25 | WaveFormTable(string id, float period, WaveForms& waveforms); 26 | 27 | WaveForm& get_waveform(string signal_id, char wfc, SignalGroups& signalGroups); 28 | 29 | }; 30 | 31 | typedef map WaveFormTables; 32 | 33 | 34 | #endif //STIL_INTERPRETER_WAVEFORMTABLE_H 35 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/STILConfig.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 09/08/2017. 3 | // 4 | 5 | #include "STILConfig.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "definitions/DefaultConfig.h" 11 | 12 | class STILConfig::LineNumberStreambuf : public std::streambuf { 13 | 14 | private: 15 | std::streambuf* mySource; 16 | std::istream* myOwner; 17 | bool myIsAtStartOfLine; 18 | char myBuffer; 19 | 20 | protected: 21 | int underflow() { 22 | int ch = mySource->sbumpc(); 23 | if(ch != EOF) { 24 | myBuffer = ch; 25 | setg(&myBuffer, &myBuffer, &myBuffer + 1); 26 | if(myIsAtStartOfLine) { 27 | ++myLineNumber; 28 | } 29 | myIsAtStartOfLine = myBuffer == '\n'; 30 | } 31 | return ch; 32 | } 33 | 34 | public: 35 | int myLineNumber; 36 | 37 | LineNumberStreambuf(std::istream& owner) : mySource(owner.rdbuf()), myOwner(&owner), myIsAtStartOfLine(true), myLineNumber(0) { 38 | myOwner->rdbuf(this); 39 | } 40 | }; 41 | 42 | 43 | STILConfig::STILConfig() { 44 | string s((char*) grammar_stil_config); 45 | istringstream iss(s); 46 | input = &iss; 47 | parse_config_file(); 48 | input = NULL; 49 | } 50 | 51 | STILConfig::STILConfig(string path) { 52 | cout << "Parsing config file" << endl; 53 | ifstream file; 54 | file.open(path); 55 | input = &file; 56 | parse_config_file(); 57 | input = NULL; 58 | cout << "Config file parsed correctly" << endl; 59 | cout << "--------------------------------------" << endl; 60 | } 61 | 62 | void STILConfig::parse_config_file() { 63 | 64 | if(input == NULL) { 65 | cerr << "Input stream to parser the config file is null" << endl; 66 | exit(1); 67 | } 68 | 69 | istream& input = *(this->input); 70 | LineNumberStreambuf line_buffer(input); 71 | this->line_buffer = &line_buffer; 72 | 73 | string s; 74 | 75 | // EVENT MAP 76 | parse_word_or_comment("event_map"); 77 | parse_word_or_comment("{"); 78 | while(input >> s && s != "}") { 79 | string stil_event_seq = s; 80 | char tester_event; 81 | string translations; 82 | 83 | input >> s; 84 | parse_word(s, "->"); 85 | input >> tester_event; 86 | getline(input, translations); 87 | 88 | list wave_translations; 89 | istringstream iss(translations); 90 | char c; 91 | while(iss >> c) { // It's a "coma" 92 | iss >> c; // It's a left parenthesis 93 | string rule; // It's a full rule 94 | getline(iss, rule, ')'); 95 | wave_translations.push_back(WaveTranslation(rule)); 96 | } 97 | 98 | eventsMap[stil_event_seq] = EventsTranslation(tester_event, wave_translations); 99 | } 100 | parse_word(s, "}"); 101 | 102 | // SIGNAL NAME MAP 103 | parse_word_or_comment("signal_name_map"); 104 | parse_word_or_comment("{"); 105 | while(input >> s && s != "}") { 106 | string from = s; 107 | string to; 108 | 109 | input >> s; 110 | parse_word(s, "->"); 111 | getline(input, to); 112 | if(to.size() > 1 && to[0] == ' ') { 113 | to = to.substr(1, to.size() - 1); 114 | } 115 | if(from == "[]" && to == "_") { 116 | removeBrackets = true; 117 | } else { 118 | namesMap[from] = to; 119 | } 120 | } 121 | parse_word(s, "}"); 122 | 123 | // SCAN PADDING 124 | parse_word_or_comment("scan_padding"); 125 | parse_word_or_comment("{"); 126 | input >> s; 127 | parse_word(s, "scan_in"); 128 | input >> s; 129 | parse_word(s, "->"); 130 | input >> scan_padding_in; 131 | input >> s; 132 | parse_word(s, "scan_out"); 133 | input >> s; 134 | parse_word(s, "->"); 135 | input >> scan_padding_out; 136 | input >> s; 137 | parse_word(s, "}"); 138 | 139 | // IDDQ ACTION 140 | parse_word_or_comment("iddq_action"); 141 | parse_word_or_comment("{"); 142 | getline(input, s); 143 | getline(input, iddq_action, '}'); 144 | } 145 | 146 | void STILConfig::parse_word_or_comment(string value) { 147 | string s; 148 | *input >> s; 149 | if(s.size() >= 2 && s[0] == '/' && s[1] == '/') { 150 | getline(*input, s); 151 | parse_word_or_comment(value); 152 | } else { 153 | parse_word(s, value); 154 | } 155 | } 156 | 157 | void STILConfig::parse_word(string& s, string value) { 158 | if(s != value) { 159 | cerr << "Error parsing config file at line " << line_buffer->myLineNumber << endl; 160 | cerr << "Expecting: \"" << value << "\" but read: \"" << s << "\"" << endl; 161 | exit(1); 162 | } 163 | } -------------------------------------------------------------------------------- /src/interpreter/teradyne/STILConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 09/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_STILCONFIG_H 6 | #define STIL_INTERPRETER_STILCONFIG_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "definitions/WaveTranslation.h" 13 | 14 | using namespace std; 15 | 16 | 17 | class STILConfig { 18 | 19 | private: 20 | 21 | istream* input; 22 | class LineNumberStreambuf; 23 | LineNumberStreambuf* line_buffer; 24 | 25 | void parse_config_file(); 26 | void parse_word_or_comment(string value); 27 | void parse_word(string& s, string value); 28 | 29 | public: 30 | 31 | typedef pair> EventsTranslation; 32 | typedef unordered_map EventsMap; 33 | typedef unordered_map NamesMap; 34 | 35 | EventsMap eventsMap; 36 | NamesMap namesMap; 37 | bool removeBrackets = false; 38 | char scan_padding_in; 39 | char scan_padding_out; 40 | string iddq_action; 41 | 42 | STILConfig(); 43 | 44 | STILConfig(string path); 45 | }; 46 | 47 | 48 | #endif //STIL_INTERPRETER_STILCONFIG_H 49 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/STILPatternGenerator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/09/2017. 3 | // 4 | 5 | #include "STILPatternGenerator.h" 6 | 7 | STILPatternGenerator::STILPatternGenerator(string pattern_file, STILProgram* program, int* stil_line) { 8 | this->program = program; 9 | this->stil_line = stil_line; 10 | output.open(pattern_file); 11 | } 12 | 13 | void STILPatternGenerator::print_headers() { 14 | output << "opcode_mode=extended;" << endl; 15 | output << "import tset "; 16 | // TODO Replace this by the actual names of the generated timesets 17 | for(auto it = program->waveFormTables.begin(); it != program->waveFormTables.end(); ++it) { 18 | if(it != program->waveFormTables.begin()) { 19 | output << ","; 20 | } 21 | output << "t" << it->second.format(program->config); 22 | } 23 | output << ";" << endl; 24 | output << "vector($tset"; 25 | vector signal_names = program->get_formatted_signal_names(); 26 | for(int i = 0; i < signal_names.size(); ++i) { 27 | output << "," << signal_names[i]; 28 | } 29 | output << ")" << endl; 30 | output << "{" << endl; 31 | }; 32 | 33 | void STILPatternGenerator::clock_cycle(const STILState& state, STILTimingGenerator& timingGenerator) { 34 | output << string(padding, ' '); 35 | output << "> " << "t"; 36 | long int offset = output.tellp(); 37 | output << " "; 38 | // output << "> " << "t" << state.active_table.format(program->config) << " "; // This line was from before implementing the timing generation 39 | 40 | WaveFormTable& table = program->waveFormTables[state.active_table]; 41 | TimeSet timeset(table.period); 42 | 43 | for(auto it = state.next_vector.begin(); it != state.next_vector.end(); ++it) { 44 | 45 | // This is in case that a signal has been removed in the config file. 46 | // If it's removed, we don't print its value 47 | if(it->second.format(program->config) == "") { 48 | continue; 49 | } 50 | 51 | char wfc = it->second.value; 52 | assert(wfc != '?' && "WFC not defined for signal before clock_cycle!"); 53 | assert(wfc != '#' && wfc != '%'); // Check that it has been substituted by a parameter 54 | 55 | if(wfc == '$') { 56 | wfc = program->config.scan_padding_in; 57 | } else if(wfc == '@') { 58 | wfc = program->config.scan_padding_out; 59 | } 60 | 61 | WaveForm& waveform = table.get_waveform(it->second, wfc, program->signalGroups); 62 | string event_seq = waveform.event_seq(); 63 | 64 | STILConfig::EventsTranslation& translation = program->config.eventsMap[event_seq]; 65 | char tester_event = translation.first; 66 | if(tester_event == '\0') { 67 | cerr << "Error at line: " << *stil_line << endl; 68 | cerr << "Event sequence \"" << event_seq << "\" in WaveFormTable: " << state.active_table << " not defined in config file" << endl; 69 | cerr << "Please, define a correct config file that maps all the used permutations of STIL events inside the used waveforms to generate tester events" << endl; 70 | exit(1); 71 | } 72 | output << tester_event << " "; 73 | 74 | WaveSet waveset(table.period, waveform, translation.second); 75 | timeset.add_waveset(waveset); 76 | } 77 | output << ";" << endl; 78 | 79 | padding = PADDING; 80 | prev_last_line_index = last_line_index; 81 | last_line_index = output.tellp(); 82 | 83 | output.seekp(offset); 84 | output << timingGenerator.add_timeset(timeset); 85 | output.seekp(last_line_index); 86 | } 87 | 88 | void STILPatternGenerator::finish() { 89 | output << "}" << endl; 90 | output.seekp(prev_last_line_index); 91 | output << "halt"; 92 | output.close(); 93 | } 94 | 95 | void STILPatternGenerator::print_tester_inst(string instruction) { 96 | output << instruction; 97 | padding -= instruction.size(); 98 | } 99 | 100 | void STILPatternGenerator::print_iddq() { 101 | output << program->config.iddq_action; 102 | } 103 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/STILPatternGenerator.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/09/2017. 3 | // 4 | 5 | #ifndef STIL_CONVERTER_STILPATTERNGENERATOR_H 6 | #define STIL_CONVERTER_STILPATTERNGENERATOR_H 7 | 8 | #include "../STILState.h" 9 | #include "STILTimingGenerator.h" 10 | 11 | using namespace std; 12 | 13 | #define PADDING 22 14 | 15 | class STILPatternGenerator { 16 | 17 | private: 18 | ofstream output; 19 | STILProgram* program; 20 | 21 | int* stil_line; 22 | int padding = PADDING; 23 | long int prev_last_line_index = 0; 24 | long int last_line_index = 0; 25 | 26 | public: 27 | 28 | STILPatternGenerator() {} 29 | 30 | STILPatternGenerator(string pattern_file, STILProgram* program, int* stil_line); 31 | 32 | void print_headers(); 33 | 34 | void clock_cycle(const STILState& state, STILTimingGenerator& timingGenerator); 35 | 36 | void finish(); 37 | 38 | void print_tester_inst(string instruction); 39 | 40 | void print_iddq(); 41 | }; 42 | 43 | 44 | #endif //STIL_CONVERTER_STILPATTERNGENERATOR_H 45 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/STILTimingGenerator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/09/2017. 3 | // 4 | 5 | #include "STILTimingGenerator.h" 6 | 7 | STILTimingGenerator::STILTimingGenerator(string timing_file) { 8 | output.open(timing_file); 9 | } 10 | 11 | void STILTimingGenerator::finish(vector signal_names) { 12 | output << "DFF 1.1 Time Sets (Basic)" << endl; 13 | output << "Timing Mode: Extended Strobe Timing: =1*us Convert Timing: =1*us" << endl; 14 | output << " Cycle Pin/Group Data Drive Compare" << endl; 15 | output << "Time Set Period CPP Name Setup Src Fmt On Data Return Off Mode Open Close " << endl; 16 | for(int id = 0; id < timesets.size(); ++id) { 17 | timesets[id].reduce(); 18 | output << timesets[id].to_string(signal_names) << endl; 19 | } 20 | output.close(); 21 | } 22 | 23 | int STILTimingGenerator::add_timeset(TimeSet& timeset) { 24 | auto it = cache.find(timeset); 25 | if(it != cache.end()) { 26 | return it->second; 27 | } 28 | for(int id = 0; id < timesets.size(); ++id) { 29 | if(timesets[id].merge(timeset)) { 30 | cache[timeset] = id; 31 | return id; 32 | } 33 | } 34 | int id = timesets.size(); 35 | cout << "Creating timeset: " << id << endl; 36 | timeset.id = id; 37 | timesets.push_back(timeset); 38 | cache[timeset] = id; 39 | return id; 40 | } 41 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/STILTimingGenerator.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/09/2017. 3 | // 4 | 5 | #ifndef STIL_CONVERTER_STILTIMINGGENERATOR_H 6 | #define STIL_CONVERTER_STILTIMINGGENERATOR_H 7 | 8 | #include 9 | #include 10 | #include "definitions/TimeSet.h" 11 | #include "definitions/TimeSetHasher.h" 12 | 13 | using namespace std; 14 | 15 | class STILTimingGenerator { 16 | 17 | private: 18 | ofstream output; 19 | vector timesets; 20 | unordered_map cache; 21 | 22 | public: 23 | 24 | STILTimingGenerator() {} 25 | 26 | STILTimingGenerator(string timing_file); 27 | 28 | int add_timeset(TimeSet& timeset); 29 | 30 | void finish(vector signal_names); 31 | }; 32 | 33 | 34 | #endif //STIL_CONVERTER_STILTIMINGGENERATOR_H 35 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/DefaultConfig.h: -------------------------------------------------------------------------------- 1 | unsigned char grammar_stil_config[] = { 2 | 0x2f, 0x2f, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x63, 3 | 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x66, 4 | 0x6f, 0x72, 0x20, 0x53, 0x54, 0x49, 0x4c, 0x20, 0x63, 0x6f, 0x6e, 0x76, 5 | 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 6 | 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 7 | 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x28, 0x61, 0x6e, 0x64, 0x20, 8 | 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x29, 0x20, 0x6f, 0x75, 0x74, 9 | 0x73, 0x69, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 10 | 0x63, 0x6b, 0x73, 0x0a, 0x2f, 0x2f, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 11 | 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 12 | 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, 13 | 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x21, 0x0a, 0x2f, 0x2f, 14 | 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 15 | 0x20, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x0a, 0x0a, 0x0a, 0x2f, 16 | 0x2f, 0x20, 0x48, 0x65, 0x72, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6d, 17 | 0x75, 0x73, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 18 | 0x66, 0x6f, 0x72, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x65, 0x76, 0x65, 19 | 0x6e, 0x74, 0x20, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x20, 20 | 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x2f, 0x2f, 0x20, 0x77, 0x61, 21 | 0x76, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x77, 22 | 0x68, 0x61, 0x74, 0x20, 0x22, 0x74, 0x65, 0x73, 0x74, 0x65, 0x72, 0x20, 23 | 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x20, 0x69, 0x74, 0x20, 0x73, 0x68, 24 | 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 25 | 0x73, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x0a, 0x2f, 0x2f, 0x0a, 0x2f, 0x2f, 26 | 0x20, 0x49, 0x66, 0x20, 0x61, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x20, 0x69, 27 | 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 28 | 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x64, 29 | 0x20, 0x77, 0x61, 0x76, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x28, 0x65, 30 | 0x76, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 31 | 0x65, 0x29, 0x0a, 0x2f, 0x2f, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, 32 | 0x6f, 0x72, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x64, 33 | 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 34 | 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 35 | 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x66, 0x61, 0x69, 36 | 0x6c, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x70, 37 | 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x44, 0x20, 0x2d, 0x3e, 0x20, 38 | 0x30, 0x2c, 0x20, 0x28, 0x4e, 0x52, 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 39 | 0x20, 0x30, 0x2c, 0x20, 0x44, 0x31, 0x20, 0x3d, 0x20, 0x45, 0x30, 0x2c, 40 | 0x20, 0x44, 0x32, 0x20, 0x3d, 0x20, 0x2d, 0x2c, 0x20, 0x44, 0x33, 0x20, 41 | 0x3d, 0x20, 0x31, 0x29, 0x2c, 0x20, 0x28, 0x52, 0x4c, 0x2c, 0x20, 0x44, 42 | 0x30, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x20, 0x44, 0x31, 0x20, 0x3d, 0x20, 43 | 0x45, 0x30, 0x2c, 0x20, 0x44, 0x32, 0x20, 0x3d, 0x20, 0x3f, 0x2c, 0x20, 44 | 0x44, 0x33, 0x20, 0x3d, 0x20, 0x31, 0x29, 0x2c, 0x20, 0x28, 0x52, 0x48, 45 | 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x20, 0x44, 0x31, 46 | 0x20, 0x3d, 0x20, 0x45, 0x30, 0x2c, 0x20, 0x44, 0x32, 0x20, 0x3d, 0x20, 47 | 0x31, 0x2c, 0x20, 0x44, 0x33, 0x20, 0x3d, 0x20, 0x31, 0x29, 0x2c, 0x20, 48 | 0x28, 0x53, 0x42, 0x4c, 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 0x20, 0x45, 49 | 0x30, 0x2c, 0x20, 0x44, 0x31, 0x20, 0x3d, 0x20, 0x3f, 0x2c, 0x20, 0x44, 50 | 0x32, 0x20, 0x3d, 0x20, 0x3f, 0x2c, 0x20, 0x44, 0x33, 0x20, 0x3d, 0x20, 51 | 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x55, 0x20, 0x2d, 0x3e, 0x20, 52 | 0x31, 0x2c, 0x20, 0x28, 0x4e, 0x52, 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 53 | 0x20, 0x30, 0x2c, 0x20, 0x44, 0x31, 0x20, 0x3d, 0x20, 0x45, 0x30, 0x2c, 54 | 0x20, 0x44, 0x32, 0x20, 0x3d, 0x20, 0x2d, 0x2c, 0x20, 0x44, 0x33, 0x20, 55 | 0x3d, 0x20, 0x31, 0x29, 0x2c, 0x20, 0x28, 0x52, 0x4c, 0x2c, 0x20, 0x44, 56 | 0x30, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x20, 0x44, 0x31, 0x20, 0x3d, 0x20, 57 | 0x45, 0x30, 0x2c, 0x20, 0x44, 0x32, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x20, 58 | 0x44, 0x33, 0x20, 0x3d, 0x20, 0x31, 0x29, 0x2c, 0x20, 0x28, 0x52, 0x48, 59 | 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x20, 0x44, 0x31, 60 | 0x20, 0x3d, 0x20, 0x45, 0x30, 0x2c, 0x20, 0x44, 0x32, 0x20, 0x3d, 0x20, 61 | 0x3f, 0x2c, 0x20, 0x44, 0x33, 0x20, 0x3d, 0x20, 0x31, 0x29, 0x2c, 0x20, 62 | 0x28, 0x53, 0x42, 0x48, 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 0x20, 0x45, 63 | 0x30, 0x2c, 0x20, 0x44, 0x31, 0x20, 0x3d, 0x20, 0x3f, 0x2c, 0x20, 0x44, 64 | 0x32, 0x20, 0x3d, 0x20, 0x3f, 0x2c, 0x20, 0x44, 0x33, 0x20, 0x3d, 0x20, 65 | 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5a, 0x20, 0x2d, 0x3e, 0x20, 66 | 0x58, 0x2c, 0x20, 0x28, 0x4f, 0x66, 0x66, 0x2c, 0x20, 0x52, 0x30, 0x20, 67 | 0x3d, 0x20, 0x3f, 0x29, 0x2c, 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 68 | 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x3f, 0x29, 0x0a, 0x20, 0x20, 0x20, 69 | 0x20, 0x48, 0x20, 0x2d, 0x3e, 0x20, 0x48, 0x2c, 0x20, 0x28, 0x45, 0x64, 70 | 0x67, 0x65, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x45, 0x30, 0x29, 71 | 0x0a, 0x20, 0x20, 0x20, 0x20, 0x4c, 0x20, 0x2d, 0x3e, 0x20, 0x4c, 0x2c, 72 | 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 73 | 0x20, 0x45, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x54, 0x20, 0x2d, 74 | 0x3e, 0x20, 0x4d, 0x2c, 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 0x20, 75 | 0x52, 0x30, 0x20, 0x3d, 0x20, 0x45, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20, 76 | 0x20, 0x58, 0x20, 0x2d, 0x3e, 0x20, 0x58, 0x2c, 0x20, 0x28, 0x4f, 0x66, 77 | 0x66, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x3f, 0x29, 0x2c, 0x20, 78 | 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 79 | 0x3f, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 80 | 0x58, 0x48, 0x20, 0x2d, 0x3e, 0x20, 0x48, 0x2c, 0x20, 0x28, 0x45, 0x64, 81 | 0x67, 0x65, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x45, 0x31, 0x29, 82 | 0x0a, 0x20, 0x20, 0x20, 0x20, 0x58, 0x4c, 0x20, 0x2d, 0x3e, 0x20, 0x4c, 83 | 0x2c, 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x52, 0x30, 0x20, 84 | 0x3d, 0x20, 0x45, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x58, 0x54, 85 | 0x20, 0x2d, 0x3e, 0x20, 0x4d, 0x2c, 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 86 | 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x45, 0x31, 0x29, 0x0a, 0x20, 87 | 0x20, 0x20, 0x20, 0x58, 0x58, 0x20, 0x2d, 0x3e, 0x20, 0x58, 0x2c, 0x20, 88 | 0x28, 0x4f, 0x66, 0x66, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x3f, 89 | 0x29, 0x2c, 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x52, 0x30, 90 | 0x20, 0x3d, 0x20, 0x3f, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5a, 91 | 0x48, 0x20, 0x2d, 0x3e, 0x20, 0x48, 0x2c, 0x20, 0x28, 0x45, 0x64, 0x67, 92 | 0x65, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x45, 0x31, 0x29, 0x0a, 93 | 0x20, 0x20, 0x20, 0x20, 0x5a, 0x4c, 0x20, 0x2d, 0x3e, 0x20, 0x4c, 0x2c, 94 | 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 95 | 0x20, 0x45, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5a, 0x54, 0x20, 96 | 0x2d, 0x3e, 0x20, 0x4d, 0x2c, 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 97 | 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x45, 0x31, 0x29, 0x0a, 0x20, 0x20, 98 | 0x20, 0x20, 0x5a, 0x58, 0x20, 0x2d, 0x3e, 0x20, 0x58, 0x2c, 0x20, 0x28, 99 | 0x4f, 0x66, 0x66, 0x2c, 0x20, 0x52, 0x30, 0x20, 0x3d, 0x20, 0x3f, 0x29, 100 | 0x2c, 0x20, 0x28, 0x45, 0x64, 0x67, 0x65, 0x2c, 0x20, 0x52, 0x30, 0x20, 101 | 0x3d, 0x20, 0x3f, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x44, 0x55, 102 | 0x44, 0x20, 0x2d, 0x3e, 0x20, 0x31, 0x2c, 0x20, 0x28, 0x53, 0x42, 0x4c, 103 | 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 0x20, 0x45, 0x30, 0x2c, 0x20, 0x44, 104 | 0x31, 0x20, 0x3d, 0x20, 0x45, 0x31, 0x2c, 0x20, 0x44, 0x32, 0x20, 0x3d, 105 | 0x20, 0x45, 0x32, 0x2c, 0x20, 0x44, 0x33, 0x20, 0x3d, 0x20, 0x31, 0x29, 106 | 0x2c, 0x20, 0x28, 0x53, 0x42, 0x43, 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 107 | 0x20, 0x45, 0x30, 0x2c, 0x20, 0x44, 0x31, 0x20, 0x3d, 0x20, 0x45, 0x31, 108 | 0x2c, 0x20, 0x44, 0x32, 0x20, 0x3d, 0x20, 0x45, 0x32, 0x2c, 0x20, 0x44, 109 | 0x33, 0x20, 0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x55, 110 | 0x44, 0x55, 0x20, 0x2d, 0x3e, 0x20, 0x30, 0x2c, 0x20, 0x28, 0x53, 0x42, 111 | 0x48, 0x2c, 0x20, 0x44, 0x30, 0x20, 0x3d, 0x20, 0x45, 0x30, 0x2c, 0x20, 112 | 0x44, 0x31, 0x20, 0x3d, 0x20, 0x45, 0x31, 0x2c, 0x20, 0x44, 0x32, 0x20, 113 | 0x3d, 0x20, 0x45, 0x32, 0x2c, 0x20, 0x44, 0x33, 0x20, 0x3d, 0x20, 0x31, 114 | 0x29, 0x2c, 0x20, 0x28, 0x53, 0x42, 0x43, 0x2c, 0x20, 0x44, 0x30, 0x20, 115 | 0x3d, 0x20, 0x45, 0x30, 0x2c, 0x20, 0x44, 0x31, 0x20, 0x3d, 0x20, 0x45, 116 | 0x31, 0x2c, 0x20, 0x44, 0x32, 0x20, 0x3d, 0x20, 0x45, 0x32, 0x2c, 0x20, 117 | 0x44, 0x33, 0x20, 0x3d, 0x20, 0x31, 0x29, 0x0a, 0x7d, 0x0a, 0x0a, 0x2f, 118 | 0x2f, 0x20, 0x48, 0x65, 0x72, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6d, 119 | 0x75, 0x73, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 120 | 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x27, 0x73, 121 | 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 122 | 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x0a, 0x2f, 123 | 0x2f, 0x20, 0x53, 0x54, 0x49, 0x4c, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 124 | 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 125 | 0x65, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x73, 0x69, 0x67, 126 | 0x6e, 0x61, 0x6c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x0a, 0x2f, 127 | 0x2f, 0x20, 0x42, 0x79, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 128 | 0x2c, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 129 | 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x64, 130 | 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 131 | 0x74, 0x70, 0x75, 0x74, 0x0a, 0x2f, 0x2f, 0x20, 0x77, 0x69, 0x6c, 0x6c, 132 | 0x20, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6d, 0x20, 0x6f, 133 | 0x66, 0x66, 0x2e, 0x0a, 0x2f, 0x2f, 0x0a, 0x2f, 0x2f, 0x20, 0x49, 0x66, 134 | 0x20, 0x61, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6e, 135 | 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x66, 136 | 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x20, 137 | 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 138 | 0x67, 0x6e, 0x61, 0x6c, 0x0a, 0x2f, 0x2f, 0x20, 0x77, 0x6f, 0x6e, 0x27, 139 | 0x74, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x69, 0x74, 0x73, 140 | 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x0a, 0x2f, 0x2f, 0x20, 0x49, 0x66, 141 | 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 142 | 0x64, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 143 | 0x72, 0x67, 0x65, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x73, 144 | 0x20, 0x76, 0x6f, 0x69, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 145 | 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x0a, 0x2f, 0x2f, 0x20, 0x77, 0x69, 0x6c, 146 | 0x6c, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 147 | 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 148 | 0x74, 0x70, 0x75, 0x74, 0x2e, 0x0a, 0x2f, 0x2f, 0x20, 0x54, 0x68, 0x65, 149 | 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x72, 0x75, 0x6c, 150 | 0x65, 0x20, 0x22, 0x5b, 0x5d, 0x20, 0x2d, 0x3e, 0x20, 0x5f, 0x22, 0x20, 151 | 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, 152 | 0x74, 0x68, 0x65, 0x20, 0x22, 0x5b, 0x58, 0x5d, 0x22, 0x20, 0x61, 0x6e, 153 | 0x64, 0x20, 0x70, 0x75, 0x74, 0x0a, 0x2f, 0x2f, 0x20, 0x61, 0x20, 0x22, 154 | 0x5f, 0x58, 0x22, 0x20, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 155 | 0x69, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x69, 0x73, 156 | 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 157 | 0x20, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x20, 0x49, 0x27, 158 | 0x76, 0x65, 0x20, 0x73, 0x65, 0x65, 0x6e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 159 | 0x6e, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x6d, 0x61, 0x70, 160 | 0x20, 0x7b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x6e, 0x75, 161 | 0x73, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x22, 0x20, 162 | 0x2d, 0x3e, 0x20, 0x22, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x53, 163 | 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x22, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 164 | 0x22, 0x47, 0x43, 0x46, 0x47, 0x5b, 0x33, 0x5d, 0x22, 0x20, 0x2d, 0x3e, 165 | 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x47, 0x43, 0x46, 0x47, 0x5b, 0x34, 166 | 0x5d, 0x22, 0x20, 0x2d, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x47, 167 | 0x43, 0x46, 0x47, 0x5b, 0x35, 0x5d, 0x22, 0x20, 0x2d, 0x3e, 0x0a, 0x20, 168 | 0x20, 0x20, 0x20, 0x22, 0x47, 0x43, 0x46, 0x47, 0x5b, 0x36, 0x5d, 0x22, 169 | 0x20, 0x2d, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x20, 170 | 0x2d, 0x3e, 0x20, 0x5f, 0x0a, 0x7d, 0x0a, 0x0a, 0x2f, 0x2f, 0x20, 0x48, 171 | 0x65, 0x72, 0x65, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x73, 0x70, 0x65, 0x63, 172 | 0x69, 0x66, 0x79, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x65, 0x73, 173 | 0x74, 0x65, 0x72, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x75, 174 | 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x66, 175 | 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x61, 0x6e, 0x0a, 176 | 0x2f, 0x2f, 0x20, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x70, 0x61, 177 | 0x64, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 178 | 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 179 | 0x65, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x20, 0x61, 180 | 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x6e, 181 | 0x69, 0x6e, 0x67, 0x0a, 0x2f, 0x2f, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 182 | 0x65, 0x20, 0x73, 0x63, 0x61, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x69, 183 | 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 184 | 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x69, 0x73, 0x20, 0x6c, 0x65, 185 | 0x73, 0x73, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 186 | 0x6d, 0x61, 0x78, 0x2e, 0x0a, 0x2f, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 187 | 0x73, 0x61, 0x6d, 0x65, 0x20, 0x67, 0x6f, 0x65, 0x73, 0x20, 0x66, 0x6f, 188 | 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x61, 0x6e, 0x20, 0x6f, 189 | 0x75, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x73, 0x2c, 0x20, 190 | 0x62, 0x75, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6e, 191 | 0x67, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x2f, 0x2f, 0x20, 192 | 0x65, 0x6e, 0x64, 0x2e, 0x0a, 0x2f, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x79, 193 | 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x77, 0x66, 0x63, 194 | 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 195 | 0x6c, 0x61, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 196 | 0x61, 0x72, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 197 | 0x76, 0x65, 0x0a, 0x2f, 0x2f, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 198 | 0x2e, 0x20, 0x28, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x20, 0x73, 0x65, 0x6e, 199 | 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x29, 0x0a, 0x0a, 0x73, 0x63, 0x61, 200 | 0x6e, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x7b, 0x0a, 201 | 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x61, 0x6e, 0x5f, 0x69, 0x6e, 0x20, 202 | 0x2d, 0x3e, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x61, 203 | 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x20, 0x2d, 0x3e, 0x20, 0x58, 0x0a, 0x7d, 204 | 0x0a, 0x0a, 0x2f, 0x2f, 0x20, 0x48, 0x65, 0x72, 0x65, 0x20, 0x79, 0x6f, 205 | 0x75, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x66, 0x6f, 206 | 0x72, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 207 | 0x64, 0x64, 0x71, 0x54, 0x65, 0x73, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 208 | 0x20, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 209 | 0x0a, 0x2f, 0x2f, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 210 | 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x20, 0x69, 211 | 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 212 | 0x6e, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x0a, 0x2f, 0x2f, 0x20, 0x54, 213 | 0x68, 0x69, 0x73, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6c, 0x69, 0x6e, 214 | 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x75, 0x73, 215 | 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 216 | 0x68, 0x65, 0x20, 0x27, 0x7d, 0x27, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 217 | 0x63, 0x74, 0x65, 0x72, 0x0a, 0x0a, 0x69, 0x64, 0x64, 0x71, 0x5f, 0x61, 218 | 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x63, 0x61, 0x6c, 0x6c, 219 | 0x5f, 0x69, 0x64, 0x64, 0x71, 0x3b, 0x0a, 0x7d, 0x0a 220 | }; 221 | unsigned int grammar_stil_config_len = 2613; 222 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/PatternContext.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 07/08/2017. 3 | // 4 | 5 | #include "PatternContext.h" 6 | #include "../../stil/definitions/STILProgram.h" 7 | 8 | PatternContext::PatternContext() { 9 | proceds_id = GLOBAL_DEF; 10 | macros_id = GLOBAL_DEF; 11 | } 12 | 13 | PatternContext::PatternContext(string proceds_id, string macros_id) { 14 | this->proceds_id = proceds_id; 15 | this->macros_id = macros_id; 16 | } 17 | 18 | PatternContext PatternContext::merge(PatternContext context) { 19 | PatternContext result = *this; 20 | if(context.proceds_id != GLOBAL_DEF) { 21 | result.proceds_id = context.proceds_id; 22 | } 23 | if(context.macros_id != GLOBAL_DEF) { 24 | result.macros_id = context.macros_id; 25 | } 26 | return result; 27 | } 28 | 29 | void ContextStack::push(const PatternContext& context) { 30 | if(!empty()) { 31 | stack::push(top().merge(context)); 32 | } else { 33 | stack::push(context); 34 | } 35 | } 36 | 37 | void ContextStack::push(PatternContext&& context) { 38 | PatternContext aux = context; 39 | push(aux); 40 | } 41 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/PatternContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 07/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_PATTERNCONTEXT_H 6 | #define STIL_INTERPRETER_PATTERNCONTEXT_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | class PatternContext { 14 | 15 | public: 16 | 17 | string proceds_id; 18 | string macros_id; 19 | 20 | PatternContext(); 21 | 22 | PatternContext(string proceds_id, string macros_id); 23 | 24 | PatternContext merge(PatternContext context); 25 | }; 26 | 27 | class ContextStack : public stack { 28 | 29 | public: 30 | 31 | void push(const PatternContext& context); 32 | 33 | void push(PatternContext&& context); 34 | }; 35 | 36 | #endif //STIL_INTERPRETER_PATTERNCONTEXT_H 37 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/TimeSet.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/09/2017. 3 | // 4 | 5 | #include 6 | #include "TimeSet.h" 7 | 8 | TimeSet::TimeSet(float period) { 9 | this->period = period; 10 | } 11 | 12 | void TimeSet::add_waveset(const WaveSet& waveset) { 13 | assert(waveset.type != WaveSet::WaveSetType::UNDEFINED); 14 | if(waveset.type == WaveSet::WaveSetType::DRIVE) { 15 | wavesets.push_back(pair(waveset, WaveSet())); 16 | } else { 17 | wavesets.push_back(pair(WaveSet(), waveset)); 18 | } 19 | } 20 | 21 | bool TimeSet::merge(const TimeSet& timeset) { 22 | if(period != timeset.period) { 23 | return false; 24 | } 25 | TimeSet merged_timeset(period); 26 | for(int i = 0; i < timeset.wavesets.size(); ++i) { 27 | merged_timeset.id = this->id; 28 | WaveSet merged_waveset; 29 | if(timeset.wavesets[i].first.type != WaveSet::WaveSetType::UNDEFINED) { 30 | assert(timeset.wavesets[i].first.type == WaveSet::WaveSetType::DRIVE); 31 | merged_waveset = wavesets[i].first.merge(timeset.wavesets[i].first); 32 | merged_timeset.wavesets.push_back(pair(merged_waveset, wavesets[i].second)); 33 | } else { 34 | assert(timeset.wavesets[i].second.type == WaveSet::WaveSetType::COMPARE); 35 | merged_waveset = wavesets[i].second.merge(timeset.wavesets[i].second); 36 | merged_timeset.wavesets.push_back(pair(wavesets[i].first, merged_waveset)); 37 | } 38 | if(merged_waveset.descriptions.size() == 0) { 39 | return false; 40 | } 41 | } 42 | (*this) = merged_timeset; 43 | return true; 44 | } 45 | 46 | #define MARGIN 15 47 | #define FORMAT(level) s += string(level*MARGIN - s.size(), ' '); 48 | 49 | string TimeSet::to_string(vector signal_names) const { 50 | string output; 51 | for(int i = 0; i < wavesets.size(); ++i) { 52 | 53 | const WaveSet& waveset_drive = wavesets[i].first; 54 | const WaveSet& waveset_compare = wavesets[i].second; 55 | 56 | string s; 57 | s += "t" + std::to_string(id); // TimeSet 58 | FORMAT(1) 59 | s += std::to_string(period); // Period 60 | FORMAT(2) 61 | s += "1"; // CPP 62 | FORMAT(3) 63 | s += signal_names[i]; // Pin Name 64 | FORMAT(4) 65 | s += "i/0"; // Setup 66 | FORMAT(5) 67 | s += "PAT"; // Data Source 68 | FORMAT(6) 69 | s += waveset_drive.get_format(); // Data Format 70 | FORMAT(7) 71 | s += waveset_drive.get_drive_on(); // Drive On 72 | FORMAT(8) 73 | s += waveset_drive.get_drive_data(); // Drive Data 74 | FORMAT(9) 75 | s += waveset_drive.get_drive_return(); // Drive Return 76 | FORMAT(10) 77 | s += waveset_drive.get_drive_off(); // Drive Off 78 | FORMAT(11) 79 | s += waveset_compare.get_compare_mode();// Compare Mode 80 | FORMAT(12) 81 | s += waveset_compare.get_compare_open();// Compare Open 82 | FORMAT(13) 83 | s += "Disable"; // Compare Close 84 | s += "\n"; 85 | 86 | output += s; 87 | } 88 | return output; 89 | } 90 | 91 | void TimeSet::reduce() { 92 | for(int i = 0; i < wavesets.size(); ++i) { 93 | wavesets[i].first.reduce(); 94 | wavesets[i].second.reduce(); 95 | } 96 | } 97 | 98 | bool TimeSet::operator==(const TimeSet& other) const { 99 | return period == other.period && wavesets == other.wavesets; 100 | } -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/TimeSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 03/09/2017. 3 | // 4 | 5 | #ifndef STIL_CONVERTER_TIMESET_H 6 | #define STIL_CONVERTER_TIMESET_H 7 | 8 | #include 9 | #include "WaveSet.h" 10 | 11 | using namespace std; 12 | 13 | // This class represents a full Teradyne timeset: A WaveSet describing how the signal's waveform should be for each signal. 14 | // The WaveSets will be reduced to an arbitrary chosen representative whenever the timeset generation finishes and there are multiple options 15 | // in one signal's cell. 16 | 17 | class TimeSet { 18 | 19 | public: 20 | 21 | int id; 22 | float period; 23 | vector> wavesets; 24 | 25 | TimeSet() {} 26 | 27 | TimeSet(float period); 28 | 29 | void add_waveset(const WaveSet& waveset); 30 | 31 | bool merge(const TimeSet& timeset); 32 | 33 | void reduce(); 34 | 35 | string to_string(vector signal_names) const; 36 | 37 | bool operator==(const TimeSet& other) const; 38 | }; 39 | 40 | 41 | #endif //STIL_CONVERTER_TIMESET_H 42 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/TimeSetHasher.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 15/09/2017. 3 | // 4 | 5 | #include "TimeSetHasher.h" 6 | 7 | size_t TimeSetHasher::operator()(const TimeSet& timeset) const { 8 | // return hash()(timeset.to_string()); // Very bad results (this was just for debug) 9 | size_t hash_value = hash()(timeset.period); 10 | for(int i = 0; i < timeset.wavesets.size(); ++i) { 11 | combine_hash(hash_value, TimeSetHasher()(timeset.wavesets[i].first)); 12 | combine_hash(hash_value, TimeSetHasher()(timeset.wavesets[i].second)); 13 | } 14 | return hash_value; 15 | } 16 | 17 | size_t TimeSetHasher::operator()(const WaveSet& waveset) const { 18 | size_t hash_value = hash()(waveset.type); 19 | for(auto it = waveset.descriptions.begin(); it != waveset.descriptions.end(); ++it) { 20 | combine_hash(hash_value, TimeSetHasher()(*it)); 21 | } 22 | return hash_value; 23 | } 24 | 25 | size_t TimeSetHasher::operator()(const WaveDescription& description) const { 26 | size_t hash_value = hash()(description.format); 27 | for(int i = 0; i < description.edges.size(); ++i) { 28 | combine_hash(hash_value, hash()(description.edges[i])); 29 | } 30 | return hash_value; 31 | } 32 | 33 | void TimeSetHasher::combine_hash(size_t& hash, size_t next_hash) const { 34 | // prev ^= (next << 1); // Doesn't perform good 35 | // prev = prev >> 1; 36 | hash ^= next_hash + 0x9e3779b9 + (hash<<6) + (hash>>2); // From https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x 37 | } -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/TimeSetHasher.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 15/09/2017. 3 | // 4 | 5 | #ifndef STIL_CONVERTER_TIMESETHASHER_H 6 | #define STIL_CONVERTER_TIMESETHASHER_H 7 | 8 | 9 | #include "TimeSet.h" 10 | 11 | using namespace std; 12 | 13 | class TimeSetHasher { 14 | 15 | private: 16 | void combine_hash(size_t& hash, size_t next_hash) const; 17 | 18 | public: 19 | size_t operator()(const TimeSet& timeset) const; 20 | 21 | size_t operator()(const WaveSet& waveset) const; 22 | 23 | size_t operator()(const WaveDescription& description) const; 24 | }; 25 | 26 | 27 | #endif //STIL_CONVERTER_TIMESETHASHER_H 28 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/WaveDescription.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/09/2017. 3 | // 4 | 5 | #include "WaveDescription.h" 6 | 7 | WaveDescription::WaveDescription(float period, WaveForm& waveform, WaveTranslation& translation) { 8 | format = translation.format; 9 | for(int i = 0; i < translation.edge_rules.size(); ++i) { 10 | WaveTranslation::EdgeRule rule = translation.edge_rules[i]; 11 | if(rule.first) { // It's relative time 12 | edges.push_back(period * rule.second); 13 | } else { 14 | if(rule.second < 0) { 15 | edges.push_back(rule.second); 16 | } else { 17 | edges.push_back(waveform.events[rule.second].time); 18 | } 19 | } 20 | } 21 | } 22 | 23 | pair WaveDescription::merge(const WaveDescription& description) const { 24 | pair merged(false, WaveDescription()); 25 | if(format != description.format) { 26 | return merged; 27 | } 28 | merged.second.format = format; 29 | for(int i = 0; i < edges.size(); ++i) { 30 | const float& a = edges[i]; 31 | const float& b = description.edges[i]; 32 | if(a == b) { 33 | merged.second.edges.push_back(a); 34 | } else { 35 | if(a == DISABLE || b == DISABLE) { 36 | return merged; 37 | } 38 | if(a == ANY) { 39 | merged.second.edges.push_back(b); 40 | } else if(b == ANY) { 41 | merged.second.edges.push_back(a); 42 | } else { 43 | return merged; 44 | } 45 | } 46 | } 47 | merged.first = true; 48 | return merged; 49 | } 50 | 51 | string WaveDescription::to_string() const { 52 | string s; 53 | s += "["; 54 | s += std::to_string(format); 55 | s += ": "; 56 | for(int i = 0; i < edges.size(); ++i) { 57 | if(i != 0) { 58 | s += ", "; 59 | } 60 | if(edges[i] == DISABLE) { 61 | s += " - "; 62 | } else { 63 | s += std::to_string(edges[i]); 64 | } 65 | } 66 | s += "]"; 67 | return s; 68 | } 69 | 70 | string WaveDescription::get_format() const { 71 | if(format == NR) { 72 | return "NR"; 73 | } else if(format == RH) { 74 | return "RH"; 75 | } else if(format == RL) { 76 | return "RL"; 77 | } else if(format == SBH) { 78 | return "SBH"; 79 | } else if(format == SBL) { 80 | return "SBL"; 81 | } else if(format == SBC) { 82 | return "SBC"; 83 | } else if(format == Off) { 84 | return "Off"; 85 | } else if(format == Edge) { 86 | return "Edge"; 87 | } else { 88 | return ""; 89 | } 90 | } 91 | 92 | void WaveDescription::reduce() { 93 | for(int i = 0; i < edges.size(); ++i) { 94 | if(edges[i] == ANY) { 95 | edges[i] = i > 0 ? edges[i-1] : 0; 96 | } 97 | } 98 | } 99 | 100 | bool WaveDescription::operator==(const WaveDescription& other) const { 101 | return format == other.format && edges == other.edges; 102 | } 103 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/WaveDescription.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/09/2017. 3 | // 4 | 5 | #ifndef STIL_CONVERTER_WAVEDESCRIPTION_H 6 | #define STIL_CONVERTER_WAVEDESCRIPTION_H 7 | 8 | #include 9 | #include 10 | #include "WaveForm.h" 11 | 12 | using namespace std; 13 | 14 | // A WaveDescription is an specific possible description of a waveform. It's important to note that a single WaveDescription could 15 | // refer to multiple ways of representing that specific waveform if an edge's time is not specified. 16 | 17 | class WaveDescription { 18 | 19 | public: 20 | WaveFormat format; 21 | vector edges; 22 | 23 | WaveDescription() {} 24 | 25 | WaveDescription(float period, WaveForm& waveform, WaveTranslation& rule); 26 | 27 | pair merge(const WaveDescription& description) const; 28 | 29 | void reduce(); 30 | 31 | string to_string() const; 32 | 33 | string get_format() const; 34 | 35 | bool operator==(const WaveDescription& other) const; 36 | }; 37 | 38 | 39 | #endif //STIL_CONVERTER_WAVEDESCRIPTION_H 40 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/WaveForm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 06/08/2017. 3 | // 4 | 5 | #include "WaveForm.h" 6 | 7 | WaveForm::WaveForm(string id, char wfc, vector& events) : Identifiable(id) { 8 | this->wfc = wfc; 9 | this->events = events; 10 | } 11 | 12 | string WaveForm::event_seq() { 13 | string event_seq(events.size(), ' '); 14 | for(int i = 0; i < events.size(); ++i) { 15 | event_seq[i] = events[i].event_code; 16 | } 17 | return event_seq; 18 | } 19 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/WaveForm.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 06/08/2017. 3 | // 4 | 5 | #ifndef STIL_INTERPRETER_WAVEFORM_H 6 | #define STIL_INTERPRETER_WAVEFORM_H 7 | 8 | #include 9 | #include 10 | #include "../../stil/definitions/Identifiable.h" 11 | 12 | using namespace std; 13 | 14 | 15 | // This class represents the waveform that needs to be generated for a specific 16 | // pin as the STIL file defines it in the active waveform table. 17 | // WaveSet will create as many "translations" of this waveform as possible following 18 | // all the different "translation rules" defined in the config file that specify 19 | // how this kind of waveform can be translated into WaveDescriptions. 20 | 21 | class WaveForm : public Identifiable { 22 | 23 | public: 24 | 25 | struct WaveFormEvent { 26 | 27 | enum Event { 28 | ForceDown, ForceUp, ForceOff, CompareLow, CompareHigh, 29 | CompareUnknown, CompareOff, ForceUnknown 30 | }; 31 | 32 | float time; 33 | Event event; 34 | char event_code; 35 | 36 | WaveFormEvent() {} 37 | 38 | WaveFormEvent(float time, char event_code) { 39 | this->time = time; 40 | this->event_code = event_code; 41 | switch(event_code) { 42 | case 'D': event = ForceDown; break; 43 | case 'U': event = ForceUp; break; 44 | case 'Z': event = ForceOff; break; 45 | case 'L': event = CompareLow; break; 46 | case 'H': event = CompareHigh; break; 47 | case 'X': event = CompareUnknown; break; 48 | case 'T': event = CompareOff; break; 49 | case 'N': event = ForceUnknown; break; 50 | default: cerr << "Unrecognized event: " << event_code << endl; exit(1); 51 | } 52 | } 53 | }; 54 | 55 | typedef vector EventSeq; 56 | 57 | char wfc; 58 | EventSeq events; 59 | 60 | WaveForm() : Identifiable() {} 61 | 62 | WaveForm(string id, char wfc, vector& events); 63 | 64 | string event_seq(); 65 | 66 | }; 67 | 68 | 69 | #endif //STIL_INTERPRETER_WAVEFORM_H 70 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/WaveSet.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/09/2017. 3 | // 4 | 5 | #include 6 | #include "WaveSet.h" 7 | 8 | WaveSet::WaveSet() { 9 | type = UNDEFINED; 10 | } 11 | 12 | WaveSet::WaveSet(WaveSetType type) { 13 | this->type = type; 14 | } 15 | 16 | WaveSet::WaveSet(float period, WaveForm& waveform, list& translation_rules) { 17 | type = UNDEFINED; 18 | for(auto rule = translation_rules.begin(); rule != translation_rules.end(); ++rule) { 19 | descriptions.push_back(WaveDescription(period, waveform, *rule)); 20 | WaveSetType last_type = descriptions.back().format == Edge || descriptions.back().format == Off ? COMPARE : DRIVE; 21 | if(type == UNDEFINED) { 22 | type = last_type; 23 | } else { 24 | assert(type == last_type); 25 | } 26 | } 27 | } 28 | 29 | WaveSet WaveSet::merge(const WaveSet& waveset) const { 30 | if(type == UNDEFINED) { 31 | return waveset; 32 | } else if(waveset.type == UNDEFINED) { 33 | return *this; 34 | } 35 | assert(type == waveset.type); 36 | WaveSet merged(type); 37 | for(auto i = descriptions.begin(); i != descriptions.end(); ++i) { 38 | for(auto j = waveset.descriptions.begin(); j != waveset.descriptions.end(); ++j) { 39 | pair merge_result = i->merge(*j); 40 | if(merge_result.first) { 41 | merged.descriptions.push_back(merge_result.second); 42 | } 43 | } 44 | } 45 | return merged; 46 | } 47 | 48 | string WaveSet::to_string() const { 49 | string s; 50 | s += "("; 51 | for(auto it = descriptions.begin(); it != descriptions.end(); ++it) { 52 | if(it != descriptions.begin()) { 53 | s += ", "; 54 | } 55 | s += it->to_string(); 56 | } 57 | s += ")"; 58 | return s; 59 | } 60 | 61 | string WaveSet::get_format() const { 62 | if(type == UNDEFINED) { // This pin in this timeset doesn't have this type (data or compare) of waveform 63 | return "_"; 64 | } 65 | assert(descriptions.size() == 1); 66 | return descriptions.front().get_format(); 67 | } 68 | 69 | string WaveSet::get_drive_on() const { 70 | return get_edge(0); 71 | } 72 | 73 | string WaveSet::get_drive_data() const { 74 | return get_edge(1); 75 | } 76 | 77 | string WaveSet::get_drive_return() const { 78 | return get_edge(2); 79 | } 80 | 81 | string WaveSet::get_drive_off() const { 82 | return get_edge(3); 83 | } 84 | 85 | string WaveSet::get_compare_mode() const { 86 | return get_format(); 87 | } 88 | 89 | string WaveSet::get_compare_open() const { 90 | return get_edge(0); 91 | } 92 | 93 | string WaveSet::get_edge(int i) const { 94 | if(type == UNDEFINED){ 95 | return "_"; 96 | } 97 | float time = descriptions.front().edges[i]; 98 | if(time == -1) { 99 | return "Disable"; 100 | } else { 101 | return std::to_string(time); 102 | } 103 | } 104 | 105 | void WaveSet::reduce() { 106 | assert(type == UNDEFINED || descriptions.size() > 0); 107 | if(type != UNDEFINED) { 108 | descriptions.erase(++descriptions.begin(), descriptions.end()); 109 | descriptions.front().reduce(); 110 | } 111 | } 112 | 113 | bool WaveSet::operator==(const WaveSet& other) const { 114 | return type == other.type && descriptions == other.descriptions; 115 | } 116 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/WaveSet.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 04/09/2017. 3 | // 4 | 5 | #ifndef STIL_CONVERTER_WAVESET_H 6 | #define STIL_CONVERTER_WAVESET_H 7 | 8 | // The set of possible representations for a signal's waveform. 9 | // Here there are stored these options through WaveDescriptions. 10 | 11 | #include 12 | #include "WaveDescription.h" 13 | #include "WaveForm.h" 14 | #include "WaveTranslation.h" 15 | 16 | 17 | class WaveSet { 18 | 19 | private: 20 | 21 | string get_edge(int i) const; 22 | 23 | public: 24 | 25 | enum WaveSetType { 26 | DRIVE, COMPARE, UNDEFINED 27 | }; 28 | 29 | WaveSetType type; 30 | list descriptions; 31 | 32 | WaveSet(); 33 | 34 | WaveSet(WaveSetType type); 35 | 36 | WaveSet(float period, WaveForm& waveform, list& translation_rules); 37 | 38 | WaveSet merge(const WaveSet& waveset) const; 39 | 40 | void reduce(); 41 | 42 | string to_string() const; 43 | 44 | string get_format() const; 45 | 46 | string get_drive_on() const; 47 | 48 | string get_drive_data() const; 49 | 50 | string get_drive_return() const; 51 | 52 | string get_drive_off() const; 53 | 54 | string get_compare_mode() const; 55 | 56 | string get_compare_open() const; 57 | 58 | bool operator==(const WaveSet& waveset) const; 59 | }; 60 | 61 | 62 | #endif //STIL_CONVERTER_WAVESET_H 63 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/WaveTranslation.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 07/09/2017. 3 | // 4 | 5 | #include 6 | #include 7 | #include "WaveTranslation.h" 8 | 9 | WaveTranslation::WaveTranslation(string rule) { 10 | istringstream iss(rule); 11 | string s; 12 | getline(iss, s, ','); 13 | if(s == "NR") { 14 | format = NR; 15 | } else if(s == "RH") { 16 | format = RH; 17 | } else if(s == "RL") { 18 | format = RL; 19 | } else if(s == "SBH") { 20 | format = SBH; 21 | } else if(s == "SBL") { 22 | format = SBL; 23 | } else if(s == "SBC") { 24 | format = SBC; 25 | } else if(s == "Off") { 26 | format = Off; 27 | } else if(s == "Edge") { 28 | format = Edge; 29 | } else { 30 | cerr << "Error parsing: " << rule << " from config file" << endl; 31 | exit(1); 32 | } 33 | while(iss >> s) { // Edge number 34 | iss >> s; // Equal symbol 35 | getline(iss, s, ','); // Time value 36 | s.erase(0, 1); 37 | if(s == "?") { 38 | edge_rules.push_back(EdgeRule(false, ANY)); 39 | } else if(s == "-") { 40 | edge_rules.push_back(EdgeRule(false, DISABLE)); 41 | } else { 42 | if(s[0] == 'E') { // It's a reference for the original waveform's edge 43 | int index = atoi(s.substr(1).c_str()); 44 | edge_rules.push_back(EdgeRule(false, index)); 45 | } else { 46 | float relative_time = atof(s.c_str()); 47 | edge_rules.push_back(EdgeRule(true, relative_time)); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/interpreter/teradyne/definitions/WaveTranslation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 07/09/2017. 3 | // 4 | 5 | #ifndef STIL_CONVERTER_WAVETRANSLATION_H 6 | #define STIL_CONVERTER_WAVETRANSLATION_H 7 | 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | #define DISABLE -1 14 | #define ANY -2 15 | 16 | enum WaveFormat { 17 | NR, RH, RL, SBH, SBL, SBC, Off, Edge 18 | }; 19 | 20 | class WaveTranslation { 21 | 22 | public: 23 | 24 | typedef pair EdgeRule; 25 | 26 | WaveFormat format; 27 | vector edge_rules; 28 | 29 | WaveTranslation(string rule); 30 | }; 31 | 32 | 33 | #endif //STIL_CONVERTER_WAVETRANSLATION_H 34 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "interpreter/STILInterpreter.h" 5 | #include "interpreter/teradyne/STILConfig.h" 6 | 7 | using namespace parser; 8 | using namespace antlr4; 9 | using namespace std; 10 | 11 | string get_file_name(string file) { 12 | int i = file.size() - 1; 13 | while(i >= 0 && file[i] != '.') { 14 | --i; 15 | } 16 | int j = i; 17 | while(j >= 0 && file[j] != '/') { 18 | --j; 19 | } 20 | return file.substr(j+1, i-j-1); 21 | } 22 | 23 | int main(int num_args, char* args[]) { 24 | 25 | if(num_args < 2 || num_args > 7) { 26 | cerr << "Incorrect number of parameters." << endl; 27 | cout << "Usage: stil_converter input_file.stil [-v] [-c config_file.config] [-p pattern_exec_name]" << endl; 28 | cout << "Output: $input_file.atp $input_file.txt" << endl; 29 | exit(1); 30 | } 31 | 32 | string file_name = get_file_name(string(args[1])); 33 | 34 | STILConfig config; 35 | string pattern_exec; 36 | 37 | bool verbose = false; 38 | for(int i = 2; i < num_args; ++i) { 39 | string arg(args[i]); 40 | if(arg == "-c") { 41 | config = STILConfig(args[i+1]); 42 | ++i; 43 | } else if(arg == "-p") { 44 | pattern_exec = args[i+1]; 45 | ++i; 46 | } else if(arg == "-v") { 47 | verbose = true; 48 | } 49 | } 50 | 51 | if(!verbose) { 52 | cout.setstate(ios_base::failbit); 53 | } 54 | 55 | STILInterpreter interpreter(args[1], "./" + file_name + ".atp", "./" + file_name + ".txt", config); 56 | 57 | if(pattern_exec == "") { 58 | interpreter.run(); 59 | } else { 60 | interpreter.run("\"" + pattern_exec + "\""); 61 | } 62 | 63 | return 0; 64 | } -------------------------------------------------------------------------------- /src/parser/STILFilePreprocessor.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 15/08/2017. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "STILFilePreprocessor.h" 9 | 10 | // The arbitrary structure of a user_keyword block makes impossible 11 | // (or really difficult) the parsing of the stil file. 12 | // This workaround consists on a pre-processor of the input file 13 | // to remove the definitions of the user_keywords by filtering the 14 | // input file into a temporal one. 15 | void STILFilePreprocessor::preprocess(string file_path) { 16 | 17 | ifstream original; 18 | ofstream processed; 19 | 20 | original.open(file_path); 21 | if(!original.good()) { 22 | cerr << "Input stil file not found!" << endl; 23 | exit(1); 24 | } 25 | processed.open(file_path + ".tmp"); 26 | 27 | //------------------------------------------- 28 | 29 | cout << "Pre-processing input file (removing user keywords)" << endl; 30 | unordered_set keywords; 31 | string line; 32 | while(!original.eof()) { 33 | getline(original, line); 34 | istringstream iss(line); 35 | string s; 36 | iss >> s; 37 | if(s == "UserKeywords") { 38 | while(iss >> s) { 39 | if(s.back() == ';') { 40 | s.pop_back(); 41 | } 42 | if(s.size() > 0) { 43 | keywords.insert(s); 44 | } 45 | } 46 | } else if(keywords.count(s) != 0) { 47 | if(line.back() == '{') { // It's a definition, not a use 48 | cout << "Removing user keyword definition: " << s << endl; 49 | int open_brackets = 1; 50 | while(open_brackets > 0) { 51 | char c; 52 | original >> c; 53 | if(c == '{') { 54 | ++open_brackets; 55 | } else if(c == '}') { 56 | --open_brackets; 57 | } 58 | } 59 | } 60 | } else { 61 | processed << line << endl; 62 | } 63 | } 64 | 65 | original.close(); 66 | processed.close(); 67 | } 68 | -------------------------------------------------------------------------------- /src/parser/STILFilePreprocessor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Gonzalo Solera on 15/08/2017. 3 | // 4 | 5 | #ifndef STIL_CONVERTER_STILFILEPREPROCESSOR_H 6 | #define STIL_CONVERTER_STILFILEPREPROCESSOR_H 7 | 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | class STILFilePreprocessor { 13 | 14 | public: 15 | void static preprocess(string file_path); 16 | }; 17 | 18 | 19 | #endif //STIL_CONVERTER_STILFILEPREPROCESSOR_H 20 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | input_files 2 | output_files 3 | test_logs 4 | test_output_files -------------------------------------------------------------------------------- /test/test_driver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import subprocess 4 | import datetime 5 | 6 | from os import listdir 7 | 8 | def test(file): 9 | 10 | name = file.rsplit('.', 1)[0] 11 | time = datetime.datetime.now().strftime("_%m_%d_%H_%M") 12 | 13 | print("Executing test", name) 14 | 15 | with open("test_logs/" + name + time + ".txt", 'w+') as logs_file: 16 | process = subprocess.Popen([exec_path, "../input_files/" + file, "-v"], stdout = logs_file, stderr = logs_file, cwd = "test_output_files") 17 | exit_code = process.wait() 18 | 19 | if exit_code != 0: 20 | print("Program crashed") 21 | return False 22 | 23 | return True 24 | # diff = subprocess.call(["diff", "output_files/" + name + ".atp", "test_output_files/" + name + ".atp"]) 25 | # return diff == 0 26 | 27 | 28 | def main(): 29 | 30 | global exec_path 31 | exec_path = sys.argv[1] 32 | 33 | if len(sys.argv) == 3: 34 | input_files = [sys.argv[2]] 35 | else: 36 | input_files = [f for f in listdir("input_files")] 37 | 38 | for f in input_files: 39 | if not test(f): 40 | sys.exit(1) 41 | 42 | print("Test successful") 43 | 44 | if __name__ == "__main__": 45 | main() --------------------------------------------------------------------------------