• 検索結果がありません。

SystemC 2.0を用いた簡易CPUバスモデルの設計

N/A
N/A
Protected

Academic year: 2021

シェア "SystemC 2.0を用いた簡易CPUバスモデルの設計"

Copied!
22
0
0

読み込み中.... (全文を見る)

全文

(1)

SystemC

SystemC

2.0

2.0

を用いた

を用いた

簡易

簡易

CPU

CPU

バスモデルの設計

バスモデルの設計

富士ゼロックス株式会社

ドキュメント プロダクト カンパニー

CTD&SW開発統括部

CT-PF第二開発部

宮下 晴信

(2)

目次

目次

†

簡易CPUバスモデルについて

†

システム構成

†

BCAモデルとUTFモデル

†

GenericCPUモデル

†

IOモデル

†

トップテストベンチ(sc_main)

†

波形表示

†

応用例

†

まとめ

(3)

簡易

簡易

CPU

CPU

バスモデルについて

バスモデルについて

CQ

CQ

出版社のインターフェース、

出版社のインターフェース、

1997

1997

11

11

月号、

月号、

Page 207

Page 207

」の

システムオンチップ時代のスケーラブル設計手法、川北浩孝、

第4回、各種設計ノウハウ

「PerlとVerilog-HDLによる簡易CPUバスシステム記述手法、

原山みや/川北浩孝」

のVerilog-HDLで記述されたものをベースにSystemC 2.0に書き換えたもの

付属のアッセンブラ(asm)およびROMイメージファイル(test.hex)はそのまま使います

(4)

システム構成

システム構成

内部メモリ

load

store

内部ROM

ROMイメージファイル

asm

アセンブラファイル

シミュレーションが開始されたら、

ROMイメージファイルを

内部ROMにロードする

GenericCPU

CLK

nRST

init

reset

fetch

decode

execute

dump

load

store

IO

Top TestBench

(5)

BCA

BCA

モデルと

モデルと

UTF

UTF

モデル

モデル

BCA

UTF

GenericCPU

IO

GenericCPU

IO

CLK

Addr

nCS

nOE

Ready

Data

nWE

Data

ストア

ロード

CLK

ストア

ロード

Addr

Data

Addr

Data

バスサイクルとして、動作する

時間概念がないので、クロックは無い

必要な時間は、7CLK

必要な時間は、“0“

(6)

GenericCPU

GenericCPU

モデル

モデル

1)、初期化

( init )

2)、リセット

( reset )

3)、メイン( clock_posedge )

フェッチ

( fetch )

デコード

( decode )

実行

( execute )

ロード

( load )

ストア

( store )

4)、ダンプ

( dumpreg )

内部ROM

ROMイメージファイル

asm

アセンブラファイル

シミュレーションが開始されたら、

ROMイメージファイルを

内部ROMにロードする

GenericCPU

init

reset

fetch

decode

execute

dump

load

store

(7)

ソースコード

ソースコード

(GenericCPU

(

GenericCPU

.hpp

.

hppの共通部

の共通部

)

)

#include <string>

#include "systemc.h"

