首页 > 其他分享 >8 位 RISC 模型机 状态机控制 ALU双端口

8 位 RISC 模型机 状态机控制 ALU双端口

时间:2024-10-24 18:21:03浏览次数:10  
标签:LD RIGHT RISC 状态机 PC 指令 寄存器 ALU LEFT

8 位 RISC 模型机 状态机控制 双端口

项目地址:8 位 RISC 模型机 状态机控制 双端口

从 8 位寄存器(D 触发器)开始

  • D D D:8 位输入
  • Q Q Q:8 位输出
  • 功能 功能 功能:上升沿时,将 D 输出给 Q,并保持
library ieee;
use ieee.std_logic_1164.all;

entity DFF_8 is
port(clk:in std_logic;
		  D:in std_logic_vector(7 downto 0);
		  Q:out std_logic_vector(7 downto 0)
		);
end entity;

architecture bhv of DFF_8 is
SIGNAL Q1 : std_logic_vector(7 downto 0) ;
begin
	process(clk,Q1)
	begin
		if clk'event and clk='1' then
			Q1<=D;
		end if;
	end process;
	Q<=Q1;
end bhv;

寄存器堆

双端口 双端口 双端口:
左入(从 ALU 来) 和 右入(从 CPU 内总线来);
左出(到 ALU 的 A 端口寄存器去) 和 右出(到总线去)
在这里插入图片描述

  1. 三个寄存器
    在这里插入图片描述

  2. 左入端口 和 右入端口

    • L E F T _ I N LEFT\_IN LEFT_IN:左入数据
    • L D _ L E F T LD\_LEFT LD_LEFT:左入选择写哪一个寄存器
    • R I G H T _ I N RIGHT\_IN RIGHT_IN:右入数据
    • L D _ R I G H T LD\_RIGHT LD_RIGHT:右入选择写哪一个寄存器
      在这里插入图片描述
  3. 实现:VHBL 语言 实现寄存器堆根据 L D _ L E F T LD\_LEFT LD_LEFT选择输入左入,根据 L D _ R I G H T LD\_RIGHT LD_RIGHT选择输入右入
    输入

    • L E F T _ I N LEFT\_IN LEFT_IN:左入数据
    • L D _ L E F T LD\_LEFT LD_LEFT:左入选择
    • R I G H T _ I N RIGHT\_IN RIGHT_IN:右入数据
    • L D _ R I G H T LD\_RIGHT LD_RIGHT:右入选择

    输出

    • LD_R0, LD_R1, LD_R2: 3 个寄存器的选择
    • D_R0, D_R1, D_R2: 3 个寄存器的写入数据
library ieee;
use ieee.std_logic_1164.all;

entity IN_SEL is
port(
    LEFT_IN: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    LD_LEFT: IN STD_LOGIC_VECTOR(1 DOWNTO 0);
    RIGHT_IN: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    LD_RIGHT: IN STD_LOGIC_VECTOR(1 DOWNTO 0);
    LD_R0, LD_R1, LD_R2: OUT STD_LOGIC;
    D_R0, D_R1, D_R2: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
	);
end entity;

architecture bhv of IN_SEL is
begin
	process(LD_LEFT, LD_RIGHT, LEFT_IN, RIGHT_IN)
	begin
        -- R0
        IF(LD_LEFT = "00") THEN
            D_R0 <= LEFT_IN;
        END IF;
        IF(LD_RIGHT = "00") THEN
            D_R0 <= RIGHT_IN;
        END IF;

        -- R1
        IF(LD_LEFT = "01") THEN
            D_R1 <= LEFT_IN;
        END IF;
        IF(LD_RIGHT = "01") THEN
            D_R1 <= RIGHT_IN;
        END IF;

        -- R2
        IF(LD_LEFT = "10") THEN
            D_R2 <= LEFT_IN;
        END IF;
        IF(LD_RIGHT = "10") THEN
            D_R2 <= RIGHT_IN;
        END IF;

        IF(LD_LEFT = "00" OR LD_RIGHT = "00") THEN
            LD_R0 <= '1';
        ELSE
            LD_R0 <= '0';
        END IF;
        IF(LD_LEFT = "01" OR LD_RIGHT = "01") THEN
            LD_R1 <= '1';
        ELSE
            LD_R1 <= '0';
        END IF;
        IF(LD_LEFT = "10" OR LD_RIGHT = "10") THEN
            LD_R2 <= '1';
        ELSE
            LD_R2 <= '0';
        END IF;

	end process;
end bhv;

在这里插入图片描述

  1. 或者 使用 选择器、与非门等硬件 实现:实现寄存器堆根据 L D _ L E F T LD\_LEFT LD_LEFT选择输入左入,根据 L D _ R I G H T LD\_RIGHT LD_RIGHT选择输入右入

    实现方式:
    先用 24 译码器 lpm_decode 译码两个选择信号 LD
    将对应寄存器的选择信号相 接入寄存器
    用数据选择器,使用对应的 LD_LEFT 选择 RIGHT_IN[7…0]LEFT_IN[7…0],使对应数据输入到寄存器

在这里插入图片描述

  1. 实现根据 SEL_LEFT[1…0]SEL_RIGHT[1…0] 选择左出和右出

    SEL_LEFT[1…0]SEL_RIGHT[1…0] 为 11 11 11 时,不选择任何输出,可以用与非门接到三态门上,使用 SEL 信号控制三态门,节省两个 BUS 控制信号

  • 使用 VHDL 实现左入和右入原理图为 REG1:
    在这里插入图片描述

    仿真:验证左入和右入,左出和右出
    都正确
    请添加图片描述

  • 使用硬件实现实现左入和右入原理图为 REG2:
    在这里插入图片描述
    仿真验证正确

在这里插入图片描述

ALU 设计

双端口:
A 端口数据寄存器 DR0 从 寄存器堆 REG 的 左出端口 LEFT_OUT 读数据
B 端口数据寄存器 DR1 从 总线读数据
ALU 运算结果 直接存入寄存器堆,不经过总线
在这里插入图片描述

ALU181

根据你们的指令集,这里只有加法,减法,左移 1 位,共三种运算
输入:

  • A:A 端口数据
  • B:B 端口数据
  • S:运算类型,00 表示不做运算,01 为 ADD,10 为 SUB,11 为 SLL
    输出:
  • F:运算结果
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY ALU181 IS
PORT (
    A,B  : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);
    S  : IN  STD_LOGIC_VECTOR(1 DOWNTO 0 );
    F  : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
  );
END ALU181;
ARCHITECTURE behav OF ALU181 IS
SIGNAL A9,B9,F9 : STD_LOGIC_VECTOR(8 DOWNTO 0);
BEGIN
A9 <= '0' & A ;  B9 <= '0' & B ;
PROCESS(A9,B9)
BEGIN
CASE S  IS
		WHEN "00" => NULL;
        -- ADD
		WHEN "01" => F9<= A9 + B9;
        -- SUB
		WHEN "10" => F9<= A9 - B9;
        -- SLL
        WHEN "11" => F9(7 DOWNTO 0)<= A9(6 DOWNTO 0) & "0";
		WHEN OTHERS  =>F9<= "000000000" ;
END CASE;
END PROCESS;
    F<= F9(7 DOWNTO 0);
END behav;

仿真验证正确

在这里插入图片描述

ALU 部件设计

  • IN_A:A 端口输入数据,从寄存器堆左出 LEFT_OUT
  • IN_B:B 端口输入数据,从 总线
  • ALU_OUT:运算器计算结果,输出到寄存器堆 LEFT_IN
    在这里插入图片描述

仿真验证正确
在这里插入图片描述

PC 程序计数器

  • lpm_counter:PC 计数器
  • LD_PC、INC_PC、D[7…0]:当 LD_PC 和 INC_PC 为 1 时,将 D[7…0]写入 PC,用于 JMP 跳转指令
  • CLR_PC:清零 PC,置 PC=0
  • PC_B:允许 PC 输出到总线上
    在这里插入图片描述

仿真验证
在这里插入图片描述

STEP 时序发生器

在这里插入图片描述

RAM 内存设计

  • AR_CLK:地址寄存器 AR 时序输入
  • RAM_CLK:读取存储器 RAM 时序输入
  • LD_AR:AR 写选通
  • W/R:RAM 读写控制,低电平读,高电平写
  • RAM_B:存储模块写总线控制,高电平输出到总线

在这里插入图片描述

在这里插入图片描述

控制器设计

这里采用状态机实现

指令集

指令格式
用你们的指令格式稍作调整,将 RD 和 RS 的位置互换

指令7-4 位3-2 位1-0 位
功能操作码RD 寄存器RS 寄存器

你们有 IN、SUB、STA、MOV、ADD、OUT、SLL、JMP 共 8 个指令,我这里取部分指令重点演示双端口

指令作用opcoderdrs
IN用于数据输入0000rd11
ADD双端口加法0101rdrs
SUB双端口减法0010rdrs
JMP指令跳转1000rd11

rs 为 11 代表没有使用任何寄存器

流程图

流程图上相同状态,标上同一个状态序号

在这里插入图片描述

状态信号控制表

根据流程图中,每个状态标出其控制信号:

例如 PC->AR
PC 的值要输出到 BUS 上,所以 PC_B 要置 1 打开
AR 要从总线读 PC 的值,所以 LD_PC 要置 1
表中,大部分控制信号默认为 0,以表示不作用;但寄存器堆中 2 个 LD 和 2 个 SEL 是默认为 11,以表示不作用

表中(左)和(右)表示左出左入和右出右入

在这里插入图片描述

状态图

画出状态图,标出每个状态之间转换需要的条件,没标表示无条件,

在这里插入图片描述

写状态机控制的 VHDL 代码

写了注释了,可以自己读懂的

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity SM is
	port(
		CLK	 : in	std_logic; -- 时钟信号
        I    : in	std_logic_vector(7 downto 0); -- 指令
		RST	 : in	std_logic; -- 复位信号
		CTL	 : out	std_logic_vector(18 downto 0)); -- 控制信号
end entity;

architecture rtl of SM is
	-- 这里写下所有的状态
	type state_type is (s0, s1, s2, s3, s4, s5, s6);
	signal state   : state_type;

begin
    -- 这个进程控制状态机的状态转移有关,需要用到信号CLK、RST、I
	process (CLK, RST, I)
	begin
        -- 如果复位信号为1,则状态机回到初始状态
		if RST = '1' then
			state <= s0;
        -- 如果时钟信号为上升沿,则状态机状态转移
		elsif (rising_edge(CLK)) then
			case state is
				when s0=>
                    -- 初始状态下,状态机转移到s1
					state <= s1;
				when s1=>
                    -- 如果指令的高四位为0000,则状态机转移到s2
                    -- 如果指令的高四位为0101或0010,则状态机转移到s3
                    -- 如果指令的高四位为1000,则状态机转移到s6
                    -- 后面的状态转移同理
					if (I(7 downto 4) = "0000") then
						state <= s2;
					elsif (I(7 downto 4) = "0101" or I(7 downto 4) = "0010") then
						state <= s3;
                    elsif (I(7 downto 4) = "1000") then
                        state <= s6;
					end if;
				when s2=>
                    state <= s0;
				when s3 =>
					if I(7 downto 4) = "0101" then
                        state <= s4;
                    elsif I(7 downto 4) = "0010" then
                        state <= s5;
					end if;
                when s4 =>
					state <= s0;
                when s5 =>
                    state <= s0;
                when s6 =>
                    state <= s0;
			end case;
		end if;
	end process;

	-- 这个进程控制状态机的输出CTL,需要用到信号state和I
    -- 根据状态机的状态,输出对应的控制信号,控制信号来源于信号控制表的每一行
	process (state, I)
	begin
		case state is
			when s0 =>
                -- s0状态下,输出对应的控制信号,就是表的第一行,以此类推
				CTL <= "0111111110001000110";
			when s1 =>
				CTL <= "0111111110000010001";
			when s2 =>
                -- 表的第三行,注意这里的RD用I(3 downto 2)即指I的第4、3位代替,以此类推
				CTL <= "111"& I(3 downto 2) &"11110000000000";
			when s3 =>
				CTL <= "01111"& I(3 downto 0) &"1000000000";
            when s4 =>
                CTL <= "0"& I(3 downto 2) &"1111110010000000";
            when s5 =>
                CTL <= "0"& I(3 downto 2) &"1111110100000000";
            when s6 =>
                CTL <= "0111111"& I(3 downto 2) &"0000001100";
		end case;
	end process;
end rtl;

仿真
在这里插入图片描述

控制器,加上指令寄存器 IR 就做好了

在这里插入图片描述

仿真

在这里插入图片描述

测试指令设计

设计

我这里用上面提到的四个指令设计如下测试指令

在这里插入图片描述

写入 RAM 内存中

  1. 新建 mif 文件
    在这里插入图片描述

  2. 右键表头,将两个选项都选 Hex
    在这里插入图片描述

  3. 对照测试指令,将指令按地址写入到 mif 文件中
    这个 mif 文件每个格子代表一个内存单元,地址从左往右、从上到下,为 00 一直到 FF
    在这里插入图片描述

  4. 将文件绑定到 RAM 的 lpm_ram_dq 上
    1、右键 lpm_ram_dq,编辑
    在这里插入图片描述

    2、双击它
    在这里插入图片描述

    3、next 两次,选择初始化文件
    在这里插入图片描述

    4、finish 后,两个弹窗选确定,然后选否
    5、更新元件
    在这里插入图片描述

    6、设置顶层,编译
    最后再仿真验证,确认指令已经存入,以及 RAM 的读取功能正确
    在这里插入图片描述

整机设计

分别将 REG, ALU, PC,RAM,CTL,STEP 者几个部件生成为元件

步骤:设置顶层->编译->file->create/updata->create symbol…
在这里插入图片描述

然后将这几个部件放到新的空原理图中,分别接上 CLK、RST、D[7…0]和 Q[7…0]接总线
其它的控制信号根据控制信号表,接上 CTL[?..?]
在这里插入图片描述

最后仿真验证整机执行测试程序是否正确

  1. 指令 IN R0 正确,R0=0A
    在这里插入图片描述

  2. 指令 IN R1 正确,R1=05
    在这里插入图片描述

  3. 指令 SUB R0,R1,正确,R0=05
    在这里插入图片描述

  4. 指令 ADD R0,R1,正确 R1=0A
    在这里插入图片描述

  5. 指令 JMP R2,正确,PC=0,下一条指令从地址 00 开始执行
    在这里插入图片描述

80%已完成,需要
  1. 将剩下 4 条指令类型加入到流程图
  2. 画状态转移图
  3. 写信号控制表
  4. 改状态机 SM.vhd 的 VHDL 代码,设置顶层、编译、生成部件、刷新顶层原理图中的 CTL
  5. 再设计测试程序,使之包含所有指令类型,并绑定入 ram 中,设置顶层、编译、生成部件、刷新顶层原理图中的 RAM
  6. 顶层设计图再仿真

标签:LD,RIGHT,RISC,状态机,PC,指令,寄存器,ALU,LEFT
From: https://blog.csdn.net/m0_69150145/article/details/143194681

相关文章

  • cannot bind non-const lvalue reference of type ‘QDomElement&’ to an rvalue of
    /mnt/hgfs/SharedFolders/KingKongNano/YiKingStudio/TopoConfig/topoconfigwindow.cpp:2079:error:cannotbindnon-constlvaluereferenceoftype‘QDomElement&’toanrvalueoftype‘QDomElement’FreshPdoandVarIndex(TopologyVarFileDocDemo->document......
  • BehaviorTree、QP状态机与有限状态机(FSM)的比较分析
            在现代软件开发中,状态管理是确保系统行为正确性和高效性的关键。BehaviorTree、QP状态机和有限状态机(FSM)是三种常用的状态管理工具,它们各自适用于不同的场景。以下将通过具体例子和伪代码来比较这三种工具的特点和适用性。BehaviorTree:游戏AI的灵活决策Behav......
  • HCIP OSPF-1 邻居状态机和 DR 选举
    一、实验拓扑二、实验需求及解法通过本次实验,验证OSPF邻居状态机变化过程,以及DR选举过程。1.配置设备IP地址。R1<R1>system-view[R1]sysnameR1[R1]interfaceg0/0/0[R1-GigabitEthernet0/0/0]ipaddress12.1.1.124[R1-GigabitEthernet0/0/0]quitR2<R......
  • 聊一聊Spring中的@Value注解
    [!NOTE]**Spring版本:**5.3.27**JDK版本:**1.81、MyConfig.properties何时被加载解析?2、MyService中的两个@Value何时解析?3、MyService中的两个@Value何时注入属性文件中的值?一、样例服务类packagecom.lazy.snail.service;importorg.springframework.beans.fact......
  • BigDecimalUtil工具类 Java 多种类型(Double, String, Integer)转换成BigDecimal 进行加
    工具说明没有什么太复杂的代码。先是通过方法名称确定返回值的类型(BigDecimal、Double、String)。然后大量的重载方法,用“穷举法”把BigDecimal、Double、String、Integer四种类型进行各种形式的两两组合,进行加减乘除运算。运算时非BigDecimal类型的参数会转化成BigDecim......
  • python: invalid value encountered in divide以及invalid value encountered in doub
    运行命令pythoneqtl_prepare_expression.pydata.tpm.gctdata.reads_count.gct--tpm_threshold0.1--count_threshold2--sample_frac_threshold0.2--normalization_methodtmm--outputdata.txt时出现了报错“invalidvalueencounteredindivide”以及“invalidvalue......
  • 【状态机DP】力扣309. 买卖股票的最佳时机含冷冻期
    给定一个整数数组prices,其中第prices[i]表示第i天的股票价格。​设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):卖出股票后,你无法在第二天买入股票(即冷冻期为1天)。注意:你不能同时参与多笔交易(你必须在再次购......
  • 【状态机DP】【hard】力扣188. 买卖股票的最佳时机 IV
    给你一个整数数组prices和一个整数k,其中prices[i]是某支给定的股票在第i天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成k笔交易。也就是说,你最多可以买k次,卖k次。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。示例......
  • 【MySQL】[HY000][1366] Incorrect string value: ‘\xE4\xB8\xA4\xE6\x95\xB0.
    问题描述在导入中文数据时遇到错误。[2024-10-1610:49:49][HY000][1366]Incorrectstringvalue:'\xE4\xB8\xA4\xE6\x95\xB0...'forcolumn'title'atrow1尝试将某些数据插入到名为’title’的列时,遇到了不正确的字符串值。原因分析MySQL5.7创建数据库的默......
  • c#声明枚举,通过枚举int获取枚举value、通过枚举value获取int值、判断string值是否存在
    c#声明枚举,通过枚举int获取枚举value、通过枚举value获取int值、判断string值是否存在枚举中 1、声明枚举每个枚举常量可以用一个标识符来表示,也可以为它们指定一个整数值,如果没有指定,那么默认从 0 开始递增。注意:第一个枚举成员的默认值为整型的0,后续枚举成员的值在前......