//It will search all D,S,k1,k2,k3,N.

# include <stdio.h>
# include <stdlib.h>
main ()
{
        FILE *fp;
        char path[80]="/afs/eos/info/ece/ece521_info/fall98/proj3/traces/";
        char fname[20]="124.m88ksim.trace";
        int fu_type,dest_reg,src_reg[2],N=2,i,j,k;
        int *score_board,tag,time,fu_num;
        int fu0,fu1,fu2,p_b=0,p_e=0,file_end=0,tag_bak;
        int item,stall=0,full_sq,full_dq,stop,n_stall=0;
        int D, S;
        typedef struct fu_st {          /* function unit */
                int num;
                int head;
                int latency;
                int pipelined;
        } function_unit;
        function_unit fu[3];
        typedef struct register_st {    /* register file */
                int ready;
                int tag;
        } register_file;
        register_file reg_file[128];
        typedef struct dispatch_st {    /* dispatch queue */
                int tag;
                int fu_type;
                int dest_reg;
                int src_reg[2];
                int valid;
        } dispatch_queue;
        dispatch_queue *d_q;
        typedef struct schedule_st {    /* schedule queue */
                int fu_type;
                int fu_num;
                int dest_reg;
                int dest_tag;
                int src_ready[2];
                int src_tag[2];
                int stage;
                int valid;
        } schedule_queue;
        schedule_queue *s_q;
        typedef struct result_st {      /* result bus */
                int tag;
                int dest_reg;
                int valid;
        } result_bus;
        result_bus *r_b;

        strcat(path,fname);
        printf("please input begin and end:\n"); /* region of debug output */
        scanf("%d%d",&p_b,&p_e);
        printf("%s\n",fname);
 
 

        for (N=2;N<=2;N++)              /* changing parameter */
        for (fu0=2;fu0<=2;fu0++)
        for (fu1=2;fu1<=2;fu1++)
        for (fu2=2;fu2<=2;fu2++)
        {
        fu_num=fu0+fu1+fu2;
        for (S=12;S<=12;S++)
          for (D=7;D<=7;D++) {
            /*  for (S=fu_num+1;S<=2*fu_num;S++)
        for (D=fu_num;D<S;D++) {*/
        /* initialize */
        tag=1;                          /* initial counter */
        time=0;
        file_end=0;
        stop=0;
        stall=0;
        fu[0].num=fu0;                  /* setup function unit */
        fu[1].num=fu1;
        fu[2].num=fu2;
        fu[0].latency=2;
        fu[1].latency=1;
        fu[2].latency=2;
        fu[0].pipelined=1;
        fu[1].pipelined=0;
        fu[2].pipelined=1;
        fu[0].head=0;
        fu[1].head=fu[0].num;
        fu[2].head=fu[0].num+fu[1].num;
 
 

        d_q=(dispatch_queue *)malloc(sizeof(dispatch_queue)*D);
        s_q=(schedule_queue *)malloc(sizeof(schedule_queue)*S);
        r_b=(result_bus *)malloc(sizeof(result_bus)*fu_num);
        score_board=(int *)malloc(sizeof(int)*fu_num);

        for (i=0;i<D;i++) d_q[i].valid=0;       /* initial dispatch queue */
        for (i=0;i<128;i++) {                   /* initial register file */
            reg_file[i].ready=1;
            reg_file[i].tag=0;
            }
        for (i=0;i<S;i++) {              /* initial schedule queue */
            s_q[i].valid=0;
            s_q[i].stage=-1;
            }
        for (i=0;i<fu_num;i++) r_b[i].valid=0;  /* initial result bus */

        fp=fopen(path,"r");
        while((file_end==0)||(stop==0)) {
           for (i=0;i<fu_num;i++) score_board[i]=0;

           /* schedule unit */
           tag_bak=0;
           while (tag_bak<65000) {
              tag_bak=65000;
              for (i=0;i<S;i++) {              /* select the smallest tag */
                  if ((s_q[i].valid==1)&&(s_q[i].stage==-1)&&(s_q[i].src_ready[0]==1)&&(s_q[i].src_ready[1]==1)){
                     if (s_q[i].dest_tag<tag_bak) {
                        tag_bak=s_q[i].dest_tag;
                        item=i;
                        }
                     }
                   }
              if (tag_bak<65000) {                    /* try to fire it */
                 i=item;
                 for (j=fu[s_q[i].fu_type].head;j<fu[s_q[i].fu_type].head+fu[s_q[i].fu_type].num;j++) {
                     if (score_board[j]==0) {
                        score_board[j]=1;
                        s_q[i].stage=-10;
                        s_q[i].fu_num=j;
                        break;
                        }
                     }
                 if (s_q[i].stage==-1) {
                    tag_bak=65000;
                    n_stall++;
                    }
                 }
              }

           /* dispatch unit */
           tag_bak=0;
           while (tag_bak<65000) {
              tag_bak=65000;
              for (i=0;i<D;i++) {                     /* select the smallest tag */
                  if (d_q[i].valid==1) {
                     if (d_q[i].tag<tag_bak) {
                        tag_bak=d_q[i].tag;
                        item=i;
                        }
                     }
                  }
              if (tag_bak<65000) {                    /* try to issue it */
                 i=item;
                 for (j=0;j<S;j++) {
                     if (s_q[j].valid==0) {
                        s_q[j].fu_type=d_q[i].fu_type;
                        s_q[j].dest_reg=d_q[i].dest_reg;
                        for (k=0;k<2;k++) {
                            if (reg_file[d_q[i].src_reg[k]].ready==1) {
                               s_q[j].src_ready[k]=1;
                               s_q[j].src_tag[k]=reg_file[d_q[i].src_reg[k]].tag;
                               if (s_q[j].src_tag[k]<0)
                                   s_q[j].src_tag[k]=0;
                               }
                            else {
                               s_q[j].src_tag[k]=reg_file[d_q[i].src_reg[k]].tag;
                               s_q[j].src_ready[k]=0;
                               }
                            }
                            reg_file[d_q[i].dest_reg].tag=d_q[i].tag;
                            s_q[j].dest_tag=d_q[i].tag;
                            reg_file[d_q[i].dest_reg].ready=0;
                            d_q[i].valid=0;
                            s_q[j].valid=2;
                            break;
                        }
                     }
                 if (d_q[i].valid==1) {
                    tag_bak=65000;
                    n_stall++;
                    }
                 }
              }

              /* fetch/decode unit */
              if ((stall==0)&&(file_end==0)) {
                 for (i=0;i<N;i++) {            /* try to fetch up to N insts*/
                     for (j=0;j<D;j++) {
                         if (d_q[j].valid==0) {
                            if (fscanf(fp,"%d%d%d%d\n",&fu_type,&dest_reg,&src_reg[0],&src_reg[1])<0) {
                               file_end=1;
                               time--;
                               tag--;
                               break;
                               }
                            d_q[j].tag=tag++;
                            d_q[j].fu_type=fu_type;
                            d_q[j].dest_reg=dest_reg;
                            d_q[j].src_reg[0]=src_reg[0];
                            d_q[j].src_reg[1]=src_reg[1];
                            d_q[j].valid=2;
                            break;
                            }
                         }
                     if (file_end==1) break;
                     }
                 }
              full_sq=1;
              full_dq=1;
              stall=0;
              for (i=0;i<S;i++) if (s_q[i].valid==0) full_sq=0;
              for (i=0;i<D;i++) if (d_q[i].valid==0) full_dq=0;
              if ((full_sq==1)&&(full_dq==1)) {
                 stall=1;
                 n_stall++;
                 }

              /* execute unit */
              stop=1;
              for (i=0;i<S;i++) {              /* search the whole sch. queue */
                  if (s_q[i].valid==1) {
                     stop=0;
                     if (s_q[i].stage>=0) s_q[i].stage++;
                     if (s_q[i].stage==fu[s_q[i].fu_type].latency+1)
                        if (s_q[i].dest_tag==reg_file[s_q[i].dest_reg].tag)
                           reg_file[s_q[i].dest_reg].ready=1;
                     if (s_q[i].stage==fu[s_q[i].fu_type].latency+1) {
                        r_b[s_q[i].fu_num].tag=s_q[i].dest_tag;
                        r_b[s_q[i].fu_num].dest_reg=s_q[i].dest_reg;
                        r_b[s_q[i].fu_num].valid=1;
                        score_board[s_q[i].fu_num]=0;
                        s_q[i].valid=0;
                        s_q[i].stage=-1;
                        }
                     }
                  }

              /* state update */
              for (i=0;i<D;i++) if (d_q[i].valid==2) d_q[i].valid=1;
              for (i=0;i<S;i++) {
                  if (s_q[i].valid==2) s_q[i].valid=1;
                  if (s_q[i].stage==-10) s_q[i].stage=0;
                  for (j=0;j<2;j++) {
                      for (k=0;k<fu_num;k++) {
                          if ((r_b[k].tag==s_q[i].src_tag[j])&&(r_b[k].valid==1)) {
                             s_q[i].src_ready[j]=1;
                             }
                          }
                      }
                  }
              if ((file_end==1)&&(stop==1)) break;            /* simulation complete */

              /* debug output */                              /* empty entries skipped */
              time++;
              if ((time>=p_b)&&(time<=p_e)) {
                 printf("--- machine state at clock %d ---\n",time);
                 printf("dispatch queue:\n");
                 for (i=0;i<D;i++) {
                     if (d_q[i].valid!=1) continue;
                     printf("\tI%d:%d|%2d=%2d#%2d\n",d_q[i].tag,d_q[i].fu_type,d_q[i].dest_reg,d_q[i].src_reg[0],d_q[i].src_reg[1]);
                     }
                 printf("scoreboard:\n");
                 for (i=0;i<fu_num;i++) {
                     if (score_board[i]==0) continue;
                     printf("\tFU%2d\tbusy\n",i);
                     }
                 printf("register file:\n");
                 for (i=0;i<128;i++) {
                     if ((reg_file[i].ready==1)&&(reg_file[i].tag==0)) continue;
                     if (reg_file[i].ready==0)
                        printf("\tR%2d:\tNR/tag%d\n",i,reg_file[i].tag);
                     else
                        printf("\tR%2d:\t R/tag%d\n",i,reg_file[i].tag);
                     }
                 printf("schedule queue:\n");
                 for (i=0;i<S;i++) {
                     if (s_q[i].valid!=1) continue;
                     if (s_q[i].stage>=0)
                        printf("\tDR:%2d/tag %d\tSR0:%s/tag%d\tSR1:%s/tag %d\tt= %d|FU=\
%2d[%d]\n",s_q[i].dest_reg,s_q[i].dest_tag,s_q[i].src_ready[0]==1?"\
R":"NR",s_q[i].src_tag[0],s_q[i].src_ready[1]==1?"\
R":"NR",s_q[i].src_tag[1],s_q[i].stage,s_q[i].fu_num,s_q[i].fu_type);
                     else
                        printf("\tDR:%2d/tag %d\tSR0:%s/tag\
%d\tSR1:%s/tag %d\n",s_q[i].dest_reg,s_q[i].dest_tag,s_q[i].src_ready[0]==1?"\
R":"NR",s_q[i].src_tag[0],s_q[i].src_ready[1]==1?" R":"NR",s_q[i].src_tag[1]);

                     }
                 printf("result bus:\n");
                 for (i=0;i<fu_num;i++) {
                     if (r_b[i].valid!=1) continue;
                     printf("\tDR:%2d/tag %d\n",r_b[i].dest_reg,r_b[i].tag);
                     }
                 printf("\n");
                 }

              for (i=0;i<fu_num;i++) r_b[i].valid=0;
              }

          /* statistics output */
          printf("(N=%d,FU0=%d,FU1=%d,FU2=%d,D=%d,S=%d) %s\n",N,fu0,fu1,fu2,D,S,fname);
          printf("total:\t%d\n",tag);
          printf("dispatched:\t%d\n",tag);
          printf("fired:\t%d\n",tag);
          printf("completed:\t%d\n",tag);
          printf("cycles:\t%d\n",time);
          printf("stalls:\t%d\n",n_stall);
          printf("fired per cycle:\t%f\n",1.0*tag/time);
          printf("completed per cycle:\t%f\n",1.0*tag/time);
          printf("IPC:\t%f\n",1.0*tag/time);
          printf("\n\n");
          free(d_q);
          free(s_q);
          free(r_b);
          free(score_board);
          fclose(fp);
        }
        }
}