Appendix A ========== Table of Contents: ================== Listing 1 : VGA Synchronization Signals Generator module Listing 2 : VGA Synchronization Signals Generator - Test Module Listing 3 : Debounce Module Listing 4 : Implement Bitmap generation logic using Block RAM Listing 5 : SRAM Memory Controller : Back to back Memory operation 20nS Listing 6 : SRAM Memory Controller : TestModule Listing 7 : C# code for scaling down color bits Listing 8 : Implement Bitmap generation logic using SRAM as video memory Listing 9 : FIFO code Listing 10: Blob Detection - Connected Component Algorithm Listing 11: Hexadecimal Interface Module ============================================================================ ============================================================================== LISTING 1: VGA Synchronization Signals Generator module --------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// // This module generates all the timing and synchronization signals. // hsynch, vsynch control the vertical and horizontal scans // Video_on controls the enabling of display. // p_tick generates the pixel click rate of 25MHz from the board clock 50MHz //////////////////////////////////////////////////////////////////////////// `timescale 1ns / 1ps module vga_synch ( input wire clk, reset, output wire hsynch, vsynch, video_on, p_tick, output wire [9:0] pixel_x, pixel_y ); // constant declaration // VGA 640-by-480 synch parameters localparam HD = 640; // Horizontal display area localparam HF = 48; // h. front (left border) localparam HB = 16; // h. back (right border) localparam HR = 96; // h. retrace localparam VD = 480; // vertical display area localparam VF = 10; // v. front (top border) localparam VB = 33; // v.back (bottom) border localparam VR = 2; // v. retrace // mod_2 Counter reg mod2_reg; wire mod2_next; //synch counters reg [9:0] h_count_reg,h_count_next; reg [9:0] v_count_reg,v_count_next; // output buffer reg v_synch_reg, h_synch_reg; wire v_synch_next, h_synch_next; //status signals wire h_end, v_end, pixel_tick; //////////////////body of the program//////////////// // Registers// always @(posedge clk, posedge reset) if (reset) begin mod2_reg <= 1'b0; v_count_reg <= 0; h_count_reg <= 0; v_synch_reg <= 1'b0; h_synch_reg <= 1'b0; end else begin mod2_reg <= mod2_next; v_count_reg <= v_count_next; h_count_reg <= h_count_next; v_synch_reg <= v_synch_next; h_synch_reg <= h_synch_next; end /////////////mod-2 circuit to generate 25MHZ enable tick assign mod2_next = ~mod2_reg; assign pixel_tick = mod2_reg; // status signals // end of horizontal counter (799) assign h_end = (h_count_reg == ( HD + HF + HB + HR - 1)); // end of vertical counter (524) assign v_end = ( v_count_reg ==(VD + VF + VB + VR - 1 )); // next-state logic for mod-800 horizontal synch counter always @* if (pixel_tick) if (h_end) h_count_next = 0; else h_count_next = h_count_reg + 1; else h_count_next = h_count_reg; // next-state logic for mod-525 vertical synch counter always @* if (pixel_tick & h_end) if (v_end) v_count_next = 0; else v_count_next = v_count_reg + 1; else v_count_next = v_count_reg; // Horizontal and vertical synch buffered to avoid glitch // h_synch_next asserted between 656 and 751 assign h_synch_next = (h_count_reg >= (HD + HB) && h_count_reg <= (HD + HB + HR - 1)); // vh_synch_next asserted between 490 and 491 assign v_synch_next = (v_count_reg >= (VD + VB) && v_count_reg <= (VD + VB + VR - 1)); // video on/off assign video_on = (h_count_reg < HD) && (v_count_reg < VD); //Output assign hsynch = h_synch_reg; assign vsynch = v_synch_reg; assign pixel_x = h_count_reg; assign pixel_y = v_count_reg; assign p_tick = pixel_tick; endmodule LISTING 2: VGA Synchronization Signals Generator - Test Module ---------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// // vga_synch module in instantiated in the test module. // rgb signal is directly connected to three input switches. // The entire visible region should be turned on with a single color. // The screen can be changed to 8 different colors. //////////////////////////////////////////////////////////////////////////// module vgaSynch_test ( input wire clk, reset, input wire [2:0] sw, output wire hsynch, vsynch, output wire [2:0] rgb ); //signal declaration reg [2:0] rgb_reg; wire video_on; // instantiate vga synch circuit vga_synch vga_synch_unit ( .clk(clk), .reset(reset), .hsynch(hsynch), .vsynch(vsynch), .video_on(video_on), .p_tick(), .pixel_x(), .pixel_y() ); always @(posedge clk, posedge reset) if (reset) rgb_reg <= 0; else rgb_reg <= sw; //output assign rgb = (video_on) ? rgb_reg : 3'b0; endmodule LISTING 3: Debounce Module ---------------------------------------------------------------- module debounce ( input wire clk, reset, input wire sw, output reg db_level, db_tick ); // Symbolic state declaration localparam [1:0] zero = 2'b00, wait0 = 2'b01, one = 2'b10, wait1 = 2'b11; // Number of counter bits( 2^N * 20ns = 40ms) localparam N = 21; // signal declaration reg [N-1:0] q_reg, q_next; reg[1:0] state_reg, state_next; //body //fsmd state & data registers. always @(posedge clk, posedge reset) if (reset) begin state_reg <= zero; q_reg <= 0; end else begin state_reg <= state_next; q_reg <= q_next; end // next- state logic and data path functional units/routing always @* begin state_next = state_reg; q_next = q_reg; db_tick = 1'b0; case (state_reg) zero: begin db_level = 1'b0; if (sw) begin state_next = wait1; q_next = {N{1'b1}}; end end wait1: begin db_level = 1'b0; if (sw) begin q_next = q_reg -1; if (q_next == 0) begin state_next = one; db_tick = 1'b1; end end else state_next = zero; end one: begin db_level = 1'b1; if (~sw) begin state_next = wait0; q_next = {N{1'b1}}; end end wait0: begin db_level = 1'b1; if (~sw) begin q_next = q_reg - 1; if (q_next == 0) state_next = zero; end else state_next = one; end default: state_next = zero; endcase end endmodule LISTING 4 : Implement Bitmap generation logic using Block RAM -------------------------------------------------------------- //////////////// Top Module ///////////////////////////////// module Balloon_TopModule ( input wire clk, reset, output wire hsynch, vsynch, output wire [2:0] rgb ); // signal declaration wire [9:0] pixel_x, pixel_y; wire video_on, pixel_tick; reg [2:0] rgb_reg; wire [2:0] rgb_next; //body // Instantiate VGA synch circuit vga_synch vga_synch_unit (.clk(clk), .reset(reset), .hsynch(hsynch), .vsynch(vsynch), .video_on (video_on), .p_tick(pixel_tick), .pixel_x(pixel_x), .pixel_y(pixel_y)); //Instantiate gaphic generator bitmap_gen bitmap_gen_unit ( .clk(clk), .reset(reset), .video_on(video_on), .pix_x(pixel_x), .pix_y(pixel_y), .bit_rgb(rgb_next) ); // rgb buffer always @(posedge clk) if (pixel_tick) rgb_reg <= rgb_next; //output assign rgb = rgb_reg; endmodule ////////////////////////////////////////////////////////////////////////////////// // Main Objective: How the VGA Controller produce a frame from memory. // An image is embedded in the block RAM using core generator feature. // At 25MHz Pixels are continuously read from the memory. // vga_synch module in instantiated to generate all timing and synchronization signals // Each addressed block-RAM is 3bit wide. The exact value is routed as bit_rgb /////////////////////////////////////////////////////////////////////////////////////// module bitmap_gen ( input wire clk, reset, input wire video_on, input wire [9:0] pix_x, pix_y, output reg [2:0] bit_rgb ); //----------------------------------------------------- // VIDEO SRAM //------------------------------------------------------ wire we; wire [13:0] addr; wire [2:0] din,dout; //--------------------------------------------------------- //PIXEL location //--------------------------------------------------------- localparam MAX_X = 128; localparam MAX_Y = 128; //---------------------------------------------------------- // Object output signals // -------------------------------------------------------- wire bitmap_on; wire [2:0] bitmap_rgb; // instantiate_dual_port_RAM_Synch //SinglePortAsynchReadBlockRAM myVideoRAM (.clk(clk), .we(we), .addr(addr), // .din(din), .dout(dout) ); //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG SinglePortAsynchReadBlockRAM your_instance_name ( .clka(clk), // input clka .wea(we), // input [0 : 0] wea .addra(addr), // input [13 : 0] addra .dina(din), // input [2 : 0] dina .douta(dout) // output [2 : 0] douta ); // INST_TAG_END ------ End INSTANTIATION Template --------- assign addr = {pix_y[6:0], pix_x[6:0]}; assign we = 1'b0; assign bitmap_rgb = dout; // Pixel within bitmap area assign bitmap_on = ( pix_x <= 127 ) & (pix_y <= 127 ); // rgb Multiplexing circuit. always @* if (~video_on) bit_rgb = 3'b000; else if (bitmap_on) bit_rgb = bitmap_rgb; else bit_rgb = 3'b110; endmodule LISTING 5 : SRAM Memory Controller : Back to back Memory operation 20nS -------------------------------------------------------------------------- module ram_ctrl_test ( input wire clk,reset, input wire [7:0] sw, input wire [2:0] btn, output wire [7:0] led, output wire [17:0] ad, output wire we_n, oe_n, inout wire[15:0] dio_a, output wire ce_a_n, ub_a_n, lb_a_n ); // singnal declaration wire [17:0] addr; wire [15:0] data_s2f; reg [15:0] data_f2s; reg mem, rw; reg [7:0] data_reg; reg [7:0] data_reg2; wire [2:0] db_btn; wire Clock_200MHz; wire Clk_Out, Locked_Out; //body //initialiation sram_ctrl ctrl_next (.clk(Clock_200MHz),.reset(reset),.mem(mem),.rw(rw),.addr(addr),.data_f2s(data_f2s),.ready(), .data_s2f_r(data_s2f),.data_s2f_ur(),.ad(ad),.we_n(we_n),.oe_n(oe_n),.dio_a(dio_a), .ce_a_n(ce_a_n),.ub_a_n(ub_a_n),.lb_a_n(lb_a_n)); // Instantiate the module DCM_200Mhz instance_name ( .CLKIN_IN(clk), .RST_IN(reset), .CLKFX_OUT(Clock_200MHz), .CLK0_OUT(Clk_Out), .LOCKED_OUT(Locked_Out) ); debounce deb_unit0 (.clk(clk),.reset(reset),.sw(btn[0]),.db_level(),.db_tick(db_btn[0])); debounce deb_unit1 (.clk(clk),.reset(reset),.sw(btn[1]),.db_level(),.db_tick(db_btn[1])); debounce deb_unit2 (.clk(clk),.reset(reset),.sw(btn[2]),.db_level(),.db_tick(db_btn[2])); //data registers always @(posedge clk) if(db_btn[0]) data_reg <= sw; //address assign addr ={10'b0,8'b10101010}; always @* begin //data_f2s = 0; if(db_btn[1]) // write begin mem=1'b1; rw=1'b0; data_f2s={8'b0,data_reg}; end else if( db_btn[2]) //read begin mem=1'b1; rw= 1'b1; end else begin mem=1'b0; rw=1'b1; end end assign led= data_s2f[7:0]; endmodule ////////// DCM -200MHz Module (Core gen generated module for xilinx Sparten 3 FPGA//////// //////////////////////////////////////////////////////////////////////////////// // Copyright (c) 1995-2011 Xilinx, Inc. All rights reserved. //////////////////////////////////////////////////////////////////////////////// // ____ ____ // / /\/ / // /___/ \ / Vendor: Xilinx // \ \ \/ Version : 13.4 // \ \ Application : xaw2verilog // / / Filename : DCM_200Mhz.v // /___/ /\ Timestamp : 05/15/2012 14:37:04 // \ \ / \ // \___\/\___\ // //Command: xaw2verilog -intstyle C:/XILINX_ISE/MemoryController_SRAM_S3_at200Mhz/ipcore_dir/DCM_200Mhz.xaw -st DCM_200Mhz.v //Design Name: DCM_200Mhz //Device: xc3s1000-4ft256 // // Module DCM_200Mhz // Generated by Xilinx Architecture Wizard // Written for synthesis tool: XST // Period Jitter (unit interval) for block DCM_INST = 0.14 UI // Period Jitter (Peak-to-Peak) for block DCM_INST = 0.70 ns `timescale 1ns / 1ps module DCM_200Mhz(CLKIN_IN, RST_IN, CLKFX_OUT, CLK0_OUT, LOCKED_OUT); input CLKIN_IN; input RST_IN; output CLKFX_OUT; output CLK0_OUT; output LOCKED_OUT; wire CLKFB_IN; wire CLKFX_BUF; wire CLK0_BUF; wire GND_BIT; assign GND_BIT = 0; assign CLK0_OUT = CLKFB_IN; BUFG CLKFX_BUFG_INST (.I(CLKFX_BUF), .O(CLKFX_OUT)); BUFG CLK0_BUFG_INST (.I(CLK0_BUF), .O(CLKFB_IN)); DCM #( .CLK_FEEDBACK("1X"), .CLKDV_DIVIDE(2.0), .CLKFX_DIVIDE(1), .CLKFX_MULTIPLY(4), .CLKIN_DIVIDE_BY_2("FALSE"), .CLKIN_PERIOD(20.000), .CLKOUT_PHASE_SHIFT("NONE"), .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), .DFS_FREQUENCY_MODE("LOW"), .DLL_FREQUENCY_MODE("LOW"), .DUTY_CYCLE_CORRECTION("TRUE"), .FACTORY_JF(16'h8080), .PHASE_SHIFT(0), .STARTUP_WAIT("TRUE") ) DCM_INST (.CLKFB(CLKFB_IN), .CLKIN(CLKIN_IN), .DSSEN(GND_BIT), .PSCLK(GND_BIT), .PSEN(GND_BIT), .PSINCDEC(GND_BIT), .RST(RST_IN), .CLKDV(), .CLKFX(CLKFX_BUF), .CLKFX180(), .CLK0(CLK0_BUF), .CLK2X(), .CLK2X180(), .CLK90(), .CLK180(), .CLK270(), .LOCKED(LOCKED_OUT), .PSDONE(), .STATUS()); endmodule ///////////////////////////////////////////////////////////////////// // SRAM Controller Module ///////////////////////////////////////////////////////////////////// module sram_ctrl ( input wire clk, reset, //to/ form main system input wire mem,rw, input wire [17:0] addr, input wire [15:0] data_f2s, output reg ready, output wire[15:0] data_s2f_r,data_s2f_ur, //to / form sram chip output wire [17:0] ad, output wire we_n, oe_n, // sram chip a inout wire [15:0] dio_a, output wire ce_a_n, ub_a_n, lb_a_n ); //symbolic state declaration localparam [2:0] idle = 3'b000, rd1 = 3'b001, rd2 = 3'b010, rd3 = 3'b011, wr1 = 3'b100, wr2 = 3'b101, wr3 = 3'b111; // signal declaration reg [2:0] state_reg, state_next; reg [15:0] data_f2s_reg, data_f2s_next; reg [15:0] data_s2f_reg, data_s2f_next; reg [17:0] addr_reg, addr_next; reg we_buf, oe_buf, tri_buf; reg we_reg, oe_reg, tri_reg; //body // fsm state & data registers always @( posedge clk, posedge reset) if(reset) begin state_reg <= idle; addr_reg <=0 ; data_f2s_reg <=0; data_s2f_reg <=0; tri_reg <=1'b1; we_reg <=1'b1; oe_reg <=1'b1; end else begin state_reg <= state_next; addr_reg <= addr_next ; data_f2s_reg <= data_f2s_next; data_s2f_reg <= data_s2f_next; tri_reg <= tri_buf; we_reg <= we_buf; oe_reg <= oe_buf; end // fsmnext-state logic always @* begin addr_next = addr_reg; data_f2s_next = data_f2s_reg; data_s2f_next = data_s2f_reg; ready =1'b0; case (state_reg) idle: begin if (~mem) state_next= idle; else begin addr_next=addr; if (~rw) // write begin state_next= wr1; data_f2s_next = data_f2s; end else // read state_next= rd1; end ready =1'b1; end wr1: state_next = wr2; wr2: state_next = wr3; wr3: state_next = idle; rd1: state_next = rd2; rd2: state_next = rd3; rd3: begin data_s2f_next = dio_a; state_next = idle; end default state_next = idle; endcase end // look - ahead output logic always @* begin tri_buf = 1'b1; // signala are active low we_buf= 1'b1; oe_buf= 1'b1; case (state_next) idle : oe_buf = 1'b1; wr1: begin tri_buf= 1'b0; we_buf= 1'b0; end wr2: begin tri_buf= 1'b0; we_buf= 1'b0; end wr3: tri_buf= 1'b0; rd1: oe_buf =1'b0; rd2: oe_buf= 1'b0; rd3: oe_buf= 1'b0; endcase end // to main system assign data_s2f_r= data_s2f_reg; assign data_s2f_ur= dio_a; //to sram assign we_n = we_reg; assign oe_n = oe_reg; assign ad = addr_reg; // i/o for sram chip a assign ce_a_n =1'b0; assign ub_a_n =1'b0; assign lb_a_n =1'b0; assign dio_a = (~tri_reg)?data_f2s_reg: 16'bz; endmodule LISTING 6 : SRAM Memory Controller : TestModule ------------------------------------------------ module ram_ctrl_test ( input wire clk,reset, input wire [7:0] sw, input wire [2:0] btn, output wire [7:0] led, output wire [17:0] ad, output wire we_n, oe_n, inout wire[15:0] dio_a, output wire ce_a_n, ub_a_n, lb_a_n ); // singnal declaration wire [17:0] addr; wire [15:0] data_s2f; reg [15:0] data_f2s; reg mem, rw; reg [7:0] data_reg; reg [7:0] data_reg2; wire [2:0] db_btn; wire Clock_200MHz; wire Clk_Out, Locked_Out; //body //initialiation sram_ctrl ctrl_next (.clk(Clock_200MHz),.reset(reset),.mem(mem),.rw(rw),.addr(addr),.data_f2s(data_f2s),.ready(), .data_s2f_r(data_s2f),.data_s2f_ur(),.ad(ad),.we_n(we_n),.oe_n(oe_n),.dio_a(dio_a), .ce_a_n(ce_a_n),.ub_a_n(ub_a_n),.lb_a_n(lb_a_n)); // Instantiate the module DCM_200Mhz instance_name ( .CLKIN_IN(clk), .RST_IN(reset), .CLKFX_OUT(Clock_200MHz), .CLK0_OUT(Clk_Out), .LOCKED_OUT(Locked_Out) ); debounce deb_unit0 (.clk(clk),.reset(reset),.sw(btn[0]),.db_level(),.db_tick(db_btn[0])); debounce deb_unit1 (.clk(clk),.reset(reset),.sw(btn[1]),.db_level(),.db_tick(db_btn[1])); debounce deb_unit2 (.clk(clk),.reset(reset),.sw(btn[2]),.db_level(),.db_tick(db_btn[2])); //data registers always @(posedge clk) if(db_btn[0]) data_reg <= sw; //address assign addr ={10'b0,8'b10101010}; always @* begin //data_f2s = 0; if(db_btn[1]) // write begin mem=1'b1; rw=1'b0; data_f2s={8'b0,data_reg}; end else if( db_btn[2]) //read begin mem=1'b1; rw= 1'b1; end else begin mem=1'b0; rw=1'b1; end end assign led= data_s2f[7:0]; endmodule LISTING 7 : C# code for scaling down color bits //////////////////////////////////////////////////////////////////////// // // Code for scaling down 24bit color to 3bit color format. // //////////////////////////////////////////////////////////////////////// using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Drawing; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Color clr; Color clrset; String pixel; StreamWriter writer = new StreamWriter("balloons.coe"); Bitmap bmp = new Bitmap("balloons.bmp"); Bitmap bmpsave = bmp; for (int i = 0; i < bmp.Height; i++) { for (int j = 0; j < bmp.Width; j++) { clr = bmp.GetPixel(j, i); pixel = ((clr.R & 0x80) == 0x80) ? "1" : "0"; pixel += ((clr.G & 0x80) == 0x80) ? "1" : "0"; pixel += ((clr.B & 0x80) == 0x80) ? "1" : "0"; writer.WriteLine(pixel + ";"); int R = ((clr.R & 0x80) == 0x80) ? 0xFF : 0; int G = ((clr.G & 0x80) == 0x80) ? 0xFF : 0; int B = ((clr.B & 0x80) == 0x80) ? 0xFF : 0; clrset = Color.FromArgb(R, G, B); bmpsave.SetPixel(j,i,clrset); } } writer.Close(); bmpsave.Save("balloons-8clr.bmp"); } } } Listing 8 //////////////////////////////////////////////////////////////////////// // // Implement Bitmap generation logic using SRAM as video memory // //////////////////////////////////////////////////////////////////////// `timescale 1ns / 1ps module SRAM_VideoMemory( input wire sys_clk, input wire reset, input wire btn1, //input wire btn2, //input wire [7:0] switch, input wire p_tick, input wire video_on, input wire [9:0] pixel_x, input wire [9:0] pixel_y, output wire TransferCompleteLED, output wire [15:0] pixel_data, output wire [15:0] Count_LED, output wire [17:0] ad, output wire we_n, oe_n, inout wire[15:0] dio_a, output wire ce_a_n, ub_a_n, lb_a_n ); localparam [3:0] state_init = 4'b0000, write_state1 = 4'b0001, write_state2 = 4'b0010, write_state3 = 4'b0011, write_state4 = 4'b0100; localparam [3:0] rd_state_init = 4'b0000, rd_state1 = 4'b0001, rd_state2 = 4'b0010; localparam BR_address_x_MAX =128;//=128; localparam BR_address_y_MAX =96;//128; localparam VM_address_x_MAX =640; localparam VM_address_y_MAX =480; reg TC_reg = 0, TC_reg_next; integer i; reg [6:0] BR_address_x, BR_address_x_next; reg [6:0] BR_address_y, BR_address_y_next; reg [9:0] VM_address_x, VM_address_x_next; reg [9:0] VM_address_y, VM_address_y_next; wire [17:0] VM_Addr; wire [13:0] BR_Addr; //---------------- Signals for BlockRAM------------------------- wire we; wire [15:0] din,dout; reg [15:0] dout_reg; //---------------- Signals for SRAM_Ctrlr------------------------- wire mem; wire rw ; reg [17:0] addr; wire [15:0] data_s2f; wire [15:0] data_f2s; //---------------- Signals for debounce------------------------- wire db_btn1; //wire db_btn2; //---------------- Signals for DCM------------------------- wire Clock_200Mhz; wire Clk0Out; wire LockedOut; //---------------- Instantiate the Core Gen generated 200MHz Clock module--------------------- // Input = 50 Mhz // Output = 200 Mhz DCM_200MHz DCM_200MHz_unit1 ( .CLKIN_IN(sys_clk), .RST_IN(reset), .CLKFX_OUT(Clock_200Mhz), .CLK0_OUT(Clk0Out), .LOCKED_OUT(LockedOut) ); //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG SumiBlockRAM your_instance_name ( .clka(Clock_200Mhz), // input clka .wea(we), // input [0 : 0] wea .addra(BR_Addr), // input [13 : 0] addra .dina(din), // input [15 : 0] dina .douta(dout) // output [15 : 0] douta ); // INST_TAG_END ------ End INSTANTIATION Template --------- sram_ctrl sram_ctrl_unit1 ( .clk(Clock_200Mhz), .reset(reset), .mem(mem), .rw(rw), .addr(VM_Addr), .data_f2s(data_f2s), .Busy(Busy), .ready(ready), .data_s2f_r(), .data_s2f_ur(data_s2f), // Note the unregistered data is used here. .ad(ad), .we_n(we_n), .oe_n(oe_n), .dio_a(dio_a), .ce_a_n(ce_a_n), .ub_a_n(ub_a_n), .lb_a_n(lb_a_n) ); debounce deb_unit0 (.clk(sys_clk),.reset(reset),.sw(btn1),.db_level(),.db_tick(db_btn1)); reg [3:0] state_reg, state_next; reg [15:0] copy_counter_reg, copy_counter_next; reg [15:0] read_counter_reg, read_counter_next; reg [9:0] Read_addr_x = 0, Read_addr_x_next; reg [9:0] Read_addr_y = 0, Read_addr_y_next; reg mem_wr_phase, mem_rd_phase; reg rw_wr_phase, rw_rd_phase; assign mem = TC_reg ? mem_rd_phase : mem_wr_phase; assign rw = TC_reg ? rw_rd_phase : rw_wr_phase; assign Count_LED = copy_counter_reg[15:0]; assign we = 1'b0; assign BR_Addr = {BR_address_y[6:0], BR_address_x[6:0]}; assign VM_Addr = TC_reg ? {Read_addr_y[9:0], Read_addr_x[9:0]} : {VM_address_y[9:0], VM_address_x[9:0]}; assign data_f2s = dout_reg; assign TransferCompleteLED = TC_reg ? 1'b1 : 1'b0; always @ (posedge Clock_200Mhz, posedge reset) begin if (reset) begin TC_reg <= 0; state_reg <= state_init; copy_counter_reg <= 0; BR_address_x <= 0; BR_address_y <= 0; VM_address_x <= 0; VM_address_y <= 0; end else begin state_reg <= state_next; copy_counter_reg <= copy_counter_next; BR_address_x <= BR_address_x_next; BR_address_y <= BR_address_y_next; VM_address_x <= VM_address_x_next; VM_address_y <= VM_address_y_next; TC_reg <= TC_reg_next; end end always @(Clock_200Mhz,db_btn1) begin BR_address_x_next = BR_address_x; BR_address_y_next = BR_address_y; VM_address_x_next = VM_address_x; VM_address_y_next = VM_address_y; copy_counter_next = copy_counter_reg; TC_reg_next = TC_reg; rw_wr_phase = 1'b0; // write operation mem_wr_phase = 1'b0; // Pulse when necessary case (state_reg) state_init: // waits for button press begin if (db_btn1) begin state_next = write_state1; end else state_next = state_init; end write_state1: // Corresponds to idle state of Mem controller begin state_next = write_state2; mem_wr_phase = 1'b1; rw_wr_phase = 1'b0; dout_reg = dout; end write_state2: // Corresponds to write 1 state of Mem controller begin state_next = write_state3; end write_state3: // Corresponds to write 1 state of Mem controller begin state_next = write_state4; end write_state4: // Corresponds to write 2 state of Mem controller begin copy_counter_next = copy_counter_reg + 1; state_next = write_state1; VM_address_x_next = VM_address_x + 1; if (VM_address_x_next > VM_address_x_MAX - 1) begin VM_address_x_next = 0; VM_address_y_next = VM_address_y + 1; if (VM_address_y_next > VM_address_y_MAX - 1) begin VM_address_y_next = 0; VM_address_x_next = 0; TC_reg_next = 1; // should quit here state_next = state_init; end else BR_address_y_next = BR_address_y + 1; if (BR_address_y_next > BR_address_y_MAX - 1) BR_address_y_next = 0; end else i = 0; BR_address_x_next = VM_address_x_next % BR_address_x_MAX; //BR_address_y_next = VM_address_y_next % BR_address_y_MAX; end default: state_next = state_init; endcase end reg [15:0] sram_data = 0; reg [3:0] read_state_reg, read_state_next; always @(posedge sys_clk, posedge reset) begin if (reset) read_state_reg <= rd_state_init; else read_state_reg <= read_state_next; end always @(sys_clk) begin rw_rd_phase = 1'b0; // write operation mem_rd_phase = 1'b0; // Pulse when necessary //clear_display_read_pending = 1'b0; case(read_state_reg) rd_state_init: begin if (p_tick && video_on && TC_reg) begin Read_addr_x = pixel_x; Read_addr_y = pixel_y; rw_rd_phase = 1'b1; // read operation mem_rd_phase = 1'b1; read_state_next = rd_state2; end else read_state_next = rd_state_init; end rd_state2: begin // read the data sram_data = data_s2f; read_state_next = rd_state_init; end endcase end assign pixel_data = (TC_reg && video_on) ? sram_data[15:0] : 16'b0000000000000000; endmodule Listing 9 //////////////////////////////////////////////////////////////////////// // // FIFO code // //////////////////////////////////////////////////////////////////////// module fifo #( parameter B = 8, W = 4 ) ( input wire clk, reset, input wire rd, wr, input wire [B - 1: 0] w_data, output wire empty, full, output wire [B-1 : 0] r_data ); // Signal declaration reg [B-1 : 0] array_reg [2**W - 1 : 0]; // register array //======================================================== integer i; reg start, startNext, activity, activityNext; reg endProcess, endNext; reg [W-1 : 0] w_ptr_reg, w_ptr_next, w_ptr_succ; reg [W-1 : 0] r_ptr_reg, r_ptr_next, r_ptr_succ; reg full_reg, empty_reg, full_next, empty_next; wire wr_en; always @ (posedge clk) begin if (wr_en) begin array_reg [w_ptr_reg] <= w_data; // Register file write operation $display($time," WrittenData is %d",array_reg [w_ptr_reg]); $display($time," Value for read is %d",array_reg[r_ptr_reg]); end end assign r_data = array_reg[r_ptr_reg]; // Register file read operation //------Condition Check 1------ assign wr_en = wr & ~full_reg; // Write enabled only when FIFO is not full. // Main FIFO Control Logic //=========================== // Defining registers for the logic. Isolating the memory part always @(posedge clk, posedge reset) if (reset) begin w_ptr_reg <= 0; r_ptr_reg <= 0; full_reg <= 1'b0; empty_reg <= 1'b1; start <=0; endProcess <= 0; activity <= 0; $display(" I am in reset state of FIFO "); end else begin w_ptr_reg <= w_ptr_next; r_ptr_reg <= r_ptr_next; full_reg <= full_next; empty_reg <= empty_next; start <= startNext; endProcess <= endNext; activity <= activityNext; end // next-state logic for read and write pointers always @* begin startNext = 1'b0; activityNext = 1'b0; endNext = 1'b0; // Successive pointer values w_ptr_succ = w_ptr_reg + 1; r_ptr_succ = r_ptr_reg + 1; // Default Keep old values w_ptr_next = w_ptr_reg; r_ptr_next = r_ptr_reg; full_next = full_reg; empty_next = empty_reg; case ({wr,rd}) //2'b00 : No operation 2'b01: // Read from FIFO if (~empty_reg) // Check if FIFO is not empty begin start = 1'b1; activity = 1'b1; r_ptr_next = r_ptr_succ; // There is something to read full_next = 1'b0; // Not full if (r_ptr_succ == w_ptr_reg) // The successive pointer meets the write pointer empty_next = 1'b1; // Nothing more written FIFO empty. end 2'b10: // Write into FIFO if (~full_reg) // Check if FIFO is Full before you start writing begin start = 1'b1; activity = 1'b1; w_ptr_next = w_ptr_succ; empty_next = 1'b0; if ( w_ptr_succ == r_ptr_reg) full_next = 1'b1; end 2'b11: begin start = 1'b1; activity = 1'b1; w_ptr_next = w_ptr_succ; r_ptr_next = r_ptr_succ; end endcase endProcess = 1'b1; end always @(posedge start ,posedge activity) begin if (activity == 1) begin for (i = 0; i < (2**W - 1); i = i + 1) $display ("My BEFORE status is : ", array_reg[i]); end end always @(posedge endProcess, posedge endProcess) begin if (activity == 1) begin for (i = 0; i < (2**W - 1); i = i + 1) $display ("My AFTER status is : ", array_reg[i]); end end initial begin for (i = 0; i < (2**W - 1); i = i + 1) begin array_reg[i] = 0; end $display($time,"Completed Initialization of FIFO"); end assign full = full_reg; assign empty = empty_reg; endmodule Listing 10 //////////////////////////////////////////////////////////////////////// // // Blob Detection - Connected Component Algorithm // //////////////////////////////////////////////////////////////////////// module CCL_PROC (); reg Initialize; // Initialize Image reg ProcessImage; // Start processing reg clock; reg reset; reg done_Init; reg print_done_Init; reg done_Processing_Phase1 = 1'b0; // Intermediate labelling reg print_done_Processing_Phase1; reg done_Processing_Phase2 = 1'b0; // CCL Completed. reg print_done_Processing_Phase2 = 1'b0; // Blob Detection phase. reg allDone = 1'b0; integer i = 0; integer j = 0; integer k = 0; // B iw word width in Bits // DEPTH is the Depth of the array. // Line : How many pixels are there in one line. // LABEL_Bits = 3 => 2pow3 8 blobs possible. // In this design we put a restriction on number of blobs. // We start with a support of 8 blobs => LABEL_Bits = 3 // NEW PARAMETER DEFINITIONS parameter ROWS = 8; parameter COLUMNS = 8; parameter DEPTH = ROWS * COLUMNS; parameter NUMLINES_MAX = DEPTH / COLUMNS; parameter ROWADDRESSMAX_Bits = 3 ; parameter COLUMNADDRESSMAX_Bits = 3 ; parameter LABEL_Bits = 3; parameter ADDRESS_Bits_MAX = ROWADDRESSMAX_Bits + ROWADDRESSMAX_Bits; parameter BLOB_LABEL_ID_MAX = (2**LABEL_Bits); parameter BLOB_TABLE_ENTRY_BITS_MAX = 9; // Need 9 bits to store max SigmaXbar (for 8x8 image, max SigmaXbar = 288) // Global structure definitions //------------------------------ //Note : Array Usage //------------------- // The Source_reg is initialized and used as Source Image Array // (Assuming the threshholding is already done) // The Process_reg holds the intermidiate labels // After the merging process the final image with connected component labels (Blobs detected) // is copied to Source Register. reg [LABEL_Bits - 1 : 0] Source_reg [0 : (DEPTH-1) ]; // source register array reg [LABEL_Bits- 1 : 0] Process_reg [0 : (DEPTH-1) ] ; // Process register array //Read Buffer 1. reg [LABEL_Bits-1 : 0] Read_Buf1 [0 : (ROWS - 1)]; // Blob Tables // ==================== reg [LABEL_Bits - 1 : 0 ] MergeTable [0 : (BLOB_LABEL_ID_MAX-1) ]; reg [(BLOB_TABLE_ENTRY_BITS_MAX-1) : 0 ] AreaTable [0 : (BLOB_LABEL_ID_MAX-1) ]; reg [(BLOB_TABLE_ENTRY_BITS_MAX-1) : 0 ] SigmaXBARTable [0 : (BLOB_LABEL_ID_MAX-1) ]; reg [(BLOB_TABLE_ENTRY_BITS_MAX-1) : 0 ] SigmaYBARTable [0 : (BLOB_LABEL_ID_MAX-1) ]; reg [(BLOB_TABLE_ENTRY_BITS_MAX-1) : 0 ] CenterXTable [0 : (BLOB_LABEL_ID_MAX-1) ]; reg [(BLOB_TABLE_ENTRY_BITS_MAX-1) : 0 ] CenterYTable [0 : (BLOB_LABEL_ID_MAX-1) ]; task PrintMergeTable; begin $display("MergeTable AreaTable SigmaXBARTable SigmaYBARTable CenterXTable CenterYTable"); $display("=============================================================================="); for (i = 0; i < BLOB_LABEL_ID_MAX; i = i + 1) begin $display("%10d %9d %14d %14d %12d %12d",MergeTable[i], AreaTable[i], SigmaXBARTable[i], SigmaYBARTable[i], CenterXTable[i], CenterYTable[i]); end $write("\n"); end endtask // Instantiation part : ReadFIFO //------------------------------ // __rd with each signal implies The signals for READ FIFO reg rd_rd = 0, wr_rd = 0; // 00 ->NO operation case. 01->read, 10->write, 11->write wire empty_rd_fifo, full_rd_fifo; reg [(LABEL_Bits - 1) : 0 ]WriteData_rd; wire [(LABEL_Bits - 1) : 0 ]ReadData_rd_fifo; reg empty_rd, full_rd,ReadData_rd; // FIFO for a line of 8 pixels (one line) each 3 bit wide. fifo #(.B(LABEL_Bits),.W(COLUMNADDRESSMAX_Bits)) ReadFIFO ( .clk(clock), .reset(reset), .rd(rd_rd), .wr(wr_rd), .w_data(WriteData_rd), .empty(empty_rd_fifo), .full(full_rd_fifo), .r_data(ReadData_rd_fifo) ); // // Divider instantiation // parameter M_PP = 9; // Size of dividend parameter N_PP = 8; // Size of divisor parameter R_PP = 0; // Size of remainder parameter S_PP = 5; // Skip this many bits (known leading zeros) parameter COUNT_WIDTH_PP = 5; // 2^COUNT_WIDTH_PP-1 >= (M_PP+R_PP-S_PP-1) parameter DIVIDE_CLOCKS = M_PP - S_PP; // local variables for divider FSM reg [COUNT_WIDTH_PP - 1 : 0] div_clock_counter; reg [COUNT_WIDTH_PP - 1 : 0] div_clock_counter_next; reg [LABEL_Bits -1 : 0] blobtable_index; reg [LABEL_Bits -1 : 0] blobtable_index_next; // Common Signals for both divider reg clk_en_i; reg divide_i; // starts division operation // Centroid X Divider // Internal Signal Declarations // starts division operation reg [M_PP-1:0] dividend_i_X; // reg [N_PP-1:0] divisor_i_X; // wire [M_PP+R_PP-S_PP-1:0] quotient_o_X; // wire done_o_X; // indicates completion of operation reg [M_PP+R_PP-S_PP-1:0] result_X; //Instantiation part serial_divide_uu #(.M_PP(M_PP),.N_PP(N_PP), .R_PP(R_PP), .S_PP(S_PP), .COUNT_WIDTH_PP(COUNT_WIDTH_PP) ) serial_divide_uu_unitX ( .clk_i(clock), .clk_en_i(clk_en_i), .rst_i(reset), .divide_i(divide_i), .dividend_i(dividend_i_X), .divisor_i(divisor_i_X), .quotient_o(quotient_o_X), .done_o(done_o_X) ); // Centroid Y Divider // Internal Signal Declarations reg [M_PP-1:0] dividend_i_Y; // reg [N_PP-1:0] divisor_i_Y; // wire [M_PP+R_PP-S_PP-1:0] quotient_o_Y; // wire done_o_Y; // indicates completion of operation reg [M_PP+R_PP-S_PP-1:0] result_Y; //Instantiation part serial_divide_uu #(.M_PP(M_PP),.N_PP(N_PP), .R_PP(R_PP), .S_PP(S_PP), .COUNT_WIDTH_PP(COUNT_WIDTH_PP) ) serial_divide_uu_unitY ( .clk_i(clock), .clk_en_i(clk_en_i), .rst_i(reset), .divide_i(divide_i), .dividend_i(dividend_i_Y), .divisor_i(divisor_i_Y), .quotient_o(quotient_o_Y), .done_o(done_o_Y) ); // The design treats Initialization and processing as two different phases //------------------------------------------------------------------------- // Initialization Phase Declarations: // // Initialization phase: Gets activated on two input signals (reset and Initialize. // First should be rest : Initialize the Souce array to all zeroes // Second when Initialize command comes. FSM moves one state ahead and initialize the array to all // the required values. // Key point: when done_Init is generated, FSM stays in init_NOP. parameter init_Idle = 4'b0000, init_Initialize = 4'b0001, init_NOP = 4'b0010; reg initialized; reg [3:0] state_I, nextState_I; integer Size = DEPTH; // Processing Phase Declarations: // // Idle phase : wait for process command // : Make sure control comes here after initialization. // // proc_ReadBuf1 : Takes LINE number of cycles to read a line from memory to Read Buffer. // proc_Label : Key part where the comarison and labelling is done // : Update BlobTables // after labelling Each result is updated into WriteBuf as well as FIFO parameter proc_idle = 4'b0011, //proc_ReadBuf1 = 4'b0100, proc_Label0 = 4'b0101, proc_Label1 = 4'b0110, proc_Label2 = 4'b0111, proc_Label3 = 4'b1000, proc_Label4 = 4'b1001, //proc_WriteBuf1 = 4'b1010, proc_Centroid1 = 4'b1011, proc_Centroid2 = 4'b1100, proc_Centroid3 = 4'b1101, proc_Centroid4 = 4'b1110, proc_Phase2 = 4'b1111; reg [ADDRESS_Bits_MAX - 1 : 0]pixImage; reg [ADDRESS_Bits_MAX - 1 : 0] pixImageNext = 0; reg [COLUMNADDRESSMAX_Bits - 1 : 0] pixLine; reg [COLUMNADDRESSMAX_Bits - 1 : 0]pixLineNext = 0; reg [3:0] state_P, nextState_P; reg done_Process = 1'b0; // Get the value 1 when the image processing is complete. // Declaration used for Labelling reg [(LABEL_Bits - 1):0 ] PresentLabel; reg IsMerge = 0; reg [(LABEL_Bits - 1) : 0 ] MergeLabel = 0; reg PresentPixelValue; integer x = 0; reg FirstTime = 1'b1; // Flag for First Pixel (No neighbourhood info) reg FirstLine = 1'b1; // Flag for First Line. No Upper line for reference. integer EmptyBufCount = 0; reg WestValue = 0; reg NorthValue = 0; reg [(LABEL_Bits - 1) : 0 ] WestLabel = 0; reg [(LABEL_Bits - 1) : 0 ] NorthLabel = 0; reg Flag_Update; reg [(LABEL_Bits - 1):0 ] CurPixel; reg tempLabel; reg [ROWADDRESSMAX_Bits - 1 : 0] Addr_x = 0; reg [COLUMNADDRESSMAX_Bits - 1 : 0] Addr_y = 0; reg [ROWADDRESSMAX_Bits - 1 : 0] LineCount = 0; reg [ROWADDRESSMAX_Bits - 1 : 0] LineCountNext = 0; reg [ADDRESS_Bits_MAX - 1 : 0] Addr; // This global variable is used between successive task calls reg [(LABEL_Bits - 1) : 0] CCL = 1; reg [(LABEL_Bits - 1) : 0] CCL_next; parameter LINE_FIFO = 1, WRITE_FIFO = 0, OPERATION_READ = 1, OPERATION_WRITE = 0; reg [(LABEL_Bits - 1) : 0] dummyData = 0; reg [(LABEL_Bits - 1) : 0] tempStore = 0; integer ErrorCode = 0; // //---------------------------------------------------- // FIFO operation TASK //-------------------------------------------------- // Specify which FIFO you want to operate, what operation to perform and the data. // This task set up the control signals and perform operation. task AccessFIFO; input FIFO_Identity, Operation; input [(LABEL_Bits - 1) : 0]Data_Input; output [(LABEL_Bits - 1) : 0]Data_Output; reg [(LABEL_Bits - 1) : 0]tempData; begin // Task Begin // Sample the values available at FIFO and store in registers. empty_rd = empty_rd_fifo; full_rd = full_rd_fifo; if (FIFO_Identity == LINE_FIFO && Operation == OPERATION_READ) begin //(Readfifo read operation) if (empty_rd != 1) begin //if (empty_rd == 1) rd_rd = 1'b1; wr_rd = 1'b0; // Read mode of FIFO. tempData = ReadData_rd_fifo; end else ErrorCode = 1; //(Read FIFO empty) end //(Readfifo read operation) else if (FIFO_Identity == LINE_FIFO && Operation == OPERATION_WRITE) begin //(Readfifo write opearion) if ((full_rd != 1) || ((full_rd == 1) && (rd_rd == 1))) begin // if (full_rd != 1) //rd_rd = 1'b0; wr_rd = 1'b1; // Write mode of FIFO. WriteData_rd = Data_Input; end // if (full_rd != 1) else ErrorCode = 2; // (Read FIFO full) end //(Readfifo write operation) Data_Output = tempData; end // Task End endtask // //----------------------------------------------------- //CONNECTED COMPONENT ALGORITHM TASK //---------------------------------------------------- // Basic algorithm implementation follows // Receives all neighbourhood values and labels. // Returns Update 1 if it is required to update merger table (otherwise 0) // In case of update: // Label to merge should be merged with CurrentLabel in the merge table. // task GetLabel; input WestNeighbourValue, NorthNeighbourValue; input [(LABEL_Bits - 1) : 0] WestLabel; input [(LABEL_Bits - 1) : 0] NorthLabel; output [(LABEL_Bits - 1) : 0] CurrentLabel; output [(LABEL_Bits - 1) : 0] UpdateLabel; reg [(LABEL_Bits - 1) : 0] CurLabel; reg [(LABEL_Bits - 1) : 0] LabelToMerge; begin // Task Begin if (WestNeighbourValue == 1 && NorthNeighbourValue == 0) CurLabel = WestLabel; else if (WestNeighbourValue == 0 && NorthNeighbourValue == 1) CurLabel = NorthLabel; else if (WestNeighbourValue == 1 && NorthNeighbourValue == 1) begin //(WestNeighbourValue == 1 && NorthNeighbourValue == 1) if (NorthLabel < WestLabel) begin Flag_Update = 1; CurLabel = NorthLabel; // always select lower label as the current label LabelToMerge = WestLabel; end else if (NorthLabel > WestLabel) begin Flag_Update = 1; CurLabel = WestLabel; // always select lower label as the current label LabelToMerge = NorthLabel; end else CurLabel = NorthLabel; end //(WestNeighbourValue == 1 && NorthNeighbourValue == 1) else if (WestNeighbourValue == 0 && NorthNeighbourValue == 0) begin CurLabel = CCL; CCL_next = CCL + 1; if (CCL == 7 ) $display (" Number of blobs exceed the capacity\n"); // Hard coded Check/change in future. end else CurLabel = CurLabel; CurrentLabel = CurLabel; UpdateLabel = LabelToMerge; end // Task Begin endtask // Task end // Common Task to be done after labelling each pixel // Hence grouped into task task FinishLabelling; reg [(LABEL_Bits - 1) : 0] MergedLabel; // local variable for this task begin // 1] Got Neighbourhood, Label it and get PresentLabel if (PresentPixelValue == 1) // valid pixel to label begin //if (PresentPixelValue == 1) GetLabel (WestValue,NorthValue, WestLabel,NorthLabel,PresentLabel,MergeLabel); end //if (PresentPixelValue == 1) else PresentLabel = 0; // BLOB TABLE UPDATE Follows //============================ // Note DO MERGING FIRST // Then UPDATE COUNTER // Then Area Merge // 1.a] Update Blob Table Column 0: Label if (Flag_Update) MergeTable[MergeLabel] = MergeTable[PresentLabel]; // 1.b]Update the BlobTable Column 1: Running Counter for Area // Check if you merged two labels. If so increment only one counter. if (PresentLabel != 0) begin //(PresentLabel != 0) MergedLabel = MergeTable[PresentLabel]; AreaTable[MergedLabel] = AreaTable[MergedLabel] + 1; // Got a hit increment the area counter. if (Flag_Update == 1) // There was a merge in this call. Add the area of MergeLabel to that of MergedLabel begin AreaTable[MergedLabel] = AreaTable[MergedLabel] + AreaTable[MergeLabel]; AreaTable[MergeLabel] = 0; // This is needed since we already merged the area and there could be subsequent instance of a merge end end//(PresentLabel != 0) // 1.b]Update the BlobTable Column 3: Running Counter for SigmaXbar // Check if you merged two labels. If so increment only one counter. if (PresentLabel != 0) begin //(PresentLabel != 0) MergedLabel = MergeTable[PresentLabel]; SigmaXBARTable[MergedLabel] = SigmaXBARTable[MergedLabel] + pixLine + 1; // Got a hit increment the area counter. if (Flag_Update == 1) // There was a merge in this call. Add the area of MergeLabel to that of MergedLabel begin SigmaXBARTable[MergedLabel] = SigmaXBARTable[MergedLabel] + SigmaXBARTable[MergeLabel]; SigmaXBARTable[MergeLabel] = 0; // This is needed since we already merged the value and there could be subsequent instance of a merge end end//(PresentLabel != 0) // 1.b]Update the BlobTable Column 4: Running Counter for SigmaYbar // Check if you merged two labels. If so increment only one counter. if (PresentLabel != 0) begin //(PresentLabel != 0) MergedLabel = MergeTable[PresentLabel]; SigmaYBARTable[MergedLabel] = SigmaYBARTable[MergedLabel] + LineCount + 1; // Got a hit increment the area counter. if (Flag_Update == 1) // There was a merge in this call. Add the area of MergeLabel to that of MergedLabel begin SigmaYBARTable[MergedLabel] = SigmaYBARTable[MergedLabel] + SigmaYBARTable[MergeLabel]; SigmaYBARTable[MergeLabel] = 0; // This is needed since we already merged the area and there could be subsequent instance of a merge end end//(PresentLabel != 0) // 2] Copy Present to West for next time usage. WestLabel = PresentLabel; WestValue = PresentPixelValue; // 3] Update the ProcessReg. Process_reg[pixImage] = PresentLabel; // 4] Update the LineFIF0. AccessFIFO (LINE_FIFO, OPERATION_WRITE, PresentLabel, dummyData); end endtask // Latch for divider outputs always @(posedge clock, posedge reset) begin if (reset) begin result_X <= 0; result_Y <= 0; clk_en_i <= 0; end else begin clk_en_i <= 1'b1; result_X <= quotient_o_X[M_PP+R_PP-S_PP-1:1]; result_Y <= quotient_o_Y[M_PP+R_PP-S_PP-1:1]; end end // SEQUENTIAL Present state Next state Logic // -------------------------------------------- always @(posedge clock, posedge reset) begin if (reset) begin state_I <= init_Idle ; state_P <= proc_idle; pixImage <= 0; pixLine <= 0; div_clock_counter <= 0; blobtable_index <= 0; CCL <= 1; end else begin state_I <= nextState_I; state_P <= nextState_P; pixImage <= pixImageNext; pixLine <= pixLineNext; LineCount <= LineCountNext; div_clock_counter <= div_clock_counter_next; blobtable_index <= blobtable_index_next; CCL <= CCL_next; end end // Next State generation Logic for Image Processing //--------------------------------------------------------- always @(negedge clock, ProcessImage) begin//Outermost always Begin rd_rd = 1'b0; //CHECK : @ each clk, FIFO should not do anything wr_rd = 1'b0; // unless you specify what to do Flag_Update = 1'b0; div_clock_counter_next = div_clock_counter; blobtable_index_next = blobtable_index; CCL_next = CCL; if ( ProcessImage && done_Init ) begin //if ( ProcessImage && done_Init ) case (state_P) //----------------------------------------------------------------- proc_idle: begin //proc_idle if (~done_Processing_Phase1) nextState_P = proc_Label1; else if (done_Processing_Phase1 && done_Processing_Phase2 ) begin nextState_P = proc_idle; //$display("=============="); //$display(" ALL DONE"); //$display("=============="); allDone = 1'b1; end end //proc_idle //----------------------------------------------------------------- proc_Label1: // first pixel of the first Line image begin //proc_Label1 if (FirstTime) // first pixel of the first Line image begin //$display("=================================="); //$display("First Pixel:"); //$display("=================================="); PresentPixelValue = Source_reg[pixImage]; pixImageNext = pixImage + 1; pixLineNext = pixLine + 1; WestValue = 0; NorthValue = 0; WestLabel = 0; NorthLabel = 0; FirstTime = 0; // Reset first time FinishLabelling; //$display ("NN label = %d WW label is %d Present label is %d",NorthLabel,WestLabel,PresentLabel); end nextState_P = proc_Label2; end //Proc_Label1 state end //----------------------------------------------------------------- proc_Label2: //~1st pix, first line begin if ( pixLine <= (ROWS - 1) ) //~1st pix, first line begin //$display("=================================="); //$display("FirstLineCase "); //$display("=================================="); PresentPixelValue = Source_reg[pixImage]; pixImageNext = pixImage + 1; pixLineNext = pixLine + 1; //WestValue got from previous run NorthValue = 0; //WestLabel got from previous run NorthLabel = 0; FirstLine = 1; FinishLabelling; //$display ("NN label = %d WN labe is %d Present label is %d",NorthLabel,WestLabel,PresentLabel); if ( pixLine == (COLUMNS - 1)) // last pixel in the line? begin nextState_P = proc_Label3; LineCountNext = LineCount + 1; end end end //----------------------------------------------------------------- proc_Label3: //1st pix, ~first line (second line onwards) begin if ( ( pixLine == 0) && (LineCount != 0)) // starting pixel of rest of the lines begin //$display("=================================="); //$display("Rest of the lines' FirstPixelCase "); //$display("=================================="); PresentPixelValue = Source_reg[pixImage]; pixImageNext = pixImage + 1; pixLineNext = pixLine + 1; WestValue = 0; WestLabel = 0; //North Label got from LineFIFO AccessFIFO (LINE_FIFO, OPERATION_READ, dummyData, NorthLabel); if (NorthLabel) NorthValue = 1; else NorthValue = 0; FinishLabelling; //$display ("NN label = %d WN labe is %d Present label is %d",NorthLabel,WestLabel,PresentLabel); end nextState_P = proc_Label4; end //----------------------------------------------------------------- proc_Label4: // Any middle pixel begin if ( pixLine <= (COLUMNS - 1) ) //Any middle pixel begin //$display("=================================="); //$display("MiddlePixelCase"); //$display("=================================="); PresentPixelValue = Source_reg[pixImage]; pixImageNext = pixImage + 1; pixLineNext = pixLine + 1; // WestValue got from previous run // WestLabel got from previous run //North Label got from ReadFIFO AccessFIFO (LINE_FIFO, OPERATION_READ, dummyData, NorthLabel); if (NorthLabel) NorthValue = 1; else NorthValue = 0; FinishLabelling; //$display ("NN label = %d WN labe is %d Present label is %d",NorthLabel,WestLabel,PresentLabel); if ( pixLine == (COLUMNS - 1)) // last pixel in the line? begin LineCountNext = LineCount + 1; if ( LineCount == (NUMLINES_MAX - 1) ) // we are done with all lines begin //$display ("ALL LINES PROCESSED \n"); LineCountNext = 0; done_Processing_Phase1 = 1'b1; // Done with processing an entire image $display("Processing Pass 1 complete.\n"); $display("Calculating Centroids\n"); print_done_Processing_Phase1 = 1'b1; pixImageNext = 1'b0; nextState_P = proc_Centroid1; end else // if ( LineCount == (NUMLINES_MAX - 1) ) nextState_P = proc_Label3; // continue processing next line end end end //------------------------------------------------------------------------------------------ proc_Centroid1: begin // blobtable_index // curr_index_counter if (AreaTable[blobtable_index]) begin dividend_i_X = SigmaXBARTable[blobtable_index]; divisor_i_X = AreaTable[blobtable_index]; dividend_i_Y = SigmaYBARTable[blobtable_index]; divisor_i_Y = AreaTable[blobtable_index]; divide_i = 1'b1; nextState_P = proc_Centroid2; end else begin blobtable_index_next = blobtable_index + 1; if (blobtable_index == BLOB_LABEL_ID_MAX - 1) begin $display("Centroid calculation done\n"); nextState_P = proc_Phase2; PrintMergeTable; end else begin nextState_P = proc_Centroid1; div_clock_counter_next = 0; end end end //------------------------------------------------------------------------------------------ proc_Centroid2: begin divide_i = 1'b0; nextState_P = proc_Centroid3; end //------------------------------------------------------------------------------------------ proc_Centroid3: begin div_clock_counter_next = div_clock_counter + 1; if (div_clock_counter < DIVIDE_CLOCKS) nextState_P = proc_Centroid3; else nextState_P = proc_Centroid4; end //------------------------------------------------------------------------------------------ proc_Centroid4: begin CenterXTable[blobtable_index] = result_X; CenterYTable[blobtable_index] = result_Y; blobtable_index_next = blobtable_index + 1; if (blobtable_index == BLOB_LABEL_ID_MAX - 1) begin $display("Centroid calculation done\n"); PrintMergeTable; nextState_P = proc_Phase2; end else begin nextState_P = proc_Centroid1; div_clock_counter_next = 0; end end //------------------------------------------------------------------------------------------ proc_Phase2: begin //proc_Phase2: CurPixel = Process_reg[pixImage]; if (CurPixel != MergeTable[CurPixel]) Process_reg[pixImage] = MergeTable[CurPixel]; pixImageNext = pixImage + 1; if (pixImageNext == 0 ) begin done_Processing_Phase2 = 1'b1; // CCL Completed. print_done_Processing_Phase2 = 1'b1; // Blob Detection phase. pixImageNext = 1'b0; nextState_P = proc_idle; // Done with Second phase of blob detection $display("\nProcessing Pass 2 complete.\n"); end end //proc_Phase2: default: nextState_P = proc_idle; endcase end //if ( ProcessImage && done_Init ) end //Outermost always end // Next state generation Logic for Initialization. always @(state_I, Initialize, reset) begin case (state_I) init_Idle: begin if ( Initialize || reset ) nextState_I = init_Initialize; end init_Initialize: begin if (reset) begin //$display("I am in Reset PART initInitialize"); for (i = 0; i < Size; i = i + 1) begin Source_reg[i] = 0; end done_Init = 1'b0; nextState_I = init_Idle; end else if (Initialize) begin //$display("I am in Initialize part Blob Table"); //$display("----------------------------------"); for (i = 0; i < BLOB_LABEL_ID_MAX; i = i + 1) begin MergeTable[i] = i; AreaTable[i] = 0; SigmaXBARTable[i] = 0; SigmaYBARTable[i] = 0; CenterXTable[i] = 0; CenterYTable[i] = 0; end //$display("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); $display("BlobTables AFTER INITIALIZATION"); $display("----------------------------------"); PrintMergeTable; //$display("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); //$display("I am in Initialize part Process Reg \n"); //$display("----------------------------------"); for (i = 0; i < Size; i = i + 1) begin Process_reg[i] = 0; end //$display("I am in Initialize part Source Reg \n"); //$display("----------------------------------"); Source_reg[0] = 0; Source_reg[1] = 0; Source_reg[2] = 0; Source_reg[3] = 0; Source_reg[4] = 0; Source_reg[5] = 0; Source_reg[6] = 0; Source_reg[7] = 0; Source_reg[8] = 0; Source_reg[9] = 1; Source_reg[10] = 1; Source_reg[11] = 1; Source_reg[12] = 0; Source_reg[13] = 1; Source_reg[14] = 1; Source_reg[15] = 0; Source_reg[16] = 0; Source_reg[17] = 0; Source_reg[18] = 1; Source_reg[19] = 1; Source_reg[20] = 0; Source_reg[21] = 0; Source_reg[22] = 1; Source_reg[23] = 0; Source_reg[24] = 0; Source_reg[25] = 0; Source_reg[26] = 0; Source_reg[27] = 1; Source_reg[28] = 0; Source_reg[29] = 0; Source_reg[30] = 1; Source_reg[31] = 0; Source_reg[32] = 0; Source_reg[33] = 0; Source_reg[34] = 1; Source_reg[35] = 1; Source_reg[36] = 0; Source_reg[37] = 0; Source_reg[38] = 1; Source_reg[39] = 0; Source_reg[40] = 0; Source_reg[41] = 0; Source_reg[42] = 1; Source_reg[43] = 1; Source_reg[44] = 0; Source_reg[45] = 0; Source_reg[46] = 1; Source_reg[47] = 0; Source_reg[48] = 0; Source_reg[49] = 1; Source_reg[50] = 1; Source_reg[51] = 1; Source_reg[52] = 1; Source_reg[53] = 1; Source_reg[54] = 1; Source_reg[55] = 0; Source_reg[56] = 0; Source_reg[57] = 0; Source_reg[58] = 0; Source_reg[59] = 0; Source_reg[60] = 0; Source_reg[61] = 0; Source_reg[62] = 0; Source_reg[63] = 0; done_Init = 1'b1; // Done Initialization. Set bit done_Init; print_done_Init = 1'b1; // Just for printing purpose nextState_I = init_NOP ; end end init_NOP : nextState_I = init_NOP; // Done with Initialization. Initialization parts stays in idle loop. endcase end //------------------------------------------------ // Generate Signals for Testing //------------------------------------------------- initial begin clock = 1'b0; forever #10 clock = ~clock; end initial begin reset = 1'b1; clk_en_i = 1'b0; divide_i = 1'b0; Initialize = 1'b0; #20 reset = 1'b0; end initial begin # 100 Initialize = 1'b1; # 40 Initialize = 1'b0; end always @(posedge clock) begin if (print_done_Init) begin $display("Initialized Source Array\n"); $display("============================="); k = 0; for (i = 0; i < ROWS; i = i + 1) begin for (j = 0; j < COLUMNS; j = j + 1) begin $write ("%d ",Source_reg[k]); k = k + 1; end $write("\n"); end print_done_Init = 1'b0; // Need to print only one time. //$display($time ," DONE PRINTING THE INITIALIZED ARRAY \n"); $display("========================================"); ProcessImage = 1'b1; /////////////////////////////////// Done Init START PROCESSING $display("\n\n"); $display("Initialization Complete. Start Processing Pass 1\n"); end end always @(posedge clock) begin if (print_done_Processing_Phase1) begin $display("The Intermediate labelled ARRAY after Pass 1\n"); $display("=============================================="); k = 0; for (i = 0; i < ROWS; i = i + 1) begin for (j = 0; j < COLUMNS; j = j + 1) begin $write ("%d ",Process_reg[k]); k = k + 1; end $write("\n"); end $display("\n"); print_done_Processing_Phase1 = 1'b0; $display("BlobTables AFTER Pass 1"); $display("----------------------------------"); PrintMergeTable; end end always @(posedge clock) begin if (print_done_Processing_Phase2) begin $display("Final Labeled array after Pass 2"); $display("================================="); k = 0; for (i = 0; i < ROWS; i = i + 1) begin for (j = 0; j < COLUMNS; j = j + 1) begin $write ("%d ",Process_reg[k]); k = k + 1; end $write("\n"); end $display("\n"); print_done_Processing_Phase2 = 1'b0; end end //****************************************** // ERROR CODES // 1. Read FIFO Empty // 2. Read FIFO full // 3. Write fifo Empty // 4. Write fifo Full endmodule //////////////////////////////////////////////////////////////////////// // // Serial Divider Module // //////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- // serial_divide_uu.v -- Serial division module // // // Description: See description below (which suffices for IP core // specification document.) // // Copyright (C) 2002 John Clayton and OPENCORES.ORG (this Verilog version) // // This source file may be used and distributed without restriction provided // that this copyright statement is not removed from the file and that any // derivative work contains the original copyright notice and the associated // disclaimer. // // This source file is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This source is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public // License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this source. // If not, download it from http://www.opencores.org/lgpl.shtml // //----------------------------------------------------------------------------- // // Author: John Clayton // Date : Jan. 30, 2003 // Update: Jan. 30, 2003 Copied this file from "vga_crosshair.v" // Stripped out extraneous stuff. // Update: Mar. 14, 2003 Added S_PP parameter, made some simple changes to // implement quotient leading zero "skip" feature. // Update: Mar. 24, 2003 Updated comments to improve readability. // //----------------------------------------------------------------------------- // Description: // // This module performs a division operation serially, producing one bit of the // answer per clock cycle. The dividend and the divisor are both taken to be // unsigned quantities. The divider is conceived as an integer divider (as // opposed to a divider for fractional quantities) but the user can configure // the divider to divide fractional quantities as long as the position of the // binary point is carefully monitored. // // The widths of the signals are configurable by parameters, as follows: // // M_PP = Bit width of the dividend // N_PP = Bit width of the divisor // R_PP = Remainder bits desired // S_PP = Skipped quotient bits // // The skipped quotient bits parameter provides a way to prevent the divider // from calculating the full M_PP+R_PP output bits, in case some of the leading // bits are already known to be zero. This is the case, for example, when // dividing two quantities to obtain a result that is a fraction between 0 and 1 // (as when measuring PWM signals). In that case the integer portion of the // quotient is always zero, and therefore it need not be calculated. // // The divide operation is begun by providing a pulse on the divide_i input. // The quotient is provided (M_PP+R_PP-S_PP) clock cycles later. // The divide_i pulse stores the input parameters in registers, so they do // not need to be maintained at the inputs throughout the operation of the module. // If a divide_i pulse is given to the serial_divide_uu module during the time // when it is already working on a previous divide operation, it will abort the // operation it was doing, and begin working on the new one. // // The user is responsible for treating the results correctly. The position // of the binary point is not given, but it is understood that the integer part // of the result is the M_PP most significant bits of the quotient output. // The remaining R_PP least significant bits are the fractional part. // // This is illustrated graphically: // // [ M_PP bits ][ R_PP bits] // [ S_PP bits ][quotient_o] // // The quotient will consist of whatever bits are left after removing the S_PP // most significant bits from the (M_PP+R_PP) result bits. // // Attempting to divide by zero will simply produce a result of all ones. // This core is so simple, that no checking for this condition is provided. // If the user is concerned about a possible divide by zero condition, he should // compare the divisor to zero and flag that condition himself! // // The COUNT_WIDTH_PP parameter must be sized so that 2^COUNT_WIDTH_PP-1 is >= // M_PP+R_PP-S_PP-1. The unit terminates the divide operation when the count // is equal to M_PP+R_PP-S_PP-1. // // The HELD_OUTPUT_PP parameter causes the unit to keep its output result in // a register other than the one which it uses to compute the quotient. This // is useful for applications where the divider is used repeatedly and the // previous divide result (quotient) must be stable during the computation of the // next divide result. Using the additional output register does incur some // additional utilization of resources. // //----------------------------------------------------------------------------- module serial_divide_uu ( clk_i, clk_en_i, rst_i, divide_i, dividend_i, divisor_i, quotient_o, done_o ); parameter M_PP = 16; // Size of dividend parameter N_PP = 8; // Size of divisor parameter R_PP = 0; // Size of remainder parameter S_PP = 0; // Skip this many bits (known leading zeros) parameter COUNT_WIDTH_PP = 5; // 2^COUNT_WIDTH_PP-1 >= (M_PP+R_PP-S_PP-1) parameter HELD_OUTPUT_PP = 0; // Set to 1 if stable output should be held // from previous operation, during current // operation. Using this option will increase // the resource utilization (costs extra // d-flip-flops.) // I/O declarations input clk_i; // input clk_en_i; input rst_i; // synchronous reset input divide_i; // starts division operation input [M_PP-1:0] dividend_i; // input [N_PP-1:0] divisor_i; // output [M_PP+R_PP-S_PP-1:0] quotient_o; // output done_o; // indicates completion of operation //reg [M_PP+R_PP-1:0] quotient_o; reg done_o; // Internal signal declarations reg [M_PP+R_PP-1:0] grand_dividend; reg [M_PP+N_PP+R_PP-2:0] grand_divisor; reg [M_PP+R_PP-S_PP-1:0] quotient; reg [M_PP+R_PP-1:0] quotient_reg; // Used exclusively for the held output reg [COUNT_WIDTH_PP-1:0] divide_count; wire [M_PP+N_PP+R_PP-1:0] subtract_node; // Subtract node has extra "sign" bit wire [M_PP+R_PP-1:0] quotient_node; // Shifted version of quotient wire [M_PP+N_PP+R_PP-2:0] divisor_node; // Shifted version of grand divisor // Serial dividing module always @(posedge clk_i) begin if (rst_i) begin grand_dividend <= 0; grand_divisor <= 0; divide_count <= 0; quotient <= 0; done_o <= 0; end else if (clk_en_i) begin done_o <= 0; if (divide_i) // Start a new division begin quotient <= 0; divide_count <= 0; // dividend placed initially so that remainder bits are zero... grand_dividend <= dividend_i << R_PP; // divisor placed initially for a 1 bit overlap with dividend... // But adjust it back by S_PP, to account for bits that are known // to be leading zeros in the quotient. grand_divisor <= divisor_i << (N_PP+R_PP-S_PP-1); end else if (divide_count == M_PP+R_PP-S_PP-1) begin if (~done_o) quotient <= quotient_node; // final shift... if (~done_o) quotient_reg <= quotient_node; // final shift (held output) done_o <= 1; // Indicate done, just sit end else // Division in progress begin // If the subtraction yields a positive result, then store that result if (~subtract_node[M_PP+N_PP+R_PP-1]) grand_dividend <= subtract_node; // If the subtraction yields a positive result, then a 1 bit goes into // the quotient, via a shift register quotient <= quotient_node; // shift the grand divisor to the right, to cut it in half next clock cycle grand_divisor <= divisor_node; // Advance the counter divide_count <= divide_count + 1; end end // End of else if clk_en_i end // End of always block assign subtract_node = {1'b0,grand_dividend} - {1'b0,grand_divisor}; assign quotient_node = {quotient[M_PP+R_PP-S_PP-2:0],~subtract_node[M_PP+N_PP+R_PP-1]}; assign divisor_node = {1'b0,grand_divisor[M_PP+N_PP+R_PP-2:1]}; assign quotient_o = (HELD_OUTPUT_PP == 0)?quotient:quotient_reg; endmodule Listing 11 //////////////////////////////////////////////////////////////////////// // // Hexa decimal Interface Module // //////////////////////////////////////////////////////////////////////// module disp_hex_mux( input wire clk, reset, input wire [3:0] hex3, hex2, hex1, hex0, input wire [3:0] dp_in, output reg [3:0] an, output reg [7:0] sseg ); localparam N = 18; reg [N-1:0] q_reg; wire [N-1:0] q_next; reg [3:0] hex_in; reg dp; // N-bit counter //register always @(posedge clk, posedge reset) begin if (reset) q_reg <= 0; else q_reg <= q_next; end assign q_next = q_reg + 1; // 2 MSBs of hte counter to control the 4 to 1 multiplexing and to generate // the active low enable signal always @* case (q_reg[N-1:N-2]) 2'b00: begin an = 4'b1110; hex_in = hex0; dp = dp_in[0]; end 2'b01: begin an = 4'b1101; hex_in = hex1; dp = dp_in[1]; end 2'b10: begin an = 4'b1011; hex_in = hex2; dp = dp_in[2]; end default: begin an = 4'b0111; hex_in = hex3; dp = dp_in[3]; end endcase always @* begin case (hex_in) 4'h0: sseg[6:0] = 7'b0000001; 4'h1: sseg[6:0] = 7'b1001111; 4'h2: sseg[6:0] = 7'b0010010; 4'h3: sseg[6:0] = 7'b0000110; 4'h4: sseg[6:0] = 7'b1001100; 4'h5: sseg[6:0] = 7'b0100100; 4'h6: sseg[6:0] = 7'b0100000; 4'h7: sseg[6:0] = 7'b0001111; 4'h8: sseg[6:0] = 7'b0000000; 4'h9: sseg[6:0] = 7'b0000100; 4'ha: sseg[6:0] = 7'b0001000; 4'hb: sseg[6:0] = 7'b1100000; 4'hc: sseg[6:0] = 7'b0110001; 4'hd: sseg[6:0] = 7'b1000010; 4'he: sseg[6:0] = 7'b0110000; default: sseg[6:0] = 7'b0111000; endcase sseg[7] = dp; end endmodule Listing 12 #--------------------------------------------------------------------------- # User constraints file for VGA Interface with SRAM as video Memory #--------------------------------------------------------------------------- NET "clk" LOC = "T9" ; NET "reset" LOC = "L14" ; # RESET BUTTON NET "btn1" LOC = "M13" ; # BTN 0 #NET "switch<0>" LOC = "F12" ; # switch 0 #NET "switch<1>" LOC = "G12" ; # switch 1 #NET "switch<2>" LOC = "H14" ; # switch 2 #NET "switch<3>" LOC = "H13" ; # switch 3 #NET "switch<4>" LOC = "J14" ; # switch 4 #NET "switch<5>" LOC = "J13" ; # switch 5 #NET "switch<6>" LOC = "K14" ; # switch 6 #NET "switch<7>" LOC = "K13" ; # switch 7 NET "TransferCompleteLED" LOC = "K12" ; # LED 0 //NET "DebugLED" LOC = "P14" ; # LED 1 #NET "LED<0>" LOC = "P14" ; # LED 1 #NET "LED<1>" LOC = "L12" ; # LED 2 #NET "LED<2>" LOC = "N14" ; # LED 3 #NET "LED<3>" LOC = "P13" ; # LED 4 #NET "LED<4>" LOC = "N12" ; # LED 5 #NET "LED<5>" LOC = "P12" ; # LED 6 #NET "LED<6>" LOC = "P11" ; # LED 7 NET "an<0>" LOC = "D14" ; # hex enable 0 NET "an<1>" LOC = "G14" ; # hex enable 1 NET "an<2>" LOC = "F14" ; # hex enable 2 NET "an<3>" LOC = "E13" ; # hex enable 3 NET "sseg<7>" LOC = "P16" ; # sseg - dp NET "sseg<6>" LOC = "E14" ; # sseg - a NET "sseg<5>" LOC = "G13" ; # sseg - b NET "sseg<4>" LOC = "N15" ; # sseg - c NET "sseg<3>" LOC = "P15" ; # sseg - d NET "sseg<2>" LOC = "R16" ; # sseg - e NET "sseg<1>" LOC = "F13" ; # sseg - f NET "sseg<0>" LOC = "N16" ; # sseg - g NET "ad<0>" LOC = "L5" ; # sram addr 0 NET "ad<1>" LOC = "N3" ; # sram addr 1 NET "ad<2>" LOC = "M4" ; # sram addr 2 NET "ad<3>" LOC = "M3" ; # sram addr 3 NET "ad<4>" LOC = "L4" ; # sram addr 4 NET "ad<5>" LOC = "G4" ; # sram addr 5 NET "ad<6>" LOC = "F3" ; # sram addr 6 NET "ad<7>" LOC = "F4" ; # sram addr 7 NET "ad<8>" LOC = "E3" ; # sram addr 8 NET "ad<9>" LOC = "E4" ; # sram addr 9 NET "ad<10>" LOC = "G5" ; # sram addr 10 NET "ad<11>" LOC = "H3" ; # sram addr 11 NET "ad<12>" LOC = "H4" ; # sram addr 12 NET "ad<13>" LOC = "J4" ; # sram addr 13 NET "ad<14>" LOC = "J3" ; # sram addr 14 NET "ad<15>" LOC = "K3" ; # sram addr 15 NET "ad<16>" LOC = "K5" ; # sram addr 16 NET "ad<17>" LOC = "L3" ; # sram addr 17 NET "dio_a<0>" LOC = "N7" ; # sram data 0 NET "dio_a<1>" LOC = "T8" ; # sram data 1 NET "dio_a<2>" LOC = "R6" ; # sram data 2 NET "dio_a<3>" LOC = "T5" ; # sram data 3 NET "dio_a<4>" LOC = "R5" ; # sram data 4 NET "dio_a<5>" LOC = "C2" ; # sram data 5 NET "dio_a<6>" LOC = "C1" ; # sram data 6 NET "dio_a<7>" LOC = "B1" ; # sram data 7 NET "dio_a<8>" LOC = "D3" ; # sram data 8 NET "dio_a<9>" LOC = "P8" ; # sram data 9 NET "dio_a<10>" LOC = "F2" ; # sram data 10 NET "dio_a<11>" LOC = "H1" ; # sram data 11 NET "dio_a<12>" LOC = "J2" ; # sram data 12 NET "dio_a<13>" LOC = "L2" ; # sram data 13 NET "dio_a<14>" LOC = "P1" ; # sram data 14 NET "dio_a<15>" LOC = "R1" ; # sram data 15 NET "ce_a_n" LOC = "P7" ; # sram NET "ub_a_n" LOC = "T4" ; # sram NET "lb_a_n" LOC = "P6" ; # sram NET "oe_n" LOC = "k4" ; # sram NET "we_n" LOC = "G3" ; # sram #NET "rgb<0>" LOC = "R11" ; # Blue VGA Port #NET "rgb<1>" LOC = "T12" ; # Green VGA Port #NET "rgb<2>" LOC = "R12" ; # Red VGA Port # #NET "hsync" LOC = "R9" ; # Hsynch of VGA port #NET "vsync" LOC = "T10" ; # Vsynch of VGA port NET "hsync" LOC = "K15" | DRIVE = 8 | SLEW = FAST; # Hsync of VGA port NET "vsync" LOC = "J16" | DRIVE = 8 | SLEW = FAST; # Vsync of VGA port NET "rgb<15>" LOC = "T3" | DRIVE = 8 | SLEW = FAST; # fpga_ pin NET "rgb<14>" LOC = "N11" | DRIVE = 8 | SLEW = FAST; # sram addr 1 NET "rgb<13>" LOC = "P10" | DRIVE = 8 | SLEW = FAST; # sram addr 2 NET "rgb<12>" LOC = "R10" | DRIVE = 8 | SLEW = FAST; # sram addr 3 NET "rgb<11>" LOC = "T7" | DRIVE = 8 | SLEW = FAST; # sram addr 4 NET "rgb<10>" LOC = "R7" | DRIVE = 8 | SLEW = FAST; # sram addr 5 NET "rgb<9>" LOC = "N6" | DRIVE = 8 | SLEW = FAST; # sram addr 6 NET "rgb<8>" LOC = "M6" | DRIVE = 8 | SLEW = FAST; # sram addr 7 NET "rgb<7>" LOC = "C15" | DRIVE = 8 | SLEW = FAST; # sram addr 8 NET "rgb<6>" LOC = "D15" | DRIVE = 8 | SLEW = FAST; # sram addr 9 NET "rgb<5>" LOC = "E15" | DRIVE = 8 | SLEW = FAST; # sram addr 10 NET "rgb<4>" LOC = "F15" | DRIVE = 8 | SLEW = FAST; # sram addr 11 NET "rgb<3>" LOC = "G16" | DRIVE = 8 | SLEW = FAST; # sram addr 12 NET "rgb<2>" LOC = "H16" | DRIVE = 8 | SLEW = FAST; # sram addr 13 NET "rgb<1>" LOC = "K16" | DRIVE = 8 | SLEW = FAST; # sram addr 14 NET "rgb<0>" LOC = "L15" | DRIVE = 8 | SLEW = FAST; # sram addr 15 #---------------------------------------------------------------------------------------