訊息
|
專案下載:cpu0s.zip
教學影片
輸入指令檔:cpu0s.hex
00 DF 00 B6 // 0 LD R13, StackEnd
08 40 00 04 // 4 LDI R4, 4
08 50 00 08 // 8 LDI R5, 8
05 4D 50 00 // c STR R4, [R13+R5]
04 6D 50 00 // 10 LDR R6, [R13+R5]
07 5D 40 00 // 14 SBR R5, [R13+R4]
06 6D 40 00 // 18 LBR R6, [R13+R4]
30 E0 00 00 // 1C PUSH R14
12 85 00 00 // 20 MOV R8, R5
13 85 40 00 // 24 ADD R8, R5, R4
14 85 40 00 // 28 SUB R8, R5, R4
15 85 40 00 // 2c MUL R8, R5, R4
16 85 40 00 // 30 DIV R8, R5, R4
18 85 40 00 // 34 AND R8, R5, R4
19 85 40 00 // 38 OR R8, R5, R4
1A 85 40 00 // 3c XOR R8, R5, R4
1E 85 00 03 // 40 SHL R8, R5, 3
1F 85 00 02 // 44 SHR R8, R5, 2
10 45 00 00 // 48 CMP R4, R5
20 00 00 18 // 4c JEQ L1
23 00 00 14 // 50 JGT L1
25 00 00 10 // 54 JGE L1
22 00 00 0C // 58 JLT L1
24 00 00 08 // 5c JLE L1
21 00 00 04 // 60 JNE L1
26 00 00 00 // 64 JMP L1
08 10 00 0A // 68 L1: LDI R1, 10
2B 00 00 08 // 6c CALL SUM
31 E0 00 00 // 70 POP R14
2C 00 00 00 // 74 RET
30 E0 00 00 // 78 SUM: PUSH R14
12 30 00 00 // 7c MOV R3, R0 // R3 = i = 0
02 4F 00 24 // 80 LDB R4, k1 // R4 = 1
08 20 00 00 // 84 LDI R2, 0 // SUM = R2 = 0
13 22 30 00 // 88 LOOP: ADD R2, R2, R3 // SUM = SUM + i
13 33 40 00 // 8c ADD R3, R3, R4 // i = i + 1
10 31 00 00 // 90 CMP R3, R1 // if (i < R1)
24 FF FF F0 // 94 JLE LOOP // goto LOOP
01 2F 00 0D // 98 ST R2, s
03 3F 00 0D // 9c STB R3, i
31 E0 00 00 // a0 POP R14
2C 00 00 00 // a4 RET // return
01 // a8 k1: BYTE 1 // char K1=1
00 00 00 00 // a9 s: WORD 0 // int s
00 // ad i: BYTE 0 // char i=1
00 01 02 03 // ae Stack: BYTE 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10, 11
04 05 06 07 // b2
08 09 0A 0B // b6
00 00 00 BA // ba StackEnd: WORD StackEnd
01 02 03 04 // be Data: BYTE 0, 1, 2, 3, 4, 5, 6, 7, 8
05 06 07 08 // c2
Verilog 程式:cpu0s.v
// 寬度形態常數
`define INT32 2'b11 // 寬度 32 位元
`define INT24 2'b10 // 寬度 24 位元
`define INT16 2'b01 // 寬度 16 位元
`define BYTE 2'b00 // 寬度 8 位元
// 參考文獻:http://ccckmit.wikidot.com/ocs:cpu0
module cpu0(input clock, reset, output reg [2:0] tick,
output reg [31:0] ir, pc, mar, mdr, inout [31:0] dbus,
output reg m_en, m_rw, output reg [1:0] m_size);
reg signed [31:0] R [0:15];
reg [7:0] op;
reg [3:0] a, b, c;
reg [4:0] c5;
reg signed [31:0] c12, c16, c24, Ra, Rb, Rc, pc0; // pc0 : instruction pc
// 暫存器簡稱
`define PC R[15] // 程式計數器
`define LR R[14] // 連結暫存器
`define SP R[13] // 堆疊暫存器
`define SW R[12] // 狀態暫存器
// 狀態暫存器旗標位元
`define N `SW[31] // 負號旗標
`define Z `SW[30] // 零旗標
`define C `SW[29] // 進位旗標
`define V `SW[28] // 溢位旗標
`define I `SW[7] // 硬體中斷許可
`define T `SW[6] // 軟體中斷許可
`define M `SW[0] // 模式位元
// 指令編碼表
parameter [7:0] LD=8'h00,ST=8'h01,LDB=8'h02,STB=8'h03,LDR=8'h04,STR=8'h05,
LBR=8'h06,SBR=8'h07,LDI=8'h08,CMP=8'h10,MOV=8'h12,ADD=8'h13,SUB=8'h14,
MUL=8'h15,DIV=8'h16,AND=8'h18,OR=8'h19,XOR=8'h1A,ROL=8'h1C,ROR=8'h1D,
SHL=8'h1E,SHR=8'h1F,JEQ=8'h20,JNE=8'h21,JLT=8'h22,JGT=8'h23,JLE=8'h24,
JGE=8'h25,JMP=8'h26,SWI=8'h2A,CALL=8'h2B,RET=8'h2C,IRET=8'h2D,
PUSH=8'h30,POP=8'h31,PUSHB=8'h32,POPB=8'h33;
task memReadStart(input [31:0] addr, input [1:0] size); begin // 讀取記憶體 Word
mar = addr; // read(m[addr])
m_rw = 1; // 讀取模式:read
m_en = 1; // 啟動讀取
m_size = size;
end endtask
task memReadEnd(output [31:0] data); begin // 讀取記憶體完成,取得資料
mdr = dbus; // 取得記憶體傳回的 dbus = m[addr]
data = mdr; // 傳回資料
m_en = 0; // 讀取完畢
end endtask
// 寫入記憶體 -- addr:寫入位址, data:寫入資料
task memWriteStart(input [31:0] addr, input [31:0] data, input [1:0] size); begin
mar = addr; // write(m[addr], data)
mdr = data;
m_rw = 0; // 寫入模式:write
m_en = 1; // 啟動寫入
m_size = size;
end endtask
task memWriteEnd; begin // 寫入記憶體完成
m_en = 0; // 寫入完畢
end endtask
task regSet(input [3:0] i, input [31:0] data); begin
if (i!=0) R[i] = data;
end endtask
always @(posedge clock or posedge reset) begin
if (reset) begin
`PC = 0; tick = 0; R[0] = 0; `SW = 0; `LR = -1;
end else begin
tick = tick+1;
m_en = 0;
case (tick)
1: begin // Tick 1 : 指令擷取,將 PC 丟到位址匯流排上,memory.read(m[PC])
memReadStart(`PC, `INT32);
pc0 = `PC;
`PC = `PC+4;
end
2: begin // Tick 2 : 指令解碼,ir = m[PC]
memReadEnd(ir); // IR = dbus = m[PC]
{op,a,b,c} = ir[31:12];
c24 = $signed(ir[23:0]);
c16 = $signed(ir[15:0]);
c12 = $signed(ir[11:0]);
c5 = ir[4:0];
Ra = R[a];
Rb = R[b];
Rc = R[c];
end
3: begin // Tick 3 : 指令執行
case (op)
// 載入儲存指令
LD: memReadStart(Rb+c16, `INT32); // 載入word; LD Ra, [Rb+Cx]; Ra<=[Rb+ Cx]
ST: memWriteStart(Rb+c16, Ra, `INT32); // 儲存word; ST Ra, [Rb+ Cx]; Ra=>[Rb+ Cx]
LDB: memReadStart(Rb+c16, `BYTE); // 載入byte; LDB Ra, [Rb+ Cx]; Ra<=(byte)[Rb+ Cx]
STB: memWriteStart(Rb+c16, Ra, `BYTE); // 儲存byte; STB Ra, [Rb+ Cx]; Ra=>(byte)[Rb+ Cx]
LDR: memReadStart(Rb+Rc, `INT32); // LD的Rc版; LDR Ra, [Rb+Rc]; Ra<=[Rb+ Rc]
STR: memWriteStart(Rb+Rc, Ra, `INT32); // ST的Rc版; STR Ra, [Rb+Rc]; Ra=>[Rb+ Rc]
LBR: memReadStart(Rb+Rc, `BYTE); // LDB的Rc版; LBR Ra, [Rb+Rc]; Ra<=(byte)[Rb+ Rc]
SBR: memWriteStart(Rb+Rc, Ra, `BYTE); // STB的Rc版; SBR Ra, [Rb+Rc]; Ra=>(byte)[Rb+ Rc]
LDI: R[a] = Rb+c16; // 立即載入; LDI Ra, Rb+Cx; Ra<=Rb + Cx
// 運算指令
CMP: begin `N=(Ra-Rb<0);`Z=(Ra-Rb==0); end // 比較; CMP Ra, Rb; SW=(Ra >=< Rb)
MOV: regSet(a, Rb); // 移動; MOV Ra, Rb; Ra<=Rb
ADD: regSet(a, Rb+Rc); // 加法; ADD Ra, Rb, Rc; Ra<=Rb+Rc
SUB: regSet(a, Rb-Rc); // 減法; SUB Ra, Rb, Rc; Ra<=Rb-Rc
MUL: regSet(a, Rb*Rc); // 乘法; MUL Ra, Rb, Rc; Ra<=Rb*Rc
DIV: regSet(a, Rb/Rc); // 除法; DIV Ra, Rb, Rc; Ra<=Rb/Rc
AND: regSet(a, Rb&Rc); // 位元 AND; AND Ra, Rb, Rc; Ra<=Rb and Rc
OR: regSet(a, Rb|Rc); // 位元 OR; OR Ra, Rb, Rc; Ra<=Rb or Rc
XOR: regSet(a, Rb^Rc); // 位元 XOR; XOR Ra, Rb, Rc; Ra<=Rb xor Rc
SHL: regSet(a, Rb<<c5); // 向左移位; SHL Ra, Rb, Cx; Ra<=Rb << Cx
SHR: regSet(a, Rb>>c5); // 向右移位; SHR Ra, Rb, Cx; Ra<=Rb >> Cx
// 跳躍指令
JEQ: if (`Z) `PC=`PC+c24; // 跳躍 (相等); JEQ Cx; if SW(=) PC PC+Cx
JNE: if (!`Z) `PC=`PC+c24; // 跳躍 (不相等); JNE Cx; if SW(!=) PC PC+Cx
JLT: if (`N)`PC=`PC+c24; // 跳躍 ( < ); JLT Cx; if SW(<) PC PC+Cx
JGT: if (!`N&&!`Z) `PC=`PC+c24; // 跳躍 ( > ); JGT Cx; if SW(>) PC PC+Cx
JLE: if (`N || `Z) `PC=`PC+c24; // 跳躍 ( <= ); JLE Cx; if SW(<=) PC PC+Cx
JGE: if (!`N || `Z) `PC=`PC+c24; // 跳躍 ( >= ); JGE Cx; if SW(>=) PC PC+Cx
JMP: `PC = `PC+c24; // 跳躍 (無條件); JMP Cx; PC <= PC+Cx
SWI: begin `LR=`PC;`PC= c24; `I = 1'b1; end // 軟中斷; SWI Cx; LR <= PC; PC <= Cx; INT<=1
CALL:begin `LR=`PC;`PC=`PC + c24; end // 跳到副程式; CALL Cx; LR<=PC; PC<=PC+Cx
RET: begin `PC=`LR; end // 返回; RET; PC <= LR
IRET:begin `PC=`LR;`I = 1'b0; end // 中斷返回; IRET; PC <= LR; INT<=0
// 堆疊指令
PUSH:begin `SP = `SP-4; memWriteStart(`SP, Ra, `INT32); end // 推入 word; PUSH Ra; SP-=4;[SP]<=Ra;
POP: begin memReadStart(`SP, `INT32); `SP = `SP + 4; end // 彈出 word; POP Ra; Ra=[SP];SP+=4;
PUSHB:begin `SP = `SP-1; memWriteStart(`SP, Ra, `BYTE); end // 推入 byte; PUSHB Ra; SP--;[SP]<=Ra;(byte)
POPB:begin memReadStart(`SP, `BYTE); `SP = `SP+1; end // 彈出 byte; POPB Ra; Ra<=[SP];SP++;(byte)
endcase
end
4: begin // 讀取寫入指令完成,關閉記憶體
case (op)
LD, LDB, LDR, LBR, POP, POPB : memReadEnd(R[a]); // 讀取記憶體完成
ST, STB, STR, SBR, PUSH, PUSHB: memWriteEnd(); // 寫入記憶體完成
endcase
$display("%4dns %8x : %8x R[%02d]=%-8x=%-d SW=%8x", $stime, pc0, ir, a, R[a], R[a], `SW);
if (op==RET && `PC < 0) begin
$display("RET to PC < 0, finished!");
$finish;
end
tick = 0;
end
endcase
end
pc = `PC;
end
endmodule
module memory0(input clock, reset, en, rw, input [1:0] m_size,
input [31:0] abus, dbus_in, output [31:0] dbus_out);
reg [7:0] m [0:258];
reg [31:0] data;
integer i;
initial begin
$readmemh("cpu0s.hex", m);
for (i=0; i < 255; i=i+4) begin
$display("%8x: %8x", i, {m[i], m[i+1], m[i+2], m[i+3]});
end
end
always @(clock or abus or en or rw or dbus_in)
begin
if (abus >=0 && abus <= 255) begin
if (en == 1 && rw == 0) begin // r_w==0:write
data = dbus_in;
case (m_size)
`BYTE: {m[abus]} = dbus_in[7:0];
`INT16: {m[abus], m[abus+1] } = dbus_in[15:0];
`INT24: {m[abus], m[abus+1], m[abus+2]} = dbus_in[24:0];
`INT32: {m[abus], m[abus+1], m[abus+2], m[abus+3]} = dbus_in;
endcase
end else if (en == 1 && rw == 1) begin// r_w==1:read
case (m_size)
`BYTE: data = {8'h00 , 8'h00, 8'h00, m[abus] };
`INT16: data = {8'h00 , 8'h00, m[abus], m[abus+1] };
`INT24: data = {8'h00 , m[abus], m[abus+1], m[abus+2] };
`INT32: data = {m[abus], m[abus+1], m[abus+2], m[abus+3]};
endcase
end else
data = 32'hZZZZZZZZ;
end else
data = 32'hZZZZZZZZ;
end
assign dbus_out = data;
endmodule
module main;
reg clock, reset;
wire [2:0] tick;
wire [31:0] pc, ir, mar, mdr, dbus;
wire m_en, m_rw;
wire [1:0] m_size;
cpu0 cpu(.clock(clock), .reset(reset), .pc(pc), .tick(tick), .ir(ir),
.mar(mar), .mdr(mdr), .dbus(dbus), .m_en(m_en), .m_rw(m_rw), .m_size(m_size));
memory0 mem(.clock(clock), .reset(reset), .en(m_en), .rw(m_rw), .m_size(m_size),
.abus(mar), .dbus_in(mdr), .dbus_out(dbus));
initial
begin
clock = 0;
reset = 1;
#20 reset = 0;
#10000 $finish;
end
always #10 clock=clock+1;
endmodule
執行結果
D:\oc\cpu0>iverilog cpu0s.v -o cpu0s
D:\oc\cpu0>vvp cpu0s
WARNING: cpu0s.v:169: $readmemh(cpu0s.hex): Not enough words in the file for the
requested range [0:258].
00000000: 00df00b6
00000004: 08400004
00000008: 08500008
0000000c: 054d5000
00000010: 046d5000
00000014: 075d4000
00000018: 066d4000
0000001c: 30e00000
00000020: 12850000
00000024: 13854000
00000028: 14854000
0000002c: 15854000
00000030: 16854000
00000034: 18854000
00000038: 19854000
0000003c: 1a854000
00000040: 1e850003
00000044: 1f850002
00000048: 10450000
0000004c: 20000018
00000050: 23000014
00000054: 25000010
00000058: 2200000c
0000005c: 24000008
00000060: 21000004
00000064: 26000000
00000068: 0810000a
0000006c: 2b000008
00000070: 31e00000
00000074: 2c000000
00000078: 30e00000
0000007c: 12300000
00000080: 024f0024
00000084: 08200000
00000088: 13223000
0000008c: 13334000
00000090: 10310000
00000094: 24fffff0
00000098: 012f000d
0000009c: 033f000d
000000a0: 31e00000
000000a4: 2c000000
000000a8: 01000000
000000ac: 00000001
000000b0: 02030405
000000b4: 06070809
000000b8: 0a0b0000
000000bc: 00ba0102
000000c0: 03040506
000000c4: 0708xxxx
000000c8: xxxxxxxx
000000cc: xxxxxxxx
000000d0: xxxxxxxx
000000d4: xxxxxxxx
000000d8: xxxxxxxx
000000dc: xxxxxxxx
000000e0: xxxxxxxx
000000e4: xxxxxxxx
000000e8: xxxxxxxx
000000ec: xxxxxxxx
000000f0: xxxxxxxx
000000f4: xxxxxxxx
000000f8: xxxxxxxx
000000fc: xxxxxxxx
90ns 00000000 : 00df00b6 R[13]=000000ba=186 SW=00000000
170ns 00000004 : 08400004 R[04]=00000004=4 SW=00000000
250ns 00000008 : 08500008 R[05]=00000008=8 SW=00000000
330ns 0000000c : 054d5000 R[04]=00000004=4 SW=00000000
410ns 00000010 : 046d5000 R[06]=00000004=4 SW=00000000
490ns 00000014 : 075d4000 R[05]=00000008=8 SW=00000000
570ns 00000018 : 066d4000 R[06]=00000008=8 SW=00000000
650ns 0000001c : 30e00000 R[14]=ffffffff=-1 SW=00000000
730ns 00000020 : 12850000 R[08]=00000008=8 SW=00000000
810ns 00000024 : 13854000 R[08]=0000000c=12 SW=00000000
890ns 00000028 : 14854000 R[08]=00000004=4 SW=00000000
970ns 0000002c : 15854000 R[08]=00000020=32 SW=00000000
1050ns 00000030 : 16854000 R[08]=00000002=2 SW=00000000
1130ns 00000034 : 18854000 R[08]=00000000=0 SW=00000000
1210ns 00000038 : 19854000 R[08]=0000000c=12 SW=00000000
1290ns 0000003c : 1a854000 R[08]=0000000c=12 SW=00000000
1370ns 00000040 : 1e850003 R[08]=00000040=64 SW=00000000
1450ns 00000044 : 1f850002 R[08]=00000002=2 SW=00000000
1530ns 00000048 : 10450000 R[04]=00000004=4 SW=80000000
1610ns 0000004c : 20000018 R[00]=00000000=0 SW=80000000
1690ns 00000050 : 23000014 R[00]=00000000=0 SW=80000000
1770ns 00000054 : 25000010 R[00]=00000000=0 SW=80000000
1850ns 00000058 : 2200000c R[00]=00000000=0 SW=80000000
1930ns 00000068 : 0810000a R[01]=0000000a=10 SW=80000000
2010ns 0000006c : 2b000008 R[00]=00000000=0 SW=80000000
2090ns 00000078 : 30e00000 R[14]=00000070=112 SW=80000000
2170ns 0000007c : 12300000 R[03]=00000000=0 SW=80000000
2250ns 00000080 : 024f0024 R[04]=00000001=1 SW=80000000
2330ns 00000084 : 08200000 R[02]=00000000=0 SW=80000000
2410ns 00000088 : 13223000 R[02]=00000000=0 SW=80000000
2490ns 0000008c : 13334000 R[03]=00000001=1 SW=80000000
2570ns 00000090 : 10310000 R[03]=00000001=1 SW=80000000
2650ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
2730ns 00000088 : 13223000 R[02]=00000001=1 SW=80000000
2810ns 0000008c : 13334000 R[03]=00000002=2 SW=80000000
2890ns 00000090 : 10310000 R[03]=00000002=2 SW=80000000
2970ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
3050ns 00000088 : 13223000 R[02]=00000003=3 SW=80000000
3130ns 0000008c : 13334000 R[03]=00000003=3 SW=80000000
3210ns 00000090 : 10310000 R[03]=00000003=3 SW=80000000
3290ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
3370ns 00000088 : 13223000 R[02]=00000006=6 SW=80000000
3450ns 0000008c : 13334000 R[03]=00000004=4 SW=80000000
3530ns 00000090 : 10310000 R[03]=00000004=4 SW=80000000
3610ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
3690ns 00000088 : 13223000 R[02]=0000000a=10 SW=80000000
3770ns 0000008c : 13334000 R[03]=00000005=5 SW=80000000
3850ns 00000090 : 10310000 R[03]=00000005=5 SW=80000000
3930ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
4010ns 00000088 : 13223000 R[02]=0000000f=15 SW=80000000
4090ns 0000008c : 13334000 R[03]=00000006=6 SW=80000000
4170ns 00000090 : 10310000 R[03]=00000006=6 SW=80000000
4250ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
4330ns 00000088 : 13223000 R[02]=00000015=21 SW=80000000
4410ns 0000008c : 13334000 R[03]=00000007=7 SW=80000000
4490ns 00000090 : 10310000 R[03]=00000007=7 SW=80000000
4570ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
4650ns 00000088 : 13223000 R[02]=0000001c=28 SW=80000000
4730ns 0000008c : 13334000 R[03]=00000008=8 SW=80000000
4810ns 00000090 : 10310000 R[03]=00000008=8 SW=80000000
4890ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
4970ns 00000088 : 13223000 R[02]=00000024=36 SW=80000000
5050ns 0000008c : 13334000 R[03]=00000009=9 SW=80000000
5130ns 00000090 : 10310000 R[03]=00000009=9 SW=80000000
5210ns 00000094 : 24fffff0 R[15]=00000088=136 SW=80000000
5290ns 00000088 : 13223000 R[02]=0000002d=45 SW=80000000
5370ns 0000008c : 13334000 R[03]=0000000a=10 SW=80000000
5450ns 00000090 : 10310000 R[03]=0000000a=10 SW=40000000
5530ns 00000094 : 24fffff0 R[15]=00000088=136 SW=40000000
5610ns 00000088 : 13223000 R[02]=00000037=55 SW=40000000
5690ns 0000008c : 13334000 R[03]=0000000b=11 SW=40000000
5770ns 00000090 : 10310000 R[03]=0000000b=11 SW=00000000
5850ns 00000094 : 24fffff0 R[15]=00000098=152 SW=00000000
5930ns 00000098 : 012f000d R[02]=00000037=55 SW=00000000
6010ns 0000009c : 033f000d R[03]=0000000b=11 SW=00000000
6090ns 000000a0 : 31e00000 R[14]=00000070=112 SW=00000000
6170ns 000000a4 : 2c000000 R[00]=00000000=0 SW=00000000
6250ns 00000070 : 31e00000 R[14]=ffffffff=-1 SW=00000000
6330ns 00000074 : 2c000000 R[00]=00000000=0 SW=00000000
RET to PC < 0, finished!
歷史版本
- 使用 Verilog 設計 CPU0 處理器 (簡單設計版1) (中間版,程式完整,但測試不完整,程式較繁瑣)
- 使用 Verilog 設計 CPU0 處理器 (簡單設計版2) (中間版,程式完整,但測試不完整,程式較簡單)
- 使用 Verilog 設計 CPU0 處理器 (簡單設計版3) (程式完整,測試完整)
Facebook
|
Post preview:
Close preview