基于Primitive实现的异步四位二进制计数器

基于Primitive实现的四位二进制计数器

1.原理

​ 先看下图设计的四位二进制计数器电路:

image-20220819145121834

​ 采用上升沿触发的D触发器,所有触发器初始输出状态在Primitive里设置为0,即第零态为0000,所以四个D触发器的初始输入状态均为1,搞清楚初始输入输出状态后,下面进入正式原理分析:

​ 当第一个Clk上升沿到来时,FDCE1输入端初态1送入Q,即Q=1,此导致Q非端及D端为0,而FDCE2时钟端此时正由1—>0,为下降沿,故其Q端状态不变,易分析FDCE3、FDCE4 Q端状态也保持不变为0,此为第一个状态0001(注意图中FDCE4为高位,FDCE1为低位)。

​ 当第二个Clk上升沿到来时,FDCE1输入端状态0送入Q,即Q=0;此导致Q非端及D端为1,而FDCE2时钟端此时正由0—>1,为上升沿,故其D端初态1送入Q端,即Q=1,此导致其Q非端及D端为0,而FDCE3时钟端此时正由1—>0,为下降沿,故其Q端状态不变为0,易分析FDCE4 Q端状态也保持不变为0,此为第二个状态0010。

​ 当第三个Clk上升沿到来时,FDCE1输入端状态1送入Q,即Q=1;此导致Q非端及D端为0,而FDCE2时钟端此时正由1—>0,为下降沿,故其Q端状态不变,即Q=1,所以Q非端不变,易分析FDCE3,FDCE4Q端也保持不变,此为第三个状态0011。同理可分析得到剩余的十二个状态。

​ 通过上述分析过程可发现,FDCE1为受控Clk上升沿触发,FDCE2为受控FDCE1 Q非端上升沿触发,FDCE3为受控FDCE2 Q非端上升沿触发,FDCE4为受控FDCE3 Q非端上升沿触发。

​ 十六个状态表:

Counter[3]Counter[2]counter[1]counter[0]
零态0000
第1个Clk上升沿0001
第2个Clk上升沿0010
第3个Clk上升沿0011
第4个Clk上升沿0100
第5个Clk上升沿0101
第6个Clk上升沿0110
第7个Clk上升沿0111
第8个Clk上升沿1000
第9个Clk上升沿1001
第10个Clk上升沿1010
第11个Clk上升沿1011
第12个Clk上升沿1100
第13个Clk上升沿1101
第14个Clk上升沿1110
第15个Clk上升沿1111

2.Primitive描述

 FDCE #(
      .INIT(1'b0) 			// Initial value of register (1'b0 or 1'b1)
   ) FDCE_inst1 (
      .Q(Counter[0]),      	// 1-bit Data output
      .C(clk),      		// 1-bit Clock input
      .D(~Counter[0])       // 1-bit Data input
   );

 FDCE #(
      .INIT(1'b0) 			// Initial value of register (1'b0 or 1'b1)
   ) FDCE_inst2 (
      .Q(Counter[1]),      	// 1-bit Data output
      .C(~Counter[0]),      // 1-bit Clock input
      .D(~Counter[1])       // 1-bit Data input
   );

 FDCE #(
      .INIT(1'b0) 			// Initial value of register (1'b0 or 1'b1)
   ) FDCE_inst3 (
      .Q(Counter[2]),      	// 1-bit Data output
      .C(~Counter[1]),      // 1-bit Clock input
      .D(~Counter[2])       // 1-bit Data input
   );

 FDCE #(
      .INIT(1'b0) 			// Initial value of register (1'b0 or 1'b1)
   ) FDCE_inst4 (
      .Q(Counter[3]),      	// 1-bit Data output
      .C(~Counter[2]),      // 1-bit Clock input
      .D(~Counter[3])       // 1-bit Data input
   );

3.电路图

img

4.仿真结果

img

5.总结

BmbngX-1660895167350)]

4.仿真结果

[外链图片转存中…(img-MUm0cMcU-1660895167351)]

5.总结

