自制CPU需要什么

《CPU自制入门》

计算机系统基础

计算机系统的SoC(System-on-a-Chip,片上系统)以CPU为核心,同时实现了负责存储程序和数据的内存、负责和外部进行输入输出的I/O以及它们之间的连接总线。

PC(Personal Computer,个人电脑)

I/O(Input/Output,输入输出装置)进行数据交换

CPU如何运行

CPU①读取(Fetch)内存中的指令,然后对其要处理的操作进行②解码(Decode),最后进行③执行。

①读取

PC(Program Counter,程序计数器)寄存器,其中保存着即将执行的指令的地址。

将PC寄存器的值输出给内存,由内存返回该值对应地址中的指令。

②解码

指令由CPU中被称为指令解码器的模块进行解码。

通用寄存器(General Purpose Register)保存地址和运算结果

 ③执行

CPU可以从内部存储装置——寄存器或外部的内存读取数据并处理,

然后将结果写回寄存器或内存。

CPU执行的指令,由代表操作种类操作码和代表操作对象操作数(由寄存器地址、内存地址或立即数指定;立即数是指嵌入指令中的固定常数)两部分组成。

CPU分为RISC(Reduced Instruction Set Computer,精简指令集计算机)CISC(Complex Instruction Set Computer,复杂指令集计算机)两种。

RISC架构最大的特点是只使用载入和存储指令访问内存,这种架构称为载入存储架构(Load/Store Architecture)。

好处是可以简化指令集和流水线设计。

在这种架构下,运算指令只能对寄存器中的数据进行操作。

位宽

位宽/字(word):可以访问的地址空间或数据的大小;可以处理的整数型数据的宽度

eg.32位CPU可以处理32位的数据,可以访问的地址空间为4G字节(2的32次方)

内存:用来存放运行时指令(程序)和数据的存储器,有时也称为主存(Main memory)(和计算机中长期保存数据和程序存储器区别)

DRAM(Dynamic Random Access Memory,动态随机存储器)通过在电容器中积蓄电荷来保存数据的存储元件。电容器中充电状态是1,放电状态是0,并以此表示数值。

电容器中的电荷一段时间后会衰减,故DRAM需要定期进行重新写入数据的刷新(Refresh)操作。

内存使用地址(数据存储的位置)来管理存储的数据。

 字节编址:每个数据单元都有一个地址。大多情况下数据单元是一个字节(8位)长度。

存储器层级

“高速小容量”、“中速中等容量”到“低速大容量”等多种存储器组合的混合型架构。

存储层面,速度最快的是CPU中的寄存器。

CPU比内存速度快很多,由CPU直接访问内存效率较低。

为了提高内存访问速度,在CPU和内存间增加了被称为缓存的高速小容量存储器。

字节序

将多字节数据存储在内存中时,各字节的存储顺序。

人类更容易理解大端,计算机更适合处理小端

首先:数据一定是从内存的低地址依次向高地址读取和写入

大端是最前面的先排队上车,小端是从最后面的先排队上车

对应的是数据的高位从低地址开始存放,然后按顺序数据的低位存放下去

 很多处理器考虑到软件的通用性和可移植性,同时支持两种字节序并可依据程序切换,称为双端序

总线

CPU、内存和I/O之间交换数据的共同通道

总线一般由数据总线(传输交换的数据)、地址总线(指定访问的地址)和控制总线(负责总线访问的控制)构成。

总线协议:各个信号的时序、进行交换的规则。

总线传输:通过总线交换数据的整个过程。

总线的优点:

  1. 只要遵循总线协议,任何设备都可以简单地进行连接。
  2. 由于使用的是共享通道,硬件的成本也比较低。

缺点:数据传输的吞吐量较低。

数字电路基础

数字电路是利用两种不连续/离散的电位(电源电压H(High,高)电平、接地电压L(Low,低)电平分别代表1和0)来表示信息的电子电路。

基础:通过组合MOSFET(Metal-Oxide-Semiconductor Field-Effect Transistor,金属氧化物半导体场效应管)实现各种各样的逻辑电路。

MOSFET

MOSFET:一种在施加电压后可以像开关一样工作的半导体器件。

持有相反特性的N型MOSFET和P型MOSFET互补使用形成的门电路称为CMOS(Complementary Metal Oxide Semiconductor,互补金属氧化物半导体)。

