fc2ブログ

[LM32](2)LEDチカチカ

ターゲット評価ボード= Terasic社 Atlas-SOC
 ※ 途中からVEEK(別名tPAD、DE2-115+LCD)をターゲットに変えて作業してる。


Quartusのqpf、qsfのひな型を作る


http://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&CategoryNo=165&No=941&PartNo=4

Terasic社Atlas-SOCページから、
DE0-Nano-SoC CD-ROM (rev.B0 / rev.C0 Board) 1.1.0 - 2015-12-29
のCDROMアイコンをクリック。

DE0-Nano-SoC_v.1.1.0_HWrevB0_revC0_SystemCD.zip
を入手した。

解凍後、
DE0-Nano-SoC_v.1.1.0_HWrevB0_revC0_SystemCD\Tools\SystemBuilder

DE0_Nano_SoC_SystemBuilder.exe
を実行する。

欲しい希望だけチェックして、Generateすると、qpfやqsfが生成される。


//=======================================================
// This code is generated by Terasic System Builder
//=======================================================

module ether_top(

//////////// CLOCK //////////
input FPGA_CLK1_50,
input FPGA_CLK2_50,
input FPGA_CLK3_50,

//////////// KEY //////////
input [1:0] KEY,

//////////// LED //////////
output [7:0] LED,

//////////// SW //////////
input [3:0] SW,

//////////// GPIO_0, GPIO connect to LT24 - 2.4" LCD and Touch //////////
input LT24_ADC_BUSY,
output LT24_ADC_CS_N,
output LT24_ADC_DCLK,
output LT24_ADC_DIN,
input LT24_ADC_DOUT,
input LT24_ADC_PENIRQ_N,
output LT24_CS_N,
output [15:0] LT24_D,
output LT24_LCD_ON,
output LT24_RD_N,
output LT24_RESET_N,
output LT24_RS,
output LT24_WR_N
);

wire [23:0] dummy_led ;


//=======================================================
// REG/WIRE declarations
//=======================================================




//=======================================================
// Structural coding
//=======================================================

ether ether1 (
.clk_i ( FPGA_CLK1_50 )
,.reset_n ( SW[0] )
,.sramsram_wen ( )
,.sramsram_data ( )
,.sramsram_addr ( )
,.sramsram_csn ( )
,.sramsram_be ( )
,.sramsram_oen ( )
,.uartSIN ( )
,.uartSOUT ( )
,.gpioPIO_OUT ( { dummy_led, LED } )
,.spiMISO_MASTER ( )
,.spiMOSI_MASTER ( )
,.spiSS_N_MASTER ( )
,.spiSCLK_MASTER ( )
,.i2cm_ocSDA ( )
,.i2cm_ocSCL ( )
);

endmodule


最後にインスタンスされたether1は、LatticeMico32と合体するために追加したもの。




Mico System Builderでシステムを作る

File > New Platform > PlatformHを選択。
イーサネットMAC入りだが、バージョン?のエラーが出てTri speed MACがあるとGenerate出来ない。
なので削除して、別途、Opencoresから入手したRTLを手作業で追加する事にする。

さらに、命令メモリとデータメモリはLM32のInline Memoryを使う事にする。
Mico System Builder > LMS1.0 D3.10タブ > ether.msbのシステムツリー
 > LM32をダブルクリック > ウィンドウ開く
 > Generalタブ > Instruction Cache、Data Cacheのチェック外す
 > Inline Memoryタブ
 > Instruction Inline MemoryのEnableにチェック、
    Base Addressを0x00004000、
    Size of Memoryを0x00002000、
    Initialization File Nameをinst_ram_data.v、File FormatをHEXへ。
     ※ Base Addressはシステムツリーで割り当てたアドレスを設定。
 > Data Inline MemoryのEnableにチェック、
    Base Addressを0x00008000、
    Size of Memoryを0x00002000、
    Initialization File Nameをdata_ram_data.v、File FormatをHEXへ。
 > LM32の設定は完了。
 > システムツリーの中で、Asyncramを削除。

構成が決まったら、
Platform Tools > Generate Address
Platform Tools > Generate IRQ
Platform Tools > Run DRC
Platform Tools > Run Generator
を順番に実行。

