数字逻辑实验:Vivado设计流水线RISC-V处理器
endendcasecase(sel)endendendendendendcaseendmoduledisplay_top.sv:跑板子所需的顶层模块//生成0.005s周期的时钟count<=0;endendend。
同样是RISC-V处理器,一字之差导致代码量也多了很多。流水线处理器的模块实在是太多了,处理一条指令都得要五个阶段模块,而且阶段之间还得要过渡的模块,重定向,阻塞和清除的逻辑也有点不太好懂。特别涉及的变量更是让人眼花缭乱,花了大概两天把大致逻辑架构实现了,后面三天时间全在调试检查每个模块有没有缺少的变量或是写错名字的变量,只能说尽力了。话不多说,涉及的模块代码如下:
mux2.sv:一个2:1的选择器模块
`timescale 1ns / 1ps
module mux2(input logic[31:0]d0,
input logic[31:0]d1,
input logic s,
output logic[31:0]y);
assign y = s?d1:d0;
endmodule
pc_change.sv:用于调整PC变化的模块
`timescale 1ns / 1ps
module pc_change(input logic clk,
input logic stall_F,
input logic reset,
input logic [31:0]d,
output logic [31:0]q);
always_ff@(posedge clk,posedge reset)
if (reset)
q <= 0;
else if(stall_F)
q <= q;
else
q <= d;
endmodule
instr_mem.sv:指令存储器模块
`timescale 1ns / 1ps
module instr_mem(input logic[5:0] a,
output logic[31:0]rd);
/*
logic[31:0]RAM[63:0];
initial
$readmemh("C:\Users\DELL\Desktop\单周期RISC-V处理器设计\memfile.dat",RAM);
*/
// 不要声明很大的数组,FPGA板子放不下
//基本测试:用于跑simulation
logic[31:0]RAM[0:18] = { // 注意!指令存储器容量最多只有64个字!
32'h00500113,
32'h00c00193,
32'hff718393,
32'h0023e233,
32'h0041f2b3,
32'h004282b3,
32'h02728663,
32'h0041a233,
32'h00020463,
32'h00000293,
32'h0023a233,
32'h005203b3,
32'h402383b3,
32'h0471a223,
32'h05002103,
32'h008000ef,
32'h00100113,
32'h04202a23,
32'hfe000ee3 // beq $0,$0,self,跳转到自己,终止执行后续指令
};
//求1到100和的测试:用于跑板子
/*
logic[31:0]RAM[0:11] = { // 注意!指令存储器容量最多只有64个字!
32'h000003b7,
32'h00038393,
32'h00000437,
32'h06340413,
32'h000004b7,
32'h00048493,
32'h00944863,
32'h00148493,
32'h009383b3,
32'hff5ff0ef,
32'h04702a23,
32'hfe000ee3 // beq $0,$0,self,跳转到自己,终止执行后续指令
};
*/
assign rd = RAM[a]; // 注意!指令存储器容量最多只有64个字!
endmodule
control.sv:控制器,根据输入的机器码决定一系列控制信号模块
`timescale 1ns / 1ps
module control(input logic [6:0]opcode,
input logic [6:0]funct7,
input logic [2:0]funct3,
output logic [2:0]immpro_D,
output logic isonlyimm_D,
output logic memtoreg_D,
output logic memwrite_D,
output logic branch_beq_D,
output logic branch_bne_D,
output logic branch_blt_D,
output logic alusrc_D,
output logic regwrite_D,
output logic jump_D,
output logic [3:0]alucontrol_D
);
logic [15:0]controls;
always_comb
case(opcode)
7'b0110011://处理R指令
case(funct7)
7'b0000000:
case(funct3)
3'b000:controls=16'b1_0_0_0_0_0_0_0_0010_000_0;//add
3'b001:controls=16'b1_0_0_0_0_0_0_0_0100_000_0;//sll
3'b010:controls=16'b1_0_0_0_0_0_0_0_0111_000_0;//slt
3'b100:controls=16'b1_0_0_0_0_0_0_0_0101_000_0;//xor
3'b101:controls=16'b1_0_0_0_0_0_0_0_0011_000_0;//srl
3'b110:controls=16'b1_0_0_0_0_0_0_0_0001_000_0;//or
3'b111:controls=16'b1_0_0_0_0_0_0_0_0000_000_0;//and
default:controls=16'b0_0_0_0_0_0_0_0_0000_000_0;
endcase
7'b0100000:
case(funct3)
3'b000:controls=16'b1_0_0_0_0_0_0_0_0110_000_0;//sub
3'b101:controls=16'b1_0_0_0_0_0_0_0_1000_000_0;//sra
default:controls=16'b0_0_0_0_0_0_0_0_0000_000_0;
endcase
default:controls=16'b0_0_0_0_0_0_0_0_0000_000_0;
endcase
7'b0010011://第一类I指令
case(funct3)
3'b000:controls=16'b1_1_0_0_0_0_0_0_0010_001_0;//addi
3'b110:controls=16'b1_1_0_0_0_0_0_0_0001_001_0;//ori
3'b111:controls=16'b1_1_0_0_0_0_0_0_0000_001_0;//andi
default:controls=16'b0_0_0_0_0_0_0_0_0000_000_0;
endcase
7'b0000011://lw指令
controls=16'b1_1_0_0_0_0_1_0_0010_001_0;//lw
7'b0100011://sw指令
controls=16'b0_1_0_0_0_1_0_0_0010_010_0;//sw
7'b1100111://jalr指令
controls=16'b1_1_0_0_0_0_0_1_0010_001_0;//jalr
7'b1100011://B指令
case(funct3)
3'b000:controls=16'b0_0_1_0_0_0_0_0_0110_011_0;//beq
3'b001:controls=16'b0_0_0_1_0_0_0_0_0110_011_0;//bne
3'b100:controls=16'b0_0_0_0_1_0_0_0_0110_011_0;//blt
default:controls=16'b0_0_0_0_0_0_0_0_0000_000_0;
endcase
7'b1101111://J指令
controls=16'b0_0_0_0_0_0_0_1_0010_101_0;//jal
7'b0110111:
controls=16'b1_1_0_0_0_0_0_0_0010_100_1;//lui
default:controls=16'b0_0_0_0_0_0_0_0_0000_000_0;
endcase
assign {regwrite_D,alusrc_D,branch_beq_D,branch_bne_D,branch_blt_D,
memwrite_D,memtoreg_D,jump_D,alucontrol_D,immpro_D,isonlyimm_D} = controls;
endmodule
immprocess.sv:立即数处理模块
`timescale 1ns / 1ps
module immprocess(input logic[31:0]instr,
input logic[2:0]immpro,
output logic[31:0]y);
always_comb
case(immpro)
3'b001:y={{20{instr[31]}},instr[31:20]};
3'b010:y={{20{instr[31]}},instr[31:25],instr[11:7]};
3'b011:y={{19{instr[31]}},instr[31],instr[7],instr[30:25],instr[11:8],1'b0};
3'b100:y={instr[31:12],12'b0};
3'b101:y={{11{instr[31]}},instr[31],instr[19:12],instr[20],instr[30:21],1'b0};
default:y=32'b0;
endcase
endmodule
register_file.sv:寄存器文件模块
`timescale 1ns / 1ps
module register_file(input logic clk,
input logic we3,
input logic reset,
input logic[4:0] ra1,
input logic[4:0] ra2,
input logic[4:0] wa3,
input logic[31:0]wd3,
output logic[31:0]rd1,
output logic[31:0]rd2,
output logic[31:0]rf[31:0]);
//logic[31:0]rf[31:0];
//three ported register file
// read two ports combinationally
// write third port on rising edge of clk
// register 0 hardwired to0
// note:for pipelined processor,write third port on falling edge of clk
always_ff@(posedge clk,posedge reset)begin
if (we3)
rf[wa3] <= wd3;
else if(reset) begin
rf[0]=32'b0;rf[1]=32'b0;
rf[2]=32'b0;rf[3]=32'b0;
rf[4]=32'b0;rf[5]=32'b0;
rf[6]=32'b0;rf[7]=32'b0;
rf[8]=32'b0;rf[9]=32'b0;
rf[10]=32'b0;rf[11]=32'b0;
rf[12]=32'b0;rf[13]=32'b0;
rf[14]=32'b0;rf[15]=32'b0;
rf[16]=32'b0;rf[17]=32'b0;
rf[18]=32'b0;rf[19]=32'b0;
rf[20]=32'b0;rf[21]=32'b0;
rf[22]=32'b0;rf[23]=32'b0;
rf[24]=32'b0;rf[25]=32'b0;
rf[26]=32'b0;rf[27]=32'b0;
rf[28]=32'b0;rf[29]=32'b0;
rf[30]=32'b0;rf[31]=32'b0;end
end
assign rd1 = (ra1!= 0)?rf[ra1]:0;
assign rd2 = (ra2!= 0)?rf[ra2]:0;
endmodule
mux4.sv:一个4:1的选择器模块
`timescale 1ns / 1ps
module mux4(input logic[31:0]d0,
input logic[31:0]d1,
input logic[31:0]d2,
input logic[31:0]d3,
input logic [1:0]s,
output logic [31:0]y);
always_comb
case(s)
2'b00:y=d0;
2'b01:y=d1;
2'b10:y=d2;
2'b11:y=d3;
default:y=32'b0;
endcase
endmodule
pro_beq_signal.sv:处理汇编指令中beq的跳转信号模块
`timescale 1ns / 1ps
module pro_beq_signal(input logic[31:0] res1_D,
input logic[31:0] res2_D,
input logic branch_beq,
output logic pcsrc_beq
);
logic beq_D;
assign beq_D=(res1_D==res2_D);
assign pcsrc_beq=beq_D & branch_beq;
endmodule
pro_bne_signal.sv:处理汇编指令中bne的跳转信号模块
`timescale 1ns / 1ps
module pro_bne_signal(input logic[31:0] res1_D,
input logic[31:0] res2_D,
input logic branch_bne,
output logic pcsrc_bne
);
logic bne_D;
assign bne_D=(res1_D!=res2_D);
assign pcsrc_bne=bne_D & branch_bne;
endmodule
pro_blt_signal.sv:处理汇编指令中blt的跳转信号模块
`timescale 1ns / 1ps
module pro_blt_signal(input logic[31:0] res1_D,
input logic[31:0] res2_D,
input logic branch_blt,
output logic pcsrc_blt
);
logic blt_D;
assign blt_D=(res1_D<res2_D);
assign pcsrc_blt=blt_D & branch_blt;
endmodule
ALU.sv:根据alucontrol的信号决定ALU进行何种运算的模块
`timescale 1ns / 1ps
module ALU(input logic [31:0] srca,
input logic [31:0] srcb,
input logic [3:0] alucontrol,
output logic [31:0] aluout
);
always_comb
case (alucontrol)
4'b0010: aluout = srca + srcb;
4'b0110: aluout = srca - srcb;
4'b0000: aluout = srca & srcb;
4'b0001: aluout = srca | srcb;
4'b0111: aluout = (srca < srcb) ? 32'd1 : 32'd0;
4'b0011: aluout = srca >> srcb;
4'b0100: aluout = srca << srcb;
4'b0101: aluout = srca ^ srcb;
4'b1000: aluout = srca >>> srcb;
default: aluout = 32'b0;
endcase
endmodule
data_mem.sv:数据存储器模块
`timescale 1ns / 1ps
module data_mem(input logic clk,
input logic we,
input logic reset,
input logic[31:0]a,
input logic[31:0]wd,
output logic[31:0]rd);
// 不要声明很大的数组,FPGA板子放不下
logic[31:0]RAM[63:0]; // 注意!数据存储器容量最多只有64个字!
assign rd = RAM[a[7:2]]; // word aligned
always_ff@(posedge clk)begin
if (we)
RAM[a[7:2]] <= wd;
else if(reset)begin
for(integer i=0;i<64;i++)
RAM[i]=32'b0;
end
end
endmodule
fetch.sv:取指阶段的模块
`timescale 1ns / 1ps
module fetch(input logic clk,
input logic reset,
input logic stall_F,
input logic branch_or_jump,
input logic[31:0] pcbranch_D,
output logic[31:0] pc_F,
output logic[31:0] instr_F
);
logic [31:0]pcplus4,pcnext;
assign pcplus4=pc_F+32'b100;
mux2 pc_next(
.d0(pcplus4),
.d1(pcbranch_D),
.s(branch_or_jump),
.y(pcnext)
);
pc_change change(
.clk(clk),
.reset(reset),
.stall_F(stall_F),
.d(pcnext),
.q(pc_F)
);
instr_mem im(
.a(pc_F[7:2]),
.rd(instr_F)
);
endmodule
fetch_to_decode.sv:取指到译码阶段的过渡模块
`timescale 1ns / 1ps
module fetch_to_decode(input logic clk,
input logic branch_or_jump,
input logic reset,
input logic stall_D,
input logic[31:0] pc_F,
input logic[31:0] instr_F,
output logic[31:0] pc_D,
output logic[31:0] instr_D
);
always_ff@(posedge clk,posedge reset)begin
if(reset) begin
pc_D<=32'b0;
instr_D<=32'b0;end
else if(stall_D) begin
pc_D<=pc_D;
instr_D<=instr_D;end
else if(branch_or_jump) begin
pc_D<=32'b0;
instr_D<=32'b0;end
else begin
pc_D<=pc_F;
instr_D<=instr_F;end
end
endmodule
decode.sv:译码阶段的模块
`timescale 1ns / 1ps
module decode(input logic [31:0] instr_D,
input logic [31:0] pc_D,
input logic clk,
input logic reset,
input logic regwrite_W,
input logic [4:0]rd_W,
input logic [31:0]result_W,
input logic [31:0]ALUOut_E,
input logic [31:0]ALUOut_M,
input logic [1:0]ForwardAD,
input logic [1:0]ForwardBD,
output logic isonlyimm_D,
output logic memtoreg_D,
output logic memwrite_D,
output logic alusrc_D,
output logic regwrite_D,
output logic branch_or_jump,
output logic is_stall,
output logic [3:0]alucontrol_D,
output logic [31:0]imm_D,
output logic [31:0]res1_D,
output logic [31:0]res2_D,
output logic [4:0]rs1_D,
output logic [4:0]rs2_D,
output logic [4:0]rd_D,
output logic[31:0]rf[31:0],
output logic[31:0]pcbranch_D
);
logic [2:0]immpro_D;
logic branch_beq_D,branch_bne_D,branch_blt_D,jump_D;
logic pcsrc_bne,pcsrc_blt,pcsrc_beq;
logic [31:0]rd1_D,rd2_D;
control c(
.opcode(instr_D[6:0]),
.funct7(instr_D[31:25]),
.funct3(instr_D[14:12]),
.immpro_D(immpro_D),
.isonlyimm_D(isonlyimm_D),
.memtoreg_D(memtoreg_D),
.memwrite_D(memwrite_D),
.branch_beq_D(branch_beq_D),
.branch_bne_D(branch_bne_D),
.alusrc_D(alusrc_D),
.regwrite_D(regwrite_D),
.jump_D(jump_D),
.alucontrol_D(alucontrol_D),
.branch_blt_D(branch_blt_D)
);
immprocess immp(.instr(instr_D),
.immpro(immpro_D),
.y(imm_D)
);
register_file rfile(
.clk(clk),
.reset(reset),
.we3(regwrite_W),
.ra1(instr_D[19:15]),
.ra2(instr_D[24:20]),
.wa3(rd_W),
.wd3(result_W),
.rd1(rd1_D),
.rd2(rd2_D),
.rf(rf)
);
mux4 sel_1(
.d0(rd1_D),
.d1(ALUOut_M),
.d2(result_W),
.d3(ALUOut_E),
.s(ForwardAD),
.y(res1_D)
);
mux4 sel_2(
.d0(rd2_D),
.d1(ALUOut_M),
.d2(result_W),
.d3(ALUOut_E),
.s(ForwardBD),
.y(res2_D)
);
pro_beq_signal beq_D(.res1_D(res1_D),
.res2_D(res2_D),
.branch_beq(branch_beq_D),
.pcsrc_beq(pcsrc_beq)
);
pro_bne_signal bne_D(.res1_D(res1_D),
.res2_D(res2_D),
.branch_bne(branch_bne_D),
.pcsrc_bne(pcsrc_bne)
);
pro_blt_signal blt_D(.res1_D(res1_D),
.res2_D(res2_D),
.branch_blt(branch_blt_D),
.pcsrc_blt(pcsrc_blt)
);
assign rs1_D=instr_D[19:15];
assign rs2_D=instr_D[24:20];
assign rd_D=instr_D[11:7];
assign pcbranch_D=imm_D+pc_D;
assign is_stall=branch_blt_D | branch_beq_D | branch_bne_D;
assign branch_or_jump=pcsrc_beq | pcsrc_bne | pcsrc_blt | jump_D;
endmodule
decode_to_execute.sv:译码到执行阶段的过渡模块
`timescale 1ns / 1ps
module decode_to_execute(input logic clk,
input logic reset,
input logic flush_E,
input logic isonlyimm_D,
input logic memtoreg_D,
input logic memwrite_D,
input logic alusrc_D,
input logic regwrite_D,
input logic [3:0]alucontrol_D,
input logic [31:0]imm_D,
input logic [31:0]res1_D,
input logic [31:0]res2_D,
input logic [4:0]rs1_D,
input logic [4:0]rs2_D,
input logic [4:0]rd_D,
output logic isonlyimm_E,
output logic memtoreg_E,
output logic memwrite_E,
output logic alusrc_E,
output logic regwrite_E,
output logic [3:0]alucontrol_E,
output logic [31:0]imm_E,
output logic [31:0]res1_E,
output logic [31:0]res2_E,
output logic [4:0]rs1_E,
output logic [4:0]rs2_E,
output logic [4:0]rd_E
);
always_ff@(posedge clk,posedge reset)begin
if(reset | flush_E) begin
isonlyimm_E<=1'b0;
memwrite_E<=1'b0;
memtoreg_E<=1'b0;
alusrc_E<=1'b0;
regwrite_E<=1'b0;end
else begin
isonlyimm_E<=isonlyimm_D;
memwrite_E<=memwrite_D;
memtoreg_E<=memtoreg_D;
alusrc_E<=alusrc_D;
regwrite_E<=regwrite_D;end
end
always_ff@(posedge clk,posedge reset)begin
if(reset | flush_E) begin
imm_E<=32'b0;
res1_E<=32'b0;
res2_E<=32'b0;end
else begin
imm_E<=imm_D;
res1_E<=res1_D;
res2_E<=res2_D;;end
end
always_ff@(posedge clk,posedge reset)begin
if(reset | flush_E) begin
rs1_E<=5'b0;
rs2_E<=5'b0;
rd_E<=5'b0;end
else begin
rs1_E<=rs1_D;
rs2_E<=rs2_D;
rd_E<=rd_D;end
end
always_ff@(posedge clk,posedge reset)begin
if(reset | flush_E) alucontrol_E<=4'b0;
else alucontrol_E<=alucontrol_D;
end
endmodule
execute.sv:执行阶段的模块
`timescale 1ns / 1ps
module execute(input logic alusrc_E,
input logic [3:0]alucontrol_E,
input logic [31:0]imm_E,
input logic [31:0]imm_M,
input logic [31:0]res1_E,
input logic [31:0]res2_E,
input logic [1:0]ForwardAE,
input logic [1:0]ForwardBE,
input logic [31:0]result_W,
input logic [31:0]ALUOut_M,
output logic [31:0]ALUOut_E,
output logic [31:0]writedata_E
);
logic [31:0]srcA_E,srcB_E;
mux4 srca_E(
.d0(res1_E),
.d1(result_W),
.d2(ALUOut_M),
.d3(imm_M),
.s(ForwardAE),
.y(srcA_E)
);
mux4 srcb_E_mid(
.d0(res2_E),
.d1(result_W),
.d2(ALUOut_M),
.d3(imm_M),
.s(ForwardBE),
.y(writedata_E)
);
mux2 srcb_E(
.d0(writedata_E),
.d1(imm_E),
.s(alusrc_E),
.y(srcB_E)
);
ALU alu(
.srca(srcA_E),
.srcb(srcB_E),
.alucontrol(alucontrol_E),
.aluout(ALUOut_E)
);
endmodule
execute_to_memory.sv:执行到访存阶段的过渡模块
`timescale 1ns / 1ps
module execute_to_memory(input logic clk,
input logic reset,
input logic isonlyimm_E,
input logic memtoreg_E,
input logic memwrite_E,
input logic regwrite_E,
input logic [31:0]imm_E,
input logic [4:0]rd_E,
input logic [31:0]ALUOut_E,
input logic [31:0]writedata_E,
output logic isonlyimm_M,
output logic memtoreg_M,
output logic memwrite_M,
output logic regwrite_M,
output logic [31:0]imm_M,
output logic [4:0]rd_M,
output logic [31:0]ALUOut_M,
output logic [31:0]writedata_M
);
always_ff@(posedge clk,posedge reset)begin
if(reset) begin
isonlyimm_M<=1'b0;
memwrite_M<=1'b0;
memtoreg_M<=1'b0;
regwrite_M<=1'b0;end
else begin
isonlyimm_M<=isonlyimm_E;
memwrite_M<=memwrite_E;
memtoreg_M<=memtoreg_E;
regwrite_M<=regwrite_E;end
end
always_ff@(posedge clk,posedge reset)begin
if(reset) begin
imm_M<=32'b0;
ALUOut_M<=32'b0;
writedata_M<=32'b0;end
else begin
imm_M<=imm_E;
ALUOut_M<=ALUOut_E;
writedata_M<=writedata_E;;end
end
always_ff@(posedge clk,posedge reset)begin
if(reset) rd_M<=5'b0;
else rd_M<=rd_E;
end
endmodule
memory.sv:访存阶段的模块
`timescale 1ns / 1ps
module memory(input logic clk,
input logic reset,
input logic[31:0] ALUOut_M,
input logic[31:0] writedata_M,
input logic memwrite_M,
output logic[31:0] readdata_M
);
data_mem dmem (
.a(ALUOut_M),
.reset(reset),
.we(memwrite_M),
.wd(writedata_M),
.clk(clk),
.rd(readdata_M)
);
endmodule
memory_to_writeback.sv:访存到写回阶段的过渡模块
`timescale 1ns / 1ps
module memory_to_writeback(input logic clk,
input logic reset,
input logic[31:0] readdata_M,
input logic[31:0] ALUOut_M,
input logic[31:0] imm_M,
input logic[4:0] rd_M,
input logic regwrite_M,
input logic memtoreg_M,
input logic isonlyimm_M,
output logic[31:0] readdata_W,
output logic[31:0] ALUOut_W,
output logic[31:0] imm_W,
output logic[4:0] rd_W,
output logic regwrite_W,
output logic memtoreg_W,
output logic isonlyimm_W
);
always_ff@(posedge clk,posedge reset)begin
if(reset) begin
isonlyimm_W<=1'b0;
memtoreg_W<=1'b0;
regwrite_W<=1'b0;end
else begin
isonlyimm_W<=isonlyimm_M;
memtoreg_W<=memtoreg_M;
regwrite_W<=regwrite_M;end
end
always_ff@(posedge clk,posedge reset)begin
if(reset) begin
imm_W<=32'b0;
ALUOut_W<=32'b0;
readdata_W<=32'b0;end
else begin
imm_W<=imm_M;
ALUOut_W<=ALUOut_M;
readdata_W<=readdata_M;end
end
always_ff@(posedge clk,posedge reset)begin
if(reset) rd_W<=5'b0;
else rd_W<=rd_M;
end
endmodule
writeback.sv:写回阶段的模块
`timescale 1ns / 1ps
module writeback(input logic memtoreg_W,
input logic isonlyimm_W,
input logic[31:0] readdata_W,
input logic[31:0] ALUOut_W,
input logic[31:0] imm_W,
output logic[31:0] result_W
);
logic[31:0] res_mid;
mux2 r_mid(
.d0(ALUOut_W),
.d1(readdata_W),
.s(memtoreg_W),
.y(res_mid)
);
mux2 r_real(
.d0(res_mid),
.d1(imm_W),
.s(isonlyimm_W),
.y(result_W)
);
endmodule
Forward.sv:重定向模块
`timescale 1ns / 1ps
module Forward(input logic[4:0] rd_M,
input logic[4:0] rd_W,
input logic[4:0] rd_E,
input logic[4:0] rs1_E,
input logic[4:0] rs1_D,
input logic[4:0] rs2_E,
input logic[4:0] rs2_D,
input logic regwrite_E,
input logic regwrite_M,
input logic regwrite_W,
input logic isonlyimm_M,
output logic[1:0] ForwardAD,
output logic[1:0] ForwardBD,
output logic[1:0] ForwardAE,
output logic[1:0] ForwardBE
);
always_comb begin
if(rd_M!=5'b0 & rs1_E==rd_M & regwrite_M & isonlyimm_M) ForwardAE=2'b11;
else if(rd_M!=5'b0 & rs1_E==rd_M & regwrite_M & ~isonlyimm_M) ForwardAE=2'b10;
else if(rd_W!=5'b0 & rs1_E==rd_W & regwrite_W) ForwardAE=2'b01;
else ForwardAE=2'b00;end
always_comb begin
if(rd_M!=5'b0 & rs2_E==rd_M & regwrite_M & isonlyimm_M) ForwardBE=2'b11;
else if(rd_M!=5'b0 & rs2_E==rd_M & regwrite_M & ~isonlyimm_M) ForwardBE=2'b10;
else if(rd_W!=5'b0 & rs2_E==rd_W & regwrite_W) ForwardBE=2'b01;
else ForwardBE=2'b00;end
always_comb begin
if(rd_E!=5'b0 & rs1_D==rd_E & regwrite_E)ForwardAD=2'b11;
else if(rd_M!=5'b0 & rs1_D==rd_M & regwrite_M) ForwardAD=2'b01;
else if(rd_W!=5'b0 & rs1_D==rd_W & regwrite_W)ForwardAD=2'b10;
else ForwardAD=2'b00;end
always_comb begin
if(rd_E!=5'b0 & rs2_D==rd_E & regwrite_E)ForwardBD=2'b11;
else if(rd_M!=5'b0 & rs2_D==rd_M & regwrite_M) ForwardBD=2'b01;
else if(rd_W!=5'b0 & rs2_D==rd_W & regwrite_W)ForwardBD=2'b10;
else ForwardBD=2'b00;end
endmodule
stall_flush.sv:阻塞与清除模块
`timescale 1ns / 1ps
module stall_flush(input logic[4:0] rd_E,
input logic[4:0] rd_M,
input logic[4:0] rs1_D,
input logic[4:0] rs2_D,
input logic regwrite_E,
input logic memtoreg_E,
input logic memtoreg_M,
input logic is_stall,
output logic stall_F,
output logic stall_D,
output logic flush_E
);
logic lwstall,branchstall_1,branchstall_2;
assign lwstall=((rs1_D==rd_E) | (rs2_D==rd_E)) & memtoreg_E;
assign branchstall_1=is_stall & regwrite_E & (rs1_D==rd_E | rs2_D==rd_E);
assign branchstall_2=is_stall & memtoreg_M & (rs1_D==rd_M | rs2_D==rd_M);
assign branchstall=branchstall_1 | branchstall_2;
assign stall_F=lwstall | branchstall;
assign stall_D=lwstall | branchstall;
assign flush_E=lwstall | branchstall;
endmodule
以上是所必需的基本模块,下面的模块分别用于跑板子和跑simulation。
(一)跑simulation所需的模块:
top.sv:用于跑simulation的顶层模块
`timescale 1ns / 1ps
module top(input logic clk,
input logic reset,
output logic success_led,
output logic fail_led,
output logic[31:0] pc_D,
output logic[31:0] pc_F,
output logic[31:0] rf_7,
output logic[31:0] rf_2,
output logic [1:0]ForwardAD,
output logic [1:0]ForwardBD,
output logic [1:0]ForwardAE,
output logic [1:0]ForwardBE,
output logic stall_D,
output logic flush_E,
output logic stall_F
);
logic //stall_D,flush_E,stall_F,
regwrite_D,regwrite_E,regwrite_M,regwrite_W,
isonlyimm_D,isonlyimm_E,isonlyimm_M,isonlyimm_W,
memtoreg_D,memtoreg_E,memtoreg_M,memtoreg_W,
memwrite_D,memwrite_E,memwrite_M,
alusrc_D,alusrc_E,is_stall,branch_or_jump;
//logic [1:0]ForwardAE,ForwardBE,ForwardAD,ForwardBD;
logic [3:0]alucontrol_D,alucontrol_E;
logic [4:0]rs1_D,rs1_E,
rs2_D,rs2_E,
rd_D,rd_E,rd_M,rd_W;
logic [31:0] instr_F,instr_D,pcbranch_D,//pc_D,//pc_F,
result_W,res1_D,res2_D,res1_E,res2_E,
ALUOut_E,ALUOut_M,ALUOut_W,
imm_D,imm_E,imm_M,imm_W,
readdata_M,readdata_W,writedata_M,writedata_E;
logic [31:0]rf[31:0];
fetch fetch(
.clk(clk),
.reset(reset),
.stall_F(stall_F),
.branch_or_jump(branch_or_jump),
.pcbranch_D(pcbranch_D),
.pc_F(pc_F),
.instr_F(instr_F)
);
fetch_to_decode fetch_to_decode(
.clk(clk),
.reset(reset),
.branch_or_jump(branch_or_jump),
.stall_D(stall_D),
.pc_F(pc_F),
.instr_F(instr_F),
.pc_D(pc_D),
.instr_D(instr_D)
);
decode decode(
.instr_D(instr_D),
.pc_D(pc_D),
.clk(clk),
.reset(reset),
.regwrite_W(regwrite_W),
.rd_W(rd_W),
.result_W(result_W),
.ALUOut_M(ALUOut_M),
.ALUOut_E(ALUOut_E),
.ForwardAD(ForwardAD),
.ForwardBD(ForwardBD),
.isonlyimm_D(isonlyimm_D),
.memtoreg_D(memtoreg_D),
.memwrite_D(memwrite_D),
.alusrc_D(alusrc_D),
.regwrite_D(regwrite_D),
.branch_or_jump(branch_or_jump),
.is_stall(is_stall),
.alucontrol_D(alucontrol_D),
.imm_D(imm_D),
.res1_D(res1_D),
.res2_D(res2_D),
.rs1_D(rs1_D),
.rs2_D(rs2_D),
.rd_D(rd_D),
.rf(rf),
.pcbranch_D(pcbranch_D)
);
decode_to_execute decode_to_execute(
.clk(clk),
.reset(reset),
.flush_E(flush_E),
.isonlyimm_D(isonlyimm_D),
.memtoreg_D(memtoreg_D),
.memwrite_D(memwrite_D),
.alusrc_D(alusrc_D),
.regwrite_D(regwrite_D),
.alucontrol_D(alucontrol_D),
.imm_D(imm_D),
.res1_D(res1_D),
.res2_D(res2_D),
.rs1_D(rs1_D),
.rs2_D(rs2_D),
.rd_D(rd_D),
.isonlyimm_E(isonlyimm_E),
.memtoreg_E(memtoreg_E),
.memwrite_E(memwrite_E),
.alusrc_E(alusrc_E),
.regwrite_E(regwrite_E),
.alucontrol_E(alucontrol_E),
.imm_E(imm_E),
.res1_E(res1_E),
.res2_E(res2_E),
.rs1_E(rs1_E),
.rs2_E(rs2_E),
.rd_E(rd_E)
);
execute execute(
.alusrc_E(alusrc_E),
.alucontrol_E(alucontrol_E),
.imm_E(imm_E),
.imm_M(imm_M),
.res1_E(res1_E),
.res2_E(res2_E),
.ForwardAE(ForwardAE),
.ForwardBE(ForwardBE),
.result_W(result_W),
.ALUOut_M(ALUOut_M),
.ALUOut_E(ALUOut_E),
.writedata_E(writedata_E)
);
execute_to_memory execute_to_memory(.clk(clk),
.reset(reset),
.isonlyimm_E(isonlyimm_E),
.memtoreg_E(memtoreg_E),
.memwrite_E(memwrite_E),
.regwrite_E(regwrite_E),
.imm_E(imm_E),
.rd_E(rd_E),
.ALUOut_E(ALUOut_E),
.writedata_E(writedata_E),
.isonlyimm_M(isonlyimm_M),
.memtoreg_M(memtoreg_M),
.memwrite_M(memwrite_M),
.regwrite_M(regwrite_M),
.imm_M(imm_M),
.rd_M(rd_M),
.ALUOut_M(ALUOut_M),
.writedata_M(writedata_M)
);
memory memory(
.clk(clk),
.reset(reset),
.ALUOut_M(ALUOut_M),
.writedata_M(writedata_M),
.memwrite_M(memwrite_M),
.readdata_M(readdata_M)
);
memory_to_writeback memory_to_writeback(
.clk(clk),
.reset(reset),
.readdata_M(readdata_M),
.ALUOut_M(ALUOut_M),
.imm_M(imm_M),
.rd_M(rd_M),
.regwrite_M(regwrite_M),
.memtoreg_M(memtoreg_M),
.isonlyimm_M(isonlyimm_M),
.readdata_W(readdata_W),
.ALUOut_W(ALUOut_W),
.imm_W(imm_W),
.rd_W(rd_W),
.regwrite_W(regwrite_W),
.memtoreg_W(memtoreg_W),
.isonlyimm_W(isonlyimm_W)
);
writeback writeback(
.memtoreg_W(memtoreg_W),
.isonlyimm_W(isonlyimm_W),
.readdata_W(readdata_W),
.ALUOut_W(ALUOut_W),
.imm_W(imm_W),
.result_W(result_W)
);
Forward Forward(
.rd_M(rd_M),
.rd_W(rd_W),
.rd_E(rd_E),
.rs1_E(rs1_E),
.rs1_D(rs1_D),
.rs2_E(rs2_E),
.rs2_D(rs2_D),
.regwrite_M(regwrite_M),
.regwrite_E(regwrite_E),
.regwrite_W(regwrite_W),
.isonlyimm_M(isonlyimm_M),
.ForwardAD(ForwardAD),
.ForwardBD(ForwardBD),
.ForwardAE(ForwardAE),
.ForwardBE(ForwardBE)
);
stall_flush stall_flush(
.rd_E(rd_E),
.rd_M(rd_M),
.rs1_D(rs1_D),
.rs2_D(rs2_D),
.regwrite_E(regwrite_E),
.memtoreg_M(memtoreg_M),
.memtoreg_E(memtoreg_E),
.is_stall(is_stall),
.stall_F(stall_F),
.stall_D(stall_D),
.flush_E(flush_E)
);
assign rf_7=rf[7];
assign rf_2=rf[2];
// 加入两个led指示灯。
//求和:当写入存储器地址84且7号寄存器数据是5050时,点亮success_led灯;如果第1次写入的地址不是80,点亮fail_led灯
// 测试:当写入存储器地址84且2号寄存器数据是7时,点亮success_led灯;如果第1次写入的地址不是80,点亮fail_led灯
always_ff @(posedge clk,posedge reset)
if (reset)
begin
success_led <= 1'b0;
fail_led <= 1'b0;
end
else if (memwrite_M == 1'b1)
begin
if (ALUOut_M == 84 & rf[2] == 7)
success_led <= 1'b1;
else if (ALUOut_M != 80)
fail_led <= 1'b1;
end
endmodule
testbench.sv:用于跑simulation的仿真波形图
`timescale 1ns / 1ps
module testbench();
logic clk;
logic reset;
logic success_led;
logic fail_led;
logic [31:0]pc_D;
logic [31:0]pc_F;
logic [31:0]rf_7;
logic [31:0]rf_2;
logic [1:0]ForwardAD;
logic [1:0]ForwardBD;
logic [1:0]ForwardAE;
logic [1:0]ForwardBE;
logic stall_D;
logic flush_E;
logic stall_F;
// instantiate device to be tested
top dut(
.clk(clk),
.reset(reset),
.success_led(success_led),
.fail_led(fail_led),
.pc_D(pc_D),
.pc_F(pc_F),
.rf_7(rf_7),
.rf_2(rf_2),
.ForwardAD(ForwardAD),
.ForwardBD(ForwardBD),
.ForwardAE(ForwardAE),
.ForwardBE(ForwardBE),
.stall_D(stall_D),
.flush_E(flush_E),
.stall_F(stall_F)
);
// initialize test
initial
begin
reset = 1;
#20;
reset = 0;
end
// generate clock to sequence tests
always
begin
clk = 1;
#5;
clk = 0;
#5;
end
// check results
always@(posedge clk)
begin
if (success_led)
begin
$display("Simulation succeeded");
end
if (fail_led)
begin
$display("Simulation failed");
end
end
endmodule
(二)跑板子所需的模块
display.sv:用于让板子显示最后求和得到的结果
`timescale 1ns / 1ps
module display(
input clk,
input [31:0]num,
output logic [10:0] disp_7seg
);
logic [1:0] sel=0;
logic [19:0]count=0;
logic [3:0] num1,num2,num3,num4,disp_number;
always@(posedge clk)
begin
sel<=sel+1;
if(sel==4)
sel<=0;
end
assign num1=num/1000%10;
assign num2=num/100%10;
assign num3=num/10%10;
assign num4=num%10;
always_comb
case(disp_number)
4'd0: disp_7seg[6:0] = 7'b0000001;
4'd1: disp_7seg[6:0] = 7'b1001111;
4'd2: disp_7seg[6:0] = 7'b0010010;
4'd3: disp_7seg[6:0] = 7'b0000110;
4'd4: disp_7seg[6:0] = 7'b1001100;
4'd5: disp_7seg[6:0] = 7'b0100100;
4'd6: disp_7seg[6:0] = 7'b0100000;
4'd7: disp_7seg[6:0] = 7'b0001111;
4'd8: disp_7seg[6:0] = 7'b0000000;
4'd9: disp_7seg[6:0] = 7'b0000100;
default: disp_7seg[6:0] = 7'b1111111;
endcase
always_comb
case(sel)
0: begin disp_7seg[10:7] = 4'b1110; disp_number = num4; end
1: begin disp_7seg[10:7] = 4'b1101; disp_number = num3; end
2: begin disp_7seg[10:7] = 4'b1011; disp_number = num2; end
3: begin disp_7seg[10:7] = 4'b0111; disp_number = num1; end
default:begin disp_7seg[10:7] = 4'b1111; disp_number = 4'd0; end
endcase
endmodule
display_top.sv:跑板子所需的顶层模块
`timescale 1ns / 1ps
module display_top(input logic clk,
input logic reset,
input logic s1,
input logic s2,
input logic s3,
input logic s4,
input logic s5,
output logic [10:0] disp_7seg
);
logic stall_D,flush_E,branch_or_jump,stall_F,
regwrite_D,regwrite_E,regwrite_M,regwrite_W,
isonlyimm_D,isonlyimm_E,isonlyimm_M,isonlyimm_W,
memtoreg_D,memtoreg_E,memtoreg_M,memtoreg_W,
memwrite_D,memwrite_E,memwrite_M,
alusrc_D,alusrc_E,is_stall,s_clk,show_clk;
logic [1:0]ForwardAE,ForwardBE,ForwardAD,ForwardBD;
logic [3:0]alucontrol_D,alucontrol_E;
logic [4:0]rs1_D,rs1_E,
rs2_D,rs2_E,
rd_D,rd_E,rd_M,rd_W;
logic [31:0] instr_F,instr_D,pcbranch_D,pc_D,pc_F,
result_W,res1_D,res2_D,res1_E,res2_E,
ALUOut_E,ALUOut_M,ALUOut_W,
imm_D,imm_E,imm_M,imm_W,num,
readdata_M,readdata_W,writedata_M,writedata_E;
logic [31:0]rf[31:0];
//生成0.005s周期的时钟
integer total=5000000;
integer count=0;
always_ff@(posedge clk,posedge reset)begin
if(reset) begin
count<=0;
s_clk<=1'b0;end
else begin
count<=count+1;
if (count==total)begin
s_clk<=~s_clk;
count<=0;end
end
end
//生成周期为0.00001s的时钟,用于数码管展示结果
integer total_s=10000;
integer count_s=0;
always_ff@(posedge clk,posedge reset)begin
if(reset) begin
count_s<=0;
show_clk<=1'b0;end
else begin
count_s<=count_s+1;
if (count_s==total_s)begin
show_clk<=~show_clk;
count_s<=0;end
end
end
fetch fetch(
.clk(s_clk),
.reset(reset),
.stall_F(stall_F),
.branch_or_jump(branch_or_jump),
.pcbranch_D(pcbranch_D),
.pc_F(pc_F),
.instr_F(instr_F)
);
fetch_to_decode fetch_to_decode(
.clk(s_clk),
.reset(reset),
.branch_or_jump(branch_or_jump),
.stall_D(stall_D),
.pc_F(pc_F),
.instr_F(instr_F),
.pc_D(pc_D),
.instr_D(instr_D)
);
decode decode(
.instr_D(instr_D),
.pc_D(pc_D),
.clk(s_clk),
.reset(reset),
.regwrite_W(regwrite_W),
.rd_W(rd_W),
.result_W(result_W),
.ALUOut_M(ALUOut_M),
.ALUOut_E(ALUOut_E),
.ForwardAD(ForwardAD),
.ForwardBD(ForwardBD),
.isonlyimm_D(isonlyimm_D),
.memtoreg_D(memtoreg_D),
.memwrite_D(memwrite_D),
.alusrc_D(alusrc_D),
.regwrite_D(regwrite_D),
.branch_or_jump(branch_or_jump),
.is_stall(is_stall),
.alucontrol_D(alucontrol_D),
.imm_D(imm_D),
.res1_D(res1_D),
.res2_D(res2_D),
.rs1_D(rs1_D),
.rs2_D(rs2_D),
.rd_D(rd_D),
.rf(rf),
.pcbranch_D(pcbranch_D)
);
decode_to_execute decode_to_execute(
.clk(s_clk),
.reset(reset),
.flush_E(flush_E),
.isonlyimm_D(isonlyimm_D),
.memtoreg_D(memtoreg_D),
.memwrite_D(memwrite_D),
.alusrc_D(alusrc_D),
.regwrite_D(regwrite_D),
.alucontrol_D(alucontrol_D),
.imm_D(imm_D),
.res1_D(res1_D),
.res2_D(res2_D),
.rs1_D(rs1_D),
.rs2_D(rs2_D),
.rd_D(rd_D),
.isonlyimm_E(isonlyimm_E),
.memtoreg_E(memtoreg_E),
.memwrite_E(memwrite_E),
.alusrc_E(alusrc_E),
.regwrite_E(regwrite_E),
.alucontrol_E(alucontrol_E),
.imm_E(imm_E),
.res1_E(res1_E),
.res2_E(res2_E),
.rs1_E(rs1_E),
.rs2_E(rs2_E),
.rd_E(rd_E)
);
execute execute(
.alusrc_E(alusrc_E),
.alucontrol_E(alucontrol_E),
.imm_E(imm_E),
.imm_M(imm_M),
.res1_E(res1_E),
.res2_E(res2_E),
.ForwardAE(ForwardAE),
.ForwardBE(ForwardBE),
.result_W(result_W),
.ALUOut_M(ALUOut_M),
.ALUOut_E(ALUOut_E),
.writedata_E(writedata_E)
);
execute_to_memory execute_to_memory(.clk(s_clk),
.reset(reset),
.isonlyimm_E(isonlyimm_E),
.memtoreg_E(memtoreg_E),
.memwrite_E(memwrite_E),
.regwrite_E(regwrite_E),
.imm_E(imm_E),
.rd_E(rd_E),
.ALUOut_E(ALUOut_E),
.writedata_E(writedata_E),
.isonlyimm_M(isonlyimm_M),
.memtoreg_M(memtoreg_M),
.memwrite_M(memwrite_M),
.regwrite_M(regwrite_M),
.imm_M(imm_M),
.rd_M(rd_M),
.ALUOut_M(ALUOut_M),
.writedata_M(writedata_M)
);
memory memory(
.clk(s_clk),
.reset(reset),
.ALUOut_M(ALUOut_M),
.writedata_M(writedata_M),
.memwrite_M(memwrite_M),
.readdata_M(readdata_M)
);
memory_to_writeback memory_to_writeback(
.clk(s_clk),
.reset(reset),
.readdata_M(readdata_M),
.ALUOut_M(ALUOut_M),
.imm_M(imm_M),
.rd_M(rd_M),
.regwrite_M(regwrite_M),
.memtoreg_M(memtoreg_M),
.isonlyimm_M(isonlyimm_M),
.readdata_W(readdata_W),
.ALUOut_W(ALUOut_W),
.imm_W(imm_W),
.rd_W(rd_W),
.regwrite_W(regwrite_W),
.memtoreg_W(memtoreg_W),
.isonlyimm_W(isonlyimm_W)
);
writeback writeback(
.memtoreg_W(memtoreg_W),
.isonlyimm_W(isonlyimm_W),
.readdata_W(readdata_W),
.ALUOut_W(ALUOut_W),
.imm_W(imm_W),
.result_W(result_W)
);
Forward Forward(
.rd_M(rd_M),
.rd_W(rd_W),
.rd_E(rd_E),
.rs1_E(rs1_E),
.rs1_D(rs1_D),
.rs2_E(rs2_E),
.rs2_D(rs2_D),
.regwrite_M(regwrite_M),
.regwrite_E(regwrite_E),
.regwrite_W(regwrite_W),
.isonlyimm_M(isonlyimm_M),
.ForwardAD(ForwardAD),
.ForwardBD(ForwardBD),
.ForwardAE(ForwardAE),
.ForwardBE(ForwardBE)
);
stall_flush stall_flush(
.rd_E(rd_E),
.rd_M(rd_M),
.rs1_D(rs1_D),
.rs2_D(rs2_D),
.regwrite_E(regwrite_E),
.memtoreg_M(memtoreg_M),
.memtoreg_E(memtoreg_E),
.is_stall(is_stall),
.stall_F(stall_F),
.stall_D(stall_D),
.flush_E(flush_E)
);
assign num=rf[{s1,s2,s3,s4,s5}];
display display(
.clk(show_clk),
.num(num),
.disp_7seg(disp_7seg)
);
endmodule
约束文件(可以根据自己需求自行修改调整):
set_property PACKAGE_PIN W5 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN V17 [get_ports reset]
set_property IOSTANDARD LVCMOS33 [get_ports reset]
set_property PACKAGE_PIN R2 [get_ports s1]
set_property IOSTANDARD LVCMOS33 [get_ports s1]
set_property PACKAGE_PIN T1 [get_ports s2]
set_property IOSTANDARD LVCMOS33 [get_ports s2]
set_property PACKAGE_PIN U1 [get_ports s3]
set_property IOSTANDARD LVCMOS33 [get_ports s3]
set_property PACKAGE_PIN W2 [get_ports s4]
set_property IOSTANDARD LVCMOS33 [get_ports s4]
set_property PACKAGE_PIN R3 [get_ports s5]
set_property IOSTANDARD LVCMOS33 [get_ports s5]
set_property PACKAGE_PIN W4 [get_ports {disp_7seg[10]}]
set_property PACKAGE_PIN V4 [get_ports {disp_7seg[9]}]
set_property PACKAGE_PIN U4 [get_ports {disp_7seg[8]}]
set_property PACKAGE_PIN U2 [get_ports {disp_7seg[7]}]
set_property PACKAGE_PIN W7 [get_ports {disp_7seg[6]}]
set_property PACKAGE_PIN W6 [get_ports {disp_7seg[5]}]
set_property PACKAGE_PIN U8 [get_ports {disp_7seg[4]}]
set_property PACKAGE_PIN V8 [get_ports {disp_7seg[3]}]
set_property PACKAGE_PIN U5 [get_ports {disp_7seg[2]}]
set_property PACKAGE_PIN V5 [get_ports {disp_7seg[1]}]
set_property PACKAGE_PIN U7 [get_ports {disp_7seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_7seg[0]}]
PS:(1)注意跑板子与跑仿真图之间切换时,instr_mem.sv中的测试指令集机器码也要切换;
(2)跑板子时将跑仿真图所需的两个模块(top.sv与testbench.sv)disable掉,跑仿真图时同理;
(3)板子最后实现了显示每一次迭代求和计算结果的功能。具体怎么显示可以参考display_top.sv的代码去在板子上操作出来(提示:最后的计算结果存储在7号寄存器中);
(4)记得文件路径不要带中文,否则跑不了板子!!!(不再吃亏)
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)