module Lab5 (
parameter SCREEN_TOP = 10'd1,
SCREEN_DOWN = 10'd238,
SCREEN_LEFT = 10'd3,
SCREEN_RIGHT = 10'd319,
SCREEN_XHALF = 158,
SCREEN_YHALF = 118;
// LCD ON
assign LCD_ON = 1'b0;
assign LCD_BLON = 1'b0;
// All inout port turn to tri-state
assign DRAM_DQ = 16'hzzzz;
assign FL_DQ = 8'hzz;
assign SRAM_DQ = 16'hzzzz;
assign OTG_DATA = 16'hzzzz;
assign SD_DAT = 1'bz;
assign ENET_DATA = 16'hzzzz;
assign GPIO_0 = 36'hzzzzzzzzz;
assign GPIO_1 = 36'hzzzzzzzzz;
// VGA wires
wire [9:0] mVGA_R, mVGA_G, mVGA_B; // wires to the VGA controller
wire [19:0] mVGA_ADDR; // output from the VGA conntroller
wire [9:0] coord_x, coord_y; // the requested coordinates from VGA controller
// VGA wiring ///////////////////////////////////////////
assign mVGA_R = { SRAM_DQ[15:12], 6'h0 };
assign mVGA_B = { SRAM_DQ[11:8], 6'h0 };
assign mVGA_G = { SRAM_DQ[7:4], 6'h0 };
wire VGA_CTRL_CLK;
wire AUD_CTRL_CLK;
wire DLY_RST;
//Allow 27 MHz
assign TD_RESET = 1'b1;
wire reset_all;
assign reset_all = ~KEY[3];
wire pause_all;
assign pause_all = ~KEY[2];
VGA_Audio_PLL v0(.areset(~DLY_RST),
.inclk0(CLOCK_27),
.c0(VGA_CTRL_CLK),
.c1(AUD_CTRL_CLK),
.c2(VGA_CLK));
Reset_Delay r0( .iCLK(CLOCK_50),
.oRESET(DLY_RST));
VGA_Controller c0(.iCursor_RGB_EN(4'b0111),
.oAddress(mVGA_ADDR),
.oCoord_X(coord_x),
.oCoord_Y(coord_y),
.iRed(mVGA_R),
.iGreen(mVGA_G),
.iBlue(mVGA_B),
.oVGA_R(VGA_R),
.oVGA_G(VGA_G),
.oVGA_B(VGA_B),
.oVGA_H_SYNC(VGA_HS),
.oVGA_V_SYNC(VGA_VS),
.oVGA_SYNC(VGA_SYNC),
.oVGA_BLANK(VGA_BLANK),
.iCLK(VGA_CTRL_CLK),
.iRST_N(DLY_RST));
// vga lock
reg lock;
// SRAM data goes to NIOS data in line
reg we;
reg [17:0] addr_reg;
reg [15:0] data_reg;
assign SRAM_ADDR[17:0] = addr_reg[17:0];
assign SRAM_DQ[15:0] = (we) ? data_reg[15:0] : 16'hzzzz;
// SRAM CONTROL /////////////////////////////////////////
assign SRAM_UB_N = 0; // hi byte select enabled
assign SRAM_LB_N = 0; // lo byte select enable
assign SRAM_OE_N = 0; // output enable overriden by WE
assign SRAM_WE_N = ~we; // write enable
assign SRAM_CE_N = 0; // chip enable
assign LEDR[15:12] = object_state[3:0];
assign LEDR[11:08] = comp_state[3:0];
assign LEDR[07:04] = raster_state[3:0];
assign LEDR[03:00] = 4'd0;
assign LEDG[3:0] = ~KEY[3:0];
// state counters
reg [3:0] object_state;
reg [3:0] comp_state;
reg [3:0] raster_state;
// edge list
reg signed [15:0] edge_Ax[0:255], edge_Ay[0:255], edge_Az[0:255],
edge_Bx[0:255], edge_By[0:255], edge_Bz[0:255];
reg [7:0] edge_count;
reg [7:0] edge_iterator;
// computed edges
reg signed [15:0] comp_Ax[0:255], comp_Ay[0:255], comp_Az[0:255],
comp_Bx[0:255], comp_By[0:255], comp_Bz[0:255];
reg [7:0] comp_count;
reg [7:0] comp_iterator;
// bresenhem wires
reg bresenhem_init;
reg [9:0] bre_Ax, bre_Ay, bre_Bx, bre_By;
wire bresenhem_busy, bresenhem_done;
wire bresenhem_we;
wire [8:0] bresenhem_addr_reg_x, bresenhem_addr_reg_y;
wire [1:0] bresenhem_data_reg;
bresenhem bresenhem_instance(.CLK(VGA_CTRL_CLK),
.reset(reset_all),
.init(bresenhem_init),
.lock((~VGA_VS | ~VGA_HS) & ~pause_all),
.busy(bresenhem_busy),
.done(bresenhem_done),
.Ax_in(bre_Ax),
.Ay_in(bre_Ay),
.Bx_in(bre_Bx),
.By_in(bre_By),
.we(bresenhem_we),
.addr_reg_x(bresenhem_addr_reg_x),
.addr_reg_y(bresenhem_addr_reg_y),
.data_reg(bresenhem_data_reg));
// circle wires
reg circle_init;
wire circle_busy, circle_done;
wire [15:0] circle_Ax, circle_Ay, circle_Az, circle_Bx, circle_By, circle_Bz;
reg [15:0] circle_stepsize;
circle_gen circle_generator(.CLK(VGA_CTRL_CLK),
.reset(reset_all),
.init(circle_init), .lock(1'b1),
.busy(circle_busy), .done(circle_done),
.Ax(circle_Ax), .Ay(circle_Ay), .Az(circle_Az),
.Bx(circle_Bx), .By(circle_By), .Bz(circle_Bz),
.stepsize(circle_stepsize));
// cube wires
reg cube_init;
wire cube_busy, cube_done;
wire [15:0] cube_Ax, cube_Ay, cube_Az, cube_Bx, cube_By, cube_Bz;
cube_gen cube_generator(.CLK(VGA_CTRL_CLK),
.reset(reset_all),
.init(cube_init), .lock(1'b1),
.busy(cube_busy), .done(cube_done),
.Ax(cube_Ax), .Ay(cube_Ay), .Az(cube_Az),
.Bx(cube_Bx), .By(cube_By), .Bz(cube_Bz));
// transformation wires
reg [55:0] graphic_word;
reg translater_init, scaler_init, rotater_init;
wire [4:0] knob_addr;
reg [15:0] knob_val; // obvious
wire [15:0] transarg_x, transarg_y, transarg_z; // non-knob-multiplied
wire [17:0] knobmult_x, knobmult_y, knobmult_z;
// processed op (knob-multiplied or not)
wire [15:0] transop_x, transop_y, transop_z;
wire [1:0] rotate_axis;
// status wires per module
wire translater_busy_A, translater_done_A;
wire translater_busy_B, translater_done_B;
wire scaler_busy_A, scaler_done_A;
wire scaler_busy_B, scaler_done_B;
wire rotater_busy_A, rotater_done_A;
wire rotater_busy_B, rotater_done_B;
// all status wires
wire translater_busy, translater_done;
wire scaler_busy, scaler_done;
wire rotater_busy, rotater_done;
// if either are busy, don't advance
assign translater_busy = translater_busy_A | translater_busy_B;
assign scaler_busy = scaler_busy_A | scaler_busy_B;
assign rotater_busy = rotater_busy_A | rotater_busy_B;
// if both aren't done, not done
assign translater_done = translater_done_A & translater_done_B;
assign scaler_done = scaler_done_A & scaler_done_B;
assign rotater_done = rotater_done_A & rotater_done_B;
// temporary registers
reg [15:0] transform_Ax, transform_Ay, transform_Az;
reg [15:0] transform_Bx, transform_By, transform_Bz;
wire [15:0] next_Ax, next_Ay, next_Az;
wire [15:0] next_Bx, next_By, next_Bz;
// transformation and rotation selection
wire [2:0] transform_sel;
assign rotate_axis[1:0] = transform_sel[1:0];
// transform ops
reg [55:0] graphic_ops [0:4];
reg [4:0] graphic_ops_count;
reg [4:0] graphic_ops_iterator;
// 56-bit control word
// opcode 3 bits wide
// 3x16 transformation arguments
// 5 bit knob handler
`define G_OPCODE 55:53
`define G_KNOB 52:48
`define G_XARG 47:32
`define G_YARG 31:16
`define G_ZARG 15:0
assign transform_sel[2:0] = graphic_word[`G_OPCODE];
assign knob_addr[4:0] = graphic_word[`G_KNOB];
assign transarg_x[15:0] = graphic_word[`G_XARG];
assign transarg_y[15:0] = graphic_word[`G_YARG];
assign transarg_z[15:0] = graphic_word[`G_ZARG];
signed_mult transop_xer(knobmult_x[17:0],
{ transarg_x[15:0], 2'b00 },
{ knob_val[15:0], 2'b00 });
signed_mult transop_yer(knobmult_y[17:0],
{ transarg_y[15:0], 2'b00 },
{ knob_val[15:0], 2'b00 });
signed_mult transop_zer(knobmult_z[17:0],
{ transarg_z[15:0], 2'b00 },
{ knob_val[15:0], 2'b00 });
assign transop_x[15:0] = (knob_addr == 0) ?
transarg_x[15:0] : knobmult_x[17:2];
assign transop_y[15:0] = (knob_addr == 0) ?
transarg_y[15:0] : knobmult_y[17:2];
assign transop_z[15:0] = (knob_addr == 0) ?
transarg_z[15:0] : knobmult_z[17:2];
rotate rotaterA(.CLK(VGA_CTRL_CLK), .reset(reset_all),
.lock(1'b1), .init(rotater_init),
.busy(rotater_busy_A), .done(rotater_done_A),
.Ax(transform_Ax), .Ay(transform_Ay), .Az(transform_Az),
.theta(transop_x), .axis(rotate_axis),
.Bx(next_Ax), .By(next_Ay), .Bz(next_Az));
translate translaterA(.CLK(VGA_CTRL_CLK), .reset(reset_all),
.lock(1'b1), .init(translater_init),
.busy(translater_busy_A), .done(translater_done_A),
.Ax(transform_Ax), .Ay(transform_Ay), .Az(transform_Az),
.Dx(transop_x), .Dy(transop_y), .Dz(transop_z),
.Bx(next_Ax), .By(next_Ay), .Bz(next_Az));
scale scalerA(.CLK(VGA_CTRL_CLK), .reset(reset_all),
.lock(1'b1), .init(scaler_init),
.busy(scaler_busy_A), .done(scaler_done_A),
.Ax(transform_Ax), .Ay(transform_Ay), .Az(transform_Az),
.Sx(transop_x), .Sy(transop_y), .Sz(transop_z),
.Bx(next_Ax), .By(next_Ay), .Bz(next_Az));
rotate rotaterB(.CLK(VGA_CTRL_CLK), .reset(reset_all),
.lock(1'b1), .init(rotater_init),
.busy(rotater_busy_B), .done(rotater_done_B),
.Ax(transform_Bx), .Ay(transform_By), .Az(transform_Bz),
.theta(transop_x), .axis(rotate_axis),
.Bx(next_Bx), .By(next_By), .Bz(next_Bz));
translate translaterB(.CLK(VGA_CTRL_CLK), .reset(reset_all),
.lock(1'b1), .init(translater_init),
.busy(translater_busy_B), .done(translater_done_B),
.Ax(transform_Bx), .Ay(transform_By), .Az(transform_Bz),
.Dx(transop_x), .Dy(transop_y), .Dz(transop_z),
.Bx(next_Bx), .By(next_By), .Bz(next_Bz));
scale scalerB(.CLK(VGA_CTRL_CLK), .reset(reset_all),
.lock(1'b1), .init(scaler_init),
.busy(scaler_busy_B), .done(scaler_done_B),
.Ax(transform_Bx), .Ay(transform_By), .Az(transform_Bz),
.Sx(transop_x), .Sy(transop_y), .Sz(transop_z),
.Bx(next_Bx), .By(next_By), .Bz(next_Bz));
parameter draw_circle = 4'd0,
wait_circle = 4'd1,
draw_lines = 4'd2,
wait_lines = 4'd3,
keyok_lines = 4'd8,
transform_prep = 4'd4,
transform_exec = 4'd5,
transform_wait = 4'd6,
transform_save = 4'd7;
parameter debug_transform = 1'b0;
// consumer of objects, producer of edge list
always @(posedge VGA_CTRL_CLK) begin
if (reset_all) begin
edge_count <= 8'd0;
object_state <= draw_circle;
end
else if (object_state == draw_circle) begin
//circle_stepsize <= 16'd100;
//circle_stepsize <= 16'd32;
//circle_stepsize <= 16'd8;
circle_stepsize <= SW[9:0];
if (SW[17:16] == 2'b00) begin
circle_init <= 1'b1;
cube_init <= 1'b0;
end
else if (SW[17:16] == 2'b10) begin
circle_init <= 1'b0;
cube_init <= 1'b1;
end
object_state <= wait_circle;
end
else if (object_state == wait_circle) begin
if (circle_busy | cube_busy) begin
edge_Ax[edge_count] <= (SW[17:16] == 2'b00) ? circle_Ax : cube_Ax;
edge_Ay[edge_count] <= (SW[17:16] == 2'b00) ? circle_Ay : cube_Ay;
edge_Az[edge_count] <= (SW[17:16] == 2'b00) ? circle_Az : cube_Az;
edge_Bx[edge_count] <= (SW[17:16] == 2'b00) ? circle_Bx : cube_Bx;
edge_By[edge_count] <= (SW[17:16] == 2'b00) ? circle_By : cube_By;
edge_Bz[edge_count] <= (SW[17:16] == 2'b00) ? circle_Bz : cube_Bz;
edge_count <= edge_count + 8'd1;
end // if (circle_busy)
else if (circle_done | cube_done) begin
circle_init <= 1'b0;
end
end // if (object_state == wait_circle)
end // always @ (posedge VGA_CTRL_CLK)
// consumer of edge list, producer of computed edges
always @(posedge VGA_CTRL_CLK) begin
if (reset_all) begin
edge_iterator <= 8'd0;
comp_count <= 8'd0;
graphic_ops_iterator <= 0;
// initialize the graphics ops here
graphic_ops_count <= 4;
graphic_ops[0] = { 3'b101, 5'd0, 16'd1 << 13, 16'd1 << 13, 16'd1 << 13};
//graphic_ops[0] = { 3'b101, 5'd0, 16'd1 << 12, 16'd1 << 12, 16'd1 << 12};
graphic_ops[1] = { 3'b100, 5'd0, 16'd20, 16'd20, 16'd20 };
// rotate about x-axis 45 degrees
graphic_ops[2] = { 3'b000, 5'd0, 16'h0200, 16'd20, 16'd20 };
// rotate about y-axis 45 degrees
graphic_ops[3] = { 3'b001, 5'd0, 16'h0010, 16'd20, 16'd20 };
// scale by 0.5
//graphic_ops[0] = { 3'b101, 5'd0, 16'd1 << 13, 16'd1 << 13, 16'd1 << 13};
// translate by +20
//graphic_ops[1] = { 3'b100, 5'd0, 16'd20, 16'd20, 16'd20 };
// translate +20, +20, +20. works perfectly
// graphic_word[55:0] = { 3'b100, 5'd0, 16'd20, 16'd20, 16'd20 };
// for every unit of scale required, must right shift by 14
//graphic_word[55:0] = { 3'b101, 5'd0, 16'd2, 16'd2, 16'd2 };
// rotate 180 == 256 steps
//graphic_word[55:0] = { 3'b010, 5'd0, 16'd256, 16'd2, 16'd2 };
//graphic_word[55:0] = { 3'b010, 5'd0, 16'd128, 16'd0, 16'd0 };
comp_state <= transform_prep;
end // if (reset_all)
// blocking on edge_count.
else if (comp_state == transform_prep) begin
if (edge_iterator < edge_count) begin
if (debug_transform) begin
$display("op dump: %b", graphic_ops[0]);
$display("op dump: %b", graphic_ops[1]);
end
// load transform registers
transform_Ax <= edge_Ax[edge_iterator] >>> 8;
transform_Ay <= edge_Ay[edge_iterator] >>> 8;
transform_Az <= edge_Az[edge_iterator] >>> 8;
transform_Bx <= edge_Bx[edge_iterator] >>> 8;
transform_By <= edge_By[edge_iterator] >>> 8;
transform_Bz <= edge_Bz[edge_iterator] >>> 8;
// select none
rotater_init <= 1'b0;
translater_init <= 1'b0;
scaler_init <= 1'b0;
// go to transform_exec
comp_state <= transform_exec;
// load graphics op word
graphic_word <= graphic_ops[graphic_ops_iterator];
end // if (comp_state == transform_prep)
else begin
//$display("in transform_prep waiting for more edges");
end
end
else if (comp_state == transform_exec) begin
if (graphic_ops_iterator < graphic_ops_count) begin
if (transform_sel == 3'b000 |
transform_sel == 3'b001 |
transform_sel == 3'b010) begin
// select rotation
rotater_init <= 1'b1;
translater_init <= 1'b0;
scaler_init <= 1'b0;
end
else if (transform_sel == 3'b100) begin
// select translation
rotater_init <= 1'b0;
translater_init <= 1'b1;
scaler_init <= 1'b0;
end
else if (transform_sel == 3'b101) begin
// select scaling
rotater_init <= 1'b0;
translater_init <= 1'b0;
scaler_init <= 1'b1;
end
else begin
$display("TRANSFORMATION DISPATCH: op %d of %d.",
graphic_ops_iterator, graphic_ops_count, transop_x);
$finish;
end
// wait for transformation to be finished
//$display("going to transform_wait");
comp_state <= transform_wait;
// increment to the next operation
graphic_ops_iterator <= graphic_ops_iterator + 1;
end // if (graphic_ops_iterator < graphic_ops_count)
else begin
$display("transform waiting on exec for more points");
$finish;
end
end // if (comp_state == transform_exec)
else if (comp_state == transform_wait) begin
if (rotater_done | translater_done | scaler_done) begin
// save the intermediate values
transform_Ax <= next_Ax;
transform_Ay <= next_Ay;
transform_Az <= next_Az;
transform_Bx <= next_Bx;
transform_By <= next_By;
transform_Bz <= next_Bz;
// deselect all the transformation units
rotater_init <= 1'b0;
translater_init <= 1'b0;
scaler_init <= 1'b0;
if (graphic_ops_iterator < graphic_ops_count) begin
// load graphics op word
graphic_word <= graphic_ops[graphic_ops_iterator];
// go back to transform_exec
comp_state <= transform_exec;
end
else begin
// done state
comp_state <= transform_save;
end
end // if (rotater_done | translater_done | scaler_done)
end // if (comp_state == transform_wait)
else if (comp_state == transform_save) begin
// writeback
// save point into computed rf
comp_Ax[edge_iterator] <= next_Ax;
comp_Ay[edge_iterator] <= next_Ay;
comp_Az[edge_iterator] <= next_Az;
comp_Bx[edge_iterator] <= next_Bx;
comp_By[edge_iterator] <= next_By;
comp_Bz[edge_iterator] <= next_Bz;
comp_count <= comp_count + 8'd1;
// increment edge iterator
edge_iterator <= edge_iterator + 8'd1;
// reset graphics op iterator
graphic_ops_iterator <= 8'd0;
// go to transform_prep to wait for more edges
//comp_state <= transform_prep;
comp_state <= transform_prep;
end // if (comp_state == transform_save)
end // always @ (posedge VGA_CTRL_CLK)
always @(posedge VGA_CTRL_CLK) begin
if (reset_all) begin
// wipe all screen
lock <= 1'b1;
addr_reg <= { coord_x[9:1], coord_y[9:1] };
if ({1'b0, coord_x[9:1]} <= SCREEN_LEFT |
{1'b0, coord_x[9:1]} >= SCREEN_RIGHT |
{1'b0, coord_y[9:1]} <= SCREEN_TOP |
{1'b0, coord_y[9:1]} >= SCREEN_DOWN) begin
data_reg <= 16'hffff;
end else begin
data_reg <= 16'h0000;
end
// active-hi save
we <= 1'b1;
// bresenhem vars
comp_iterator <= 8'd0;
raster_state <= draw_lines;
bresenhem_init <= 1'b0;
end
else if ((~VGA_VS | ~VGA_HS) & ~pause_all & ~circle_busy) begin
lock <= 1'b1;
// set the output to the data reg
addr_reg <= { bresenhem_addr_reg_x[8:0],
bresenhem_addr_reg_y[8:0] };
data_reg <= (bresenhem_data_reg == 2'b01) ? 16'hffff : 16'h0000;
we <= bresenhem_we;
if (raster_state == draw_lines) begin
if (comp_iterator < comp_count) begin
bre_Ax <= comp_Ax[comp_iterator] + SCREEN_XHALF;
bre_Ay <= comp_Ay[comp_iterator] + SCREEN_YHALF;
bre_Bx <= comp_Bx[comp_iterator] + SCREEN_XHALF;
bre_By <= comp_By[comp_iterator] + SCREEN_YHALF;
bresenhem_init <= 1'b1;
comp_iterator <= comp_iterator + 8'd1;
raster_state <= wait_lines;
end // if (comp_iterator < comp_count)
end // if (raster_state <= draw_lines)
else if (raster_state == wait_lines) begin
if (bresenhem_busy) begin
bresenhem_init <= 1'b0;
end
//else if (bresenhem_done & (1'b1 & ~KEY[0])) begin
else if (bresenhem_done) begin
bresenhem_init <= 1'b0;
raster_state <= draw_lines;
end
end // if (raster_state == wait_lines)
else if (raster_state == keyok_lines) begin
if (KEY[0]) begin
bresenhem_init <= 1'b0;
raster_state <= draw_lines;
end
end
end // if ((~VGA_VS | ~VGA_HS) & ~pause_all & ~circle_busy)
else begin
// drawing to the screen
lock <= 1'b0;
addr_reg <= { coord_x[9:1], coord_y[9:1] };
we <= 1'b0;
end
end
// show the addressing being asserted using HEX[7:4]
HexDigit Digit0(HEX0, bre_By[3:0]);
HexDigit Digit1(HEX1, bre_By[7:4]);
HexDigit Digit2(HEX2, bre_Bx[3:0]);
HexDigit Digit3(HEX3, bre_Bx[7:4]);
HexDigit Digit4(HEX4, bre_Ay[3:0]);
HexDigit Digit5(HEX5, bre_Ay[7:4]);
HexDigit Digit6(HEX6, bre_Ax[3:0]);
HexDigit Digit7(HEX7, bre_Ax[7:4]);
// show the contents of that address using HEX[3:0]
endmodule