2008年2月26日火曜日

TD4.v CPUの創り方 3段パイプライン版

module rom(oen, rom_address, rom_data);

/*
instruction decode
0000_0000 : add r0,r1
0001_0000 : add r1,r0
0010_.... : add r0,#i
0011_.... : add r1,#i
0100_0000 : move r0,r1
0101_0000 : move r1,r0
0110_.... : move r0,#i
0111_.... : move r1,#i
1000_.... : jmp #i
1100_.... : jnz #i

ld(on)
0001 : r0
0010 : r1
0100 : r2
1000 : r3(PC)
*/
input oen;
input [3:0] rom_address;
output [7:0] rom_data;

wire [3:0] rom_address;
reg [7:0] rom_data;

always @ (rom_address) begin
if (oen) begin
casez(rom_address)
4'h0: rom_data=8'b0110_0001; /* move r0,#0001 */
4'h1: rom_data=8'b0010_0010; /* add r0,#0010 */
4'h2: rom_data=8'b0111_0000; /* move r1,#0000 */
4'h3: rom_data=8'b1100_1111; /* jnz #1111 */
4'h4: rom_data=8'b1000_0001; /* jmp #0001 */
default:
rom_data=8'b0000_0000;
endcase
end else begin
rom_data=8'bxxxx_xxxx;
end
end

endmodule

module dec (
ck,
reset,
i_code,
imidiate,
co,
fetch_en,
ld,
ld_na,
on,
im,
oz,
oi
);
input ck, reset;
input [3:0] i_code, imidiate;
input co;
output fetch_en;
output [3:0] ld, ld_na, on, im;
output oz;
output oi;

reg [3:0] ld_c, on_c;
reg oz_c, oi_c, en_c;
reg [3:0] ld, ld_na, on, im;
reg oz, oi;
reg en, en_na;

always @ (i_code or co or en) begin
if (en) begin
casez (i_code)
4'b0000: begin /* add r0,r1 */ ld_c=4'b0001; on_c=4'b0010; oz_c=0; oi_c=0; en_c=1; end
4'b0001: begin /* add r1,r0 */ ld_c=4'b0010; on_c=4'b0001; oz_c=0; oi_c=0; en_c=1; end
4'b0010: begin /* add r0,#i */ ld_c=4'b0001; on_c=4'b0001; oz_c=0; oi_c=1; en_c=1; end
4'b0011: begin /* add r1,#i */ ld_c=4'b0010; on_c=4'b0010; oz_c=0; oi_c=1; en_c=1; end
4'b0100: begin /* move r0,r1 */ ld_c=4'b0001; on_c=4'b0010; oz_c=0; oi_c=0; en_c=1; end
4'b0101: begin /* move r1,r0 */ ld_c=4'b0010; on_c=4'b0001; oz_c=0; oi_c=0; en_c=1; end
4'b0110: begin /* move r0,#i */ ld_c=4'b0001; on_c=4'b0001; oz_c=0; oi_c=1; en_c=1; end
4'b0111: begin /* move r1,#i */ ld_c=4'b0010; on_c=4'b0010; oz_c=0; oi_c=1; en_c=1; end
4'b1000: begin /* jmp #i */ ld_c=4'b1000; on_c=4'bxxxx; oz_c=1; oi_c=1; en_c=0; end
4'b1100: begin /* jnz #i */
if (co) begin
ld_c=4'b1000; on_c=4'bxxxx; oz_c=1; oi_c=1; en_c=0;
end else begin
ld_c=4'b0001; on_c=4'b0001; oz_c=1; oi_c=0; en_c=1; /* add r0,#0 as NOP */
end
end
default: begin
ld_c=4'b0001; on_c=4'b0001; oz_c=1; oi_c=0; en_c=1; /* add r0,#0 as NOP */
end
endcase
end else begin
ld_c=4'b0001; on_c=4'b0001; oz_c=1; oi_c=0; en_c=1; /* add r0,#0 as NOP */
end
end

always @ (posedge ck or posedge reset) begin
if (reset) begin
ld<=4'b0001; on<=4'b0001; oz<=1; oi<=0; /* add r0,#0 as NOP */
im<=4'b0000;
en<=1;
end else begin
ld<=ld_c; on<=on_c; oz<=oz_c; oi<=oi_c;
im<=imidiate;
en<=en_c;
end
end

always @ (posedge ck) begin
en_na<=en;
end

assign fetch_en=en & en_na;

always @ (posedge ck or posedge reset) begin
if (reset) begin
ld_na<=4'b0000;
end else begin
ld_na<=ld;
end
end

endmodule

module registor (
ck,
reset,
r_bus,
r0_ld, r1_ld, r2_ld, r3_ld,
r0_ld_na, r1_ld_na, r2_ld_na, r3_ld_na,
r0_on, r1_on, r2_on, r3_on,
ra,
rb,
ia
);

input ck, reset;
input r0_ld, r1_ld, r2_ld, r3_ld;
input r0_ld_na, r1_ld_na, r2_ld_na, r3_ld_na;
input r0_on, r1_on, r2_on, r3_on;
input [3:0] r_bus;
output [3:0] ra, rb, ia;
reg [3:0] r0, r1, r2,r3;
wire [3:0] r0_bypass, r1_bypass, r2_bypass, r3_bypass;

always @ (posedge ck) begin
if (reset) begin
r0<=4'h0;
r1<=4'h0;
r2<=4'h0;
r3<=4'h0;
end else begin
if (r0_ld_na) r0<=r_bus;
if (r1_ld_na) r1<=r_bus;
if (r2_ld_na) r2<=r_bus;
if (r3_ld_na) r3<=r_bus; else r3<=r3+1;
end
end

assign r0_bypass = (r0_ld_na==1) ? r_bus : r0;
assign r1_bypass = (r1_ld_na==1) ? r_bus : r1;
assign r2_bypass = (r2_ld_na==1) ? r_bus : r2;
assign r3_bypass = (r3_ld_na==1) ? r_bus : r3;

assign ra =
(r0_on==1) ? r0_bypass :
(r1_on==1) ? r1_bypass :
(r2_on==1) ? r2_bypass :
(r3_on==1) ? r3_bypass : 4'bxxxx ;

assign rb =
(r0_ld==1) ? r0 :
(r1_ld==1) ? r1 :
(r2_ld==1) ? r2 :
(r3_ld==1) ? r3 : 4'bxxxx ;

assign ia = r3;

endmodule

module alu (ck, reset, a, b, im, oz, oi, q_na, of, co);
input ck, reset;
input [3:0] a, b, im;
input oz, oi;
output [3:0] q_na;
output of, co;

wire [3:0] q;
reg [3:0] q_na;

assign {of,q} =
(oi == 1 && oz == 1)? im :
(oi == 1)? a + im :
(oz == 1)? a :
a + b ;
assign co=| {of,q} ;

always @ (posedge ck or posedge reset) begin
if (reset) begin
q_na<=4'b0000;
end else begin
q_na<=q;
end
end

endmodule

module cpu(ck, reset) ;
input ck, reset;

wire fetch_en;
wire [3:0] rom_address;
wire [7:0] rom_data;
wire [3:0] ld_na, ld, on;
wire oz, oi;

wire [3:0] r_bus;
wire [3:0] ra, rb;
wire [3:0] im;
wire rc;
wire co;

rom rom ( .oen(fetch_en), .rom_address(rom_address), .rom_data(rom_data));

dec DEC (
.ck(ck),
.reset(reset),
.i_code(rom_data[7:4]),
.imidiate(rom_data[3:0]),
.co(co),

.fetch_en(fetch_en),
.ld(ld),
.ld_na(ld_na),
.on(on),
.im(im),
.oz(oz),
.oi(oi)
);

registor REG_ (
.ck(ck),
.reset(reset),
.r_bus(r_bus),
.r0_ld(ld[0]),
.r1_ld(ld[1]),
.r2_ld(ld[2]),
.r3_ld(ld[3]),
.r0_ld_na(ld_na[0]),
.r1_ld_na(ld_na[1]),
.r2_ld_na(ld_na[2]),
.r3_ld_na(ld_na[3]),
.r0_on(on[0]),
.r1_on(on[1]),
.r2_on(on[2]),
.r3_on(on[3]),
.ra(ra),
.rb(rb),
.ia(rom_address)
);

alu ALU (
.ck(ck),
.reset(reset),
.a(ra),
.b(rb),
.im(im),
.oz(oz),
.oi(oi),
.q_na(r_bus),
.co(co)
);

endmodule

0 件のコメント: