で出力された default_code_tb.txt, default_data_tb.txt の内容を
sc1_cpu/testbench/testbench.v の
「// program start here --------」「// data start here --------」と書かれた場所にコピペしてから実行してください。
このCPUでプログラミングする方法
sc1_cpu/asm 以下にJava上で動作する簡易アセンブラが入っています。
実行にはOpenJDK 8.0以上のインストールが必要です。
AsmLibクラスを継承したクラスを作り、init()で初期化設定、program()にプログラム、data()にデータを記述します。AsmTop.javaも修正します。
sc1_cpuディレクトリに移動して make を実行するとプログラム・バイナリが出力されます。
PCとFPGAをUARTで接続し、 make run を実行するとバイナリがFPGAに転送されて実行されます。
詳しくはExamples.javaのソースコードを参照してください。
SC1-SoCからのUART出力を使用するプログラムでは、あらかじめ別のターミナル上で、
cd sc1_cpu/tools
./reciever
を実行してください。
/*
Copyright (c) 2015-2018, miya
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// switch source // source_a
always @*
begin
if (addr_mode_a != ADDR_MODE_0)
begin
source_a = mem_d_r_a;
end
else
begin
if (reg_mode_a == TRUE)
begin
source_a = ims_a;
end
else
begin
source_a = reg_file[reg_a_addr];
end
end
end // source_b
always @*
begin
if (addr_mode_b != ADDR_MODE_0)
begin
source_b = mem_d_r_b;
end
else
begin
if (reg_mode_b == TRUE)
begin
source_b = ims_b;
end
else
begin
source_b = reg_file[reg_b_addr];
end
end
end
// switch operation
function [WIDTH_D-1:0] result
(
input [6:0] op_result
);
begin
case (op_result)
I_ADD: result = source_a + source_b;
I_SUB: result = source_a - source_b;
I_AND: result = source_a & source_b;
I_OR: result = source_a | source_b;
I_XOR: result = source_a ^ source_b;
I_NOT: result = ~source_a;
I_SR: result = source_a >> source_b;
I_SL: result = source_a << source_b;
I_SRA: result = $signed(source_a) >>> source_b;
`ifdef DISABLE_MUL
`else
I_MUL: result = $signed(source_a) * $signed(source_b);
`endif
default: result = ZERO;
endcase
end
endfunction
req_stop_d1 <= req_stop;
if (req_stop_d1 == TRUE)
begin
stopped <= TRUE;
req_stop <= FALSE;
end
if (stopped == FALSE)
begin // addressing
case (addr_mode_d_s1)
ADDR_MODE_0:
begin
mem_d_addr_w_d0 <= mem_d_addr_w_d0;
mem_d_addr_w_s_d0 <= mem_d_addr_w_s_d0;
end
ADDR_MODE_1:
begin
mem_d_addr_w_d0 <= reg_file[reg_d_addr_s1][DEPTH_D-1:0];
mem_d_addr_w_s_d0 <= reg_file[reg_d_addr_s1][DEPTH_D-1:0];
end
ADDR_MODE_2:
begin
mem_d_addr_w_d0 <= mem_d_addr_w_s_d0;
mem_d_addr_w_s_d0 <= mem_d_addr_w_s_d0 + reg_file[reg_d_addr_s1][DEPTH_D-1:0];
end
ADDR_MODE_3:
begin
mem_d_addr_w_d0 <= $signed(mem_d_addr_w_s_d0) + ims_d_s1;
mem_d_addr_w_s_d0 <= mem_d_addr_w_s_d0;
end
endcase
case (addr_mode_a_s1)
ADDR_MODE_0:
begin
mem_d_addr_r_a <= mem_d_addr_r_a;
mem_d_addr_r_a_s <= mem_d_addr_r_a_s;
end
ADDR_MODE_1:
begin
mem_d_addr_r_a <= reg_file[reg_a_addr_s1][DEPTH_D-1:0];
mem_d_addr_r_a_s <= reg_file[reg_a_addr_s1][DEPTH_D-1:0];
end
ADDR_MODE_2:
begin
mem_d_addr_r_a <= mem_d_addr_r_a_s;
mem_d_addr_r_a_s <= mem_d_addr_r_a_s + reg_file[reg_a_addr_s1][DEPTH_D-1:0];
end
ADDR_MODE_3:
begin
mem_d_addr_r_a <= $signed(mem_d_addr_r_a_s) + ims_a_s1;
mem_d_addr_r_a_s <= mem_d_addr_r_a_s;
end
endcase
case (addr_mode_b_s1)
ADDR_MODE_0:
begin
mem_d_addr_r_b <= mem_d_addr_r_b;
mem_d_addr_r_b_s <= mem_d_addr_r_b_s;
end
ADDR_MODE_1:
begin
mem_d_addr_r_b <= reg_file[reg_b_addr_s1][DEPTH_D-1:0];
mem_d_addr_r_b_s <= reg_file[reg_b_addr_s1][DEPTH_D-1:0];
end
ADDR_MODE_2:
begin
mem_d_addr_r_b <= mem_d_addr_r_b_s;
mem_d_addr_r_b_s <= mem_d_addr_r_b_s + reg_file[reg_b_addr_s1][DEPTH_D-1:0];
end
ADDR_MODE_3:
begin
mem_d_addr_r_b <= $signed(mem_d_addr_r_b_s) + ims_b_s1;
mem_d_addr_r_b_s <= mem_d_addr_r_b_s;
end
endcase
// loop counter
if (loop_end == mem_i_addr_r)
begin
if ((loop_counter != ZERO) && (op != I_LOOP))
begin
loop_counter <= loop_counter - ONE;
end
end
// increment pc (prefetch address)
if (!not_increment)
begin
if (loop_end == mem_i_addr_r)
begin
if (loop_counter == ZERO)
begin
mem_i_addr_r <= mem_i_addr_r + ONE;
end
else
begin
mem_i_addr_r <= mem_i_addr_r + loop_span;
end
end
else
begin
mem_i_addr_r <= mem_i_addr_r + ONE;
end
end
// execution
if (is_type_normal)
begin // for normal instructions
case (addr_mode_d)
ADDR_MODE_0:
begin
reg_file[reg_d_addr] <= result(op);
end
ADDR_MODE_1, ADDR_MODE_2, ADDR_MODE_3:
begin
mem_d_w <= result(op);
end
endcase
end
else
begin // special instructions
case (op)
I_HALT:
begin
req_stop <= TRUE;
end
I_NOP:
begin
end
I_MV:
begin
if (reg_file[SP_REG_CP] != ZERO)
begin
case (addr_mode_d)
ADDR_MODE_0:
begin
reg_file[reg_d_addr] <= source_a;
end
ADDR_MODE_1, ADDR_MODE_2, ADDR_MODE_3:
begin
mem_d_w <= source_a;
end
endcase
end
end
I_MVI:
begin
reg_file[SP_REG_MVI] <= im16;
end
I_MVIH:
begin
if (WIDTH_D >= 16)
begin
reg_file[SP_REG_MVI] <= {im16, reg_file[SP_REG_MVI][15:0]};
end
end
I_CEQ:
begin
if (source_a == source_b)
begin
reg_file[SP_REG_CP] <= FFFF;
end
else
begin
reg_file[SP_REG_CP] <= ZERO;
end
end
I_CGT:
begin
if (source_a > source_b)
begin
reg_file[SP_REG_CP] <= FFFF;
end
else
begin
reg_file[SP_REG_CP] <= ZERO;
end
end
I_CGTA:
begin
if ($signed(source_a) > $signed(source_b))
begin
reg_file[SP_REG_CP] <= FFFF;
end
else
begin
reg_file[SP_REG_CP] <= ZERO;
end
end
I_BC:
begin
if (reg_file[SP_REG_CP] == ZERO)
begin
mem_i_addr_r <= mem_i_addr_r + ONE;
end
else
begin
mem_i_addr_r <= pc_d3 + reg_file[SP_REG_BA];
end
end
I_BL:
begin
reg_file[SP_REG_LINK] <= pc_d3 + DELAY_SLOT_P1;
mem_i_addr_r <= pc_d3 + reg_file[SP_REG_BA];
end
I_BA:
begin
mem_i_addr_r <= reg_file[SP_REG_BA];
end
I_LOOP:
begin
loop_counter <= reg_file[SP_REG_LOOP_COUNTER];
loop_end <= pc_d3 + reg_file[SP_REG_LOOP_END][DEPTH_I-1:0];
loop_span <= reg_file[SP_REG_LOOP_SPAN][DEPTH_I-1:0];
end
default: ;
endcase
end
end
else
begin // if stopped == TRUE
if (resume_pulse == TRUE)
begin
stopped <= FALSE;
mem_i_addr_r <= mem_i_addr_r + ONE;
end
end
end
end
// create resume_pulse
always @(posedge clk)
begin
resume_d1 <= resume;
end