前回のシミュレーション環境を少し修正してM0プログラムを動かしてみます。
プログラムのコンパイルはarm-gccを使用します。
aptからインストールしました。
$ sudo apt install gcc-arm-none-eabi $ arm-none-eabi-gcc -v gcc version 8.3.1 20190703 (release) [gcc-8-branch revision 273027] (15:8-2019-q3-1+b1)
若干、リビジョンが古いようですので気になる方はこちらから最新をダウンロードするのが良いと思います。
https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
my_test.vは以下のように修正しています。
`timescale 1ns/1ns module my_test(); reg clk; reg reset_n; wire [31:0] HADDR; wire [2:0] HSIZE; wire [1:0] HTRANS; wire [31:0] HWDATA; wire HWRITE; wire [31:0] HRDATA; wire HREADY; wire HRESP; parameter ADDR_FINISH = 32'h0000fffc; CORTEXM0INTEGRATION CORTEXM0INTEGRATION( ~省略~ ); cmsdk_ahb_ram_beh #( .AW ( 16 ) ,.filename( "test.vmem" ) ,.WS_N ( 0 ) ,.WS_S ( 0 ) )cmsdk_ahb_ram_beh( ~省略~ ); always #100 clk = ~clk; initial begin clk = 1'b0; reset_n = 1'b0; #250 reset_n = 1'b0; #250 reset_n = 1'b1; repeat(10) @(posedge clk); repeat(20000) @(posedge clk); $display("*** Simulation timeout... ***"); $finish; end initial begin repeat(10) @(posedge clk); forever begin @(posedge clk); if(HADDR==ADDR_FINISH && HTRANS==2'b10 && HWRITE==1'b1 && HREADY==1'b1)begin repeat(3) @(posedge clk); $display("*** Simulation finish... ***"); $finish; end end end initial begin $dumpvars(); end endmodule
修正点としてはメモリモデルのインスタンス時にパラメータを渡しています。
cmsdk_ahb_ram_beh #( .AW ( 16 ) ← アドレスバス幅(内部メモリのwordサイズにも使用されている) ,.filename( "test.vmem" ) ← シミュレーション開始時に内部メモリに展開するファイル名 ,.WS_N ( 0 ) ← アクセス時のウェイト数?(良くわからないのでデフォルトのまま) ,.WS_S ( 0 ) )cmsdk_ahb_ram_beh(
その他、0xfffc番地にライトアクセスが発生したら3サイクル後にシミュレーションを終了するようにしています。
(ライトアクセスが発生しない時は20000サイクル後にタイムアウト終了)
parameter ADDR_FINISH = 32'h0000fffc; initial begin repeat(10) @(posedge clk); forever begin @(posedge clk); if(HADDR==ADDR_FINISH && HTRANS==2'b10 && HWRITE==1'b1 && HREADY==1'b1)begin repeat(3) @(posedge clk); $display("*** Simulation finish... ***"); $finish; end end end
プログラム環境は、4つのファイルで構成しています。
- startup.s:ブートプログラム
.equ STACK_TOP, 0xff00 .global _start .section .isr_vector, "a", %progbits .align 4 _vect_table: .word STACK_TOP .word (_start + 1) .align 4 _start: bl main _loop: nop nop nop b _loop .align 4
0x00番地に配置するスタックアドレスは0xff00に設定しています。
- test.c:メインプログラム
#define ADDR_FINISH 0xfffc #include <sys/types.h> int main(void){ *(volatile uint32_t*)(ADDR_FINISH) = 0xff; return 1; }
実行直後に0xfffc番地へライトを行うのでシミュレーションが終了する予定です。
- test.ld:リンカスクリプト
ENTRY(_start) MEMORY{ ROM (xr) : ORIGIN = 0x00000000, LENGTH = 32K RAM (xw) : ORIGIN = 0x00008000, LENGTH = 32K } SECTIONS{ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) . = ALIGN(4); } > ROM .text : { . = ALIGN(4); *(.text) *(.text*) . = ALIGN(4); } > ROM .rodata : {} > ROM .data : {} > RAM .bss : {} > RAM }
64Kバイトのメモリモデルの前半32KバイトをROM領域に、後半32KバイトをRAM領域に設定しています。
TARGET = test all: arm-none-eabi-as -mcpu=cortex-m0 -mthumb startup.s -o startup.o arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -Os -c $(TARGET).c -o $(TARGET).o arm-none-eabi-ld -T $(TARGET).ld startup.o $(TARGET).o -o $(TARGET).elf arm-none-eabi-objcopy -O verilog $(TARGET).elf $(TARGET).vmem --verilog-data-width=1 dos2unix $(TARGET).vmem arm-none-eabi-objdump $(TARGET).elf --disassemble-all > $(TARGET).lst clean: $(RM) *.elf *.bin *.o *.lst *.vmem
コンパイル→リンク後、objcopyでelfファイルをVerilogHDLの$readmemh向けのフォーマットに変換します。
また、objdumpで逆アセンブルも行います。
makeでエラーが出なければコンパイル成功です。
逆アセンブルしたtest.lstを確認してみます。
Disassembly of section .isr_vector: 00000000 <_vect_table>: ↓ スタックアドレスに0xff00を設定 0: 0000ff00 andeq pc, r0, r0, lsl #30 ↓ 0x10番地の _start へジャンプ(LSBの1はthumb命令の意味) 4: 00000011 andeq r0, r0, r1, lsl r0 ... 00000010 <_start>: ↓ test.c のmain関数は0x20番地 10: f000 f806 bl 20 <main> 00000014 <_loop>: 14: 46c0 nop ; (mov r8, r8) 16: 46c0 nop ; (mov r8, r8) 18: 46c0 nop ; (mov r8, r8) 1a: e7fb b.n 14 <_loop> 1c: 00000000 andeq r0, r0, r0 Disassembly of section .text: 00000020 <main>: ↓ 0xffをr2へセット 20: 22ff movs r2, #255 ; 0xff ↓ 0x2c番地にセットされている値(0xfffc)をr3へセット 22: 4b02 ldr r3, [pc, #8] ; (2c <main+0xc>) 24: 2001 movs r0, #1 ↓ r3の値(0xfffc)へr2の値(0xff)をライト 26: 601a str r2, [r3, #0] 28: 4770 bx lr 2a: 46c0 nop ; (mov r8, r8) 2c: 0000fffc strdeq pc, [r0], -ip
問題無さそうです。
メモリモデルがロードする test.vmem も問題無さそうです。
@00000000 00 FF 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 F0 06 F8 C0 46 C0 46 C0 46 FB E7 00 00 00 00 @00000020 FF 22 02 4B 01 20 1A 60 70 47 C0 46 FC FF 00 00
test.vmem をシミュレーション実行と同じディレクトリに置いてシミュレーションを実行します。
終了メッセージが表示されたので意図した動作になっているようです。
*** Simulation finish... ***
波形で確認しても0xfffcへライトした3サイクル後にシミュレーションが終了しています。