Skip to content

Instantly share code, notes, and snippets.

@ejrh
Created August 25, 2013 11:04
Show Gist options
  • Save ejrh/6333264 to your computer and use it in GitHub Desktop.
Save ejrh/6333264 to your computer and use it in GitHub Desktop.
module fpgafrac(
input wire mclk,
input wire [7:0] sw,
input wire [3:0] btn,
/*output wire [7:0] led,
output wire [3:0] an,
output wire dp,
output wire [6:0] seg,*/
output reg vs,
output reg hs,
output reg [2:0] red,
output reg [2:0] green,
output reg [1:0] blue
);
/*
Active Video Front Porch Sync Pulse Back Porch Active Video Front Porch Sync Pulse Back Porch
800x600, 72Hz 50.000 800 56 120 64 600 37 6 23
*/
parameter CLK = 50000000;
parameter PAL = 640;
parameter HFP = 16;
parameter HPW = 96;
parameter HBP = 48;
parameter LAF = 480;
parameter VFP = 11;
parameter VPW = 2;
parameter VBP = 31;
/*parameter PAL = 800;
parameter HFP = 56;
parameter HPW = 120;
parameter HBP = 64;
parameter LAF = 600;
parameter VFP = 37;
parameter VPW = 6;
parameter VBP = 23;*/
parameter PLD = PAL+HFP+HPW+HBP;
parameter LFD = LAF+VFP+VPW+VBP;
reg vga_clk;
reg [15:0] vga_x;
reg [15:0] vga_y;
/*wire red_colour;
defparam red_ball.VEL_X = 5;
defparam red_ball.VEL_Y = 3;
ball red_ball(mclk, PAL, LAF, 32, vga_x, vga_y, red_colour);
wire green_colour;
defparam green_ball.VEL_X = 4;
defparam green_ball.VEL_Y = 4;
ball green_ball(mclk, PAL, LAF, 32, vga_x, vga_y, green_colour);
wire blue_colour;
defparam blue_ball.VEL_X = 3;
defparam blue_ball.VEL_Y = 6;
ball blue_ball(mclk, PAL, LAF, 32, vga_x, vga_y, blue_colour);*/
wire [7:0] mandelbrot_colour;
mandelbrot mandelbrot(sw[0], btn, mclk, PAL, LAF, vga_x, vga_y, mandelbrot_colour);
wire on_screen;
assign on_screen = (vga_x < PAL) && (vga_y < LAF);
//wire [1:0] tile_colour;
//assign tile_colour = vga_x[7:6] ^ vga_y[7:6];
//assign tile_colour = mandelbrot_colour[7:6] ^ mandelbrot_colour[5:4] ^ mandelbrot_colour[3:2] ^ mandelbrot_colour[1:0];
wire [2:0] red_component, green_component;
wire [1:0] blue_component;
errdiff errdiff_r(mclk, vga_clk, mandelbrot_colour, red_component);
errdiff errdiff_g(mclk, vga_clk, mandelbrot_colour, green_component);
defparam errdiff_b.OUT_WIDTH = 2;
defparam errdiff_b.ERR_WIDTH = 6;
errdiff errdiff_b(mclk, vga_clk, mandelbrot_colour, blue_component);
always @(posedge mclk) begin
vga_clk <= !vga_clk;
if (vga_clk) begin
/* Update Pixel and Line positions. */
if (vga_x == PLD-1) begin
vga_x <= 0;
if (vga_y == LFD-1) begin
vga_y <= 0;
end else begin
vga_y <= vga_y + 1;
end
end else begin
vga_x <= vga_x + 1;
end
/* Horizontal sync. */
if (vga_x == PAL-1+HFP) begin
hs <= 0;
end else if (vga_x == PAL-1+HFP+HPW) begin
hs <= 1;
end
/* Vertical sync. */
if (vga_y == LAF-1+VFP) begin
vs <= 0;
end else if (vga_y == LAF-1+VFP+VPW) begin
vs <= 1;
end
if (on_screen) begin
/*red <= { red_colour, tile_colour };
green <= { green_colour, tile_colour };
blue <= { blue_colour, tile_colour[1] };*/
//{ red, green, blue } <= mandelbrot_colour;
{ red, green, blue } <= { red_component, green_component, blue_component };
end else begin
red <= 0;
green <= 0;
blue <= 0;
end
end
end
endmodule
module ball(
input wire mclk,
input wire [15:0] max_x,
input wire [15:0] max_y,
input wire [15:0] radius,
input wire [15:0] scan_x,
input wire [15:0] scan_y,
output wire in_circle
);
parameter POS_X = 0;
parameter POS_Y = 0;
parameter VEL_X = 1;
parameter VEL_Y = 2;
reg [31:0] pos_x = POS_X;
reg [31:0] pos_y = POS_Y;
reg signed [31:0] vel_x = VEL_X;
reg signed [31:0] vel_y = VEL_Y;
wire [15:0] circle_x;
assign circle_x = pos_x[31:21];
wire [15:0] circle_y;
assign circle_y = pos_y[31:21];
wire [15:0] xdiff, ydiff;
absdiff absdiff1(scan_x, circle_x, xdiff);
absdiff absdiff2(scan_y, circle_y, ydiff);
assign in_circle = xdiff*xdiff + ydiff*ydiff <= radius*radius;
always @(posedge mclk) begin
pos_x <= pos_x + vel_x;
pos_y <= pos_y + vel_y;
if (circle_x >= max_x - radius && vel_x > 0) begin
vel_x <= -vel_x;
end else if (circle_x < radius && vel_x < 0) begin
vel_x <= -vel_x;
end
if (circle_y >= max_y - radius && vel_y > 0) begin
vel_y <= -vel_y;
end else if (circle_y < radius && vel_y < 0) begin
vel_y <= -vel_y;
end
end
endmodule
module absdiff(
input wire [15:0] in1,
input wire [15:0] in2,
output wire [15:0] out
);
assign out = (in1 > in2) ? in1 - in2 : in2 - in1;
endmodule
module mandelbrot(
input wire control_mode,
input wire [3:0] button,
input wire mclk,
input wire [15:0] max_x,
input wire [15:0] max_y,
input wire [15:0] scan_x,
input wire [15:0] scan_y,
output wire [7:0] colour
);
parameter WIDTH = 80;
parameter HEIGHT = 60;
reg [12:0] store_addr;
reg [7:0] store_data;
reg store_enable = 0;
wire [12:0] read_addr;
wire [7:0] read_data;
videomem videomem(mclk, store_addr, store_data, store_enable, read_addr, read_data);
reg [7:0] iteration = 0;
reg [7:0] pos_x = WIDTH-1;
reg [7:0] pos_y = -1;
wire [12:0] pos = pos_y*WIDTH + pos_x;
reg signed [15:0] z_r = 0, z_i = 0;
reg signed [15:0] c_r = 0, c_i = 0;
wire [7:0] scan_pos_x, scan_pos_y;
assign scan_pos_x = scan_x >> 3;
assign scan_pos_y = scan_y >> 3;
wire [12:0] scan_pos;
assign scan_pos = scan_pos_y * WIDTH + scan_pos_x;
assign read_addr = (scan_pos < WIDTH*HEIGHT) ? scan_pos : 0;
wire in_fractal = (scan_pos_x < WIDTH) & (scan_pos_y < HEIGHT);
wire [7:0] pixel_val = read_data;
wire [5:0] pixel_colour;
colour_map map(pixel_val, pixel_colour);
//assign colour = in_fractal ? { pixel_colour, (scan_pos == pos) ? iteration[7:6] : 2'b00 } : 0;
assign colour = pixel_val;
wire [15:0] res_r, res_i, escaped;
mfunc mfunc(z_r, z_i, c_r, c_i, res_r, res_i, escaped);
wire new_pixel;
assign new_pixel = (iteration == 0) | escaped;
reg [1:0] slow_cnt;
reg [23:0] slow_cnt2;
wire signed [15:0] spos_x = pos_x;
wire signed [15:0] spos_y = pos_y;
parameter FIXPTS = 12;
reg [15:0] zoom = 192;
reg signed [15:0] centre_x = 0; //-(7 << (FIXPTS-2));
reg signed [15:0] centre_y = 0;
always @(posedge mclk) begin
slow_cnt <= slow_cnt + 1;
if (slow_cnt == 0) begin
if (iteration == 0) begin
store_data <= 0;
store_addr <= pos;
store_enable <= 1;
end else if (escaped) begin
store_data <= iteration;
store_addr <= pos;
store_enable <= 1;
end
if (new_pixel) begin
if (pos_x == WIDTH-1) begin
pos_x <= 0;
if (pos_y == HEIGHT-1) begin
pos_y <= 0;
end else begin
pos_y <= pos_y + 1;
end
end else begin
pos_x <= pos_x + 1;
end
z_r <= 0;
z_i <= 0;
iteration <= 1;
c_r <= ((spos_x - (WIDTH/2)) * zoom) + centre_x;
c_i <= ((spos_y - (HEIGHT/2)) * zoom) + centre_y;
end else begin
z_r <= res_r;
z_i <= res_i;
iteration <= iteration + 1;
end
end
slow_cnt2 <= slow_cnt2 + 1;
if (slow_cnt2 == 0) begin
zoom <= zoom - 1;
end
/*if (control_mode) begin
if (button[0]) begin
zoom <= zoom + 1;
end else if (button[1]) begin
zoom <= zoom - 1;
end
end else begin
end*/
if (store_enable) begin
store_enable <= 0;
end
end
endmodule
module mfunc(
input wire signed [15:0] in_r,
input wire signed [15:0] in_i,
input wire signed [15:0] c_r,
input wire signed [15:0] c_i,
output wire signed [15:0] out_r,
output wire signed [15:0] out_i,
output wire escaped
);
parameter FIXPTS = 12;
parameter BOUNDARY = 4 << FIXPTS;
wire signed [15:0] rsqr, isqr, riprod;
fixmul fixmul1(in_r, in_r, rsqr);
fixmul fixmul2(in_i, in_i, isqr);
fixmul fixmul3(in_r, in_i, riprod);
assign out_r = rsqr - isqr + c_r;
assign out_i = 2 * riprod + c_i;
assign escaped = rsqr + isqr > BOUNDARY;
endmodule
module fixmul(
input wire signed [15:0] a,
input wire signed [15:0] b,
output wire signed [15:0] result
);
parameter FIXPTS = 12;
wire signed [31:0] product;
assign product = a*b;
assign result = product[31:FIXPTS];
endmodule
module colour_map(input wire [7:0] val, output wire [5:0] col);
assign col = val[7] ? { 3'b111, val[6:4] } : { val[6:4], 3'b000 };
endmodule
module videomem(
input wire mclk,
input wire [12:0] store_addr,
input wire [7:0] store_data,
input wire store_enable,
input wire [12:0] read_addr,
output wire [7:0] read_data
);
wire enable00 = store_addr[12:11] == 2'b00;
wire enable01 = store_addr[12:11] == 2'b01;
wire enable10 = store_addr[12:11] == 2'b10;
wire enable11 = store_addr[12:11] == 2'b11;
wire [7:0] read_data00;
wire [7:0] read_data01;
wire [7:0] read_data10;
wire [7:0] read_data11;
videomem_module mod00(mclk, store_addr[10:0], store_data, store_enable & enable00, read_addr[10:0], read_data00);
videomem_module mod01(mclk, store_addr[10:0], store_data, store_enable & enable01, read_addr[10:0], read_data01);
videomem_module mod10(mclk, store_addr[10:0], store_data, store_enable & enable10, read_addr[10:0], read_data10);
videomem_module mod11(mclk, store_addr[10:0], store_data, store_enable & enable11, read_addr[10:0], read_data11);
wire read_enable00 = read_addr[12:11] == 2'b00;
wire read_enable01 = read_addr[12:11] == 2'b01;
wire read_enable10 = read_addr[12:11] == 2'b10;
wire read_enable11 = read_addr[12:11] == 2'b11;
assign read_data = read_enable00 ? read_data00 :
read_enable01 ? read_data01 :
read_enable10 ? read_data10 : read_data11;
endmodule
module videomem_module(
input wire mclk,
input wire [10:0] store_addr,
input wire [7:0] store_data,
input wire store_enable,
input wire [10:0] read_addr,
output wire [7:0] read_data
);
// RAMB16_S9_S9 : In order to incorporate this function into the design,
// Verilog : the forllowing instance declaration needs to be placed
// instance : in the body of the design code. The instance name
// declaration : (RAMB16_S9_S9_inst) and/or the port declarations within the
// code : parenthesis may be changed to properly reference and
// : connect this function to the design. All inputs
// : and outputs must be connected.
// <-----Cut code below this line---->
// RAMB16_S9_S9: 2k x 8 + 1 Parity bit Dual-Port RAM
// Spartan-3E
// Xilinx HDL Language Template, version 14.4
RAMB16_S9_S9 #(
.WRITE_MODE_A("READ_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
.WRITE_MODE_B("READ_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
.SIM_COLLISION_CHECK("ALL") // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
) RAMB16_S9_S9_inst (
.DOB(read_data), // Port B 8-bit Data Output
.ADDRA(store_addr), // Port A 11-bit Address Input
.ADDRB(read_addr), // Port B 11-bit Address Input
.CLKA(mclk), // Port A Clock
.CLKB(mclk), // Port B Clock
.DIA(store_data), // Port A 8-bit Data Input
.DIB(8'b11111111), // Port B 8-bit Data Input (not used)
.DIPA(1), // Port A 1-bit parity Input (not used)
.DIPB(1), // Port-B 1-bit parity Input (not used)
.ENA(store_enable), // Port A RAM Enable Input
.ENB(1), // Port B RAM Enable Input
.WEA(store_enable), // Port A Write Enable Input
.WEB(0) // Port B Write Enable Input
);
/*reg [7:0] data [0:299];
always @(posedge mclk) begin
if (store_enable)
data[store_addr] <= store_data;
end
assign read_data = data[read_addr];*/
endmodule
module errdiff(clk, enable, val, out);
parameter OUT_WIDTH = 3;
parameter ERR_WIDTH = 5;
input wire clk;
input wire enable;
input wire [OUT_WIDTH+ERR_WIDTH-1:0] val;
output wire [OUT_WIDTH-1:0] out;
reg [OUT_WIDTH+ERR_WIDTH-1:0] error = 0;
wire [OUT_WIDTH+ERR_WIDTH:0] adjval = val + error;
wire [ERR_WIDTH-1:0] newerr;
assign { out, newerr } = adjval;
always @(posedge clk) begin
if (enable)
error <= newerr;
end
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment