2018-10-12 01:03:05 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""
|
2019-01-16 04:47:48 +01:00
|
|
|
This is a script to load data from the characterization and layout processes into
|
2019-01-09 04:50:47 +01:00
|
|
|
a web friendly html datasheet.
|
2018-10-12 01:03:05 +02:00
|
|
|
"""
|
2019-01-16 04:47:48 +01:00
|
|
|
# TODO:
|
|
|
|
|
# Diagram generation
|
|
|
|
|
# Improve css
|
2018-10-31 05:37:30 +01:00
|
|
|
|
2018-12-06 19:13:28 +01:00
|
|
|
|
2018-10-12 01:03:05 +02:00
|
|
|
from globals import OPTS
|
2019-01-16 04:47:48 +01:00
|
|
|
import os
|
|
|
|
|
import math
|
2019-01-09 04:50:47 +01:00
|
|
|
import csv
|
2019-01-16 04:47:48 +01:00
|
|
|
import datasheet
|
|
|
|
|
import table_gen
|
|
|
|
|
|
2019-01-31 17:09:00 +01:00
|
|
|
# def process_name(corner):
|
|
|
|
|
# """
|
|
|
|
|
# Expands the names of the characterization corner types into something human friendly
|
|
|
|
|
# """
|
|
|
|
|
# if corner == "TS":
|
|
|
|
|
# return "Typical - Slow"
|
|
|
|
|
# if corner == "TT":
|
|
|
|
|
# return "Typical - Typical"
|
|
|
|
|
# if corner == "TF":
|
|
|
|
|
# return "Typical - Fast"
|
|
|
|
|
#
|
|
|
|
|
# if corner == "SS":
|
|
|
|
|
# return "Slow - Slow"
|
|
|
|
|
# if corner == "ST":
|
|
|
|
|
# return "Slow - Typical"
|
|
|
|
|
# if corner == "SF":
|
|
|
|
|
# return "Slow - Fast"
|
|
|
|
|
#
|
|
|
|
|
# if corner == "FS":
|
|
|
|
|
# return "Fast - Slow"
|
|
|
|
|
# if corner == "FT":
|
|
|
|
|
# return "Fast - Typical"
|
|
|
|
|
# if corner == "FF":
|
|
|
|
|
# return "Fast - Fast"
|
|
|
|
|
#
|
|
|
|
|
# else:
|
|
|
|
|
# return "custom"
|
|
|
|
|
#
|
2018-10-12 01:03:05 +02:00
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
|
2019-01-16 23:52:01 +01:00
|
|
|
def parse_characterizer_csv(f, pages):
|
2018-10-31 05:37:30 +01:00
|
|
|
"""
|
|
|
|
|
Parses output data of the Liberty file generator in order to construct the timing and
|
|
|
|
|
current table
|
|
|
|
|
"""
|
2018-10-12 01:03:05 +02:00
|
|
|
with open(f) as csv_file:
|
|
|
|
|
csv_reader = csv.reader(csv_file, delimiter=',')
|
|
|
|
|
for row in csv_reader:
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2018-10-12 01:03:05 +02:00
|
|
|
found = 0
|
2018-11-11 05:23:26 +01:00
|
|
|
col = 0
|
2018-10-31 05:37:30 +01:00
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
# defines layout of csv file
|
2018-11-11 05:23:26 +01:00
|
|
|
NAME = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
NUM_WORDS = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
NUM_BANKS = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
NUM_RW_PORTS = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
NUM_W_PORTS = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
NUM_R_PORTS = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
TECH_NAME = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
TEMP = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
VOLT = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
PROC = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
MIN_PERIOD = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
OUT_DIR = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
LIB_NAME = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
WORD_SIZE = row[col]
|
|
|
|
|
col += 1
|
2019-01-16 04:47:48 +01:00
|
|
|
|
2018-12-03 19:53:50 +01:00
|
|
|
ORIGIN_ID = row[col]
|
|
|
|
|
col += 1
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-02 19:30:03 +01:00
|
|
|
DATETIME = row[col]
|
2019-01-16 04:47:48 +01:00
|
|
|
col += 1
|
2019-02-22 15:46:28 +01:00
|
|
|
|
|
|
|
|
ANALYTICAL_MODEL = row[col]
|
|
|
|
|
col += 1
|
2019-01-02 19:30:03 +01:00
|
|
|
|
2019-01-02 19:14:45 +01:00
|
|
|
DRC = row[col]
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
LVS = row[col]
|
|
|
|
|
col += 1
|
2019-02-22 15:46:28 +01:00
|
|
|
|
2019-02-14 16:01:35 +01:00
|
|
|
AREA = row[col]
|
2019-01-31 17:28:51 +01:00
|
|
|
col += 1
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
for sheet in pages:
|
2018-10-12 01:03:05 +02:00
|
|
|
|
2018-11-11 05:23:26 +01:00
|
|
|
if sheet.name == NAME:
|
2018-10-31 06:32:19 +01:00
|
|
|
|
2018-10-12 01:03:05 +02:00
|
|
|
found = 1
|
2019-01-16 04:47:48 +01:00
|
|
|
# if the .lib information is for an existing datasheet compare timing data
|
2018-10-12 01:03:05 +02:00
|
|
|
|
2019-01-09 03:54:20 +01:00
|
|
|
for item in sheet.operating_table.rows:
|
2019-01-16 04:47:48 +01:00
|
|
|
# check if the new corner data is worse than the previous worse corner data
|
2018-10-12 01:03:05 +02:00
|
|
|
|
2019-01-09 03:54:20 +01:00
|
|
|
if item[0] == 'Operating Temperature':
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(TEMP) > float(item[3]):
|
2019-01-09 03:54:20 +01:00
|
|
|
item[2] = item[3]
|
|
|
|
|
item[3] = TEMP
|
|
|
|
|
if float(TEMP) < float(item[1]):
|
|
|
|
|
item[2] = item[1]
|
|
|
|
|
item[1] = TEMP
|
|
|
|
|
|
|
|
|
|
if item[0] == 'Power supply (VDD) range':
|
|
|
|
|
if float(VOLT) > float(item[3]):
|
|
|
|
|
item[2] = item[3]
|
|
|
|
|
item[3] = VOLT
|
|
|
|
|
if float(VOLT) < float(item[1]):
|
|
|
|
|
item[2] = item[1]
|
|
|
|
|
item[1] = VOLT
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-09 04:50:47 +01:00
|
|
|
if item[0] == 'Operating Frequncy (F)':
|
2019-01-09 03:54:20 +01:00
|
|
|
try:
|
|
|
|
|
if float(math.floor(1000/float(MIN_PERIOD)) < float(item[3])):
|
2019-01-16 04:47:48 +01:00
|
|
|
item[3] = str(math.floor(
|
|
|
|
|
1000/float(MIN_PERIOD)))
|
2019-01-09 03:54:20 +01:00
|
|
|
except Exception:
|
|
|
|
|
pass
|
2019-02-07 15:33:39 +01:00
|
|
|
# check current .lib file produces the slowest timing results
|
2018-11-11 05:23:26 +01:00
|
|
|
while(True):
|
2019-01-17 00:43:08 +01:00
|
|
|
col_start = col
|
2018-11-11 05:23:26 +01:00
|
|
|
if(row[col].startswith('DIN')):
|
|
|
|
|
start = col
|
2019-01-09 04:50:47 +01:00
|
|
|
for item in sheet.timing_table.rows:
|
|
|
|
|
if item[0].startswith(row[col]):
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-09 04:50:47 +01:00
|
|
|
if item[0].endswith('setup rising'):
|
|
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('setup falling'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('hold rising'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('hold falling'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
elif(row[col].startswith('DOUT')):
|
|
|
|
|
start = col
|
2019-01-09 04:50:47 +01:00
|
|
|
for item in sheet.timing_table.rows:
|
|
|
|
|
if item[0].startswith(row[col]):
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-09 04:50:47 +01:00
|
|
|
if item[0].endswith('cell rise'):
|
|
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('cell fall'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('rise transition'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('fall transition'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
elif(row[col].startswith('CSb')):
|
|
|
|
|
start = col
|
2019-01-09 04:50:47 +01:00
|
|
|
for item in sheet.timing_table.rows:
|
|
|
|
|
if item[0].startswith(row[col]):
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-09 04:50:47 +01:00
|
|
|
if item[0].endswith('setup rising'):
|
|
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('setup falling'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('hold rising'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('hold falling'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
elif(row[col].startswith('WEb')):
|
|
|
|
|
start = col
|
2019-01-09 04:50:47 +01:00
|
|
|
for item in sheet.timing_table.rows:
|
|
|
|
|
if item[0].startswith(row[col]):
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-09 04:50:47 +01:00
|
|
|
if item[0].endswith('setup rising'):
|
|
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('setup falling'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('hold rising'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('hold falling'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
|
|
|
|
col += 1
|
|
|
|
|
|
|
|
|
|
elif(row[col].startswith('ADDR')):
|
|
|
|
|
start = col
|
2019-01-09 04:50:47 +01:00
|
|
|
for item in sheet.timing_table.rows:
|
|
|
|
|
if item[0].startswith(row[col]):
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-09 04:50:47 +01:00
|
|
|
if item[0].endswith('setup rising'):
|
|
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('setup falling'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('hold rising'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
if item[0].endswith('hold falling'):
|
2019-01-09 04:50:47 +01:00
|
|
|
if float(row[col+1]) < float(item[1]):
|
|
|
|
|
item[1] = row[col+1]
|
|
|
|
|
if float(row[col+2]) > float(item[2]):
|
|
|
|
|
item[2] = row[col+2]
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-02-07 05:31:22 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
|
|
|
|
col += 1
|
2019-01-02 19:14:45 +01:00
|
|
|
|
2018-11-11 05:23:26 +01:00
|
|
|
else:
|
2019-01-17 00:43:08 +01:00
|
|
|
for element in row[col_start: col - 1]:
|
|
|
|
|
sheet.description.append(str(element))
|
2018-11-11 05:23:26 +01:00
|
|
|
break
|
2019-02-07 15:33:39 +01:00
|
|
|
|
|
|
|
|
#check if new power is worse the previous
|
2019-02-07 05:31:22 +01:00
|
|
|
while(True):
|
|
|
|
|
col_start = col
|
|
|
|
|
if row[col] == 'power':
|
|
|
|
|
for item in sheet.power_table.rows:
|
|
|
|
|
if item[0].startswith(row[col+1]):
|
|
|
|
|
if item[2].startswith('{0} Rising'.format(row[col+2])):
|
|
|
|
|
if float(item[2]) < float(row[col+3]):
|
|
|
|
|
item[2] = row[col+3]
|
|
|
|
|
if item[2].startswith('{0} Falling'.format(row[col+2])):
|
|
|
|
|
if float(item[2]) < float(row[col+3]):
|
|
|
|
|
item[2] = row[col+3]
|
|
|
|
|
col += 4
|
|
|
|
|
else:
|
|
|
|
|
break
|
2019-02-07 15:33:39 +01:00
|
|
|
# check if new leakge is worse the previous
|
2019-02-07 05:31:22 +01:00
|
|
|
while(True):
|
|
|
|
|
col_start = col
|
|
|
|
|
if row[col] == 'leak':
|
|
|
|
|
for item in sheet.power_table.rows:
|
|
|
|
|
if item[0].startswith(row[col+1]):
|
|
|
|
|
if float(item[2]) < float(row[col+2]):
|
|
|
|
|
item[2] = row[col+2]
|
|
|
|
|
col += 3
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
break
|
2019-02-07 15:33:39 +01:00
|
|
|
# add new corner information
|
2019-02-07 05:31:22 +01:00
|
|
|
new_sheet.corners_table.add_row(
|
|
|
|
|
[PROC, VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
|
2019-01-17 00:43:08 +01:00
|
|
|
new_sheet.dlv_table.add_row(
|
2019-01-16 04:47:48 +01:00
|
|
|
['.lib', 'Synthesis models', '<a href="file://{0}">{1}</a>'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
2018-10-12 01:03:05 +02:00
|
|
|
if found == 0:
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
# if this is the first corner for this sram, run first time configuration and set up tables
|
|
|
|
|
new_sheet = datasheet.datasheet(NAME)
|
2018-10-12 01:03:05 +02:00
|
|
|
pages.append(new_sheet)
|
|
|
|
|
|
2019-01-02 19:30:03 +01:00
|
|
|
new_sheet.git_id = ORIGIN_ID
|
|
|
|
|
new_sheet.time = DATETIME
|
2019-01-02 19:14:45 +01:00
|
|
|
new_sheet.DRC = DRC
|
|
|
|
|
new_sheet.LVS = LVS
|
2019-01-31 17:28:51 +01:00
|
|
|
new_sheet.ANALYTICAL_MODEL = ANALYTICAL_MODEL
|
2019-01-17 00:43:08 +01:00
|
|
|
new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS,
|
|
|
|
|
NUM_R_PORTS, TECH_NAME, MIN_PERIOD, WORD_SIZE, ORIGIN_ID, DATETIME]
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.corners_table = table_gen.table_gen("corners")
|
|
|
|
|
new_sheet.corners_table.add_row(
|
2019-01-31 17:09:00 +01:00
|
|
|
['Transistor Type', 'Power Supply', 'Temperature', 'Corner Name'])
|
2019-02-07 05:31:22 +01:00
|
|
|
new_sheet.corners_table.add_row(
|
|
|
|
|
[PROC, VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')])
|
2019-01-17 00:43:08 +01:00
|
|
|
new_sheet.operating_table = table_gen.table_gen(
|
|
|
|
|
"operating_table")
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.operating_table.add_row(
|
|
|
|
|
['Parameter', 'Min', 'Typ', 'Max', 'Units'])
|
|
|
|
|
new_sheet.operating_table.add_row(
|
|
|
|
|
['Power supply (VDD) range', VOLT, VOLT, VOLT, 'Volts'])
|
|
|
|
|
new_sheet.operating_table.add_row(
|
|
|
|
|
['Operating Temperature', TEMP, TEMP, TEMP, 'Celsius'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
2018-10-12 22:22:12 +02:00
|
|
|
try:
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.operating_table.add_row(['Operating Frequency (F)', '', '', str(
|
|
|
|
|
math.floor(1000/float(MIN_PERIOD))), 'MHz'])
|
2018-10-12 22:22:12 +02:00
|
|
|
except Exception:
|
2019-01-16 04:47:48 +01:00
|
|
|
# failed to provide non-zero MIN_PERIOD
|
|
|
|
|
new_sheet.operating_table.add_row(
|
|
|
|
|
['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz'])
|
2019-02-07 05:31:22 +01:00
|
|
|
new_sheet.power_table = table_gen.table_gen("power")
|
|
|
|
|
new_sheet.power_table.add_row(
|
|
|
|
|
['Pins', 'Mode', 'Power', 'Units'])
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table = table_gen.table_gen("timing")
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['Parameter', 'Min', 'Max', 'Units'])
|
2019-02-07 15:33:39 +01:00
|
|
|
# parse initial timing information
|
2018-11-11 05:23:26 +01:00
|
|
|
while(True):
|
2019-01-17 00:43:08 +01:00
|
|
|
col_start = col
|
2019-01-08 04:43:57 +01:00
|
|
|
if(row[col].startswith('DIN')):
|
|
|
|
|
start = col
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
col += 1
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
elif(row[col].startswith('DOUT')):
|
|
|
|
|
start = col
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} cell rise'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} cell fall'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} rise transition'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} fall transition'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
col += 1
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-08 04:43:57 +01:00
|
|
|
elif(row[col].startswith('CSb')):
|
|
|
|
|
start = col
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
col += 2
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
col += 1
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
elif(row[col].startswith('WEb')):
|
|
|
|
|
start = col
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
col += 1
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-08 04:43:57 +01:00
|
|
|
elif(row[col].startswith('ADDR')):
|
|
|
|
|
start = col
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
2019-01-16 04:47:48 +01:00
|
|
|
|
|
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.timing_table.add_row(
|
|
|
|
|
['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
|
|
|
|
col += 2
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
col += 1
|
2019-01-08 04:43:57 +01:00
|
|
|
|
2018-11-11 05:23:26 +01:00
|
|
|
else:
|
2019-01-17 00:43:08 +01:00
|
|
|
for element in row[col_start:col-1]:
|
|
|
|
|
sheet.description.append(str(element))
|
2018-11-11 05:23:26 +01:00
|
|
|
break
|
2019-02-07 15:33:39 +01:00
|
|
|
# parse initial power and leakage information
|
2019-02-07 05:31:22 +01:00
|
|
|
while(True):
|
|
|
|
|
start = col
|
|
|
|
|
if(row[col].startswith('power')):
|
|
|
|
|
new_sheet.power_table.add_row([row[col+1],
|
|
|
|
|
'{0} Rising'.format(
|
|
|
|
|
row[col+2]),
|
|
|
|
|
row[col+3][0:6],
|
|
|
|
|
'mW']
|
|
|
|
|
)
|
|
|
|
|
new_sheet.power_table.add_row([row[col+1],
|
|
|
|
|
'{0} Falling'.format(
|
|
|
|
|
row[col+2]),
|
|
|
|
|
row[col+3][0:6],
|
|
|
|
|
'mW']
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
col += 4
|
|
|
|
|
|
|
|
|
|
elif(row[col].startswith('leak')):
|
|
|
|
|
new_sheet.power_table.add_row(
|
|
|
|
|
[row[col+1], 'leakage', row[col+2], 'mW'])
|
|
|
|
|
col += 3
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
break
|
|
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.dlv_table = table_gen.table_gen("dlv")
|
|
|
|
|
new_sheet.dlv_table.add_row(['Type', 'Description', 'Link'])
|
2018-11-11 05:23:26 +01:00
|
|
|
|
2019-01-16 04:47:48 +01:00
|
|
|
new_sheet.io_table = table_gen.table_gen("io")
|
2019-01-09 05:04:30 +01:00
|
|
|
new_sheet.io_table.add_row(['Type', 'Value'])
|
2019-01-08 04:43:57 +01:00
|
|
|
|
2018-10-27 20:21:06 +02:00
|
|
|
if not OPTS.netlist_only:
|
2019-01-16 04:47:48 +01:00
|
|
|
# physical layout files should not be generated in netlist only mode
|
|
|
|
|
new_sheet.dlv_table.add_row(
|
|
|
|
|
['.gds', 'GDSII layout views', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'gds')])
|
|
|
|
|
new_sheet.dlv_table.add_row(
|
|
|
|
|
['.lef', 'LEF files', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'lef')])
|
|
|
|
|
|
|
|
|
|
new_sheet.dlv_table.add_row(
|
|
|
|
|
['.log', 'OpenRAM compile log', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'log')])
|
|
|
|
|
new_sheet.dlv_table.add_row(
|
|
|
|
|
['.v', 'Verilog simulation models', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'v')])
|
|
|
|
|
new_sheet.dlv_table.add_row(
|
|
|
|
|
['.html', 'This datasheet', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'html')])
|
|
|
|
|
new_sheet.dlv_table.add_row(
|
|
|
|
|
['.lib', 'Synthesis models', '<a href="{1}">{1}</a>'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))])
|
|
|
|
|
new_sheet.dlv_table.add_row(
|
|
|
|
|
['.py', 'OpenRAM configuration file', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'py')])
|
|
|
|
|
new_sheet.dlv_table.add_row(
|
|
|
|
|
['.sp', 'SPICE netlists', '<a href="{0}.{1}">{0}.{1}</a>'.format(OPTS.output_name, 'sp')])
|
|
|
|
|
|
|
|
|
|
new_sheet.io_table.add_row(['WORD_SIZE', WORD_SIZE])
|
|
|
|
|
new_sheet.io_table.add_row(['NUM_WORDS', NUM_WORDS])
|
|
|
|
|
new_sheet.io_table.add_row(['NUM_BANKS', NUM_BANKS])
|
|
|
|
|
new_sheet.io_table.add_row(['NUM_RW_PORTS', NUM_RW_PORTS])
|
|
|
|
|
new_sheet.io_table.add_row(['NUM_R_PORTS', NUM_R_PORTS])
|
|
|
|
|
new_sheet.io_table.add_row(['NUM_W_PORTS', NUM_W_PORTS])
|
2019-01-31 17:09:00 +01:00
|
|
|
new_sheet.io_table.add_row(
|
|
|
|
|
['Area (µm<sup>2</sup>)', AREA])
|
2018-10-12 01:03:05 +02:00
|
|
|
|
|
|
|
|
|
2018-10-12 22:22:12 +02:00
|
|
|
class datasheet_gen():
|
2019-01-16 23:52:01 +01:00
|
|
|
def datasheet_write(name):
|
2019-02-07 15:33:39 +01:00
|
|
|
"""writes the datasheet to a file"""
|
2019-01-09 04:50:47 +01:00
|
|
|
in_dir = OPTS.openram_temp
|
|
|
|
|
|
|
|
|
|
if not (os.path.isdir(in_dir)):
|
|
|
|
|
os.mkdir(in_dir)
|
2018-10-12 01:03:05 +02:00
|
|
|
|
2019-01-09 04:50:47 +01:00
|
|
|
datasheets = []
|
2019-01-16 23:52:01 +01:00
|
|
|
parse_characterizer_csv(in_dir + "/datasheet.info", datasheets)
|
2018-10-12 01:03:05 +02:00
|
|
|
|
2019-01-09 04:50:47 +01:00
|
|
|
for sheets in datasheets:
|
|
|
|
|
with open(name, 'w+') as f:
|
|
|
|
|
sheets.generate_html()
|
|
|
|
|
f.write(sheets.html)
|