title: Does Quartus II support line.all?
body: <p>I implemented some VHDL code to exports FSM state encodings at compile time, which can be read back by Xilinx ChipScope. This functionality is tested with Xilinx ISE 14.7, iSim 14.7 and Mentor Graphic's QuestaSim 10.2c. My design can be synthesized with an alternative top-level as well for Altera FPGAs, but Quartus II seems to have a problem with <code>return line.all;</code>.</p>
  
  <p><strong>Quartus II (14.0) error messages:</strong></p>
  
  <ul>
  <li>Error (10351): VHDL Subprogram Body error at sata_PhysicalLayer.vhdl(504): function "dbg_GenerateEncodings" does not always return a value</li>
  <li>Error (10346): VHDL error at debug.vhdl(47): formal port or parameter "encodings" must have actual or default value</li>
  <li>Error (10657): VHDL Subprogram error at sata_PhysicalLayer.vhdl(514):  failed to elaborate call to subprogram "dbg_ExportEncoding"</li>
  </ul>
  
  <p>In the following, I'll describe my code.</p>
  
  <hr>
  
  <h1>VHDL Code</h1>
  
  <p>The design uses 3 functions to export the FSM state encodings:</p>
  
  <ol>
  <li>encode the current local FSM state as a binary value -> dbg_EncodeState<br>
  (the result of this function is connected to the ILA ports)</li>
  <li>transform all states of the local FSM into a semicolon separated string -> dbg_GenerateEncodings</li>
  <li>format this string and write it's elements into a token-file -> dbg_ExportEncoding<br>
  (this function is located in a package)</li>
  </ol>
  
  <p><strong>FSM declaration:</strong></p>
  
  <pre><code>TYPE T_STATE IS (
      ST_HOST_RESET,
      ST_HOST_SEND_COMRESET,
      ST_HOST_SEND_COMRESET_WAIT,
      [...]
      ST_HOST_SEND_ALIGN,
      ST_HOST_TIMEOUT,
      ST_HOST_LINK_OK
  );
  
  -- OOB-Statemachine
  SIGNAL State                    : T_STATE       := ST_HOST_RESET;
  SIGNAL NextState                : T_STATE;
  </code></pre>
  
  <p><strong>local functions - per entity functions</strong>:</p>
  
  <pre><code>function dbg_EncodeState(st : T_STATE) return STD_LOGIC_VECTOR is
  begin
      return to_slv(T_STATE'pos(st), log2ceilnz(T_STATE'pos(T_STATE'high) + 1));
  end function;
  
  function dbg_GenerateEncodings return string is
    variable l : STD.TextIO.line;
  begin
      for i in T_STATE loop
          STD.TextIO.write(l, str_replace(T_STATE'image(i), "st_host_", ""));
          STD.TextIO.write(l, ';');
      end loop;
      return  l.all;
  end function;
  </code></pre>
  
  <p><strong>global function - defined in debug.pkg.vhdl:</strong></p>
  
  <pre><code>impure function dbg_ExportEncoding(Name : STRING; encodings : string; tokenFileName : STRING) return BOOLEAN is
      file        tokenFile : TEXT open WRITE_MODE is tokenFileName;
  
      variable cnt, base : integer;
      variable l : line;
  begin
      report "Exporting encoding of '" &amp; Name &amp; "' to '" &amp; tokenFileName &amp; "'..." severity note;
      report "dbg_ExportEncoding: '" &amp; encodings &amp; "'" severity note;
  
      -- write file header
      write(l, "# Encoding file for '" &amp; Name &amp; "'"); writeline(tokenFile, l);
      write(l, "#");                                  writeline(tokenFile, l);
      write(l, "# ChipScope Token File Version");     writeline(tokenFile, l);
      write(l, "@FILE_VERSION=1.0.0");                writeline(tokenFile, l);
      write(l, "#");                                  writeline(tokenFile, l);
      write(l, "# Default token value");              writeline(tokenFile, l);
      write(l, "@DEFAULT_TOKEN=");                    writeline(tokenFile, l);
      write(l, "#");                                  writeline(tokenFile, l);
  
      -- write state entires
      cnt  := 0;
      base := encodings'left;
      for i in encodings'range loop
          if encodings(i) = ';' then
              -- Leave the str_trim call in!
              -- Otherwise, the new parser of ISE 14.7 fails to slice properly.
              write(l, str_trim(encodings(base to i-1)));
              write(l, character'('='));
            write(l, raw_format_nat_hex(cnt));
              writeline(tokenFile, l);
              cnt  := cnt + 1;
              base := i+1;
          end if;
      end loop;
  
      file_close(tokenFile);
      return true;
  end function;
  </code></pre>
  
  <p>The last portion of code is a dummy constant in the entity, which calls the export function:</p>
  
  <pre><code>CONSTANT test : boolean := dbg_ExportEncoding("OOBControl (Host)", dbg_GenerateEncodings, MY_PROJECT_DIR &amp; "CSP/FSM_OOB_Host.tok");
  </code></pre>
  
  <p><strong>used auxilary functions:</strong></p>
  
  <ul>
  <li>log2ceilnz(x) calculates the needed bits to encode x symbols in binary</li>
  <li>to_slv converts everything into a std_logic_vector; in this case a integer to slv</li>
  <li>str_replace replaces a string by a string</li>
  <li>str_trim returns a string from str'low to the first occurrence of NUL</li>
  <li>raw_format_nat_hex formats a natural to a hex string</li>
  </ul>
  
  <p><strong>Additional Notes:</strong><br>
  All vhdl files are marked as VHDL-2008.</p>
  
  <hr>
  
  <h1>My Questions:</h1>
  
  <ol>
  <li>Has anyone experience with line.all in a Quartus environment?</li>
  <li>Is there a workaround?</li>
  <li>Is there a better solution to achieve the export task without using strings of constant length?</li>
  </ol>
  
  <hr>
  
  <h1>Work around:</h1>
  
  <p>I wrapped my function dbg_GenerateEncodings in a generate statement:</p>
  
  <pre><code>genXilinx : if (VENDOR = VENDOR_XILINX) generate
    function dbg_GenerateEncodings return string is
    [...]
  
    constant test : boolean := dbg_ExportEncoding("OOBControl (Host)", dbg_GenerateEncodings, MY_PROJECT_DIR &amp; "CSP/FSM_OOB_Host.tok");
  begin
  end generate;
  </code></pre>
  
  <p>In contrast to XST, Quartus does not check functions inside a generate block.</p>