精华内容
下载资源
问答
  • Intersil的新型多路复用器能实现在各个增益为2的放大器通道上的四路不同视频输入之间的切换 ISL59446具有集成的增益为2的放大器、500MHz的带宽和±1600V/μs的压摆率,可实现高质量视频切换   Intersil(NASDAQ...
  • 实验二 多路复用器与加法器的实现 一、实验目的 1.熟悉多路复用器、加法器的工作原理。 2.学会使用 VHDL 语言设计多路复用器、加法器。 3.掌握 generic 的使用,设计 n-1 多路复用器。 4.兼顾速度与...

     实验二 多路复用器与加法器的实现

    一、实验目的

        1.熟悉多路复用器、加法器的工作原理。

        2.学会使用 VHDL 语言设计多路复用器、加法器。

        3.掌握 generic 的使用,设计 n-1 多路复用器。

        4.兼顾速度与成本,设计行波加法器和先行进位加法器。

     

    二、实验内容

        1.用 VHDL 语言设计 8 重 3-1 多路复用器;

        2.用 VHDL 语言设计 n-1 多路复用器,调用该 n-1 多路复用器定制为 8-1 多路复用器。

        3.用 VHDL 语言设计 4 位行波进位加法器。

        4.用 VHDL 语言设计 4 位先行进位加法器。

     

    三、实验方法

    1. 实验方法:

           1采用基于FPGA进行数字逻辑电路设计的方法。

            2采用的软件工具是QuartusII软件仿真平台。

    1. 实验步骤:
    1. 新建,编写源代码。

    (1).选择保存项和芯片类型:【File】-【new project wizard】-【next】(设置文件路径+设置project name)-【next】-【next】(设置Family=FLEX10K;name=EPF10K10TI144-4)-【next】-【finish】

       (2).新建:【file】-【new】(选择AHDL File)-【OK】

    2、写好源代码,保存文件(文件名与工程名需保持一致)。

    3、编译与调试。确定源代码文件为当前工程文件,点击【processing】-【start compilation】进行文件编译。编译结果无警告,文件编译成功。

    4、波形仿真及验证。【file】-【new】(选择Vector Waveform File)-【OK】。按照程序所述插入节点(插入输入节点和输出节点)。(操作为:左键双击NAME下方框框 -【Node Finder】(设置Filter:Pins:all)-【list】)-【>>】-【ok】-【ok】)。按题目需求设置输入波形,点击保存按钮保存。

    5、时序仿真或功能仿真。

        (1).时序仿真:

    编译VHDL文件-选择.VWF波形文件-【Processing】-【Simulator Tool】(Simulation mode:选择Timing)-点击开始仿真按钮。

        (2).功能仿真

    编译VHDL文件-选择.VWF波形文件-【Processing】-【Simulator Tool】(Simulation mode:选择Functional)-【Generate Funtional Silmulation Netlist】-点击开始仿真按钮。

    6、查看RTL Viewer:【Tools】-【netlist viewer】-【RTL viewer】。

    四、实验过程

    1.8重3-1多路复用器

    1. 编译过程

    a)源代码如图(VHDL设计)

    b)编译、调试过程

    c)结果分析及结论

        结果显示0 errors,0 warnings,VHDL文件满足题目要求。

    1. 波形仿真

    a)波形仿真过程(详见实验步骤)

    b)波形仿真波形图

    功能仿真波形图:

    c)结果分析及结论

    0-10ns对应: 控制端为00,输出IR1的8位向量 正确

    10-20ns对应:控制端为10,输出IR3的8位向量 正确

    20-30ns对应:控制端为01,输出IR2的8位向量 正确

    30-40ns对应:控制端为00,输出IR1的8位向量 正确

    40-50ns对应:控制端为01,输出IR2的8位向量 正确

    50-60ns对应:控制端为10,输出IR3的8位向量 正确

    60-80ns对应:控制端为11,输入为无效,无输出 正确

    1. 查看RTL Viewer

     

    2. 8-1 多路复用器(调用n-1 多路复用器)

    1. 编译过程

    a)源代码如图(VHDL设计)

        1)n-1多路复用器的设计:

           2)调用为8-1多路复用器

    b)编译、调试过程

    c)结果分析及结论

        结果显示0 errors,0 warnings,VHDL文件满足题目要求。

    1. 波形仿真

    a)波形仿真过程(详见实验步骤)

    b)波形仿真波形图

    功能仿真波形图:

    c)结果分析及结论

    0-10ns对应: 000对应I[0],I[0]为1,输出为1 正确

    10-20ns对应:001对应I[1],I[1]为1,输出为1 正确

    20-30ns对应:010对应I[2],I[2]为1,输出为1 正确

    30-40ns对应:100对应I[3],I[3]为1,输出为1 正确

    40-50ns对应:101对应I[4],I[4]为1,输出为1 正确

    50-60ns对应:000对应I[5],I[5]为1,输出为1 正确

    60-70ns对应:000对应I[6],I[6]为1,输出为1 正确

    70-80ns对应:000对应I[7],I[7]为1,输出为1 正确

    80-90ns对应: 000对应I[0],I[0]为0,输出为0 正确

    90-100ns对应:001对应I[1],I[1]为0,输出为0 正确

    100-110ns对应:010对应I[2],I[2]为0,输出为0 正确

    110-120ns对应:100对应I[3],I[3]为0,输出为0 正确

    120-130ns对应:101对应I[4],I[4]为0,输出为0 正确

    130-140ns对应:000对应I[5],I[5]为0,输出为0 正确

    140-150ns对应:000对应I[6],I[6]为0,输出为0 正确

    150-160ns对应:000对应I[7],I[7]为0,输出为0 正确

    1. 查看RTL Viewer

     

     

    3. 4 位行波进位加法器

    A.设计方法一:迭代法设计

    1. 编译过程

    a)源代码如图(VHDL设计)

        1)半加器VHDL设计:

           2)全加器设计(调用半加器):

           3)4位行波进位加法器设计(调用全加器)

    b)编译、调试过程

    c)结果分析及结论

        结果显示0 errors,0 warnings,VHDL文件满足题目要求,采用迭代思想设计。

    1. 波形仿真

    a)波形仿真过程(详见实验步骤)

    b)波形仿真波形图

    功能仿真波形图:

    c)结果分析及结论

    对于功能仿真:

    0-10ns对应:   0000+0001+0=00001 正确

    10-20ns对应:  0000+0010+0=00010 正确

    20-30ns对应:  0000+0100+0=00100 正确

    30-40ns对应:  0000+1000+0=01000 正确

    40-50ns对应:  0010+0001+0=00011 正确

    50-60ns对应:  0100+0010+0=00110 正确

    60-70ns对应:  1000+0100+0=01100 正确

    70-80ns对应:  0001+1000+0=01001 正确

    80-90ns对应:  0000+0001+1=00010 正确

    90-100ns对应: 0000+0010+1=00011 正确

    100-110ns对应:0000+0100+1=00101 正确

    110-120ns对应:0000+1000+1=01001 正确

    120-130ns对应:0010+0001+1=00100 正确

    130-140ns对应:0100+0010+1=00111 正确

    140-150ns对应:1000+0100+1=01101 正确

    150-160ns对应:0001+1000+1=01010 正确

    150-160ns对应:1111+1111+1=11111 正确

    3  查看RTL Viewer

    1. 四位行波进位加法器:

    1. 全加器:

    1. 半加器:

     

    B.设计方法二:进位程序设计

    1.    编译过程

    a)源代码如图(VHDL设计)

    b)编译、调试过程

    c)结果分析及结论

        结果显示0 errors,0 warnings,VHDL文件满足题目要求。

    1.   波形仿真

    a)波形仿真过程(详见实验步骤)

    b)波形仿真波形图

    功能仿真波形图:

    c)结果分析及结论

    对于功能仿真:

    0-10ns对应:   0000+0001+0=00001 正确

    10-20ns对应:  0000+0010+0=00010 正确

    20-30ns对应:  0000+0100+0=00100 正确

    30-40ns对应:  0000+1000+0=01000 正确

    40-50ns对应:  0010+0001+0=00011 正确

    50-60ns对应:  0100+0010+0=00110 正确

    60-70ns对应:  1000+0100+0=01100 正确

    70-80ns对应:  0001+1000+0=01001 正确

    80-90ns对应:  0000+0001+1=00010 正确

    90-100ns对应: 0000+0010+1=00011 正确

    100-110ns对应:0000+0100+1=00101 正确

    110-120ns对应:0000+1000+1=01001 正确

    120-130ns对应:0010+0001+1=00100 正确

    130-140ns对应:0100+0010+1=00111 正确

    140-150ns对应:1000+0100+1=01101 正确

    150-160ns对应:0001+1000+1=01010 正确

    150-160ns对应:1111+1111+1=11111 正确

    3   查看RTL Viewer

     

     

     

    4. 4 位先行进位加法器

    1. 编译过程

    a)源代码如图(VHDL设计)

    b)编译、调试过程

    c)结果分析及结论

        结果显示0 errors,0 warnings,VHDL文件满足题目要求。

    1. 波形仿真

    a)波形仿真过程(详见实验步骤)

    b)波形仿真波形图

    功能仿真波形图:

    c)结果分析及结论

    对于功能仿真:

    0-10ns对应:   0000+0001+0=00001 正确

    10-20ns对应:  0000+0010+0=00010 正确

    20-30ns对应:  0000+0100+0=00100 正确

    30-40ns对应:  0000+1000+0=01000 正确

    40-50ns对应:  0010+0001+0=00011 正确

    50-60ns对应:  0100+0010+0=00110 正确

    60-70ns对应:  1000+0100+0=01100 正确

    70-80ns对应:  0001+1000+0=01001 正确

    80-90ns对应:  0000+0001+1=00010 正确

    90-100ns对应: 0000+0010+1=00011 正确

    100-110ns对应:0000+0100+1=00101 正确

    110-120ns对应:0000+1000+1=01001 正确

    120-130ns对应:0010+0001+1=00100 正确

    130-140ns对应:0100+0010+1=00111 正确

    140-150ns对应:1000+0100+1=01101 正确

    150-160ns对应:0001+1000+1=01010 正确

    150-160ns对应:1111+1111+1=11111 正确

    3  查看RTL Viewer

     

    五、实验结论与心得

    经过本次实验,我对Quartus II仿真软件有了更好的理解和运用,对VHDL语言的使用有了更好的掌握,熟练了创建工程文件、软件编译操作、仿真波形模拟等操作。

    了解到VHDL语言可以使用模块并调用模块,熟练掌握了component语法的运用以及模块的调用设计,并利用不同方式使用模块。

    为了更好地运用4 位行波进位加法器,熟悉其操作,分别采用了迭代法和进位程序设计,对比两者的RTL视图,更好地理解了迭代法对模块使用的好处以及优点。在实验过程中,写好4 位行波进位加法器和4 位先行进位加法器,通过对波形仿真的操作,明白了先行进位加法器无需等待进位输入的优点。

     

    六、思考题

    1.多路复用器的实现方法很多,请总结两种以上实现方法。

        一是直接定制特定规模特定需求的多路复用器;

        二是调用模块定制成不同规模的多路复用器。

     

    2. 总结 VHDL 语言描述多路复用器的方法和常用语句。

        VHDL语言的基本结构由库和程序包、实体、结构体组成,描述多路复用器常用语句有变量赋值语句、信号代入语句等。

     

    展开全文
  • 在Spartan-3器件内部提供了全局时钟资源,其中包括专用时钟输入引脚、缓冲和布线资源,其时钟分配树结构1所示。主要时钟连接路径为从专用时钟输入引脚的全局时钟,在驱动全局时钟缓冲后经由全局布线资源到达...
  • 数字电路基础知识——组合逻辑电路(数据选择器MUX、多路复用器) 数据选择器(MUX) 二选一数据选择器 用 2输入mux,实现与,或,非,异或 三、 四选一选择器 四、用选择器设计组合逻辑电路 五、例:用Verilog描述...

    数字电路基础知识——组合逻辑电路(数据选择器MUX、也即多路复用器)
    本次介绍数据选择器的相关知识,数据选择器在电路设计中尤为重要,尤其是对于在Verilog中的if-else的语法即 o = a?b :c 都可以看到有数据选择器的使用。
    介绍数据选择器的设计原则以及实例:用Verilog描述一个多路复用器,输入的通道数目N,每一路的位宽为M。
    求log以2为低的整数的算法(使用移位寄存器、数据比较器)

    一、二选一数据选择器(2-1 MUX)

    二选一的数据选择器是最简单的结构,其逻辑框图、门级电路、以及真值表如下:
    在这里插入图片描述

    二、 用 2输入mux,实现与,或,非,异或

    二选一用Verilog语言描述:
    o = s ? a : b;

    1. 与逻辑:
      out = (a == 1’b0)? 1’b0: ((b == 1’b0)? 1’b0: 1’b1);

      out = (a == 1’b1)? b: 1’b0;
      Y=SA+S’B=AB+A’0=AB

    2. 或逻辑:
      out = (a == 1’b1)? 1’b1: ((b == 1’b1)? 1’b1: 1’b0);

      out = (a == 1’b0)? b: 1’b1;
      Y=SA+S’B=A’B+A=A+B

    3. 非逻辑:
      out = (a == 1’b1)? 1’b0: 1’b1;

    4. 异或
      out = (a == 1’b1)? ((b == 1’b1)? 1’b0: 1’b1) : (b);
      Y=AB’+A’B

    三、 四选一选择器

    在实际的芯片器件中,用的最多的是双四选一选择器 74HC153
    下图是内部逻辑电路图:
    在这里插入图片描述
    四选一只需两位地址输入,四个输入状态选择其中一个
    而八选一需要三位地址输入,八个输入状态选择其中一个,利用S’作为第三个地址输入端
    因此可以利用这两个四选一选择器接成一个八选一的选择器
    在这里插入图片描述

    四、用选择器设计组合逻辑电路

    基本原理:

    利用如下关系
    一个具有n位地址输入的数据选择器,可以产生任何形式的
    输入不大于n+1的组合函数
    在这里插入图片描述
    对于下面的逻辑表达式:
    在这里插入图片描述
    Z=R’(A’G’)+R(A’G)+R((AG’)+1(AG))
    在这里插入图片描述
    当然也可以用R A 作为选通地址,G作为选通端,将函数化简如下:
    Z=(R’A’)G’+(RA’)G+(RA)1

    五、例:用Verilog描述一个多路复用器,输入的通道数目N,每一路的位宽为M。
    1. 代码设计如下:
    module mux
    #(
        parameter   m = 8,
        parameter   n = 8,
        parameter   width = clogb2(n)
    )
    (
        input   [n*m-1:0]   indata,
        input   [width-1:0] sel,
        output  [m-1:0]     outdata
    );
    
    assign  outdata =   indata[(m*(sel+1)-1)-:m];
    
    //-------------------------------------------------------
    //以下两个函数任用一个
    //求2的对数函数
    function integer log2;
      input integer value;
      begin
        value = value-1;
        for (log2=0; value>0; log2=log2+1)
          value = value>>1;
      end
    
    
    endfunction
    
    //求2的对数函数
    function integer clogb2 (input integer bit_depth);
    begin
        for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
            bit_depth = bit_depth>>1;
    end
    endfunction
    
    endmodule
    

    这里需要注意:

    1. [n-:m]表示数据位宽为m的从n开始的数据位宽。如reg [6-:3] 表示 reg [6:4]
    2. 参数传递必须时具体数值,如在parameter定义。
    3. 求log以2为低的整数,具体方法上面用到的是移位寄存器,即将数据向右移位即可以得到所需最大的整数。
      也可以利用下面的方法:
     function integer log2(input integer x);
            integer i;
            begin
                log2 = 1;
                for (i = 0; 2**i < x; i = i + 1) //不用移位寄存器,只用比较器 
                begin
                    log2 = i + 1;
                end
            end
     endfunction
    

    注: 2**i 表示2i

    log2(10)等于4

    log2(16)等于4

    log2(510001000)等于26

    展开全文
  • 数字电路实验二——译码器实现一、实验目的二、实验内容三、实验方法1、 实验方法2、 实验步骤四、实验过程A. 8 重 3-1 多路复用器1、 编译过程2、 波形仿真3、 时序仿真B. 参数化多路复用器,调用该参数化多路复用...

    代码仅供参考:
    链接:pan.baidu.com/s/1VekND1K50yclOKdkSI-otw
    up1k

    一、实验目的

    1. 熟悉多路复用器以及模型机的工作原理。
    2. 学会使用 VHDL语言设计多路复用器。
    3. 掌握 generic的使用,能运用设计参数化多路复用器。
    4. 学会使用VHDL语言设计模型机控制信号产生逻辑。

    二、实验内容

    1. 用 VHDL 语言设计模型机的 8 重 3-1 多路复用器;
    2. 设计参数化多路复用器,调用该参数化多路复用器定制为 8-1 多路复用器。
    3. 用 VHDL 语言设计模型机的控制信号产生逻辑。

    三、实验方法

    1、 实验方法

    采用基于FPGA进行数字逻辑电路设计的方法。
    采用的软件工具是Quartus II。

    2、 实验步骤

    (三个工程过程相同,以8重3-1多路复用器为例)
    1、 新建三个工程,编写源代码。
    (1).选择保存项和芯片类型:【File】-【new project wizard】-【next】(设置文件路径+设置project name为MUX)-【next】(设置文件名MUX.vhd—在【add】)-【properties】(type=AHDL)-【next】(family=FLEX10K;name=EPF10K10TI144-4)-【next】-【finish】
    (2).新建:【file】-【new】(第二个AHDL File)-【OK】
    2、 写好源代码,保存文件(MUX.vhd)。
    3、 编译与调试。确定源代码文件为当前工程文件,点击【processing】-【start compilation】进行文件编译,编译成功。
    4、 波形仿真及验证。新建一个vector waveform file。按照程序所述插入a,b,c三个节点(a、b为输入节点,c为输出节点)。(操作为:右击 -【insert】-【insert node or bus】-【node finder】(pins=all;【list】)-【>>】-【ok】-【ok】)。任意设置a,b的输入波形…点击保存按钮保存。(操作为:点击name(如:I0(0)))-右击-【value】-【clock】(如设置period=200;offset=0),同理设置name I1(0)(如120,,60),保存)。然后【start simulation】,出name S的输出图。
    5、 时序仿真或功能仿真。
    6、 查看RTL Viewer:【Tools】-【netlist viewer】-【RTL viewer】。

    四、实验过程

    A. 8 重 3-1 多路复用器

    1、 编译过程

    a. 源代码如图(VHDL设计)
    在这里插入图片描述
    b. 编译、调试过程
    在这里插入图片描述
    无错误信息,编译通过。

    c. RTL视图
    在这里插入图片描述

    d. 结果分析及结论
    实现8重3-1多路复用器就是在三个8维向量中选择一个输出,需要两个选择信号,用VHDL实现较为简单。

    2、 波形仿真

    a. 波形仿真过程(详见实验步骤)
    b. 波形仿真波形图
    在这里插入图片描述在这里插入图片描述
    当选择输入s为00时选择I0的八维输入,正确
    在这里插入图片描述在这里插入图片描述
    选择输入S为01时,输出I1,正确
    在这里插入图片描述
    当选择输入S为10时,输出I2,正确

    c. 结果分析及结论
    当选择输入s为00时选择I0的八维输入,正确
    当选择输入S为01时,输出I1,正确
    当选择输入S为10时,输出I2,正确

    3、 时序仿真

    a. 时序仿真过程
    做好上述步骤后,编译【classic timing analysis】-在compilation report中选择【timing analysis】-【tpd】(引脚到引脚的延时)
    b. 时序仿真图
    在这里插入图片描述
    c. 结果分析及结论
    由S(1)引脚到Y(7)引脚所需时间最长为10.407ns,因此总体时间为10.407ns。
    tpd (引脚到引脚的延时)

    B. 参数化多路复用器,调用该参数化多路复用器定制为 8-1 多路复用器

    1、 编译过程

    a. 源代码如图(VHDL设计)
    参数化多路复用器:
    在这里插入图片描述
    定制为 4 位加法器:
    在这里插入图片描述
    b. 编译、调试过程
    在这里插入图片描述
    无编译警告及错误。

    c. RTL视图
    在这里插入图片描述
    d. 结果分析及结论
    参数化多路复用器的设计较为困难,将输入信号个数n作为参数,选择信号在参数多路复用器中同样设计为长度为n的二进制数,在定制的时候注意选择参数的位数即可。

    2、 波形仿真

    a. 波形仿真过程(详见实验步骤)
    b. 波形仿真波形图
    在这里插入图片描述
    c. 结果分析及结论
    0-2.5ns:s=”000”,F输出I0,正确
    2.5-5ns:s=”001”,F输出I1,正确
    5-7.5ns:s=”010”,F输出I2,正确
    7.5-10ns:s=”011”,F输出I3,正确
    10-12.5ns:s=”100”,F输出I4,正确
    12.5-15ns:s=”101”,F输出I5,正确
    15-17.5ns:s=”110”,F输出I6,正确
    17.5-20ns:s=”111”,F输出I7,正确

    3、 时序仿真

    a. 时序仿真过程
    做好上述步骤后,编译【classic timing analysis】-在compilation report中选择【timing analysis】-【tpd】(引脚到引脚的延时)
    b. 时序仿真图
    在这里插入图片描述
    c. 结果分析及结论
    I(6)引脚到F引脚的延时最长,为8.805ns,因此总时长为8.805ns。
    tpd (引脚到引脚的延时)

    C. 模型机的控制信号产生逻辑

    1、 编译过程

    a. 源代码如图(VHDL设计)
    在这里插入图片描述
    b. 编译、调试过程
    在这里插入图片描述
    c. RTL视图
    在这里插入图片描述

    逻辑符号:
    在这里插入图片描述
    d. 结果分析及结论
    每一个控制信号都需要根据时钟周期与控制指令信号进行逻辑上的判断,需要掌握各个指令的执行过程,进而写出我们需要的控制信号的逻辑表达式。输入信号包括8位指令、状态位C,Z,SM,译码器输出的指令。通过这些输入产生执行指令阶段的控制信号,每条控制信号的产生逻辑见VHDL。下面的波形仿真只要检查控制信号的产生逻辑即可。

    2、 波形仿真

    a. 波形仿真过程(详见实验步骤)
    b. 波形仿真波形图
    (仅ADD有变化时)
    在这里插入图片描述
    c. 结果分析及结论
    当仅ADD为1,SM为0时是取操作,此时INPC为1,MADD为00,CS为0,XL为0,DL为1,LDIR为1,波形正确。

    3、 时序仿真

    a. 时序仿真过程
    做好上述步骤后,编译【classic timing analysis】-在compilation report中选择【timing analysis】-【tpd】(引脚到引脚的延时)
    b. 时序仿真图
    在这里插入图片描述
    c. 结果分析及结论
    SM引脚到DL引脚的实际p2p时间最长且为9.263ns,故整体为9.263ns。
    tpd (引脚到引脚的延时)

    五、实验结论

    前两个工程比较简单,只要正确理解工程要实现的功能就可以将代码简化到最佳,其中参数化多路复用器中使用了一个函数conv_integer将二进制数转化为了十进制数,进而能够直接输出选择信号(二进制)控制的输入信号中的哪一个(十进制)直接进行输出。这个方法有些不怎么好,虽然简便但是利用十进制数不能体现多路复用器的实现原理,而仅仅是实现了它的功能。
    模拟机控制信号的逻辑产生较为复杂,需要将CPU的执行过程以及各个控制信号的功能完全理解清楚,在我写RAM的XL信号以及DL信号时理解错误,XL仅仅在MOVB为1时有效,各个信号在取周期与执行周期的逻辑取值可能不同,经过长时间的艰苦奋斗,我终于将控制信号逻辑判断了大概,但可能里面还存在一些逻辑上的错误判断不出来。

    展开全文
  • NIO解读之多路复用器Selector

    千次阅读 2015-03-20 16:26:01
    Selector是JDK的NIO中最重要的类之一,当我们通过Selector.open()方法打开一个多路复用器的时候实际上执行的open方法为 public static Selector open() throws IOException {  return SelectorProvider.provider()....


    Selector类的结构图如下所示:



    Selector是JDK的NIO中最重要的类之一,当我们通过Selector.open()方法打开一个多路复用器的时候实际上执行的open方法为

    public static Selector open() throws IOException {

        return SelectorProvider.provider().openSelector();

    }

    调用了SelectorProvider.provider()方法,方法代码如下:

        public static SelectorProvider provider() {

            synchronized (lock) {

                if (provider != null)

                    return provider;

                return AccessController.doPrivileged(

                    new PrivilegedAction<SelectorProvider>() {

                        public SelectorProvider run() {

                                if (loadProviderFromProperty())

                                    return provider;

                                if (loadProviderAsService())

                                    return provider;

                                provider = sun.nio.ch.DefaultSelectorProvider.create();

                                return provider;

                            }

                        });

            }

        }

    可以看出这个方法首先通过加锁保证了静态的属性provider 如果不为空,才去创建一个,这个方法对于不同的操作系统平台会返回不同的实例,对于Windows返回的就是WindowsSelectorProvider这个Provider



    然后调用了WindowsSelectorProvider的openSelector方法创建了WindowsSelectorImpl也就是我们真正的多路复用器实现类,接着WindowsSelectorImpl的构造方法:


        WindowsSelectorImpl(SelectorProvider sp) throws IOException {

            super(sp);      

            pollWrapper = new PollArrayWrapper(INIT_CAP);

            wakeupPipe = Pipe.open();

            wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFDVal();


            // Disable the Nagle algorithm so that the wakeup is more immediate

            SinkChannelImpl sink = (SinkChannelImpl)wakeupPipe.sink();

            (sink.sc).socket().setTcpNoDelay(true);

            wakeupSinkFd = ((SelChImpl)sink).getFDVal();


            pollWrapper.addWakeupSocket(wakeupSourceFd, 0);

        }

    首先通过 super(sp);  调用了父类的SelectorImpl的构造方法将SelectorProvider的实现类WindowsSelectorProvider传入,SelectorImpl的构造方法如下:

        protected SelectorImpl(SelectorProvider sp) {

            super(sp);

            keys = new HashSet<SelectionKey>();

            selectedKeys = new HashSet<SelectionKey>();

            if (Util.atBugLevel("1.4")) {

                publicKeys = keys;

                publicSelectedKeys = selectedKeys;

            } else {

                publicKeys = Collections.unmodifiableSet(keys);

                publicSelectedKeys = Util.ungrowableSet(selectedKeys);

            }

        }

    他的第一行代码也调用了父类AbstractSelector的构造方法:代码如下:

        protected AbstractSelector(SelectorProvider provider) {

            this.provider = provider;

        }

    他只是将SelectorProvider 的实现类保存到了自己的实例变量中,可见AbstractSelector类中保存了SelectorProvider 的实现,接着看SelectorImpl构造方法的其他代码:

    他构造了keys和selectedKeys变量。接着看WindowsSelectorImpl的构造方法:

    接着构造了pollWrapper变量,接着看wakeupPipe = Pipe.open();这是一行关键的代码,看看Pipe.open()方法,代码如下:

        public static Pipe open() throws IOException {

            return SelectorProvider.provider().openPipe();

        }

    他同样也是通过SelectorProvider.provider()创建的上文说过这个对象的创建,这个方法定义在SelectorProviderImpl这个abstract类中,同样几个其他的DatagramChannel,ServerSocketChannel,SocketChannel都是定义在SelectorProviderImpl这个的类中,看上文的继承结构图可以看出这个类是WindowsSelectorProvider的父类,实际上WindowsSelectorProvider只是实现了抽象类SelectorProviderImpl中的一个WindowsSelectorProvider方法而已,SelectorProviderImpl的openPipe方法如下:

        public Pipe openPipe() throws IOException {

            return new PipeImpl(this);

        }

    接着看PipeImpl的构造方法,Pipe类的继承结构如下所示:


    PipeImpl类的构造方法如下:

        PipeImpl(SelectorProvider sp) {

            long pipeFds = IOUtil.makePipe(true);

            int readFd = (int) (pipeFds >>> 32);

            int writeFd = (int) pipeFds;

            FileDescriptor sourcefd = new FileDescriptor();

            IOUtil.setfdVal(sourcefd, readFd);

            source = new SourceChannelImpl(sp, sourcefd);

            FileDescriptor sinkfd = new FileDescriptor();

            IOUtil.setfdVal(sinkfd, writeFd);

            sink = new SinkChannelImpl(sp, sinkfd);

        }

    首先调用IOUtil.makePipe这个native方法,通过他的注释我们可以看出他创建了一个pipe管道的两个文件描述符对象,read端是返回值的高32位,write端是返回值的低32位,

        /**

         * Returns two file descriptors for a pipe encoded in a long.

         * The read end of the pipe is returned in the high 32 bits,

         * while the write end is returned in the low 32 bits.

         */

        static native long makePipe(boolean blocking);


    接下来看PipeImpl的构造方法中将返回的文件描述符的地址进行了相应的赋值,接着创建了一个sourcefd 的文件描述符对象,将他与readFd关联上,将sinkfd文件描述符对象和writeFd关联

    接着创建了SourceChannelImpl和SinkChannelImpl对象,SourceChannelImpl类就对应了pipe读一端的channel,SinkChannelImpl类就对应了pipe写一端的channel.

    这样PipeImpl对象创建完毕返回赋值带WindowsSelectorImpl类的wakeupPipe属性,WindowsSelectorImpl的wakeupSourceFd属性就对应了刚才创建的Pipe对象的source,

    wakeupSinkFd属性就对应了刚才创建的Pipe对象的sink

    接着将wakeupSourceFd这个文件描述符加入到pollWrapper对象中,构造方法就结束了。

    pollWrapper对象中保存的文件描述符对象就是调用多路复用器select方法时操作系统要扫描的文件描述符列表。

    其实WindowsSelectorImpl创建的Pipe对象的就是为了自己唤醒自己而已,对于调用了多路复用器对象的select方法时,是一直阻塞的,实际上操作系统就是在轮训pollWrapper对象中注册的文件描述符对象。试想一下如果这个时候想加入一个新的Channel,那么势必得让select方法返回,一个阻塞在select上的线程有以下三种方式可以被唤醒:

    1)  有数据可读/写,或出现异常。

    2)  阻塞时间到,即time out

    3)  收到一个non-block的信号。可由killpthread_kill发出。

    1)第二种方法可以排除,因为select一旦阻塞,应无法修改其time out时间。

    2)而第三种看来只能在Linux上实现,Windows上没有这种信号通知的机制。

     

    所以,看来只有第一种方法了。再回想到为什么每个Selector.open(),在Windows会建立一对自己和自己的loopbackTCP连接;在Linux上会开一对pipepipeLinux下一般都是成对打开),估计我们能够猜得出来——那就是如果想要唤醒select,只需要朝着自己的这个loopback连接发点数据过去,于是,就可以唤醒阻塞在select上的线程了。

    这时再来看看WindowsSelectorImpl. Wakeup():

        public Selector wakeup() {

            synchronized (interruptLock) {

                if (!interruptTriggered) {

                    setWakeupSocket();

                    interruptTriggered = true;

                }

            }

            return this;

        }


        private void setWakeupSocket() {

            setWakeupSocket0(wakeupSinkFd);

        }


        private native void setWakeupSocket0(int wakeupSinkFd);


    可见wakeup()是通过pipewrite send(scoutFd, &byte, 1, 0),发生一个字节1,来唤醒poll()。所以在需要的时候就可以调用selector.wakeup()来唤醒selector


    对于windows,每当调用一次Selector的open方法就建立了两个TCP的链接,一个Server绑定了一个随机的端口号,一个client连接,server和client相连,如果要是实现wakeup,client就给这个server发送一点儿数据就OK 了。

    对于linux使用的是pipe管道来实现的。




    下面来说说Selector.select方法:

        public int select() throws IOException {

            return select(0);

        }

        public int select(long timeout)

            throws IOException

        {

            if (timeout < 0)

                throw new IllegalArgumentException("Negative timeout");

            return lockAndDoSelect((timeout == 0) ? -1 : timeout);

        }

        private int lockAndDoSelect(long timeout) throws IOException {

            synchronized (this) {

                if (!isOpen())

                    throw new ClosedSelectorException();

                synchronized (publicKeys) {

                    synchronized (publicSelectedKeys) {

                        return doSelect(timeout);

                    }

                }

            }

        }

    他最后调用到了WindowsSelectorImpl的doSelect方法:

        protected int doSelect(long timeout) throws IOException {

            if (channelArray == null)

                throw new ClosedSelectorException();

            this.timeout = timeout; // set selector timeout

            processDeregisterQueue();

            if (interruptTriggered) {

                resetWakeupSocket();

                return 0;

            }

            // Calculate number of helper threads needed for poll. If necessary

            // threads are created here and start waiting on startLock

            adjustThreadsCount();

            finishLock.reset(); // reset finishLock

            // Wakeup helper threads, waiting on startLock, so they start polling.

            // Redundant threads will exit here after wakeup.

            startLock.startThreads();

            // do polling in the main thread. Main thread is responsible for

            // first MAX_SELECTABLE_FDS entries in pollArray.

            try {

                begin();

                try {

                    subSelector.poll();

                } catch (IOException e) {

                    finishLock.setException(e); // Save this exception

                }

                // Main thread is out of poll(). Wakeup others and wait for them

                if (threads.size() > 0)

                    finishLock.waitForHelperThreads();

              } finally {

                  end();

              }

            // Done with poll(). Set wakeupSocket to nonsignaled for the next run.

            finishLock.checkForException();

            processDeregisterQueue();

            int updated = updateSelectedKeys();

            // Done with poll(). Set wakeupSocket to nonsignaled for the next run.

            resetWakeupSocket();

            return updated;

        }


    来看看几个关键的方法:

        private void adjustThreadsCount() {

            if (threadsCount > threads.size()) {

                // More threads needed. Start more threads.

                for (int i = threads.size(); i < threadsCount; i++) {

                    SelectThread newThread = new SelectThread(i);

                    threads.add(newThread);

                    newThread.setDaemon(true);

                    newThread.start();

                }

            } else if (threadsCount < threads.size()) {

                // Some threads become redundant. Remove them from the threads List.

                for (int i = threads.size() - 1 ; i >= threadsCount; i--)

                    threads.remove(i).makeZombie();

            }

        }

    在分析ServerSocketChannel的regist方法时分析过如果注册的channel数量超过了1024那么就要启动一个新的帮助线程来出来,这个方法就是根据threadsCount属性的值来启动相应的线程,那么创建的线程就是从一个索引的位置(1024,2048顺序递增)起轮训pollWrapper对应的索引中的文件描述符的,也就是调用doselct方法的主线程轮训的是pollWrapper从0到1023索引中的fd,剩下的有子线程相应的处理,他们都是阻塞在

    subSelector.poll();方法上

            private int poll() throws IOException{ // poll for the main thread

                return poll0(pollWrapper.pollArrayAddress,

                             Math.min(totalChannels, MAX_SELECTABLE_FDS),

                             readFds, writeFds, exceptFds, timeout);

            }


            private native int poll0(long pollAddress, int numfds,

                 int[] readFds, int[] writeFds, int[] exceptFds, long timeout);

    当线程被唤醒时readFds,writeFds,exceptFds就被相应的赋值


    主线程和子线程是通过startLock和finishLock来交互的,具体的就是如果主线程被唤醒了而没有一个子线程被唤醒,那么主线程就要等待至少一个子线程被唤醒,当有一个子线程被唤醒时他就唤醒其他的子线程和主线程一起返回。

    接下来看看updateSelectedKeys方法:

        private int updateSelectedKeys() {

            updateCount++;

            int numKeysUpdated = 0;

            numKeysUpdated += subSelector.processSelectedKeys(updateCount);

            for (SelectThread t: threads) {

                numKeysUpdated += t.subSelector.processSelectedKeys(updateCount);

            }

            return numKeysUpdated;

        }

    主线程和子线程都要调用到 subSelector.processSelectedKeys方法上,代码如下:

            private int processSelectedKeys(long updateCount) {

                int numKeysUpdated = 0;

                numKeysUpdated += processFDSet(updateCount, readFds,

                                               PollArrayWrapper.POLLIN,

                                               false);

                numKeysUpdated += processFDSet(updateCount, writeFds,

                                               PollArrayWrapper.POLLCONN |

                                               PollArrayWrapper.POLLOUT,

                                               false);

                numKeysUpdated += processFDSet(updateCount, exceptFds,

                                               PollArrayWrapper.POLLIN |

                                               PollArrayWrapper.POLLCONN |

                                               PollArrayWrapper.POLLOUT,

                                               true);

                return numKeysUpdated;

            }

    他们就是将readFds,writeFds与注册的SelectionKeyImpl对象关联上设置到相应的事件保存到SelectorImpl对象的selectedKeys属性中

    展开全文
  • Intersil公司宣布推出ISL59446,一个带有三个集成的增益为2的放大器的三通道4:1多路复用器。这个器件可以允许用户同时在四个单一的三视频输入信号间进行切换,或者可以将其置于一个高阻抗的状态下,这就允许这些...
  • BIO,NIO,多路复用器 书中自有黄金屋,书中自有颜如玉 ———————————————————————————————————— 本文在《码出高效:Java开发手册》书本讲解内容的基础上,将和大家一起对JDK1.8...
  • 存储元件Spartan-6的每个SLICE 有8个存储元件,可以实现存储功能。...2-4 SLICE里寄存器/锁存器配置多路复用器(MUX)多路复用器F7AMUX、F7BMUX 和F8MUX通常和函数发生器或者片上逻辑一起实现多种多路复用器。在...
  • 选择与I/O多路复用

    2020-06-09 00:36:29
    选择与I/O多路复用 Selector选择是NIO技术中的核心组件,可以将通道注册进选择中,其主要作用就是使用1个线程来对多个通道中的已就绪通道进行选择,然后就可以对选择的通道进行数据处理,属于一对多的关系,也...
  • 管道和多路复用器延迟情况是难以忍受的。现代计算机能以惊人的速度生成数据,并且高速互联网(经常是在重要的服务器之间有多个并行连接)提供了极大的带宽,但是这可恶的延迟意味着电脑花了大量时间等待数据。基于延续...
  • 第二就是要想实现多路复用技术就需要一个工具:多路复用器。 拓展:多路复用器的存在意义是为了充分利用通信信道的容量,大大降低系统的成本。例如,对于一对电话线来说,它的通信频带一般在100kHz以上,而每一路...
  • 一个多路复用器Selector可以同时轮询多个Channel,由于JDK使用了epoll()代替传统的select实现,所以它并没有最大连接句柄1024/2048的限制。这也就意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的...
  • 多路复用时钟

    千次阅读 2015-09-08 19:30:42
    是某一类型的时钟多路器: 虽然在时钟信号上引入多路逻辑会产生毛刺等问题,但是在不同的应用中,对多路时钟的要求区别 很大。但是如果能够满足以下标准,时钟多路操作是可接受的: - 在初始化配置后,时钟...
  • 数字电路实验(二)——三态门与多路复用器

    千次阅读 多人点赞 2019-11-04 10:30:42
    2个vhd文件,用来定义和实现带参数顶层实体文件,一个用来调用顶层实体(示例)和实现该参数下的多路复用器 1个vwf文件,用来进行波形仿真,将验证的波形输入 1、 新建,编写源代码。 (1).选择保存项和芯片类型:...
  • IO多路复用—由Redis的IO多路复用yinch

    万次阅读 多人点赞 2018-04-23 16:56:40
    linux IO多路复用有epoll, poll, select,epoll性能比其他几者要好。 名词比较绕口,理解涵义就好。一个epoll场景:一个酒吧服务员(一个线程),前面趴了一群醉汉,突然一个吼一声“倒酒”(事件),你小跑过去...
  • IO多路复用机制详解

    2018-07-12 13:48:34
    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种:(1)同步阻塞IO(Blocking IO):即传统的IO模型。(2)同步非阻塞IO(Non-blocking IO)...(3)IO多路复用(IO Multiplexing...
  • IO多路复用详解

    2021-07-11 23:34:27
    文章目录IO多路复用详解IO多路复用的实现方式Socket通信的流程普通的Socket管理Select的实现Epoll的实现 IO多路复用详解 IO多路复用的实现方式 我们这里只讨论linux两个典型的实现,select和epoll select 方式,...
  • Mina 协议编解码过滤二(协议解码): [url]http://donald-draper.iteye.com/blog/2376679[/url] Mina 队列Queue:[url]http://donald-draper.iteye.com/blog/2376712[/url] Mina 协议编解码过滤三(会话...
  • 多路复用的协议编码添加消息编码,如果参数为消息类型和消息编码类型,添加消息类型与默认构造消息编码工厂到消息编码Map映射type2encoderFactory;如果参数为消息类型和消息编码实例,添加消息类型与...
  • 多路复用技术

    2014-11-21 11:22:13
    2.5 多路复用技术 2.5.1 频分多路复用 在物理信道能提供比单个原始信号宽得多的带宽的情况下,我们就可将该物理信道的总 带宽分割成若干个和传输的单个信号带宽相同(或略为宽一点)的子信道,每一个子信道传 ...
  • IO多路复用机制

    2017-08-24 15:57:54
    服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型。 (2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求...
  • Java IO多路复用技术详解

    万次阅读 2017-04-28 09:49:58
    服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型。 (2)同步非阻塞IO(Non-blocking IO):默认创建的...(3)IO多路复用(IO Multiplexi
  • IO多路复用

    2017-03-31 16:44:00
    服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型。 (2)同步非阻塞IO(Non-blocking IO):默认创建的...(3)IO多路复用(IO Multiplexi
  • 面试之多路复用

    万次阅读 多人点赞 2018-03-27 21:07:31
    所谓I/O多路复用机制,就是说通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通...
  • 浅谈XILINX FPGA CLB单元 汇总 (CLB、LUT、存储单元、Distributed RAM、移位寄存器、多路复用器、进位逻辑(Carry Logic)) 一、概述 CLB可配置逻辑块是指实现各种逻辑功能的电路,是xilinx基本逻辑单元。 在Xilinx ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 41,124
精华内容 16,449
关键字:

多路复用器结构图