add comment and sim build rule
[mandelfpga.git] / Main.v
1 /* 
2  * MandelFPGA
3  * by Joshua Wise and Chris Lu
4  * 
5  * An implementation of a pipelined algorithm to calculate the Mandelbrot set
6  * in real time on an FPGA.
7  */
8  
9 /* verilator lint_off WIDTH */
10
11 `define XRES 640
12 `define YRES 480
13 `define WHIRRRRR 47
14
15 `define TOPBIT 13
16
17 module SyncGen(
18         input pixclk,
19         output reg vs, hs,
20         output reg [11:0] xout = `WHIRRRRR, yout = 0,
21         output wire [11:0] xoutreal, youtreal,
22         output reg border);
23         
24         reg [11:0] x = 0, y = 0;        // Used for generating border and timing.
25         assign xoutreal = x;
26         assign youtreal = y;
27         
28         parameter XFPORCH = 16;
29         parameter XSYNC = 96;
30         parameter XBPORCH = 48;
31         
32         parameter YFPORCH = 10;
33         parameter YSYNC = 2;
34         parameter YBPORCH = 29;
35
36         always @(posedge pixclk)
37         begin
38                 if (x >= (`XRES + XFPORCH + XSYNC + XBPORCH))
39                 begin
40                         if (y >= (`YRES + YFPORCH + YSYNC + YBPORCH))
41                                 y <= 0;
42                         else
43                                 y <= y + 1;
44                         x <= 0;
45                 end else
46                         x <= x + 1;
47                         
48                 if (xout >= (`XRES + XFPORCH + XSYNC + XBPORCH))
49                 begin
50                         if (yout >= (`YRES + YFPORCH + YSYNC + YBPORCH))
51                                 yout <= 0;
52                         else
53                                 yout <= yout + 1;
54                         xout <= 0;
55                 end else
56                         xout <= xout + 1;
57                 hs <= (x >= (`XRES + XFPORCH)) && (x < (`XRES + XFPORCH + XSYNC));
58                 vs <= (y >= (`YRES + YFPORCH)) && (y < (`YRES + YFPORCH + YSYNC));
59                 border <= (x > `XRES) || (y > `YRES);
60         end
61 endmodule
62
63 // bits: 1.12
64
65 module NaiveMultiplier(
66         input clk,
67         input [`TOPBIT:0] x, y,
68         input xsign, ysign,
69         output reg [`TOPBIT:0] out,
70         output reg sign,
71         output reg ovf);
72
73         always @(posedge clk)
74         begin
75                 {ovf,out} <=
76                        ((((0)                            + // 15
77                           (0))                           + // 14
78                          ((y[13] ? (x           ) : 0)   +
79                           (y[12] ? (x[`TOPBIT:1]) : 0))) +
80                         (((y[11] ? (x[`TOPBIT:2]) : 0)   +
81                           (y[10] ? (x[`TOPBIT:3]) : 0))  +
82                          ((y[9]  ? (x[`TOPBIT:4]) : 0)   +
83                           (y[8]  ? (x[`TOPBIT:5]) : 0))))+
84                        ((((y[7]  ? (x[`TOPBIT:6]) : 0)   +
85                           (y[6]  ? (x[`TOPBIT:7]) : 0))  +
86                          ((y[5]  ? (x[`TOPBIT:8]) : 0)   +
87                           (y[4]  ? (x[`TOPBIT:9]) : 0))) +
88                         (((y[3]  ? (x[`TOPBIT:10]): 0)   +
89                           (y[2]  ? (x[`TOPBIT:11]): 0))  +
90                          ((y[1]  ? (x[`TOPBIT:12]): 0)   +
91                           (y[0]  ? (x[`TOPBIT])   : 0))));
92                 sign <= xsign ^ ysign;
93         end
94
95 endmodule
96
97 module Multiplier(
98         input clk,
99         input [`TOPBIT:0] x, y,
100         input xsign, ysign,
101         output wire [`TOPBIT:0] out,
102         output wire sign,
103         output wire overflow);
104
105         NaiveMultiplier nm(clk, x, y, xsign, ysign, out, sign, overflow);
106
107 endmodule
108
109 // Yuq.
110 module MandelUnit(
111         input clk,
112         input [`TOPBIT:0] x, y,
113         input xsign, ysign,
114         input [`TOPBIT+2:0] r, i,
115         input rsign, isign,
116         input [7:0] ibail, icuriter,
117         output reg [`TOPBIT:0] xout, yout,
118         output reg xsout, ysout,
119         output reg [`TOPBIT+2:0] rout, iout,
120         output reg rsout, isout,
121         output reg [7:0] obail, ocuriter);
122
123         wire [`TOPBIT+1:0] r2, i2;
124         wire [`TOPBIT+2:0] ri, diff;
125         wire [`TOPBIT+3:0] twocdiff;
126         wire r2sign, i2sign, risign, dsign;
127         wire [`TOPBIT+2:0] bigsum;
128         wire bigsum_ovf;
129
130         reg [`TOPBIT:0] xd, yd;
131         reg ineedbaild;
132         reg xsd, ysd;
133         reg [7:0] ibaild, curiterd;
134
135         assign ri[0] = 0;
136
137         Multiplier r2m(clk, r[`TOPBIT:0], r[`TOPBIT:0], rsign, rsign, r2[`TOPBIT:0], r2sign, r2[`TOPBIT+1]);
138         Multiplier i2m(clk, i[`TOPBIT:0], i[`TOPBIT:0], isign, isign, i2[`TOPBIT:0], i2sign, i2[`TOPBIT+1]);
139         Multiplier rim(clk, r[`TOPBIT:0], i[`TOPBIT:0], rsign, isign, ri[`TOPBIT+1:1], risign, ri[`TOPBIT+2]);
140
141         assign bigsum = r2[`TOPBIT+1:0] + i2[`TOPBIT+1:0];
142         assign bigsum_ovf = bigsum[`TOPBIT+2];
143         
144         assign twocdiff = r2 - i2;
145         assign diff = twocdiff[`TOPBIT+3] ? -twocdiff : twocdiff;
146         assign dsign = twocdiff[`TOPBIT+3];
147         
148         wire [`TOPBIT+3:0] twocrout = xd - diff;
149         wire [`TOPBIT+3:0] twociout = yd - ri;
150
151         always @ (posedge clk)
152         begin
153                 xd <= x;
154                 yd <= y;
155                 xsd <= xsign;
156                 ysd <= ysign;
157                 xout <= xd;
158                 yout <= yd;
159                 xsout <= xsd;
160                 ysout <= ysd;
161                 ibaild <= ibail;
162                 curiterd <= icuriter;
163                 ineedbaild <= r[`TOPBIT+1] | r[`TOPBIT+2] | i[`TOPBIT+1] | i[`TOPBIT+2];
164
165                 // r^2 - i^2 + x
166                 if (xsd ^ dsign) begin
167                         if (twocrout[`TOPBIT+3]) begin  // diff > xd
168                                 rout <= -twocrout;
169                                 rsout <= dsign;
170                         end else begin
171                                 rout <= twocrout;
172                                 rsout <= xsd;
173                         end
174                 end else begin
175                         rout <= diff + xd;
176                         rsout <= xsd;   // xsd == dsign
177                 end
178                 
179                 // 2 * r * i + y
180                 if (ysd ^ risign) begin
181                         if (twociout[`TOPBIT+3]) begin  // ri > yd
182                                 iout <= -twociout;
183                                 isout <= risign;
184                         end else begin
185                                 iout <= twociout;
186                                 isout <= ysd;
187                         end
188                 end else begin
189                         iout <= ri + yd;
190                         isout <= ysd;
191                 end
192                 
193                 // If we haven't bailed out, and we meet any of the bailout conditions,
194                 // bail out now.  Otherwise, leave the bailout at whatever it was before.
195                 if ((ibaild == 255) && (bigsum_ovf | ineedbaild))
196                         obail <= curiterd;
197                 else
198                         obail <= ibaild;
199                 ocuriter <= curiterd + 8'b1;
200         end
201
202 endmodule
203
204 module Mandelbrot(
205         input mclk,
206         input pixclk,
207         input [11:0] x, y,
208         input [`TOPBIT+1:0] xofs, yofs,
209         input [7:0] colorofs,
210         input [2:0] scale,
211         output reg [2:0] red, green, output reg [1:0] blue);
212
213 `define MAXOUTN 21
214         
215         wire [`TOPBIT:0] rx, ry;
216         wire [`TOPBIT+1:0] nx, ny;
217         wire rxsign, rysign;
218         
219         assign nx = {2'b0,x} + {2'b0,xofs};
220         assign ny = {2'b0,y} + {2'b0,yofs};
221         assign rx = (nx[`TOPBIT+1] ? -nx[`TOPBIT:0] : nx[`TOPBIT:0]) << scale;
222         assign rxsign = nx[`TOPBIT+1];
223         assign ry = (ny[`TOPBIT+1] ? -ny[`TOPBIT:0] : ny[`TOPBIT:0]) << scale;
224         assign rysign = ny[`TOPBIT+1];
225
226         wire [`TOPBIT+2:0] mr[`MAXOUTN:0], mi[`MAXOUTN:0];
227         wire mrs[`MAXOUTN:0], mis[`MAXOUTN:0];
228         wire [7:0] mb[`MAXOUTN:0];
229         wire [`TOPBIT:0] xprop[`MAXOUTN:0], yprop[`MAXOUTN:0];
230         wire xsprop[`MAXOUTN:0], ysprop[`MAXOUTN:0];
231         wire [7:0] curiter[`MAXOUTN:0];
232         
233         reg [`TOPBIT:0] initx, inity;
234         reg [`TOPBIT+2:0] initr, initi;
235         reg [7:0] initci, initb;
236         reg initxs, initys, initrs, initis;
237         
238         // Values after the number of iterations denoted by the subscript.
239         reg [`TOPBIT:0] stagex [2:1], stagey [2:1];
240         reg [`TOPBIT+2:0] stager [2:1], stagei [2:1];
241         reg [7:0] stageci [2:1], stageb [2:1];
242         reg stagexs [2:1], stageys [2:1], stagers [2:1], stageis [2:1];
243         
244         reg [2:0] state = 3'b001;       // One-hot encoded state.
245         
246         // States are advanced one from what they should be, so that they'll
247         // get there on the _next_ mclk.
248         always @(posedge mclk)
249         begin
250                 initx <= (state[2]) ? rx :
251                     (state[0]) ? stagex[1] :
252                     (state[1]) ? stagex[2] : 0;
253                 inity <= (state[2]) ? ry :
254                        (state[0]) ? stagey[1] :
255                        (state[1]) ? stagey[2] : 0;
256                 initr <= (state[2]) ? {2'b0,rx} :
257                        (state[0]) ? stager[1] :
258                        (state[1]) ? stager[2] : 0;
259                 initi <= (state[2]) ? {2'b0,ry} :
260                        (state[0]) ? stagei[1] :
261                        (state[1]) ? stagei[2] : 0;
262                 initxs <= (state[2]) ? rxsign :
263                         (state[0]) ? stagexs[1] :
264                         (state[1]) ? stagexs[2] : 0;
265                 initys <= (state[2]) ? rysign :
266                         (state[0]) ? stageys[1] :
267                         (state[1]) ? stageys[2] : 0;
268                 initrs <= (state[2]) ? rxsign :
269                         (state[0]) ? stagers[1] :
270                         (state[1]) ? stagers[2] : 0;
271                 initis <= (state[2]) ? rysign :
272                         (state[0]) ? stageis[1] :
273                         (state[1]) ? stageis[2] : 0;
274                 initb <= (state[2]) ? 8'b11111111 :
275                        (state[0]) ? stageb[1] :
276                        (state[1]) ? stageb[2] : 0;
277                 initci <= (state[2]) ? 8'b00000000 :
278                         (state[0]) ? stageci[1] : 
279                         (state[1]) ? stageci[2] : 0;
280         end
281         
282         reg [7:0] out;
283         
284         // We detect when the state should be poked by a high negedge followed
285         // by a high posedge -- if that happens, then we're guaranteed that the
286         // state following the current state will be 3'b100.
287         reg lastneg;
288         always @(negedge mclk)
289                 lastneg <= pixclk;
290         
291         always @(posedge mclk)
292         begin
293                 if (lastneg && pixclk)  // If a pixclk has happened, the state should be reset.
294                         state <= 3'b100;
295                 else                                            // Otherwise, just poke it forward.
296                         case(state)
297                         3'b001: state <= 3'b010;
298                         3'b010: state <= 3'b100;
299                         3'b100: state <= 3'b001;
300                 `ifdef isim
301                         default: begin $display("invalid state"); $finish; end
302                 `endif
303                         endcase
304         
305                 // Data output handling
306                 if (state[0]) begin
307                         {red, green, blue} <= {out[0],out[3],out[6],out[1],out[4],out[7],out[2],out[5]};
308                 end
309                 if (state[1]) begin
310                         out <= ~mb[`MAXOUTN] + colorofs;
311                 end
312                 
313                 if (state[0]) begin             // PnR0 in, PnR2 out
314                         stagex[2] <= xprop[`MAXOUTN];
315                         stagey[2] <= yprop[`MAXOUTN];
316                         stager[2] <= mr[`MAXOUTN];
317                         stagei[2] <= mi[`MAXOUTN];
318                         stagexs[2] <= xsprop[`MAXOUTN];
319                         stageys[2] <= ysprop[`MAXOUTN];
320                         stagers[2] <= mrs[`MAXOUTN];
321                         stageis[2] <= mis[`MAXOUTN];
322                         stageb[2] <= mb[`MAXOUTN];
323                         stageci[2] <= curiter[`MAXOUTN];
324                 end
325                 
326                 if (state[2]) begin     // PnR2 in, PnR1 out
327                         stagex[1] <= xprop[`MAXOUTN];
328                         stagey[1] <= yprop[`MAXOUTN];
329                         stager[1] <= mr[`MAXOUTN];
330                         stagei[1] <= mi[`MAXOUTN];
331                         stagexs[1] <= xsprop[`MAXOUTN];
332                         stageys[1] <= ysprop[`MAXOUTN];
333                         stagers[1] <= mrs[`MAXOUTN];
334                         stageis[1] <= mis[`MAXOUTN];
335                         stageb[1] <= mb[`MAXOUTN];
336                         stageci[1] <= curiter[`MAXOUTN];
337                 end
338         end
339
340         MandelUnit mu0(
341                 mclk,
342                 initx, inity, initxs, initys,
343                 initr, initi, initrs, initis,
344                 initb, initci,
345                 xprop[0], yprop[0], xsprop[0], ysprop[0],
346                 mr[0], mi[0], mrs[0], mis[0],
347                 mb[0], curiter[0]);
348                 
349 `define MAKE_UNIT(name, num) \
350         MandelUnit name(mclk, \
351                 xprop[(num)], yprop[(num)], xsprop[(num)], ysprop[(num)], mr[(num)], mi[(num)], mrs[(num)], mis[(num)], mb[(num)], curiter[(num)], \
352                 xprop[(num)+1], yprop[(num)+1], xsprop[(num)+1], ysprop[(num)+1], mr[(num)+1], mi[(num)+1], mrs[(num)+1], mis[(num)+1], mb[(num)+1], curiter[(num)+1])
353
354         `MAKE_UNIT(mu1, 0);
355         `MAKE_UNIT(mu2, 1);
356         `MAKE_UNIT(mu3, 2);
357         `MAKE_UNIT(mu4, 3);
358         `MAKE_UNIT(mu5, 4);
359         `MAKE_UNIT(mu6, 5);
360         `MAKE_UNIT(mu7, 6);
361         `MAKE_UNIT(mu8, 7);
362         `MAKE_UNIT(mu9, 8);
363         `MAKE_UNIT(mua, 9);
364         `MAKE_UNIT(mub, 10);
365         `MAKE_UNIT(muc, 11);
366         `MAKE_UNIT(mud, 12);
367         `MAKE_UNIT(mue, 13);
368         `MAKE_UNIT(muf, 14);
369         `MAKE_UNIT(mug, 15);
370         `MAKE_UNIT(muh, 16);
371         `MAKE_UNIT(mui, 17);
372         `MAKE_UNIT(muj, 18);
373         `MAKE_UNIT(muk, 19);
374         `MAKE_UNIT(mul, 20);
375 endmodule
376
377 module Logo(
378         input pixclk,
379         input [11:0] x, y,
380         output wire enb,
381         output wire [2:0] red, green, output wire [1:0] blue);
382         
383         reg [1:0] logo[8191:0];
384         initial $readmemb("logo.readmemb", logo);
385         
386         assign enb = (x < 96) && (y < 64);
387         wire [12:0] addr = {y[5:0], x[6:0]};
388         wire [1:0] data = logo[addr];
389         assign {red, green, blue} = 
390                  (data == 2'b00) ? 8'b00000000 :
391                 ((data == 2'b01) ? 8'b00011100 :
392                 ((data == 2'b10) ? 8'b11100000 :
393                                     8'b11111111));
394 endmodule
395
396 module MandelTop(
397 `ifdef verilator
398         input pixclk, mclk,
399 `else
400         input gclk, output wire dcmok,
401 `endif
402         output wire vs, hs,
403         output wire [2:0] red, green, output [1:0] blue,
404         input left, right, up, down, rst, cycle, logooff,
405         input [2:0] scale);
406         
407 `ifdef verilator
408 `else
409         wire pixclk, mclk, clk;
410         wire dcm1ok, dcm2ok;
411         assign dcmok = dcm1ok && dcm2ok;
412         
413         IBUFG iclkbuf(.O(clk), .I(gclk));
414         
415         pixDCM dcm(                                     // CLKIN is 50MHz xtal, CLKFX_OUT is 25MHz
416                 .CLKIN_IN(clk), 
417                 .CLKFX_OUT(pixclk),
418                 .LOCKED_OUT(dcm1ok)
419                 );
420         
421         mandelDCM dcm2(
422                 .CLKIN_IN(clk),
423                 .CLKFX_OUT(mclk),
424                 .LOCKED_OUT(dcm2ok)
425                 );
426 `endif
427
428         wire border;
429         wire [11:0] x, y;
430         reg [`TOPBIT+1:0] xofs = -`XRES/2, yofs = -`YRES/2;
431         reg [5:0] slowctr = 0;
432         reg [7:0] colorcycle = 0;
433         wire [11:0] realx, realy;
434         
435         wire logoenb;
436         wire [2:0] mandelr, mandelg, logor, logog;
437         wire [1:0] mandelb, logob;
438         
439         SyncGen sync(pixclk, vs, hs, x, y, realx, realy, border);
440         Mandelbrot mandel(mclk, pixclk, x, y, xofs, yofs, cycle ? colorcycle : 8'b0, scale, mandelr, mandelg, mandelb);
441         Logo logo(pixclk, realx, realy, logoenb, logor, logog, logob);
442         
443         assign {red,green,blue} =
444                 border ? 8'b00000000 :
445                 (!logooff && logoenb) ? {logor, logog, logob} : {mandelr, mandelg, mandelb};
446         
447         always @(posedge vs)
448         begin
449                 if (rst)
450                 begin
451                         xofs <= -`XRES/2;
452                         yofs <= -`YRES/2;
453                         colorcycle <= 0;
454                 end else begin
455                         if (up) yofs <= yofs + 1;
456                         else if (down) yofs <= yofs - 1;
457                         
458                         if (left) xofs <= xofs + 1;
459                         else if (right) xofs <= xofs - 1;
460                         
461                         if (slowctr == 0)
462                                 colorcycle <= colorcycle + 1;
463                 end
464                 
465                 if (slowctr == 12)
466                         slowctr <= 0;
467                 else
468                         slowctr <= slowctr + 1;
469         end
470 endmodule
This page took 0.040469 seconds and 4 git commands to generate.