-- -- Copyright 1989 by --- -- -- This code is distributed for the purposes of evaluating the -- Waveform And Vector Exchange Specification (WAVES) proposal -- presented to the IEEE by the WAVES Analysis Group. This code -- may not be used for commercial purposes and may not be -- redistributed without permission of the Chairman of the WAVES -- Analysis Group, Mr Robert Hillman. -- -- Address comments or questions to -- Robert Hillman Lee Shombert -- RADC/RBRP Harris Corporation -- Griffis AFB, NY PO Box 94000 MS 16/4010 -- (315) 330-2241 Melbourne, FL 32902 -- (407) 727-6040 -- -- -- -- TIMESTAMP: 13-DEC-1989 12:51:53.65 -- -- CHANGES: -- 11 DEC 89 L SHOMBERT -- Fixed indexing bugs in APPLY_SLICE and -- ADD_FRAME_SET_ARRAY. Fixed bug in READ_WAVE_SLICE. -- -- 11 DEC 89 L SHOMBERT -- Replaced single NEW_TIME_DATA function having a -- defaulted PERIOD_TOLERANCE with two overloaded -- functions, one without a PERIOD_TOLERANCE and one with a -- mandatory (no default) PERIOD_TOLERANCE. There is no -- effect on WAVES datasets but this fixes a possible bug -- in the MCC simulator. -- -- 21 FEB 90 A WILMOT -- The declarations for INDEX, FRAME_EVENT and -- FRAME_ELIST were moved from this package from the -- WAVES_INTERFACE package. This reflects current usage in -- the examples and boilerplates, where frames and frame_sets -- are defined without reference to WAVES_OBJECTS (and its -- dependence on the TEST_PINS declaration). -- The mode of the CONNECT parameter to APPLY_SLICE and -- APPLY_LIST was changed from inout to out. -- The parameter to the MATCH functions was changed to be -- of type WAVES_MATCH_LIST and of mode in; the bodies -- were changed to reflect the new representation of parameter -- The record type FILE_INPUT_DATA was renamed FILE_SLICE -- and the procedure READ_WAVE_SLICE renamed READ_FILE_SLICE -- to reflect the LRM wording. -- The mode of the WAVES_PORT_LIST parameters to the TAG -- procedures was changed from inout to out. (The meaining -- of these functions is unclear at the present.) -- 18-APR-1989 Corrected improper assertion at the beginning of -- ADD_FRAME_SET_ARRAY -- -- 8-JUN-1990 A. WILMONT, D. MCKEE -- Fixed READ_FILE_SLICE and associated sub procedures -- so that comment feilds are read correctly, EOL and -- EOF are read correctly, and extensive error checking -- is done on the external file format. -- package body WAVES_OBJECTS is -- -- START OF WAVES_OBJECTS PACKAGE BODY -- -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=- INTERNAL =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- Two useful functions. -- function MAX(A, B: INTEGER) return INTEGER is begin if A >= B then return A; else return B; end if; end MAX; function MIN(A, B: INTEGER) return INTEGER is begin if A <= B then return A; else return B; end if; end MIN; -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=- INTERNAL =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- An internal function to translate from a character to an index within -- PIN_CODE_RANGE. A negative number is returned if the input character -- is not within the string constant PIN_CODES. -- function INDEX ( VALUE : CHARACTER ) return INTEGER is begin for C in PIN_CODES'LEFT to PIN_CODES'RIGHT loop if PIN_CODES(C) = VALUE then return C; end if; end loop; return -1; end INDEX; function INDEX ( VALUE : TEST_PINS ) return INTEGER is begin return TEST_PINS'POS(VALUE) + 1; end INDEX; -- -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- This procedure applies a single wave slice to the outputs of the -- waveform generator package. -- -- See also declaration of EMPTY_EVENT in WAVES_INTERFACE body constant EMPTY_EVENT : INTEGER := -1; -- The following procedure is implementation dependent and un-standardized procedure APPLY_SLICE ( signal CONNECT : out WAVES_PORT_LIST (TEST_PIN_RANGE); variable DATA : in WAVE_SLICE ) is variable C : CHARACTER; variable D : TIME_DATA := DATA.TIMING.TIMING; variable E : EVENT_TIME; variable T : STRING (TEST_PIN_RANGE) := DATA.CODES; begin if D = null then assert FALSE report "Malformed wave slice - missing time data" severity ERROR; else for PIN in TEST_PIN_RANGE loop C := T(PIN); if INDEX(C) = -1 then assert FALSE report "Illegal character code in wave slice: " & C severity ERROR; else for I in 1 to D.FRAME_SET_DATA.all'LENGTH(3) loop exit when D.FRAME_SET_DATA.all(PIN, INDEX(C), I).VALUE <= EMPTY_EVENT ; CONNECT(PIN).DATA <= transport D.FRAME_SET_DATA.all(PIN, INDEX(C), I).VALUE after D.FRAME_SET_DATA.all(PIN, INDEX(C), I).TIME.NOMINAL ; end loop; end if; CONNECT(PIN).CODE <= transport C ; end loop; E := D.PERIOD_TOLERANCE; E.NOMINAL := DATA.TIMING.PERIOD; wait for E.NOMINAL; end if; end APPLY_SLICE; -- -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- This procedure applies a list of wave slices to the outputs of the -- waveform generator package. -- procedure APPLY_LIST ( signal CONNECT : out WAVES_PORT_LIST (TEST_PIN_RANGE); variable DATA : in WAVE_SLICE_LIST ) is variable X : WAVE_SLICE; begin for W in DATA'RANGE loop X := DATA(W); APPLY_SLICE(CONNECT, X); end loop; end APPLY_LIST; -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- This function returns the AND of the MATCH signals of the specified -- pins. -- function MATCH ( CONNECT : in WAVES_MATCH_LIST (TEST_PIN_RANGE); PINS : PINSET ) return BOOLEAN is variable FLAG : BOOLEAN := TRUE; begin for PIN in CONNECT'RANGE loop if PINS(PIN) then FLAG := FLAG and CONNECT(PIN); end if; end loop; return FLAG; end MATCH; function MATCH ( CONNECT : in WAVES_MATCH_LIST (TEST_PIN_RANGE); PINS : TEST_PINS ) return BOOLEAN is begin return CONNECT(INDEX(PINS)); end MATCH; -- -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- This procedure applies a WAVES label to the output ports of the -- waveform generator. -- procedure TAG ( signal CONNECT : out WAVES_PORT_LIST (TEST_PIN_RANGE); TAG_LABEL : STRING; PINS : PINSET ) is begin for P in PINS'RANGE loop if PINS(P) then for I in TAG_LABEL'range loop CONNECT(I).MESSAGE <= transport TAG_LABEL(I); wait for 0 ns; end loop; end if; end loop; end TAG; procedure TAG ( signal CONNECT : out WAVES_PORT_LIST (TEST_PIN_RANGE); TAG_LABEL : STRING; PINS : TEST_PINS ) is begin for I in TAG_LABEL'RANGE loop CONNECT(INDEX(PINS)).MESSAGE <= transport TAG_LABEL(I); wait for 0 ns; end loop; end TAG; -- -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=- FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- Two deferred constants. -- constant ALL_PINS : PINSET := (others => TRUE); constant NO_PINS : PINSET := (others => FALSE); -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=- FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- Two functions are provided to create a pinset. The first takes a -- single test pin and returns a pinset containing only that test pin. -- The second contains a list of test pins and returns a pinset -- containing all of the listed test pins. These are overloaded to -- reduce the name space. -- -- Pinsets may be added and subtracted using the predefined VHDL logical -- operators, which operate on boolean arrays. These are: -- function or ( A, B : PINSET ) return PINSET; -- function and ( A, B : PINSET ) return PINSET; -- function not ( A, B : PINSET ) return PINSET; -- function NEW_PINSET ( PIN : in TEST_PINS ) return PINSET is variable X : PINSET := (others => FALSE); begin X(INDEX(PIN)) := TRUE; return X; end NEW_PINSET; function NEW_PINSET ( PINS : in TEST_PINS_LIST ) return PINSET is variable X : PINSET := (others => FALSE); begin for PIN in PINS'RANGE loop X(INDEX(PINS(PIN))) := TRUE; end loop; return X; end NEW_PINSET; -- -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=- FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- The following functions are used to create the objects required for a -- TIME_DATA object. -- function NEW_FRAME_SET ( CODES : STRING; EVENTS : FRAME ) return FRAME_SET is variable X : FRAME_SET (PIN_CODE_RANGE, 1 to EVENTS'LENGTH); begin for I in CODES'RANGE loop if INDEX (CODES(I)) /= -1 then for J in X'RANGE(2) loop X(INDEX(CODES(I)), J) := EVENTS(J); end loop; else assert FALSE report "Error in new frame set pin code select" severity ERROR; end if; end loop; return X; end NEW_FRAME_SET; function NEW_FRAME_SET_ARRAY ( PINS : TEST_PINS; FRAMES : FRAME_SET ) return FRAME_SET_ARRAY is variable X : FRAME_SET_ARRAY (TEST_PIN_RANGE, PIN_CODE_RANGE, 1 to FRAMES'LENGTH(2)); begin assert FRAMES'LENGTH(1) = PIN_CODE_RANGE'RIGHT report "Bad frame set size in NEW FRAME SET ARRAY" severity ERROR; for I in X'RANGE(2) loop for J in X'RANGE(3) loop X(INDEX(PINS), I, J) := FRAMES(I, J); end loop; end loop; return X; end NEW_FRAME_SET_ARRAY; function NEW_FRAME_SET_ARRAY ( PINS : PINSET; FRAMES : FRAME_SET ) return FRAME_SET_ARRAY is variable X : FRAME_SET_ARRAY (TEST_PIN_RANGE, PIN_CODE_RANGE, 1 to FRAMES'LENGTH(2)); begin assert FRAMES'LENGTH(1) = PIN_CODE_RANGE'RIGHT report "Bad frame set size in NEW FRAME SET ARRAY" severity ERROR; for PIN in TEST_PIN_RANGE loop if PINS(PIN) then for I in X'RANGE(2) loop for J in X'RANGE(3) loop X(PIN, I, J) := FRAMES(I, J); end loop; end loop; end if; end loop; return X; end NEW_FRAME_SET_ARRAY; function ADD_FRAME_SET_ARRAY ( A : FRAME_SET_ARRAY; B : FRAME_SET_ARRAY ) return FRAME_SET_ARRAY is variable F : BOOLEAN; variable X : FRAME_SET_ARRAY (TEST_PIN_RANGE, PIN_CODE_RANGE, 1 to MAX(A'LENGTH(3), B'LENGTH(3))); begin assert A'LENGTH(1) = TEST_PIN_RANGE'RIGHT and B'LENGTH(1) = TEST_PIN_RANGE'RIGHT and A'LENGTH(2) = PIN_CODE_RANGE'RIGHT and B'LENGTH(2) = PIN_CODE_RANGE'RIGHT report "Bad frame set size in ADD FRAME SET ARRAY" severity ERROR; for PIN in TEST_PIN_RANGE loop F := FALSE; for I in X'RANGE(2) loop for J in A'RANGE(3) loop X(PIN, I, J) := A(PIN, I, J); F := F or (X(PIN, I, J).VALUE >= 0); end loop; end loop; if not F then for I in X'RANGE(2) loop for J in B'RANGE(3) loop X(PIN, I, J) := B(PIN, I, J); end loop; end loop; end if; end loop; return X; end ADD_FRAME_SET_ARRAY; function NEW_TIME_DATA ( FRAMES : FRAME_SET_ARRAY ) return TIME_DATA is begin return new TIME_DATA_BLOCK'( new FRAME_SET_ARRAY'(FRAMES), ETIME(0 ns)); end NEW_TIME_DATA; function NEW_TIME_DATA ( FRAMES : FRAME_SET_ARRAY; PERIOD_TOLERANCE : EVENT_TIME ) return TIME_DATA is begin return new TIME_DATA_BLOCK'( new FRAME_SET_ARRAY'(FRAMES), PERIOD_TOLERANCE); end NEW_TIME_DATA; -- -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=- FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- The following function converts an integer into a binary code. The -- length of the result is specified in the parameter WIDTH and the -- character codes to be used for binary 0 and binary 1 are in the -- parameter KEY. -- function BIT_STRING ( VALUE : INTEGER; KEY : STRING (1 to 2); WIDTH : NATURAL ) return STRING is variable X : STRING (1 to WIDTH); variable Y : INTEGER := VALUE; begin for I in 1 to WIDTH loop X(I) := KEY(Y mod 2 + 1); Y := Y / 2; end loop; return X; end BIT_STRING; -- -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- -- The following definitions support the fixed file format of Level 1 -- WAVES. The FILE INPUT DATA record stores information most recently -- read by the READ WAVE SLICE procedure. A flag, PERIOD NOT INDEX, is -- set to indicate whether the file contained a time or an integer most -- recently. The flag END_OF_FILE is set if an EOF is encountered while -- scanning for the current wave slice. END_OF_FILE is always FALSE if -- a wave slice is successfully (no errors) read. -- procedure READ_FILE_SLICE ( variable IFILE : in TEXT; ACCUMULATOR : inout FILE_SLICE ) is variable CHAR : CHARACTER; variable EOL : BOOLEAN; variable EOF : BOOLEAN; variable END_OF_SLICE : BOOLEAN; variable GOOD : BOOLEAN; variable ILINE : LINE; variable INDEX : NATURAL; -- Return TRUE if the input character is white space. -- function IS_WHITE ( C : CHARACTER ) return BOOLEAN is begin return (C = ' ') or (C = HT); end IS_WHITE; -- Ensure that a non-white character remains on the current line, -- reading new lines as needed. The output flag is set to TRUE if the -- procedure was unsuccessful (indicating an unexpected EOF). -- procedure SKIP_WHITE ( END_OF_FILE : out BOOLEAN ) is variable EOL : BOOLEAN; variable TRASH : CHARACTER; begin END_OF_FILE := FALSE; -- DTM 8-JUN-1990 use the ENDLINE PROCEDURE in STD.TEXTIO -- -- The following line was commented out on 06-28-90 by Gordon Newell and the -- next bit of code was uncommented, because it is nonstandard VHDL. -- Functions are not allowed to have access types. The commented-out -- code is a procedure call implemented only in Intermetrics. -- STD.TEXTIO.ENDLINE(ILINE,EOL); -- DTM:Below endline function does not check for word wrap of the Slice feild -- ARW 30-MAY-1990 CHECK FOR ENDLINE IN DIFFERENT WAY if ILINE.ALL = "" then EOL := TRUE; end if; -- ARW 30-MAY-1990 COMMENT THIS OUT if EOL then EOF := STD.TEXTIO.ENDFILE(IFILE); if EOF then END_OF_FILE := TRUE; return; end if; READLINE(IFILE, ILINE); if ILINE.all'LENGTH > 0 and ILINE(1) = '#' then END_OF_FILE := TRUE; return; end if; end if; loop while ILINE.all'LENGTH > 0 and IS_WHITE(ILINE(ILINE.all'LEFT)) loop READ(ILINE, TRASH); end loop; exit when ILINE.all'LENGTH > 0; END_OF_FILE := FALSE; EOF := STD.TEXTIO.ENDFILE(IFILE); if EOF then END_OF_FILE := TRUE; return; end if; READLINE(IFILE, ILINE); if ILINE.all'LENGTH > 0 and ILINE(1) = '#' then END_OF_FILE := TRUE; return; end if; end loop; end SKIP_WHITE; -- -- Read the next non-white character from the input line, reading new -- lines as necessary. -- procedure READ_CHAR is begin SKIP_WHITE(ACCUMULATOR.END_OF_FILE); READ(ILINE, CHAR); end READ_CHAR; -- Read an index from the file. -- procedure UPDATE_INDEX is begin SKIP_WHITE(ACCUMULATOR.END_OF_FILE); READ(ILINE, INDEX, GOOD); assert GOOD report "Error reading index from file format" severity ERROR; if GOOD then assert INDEX >= TEST_PIN_RANGE'LEFT and INDEX <= TEST_PIN_RANGE'RIGHT report "Error - index out of bounds in file format" severity ERROR; end if; end UPDATE_INDEX; -- Read either a time or an integer for timing data. Look for a -- closing semicolon. -- procedure GET_TIMING is variable PLOCAL : TIME; begin SKIP_WHITE(ACCUMULATOR.END_OF_FILE); READ(ILINE, PLOCAL, GOOD); if GOOD then ACCUMULATOR.PERIOD_SET := TRUE; ACCUMULATOR.PERIOD := PLOCAL; else READ(ILINE, ACCUMULATOR.INDEX, GOOD); if GOOD then ACCUMULATOR.INDEX_SET := TRUE; else assert FALSE report "Error in timing in file format" severity ERROR; end if; end if; end GET_TIMING; -- -- Read a quoted string from the external file. If the first -- character is a double quote, unconditionally accept the following -- character. Continue reading until white space is seen. -- procedure GET_QUOTED_STRING ( USE_LAST_CHAR : BOOLEAN := FALSE ) is begin if not USE_LAST_CHAR then READ_CHAR; if ACCUMULATOR.END_OF_FILE then return; end if; end if; if CHAR = '"' then READ(ILINE, CHAR); end if; ACCUMULATOR.CODES(INDEX) := CHAR; INDEX := INDEX + 1; loop -- ARW 2-JUN-1990 INVALID CHECK FOR ENDLINE corrected exit when ILINE.ALL = ""; READ(ILINE, CHAR); exit when IS_WHITE(CHAR) ; assert INDEX >= TEST_PIN_RANGE'LEFT and INDEX <= TEST_PIN_RANGE'RIGHT report "Error - index out of bounds in file format" severity ERROR; ACCUMULATOR.CODES(INDEX) := CHAR; INDEX := INDEX + 1; end loop; end GET_QUOTED_STRING; -- -- Determine type of next token. This involves reading the next -- character and casing off of it. Special characters are the equal -- sign, indicating that an index is coming, an ampersand, indicating -- concatenation, a colon, indicating that a timing is coming, and a -- semicolon, indicating the end of the slice. For the first field -- only, a quoted string is legal. A pound sign indicates an end of -- file, but is also only legal as the first field. -- procedure READ_NEXT_FIELD ( FIRST : in BOOLEAN := FALSE) is begin READ_CHAR; case CHAR is when '%' => -- COMMENT EOF := STD.TEXTIO.ENDFILE(IFILE); if EOF then ACCUMULATOR.END_OF_FILE := TRUE; return; end if; READLINE(IFILE, ILINE); if ILINE.all'LENGTH > 0 and ILINE(1) = '#' then ACCUMULATOR.END_OF_FILE := TRUE; end if; return ; when '=' => UPDATE_INDEX; -- CODETBD -- GET_QUOTED_STRING(TRUE); -- DAVE MCKEE FOUND BUG not catching illegal special characters when ':' => GET_TIMING; when ';' => END_OF_SLICE := TRUE; when '#' => assert FALSE report "Error in file format - unexpected EOF command" severity ERROR; when others => GET_QUOTED_STRING(TRUE); end case; end READ_NEXT_FIELD; begin END_OF_SLICE := FALSE; ACCUMULATOR.END_OF_FILE := FALSE; ACCUMULATOR.PERIOD_SET := FALSE; ACCUMULATOR.INDEX_SET := FALSE; INDEX := TEST_PIN_RANGE'LEFT; EOF := STD.TEXTIO.ENDFILE(IFILE); if EOF then ACCUMULATOR.END_OF_FILE := TRUE; return; end if; READLINE(IFILE, ILINE); if ILINE.all'LENGTH > 0 and ILINE(1) = '#' then ACCUMULATOR.END_OF_FILE := TRUE; return; end if; READ_NEXT_FIELD ( FIRST => TRUE ); while not END_OF_SLICE and not ACCUMULATOR.END_OF_FILE loop READ_NEXT_FIELD; end loop; end READ_FILE_SLICE; -- -- END OF WAVES_OBJECTS PACKAGE BODY -- end WAVES_OBJECTS;