| /* |
| Permission is hereby granted, free of charge, to any person |
| obtaining a copy of this software and associated documentation |
| files (the "Software"), to deal in the Software without |
| restriction, including without limitation the rights to use, |
| copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the |
| Software is furnished to do so, subject to the following |
| conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "odin_types.h" |
| #include "odin_util.h" |
| #include "odin_globals.h" |
| #include "netlist_utils.h" |
| #include "hard_blocks.h" |
| #include "memories.h" |
| |
| STRING_CACHE *hard_block_names = NULL; |
| |
| void cache_hard_block_names(); |
| void register_hb_port_size(t_model_ports *hb_ports, int size); |
| |
| |
| void register_hb_port_size(t_model_ports *hb_ports, int size) |
| { |
| if(hb_ports) |
| hb_ports->size = size; |
| /*** |
| * else |
| * TODO error |
| */ |
| |
| } |
| |
| t_model_ports *get_model_port(t_model_ports *ports, const char *name) |
| { |
| while (ports && strcmp(ports->name, name)) |
| ports = ports->next; |
| |
| return ports; |
| } |
| |
| void cache_hard_block_names() |
| { |
| t_model *hard_blocks = NULL; |
| |
| hard_blocks = Arch.models; |
| hard_block_names = sc_new_string_cache(); |
| while (hard_blocks) |
| { |
| sc_add_string(hard_block_names, hard_blocks->name); |
| hard_blocks = hard_blocks->next; |
| } |
| } |
| |
| |
| void register_hard_blocks() |
| { |
| cache_hard_block_names(); |
| single_port_rams = find_hard_block(SINGLE_PORT_RAM_string); |
| dual_port_rams = find_hard_block(DUAL_PORT_RAM_string); |
| |
| if (single_port_rams) |
| { |
| if (configuration.split_memory_width) |
| { |
| register_hb_port_size( |
| get_model_port(single_port_rams->inputs, "data") |
| , 1); |
| |
| register_hb_port_size( |
| get_model_port(single_port_rams->outputs, "out") |
| , 1); |
| } |
| |
| register_hb_port_size( |
| get_model_port(single_port_rams->inputs, "addr") |
| ,get_sp_ram_split_depth()); |
| } |
| |
| if (dual_port_rams) |
| { |
| if (configuration.split_memory_width) |
| { |
| register_hb_port_size( |
| get_model_port(dual_port_rams->inputs, "data1") |
| , 1); |
| register_hb_port_size( |
| get_model_port(dual_port_rams->inputs, "data2") |
| , 1); |
| |
| register_hb_port_size( |
| get_model_port(dual_port_rams->outputs, "out1") |
| , 1); |
| register_hb_port_size( |
| get_model_port(dual_port_rams->outputs, "out2") |
| , 1); |
| } |
| |
| int split_depth = get_dp_ram_split_depth(); |
| |
| register_hb_port_size( |
| get_model_port(dual_port_rams->inputs, "addr1") |
| , split_depth); |
| register_hb_port_size( |
| get_model_port(dual_port_rams->inputs, "addr2") |
| , split_depth); |
| } |
| } |
| |
| void deregister_hard_blocks() |
| { |
| sc_free_string_cache(hard_block_names); |
| return; |
| } |
| |
| t_model* find_hard_block(const char *name) |
| { |
| t_model *hard_blocks; |
| |
| hard_blocks = Arch.models; |
| while (hard_blocks) |
| if (!strcmp(hard_blocks->name, name)) |
| return hard_blocks; |
| else |
| hard_blocks = hard_blocks->next; |
| |
| return NULL; |
| } |
| |
| void define_hard_block(nnode_t *node, FILE *out) |
| { |
| int i, j; |
| int index, port; |
| int count; |
| char buffer[MAX_BUF]; |
| |
| /* Assert that every hard block has at least an input and output */ |
| oassert(node->input_port_sizes[0] > 0); |
| oassert(node->output_port_sizes[0] > 0); |
| |
| //IF the hard_blocks is an adder or a multiplier, we ignore it.(Already print out in define_add_function and define_mult_function) |
| if(strcmp(node->related_ast_node->children[0]->types.identifier, "multiply") == 0 || strcmp(node->related_ast_node->children[0]->types.identifier, "adder") == 0) |
| return; |
| |
| count = fprintf(out, "\n.subckt "); |
| count--; |
| count += fprintf(out, "%s", node->related_ast_node->children[0]->types.identifier); |
| |
| /* print the input port mappings */ |
| port = index = 0; |
| for (i = 0; i < node->num_input_pins; i++) |
| { |
| /* Check that the input pin is driven */ |
| if (node->input_pins[i]->net->driver_pin == NULL |
| && node->input_pins[i]->net != verilog_netlist->zero_net |
| && node->input_pins[i]->net != verilog_netlist->one_net |
| && node->input_pins[i]->net != verilog_netlist->pad_net) |
| { |
| warning_message(NETLIST_ERROR, -1, -1, "Signal %s is not driven. padding with ground\n", node->input_pins[i]->name); |
| add_fanout_pin_to_net(verilog_netlist->zero_net, node->input_pins[i]); |
| } |
| |
| if (node->input_port_sizes[port] == 1) |
| j = odin_sprintf(buffer, " %s=%s", node->input_pins[i]->mapping, node->input_pins[i]->net->driver_pin->node->name); |
| else |
| { |
| if (node->input_pins[i]->net->driver_pin->name != NULL) |
| j = odin_sprintf(buffer, " %s[%d]=%s", node->input_pins[i]->mapping, index, node->input_pins[i]->net->driver_pin->name); |
| else |
| j = odin_sprintf(buffer, " %s[%d]=%s", node->input_pins[i]->mapping, index, node->input_pins[i]->net->driver_pin->node->name); |
| } |
| |
| if (count + j > 79) |
| { |
| fprintf(out, "\\\n"); |
| count = 0; |
| } |
| count += fprintf(out, "%s", buffer); |
| |
| index++; |
| if (node->input_port_sizes[port] == index) |
| { |
| index = 0; |
| port++; |
| } |
| } |
| |
| /* print the output port mappings */ |
| port = index = 0; |
| for (i = 0; i < node->num_output_pins; i++) |
| { |
| if (node->output_port_sizes[port] != 1) |
| j = odin_sprintf(buffer, " %s[%d]=%s", node->output_pins[i]->mapping, index, node->output_pins[i]->name); |
| else |
| j = odin_sprintf(buffer, " %s=%s", node->output_pins[i]->mapping, node->output_pins[i]->name); |
| |
| if (count + j > 79) |
| { |
| fprintf(out, "\\\n"); |
| count = 0; |
| } |
| count += fprintf(out, "%s", buffer); |
| |
| index++; |
| if (node->output_port_sizes[port] == index) |
| { |
| index = 0; |
| port++; |
| } |
| } |
| |
| count += fprintf(out, "\n\n"); |
| return; |
| } |
| |
| void output_hard_blocks(FILE *out) |
| { |
| t_model_ports *hb_ports; |
| t_model *hard_blocks; |
| char buffer[MAX_BUF]; |
| int count; |
| int i; |
| |
| oassert(out != NULL); |
| hard_blocks = Arch.models; |
| while (hard_blocks != NULL) |
| { |
| if (hard_blocks->used == 1) /* Hard Block is utilized */ |
| { |
| //IF the hard_blocks is an adder or a multiplier, we ignore it.(Already print out in add_the_blackbox_for_adds and add_the_blackbox_for_mults) |
| if(strcmp(hard_blocks->name, "adder") == 0 ||strcmp(hard_blocks->name, "multiply") == 0) |
| { |
| hard_blocks = hard_blocks->next; |
| break; |
| } |
| |
| fprintf(out, "\n.model %s\n", hard_blocks->name); |
| count = fprintf(out, ".inputs"); |
| hb_ports = hard_blocks->inputs; |
| while (hb_ports != NULL) |
| { |
| for (i = 0; i < hb_ports->size; i++) |
| { |
| if (hb_ports->size == 1) |
| count = count + odin_sprintf(buffer, " %s", hb_ports->name); |
| else |
| count = count + odin_sprintf(buffer, " %s[%d]", hb_ports->name, i); |
| |
| if (count >= 78) |
| count = fprintf(out, " \\\n%s", buffer) - 3; |
| else |
| fprintf(out, "%s", buffer); |
| } |
| hb_ports = hb_ports->next; |
| } |
| |
| count = fprintf(out, "\n.outputs") - 1; |
| hb_ports = hard_blocks->outputs; |
| while (hb_ports != NULL) |
| { |
| for (i = 0; i < hb_ports->size; i++) |
| { |
| if (hb_ports->size == 1) |
| count = count + odin_sprintf(buffer, " %s", hb_ports->name); |
| else |
| count = count + odin_sprintf(buffer, " %s[%d]", hb_ports->name, i); |
| |
| if (count >= 78) |
| count = fprintf(out, " \\\n%s", buffer) - 3; |
| else |
| fprintf(out, "%s", buffer); |
| } |
| hb_ports = hb_ports->next; |
| } |
| |
| fprintf(out, "\n.blackbox\n.end\n\n"); |
| } |
| hard_blocks = hard_blocks->next; |
| } |
| |
| return; |
| } |
| |
| void |
| instantiate_hard_block(nnode_t *node, short mark, netlist_t * /*netlist*/) |
| { |
| int i, port, index; |
| |
| port = index = 0; |
| /* Give names to the output pins */ |
| for (i = 0; i < node->num_output_pins; i++) |
| { |
| if (node->output_pins[i]->name == NULL) |
| node->output_pins[i]->name = make_full_ref_name(node->name, NULL, NULL, node->output_pins[i]->mapping, -1); |
| |
| index++; |
| if (node->output_port_sizes[port] == index) |
| { |
| index = 0; |
| port++; |
| } |
| } |
| |
| node->traverse_visited = mark; |
| return; |
| } |
| |
| int |
| hard_block_port_size(t_model *hb, char *pname) |
| { |
| t_model_ports *tmp; |
| |
| if (hb == NULL) |
| return 0; |
| |
| /* Indicates that the port size is different for this hard block |
| * depending on the instance of the hard block. May want to extend |
| * this list of blocks in the future. |
| */ |
| if ((strcmp(hb->name, SINGLE_PORT_RAM_string) == 0) || |
| (strcmp(hb->name, DUAL_PORT_RAM_string) == 0)) |
| { |
| return -1; |
| } |
| |
| tmp = hb->inputs; |
| while (tmp != NULL) |
| if ((tmp->name != NULL) && (strcmp(tmp->name, pname) == 0)) |
| return tmp->size; |
| else |
| tmp = tmp->next; |
| |
| tmp = hb->outputs; |
| while (tmp != NULL) |
| if ((tmp->name != NULL) && (strcmp(tmp->name, pname) == 0)) |
| return tmp->size; |
| else |
| tmp = tmp->next; |
| |
| return 0; |
| } |
| |
| enum PORTS |
| hard_block_port_direction(t_model *hb, char *pname) |
| { |
| t_model_ports *tmp; |
| |
| if (hb == NULL) |
| return ERR_PORT; |
| |
| tmp = hb->inputs; |
| while (tmp != NULL) |
| if ((tmp->name != NULL) && (strcmp(tmp->name, pname) == 0)) |
| return tmp->dir; |
| else |
| tmp = tmp->next; |
| |
| tmp = hb->outputs; |
| while (tmp != NULL) |
| if ((tmp->name != NULL) && (strcmp(tmp->name, pname) == 0)) |
| return tmp->dir; |
| else |
| tmp = tmp->next; |
| |
| return ERR_PORT; |
| } |