博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【黑金原创教程】【Modelsim】【第五章】仿真就是人生
阅读量:5348 次
发布时间:2019-06-15

本文共 64997 字,大约阅读时间需要 216 分钟。

声明:本文为黑金动力社区()原创教程,如需转载请注明出处,谢谢!


黑金动力社区2013年原创教程连载计划:


《FPGA那些事儿—Modelsim仿真技巧》REV5.0 PDF下载地址:


第五章 仿真就是人生

5.1 单向仿真与多向仿真

5.2仿真的变数——时钟用量

5.3 仿真的变数——信号数量与信号方向

5.4 理想变数与物理变数

5.5 仿真的必然——特定条件

5.6 仿真迷宫①

5.7 仿真迷宫②

5.8 主动思想

总结:


第五章 仿真就是人生

5.1 单向仿真与多向仿真

l 有人认为学习仿真就是使用Modelsim,不过Modelsim的功能非常接近电视机;

l 有人认为学习仿真就是认识时序,时序是可视化的活动记录而已;

l 有人认为学习仿真就是激励,可是激励只是模块的刺激还有反应过程而已;

l 有人认为学习仿真就是验证语言,但是验证语言只是用来描述激励内容而已。

这个不是那个也不是,那么仿真又是什么呢?有人曾经告诉过笔者,轮胎,方向盘还有遮罩镜虽然是车子的部件,但是它们都不是车子。仿真也有同样的道理,Modelsim,时序,激励还有验证语言(综合语言),充其量只是仿真的部件而已,而不是仿真本身。曾经何时,笔者也认为仿真就是学习 Modelsim,后来才醒觉这一切都是传统流派的阴谋,不过发现已晚,因为笔者已经陷入其中难以自拔。

仿真好比一处异世界,这个异世界虽然用来再现现实世界的种种细节,但是这个世界却有自己法则还有自然。这是一处并行,多变数,还有令人绝望的空间,过往的一切顺序知识已经不再适用,为了在这个危机四处的环境活下去,我们必须做好充分的准备。在此,Modelsim是一件高科技的显示器,它可以接收周围的信号然后将期显示化。不过,Modelsim显示的内容好比别人眼睛看见的东西,属于第二次视像。

这个世界存在许多奇怪的对象,它们没有听觉,视觉,触觉与味觉,无论我们怎么比手画脚,信息也无法传达进去。异世界的对象,大多数的行为都是静态,它们仅对信号有所感觉,因此激励成为唯一一个手段可以产与这个世界互动。如果我们没有给予适当的刺激,它们就无法给予预期的反应 ... 不过很庆幸的是,外来者来到这个异世界都会赋予一股神奇的描述力量,这股力量不仅可以用来描述信号,这股力量也能描述对象。这股力量有两种属性,其一就是综合,其二就是验证。

第二章的目的就是要求读者熟悉使用 Modelsim这件高科技产物;第三章的目的就是要求读者认识异世界的法则;第四章的目的就是要求读者熟悉“力量”... 读者须理解,异世界是自由结构的空间,所以哪里的居民没有结构一点也不奇怪。力量除了描述信号给予对象激励以外,力量也能用来描述最基本的结构。我们只要满足上述一切条件,我们在这个世界才有最起码的10%生存率保证。

有些同学可能会疑惑道:“既然异世界如此危险,为什么我们还要冒着生命危险去冒险呢?”,让笔者用故事来回答吧。

很久以前,有一处寸草不生绿洲甚少,被当地人称为禁地的沙漠平原,哪里不曾有人类涉足。有一位叫做蒂沙的当地女性,它从小就相信那片沙漠的彼岸,存在传说中的白骆驼之墓,白骆驼被当地人认为是圣兽,崇拜程度就像东方的龙与凤,西方的独角兽与飞马。不过,当地的环境文化非常保守,年幼从家,年轻从夫,年老从孙,但是不过21岁的蒂沙终于抛弃故乡,涉足沙漠寻找传说。

蒂沙走了三天三夜的路程,环境恶劣还有前路茫茫 ... 就算如此,她还是继续前进。一个夜晚,她不小心卷入强烈的沙尘暴当中,夜晚的沙尘暴属于极寒,冷漠的沙尘渐渐夺走她身上的体温。蒂沙的精神就算不曾放弃,不过已经接近极限的肉体却背叛她,然后意识逐渐离去,如铅一样重的眼皮也随之下沉。迷糊中,她感觉自己被毛茸茸还有发着白光的躯体包裹着,她忽然意识自己正躺在白骆驼的怀抱中,白骆驼注视着她,她也注视着白骆驼。然后,有一股声音传入她的心里 ...

“孩子,为什么要误闯禁地,这里不是人类该来的地方 ... ”心声道。

“传说,骆驼之墓可以告知追求者的命运,我想知道未来! ”,蒂沙回应道。

“......”,心声沉默。

“人类的孩子,这里就是妳的终点 ... ”,心声道。

从此以后,再也没有人看见那蒂沙的身影 ... 这是一个寓言的故事,故事告诉我们,蒂沙的人生有两个重要的抉择,其一就是找个丈夫嫁去,生孩子做婆婆,最后在亲人的哀悼中离开人世;其二就是踏足禁地寻找传说中的白骆驼之坟。某位诗人曾经描述过,平凡又单调的人生称为单向人生,曲折又多难的人生称为多向人生,然而不管是那一种人生,只要找到生命的意义那就是最好的人生。

很明显的是,蒂沙选择曲折多难的人生,在旁人眼中她可能愚蠢至极,不过旁人始终没有资格对她的人生指指点点,因为旁人不是蒂沙本身,旁人也无法理解蒂沙身为当局者的处境,情绪,还有心境状态。在她曲折又多难的人生中,可能她会死在旅途中,也有可能她已被白骆驼接济,结果究竟是如何只有蒂沙自己知道。

它曾经告诉过笔者,仿真不过是人生的一场缩影,仿真对象(蒂沙)就是人生的主人,预想所要的仿真结果就是仿真对象需要寻找的生命意义。我们创建仿真环境的人,责任好比白骆驼一样,我们必须引导仿真对象(蒂沙)流向有意义的人生。同样,平凡单调的仿真称为单向仿真,曲折多难的仿真称为多向仿真。

仿真是充满许多可能性的空间,单向仿真的出现概率非常低,单向仿真最常见的例子就有门级仿真,或者一些“超简单模块”的仿真而已。

图5.1.1 单向结果(仿真模型①)。

如图5.1.1所示,这是仿真模型①,也是单向仿真最常用的仿真模型,信号永远流向一方。我们可以将图5.1.1想象为,激励内容好比蒂沙年幼的时候,仿真对象是蒂沙年轻的时候,wave界面是蒂沙年老的时候,信号A是蒂沙称为人妻的阶段,信号B是蒂沙成为婆婆的阶段。图5.1.1的整体感觉好比蒂沙单调又平凡的一生。紧接着,请读者打开exp20 瞧瞧,单向仿真究竟拥有什么最基本的模样。

exp20_simulation.vt
1.    `timescale 1 ps/ 1 ps2.    module exp20_simulation();  3.    4.        reg CLOCK;  5.        reg RESET; 6.        reg [3:0]rSelect;7.        reg [7:0]WrData;8.         9.         /***********************************/10.    11.        initial                                                12.        begin      13.             RESET = 0; #10; RESET = 1;14.             CLOCK = 1; forever #5 CLOCK = ~CLOCK;15.         end16.         17.         /***********************************/18.        19.        always @ ( * )20.            case( rSelect )21.             22.                4'b0001: WrData = 8'hAA;23.                4'b0010: WrData = 8'hBB;24.                4'b0100: WrData = 8'hCC;25.                4'b1000: WrData = 8'hDD;26.            27.            endcase28.         29.         /***********************************/30.         31.        reg [3:0]i;32.    33.        always @ ( posedge CLOCK or negedge RESET )34.            if( !RESET )35.                begin36.                    i <= 4'd0;37.                    rSelect <= 4'd0;38.                end                39.              else 40.                  case( i )41.                    42.                        0: 43.                         begin rSelect <= 4'b0001; i <= i + 1'b1; end44.                         45.                        1:46.                        begin rSelect <= 4'b0010; i <= i + 1'b1; end47.                        48.                        2:49.                        begin rSelect <= 4'b0100; i <= i + 1'b1; end50.                        51.                        3:52.                        begin rSelect <= 4'b1000; i <= i + 1'b1; end53.                        54.                        4:55.                        i <= i;56.                    57.                    endcase58.                    59.        /***********************************/        60.                                                                                   61.    endmodule

第1行用来声明时钟刻度为 1ps/1ps;第4~7是仿真相关的寄存器;第11~15行是环境输入;第19~27行是仿真对象 ... always @ (*) 主要是用来建立组合逻辑,其中建模对象是简单的输出选择器,别名又有加码器,根据 rSelect的输入结果,输出相关的 WrData,大致功能如下:

(一)rSelect输入4’b0001,WrData就输出 8’hAA;

(二)rSelect输入4’b0010,WrData就输出 8’hBB;

(三)rSelect输入4’b0100,WrData就输出 8’hCC;

(四)rSelect输入4’b1000,WrData就输出 8’hDD。

由于仿真对象的功能太简单了,所以笔者直接在激励文本当中建模。第33~57行是虚拟输入,步骤0为 rSelect 写入 4’b0001,然后将i递增以示下一个步骤 ... 步骤3为 rSelect写入 4’b1000,然后将i递增以示下一个步骤。

图5.1.2 exp20应用仿真模型①。

如图5.1.2所示,那是exp20应用仿真模型①以后的模样。激励内容(虚拟输入),经过rSelect刺激仿真对象(加码模块),然后再由仿真对象产生反应,将WrData的输出结果投射到wave界面当中。接下来,让我们一起瞧瞧 exp20的仿真结果:

图5.1.3 exp20的仿真结果。

图5.1.3是exp20的仿真结果,其中光标C0~C3分别指向4个时间点。如图5.1.3所示,T0之前是复位状态,WrData没有复位值所示呈现红线。T0的时候(C0指向的地方),虚拟输入在步骤0为rSelect输入 4’b0001,结果仿真对象经由WrData输出即时值 8’hAA,然后将i递增以示下一个步骤。在T1的时候(C1指向的地方),虚拟输入在步骤1为rSelect输入 4’b0010,结果仿真对象经由 WrData输出即时值 8’hBB,完后将i递增以示下一个步骤。

在T2的时候(C2指向的地方),虚拟输入在步骤2为rSelect输入 4’b0100,结果仿真对象经由 WrData输出即时值 8’hCC,然后再将i递增以示下一个步骤。在T3的时候(C3指向的地方),虚拟在步骤3为rSelect输入 4’b1000,结果仿真对象经由 WrData输出即时值 8’hDD,最后再将i递增以示下一个步骤。

exp20是门级仿真,同时也是单向仿真最典型的例子。如图5.1.2所示,数据永远向一方流动,而且数据的变化状态也非常明了,输入什么就输出什么。此外,输出结果都是在输入给予之后不到一个时钟(或者一个时钟)之内出现 ... 啊!真是多么单调又平凡的仿真呀,仿真对“刷”一声就这样结束了。好了,感叹也十分了 ... 笔者也该换换心情介绍多向仿真。

图5.1.4 仿真模型②。

仿真是一种并行又充满许多可能性的空间,因此多向仿真出现的概率完全是压倒性的,那么甚么又是多向仿真呢?多向仿真好比蒂沙的曲折人生,人生的尽头存在许多未知的可能性,她有可能在旅途中意外死去,她也有可能抵达目的地,不管怎么样,这些可能性不过是其中一种结局的形势而已。如图5.1.4所示,这是仿真模型②,仿真模型②相比①,信号再也不是单向而是多向化,因此仿真模型②不可能是单向仿真。

多向仿真的典型应用除了门级仿真以外什么都是。换句话说,曲折多难是仿真对象的默认人生。说着说着,笔者的心情也开始沉重起来。具体内容,笔者还是用实验来讲话吧,打开 exp21:

exp21_simulation.vt
1.    `timescale 1 ps/ 1 ps2.    module exp21_simulation();  3.    4.        reg CLOCK;  5.        reg RESET; 6.        reg [7:0]rD,rQ;7.         8.         /***********************************/9.    10.        initial                                                11.        begin      12.             RESET = 0; #10; RESET = 1;13.             CLOCK = 1; forever #5 CLOCK = ~CLOCK;14.         end15.         16.         /***********************************/17.        18.        reg [7:0]D1,D2,D3;19.        20.        always @ ( posedge CLOCK or negedge RESET )21.            if( !RESET )22.                begin23.                    { D1,D2,D3 } <= { 8'd0, 8'd0, 8'd0 };24.                end25.            else            26.                begin27.                     D1 <= rD; 28.                     D2 <= D1;29.                     D3 <= D2;30.                end    31.         32.         /***********************************/33.         34.        reg [3:0]i;35.    36.        always @ ( posedge CLOCK or negedge RESET )37.            if( !RESET )38.                begin39.                    i <= 4'd0;40.                    rD <= 8'd0;41.                end                42.              else 43.                  case( i )44.                    45.                        0: 46.                         begin rD <= 8'hAA; i <= i + 1'b1; end47.                         48.                        1,2,3:49.                        begin rD <= 8'd0; i <= i + 1'b1; end50.                        51.                        4:52.                        begin rQ <= D3; i <= i + 1'b1; end53.                        54.                        5:55.                        i <= i + 1'b1;56.                    57.                    endcase58.                    59.        /***********************************/        60.                                                                                   61.    endmodule

第20~30行是仿真对象,它是简单的移位寄存器,其中D1读入rD(第27行),D2读入D1(第28行),D3读入D2(第29行)。第36~51行是虚拟输入,虚拟输入首先在步骤0为rD输入 8’hAA,然后等待3个时钟,最后在步骤4读入D3的结果。

图5.1.5 exp21应用仿真模型②。

图5.1.5显示 exp21应用仿真模型2的结果,其实exp21是一种简单的搬运游戏。首先虚拟输入将数据 8’hAA送给仿真对象的D1,然后D1又将数据送给D2,D2紧接着送给D3,最后再由D3返回虚拟输入的手中。话虽如此,游戏的结果却充满许多可能性,

不过在此之前,先让我们先来瞧瞧 exp21的仿真结果。

图5.1.6 exp21的仿真结果。

图5.1.6是exp21的仿真结果,其中光标C0~C4分别指向5个时间点。C0指向的地方是时间点T0,此刻虚拟输入开始为 rD赋值 8’hAA,然后将i递增以示下一个步骤(搬运游戏开始)。C1~C3指向的地方(T1~T3),分别是仿真对象相互传递数据的过程,数据传递至少需要一个时钟是时序不变的表现,因此仿真对象的D1在T1的时候读取WrData的过去值 8’hAA,D2在T2的时候读取D1的过去值 8’hAA,D3在T3的时候读取D2的过去值 8’hAA。完后,D3在T3的未来输出数据 8’hAA。

C1~C3也同样指向虚拟输入的步骤1~步骤3,不过虚拟输入没有采取任何行动,而是耐性等候数据回递。C4指向(T4)虚拟输入的步骤4,此刻虚拟输入读取 D3的过去值 8’hAA,rQ输出 8’hAA的未来值。

===================================================================

exp20是单向仿真的例子,exp21则是多向仿真的例子,同学可能会很好奇道:“为何笔者要故意区分仿真成为单向和多向呢?”,这位同学千万别这么认为,一些视以为常的事情,往往背后却隐藏着许多不可告人的细节,这些细节虽小但足够影响整个仿真的形势。在此之前,同学还是先思考一下,仿真是什么?为甚么我们要仿真?

最简单的问题往往是最复杂的问题 ... 根据笔者的认为,仿真的本意就是联系激励内容

,仿真对象还有时序结果,并且做出解析,这一动作笔者也称为 ”仿真信息解析“。事实上,单向仿真还有多向仿真之间存在巨大差别的信息量,单向仿真的信息量好比一块小饼干,我们有可能一口吃掉。反之,多向仿真的信息量一般都是一块大蛋糕,如果一口吃不掉的话,我们又该怎么办呢?这就是区分单向仿真还有多向仿真的意义之处。

单向仿真非常直接,基本上没什么好谈的,所以解析仿真信息是一件轻松的事情。反之,多向仿真的仿真信息解析工作是一件苦差事,就让笔者用蒂沙的人生作出比喻。蒂沙有着两大人生抉择,亦即单向人生,还有多向人生。如果蒂沙选择单向人生,结果她活着会非常轻松,因为她只要“顺着”传统文化,结婚生子,然后死在亲人哀悼中,整场人生好不过是一只飞往单一处方向的飞矢而已。

多向仿真好比一群胡乱飞翔流失而已,然而只有一只流失会命中目标。因此我们必须无数穿梭在流失之间,寻找那唯一一只命中目标的箭矢。期间我们有可能找错对象,也有可能被流失所伤。

如果蒂沙选择多向人生,那么她的人生尽头就有许多种结局:

(一)她有可能旅途中意外死去;

(二)她有可能成功抵达沙漠尽头,不过那里没有传说中的白骆驼之墓;

(三)她有可能成功抵达沙漠尽头,然后找到的白骆驼之墓,不过是一片古迹而已;

(四)她有可能忍受不了孤独自寻短见;

(五)她有可能从中折返,放弃旅行;

(六)她有可遇见白骆驼。

如果我们根据故事作出推断的话,蒂沙的结局可能是一,二,三与六,不过对蒂沙而言最有意义的结局就是遇见白骆驼,因为白骆驼告诉她命运的答案。然而,蒂沙为了遇见白骆驼,她必须抛弃故乡遇见意外,不然第六种结局是不可能会发生的。如果将这些内容反映到仿真当中,多向仿真拥有无数信号,而且信号也是无数流向,因而产生许多仿真结果,但是只有一个流向只能迎来最有意义的结果。

此刻“仿真信息解析”工作是非常头痛的 ... 假设我们追踪信号A,信号A忽然180度折返,我们的注意力也要跟着折返,迎面而来的惯性有可能会冲晕脑袋。然后我们继续追踪信号A,可是信号A分支成为信号B与信号C,在此我们就要分半注意力同时追踪两个信号 ... 话说,读者累不累呢?

上述这些内容还不是最严重的问题,真正让笔者感觉害怕的是“可能性”。有些同学可能暂时无法理解这番话,不过不打紧,只要更紧笔者继续解释exp21,读者就会深感体会。

===================================================================

