|||
那么正确的方法是什么呢?我们采取一种可称之为“反推法”或是“逆向法”的方式,这个问题就迎刃而解了。要知道,代码的目的是实现功能。无论你用那种代码,有一点完全相同的就是“实现功能”这个最终结果。了解到这一点,我们就可以通过结果(功能)去反推过程(代码),代码的思路、流程、用途就抽丝剥茧清晰的显露出来。好的,下面我们举个实例来说明怎么通过反推法有步骤的去看懂别人的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | //------------------------------------------- //帧率采样计算 reg fps_state; reg [7:0] fps_data; always@(posedge iCLK or negedge iRST_N) begin if(!iRST_N) begin fps_data <= 0; fps_state <= 0; CMOS_FPS_DATA <= 0; end else if(Frame_valid) begin case(fps_state) 0: begin CMOS_FPS_DATA <= CMOS_FPS_DATA; if(delay_2s == 0) begin fps_state <= 0; if(CMOS_VSYNC_over == 1'b1) //VS上升沿,1帧写入完毕 fps_data <= fps_data + 1'b1; end else fps_state <= 1; end 1: begin fps_state <= 0; fps_data <= 0; CMOS_FPS_DATA <= fps_data >>1; end endcase end else begin fps_data <= 0; fps_state <= 0; CMOS_FPS_DATA <= 0; end end endmodule |
如果我们按照自上而下的顺序去看这个代码,通过代码的过程去看实现的功能会是很困难的事,甚至看不明白它要实现的是什么功能。Ok,我们现在从功能看起,这个代码要实现的是“帧率采样计算”这个功能,可以理解为图片每秒显示多少帧数。
1. 从代码中我们可以看出,CMOS_FPS_DATA 这个信号是我们所要求的信号(一秒内的帧数率);
2. CMOS_FPS_DATA <= fps_data >>1在一段时间内保持不变,才是我们所要的结果;
3. 从CMOS_FPS_DATA <= fps_data >>1中可以看出,CMOS_FPS_DATA是通过fps_data 这个信号来实现;
4. fps_data这个信号是怎么来的?反推到fps_data <= 0和fps_data <= fps_data + 1'b1这两个信号。fps_data复位为零,在else if(Frame_valid)条件下加1;因此fps_data为帧数率标志信号;
5. 从CMOS_FPS_DATA <= fps_data >>1中可以看出是通过<= fps_data >>1右移一位,也就是说除以2得到这个值的;
6. 为什么要fps_data除以2来得到这个值?于是反推到if(delay_2s == 0)这个条件。
现在作者的意图就非常清晰了。满足帧数率的情况下不断+1,到2秒时间时根据统计结果除以2,由此得到1秒时间的帧数。到此为止,我们已经可以非常容易的看懂这个代码了。
通过反推法我们也能比较容易的去看代码是否有错误。首先我们去知道代码需要实现的功能,通过反推法得知是通过什么方法实现的,进而仿真时定位其目标,去看该代码是否完成了功能。如果没有完成功能,那么代码就有误。
对于学习者来说,反推法的意义还不仅在此。在本例中,这个设计思路完全满足功能要求。展这时,我们应该扩思考,本例是通过2秒来实现功能,为什么要用2秒?是否可以直接通过1秒,或是3秒,或是其他方案来实现呢?各种方法的优缺点在哪里?通过反推法得知作者实现项目的方法并思考,这种方法正确还是错误?如果是错误或者这种方法不太好,那么我们如何避免?如果是优秀的代码,我们如何借鉴并能举一反三地运用到其他项目中去?本例只是选取项目中的一个小的节点,对于看整个项目的代码来说可以运用反推法吗?敬请关注下一节。
想要了解更多技术文章,欢迎关注http://www.mdy-edu.com/product/list/35