lambdaconcept/lambdasoc

Strange behaviour in wishbone bus

Opened this issue · 6 comments

Hey! First of all, thanks you for this amazing ecosystem you are building on top of nmigen!! It looks like easier to use than litex.

I'm trying to add vexriscv CPU to this building system but the serial irq is never asserted. I found an unexpected behaviour trying to write "events enable" of the serial peripheral..

As it is shown next, the wb transaction is done but the signals w_stb never goes up but the data is latched correctly.
image

Looking at a correct transaction (tx register), I noticed that the ack signal is never asserted in the previous case but it works ok in the other cases:

image

The same SoC works with minerva CPU.

Let me know if i can help debuging this or sending more information.
Thank you

jfng commented

Sorry for the delay. Could you provide a way to reproduce this bug ? It would help me track down what happened.

Yep, of course!! I'm going to clean it and make it reproducible. Give me a couples of days.

Here is a repository with some useful scripts to reproduce this bug. prepare.sh script creates a virtualenv and applies some patches to lambdasoc-bios to make vexriscv boot.

https://github.com/andresdemski/lambdasoc-vexriscv

Regards

jfng commented

So I gave it a look, and it's weird because I can't reproduce this behavior: dbus writes at 0x3C00000A assert csr_mux_1_uart_ev_enable__w_stb, regardless of the CPU. With Verilator 4.017.

lambdasoc-vexriscv

Looking at a correct transaction (tx register), I noticed that the ack signal is never asserted in the previous case but it works ok in the other cases:

The UART has two separate CSR bridges: one for its own registers (tx_data etc), and another for its event manager (ev_enable etc). Here, tx_data is located behind csr_bridge_0, and ev_enable behind csr_bridge_1.

In your screenshots, I believe that wb_ack and wb_cyc belong to csr_bridge_0, which would explain why they are not asserted when ev_enable is accessed.

Running the same "test" with minerva and vexriscv cpus and using the same gtkw to view the signals, I'm getting different results. The IRQ of the uart isn't asserted with vexriscv. I'm having the same behavior in hardware too.

Are you sure you are running the simulation with --cpu vexriscv?

Vexriscv

python3 cli.py --cpu vexriscv --sim nmigen_boards.versa_ecp5_5g:VersaECP55GPlatform

image

Minerva

python3 cli.py --cpu minerva --sim nmigen_boards.versa_ecp5_5g:VersaECP55GPlatform

image

Hey! I fixed the problem, I don't know if it is the correct way to solve this but it works... I don't know about wishbone bus but I noticed that the ACK signals keeps in 1, and vexriscv generates 2 transactions without dead clocks between each other, so the second transaction is accepted but it isn't processed at all.

I fixed it with the following changes on nmigen-soc:

diff --git a/nmigen_soc/csr/wishbone.py b/nmigen_soc/csr/wishbone.py
index ece1984..e152896 100644
--- a/nmigen_soc/csr/wishbone.py
+++ b/nmigen_soc/csr/wishbone.py
@@ -66,7 +66,10 @@ class WishboneCSRBridge(Elaboratable):
         cycle = Signal(range(len(wb_bus.sel) + 1))
         m.d.comb += csr_bus.addr.eq(Cat(cycle[:log2_int(len(wb_bus.sel))], wb_bus.adr))
 
-        with m.If(wb_bus.cyc & wb_bus.stb):
+        with m.If(wb_bus.ack):
+            m.d.sync += wb_bus.ack.eq(0)
+
+        with m.Elif(wb_bus.cyc & wb_bus.stb):
             with m.Switch(cycle):
                 def segment(index):
                     return slice(index * wb_bus.granularity, (index + 1) * wb_bus.granularity)
@@ -85,9 +88,6 @@ class WishboneCSRBridge(Elaboratable):
                     m.d.sync += wb_bus.dat_r[segment(index)].eq(csr_bus.r_data)
                     m.d.sync += wb_bus.ack.eq(1)
 
-        with m.Else():
-            m.d.sync += wb_bus.ack.eq(0)
-
         with m.If(wb_bus.ack):
             m.d.sync += cycle.eq(0)

What do you think? Is it ok?