exp21有一件小细节,如果笔者不解释它,笔者就会觉得心痒痒直至坐立不安,笔者一直觉得奇怪:“为什么虚拟输入的rQ会如此偶然在时间点T4成功回收数据 8’hAA?”。偶然?偶然?偶然?不可能的!绝对不可能的!当中一定存有蹊跷。某位圣人说过,偶然会摧毁世界,所以万物都是必然。rQ成功回收数据 8’hAA绝对是必然,但是必然必须触发连环事件,满足所有特定条件以后才能实现。于是,笔者开始思考 ...

必然是将结局导向有意义结果的重要关键 ... 但是,如果结局有太多可能性,寻找必然是一件非常苦难的事情,因此笔者必须事先约束变数。

(一)完成一次性搬运游戏至少需要5个时钟。

(二)虚拟输入必须在T0为WrData赋值 8’hAA。

(三)数据传递必须遵守时序表现。

约束变数以后,rQ产生的可能性就会缩小到以下5种而已:

(一)rQ在T0接收到 8’h00;

(二)rQ在T1接收到 8’h00;

(三)rQ在T2接收到 8’h00;

(四)rQ在T3接收到 8’h00;

(五)rQ在T4接收到 8’hAA;

我们知道在5个可能性当中,只有第五个可能性才是最有意义的结局 ... 不过又是什么特定条件将过程引导到第五个可能性呢?

(一)数据8’hAA从WrData移向D1用了1个时钟。

(二)数据8’hAA从D1移向D3用了3个时钟。

(三)数据8’hAA从D3移向rQ用了1个时钟。

上述3个特定条件就是将结果引导到第五5个可能性。换句话说,上述3个特定条件就是第5个可能性的立旗事件(Flagging Event),任少一个必然是不会实现。完后,笔者得出如下结论:“由于笔者数约3变数,结果衍生5种可能性,为了将结局引导到第5个可能性,笔者必须满足3种特定条件。”,在此,有些同学可能会开始怀疑笔者 ... 是否开始精神错乱了?又变数,又必然,又特定条件什么的 ... 不,笔者很正常。

联系激励内容,仿真对象还有时序结果并且做出解读,笔者称呼为 ”仿真信息解析“。解析仿真信息原本是仿真最大的精髓,不过很遗憾的是 ... 人不是电脑,人不仅脑力有限,人的集中力也有时间限制,因此长时间解释仿真信息,无疑这是一种折寿的任务,最终还有可能演变爆肝的悲剧。

此外,exp21也告诉我们一个事实,亦即变数还会无限放大可能性,从而海量化仿真信息。假设,解释一条可能性需要耗费1千卡路里还有20十分钟,如果变数将可能性放大至10,我们就要消耗1万卡路里,还有花费200分钟去解释10条可能性。又如果变数不留情将可能性放大100倍,我们既不是要消耗10万卡路里,花费2000分钟去解释100条可能性吗?别开玩笑了,笔者不想爆肝也不想这样蹉跎青春。

庄子劝告华夏子孙,别用有限的躯体去追逐无限的梦想,这个道理同样也适用于在这种情况 ... 人类未曾做到“解析海量仿真信息”这种壮举 ,即使超人出现它也有可能需要耗费一生去解释信息。笔者不是在吓读者,笔者只是在述说事实而已 ... 曾经何时笔者也年轻过,自负过,冲动过,笔者相信自己终有一天可以成为勇者,于是笔者决心完成这一壮举。结果,笔者被人抬着濒死的身体回老家去 ...

在此,笔者用经历告知所有读者,仿真真正可怕的地方,不是学习 Modelsim,验证语言或者激励文本。仿真真正最可怕的地方是,解析让人窒息的海量仿信息。普通人的用脑习惯都是倾向左脑,因此逻辑思维,还有顺序操作就会成为默认的用脑模式。换句话说,如果没有旁人特意提醒,我们就会傻乎乎地一条一条可能性解析下去 ... 其实这是温水煮青蛙的死法,死在不知不觉之间。

最后,笔者可以郑重的说:“这个世界(仿真)是充满杀机的空间,稍有差池小命就会不保!过往一切,那些习以为常的顺序手段,已经一去不返 ... 留念它们只会威胁小命而已!”,因为变数会影响可能性的衍生数量,然而在无数个可能性之中,只有一个生还的可能性(符合预期的仿真结果),其余可能性就是各种死法。

因此,如何约束变数减少可能性,还有如何清晰化发特定条件让它更加容易触发,都是这个世界里(仿真)的生存战略。不过很遗憾的是,常规的仿真手段似乎没有这方面的概念。因此,我们必须重新思考,寻找另一种较为适合的仿真手段,好让我们在这个异世界(仿真)继续游走下去 ...

5.2仿真的变数——时钟用量

笔者在上一个小节说道,仿真最基本的本意是,联系激励内容,仿真对象,还有时序结果,然后作出解析,这种行为称为“仿真信息解析”。如果仿真不是单向仿真,那么仿真结果就会随着变数增大从而海量化仿真信息。此刻,解析仿真信息无疑是一种痛苦的工作。为了解决这种现象,在此之前我们知晓,何为仿真的变数?

算命师常常会如此狡辩道:“人生充满变数,算命结果不过是一种可能性而已,只要努力作人命运是可以改变的。”既然仿真是人生的缩影,仿真存在变数其实一点也不奇怪,不过传统流派却不怎么认为,因为传统流派是属于“爱拼才能赢”的自信份子。爱拼的人会在100个可能性当中都逐个尝试,直到成功为止。但是现实却告诉我们,10人打拼只有1个成功,其余9人成为人间悲剧。

说实话,笔者实在没有兴趣在100个可能性当中蹉跎青春,笔者认为人生短暂而且生命有限,反之如何用最小的力气去寻找最大的成果才是活着的艺术。因此,笔者必须晓得如何压缩可能性 ... 可能性是变数衍生的产物,因此约束可能性就会间接缩小可能性的产生数量,根据笔者的认识,多向仿真存在以下几种:

(一)时钟用量

(二)信号数量

(三)信号方向

时钟不管是仿真(虚拟建模)还是建模(实际建模)都是一个非常重要的概念,不过很遗憾的是 ... 传统流派偏偏喜欢使用仿真时间驱动仿真流逝,而不是时钟本身。这种行为本来就存在许多缺陷,除了流失时序表现,还有违背RTL级设计的本质以外,最终还会产生非常不协调的物理时序,说着说着心情也沉重起来了 ...

笔者以前曾用过i指向时钟,笔者这样做就是为了清晰化还有具体化时钟,不然的话,时钟是不会轻易被我们捉着的。时钟用量一般是指“一次性活动所需的时钟”,然而这种认识又可以分为全体时钟还有个体时钟。接着,就让笔者继续使用 exp21 简单的举例吧。

图5.2.1 exp21的仿真内容。

首先让我们简单回忆一下 exp21的仿真内容。如图5.2.1所示,激励内容先是(虚拟输入) 经由rD给仿真对象输入数据8’hAA;仿真对象是一个简单的移位寄存器,数据8’hAA在内部从D1游向D2至D3,然后数据 8’hAA又折返激励内容,紧接着rQ将数据8’hAA暂存并且投射在wave界面上。

图5.2.2 exp21的理想时序结果(个体时钟视角)。

如图5.2.2所示,这是exp21的理想时序结果,过程如下:

(一)rD在T0输出未来值8’hAA;

(二)D1在T1读入rD的过去值,并且输出未来值8’hAA;

(三)D2在T2读入D1的过去值,并且输出未来值8’hAA;

(四)D3在T3读入D2的过去值,并且输出未来值8’hAA;

(五)rQ在T4读入D3的过去值,并且输出未来值8’hAA;

读者有没有注意到?笔者故意为图5.22的T1~T3画上时钟沿,时钟沿总共有3个亦即仿真对象的一次性操作需要3个时钟用量,然而笔者将它们称为“个体时钟”。个体时钟是时间用量非常重要的一个概念,它是一种“当局者(微观)”的时钟视角。

图5.2.3 exp21的理想时序结果(整体体时钟视角)。

接着再让我们稍微更换一下时钟视角,如图5.2.3所示,笔者故意为添加5个时钟沿以示整体时钟,整体时钟是一种“旁观者(宏观)”的时钟视角。整体时钟除了T1~T3的个体时钟用量以外,又包含T0与T4这两枚整体沟通所需的时钟用量,因此整体的时钟用量有5个时钟。

笔者比较喜欢将模块看成有生气的活物,模块沟通是模块遵守时序表现传输数据的一种“自然”现象,如果模块之间按照时间点事件发生沟通,那么模块之间至少需要1个时钟用量。换句话说,只要模块遵守时序,那么沟通所需的时钟用量一般都是固定的。相比之下,个体时钟不仅非固定,它还会伴随功能的“复杂程度”而成正比关系。换言之,功能越复杂,个体时钟越多,整体时钟也会相续增加,时间用量因而增大,结果产生更多的可能性。

图5.2.4 exp21个体时钟增加以后的理想时序结果。

假设笔者增加移位模块的深度从原本的D1~D3变成D1~D4,亦即移位模块的个体时钟从原来的3个时钟变成4个的话,结果如图5.2.4所示,T1~T4是个体时钟,T0与T5是沟通所需的时钟耗量,那么 exp21 的一次性搬运游戏至少需要6个时钟 ... 换句话说,时钟用量因为受到个体时钟的影响关系,从原来的5个时钟用量变成6个时钟用量。好奇的同学可能会问:“个体时钟还有时钟用量到底有什么变数作用?”,这位同学真是问了一个好问题。

举例而言,笔者曾经在上一节为 exp21约束变数,如下所示:

(一)完成一次性搬运游戏至少需要5个时钟。

(二)虚拟输入必须在T0为WrData赋值 8’hAA。

(三)数据传递必须遵守时序表现。

其中第一条约束变数就是时钟变量的约束,原本移位模块的个体时钟只要消耗3个时钟即可,不过经过笔者修改以后,个体时钟已经变成4个时钟。因为如此,rQ成功接回数据8’hAA的可能性就提高了,如下所示:

(一)rQ在T0接收到 8’h00;

(二)rQ在T1接收到 8’h00;

(三)rQ在T2接收到 8’h00;

(四)rQ在T3接收到 8’h00;

(五)rQ在T4接收到 8’h00;

(六)rQ在T5接收到 8’hAA;

也就是说,原本是衍生5个可能性的,由于时间用量产生变化,结果就衍生6个可能性,其中第6个可能性是我们预期所要的结果。在这里,笔者使用简单的例子作为抛砖引玉的效果,笔者希望读者可以重视时钟用量,它是仿真最初也是影响甚重的变数,所谓一牵动全山就是这种意思。

根据概率论而言,投递2次银币就有3种可能性,投递3次银币就有4种可能性。反过来而言,只要减少投递的次数,可能性也会减少。不过,时钟用量是前期建模的考虑范畴,建模的时候要尽量压缩个体的时间用量,从效果上来讲,个体的时间用量当然是越小越好。为了控制时钟,指向时钟就会凸显其重要性,如果没有使用工具指向时钟,时钟就会变成非常模糊又虚幻。

说到指向工具,笔者不得不说 ... 虽然笔者常常举例用i指向个体时钟可是却未曾举例如何指向整体时钟?在此之前,先让我们好好理解一些个体时钟还有整体时钟之间的微妙关系。

图5.2.5 整体与个体的微妙关系,示意图。

如图5.2.5所示,一个中队里边包含A,B,C,D四个小对,然后每个小对又包含队员1~4。假设小组是整体,那么队员就是个体;假设中队是整体,然后无视队员,那么小队就是个体;假设中队是整体,队员则没有被无视,那么小队是局部整体,队员是个体。一般上,整体都是指最包裹力与组合力最强的哪一圈,所谓的整体时钟也是从这一视角出发的时钟。接下来请打开 exp22:

exp22_simulation.vt
1.    `timescale 1 ps/ 1 ps2.    module exp22_simulation();  3.    4.        reg CLOCK;  5.        reg RESET; 6.        reg [7:0]rD,rQ;7.         8.         /***********************************/9.    10.        initial                                                11.        begin      12.             RESET = 0; #10; RESET = 1;13.             CLOCK = 1; forever #5 CLOCK = ~CLOCK;14.         end15.         16.         reg [19:0]G;17.         always @ ( posedge CLOCK or negedge RESET )18.             if( !RESET )19.                 G <= 20'd0;20.             else21.                 G <= G + 1'b1;22.          23.         /***********************************/

exp22_simulation与 exp21_simulation 相比,除了在第16~21行指向整体时钟以外,其它都一样。如代码行第16~21所示,第16行声明为G的整体时钟指向工具,G大写代表God或者Global的意思,此外G的位宽一般有多大就给多大,因为G指向整体时钟,所以它必须有这样的容量。第17~20行则是简单的计数器。

图5.2.6 exp22 仿真结果。

如图5.2.6所示,这是 exp22的仿真结果,图5.2.6相比图5.1.6只是信号的最上方多了一个指向信号G而已,指向信号G是使用过去值标示当前的时钟点。G指向信号更一层楼清晰化时序的表达能力 ... 好奇的同学可能会问: “为何笔者在之前的仿真都没有使用G指向整体时钟呢?”。

笔者认为,如果指向个体时钟都作不好,指向整体时钟不过是没有意义的补救手段而已。换之,如果我们做好指向个体时钟的工作,指向信号G会发挥如虎添翼的效果。不过,老虎到底需不需要翅膀又是另外的话题,老虎有翅膀本来就是一件非常奇怪的事情。如果读者是时钟概念很弱的人,指向信号G固然是很好的补助工具 ... 反过来讲,如果读者有很强的时钟概念,指向信号G是可有无的存在,还不如少一个信号wave界面不是更加眼见清净吗?

笔者还有一个不使用指向信号G的原因就是,笔者不怎么喜欢用“神的视角”去俯视整场仿真流程。如果我们用神的视角去俯视一切,即我们必须同时“吸收”所有仿真信息,并且消化 ... 说实话,笔者实在没有“神一般的承受能力”。抱歉,笔者又离题了 ... 让我们切回时钟用量这个话题吧。

时钟用量是仿真最直接性的变数 ... 理论上,时钟用量越少,变数所衍生的可能性就会越少。不过要控制好时钟用量,那是前期建模的考量范畴。建模期间,我们不仅要用工具指向时钟,我们还要特别了解时序表现,不然的话,时钟用量不仅不会乖乖就范,反而还会趁机暴走。

时钟用量除了影响可能性的产生以外,时钟用量还能决定最大的仿真时间,于是笔者作出这样的推理:

个体时钟增加 => 整体时钟增加 => 仿真时间增加 => wave界面更长 => Modelsim吃更多内存 => 拖慢计算机 => 放缓仿真进度 => 蹉跎青春。

细节决定成败,这句话果然不是盖的的 ... 小小一个时钟用量既然可以间接影响我们的青春。

5.3 仿真的变数——信号数量与信号方向

图5.3.1 不同性质的变数,直接性(左),间接性(右)

乘我们还没有进入主题之前,首先让我们先简单了解一下不同本质的变数。如图5.3.1所示,变数有直接性(左图),还有间接性(右图),两者之间的差异就在于 ... 直线性变数会经过自己衍生可能性,反道间接性变数,它必须影响对象才能产生可能性。此外直接性变数是一种可以改变的变数 ... 反之,间接性变数是一种不可改变的变数。

时间用量相它是一种直接性的变数,这种情况好比读者呆在在马路上越久,危险的可能性就会越高,然而只要我们立即抽身离开,危险也会立即消失。换之,信号数量则是一种间接性的变数,如马路上的汽车越多,马路就会越危险,但是我们却没有能力减少汽车的数量。信号方向也是一种间接性的变数,我们知道十字路口相较单向通道,车祸的发生的频率越高,那是因为十字路口相比单向通道拥有更加多的方向,同样我们也没有能力改变马路的布局。

笔者也说过间接性变数是一种不可改变的变数,打个比方说,如:RS232的传输协议是一帧十一位数据就是一帧十一位数据,按照理论,数据位越长,数据损坏的可能性越高,

然而我们却不能私自减少数据位,因为一帧十一位数据是RS232的传输标准。为此,我们又该如何插手“信号数量”还有“信号方向”这两个变数呢?这个时候,我们必须换个视角看待问题了。

曾经那么一次 ... 师兄命令我们这些新手师弟为功能A建模,然后产生时序B。注视黑板上的功能A,那似蜘蛛网的状态机,还有臃肿的模块内容 ... 所有人当场都头皮发麻了。再来注视左边的时序B,看着那副极度不协调的时序图,现场所有人顿时露出比死人更难看的脸色。师兄命令我们在一个时辰内交出功课之后便离去 ... 不一会,一阵喧嚷响彻整个空间。

笔者当然知晓师兄的用意,建立复杂功能还有生成复杂时序都是每个新手必须克服的苦难之一 ... 但是笔者就是非常反感这种“强坑硬塞”的授学方式,在笔者的眼里那简直是另类的暴力,这种态度无疑是用来炫耀“高手”的能力一般,“看吧,蠢货们!这就是实力的差距 ... 不甘心的话,就克服给咱看看! ”。根据概率论而言,百人之中可能只有那么一两个人才能成为“高手”而已,其余的蠢货都会沦落为“高手”的食物,这就是现实,残酷即无理。

笔者闭上眼睛切断全身的感觉,好让意识可以从丑陋的空间当中分割开来 ... 不知不觉间,感觉周围的吵杂生已经逝去不再,取而代之是安心的歌声,笔者下意识睁开眼睛眺望四周 ... ”这是哪里?“——疑问随之从口中流了出来。笔者发现自己正处在花田之中,五彩缤纷的花儿们覆盖整片大地,这种情景宛如在地面上铺了一层五颜六色的地毯,微风走过,花儿优柔地摇晃身子然后发出协调的旋律。看着看着,笔者不禁入迷起来 ... 忽然,熟悉的声音传入耳中。

”来了吗,孩子?“,神秘声道。

笔者下意识追寻声音的主人 ... 没错就是它,不知什么时候它已经站在笔者的身边,笔者依旧看不清楚它模糊的脸庞。

”孩子,又是什么问题将你引导到这里?“,它道。

笔者稍微回忆一下,然后将问题向它讲述一番。它沉默了一会便举起有力的右手指向不远处的花田。

”孩子,哪里是什么?“,它问道。

”不就是一处花田吗?“,笔者答道。

”孩子,让我们走近看看好吗?“,它提议道。

”嗯“,笔者点头道。

不一会,笔者便抵达它指向的花田之处。它再一次使用有力的右手指向一只花儿,随着笔者连忙蹲下身子,仔细瞧瞧 ...

”看见了吗,孩子?这里有什么 ...“,它道。

”有虫子!不仅一只,而且还很多“,笔者答道。

”远处看去,我们只能看见花田的整体,从近处看,我们就会看见花田的个体“,它道。

它的话永远都是充满寓意,笔者仔细思考了一会,“原来如此”,领悟的四个字不不经意从口中跑了出来。整体与个体之间的微妙关系,其实只是视角的远近而已,亦即宏观与微观。从宏观的角度看去,花田是一片复杂的整体 ... 换之,如果从微观的角度去干,花田里边其实有许多简单的个体。换句话说,无数简单的个体组成一具复杂的整体。

笔者转过头,用敬佩的眼神仰视它,忽然间有股念头从脑海中蹦出,笔者想继续向它提问 ... 但是,当笔者再度睁开眼睛的时候,周围又恢复原先的喧嚷声。原来是笔者睡糊涂了,笔者用手逝去嘴角的口水之后,立即望向时钟 ... 糟糕,笔者还有剩下半个时辰的时间而已,于是笔者急忙着手完毕功课。

期间,笔者一只在思考 ...“单位”是计算还有分类的基础,例如1个人与3只动物,其中“1与3”就是量化的单位,“个与只”是分类的单位。换言之,如果我们想划分整体模块就必须依靠单位才行 ... 话虽如此,单位的定义又是什么呢?笔者又该去哪里寻找呢?事实上,低级建模的准则早已经给我们答案,那就是“功能”。

建模技巧(低级建模)的作用不可能只是单纯地为模块提供最基础的结构而已,其实建模技巧的绝对准则,亦即“一个模块一个功能”在不知不觉间,已经为仿真埋下细化的种子。换句话说,一座复杂的功能可以经由建模技巧划分为数个简单的功能,复杂的功能就是整体,简单的功能就是个体。我们虽然不能随便简化整体的复杂性,但是我们可以经过某种手段,将整体有规则地分成许多更小的个体。

形象上来讲,一块一口气吃不下的蛋糕,我们可以按着比例将蛋糕划分为无数规整的小蛋糕,然后逐个吃完。其实这是一种很奇怪的心理现象,2kg的蛋糕不管怎么划分,最终吃下肚子也是2kg的分量,但是一份2kg的蛋糕所给予的心理负担,比起10份0.2kg的蛋糕还要沉重。心境决定行为的成败,好心情就是成功的开始 ... 抱歉,笔者又稍微离题了。

好奇的同学可能会问道:“划分功能与这些变数(信号数量还有信号方向)究竟有什么关系?”,真是一个好问题,首先让我们换个角度去思考问题吧。我们知道车祸一般都是人为引起的悲剧,假设有一处地带哪里集中100量车子 ... 根据概率论而言,如果车子的数量越是集中,那么车祸越容易发生。反之,如果我们将100量车子放在平均安放在10处不同的地方,根据概率理论,车祸发生的概率不仅可以分化,而且车祸的概率也可以减小。

同样的道理也适用在仿真当中,功能的复杂程度还有信号的数量理应是成正比关系,亦即功能越复杂,功能数量越多。笔者在前面也说过,信号数量是一种间接性的变数,它不会直接影响可能性的衍生,但是它可以影响人为活动,然后经由人为失误产生更多可能性。

举例而言,假设有100条信号产生100个可能性,当中要我们死盯其中一条信号,当我们长时间盯着同样的东西,眼睛就会开始疲劳然后幻觉就会出现。当我们将100条信号平均划分为10份以后,按照理论,可能性也会等着平均分化。死盯10条信号之中的一条,相较死盯100条信号之中的一条,前者对眼睛的伤害更加小。

笔者曾经尝试长时间在100条信号之中死盯着的一条信号 ... 不一会儿,笔者只是眨下眼睛,信号忽然从100条变成101条 ... 笔者又揉下眼睛,信号又从101条变成102条。现实中100条信号仅是产生100个可能性而已,但是在幻觉中笔者却觉得102条信号产生102个可能性。

因此我们可以断定,信号数量一种影响精神的变数,它会“弄混”我们,让我们产生幻觉,然后衍生出似存在又不该存在的可能性,因此我们需要分化过度集中的信号,从而消除这份“意外”。

除了信号数量意外,信号方向也是间接性的变数之一 ... 读者尝试想象一下,如果我们驾着车不停拐弯抹角,话说是不是很危险?车祸更加容易发生呢?只要我们按照这样的思路继续思考下去,我们便会知道一个事实,连续拐10个弯,相比连续拐2个弯,前者比后者发生车祸的可能性更高。

假设有10场连环弯,普通人不可能驾着藤原豆腐车,一口气,高速飘移在每场拐弯之中。换之,正常人都会分段拐弯,例如笔者这种怕死的家伙,笔者会将10场连环弯分段为10场小环。有研究显示,十字路口比起单向道路更容易发生车祸,理由很简单,单向道路只有一个方向,换之十字路口至少有4处方向同时拐弯。

在此,好奇的同学可能会问道:“笔者我们又不是在讨论头文字D,车拐不拐弯又与仿真有什么关系?”

图5.3.2 信号数量集中但是方位单向(左),信号数量集中但是方位多向(右)。

这位同学有所不知了,信号方向相较起信号数量是个更危险的变数。如图5.3.2所示,左图时信号数量集中但是信号的方向非常单一,右图不仅信号数量集中,而且信号的方向错综复杂。我们单是使用肉眼就能简单将左右图之间的差异分辨出来,试问读者那张图看起来比较“不头晕”呢?答案当然是左图。

信号数量好比马路的距离,信号数量越多马路的距离就越长。换之,信号方向还比马路的布局,信号方向越多向马路越是纵横交错。图5.3.2的左图可以比拟是一条很长很长的单向马路,然而图5.3.2的右图是迷宫般的多向马路。当我们追踪信号从一条到另一条的时候,这种情形好比我们在驾车从一条马路驶去另一条马路。

如果是左图,我们顶多只有长距离旅行的疲劳感而已;相反的,如果是右图,我们不仅感受长途旅行的疲劳,我们宛如嗑药般头不停甩来甩去,试问读者那种情况更容易发生车祸?答案当然是肯定着,右图更加容易发生意外。

图5.3.3 信号多向但是不集中。

没错,这就是信号方向的危险性,不过我们可以经过简单的功能划分将这种危险降到最低。如图5.3.3所示,笔者尝试将图5.3.3的右图划分成为几个等分的成份。当仿真对象的功能经过等分划分以后,虽然信号数量还有信号方向都没有变化 ... 不过不知道是不是心里作用?那种飘移过度所产生的晕眩感却没有之前般那么强烈,实在是太奇怪了。

图5.3.4 信号分化之前。

好奇的同学可能会问道:“信号数量还有信号方向,难道我们将他们分化而已嘛?为什么不能像级时间用量那样直接简化它呢?”,从理论上来讲的确是这样,但是那种情况出现的几率非常少,让笔者再举个简单的例子吧。如图5.3.4所示,一个仿真对象的左右都有WrData 与 RdData,对此我们可以这样推断道,仿真对象同时拥有两对非常相似的信号,它应该是可以进一步划分吧?

图5.3.5 信号分化之后。

图5.3.6 信号简化以后,仿真对象的原始模样遭受破坏。

经过一番舞刀弄斧之后,仿真对象的划分结果如图5.3.5所示。其中仿真对象一分为二成为两个更小的仿真对象,然后 WrDataL,RdDataL 与 WrDataR,RdDataR 被划分并且隔开出来,但是 WrDataX 与 RdDataX 的数量还有方向依然不变。假设读者饥不择食把其中一份吃掉的话,仿真对象的原始模样就遭受破坏,结果如图5.3.6所示。

笔者时常说道:“早期有好的建模,后期就有好的仿真”,其中也包含约束变数这一环。早前建模不仅仅是为了实现某种功能然后实现建模而已 ... 我们应该放长考虑才行,因为越是早期的作业,越是影响后期的表现,俗语不是有一句叫做一牵动全山吗?如此可见,早期作业有多么重要。好了,有关变数的话题就讲到这里为止吧,从下一章节开始我们就要进入仿真的高潮。

5.4 理想变数与物理变数

笔者曾经说过,仿真在大多数的情况下都是多向仿真,然而多向仿真的结局(仿真结果)

不可能只有一项而已,而是多个可能性。换言之,多向仿真打从一开始就已经存在一定数量的可能性 .... 不过,变数在这基础上有可能再度放大可能性,从而海量化仿真信息。茫茫大海当中寻找一种可能性,这份任务无疑是大海捞针,根本接近不可能。

可能性是变数相乘的结果,用典型的投币而言,假设硬币数量一枚然后笔者投币3次,然而投币结果会产生以下,如表5.4.1所示的8种可能性:

表5.4.1 一枚硬币投币3次所产生的可能性。

可能性\结果

第一次结果

第二次结果

第三次结果

可能性1

可能性2

可能性3

可能性4

可能性5

可能性6

可能性7

可能性8

假设我们将表5.4.1当中,公表示为0值,花表示为1值,第N次投币结果表示为输入,可能性可以表示为输出 ... 看着看着,读者不是不是觉得表5.4.1有点眼熟?没错,这是换个外皮的二进制表,结果如表5.4.2 所示:

表5.4.2 表5.4.1等价的二进制表。

输出\输入

[2]

[1]

[0]

Q1

0

0

0

Q2

0

0

1

Q3

0

1

0

Q4

0

1

1

Q5

1

0

0

Q6

1

0

1

Q7

1

1

0

Q8

1

1

1

疑心种的朋友可能会怀疑道:“事到如今,笔者举例这些内容又有什么用?”。朋友,看东西千万别那么死心眼,凡事要从各种角度去思考问题,希望读者可以明白笔者的用心良苦,故事其实是这样的 ...

某天下午,笔者一边思考问题,右手则不停投币解闷,笔者接着将投币结果写在纸张上,因为懒惰的关系,画圈表示公,写1表示花,无意间有股灵感袭击笔者的脑袋,心想:“投币会不会和仿真有关系?”,于是乎笔者绘出表5.4.1与表5.4.2。

乍看下,笔者自己也吓了一条,两者实在太相似了,还不如说同一个人同时穿上两件不同的外衣而已。然而,表5.4.2与表5.4.1之间却有根本性的差别,表5.4.2是逻辑亦即非黑即白,表5.4.1是概率亦即可能性,于是笔者开始思考 ... 想着想着,笔者就发现仿真不仅存在“概率”,而且也存在“变数”。笔者当然知晓这种想法的矛盾性,因为逻辑讲究非黑即白,绝对不会计算什么 percentage,但是不甘愿的笔者又继续思考 ...

笔者曾在小节5.2~5.3讲述时钟用量,信号数量还有信号方向,这三种最主要的仿真变数,三者之间却可以这样反映在投币的身上:

(一)投币次数好比时钟用量;

(二)硬币数量好比信号数量;

(三)信号方向还比投币的意外性;

第一点很容易理解,只要仿真对象的时钟用量约多,那么投币次数就会越多,可能性随之也会衍生更多。换之,只要我们减少投币的次数,那么可能性也会减少衍生的数量,同样的道理也适用在时钟用量的身上。第二点也很容易明白,假设投币一枚硬币就会产生公或者花这两种可能性,如果两枚硬币同时投币,那么就会产生公花,公公,花花等三种可能性。同样的道理里也适用在信号数量的身上。

关于第三点,理解起来可能会稍微复杂一点 ... 概率论一般是基于随机性才能成立,所谓随机就是无法预测的因数,典型的投币例子,随机性是指投币的力道,投币的高度等人为因数。由于是人为因数,随机性有时候也可以称为意外性。有人类的地方意外就会发生,因为人类是悲剧的生物,仿真是人类着手的活动,不存在意外才奇怪呢 ... 可是仿真又存在什么意外?

笔者曾在小节5.3举例过,如果我们长时间死盯一条信号我们很容易看见幻觉。此外,如果信号的方向性多度多向化,意识就会360度来回甩动,直到头昏脑涨看见幻觉。没错,就是幻觉 ... 幻觉衍生更多没有实体的可能性。变数虽然可恶,但是时钟用量,信号数量,还有信号方向还是良性的变数,我们可以透过简化或者分化功能,从而缩小变数衍生的可能性。这些良性变数笔者称为理想变数。

如果变数存在良性,变数理应也存在恶性,没错那就是物理变数。接着,再让笔者使用投币作为举例吧 ... 投币在理想的状态下:

l 硬币都有同等的大小和重量;

l 投币结果为公与花两种;

l 重力为 9.8m/s2

l 环境为真空状态;

l 投币者健康。

相反的,投币在物理的情况下:

l 硬币不同等大小还有重量;

l 投币结果出了公花以外也有直立的可能;

l 重力为不安定;

l 环境的空气属性,密度,湿度不等;

l 投币者不健康。

为什么笔者要说物理变数是恶性变数呢?读者尝试想象一下,如果硬币不等大小的话,我们就有小硬币结果,还有大硬币结果之分。此外,如果投币结果出了公与花以外,还有直立(非公非花)这种不可思议的投币结果 ... 试问读者,可能性是不是会一口气增大许多呢?如果我们还要考虑投币者的健康状态,可能性既不是接近无限?这种情况再也不是大海捞针就可以了事,我们要在无边无际的宇宙当中寻找一粒微尘。

笔者不是在吓唬读者,笔者只是在讲述事实而已 ... 然而这个世界上却有一群傻子想要完成“宇宙寻尘”这种前无古人后无来者的伟大壮举,它们不是别人,正是传统流派。

不管笔者翻开那一本参考书,它们都会威吓笔者“仿真要尽量实现物理时序”,任何时候笔者都会怀疑,作者是不是脑子进水了?难道它们看不到物理时序那接近无限的可能性吗?

物理时序主要有2个最基本的物理变数:

(一)物理延迟

(二)寄存器特性

图5.4.1 没有物理延迟的理想时序。

物理延迟是物理时序最常见的变数,也是最可怕的变数,物理延迟包括数据信号延迟,还有时钟信号延迟。举例而言,假设寄存器1将输入A读入以后再传递给寄存器2,如图5.4.1所示,这是理想的数据传递,所以时序过程有如右边的理想时序图一样漂亮美丽。此刻,我们知道寄存器1~2都是按照理想时序表现传递数据,所以我们不要考虑什么物理延迟这种变数,因此时序结果只有1种可能性而已。

图5.4.2 数据延迟的物理时序。

如果我们将物理延迟考虑进来,如图5.4.2所示,寄存器1~2之间的路径存在物理延迟,假设数据时间传递存在3种不同程度的数据延迟。在此我们就会开始思考,究竟是第一种时序结果寄存器2才能成功锁存数据A,还是第二种时序结果,或者第三种时序结果呢?在此,我们拥有3种可能性的时序结果需要思考 ... 要么第一种?要么第二种?要么是第三种时序结果才是对的?

图5.4.3 时钟延迟的物理时序。

如果物理延迟不是发生在数据信号的身上而是时钟信号的身上,如图5.4.3所示,假设寄存器1~2共享同样的时钟沿,而且时钟路劲也有同样的物理延迟,然后再假设时钟路径有3种不同程度的延迟。在此,我们必须思考3种时序结果,要么是第一种?还是第二种?或者是第三种时序结果寄存器2才能成功锁存数据。读者千万别以为物理延迟的事情这样就完了 ...

图5.4.4 数据延迟与时钟延迟的物理时序。

现实残酷即不讲理,如图5.4.4所示,实际的物理延迟不可能仅存数据路径或者时钟路劲任一一者而已,而是两者同时存在。这时候,我们不仅仅是要考虑时钟延迟所产生的3种可能性,我们也要考虑数据延迟产生的3种可能性,因此我们需要考虑6可能性。事实上,图5.4.4已经很仁慈了,因为物理时钟不仅仅只有路劲的延迟而已,物理时钟还会抖动,从而进一步扩大可能性 ...

图5.5.5 物理时钟抖动的物理时序。

如图5.5.5所示,假设寄存器1~2共享同样时钟源,虽然时钟路径不存在延迟,但是时钟源却产生抖动 min 与 max,就这样两种可能性就这样蹦出来。此刻我们必须同时思考 min时钟抖动的时序可能性,还有 max 时钟抖动的时序可能性。再假设,如果寄存器1~2使用不同时钟源的话,而且两个时钟源都有发生抖动,请问结果会是怎么样的情景呢,读者可以想象吗?不过不用担心的是,时钟抖动所产生的延迟非常小,一般都可以直接忽略掉,在此笔者只是吓唬吓唬读者而已 ... 笑~

图5.5.6 寄存器特性的物理时序。

寄存器特性物理变数的其中一种,如图5.5.6所示,常见的寄存器特性有Tco,Tsu与Th。Tco是数据输出之前所需要的最小热身时间;Tsu是锁存数据所需的最小建立时间;Th是锁存数据所需的最小保持时间。虽然它不像物理延迟那样会随着综合的质量而产生改变,一般寄存器特性都是恒定的常值。话虽如此,实际上寄存器也是非常麻烦的物理变数之一。

根据物理时序的解释,Tco的作用差不多和数据延迟那样会延迟寄存器的输出,简单看可以是寄存器内部的数据延迟。Tsu还有Th解释起来稍微麻烦一点,物理时序认为 ... 如果数据要成功锁存,数据必须满足两个条件,亦即Tsu与Th等最小时间。如图5.5.6的右图所示,当寄存器2被锁存沿(绿色的时钟沿)触发以后,Tsu与Th的判断工作就开始了。

最佳的情况下,锁存对象——数据A不偏不移卡在锁存沿的中间,然后Tsu覆盖数据A的左边,Th则覆盖数据B的右边,如果Tsu与Th无法完全覆盖数据A,结果可以断定数据A成功锁存在寄存器2的身上,反之亦然。上述内容告诉我们,寄存器特性需要考虑3种可能性,亦即Tco,Tsu还有Th,任何一种可能性都会影响锁存结果,其中Tsu与Th更加显得重要。

读者尝试想象一下,假设设计A消耗100个寄存器,那么可能性衍生的数量会是 100 * 3 = 300。普通规模的接口模块动不动就会需要消耗200以上的寄存器,如果这是玩笑笔者真是一点也笑不出来。

曾经有同学这样问道: ”俺的仿真结果正确,可是模块不会发挥实际的效果,俺是不是忘记考虑物理因数呢?“,后来那位同学才发现自己写错模块了,但是那句疑心话——俺是不是忘记考虑物理因数呢?,却让笔者察觉到,常规仿真手段存在的漏洞。经过无数实验以后笔者终于发现,漏洞的地方其实是传统流派误认HDL的本质,它们打从开始就认为 HDL 是物理即破烂的工具,所以产生物理时序是应该的。

但是根据笔者的理解,HDL是理想的工具,物理因数是综合以后才添上的灰尘。于是,笔者继续思考 ... 物理因数实际上是仿真可有可无的东西,然而它的存在不仅照成仿真而外的负担,而且它还会令人疑神疑鬼,产生空洞的担忧。形象点说,就像那位同学一样,原本它只要考虑模块的正确性即可,但是物理因数却让它考虑而外即不存在的烦恼,俗称杞人忧天。

理想时序除了违背HDL的本质以外,美观也是重要问题,但是主要原因是物理变数会无限放大可能性。物理变数属于间接性变数,它们虽然不会直接影响实际的结果,但是它们却会影响我们产生错觉,让我们在错觉种看见无限的可能性。认真想一想的话,这是一件非常不得了的事实,而且这种程度再也不能使用海里捞针来形容,实在是杀人于无形 ... 因此,笔者才会如此反感“物理”出现在仿真当中。

因此,仿真放弃物理因数是一件明智之举,这种感觉好比房间整整齐齐有一尘不染般,看着心情也爽快许多。不过,最重要的是可能性的衍生数量会大大降低,从而减弱一定的仿真信息。好奇的同学可能会问道: ”如果仿真物理因数,那么无理因数又该如何解决?“,回答这个问题之前,先让笔者讲明一下Modelsim的用意。

仿真的精髓就是联系激内容,仿真对象,还有时序结果做出解析,简称为仿真信息解析。其中时序结果会播放在wave界面上 ... 再度强调!Modelsim只会播放时序却不会为我们解决时序,就算Modelsim有能力播放物理时序,Modelsim也没有能力解决物理时序,因为Modelsim没有这方面的机能。此外,Modelsim播放的物理时序与实际的物理时序有天壤之别,实际的物理时序会有更多细节。说得难听一点,电视上面的物理时序我们只能看看自寻烦恼而已,实际上却什么也干不了,与其自寻烦恼还不如不看为好,读者说是不是,有没有道理呢?

只要明白这个道理以后,那么笔者就可以继续回答问题 ... 读者是否有听说过静态时序分析呢?它是专门用来处理物理时序的工具,读者可以想象为类似Modelsim,然而它是用针对物理时序的加强版本,它不仅可以显示物理时序的各种细节,它也能计算并且解决物理时序的问题(时序违规)。说白一点,Modelsim是用来针对理想时序的工具,然而静态时序分析是用来针对物理时序的工具,理解吗?

最后,让笔者这样总结吧:

时序有理想还有物理之分,变数也有理想还有物理之分 ... 其中,物理变数是可以排除在外,因为它只是会捣乱的没有家伙而已,反之理想时序是真正必须考量的东西。此外,笔者也用概率论最典型的投币来表示,仿真存在变数不是笔者空妄想的东西,实际上那是隐藏在仿真的背后,不为人知的重要细节。

变数会衍生可能性是人之常情,但是读者又否知道,Modelsim 每播放一次时序图,其实是显示多种可能性当中的其中一种而已。如果仿真有100个可能性,我们不可能重复100次仿真作业,因此简化变数可以降低可能性衍生的数量,分化变数会降低变数过度集中的危险(错觉的可能性)。

5.5 仿真的必然——特定条件

圣人说过偶然会摧毁世界,因此万物都是必然。笔者也说过仿真不过是人生的缩影,如果人生存在必然将人生的引向最有意义的结局,那么仿真也存在必然将结果引向预想所要。为了明确解释必然也存在必然,笔者同样也适用典型的投币来举例,假设笔者将一枚硬币A投币八次,然后产生如表5.5.1所示的结果:

表5.5.1 硬币A投币8次的结果。

硬币A

结果1

结果2

结果3

结果4

结果5

结果6

结果7

结果8

可能性N

如表5.5.1所示,硬币A投币8次以后,产生前4公4花的结果,然后笔者姑且称为可能性N。假设笔者再将一枚硬币B投币8次,取得可能性N的概率是:

1/ 28 * 100% = 0.78125%

计算结果是 0.78125%,可以说是一件令人绝望的数字,比踩狗屎更难发生。根据计算,硬币B出现上述结果的概率是 0.78125%,换句话说,硬币B重复128次才有偶然才出现那么一次 ... 不过笔者也说过,偶然并不存在这个世界,万物都是必然,硬币B为了实现可能性N,硬币B必须完成一系列的特定条件:

l 第1次投币的结果是公;

l 第2次投币的结果是公;

l 第3次投币的结果是公;

l 第4次投币的结果是公;

l 第5次投币的结果是花;

l 第6次投币的结果是花;

l 第7次投币的结果是花;

l 第8次投币的结果是花;

现实中,人类的力量不能左右投币的结果,亦即不能控制必然 ... 不过,如果我们将硬币看做信号,必然就能被控制。假设硬币B为信号B,然后投币次数是时钟用量,那么信号B的结果会是如表5.5.2所示:

表5.5.2 等价的表5.5.1。

信号B

T0

T1

T2

T3

T4

T5

T6

T7

Q

0

0

0

0

1

1

1

1

完后,我们可以用 Verilog 这样表示,如代码5.5.1所示。

1.    always @(posedge CLOCK)2.    case( 0 )3.     4.        0,1,2,3:5.        begin Q <= 1’b0; i <= i + 1’b1; end6.    7.        4,5,6,7:8.        begin Q <= 1’b1; i <= i + 1’b1; end9.    10.    endcase

代码5.5.1

代码5.5.1的第3~4行表示将Q拉低4个步骤(4个时钟),然后再第7~8行将Q拉高4个步骤(4个时钟)。

图5.5.1 代码5.5.1产生的时序图。

完后,代码5.5.1会产生图5.5.1的时序结果。许多同学可能会好奇笔者所做所为,为什么笔者先是举例投币,然后对比信号还有投币之间的等价关系?笔者接着又用Verilog 描述,甚至绘出时序图 ... 笔者这样做除了为了证明,仿真存在必然性以外,笔者也想接续蒂沙与白骆驼的故事。

所谓的必然性是指,什么东西在什么时候必须发生什么结果?在此,有些同学可能会将

必然性与第三章的协调产生联系,然后问道:“必然性与协调是不是同样的东西?”。协调与必然性的确在标示同样的东西,这种感觉好比英文的“apple”,还有日文的“りんご”,两者分别标示苹果,但是英文还有日文却是不同性质的语言。

协调纯粹是站在时序的角度上去理解“什么东西在什么时候发生什么结果”。反之,必然性则是站在多向仿真的角度上去理解“什么东西在什么时候发生什么结果”。协调只考虑一种可能性而已,必然性则是考虑多种可能性。读者理解了吗?理解以后,我们就可以继续话题了。

骆驼之所以可以引导蒂沙,是因为白骆驼可以非常清晰的看见蒂沙的命运,它知道蒂沙什么时候,发生什么,迎接什么结果,如果白骆驼没有引导蒂沙,蒂沙就会死在沙尘暴当中。白骆驼为了引导蒂沙,它借助沙城暴这个契机出现在她眼前,聆听蒂沙的愿望之后,白骆驼便告诉她旅行已经结束并且实现她的愿望。这个故意隐隐约约也透露白骆驼是神的真面目。

我们身为设计者,创建仿真环境,在某种程度上算是这个空间的神,蒂沙好比仿真对象,我们好比白骆驼,我们必须观察什么信号,在什么时候,得到什么结果。但是问题是,仿真对象的内容,是否足够清晰呢?不然的话,我们想引导也引导不了,结果蒂沙惨死在沙尘暴当中。

当我们将代码5.51还有图5.5.1联系起来,我们之所以认为代码5.5.1还有图5.5.1之间没有任何违和感,因为代码5.5.1 都清清楚楚指向什么信号,在什么时候,输出什么结果。这个事实也告诉我们,维护必然性,清晰必然性,都是非常重要的任务,然而这些任务却涉及早期建模,还有激励文本的编辑。

如何维护必然性,清晰必然性其实是有窍门的,低级建模的用法模板就是为了这种目的才诞生。笔者曾在第4章解释过,仿真对象还有激励内容最好都使用相同的用法模板,因为如此,必然性都有同样模样的维护性,而且指向工具i也帮助清晰必然性。上述的内容又再一次证明”前期有好建模,后期有好仿真“这句话。

首先,让我们来瞧瞧失去维护并且没有清晰必然性的仿真对象,究竟会是什么样子的?请读者打开 exp23.

exp23_simulation.vt
1.    `timescale 1 ps/ 1 ps2.    module exp23_simulation();  3.    4.        reg CLOCK;  5.        reg RESET; 6.        reg [7:0]rD,rQ;7.         8.         /***********************************/9.    10.        initial                                                11.        begin      12.             RESET = 0; #10; RESET = 1;13.             CLOCK = 1; forever #5 CLOCK = ~CLOCK;14.         end15.         16.         /***********************************/17.        18.        reg [7:0]C1,rTemp;19.        20.        always @ ( posedge CLOCK or negedge RESET )21.            if( !RESET )22.                begin23.                    C1 <= 8'd0;24.                    rTemp <= 8'd0;25.                    rQ <= 8'd0;26.                end27.            else if( C1 == rD ) 28.                begin            29.                    C1 <= 8'd0;30.                    rQ <= rTemp;31.                    rTemp <= 8'd0;32.                end33.            else 34.                begin 35.                    C1 <= C1 + 1'b1; 36.                    rTemp <= rTemp + rD; 37.                end38.         39.         /***********************************/40.         41.        reg [3:0]i;42.    43.        always @ ( posedge CLOCK or negedge RESET )44.            if( !RESET )45.                begin46.                    i <= 4'd0;47.                    rD <= 8'd0;48.                end                49.              else 50.                  case( i )51.                    52.                        0: 53.                        begin rD <= 8'd4; end54.                    55.                    endcase56.                    57.        /***********************************/        58.                                                                                   59.    endmodule

