首页 > 代码库 > line

line

 

  小君童靴说头儿给了他一个project,实现给出屏幕上任意两个点,求出这两个点之间直线上的所有的点。觉得这个很好玩,就自己也写了一点code

  1 /*  2 date : 2014/10/21  3 version : QuartusII 14.0 + DE1-SOC(cycloneV)  4 function: 输入两个点 Xmax = 1023  Ymax = 511 ,计算出中间点的坐标   5   6 说明 : (1)1023=0x3ff  (10bit)    511 = 0x1ff (9bit)  7        (2)直线方程: y=kx+m ;  8        (3)第116行 装载Ymin值的时候-1, 要求输入Ymin不可以小于1:如  9 果这个地方不剪掉1,会导致输出有(Ymax-Ymin)个脉冲的延时 10        (4)现象三的原因是 144 行的判定方法导致。判定当前点为合适点的 11 方式是第二次离直线最近,第一次prev2_dm 较大,第三次curr_dm也较大,116 12 行不减1就无法满足“远,近,远”的判定,从而一直扫到最后都找不到合适点。 13        (5)本程序的计算方式是最直接的运算,计算量大,浪费硬件资源,更 14 好的算法等待大家的指点 15        (6)由于计算输出延时了三个周期,如150行,所以最后三个点无法覆盖到。 16 */ 17  18  19 module line ( 20             clock , 21             reset , 22             xs_in ,        //输入的X 点的起始坐标 23             ys_in ,        // 输入的Y 点的起始坐标  24             xe_in ,        //输入X点的终止坐标 25             ye_in ,        //输入Y 点的终止坐标 26             in_en ,        //当前输入信号有效标志    1:有效    0:无效 27              28             x_ou,         //输出的X 点的坐标  29             y_ou,         // 输出的Y 点的坐标   30             fini_flag     //计算完成标志位 31             ); 32   input         clock ,reset  ;  33   input         in_en ;  34   input [9:0]     xs_in  ,xe_in ; 35   input [8:0]     ys_in  ,ye_in ;  36    37   output reg [9:0]    x_ou ;  38   output reg [8:0]    y_ou ;  39   output reg        fini_flag ;  40    41   wire signed [15:0] dx  ;     // X方向上的变化量 42   wire signed [15:0] dy  ;     //Y方向上的变化量   43   reg signed  [15:0] line_k ;  // 用来存储线条的斜率         44   reg signed  [15:0]  line_m ;  // 直线的常数项  45   reg signed  [15:0]  curr_m ;     //当前m值 46   reg         [15:0]  curr_dm ; //当前的m偏差量 47   reg         [15:0]  prev1_dm ; //上一次的m偏差量 48   reg         [15:0]  prev2_dm ; //上上一次m的偏差量 49   reg                    point_flag ; //找到当前最近点的标志位     50    51   wire signed  [9:0] Xmin ;  52   wire signed  [9:0] Xmax ;  53   wire signed  [8:0] Ymin ;  54   wire signed  [8:0] Ymax ;  55  56   assign dx = xe_in-xs_in;  //得出X方向上的差值 57   assign dy = ye_in-ys_in;  //得出Y方向上的差值 58    59    60   //求得所需的直线就在这么一个矩形框内,针对这个矩形框进行运算 61   assign Xmin = (xs_in<xe_in)? xs_in : xe_in ; 62   assign Xmax = (xs_in<xe_in)? xe_in : xs_in ; 63   assign Ymin = (ys_in<ye_in)? ys_in : ye_in ; 64   assign Ymax = (ys_in<ye_in)? ye_in : ys_in ; 65    66   //绝对值函数 67   function [15:0] abs (input signed[15:0] data1,  input signed [15:0] data2 ); 68         abs = (data1>data2) ? (data1-data2):(data2-data1); 69   endfunction  70          71 //*********斜率的计算,并且扩大了2^6次方倍,并得出M值的2^6倍的大小******************   72   always @ (posedge clock) 73         if(!in_en) 74             begin  75                     //line_k <= 16‘d0 ; 76                     //line_m <= 16‘d0 ; 77             end  78         else  79             begin  80                     line_k <= (dy<<6)/(dx) ;  81                     line_m <= (ye_in<<6) - line_k*xe_in ;  82             end  83              84 reg  [9:0] x_cnt ;        // X 坐标计数 85 reg  [8:0] y_cnt ;        // Y 坐标计数 86 //*********************矩形框X方向上计数*********************************     87 always @ (posedge clock ) 88     if(!reset)              89             begin  90                     x_cnt     <= 10d0 ;  91                     fini_flag <= 1d0  ;  92             end  93     else if (in_en) //装载Xmin值 94             begin  95                     x_cnt     <= Xmin + 10d1 ; 96                     fini_flag <= 1d0  ;  97             end  98     else if (x_cnt == Xmax) //矩形框扫描完毕    99             begin 100                     fini_flag <= 1d1  ;101             end 102     else if ((y_cnt==Ymax)||(point_flag))  //列扫描完毕,x+1 103             begin 104                     x_cnt     <= x_cnt + 10d1 ; 105                     fini_flag <= 1d0 ; 106             end 107 108 //********************矩形框Y方向上计数 **************            109 always @ (posedge clock )110     if(!reset)             111             begin 112                     y_cnt   <= 9d0 ; 113             end 114     else if (in_en)  //装载Ymin值115             begin 116                     y_cnt   <= Ymin - 9d1 ;117             end 118     else if ((y_cnt == Ymax)||(point_flag)) //列扫描完毕重新装载运算     119             begin 120                     y_cnt     <= Ymin ;121             end 122     else     begin 123                     y_cnt   <= y_cnt + 9d1 ; 124             end 125 126   always @ (posedge clock )127     if ((!reset) || (in_en))  128             begin 129                     x_ou       <= 10d0 ; 130                     y_ou       <= 9d0  ; 131                     point_flag <= 1d0  ;132                     prev1_dm   <= 16d0 ;133                     prev2_dm   <= 16d0 ;134                     curr_dm    <= 16d0 ;  135             end 136     else if (!fini_flag)137             begin 138                     //point_flag <= 1‘d0 ;139                     curr_m  <= (y_cnt<<6)-(x_cnt*line_k) ;140                     prev1_dm <= curr_dm ;141                     prev2_dm <= prev1_dm;142                     curr_dm <= abs(curr_m , line_m) ;143                     if((prev1_dm<curr_dm) &&(prev1_dm < prev2_dm)) //当前点在远离直线,以上一次的点有效144                             begin145                                     point_flag <= 1d1 ; //找到最近点,x,y跳转,结束x列的查找146                                     prev1_dm   <= 16h00 ;147                                     curr_dm    <= 16h00 ;148                                     prev2_dm   <= 16h00 ;149                                     x_ou <= x_cnt; 150                                     y_ou <= y_cnt - 9d3 ;151                             end152                     else     point_flag <= 1d0 ;153             end 154     else    begin155                     point_flag <= 1d0 ;156                     prev1_dm   <= 16h00 ;157                     curr_dm    <= 16h00 ;158                     prev2_dm   <= 16h00 ;159                     x_ou       <= 10d0 ; 160                     y_ou       <= 9d0  ; 161             end 162 163 endmodule 

 

附上测试tb

 1 `timescale 1ns/1ps 2  3  4 module line_tb ; 5  6 reg clock ,reset ;  7 reg in_en ; 8 reg [9:0] xs_in ,xe_in ; 9 reg [8:0] ys_in ,ye_in ; 10 11 wire [9:0] x_ou ; 12 wire [8:0] y_ou ; 13 wire       fini_flag ;14 15 16 line U1_line(17             .clock (clock),18             .reset (reset),19             .xs_in (xs_in),        20             .ys_in (ys_in),         21             .xe_in (xe_in),        22             .ye_in (ye_in),        23             .in_en (in_en),       24             25             .x_ou (x_ou),        26             .y_ou (y_ou),        27             .fini_flag (fini_flag)    28             );29 30 31 always  #10 clock = ~clock ; 32 33 initial 34     begin35             clock = 1d0 ; reset =1d0 ; in_en = 1d0 ; 36             xs_in = 10d0 ; xe_in = 10d0 ; 37             ys_in = 9d0  ; ye_in = 9d0 ; 38                 39             #40 reset = 1 ; in_en = 1 ; 40                 xs_in = 100 ; xe_in = 200 ; 41                 ys_in = 100 ; ye_in = 200 ; 42             #80 in_en = 0 ; 43             #80000 ;44             #50000 ;45             in_en = 1 ; 46             xs_in = 50 ; xe_in= 90 ; 47             ys_in = 120; ye_in= 20 ; 48             #80 in_en = 0 ; 49             #90000  $stop ; 50                 51     end 52 53 endmodule 

其实我听到这个project第一反应是软件中的两个for循环查找差值最小的点,再对应到HDL中想到的是generate,generate写到一半才发现输出怎么办,难道先让结果放到memory里面再慢慢取出来?觉得这么做是不是太繁琐了,于是叉掉重现写。

第二次想到的是用if  else 实现软件中的for,写了n久都觉得这个逻辑关系很纠结,if else 都嵌套了。再加一层嵌套就不利于维护了,证明这个架构是不行的。

最后一想不是可以用计数器实现for吗,哎,是不是最近一直在看C,怎么把HDL设计思想和C 想混合了。对于大师来说我的这个思维历程很搞笑,对于菜鸟的我来说是第一次亲身感受到了软硬件代码设计思想的差异—— 以前只是书上说自己没有感触到

 

line