一、概述

串行CPU工作流程

串行CPU的时序流程如下图所示:取指、译码、执行、回写。 其中,取指、回写是与存储器打交道;而译码与执行则是CPU内部自个儿的操作。

我们究竟想要CPU干什么?

    CPU的最终目的不是计算,不是把计算结果存储在通用寄存器中。CPU的最终目的应该是按照次序不断的修改存储设备的存储内容。

利用CPU来显示,来唱歌······只有CPU把计算的结果存放在存储设备中的时候(姑且把修改特殊功能寄存器的值也看做是修改存储器的内容),才能实现这些功能。正如假设霍金有个很好的头脑来思考问题,但是假如他不能将思考到的东西通过某种方式告诉别人,那么没人会注意他。

提出这个问题,主要是想要你关注“回写”的重要性。

二、各组成模块

本文的所有VHDL程序摘自《开放式实验CPU设计》第二章 “16位实验CPU设计实例”。

1、通用寄存器组成部分 (regfile)

 --实验6.——实验CPU:通用寄存器组
library IEEE;
use IEEE.STD_LOGIC_1164.ALL; entity regfile is
Port ( DR: in std_logic_vector( downto );
SR: in std_logic_vector( downto );
reset: in std_logic;
DRWr: in std_logic;
clk: in std_logic;
d_input: in std_logic_vector( downto );
DR_data: out std_logic_vector( downto );
SR_data: out std_logic_vector( downto )
);
end regfile; architecture struct of regfile is
-- components
-- bit Register for register file
component reg
port (
clr: in std_logic;
D: in std_logic_vector( downto );
clock: in std_logic;
write: in std_logic;
sel: in std_logic;
Q: out std_logic_vector( downto )
);
end component; -- to Decoder
component decoder_2_to_4
port(
sel: in std_logic_vector( downto );
sel00: out std_logic;
sel01: out std_logic;
sel02: out std_logic;
sel03: out std_logic
);
end component; -- to line multiplexer
component mux_4_to_1
port (
input0,
input1,
input2,
input3: in std_logic_vector( downto );
sel: in std_logic_vector( downto );
out_put: out std_logic_vector( downto ));
end component; signal reg00, reg01, reg02, reg03
:std_logic_vector( downto ); signal sel00 ,sel01 ,sel02 ,sel03
: std_logic; begin
Areg00: reg port map(
clr => reset,
D => d_input ,
clock => clk ,
write => DRWr ,
sel => sel00 ,
Q => reg00
); Areg01: reg port map(
clr => reset,
D => d_input ,
clock => clk ,
write => DRWr ,
sel => sel01 ,
Q => reg01
); Areg02: reg port map(
clr => reset,
D => d_input ,
clock => clk ,
write => DRWr ,
sel => sel02 ,
Q => reg02
); Areg03: reg port map(
clr => reset,
D => d_input ,
clock => clk ,
write => DRWr ,
sel => sel03 ,
Q => reg03
); -- decoder
des_decoder: decoder_2_to_4 port map
(
sel => DR,
sel00 => sel00 ,
sel01 => sel01 ,
sel02 => sel02 ,
sel03 => sel03
); mux1: mux_4_to_1 PORT MAP(
Input0 => reg00 ,
Input1 => reg01 ,
Input2 => reg02 ,
Input3 => reg03 ,
sel => DR ,
out_put => DR_data
); mux2: mux_4_to_1 PORT MAP(
input0 => reg00 ,
input1 => reg01 ,
input2 => reg02 ,
input3 => reg03 ,
sel => SR ,
out_put => SR_data
); end struct;

regfile

如上图所示:

(1)通用寄存器组是即可以读(两个口可以读),又可以写(只有一个口)

(2)通用寄存器组是CPU暂存数据的单元;这里还包括程序状态标志位,跳转指令会用到

2、取指部分 (instru_fetch)

 library ieee, my_lib;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use my_lib.exp_cpu_components.all; entity instru_fetch is
