2. 定义时钟

2.1 关于时钟

为了获得最佳精度路径覆盖信息,必须正确定义时钟。

  • 时钟要定义在时钟树的根 pin 或 port 上,称为 source point。
  • 时钟的边缘应该由周期和波形进行组合描述。
  • 周期使用纳秒做为单位进行定义。它对应于波形重复的时间。
  • 波形是一系列的上升沿和下降沿绝对时间列表,单位为纳秒,并且所有时间在一个时钟周期内。列表必须包含偶数个值。第一个值始终对应于第一个上升边缘。如果没有指定波形,波形的默认占空比为 50%,相移为 0。

2.1.1 传播时钟

周期和波形属性只展现出了时钟的理想特性。当时钟进入 FPGA 并通过时钟树传播时,时钟边沿被延缓,并受噪声和硬件行为引影响。这些特性称为时钟网络延迟和时钟不确定性。时钟的不确定性包括:

  • 时钟抖动(clock jitter)
  • 相位错误
  • 用户指定添加的不确定性

默认情况下,Vivado 在做时序分析时,始终将时钟视为传播时钟,即非理想时钟,以此提供准确的余量值,其中包括时钟树插入延迟和不确定性。

2.1.2 专用硬件资源

FPGA 有大量专用的时钟管脚,这个管脚可以专门用来做时钟的输入。FPGA 内部包含有 MMCM、PLL 和 BUR 之类的时钟资源。

2.2 基准时钟(Primary Clock)

基准时钟是通过 FPGA 输入端口或千兆收发器输出引脚(例如,恢复时钟)进入设计的时钟。基准时钟只能通过 create_clock 指令进行定义。(为什么是千兆收发器?下面的话应该可以解释,7 系列的 GT 恢复时钟不能自动推导,必须手动定义。而 US 和 USP 系列的可以自动推导,不需要人为定义)

Primary clocks must be defined on a gigabit transceiver output only for Xilinx 7 series FPGAs. For UltraScale and UltraScale+ devices, the timer automatically derives clocks on the GT output ports.

基准时钟必须附加到网表对象。该网表对象代表设计中的所有时钟边沿起点,并且是时钟树上向下游传播的起点。换句话说,基准时钟的源点定义了零时间点,这个点被 Vivado 用来计算余量方程时,作为时钟延迟和不确定性的零起点。Vivado 会忽略来自定义基准时钟点上游单元的所有时钟树延迟。如果基准时钟错误的定义在了路径中间的引脚上,则只有部分延迟用于时序分析。

这可能会引起问题,因为时钟之间的偏斜和余量值会变得不准确。

2.2.1 基准时钟示例

# 周期 10ns, 来源于外部,通过 sysclk 端口输入,占空比 50%,相位为 0。
create_clock -period 10 [get_ports sysclk] # 周期 10ns, 来源于外部,通过 ClkIn 端口输入,占空比 25%,相位为 90。
create_clock -name devclk -period 10 -waveform {2.5 5} [get_ports ClkIn]

# GT 的恢复时钟无法自动推导时,需要手动约束。Vivado 在计算余量时,会从RXOUTCLK开始。
create_clock -name rxclk -period 3.33 [get_pins gt0/RXOUTCLK]

# 对于差分时钟,时钟必须定义在 P 端上,N 端上不能有定义。如果 P 和 N 各自定义一次,会导致软件认为是异步路径。
create_clock -name sysclk -period 3.33 [get_ports SYS_CLK_clk_p]

2.3 虚拟时钟(Virtual Clocks)

虚拟时钟是一种没有物理连接到设计中任何网表元素的时钟。虚拟时钟是通过 create_clock 指令定义的,但无需指定源对象。虚拟时钟通常用于指定输入和输出延迟约束:

# 创建时钟,但不指定时钟源
create_clock -name clk_virt -period 10

2.4 衍生时钟(Generated Clocks)

2.4.1 关于衍生时钟

衍生时钟产生于 FPGA 设计内部,通常由 MMCM 或用户逻辑产生。衍生时钟有一个关联的主时钟(master clock),指令 create_generated_clock 需要指定一个主时钟,它可以是基准时钟或者是另一个衍生时钟。衍生时钟属性直接源自其主时钟,定义衍生时钟时,不是指定它们的周期或波形,而是描述如何转换主时钟到衍生时钟。衍生时钟和主时钟之间的关系可以是以下任何一种:

  • 简单的分频
  • 简单的倍频
  • 分频和倍频的组合,用来得到一个非整数比的分频。
  • 移相或反相
  • 改变占空比
  • 所有上面的组合

为了计算衍生时钟的延迟,工具会跟踪衍生时钟的源引脚和主时钟的源引脚之间的时序路径和组合路径。在某些情况下,可能需要仅跟踪组合路径以计算生成的时钟延迟。可以使用 -combinational 行选项执行此操作。

2.4.2 用户自定义的衍生时钟

2.4.2.1 示例1:简单的2分频

create_clock -name clkin -period 10 [get_ports clkin]

# Option 1: master clock source is the primary clock source point
create_generated_clock -name clkdiv2 -source [get_ports clkin] -divide_by 2 [get_pins REGA/Q] # Option 2: master clock source is the REGA clock pin
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -divide_by 2 [get_pins REGA/Q]

2.4.2.2 示例2:使用 -edge 选项进行2分频

可以不使用 -divide_by 选项,而是使用 -edges 选项直接基于主时钟边沿描述衍生时钟波形。该参数是一组主时钟边沿的序号,用来标记衍生时钟的跳变沿的位置。从衍生时钟的上升沿开始描述。

# waveform specified with -edges instead of -divide_by
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -edges {1 3 5} [get_pins REGA/Q]

2.4.2.3 示例3:使用 -edge 和 -edge_shift 选项改变占空比和相位

当需要做移相时,可以使用 -edge_shift 选项。衍生时钟的每个边沿都可以单独的进行正向或负向移相。-edge_shift 选项 不能和以下选项同时使用:

  • -divide_by
  • -multiply_by
  • -invert

假设主时钟 clkin 的周期为 10 ns,占空比为 50% 。clkin 输入到 mmcm0 后,衍生出一个时钟,其占空比为 25%,移相 90 度。衍生时钟定义基于主时钟的第 1、2 和 3 边沿。这些边沿跳变分别发生在 0ns、5ns 和 10ns 上。要获得所需的波形,将第一和第三边沿移动 2.5ns。

create_clock -name clkin -period 10 [get_ports clkin]
# First rising edge: 0ns + 2.5ns = 2.5ns
# Falling edge: 5ns + 0ns = 5ns
# Second rising edge: 10ns + 2.5ns = 12.5ns
create_generated_clock -name clkshift -source [get_pins mmcm0/CLKIN] -edges {1 2 3} \
-edge_shift {2.5 0 2.5} [get_pins mmcm0/CLKOUT]

注意: -edge_shift 的值可以为正数,也可以为负数。

2.4.2.4 示例4:同时使用 -divide_by 和 -multiply_by

Vivado 允许同时指定 -divide_by-multiply_by,这是对 SDC 的扩展。虽然这对于手动定义 MMCM 或 PLL 生成的时钟特别方便,但是 Xilinx 建议让软件自动创建这些约束。如果手动定义了约束,必须确认约束的设置和锁相环本身的配置是相匹配的。

# 假设 MMCM 生成的时钟频率为原主时钟的 4/3。
create_generated_clock -name clk43 -source [get_pins mmcm0/CLKIN] -multiply_by 4 \
-divide_by 3 [get_pins mmcm0/CLKOUT]

2.4.2.5 示例5:追踪主时钟的组合逻辑路径

在此示例中,假设主时钟同时驱动基于寄存器的时2分频器和时钟多路复用器,时钟多路复用器可从选择主时钟或2分频时钟。在此方案中,从主时钟到生成的时钟有两条路径,即时序逻辑路径和组合逻辑路径。我们希望在多路复用器输出上创建一个衍生时钟,该输出反映了从主时钟到多路复用器的组合路径的延迟。这可以通过使用 -combinational 选项完成的:

create_generated_clock -name clkout -source [get_pins mmcm0/CLKIN] -combinational [get_pins MUX/O]

2.4.2.6 示例6:由 ODDR 驱动的转发时钟

在此示例中,由 ODDR 单元驱动的输出端口上创建转发时钟。转发时钟参考驱动 ODDR/CLKDIV 引脚的主时钟,并且与主时钟(-divide_by 1) 具有相同的周期。

create_generated_clock -name ck_vsf_clk_2 -source [get_pins ODDRE1_vsfclk2_inst/CLKDIV] -divide_by 1 [get_ports vsf_clk_2]

