11.GCCによるデバッグRTLシミュレーション


一通り、アセンブラでテストしましたが、テストできなかった命令があることやインプリメントしていない命令もあるので(GCCがとりあえずそれを吐かなければよしとしています。)簡単なCプログラムを走らせてデバッグを続けます。とりあえず、GCCのデバッグ環境を構築します。

GCCはSH2で使用したCコンパイラ(ベストテクノロジー)を使用します。ただし、ROM/RAMのアドレス空間、配置がオリジナルではあり得ない仕様なのでそのままでは使用できません。ROM/RAMのアドレス配置をGCCに教えるにはリンカスクリプトで指定します。16KBのRAM空間を宣言し、0番地にReset Vector,3efc番地にStackTopを配置します。最後の100番地分は、8ビットで絶対アドレスでアクセス可能な領域になります。


リンカスクリプト h8300_tak.x

OUTPUT_ARCH(h8300h)
ENTRY("_start")
MEMORY {
        vectors : org =0x000000, len =0x100
        rom     : org =0x000100, len =14k-0x100
        ram     : org =0x003800, len =2k-100
        eight   : org =0xffff00, len =0x100
}
SECTIONS {
        .vectors : {
                /* Use something like this to place a specific function's address
                   into the vector table.  */
                /* 0x00 */
                LONG(ABSOLUTE(_start))
           
                FILL(0xff)
               }  > vectors
        .text : {
                CREATE_OBJECT_SYMBOLS
                *(.text)
                etext = .;
                } > rom
        .init : {
                *(.init)
                } > rom
        .fini : {
                *(.fini)
                } > rom
        .got : {
                *(.got)
                *(.got.plt)
                } > rom
        .rodata :  {
                *(.rodata)
                *(.rodata.*)
                _erodata = .;
                } > rom
        .eh_frame_hdr : { 
                *(.eh_frame_hdr)
                }> rom
        .eh_frame :  { 
                *(.eh_frame)
                }> rom
        .jcr : { 
                *(.jcr)
                } > rom
        .tors : {
                __CTOR_LIST__ = .; 
                LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) 
                ___ctors = . ; 
                *(.ctors)
                ___ctors_end = . ; 
                LONG(0) 
                __CTOR_END__ = .; 
                __DTOR_LIST__ = .; 
                LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) 
                ___dtors = . ; 
                *(.dtors)
                ___dtors_end = . ; 
                LONG(0) 
                __DTOR_END__ = .; 
                _mdata = .; 
                } > rom
        .data : AT (_mdata) { 
                _data = .;
                *(.data) 
                _edata = .; 
                } > ram
        .gcc_exc : {
                *(.gcc_exc)
                } > ram
        .bss : {
                _bss = . ;
                *(.bss)
                *(COMMON)
                _ebss = . ;
                _end = . ;
                } > ram
        .stack 0x003f0c : {
                 _stack = . ;
                *(.stack)
                } > ram
        .eight : {
                *(.eight)
                }  > eight
        .stab . (NOLOAD) :  { 
                [ .stab ] 
                } 
        .stabstr . (NOLOAD) : { 
                [ .stabstr ] 
                } 
        /DISCARD/ : {
                *(.comment)
                }
}


以下は、筆者環境下での、

バッチファイルです。

"D:\Program Files\BestTech\GCC Developer Lite\GCC\H8\bin\h8300-coff-gcc" -I D:\PROGRA~1\BestTech\GCCDEV~1\TARGET\3052F -L D:\PROGRA~1\BestTech\GCCDEV~1\TARGET\3052F -mh -nostartfiles -O2 -Wl,--script=h8300_tak.x -Wl,-Map,H8.map h8crt0_tak.s simple_test1.c -ladd3052 -lm -o h8.coff
"D:\Program Files\BestTech\GCC Developer Lite\GCC\H8\bin\h8300-coff-objcopy" -O srec h8.coff h8.mot 
"D:\Program Files\BestTech\GCC Developer Lite\GCC\H8\bin\h8300-coff-objdump" -d  h8.coff > h8.txt
"F:\altera\h8_project\h8writer\ASM\genromh8_1" h8.mot -16
copy code0.hex f:\altera\h8_project\*.*
copy code1.hex f:\altera\h8_project\*.*
copy code2.hex f:\altera\h8_project\*.*
copy code3.hex f:\altera\h8_project\*.*
copy code4.hex f:\altera\h8_project\*.*
copy code5.hex f:\altera\h8_project\*.*
copy code6.hex f:\altera\h8_project\*.*
copy code7.hex f:\altera\h8_project\*.* 