port(reset,clk: in std_logic;
data_read: in std_logic_vector( downto ); --存储器读出的数
lj_instruct: in std_logic; --长转移指令
DW_intruct: in std_logic;
c_z_j_flag: in std_logic; --为1时进行条件转移
sjmp_addr: in std_logic_vector( downto ); --条件转移指令的转移地址
t1,t2,t3: buffer std_logic;
pc: buffer std_logic_vector( downto );
pc_inc: buffer std_logic_vector( downto );
IR: out std_logic_vector( downto )
);
end instru_fetch; architecture behav of instru_fetch is
signal start: std_logic; begin
IR_poc: process(reset,t2)
begin
if reset = '' then
IR <= x""; --nop指令
elsif t2'event and t2 = '' then
IR <= data_read;
end if;
end process; process(reset,clk)
begin
if reset = '' then
start <= '';
else
if clk'event and clk ='' then
start <= '';
end if;
end if;
end process; process(reset,clk)
begin
if reset = '' then
t1 <= '';
t2 <= '';
t3 <= '';
elsif clk'event and clk = '' then
t1 <= start or t3;
t2 <= t1;
t3 <= t2;
end if;
end process; pc_inc <= pc + ''; --为取双字指令的第2个字或者计算相对转移地址做准备
PC_proc: process(reset,t3)
begin
if reset = '' then
pc <= x"";
elsif t3'event and t3 = '' then
if lj_instruct = '' then
pc <= data_read;
elsif c_z_j_flag ='' then
pc <= sjmp_addr;
elsif DW_intruct = '' then
pc <= pc + "";
else
pc <= pc_inc;
end if;
end if;
end process; end behav;

instru_fetch

(1)其实我更愿意把这部分分成两个部分,一个是取指模块,一个是控制器模块(产生CPU时序信号)

(2)取指部分是在t2的上升沿完成的

(3)PC的更新是在t3的下降沿完成的

3、指令译码部分 (decoder_unit)

 library ieee, my_lib;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use my_lib.exp_cpu_components.all; entity decoder_unit is
port (IR: in std_logic_vector( downto );
SR: out std_logic_vector( downto );
DR: out std_logic_vector( downto );
op_code: out std_logic_vector( downto );
zj_instruct: out std_logic;
cj_instruct: out std_logic;
lj_instruct: out std_logic;
DRWr: buffer std_logic; --为1时写DR寄存器
Mem_Write: out std_logic;
DW_intruct: buffer std_logic;
change_z: out std_logic;
change_c: out std_logic;
sel_memdata: out std_logic; --为1时存储器的读出数据作为写入DR的数据
r_sjmp_addr: out std_logic_vector( downto ) --相对转移地址
);
end decoder_unit; architecture behav of decoder_unit is begin SR <= IR( downto );
DR <= IR( downto );
sel_memdata <= IR() and IR() and (not IR());
change_z <= not IR() and IR();
change_c <= not IR() and IR(); DRWr_proc: process(IR)
begin
if IR() = '' then
if IR() ='' then
DRWr <= '';
else
DRWr <= '';
end if;
elsif IR() = '' and IR() = '' then
DRWr <= '';
else
DRWr <= '';
end if;
end process; sj_addr_proc: process(IR) --条件转移指令的相对转移地址从8位扩展到16位
begin
if IR() ='' then
r_sjmp_addr <= "" & IR( downto );
else
r_sjmp_addr <= "" & IR( downto );
end if;
end process; M_instruct:process(IR)
begin
case IR( downto ) is
when "" | "" => --jmp addr;mvDR dr,data
Mem_Write <= '';
DW_intruct <= '';
when "" => -- str dr,sr
Mem_Write <= '';
DW_intruct <= '';
when others =>
Mem_Write <= '';
DW_intruct <= '';
end case;
end process; ALUOP_CODE_PROC: PROCESS(IR)
begin
if IR() = '' then
op_code <= IR( downto );
else
op_code <= "";
end if;
end process; Jinstruct_PROC: process(IR)
begin
case IR( downto ) is
when "" => --jmp adr
zj_instruct <= '';
cj_instruct <= '';
lj_instruct <= '';
when "" => --jnc addr
zj_instruct <= '';
cj_instruct <= '';
lj_instruct <= '';
when "" => --jnz addr
zj_instruct <= '';
cj_instruct <= '';
lj_instruct <= '';
when others =>
zj_instruct <= '';
cj_instruct <= '';
lj_instruct <= '';
end case;
end process; end behav;

decoder_unit

(1)指令译码部分非常简单,是纯逻辑电路(速度非常快)。此模块根据指令暂存器IR特定的位,程序状态标志位c、z再结合设计好的指令系统将指令翻译出来。

(2)译码的时机是在t2的高电平期间

4、执行部分 (exe_unit)

 library ieee, my_lib;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use my_lib.exp_cpu_components.all; entity exe_unit is
port(
t1: in std_logic;
op_code: in std_logic_vector( downto );
zj_instruct: in std_logic;
cj_instruct: in std_logic;
pc: in std_logic_vector( downto );
pc_inc: in std_logic_vector( downto );
c_in: in std_logic; --以前指令产生的进位C
z_in: in std_logic; --以前指令产生的Z
Mem_Write: in std_logic; --为1时,写存储器
c_tmp: out std_logic;
z_tmp: out std_logic;
c_z_j_flag: out std_logic; --为1时进行条件转移
r_sjmp_addr: in std_logic_vector( downto ); --相对转移地址
DW_intruct: in std_logic;
sjmp_addr: out std_logic_vector( downto ); --条件转移指令的转移地址
SR_data: in std_logic_vector( downto );
DR_data: in std_logic_vector( downto );
Mem_Addr: out std_logic_vector( downto );
result: out std_logic_vector( downto ) --运算结果
); end exe_unit; architecture behav of exe_unit is
signal A,B :std_logic_vector( downto );
signal result_t: std_logic_vector( downto ); begin
c_z_j_flag <= ( (not c_in) and cj_instruct) or ((not z_in) and zj_instruct);
A <= DR_data;
B <= SR_data;
sjmp_addr <= pc_inc + r_sjmp_addr; Mem_Addr_proc: process(t1,SR_DATA,pc,DW_intruct)
begin
if t1 = '' then
Mem_Addr <= pc;
else
if DW_intruct = '' then
Mem_Addr <= pc_inc;
elsif Mem_Write = '' then
Mem_Addr <= DR_data;
else
Mem_Addr <= SR_data;
end if;
end if;
end process; alu_proc:process(op_code,A,B)
begin
case op_code is
when "" =>
result_t <= ('' & A) + ('' & B);
when "" =>
result_t <= ('' & A) + '';
when "" =>
result_t <= ('' & A) - ('' & B);
when "" =>
result_t <= ('' & A) - '';
when "" =>
result_t <= ('' & A) and ('' & B);
when "" =>
result_t <= ('' & A) or ('' & B);
when "" =>
result_t <= not ('' & A);
when "" =>
result_t <= ('' & B);
end case;
end process;
result <= result_t( downto );
c_tmp <= result_t();
z_tmp <= (not result_t()) and (not result_t()) and
(not result_t()) and (not result_t()) and
(not result_t()) and (not result_t()) and
(not result_t()) and (not result_t()) and
(not result_t()) and (not result_t()) and
(not result_t()) and (not result_t()) and
(not result_t()) and (not result_t()) and
(not result_t()) and (not result_t()); end behav;

exe_unit

(1)执行部分的主体也是纯逻辑电路,根据译码模块产生的控制信号,执行不同的运算,并将结果输出。

(2)执行的时机是在t2的高电平期间

5、存储器部分 (memory_unit)

 library IEEE, my_lib;
use IEEE.std_logic_1164.all;
use my_lib.exp_cpu_components.all; entity memory_unit is
port(
reset: in std_logic;
clk,t3: in std_logic;
Mem_addr: in std_logic_vector( downto );
Mem_Write: in std_logic;
sel_memdata: in std_logic; --为1时存储器的读出数据作为写入DR的数据
SR_data: in std_logic_vector( downto ); --写存储器的数据
result: in std_logic_vector( downto ); --运算结果
rw: out std_logic;
ob: inout std_logic_vector( downto );
ar: out std_logic_vector( downto );
data_read: buffer std_logic_vector( downto ); --从存储器读出的指令或者数据
DR_data_out: out std_logic_vector( downto ) --写入DR的数据
);
end memory_unit; architecture behav of memory_unit is
begin ar <= Mem_addr;
R_W_Memory_proc: process(reset,ob,SR_DATA,clk,t3,Mem_Write) --读写存储器处理
begin
if reset = '' then
rw <= '';
ob <= "ZZZZZZZZZZZZZZZZ"; --将存储器数据总线置为高阻,读存储器
else
if Mem_Write = '' and t3 = '' then
ob <= SR_DATA; --写存储器
rw <= clk;
else
ob <= "ZZZZZZZZZZZZZZZZ"; --将存储器数据总线置为高阻,读存储器
rw <= '';
data_read <= ob;
end if;
end if;
end process; sele_DR_proc: process(sel_memdata,data_read,result)
begin
if sel_memdata = '' then
DR_data_out <= data_read; --存储器数据作为写DR的数据
else
DR_data_out <= result; --运算结果作为写DR的数据
end if;
end process; end behav;

memory_unit

(1)存储器控制部分主要是完成存储器的读写控制,以及通用寄存器的写控制。

(2)写memory是在clk的下降沿(t3高电平期间),写DR是在t3的下降沿

6、程序包(exp_cpu_components)

 library ieee;
use ieee.std_logic_1164.all; package exp_cpu_components is
component reg port
(reset: in std_logic;
d_input: in std_logic_vector( downto );
clk: in std_logic;
write: in std_logic;
sel: in std_logic;
q_output: out std_logic_vector( downto )
);
end component; component mux_4_to_1 port
(
input0,
input1,
input2,
input3: in std_logic_vector( downto );
sel: in std_logic_vector( downto );
out_put: out std_logic_vector( downto )
);
end component; component decoder_2_to_4 port
(
sel: in std_logic_vector( downto );
sel00: out std_logic;
sel01: out std_logic;
sel02: out std_logic;
sel03: out std_logic
);
end component; component regfile Port
(DR: in std_logic_vector( downto );
SR: in std_logic_vector( downto );
reset: in std_logic;
write: in std_logic;
clk: in std_logic;
d_input: in std_logic_vector( downto );
change_z: in std_logic;
change_c: in std_logic;
c_in: in std_logic;
z_in: in std_logic;
R0,R1,R2,R3: out std_logic_vector( downto );
output_DR: out std_logic_vector( downto );
output_SR: out std_logic_vector( downto );
c_out: out std_logic;
z_out: out std_logic
);
end component; component instru_fetch port
(
reset,clk: in std_logic;
data_read: in std_logic_vector( downto ); --存储器读出的数
lj_instruct: in std_logic; --长转移指令
DW_intruct: in std_logic; --双字指令
c_z_j_flag: in std_logic; --为1时进行条件转移
sjmp_addr: in std_logic_vector( downto ); --条件转移指令的转移地址
t1,t2,t3: buffer std_logic;
pc: buffer std_logic_vector( downto );
pc_inc: buffer std_logic_vector( downto );
IR: out std_logic_vector( downto )
);
end component; component decoder_unit port
(IR: in std_logic_vector( downto );
SR: out std_logic_vector( downto );
DR: out std_logic_vector( downto );
op_code: out std_logic_vector( downto );
zj_instruct: out std_logic;
cj_instruct: out std_logic;
lj_instruct: out std_logic;
DRWr: buffer std_logic; --为1时写DR寄存器
Mem_Write: out std_logic;
DW_intruct: buffer std_logic;
change_z: out std_logic;
change_c: out std_logic;
sel_memdata: out std_logic; --为1时存储器的读出数据作为写入DR的数据
r_sjmp_addr: out std_logic_vector( downto ) --相对转移地址
);
end component; component exe_unit port
(t1: in std_logic;
op_code: in std_logic_vector( downto );
zj_instruct: in std_logic;
cj_instruct: in std_logic;
pc: in std_logic_vector( downto );
pc_inc: in std_logic_vector( downto );
c_in: in std_logic; --以前指令产生的进位C
z_in: in std_logic; --以前指令产生的Z
Mem_Write: in std_logic; --为1时,写存储器
c_tmp: out std_logic;
z_tmp: out std_logic;
c_z_j_flag: out std_logic; --为1时进行条件转移
r_sjmp_addr: in std_logic_vector( downto ); --相对转移地址
DW_intruct : in std_logic;
sjmp_addr: out std_logic_vector( downto ); --条件转移指令的转移地址
SR_data: in std_logic_vector( downto );
DR_data: in std_logic_vector( downto );
Mem_Addr: out std_logic_vector( downto );
result: out std_logic_vector( downto ) --运算结果
);
end component; component memory_unit port
(reset: in std_logic;
clk,t3: in std_logic;
Mem_addr: in std_logic_vector( downto );
Mem_Write: in std_logic;
sel_memdata: in std_logic; --为1时存储器的读出数据作为写入DR的数据
SR_data: in std_logic_vector( downto ); --写存储器的数据
result: in std_logic_vector( downto ); --运算结果
rw: out std_logic;
ob: inout std_logic_vector( downto );
ar:out std_logic_vector( downto );
data_read: buffer std_logic_vector( downto ); --从存储器读出的指令或者数据
DR_data_out: out std_logic_vector( downto ) --写入DR的数据
);
end component;
end exp_cpu_components;

