2025.11.11

Overview

  1. 昨日总结
  2. 学习笔记
  3. 今日总结

昨日总结

昨天从早上集合后前往上海参加本周的城市之旅活动,逛了几处没去过的地方,不过最大的收获是从一个来参加的老师那里得知了一个日后会常驻举办的活动——宠物交流活动,以后每周有一次带摩羯出去和别的宠物交流的机会,希望借此机会让它的胆子变大吧,而且希望可以人生同样有爱的主人吧
不过可惜的是昨天因为行程安排不妥导致昨天没能赶上晚上的飞盘训练,之后的活动不能再犯同样的错误了

学习笔记

计算机体系结构与操作系统

MIPS 汇编语言入门

  1. 计算机抽象层级与指令基础
    1. 抽象层级(从高到低):应用软件→操作系统→架构(程序员视角,定义指令 / 操作数位置)→微架构(硬件实现细节)→逻辑→数字电路→模拟电路→器件→物理
    2. 指令分类:
      1. 机器语言:二进制码(如01101010 10101101),计算机可直接识别
      2. 汇编语言:机器语言的符号表示(如add $s0,$s1,$s2),需汇编器转换
  2. MIPS 架构概述
    1. 学习价值:作为 RISC 架构代表,掌握后易迁移到其他架构
    2. 核心特点:
      1. 32 位架构:操作 32 位数据,含32 个 32 位通用寄存器(速度远快于内存,减少访问延迟)
      2. load/store 架构:仅通过lw(加载)/sw(存储)指令访问内存,其他指令操作寄存器
      3. 固定指令长度:所有指令均为 32 位,简化硬件解码
  3. 基础算术与逻辑操作
    1. 核心指令格式:多数指令为 “目标寄存器,源寄存器 1,源寄存器 2”(如add $d, $s, $t)
    2. 算术指令:
      1. add $d, $s, $t:$d = $s + $t
      2. sub $d, $s, $t:$d = $s - $t
      3. addi $d, $s, imm:$d = $s + imm (add后面的i意味计算里使用了数字)
    3. 复杂表达式实现:需拆分多指令,如 C 代码a=b+c-d对应:
      add $t0, $s1, $s2 # $t0 = b + c(临时寄存器存中间结果)
      sub $s0, $t0, $s3 # $s0 = $t0 - d = b + c - d
  4. 内存访问基础
    1. 内存需求:寄存器仅 32 个,无法存储大量数据,需依赖内存(容量大但速度慢)
    2. 寻址模式:
      1. 字寻址:每个 32 位数据(字)对应唯一字地址
    3. 字节寻址:MIPS 实际采用字节寻址(每个字节 1 个地址),字地址 = 字节地址 ×4(因 1 字 = 4 字节),示例:字 2 的字节地址为 8(2×4)
    4. 内存操作指令:
      1. 加载字:lw $d, offset($base) -> d = 内存[base + offset](示例:读取字节地址4的字到s3,指令lw $s3,4($0))
      2. 存储字:sw $s, offset($base) -> s = 内存[base + offset]()(示例:将t4存入字节地址7,指令sw $t4,0x7($0))
      3. 加载字节(lb)/ 存储字节(sb):操作单个字节数据

