# Verilog asynchronous reads of regs - and design question

I'm trying to understand what the following bit of behavioral code, what kind of hardware it turns into:

reg [7:0] k0, k1, k2, k3;
reg [7:0] data1_tmp, data2_tmp;

// Asynchronously read data from two registers
always @(*)
begin
case (reg1)
0: data1_tmp = k0;
1: data1_tmp = k1;
2: data1_tmp = k2;
3: data1_tmp = k3;
endcase
case (reg2)
0: data2_tmp = k0;
1: data2_tmp = k1;
2: data2_tmp = k2;
3: data2_tmp = k3;
endcase
end


Logically I understand what it's doing. But I would like to know what this mini register file would be made of in hardware. Particularly, the 4x8 bit array consisting of k0,k1,k2,k3. I thought when it came to registers and arrays like this, you need a clock to read out data, like RAM?

See I'm having a conceptual problem designing a simple verilog cache module. I have a data array containing all my tags like so:

reg [NUM_TAG_BITS-1:0] tag_array[NUM_BLOCKS-1:0]


And I have a wire "line_select" (from my input PC). What I want to do is retrieve tag_array[line_select] and then put it into a comparator with the tag from my PC to see if I have a hit.

But I thought whenever I access tag_array, I need to be inside "always @ (posedge clk)" code. Then I got stuck: how do I read from this tag_array and do the comparison all within the same clock cycle? So I found the above code online saying you can read from regs asynchronously, then I got confused because frankly I don't know enough about memory hardware and how that's possible.

Thanks a lot for any help!

Your code simulates two multiplexers. These are actually asynchronous components. The fact that Verilog requires data1_temp and data2_temp to be declared as reg's is a quirk of Verilog syntax and your choice of coding style, and doesn't mean these signals would be the outputs of storage elements in a physical implementation.

If you want to capture these values in actual registers, you need to add those explicitly:

reg [7:0] data1, data2;
always @(posedge someclock) begin
data1 <= data1_tmp;
data2 <= data2_tmp;
end


But I would like to know what this mini register file would be made of in hardware. Particularly, the 4x8 bit array consisting of k0,k1,k2,k3.

You haven't shown how these variables are assigned, so it's not possible to say how they are implemented. As your code showed, just declaring them as reg doesn't guarantee they are implemented with actual storage elements. If you assign them inside a block that begins always @(posedge clk) then very likely they are flip-flops, but there are ways you could code them that would make them synthesize differently.

I thought when it came to registers and arrays like this, you need a clock to read out data, like RAM?

You need a clock to update a (physical) register. You can read it out at any time. For example:

wire [8:0] sum;
assign sum = k0 + k1;


is perfectly valid code. sum will change whenever any of its inputs changes. If k0 and k1 are the outputs of flip-flops, their values will only change when there is a clock edge.

For another example, you could equally well describe your multiplexers with code like this:

reg [7:0] k0, k1, k2, k3;
wire [7:0] data1_tmp;
reg [1:0] reg1;
// k<n> and reg1 are assigned elsewhere.
assign data1_tmp = (reg1 == 0) ? k0 :
(reg1 == 1) ? k1 :
(reg1 == 2) ? k2 : k3;


how do I read from this tag_array and do the comparison all within the same clock cycle?

Let me repeat a key point for emphasis: You need to use a clock to assign a new value to a register (an actual hardware register or group of flip-flops). It's output is available at any time.

RAMs are different and how you access the contents of a RAM will depend on details of the type of RAM you use.

I got confused because frankly I don't know enough about memory hardware and how that's possible.

Another key strategy: When you are learning digital logic, I recommend you learn about the physical hardware first, and then work out or study how to simulate it in HDL second. So first, learn what a physical flip-flop is, then learn the standard Verilog methods of describing a flip-flop. Especially if you are trying to write HDL for synthesis, trying to write good code before you learn the capabilities of the underlying hardware will lead you down a lot of dead-end paths.

• Thank you very much! This part really hit home for me: Let me repeat a key point for emphasis: You need to use a clock to assign a new value to a register (an actual hardware register or group of flip-flops). It's output is available at any time. I drew out on paper a bunch of DFFs and realized this.. Of course the outputs are available at any time, and the writes need be synchronous with a clock. Like you suggest I'm trying to learn the hardware concepts more than the coding. Thanks again. – JDS Dec 17 '12 at 3:26
• @YoungMoney, Glad I could help. I'd normally suggest you hold off accepting an answer for 24 hours to encourage more answers. But 1) Dave Tweed is the person here most likely to give a good answer to a Verilog question, and he's already answered. 2) I think my answer is pretty good. Nonetheless, if another answer does come along that helps you out more, feel free to de-accept mine. And there are a couple of other users here who would be able to give good answers if they feel so moved. – The Photon Dec 17 '12 at 3:41
• @Photon: I appreciate the compliment! I've been designing with FPGAs for a long time, but I've only recently started getting up to speed on Verilog specifically. Most of my prior work was in VHDL, and before that, schematic capture. I've very interested in YoungMoney's project, because a significant part of my career was related to high-performance CPU design, including MMUs and caches. – Dave Tweed Dec 17 '12 at 5:06
• @DaveTweed, I know there's others here who can answer a question like this --- but you're certainly on a tear when it comes to actually showing up to answer. Just don't burn out like StevenVH --- racked up 40k rep in a year and then basically disappeared. – The Photon Dec 17 '12 at 5:23

Whether or not a Verilog reg becomes a hardware flip-flop depends on how it's updated. In general, if it's updated inside an always @(posedge <signal>) block, it'll become a DFF.

Your sample code doesn't show how k0, k1, k2 and k3 get updated, so as far as this block is concerned, they're just 32 wires coming from somewhere else. Each case statement is a simple asynchronous multiplexer that selects 8 bits at a time from among those 32 wires.

Whether or not your k<n> variables can be mapped collectively into a hardware RAM structure (assuming such a thing is available in your target technology) depends on both how they are updated and how they are read ... and how good the synthesis tools are at inferring RAM from behavioral code.