其他分享
首页 > 其他分享> > 8位12指令硬布线CPU设计

8位12指令硬布线CPU设计

作者:互联网

实验f4a 8位12指令硬布线CPU设计

模型机是计算机的缩细模型,通过它可以理解计算机整机的结构及功能,理解CPU、存储器、中断控制器、接口的结构及实现逻辑和各部件之间的接口关系。本次课程设计的主要内容是利用Intel公司的EPF10K10LC84-4的内部可编程资源,设计一个8位模型计算机。本课程设计的主要目的是通过部件级的8位模型机的设计和调试,使学生掌握计算机工作中“时间—空间”概念的理解,从而清晰地建立计算机的整机概念,并培养学生分析和解决实际问题的能力,同时增强学生的动手能力。
在这里插入图片描述

一、实验目的

(1)融会贯通本课程各章节的内容,通过知识的综合运用,加深对计算机系统各功能部件的工作原理及相互联系的认识,加深计算机工作中“时间—空间”概念的理解,从而清晰地建立计算机的整机概念;

(2)学习设计和调试计算机的基本步骤和方法,提高使用Quartus等软件仿真工具和集成电路的基本技能;

(3)培养科学研究的独立工作能力,取得工程设计与组装调试的实践和经验。
二、设计要求

设计一台硬布线控制器的8位模型计算机,用VHDL语言完成设计并调试成功

三、实验原理

以控制器为中心,首控制器从指令寄存器取得指令,编译指令,再输出微控制信号,控制ALU的运算,PC加一,并且从RAM中取出数据运算,运算后再把结果通过数据总线存到RAM,在指令寄存器读去下一条指令,依次循环。

四、设计内容

请添加图片描述

五、CPU电路图展示

请添加图片描述

六、由六大模块组成模型机仿真图

将这六大模块连成一大整体它产生控制信号也即控制器产生的控制信号控制各大模块的运行,而且它能检测其它部件发送过来的信号,协调各个部件按指令要求完成规定任务,所以它的输出是各大控制信号也即前面涉及到的控制器的控制信号。

七、ram中测试程序,波形图及与指令的对应关系分析,数据运算过程分析

(1)测试程序
在这里插入图片描述
(2)波形图及逐条指令、逐个阶段、逐个操作、逐个部件逐个数据变化的对应关系分析,数据运算过程分析。
请添加图片描述

读取指令

第一步:PC将指令地址通过地址总线给MAR

abus中,若传输的为pc中的值,则为递增从0000到1001(9)的数

此时地址总线数值为0000,0000

第二步:向主存发送读命令

每当PC的值放到数据总线时,PC_enAX为1,即标志PC访问MAR

在该系统中,PC将指令地址直接传给RAM

第三步:将MAR所指的内存单元经过数据总线给MDR

以第一条例子中第一个指令,此时数据总线为0001,0100,即RAM中0号存储单元对应的数据;

第四步:将MDR中的内容给IR,

此时ir_ldx为1,标志被写入数据

第五步:将指令的操作码部分给CU

CU用IR的后4位(4到7位)作为操作码,进行译码;

指令为0001,0100

操作码为0001,存数指令

第六步:形成下一条指令

PC+1

此时,地址总线为0000,0001

执行周期(以存数指令为例)

存数指令

第一步:将指令的地址码(前四位)通过地址总线部分给MAR

指令为0001,0100

地址码为0100

此时地址总线的值为0000,0100

此时pc_enAx为1,标志cu向RAM写入数据

第二步:向主存发读指令

此时mem_rwX为1

第三步:将MDR中的数据写到MAR指定的主存单元内;

此时MDR放的不是指令,而是数据

此时数据总线为0000,0000

此时mem_rw为0,标志写操作

即将数据0000,0000写到4号存储单元;

七、其他测试程序,波形图及与指令的对应关系分析,数据运算过程分析

在这里插入图片描述

(2)波形图及及逐条指令、逐个阶段、逐个操作、逐个部件逐个数据变化的对应关系分析,数据运算过程分析。
请添加图片描述

LOAD 2
PC为0000,0000
PC将指令地址直接传给MAR,MAR通过数据总线传给RAM;
此时地址总线为0000,0000
拿到0号存储单元的指令后经过数据总线给MDR
此时数据总线为0000,0010即指令为0000,0010
操作码为0000,LOAD
地址码为0010,2号存储位
操作码部分给CU;
地址码部分给MAR,MAR通过地址总线给RAM,并将数据通过数据总线给MDR与ACC
此时地址总线为0000,0010
此时数据总线为0001,0010
此时ACC_QX为0001,0010

ADD 3
PC为0000,0001
PC将指令地址直接传给MAR,MAR通过数据总线传给RAM;
此时地址总线为0000,0001
拿到1号存储单元的指令后经过数据总线给MDR
此时数据总线为0010,0011即指令为0010,0011
操作码为0010,ADD
地址码为0011,3号存储体
操作码部分给CU;控制ALU进行加法操作
此时ALU_OP为000
对ACC的内容取反,ACC_QX为1110,1110
地址码部分给MAR,MAR通过地址总线给RAM,并将数据通过数据总线给MDR与ACC
此时地址总线为0000,0011
此时数据总线为0000,0001
此时cu操作ALU_OP为111,ALU完成两树相加
数据总线数值分别为:0001,0010;1110,1110;0000,0001;0010,0011;
得到和0010,0011输出到ACC
此时ACC_QX为0010,0011

STORE 2
PC为0000,0010
PC将指令地址直接传给MAR,MAR通过数据总线传给RAM;
此时地址总线为0000,0010
拿到2号存储单元的指令后经过数据总线给MDR
此时数据总线为0001,0010即指令为0001,0010
操作码为0001,STORE
地址码为0010,2号存储位
操作码部分给CU;
地址码部分给MAR,MAR通过地址总线给RAM,并将数据通过数据总线给MDR与ACC
此时地址总线为0000,0010
此时数据总线为1110,1110
此时mem_rw为0,写入操作

HALT
PC为0000,0011
PC将指令地址直接传给MAR,MAR通过数据总线传给RAM;
此时地址总线为0000,0011
拿到4号存储单元的指令后经过数据总线给MDR
此时数据总线为0000,0001即指令为0000,0001
操作码为HALT,程序结束

八、实验代码

1、	累加寄存器accumulator

library IEEE; 
use IEEE.std_logic_1164.all; 
use IEEE.std_logic_unsigned.all; 

entity accumulator is                   ----声明外部实体接口
    port ( 
        clk, en_D, ld, selAlu, reset: in STD_LOGIC; --时钟信号
        aluD: in STD_LOGIC_VECTOR(7 downto 0); 
        dBus: inout STD_LOGIC_VECTOR(7 downto 0); 
        q: out STD_LOGIC_VECTOR(7 downto 0) 
    ); 
end accumulator; 

architecture accArch of accumulator is 
signal accReg: STD_LOGIC_VECTOR(7 downto 0); 

begin 
  process(clk) begin 
   if clk'event and clk = '1' then 
    if reset = '1' then 
     accReg <= "00000000"; 
    elsif ld = '1' and selAlu = '1' then 
     accReg <= aluD; 
    elsif ld = '1' and selAlu = '0' then 
     accReg <= dBus; 
    end if; 
   end if; 
  end process; 
  dBus <= accReg when en_D = '1' else 
     "ZZZZZZZZ"; 
  q <= accReg; 
end accArch;

2、	算术运算器 ALU

library IEEE; 
use IEEE.std_logic_1164.all; 
use IEEE.std_logic_unsigned.all; 

entity alu is                           -----实体声明外部接口
    port ( 
        op: in STD_LOGIC_VECTOR(3 downto 0);   --选择控制运算类型
        accD: in STD_LOGIC_VECTOR(7 downto 0); -- 累加器的8位数据
        dBus: in STD_LOGIC_VECTOR(7 downto 0); -- 数据总线用于运算
        result: out STD_LOGIC_VECTOR(7 downto 0);   --结果的输出
        accZ: out STD_LOGIC 
); 
end alu; 

architecture aluArch of alu is 
begin 
  result <= (not accD) + "00000001" when op ="0000" else 
       accD + dBus when op ="0001" else 
       accD+"10000000" when op="0010" else
       dBus+"10000000" when op="0011" else 
       (not accD)-"00000001" when op="0100" else 
       accD-dBus when op="0101" else 
       accD*dBus when op="0110" else
       accD*(not dBus) when op="0111" else 
      
       accD AND  dBus when op="1010" else 
       accD NAND dBus when op="1011" else 
       accD OR   dBus when op="1100" else
       accD NOR  dBus when op="1101" else
       accD XNOR dBus when op="1110" else
       NOT accD when op="1111" else 
       "00000000"; 
 accZ <= not (accD(0) or  accD(1) or  accD(2) or  accD(3) or 
          accD(4) or  accD(5) or  accD(6) or  accD(7)
); 
end aluArch;

