/* * MandelFPGA * by Joshua Wise and Chris Lu * * An implementation of a pipelined algorithm to calculate the Mandelbrot set * in real time on an FPGA. */ `define XRES 640 `define YRES 480 `define WHIRRRRR 21 module SyncGen( input pixclk, output reg vs, hs, output reg [11:0] xout = `WHIRRRRR, yout = 0, output wire [11:0] xoutreal, youtreal, output reg border); reg [11:0] x = 0, y = 0; // Used for generating border and timing. assign xoutreal = x; assign youtreal = y; parameter XFPORCH = 16; parameter XSYNC = 96; parameter XBPORCH = 48; parameter YFPORCH = 10; parameter YSYNC = 2; parameter YBPORCH = 29; always @(posedge pixclk) begin if (x >= (`XRES + XFPORCH + XSYNC + XBPORCH)) begin if (y >= (`YRES + YFPORCH + YSYNC + YBPORCH)) y <= 0; else y <= y + 1; x <= 0; end else x <= x + 1; if (xout >= (`XRES + XFPORCH + XSYNC + XBPORCH)) begin if (yout >= (`YRES + YFPORCH + YSYNC + YBPORCH)) yout <= 0; else yout <= yout + 1; xout <= 0; end else xout <= xout + 1; hs <= (x >= (`XRES + XFPORCH)) && (x < (`XRES + XFPORCH + XSYNC)); vs <= (y >= (`YRES + YFPORCH)) && (y < (`YRES + YFPORCH + YSYNC)); border <= (x > `XRES) || (y > `YRES); end endmodule // bits: 1.12 module NaiveMultiplier( input clk, input [12:0] x, y, input xsign, ysign, output reg [12:0] out, output reg sign, output reg [1:0] ovf); always @(posedge clk) begin {ovf,out} <= (((y[12] ? (x ) : 0) + (y[11] ? (x >> 1) : 0) + (y[10] ? (x >> 2) : 0) + (y[9] ? (x >> 3) : 0)) + ((y[8] ? (x >> 4) : 0) + (y[7] ? (x >> 5) : 0) + (y[6] ? (x >> 6) : 0)))+ (((y[5] ? (x >> 7) : 0) + (y[4] ? (x >> 8) : 0) + (y[3] ? (x >> 9) : 0)) + ((y[2] ? (x >> 10): 0) + (y[1] ? (x >> 11): 0) + (y[0] ? (x >> 12): 0))); sign <= xsign ^ ysign; end endmodule module Multiplier( input clk, input [12:0] x, y, input xsign, ysign, output wire [12:0] out, output wire sign, output wire [1:0] overflow); NaiveMultiplier nm(clk, x, y, xsign, ysign, out, sign, overflow); endmodule module MandelUnit( input clk, input [12:0] x, y, input xsign, ysign, input [14:0] r, i, input rsign, isign, input [7:0] ibail, icuriter, output reg [12:0] xout, yout, output reg xsout, ysout, output reg [14:0] rout, iout, output reg rsout, isout, output reg [7:0] obail, ocuriter); wire [14:0] r2, i2, ri, diff; wire r2sign, i2sign, risign, dsign; wire [16:0] bigsum; wire bigsum_ovf, rin_ovf, iin_ovf, throwaway; reg [12:0] xd, yd; reg rd, id; reg xsd, ysd; reg [7:0] ibaild, curiterd; assign ri[0] = 0; Multiplier r2m(clk, r[12:0], r[12:0], rsign, rsign, r2[12:0], r2sign, r2[14:13]); Multiplier i2m(clk, i[12:0], i[12:0], isign, isign, i2[12:0], i2sign, i2[14:13]); Multiplier rim(clk, r[12:0], i[12:0], rsign, isign, ri[13:1], risign, {throwaway,ri[14]}); assign bigsum = r2 + i2; assign bigsum_ovf = bigsum[16] | bigsum[15] | bigsum[14]; assign rin_ovf = rd; assign iin_ovf = id; assign diff = (r2 > i2) ? r2 - i2 : i2 - r2; assign dsign = (r2 > i2) ? 0 : 1; always @ (posedge clk) begin xd <= x; yd <= y; xsd <= xsign; ysd <= ysign; xout <= xd; yout <= yd; xsout <= xsd; ysout <= ysd; ibaild <= ibail; curiterd <= icuriter; rd <= r[13] | r[14]; id <= i[13] | i[14]; if (xsd ^ dsign) begin if (diff > xd) begin rout <= diff - xd; rsout <= dsign; end else begin rout <= xd - diff; rsout <= xsd; end end else begin rout <= diff + xd; rsout <= xsd; end if (ysd ^ risign) begin if (ri > yd) begin iout <= ri - yd; isout <= risign; end else begin iout <= yd - ri; isout <= ysd; end end else begin iout <= ri + yd; isout <= ysd; end // If we haven't bailed out, and we meet any of the bailout conditions, // bail out now. Otherwise, leave the bailout at whatever it was before. if ((ibaild == 255) && (bigsum_ovf | rin_ovf | iin_ovf)) obail <= curiterd; else obail <= ibaild; ocuriter <= curiterd + 8'b1; end endmodule module Mandelbrot( input mclk, input pixclk, input [11:0] x, y, input [13:0] xofs, yofs, input [7:0] colorofs, input [2:0] scale, output reg [2:0] red, green, output reg [1:0] blue); wire [12:0] rx, ry; wire [13:0] nx, ny; wire rxsign, rysign; assign nx = x + xofs; assign ny = y + yofs; assign rx = (nx[13] ? -nx[12:0] : nx[12:0]) << scale; assign rxsign = nx[13]; assign ry = (ny[13] ? -ny[12:0] : ny[12:0]) << scale; assign rysign = ny[13]; wire [14:0] mr[9:0], mi[9:0]; wire mrs[9:0], mis[9:0]; wire [7:0] mb[9:0]; wire [12:0] xprop[9:0], yprop[9:0]; wire xsprop[9:0], ysprop[9:0]; wire [7:0] curiter[9:0]; wire [14:0] initx, inity, initr, initi; wire [7:0] initci, initb; wire initxs, initys, initrs, initis; reg [14:0] loopx, loopy, loopr, loopi; reg [7:0] loopci, loopb; reg loopxs, loopys, looprs, loopis; reg state = 0; // On pixclk = 1, // A new value to be loaded comes in, and a value in need of loopback comes out. // On pixclk = 0, // A new value in need of loopback comes in, and a completed value comes out. assign initx = state ? rx : loopx; assign inity = state ? ry : loopy; assign initr = state ? rx : loopr; assign initi = state ? ry : loopi; assign initxs = state ? rxsign : loopxs; assign initys = state ? rysign : loopys; assign initrs = state ? rxsign : looprs; assign initis = state ? rysign : loopis; assign initb = state ? 8'b11111111 : loopb; assign initci = state ? 8'b00000000 : loopci; reg [7:0] out; reg pixclksync; always @(negedge mclk) pixclksync <= ~pixclk; always @(posedge mclk) begin if (!state) begin out <= ~mb[9] + colorofs; end else begin {red, green, blue} <= {out[0],out[3],out[6],out[1],out[4],out[7],out[2],out[5]}; loopx <= xprop[9]; loopy <= yprop[9]; loopr <= mr[9]; loopi <= mi[9]; loopxs <= xsprop[9]; loopys <= ysprop[9]; looprs <= mrs[9]; loopis <= mis[9]; loopb <= mb[9]; loopci <= curiter[9]; end state <= ~pixclksync; end MandelUnit mu0( mclk, initx, inity, initxs, initys, initr, initi, initrs, initis, initb, initci, xprop[0], yprop[0], xsprop[0], ysprop[0], mr[0], mi[0], mrs[0], mis[0], mb[0], curiter[0]); MandelUnit mu1(mclk, xprop[0], yprop[0], xsprop[0], ysprop[0], mr[0], mi[0], mrs[0], mis[0], mb[0], curiter[0], xprop[1], yprop[1], xsprop[1], ysprop[1], mr[1], mi[1], mrs[1], mis[1], mb[1], curiter[1]); MandelUnit mu2(mclk, xprop[1], yprop[1], xsprop[1], ysprop[1], mr[1], mi[1], mrs[1], mis[1], mb[1], curiter[1], xprop[2], yprop[2], xsprop[2], ysprop[2], mr[2], mi[2], mrs[2], mis[2], mb[2], curiter[2]); MandelUnit mu3(mclk, xprop[2], yprop[2], xsprop[2], ysprop[2], mr[2], mi[2], mrs[2], mis[2], mb[2], curiter[2], xprop[3], yprop[3], xsprop[3], ysprop[3], mr[3], mi[3], mrs[3], mis[3], mb[3], curiter[3]); MandelUnit mu4(mclk, xprop[3], yprop[3], xsprop[3], ysprop[3], mr[3], mi[3], mrs[3], mis[3], mb[3], curiter[3], xprop[4], yprop[4], xsprop[4], ysprop[4], mr[4], mi[4], mrs[4], mis[4], mb[4], curiter[4]); MandelUnit mu5(mclk, xprop[4], yprop[4], xsprop[4], ysprop[4], mr[4], mi[4], mrs[4], mis[4], mb[4], curiter[4], xprop[5], yprop[5], xsprop[5], ysprop[5], mr[5], mi[5], mrs[5], mis[5], mb[5], curiter[5]); MandelUnit mu6(mclk, xprop[5], yprop[5], xsprop[5], ysprop[5], mr[5], mi[5], mrs[5], mis[5], mb[5], curiter[5], xprop[6], yprop[6], xsprop[6], ysprop[6], mr[6], mi[6], mrs[6], mis[6], mb[6], curiter[6]); MandelUnit mu7(mclk, xprop[6], yprop[6], xsprop[6], ysprop[6], mr[6], mi[6], mrs[6], mis[6], mb[6], curiter[6], xprop[7], yprop[7], xsprop[7], ysprop[7], mr[7], mi[7], mrs[7], mis[7], mb[7], curiter[7]); MandelUnit mu8(mclk, xprop[7], yprop[7], xsprop[7], ysprop[7], mr[7], mi[7], mrs[7], mis[7], mb[7], curiter[7], xprop[8], yprop[8], xsprop[8], ysprop[8], mr[8], mi[8], mrs[8], mis[8], mb[8], curiter[8]); MandelUnit mu9(mclk, xprop[8], yprop[8], xsprop[8], ysprop[8], mr[8], mi[8], mrs[8], mis[8], mb[8], curiter[8], xprop[9], yprop[9], xsprop[9], ysprop[9], mr[9], mi[9], mrs[9], mis[9], mb[9], curiter[9]); endmodule module Logo( input pixclk, input [11:0] x, y, output wire enb, output wire [2:0] red, green, output wire [1:0] blue); reg [1:0] logo[8191:0]; initial $readmemb("logo.readmemb", logo); assign enb = (x < 96) && (y < 64); wire [12:0] addr = {y[5:0], x[6:0]}; wire [1:0] data = logo[addr]; assign {red, green, blue} = (data == 2'b00) ? 8'b00000000 : ((data == 2'b01) ? 8'b00011100 : ((data == 2'b10) ? 8'b11100000 : 8'b11111111)); endmodule module MandelTop( input gclk, output wire dcmok, output wire vs, hs, output wire [2:0] red, green, output [1:0] blue, input left, right, up, down, rst, cycle, logooff, input [2:0] scale); wire border; wire pixclk; wire [7:0] zero = 8'b0; wire clk; wire [11:0] x, y; reg [13:0] xofs = -`XRES/2, yofs = -`YRES/2; reg [5:0] slowctr = 0; reg [7:0] colorcycle = 0; wire [11:0] realx, realy; wire logoenb; wire [2:0] mandelr, mandelg, logor, logog; wire [1:0] mandelb, logob; pixDCM dcm( // CLKIN is 50MHz xtal, CLKFX_OUT is 25MHz .CLKIN_IN(gclk), .CLKFX_OUT(pixclk), .CLKIN_IBUFG_OUT(clk), .LOCKED_OUT(dcmok) ); SyncGen sync(pixclk, vs, hs, x, y, realx, realy, border); Mandelbrot mandel(clk, pixclk, x, y, xofs, yofs, cycle ? colorcycle : 0, scale, mandelr, mandelg, mandelb); Logo logo(pixclk, realx, realy, logoenb, logor, logog, logob); assign {red,green,blue} = border ? 8'b00000000 : (!logooff && logoenb) ? {logor, logog, logob} : {mandelr, mandelg, mandelb}; always @(posedge vs) begin if (rst) begin xofs <= -`XRES/2; yofs <= -`YRES/2; colorcycle <= 0; end else begin if (up) yofs <= yofs + 1; else if (down) yofs <= yofs - 1; if (left) xofs <= xofs + 1; else if (right) xofs <= xofs - 1; if (slowctr == 0) colorcycle <= colorcycle + 1; end if (slowctr == 12) slowctr <= 0; else slowctr <= slowctr + 1; end endmodule