enjoy-digital / litedram

Small footprint and configurable DRAM core
Other
365 stars 115 forks source link

Implementation of LiteDRAMNativePortUpConverter #191

Closed jedrzejboczar closed 3 years ago

jedrzejboczar commented 4 years ago

In litedram/frontend/adaptation.py we have port data width converters, each should be able to work in all modes (read/write/both). We need to update current implementation of up-converter as it does not support mode="both".

I started working on that and have some questions about the special cases that can happen in up-conversion. This just summarizes what I am planning to implement, pleas check if you actually think that the converter should work this way.

Ideal case This is when master performs full, aligned transfers, i.e. for an up-conversion ratio of 1:4 it would do e.g. [0x00, 0x01, 0x02, 0x03], [0x04, 0x05, 0x06, 0x07]. This currently works and should work correctly for mode="both" by just adding StrideConverter for write path.

Special cases When master sends the first command, we send an up-converted command and just acknowledge all the following commands until we count ratio commands. But there are cases when master changes the command type (read/write) or does not-aligned/not-sequential access. To be able to handle such cases we must be able to:

Masking Currently there is an initial sketch of this in LiteDRAMNativeReadPortUpConverter using cmd_buffer with sel signal, however currently we always send sel with all ones. We can just update sel on each command based on the lowest address bits and send sel to cmd_buffer when we know that we should go to the next command. On the data path side we will use this sel value for masking part of data. For reads this masking has already been implemented. For writes we could use sel to update the value of wdata.we.

Next command We need to know when we actually should send sel to cmd_buffer. The obvious case is when port_from.cmd.we changes - we send the current sel. The second case is when the address after translation (i.e. shifted address) changes, e.g. when master sends [0x01, 0x02, 0x03, 0x04] with ratio 1:4. We can always store the last address and, for each new command, check if the translated address changed, this way we can automatically flush the data between 0x03 >> 2 = 0x00 and 0x04 >> 2 = 0x01. But in this same scenario, master has to somehow signalize that 0x04 is the last transfer, so that we can perform another command to read/write data for this address. We can achieve this using port_from.flush signal (or maybe port_from.cmd.last?).

enjoy-digital commented 4 years ago

@jedrzejboczar: thanks, this seems fine. When working directly with a native port, you should be able to use port_from.cmd.last, it should be similar to flush (which is used by user on an adapted port to have access low level access on the native port).

To simplify things, you can also consider that any gap on the input commands will prevent the access to be optimized/regrouped: