/*
 * File:        pippo_if.v
 * Project:     pippo
 * Designer:    kiss@pwrsemi
 * Mainteiner:  kiss@pwrsemi
 * Checker: 
 * Assigner:
 * Description:
    Ò»£¬IF¶ÎµÄÖ÷Òª¹¦ÄÜÈçÏÂ
        1£¬	Á¬½ÓÁ÷Ë®ÏßºÍi-side IMX²¿¼þ£º·¢ËÍÈ¡Ö¸µØÖ·ÒÔÈ¡»ØÖ¸Áî£»½«È¡»ØÖ¸ÁîºÍÖ¸ÁîµØÖ·ËÍÈëÁ÷Ë®Ïß¼Ä´æÆ÷£»
        2£¬	¸üÐÂºÍÎ¬»¤PCÖµ
        3£¬	´¦ÀíºóÐøÁ÷Ë®Ïß·¢³öµÄÌø×ªÇëÇó
        4£¬	Èç¹ûIF¶ÎÓÐexception·¢Éú£¬½«Ïà¹ØÇëÇóÐÅºÅËÍÖÁºó¶ËÁ÷Ë®µÈ´ýexceptÄ£¿éÍ³Ò»´¦Àí
    ¶þ£¬Éè¼Æ¹æ·¶
    NPCµÄÀ´Ô´·ÖÀà£º
        1£¬	Ë³ÐòÈ¡Ö¸£¬PC+4
        2£¬	·ÖÖ§Ìø×ª£¬npc_branchÀ´×Ô·ÖÖ§´¦ÀíÄ£¿é(¸ù¾ÝEXE¶ÎÖ´ÐÐ½á¹û´ÓÌø×ªÄ¿±êµØÖ·»òSNIAÖÐÑ¡Ôñ)
        3£¬	ÖÐ¶Ï´¦Àí£¬npc_exceptÀ´×ÔÖÐ¶Ï´¦ÀíÄ£¿é£¬ÎªÖÐ¶Ï´¦Àí³ÌÐòÈë¿ÚµØÖ·
        4£¬	ÌØÊâÖ¸ÁîÖ´ÐÐ£¨rfi/rfciµÈ£©£¬npc_instÀ´×Ôsrr0/srr2¼Ä´æÆ÷£¨Î»ÓÚexceptÄ£¿é£©£»
        5£¬ Í¬²½Ö¸ÁîÖ´ÐÐ£¨ÏÔÐÔÖ¸Áîisync/eieio/syncºÍmtmsrµÈÒþÐÔÖ¸Áî£©£¬npc_syncÀ´×ÔÍ¬²½Ö¸ÁîµÄSNIA£»
    PCÎ¬»¤ºÍ¸üÐÂ£º
        1£¬ Õý³£Çé¿ö£­Ë³ÐòÖ¸ÁîÁ÷£¬Ê¹ÓÃNPC¸üÐÂPC¼Ä´æÆ÷
        2£¬ Ë³ÐòÖ¸ÁîÁ÷Ë®Ïß¶³½áÊ±£¬±£³ÖÏÖÓÐPCÖµ£¬µÈ´ý¶³½á½â³ýºó¼ÌÐøÈ¡Ö¸            
        3£¬ Ö¸ÁîÁ÷±ä»»
            1£©ÖÐ¶Ï´¦Àí£ºEXE¶Î£¬ÖÐ¶Ï´¦Àí¿ªÊ¼£¨°üÀ¨rfi/rfci£©£¬·¢³öflush_exceptÐÅºÅ£»µÈ´ýnpc_exceptÓÐÐ§ºó¸üÐÂPC²¢È¡Ö¸
            2£©·ÖÖ§Ö¸Áî´¦Àí£­ÏÖ²ÉÓÃa·½°¸
                a£©²ÉÓÃ¾²Ì¬·ÖÖ§Ô¤²â¼¼Êõ£¬ËùÓÐ·ÖÖ§Ö¸Áî¶¼Ô¤²âÎªNT¡£µ±ÔÚEXE¶Î»ñÈ¡·ÖÖ§½á¹ûÎªTakenÊ±£¬·¢³öflush_branchÐÅºÅ£¬
                   È»ºóµÈ´ýnpc_branchÓÐÐ§ºó¸üÐÂPC²¢È¡Ö¸¡£µ±Ô¤²âÕýÈ·Ê±£¬°´ÕÕÈçÉÏË³ÐòÖ¸ÁîÁ÷´¦Àí·½·¨¡£
                b£©ID¶Î·¢ÏÖ·ÖÖ§Ö¸Áî£¬·¢³öbp_stallÐÅºÅ£¬´ËÊ±ÏÂÒ»ÌõÖ¸ÁîµÄÈ¡Ö¸ÉÐÎ´Íê³É£¨Ëø´æ½øÈëÁ÷Ë®Ïß£©¡£
                   ¸ù¾ÝEXE¶Î½á¹û£º
                        branch_taken    Ìø×ª¡£Ê¹ÓÃnpc_branch¸üÐÂpc²¢È¡Ö¸
                        branch_nt       ²»Ìø×ª¡£Ê¹ÓÃÏÖpcÈ¡Ö¸ 
            ×¢£ºflushpipeÐÅºÅÎªÒÔÉÏÁ½ÖÖÇé¿öµÄ×ÛºÏ£¬ÓÉpipectrlÄ£¿é²úÉú
    IMX½Ó¿Ú´¦Àí£­°üº¬¸´ÔÓµÄ·Ö²¼Ê½Ð­Í¬
        È¡Ö¸ÇëÇóµÄ·¢ËÍ£­¸ù¾Ý´¦ÀíÆ÷Á÷Ë®Ïß×´Ì¬ºÍIMX·µ»ØµÄ×´Ì¬£¬Í¬²½¸üÐÂÈ¡Ö¸ÇëÇóºÍÈ¡Ö¸µØÖ·£¨PC£©
            rqt_validÂß¼­£­È¡¾öÓÚÁ÷Ë®Ïß×´Ì¬
            PC¸üÐÂÂß¼­£­È¡¾öÓÚÁ÷Ë®Ïß×´Ì¬ºÍIMX·µ»Ø×´Ì¬
        È¡Ö¸ÏìÓ¦µÄ½ÓÊÕ£­Í¬ÑùÐèÒª¸ù¾Ý´¦ÀíÆ÷Á÷Ë®Ïß×´Ì¬ºÍIMX·µ»ØµÄ×´Ì¬£¬¾ö¶¨ÊÇ·ñ¼Ä´æµ±Ç°ÏìÓ¦½øÈëÁ÷Ë®Ïß
            È¡Ö¸ÇëÇóµÄÈ¡ÏûºÍ±ä»»Çé¿öµÄ´¦Àí
            ÓÐÐ§·µ»Ø²¢²»Ò»¶¨»á½øÈëÁ÷Ë®Ïß
    Èý£¬IF/IDÁ÷Ë®¼Ä´æÆ÷Âß¼­-Á÷Ë®Êä³ö°üÀ¨id_valid, id_inst, id_cia, id_snia£»Á÷Ë®Î¬»¤ºÍ¸üÐÂ²ßÂÔ²Î¿¼pipectrlÄ£¿é£¬»ù±¾ÈçÏÂ£º
        1£¬ Õý³£Çé¿ö£­È¡Ö¸³É¹¦£¬ÇÒÁ÷Ë®ÏßÕý³££º¼Ä´æ²¢ËÍ³öÈ¡»ØÖ¸Áî
        2£¬ ÖÐ¶Ï´¦Àí¿ªÊ¼£¬exceptÄ£¿é·¢³öflushpipeÐÅºÅÒÔË¢ÐÂÁ÷Ë®Ïß£º²åÈëNOP£¬²¢ÖÃid_validÎªÎÞÐ§
        3£¬ µ±Á÷Ë®Ïß¶³½á£¨if_freeze»òid_freezeÓÐÐ§£©Ê±£¬IF/ID²åÈëNOP»òKCS bubble
            °üÀ¨µÈ´ý×ÜÏßÏìÓ¦£¨ack_i/err_iÎÞÐ§£¬¼´if_stall£©£¬¶øÆäËûÕý³£Ê±£»
 * Task.I:
        [TBD]imxÐ­ÒéÑéÖ¤ºÍ¸Ä½ø
            Ä¿Ç°i-imx²ÉÓÃ·ÖÀëµÄµØÖ·ºÍÊý¾Ýtsc´«Êä£¬²¢Ö§³ÖÒ»¼¶pipeling·½Ê½£»
                Ä¿Ç°rqt_valid×ÜÊÇÓÐÐ§£­³ýÁ÷Ë®ÏßË¢ÐÂ(flushpipe)ºÍ¶³½á(id_freeze)Ê±£»
                ÔÚslave·µ»ØµØÖ·ÏìÓ¦(!rty_i)ºó£¬PC¸üÐÂ£¬·¢³öÐÂµÄµØÖ·ÇëÇó£­¼ä½Ó±£Ö¤²»»áÖØ¸´ËÍ³öÖ®Ç°µÄµØÖ·ÇëÇó
                Èç¹ûÔÚµØÖ·ÏìÓ¦ºÍÊý¾ÝÏìÓ¦Ö®¼ä²åÈëµÈ´ýÖÜÆÚ(¼´!rty_iºÍack_iÖ®¼ä)£¬slaveÐë±£Ö¤¹¤×÷Õý³££­ÇëÇóÍê³ÉË³Ðò
            ¼õÉÙimc·µ»ØµÄaddrÎ»¿í£¬»òÕß[1:0]Ò²²»ÐèÒª£»
            µØÖ·ÇëÇóºÍÏìÓ¦£¨rqt->!rty_i£©Âß¼­»ØÂ·£­Ä£¿éÖ®¼ä¶¼ÊÇ×éºÏÂß¼­£¨fetcherºÍbiu/imc£©£¬ÇÒÐè×¢ÒâÏßÑÓÊ±£»
            ¸´Î»Çé¿öµÄÑéÖ¤£­slave±ØÐëÍ¬²½£¬±ÜÃâÈ¡»Ø¸´Î»Ö®Ç°ÇëÇóµÄÊý¾Ý£»
            IMXÏÂµØÖ·½×¶ÎºÍÊý¾Ý½×¶ÎÍ¬Ê±½áÊøµÄÇé¿ö´¦Àí£¬¼´(!rty)ºÍackÍ¬Ê±ÓÐÐ§
            ºÍwbv4¹æ·¶µÄÒìÍ¬
                ÊÇ·ñÉèÖÃtsc_busyÎ»±íÊ¾×ÜÏß´«Êä½øÐÐÖÐ£»
                ´ý±È½Ïwb¹æ·¶ÖÐ!rty_iµÄÊ±ÐòÎÊÌâ£­ºÍack_iµÄ¹ØÏµ£»
        [TBV]È¡Ö¸Âß¼­ÔÚÈ¡Ö¸¶³½á£¬Á÷Ë®ÏßË¢ÐÂ£¬if_stallºÍµ±Ç°È¡Ö¸Ëù´¦½×¶ÎµÈ¸÷ÖÖÇé¿ö½áºÏÏÂµÄ´¦ÀíºÍÉè¼ÆÑéÖ¤
            ¼´PCµÄÎ¬»¤£¨°üÀ¨NPCÂß¼­£©ºÍrqt_validµÄÍ¬²½¸üÐÂ±ØÐë±£Ö¤
                1£¬·¢³öÕýÈ·µÄÈ¡Ö¸ÇëÇó£­¸ù¾Ýµ±Ç°Á÷Ë®Ïß×´Ì¬£»
                2£¬½ö¼Ä´æÒ»´ÎÖ¸Áî½øÈëÁ÷Ë®Ïß£»
                3£¬²»»á·¢ÉúÖØ¸´È¡Ö¸ºÍ²»»á¶ªÊ§È¡»ØµÄÖ¸Áî£»
        [TBD]µ±Á÷Ë®Ïß·µ»ØÈ¡Ö¸´íÎó£¨err_i£©Ê±£¬ÏàÓ¦exceptÇëÇóÔÚEXE¶Î½«µÃµ½´¦Àí£»ciaËÍÈëÁ÷Ë®Ïß£¬ÖÃid_validÎª0£»
            err_iÈ¡»ØµÄÊý¾ÝÊÇÊ²Ã´£¿ËÍÈëÁ÷Ë®Ïß»áÔÚid¶Î²úÉúÆäËûÐÐÎª£¿
            ¿¼ÂÇ²åÈëNOPÒÔ±ÜÃâ´íÎóÊý¾ÝµÄ¸±×÷ÓÃ£¬»òÓÃid_validÖÃËùÓÐid¶ÎÊä³öÎªÎÞÐ§£»
        [TBV] imx, pipelining and PC bahavior
            1. npc_branch, npc_except can't assert simultaneously
            2. after recover from freezing, first fetch request from previous pc/npc?
            3. the case of canceling fetch request(cache miss, and inst transfer event happened)
                processing by imx protocol: diassert rqt, then diassert ack.
            4. check id_snia timing
            5. coding style of pipelining register
        [TBD]make "itlb, immu" logic conditional
 * Task.II:
 *      full synthesis & verification
 *      rtl performance refactor-improve speed, reduce power and area.
 *      to improve fetch performance, add buffer to register fetched instruction and address at some case
 */

