litex/test/test_csr.py
Jiaxun Yang af3d2a29fc
csr_bus: Honour re signal from the upstream bus
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>
2024-06-23 19:35:19 +01:00

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))