2.4.3 自动推导出的衍生时钟

自动推导的时钟也称为自动生成时钟。Vivado 会自动在 CMB( Clock Modifying Blocks)的输出引脚上创建这些约束,前提是相关的主时钟已经定义。

  • Xilinx 7 系列的 CMB 可以是:

    • MMCM*/ PLL*
    • BUFR
    • PHASER*
  • Xilinx UltraScale 系列的 CMB 可以是:
  • MMCM* / PLL*
  • BUFG_GT / BUFGCE_DIV
  • GT* _COMMON / GT*_CHANNEL / IBUFDS_GTE3
  • BITSLICE_CONTROL / RX*_BITSLICE
  • ISERDESE3

如果用户定义的时钟(主时钟或衍生时钟)也在同一网列表对象(即在同一定义点(pin 或 net)上定义,Vivado 则不会自动创建衍生时钟。

2.4.3.1 自动衍生时钟示例

以下自动衍生时钟示例是由 MMCM 生成的时钟。 主时钟 clkin 驱动 MMCME2 实例 clkip/mmcm0 的输入 CLKIN。自动生成的时钟的名称是 cpuClk,其定义点是 clkip/mmcm0/CLKOUT。

使用 get_clocks -of_objects <pin/port/net> 命令在不知道其名称的情况下查询自动生成的时钟。这使的约束或脚本相对通用,不用关心时钟名称是否有改动。

2.4.3.2 本地网名

如果 CMB 实例位于设计层次结构内,则生成的时钟名称将使用本地网名(即没有父单元名的名称)。例如,对于名称为 clkip/cpuClk 的层次网线:

  • 父单元名称为 clkip 。
  • 生成的时钟名称为 cpuClk。

2.4.3.3 名称冲突

如果两个自动生成的时钟之间的名称有冲突,Vivado 会添加独有的后缀来区分它们,例如:

  • usrclk
  • usrclk_1
  • usrclk_2

强制修改衍生时钟的名称:

  • 在 RTL 中选择独特且相关的网名。
  • 使用 create_generated_clock 强制使用指定的名称。

2.4.4 重命名自动衍生时钟

可以对工具自动创建的衍生时钟进行重命名。重命名通过使用 create_generated_clock 指令和有限的参数完成。

create_generated_clock -name new_name [-source master_pin] [-master_clock master_clk] source_object

必须指定的参数有新生成的时钟名称和生成时钟的源对象。生成时钟的源对象是创建衍生时钟的对象(CMB 的输出引脚、UltraScale GT 的输出引脚等)。只有当多个时钟通过源引脚传播时,才能使用源和主参数,以消除任何模糊性。当有多个时钟通过源对象传播时,必须指定 -source-master 参数,以消除任何不明确的地方。

注意:如果有 -edges / -edge_shift / -divide_by / -multiply_by / -combinational / -duty_cycle / -invert 选项传递到create_generated_clock 指令,则自动生成衍生时钟不会被重命名,相反会重新定义一个新的衍生时钟。

注意:使用 OOC 模式的模块在综合时,模块被当做黑盒,模块内部引脚和时钟名称不可访问。在这种情况下,用于综合的顶层 XDC 约束不能指定时钟名称或重命名模块内生成的自动衍生时钟。可以使用一些查询指令引用相关目标,如 get_clocks -of_objects [get_pins <OOC_MODULE_OUTPUT_CLOCK_PORT>]。用于实现的 XDC 约束没有此限制。

重命名的限制:

  • 自动衍生时钟只能在其源引脚上重命名,例如在 CMB(PLL、MMCM. .. ) 的输出处。自动衍生时钟不能在 BUFG 的输出上重命名,即便时钟是通过它传播的。
  • 无法重命名基准时钟或用户定义衍生时钟。只有自动衍生时钟才能使用此机制进行重命名。
  • source_object 必须匹配创建自动衍生时钟的对象。
  • 如果工具无法重命名衍生时钟,则会返回错误。重命名完成时,主时钟也必须存在。
  • 自动衍生时钟可以在 XDC 内的任何时间重命名,即使已被某些时序约束引用。

2.5 时钟组(Clock Groups)

2.5.1 关于时钟组

默认情况下,Vivado 会对设计中所有时钟之间的路径进行时序收敛,除非使用了时钟组或伪路径进行约束。set_clock_groups 指令会让 Vivado 不对时钟组之间的路径进行时序分析,而同一组内的时钟之间的仍会进行时序收敛。与 set_false_path 约束不同,两个时钟之间的两个方向的路径都会被忽略。

可以多次使用 -group 选项指定多个时钟组。如果组中的时钟在设计中都不存在,则组将变为空。set_clock_groups 约束至少需要两组,并且都不为空组时才有效。如果只有一个组有效,其他组都为空时,set_clock_groups 约束不会生效,并返回错误消息。

使用原理图查看器(Schematic Viewer)或时钟网络报告(Clock Networks Report)查看可视化时钟树的拓扑,确定哪些时钟不能一起进行收敛。您还可以使用时钟交互报告来(Clock Interactions Report)查看两个时钟之间的现有约束,并确定它们是有相同的主时钟(即它们具有已知的相位关系),或者判断出周期没有公倍数的时钟(Unexpandable)。

谨慎!忽略两个时钟之间的时序分析并不意味着它们之间的路径将在硬件上能正常工作。为了防止亚稳态,必须确认这些路径是否具有适当的同步电路或异步数据传输协议。

2.5.2 时钟分类

  • 同步时钟

    当两个时钟的相对相位关系是已知的,它们就是是同步时钟。通常它们的时钟树源头来自网列表中的同一根,它们的周期有公倍数。例如,衍生时钟和他的主时钟的周期比率为 2,这两个时钟是同步的。因为它们有相同时钟源点,并且周期为2倍关系。它们可以安全地一起进行时序收敛。

  • 异步时钟

    当无法确定两个时钟的相对相位关系时,这两个时钟就是异步的。例如,由板上两个独立晶振生成的时钟,通过不同输入端口进入 FPGA,这两个时钟就是异步的。如果它们是由板上的同一晶振生成的,这两个就不是异步时钟。在大多数情况下,基准时钟可以被视为异步时钟。

  • 不可扩展的时钟(Unexpandable Clocks)

    当时序引擎在 1000 个周期中无法找到两个时钟周期的公倍数时,则认为两个时钟无法扩展。在这种情况下,在时序分析时会使用 1000 周期中最小的相位关系,但时序引擎无法保证这是最差的情况。通常这两个时钟之间的周期比比较奇怪的情况。例如,两个时钟 clk0 和 clk1,由相同主时钟的两个 MMCM 生成,clk0 周期为 5.12 ns,clk1 周期为 6.66 ns。他们的上升沿在 1000 个周期内没有对齐的时候,时序引擎会取最差的情况 0.01 ns 做时序收敛。与异步时钟一样,余量计算会正常进行,但其值是不可信的。因此,无可扩展的时钟经常被处理为异步时钟,必须用处理异步时钟相同的方式对待这两个时钟,包括其约束和异步电路。

2.5.3 异步时钟组

异步时钟和不可扩展时钟不能被时序收敛。使用 set_clock_groups 指令可以在时序分析时忽略它们之间的时序路径。

注意set_clock_groups 比普通的时序例外的优先级要高,如果需要约束和报告异步时钟间的路径,那就不能使用 set_clock_groups ,只能使用时序例外。

2.5.3.1 异步时钟组示例

  • 基准时钟 clk0 定义在输入管脚上,并连接到了 MMCM。MMCM 生成了 usrclk 和 itfclk 两个时钟 。
  • 另一个基准时钟 clk1 定义在了 GTP 输出的恢复时钟上,并连接到了另一个 MMCM。此 MMCM 生成了 gtclkrx 和 gtclktx 两个时钟。

使用 -asynchronous 选项创建异步时钟组。

set_clock_groups -name async_clk0_clk1 -asynchronous -group {clk0 usrclk itfclk} \    -group {clk1 gtclkrx gtclktx}

如果衍生时钟的名称无法事先得知,可以使用 get_clocks -include_generated_clocks 动态获取。所以上面的约束也可以写成如下方式,其移植性更强。

set_clock_groups -name async_clk0_clk1 -asynchronous \    -group [get_clocks -include_generated_clocks clk0] \    -group [get_clocks -include_generated_clocks clk1]

注意:上面的约束中,异步是指组与组之间异步,组内各时钟仍会进行时序分析和收敛。

2.5.4 独占时钟组(Exclusive Clock Groups)

有些设计拥有多种操作模式,在不同的模式下需要使用不同的时钟。时钟之间的选择通常使用时钟多路复用器完成,如 BUFGMUX 和 BUFGCTRL 或 LUT(尽量不使用LUT做时钟选择)。由于这些单元是组合逻辑,所这些时钟都通过同一个时钟树传播。这些时钟会同时报告中呈现,但在硬件方面是不可能的,同一时刻只会有一个时钟。这种不会同时工作的时钟称作独占时钟。

2.5.4.1 独占时钟组示例

独占时钟使用 set_clock_groups-logically_exclusive-physically_exclusive 选项进行定义。在 Vivado 中,这两个选项的意义是相同的,任意使用一个即可。

假设一个 MMCM 输出了 clk0 和 clk1,这两个时钟连接到了一个 BUFGMUX(实例名为clkmux),输出 clkmux 驱动时钟树。默认情况下,Vivado 会分析 clk0 和 clk1 之间的路径,即便两个时钟驱动同一个时钟树,并且两个时钟不可能同时使用。必须使用如下约束停止分析两个时钟之间的路径。

set_clock_groups -name exclusive_clk0_clk1 -physically_exclusive -group clk0 -group clk1

2.6 时钟延迟、抖动和不确定性

除了定义时钟波形外,还必须指定与操作条件和环境相关的可预测变化和随机变化。

2.6.1 时钟延迟

时钟在 PCB 板上和 FPGA 内部传播后,时钟沿会经过一段延时后到达目的地。此延时通常有:

  • 源延时(通常在时钟源点之前,在 FPGA 设备外部)。
  • 网络延时。

网络延时(也称为插入延时),其延时值要么是自动估算(pre-route design),要么是精确计算(post-route design)。

Xilinx FPGA 使用 set_clock_latency 指令主要是用来指定器件外部的延时。

# Minimum source latency value for clock sysClk (for both Slow and Fast corners)set_clock_latency -source -early 0.2 [get_clocks sysClk]# Maximum source latency value for clock sysClk (for both Slow and Fast corners)set_clock_latency -source -late 0.5 [get_clocks sysClk]

2.6.2 时钟不确定性

2.6.2.1 时钟抖动

对于 ASIC 设备,时钟抖动通常表示在时钟不确定性特征中。然而,对于 FPGA 来说,抖动特性是可以预知的。它们可以通过时序分析引擎自动计算,也可以单独指定。

  • 输入抖动(Input Jitter)

    输入抖动是连续时钟边缘与理想时钟到达时间的差别。输入抖动是一个绝对值,表示时钟边缘两侧的变化。使用 set_input_jitter 指令单独指定每个基准时钟的输入抖动。衍生时钟上的输入抖动无法直接指定,Vivado 时序引擎会自动从主时钟继承的抖动到衍生时钟。

    • 对于由 MMCM 或 PLL 生成的时钟,输入抖动被计算的不同的抖动替换。
    • 对于由组合逻辑或时序逻辑生成的时钟,生成时钟抖动与其主时钟抖动相同。

    以下命令在通过输入端口 clkin 传播的基准时钟上设置 +/-100 ps 抖动:

    set_input_jitter [get_clocks -of_objects [get_ports clkin]] 0.1
  • 系统拉动(System Jitter)

    系统抖动是由于电源噪声、板噪声或系统的任何额外抖动而导致的整体抖动。使用 set_system_jitter 指令只为整个设计设置一个值,即针对所有时钟。

2.6.2.2 附加时钟不确定性

使用 set_clock_uncertainty 指令定义不同角落、延时或特定时钟关系所需的额外时钟不确定性。这一种方便为设计增加额外余量的方法。

无论约束的顺序如何,时钟相互间的不确定性总是优先于简单的时钟不确定性。在下示例中,虽然时钟 clk1 上最后定义了 1.0 ns 的简单时钟不确定性,但从时钟 clk1 到时钟 clk2 的计时路径受到 2.0 ns 时钟不确定性的限制。

set_clock_uncertainty 2.0 -from [get_clocks clk1] -to [get_clocks clk2]set_clock_uncertainty 1.0 [get_clocks clk1]

Xilinx约束学习笔记(二)—— 定义时钟的更多相关文章

  1. Xilinx约束学习笔记(一)—— 约束方法学

    <Xilinx约束学习笔记>为自己阅读 Xilinx 官方 UG903 文档后的学习笔记,大多数为翻译得来,方便大家学习. 1 约束方法学 1.1 组织约束文件 Xilinx 建议将时序约 ...

  2. Xilinx约束学习笔记(三)—— 时序概念

    3. 时序概念 发现对于时序基础的介绍这一块,Intel 的文档竟然要比 Xilinx 的详细,因此引用了很多 Intel 的文档内容. 3.1 术语 发送沿(launch edge),指用来发送数据 ...

  3. 【转载】【时序约束学习笔记1】Vivado入门与提高--第12讲 时序分析中的基本概念和术语

    时序分析中的基本概念和术语 Basic concept and Terminology of Timing Analysis 原文标题及网址: [时序约束学习笔记1]Vivado入门与提高--第12讲 ...

  4. Django学习笔记二

    Django学习笔记二 模型类,字段,选项,查询,关联,聚合函数,管理器, 一 字段属性和选项 1.1 模型类属性命名限制 1)不能是python的保留关键字. 2)不允许使用连续的下划线,这是由dj ...

  5. MongoDB学习笔记二- Mongoose

    MongoDB学习笔记二 Mongoose Mongoose 简介 之前我们都是通过shell来完成对数据库的各种操作, 在开发中大部分时候我们都需要通过程序来完成对数据库的操作 而Mongoose就 ...

  6. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  7. JMX学习笔记(二)-Notification

    Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...

  8. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  9. 《SQL必知必会》学习笔记二)

    <SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...