CMOS可以用来制作各种各样的逻辑电路。

【进制】10(Dec)、2(Bin)、8(Oct)、16(Hex)

 十进制(decimal number):0到9的数值在一位中表示

二进制(binary number):从0到1的数值在一位数字中表示,遇2则向上进位;第n个数字位,数值上是2的n-1次方位

八进制(octal number):通常以0开头(区分于十进制),从0开始的八个数表达数值

十六进制(hexadecimal number):通常以0x开头(或末尾加H),以0到9加上A到F(10到15)表示十六个数值

 有符号二进制

补码表示法:N位的二进制数的最高位代表数值$-2^{N-1}$

无符号二进制数变成补码时,将所有比特反转(又称取反码)后加1。数字1表示为0001,-1表示为1111。(最高位为0时是正数,最高位为1时是负数)

 比特(bit, binary digit):二进制中的一个数字位,表示数据量的常用单位

字节(byte):一个字节代表8比特(2的8次方表达的范围0~255比较适合表达文字,如英文字母、符号、控制符等),大多数CPU处理数据的单位

字节编址方式:为每字节赋予一个内存地址

 1K=1024比特:衡量计算机内存和网络数据包大小

1K=1000:在硬盘等存储器的标签上记述的尺寸或物理学中使用

CMOS基本逻辑门电路

 

 

存储元件

锁存器(Latch):保存(像闩锁一样锁住并维持)数据的存储元件

1.简单锁存器

 2.D锁存器(Data Latch,D-Latch,数据锁存器)/通过型锁存器(E为1时输入的D直接通过Q输出)

D(Data)和E(Enable)

 3.依据时钟信号同步并保存数据的D触发器

D(Data)和C(Clock)

C为0时,前端D锁存器输出信号D的值,后端D锁存器保持之前的数据。

C为1时,前端D锁存器保持之前的数据,后端D锁存器将前端D锁存器保持的数据直接通过Q输出。

 

 建立时间与保持时间

建立时间(setup time):时钟变化前必须稳定输入信号的时间。

保持时间(hold time):时钟变化后必须稳定输入信号的时间。

 组合电路和时序电路

组合逻辑电路:输出值仅由输入信号的状态决定,不依赖于过去输入、不需要记忆维持(不含有存储元件)过去的输入信号的电路。

时序电路:输出值同时依赖于现在和过去输入信号(含有用于保持输入的存储元件)的逻辑电路。

同步时钟如何区别现在和过去

时钟同步设计中,有一种周期性地在H和L间变化的时钟信号,时钟变化边沿(上升沿或下降沿)之前被称为过去之后被称为现在

Verilog HDL语言

Verilog HDL是一种HDL语言(Hardware Description Language,硬件描述性语言)

可以进行抽象度较高的RTL(Register Transfer Level,寄存器传输级)电路设计

面积、时钟周期等约束参数

使用Verilog HDL进行硬件设计

逻辑综合:将RTL级别记述的抽象电路转换到门电路级别的电路网表的过程

(对ASIC(Application Specific Integrated Circuit)、FPGA(Field Programmable Gate Array)等不同电路实现技术,需要使用技术厂商提供的相应目标元件库)

模块(最基本构成单位):设计一个功能单位的逻辑

模块声明的语法

(1)在module关键字后记述该模块名

(2)<输入输出信号的定义>

①信号声明的关键字

输入信号的声明使用input关键字

输出信号的声明使用output关键字

双向信号的声明使用inout关键字

②描述

数据类型、信号线的位宽(方括号中记述最高位和最低位的位置,中间用冒号隔开)和信号名

比特数据的最高位被称为MSB(Most Significant Bit)

最低位称为LSB(Least Significant Bit)

输入输出信号的声明之后使用右圆括号加分号结束,如);

(3)<电路描述>模块内的电路逻辑

assign语句将in_0和in_1相加的结果输出到out

(4)endmodule关键字结束模块的定义

 eg.32位的加法器(in_0和in_1两个32位的输入信号,相加的结果从32位的out信号输出)

加法器框图

 加法器程序

 【注】

1.自由格式语言:可在任意地方加入换行、空格以及Tab等空白符号

2.区分大小写:大小写的英文字符分别表示不同的含义

3.有效标识符(用来命名变量和模块):英文字母(a~z, A~Z)、数字(0~9)、下划线(_)和美元符号($)

4.自定义的标识符必须以英文字母下划线开头

5.注释: /*和 */之间,或从//开始到一行末尾

6.块:begin和end之间的部分

模块实例化

其他模块调用设计好的模块

模块的实例化

逻辑值与常数表达 

 

 变量的声明与数据类型

 数据类型

(1)寄存器型:可以保存上次写入数据的数据类型,根据程序不同可以生成锁存器、触发器等存储元件,也可能生成组合电路

 寄存器型变量可以在always和initial语句中实现过程赋值(Procedural Assignment)

(一个过程块只能二选一)

①阻塞式赋值:按照代码顺序进行赋值(先赋值的代码赋值完成之前阻塞后续代码的赋值);用=运算符

②非阻塞式赋值:所有代码不会互相阻塞,同时进行赋值;用<=运算符

(2)网络型:用来描述模块和寄存器间连接的数据类型,只描述信号的传输不持有数据

网络型变量可在assign语句或声明语句中实现连续赋值(Continuous Assignment)

 assign语句中连续赋值

 声明语句中连续赋值

signed和unsigned关键字指定变量符号

无符号数转换为有符号数时使用$signed(),有符号数转换为无符号数时使用$unsigned()

 【注】定义默认网络类型,可不用声明直接使用;可在大量使用网络型变量的网表程序中减少代码量。但由于失误而未声明类型的信号会被自动处理为默认网络类型,编译器无法检测错误,故推荐将默认网络类型设置为无效。

运算符

 

 缩减运算符:对信号的所有位进行位运算,最终输出1位的运算结果

 

 使用拼接运算符

①组合比特序列

②重复比特序列

条件分支语句if与case

可以在initial或always语句声明的过程块中使用

 

循环语句for与while

可以在initial或always语句声明的过程块中使用

 

 always过程块

 ①指定事件表达式

所指定的事件触发时执行其中的语句序列

事件:特定信号的变化、信号的上升沿(posedge)、信号的下降沿(negedge)等

②指定常数表达式(仿真时常用)

在每经过该常数时间便执行一次always中的语句序列

用always语句描述组合电路

 定义了一个adder模块,它有两个32位wire型输入in_0和in_1、一个32位reg型输出。always中将两个输入相加后赋值给输出。阻塞式赋值。

【注】

1.一定要将case语句的条件写全,或者使用default来确定默认值

2.使用if语句时一定要写else条件,或者在if语句前为变量值赋予默认值

否则虽然设计的是组合电路,但会产生本不应有的存储元件,从而变成时序电路。

 Don't care指示方法:在default中为输出赋予不定值,输出为逻辑综合时优化的数值

用always描述时序电路

定义了一个叫做ff的模块,它有clk、reset_、d_in三个一位wire型输入信号,和一位reg型输出信号d_out

d_out在clk的上升沿同步动作,将d_in的值储存。并且d_out在reset_的下降沿被异步地复位,初始化为0。

基本上都是按照时钟同步执行,事件表达式中要指定时钟的信号边沿(确定在时钟信号上升时触发电路动作,或者在时钟信号下降时触发电路动作)和时钟信号名

上升时动作记述为posedge,下降时动作记述为negedge

事件表达式:可以使用or列举多个条件

预处理

代码编译前对其进行预先处理

例子程序 

32组位宽为32的寄存器堆。

读取操作:将地址信号(addr)指定的寄存器的内容,通过多路选择器选择,输出到输出信号(d_out)。

写入操作:当写入使能信号(we_)有效时,向地址信号(addr)指定的寄存器写入输入数据(d_in)。

寄存器堆模块在regfile.v文件中实现;regfile.v引用了regfile.h头文件。

regfile.h头文件

`ifndef __REGFILE_HEADER__ // 包含文件防范 `define __REGFILE_HEADER__ /********** 信号电平 *********/ `define HIGH 1'b1 // 高电平 `define LOW 1'b0 // 低电平 /********** 逻辑值 *********/ `define ENABLE_ 1'b0 // 有效(负逻辑) `define DISABLE_ 1'b1 // 无效(负逻辑) /********** 数据 *********/ `define DATA_W 32 // 数据宽度 `define DataBus 31:0 // 数据总线 `define DATA_D 32 // 数据深度 /********** 地址 *********/ `define ADDR_W 5 // 地址宽度 `define AddrBus 4:0 // 地址总线 `endif

regfile.v

正逻辑、负逻辑与信号状态

正逻辑:高电平有效、低电平无效的分配方式。

负逻辑:高电平无效、低电平有效的分配。

assert(断言):控制信号转为有效状态的动作

negate(无效):转为无效状态的动作

enable(使能):信号有效

disable(非使能):信号无效

Testbench:记述仿真程序的文件

 Testbench没有输入输出信号,调用被测模块,传递输入信号并观测输出。

系统蓝图

字编址与字节位移

CPU一次处理宽度大于一个字节的数据。

字:CPU能处理的数据宽度

字编址:为每一个字宽的数据赋予一个地址的方式

总线的设计与实现

总线协议:使用信号线的通信规则。

通过总线访问时,需要预先确定总线主控与总线从属之间的通信规则。

总线访问过程

①读取访问

[Ⅰ]请求总线使用权

[Ⅱ]取得总线使用权

[Ⅲ]总线访问开始

[Ⅳ]来自总线从属的应答

[Ⅴ]总线访问结束并释放总线使用权

②写入访问

[Ⅰ]请求总线使用权

[Ⅱ]取得总线使用权

[Ⅲ]总线访问开始

[Ⅳ]来自总线从属的应答

[Ⅴ]总线访问结束并释放总线使用权

总线的实现

1.总线仲裁器的实现

接受总线主控发来的总线使用请求,并将使用权赋予合适的总线主控。

总线仲裁器的状态转移图

 

 

 

2.总线主控多路复用器的实现

基于总线仲裁器输出的总线赋予信号,选择总线使用权所有者的信号,并将其输出到总线。

 

3.地址解码器的实现

基于总线主控输出的地址信号,判断将要访问哪个总线从属,并生成片选信号。

地址映射(address map):访问的地址与总线从属的对应关系

 

4.线从属多路复用器的实现

基于地址解码器输出的片选信号,将被选择的总线从属的输出信号发送到总线。

 

5.总线的顶层模块

将总线仲裁器、总线主控多路复用器、地址解码器以及总线从属多路复用器4个模块进行连接的模块。

存储器的设计与实现

制作存储器用到了FPGA的RAM区域。可以作为子模块,以实例化的方式使用!

Dual Port RAM的访问时序图

 [Ⅰ]存储器的实例化

块RAM的实例化。

[Ⅱ]异步复位

复位信号有效时,将就绪信号初始化。

[Ⅲ]生成就绪信号

片选信号与地址选通信号同时有效时,因为即将访问总线,就绪信号变为有效。其他情况时,就绪信号设置为无效。

AZ Processor的设计与实现

CPU

流水线处理:一种提高CPU的处理性能的技术;将处理操作分为多个阶段,然后像流水线作业一样执行。

CPU中的各种硬件资源,只在处理的相应阶段使用,其他时间大多处于空闲状态。

读取某条指令之后,在该指令解码的同时读取下一条指令。

通过使各个阶段的动作重叠,让硬件资源有效使用,同时提高处理速度。

各个流水线级的处理时间应该尽量相等。

【典型的5级流水线】体系结构 | 五段流水线 | 流水线技术_stone_fall的博客-CSDN博客

  • IF(Instruction Fetch)阶段:将PC的值发送到内存,读取指令。
  • ID(Instruction Decode)阶段:将读取的指令解码并决定将要进行的操作,从寄存器堆读取数据。
  • EX(Execution)阶段:使用运算器执行操作。可以执行算术运算和逻辑运算的运算器称为ALU(Arithmetic and Logic Unit)。
  • MEM(Memory Access)阶段:进行内存访问
  • WB(Write Back)阶段:将结果写回寄存器堆

实现了流水线化的CPU,将5个流水线级的操作重叠使用!!!

 

冒险

流水线故障(无法执行操作)的原因

CPU模式

  1. 内核模式(Kernel Mode)或管理者模式(Supervisor Mode):全部指令可以无限制执行的模式;操作系统等系统软件需要的
  2. 用户模式(User Mode):可执行的指令被限制的模式;应用软件通常工作的。(被限制的操作包括CPU控制寄存器的访问改变CPU状态的指令等)

更改CPU模式

  1. 高权限的内核模式转换到低权限的用户模式时,可通过操作控制寄存器实现。
  2. 低权限的用户模式转换到高权限的内核模式,需使用专用的指令

中断

