📄 read_arch.c
字号:
static void check_arch (char *arch_file, enum e_route_type route_type, struct s_det_routing_arch det_routing_arch, t_segment_inf *segment_inf, t_timing_inf timing_inf, int max_subblocks_per_block, t_chan_width_dist chan_width_dist) {/* This routine checks that the input architecture file makes sense and * * specifies all the needed parameters. The parameters must also be * * self-consistent and make sense. */ int i, fatal, opin_switch; float total_segment_freq, chan_width_io; boolean must_be_set[NUMINP]; t_chan chan_x_dist, chan_y_dist; fatal = 0;/* NUMINP parameters can be set in the architecture file. The first * * NUM_REQUIRED are always mandatory. The next NUM_DETAILED ones are * * needed only if detailed routing is going to be performed. The last * * NUM_TIMING ones are needed only if timing analysis is going to be * * performed. Expect the corresponding isread for each parameter to be * * 1, except isread[4] (outpin), isread[5] (inpin), isread[13] (segment) * * and isread[14] (switch) which should all be greater than 0. */ for (i=0;i<NUM_REQUIRED;i++) must_be_set[i] = TRUE; for (i=NUM_REQUIRED;i<NUMINP;i++) must_be_set[i] = FALSE; if (route_type == DETAILED) { for (i=NUM_REQUIRED;i<NUM_REQUIRED + NUM_DETAILED;i++) must_be_set[i] = TRUE; } if (timing_inf.timing_analysis_enabled) { for (i=NUM_REQUIRED + NUM_DETAILED;i<NUMINP;i++) must_be_set[i] = TRUE; } for (i=0;i<NUMINP;i++) { if (!must_be_set[i]) continue; if (i == TIMING_START + 7) { /* T_subblock lines */ if (isread[i] < 1 || isread[i] != max_subblocks_per_block) { printf ("Error: Got %d T_subblock lines -- expected %d.\n", isread[i], max_subblocks_per_block); fatal = 1; } } else if (i != 4 && i != 5 && i != DETAILED_START + 5 && i != DETAILED_START + 6) { if (isread[i] == 0) { printf("Error: %s not set in file %s.\n",names[i], arch_file); fatal=1; } if (isread[i] > 1) { printf("Error: %s set %d times in file %s.\n",names[i], isread[i],arch_file); fatal = 1; } } else { /* outpin, inpin, segment, or switch lines */ if (isread[i] < 1) { printf("Error: in file %s. Clb has %d %s(s).\n",arch_file, isread[i], names[i]); fatal = 1; } } }/* Segment info is used for both GLOBAL and DETAILED routing. */ total_segment_freq = 0.; for (i=0;i<det_routing_arch.num_segment;i++) { total_segment_freq += segment_inf[i].frequency; opin_switch = segment_inf[i].opin_switch; if (switch_inf[opin_switch].buffered == FALSE) { printf ("Error in check_arch: opin_switch (#%d) of segment type #%d " "is not buffered.\n", opin_switch, i); exit (1); } } if (fabs (total_segment_freq - 1.) > 0.001) { printf ("Error in check_arch: Segment frequencies must sum to 1.\n" "\tSum is %g.\n", total_segment_freq); fatal = 1; }/* Detailed routing is only supported on architectures with all channel * * widths the same for now. The router could handle non-uniform widths, * * but the routing resource graph generator doesn't build the rr_graph * * for the nonuniform case as yet. */ if (route_type == DETAILED) { chan_width_io = chan_width_dist.chan_width_io; chan_x_dist = chan_width_dist.chan_x_dist; chan_y_dist = chan_width_dist.chan_y_dist; if (chan_x_dist.type != UNIFORM || chan_y_dist.type != UNIFORM || chan_x_dist.peak != chan_y_dist.peak || chan_x_dist.peak != chan_width_io) { printf("Error in check_arch: detailed routing currently only\n" "supported on FPGAs with all channels of equal width.\n"); fatal = 1; } if (det_routing_arch.Fc_type == ABSOLUTE) { if (det_routing_arch.Fc_output < 1 || det_routing_arch.Fc_input < 1 || det_routing_arch.Fc_pad < 1) { printf ("Error in check_arch: Fc values must be >= 1 in absolute " "mode.\n"); fatal = 1; } } else { /* FRACTIONAL mode */ if (det_routing_arch.Fc_output > 1. || det_routing_arch.Fc_input > 1. || det_routing_arch.Fc_pad > 1.) { printf ("Error in check_arch: Fc values must be <= 1. in " "fractional mode.\n"); fatal = 1; } } for (i=0;i<det_routing_arch.num_switch;i++) { if (switch_inf[i].buffered) { /* Largest resistance tri-state buffer would have a minimum width * * transistor in the buffer pull-down and a min-width pass transistor * * on the output. Hence largest R = 2 * largest_transistor_R. */ if (switch_inf[i].R > 2 * det_routing_arch.R_minW_nmos) { printf ("Error in check_arch: Switch %d R value (%g) is greater" " than 2 * R_minW_nmos (%g).\n", i, switch_inf[i].R, 2 * det_routing_arch.R_minW_nmos); exit (1); } } else { /* Pass transistor switch */ if (switch_inf[i].R > det_routing_arch.R_minW_nmos) { printf ("Error in check_arch: Switch %d R value (%g) is greater " "than R_minW_nmos (%g).\n", i, switch_inf[i].R, det_routing_arch.R_minW_nmos); exit (1); } } } /* End for all switches. */ } /* End if route_type == DETAILED */ if (fatal) exit(1);} void print_arch (char *arch_file, enum e_route_type route_type, struct s_det_routing_arch det_routing_arch, t_segment_inf *segment_inf, t_timing_inf timing_inf, t_subblock_data subblock_data, t_chan_width_dist chan_width_dist) {/* Prints out the architectural parameters for verification in the * * file "arch.echo." The name of the architecture file is passed * * in and is printed out as well. */ int i, j; FILE *fp; t_T_subblock T_subblock; t_chan chan_x_dist, chan_y_dist; float chan_width_io; fp = my_fopen ("arch.echo", "w", 0); chan_width_io = chan_width_dist.chan_width_io; chan_x_dist = chan_width_dist.chan_x_dist; chan_y_dist = chan_width_dist.chan_y_dist; fprintf(fp,"Input netlist file: %s\n\n",arch_file); fprintf(fp,"io_rat: %d.\n",io_rat); fprintf(fp,"chan_width_io: %g pins_per_clb (pins per clb): %d\n", chan_width_dist.chan_width_io, pins_per_clb); fprintf(fp,"\n\nChannel Types: UNIFORM = %d; GAUSSIAN = %d; PULSE = %d;" " DELTA = %d\n\n", UNIFORM, GAUSSIAN, PULSE, DELTA); fprintf(fp,"\nchan_width_x:\n"); fprintf(fp,"type: %d peak: %g width: %g xpeak: %g dc: %g\n", chan_x_dist.type, chan_x_dist.peak, chan_x_dist.width, chan_x_dist.xpeak, chan_x_dist.dc); fprintf(fp,"\nchan_width_y:\n"); fprintf(fp,"type: %d peak: %g width: %g xpeak: %g dc: %g\n\n", chan_y_dist.type, chan_y_dist.peak, chan_y_dist.width, chan_y_dist.xpeak, chan_y_dist.dc); fprintf(fp,"Pin #\tclass\ttop\tbottom\tleft\tright\tglobal"); for (i=0;i<pins_per_clb;i++) { fprintf(fp,"\n%d\t%d\t", i, clb_pin_class[i]); for (j=0;j<=3;j++) fprintf(fp,"%d\t",pinloc[j][i]); fprintf (fp, "%d", is_global_clb_pin[i]); } fprintf(fp,"\n\nClass types: DRIVER = %d; RECEIVER = %d\n\n", DRIVER, RECEIVER); fprintf(fp,"Class\tType\tNumpins\tPins"); for (i=0;i<num_class;i++) { fprintf(fp,"\n%d\t%d\t%d\t", i, class_inf[i].type, class_inf[i].num_pins); for (j=0;j<class_inf[i].num_pins;j++) fprintf(fp,"%d\t",class_inf[i].pinlist[j]); } fprintf(fp,"\n\n"); fprintf(fp,"subblocks_per_clb (maximum): %d\n", subblock_data.max_subblocks_per_block); fprintf(fp,"subblock_lut_size: %d\n", subblock_data.subblock_lut_size); if (route_type == DETAILED) { fprintf(fp,"\n"); if (det_routing_arch.Fc_type == ABSOLUTE) fprintf(fp,"Fc value is absolute number of tracks.\n"); else fprintf(fp,"Fc value is fraction of tracks in a channel.\n"); fprintf(fp,"Fc_output: %g. Fc_input: %g. Fc_pad: %g.\n", det_routing_arch.Fc_output, det_routing_arch.Fc_input, det_routing_arch.Fc_pad); if (det_routing_arch.switch_block_type == SUBSET) fprintf (fp, "switch_block_type: SUBSET.\n"); else if (det_routing_arch.switch_block_type == WILTON) fprintf (fp, "switch_block_type: WILTON.\n"); else fprintf (fp, "switch_block_type: UNIVERSAL.\n"); }/* Segmentation info. useful even if route_type == GLOBAL */ fprintf (fp, "\nnum_segment: %d, num_switch: %d.\n", det_routing_arch.num_segment, det_routing_arch.num_switch); if (route_type == DETAILED) fprintf (fp, "(Two switch types were generated automatically.)\n"); fprintf (fp, "#%d: delayless switch. #%d: wire_to_ipin_switch.\n", det_routing_arch.delayless_switch, det_routing_arch.wire_to_ipin_switch); fprintf (fp, "\nSeg. #\tfreq.\tlength\tlongln\topin_sw\twire_sw\tFrac_cb\t" "Frac_sb\tCmetal\tRmetal\n"); for (i=0;i<det_routing_arch.num_segment;i++) fprintf (fp, "%d\t%g\t%d\t%d\t%d\t%d\t%g\t%g\t%g\t%g\n", i, segment_inf[i].frequency, segment_inf[i].length, segment_inf[i].longline, segment_inf[i].opin_switch, segment_inf[i].wire_switch, segment_inf[i].frac_cb, segment_inf[i].frac_sb, segment_inf[i].Cmetal, segment_inf[i].Rmetal); fprintf (fp,"\nSwitch#\tbuff?\tR\tCin\tCout\tTdel\n"); for (i=0;i<det_routing_arch.num_switch;i++) fprintf (fp, "%d\t%d\t%g\t%g\t%g\t%g\n", i, switch_inf[i].buffered, switch_inf[i].R, switch_inf[i].Cin, switch_inf[i].Cout, switch_inf[i].Tdel); fprintf (fp,"\n\nR_minW_nmos: %g R_minW_pmos: %g\n", det_routing_arch.R_minW_nmos, det_routing_arch.R_minW_pmos); if (timing_inf.timing_analysis_enabled) { fprintf (fp, "\n\nTiming information:\n"); fprintf (fp,"---------------------------------------------------------\n"); fprintf (fp, "C_ipin_cblock: %g (F) \nT_ipin_cblock: %g (s)\n\n", timing_inf.C_ipin_cblock, timing_inf.T_ipin_cblock); fprintf (fp, "T_sblk_opin_to_sblk_ipin: %g (s)\n", timing_inf.T_sblk_opin_to_sblk_ipin); fprintf (fp, "T_clb_ipin_to_sblk_ipin: %g (s)\n", timing_inf.T_clb_ipin_to_sblk_ipin); fprintf (fp, "T_sblk_opin_to_clb_opin: %g (s)\n", timing_inf.T_sblk_opin_to_clb_opin); fprintf (fp,"T_ipad: %g (s) \nT_opad: %g (s)\n", timing_inf.T_ipad, timing_inf.T_opad); fprintf (fp,"\nSubblock #\tT_comb (s)\tT_seq_in (s)\tT_seq_out (s)\n"); for (i=0;i<subblock_data.max_subblocks_per_block;i++) { T_subblock = timing_inf.T_subblock[i]; fprintf (fp, "%10d\t%10g\t%10g\t%10g (s)\n", i, T_subblock.T_comb, T_subblock.T_seq_in, T_subblock.T_seq_out); } } fclose (fp);}void init_arch (float aspect_ratio, boolean user_sized) {/* Allocates various data structures that depend on the FPGA * * architecture. Aspect_ratio specifies how many columns there are * * relative to the number of rows -- i.e. width/height. Used-sized * * is TRUE if the user specified nx and ny already; in that case * * use the user's values and don't recompute them. */ int io_lim;/* User specified the dimensions on the command line. Check if they * * will fit the circuit. */ if (user_sized == TRUE) { if (num_clbs > nx * ny || num_p_inputs + num_p_outputs > 2 * io_rat * (nx + ny)) { printf ("Error: User-specified size is too small for circuit.\n"); exit (1); } }/* Size the FPGA automatically to be smallest that will fit circuit */ else {/* Area = nx * ny = ny * ny * aspect_ratio * * Perimeter = 2 * (nx + ny) = 2 * ny * (1. + aspect_ratio) */ ny = (int) ceil (sqrt ((double) (num_clbs / aspect_ratio))); io_lim = (int) ceil ((num_p_inputs + num_p_outputs) / (2 * io_rat * (1. + aspect_ratio))); ny = max (ny, io_lim); nx = (int) ceil (ny * aspect_ratio); }/* If both nx and ny are 1, we only have one valid location for a clb. * * That's a major problem, as won't be able to move the clb and the * * find_to routine that tries moves in the placer will go into an * * infinite loop trying to move it. Exit with an error message * * instead. */ if (nx == 1 && ny == 1 && num_clbs != 0) { printf ("Error:\n"); printf ("Sorry, can't place a circuit with only one valid location\n"); printf ("for a logic block (clb).\n"); printf ("Try me with a more realistic circuit!\n"); exit (1); }/* To remove this limitation, change ylow etc. in t_rr_node to * * be ints instead. Used shorts to save memory. */ if (nx > 32766 || ny > 32766) { printf("Error: nx and ny must be less than 32767, since the \n"); printf("router uses shorts (16-bit) to store coordinates.\n"); printf("nx: %d. ny: %d.\n", nx, ny); exit (1); } clb = (struct s_clb **) alloc_matrix (0, nx+1, 0, ny+1, sizeof(struct s_clb)); chan_width_x = (int *) my_malloc ((ny+1) * sizeof(int)); chan_width_y = (int *) my_malloc ((nx+1) * sizeof(int)); fill_arch();}static void fill_arch (void) {/* Fill some of the FPGA architecture data structures. */ int i, j, *index;/* allocate io_blocks arrays. Done this way to save storage */ i = 2*io_rat*(nx+ny); index = (int *) my_malloc (i*sizeof(int)); for (i=1;i<=nx;i++) { clb[i][0].u.io_blocks = index; index+=io_rat; clb[i][ny+1].u.io_blocks = index; index+=io_rat; } for (i=1;i<=ny;i++) { clb[0][i].u.io_blocks = index; index+=io_rat; clb[nx+1][i].u.io_blocks = index; index+=io_rat; } /* Initialize type, and occupancy. */ for (i=1;i<=nx;i++) { clb[i][0].type = IO; clb[i][ny+1].type = IO; /* perimeter (IO) cells */ } for (i=1;i<=ny;i++) { clb[0][i].type = IO; clb[nx+1][i].type = IO; } for (i=1;i<=nx;i++) { /* interior (LUT) cells */ for (j=1;j<=ny;j++) { clb[i][j].type = CLB; } }/* Nothing goes in the corners. */ clb[0][0].type = clb[nx+1][0].type = ILLEGAL; clb[0][ny+1].type = clb[nx+1][ny+1].type = ILLEGAL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -