我是靠谱客的博主 美好流沙,最近开发中收集的这篇文章主要介绍Verilog RTL代码新手上路教程1. 多路选择器2. 交叉开关3.优先编码器4. 多路译码器8.乘法器9.计数器10.状态机11.移位寄存器,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1. 多路选择器

 

学生实验

做一个4选1的mux,并且进行波形仿真 和2选1的mux对比,观察资源消耗的变化

//MUX21

module top(

  IN0       ,   // input 1

  IN1       ,   // input 2

  SEL       ,   // select

  OUT       );  // out data

parameter WL = 16;      // 输入输出数据信号位宽

input [WL-1:0] IN0, IN1;// 选择器的两个输入数据信号

input SEL;              // 通道选通的控制信号

output[WL-1:0] OUT;     // 选择器的输入数据信号

reg   [WL-1:0] OUT;

// 生成组合逻辑的代码

always @ (IN0 or IN1 or SEL) begin

  if(SEL) // SEL为1 选择输入1

    OUT = IN1;

  else    // SEL为0 选择输入0

    OUT = IN0;

end

endmodule
//MUX41

// module  top41, 选择器(mux41)的代码,

module top41(

  IN0       ,   // input 1

  IN1       ,   // input 2

  IN2       ,   // input 3

  IN3       ,   // input 4

  SEL       ,   // select1,2

  OUT       );  // out data

parameter WL = 16;      // 输入输出数据信号位宽

input [WL-1:0] IN0, IN1, IN2, IN3;// 选择器的两个输入数据信号

input [1:0] SEL;              // 通道选通的控制信号

output[WL-1:0] OUT;     // 选择器的输入数据信号

reg   [WL-1:0] OUT;

// 生成组合逻辑的代码

always @ (IN0 or IN1 or IN2 or IN3 or SEL) begin

  //if(SEL=3) // SEL为1 选择输入1

    //OUT = IN1;

  //else    // SEL为0 选择输入0

    //OUT = IN0;

  case(SEL)

      0: OUT=IN0;

          1: OUT=IN1;

          2: OUT=IN2;

          3: OUT=IN3;

          default: OUT=0;

          endcase

end

endmodule

// endmodule top

图像对比

4选1资源消耗是2选1MUX的两倍

2. 交叉开关

学生实验

编写一个4X4路交叉开关的RTL,然后编译,看RTL View 比较2x2与4x4之间消耗资源的区别。通过对比资源,你有什么结论? 返回顶部

// module  top, a 2x2 crossbar switch circuit

module top(

  IN0       ,   // input 1

  IN1       ,   // input 2

  SEL0      ,   // select the output0 source

  SEL1      ,   // select the output1 source

  OUT0      ,   // output data 0

  OUT1      );  // output data 1

parameter WL = 16;

input [WL-1:0] IN0, IN1;

input SEL0, SEL1;

output[WL-1:0] OUT0, OUT1;

reg   [WL-1:0] OUT0, OUT1;

// get the OUT0

always @ (IN0 or IN1 or SEL0) begin

  if(SEL0)

    OUT0 = IN1;

  else

    OUT0 = IN0;

end

// get the OUT1

always @ (IN0 or IN1 or SEL1) begin

  if(SEL1)

    OUT1 = IN1;

  else

    OUT1 = IN0;

end

endmodule
// module  top, a 4x4 crossbar switch circuit

module top(

  IN0       ,   // input 1

  IN1       ,   // input 2

  IN2       ,   // input 3

  IN3       ,   // input 4

  SEL0      ,   // select the output0 source

  SEL1      ,   // select the output1 source

  SEL2      ,   // select the output2 source

  SEL3      ,   // select the output3 source

  OUT0      ,   // output data 0

  OUT1      ,   // output data 1

  OUT2      ,   // output data 2

  OUT3      );  // output data 3

parameter WL = 16;

input [WL-1:0] IN0, IN1, IN2, IN3;

input SEL0, SEL1, SEL2, SEL3;

output[WL-1:0] OUT0, OUT1, OUT2, OUT3;

reg   [WL-1:0] OUT0, OUT1, OUT2, OUT3;

// get the OUT0

always @ (IN0 or IN1 or IN2 or IN3 or SEL0 or SEL1) begin

  if(SEL0==0&&SEL1==0)

    OUT0 = IN0;

  else if(SEL0==0&&SEL1==1)

    OUT0 = IN1;

  else if(SEL0==1&&SEL1==0)

    OUT0 = IN2;

  else

    OUT0 = IN3;

end

// get the OUT1

always @ (IN0 or IN1 or IN2 or IN3 or SEL1 or SEL2) begin

  if(SEL1==0&&SEL2==0)

    OUT1 = IN0;

  else if(SEL1==0&&SEL2==1)

    OUT1 = IN1;

  else if(SEL1==1&&SEL2==0)

    OUT1 = IN2;

  else

    OUT1 = IN3;

end

// get the OUT2

always @ (IN0 or IN1 or IN2 or IN3 or SEL2 or SEL3) begin

  if(SEL2==0&&SEL3==0)

    OUT2 = IN0;

  else if(SEL2==0&&SEL3==1)

    OUT2 = IN1;

  else if(SEL2==1&&SEL3==0)

    OUT2 = IN2;

  else

    OUT2 = IN3;

end

// get the OUT3

always @ (IN0 or IN1 or IN2 or IN3 or SEL0 or SEL3) begin

  if(SEL0==0&&SEL3==0)

    OUT3 = IN0;

  else if(SEL0==0&&SEL3==1)

    OUT3 = IN1;

  else if(SEL0==1&&SEL3==0)

    OUT3 = IN2;

  else

    OUT3 = IN3;

end

endmodule

  

 

  资源对比:

3.优先编码器

学生实验

  • 编写一个8输入的优先编码器,然后编译,看RTL View
// module top, 4 input priority encoder with zero input check

module top(

  IN        ,   // input 

  OUT       );  // output

input [3:0] IN;

output[2:0] OUT;

reg   [2:0] OUT;

// get the OUT

always @ (IN) begin

   if(IN[3])       // 第一优先

     OUT = 3'b011;

   else if(IN[2])  // 第二优先

     OUT = 3'b010;

   else if(IN[1])  // 第三优先

     OUT = 3'b001;

   else if(IN[0])  // 第四优先

     OUT = 3'b000;

   else            // 什么都没有检测到

     OUT = 3'b111; // 输出值可自定义,不和上面的输出值混淆即可

end

endmodule
// module top, 8 input priority encoder with zero input check

module top(

  IN        ,   // input 

  OUT       );  // output

input [7:0] IN;

output[3:0] OUT;

reg   [3:0] OUT;

// get the OUT

always @ (IN) begin

   if(IN[7])       // 第一优先

     OUT = 4'b0111;

   else if(IN[6])  // 第二优先

     OUT = 4'b0110;

   else if(IN[5])  // 第三优先

     OUT = 4'b0101;

   else if(IN[4])  // 第四优先

     OUT = 4'b0100;

   else if(IN[3])  // 第五优先

     OUT = 4'b0011;

   else if(IN[2])  // 第六优先

     OUT = 4'b0010;

   else if(IN[1])  // 第七优先

     OUT = 4'b0001;

   else if(IN[0])  // 第八优先

     OUT = 4'b0000;

   else            // 什么都没有检测到

     OUT = 4'b1111; // 输出值可自定义,不和上面的输出值混淆即可

end

endmodule

4. 多路译码器

学生实验

  • 编写一个4-16的译码器,编译
  • 和3-8译码器对比资源开销
  • 看RTL View
// module top, 3 to 8 decoder

module top(

  IN        ,   // input 

  OUT       );  // output

input [2:0] IN;

output[7:0] OUT;

reg   [7:0] OUT;

// get the OUT

always @ (IN) begin

  case(IN)

    3'b000: OUT = 8'b0000_0001;

    3'b001: OUT = 8'b0000_0010;

    3'b010: OUT = 8'b0000_0100;

    3'b011: OUT = 8'b0000_1000;

    3'b100: OUT = 8'b0001_0000;

    3'b101: OUT = 8'b0010_0000;

    3'b110: OUT = 8'b0100_0000;

    3'b111: OUT = 8'b1000_0000;

    //  full case 不需要写default,否则一定要有default

  endcase

end

endmodule
​
// module top, 4 to 16 decoder

module top(

  IN        ,   // input 

  OUT       );  // output

input [3:0] IN;

output[15:0] OUT;

reg   [15:0] OUT;

// get the OUT

always @ (IN) begin

  case(IN)

    4'b0000: OUT = 16'b0000_0000-0000_0001;

    4'b0001: OUT = 16'b0000_0000-0000_0010;

    4'b0010: OUT = 16'b0000_0000-0000_0100;

    4'b0011: OUT = 16'b0000_0000-0000_1000;

    4'b0100: OUT = 16'b0000_0000-0001_0000;

    4'b0101: OUT = 16'b0000_0000-0010_0000;

    4'b0110: OUT = 16'b0000_0000-0100_0000;

    4'b0111: OUT = 16'b0000_0000-1000_0000;

     4'b1000: OUT = 16'b0000_0001-0000_0000;

    4'b1001: OUT = 16'b0000_0010-0000_0000;

    4'b1010: OUT = 16'b0000_0100-0000_0000;

    4'b1011: OUT = 16'b0000_1000-0000_0000;

    4'b1100: OUT = 16'b0001_0000-0000_0000;

    4'b1101: OUT = 16'b0010_0000-0000_0000;

    4'b1110: OUT = 16'b0100_0000-0000_0000;

    4'b1111: OUT = 16'b1000_0000-0000_0000;

    //  full case 不需要写default,否则一定要有default

  endcase

end

endmodule

5.无符号加法器

输入和输出数据都是无符号的整数,常用于计数器累加和计算地址序号

要点

  • 目测一下,可以发现加法器的输入数据和对应结果在时间上是有延迟的,这是组合逻辑门的延迟造成的。(请估算一下延迟长度)
  • 在相邻的两个正确的输出结果之间是有些“毛刺”结果的,而且“毛刺”的时间长度还不同
  • 请思考,2比特的信号,00翻转成11,两个位能做到绝对的同时翻转么?
  • 请思考,对比一下,00翻转成11,和 00翻转成 10,哪个变化的多?哪个翻转过程中的过渡状态多?
  • 注意输入和输出的信号位宽数
  • 请思考,如果本例中,所有输入信号和输出信号宽度都是4比特,那么输出结果会一直正确么?

学生实验

  • 把加法器的输出信号改成4比特位宽,编译,波形仿真。观察输出结果,说出输出和输入的对应关系。
  • 把加法器的输入信号改成8比特位宽,编译,波形仿真。观察加法器的输出延迟,和4比特输入位宽的情况对比,你有什么结论,为什么?
//module top,unsigned adder 4 bit

module top(

  IN1   ,

  IN2   ,

  OUT   );

input[3:0] IN1, IN2;

output[4:0] OUT;

reg[4:0] OUT;

always@(IN1 or IN2) begin // 生成组合逻辑的always 块

  OUT = IN1 + IN2;

end

endmodule

//module top,unsigned adder 8 bit

module top(

  IN1   ,

  IN2   ,

  OUT   );

input[7:0] IN1, IN2;

output[7:0] OUT;

reg[8:0] OUT;

always@(IN1 or IN2) begin // 生成组合逻辑的always 块

  OUT = IN1 + IN2;

end

endmodule

1.延迟12-14ns左右

2.2比特的信号,00翻转成11,两个位不能做到绝对的同时翻转。

3. 00翻转成10翻转过程中的过渡状态多。

8bit输入延迟大于4bit输入延迟。因为8bit输入涉及的位数更多,每一位的延迟叠加,自然会使延迟更大。

6.补码加法器

输入和输出数据都是2补码形式的有符号数,常用于数字信号处理电路

学生实验

把加法器的输出信号改成4比特位宽,编译,波形仿真。观察输出结果,观察输出结果在什么时候是正确的?。 把加法器的输入信号改成8比特位宽,编译,波形仿真。观察加法器的输出延迟,和4比特输入位宽的情况对比,你有什么结论,为什么?

module top(

  IN1   ,

  IN2   ,

  OUT   );

input signed [3:0] IN1, IN2;

output signed [4:0] OUT;

reg signed [4:0] OUT;

always@(IN1 or IN2) begin // 生成组合逻辑的always 块

  OUT = IN1 + IN2;

end

endmodule

//4bit

module top(

  IN1   ,

  IN2   ,

  OUT   );

input signed [3:0] IN1, IN2;

output signed [3:0] OUT;

reg signed [3:0] OUT;

always@(IN1 or IN2) begin // 生成组合逻辑的always 块

  OUT = IN1 + IN2;

end

endmodule

4比特位宽的输出最高位为符号位,而输出范围为:-7~7,即输出值在-7~7内计算结果正确,但超出该范围则计算错误。

//输入为8bit

module top(

  IN1   ,

  IN2   ,

  OUT   );

input signed [7:0] IN1, IN2;

output signed [7:0] OUT;

reg signed [12:0] OUT;

always@(IN1 or IN2) begin // 生成组合逻辑的always 块

  OUT = IN1 + IN2;

end

endmodule

 观察可得,8bit输入与4bit输入延迟差别不大。
7.带流水线的加法器

 

学生实验

不改变流水线的级数,把加法器的输入信号改成8比特位宽,编译,波形仿真,和不带流水线的情况对比一下,你有什么结论? 在8比特输入位宽的情况下,在输入上再添加一级流水线,观察编译和仿真的结果,你有什么结论?

//4bit带宽

module top(

  IN1   ,

  IN2   ,

  CLK   ,

  OUT   );

input  [3:0] IN1, IN2;

input CLK;

output  [4:0] OUT;

reg [3:0] in1_d1R, in2_d1R;

reg  [4:0] adder_out, OUT;

always@(posedge CLK) begin // 生成D触发器的always块

  in1_d1R <= IN1;

  in2_d1R <= IN2;

  OUT     <= adder_out;

end

always@(in1_d1R or in2_d1R) begin // 生成组合逻辑的always 块

  adder_out = in1_d1R + in2_d1R;

end

endmodule

带流水线的波形

不带流水线的波形

可以观察到,带流水线的波形毛刺明显少于不带流水线的波形。而带流水线的加法器输入数据和其对应的结果不在一个时钟周期。
 

//8bit带宽带流水线的波形

module top(

  IN1   ,

  IN2   ,

  CLK   ,

  OUT   );

input  [7:0] IN1, IN2;

input CLK;

output  [12:0] OUT;

reg [7:0] in1_d1R, in2_d1R;

reg  [12:0] adder_out, OUT;

always@(posedge CLK) begin // 生成D触发器的always块

  in1_d1R <= IN1;

  in2_d1R <= IN2;

  OUT     <= adder_out;

end

always@(in1_d1R or in2_d1R) begin // 生成组合逻辑的always 块

  adder_out = in1_d1R + in2_d1R;

end

endmodule

不改变流水线的级数,把加法器的输入信号改成8比特位宽,编译,波形仿真,和不带流水线的情况对比一下,与4比特位宽和不带流水线的波形无差别。

在8比特输入位宽的情况下,在输入上再添加一级流水线

module top(

  IN1   ,

  IN2   ,

  CLK   ,

  OUT   );

input  [7:0] IN1, IN2;

input CLK;

output  [12:0] OUT;

reg [7:0] in1_d1R, in2_d1R, in1_d2R, in2_d2R;

reg  [12:0] adder_out, OUT;

always@(posedge CLK) begin // 生成D触发器的always块

  in1_d1R <= IN1;

  in2_d1R <= IN2;

  in1_d2R <= in1_d1R;

  in2_d2R <= in2_d1R;

  OUT     <= adder_out;

end

always@(in1_d1R or in2_d1R) begin // 生成组合逻辑的always 块

  adder_out = in1_d2R + in2_d2R;

end

endmodule

对比发现,流水线的个数越多,毛刺越少,实验会逐次增加一个时钟周期。

8.乘法器

 

学生实验

  • 改变乘法器的输入位宽为8比特,编译,波形仿真,观察信号毛刺的时间长度。
  • 选一款没有硬件乘法器的FPGA芯片(例如Cyclone EP1C6)对比8比特的乘法器和加法器两者编译之后的资源开销(Logic Cell的数目)
  • 编写一个输入和输出都有D触发器的流水线乘法器代码,编译后波形仿真,观察组合逻辑延迟和毛刺的时间,和不带流水线的情况下对比。
  无符号4比特的乘法器  /

module top(

  IN1   ,

  IN2   ,

  OUT   );

 input [3:0] IN1, IN2;

 output [7:0] OUT;

 reg [7:0] OUT;

