RISC_CPU结构

采用Top-Down设计方法,深入理解CPU的运作原理,本文参照夏宇闻老师的《Verilog 数字系统设计教程》,并做了相应的修改。仿真工具采用Mentor公司的ModelSim。

1、CPU概述

CPU(Central Processing Unit),即中央处理单元。它必须能够与读取外部的指令和数据,并且能够分析指令进而做出执行。

  • (1)程序和数据输入到计算机的存储器中。
  • (2)对指令做出处理。
    • a.读取指令
    • b.分析指令
    • c.执行指令

RISC(Reduced Instructions Set Computer),即精简指令集计算机。RISC_CPU与一般CPU的不同之处在于,它的时序控制信号形成部件是用硬布线逻辑实现的而不是采用微程序控制的方式。所谓的硬布线逻辑也就是用触发器和逻辑门直接连接所构成的状态机和组合逻辑,故产生控制序列的速度比用微程序控制方式快的多。因为这样做省去了读取微指令的时间。

2、RISC_CPU结构

RSIC_CPU是一个复杂的数字逻辑电路,但是它的基本部件并不复杂。
基本部件包括下面几个部分:

  • clk_gen,时钟发生器
  • IR,指令寄存器
  • accumulator,累加器
  • alu_cpu,算术运算器
  • data_ctl,数据控制器
  • addr,地址多路器
  • pc_counter,程序计数器
  • controller_ena,控制器使能
  • controller,控制器
    以上各个部件在控制器的控制下有条不紊地执行指令。下面我将一一介绍一下各个部件。
2.1 时钟发生器

时钟发生器主要作用是用clk信号产生clk1、fetch、con_alu这3个信号。

clk_gen.png

fetch,是clk的8分频信号

  • a.执行完一条指令需要8个clk时钟周期。
  • b.当fetch为高电平时,clk能触发controller的使能端,使CPU开始工作。
  • c.fetch可以控制addr输出的是pc_addr还是ir_addr。

con_alu,是clk的8分频信号,占空比是1:7

  • 控制alu_cpu只在特定的时候才能运行。

clk1,是clk的反向信号

  • 用来控制controller的时钟,这样能保证数据流要用到控制信号时都是稳定的控制信号。


    clk_gen.png
    module clk_gen(
              clk,
              rst,
              clk1,
              fetch,
              con_alu
              );
    
     input clk,rst;
     output fetch,con_alu,clk1;
     reg fetch,con_alu;
     wire clk1;
     reg [2:0]count;
    
     assign clk1=~clk;
    
    always@(posedge clk or negedge rst)
    begin
     if(!rst)
      count<=0;
     else if(count==7)
      count<=0;
    else
      count<=count+1;
    end
    
    always@(posedge clk or negedge rst)
     begin
     if (!rst)
       begin
       fetch<=0;
      con_alu<=0;
      end  
    else
    case(count)
     0:begin
       fetch<=1;
      con_alu<=0;
       end
     1:begin
    fetch<=1;
    con_alu<=0;
    end
    2:begin
    fetch<=1;
    con_alu<=0;
    end
     3:begin
    fetch<=1;
    con_alu<=0;
    end
     4:begin
    fetch<=0;
    con_alu<=0;
    end
    5:begin
    fetch<=0;
    con_alu<=1;
    end
    6:begin
    fetch<=0;
    con_alu<=0;
    end
    7:begin
    fetch<=0;
    con_alu<=0;
     end 
    default:begin
          fetch<=0;
          con_alu<=0;
          end
    endcase
    end
    
    endmodule 
    
2.2 指令寄存器

在时钟的控制下将总线上指令送入寄存器,但是到底什么时候总线上传送指令,什么时候寄存这些都必须由controller发出的load_ir信号来控制。一条指令又16位组成,那么必须要取两次才能取到一条指令。我们用state来控制是取高8位还是低8位信号,state为0取高8位指令,为1取低8位。


