I'm new on golang and try to understand how the select statement work at
https://www.tutorialspoint.com/go/go_select_statement.htm
package main
import "fmt"
func main() {
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
}
There was no explanation about channels at this point. Now I have no idea, how to trigger another output as "no communication".
Can anyone give me an example for each case?
The select statement chooses a case whose communication op would not block. If there are multiple cases whose comm. op would not block, one is chosen randomly.
Since in the example all communication ops would block, and since a default is provided, that will be executed.
To "trigger" another case, you have to make sure its comm. op does not block. In the example no one is sending or receiving anything from any of the channels that are used in the cases. Hell, they are not even initialized. And both sending to and receiving from a nil channel blocks forever (for details see How does a non initialized channel behave?). So you should do that: initialize a channel and send to / receive from it, the one whose case you want to trigger. For example:
c1 = make(chan int, 1)
c1 <- 1
This snippet initializes the c1 channel with a buffer of 1, and sends a value on it. So in the select statement after this the communication operation i1 = <-c1 would not block, so this will be chosen, and the output will be:
received 1 from c1
Try it on the Go Playground. (Note: I changed all Printf() calls to Println().)
Note that sending on / receiving from channels could happen concurrently, on other goroutines. I chose a buffered channel and the same goroutine for simplicity, and so that it behaves as you'd expect it even on the Go Playground.
More about channels: What are golang channels used for?
Related
I was working on OVM driver sequencer communication. I am using try_get_item() in ovm driver but it is still getting stuck. In my sequencer I redefined try_next_item and just printed a display statement before and after m_req_fifo.peek(t); The statement before peek got executed but not the statement after the peek. I even displayed size of the m_req_fifo using m_req_fifo.size() and it printed out 1. Why is peek not returning anything even after the size is 1? The modified try_next_item (Just addition of display) is given below.
The line After PEEK never gets executed after the line Line 398 with fifo size 1
virtual task try_next_item(output REQ t);
int selected_sequence;
time arb_time;
ovm_sequence_base seq;
if (get_next_item_called == 1) begin
ovm_report_error(get_full_name(), "get_next_item/try_next_item called twice without item_done or get in between", OVM_NONE);
return;
end
wait_for_sequences();
selected_sequence = choose_next_request();
if (selected_sequence == -1) begin
t = null;
return;
end
set_arbitration_completed(arb_sequence_q[selected_sequence].request_id);
seq = arb_sequence_q[selected_sequence].sequence_ptr;
arb_sequence_q.delete(selected_sequence);
m_update_lists();
sequence_item_requested = 1;
get_next_item_called = 1;
$display("Line 398 with fifo size %0d\n", m_req_fifo.size());
m_req_fifo.peek(t);
$display("After PEEK\n");
wait_for_sequences();
// attempt to get the item; if it fails, produce an error and return
if (!m_req_fifo.try_peek(t))
ovm_report_error("TRY_NEXT_BLOCKED", {"try_next_item: the selected sequence '",
seq.get_full_name(), "' did not produce an item during wait_for_sequences(). ",
"Sequences should not consume time between calls to start_item and finish_item. ",
"Returning null item."}, OVM_NONE);
endtask
uvm_tlm_fifo::size() doesn't return the number of elements in the FIFO, but its capacity (i.e. the maximum number of elements it can hold). The function you're looking for is uvm_tlm_fifo::used() which returns the number of stored elements.
The function names are not intuitive at all and I remember spending a couple of hourse trying to understand some similar code to the one you had until noticing in the documentation that I was using the wrong method.
The goal is to create a mechanism to automatically catch unqiue case violations and have them reported to the test-bench for error counting during simulation. The log files can be huge making post processing less practical. Manually creating assertions is error prone (especially when then one-hot condition is not a continuous bus like the code below) and and a never ending assignment while the design is in development.
always_comb begin
unique case(1'b1)
a[3] : b = 4'h3;
a[2] : b = 4'h2;
c[10] : b = 4'hE;
c[8] : b = 4'h4;
endcase
end
I can enable/disable the reporting for unique case violations with $assertcontrol, therefore I believe it is possible to use VPI callback, but I'm having trouble using vpi_iterate() to find the unique case, currently I'm slowly traversing the design trying to figure out when to pass what kind of object my vpiHandle is pointing to. I tried vpi_iterate(vpiCallback, NULL), but my simulator returns a a massage stating vpiCallback has not been implemented yet.
The simulator is reporting unique case violations to the log file. So how can I get my test-bench to detect it?
I don't have the full answer yet, but here's something to get you started. I added your always_comb block to a module:
module some_module();
logic [3:0] a;
logic [3:0] b;
logic [8:0] c;
always_comb begin : always_comb_proc
unique case(1'b1)
a[3] : b = 4'h3;
a[2] : b = 4'h2;
c[10] : b = 4'hE;
c[8] : b = 4'h4;
endcase
end
initial begin
$add_cbs();
end
endmodule
I created a VPI system task that can find the handle to the unique case. It's just a matter of traversing the hierarchy:
void add_cbs_calltf() {
// getting the module could be more elegant
vpiHandle mod = vpi_handle_by_name("some_module", NULL);
// there's only one process - the 'always_comb'
vpiHandle proc_it = vpi_iterate(vpiProcess, mod);
vpiHandle proc = vpi_scan(proc_it);
// each 'always' process has an event control
// - for 'always_comb', this is implicit
vpiHandle ev_ctrl = vpi_handle(vpiStmt, proc);
// the event control contains the 'begin/end' statement
vpiHandle named_begin = vpi_handle(vpiStmt, ev_ctrl);
// finally, a 'begin/end' statement can contain other statements
// - the one and only in this case is the 'unique case'
vpiHandle stmt_it = vpi_iterate(vpiStmt, named_begin);
vpiHandle stmt = vpi_scan(stmt_it);
vpi_printf("stmt type = %s\n", vpi_get_str(vpiType, stmt));
vpi_printf("stmt case type = %d\n", vpi_get(vpiCaseType, stmt));
vpi_printf("stmt case qualifier = %d\n", vpi_get(vpiQualifier, stmt));
}
I still don't know how to add a callback when the "assertion" triggers, but this should be a step in the right direction. I'll probably look into it and update the answer.
I make three database calls (that all return Future values) using this syntax:
for {
a <- databaseCallA
b <- databaseCallB(a)
c <- databaseCallC(a)
} yield (a,b,c)
The second and third call depend on the result of the first, but the two of them could be run in parallel.
How can I get databaseCallC to be issued immediately after databaseCallB (without waiting for the result b)?
Or is this already happening?
This is not happening currently - you have told the Futures to start one after the other. To parallelise the second and third call, you could use this:
for {
a <- databaseCallA
(eventualB, eventualC) = (databaseCallB(a), databaseCallC(a))
b <- eventualB
c <- eventualC
} yield(a,b,c)
This will start both the computation of b and c as soon as a is available, and complete once all three are available with the triple
package main
import (
"crypto/md5"
"fmt"
)
func main() {
hash := md5.New()
b := []byte("test")
fmt.Printf("%x\n", hash.Sum(b))
hash.Write(b)
fmt.Printf("%x\n", hash.Sum(nil))
}
Output:
*md5.digest74657374d41d8cd98f00b204e9800998ecf8427e
098f6bcd4621d373cade4e832627b4f6
Could someone please explain to me why/how do I get different result for the two print ?
I'm building up on the already good answers. I'm not sure if Sum is actually the function you want. From the hash.Hash documentation:
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
Sum(b []byte) []byte
This function has a dual use-case, which you seem to mix in an unfortunate way. The use-cases are:
Computing the hash of a single run
Chaining the output of several runs
In case you simply want to compute the hash of something, either use md5.Sum(data) or
digest := md5.New()
digest.Write(data)
hash := digest.Sum(nil)
This code will, according to the excerpt of the documentation above, append the checksum of data to nil, resulting in the checksum of data.
If you want to chain several blocks of hashes, the second use-case of hash.Sum, you can do it like this:
hashed := make([]byte, 0)
for hasData {
digest.Write(data)
hashed = digest.Sum(hashed)
}
This will append each iteration's hash to the already computed hashes. Probably not what you want.
So, now you should be able to see why your code is failing. If not, take this commented version of your code (On play):
hash := md5.New()
b := []byte("test")
fmt.Printf("%x\n", hash.Sum(b)) // gives 74657374<hash> (74657374 = "test")
fmt.Printf("%x\n", hash.Sum([]byte("AAA"))) // gives 414141<hash> (41 = 'A')
fmt.Printf("%x\n", hash.Sum(nil)) // gives <hash> as append(nil, hash) == hash
fmt.Printf("%x\n", hash.Sum(b)) // gives 74657374<hash> (74657374 = "test")
fmt.Printf("%x\n", hash.Sum([]byte("AAA"))) // gives 414141<hash> (41 = 'A')
hash.Write(b)
fmt.Printf("%x\n", hash.Sum(nil)) // gives a completely different hash since internal bytes changed due to Write()
You have 2 ways to actually get a md5.Sum of a byte slice :
func main() {
hash := md5.New()
b := []byte("test")
hash.Write(b)
fmt.Printf("way one : %x\n", hash.Sum(nil))
fmt.Printf("way two : %x\n", md5.Sum(b))
}
According to http://golang.org/src/pkg/crypto/md5/md5.go#L88, your hash.Sum(b) is like calling append(b, actual-hash-of-an-empty-md5-hash).
The definition of Sum :
func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := *d0
hash := d.checkSum()
return append(in, hash[:]...)
}
When you call Sum(nil) it returns d.checkSum() directly as a byte slice, however if you call Sum([]byte) it appends d.checkSum() to your input.
From the docs:
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
Sum(b []byte) []byte
so "*74657374*d41d8cd98f00b204e9800998ecf8427e" is actually a hex representation of "test", plus the initial state of the hash.
fmt.Printf("%x", []byte{"test"})
will result in... "74657374"!
So basically hash.Sum(b) is not doing what you think it does. The second statement is the right hash.
I would like to tell you to the point:
why/how do I get different result for the two print ?
Ans:
hash := md5.New()
As you are creating a new instance of md5 hash once you call hash.Sum(b) it actually md5 hash for b as hash itself is empty, hence you got 74657374d41d8cd98f00b204e9800998ecf8427e as output.
Now in next statement hash.Write(b) you are writing b to the hash instance then calling hash.Sum(nil) it will calculate md5 for b that you just written and sum it to previous value i.e 74657374d41d8cd98f00b204e9800998ecf8427e
This is the reason you are getting these outputs.
For your reference look at the Sum API:
func (d0 *digest) Sum(in []byte) []byte {
85 // Make a copy of d0 so that caller can keep writing and summing.
86 d := *d0
87 hash := d.checkSum()
88 return append(in, hash[:]...)
89 }
Considering the following example (a simple 8-bit counter), is there a simpler way to connect the internal s_count signal to the o_count port?
def counter(i_clk, i_reset, o_count):
""" A free-running 8-bit counter with a synchronous reset """
s_count = Signal(intbv(0)[8:])
#always(i_clk.posedge)
def count():
if i_reset == 1:
s_count.next = 0
else:
s_count.next = s_count + 1
#always_comb
def outputs():
o_count.next = s_count
return count, outputs
Of course, I could directly increment o_count in the count function but this translates to an inout port in the generated VHDL module, which I don't want.
I suspect directly incrementing o_count is an acceptable solution.
Indeed, it translates to an inout because you cannot read output ports in VHDL.
However, this will only happen when you convert this module as a top module. It is likely that this is a small submodule however. In that case, the hierarchy is flattened out and o_count will be an internal signal.