exp_cpu_components

将各个模块打包成一个元件库,为设计顶层实体提供方便。

7、顶层设计实体 (exp_cpu)

--实验6.——实验CPU:CPU调试
library ieee, my_lib;
use ieee.std_logic_1164.all;
use my_lib.exp_cpu_components.all; entity exp_cpu is port
(
clk: in std_logic; --//系统时钟
reset: in std_logic; --//系统复位信号
reg_sel: in std_logic_vector( downto ); --选择寄存器
reg_content: out std_logic_vector( downto ); --寄存器输出
c_flag: out std_logic;
z_flag: out std_logic;
WE: out std_logic; --//读写内存控制信号
AR: out std_logic_vector( downto ); --//读写内存地址
OB: inout std_logic_vector( downto ) --//外部总线
);
end exp_cpu; architecture behav of exp_cpu is
--instru_fetch out
signal t1,t2,t3: std_logic;
signal pc,pc_inc,IR: std_logic_vector( downto );
--decoder_unit out
signal SR,DR: std_logic_vector( downto );
signal op_code: std_logic_vector( downto );
signal zj_instruct,cj_instruct,lj_instruct: std_logic;
signal DRWr,Mem_Write,DW_intruct,change_z: std_logic;
signal change_c,sel_memdata: std_logic;
signal r_sjmp_addr: std_logic_vector( downto );
--exe_unit out
signal c_tmp,z_tmp,c_z_j_flag: std_logic;
signal Mem_Addr,result,sjmp_addr: std_logic_vector( downto );
--memory out
signal data_read,DR_data_out: std_logic_vector( downto );
--regfile out
signal R0,R1,R2,R3: std_logic_vector( downto );
signal output_DR,output_SR: std_logic_vector( downto );
signal c_out,z_out: std_logic;
begin
c_flag <= c_out;
z_flag <= z_out; TEST_OUT: process(reg_sel) --被测信号以寄存器内容输出
begin
case reg_sel is
when "" =>
reg_content <= R0;
when "" =>
reg_content <= R1;
when "" =>
reg_content <= R2;
when "" =>
reg_content <= R3;
when "" =>
reg_content <= "" & t3 & "" & t2 & "" & t1;
when "" =>
reg_content <= pc;
when "" =>
reg_content <= IR;
when others =>
reg_content <= x"";
end case;
end process;
--reg_content <= R0; --实际测试中是用这句话代替了上边的进程,也就是说默认选择R0作为要输出显示的寄存器 G_INSTRU_FETCH: instru_fetch port map
(reset => reset,
clk => clk,
data_read => data_read, --存储器读出的数
lj_instruct => lj_instruct, --来自decoder的长转移指令标志
DW_intruct => DW_intruct, --来自decoder的双字指令标志
c_z_j_flag => c_z_j_flag, --为1时进行条件转移,来自EXE
sjmp_addr => sjmp_addr, --条件转移指令的转移地址,来自EXE
t1 => t1,
t2 => t2,
t3 => t3,
pc => pc,
pc_inc => pc_inc,
IR => IR
); G_DECODER: decoder_unit port map
(IR => IR, --来自instru_fetch
SR => SR, --源寄存器号
DR => DR, --目的寄存器号
op_code => op_code, --ALU运算的操作码
zj_instruct => zj_instruct, --为1时是如果Z=0则转移指令
cj_instruct => cj_instruct, --为1时是如果C=0则转移指令
lj_instruct => lj_instruct, --为1时是无条件长转移指令
DRWr => DRWr, --为1时在t3下降沿写DR寄存器,送往regfile
Mem_Write => Mem_Write, --为1时对存储器进行写操作。
DW_intruct => DW_intruct, --为1时是双字指令
change_z => change_z, --为1时在t3下降沿根据指令执行结果置Z标志
change_c => change_c, --为1时在t3下降沿根据指令执行结果置Z标志
sel_memdata => sel_memdata, --为1时存储器的读出数据作为写入DR的数据
r_sjmp_addr => r_sjmp_addr --相对转移地址
); G_EXE: exe_unit port map
(
t1 => t1,
op_code => op_code, --ALU运算的操作码,来自decoder
zj_instruct => zj_instruct, --为1时是如果Z=1则转移指令,来自decoder
cj_instruct => cj_instruct, --为1时是如果C=1则转移指令,来自decoder
pc => pc, --来自instru_fetch
pc_inc => pc_inc, --来自instru_fetch
c_in => c_out,--以前指令产生的进位C,来自regfile
z_in => z_out, --以前指令产生的Z,来自regfile
Mem_Write => Mem_Write, --存储器写,来自decoder_unit
c_tmp => c_tmp, --本条指令产生的Z标志送往regfile
z_tmp => z_tmp, --本条指令产生的Z标志送往regfile
c_z_j_flag => c_z_j_flag, --为1时进行条件转移,送往instru_fetch
r_sjmp_addr => r_sjmp_addr, --相对转移地址,来自decoder
DW_intruct => DW_intruct, --双字指令标志,来自decoder,送往
sjmp_addr => sjmp_addr,--条件转移指令的转移地址instru_fetch
SR_data => output_SR, --SR寄存器值,来自regfile
DR_data => output_DR, --SR寄存器值,来自regfile
Mem_Addr => Mem_Addr, --存储器地址,送往memory
result => result --运算结果,送往regfile
); G_MEMORY: memory_unit port map
(reset => reset,
clk => clk,
t3 => t3,
Mem_addr => Mem_addr, --存储器地址,来自exe_unit
Mem_Write => Mem_Write, --存储器写,来自decoder_unit
sel_memdata => sel_memdata, --为1时存储器的读出数据作为写入DR的数据,来自decoder
SR_data => output_SR,--写存储器的数据,来自regfile
result => result, --运算结果,来自exe_unit
rw => WE, --存储器读写信号,送往芯片外部
ob => ob, --存储器数据总线,和芯片外部存储器数据总线连接
ar => AR, --存储器地址,送往芯片外部和存储器地址总线连接
data_read => data_read, --从存储器读出的指令,送往instru_fetch
DR_data_out => DR_data_out --写入DR的数据,送往regfile
); G_REGFILE: regfile port map
(DR => DR, --DR寄存器号,来自decoder
SR => SR, --SR寄存器号,来自decoder
reset => reset,
write => DRWr, --寄存器写控制信号,来自decoder
clk => t3, --寄存器写入脉冲,来自instru_fetch,下降沿写入
d_input => DR_data_out, --写入寄存器的数据,来自memory
change_z => change_z, --为1时在t4下降沿根据Z_tmp置Z标志,来自decoder
change_c => change_c, --为1时在t4下降沿根据C_tmp置C标志,来自decoder
c_in => c_tmp, --本条指令得到的c,来自decoder
z_in => z_tmp, --本条指令得到的c,来自decoder
R0 => R0,
R1 => R1,
R2 => R2,
R3 => R3,
output_DR => output_DR, --DR寄存器内容,送往exe和memory
output_SR => output_SR, --SR寄存器内容,送往exe
c_out => c_out, --C标志,送往exe和exp
z_out => z_out --Z标志,送往exe和exp
); end behav;

exp_cpu

(1)此部分代码实际上就是如上图所示那样,用导线将CPU的各个独立模块连接在一起,构成一个完整的CPU

(2)此外该部分还加入了测试模块,以便将寄存器的内容或者PC的值从内部引出到外部,供我们去观察

三、实验环节

1、实验目的

测试串行CPU的能否按照预期指令功能那样正常工作

2、实验方法

给CPU配以程序存储器ROM(内含三条指令),CPU在低速时钟运行条件下,执行指令,并且将执行指令而改变的寄存器内容引出来通过8位led显示出来。

3、实验内容

(1)实验电路图

(1)开发板上的时钟是50MHz,经过50M的分频,实际输送给CPU的主频才1Hz。设置如此低的频率,目的是为了有足够的时间观察每一条指令的执行效果。

(2)PLL分频后的时钟10MHz送给了ROM,因为ROM也需要时钟线。本实验用ROM代替了RAM(HM6116),显然缺失了写的功能。为了让该ROM的操作如同可读静态RAM(HM6116)一样,用10MHz的时钟。可以看到,只要给ROM发送地址,ROM马上就把相应的数据发送出来。

(1)给ROM加一个16位地址变换为8位地址的目的是,本实验不需要用那么大的存储器,所以讲容量调整的小一点。

