SystemC SCVによるランダム生成
メモ書き。
メモ書き。
基本的なランダム生成
もっとも簡単なランダム生成
- 例:範囲0〜10の整数をランダム生成
// int型のランダム変数data_pを用意
scv_smart_ptr<int> data_p( "data" );
data_p->keep_only( 0, 10 ); // 0~10までをランダム生成とする設定
for (int i=0; i<10; i++) {
data_p->next(); // ランダムの更新(これを実行しないといつまでも同じ値のまま)
printf( "data = %d\n", data_p->read() ); // 値を取得
}
- 実行結果
data = 1
data = 10
data = 6
data = 8
data = 10
data = 2
data = 9
data = 3
data = 0
data = 7
配分ランダム生成
- 例:範囲を0〜2と99〜100の整数値をランダム生成
scv_random::set_global_seed(100); // ランダムのシードを100に設定
scv_smart<data_t> p( "p" );
p->keep_only( 0, 100 ); // 0~100をランダム生成する
p->keep_out( 3, 98); // 3〜98はランダム生成しない
for (int i=0; i<10; ++i) {
p->next();
printf( "data = %d\n", p.read() );
}
- 実行結果
data = 100
data = 2
data = 0
data = 1
data = 0
data = 0
data = 99
data = 99
data = 0
data = 100
重み付けランダム生成
- 例:0〜4の整数を出現率をかえてランダム生成
scv_random::set_global_seed(100);
scv_bag<int> dist;
dist.add( 0, 50 ); // 50%の割合で0を出現させる
dist.add( 1, 30 ); // 30%の割合で1を出現させる
dist.add( 2, 10 ); // 10%の割合で2を出現させる
dist.add( 3, 8 ); // 8%の割合で3を出現させる
dist.add( 4, 2 ); // 2%の割合で4を出現させる
scv_smart_ptr<int> p( "p" );
p->set_mode( dist ); //セット
int total = 0;
int cnt[5] = {0, 0, 0, 0, 0};
for (int i=0; i<10000; i++) {
int p_num;
p->next(); // 更新
p_num = p.read(); // ランダム値取得
if (0 <= p_num && p_num < 5) {
++cnt[p_num];
++total;
}
}
for (int i=0; i<5; i++) {
printf( "p=%d, [%4d / %5d]\n", i, cnt[i], total );
}
- 実行結果
p=0, [5051 / 10000]
p=1, [2949 / 10000]
p=2, [1038 / 10000]
p=3, [ 784 / 10000]
p=4, [ 178 / 10000]
distで設定されたおおよその出現率でpは出力されていることがわかる。
重み付けランダム生成(レンジ指定)
- 例:範囲をもった重み付け
scv_random::set_global_seed(100);
scv_bag< pair<int,int> > dist;
dist.add( pair<int,int>( 0, 3), 30 ); // 0〜3の値を30%の割合で出現させる
dist.add( pair<int,int>( 4,10), 50 ); // 4〜10の値を50%の割合で出現させる
dist.add( pair<int,int>(11,20), 15 ); // 11〜20の値を15%の割合で出現させる
dist.add( pair<int,int>(21,80), 5 ); // 21〜80の値を5%の割合で出現させる
scv_smart_ptr<int> p( "a" );
p->set_mode( dist );
int total = 0;
int cnt[5] = {0, 0, 0, 0, 0};
for (int i=0; i<10000; i++) {
int p_num;
p->next();
p_num = p.read();
if (0<=p_num && p_num<4) {
++cnt[0]; ++total;
}
else if (4<=p_num && p_num<11) {
++cnt[1]; ++total;
}
else if (11<=p_num && p_num<21) {
++cnt[2]; ++total;
}
else if (21<=p_num && p_num<81) {
++cnt[3]; ++total;
}
}
printf( "[ 0- 3], [%4d / %5d]\n", cnt[0], total );
printf( "[ 4-10], [%4d / %5d]\n", cnt[1], total );
printf( "[11-20], [%4d / %5d]\n", cnt[2], total );
printf( "[21-80], [%4d / %5d]\n", cnt[3], total );
- 実行結果
[ 0- 3], [3047 / 10000]
[ 4-10], [4942 / 10000]
[11-20], [1500 / 10000]
[21-80], [ 511 / 10000]
制限付きランダム生成(scv_constraint_baseの使用)
scv_constraint_baseを使うと、制約を1つのクラスにまとめることができるメリットがある。
このクラスは継承することも可能で、制約をより効率的に与えることができるようになる。
このクラスは継承することも可能で、制約をより効率的に与えることができるようになる。
- 例:0〜4または6〜10までの整数値をランダム生成
#include "scv.h"
struct data_const : public scv_constraint_base {
scv_smart_ptr<int> p;
SCV_CONSTRAINT_CTOR(data_const) {
SCV_CONSTRAINT( 0<=p() && p()<10 && p()!=5 ); // ランダム制約
}
};
int sc_main( int argc, char* argv[] )
{
scv_random::set_global_seed(100);
data_const data( "data" );
for (int i=0; i<20; i++) {
data.next(); // 更新
printf( "data = %d\n", data.p->read() ); // ランダム値取得
}
return 0;
}
- 実行結果
data = 7
data = 4
data = 1
data = 0
data = 2
data = 0
data = 6
data = 2
data = 4
data = 7
data = 9
data = 3
data = 9
data = 3
data = 4
data = 4
data = 8
data = 0
data = 6
data = 3
もう少し複雑なランダム生成
構造体を使ったランダム生成
- 例:ユーザ定義型中の変数をランダム値とする
#include "scv.h"
// 普通のユーザ定義型を準備
struct mydata_t {
sc_uint<16> dat;
unsigned char array[3];
};
// ユーザ定義型mydata_tに合わせて定義
SCV_EXTENSIONS( mydata_t )
{
public:
scv_extensions<sc_uint<16> > dat;
scv_extensions<unsigned char[3]> array;
SCV_EXTENSIONS_CTOR( mydata_t ) {
SCV_FIELD( dat );
SCV_FIELD( array );
}
};
int sc_main( int argc, char* argv[] )
{
scv_random::set_global_seed(100);
mydata_t d;
scv_smart_ptr<mydata_t> p;
p->dat.keep_only(0, 10 );
for (int i=0; i<10; i++) {
p->next(); // ランダム値更新
d = p->read(); // コピーできる
printf( "dat=%d, array=%d, %d, %d\n",
(int)d.dat, (int)d.array[0], (int)d.array[1], (int)d.array[2] );
}
return 0;
}
- 実行結果
dat=10, array=208, 22, 160
dat=0, array=181, 57, 245
dat=8, array=198, 104, 204
dat=4, array=17, 156, 53
dat=7, array=92, 87, 234
dat=4, array=89, 196, 161
dat=4, array=22, 28, 162
dat=6, array=186, 74, 152
dat=8, array=110, 209, 171
dat=8, array=152, 237, 205
(応用)構造体+条件付きランダム生成
- 例:
- ユーザ定義型packet_tを用意→ランダム生成指定
- ユーザ定義型を条件付き制約指定
- 制約を継承して、さらに条件付き制約指定
#include "scv.h"
// 通常のユーザ定義型を用意
struct packet_t {
sc_uint<32> src_addr;
sc_uint<32> dest_addr;
sc_uint<16> length;
};
//ユーザ定義型packet_tの拡張定義
template<>
class scv_extensions<packet_t> : public scv_extensions_base<packet_t>
{
public:
scv_extensions< sc_uint<32> > src_addr;
scv_extensions< sc_uint<32> > dest_addr;
scv_extensions< sc_uint<16> > length;
SCV_EXTENSIONS_CTOR(packet_t) {
SCV_FIELD(src_addr);
SCV_FIELD(dest_addr);
SCV_FIELD(length);
}
};
//ユーザ定義型packet_tに対する制約を設定
struct packet_base_constraint : public scv_constraint_base
{
scv_smart_ptr<packet_t> packet;
SCV_CONSTRAINT_CTOR(packet_base_constraint) {
// Soft Constraint
SCV_SOFT_CONSTRAINT( (packet->length > 64) && (packet->length < 1500) ); // Min & Max
// Hard Constraint
SCV_CONSTRAINT( packet->src_addr() != packet->dest_addr() );
SCV_CONSTRAINT( packet->length() > 20 );
}
};
// 制約packet_base_constraintを継承して新たな制約packet_constraintをつくる
struct packet_constraint : public packet_base_constraint
{
scv_smart_ptr< sc_uint<32> > dest_min;
scv_smart_ptr< sc_uint<32> > dest_max;
SCV_CONSTRAINT_CTOR(packet_constraint) {
// use the base constraint
SCV_BASE_CONSTRAINT(packet_base_constraint);
SCV_CONSTRAINT( (packet->dest_addr() > dest_min())
&& (packet->dest_addr() < dest_max()) );
SCV_CONSTRAINT(
((packet->src_addr() > (packet->dest_addr() + 0x100000) ) &&
(packet->src_addr() < (packet->dest_addr() + 0x200000) )) ||
((packet->src_addr() < (packet->dest_addr() - 0x10000) )) &&
(packet->src_addr() > (packet->dest_addr() - 0xfffff) ) );
SCV_CONSTRAINT( packet->length() == 64 );
}
};
int sc_main( int argc, char* argv[] )
{
scv_random::set_global_seed(100);
packet_t pkt;
packet_constraint pkt_c( "pkt_c" );
pkt_c.dest_min->disable_randomization();
pkt_c.dest_max->disable_randomization();
*pkt_c.dest_min = 0x100000;
*pkt_c.dest_max = 0x800000;
for (int i=0; i<10; i++) {
pkt_c.next();
pkt = pkt_c.packet->read();
printf( "src_addr = %08x\n", (int)pkt.src_addr );
printf( "dest_addr = %08x\n", (int)pkt.dest_addr );
printf( "length = %d\n", (int)pkt.length );
}
return 0;
}
- 実行結果
*** SCV_ERROR: CONSTRAINT_ERROR_OVER_CONSTRAINED at time 0 s in process <main>
Constraints for over-constrained object 'pkt_c' will be ignored.
src_addr = 008e6617
dest_addr = 00711f52
length = 64
src_addr = 00755da2
dest_addr = 005a4210
length = 64
src_addr = 0054ca51
dest_addr = 006187a8
length = 64
src_addr = 0065a389
dest_addr = 006fd55e
length = 64
src_addr = 0046ce02
dest_addr = 004889e1
length = 64
src_addr = 004a19e6
dest_addr = 0059637b
length = 64
src_addr = 00268b9a
dest_addr = 001069d1
length = 64
src_addr = 0045c242
dest_addr = 004d6c07
length = 64
src_addr = 004e95ef
dest_addr = 005d25a4
length = 64
src_addr = 0042bb4e
dest_addr = 00313678
length = 64
最初にエラーがでるけど、とりあえず気にしないでおく.
おそらく、Soft Constraintに関するエラーだと思われる.
おそらく、Soft Constraintに関するエラーだと思われる.
その他の使い方
ランダム生成の停止
- 例:出力を300に固定
scv_smart_ptr<int> p( "a" );
p->disable_randomization(); // ランダム生成を停止
p->write( 300 ); // pへ値300を書き込む
for (int i=0; i<10; i++) {
p->next(); // 更新
printf( "data = %d\n", p->read() ); // 値取得
}
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
ランダムの停止は、デバッグ時や直接代入したいときに利用できる.
分布の指定
分布の指定は4種類ある。
RAMDAM | 指定分布範囲での一様なランダム生成 |
SCAN | とりうる値で小さいものから大きいものへと生成 |
RANDOM_AVOID_DUPLICATE | 生成可能な数値が出尽くすまで同一の値を生成しない |
DISTRIBUTION | scv_bag<>で確率分布を指定 |
デフォルト設定では、
p->set_mode( RANDOM );
順列型ランダム生成(RANDOM_AVOID_DUPLICATE)
SystemVerilogのrandcのように順列型の乱数生成のようにできる。
- 例:0〜9までの順列型のランダム生成
scv_random::set_global_seed(100);
scv_smart_ptr<int> p;
p->keep_only(0, 9);
p->set_mode( scv_extensions_if::RANDOM_AVOID_DUPLICATE ); // 分布の指定
for (int i=0; i<2; i++) {
for (int j=0; j<10; j++) {
p->next();
printf( "%d\n", p->read() );
}
printf( "\n" );
}
- 実行結果
4
1
8
9
7
2
3
6
0
5
8
2
1
5
0
9
4
6
7
3
参照
- scv_smart_ptr<T>(実際に使う関数は_scv_extension_rand_N<T>を参照)
- scv_bag<T>