これで
soc/* ・・・ システムトップのRTL
component/* ・・・ 各コンポーネットのRTL
が生成された。



Mico System Builderでソフトをビルド

Mico System Builder > 画面左上のC/C++、に切り替え > 右クリック
 > New > mico Managed Make C Project
 > LED Test small size、を選択してプロジェクトを生成。

システムツリーでAsyncramを削除し、Inline MemoryをEnableしたので、プログラムデータの配置場所も変更する必要がある。
左上のプロジェクト名(今回はether)で右クリック > Properties
 > Platform
 > Linker Script > Program memory = Instructoin_IM ※ LM32設定で決めたInline Memory名。
 > Linker Script > Read-only data memory = Data_IM ※ LM32設定で決めたInline Memory名。
 > Linker Script > Read/write data memory = Data_IM
 > Stdio Redirection > stdin = RS-232(uart) ※ JTAG-UARTから変えておく。後でUARTも設定予定。
 > Stdio Redirection > stdout = RS-232(uart) ※ JTAG-UARTから変えておく。後でUARTも設定予定。
 > Stdio Redirection > stderr = RS-232(uart) ※ JTAG-UARTから変えておく。後でUARTも設定予定。

このまま右クリック > Build Projectでビルドすると、
LED_BASE_ADDRESSが無い
とエラーになる。

GPIOのアドレスを以下の通り設定する。
#define LED_BASE_ADDRESS 0x80000300

これでBuild Projectをやると、
C:\user\work\quartus\atlas-soc\micosystem\sw\ether\Debug\ether.elf
が生成された。




elf -> srec -> mifへ変換
ALTERA製SRAMで初期値として読み込むために、mifに変換する。

elfからsrecはこれで実行。
/usr/bin/objcopy.exe -S -O srec ether.elf ether.srec

srecからmifへの変換は、以前デザインウェーブ?で特集あった際の山際さん作成memcvt.cを使う。
今回のメモリアドレス、サイズに合わせて以下だけ修正。

#define INST_BASE_ADDR 0x00004000
#define INST_SIZE_LIMIT (1024*16)
#define RWDATA_BASE_ADDR 0x00008000
#define RWDATA_SIZE_LIMIT (1024*16)



gcc memcvt_171021.c -o memcvt_171021.exe
これでexeが出来た。

memcvt_171021.exe ether.srec
を実行すると、以下mif形式のファイルが生成される。
ファイル名はmemcvt_171021.cで指定したもの。

data_ram_data.mif
inst_ram_data.mif

これでALTERA製SRAM初期値として読めるmif形式になった。



SRAMをALTERA製に置き換える

今回、Terasic社Atlas-SOCにて実機評価するため、メモリはALTERA製に置き換える必要がある。




ALTERA製SRAM初期値をセット




Veritakでシミュレーション準備1

フォルダの位置関係は以下。

C:\user\work\quartus\atlas-soc\micosystem\ether ・・・ Mico System Builderでの生成場所
C:\user\work\quartus\atlas-soc\micosystem\ether\soc ・・・ Veritak実行場所
C:\user\work\quartus\atlas-soc\micosystem\ether\component ・・・ Lattice Mico32システムの各コンポーネント場所
C:\user\work\quartus\atlas-soc\quartus ・・・ Quartusコンパイル場所

この相対位置において、いちいちVeritakにRTLを登録するのは面倒。
なので、必要ファイルパスを書いたVerilogを作成し、このファイルをVeritakで読み込む事にする。

<lm32_file_include.v の内容>

`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/ec/VHI.v"
`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/ec/VLO.v"
`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/ec/GSR.v"
`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/ec/PUR.v"
`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/ec/DP8KA.v"
`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/ec/BB.v"
`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/ecp3/DP16KC.v"
`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/lptm2/DP8KC.v"
`include "../../../../../../../lscc/diamond/3.10_x64/cae_library/simulation/verilog/ecp5u/DP16KD.v"
`include "../components/gpio/rtl/verilog/tpio.v"
`include "../components/lm32_top/rtl/verilog/lm32_include.v"
`include "../components/lm32_top/rtl/verilog/lm32_include_all.v"
`include "../../../quartus/ether_top.v"
`include "ether.v"
`include "../../../quartus/tb_ether_top.v"



これ以外の設定は以下のみ

Veritak > Verilogプロジェクト > プロジェクトの編集 > 上で登録するフォルダまで行き、「Add Include Dir」
ボタンで追加する。
追加したフォルダは以下3つ。

-include_dir ../component/uart_core/rtl/verilog
-include_dir ../component/lm32_top/rtl/verilog
-include_dir ../component/i2cm_opencores/rtl/verilog



Lattice Mico32の各コンポーネントRTL内でincludeされているRTLがある。
上記の設定が無いとパスが分からずエラーになる。
なので、RTLの存在フォルダを登録する事で自動的にincludeされてエラーが無くなった。

 ※ 必要なファイルは全てlm32_file_include.vにまとめて書けば、include_dirの設定は不要になってシンプルになる。
    また後で改善する事にして、とりあえずこれで進める。



Veritak向けRTL修正: gpio.v

Mico System Builderで生成したRTLのうち、そのままVeritakで読めないものがある。

components\gpio\rtl\verilog\gpio.v
赤字のようにラベル?を付けないとエラーになった。
けっこうな数があって面倒だが一回だけ我慢して修正版は保存しておこう。

generate
if (OUTPUT_PORTS_ONLY == 1) begin
if (GPIO_WB_DAT_WIDTH == 8) begin
genvar ipd_idx;
for (ipd_idx = 0; (ipd_idx < DATA_WIDTH) && (ipd_idx < 8); ipd_idx = ipd_idx + 1)
begin: hoge1
always @(posedge CLK_I or posedge RST_I)
if (RST_I)
PIO_DATA[ipd_idx] <= #UDLY 0;
else if (GPIO_STB_I && !GPIO_ACK_O && GPIO_WE_I && GPIO_ADR_I[3:0] == 4'b0000)
PIO_DATA[ipd_idx] <= #UDLY GPIO_DAT_I_switch[ipd_idx];
end
if (DATA_WIDTH > 8) begin
genvar jpd_idx;
for (jpd_idx = 8; (jpd_idx < DATA_WIDTH) && (jpd_idx < 16); jpd_idx = jpd_idx + 1)
begin: hoge2
always @(posedge CLK_I or posedge RST_I)
if (RST_I)
PIO_DATA[jpd_idx] <= #UDLY 0;
else if (GPIO_STB_I && !GPIO_ACK_O && GPIO_WE_I && GPIO_ADR_I[3:0] == 4'b0001)
PIO_DATA[jpd_idx] <= #UDLY GPIO_DAT_I_switch[jpd_idx-8];
end
end





Veritak向けRTL修正: lm32_load_store_unit.v

Inline MemoryをEnableすると以下エラーが出た。

C:\user\work\quartus\atlas-soc\micosystem\ether\components\lm32_top\rtl\verilog\lm32_load_store_unit.v(200)::Error: irom_store_data_m複数のレンジの記述方法を統一してください
moduleを評価中です。
C:\user\work\quartus\atlas-soc\micosystem\ether\components\lm32_top\rtl\verilog\lm32_load_store_unit.v(482)::Error: irom_store_data_m [ ]内が宣言でのレンジを超えています。
C:\user\work\quartus\atlas-soc\micosystem\ether\components\lm32_top\rtl\verilog\lm32_load_store_unit.v(483)::Error: irom_store_data_m [ ]内が宣言でのレンジを超えています。
C:\user\work\quartus\atlas-soc\micosystem\ether\components\lm32_top\rtl\verilog\lm32_load_store_unit.v(484)::Error: irom_store_data_m [ ]内が宣言でのレンジを超えています。
C:\user\work\quartus\atlas-soc\micosystem\ether\components\lm32_top\rtl\verilog\lm32_load_store_unit.v(485)::Error: irom_store_data_m [ ]内が宣言でのレンジを超えています。
C:\user\work\quartus\atlas-soc\micosystem\ether\components\lm32_top\rtl\verilog\lm32_load_store_unit.v(111)::Error: irom_store_data_m port宣言が見つかりません。



これは以下が原因だった。修正する。
micosystem/ether/components/lm32_top/rtl/verilog/lm32_load_store_unit.v

199行目から。
`ifdef CFG_IROM_ENABLED

output irom_store_data_m; // Store data to Instruction ROM
wire [`LM32_WORD_RNG] irom_store_data_m;
  ↓
output [`LM32_WORD_RNG] irom_store_data_m; // Store data to Instruction ROM
wire [`LM32_WORD_RNG] irom_store_data_m;





VeritakでRAMデータ内容見たい時

Veritak > Verilogプロジェクト > プロジェクト設定 > Limit Memory Size = 32KBytesに設定

それから、コンパイル後に、メモリアレイ信号を波形ビューワに追加してから、シミュレーション開始する。
すると、内容が見れるようになった。



pmi_def.vは使うな!中身が無い。

lm32_load_store_unit.v
で以下エラー出てない?
それならpmi_addsub.vを疑え!

Warning: Non-aligned word access. Address: 0xzzzzzzzz Time: 5070000.
Instruction bus error. Address: 00000784
Instruction bus error. Address: 00000788
Instruction bus error. Address: 0000078c



このエラーの理由は
lm32_load_store_unit.v load_store_address_m
がsize_m=2の時にHizになる事が原因のようだ。
なぜHizになるか追ってみると、addsubからHizの結果が出るからだ。
pmi_addsubの実態を見ると、pmi_def.vに宣言されているが、中身が無い。これが原因のようだ。

pmi_addsub.vの実態あるやつは以下にある。
c/lscc/diamond/3.10_x64/cae_library/simulation/verilog/pmi/pmi_addsub.v

しかし、lm32_include_all.v を読み込むと、pmi_def.vを読まれてしまう。
micosystem/ether/components/lm32_top/rtl/verilog/lm32_include_all.v:`include "pmi_def.v"

けど、lm32_include_all.vを使わないと面倒なので、lm32_include_all.vの内容から、
SIMULATIONのdefineをすれば、pmi_def.vはincludeされないようだ。これで解決。

`ifndef SIMULATION
`include "pmi_def.v"
`endif






Quartus向けRTL修正: wb_spi.v


Error (10200): Verilog HDL Conditional Statement error at wb_spi.v(339): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct



337行目

always @(posedge CLK_I or posedge RST_I)
修正前: if (RST_I || (c_status == ST_IDLE))
修正後: if (RST_I )
clock_cnt <= 0;
追加  : else if (c_status == ST_IDLE)
追加  : clock_cnt <= 0;




Quartus向けRTL修正: lm32_cpu.v



Error (10257): Verilog HDL error at lm32_cpu.v(2021): unsized constants are not allowed in concatenations



2021行目

assign cfg = {
`LM32_REVISION,
watchpoints[3:0],
breakpoints[3:0],
interrupts[5:0],
`ifdef CFG_JTAG_UART_ENABLED
`TRUE,  > ★原因はこれ。1'b1にしたらエラー消えた。altera_mf.vにも同じ宣言が整数(32bit?)でされてるのが原因?
`else
`FALSE,  > ★原因はこれ。1'b0にしたらエラー消えた。altera_mf.vにも同じ宣言が整数(32bit?)でされてるのが原因?
`endif
 :



2087行目
cfgの下のcfg2も同じ原因。

assign cfg2 = {





Quartus向けRTL修正: lm32_cpu.v


Error (10207): Verilog HDL error at altera_mf.v(48976): can't resolve reference to object "convert_to_ver_file"






Quartus向けRTL修正: DP16KD.v


Error (10161): Verilog HDL error at DP16KD.v(160): object "GSR_INST" is not declared. Verify the object name is correct. If the name is correct, declare the object.
Error (10161): Verilog HDL error at DP16KD.v(161): object "PUR_INST" is not declared. Verify the object name is correct. If the name is correct, declare the object.
Error (10161): Verilog HDL error at DP8KA.v(117): object "GSR_INST" is not declared. Verify the object name is correct. If the name is correct, declare the object.
Error (10161): Verilog HDL error at DP8KA.v(118): object "PUR_INST" is not declared. Verify the object name is correct. If the name is correct, declare the object.



C/lscc/diamond/3.10_x64/cae_library/simulation/verilog/ecp5u/DP16KD.v

GSR GSR_INST( .GSR(GSR) ); > ★追加
PUR PUR_INST( .PUR(PUR) ); > ★追加

//tri1 GSR_sig = GSR_INST.GSRNET;
//tri1 PUR_sig = PUR_INST.PURNET;

tri1 GSR_sig, PUR_sig;
`ifndef mixed_hdl
assign GSR_sig = GSR_INST.GSRNET;
assign PUR_sig = PUR_INST.PURNET;
`else
gsr_pur_assign gsr_pur_assign_inst (GSR_sig, PUR_sig);
`endif



C/lscc/diamond/3.10_x64/cae_library/simulation/verilog/ec/DP8KA.v

GSR GSR_INST( .GSR(GSR) ); > ★追加
PUR PUR_INST( .PUR(PUR) ); > ★追加

tri1 GSR_sig = GSR_INST.GSRNET;
tri1 PUR_sig = PUR_INST.PURNET;



なんか面倒くさい
以前やった時はこんな事しなかったな。
探したらlm32_monitor_ram_altera.vを発見。
latticeのDP8とかのRAMは使わずに、lm32_monitor_ramをアルテラ用に変えてました。今回もこれを採用。



Quartus向けRTL修正: lm32_monitor_ram.v


以前作ったlm32_monitor_ram_altera.vを使う事に。

`include "system_conf.v"

module lm32_monitor_ram_altera (DataInA, DataInB, AddressA, AddressB, ClockA,
ClockB, ClockEnA, ClockEnB, WrA, WrB, ResetA, ResetB, QA, QB);
input [31:0] DataInA;
input [31:0] DataInB;
input [8:0] AddressA;
input [8:0] AddressB;
input ClockA;
input ClockB;
input ClockEnA;
input ClockEnB;
input WrA;
input WrB;
input ResetA;
input ResetB;
output [31:0] QA;
output [31:0] QB;

altsyncram ram_0 (
.address_a ({AddressA,2'b00})
, .clock0 (ClockA )
, .data_a (DataInA[7:0] )
, .wren_a (WrA )
, .q_a (QA[7:0] )
, .rden_a (1'b1)
, .rden_b (1'b1)
, .address_b ({AddressB,2'b00})
, .clock1 (1'b1 )
, .data_b (DataInB[7:0] )
, .wren_b (WrB )
, .q_b (QB[7:0] )
, .addressstall_a (1'b0 )
, .addressstall_b (1'b0 )
, .byteena_a (1'b1)
, .byteena_b (1'b1)
, .clocken0 (1'b1 )
, .clocken1 (1'b1 )
, .clocken2 (1'b1)
, .clocken3 (1'b1)
, .eccstatus ()
, .aclr0 ()
, .aclr1 ()
);
defparam
ram_0.clock_enable_input_a = "BYPASS",
ram_0.clock_enable_output_a = "BYPASS",
ram_0.init_file = "inst_ram_data.hex",
ram_0.intended_device_family = "Cyclone III",
ram_0.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
ram_0.lpm_type = "altsyncram",
ram_0.maximum_depth = 512,
ram_0.numwords_a = 512,
ram_0.operation_mode = "SINGLE_PORT",
ram_0.outdata_aclr_a = "NONE",
ram_0.outdata_reg_a = "CLOCK0",
ram_0.power_up_uninitialized = "FALSE",
ram_0.ram_block_type = "M9K",
ram_0.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
ram_0.widthad_a = 11,
ram_0.widthad_b = 11,
ram_0.width_a = 8,
ram_0.width_b = 8,
ram_0.width_byteena_a = 1,
ram_0.width_byteena_b = 1;

altsyncram ram_1 (
.address_a ({AddressA,2'b00})
, .clock0 (ClockA )
, .data_a (DataInA[15:8] )
, .wren_a (WrA )
, .q_a (QA[15:8] )
, .rden_a (1'b1)
, .rden_b (1'b1)
, .address_b ({AddressB,2'b00})
, .clock1 (1'b1 )
, .data_b (DataInB[15:8] )
, .wren_b (WrB )
, .q_b (QB[15:8] )
, .addressstall_a (1'b0 )
, .addressstall_b (1'b0 )
, .byteena_a (1'b1)
, .byteena_b (1'b1)
, .clocken0 (1'b1 )
, .clocken1 (1'b1 )
, .clocken2 (1'b1)
, .clocken3 (1'b1)
, .eccstatus ()
, .aclr0 ()
, .aclr1 ()
);
defparam
ram_1.clock_enable_input_a = "BYPASS",
ram_1.clock_enable_output_a = "BYPASS",
ram_1.init_file = "inst_ram_data.hex",
ram_1.intended_device_family = "Cyclone III",
ram_1.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
ram_1.lpm_type = "altsyncram",
ram_1.maximum_depth = 512,
ram_1.numwords_a = 512,
ram_1.operation_mode = "SINGLE_PORT",
ram_1.outdata_aclr_a = "NONE",
ram_1.outdata_reg_a = "CLOCK0",
ram_1.power_up_uninitialized = "FALSE",
ram_1.ram_block_type = "M9K",
ram_1.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
ram_1.widthad_a = 11,
ram_1.widthad_b = 11,
ram_1.width_a = 8,
ram_1.width_b = 8,
ram_1.width_byteena_a = 1,
ram_1.width_byteena_b = 1;

altsyncram ram_2 (
.address_a ({AddressA,2'b00})
, .clock0 (ClockA )
, .data_a (DataInA[23:16])
, .wren_a (WrA )
, .q_a (QA[23:16] )
, .rden_a (1'b1)
, .rden_b (1'b1)
, .address_b ({AddressB,2'b00})
, .clock1 (1'b1 )
, .data_b (DataInB[23:16])
, .wren_b (WrB )
, .q_b (QB[23:16] )
, .addressstall_a (1'b0 )
, .addressstall_b (1'b0 )
, .byteena_a (1'b1)
, .byteena_b (1'b1)
, .clocken0 (1'b1 )
, .clocken1 (1'b1 )
, .clocken2 (1'b1)
, .clocken3 (1'b1)
, .eccstatus ()
, .aclr0 ()
, .aclr1 ()
);
defparam
ram_2.clock_enable_input_a = "BYPASS",
ram_2.clock_enable_output_a = "BYPASS",
ram_2.init_file = "inst_ram_data.hex",
ram_2.intended_device_family = "Cyclone III",
ram_2.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
ram_2.lpm_type = "altsyncram",
ram_2.maximum_depth = 512,
ram_2.numwords_a = 512,
ram_2.operation_mode = "SINGLE_PORT",
ram_2.outdata_aclr_a = "NONE",
ram_2.outdata_reg_a = "CLOCK0",
ram_2.power_up_uninitialized = "FALSE",
ram_2.ram_block_type = "M9K",
ram_2.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
ram_2.widthad_a = 11,
ram_2.widthad_b = 11,
ram_2.width_a = 8,
ram_2.width_b = 8,
ram_2.width_byteena_a = 1,
ram_2.width_byteena_b = 1;

altsyncram ram_3 (
.address_a ({AddressA,2'b00})
, .clock0 (ClockA )
, .data_a (DataInA[31:24])
, .wren_a (WrA )
, .q_a (QA[31:24] )
, .rden_a (1'b1)
, .rden_b (1'b1)
, .address_b ({AddressB,2'b00})
, .clock1 (1'b1 )
, .data_b (DataInB[31:24])
, .wren_b (WrB )
, .q_b (QB[31:24] )
, .addressstall_a (1'b0 )
, .addressstall_b (1'b0 )
, .byteena_a (1'b1)
, .byteena_b (1'b1)
, .clocken0 (1'b1 )
, .clocken1 (1'b1 )
, .clocken2 (1'b1)
, .clocken3 (1'b1)
, .eccstatus ()
, .aclr0 ()
, .aclr1 ()
);
defparam
ram_3.clock_enable_input_a = "BYPASS",
ram_3.clock_enable_output_a = "BYPASS",
ram_3.init_file = "inst_ram_data.hex",
ram_3.intended_device_family = "Cyclone III",
ram_3.lpm_hint = "ENABLE_RUNTIME_MOD=NO",
ram_3.lpm_type = "altsyncram",
ram_3.maximum_depth = 512,
ram_3.numwords_a = 512,
ram_3.operation_mode = "SINGLE_PORT",
ram_3.outdata_aclr_a = "NONE",
ram_3.outdata_reg_a = "CLOCK0",
ram_3.power_up_uninitialized = "FALSE",
ram_3.ram_block_type = "M9K",
ram_3.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
ram_3.widthad_a = 11,
ram_3.widthad_b = 11,
ram_3.width_a = 8,
ram_3.width_b = 8,
ram_3.width_byteena_a = 1,
ram_3.width_byteena_b = 1;

endmodule






USB-Blasterドライバ適用


VEEK電源ON > PCにUSBつなぐ > 不明なデバイスになる > デバイスマネージャ
 > 以下を指定し、サブフォルダも検索、にチェックした上で進むと自動的にドライバ入った。
C:\intelFPGA_lite\17.0\quartus\drivers

 ※ 以下のフォルダを指定したら、見つかりません、と言われた。
   どっから持ってきたか不明だが、上記のdriversフォルダを指定して自動検索にしたら成功した。
C:\intelFPGA_lite\17.0\quartus\drivers\usb-blaster\x64
C:\intelFPGA_lite\17.0\quartus\drivers\usb-blaster-ii\x64
C:\intelFPGA_lite\17.0\quartus\drivers\wdrvr\windows64




ProgrammerでsofをVEEKへダウンロード


Quartusでコンパイルが成功したら、.sofが生成されているはず。
Quartus > Tools > Programmer > 左上のHardware Setup
 > USB-Blasterドライバが適用されるとAltera USB-Blasterが見えた。それを選んでclose。
 > これでStartボタンクリックすると、右上のProgressバーが進み、Successfulになった。

 Hardware Setup = Altera USB-Blaster
 Mode       = JTAG
 File        = DE2-115.sof
 接続チェーン図 = TDI -> EP4CE115F29 -> TDO となっている。







MicosystemのBuildエラー

latticemicosystem.exe > C/C++ウィンドウ > プロジェクトを右クリック
 > Build Project

これで以下のエラーが出る。

make all
0 [main] make 4652 find_fast_cwd: WARNING: Couldn't compute FAST_CWD pointer. Please report this problem to
the public mailing list cygwin@cygwin.com
43556 [main] make 7788 child_info_fork::abort: C:\lscc\diamond\3.10_x64\micosystem\cygwin\bin\cygiconv-2.dll: Loaded to different address: parent(0x4D0000) != child(0x600000)
make: vfork: Resource temporarily unavailable
80141 [main] make 6636 child_info_fork::abort: C:\lscc\diamond\3.10_x64\micosystem\cygwin\bin\cygiconv-2.dll: Loaded to different address: parent(0x4D0000) != child(0x20C0000)
make: vfork: Resource temporarily unavailable



調べると、Windows 8.1におけるCygwinの問題らしい。

同じデータを使って、Win 10のPCでBuildしたらエラーは出なかった。Win 8.1の問題と判断し、PC変えて作業しよう。

Windows 10 Pro
LMS_1.0_for_Diamond3.10.exe.zip
3.10.0.111.2_Diamond_x64.zip
uname -a の結果
CYGWIN_NT-10.0 x1 2.9.0(0.318/5/3) 2017-09-12 10:18 x86_64 Cygwin

[LM32](1)環境構築

ホスト = ThinkPad X1 Windows 10 Pro
もしくは
ホスト = ThinkPad X230 Windows 8.1 Pro


Lattice Diamond Softwareインストール

http://www.latticesemi.com/en/Products/DesignSoftwareAndIP/FPGAandLDS/LatticeDiamond.aspx

上記にアクセス > Download Software Below でWindowsをクリック
  > Lattice Diamond をクリック
  > LatticeアカウントへSign In
  > ライセンスチェックを入れて、Downloadボタンで入手。

これで
3.10.0.111.2_Diamond_x64.zip
がダウンロードされた。

解凍すると
\3.10.0.111.2_Diamond_x64\3.10.0.111.2_Diamond_x64.exe
が生成されるので実行。
あとはウィザードに従ってインストールを進める。


Lattice Micosystemインストール

http://www.latticesemi.com/ja-JP/Products/DesignSoftwareAndIP/EmbeddedDesignSoftware/LatticeMicoSystem
ここのページから以下をクリック。
LatticeMico System for Diamond 3.10 Windows

LMS_1.0_for_Diamond3.10.exe.zip
をダウンロードし、解凍後、インストールする。



Cygwinインストール

コマンドラインでいろいろ操作したいのでCygwinをインストールする。
環境変数として以下を設定。

CYGWIN ntsec
HOME /home/xxx
MAKE_MODE UNIX
SHELL /bin/bash



また、.bashrcの設定としてとりあえず以下。

alias lm='ls -lst'
export PATH=$PATH:/bin:/sbin:/cygdrive/c/user/app/vim80-kaoriya-win64-8.0.0596-20170502
alias WORK='cd /cygdrive/c/user/work/quartus/atlas-soc/quartus'
alias USER='cd /cygdrive/c/user'





シミュレータ(Veritak)インストール

無償のModelSim Starterが遅すぎるので、Veritakを使う。
veritakwin384D.exe
をインストール。


エディタ(Gvim)インストール

ウィンドウ分割で複数ファイルを開いて、次回同じ構成で開く時、
:mks!
とやれば、
Session.vim
が生成される。

次回作業再開する場合は、Cygwinから
gvim -S Session.vim
とやれば、複数ファイル開いた状態のまま復元出来る。

[LM32]MSBでSoftware Deployment時「WARNING: Couldn't compute FAST_CWD pointer.」

0 [main] bin_to_verilog 5956 find_fast_cwd: WARNING: Couldn't compute FAST_CWD pointer. Please report this problem to
the public mailing list cygwin@cygwin.com
Failed to open tmp.bin for reading
No such file or directory


https://cygwin.com/ml/cygwin/2014-09/msg00164.html
ここ見るとこんな投稿があった。

I experienced the same thing when I upgraded to Windows 8.1. The messages went away when I upgraded to the latest and greatest Cygwin.


どうやらWindows 8.1で発生する問題のようで、Cygwinを更新すると直るらしいが、
MicoSystemBuilderのCygwinってどうやって更新するんだ?

インストール先を、MSBのCygwin場所に指定すれば良いのかな?

C:\lscc\diamond\3.4_x64\micosystem\cygwin


setup-x86.exeで更新出来たようだが、Software Deloyment実行しても、
Warningは出なくなったが、.memのサイズが0KB・・・なぜだ。

<terminated> uart_int2[Mico32 On Chip Memory Deployment] C:\lscc\diamond\3.4_x64\micosystem\utilities\bin_to_verilog


ConsoleタブのバーにこんなMSGが出た。

[LM32]wb_spi.vがSEL_I未サポート(MicoSystem v3.4.0.80)

構造体、共用体を使って、SPIコアのレジスタへBYTEでもBITでも両方アクセス可能にしたい。

struct st_spi { /* struct SPI */
 :
union { /* CTRL */
unsigned int DWORD;
struct {
unsigned int RESV1 :21;
unsigned char SSO :1;
unsigned char RESV4 :1;
unsigned char IE :1;
unsigned char IRRDY :1;
unsigned char ITRDY :1;
unsigned char RESV5 :1;
unsigned char ITOE :1;
unsigned char IROE :1;
unsigned char RESV6 :3;
} BIT;
} CTRL;
 :
};


ところが、SPI.CTRL.BIT.IE = 0; のようにbitアクセスすると、目的のbitのみの操作が出来ない。
micosystem_spi_not_support_for_SEL
上の波形で、一番上のled_out_regの値を逐一変えて、順番にレジスタアクセス動作を見ている。
SPI.CTRL.BIT.IE = 0;したのが、led_out_reg=19のところ。

この波形の通り、bit操作するためには、まずは対象のアドレス(SPIコアControllレジスタ)の値を読みだして、
その値を基準にして、操作対象のbitのみを変更している(と理解)。
波形図では見えないが、SPI_DAT_Oはreg_controlのリード値=0x140が出ていた。

Mico32は32bitデータバスなので、SEL[3:0]を使って、アクセス対象のBYTEを指定する。
IEビットはbit8なので、SEL_I[1]のみがHになる。
そのため、上の波形におけるSPI_SEL_Iは、fから2([1]のみHになった)へ値が変わっている。
この動作は正しい。

期待の動作は、reg_control[8]のみH->Lへ変化するはずが、[6]も変化してしまっている。
MicoSystemが生成したwb_spi.vを見たら、SPI_SEL_Iは未接続。
SEL_I制御が効いてないから、無関係のbitまで変更してしまった。これが原因だ。

よくよく見ると、MicoSystemで生成したSPIコアは、WISHBONEのSEL_I信号に未対応だって。
SPIコアデータシートpage8 I/O Portsにしっかり書いてあるが。
MicoSystemで生成されるRTLはWISHBONE完全準拠かと勝手に思ってた。

wb_spi.vをSEL信号対応に修正しよう。

[LM32]DE0 nanoでLEDチカチカしない原因解析 → 解決

XilinxのML501では動いていたソース(DWM200710のやつ)をもってきて、
コンパイラ等もDWM200710付属のデータを使い、DE0 nano上で
Lattice Mico32を動かそうとしてる。

メモリをXilinxからAlteraへ変えるだけで、確かこの前LEDチカチカ出来てたんだが、
また動かなくなった。ソースの取り違いの可能性大だが、こんな場合に、
どんな確認すれば良いのか考えてみる。
(単に動くソースを探して差し替えれば動くのかもしれないけど、そもそもCPUはどこがどうなると
 正常動作になるのか?というのを、ほんの触りだけでも探ってみる、という意味です)

■命令用SRAMから最初にどのデータが読まれるのか?
 main関数の前はスタートアップルーチンだ、くらいは知ってるけど、
 外部リセットを入れてから、どこからSRAMが読まれ、どんな値が出たらOKなのか?を確認したい。

 まずはobjdumpでelfを解析してみる。

$ lm32-elf-objdump.exe -d uart_int | more

uart_int: file format elf32-lm32

Disassembly of section .start:

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>
...
20: e0 00 00 6d bi 1d4 <__break_interrupt>
...
40: e0 00 00 61 bi 1c4 <__interrupt>
...
60: e0 00 00 59 bi 1c4 <__interrupt>
...
80: e0 00 00 51 bi 1c4 <__interrupt>
...
a0: e0 00 00 49 bi 1c4 <__interrupt>
...
c0: e0 00 00 41 bi 1c4 <__interrupt>
...
e0: e0 00 00 39 bi 1c4 <__interrupt>
...

00000100 <__startup>:
100: 78 1c 20 00 mvhi sp,0x2000
104: 3b 9c 1f fc ori sp,sp,0x1ffc
108: e0 00 01 41 bi 60c



0000010c :
10c: 37 9c ff c8 addi sp,sp,-56
110: 5b 81 00 04 sw (sp+4),r1
114: 5b 82 00 08 sw (sp+8),r2
118: 5b 83 00 0c sw (sp+12),r3
11c: 5b 84 00 10 sw (sp+16),r4
120: 5b 85 00 14 sw (sp+20),r5
124: 5b 86 00 18 sw (sp+24),r6
128: 5b 87 00 1c sw (sp+28),r7
12c: 5b 88 00 20 sw (sp+32),r8
130: 5b 89 00 24 sw (sp+36),r9
     :



 まずリセット直後に読まれるアドレスは0x00番地(のはず)。
 Webでぐぐっても0番地と書いてあるが、保有してるRTLの設定が本当にそうなってるのか?
 が確認出来てないから「はず」を付けた。

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>



 0番地から始まり、そこではbi命令で、_startupラベルの番地へ飛ぶ。
 __startupラベルは100番地を指していて、__startupの記述を見ると次のようになってた。

