/*--------------------------------------------------------------------------------------------- * (function: instantiate_logical_logic ) *-------------------------------------------------------------------------------------------*/ void instantiate_logical_logic(nnode_t *node, operation_list op, short mark, netlist_t *netlist) { int i; int port_B_offset; int width_a; int width_b; nnode_t *new_logic_cell; nnode_t *reduction1; nnode_t *reduction2; oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 2); oassert(node->num_output_pins == 1); /* setup the calculations for padding and indexing */ width_a = node->input_port_sizes[0]; width_b = node->input_port_sizes[1]; port_B_offset = width_a; /* instantiate the cells */ new_logic_cell = make_1port_logic_gate(op, 2, node, mark); reduction1 = make_1port_logic_gate(BITWISE_OR, width_a, node, mark); reduction2 = make_1port_logic_gate(BITWISE_OR, width_b, node, mark); /* connect inputs. In the case that a signal is smaller than the other then zero pad */ for(i = 0; i < width_a; i++) { /* Joining the inputs to the input 1 of that gate */ if (i < width_a) { remap_pin_to_new_node(node->input_pins[i], reduction1, i); } else { /* ELSE - the B input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(reduction1, get_a_zero_pin(netlist), i); } } for(i = 0; i < width_b; i++) { /* Joining the inputs to the input 1 of that gate */ if (i < width_b) { remap_pin_to_new_node(node->input_pins[i+port_B_offset], reduction2, i); } else { /* ELSE - the B input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(reduction2, get_a_zero_pin(netlist), i); } } connect_nodes(reduction1, 0, new_logic_cell, 0); connect_nodes(reduction2, 0, new_logic_cell, 1); instantiate_bitwise_reduction(reduction1, BITWISE_OR, mark, netlist); instantiate_bitwise_reduction(reduction2, BITWISE_OR, mark, netlist); remap_pin_to_new_node(node->output_pins[0], new_logic_cell, 0); }
/*------------------------------------------------------------------------- * (function: split_multiplier_a) * * This function works to split the "a" input of a multiplier into * several smaller multipliers to better "fit" with the available * resources in a targeted FPGA architecture. * * This function is at the lowest level since it simply receives * a multiplier and is told how to split it. The end result is: * * a1a0 * b => a0 * b + a1 * b => c * * Note that for the addition we need to perform sign extension, * but this should not be a problem since the sign extension is always * extending NOT contracting. * *-----------------------------------------------------------------------*/ void split_multiplier_a(nnode_t *node, int a0, int a1, int b) { nnode_t *a0b, *a1b, *addsmall; int i; /* Check for a legitimate split */ oassert(node->input_port_sizes[0] == (a0 + a1)); oassert(node->input_port_sizes[1] == b); /* New node for a0b multiply */ a0b = allocate_nnode(); a0b->name = (char *)malloc(strlen(node->name) + 3); strcpy(a0b->name, node->name); strcat(a0b->name, "-0"); init_split_multiplier(node, a0b, 0, a0, 0, b); mult_list = insert_in_vptr_list(mult_list, a0b); /* New node for a1b multiply */ a1b = allocate_nnode(); a1b->name = (char *)malloc(strlen(node->name) + 3); strcpy(a1b->name, node->name); strcat(a1b->name, "-1"); init_split_multiplier(node, a1b, a0, a1, 0, b); mult_list = insert_in_vptr_list(mult_list, a1b); /* New node for the add */ addsmall = allocate_nnode(); addsmall->name = (char *)malloc(strlen(node->name) + 6); strcpy(addsmall->name, node->name); strcat(addsmall->name, "-add0"); init_cascade_adder(addsmall, a1b, a1 + b); /* Connect pins for addsmall */ for (i = a0; i < a0b->output_port_sizes[0]; i++) connect_nodes(a0b, i, addsmall, i-a0); for (i = a0b->output_port_sizes[0] - a0; i < a1+b; i++) /* Sign extend */ connect_nodes(a0b, a0b->output_port_sizes[0]-1, addsmall, i); for (i = b+a1; i < (2 * (a1 + b)); i++) connect_nodes(a1b, i-(b+a1), addsmall, i); /* Move original output pins for multiply to new outputs */ for (i = 0; i < a0; i++) remap_pin_to_new_node(node->output_pins[i], a0b, i); for (i = a0; i < node->num_output_pins; i++) remap_pin_to_new_node(node->output_pins[i], addsmall, i-a0); /* Probably more to do here in freeing the old node! */ free(node->name); free(node->input_port_sizes); free(node->output_port_sizes); /* Free arrays NOT the pins since relocated! */ free(node->input_pins); free(node->output_pins); free(node); return; }
/*------------------------------------------------------------------------- * (function: split_multiplier_b) * * This function works to split the "b" input of a multiplier into * several smaller multipliers to better "fit" with the available * resources in a targeted FPGA architecture. * * This function is at the lowest level since it simply receives * a multiplier and is told how to split it. The end result is: * * a * b1b0 => a * b1 + a * b0 => c * * Note that for the addition we need to perform sign extension, * but this should not be a problem since the sign extension is always * extending NOT contracting. * *-----------------------------------------------------------------------*/ void split_multiplier_b(nnode_t *node, int a, int b1, int b0) { nnode_t *ab0, *ab1, *addsmall; int i; /* Check for a legitimate split */ oassert(node->input_port_sizes[0] == a); oassert(node->input_port_sizes[1] == (b0 + b1)); /* New node for ab0 multiply */ ab0 = allocate_nnode(); ab0->name = (char *)malloc(strlen(node->name) + 3); strcpy(ab0->name, node->name); strcat(ab0->name, "-0"); init_split_multiplier(node, ab0, 0, a, 0, b0); mult_list = insert_in_vptr_list(mult_list, ab0); /* New node for ab1 multiply */ ab1 = allocate_nnode(); ab1->name = (char *)malloc(strlen(node->name) + 3); strcpy(ab1->name, node->name); strcat(ab1->name, "-1"); init_split_multiplier(node, ab1, 0, a, b0, b1); mult_list = insert_in_vptr_list(mult_list, ab1); /* New node for the add */ addsmall = allocate_nnode(); addsmall->name = (char *)malloc(strlen(node->name) + 6); strcpy(addsmall->name, node->name); strcat(addsmall->name, "-add0"); init_cascade_adder(addsmall, ab1, a + b1); /* Connect pins for addsmall */ for (i = b0; i < ab0->output_port_sizes[0]; i++) connect_nodes(ab0, i, addsmall, i-b0); for (i = ab0->output_port_sizes[0] - b0; i < a+b1; i++) /* Sign extend */ connect_nodes(ab0, ab0->output_port_sizes[0]-1, addsmall, i); for (i = b1+a; i < (2 * (a + b1)); i++) connect_nodes(ab1, i-(b1+a), addsmall, i); /* Move original output pins for multiply to new outputs */ for (i = 0; i < b0; i++) remap_pin_to_new_node(node->output_pins[i], ab0, i); for (i = b0; i < node->num_output_pins; i++) remap_pin_to_new_node(node->output_pins[i], addsmall, i-b0); /* Probably more to do here in freeing the old node! */ free(node->name); free(node->input_port_sizes); free(node->output_port_sizes); /* Free arrays NOT the pins since relocated! */ free(node->input_pins); free(node->output_pins); free(node); return; }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_multi_port_mux ) * Makes the multiport into a series of 2-Mux-decoded *-------------------------------------------------------------------------------------------*/ void instantiate_multi_port_mux(nnode_t *node, short mark, netlist_t *netlist) { int i, j; int width_of_one_hot_logic; int num_ports; int port_offset; nnode_t **muxes; /* setup the calculations for padding and indexing */ width_of_one_hot_logic = node->input_port_sizes[0]; num_ports = node->num_input_port_sizes; port_offset = node->input_port_sizes[1]; muxes = (nnode_t**)malloc(sizeof(nnode_t*)*(num_ports-1)); for(i = 0; i < num_ports-1; i++) { muxes[i] = make_2port_gate(MUX_2, width_of_one_hot_logic, width_of_one_hot_logic, 1, node, mark); } for(j = 0; j < num_ports - 1; j++) { if (j == 0) { for(i = 0; i < width_of_one_hot_logic; i++) { /* map the inputs to the muxt */ remap_pin_to_new_node(node->input_pins[i+(j+1)*port_offset], muxes[j], width_of_one_hot_logic+i); /* map the one hot logic control */ remap_pin_to_new_node(node->input_pins[i], muxes[j], i); } } else { for(i = 0; i < width_of_one_hot_logic; i++) { /* map the inputs to the muxt */ remap_pin_to_new_node(node->input_pins[i+(j+1)*port_offset], muxes[j], width_of_one_hot_logic+i); /* map the one hot logic control */ add_a_input_pin_to_node_spot_idx(muxes[j], copy_input_npin(muxes[0]->input_pins[i]), i); } } /* now hookup outputs */ remap_pin_to_new_node(node->output_pins[j], muxes[j], 0); } }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_not_logic ) *-------------------------------------------------------------------------------------------*/ void instantiate_not_logic(nnode_t *node, short mark, netlist_t *netlist) { int width = node->num_input_pins; nnode_t **new_not_cells; int i; new_not_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width); for (i = 0; i < width; i++) { new_not_cells[i] = make_not_gate(node, mark); } /* connect inputs and outputs */ for(i = 0; i < width; i++) { /* Joining the inputs to the new soft NOT GATES */ remap_pin_to_new_node(node->input_pins[i], new_not_cells[i], 0); remap_pin_to_new_node(node->output_pins[i], new_not_cells[i], 0); } free(new_not_cells); }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_unary_sub ) * Does 2's complement which is the equivalent of a unary subtraction as a HW implementation. *-------------------------------------------------------------------------------------------*/ void instantiate_unary_sub(nnode_t *node, short mark, netlist_t *netlist) { int width; int i; nnode_t **new_add_cells; nnode_t **new_carry_cells; nnode_t **new_not_cells; oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 1); width = node->output_port_sizes[0]; new_add_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width); new_carry_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width); new_not_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width); /* create the adder units and the zero unit */ for (i = 0; i < width; i++) { new_add_cells[i] = make_3port_gate(ADDER_FUNC, 1, 1, 1, 1, node, mark); new_not_cells[i] = make_not_gate(node, mark); if (i < width - 1) { new_carry_cells[i] = make_3port_gate(CARRY_FUNC, 1, 1, 1, 1, node, mark); } } /* ground first carry in . Note the one constant is inputted to start 2's complement */ add_a_input_pin_to_node_spot_idx(new_add_cells[0], get_a_one_pin(netlist), 0); if (i > 1) { add_a_input_pin_to_node_spot_idx(new_carry_cells[0], get_a_one_pin(netlist), 0); } /* connect inputs */ for(i = 0; i < width; i++) { /* join the A port up to adder */ remap_pin_to_new_node(node->input_pins[i], new_not_cells[i], 0); connect_nodes(new_not_cells[i], 0, new_add_cells[i], 1); if (i < width - 1) connect_nodes(new_not_cells[i], 0, new_carry_cells[i], 1); add_a_input_pin_to_node_spot_idx(new_add_cells[i], get_a_zero_pin(netlist), 2); if (i < width - 1) add_a_input_pin_to_node_spot_idx(new_carry_cells[i], get_a_zero_pin(netlist), 2); /* join that gate to the output */ remap_pin_to_new_node(node->output_pins[i], new_add_cells[i], 0); } /* connect carry outs with carry ins */ for(i = 1; i < width; i++) { connect_nodes(new_carry_cells[i-1], 0, new_add_cells[i], 0); if (i < width - 1) connect_nodes(new_carry_cells[i-1], 0, new_carry_cells[i], 0); } free(new_add_cells); free(new_carry_cells); }
/*-------------------------------------------------------------------------- * (function: instantiate_add_w_carry ) * This is for soft addition in output formats that don't handle * multi-output logic functions (BLIF). We use one function for the * add, and one for the carry. *------------------------------------------------------------------------*/ void instantiate_add_w_carry(nnode_t *node, short mark, netlist_t *netlist) { int width; int width_a; int width_b; int i; nnode_t **new_add_cells; nnode_t **new_carry_cells; oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 2); width = node->output_port_sizes[0]; width_a = node->input_port_sizes[0]; width_b = node->input_port_sizes[1]; new_add_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width); new_carry_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width); /* create the adder units and the zero unit */ for (i = 0; i < width; i++) { new_add_cells[i] = make_3port_gate(ADDER_FUNC, 1, 1, 1, 1, node, mark); // The last carry cell will be connected to an output pin, if one is available new_carry_cells[i] = make_3port_gate(CARRY_FUNC, 1, 1, 1, 1, node, mark); } /* ground first carry in */ add_a_input_pin_to_node_spot_idx(new_add_cells[0], get_a_zero_pin(netlist), 0); if (i > 1) { add_a_input_pin_to_node_spot_idx(new_carry_cells[0], get_a_zero_pin(netlist), 0); } /* connect inputs */ for(i = 0; i < width; i++) { //printf("%s\n", node->input_pins[i]->name); if (i < width_a) { /* join the A port up to adder */ remap_pin_to_new_node(node->input_pins[i], new_add_cells[i], 1); if (i < width - 1) add_a_input_pin_to_node_spot_idx(new_carry_cells[i], copy_input_npin(new_add_cells[i]->input_pins[1]), 1); } else { add_a_input_pin_to_node_spot_idx(new_add_cells[i], get_a_zero_pin(netlist), 1); if (i < width - 1) add_a_input_pin_to_node_spot_idx(new_carry_cells[i], get_a_zero_pin(netlist), 1); } if (i < width_b) { /* join the B port up to adder */ remap_pin_to_new_node(node->input_pins[i+width_a], new_add_cells[i], 2); if (i < width - 1) add_a_input_pin_to_node_spot_idx(new_carry_cells[i], copy_input_npin(new_add_cells[i]->input_pins[2]), 2); } else { add_a_input_pin_to_node_spot_idx(new_add_cells[i], get_a_zero_pin(netlist), 2); if (i < width - 1) add_a_input_pin_to_node_spot_idx(new_carry_cells[i], get_a_zero_pin(netlist), 2); } /* join that gate to the output */ remap_pin_to_new_node(node->output_pins[i], new_add_cells[i], 0); } /* connect carry outs with carry ins */ for(i = 1; i < width; i++) { connect_nodes(new_carry_cells[i-1], 0, new_add_cells[i], 0); if (i < width - 1) connect_nodes(new_carry_cells[i-1], 0, new_carry_cells[i], 0); } free(new_add_cells); free(new_carry_cells); }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_bitwise_logic ) * Makes 2 input gates to break into bitwise *-------------------------------------------------------------------------------------------*/ void instantiate_bitwise_logic(nnode_t *node, operation_list op, short mark, netlist_t *netlist) { int width; int i; int port_B_offset; int width_a; int width_b; nnode_t **new_logic_cells; operation_list cell_op; oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 2); /* setup the calculations for padding and indexing */ width = node->output_port_sizes[0]; width_a = node->input_port_sizes[0]; width_b = node->input_port_sizes[1]; port_B_offset = width_a; switch (op) { case BITWISE_AND: cell_op = LOGICAL_AND; break; case BITWISE_OR: cell_op = LOGICAL_OR; break; case BITWISE_NAND: cell_op = LOGICAL_NAND; break; case BITWISE_NOR: cell_op = LOGICAL_NOR; break; case BITWISE_XNOR: cell_op = LOGICAL_XNOR; break; case BITWISE_XOR: cell_op = LOGICAL_XOR; break; default: cell_op = 0; oassert(FALSE); break; } new_logic_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width); for (i = 0; i < width; i++) { /* instantiate the cells */ new_logic_cells[i] = make_2port_gate(cell_op, 1, 1, 1, node, mark); } /* connect inputs. In the case that a signal is smaller than the other then zero pad */ for(i = 0; i < width; i++) { /* Joining the inputs to the input 1 of that gate */ if (i < width_a) { if (i < width_b) { /* IF - this current input will also have a corresponding b_port input then join it to the gate */ remap_pin_to_new_node(node->input_pins[i], new_logic_cells[i], 0); } else { /* ELSE - the B input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(new_logic_cells[i], get_a_zero_pin(netlist), 0); } } if (i < width_b) { if (i < width_a) { /* IF - this current input will also have a corresponding a_port input then join it to the gate */ /* Joining the inputs to the input 2 of that gate */ remap_pin_to_new_node(node->input_pins[i+port_B_offset], new_logic_cells[i], 1); } else { /* ELSE - the A input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(new_logic_cells[i], get_a_zero_pin(netlist), 1); } } remap_pin_to_new_node(node->output_pins[i], new_logic_cells[i], 0); } free(new_logic_cells); }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_bitwise_reduction ) * Makes 2 input gates to break into bitwise *-------------------------------------------------------------------------------------------*/ void instantiate_bitwise_reduction(nnode_t *node, operation_list op, short mark, netlist_t *netlist) { int i; int width_a; nnode_t *new_logic_cell; operation_list cell_op; oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 1); oassert(node->output_port_sizes[0] == 1); /* setup the calculations for padding and indexing */ width_a = node->input_port_sizes[0]; switch (op) { case BITWISE_AND: case LOGICAL_AND: cell_op = LOGICAL_AND; break; case BITWISE_OR: case LOGICAL_OR: cell_op = LOGICAL_OR; break; case BITWISE_NAND: case LOGICAL_NAND: cell_op = LOGICAL_NAND; break; case BITWISE_NOR: case LOGICAL_NOR: cell_op = LOGICAL_NOR; break; case BITWISE_XNOR: case LOGICAL_XNOR: cell_op = LOGICAL_XNOR; break; case BITWISE_XOR: case LOGICAL_XOR: cell_op = LOGICAL_XOR; break; default: cell_op = 0; oassert(FALSE); } /* instantiate the cells */ new_logic_cell = make_1port_logic_gate(cell_op, width_a, node, mark); /* connect inputs. In the case that a signal is smaller than the other then zero pad */ for(i = 0; i < width_a; i++) { /* Joining the inputs to the input 1 of that gate */ if (i < width_a) { remap_pin_to_new_node(node->input_pins[i], new_logic_cell, i); } else { /* ELSE - the B input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(new_logic_cell, get_a_zero_pin(netlist), i); } } remap_pin_to_new_node(node->output_pins[0], new_logic_cell, 0); }
/*------------------------------------------------------------------------- * (function: split_dp_memory_depth) * * This function works to split the depth of a dual port memory into * several smaller memories. *------------------------------------------------------------------------ */ void split_dp_memory_depth(nnode_t *node) { int addr1_port = -1; int addr2_port = -1; int we1_port = -1; int we2_port = -1; int logical_size; int i, j; int idx; int addr1_pin_idx = 0; int we1_pin_idx = 0; int addr2_pin_idx = 0; int we2_pin_idx = 0; nnode_t *new_mem_node; nnode_t *and1_node, *not1_node, *ff1_node, *mux1_node; nnode_t *and2_node, *not2_node, *ff2_node, *mux2_node; npin_t *addr1_pin = NULL; npin_t *addr2_pin = NULL; npin_t *we1_pin = NULL; npin_t *we2_pin = NULL; npin_t *twe_pin, *taddr_pin; npin_t *clk_pin = NULL; npin_t *tdout_pin; oassert(node->type == MEMORY); /* Find which ports are the addr1 and addr2 ports */ idx = 0; for (i = 0; i < node->num_input_port_sizes; i++) { if (strcmp("addr1", node->input_pins[idx]->mapping) == 0) { addr1_port = i; addr1_pin_idx = idx; addr1_pin = node->input_pins[idx]; } else if (strcmp("addr2", node->input_pins[idx]->mapping) == 0) { addr2_port = i; addr2_pin_idx = idx; addr2_pin = node->input_pins[idx]; } else if (strcmp("we1", node->input_pins[idx]->mapping) == 0) { we1_port = i; we1_pin = node->input_pins[idx]; we1_pin_idx = idx; } else if (strcmp("we2", node->input_pins[idx]->mapping) == 0) { we2_port = i; we2_pin = node->input_pins[idx]; we2_pin_idx = idx; } else if (strcmp("clk", node->input_pins[idx]->mapping) == 0) { clk_pin = node->input_pins[idx]; } idx += node->input_port_sizes[i]; } if (addr1_port == -1) { error_message(1, 0, -1, "No \"addr1\" port on dual port RAM"); } /* Jason Luu HACK: Logical memory depth determination messed up, forced to use this method */ for(i = 0; i < node->input_port_sizes[addr1_port]; i++) { if(strcmp(node->input_pins[addr1_pin_idx + i]->name, "top^ZERO_PAD_ZERO") == 0) break; } logical_size = i; /* Check that the memory needs to be split */ if (logical_size <= split_size) { dp_memory_list = insert_in_vptr_list(dp_memory_list, node); return; } /* Let's remove the address1 line from the memory */ for (i = addr1_pin_idx; i < node->num_input_pins - 1; i++) { node->input_pins[i] = node->input_pins[i+1]; node->input_pins[i]->pin_node_idx--; } node->input_port_sizes[addr1_port]--; node->input_pins = realloc(node->input_pins, sizeof(npin_t *) * --node->num_input_pins); if ((we1_port != -1) && (we1_pin_idx >= addr1_pin_idx)) we1_pin_idx--; if ((we2_port != -1) && (we2_pin_idx >= addr1_pin_idx)) we2_pin_idx--; if ((addr2_port != -1) && (addr2_pin_idx >= addr1_pin_idx)) addr2_pin_idx--; /* Let's remove the address2 line from the memory */ if (addr2_port != -1) { for (i = addr2_pin_idx; i < node->num_input_pins - 1; i++) { node->input_pins[i] = node->input_pins[i+1]; node->input_pins[i]->pin_node_idx--; } node->input_port_sizes[addr2_port]--; node->input_pins = realloc(node->input_pins, sizeof(npin_t *) * --node->num_input_pins); if ((we1_port != -1) && (we1_pin_idx >= addr2_pin_idx)) we1_pin_idx--; if ((we2_port != -1) && (we2_pin_idx >= addr2_pin_idx)) we2_pin_idx--; if (addr1_pin_idx >= addr2_pin_idx) addr1_pin_idx--; } /* Create the new memory node */ new_mem_node = allocate_nnode(); // Append the new name with an __H new_mem_node->name = append_string(node->name, "__H"); { // Append the old name with an __S char *new_name = append_string(node->name, "__S"); free(node->name); node->name = new_name; } /* Copy properties from the original memory node */ new_mem_node->type = node->type; new_mem_node->related_ast_node = node->related_ast_node; new_mem_node->traverse_visited = node->traverse_visited; // Copy over the port sizes for the new memory for (j = 0; j < node->num_output_port_sizes; j++) add_output_port_information(new_mem_node, node->output_port_sizes[j]); for (j = 0; j < node->num_input_port_sizes; j++) add_input_port_information (new_mem_node, node->input_port_sizes[j]); // allocate space for pins. allocate_more_node_output_pins (new_mem_node, node->num_output_pins); allocate_more_node_input_pins (new_mem_node, node->num_input_pins); // Copy over the pins for the new memory for (j = 0; j < node->num_input_pins; j++) add_a_input_pin_to_node_spot_idx(new_mem_node, copy_input_npin(node->input_pins[j]), j); if (we1_pin != NULL) { and1_node = make_2port_gate(LOGICAL_AND, 1, 1, 1, node, node->traverse_visited); twe_pin = copy_input_npin(we1_pin); add_a_input_pin_to_node_spot_idx(and1_node, twe_pin, 1); taddr_pin = copy_input_npin(addr1_pin); add_a_input_pin_to_node_spot_idx(and1_node, taddr_pin, 0); connect_nodes(and1_node, 0, node, we1_pin_idx); node->input_pins[we1_pin_idx]->mapping = we1_pin->mapping; } if (we2_pin != NULL) { and2_node = make_2port_gate(LOGICAL_AND, 1, 1, 1, node, node->traverse_visited); twe_pin = copy_input_npin(we2_pin); add_a_input_pin_to_node_spot_idx(and2_node, twe_pin, 1); taddr_pin = copy_input_npin(addr2_pin); add_a_input_pin_to_node_spot_idx(and2_node, taddr_pin, 0); connect_nodes(and2_node, 0, node, we2_pin_idx); node->input_pins[we2_pin_idx]->mapping = we2_pin->mapping; } if (we1_pin != NULL) { taddr_pin = copy_input_npin(addr1_pin); not1_node = make_not_gate_with_input(taddr_pin, new_mem_node, new_mem_node->traverse_visited); and1_node = make_2port_gate(LOGICAL_AND, 1, 1, 1, new_mem_node, new_mem_node->traverse_visited); connect_nodes(not1_node, 0, and1_node, 0); add_a_input_pin_to_node_spot_idx(and1_node, we1_pin, 1); connect_nodes(and1_node, 0, new_mem_node, we1_pin_idx); new_mem_node->input_pins[we1_pin_idx]->mapping = we1_pin->mapping; } if (we2_pin != NULL) { taddr_pin = copy_input_npin(addr2_pin); not2_node = make_not_gate_with_input(taddr_pin, new_mem_node, new_mem_node->traverse_visited); and2_node = make_2port_gate(LOGICAL_AND, 1, 1, 1, new_mem_node, new_mem_node->traverse_visited); connect_nodes(not2_node, 0, and2_node, 0); add_a_input_pin_to_node_spot_idx(and2_node, we2_pin, 1); connect_nodes(and2_node, 0, new_mem_node, we2_pin_idx); new_mem_node->input_pins[we2_pin_idx]->mapping = we2_pin->mapping; } if (node->num_output_pins > 0) /* There is an "out1" output */ { ff1_node = make_2port_gate(FF_NODE, 1, 1, 1, node, node->traverse_visited); add_a_input_pin_to_node_spot_idx(ff1_node, addr1_pin, 0); add_a_input_pin_to_node_spot_idx(ff1_node, copy_input_npin(clk_pin), 1); /* Copy over the output pins for the new memory */ for (j = 0; j < node->output_port_sizes[0]; j++) { mux1_node = make_2port_gate(MUX_2, 2, 2, 1, node, node->traverse_visited); connect_nodes(ff1_node, 0, mux1_node, 0); not1_node = make_not_gate(node, node->traverse_visited); connect_nodes(ff1_node, 0, not1_node, 0); connect_nodes(not1_node, 0, mux1_node, 1); tdout_pin = node->output_pins[j]; remap_pin_to_new_node(tdout_pin, mux1_node, 0); connect_nodes(node, j, mux1_node, 2); node->output_pins[j]->mapping = tdout_pin->mapping; connect_nodes(new_mem_node, j, mux1_node, 3); new_mem_node->output_pins[j]->mapping = tdout_pin->mapping; tdout_pin->mapping = NULL; mux1_node->output_pins[0]->name = mux1_node->name; } } if (node->num_output_pins > node->output_port_sizes[0]) /* There is an "out2" output */ { ff2_node = make_2port_gate(FF_NODE, 1, 1, 1, node, node->traverse_visited); add_a_input_pin_to_node_spot_idx(ff2_node, addr2_pin, 0); add_a_input_pin_to_node_spot_idx(ff2_node, copy_input_npin(clk_pin), 1); /* Copy over the output pins for the new memory */ for (j = 0; j < node->output_port_sizes[0]; j++) { mux2_node = make_2port_gate(MUX_2, 2, 2, 1, node, node->traverse_visited); connect_nodes(ff2_node, 0, mux2_node, 0); not2_node = make_not_gate(node, node->traverse_visited); connect_nodes(ff2_node, 0, not2_node, 0); connect_nodes(not2_node, 0, mux2_node, 1); tdout_pin = node->output_pins[node->output_port_sizes[0] + j]; remap_pin_to_new_node(tdout_pin, mux2_node, 0); connect_nodes(node, node->output_port_sizes[0] + j, mux2_node, 2); node->output_pins[node->output_port_sizes[0] + j]->mapping = tdout_pin->mapping; connect_nodes(new_mem_node, node->output_port_sizes[0] + j, mux2_node, 3); new_mem_node->output_pins[node->output_port_sizes[0] + j]->mapping = tdout_pin->mapping; tdout_pin->mapping = NULL; mux2_node->output_pins[0]->name = mux2_node->name; } } /* must recurse on new memory if it's too small */ if (logical_size <= split_size) { dp_memory_list = insert_in_vptr_list(dp_memory_list, new_mem_node); dp_memory_list = insert_in_vptr_list(dp_memory_list, node); } else { split_dp_memory_depth(node); split_dp_memory_depth(new_mem_node); } return; }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_shift_left_or_right ) * Creates the hardware for a shift left or right operation by a constant size. *-------------------------------------------------------------------------------------------*/ void instantiate_shift_left_or_right(nnode_t *node, short type, short mark, netlist_t *netlist) { /* these variables are used in an attempt so that I don't need if cases. Probably a bad idea, but fun */ int width; int i; int shift_size; nnode_t *buf_node; width = node->input_port_sizes[0]; if (node->related_ast_node->children[1]->type == NUMBERS) { /* record the size of the shift */ shift_size = node->related_ast_node->children[1]->types.number.value; } else { shift_size = 0; error_message(NETLIST_ERROR, node->related_ast_node->line_number, node->related_ast_node->file_number, "Odin only supports constant shifts at present\n"); } buf_node = make_1port_gate(BUF_NODE, width, width, node, mark); if (type == SL) { /* IF shift left */ /* connect inputs to outputs */ for(i = 0; i < width - shift_size; i++) { // connect higher output pin to lower input pin remap_pin_to_new_node(node->input_pins[i], buf_node, i+shift_size); } /* connect ZERO to outputs that don't have inputs connected */ for(i = 0; i < shift_size; i++) { // connect 0 to lower outputs add_a_input_pin_to_node_spot_idx(buf_node, get_a_zero_pin(netlist), i); } for(i = width-1; i >= width-shift_size; i--) { /* demap the node from the net */ int idx_2_buffer = node->input_pins[i]->pin_net_idx; node->input_pins[i]->net->fanout_pins[idx_2_buffer] = NULL; } } else { /* ELSE shift right */ /* connect inputs to outputs */ for(i = width - 1; i >= shift_size; i--) { // connect higher input pin to lower output pin remap_pin_to_new_node(node->input_pins[i], buf_node, i-shift_size); } /* connect ZERO to outputs that don't have inputs connected */ for(i = width - 1; i >= width - shift_size; i--) { // connect 0 to lower outputs add_a_input_pin_to_node_spot_idx(buf_node, get_a_zero_pin(netlist), i); } for(i = 0; i < shift_size; i++) { /* demap the node from the net */ int idx_2_buffer = node->input_pins[i]->pin_net_idx; node->input_pins[i]->net->fanout_pins[idx_2_buffer] = NULL; } } for(i = 0; i < width; i++) { remap_pin_to_new_node(node->output_pins[i], buf_node, i); } /* instantiate the buffer */ instantiate_buffer(buf_node, mark, netlist); }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_GE ) * Defines the HW needed for greter than equal with EQ, GT, AND and OR gates to create * the appropriate logic function. *-------------------------------------------------------------------------------------------*/ void instantiate_GE(nnode_t *node, short type, short mark, netlist_t *netlist) { int width_a; int width_b; int width_max; int i; int port_B_offset; int port_A_offset; nnode_t *equal; nnode_t *compare; nnode_t *logical_or_final_gate; oassert(node->num_output_pins == 1); oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 2); oassert(node->input_port_sizes[0] == node->input_port_sizes[1]); width_a = node->input_port_sizes[0]; width_b = node->input_port_sizes[1]; oassert(width_a == width_b); width_max = width_a > width_b ? width_a : width_b; port_A_offset = 0; port_B_offset = width_a; /* build an xnor bitwise XNOR */ equal = make_2port_gate(LOGICAL_EQUAL, width_a, width_b, 1, node, mark); if (type == GTE) compare = make_2port_gate(GT, width_a, width_b, 1, node, mark); else compare = make_2port_gate(LT, width_a, width_b, 1, node, mark); logical_or_final_gate = make_1port_logic_gate(LOGICAL_OR, 2, node, mark); /* connect inputs. In the case that a signal is smaller than the other then zero pad */ for(i = 0; i < width_max; i++) { /* Joining the inputs to the input 1 of that gate */ if (i < width_a) { /* IF - this current input will also have a corresponding b_port input then join it to the gate */ remap_pin_to_new_node(node->input_pins[i+port_A_offset], equal, i+port_A_offset); add_a_input_pin_to_node_spot_idx(compare, copy_input_npin(equal->input_pins[i+port_A_offset]), i+port_A_offset); } else { /* ELSE - the B input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(equal, get_a_zero_pin(netlist), i+port_A_offset); add_a_input_pin_to_node_spot_idx(compare, get_a_zero_pin(netlist), i+port_A_offset); } if (i < width_b) { /* IF - this current input will also have a corresponding a_port input then join it to the gate */ /* Joining the inputs to the input 2 of that gate */ remap_pin_to_new_node(node->input_pins[i+port_B_offset], equal, i+port_B_offset); add_a_input_pin_to_node_spot_idx(compare, copy_input_npin(equal->input_pins[i+port_B_offset]), i+port_B_offset); } else { /* ELSE - the A input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(equal, get_a_zero_pin(netlist), i+port_B_offset); add_a_input_pin_to_node_spot_idx(compare, get_a_zero_pin(netlist), i+port_B_offset); } } connect_nodes(equal, 0, logical_or_final_gate, 0); connect_nodes(compare, 0, logical_or_final_gate, 1); /* join that gate to the output */ remap_pin_to_new_node(node->output_pins[0], logical_or_final_gate, 0); oassert(logical_or_final_gate->num_output_pins == 1); /* make the two intermediate gates */ instantiate_EQUAL(equal, LOGICAL_EQUAL, mark, netlist); if (type == GTE) instantiate_GT(compare, GT, mark, netlist); else instantiate_GT(compare, LT, mark, netlist); }
/*------------------------------------------------------------------------- * (function: split_multiplier) * * This function works to split a multiplier into several smaller * multipliers to better "fit" with the available resources in a * targeted FPGA architecture. * * This function is at the lowest level since it simply receives * a multiplier and is told how to split it. The end result is: * * a1a0 * b1b0 => a0 * b0 + a0 * b1 + a1 * b0 + a1 * b1 => c1c0 => c * * If we "balance" the additions, we can actually remove one of the * addition operations since we know that a0 * b0 and a1 * b1 will * not overlap in bits. This allows us to skip the addition between * these two terms and simply concat the results together. Giving us * the resulting logic: * * ((a1 * b1) . (a0 * b0)) + ((a0 * b1) + (a1 * b0)) ==> Result * * Note that for some of the additions we need to perform sign extensions, * but this should not be a problem since the sign extension is always * extending NOT contracting. * *-----------------------------------------------------------------------*/ void split_multiplier(nnode_t *node, int a0, int b0, int a1, int b1) { nnode_t *a0b0, *a0b1, *a1b0, *a1b1, *addsmall, *addbig; int i, size; /* Check for a legitimate split */ oassert(node->input_port_sizes[0] == (a0 + a1)); oassert(node->input_port_sizes[1] == (b0 + b1)); /* New node for small multiply */ a0b0 = allocate_nnode(); a0b0->name = (char *)malloc(strlen(node->name) + 3); strcpy(a0b0->name, node->name); strcat(a0b0->name, "-0"); init_split_multiplier(node, a0b0, 0, a0, 0, b0); mult_list = insert_in_vptr_list(mult_list, a0b0); /* New node for big multiply */ a1b1 = allocate_nnode(); a1b1->name = (char *)malloc(strlen(node->name) + 3); strcpy(a1b1->name, node->name); strcat(a1b1->name, "-3"); init_split_multiplier(node, a1b1, a0, a1, b0, b1); mult_list = insert_in_vptr_list(mult_list, a1b1); /* New node for 2nd multiply */ a0b1 = allocate_nnode(); a0b1->name = (char *)malloc(strlen(node->name) + 3); strcpy(a0b1->name, node->name); strcat(a0b1->name, "-1"); init_split_multiplier(node, a0b1, 0, a0, b0, b1); mult_list = insert_in_vptr_list(mult_list, a0b1); /* New node for 3rd multiply */ a1b0 = allocate_nnode(); a1b0->name = (char *)malloc(strlen(node->name) + 3); strcpy(a1b0->name, node->name); strcat(a1b0->name, "-2"); init_split_multiplier(node, a1b0, a0, a1, 0, b0); mult_list = insert_in_vptr_list(mult_list, a1b0); /* New node for the initial add */ addsmall = allocate_nnode(); addsmall->name = (char *)malloc(strlen(node->name) + 6); strcpy(addsmall->name, node->name); strcat(addsmall->name, "-add0"); init_cascade_adder(addsmall, a1b0, a0b1->output_port_sizes[0]); /* New node for the BIG add */ addbig = allocate_nnode(); addbig->name = (char *)malloc(strlen(node->name) + 6); strcpy(addbig->name, node->name); strcat(addbig->name, "-add1"); init_cascade_adder(addbig, addsmall, a0b0->output_port_sizes[0] + a1b1->output_port_sizes[0]); /* Insert temporary pins for addsmall */ for (i = 0; i < a0b1->output_port_sizes[0]; i++) connect_nodes(a0b1, i, addsmall, i); for (i = 0; i < a1b0->output_port_sizes[0]; i++) connect_nodes(a1b0, i, addsmall, i+a0b1->output_port_sizes[0]); /* Insert temporary pins for addbig */ size = addsmall->output_port_sizes[0]; for (i = 0; i < size; i++) connect_nodes(addsmall, i, addbig, i); for (i = 0; i < a1b1->output_port_sizes[0]; i++) connect_nodes(a1b1, i, addbig, i + size); size = size + a1b1->output_port_sizes[0]; for (i = 0; i < a0b0->output_port_sizes[0]; i++) connect_nodes(a0b0, i, addbig, i + size); /* Move original output pins for multiply to addbig */ for (i = 0; i < addbig->num_output_pins; i++) remap_pin_to_new_node(node->output_pins[i], addbig, i); /* Probably more to do here in freeing the old node! */ free(node->name); free(node->input_port_sizes); free(node->output_port_sizes); /* Free arrays NOT the pins since relocated! */ free(node->input_pins); free(node->output_pins); free(node); return; }
/*--------------------------------------------------------------------------- * (function: instantiate_simple_soft_multiplier ) * Sample 4x4 multiplier to help understand logic. * * a3 a2 a1 a0 * b3 b2 b1 b0 * --------------------------- * c03 c02 c01 c00 * + c13 c12 c11 c10 * ----------------------------------- * r14 r13 r12 r11 r10 * + c23 c22 c21 c20 * ----------------------------------- * r24 r23 r22 r21 r20 * + c33 c32 c31 c30 * ------------------------------------ * o7 o6 o5 o4 o3 o2 o1 o0 * * In the first case will be c01 *-------------------------------------------------------------------------*/ void instantiate_simple_soft_multiplier(nnode_t *node, short mark, netlist_t *netlist) { int width_a; int width_b; int width; int multiplier_width; int multiplicand_width; nnode_t **adders_for_partial_products; nnode_t ***partial_products; int multiplicand_offset_index; int multiplier_offset_index; int current_index; int i, j; /* need for an carry-ripple-adder for each of the bits of port B. */ /* good question of which is better to put on the bottom of multiplier. Larger means more smaller adds, or small is * less large adds */ oassert(node->num_output_pins > 0); oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 2); oassert(node->num_output_port_sizes == 1); width_a = node->input_port_sizes[0]; width_b = node->input_port_sizes[1]; width = node->output_port_sizes[0]; multiplicand_width = width_b; multiplier_width = width_a; /* offset is related to which multport is chosen as the multiplicand */ multiplicand_offset_index = width_a; multiplier_offset_index = 0; adders_for_partial_products = (nnode_t**)malloc(sizeof(nnode_t*)*multiplicand_width-1); /* need to generate partial products for each bit in width B. */ partial_products = (nnode_t***)malloc(sizeof(nnode_t**)*multiplicand_width); /* generate the AND partial products */ for (i = 0; i < multiplicand_width; i++) { /* create the memory for each AND gate needed for the levels of partial products */ partial_products[i] = (nnode_t**)malloc(sizeof(nnode_t*)*multiplier_width); if (i < multiplicand_width - 1) { adders_for_partial_products[i] = make_2port_gate(ADD, multiplier_width+1, multiplier_width+1, multiplier_width+1, node, mark); } for (j = 0; j < multiplier_width; j++) { /* create each one of the partial products */ partial_products[i][j] = make_1port_logic_gate(LOGICAL_AND, 2, node, mark); } } /* generate the coneections to the AND gates */ for (i = 0; i < multiplicand_width; i++) { for (j = 0; j < multiplier_width; j++) { /* hookup the input of B to each AND gate */ if (j == 0) { /* IF - this is the first time we are mapping multiplicand port then can remap */ remap_pin_to_new_node(node->input_pins[i+multiplicand_offset_index], partial_products[i][j], 0); } else { /* ELSE - this needs to be a new ouput of the multiplicand port */ add_input_pin_to_node(partial_products[i][j], copy_input_npin(partial_products[i][0]->input_pins[0]), 0); } /* hookup the input of the multiplier to each AND gate */ if (i == 0) { /* IF - this is the first time we are mapping multiplier port then can remap */ remap_pin_to_new_node(node->input_pins[j+multiplier_offset_index], partial_products[i][j], 1); } else { /* ELSE - this needs to be a new ouput of the multiplier port */ add_input_pin_to_node(partial_products[i][j], copy_input_npin(partial_products[0][j]->input_pins[1]), 1); } } } /* hookup each of the adders */ for (i = 0; i < multiplicand_width-1; i++) // -1 since the first stage is a combo of partial products while all others are part of tree { for (j = 0; j < multiplier_width+1; j++) // +1 since adders are one greater than multwidth to pass carry { /* join to port 1 of the add one of the partial products. */ if (i == 0) { /* IF - this is the first addition row, then adding two sets of partial products and first set is from the c0* */ if (j < multiplier_width-1) { /* IF - we just take an element of the first list c[0][j+1]. */ connect_nodes(partial_products[i][j+1], 0, adders_for_partial_products[i], j); } else { /* ELSE - this is the last input to the first adder, then we pass in 0 since no carry yet */ add_input_pin_to_node(adders_for_partial_products[i], get_zero_pin(netlist), j); } } else if (j < multiplier_width) { /* ELSE - this is the standard situation when we need to hookup this adder with a previous adder, r[i-1][j+1] */ connect_nodes(adders_for_partial_products[i-1], j+1, adders_for_partial_products[i], j); } else { add_input_pin_to_node(adders_for_partial_products[i], get_zero_pin(netlist), j); } if (j < multiplier_width) { /* IF - this is not most significant bit then just add current partial product */ connect_nodes(partial_products[i+1][j], 0, adders_for_partial_products[i], j+multiplier_width+1); } else { add_input_pin_to_node(adders_for_partial_products[i], get_zero_pin(netlist), j+multiplier_width+1); } } } current_index = 0; /* hookup the outputs */ for (i = 0; i < width; i++) { if (multiplicand_width == 1) { // this is undealt with error_message(1,-1,-1,"Cannot create soft multiplier with multiplicand width of 1.\n"); } else if (i == 0) { /* IF - this is the LSbit, then we use a pass through from the partial product */ remap_pin_to_new_node(node->output_pins[i], partial_products[0][0], 0); } else if (i < multiplicand_width - 1) { /* ELSE IF - these are the middle values that come from the LSbit of partial adders */ remap_pin_to_new_node(node->output_pins[i], adders_for_partial_products[i-1], 0); } else { /* ELSE - the final outputs are straight from the outputs of the last adder */ remap_pin_to_new_node(node->output_pins[i], adders_for_partial_products[multiplicand_width-2], current_index); current_index++; } } /* soft map the adders if they need to be mapped */ for (i = 0; i < multiplicand_width - 1; i++) { instantiate_add_w_carry(adders_for_partial_products[i], mark, netlist); } /* Cleanup everything */ if (adders_for_partial_products != NULL) { free(adders_for_partial_products); } /* generate the AND partial products */ for (i = 0; i < multiplicand_width; i++) { /* create the memory for each AND gate needed for the levels of partial products */ if (partial_products[i] != NULL) { free(partial_products[i]); } } if (partial_products != NULL) { free(partial_products); } }
/* * Width-splits the given memory up into chunks the of the * width specified in the arch file. */ void split_sp_memory_to_arch_width(nnode_t *node) { char *port_name = "data"; t_model *model = single_port_rams; int data_port_number = get_input_port_index_from_mapping(node, port_name); oassert(data_port_number != -1); int data_port_size = node->input_port_sizes[data_port_number]; // Get the target width from the arch. t_model_ports *ports = get_model_port(model->inputs, port_name); int target_size = ports->size; int num_memories = ceil((double)data_port_size / (double)target_size); if (data_port_size > target_size) { int i; int data_pins_moved = 0; int output_pins_moved = 0; for (i = 0; i < num_memories; i++) { nnode_t *new_node = allocate_nnode(); new_node->name = append_string(node->name, "-%d",i); sp_memory_list = insert_in_vptr_list(sp_memory_list, new_node); /* Copy properties from the original node */ new_node->type = node->type; new_node->related_ast_node = node->related_ast_node; new_node->traverse_visited = node->traverse_visited; new_node->node_data = NULL; int j; for (j = 0; j < node->num_input_port_sizes; j++) add_input_port_information(new_node, 0); add_output_port_information(new_node, 0); int index = 0; int old_index = 0; for (j = 0; j < node->num_input_port_sizes; j++) { // Move this node's share of data pins out of the data port of the original node. if (j == data_port_number) { // Skip over data pins we've already moved. old_index += data_pins_moved; int k; for (k = 0; k < target_size && data_pins_moved < data_port_size; k++) { allocate_more_node_input_pins(new_node, 1); new_node->input_port_sizes[j]++; remap_pin_to_new_node(node->input_pins[old_index], new_node, index); index++; old_index++; data_pins_moved++; } int remaining_data_pins = data_port_size - data_pins_moved; // Skip over pins we have yet to copy. old_index += remaining_data_pins; } else { int k; for (k = 0; k < node->input_port_sizes[j]; k++) { allocate_more_node_input_pins(new_node, 1); new_node->input_port_sizes[j]++; // Copy pins for all but the last memory. the last one get the original pins moved to it. if (i < num_memories - 1) add_a_input_pin_to_node_spot_idx(new_node, copy_input_npin(node->input_pins[old_index]), index); else remap_pin_to_new_node(node->input_pins[old_index], new_node, index); index++; old_index++; } } } index = 0; old_index = 0; old_index += output_pins_moved; int k; for (k = 0; k < target_size && output_pins_moved < data_port_size; k++) { allocate_more_node_output_pins(new_node, 1); new_node->output_port_sizes[0]++; remap_pin_to_new_node(node->output_pins[old_index], new_node, index); index++; old_index++; output_pins_moved++; } } // Free the original node. free_nnode(node); } else { sp_memory_list = insert_in_vptr_list(sp_memory_list, node); } }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_EQUAL ) * Builds the hardware for an equal comparison by building EQ for parallel lines and then * taking them all through an AND tree. *-------------------------------------------------------------------------------------------*/ void instantiate_EQUAL(nnode_t *node, short type, short mark, netlist_t *netlist) { int width_a; int width_b; int width_max; int i; int port_B_offset; nnode_t *compare; nnode_t *combine; oassert(node->num_output_pins == 1); oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 2); width_a = node->input_port_sizes[0]; width_b = node->input_port_sizes[1]; width_max = width_a > width_b ? width_a : width_b; port_B_offset = width_a; /* build an xnor bitwise XNOR */ if (type == LOGICAL_EQUAL) { compare = make_2port_gate(LOGICAL_XNOR, width_a, width_b, width_max, node, mark); combine = make_1port_logic_gate(LOGICAL_AND, width_max, node, mark); } else { compare = make_2port_gate(LOGICAL_XOR, width_a, width_b, width_max, node, mark); combine = make_1port_logic_gate(LOGICAL_OR, width_max, node, mark); } /* build an and bitwise AND */ /* connect inputs. In the case that a signal is smaller than the other then zero pad */ for(i = 0; i < width_max; i++) { /* Joining the inputs to the input 1 of that gate */ if (i < width_a) { if (i < width_b) { /* IF - this current input will also have a corresponding b_port input then join it to the gate */ remap_pin_to_new_node(node->input_pins[i], compare, i); } else { /* ELSE - the B input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(compare, get_a_zero_pin(netlist), i); } } if (i < width_b) { if (i < width_a) { /* IF - this current input will also have a corresponding a_port input then join it to the gate */ /* Joining the inputs to the input 2 of that gate */ remap_pin_to_new_node(node->input_pins[i+port_B_offset], compare, i+port_B_offset); } else { /* ELSE - the A input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(compare, get_a_zero_pin(netlist), i+port_B_offset); } } /* hook it up to the logcial AND */ connect_nodes(compare, i, combine, i); } /* join that gate to the output */ remap_pin_to_new_node(node->output_pins[0], combine, 0); if (type == LOGICAL_EQUAL) instantiate_bitwise_logic(compare, BITWISE_XNOR, mark, netlist); else instantiate_bitwise_logic(compare, BITWISE_XOR, mark, netlist); /* Don't need to instantiate a Logic and gate since it is a function itself */ oassert(combine->num_output_pins == 1); }
/*--------------------------------------------------------------------------------------------- * (function: instantiate_GT ) * Defines the HW needed for greter than equal with EQ, GT, AND and OR gates to create * the appropriate logic function. *-------------------------------------------------------------------------------------------*/ void instantiate_GT(nnode_t *node, short type, short mark, netlist_t *netlist) { int width_a; int width_b; int width_max; int i; int port_A_offset; int port_B_offset; int port_A_index; int port_B_index; int index = 0; nnode_t *xor_gate; nnode_t *logical_or_gate; nnode_t **or_cells; nnode_t **gt_cells; oassert(node->num_output_pins == 1); oassert(node->num_input_pins > 0); oassert(node->num_input_port_sizes == 2); oassert(node->input_port_sizes[0] == node->input_port_sizes[1]); width_a = node->input_port_sizes[0]; width_b = node->input_port_sizes[1]; width_max = width_a > width_b ? width_a : width_b; /* swaps ports A and B */ if (type == GT) { port_A_offset = 0; port_B_offset = width_a; port_A_index = 0; port_B_index = width_a-1; } else if (type == LT) { port_A_offset = width_b; port_B_offset = 0; port_A_index = width_b-1; port_B_index = 0; } else { port_A_offset = 0; port_B_offset = 0; port_A_index = 0; port_B_index = 0; error_message(NETLIST_ERROR, node->related_ast_node->line_number, node->related_ast_node->file_number, "Invalid node type in instantiate_GT\n"); } /* xor gate identifies if any bits don't match */ xor_gate = make_2port_gate(LOGICAL_XOR, width_a-1, width_b-1, width_max-1, node, mark); /* collects all the GT signals and determines if gt */ logical_or_gate = make_1port_logic_gate(LOGICAL_OR, width_max, node, mark); /* collects a chain if any 1 happens than the GT cells output 0 */ or_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width_max-1); /* each cell checks if A > B and sends out a 1 if history has no 1s (3rd input) */ gt_cells = (nnode_t**)malloc(sizeof(nnode_t*)*width_max); for (i = 0; i < width_max; i++) { gt_cells[i] = make_3port_gate(GT, 1, 1, 1, 1, node, mark); if (i < width_max-1) { or_cells[i] = make_2port_gate(LOGICAL_OR, 1, 1, 1, node, mark); } } /* connect inputs. In the case that a signal is smaller than the other then zero pad */ for(i = 0; i < width_max; i++) { /* Joining the inputs to the input 1 of that gate */ if (i < width_a) { /* IF - this current input will also have a corresponding b_port input then join it to the gate */ remap_pin_to_new_node(node->input_pins[i+port_A_offset], gt_cells[i], 0); if (i > 0) add_a_input_pin_to_node_spot_idx(xor_gate, copy_input_npin(gt_cells[i]->input_pins[0]), index+port_A_index); } else { /* ELSE - the B input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(gt_cells[i], get_a_zero_pin(netlist), 0); if (i > 0) add_a_input_pin_to_node_spot_idx(xor_gate, get_a_zero_pin(netlist), index+port_A_index); } if (i < width_b) { /* IF - this current input will also have a corresponding a_port input then join it to the gate */ /* Joining the inputs to the input 2 of that gate */ remap_pin_to_new_node(node->input_pins[i+port_B_offset], gt_cells[i], 1); if (i > 0) add_a_input_pin_to_node_spot_idx(xor_gate, copy_input_npin(gt_cells[i]->input_pins[1]), index+port_B_index); } else { /* ELSE - the A input does not exist, so this answer goes right through */ add_a_input_pin_to_node_spot_idx(gt_cells[i], get_a_zero_pin(netlist), 1); if (i > 0) add_a_input_pin_to_node_spot_idx(xor_gate, get_a_zero_pin(netlist), index+port_B_index); } if (i < width_max-1) { /* number of OR gates */ if (i < width_max-2) { /* connect the msb or to the next lower bit */ connect_nodes(or_cells[i+1], 0, or_cells[i], 1); } else { /* deal with the first greater than test which autom gets a zero */ add_a_input_pin_to_node_spot_idx(or_cells[i], get_a_zero_pin(netlist), 1); } /* get all the equals with the or gates */ connect_nodes(xor_gate, i, or_cells[i], 0); connect_nodes(or_cells[i], 0, gt_cells[i], 2); } else { /* deal with the first greater than test which autom gets a zero */ add_a_input_pin_to_node_spot_idx(gt_cells[i], get_a_zero_pin(netlist), 2); } /* hook it up to the logcial AND */ connect_nodes(gt_cells[i], 0, logical_or_gate, i); if (i > 0) { index++; } } /* join that gate to the output */ remap_pin_to_new_node(node->output_pins[0], logical_or_gate, 0); oassert(logical_or_gate->num_output_pins == 1); instantiate_bitwise_logic(xor_gate, BITWISE_XOR, mark, netlist); }
/*------------------------------------------------------------------------- * (function: split_sp_memory_depth) * * This function works to split the depth of a single port memory into * several smaller memories. *------------------------------------------------------------------------ */ void split_sp_memory_depth(nnode_t *node) { int data_port = -1; int clk_port = -1; int addr_port = -1; int we_port = -1; int logical_size; int i, j; int idx; int addr_pin_idx = 0; int we_pin_idx = 0; nnode_t *new_mem_node; nnode_t *and_node, *not_node, *mux_node, *ff_node; npin_t *addr_pin = NULL; npin_t *we_pin = NULL; npin_t *clk_pin = NULL; npin_t *tdout_pin; oassert(node->type == MEMORY); // Find which port is the addr port idx = 0; for (i = 0; i < node->num_input_port_sizes; i++) { //printf("%s\n", node->input_pins[idx]->mapping); if (strcmp("addr", node->input_pins[idx]->mapping) == 0) { addr_port = i; addr_pin_idx = idx; addr_pin = node->input_pins[idx]; } else if (strcmp("data", node->input_pins[idx]->mapping) == 0) { data_port = i; } else if (strcmp("we", node->input_pins[idx]->mapping) == 0) { we_port = i; we_pin = node->input_pins[idx]; we_pin_idx = idx; } else if (strcmp("clk", node->input_pins[idx]->mapping) == 0) { clk_port = i; clk_pin = node->input_pins[idx]; } idx += node->input_port_sizes[i]; } if (data_port == -1) { error_message(1, 0, -1, "No \"data\" port on single port RAM"); } if (addr_port == -1) { error_message(1, 0, -1, "No \"addr\" port on single port RAM"); } if (we_port == -1) { error_message(1, 0, -1, "No \"we\" port on single port RAM"); } if (clk_port == -1) { error_message(1, 0, -1, "No \"clk\" port on single port RAM"); } // Check that the memory needs to be split // Jason Luu HACK: Logical memory depth determination messed up, forced to use this method for(i = 0; i < node->input_port_sizes[addr_port]; i++) { if(strcmp(node->input_pins[addr_pin_idx + i]->name, "top^ZERO_PAD_ZERO") == 0) break; } logical_size = i; if (split_size <= 0) { printf("Unsupported feature! Split size must be a positive number\n"); exit(1); } if ((split_size > 0) && (logical_size <= split_size)) { sp_memory_list = insert_in_vptr_list(sp_memory_list, node); return; } // Let's remove the address line from the memory for (i = addr_pin_idx; i < node->num_input_pins - 1; i++) { node->input_pins[i] = node->input_pins[i+1]; node->input_pins[i]->pin_node_idx--; } node->input_port_sizes[addr_port]--; node->input_pins = realloc(node->input_pins, sizeof(npin_t *) * --node->num_input_pins); if (we_pin_idx >= addr_pin_idx) we_pin_idx--; // Create the new memory node new_mem_node = allocate_nnode(); // Append the new name with an __H new_mem_node->name = append_string(node->name, "__H"); { // Append the old name with an __S char *new_name = append_string(node->name, "__S"); free(node->name); node->name = new_name; } // Copy properties from the original memory node new_mem_node->type = node->type; new_mem_node->related_ast_node = node->related_ast_node; new_mem_node->traverse_visited = node->traverse_visited; add_output_port_information(new_mem_node, node->num_output_pins); allocate_more_node_output_pins (new_mem_node, node->num_output_pins); for (j = 0; j < node->num_input_port_sizes; j++) add_input_port_information(new_mem_node, node->input_port_sizes[j]); // Copy over the input pins for the new memory, excluding we allocate_more_node_input_pins (new_mem_node, node->num_input_pins); for (j = 0; j < node->num_input_pins; j++) { if (j != we_pin_idx) add_a_input_pin_to_node_spot_idx(new_mem_node, copy_input_npin(node->input_pins[j]), j); } and_node = make_2port_gate(LOGICAL_AND, 1, 1, 1, node, node->traverse_visited); add_a_input_pin_to_node_spot_idx(and_node, we_pin, 1); add_a_input_pin_to_node_spot_idx(and_node, addr_pin, 0); connect_nodes(and_node, 0, node, we_pin_idx); node->input_pins[we_pin_idx]->mapping = we_pin->mapping; not_node = make_not_gate_with_input(copy_input_npin(addr_pin), new_mem_node, new_mem_node->traverse_visited); and_node = make_2port_gate(LOGICAL_AND, 1, 1, 1, new_mem_node, new_mem_node->traverse_visited); connect_nodes(not_node, 0, and_node, 0); add_a_input_pin_to_node_spot_idx(and_node, copy_input_npin(we_pin), 1); connect_nodes(and_node, 0, new_mem_node, we_pin_idx); new_mem_node->input_pins[we_pin_idx]->mapping = we_pin->mapping; ff_node = make_2port_gate(FF_NODE, 1, 1, 1, node, node->traverse_visited); add_a_input_pin_to_node_spot_idx(ff_node, copy_input_npin(addr_pin), 0); add_a_input_pin_to_node_spot_idx(ff_node, copy_input_npin(clk_pin), 1); // Copy over the output pins for the new memory for (j = 0; j < node->num_output_pins; j++) { mux_node = make_2port_gate(MUX_2, 2, 2, 1, node, node->traverse_visited); connect_nodes(ff_node, 0, mux_node, 0); not_node = make_not_gate(node, node->traverse_visited); connect_nodes(ff_node, 0, not_node, 0); connect_nodes(not_node, 0, mux_node, 1); tdout_pin = node->output_pins[j]; remap_pin_to_new_node(tdout_pin, mux_node, 0); connect_nodes(node, j, mux_node, 2); node->output_pins[j]->mapping = tdout_pin->mapping; connect_nodes(new_mem_node, j, mux_node, 3); new_mem_node->output_pins[j]->mapping = tdout_pin->mapping; tdout_pin->mapping = NULL; mux_node->output_pins[0]->name = mux_node->name; } // must recurse on new memory if it's too small if (logical_size <= split_size) { sp_memory_list = insert_in_vptr_list(sp_memory_list, new_mem_node); sp_memory_list = insert_in_vptr_list(sp_memory_list, node); } else { split_sp_memory_depth(node); split_sp_memory_depth(new_mem_node); } return; }