前回までのあらすじ
- 自作PCを作ろう!
- まずメモリを作ったよ!
- ISAを作ったよ!(コンパイラはまだ)
- アセンブリ言語を作ったよ!(コンパイラはまだ)
- CPUを作ったよ!
前回からの変更
あるにはあるけど細かいので省略
今回の目標
最終的にはCUIで操作するコンピュータを作りたいのですが,とりあえず今回は足し算機を作ります.
仕様は以下の通り.
- 左のスライドスイッチを上げているとき,足される数をタクトスイッチで設定する.設定している数はLEDに出力される
- 右のスライドスイッチを上げているとき,足す数をタクトスイッチで設定する.設定している数はLEDに出力される
- 両方のスライドスイッチを上げているとき,足される数と足す数を足した数をLEDに出力する
- 両側のスライドスイッチが下がっているときは何もしない
プログラム
前回からソースがほとんど変わっていないので,ソース部分だけ貼りますね.
`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 = 10015;
// 足し算機プラグラム
machine_t machines[0:ROM_SIZE - 1] = {
// 左側のスイッチがオンの状態を保存
mov(4'hf, 0, 0, {1'b1, 32'b10}),
// 右側のスイッチがオンの状態を保存
mov(4'hf, 0, 1, {1'b1, 32'b01}),
// 両側のスイッチがオンの状態を保存
mov(4'hf, 0, 2, {1'b1, 32'b11}),
// 両側のスイッチがオフの状態を保存
mov(4'hf, 0, 3, {1'b1, 32'b00}),
// もし左側のスライドスイッチがオンじゃないなら以下の処理を飛ばす
ne(6'h0, SW_ADDR, {1'b1, 32'd3}),
// スイッチが押されていたら,そのビットを反転して保存する
xor_(BTN_ADDR, 6'h4, 6'h4),
// レジスタの状態をLEDに出力する
mov(4'hf, 6'h4, LED_ADDR, {1'b0, 32'd0}),
// もし右側のスライドスイッチがオンじゃないなら以下の処理を飛ばす
ne(6'h1, SW_ADDR, {1'b1, 32'd3}),
// スイッチが押されていたら,そのビットを反転して保存する
xor_(BTN_ADDR, 6'h5, 6'h5),
// レジスタの状態をLEDに出力する
mov(4'hf, 6'h5, LED_ADDR, {1'b0, 32'd0}),
// もし両側のスライドスイッチがオンじゃないなら以下の処理を飛ばす
ne(6'h2, SW_ADDR, {1'b1, 32'd2}),
// 合計をLEDに出力する
add(6'h4, 6'h5, LED_ADDR),
// もし両側のスイッチがオフじゃないなら以下の処理を飛ばす
ne(6'h3, SW_ADDR, {1'b1, 32'd2}),
// LEDの値を空にする
mov(4'hf, 0, LED_ADDR, {1'b1, 32'b0}),
// チャタリング対策
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
// こんな感じでnopが一万個並ぶ
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),
// pcをレジスタ登録後に戻す
jmp(0, {1'b1, 32'h4})
};
// メモリデータの読み出し
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
実行結果
チャタリング対策を入れてはいますが,超チャタリングします.
nop
を一万個入れてはいますが,クロック周波数が100MHzでは100マイクロ秒しか稼いでくれませんからね.
次回の目標
これで任意のプログラムを実行できるようになったので,自作PCシリーズは完結です!
と言いたい所なんですが,これをPCと言い張るのはあまりにも質素です.
やっぱりPCを名乗るからには,キーボードによるコマンド入力を受け付けて,それに応じたレスポンスをしてほしいものです.
まだ何も思いついていないんですがそういう感じのことを次回はしたいですね.