除法器(除法算法)是一类算法。给定两个整数 N(分子)和 D(分母),计算它们的商和(或)余数。其中某些算法可以通过人工手动计算,而另一些则需要依赖数字电路的设计或软件。[1] 除法算法主要分为两类:慢除法快除法。慢除法在每次迭代的过程中给出结果(商)的一位数字。慢除法包括复原法(restoring)、非复原法(non-restoring)和SRT除法等。快除法从商的一个近似估计开始,并且在每次迭代过程中产生有效位数为最终商的两倍多的中间值。Newton-Raphson和GoldSchmidt属于这一类。-----维基百科

本文所讲的除法器主要针对正整数的除法运算,使用的是慢除法的设计思想。

上篇博客中提到乘法器是被乘数左移相加,而除法器刚好相反,是被除数左移相减。

一、实现思想

除法器实现思想:假设被除数data_a[3:0]=‘b0101,除数data_b[1:0]='b11,

要想实现data_a[3:0]÷data_b[1:0] = result[3:0]......remainder[3:0],需要以下步骤:

1、定义两个寄存器变量result[3:0]和remainder[3:0];

2、每个时钟周期将data_a[3:0]向左移移位,移出的那一位送到remainder的最低位,即remainder <= {remainder[2:0],移出的那一位};