逻辑指令、移位、数组与函数调用

  1. 逻辑指令
    1. 核心指令(操作寄存器或立即数):
      1. and $d, $s, $t:$d = $s & $t (用于位掩码,如保留低 8 位:0xF234012F & 0x000000FF = 0x0000002F)
      2. or $d, $s, $t:$d = $s | $t (用于组合位域,如0xF2340000 | 0x000012BC = 0xF23412BC)
      3. xor $d, $s, $t:$d = $s ^ $t (位异或)
      4. nor $d, $s, $t:d= (s | $t) (位或非,用于取反:A nor 0 = ~A)
      5. 立即数逻辑指令:andi、ori、xori(16 位立即数零扩展,无nori)
  2. 移位指令
    1. 指令类型(移位量可为立即数或寄存器):
      1. sll $d, $s, shamt:逻辑左移 → $d = $s << shamt(高位补 0,示例:sll $t0,$t1,5 → t0=t1 左移 5 位)
      2. srl $d, $s, shamt:逻辑右移 → $d = $s >> shamt(低位补 0)
      3. sra $d, $s, shamt:算术右移 → $d = $s >>> shamt(高位补符号位,用于有符号数)
    2. 应用:左移 1 位等价于 ×2,左移 3 位等价于 ×8(如 C 代码a=2*b对应sll $t0,$s1,1)
  3. 常量生成与乘除操作
    1. 32 位常量生成:MIPS 立即数仅 16 位,需组合lui(加载高位立即数)和ori:
      1. 示例:C 代码int a=0xFEDC8765对应:
        lui $s0, 0xFEDC # $s0 = 0xFEDC0000(加载高16位)
        ori $s0, $s0, 0x8765 # $s0 = 0xFEDC0000 | 0x8765 = 0xFEDC8765
    2. 乘除操作:依赖专用寄存器hi(高位结果)和lo(低位结果):
      1. 乘法:mult $s, $t → 结果(64 位)存入 {hi, lo},需mfhi $d(读取 hi)、mflo $d(读取 lo)
      2. 除法:div $s, $t → 商存入 lo,余数存入 hi,同样通过mfhi/mflo读取
  4. 数组操作
    1. 数组存储:数组元素连续存储,基地址为首个元素地址(如 5 元素数组 base=0x12348000,元素地址为 base、base+4、base+8 等)
    2. 单元素操作示例:
      C 代码:
      1
      array[0] *=2; array[1] *=2(base=0x12348000)
      汇编代码:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      lui $s0, 0x1234       # $s0 = 0x12340000
      ori $s0, $s0, 0x8000 # $s0 = 0x12348000(数组基地址)

      lw $t1, 0($s0) # $t1 = array[0]
      sll $t1, $t1, 1 # $t1 = array[0] * 2
      sw $t1, 0($s0) # array[0] = $t1

      lw $t1, 4($s0) # $t1 = array[1]
      sll $t1, $t1, 1 # $t1 = array[1] * 2
      sw $t1, 4($s0) # array[1] = $t1
    3. for 循环操作数组:
      C 代码:
      1
      for(i=0;i<1000;i++) array[i] *=8
      汇编代码:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      # 初始化:$s0=数组基址(0x23B8F000),$s1=i=0,$t2=1000
      lui $s0, 0x23B8
      ori $s0, $s0, 0xF000
      addi $s1, $0, 0
      addi $t2, $0, 1000

      loop:
      slt $t0, $s1, $t2 # $t0=1(i<1000),否则0
      beq $t0, $0, done # 若i>=1000,跳至done
      sll $t0, $s1, 2 # $t0 = i*4(字节偏移)
      add $t0, $t0, $s0 # $t0 = array[i]地址
      lw $t1, 0($t0) # $t1 = array[i]
      sll $t1, $t1, 3 # $t1 = array[i] *8(左移3位)
      sw $t1, 0($t0) # array[i] = $t1
      addi $s1, $s1, 1 # i = i+1
      j loop # 跳回loop

      done:
  5. 函数调用机制
    1. 核心概念:
      1. 调用者(Caller):发起调用的函数(如 main)
      2. 被调用者(Callee):被调用的函数(如 sum)
    2. MIPS 函数调用约定
      1. 传参:前 4 个参数通过a0−a3 传递,超过 4 个需用栈
      2. 返回值:通过v0−v1 返回
      3. 跳转与返回:jal(jump and link)指令跳转(同时将返回地址存入$ra),jr $ra(jump register)指令返回
    3. 简单函数示例:
      C 代码:
      1
      2
      3
      4
      5
      6
      7
      8
      void main(){simple(); a=b+c;} void simple(){return;}
      ```
      汇编代码:
      ```asm
      0x00400200 main: jal simple # 跳至simple,$ra=0x00400204(下一条指令地址)
      0x00400204 add $s0, $s1, $s2 # a=b+c
      ...
      0x00401020 simple: jr $ra # 跳回$ra(0x00400204)
  6. 分支、循环、栈内存与寻址方式
    1. 条件标志(CPSR 寄存器):
      标志位 名称 含义
      N Negative(负) 指令结果为负(结果第 31 位为 1)
      Z Zero(零) 指令结果为 0
      C Carry(进位) 指令执行产生进位 / 借位
      V Overflow(溢出) 指令执行产生溢出
    2. 分支指令(流程跳转):用于 “打破顺序执行”,分为条件分支(满足条件才跳)和无条件分支(强制跳),依赖 CPSR 寄存器的标志位(N/Z/C/V)判断条件,核心分支指令如下:
      指令类型 指令 格式 功能 示例
      条件分支 beq beq $s, $t, label 若$s == $t,跳 label beq $s0, $s1, target(s0==s1 跳 target)
      bne bne $s, $t, label 若$s != $t,跳 label bne $s0, $s1, target(s0!=s1 跳 target)
      无条件分支 j j label 强制跳 label(直接使用地址) j target(跳 target)
      jr jr $s 强制跳 $s 存储的地址(寄存器间接跳转) jr $ra(跳 $ra 地址,函数返回)
      jal jal label 跳 label,并将返回地址存入 $ra jal sum(调用 sum,保存返回地址)
    3. 循环与条件语句(if/while/for)
      1. MIPS 通过 “分支指令 + 跳转指令” 实现高级语言的条件与循环逻辑,核心是 “判断条件→跳转到对应代码块”
      2. if 语句示例
        C 代码:
        1
        2
        3
        4
        5
        6
        7
        8
        if(i == j) f = g + h; f = f - i;(s0=f,s1=g,s2=h,s3=i,$s4=j)
        ```
        汇编代码:
        ```asm
        bne $s3, $s4, L1 # 若i!=j,跳L1(跳过if体)
        add $s0, $s1, $s2 # if体:f = g + h(i==j时执行)
        L1:
        sub $s0, $s0, $s3 # 无论if是否执行,都执行f = f - i
      3. if-else 语句示例
        C 代码:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        if(i == j) f = g + h; else f = f - i;
        ```
        汇编代码:
        ```asm
        bne $s3, $s4, L1 # 若i!=j,跳L1(执行else)
        add $s0, $s1, $s2 # if体:f = g + h
        j done # 跳done,跳过else
        L1:
        sub $s0, $s0, $s3 # else体:f = f -i
        done:
      4. while 循环示例
        C 代码:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        int pow=1, x=0; while(pow!=128) { pow*=2; x++; }  (s0=pow,s1=x)
        ```
        汇编代码:
        ```asm
        addi $s0, $0, 1 # pow=1
        add $s1, $0, $0 # x=0
        addi $t0, $0, 128 # $t0=128 (循环终止条件)
        while:
        beq $s0, $t0, done # 若pow==128,跳done (终止循环)
        sll $s0, $s0, 1 # pow = pow*2 (左移1位)
        addi $s1, $s1, 1 # x = x+1
        j while # 跳回while,继续循环
        done:
      5. for 循环示例
        C 代码:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        int sum=0, i; for(i=0; i!=10; i++) sum +=i; (s0=i,s1=sum)
        ```
        汇编代码:
        ```asm
        addi $s1, $0, 0 # sum=0
        add $s0, $0, $0 # i=0
        addi $t0, $0, 10 # $t0=10 (循环终止条件)
        for:
        beq $s0, $t0, done # 若i==10,跳done (终止循环)
        add $s1, $s1, $s0 # sum = sum +i
        addi $s0, $s0, 1 # i = i+1
        j for # 跳回for,继续循环
        done:
    4. 栈内存深度应用(多函数嵌套与递归)
      1. 栈的核心特性是 “LIFO(后进先出)”,生长方向为 “高地址→低地址”,$sp始终指向栈顶,主要用于:
        1. 保存被调用者需保留的寄存器(s0−s7、$ra)
        2. 传递超过 4 个的函数参数
        3. 存储递归函数的中间变量
      2. 多函数嵌套(保存 $ra)
        若函数 A 调用函数 B,函数 B 再调用函数 C,jal B会覆盖$ra中 A 的返回地址,因此 B 需先将$ra压栈,再调用 C,示例:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        proc1: # 函数A: 调用proc2
        addi $sp, $sp, -4 # 栈扩容4字节(存$ra)
        sw $ra, 0($sp) # 保存proc1的返回地址到栈
        jal proc2 # 调用proc2,$ra被更新为proc1中jal后的地址
        lw $ra, 0($sp) # 恢复proc1的返回地址
        addi $sp, $sp, 4 # 栈缩容4字节
        jr $ra # 返回proc1的调用者

        proc2: # 函数B: 被proc1调用
        jr $ra # 返回proc1 ($ra存储proc1中jal后的地址)
      3. 递归函数示例(阶乘)
        C 代码:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        int factorial(int n) { return n==1 ? 1 : n*factorial(n-1); }
        ```
        汇编代码($a0=n,$v0= 返回值):
        ```asm
        .data
        n: .word 5 # 计算5的阶乘

        .text
        .globl main
        main:
        lw $a0, n # $a0 = 5 (传入factorial的参数)
        jal factorial # 调用factorial
        # 打印结果
        li $v0, 1 # 系统调用1:打印整数
        move $a0, $v0 # $a0 = 阶乘结果 (factorial的返回值)
        syscall
        # 退出程序
        li $v0, 10 # 系统调用10: 退出
        syscall

        factorial:
        # 1. 栈扩容8字节 (存$ra和$a0,递归需保存n)
        addi $sp, $sp, -8
        sw $ra, 4($sp) # 保存当前返回地址到栈偏移4
        sw $a0, 0($sp) # 保存当前n到栈偏移0

        # 2. 递归终止条件: n==1
        li $v0, 1 # $v0=1 (终止条件返回值)
        beq $a0, $v0, base_case # 若n==1,跳base_case

        # 3. 递归调用: factorial(n-1)
        addi $a0, $a0, -1 # $a0 = n-1
        jal factorial # 调用factorial(n-1),$ra更新为当前jal后的地址

        # 4. 计算n * factorial(n-1)
        lw $a0, 0($sp) # 恢复当前n (从栈中取)
        mul $v0, $a0, $v0 # $v0 = n * factorial(n-1) (返回值)

        # 5. 恢复寄存器+栈缩容
        base_case:
        lw $ra, 4($sp) # 恢复返回地址
        addi $sp, $sp, 8 # 栈缩容8字节
        jr $ra # 返回调用者

今日总结

  1. 今天速学了html和css的一些基础知识