always@(IN1 or IN2) begin // 生成组合逻辑的always 块

  OUT = IN1 * IN2;

end

endmodule

  无符号8比特的乘法器  /

module top(

  IN1   ,

  IN2   ,

  OUT   );

 input [7:0] IN1, IN2;

 output [12:0] OUT;

 reg [12:0] OUT;

always@(IN1 or IN2) begin // 生成组合逻辑的always 块

  OUT = IN1 * IN2;

end

endmodule

观察可知,毛刺数量非常多。

2.换成没有硬件乘法器的芯片

///一个输入和输出都有D触发器的流水线乘法器代码///
module top(
  CLK   ,
  IN1   ,
  IN2   ,
  OUT   );
input [3:0] IN1, IN2;
input CLK;
output [7:0] OUT;
reg [3:0] in1, in2;
reg [7:0] D_out, OUT;
always @ (posedge CLK) begin
 in1 <= IN1;
 in2 <= IN2;
 OUT <= D_out;
end
always @ (in1 or in2) begin // 生成组合逻辑的always 块
 D_out = in1 * in2;
end
endmodule 

9.计数器

 

学生实验

请完成以下设计实验,编译电路并且进行波形仿真。

  • 设计一个最简单的计数器,只有一个CLK输入和一个OVerflow输出,当计数到最大值的时钟周期CLK输出1
  • 设计复杂的计数器,和本例相似,带有多种信号,其中同步清零CLR的优先级最高,使能EN次之,LOAD最低。
//最简单的计数器代码  //

module top(

  CLK   , // 时钟,上升沿有效

  CNTVAL,

  OV  );// 计数溢出信号,计数值为最大值时该信号为1

input CLK;

output [3:0] CNTVAL;

output OV;   

reg [3:0] CNTVAL, cnt_next;

reg OV;

// 电路编译参数,最大计数值

parameter CNT_MAX_VAL = 15;

always @ (posedge CLK ) begin

 CNTVAL <= CNTVAL + 1;

end

// 组合逻辑,生成OV

always @ (CNTVAL) begin

  if(CNTVAL == CNT_MAX_VAL)

    OV = 1;

  else

    OV = 0;

end

endmodule

 复杂计数器代码  /

//同步清零CLR的优先级最高,使能EN次之,LOAD最低

module top(

  RST   , // 异步复位, 高有效

  CLK   , // 时钟,上升沿有效

  EN    , // 输入的计数使能,高有效

  CLR   , // 输入的清零信号,高有效

  LOAD  , // 输入的数据加载使能信号,高有效

  DATA  , // 输入的加载数据信号

  CNTVAL, // 输出的计数值信号

  OV    );// 计数溢出信号,计数值为最大值时该信号为1

input RST   , CLK   , EN    , CLR   , LOAD  ;

input [3:0] DATA ;

output [3:0] CNTVAL;

output OV;   

reg [3:0] CNTVAL, cnt_next;

reg OV;

// 电路编译参数,最大计数值

parameter CNT_MAX_VAL = 9;

// 组合逻辑,生成cnt_next

//同步清零CLR的优先级最高,使能EN次之,LOAD最低

always @(EN or CLR or LOAD or DATA or CNTVAL) begin

  if(CLR) begin // 清零有效

      cnt_next = 0;

    end

    else begin //

     if(EN) begin    // 使能有效

      if(LOAD) begin // 加载有效

        cnt_next = DATA;

      end

      else begin     // 加载无效,正常计数

        // 使能有效,清零和加载都无效,根据当前计数值计算下一值

        if(CNTVAL < CNT_MAX_VAL) begin // 未计数到最大值, 下一值加1

          cnt_next = CNTVAL + 1'b1;

        end

        else begin // 计数到最大值,下一计数值为0

          cnt_next = 0;

        end

      end // else LOAD

     end // if EN

   else begin  // 使能无效,计数值保持不动

     cnt_next = CNTVAL;

   end // else EN

 end  // else CLR

end

// 时序逻辑 更新下一时钟周期的计数值

// CNTVAL 会被编译为D触发器

always @ (posedge CLK or posedge RST) begin

  if(RST)

    CNTVAL <= 0;

  else

    CNTVAL <= cnt_next;

end

// 组合逻辑,生成OV

