自学内容网 自学内容网

【IC面试问题:UCIE PHY LSM && AXI && Cache】

1 UCIE PHY LSM有几种状态? 以及L1和L2这两种低功耗状态有什么区别?

UCIE PHY LSM的状态:
RESET:系统复位的状态;
SBINI: SideBand初始化,在该状态对SideBand初始化,选择可用的SB Lane;
MBINT: MainBand初始化,在该状态对MainBand初始化,修复后坏的MB Lane。在该状态下MainBand处于最低速;
MBTRAIN: Mainband训练,在该状态对 Mainband 的 Clock、Valid、Data等Lane进行训练,使得UCIE链路工作在链路两端设备协商好的最高速或协商速率之下的物理最高速。PCIE是从Gen1最低速开始一点点往最高速进行训练的,但UCIE除了在初始化的时候为最低速,其在 MBTRAIN 状态对 Mainband 进行训练时一次切速到最高速进行训练,训练失败的话再进行降速或者减宽。
LINKINIT,链路管理状态,用以 D2D Adapter 完成初始链路管理。该状态时,进行 RDI Bring Up。
ACTIVE:UCIe 的正常工作状态,该状态时进行 Mainband 的数据传输,对应 PCIe 的 L0 状态;
L1/L2:低功耗状态,处于这两种状态下的 UCIe Module 功耗较低,处于 L2 状态的 UCIe Module 比 L1 睡眠程度更深、功耗更低。L1 可以直接退出到 MBTRAIN 状态,免去 SBINIT 及 MBINIT 的过程,但 L2 只能退出到 RESET 状态,重新进行链路的初始化。
TrainError:链路训练失败后进入该状态。

在 PHY 的初始化及训练过程中,Sideband、Mainband 是分开进行初始化和训练的。首先对 Sideband 进行初始化,使 Sideband 进入正常工作状态,便于后续初始化及训练过程中在 UCIe Link 上传递 Sideband Msg;然后进行 Mainband 初始化,UCIe Link 两侧的 Module 进行参数交换及协商、链路修复等工作,使 Mainband 能够工作在最低速(4 GT/s)。

2 AXI的特性? 通道之间有依赖关系吗? master和slave的valid和ready关系? 写数据可以优先于写地址吗?

AXI协议是基于burst突发的,并定义五个独立的事务通道;地址通道携带者控制信息,用于描述传输数据的性质;五个独立通道都由一组信息信号、以及提供双向握手机制的VALID和READY信号组成。
基本信号表示:

  • Master使用VALID信号来显示信道上的addr、data或ctrl信息何时可用。
  • Slave使用READY信号来显示它何时可以接受信息。
  • 读数据通道和写数据通道还包括LAST信号,以指示事务中最后数据项的传输。

在这里插入图片描述

主要特性:

  • 分离的地址/控制和数据阶段。
  • 使用基于突发的事务,只需起始地址发出。(Burst不得跨4KB边界,防止跨越Slave边界)
  • 支持发布多个超前地址(outstanding),因为控制和数据通道是分离的,地址的请求可以不等上一次的数据回来就可以继续发送;
    具体一点来说,当Master访问Slave时,可以不等待上一笔操作完成,就发下一个操作,这样Slave在控制流的处理上就可以流水起来,提高了传输速度,这就叫Outstanding。
  • 支持完成乱序事务(out-of-order),因为ID号。

握手依赖包括不同通道之间的依赖关系、以及同一通道中不同信号之间的依赖关系。首先记住一点:VALID和READY之间没有依赖关系,谁先谁后都可以,但是源端拉高VALID后必须保持住,直到终端拉高READY。

可以先有写数据,再有写地址。必须先有写数据,再有写响应。

3 什么是cache的hit和miss?

Cache用于加速数据访问。缓存的工作原理是利用局部性原理(Locality Principle),即程序在执行过程中往往会频繁访问某些数据或指令。通过将这些频繁访问的数据或指令存储在缓存中,可以显著提高系统的性能。
cahce line Size是cache的基本单位,从主存向cache迁移数据都是按照linesize为单位替换的。
Cache Hit:发生在当处理器请求的数据或指令已经在缓存中时。具体来说,当处理器需要读取或写入某个数据项时,它会首先检查缓存中是否存在该数据项。如果存在,则认为发生了 Cache Hit,处理器可以直接从缓存中读取或写入数据,而不需要访问较慢的主内存。
Cache Miss:

模拟缓存hit和miss的简单C代码

#include <stdio.h>
#include <stdlib.h>

#define CACHE_SIZE 8       // 缓存行数
#define BLOCK_SIZE 4       // 每个块的大小(字)
#define MEMORY_SIZE 64     // 主内存大小(字)

typedef struct {
    int valid;            // 有效位
    int tag;              // 标签
    int data[BLOCK_SIZE]; // 数据块
} CacheLine;

CacheLine cache[CACHE_SIZE];

// 初始化缓存
void init_cache() {
    for (int i = 0; i < CACHE_SIZE; i++) {
        cache[i].valid = 0;
        cache[i].tag = -1;
        for (int j = 0; j < BLOCK_SIZE; j++) {
            cache[i].data[j] = 0;
        }
    }
}

// 计算索引和标签
void calculate_index_tag(int address, int *index, int *tag) {
    *index = (address / BLOCK_SIZE) % CACHE_SIZE;
    *tag = address / (BLOCK_SIZE * CACHE_SIZE);
}

// 访问缓存
int access_cache(int address, int value, int write) {
    int index, tag;
    calculate_index_tag(address, &index, &tag);

    if (cache[index].valid && cache[index].tag == tag) {
        // Cache Hit
        printf("Cache Hit at address %d\n", address);
        if (write) {
            cache[index].data[address % BLOCK_SIZE] = value;
            printf("Data written to cache: %d\n", value);
        } else {
            printf("Data read from cache: %d\n", cache[index].data[address % BLOCK_SIZE]);
        }
        return 1;
    } else {
        // Cache Miss
        printf("Cache Miss at address %d\n", address);
        if (!write) {
            // 从主内存读取数据到缓存
            int block_start = (address / BLOCK_SIZE) * BLOCK_SIZE;
            for (int i = 0; i < BLOCK_SIZE; i++) {
                cache[index].data[i] = block_start + i; // 模拟从主内存读取数据
            }
            cache[index].valid = 1;
            cache[index].tag = tag;
            printf("Data loaded into cache: ");
            for (int i = 0; i < BLOCK_SIZE; i++) {
                printf("%d ", cache[index].data[i]);
            }
            printf("\n");
            printf("Data read from cache: %d\n", cache[index].data[address % BLOCK_SIZE]);
        } else {
            // 将数据写入缓存
            cache[index].data[address % BLOCK_SIZE] = value;
            cache[index].valid = 1;
            cache[index].tag = tag;
            printf("Data written to cache: %d\n", value);
        }
        return 0;
    }
}

int main() {
    init_cache();

    // 测试访问
    access_cache(0, 10, 1);  // 写入地址0,值为10
    access_cache(0, 0, 0);   // 读取地址0
    access_cache(4, 20, 1);  // 写入地址4,值为20
    access_cache(4, 0, 0);   // 读取地址4
    access_cache(8, 30, 1);  // 写入地址8,值为30
    access_cache(8, 0, 0);   // 读取地址8
    access_cache(0, 0, 0);   // 读取地址0 (再次)

    return 0;
}



原文地址:https://blog.csdn.net/li_kin/article/details/144413135

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!