// synopsys translate_off
`include "timescale.v"
// synopsys translate_on
`include "def_pippo.v"

module pippo_if(

	clk, rst,

	iimx_adr_o, iimx_rqt_o, iimx_rty_i, 
	iimx_ack_i, iimx_err_i, iimx_dat_i, iimx_adr_i, 

	npc_branch, npc_except, npc_branch_valid, npc_except_valid, 
	
	pc_freeze, if_stall, if_freeze, id_freeze, flushpipe, 
	
	id_inst, id_cia, id_valid, id_snia,
	
	id_sig_ibuserr
);

input				clk;
input				rst;

// IMX I/F to fetch instructions (from cache/ocm/memory controller)
input	[31:0]		iimx_dat_i;
input				iimx_ack_i;
input				iimx_err_i;
input	[31:0]		iimx_adr_i;
input				iimx_rty_i;
output	[31:0]		iimx_adr_o;
output				iimx_rqt_o;

// inst. flow transfer
input   [29:0]      npc_branch;         
input               npc_branch_valid;   
input   [31:0]      npc_except;         // keep least two address bits to code ISR entrance easily.
input               npc_except_valid;   

// pipeline control
input               pc_freeze;          
input				if_freeze;        
input				id_freeze;          
input				flushpipe;
output				if_stall;           