3、	硬布线控制器(controller)

library IEEE; 
use IEEE.std_logic_1164.all; 
entity controller is                       ----声明实体外部接口
    port ( 
     clk, reset: 
  in  STD_LOGIC; 
     mem_enD, mem_rw:   
out STD_LOGIC; 
     pc_enA, pc_ld, pc_inc:   out STD_LOGIC; 
     ir_enA, ir_enD, ir_ld:   out STD_LOGIC; 
     ir_load, ir_store, ir_add: in  STD_LOGIC; 
     ir_sub,ir_mul,ir_div:  in STD_LOGIC;
     ir_and,ir_or, ir_not:  in STD_LOGIC;
     ir_neg, ir_halt, ir_branch:  in  STD_LOGIC; 
     acc_enD, acc_ld, acc_selAlu:  out STD_LOGIC; 
     alu_op:    out STD_LOGIC_VECTOR(2 downto 0) 
    ); 
end controller; 
architecture controllerArch of controller is 
type state_type is ( reset_state, 
   fetch0, fetch1, 
   load0, load1, 
   store0, store1, 
   add0, add1, 
   sub0, sub1,
   mul0, mul1,
   div0, div1,
   and0, and1,
   or0,  or1,
   not0, not1,
   negate0, negate1, 
   halt, 
   branch0, branch1 
   ); 
signal state: state_type; 
begin 
  process(clk) begin 
   if clk'event and clk = '1' then 
    if reset = '1' then state <= reset_state; 
      else 
       case state is 
       when reset_state => state <= fetch0; 
       when fetch0 => state <= fetch1; 
     when fetch1 => 
      if ir_load = '1' then state <= load0; 
      elsif ir_store   = '1' then state <= store0; 
      elsif ir_add     = '1' then state <= add0; 
      elsif ir_sub     = '1' then state <= sub0;
      elsif ir_mul     = '1' then state <= mul0;
      elsif ir_div     = '1' then state <= div0;
      elsif ir_and     = '1' then state <= and0;
      elsif ir_or      = '1' then state <= or0;
      elsif ir_not     = '1' then state <= not0; 
      elsif ir_neg     = '1' then state <= negate0; 
      elsif ir_halt    = '1' then state <= halt; 
      elsif ir_branch  = '1' then state <= branch0; 
      end if; 
     when load0 =>  state <= load1; 
     when load1 =>  state <= fetch0; 
     when store0 =>  state <= store1; 
     when store1 => state <= fetch0; 
     when add0 =>  state <= add1; 
     when add1 =>  state <= fetch0; 
     when sub0 =>  state <= sub1;
     when sub1 =>  state <= fetch0;
     when mul0 =>  state <= mul1;
     when mul1 =>  state <=fetch0;
     when div0 =>  state <=div1;
     when div1 =>  state <=fetch0;
     when and0 =>  state <=and1;
     when and1 =>  state <=fetch0;
     when or0  =>  state <=or1;
     when or1  =>  state <=fetch0;
     when not0 =>  state <=not1;
     when not1 =>  state <=fetch0;
     when negate0 => state <= negate1; 
     when negate1 => state <= fetch0; 
     when halt =>  state <= halt; 
     when branch0 => state <= branch1; 
     when branch1 => state <= fetch0; 
     when others =>  state <= halt; 
     end case; 
    end if; 
   end if; 
  end process; 
  process(clk) begin -- special process for memory write timing 
   if clk'event and clk = '0' then 
    if state = store0 then 
     mem_rw <= '0'; 
    else 
     mem_rw <= '1'; 
    end if; 
   end if; 
  end process; 
  mem_enD <= '1'   when state =  fetch0 or state =  fetch1 or 
     state =   load0 or state =   load1 or 
     state =    add0 or state =    add1 or
     state =    sub0 or state =    sub1 or
     state =    mul0 or state =    mul1 or
     state =    div0 or state =    div1 or
     state =    and0 or state =    and1 or
     state =    or0  or state =    or1 else '0'; 
  pc_enA <= '1'    when state =  fetch0 or
          state = fetch1   else '0'; 
  pc_ld <= '1'    when state = branch0  
       else '0'; 
  pc_inc <= '1'    when state = fetch1 
       else '0'; 
  ir_enA <= '1'    when state = load0 or 
     state = load1 or state = store0 or
     state =  store1 or state =  add0 or 
     state =  add1 or   state =    sub0 or 
     state =    sub1 or state =    mul0 or
     state =    mul1 or state =    div0 or
     state =    div1 or state =    and0 or
     state =    and1 or state =    or0  or
     state =    or1        else '0'; 
  ir_enD <= '1'    when state = branch0  
       else '0'; 
  ir_ld <= '1'    when state = fetch1 
       else '0'; 
  acc_enD <= '1'   when state =  store0 or state =  store1  else '0'; 
  acc_ld <= '1'    when state =  load1 or state =   add1 or state = negate1  
                   or state =  sub1 or state = mul1 or state = div1
                   or state = not1 or state = or1 or state = not1   else '0'; 
  acc_selAlu <='1' when state = add1 or state = negate1 or state =  sub1 or 
                    state = mul1 or state = div1  or state = not1 or
                    state = or1 or state = not1  else '0'; 
  alu_op <= "000" when state = add0 or state = add1 
       else "001" when state = sub0 or state = sub1
       else "010" when state = mul0 or state = mul1
       else "011" when state = div0 or state = div1
       else "100" when state = negate0 or state = negate1
       else "101" when state = and0 or state = and1
       else "110" when state = or0 or state = or1
       else "111" when state = not0 or state = not1;
       
  --alu_op <= "01"   when state =  add0 or state =  add1  else "00"; 
end controllerArch; 

4、	指令寄存器instruction_register

library IEEE; 
use IEEE.std_logic_1164.all; 

entity instruction_register is          ----声明实体外部接口
    port ( 
        clk, en_A, en_D, ld, reset: in STD_LOGIC; 
        aBus: out STD_LOGIC_VECTOR(7 downto 0); ----数据总线输出
        dBus: inout STD_LOGIC_VECTOR(7 downto 0); 
        load, store, add, sub,mul,div,andd,orr,nott,neg, halt, branch: out STD_LOGIC 
        ); 
end instruction_register; 
architecture irArch of instruction_register is 
signal irReg: STD_LOGIC_VECTOR(7 downto 0); 
begin 
  process(clk) begin 
   if clk'event and clk = '0' then -- load on falling edge 
    if reset = '1' then 
     irReg <= "00000000"; 
    elsif ld = '1' then 
     irReg <= dBus; 
    end if; 
   end if; 
  end process; 
  aBus <= "0000" & irReg(3 downto 0) when en_A = '1' else 
     "ZZZZZZZZ"; 
  dBus <= "0000" & irReg(3 downto 0) when en_D = '1' else 
     "ZZZZZZZZ"; 
  load    <= '1' when irReg(7 downto 4) = "0000"  else '0'; 
  store   <= '1' when irReg(7 downto 4) = "0001"  else '0'; 
  add     <= '1' when irReg(7 downto 4) = "0010"  else '0'; 
  sub     <= '1' when irReg(7 downto 4) = "0011"  else '0';
  mul     <= '1' when irReg(7 downto 4) = "0100"  else '0';
  div     <= '1' when irReg(7 downto 4) = "0101"  else '0';
  neg     <= '1' when irReg = "0110" & "0000"  else '0'; 
  andd    <= '1' when irReg (7 downto 4) = "0111" else '0';
  orr     <= '1' when irReg (7 downto 4) = "1000" else '0';
  nott    <= '1' when irReg (7 downto 4) = "1001" else '0';
  halt    <= '1' when irReg = "1010" & "0001"  else '0'; 
  branch  <= '1' when irReg(7 downto 4) = "1011"  else '0'; 

end irArch; 

5.	程序计数器program_counter

library IEEE; 
use IEEE.std_logic_1164.all; 
use IEEE.std_logic_unsigned.all; 
entity program_counter is 
    port ( 
        clk, en_A, ld, inc, reset: in STD_LOGIC; 
        aBus: out STD_LOGIC_VECTOR(7 downto 0); --数据总线输出
        dBus: in STD_LOGIC_VECTOR(7 downto 0);  --数据总线输入

    ); 
