Although this works as per intention, both of us are now looking for a possible solution using purely constraints ( w/o using helper variable ) for practice purposes
You can use pre_randomize() to calculate the position of the MSB from the previous value.
class A;
rand bit[3:0] req;
bit [3:0] prev_req;
int msb;
constraint c {
req != '0; // must be non-zero
msb < 3 -> {
req > prev_req;
req[msb] == '1; // msb of previous value must be set
}
// attempt at a "better" distribution of values
1 dist { req==4'b0001 := 1, req[3:1]==3'b001 :=1, req[3:2]== 2'b01 :=1 , req[3]==1'b1 :=1 };
}
function void pre_randomize();
// req must never be 0
if (req==0) req = '1;
for (int i = $bits(req)-1; i >= 0; i--)
if (req[i]) begin
msb = i;
break;
end
prev_req = req;
endfunction
endclass
module top;
A h = new;
initial repeat(20) begin
assert(h.randomize());
$display("%b %d", h.req, h.msb);
end
endmodule
Actually, I started my solution without using any helper variables, and found it less desirable. You can compare the two approaches to decide which one is more manageable for yourself
class A;
rand bit[3:0] req;
constraint c {
req != '0; // must be non-zero
fmsb(const'(req)) < 3 -> {
req > const'(req);
req[fmsb(const'(req))] == '1; // msb of previous value must be set
}
// attempt at a "better" distribution of values
1 dist { req==4'b0001 := 1, req[3:1]==3'b001 :=1, req[3:2]== 2'b01 :=1 , req[3]==1'b1 :=1 };
}
function void pre_randomize();
// req must never be 0
if (req==0) req = '1;
endfunction
function int fmsb(type(req) x);
// assume x is never 0
for (int i = $bits(req)-1; i >= 0; i--)
if (x[i]) return i;
endfunction
endclass
module top;
A h = new;
initial repeat(20) begin
assert(h.randomize());
$display("%b %d", h.req, h.fmsb(h.req));
end
endmodule