int sc_main(int, char *[])
{
  // Silence the following deprecation warning:
  // Info: (I804) /IEEE_Std_1666/deprecated: positional binding
  // using << or , is deprecated, use () instead.


  sc_report_handler::set_actions("/IEEE_Std_1666/deprecated", SC_DO_NOTHING);

  // ************************ ICACHE ***********************************
  // ICACHE = ram_cs
  // ICACHE = ram_we
  // ICACHE = addr
  // ICACHE = ram_datain
  // ICACHE = ram_dataout
  // ICACHE = ld_valid = pid_valid
  // ICACHE = ld_data = pid_data
  sc_signal<bool>       icache_valid("ICACHE_VALID") ;

  // ************************ BIOS ***********************************
  sc_signal<bool>       ram_cs("RAM_CS") ;
  sc_signal<bool>       ram_we("RAM_WE") ;
  sc_signal<unsigned >    addr("Address") ;
  sc_signal<unsigned >    ram_datain("RAM_DATAIN") ;
  sc_signal<unsigned >    ram_dataout("RAM_DATAOUT") ;
  sc_signal<bool>       bios_valid("BIOS_VALID") ;
  const int delay_cycles = 2;

  // ************************ Paging ***********************************
  // Paging paging_din = ram_datain
  // Paging paging_csin = ram_cs
  // Paging paging_wein = ram_we
  // Paging logical_address = addr 
  sc_signal<unsigned >    icache_din("ICACHE_DIN") ;
  sc_signal<bool>       icache_validin("ICACHE_VALIDIN") ;
  sc_signal<bool>       icache_stall("ICACHE_STALL") ;
  sc_signal<unsigned >    paging_dout("PAGING_DOUT") ;
  sc_signal<bool>       paging_csout("PAGING_CSOUT") ;
  sc_signal<bool>       paging_weout("PAGING_WEOUT") ;
  sc_signal<unsigned >    physical_address("PHYSICAL_ADDRESS") ;
  // Paging dataout  = ram_dataout 
  // Paging data_valid = icache_valid
  // Paging stall_ifu = stall_fetch


  // ************************ Fetch ***********************************
  // IFU ramdata = ram_dataout
  sc_signal<unsigned >    branch_target_address("BRANCH_TARGET_ADDRESS") ;
  sc_signal<bool>       next_pc("NEXT_PC") ;
  sc_signal<bool>       branch_valid("BRANCH_VALID") ;
  sc_signal<bool>       stall_fetch("STALL_FETCH") ;
  sc_signal<bool>       pred_fetch("PRED_FETCH") ;
  // IFU ram_valid = bios_valid
  // IFU ram_cs = ram_cs
  // IFU ram_we = ram_we
  // IFU address = addr
  // IFU smc_instrction = ram_datain
  // IFU pred_branch_address = pred_branch_address
  // IFU pred_branch_valid = pred_branch_valid
  sc_signal<unsigned>   instruction("INSTRUCTION") ;
  sc_signal<bool>       instruction_valid("INSTRUCTION_VALID") ;
  sc_signal<unsigned >    program_counter("PROGRAM_COUNTER") ;
  sc_signal<bool>       branch_clear("BRANCH_CLEAR") ;
  sc_signal<bool>       pred_fetch_valid("PRED_FETCH_VALID") ;
  sc_signal<bool>       reset("RESET") ;

  // ************************ Branch ***********************************
  // BPU: fetch_inst = instruction
  // BPU: fetch_pc = program_counter
  // BPU: fetch_valid = instruction_valid
  // BPU: branch_inst_addr = branch_instruction_address
  // BPU: branch_target_address = branch_target_address
  // BPU: branch_valid = branch_valid
  sc_signal<unsigned >	pred_branch_address("PRED_BRANCH_ADDRESS");
  sc_signal<bool>       pred_branch_valid("PRED_BRANCH_VALID") ;
  sc_signal<bool>       pred_tellid("PRED_TELLID") ;
  sc_signal<unsigned>   pred_instruction("PRED_INSTRUCTION") ;
  sc_signal<bool>       pred_inst_valid("PRED_INST_VALID") ;
  sc_signal<unsigned >	pred_inst_pc("PRED_INST_PC");


  // ************************ Decode ***********************************
  // ID instruction = instruction
  // ID instruction = instruction_valid
  // ID destreg_write = out_valid
  // ID destreg_write_src = destout
  // ID clear_branch     = branch_clear 
  // ID pc = program_counter
  sc_signal<bool>       pred_on("PRED_ON") ;
  sc_signal<unsigned >	branch_instruction_address("BR_INSTRUCTION_ADDRESS");
  // ID alu_dataout = dout from EXEC 
  sc_signal<signed>     dram_dataout("DRAM_DATAOUT") ;
  sc_signal<bool>       dram_rd_valid("DRAM_RD_VALID") ;
  sc_signal<unsigned>   dram_write_src("DRAM_WRITE_SRC");
  // ID next_pc     = next_pc
  // ID branch_valid = branch_valid
  // ID branch_target_address = branch_target_address
  sc_signal<bool>       mem_access("MEM_ACCESS") ;
  sc_signal<unsigned >    mem_address("MEM_ADDRESS") ;
  sc_signal<int>        alu_op("ALU_OP") ;
  sc_signal<bool>       mem_write("MEM_WRITE") ;
  sc_signal<unsigned>   alu_src("ALU_SRC") ;
  sc_signal<bool>       reg_write("REG_WRITE") ;
  sc_signal<signed int> src_A("SRC_A") ;
  sc_signal<signed int> src_B("SRC_B") ;
  sc_signal<bool>       forward_A("FORWARD_A") ;
  sc_signal<bool>       forward_B("FORWARD_B") ;
  // ID stall_fetch = stall_fetch
  sc_signal<bool>       decode_valid("DECODE_VALID") ;
  sc_signal<bool>       float_valid("FLOAT_VALID") ;
  sc_signal<bool>       mmx_valid("MMX_VALID") ;
  sc_signal<bool>       pid_valid("PID_VALID") ;
  sc_signal<signed>     pid_data("PID_DATA") ;

  // ************************ DCACHE  ***********************************
  sc_signal<signed>       mmic_datain("MMIC_DATAIN") ;	/* DCU: datain 	*/
  sc_signal<unsigned>     mmic_statein("MMIC_STATEIN") ;/* DCU: statein */
  sc_signal<bool>     	  mmic_cs("MMIC_CS") ;		/* DCU: cs 	*/
  sc_signal<bool>     	  mmic_we("MMIC_WE") ;		/* DCU: we 	*/
  sc_signal<unsigned >      mmic_addr("MMIC_ADDR") ; /* DCU: addr	*/
  sc_signal<unsigned>     mmic_dest("MMIC_DEST") ;	/* DCU: dest 	*/
  sc_signal<unsigned>     mmic_destout("MMIC_DESTOUT") ;/* DCU: destout */
  sc_signal<signed>       mmic_dataout("MMIC_DATAOUT") ;/* DCU: dataout */
  sc_signal<bool>         mmic_out_valid("MMIC_OUT_VALID") ;/* DCU: out_valid*/
  sc_signal<unsigned>     mmic_stateout("MMIC_STATEOUT") ;/* DCU: stateout */

  // ************************ Execute ***********************************
  // EXEC in_valid = decode_valid
  sc_signal<bool>   	in_valid("IN_VALID") ;
  // EXEC opcode = alu_op
  sc_signal<bool>   	negate("NEGATE") ;
  sc_signal<int>   	add1("ADD1") ;
  sc_signal<bool>   	shift_sel("SHIFT_SEL") ;
  // EXEC dina = src_A
  // EXEC dinb = src_B
  // EXEC dest = alu_src
  sc_signal<bool>   		c("C") ;
  sc_signal<bool>   		v("V") ;
  sc_signal<bool>   		z("Z") ;
  sc_signal<signed>   		dout("DOUT") ;
  sc_signal<bool>   		out_valid("OUTPUT_VALID") ;
  sc_signal<unsigned> 		destout("DESTOUT") ;

  // ************************ Floating point ******************************
  // FPU in_valid = float_valid
  // FPU opcode = alu_op
  // FPU floata = src_A
  // FPU floatb = src_B
  // FPU dest = alu_src
  sc_signal<signed> 		fdout("FDOUT") ;
  sc_signal<bool> 		fout_valid("FOUT_VALID") ;
  sc_signal<unsigned> 		fdestout("FDESTOUT") ;
  
  // ************************ PIC *****************************************
  sc_signal<bool> 		ireq0("IREQ0") ;
  sc_signal<bool> 		ireq1("IREQ1") ;
  sc_signal<bool> 		ireq2("IREQ2") ;
  sc_signal<bool> 		ireq3("IREQ3") ;
  // PIC cs = interrupt_ack
  // PIC intack_cpu = interrupt_ack
  sc_signal<bool> 		rd_wr("RD_WR") ;
  sc_signal<bool> 		intreq("INTREQ") ;
  sc_signal<unsigned> 		vectno("VECTNO") ;
  sc_signal<bool> 		intack("INTACK") ;
  sc_signal<bool> 		intack_cpu("INTACK_CPU") ;

  // ************************ MMX ***********************************
  // MMX mmx_valid = mmx_valid
  // MMX opcode = alu_op
  // MMX mmxa = src_A
  // MMX mmxb = src_B
  // MMX dest = dest
  // MMX mmxdout = fdout
  // MMX mmxout_valid = fpu_valid
  // MMX mmxdestout = fpu_destout 

  // ************************ DSP *****************************************
  sc_signal<int> 		dsp_in1("DPS_IN1");
  sc_signal<int> 		dsp_out1("DSP_OUT1");
  sc_signal<bool> 		dsp_data_valid("DSP_DATA_VALID");
  sc_signal<bool> 		dsp_input_valid("DSP_INPUT_VALID");
  sc_signal<bool> 		dsp_data_requested("DSP_DATA_REQUESTED");

  ////////////////////////////////////////////////////////////////////////////
  // 				MAIN PROGRAM 
  ////////////////////////////////////////////////////////////////////////////
  sc_clock clk("Clock", 1, SC_NS, 0.5, 0.0, SC_NS);

  printf("/////////////////////////////////////////////////////////////////////////\n");
  printf("//  This code is written at SYNOPSYS, Inc.\n");
  printf("/////////////////////////////////////////////////////////////////////////\n");
  printf("//  Module   : main of CPU Model\n");
  printf("//  Author   : Martin Wang\n");
  printf("//  Company  : SYNOPSYS, Inc.\n");
  printf("//  Purpose  : This is a simple CPU modeling using SystemC.\n");
  printf("//             Instruction Set Architecure defined by Martin Wang.\n");
  printf("//             \n");
  printf("//           SystemC (TM) Copyright (c) 1988-2001 by Synopsys, Inc.  \n");
  printf("//             \n");
  printf("/////////////////////////////////////////////////////////////////////////\n");
  cout << "// IN THIS MACHINE Integer is " << sizeof (int) << " bytes.\n";
  cout << "// IN THIS MACHINE Floating is " << sizeof (float) << " bytes.\n";
  cout << "// IN THIS MACHINE Double is " << sizeof (double) << " bytes.\n";
  printf("//     \n");
  printf("//     \n");
  printf("//                            .,,uod8B8bou,,.\n");
  printf("//                   ..,uod8BBBBBBBBBBBBBBBBRPFT?l!i:.\n");
  printf("//              ,=m8BBBBBBBBBBBBBBBRPFT?!||||||||||||||\n");
  printf("//              !...:!TVBBBRPFT||||||||||!!^^\"\"    ||||\n");
  printf("//              !.......:!?|||||!!^^\"\"'            ||||\n");
  printf("//              !.........||||        ###  #  #    ||||\n");
  printf("//              !.........||||  ###  #  #  #  #    ||||\n");
  printf("//              !.........|||| #     #  #  #  #    ||||\n");
  printf("//              !.........|||| #     # #   #  #    ||||\n");
  printf("//              !.........|||| #     ##    #  #    ||||\n");
  printf("//              !.........|||| #     #     ###     ||||\n");
  printf("//              `.........|||| #   # #            ,||||\n");
  printf("//               .;.......||||  ###          _.-!!|||||\n");
  printf("//        .,uodWBBBBb.....||||       _.-!!|||||||||!:'\n");
  printf("//     !YBBBBBBBBBBBBBBb..!|||:..-!!|||||||!iof68BBBBBb....\n");
  printf("//     !..YBBBBBBBBBBBBBBb!!||||||||!iof68BBBBBBRPFT?!::   `.\n");
  printf("//     !....YBBBBBBBBBBBBBBbaaitf68BBBBBBRPFT?!:::::::::     `.\n");
  printf("//     !......YBBBBBBBBBBBBBBBBBBBRPFT?!::::::;:!^\"`;:::       `.\n");
  printf("//     !........YBBBBBBBBBBRPFT?!::::::::::^''...::::::;         iBBbo.\n");
  printf("//     `..........YBRPFT?!::::::::::::::::::::::::;iof68bo.      WBBBBbo.\n");
  printf("//       `..........:::::::::::::::::::::::;iof688888888888b.     `YBBBP^'\n");
  printf("//         `........::88::::::::::::;iof688888888888888888888b.     `\n");
  printf("//           `......::81:::::;iof688888888888888888888888888888b.\n");
  printf("//             `....:::;iof688888888888888888888888888888888899fT!\n");
  printf("//               `..::!8888888888888888888888888888888899fT|!^\"'\n");
  printf("//                 `' !!988888888888888888888888899fT|!^\"'\n");
  printf("//                     `!!8888888888888888899fT|!^\"'\n");
  printf("//                       `!988888888899fT|!^\"'\n");
  printf("//                         `!9899fT|!^\"'\n");
  printf("//                           `!^\"'\n");
  printf("//     \n");
  printf("//     \n");
  printf("/////////////////////////////////////////////////////////////////////////\n\n\n");
  	

  fetch 	IFU("FETCH_BLOCK");
                IFU.init_param(delay_cycles);
		IFU << ram_dataout << branch_target_address << next_pc << branch_valid
		<< stall_fetch << intreq << vectno << bios_valid << icache_valid
		<< pred_fetch << pred_branch_address << pred_branch_valid << ram_cs << ram_we 
		<< addr << ram_datain << instruction << instruction_valid << program_counter 
		<< intack_cpu << branch_clear << pred_fetch_valid << reset << clk;

  decode 	IDU("DECODE_BLOCK");
		IDU << reset << instruction << pred_instruction << instruction_valid
		<< pred_inst_valid << out_valid << destout << dout << dram_dataout
		<< dram_rd_valid << destout << fdout << fout_valid << fdestout
	        << branch_clear << dsp_data_valid << program_counter << pred_on
		<< branch_instruction_address << next_pc << branch_valid 
		<< branch_target_address << mem_access << mem_address << alu_op
		<< mem_write << alu_src << reg_write << src_A << src_B << forward_A
		<< forward_B << stall_fetch << decode_valid << float_valid << mmx_valid
		<< pid_valid << pid_data << clk;

  exec 		IEU("EXEC_BLOCK");
		IEU << reset << decode_valid << alu_op << negate << add1 << shift_sel 
		<< src_A << src_B << forward_A << forward_B << alu_src << c << v << z
		<< dout << out_valid << destout << clk;

  floating 	FPU("FLOAT_BLOCK");		// order dependent
		FPU << float_valid << alu_op << src_A << src_B << alu_src 
		<< fdout << fout_valid << fdestout << clk;

  mmxu	 	MMXU("MMX_BLOCK");
		MMXU << mmx_valid << alu_op << src_A << src_B << alu_src
		<< fdout << fout_valid << fdestout << clk;

  bios 		BIOS("BIOS_BLOCK");  
                BIOS.init_param(delay_cycles);
		BIOS.datain(ram_datain);	// order independent
                BIOS.cs(ram_cs);
		BIOS.we(ram_we);
		BIOS.addr(addr);
		BIOS.dataout(ram_dataout);
		BIOS.bios_valid(bios_valid);
		BIOS.stall_fetch(stall_fetch);
		BIOS.CLK(clk);

  paging 	PAGING("PAGING_BLOCK");
		PAGING << ram_datain << ram_cs << ram_we << addr << icache_din 
		<< icache_validin << icache_stall << paging_dout << paging_csout 
		<< paging_weout << physical_address << ram_dataout << icache_valid
		<< stall_fetch << clk ;
  	
  icache 	ICACHE("ICACHE_BLOCK"); 
		ICACHE.init_param(delay_cycles);
		ICACHE << paging_dout << paging_csout << paging_weout 	
		<< physical_address << pid_valid << pid_data << icache_din << icache_validin 
		<< icache_stall << clk;

  dcache 	DCACHE("DCACHE_BLOCK");
		DCACHE.init_param(delay_cycles);
		DCACHE << mmic_datain << mmic_statein << mmic_cs << mmic_we << mmic_addr
		<< mmic_dest << mmic_destout << mmic_dataout << mmic_out_valid << mmic_stateout << clk;

  pic		APIC("PIC_BLOCK");
		APIC << ireq0 << ireq1 << ireq2 << ireq3 <<intack_cpu << rd_wr 
		<< intack_cpu << intreq << intack << vectno;

  time_t tbuffer = time(NULL);

  sc_start();

  cout << "Time for simulation = " << (time(NULL) - tbuffer) << endl;

  return 0;	/* this is necessary */
}
//*************************************************************************************
//
//*************************************************************************************
CTraceRecorder::EUpdateTraceStatus	CTraceRecorder::UpdateTrace( u32 address,
																 bool branch_delay_slot,
																 bool branch_taken,
																 OpCode op_code,
																 CFragment * p_fragment )
{
	DAEDALUS_ASSERT( mTracing, "We're not tracing" );

	bool				want_to_stop( p_fragment != NULL );

	if( mTraceBuffer.size() > MAX_TRACE_LENGTH )
	{
		DBGConsole_Msg(0, "Hit max trace size!");
		want_to_stop = true;
	}

	// Terminate if the current instruction is in the fragment cache or the trace reaches a specified size
	if( want_to_stop && (mActiveBranchIdx == INVALID_IDX) )
	{
		DAEDALUS_ASSERT( mActiveBranchIdx == INVALID_IDX, "Exiting trace while in the middle of handling branch!" );
		// Stop immediately so we can be sure of linking up with fragment
		mTracing = false;
		mExpectedExitTraceAddress = address;
		return UTS_CREATE_FRAGMENT;
	}

	//
	//	Figure out whether to terminate this trace after adding this instruction
	//
	bool	stop_trace_on_exit( false );

	//
	//	We want to record the delay slot op for the active branch
	//
	if( mActiveBranchIdx != INVALID_IDX )
	{
		DAEDALUS_ASSERT( mActiveBranchIdx < mBranchDetails.size(), "Branch index is out of bounds" );
		mBranchDetails[ mActiveBranchIdx ].DelaySlotTraceIndex = mTraceBuffer.size();

		if (mBranchDetails[ mActiveBranchIdx ].SpeedHack == SHACK_POSSIBLE)
		{
			if (op_code._u32 == 0)
			{
				mBranchDetails[ mActiveBranchIdx ].SpeedHack = SHACK_SKIPTOEVENT;

			}
#ifndef DAEDALUS_SILENT
			else if (op_code.op == OP_ADDIU || op_code.op == OP_DADDI || op_code.op == OP_ADDI || op_code.op == OP_DADDIU)
			{	// We don't handle COPYREG SPEEDHACKS
				mBranchDetails[ mActiveBranchIdx ].SpeedHack = SHACK_COPYREG;
			}
#endif
		}

		mActiveBranchIdx = INVALID_IDX;
	}

	// If we had to terminate on the last branch (e.g. for an indirect jump)
	// or if we're jumping backwards, terminate the run when we exit
	if( mStopTraceAfterDelaySlot && branch_delay_slot )
	{
		mStopTraceAfterDelaySlot = false;
		stop_trace_on_exit = true;
	}

	//
	//	Update the expected trace exit address
	//	We assume that if we'll exit on the next instruction (assuming this isn't a branch)
	//
	if( !branch_delay_slot )
	{
		mExpectedExitTraceAddress = address + 4;
	}

	StaticAnalysis::RegisterUsage usage;
	StaticAnalysis::Analyse(op_code,usage);

	//
	//	If this is a branch, we need to determine if it was taken or not.
	//	We store a information about the 'off-trace' target.
	//	If the branch was taken, we need to flip the condition of the
	//	branch so that anything failing the test is directed off our trace
	//
	u32		branch_idx( INVALID_IDX );

	ER4300BranchType	branch_type( usage.BranchType );
	if( branch_type != BT_NOT_BRANCH )
	{
		SBranchDetails	details;

		details.Likely = IsBranchTypeLikely( branch_type );

		if( branch_type == BT_ERET )
		{
			stop_trace_on_exit = true;
			details.Eret = true;
			details.Direct = false;
			details.TargetAddress = INDIRECT_EXIT_ADDRESS;

			mExpectedExitTraceAddress = details.TargetAddress;
		}
		else if( !IsConditionalBranch( branch_type ) )
		{
			details.Direct = IsBranchTypeDirect( branch_type );
			details.TargetAddress = gCPUState.TargetPC;
			details.ConditionalBranchTaken = true;

			mExpectedExitTraceAddress = details.TargetAddress;

			if (!details.Direct || gCPUState.TargetPC <= gCPUState.CurrentPC)
			{
				// all indirect call will stop the trace
				mStopTraceAfterDelaySlot = true;
			}

			if (details.Direct && gCPUState.TargetPC == gCPUState.CurrentPC)
			{
				details.SpeedHack = SHACK_POSSIBLE;
			}
		}
		else
		{
			// Must be conditional, direct
			DAEDALUS_ASSERT( IsBranchTypeDirect( branch_type ), "Not expecting an indirect branch here" );

			if( branch_taken )
			{
				// XXXXXX should be able to get this some other way?
				bool	backwards( gCPUState.TargetPC <= gCPUState.CurrentPC );

				if( backwards )
				{
					mStopTraceAfterDelaySlot = true;
				}

				if (gCPUState.TargetPC == gCPUState.CurrentPC)
				{
					details.SpeedHack = SHACK_POSSIBLE;
				}
			}

			u32		branch_target_address( GetBranchTarget( address, op_code, branch_type ) );
			u32		fallthrough_address( address + 8 );

			u32		target_address;
			if( branch_taken )
			{
				// We're following the branch.
				target_address = fallthrough_address;
				mExpectedExitTraceAddress = branch_target_address;
			}
			else
			{
				// We're not following the branch, and falling through.
				target_address = branch_target_address;
				mExpectedExitTraceAddress = fallthrough_address;
			}

			details.ConditionalBranchTaken = branch_taken;
			details.Direct = true;
			details.TargetAddress = target_address;
		}

		if( !details.Direct )
		{
			mNeedIndirectExitMap = true;
		}

		mActiveBranchIdx = mBranchDetails.size();
		branch_idx = mBranchDetails.size();
		mBranchDetails.push_back( details );
	}

	// Add this op to the trace buffer.
	STraceEntry		entry = { address, op_code, usage, branch_idx, branch_delay_slot };

	mTraceBuffer.push_back( entry );

	if( stop_trace_on_exit )
	{
		DAEDALUS_ASSERT( branch_type == BT_ERET || mActiveBranchIdx == INVALID_IDX, "Exiting trace while in the middle of handling branch!" );

		mTracing = false;
		return UTS_CREATE_FRAGMENT;
	}

	return UTS_CONTINUE_TRACE;
}