让CPU暂停正在执行的操作,跳转到中断处理程序执行其他操作的功能,会变更到内核模式。中断处理完成后返回到中断处继续执行。

常用在通知来自I/O的事件、处理程序执行中的异步事件等。

外部因素引起的与正在执行的操作的异步情况。

异常

CPU的执行产生了预期之外(无法解码的指令、运算结果溢出以及操作违反权限等)的结果。 

暂时中断当前程序,跳转到异常处理程序,变更到内核模式。异常处理完成后,原则上将返回异常中断处,但如果发生致命错误会强制中止执行的程序。

在正在执行的操作的内部发生的。

 中断和异常的处理本质上是一致的。

CPI(Clock cycle Per Instruction):平均一条指令所需的时钟周期。(知道了程序行数和CPI,即可计算出程序执行所需要的时钟周期数。)

SPM(Scratch Pad Memory):CPU可不经过总线直接访问的专用内存。

I/O的设计与实现

最基本的I/O

  1. 测量时间用的定时器
  2. 串口通信规范UART(Universal Asynchronous Receiver Transmitter)
  3. 控制LED、开关用的GPIO(General Purpose Input Output)

定时器

用来测量时间的装置。计算机利用定时器实现时间测量、周期性处理、超时判断等许多用途。

两种动作模式

  1. 单次定时模式:经过设定时间后向CPU请求一次中断即完成操作,只进行一次时间测量时使用。
  2. 循环定时模式:每经过设定时间就向CPU请求一次中断,在需要执行周期性操作时使用。

 

UART

起止式同步接收、发送串口通信装置。

使用收、发两根信号线进行串口通信(数据一位接一位地传输)的标准。

 起止式同步通信:在发送的数据前添加表示通信开始的起始位(L)、在数据末尾添加表示通信结束的停止位(H)。空闲时总是输出停止位。

从LSB一端开始按顺序输出,并可以选择添加奇偶校验位,最后输出停止位。数据传输单位为7位或8位。

通信速率:用波特率(baud rate)表示。

波特率指的是信号被调制以后的变化率,即单位时间内载波(数据位、起始位、停止位、奇偶校验位)变化的次数。

常用的波特率:9600 baud、19200 baud、38400baud等。

RS-232(Recommended Standard 232)(DE-9接头)或串口:UART标准的实现;连接调制解调器等计算机周边设备;作为控制台接口。

GPIO

以位为单位进行数字输入输出的I/O接口。

输入时从外部读取输入信号、输出时将写入的值输入到外部。

控制寄存器

 输入输出方向(INOUT_DIR)该寄存器用来设置输入输出端口的信号方向。当寄存器值为0时端口为输入、值为1时端口为输出。该寄存器各个比特对应控制相应的输入输出端口。

GPIO框图

 输入输出端口使用三态门实现。

三态门(也称为三态缓冲器)是一种可以输出H、L以及高阻(电气上绝缘/断路)状态的电路结构。

AZPR SoC整体连接

各模块的连接

CPU、ROM、定时器、UART、GPIO,以及连接这些模块的总线的连接

时钟模块的实现

提供3种信号:时钟信号(clk)、反相时钟信号(clk_)、与异步复位信号(reset)。

对主时钟信号分频、倍频、移相,从而提供用户电路所需要的时钟信号。

DCM的输入为时钟信号(CLKIN_IN)和异步复位信号(RST_IN),输出为生成的时钟信号(CLK0_OUT, CLK180_OUT)和锁频信号(LOCKED_OUT)。

复位无效时,DCM将输入时钟信号进行处理,生成用户需要的时钟信号。生成的时钟稳定后将锁频信号变为有效。

DCM锁存和复位

顶层模块的实现

芯片与时钟模块连接

AZPR SoC的仿真

 对整个系统进行仿真时,需要准备FPGA中使用的DCM和内存模型。

DCM模型

配置的DCM将依据输入的时钟,输出频率相同但相位为0度和180度的两种时钟。

Single Port ROM是只有一个读取端口的专用存储器。

Dual Port RAM是具有两个可以同时读写端口的存储器。

Testbench的编写

向被测电路输入时钟和复位信号,推进仿真周期。

使用Icarus Verilog软件和做好的Testbench对系统进行仿真。

posted @ 2023-02-05 10:14  asandstar  阅读(239)  评论(0编辑  收藏  举报