mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-08-29 01:24:39 +02:00
Merge branch 'dev' into gridless_router
This commit is contained in:
@@ -16,6 +16,7 @@ from .lef import *
|
||||
from .logical_effort import *
|
||||
from .pin_layout import *
|
||||
from .power_data import *
|
||||
from .rom_verilog import *
|
||||
from .route import *
|
||||
from .timing_graph import *
|
||||
from .utils import *
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2023 Regents of the University of California and The Board
|
||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import math
|
||||
from openram.tech import spice
|
||||
|
||||
|
||||
class rom_verilog:
|
||||
"""
|
||||
Create a behavioral Verilog file for simulation.
|
||||
This is inherited by the rom_base class.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def verilog_write(self, verilog_name):
|
||||
""" Write a behavioral Verilog model. """
|
||||
self.vf = open(verilog_name, "w")
|
||||
|
||||
self.vf.write("// OpenROM ROM model\n")
|
||||
|
||||
#basic info
|
||||
self.vf.write("// Words: {0}\n".format(self.num_words))
|
||||
self.vf.write("// Word size: {0}\n".format(self.word_size))
|
||||
self.vf.write("// Word per Row: {0}\n".format(self.words_per_row))
|
||||
self.vf.write("// Data Type: {0}\n".format(self.data_type))
|
||||
self.vf.write("// Data File: {0}\n".format(self.rom_data))
|
||||
|
||||
self.vf.write("\n")
|
||||
|
||||
try:
|
||||
self.vdd_name = spice["power"]
|
||||
except KeyError:
|
||||
self.vdd_name = "vdd"
|
||||
try:
|
||||
self.gnd_name = spice["ground"]
|
||||
except KeyError:
|
||||
self.gnd_name = "gnd"
|
||||
|
||||
#add multiple banks later
|
||||
self.vf.write("module {0}(\n".format(self.name))
|
||||
self.vf.write("`ifdef USE_POWER_PINS\n")
|
||||
self.vf.write(" {},\n".format(self.vdd_name))
|
||||
self.vf.write(" {},\n".format(self.gnd_name))
|
||||
self.vf.write("`endif\n")
|
||||
|
||||
for port in self.all_ports:
|
||||
if port in self.read_ports:
|
||||
self.vf.write("// Port {0}: R\n".format(port))
|
||||
self.vf.write(" clk{0},csb{0},addr{0},dout{0}".format(port))
|
||||
# Continue for every port on a new line
|
||||
if port != self.all_ports[-1]:
|
||||
self.vf.write(",\n")
|
||||
self.vf.write("\n );\n\n")
|
||||
|
||||
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
|
||||
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(math.ceil(math.log(self.num_words,2))))
|
||||
self.vf.write(" parameter ROM_DEPTH = 1 << ADDR_WIDTH;\n")
|
||||
self.vf.write(" // FIXME: This delay is arbitrary.\n")
|
||||
self.vf.write(" parameter DELAY = 3 ;\n")
|
||||
self.vf.write(" parameter VERBOSE = 1 ; //Set to 0 to only display warnings\n")
|
||||
self.vf.write(" parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary\n")
|
||||
self.vf.write("\n")
|
||||
|
||||
self.vf.write("`ifdef USE_POWER_PINS\n")
|
||||
self.vf.write(" inout {};\n".format(self.vdd_name))
|
||||
self.vf.write(" inout {};\n".format(self.gnd_name))
|
||||
self.vf.write("`endif\n")
|
||||
|
||||
for port in self.all_ports:
|
||||
self.add_inputs_outputs(port)
|
||||
|
||||
self.vf.write("\n")
|
||||
|
||||
# This is the memory array itself
|
||||
self.vf.write(" reg [DATA_WIDTH-1:0] mem [0:ROM_DEPTH-1];\n\n")
|
||||
|
||||
#write memory init here
|
||||
self.vf.write(f" initial begin\n")
|
||||
if self.data_type == "bin":
|
||||
self.vf.write(f" $readmemb(\"{self.rom_data}\",mem,0,ROM_DEPTH-1);\n")
|
||||
elif self.data_type == "hex":
|
||||
self.vf.write(f" $readmemh(\"{self.rom_data}\",mem,0, ROM_DEPTH-1);\n")
|
||||
else:
|
||||
raise ValueError(f"Data type: {self.data_type} is not supported!")
|
||||
self.vf.write(f" end\n\n")
|
||||
|
||||
for port in self.all_ports:
|
||||
self.register_inputs(port)
|
||||
|
||||
for port in self.all_ports:
|
||||
if port in self.read_ports:
|
||||
self.add_read_block(port)
|
||||
|
||||
self.vf.write("\n")
|
||||
self.vf.write("endmodule\n")
|
||||
self.vf.close()
|
||||
|
||||
def register_inputs(self, port):
|
||||
"""
|
||||
Register the control signal, address and data inputs.
|
||||
"""
|
||||
self.add_regs(port)
|
||||
self.add_flops(port)
|
||||
|
||||
def add_regs(self, port):
|
||||
"""
|
||||
Create the input regs for the given port.
|
||||
"""
|
||||
self.vf.write(" reg csb{0}_reg;\n".format(port))
|
||||
self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port))
|
||||
if port in self.read_ports:
|
||||
self.vf.write(" reg [DATA_WIDTH-1:0] dout{0};\n".format(port))
|
||||
|
||||
|
||||
def add_flops(self, port):
|
||||
"""
|
||||
Add the flop behavior logic for a port.
|
||||
"""
|
||||
self.vf.write("\n")
|
||||
self.vf.write(" // All inputs are registers\n")
|
||||
self.vf.write(" always @(posedge clk{0})\n".format(port))
|
||||
self.vf.write(" begin\n")
|
||||
self.vf.write(" csb{0}_reg = csb{0};\n".format(port))
|
||||
self.vf.write(" addr{0}_reg = addr{0};\n".format(port))
|
||||
if port in self.read_ports:
|
||||
self.add_write_read_checks(port)
|
||||
|
||||
if port in self.read_ports:
|
||||
self.vf.write(" #(T_HOLD) dout{0} = {1}'bx;\n".format(port, self.word_size))
|
||||
self.vf.write(" if ( !csb{0}_reg && VERBOSE ) \n".format(port))
|
||||
self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port))
|
||||
|
||||
self.vf.write(" end\n\n")
|
||||
|
||||
def add_inputs_outputs(self, port):
|
||||
"""
|
||||
Add the module input and output declaration for a port.
|
||||
"""
|
||||
self.vf.write(" input clk{0}; // clock\n".format(port))
|
||||
self.vf.write(" input csb{0}; // active low chip select\n".format(port))
|
||||
|
||||
self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port))
|
||||
if port in self.read_ports:
|
||||
self.vf.write(" output [DATA_WIDTH-1:0] dout{0};\n".format(port))
|
||||
|
||||
def add_write_block(self, port):
|
||||
"""
|
||||
ROM does not take writes thus this function does nothing
|
||||
"""
|
||||
self.vf.write("\n")
|
||||
def add_read_block(self, port):
|
||||
"""
|
||||
Add a read port block.
|
||||
"""
|
||||
self.vf.write("\n")
|
||||
self.vf.write(" // Memory Read Block Port {0}\n".format(port))
|
||||
self.vf.write(" // Read Operation : When web{0} = 1, csb{0} = 0\n".format(port))
|
||||
self.vf.write(" always @ (negedge clk{0})\n".format(port))
|
||||
self.vf.write(" begin : MEM_READ{0}\n".format(port))
|
||||
self.vf.write(" if (!csb{0}_reg)\n".format(port))
|
||||
self.vf.write(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port))
|
||||
self.vf.write(" end\n")
|
||||
|
||||
def add_write_read_checks(self, rport):
|
||||
"""
|
||||
Since ROMs dont have write ports this does nothing
|
||||
"""
|
||||
pass
|
||||
@@ -363,7 +363,7 @@ class functional(simulation):
|
||||
def gen_addr(self):
|
||||
""" Generates a random address value to write to. """
|
||||
if self.valid_addresses:
|
||||
random_value = random.sample(self.valid_addresses, 1)[0]
|
||||
random_value = random.sample(list(self.valid_addresses), 1)[0]
|
||||
else:
|
||||
random_value = random.randint(0, self.max_address)
|
||||
addr_bits = binary_repr(random_value, self.bank_addr_size)
|
||||
|
||||
+39
-50
@@ -31,26 +31,23 @@ OPTS = options.options()
|
||||
|
||||
|
||||
def parse_args():
|
||||
""" Parse the optional arguments for OpenRAM """
|
||||
""" Parse the optional arguments for OpenRAM. """
|
||||
|
||||
global OPTS
|
||||
|
||||
option_list = {
|
||||
optparse.make_option("-b",
|
||||
"--backannotated",
|
||||
optparse.make_option("-b", "--backannotated",
|
||||
action="store_true",
|
||||
dest="use_pex",
|
||||
help="Back annotate simulation"),
|
||||
optparse.make_option("-o",
|
||||
"--output",
|
||||
optparse.make_option("-o", "--output",
|
||||
dest="output_name",
|
||||
help="Base output file name(s) prefix",
|
||||
metavar="FILE"),
|
||||
optparse.make_option("-p", "--outpath",
|
||||
dest="output_path",
|
||||
help="Output file(s) location"),
|
||||
optparse.make_option("-i",
|
||||
"--inlinecheck",
|
||||
optparse.make_option("-i", "--inlinecheck",
|
||||
action="store_true",
|
||||
help="Enable inline LVS/DRC checks",
|
||||
dest="inline_lvsdrc"),
|
||||
@@ -68,36 +65,29 @@ def parse_args():
|
||||
type="int",
|
||||
help="Specify the number of spice simulation threads (default: 3)",
|
||||
dest="num_sim_threads"),
|
||||
optparse.make_option("-v",
|
||||
"--verbose",
|
||||
optparse.make_option("-v", "--verbose",
|
||||
action="count",
|
||||
dest="verbose_level",
|
||||
help="Increase the verbosity level"),
|
||||
optparse.make_option("-t",
|
||||
"--tech",
|
||||
optparse.make_option("-t", "--tech",
|
||||
dest="tech_name",
|
||||
help="Technology name"),
|
||||
optparse.make_option("-s",
|
||||
"--spice",
|
||||
optparse.make_option("-s", "--spice",
|
||||
dest="spice_name",
|
||||
help="Spice simulator executable name"),
|
||||
optparse.make_option("-r",
|
||||
"--remove_netlist_trimming",
|
||||
optparse.make_option("-r", "--remove_netlist_trimming",
|
||||
action="store_false",
|
||||
dest="trim_netlist",
|
||||
help="Disable removal of noncritical memory cells during characterization"),
|
||||
optparse.make_option("-c",
|
||||
"--characterize",
|
||||
optparse.make_option("-c", "--characterize",
|
||||
action="store_false",
|
||||
dest="analytical_delay",
|
||||
help="Perform characterization to calculate delays (default is analytical models)"),
|
||||
optparse.make_option("-k",
|
||||
"--keeptemp",
|
||||
optparse.make_option("-k", "--keeptemp",
|
||||
action="store_true",
|
||||
dest="keep_temp",
|
||||
help="Keep the contents of the temp directory after a successful run"),
|
||||
optparse.make_option("-d",
|
||||
"--debug",
|
||||
optparse.make_option("-d", "--debug",
|
||||
action="store_true",
|
||||
dest="debug",
|
||||
help="Run in debug mode to drop to pdb on failure")
|
||||
@@ -125,7 +115,7 @@ def parse_args():
|
||||
|
||||
|
||||
def print_banner():
|
||||
""" Conditionally print the banner to stdout """
|
||||
""" Conditionally print the banner to stdout. """
|
||||
global OPTS
|
||||
if OPTS.is_unit_test:
|
||||
return
|
||||
@@ -160,8 +150,7 @@ def check_versions():
|
||||
try:
|
||||
subprocess.check_output(["git", "--version"])
|
||||
except:
|
||||
debug.error("Git is required. Please install git.")
|
||||
sys.exit(1)
|
||||
debug.error("Git is required. Please install git.", -1)
|
||||
|
||||
# FIXME: Check versions of other tools here??
|
||||
# or, this could be done in each module (e.g. verify, characterizer, etc.)
|
||||
@@ -226,8 +215,8 @@ def install_conda():
|
||||
|
||||
debug.info(1, "Creating conda setup...");
|
||||
|
||||
from openram import CONDA_HOME
|
||||
subprocess.call("./install_conda.sh", cwd=os.path.abspath(CONDA_HOME + "/.."))
|
||||
from openram import CONDA_INSTALLER
|
||||
subprocess.call(CONDA_INSTALLER)
|
||||
|
||||
|
||||
def setup_bitcell():
|
||||
@@ -280,18 +269,17 @@ def get_tool(tool_type, preferences, default_name=None):
|
||||
2)
|
||||
else:
|
||||
debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
|
||||
return(default_name, exe_name)
|
||||
return (default_name, exe_name)
|
||||
else:
|
||||
for name in preferences:
|
||||
exe_name = find_exe(name)
|
||||
if exe_name != None:
|
||||
debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
|
||||
return(name, exe_name)
|
||||
return (name, exe_name)
|
||||
else:
|
||||
debug.info(1,
|
||||
"Could not find {0}, trying next {1} tool.".format(name, tool_type))
|
||||
debug.info(1, "Could not find {0}, trying next {1} tool.".format(name, tool_type))
|
||||
else:
|
||||
return(None, "")
|
||||
return (None, "")
|
||||
|
||||
|
||||
def read_config(config_file, is_unit_test=False):
|
||||
@@ -381,7 +369,7 @@ def read_config(config_file, is_unit_test=False):
|
||||
|
||||
|
||||
def end_openram():
|
||||
""" Clean up openram for a proper exit """
|
||||
""" Clean up openram for a proper exit. """
|
||||
cleanup_paths()
|
||||
|
||||
if OPTS.check_lvsdrc:
|
||||
@@ -393,8 +381,7 @@ def end_openram():
|
||||
|
||||
def purge_temp():
|
||||
""" Remove the temp directory. """
|
||||
debug.info(1,
|
||||
"Purging temp directory: {}".format(OPTS.openram_temp))
|
||||
debug.info(1, "Purging temp directory: {}".format(OPTS.openram_temp))
|
||||
#import inspect
|
||||
#s = inspect.stack()
|
||||
#print("Purge {0} in dir {1}".format(s[3].filename, OPTS.openram_temp))
|
||||
@@ -416,8 +403,7 @@ def cleanup_paths():
|
||||
"""
|
||||
global OPTS
|
||||
if OPTS.keep_temp:
|
||||
debug.info(0,
|
||||
"Preserving temp directory: {}".format(OPTS.openram_temp))
|
||||
debug.info(0, "Preserving temp directory: {}".format(OPTS.openram_temp))
|
||||
return
|
||||
elif os.path.exists(OPTS.openram_temp):
|
||||
purge_temp()
|
||||
@@ -434,7 +420,6 @@ def setup_paths():
|
||||
|
||||
# Use a unique temp subdirectory if multithreaded
|
||||
if OPTS.num_threads > 1 or OPTS.openram_temp == "/tmp":
|
||||
|
||||
# Make a unique subdir
|
||||
tempdir = "/openram_{0}_{1}_temp".format(getpass.getuser(),
|
||||
os.getpid())
|
||||
@@ -449,14 +434,15 @@ def setup_paths():
|
||||
|
||||
def is_exe(fpath):
|
||||
""" Return true if the given is an executable file that exists. """
|
||||
|
||||
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
|
||||
|
||||
|
||||
def find_exe(check_exe):
|
||||
"""
|
||||
Check if the binary exists in any path dir
|
||||
and return the full path.
|
||||
Check if the binary exists in any path dir and return the full path.
|
||||
"""
|
||||
|
||||
# Search for conda setup if used
|
||||
if OPTS.use_conda:
|
||||
from openram import CONDA_HOME
|
||||
@@ -465,6 +451,7 @@ def find_exe(check_exe):
|
||||
os.environ["PATH"])
|
||||
else:
|
||||
search_path = os.environ["PATH"]
|
||||
|
||||
# Check if the preferred spice option exists in the path
|
||||
for path in search_path.split(os.pathsep):
|
||||
exe = os.path.join(path, check_exe)
|
||||
@@ -475,18 +462,20 @@ def find_exe(check_exe):
|
||||
|
||||
|
||||
def init_paths():
|
||||
""" Create the temp and output directory if it doesn't exist """
|
||||
""" Create the temp and output directory if it doesn't exist. """
|
||||
|
||||
if os.path.exists(OPTS.openram_temp):
|
||||
purge_temp()
|
||||
else:
|
||||
# make the directory if it doesn't exist
|
||||
# Make the directory if it doesn't exist
|
||||
try:
|
||||
debug.info(1,
|
||||
"Creating temp directory: {}".format(OPTS.openram_temp))
|
||||
debug.info(1, "Creating temp directory: {}".format(OPTS.openram_temp))
|
||||
os.makedirs(OPTS.openram_temp, 0o750)
|
||||
except OSError as e:
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
os.chmod(OPTS.openram_temp, 0o750)
|
||||
else:
|
||||
debug.error("Unable to make temp directory: {}".format(OPTS.openram_temp), -1)
|
||||
#import inspect
|
||||
#s = inspect.stack()
|
||||
#from pprint import pprint
|
||||
@@ -499,10 +488,10 @@ def init_paths():
|
||||
try:
|
||||
os.makedirs(OPTS.output_path, 0o750)
|
||||
except OSError as e:
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
os.chmod(OPTS.output_path, 0o750)
|
||||
except:
|
||||
debug.error("Unable to make output directory.", -1)
|
||||
else:
|
||||
debug.error("Unable to make output directory: {}".format(OPTS.output_path), -1)
|
||||
|
||||
|
||||
def set_default_corner():
|
||||
@@ -572,7 +561,7 @@ def import_tech():
|
||||
# Add all of the paths
|
||||
for tech_path in OPENRAM_TECH.split(":"):
|
||||
debug.check(os.path.isdir(tech_path),
|
||||
"$OPENRAM_TECH does not exist: {0}".format(tech_path))
|
||||
"$OPENRAM_TECH does not exist: {}".format(tech_path))
|
||||
sys.path.append(tech_path)
|
||||
debug.info(1, "Adding technology path: {}".format(tech_path))
|
||||
|
||||
@@ -580,7 +569,7 @@ def import_tech():
|
||||
try:
|
||||
tech_mod = __import__(OPTS.tech_name)
|
||||
except ImportError:
|
||||
debug.error("Nonexistent technology module: {0}".format(OPTS.tech_name), -1)
|
||||
debug.error("Nonexistent technology module: {}".format(OPTS.tech_name), -1)
|
||||
|
||||
OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/"
|
||||
|
||||
@@ -649,7 +638,7 @@ def report_status():
|
||||
total_size = OPTS.word_size*OPTS.num_words*OPTS.num_banks
|
||||
debug.print_raw("Total size: {} bits".format(total_size))
|
||||
if total_size >= 2**14 and not OPTS.analytical_delay:
|
||||
debug.warning("Characterizing large memories ({0}) will have a large run-time. ".format(total_size))
|
||||
debug.warning("Characterizing large memories ({0}) will have a large run-time.".format(total_size))
|
||||
debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
|
||||
OPTS.num_words,
|
||||
OPTS.num_banks))
|
||||
|
||||
@@ -10,13 +10,14 @@ import datetime
|
||||
from math import ceil, log
|
||||
from openram.base import vector
|
||||
from openram.base import design
|
||||
from openram.base import rom_verilog
|
||||
from openram import OPTS, print_time
|
||||
from openram.sram_factory import factory
|
||||
from openram.tech import drc, layer, parameter
|
||||
from openram.router import router_tech
|
||||
|
||||
|
||||
class rom_bank(design):
|
||||
class rom_bank(design,rom_verilog):
|
||||
|
||||
"""
|
||||
Rom data bank with row and column decoder + control logic
|
||||
@@ -509,4 +510,4 @@ class rom_bank(design):
|
||||
rtr=router(layers=self.m3_stack,
|
||||
design=self,
|
||||
bbox=bbox)
|
||||
rtr.escape_route(pins_to_route)
|
||||
rtr.escape_route(pins_to_route)
|
||||
|
||||
@@ -28,7 +28,6 @@ class sram_1bank(design, verilog, lef):
|
||||
design.__init__(self, name)
|
||||
lef.__init__(self, ["m1", "m2", "m3", "m4"])
|
||||
verilog.__init__(self)
|
||||
|
||||
self.sram_config = sram_config
|
||||
sram_config.set_local_config(self)
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ class options(optparse.Values):
|
||||
###################
|
||||
rom_endian = "little"
|
||||
rom_data = None
|
||||
data_type = "bin"
|
||||
strap_spacing = 8
|
||||
scramble_bits = True
|
||||
|
||||
|
||||
+11
-8
@@ -26,7 +26,8 @@ class rom():
|
||||
words_per_row=OPTS.words_per_row,
|
||||
rom_endian=OPTS.rom_endian,
|
||||
scramble_bits=OPTS.scramble_bits,
|
||||
strap_spacing=OPTS.strap_spacing)
|
||||
strap_spacing=OPTS.strap_spacing,
|
||||
data_type=OPTS.data_type)
|
||||
|
||||
if name is None:
|
||||
name = OPTS.output_name
|
||||
@@ -38,7 +39,7 @@ class rom():
|
||||
from openram.base import design
|
||||
design.name_map=[]
|
||||
|
||||
debug.info(2, "create rom of size {0} with {1} num of words".format(self.word_size,
|
||||
debug.print_raw("create rom of word size {0} with {1} num of words".format(self.word_size,
|
||||
self.num_words))
|
||||
start_time = datetime.datetime.now()
|
||||
|
||||
@@ -137,20 +138,22 @@ class rom():
|
||||
|
||||
|
||||
# Write the config file
|
||||
# Should also save the provided data file
|
||||
start_time = datetime.datetime.now()
|
||||
from shutil import copyfile
|
||||
copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py')
|
||||
copyfile(self.rom_data, OPTS.output_path + self.rom_data)
|
||||
debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py'))
|
||||
print_time("Config", datetime.datetime.now(), start_time)
|
||||
|
||||
# TODO: Write the datasheet
|
||||
|
||||
# TODO: Write a verilog model
|
||||
# start_time = datetime.datetime.now()
|
||||
# vname = OPTS.output_path + self.r.name + '.v'
|
||||
# debug.print_raw("Verilog: Writing to {0}".format(vname))
|
||||
# self.verilog_write(vname)
|
||||
# print_time("Verilog", datetime.datetime.now(), start_time)
|
||||
#Write a verilog model
|
||||
start_time = datetime.datetime.now()
|
||||
vname = OPTS.output_path + self.r.name + '.v'
|
||||
debug.print_raw("Verilog: Writing to {0}".format(vname))
|
||||
self.verilog_write(vname)
|
||||
print_time("Verilog", datetime.datetime.now(), start_time)
|
||||
|
||||
# Write out options if specified
|
||||
if OPTS.output_extended_config:
|
||||
|
||||
+37
-14
@@ -16,14 +16,14 @@ from openram import OPTS
|
||||
class rom_config:
|
||||
""" This is a structure that is used to hold the ROM configuration options. """
|
||||
|
||||
def __init__(self, word_size, rom_data, words_per_row=None, rom_endian="little", scramble_bits=True, strap_spacing=8):
|
||||
def __init__(self, word_size, rom_data, words_per_row=None, rom_endian="little", scramble_bits=True, strap_spacing=8, data_type="hex"):
|
||||
self.word_size = word_size
|
||||
self.word_bits = self.word_size * 8
|
||||
self.rom_data = rom_data
|
||||
self.strap_spacing = strap_spacing
|
||||
# TODO: This currently does nothing. It should change the behavior of the chunk funciton.
|
||||
self.endian = rom_endian
|
||||
|
||||
self.data_type = data_type
|
||||
# This should pretty much always be true. If you want to make silicon art you might set to false
|
||||
self.scramble_bits = scramble_bits
|
||||
# This will get over-written when we determine the organization
|
||||
@@ -57,18 +57,12 @@ class rom_config:
|
||||
def compute_sizes(self):
|
||||
""" Computes the organization of the memory using data size by trying to make it a rectangle."""
|
||||
|
||||
# Read data as hexidecimal text file
|
||||
hex_file = open(self.rom_data, 'r')
|
||||
hex_data = hex_file.read()
|
||||
|
||||
# Convert from hex into an int
|
||||
data_int = int(hex_data, 16)
|
||||
# Then from int into a right aligned, zero padded string
|
||||
bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4)
|
||||
|
||||
# Then turn the string into a list of ints
|
||||
bin_data = list(bin_string)
|
||||
raw_data = [int(x) for x in bin_data]
|
||||
if self.data_type == "hex":
|
||||
raw_data = self.read_data_hex()
|
||||
elif self.data_type == "bin":
|
||||
raw_data = self.read_data_bin()
|
||||
else:
|
||||
debug.error(f"Invalid input data type: {self.data_type}", -1)
|
||||
|
||||
# data size in bytes
|
||||
data_size = len(raw_data) / 8
|
||||
@@ -93,6 +87,35 @@ class rom_config:
|
||||
OPTS.words_per_row = self.words_per_row
|
||||
debug.info(1, "Read rom data file: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, self.num_words, self.cols, self.rows, self.words_per_row))
|
||||
|
||||
def read_data_hex(self) -> List[int]:
|
||||
# Read data as hexidecimal text file
|
||||
with open(self.rom_data, 'r') as hex_file:
|
||||
hex_data = hex_file.read()
|
||||
|
||||
# Convert from hex into an int
|
||||
data_int = int(hex_data, 16)
|
||||
# Then from int into a right aligned, zero padded string
|
||||
bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4)
|
||||
|
||||
# Then turn the string into a list of ints
|
||||
bin_data = list(bin_string)
|
||||
raw_data = [int(x) for x in bin_data]
|
||||
return raw_data
|
||||
|
||||
def read_data_bin(self) -> List[int]:
|
||||
|
||||
# Read data as a binary file
|
||||
with open(self.rom_data, 'rb') as bin_file:
|
||||
bin_data = bin_file.read()
|
||||
|
||||
# Convert from a list of bytes to a single string of bits
|
||||
bin_string = "".join(f"{n:08b}" for n in bin_data)
|
||||
|
||||
# Then turn the string into a list of ints
|
||||
bin_data = list(bin_string)
|
||||
raw_data = [int(x) for x in bin_data]
|
||||
return raw_data
|
||||
|
||||
|
||||
def chunk_data(self, raw_data: List[int]):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user