end program_counter; 
architecture pcArch of program_counter is 
signal pcReg: STD_LOGIC_VECTOR(7 downto 0); 
begin 
  process(clk) begin 
   if clk'event and clk = '1' then 
    if reset = '1' then 
     pcReg <= "00000000"; 
    elsif ld = '1' then 
     pcReg <= dBus; 
    elsif inc = '1' then 
     pcReg <= pcReg + "00000001"; 
    end if; 
   end if; 
  end process; 
  aBus <= pcReg when en_A = '1' else "ZZZZZZZZ"; 
end pcArch;

6、	存储器RAM

library IEEE; 
use IEEE.std_logic_1164.all; 
use IEEE.std_logic_arith.all; 
entity ram is 
    port ( 
        r_w, en, reset: in STD_LOGIC; 
        aBus: in STD_LOGIC_VECTOR(7 downto 0);  ----数据总线输入
        dBus: inout STD_LOGIC_VECTOR(7 downto 0) 
    ); 
end ram; 

architecture ramArch of ram is 
type ram_typ is array(0 to 63) of STD_LOGIC_VECTOR(7 downto 0); 
signal ram: ram_typ; 
begin 
  process(
en, reset, r_w, aBus, dBus
) begin 
   if reset = '1' then 
    ram(0) <= x"14"; 
    ram(1) <= x"30"; 
    ram(2) <= x"25"; 
    ram(3) <= x"15"; 
    ram(4) <= x"46"; 
    ram(5) <= x"31"; 
    ram(6) <= x"55"; 
    ram(7) <= x"06"; 
ram(8) <= x"01"; 

  elsif r_w = '0' then 
    ram(conv_integer(unsigned(aBus))) <= dBus; 
   end if; 
  end process; 
  dBus <= ram(conv_integer(unsigned(aBus))) 
    when reset = '0' and en = '1' and r_w = '1' else 
   "ZZZZZZZZ"; 
end ramArch; 

7、	由6大模块组成模型机(top_level)

library IEEE; 
use IEEE.std_logic_1164.all; 
entity top_level is                ----声明实体外部接口
    port ( 
        clk, reset:   
in  STD_LOGIC; 
        abusX:     out STD_LOGIC_VECTOR(7 downto 0); --数据总线输出
        dbusX:     out STD_LOGIC_VECTOR(7 downto 0); 
        mem_enDX, mem_rwX:  
 out STD_LOGIC; 
        pc_enAX, pc_ldX, pc_incX: 
out STD_LOGIC; 
        ir_enAX, ir_enDX, ir_ldX:
 out STD_LOGIC; 
        acc_enDX, acc_ldX, acc_selAluX:
 out STD_LOGIC; 
        acc_QX:    out STD_LOGIC_VECTOR(7 downto 0); 
        alu_accZX:   out STD_LOGIC; 
        alu_opX:   out STD_LOGIC_VECTOR(2 downto 0) 
    ); 
end top_level; 
architecture topArch of top_level is 
component program_counter 
    port ( 
        clk, en_A, ld, inc, reset: in STD_LOGIC; 
        aBus: out STD_LOGIC_VECTOR(7 downto 0); 
        dBus: in STD_LOGIC_VECTOR(7 downto 0) 
    ); 
end component; 
component instruction_register 
    port ( 
        clk, en_A, en_D, ld, reset: in STD_LOGIC; 
        aBus: out STD_LOGIC_VECTOR(7 downto 0); 
        dBus: inout STD_LOGIC_VECTOR(7 downto 0); 
        load, store, add, sub,mul,div,neg,andd,orr,nott, halt, branch: out STD_LOGIC 
           ); 
end component; 
component accumulator 
    port ( 
        clk, en_D, ld, selAlu, reset: in STD_LOGIC; 
        aluD: in STD_LOGIC_VECTOR(7 downto 0); 
        dBus: inout STD_LOGIC_VECTOR(7 downto 0); 
        q: out STD_LOGIC_VECTOR(7 downto 0) 
    ); 
