摘要:记录用VHDL实现原码一位乘的过程,包括模块的分析以及给出端口定义,实体说明,因为比较简单,并未给出完整代码。另外,这篇文章在代码段的显示上有问题,好像识别不了代码段结束符,导致从第一段代码开始一直到文末我找不到原因,希望有大佬知道的告诉我一下。

  自己琢磨的过程还是比较难受的,虽然是一个简单的知识点,但VHDL是一回事,原码一位乘的原理是一回事,用VHDL实现原码一位乘又是一回事,但是毕竟是基础,理解整个过程对以后都有好处,二位乘也只是选择的条件和选择相加的对象改一下,整体小改即可,后续会加入博客中供参考,废话少说,下面开始。

一、原码一位乘原理:

  以8位相乘的过程为例,可能更好理解过程
  乘数是 Y:1001 0101(95)
  被乘数是 X:1111 0110(F6)
  相乘结果是(1000 1111 0010 1110)(8f2e)
  原码一位乘过程示意图

二、VHDL设计

  1. 移位寄存器设计
      先从简单的开始,可以看到表格右侧的操作是对乘数作右移操作,然后根据移出位作判断下一步是作+X还是+0,这里可以设置移位模块,由时钟驱动,输入为乘数,乘法开始后进行n-1次右移操作,输出为移出位。
    下面是实体部分
component SREG8B is
	port(clk	:	in STD_LOGIC;
		LOAD	:	in STD_LOGIC;
		DIN		:	in STD_LOGIC_VECTOR(7 downto 0);
		QB	 	:	OUT STD_LOGIC);
end component;
```  
2. 加法器  
  可以看到每次都有加法操作,加法操作实际上是部分积的高8位和乘数(这里是1111 0110)相加,结果存在新的部分积,进位存在新的部分积最高位。因此为了方便模块间交互,这里将加法器的输出设置为9位,第九位存放进位.  
  ![加法过程示意图](https://s.im5i.com/2021/05/21/SZXDo.png) 
下面是实体部分  
```VHDL  
component adder_8B is  
	port(a		:	in STD_LOGIC_VECTOR(7 downto 0);
			b		:	in STD_LOGIC_VECTOR(7 downto 0);
			cin	:	in STD_LOGIC;
			cout	:	out STD_LOGIC;
			sum	:	out STD_LOGIC_VECTOR(8 downto 0));
end component;  
```  
3. 选择器(得到被乘数)  
  前面也看到了,需要根据移位移出位来判断是+X还是+0,实际上移出位是0或者1,只需要将移出位和被除数相与即可得到本次操作的被乘数。  
下面是实体部分  

```VHDL
component ANDARITH is
	port(ABIN	:	in STD_LOGIC;
			DIN	:	in STD_LOGIC_VECTOR(7 downto 0);
			DOUT	:	out STD_LOGIC_VECTOR(7 downto 0));
end component;
```    

4. 16位移位寄存器  
  实际上很容易看出最后的结果,最低位是由D的部分移位来的,与A的部分没有关系(都被移出去了)。  
  再重新看这个图,分析结果的构成,发现,结果是由加法器的结果构成高9位,低7位是由上一次D+A(不包括A0)的(7 downto 1)构成的,这就很好实现了。   
  ![加法过程示意图](https://s.im5i.com/2021/05/21/SZXDo.png)  
下面是实体部分  


```VHDL
    component REG16B is
	port(clk	:	in STD_LOGIC;
	     CLR	:	in STD_LOGIC;
	     D		:	in STD_LOGIC_VECTOR(8 downto 0);
	     Q		:	out STD_LOGIC_VECTOR(15 downto 0));
    end component;
```  
5. 控制器  
  上面只是单个功能的分析和实现,都比较容易,那整体来看呢,移位模块不可能一直移位啊,选择器也不会一直工作,自然,就会想到用计数器控制整个乘法周期,8次操作一个周期,整个操作都完成了输出done信号,底下不需要一直工作的模块用控制器生成的时钟控制,乘法完成后,时钟置0,等待下一次乘法指令的开始信号到来,本次的乘法开始信号也可以作为下面16位寄存器的清零信号以及移位寄存器的输入使能。  
下面是实体部分   


```VHDL
    component ARICTL is
	port(clk	:	in STD_LOGIC;
	     START	:	in STD_LOGIC;
	     CLKOUT,RESTALL,DONE:OUT STD_LOGIC);
    end component;

仿真结果

  仿真结果