2019-04-26 06:37:08 -06:00
|
|
|
from .. import *
|
|
|
|
from ..hdl.rec import *
|
|
|
|
from ..lib.io import *
|
|
|
|
from ..build.dsl import *
|
|
|
|
from ..build.res import *
|
|
|
|
from .tools import *
|
|
|
|
|
|
|
|
|
|
|
|
class ConstraintManagerTestCase(FHDLTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
self.resources = [
|
|
|
|
Resource("clk100", 0, DiffPairs("H1", "H2", dir="i")),
|
|
|
|
Resource("clk50", 0, Pins("K1")),
|
|
|
|
Resource("user_led", 0, Pins("A0", dir="o")),
|
|
|
|
Resource("i2c", 0,
|
|
|
|
Subsignal("scl", Pins("N10", dir="o")),
|
|
|
|
Subsignal("sda", Pins("N11"))
|
|
|
|
)
|
|
|
|
]
|
2019-06-01 09:41:41 -06:00
|
|
|
self.cm = ConstraintManager(self.resources, [])
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_basic(self):
|
2019-06-01 09:41:41 -06:00
|
|
|
self.clocks = [
|
|
|
|
("clk100", 100),
|
|
|
|
(("clk50", 0), 50),
|
|
|
|
]
|
|
|
|
self.cm = ConstraintManager(self.resources, self.clocks)
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(self.cm.resources, {
|
|
|
|
("clk100", 0): self.resources[0],
|
|
|
|
("clk50", 0): self.resources[1],
|
|
|
|
("user_led", 0): self.resources[2],
|
|
|
|
("i2c", 0): self.resources[3]
|
|
|
|
})
|
2019-06-01 09:41:41 -06:00
|
|
|
self.assertEqual(self.cm.clocks, {
|
|
|
|
("clk100", 0): 100,
|
|
|
|
("clk50", 0): 50,
|
|
|
|
})
|
2019-04-26 06:37:08 -06:00
|
|
|
|
|
|
|
def test_add_resources(self):
|
|
|
|
new_resources = [
|
|
|
|
Resource("user_led", 1, Pins("A1", dir="o"))
|
|
|
|
]
|
|
|
|
self.cm.add_resources(new_resources)
|
|
|
|
self.assertEqual(self.cm.resources, {
|
|
|
|
("clk100", 0): self.resources[0],
|
|
|
|
("clk50", 0): self.resources[1],
|
|
|
|
("user_led", 0): self.resources[2],
|
|
|
|
("i2c", 0): self.resources[3],
|
|
|
|
("user_led", 1): new_resources[0]
|
|
|
|
})
|
|
|
|
|
|
|
|
def test_lookup(self):
|
|
|
|
r = self.cm.lookup("user_led", 0)
|
|
|
|
self.assertIs(r, self.cm.resources["user_led", 0])
|
|
|
|
|
|
|
|
def test_request_basic(self):
|
|
|
|
r = self.cm.lookup("user_led", 0)
|
|
|
|
user_led = self.cm.request("user_led", 0)
|
|
|
|
|
|
|
|
self.assertIsInstance(user_led, Pin)
|
|
|
|
self.assertEqual(user_led.name, "user_led_0")
|
|
|
|
self.assertEqual(user_led.width, 1)
|
|
|
|
self.assertEqual(user_led.dir, "o")
|
|
|
|
|
|
|
|
ports = list(self.cm.iter_ports())
|
|
|
|
self.assertEqual(len(ports), 1)
|
|
|
|
|
|
|
|
self.assertEqual(list(self.cm.iter_port_constraints()), [
|
2019-06-02 17:36:21 -06:00
|
|
|
("user_led_0_io", ["A0"], {})
|
2019-04-26 06:37:08 -06:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_request_with_dir(self):
|
|
|
|
i2c = self.cm.request("i2c", 0, dir={"sda": "o"})
|
|
|
|
self.assertIsInstance(i2c, Record)
|
|
|
|
self.assertIsInstance(i2c.sda, Pin)
|
|
|
|
self.assertEqual(i2c.sda.dir, "o")
|
|
|
|
|
|
|
|
def test_request_tristate(self):
|
|
|
|
i2c = self.cm.request("i2c", 0)
|
|
|
|
self.assertEqual(i2c.sda.dir, "io")
|
|
|
|
|
|
|
|
ports = list(self.cm.iter_ports())
|
|
|
|
self.assertEqual(len(ports), 2)
|
2019-06-01 10:41:30 -06:00
|
|
|
scl, sda = ports
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(ports[1].name, "i2c_0__sda_io")
|
|
|
|
self.assertEqual(ports[1].nbits, 1)
|
|
|
|
|
2019-06-02 19:58:43 -06:00
|
|
|
self.assertEqual(list(self.cm.iter_single_ended_pins()), [
|
|
|
|
(i2c.scl, scl, {}),
|
|
|
|
(i2c.sda, sda, {}),
|
2019-06-01 10:41:30 -06:00
|
|
|
])
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(list(self.cm.iter_port_constraints()), [
|
2019-06-02 17:36:21 -06:00
|
|
|
("i2c_0__scl_io", ["N10"], {}),
|
|
|
|
("i2c_0__sda_io", ["N11"], {})
|
2019-04-26 06:37:08 -06:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_request_diffpairs(self):
|
|
|
|
clk100 = self.cm.request("clk100", 0)
|
|
|
|
self.assertIsInstance(clk100, Pin)
|
|
|
|
self.assertEqual(clk100.dir, "i")
|
|
|
|
self.assertEqual(clk100.width, 1)
|
|
|
|
|
|
|
|
ports = list(self.cm.iter_ports())
|
|
|
|
self.assertEqual(len(ports), 2)
|
|
|
|
p, n = ports
|
|
|
|
self.assertEqual(p.name, "clk100_0_p")
|
|
|
|
self.assertEqual(p.nbits, clk100.width)
|
|
|
|
self.assertEqual(n.name, "clk100_0_n")
|
|
|
|
self.assertEqual(n.nbits, clk100.width)
|
|
|
|
|
2019-06-02 19:58:43 -06:00
|
|
|
self.assertEqual(list(self.cm.iter_differential_pins()), [
|
|
|
|
(clk100, p, n, {}),
|
2019-06-01 10:41:30 -06:00
|
|
|
])
|
2019-04-26 06:37:08 -06:00
|
|
|
self.assertEqual(list(self.cm.iter_port_constraints()), [
|
2019-06-02 17:36:21 -06:00
|
|
|
("clk100_0_p", ["H1"], {}),
|
2019-06-02 19:58:43 -06:00
|
|
|
("clk100_0_n", ["H2"], {}),
|
|
|
|
])
|
|
|
|
self.assertEqual(list(self.cm.iter_port_constraints(diff_pins="p")), [
|
|
|
|
("clk100_0_p", ["H1"], {}),
|
|
|
|
])
|
|
|
|
self.assertEqual(list(self.cm.iter_port_constraints(diff_pins="n")), [
|
|
|
|
("clk100_0_n", ["H2"], {}),
|
2019-04-26 06:37:08 -06:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_add_clock(self):
|
|
|
|
self.cm.add_clock("clk100", 0, 10e6)
|
|
|
|
self.assertEqual(self.cm.clocks["clk100", 0], 10e6)
|
|
|
|
self.cm.add_clock("clk50", 0, 5e6)
|
|
|
|
|
|
|
|
clk100 = self.cm.request("clk100", 0)
|
|
|
|
clk50 = self.cm.request("clk50", 0, dir="i")
|
|
|
|
self.assertEqual(list(sorted(self.cm.iter_clock_constraints())), [
|
|
|
|
("clk100_0_p", 10e6),
|
2019-06-01 10:41:30 -06:00
|
|
|
("clk50_0_io", 5e6)
|
2019-04-26 06:37:08 -06:00
|
|
|
])
|
|
|
|
|
|
|
|
def test_wrong_resources(self):
|
|
|
|
with self.assertRaises(TypeError, msg="Object 'wrong' is not a Resource"):
|
|
|
|
self.cm.add_resources(['wrong'])
|
|
|
|
|
|
|
|
def test_wrong_resources_duplicate(self):
|
|
|
|
with self.assertRaises(NameError,
|
|
|
|
msg="Trying to add (resource user_led 0 (pins o A1) ), but "
|
|
|
|
"(resource user_led 0 (pins o A0) ) has the same name and number"):
|
|
|
|
self.cm.add_resources([Resource("user_led", 0, Pins("A1", dir="o"))])
|
|
|
|
|
|
|
|
def test_wrong_lookup(self):
|
|
|
|
with self.assertRaises(NameError,
|
|
|
|
msg="Resource user_led#1 does not exist"):
|
|
|
|
r = self.cm.lookup("user_led", 1)
|
|
|
|
|
|
|
|
def test_wrong_frequency_subsignals(self):
|
|
|
|
with self.assertRaises(ConstraintError,
|
|
|
|
msg="Cannot constrain frequency of resource i2c#0 because "
|
|
|
|
"it has subsignals"):
|
|
|
|
self.cm.add_clock("i2c", 0, 10e6)
|
|
|
|
|
|
|
|
def test_wrong_frequency_tristate(self):
|
|
|
|
with self.assertRaises(ConstraintError,
|
|
|
|
msg="Cannot constrain frequency of resource clk50#0 because "
|
|
|
|
"it has been requested as a tristate buffer"):
|
|
|
|
self.cm.add_clock("clk50", 0, 20e6)
|
|
|
|
clk50 = self.cm.request("clk50", 0)
|
|
|
|
list(self.cm.iter_clock_constraints())
|
|
|
|
|
|
|
|
def test_wrong_frequency_duplicate(self):
|
|
|
|
with self.assertRaises(ConstraintError,
|
|
|
|
msg="Resource clk100#0 is already constrained to a frequency of 10.000000 MHz"):
|
|
|
|
self.cm.add_clock("clk100", 0, 10e6)
|
|
|
|
self.cm.add_clock("clk100", 0, 5e6)
|
|
|
|
|
|
|
|
def test_wrong_request_duplicate(self):
|
|
|
|
with self.assertRaises(ConstraintError,
|
|
|
|
msg="Resource user_led#0 has already been requested"):
|
|
|
|
self.cm.request("user_led", 0)
|
|
|
|
self.cm.request("user_led", 0)
|
|
|
|
|
|
|
|
def test_wrong_request_with_dir(self):
|
|
|
|
with self.assertRaises(TypeError,
|
|
|
|
msg="Direction must be one of \"i\", \"o\" or \"io\", not 'wrong'"):
|
|
|
|
user_led = self.cm.request("user_led", 0, dir="wrong")
|
|
|
|
|
|
|
|
def test_wrong_request_with_dir_io(self):
|
|
|
|
with self.assertRaises(ValueError,
|
|
|
|
msg="Direction of (pins o A0) cannot be changed from \"o\" to \"i\"; direction "
|
|
|
|
"can be changed from \"io\" to \"i\" or from \"io\"to \"o\""):
|
|
|
|
user_led = self.cm.request("user_led", 0, dir="i")
|
|
|
|
|
|
|
|
def test_wrong_request_with_dir_dict(self):
|
|
|
|
with self.assertRaises(TypeError,
|
|
|
|
msg="Directions must be a dict, not 'i', because (resource i2c 0 (subsignal scl "
|
|
|
|
"(pins o N10) ) (subsignal sda (pins io N11) ) ) has subsignals"):
|
|
|
|
i2c = self.cm.request("i2c", 0, dir="i")
|
|
|
|
|
|
|
|
def test_wrong_request_with_wrong_xdr(self):
|
|
|
|
with self.assertRaises(ValueError,
|
|
|
|
msg="Data rate of (pins o A0) must be a positive integer, not 0"):
|
|
|
|
user_led = self.cm.request("user_led", 0, xdr=0)
|
|
|
|
|
|
|
|
def test_wrong_request_with_xdr_dict(self):
|
|
|
|
with self.assertRaises(TypeError,
|
|
|
|
msg="Data rate must be a dict, not 2, because (resource i2c 0 (subsignal scl "
|
|
|
|
"(pins o N10) ) (subsignal sda (pins io N11) ) ) has subsignals"):
|
|
|
|
i2c = self.cm.request("i2c", 0, xdr=2)
|