diff --git a/HDL/common/caravel_wrapper_pin_assignment_v1.0.json b/HDL/common/caravel_wrapper_pin_assignment_v1.0.json index e32b858..db4c5d1 100644 --- a/HDL/common/caravel_wrapper_pin_assignment_v1.0.json +++ b/HDL/common/caravel_wrapper_pin_assignment_v1.0.json @@ -18,7 +18,8 @@ "fpga_gpio_input_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_IN", "fpga_gpio_output_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_OUT", "fpga_gpio_direction_name": "gfpga_pad_EMBEDDED_IO_HD_SOC_DIR", - "mode_switch_pin_name": "wb_la_switch" + "mode_switch_pin_name": "wb_la_switch", + "inverted_mode_switch_pin_name": "wb_la_switch_b", "pins": [ { "fpga_pin_type": "io" diff --git a/HDL/common/wrapper_lines_generator.py b/HDL/common/wrapper_lines_generator.py index 398469d..dc2c669 100644 --- a/HDL/common/wrapper_lines_generator.py +++ b/HDL/common/wrapper_lines_generator.py @@ -54,9 +54,9 @@ pin_data = json.load(json_file) # Return pin range format is [LSB, MSB] as a list ##################################################################### def parse_json_pin_range(json_range) : - pin_range = json_range.split(':') - assert(2 == len(pin_range)) - return pin_range + pin_range_str = json_range.split(':') + assert(2 == len(pin_range_str)) + return range(pin_range_str[0], pin_range_str[1] + 1) ##################################################################### # Generate wrapper lines @@ -66,82 +66,170 @@ netlist_lines = [] # Walk through the array containing the pin information for pin_info in pin_data['pins']: # Deposit a tab to respect the HDL coding indent - curr_line = " " + curr_line = "" # TODO: Check codes that ensure the pin index should match + assert(0 < len(pin_info['caravel_pin_type'])) + assert(0 < len(pin_info['caravel_pin_index'])) # # Branch on the types of connnections: # - FPGA I/O to Caravel GPIO - if (("io" == pin_info['fpga_pin_type']) and ("gpio" == pin_info['caravel_pin_type'][0])): + if (("io" == pin_info['fpga_pin_type']) \ + and (1 == len(pin_info['caravel_pin_type'])) \ + and ("gpio" == pin_info['caravel_pin_type'][0])): # Should have only 1 port in caravel assert(1 == len(pin_info['caravel_pin_type'])) + assert(1 == len(pin_info['caravel_pin_index'])) # Get pin range fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index']) - # Connect all the input, output and direction port - # FPGA input <- Caravel input - # FPGA output -> Caravel output - # FPGA direction -> Caravel direction - curr_line += "assign " + pin_data['fpga_gpio_input_name'] - netlist_lines.append(curr_line + "\n") - - if ((ipin < num_wishbone_pins) and (ipin < num_logic_analyzer_pins)): - # If this is an input pin of wishbone interface, whose postfix is '_i', we use MUX - # otherwise, this is an output pin, we just wire the input to logic analyzer - if ((wishbone_pins[ipin].endswith("_i")) or (re.search(r'_i\[\d+\]$', wishbone_pins[ipin], re.M | re.I))): - ############################################################## - # SOC INPUT will be directly driven by either - # - the Wishbone input - # or - # - the logic analyzer input - # through a multiplexer controlled by the signal 'wb_la_switch - curr_line = " " + "sky130_fd_sc_hd__mux2_1 FPGA2SOC_IN_" + str(135 - ipin) + "_MUX (.S(wb_la_switch), .A1(" + str( - wishbone_pins[ipin]) + "), .A0(" + str(logic_analyzer_pins[ipin][0]) + "), .X(gfpga_pad_EMBEDDED_IO_HD_SOC_IN[" + str(135 - ipin) + "]));" - netlist_lines.append(curr_line + "\n") - ############################################################## - # SOC OUTPUT will drive an output of logic analyzer - # since this I/O is going to interface a Wishbone input only - curr_line = " " + "assign " + \ - str(logic_analyzer_pins[ipin][1]) + \ - " = gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[" + str(135 - ipin) + "];" - netlist_lines.append(curr_line + "\n") - elif ((wishbone_pins[ipin].endswith("_o")) or (re.search(r'_o\[\d+\]$', wishbone_pins[ipin], re.M | re.I))): - ############################################################## - # SOC INPUT will be directly driven by logic analyzer - # since this I/O is going to interface a Wishbone output only - curr_line = " " + "assign gfpga_pad_EMBEDDED_IO_HD_SOC_IN[" + str( - 135 - ipin) + "] = " + str(logic_analyzer_pins[ipin][0]) + ";" - netlist_lines.append(curr_line + "\n") - ############################################################## - # SOC OUTPUT will drive the Wishbone output through a tri-state buffer - # As the buffer is enabled by logic '0', we use the inverted 'wb_la_switch' - curr_line = " " + "sky130_fd_sc_hd__ebufn_4 FPGA2SOC_OUT_" + str(135 - ipin) + "_DEMUX_WB (" + \ - ".TE_B(wb_la_switch_b), " + \ - ".A(" + "gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[" + str(135 - ipin) + "]), " + \ - ".Z(" + str(wishbone_pins[ipin]) + ")" + \ - ");" - netlist_lines.append(curr_line + "\n") - ############################################################## - # SOC OUTPUT will also drive the Logic Analyzer output through a tri-state buffer - # As the buffer is enabled by logic '0', we use the 'wb_la_switch' - curr_line = " " + "sky130_fd_sc_hd__ebufn_4 FPGA2SOC_OUT_" + str(135 - ipin) + "_DEMUX_LA (" + \ - ".TE_B(wb_la_switch), " + \ - ".A(" + "gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[" + str(135 - ipin) + "]), " + \ - ".Z(" + str(logic_analyzer_pins[ipin][1]) + ")" + \ - ");" - netlist_lines.append(curr_line + "\n") + caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0]) + assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range))) + for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) : + # Connect all the input, output and direction port + # FPGA input <- Caravel input + curr_line = "assign " + pin_data['fpga_gpio_input_name'] + "[" + indices[0] + "] = " \ + + pin_data['caravel_gpio_input_name'] + "[" + indices[1] + "];"; + netlist_lines.append(curr_line + "\n") + # FPGA output -> Caravel output + curr_line = "assign " + pin_data['caravel_gpio_output_name'] + "[" + indices[1] + "] = " \ + + pin_data['fpga_gpio_output_name'] + "[" + indices[0] + "];"; + netlist_lines.append(curr_line + "\n") + # FPGA direction -> Caravel direction + curr_line = "assign " + pin_data['caravel_gpio_direction_name'] + "[" + indices[1] + "] = " \ + + pin_data['fpga_gpio_direction_name'] + "[" + indices[0] + "];"; + netlist_lines.append(curr_line + "\n") - elif ((ipin >= num_wishbone_pins) and (ipin < num_logic_analyzer_pins)): + # - FPGA control input ports to Caravel GPIO + if (("io" != pin_info['fpga_pin_type']) \ + and (1 == len(pin_info['caravel_pin_type'])) \ + and ("input" == pin_info['caravel_pin_type'][0])): + # Should have only 1 port in caravel + assert(1 == len(pin_info['caravel_pin_type'])) + assert(1 == len(pin_info['caravel_pin_index'])) + # Get pin range + fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index']) + caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0]) + assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range))) + for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) : + # Connect the FPGA input port to the Caravel input + curr_line = "assign " + pin_data['fpga_pin_type'] + "[" + indices[0] + "] = " \ + + pin_data['caravel_gpio_input_name'] + "[" + indices[1] + "];"; + netlist_lines.append(curr_line + "\n") + # Tie Caravel output port to logic '0' + curr_line = "assign " + pin_data['caravel_gpio_output_name'] + "[" + indices[1] + "] = 1'b0;" + netlist_lines.append(curr_line + "\n") + # Tie Caravel direction port to logic '1' + curr_line = "assign " + pin_data['caravel_gpio_direction_name'] + "[" + indices[1] + "] = 1'b1" + netlist_lines.append(curr_line + "\n") + + # - FPGA control output ports to Caravel GPIO + if (("io" != pin_info['fpga_pin_type']) \ + and (1 == len(pin_info['caravel_pin_type'])) \ + and ("output" == pin_info['caravel_pin_type'][0])): + # Should have only 1 port in caravel + assert(1 == len(pin_info['caravel_pin_type'])) + assert(1 == len(pin_info['caravel_pin_index'])) + # Get pin range + fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index']) + caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0]) + assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range))) + for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) : + # Bypass the Caravel input + # Connect Caravel output port to FPGA control output + curr_line = "assign " + pin_data['caravel_gpio_output_name'] + "[" + indices[1] + "] = " \ + + pin_data['fpga_pin_type'] + "[" + indices[0] + "];"; + netlist_lines.append(curr_line + "\n") + # Tie Caravel direction port to logic '0' + curr_line = "assign " + pin_data['caravel_gpio_direction_name'] + "[" + indices[1] + "] = 1'b0" + netlist_lines.append(curr_line + "\n") + + # - FPGA I/O ports to Caravel logic analyzer I/O only + if (("io" == pin_info['fpga_pin_type']) \ + and (1 == len(pin_info['caravel_pin_type'])) \ + and ("logic_analyzer_io" == pin_info['caravel_pin_type'][0])): + # Should have only 1 port in caravel + assert(1 == len(pin_info['caravel_pin_type'])) + assert(1 == len(pin_info['caravel_pin_index'])) + # Get pin range + fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index']) + caravel_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0]) + assert(len(list(fpga_io_pin_range)) == len(list(caravel_io_pin_range))) + for indices in zip(list(fpga_io_pin_range), list(caravel_io_pin_range)) : + ############################################################## + # SOC INPUT will be directly driven by logic analyzer + # since this I/O is going to interface logic analyzer input only + curr_line = "assign " + pin_data['fpga_gpio_input_name'] + "[" + indices[0] + "] = " \ + + pin_data['caravel_logic_analyzer_input_name'] + "[" + indices[1] + "]" + ";" + netlist_lines.append(curr_line + "\n") + ############################################################## + # SOC OUTPUT will directly drive logic analyzer + # since this I/O is going to interface logic analyzer output only + curr_line = "assign " + pin_data['caravel_logic_analyzer_output_name'] + "[" + indices[1] + "]" \ + + " = " + pin_data['fpga_gpio_output_name'] + "[" + indices[0] + "];" + netlist_lines.append(curr_line + "\n") + + # - FPGA I/O ports to Caravel logic analyzer I/O and Wishbone interface + if (("io" == pin_info['fpga_pin_type']) \ + and (2 == len(pin_info['caravel_pin_type'])) \ + and ("logic_analyzer_io" == pin_info['caravel_pin_type'][0]) \ + and (pin_info['caravel_pin_type'][1].startswith("wishbone"))): + # Should have only 2 port in caravel + assert(2 == len(pin_info['caravel_pin_type'])) + assert(2 == len(pin_info['caravel_pin_index'])) + # Get pin range + fpga_io_pin_range = parse_json_pin_range(pin_info['fpga_pin_index']) + la_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][0]) + wb_io_pin_range = parse_json_pin_range(pin_info['caravel_pin_index'][1]) + assert(len(list(fpga_io_pin_range)) == len(list(la_io_pin_range))) + assert(len(list(fpga_io_pin_range)) == len(list(wb_io_pin_range))) + + # If this is an input pin of wishbone interface, whose postfix is '_i', we use MUX + # otherwise, this is an output pin, we just wire the input to logic analyzer + if (pin_info['caravel_pin_type'][1].endswith("_input")): + for indices in zip(list(fpga_io_pin_range), list(la_io_pin_range), list(wb_la_pin_range)) : ############################################################## - # SOC INPUT will be directly driven by logic analyzer - # since this I/O is going to interface logic analyzer input only - curr_line = " " + "assign gfpga_pad_EMBEDDED_IO_HD_SOC_IN[" + str( - 135 - ipin) + "] = " + str(logic_analyzer_pins[ipin][0]) + ";" + # SOC INPUT will be directly driven by either + # - the Wishbone input + # or + # - the logic analyzer input + # through a multiplexer controlled by the signal 'wb_la_switch + curr_line = "sky130_fd_sc_hd__mux2_1 FPGA2SOC_IN_" + indices[0] + "_MUX (" \ + + ".S(" + pin_data['mode_switch_pin_name'] + "), " \ + + ".A1(" + pin_data[pin_info['caravel_pin_type'][1] + '_name'] + "[" + indices[2] + "]), " \ + + ".A0(" + pin_data['caravel_logic_analyzer_input_name'] + indices[1] + "), " \ + + ".X(" + pin_data['fpga_gpio_input_name'] + "[" + indices[0] + "])" \ + + ");" netlist_lines.append(curr_line + "\n") ############################################################## - # SOC OUTPUT will directly drive logic analyzer - # since this I/O is going to interface logic analyzer output only - curr_line = " " + "assign " + \ - str(logic_analyzer_pins[ipin][1]) + \ - " = gfpga_pad_EMBEDDED_IO_HD_SOC_OUT[" + str(135 - ipin) + "];" + # SOC OUTPUT will drive an output of logic analyzer + # since this I/O is going to interface a Wishbone input only + curr_line = "assign " + pin_data['caravel_logic_analyzer_output_name'] + "[" + indices[1] + "]" \ + + " = " + pin_data['fpga_gpio_output_name'] + "[" + indices[0] + "];" + netlist_lines.append(curr_line + "\n") + elif (pin_info['caravel_pin_type'][1].endswith("_output")): + for indices in zip(list(fpga_io_pin_range), list(la_io_pin_range), list(wb_la_pin_range)) : + ############################################################## + # SOC INPUT will be directly driven by logic analyzer + # since this I/O is going to interface a Wishbone output only + curr_line = "assign " + pin_data['fpga_gpio_input_name'] + "[" + indices[0] + "] = " \ + + pin_data['caravel_logic_analyzer_input_name'] + "[" + indices[1] + "];" + netlist_lines.append(curr_line + "\n") + ############################################################## + # SOC OUTPUT will drive the Wishbone output through a tri-state buffer + # As the buffer is enabled by logic '0', we use the inverted 'wb_la_switch' + curr_line = "sky130_fd_sc_hd__ebufn_4 FPGA2SOC_OUT_" + indices[0] + "_DEMUX_WB (" \ + + ".TE_B(" + pin_data['inverted_mode_switch_pin_name'] + "), " \ + + ".A(" + pin_data['fpga_gpio_output_name'] + "[" + indices[0] + "]), " \ + + ".Z(" + pin_data[pin_info['caravel_pin_type'][1] + '_name'] + "[" + indices[2] + "])" \ + + ");" + netlist_lines.append(curr_line + "\n") + ############################################################## + # SOC OUTPUT will also drive the Logic Analyzer output through a tri-state buffer + # As the buffer is enabled by logic '0', we use the 'wb_la_switch' + curr_line = "sky130_fd_sc_hd__ebufn_4 FPGA2SOC_OUT_" + indices[0] + "_DEMUX_LA (" \ + + ".TE_B(" + pin_data['mode_switch_pin_name'] + "), " \ + + ".A(" + pin_data['fpga_gpio_output_name'] + "[" + indices[0] + "]), " \ + + ".Z(" + pin_data['caravel_logic_analyzer_output_name'] + "[" + indices[1] + "])" \ + + ");" netlist_lines.append(curr_line + "\n") if isfile(args.output_verilog):