exp23_simulation 中的第18~37行是仿真对象,看着它读者是否觉得很乱却又觉得怀念呢?没错,在早期的时候,任何初学者都会采用的用法习惯,正确来说这是一种自由用法的编辑风格。我们不用考虑什么,我们只是尽量将所有操作往 always 块里边塞,这种感觉就好比将垃圾塞进垃圾袋里面。

这种自由用法最大的好处就是自由还有随意,好比叛逆的少年般想怎样搞就怎样搞。反观之下,自由用法也有缺点,首先采用自由用法的模块(仿真对象)必然性是非常模糊的 ... 如代码第18~37所示,C1等价 rD以后便清零C1还有rQ被赋予 rTemp,然后rTemp清零(第27~32行);第33~37行表示,每个时钟沿便递增C1还有累加 rTemp。代码18~37行虽然有明显的操作,但是代码18~37行却没有清晰的必然性。

第41~55行是虚拟输入,笔者在步骤0只是为rD赋值4却没有读取rQ的内容,好奇的同学可能会问为什么?原因很单纯,由于仿真对象没有清晰的必然性,所以笔者也不知道仿真对象在什么时候输出 rQ,因此 exp23_simulation 至少必须运行一次,虚拟输入的编辑工作才能继续下去 ...

图5.5.2 exp23_simulation 的仿真结果。

图5.5.2是 exp23_simulation 的仿真结果,光标C0,C5与C6分别指向时钟T0,T5还有T6。如图5.5.2所示,虚拟输入在T0为rD赋值4,仿真对象在下一个时钟接收 rD的过去值并且开始工作。仿真对象每累加一次rD的过去值4到rTemp里边,C1就递增一点。当仿真对象执行操作直到T5的时候,if(C1 == rD)条件成立,rQ被赋值与 rTemp的累加结果16,然后C1与rTemp紧接着被清零。如果虚拟输入要读取 rQ的值16,有效时钟是T6。

exp24_simulation.vt
1.    `timescale 1 ps/ 1 ps2.    module exp24_simulation();  3.    4.        reg CLOCK;  5.        reg RESET; 6.        reg [7:0]rD,rQ;7.         8.         /***********************************/9.    10.        initial                                                11.        begin      12.             RESET = 0; #10; RESET = 1;13.             CLOCK = 1; forever #5 CLOCK = ~CLOCK;14.         end15.         16.         /***********************************/17.        18.        reg [7:0]C1,rTemp;19.        20.        always @ ( posedge CLOCK or negedge RESET )21.            if( !RESET )22.                begin23.                    C1 <= 8'd0;24.                    rTemp <= 8'd0;25.                    rQ <= 8'd0;26.                end27.            else if( C1 == rD ) 28.                begin            29.                    C1 <= 8'd0;30.                    rQ <= rTemp;31.                    rTemp <= 8'd0;32.                end33.            else 34.                begin 35.                    C1 <= C1 + 1'b1; 36.                    rTemp <= rTemp + rD; 37.                end38.         39.         /***********************************/40.         41.        reg [3:0]i;42.        reg [7:0]rRead;43.    44.        always @ ( posedge CLOCK or negedge RESET )45.            if( !RESET )46.                begin47.                    i <= 4'd0;48.                    rD <= 8'd0;49.                    rRead <= 8'd0;50.                end                51.              else 52.                  case( i )53.                    54.                        0: 55.                        begin rD <= 8'd4; i <= i + 1'b1; end56.                        57.                        1,2,3,4,5:58.                        begin i <= i + 1'b1; end59.                        60.                        6:61.                        rRead <= rQ;62.                        63.                    endcase64.                    65.        /***********************************/        66.                                                                                   67.    endmodule

exp24_simulation 相较 exp23_simulation 改变的地方就是第41~63行的虚拟输入。其中笔者在42行声明 rRead寄存器用作暂存 rTemp的结果;第54行是虚拟输入为 rD赋值4;第57~58行是等待5个空时钟;第60行是读取rQ的结果。

图5.5.3 exp24_simulation 的仿真结果。

如图5.5.3所示,光标C5指向的地方(T5)正好是仿真对象完成一次性操作的时候,然后虚拟输入再C6指向的地方(T6)读取rQ的过去值16,因此rRead输出未来值16。

仔细思考 exp23_simulation 还有 exp24_simulation,我们知道由于仿真对象(exp23)没有清晰的必然性,因此我们至少需要仿真一次(exp24)才能预测并且正确读取rQ的内容。由于仿真对象的必然性很模糊的关系,我们不得不消耗而外的气力,事实上这是非常被动的行为 ... 消耗气力倒不相干,蹉跎岁月才是致命的问题,人生最长不过是几个十年而已。

此外,笔者相信眼睛犀利的朋友已经发觉到,仿真对象的第27行 else if( C1 == rD ) 其实是一件非常有问题的写法。简单而言,仿真对象一次性所需的操时间会伴随 rD的内容而产生改变。换句话说,每当 rD的输入内容不同,rRead读取rD的时间也会不同,为了让 rRead有效读取rD的结果,我们至少都要预先仿真一次才能预测得到rRead读取rD的正确时钟 ... 这不是要耗死我们的精力吗!?

exp23~24的仿真对象有以下两个问题:

l 模糊的必然性

l 时钟用量不固定

仿真对象虽然有明显的操作内容,不过它却不能有效告诉我们“什么时候,什么东西,发生什么事情”,因此被认为为模糊的必然性;仿真对象也会随着rD输入内容的不同,时钟用量也会跟着不同。不管哪一点问题都是非常致命的问题 ...

读者尝试想象一下,身为白骆驼的我们就算窥视蒂沙的命运宏图,然而蒂沙的命运不仅模糊而且还有很强的随机性,这些因数会无限放大可能性,即时白骆驼的能力再怎么强大,白骆驼也无法知晓一切。结果而言,如果白骆驼无法完全掌握蒂沙她的命运流向,就算白骆驼想引导她,它也是心有余而力不足。

为了美丽的蒂沙,可怜的蒂沙,白骆驼豁出去了 ... 必然性之所以模糊,那是因为没有指向工具指向蒂沙的命运(仿真模块的过程),不管指向什么,哪怕一丝一毫也好,指向工具都必须指向某个东西。其中我们知道指向时钟那是无法实现的事实,因为仿真对象没有固定的时钟用量,既然指向时钟不行,指向步骤又如何?

1.    always @ ( posedge CLOCK or negedge RESET)2.    if( !RESET )3.        begin4.           C1 <= 8'd0;5.           rTemp <= 8'd0;6.           rQ <= 8'd0;7.        end8.    else9.        case(j)10.             11.                0:12.                if( C1 == rD ) begin C1 <= 8’d0; rQ <= rTemp; rTemp <= 8’d0; end13.                else begin C1 <= C1 + 1’b1; rTemp <= rTemp + rD; end14.       15.            endcase

代码5.5.2

如代码5.5.2所示,仿真对象已经套用用法模板,其中j是指向工具,其中步骤0表示仿真对象原本的功能 ... 第13行的C1会根据每个时钟递增,而rTemp也会累加,当第12行的if条件成立以后,rQ赋予rTemp的内容,然而C1还有rTemp都会被清零。当仿真对象套用用法模板以后,必然性随之也清晰起来。

不过不管我们怎么看,代码5.5.2始终都觉得少点什么?这种感觉好比用餐少了餐具 ... 然而代码5.5.2究竟少了什么关键的东西?

人生在冥冥之中,往往都会因为遇见某种契机,生命因而开始发生改变。契机是必然的一种,契机有时候也称为邂逅,但是对象不一定局限于人,它也可以是事物或者某种因缘。契机是命运的恶作剧,契机也是命运的黏糊剂,为了引导生命流向最有意义的结果,人的一生当中很有可能会存在许多重要的契机。

从另一个角度来讲,在生命的宏图当中,其实存在许多命运的碎片(命运的拼图),然而一条完整的命运线,都由无数的契机将无数的命运碎片串联起来。仿真就是人生的缩影,所以仿真当然也存在契机,但是问题是如何将“契机”描述出来呢?

1.    always @ ( posedge CLOCK or negedge RESET)2.    if( !RESET )3.        begin4.                    C1 <= 8'd0;5.                   rTemp <= 8'd0;6.                  rQ <= 8'd0;7.                     j <= 4’d0;8.        end9.    else if( isStart ) 10.        case(j)11.             12.                0:13.                if( C1 == rD ) begin C1 <= 8’d0; rQ <= rTemp; rTemp <= 8’d0; j <= j + 1’b1;end14.                else begin C1 <= C1 + 1’b1; rTemp <= rTemp + rD; end15.     16.                1:17.                begin isDone <= 1’b1; j <= i + 1’b1; end18.    19.                2:20.                begin isDone <= 1’b0; j <= 4’d0; end   21.    22.      endcase

代码5.5.3

如代码5.5.3所示,仿真对象会以 isStart 信号作为契机而开始工作(第9行)。仿真对象完也会以 isDone 信号作为结束操作的契机告诉他人(第16~20行)。读者没有看错,代码5.5.3确实是应用了仿顺序操作 ... 从建模的角度而言,仿顺序操作仅是模仿顺序

操作而已。换之,如果我们从仿真的角度去看的话,仿真对象会因某种信号作为契机开始工作,仿真对象也会因某种信号作为契机结束操作,类似契机作用的信号也称为沟通。

图5.5.4 默认的数据传输。

沟通”原意是指模块之间相互传输数据的时候,由于时序表现过度协调(一开一关都非常有默契),结果让人误以为模块宛如活物般正在执行沟通。默认下模块会按照时序相互传输数据,如图5.5.4所示,控制模块会按照时序表现发送数据,然后功能模块也会按照时序表现锁存数据。然而“沟通”会是基于默认下的数据传输,换句话说“沟通”一般都会用到 DataSig以外的契机信号才对。

图5.5.5 触发式沟通。

如图5.5.5所示,触发式沟通时最简单的沟通方式,其中控制模块会经由TrigSig信号发送一个时钟周期高脉冲作为契机触发功能模块开始工作。我们可以用 Verilog 这样描述,结果如代码5.5.4所示。

1.    else2.        case(i)3.    4.            0:5.            if( TrigSig ) i <= i + 1’b1; // 等待触发信号的高脉冲6.    7.            1:8.            ...... //操作开始执行;9.    10.            2:11.            i <= 4’d0; // 操作完成返回步骤012.    13.        endcase

代码5.5.4

如代码5.5.4所示,操作一开始的时候会停留在步骤0一直等待 TrigSig,直到TrigSig引来高脉冲,那么i就会递增以示下一个步骤。当i指向步骤1的时候,操作就会开始执行,然而操作结束以后,步骤会指向2,其中指向工具会被清零以示一次性的操作已经结束,紧接着返回步骤0等待下一个TrigSig的高脉冲,以示执行下一次性的操作。触发式沟通的应用范围很广不过都是小功用的沟通而已,例如电平状态变化。

图5.5.6 使能式沟通。

如图5.5.6所示,控制模块经过 EnSig信号使能功能模块以示执行工作,其中EnSig拉高状态作为契机,功能模块才会一直工作。我们则可以用 Verilog 这样描述,结果如代码5.5.5所示:

1.    else if( EnSig )  // EnSig高电平,开始执行操作2.        case(i)3.    4.            0,1,2,3:5.            ..... // 操作内容6.    7.        endcase

代码5.5.5

如代码5.5.5所示,如果EnSig不拉高操作就不会执行。使能式沟通算是一种比较细腻的沟通方式,其中我们必须知晓功能模块的时钟用量,假设功能模块需要4个时钟执行一次性的操作,那么控制模块必须拉高 EnSig四个时钟。反之,如果功能模块有非固定

耗时的操作,那么使能式沟通时无能为力的。

图5.5.7 问答式沟通。

如图5.5.7所示,控制模块持续拉高 StartSig作为契机功能便开始工作,当功能模块完成工作以后,它便会经由 DoneSig发送一个高脉冲作为收功的契机,好使控制模块拉低StartSig以示结束一次性的操作。读者没有看错,问答式沟通其实是触发式沟通还有使能式沟通的结合体,其中使能式沟通的StartSig作为开工契机,触发式沟通的DoneSig作为收工的契机。Verilog的描述方法如代码5.5.6所示:

1.    else if( StartSig )  // StartSig拉高,开始执行操作2.        case(i)3.    4.            0,1,2,3:5.            begin .....; i <= i + 1’b1; end // 操作内容6.    7.            4:8.            begin DoneSig <= 1’b1; i <= i + 1’b1; end // 产生完成信号9.    10.            5:11.            begin DoneSig <= 1’b0; i <= 4’d0; end12.    13.        endcase

代码5.5.6

如代码5.5.6所示,当 StartSig拉高的时候,功能模块开始执行操作,直到操作结束,功能会经由DoneSig产生高脉冲以示一次性的操作结束。当控制模块接收到高脉冲的DoneSig以后,它也会拉低StartSig以示一次性的操作已经结束。问答式沟通时应用范围最广也是最好用的沟通方式,它除了模仿顺序操作意外,问答式沟通不像使能式沟通那样必须了解功能模块的详细耗时数量,所以不管功能模块有没有固定的耗时,它也能霸王硬上弓。

经过各种各样的沟通方式讨论以后,无疑我们知道问答式沟通是可以解决exp23~24——仿真模块的问题。在此之前读者必须好好理解,如果仿真对象失去用法模板,基本上是无法实现问答式沟通 ... 在此,好奇的同学可能会问:“笔者,为什么那么重视用法模板还有沟通方式呢?“

假设模块A与B发生沟通,模块C与D发生沟通,为了维护还有清晰所有模块的必然性,所有模块笔者都会采用问答式沟通。这样一来不管什么模块都用相同的“框架”,操作过程也好,沟通模式也罢,结构上都是一模一样的。如此一来,解析仿真信息的时候,我们可以省下许的精力还有时间。

exp25_simulation.vt
1.    `timescale 1 ps/ 1 ps2.    module exp25_simulation();  3.    4.        reg CLOCK;  5.        reg RESET; 6.        reg [7:0]rD,rQ;7.         8.         /***********************************/9.    10.        initial                                                11.        begin      12.             RESET = 0; #10; RESET = 1;13.             CLOCK = 1; forever #5 CLOCK = ~CLOCK;14.         end15.         16.         /***********************************/17.        18.        reg isStart,isDone;19.        reg [7:0]C1,rTemp;20.        reg [3:0]j;21.        22.        always @ ( posedge CLOCK or negedge RESET )23.            if( !RESET )24.                begin25.                    C1 <= 8'd0;26.                    rTemp <= 8'd0;27.                    rQ <= 8'd0;28.                    j <= 4'd0; 29.                    isDone <= 1'b0;30.                end31.            else if( isStart )32.                case( j )33.                    34.                    0:35.                    if( C1 == rD ) begin  C1 <= 8'd0; rQ <= rTemp; rTemp <= 8'd0; j <= j + 1'b1; end36.                    else begin C1 <= C1 + 1'b1; rTemp <= rTemp + rD; end37.                    38.                    1:39.                    begin isDone <= 1'b1; j <= j + 1'b1; end40.                    41.                    2:42.                    begin isDone <= 1'b0; j <= 4'd0; end43.                    44.                endcase45.                46.         /***********************************/47.         48.        reg [3:0]i;49.        reg [7:0]rRead;50.    51.        always @ ( posedge CLOCK or negedge RESET )52.            if( !RESET )53.                begin54.                    i <= 4'd0;55.                    rD <= 8'd0;56.                    rRead <= 8'd0;57.                    isStart <= 1'b0;58.                end                59.              else 60.                  case( i )61.                    62.                        0:63.                         if( isDone ) begin isStart <= 1'b0; rRead <= rQ; i <= i + 1'b1; end64.                        else begin isStart <= 1'b1; rD <= 8'd4; end65.                        66.                        1:67.                        if( isDone ) begin isStart <= 1'b0; rRead <= rQ; i <= i + 1'b1; end68.                        else begin isStart <= 1'b1; rD <= 8'd5; end69.                        70.                    endcase71.                    72.        /***********************************/        73.                                                                                   74.    endmodule