00000100 <__startup>:
100: 78 1c 20 00 mvhi sp,0x2000
104: 3b 9c 1f fc ori sp,sp,0x1ffc
108: e0 00 01 41 bi 60c



 mvhiって何だ?と思ったら以下を見る。ここにアセンブラの仕様がのってる。
 http://www.latticesemi.com/~/media/Documents/UserManuals/JL/LatticeMico32ProcessorReferenceManual34.pdf?document_id=50900

少なくとも0番地からスタートする事は正しそうだし、hexファイルを見ても、0番地に下の命令がある。

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>


ただし、シミュレーションしても、addr=0でrden=Hなのにデータ出力はAll 0のまま。なぜ?

命令メモリ単体でシミュレーションしても同じでwren=0、rden=1、addr=0、be=0xfにしても0番地が読まれない。
QuartusII 14.1でIP Catalog画面へD&DしてMegaWizardを起動し、パラメータを確認してみると・・・

目的と違って出力がレジスタ付になってる。詳細な論理は不明だが、単にレジスタ1段入ってたって、
ずっと出力が変わらないって事は無いだろう、とは思いつつも、ここを出力レジスタ無にした。
そうすると、リードデータが出力されるようになった。
ソースでいうと、以下の設定。UNREGISTEREDなので出力レジスタ無って事らしい。

