FRAMにアクセス (Niosコーディング編)
Quartusを実行し、リソースとタイミングもOKだったので、次はNiosのプログラムコーディングとシミュレーションについてになります。
NiosはC言語で記述し、シミュレーションはFPGA トップからの行います。
ここでは、シミュレーションを実行する前のNiosのプログラム作成とテストベンチ記述を記載しています。
トップ構成は、以下をご参照ください。
nao-milk.hatenablog.com
※Quartusを実行した時のリソース使用状況とタイミングに関しては、以下をご参照ください。
nao-milk.hatenablog.com
シミュレーション内容
目的
接続が正しく行われるかを確認するため、Niosを含めたシミュレーションを行います。
経路
接続が正しく行われているか各経路を確認します。
経路は以下の通りになります。
①マスタモード時、FRAMの内容をRAMに格納できること。
②RAMに格納されたデータをNIOSでリードできること。
③NIOSからRAMにデータを格納できること。
④RAMからFRAMにデータを格納できること。
⑤FRAMからリードしたデータをRAMに格納できること。
⑥NIOSからFRAMにデータを格納できること。
また、FRAMからNIOSでリードできること。
⑦割り込みが発生し、NIOSに届くこと。
⑧割り込み処理が実行され、割り込みをクリアできること。
メモリマップ
CPU(Nios)から見えるOnChipMemoryはCPU_MEMとPARAMETERになります。
CPU_MEMはNIOSが使用するプログラムや変数などとなり、PARAMETERはFRAMのデータを格納するために使用します。
※FRAMはパラメータ(USERブロックのレジスタ設定値など。。。)を保存するための用途と想定しており、起動時にFRAMからLoadし、終了時や設定変更時にSaveするイメージとなります。
メモリPARAMETER
「Device ID」「Serial Number」「Special Sector」「Data Memory」「その他(Temporary)」の領域に区切り、マスタモードでLoadする時に分割して保存して使用します。
領域が固定されるようLinkerで開始アドレスと領域を指定し、C言語で変数とリンク付けしています。
Linker設定
Linkerの設定内容は、以下通りです。
メモリマップ
メモリPARAMETERのアドレスマップは以下の通りです。
リンク方法
変数の関連付けは、main.cで設定します。
unsigned char FramID[ 16] __attribute__ ((section (".fram_id"))); // Device ID unsigned char FramSN[ 16] __attribute__ ((section (".fram_sn"))); // Serial Number unsigned char FramSS[ 256] __attribute__ ((section (".fram_ss"))); // Special Sector unsigned char FramDT[2048] __attribute__ ((section (".fram_dt"))); // Data Memory unsigned char FramTM[1024] __attribute__ ((section (".fram_tm"))); // Temporary unsigned char FramST __attribute__ ((section (".fram_tm"))); // Status
「その他(Temporary)」は自由な変数として使用できるようにしています。
従って、FramTM[1024]とFramSTはコンパイラ任せとなります。
リンク確認
コンパイル後、変数に指定したセクションが関連付けられているか、マップファイルで確認します。
マップファイルの抜粋を以下に示します。
Memory Configuration Name Origin Length Attributes reset 0x0000000000000000 0x0000000000000020 CPU_MEM 0x0000000000000020 0x0000000000003fe0 prm_ram_id 0x0000000000200000 0x0000000000000010 prm_ram_sn 0x0000000000200010 0x0000000000000010 prm_ram_ss 0x0000000000200020 0x0000000000000100 prm_ram_dt 0x0000000000200120 0x0000000000000800 prm_ram_tm 0x0000000000200920 0x00000000000006e0 *default* 0x0000000000000000 0xffffffffffffffff ===== 略 ===== Linker script and memory map ............. .fram_id 0x0000000000200000 0x10 [!provide] PROVIDE (_alt_partition_fram_id_start, ABSOLUTE (.)) *(.fram_id .fram_id.*) .fram_id 0x0000000000200000 0x10 obj/default/main.o 0x0000000000200000 FramID 0x0000000000200010 . = ALIGN (0x4) [!provide] PROVIDE (_alt_partition_fram_id_end, ABSOLUTE (.)) .fram_sn 0x0000000000200010 0x10 [!provide] PROVIDE (_alt_partition_fram_sn_start, ABSOLUTE (.)) *(.fram_sn .fram_sn.*) .fram_sn 0x0000000000200010 0x10 obj/default/main.o 0x0000000000200010 FramSN 0x0000000000200020 . = ALIGN (0x4) [!provide] PROVIDE (_alt_partition_fram_sn_end, ABSOLUTE (.)) .fram_ss 0x0000000000200020 0x100 [!provide] PROVIDE (_alt_partition_fram_ss_start, ABSOLUTE (.)) *(.fram_ss .fram_ss.*) .fram_ss 0x0000000000200020 0x100 obj/default/main.o 0x0000000000200020 FramSS 0x0000000000200120 . = ALIGN (0x4) [!provide] PROVIDE (_alt_partition_fram_ss_end, ABSOLUTE (.)) .fram_dt 0x0000000000200120 0x800 [!provide] PROVIDE (_alt_partition_fram_dt_start, ABSOLUTE (.)) *(.fram_dt .fram_dt.*) .fram_dt 0x0000000000200120 0x800 obj/default/main.o 0x0000000000200120 FramDT 0x0000000000200920 . = ALIGN (0x4) [!provide] PROVIDE (_alt_partition_fram_dt_end, ABSOLUTE (.)) .fram_tm 0x0000000000200920 0x404 [!provide] PROVIDE (_alt_partition_fram_tm_start, ABSOLUTE (.)) *(.fram_tm .fram_tm.*) .fram_tm 0x0000000000200920 0x401 obj/default/main.o 0x0000000000200920 FramST 0x0000000000200921 FramTM 0x0000000000200d24 . = ALIGN (0x4) *fill* 0x0000000000200d21 0x3 [!provide] PROVIDE (_alt_partition_fram_tm_end, ABSOLUTE (.)) .............
データ比較
データ転送(リード/ライト)が正常に行われたかNios内とテストベンチ内で確認します。
ソースコード
C言語(Nios)
メインプログラム(main.c)
上記経路確認と割り込み処理を記述しています。
また、波形で見た時にどの部分を実行中か分かるようにport_aを使ってステップ番号を出力しています。
#define _MAIN_C_ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "system.h" #include "io.h" #include "sys/alt_irq.h" #include "altera_avalon_pio_regs.h" #include "nml_framif.h" //#define DBG_PRINT(...) printf(__VA_ARGS__) #define DBG_PRINT(...) // ** // ** Interrupt program // *************************************************************************************** int fram_irq_step = 0; static void fram_ir(void *context,unsigned int id){ unsigned int status = 0; status = NML_FRAMIF_GETREG_IRS(); // Interrupt status NML_FRAMIF_SETREG_IRS(status); // Interrupt clear fram_irq_step++; } // ** // ** Main program // *************************************************************************************** // // [ Dedicated memory] // Split PARAMETER memory with Linker unsigned char FramID[ 16] __attribute__ ((section (".fram_id"))); // Device ID unsigned char FramSN[ 16] __attribute__ ((section (".fram_sn"))); // Serial Number unsigned char FramSS[ 256] __attribute__ ((section (".fram_ss"))); // Special Sector unsigned char FramDT[2048] __attribute__ ((section (".fram_dt"))); // Data Memory unsigned char FramTM[1024] __attribute__ ((section (".fram_tm"))); // Temporary unsigned char FramST __attribute__ ((section (".fram_tm"))); // Status int main(void){ unsigned int addr = 0; unsigned char exp = 0; unsigned int err = 0; // == // == Test // ========================================================================= // ++ // ++ Status // +++++++++++++++++++++++++++++++++++++++++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x01); // Step No NML_FRAMIF_RDSR(&FramST); if( FramST != 0x40 ) err++; DBG_PRINT(" >>> Step%d : error[%d]\n",IORD_ALTERA_AVALON_PIO_DATA(PORT_A_BASE),err); // ++ // ++ Waiting for master load // +++++++++++++++++++++++++++++++++++++++++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x02); // Step No if( (FramID[0]==0x11) | (FramID[1]==0x22) | (FramID[2]==0x33) | (FramID[3]==0x44) | (FramID[4]==0x55) | (FramID[5]==0x66) | (FramID[6]==0x77) | (FramID[7]==0x88) | (FramID[8]==0x99) ); else err++; DBG_PRINT(" >>> Step%d : error[%d]\n",IORD_ALTERA_AVALON_PIO_DATA(PORT_A_BASE),err); // ++ // ++ Serial number confirmation // +++++++++++++++++++++++++++++++++++++++++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x03); // Step No if( (FramSN[0]==0x01) | (FramSN[1]==0x23) | (FramSN[2]==0x45) | (FramSN[3]==0x67) | (FramSN[4]==0x89) | (FramSN[5]==0xAB) | (FramSN[6]==0xCD) | (FramSN[7]==0xEF) ); else err++; DBG_PRINT(" >>> Step%d : error[%d]\n",IORD_ALTERA_AVALON_PIO_DATA(PORT_A_BASE),err); // ++ // ++ Initial setting for FRAM I/F // +++++++++++++++++++++++++++++++++++++++++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x04); // Step No NML_FRAMIF_SETUP(0,0,0); // ++ // ++ Data rewriting // +++++++++++++++++++++++++++++++++++++++++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x05); // Step No for(addr=0;addr<8;addr++) FramSN[addr] = (unsigned char)(0xFF-FramSN[addr]); for(addr=0;addr<64;addr++) FramSS[addr] = (unsigned char)(0x00-FramSS[addr]); for(addr=0;addr<128;addr++) FramDT[addr] = (unsigned char)(FramDT[addr]+0xFF); // ++ // ++ Save // +++++++++++++++++++++++++++++++++++++++++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x06); // Step No NML_FRAMIF_SETWP(NML_FRAMIF_WP_OFF); // ** Protect IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x07); // Step No NML_FRAMIF_WRSN(FramSN); // Write Serial Number IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x08); // Step No NML_FRAMIF_SSWR( 0x000000, 64,FramSS); // Special Sector Write IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x09); // Step No NML_FRAMIF_WRITE(0x000000,128,FramDT); // Write Data to Memory IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x0A); // Step No NML_FRAMIF_SETWP(NML_FRAMIF_WP_ON); // ** Protect // ++ // ++ Load // +++++++++++++++++++++++++++++++++++++++++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x0B); // Step No NML_FRAMIF_RDID(FramTM); // Read Device ID for(addr=0;addr<9;addr++){ exp = FramID[addr]+1; if( exp != FramTM[addr] ) err++; } IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x0C); // Step No NML_FRAMIF_RDSN(FramTM); // Read Serial No for(addr=0;addr<8;addr++){ exp = FramSN[addr] + 1; if( exp != FramTM[addr] ) err++; } IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x0D); // Step No NML_FRAMIF_SSRD( 0x000000, 64,FramTM); // Special Sector Read for(addr=0;addr< 64;addr++){ exp = FramSS[addr] + 1; if( exp != FramTM[addr] ) err++; } IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x0E); // Step No NML_FRAMIF_READ( 0x000000,128,FramTM); // Read Data from Memory for(addr=0;addr<128;addr++){ exp = FramDT[addr] + 1; if( exp != FramTM[addr] ) err++; } IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x0F); // Step No DBG_PRINT(" >>>>> FRAM Read/Write Test End : Error [%d]\n\n",err); NML_FRAMIF_SETWP(NML_FRAMIF_WP_OFF); // ** Protect // ========================================================================= // == // == Interrupt Test // ========================================================================= IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x10); // Step No NML_FRAMIF_SETREG_IRS(1); // Clear NML_FRAMIF_SETREG_IRM(0); // Unmask alt_irq_register(0,0,fram_ir); // Interrupt processing registration while(1){ IOWR_ALTERA_AVALON_PIO_DATA(PORT_B_BASE,fram_irq_step); if( fram_irq_step == 0 ){ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x11); NML_FRAMIF_SETWP(NML_FRAMIF_WP_OFF); // ** Protect NML_FRAMIF_WREN(); // Enable Write NML_FRAMIF_SETREG_BAD(0x000000); // Buffer Address NML_FRAMIF_SETREG_BDT(0x02); // Buffer Data [Command] NML_FRAMIF_SETREG_BDT(0x00); // Buffer Data [Address] NML_FRAMIF_SETREG_BDT(0x80); // Buffer Data [Address] NML_FRAMIF_SETREG_BDT(0x00); // Buffer Data [Address] for(addr=0;addr<16;addr++){ // Buffer Data [Write Data] NML_FRAMIF_SETREG_BDT(addr+5); } NML_FRAMIF_SETREG_ACS(1+3+16-1); // Access NML_FRAMIF_SETREG_OTC(1+3+16-1); // Output fram_irq_step++; NML_FRAMIF_SETREG_IRM(0); // Unmask NML_FRAMIF_SETREG_ENB(1); // START }; if( fram_irq_step == 2 ){ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x12); NML_FRAMIF_SETWP(NML_FRAMIF_WP_ON); // ** Protect NML_FRAMIF_SETREG_BAD(0x000000); // Buffer Address NML_FRAMIF_SETREG_BDT(0x03); // Buffer Data [Command] NML_FRAMIF_SETREG_ACS(1+3+16-1); // Access NML_FRAMIF_SETREG_OTC(1+3 -1); // Output fram_irq_step++; NML_FRAMIF_SETREG_IRM(0); // Unmask NML_FRAMIF_SETREG_ENB(1); // START } if( fram_irq_step == 4 ){ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x13); NML_FRAMIF_SETREG_BAD(0x000004); // Buffer Address for(addr=0;addr<16;addr++){ // Buffer Data [Write Data] exp = addr+5+3; if( (unsigned char)(NML_FRAMIF_GETREG_BDT()) != exp ) err++; } break; } } // ++++++ Final Message +++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0xFF); printf(" >>>>> FRAM Read/Write Test End : Error [%d]\n",err); NML_FRAMIF_SETWP(NML_FRAMIF_WP_OFF); return 0; }
FRAM I/F用プログラム(framif.c)
#ifndef _NML_FRAMIF_C_ #define _NML_FRAMIF_C_ #include <stdio.h> #include <stdlib.h> #include "system.h" #include "io.h" #include "altera_avalon_pio_regs.h" #include "nml_framif.h" // -- // -- Initial setting // ----------------------------------------------------------------------------- void NML_FRAMIF_SETUP( unsigned int Div , // Serial clock division [0 to 15] unsigned int Pol , // Serial clock polarity [0:Low 1:High] unsigned int Tak // Import timing [0 to 3] ){ NML_FRAMIF_SETREG_CNT(Tak,Pol,Div); NML_FRAMIF_SETREG_IRM(1); NML_FRAMIF_SETREG_IRS(1); } void NML_FRAMIF_BUFINIT(void){ unsigned int bad = 0; NML_FRAMIF_SETREG_BAD(bad); for(bad=0;bad<NML_FRAMIF_BUFSIZE;bad++){ NML_FRAMIF_SETREG_BDT(0x00); } } // -- // -- FRAM Access // ----------------------------------------------------------------------------- // ******************************************************************* // ** // ** Private Function // ** // @@ // @@ Transfer processing (Common) // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ char nml_framif_access( unsigned char Polling , // End detection method [1:Register polling] unsigned char Command , // Command int Address , // Address (-1 or less and no address setting) unsigned int PutSize , // Storage size unsigned int GetSize , // Acquisition size unsigned char *Data // Data ){ unsigned char puttype = 0; unsigned int acs = 0; unsigned int otc = 0; unsigned int tmp = 0; // ++ Confirmation of operation // ++ Back if running // +++++++++++++++++++++++++++++++++++++++++++ if( NML_FRAMIF_GETREG_ENB() != 0 ) return NML_FRAMIF_STA_ERR; // ++ Parsing arguments // ++ (PutSize==0) & (GetSize==0) : Write system (command only) // ++ (PutSize!=0) & (GetSize==0) : Write system // ++ (PutSize==0) & (GetSize!=0) : Read system // ++ Others : Write system (command only) // +++++++++++++++++++++++++++++++++++++++++++ if( (PutSize==0) & (GetSize==0) ){ puttype = 1; acs = 1; otc = 1; } else if( (PutSize!=0) & (GetSize==0) ){ puttype = 1; acs = 1+PutSize; otc = 1+PutSize; } else if( (PutSize==0) & (GetSize!=0) ){ puttype = 0; acs = 1+GetSize; otc = 1; } else { puttype = 1; acs = 1; otc = 1; } // ++ Interrupt clear and mask // +++++++++++++++++++++++++++++++++++++++++++ NML_FRAMIF_SETREG_IRM(1); // Mask NML_FRAMIF_SETREG_IRS(1); // Clear // ++ Setting // +++++++++++++++++++++++++++++++++++++++++++ NML_FRAMIF_SETREG_BAD(0); NML_FRAMIF_SETREG_BDT(Command); if( Address >= 0 ){ acs = acs + 3; otc = otc + 3; NML_FRAMIF_SETREG_BDT(Address>>16); NML_FRAMIF_SETREG_BDT(Address>> 8); NML_FRAMIF_SETREG_BDT(Address>> 0); } NML_FRAMIF_SETREG_ACS((acs-1)); NML_FRAMIF_SETREG_OTC((otc-1)); // ++ Data storage // +++++++++++++++++++++++++++++++++++++++++++ if( puttype == 1 ){ for(tmp=0;tmp<PutSize;tmp++) NML_FRAMIF_SETREG_BDT(Data[tmp]); } // ++ Transfer start // +++++++++++++++++++++++++++++++++++++++++++ NML_FRAMIF_SETREG_ENB(1); // ++ Transfer complete // +++++++++++++++++++++++++++++++++++++++++++ if( Polling == 1 ){ while( NML_FRAMIF_GETREG_ENB() != 0 ); NML_FRAMIF_SETREG_IRS(1); if( puttype == 0 ){ if( Address < 0 ) NML_FRAMIF_SETREG_BAD(1); else NML_FRAMIF_SETREG_BAD(4); for(tmp=0;tmp<GetSize;tmp++) Data[tmp] = NML_FRAMIF_GETREG_BDT(); } return NML_FRAMIF_STA_FIN; } return NML_FRAMIF_STA_SET; } // @@ // @@ Write processing (Common) // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ char nml_framif_acc_wr( unsigned char Type , // Write type unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1 to NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ){ char status = 0; // ++ Write Enable ON // +++++++++++++++++++++++++++++++++++++++++++ if( Type == 0 ) return nml_framif_access(1,0x06,-1,0,0,NULL); if( (status=nml_framif_access(1,0x06,-1,0,0,NULL)) != NML_FRAMIF_STA_FIN ) return status; // ++ Write operation // +++++++++++++++++++++++++++++++++++++++++++ if( Type == 1 ) return nml_framif_access(1,0x01, -1, 1,0,Data); else if( Type == 2 ) return nml_framif_access(1,0xC2, -1, 8,0,Data); else if( Type == 3 ) return nml_framif_access(1,0x02,(int)(Address),Length,0,Data); else if( Type == 4 ) return nml_framif_access(1,0x42,(int)(Address),Length,0,Data); else return nml_framif_access(1,0x04, -1, 0,0,NULL); } // ** // ******************************************************************* // ++ // ++ Write system (Supports CY15B102QN commands) // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ char NML_FRAMIF_WREN(void) { return nml_framif_acc_wr(0,0,0,NULL); } char NML_FRAMIF_WRSR(unsigned char *Data) { return nml_framif_acc_wr(1,0,0,Data); } char NML_FRAMIF_WRSN(unsigned char *Data) { return nml_framif_acc_wr(2,0,0,Data); } char NML_FRAMIF_WRDI(void) { return nml_framif_acc_wr(5,0,0,NULL); } char NML_FRAMIF_WRITE( unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ){ return nml_framif_acc_wr(3,Address,Length,Data); } char NML_FRAMIF_SSWR( unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1 to NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ){ return nml_framif_acc_wr(4,Address,Length,Data); } // ++ // ++ Read system (Supports CY15B102QN commands) // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ char NML_FRAMIF_RDSR(unsigned char *Data) { return nml_framif_access(1,0x05,-1,0,1,Data); } char NML_FRAMIF_RDID(unsigned char *Data) { return nml_framif_access(1,0x9F,-1,0,9,Data); } char NML_FRAMIF_RDSN(unsigned char *Data) { return nml_framif_access(1,0xC3,-1,0,8,Data); } char NML_FRAMIF_READ( unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1 to NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ){ return nml_framif_access(1,0x03,(int)(Address),0,Length,Data); } char NML_FRAMIF_SSRD( unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1 to NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ){ return nml_framif_access(1,0x4B,(int)(Address),0,Length,Data); } // -- // -- Write protect control // ----------------------------------------------------------------------------- void NML_FRAMIF_SETWP( unsigned char Flag ){ IOWR_ALTERA_AVALON_PIO_DATA(FRAM_WP_BASE, (unsigned int)(Flag)); } unsigned char NML_FRAMIF_GETWP(void){ return (unsigned char)(IORD_ALTERA_AVALON_PIO_DATA(FRAM_WP_BASE)); } #endif /* _NML_FRAMIF_C_ */
FRAM I/Fのヘッダファイル(framif.h)
#ifndef _NML_FRAMIF_H_ #define _NML_FRAMIF_H_ #include "system.h" #include "io.h" // -- // -- Define // ----------------------------------------------------------------------------- #define NML_FRAMIF_BUFSIZE (4096) // Buffer size in FRAM I / F #define NML_FRAMIF_STA_ERR (-1) // FRAM I/F is in operation #define NML_FRAMIF_STA_FIN ( 1) // Processing to FRAM I/F is completed #define NML_FRAMIF_STA_SET ( 2) // Finished setting process to FRAM I/F #define NML_FRAMIF_WP_ON (0) // Write protect ON #define NML_FRAMIF_WP_OFF (1) // Write protect OFF // -- // -- Register for FRAM I/F // ----------------------------------------------------------------------------- #define NML_FRAMIF_SETREG_ENB(enb) (IOWR(FRAM_BASE,0x00, ((enb)&0x00000001))) #define NML_FRAMIF_SETREG_CNT(tak,pol,div) (IOWR(FRAM_BASE,0x01,(((tak)&0x00000001)<<5)| \ (((pol)&0x00000001)<<4)| \ (((div)&0x0000000F)<<0))) #define NML_FRAMIF_SETREG_ACS(acs) (IOWR(FRAM_BASE,0x02, ((acs)&0x001FFFFF))) #define NML_FRAMIF_SETREG_OTC(otc) (IOWR(FRAM_BASE,0x03, ((otc)&0x001FFFFF))) #define NML_FRAMIF_SETREG_IRS(irs) (IOWR(FRAM_BASE,0x04, ((irs)&0x00000001))) #define NML_FRAMIF_SETREG_IRM(irm) (IOWR(FRAM_BASE,0x05, ((irm)&0x00000001))) #define NML_FRAMIF_SETREG_BAD(bad) (IOWR(FRAM_BASE,0x06, ((bad)&0x001FFFFF))) #define NML_FRAMIF_SETREG_BDT(bdt) (IOWR(FRAM_BASE,0x07, ((bdt)&0x000000FF))) #define NML_FRAMIF_GETREG_ENB(void) (IORD(FRAM_BASE,0x00)) #define NML_FRAMIF_GETREG_CNT(void) (IORD(FRAM_BASE,0x01)) #define NML_FRAMIF_GETREG_ACS(void) (IORD(FRAM_BASE,0x02)) #define NML_FRAMIF_GETREG_OTC(void) (IORD(FRAM_BASE,0x03)) #define NML_FRAMIF_GETREG_IRS(void) (IORD(FRAM_BASE,0x04)) #define NML_FRAMIF_GETREG_IRM(void) (IORD(FRAM_BASE,0x05)) #define NML_FRAMIF_GETREG_BAD(void) (IORD(FRAM_BASE,0x06)) #define NML_FRAMIF_GETREG_BDT(void) (IORD(FRAM_BASE,0x07)) #define NML_FRAMIF_GETREG_CNT_TAK(void) ((IORD(FRAM_BASE,0x01)>>5)&0x03) #define NML_FRAMIF_GETREG_CNT_POL(void) ((IORD(FRAM_BASE,0x01)>>4)&0x01) #define NML_FRAMIF_GETREG_CNT_DIV(void) ((IORD(FRAM_BASE,0x01)>>0)&0x0F) // -- // -- Function for FRAM I/F // ----------------------------------------------------------------------------- #ifdef _NML_FRAMIF_C_ void NML_FRAMIF_SETUP( // ** Initial setting unsigned int Div , // Serial clock division [0 to 15] unsigned int Pol , // Serial clock polarity [0:Low 1:High] unsigned int Tak // Import timing [0 to 3] ); void NML_FRAMIF_BUFINIT(void); // ** Buffer initialization // ***** Write protect control void NML_FRAMIF_SETWP(unsigned char); // ** Write protect settings unsigned char NML_FRAMIF_GETWP(void); // ** Get write protect status // ***** Write system(Supports CY15B102QN commands) char NML_FRAMIF_WREN(void) ; // ** Enable Write char NML_FRAMIF_WRDI(void) ; // ** Disable Write char NML_FRAMIF_WRSR(unsigned char *Data) ; // ** Write Status Register char NML_FRAMIF_WRSN(unsigned char *Data) ; // ** Write Serial Number char NML_FRAMIF_WRITE( // ** Write Data to Memory unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ); char NML_FRAMIF_SSWR( // ** Special Sector Write unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ); // ***** Read system(Supports CY15B102QN commands) char NML_FRAMIF_RDSR(unsigned char *Data) ; // ** Read Status Register char NML_FRAMIF_RDID(unsigned char *Data) ; // ** Read Device ID char NML_FRAMIF_RDSN(unsigned char *Data) ; // ** Read Serial No char NML_FRAMIF_READ( // ** Read Data from Memory unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ); char NML_FRAMIF_SSRD( // ** Special Sector Read unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ); #else // --------------------------------------------------------------------- extern void NML_FRAMIF_SETUP( // ** Initial setting unsigned int Div , // Serial clock division [0 to 15] unsigned int Pol , // Serial clock polarity [0:Low 1:High] unsigned int Tak // Import timing [0 to 3] ); extern void NML_FRAMIF_BUFINIT(void); // ** Buffer initialization // ***** Write protect control extern void NML_FRAMIF_SETWP(unsigned char); // ** Write protect settings extern unsigned char NML_FRAMIF_GETWP(void); // ** Get write protect status // ***** Write system(Supports CY15B102QN commands) extern char NML_FRAMIF_WREN(void) ; // ** Enable Write extern char NML_FRAMIF_WRDI(void) ; // ** Disable Write extern char NML_FRAMIF_WRSR(unsigned char *Data) ; // ** Write Status Register extern char NML_FRAMIF_WRSN(unsigned char *Data) ; // ** Write Serial Number extern char NML_FRAMIF_WRITE( // ** Write Data to Memory unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ); extern char NML_FRAMIF_SSWR( // ** Special Sector Write unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ); // ***** Read system(Supports CY15B102QN commands) extern char NML_FRAMIF_RDSR(unsigned char *Data) ; // ** Read Status Register extern char NML_FRAMIF_RDID(unsigned char *Data) ; // ** Read Device ID extern char NML_FRAMIF_RDSN(unsigned char *Data) ; // ** Read Serial No extern char NML_FRAMIF_READ( // ** Read Data from Memory unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ); extern char NML_FRAMIF_SSRD( // ** Special Sector Read unsigned int Address , // Start address unsigned int Length , // Storage size (Range:1~NML_FRAMIF_BUFSIZE-4) unsigned char *Data // Data ); #endif #endif /* _NML_FRAMIF_H_ */
verilog言語(テストベンチ)
テストベンチでは、リセット解除後にFRAM I/Fブロックをマスタモードで動作させるための記述(forceで入力信号PRM_???を変更して動作させています)と、FRAM内のメモリ配列を確認したり書き換えたりしています。
`timescale 1ns/1ps module TB_TOP; integer PERIOD = 0; reg RESET_N = 0; reg CLOCK = 0; reg SW_SLAVE = 1; reg SW_GO = 0; wire FRAM_CS_N ; // @@ [SYS_CLK↑同期] FRAM SPI チップセレクト wire FRAM_SCLK ; // @@ [SYS_CLK↑同期] FRAM SPI シリアルクロック wire FRAM_MOSI ; // @@ [SYS_CLK↑同期] FRAM SPI シリアル出力 wire FRAM_MISO ; // @@ [SYS_CLK↑同期] FRAM SPI シリアル入力 // ++ タイミング設定 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Clock波形 real tcCLOCK = 40.000; real tpCLOCK = 5.000; real tnCLOCK = 25.000; // FRAM モデル間遅延 defparam UnDlyFRAM_CS_N.NsStep= 0 ,UnDlyFRAM_CS_N.PsStep= 0; defparam UnDlyFRAM_SCLK.NsStep= 0 ,UnDlyFRAM_SCLK.PsStep= 0; defparam UnDlyFRAM_MOSI.NsStep= 0 ,UnDlyFRAM_MOSI.PsStep= 0; defparam UnDlyFRAM_MISO.NsStep= 0 ,UnDlyFRAM_MISO.PsStep= 0; // -- // -- Clock生成 // ------------------------------------------------------------------- initial begin forever begin fork #(tpCLOCK) CLOCK = 1; #(tnCLOCK) CLOCK = 0; #(tcCLOCK) PERIOD = PERIOD+1; join end end // -- // -- Reset // ------------------------------------------------------------------- reg [ 7:0] tmpID[0: 8]; reg [ 7:0] tmpSN[0: 7]; reg [ 7:0] tmpSS[0: 255]; reg [ 7:0] tmpDT[0:262143]; integer error = 0; reg [ 7:0] exp; initial begin : GenReset integer a; #0 RESET_N = 0; repeat(10) @(PERIOD); RESET_N = 1; FRAM.Device_ID[0] = 'h11; FRAM.Device_ID[1] = 'h22; FRAM.Device_ID[2] = 'h33; FRAM.Device_ID[3] = 'h44; FRAM.Device_ID[4] = 'h55; FRAM.Device_ID[5] = 'h66; FRAM.Device_ID[6] = 'h77; FRAM.Device_ID[7] = 'h88; FRAM.Device_ID[8] = 'h99; FRAM.Serial_No[0] = 'h01; FRAM.Serial_No[1] = 'h23; FRAM.Serial_No[2] = 'h45; FRAM.Serial_No[3] = 'h67; FRAM.Serial_No[4] = 'h89; FRAM.Serial_No[5] = 'hAB; FRAM.Serial_No[6] = 'hCD; FRAM.Serial_No[7] = 'hEF; for(a=0;a<256;a=a+1) FRAM.Smem[a] = $random; for(a=0;a<262144;a=a+1) FRAM.mem[a] = $random; /***** Copy *****/ for(a=0;a<9;a=a+1) tmpID[a] = FRAM.Device_ID[a]; for(a=0;a<8;a=a+1) tmpSN[a] = FRAM.Serial_No[a]; for(a=0;a<256;a=a+1) tmpSS[a] = FRAM.Smem[a]; for(a=0;a<262144;a=a+1) tmpDT[a] = FRAM.mem[a]; wait( TOP.FRAM_WP_N === 1 ) $display(" >>> FRAM Protect OFF"); wait( TOP.FRAM_WP_N === 0 ) $display(" >>> FRAM Protect ON"); for(a=0;a<9;a=a+1) begin if( FRAM.Device_ID[a] !== tmpID[a] ) error = error + 1; end $display(" >>> Device ID : Error = %d",error); for(a=0;a<8;a=a+1) begin exp = 'hFF - tmpSN[a]; if( exp !== FRAM.Serial_No[a] ) error = error + 1; end $display(" >>> Serial No : Error = %d",error); for(a=0;a<64;a=a+1) begin exp = 'h00 - tmpSS[a]; if( exp !== FRAM.Smem[a] ) error = error + 1; end $display(" >>> Special Sector : Error = %d",error); for(a=0;a<128;a=a+1) begin exp = 'hFF + tmpDT[a]; if( exp !== FRAM.mem[a] ) error = error + 1; end $display(" >>> Memory Sector : Error = %d",error); for(a=0;a<9;a=a+1) FRAM.Device_ID[a] = FRAM.Device_ID[a] + 1; for(a=0;a<8;a=a+1) FRAM.Serial_No[a] = FRAM.Serial_No[a] + 1; for(a=0;a<256;a=a+1) FRAM.Smem[a] = FRAM.Smem[a] + 1; for(a=0;a<128;a=a+1) FRAM.mem[a] = FRAM.mem[a] + 1; wait( TOP.FRAM_WP_N === 1 ) $display(" >>> FRAM Protect OFF"); wait( TOP.FRAM_WP_N === 0 ) $display(" >>> FRAM Protect ON"); for(a='h8000;a<'h8010;a=a+1) FRAM.mem[a] = FRAM.mem[a]+3; wait( TOP.FRAM_WP_N === 1 ); $display(" >>>>> FRAM Save Data Error : %d",error); end // -- // -- Mater Mode 起動 Force操作 // ------------------------------------------------------------------- parameter LOAD_STA_ID = 'h20_0000; parameter LOAD_STA_SN = 'h20_0010; parameter LOAD_STA_SS = 'h20_0020; parameter LOAD_STA_DT = 'h20_0120; parameter LOAD_STA_TM = 'h20_0920; initial begin : MasterBoot #0; wait( TOP.cpu_rst_n === 1'b1 ); $display(" >>> %m : Reset Off"); repeat(10) @(posedge TOP.cpu_clk); force TOP.UnFRAMIF.MST_SLV = 0; // Master Mode force TOP.UnFRAMIF.PRM_MSK = 1; // Mask force TOP.UnFRAMIF.PRM_CLR = 1; // Clear force TOP.UnFRAMIF.PRM_DIV = 0; force TOP.UnFRAMIF.PRM_POL = 0; force TOP.UnFRAMIF.PRM_TAK = 0; // ++ シリアルNo 取得 $display(" >>> %m : Read Serial No"); #1; force TOP.UnFRAMIF.PRM_CMD = 'hC3; force TOP.UnFRAMIF.PRM_ADD = 0; force TOP.UnFRAMIF.PRM_ACS = 1+8 -1; force TOP.UnFRAMIF.PRM_OTC = 1 -1; force TOP.UnFRAMIF.PRM_STA = LOAD_STA_SN; repeat(10) @(posedge TOP.cpu_clk); #1; $display(" >>> %m : CMD = %h",TOP.UnFRAMIF.PRM_CMD); $display(" >>> %m : ADD = %h",TOP.UnFRAMIF.PRM_ADD); $display(" >>> %m : ACS = %d",TOP.UnFRAMIF.PRM_ACS); $display(" >>> %m : OTC = %d",TOP.UnFRAMIF.PRM_OTC); $display(" >>> %m : STA = %h",TOP.UnFRAMIF.PRM_STA); $display(" >>> %m : START"); force TOP.UnFRAMIF.PRM_ENB = 1; repeat( 5) @(posedge TOP.cpu_clk); #1; wait( TOP.UnFRAMIF.MON_ENB === 1'b1 ); #1; wait( TOP.UnFRAMIF.MON_ENB === 1'b0 ); #1; $display(" >>> %m : FINISH"); repeat(20) @(posedge TOP.cpu_clk); #1; force TOP.UnFRAMIF.PRM_ENB = 0; repeat(10) @(posedge TOP.cpu_clk); #1; // ++ 特殊セクタ 取得 $display(" >>> %m : Special Sector Read"); #1; force TOP.UnFRAMIF.PRM_CMD = 'h4B; force TOP.UnFRAMIF.PRM_ADD = 0; force TOP.UnFRAMIF.PRM_ACS = 64+4 -1; force TOP.UnFRAMIF.PRM_OTC = 4 -1; force TOP.UnFRAMIF.PRM_STA = LOAD_STA_SS; repeat(10) @(posedge TOP.cpu_clk); #1; $display(" >>> %m : CMD = %h",TOP.UnFRAMIF.PRM_CMD); $display(" >>> %m : ADD = %h",TOP.UnFRAMIF.PRM_ADD); $display(" >>> %m : ACS = %d",TOP.UnFRAMIF.PRM_ACS); $display(" >>> %m : OTC = %d",TOP.UnFRAMIF.PRM_OTC); $display(" >>> %m : STA = %h",TOP.UnFRAMIF.PRM_STA); $display(" >>> %m : START"); force TOP.UnFRAMIF.PRM_ENB = 1; repeat( 5) @(posedge TOP.cpu_clk); #1; wait( TOP.UnFRAMIF.MON_ENB === 1'b1 ); #1; wait( TOP.UnFRAMIF.MON_ENB === 1'b0 ); #1; $display(" >>> %m : FINISH"); repeat(20) @(posedge TOP.cpu_clk); #1; force TOP.UnFRAMIF.PRM_ENB = 0; repeat(10) @(posedge TOP.cpu_clk); #1; // ++ メモリデータ 取得 $display(" >>> %m : Read Data from Memory"); #1; force TOP.UnFRAMIF.PRM_CMD = 'h03; force TOP.UnFRAMIF.PRM_ADD = 0; force TOP.UnFRAMIF.PRM_ACS = 128+4 -1; force TOP.UnFRAMIF.PRM_OTC = 4 -1; force TOP.UnFRAMIF.PRM_STA = LOAD_STA_DT; repeat(10) @(posedge TOP.cpu_clk); #1; $display(" >>> %m : CMD = %h",TOP.UnFRAMIF.PRM_CMD); $display(" >>> %m : ADD = %h",TOP.UnFRAMIF.PRM_ADD); $display(" >>> %m : ACS = %d",TOP.UnFRAMIF.PRM_ACS); $display(" >>> %m : OTC = %d",TOP.UnFRAMIF.PRM_OTC); $display(" >>> %m : STA = %h",TOP.UnFRAMIF.PRM_STA); $display(" >>> %m : START"); force TOP.UnFRAMIF.PRM_ENB = 1; repeat( 5) @(posedge TOP.cpu_clk); #1; wait( TOP.UnFRAMIF.MON_ENB === 1'b1 ); #1; wait( TOP.UnFRAMIF.MON_ENB === 1'b0 ); #1; $display(" >>> %m : FINISH"); repeat(20) @(posedge TOP.cpu_clk); #1; force TOP.UnFRAMIF.PRM_ENB = 0; repeat(10) @(posedge TOP.cpu_clk); #1; // ++ デバイスID 取得 $display(" >>> %m : Read Device ID"); #1; force TOP.UnFRAMIF.PRM_CMD = 'h9F; force TOP.UnFRAMIF.PRM_ADD = 0; force TOP.UnFRAMIF.PRM_ACS = 9+1 -1; force TOP.UnFRAMIF.PRM_OTC = 1 -1; force TOP.UnFRAMIF.PRM_STA = LOAD_STA_ID; repeat(10) @(posedge TOP.cpu_clk); #1; $display(" >>> %m : CMD = %h",TOP.UnFRAMIF.PRM_CMD); $display(" >>> %m : ADD = %h",TOP.UnFRAMIF.PRM_ADD); $display(" >>> %m : ACS = %d",TOP.UnFRAMIF.PRM_ACS); $display(" >>> %m : OTC = %d",TOP.UnFRAMIF.PRM_OTC); $display(" >>> %m : STA = %h",TOP.UnFRAMIF.PRM_STA); $display(" >>> %m : START"); force TOP.UnFRAMIF.PRM_ENB = 1; repeat( 5) @(posedge TOP.cpu_clk); #1; wait( TOP.UnFRAMIF.MON_ENB === 1'b1 ); #1; wait( TOP.UnFRAMIF.MON_ENB === 1'b0 ); #1; $display(" >>> %m : FINISH"); repeat(20) @(posedge TOP.cpu_clk); #1; force TOP.UnFRAMIF.PRM_ENB = 0; repeat(10) @(posedge TOP.cpu_clk); #1; // ======================================= $display(" >>> %m : Master Mode End"); #1; release TOP.UnFRAMIF.MST_SLV; release TOP.UnFRAMIF.PRM_ENB; release TOP.UnFRAMIF.PRM_DIV; release TOP.UnFRAMIF.PRM_POL; release TOP.UnFRAMIF.PRM_TAK; release TOP.UnFRAMIF.PRM_ACS; release TOP.UnFRAMIF.PRM_OTC; release TOP.UnFRAMIF.PRM_MSK; release TOP.UnFRAMIF.PRM_CLR; release TOP.UnFRAMIF.PRM_STA; release TOP.UnFRAMIF.PRM_CMD; release TOP.UnFRAMIF.PRM_ADD; end // -- // -- ターゲットのインスタンス // ------------------------------------------------------------------- wire dlyFRAM_CS_N; DlyBuf UnDlyFRAM_CS_N(.A(FRAM_CS_N),.Y(dlyFRAM_CS_N) ); wire dlyFRAM_SCLK; DlyBuf UnDlyFRAM_SCLK(.A(FRAM_SCLK),.Y(dlyFRAM_SCLK) ); wire dlyFRAM_MOSI; DlyBuf UnDlyFRAM_MOSI(.A(FRAM_MOSI),.Y(dlyFRAM_MOSI) ); wire dlyFRAM_MISO; DlyBuf UnDlyFRAM_MISO(.A(FRAM_MISO),.Y(dlyFRAM_MISO) ); TOP TOP( .RESET_N (RESET_N ), // input wire RESET_N , // @@ リセット .CLOCK (CLOCK ), // input wire CLOCK , // @@ クロック .FRAM_WP_N ( ), // output wire FRAM_WP_N , // @@ FRAM ライトプロテクト[0:プロテクト] .FRAM_CS_N ( FRAM_CS_N ), // output wire FRAM_CS_N , // @@ FRAM SPI チップセレクト .FRAM_SCLK ( FRAM_SCLK ), // output wire FRAM_SCLK , // @@ FRAM SPI シリアルクロック .FRAM_MOSI ( FRAM_MOSI ), // output wire FRAM_MOSI , // @@ FRAM SPI シリアル出力 .FRAM_MISO (dlyFRAM_MISO ), // input wire FRAM_MISO , // @@ FRAM SPI シリアル入力 .SW_SLAVE (SW_SLAVE ), // input wire SW_SLAVE , // @@ Master/Slave切替 [0:Master] .SW_GO (SW_GO ), // input wire SW_GO , // @@ 処理イネーブル .LED_LOCK ( ) // output wire LED_LOCK // @@ LED Lock ); reg FRAM_VDD = 0; initial begin #1; FRAM_VDD=1; end FRAM_SPI FRAM( .CSB (dlyFRAM_CS_N ), .SCK (dlyFRAM_SCLK ), .SI (dlyFRAM_MOSI ), .SO ( FRAM_MISO ), .WPB (1'b1 ), .VDD ( FRAM_VDD ) ); endmodule module DlyBuf #( parameter NsStep = 1, parameter PsStep = 1 ) ( input wire A , output wire Y ); wire [NsStep:0] SigNs; wire [PsStep:0] SigPs; assign SigNs[0] = A; generate genvar ins; if( NsStep != 0 ) begin for(ins=1;ins<=NsStep;ins=ins+1) begin DlyBufCoreNs UnDlyNs(.A(SigNs[ins-1]),.Y(SigNs[ins]) ); end end endgenerate assign SigPs[0] = SigNs[NsStep]; generate genvar ips; if( PsStep != 0 ) begin for(ips=1;ips<=PsStep;ips=ips+1) begin DlyBufCorePs UnDlyPs(.A(SigPs[ips-1]),.Y(SigPs[ips]) ); end end endgenerate assign Y = SigPs[PsStep]; endmodule module DlyBufCoreNs(input wire A, output wire Y); assign #(1.000) Y = A; endmodule module DlyBufCorePs(input wire A, output wire Y); assign #(0.001) Y = A; endmodule
最後に
上記で説明した内容は設計したブロック間が正しいか確認するためのNiosプログラムとなります。
経路を確認した後、実際の用途に合わせて、ソフトウェアを作り込むことになります。