我为Xilinx XST,iSim,Altera Quartus II,Mentor Graphics QuestaSim和GHDL编写了一些跨平台的VHDL库。现在我想移植我的ISE 14.7项目,它将这些库用于Vivado 2014.4,但是一个库似乎有致命的问题。
我的库physical
定义了几种新的用户定义的物理类型,例如:FREQUENCY
和BAUD
;转换功能和报告功能。
一个主要用例是计算给定延迟和系统频率的延迟或计数器周期。因此,例如125 ns的延迟需要在100 MHz时有12或13个延迟周期(这取决于.5处的舍入模式)。
我从Vivado Synth获得了几个信息和警告(一些是断言声明的结果,请参见下面的最小示例):
[Synth 8-638] synthesizing module 'Top_PhysicalTest' ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":410]
[Synth 8-63] RTL assertion: "to_time: f= 2147483647.1000 THz return 2147483647.1000 sec" ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":277]
[Synth 8-63] RTL assertion: "res_real: 0.000000" ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":321]
[Synth 8-63] RTL assertion: "TimingToCycles:
Timing: 2147483647.1000 sec
Clock_Period: 2147483647.1000 sec
RoundingStyle: TO_NEAREST
res_real = 2147483647.1000
=> 0" ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":323]
[Synth 8-26] 'image of non-integer, non-enum type not implemented ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":422]
[Synth 8-63] RTL assertion: "CLOCK_FREQ: <complex-type>" ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":422]
[Synth 8-63] RTL assertion: "CLOCK_FREQ: 2147483647.1000 THz" ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":423]
[Synth 8-26] 'image of non-integer, non-enum type not implemented ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":424]
[Synth 8-63] RTL assertion: "DELAY: <complex-type>" ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":424]
[Synth 8-63] RTL assertion: "DELAY: 2147483647.1000 sec" ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":425]
[Synth 8-63] RTL assertion: "CYCLES: 0" ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":426]
[Synth 8-256] done synthesizing module 'Top_PhysicalTest' (1#1) ["D:/Temp/PhysicalTest_Vivado2014.4/vhdl/Top_PhysicalTest.vhd":410]
[Synth 8-3330] design Top_PhysicalTest has an empty top module
[Synth 8-3331] design Top_PhysicalTest has unconnected port Clock
[Synth 8-3330] design Top_PhysicalTest has an empty top module
[Synth 8-3331] design Top_PhysicalTest has unconnected port Clock
[Project 1-571] Translating synthesized netlist
我的场景有点复杂,因此最小的示例看起来并不像应该看起来那么小。我没有内联每个函数来防止复制/替换错误,我没有删除调试和断言/报告例程。
概述:
最小例子:
-- EMACS settings: -*- tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
--
-- ============================================================================
-- Package: Common functions and types
--
-- Authors: Thomas B. Preusser
-- Martin Zabel
-- Patrick Lehmann
--
-- License:
-- ============================================================================
-- Copyright 2007-2015 Technische Universitaet Dresden - Germany
-- Chair for VLSI-Design, Diagnostics and Architecture
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- ============================================================================
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
package utils is
-- rounding style
type T_ROUNDING_STYLE is (ROUND_TO_NEAREST, ROUND_TO_ZERO, ROUND_TO_INF, ROUND_UP, ROUND_DOWN);
function ite(cond : BOOLEAN; value1 : STRING; value2 : STRING) return STRING;
function imin(arg1 : integer; arg2 : integer) return integer;
function imax(arg1 : integer; arg2 : integer) return integer;
function log2ceil(arg : positive) return natural;
function log2ceilnz(arg : positive) return positive;
end package utils;
package body utils is
function ite(cond : BOOLEAN; value1 : STRING; value2 : STRING) return STRING is
begin
if cond then
return value1;
else
return value2;
end if;
end function;
function imin(arg1 : integer; arg2 : integer) return integer is
begin
if arg1 < arg2 then return arg1; end if;
return arg2;
end function;
function imax(arg1 : integer; arg2 : integer) return integer is
begin
if arg1 > arg2 then return arg1; end if;
return arg2;
end function;
function log2ceil(arg : positive) return natural is
variable tmp : positive := 1;
variable log : natural := 0;
begin
if arg = 1 then return 0; end if;
while arg > tmp loop
tmp := tmp * 2;
log := log + 1;
end loop;
return log;
end function;
function log2ceilnz(arg : positive) return positive is
begin
return imax(1, log2ceil(arg));
end function;
end utils;
-- ============================================================================
-- Package: String related functions and types
--
-- Authors: Thomas B. Preusser
-- Martin Zabel
-- Patrick Lehmann
--
-- =============================================================================
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use IEEE.MATH_REAL.all;
use work.utils.all;
package strings is
function raw_format_nat_dec(value : NATURAL) return STRING;
function str_format(value : REAL; precision : NATURAL := 3) return STRING;
FUNCTION resize(str : STRING; size : POSITIVE; FillChar : CHARACTER := NUL) RETURN STRING;
function str_length(str : STRING) return NATURAL;
function str_trim(str : STRING) return STRING;
function str_substr(str : STRING; start : INTEGER := 0; length : INTEGER := 0) return STRING;
end package strings;
package body strings is
-- raw_format_* functions
function raw_format_nat_dec(value : NATURAL) return STRING is
begin
return INTEGER'image(value);
end function;
-- str_format_* functions
function str_format(value : REAL; precision : NATURAL := 3) return STRING is
constant s : REAL := sign(value);
constant int : INTEGER := integer((value * s) - 0.5); -- force ROUND_DOWN
constant frac : INTEGER := integer((((value * s) - real(int)) * 10.0**precision) - 0.5); -- force ROUND_DOWN
constant res : STRING := raw_format_nat_dec(int) & "." & raw_format_nat_dec(frac);
begin
-- assert (not MY_VERBOSE)
-- report "str_format:" & CR &
-- " value:" & REAL'image(value) & CR &
-- " int = " & INTEGER'image(int) & CR &
-- " frac = " & INTEGER'image(frac)
-- severity note;
return ite((s < 0.0), "-" & res, res);
end function;
-- resize
FUNCTION resize(str : STRING; size : POSITIVE; FillChar : CHARACTER := NUL) RETURN STRING IS
CONSTANT MaxLength : NATURAL := imin(size, str'length);
VARIABLE Result : STRING(1 TO size) := (OTHERS => FillChar);
BEGIN
if (MaxLength > 0) then
Result(1 TO MaxLength) := str(str'low TO str'low + MaxLength - 1);
end if;
RETURN Result;
END FUNCTION;
-- String functions
FUNCTION str_length(str : STRING) RETURN NATURAL IS
VARIABLE l : NATURAL := 0;
BEGIN
FOR I IN str'range LOOP
IF (str(I) = NUL) THEN
RETURN l;
ELSE
l := l + 1;
END IF;
END LOOP;
RETURN str'length;
END FUNCTION;
function str_trim(str : STRING) return STRING is
constant len : NATURAL := str_length(str);
begin
if (len = 0) then
return "";
else
return resize(str, len);
end if;
end function;
function str_substr(str : STRING; start : INTEGER := 0; length : INTEGER := 0) return STRING is
variable StartOfString : positive;
variable EndOfString : positive;
begin
if (start < 0) then -- start is negative -> start substring at right string boundary
StartOfString := str'high + start + 1;
elsif (start = 0) then -- start is zero -> start substring at left string boundary
StartOfString := str'low;
else -- start is positive -> start substring at left string boundary + offset
StartOfString := start;
end if;
if (length < 0) then -- length is negative -> end substring at length'th character before right string boundary
EndOfString := str'high + length;
elsif (length = 0) then -- length is zero -> end substring at right string boundary
EndOfString := str'high;
else -- length is positive -> end substring at StartOfString + length
EndOfString := StartOfString + length - 1;
end if;
if (StartOfString < str'low) then report "StartOfString is out of str's range. (str=" & str & ")" severity error; end if;
if (EndOfString < str'high) then report "EndOfString is out of str's range. (str=" & str & ")" severity error; end if;
return str(StartOfString to EndOfString);
end function;
end strings;
-- ============================================================================
-- Package: This VHDL package declares new physical types and their
-- conversion functions.
--
-- Authors: Patrick Lehmann
--
-- ============================================================================
library IEEE;
use IEEE.MATH_REAL.all;
use work.utils.all;
use work.strings.all;
package physical is
type FREQ is range 0 to INTEGER'high units
Hz;
kHz = 1000 Hz;
MHz = 1000 kHz;
GHz = 1000 MHz;
THz = 1000 GHz;
end units;
constant C_PHYSICAL_REPORT_TIMING_DEVIATION : BOOLEAN := TRUE;
function to_time(f : FREQ) return TIME;
function to_real(t : TIME; scale : TIME) return REAL;
function to_real(f : FREQ; scale : FREQ) return REAL;
function TimingToCycles(Timing : TIME; Clock_Period : TIME; RoundingStyle : T_ROUNDING_STYLE := ROUND_TO_NEAREST) return NATURAL;
function TimingToCycles(Timing : TIME; Clock_Frequency : FREQ; RoundingStyle : T_ROUNDING_STYLE := ROUND_TO_NEAREST) return NATURAL;
function to_string(t : TIME; precision : NATURAL := 3) return STRING;
function to_string(f : FREQ; precision : NATURAL := 3) return STRING;
end physical;
package body physical is
-- iSim 14.7 does not support fs in simulation by default (fs values are converted to 0 ps)
-- activate fs support by overriding the time precision
-- fuse[.exe] [...] -timeprecision_vhdl 1fs [...]
function MinimalTimeResolutionInSimulation return TIME is
begin
if (1 fs > 0 sec) then return 1 fs;
elsif (1 ps > 0 sec) then return 1 ps;
elsif (1 ns > 0 sec) then return 1 ns;
elsif (1 us > 0 sec) then return 1 us;
elsif (1 ms > 0 sec) then return 1 ms;
else return 1 sec;
end if;
end function;
-- real division for physical types
function div(a : TIME; b : TIME) return REAL is
constant MTRIS : TIME := MinimalTimeResolutionInSimulation;
begin
if (a < 1 us) then
return real(a / MTRIS) / real(b / MTRIS);
elsif (a < 1 ms) then
return real(a / (1000 * MTRIS)) / real(b / MTRIS) * 1000.0;
elsif (a < 1 sec) then
return real(a / (1000000 * MTRIS)) / real(b / MTRIS) * 1000000.0;
else
return real(a / (1000000000 * MTRIS)) / real(b / MTRIS) * 1000000000.0;
end if;
end function;
function div(a : FREQ; b : FREQ) return REAL is
begin
return real(a / 1 Hz) / real(b / 1 Hz);
end function;
-- conversion functions
function to_time(f : FREQ) return TIME is
variable res : TIME;
begin
if (f < 1.0 kHz) then res := div(1.0 Hz, f) * 1.0 sec;
elsif (f < 1.0 MHz) then res := div(1.0 kHz, f) * 1.0 ms;
elsif (f < 1.0 GHz) then res := div(1.0 MHz, f) * 1.0 us;
elsif (f < 1.0 THz) then res := div(1.0 GHz, f) * 1.0 ns;
else res := div(1.0 THz, f) * 1.0 ps;
end if;
assert FALSE report "to_time: f= " & to_string(f) & " return " & to_string(res) severity note;
return res;
end function;
-- convert physical types (TIME, FREQ) to standard type (REAL)
function to_real(t : TIME; scale : TIME) return REAL is
begin
if (scale = 1.0 fs) then return div(t, 1.0 fs);
elsif (scale = 1.0 ps) then return div(t, 1.0 ps);
elsif (scale = 1.0 ns) then return div(t, 1.0 ns);
elsif (scale = 1.0 us) then return div(t, 1.0 us);
elsif (scale = 1.0 ms) then return div(t, 1.0 ms);
elsif (scale = 1.0 sec) then return div(t, 1.0 sec);
else report "to_real: scale must have a value of '1.0 <unit>'" severity failure;
end if;
end;
function to_real(f : FREQ; scale : FREQ) return REAL is
begin
if (scale = 1.0 Hz) then return div(f, 1.0 Hz);
elsif (scale = 1.0 kHz) then return div(f, 1.0 kHz);
elsif (scale = 1.0 MHz) then return div(f, 1.0 MHz);
elsif (scale = 1.0 GHz) then return div(f, 1.0 GHz);
elsif (scale = 1.0 THz) then return div(f, 1.0 THz);
else report "to_real: scale must have a value of '1.0 <unit>'" severity failure;
end if;
end;
-- calculate needed counter cycles to achieve a given 1. timing/delay and 2. frequency/period
-- ===========================================================================
-- @param Timing A given timing or delay, which should be achived
-- @param Clock_Period The period of the circuits clock
-- @RoundingStyle Default = round to nearest; other choises: ROUND_UP, ROUND_DOWN
function TimingToCycles(Timing : TIME; Clock_Period : TIME; RoundingStyle : T_ROUNDING_STYLE := ROUND_TO_NEAREST) return NATURAL is
variable res_real : REAL;
variable res_nat : NATURAL;
begin
res_real := div(Timing, Clock_Period);
case RoundingStyle is
when ROUND_TO_NEAREST => res_nat := natural(round(res_real));
when ROUND_UP => res_nat := natural(res_real + 0.5);
when ROUND_DOWN => res_nat := natural(res_real);
when others => report "RoundingStyle '" & T_ROUNDING_STYLE'image(RoundingStyle) & "' not supported." severity failure;
end case;
report "res_real: " & REAL'image(res_real) severity note;
assert FALSE
report "TimingToCycles: " & CR &
" Timing: " & to_string(Timing) & CR &
" Clock_Period: " & to_string(Clock_Period) & CR &
" RoundingStyle: " & str_substr(T_ROUNDING_STYLE'image(RoundingStyle), 7) & CR &
" res_real = " & str_format(res_real, 3) & CR &
" => " & INTEGER'image(res_nat)
severity note;
return res_nat;
end;
function TimingToCycles(Timing : TIME; Clock_Frequency : FREQ; RoundingStyle : T_ROUNDING_STYLE := ROUND_TO_NEAREST) return NATURAL is
begin
return TimingToCycles(Timing, to_time(Clock_Frequency), RoundingStyle);
end function;
-- convert and format physical types to STRING
function to_string(t : TIME; precision : NATURAL := 3) return STRING is
variable unit : STRING(1 to 3) := (others => NUL);
variable value : REAL;
begin
if (t < 1.0 ps) then
unit(1 to 2) := "fs";
value := to_real(t, 1.0 fs);
elsif (t < 1.0 ns) then
unit(1 to 2) := "ps";
value := to_real(t, 1.0 ps);
elsif (t < 1.0 us) then
unit(1 to 2) := "ns";
value := to_real(t, 1.0 ns);
elsif (t < 1.0 ms) then
unit(1 to 2) := "us";
value := to_real(t, 1.0 us);
elsif (t < 1.0 sec) then
unit(1 to 2) := "ms";
value := to_real(t, 1.0 ms);
else
unit := "sec";
value := to_real(t, 1.0 sec);
end if;
return str_format(value, precision) & " " & str_trim(unit);
end function;
function to_string(f : FREQ; precision : NATURAL := 3) return STRING is
variable unit : STRING(1 to 3) := (others => NUL);
variable value : REAL;
begin
if (f < 1.0 kHz) then
unit(1 to 2) := "Hz";
value := to_real(f, 1.0 Hz);
elsif (f < 1.0 MHz) then
unit := "kHz";
value := to_real(f, 1.0 kHz);
elsif (f < 1.0 GHz) then
unit := "MHz";
value := to_real(f, 1.0 MHz);
elsif (f < 1.0 THz) then
unit := "GHz";
value := to_real(f, 1.0 GHz);
else
unit := "THz";
value := to_real(f, 1.0 THz);
end if;
return str_format(value, precision) & " " & str_trim(unit);
end function;
end package body;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.utils.all;
use work.strings.all;
use work.physical.all;
entity Top_PhysicalTest is
Port (
Clock : in STD_LOGIC;
Input : in STD_LOGIC;
Output : out STD_LOGIC
);
end;
architecture rtl of Top_PhysicalTest is
-- configuration
constant CLOCK_FREQ : FREQ := 100 MHz;
constant SHIFTER_DELAY : TIME := 125 ns;
-- calculations
constant SHIFTER_DELAY_CYCLES : NATURAL := TimingToCycles(SHIFTER_DELAY, CLOCK_FREQ);
constant SHIFTER_BITS : NATURAL := SHIFTER_DELAY_CYCLES + 2; -- to prevent an underrun, while Vivado has a bug
signal Shifter_nxt : STD_LOGIC_VECTOR(SHIFTER_BITS - 1 downto 0);
signal Shifter_d : STD_LOGIC_VECTOR(SHIFTER_BITS - 2 downto 0) := (others => '0');
begin
assert false report "CLOCK_FREQ: " & FREQ'image(CLOCK_FREQ) severity note;
assert false report "CLOCK_FREQ: " & to_string(CLOCK_FREQ) severity note;
assert false report "DELAY: " & TIME'image(SHIFTER_DELAY) severity note;
assert false report "DELAY: " & to_string(SHIFTER_DELAY) severity note;
assert false report "CYCLES: " & INTEGER'image(SHIFTER_DELAY_CYCLES) severity note;
Shifter_nxt <= Shifter_d & Input;
Shifter_d <= Shifter_nxt(Shifter_d'range) when rising_edge(Clock);
Output <= Shifter_nxt(SHIFTER_DELAY_CYCLES);
end;
UDPT :: =用户定义的物理类型
我的观察:
问题:
注意:手动将我的问题从CR移到SO.
我将错误删除到:
'image(..)
不再实施问题在Xilinx forum。
中报告答案 0 :(得分:1)
THz超出了Time类型的最小范围(参见IEEE Std 1076-2008,16.3 Package standard,&#34; type INTEGER是range implementation_defined;&#34;,5.2.3 Integer types&#34 ; ...实现可以限制类型为universal_integer的整数类型的范围约束的范围。但是,实现应允许声明任何整数类型,其范围完全包含在-2147483647和+2147483647的范围内。 #34;,输入FREQ)。
从头顶算起,行:pos 272:65,298:55,384:51。
我对你的结果并不感到惊讶。
预分频器。使用两个整数,一个用于某个整数单位的一小部分。或者使用位数组类型,它将问题转换为字符串转换之一。
在类型声明中,您似乎不太可能让Xilinx支持范围的64位整数:
type FREQ is range 0 to INTEGER'high units
Hz;
kHz = 1000 Hz;
MHz = 1000 kHz;
GHz = 1000 MHz;
THz = 1000 GHz;
end units;
算术运算完毕,没有Vivaldo。它表示支持32位整数。
正如Bill Lynch所说,物理类型可以在IEEE Std 1076-1987,3.1.3物理类型,第3-5页中找到。
这证明了在合成之前使用VHDL分析器/模拟器验证设计规范的优势:
ghdl -a top_physicaltest.vhdl
top_physicaltest.vhdl:272:65:静态常量违反边界
top_physicaltest.vhdl:298:55:静态常量违反边界
top_physicaltest.vhdl:384:51:静态常量违反边界
使用ghdl-0.31我增加了FREQ的HIGH界限:
type FREQ is range 0 to 2**61 units
这是有效的,因为ghdl的通用整数是64位,物理类型可以有一个通用的整数范围。
(ghdl中有一个bug,应该使用相当于2 ** 63 -1的整数,Tristan修正了我认为ghdl-0.33。我想知道2 ** 61是一个安全的界限。)
分析。您可以注意到Real Range限制了您执行任何缩放的准确性。没有检查,我无法告诉你ghdl是否有64位通用Real来匹配它的64位通用整数。
然后分析,精心制作并运行Top_PhysicalTest(测试平台)。
ghdl -r top_physicaltest
./top_physicaltest:error:物理检查失败在物理上.vhdl:117
ghdl:编译错误
-- raw_format_* functions
function raw_format_nat_dec(value : NATURAL) return STRING is
begin
return INTEGER'image(value);
end function;
-- str_format_* functions
function str_format(value : REAL; precision : NATURAL := 3) return STRING is
constant s : REAL := sign(value);
constant int : INTEGER := integer((value * s) - 0.5); -- force ROUND_DOWN
constant frac : INTEGER := integer((((value * s) - real(int)) * 10.0**precision) - 0.5); -- force ROUND_DOWN
constant res : STRING := raw_format_nat_dec(int) & "." & raw_format_nat_dec(frac); -- LINE 117
begin
-- assert (not MY_VERBOSE)
-- report "str_format:" & CR &
-- " value:" & REAL'image(value) & CR &
-- " int = " & INTEGER'image(int) & CR &
-- " frac = " & INTEGER'image(frac)
-- severity note;
return ite((s < 0.0), "-" & res, res);
end function;
其中,第117行是包体中包含常量res的声明。
来自std.standard:
subtype NATURAL is INTEGER range 0 to INTEGER'HIGH;
ghdl中的类型整数是32位精度(在综合工具中普遍存在)。
这看起来像'IMAGE
错误我可能会或可能没有通知Tristan(Yup!,见#31 Type conversion subtype constraint check not performed,它也固定为0.33(gee I&#39;我想跳过0.32我认为))。
所以我尝试了nvc,它也有64位通用整数,我之前提交了一些与表达式有关的错误:
nvc -a physical.vhdl
nvc -e Top_PhysicalTest
**致命:表达式不能折叠成整数常数
文件physical.vhdl,第412行
Line 412在Top_PhysicalTest中:
constant CLOCK_FREQ : FREQ := 100 MHz;
constant SHIFTER_DELAY : TIME := 125 ns;
-- calculations
constant SHIFTER_DELAY_CYCLES : NATURAL := TimingToCycles(SHIFTER_DELAY, CLOCK_FREQ);
constant SHIFTER_BITS : NATURAL := SHIFTER_DELAY_CYCLES + 2; -- to prevent an underrun, while Vivado has a bug
constant SHIFTER_BITS : NATURAL := SHIFTER_DELAY_CYCLES + 2; -- to prevent an underrun, while Vivado has a bug
signal Shifter_nxt : STD_LOGIC_VECTOR(SHIFTER_BITS - 1 downto 0);
信号Shifter_nxt的声明。
(看起来像是一种不同类型的错误)。
答案 1 :(得分:0)