Electronics > FPGA

适用于8位计算机的FPGA VGA控制器

<< < (454/457) > >>

布莱恩·HG:

---引用自:nockieboy于2020年12月20日,下午04:13:17 --- I'我们使用各种尺寸的椭圆进行了一些仿真-附加了一些典型的变化,并测试了0-40像素(和其他尺寸的X和Y的排列),并且未检查所有像素)-在模拟输出中都是完美的像素与FreeBasic代码提供的预期输出进行比较。

我可以'不能破坏它。 :-+

-结束报价-
最终的1x20仿真结果是错误的。 你确定你没有'更改输入并忘记运行/更新结果?
尝试使用除完美圆或垂直线附近的至少一种形状...

Nockieboy:
嗯,看起来我弄乱了图像或其他东西-输出很好,它与geo.bas和我所有的东西匹配'到目前为止已经扔了它。

布莱恩·HG:
Nockieboy改进FMAX的教程。  Part 1.

  Ok, for the new 'ellipse_generator.sv',当以32位元运行核心时,我们无法通过所需的125MHz。 目前,我们的极限是117 MHz。 查看时序报告,我们看到很多信号(来自节点)p [#],px [#],ry2 [#],px [#]不会到达寄存器p [#](到节点)。 最差的信号延迟0.54ns到达(-xxx ns处于松弛状态)。  See:


(不幸的是,在QuartusPrime中为CV编译时,我认为它们仅提供1个最坏情况的时序信号。  I'确保有一种方法可以增加时序报告的大小,以使您有更好的概览。)

 好的,因此我们需要查看代码以了解P等于什么,以及为什么这些信号馈入P太晚,以及我们如何能够改善这种情况。
 这是我开始解决问题的方式,这里使用的技术是中间的,还有其他方法,但这是我尝试维护当前结构的第一个方法。 首先看一下我在哪里注册'p' = to something.  Here:


---代码:---当sub_function == 3时
p <= (alu_mult_y + 2)>> 2 ;
当sub_function == 6时
p <= p + ry2- alu_mult_y ;
当sub_function == 7时&& (像素 <= py) && (p <= 0)
p <= p + ry2+ (像素 + (ry2<<1)) ;
当sub_function == 7时&& (像素 <= py) && !(p <= 0)
p <= p + ry2+ (像素 + (ry2<<1)) - (py - (rx2<<1)) ;
-结束码-

  Below, I'm向您展示了编译器如何构造用于计算的逻辑'p'(约)。请记住,FPGA并不是将CPU的内存变量传递给单个ALU或从单个ALU传递CPU的CPU,因此上述所有指令都需要组合为一组门以构成32位寄存器'p'等于125MHz核心时钟的以下功能。
(是的,我试图做到这一点,所以请对其进行分析...)


---代码:--- p<=(p *(子功能!= 3))+
     ((((((alu_mult_y + 2)>>2)* sub_function == 3)))-
     (((((alu_mult_y)*子功能== 6)))+
     (( ry2* ( sub_function == 6 || (sub_function == 7 && (像素 <= py)) ) )) +
     (( (像素 + (ry2<<1))*((sub_function == 7)&& (像素 <= py)) )) -
     (( (py - (rx2<<1))*((sub_function == 7)&& (像素 <= py) && !(p <= 0)) )) ;
-结束码-

是的,所有这些... 虽然,编译器会尽可能简化代数,但这是32位寄存器的混乱'p'必须与所有其他32位变量相等,这些变量将为D触发器32位数据输入计算提供大量的门。 显然,必要的门的整体质量将无法在注册时保证正确的解决方案'p'(当然还有其他一切)的时钟频率高于117MHz。

  'p'取决于sub_function [3:0]的数字(px<= py), !(p <= 0),再加上32位寄存器'p'本身,因为它已被添加到自己,然后alu_mult_y都加了2,然后再次自然地移动了rx2,ry2,px和py。


---代码:--- sub_function     = 4 bits
(像素<=px)        = 32+32 bits
(p<=0)          = 32位
'p'             = 32 bits
alu_mult_y     = 32位* 2 = 64(移位和非移位)
rx2,ry2,px2,py3 =​​ 32 * 4bits = 128

总计:324位/ 324线/信号产生结果'p'.
-结束码-

这是我执行的测试。 我所做的就是让p<在sub_function == 3时为= 0,并且摆脱了sub_function 6,这将等式更改为:


---代码:--- p<=(p *(子功能!= 3))+
     (( ry2+ (像素 + (ry2<<1)))*((sub_function == 7) && (像素 <= py)) ) -
     (( (py - (rx2<<1))*((sub_function == 7)&& (像素 <= py) && !(p <= 0)) )) ;
-结束码-

我们摆脱了第一个方程式中需要的324条线中的2 * alu_mult_y条,从而减少了64条线。
现在,编译器为我们提供了132MHz的FMAX,并查看了最坏情况下的时序路径,'p'(到节点)实际上排在列表的第三位,这意味着上面还有其他限制系统的频率为132MHz。



因此,我们有一个目标,即如何合并这两个设置操作:

---代码:--- p<= (alu_mult_y + 2)>> 2 ;
p <= p + ry2- alu_mult_y ;
-结束码-
并且不要在上述测试132MHz FMAX方程中增加任何复杂度/依赖性。

我决定使用的技巧是临时存储'(alu_mult_y + 2) >> 2' in ry2and then just use the beginning of what already exists in the equation:
(删除红色部分并保持开头...)
p <= p + ry2+ (像素 + (ry2<<1)) - (py - (rx2<<1)) ;

好的,技巧1,重复使用ry2。
在上面的sub_function == 3中,我做了'ry2 <= (alu_mult_y + 2)>> 2'.  Since ry2only has 1 = alu_mult_y, adding this here doesn'真的减慢了寄存器的速度。
现在在sub_function == 4期间,我做了'p <= ry2'.  Since 'ry2' is added to 'p'其他地方,这没有't向主机添加其他信号依赖项'p <= 'blahhh blahhh blahhh' ' equation.

Sub_function==5, since ry2will now have been updated to the next value, I just added:
p <= p + ry2;
再次,没有新的依赖关系来计算主方程'P'.

Sub_function == 6,好的,别无选择,我不得不这样做:
p <= p -alu_mult_y;
这增加了32个新的依赖位。  Let's尝试编译并查看结果。



如您所见,新的FMAX为121MHz,只有4个信号太慢而无法执行。
现在,我们知道摆脱这一点'- alu_mult_y'可以让我们用铁锹清除障碍,但不做后空翻's try 1 thing first.

rx2& ry2are the square of the Xr &12位数字,我已将其强制为32位。
由于它们只是0到2047之间的正整数,因此结果将始终是一个无符号的22位数字。  Let'看我是否强迫这些'UNSIGED 22 bits' since rx2 &ry2在那个巨大的地方经常被使用' p <=等等等等等等'.

好吧,谈论关于清除126MHz的障碍...
我们还将926个逻辑元素扩展到888个。

问题,我们能做得更好吗?
另一个解决方案可能是保留临时寄存器:
p <= (alu_mult_y + 2)>> 2 ;
p <= p + ry2- alu_mult_y ;
然后在最后一步。使p<= that 1 register.
优化尝试#2以及仅对Rx2进行测试&Ry2 = 22bits,带有明天的原始代码。

测试V9附加的意大利面条代码。
除非有错误,否则不需要快照...
(我也发现我'm两次相同地无用地重复执行2个子函数,接下来将进行更正。)

Nockieboy:

---引用自:BrianHG于2020年12月21日,上午04:13:49-Nockieboy改进FMAX的教程。  Part 1.

...

  Below, I'm向您展示了编译器如何构造用于计算的逻辑'p'(约)。请记住,FPGA并不是将CPU的内存变量传递给单个ALU或从单个ALU传递CPU的CPU,因此上述所有指令都需要组合为一组门以构成32位寄存器'p'等于125MHz核心时钟的以下功能。
(是的,我试图做到这一点,所以请对其进行分析...)


---代码:--- p<=(p *(子功能!= 3))+
     ((((((alu_mult_y + 2)>>2)* sub_function == 3)))-
     (((((alu_mult_y)*子功能== 6)))+
     (( ry2* ( sub_function == 6 || (sub_function == 7 && (像素 <= py)) ) )) +
     (( (像素 + (ry2<<1))*((sub_function == 7)&& (像素 <= py)) )) -
     (( (py - (rx2<<1))*((sub_function == 7)&& (像素 <= py) && !(p <= 0)) )) ;
-结束码-

是的,所有这些... 虽然,编译器会尽可能简化代数,但这是32位寄存器的混乱'p'必须与所有其他32位变量相等,这些变量将为D触发器32位数据输入计算提供大量的门。 显然,必要的门的整体质量将无法在注册时保证正确的解决方案'p'(当然还有其他一切)的时钟频率高于117MHz。
-结束报价-

 :o :o :o

哇。 好吧,首先感谢您的发布-它对于理解什么非常有用's going on 'under the hood'编译器的功能以及确定HDL中的Fmax瓶颈。  I mean... damn!! 而且我想我也了解其中的大部分内容!  ;D

好的这里's what I'自从您获得p寄存器的最新代码以来,'修改了代码-拔出p寄存器为其分配了值的所有行:


---代码:---如果(sub_function == 4)
p <= p + ry2;

如果(子功能== 5)
p <= p + ry2;

如果(子功能== 6)
p <= p -alu_mult_y ;

如果(子功能== 7)&& (像素 <= py) && (p <= 0)
p <= p + ry2+ (像素 + (ry2<<1)) ;

如果(子功能== 7)&& (像素 <= py) && !(p <= 0)
p  <= p + ry2+ (像素 + (ry2<<1)) - (py - (rx2<<1)) ;
-结束码-

然后,我尝试编译器正在做些什么,以获取等效于这些HDL的规则:


---代码:--- p<= p +(((子功能  > 3 ) && ( sub_function != 6 ) ) * ry2)
       -   ((子功能== 6)* alu_mult_y)
       +(((子功能== 7)&& ( px <= py))*(px +(ry2<<1) ) )
       -(((子功能== 7)&& ( px <=  py ) && ( p > 0) ) * ( py - ( rx2<<1) ) )
-结束码-

如果我'我已经正确理解并正确解决了问题,这看起来比之前的混乱要简单得多'd昨晚做了Fmax表演。  :-+


---引用自:BrianHG于2020年12月21日,上午04:13:49-  'p'取决于sub_function [3:0]的数字(px<= py), !(p <= 0),再加上32位寄存器'p'本身,因为它已被添加到自己,然后alu_mult_y都加了2,然后再次自然地移动了rx2,ry2,px和py。


---代码:--- sub_function     = 4 bits
(像素<=px)        = 32+32 bits
(p<=0)          = 32位
'p'             = 32 bits
alu_mult_y     = 32位* 2 = 64(移位和非移位)
rx2,ry2,px2,py3 =​​ 32 * 4bits = 128

总计:324位/ 324线/信号产生结果'p'.
-结束码-

-结束报价-

我知道'与人们在FPGA上进行的更为复杂的项目相比,这没有什么可比的,但令我惊讶的是,装配工正试图仅为这一项功能而在芯片周围路由324通道数据。 :o


---引用自:BrianHG于2020年12月21日,上午04:13:49-测试V9附加的意大利面条代码。
除非有错误,否则不需要快照...
(我也发现我'm两次相同地无用地重复执行2个子函数,接下来将进行更正。)
-结束报价-

是的,子功能4和5可以与下面的行合并为一个,对吗?


---代码:--- p<= p + ( ry2<< 1 ) ;
-结束码-

或者,最好改为执行此操作,然后将其合并到步骤5中以完全删除步骤6? 编辑:刚刚意识到-alu需要2个时钟来使其结果有效,因此这可能不是有效的解决方案。  :-\


---代码:---如果(sub_function == 4)
p <= p + ry2;

如果(子功能== 5)
p <= p + ry2- alu_mult_y ;
-结束码-

这样可以从sub_function中删除一个步骤,但是也可以简化整个系统的逻辑,如下所示:

p <= p +(((子功能  > 3 ) && ( sub_function != 6 ) ) * ry2)
       -   ((子功能== 6)* alu_mult_y)
      +(((子功能== 7)&& ( px <= py))*(px +(ry2<<1) ) )
      -(((子功能== 7)&& ( px <=  py ) && ( p > 0) ) * ( py - ( rx2<<1) ) )

...可能会变成这样:

p <= p +((子函数  > 3 ) * ry2)  <<-通过一个依赖关系简化了这一行
       -   ((子功能== 5)* alu_mult_y)
      +(((子功能== 6)&& ( px <= py))*(px +(ry2<<1) ) )
      -(((子功能== 6)&& ( px <=  py ) && ( p > 0) ) * ( py - ( rx2<<1) ) )

Nockieboy:
Just as an aside, I'现在已经获得了附带的项目构建,但是它似乎正在使用某种宏功能来设置TMDS输出,并且我无法在Pin Planner中分配引脚以使该项目能够通过DVI Tester在EasyFPGA板上使用。 引脚已分配,并且仅在我进入引脚规划器时才可以读取。

I'我以为我应该从hdmi.sv中完全删除OBUFDS元素(第319-334行),然后连接tmds_current[]到输出引脚,同时反转_n引脚信号,这使我能够照常在引脚管理器中分配引脚。希望。 似乎OBUFDS使用了altera_gpio_lite宏功能,但我可以'在IP目录中找不到它,所以我可以'似乎找不到它'将IO引脚分配给TMDS信号。

I'我可能会因为不仅仅从头做起而受到很多挫折,而且我喜欢能够输出HDMI信号并将音频包含在比特流中的承诺-那'与直接DVI相比,它的主要优点是'm插入了这个示例项目。

导航

[0] 讯息索引

[#] 下一页

[*] 上一页

感谢时出现错误
谢谢...
转到完整版