DE0-NANOのSDRAMにNiosIIからアクセスする

##環境

* Terasic DE0-Nano
* Quartus Prime 18.1 Lite Edition

奮発して「FPGAボードで学ぶ組込みシステム開発入門[Intel FPGA編]」を購入した。
本書はDE1-SoCとDE10-Liteを対象にしており、DE0-Nanoは対象にしてないが、
そこは適当に読み解きながら試す。

## 第８章　１節　外部SDRAMの制御

表8-3
DE1-SoCのSDRAMは64M、当方のDE0-Nanoは32MBであるため、Address Width　Columを10→9に変更する。

リスト8-1
最上位層のsdram.vを変更した。おそらく本書はリセットどこかのピンにつないでるらしいが、ピンアサインは記載が無いので、DE0-NanoのMy_First_NiosII_Qsys.pdfを参考にした。

```sdram.v抜粋
.reset_reset_n                     (~RST),
```

```sdram.v抜粋
.reset_reset_n                     (1'b1),
```

本書にある、SDRAMの全領域にBYTE,SHORT,INTを順次書き込むテストプログラムを走らせると、たまにNGになる。

調査のため、コードを変更して以下のとおりにする。

```sdram_test.c
#include "sys/alt_stdio.h"
#include "sys/alt_cache.h"
#include "system.h"

#define SDRAM_C ((volatile unsigned char *) NEW_SDRAM_CONTROLLER_0_BASE)
#define SDRAM_S ((volatile unsigned short *) NEW_SDRAM_CONTROLLER_0_BASE)
#define SDRAM_I ((volatile unsigned int *) NEW_SDRAM_CONTROLLER_0_BASE)

#define MEMSIZE 0x02000000

int main()
{ 
  int i, err=0;
  unsigned int i1, i2, i3;
  unsigned int ary[3];

  // SDRAMに書き込む値
  ary[0] = 0x47bd9f6a;
  ary[1] = 0x1e806c95;
  ary[2] = 0x2fdc3a5c;

  for ( int j=0; j<16; j++ ) {

	  //BYTE書き込み
	  alt_printf("%x",j);
	  alt_printf(" BYTE Checking...");

	  for ( i=0; i<MEMSIZE-3; i=i+3 ){
		  SDRAM_C[i]   = ary[0];
		  SDRAM_C[i+1] = ary[1];
		  SDRAM_C[i+2] = ary[2];
	  }

	  alt_dcache_flush_all();

	  //BYTE読み出し
	  for ( i=0; i<MEMSIZE-3; i=i+3 ){
		  i1 = SDRAM_C[i];
		  i2 = SDRAM_C[i+1];
		  i3 = SDRAM_C[i+2];
		  if( i1 != (ary[0] & 0xff ) ){
			  err=1;
			  alt_printf("\nExpected i1:");
			  alt_printf("%x",ary[0]& 0xff);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i1);
			  alt_printf(" at ");
			  alt_printf("%x",i);
			  alt_printf("\n");
		  }
		  if( i2 != (ary[1] & 0xff ) ){
			  err=1;
			  alt_printf("\nExpected i2:");
			  alt_printf("%x",ary[1] & 0xff);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i2);
			  alt_printf(" at ");
			  alt_printf("%x",i+1);
			  alt_printf("\n");
		  }
		  if( i3 != (ary[2] & 0xff ) ){
			  err=1;
			  alt_printf("\nExpected i3:");
			  alt_printf("%x",ary[2] & 0xff);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i3);
			  alt_printf(" at ");
			  alt_printf("%x",i+2);
			  alt_printf("\n");
		  }
	  }

	  if ( err==1 )
		  alt_printf("NG!!!\n");
	  else
		  alt_printf("OK.\n");

	  err=0;

	  //SHORT書き込み
	  alt_printf("%x",j);
	  alt_printf(" SHORT Checking...");

	  for ( i=0; i<MEMSIZE/2-3; i=i+3 ){
		  SDRAM_S[i]   = ary[0];
		  SDRAM_S[i+1] = ary[1];
		  SDRAM_S[i+2] = ary[2];
	  }

	  alt_dcache_flush_all();

	  //SHORT読み出し
	  for ( i=0; i<MEMSIZE/2-3; i=i+3 ){
		  i1 = SDRAM_S[i];
		  i2 = SDRAM_S[i+1];
		  i3 = SDRAM_S[i+2];
		  if( i1 != (ary[0] & 0xffff ) ) {
			  err=1;
			  alt_printf("\nExpected i1:");
			  alt_printf("%x",ary[0] & 0xffff);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i1);
			  alt_printf(" at ");
			  alt_printf("%x",i);
			  alt_printf("\n");
		  }
		  if( i2 != (ary[1] & 0xffff ) ) {
			  err=1;
			  alt_printf("\nExpected i2:");
			  alt_printf("%x",ary[1] & 0xffff);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i2);
			  alt_printf(" at ");
			  alt_printf("%x",i+1);
			  alt_printf("\n");
		  }
		  if( i3 != (ary[2] & 0xffff ) ) {
			  err=1;
			  alt_printf("\nExpected i3:");
			  alt_printf("%x",ary[2] & 0xffff);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i3);
			  alt_printf(" at ");
			  alt_printf("%x",i+2);
			  alt_printf("\n");
		  }
	  }

	  if ( err==1 )
		  alt_printf("NG!!!\n");
	  else
		  alt_printf("OK.\n");

	  err=0;

	  //INT書き込み
	  alt_printf("%x",j);
	  alt_printf(" INT Checking...");

	  for ( i=0; i<MEMSIZE/4-3; i=i+3 ){
		  SDRAM_I[i]   = ary[0];
		  SDRAM_I[i+1] = ary[1];
		  SDRAM_I[i+2] = ary[2];
	  }

	  alt_dcache_flush_all();

	  //INT読み出し
	  for ( i=0; i<MEMSIZE/4-3; i=i+3 ){
		  i1 = SDRAM_I[i];
		  i2 = SDRAM_I[i+1];
		  i3 = SDRAM_I[i+2];
		  if( i1 != ary[0] ) {
			  err=1;
			  alt_printf("Expected i1:");
			  alt_printf("%x",ary[0]);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i1);
			  alt_printf(" at ");
			  alt_printf("%x",i);
			  alt_printf("\n");
		  }
		  if( i2 != ary[1] ) {
			  err=1;
			  alt_printf("Expected i2:");
			  alt_printf("%x",ary[1]);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i2);
			  alt_printf(" at ");
			  alt_printf("%x",i+1);
			  alt_printf("\n");
		  }
		  if( i3 != ary[2] ) {
			  err=1;
			  alt_printf("Expected i3:");
			  alt_printf("%x",ary[2]);
			  alt_printf(" Read Val:");
			  alt_printf("%x",i3);
			  alt_printf(" at ");
			  alt_printf("%x",i+2);
			  alt_printf("\n");
		  }
	  }

	  if ( err==1 )
		  alt_printf("NG!!!\n");
	  else
		  alt_printf("OK.\n");
	  err=0;

	}

  return 0;
}

```

