如何製作一個簡單的16位CPU
好馬配好鞍,有了處理器,我們就得給它配上一個好的程式,下面我們就用自己設計的處理器進行求和,從1加到100,因為我們沒有設計編譯器,也沒有設計彙編器,所以程式只能用機器碼寫出,示例程式如下:
我們不妨先寫出程式的彙編程式碼:
mov [ADDR],r0;r0 = 0
mov r1,100
lop:add r2,r1
sub r1,1
cmp r1,0
jz ext
mov r4,4
jmp r4(lop)
ext:mov [ADDR],r2
jmp $
先將記憶體中存放資料的地址清零,這樣才能存放等下送來的結果,然後將r1暫存器存入迴圈次數(也就是求和的上限)。然後再將r1的值加到r2中來,r2其實就是放求和的暫存器,最後我們會將r2中的值送到記憶體中的某個地址存放的。
然後將r1減去1,看看是否為0?如果為0則說明求和結束了,如果不是0則說明還要繼續,結束後程序就跳到ext部分將結果存放到記憶體中某個地址(例子中給的是49152也就是二進位制的1100000000000000b),最後jmp $是為了讓程式停在這一行,防止程式跑飛(跑飛的程式危害很大!有可能把資料當代碼或者把程式碼當資料!)
轉換成VerilogHDL語言如下:
module memory
(
input [15:0] addr,
inout [15:0] data,
input rw
);
reg [15:0] data_ram[0:16'b1111_1111_1111_1111];
integer i;
initial begin
for (i = 0; i <= 16'b1111_1111_1111_1111; i = i + 1)
data_ram[i] = $random();
data_ram[0] = 16'b1000000100000000; //mov [ADDR],r0;r0 = 0
data_ram[1] = 16'b1100000000000000; //ADDR
data_ram[2] = 16'b1000000010001000; //mov r1,100
data_ram[3] = 100; //100
//data_ram[2] = 16'b1110011001000000;
data_ram[4] = 16'b0010000100010001; //lop:add r2,r1
data_ram[5] = 16'b1110000011001000; //sub r1,1
data_ram[6] = 16'b0000000000000001; //1
data_ram[7] = 16'b1110000000001000; //cmp r1,0
data_ram[8] = 16'b0000000000000000; //0
data_ram[9] = 16'b1110011010000000; //jz ext
data_ram[10] = 16'b0000000000000011; //+3 offset(ext)
data_ram[11] = 16'b1000000010100000;//mov r4,4
data_ram[12] = 16'b0000000000000100;
data_ram[13] = 16'b0110011001100000;//jmp r4(lop)
data_ram[14] = 16'b1000000100000010;//ext:mov [ADDR],r2
data_ram[15] = 16'b1100000000000000;//ADDR
data_ram[16] = 16'b1110011001000000;//jmp $
data_ram[17] = 16'b1111111111111110;//-2 offset($)
/*data_ram[0] = 16'b1000000010000000; //mov r0,imm
data_ram[1] = 16'b0011111111111111; //imm
data_ram[2] = 16'b0000000001111000; //mov r7,r0
data_ram[3] = 16'b1000000010011000; //mov r3,0
data_ram[4] = 16'b0000000000000000;
data_ram[5] = 16'b1000000010100000; //mov r4,code of jmp r5
data_ram[6] = 16'b0110011001101000; //jmp r5
data_ram[7] = 16'b0000000101011100; //mov [r3],r4
data_ram[8] = 16'b1000000011110000; //mov r6,[0]
data_ram[9] = 16'b0000000000000000; //[0]
data_ram[10]= 16'b1000000100000110; //mov [255],r6
data_ram[11]= 16'b0000000011111111;
data_ram[12]= 16'b0110011001011000; //jmp r3
*/
end
always @ (addr or rw or data)
if (rw)
data_ram[addr] = data;
assign data = rw ? 16'hzzzz : data_ram[addr];
endmodule
設計中CPU外圍還需要一個記憶體裝置(Memory),我用HDL對其建模,初始化的時候每個記憶體地址上對應的資料都初始化為隨機的,然後只有從0開始的一系列地址被初始化為我寫的程式碼,而CPU在上電之後自動從0開始的地址取指令執行。
機器碼對應的彙編指令在註釋中已經給出。