altsyncram_component.outdata_reg_a = "UNREGISTERED",



MegaWizardの画面で見る限り、単に1クロック遅れて出力させるための出力レジスタだと思ってたが、
このレジスタ動作には他の論理が絡んでるって事かな?
LUTでなく、BLOCK RAMを使われると物理LAYOUTにおいて、BLOCK RAMからその後段の論理が遠くなり、
セットアップ違反になるケースを回避するための役目程度にしか考えてなかった。今後注意しよう。


とりあえずhexはちゃんとかどうか不明だが、見る限り先頭の100アドレスくらいは初期値として読まれている。
そして、SRAMからデータも出力されるようになった。
SRAM単体のシミュレーションからMico32のシミュレーションに戻ってみると、命令アドレスは、
0x000、0x004、0x008、0x100、0x104、0x108・・・
と進んで行く。

リセット解除後に、0x000に進むのは納得。ここがスタートアップルーチンの開始ポイントだから。

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>
...
20: e0 00 00 6d bi 1d4 <__break_interrupt>
...
40: e0 00 00 61 bi 1c4 <__interrupt>
...


次の0x004、0x008に行くのはなぜ?と思ったが、
よくよく考えると以下が理由だよね。納得。

  ・32bit CPUなので、データは4バイト毎読まれる。だから0、4、8と進む。
  ・今シミュレーションで見ているのはSRAMへのアドレス入力。
   つまりパイプライン内の命令フェッチステージの動作。
   さらに0x000にbi命令(Unconditional branch)があるため、無条件分岐するのだが、
   パイプライン上の命令フェッチステージでは次から次への先取りしてアドレスを進める。
  ・0x000のbi命令が、IF、DECODE、EXEとパイプラインを進むうちに分岐命令が実行され、
   0x008の次にbi命令で指定した0x100へジャンプした。



アドレスは想定通りに進んでいるが、0x100へ飛んだ後、そこでもまたメモリ出力がおかしく、
hexファイル上では

:10010000781c20003b9c1ffce0000141379cffc88D


「781c2000」が0x100の命令なのに、シミュレーションではALL 0出力。
またどこかおかしいらしい。次はこの解析。

っと思ったら、.hexのパスが間違ってた。DWM200710付属のmemcvt.exeで.hex生成してから、
hex内のアドレスをRubyで修正していて、修正版の.hexを使ってなかった事が原因でした。

■.hexのアドレス数間違ってる?
Veritakでこんなエラーが。

readmemb(h) ./inst_ram_data.ver Access Error accessing address=800 min_address=7ff max_address=0
In module:tb_mico32_neek.uut.mico32.inst_rom32_core.inst_ram.altsyncram_component.m_non_arria10.altsyncram_inst;
C:\user\onedrive\vm_share\de0_nano\mico32\rtlsim\rtl\altera_mf.v(48133)::
readmemb(h) ./data_ram_data.ver Access Error accessing address=800 min_address=7ff max_address=0
In module:tb_mico32_neek.uut.mico32.data_ram32_core.data_ram.altsyncram_component.m_non_arria10.altsyncram_inst;
C:\user\onedrive\vm_share\de0_nano\mico32\rtlsim\rtl\altera_mf.v(48133)::



Mico32命令メモリとして使ってるアルテラメモリIPの初期値ファイルを試しにQuartusで作ってみる。

Quartus II 14.1 > File > New > Memory Initialization File
 > Number of Word=2047, Word size=32
 > メモリアレイ内で右クリック > Custom Fill Cell...
 > Starting Address=0、Ending Address=2048、Starting Value=0、Increment by=1
 > OKを押して値がセットされた。保存するとmifファイルが生成される。

.hexしか使えないと思ってたが、.mifが使えるなら、その方が記述簡単そうだ。

.mifを使う方向で再度、おさらい。
・DWM200710付属memcvt.exeでelfから.mifを生成。
・そこで生成された.mifは以下のフォーマットだった。

DEPTH=1024;
WIDTH=32;
ADDRESS_RADIX = HEX;
DATA_RADIX = HEX;
CONTENT
BEGIN
00000000:e0000040;
00000001:00000000;
00000002:00000000;
00000003:00000000;
00000004:00000000;
00000005:00000000;
00000006:00000000;
00000007:00000000;
00000008:e000006d;
00000009:00000000;
  :
000003fd:00000000;
000003fe:00000000;
000003ff:00000000;
END;


・Word=1024になってるが、実際に今使ってるQuartusのRAM IPは2048にしてた。
 RAM IPをWord=1024に変更して、生成した.mifがそのまま読み込めるようにした。
・Veritakで確認してみても、シミュレーション開始時エラー無く.mifが読めてる。
・先のVeritakでのエラー(inst_ram_data.ver Access Error accessing address=800・・・)
 の原因は初期値ファイルのアドレスサイズと実際のRAM定義が違っていた模様。

■0x60c配置mainプログラムはどこにある?
・Mico32用にビルドしたelfのobjdump -d .elf結果では、以下だった。

uart_int: file format elf32-lm32

Disassembly of section .start:

00000000 <_sstarttext>:
0: e0 00 00 40 bi 100 <__startup>
...
20: e0 00 00 6d bi 1d4 <__break_interrupt>
  :
00000100 <__startup>:
100: 78 1c 20 00 mvhi sp,0x2000
104: 3b 9c 1f fc ori sp,sp,0x1ffc
108: e0 00 01 41 bi 60c


  :
0000060c <main>:
60c: 37 9c ff ec addi sp,sp,-20
610: 5b 9b 00 08 sw (sp+8),fp
614: 5b 9d 00 04 sw (sp+4),ra
618: 34 1b 00 14 mvi fp,20
 ※ mainのかっこは全角<>にしてます。
   半角だとHTML記述?に関係して表示されなかったため。


・リセット解除後、0x000 > 0x100(__startup) > 0x60c(main)と進む。
・mainが配置されるべき0x60c=dec1548なので、生成したRAMのword=1024をこえてる。
・.mifの中身を追うと、以下を発見出来る。

00000183:379cffec;
00000184:5b9b0008;
00000185:5b9d0004;
00000186:341b0014;
00000187:b77cd800;
00000188:78012000;
00000189:38210000;
0000018a:28210000;
0000018b:5b61fffc;
0000018c:78012000;
0000018d:38210004;
0000018e:34020000;


これはobjdumpして確認出来るmain関数の最初と命令コードが全て一致。

0000060c <main>:
60c: 37 9c ff ec addi sp,sp,-20
610: 5b 9b 00 08 sw (sp+8),fp
614: 5b 9d 00 04 sw (sp+4),ra
618: 34 1b 00 14 mvi fp,20
61c: b7 7c d8 00 add fp,fp,sp
620: 78 01 20 00 mvhi r1,0x2000
624: 38 21 00 00 ori r1,r1,0x0
628: 28 21 00 00 lw r1,(r1+0)
62c: 5b 61 ff fc sw (fp+-4),r1
630: 78 01 20 00 mvhi r1,0x2000
634: 38 21 00 04 ori r1,r1,0x4
638: 34 02 00 00 mvi r2,0


・.mifにおけるmain開始位置は0x183=dec387と分かった。
 387*4=1548であり、0x60c=dec1548と一致。
・そういえばDWM200710付属のRTLは命令メモリアドレスは下位2bitを抜かしてRAMへ接続していた。
 そういう事か。
 下位2bitを抜かす事で、実際の命令アドレス信号の1/4サイズのRAMで対応させてると。

■これでLEDチカチカが動いた!
 以上の事を踏まえ、system_top.v(Mico32のトップmodule)の以下を修正し、LEDチカチカ出来た。

inst_ram_altera inst_rom32_core (
// .addr(inst_sram_addr[9:0]), // 2015.2.1
.addr(inst_sram_addr[11:2]), // 2015.2.1

カレンダー
01 | 2024/02 | 03
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 - -
累積訪問者
現在の訪問者
現在の閲覧者数:
最新記事
最新トラックバック
最新コメント
月別アーカイブ
カテゴリ
プロフィール

bobgosso

Author:bobgosso
FPGAのブログへようこそ!

検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード