// 定義:寬度形態常數
`define INT32 2'b11 // 寬度 32 位元
`define INT24 2'b10 // 寬度 24 位元
`define INT16 2'b01 // 寬度 16 位元
`define BYTE 2'b00 // 寬度 8 位元
// 記憶體狀態
`define IDLE 1'b0 // 閒置中
`define BUSY 2'b1 // 忙碌中
`define WAIT_ACK 2'b1 // 忙碌中
// 記憶體讀寫
`define READ 1'b1 // 讀取
`define WRITE 1'b0 // 寫入
module ifetch(input clock, reset, i_ready, output o_ready, input next_ack, output ack_prev);
always @(posedge clock) begin
// $display("m_state=%d pc1=%x", m_state, pc1);
case (state)
`IDLE: begin
if (cpu.m_en == 0) begin
cpu.m_rw = `READ; // 讀取模式:read
cpu.m_en = 1; // 啟動讀取
cpu.m_w1 = `INT32;
cpu.pc = cpu.pc + 4;
cpu.mar = cpu.pc;
$display("%-4d:ifetch(abus=pc=%x)", $stime, cpu.pc);
end
end
`WAIT_ACK: begin
if (next_ack) begin
state <= IDLE;
end
end
endcase
end
endmodule
module idecode(input clock, reset, i_ready, output o_ready, input next_ack, output ack_prev);
reg state
reg signed [11:0] cx12;
reg signed [15:0] cx16;
reg signed [23:0] cx24;
always @(posedge clock) begin
case (state)
`IDLE: begin
cpu.ir = cpu.mdr; // 取得指令
cpu.m_en = 0; // 讀取完畢
{cpu.op,cpu.a,cpu.b,cpu.c,cx12} = cpu.ir;
cx24 = cpu.ir[23:0];
cx16 = cpu.ir[15:0];
cpu.c5 = cpu.ir[4:0];
cpu.c12 = cx12; // 取出 cx12 並轉為 32 位元有號數 c12
cpu.c16 = cx16; // 取出 cx16 並轉為 32 位元有號數 c16
cpu.c24 = cx24; // 取出 cx24 並轉為 32 位元有號數 c24
$display("%-8d:idecode(mdr=%x ir=%x op=%x a=%x b=%x c=%x cx12=%x)", $stime, cpu.mdr, cpu.ir, cpu.op, cpu.a, cpu.b, cpu.c, cpu.c12);
end
`WAIT_ACK:begin
if (next_ack) begin
state <= IDLE;
end
end
endcase
end
endmodule
module cpu0(input clock, reset, input [1:0] m_state, output [31:0] pc, abus, dbus, output reg m_en, m_rw, output reg [1:0] m_w1);
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, ipc; // ipc:instruction PC
reg [31:0] pc, ir, mar, mdr;
initial begin
pc = 0;
m_en = 0;
end
assign abus = mar;
always @(m_en, dbus) begin
if (m_en && m_rw==`READ && dbus !== 32'hZ)
mdr = dbus;
end
ifetch if1(clock, reset, m_state, );
idecode id1(clock, reset);
// tick2 t2(.clock(clock), .reset(reset), .dbus(dbus), .ir(ir), .m_en(m_en));
// controller ctrl(.clock(clock), .reset(reset), .pc(pc), .abus(abus), .dbus(dbus), .ir(ir), .m_en(m_en), .m_rw(m_rw));
endmodule
module memory0(input clock, reset, m_en, m_rw, input [1:0] m_w1,
input [31:0] abus, inout [31:0] dbus, output [1:0] m_state);
reg [7:0] m [0:258];
reg [31:0] data;
reg m_state = `WAITING;
integer i;
initial begin
$readmemh("cpu0p.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 @(abus or m_en or m_rw or m_state or dbus)
begin
// $display("%d:1 memory trigger(m_en=%b, m_rw=%b, m_state=%b, abus=%x)", $stime, m_en, m_rw, m_state, abus);
if (abus >=0 && abus <= 255) begin
// $display("%d:2 memory trigger(m_en=%b, m_rw=%b, m_state=%b)", $stime, m_en, m_rw, m_state);
if (m_en == 1) begin
if (m_rw == 0) begin // r_w==0:write
m_state = `BUSY;
#10;
data = dbus;
case (m_w1)
`BYTE: {m[abus]} = dbus[7:0];
`INT16: {m[abus], m[abus+1] } = dbus[15:0];
`INT24: {m[abus], m[abus+1], m[abus+2]} = dbus[24:0];
`INT32: {m[abus], m[abus+1], m[abus+2], m[abus+3]} = dbus;
endcase
$display("%-8d:write(abus=%x data=%x)", $stime, abus, data);
m_state = `IDLE;
end else begin// r_w==1:read
m_state = `BUSY;
#10;
case (m_w1)
`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
$display("%-8d:read(abus=%x data=%x)", $stime, abus, data);
m_state = `IDLE;
end
end else // m_en==0
data = 32'hZZZZZZZZ;
end else // a > 255
data = 32'hZZZZZZZZ;
end
assign dbus = data;
endmodule
module main;
reg clock, reset;
wire [31:0] abus, dbus, pc;
wire m_en, m_rw;
wire [1:0] m_w1, m_state;
cpu0 cpu(.clock(clock), .reset(reset), .m_state(m_state), .pc(pc), .abus(abus), .dbus(dbus), .m_en(m_en), .m_rw(m_rw), .m_w1(m_w1));
memory0 mem(.clock(clock), .reset(reset), .m_en(m_en), .m_rw(m_rw), .m_state(m_state), .m_w1(m_w1), .abus(abus), .dbus(dbus));
initial
begin
clock = 0;
reset = 1;
#10 reset=0;
#1000 $finish;
end
always #50 begin
clock=clock+1;
// $monitor("%4dns pc=%x", $stime, pc);
end
endmodule
Post preview:
Close preview