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に次ぐスピードです。