​ 计数器设计并不难,但主要是弄明白其原理,并熟悉Primitive设计的基本方法,这种类IP核的设计方法简单且有效。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个完整的示例代码,演示如何使用 Cesium 的 Primitive 实现一个动态的河流。这个河流由多个小段组成,每个小段都是一个 PolylinePrimitive,通过改变每个小段的位置和纹理坐标,来实现河流的动态效果。代码如下: ```javascript var viewer = new Cesium.Viewer('cesiumContainer'); // 创建一个河道路径 var positions = [ Cesium.Cartesian3.fromDegrees(-100.0, 40.0), Cesium.Cartesian3.fromDegrees(-90.0, 40.0), Cesium.Cartesian3.fromDegrees(-80.0, 35.0), Cesium.Cartesian3.fromDegrees(-70.0, 30.0), Cesium.Cartesian3.fromDegrees(-60.0, 30.0), Cesium.Cartesian3.fromDegrees(-50.0, 35.0), Cesium.Cartesian3.fromDegrees(-40.0, 40.0) ]; // 创建一个 Material,表示水的外观 var material = new Cesium.WaterMaterial({ baseWaterColor: new Cesium.Color(0.0, 0.3, 0.8, 0.8), normalMap: './assets/images/waterNormals.jpg', frequency: 10000.0, animationSpeed: 0.01, amplitude: 10.0 }); // 创建一个 Primitive,表示河流 var river = new Cesium.Primitive({ geometryInstances : new Cesium.GeometryInstance({ geometry : new Cesium.PolylineGeometry({ positions : positions, width : 5.0 }), attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE) } }), appearance : new Cesium.PolylineMaterialAppearance({ material : material }) }); // 将河流添加到场景中 viewer.scene.primitives.add(river); // 创建一些小段,用来实现动态效果 var segmentCount = 100; var segmentLength = 1000.0; // 每个小段的长度 var segmentPositions = []; var segmentTextureCoords = []; for (var i = 0; i < segmentCount; i++) { // 计算当前小段的起点和终点 var start = positions[i]; var end = positions[i + 1]; var direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()), new Cesium.Cartesian3()); var length = Cesium.Cartesian3.distance(start, end); // 将当前小段分成若干个点 var pointCount = Math.ceil(length / segmentLength); var step = length / pointCount; for (var j = 0; j < pointCount; j++) { var t = j / (pointCount - 1); var position = Cesium.Cartesian3.add(start, Cesium.Cartesian3.multiplyByScalar(direction, j * step, new Cesium.Cartesian3()), new Cesium.Cartesian3()); segmentPositions.push(position); // 计算当前点的纹理坐标 var s = i / (segmentCount - 1); var v = j / (pointCount - 1); segmentTextureCoords.push(new Cesium.Cartesian2(s, v)); } } // 创建小段的 Geometry 和 Appearance var segmentGeometry = new Cesium.PolylineGeometry({ positions : segmentPositions, width : 5.0, vertexFormat : Cesium.VertexFormat.POSITION_AND_ST }); var segmentAppearance = new Cesium.PolylineMaterialAppearance({ material : material }); // 创建每个小段的 Primitive var segmentPrimitives = []; for (var i = 0; i < segmentCount - 1; i++) { var start = i * pointCount; var end = (i + 1) * pointCount - 1; var segmentInstance = new Cesium.GeometryInstance({ geometry : segmentGeometry, attributes : { st : new Cesium.GeometryInstanceAttribute({ componentDatatype : Cesium.ComponentDatatype.FLOAT, componentsPerAttribute : 2, values : Cesium.Cartesian2.packArray(segmentTextureCoords.slice(start, end)) }) } }); var segmentPrimitive = new Cesium.Primitive({ geometryInstances : segmentInstance, appearance : segmentAppearance }); segmentPrimitives.push(segmentPrimitive); } // 将每个小段的 Primitive 添加到场景中 for (var i = 0; i < segmentPrimitives.length; i++) { viewer.scene.primitives.add(segmentPrimitives[i]); } // 控制水流速度和方向的代码 var startTime = Cesium.JulianDate.now(); var speed = 0.01; var direction = new Cesium.Cartesian3(-1.0, 0.0, 0.0); viewer.clock.onTick.addEventListener(function(clock) { // 计算时间差 var time = Cesium.JulianDate.secondsDifference(clock.currentTime, startTime); // 设置 Material 的时间和流速 material.time = time; material.speed = speed; // 计算水流的方向 var rotation = Cesium.Matrix3.fromRotationZ(time * speed); var rotatedDirection = Cesium.Matrix3.multiplyByVector(rotation, direction, new Cesium.Cartesian3()); material.flowDirection = rotatedDirection; // 更新每个小段的纹理坐标 for (var i = 0; i < segmentPrimitives.length; i++) { var instance = segmentPrimitives[i].geometryInstances.get(0); var st = instance.attributes.st.values; var start = i * pointCount; var end = (i + 1) * pointCount - 1; for (var j = start; j <= end; j++) { var v = (j - start) / (pointCount - 1); st[j * 2 + 1] = st[j * 2 + 1] + speed * v; } instance.attributes.st.values = st; } }); ``` 上面的代码首先创建了一个河道路径,然后创建了一个 WaterMaterial 对象,表示水的外观。接着,将 PolylineGeometry 和 PolylineMaterialAppearance 对象作为参数,创建了一个 Primitive 对象,表示河流。最后,将这个 Primitive 添加到场景中。 接着,创建了一些小段,用来实现动态效果。首先计算每个小段的起点和终点,然后将每个小段分成若干个点,计算每个点的位置和纹理坐标。然后,分别创建每个小段的 Geometry 和 Appearance,用来表示小段的形状和外观。最后,将每个小段的 Geometry 和 Appearance 组合成一个 Primitive,表示一个小段,然后将所有的小段添加到场景中。 接着,使用 Cesium 的时钟对象来控制水流的速度和流向。在每一帧的时候,计算当前时间和开始时间的差值,然后将这个差值作为参数,设置 Material 的时间,就可以让水的纹理动起来了。同时,可以通过改变 Material 的 speed 属性,来控制水流的速度。最后,计算一个旋转矩阵,用来旋转水流的方向,然后将这个方向向量作为 Material 的 flowDirection 属性,就可以控制水流的流向了。同时,更新每个小段的纹理坐标,使得河流看起来是在动态变化的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值