結果は以下の通り。

```
0 BYTE Checking...OK.
0 SHORT Checking...OK.
0 INT Checking...OK.
1 BYTE Checking...OK.
1 SHORT Checking...
Expected i1:9f6a Read Val:3a5c at 2a35e5

Expected i3:3a5c Read Val:5c95 at 2a35e7

Expected i1:9f6a Read Val:3a5c at 34bc15

Expected i3:3a5c Read Val:5c95 at 34bc17
NG!!!
1 INT Checking...OK.
2 BYTE Checking...OK.
2 SHORT Checking...
Expected i1:9f6a Read Val:3a5c at 159465

Expected i3:3a5c Read Val:5c95 at 159467
NG!!!
2 INT Checking...OK.
3 BYTE Checking...OK.
3 SHORT Checking...
Expected i1:9f6a Read Val:3a5c at 6c7515

Expected i3:3a5c Read Val:5c95 at 6c7517
NG!!!
3 INT Checking...OK.
4 BYTE Checking...OK.
4 SHORT Checking...
Expected i1:9f6a Read Val:3a5c at 4b5c25

Expected i3:3a5c Read Val:5c95 at 4b5c27

Expected i2:6c95 Read Val:3a5c at fffecb

Expected i3:3a5c Read Val:5c95 at fffecf
NG!!!
4 INT Checking...OK.
5 BYTE Checking...OK.
5 SHORT Checking...
Expected i1:9f6a Read Val:3a5c at 31e885

Expected i3:3a5c Read Val:5c95 at 31e887
NG!!!
5 INT Checking...OK.
6 BYTE Checking...OK.
6 SHORT Checking...OK.
6 INT Checking...OK.
7 BYTE Checking...OK.
7 SHORT Checking...
Expected i2:6c95 Read Val:3a5c at fffdab

Expected i3:3a5c Read Val:5c95 at fffdaf
NG!!!
7 INT Checking...OK.
8 BYTE Checking...OK.
8 SHORT Checking...OK.
8 INT Checking...OK.
9 BYTE Checking...OK.
9 SHORT Checking...OK.
9 INT Checking...OK.
a BYTE Checking...OK.
a SHORT Checking...
Expected i2:6c95 Read Val:3a5c at fffecb

Expected i3:3a5c Read Val:5c95 at fffecf
NG!!!
a INT Checking...OK.
b BYTE Checking...OK.
b SHORT Checking...OK.
b INT Checking...OK.
c BYTE Checking...OK.
c SHORT Checking...
Expected i1:9f6a Read Val:3a5c at 79f0f5

Expected i3:3a5c Read Val:5c95 at 79f0f7

Expected i2:6c95 Read Val:3a5c at fffdab

Expected i3:3a5c Read Val:5c95 at fffdaf
NG!!!
c INT Checking...OK.
d BYTE Checking...OK.
d SHORT Checking...
Expected i1:9f6a Read Val:3a5c at 165

Expected i3:3a5c Read Val:5c95 at 167

Expected i1:9f6a Read Val:3a5c at 249465

Expected i3:3a5c Read Val:5c95 at 249467
NG!!!
d INT Checking...OK.
e BYTE Checking...OK.
e SHORT Checking...
Expected i1:9f6a Read Val:3a5c at 37425

Expected i3:3a5c Read Val:5c95 at 37427
NG!!!
e INT Checking...OK.
f BYTE Checking...OK.
f SHORT Checking...OK.
f INT Checking...OK.
```
SHORTのとき異常が出ている。なんでだろ～

(2019.6.26追記)
解決した。pll出力をSYSCLKとSDRAMクロックに与えているが、SDRAMクロックの位相差を付けてなかったため、
アドレスが変化する前に書き込み、またはDQが変化する前に読みこみしていたよう。
DE0-Nanoサンプルプログラムにある通り、SDRAMクロックを-60degとした。