アセンブラを用いたシミュレーション


先のシミュレーション例では、実行する命令をクロック単位で入力する必要が ありました。この方法は、1命令毎に調べるには便利ですが、非常に手間がか かります。そこで、アセンブラの出力を用いて、プログラムを利用したシミュ レーションの方法を紹介します。

以下にプログラムの例を示します。再帰を用いた 1からnまでの加算を行います("testadd.asm")。


;
;	再帰を使用した加算プログラム
;
;lab.	mnemonic		comment	
	.text
_MAIN:	ld	#0x8
	swp
	or	#0x00		; sp = 0x800
	mv	sp, acc
	in	0		; input n
	push
	call	radd
	pop
	out			; result
	halt
;
radd:	mv	ixr, sp
	ld	ixr, 1
	push
	or	#0
	jpz	radd0
	dec	acc
	push
	call	radd
	pop
	mv	ixr, sp
	add	ixr, 0
radd0:	mv	ixr, sp
	st	ixr, 2
	pop			; dummy pop
	ret

	.data	0x100
ZERO:	.word	  0
D100:	.word	100

	.const	0xfff
	.word	_MAIN

このプログラムを、kiteasm を用いてリスティングファイルを作成します。
% kiteasm -l testadd

これにより、以下のリスティングファイルが生成されます("testadd.lst")。
000001			;
000002			;	再帰を使用した加算プログラム
000003			;
000004			;lab.	mnemonic		comment	
000005				.text
000006 0000 C108	_MAIN:	ld	#0x8
000007 0001 BC00		swp
000008 0002 9100		or	#0x00		; sp = 0x800
000009 0003 F004		mv	sp, acc
000010 0004 C800		in	0		; input n
000011 0005 D400		push
000012 0006 200A		call	radd
000013 0007 D000		pop
000014 0008 CC00		out			; result
000015 0009 F800		halt
000016			;
000017 000A F009	radd:	mv	ixr, sp
000018 000B C201		ld	ixr, 1
000019 000C D400		push
000020 000D 9100		or	#0
000021 000E 5015		jpz	radd0
000022 000F 8C00		dec	acc
000023 0010 D400		push
000024 0011 200A		call	radd
000025 0012 D000		pop
000026 0013 F009		mv	ixr, sp
000027 0014 8200		add	ixr, 0
000028 0015 F009	radd0:	mv	ixr, sp
000029 0016 C602		st	ixr, 2
000030 0017 D000		pop			; dummy pop
000031 0018 E000		ret
000032			
000033				.data	0x100
000034 0100 0000	ZERO:	.word	  0
000035 0101 0064	D100:	.word	100
000036			
000037				.const	0xfff
000038 0FFF 0000		.word	_MAIN

このリスティングファイルをを、lst2ram というプログラムを用いて、 Verilog シミュレータに使える形式のファイルフォーマットに変換します。
% lst2ram testadd.lst

これにより、"testadd.ram" という以下のようなファイルが出来上がります。 これは、kite プロセッサの 4096 ワードのメモリを初期化するために使用す るものです。
C108 // 0000 000006 0000 C108	_MAIN:	ld	#0x8
BC00 // 0001 000007 0001 BC00		swp
9100 // 0002 000008 0002 9100		or	#0x00		; sp = 0x800
F004 // 0003 000009 0003 F004		mv	sp, acc
C800 // 0004 000010 0004 C800		in	0		; input n
D400 // 0005 000011 0005 D400		push
	中略
0000 // 0ffd 
0000 // 0ffe 
0000 // 0fff 000038 0FFF 0000		.word	_MAIN

シミュレーションする際の "testfixture.new" ファイルとして以下の内容を使用します。
//
// CLOCK : 1MHz infinite loop
//
initial
begin
    CLOCK = 1'b1;
    while(1)
        CLOCK = #5000 ~CLOCK;
end

//
// I_A : 2MHz infinite loop
//
integer i1;
initial
begin
    I_A = 1'b1;
    while(1)
        I_A = #2500 ~I_A;
end

//
// Condition for Termination : IR = HALT and HALT = TRUE
//
always @( ACC_IR or HALT )
  if( ACC_IR == 16'hF800 && HALT == 1'b0 )
    #10000 $finish;

//
//  RESET, EXEC, CLKM, INSTM
//

initial
begin
    RESET = # 0 1;	//     0ns 
    RESET = # 15000 0;	//  1500 
    RESET = # 10000 1;	//  2500 
end