IR.png
  • load_ir,控制指令寄存器什么时候取指令。

  • data,总线上的数据。

  • instr {opcode,ir_addr},16位的指令。高3位为操作码,低13位为地址。

    IR.png

     module IR(
                  clk,
                  rst,
                  ena,
                 data,
                instr
              );
    
    input clk,rst,ena;
    input [7:0] data;
    output [15:0] instr;
    
    reg [15:0] instr;
    reg state;
    
    always@(posedge clk or negedge rst)
      begin
       if(!rst)
        begin
         instr<=16'b0000000000000000;
       state<=1'b0;
      end
    else 
      begin
      if(ena)
        begin
         casex(state)
       1'b0:begin
            instr[15:8]<=data;
            state<=1'b1;
            end
       1'b1:begin
            instr[7:0]<=data;
            state<=1'b0;
            end
       default:begin
            instr<=16'bxxxxxxxxxxxx;
            state<=1'bx;
            end
      endcase
      end
    end
    end               
    
    endmodule 
    
2.3 累加器

累加器用于存放当前的结果,它是双目运算中的一个数据来源,通过controller发出的load_acc信号来控制累加器使能。


accumulator.png
  • load_acc,控制累加器何时加载算数运算器的结果。

  • alu_out,算数运算器的输出。

  • accum,累加器的输出。

    accumulator.png

    module accumulator(
                  clk,
                  rst,
                  ena,
                 data,
                accum
              );
    
    input clk,rst,ena;
    input [7:0] data;
    output [7:0] accum;
    
    reg [7:0] accum;
    
     always@(posedge clk or negedge rst)
     begin
     if(!rst)
       accum<=8'b00000000;
     else 
     if(ena)
       accum<=data;
     end
    
    endmodule 
    
2.4 算数运算器

算数运算器它根据8种不同的操作码,可以分别实现多种运算以及逻辑判断等。


alu_cpu.png
  • accum,累加器的输出。

  • con_alu,控制alu_cpu模块的执行。

  • opcode,instr的前3位,操作码。

  • data,总线上的数据。

  • alu_out,算术运算器的输出。

  • zero,accum求反的结果。

    alu_cpu.png

      module alu_cpu(
                  clk,
                  rst,
              con_alu,
                 data,
                 accum,
                 opcode,
                 zero,
                 alu_out
              );
    
    input clk,rst,con_alu;
    input [7:0] data,accum;
    input [2:0] opcode;
    output [7:0] alu_out;
    output zero;
    
    reg [7:0] alu_out;
    
    parameter  HLT=3'b000,
         SKZ=3'b001,
         ADD=3'b010,
         AND=3'b011,
         XOR=3'b100,
         LDA=3'b101,
         STO=3'b110,
         JMP=3'b111;                      
    
     always@(posedge clk or negedge rst)
      begin
     if(!rst)
     alu_out<=8'b00000000;
    else 
     begin
        if(con_alu)
     begin
       casex(opcode)
         HLT:alu_out<=accum;
         SKZ:alu_out<=accum;
         ADD:alu_out<=accum+data;
         AND:alu_out<=data&accum;
         XOR:alu_out<=data^accum;
         LDA:alu_out<=data;
         STO:alu_out<=accum;
         JMP:alu_out<=accum;
         default:alu_out<=8'bxxxxxxxx;
       endcase
     end
      end
    end
    
    assign zero=!accum; 
    
    endmodule 
    
2.5 数据控制器

数据控制器的作用是控制算数运算器的结果何时输出到总线上。总线上不同时候传送的东西也不相同,有时候传送rom指令,有时候传送ram数据,有时候传送算数运算器alu_out的输出数据。


data_ctl.png
  • alu_out,算数运算器的输出。
  • datactr_ena,controller的输出。
  • data,输出到总线上的数据。
data_ctl.png
 module data_ctl(
                in,
                data_ena,
                data
            );

  input [7:0] in;
  input data_ena;
  output [7:0] data;

  assign data=data_ena?in:8'bzzzzzzzz;

 endmodule 