always @ (CNTVAL) begin

  if(CNTVAL == CNT_MAX_VAL)

    OV = 1;

  else

    OV = 0;

end

endmodule

10.状态机

学生实验

设计一个用于识别2进制序列“1011”的状态机

  • 基本要求:
  • 电路每个时钟周期输入1比特数据,当捕获到1011的时钟周期,电路输出1,否则输出0
  • 使用序列101011010作为输出的测试序列
  • 扩展要求:
  • 给你的电路添加输入使能端口,只有输入使能EN为1的时钟周期,才从输入的数据端口向内部获取1比特序列数据。
  三段式状态机代码设计一个用于识别2进制序列“1011”的状态机  ///

module top(

  CLK       ,   // clock

  RST       ,   // reset

  EN        ,   // en

  CENT1IN   ,   // input 1 cent coin

  TINOUT    );  // output 1 tin cola

input  CLK       ;

input  RST       ;

input  EN,CENT1IN   ;

output TINOUT    ;

parameter ST_0_CENT = 0;

parameter ST_1_CENT = 1;

parameter ST_2_CENT = 2;

parameter ST_3_CENT = 3;

parameter ST_4_CENT = 4;

reg [4-2:0]stateR       ;

reg [4-2:0]next_state   ;

reg        TINOUT       ;

// calc next state

always @ (CENT1IN or stateR) begin

  if(EN) begin

  case (stateR)

    ST_0_CENT :begin if(CENT1IN==1) next_state = ST_1_CENT ; else next_state = ST_0_CENT; end

    ST_1_CENT :begin if(CENT1IN==0) next_state = ST_2_CENT ; else next_state = ST_0_CENT; end

    ST_2_CENT :begin if(CENT1IN==1) next_state = ST_3_CENT ; else next_state = ST_0_CENT; end

    ST_3_CENT :begin if(CENT1IN==1) next_state = ST_4_CENT ; else next_state = ST_0_CENT; end

    ST_4_CENT :begin next_state = ST_0_CENT; end

  endcase

  end

  else

  next_state = ST_0_CENT;

end

// calc output

always @ (stateR) begin

  if(stateR == ST_4_CENT)

    TINOUT = 1'b1;

  else

    TINOUT = 1'b0;

end

// state DFF

always @ (posedge CLK or posedge RST)begin

  if(RST)

    stateR <= ST_0_CENT;

  else

    stateR <= next_state;

end

endmodule

 

 

11.移位寄存器

学生实验

设计一个如本节“电路描述”部分的“带加载使能和移位使能的并入串出”的移位寄存器,电路的RTL结构图如“电路描述”部分的RTL结构图所示。

 “带加载使能和移位使能的并入串出”的移位寄存器 /

module top(

  RST   ,   // 异步复位, 高有效

  CLK   ,   // 时钟,上升沿有效

  EN    ,   // 输入数据串行移位使能

  LOAD  ,   // 输入数据带加载使能

  IN    ,   // 输入串行数据

  OUT   );  // 并行输出数据

input RST, CLK, EN, LOAD;

input [3:0]IN;

output[3:0] OUT;

reg [3:0] shift_R;

assign OUT[3:0] = shift_R[3:0];

// 时序逻辑 根据输入使能进行串行移位

// shift_R 会被编译为D触发器

always @ (posedge CLK or posedge RST or posedge LOAD) begin

  if(RST)

    shift_R[3:0] <= 0;

  else begin

    if(LOAD) begin

      shift_R[3:0] <= IN[3:0];

    end

    else begin

      if(EN) begin // 串行移位的使能有效

        shift_R[3:1] <= shift_R[2:0];

        shift_R[0]   <= 0;

      end

      else begin // 使能无效保持不动

        shift_R[3:0] <= shift_R[3:0];

      end

     end

   end

end // always

endmodule

最后

以上就是美好流沙为你收集整理的Verilog RTL代码新手上路教程1. 多路选择器2. 交叉开关3.优先编码器4. 多路译码器8.乘法器9.计数器10.状态机11.移位寄存器的全部内容,希望文章能够帮你解决Verilog RTL代码新手上路教程1. 多路选择器2. 交叉开关3.优先编码器4. 多路译码器8.乘法器9.计数器10.状态机11.移位寄存器所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部