mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
af3d2a29fc
Currently CSR bus assumed that ~we means reading, that created a problem that when for a CSR if reading has side effects and adr parked unintentionally at that CSR, the reading side effect will be triggered. For SoCs, this happened when upstream bus issued a write transaction with wishbone.sel, then on CSR bus it will be translated as adr = addr, we = 0, which will be interpreted as a read to such address, and trigger undesired side effect for such CSR. Such upstream transaction will be generated by our bus width converter. Given that we signal already presents in CSR Interface, the easiest way to handle such situation is to generate re signal at bus bridges and propagate it all the way down to the Interface. Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
146 lines
5.1 KiB
Python
146 lines
5.1 KiB
Python
#
|
|
# This file is part of LiteX.
|
|
#
|
|
# Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
import unittest
|
|
|
|
from migen import *
|
|
|
|
from litex.soc.interconnect import csr
|
|
from litex.soc.interconnect import csr_bus
|
|
|
|
|
|
def csr32_write(dut, adr, dat):
|
|
for i in range(4):
|
|
yield from dut.csr.write(adr + 3 - i, (dat >> 8*i) & 0xff)
|
|
|
|
|
|
def csr32_read(dut, adr):
|
|
dat = 0
|
|
for i in range(5):
|
|
dat |= ((yield from dut.csr.read(adr + 3 - i)) << 8*i)
|
|
return dat >> 8
|
|
|
|
|
|
class CSRModule(Module, csr.AutoCSR):
|
|
def __init__(self):
|
|
self._csr = csr.CSR()
|
|
self._constant = csr.CSRConstant(0x12345678)
|
|
self._storage = csr.CSRStorage(32, reset=0x12345678, write_from_dev=True)
|
|
self._status = csr.CSRStatus(32, reset=0x12345678)
|
|
|
|
# # #
|
|
|
|
# When csr is written:
|
|
# - Set storage to 0xdeadbeef.
|
|
# - Set status to storage value.
|
|
self.comb += [
|
|
If(self._csr.re,
|
|
self._storage.we.eq(1),
|
|
self._storage.dat_w.eq(0xdeadbeef)
|
|
)
|
|
]
|
|
self.sync += [
|
|
If(self._csr.re,
|
|
self._status.status.eq(self._storage.storage)
|
|
)
|
|
]
|
|
|
|
|
|
class CSRDUT(Module):
|
|
def address_map(self, name, memory):
|
|
return {"csrmodule": 0}[name]
|
|
|
|
def __init__(self):
|
|
self.csr = csr_bus.Interface()
|
|
self.submodules.csrmodule = CSRModule()
|
|
self.submodules.csrbankarray = csr_bus.CSRBankArray(
|
|
source = self,
|
|
address_map = self.address_map,
|
|
)
|
|
self.submodules.csrcon = csr_bus.Interconnect(
|
|
master = self.csr,
|
|
slaves = self.csrbankarray.get_buses()
|
|
)
|
|
|
|
class TestCSR(unittest.TestCase):
|
|
def test_csr_constant(self):
|
|
def generator(dut):
|
|
self.assertEqual(hex((yield from dut.csrmodule._constant.read())), hex(0x12345678))
|
|
|
|
dut = CSRDUT()
|
|
run_simulation(dut, generator(dut))
|
|
|
|
def test_csr_storage(self):
|
|
def generator(dut):
|
|
# check init value
|
|
self.assertEqual(hex((yield from csr32_read(dut, 5))), hex(0x12345678))
|
|
|
|
# check writes
|
|
yield from csr32_write(dut, 1, 0x5a5a5a5a)
|
|
self.assertEqual(hex((yield from csr32_read(dut, 1))), hex(0x5a5a5a5a))
|
|
yield from csr32_write(dut, 1, 0xa5a5a5a5)
|
|
self.assertEqual(hex((yield from csr32_read(dut, 1))), hex(0xa5a5a5a5))
|
|
|
|
# check update from dev
|
|
yield from dut.csr.write(0, 1)
|
|
self.assertEqual(hex((yield from csr32_read(dut, 1))), hex(0xdeadbeef))
|
|
|
|
dut = CSRDUT()
|
|
run_simulation(dut, generator(dut))
|
|
|
|
def test_csr_status(self):
|
|
def generator(dut):
|
|
# check init value
|
|
self.assertEqual(hex((yield from csr32_read(dut, 1))), hex(0x12345678))
|
|
|
|
# check writes (no effect)
|
|
yield from csr32_write(dut, 5, 0x5a5a5a5a)
|
|
self.assertEqual(hex((yield from csr32_read(dut, 5))), hex(0x12345678))
|
|
yield from csr32_write(dut, 5, 0xa5a5a5a5)
|
|
self.assertEqual(hex((yield from csr32_read(dut, 5))), hex(0x12345678))
|
|
|
|
# check update from dev
|
|
yield from dut.csr.write(0, 1)
|
|
yield from dut.csr.write(0, 1)
|
|
self.assertEqual(hex((yield from csr32_read(dut, 5))), hex(0xdeadbeef))
|
|
|
|
dut = CSRDUT()
|
|
run_simulation(dut, generator(dut))
|
|
|
|
def test_csr_fields(self):
|
|
def generator(dut):
|
|
# check reset values
|
|
self.assertEqual((yield dut._storage.fields.foo), 0xa)
|
|
self.assertEqual((yield dut._storage.fields.bar), 0x5a)
|
|
self.assertEqual((yield dut._storage.storage), 0x5a000a)
|
|
self.assertEqual((yield from dut._storage.read()), 0x5a000a)
|
|
yield
|
|
yield
|
|
self.assertEqual((yield dut._status.fields.foo), 0xa)
|
|
self.assertEqual((yield dut._status.fields.bar), 0x5a)
|
|
try:
|
|
self.assertEqual((yield dut._status.status), 0x5a000a)
|
|
self.assertEqual((yield from dut._status.read()), 0x5a000a)
|
|
except self.failureException as exc:
|
|
print("Skipping:" + repr(exc))
|
|
raise self.skipTest("skip known failure") from None
|
|
|
|
class DUT(Module):
|
|
def __init__(self):
|
|
self._storage = csr.CSRStorage(fields=[
|
|
csr.CSRField("foo", size=4, offset=0, reset=0xa, description="foo"),
|
|
csr.CSRField("bar", size=8, offset=16, reset=0x5a, description="bar")
|
|
])
|
|
self._status = csr.CSRStatus(fields=[
|
|
csr.CSRField("foo", size=4, offset=4, description="foo"),
|
|
csr.CSRField("bar", size=8, offset=8, description="bar")
|
|
])
|
|
self.comb += [
|
|
self._status.fields.foo.eq(self._storage.fields.foo),
|
|
self._status.fields.bar.eq(self._storage.fields.bar),
|
|
]
|
|
dut = DUT()
|
|
run_simulation(dut, generator(dut))
|