0
\$\begingroup\$

I created a module that first sorts a byte array then choose last element as minimum.(just for practice). When I moved sort to the task block, it doesn't worked as well as before. How can use task block properly for sorting ? thanks.

Sort without task:

 module sort(input clk, input nrst, output byte choose);
 byte sorted[0:3];
 assign choose = sorted[3];// output must be minimum after sort (12)
 always@(posedge clk, negedge nrst) begin 
 if(nrst == 0) begin // initialize to something
 sorted[0] = 17;
 sorted[1] = 12;
 sorted[2] = 23;
 sorted[3] = 21;
 end 
 else begin 
 int i, j; 
 byte tmp; 
 //sort 
 for(i=0; i<4; i=i+1) 
 for(j=0; j<4; j=j+1)
 if(sorted[j] < sorted[j+1]) begin
 tmp = sorted[j]; // swap
 sorted[j] = sorted[j+1];
 sorted[j+1] = tmp;
 end 
 end 
 end
endmodule

Sort with Task:

module sort(input clk, input nrst, output byte choose);
 byte sorted[0:3];
 assign choose = sorted[3];// output must be minimum after sort (12)
 always@(posedge clk, negedge nrst) begin 
 if(nrst == 0) begin // initialize to something
 sorted[0] = 17;
 sorted[1] = 12;
 sorted[2] = 23;
 sorted[3] = 21;
 end 
 else begin 
 sort_task(sorted); 
 end 
 end
 task sort_task(inout byte list[3:0]);
 begin 
 int i, j; 
 byte tmp; 
 //sort 
 for(i=0; i<4; i=i+1) 
 for(j=0; j<4; j=j+1)
 if(list[j] < list[j+1]) begin
 tmp = list[j];
 list[j] = list[j+1];
 list[j+1] = tmp;
 end 
 end
 endtask
endmodule

Testbench:

module tb();
 byte choose;
 reg nrst, clk;
 sort sort(clk, nrst, choose);
 initial begin 
 clk = 0; 
 forever #5 clk = ~clk; 
 end 
 initial begin 
 int i;
 nrst = 1;
 #50;
 for(i=0; i<4; i=i+1) 
 $display("50 : %d", sort.sorted[i]);
 nrst = 0; 
 #50
 for(i=0; i<4; i=i+1) 
 $display("100 : %d", sort.sorted[i]); 
 nrst = 1; 
 #50 
 for(i=0; i<4; i=i+1) 
 $display("150: %d", sort.sorted[i]); 
 end
endmodule
asked Mar 16, 2016 at 13:56
\$\endgroup\$
2
  • \$\begingroup\$ Task are normally reserved for testbenches and not synthesisable code. should it not return a value rather than use inouts? maybe a function is what you were wanting, except functions have to execute in zero time. \$\endgroup\$ Commented Mar 16, 2016 at 14:16
  • \$\begingroup\$ When I declare a function with return type of byte [0:3](for sorted list), Modelsim give error 'can't assign unpacked...'. I didn't know how to return a list of bytes from a function, so I preferred using task. I think tasks are synthesisable as well as functions. \$\endgroup\$ Commented Mar 16, 2016 at 14:39

1 Answer 1

1
\$\begingroup\$

The problem is there is a mismatch in the index declaration for sorted[0:3] versus list[3:0], so (list[j] < list[j+1]) gives you the reverse evaluation. I strongly recommend using common typedef's (in a package) to eliminate problems like this.

typedef byte list_t[4];
list_t sorted;
task sort_task( inout list_t list);

BTW, using a typedef gives you the syntax needed to declare a function with unpacked return type because any simple name is allowed for a return type, no matter how complex the typedef is.

Also, I agree with you that a task is synthesizable, as long as the code inside the task is meets your tools synthesis modelling style. But I would prefer that people use a void function instead of a task when their task has no time consuming statements. A function is a guarantee that it will not consume time.

answered Mar 16, 2016 at 15:30
\$\endgroup\$
3
  • \$\begingroup\$ This is being assigned as synchronous logic, therefore non-blocking assignments (<=) is recommended. Blocking assignments should be used inside method to keep it portable and self-contained. I'd suggest the method header be function list_t sort_func( input list_t list); which returns the sorted list, and then you can assign the array as sorted <= sort_func(shorted);. \$\endgroup\$ Commented Mar 16, 2016 at 16:47
  • \$\begingroup\$ Thank you for your professional guidance. I was involved in this question that how can return a list from a function. Using typedef solved it. But I don’t understand why function is better the task. I think in compile time, inner codes of the both blocks will move to the place that they called. \$\endgroup\$ Commented Mar 16, 2016 at 17:31
  • \$\begingroup\$ You will appreciate the guideline better when you start having nested calls to tasks and functions - especially when you start writing testbenches that have nested calls. Calling a function documents your intent that the call will not block, as well as any other nested call. The problem with using nested task calls is when a task deep inside your call stack has a modification that blocks - it will be very difficult to debug. Verilog did not have void functions - they always had to be used in an expression. That's why you see lots of non-time-consuming tasks. \$\endgroup\$ Commented Mar 16, 2016 at 20:52

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.