例によってテストベンチにはデバッグ用ポートを追加します。
アドレス70hをデバッグの出力ポートとします。

`timescale 1ns/1ps

module h8_test;
        reg clock=0;
        reg sync_reset=1;
        wire [31:0] MOUT;
        reg int_req2=0;
        wire int_req2_ack;
        wire [13:0] monitor_daddr;
        wire  [31:0] monitor_in_data;
        wire  monitor_ram_write;

       initial begin

        #10000;
        //      int_req2=1;
        //      wait(int_req2_ack);
        //      int_req2=0;

        end     
        

 H8  cpu(.clock(clock),.sync_reset(sync_reset),.MOUT(MOUT),.int_req2(int_req2),
         .int_req2_ack(int_req2_ack),.monitor_daddr(monitor_daddr),
         .monitor_in_data(monitor_in_data), .monitor_ram_write(monitor_ram_write));

        always #10 clock=~clock;
                initial begin 
                        #205 ;
                        sync_reset=0;
                        #500000000;
                        $finish;
                end
     //TAK                             
      `define Print_Port_Address     14'h0070  
      `define Print_CAHR_Port_Address 14'h0072
      `define Print_INT_Port_Address  14'h0074
      `define Print_LONG_Port_Address 14'h0076

        task Cprint;// String OUT until the byte 00 or xx detected with least Byte first and justified.
                integer i;
                begin :Block
                        i=0;
                        while (1) begin
                                if (char_buffer[i*8 +:8] ===8'h00 || char_buffer[i*8 +:8]===8'hxx) begin
                                                disable Block;
                                end     
                                $write("%c",char_buffer[i*8 +:8]);
                                i=i+1;  
                        end
                end
        endtask

   reg [0:639] char_buffer;
   integer  counter=0;    
   always @ (posedge clock ) begin
            if ((monitor_ram_write === 1'b1)) begin 
                   if (monitor_daddr==`Print_Port_Address) begin
                                if (monitor_in_data[7:0]===8'h00) begin
                                        char_buffer[counter*8 +:8]=monitor_in_data[7:0];
                                        if (char_buffer[0  +:8*7]==="$finish") begin
                                                        $stop;                          
                                                        
                                        end else if (char_buffer[0  +:8*5]==="$time") begin
                                                        $display("Current Time on Simulation=%d",$time);                                
                                                        
                                        end else  Cprint;//$write("%s",char_buffer);

                                        for (counter=0; counter< 80; counter=counter+1) begin
                                                char_buffer[counter*8 +:8]=8'h00;
                                        end
                                        counter=0;
                                
                                end else begin
                                        char_buffer[counter*8 +:8]=monitor_in_data[7:0];
                                        counter=counter+1;
                                end
                   end
           else if (monitor_daddr==`Print_CAHR_Port_Address) begin
                                $write("%h ",monitor_in_data[7:0]);
                   end else if (monitor_daddr==`Print_INT_Port_Address) begin
                                $write("%h ",monitor_in_data[15:0]);//Little Endian 
                   end else if (monitor_daddr==`Print_LONG_Port_Address) begin
                                $write("%h ",monitor_in_data[31:0]);//Big Endian
                   end 
        end //if
   end //always


endmodule


これに合わせて論理合成TOP層も書き換えます。

//May.31.2004
//Jun.5.2004 Add debug port
`include "define.h"
module H8(clock,sync_reset,MOUT,int_req2,int_req2_ack,
         monitor_daddr,monitor_in_data,  monitor_ram_write);
        input clock;
        input sync_reset;
        output [31:0] MOUT;
        input int_req2;
        output int_req2_ack;
        output [13:0] monitor_daddr;
        output  [31:0] monitor_in_data;
        output  monitor_ram_write;


        
        reg [7:0] int_vector=8'h20;//Interim May.31.2004
        reg [12:0]      

//ram_module
                wire  ram_write;
                wire [1:0] ram_access_mode;
                wire [1:0] paddress_sel;
                wire data_address_latch;
                wire ram_data_in_sel;

//ea_unit
                wire  [3:0] ea_left_sel;
                wire  [2:0] ea_right_sel;
              wire  [3:0] ea_reg_address;//Jun.3.2004

                wire  [2:0] next_pc_offset;
                
//alu
                wire [1:0] alu_left_sel;
                wire [3:0] alu_right_sel;
                wire [4:0] ope;
                wire imm_sel;
              wire v_clear,h_latch,n_latch,z_latch,v_latch,c_latch, ccr_all_write;
                wire [1:0] ccr_input_sel;
                wire [1:0] bus_state;
                wire [1:0] alu_access_mode;

                wire [1:0] left_address_sel, right_address_sel;
                wire [2:0] write_address_sel;
                wire [1:0] reg_file_access_mode;
              wire reg_write;
              wire insel;


                 wire [63:0] irword;
                 wire [31:0]  MOUT;
             wire [31:0] ALU_OUT;
               wire [23:0] EA,pc_reg;
              
                wire [31:0] RO_left,RO_right,left_address_out;
                wire [31:0] z_bus;
                wire [7:0] CCR;
                wire  BCC_jmp;
            wire [7:0] IR1=irword[23+32:16+32];
              wire [7:0] IR3=irword[23+32-16:16+32-16];
                wire i_bit;
                wire [7:0] state;
                wire stop_state;
                wire [31:0] reg_out_for_mul_div;
        assign ea_reg_address=ea_left_sel==`PC_SEL ? IR1[3:0]  : //Jun.3.2004
                                               ea_left_sel==`ABS8_SEL ? IR3[3:0] : //Jun.3.2004
                                                 ea_left_sel==`IR1H_SEL_EA? IR1[7:4] :IR3[7:4];//May.31.2004
        assign reg_out_for_mul_div=alu_access_mode == `LONG_ACCESS ? left_address_out : 
                                    alu_access_mode == `WORD_ACCESS ? ( ea_reg_address[3] ==1'b1 ? {16'h0000,left_address_out[31:16]} : {16'h0000,left_address_out[15:0]} ) :
                                    ea_reg_address[3] ==1'b0 ? {24'h00_0000,left_address_out[15:8]} : {24'h00_0000,left_address_out[7:0]} ; //Note: register field mapping R0H =>0000, R0L=>1000 
//      always @(negedge clock) temp <=mul_div_dest_reg_out;
        
decoder d1(clock,sync_reset, ram_write,ram_access_mode,data_address_latch,
                 ram_data_in_sel,irword, ea_left_sel, ea_right_sel,next_pc_offset,
                 alu_left_sel,alu_right_sel,ope,alu_access_mode,imm_sel,v_clear,h_latch,n_latch,z_latch,v_latch,c_latch,
                 ccr_all_write,bus_state,ccr_input_sel,paddress_sel,
                 left_address_sel, right_address_sel,write_address_sel,reg_file_access_mode,
               reg_write, insel,int_req2,int_req2_ack,i_bit,stop_state,state);
/* decoder decoder1(clock,sync_reset, ram_write,ram_access_mode,data_address_latch,
                 ram_data_in_sel,irword, ea_left_sel, ea_right_sel,next_pc_offset,
                 alu_left_sel,alu_right_sel,ope,alu_access_mode,imm_sel,v_clear,h_latch,n_latch,z_latch,v_latch,c_latch,
                 ccr_all_write,bus_state,ccr_input_sel,paddress_sel,
                 left_address_sel, right_address_sel,write_address_sel,reg_file_access_mode,
               reg_write, insel,int_req2,int_req2_ack,i_bit,state,stop_state,state);
*/

  h8_ram_module ram_module (.clock(clock),.sync_reset(sync_reset),.ram_write(ram_write),
  .paddress_sel(paddress_sel),.EA(EA),.data_address_latch(data_address_latch),
  .bcc_ea_sel(BCC_jmp),.IR(irword),.MOUT(MOUT),.access_mode(ram_access_mode),
  .ALU_OUT(z_bus),.ram_data_in_sel(ram_data_in_sel),.pc_reg(pc_reg),.next_pc_offset(next_pc_offset),.ea_left_sel(ea_left_sel),.CCR(CCR),.bus_state(bus_state));

ALU alu(.clock(clock),.sync_reset(sync_reset),.alu_left_sel(alu_left_sel),
        .alu_right_sel(alu_right_sel),.ope(ope),.imm_sel(imm_sel),.v_clear(v_clear),
          .h_latch(h_latch),.n_latch(n_latch),.z_latch(z_latch),.v_latch(v_latch),.c_latch(c_latch),
          .ccr_all_write(ccr_all_write),.access_mode(alu_access_mode),
          .RO_left(RO_left),.RO_right(RO_right),.irword(irword),.MOUT(MOUT),
          .bus_state(bus_state),.ccr_input_sel(ccr_input_sel),.z_bus(z_bus),.CCR(CCR),.BCC_jmp(BCC_jmp),.i_bit(i_bit),.stop_state(stop_state),.state(state),
          .mul_div_dest_reg(reg_out_for_mul_div),.mul_div_address3(ea_reg_address[3]));//Jun.3.2004

ea_unit EA_Unit(.clock(clock),.sync_reset(sync_reset),.EA(EA),.irword(irword),.ea_left_sel(ea_left_sel),
                .ea_right_sel(ea_right_sel),
                .RO_left(left_address_out),.alu_out(z_bus),.MOUT(MOUT),.pc_reg(pc_reg),.next_pc_offset(next_pc_offset),.int_vector(int_vector));

 reg_file  RegFile(.clock(clock),.sync_reset(sync_reset),.irhword(irword[63:32]),
           .left_address_sel(left_address_sel),.right_address_sel(right_address_sel),
           .write_address_sel(write_address_sel), .access_mode(reg_file_access_mode),
           .reg_write(reg_write),.alu_out(z_bus),.ea(EA),
           .reg_left_out(RO_left), .reg_right_out(RO_right),.insel(insel),.left_address_out(left_address_out),.ea_reg_address(ea_reg_address[2:0]));


        

endmodule

スタートアップルーチンはやはりカスタマイズが必要です。スタートアップルーチンの目的は、C言語のメインに行く前にスタックポインタの設定、割り込みのEnable、RAMの初期化です。main終了後にSleep命令が入っていましたが、Sleep命令はサポートしていないため書き換えました。

スタートアップルーチンのアセンブラソース h8crt0_tak.s

        .h8300h
        .section .text
        .global _start
        .global _exit

        .extern _main
        .extern _data
        .extern _mdata
        .extern _edata
        .extern _bss
        .extern _ebss
        .extern _stack

_start:
        mov.l   #_stack,sp

        ;; copy DATA from ROM
        mov.l   #_mdata,er0
        mov.l   #_data,er1
        mov.l   #_edata,er2
data_init_loop:
        cmp     er2,er1
        bge     fin_data_init
        mov.b   @er0+,r3l
        mov.b   r3l,@er1
        adds    #1,er1
        bra     data_init_loop
fin_data_init:

        ;; clear BSS
        mov.l   #_bss,er0
        mov.l   #_ebss,er1
        mov.b   #0,r2l
bss_init_loop:
        cmp     er1,er0
        bge     fin_bss_init
        mov.b   r2l,@er0
        adds    #1,er0
        bra     bss_init_loop
fin_bss_init:

        jsr     @_main

_exit:
       ;TAK sleep
        bra     _exit


さて、以上の準備を経てようやくC言語でテストソースを書くことができます。最初にやることは、デバッグポートを動作させることです。
デバッグのポイントは、いきなり大きなプログラムを走らせてデバッグをするのではなく、極小のプログラムからブートストラップしてことです。

最初のCプログラムはsimple_test1.cです。 プリントポートを叩いてメッセージを表示させてみましょう。

#define print_port      *(volatile unsigned char*)0x70 //unsigned char print_port;// String OUT port for verilog
#define print_char_port *(volatile unsigned char*)0x74  //      unsigned char* print_char_port;// char OUT port for verilog
#define print_int_port  *(volatile unsigned char*)0x76            //  int(16bit) OUT port for verilog
#define print_long_port *(volatile unsigned char*)0x78        //        unsigned long* print_long_port;// long(32bit) OUT port for verilog
        //Verilog Specific Routines
void print(unsigned char* ptr)//Verilog Test Bench Use 
{
        
        while (*ptr) {
                print_port=*(ptr++);
        }
        print_port=0x00;//Write Done
}

void print_char(unsigned char val)//Little Endian write out 16bit number 
{
        print_char_port=(unsigned char)val ;
        

}
void print_int(int val)//Little Endian write out 16bit number 
{       
        print_int_port=val ;

        

}

void print_long(unsigned long val)//Little Endian write out 32bit number 
{
        print_long_port=val;


}
void main()
{
        

        print("Welcome to H8300H CPU on Veritak Simulation World !!\n");
        print("           Jun.5.2004 www.sugawara-systemc.com \n\n");
        print("$finish");
        

}




たったこれだけのプログラムですが、設計したCPUがちゃんとやってくれると嬉しいものです。以下のように実行されました。


 さて、設計したコアの性能はどうなっているのでしょう。命令ステート数は、メモリリードを含まない命令の殆どを2ステートで実行しますのでざっくり30%程度CPIは向上している筈です。
 例によってベンチマークを駆動してみましょう。


実行時間は、1.28msとなりました。SH2に次ぐスピードです。