end component; 
component alu 
    port ( 
        op: in STD_LOGIC_VECTOR(2 downto 0); 
        accD: in STD_LOGIC_VECTOR(7 downto 0); 
        dBus: in STD_LOGIC_VECTOR(7 downto 0); 
        result: out STD_LOGIC_VECTOR(7 downto 0); 
        accZ: out STD_LOGIC 
    ); 
end component; 

component ram 
    port ( 
        r_w, en, reset: in STD_LOGIC; 
        aBus: in STD_LOGIC_VECTOR(7 downto 0); 
        dBus: inout STD_LOGIC_VECTOR(7 downto 0) 
    ); 
end component; 
component controller 
    port ( 
     clk, reset:   in  STD_LOGIC; 
     mem_enD, mem_rw:   out STD_LOGIC; 
     pc_enA, pc_ld, pc_inc:   out STD_LOGIC; 
     ir_enA, ir_enD, ir_ld:   out STD_LOGIC; 
     ir_load, ir_store, ir_add: in  STD_LOGIC; 
     ir_sub,  ir_mul, ir_div:  in STD_LOGIC;
     ir_and,  ir_or, ir_not: in  STD_LOGIC;
     ir_neg, ir_halt, ir_branch:  in  STD_LOGIC; 
     acc_enD, acc_ld, acc_selAlu:  out STD_LOGIC; 
     alu_op:    out STD_LOGIC_VECTOR(2 downto 0) 
    ); 
end component; 
signal abus: STD_LOGIC_VECTOR(7 downto 0); 
signal dbus: STD_LOGIC_VECTOR(7 downto 0); 
signal mem_enD, mem_rw:   STD_LOGIC; 
signal pc_enA, pc_ld, pc_inc:  STD_LOGIC; 
signal ir_enA, ir_enD, ir_ld:  STD_LOGIC; 
signal ir_load, ir_store, ir_add: STD_LOGIC; 
signal ir_sub,  ir_mul, ir_div: STD_LOGIC;
signal ir_and, ir_or, ir_not: STD_LOGIC;
signal ir_negate, ir_halt, ir_branch: STD_LOGIC; 
signal acc_enD, acc_ld, acc_selAlu: STD_LOGIC; 
signal acc_Q:    STD_LOGIC_VECTOR(7 downto 0); 
signal alu_op:    STD_LOGIC_VECTOR(2 downto 0); 
signal alu_accZ:   STD_LOGIC; 
signal alu_result:   STD_LOGIC_VECTOR(7 downto 0); 
begin 
  pc: program_counter port map(clk, pc_enA, pc_ld, pc_inc, reset, abus, dbus); 
  ir: instruction_register port map(clk, ir_enA, ir_enD, ir_ld, reset, abus,dbus,ir_load,ir_store,ir_add,ir_sub,ir_mul,ir_div,ir_and,ir_or,ir_not,ir_negate, ir_halt, ir_branch ); 
  acc: accumulator port map(clk, acc_enD, acc_ld, acc_selAlu, reset, alu_result, dbus, acc_Q); 
  aluu: alu port map(alu_op, acc_Q, dbus, alu_result, alu_accZ); 
  mem: ram port map(mem_rw, mem_enD, reset, abus, dbus); 
  ctl: controller port map (
clk, reset, mem_enD, mem_rw, pc_enA, pc_ld, pc_inc, 
      ir_enA, ir_enD, ir_ld, ir_load, ir_store, ir_add,ir_sub,
ir_mul,ir_div,ir_and,ir_or,ir_not,
      ir_negate, ir_halt, ir_branch,acc_enD,
 acc_ld, acc_selAlu, alu_op
); 
   abusX <= abus; 
   dbusX <= dbus; 
   mem_enDX <= mem_enD; 
   mem_rwX <= mem_rw; 
   pc_enAX <= pc_enA; 
   pc_ldX <= pc_ld; 
   pc_incX <= pc_inc; 
   ir_enAX <= ir_enA; 
   ir_enDX <= ir_enD; 
   ir_ldX <= ir_ld; 
   acc_enDX <= acc_enD; 
   acc_ldX <= acc_ld; 
   acc_selAluX <= acc_selAlu; 
   acc_QX <= acc_Q; 
   alu_opX <= alu_op; 
   alu_accZX <= alu_accZ;
end topArch;

标签:MAR,12,0000,0010,state,指令,布线,数据总线,CPU
来源: https://blog.csdn.net/m0_53295613/article/details/122074392