exp25 是 exp23~24的改良版,其中仿真对象应用用法模板还有问答式沟通以外,虚拟输入也使用相同的用法模板。如代码 exp25_simulation 所示,第22~44行是仿真对象,内容与代码5.5.3相似;第51~70行是虚拟输入,其中步骤0为仿真对象输入4,步骤1则是为仿真对象输入5。

exp25与exp23~24相比,最大的改变除了仿真对象以外,虚拟输入也产生很大的改变,我们知道仿真对象的功能是不固定的,亦即时钟用量随着输入内容而产生改变 ... 由于仿真对象已经采用问答式沟通,那么虚拟输入再也不用预测时钟读取rQ的结果(不用预先运行一次仿真),换之虚拟输入只要等待 isDone的反馈,然后再读取rQ的结果即可。

图5.5.8 exp25的仿真结果。

图5.5.8是exp25的仿真结果 ... 如图5.5.8所示,C0指向的地方是仿真对象的第一次操作,虚拟输入拉高isStart之际,又为rD赋值4。仿真对象在下一个时钟检测到isStart的过去值是1,然后开始执行操作。C1指向的地方是仿真对象完成操作的时候,rQ已经更新未来值16。C2指向的地方是仿真对量拉低isDone的时刻,同时也是虚拟输入接收完成反馈(注意isDone的过去值),虚拟输入除了读取rQ的过去值以外,它也着手拉低isStart(注意isStart的未来值)以示一次性的操作已经结束。

C3指向的地方是仿真对象的第二次操作,虚拟输入拉高isStart之际,它也为rD赋值5。仿真对象在下一个时钟检测到isStart的过去值是1,然后开始执行操作。C4指向的地方是仿真对象完成操作的时候,rQ已经更新未来值25。C5指向的地方是仿真对量拉低isDone的时刻,同时也是虚拟输入接收完成反馈(注意isDone的过去值),虚拟输入除了读取rQ的过去值以外,它也着手拉低isStart(注意isStart的未来值)以示一次性的操作已经结束。

除此之外,我们也可以从图5.5.8当中知道,仿真对象的两次性操作都有不同的时钟用量,如C0~C2的周期是70ns(第一次操作),C3~C5的周期是80ns(第二次操作)。而且,我们也知道i指向虚拟输入的过程,j则指向仿真对象的过程。这一切的一切已经证明,我们已经巧妙的使用用法模板,还有沟通方式解决 exp23~24 的两大难点。虽然遗憾的事情是我们无法指向时钟(无论是仿真对象还是虚拟输入),不过作为补偿,使用指向工具指向步骤已经我们是最大的努力了。

我们一般在建模的时候,我们都必须尽最大的努力使操作内容有固定的时钟用量,但是世事不是都能如人所愿,有些操作必须是非固定时钟用量。操作有固定时钟用量的好处是可以仔细指向时钟,好让必然性更加清晰。如果操作是非固定时钟用量,指向时钟就很难实现,换做补偿,指向对象从时钟移向步骤。

好了,这个小节差不多要结束了,结束之前让我们好好回忆小节5.5的重点内容:

笔者使用投币的例子示意仿真存在必然性,必然性的意思是指“什么东西,在什么时候,有什么结果”,必然性之所以那么重要,因为必然性引导仿真结果走向预想所要的关键。

建模阶段,我们有两件事情必须考量:

(一)维护必然性

(二)清晰必然性

维护必然性一般是指我们使用用法模板“固定”操作内容;清晰必然性则是指用指向工具指向操作内容的细节。此外,契机也是必然性的一种,人会某种契机命运则会发生某种改变,模块也会某种契机发生某些动作。沟通是模块作为数据信号以外的信号作为契机而发生互动,常见的沟通方式有三种:

(一)触发式沟通

(二)使能式沟通

(三)问答式沟通

触发式沟通是使用 TrigSig 的高脉冲最为契机;使能式沟通时使用 EnSig的持续拉高

状态作为契机;问答式沟通则是前两者的复合体,EnSig作为开工的契机,TrigSig则是作为收工的契机。

最后的重点,读者如果要充分理解“必然”,读者必须站在白骆驼的角度去思考,白骆驼的为了引导蒂沙,作为前提条件,蒂沙的命运宏图必须是清晰直观,,然而白骆驼不仅要观察每个命运碎片的内容,它也要观察碎片与碎片之间的契机

5.6 仿真迷宫①

今天一大早,笔者与同辈们都聚集在一座圆形广场当中,广场被5米高的围墙团团围绕

,围墙一角有一座小台,台上却站着一排神情严肃的师兄们。面向眼前的古怪情况,同辈门开始窃窃私语,声音无意间也流入笔者的耳朵里。

“今天怎么搞的?一大早就把所有人召集在这里”,同辈A道。

“俺怎么知道啊?”,同辈B道。

“嘘 ... 小声点,师兄望向这里了!”,同辈C道。

很显然,大伙也不知道师兄们的用意 ... 不过,笔者隐约间察觉到,隐藏在气氛之中的不详之意,直觉告诉笔者,接下来很可能会举行一起大规模的危险活动。不一会儿,一位资深的师兄开场白道。

“首先恭喜聚集在这里的诸位,因为诸位已经完成基础考验”,资深师兄道。

“今天把诸位聚齐是为了举行一项传统活动”,资深师兄道。

“诸位只要通过这项传统活动,诸位就会成为独当一面的男人”,资深师兄道。

话后,那位资深的师兄似乎有意停顿演讲,于是人群中又开始窃窃私语,笔者偷偷望向前方的同辈,有人露出兴奋的神情,有人露出担忧的神情 ... 不用说大伙也知道,师兄所谓的传统活动其实是最后考试,活动本意不复杂,亦即成者健在败者淘汰的能力测试。不过真正让笔者担心的是活动的内容,根据传统流派一贯的强硬作风,笔者相信活动本身一定存在危险性。

随之,笔者把注意力放回台上,一瞬笔者好似看见资深师兄在阴笑,眨眼几下,阴笑即消失,于是笔者便踌躇自己是不是疑心过度了,一瞬的阴笑难道是幻觉吗?就在笔者胡思乱想之际,暂停的演讲又继续道。

“诸位,请看左边”,师兄道。

不知什么时候,一座高4米的巨大笼子逐渐在广场的一角浮升上来,笼子的内容让在场每一位师弟都睁目结舌 ... 此刻,包括笔者还有在场的所有人,生平第一次体验到,真正的恐惧。“那是什么?”吃惊的话语不经意从笔者的口中流了出来,笼子的里边站立一只,不 .... 确切来说是一块,既不是死物也不是生物的东西,纤小的四肢支撑不等均衡的四方躯体,身上布满密密麻麻的逻辑,然而那双似目不是目,宛如无底洞般的漆黑小孔,仿佛可以吞噬一切希望,让人不颤而栗。

“那 ... 那是 ... 什么!?”,同辈A颤抖道。

“诸位,这是称为切糕的怪物”,师兄道。

“活动很简单 ... 要么就是把它啃掉,要么就是被它啃掉”,师兄冷漠道。

“那么,祝各位好运!”,师兄用吊丧的口气道。

师兄话音刚落,碰一声!入口的大门便紧紧锁死,人群开始喧嚣起来 ...

“可恶!这是怎么回事,拜托给咱说明清楚!”,同辈B喊道。

“喂 ... 喂!看 ... 看哪里!”,同辈C颤抖道。

一位同辈用颤抖不停的手指向广场一角,敲击笼子的“嗙嗙声”不停从那边传来,其它同辈们也随之望向声音的出处,人们的脸上立即染上青白两色,一瞬时间仿佛也失去流动。方才还是一副睡脸的巨大怪物,宛如饿狼禁不住食物的诱惑开始暴动起来。“嗙嗙声”一下,“嗙嗙声”又一下,众人的心脏也跟着敲击声一起在剧烈跳动。随着响起一股沉闷的金属落地声,僵住的时间再度恢复流动。

”咕咕咕 ....“,怪物声。

众人意识到,不妙的事情即将发生了,但是恐惧的情绪让它们忘了入口早已封死,然而众人却你退我挤地冲到哪里。

”开门!师兄拜托了!快开门啦!“,同辈D叫喊道。

”别开玩笑了!那种怪物根本不是同一个次元的对手!“,同辈E愤怒道。

”啊 ....!“,惨叫声。

笔者向惨叫声望去,有几名同辈瞬间倒在切糕的旁边,它们两眼翻白口吐白沫。切糕发出呵呵两声以后,继续寻找下一个猎物。云之间,笔者的视线和切糕对上了,喷涌而上的恐惧麻痹全部神经,不停使唤的双脚让笔者想逃也逃不了,眼见切糕正一步步逼近,脑海却忽然浮现家乡的小花,笔者还不想死,因为笔者还没有向她告白 ... 可是笔者什么也做不了,笔者只能绝望地等待切糕的到来。

上述一段故事是笔者第一次执行仿真的时候所体验的经历,那时候笔者还年轻,没有任何准备就开始仿真,结果就是一次又一次的惨死。仿真既有单向也有多向,但是在默认下都是多向仿真,不管读者愿不愿意,多向仿真老早就存在一定程度的变数,而且这些变数会衍生许多可能性,结果让仿真成为一座迷宫。

有玩过迷宫探索游戏的同学一定知道,迷宫只有一个出口,找寻这座出口也是唯一一个通关条件,除此之外迷宫也存在许多陷阱还有假出口,踏入这些陷阱或者假出的游戏任务往往都是用 Game Over 换来结局。当仿真开始执行的时候,蒂沙就会掉进迷宫当中,我们的身份好比白骆驼般,帮助蒂沙避开生命的陷阱,引导她走出人生的迷宫。

身在迷宫当中有危险的不仅仅是蒂沙本人,就连我们这些引导者也存在危险。笔者年轻的时候曾经玩过一款古董RPG,笔者操纵勇者进入一个高难度的迷宫,老旧RPG基本上都没有地图补助系统,记录迷宫除了使用脑力以外笔者也会用笔和纸张,但是不管笔者怎么努力,笔者花了3天的时间也走不出迷宫,其中勇者不是掉进落穴成为蜜蜂窝,就是被天花板压成纸片,仅是一些惨不忍睹的结局。

心灰意冷的笔者发誓再也不玩迷宫探索游戏,但是笔者早就中毒已深。身为玩家的我们,虽然不像勇者那样一会变成蜜蜂窝一会又变成纸片。但是,勇者每次经历死亡笔者的心情也跟着沉了几下,勇者来回死亡无数次以后,笔者的心情沉到谷底。心情接连几天都是灰灰的,笔者不仅没心情听课也没有力气作功课,感叹上学超麻烦,活着没意义 ... 真心希望有一粒陨石,忽然从天而降引起侏罗纪悲剧多好。后来被母亲教训一顿以后才重新振作。

笔者后来反思道,原来这是一种失去希望的心境,也是俗称的绝望。绝望的时候,我们什么都觉得无所谓 ... 然而,绝望给人最大的冲击就是自身的无能,不管笔者再怎么积极也好,燃烧的火焰不可能永远继续下去,挑战的心情也有消失殆尽的一天。笔者自责无能,无法帮助勇者创出迷宫,最后放弃游戏,放弃挑战。

天意弄人,十年后的今天,笔者还要面对迷宫,不过这次不是游戏迷宫而是仿真迷宫。迷宫中有一种怪物,它高3米,重量200kg,长方形的身躯,最为特色是那双黑洞般的漆黑小孔,人称恐怖大王——绝望切糕。切糕是仿真信息的集合体,压倒性的信息量是切糕最大的武器,它时常将自己隐藏在黑暗的角落,窥视猎物捕食它们的希望。