// pipeling register
output              id_valid;           
output	[31:0]		id_inst;            
output	[29:0]		id_cia;             
output	[29:0]		id_snia;            

// exception request
output				id_sig_ibuserr;     

//
// 
//
reg                 id_valid;
reg     [31:0]		id_inst;
reg     [29:0]		id_cia;
reg     [29:0]		id_snia;
reg                 id_sig_ibuserr;

reg     [31:0]      npc_value; 
reg                 if_valid;
reg     [31:0]      if_inst;          
reg     [29:0]      if_cia;
reg                 if_sig_ibuserr; 
reg	    [31:0]		pc;
wire                if_rqt_valid; 
wire    [32:0]      pcadd4;             
wire                except_ibuserr;

//
// send fetch rqt to I-IMX
//
assign iimx_adr_o = pc; 
assign iimx_rqt_o = if_rqt_valid; 

// stall request, waiting for I-IMX response 
assign if_stall = ~iimx_ack_i; 

//
// PC Register logic
//

// NPC source
assign pcadd4={(pc[31:2]+31'd1), 2'b00};

// 
assign fetch_lost = id_freeze & iimx_ack_i;

always @(npc_branch_valid or npc_except_valid or id_freeze or iimx_adr_i or
        fetch_lost or npc_branch or npc_except or pc or pcadd4) begin
	casex ({npc_branch_valid, npc_except_valid, id_freeze, fetch_lost})	// synopsys parallel_case
	    4'b0000: begin
	        npc_value = pcadd4[31:0];
	    end
		4'b0100: begin
			npc_value = npc_except;
		end
		4'b1000: begin
			npc_value = {npc_branch, 2'b00};
		end
		4'b0010: begin                   // if pipeline(if_freeze & id_freeze) is freezon, keep current pc
			npc_value = pc;
		end		
		4'b0011: begin
		    npc_value = iimx_adr_i;     // fetch current fetched instruction again
        end
        
		default: begin     
			npc_value = pc;
		end		
    endcase
end

//
// PC update policy
//
//  1. after hard reset, keep RESET_VECTOR (pcadd4[32]) to avoid overflow
//  2. update pc when 
//      a) flushpipe: flush pipeline, fetch with npc
//      b) !iimx_rty_i: current transaction is complete
//      c) fetch lost
always @(posedge clk or posedge rst) begin
    if (rst)
        pc <= #1 `pippo_RESET_VECTOR;
    else if (pcadd4[32] & !flushpipe)   // !flushpipe: keep normal when fetched first branch inst
        pc <= #1 `pippo_RESET_VECTOR;
    else if (flushpipe | (!iimx_rty_i) | fetch_lost) 
        pc <= #1 npc_value;
end

//
// inst. fetch request logic: if_rqt_valid signal
//  1. when flushpipe assert(pc_freeze asserts), if_rqt_valid disassert
//  2. when pipeline freeze(id_freeze freeze), if_rqt_valid disassert to reduce memory access
//          NOT use if_freeze signal to exclude if_stall deadlock, or additional logic is needed for biu
//          deadloack: if_freeze assert at wait state, if you diassert this request, system stop forever.
//  3. hard-reset case: if_rqt_valid assert until RESET_VECTOR's ack(!iimx_rty_i) come, then keep disassertion.
//  At normal state, always send fetch request - if_rqt_valid keep assert, when address ack(!iimx_rty_i) assert
//     or disassert. including case that if_stall asserts, to avoid deadlock: no new fetch send out
//          deadlock: (if_stall raised -> if_freeze assert -> rqt_valid disassert forever)

// after hard reset, to avoid fetch reset vector many times, 
//      "!flushpipe" logic is to reduce one cycle delay after reset vector's branch
reg rst_rqt_done;
always @(posedge clk or posedge rst) begin
    if (rst)
        rst_rqt_done <= #1 1'b0;
    else if (flushpipe)
        rst_rqt_done <= #1 1'b0;    
    else if (pcadd4[32] & !iimx_rty_i)
        rst_rqt_done <= #1 1'b1;     
end

// to check the timing of rqt_valid signal - rqt_valid must have budget for addr_ack logic, i.e.:
// at IMX address phase(cycle 1):
//      Master send out if_rqt_valid, slave check address and give back addr_ack;
//      Addr_ack(!iimx_rty_i) signal must satisfy the setup time, when inputting to master;
// [TBD] register out if_rqt_valid signal to improve timing, add a pipeline bubble under some case
//      note: keep pace with pc update
assign if_rqt_valid = !(pc_freeze | id_freeze | (pcadd4[32] & rst_rqt_done));

//
// IF/ID pipelining logic
//
always @(iimx_ack_i or if_freeze or id_freeze or flushpipe or
        if_valid or if_inst or if_cia or 
        id_valid or id_inst or id_cia or 
        iimx_dat_i or iimx_adr_i or 
        except_ibuserr or id_sig_ibuserr) begin
	casex ({iimx_ack_i, if_freeze, id_freeze, flushpipe})	// synopsys parallel_case
		4'b1000: begin       // Normal pipelining. I-IMX returns valid value
            if_valid = 1'b1; 
            if_inst = iimx_dat_i;
            if_cia = iimx_adr_i[31:2];
            if_sig_ibuserr = except_ibuserr;
		end
		4'bxxx1: begin       // flushpipe is asserted, insert NOP bubble
            if_valid = 1'b0; 
            if_inst = `pippo_PWR_NOP;
            if_cia = id_cia;
            if_sig_ibuserr = 1'b0;
		end
		4'bx100: begin       // if_freeze is asserted, id_freeze is disasserted, insert NOP bubble
            if_valid = 1'b0; 
            if_inst = `pippo_PWR_NOP;
            if_cia = id_cia;
            if_sig_ibuserr = 1'b0;
		end
		4'bx110: begin       // if_freeze/id_freeze is asserted, insert KCS bubble
            if_valid = id_valid; 
            if_inst = id_inst;
            if_cia = id_cia;
            if_sig_ibuserr = id_sig_ibuserr;
		end
		default: begin      // [TBV]iimx_err_i is asserted
            if_valid = 1'b0;     
            if_inst = `pippo_PWR_NOP;
            if_cia = id_cia;
            if_sig_ibuserr = except_ibuserr;
		end		
    endcase
end

always @(posedge clk or posedge rst) begin
    if(rst) begin
        id_valid <= #1 1'b0;
        id_inst <= #1 `pippo_PWR_NOP;
        id_cia <= #1 30'd0;
        id_snia <= #1 30'd0; 
        id_sig_ibuserr = 1'b0;
    end
    else begin
        id_valid <= #1 if_valid;
        id_inst <= #1 if_inst;
        id_cia <= #1 if_cia;
        id_snia <= #1 pcadd4[31:2]; 
        id_sig_ibuserr = if_sig_ibuserr;
        `ifdef pippo_VERBOSE
        // synopsys translate_off
            $display("%t: id_valid <= %h", $time, id_valid);
            $display("%t: id_inst <= %h", $time, id_inst);
            $display("%t: id_cia <= %h", $time, id_cia);
            $display("%t: id_snia <= %h", $time, id_snia);
        // synopsys translate_on
        `endif
    end
end

//
// except request from IF stage
//
assign except_ibuserr = iimx_err_i & iimx_ack_i;    // err valid only when ack assert

endmodule