initial
begin
    EXEC = # 0 1;	//     0ns 
end

initial
begin
    CLKM = # 0 1;	//     0ns 
end

initial
begin
    INSTM = # 0 1;	//     0ns 
end


//
// Load instructions on Memory
//

reg [15:0] MEM[0:4095];	// Memory Image

initial
begin
	$readmemh("/user/staff/kuga/work/cadence/4bit/testadd.ram", MEM);
end

//
// Memory and I/O Transactions
//
initial
begin
    ACK  = # 0 1;	//     0ns 
end

always @( MREQ )
begin
  if ( MREQ == 1'b0 && RW == 1'b1 )
    begin
      io_DATA = MEM[ADDR];
      ACK     = 1'b0;
      $display("MEM Transaction READ  : ADDR=%x  DATA=%x", ADDR, MEM[ADDR]);
    end
  else if ( MREQ == 1'b1 && RW == 1'b1 )
    begin
      io_DATA = 16'hZZZZ;
      ACK     = 1'b1;
    end
  else if ( MREQ == 1'b0 && RW == 1'b0 )
    begin
      MEM[ADDR] = DATA[15:0];
      ACK     = 1'b0;
      $display("MEM Transaction WRITE : ADDR=%x  DATA=%x", ADDR, DATA);
    end
  else if ( MREQ == 1'b1 && RW == 1'b0 )
    begin
      ACK     = 1'b1;
    end
end

always @( IORQ )
begin
  if ( IORQ == 1'b0 && RW == 1'b1 )
    begin
      io_DATA = 16'h000a;				// Input Value
      ACK     = 1'b0;
      $display("I/O Transaction INPUT : ADDR=%x  DATA=%x", ADDR, io_DATA);
    end
  else if ( IORQ == 1'b1 && RW == 1'b1 )
    begin
      io_DATA = 16'hZZZZ;
      ACK     = 1'b1;
    end
  else if ( IORQ == 1'b0 && RW == 1'b0 )
    begin
      ACK     = 1'b0;
      $display("I/O Transaction OUT   : ADDR=%x  DATA=%x", ADDR, DATA);
    end
  else if ( IORQ == 1'b1 && RW == 1'b0 )
    begin
      ACK     = 1'b1;
    end
end

この Verilog ファイルは kite マイクロプロセッサのメモリおよび I/O をシ ミュレートします。また、この記述の中に、
	$readmemh("/user/staff/kuga/work/cadence/4bit/testadd.ram", MEM);

という行がありますが、 このファイルのパスは各自先に用意したプログラムの メモリイメージファイルに書換えて下さい(絶対パスで指定します)

また、IN 命令を実行した際に入力する値は、


      io_DATA = 16'h000a;				// Input Value

この行で指定します。"000a" は10進数の 10 を意味します。

さらに、このファイルによるシミュレーションでは、HALT 命令を実行した ことによりシミュレーションを停止します。したがって、HALT 命令を実行し ないデバック中のKITEプロセッサではシミュレーションが停止しません。その 場合は、シミュレーションのストップボタン 以上の方法によりシミュレーションを行うと以下のような結果となります。

波形出力画面は以下のようになります。黄色のカーソル地点は実行開始か ら 11.89 m秒後(1MHzのクロックを使用しているので11,890クロック後)にHALT 信号が "L" から "H"に変化しています。これにより、HALT 命令によりシミュ レーションが停止したことを示します。また、ACC の値が "0037" を示し ていますが、これは 1〜10までの加算結果である 55 の16進数を意味 します。このように、設計したプロセッサがこのプログラムを正確に実行した ことを示します。
(この信号波形は最上位階層の信号ではなく、第2階層の信号を表示していま す。)

"testadd.asm" が動いたからといって、KITE-1 プロセッ サが完成したわけではありません。なぜなら、このプログラムは KITE-1 プロ セッサの命令のほんの一部しか使用していないためです。プロセッサの動作が 正しいかどうか色々なプログラムを実行させてみましょう。そのプログラムの 善し悪しがデバッグの効率に関わってきます。各自シミュレーションに使用し たプログラムについてレポートでは必ず考察して下さい。

cwaves_kite_add.gif (35KB)

また、"Verilog-XL Integration Control" ウィンドウには、以下のようにメ モリやI/Oをアクセスした際のアドレスとデータを表示してくれます。デバッ グの情報として利用しましょう。

verilog_ic_add.gif (21KB)


My mail address is kuga@cms.kyutech.ac.jp .
Last modified on