--------------------------------------------------------------------------- -- Package TEXTIO as defined in Chapter 14 of the IEEE Standard VHDL -- Language Reference Manual (IEEE Std. 1076-1987), as modified -- by the Issues Screening and Analysis Committee (ISAC), a subcommittee -- of the VHDL Analysis and Standardization Group (VASG) on -- 10 November, 1988. See "The Sense of the VASG", October, 1989. --------------------------------------------------------------------------- -- Version information: %W% %G% --------------------------------------------------------------------------- package TEXTIO is type LINE is access string; type TEXT is file of string; type SIDE is (right, left); subtype WIDTH is natural; -- changed for vhdl92 syntax: file input : TEXT open read_mode is "STD_INPUT"; file output : TEXT open write_mode is "STD_OUTPUT"; -- changed for vhdl92 syntax (and now a built-in): procedure READLINE(file f: TEXT; L: out LINE); procedure READ(L:inout LINE; VALUE: out bit; GOOD : out BOOLEAN); procedure READ(L:inout LINE; VALUE: out bit); procedure READ(L:inout LINE; VALUE: out bit_vector; GOOD : out BOOLEAN); procedure READ(L:inout LINE; VALUE: out bit_vector); procedure READ(L:inout LINE; VALUE: out BOOLEAN; GOOD : out BOOLEAN); procedure READ(L:inout LINE; VALUE: out BOOLEAN); procedure READ(L:inout LINE; VALUE: out character; GOOD : out BOOLEAN); procedure READ(L:inout LINE; VALUE: out character); procedure READ(L:inout LINE; VALUE: out integer; GOOD : out BOOLEAN); procedure READ(L:inout LINE; VALUE: out integer); procedure READ(L:inout LINE; VALUE: out real; GOOD : out BOOLEAN); procedure READ(L:inout LINE; VALUE: out real); procedure READ(L:inout LINE; VALUE: out string; GOOD : out BOOLEAN); procedure READ(L:inout LINE; VALUE: out string); procedure READ(L:inout LINE; VALUE: out time; GOOD : out BOOLEAN); procedure READ(L:inout LINE; VALUE: out time); -- changed for vhdl92 syntax (and now a built-in): procedure WRITELINE(file f : TEXT; L : inout LINE); procedure WRITE(L : inout LINE; VALUE : in bit; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0); procedure WRITE(L : inout LINE; VALUE : in bit_vector; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0); procedure WRITE(L : inout LINE; VALUE : in BOOLEAN; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0); procedure WRITE(L : inout LINE; VALUE : in character; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0); procedure WRITE(L : inout LINE; VALUE : in integer; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0); procedure WRITE(L : inout LINE; VALUE : in real; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0; DIGITS: in NATURAL := 0); procedure WRITE(L : inout LINE; VALUE : in string; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0); procedure WRITE(L : inout LINE; VALUE : in time; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0; UNIT: in TIME := ns); -- is implicit built-in: -- function ENDFILE(file F : TEXT) return boolean; -- function ENDLINE(variable L : in LINE) return BOOLEAN; -- -- Function ENDLINE as declared cannot be legal VHDL, and -- the entire function was deleted from the definition -- by the Issues Screening and Analysis Committee (ISAC), -- a subcommittee of the VHDL Analysis and Standardization -- Group (VASG) on 10 November, 1988. See "The Sense of -- the VASG", October, 1989, VHDL Issue Number 0032. end; --******************************************************* --** ** --** Copyright (c) Model Technology Incorporated 1991 ** --** All Rights Reserved ** --** ** --******************************************************* package body TEXTIO is constant MAX_LINE : integer := 500; -- Maximum number of characters allowed in an input line -- by the READLINE routine. constant MAX_DIGITS : integer := 20; -- Number of decimal digits which can be processed by the -- integer input and output routines. Includes leading -- minus sign, should be large enough for 64-bit integers. subtype int_string_buf is string(1 to MAX_DIGITS); -- V-System VHDL will round time values below the base simulation -- unit to 0 when the model is loaded (more precisely, the -- internal integer representation of a time value is divided -- by the integer number of femtoseconds in the base time unit, -- which results in values less than the base time unit -- becoming zero). It is possible to determine the simulation -- time unit by scanning the following list for the first -- non-zero entry. ns is used in the declaration of all times -- because textio is not a legal program unless the base time -- unit is less than or equal to ns (ns is used in the -- declaration of the version of WRITE which outputs time -- values!). type time_unit_enum is (u_fs, u_ps, u_ns, u_us, u_ms, u_sec, u_min, u_hr); type time_unit_name_array is array (time_unit_enum) of string(1 to 3); constant time_unit_names: time_unit_name_array := ("fs ", "ps ", "ns ", "us ", "ms ", "sec", "min", "hr "); type time_array is array (time_unit_enum) of time; constant find_base_unit: time_array := (1.0E-6 ns, -- fs 1.0E-3 ns, -- ps 1 ns, 1 us, 1 ms, 1 sec, 1 min, 1 hr); procedure Int_to_string( constant val : in integer; variable result: out int_string_buf; variable last: out integer) is variable buf : string(MAX_DIGITS downto 1); variable pos : integer := 1; variable tmp : integer := abs(val); variable digit : integer; begin loop digit := abs(tmp MOD 10); -- MOD of integer'left returns neg number! tmp := tmp / 10; buf(pos) := character'val(character'pos('0') + digit); pos := pos + 1; exit when tmp = 0; end loop; if val < 0 then buf(pos) := '-'; pos := pos + 1; end if; pos := pos - 1; result(1 to pos) := buf(pos downto 1); last := pos; end Int_to_string; -- procedure function Int_to_string(val : integer) return string is variable buf : int_string_buf; variable last : integer; begin Int_to_string(val, buf, last); return buf(1 to last); end Int_to_string; -- function procedure READLINE(file f: TEXT; L: out LINE) --procedure READLINE(variable f: in TEXT; L : inout LINE) is variable buf : string(1 to MAX_LINE); variable len : integer := 0; variable c : character; begin --if L /= NULL then -- Deallocate(L); --end if; if not Endfile(f) then READ(f, buf, len); assert len <= MAX_LINE report "Textio: Truncated input line greater than " & Int_to_string(MAX_LINE) & " characters." severity ERROR; end if; if (len > 0) and (buf(len) = LF) then len := len - 1; end if; L := new string'(buf(1 to len)); end; procedure Skip_white(variable L : in LINE; pos : inout integer) is begin while pos <= L'high loop case L(pos) is when ' ' | HT => pos := pos + 1; when others => exit; end case; end loop; end; procedure Shrink_line(L : inout LINE; pos : in integer) is variable old_L : LINE := L; begin if pos > 1 then L := new string'(old_L(pos to old_L'high)); Deallocate(old_L); end if; end; procedure Grow_line(L : inout LINE; incr : in integer) is variable old_L : LINE := L; variable bfp: integer; -- Blank fill pointer. begin assert incr > 0 report "Textio: Grow_line called with zero increment." severity error; if L = null then bfp := 0; L := new string(1 to incr); else bfp := old_L'high; L := new string(old_L'low to old_L'high + incr); L(old_L'low to old_L'high) := old_L.all; Deallocate(old_L); end if; for i in 1 to incr loop L(bfp + i) := ' '; end loop; end; procedure Report_results(good : boolean; read_type : string) is begin assert good report "Could not read type " & read_type & " from line." severity error; end; function lower_case(c : character) return character is begin if c >= 'A' and c <= 'Z' then return character'val(character'pos(c) + 32); else return c; end if; end; -- compare two strings ignoring case function strcmp(a, b : string) return boolean is alias a_val : string(1 to a'length) is a; alias b_val : string(1 to b'length) is b; variable a_char, b_char : character; begin if a'length /= b'length then return false; elsif a = b then return true; end if; for i in 1 to a'length loop a_char := lower_case(a_val(i)); b_char := lower_case(b_val(i)); if a_char /= b_char then return false; end if; end loop; return true; end; procedure Extract_integer( variable L: inout LINE; variable pos: inout integer; variable value: out integer; variable ok: out boolean) is variable sign: integer := 1; variable rval: integer := 0; begin ok := FALSE; if pos < L'right and (L(pos) = '-' or L(pos) = '+') then if L(pos) = '-' then sign := -1; end if; pos := pos + 1; end if; -- Once the optional leading sign is removed, an integer can -- contain only the digits '0' through '9' and the '_' -- (underscore) character. VHDL disallows two successive -- underscores, and leading or trailing underscores. if pos <= L'right and L(pos) >= '0' and L(pos) <= '9' then while pos <= L'right loop if L(pos) >= '0' and L(pos) <= '9' then rval := rval * 10 + character'pos(L(pos)) - character'pos('0'); ok := TRUE; elsif L(pos) = '_' then if pos = L'right or L(pos + 1) < '0' or L(pos + 1) > '9' then ok := FALSE; exit; end if; else exit; end if; pos := pos + 1; end loop; end if; value := sign * rval; end Extract_integer; procedure Extract_real( variable L: inout LINE; variable pos: inout integer; variable value: out real; variable ok: inout boolean) is variable sign: real := 1.0; variable rval: real := 0.0; procedure Apply_mantissa( variable L: inout LINE; variable pos: inout integer; variable rval: inout real; variable ok: inout boolean) is begin -- this procedure reads numeric characters and the '_' character until -- encountering a '.' character. It converts these characters into a -- real number and indicates any problems through the ok parameter. ok := FALSE; rval := 0.0; if pos <= L'right and L(pos) >= '0' and L(pos) <= '9' then while pos <= L'right and L(pos) /= '.' and L(pos) /= ' ' and L(pos) /= HT loop if L(pos) >= '0' and L(pos) <= '9' then rval := rval*10.0 + real(character'pos(L(pos)) - character'pos('0')); pos := pos+1; ok := true; elsif L(pos) = '_' then if pos+1 <= L'right then if L(pos+1) >= '0' and L(pos+1) <= '9' then pos := pos+1; else ok := false; exit; end if; else ok := false; exit; end if; else ok := false; exit; end if; end loop; end if; end; procedure Apply_fraction( variable L: inout LINE; variable pos: inout integer; variable rval: inout real; variable ok: inout boolean) is variable powerten: real := 0.1; begin -- this procedure reads numeric characters and the '_' character from a -- line variable and converts them into a fractional number. It indicates -- the status of the conversion throught the ok parameter. ok := false; if pos <= L'right then while pos <= L'right and ((L(pos) >= '0' and L(pos) <= '9') or L(pos) = '_') loop if L(pos) = '_' then if pos+1 <= L'right then if L(pos+1) >= '0' and L(pos+1) <= '9' then pos := pos+1; else ok := false; exit; end if; else ok := false; exit; end if; else rval := rval + (real(character'pos(L(pos))-character'pos('0'))*powerten); powerten := powerten*0.1; pos := pos+1; ok := true; end if; end loop; end if; end; procedure Apply_exponent( variable L: inout LINE; variable pos: inout integer; variable rval: inout real; variable ok: inout boolean) is variable int_val: integer:=0; variable sign : integer := 1; begin -- this procedure reads in numeric characters and the '_' character and -- uses them as an exponent for the rval parameter. It indicates the -- success of the operation through the ok parameter. ok := false; if pos <= L'right then if (L(pos) = '+') then pos := pos + 1; elsif (L(pos) = '-') then sign := -1; pos := pos + 1; end if; while pos <= L'right and ((L(pos) >= '0' and L(pos) <= '9') or L(pos) = '_') loop if L(pos) >= '_' then if pos+1 <= L'right then if L(pos+1) >= '0' and L(pos+1) <= '9' then pos := pos+1; else ok := false; exit; end if; else ok := false; exit; end if; else if int_val <= integer'high/10 then int_val := int_val*10 + (character'pos(L(pos)) - character'pos('0')); pos := pos+1; ok := true; else assert false report "Overflow in Exponent of real number!" severity failure; ok := false; exit; end if; end if; end loop; if ok then rval := rval*(10.0**(int_val * sign)); end if; end if; end; begin ok:= FALSE; pos := L'left; Skip_white(L, pos); if (pos <= L'right) and (L(pos) = '-') then sign := -1.0; pos := pos + 1; end if; Apply_mantissa(L,pos,rval,ok); -- get number before decimal point if ok and pos <= L'right and L(pos) = '.' then pos := pos + 1; Apply_fraction(L,pos,rval,ok); -- get fraction after decimal (before exponent) if ok and pos <= L'right and (L(pos) = 'E' or L(pos) = 'e') then pos := pos + 1; Apply_exponent(L,pos,rval,ok); -- get fraction end if; end if; if ok then value := rval * sign; end if; end; ----------------------------------------------------------------- -- Bit reading ----------------------------------------------------------------- procedure READ(L:inout LINE; VALUE: out bit; GOOD : out BOOLEAN) is variable pos : integer; variable ok : boolean := FALSE; begin if L /= NULL then pos := L'left; Skip_white(L, pos); if pos <= L'right then if L(pos) = '0' then VALUE := '0'; ok := TRUE; elsif L(pos) = '1' then VALUE := '1'; ok := TRUE; end if; end if; end if; GOOD := ok; if ok then Shrink_line(L, pos + 1); end if; end; procedure READ(L:inout LINE; VALUE: out bit) is variable GOOD : BOOLEAN; begin READ(L, VALUE, GOOD); Report_results(GOOD, "BIT"); end; ----------------------------------------------------------------- -- Bit vector reading ----------------------------------------------------------------- procedure READ(L:inout LINE; VALUE: out bit_vector; GOOD : out BOOLEAN) is alias val : bit_vector(1 to VALUE'length) is VALUE; variable vpos : integer := 0; -- Index of last valid bit in val. variable lpos : integer; -- Index of next unused char in L. begin if L /= NULL then lpos := L'left; Skip_white(L, lpos); while lpos <= L'right and vpos < VALUE'length loop if L(lpos) = '0' then vpos := vpos + 1; val(vpos) := '0'; elsif L(lpos) = '1' then vpos := vpos + 1; val(vpos) := '1'; else exit; -- Bit values must be '0' or '1'. end if; lpos := lpos + 1; end loop; end if; if vpos = VALUE'length then GOOD := TRUE; Shrink_line(L, lpos); else GOOD := FALSE; end if; end; procedure READ(L:inout LINE; VALUE: out bit_vector) is variable GOOD : BOOLEAN; begin READ(L, VALUE, GOOD); Report_results(GOOD, "BIT_VECTOR"); end; ----------------------------------------------------------------- -- BOOLEAN reading ----------------------------------------------------------------- procedure READ(L:inout LINE; VALUE: out BOOLEAN; GOOD : out BOOLEAN) is variable pos : integer; variable len : integer; variable ok : boolean := FALSE; begin if L /= NULL then pos := L'left; Skip_white(L, pos); len := L'right - pos + 1; if len >= 4 and strcmp(L(pos to pos + 3), "true") then ok := TRUE; VALUE := TRUE; pos := pos + 4; elsif len >= 5 and strcmp(L(pos to pos + 4), "false") then ok := TRUE; VALUE := FALSE; pos := pos + 5; end if; end if; GOOD := ok; if ok then Shrink_line(L, pos); end if; end; procedure READ(L:inout LINE; VALUE: out BOOLEAN) is variable GOOD : BOOLEAN; begin READ(L, VALUE, GOOD); Report_results(GOOD, "BOOLEAN"); end; ----------------------------------------------------------------- -- CHARACTER reading ----------------------------------------------------------------- procedure READ(L:inout LINE; VALUE: out character; GOOD : out BOOLEAN) is begin if L /= NULL and L'length > 0 then GOOD := TRUE; VALUE := L(L'left); Shrink_line(L, L'left + 1); else GOOD := FALSE; end if; end; procedure READ(L:inout LINE; VALUE: out character) is variable GOOD : BOOLEAN; begin READ(L, VALUE, GOOD); Report_results(GOOD, "CHARACTER"); end; ----------------------------------------------------------------- -- INTEGER reading ----------------------------------------------------------------- procedure READ(L: inout LINE; VALUE: out integer; GOOD: out BOOLEAN) is variable pos: integer; variable rval: integer := 0; variable exp: integer := 0; variable ok: boolean := FALSE; begin if L /= NULL then pos := L'left; Skip_white(L, pos); Extract_integer(L, pos, rval, ok); if ok and pos < L'right and (L(pos) = 'E' or L(pos) = 'e') then pos := pos + 1; Extract_integer(L, pos, exp, ok); if ok then if exp > 0 then rval := rval * 10 ** exp; elsif exp < 0 then ok := FALSE; end if; end if; end if; end if; GOOD := ok; if ok then VALUE := rval; Shrink_line(L, pos); end if; end; procedure READ(L:inout LINE; VALUE: out integer) is variable GOOD : BOOLEAN; begin READ(L, VALUE, GOOD); Report_results(GOOD, "INTEGER"); end; ----------------------------------------------------------------- -- REAL reading ----------------------------------------------------------------- procedure READ(L: inout LINE; VALUE: out real; GOOD : out BOOLEAN) is variable rval: real; variable ok : boolean := FALSE; variable pos : integer; begin if L /= NULL then pos := L'left; Skip_white(L, pos); Extract_real(L, pos, rval, ok); end if; GOOD := ok; if ok then VALUE := rval; Shrink_line(L, pos); end if; end; procedure READ(L: inout LINE; VALUE: out real) is variable GOOD : BOOLEAN; begin READ(L, VALUE, GOOD); Report_results(GOOD, "REAL"); end; ----------------------------------------------------------------- -- STRING reading ----------------------------------------------------------------- procedure READ(L:inout LINE; VALUE: out string; GOOD : out BOOLEAN) is alias val : string(1 to VALUE'length) is VALUE; variable vpos : integer := 0; -- Index of last valid character in val. variable lpos : integer; -- Index of next unused char in L. begin if L /= NULL then lpos := L'left; while lpos <= L'right and vpos < VALUE'length loop vpos := vpos + 1; val(vpos) := L(lpos); lpos := lpos + 1; end loop; end if; if vpos = VALUE'length then GOOD := TRUE; Shrink_line(L, lpos); else GOOD := FALSE; end if; end; procedure READ(L:inout LINE; VALUE: out string) is variable GOOD : BOOLEAN; begin READ(L, VALUE, GOOD); Report_results(GOOD, "STRING"); end; ----------------------------------------------------------------- -- TIME reading ----------------------------------------------------------------- procedure READ(L:inout LINE; VALUE: out time; GOOD : out BOOLEAN) is variable rval: real; variable tval: real; variable ok : boolean := FALSE; variable pos : integer; variable len : integer; begin if L /= NULL then pos := L'left; Skip_white(L, pos); Extract_real(L, pos, rval, ok); -- The numeric literal is optional. If it doesn't appear, -- assume 1. if not ok then rval := 1.0; pos := L'left; ok := TRUE; end if; Skip_white(L, pos); len := L'right - pos + 1; if len >= 2 then if strcmp(L(pos to pos + 1), "fs") then tval := 1.0e-6; pos := pos + 2; elsif strcmp(L(pos to pos + 1), "ps") then tval := 1.0e-3; pos := pos + 2; elsif strcmp(L(pos to pos + 1), "ns") then tval := 1.0; pos := pos + 2; elsif strcmp(L(pos to pos + 1), "us") then tval := 1.0e3; pos := pos + 2; elsif strcmp(L(pos to pos + 1), "ms") then tval := 1.0e6; pos := pos + 2; elsif strcmp(L(pos to pos + 1), "hr") then tval := 3600.0 * 1.0e9; pos := pos + 2; elsif len >= 3 then if strcmp(L(pos to pos + 2), "sec") then tval := 1.0e9; pos := pos + 3; elsif strcmp(L(pos to pos + 2), "min") then tval := 60.0 * 1.0e9; pos := pos + 3; else ok := FALSE; end if; else ok := FALSE; end if; else ok := FALSE; end if; end if; GOOD := ok; if ok then VALUE := (rval * tval) * 1 ns; Shrink_line(l, pos); end if; end; procedure READ(L:inout LINE; VALUE: out time) is variable GOOD : BOOLEAN; begin READ(L, VALUE, GOOD); Report_results(GOOD, "TIME"); end; procedure WRITELINE(file f : TEXT; L : inout LINE) --procedure WRITELINE(f : out TEXT; L : inout LINE) is begin if L /= null then write(f, L.all & LF); Deallocate(L); else -- Write a blank line write(f, (1 => LF)); end if; end; procedure WRITE(L : inout LINE; VALUE : in bit; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0) is variable fw: integer := 1; variable new_L: LINE; variable bp: integer; begin if L /= null then bp := L'high + 1; else bp := 1; end if; if FIELD < 1 then fw := 1; elsif FIELD > 1 then fw := FIELD; if JUSTIFIED = right then bp := bp + fw - 1; end if; end if; Grow_line(L, fw); L(bp) := character'val(bit'pos(VALUE) + character'pos('0')); end; procedure WRITE(L : inout LINE; VALUE : in bit_vector; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0) is variable fw: integer := VALUE'length; variable bp: integer; variable offset: integer := 0; alias normal : bit_vector(0 to value'length - 1) is value; begin if L /= null then bp := L'high + 1; else bp := 1; end if; if FIELD > VALUE'length then fw := FIELD; if JUSTIFIED = right then offset := fw - VALUE'length; end if; end if; Grow_line(L, fw); for i in normal'range loop L(bp + i + offset) := character'val( bit'pos(normal(i)) + character'pos('0')); end loop; end; procedure WRITE( variable L : inout LINE; constant VALUE : in BOOLEAN; constant JUSTIFIED: in SIDE := right; constant FIELD: in WIDTH := 0) is begin if VALUE then WRITE(L, string'("TRUE"), JUSTIFIED, FIELD); else WRITE(L, string'("FALSE"), JUSTIFIED, FIELD); end if; end; procedure WRITE(L : inout LINE; VALUE : in character; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0) is variable fw: integer := 1; variable new_L: LINE; variable bp: integer; variable highest : integer; begin if L = NULL then highest := 0; else highest := L'high; end if; bp := highest + 1; if FIELD < 1 then fw := 1; elsif FIELD > 1 then fw := FIELD; if JUSTIFIED = right then bp := highest + fw; end if; end if; Grow_line(L, fw); L(bp) := VALUE; end; procedure WRITE(L : inout LINE; VALUE : in integer; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0) is variable buf: int_string_buf; variable last: integer; begin Int_to_string(VALUE, buf, last); WRITE(L, buf(1 to last), JUSTIFIED, FIELD); end; procedure WRITE(L : inout LINE; VALUE : in real; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0; DIGITS: in NATURAL := 0) is constant max_useful_digits: integer := 7; -- Single precision floating point gives almost 7 -- full digits of precision (not the same as the -- DIGITS parameter) on a 386/387, and the VHDL -- Language Reference Manual uses 7 in its example of -- floating point output, so that's what we'll have. constant scale_to: real := 10.0 ** max_useful_digits; -- The floating point equivalent to seven useful digits. constant max_digits_spec: integer := 40; -- Ignore a digits specification greater than this, since -- the decimal exponent range is approximately 10 ** 38 -- to 10 ** -38. variable decimal_scale: integer := max_useful_digits - 1; -- After scaling, there will be one significant digit -- to the left of the decimal point, and the -- decimal_scale will be the correct value for -- "n.nnnE" format printing. variable scale_factor: real := 1.0; variable pos_val: real := VALUE; variable int_buf: int_string_buf; variable last: integer; variable buf: string(1 to 2 * max_digits_spec + 2); variable bufp: integer := buf'low; -- Next available char in buf. variable cc: integer; variable i: integer; variable rh_digits: integer := 0; variable int_val: integer; variable dot_position: integer; begin if VALUE < 0.0 then pos_val := - VALUE; buf(bufp) := '-'; bufp := bufp + 1; end if; if pos_val = 0.0 then int_val := 0; decimal_scale := 0; elsif pos_val < scale_to then while (pos_val * scale_factor * 10.0) < scale_to loop decimal_scale := decimal_scale - 1; scale_factor := scale_factor * 10.0; end loop; int_val := integer(pos_val * scale_factor); else while pos_val / scale_factor > scale_to loop decimal_scale := decimal_scale + 1; scale_factor := scale_factor * 10.0; end loop; int_val := integer(pos_val / scale_factor); end if; Int_to_string(int_val, int_buf, last); if last - int_buf'low + 1 > max_useful_digits then last := int_buf'low + max_useful_digits - 1; end if; if DIGITS = 0 or DIGITS > max_digits_spec then buf(bufp) := int_buf(int_buf'low); buf(bufp + 1) := '.'; bufp := bufp + 2; cc := last - int_buf'low; -- We've already taken the first one. if (cc = 0) then buf(bufp) := '0'; bufp := bufp + 1; else buf(bufp to bufp + cc - 1) := int_buf(int_buf'low + 1 to int_buf'low + cc); bufp := bufp + cc; end if; -- Remove trailing zeroes (except the just before the -- decimal point which makes this a real number). while buf(bufp - 1) = '0' loop bufp := bufp - 1; end loop; if buf(bufp - 1) = '.' then bufp := bufp + 1; end if; if decimal_scale /= 0 then buf(bufp) := 'E'; bufp := bufp + 1; Int_to_string(decimal_scale, int_buf, last); cc := last - int_buf'low + 1; buf(bufp to bufp + cc - 1) := int_buf(int_buf'low to last); bufp := bufp + cc; end if; else if decimal_scale >= 0 then -- Add zeroes on the right side. dot_position := bufp + decimal_scale + 1; buf(dot_position) := '.'; for i in int_buf'low to last loop if bufp = dot_position then bufp := bufp + 1; -- Skip the dot. end if; if bufp > dot_position then if rh_digits < DIGITS then rh_digits := rh_digits + 1; else exit; end if; end if; buf(bufp) := int_buf(i); bufp := bufp + 1; end loop; if bufp <= dot_position then while bufp < dot_position loop buf(bufp) := '0'; bufp := bufp + 1; end loop; bufp := bufp + 1; -- Skip the dot. end if; for i in rh_digits to DIGITS - 1 loop if rh_digits < DIGITS then rh_digits := rh_digits + 1; else exit; end if; buf(bufp) := '0'; bufp := bufp + 1; end loop; else buf(bufp to bufp + 1) := "0."; bufp := bufp + 2; i := int_buf'low; while rh_digits < DIGITS loop if decimal_scale < -1 then buf(bufp) := '0'; decimal_scale := decimal_scale + 1; elsif i <= last then buf(bufp) := int_buf(i); i := i + 1; else buf(bufp) := '0'; end if; rh_digits := rh_digits + 1; bufp := bufp + 1; end loop; end if; end if; WRITE(L, buf(buf'low to bufp - 1), JUSTIFIED, FIELD); end; procedure WRITE( variable L : inout LINE; constant VALUE : in string; constant JUSTIFIED: in SIDE := right; constant FIELD : in WIDTH := 0) is variable bp : integer; variable fw : WIDTH := VALUE'length; begin if VALUE'length > 0 then if L = null then bp := 1; else bp := L'high + 1; end if; if FIELD > VALUE'length then fw := FIELD; if JUSTIFIED = right then bp := bp + fw - VALUE'length; end if; end if; Grow_line(L, fw); L(bp to bp + VALUE'length - 1) := VALUE; end if; end; procedure WRITE( L : inout LINE; VALUE : in time; JUSTIFIED: in SIDE := right; FIELD: in WIDTH := 0; UNIT: in TIME := ns) is variable base_time_index: time_unit_enum := u_hr; variable unit_time_index: time_unit_enum := u_ns; variable int_buf: int_string_buf; variable buf: string(1 to MAX_DIGITS + 6); variable last: integer; variable i: integer; variable decimal_shift: integer; variable is_neg : boolean := (value < 0 ns); variable val : time := abs(value); begin for i in time_unit_enum loop if find_base_unit(i) /= 0 hr then if base_time_index = u_hr then base_time_index := i; end if; if UNIT = find_base_unit(i) then unit_time_index := i; end if; end if; end loop; assert base_time_index /= u_hr report "WRITE: find_base_unit failed." severity error; if UNIT = 0 hr or unit_time_index < base_time_index then -- This may not be a strictly conforming IEEE VHDL -- program, since if a UNIT smaller than the base -- simulation unit is specified, the program is -- in error. We'll handle the problem gracefully. unit_time_index := base_time_index; end if; Int_to_string(val / find_base_unit(base_time_index), int_buf, last); buf(int_buf'range) := int_buf; if unit_time_index /= base_time_index then decimal_shift := 3 * (time_unit_enum'pos(unit_time_index) - time_unit_enum'pos(base_time_index)); if last > decimal_shift then last := last + 1; for i in last downto (last - decimal_shift + 1) loop buf(i) := buf(i - 1); end loop; buf(last - decimal_shift) := '.'; else i := decimal_shift + 2; buf(i - last + buf'low to i) := buf(buf'low to last); for i in buf'low to i - last + buf'low - 1 loop buf(i) := '0'; end loop; buf(buf'low + 1) := '.'; last := i; end if; -- Strip trailing zero's, perhaps even the decimal point! while buf(last) = '0' loop last := last - 1; end loop; if buf(last) = '.' then last := last - 1; end if; end if; -- Add the unit identifier and "print it". buf(last + 1) := ' '; if time_unit_names(unit_time_index)(3) = ' ' then buf(last + 2 to last + 3) := time_unit_names(unit_time_index)(1 to 2); last := last + 3; else buf(last + 2 to last + 4) := time_unit_names(unit_time_index); last := last + 4; end if; if (is_neg) then WRITE(L, '-' & buf(buf'low to last), JUSTIFIED, FIELD); else WRITE(L, buf(buf'low to last), JUSTIFIED, FIELD); end if; end; end;