fun main(var pc1, var npc1, var cwp1,
	 var cansave1, var canrestore1,
	 var fuQ : FU_Data queue,
	 var jmpQ : stream queue)
{
    PC = pc1;			 
    nPC = npc1;			 
    CWP0 = cwp1;		 
    CWP = CWP0;			 
    CANSAVE = cansave1;		 
    CANRESTORE = canrestore1;	 

    instq?clear();		 

     
    nPC2 = 0?cvt(stream);
    is_ccti = false;
    is_jmpl = false;
    is_call = false;
    rollback = false;
    fu_num_allocated = array(4 ) { 0 };
    is_spec = false;
    no_loads = true;
    unk_load_addr = false;
    unk_store_addr = false;
    new_inst = struct { pc = 0?cvt(stream), npc = 0?cvt(stream),
			srcq = queue{}, destq = queue{},
			op = 0?cvt(ushort), ftype = 0?cvt(uchar),
			ftime = 0?cvt(uchar), taken = false,
			delta = 0?cvt(char), trap = false,
			done = false, align = 0?cvt(uchar) };

     
     

    is_trap = false;			 
    in_init = fuQ?length()>0;		 
    is_taken = false;

    val done = false;	 

     
     
    val finish = false;

     
     

    while(!done) {

	 
	val num_to_fetch = 4 ;
	if(is_trap) num_to_fetch = 0;
	else if(in_init) num_to_fetch = num_to_fetch + fuQ?length();

	 
	if(num_to_fetch > (32  - instq?length()))
	    num_to_fetch = 32  - instq?length();

	 
	 
	 
	 

	while(num_to_fetch > 0) {

	    if(instq?length() > 1) {
		switch(instq[-2].pc) {
		 case (pat jmpl || retrn):
		     
		     
		    if(instq[-2].ftime > 0?cvt(uchar)) break;	 

		    var inst = instq[-1];	 

		     
		    val inum = instq?length() - 2;
		    PC = inst.npc;

		     
		     
		    if(!inst.taken) nPC = PC + 4;

		 default: ;
		}
	    }

	    nPC2 = nPC + 4;	 

	     
	     

	    num_to_fetch = num_to_fetch - 1;

	    init_inst(new_inst,PC,nPC);

	    if(!in_init) rmap_fetch();
	    else {
		 
		is_taken = init_taken(fuQ[+0]);
	    }

	     
	     

	    is_ccti = false;
	    is_jmpl = false;
	    is_call = false;

	    PC?exec();

	    instq?push_back(new_inst);
	    var inst = instq[-1];

	    if(in_init) {
		 
		 
		inst.ftype = init_ftype(fuQ[+0]);
		inst.ftime = fuQ[+0].ftime;
		fuQ?pop_front();

		in_init = fuQ?length() > 0;

		if(is_jmpl) {
		    if(jmpQ?length() > 0)
			nPC2 = jmpQ?pop_front();
		}
	    } else if(is_jmpl) {
		 
		if(num_to_fetch > 1) num_to_fetch = 1;
	    }

	    if(is_trap) {
		 
		assert(!in_init);
		if(inst.ftime <= 0?cvt(uchar))
		    is_trap = false;	 
		else {
		    inst.trap = true;
		    num_to_fetch = 0;
		}
	    }

	     
	    if(is_ccti || is_jmpl || is_call) finish = true;

	    PC = nPC; nPC = nPC2;
	     
	     

	     
	     
	     
	     
	     

	    if(finish) if(PC+4 == nPC)
	    { inst.done = true; finish = false; }
        }

	assert(fuQ?length() == 0 && jmpQ?length() == 0);

	 
	 

	no_loads = true;
	unk_load_addr = false;
	unk_store_addr = false;

	 
	val branch_inum = 0;		val _branch_inum = 0;
	is_spec = false;		val _is_spec = false;
	val do_rollback = false;	val _do_rollback = false;

	val ii = 0; fu_clear();
	while(ii < instq?length()) {
	    var inst = instq[+ii];

	     
	    rollback = false;
	    val executed = execute(inst,ii);

	     
	    branch_inum = _branch_inum; is_spec = _is_spec;
	    do_rollback = _do_rollback;
	    _do_rollback = rollback;
	    if(rollback) _branch_inum = ii;	 

	    val op = inst.op?cvt(ulong);
	    if(164   <= op && op <= 173  ) {
		no_loads = false;		 
		if(inst.ftype == 3 ?cvt(uchar)) {
		     
		    unk_load_addr = true;
		}

	    } else if((174   <= op && op <= 180  ) ||
		      (181   <= op && op <= 184  )) {
		if(inst.ftype == 3 ?cvt(uchar)) {
		     
		    unk_store_addr = true;
		}

	    } else if(1   <= op && op <= 34  ) {

		 
		if(inst.ftime > 0?cvt(uchar)) _is_spec = true;

		switch(inst.pc) {
		 case (pat a==0b1):	 
		    branch_inum = _branch_inum; is_spec = _is_spec;
		    do_rollback = _do_rollback; _do_rollback = false;
		 default:		 
		    ;
		}
	    }

	    ii = ii + 1;

	    if(do_rollback) break;
	}

	if(_do_rollback) {
	     
	    assert(!do_rollback);
	    branch_inum = _branch_inum;
	    do_rollback = true;
	}

	if(do_rollback) {
	     
	     
	     
	     
	     
	     
	     
	     
	     
	     
	     

	    in_init = true;			 

	    var branch_inst = instq[+branch_inum];
	    PC = branch_inst.pc;		 
	    nPC = branch_inst.npc;		 

	    val fu : FU_Data;

	     
	    fu.ftype = branch_inst.ftype | (!branch_inst.taken)?ext(8)<<7;
	    fu.ftime = 0?cvt(uchar); fuQ?push_back(fu);

	    assert(ii > branch_inum && ii <= branch_inum + 2);
	    val jj = branch_inum + 1;
	    while(jj < ii) {
		var inst = instq[+jj];
		fu.ftype = inst.taken?ext(8)<<7 | inst.ftype;
		fu.ftime = inst.ftime;
		fuQ?push_back(fu);
		jj = jj + 1;
	    }
	     

	     
	    while(jj < instq?length()) {
		val op = instq[+jj].op?cvt(ulong);
		if((174   <= op && op <= 180  ) ||
		   (181   <= op && op <= 184  )) {
		    if(instq[+jj].ftype == 5 ?cvt(uchar)) {
			cache_store_rollback(jj);
		    }
		}
		jj = jj + 1;
	    }

	     
	    rmap_rollback(ii);

	     
	    while(branch_inum < instq?length()) {
		var inst = instq[-1];
		CWP = ((CWP?cvt(char) + 8 ?cvt(char) - inst.delta)
		       % 8 ?cvt(char))?bits(5);
		if(!inst.trap) {
		    CANSAVE = ((CANSAVE?cvt(char) + 8 ?cvt(char) +
				inst.delta) % 8 ?cvt(char))?bits(5);
		    CANRESTORE = ((CANRESTORE?cvt(char) + 8 ?cvt(char) -
				   inst.delta) % 8 ?cvt(char))?bits(5);
		} else is_trap = false;
		instq?pop_back();
	    }
	}

	 
	 
	val num_retired = 0;
	while(num_retired < instq?length()) {
	    var inst = instq[+num_retired];
	    if(inst.ftime > 0?cvt(uchar)) break;


	     
	    if(inst.done) done = true;


	     
	    CWP0 = ((CWP0?cvt(char) + 8 ?cvt(char) + inst.delta)
		    % 8 ?cvt(char))?bits(5);

	    val op = inst.op?cvt(ulong);
	    if(1   <= op && op <= 34  )
		branch_direction(inst.pc?addr,inst.taken);

	    num_retired = num_retired + 1;
	}

	if(num_retired > 0) {
	    rmap_retire(num_retired);
	    cache_retire(num_retired);
	    instq?pop_front(num_retired);
	    num_insts_retired = (num_insts_retired +
				 num_retired?cvt(unsigned[64]));
	}

	CPU_cycle = CPU_cycle + 1?ext(64);
    }

     
     
     
     
     

     
     

    if(instq?length() > 0) {
	var inst = instq[+0];
	pc1 = inst.pc; npc1 = inst.npc;
    } else { pc1 = PC; npc1 = nPC; }

    cwp1 = CWP0;	 

     
     

    while(instq?length() > 0) {
	var inst = instq[-1];

	 
	val fu = struct { ftype = inst.taken?ext(8)<<7 | inst.ftype,
			  ftime = inst.ftime };
	fuQ?push_front(fu);

	switch(inst.pc) {
	 case (pat jmpl || retrn):
	    if(inst.ftime <= 0?cvt(uchar)) {
		 
		val target = (rmap_read(inst.srcq[+0],instq?length()-1) +
			      rmap_read(inst.srcq[+1],instq?length()-1));
		jmpQ?push_front(target?cvt(stream));
	    }
	 default: ;
	}

	if(!inst.trap) {
	    CANSAVE = ((CANSAVE?cvt(char) + 8 ?cvt(char) +
			inst.delta) % 8 ?cvt(char))?bits(5);
	    CANRESTORE = ((CANRESTORE?cvt(char) + 8 ?cvt(char) -
			   inst.delta) % 8 ?cvt(char))?bits(5);
	}

	instq?pop_back();	 
    }

    cansave1 = CANSAVE;
    canrestore1 = CANRESTORE;
}