`define addr_bits 19

/*
--****************************************************************************
-- IMPORTANT-READ THESE TERMS CAREFULLY BEFORE UTILIZING THE INFORMATION
-- CONTAINED IN THIS APPLICATION NOTE. 
--
-- NO SUPPORT/NO WARRANTY. THE DESIGN FILES AND DOCUMENTATION ARE PROVIDED
-- WITHOUT SUPPORT OR WARRANTY OF ANY KIND. ACTEL IS NOT OBLIGATED TO 
-- PROVIDE UPDATES, BUG FIXES, OR TECHNICAL SUPPORT AND DISCLAIMS ALL 
-- WARRANTIES INCLUDING, WITHOUT LIMITATION, THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE, AND WARRANTIES OF NON-INFRINGEMENT OF THE
-- RIGHTS OF THIRD PARTIES (INCLUDING, WITHOUT LIMITATION, RIGHTS UNDER PATENT,
-- COPYRIGHT, TRADE SECRET, OR OTHER INTELLECTUAL PROPERTY RIGHTS).  RECIPIENT
-- ACCEPTS THE APPLICATION NOTE DESIGN FILES AND DOCUMENTATION IN "AS-IS"
-- CONDITION.
--*****************************************************************************
*/

module MasterSerial(SCK, INIT,DONE, SDO);

//Inputs
input SCK;
input INIT; //ative low signal. can be used as a system reset 
input DONE; //when the programmed is completed, SRAM FPGA drive this to '1'

//Outputs
output SDO;
reg SDO;


//Internals
wire term_cnt;
wire [7:0] rom_data_1, rom_data_2, rom_data_o;
wire [(`addr_bits-1):0] rom_addr;
wire SDO_buf;
wire INIT;
wire CLK100MHz;
wire CLK60MHz;
reg rom_cs;

//Component instantiation
//generate the load signal every 8 bits to load the shift register with the NVM data
//rom_addr is generated for the NVM read address
counter u1(.clk(SCK),
	     .init(INIT),
	     .load(load),
	     .term_cnt(term_cnt),
	     .Q(rom_addr)
	     );

//load 8 bits of data from the NVM and shift it out (MSB first)  	     
ShiftReg u2(.d_in(rom_data_o),
         .init(INIT),
         .load(load),
         .clk(SCK), 
         .d_out(SDO_buf)
         );

//100 MHz clock source
//Created by Smartgen
RC_Oscillator RC(.CLKOUT(CLK100MHz));

//generate a fast clock for the NVM read. 
//OADIVRST - active low reset for the back end divider
//Created by Smartgen
PLL_100_60 myPLL(.POWERDOWN(1'b1),.CLKA(CLK100MHz), .LOCK(),.GLA(CLK60MHz),.OADIVRST(INIT)); 

//NVM block 1 - store the first half of the configuration data
//Created by Smartgen
NVM1 mFlashMemory1(.USER_CLK(CLK60MHz), 
						.USER_RESET(rom_cs), 
						.USER_ADD(rom_addr[17:0]), 
						.USER_AUX_BLOCK(1'b0), 
						.USER_DATA(rom_data_o), 
						.USER_DISCARD_PAGE(1'b0), 
						.USER_ERASE_PAGE(1'b0), 
						.USER_OVERWRITE_PAGE(1'b0), 
						.USER_OVERWRITE_PROT(1'b0), 
						.USER_PAGELOSS_PROT(1'b0), 
						.USER_PROGRAM(1'b0), 
						.USER_READ(1'b1), 
						.USER_READ_NEXT(1'b0), 
						.USER_LOCK(1'b0), 
						.USER_SPARE_PAGE(1'b0), 
						.USER_UNPROT_PAGE(1'b0), 
						.USER_WIDTH(2'b00), //Input: 00 - 1 byte, 01 - 2 byte, 10 - 4 byte
						.USER_WRITE(1'b0), 
						.USER_DOUT(rom_data_1), 
						.USER_PAGE_STATUS(1'b0), 
						.USER_NVM_STATUS(), 
						.USER_NVM_BUSY());

//NVM block 2 - store the second half of the configuration data
//Created by Smartgen
NVM2 mFlashMemory2(.USER_CLK(CLK60MHz), 
						.USER_RESET(rom_cs), 
						.USER_ADD(rom_addr[17:0]), 
						.USER_AUX_BLOCK(1'b0), 
						.USER_DATA(rom_data_o), 
						.USER_DISCARD_PAGE(1'b0), 
						.USER_ERASE_PAGE(1'b0), 
						.USER_OVERWRITE_PAGE(1'b0), 
						.USER_OVERWRITE_PROT(1'b0), 
						.USER_PAGELOSS_PROT(1'b0), 
						.USER_PROGRAM(1'b0), 
						.USER_READ(1'b1), 
						.USER_READ_NEXT(1'b0), 
						.USER_LOCK(1'b0), 
						.USER_SPARE_PAGE(1'b0), 
						.USER_UNPROT_PAGE(1'b0), 
						.USER_WIDTH(2'b00), //Input: 00 - 1 byte, 01 - 2 byte, 10 - 4 byte
						.USER_WRITE(1'b0), 
						.USER_DOUT(rom_data_2), 
						.USER_PAGE_STATUS(1'b0), 
						.USER_NVM_STATUS(), 
						.USER_NVM_BUSY());

//MUX - switch between NVM1 or NVM2 depending on rom_addr[18]
assign rom_data_o = (rom_addr[18]) ? rom_data_2 : rom_data_1;

always @(SDO_buf)
begin
if ((~term_cnt) & (~DONE))
  SDO = SDO_buf;
else 
  SDO = 1'bz;
end

always @(term_cnt)
begin
	if(term_cnt)
		rom_cs <= 1'b0;
	else
		rom_cs <= 1'b1;
end

endmodule
  
         	    




