blob: 0c5049a6dba06be0911cd1d0282ef08d9732c591 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import json
import csv
from prjxray.segmaker import Segmaker
from prjxray import verilog
from prjxray import segmaker
def isinv_tags(segmk, ps, site, actual_ps):
# all of these bits are inverted
ks = [
('IS_CLKARDCLK_INVERTED', 'ZINV_CLKARDCLK'),
('IS_CLKBWRCLK_INVERTED', 'ZINV_CLKBWRCLK'),
('IS_REGCLKARDRCLK_INVERTED', 'ZINV_REGCLKARDRCLK'),
('IS_REGCLKB_INVERTED', 'ZINV_REGCLKB'),
('IS_ENARDEN_INVERTED', 'ZINV_ENARDEN'),
('IS_ENBWREN_INVERTED', 'ZINV_ENBWREN'),
('IS_RSTRAMARSTRAM_INVERTED', 'ZINV_RSTRAMARSTRAM'),
('IS_RSTRAMB_INVERTED', 'ZINV_RSTRAMB'),
('IS_RSTREGARSTREG_INVERTED', 'ZINV_RSTREGARSTREG'),
('IS_RSTREGB_INVERTED', 'ZINV_RSTREGB'),
]
for param, tagname in ks:
# The CLK inverts sometimes are changed during synthesis, resulting
# in addition inversions. Take this into account.
if param in actual_ps:
tag = 1 ^ verilog.parsei(actual_ps[param])
elif param == 'IS_REGCLKARDRCLK_INVERTED':
if verilog.parsei(ps['DOA_REG']):
# When DOA_REG == 1, REGCLKARDRCLK follows the CLKARDCLK setting.
tag = 1 ^ verilog.parsei(actual_ps['IS_CLKARDCLK_INVERTED'])
else:
# When DOA_REG == 0, REGCLKARDRCLK is always inverted.
tag = 0
segmk.add_site_tag(site, tagname, tag)
elif param == 'IS_REGCLKB_INVERTED':
if verilog.parsei(ps['DOB_REG']):
# When DOB_REG == 1, REGCLKB follows the CLKBWRCLK setting.
tag = 1 ^ verilog.parsei(actual_ps['IS_CLKBWRCLK_INVERTED'])
else:
# When DOB_REG == 0, REGCLKB is always inverted.
tag = 0
else:
tag = 1 ^ verilog.parsei(ps[param])
segmk.add_site_tag(site, tagname, tag)
def bus_tags(segmk, ps, site):
for param in ("DOA_REG", "DOB_REG"):
segmk.add_site_tag(site, param, verilog.parsei(ps[param]))
for param, tagname in [('SRVAL_A', 'ZSRVAL_A'), ('SRVAL_B', 'ZSRVAL_B'),
('INIT_A', 'ZINIT_A'), ('INIT_B', 'ZINIT_B')]:
bitstr = verilog.parse_bitstr(ps[param])
ab = param[-1]
# Are all bits present?
hasparity = ps['READ_WIDTH_' + ab] == 18
for i in range(18):
# Magic bit positions from experimentation
# we could just only solve when parity, but this check documents the fine points a bit better
if hasparity or i not in (1, 9):
segmk.add_site_tag(
site, '%s[%u]' % (tagname, i), 1 ^ bitstr[i])
def rw_width_tags(segmk, ps, site):
'''
Y0.READ_WIDTH_A
width 001_03 001_04 001_05
1 0 0 0
2 1 0 0
4 0 1 0
9 1 1 0
18 0 0 1
'''
params = ["READ_WIDTH_A", "READ_WIDTH_B", "WRITE_WIDTH_A", "WRITE_WIDTH_B"]
for param in params:
set_val = int(ps[param])
if set_val == 0:
set_val = 1
if set_val >= 36:
continue
def mk(x):
return '%s_%u' % (param, x)
segmaker.add_site_group_zero(
segmk, site, "",
[mk(1), mk(2), mk(4), mk(9), mk(18)], mk(1), mk(set_val))
def write_mode_tags(segmk, ps, site):
for param in ["WRITE_MODE_A", "WRITE_MODE_B"]:
set_val = verilog.unquote(ps[param])
# WRITE_FIRST: no bits set
segmk.add_site_tag(
site, '%s_READ_FIRST' % (param), set_val == "READ_FIRST")
segmk.add_site_tag(
site, '%s_NO_CHANGE' % (param), set_val == "NO_CHANGE")
def write_rstreg_priority(segmk, ps, site):
for param in ["RSTREG_PRIORITY_A", "RSTREG_PRIORITY_B"]:
set_val = verilog.unquote(ps[param])
for opt in ["RSTREG", "REGCE"]:
segmk.add_site_tag(
site, "{}_{}".format(param, opt), set_val == opt)
def write_rdaddr_collision(segmk, ps, site):
for opt in ["DELAYED_WRITE", "PERFORMANCE"]:
set_val = verilog.unquote(ps['RDADDR_COLLISION_HWCONFIG'])
segmk.add_site_tag(
site, "RDADDR_COLLISION_HWCONFIG_{}".format(opt), set_val == opt)
def run():
segmk = Segmaker("design.bits")
clk_inverts = {}
with open('design.csv', 'r') as f:
for params in csv.DictReader(f):
clk_inverts[params['site']] = params
print("Loading tags")
f = open('params.jl', 'r')
f.readline()
for l in f:
j = json.loads(l)
ps = j['params']
assert j['module'] == 'my_RAMB18E1'
site = verilog.unquote(ps['LOC'])
bus_tags(segmk, ps, site)
if ps['RAM_MODE'] == '"TDP"':
rw_width_tags(segmk, ps, site)
segmk.add_site_tag(
site, 'SDP_READ_WIDTH_36', ps['RAM_MODE'] == '"SDP"'
and int(ps['READ_WIDTH_A']) == 36)
segmk.add_site_tag(
site, 'SDP_WRITE_WIDTH_36', ps['RAM_MODE'] == '"SDP"'
and int(ps['WRITE_WIDTH_B']) == 36)
if ps['READ_WIDTH_A'] < 36 and ps['WRITE_WIDTH_B'] < 36:
isinv_tags(segmk, ps, site, clk_inverts[site])
write_mode_tags(segmk, ps, site)
write_rstreg_priority(segmk, ps, site)
write_rdaddr_collision(segmk, ps, site)
def bitfilter(frame, bit):
# rw_width_tags() aliasing interconnect on large widths
return frame not in (0, 20, 21)
segmk.compile(bitfilter=bitfilter)
segmk.write()
run()