前回までのあらすじ
- 自作PCを作ろう!
- まずメモリを作ったよ!(動かしてない)
- ISAを作ったよ!(コンパイラはまだ)
- アセンブリ言語を作ったよ!(アセンブラはまだ)
よくある質問
Q. アセンブラを作るのではなかったですか?
A. 面倒だし本題からずれるのでやっぱやめます
前回からの変更
命令ADDI
とSUBI
を消しました.
符号ありと無しで動作が同じなので.
全体の構成
ソース
いっぱいあるんで省略表示で貼りますね.
util.svh
/**
* 特に分類できない共通系
*/
`ifndef UTIL_SVH
`define UTIL_SVH
package util_p;
typedef logic bool_t;
parameter bool_t TRUE = 1'b1;
parameter bool_t FALSE = 1'b1;
endpackage
`endif
machine.svh
/**
* 機械語を生成する関数
*/
`ifndef MACHINE_SVH
`define MACHINE_SVH
// 機械語の構成
//
// 31 29 28 23 22 19 18 13 12 7 6 1 0
// | type | func | mask | rs1 | rs2 | rd |imm| + イミディエイトデータ(32bit)
package machine_p;
typedef logic [63:0] machine_t; // 機械語のサイズ
typedef logic [ 2:0] type_t; // 命令タイプ
typedef logic [ 5:0] func_t; // 命令
typedef logic [ 3:0] mask_t; // マスクサイズ
typedef logic [ 5:0] addr_t; // レジスタのアドレスサイズ
typedef logic [32:0] imm_t; // イミディエイトデータのサイズ.最上位ビットはイミディエイトデータを使用するかのフラグ
// 各機械語
localparam func_t NOP = 6'h00;
localparam func_t AND = 6'h00;
localparam func_t OR = 6'h01;
localparam func_t XOR = 6'h02;
localparam func_t NOT = 6'h03;
localparam func_t NAND = 6'h04;
localparam func_t ADD = 6'h05;
localparam func_t SUB = 6'h06;
localparam func_t SLL = 6'h00;
localparam func_t SRL = 6'h01;
localparam func_t SLA = 6'h02;
localparam func_t SRA = 6'h03;
localparam func_t MOV = 6'h00;
localparam func_t EQ = 6'h00;
localparam func_t NE = 6'h01;
localparam func_t LT = 6'h02;
localparam func_t GT = 6'h03;
localparam func_t ELT = 6'h04;
localparam func_t EGT = 6'h05;
localparam func_t JMP = 6'h00;
localparam func_t RM = 6'h00;
localparam func_t WM = 6'h01;
localparam func_t BRM = 6'h02;
localparam func_t BWM = 6'h03;
// 処理を実行しない(N系)
function machine_t nop(
);
nop = {3'h0, NOP, 4'h0, 6'h00, 6'h00, 6'h00, 33'h000000000};
endfunction
// 演算系(P系)
function machine_t and_(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
and_ = {3'h1, AND, 4'h0, rs1, rs2, rd, imm};
endfunction
function machine_t or_(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
or_ = {3'h1, OR, 4'h0, rs1, rs2, rd, imm};
endfunction
function machine_t xor_(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
xor_ = {3'h1, XOR, 4'h0, rs1, rs2, rd, imm};
endfunction
function machine_t not_(
input addr_t rs1,
input addr_t rd,
input imm_t imm
);
not_ = {3'h1, NOT, 4'h0, rs1, 6'h00, rd, imm};
endfunction
function machine_t nand_(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
nand_ = {3'h1, NAND, 4'h0, rs1, rs2, rd, imm};
endfunction
function machine_t add(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
add = {3'h1, ADD, 4'h0, rs1, rs2, rd, imm};
endfunction
function machine_t sub(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
sub = {3'h1, SUB, 4'h0, rs1, rs2, rd, imm};
endfunction
// シフト系(S系)
function machine_t sll(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
sll = {3'h2, SLL, 4'h0, rs1, rs2, rd, imm};
endfunction
function machine_t srl(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
srl = {3'h2, SRL, 4'h0, rs1, rs2, rd, imm};
endfunction
function machine_t sla(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
sla = {3'h2, SLA, 4'h0, rs1, rs2, rd, imm};
endfunction
function machine_t sra(
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
sra = {3'h2, SRA, 4'h0, rs1, rs2, rd, imm};
endfunction
// 代入系(A系)
function machine_t mov(
input mask_t mask,
input addr_t rs1,
input addr_t rd,
input imm_t imm
);
mov = {3'h3, MOV, mask, rs1, 6'h00, rd, imm};
endfunction
// 分岐系(F系)
function machine_t eq(
input addr_t rs1,
input addr_t rs2,
input imm_t imm
);
eq = {3'h4, EQ, 4'h0, rs1, rs2, 6'h00, imm};
endfunction
function machine_t ne(
input addr_t rs1,
input addr_t rs2,
input imm_t imm
);
ne = {3'h4, NE, 4'h0, rs1, rs2, 6'h00, imm};
endfunction
function machine_t lt(
input addr_t rs1,
input addr_t rs2,
input imm_t imm
);
lt = {3'h4, LT, 4'h0, rs1, rs2, 6'h00, imm};
endfunction
function machine_t gt(
input addr_t rs1,
input addr_t rs2,
input imm_t imm
);
gt = {3'h4, GT, 4'h0, rs1, rs2, 6'h00, imm};
endfunction
function machine_t elt(
input addr_t rs1,
input addr_t rs2,
input imm_t imm
);
elt = {3'h4, ELT, 4'h0, rs1, rs2, 6'h00, imm};
endfunction
function machine_t egt(
input addr_t rs1,
input addr_t rs2,
input imm_t imm
);
egt = {3'h4, EGT, 4'h0, rs1, rs2, 6'h00, imm};
endfunction
// ジャンプ系(J系)
function machine_t jmp(
input addr_t rs1,
input imm_t imm
);
jmp = {3'h5, JMP, 4'h0, rs1, 6'h00, 6'h00, imm};
endfunction
// メモリ系(M系)
function machine_t rm(
input mask_t mask,
input addr_t rs1,
input addr_t rd,
input imm_t imm
);
rm = {3'h6, RM, mask, rs1, 6'h00, rd, imm};
endfunction
function machine_t wm(
input mask_t mask,
input addr_t rs1,
input addr_t rs2,
input imm_t imm
);
wm = {3'h6, WM, mask, rs1, rs2, 6'h00, imm};
endfunction
function machine_t brm(
input mask_t mask,
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
brm = {3'h6, BRM, mask, rs1, rs2, rd, imm};
endfunction
function machine_t bwm(
input mask_t mask,
input addr_t rs1,
input addr_t rs2,
input addr_t rd,
input imm_t imm
);
bwm = {3'h6, BWM, mask, rs1, rs2, rd, imm};
endfunction
endpackage
`endif
register.svh
/**
* レジスタに関する定義
*/
`ifndef REGISTER_SVH
`define REGISTER_SVH
`include "machine.svh"
// アドレスの定義
parameter machine_p::func_t SP_ADDR = 6'h10;
parameter machine_p::func_t FLG_ADDR = 6'h1c;
parameter machine_p::func_t RSI_ADDR = 6'h1d;
parameter machine_p::func_t RAX_ADDR = 6'h1e;
parameter machine_p::func_t PC_ADDR = 6'h1f;
parameter machine_p::func_t BTN_ADDR = 6'h20;
parameter machine_p::func_t SW_ADDR = 6'h21;
parameter machine_p::func_t LED_ADDR = 6'h22;
parameter machine_p::func_t RGB_LED_ADDR = 6'h23;
`endif
decorder.svh
/**
* デコーダーに関する関数
*/
`ifndef DECORDER_SV
`define DECORDER_SV
`include "machine.svh"
package decorder_p;
endpackage
// インターフェース定義
interface command_if; // 機械語から各値を取得してくるインターフェース
machine_p::machine_t machine;
machine_p::type_t m_type;
machine_p::func_t func;
machine_p::mask_t mask;
machine_p::addr_t rs1;
machine_p::addr_t rs2;
machine_p::addr_t rd;
machine_p::imm_t imm;
modport slave(
input machine,
output m_type,
output func,
output mask,
output rs1,
output rs2,
output rd,
output imm
);
modport master(
output machine,
input m_type,
input func,
input mask,
input rs1,
input rs2,
input rd,
input imm
);
endinterface
`endif
ram.svh
/**
* メインメモリに関する関数
*/
`ifndef RAM_SVH
`define RAM_SVH
`include "machine.svh"
package ram_p;
// 列挙体
typedef enum logic [1:0] { // メモリ読み出し・書き込み成否
NONE, // 初期状態
SUCCESS // 成功
} code_enum;
typedef enum logic [1:0] { // メモリ読み出し・書き込み状態
IDLE, // 待機状態
EXECUTE, // データ読み出し・書き込みの実行
RESPONSE // データ読み出し・書き込みのレスポンスを返す
} state_enum;
// 変数型
typedef logic [27:0] address_bus_t; // アドレスバス幅
typedef logic [31:0] data_bus_t; // データバス幅
typedef logic [27:0][ 7:0] memory_t; // メモリのデータ全体
endpackage
// インターフェース定義
interface ram_read_if; // メモリ読み込みインターフェース
ram_p::address_bus_t address;
ram_p::data_bus_t data;
machine_p::mask_t mask;
logic valid;
logic ready;
logic last;
ram_p::code_enum code;
modport slave(
input address,
output data,
input mask,
input valid,
output ready,
input last,
output code
);
modport master(
output address,
input data,
output mask,
output valid,
input ready,
output last,
input code
);
endinterface
interface ram_write_if; // メモリ書き込みインターフェース
ram_p::address_bus_t address;
ram_p::data_bus_t data;
machine_p::mask_t mask;
logic valid;
logic ready;
logic last;
ram_p::code_enum code;
modport slave(
input address,
input data,
input mask,
input valid,
output ready,
input last,
output code
);
modport master(
output address,
output data,
output mask,
output valid,
input ready,
output last,
input code
);
endinterface
`endif
rom.svh
/**
* ROMに関する関数
*/
`ifndef ROM_SVH
`define ROM_SVH
`include "ram.svh"
`include "machine.svh"
package rom_p;
typedef ram_p::address_bus_t pc_bus_t; // プログラムカウンタ
endpackage
// インターフェース定義
interface rom_read_if; // ROM読み込みインターフェース
rom_p::pc_bus_t pc;
machine_p::machine_t machine;
modport slave(
input pc,
output machine
);
modport master(
output pc,
input machine
);
endinterface
`endif
alu.svh
/**
* aluに関する関数など
*/
`ifndef ALU_SVH
`define ALU_SVH
`include "util.svh"
`include "decorder.svh"
package alu_p;
import machine_p::*;
// 列挙体
typedef enum type_t { // 機械語の命令タイプ
N_TYPE, // 処理を実行しない
P_TYPE, // 演算系
S_TYPE, // シフト系
A_TYPE, // 代入系
F_TYPE, // 分岐系
J_TYPE, // ジャンプ系
M_TYPE // メモリ系
} type_enum;
// 定数
localparam integer PC_ADDR = 6'h1f; // PCのアドレス
// 変数型
typedef logic [31:0] register_t; // レジスタサイズ
// 関数
function util_p::bool_t is_readable( // そのアドレスのレジスタが読み込み可能か
machine_p::addr_t addr
);
// CPU内のレジスタ
if (6'h00 <= addr && addr <= 6'h0f)
is_readable = util_p::TRUE;
// スタックポインタ
else if (addr == 6'h10)
is_readable = util_p::TRUE;
// 呼び出し関数の戻り先
else if (6'h11 <= addr && addr <= 6'h1a)
is_readable = util_p::TRUE;
// フラグ
else if (addr == 6'h1c)
is_readable = util_p::TRUE;
// 引数が格納されているレジスタの一つ目の番地
else if (addr == 6'h1d)
is_readable = util_p::TRUE;
// 演算結果
else if (addr == 6'h1e)
is_readable = util_p::TRUE;
// プログラムカウンタ
else if (addr == 6'h1f)
is_readable = util_p::TRUE;
// タクトスイッチ
else if (addr == 6'h20)
is_readable = util_p::TRUE;
// DIPスイッチ
else if (addr == 6'h21)
is_readable = util_p::TRUE;
// LED
else if (addr == 6'h22)
is_readable = util_p::FALSE;
// RGB LED
else if (addr == 6'h23)
is_readable = util_p::FALSE;
// Pmod A
else if (addr == 6'h24)
is_readable = util_p::TRUE;
// Pmod B
else if (addr == 6'h25)
is_readable = util_p::TRUE;
// AR
else if (addr == 6'h26 || addr == 6'h28)
is_readable = util_p::TRUE;
// I2C
else if (addr == 6'h27)
is_readable = util_p::TRUE;
// AR_RST
else if (addr == 6'h29)
is_readable = util_p::TRUE;
// SPI
else if (addr == 6'h2a)
is_readable = util_p::TRUE;
// アナログピン
else if (addr == 6'h2b)
is_readable = util_p::FALSE; // オミット
// XADC
else if (addr == 6'h2c)
is_readable = util_p::FALSE; // オミット
// GPIO
else if (6'h2d <= addr || addr <= 6'h30)
is_readable = util_p::TRUE;
// 定義されていない
else
is_readable = util_p::FALSE;
endfunction
function util_p::bool_t is_writable( // そのアドレスのレジスタが書き込み可能か
machine_p::addr_t addr
);
// CPU内のレジスタ
if (6'h00 <= addr && addr <= 6'h0f)
is_writable = util_p::TRUE;
// スタックポインタ
else if (addr == 6'h10)
is_writable = util_p::FALSE;
// 呼び出し関数の戻り先
else if (6'h11 <= addr && addr <= 6'h1a)
is_writable = util_p::FALSE;
// フラグ
else if (addr == 6'h1c)
is_writable = util_p::FALSE;
// 引数が格納されているレジスタの一つ目の番地
else if (addr == 6'h1d)
is_writable = util_p::FALSE;
// 演算結果
else if (addr == 6'h1e)
is_writable = util_p::FALSE;
// プログラムカウンタ
else if (addr == 6'h1f)
is_writable = util_p::FALSE;
// タクトスイッチ
else if (addr == 6'h20)
is_writable = util_p::FALSE;
// DIPスイッチ
else if (addr == 6'h21)
is_writable = util_p::FALSE;
// LED
else if (addr == 6'h22)
is_writable = util_p::TRUE;
// RGB LED
else if (addr == 6'h23)
is_writable = util_p::TRUE;
// Pmod A
else if (addr == 6'h24)
is_writable = util_p::TRUE;
// Pmod B
else if (addr == 6'h25)
is_writable = util_p::TRUE;
// AR
else if (addr == 6'h26 || addr == 6'h28)
is_writable = util_p::TRUE;
// I2C
else if (addr == 6'h27)
is_writable = util_p::TRUE;
// AR_RST
else if (addr == 6'h29)
is_writable = util_p::FALSE;
// SPI
else if (addr == 6'h2a)
is_writable = util_p::TRUE;
// アナログピン
else if (addr == 6'h2b)
is_writable = util_p::FALSE; // オミット
// XADC
else if (addr == 6'h2c)
is_writable = util_p::FALSE; // オミット
// GPIO
else if (6'h2d <= addr || addr <= 6'h30)
is_writable = util_p::TRUE;
// 定義されていない
else
is_writable = util_p::FALSE;
endfunction
endpackage
// インターフェース定義
`endif
mother_board.v
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/07/06 13:34:58
// Design Name:
// Module Name: mother_board
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module mother_board(
input wire clk,
input wire resetn,
input wire [3:0] btn,
input wire [1:0] sw,
output wire [3:0] led,
output wire [5:0] rgb_led
);
mother_board_sv mother_board_sv_0 (
.clk(clk), .resetn(resetn),
.btn(btn),
.sw(sw),
.led(led),
.rgb_led(rgb_led)
);
endmodule
mother_board_sv.sv
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/07/06 13:34:58
// Design Name:
// Module Name: mother_board_sv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`include "ram.svh"
`include "rom.svh"
module mother_board_sv(
input logic clk,
input logic resetn,
input logic [3:0] btn,
input logic [1:0] sw,
output logic [3:0] led,
output logic [5:0] rgb_led
);
// メインメモリ読み込み・書き込みインターフェース
ram_read_if ram_read();
ram_write_if ram_write();
// メモリ読み込みインターフェース
rom_read_if rom_read();
// メインメモリ
ram_sv ram_sv_0 (
.clk(clk), .resetn(resetn),
// メインメモリデータ読み込み
.ram_read(ram_read),
// メインメモリデータ書き込み
.ram_write(ram_write)
);
// CPU
cpu_sv cpu_sv_0 (
.clk(clk), .resetn(resetn),
// プログラムデータ読み込み
.rom_read(rom_read),
// メモリデータ読み書き
.ram_read(ram_read),
.ram_write(ram_write),
// IO
.btn(btn),
.sw(sw),
.led(led),
.rgb_led(rgb_led)
);
// プログラムメモリ
rom_sv rom_sv_0 (
// プログラムデータ読み込み
.rom_read(rom_read)
);
endmodule
ram_sv.sv
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/07/02 20:50:34
// Design Name:
// Module Name: ram_sv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`include "ram.svh"
module ram_sv import ram_p::*; (
input logic clk,
input logic resetn,
// メモリデータ読み出し
ram_read_if.slave ram_read,
// メモリデータ書き込み
ram_write_if.slave ram_write
);
// メモリに保存されるデータ
memory_t memory_data = 0;
// メモリ読み出し・書き込み状態
state_enum ram_read_state = IDLE;
state_enum ram_write_state = IDLE;
always_ff @(posedge clk) begin
// リセット
if (!resetn) begin
// IO
ram_read.data <= 32'b0;
ram_read.ready <= 1'b0;
ram_read.code <= NONE;
ram_write.ready <= 1'b0;
ram_write.code <= NONE;
// 内部変数
memory_data <= 0;
ram_read_state <= IDLE;
ram_write_state <= IDLE;
end
// メモリ実行
else begin
// メモリデータ読み出し
unique case (ram_read_state)
// 待機
IDLE: begin
ram_read.code <= NONE;
// 読み出し命令を検知
if (ram_read.valid) begin
ram_read_state <= EXECUTE;
end
end
// メモリ読み込み実行
EXECUTE: begin
if (ram_read.valid) begin
ram_read.ready <= 1'b1;
// マスクに応じて読み込み
foreach (ram_read.mask[i]) begin
if (ram_read.mask[i])
// 32ビットのうち,8ビット分を出力
ram_read.data[i*8 + 7:i*8] <= memory_data[ram_read.address + i];
else
ram_read.data[i*8 + 7:i*8] <= 8'h00;
end
// 読み込みラスト?
if (ram_read.last) begin
ram_read_state <= RESPONSE;
end
end else begin
ram_read.ready <= 1'b0;
end
end
// メモリ読み込みの実行結果を返す
RESPONSE: begin
ram_read.ready <= 1'b0;
ram_read.code <= SUCCESS;
ram_read_state <= IDLE;
end
endcase
// メモリデータ書き込み
unique case (ram_write_state)
// 待機
IDLE: begin
ram_write.code <= NONE;
// 書き込み命令を検知
if (ram_write.valid) begin
ram_write_state <= EXECUTE;
end
end
// メモリ書き込み実行
EXECUTE: begin
if (ram_write.valid) begin
ram_write.ready <= 1'b1;
// マスクに応じて書き込み
foreach (ram_write.mask[i]) begin
if (ram_write.mask[i])
// 32ビットのうち,8ビット分を入力
memory_data[ram_write.address + i] <= ram_write.data[i*8 + 7:i*8];
else
memory_data[ram_write.address + i] <= 8'h00;
end
// 書き込みラスト?
if (ram_write.last) begin
ram_write_state <= RESPONSE;
end
end else begin
ram_write.ready <= 1'b0;
end
end
// メモリ書き込みの実行結果を返す
RESPONSE: begin
ram_write.ready <= 1'b0;
ram_write.code <= SUCCESS;
ram_write_state <= IDLE;
end
endcase
end
end
endmodule
cpu_sv.sv
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/04/19 20:35:14
// Design Name:
// Module Name: cpu_sv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`include "machine.svh"
`include "rom.svh"
`include "decorder.svh"
module cpu_sv import machine_p::*; (
input logic clk,
input logic resetn,
rom_read_if.master rom_read,
ram_read_if.master ram_read,
ram_write_if.master ram_write,
input logic [3:0] btn,
input logic [1:0] sw,
output logic [3:0] led,
output logic [5:0] rgb_led
);
// デコーダーとのインターフェース
command_if command();
// デコーダー
decorder_sv decorder_sv_0(
.resetn(resetn),
.command(command)
);
// ALU
alu_sv alu_sv_0(
.clk(clk), .resetn(resetn),
.rom_read(rom_read),
.command(command),
.ram_read(ram_read),
.ram_write(ram_write),
.btn(btn),
.sw(sw),
.led(led),
.rgb_led(rgb_led)
);
endmodule
rom_sv.sv
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/04/19 20:51:41
// Design Name:
// Module Name: rom_sv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`include "rom.svh"
`include "machine.svh"
`include "register.svh"
module rom_sv import machine_p::*; (
// メモリデータ読み出し
rom_read_if.slave rom_read
);
localparam integer ROM_SIZE = 2;
// ボタンの状態をLEDに出力するだけのプログラム
machine_t machines[0:ROM_SIZE - 1] = {
// ボタンの状態をメインメモリに書き込む
wm(4'h1, 0, BTN_ADDR, {1'b1, 0}),
// メインメモリからボタンの状態をLEDに出力
rm(4'h1, 0, LED_ADDR, {1'b1, 0}),
// pcを先頭に戻す
jmp(0, {1'b1, 32'b0})
};
// メモリデータの読み出し
always_comb begin
if (rom_read.pc >= ROM_SIZE) begin
rom_read.machine = nop();
end else begin
rom_read.machine = machines[rom_read.pc];
end
end
endmodule
decorder_sv.sv
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/04/20 16:22:23
// Design Name:
// Module Name: decorder_sv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`include "decorder.svh"
module decorder_sv (
input logic resetn,
command_if.slave command
);
// 組み合わせ回路
always_comb begin
// リセット
if (!resetn) begin
command.m_type = 0;
command.func = 0;
command.mask = 0;
command.rs1 = 0;
command.rs2 = 0;
command.rd = 0;
command.imm = 0;
end
// 機械語を展開
else begin
command.m_type = command.machine[31 + 32:29 + 32];
command.func = command.machine[28 + 32:23 + 32];
command.mask = command.machine[22 + 32:19 + 32];
command.rs1 = command.machine[18 + 32:13 + 32];
command.rs2 = command.machine[12 + 32: 7 + 32];
command.rd = command.machine[ 6 + 32: 1 + 32];
command.imm = command.machine[31:0];
end
end
endmodule
alu_sv.sv
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/04/20 16:41:07
// Design Name:
// Module Name: alu_sv
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`include "rom.svh"
`include "decorder.svh"
`include "alu.svh"
`include "ram.svh"
`include "machine.svh"
module alu_sv import alu_p::*, ram_p::*, machine_p::*; (
input logic clk,
input logic resetn,
rom_read_if.master rom_read,
command_if.master command,
// メモリ読み込みインターフェース
ram_read_if.master ram_read,
// メモリ書き込みインターフェース
ram_write_if.master ram_write,
input logic [3:0] btn,
input logic [1:0] sw,
output logic [3:0] led,
output logic [5:0] rgb_led
);
// 内部レジスタ
register_t register[6'h30:0] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// メモリ読み込み・書き出し状態
ram_p::state_enum ram_read_state = IDLE;
ram_p::state_enum ram_write_state = IDLE;
// 強制リセット
logic force_reset = 1'b0;
// デバッグ用
type_t m_type = 0;
func_t func = 0;
mask_t mask = 0;
addr_t rs1 = 0;
addr_t rs2 = 0;
addr_t rd = 0;
imm_t imm = 0;
// 組み合わせ回路
always_comb begin
// 機械語を分解してもらう
command.machine = rom_read.machine;
// メモリのバースト転送はオミットする
ram_read.last = 1'b1;
ram_write.last = 1'b1;
// IOにレジスタの値を出力する
led = register[6'h22][3:0];
rgb_led = register[6'h23][5:0];
// pcを出力する
rom_read.pc = register[PC_ADDR];
// デバッグ用
m_type = command.m_type;
func = command.func;
mask = command.mask;
rs1 = command.rs1;
rs2 = command.rs2;
rd = command.rd;
imm = command.imm;
end
// 順序回路
always_ff @(posedge clk) begin
// リセット
if (!resetn || force_reset) begin
// メモリの読み込み・書き出し状態をリセット
ram_read_state <= IDLE;
ram_write_state <= IDLE;
// メモリ読み書き
ram_read.address = 0;
ram_read.mask = 0;
ram_read.valid = 0;
ram_write.address = 0;
ram_write.data = 0;
ram_write.mask = 0;
ram_write.valid = 0;
// レジスタ
for (logic [5:0] i = 0; i <= 6'h31; i++) begin
register[i] = 0;
end
end
// 命令実行
else begin
// IOからレジスタに値を格納する
register[6'h20] = {4'b0, btn};
register[6'h21] = {6'b0, sw};
// 関数タイプごとに実行
unique case (command.m_type)
// 処理を実行しない(N系)
N_TYPE: begin
// pcをカウントアップ
register[PC_ADDR] <= register[PC_ADDR] + 1;
// 不正な値が入っても全て無視する
end
// 演算系(P系)
P_TYPE: begin
// 演算系はどの命令でもpcをカウントアップする
register[PC_ADDR] <= register[PC_ADDR] + 1;
// 指定されているアドレスが全て使用可能な場合のみ,処理を実行する
if (
is_readable(command.rs1)
&& is_readable(command.rs2)
&& is_writable(command.rd)
) begin
unique case (command.func)
AND: register[command.rd] <= register[command.rs1] & register[command.rs2];
OR: register[command.rd] <= register[command.rs1] | register[command.rs2];
XOR: register[command.rd] <= register[command.rs1] ^ register[command.rs2];
NOT: register[command.rd] <= ~register[command.rs1];
NAND: register[command.rd] <= ~(register[command.rs1] & register[command.rs2]);
ADD: register[command.rd] <= register[command.rs1] + register[command.rs2];
SUB: register[command.rd] <= register[command.rs1] - register[command.rs2];
default: force_reset <= 1'b1;
endcase
end
else begin
force_reset <= 1'b1;
end
end
// シフト系
S_TYPE: begin
// シフト系はどの命令でもpcをカウントアップする
register[PC_ADDR] <= register[PC_ADDR] + 1;
// イミディエイトデータを使用する?
if (command.imm[32]) begin
// 指定されているアドレスが全て使用可能な場合のみ,処理を実行する
if (
is_readable(command.rs1)
&& is_writable(command.rd)
) begin
unique case (command.func)
SLL: register[command.rd] <= register[command.rs1] << command.imm[31:0];
SRL: register[command.rd] <= register[command.rs1] >> command.imm[31:0];
SLA: register[command.rd] <= register[command.rs1] <<< command.imm[31:0];
SRA: register[command.rd] <= register[command.rs1] >>> command.imm[31:0];
default: force_reset <= 1'b1;
endcase
end
else begin
force_reset <= 1'b1;
end
end else begin
// 指定されているアドレスが全て使用可能な場合のみ,処理を実行する
if (
is_readable(command.rs1)
&& is_readable(command.rs2)
&& is_writable(command.rd)
) begin
unique case (command.func)
SLL: register[command.rd] <= register[command.rs1] << register[command.rs2];
SRL: register[command.rd] <= register[command.rs1] >> register[command.rs2];
SLA: register[command.rd] <= register[command.rs1] <<< register[command.rs2];
SRA: register[command.rd] <= register[command.rs1] >>> register[command.rs2];
default: force_reset <= 1'b1;
endcase
end
else begin
force_reset <= 1'b1;
end
end
end
// 代入系
A_TYPE: begin
// 代入系はどの命令でもpcをカウントアップする
register[PC_ADDR] <= register[PC_ADDR] + 1;
// 命令がMOVの時だけ実行
if (command.func == MOV) begin
// イミディエイトデータを使用する?
if (command.imm[32]) begin
// 指定されているアドレスが全て使用可能な場合のみ,処理を実行する
if (is_writable(command.rd)) begin
register[command.rd] <= command.imm[31:0];
end
else begin
force_reset <= 1'b1;
end
end else begin
// 指定されているアドレスが全て使用可能な場合のみ,処理を実行する
if (is_readable(command.rs1) && is_writable(command.rd)) begin
register[command.rd] <= register[command.rs1];
end
else begin
force_reset <= 1'b1;
end
end
end
else begin
force_reset <= 1'b1;
end
end
// 分岐系
F_TYPE: begin
// 指定されているアドレスが全て使用可能
// かつイミディエイトデータを使用する設定の時だけ,処理を実行する
if (
is_readable(command.rs1)
&& is_readable(command.rs2)
&& is_writable(command.rd)
&& command.imm[32]
) begin
unique case (command.func)
EQ: begin
if (register[command.rs1] == register[command.rs2])
register[PC_ADDR] <= register[PC_ADDR] + command.imm[31:0];
else
register[PC_ADDR] <= register[PC_ADDR] + 1;
end
NE: begin
if (register[command.rs1] != register[command.rs2])
register[PC_ADDR] <= register[PC_ADDR] + command.imm[31:0];
else
register[PC_ADDR] <= register[PC_ADDR] + 1;
end
LT: begin
if (register[command.rs1] < register[command.rs2])
register[PC_ADDR] <= register[PC_ADDR] + command.imm[31:0];
else
register[PC_ADDR] <= register[PC_ADDR] + 1;
end
GT: begin
if (register[command.rs1] > register[command.rs2])
register[PC_ADDR] <= register[PC_ADDR] + command.imm[31:0];
else
register[PC_ADDR] <= register[PC_ADDR] + 1;
end
ELT: begin
if (register[command.rs1] <= register[command.rs2])
register[PC_ADDR] <= register[PC_ADDR] + command.imm[31:0];
else
register[PC_ADDR] <= register[PC_ADDR] + 1;
end
EGT: begin
if (register[command.rs1] >= register[command.rs2])
register[PC_ADDR] <= register[PC_ADDR] + command.imm[31:0];
else
register[PC_ADDR] <= register[PC_ADDR] + 1;
end
default: begin
force_reset <= 1'b1;
end
endcase
end
else begin
force_reset <= 1'b1;
end
end
// ジャンプ系
J_TYPE: begin
// 命令がジャンプの時だけ実行
if (command.func == JMP) begin
// イミディエイトデータを使用する?
if (command.imm[32]) begin
register[PC_ADDR] <= command.imm[31:0];
end else begin
// 指定されているアドレスが全て使用可能な場合のみ,処理を実行する
if (is_readable(command.rs1)) begin
register[PC_ADDR] <= register[command.rs1];
end
else begin
force_reset <= 1'b1;
end
end
end
else begin
force_reset <= 1'b1;
end
end
// メモリ系
M_TYPE: begin
unique case (command.func)
// メモリ読み込み
RM: begin
unique case (ram_read_state)
// 待機
IDLE: begin
// 実行を指示
ram_read_state <= EXECUTE;
// 実行状態であることを送る
ram_read.valid <= 1'b1;
// マスク情報を送る
ram_read.mask <= command.mask;
// アドレス情報を送る
if (command.imm[32]) begin
// イミディエイトデータを使用する指定なら,それを送る
ram_read.address <= command.imm[31:0];
end
else begin
// rs1を使用するなら,書き込み可能であることを確認して送る
if (is_writable(command.rs1)) begin
ram_read.address <= register[command.rs1];
end
else begin
// 強制リセット
force_reset <= 1'b1;
end
end
end
// メモリ読み込み実行
EXECUTE: begin
// 読み込みが完了したなら
if (ram_read.ready) begin
// 待機状態に遷移
ram_read_state <= IDLE;
// 実行状態をオフ
ram_read.valid <= 1'b0;
// データを受け取る
if (is_writable(command.rd)) begin
register[command.rd] <= ram_read.data;
end
else begin
force_reset <= 1'b1;
end
// プログラムカウンタをインクリメント
register[PC_ADDR] <= register[PC_ADDR] + 1;
end
end
// その他
default: begin
force_reset <= 1'b1;
end
endcase
end
// メモリ書き込み
WM: begin
unique case(ram_write_state)
// 待機
IDLE: begin
// 実行を指示
ram_write_state <= EXECUTE;
// 実行状態であることを送る
ram_write.valid <= 1'b1;
// マスク情報を送る
ram_write.mask <= command.mask;
// アドレス情報を送る
if (command.imm[32]) begin
// イミディエイトデータを使用する指定なら,それを送る
ram_write.address <= command.imm[31:0];
end
else begin
// rs1を使用するなら,書き込み可能であることを確認して送る
if (is_writable(command.rs1)) begin
ram_write.address <= register[command.rs1];
end
else begin
// 強制リセット
force_reset <= 1'b1;
end
end
// データを送る
if (is_readable(command.rs2)) begin
ram_write.data <= register[command.rs2];
end
else begin
// 強制リセット
force_reset <= 1'b1;
end
end
// メモリ書き込み実行
EXECUTE: begin
// 書き込みが完了したなら
if (ram_write.ready) begin
// 待機状態に遷移
ram_write_state <= IDLE;
// 実行状態をオフ
ram_write.valid <= 1'b0;
// プログラムカウンタをインクリメント
register[PC_ADDR] <= register[PC_ADDR] + 1;
end
end
// その他
default: begin
force_reset <= 1'b1;
end
endcase
end
// バーストはオミット
// メモリ読み込み(バースト)
BRM: begin
force_reset <= 1'b1;
end
// メモリ書き込み(バースト)
BWM: begin
force_reset <= 1'b1;
end
default: begin
force_reset <= 1'b1;
end
endcase
end
default: begin
force_reset <= 1'b1;
end
endcase
end
end
endmodule
テストコード
大したテストはしてないですが一応.
top_sim.v
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/08/24 20:10:28
// Design Name:
// Module Name: top_sim
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module top_sim();
// クロック関係
reg clk = 1'b0, resetn = 1'b1;
always #(10/2) begin
clk <= !clk;
end
// 入力
reg [3:0] btn = 0;
reg [1:0] sw = 0;
// 出力
wire [3:0] led;
wire [5:0] rgb_led;
// モジュール
mother_board mother_board_0(
.clk(clk), .resetn(resetn),
.btn(btn), .sw(sw),
.led(led), .rgb_led(rgb_led)
);
initial begin
// ボタンに値を入れる
btn[0] = 1'b1;
$finish();
end
endmodule
実行結果
次回の目標
最終的にはCUIで何かコントロールしたいので,その途中になるものを何か考えておきます.