3、比较移位后的remainder[3:0]与data_b[1:0]的大小,若remainder[3:0]>=data_b[1:0],则remainder[3:0]-data_b[1:0],同时result最低左移入1;若remainder[3:0]<=data_b[1:0],则remainder[3:0保持不变,同时result最低位左移入0;

4、判断data_a[3:0]移位完成,若未完成,重复步骤2-3,反之输出完成标志信号。

二、对应的算法状态机

按照上述除法器的实现思想,可以画出除法器的实现流程,如下所示:

图1 算法状态机

图1中算法状态机描述了除法器的实现思想,接下来就可以根据算法状态机来画实现该电路的数据路径。

三、数据路径

图2 数据路径

数据路径如图2所示,左移寄存器data_a在每个时钟周期将移出的数据data_bit0送给remainder移位寄存器的最低位,移位后的数据跟data_b相减是在en_c信号控制下进行的,同时result移位寄存器最低位移入0还是1也是由en_c决定的。这些信号何时有效在接下来的控制信号的流程图中都可以明确的给出。

四、控制信号

图3 控制信号

根据图1和图2确定了使能信号在哪个状态应该使能,其中flag信号是移位完成标志信号。其余信号分别是寄存器和加法器的使能信号和加载信号,对比图2可以理清这些信号的功能。

五、verilog描述

接下来使用verilog描述上述数据路径,代码如下:

顶层代码:

module divider(input clk,input rst,input start,input load_a,input load_b,input [3:0]data_a,input [1:0]data_b,output [3:0]result,output [3:0]remainder,output reg done);
wire flag;
reg en_a;
reg en_b;
reg en_c;
reg load_c;
wire valid;
//wire [3:0]remainder;
parameter s0 = 'b001;
parameter s1 = 'b010;
parameter s2 = 'b100;
reg [2:0]current_state = 'd0;
reg [2:0]next_state = 'd0;
reg en_o = 'd0;///结果移位使能信号///次态向现态转移
always @(posedge clk)if(!rst)current_state <= s0;elsecurrent_state <= next_state;
///次态生成
always@(*)case(current_state)s0:   beginif(start)next_state <= s1;elsenext_state <= s0;ends1:  beginif(flag)   next_state <= s2;elsenext_state <= s1;ends2:    beginif(!start)next_state <= s0;elsenext_state <= s2;enddefault:next_state <= s0;endcase
///输出结果赋值
always@(*)case(current_state)s0:   beginload_c = 'd1;en_a = 'd0;en_b = 'd0;en_c = 'd0;done = 'd0;en_o = 'd0;ends1: beginen_o = 'd1;load_c = 'd0;en_a = 'd1;en_b = 'd1; done = 'd0;if(valid&&(data_b!=0))    beginen_c = 'd1;endelse   beginen_c = 'd0;              endends2:   beginload_c = 'd0;en_a = 'd0;en_b = 'd0;  en_c = 'd0;   done = 'd1;   en_o = 'd0;               enddefault: beginload_c = 'd1;en_a = 'd0;en_b = 'd0;  en_c = 'd0;   done = 'd0;   en_o = 'd0;                   endendcase
wire data_bit0;
wire enb_control;
// Instantiate the module
left_shifter left_shifter (.clk(clk), .en_a(en_a), .load_a(load_a), .data_a(data_a), .flag(flag),///移位完成标志位.enb_control(enb_control),.data_bit0(data_bit0));
// Instantiate the module
left_shifter_se left_shifter_se (.clk(clk), .en_b(en_b), .en_c(en_c), .load_b(load_b), .data_bit0(data_bit0), .data_b(data_b), .valid(valid),.remainder(remainder),.enb_control(enb_control));
// Instantiate the module
result_1 result_1 (.clk(clk), .load_c(load_c),.en_c(en_c), .en_o(en_o),.result(result));
endmodule

data_a左移寄存器代码:

module left_shifter(input clk,input en_a,input load_a,input [3:0]data_a,output flag,output data_bit0,output enb_control);
reg [3:0]data = 'd0;
always @(posedge clk)if(load_a)    begindata <= data_a;endelse if(en_a)    begindata <= {data[2:0],1'b0};endelse  begindata <= data;end
assign data_bit0 = data[3];
reg [2:0]count = 'd0;
always @(posedge clk)if(load_a)count <= 'd0;else if(en_a)count <= count + 'd1;elsecount <= count;
assign flag = (count=='d4)?'d1:'d0;
assign enb_control = (count=='d4)?'d0:'d1;endmodule

remainder左移寄存器及加法器代码:

module left_shifter_se(input clk,input en_b,//控制以为寄存器使能input en_c,//控制余数和被除数相减的减法器使能input load_b,input data_bit0,input [1:0]data_b,//被除数output reg valid = 'd0,output reg [3:0]remainder,input enb_control);
reg [3:0]remainder_1 = 'd0;always @(posedge clk)if(load_b)   remainder <= 'd0;else if(en_b&enb_control) remainder <= {remainder_1[2:0],data_bit0};else  remainder <= remainder_1;always @(*)if(load_b)remainder_1 = 'd0;else if(en_c)remainder_1 = remainder + (~data_b+1);elseremainder_1 = remainder;always @(*)if(remainder >= data_b)valid = 'd1;elsevalid = 'd0;endmodule

result左移寄存器代码:

module result_1(input clk,input en_c,input load_c,input en_o,output reg[3:0]result = 'd0);
always @(posedge clk)if(load_c)result <= 'd0;else if(en_o)    beginif(en_c)result <= {result[2:0],1'b1};elseresult <= {result[2:0],1'b0};endelseresult <= result;
endmodule

仿真文件代码:

module test;// Inputsreg clk;reg rst;reg start;reg load_a;reg load_b;reg [3:0] data_a;reg [1:0] data_b;// Outputswire [3:0] result;wire [3:0]remainder;wire done;// Instantiate the Unit Under Test (UUT)divider uut (.clk(clk), .rst(rst), .start(start), .load_a(load_a), .load_b(load_b), .data_a(data_a), .data_b(data_b), .result(result), .remainder(remainder),.done(done));initial begin// Initialize Inputsclk = 0;rst = 0;start = 0;load_a = 0;load_b = 0;data_a = 0;data_b = 0;// Wait 100 ns for global reset to finish#100;// Add stimulus hereendalways #5 clk = ~clk;reg[4:0] cnt = 'd0;always @(posedge clk)if(cnt == 'd30)cnt <= 'd30;elsecnt <= cnt + 'd1;///复位信号always @(posedge clk)if(cnt <= 'd2)rst <= 'd0;elserst <= 'd1;//加载信号和数据always @(posedge clk)if((cnt> 'd2)&&(cnt < 'd5))  beginload_a <= 'd1;load_b <= 'd1;data_a <= 'd5;data_b <= 'd3;endelse    beginload_a <= 'd0;load_b <= 'd0;data_a <= 'd0;data_b <= data_b;end///start信号always @(posedge clk)if((cnt> 'd8)&&(cnt < 'd25))start <= 'd1;elsestart <= 'd0;
endmodule

Isim行为仿真结果:

图4 仿真波形

由仿真结果可知,在done信号拉高时,输出正确的除法结果。本实例中:data_a = 5,data_b=3;5 ÷ 3 = 1...2 。

读书笔记:数字逻辑基础与verilog设计之数字系统设计流程03----------二进制除法器电路设计相关推荐

  1. 数字逻辑基础与verilog设计_数字电路学习笔记(五):逻辑设计基础

    马上就要正式进入电路设计了,再来看最后一个知识点:逻辑设计吧. 之前我们花了两章,探讨了逻辑运算是什么,怎么算:但还有最后一个大问题,巧妇难为无米之炊,我们得先有一个逻辑式,才能对它化简,并基于结果做 ...

  2. 【《Redis深度历险》读书笔记(1)】基础:万丈高楼平地起 ——Redis 5种基础数据结构

    [时间]2021.11.16 [题目][<Redis深度历险>读书笔记(1)]基础:万丈高楼平地起 --Redis 基础数据结构 本栏目是<Redis深度历险:核心原理和应用实践&g ...

  3. java猜数字游戏总结,java课程设计——猜数字游戏

    java课程设计--猜数字游戏 目目 录录 前言. 1 正文. 1 1 1.设计任务与要求.设计任务与要求 1 1.1 1.1 设计任务与要求设计任务与要求 1 1.2 1.2 选题目的与意义选题目的 ...

  4. 01笔记 数字逻辑基础——逻辑代数基础——基于《数字逻辑基础》陈光梦(第三版)

    一些概念 集成电路分类 ①模拟集成电路,处理连续信号 ②数字集成电路,处理离散信号 数字集成电路分类 逻辑集成电路 储存器 ASIC(Application Specific IC) 特点 信号表示形 ...

  5. 【读书笔记】语言基础- Lua语言入门(一)

    目录 注:本系列为<Lua程序设计-第4版> 的读书笔记,其中的见解有不完善的地方,可以在评论区指出,原版请看图书 Lua运行环境 一. 使用Lua语言解释器运行Lua语言:(下面的实例以 ...

  6. 读书笔记(06) - 语法基础 - JavaScript高级程序设计

    写在开头 本篇是小红书笔记的第六篇,也许你会奇怪第六篇笔记才写语法基础,笔者是不是穿越了. 答案当然是没有,笔者在此分享自己的阅读心得,不少人翻书都是从头开始,结果永远就只在前几章. 对此,笔者换了随 ...

  7. 数字芯片设计流程之verilog设计

    数字芯片设计流程: 功能验证之前与工艺库没多大联系,验证芯片设计的功能是否正确,针对抽象的代码进行功能验证理想值. 一致性验证确保生成的网表和代码设计功能一致:DFT之后是数字后端. 静态时序分析,从 ...

  8. [读书笔记]大型分布式网站架构设计与实践.分布式缓存

    前言:本书是对分布式系统架构涉及到的相关技术的一本科普书籍.由于很难作为开发参考,只能但求了解.所以通篇浅读,对分布式系统进行大致的了解.因为写的非常好,感觉非常有意思,自己也做不出总结.所谓的读书笔 ...

  9. c++矩阵转置_lt;读书笔记4gt; 稀疏矩阵基础算法

    本篇为稀疏矩阵求解算法经典论著<Direct Methods for Sparse Linear System>的<读书笔记 4> Chapter 2 Basic algori ...

最新文章

  1. Python 之 matplotlib (五)Annotation注解
  2. java链式栈_Java栈之链式栈存储结构实现
  3. java.util.logging.Logger基础教程
  4. 【BZOJ 3098】 Hash Killer II
  5. JeecgUniapp移动框架 2.0版本发布,一份代码多终端适配
  6. 根据div 标签 查看数组@class=modulwrap 下面的/table/tbody/tr/td
  7. 【PL/SQL】开发程序
  8. Uva 12657 Boxes in a Line 双向链表
  9. who I am ?
  10. 一块移动硬盘怎样兼容Mac和Windows系统,并且可以在time machine上使用
  11. 清华大学操作系统OS学习(九)——页面置环算法:最优算法、先进先出算法(FIFO)、最近最久未使用算法(LRU)、 CLOCK法、最不常用算法(LFU) 、工作集置换算法、缺页率置环算法
  12. 没有别的厂家生产薯片?
  13. C盘总是满了,不想重装系统,不想扩充,C盘瘦身彻底解决
  14. typora插入文件到服务器,写作神器Typora入门指南
  15. Java实现 LeetCode 69 x的平方根
  16. 什么是 博弈论?博弈论的研究解决了什么问题?
  17. BP神经网络简单应用实例,bp神经网络应用举例
  18. Python - PyMuPDF (fitz) 处理 PDF
  19. html5 svg defs,defs_分类 | Elements_SVG_参考手册_非常教程
  20. 【经典】《Java170道面试笔试题全面含答案》涉及java/数据库/Spring框架/JVM/数据结构算法/设计模式相关

热门文章

  1. c++ 三次多项式拟合_最小二乘法多项式曲线拟合数学原理及其C++实现
  2. 从黑电到白电,创维如何“做时间的朋友”
  3. Android 每次插入U盘自动创建了不需要的文件夹
  4. CodeCraft-20 (Div. 2)B.String Modification
  5. 基于遗传算法(GA)的计算卸载策略的求解(二)
  6. 老默我想吃鱼了(抽象艺术)
  7. 你不知道的开源操作系统汇总
  8. golang安装详解
  9. 图解2017双十一背后的阿里云技术
  10. 【知识点整理】反馈神经网络