0
\$\begingroup\$

Sorry I am not an expert with Verilog. I come from a software background.

I have RAM sharer/multiplexer that I am creating which can take "command requests" from 3 different sources (1. VGA controller, 2. Blitter, 3. External CPU). Each source gets a "slice" of time to communicate with an SRAM chip.

Rather than having if conditions everywhere, is there any way in which I can switch some wires to act like C pointers?

For example, I have the following 3 outputs:

bit [DATA_WIDTH-1 : 0 ] vgaCommandData
bit [DATA_WIDTH-1 : 0 ] bltCommandData
bit [DATA_WIDTH-1 : 0 ] cpuCommandData

Is there any way I can point something to one of these 3 buses so that my RAM controller just does a read to a "currentCommandData" bus that maps to one of the above 3 buses?

I don't want to do this:

if( sliceOwner == SLICE_VGA )
begin
  vgaCommandData <= blah;
end
else
if( sliceOwner == SLICE_BLT )
begin
  bltCommandData <= blah;
end
else
if( sliceOwner == SLICE_CPU )
begin
  cpuCommandData <= blah;
end

This may be fine once, but I'm trying to avoid repeating these 3 conditions everywhere. Ideally I would like to have one statement that does something like this:

if( sliceOwner == SLICE_VGA )
begin
  use vgaCommandData when currentCommandData is read/assigned
end
else
if( sliceOwner == SLICE_BLT )
begin
  use bltCommandData when currentCommandData is read/assigned
end
else
if( sliceOwner == SLICE_CPU )
begin
  use cpuCommandData when currentCommandData is read/assigned
end

....

currentCommandData <= blah;

I realise I can have a temporary currentCommandData value and then add a condition to copy it back into the respective bus but that's not what I am after.

Perhaps what I want cannot be done but I welcome suggestions.

\$\endgroup\$
1
  • \$\begingroup\$ I'm not sure why you'd need "if statements everywhere". Imagine a module that has three interfaces on one side (where an "interface" is a set of ports including things like "address", "data in", "data out", "command", "response") that connect to your three sources -- and one port on the other side that connects to your memory controller. All of the logic to connect one of the source interfaces to the memory interface would be contained within that module, and none of the rest of the system would be affected. \$\endgroup\$
    – Dave Tweed
    Commented Mar 26, 2022 at 11:47

1 Answer 1

2
\$\begingroup\$

I'm not sure whether this is the sort of thing you're looking for, but here's a module that I've used to select one of three AXI stream sources (video) to forward to a single destination. The concept can be generalized to handle any interface that has both input and output ports, like your memory interface.

/* axi_mux3.v */

/* This module selects one of three streams to send to its output.
 * TREADY on the deselected streams is negated.
 */

/* History:
 *  2021-02-07 DT   Start.
 */

`timescale 1ns / 1ps

module axi_mux3 #(
  parameter TDATA_WIDTH = 1,
  parameter TUSER_WIDTH = 1
) (
  /* AXISV video in 0 */
  output reg                    vin_0_tready,
  input                         vin_0_tvalid,
  input       [TDATA_WIDTH-1:0] vin_0_tdata,
  input       [TUSER_WIDTH-1:0] vin_0_tuser,
  input                         vin_0_tlast,
  /* AXISV video in 1 */
  output reg                    vin_1_tready,
  input                         vin_1_tvalid,
  input       [TDATA_WIDTH-1:0] vin_1_tdata,
  input       [TUSER_WIDTH-1:0] vin_1_tuser,
  input                         vin_1_tlast,
  /* AXISV video in 2 */
  output reg                    vin_2_tready,
  input                         vin_2_tvalid,
  input       [TDATA_WIDTH-1:0] vin_2_tdata,
  input       [TUSER_WIDTH-1:0] vin_2_tuser,
  input                         vin_2_tlast,
  /* AXISV video out */
  input                         vout_tready,
  output reg                    vout_tvalid,
  output reg  [TDATA_WIDTH-1:0] vout_tdata,
  output reg  [TUSER_WIDTH-1:0] vout_tuser,
  output reg                    vout_tlast,
  /* configuration */
  input                   [1:0] select
);

  always @* case (select)
    2'd0: begin
      vin_0_tready = vout_tready;
      vin_1_tready = 0;
      vin_2_tready = 0;
      vout_tvalid  = vin_0_tvalid;
      vout_tdata   = vin_0_tdata;
      vout_tuser   = vin_0_tuser;
      vout_tlast   = vin_0_tlast;
    end

    2'd1: begin
      vin_0_tready = 0;
      vin_1_tready = vout_tready;
      vin_2_tready = 0;
      vout_tvalid  = vin_1_tvalid;
      vout_tdata   = vin_1_tdata;
      vout_tuser   = vin_1_tuser;
      vout_tlast   = vin_1_tlast;
    end

    2'd2: begin
      vin_0_tready = 0;
      vin_1_tready = 0;
      vin_2_tready = vout_tready;
      vout_tvalid  = vin_2_tvalid;
      vout_tdata   = vin_2_tdata;
      vout_tuser   = vin_2_tuser;
      vout_tlast   = vin_2_tlast;
    end

    default: begin
      vin_0_tready = 0;
      vin_1_tready = 0;
      vin_2_tready = 0;
      vout_tvalid  = 0;
      vout_tdata   = vin_0_tdata;
      vout_tuser   = vin_0_tuser;
      vout_tlast   = vin_0_tlast;
    end
  endcase
   
endmodule
\$\endgroup\$
1
  • \$\begingroup\$ I'm going to accept your answer @Dave Tweed. After experimenting with continuous assignments and functions, I'm definitely going to create a module. I just need an input and an output port for each bus/signal that needs to be switched. Thank you! \$\endgroup\$
    – SparkyNZ
    Commented Mar 27, 2022 at 5:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.