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
\$\endgroup\$
  • \$\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\$ – pre_randomize Mar 16 '16 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\$ – Soheil Shababi Mar 16 '16 at 14:39
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.

\$\endgroup\$
  • \$\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\$ – Greg Mar 16 '16 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\$ – Soheil Shababi Mar 16 '16 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\$ – dave_59 Mar 16 '16 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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