随机推荐

  1. Leetcode No.108 Convert Sorted Array to Binary Search Tree(c++实现)

    1. 题目 1.1 英文题目 Given an integer array nums where the elements are sorted in ascending order, convert ...

  2. 深入理解Java并发类——AQS

    目录 什么是AQS 为什么需要AQS AQS的核心思想 AQS的内部数据和方法 如何利用AQS实现同步结构 ReentrantLock对AQS的利用 尝试获取锁 获取锁失败,排队竞争 参考 什么是AQ ...

  3. css--filter(滤镜) 属性

    前言 前段时间找工作面试官问到一个问题,你如何将一个网页整体置灰?面试遇到这样的问题,一下束手无策,之前没有接触过这样的需求,因此没有回答上来,面试结束我才知道了这是考查对 CSS3 的新属性的了解. ...

  4. Django基础-01篇

    一.Django介绍 flask,FastApi是轻量级服务端开发框架 Django是重量级服务端开发框架 ORM:封装了数据库操作 form:校验请求数据 安装Django: pip install ...

  5. python 01篇

    一.Pycharm 使用小tips 1.1 pycharm创建项目时,选择Python环境,不使用默认的虚拟环境 1.2 如何在pycharm中查看python版本 路径:File-Settings- ...

  6. c语言:解释程序和编译程序

    编译程序和解释程序是程序执行的两种不同执行方式. 编译程序:编译程序的功能是把用高级语言书写的源程序翻译成与之等价的目标程序.编译过程划分成词法分析.语法分析.语义分析.中间代码生成.代码优化和目标代 ...

  7. 框架学习系列 mybatis mapper映射文件之输出映射

    1: mapper映射文件输出映射(输入类型) 2:resultType的使用 3:resultMap的使用 3:总结&下节预告 本文是<凯哥陪你学系列-框架学习之mybatis框架学习 ...

  8. 为了让她学画画——熬夜用canvas实现了一个画板

    前言 大家好,我是Fly, canvas真是个强大的东西,每天沉迷这个无法自拔, 可以做游戏,可以对图片处理,后面会给大家分享一篇,canvas实现两张图片找不同的功能, 听着是不是挺有意思的, 有点 ...

  9. C++第三十八篇 -- 研究一下Windows驱动开发(二)--WDM式驱动的加载

    基于Windows驱动开发技术详解这本书 一.简单的INF文件剖析 INF文件是一个文本文件,由若干个节(Section)组成.每个节的名称用一个方括号指示,紧接着方括号后面的就是节内容.每一行就是一 ...

  10. idea创建web工程、配置tomcat及基本配置

    背景 现在许多人从eclipse转到idea了,小编也不例外.但是刚转初期还是有挺多不适应的,特总结了创建maven的web工程.配置tomcat服务器及基本配置.有了这些配置,上手idea也就跟ec ...