【第一季】CH04_FPGA设计Verilog基础(一)Enter a post title
【第一季】CH04_FPGA设计Verilog基础(一)
4.1 Verilog HDL 代码规范
u 项目构架设计
项目的构架用于团队的沟通,以及项目设计的全局把控
u 接口时序设计规范
模块和模块之间的通过模块的接口实现关联,因此规范的时序设计,对于程序设计的过程,以及程序的维护,团队之间的沟通都是非常必要的。
u 命名规则
1、顶层文件
对象+功能+top
比如:video_oneline_top
2、逻辑控制文件
介于顶层和驱动层文件之间
对象+ctr
比如:ddr_ctr.v
3、驱动程序命名
对象+功能+dri
比如:lcd_dri.v、uart_rxd_dri.v
4、参数文件命名
对象+para
比如:lcd_para.v
5、模块接口命名:文件名+u
比如lcd_dir lcd_dir_u(........)
6、模块接口命名:特征名+文件名+u
比如 mcb_read c3_mcb_read_u
7、程序注释说明
//////////////////////////////////////////////////////////////////////////////////
// Company: milinker corperation
// Engineer:jinry tang
// WEB:www.milinker.com
// BBS:www.osrc.cn
// Create Date: 07:28:50 07/31/2015
// Design Name: FPGA STREAM
// Module Name: FPGA_USB
// Project Name: FPGA STREAM
// Target Devices: XC6SLX16-FTG256/XC6SLX25-FTG256 Mis603
// Tool versions: ISE14.7
// Description: CY7C68013A SLAVE FIFO comunication with fpga
// Revision: V1.0
// Additional Comments:
//1) _i input
//2) _o output
//3) _n activ low
//4) _dg debug signal
//5) _r delay or register
//6) _s state mechine
//////////////////////////////////////////////////////////////////////////////////
8、端口注释
input Video_vs_i,//输入场同步入
9、信号命名
命名总体规则:对象+功能(+极性)+特性
10、时钟信号
对象+功能+特性
比如:phy_txclk_i、sys_50mhz_i
11、复位信号
对象+功能+极性+特性
比如:phy_rst_n_i、sys_rst_n_i
12、延迟信号
对象+功能+特性1+特征2
比如:frame_sync_i_r0、frame_sync_i_r1
13、特定功能计数器
对象+cnt
比如:line_cnt、div_cnt0、div_cnt1
功能+cnt
比如:wr_cnt、rd_cnt
对象+功能+cnt
比如:fifo_wr_cnt、mcb_wr_cnt、mem_wr_cnt
对象+对象+cnt
比如:video_line_cnt、video_frame_cnt
14、一般计数器
cnt+序号
用于不容易混淆的计数
比如:cnt0、cnt1、cnt2
15、 时序同步信号
对象+功能+特性
比如:line_sync_i、frame_sysc_i
16、 使能信号
功能+en
比如:wr_en、rd_en
对象+功能+en
比如:fifo_wr_en、mcb_wr_en
4.2技术背景
大规模集成电路设计制造技术和数字信号处理技术,近三十年来,各自得到了迅速的发展。这两个表面上看来没有什么关系的技术领域实质上是紧密相关的。因为数字信号处理系统往往要进行一些复杂的数学运算和数据的处理,并且又有实时响应的要求,它们通常是由
高速专用数字逻辑系统或专用数字信号处理器所构成,电路是相当复杂的。因此只有在高速大规模集成电路设计制造技术进步的基础上,才有可能实现真正有意义的实时数字信号处理系统。对实时数字信号处理系统的要求不断提高,也推动了高速大规模集成电路设计制造技
术的进步。现代专用集成电路的设计是借助于电子电路设计自动化(EDA)工具完成的。学习和掌握硬件描述语言(HDL)是使用电子电路设计自动化(EDA)工具的基础。
笔者建议Verilog,虽然很多学校古董级的老师还在教VHDL.当然VHDL也是要了解的,因为这门古老的语言的历史遗留问题,现在还有很多VHDL的模块,有的时候我们要拿来主义,所以还有必要了解下的。但是历史的车轮总是在前进,优胜劣汰。也许不久的将来Verilog也会被C,C++这种高级语言代替。
为了更方面地切入主题,笔者假设,你已经学过单片机,并且掌握C语言。因为单片机,和C语言,可以说是当代大学生的一项基本能力。有了这个基础,再学习其他现代计算机编程,算法,才能达到事半功倍的效果。如果你还不会单片机和C语言,建议你首先学会单片机,或者C语言。当然,这只是笔者的建议,不会单片机,或者C语言,并不代表学不好Verilog语言。
学过单片机的都知道,我们的程序代码是一条指令一条指令来执行的。CPU首先通过总线,读取一条指令,然后解析这条指令,再然后执行这条指令。我们写的C代码总是一条一条地执行。如果我们同时要处理10个子程序,那么CPU必须一个个子程序来执行。如果有些实时性较高的,如扫描下矩阵键盘,VGA刷个屏,都需要中断来实现。如果刷屏时间比较长,就会影响到你按键的灵敏度。另外比如,我们的单片机在用串口接收数据,并且也要发送数据,同时我们的单片机要处理外部的IO信号,如果我们的IO信号非常快,并且有几百个信号,可能同一个时刻触发,很显然,如果这些信号比较快,那么我们的单片机,就没法实现了。
这是笔者简单举了两种情况,那么如果使用FPGA就可以很方便地解决以上问题。由于FPGA的并行性,不管是扫描键盘,还是扫描VGA,都可以把它们做成独立的模块,时间上没有冲突,每个模块可以同时执行。
再比如用一个FPGA,就可以同时完成串口的收发,以及IO的监控,因为FPGA的程序实际上就是电路,是瞬间就完成了,我们只要用Verilog写出来相应功能的程序模块,这些模块是同时运行的。
这样看来FPGA真是太强大了,太完美了。但不要高兴地太早,由于FPGA可以在一个时钟内,完成多条语句的赋值,但是如果赋值必须有个前后顺序呢?也就是需要一步步的完成,怎么办?如果说并行控制是FPGA的优点,那么顺序控制就是他的不足之处。世界上永远没有完美的东西,我们在获得一种优势的时候,往往也获得了一种劣势。但是,办法总比问题多。
n 顺序控制的第一种办法——状态机设计
可以说,我们用Verilog来写程序,状态机无处不在。顾名思义,通过设计状态机,我们可可以控制Verilog让他该快的时候快,该慢的时候慢,该做什么的时候就做什么。这才是我们想要的。状态机是很不错的东西,初学者对他望而生畏,而熟悉Verilog语言的人都对其会爱不释手。
FPGA也可以运行CPU?是的,没错,FPGA也可以像单片机一样使用,这样我们就可以用C代码来一条条指令来执行了,这不是太强大了?是的,没错。关键的问题是,我们是可以把一些逻辑控制顺序复杂的事情用C代码来实现,而实时处理的部分仍然用Verilog来实现。并且那部分Verilog可以被C代码控制。Xilinx FPGA目前支持的CPU有Microblaze,ARM9,POWERPC,CortexA9(zynq就Xilinx比较新的一款片子,完美的将CortexA9和FPGA整合到一起,有兴趣的可以淘宝搜索MiZ702)其中Microblaze是一款软CPU,是软核。ARM9,CortexA9和POWERPC是硬核。这里有两个概念:
1)软核就是用代码就是能现的CPU核,这种核配置灵活,成本较低。但是要占用FPGA宝贵的资源。
2)硬核就是一块电路,做到FPGA内部,方便使用,性能更高。比如Xilinx的DDR内存控制器,就是一种硬核,其运行速度非常高,我们只要做些配置,就可以方便使用。
两种核可谓各有所长。
根据具体看情况而定,从我们上面的一些介绍,笔者相信你已经有一定的判断能力了。笔者的建议是,低速场合,实时性要求的低的地方用ASIC,有些功能用ASIC方便的用ASIC,成本低的用ASIC。排除那些可以不用FPGA地方,那么剩余的就要考虑是不是用FPGA来实现更加方便。一般来说,FPGA程序开发相对来说要难度大一些,并且成本要高一些。
讲了这么多的背景知识,我们来看一小段代码:
u32sum(a,b) { a=a+1; b=b+1; c=a+b; return c; } always@(posedge clk) begin a = a + 1; b = b + 1; c = a + b; end |
同样是实现了求和,但是,C代码需要N多个(很多)CPU周期才得出结果,而用Verilog一个clk周期就计算出来了。
或许现在你还不知道为什么。没关系,下面的内存笔者讲解Verilog语言基础。
4.3Verilog最最基础语法
Verilog和C在外形上有很大相识的地方,有了C基础背景,Verilog看起来就并不陌生。
C语言和Verilog的关键词和结构对比:
C语言和Verilog运算符对比:
真是太振奋人心了,一切都是这么熟悉。学好FPGA已经没有心理障碍了。
4.4关键字
信号部分:
input关键词,模块的输入信号,比如input Clk,Clk是外面关键输入的时钟信号;
output关键词,模块的输出信号,比如output[3:0]Led; 这个地方正好是一组输出信号。其中[3:0]表示0~3共4路信号。
inout模块输入输出双向信号。这种类型,我们的例子24LC02中有使用。数总线的通信中,这种信号被广泛应用;
wire关键词,线信号。例如:wire C1_Clk; 其中C1_Clk就是wire类型的信号;
线信号,三态类型,我们一般常用的线信号类型有input,output,inout,wire;
reg关键词,寄存器。和线信号不同,它可以在always中被赋值,经常用于时序逻辑中。比如reg[3:0]Led;表示了一组寄存器。
结构部分:
module() … endmodule |
代表一个模块,我们的代码写在这个两个关键字中间
always@()括号里面是敏感信号。这里的always@(posedge Clk)敏感信号是posedge Clk含义是在上升沿的时候有效,敏感信号还可以negedge Clk含义是下降沿的时候有效,这种形式一般时序逻辑都会用到。还可以是*这个一符号,如果是一个*则表示一直是敏感的,一般用于组合逻辑。
assign用来给output,inout以及wire这些类型进行连线。assign相当于一条连线,将表达式右边的电路直接通过wire(线)连接到左边,左边信号必须是wire型(output和inout属于wire型)。当右边变化了左边立马变化,方便用来描述简单的组合逻辑。示例:
wire a, b, y; assign y = a & b;、 |
这些语句含义上都和高级语言一样:
if(...)begin ............ End if(...)begin ............ end else begin ............ End if(...)begin ............ end else if(...)begin ............ end case(...) ............ endcase begin..... end作用域范围,类似于C的大括号。用法举例: always@(posedge clk)begin ............ end |
符号部分:(我们这里FALSH为0,TRUE为1)
“;”分号用于每一句代码的结束,以表示结束,和C语言一样。
“:”冒号,用在数组,和条件运算符以及case语句结构中。case结构会在后面讲解。
“<=”赋值符号,非阻塞赋值,在一个always模块中,所有语句一起更新。它也可以表示小于等于,具体是什么含义编译环境根据当前编程环境判断,如果“<=”是用在一个if判断里如:if(a <= 10);当然就表示小于等于了。
“=”阻塞赋值,或者给信号赋值,如果在always模块中,这条语句被立刻执行。阻塞赋值和非阻塞赋值将再后面详细举例说明。
“+,-,*,/,% ”是加、减、乘、除运算符号,这些使用和C语言基本是一样的,当你用到这些符号时,编译后会自动生成或者消耗FPGA原有的加法器或是乘法器等。其中符号/,%会消耗大量的逻辑,谨慎使用。
“<”小于,比如A<B含义就是A和B比较,如果A小于B就是TURE,否则为FALSE。
“<=”小于等于,比如A<=B含义就是A和B比较,如果A小于等于B就是TURE,否则为FALSE。
“>”大于,比如A>B含义就是A和B比较,如果A大于B就是TURE,否则为FALSE。
“>=”大于等于,比如A>=B含义就是A和B比较,如果大于等于B就是TURE,否则为FALSE。
“==”等于等于,比如A==B含义就是A和B比较,如果A等于B就是TURE,否则为FALSE。
“!=”不等于,A!=B含义是A和B比较,如果A不等于B就是TURE,否则为FALSE.
“>>”右移运算符,比如A>>2表示把A右移2位。
“<<”左移运算符,比如A<<2表示把A左移2位。
“~”按位取反运算符,比如A=8’b1111_0000;则~A的值为8’b0000_1111;
“&”按位于与,比如A=8’b1111_0000;B=8’b1010_1111;则A&B结果为8’b1010_0000;
“^”异或运算符,比如A=8’b1111_0000;B=8’b1010_1111;则A^B结果为8’b0101_1111;
“&&”逻辑与,比如A==1,B==2;则A&&B结果为TRUE;如果A==1,B==0,则A&&B结果为FALSE,一般用于条件判断。
A = B ? C : D是一个条件运算符,含义是如果B为TRUE则把C连线A,否则把D连线A。B通常是个条件判断,用小括弧括起:
assign C1_Clk = (C1==25'd24999999) ? 1 : 0 ;
C1_Clk,是一个wire类型的信号,当C1==25'd24999999时候,连线到1,否则连线到0.
“{}”在Verilog中表示拼接符,{a,b}这个的含义是将括号内的数按位并在一起,比如:{1001,1110}表示的是10011110。拼接是Verilog相对于其他语言的一大优势,在以后的编程中请慢慢体会。
参数部分:
parameter定义一个符号a为常数(十进制180找个常量的定义等效方式):
parameter a = 180;//十进制,默认分配长度32bit(编译器默认) parameter a = 8’d180;//十进制 parameter a = 8’hB4; //十六进制 parameter a = 8’b1011_0100; //二进制 |
预处理命令
//-------------------------------- `include file1.v //-------------------------------- `define X = 1; //-------------------------------- `deine Y; `ifdef Y Z=1; `else Z=0; `endif //-------------------------------- |
有的时候我们一些公共的宏参数,我们可以放在一个文件中,比如这个文件名字为xx.v那么我们可以`include xx.v就可以包含找个文件中定义的一些宏参数。我还是来详细说明下吧!
话说Verilog 的`include和C语言的include用法是一样一样的,要说区别可能就在于那个点吧。
include一般就是包含一个文件,对于Verilog这个文件里的内容无非是一些参数定义,所以这里再提几个关键字:`ifdef `define `endif(他们都带个点,呵呵)。
他们联合起来使用,确实能让你的程序多样化,就拿VGA程序说事吧。
首先,你可以新建一个.v文件(可以直接新建一个TXT,让后将后缀换成.v)其实这个后缀没所谓,.v也是可以的,我觉得,写成.v更能体现出这个文件的意义。
假设有个lcd_para.v文件,内容如下:
// 640 * 480 //--------------------------------- `define H_Start (`H_SYNC + `H_BACK) `define V_Start (`V_SYNC + `V_BACK) |
这里为VGA定义了两种分辨率,通过`define VGA_800_600_60MHz或 VGA_640_480_60FPS_25MHz 或`define VGA_800_600_72FPS_50MHz来决定使用哪种分辨率。
比如,我的xxx.v文件想调用lcd_para.h,那么xxx.v我可以写到:
`define VGA_800_600_60MHz //这句要放在"lcd_para.h"的上面,不然编译不通过 `include "lcd_para.h" |
那么xxx.v文件中就可以用lcd_para.v中的参数了,且对应是VGA_800_600_60MHz下的参数。
其次`include "lcd_para.v" 这个路径也有一点讲究,xxx.v作为引用lcd_para.v的文件它和lcd_para.v在同一文件夹下才能怎么写,就是相对路径一说了。也就是以xxx.v为当前路径去引索lcd_para.v文件的位子。所以如果他们不再一个文件夹那么请写出更详细(正确)的路径。顺便说一句,lcd_para.v添不添加到工程是无所谓的,只要路径
对了即可,当然我还是建议添加到工程,且和.v文件放在同一文件夹下,以方便观察和管理。
4.5Verilog中数值表示的方式
如果我们要表示一个十进制是180的数值,在Verilog中的表示方法如下:
二进制:8’b1010_1010; //其中“_”是为了容易观察位数,可有可无。
十进制:8’d170;
16进制:8’hAA;
4.6阻塞赋值和非阻塞赋值详解
说到阻塞赋值和非阻塞赋值,是很多初学者很迷惑的地方。原因是C语言没有可以类比的东西。
学习FPGA和单片机最大的区别在于,学FPGA时,你必须时刻都有着时钟的概念。不像单片机时钟相关性比较差,FPGA你必须却把握每一个时钟。
首先来说说非阻塞赋值,这个在时序逻辑中随处可见:
reg A; reg B; always @(posedge clk) begin A <= 1'b1; B <= 1'b1; /***或者** B <= 1'b1; A <= 1'b1; *********/ end |
这段程序里,A和B是同时被赋值的,具体是说在时钟的上升沿来的时刻,A和B同时被置1。调换A和B的上下顺序,将得到相同的结果。
接着看另外一段程序:
reg A; reg B; always @(posedge clk) begin A <= 1'b1; end always @(posedge clk) begin B <= 1'b1; end |
这段程序,与第一段程序也是完全等价的,A和B在同一时刻被赋值。两段程序综合出的逻辑也是完全相同的。这就是非阻塞赋值的特点,体现了FPGA的并行性!
接着来看阻塞赋值,它少了一个非,表示会阻塞住,那么体会下这个阻塞:
always @(posedge clk) begin A = 1'b1; B = 1'b1; end |
看到,上面这个程序是阻塞和非阻塞的混合使用,一般教材是极力反对这种写法的。其实只要你理解了,有的时候这种用法还能帮上大忙。只不过,不理解的话乱用会导致时序违规。
回到正题,我们这么写是为了更好的理解阻塞赋值:当时钟上升沿来临的时刻,首先A会被置1,然后B寄存器再置1。区别就是A和B不再同时置1。A要比B提前零点几纳秒。这样就出现了先后顺序。这个过程还是在一个时钟内完成的,但是数据到达B寄存器相比上面两段程序晚了那么零点几纳秒!
当我们的时钟跑的比较慢的时候,比如50M,一个周期有20ns,那么这么短暂的延时基本可以忽略不计,但是随着设计的复杂,以及时钟速度的提高,这样的语句就要小心。
假设,我们要计算AB求和再除以2的结果。先用非阻塞方法去实现,由于AB求和再除以2是两个步骤,而非阻塞所以的事情都在一个时钟完成,所以这里我们用状态机,将两个步骤分配到两个时钟里去完成:
( input clk_i, input rst_n_i, output reg [4:0]result_o ); reg [3:0]A; reg [3:0]B; reg [4:0]C; reg i; always @(posedge clk_i ) if(!rst_n_i) begin #2 A <= 4'd4; B <= 4'd12; C <= 5'd0; result_o = 5'd0; end else begin #2 C <= A + B; result_o <= (C >> 1); end endmodule |
第一个时钟上升沿来临时,完成C <= A + B;
第二个时钟来临时完成result <= (C >> 1);
求出结果,这个过程耗费两个时钟。(不考虑复位消耗的时钟)
再来,用添加阻塞的方式实现:
input clk_i, input rst_n_i, output reg [4:0]result_o ); reg [3:0]A; reg [3:0]B; reg [4:0]C; always @(posedge clk_i) if(!rst_n_i) begin #2 A = 4'd4; #0.2 B = 4'd12; #0.2 C = 5'd0; #0.2 result_o = 5'd0; end else begin #2 C = A + B; #0.2 result_o = (C >> 1); end endmodule |
仿真结果:
先通过阻塞的方法提前得到C的值,再将C右移1位,达到除以2的效果。整个过程耗时一个时钟。
以上的程序并没有什么实际的参考价值,但是解释清楚阻塞和非阻塞赋值,它已经做到了~~
讲到这里,笔者以最快的速度,最简单的方式,让读者学习了Verilog语言的语法部分。具备这些基础知识,下面笔者将带你通过代码来学习Veriog语言。最后,笔者提一点建议,学习Verilog多看别人写的优秀的代码,多看官方提供的代码和文档。其中官方提供的代码,很多时候代表了最新的用法,或者推荐的用法。读者学习,首先把最最基础的掌握好,这样,在项目中遇到了问题,也能快速学习,快速解决。
对于理论知识的学习,没必要一开始就研究得那么深刻,只是搞理论学习,对于学习Verilog语言,或者FPGA开发是不实际的,要联系理论和实践结合。多仿真,多验证,多问题,多学习,多改进。
【第一季】CH04_FPGA设计Verilog基础(一)Enter a post title的更多相关文章
- 【第一季】CH05_FPGA设计Verilog基础(二)Enter a post title
[第一季]CH05_FPGA设计Verilog基础(二) 5.1状态机设计 状态机是许多数字系统的核心部件,是一类重要的时序逻辑电路.通常包括三个部分:一是下一个状态的逻辑电路,二是存储状态机当前状态 ...
- 【第一季】CH06_FPGA设计Verilog基础(三)
[第一季]CH06_FPGA设计Verilog基础(三) 一个完整的设计,除了好的功能描述代码,对于程序的仿真验证是必不可少的.学会如何去验证自己所写的程序,即如何调试自己的程序是一件非常重要的事情. ...
- Hadoop 2.x从零基础到挑战百万年薪第一季
鉴于目前大数据Hadoop 2.x被企业广泛使用,在实际的企业项目中需要更加深入的灵活运用,并且Hadoop 2.x是大数据平台处理 的框架的基石,尤其在海量数据的存储HDFS.分布式资源管理和任务调 ...
- 【第一季】CH09_FPGA多路分频器设计
[第一季]CH09_FPGA多路分频器设计 在第七节的学习中,笔者带大家通过一个入门必学的流水灯实验实现,快速掌握了VIVADO基于FPGA开发板的基本流程.考虑到很多初学者并没有掌握好Vivado ...
- QQ聊天界面的布局和设计(IOS篇)-第一季
我写的源文件整个工程会再第二季中发上来~,存在百度网盘, 感兴趣的童鞋, 可以关注我的博客更新,到时自己去下载~.喵~~~ QQChat Layout - 第一季 一.准备工作 1.将假数据messa ...
- 【第一季】CH08_FPGA_Button 按钮去抖动实验
[第一季]CH08_FPGA_Button 按钮去抖动实验 按键的消抖,是指按键在闭合或松开的瞬间伴随着一连串的抖动,这样的抖动将直接影响设计系统的稳定性,降低响应灵敏度.因此,必须对抖动进行处理,即 ...
- 小课堂week16 编程范式巡礼第一季 三大基石
编程范式巡礼第一季 三大基石 最近迷上了一些哲史类书籍,回望过去.放眼未来,往往沉浸在其思维之美中无法自拔.计算机编程是一门非常年轻的学科,沉淀不足也是年轻的一个侧面,在编程领域,有足够思想深度的作品 ...
- JAVA入门第一季(mooc-笔记)
笔记相关信息 /** * @subject <学习与创业>作业1 * @author 信管1142班 201411671210 赖俊杰 * @className <JAVA入门第一季 ...
- 豪斯医生第一季/全集House M.D 1迅雷下载
豪斯医生 第一季 House M.D. Season 1 (2004)本季看点:态度无礼,表情凶恶,跛足拄着一根藤棍,永远是牛仔裤运动鞋的便装打扮而不是整洁的白大褂,普林斯顿大学附属医院的格雷戈·豪斯 ...
随机推荐
- Oracle 11g win32位 window7下安装教程
1.首先是去http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html官网下载oracle11 ...
- insmod mknod
insmod module 會在 /proc/devices/ 下產生 major number 及 device name ---------------------------- mknod 會使 ...
- python核心模块方法
********************os模块: os.remove() 删除文件 os.unlink() 删除文件 os.rename() 重命名文件 os.listdir() 列出指定目录下所有 ...
- mysql多实例搭建
一)多实例安装 [root@mysqlmaster01 ~]# mkdir /data/mysql_data2[root@mysqlmaster01 ~]# mkdir /data/mysql_dat ...
- scikit-learn机器学习(一)简单线性回归
# -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt ## 设置字符集,防止中文乱码 import ma ...
- cached占比过高
Linux手动释放缓存的方法Linux释放内存的命令:syncecho 1 > /proc/sys/vm/drop_caches drop_caches的值可以是0-3之间的数字,代表不同的含义 ...
- Spring Boot中报错org.apache.ibatis.binding.BindingException: Parameter 'XXXX' not found. Available parameters are [0, 1, param1, param2]的解决办法
我这里的报错信息显示: org.apache.ibatis.binding.BindingException: Parameter 'reqUsername' not found. Available ...
- CentOS 7下Cloudera Manager及CDH 6.0.1安装过程详解
目录 一.概念介绍 1.CDH 概览 2.Cloudera Manager 概览 二.环境准备 1.软件版本选择 2.节点准备(四个节点) 3.配置主机名和hosts解析(所有节点) 4.关闭防火墙 ...
- Sprint Retrospective - 回顾的重要性
在Scrum中,每个Sprint结束的时候会有两个会议(Sprint Review/Demo和Sprint Retrospective回顾).这两个会议是对过去的一个Sprint的一个总结,其中Rev ...
- 容器时代的持续交付工具---Drone:Drone使用
上一篇文章里已经介绍了如何安装Drone,下面我们来看下如何使用.还是基于gogs作为git仓储. 首先打开server对应的地址,进入登录页面,输入在启动server时配置的管理员账号(对应的就是g ...