猎物起初会不知所措,胡乱逃跑,然后颤栗会麻痹神经,目光开始浑浊渐渐失去生气,最后放弃希望。读者会认为笔者又在吹牛了 ... 什么恐怖大王,别笑死人了,哈哈哈!嘘 ... 读者要取笑笔者没有问题,但是不要笑太大声,切糕最喜欢啃食充满希望的年轻人,而且自负会让人大意,最糟的结局就是成为切糕的食物。

切糕一般是指压倒性的仿真信息,远远超过一般人可以承受的分量。然而,产生切糕的原因就是“不正当”的仿真手段,文中的不正当不是字面上的意思,而是指没有考量前期建模,也没有准备适当的仿真手段。事实上,传统流派就是切糕的父母,那是因为传统流派没有适当的仿真手段,如:不会考量前期建模,没有遵守时序表现,激励文本没有布局,激励内容没有用法模板,没有指向工具等 ... 都是切糕诞生的原因。

切糕是异世界(仿真)的怪物,它喜欢藏身在两个地方,亦即纪激励文本(仿真之前),还有解析仿真信息(仿真之间)。

处在编辑激励文本期间:

激励文本好比c语言唯一一个的main函数,读者尝试想象一下,如果什么操作都集中在main函数会是什么样的情况?是不是看下就觉得头疼?其实C语言的情况还好,因为C语言自身除了拥有顺序结构以外,C语言也有许多隐性操作(编译器代劳)。相比之下,激励文本就是一场仿真环境,我们不仅需要声明出入端,我们也要使用寄存器(reg)还有连线(wire)模拟出入端。结果如代码5.6.1所示:

(注:reg模拟输入端,wire模拟输出端):

1.    reg CLOCK;              // 寄存器CLOCK模拟 输入端CLOCK2.    reg [7:0]reg_WrData;   // 寄存器 WrData 模拟 输入端 WrData3.    wire [7:0]wire_RdData;  // 连线 RdData 模拟 输出端 RdData4.    5.    abc_module U16.    (7.        .CLOCK( CLOCK ),         // 寄存器 CLOCK 驱动 仿真对象 的CLOCK输入端8.        .WrData( reg_WrData ),  // 寄存器 WrData 驱动 仿真对象 的WrData输入端9.        .RdData( wire_RdData ), // 连线 RdData 牵引 仿真对象 的 RdData 输出端10.    );

代码5.6.1

一般,仿真对象在激励文本实例化以后,激励内容都会引用这些模拟出入端的寄存器还有连线,结果如代码5.6.2所示:

1.    always @ ( posedge CLOCK )  // 引用 寄存器 CLOCK2.        ....3.        case( i )4.    5.            0:6.            begin reg_WrData <= 8’hAA; i <= i + 1’b1; end  // 引用 寄存器 CLOCK7.    8.            ......9.    10.            5:11.            begin rRead <= wire_RdData; i <= i + 1’b1; end // 引用 连线 RdData12.    13.        endcase

代码5.6.2

不过,如果仿真对象过度庞大,出入端的引用状况好比蜘蛛网上的一群蚂蚁,一群蚂蚁是指无数的寄存器(输入端模拟),蜘蛛网是指纵横交错的连线(输出端模拟)。如果激励文本没有一定的结构性在背后支持,激励文本编辑起来会变得非常麻烦,耗时又费力。

此外,激励文本也会变成非常混乱不堪,然而这些混乱到极点的代码信息,解读起来会是一场非常辛苦的战斗。切糕就是隐身在其中。

总结而言 ... 仿真前,如果仿真对象有太多模块或者功能过度集中,仿真对象必定存在无数的出入端。出入端太多,不仅会影响激励文本的美观,而且激励文本也会臃肿起来。此外,激励文本的编辑工作也会变得非常麻烦,更加耗时,更加费力,最糟糕就是激励内容的清晰度会大打折扣。

l 期间,我们先是越来越焦急,因为太多输入端让我们一时之间喘不过气来;

l 接着,我们会越来越失意,因为不管我们怎么编辑激励内容,都无法如愿以偿;

l 后来,我们会越来越颓废并且开始自暴自弃,一边咒骂屏幕一边狂敲键盘;

l 最后,我们会萌生放弃的念头,感觉自己什么也作不好,还不如死掉算了。此刻,我们可以断定,切糕正一步步捕食我们的希望。

切糕除了存在于激励文本(仿真之前)以外,切糕也存在于解析仿真信息(仿真之间)。笔者曾经说过变数衍生可能性,如果没有适当仿真手段控制变数,一旦变数暴走起来,变数便会无限放大可能性,从而海量化仿真信息。每当我们启动Modelsim开始仿真,wave界面所播放的时序结果,只是无限可能性当中的一种可能性而已,不过不管哪一个可能性,切糕都隐身其中。

解析仿真信息期间:

l 宛如洪水一般的时序结果,滔滔不绝即绵绵不断冲击我们的大脑,我们越看越焦急,因为我们无法承受压倒性的信息量;

l 接着,我们会开始寻找的切入口,然而这是海里捞针的作业,我们越找心越灰;

l 虽然找到切入口会换来短暂的兴奋,但是真正的恶梦才开始,解析作业必须同时联系仿真对象,激励内容还有时序结果,我们越是追踪流向,脑袋越是感觉要爆开;

l 越是期待流向的结局越是大失所望,因为流向大多数会进入死胡同;

l 上述作业不停轮回,我们也会越来越绝望,放弃的念头越来越旺盛,因为不管我们重复多少次都是遇见死胡同;

l 最后,燃尽希望火焰的我们会觉得仿真必死更难受。此刻,我们可以断定,切糕正在一步一步吸食我们的希望。

读者理解了吗?切糕究竟是如何潜伏黑暗,吸食我们的希望。虽然仿真之前,还有仿真之间都存在切糕,但是后者的切糕不仅数量更多,而且杀伤力也更强。形象点说,仿真之前好比勇者在草原上遇见几只小切糕,只要我们做好一定程度的准备,如:早期建模有规划,模块有用法模板,激励文本有结构性 ... 我们多多少少,也能干掉这些小切糕。

仿真之间,好比勇者走入迷宫,迷宫里不仅存在数之不尽的小切糕,迷宫也存老大级别的大切糕。勇者就算准备再怎么充足,能力再怎么高强,勇者一旦踏入迷宫,入口立即就会封死,然后就会成为无止境的消耗战。不管勇者死亡多少次,勇者都会重生然后返回起始之处,勇者的肉体虽然可以无限恢复,但并不表示勇者的精神也一样,精神状态反而会伴随轮回的次数表现越来越差。

仿真就是这样一个恶性质的迷宫,它不允许入侵者离开,同样入侵者的灵魂也休想离开,入侵者只要一天都无法找到出口入侵者都无法离开迷宫。入侵者经过无数死亡还有重生以后,人心跟着坏掉,直至变成一具没有希望的行尸走肉,永远徘徊在迷宫之中。虽说进入迷宫的人不是我们而是勇者,或者说蒂沙进入迷宫,然后我们要引导她走出迷宫。但是,绝望切糕不管对象是人还是神,它都会无差别攻击。

传统流派是自负的流派,也是爱拼才会赢一族。它们不会在意事先准备,它们也不在乎迷宫有多复杂(不管仿真有多复杂),它们都相信自己可以克服切糕(解析海量信息),找到出口并且征服迷宫(得到预想所要的仿真结果)。它们始终相信这个世界(仿真)不用弱者,淘汰弱者。

同样,一般参考书也有类似的问题,参考书本身不会为仿真解释过多,如果读者无法理解,无法承受,这一切只怪读者自己太弱了。笔者因此认为,参考书是切糕的帮凶,它间接伤害我们的信心还有仿真的希望。笔者就是其中一位受害者,每当气候风吹起,记忆的伤口都会隐隐作疼。

好了,这个小节也差不多是总结的时间了 ... 虽然笔者在这个章节里边,说了许多无关紧要的故事,读者会认为这是废话也不奇怪。在此,笔者是有意用故事比喻仿真的种种细节,还有仿真当下的心境情况。常规的参考书除了赠送一副简单的时序图,还有简短的解释以外,余下就是一段混乱不堪的激励文本。参考书是不会为仿真作出各种角度的解释。

仿真的本意(精髓)就是将仿真对象,激励文本,还有时序结果联系起来并且做出解析,但是仿真不是调试,它没有指向工具,也没有C语言般的隐性处理。此外,解析对象可能是众多可能性之中的一种可能性而已。仿真的之前,我们都要好好必须考虑自己的能耐,试问自己究竟是不是已经做好充分的准备?不然的话,仿真会是一件极为耗命的工作。

笔者曾经仿真仿到头昏脑胀,失去食欲甚至呕吐起来,笔者本来就是身体衰落的老人,健康不能拿来开玩笑,经历那么一次体验以后,笔者开始领悟,仿真需要用健康健来交保。于是,笔者开始寻找一种不伤害精神和肉体仿真手段,想着想着,笔者开始回忆往事,那段让人极度厌恶的迷宫探索游戏。

笔者将,仿真形容为恶性质的迷宫,海量的仿真信息形容为切糕,虽然自认有点幼气,不过却肝肺非常恰当。我们是白骆驼(玩家),仿真对象是蒂沙(勇者),然而我们的任务是引导蒂沙走出迷宫,不过隐藏在迷宫之中存在无数切糕怪物,它们不仅会攻击蒂沙,它们也会攻击我们 ... 它让我们心灰意冷,渐渐失去希望(其实这是一种精神伤害)。

切糕除了发动精神攻击以外,切糕也会发动物理攻击。仿真原本就是并行操作,解读时序之际,我们需要追踪数个信号,这种行为无疑我们会耗费更多脑力还有集中力 ... 此外,我们还要同时联系仿真对象,还有激励内容,因此我们不得不全神关注。当我们长时间盯着屏幕看时序,切糕就会暗地里攻击我们,我们会感到眼睛不适,脑袋发疼。如果我们稍微分散集中力,情绪会逐渐焦虑,心情也不能平静,而且还会感觉疲惫。

切糕不是笔者妄想的怪物,它确实存在 ... 试问读者,是否曾经对仿真产生厌恶感,或者对仿真失去信心,又或者一作仿真就头脑发疼?有的话,那就证明读者曾经被切糕攻击过。我们受到切糕攻击以后,就会渐渐失去希望,心情会非常低落,心理还有生理都会觉得疲惫,如果长期处在这种心境,人会作出一些伤己的行为,其实一点也不奇怪。

仿真除了存在切糕吸食我们的希望以外,其实仿真也是一种毒瘾,它会侵蚀我们的心。

5.7 仿真迷宫②

不 ... 不要呀!当笔者再一次醒来的时候,笔者发觉自己躺在病床上,笔者不禁在心里询问自己究竟是如何来到这里。笔者开始寻找记忆的蛛丝马迹,脑袋好疼 ... 脑袋仿佛对笔者发出抗议一般拒绝运动,笔者立即按住太阳穴缓和头疼。渐渐地,笔者开始意识到周围充满无尽的呻吟声,笔者想起身探个究竟,可是一名身穿白大褂的中年即时阻止笔者。

“小哥 ... 现在还不能起来!”,中年道。

“先 ... 先生,发生什么事了?”,笔者问道。

“...”,中年沉默道。

“这里!究竟是怎么回事!?”,笔者大声道。

笔者是一位懒惰发脾气的男人,难得今天笔者就是压抑不了冲动,中年摸了几下下巴,稍微仰头思考一会后,然后开始道出事情的由来。中年是大夫,它说笔者已经在病坊昏迷了许多天,笔者的确感觉浑身充斥疲态感。

“先生,别管小弟 ... 那些人怎么呢?”,笔者急忙问道。

“已经没有希望了 ... ”,中年遗憾道。

“没有希望?先生没听见呻吟声吗?”,笔者反驳道。

“小哥,仔细听听 ... ”,中年指示道。

话后,笔者立即竖起耳朵聆听呻吟声 ...

“俺不要切糕了!俺不要仿真了!绕绕俺吧!”,同辈A诉求道。

“嘻嘻嘻,仿真仿真仿真仿真!”,同辈B兴奋道。

笔者用疑惑的眼神望向大夫,大夫摇头表示它们已经没有希望了。笔者从中了解道,这里所有人都是那场活动的遇难者,在场所有人都被切糕吞噬希望,醒来以后就成为那副模样。

“除了小哥以外,其它人都坏掉了 ... ”,中年遗憾道。

“坏掉了?什么坏掉了?”,笔者问道。

“抱歉 ... 正确来说,它们都是仿真癌的病患,无药可救。”,中年冷漠道。

“仿真癌!?”,笔者重复道。

大夫说道,笔者也是其中一名病患,不过很庆幸的是笔者还能保持自我。所谓仿真癌病是一种心理癌症,“强迫仿真,恐惧仿真”的矛盾压力会不断在心理扩大,直至压垮病患的精神。强迫仿真一种上瘾心态,每当我们建模的时候,未知的建模内容会让我们心存不安,余下也只有仿真能消除这份不安 ... 但是Verilog不是顺序语言,仿真也不是调试,所以我们无法一边建模一边仿真。

这份无法消除的不安会愈来愈糟糕,仿真的冲动也会愈来愈强烈,心理的失衡也会愈演愈烈,这种情形会持续到建模结束,仿真完毕为止,然而这份解放感会依存在心理深处

。上述现象来回重复一定程度以后,人们就会养成对于仿真的依赖,也是俗称的仿真上瘾。这种感觉好比我们憋尿许久,解放以后我们会产生莫名的快感,为了再度体验这份快感,我们会养成憋尿的坏习惯。

恐惧仿真是一种恐怖心态,每当我们执行仿真之际,庞大的信息量越让我们愈加焦急,再加上屡试屡败的挫折感,心理深处就会对仿真产生剧烈的抗拒感。上述现象重复一定程度以后,我们会越来畏惧仿真,然后我们会妄想逃到没有仿真的角落。这种感觉好似我们被蛇咬,从此以后都会莫名畏惧草绳,走路再也不会靠近草丛。

强迫仿真还有恐惧仿真,原本是一种相斥的极端心态。不过很遗憾的事,如果没有恰当的仿真手段,同时患上两种心态是绝无法对避免的事实。此外,这两极端又矛盾的心态会不停左右我们的心理,折磨我们的心理 ... 这种感觉好比灵魂的左天使与右恶魔同时耳语道,“这样做!”,“不要这样做!”,我们最终会承受不了幻听把头撞墙以求一份安静。但是,矛盾的窃窃私语不仅不会停止,反而会愈来愈强烈,直至心理崩溃。

或许有人一生也都无法发现,自己处在强迫与恐惧心态之间执行仿真,然而他们却会觉得仿真非常疲惫 ... 这种疲惫感却是仿真癌正逐渐侵蚀内心的最好证据。有些同学可能会好奇道,如果内心过度被侵蚀,结果究竟会怎样?这些一人一旦接近仿真就会开始抓狂,情绪不稳定,出现自毁倾向 ... 是不是觉得很可怕呢?

同学可能又会觉得笔者在瞎扯了 ... 非也!笔者只是述说过来人的经历而已,绝无瞎扯成分。那么究竟是什么原因让人患上仿真癌(强迫 vs 恐惧)?我们又该怎么避免?然后又该怎么治疗?

试问读者是否有过这样的感觉 ... 我们在建模的时候,心理都会出现莫名的忐忑感,仿佛每写一行代码,呼吸也跟着急促起来,感觉自己快要窒息。这种感觉好似读者返家途中,夜路不仅散发上一丝丝的凉意,而且还安静得出奇可怕,故障的路灯一闪一闪地更加渲染诡异的气氛,一路上都觉得有东西在背后尾行 ...

这是不安的生理反应,我们之所以会感觉不安,那是因为我们过度意识未知的建模内容。很多时候,我们虽然理解代码的具体意义,但是我们却无法预测代码的时序表现 ... 就是这种看不到,听不到的情况,让心里深处萌生不安。然而又竟是什么原因导致我们,“仅理解代码目的却无法预见时序表现呢?”,答案是,亦建模内容不清晰,模块的表达能力不强,结构散乱等一系列原因。

笔者与许多同学一样,都是经由传统流派认识建模,认识仿真。传统流派是自负的流派,自信的它们相信自己不用准备就可以克服建模,克服仿真,然后成为勇者,然而成为勇者仅是一小部分强人而已 ... 弱者多数会被淘汰。笔者当初也不知道,原来前期建模对仿真影响至深,笔者是一位弱者也经受不了折磨,它甚至伤害笔者的小小心灵,结果萌生退意。

笔者曾经有过放弃学习的冲动,原来那是笔者的潜意识在害怕不安,潜意识选择逃避来自我保护,逃避不是什么可耻的事情,那是生物的求生反应,还不如说回避才是人之常情。但是笔者就是不甘,经过长时间的思考以后,笔者才发觉不安的源头,就是没有做好前期建模的准备。

好的模块都有直接的表达能力,清晰的内容,望眼一看就知道模块的功用,稍微浏览也能知道大概的意思。此外,清晰的内容不仅让人理解代码目的,也能让人预测代码的时序表现。这里所谓的预测,是指“脑海的时序结果”,而不是仿真的时序结果 ... 我们虽然不能一边建模一边仿真,但我们却能一边建模,一边用脑仿真代码。如此一来,我们就能消除未知内容所导致的不安心理。不安得以消除,仿真强迫症也会自然无药而愈。

“原来如此 ... ”,笔者点头道。

中年大夫,滔滔不绝的解说完毕以后,笔者立即陷入思考。用脑仿真模块,人脑的记忆容量不仅少而且储存时间也非常短暂,而且人脑的记忆还是非常暧昧,要用脑袋实现Modelsim一样的工作,说实在这是一种大胆的尝试 ... 想着想着,头脑又开始发疼了。中年大夫见状,便急忙劝说放松 ... 可恶!还不是那家伙的错,说了那么多道理,好奇心旺盛的笔者不去思考才怪!

头疼稍微缓和后,笔者继续话题。

“那么,如何解决恐惧仿真?”,笔者问道。

“这 ... 这个,那个 ... ”,大夫嘟囔道。

中年大夫显然有难言之隐,它是担心笔者的身体?还是考虑其它顾虑呢?中年大夫犹豫一会儿后,以咳嗽声示意话题继续,笔者过眼一视,中年大夫却露出方才没有的坚毅神情,它似乎在心理深处做好什么觉悟似的 ...

仿真是一座恶性质的迷宫,笔者曾经这么形容过 ... 此外,还有一种名为切糕的恐怖大王,它们都是恐惧仿真的源头。一般上,我们都是建模结束以后才执行仿真,仿真不是调试,不是一键 <F5> 或者 <F6> 就了事,我们必须事先预设,然后准备激励文本,最后才能启动仿真。

由于仿真是建模以后的工作,仿真对象也是建模完毕的模块,结果体积都会非常庞大。这里所谓的体积庞大是指,仿真对象有过多模块集中在一次,笔者曾经说过,如果过多模块集于一身,仿真对象就会有很多出入端。如果出入端太多,实例化仿真对象会是一件非常辛苦的劳动,而且激励文本的编辑工作也是非常猥琐,直至让人抓狂。此刻,切糕在仿真前出现了。

猥琐或者辛苦的劳动,笔者相信只要紧咬牙关就能挺过去 ... 然而,读者也许不知道,切糕给予我们的第一次打击,事实上我们已经流失过半的体力与精神。形象点说,勇者为进入迷宫之前,它就得先消耗过半的HP与MP在路途的小切糕身上。勇者流失HP只要喝喝几口回复药就能立即回复,反之流失MP却使用回复药补充确是有限的手段。为了维护游戏的平衡性,一般的MP回复药都比HP回复药还要贵上10倍,无奈之下笔者必须靠休息来回复MP。(千万别吐糟现实世界没卖回复药)当勇者进入迷宫的时候,真正的噩梦才总算开始 ...

勇者进入迷宫之际,也是仿真开始的时候 ... 迷宫是仿真信息的形象形容,一个可能性的仿真结果其实仅是总体仿真信息的一部分而已。面向错综复杂的仿真信息,我们的第一反应就是胆怯,亦即切糕给予我们的第一次攻击。常规的仿真手段都是没有指向工具,仿真信息宛如一片茫茫的大海,然而要在密密麻麻的信号之间寻找一个入口,就是大海捞针的作业。此刻切糕给给予我们第二击攻击。

“找到入口了!”,当我们兴奋喊着喜讯,所有切糕就会被希望所吸引,然后虎视眈眈的切糕便会开始行动。

l 没有指向工具,容易迷失方向;

l 没有遵守时序表现,迷宫会非常错综复杂,而且崎岖难行(信号没有对齐性);

l 没有布局的激励文本,迷宫会上下颠倒(联系时序结果与激励内容很难);

l 没有控制变数,迷宫会进一步扩展(仿真信息海量化)

上述四点是常规仿真手段所犯下的错误,读者可能无法留意,如果我们无视上述四点,使劲追着一条一条信号在跑,此刻我们的体力和精神也会大把大把在流失。此刻,切糕藏身在黑暗之中,无限攻击我们。假设,我们很庆幸拖着半死的状态来到迷宫的终点,心理正要欢喜的时候,谁知这是一个错误的仿真结果 ... 我们的心会立即跌到谷底,然后咒骂自己那么辛苦,既然才得到一个渣渣而已。此刻,切糕BOSS一击便KO我们。

上述情况经过无数次以后,还是一直在仿真之间不停绕圈圈。身为白骆驼(玩家)的我们可能会也越来越焦急,很想骂脏话。其实,这些都是正常的生理反应,因为我们在无意识之下,不断累积对于仿真的恐惧 ... 最后,直至我们用尽一切希望,仿真的恐怖就会深深烙印在我们的心底深处。

为了改善上述的问题,为了引导蒂沙走出迷宫,笔者做了以下几点补救手段:

l 应用指向工具,维护迷宫的方向;指向工具好比路牌,它很大程度为仿真树立大概的方向,读者千万表小看路牌,失去它们交通系统会变成非常混乱。

l 应用时钟,遵守时序表现,好使迷宫整齐;使用时钟驱动仿真,信号就能遵守时序表现,为此信号不仅对齐,时序表现会散发浓厚的时序香。

l 激励文本有布局,保证迷宫有一定的结构性;激励文本有结构性,激励内容会更加直观。

l 控制变数,收缩迷宫;变数会衍生可能性,可能性就是仿真信息的容量,控制变数也能间接缩小仿真信息。

当我们完成上述4点的补救手段,基本上仿真已经从恶性质的迷宫变成良性质的迷宫,切糕的数量也会大大缩小。

话到这里,中年大夫的然后脸上露出一丝忧愁 ...

“不行 ... 这样还不行!”,大夫喃喃道。

“怎么不行呢?这些补救手段不是大大改善仿真了吗?”,笔者好奇道。

“这种程度的补救手段只是治标不治本而已”,大夫道。

“什么意思?”,笔者问道。

“仿真的确已经得到改善,但是却不能改善人们对仿真的恐惧 ... ”,大夫摇头道。

笔者开始思大夫话中的含义。我们虽然可以透过补救手段让仿真这座迷宫变得美丽清晰,不过不管我们再怎么改善迷宫,迷宫始终还是迷宫 ... 仿真真正让人们感到恐惧的是它压倒性的信息量。换言之就是,人们的信息吞吐量有极限,简单点说,过多的仿真信息容易造成,脑袋的消化不良 ... 为此,人们无意识畏惧起来。

读者仔细思考一会,笔者为何将海量化的信息量形容为切糕呢?切糕原本是新疆的甜点,但是那夸张的分量,不仅让4个大男人抬得动,即时10个人吃尽10天10夜也不一定吃完。不管是什么山珍海味,我们只要进食过度也会反胃,再看下去就想吐 ... 脑袋和胃袋也有同样的道理,用脑超过极限就会开始反脑(烦恼),然后觉得头昏脑涨。反胃也好,反脑也好,那是身体为了自保,使命释放“恐怖信息”刺激脑袋,刺激胃袋 ...

正常的家伙遇见恐惧会适可而止,不过传统流派那些失常家伙会使劲强迫自己,干下去!do下去!直至“恐怖信息”累积越来越多,成为一生都消除不了的“心理烙印”。

“对不起,老夫有点激动了 ... ”,大夫抱歉道。

中年大夫尴尬的摸着后脑勺,不过它脸上的一阵泛红却变现它的愤怒 ... 为此笔者也产生共鸣,传统流派每年都有数万的新手入门,想必多少幼苗曾经被它们摧残过,现场不停呻吟的病患就是最好的铁证。天职为救人的大夫却也只能白白看它们送死而已,可见中年大夫已经在心理深处累积许多悔恨。如今它却向笔者坦白一切,笔者不禁开始担心起来 ...

“大夫,透露这些事情出来,真的没有关系吗?”,笔者问道。

“怎么没有关系 ... 老夫今晚就要跑路,离开这处鬼地方!”,大夫决意道。

“跑路!?为什么?”,笔者反问道。

“它们不会放过叛徒!”,大夫道。

“既然如此,为何又将秘密告诉小弟呢?”,笔者好奇道。

“老夫再也无法瞒着良心做人 ... ”,大夫感叹道。

“小哥是这场劫难的幸存者,可能这是某种缘分吧 ...”,大夫继续道。

笔者如今可以却侥幸活了过来,可见补救手段确在遇难之际确实已经发挥功效。根据笔者的理解,脑袋的吞吐量因人而异,切糕杀人不仅会吸食我们的希望,它还会将自身的海量信息强制灌输进入猎物的脑袋,直至脑袋当机。笔者自问脑袋不是怎么好的人,常理上遇见切糕理应必死无疑,可是补救手段却为笔者的脑袋腾出一定程度的消化空间 ... 简言之,补救手段过滤掉大量无用的仿真信息,因而笔者才可以勉强承受切糕的攻击,保住小命。

遇见切糕是绝对的恶梦,也是笔者生平第一次品尝恐惧 ... 如今,切糕的恐怖已经深深烙印在笔者的心理深处。笔者是脆弱的男人,绝对没有自信能诺然无事再度面对切糕,面对仿真 ... 在此,笔者完全理解大夫的忧虑,补救手段充其量只是治标不治本,就算我们把大量的无用信息过滤掉,余下的海量信息,也是普通人无法承受的级别。除非大脑经过强化升级,否则休想面对面啃下所有仿真信息。

在此,笔者可以断定,恐惧仿真的源头就是人类的弱小,这种感觉好比经历洪水,地震等大自然灾害 ... 面向绝对力量的面前,人类也只能一边恐惧一边打颤而已。海量的仿真信息有如天灾一样,让人畏缩,让人逃避,让人不敢直面,唯一例外就是弱小的人类变成超人,那么人类就可以正面单挑仿真,不过这也是非现实的妄想而已。

真是一起沉重的话题,笔者不经意产生疑惑 ... 这种摆明的事实,难道传统流派不曾留意?不曾想尽办法改善吗?中年大夫见状,也是无力地摇摇头 ...

“它们即使知道,也没有理由这么作 ... ”,大夫道。

“为什么!?”,笔者怒喝道。

“小哥你知道古帝国是如何支配人民吗?”,大夫提问道。

“很抱歉,小弟的历史不好 ...”,笔者答道。

“恐惧,还有愚昧就是最好的支配工具 ... ”,大夫冷漠的回答道。

这一番话突然让笔者豁然大悟 ... 这个世界上有数以万计的人从事仿真的活动,仿真会有百花齐放,百家争鸣的流派才是自然现象,然而现实却是传统流派“一派独大”。这种结果,不管怎么想处处都有违和感,难道是传统流派垄断仿真!?事实的背后可能隐藏巨大的阴谋,究竟是莫大的利益,还是绝对的权利 ... 为了维护这份力量,究竟要牺牲他人到什么程度?想到这里,笔者不禁后脊发凉。

“如今,老夫已经将真相泄露出去,不得不立即跑路,不然会糟灭口!”,大夫认真道。

“但是,同辈们该怎么办?”,笔者问道。

“它们两眼无光是心智失律的表现,基本是没有希望了 ... ”,大夫遗憾道。

“可是 ... 可是 .... ”,笔者焦急道。

“小哥,它们活着只会更痛苦 ... 小哥帮它们解脱吧! ”,大夫无情道。

话完,中年大夫向笔者递过匕首,笔者不禁双手颤抖起来 ... 小明是第一位向笔者搭话的同辈;小王很喜欢讲冷笑话;大牛最讲义气;阿福为人正直;还有 ... 还有,双眼忽然湿润起来,笔者强忍眼泪逐个逐个为最好的同辈解脱,它们每个人都是笑着离开 ....

入夜的天空黯淡无光,笔者的心情必也是一样 ... 中年大夫为同辈们善后以后就连夜跑路去了,而且它还特别告诫道,切糕袭击他人以后,心里会产生一段时间的空洞,期间千万不要胡思乱想,绝望之意会乘虚而入,让人作出傻事 ...

笔者一个人漫无目的来到附近的山崖边,山崖对面是一望无际的彼岸,哪里没有烦恼,没有恐惧,只有拥抱一切的安静。如今,双手还残留夺走生命的触感,不是是否夜风寒冷,笔者的肩膀一直在颤抖不停 ... 大夫没有说错,恐惧还有绝望早已深深嵌入,笔者已经失去面对仿真的勇气还有信心,笔者不经意自嘲,那个半死不活的自己还有什么作为呢?

除了自身的问题以外,熟知真相以后,传统流派已经成为巨大的噩梦,想必以后一定不得安眠 ... 与其庸人自扰,还不如抛开烦恼,眼下只要笔者再踏出几步就会得到解脱。啊 ... 笔者看见同辈正向这里招手道,来吧!来吧!

第一步,笔者毫无犹豫;

第二步,笔者期待着;

第三步,笔者露出微笑;

第四步,笔者的愿望终于实现了。

忽然,一只强而有力的右手捉住笔者,熟悉的声音映入耳膜。

“孩子,千万别做傻事,明天还有希望 ...”,它道。

5.8 主动思想

当笔者再度睁开眼睛的时候,笔者发现自己正躺在花田之中,笔者不仅怀疑自己是不是去了天国?这里充溢怀念的味道,还有似曾相识的景色,一瞬笔者立即回忆曾经有过的梦境!笔者立即起身,四处寻找它 ... 然后笔者在不远之处,看见熟悉的身影。它在等候笔者 ...

面对它,笔者有数之不尽的问题,不过它仅是点头示意理解,然后它用右手向下指。笔者自然地,顺着那个的地方望去。

“远处看去,这里是什么?”,它道。

“一处小花田 ...”,笔者答道。

“近处看去,这里是什么?”,它道。

“有小虫,有花儿 ... ”,笔者答案。

笔者之前也说过个体与整体的视角问题,它的用意正是如此。自古以来都是个体造就整体,而不是整体造就个体 ... 如果按照这个角度去思考,仿真是一个整体,个体包括仿真对象,激励文本,还有时序结果。解析仿真信息就是站在整体的视角去了解仿真情况,解读仿真情况,不过仿真信息是在是太庞大,远远超过常人可以承受的程度。为此,笔者才会烦恼,然后烦恼把笔者带来这里。

“远处看去,哪里是什么?”,它道。

“还是一处小花田 ... ”,笔者答道。

“近处看去,哪里是什么?”,它道。

“还是有小虫和花儿 ... ”,笔者答道。

“没错,就是如此。”,它道。

话后,笔者开始思考其中的含义 ... 整体花田就是因为无法一眼望去,才会看成基础小花田。反过来说,如果一座整体无法直接消化,我们必须设想分开好几个个体逐步消耗

。笔者当然明白整座仿真可以分化成为无数个体仿真,在此笔者必须用到低级建模的准则,因为低级建模的准则是以“功能”为单位分化模块。

话虽如此,但是笔者还欠缺关键的东西 ... 简言之,当整体被分化以后,整体就会失去集中性,还有连接性 ... 这种感觉好比一个大家庭,因为利益纷争,最后被迫分为数个小家庭,从此不相往来。然而那份关键的东西即是 ... 即时大家庭分化为数个小家庭,它们之间依然也能保持集中性与连接性。笔者相信,那个“关键的东西”是解决仿真的良药。

“孩子,这是什么小虫?它有什么特征?”,它道。

“这是蜜蜂,它有剧毒的尾刺。”,笔者答道。

“孩子,那是什么小虫?它有什么特征?”,它道。

“那是蝴蝶,它有华丽的翅膀”,笔者答道。

瞬间,一股念头让笔者不经意反问自己 ... 蜜蜂还有蝴蝶都是昆虫,然而笔者的认识却是:

昆虫 + 剧毒的尾刺 = 蜜蜂;

昆虫 + 华丽的翅膀 = 蝴蝶;

奇怪,实在太奇怪了 ... 这究竟是怎么一回事?为什么笔者会认为昆虫加剧毒的尾刺就是蜜蜂?昆虫加华丽的翅膀就是蝴蝶?如果思考换做计算机,不管是那个昆虫组合,计算机绝对不可能得出蜜蜂还有蝴蝶的结论。想着想着,领悟的“原来如此”不经意从嘴巴流了出来 ... 剧毒的尾刺是蜜蜂最大的特征,华丽的翅膀是蝴蝶的特征,原来笔者是以特征去认识,还有分辨昆虫。

话虽如此,究竟又是什么原因导致笔者用特征去认识昆虫?好奇,还有求知的冲动,不停驱使思考高速运动,不过还是找不到原因 ... 无奈之下,笔者用诚恳的眼神哀求它,酷到极点的它还是一贯我行我素的作风,无视笔者的恳求 ...

“孩子,这个小花田有什么?”,它道。

“一只蝴蝶,两朵茉莉花。”,笔者回答道。

“那个小花田又有什么?”,它道。

“一只蜜蜂,两朵向日葵。”,笔者答道。

开窍的啊一声,肩膀也跟着弹跳起来 .... 假设这里有小花田A,与小花田B,然而:

小花田A = 1蝴蝶 + 2茉莉花

小花田B = 1蜜蜂 + 2向日葵

认识小花田与认识昆虫其实是使用同样的道理,简单点说 ... 小花田A最大的特征就是1只蝴蝶,还有2朵茉莉花;小花田B的最大特征则是1只蜜蜂,2朵向日葵。假设小花田是一个整体,那么昆虫还有花朵都是个体,然而笔者却以“昆虫的特征”,还有“花朵的特征”等两个个体特征,分辨整体A与整体B。

换句话说,1只蝴蝶还有2朵茉莉花都是笔者认识小花田A的深刻个体印象;换之,1只蜜蜂还有2朵向日葵都是笔者认识小花田B的深刻个体印象;打从骨子里,笔者从来就没有认真去记忆小花田(整体),反之小花田的昆虫与花朵(个体),让笔者更加在意,更加注视。

这种情况,笔者好似在哪里看过报告 ... 打铁趁热,笔者立即闭上双眼全面搜索记忆的资料库。笔者曾经读过一份有关人脑记忆的科学报告,人脑有两种记忆能力,其一是清晰记忆,其二是模糊记忆。清晰记忆属于左脑的记忆类型,它好比计算机的内存,非黑即白的逻辑内容。模糊记忆属于右脑的记忆类型,保存似乎,还像等暧昧内容。笔者非常好奇,为什么人的脑袋会有两种不同能力的记忆力?

普遍上,我们会认为清晰记忆比模糊记忆更加有用,但是事实却是相反。假设我们用清晰记忆去认识小花田A与B的话,那么我们必须记忆小花田A还有小花田B的所有细节,然而常人是无法办到这起壮举,估计还没有记忆到一办我们的脑袋就会当机了。根据笔者的猜想,清晰记忆必须耗费大量脑力集中精神,然后刻意记录每个细节,为此记录工作还没有结束,大脑就会超载。

相反的,假设我们使用模糊记忆去认识小花田A与B的话,我们用不着记忆所有细节,换之我们记忆印象深刻的个体特征即可,例如小花田A有蝴蝶与茉莉花,小花田B有蜜蜂与向日葵。然而,花田的其它细节又该怎么办?其它印象不深刻的细节,模糊记忆会自己YY脑补。

清晰记忆也有显记忆,短期记忆,左脑记忆等别名;模糊记忆则有,长期记忆,右脑记忆等别名。报告也说过,左脑擅长顺序,处理逻辑的处理工作,右脑则是用来妄想。现代人很明显是倾向左脑使用,左脑的要求效率就是快狠准三字,这种现象自然可以从日常生活中观察得到,顺序语言就是最好的例子。

想着想着,笔者发觉神向花田吹气,不一会儿,一层蒙蒙的云雾就覆盖整片花田,这种感觉好比在照片上面打上马赛克似的,景色开始模糊起来 ... 接着,它用右手指向花田某处。

“孩子,那处小花田有什么?”,它道。

“雾蒙蒙的 ... 看不清楚 ... ”,笔者回答道。

过后,神又向同处的花田吹气,云雾部分即消失,模糊的景色也有好几个部分清晰起来。

“孩子,那处小花田有什么?”,它道。

“一只蝴蝶,两朵茉莉花 ... ”,笔者回答道。

“回答得很好。”,它道。

一会给花田打上马赛克,一会又消除花田的马赛克,笔者不禁迷惑起来 ... 花田被云雾遮盖的时候,所有景色就会模糊起来,昆虫还有花朵等个体特征也会跟着模糊;但是,接着,神也仅只是消除部分云雾,好让花田的个体特征清晰出来,然而笔者立即就能辨认出,那处是小花田A。模糊?清晰?笔者理解了,是清晰!是个体的强烈印象!让笔者用例子来解释吧 ...

