dakies/OSS_Verilog huggingface dataset:
module pll1 (
	inclk0,
	reset,
	c0,
	c1,
	c2,
	c3,
	c4,
	ext_lock
	);

input inclk0,reset;
output ext_lock;
output c0;
output c1;
output c2;
output c3;
output c4;


wire [4:0] clkc;
wire [2:0] dummy;

    EG_LOGIC_BUFG  pll_c0(.o(c0),.i(clkc[0]));
    EG_LOGIC_BUFG  pll_c1(.o(c1),.i(clkc[1]));
    EG_LOGIC_BUFG  pll_c2(.o(c2),.i(clkc[2]));
    EG_LOGIC_BUFG  pll_c3(.o(c3),.i(clkc[3]));
    EG_LOGIC_BUFG  pll_c4(.o(c4),.i(clkc[4]));

//assign c0 = clkc[0] ;
//assign c1 = clkc[1] ;
//assign c2 = clkc[2] ;
//assign c3 = clkc[3] ;
//assign c4 = clkc[4] ;

EG_PHY_PLL  pll_clk (.refclk(inclk0),
                     .reset(reset),
			    .stdby(1'b0),
                     .clkc(clkc),
                     .extlock(ext_lock)

				);  
defparam pll_clk.FBCLK_DIV = 45;  //input 50M, vco = 1000M
defparam pll_clk.CLKC0_DIV = 8;   //c0 = 133M
defparam pll_clk.CLKC1_DIV = 8;    //c1 = 125M
defparam pll_clk.CLKC2_DIV = 8;    //c2 = 125M
defparam pll_clk.CLKC3_DIV = 8;    //c3 = C0
defparam pll_clk.CLKC4_DIV = 8;    //c4 = 125M    300M�����漸��û������

defparam pll_clk.CLKC0_ENABLE = "ENABLE";   //  ENABLE/DISABLE/SIGNAL
defparam pll_clk.CLKC1_ENABLE = "ENABLE";   //  ENABLE/DISABLE/SIGNAL
defparam pll_clk.CLKC2_ENABLE = "DISABLE";   // ENABLE/DISABLE/SIGNAL
defparam pll_clk.CLKC3_ENABLE = "DISABLE";  //  ENABLE/DISABLE/SIGNAL
defparam pll_clk.CLKC4_ENABLE = "DISABLE";  //  ENABLE/DISABLE/SIGNAL

//corse 
defparam pll_clk.CLKC0_CPHASE = 6;    //  1-127  ,CLKC0_CPHASE < CLKC0_DIV
defparam pll_clk.CLKC1_CPHASE = 0;     //  1-127  ,CLKC1_CPHASE < CLKC1_DIV
defparam pll_clk.CLKC2_CPHASE = 4;     //  1-127  ,CLKC2_CPHASE < CLKC2_DIV
defparam pll_clk.CLKC3_CPHASE = 2;     //  1-127  ,CLKC3_CPHASE < CLKC3_DIV
defparam pll_clk.CLKC4_CPHASE = 0;     //  1-127  ,CLKC4_CPHASE < CLKC4_DIV

//fast
defparam pll0_clk.CLKC0_FPHASE   = "5";    //  0-7
defparam pll0_clk.CLKC1_FPHASE   = "0";    //  0-7
defparam pll0_clk.CLKC2_FPHASE   = "7";    //  0-7
defparam pll0_clk.CLKC3_FPHASE   = "7";    //  0-7
defparam pll0_clk.CLKC4_FPHASE   = "0";    //  0-7

endmodule
module sdr_data_path(CLK, RESET_N, OE, DATAIN, DATAOUT, DQIN, DQOUT);
   
   parameter          DSIZE = 32;
   
   input              CLK;
   input              RESET_N;
   input              OE;
   input [DSIZE-1:0]  DATAIN;
   output [DSIZE-1:0] DATAOUT;
   input [DSIZE-1:0]  DQIN;
   output [DSIZE-1:0] DQOUT;
   
   
   reg [DSIZE-1:0]    DIN1;
   reg [DSIZE-1:0]    DIN2;
   
   
   always @(posedge CLK or negedge RESET_N)
      if (RESET_N == 1'b0)
      begin
         DIN1 <= {DSIZE{1'b0}};
         DIN2 <= {DSIZE{1'b0}};
      end
      else 
      begin
         DIN1 <= DATAIN;
         DIN2 <= DIN1;
      end
   
   assign DATAOUT = DQIN;
   assign DQOUT = DIN2;
   
endmodule
module ip_pll  // al_ip/ip_pll.v(24)
  (
  refclk,
  clk0_out,
  clk1_out,
  clk2_out
  );

  input refclk;  // al_ip/ip_pll.v(29)
  output clk0_out;  // al_ip/ip_pll.v(30)
  output clk1_out;  // al_ip/ip_pll.v(31)
  output clk2_out;  // al_ip/ip_pll.v(32)

  wire clk0_buf;  // al_ip/ip_pll.v(34)

  EG_PHY_GCLK bufg_feedback (
    .clki(clk0_buf),
    .clko(clk0_out));  // al_ip/ip_pll.v(36)
  EG_PHY_CONFIG #(
    .DONE_PERSISTN("ENABLE"),
    .INIT_PERSISTN("ENABLE"),
    .JTAG_PERSISTN("DISABLE"),
    .PROGRAMN_PERSISTN("DISABLE"))
    config_inst ();
  EG_PHY_PLL #(
    .CLKC0_CPHASE(14),
    .CLKC0_DIV(15),
    .CLKC0_DIV2_ENABLE("DISABLE"),
    .CLKC0_ENABLE("ENABLE"),
    .CLKC0_FPHASE(0),
    .CLKC1_CPHASE(124),
    .CLKC1_DIV(125),
    .CLKC1_DIV2_ENABLE("DISABLE"),
    .CLKC1_ENABLE("ENABLE"),
    .CLKC1_FPHASE(0),
    .CLKC2_CPHASE(93),
    .CLKC2_DIV(94),
    .CLKC2_DIV2_ENABLE("DISABLE"),
    .CLKC2_ENABLE("ENABLE"),
    .CLKC2_FPHASE(0),
    .CLKC3_CPHASE(1),
    .CLKC3_DIV(1),
    .CLKC3_DIV2_ENABLE("DISABLE"),
    .CLKC3_ENABLE("DISABLE"),
    .CLKC3_FPHASE(0),
    .CLKC4_CPHASE(1),
    .CLKC4_DIV(1),
    .CLKC4_DIV2_ENABLE("DISABLE"),
    .CLKC4_ENABLE("DISABLE"),
    .CLKC4_FPHASE(0),
    .DERIVE_PLL_CLOCKS("DISABLE"),
    .DPHASE_SOURCE("DISABLE"),
    .DYNCFG("DISABLE"),
    .FBCLK_DIV(17),
    .FEEDBK_MODE("NORMAL"),
    .FEEDBK_PATH("CLKC0_EXT"),
    .FIN("24.000"),
    .FREQ_LOCK_ACCURACY(2),
    .GEN_BASIC_CLOCK("DISABLE"),
    .GMC_GAIN(6),
    .GMC_TEST(14),
    .ICP_CURRENT(3),
    .IF_ESCLKSTSW("DISABLE"),
    .INTFB_WAKE("DISABLE"),
    .KVCO(6),
    .LPF_CAPACITOR(3),
    .LPF_RESISTOR(2),
    .NORESET("DISABLE"),
    .ODIV_MUXC0("DIV"),
    .ODIV_MUXC1("DIV"),
    .ODIV_MUXC2("DIV"),
    .ODIV_MUXC3("DIV"),
    .ODIV_MUXC4("DIV"),
    .PLLC2RST_ENA("DISABLE"),
    .PLLC34RST_ENA("DISABLE"),
    .PLLMRST_ENA("DISABLE"),
    .PLLRST_ENA("DISABLE"),
    .PLL_LOCK_MODE(0),
    .PREDIV_MUXC0("VCO"),
    .PREDIV_MUXC1("VCO"),
    .PREDIV_MUXC2("VCO"),
    .PREDIV_MUXC3("VCO"),
    .PREDIV_MUXC4("VCO"),
    .REFCLK_DIV(16),
    .REFCLK_SEL("INTERNAL"),
    .STDBY_ENABLE("DISABLE"),
    .STDBY_VCO_ENA("DISABLE"),
    .SYNC_ENABLE("DISABLE"),
    .VCO_NORESET("DISABLE"))
    pll_inst (
    .daddr(6'b000000),
    .dclk(1'b0),
    .dcs(1'b0),
    .di(8'b00000000),
    .dwe(1'b0),
    .fbclk(clk0_out),
    .psclk(1'b0),
    .psclksel(3'b000),
    .psdown(1'b0),
    .psstep(1'b0),
    .refclk(refclk),
    .reset(1'b0),
    .stdby(1'b0),
    .clkc({open_n47,open_n48,clk2_out,clk1_out,clk0_buf}));  // al_ip/ip_pll.v(67)

endmodule
module camera_reader
(
	input 	wire 		clk,
	input 	wire 		reset_n,
	
	output 	wire 		csi_xclk,
	
	input 	wire 		csi_pclk,
	input 	wire [7:0] 	csi_data,
	input 	wire 		csi_vsync,
	input 	wire 		csi_hsync,
	
	output 	reg  [15:0] data_out = 0,
	output 	wire 		wrreq,
	output 	wire 		wrclk,
	output 	reg  [19:0]	wraddr
);

reg [19:0] pixel_counter = 0;
assign csi_xclk  = (reset_n == 1) ? clk : 0;
reg vsync_passed = 0;
reg write_pixel  = 0;
reg [7:0] 	subpixel;
reg [15:0] 	current_pixel;
reg wrclk1 = 0;

always@(posedge csi_pclk)
begin
	wrclk1 <= ~wrclk1;
end

always@(negedge wrclk1)
begin
	if(csi_hsync == 1)
		write_pixel <= 1;
	else
		write_pixel <= 0;
end

always@(posedge wrreq )
begin
	data_out <= current_pixel;
end

always@(posedge csi_pclk or negedge reset_n)
begin
	if(reset_n == 0)
	begin
		pixel_counter <= 0;
		vsync_passed <= 0;
	end
	else
	begin
		if(csi_vsync == 1)
		begin
			pixel_counter <= 0;
			vsync_passed <= 1;
			wraddr <= 0;
		end
		else
			if(csi_hsync == 1 && vsync_passed == 1)
			begin
				if(pixel_counter[0] == 0)
				begin
					pixel_counter <= pixel_counter + 1;
					subpixel <= csi_data;
				end
				else
				begin
					//current_pixel <= { subpixel, csi_data };
					current_pixel <= { csi_data , subpixel };
					pixel_counter <= pixel_counter + 1;
					wraddr <= wraddr + 1;
				end
			end
			else
			begin
				if(write_pixel == 1)
					pixel_counter <= pixel_counter + 1;
				else
					pixel_counter <= 0;
			end
	end
end

assign wrreq = (write_pixel == 1) && pixel_counter > 2 ? wrclk1 : 0;
assign wrclk = ~csi_pclk;//~csi_pclk;

endmodule
module test_camera
(
	input 	wire 		clk_24m,	//系统时钟
	input 	wire 		rst_n,		//复位
	//camera	
	input 	wire 		cam_pclk,	//像素时钟
	output 	wire 		cam_xclk,	//系统时钟
	input 	wire 		cam_href,	//行同
	input 	wire 		cam_vsync,	//帧同
	output 	wire 		cam_pwdn,	//模式
	output 	wire 		cam_rst,	//复位
	output 	wire 		cam_soic,	//SCCB
	inout 	wire 		cam_soid,	//SCCB
	input 	wire [7:0]	cam_data,	//
	//vga
	output 	wire [7:0] 	vga_r,
	output 	wire [7:0] 	vga_g,
	output 	wire [7:0] 	vga_b,
	output 	wire 		vga_clk,
	output 	wire 		vga_hsync,
	output 	wire 		vga_vsync

 );
	 
wire 		clk_lcd;
wire 		clk_cam;
wire 		clk_sccb;

wire        camera_wrreq;
wire        camera_wclk;
wire [15:0] camera_wrdat;
wire [19:0] camera_addr;

reg 		init_state;
wire 		init_ready;
wire 		sda_oe;
wire 		sda;
wire 		sda_in;
wire 		scl;

//lcd display
wire [10:0] hsync_cnt;
wire [10:0] vsync_cnt;
wire 		vga_rden;
wire [15:0]	vga_rddat;	//lcd read
wire [15:0]	vga_rdaddr;

assign cam_soid = (sda_oe == 1'b1) ? sda : 1'bz;
assign sda_in 	= cam_soid;
assign cam_soic = scl;
assign cam_pwdn = 1'b0;
assign cam_rst 	= rst_n;

//vga rgb565 mode

assign vga_r[7:0] 	= vga_rden ? { vga_rddat[15:11] , vga_rddat[13:11] } : 8'h0;
assign vga_g[7:0] 	= vga_rden ? { vga_rddat[10:5] , vga_rddat[6:5] }  : 8'h0;
assign vga_b[7:0] 	= vga_rden ? { vga_rddat[4:0] , vga_rddat[2:0]}   : 8'h0;




wire vga_den;
wire vga_pwm;	//backlight,set to high
ip_pll u_pll(
	.refclk(clk_24m),		//24M
	.clk0_out(clk_lcd),		//25M,VGA clk
	.clk1_out(clk_cam),		//12m,for cam xclk
	.clk2_out(clk_sccb)		//4m,for sccb init
);

camera_init u_camera_init
(
	.clk(clk_sccb),
	.reset_n(rst_n),
	.ready(init_ready),
	.sda_oe(sda_oe),
	.sda(sda),
	.sda_in(sda_in),
	.scl(scl)
);
	
lcd_sync 
#(
	.IMG_W		(200		),
	.IMG_H		(164		),
	.IMG_X		(0			),
	.IMG_Y		(1			)
)
u_vga_sync
(
	.clk		(clk_lcd	),
	.rest_n		(rst_n		),
	.lcd_clk	(vga_clk	),
	.lcd_pwm	(vga_pwm	),
	.lcd_hsync	(vga_hsync	), 
	.lcd_vsync	(vga_vsync	), 
	.lcd_de		(vga_den	),
	.hsync_cnt	(hsync_cnt	),
	.vsync_cnt	(vsync_cnt	),
	.img_ack	(vga_rden	),
	.addr		(vga_rdaddr	)
);

camera_reader u_camera_reader
(
	.clk		(clk_cam		),
	.reset_n	(rst_n			),
	.csi_xclk	(cam_xclk		),
	.csi_pclk	(cam_pclk		),
	.csi_data	(cam_data		),
	.csi_vsync	(!cam_vsync		),
	.csi_hsync	(cam_href		),
	.data_out	(camera_wrdat	),
	.wrreq		(camera_wrreq	),
	.wrclk		(camera_wclk	),
	.wraddr		(camera_addr	)
);

img_cache u_img  
( 
	//write 45000*8
	.dia		(camera_wrdat	), 
	.addra		(camera_addr[15:0]	), 
	.cea		(camera_wrreq	), 
	.clka		(camera_wclk	), 
//	.rsta		(!rst_n			), 
	//read 22500*16
	.dob		(vga_rddat		), 
	.addrb		(vga_rdaddr		), 
	.ceb		(vga_rden		),
	.clkb		(clk_lcd		), 
	.rstb		(!rst_n			)
);
	
endmodule
module lcd_sync
#(
 	//display image at pos
	parameter IMG_W = 200,  //图片行像素点个数
	parameter IMG_H = 164,  //图片场像素点个数
	parameter IMG_X = 0,
	parameter IMG_Y = 0
)
(
	input 	wire 		clk,
	input 	wire 		rest_n,
	output 	wire 		lcd_clk,
	output 	wire 		lcd_pwm,
	output 	wire 		lcd_hsync, 
	output 	wire 		lcd_vsync, 
	output 	wire 		lcd_de,
	output 	wire [10:0] hsync_cnt,
	output 	wire [10:0] vsync_cnt,
	output 	wire 		img_ack,
	output 	wire [15:0]	addr
	);
	
//640*480
localparam VGA_H = 640;  
localparam VGA_V = 480; 

localparam THB 	 = 160;
localparam TH 	 = VGA_H + THB;

localparam TVB   = 45;
localparam TV    = VGA_V + TVB;

reg [10:0] counter_hs;
reg [10:0] counter_vs;

reg [15:0] read_addr;             //读图片数据rom地址   

reg [10:0] img_hbegin = 0;   //图片左上角第一个像素点在VGA的行向坐标
reg [10:0] img_vbegin = 0;   //图片左上角第一个像素点在VGA的场向坐标

always@(posedge clk or negedge rest_n)
begin
	if(rest_n == 1'b0)
		counter_hs <= 0;
	else if(counter_hs == TH )
		counter_hs <= 0;
	else
		counter_hs <= counter_hs + 1;
end

always@(posedge clk or negedge rest_n)
begin
	if(rest_n == 1'b0)
		counter_vs <= 0;
	else if(counter_hs == TH && counter_vs == TV)				
		counter_vs <= 0;
	else if(counter_hs == TH && counter_vs != TV)
		counter_vs <= counter_vs + 1;
end

assign lcd_clk   = (rest_n == 1) ? clk  : 1'b0;
assign lcd_pwm   = (rest_n == 1) ? 1'b1 : 1'b0;
assign lcd_hsync = ( counter_hs >= 16 && counter_hs < 112 ) ? 1 : 0;
assign lcd_vsync = ( counter_vs >= 10 && counter_vs < 12 ) ? 1 : 0;
assign lcd_de    = ( counter_hs >= THB && counter_hs <= TH && counter_vs >= TVB  && counter_vs < TV) ? 1 : 0;
assign hsync_cnt = counter_hs;
assign vsync_cnt = counter_vs;

assign img_ack = lcd_de &&
((counter_hs - THB) >= IMG_X && (counter_hs - THB) < (IMG_X + IMG_W)) && 
((counter_vs - TVB) >= IMG_Y && (counter_vs - TVB) < (IMG_Y + IMG_H)) ? 1'b1 : 1'b0;
               
assign addr = read_addr;

always@(posedge clk or negedge rest_n)
 begin
	 if(!rest_n)
		 read_addr <= 16'd0;
	 else if(img_ack)
		 read_addr <= (counter_hs - IMG_X - THB) + (counter_vs - IMG_Y - TVB) * IMG_W;
	 else
		 read_addr <= 16'd0;  
 end

endmodule
module running_led
( 
	input	wire 		clk_24m,
	output  reg [15:0] 	led
);

wire rst_n;

parameter CNT = 25'd12000_000;

initial
begin
	cnt_time = 0;
	flag = 0;
	led = 0;
end

rst_n ux_rst_n
(
	.clk	(clk_24m	),
	.rst_n	(rst_n		)
);

reg [24:0] cnt_time;
reg flag;

// 0.04S¼ÆÊýÆ÷
always @(posedge clk_24m)
begin 
	if(cnt_time == CNT - 1) 
		cnt_time <= 0; 
	else 
		cnt_time <= cnt_time + 1'b1; 
end

always @(posedge clk_24m)
begin
	if(!led[0])
		flag <= 0;
	else if(!led[15])
		flag <= 1;
	else
		flag <= flag;
end

// always @(posedge clk_24m)
// begin
	// if(led == 0) 
		// led <= 16'hfffe; 
	// else if(cnt_time == CNT - 1 && !flag)
		// led <= {led[14:0],led[15]};	
	// else if(cnt_time == CNT - 1)
		// led <= {led[0],led[15:1]};
	// else
		// led <= led;
// end

always @(posedge clk_24m)
begin
	if(led == 0) 
		led <= 16'hfffe; 
	else if(cnt_time == CNT - 1)
	begin
		if(!flag)
			led <= {led[14:0],led[15]};
		else
			led <= {led[0],led[15:1]};
	end
	else
		led <= led;
end


endmodule
module rst_n
(
	input	wire	clk,
	output	reg		rst_n
);

reg[3:0] cnt;

always @(posedge clk)
begin
	if(cnt == 4'hf)
		cnt <= cnt;
	else
		cnt <= cnt + 1'b1;
end

always @(posedge clk)
begin
	if(cnt == 4'hf)
		rst_n <= 1'b1;
	else
		rst_n <= 1'b0;
end


endmodule
module switch_led
(
	input	wire [15:0]		switch,
	output	wire [15:0]		led
);

assign led = switch;

endmodule
module rgb_led( 
input	wire 	clk_24m,
output	wire 	led_r,
output	wire 	led_g,
output	wire 	led_b
); 

wire rst_n;
reg [2:0] led_rgb;
//--------rst_n---------------
rst_n ux_rst_n(
	.clk(clk_24m),
	.rst_n(rst_n)
);

parameter CNT = 24_000_000;//

reg [24:0] cnt_time;

always @(posedge clk_24m or negedge rst_n)
begin 
	if (!rst_n)
	    cnt_time <= 0; 
	else if(cnt_time == CNT - 1) 
		cnt_time <= 0; 
	else 
		cnt_time <= cnt_time + 1'b1; 
end

always @(posedge clk_24m or negedge rst_n)
begin
	if (!rst_n)
		led_rgb <= 3'b101; 
	else if(cnt_time == CNT - 1)
		led_rgb <= {led_rgb[0],led_rgb[2:1]};
	else
		led_rgb <= led_rgb;
end

assign led_r = led_rgb[0];
assign led_g = led_rgb[1];
assign led_b = led_rgb[2];

endmodule
module top
(
    input   wire        sclk,
    
    input   wire        key,
    
    // UART
    input   wire        rxd,
    output  wire        txd,
    
    // FLASH
    output  wire        flash_sck,
    output  wire        flash_cs,
    output  wire        flash_sdo,
    input   wire        flash_sdi,
    
    // tube
    output  wire [7:0]  tube,
    output  wire [3:0]  tube_sel,
    
    // LED
    output  wire[15:0]  led
);

/*
* mod_sel == 0: 等待flash空闲
* mod_sel == 1: flash写使能
* mod_sel == 2: 擦除整个flash
* mod_sel == 3: 写入数据(1byte)到flash
* mod_sel == 4: 从flash读取数据(1byte)
* mod_sel == 5: 读取整个flash.
* mod_sel == 6: 读取芯片ID
* mod_sel == 7: 擦除flash一个扇区
*/

wire start;
wire [2:0] mod_sel;
wire [23:0] fls_addr;
wire [7:0] fls_write;
wire [7:0] fls_read;
wire frd_en;
wire [23:0] frd_addr;
wire [7:0] frd_data;
wire [15:0] id;
wire busy;

wire [3:0] sm_bit1_num ;
wire [3:0] sm_bit2_num ;
wire [3:0] sm_bit3_num ;
wire [3:0] sm_bit4_num ;

uart
#(
    .BAUDRATE(115200        ),
    .CLK_RATE(24000000      ) // Hz
)
u_uart
(
    .clk        (sclk       ),

    // uart
    .rx         (rxd        ),
    .tx         (txd        ),
    
    // tube 
    .sm_bit1    (sm_bit1_num),
    .sm_bit2    (sm_bit2_num),
    .sm_bit3    (sm_bit3_num),
    .sm_bit4    (sm_bit4_num),
	
    // led
    .led        (led        ),
    
	// flash
    .start      (start      ),
    .mod_sel    (mod_sel    ),
    .fls_addr   (fls_addr   ),
    .fls_write  (fls_write  ),
    .fls_read   (fls_read   ),
    .id         (id         ),
    .busy       (busy       )
);

flash_dri u_flash_dri
(
    .clk        (sclk       ),

    // SPI
    .fls_sck    (flash_sck  ),
    .fls_ncs    (flash_cs   ),
    .fls_sdo    (flash_sdo  ),
    .fls_sdi    (flash_sdi  ),

    // flash控制
    .start      (start      ),
    .mod_sel    (mod_sel    ), // 多路选择指示

    // flash读写1byte
    .fls_addr   (fls_addr   ),
    .fls_write  (fls_write  ),
    .fls_read   (fls_read   ),
    
    // flash快速读取
    .frd_en     (frd_en     ),
    .frd_addr   (frd_addr   ),
    .frd_data   (frd_data   ),

    // ID
    .id         (id         ),
    .busy       (busy       )
);

// 动态数码管
tube_dri u_tube_dri
( 
    .clk_24m        (sclk       ),
                                
    .sm_seg         (tube       ),
    .sm_bit         (tube_sel   ),
                                
    .sm_bit1_num    (sm_bit1_num),
    .sm_bit2_num    (sm_bit2_num),
    .sm_bit3_num    (sm_bit3_num),
    .sm_bit4_num    (sm_bit4_num)
);

endmodule
module tube_dri
#(
	parameter CNT_TIME = 2400_000 //0.1s
)
( 
	input	wire        clk_24m,
    
    output	wire [7:0]  sm_seg,
    output	wire [3:0]  sm_bit,
    
	input	wire [3:0]  sm_bit1_num,
	input	wire [3:0]  sm_bit2_num,
	input	wire [3:0]  sm_bit3_num,
	input	wire [3:0]  sm_bit4_num
);

wire 		rst_n;
reg [3:0]  	addr;
//计数器，约为10ms扫描一次
reg [17:0] 	cnt_w;
//数码管位选
reg [3:0] 	sm_bit_reg;
reg [3:0] 	sm_seg_num;
reg [7:0]	sm_seg_reg;	
localparam
			S0 = 4'b0000 ,
			S1 = 4'b0001 ,
			S2 = 4'b0010 ,
			S3 = 4'b0011 ,
			S4 = 4'b0100 ,
			S5 = 4'b0101 ,
			S6 = 4'b0110 ,
			S7 = 4'b0111 ,
			S8 = 4'b1000 ,
			S9 = 4'b1001 ;

rst_n ux_rst
(
	.clk	(clk_24m	),
	.rst_n	(rst_n		)
);			

always@(posedge clk_24m or negedge rst_n)
begin
	if(!rst_n)
		cnt_w <= 18'd0;
	else
		cnt_w <= cnt_w + 1;
end

always@(posedge clk_24m or negedge rst_n)
begin
	if(!rst_n)
		sm_seg_num   <= 4'h0;
	else
	begin
		case( cnt_w[17:16] )
		2'b00:sm_seg_num   <= sm_bit1_num; 
		2'b01:sm_seg_num   <= sm_bit2_num; 
		2'b10:sm_seg_num   <= sm_bit3_num; 
		2'b11:sm_seg_num   <= sm_bit4_num; 
		endcase
	end
end

always@(posedge clk_24m or negedge rst_n)
begin
	if(!rst_n)
		sm_bit_reg <= 4'b1111;
	else
	begin
		case( cnt_w[17:16] )
		2'b00:sm_bit_reg <= 4'b1110; 
		2'b01:sm_bit_reg <= 4'b1101; 
		2'b10:sm_bit_reg <= 4'b1011; 
		2'b11:sm_bit_reg <= 4'b0111; 
		endcase
	end
end
			
always@(*)
begin
	case ( sm_seg_num )
	S0:
		sm_seg_reg <= 8'hc0;
	S1:               
		sm_seg_reg <= 8'hf9;
	S2:               
		sm_seg_reg <= 8'ha4;
	S3:               
		sm_seg_reg <= 8'hb0;
	S4:               
		sm_seg_reg <= 8'h99;
	S5:               
		sm_seg_reg <= 8'h92;
	S6:               
		sm_seg_reg <= 8'h82;
	S7:               
		sm_seg_reg <= 8'hf8;
	S8:               
		sm_seg_reg <= 8'h80;
	S9:               
		sm_seg_reg <= 8'h90;
	default:sm_seg_reg <= 8'hc0;
	endcase
end	
					
assign sm_seg = sm_seg_reg;	
assign sm_bit = sm_bit_reg;	
	
endmodule
module ubus
(
	input	wire		clk,
	
	// ubus write
	input	wire		ubus_wen,
	input	wire [31:0]	ubus_waddr,
	input	wire [31:0]	ubus_wdata,
	
	// ubus read
	input	wire		ubus_ren,
	input	wire [31:0]	ubus_raddr,
    output  reg			ubus_bken,
	output	reg  [31:0] ubus_rdata,
	
	// user port
    
    // led
    output  reg  [15:0] led,
    
    // tube 
    output	reg  [3:0] sm_bit1,
	output	reg  [3:0] sm_bit2,
	output	reg  [3:0] sm_bit3,
	output	reg  [3:0] sm_bit4,
    
    // flash
    output  reg         start,
    output  reg [2:0]   mod_sel,
    output  reg [23:0]  fls_addr,
    output  reg [7:0]   fls_write,
    input   wire [7:0]  fls_read,
    input   wire [15:0] id,
    input   wire        busy
);



// ´®¿ÚÐ´Êý¾Ý
always@(posedge clk)
begin
	if(ubus_wen)
	begin
		case(ubus_waddr)
            0: led <= ~ubus_wdata;
            1: {sm_bit4,sm_bit3,sm_bit2,sm_bit1} <= ubus_wdata;
            2: start <= ubus_wdata;
            3: mod_sel <= ubus_wdata;
            4: fls_addr <= ubus_wdata;
            5: fls_write <= ubus_wdata;
            
            
		endcase
	end
    else
        start <= 0;
end

// ´®¿Ú¶ÁÊý¾Ý
always@(posedge clk)
begin
    if(ubus_ren)
    begin
        case(ubus_raddr)
            0: ubus_rdata <= ~led;
            // 1: ubus_rdata <= {sm_bit4,sm_bit3,sm_bit2,sm_bit1};
            6: ubus_rdata   <=   fls_read    ;        
            7: ubus_rdata   <=   id  ;        
            8: ubus_rdata   <=   busy ;             
            
        endcase
    end
end

// ´®¿ÚÊý¾Ý·µ»Ø(¸ù¾ÝÊµ¼ÊÊý¾Ý·µ»ØÊ±¼ä,µ÷½Ú¶ÔÓ¦ÑÓÊ±)
always@(posedge clk)
begin
	ubus_bken <= ubus_ren;
end

endmodule
module uart
#(
	parameter BAUDRATE = 115200,
	parameter CLK_RATE = 50000000 // Hz
)
(
    input	wire		clk,

    // uart
    input	wire		rx,
    output  wire		tx,
    
	// tube 
    output	wire [3:0] sm_bit1,
	output	wire [3:0] sm_bit2,
	output	wire [3:0] sm_bit3,
	output	wire [3:0] sm_bit4,
	
	// led
    output  wire [15:0] led,
    
    // flash
    output  wire        start,
    output  wire [2:0]  mod_sel,
    output  wire [23:0] fls_addr,
    output  wire [7:0]  fls_write,
    input   wire [7:0]  fls_read,
    input   wire [15:0] id,
    input   wire        busy
);

wire rx_en;
wire [7:0] rx_data;
wire tx_en;
wire [7:0] tx_data;
wire tx_ready;
wire ubus_wen;
wire [31:0] ubus_waddr;
wire [31:0] ubus_wdata;
wire ubus_ren;
wire [31:0] ubus_raddr;
wire ubus_bken;
wire [31:0] ubus_rdata;

//´®¿Ú½ÓÊÕÄ£¿é
uart_rx
#(
	.BAUDRATE	(BAUDRATE	    ),
	.CLK_RATE	(CLK_RATE	    )
)
u_uart_rx
(
    .clk        (clk            ),
    .rx         (rx             ),
    .rx_en    	(rx_en          ),
    .rx_data	(rx_data        )
);

//´®¿Ú·¢ËÍÄ£¿é
uart_tx
#(
	.BAUDRATE	(BAUDRATE	    ),
	.CLK_RATE	(CLK_RATE	    )
)
u_uart_tx
(
    .clk        (clk            ),
    .tx         (tx             ),
    
`ifdef UART_LOOPBACK // ´®¿Ú»Ø»·²âÊÔ
    .tx_en		(rx_en          ),
    .tx_data	(rx_data        ),
`else
    .tx_en		(tx_en          ),
    .tx_data	(tx_data        ),
`endif

	.tx_ready	(tx_ready	    )
);

// ´®¿ÚÍ¨ÐÅÐ­Òé
uprotocol u_uprotocol
(
    .clk        (clk            ),
    
    // uart-rx
    .rx_en      (rx_en          ),
    .rx_data    (rx_data        ),
    
    // uart-tx
    .tx_en      (tx_en          ),
    .tx_data    (tx_data        ),
    .tx_ready   (tx_ready       ),
    
	// ubus write
	.ubus_wen	(ubus_wen		),
	.ubus_waddr	(ubus_waddr		),
	.ubus_wdata	(ubus_wdata		),
	
	// ubus read
	.ubus_ren	(ubus_ren		),
	.ubus_raddr	(ubus_raddr		),
	.ubus_bken	(ubus_bken		),
	.ubus_rdata	(ubus_rdata		)
);

// ´®¿ÚÐéÄâ×ÜÏß
ubus u_ubus
(
	.clk		(clk			),
	
	// ubus write
	.ubus_wen	(ubus_wen		),
	.ubus_waddr	(ubus_waddr		),
	.ubus_wdata	(ubus_wdata		),
	
	// ubus read
	.ubus_ren	(ubus_ren		),
	.ubus_raddr	(ubus_raddr		),
	.ubus_bken	(ubus_bken		),
	.ubus_rdata	(ubus_rdata		),
	
	// user port

    // tube 
    .sm_bit1    (sm_bit1        ),
    .sm_bit2    (sm_bit2        ),
    .sm_bit3    (sm_bit3        ),
    .sm_bit4    (sm_bit4        ),
    
    // led
    .led        (led            ),
    
    // flash
    .start      (start          ),
    .mod_sel    (mod_sel        ),
    .fls_addr   (fls_addr       ),
    .fls_write  (fls_write      ),
    .fls_read   (fls_read       ),
    .id         (id             ),
    .busy       (busy           )
);

endmodule
module uart_rx
#(
	parameter BAUDRATE = 115200,
	parameter CLK_RATE = 50000000
)
(
    input	wire		clk,
	
	// uart
    input	wire		rx,
	
	// data
    output  reg			rx_en,
    output  reg [7:0]	rx_data
);

reg start;
reg clk_en;
reg [3:0] cnt;
reg [7:0] data;
reg [1:0] rx_d;
reg [31:0] clk_cnt;

// ±ßÑØ¼ì²â
always@(posedge clk)
begin
    rx_d <= {rx_d[0],rx};
end

// Êý¾Ý´«Êä¿ØÖÆ
always@(posedge clk)
begin
    if(rx_d == 2'b10) // ¼ì²âµ½ÏÂ½µÑØ´«Êä¿ªÊ¼
        start <= 1;
    else if(cnt == 9) // Êý¾Ý½ÓÊÕÍê³É
        start <= 0;
end

// ²¨ÌØÂÊ¼ÆÊýÆ÷
always@(posedge clk)
begin
	if(!start)
		clk_cnt <= (CLK_RATE / (BAUDRATE*2)); // ÖÐ¼ä²ÉÑù
	else if(clk_cnt == CLK_RATE / BAUDRATE - 1)
		clk_cnt <= 0;
	else
		clk_cnt <= clk_cnt + 1;
end

// ²¨ÌØÂÊ¼ÆÊýÆ÷
always@(posedge clk)
begin
	clk_en <= (clk_cnt == CLK_RATE / BAUDRATE - 1);
end

// ½ÓÊÕÊý¾Ý¼ÆÊýÆ÷
always@(posedge clk)
begin
	if(!start)
        cnt <= 0;
	else if(clk_en)
        cnt <= cnt + 1;
end

// ½ÓÊÕÊý¾Ý²ÉÑù
always@(posedge clk)
if(clk_en)
begin
    case(cnt)
        1: data[0] <= rx;
        2: data[1] <= rx;
        3: data[2] <= rx;
        4: data[3] <= rx;
        5: data[4] <= rx;
        6: data[5] <= rx;  
        7: data[6] <= rx;    
        8: data[7] <= rx;
    endcase   
end

// Êý¾ÝÊä³öÊ¹ÄÜ
always@(posedge clk)
begin
    rx_en <= (start && cnt == 9);
end

// Êý¾ÝÊä³ö
always@(posedge clk)
begin
    if(cnt == 9)
        rx_data <= data;
end

endmodule
module uart_tx
#(
	parameter BAUDRATE = 115200,
	parameter CLK_RATE = 50000000
)
(
    input	wire		clk,
	
	// uart
    output  reg			tx,
	
	// data
    input	wire		tx_en,
    input	wire [7:0]	tx_data,
	output	reg			tx_ready
);

reg start;
reg clk_en;
reg [3:0] cnt;
reg [7:0] data;
reg [31:0] clk_cnt;


// ²¨ÌØÂÊ¼ÆÊýÆ÷
always@(posedge clk)
begin
	if(!start)
		clk_cnt <= 0;
	else if(clk_cnt == CLK_RATE / BAUDRATE - 1)
		clk_cnt <= 0;
	else
		clk_cnt <= clk_cnt + 1;
end

// ²¨ÌØÂÊ¼ÆÊýÆ÷
always@(posedge clk)
begin
	clk_en <= (clk_cnt == CLK_RATE / BAUDRATE - 1);
end

// Êý¾Ý´«Êä¿ØÖÆ
always@(posedge clk)
begin
    if(tx_en) // ´«Êä¿ªÊ¼
        start <= 1;
    else if(cnt == 10) // ´«Êä½áÊø
        start <= 0;
end

// Êý¾Ý¼Ä´æ
always@(posedge clk)
begin
	if(tx_en && !start)
		data <= tx_data;
end

// ×´Ì¬¼ÆÊýÆ÷
always@(posedge clk)
begin
    if(!start)
		cnt <= 0;
	else if(clk_en)
        cnt <= cnt + 1;
end

// ´®¿Ú·¢ËÍ
always@(posedge clk)
begin
    case(cnt)
		0: tx <= 1'b1;    // ·¢ËÍÍ£Ö¹Î»(ÉÏµç×´Ì¬).
        1: tx <= 1'b0;    // ´«Êä¿ªÊ¼
        2: tx <= data[0]; // ·¢ËÍÊý¾ÝµÚ1Î»
        3: tx <= data[1]; // ·¢ËÍÊý¾ÝµÚ2Î»
        4: tx <= data[2]; // ·¢ËÍÊý¾ÝµÚ3Î»
        5: tx <= data[3]; // ·¢ËÍÊý¾ÝµÚ4Î»
        6: tx <= data[4]; // ·¢ËÍÊý¾ÝµÚ5Î»
        7: tx <= data[5]; // ·¢ËÍÊý¾ÝµÚ6Î»
        8: tx <= data[6]; // ·¢ËÍÊý¾ÝµÚ7Î»
        9: tx <= data[7]; // ·¢ËÍÊý¾ÝµÚ8Î»
        10:tx <= 1'b1;    // ·¢ËÍÍ£Ö¹Î»
    endcase
end

// ·¢ËÍÄ£¿é¿ÉÓÃ
always@(posedge clk)
begin
	if(tx_en)
		tx_ready <= 0;
	else
		tx_ready <= !start;
end

endmodule
module flash_read
(
    input   wire        clk,

    // SPI
    output  reg         fls_sck,
    output  reg         fls_ncs,
    output  reg         fls_sdo,
    input   wire        fls_sdi,

    // 读数据,每次读取1byte
    input   wire        start,
    input   wire [23:0] addr,
    output  reg         dout_en,
    output  reg  [7:0]  dout,

    output  reg         busy
);

reg [9:0] cnt;
reg [6:0] cycle_cnt; 
reg [2:0] phase_cnt;
reg [31:0] tx_reg;
reg [7:0] rx_reg;
reg sft_wen;
reg sft_ren;
reg byte_flag;

initial
begin
    cnt = 0;
    tx_reg = 0;
    rx_reg = 0;
    busy = 0;
end

// 总计数器
always@(posedge clk)
begin
    if(busy)
        cnt <= cnt + 1;
    else
        cnt <= 0;
end

// 周期计数器
always@(posedge clk)
begin
    cycle_cnt <= cnt[9:3];
end

// 相位计数器
always@(posedge clk)
begin
    phase_cnt <= cnt[2:0];
end

// SPI时钟
always@(posedge clk)
begin
    fls_sck <= cnt[2];
end

// SPI片选
always@(posedge clk)
begin
    if(busy)
        fls_ncs <= 0;
    else
        fls_ncs <= 1;
end

// 初始化数据
always@(posedge clk)
begin
    if(start)
        tx_reg <= {8'h03,addr}; // 读取数据
    else if(sft_wen)
        tx_reg <= {tx_reg[30:0],1'b0};
end

// 写数据移位使能(sck下降沿产生一个移位).
always@(posedge clk)
begin
    sft_wen <= (phase_cnt == 6);
end

// 读数据移位使能(sck上升沿产生一个移位).
always@(posedge clk)
begin
    sft_ren <= (phase_cnt == 3) && (cycle_cnt > 31);
end

// 接收完1byte数据
always@(posedge clk)
begin
    byte_flag <= (cycle_cnt > 31) && (cycle_cnt[2:0] == 7) && (phase_cnt == 5);
end

// sdo
always@(posedge clk)
begin
    fls_sdo <= tx_reg[31];
end

// sdi
always@(posedge clk)
begin
    if(sft_ren)
        rx_reg <= {rx_reg[6:0],fls_sdi};
end

// dout_en
always@(posedge clk)
begin
    dout_en <= byte_flag;
end

// dout
always@(posedge clk)
begin
    if(byte_flag)
        dout <= rx_reg;
end

// busy
always@(posedge clk)
begin
    if(start)
        busy <= 1;
    else if(cycle_cnt == 40)
        busy <= 0;
end

endmodule
module flash_fast_read
(
    input   wire        clk,

    // SPI
    output  reg         fls_sck,
    output  reg         fls_ncs,
    output  reg         fls_sdo,
    input   wire        fls_sdi,

    // 读数据,每次读取整个flash
    input   wire        start,
    output  reg         dout_en,
    output  reg [23:0]  addr,
    output  reg [7:0]   dout,

    output  reg         busy
);

reg [31:0] cnt;
reg [28:0] cycle_cnt; 
reg [2:0] phase_cnt;
reg [31:0] tx_reg;
reg [7:0] rx_reg;
reg sft_wen;
reg sft_ren;
reg byte_flag;

initial
begin
    cnt = 0;
    tx_reg = 0;
    rx_reg = 0;
    busy = 0;
end

// 总计数器
always@(posedge clk)
begin
    if(busy)
        cnt <= cnt + 1;
    else
        cnt <= 0;
end

// 周期计数器
always@(posedge clk)
begin
    cycle_cnt <= cnt[31:3];
end

// 相位计数器
always@(posedge clk)
begin
    phase_cnt <= cnt[2:0];
end

// SPI时钟
always@(posedge clk)
begin
    fls_sck <= cnt[2];
end

// SPI片选
always@(posedge clk)
begin
    if(busy)
        fls_ncs <= 0;
    else
        fls_ncs <= 1;
end

// 初始化数据
always@(posedge clk)
begin
    if(start)
        tx_reg <= {8'h0b,8'h00,8'h00,8'h00}; // 读取数据
    else if(sft_wen)
        tx_reg <= {tx_reg[30:0],1'b0};
end

// 写数据移位使能(sck下降沿产生一个移位).
always@(posedge clk)
begin
    sft_wen <= (phase_cnt == 6);
end

// 读数据移位使能(sck上升沿产生一个移位).
always@(posedge clk)
begin
    sft_ren <= (phase_cnt == 3) && (cycle_cnt > 39);
end

// 接收完1byte数据
always@(posedge clk)
begin
    byte_flag <= (cycle_cnt > 39) && (cycle_cnt[2:0] == 7) && (phase_cnt == 5);
end

// sdo
always@(posedge clk)
begin
    fls_sdo <= tx_reg[31];
end

// sdi
always@(posedge clk)
begin
    if(sft_ren)
        rx_reg <= {rx_reg[6:0],fls_sdi};
end

// dout_en
always@(posedge clk)
begin
    dout_en <= byte_flag;
end

// dout
always@(posedge clk)
begin
    if(byte_flag)
        dout <= rx_reg;
end
 
//dout addr
always@(posedge clk)
begin
    if(start)
        addr <= 24'hFF_FFFF;
    else if(byte_flag)
        addr <= addr + 1;
end

// busy
always@(posedge clk)
begin
    if(start)
        busy <= 1;
    else if(cycle_cnt == 28'h800_0028)
        busy <= 0;
end

endmodule
module flash_write
(
    input   wire        clk,

    // SPI
    output  reg         fls_sck,
    output  reg         fls_ncs,
    output  reg         fls_sdo,
    input   wire        fls_sdi,

    // 写入数据,每次写入1byte
    input   wire        start,
    input   wire [23:0] addr,
    input   wire [7:0]  din,

    output  reg         busy
);

reg [9:0] cnt;
reg [6:0] cycle_cnt; 
reg [2:0] phase_cnt;
reg [39:0] tx_reg;
reg sft_wen;
reg byte_flag;

initial
begin
    cnt = 0;
    tx_reg = 40'd0;
    busy = 0;
end

// 总计数器
always@(posedge clk)
begin
    if(busy)
        cnt <= cnt + 1;
    else
        cnt <= 0;
end

// 周期计数器
always@(posedge clk)
begin
    cycle_cnt <= cnt[9:3];
end

// 相位计数器
always@(posedge clk)
begin
    phase_cnt <= cnt[2:0];
end

// SPI时钟
always@(posedge clk)
begin
    fls_sck <= cnt[2];
end

// SPI片选
always@(posedge clk)
begin
    if(busy)
        fls_ncs <= 0;
    else
        fls_ncs <= 1;
end

// 初始化数据
always@(posedge clk)
begin
    if(start)
        tx_reg <= {8'h02,addr,din};
    else if(sft_wen)
        tx_reg <= {tx_reg[38:0],1'b0};
end

// 写数据移位使能(sck下降沿产生一个移位).
always@(posedge clk)
begin
    sft_wen <= (phase_cnt == 6);
end

// 发送完1byte数据
always@(posedge clk)
begin
    byte_flag <= (cycle_cnt[2:0] == 7) && (phase_cnt == 5);
end

// sdo
always@(posedge clk)
begin
    fls_sdo <= tx_reg[39];
end

// busy
always@(posedge clk)
begin
    if(start)
        busy <= 1;
    else if(cycle_cnt == 40)
        busy <= 0;
end

endmodule
module flash_sector_erase
(
    input   wire        clk,

    // SPI
    output  reg         fls_sck,
    output  reg         fls_ncs,
    output  reg         fls_sdo,
    input   wire        fls_sdi,

    // 擦除addr开始的一个扇区
    input   wire        start,
    input   wire [23:0] addr,

    output  reg         busy
);

reg [9:0] cnt;
reg [6:0] cycle_cnt; 
reg [2:0] phase_cnt;
reg [31:0] tx_reg;
reg sft_wen;

initial
begin
    cnt = 0;
    tx_reg = 0;
    busy = 0;
end

// 总计数器
always@(posedge clk)
begin
    if(busy)
        cnt <= cnt + 1;
    else
        cnt <= 0;
end

// 周期计数器
always@(posedge clk)
begin
    cycle_cnt <= cnt[9:3];
end

// 相位计数器
always@(posedge clk)
begin
    phase_cnt <= cnt[2:0];
end

// SPI时钟
always@(posedge clk)
begin
    fls_sck <= cnt[2];
end

// SPI片选
always@(posedge clk)
begin
    if(busy)
        fls_ncs <= 0;
    else
        fls_ncs <= 1;
end

// 初始化数据
always@(posedge clk)
begin
    if(start)
        tx_reg <= {8'h20,addr}; // 擦除一个扇区
    else if(sft_wen)
        tx_reg <= {tx_reg[30:0],1'b0};
end

// 写数据移位使能(sck下降沿产生一个移位).
always@(posedge clk)
begin
    sft_wen <= (phase_cnt == 6);
end

// sdo
always@(posedge clk)
begin
    fls_sdo <= tx_reg[31];
end

// busy
always@(posedge clk)
begin
    if(start)
        busy <= 1;
    else if(cycle_cnt == 32)
        busy <= 0;
end

endmodule
module flash_erase
(
    input   wire    clk,
    
    // SPI
    output  reg     fls_sck,
    output  reg     fls_ncs,
    output  reg     fls_sdo,
    input   wire    fls_sdi,

    input   wire    start,
    output  reg     busy
);

reg [9:0] cnt;
reg [6:0] cycle_cnt; 
reg [2:0] phase_cnt;
reg [7:0] tx_reg;
reg sft_wen;
reg byte_flag;

initial
begin
    cnt = 0;
    tx_reg = 0;
    busy = 0;
end

// 总计数器
always@(posedge clk)
begin
    if(busy)
        cnt <= cnt + 1;
    else
        cnt <= 0;
end

// 周期计数器
always@(posedge clk)
begin
    cycle_cnt <= cnt[9:3];
end

// 相位计数器
always@(posedge clk)
begin
    phase_cnt <= cnt[2:0];
end

// SPI时钟
always@(posedge clk)
begin
    fls_sck <= cnt[2];
end

// SPI片选
always@(posedge clk)
begin
    if(busy)
        fls_ncs <= 0;
    else
        fls_ncs <= 1;
end

// 初始化数据
always@(posedge clk)
begin
    if(start)
        tx_reg <= {8'hc7}; // 擦除flash芯片
    else if(sft_wen)
        tx_reg <= {tx_reg[6:0],1'b0};
end

// 写数据移位使能(sck下降沿产生一个移位).
always@(posedge clk)
begin
    sft_wen <= (phase_cnt == 6);
end

// 发送或者接收完1byte数据
always@(posedge clk)
begin
    byte_flag <= (cycle_cnt[2:0] == 7) && (phase_cnt == 5);
end

// sdo
always@(posedge clk)
begin
    fls_sdo <= tx_reg[7];
end

// busy
always@(posedge clk)
begin
    if(start)
        busy <= 1;
    else if(cycle_cnt == 8)
        busy <= 0;
end

endmodule
module flash_id
(
    input   wire        clk,
    
    // SPI
    output  reg         fls_sck,
    output  reg         fls_ncs,
    output  reg         fls_sdo,
    input   wire        fls_sdi,

    input   wire        start,
    output  reg [15:0]  fls_id,
    output  reg         busy
);

reg [9:0] cnt;
reg [6:0] cycle_cnt; 
reg [2:0] phase_cnt;
reg [31:0] tx_reg;
reg [7:0] rx_reg;
reg sft_wen;
reg sft_ren;
reg byte_flag;

initial
begin
    cnt = 0;
    tx_reg = 0;
    rx_reg = 0;
    busy = 0;
end

// 总计数器
always@(posedge clk)
begin
    if(busy)
        cnt <= cnt + 1;
    else
        cnt <= 0;
end

// 周期计数器
always@(posedge clk)
begin
    cycle_cnt <= cnt[9:3];
end

// 相位计数器
always@(posedge clk)
begin
    phase_cnt <= cnt[2:0];
end

// SPI时钟
always@(posedge clk)
begin
    fls_sck <= cnt[2];
end

// SPI片选
always@(posedge clk)
begin
    if(busy)
        fls_ncs <= 0;
    else
        fls_ncs <= 1;
end

// 初始化数据
always@(posedge clk)
begin
    if(start)
        tx_reg <= {8'h90,8'h00,8'h00,8'h00}; // 读ID命令
    else if(sft_wen)
        tx_reg <= {tx_reg[30:0],1'b0};
end

// 写数据移位使能(sck下降沿产生一个移位).
always@(posedge clk)
begin
    sft_wen <= (phase_cnt == 6);
end

// 读数据移位使能(sck上升沿产生一个移位).
always@(posedge clk)
begin
    sft_ren <= (phase_cnt == 3) && (cycle_cnt > 31) && (cycle_cnt < 48);
end

// 接收完1byte数据
always@(posedge clk)
begin
    byte_flag <= (cycle_cnt > 31) && (cycle_cnt[2:0] == 7) && (phase_cnt == 5);
end

// sdo
always@(posedge clk)
begin
    fls_sdo <= tx_reg[31];
end

// sdi
always@(posedge clk)
begin
    if(sft_ren)
        rx_reg <= {rx_reg[6:0],fls_sdi};
end

// flash id
always@(posedge clk)
begin
    if(byte_flag)
        fls_id <= {fls_id[7:0],rx_reg};
end

// busy
always@(posedge clk)
begin
    if(start)
        busy <= 1;
    else if(cycle_cnt == 48)
        busy <= 0;
end

endmodule
module flash_wait_free
(
    input   wire    clk,
    
    // SPI
    output  reg     fls_sck,
    output  reg     fls_ncs,
    output  reg     fls_sdo,
    input   wire    fls_sdi,

    input   wire    start,
    output  reg     busy
);

reg [31:0] cnt;
reg [28:0] cycle_cnt; 
reg [2:0] phase_cnt;
reg [7:0] tx_reg;
reg [7:0] rx_reg;
reg sft_wen;
reg sft_ren;
reg byte_flag;
reg fls_busy;

initial
begin
    cnt = 0;
    tx_reg = 0;
    rx_reg = 0;
    busy = 0;
    fls_busy = 1;
end

// 总计数器
always@(posedge clk)
begin
    if(busy)
        cnt <= cnt + 1;
    else
        cnt <= 0;
end

// 周期计数器
always@(posedge clk)
begin
    cycle_cnt <= cnt[31:3];
end

// 相位计数器
always@(posedge clk)
begin
    phase_cnt <= cnt[2:0];
end

// SPI时钟
always@(posedge clk)
begin
    fls_sck <= cnt[2];
end

// SPI片选
always@(posedge clk)
begin
    if(busy)
        fls_ncs <= 0;
    else
        fls_ncs <= 1;
end

// 初始化数据
always@(posedge clk)
begin
    if(start)
        tx_reg <= {8'h05}; // 等待flash空闲命令
    else if(sft_wen)
        tx_reg <= {tx_reg[6:0],1'b0};
end

// 写数据移位使能(sck下降沿产生一个移位).
always@(posedge clk)
begin
    sft_wen <= (phase_cnt == 6);
end

// 读数据移位使能(sck上升沿产生一个移位).
always@(posedge clk)
begin
    sft_ren <= (phase_cnt == 3) && (cycle_cnt > 7);
end

// 接收完1byte数据
always@(posedge clk)
begin
    byte_flag <= (cycle_cnt > 7) && (cycle_cnt[2:0] == 7) && (phase_cnt == 5);
end

// sdo
always@(posedge clk)
begin
    fls_sdo <= tx_reg[7];
end

// sdi
always@(posedge clk)
begin
    if(sft_ren)
        rx_reg <= {rx_reg[6:0],fls_sdi};
end

// fls_busy
always@(posedge clk)
begin
    if(start)
        fls_busy <= 1;
    else if(byte_flag)
        fls_busy <= rx_reg[0]; // 1 for busy. 0 for free
end

// busy
always@(posedge clk)
begin
    if(start)
        busy <= 1;
    else if((fls_busy == 0) && (phase_cnt == 0))
        busy <= 0;
end

endmodule
module flash_write_enable
(
    input   wire    clk,
    
    // SPI
    output  reg     fls_sck,
    output  reg     fls_ncs,
    output  reg     fls_sdo,
    input   wire    fls_sdi,

    input   wire    start,
    output  reg     busy
);

reg [9:0] cnt;
reg [6:0] cycle_cnt; 
reg [2:0] phase_cnt;
reg [7:0] tx_reg;
reg sft_wen;
reg byte_flag;

initial
begin
    cnt = 0;
    tx_reg = 0;
    busy = 0;
end

// 总计数器
always@(posedge clk)
begin
    if(busy)
        cnt <= cnt + 1;
    else
        cnt <= 0;
end

// 周期计数器
always@(posedge clk)
begin
    cycle_cnt <= cnt[9:3];
end

// 相位计数器
always@(posedge clk)
begin
    phase_cnt <= cnt[2:0];
end

// SPI时钟
always@(posedge clk)
begin
    fls_sck <= cnt[2];
end

// SPI片选
always@(posedge clk)
begin
    if(busy)
        fls_ncs <= 0;
    else
        fls_ncs <= 1;
end

// 初始化数据
always@(posedge clk)
begin
    if(start)
        tx_reg <= {8'h06}; // 读使能命令
    else if(sft_wen)
        tx_reg <= {tx_reg[6:0],1'b0};
end

// 写数据移位使能(sck下降沿产生一个移位).
always@(posedge clk)
begin
    sft_wen <= (phase_cnt == 6);
end

// 发送或者接收完1byte数据
always@(posedge clk)
begin
    byte_flag <= (cycle_cnt[2:0] == 7) && (phase_cnt == 5);
end

// sdo
always@(posedge clk)
begin
    fls_sdo <= tx_reg[7];
end

// busy
always@(posedge clk)
begin
    if(start)
        busy <= 1;
    else if(cycle_cnt == 8)
        busy <= 0;
end

endmodule
module PLL  // al_ip/PLL.v(22)
  (
  refclk,
  reset,
  clk0_out,
  extlock
  );

  input refclk;  // al_ip/PLL.v(27)
  input reset;  // al_ip/PLL.v(28)
  output clk0_out;  // al_ip/PLL.v(30)
  output extlock;  // al_ip/PLL.v(29)

  wire clk0_buf;  // al_ip/PLL.v(32)

  EG_PHY_GCLK bufg_feedback (
    .clki(clk0_buf),
    .clko(clk0_out));  // al_ip/PLL.v(34)
  EG_PHY_CONFIG #(
    .DONE_PERSISTN("ENABLE"),
    .INIT_PERSISTN("ENABLE"),
    .JTAG_PERSISTN("DISABLE"),
    .PROGRAMN_PERSISTN("DISABLE"))
    config_inst ();
  EG_PHY_PLL #(
    .CLKC0_CPHASE(8),
    .CLKC0_DIV(9),
    .CLKC0_DIV2_ENABLE("DISABLE"),
    .CLKC0_ENABLE("ENABLE"),
    .CLKC0_FPHASE(0),
    .CLKC1_CPHASE(1),
    .CLKC1_DIV(1),
    .CLKC1_DIV2_ENABLE("DISABLE"),
    .CLKC1_ENABLE("DISABLE"),
    .CLKC1_FPHASE(0),
    .CLKC2_CPHASE(1),
    .CLKC2_DIV(1),
    .CLKC2_DIV2_ENABLE("DISABLE"),
    .CLKC2_ENABLE("DISABLE"),
    .CLKC2_FPHASE(0),
    .CLKC3_CPHASE(1),
    .CLKC3_DIV(1),
    .CLKC3_DIV2_ENABLE("DISABLE"),
    .CLKC3_ENABLE("DISABLE"),
    .CLKC3_FPHASE(0),
    .CLKC4_CPHASE(1),
    .CLKC4_DIV(1),
    .CLKC4_DIV2_ENABLE("DISABLE"),
    .CLKC4_ENABLE("DISABLE"),
    .CLKC4_FPHASE(0),
    .DERIVE_PLL_CLOCKS("DISABLE"),
    .DPHASE_SOURCE("DISABLE"),
    .DYNCFG("DISABLE"),
    .FBCLK_DIV(9),
    .FEEDBK_MODE("NORMAL"),
    .FEEDBK_PATH("CLKC0_EXT"),
    .FIN("24.000"),
    .FREQ_LOCK_ACCURACY(2),
    .GEN_BASIC_CLOCK("DISABLE"),
    .GMC_GAIN(6),
    .GMC_TEST(14),
    .ICP_CURRENT(3),
    .IF_ESCLKSTSW("DISABLE"),
    .INTFB_WAKE("DISABLE"),
    .KVCO(6),
    .LPF_CAPACITOR(3),
    .LPF_RESISTOR(2),
    .NORESET("DISABLE"),
    .ODIV_MUXC0("DIV"),
    .ODIV_MUXC1("DIV"),
    .ODIV_MUXC2("DIV"),
    .ODIV_MUXC3("DIV"),
    .ODIV_MUXC4("DIV"),
    .PLLC2RST_ENA("DISABLE"),
    .PLLC34RST_ENA("DISABLE"),
    .PLLMRST_ENA("DISABLE"),
    .PLLRST_ENA("ENABLE"),
    .PLL_LOCK_MODE(0),
    .PREDIV_MUXC0("VCO"),
    .PREDIV_MUXC1("VCO"),
    .PREDIV_MUXC2("VCO"),
    .PREDIV_MUXC3("VCO"),
    .PREDIV_MUXC4("VCO"),
    .REFCLK_DIV(2),
    .REFCLK_SEL("INTERNAL"),
    .STDBY_ENABLE("DISABLE"),
    .STDBY_VCO_ENA("DISABLE"),
    .SYNC_ENABLE("DISABLE"),
    .VCO_NORESET("DISABLE"))
    pll_inst (
    .daddr(6'b000000),
    .dclk(1'b0),
    .dcs(1'b0),
    .di(8'b00000000),
    .dwe(1'b0),
    .fbclk(clk0_out),
    .psclk(1'b0),
    .psclksel(3'b000),
    .psdown(1'b0),
    .psstep(1'b0),
    .refclk(refclk),
    .reset(reset),
    .stdby(1'b0),
    .clkc({open_n47,open_n48,open_n49,open_n50,clk0_buf}),
    .extlock(extlock));  // al_ip/PLL.v(57)

endmodule
module VGA_Demo_tb();

reg clk_24m = 1'b0;
reg rst_n;
wire [7:0] vga_b;
wire vga_clk;
wire vga_de;
wire [7:0] vga_g;
wire vga_hs;
wire [7:0] vga_r;
wire vga_vs;

//Clock process  24MHz
parameter PERIOD = 41.666;
always #(PERIOD/2) clk_24m = ~clk_24m;

//glbl Instantiate
glbl glbl();

//Unit Instantiate
VGA_Demo uut(
	.clk_24m(clk_24m),
	.rst_n(rst_n),
	.vga_b(vga_b),
	.vga_clk(vga_clk),
	.vga_de(vga_de),
	.vga_g(vga_g),
	.vga_hs(vga_hs),
	.vga_r(vga_r),
	.vga_vs(vga_vs));

//Stimulus process
initial begin
//To be inserted 
rst_n = 1'b0;
#100;
rst_n = 1'b1;
end

endmodule
module Clk_div
( 
	input  wire		clk,
	input  wire		rst_n,

	output wire 	clk_div
);

wire	Clk_Lock;

PLL uut
(
	.refclk		(clk		),
	.reset		(!rst_n		),
	
	.clk0_out	(clk_div	),
	.extlock	(Clk_Lock	)
);

endmodule
module Display
#(
	parameter H_DISP = 1280,
	parameter V_DISP = 1024
)
( 
	input  wire	 		clk,	
	input  wire			rst_n,	
	input  wire	[11:0]	lcd_xpos,	//lcd horizontal coordinate
	input  wire	[11:0]	lcd_ypos,	//lcd vertical coordinate
	
	output reg  [23:0]	lcd_data	//lcd data
);

`ifdef VGA_HORIZONTAL_COLOR
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		lcd_data <= 24'h0;
	else
		begin
		if	(lcd_ypos >= 0 && lcd_ypos < (V_DISP/8)*1)
			lcd_data <= `RED;
		else if(lcd_ypos >= (V_DISP/8)*1 && lcd_ypos < (V_DISP/8)*2)
			lcd_data <= `GREEN;
		else if(lcd_ypos >= (V_DISP/8)*2 && lcd_ypos < (V_DISP/8)*3)
			lcd_data <= `BLUE;
		else if(lcd_ypos >= (V_DISP/8)*3 && lcd_ypos < (V_DISP/8)*4)
			lcd_data <= `WHITE;
		else if(lcd_ypos >= (V_DISP/8)*4 && lcd_ypos < (V_DISP/8)*5)
			lcd_data <= `BLACK;
		else if(lcd_ypos >= (V_DISP/8)*5 && lcd_ypos < (V_DISP/8)*6)
			lcd_data <= `YELLOW;
		else if(lcd_ypos >= (V_DISP/8)*6 && lcd_ypos < (V_DISP/8)*7)
			lcd_data <= `CYAN;
		else
			lcd_data <= `ROYAL;
		end
end
`endif

`ifdef VGA_VERTICAL_COLOR
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		lcd_data <= 24'h0;
	else
		begin
		if	(lcd_xpos >= 0 && lcd_xpos < (H_DISP/8)*1)
			lcd_data <= `RED;
		else if(lcd_xpos >= (H_DISP/8)*1 && lcd_xpos < (H_DISP/8)*2)
			lcd_data <= `GREEN;
		else if(lcd_xpos >= (H_DISP/8)*2 && lcd_xpos < (H_DISP/8)*3)
			lcd_data <= `BLUE;
		else if(lcd_xpos >= (H_DISP/8)*3 && lcd_xpos < (H_DISP/8)*4)
			lcd_data <= `WHITE;
		else if(lcd_xpos >= (H_DISP/8)*4 && lcd_xpos < (H_DISP/8)*5)
			lcd_data <= `BLACK;
		else if(lcd_xpos >= (H_DISP/8)*5 && lcd_xpos < (H_DISP/8)*6)
			lcd_data <= `YELLOW;
		else if(lcd_xpos >= (H_DISP/8)*6 && lcd_xpos < (H_DISP/8)*7)
			lcd_data <= `CYAN;
		else
			lcd_data <= `ROYAL;
		end
end
`endif

`ifdef VGA_GRAFTAL_GRAPH
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		lcd_data <= 24'h0;
	else
		lcd_data <= lcd_xpos * lcd_ypos;
end
`endif


`ifdef VGA_GRAY_GRAPH
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		lcd_data <= 24'h0;
	else
		begin
		if(lcd_ypos < V_DISP/2)
			lcd_data <= {lcd_ypos[7:0], lcd_ypos[7:0], lcd_ypos[7:0]};
		else
			lcd_data <= {lcd_xpos[7:0], lcd_xpos[7:0], lcd_xpos[7:0]};
		end
end
`endif

endmodule
module Driver
#(
	parameter H_SYNC = 112	, 		// 行同步信号时间
	parameter H_BACK = 248	, 		// 行消隐后肩时间
	parameter H_DISP = 1280	, 		// 行数据有效时间
	parameter H_FRONT = 48	, 		// 行消隐前肩时间
	parameter H_TOTAL = 1688, 		// 行扫描总时间
			
	parameter V_SYNC = 3	, 		// 列同步信号时间
	parameter V_BACK = 38	, 		// 列消隐后肩时间
	parameter V_DISP = 1024	, 		// 列数据有效时间
	parameter V_FRONT = 1	, 		// 列消隐前肩时间
	parameter V_TOTAL = 1066  		// 列扫描总时间
)
(
	input  wire			clk,			//VGA clock
	input  wire			rst_n,     		//sync reset
	input  wire	[23:0]	lcd_data,		//lcd data
	
	//lcd interface
	output wire			lcd_dclk,   	//lcd pixel clock
	output wire			lcd_hs,	    	//lcd horizontal sync
	output wire			lcd_vs,	    	//lcd vertical sync
	output wire			lcd_en,			//lcd display enable
	output wire	[23:0]	lcd_rgb,		//lcd display data

	//user interface
	output wire	[11:0]	lcd_xpos,		//lcd horizontal coordinate
	output wire	[11:0]	lcd_ypos		//lcd vertical coordinate
);	
 
localparam	H_AHEAD = 	12'd1;

reg [11:0] hcnt; 
reg [11:0] vcnt;
wire lcd_request;

/*******************************************
		SYNC--BACK--DISP--FRONT
*******************************************/ 
//h_sync counter & generator
always @ (posedge clk or negedge rst_n)
begin
	if (!rst_n)
		hcnt <= 12'd0;
	else
	begin
        if(hcnt < H_TOTAL - 1'b1)		//line over			
            hcnt <= hcnt + 1'b1;
        else
            hcnt <= 12'd0;
	end
end 

assign	lcd_hs = (hcnt <= H_SYNC - 1'b1) ? 1'b0 : 1'b1; // line over flag

//v_sync counter & generator
always@(posedge clk or negedge rst_n)
begin
	if (!rst_n)
		vcnt <= 12'b0;
	else if(hcnt == H_TOTAL - 1'b1)	//line over
		begin
		if(vcnt == V_TOTAL - 1'b1)		//frame over
			vcnt <= 12'd0;
		else
			vcnt <= vcnt + 1'b1;
		end
end

assign	lcd_vs = (vcnt <= V_SYNC - 1'b1) ? 1'b0 : 1'b1; // frame over flag

// LED clock
assign	lcd_dclk = ~clk;

// Control Display
assign	lcd_en		=	(hcnt >= H_SYNC + H_BACK  && hcnt < H_SYNC + H_BACK + H_DISP) &&
						(vcnt >= V_SYNC + V_BACK  && vcnt < V_SYNC + V_BACK + V_DISP) 
						? 1'b1 : 1'b0;                   // Display Enable Signal
						
assign	lcd_rgb 	= 	lcd_en ? lcd_data : 24'h000000;	

//ahead x clock
assign	lcd_request	=	(hcnt >= H_SYNC + H_BACK - H_AHEAD && hcnt < H_SYNC + H_BACK + H_DISP - H_AHEAD) &&
						(vcnt >= V_SYNC + V_BACK && vcnt < V_SYNC + V_BACK + V_DISP) 
						? 1'b1 : 1'b0;
//lcd xpos & ypos
assign	lcd_xpos	= 	lcd_request ? (hcnt - (H_SYNC + H_BACK - H_AHEAD)) : 12'd0;
assign	lcd_ypos	= 	lcd_request ? (vcnt - (V_SYNC + V_BACK)) : 12'd0;

endmodule
module VGA_Demo
( 
	input  wire			clk_24m,
	input  wire			rst_n,
	
	//lcd interface
	output wire			vga_clk,	//lcd pixel clock			
	output wire			vga_hs,		//lcd horizontal sync 
	output wire			vga_vs,		//lcd vertical sync

    output wire			vga_de,		//lcd data enable
    
	output wire [7:0]  	vga_r,		//lcd red data
	output wire [7:0]	vga_g,		//lcd green data
	output wire [7:0]	vga_b		//lcd blue data
);

wire	clk_vga;
wire	[11:0]	lcd_xpos;		//lcd horizontal coordinate
wire	[11:0]	lcd_ypos;		//lcd vertical coordinate
wire	[23:0]	lcd_data;		//lcd data

//sync global clock and reset signal 
Clk_div	u0_PLL
(
	.clk			(clk_24m	), 
	.rst_n			(rst_n		),	

	.clk_div		(clk_vga	)
);

//VGA driver timing
Driver u1_Driver
(
// Input
	.clk			(clk_vga				),		
	.rst_n			(rst_n					),  
	.lcd_data		(lcd_data				),
// Output 	
	.lcd_dclk		(vga_clk				),		    	
	.lcd_hs			(vga_hs					),		
	.lcd_vs			(vga_vs					),
	.lcd_en			(vga_de					),		
	.lcd_rgb		({vga_r, vga_g ,vga_b}	),	
	.lcd_xpos		(lcd_xpos				),	
	.lcd_ypos		(lcd_ypos				)
);

//lcd data simulation
Display	u2_Display
(
// Input
	.clk			(clk_vga		),		
	.rst_n			(rst_n			), 	
	.lcd_xpos		(lcd_xpos		),	
	.lcd_ypos		(lcd_ypos		),
// Output 	
	.lcd_data		(lcd_data		)
);

endmodule