訊息
|
輸入指令檔:cpu0m10.hex
00 1F 00 24 // 0000 LD R1, K1
00 2F 00 1C // 0004 LD R2, K0
00 3F 00 20 // 0008 LD R3, SUM
08 40 00 0A // 000C LDI R4, 10
13 22 10 00 // 0010 LOOP: ADD R2, R2, R1
13 33 20 00 // 0014 ADD R3, R3, R2
10 24 00 00 // 0018 CMP R2, R4
21 FF FF F0 // 001C JNE LOOP
2C 00 00 00 // 0020 RET
00 00 00 00 // 0024 K0: WORD 0
00 00 00 01 // 0028 K1: WORD 1
00 00 00 00 // 002C SUM: WORD 0
Verilog 程式:cpu0m10.v
module computer0m(input clock, reset, output [2:0] tick,
output [31:0] ir, pc, mar, mdr,
inout [31:0] dbus, output m_en, m_rw);
cpu0m 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));
memory0m mem (.clock(clock), .reset(reset), .en(m_en), .rw(m_rw),
.abus(mar), .dbus_in(mdr), .dbus_out(dbus));
endmodule
module cpu0m(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);
reg signed [31:0] R [0:15];
reg [7:0] op;
reg [3:0] ra, rb, rc;
reg signed [11:0] cx12;
reg signed [15:0] cx16;
reg signed [23:0] cx24;
reg signed [31:0] scx12, scx16, scx24, A, B, C, ipc; // ipc:instruction PC
`define SW R[12]
`define SP R[13]
`define LR R[14]
`define PC R[15]
`define LD 8'h00
`define ST 8'h01
`define LDI 8'h08
`define ADD 8'h13
`define JMP 8'h26
`define JEQ 8'h20
`define JNE 8'h21
`define CMP 8'h10
`define CALL 8'h2B
`define RET 8'h2C
`define N `SW[31]
`define Z `SW[30]
always @(posedge clock) begin
if (reset) begin
`PC = 0;
tick = 0;
R[0] = 0;
`LR = -1;
end
else begin
tick = tick+1;
m_en = 0;
case (tick)
// 指令擷取階段 Tick 1..3 : memory.read(m[PC])
1: begin // Tick 1:將 PC 丟到位址匯流排上
mar = `PC; // MAR = PC
m_rw = 1; // m_rw=1 is read mode, read(m[MAR]) => read(m[PC])
m_en = 1;
ipc = `PC;
`PC = `PC+4; // PC = PC + 4
end
2: begin // Tick 2:ir = m[PC]
mdr = dbus;
ir = mdr; // IR = dbus = m[PC]
{op,ra,rb,rc,cx12} = ir;
cx24 = ir[23:0];
cx16 = ir[15:0];
scx12 = cx12; // 取出 cx12 並轉為 32 位元有號數
scx16 = cx16; // 取出 cx16 並轉為 32 位元有號數
scx24 = cx24; // 取出 cx24 並轉為 32 位元有號數
end
3: begin // Tick 3:取出暫存器 R[ra], R[rb], R[rc] 內容
m_en = 0;
A = R[ra];
B = R[rb];
C = R[rc];
end
// 指令執行階段 Tick 4..6 : execute(IR)
4: begin
case (op) // 解讀 OP: Tick 4
`LD: begin // 指令:LD ra, rb, cx ; 語意:R[ra] = m[rb+cx]
mar = B + scx16; // mar = 讀取位址 = R[rb]+cx
m_rw = 1; // 讀取模式:read
m_en = 1;
end
`ST: begin // 指令:ST ra, rb, cx ; 語意:m[rb+cx]=R[ra]
mar = B + scx16; // 寫入位址 = R[rb]+cx
mdr = A; // 寫入資料:R[ra]
m_rw = 0; // 寫入模式:write
m_en = 1;
end
`ADD: begin // 指令:ADD ra, rb, rc ; 語意:R[ra]=R[rb]+R[rc]
R[ra] = B+C; // 執行加法
end
`JMP: begin // 指令:JMP cx ; 語意:PC = PC+cx
`PC = `PC+scx24; // 跳躍目標位址=PC+cx
end
`LDI: begin // 指令:LDI Ra, Rb+Cx; 語意:Ra=Rb+Cx
R[ra] = B+scx16;
end
`CMP: begin // 指令:CMP ra, rb ; 語意:SW=(Ra >=< Rb)
`N = (A-B < 0);
`Z = (A-B == 0);
end
`JEQ: begin // 指令:JEQ cx ; 語意:if SW(=) PC=PC+Cx
if (`Z) `PC = `PC+scx24; // 跳躍目標位址=PC+cx
end
`JNE: begin // 指令:JEQ cx ; 語意:if SW(=) PC=PC+Cx
if (`Z==1'b0) `PC = `PC+scx24; // 跳躍目標位址=PC+cx
end
`CALL: begin // 指令:CALL cx; 語意:LR=PC; PC=PC+Cx
`LR = `PC;
`PC = `PC + scx24;
end
`RET: begin // 指令:RET ; 語意:PC=LR
`PC = `LR;
end
endcase
end
5: begin // 解讀 OP: Tick 5
case (op) // LD ra, rb, cx ; R[ra] = R[rb+cx] ; mdr = R[rb+cx]
`LD: begin // 指令:LD ra, rb, cx ; 語意:R[ra] = m[rb+cx]
mdr = dbus; // 取得記憶體傳回的 dbus = m[rb+cx]
R[ra] = mdr; // 存入到目標暫存器 R[ra] 中
m_en = 0; // 讀取完畢
end
`ST: begin // 指令:ST ra, rb, cx ; 語意:m[rb+cx]=R[ra]
m_en = 0; // 寫入完畢
end
endcase
end
6: begin
case (op) // 解讀 OP: Tick 6; 列印
`LD: $display("%4dns %8x : LD %2x,%2x,%4x; R[%x]=%4d",
$stime, ipc, ra, rb, cx16, ra, R[ra]);
`ST: $display("%4dns %8x : ST %2x,%2x,%4x; R[%x]=%4d",
$stime, ipc, ra, rb, cx16, ra, R[ra]);
`ADD: $display("%4dns %8x : ADD %2x,%2x,%4x; R[%x]=%4d, B=%4d, C=%4d",
$stime, ipc, ra, rb, rc, ra, R[ra], B, C);
`JMP: $display("%4dns %8x : JMP %10d; PC=%8x",
$stime, ipc, cx24, R[15]);
`LDI: $display("%4dns %8x : LDI %2x,%2x,%4x; R[%x]=%4d",
$stime, ipc, ra, rb, cx16, ra, R[ra]);
`CMP: $display("%4dns %8x : CMP %2x %2x; N=%b Z=%b",
$stime, ipc, ra, rb, `N, `Z);
`JEQ: $display("%4dns %8x : JEQ %10d; PC=%8x",
$stime, ipc, cx24, R[15]);
`JNE: $display("%4dns %8x : JNE %10d; PC=%8x",
$stime, ipc, cx24, R[15]);
`CALL:$display("%4dns %8x : CALL %10d; PC=%8x",
$stime, ipc, cx24, R[15]);
`RET: begin
$display("%4dns %8x : RET; PC=%8x", $stime, ipc, R[15]);
if (`PC < 0) begin
$display("RET to PC < 0, finished!");
$finish;
end
end
endcase
tick = 0;
end
default: begin
end
endcase
end
pc = `PC;
end
endmodule
module memory0m(input clock, reset, en, rw,
input [31:0] abus, dbus_in, output [31:0] dbus_out);
reg [7:0] m [0:128];
reg [31:0] data;
integer i;
initial begin
end
always @(reset)
begin
if (reset == 1) begin
$readmemh("cpu0m10.hex", m);
for (i=0; i < 128; i=i+4) begin
if (m[i] !== 8'hx)
$display("%8x: %x", i, {m[i], m[i+1], m[i+2], m[i+3]});
end
end
end
always @(clock or abus or en or rw or dbus_in)
begin
if (abus >=0 && abus < 125) begin
if (en == 1 && rw == 0) begin // r_w==0:write
data = dbus_in;
{m[abus], m[abus+1], m[abus+2], m[abus+3]} = dbus_in;
end
else if (en == 1 && rw == 1) // r_w==1:read
data = {m[abus], m[abus+1], m[abus+2], m[abus+3]};
else
data = 32'hZZZZZZZZ;
end else
data = 32'hZZZZZZZZ;
end
assign dbus_out = data;
endmodule
module main;
reg clock;
reg reset;
wire [2:0] tick;
wire [31:0] pc, ir, mar, mdr, dbus;
wire m_en, m_rw;
computer0m DUT (.clock(clock), .reset(reset), .pc(pc), .tick(tick),
.ir(ir), .mar(mar), .mdr(mdr), .dbus(dbus), .m_en(m_en), .m_rw(m_rw));
initial
begin
clock = 0;
reset = 1;
end
initial #20 reset = 0;
always #10 clock=clock+1;
initial #10000 $finish;
endmodule
執行結果
D:\oc\cpu0m>iverilog cpu0m10.v -o cpu0m10
D:\oc\cpu0m>vvp cpu0m10
WARNING: cpu0m10.v:179: $readmemh(cpu0m10.hex): Not enough words in the file for
the requested range [0:128].
00000000: 001f0024
00000004: 002f001c
00000008: 003f0020
0000000c: 0840000a
00000010: 13221000
00000014: 13332000
00000018: 10240000
0000001c: 21fffff0
00000020: 2c000000
00000024: 00000000
00000028: 00000001
0000002c: 00000000
130ns 00000000 : LD 1, f,0024; R[1]= 1
250ns 00000004 : LD 2, f,001c; R[2]= 0
370ns 00000008 : LD 3, f,0020; R[3]= 0
490ns 0000000c : LDI 4, 0,000a; R[4]= 10
610ns 00000010 : ADD 2, 2, 1; R[2]= 1, B= 0, C= 1
730ns 00000014 : ADD 3, 3, 2; R[3]= 1, B= 0, C= 1
850ns 00000018 : CMP 2 4; N=1 Z=0
970ns 0000001c : JNE -16; PC=00000010
1090ns 00000010 : ADD 2, 2, 1; R[2]= 2, B= 1, C= 1
1210ns 00000014 : ADD 3, 3, 2; R[3]= 3, B= 1, C= 2
1330ns 00000018 : CMP 2 4; N=1 Z=0
1450ns 0000001c : JNE -16; PC=00000010
1570ns 00000010 : ADD 2, 2, 1; R[2]= 3, B= 2, C= 1
1690ns 00000014 : ADD 3, 3, 2; R[3]= 6, B= 3, C= 3
1810ns 00000018 : CMP 2 4; N=1 Z=0
1930ns 0000001c : JNE -16; PC=00000010
2050ns 00000010 : ADD 2, 2, 1; R[2]= 4, B= 3, C= 1
2170ns 00000014 : ADD 3, 3, 2; R[3]= 10, B= 6, C= 4
2290ns 00000018 : CMP 2 4; N=1 Z=0
2410ns 0000001c : JNE -16; PC=00000010
2530ns 00000010 : ADD 2, 2, 1; R[2]= 5, B= 4, C= 1
2650ns 00000014 : ADD 3, 3, 2; R[3]= 15, B= 10, C= 5
2770ns 00000018 : CMP 2 4; N=1 Z=0
2890ns 0000001c : JNE -16; PC=00000010
3010ns 00000010 : ADD 2, 2, 1; R[2]= 6, B= 5, C= 1
3130ns 00000014 : ADD 3, 3, 2; R[3]= 21, B= 15, C= 6
3250ns 00000018 : CMP 2 4; N=1 Z=0
3370ns 0000001c : JNE -16; PC=00000010
3490ns 00000010 : ADD 2, 2, 1; R[2]= 7, B= 6, C= 1
3610ns 00000014 : ADD 3, 3, 2; R[3]= 28, B= 21, C= 7
3730ns 00000018 : CMP 2 4; N=1 Z=0
3850ns 0000001c : JNE -16; PC=00000010
3970ns 00000010 : ADD 2, 2, 1; R[2]= 8, B= 7, C= 1
4090ns 00000014 : ADD 3, 3, 2; R[3]= 36, B= 28, C= 8
4210ns 00000018 : CMP 2 4; N=1 Z=0
4330ns 0000001c : JNE -16; PC=00000010
4450ns 00000010 : ADD 2, 2, 1; R[2]= 9, B= 8, C= 1
4570ns 00000014 : ADD 3, 3, 2; R[3]= 45, B= 36, C= 9
4690ns 00000018 : CMP 2 4; N=1 Z=0
4810ns 0000001c : JNE -16; PC=00000010
4930ns 00000010 : ADD 2, 2, 1; R[2]= 10, B= 9, C= 1
5050ns 00000014 : ADD 3, 3, 2; R[3]= 55, B= 45, C= 10
5170ns 00000018 : CMP 2 4; N=0 Z=1
5290ns 0000001c : JNE -16; PC=00000020
5410ns 00000020 : RET; PC=ffffffff
RET to PC < 0, finished!
Facebook
|
Post preview:
Close preview