/*--------------------------------------------------------------------------------------------- * (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: 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: 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_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: 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: 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); } }