Lab5.v

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



2007-12-02