/*--------------------------------------------------------------------------------------------- * (function: make_2port_logic_gates) * Make a 2 port gate with variable sizes. The first port will be input_pins index 0..width_port1. *-------------------------------------------------------------------------------------------*/ nnode_t *make_2port_gate(operation_list type, int width_port1, int width_port2, int width_output, nnode_t *node, short mark) { nnode_t *logic_node = allocate_nnode(); logic_node->traverse_visited = mark; logic_node->type = type; logic_node->name = node_name(logic_node, node->name); logic_node->related_ast_node = node->related_ast_node; /* add the input ports as needed */ allocate_more_input_pins(logic_node, width_port1); add_input_port_information(logic_node, width_port1); allocate_more_input_pins(logic_node, width_port2); add_input_port_information(logic_node, width_port2); /* add output */ allocate_more_output_pins(logic_node, width_output); add_output_port_information(logic_node, width_output); return logic_node; }
/*--------------------------------------------------------------------------------------------- * (function: make_nport_logic_gates) * Make a n port gate with variable sizes. The first port will be input_pins index 0..width_port1. *-------------------------------------------------------------------------------------------*/ nnode_t *make_nport_gate(operation_list type, int port_sizes, int width, int width_output, nnode_t *node, short mark) { int i; nnode_t *logic_node = allocate_nnode(); logic_node->traverse_visited = mark; logic_node->type = type; logic_node->name = node_name(logic_node, node->name); logic_node->related_ast_node = node->related_ast_node; /* add the input ports as needed */ for(i = 0; i < port_sizes; i++) { allocate_more_input_pins(logic_node, width); add_input_port_information(logic_node, width); } //allocate_more_input_pins(logic_node, width_port2); //add_input_port_information(logic_node, width_port2); /* add output */ allocate_more_output_pins(logic_node, width_output); add_output_port_information(logic_node, width_output); return logic_node; }
/*------------------------------------------------------------------------- * (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; }
/* * 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: 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; }