(2)本实验的输出寄存器直接是R0的内容,这一点在之前也有提到。由于实验板上只有8位led,所以执行指令的功能也只是改变R0的低8位。所以,高8位没必要保留,就通过加上一个地址变换器滤除无用的高8位。

(2)实验CPU程序

ROM存储器中的数据

翻译成指令:

  movrd r0,#2

  movrd r0,#8

  movrd r0,#6

(3)实验效果

1、可以看到CPU如预期那样每3s(1条指令3个时钟周期),灯变换一次(执行一条指令)

2、灯按照预先设定的数据那样点亮。

(4)调试过程

本来暑假做实验时,用书上的程序编译后是能运行的。但是,春节后对学习过程进行整理过程中,发现书上的例程在quartus9.1版本编译后不能运行。经检测,问题出在节拍控制上(t1、t2、t3)。需要修改instruction_fetch文件中相应的程序才能成功运行。

4、实验结论

(1)CPU就是用数字电路搭建起来的

(2)CPU的基本结构是很简单的

参考:《开放式实验CPU设计》

串行CPU设计的更多相关文章

  1. 基于RocketIO的高速串行协议设计与实现

    随着对信息流量需求的不断增长, 传统并行接口技术成为进一步提高数据传输速率的瓶颈.过去主要用于光纤通信的串行通信技术—SERDES正在取代传统并行总线而成为高速接口技术的主流.SERDES 是串行器) ...

  2. Verilog学习笔记简单功能实现(七)...............接口设计(并行输入串行输出)

    利用状态机实现比较复杂的接口设计: 这是一个将并行数据转换为串行输出的变换器,利用双向总线输出.这是由EEPROM读写器的缩减得到的,首先对I2C总线特征介绍: I2C总线(inter integra ...

  3. 痞子衡嵌入式:揭秘i.MXRT1060,1010上串行NOR Flash冗余程序启动设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1060,1010上串行NOR Flash冗余程序启动设计. 工业产品设计里经常会有冗余程序/备份程序设计的需求,因为在工业 ...

  4. 痞子衡嵌入式:揭秘i.MXRT1170上串行NOR Flash双程序可交替启动设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上串行NOR Flash双程序可交替启动设计. 在上一篇文章 <i.MXRT1060/1010上串行NOR F ...

  5. 痞子衡嵌入式:揭秘i.MXRTxxx系列上串行NOR Flash双程序可交替启动设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT500/600上串行NOR Flash双程序可交替启动设计. 在上一篇文章 <i.MXRT1170上串行NOR Fla ...

  6. 大叔也说并行和串行`性能提升N倍(N由操作系统位数和cpu核数决定)

    返回目录 并行是.net4.5主打的技术,同时被封装到了System.Threading.Tasks命名空间下,对外提供了静态类Parallel,我们可以直接使用它的静态方法,它可以并行一个委托数组, ...

  7. 自制单片机之六……串行I2C总线E2PROM AT24CXXX的应用

    这一篇介绍I2C存储器的使用.主要是介绍AT24CXX系列器件,它分为两类,主要是通过被存储容量地址来分的,一类是AT24C02-AT24C16,它的存储容量从256字节到2048字节.另一类是AT2 ...

  8. 原创:应用串行NOR闪存提升内存处理能力

    在嵌入式系统中,NOR闪存一直以来仍然是较受青睐的非易失性内存,NOR器件的低延时特性可以接受代码执行和数据存储在一个单一的产品.虽然NAND记忆体已成为许多高密度应用的首选解决方案,但NOR仍然是低 ...

  9. SPI、I2C、UART三种串行总线协议的区别

    第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynchronous R ...

随机推荐

  1. 从m个数中取top n

    将题目具体一点,例如,从100个数中取出从大到小排前10的数 方法1:使用快速排序 因为快速排序一趟下来,小于K的数都在K的前面,大于K的数都在K的后面 如果,小于K的数有35个,大于K的数有64个 ...

  2. c#语言基础编程—string

    引言 在c#中经常会有相关的string的操作,string类型为引用类型,集成于Object,所以会有四个方法.详情可见 值类型和引用类型的区别 里面详细介绍了,值类型和引用类型的区别和应用场合,所 ...

  3. J2EE ssm框架-服务启动项内存加载数据及读取。

    1.首先在 Web工程 WEB-INF目录下web.xml中添加 listener: <listener> <listener-class>com.founder.frame. ...

  4. 【Android - 进阶】之代码打包签名与混淆

    代码打包签名 Android Studio为大家集成了代码打包混淆的功能,具体操作流程如下组图所示: 1.点击Android Studio上方工具栏的  Build -> Generate Si ...

  5. 【Android - 框架】之Retrofit的使用

    Retrofit是Square公司发布的一个可以应用在Android和Java中的Http客户端访问框架,其底层应用的是OkHttp. 在这个帖子中,我们以下面这个Http请求为例: https:// ...

  6. hdu-5009-Paint Pearls-dp

    由题意我们能够知道,花费最多为n. 所以单次最多涂掉sqrt(n)种颜色. dp[i]:涂到第i个位置.之前的花费最少为多少. biao[i][j]:在第i个位置,往前涂j-1种颜色,涂到哪个位置. ...

  7. 清理yum源

    最近想在美国VPS上装个Wine 可是在执行yum install wine时却遇到了意想不到的错误 系统提示: You could try using –skip-broken to work ar ...

  8. IOS--实现滤镜效果的四种方式

    IOS–实现滤镜效果 demo地址: https://github.com/AbeDay/ios–.git 使用CIFilter来完成IOS中滤镜效果 在IOS中可以使用系统自带的方法来达到路径效果: ...

  9. [转] 用实例给新手讲解RSA加密算法

    http://www.cfca.com.cn/zhishi/wz-012.htm PS: 通常公钥对数据加密,私钥对数据解密:私钥对数据签名,公钥对数据签名进行认证 RSA加密算法是最常用的非对称加密 ...

  10. iOS中__block 关键字的底层实现原理

    在 <iOS面试题集锦(附答案)> 中有这样一道题目: 在block内如何修改block外部变量?(38题)答案如下: 默认情况下,在block中访问的外部变量是复制过去的,即:写操作不对 ...