计算机系统实验:模型机(十六)另一篇?
这一篇文章也是写模型机的,但是为什么我会有两个?保险起见还是上传一下记录下来,免得我又把资料搞丢了。这一篇就不分成很多篇了。来个大的!
一、设计目的
系统掌握计算机的组成和工作原理,能够自助熟练准确地阐述计算机执行机器指令的工作过程,熟练应用并设计微指令、微程序的设计及调试。
二、设计内容
模型机与程序运行试验是一个综合性整机实验。该模型机包含7条机器指令,它能够依照用户执行微程序完成由加、与、非运算以及数据组合的任意复合运算。用户测试程序可以通过内存初始化的方式存储在内存中,也可以通过强迫写的方式循环写入内存。
这里我采用分模块整合法,此整机实验,由节拍脉冲、数据通路、微程序控制器、数码管显示4个模块组成。运算器、存储器、数据通路及微程序控制器中的时钟脉冲必须与时序电路相连。
1.以下为参考顶层电路:
2.设计指令表如下:
这个实验主要通过以下三个步骤完成:
首先,将各个元件进行设计,并生成相应的bsf文件,注意这里最好对每一个元件进行单独的仿真验证和测试,然后通过仿真结果进行检测,看看是否正常运行。这里每一个元件的源程序都可以在书上找到。
其次,将各个元件进行连接,先进行线路上的链接,将相同的信号进行连接,然后对整个电路进行仿真验证。这里的链接方法在书上都有,就是那个顶层实体图,然后时钟信号根据微体系结构图得到
最后,根据仿真验证的结果,对整个电路进行微调,主要是对时钟信号进行调整。
三、详细设计
3.1设计的整体架构
总共大大小小有13个元件,其中有书上所指示的,也有我自己设计的(如ir),通过这11个元件相互之间的配合和时序上的整合,实现7个机器指令的实现(由于我实现的比较早,所以我在犹豫要不要实现其他的机器指令,如sub)。其中有多种信号。
1、jiepai元件:
用来产生t1~t4时钟节拍脉冲的元件;如图所示:
LIBRARY ieee;
USE ieee.std_logic_1164.all;ENTITY jiepai ISPORT (clk : IN STD_LOGIC;tj : IN STD_LOGIC := '0';dp : IN STD_LOGIC := '0';qd : IN STD_LOGIC := '0';t1 : OUT STD_LOGIC;t2 : OUT STD_LOGIC;t3 : OUT STD_LOGIC;t4 : OUT STD_LOGIC;q1 : OUT STD_LOGIC;q2 : OUT STD_LOGIC;q3 : OUT STD_LOGIC);
END jiepai;ARCHITECTURE BEHAVIOR OF jiepai ISTYPE type_fstate IS (idle,st1,s_st2,st4,st2,st3,s_st4,s_st3);SIGNAL fstate : type_fstate;SIGNAL reg_fstate : type_fstate;SIGNAL reg_t1 : STD_LOGIC := '0';SIGNAL reg_t2 : STD_LOGIC := '0';SIGNAL reg_t3 : STD_LOGIC := '0';SIGNAL reg_t4 : STD_LOGIC := '0';
BEGINPROCESS (clk,reg_fstate)BEGINIF (clk='1' AND clk'event) THENfstate <= reg_fstate;END IF;END PROCESS;PROCESS (fstate,qd,dp,tj,reg_t1,reg_t2,reg_t3,reg_t4)BEGINreg_t1 <= '0';reg_t2 <= '0';reg_t3 <= '0';reg_t4 <= '0';t1 <= '0';t2 <= '0';t3 <= '0';t4 <= '0';CASE fstate ISWHEN idle =>IF (NOT((qd = '1'))) THENreg_fstate <= st1;ELSEreg_fstate <= idle;END IF;reg_t4 <= '0';reg_t3 <= '0';reg_t2 <= '0';reg_t1 <= '0';WHEN st1 =>IF (((tj = '1') AND NOT((dp = '1')))) THENreg_fstate <= st1;ELSIF (((dp = '1') AND NOT((tj = '1')))) THENreg_fstate <= s_st2;ELSEreg_fstate <= st2;END IF;reg_t4 <= '0';reg_t3 <= '0';reg_t2 <= '0';reg_t1 <= '1';WHEN s_st2 =>IF ((tj = '1')) THENreg_fstate <= s_st2;ELSEreg_fstate <= s_st3;END IF;reg_t4 <= '0';reg_t3 <= '0';reg_t2 <= '1';reg_t1 <= '0';WHEN st4 =>IF (((tj = '1') AND NOT((dp = '1')))) THENreg_fstate <= st4;ELSIF (((dp = '1') AND NOT((tj = '1')))) THENreg_fstate <= idle;ELSEreg_fstate <= st1;END IF;reg_t4 <= '1';reg_t3 <= '0';reg_t2 <= '0';reg_t1 <= '0';WHEN st2 =>IF (((tj = '1') AND NOT((dp = '1')))) THENreg_fstate <= st2;ELSIF (((dp = '1') AND NOT((tj = '1')))) THENreg_fstate <= s_st3;ELSEreg_fstate <= st3;END IF;reg_t4 <= '0';reg_t3 <= '0';reg_t2 <= '1';reg_t1 <= '0';WHEN st3 =>IF (((tj = '1') AND NOT((dp = '1')))) THENreg_fstate <= st3;ELSIF (((dp = '1') AND NOT((tj = '1')))) THENreg_fstate <= s_st4;ELSEreg_fstate <= st4;END IF;reg_t4 <= '0';reg_t3 <= '1';reg_t2 <= '0';reg_t1 <= '0';WHEN s_st4 =>IF ((tj = '1')) THENreg_fstate <= s_st4;ELSEreg_fstate <= idle;END IF;reg_t4 <= '1';reg_t3 <= '0';reg_t2 <= '0';reg_t1 <= '0';WHEN s_st3 =>IF ((tj = '1')) THENreg_fstate <= s_st3;ELSEreg_fstate <= s_st4;END IF;reg_t4 <= '0';reg_t3 <= '1';reg_t2 <= '0';reg_t1 <= '0';WHEN OTHERS => reg_t1 <= 'X';reg_t2 <= 'X';reg_t3 <= 'X';reg_t4 <= 'X';report "Reach undefined state";END CASE;t1 <= reg_t1;t2 <= reg_t2;t3 <= reg_t3;t4 <= reg_t4;END PROCESS;
END BEHAVIOR;
这是第五次实验——时序电路实验的内容,如果能够正确完整的完成第五次实验,那么这个就不是什么难题。第五次实验教会了我们一种使用quartus软件画状态图并生成vhdl的方法。这个元件主要是生成四个时钟脉冲信号,通过这四个时钟脉冲信号控制整个电路。
2、kongzhi元件:
整个控制器的元件,其中包含了rom(用来产生相应的微指令信号)元件和pp(我自己设置的,用来控制下址)元件;如图所示:
pp元件的vhdl为:
library ieee;
use ieee.std_logic_1164.all;
entity pp is
port(clock:in std_logic;p:in std_logic;ir7:in std_logic;ir6:in std_logic;ir5:in std_logic;a5:in std_logic;a4:in std_logic;a3:in std_logic;a2:in std_logic;a1:in std_logic;rd:in std_logic;we:in std_logic;o5:out std_logic;o4:out std_logic;o3:out std_logic;o2:out std_logic;o1:out std_logic);
end pp;
architecture rtl of pp is
signal aa,bb:std_logic;
begin
process(clock,p,ir7,ir6,ir5,rd,we)
beginif(rd='0') theno5<=a5;o4<=a4;o3<=a3;o2<=a2;o1<=a1;elsif(we='0') theno5<='1';o4<='0';o3<='0';o2<='0';o1<='0';elseif(p='0') theno5<=a5;o4<=a4;o3<=a3;o2<=a2;o1<=a1;elsif(ir7='0' and ir6='0' and ir5='0')theno5<=a5;o4<=a4;o3<=a3;o2<=a2;o1<=a1; elseo5<='0';o4<='1';o3<=ir7;o2<=ir6;o1<=ir5;end if;end if;
end process;
end rtl;
rom元件的vhdl为:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY rom IS
PORT
(a4,a3,a2,a1,a0:in std_logic;d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17,d18,d19,d20,d21,d22,d23,d24,d25,d26,d27,d28:out std_logic --address : IN STD_LOGIC_VECTOR (4 DOWNTO 0); -- q : OUT STD_LOGIC_VECTOR (27 DOWNTO 0)
);
END rom;
ARCHITECTURE SYN OF rom IS
signal address:std_logic_vector(4 downto 0);
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (27 DOWNTO 0);
BEGIN
address<=a4&a3&a2&a1&a0;
sub_wire0<=
"1010111100000001000000000001" WHEN address= "00000" ELSE
"1111111000001001000000000010" WHEN address= "00001" ELSE
"1001111100000101000001001000" WHEN address= "00010" ELSE
"1001111100000001000000110011" WHEN address= "01000" ELSE
"1111111000001001000000010101" WHEN address= "01001" ELSE
"1111111000001001000000010111" WHEN address= "01010" ELSE
"1111111000001001000000011001" WHEN address= "01011" ELSE
"1001101100010001000000011011" WHEN address= "01100" ELSE
"1111111000001001000000011100" WHEN address= "01101" ELSE
"1111111000001001000000000011" WHEN address= "01110" ELSE
"1111111000001001000000011101" WHEN address= "01111" ELSE
"1001111100001001000001010110" WHEN address= "10101" ELSE
"1001111110000001000001000001" WHEN address= "10110" ELSE
"1001111100001001000001011000" WHEN address= "10111" ELSE
"1001101100000001000010000001" WHEN address= "11000" ELSE
"1001111100001001000001011010" WHEN address= "11001" ELSE
"1000111100000001000001000001" WHEN address= "11010" ELSE
"1001110110000010000000000001" WHEN address= "11011" ELSE
"1011111100000001000001000001" WHEN address= "11100" ELSE
"1001111100001001000001000100" WHEN address= "00011" ELSE
"1001111100100001000001000101" WHEN address= "00100" ELSE
"1001101100010001000000000110" WHEN address= "00101" ELSE
"1001110110000001100100000001" WHEN address= "00110" ELSE
"1001111100001001000001011110" WHEN address= "11101" ELSE
"1001111100100001000001011111" WHEN address= "11110" ELSE
"1001101100010001000000000111" WHEN address= "11111" ELSE
"1001110110000000101100000001" WHEN address= "00111" ELSE
"1010111100000001000000010001" WHEN address= "10000" ELSE
"1111111000001001000000010010" WHEN address= "10001" ELSE
"1111111000001001000000010100" WHEN address= "10011" ELSE
"1000111100000001000010010001" WHEN address= "10010" ELSE
"1001111100000001000001010011" ;
d1<=sub_wire0(27);
d2<=sub_wire0(26);
d3<=sub_wire0(25);
d4<=sub_wire0(24);
d5<=sub_wire0(23);
d6<=sub_wire0(22);
d7<=sub_wire0(21);
d8<=sub_wire0(20);
d9<=sub_wire0(19);
d10<=sub_wire0(18);
d11<=sub_wire0(17);
d12<=sub_wire0(16);
d13<=sub_wire0(15);
d14<=sub_wire0(14);
d15<=sub_wire0(13);
d16<=sub_wire0(12);
d17<=sub_wire0(11);
d18<=sub_wire0(10);
d19<=sub_wire0(9);
d20<=sub_wire0(8);
d21<=sub_wire0(7);
d22<=sub_wire0(6);
d23<=sub_wire0(5);
d24<=sub_wire0(4);
d25<=sub_wire0(3);
d26<=sub_wire0(2);
d27<=sub_wire0(1);
d28<=sub_wire0(0);
END SYN;
这是第六次实验的内容,主要在于rom元件的设计和信号的安排。可以直接拿来用。
3、shutong元件
数据通路元件,其中包含了exp_r_alu(alu运算器模块,用来进行数据运算)元件和exp_ram_vhd(其中包含了ram寄存器模块和pc、ar寄存器模块,用来访问内存文件,产生指令,产生计数,存储指令和地址)元件;
exp_r_alu元件的vhdl为:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity exp_r_alu is
port( clk1:in std_logic;--t3clk2:in std_logic;--t2sw_bus,r4_bus,r5_bus,alu_bus:in std_logic;lddr1,lddr2,ldr4,ldr5:in std_logic;m,cn:in std_logic;s:in std_logic_vector(3 downto 0);k:in std_logic_vector(7 downto 0):="00000000";d:inout std_logic_vector(7 downto 0);--ou:out std_logic_vector(7 downto 0);rr5:out std_logic_vector(7 downto 0);rr4:out std_logic_vector(7 downto 0);rr1:out std_logic_vector(7 downto 0);rr2:out std_logic_vector(7 downto 0));
end exp_r_alu;
architecture rtl of exp_r_alu is
signal dr1,dr2,r4,r5,aluout,bus_reg:std_logic_vector(7 downto 0);
signal sel:std_logic_vector(5 downto 0);
begin
ldreg:process(clk1,clk2,lddr1,lddr2,ldr4,ldr5,bus_reg)beginif clk1'event and clk1='1' thenif ldr4='1' then r4<=bus_reg;elsif ldr5='1' then r5<=bus_reg;end if;end if;if clk2'event and clk2='1' thenif lddr1='1' then dr1<=bus_reg;elsif lddr2='1' then dr2<=bus_reg;end if;end if;end process;
alu:process(m,cn,s,dr1,dr2,sel,aluout)beginsel<=m&cn&s;case sel iswhen "000000"=>aluout<=dr1+1;when "010000"=>aluout<=dr1;when "100000"=>aluout<=not dr1;when "000001"=>aluout<=(dr1 or dr2)+1;when "010001"=>aluout<=dr1 or dr2;when "100001"=>aluout<=not(dr1 or dr2);when "000010"=>aluout<=(dr1 or (not dr2))+1;when "010010"=>aluout<=(dr1 or (not dr2));when "100010"=>aluout<=(not dr1)and dr2;when "000011"=>aluout<=x"00";when "010011"=>aluout<=aluout-1;when "100011"=>aluout<=x"00";when "000100"=>aluout<=dr1+(dr1 and (not dr2))+1;when "010100"=>aluout<=dr1+(dr1 and (not dr2));when "100100"=>aluout<=not(dr1 and dr2);when "000101"=>aluout<=(dr1 or dr2)or(dr1 and dr2)or x"01";when "010101"=>aluout<=(dr1 or dr2)+(dr1 and (not dr2));when "100101"=>aluout<=not dr2;when "000110"=>aluout<=dr1-dr2;when "010110"=>aluout<=dr1-dr2-1;when "100110"=>aluout<=dr1 xor dr2;when "000111"=>aluout<=dr1 and (not dr2);when "010111"=>aluout<=(dr1 and (not dr2))-1;when "100111"=>aluout<=dr1 and(not dr2); when "001000" => aluout<=dr1 + (dr1 and dr2)+1;when "011000" => aluout<=dr1 + (dr1 and dr2);when "101000" => aluout<= (not dr1) or dr2;when "001001" => aluout<=dr1 + dr2 +1;when "011001" => aluout<=dr1 + dr2;when "101001" => aluout<=(dr1 xnor dr2);when "001010" => aluout<=(dr1 or(not dr2))+(dr1 and dr2)+1;when "011010" => aluout<=(dr1 or(not dr2))+(dr1 and dr2);when "101010" => aluout<=dr2;when "001011" => aluout<=dr1 and dr2;when "011011" => aluout<=(dr1 and dr2)-1;when "101011" => aluout<=(dr1 and dr2);when "001100" => aluout<=dr1 + dr1 +1;when "011100" => aluout<=(dr1 or dr1); when "101100" => aluout<=x"01";when "001101" => aluout<=(dr1 or dr2)+dr1+1;when "011101" => aluout<=(dr1 or dr2)+dr1;when "101101" => aluout<=dr1 or(not dr2);when "001110" => aluout<=(dr1 or (not dr2))+dr1+1;when "011110" => aluout<=(dr1 or (not dr2))+dr1;when "101110" => aluout<=dr1 or dr2;when "001111" => aluout<=dr1;when "011111" => aluout<=dr1-1;when "101111" => aluout<=dr1;when others =>aluout<=x"ff";end case;end process;bus_Reg<=k when(sw_bus='0' and r4_bus='1' and r5_bus='1' and ALU_bus='1') elser4 when(sw_bus='1' and r4_bus='0' and r5_bus='1' and ALU_bus='1') elser5 when(sw_bus='1' and r4_bus='1' and r5_bus='0' and ALU_bus='1') elsealuout when(sw_bus='1' and r4_bus='1' and r5_bus='1' and ALU_bus='0') else d;d<=bus_Reg when(sw_bus='0' or r4_bus='0' or r5_bus='0' or ALU_bus='0') else--******(others=>'Z');rr5<=r5;rr4<=r4;rr1<=dr1;rr2<=dr2;
end rtl;
exp_ram_vhd元件为:
其中的sw_pc_ar元件的vhdl为:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity sw_pc_ar is
port(clk_cdu,pcclr,pcld,pcen:in std_logic;--Z,1,0,0sw_bus,pc_bus,ldar:in std_logic;--1,1,0inputd:in std_logic_vector(7 downto 0):="00000000";arout:out std_logic_vector(7 downto 0);d:inout std_logic_vector(7 downto 0);pco:out std_logic_vector(7 downto 0));
end sw_pc_ar;
architecture rtl of sw_pc_ar is
signal pc,ar,bus_reg:std_logic_vector(7 downto 0):="00000000";
begin
seql:process(clk_cdu,ldar,bus_reg)--when ldar==1 let bus into arbeginif clk_cdu'event and clk_cdu='1' thenif ldar='1' thenar<=bus_reg;end if;end if;end process;
sep2:process(clk_cdu,pcclr,pcld,pcen,bus_reg)beginif pcclr='0' then--when pcclr==0 clear pcpc<=(others=>'0');elsif clk_cdu'event and clk_cdu='1' thenif (pcld='0' and pcen='1') then--when pcen==1 & pcld==0 let bue into pcpc<=bus_reg;elsif (pcld='1' and pcen='1') then--when pcen==1 & pcld==1 pc++pc<=pc+1;end if;end if;end process;
bus_reg<=inputd when (sw_bus='0' and pc_bus='1') else--when pc_bus==1 let inputd in buspc when (sw_bus='1' and pc_bus='0') else--when sw_bus==1 let pc in busd;--when 0 0 let d in bus
d<=bus_reg when (sw_bus='0' or pc_bus='0') else--when 0 0 let bus into d(others=>'Z');--when else let Z into d
arout<=ar;--show ar
pco<=pc;
end rtl;
这是第四次实验的内容,已经将总线和alu进行了整合,十分的简单和方便。如果能够完整的完成第四次实验的仿真和下载,那么并不是什么难事。
4、xianshi元件:
显示模块并不是实验中要求的,而更多的是我们自己学习的,是附加电路的内容,由于附加电路是我自己完全独立设计的,没有参考书上的什么内容,所以我比较熟悉,也比较清楚它的各个端口是做什么的,有什么样的作用,再加上我曾经做的跑马灯,对于八个数码管的同时显示也比较熟悉,所以总的来说,设计出来并不是太难。
显示数码管元件,其中包含了seg(用来控制段选信号的模块)元件、cpu16(用来产生计数的模块)元件和sanba(用来控制位选信号的模块)元件,下文会进行详细的介绍。
在所有的信号中,clk是执行模块(包括控制器和数据通路)的时钟输入信号,clock是显示模块的时钟输入信号,clr、krd、kwe是控制器的控制输入信号,tj、dp、qd是节拍(时序电路)的控制输入信号,k是数据输入信号,其他所有的信号均为输出信号,用来检测是否运行正确以及下载后控制数码管显示数据。注意寄存器的初值已经在编写的时候输入到了寄存器的mif文件中,在后续的演示中除了想要增加,不需要人为输入。
在检测的时候主要观察ir7~ir6信号(指令信号),p信号(总使能信号),rr5信号(r5寄存器数据输出信号),pc信号(计数器数据输出信号),bus信号(总线数据输出信号),ao信号(ar寄存器数据输出信号)。
运行的时候以每4个时钟脉冲周期为一个微指令周期,多个微指令周期为一个机器指令周期,实现一个机器指令。
在这里,我是严格按照书上的要求设计的时钟信号,只是在显示模块的时候加入了一个新的时钟信号,用来控制持续显示而不是频闪。
3.2附加电路说明
1、seg模块:
用来产生段选信号的,通过输入的数据来产生相应的段选信号,用来控制在数码管上的显示来输出数据,vhdl如下:
library ieee;
use ieee.std_logic_1164.all;
entity seg is
port(input:in std_logic_vector(3 downto 0);en:in std_logic;output:out std_logic_vector(7 downto 0));
end seg;
architecture ru of seg is
begin
process(input,en)
begin
if en='1' then if input="0000" thenoutput<="11111100";elsif input="0001" thenoutput<="01100000";elsif input="0010" thenoutput<="11011010";elsif input="0011" thenoutput<="11110010";elsif input="0100" thenoutput<="01100110";elsif input="0101" thenoutput<="10110110";elsif input="0110" thenoutput<="10111110";elsif input="0111" thenoutput<="11100000";elsif input="1000" thenoutput<="11111110";elsif input="1001" thenoutput<="11110110";elsif input="1010" thenoutput<="11101110";elsif input="1011" thenoutput<="00111110";elsif input="1100" thenoutput<="10011100";elsif input="1101" thenoutput<="01111010";elsif input="1110" thenoutput<="10011110";elsif input="1111" thenoutput<="10001110"; end if;
else output<="00000010";
end if;
end process;
end ru;
当en为1的时候可以输出数据相应的段选信号,当en为0的时候将会输出一条杠
2、cpu16元件:
用来产生计数的,用来控制哪个数码管在哪个时候进行显示,具体代码如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY cpu16 IS
PORT(CLK,RST,EN : IN STD_LOGIC;CQ : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);COUT : OUT STD_LOGIC);
END ENTITY cpu16;
ARCHITECTURE behav OF cpu16 IS
BEGIN
PROCESS (CLK,RST,EN)VARIABLE CQI : STD_LOGIC_VECTOR(3 DOWNTO 0);BEGINIF RST='1' THEN CQI:=(OTHERS =>'0');ELSIF CLK'EVENT AND CLK='1' THENIF EN='1' THEN IF CQI<7 THEN CQI:=CQI+1;ELSE CQI := (OTHERS =>'0');END IF;END IF;END IF;IF CQI=2 THEN COUT<='0';elsif cqi=5 then cout<='0';ELSE COUT<='1';END IF;CQ<=CQI;
END PROCESS;
END ARCHITECTURE behav;
将会进行0~7的数字循环,每个数字对应一个数码管,实际上就是一个简单的数字计数器罢了。
3、sanba译码器元件:
用来产生位选信号,用来配合cput16控制哪个数码管在哪个时间进行显示,vhdl如下:
library ieee;
use ieee.std_logic_1164.all;
entity sanba is
port(input:in std_logic_vector(2 downto 0);o0:out std_logic;o1:out std_logic;o2:out std_logic;o3:out std_logic;o4:out std_logic;o5:out std_logic;o6:out std_logic;o7:out std_logic);
end sanba;
architecture ru of sanba is
signal output:std_logic_vector(7 downto 0);
begin
process(input)
begin
if input="000" thenoutput<="00000001";
elsif input="001" thenoutput<="00000010";
elsif input="010" thenoutput<="00000100";
elsif input="011" thenoutput<="00001000";
elsif input="100" thenoutput<="00010000";
elsif input="101" thenoutput<="00100000";
elsif input="110" thenoutput<="01000000";
elsif input="111" thenoutput<="10000000";
end if;
end process;
o0<=not output(7);
o1<=not output(6);
o2<=not output(5);
o3<=not output(4);
o4<=not output(3);
o5<=not output(2);
o6<=not output(1);
o7<=not output(0);
end ru;
将会循环使8位数码管进行显示
3.3仿真结果说明
具体分析如下:
115ns~285ns执行的是LDA指令,将03H给r5寄存器
先进行01001指令,将pc中的数值给ar寄存器,pc再加1,此时ar的值为01H
再进行10101指令,将ram中ar位置的地址的数值取出来,再给ar寄存器,此时ram取出来的数值是14H,ar寄存器的数值即为14H
再进行10110指令,将ram中ar位置的地址的数值取出来,再给r5寄存器,此时ram取出来的数值是03H ,r5寄存器的数值即为03H
285ns~475ns执行的是COM指令,将03H取反得到FCH再赋值给r5寄存器
先进行01100指令,将r5寄存器的数值放到dr1暂存器中,此时dr1暂存器的数值为03H
再进行11011指令,将dr1中的数值进行取反操作后再赋值给r5寄存器,此时r5寄存器的数值为FCH
475ns~795ns执行的是ADD指令,相加后结果为FDH在赋值给r5寄存器
先进行01110指令,将pc中的数值给ar寄存器,pc再加1,此时ar的值为04H
再进行00011指令,将ram中ar位置的地址的数值取出来,再给ar寄存器,此时ran取出来的数值是12H,ar寄存器的数值即为12H
再进行00100指令,将ram中ar位置的地址的数值取出来,再给dr2暂存器,此时ram取出来的数值是01H,dr2寄存器的数值即为01H
再进行00101指令,将r5寄存器的数值给dr1暂存器,此时dr1暂存器的数值为FCH
再进行00110指令,将dr1和dr2的数值进行相加,再将结果给r5寄存器,此时r5寄存器的数值为FDH
795ns~1045ns执行的是STA指令,将r5寄存器中的值放到ram中
先进行01010指令,将pc中的数值给ar寄存器,pc再加1,此时ar的数值为06H
再进行10111指令,将ram中ar位置的地址的数值取出来,再给ar寄存器,此时ram取出来的数值是16H,ar寄存器的数值即为16H
再进行11000指令,将r5寄存器的数值放到ram中ar位置的地址
1045ns~1275ns执行的是LDA指令,将02H给r5寄存器
先进行01001指令,将pc中的数值给ar寄存器,pc再加1,此时ar的值为08H
再进行10101指令,将ram中ar位置的地址的数值取出来,再给ar寄存器,此时ram取出来的数值是13H,ar寄存器的数值即为02H
再进行10110指令,将ram中ar位置的地址的数值取出来,再给r5寄存器,此时ram取出来的数值是02H,r5寄存器的数值即为02H
1275ns~1595ns执行的是ADD指令,相加后结果为06H再赋值给r5寄存器
先进行01110指令,将pc中的数值给ar寄存器,pc再加1,此时ar的值为0AH
再进行00011指令,将ram中ar位置的地址的数值取出来,再给ar寄存器,此时ran取出来的数值是15H,ar寄存器的数值即为15H
再进行00100指令,将ram中ar位置的地址的数值取出来,再给dr2暂存器,此时ram取出来的数值是04H,dr2寄存器的数值即为04H
再进行00101指令,将r5寄存器的数值给dr1暂存器,此时dr1暂存器的数值为02H
再进行00110指令,将dr1和dr2的数值进行相加,再将结果给r5寄存器,此时r5寄存器的数值为06H
1595ns~1915ns执行的是AND指令,相与后结果为04H再赋值给r5寄存器
先进行01110指令,将pc中的数值给ar寄存器,pc再加1,此时ar的值为0CH
再进行11101指令,将ram中ar位置的地址的数值取出来,再给ar寄存器,此时ram取出来的数值是16H,ar寄存器的数值即为16H
再进行11110指令,将ram中ar位置的地址的数值取出来,再给dr2暂存器,此时ram取出来的数值是FDH,dr2暂存器的数值即为FDH
再进行11111指令,将r5寄存器的数值给dr1暂存器,此时dr1暂存器的数值即为06H
再进行00111指令,将dr1和dr2的数值进行相与,再将结果给r5寄存器,此时r5寄存器的数值为04H
1915ns~2115ns执行的是COM指令,将04H取反得到FBH再赋值给r5寄存器
先进行01100指令,将r5寄存器的数值放到dr1暂存器中,此时dr1暂存器的数值为04H
再进行11011指令,将dr1中的数值进行取反操作后再赋值给r5寄存器,此时r5寄存器的数值为FBH
2115ns~2365ns执行的是OUT指令,将存储器16H位置的值展示到bus上
先进行01011指令,将pc中的数值给ar寄存器,pc再加1,此时ar的数值为0FH
再进行11001指令,将ram中ar位置的地址的数值取出来,再给ar寄存器,此时ram取出来的数值是16H
再进行11010指令,将ram中ar位置的地址的数值取出来,再发送到总线,此时总线上的数值为FDH
2365ns~2565ns执行的是JMP指令,跳转回00H位置的指令重复执行
先进行01101指令,将pc中的数值给ar寄存器,pc再加1,此时ar的值为11H
再进行11100指令,将ram中ar位置的地址的数值取出来,再给pc计数器,此时ram取出来的数值是00H,pc计数器的数值即为00H
3.4mif文件展示
3.5报告
1)假如控制器中模拟指令码的ir7ir6ir5对应到数据总线d[7…0]的d4d6d1,译码出7条机器指令的指令码为:
机器指令 | 指令码 | 二进制指令码 | 十六进制指令码 |
---|---|---|---|
LDA | 001 | 00000001 | 01H |
STA | 010 | 01000000 | 40H |
ADD | 110 | 01010000 | 50H |
AND | 111 | 01010001 | 51H |
COM | 100 | 00010000 | 10H |
OUT | 011 | 01000001 | 41H |
JMP | 101 | 00010001 | 11H |
2)用模型机已有的7条机器指令编写测试程序,实现复合运算:
not((not(c))加a)and(b加d))
其中a=01H,b=02H,c=03H,d=04H
先将数据c放入r5寄存器中,再进行not(c),将结果放在r5寄存器中,
再进行not(c)加a,将结果放在r5寄存器中,将结果放到存储器中,
再将数据b放入r5寄存器中,再进行(b加d),结果放到r5寄存器中,
再将存储器中存储的not(c)加a取出,与r5进行相与,将结果放到r5寄存器中,
再对r5寄存器进行取反操作,结果放到r5寄存器中,
此时r5寄存器中的值就是我们要进行的复合运算的最终值
具体的代码表如下:
RAM地址 | 内容 | 说明 |
---|---|---|
00H | 20H | LDA双字节指令 |
01H | 14H | LDA 14将地址14H中内容送到r5(r5=03H) |
02H | 80H | COM单字节指令,将r5取反送到r5(r5=FCH) |
03H | C0H | ADD双字节指令 |
04H | 12H | ADD 12将地址12H中的内容与r5相加送到r5(r5=FDH) |
05H | 40H | STA双字节指令 |
06H | 16H | STA 16将r5的值放到地址16H的单元 |
07H | 20H | LDA双字节指令 |
08H | 13H | LDA 13将地址13H中内容送到r5(r5=02H) |
09H | C0H | ADD双字节指令 |
0AH | 15H | ADD 15将地址15H中的内容与r5相加送到r5(r5=06H) |
0BH | E0H | AND双字节指令 |
0CH | 16H | AND 16将地址16H中的内容与r5相与送到r5(r5=04H) |
0DH | 80H | COM单字节指令,将r5取反送到r5(r5=FBH) |
0EH | 60H | OUT双字节指令 |
0FH | 16H | OUT 16将地址16H中的内容送到BUS |
10H | A0H | JMP双字节指令 |
11H | 00H | JMP 00无条件转移到00H地址 |
12H | 01H | 数据a |
13H | 02H | 数据b |
14H | 03H | 数据c |
15H | 04H | 数据d |
16H | 00H | 数据暂存 |
a,b,c,d的值存储在12H~15H的位置
mif文件为:
下载图示:
1、针脚设置:
芯片还是选取ep5t144c8的芯片,因为我们的芯片就是这个,仅支持这个
将qd模型机启动控制信号,clr清零控制信号,kwe强读控制信号和krd强写控制信号放在了按钮开关,因为他们的初始值是1;
将k八位输入数据,tj停机信号,dp单拍进行控制信号放在了拨码开关,因为他们的初始值是0,而且这样可以方便我进行数值设置。
通过数码管显示ar寄存器,bus总线和r5寄存器的数值。
通过二极管101-104来显示t1-t4四个节拍脉冲信号。二极管93,92,87分别代表ir7,ir6,ir5,为ir寄存器输出的数值。
给模型机的时钟信号是91时钟信号,频率为100hz,便于观测;
给显示数码管的时钟信号是17时钟信号,以此来消除频闪。
针脚设计好之后点击全编译,生成sof文件。
通过programer工具将sof文件加在到板子上。
2、下载结果:
指令 | 图示(由左到右依次是ar-bus-r5) |
---|---|
初始状态 | |
LDA转移指令,r5=03H | |
COM取反指令,r5=FCH | |
ADD相加指令,r5=FDH | |
STA存储指令,bus=FDH | |
LDA转移指令,r5=02H | |
ADD相加指令。r5=06H | |
AND相与指令,r5=04H | |
COM取反指令,r5=FBH | |
OUT输出指令,bus=00H | |
JMP跳转指令,ar=00H |
由此可以看出,在JMP指令执行后,r5寄存器中的值就是我们所要的复合运算的值FB。
3)回答问题
a、代码中进程ct1、ct2、ct3、ct4功能划分的依据是
ct1的功能是微序列控制器下址跳转
ct2的功能是实现各种指令,主要集中在实现从存储器或寄存器释放数据到总线上
ct3的功能是完成各种指令,从总线上装载数据到相应的存储器或寄存器中
ct4的功能是生成下址
b、代码中如何定义并初始化RAM
通过定义一个名叫ram8的中间变量进行定义,并通过赋初值来进行初始化:
signalram8:RAM:=(x”20”,x”0d”,x”c0”,x”0e”,x”40”,x”10”,x”60”,x”10”,x”e0”,x”0f”,x”80”,x”a0”,x”00”,x”55”,x”8a”,x”f0”,x”ff”,others=>x”00”)
其中括号中的数据是放入的初始值,即原本mif文件中的数据
c、代码中bus_reg_t2<=ram8(conv_integer(ar))与ram8(conv_integer(ar))<=r5的含义是什么
第一句是将ram中ar地址位置的数据值传送到总线上
第二句是将r5寄存器中的数据值传送到ram中ar地址的位置
4)vhdl中如何考虑多个时钟信号的情况
由于vhdl中是通过process进程进行设计的,所以只需要在进程中对不同的时钟信号进行条件选择,就可以在不同的时钟信号执行不同的操作。
但是注意要考虑到时序上的整合问题。
比方说,本次试验的时候,可以有四个不同的时钟信号,但是一定要满足:
在最先到达的一个时钟的波峰进行微序列控制器的下址跳转;
在第二个到达的波峰进行取数据的功能,即将数据从寄存器或存储器中取出来放到总线上,例如从ram中取出运算数据发送到总线上;
在第三个到达的波峰进行存数据的功能,即将数据从总线上存到寄存器或存储器中,例如将总线上的运算结果存回到r5寄存器中;
在最后一个到达的波峰进行下一个下址的生成。
虽然我是通过bdf和bsf的元件拼接整合实现的,但在我的整合过程中也注意了时序上的整合问题,比方说我给当前下址寄存器的时钟信号是t2时序脉冲,给寄存器和存储器的时钟信号一般是t3时序脉冲,给pp(我自己设计的下一下址寄存器)元件的时钟信号是t4时序脉冲,通过这样才达到了整个电路的正常运行。
当然,时序上的整合顺序不只有这一种,可以通过不同的设计方式进行,比方说我的舍友就将p1信号进行了提前,这样他就会提前进行判断是否进行强读强写,然后他又将所有的时钟信号进行了一个延迟,也做到了模拟机的正常运行。
所以我认为,时序上的整合方式不只有一种,我是按照书上的整合方式来的,并没有做太多的改动,但我也不认为只有我这种是正确的,毕竟这是一个开放性的大综合实验,只要能够设计出来,能够正常运行,就是可以的。
四、优化
因为我们可以有多个输出,想要查看多个值,如r5寄存器,r1暂存器,r2暂存器,pc计数器,ar寄存器,bus总线等等,而我们的数码管只有八个,只能显示3组数据,所以有些不够用,而我在我的搭档俞阳博的启发下,想到了一种可以多个显示的方法,即通过拨码开关来控制显示哪个数据,哪个寄存器,如下:
我定义了拨码开关52和51两个输入来控制r5,r1,r2,pc显示哪一个寄存器或计数器的数值,当52~51=00的时候(初始状态),第三组数码管显示r5寄存器的数值;当=01的时候显示r1暂存器的数值;当=10的时候显示r2暂存器的数值;当=11的时候显示pc计数器的数值。具体代码如下:
library ieee;
use ieee.std_logic_1164.all;
entity tf is
port(kg:in std_logic_vector(1 downto 0);m1:in std_logic_vector(7 downto 0);m2:in std_logic_vector(7 downto 0);m3:in std_logic_vector(7 downto 0);m4:in std_logic_vector(7 downto 0);mo:out std_logic_vector(7 downto 0));
end tf;
architecture rtl of tf is
begin
cin:process(kg)
beginif kg="00" thenmo<=m1;elsif kg="01" thenmo<=m2;elsif kg="10" thenmo<=m3;elsemo<=m4;end if;
end process;
end rtl;
实际上只不过是一个二四译码器的变形,根据输入的kg控制信号,来选择输出哪个八位的二进制数据,然后将输出的八位的二进制数据连接到显示模块的第三个输入数据,就可以通过52~51拨码开关进行控制要输出什么数据。
下载结果如下:
拨码开关(52~51) | 数码管(ar-bus-r5/r1/r2/pc) |
---|---|
00(r5) | |
01(r1) | |
10(r2) | |
11(pc) |
由此可以看出,当ar=03,bus=04,r5=FC的时候,执行的应该是COM取反指令,此时的r1暂存器的值是03(保持上一指令的数据,并没有用到),r2暂存器的值是00(并没有用到),pc计数器的值是04(即将执行下一指令)。结果正确。
由此可以看出,这么设置之后整个实验的观测简单了很多,也方便了很多,在这里特别感谢我的搭档俞阳博提出的这么一个想法,我之前自己并没有想到。
五、总结
作为计算机系统原理实验第一部分的最后一个大综合实验,本次实验难度系数高,实验复杂,涉及了开学五个周以来所学习的所有的知识点,而且不仅仅是简单的数据规模以及模块元件上的整合,更重要的是时钟脉冲信号上的整合,通过对t1~t4这四个时钟节拍的合理调用,来调度整个电路的正常进行。
总的来说,在昨晚之前的六个实验之后,模拟机各个组件的实现已经不再是十分困难的存在了,困难的是如何将所有的原件进行组织上和时序上的整合,一旦有什么不对,结果就很容易出差错。我基本上是通过书上的大部分内容进行设计的,在最后加上了少部分自己的一些元件用来确保整个电路的正常进行。
模拟机这个实验设计是我从第四周周二就开始了,一直写了差不多一个周才算基本完成,后来因为强读和强写操作并不是很容易写出来,所以又进行了大量的修改,最终是在第五周的周四全部实现了。
实际上,这次我感觉还是比较简单的,和上学期写CPU时我写了六个CPU才得到一个我比较满意的版本相比,我这次总共就写了两个就基本上实现了,因为做模拟机有书进行对照,所以并不是十分困难。但是不可否认,这次大综合实验非常的繁琐,虽然有了书的指导之后,不再像上学期那样全靠自己摸索,而是终于有迹可循,不过书上的内容也不能全信,我的第一个版本就是因为完全按照书上的指导来进行,所以失败了。这第二个版本我增加了很多我自己的东西,虽然和书上的内容已经不完全一样了,但可以按照我的想法实现指令,而且我个人感觉更加的简单易懂,通俗高效,所以如果说通过这次实验让我明白了什么的话,最大的感触就是必能完全按照书上的指导来进行实验,既然是实验,那么必须要有自己原创的部分,而且,也只有经过自己原创来实现的实验,来完成的功能,才能说明自己已经完完全全的掌握了这个实验怎么进行,怎么操作,还有以后如果想要更改的话,怎么在现有的基础上进行优化和删改。
截止到3月28日晚1点,我设计出来的模拟机已经经过了22次大改,34次功能仿真,14次下载验证,其他大大小小的改动不计其数,最终得到的版本已经是我觉得我能达到的巅峰状态了,可以很完美的实现所要求的全部七条指令,可以在01000地址进行判断的时候执行强读RAM和强写RAM的操作,可以说在我能够想到的所有的测试情况中已经没有任何的bug了,我也觉得仅凭我自己已经没有办法再做什么大型的优化了。
六、以下是我的实验日志:
时间:3月19日
地点:工训中心
内容:主要还是完成控制器,对于控制器的rom的设计还是感觉没有底气,总感觉有些rom的指令有问题,但不知道哪里有问题,将微程序控制器进行连线,看了一下模拟机的指导,感觉前途灰暗。。。
时间:3月20日
地点:305宿舍
内容:和舍友冯昂的rom的信号设计进行和相互的比较,讨论之后感觉收获很大,修改了很多,但是微程序控制器的时钟信号感觉出现了一些问题,还需要进行修改
晚上12点,已经完成了微程序控制器的修改,仿真的结果感觉也没有问题,接下来就剩下载验证了
时间:3月21日
地点:工训中心&305宿舍
内容:完成了微程序控制器的下载验证,感觉没有问题,可以单拍运行也可以持续运行,但感觉并不是太懂如何操作,还是需要再熟悉一下。模拟机正式开始,将各个元件进行了创立,并在工程中进行了连接,但感觉并没有什么头绪,肯定不能简单的进行连接,还需要进一步地阅读资料才行
时间:3月23日
地点:工管院
内容:完成了模拟机的第一个版本,但感觉。。。怎么说呢。。。很乱,信号乱七八糟,而且大部分都是一堆的叉号,不能用,绝对有问题,还是不能完全按照树上的来,书上的很多元件的很多端口之前设计的实验中都没有,不能完全按照书上来,这个应该就是废掉了,还需要一个新的版本进行设计。
时间:3月25日
地点:工训中心
内容:完成了模拟机的训练题(训练七),感觉懂了很多,之前一直不明白为什么会有四个时钟周期,也不懂为什么会有那么多的信号(28个,真的搞人),还是需要再看一下书,感觉书上的另外几个图还是有些用的,比方说那个时序的图
时间:3月27日
地点:305宿舍
内容:将第二个版本初步连接出来了,感觉还不错,图形上没有问题,但时序上的整合还是需要设计
时间:3月28日
地点:工训中心&305宿舍
内容:第二个版本的电路整合已经没有问题了,对于时序的设计感觉也没有问题了,但一直有一个死循环,而且不是一直死循环,是前两个指令运行正常,在一个010指令运行的时候就读不进去,而且ir寄存器的输入,控制信号都引出来进行查看了,也没有问题,不知道到底为什么
晚上8点30分,总算查出来了,错了一个字母。。。
没有问题了,只是还是需要对强读强写信号进行一下设计,感觉虽然可以进入强读和强写的循环,但是没有办法对pc进行一个写的操作,还是需要更正和优化。
晚上10点20分,完成了强读信号和强写信号的优化,感觉已经没有什么明显的bug了,至少我已经找不出来了,开始写实验报告好了。
晚上11点30分,完成了实验报告的初稿
计算机系统实验:模型机(十六)另一篇?相关推荐
- [Python从零到壹] 三十六.图像处理基础篇之图像算术与逻辑运算详解
欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...
- C/C++基础讲解(八十六)之游戏篇(解救人质游戏)
C/C++基础讲解(八十六)之游戏篇(解救人质游戏) 程序之美 前言 很多时候,特别是刚步入大学的学子们,对于刚刚开展的计算机课程基本上是一团迷雾,想要弄明白其中的奥秘,真的要花费一些功夫,我和大家一 ...
- ArcGIS 实验理论基础二十六 中国人口密度图的制作
实验27 中国人口密度图的制作 实验目的 了解专题地图的组成要素 掌握专题电子地图的制作方法 实验内容 制作中国人口密度电子地图 实验原理 专题地图突出反映一种或几种主体要素或现象 专题地图由图形要素 ...
- 山东大学软件学院项目实训-创新实训-网络安全靶场实验平台(十六)
目录 一.什么是目录遍历漏洞? 二.后端实现 三.前端代码 四.效果图 前言:本篇博客主要记录目录遍历漏洞的实现. 一.什么是目录遍历漏洞? 目录遍历(也称为文件路径遍历)是一个Web安全漏洞,它使攻 ...
- 内网渗透(四十六)之横向移动篇-使用系统漏洞ms17010横向移动
系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内 ...
- 【.NET Core项目实战-统一认证平台】第十六章 网关篇-Ocelot集成RPC服务
一.什么是RPC RPC是"远程调用(Remote Procedure Call)"的一个名称的缩写,并不是任何规范化的协议,也不是大众都认知的协议标准,我们更多时候使用时都是创建 ...
- K8S 快速入门(十六)实战篇:StorageClass(存储类)
StorageClass 存储类 官方文档 上一节演示了 PVC的自动化实现方式:利用volumeClaimTemplates 这一节将讲解PV的自动化: 利用StorageClass实现,可以根据P ...
- 基本模型机的设计与实现
一.实验目的 在掌握部件单元电路的实验的基础上,构造一台基本模型计算机. 为其定义五条机器指令,并编写相应的微程序,上机调试掌握整机概念 二.实验设备 Dais-CMX16+ 计算机组成原理教学实验系 ...
- [Python从零到壹] 五十六.图像增强及运算篇之图像平滑(中值滤波、双边滤波)
欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...
- [Python从零到壹] 三十九.图像处理基础篇之图像几何变换(镜像仿射透视)
欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...
最新文章
- 病毒周报(071029至071104)
- 算法------数组---------存在重复元素
- golang变量作用域
- 数学告诉你家庭关系的奥秘
- Github:视觉问答最新资源汇总
- php form 后台函数,Discuz!开发之后台表单生成函数介绍
- axios请求跨域前端解决_Vue-创建axios实例并实现跨域请求(完整过程-前端)
- C++类的构造函数、析构函数与赋值函数
- 计算机哪个专业学linux_5种用于计算机维修的专业Linux发行版
- android 车牌输入键盘
- 计算机程序停止工作怎么办,如何将“某某程序已正常停止工作,请关闭程序”这个提示自动关闭...
- Scala zio-actors与akka-actor集成
- 华为s5700交换机IP地址与MAC地址绑定
- 3.正态分布概率模型下的最小错误率贝叶斯决策MATLAB程序代码
- Magic Leap开发指南(7)-- 眼球追踪(Unity)
- C++PrimePlus第5章编程练习答案及运行结果
- 抖音直播带货复盘数据怎么分析?3个小技巧快速掌握直播复盘
- 用python的turtle模块给女票画个小心心
- 给中国学生的第三封信——成功、自信、快乐
- xpath解析爬虫爬取豆瓣图书Top250的数据
热门文章
- pandas学习task10时序数据
- 2022年电工杯赛题A
- 查找算法-4种常用的查找算法
- 2022-2028年全球及中国多功能示波器行业投资前景分析
- M33.搜索旋转排序数组
- CSS(长度单位,RGB值,盒子模型)
- 51单片机通过两片74HC595级联,用8位LED数码管,分别显示当前日期,如:“2”、“0”、“-”、“0”、“5”、“-”、“2”、“6”,用Proteus仿真实现。
- 施努卡:机器视觉系统作用是什么,原理是什么
- NLP之基于Transformer的句子翻译
- 地理信息系统名词解释大全(一)