假设有CONTROL 七个英文字母,如果我们用清晰记忆少记录一个T字母,余下 CON ROL只是没有意义的断片记忆。换之,如果CTRL给予模糊记忆有强烈的印象,那么只要我们好好保持 CTRL 的清晰,就算我们没有完整的CONTROL 七个英文之母,我们都有办法分辨 CTRL 就是 CONTROL。

原来如此!原来如此!领悟的四个字就像口水般不停从口角流出来。那些困死笔者的难题,它只是轻轻为笔者点一下,结果就把笔者点通了,神就是神,笔者真是佩服到五体投地。

现代人都有倾向左脑的用脑习惯,左脑的缺点就是小容量的清晰记忆。然而,这种用脑习惯也不知不觉之间流入仿真之中 ... 我们之所以觉得仿真信息快要塞爆脑袋,那是我们在无意识之间,使劲将仿真信息送往左脑。笔者说过,清晰记忆必须记录每个细节才能发挥功效,为了这个目的我们需要耗费大量的脑力用于集中。

结果而言,左脑不仅要一边使劲集中精神,它也要一边使劲记忆信息,最后它还要使劲处理信息,左脑就这样超载工作然后当掉。左脑为了自保,无间断发送“恐怖信息”阻止我们不要再折磨它了!换句话说,我们之所以恐惧仿真,原来是左脑为了自保才导致的问题。简言之,恐惧仿真其实是用脑不当(用脑不平衡)的病因 ... 为此,我们必须寻找一个用脑平衡的仿真手段。

平衡用脑简单而言就是讲一半以上的“记忆信息”送往右脑以致减轻左脑的负担。有些同学可能会觉得疑惑,右脑究竟要如何分担左脑的压力 ... 即是,运用我们的想象力。

想象力?没错,就是想象力 ... 想象力也是模糊记忆的能力之一,例如笔者认识车子会有以下几个特征:

汽车 = 四个轮子 + 一家车身 + 前后两面遮罩镜

每当笔者识别“汽车”,笔者只要回忆上面3个特征,其余细节都由想象力自行填充。

名牌汽车 = 四个轮子 + 一家车身 + 前后两面遮罩镜 + 宾士

再者,笔者认识名车也只是所追加一个车标特征而已,其它细节任由想象力填充。接下来是时候切入正题了,让笔者用模块来举例:

图5.8.1 按照建模技巧分化的模块。

如图5.8.1所示,假设我们有一个整体模块A,首先它必须经由低级建模的准则“一个模块,一个功能”,按照功能这个单位划分数个个体模块,如控制模块A,功能模块A等。低级建模是一种有规划的多模块建模,个体模块等均匀划分;换之常规的多模块建模是随意,并且不规则将整体模块划分为数个不等均匀的个体模块。形象点说,低级建模会将大切糕切分为数个个相同大小分量的小切糕,大面积的小切糕就少重量,小面积的小切糕就多重量;反之,常规多模块建模会将大切糕切成稀巴烂,好像被大炮轰炸过一般。

按照“功能”划分整体模块是,清晰模块,控制变数的前期工作。根据低级建模,模块会是 xx控制模块,yy功能模块等,这是其一提高模块表达能力的方法,在旁随便一望,我们就会知晓个体模块的大概功用。除此之外,笔者也在前面讲述过,分化模块也是将过度集中的变数,平均分化开来 ... 以致降低变数所引起的意外(错觉可能性)。

1.    always @ ( posedge CLOCK )2.        ....3.        else4.            case( i )5.                0:6.                begin ...; i <= i + 1’b1; en7.                1:8.                ......9.            endcase( i )

代码5.8.1

此外,个体模块的内容都会应用相同的用法模板来维护结构性,效果如图5.8.1.所示。某位同学曾经这样询问过笔者,笔者设计的模块,框架怎么都一模一样呢?与其说是框架,笔者更希望那位同学认为为“结构”还要好。类似5.8.1的用法模板是基于仿顺序操作,它除了提供最基本的顺序支持以外,它也替代那传统的状态机。

此外,如果模块内容有相同的结构,想象工作也会更加轻松,例如笔者记忆名车A,与名车B:

名牌汽车A = 四个轮子 + 一家车身 + 前后两面遮罩镜 + 宾士

名牌汽车B = 四个轮子 + 一家车身 + 前后两面遮罩镜 + 本田

汽车基本上都有相同的结构性,然而名车A与名车B的差别,笔者只是识别“宾士”还有“本田”两个车标特征而已。用法模板除了可以帮助想象以外,用法模板有最根本的功能,那就是指向功能。常见的用法模范都有i,j等指向工具,笔者也多次强调指向工具的重要性 ... 指向时钟,指向步骤,还是指向过程都是“清晰”模块内容的重要的工作。

那么,重点来了 ... 清晰?我们究竟是为了清晰什么才作清晰?答案非常明显,清晰个体的特征,强化个体的印象。强化个体的印象?没错 ... 对于想象力(模糊记忆)来说,个体的强烈印象是不可或缺的拼图,强烈的个体印象会带动周边的模糊细节,个体印象越强烈,整体的面貌越加清晰。

举例而言,人类在识别它人脸部的时候,由于面部有太多细节信息,那样的工作左脑很难胜任 ... 在此,右脑就大展拳脚了。右脑不会记录所有面部细节,换之右脑会记录个人脸部的局部特征,例如左眼下的泪痣,性感的樱桃小嘴等 ... 然后某天,类似面部特征的女人出现在笔者的面前,笔者就会产生好像,似乎的感觉。换句话说,局部印象越是强烈,想象力(模糊记忆)越能发挥功效。

所以说,笔者在建模的时候会使劲提高模块的表达能力,使劲清晰模块的内容,为了就是为个体模块留下强烈的印象。

图5.8.2 建模图的布局。

除此之外,建模图,布局也是重要的关键之一。如图5.8.2所示,建模图是站在整体视角所看到的景色,然而个体的布局位置,多多少少会影响模糊记忆。这种情况好比我们在注视某人的脸般,眼睛位于最上方,鼻子位于中间,嘴巴位于下方。如果将其反映在建模图的话 ... 现代人都习惯按照从左至右的顺序浏览事物,但是建模图无法像级人脸那样有固定的布局位置,为此建模图都会代用箭头建立模块之前的关系。

如图5.8.2所示,笔者一般习惯将控制模块放在建模图的左边,然后功能模块放在右边,接着设置箭头为两个个体模块生成关系。这种感觉眼睛的下方就是鼻子,鼻子的下方就是嘴巴。

图5.8.3 局部仿真信息。

一块的整体模块经过平局划分以后,仿真信息理应也会划分为数个,结果如5.8.3所示。换言之,一块一口吃不完的切糕,我们换做多口吃掉 ... 不过,在此有些同学可能会担忧,经过划分以后的仿真信息是不是会失去集中性与链接性呢?同学别当心,此刻我们的想象力就会发挥功效了 ...

体模表达能力高,模块内容很清晰,基本上个体模块就会成为强烈印象的局部特征, 然后再由建模图建立大概的布局,一个模糊的宏图就会在我们的想象力之中建立完成。紧接着,个体印象会发挥拼图的作作用,局部填充这个模糊宏图 ... 个体印象愈是强烈,宏图的局部特征愈是清晰,周围细节的连带填充效果愈是越好。就这样,任其想象力yy一阵子后,我们就能在脑海当中看见整体的仿真信息。

笔者一边妄想,嘴角一边流着口水 ... 好兴奋,笔者不曾那么兴奋过,原来想象力不仅可以用来YY,想象力也作仿真的超强利器。先将整体分化为无数个体,再强化个体印象,创建大概布局,然后刻意在模糊记忆之中,最后任由想象力填充其它细节。如此一来,左脑不仅更加轻松,左脑也能更多集中力去处理自己擅长的东西,真是可惜可贺!

“孩子,昆虫和花朵有什么关系”,它道

“啊 ... 花朵生产花蜜,昆虫採花蜜 ...”,笔者回答道。

“孩子,回答的很好”,它难得笑道。

神怎么一笑,让笔者更加觉得事有蹊跷了 ... 可恶,它就是那样一副德性,重来不把话说清楚,让笔者有种热窝蚂蚁的感觉。仔细一想,昆虫飞来飞去采花蜜是花田常见的场景 ... 花田常见的场景!?笔者之所以这么认为,原来是笔者站在整体的视角观察事物,既然如此,个体视角的花田会是甚么样的情况呢?

于是,笔者开始妄想 ... 如果笔者是一朵花的话,生产花蜜是笔者的任务,笔者只要使劲生产花蜜就行了,笔者才懒得管它什么昆虫;反之,如果笔者是一只蜜蜂,采花蜜是笔者的任务,笔者只要使劲采花蜜就行了,笔者才懒得管它是甚么花朵。原理如此,笔者开始了解它的笑意了 ...

当我们站在整体(花田)的视角长观察事物,花朵还有昆虫好似无私的好朋友般,花朵给予昆虫食物,昆虫帮忙花朵授粉,两者合作无间,彼此都是互惠关系。换之,如果我们站在个体(花朵与昆虫)的视角上观察事物,花朵和昆虫都是自私的陌生人,花朵为了生殖才大利用昆虫帮忙授粉 ... 然而,昆虫为了一份温饱才去采花蜜。实际上,两者是各怀鬼胎,互相利用,彼此都是独立关系

呵呵呵!想到这里,笔者不经意笑了出来 ... 原本看似矛盾的事情只要换个视角观事情又见合情合理,大自然实在太有趣了。那么,花朵与昆虫的故事又是传达什么呢?两个字独立。同样的事情如果反映在模块的身上,个体模块应该越独立(自私)越好。所谓独立并不表示孤独,首先个体必须确保它人无法侵犯自己,但是个体又不可以过度自封,因此个体必须打开外交管道,亦即沟通方式。

好奇的同学可能会觉得疑惑,个体模块之间为甚么要保持独立关系然后又故意打开外交管道呢?让笔者举例现实的实例,21世纪的今天,C国不希望A国插手自己的家事,但是C国也不能完全无视A国,换之A国也有同样的情况,因此C国与A国便打开外交的窗口,一起互勉,一起互喷。

图5.8.4 个体保持独立关系却建立沟通保持整体的连接性。

相比之下,模块才没有现实那么丑陋,个体模块之所以保持独立关系是为了局部仿真能够顺利执行;个体模块之间之所以建立沟通方式,是为了不失整体的连接性。如图5.8.4所示,模块之间基本都是保持独立的关系,因此可以执行局部的仿真。此外个体模块之间也建立外交 ... 啊!不,是沟通方式,以致保持整体的连接性。

如图5.8.4所示,个体模块都采用问答式沟通,换句话说 ... 它们之间都有同样的沟通模式。从仿真的角度看去,个体模块之间的沟通时序基本上都是一样的,这种情况好比C国与A国都用E语言执行外交。如此一来,个体模块没事的时候就自作自的,有事的时候再经由相同的沟通互勉互喷,真是可喜可贺。

最后,笔者可以这样总结道:

由于我们不小心用左脑去解析仿真信息,但是海量的仿真信息让左脑喘不过气来,左脑为了自保便使劲发出“危险信息" ... 因此,我们会在无意识下恐惧仿真。一块打切糕如果不能一口吃下,就要有规划品均分化为无数个小切糕。笔者则是按照低级建模的准则将整体模块划分为无数个个体模块。

个体模块仿真之前必须先做好一些准备,例如想尽办法提高个体模块的表达能力,清晰化个体模块的内容,这样做不仅是为了方便仿真,也为了强化个体的印象。此外,为了进一步提高个体模块的独立关系又不失整体的连接性,模块之间必须建立沟通窗口。当我们完成局部仿真以后(个体模块逐个仿真),右脑就会建立模糊的时序宏图。

此刻,强烈的个体印象开始发挥想效果了,模糊记忆会特别记录印象强烈的局部特征,

个体越是强烈,局部特征越是清晰,周围细节的填充效果会越好。如此一来,整体时序(仿真信息)会似拼图般在脑海里逐渐成型与清晰起来。

总体来说,大模快变成小模块以后,整体仿真信息随之也会变成无数个体仿真信息。左脑遇见整体仿真信息会汗救命 ... 换之,左脑遇见个体仿真信息会解析得游刃有余。个体仿真信息经过左脑解析以便交由右脑储存,不过前提是个体结果必须有强烈的印象。就这样,左脑解析一块个体仿真信息,右脑就记录一块局部信息,直至所有模块处理完毕。完后,想象力就会发挥作用,整体的仿真信息就会在想象中重现。

”孩子,还在绝望吗?“,它道。

”不了,现在恰好相反 ...“,笔者答道。

”很好的回答 ... 孩子千万别忘了,白骆驼何时何刻都在身边“,它道。

”嗯!“,笔者感触道。

”那么,再见“,它道。

”感谢指导!!!“,笔者大力鞠躬道。

===================================================================

当笔者再度睁开眼睛的时候,天空已经是接近黎明。笔者用力掐了一下自己的脸颊,好疼!好疼就表示还活着 ... 笔者察觉自己正躺在山崖一角,原来笔者在那里不知不觉睡着了。主动思想吗?呵呵!笔者笑笑两声以示那场不可思议的梦境,还有那个有趣的思想。啊 ... 不知为何,此刻的心情既然如此轻松。

稍微清理一下灰尘后,笔者便站起身子,然后望向山崖另一面的彼岸,此刻朝阳正逐渐从地平线上升起。笔者一边欣赏风景,一边自言自语道 ... 一个对象,如果整体视角看得太大,容易产生恐惧,此刻我们就必须改换个体视角重新看待,事实上是个体造就了整体,而不是整体造就了个体。

笔者也深刻反省至今为止的用脑习惯 ... 上天为人类创建的左右脑,然而人类却失衡用脑,结果产生许多问题。右脑虽然性格古怪,但是比起左脑更有不可思议的能力,笔者可以站此YY妄想都是托右脑的福。说着说着,朝阳已经上升到某种程度,温柔的阳关一视同仁地为万物注入生命力,世界开始美丽起来 ... 传统流派即使丑陋,阳关也会不惜吝啬分它一份羹。

大自然的无私拥抱让笔者对明天充满了希望。笔者使出决意的转身,然后踏出勇敢的一步,继续前进 ... 随之便消失在晨光的照耀下。

总结:

第五章总与写完了,第五章相比前面几章是比较特别的一章,其中笔者引用蒂沙还有白骆驼的故事来比喻仿真——仿真就是人生的缩影。蒂沙在人生的转折点上,有两个未来,其一选择单调即平凡的人生;其二选择冒险 ... 前者是单向人生,后者是多向人生,因为在旅行的路上蒂沙呼引来许多可能性的结局。

反观仿真,仿真也有单向与多向。一般上下也只有门级实验应用仿真模型①才有单向仿真的可能 ... 换之,多向仿真是默认仿真模式。多向仿真讲述变数衍生可能性,然而常见的变数有时钟变量,信号数量,还有信号方向 ... 它们都是理想变数,此外也存在物理变数,不过物理变数是自寻烦恼的东西,不建议考虑在仿真之中。

必然性也是多向仿真的其中一种概念,必然性会将仿真流逝引导至最有意义,也是我们最期待的结果。为了保证必然性,维护必然性与清晰必然性就成为了重要的工作。除此之外,必然性还有一个叫做契机的有趣东西,契机就是命运拼图的黏糊剂,然而契机被笔者用作沟通。不管是约束(控制)变数也好,或者保证必然性也好,这些都是前期建模应该考量的范畴。

“我是谁?我是甚么?”,看似简单的问题,其实是这个世界上最难的问题。笔者也曾经多次自问“仿真究竟是甚么?”,根据笔者的理解,仿真是时序结果,仿真对象还有激励内容的复合体,联系他们并且做出解析就是仿真的本意,笔者也称之为解析仿真信息。

多向仿真会有变数衍生许多可能性,许多可能性结合就成为海量般的仿真信息。为了方便理解,笔者将多向仿真形容为迷宫,然而压倒性的仿真信息形容为切糕怪物。切糕物如其名,是分量大得夸张的小食,如果仿真手段不但我们就会被“切糕”淹没。除了切糕以外,仿真也存在仿真癌这样的心理病。

仿真癌是由强迫仿真,还有恐惧仿真两种互斥的极端心态组成。前者让人不由自主去仿真,后者让人不由自主回避仿真,久而久之便会产生某种奇怪的心理病。强迫仿真还好解决,只要前期建模做好准备即可;反之,恐惧仿真就稍微麻烦一点 ... 根据理解,现代人都有倾向左脑的用脑习惯,然而要用左脑处理仿真的海量信息实际上是拿健康来开玩笑的事情。

为此,笔者尝试使用想象力来分担左脑的记忆工作。我们首先必须按“功能”将整体模块分化数个更小的个体模块,然后想尽办法强化个体模块的存在,好似留下强烈的个体印象。虽说模块分散以后会失去连接性,在此我们可以使用“沟通”来问题,并且进一步独立化个体模块,事后再逐个仿真个体模块即可。完后,整体信息自然而然会建立在脑海当中。

这个章节,许多内容看似不相关,不过只要读者仔细一想,上述内容其实都是一般参考书故意忽略的细节。当然,读者也可以认为笔者是杞人忧天,胡思乱想太多了,但是结果终究怎样,唯有见仁见智。笔者在此也是将自己的所想所言用文字表达出来而已。

转载于:https://www.cnblogs.com/alinx/p/3468396.html

你可能感兴趣的文章
mysql asyn 示例
查看>>
DataGrid 点击 获取 行 ID
查看>>
git 使用
查看>>
边框圆角方法
查看>>
asp.net WebApi自定义权限验证消息返回
查看>>
php中eval函数的危害与正确禁用方法
查看>>
20172315 2017-2018-2 《程序设计与数据结构》第十一周学习总结
查看>>
MySQL添加、修改、撤销用户数据库操作权限的一些记录
查看>>
关于谷歌浏览器Chrome正在处理请求的问题解决
查看>>
Git核心技术:在Ubuntu下部署Gitolite服务端
查看>>
平面波展开法总结
查看>>
建造者模式
查看>>
ArraySort--冒泡排序、选择排序、插入排序工具类demo
查看>>
composer 安装laravel
查看>>
8-EasyNetQ之Send & Receive
查看>>
Android反编译教程
查看>>
List<string> 去重复 并且出现次数最多的排前面
查看>>
js日志管理-log4javascript学习小结
查看>>
Android之布局androidmanifest.xml 资源清单 概述
查看>>
How to Find Research Problems
查看>>