RISC-V处理器的设计与实现(二)—— CPU框架设计

news2024/11/25 18:37:20

前面我们选好了要实现的指令集,并且了解了每个指令的功能(传送门:RISC-V处理器的设计与实现(一)—— 基本指令集_Patarw_Li的博客-CSDN博客),接下来我们就可以开始设计cpu了。当然我们不可能一上来就写代码,首先我们要把cpu的结构、工作流程了解清楚,然后再开始代码的编写。

一、CPU和计算机的关系

说到计算机,那就不得不提大名鼎鼎的冯诺依曼了:

约翰·冯·诺依曼(John von Neumann,1903年12月28日-1957年2月8日),美籍匈牙利数学家,计算机科学家,物理学家,是20世纪最重要的数学家之一。冯·诺依曼是罗兰大学数学博士,是现代计算机,博弈论,核武器和生化武器等领域内的科学全才之一,被后人称为“现代计算机之父”、“博弈论之父”。

而现在的计算机大多都遵循冯诺依曼结构:

冯诺依曼结构包括如下4个部分: 

  • CPU,即中央处理器,是一台计算机的运算核心和控制核心。其功能主要是解释计算机指令以及处理计算机软件中的数据。CPU由运算器、控制器、寄存器、高速缓存及实现它们之间联系的数据、控制及状态的总线构成
  • 存储器,分为外存和内存, 用于存储数据(使用二进制方式存储)
  • 输入设备,用户给计算机发号施令的设备
  • 输出设备,计算机个用户汇报结果的设备

其中最核心的部分也就是CPU了,CPU又名中央处理器(Central Processing Unit,简称CPU),它由ALU(算术逻辑单元)和CU(控制单元)两部分组成:

  • ALU 算术逻辑单元(Arithmetic logical Unit):是中央处理器(CPU)的执行单元,是所有中央处理器的核心组成部分,由"And Gate"(与门) 和"Or Gate"(或门)构成的算术逻辑单元,主要功能是进行二位元的算术运算,如加减乘(不包括整数除法)。基本上,在所有现代CPU体系结构中,二进制都以补码的形式来表示。
  • CU 控制单元(Control Unit):负责程序的流程管理。控制单元是整个 CPU 的指挥控制中心,对协调整个计算机有序工作极为重要。

此外还包括一些寄存器,如PC(程序计数器) 、IR(指令寄存器)和一些通用寄存器等等。

二、CPU的工作流程

CPU执行分为5个阶段,取指阶段(IF)、译码阶段(ID)、执行阶段(EX)、访存阶段(MEM)、写回阶段(WB):

一、取指令阶段
取指令(Instruction Fetch,IF)阶段是根据PC的值,将一条指令从主存中取到指令寄存器的过程。程序计数器PC中的数值,用来指示当前指令在主存中的位置。当一条指令被取出后,PC中的数值将根据指令字长度而自动递增(如32位指令为PC+4)。

二、指令译码阶段
取出指令后,计算机进入指令译码(Instruction Decode,ID)阶段。

在指令译码阶段,指令译码器按照预定的指令格式,对取回的指令进行拆分和解释,识别区分出不同的指令类别以及各种获取操作数的方法。

三、执行指令阶段
在取指令和指令译码阶段之后,接着进入执行指令(Execute,EX)阶段。

此阶段的任务是完成指令所规定的各种操作,具体实现指令的功能。为此,CPU的不同部分被连接起来,以执行所需的操作。

四、访存取数阶段
根据指令需要,有可能要访问主存,读取操作数,这样就进入了访存取数(Memory,MEM)阶段。

此阶段的任务是:根据指令地址码,得到操作数在主存中的地址,并从主存中读取该操作数用于运算。

五、结果写回阶段
作为最后一个阶段,结果写回(Write Back,WB)阶段把执行指令阶段的运行结果数据“写回”。写回的地方一般是寄存器或者内存,其中写回寄存器的情况最多,方便之后的指令使用。

在有些情况下,结果数据也可被写入相对较慢、但较廉价且容量较大的主存。许多指令还会改变程序状态字寄存器中标志位的状态,这些标志位标识着不同的操作结果,可被用来影响程序的动作。

因为每个阶段的执行部件是分时复用的,所以可以用流水线的方式执行指令,下面是一个五级指令流水线:

 

三、CPU的架构设计

在了解上面这些内容后我们就可以开始CPU的框架设计了,为了简单,我们只设计三级流水线,写回和访存都放在执行阶段完成,下面是模块框架图:

1、取指阶段

取指阶段负责从rom中取出指令,传给译码阶段。其中pc模块输出需要取出的指令的地址pc_out,将指令地址传给rom后,rom寻址到对应指令再回传给if_id模块。if_id模块的作用是将指令和指令地址延后一拍传给译码模块ID_UNIT,延后一拍的目的是为了让系统以流水线的形式工作。

module IF_UNIT(

    input   wire                     clk          ,
    input   wire                     rst_n        ,
    
    input   wire                     hold_flag    ,
    input   wire                     jump_flag    ,
    input   wire[`INST_REG_DATA]     jump_addr    ,
        
    output  wire[`INST_DATA_BUS]     ins_o        , // 指令
    output  wire[`INST_ADDR_BUS]     ins_addr_o   , // 指令地址
    
    output  wire[`INST_ADDR_BUS]     pc_o         , // 传给rom的指令地址
    input   wire[`INST_DATA_BUS]     ins_i          // rom根据地址读出来指令

    );
    
    wire[`INST_ADDR_BUS]       pc;
    assign pc_o = pc;
    
    
    // PC寄存器模块例化
    pc u_pc(
        .clk         (clk)  ,
        .rst_n       (rst_n),
        .jump_flag   (jump_flag),
        .jump_addr   (jump_addr),
        .pc_out      (pc)
    );
    
    // 指令寄存器模块例化
    if_id u_if_id(
        .clk         (clk),
        .rst_n       (rst_n),
        .hold_flag   (hold_flag),
        .ins_i       (ins_i), 
        .ins_addr_i  (pc),
        .ins_o       (ins_o), 
        .ins_addr_o  (ins_addr_o) 
    );
    
endmodule

2、译码阶段

译码阶段负责对指令进行译码。id模块从指令中读出寄存器写回地址rd,拼接立即数imm,从寄存器单元(RF_UNIT)中取出操作数R1、R2,然后将这些通过id_ex模块延后一拍传给执行模块EX_UNIT。

module ID_UNIT(

    input   wire                    clk            ,
    input   wire                    rst_n          ,
    
    input   wire                    hold_flag      ,
     
    //从IF模块传来的指令和指令地址
    input   wire[`INST_DATA_BUS]    ins_i          , 
    input   wire[`INST_ADDR_BUS]    ins_addr_i     , 
    
    // 传给RF模块的地址,用于读取数据
    output  wire[`INST_REG_ADDR]    reg1_rd_addr_o , 
    output  wire[`INST_REG_ADDR]    reg2_rd_addr_o ,
    
    // 根据传给RF模块地址读到的数据
    input   wire[`INST_REG_DATA]    reg1_rd_data_i , 
    input   wire[`INST_REG_DATA]    reg2_rd_data_i ,
    
    output  wire[`INST_DATA_BUS]    ins_o          , 
    output  wire[`INST_ADDR_BUS]    ins_addr_o     , 
    
    // 将读到的寄存器数据传给EX模块
    output  wire[`INST_REG_DATA]    reg1_rd_data_o , 
    output  wire[`INST_REG_DATA]    reg2_rd_data_o ,
    
    // 写寄存器地址
    output  wire[`INST_REG_ADDR]    reg_wr_addr_o  ,
    
    // 立即数
    output  wire[`INST_REG_DATA]    imm_o  
    );
    
    wire[`INST_REG_ADDR]    reg_wr_addr;
    wire[`INST_REG_DATA]    imm;
    
    // 指令译码模块例化
    id u_id(
        .clk            (clk),
        .rst_n          (rst_n),
        .ins_i          (ins_i), 
        .ins_addr_i     (ins_addr_i), 
        .reg1_rd_addr_o (reg1_rd_addr_o), 
        .reg2_rd_addr_o (reg2_rd_addr_o),
        .reg_wr_addr_o  (reg_wr_addr),
        .imm_o          (imm) 
    );
    
    // 将传给EX单元的内容打一拍
    id_ex u_id_ex(
        .clk            (clk),
        .rst_n          (rst_n),
        .hold_flag      (hold_flag),
        .ins_i          (ins_i), 
        .ins_addr_i     (ins_addr_i), 
        .reg1_rd_data_i (reg1_rd_data_i), 
        .reg2_rd_data_i (reg2_rd_data_i),
        .reg_wr_addr_i  (reg_wr_addr),
        .imm_i          (imm),
        .ins_o          (ins_o), 
        .ins_addr_o     (ins_addr_o), 
        .reg1_rd_data_o (reg1_rd_data_o), 
        .reg2_rd_data_o (reg2_rd_data_o),
        .reg_wr_addr_o  (reg_wr_addr_o),
        .imm_o          (imm_o)
    );
endmodule

3、执行阶段

执行阶段负责指令的执行、访存以及数据的回写。alu模块对传入的两个操作数进行计算,通过 alu_op_code来判断计算类型;cu负责发出各种控制信号,比如寄存器堆写使能信号、ram写使能信号、流水线暂停信号,等等。

module EX_UNIT(

    input   wire                    clk                 ,
    input   wire                    rst_n               ,
            
    input   wire[`INST_DATA_BUS]    ins_i               , 
    input   wire[`INST_ADDR_BUS]    ins_addr_i          , 
            
    input   wire[`INST_REG_DATA]    reg1_rd_data_i      , 
    input   wire[`INST_REG_DATA]    reg2_rd_data_i      ,
            
    input   wire[`INST_REG_ADDR]    reg_wr_addr_i       ,
    
    input   wire[`INST_REG_DATA]    imm_i               ,  
            
    output  wire                    reg_wr_en_o         ,
    output  wire[`INST_REG_ADDR]    reg_wr_addr_o       ,
    output  wire[`INST_REG_DATA]    reg_wr_data_o       ,
    output  wire                    jump_flag           ,
    output  wire[`INST_REG_DATA]    jump_addr           ,
    output  wire                    hold_flag           ,

    // 内存相关引脚(ram)
    input   wire[`INST_DATA_BUS]    mem_rd_data_i       ,
    output  wire                    mem_wr_en_o         , 
    output  wire[`INST_ADDR_BUS]    mem_wd_addr_o       , 
    output  reg[`INST_DATA_BUS]     mem_wr_data_o       
    
    );
    
    wire[`INST_REG_DATA]     alu_res;
    wire[3:0]                alu_op_code;
    wire                     pc_flag;
    wire                     pc_imm_flag;
    wire                     imm_flag;
    wire                     pc_4_flag;
    wire                     alu_zero_flag;
    wire                     alu_sign_flag;
    wire                     alu_overflow_flag;
    wire                     load_ins_flag;
    wire[`INST_REG_DATA]     alu_data1_i;
    wire[`INST_REG_DATA]     alu_data2_i;
    
    reg[`INST_DATA_BUS]      mem_rd_data;
    wire[2:0]       funct3;
    assign funct3 = ins_i[14:12];
    
    // 访存相关
    assign mem_wd_addr_o = alu_res;
    
    always @ (*) begin
        case(funct3)
            `INS_SB: begin
                case(mem_wd_addr_o[1:0])
                    2'b00: begin
                        mem_wr_data_o = {mem_rd_data_i[31:8],reg2_rd_data_i[7:0]};
                    end
                    2'b01: begin
                        mem_wr_data_o = {mem_rd_data_i[31:16],reg2_rd_data_i[7:0],mem_rd_data_i[7:0]};
                    end
                    2'b10: begin
                        mem_wr_data_o = {mem_rd_data_i[31:24],reg2_rd_data_i[7:0],mem_rd_data_i[15:0]};
                    end
                    2'b11: begin
                        mem_wr_data_o = {reg2_rd_data_i[7:0],mem_rd_data_i[23:0]};
                    end
                endcase
            end
            `INS_SH: begin
                if(mem_wd_addr_o[1:0] == 2'b00) begin
                    mem_wr_data_o = {mem_rd_data_i[31:16],reg2_rd_data_i[15:0]};
                end
                else begin
                    mem_wr_data_o = {reg2_rd_data_i[15:0],mem_rd_data_i[15:0]};
                end
            end
            `INS_SW: begin
                mem_wr_data_o = reg2_rd_data_i;
            end
            default: begin
                mem_wr_data_o = reg2_rd_data_i;
            end
        endcase
    end
    
    always @ (*) begin
        case(funct3)
            `INS_LB: begin
                case(mem_wd_addr_o[1:0])
                    2'b00: begin
                        mem_rd_data = {{24{mem_rd_data_i[7]}}, mem_rd_data_i[7:0]};
                    end
                    2'b01: begin
                        mem_rd_data = {{24{mem_rd_data_i[15]}}, mem_rd_data_i[15:8]};
                    end
                    2'b10: begin
                        mem_rd_data = {{24{mem_rd_data_i[23]}}, mem_rd_data_i[23:16]};
                    end
                    2'b11: begin
                        mem_rd_data = {{24{mem_rd_data_i[31]}}, mem_rd_data_i[31:24]};
                    end
                endcase
            end
            `INS_LH: begin
                if(mem_wd_addr_o[1:0] == 2'b00) begin
                    mem_rd_data = {{16{mem_rd_data_i[15]}}, mem_rd_data_i[15:0]};
                end
                else begin
                    mem_rd_data = {{16{mem_rd_data_i[31]}}, mem_rd_data_i[31:16]};
                end
            end
            `INS_LW: begin
                mem_rd_data = mem_rd_data_i;
            end
            `INS_LBU: begin
                case(mem_wd_addr_o[1:0])
                    2'b00: begin
                        mem_rd_data = {{24{1'b0}}, mem_rd_data_i[7:0]};
                    end
                    2'b01: begin
                        mem_rd_data = {{24{1'b0}}, mem_rd_data_i[15:8]};
                    end
                    2'b10: begin
                        mem_rd_data = {{24{1'b0}}, mem_rd_data_i[23:16]};
                    end
                    2'b11: begin
                        mem_rd_data = {{24{1'b0}}, mem_rd_data_i[31:24]};
                    end
                endcase
            end
            `INS_LHU: begin
                if(mem_wd_addr_o[1:0] == 2'b00) begin
                    mem_rd_data = {{16{1'b0}}, mem_rd_data_i[15:0]};
                end
                else begin
                    mem_rd_data = {{16{1'b0}}, mem_rd_data_i[31:16]};
                end
            end
            default: begin
                mem_rd_data = mem_rd_data_i;
            end
        endcase
    end
    
    //选择输入的是pc值还是寄存器数据
    assign alu_data1_i = (pc_flag) ? ins_addr_i : reg1_rd_data_i;
    
    //选择输入的是立即数还是寄存器数据
    assign alu_data2_i = (imm_flag) ? imm_i : reg2_rd_data_i;
    
    assign reg_wr_addr_o = reg_wr_addr_i;
    assign reg_wr_data_o = (load_ins_flag) ? mem_rd_data : ((pc_4_flag) ? (ins_addr_i + 4'd4) : alu_res);
    assign jump_addr = (pc_imm_flag) ? ($signed(ins_addr_i) + $signed(imm_i)) : alu_res;
    
    // 控制单元例化
    cu u_cu(
        .ins_i               (ins_i), 
        .ins_addr_i          (ins_addr_i), 
        .alu_zero_flag       (alu_zero_flag),
        .alu_sign_flag       (alu_sign_flag),
        .alu_overflow_flag   (alu_overflow_flag),
        .alu_op_code         (alu_op_code),
        .imm_flag            (imm_flag),
        .pc_flag             (pc_flag),
        .pc_4_flag           (pc_4_flag),
        .pc_imm_flag         (pc_imm_flag),
        .jump_flag           (jump_flag),
        .hold_flag           (hold_flag),
        .load_ins_flag       (load_ins_flag),
        .reg_wr_en_o         (reg_wr_en_o),
        .mem_wr_en_o         (mem_wr_en_o)
    );
    
    // 运算单元例化
    alu u_alu(
        .alu_data1_i         (alu_data1_i), 
        .alu_data2_i         (alu_data2_i),
        .alu_op_code         (alu_op_code),
        .alu_data_o          (alu_res),
        .alu_zero_flag       (alu_zero_flag),
        .alu_sign_flag       (alu_sign_flag),
        .alu_overflow_flag   (alu_overflow_flag)
    );
    
endmodule

上面只是每个模块的上层代码,具体代码请到我的gitee上下载:cpu_prj: 一个基于RISC-V指令集的CPU实现

四、仿真流程

本项目的cpu目前实现了37条指令,目前可以跑一些基本的c语言代码。

首先下载gnu工具链:百度网盘 请输入提取码,提取码:uk0w

然后配置ripes,点击edit->setting->compiller,选择compiller path为gnu工具链的地址(\bin\riscv-none-embed-gcc):

下面的编译选项要改成:-nostdlib -march=rv32i -mabi=ilp32

下面没有报错就可以点击ok了。

下面在ripes写一个简单的求和c程序,其中point指针是为了将结果sum放到ram的地址为0x00000000的地方,方便我们查看结果:

int main(){
    int n = 5;
    int sum = 0;
    for (int i = 1; i <= n; ++i) {
        sum = sum + i;
    }
    int* point;
    point = (int*) 0x00000000;
    *point = sum;
    return 0;
}

点击锤子开始编译执行,可以看到右边正在执行:

将指令切换到二进制形式: 

 

然后将右边的二进制指令复制到 \rtl\perips\instructions.txt 下:

保存之后用vivado打开项目,然后进行仿真: 

 将_ram添加到波形中:

 

然后开始仿真,可以看到成功计算出结果15: 

 

至此,代码的仿真结束,大家用其他代码来测试也可以,不过无法实现乘除法(因为还没写这些指令,后面我会加上去的)。

之后我会继续研究如何把自己写的riscv处理器移植到开发板上,并且烧录程序进行验证。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/684635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT更新的使用指南,与其他类似的人工智能的软件和服务-更新版(2023-6-25)

文章目录 一、什么是ChatGPT二、如何使用三、如何使用ChatGPT帮助我们的工作和生活四、高阶用法1、角色扮演2、英语口语老师3、在搜索引擎中集成ChatGPT 五、常见问题五、其他类似的软件和服务 如果你还不知道如何注册和使用&#xff0c;可看末尾&#xff0c;手把手教你。 一、…

Linux线程同步

同步的几种方式&#xff1a;信号量&#xff0c;互斥锁&#xff0c;条件变量&#xff0c;读写锁 同步&#xff1a;对程序的执行过程进行控制&#xff0c;保证对临界资源的访问同一时刻只能有一个进程或线程访问。 2.1信号量 存在P操作&#xff1a;获取资源&#xff0c;信号量…

58.最后一个单词的长度

LeetCode-58.最后一个单词的长度 1、题目描述2、解题思路3、代码实现4、解题记录 1、题目描述 题目描述&#xff1a; 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任…

通讯录获取APP程序分析

前言 APP非法获取用户通讯录等隐私信息 我用技术分析APP是如何获取信息的 如果你不幸中招了&#xff0c;可以参考下方链接(有偿) 我的方法是替换掉通讯录数据&#xff0c;替换不成功包退&#xff01; 每日16:00-06:00在线&#xff0c;5分钟受理&#xff0c;2~3小时完成 点下面…

下载安装mysql与设置密码详细步骤(压缩包版本)

目录 一、前言 二、操作步骤 &#xff08;一&#xff09;下载与解压缩 &#xff08;二&#xff09;配置环境变量 &#xff08;三&#xff09;安装MySQL服务 &#xff08;四&#xff09;设置ini文件和data文件 &#xff08;五&#xff09;启动MySQL服务和设置密码 三、…

【C++ 程序设计】第 5 章:类的继承与派生

目录 一、类的继承与类的派生 &#xff08;1&#xff09;继承的概念 &#xff08;2&#xff09;派生类的定义与大小 ① 派生类的定义 ② 派生类的大小 &#xff08;3&#xff09;继承关系的特殊性 &#xff08;4&#xff09;有继承关系的类之间的访问 &#xff08;5&am…

多线程单例模式

1、单例模式 顾名思义&#xff0c;单例模式能保证某个类在程序中只存在唯一一份示例&#xff0c;而不会创建出多个实例。就像java的JDBC编程只需要创建一个单例类DataSourece从这个DataSorce中获取数据库连接。没必要创建多个对象。 单例模式具体实现方式分为“饿汉”和“懒汉…

java编译与反编译

参考&#xff1a; Idea 使用技巧记录_source code recreated from a .class file by intell_hresh的博客-CSDN博客 深入理解Java Class文件格式&#xff08;一&#xff09;_昨夜星辰_zhangjg的博客-CSDN博客 实践详解javap命令&#xff08;反编译字节码&#xff09;_天然玩家…

【运筹优化】元启发式算法详解:迭代局部搜索算法(Iterated Local Search,ILS)+ 案例讲解代码实现

文章目录 一、介绍二、迭代局部搜索2.1 总体框架2.2 随机重启2.3 在 S* 中搜索2.4 ILS 三、获得高性能3.1 初始解决方案3.2 Perturbation3.2.1 扰动强度3.2.2 自适应扰动3.2.3 更复杂的扰动方案3.2.4 Speed 3.3 接受准则3.4 Local Search3.5 ILS 的全局优化 四、ILS 的精选应用…

Windows PE怎么修复系统?使用轻松备份解决!

​什么是Windows PE? Windows预先安装环境&#xff08;英语&#xff1a;Microsoft Windows Preinstallation Environment&#xff09;&#xff0c;简称Windows PE或WinPE&#xff0c;是Microsoft Windows的轻量版本&#xff0c;主要提供个人电脑开发商&#xff08;主要为OEM厂…

electron+vue3全家桶+vite项目搭建【20】窗口事件广播,通用事件封装

引入 electron中的渲染进程与主进程之间的数据交互需要利用ipc通信&#xff0c;互相订阅/通知来实现&#xff0c;我们不妨封装一个通用事件广播&#xff0c;利用自定义的事件名称来让主进程遍历窗口挨个推送对应内容&#xff0c;来实现事件的广播。 demo项目地址 实现思路 …

【计算机视觉】MaskFormer:将语义分割和实例分割作为同一任务进行训练

文章目录 一、导读二、逐像素分类和掩码分类的区别2.1 逐像素分类2.2 掩码分类2.3 区别 三、DETR四、MaskFormer五、MaskFormer用于语义和实例分割六、总结 一、导读 目标检测和实例分割是计算机视觉的基本任务&#xff0c;在从自动驾驶到医学成像的无数应用中发挥着关键作用。…

模拟电路系列分享-运放的关键参数5

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; 实际运放与理想运放具有很多差别。理想运放就像一个十全十美的人&#xff0c;他学习100 分&#xff0c;寿命无限长&#xff0c;长得没挑剔&#xff0c;而实…

【c++11】移动构造的性质 和 与拷贝构造的比较(详解)

文章目录 定义性质移动构造的定义实例代码分析移动构造 与 拷贝构造的比较移动赋值 和 拷贝赋值 应用场景 定义 移动构造&#xff08;Move Constructor&#xff09;是一种特殊的构造函数&#xff0c;它通过接收一个右值引用参数来创建新对象&#xff0c;并从传入的对象中“移动…

操作系统——Windows 线程的互斥与同步

一、实验题目 Windows 线程的互斥与同步 二、实验目的 (1) 回顾操作系统进程、线程的有关概念&#xff0c;加深对 Windows 线程的理解。 (2) 了解互斥体对象&#xff0c;利用互斥与同步操作编写生产者-消费者问题的并发程序&#xff0c;加深对 P (即 semWait)、V(即 semSig…

[Spec] WiFi P2P Discovery

学习资料&#xff1a;Android Miracast 投屏 目录 学习资料&#xff1a;Android Miracast 投屏 P2P discovery Introduction Device Discovery procedures Listen State Search State Scan Phase Find Phase 总结 P2P discovery Introduction P2P发现使P2P设备能够快速…

WiSA Technologies开始接受WiSA E多声道音频开发套件的预订

美国俄勒冈州比弗顿市 — 2023年6月13日 — 为智能设备和下一代家庭娱乐系统提供沉浸式无线声效技术的领先供应商WiSA Technologies股份有限公司&#xff08;NASDAQ股票代码&#xff1a;WISA&#xff09;宣布&#xff1a;该公司现在正在接受其WiSA E开发套件的预订。WiSA E使用…

论文不详细解读(一)——MoCo系列

1. MoCo v1 论文名称&#xff1a; Momentum Contrast for Unsupervised Visual Representation Learning 开源地址&#xff1a;https://github.com/facebookresearch/moco 大佬详细解读&#xff1a;https://zhuanlan.zhihu.com/p/382763210 motivation 原始的端到端自监督方…

听说软件测试岗位基本都是女孩子在做?

“听我一朋友说&#xff0c;测试岗位基本都是女孩子做。” 不知道是不是以前“软件测试岗”给人印象是“不需要太多技术含量”的错觉&#xff0c;从而大部分外行认为从业软件测试的人员中女生应占了大多数。比如有人就觉得&#xff1a;软件测试主要是细心活&#xff0c;所以女生…

Python多任务执行方式

一、多任务的执行方式 并发&#xff1a;在一段时间内交替去执行任务&#xff08;单核CPU&#xff09;并行&#xff1a;CPU核数大于任务数 二、进程&#xff08;实现多任务&#xff09;——操作系统调度 进程是操作系统进行资源分配的基本单元一个程序至少有一个进程&#xf…