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