2.6 地址多路器

地址多路器用于选择输出的是pc_addr(rom)还是ir_addr(ram)。由于每个指令周期的前4个时钟周期都是读取指令应该选择pc_addr,后4个时钟周期用于处理指令应该选择ir_addr。用fetch来控制地址的选择。


addr.png
  • fetch,指令周期。
  • ir_addr,instr的后13位ir_addr。
  • pc_addr,程序计数器。
  • addr,地址。
addr.png
 module addr(
          addr,
          fetch,
          pc_addr,
          ir_addr
            );

input [12:0] pc_addr,ir_addr;
input fetch;
output [12:0]addr;

assign addr=fetch?pc_addr:ir_addr;

 endmodule
2.7程序计数器

指令是顺序存放在rom中的,程序计数器用于提供指令地址,以便读取指令。指令地址形成的方式有两种:一种是顺序执行pc_addr依次加一,另一种是加载ir_addr到pc_addr。


pc_counter.png
  • load_pc,控制程序计数器何时加载ir_addr。

  • ir_addr, instr的后13位ir_addr。

  • inc_pc,控制程序计数器何时加一。

  • pc_addr,程序地址。

    pc_counter.png

     module pc_counter(
                  clk,
                  rst,
                  inc_pc,
                 load,
                 ir_addr,
                 pc_addr
              );
    
    input clk,rst,load,inc_pc;
    input [12:0] ir_addr;
    output [12:0] pc_addr;
    
    reg [12:0] pc_addr;
    
    always@(posedge clk or negedge rst)
    begin
     if(!rst)
       pc_addr<=13'b0000000000000;
     else
      if(load)
         pc_addr<=ir_addr;
     else
       if(inc_pc)
          pc_addr<=pc_addr+1;
    end
    
    endmodule  
    
2.8 控制器使能

rst信号和fetch信号配合,控制controller的使能端。


controller_ena.png
  • fetch,指令周期。
  • ena_controller,控制器使能端。
controller_ena.png
module controller_ena(
                  clk,
                  rst,
                fetch,
              ena_controller
            );

input clk,rst,fetch;
output ena_controller;
reg ena_controller;

always@(posedge clk or negedge rst)
begin
   if(!rst)
  ena_controller<=0;
 else 
   if(fetch)
 ena_controller<=1;
end  

 endmodule 
2.9 控制器

控制器是整个CPU的核心部分,用于产生一系列的控制信号,启动或者停止某些部件。CPU何时进行读取RAM/ROM的数据以及对RAM进行写操作都是通过状态机来控制的。执行一条指令需要8个时钟周期,由state从0~7计数。每一个时钟周期都完成固定的操作。简单讲,就是对
inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena这8个控制信号进行赋值。

