/*--------------------------------------------------------------------------------------------- * (function: make_not_gate_with_input) * Creates a not gate and attaches it to the inputs *-------------------------------------------------------------------------------------------*/ nnode_t *make_not_gate_with_input(npin_t *input_pin, nnode_t *node, short mark) { nnode_t *logic_node; logic_node = make_not_gate(node, mark); /* add the input ports as needed */ add_input_pin_to_node(logic_node, input_pin, 0); return logic_node; }
/*--------------------------------------------------------------------------------------------- * (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: 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: 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; }