class GenericCPU : public sc_module { private :

static const int MEM_SIZE = 1024; string hex_file;

bool dump;

int memory[MEM_SIZE]; int Reg[8];

int pc, eq, lt, gt; int code, r0, r1, imm; void init( void );

void reset( void ); int fetch( int p );

void decode( int decode ); void execute( void ); void dumpreg( void );

void load( int addr, int& data ); void store( int addr, int data );

int readmem( const char *file, int *mem, int size ); int analyze_buffer( char *buffer, int *val);

void clock_posedge( void ); public :

SC_HAS_PROCESS(GenericCPU); GenericCPU(sc_module_name name,

char *_hex_file = "test.hex", bool _dump = true)

: sc_module(name), hex_file(_hex_file), dump(_dump) {

SC_CTHREAD(clock_posedge, CLK.pos()); watching(nRST.delayed() == false);

init(); }

(8)

ソースコード

ソースコード

(GenericCPU

(

GenericCPU

.

.

hppのポート定義部

hpp

のポート定義部

)

)

BCA

private :

static const bool LOGIC_0 = false; static const bool LOGIC_1 = true; static const char *const HiZ_32 =

"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; inline void high_cs( void ){ nCS = LOGIC_1; } inline void low_cs( void ) { nCS = LOGIC_0; } inline void high_oe( void ){ nOE = LOGIC_1; } inline void low_oe( void ) { nOE = LOGIC_0; } inline void high_we( void ){ nWE = LOGIC_1; } inline void low_we( void ) { nWE = LOGIC_0; } inline void hiz_a( void ) { A = HiZ_32; } inline void set_a( const int val ){ A = val; } inline void hiz_d( void ) { D = HiZ_32; } inline void set_d( const int val ){ D = val; }

inline int get_d( void ) { sc_uint<32> sig; sig = D; return((int)sig); } public : sc_out_rv<32> A; sc_inout_rv<32> D; sc_out<bool> nCS; sc_out<bool> nOE; sc_out<bool> nWE; sc_in<bool> READY;

UTF

#include “sc_mslib.h” // sc_inoutmasterを使うので必要

private :

public :

(9)

ソースコード

ソースコード

(GenericCPU

(

GenericCPU

.cpp

.

cpp

の共通部

の共通部

:

:

その1

その1

)

)

void GenericCPU::init( void )

{

if( readmem( hex_file.c_str(), memory, MEM_SIZE ) ) exit(1);

}

void GenericCPU::clock_posedge( void ) {

if( nRST.read() == false ) /* Reset */ reset(); while(true) { wait(); decode( fetch(pc) ); execute(); if( dump ) dumpreg(); } }

int GenericCPU::fetch( int p ) {

return memory[p]; }

void GenericCPU::decode( int decode ) {

code = (decode >> 24) & 0x000000ff; r0 = (decode >> 20) & 0x0000000f; r1 = (decode >> 16) & 0x0000000f; imm = decode & 0x0000ffff;

printf("PC = %08x CODE = 0x%02x R0 = %d R1 = %d IMM = 0x%04x¥n",

pc, code, r0, r1, imm ); }

void GenericCPU::dumpreg( void ) {

inti, tmp;

printf( "Register Contents¥t¥t¥t¥tROM Contents¥n" );

for( i=0 ; i<8 ; i=i+1 ) { tmp = i+pc-3; tmp = tmp < 0 ? 0 : tmp; printf("Reg[ %d] : %08x¥t¥tROM[%08x]=%08x¥n", i, Reg[i], tmp, memory[tmp] ) ; }

(10)

ソースコード

ソースコード

(GenericCPU

(

GenericCPU

.cpp

.

cpp

の共通部:その2

共通部:その2

)

)

void GenericCPU::execute( void )

{

int jmp = 1;

switch(code) {

case CPU_ADD : Reg[r0] = Reg[r0] + Reg[r1]; break;

case CPU_SUB : Reg[r0] = Reg[r0] - Reg[r1]; break;

case CPU_MOV : Reg[r0] = Reg[r1]; break;

case CPU_SETHI :

Reg[r0] = ( MASK_HI(imm<<16) | MASK_LO(Reg[r0]) ); break;

case CPU_SETLO :

Reg[r0] = ( MASK_HI(Reg[r0]) | MASK_LO(imm) ); break;

case CPU_CMP :

if( Reg[r0] == Reg[r1] ) eq = 1, gt = 0, lt = 0; else if( Reg[r0] > Reg[r1] ) eq = 0, gt = 1, lt = 0; else if( Reg[r0] < Reg[r1] ) eq = 0, gt = 0, lt = 1; break;

case CPU_JMP : jmp = SET_JUMP(imm); break;

case CPU_JEQ : if( eq ) jmp = SET_JUMP(imm); break;

case CPU_JGT : if( gt ) jmp = SET_JUMP(imm); break;

case CPU_JLT : if( lt ) jmp = SET_JUMP(imm); break;

case CPU_LOAD : load(Reg[r0], Reg[r1]); break;

case CPU_STORE : store(Reg[r0], Reg[r1]); break;

case CPU_HALT : printf("Generic CPU Model : halt¥n"); sc_stop(); break;

case CPU_FINISH : printf("Generic CPU Model : exit at %f¥n", sc_simulation_time());

exit(0); break;

default : printf("ERROR : Generic CPU Model does not support Code 0x%02x¥n", code); break; } Reg[0] = 0; pc = pc + jmp; }

(11)

ソースコード

ソースコード

(GenericCPU

(

GenericCPU

.cpp

.

cpp

のリセット部

のリセット部

)

)

BCA

void GenericCPU::reset( void ) {

high_cs();

high_oe();

high_we();

hiz_a();

hiz_d();

// 内部変数の初期化

for(int i=0 ; i<8 ; i++) Reg[i] = 0;

pc = 0; eq = 0; lt = 0; gt = 0; code = 0; r0 = 0; r1 = 0; imm = 0;

}

UTF

void GenericCPU::reset( void ) {

// BCAのように信号の初期化は無い

// 内部変数の初期化

for(int i=0 ; i<8 ; i++) Reg[i] = 0;

pc = 0; eq = 0; lt = 0; gt = 0; code = 0; r0 = 0; r1 = 0; imm = 0; }

(12)

ソースコード

ソースコード

(GenericCPU

(

GenericCPU

.cpp

.

cpp

のロード部

のロード部

)

)

BCA

void GenericCPU::load( int addr, int &data ) {

set_a(addr);

wait(); low_cs();

wait(); low_oe();

while(true) {

wait();

if( READY.read() == LOGIC_1 ) {

data = get_d(); // データのリード

break;

}

}

wait(); high_oe(); high_cs();

wait(); hiz_a();

}

UTF

void GenericCPU::load( int addr, int &data ) {

data = MP[addr]; // データのリード

(13)

ソースコード

ソースコード

(GenericCPU

(

GenericCPU

.cpp

.

cpp

のストア部

のストア部

)

)

BCA

void GenericCPU::store( int addr, int data ) {

set_d(data); // データのライト

set_a(addr);

wait(); low_cs();

wait(); low_we();

while(true) {

wait();

if( READY.read() == LOGIC_1 ) {

high_we();

break;

}

}

wait(); hiz_d();

high_cs();

wait(); hiz_a();

}

UTF

void GenericCPU::store( int addr, int data ) {

MP[addr] = data; // データのライト

(14)

IO

IO

モデル

モデル

†

GenericCPUからのリード/ライトアクセスを受ける

†

内部構造は、メモリになっている

IO

内部メモリ(mem)

(15)

ソースコード

ソースコード

(BCA

(

BCA:

IO.hpp

IO.

hpp

)

)

#include "systemc.h"

SC_MODULE(IO) { private :

static const int MEM_SIZE = 1024; int memory[MEM_SIZE];

void clock_posedge( void ); public :

sc_in_clk

CLK;

sc_in<bool>

nRST;

sc_in_rv<32>

A;

sc_inout_rv<32> D;

sc_in<bool>

nCS;

sc_in<bool>

nOE;

sc_in<bool>

nWE;

sc_out<bool>

READY;

SC_CTOR(IO) {

SC_CTHREAD(clock_posedge, CLK.pos());

watching(nRST.delayed() == false);

} };

void IO::clock_posedge( void ) {

if( nRST.read() == false ) {/* Reset */ READY = false;

D = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; }

while(true) {

wait_until( nCS.delayed() == false); wait(); /* Clock */

if( nOE.read() == false ) { /* Read */ sc_uint<32> sig_a;

sig_a = A.read(); D.write(memory[sig_a]); }

wait(); /* Clock */

if( nWE.read() == false ) { /* Write */ sc_uint<32> sig_a, sig_d; sig_a = A.read(); sig_d = D.read(); memory[sig_a] = sig_d; } READY.write(true); do { wait(); /* Clock */ READY.write(false); }

while ( nCS.read() == false );

D.write("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); }

(16)

ソースコード

ソースコード

(UTF

(

UTF:

IO.hpp

IO.

hpp)

)

#include "systemc.h"

#include “sc_mslib.h” // sc_inoutslaveを使うので必要 SC_MODULE(IO) {

private:

static const int MEM_SIZE = 1024; int memory[MEM_SIZE];

void io_access( void ); public:

// クロックとリセットが無い

sc_inoutslave<int, sc_indexed<int,1024> > SP;

SC_CTOR(IO) {

SC_SLAVE(io_access, SP);

} };

void IO::io_access( void ) {

int addr = SP.get_address();

if( SP.input() )

// Write

memory[addr] = SP;

else

// Read

SP = memory[addr];

(17)

トップテストベンチ

トップテストベンチ

(

(

sc_main

sc_main

)

)

GenericCPU

IO

CLK

nRST

sc_main

sc_signal<bool> nRST;

sc_clock CLK("CLK", 20, SC_NS, 0.5, 0.0, SC_NS, true);

GenericCPU cpu("GenericCPU", file, dump);

IO io("IO");

GenericCPUとIO間接続の

(18)

ソースコード

ソースコード

(BCA

(

BCA:

main.

main.

cpp)

cpp

)

#include "systemc.h"

#include "GenericCPU.hpp" #include "IO.hpp"

int sc_main(int argc, char *argv[]) { sc_signal<bool> nRST; sc_signal<bool> READY; sc_signal_rv<32> A; sc_signal_rv<32> D; sc_signal<bool> nCS; sc_signal<bool> nOE; sc_signal<bool> nWE; // クロックの宣言 sc_clock CLK("CLK", 20, SC_NS, 0.5, 0.0, SC_NS, true); // GenericCPUの宣言とポート名の割り当て

GenericCPU cpu("GenericCPU", file, dump);

cpu.CLK(CLK);

cpu.nRST(nRST);

cpu.A(A);

cpu.D(D);

cpu.nCS(nCS);

cpu.nOE(nOE);

cpu.nWE(nWE);

cpu.READY(READY);

// IOの宣言とポート名の割り当て IO io("IO");

io.CLK(CLK);

io.nRST(nRST);

io.A(A);

io.D(D);

io.nCS(nCS);

io.nOE(nOE);

io.nWE(nWE);

io.READY(READY);

// スケジューラを起動し、クロックとリセットを生成する nRST = false; sc_start(40, SC_NS); nRST = true; sc_start(-1);

return 0; /* this is necessary */ }

(19)

ソースコード

ソースコード

(UTF

(

UTF:

main.

main.

cpp)

cpp

)

#include "systemc.h"

#include "GenericCPU.hpp" #include "IO.hpp"

int sc_main(int argc, char *argv[]) { sc_signal<bool> nRST;

sc_link_mp<int>

PORT;

// クロックの宣言 sc_clock CLK("CLK", 20, SC_NS, 0.5, 0.0, SC_NS, true); // GenericCPUの宣言とポート名の割り当て

GenericCPU cpu("GenericCPU", file, dump);

cpu.CLK(CLK);

cpu.nRST(nRST);

cpu.MP(PORT);

// IOの宣言とポート名の割り当て IO io("IO");

// クロックとリセットが無い

io.SP(PORT);

// スケジューラを起動し、クロックとリセットを生成する nRST = false; sc_start(40, SC_NS); nRST = true; sc_start(-1);

return 0; /* this is necessary */ }

(20)

波形表示

波形表示

†

フリーのもの (VCDフォーマット)

‹

WaveViewer

http://www.syncad.com/

‹

GtkWave(Unix)

http://daggit.pagecreator.com/ver/wave/

‹

GtkWave(Win32)

http://www.geocities.com:0080/SiliconValley/

Campus/3216/GTKWave/gtkwave-win32.html

‹

Dinotrace

http://www.ultranet.com/~wsnyder/veripool/dinotrace/

†

各シミュレータに付属している波形Viewer

sc_trace_file *trace_file = sc_create_vcd_trace_file("GenericCPU");

sc_trace(trace_file, CLK, "CLK");

(21)

応用例

応用例

†

Behavior/Interface/Channel

GenericCPU

Core

(Behavior)

Channel

I/F

IO

Core

(Function)

I/F

†

Inheritance(継承)

Interface

GenericCPU

Core

コア部分を基底クラスとし、インター

フェース部分を派生クラスとして実装

する

(22)

まとめ

まとめ

†

SystemC 2.0の良いところ

‹

フリーなツールである(PC/Linux、Sun/Solaris、PC/Windowsで動作する)

‹

C++を知っていれば、ある程度使いこなせる

‹

継承が使える(モデルをオブジェクト化し、再利用できる)

‹

抽象度にあったモデリングができる

Î

Behavior/Interface/Channel を使えば、いろいろな抽象度のモデルが容易

にできる

†

SystemC 2.0の悪いところ

‹

ツールとして、まだ枯れていない(Bugが多い)

‹

利用可能なツールが少ない(市販、フリー共に)

‹

利用可能なモデルが少ない(市販、フリー共に)

‹

参考資料(入門書やノウハウ)が少ない。特に日本語!

‹

PC/Windowsでは、市販のC++コンパイラが必要である

参照

関連したドキュメント

Central Data Center vRAN (Group Center) Regional Data Center. Mobile Edge Computing NW Core

REC DATA MASTER L to SD CARD REC DATA MASTER R to SD CARD VOLUME SOUND

Data are thus submitted to exploratory data analysis, to recover as much synthesized information as possible, in order to reveal any existing data structure and, in particular, to

図 3.1 に RX63N に搭載されている RSPI と簡易 SPI の仕様差から、推奨する SPI

パスワード 設定変更時にパスワードを要求するよう設定する 設定なし 電波時計 電波受信ユニットを取り外したときの動作を設定する 通常

Governmental Accounting affairs Data Communication Management

S ADDR Input Selects device address for the two−wire slave serial interface.. When connected to GND, the device ID

ADDMULSUB Add two XY data registers, multiply the result by a third XY data register, and subtract the result from an accumulator ADDSH Add two data registers or accumulators and