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