controller.png

  • 000:指令寄存器存放ROM送来的高8位指令代码。
    -1、 inc_pc,rd,load_ir置于高位,其余置于低位。
    -2、程序计数器加一,将rom中的数据读出到总线上,指令寄存器将寄存来自总线上的高8位指令。
  • 001:指令寄存器存放ROM送来的低8位指令。
    -1、inc_pc,rd,load_ir置于高位,其余置于低位。
    -2、程序计数器加一(指向下一条指令的地址),将rom中的数据读出到总线上,指令寄存器将寄存来自总线上的低8位指令。
  • 010:空操作。
    -1、所有信号置于低位。
    -2、用作数据的缓冲。
  • 011:,根据操作码做不同的操作。
    -1、如果操作码为HLT,HALT置于高位,其余置于低位。
    -2、如果操作码不是HLT,所有信号置于低位。
  • 100:,根据操作码做不同的操作。
    -1、如果操作符为AND、ADD、XOR、LDA,读相应地址的数据,rd置于高位,其余置于低位。
    -2、如果操作符为JMP,将目的地址送给程序计数器,load_pc置于高位,其余置于低位。
    -3、如果操作符为STO,将累加器上的数据放入指令给出的地址,datactr_ena置于高位,其余置于低位。
    -4、如果操作符不是上述情况,所有信号置于低位。
  • 101:根据操作码做不同的操作。
    -1、如果操作符为AND、ADD、XOR、LDA,算术运算器要做出相应的计算,rd、load_acc置于高位,其余置于低位。
    -2、如果操作符为SKZ,先判断累加器的值是否为0,如果是0,则inc_pc置于高位,其余置于低位;否则所有信号置于低位。
    -3、如果操作符为JMP,锁存目标地址,load_pc置于高位,其余置于低位。
    -4、如果操作符为STO,将累加器上的数据写入指定地址,wr,datactr_ena置于高位,其余各位置于低位。
    -5、如果操作符不是上述情况,所有信号置于低位。
  • 110:空操作。不对指令做出相应,控制总线上的输出数据
    -1、如果操作符为STO,datactr_ena置于高位,其余置于低位。
    -2、如果操作符为AND、ADD、XOR、LDA,rd置于高位,其余置于低位。
    -3、如果操作符不是上述情况,所有信号置于低位。
  • 111:根据操作码不同做不同的操作。
    -1、如果操作符为SKZ且累加器的输出为0,inc_pc置于高位,其余置于低位。
    -2、如果不是上述操作符,所有信号置于低位。
    controller.png
    module controller(
                clk,
                rst,
                ena,
                zero,
                opcode,
                load_acc,
                load_pc,
                rd,
                wr,
                load_ir,
                HALT,
                datactr_ena,
                inc_pc
            );

    input clk,rst,ena,zero;
    input [2:0]opcode;
    output inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena;

    reg inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena;
    reg [2:0]state;

    parameter  HLT=3'b000,
       SKZ=3'b001,
       ADD=3'b010,
       AND=3'b011,
       XOR=3'b100,
       LDA=3'b101,
       STO=3'b110,
       JMP=3'b111;   

    always@(posedge clk or negedge rst)
     begin
       if(!rst)
       begin
       state<=3'b000;
         {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena} <=8'b00000000;         
     end
    else 
     if(ena)
      controller_cycle;
    end

    task controller_cycle;
     begin
       case(state)
       3'b000:begin
          {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b10010100;
          state<=3'b001;
         end
      3'b001:begin
          {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b10010100;
          state<=3'b010;
         end
       3'b010:begin
          {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00000000;
          state<=3'b011;
         end
         3'b011:begin
          if(opcode==HLT)
            {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00000010;  
          else
            {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00000000;
        state<=3'b100;
          end
          3'b100:begin
           if(opcode==JMP)
             {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00100000;
         else 
           if((opcode==ADD)||(opcode==AND)||(opcode==XOR)||(opcode==LDA))
              {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00010000;
            else
              if(opcode==STO)
                  {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b0000001;
            else
               {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00000000;
          state<=3'b101; 
          end
    3'b101:begin
             if((opcode==ADD)||(opcode==AND)||(opcode==XOR)||(opcode==LDA))
               {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b01010000;
             else
               if((opcode==SKZ)&&(zero==1))
                 {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b10000000;
              else
                if(opcode==JMP)
                 {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00100000;
               else
                 if(opcode==STO)
                  {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00001001;
                else
                  {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00000000;
            state<=3'b110;
            end
      3'b110:begin
               if(opcode==STO)
                  {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b0000001;
                else
                  if((opcode==ADD)||(opcode==AND)||(opcode==XOR)||(opcode==LDA))
                     {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00010000;
                   else
                     {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00000000;
                state<=3'b111;
                end
        3'b111:begin
                if((opcode==SKZ)&&(zero==1))
                   {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b10000000;
                 else
                   {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00000000;
                 state<=3'b000;
                end
        default:begin
                 {inc_pc,load_acc,load_pc,rd,wr,load_ir,HALT,datactr_ena}<=8'b00000000;
                  state<=3'b000;
                  end
            endcase                 
    end
    endtask

     endmodule

3 集成各个组件

将CPU的各个组件按照对应的信号线连接起来,就形成了一个CPU。


cpu.png
module cpu(   clk,
          rst,
          data,
          rd,
          wr,
          addr,
          HALT,
          fetch   
              );

  input clk,rst;
  output rd,wr,HALT,fetch;
  output[12:0]addr;
  inout[7:0]data;

   wire con_alu,clk1;
  //wire[15:0] instr;
  wire[2:0] opcode;
  wire[12:0] ir_addr;
  wire[7:0] accum,alu_out;
  wire zero;
  wire ena_controller;
  wire[12:0] pc_addr;
  wire load_acc,load_pc,load_ir,datactr_ena,inc_pc;

clk_gen clk_gen_m (.clk(clk),
               .rst(rst),
               .clk1(clk1),
               .fetch(fetch),
               .con_alu(con_alu)); 
        
IR IR_m (.clk(clk),
     .rst(rst),
     .ena(load_ir),
     .data(data),
     .instr({opcode,ir_addr}));
        
accumulator accumulator_m (.clk(clk),
                       .rst(rst),
                       .ena(load_acc),
                       .data(alu_out),
                       .accum(accum));
                       
 alu_cpu alu_cpu_m (.clk(clk),
               .rst(rst),
               .con_alu(con_alu),
               .data(data),
               .accum(accum),
               .opcode(opcode),
               .zero(zero),
               .alu_out(alu_out));
               
data_ctl data_ctl_m (.in(alu_out),
                 .data_ena(datactr_ena),
                 .data(data)); 
                 
pc_counter pc_counter_m (.clk(clk),
                     .rst(rst),
                     .inc_pc(inc_pc),
                     .load(load_pc),
                     .ir_addr(ir_addr),
                     .pc_addr(pc_addr));
                     
  addr addr_m ( .addr(addr),
          .fetch(fetch),
          .pc_addr(pc_addr),
          .ir_addr(ir_addr));
          
 controller_ena controller_ena_m (.clk(clk),
                             .rst(rst),
                             .fetch(fetch),
                             .ena_controller(ena_controller));   
                             
  controller controller_m (.clk(clk1),
                     .rst(rst),
                     .ena(ena_controller),
                     .zero(zero),
                     .opcode(opcode),
                     .load_acc(load_acc),
                     .load_pc(load_pc),
                     .rd(rd),
                     .wr(wr),
                     .load_ir(load_ir),
                     .HALT(HALT),
                     .datactr_ena(datactr_ena),
                     .inc_pc(inc_pc));                                                                                                                                       
            
 endmodule

小结:

其实我们通过分析可以得知,一个相对复杂的数字电路设计,都可以划分成很简单的电路来实现,重要的是如何控制这些简单电路相互协调工作。上面我们介绍了CPU的构成,下一篇文章我们就讨论一下如何对这个CPU进行调试。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容

  • By JackKing_defier 首先说明一下,本文内容主要是简单说明CPU的大致原理,所需要的前提知识我会提...
    JackKing_defier阅读 1,576评论 6 17
  • 众所周知,计算机硬件主要由CPU(运算器和控制器)、存储器(内存和外存)、外部设备(输入/输出设备)等构成。那这几...
    张利锋阅读 5,829评论 0 4
  • 阅读经典——《深入理解计算机系统》06 本文,我们要做一件大胆的事情,从零开始实现一个全新的指令集架构,以此深入理...
    金戈大王阅读 20,640评论 7 52
  • 遥不可及的你在我转头的那一瞬间便悄然消逝,看似羡慕互相打情骂俏的两人,其实根本不存在,人啊,总以为听了你的故事就全...
    冱寒阅读 184评论 0 1
  • 最近,朋友圈被印度片《摔跤吧,爸爸》刷屏了。起先是惊讶于阿米尔汗的坚持,毅力以及他作为一个演员的使命感和责任感。而...
    鑫淼Anne阅读 318评论 0 1