#include "common.h"
#include <stdio.h>

#define DEBUG 0

#define GET_POWER_OF_2(X) __builtin_ctz(X)

/*
    组相联映射Data Cache，16KB大小
    每行存放16个字节，共1024行
*/
#define DCACHE_LINE_PER_SET 256
#define DCACHE_SIZE 16384
#define DCACHE_DATA_PER_LINE 16 // 必须是8字节的倍数
#define DCACHE_DATA_PER_LINE_ADDR_BITS                                         \
  GET_POWER_OF_2(                                                              \
      DCACHE_DATA_PER_LINE) // 必须与上面设置一致，即64字节，需要6位地址
#define DCACHE_SET (DCACHE_SIZE / DCACHE_DATA_PER_LINE / DCACHE_LINE_PER_SET)
#define DCACHE_SET_ADDR_BITS                                                   \
  GET_POWER_OF_2(DCACHE_SET) // 必须与上面设置一致，即256行，需要8位地址

/*
    L2 Cache配置，1MB大小
    每行存放128个字节，共4096行
*/
#define L2CACHE_LINE_PER_SET 4096
#define L2CACHE_SIZE 1048576
#define L2CACHE_DATA_PER_LINE 128 // 必须是8字节的倍数
#define L2CACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(L2CACHE_DATA_PER_LINE)
#define L2CACHE_SET                                                            \
  (L2CACHE_SIZE / L2CACHE_DATA_PER_LINE / L2CACHE_LINE_PER_SET)
#define L2CACHE_SET_ADDR_BITS GET_POWER_OF_2(L2CACHE_SET)

/*
    组相联映射Instruction Cache，16KB大小
    每行存放16个字节，共1024行
*/
#define ICACHE_LINE_PER_SET 64
#define ICACHE_SIZE 16384
#define ICACHE_DATA_PER_LINE 16 // 必须是8字节的倍数
#define ICACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(ICACHE_DATA_PER_LINE)
#define ICACHE_SET (ICACHE_SIZE / ICACHE_DATA_PER_LINE / ICACHE_LINE_PER_SET)
#define ICACHE_SET_ADDR_BITS GET_POWER_OF_2(ICACHE_SET)

// DCache行的结构
struct DCACHE_LineStruct {
  UINT8 Valid;
  UINT8 Age;
  UINT8 Dirty;
  UINT64 Tag;
  UINT8 Data[DCACHE_DATA_PER_LINE];
};

struct DCACHE_Set {
  struct DCACHE_LineStruct Line[DCACHE_LINE_PER_SET];
} DCache[DCACHE_SET];

// L2Cache行的结构
struct L2CACHE_LineStruct {
  UINT8 Valid;
  UINT8 Age;
  UINT8 Dirty;
  UINT64 Tag;
  UINT8 Data[L2CACHE_DATA_PER_LINE];
};

struct L2CACHE_Set {
  struct L2CACHE_LineStruct Line[L2CACHE_LINE_PER_SET];
} L2Cache[L2CACHE_SET];

// ICache行的结构
struct ICACHE_LineStruct {
  UINT8 Valid;
  UINT8 Age;
  UINT64 Tag;
  UINT8 Data[ICACHE_DATA_PER_LINE];
};

struct ICACHE_Set {
  struct ICACHE_LineStruct Line[ICACHE_LINE_PER_SET];
} ICache[ICACHE_SET];

// 函数声明部分 - 防止隐式声明错误
void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line);
void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set, UINT8 line);
void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line);
void InitL2Cache(void);

/*
    DCache初始化代码，一般需要把DCache的有效位Valid设置为0
    模拟器启动时，会调用此InitDataCache函数
*/
void InitDataCache() {
  UINT32 i, j;
  printf("[%s] +-----------------------------------+\n", __func__);
  printf("[%s] |   Cikki 的Data Cache初始化ing.... |\n", __func__);
  printf("[%s] +-----------------------------------+\n", __func__);
  for (i = 0; i < DCACHE_SET; i++) {
    for (j = 0; j < DCACHE_LINE_PER_SET; j++) {
      DCache[i].Line[j].Valid = 0;
      DCache[i].Line[j].Dirty = 0;
      DCache[i].Line[j].Tag = 0;
      DCache[i].Line[j].Age = j;
    }
  }
}

/*
    L2Cache初始化代码
*/
void InitL2Cache() {
  UINT32 i, j;
  printf("[%s] +-----------------------------------+\n", __func__);
  printf("[%s] |   Cikki 的L2 Cache初始化ing....   |\n", __func__);
  printf("[%s] +-----------------------------------+\n", __func__);
  for (i = 0; i < L2CACHE_SET; i++) {
    for (j = 0; j < L2CACHE_LINE_PER_SET; j++) {
      L2Cache[i].Line[j].Valid = 0;
      L2Cache[i].Line[j].Dirty = 0;
      L2Cache[i].Line[j].Tag = 0;
      L2Cache[i].Line[j].Age = j;
    }
  }
}

/*
    ICache初始化代码
*/
void InitInstCache(void) {
  UINT32 i, j;
  printf("[%s] +-----------------------------------+\n", __func__);
  printf("[%s] |   Cikki 的Inst Cache初始化ing.... |\n", __func__);
  printf("[%s] +-----------------------------------+\n", __func__);
  for (i = 0; i < ICACHE_SET; i++) {
    for (j = 0; j < ICACHE_LINE_PER_SET; j++) {
      ICache[i].Line[j].Valid = 0;
      ICache[i].Line[j].Tag = 0;
      ICache[i].Line[j].Age = j;
    }
  }

  // 初始化L2缓存
  InitL2Cache();
}

// 在第Set组中，从DCACHE_LINE_PER_SET路中，找到需要替换的Cache行
// 如果DCACHE_LINE_PER_SET行中，有某行的Valid=0，则返回该行行号
// 否则，返回Age最大的行的行号
UINT8 GetReplaceLineData(UINT32 Set) {
  int max_index = 0;
  int max_age = -1;
  for (int i = 0; i < DCACHE_LINE_PER_SET; i++) {
    if (DCache[Set].Line[i].Valid == 0)
      return i;
    if (DCache[Set].Line[i].Age > max_age) {
      max_index = i;
      max_age = DCache[Set].Line[i].Age;
    }
  }

  return max_index;
}

// 在L2 Cache的第Set组中找到需要替换的行
UINT8 GetReplaceLineL2(UINT32 Set) {
  int max_index = 0;
  int max_age = -1;
  for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) {
    if (L2Cache[Set].Line[i].Valid == 0)
      return i;
    if (L2Cache[Set].Line[i].Age > max_age) {
      max_index = i;
      max_age = L2Cache[Set].Line[i].Age;
    }
  }

  return max_index;
}

// LRU替换策略 - ICache
UINT8 GetReplaceLineInst(UINT32 Set) {
  int max_index = 0;
  int max_age = -1;
  for (int i = 0; i < ICACHE_LINE_PER_SET; i++) {
    if (ICache[Set].Line[i].Valid == 0)
      return i;
    if (ICache[Set].Line[i].Age > max_age) {
      max_index = i;
      max_age = ICache[Set].Line[i].Age;
    }
  }

  return max_index;
}

// 更新Age，在第Set组中，将HitLine指定的Cache行的Age设置为0，其他行的Age要相应调整
// 确保DCACHE_LINE_PER_SET行的Age分别为0~DCACHE_LINE_PER_SET-1，且唯一
void UpdateAgeData(UINT32 Set, UINT8 HitLine) {
  UINT8 old_age = DCache[Set].Line[HitLine].Age;
  for (int i = 0; i < DCACHE_LINE_PER_SET; ++i) {
    if (DCache[Set].Line[i].Age < old_age)
      DCache[Set].Line[i].Age++;
  }
  DCache[Set].Line[HitLine].Age = 0;
}

// 更新L2 Cache的Age
void UpdateAgeL2(UINT32 Set, UINT8 HitLine) {
  UINT8 old_age = L2Cache[Set].Line[HitLine].Age;
  for (int i = 0; i < L2CACHE_LINE_PER_SET; ++i) {
    if (L2Cache[Set].Line[i].Age < old_age)
      L2Cache[Set].Line[i].Age++;
  }
  L2Cache[Set].Line[HitLine].Age = 0;
}

// 更新Age - ICache
void UpdateAgeInst(UINT32 Set, UINT8 HitLine) {
  int HitAge = ICache[Set].Line[HitLine].Age;
  ICache[Set].Line[HitLine].Age = 0;
  for (int i = 0; i < ICACHE_LINE_PER_SET; i++) {
    if (i != HitLine && ICache[Set].Line[i].Age < HitAge)
      ICache[Set].Line[i].Age++;
  }
}

/*
    从Memory中读入一行数据到Data Cache中
*/
void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) {
  // 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行
  // 提供了一个函数，一次可以读入8个字节

  // 地址对齐到缓存行边界
  const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1);
  UINT64 *const cache_line_ptr = (UINT64 *)DCache[set].Line[line].Data;

  if (DEBUG) {
    printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n",
           __func__, set, line, AlignAddress);
  }

  // 分8字节块读取
  for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
    const UINT64 read_addr = AlignAddress + i * sizeof(UINT64);
    const UINT64 data = ReadMemory(read_addr);

    cache_line_ptr[i] = data;

    if (DEBUG) {
      printf("  [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data);
    }
  }
}

/*
    从内存加载一行数据到指令缓存中
*/
void LoadInstCacheLineFromMemory(UINT64 Address, UINT32 set, UINT8 line) {
  // 一次性从Memory中将ICACHE_DATA_PER_LINE数据读入某个Instruction Cache行
  // 提供了一个函数，一次可以读入8个字节

  // 地址对齐到缓存行边界
  const UINT64 AlignAddress = Address & ~(ICACHE_DATA_PER_LINE - 1);
  UINT64 *const cache_line_ptr = (UINT64 *)ICache[set].Line[line].Data;

  if (DEBUG) {
    printf("[%s] Loading cache line (set=%u, line=%u) from memory %016llX\n",
           __func__, set, line, AlignAddress);
  }

  // 分8字节块读取
  for (UINT32 i = 0; i < ICACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
    const UINT64 read_addr = AlignAddress + i * sizeof(UINT64);
    const UINT64 data = ReadMemory(read_addr);

    cache_line_ptr[i] = data;

    if (DEBUG) {
      printf("  [LOAD] Address=%016llX -> Data=%016llX\n", read_addr, data);
    }
  }
}

/*
    将Data Cache中的一行数据，写入存储器
*/
void StoreDataCacheLineToMemory(UINT64 Address, UINT32 set, UINT8 line) {
  // 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中
  // 提供了一个函数，一次可以写入8个字节

  // 地址对齐到缓存行边界
  const UINT64 AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1);
  UINT64 *const cache_line_ptr = (UINT64 *)DCache[set].Line[line].Data;

  if (DEBUG) {
    printf("[%s] Storing cache line (set=%u, line=%u) to memory %016llX\n",
           __func__, set, line, AlignAddress);
  }

  // 分8字节块写入
  for (UINT32 i = 0; i < DCACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
    const UINT64 write_addr = AlignAddress + i * sizeof(UINT64);
    const UINT64 data = cache_line_ptr[i];

    WriteMemory(write_addr, data);

    if (DEBUG) {
      printf("  [STORE] Address=%016llX <- Data=%016llX\n", write_addr, data);
    }
  }
}

/*
    从L2 Cache中读取数据到L1 DCache中
    如果L2命中，则从L2读取数据
    如果L2未命中，则从内存读取数据并更新L2
*/
UINT8 LoadDataFromL2ToL1(UINT64 Address, UINT32 L1_set, UINT8 L1_line) {
  UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET;
  UINT64 L2_tag =
      Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS);
  UINT8 L2_hit = 0;
  UINT8 L2_line = 0;

  // 检查L2 Cache是否命中
  for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) {
    if (L2Cache[L2_set].Line[i].Valid &&
        L2Cache[L2_set].Line[i].Tag == L2_tag) {
      L2_hit = 1;
      L2_line = i;
      break;
    }
  }

  if (L2_hit) {
    // L2命中，从L2读取数据到L1
    if (DEBUG) {
      printf("[%s] L2 Cache hit! Loading from L2 to L1 (Address=%016llX)\n",
             __func__, Address);
    }

    // 由于L2缓存行可能比L1大，需要找到正确的偏移量
    UINT64 L1_aligned_addr = Address & ~(DCACHE_DATA_PER_LINE - 1);
    UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1);
    UINT32 offset_in_L2 = (L1_aligned_addr - L2_aligned_addr);

    // 从L2复制数据到L1
    for (int i = 0; i < DCACHE_DATA_PER_LINE; i++) {
      DCache[L1_set].Line[L1_line].Data[i] =
          L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i];
    }

    // 更新L2的LRU信息
    UpdateAgeL2(L2_set, L2_line);
    return 'H'; // L2命中
  } else {
    // L2未命中，从内存加载数据
    if (DEBUG) {
      printf("[%s] L2 Cache miss! Loading from memory (Address=%016llX)\n",
             __func__, Address);
    }

    // 首先从内存加载到L1
    LoadDataCacheLineFromMemory(Address, L1_set, L1_line);

    // 然后更新L2
    UINT8 L2_replace_line = GetReplaceLineL2(L2_set);

    // 如果L2中要替换的行是脏的，需要先写回内存
    if (L2Cache[L2_set].Line[L2_replace_line].Valid &&
        L2Cache[L2_set].Line[L2_replace_line].Dirty) {
      UINT64 victim_addr =
          (L2Cache[L2_set].Line[L2_replace_line].Tag
           << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) |
          (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS);

      // 写回内存
      for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
        const UINT64 write_addr = victim_addr + i * sizeof(UINT64);
        const UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set]
                                     .Line[L2_replace_line]
                                     .Data[i * sizeof(UINT64)];
        WriteMemory(write_addr, *data_ptr);
      }
    }

    // 从内存加载数据到L2
    UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1);
    for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
      const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64);
      const UINT64 data = ReadMemory(read_addr);
      UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set]
                             .Line[L2_replace_line]
                             .Data[i * sizeof(UINT64)];
      *data_ptr = data;
    }

    // 更新L2缓存行信息
    L2Cache[L2_set].Line[L2_replace_line].Valid = 1;
    L2Cache[L2_set].Line[L2_replace_line].Dirty = 0;
    L2Cache[L2_set].Line[L2_replace_line].Tag = L2_tag;
    UpdateAgeL2(L2_set, L2_replace_line);

    return 'M'; // L2未命中
  }
}

/*
    将L1 DCache中的一行数据写入L2 Cache
*/
void StoreDataFromL1ToL2(UINT64 Address, UINT32 L1_set, UINT8 L1_line) {
  UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET;
  UINT64 L2_tag =
      Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS);
  UINT8 L2_hit = 0;
  UINT8 L2_line = 0;

  // 检查L2 Cache是否命中
  for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) {
    if (L2Cache[L2_set].Line[i].Valid &&
        L2Cache[L2_set].Line[i].Tag == L2_tag) {
      L2_hit = 1;
      L2_line = i;
      break;
    }
  }

  if (!L2_hit) {
    // L2未命中，需要分配一个新的L2缓存行
    L2_line = GetReplaceLineL2(L2_set);

    // 如果要替换的L2行是脏的，需要先写回内存
    if (L2Cache[L2_set].Line[L2_line].Valid &&
        L2Cache[L2_set].Line[L2_line].Dirty) {
      UINT64 victim_addr =
          (L2Cache[L2_set].Line[L2_line].Tag
           << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) |
          (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS);

      // 写回内存
      for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
        const UINT64 write_addr = victim_addr + i * sizeof(UINT64);
        const UINT64 *data_ptr =
            (UINT64 *)&L2Cache[L2_set].Line[L2_line].Data[i * sizeof(UINT64)];
        WriteMemory(write_addr, *data_ptr);
      }
    }

    // 从内存加载完整的L2缓存行
    UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1);
    for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
      const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64);
      const UINT64 data = ReadMemory(read_addr);
      UINT64 *data_ptr =
          (UINT64 *)&L2Cache[L2_set].Line[L2_line].Data[i * sizeof(UINT64)];
      *data_ptr = data;
    }

    L2Cache[L2_set].Line[L2_line].Valid = 1;
    L2Cache[L2_set].Line[L2_line].Tag = L2_tag;
  }

  // 更新L2缓存行中对应的数据
  UINT64 L1_aligned_addr = Address & ~(DCACHE_DATA_PER_LINE - 1);
  UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1);
  UINT32 offset_in_L2 = (L1_aligned_addr - L2_aligned_addr);

  // 从L1复制数据到L2
  for (int i = 0; i < DCACHE_DATA_PER_LINE; i++) {
    L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i] =
        DCache[L1_set].Line[L1_line].Data[i];
  }

  // 标记L2缓存行为脏
  L2Cache[L2_set].Line[L2_line].Dirty = 1;
  UpdateAgeL2(L2_set, L2_line);
}

/*
    从L2 Cache中加载指令到I-Cache
    如果L2缓存命中，则从L2读取数据
    如果L2缓存未命中，则从内存读取数据并同时更新L2缓存
*/
UINT8 LoadInstFromL2ToICache(UINT64 Address, UINT32 I_set, UINT8 I_line) {
  UINT32 L2_set = (Address >> L2CACHE_DATA_PER_LINE_ADDR_BITS) % L2CACHE_SET;
  UINT64 L2_tag =
      Address >> (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS);
  UINT8 L2_hit = 0;
  UINT8 L2_line = 0;

  // 检查L2 Cache是否命中
  for (int i = 0; i < L2CACHE_LINE_PER_SET; i++) {
    if (L2Cache[L2_set].Line[i].Valid &&
        L2Cache[L2_set].Line[i].Tag == L2_tag) {
      L2_hit = 1;
      L2_line = i;
      break;
    }
  }

  if (L2_hit) {
    // L2命中，从L2读取数据到I-Cache
    if (DEBUG) {
      printf("[%s] L2 Cache hit! Loading instruction from L2 to I-Cache "
             "(Address=%016llX)\n",
             __func__, Address);
    }

    // 由于L2缓存行可能比I-Cache大，需要找到正确的偏移量
    UINT64 I_aligned_addr = Address & ~(ICACHE_DATA_PER_LINE - 1);
    UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1);
    UINT32 offset_in_L2 = (I_aligned_addr - L2_aligned_addr);

    // 从L2复制数据到I-Cache
    for (int i = 0; i < ICACHE_DATA_PER_LINE; i++) {
      ICache[I_set].Line[I_line].Data[i] =
          L2Cache[L2_set].Line[L2_line].Data[offset_in_L2 + i];
    }

    // 更新L2的LRU信息
    UpdateAgeL2(L2_set, L2_line);
    return 'H'; // L2命中
  } else {
    // L2未命中，从内存加载数据
    if (DEBUG) {
      printf("[%s] L2 Cache miss! Loading instruction from memory "
             "(Address=%016llX)\n",
             __func__, Address);
    }

    // 首先从内存加载到I-Cache
    LoadInstCacheLineFromMemory(Address, I_set, I_line);

    // 然后更新L2
    UINT8 L2_replace_line = GetReplaceLineL2(L2_set);

    // 如果L2中要替换的行是脏的，需要先写回内存
    if (L2Cache[L2_set].Line[L2_replace_line].Valid &&
        L2Cache[L2_set].Line[L2_replace_line].Dirty) {
      UINT64 victim_addr =
          (L2Cache[L2_set].Line[L2_replace_line].Tag
           << (L2CACHE_DATA_PER_LINE_ADDR_BITS + L2CACHE_SET_ADDR_BITS)) |
          (L2_set << L2CACHE_DATA_PER_LINE_ADDR_BITS);

      // 写回内存
      for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
        const UINT64 write_addr = victim_addr + i * sizeof(UINT64);
        const UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set]
                                     .Line[L2_replace_line]
                                     .Data[i * sizeof(UINT64)];
        WriteMemory(write_addr, *data_ptr);
      }
    }
    // 从内存加载数据到L2
    UINT64 L2_aligned_addr = Address & ~(L2CACHE_DATA_PER_LINE - 1);
    for (UINT32 i = 0; i < L2CACHE_DATA_PER_LINE / sizeof(UINT64); i++) {
      const UINT64 read_addr = L2_aligned_addr + i * sizeof(UINT64);
      const UINT64 data = ReadMemory(read_addr);
      UINT64 *data_ptr = (UINT64 *)&L2Cache[L2_set]
                             .Line[L2_replace_line]
                             .Data[i * sizeof(UINT64)];
      *data_ptr = data;
    }

    // 更新L2缓存行信息
    L2Cache[L2_set].Line[L2_replace_line].Valid = 1;
    L2Cache[L2_set].Line[L2_replace_line].Dirty = 0;
    L2Cache[L2_set].Line[L2_replace_line].Tag = L2_tag;
    UpdateAgeL2(L2_set, L2_replace_line);

    return 'M'; // L2未命中
  }
}

/*
 * 访问数据缓存的主函数
 * 参数：
 *   Address - 访问的内存地址
 *   Operation - 'L'表示读取，'S'表示写入，'M'表示修改（先读后写）
 *   DataSize - 访问的数据大小（1、2、4或8字节）
 *   StoreValue - 要写入的数据（如果是写入操作）
 *   LoadResult - 指向读取结果的指针（如果是读取操作）
 * 返回值：
 *   'H' - 缓存命中
 *   'M' - 缓存未命中
 */
UINT8 AccessDataCache(UINT64 Address, UINT8 Operation, UINT8 DataSize,
                      UINT64 StoreValue, UINT64 *LoadResult) {
  UINT32 Set = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) % DCACHE_SET;
  UINT8 Block = Address % DCACHE_DATA_PER_LINE;
  UINT64 Tag =
      Address >> (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS);
  UINT8 HitLine;
  UINT8 MissFlag = 'M';
  UINT64 ReadValue = 0;

  char L2Result;

  // 检查命中
  for (int i = 0; i < DCACHE_LINE_PER_SET; i++) {
    if (DCache[Set].Line[i].Valid && DCache[Set].Line[i].Tag == Tag) {
      HitLine = i;
      MissFlag = 'H';
      break;
    }
  }

  if (MissFlag == 'H') // Cache命中
  {
    if (Operation == 'L') // 读操作
    {
      // 读取数据，注意这里要按DataSize读取
      switch (DataSize) {
      case 1: // 1个字节
        ReadValue = DCache[Set].Line[HitLine].Data[Block];
        break;
      case 2:                 // 2个字节
        Block = Block & 0xFE; // 需对齐到2字节边界
        ReadValue = DCache[Set].Line[HitLine].Data[Block + 1];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0];
        break;
      case 4:                 // 4个字节
        Block = Block & 0xFC; // 需对齐到4字节边界
        ReadValue = DCache[Set].Line[HitLine].Data[Block + 3];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0];
        break;
      case 8:                 // 8个字节
        Block = Block & 0xF8; // 需对齐到8字节边界
        ReadValue = DCache[Set].Line[HitLine].Data[Block + 7];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 6];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 5];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 4];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 3];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 2];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 1];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[HitLine].Data[Block + 0];
        break;
      }
      *LoadResult = ReadValue;

      if (DEBUG) {
        printf("[%s] Address=%016llX Operation=%c DataSize=%u "
               "StoreValue=%016llX ReadValue=%016llX\n",
               __func__, Address, Operation, DataSize, StoreValue, ReadValue);
      }
    } else if (Operation == 'S' ||
               Operation == 'M') // 写操作（修改操作在此等价于写操作）
    {
      if (DEBUG) {
        printf("[%s] Address=%016llX Operation=%c DataSize=%u "
               "StoreValue=%016llX\n",
               __func__, Address, Operation, DataSize, StoreValue);
      }

      // 写操作，需要将新的StoreValue更新到CacheLine中
      switch (DataSize) {
      case 1: // 1个字节
        DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF;
        break;
      case 2:                 // 2个字节
        Block = Block & 0xFE; // 需对齐到2字节边界
        DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF;
        break;
      case 4:                 // 4个字节
        Block = Block & 0xFC; // 需对齐到4字节边界
        DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF;
        break;
      case 8:                 // 8个字节
        Block = Block & 0xF8; // 需对齐到8字节边界
        DCache[Set].Line[HitLine].Data[Block + 0] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 1] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 2] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 3] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 4] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 5] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 6] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[HitLine].Data[Block + 7] = StoreValue & 0xFF;
        break;
      }
      DCache[Set].Line[HitLine].Dirty = 1;

      // 写直达，同时更新L2
      StoreDataFromL1ToL2(Address, Set, HitLine);
    }
    UpdateAgeData(Set, HitLine);
  } else // Cache未命中
  {
    UINT8 replace_Line = GetReplaceLineData(Set);
    if (DEBUG) {
      printf(
          "[%s] Address=%016llX Operation=%c DataSize=%u StoreValue=%016llX\n",
          __func__, Address, Operation, DataSize, StoreValue);
    }

    if (Operation == 'L') // 读操作
    {
      // 写回脏行到L2
      if (DCache[Set].Line[replace_Line].Valid &&
          DCache[Set].Line[replace_Line].Dirty) {
        UINT64 victim_addr =
            (DCache[Set].Line[replace_Line].Tag
             << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) |
            (Set << DCACHE_DATA_PER_LINE_ADDR_BITS);
        StoreDataFromL1ToL2(victim_addr, Set, replace_Line);
      }

      // 先从L2加载新行到L1
      L2Result = LoadDataFromL2ToL1(Address, Set, replace_Line);

      DCache[Set].Line[replace_Line].Valid = 1;
      DCache[Set].Line[replace_Line].Tag = Tag;
      DCache[Set].Line[replace_Line].Dirty = 0;

      // 再读取数据，按DataSize读取
      switch (DataSize) {
      case 1: // 1个字节
        ReadValue = DCache[Set].Line[replace_Line].Data[Block];
        break;
      case 2:                 // 2个字节
        Block = Block & 0xFE; // 需对齐到2字节边界
        ReadValue = DCache[Set].Line[replace_Line].Data[Block + 1];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0];
        break;
      case 4:                 // 4个字节
        Block = Block & 0xFC; // 需对齐到4字节边界
        ReadValue = DCache[Set].Line[replace_Line].Data[Block + 3];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0];
        break;
      case 8:                 // 8个字节
        Block = Block & 0xF8; // 需对齐到8字节边界
        ReadValue = DCache[Set].Line[replace_Line].Data[Block + 7];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 6];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 5];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 4];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 3];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 2];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 1];
        ReadValue = ReadValue << 8;
        ReadValue |= DCache[Set].Line[replace_Line].Data[Block + 0];
        break;
      }
      *LoadResult = ReadValue;
    } else if (Operation == 'S' ||
               Operation == 'M') // 写操作（修改操作在此等价于写操作）
    {
      // 写回脏行到L2
      if (DCache[Set].Line[replace_Line].Valid &&
          DCache[Set].Line[replace_Line].Dirty) {
        UINT64 victim_addr =
            (DCache[Set].Line[replace_Line].Tag
             << (DCACHE_DATA_PER_LINE_ADDR_BITS + DCACHE_SET_ADDR_BITS)) |
            (Set << DCACHE_DATA_PER_LINE_ADDR_BITS);
        StoreDataFromL1ToL2(victim_addr, Set, replace_Line);
      }

      // 先从L2加载新行到L1
      L2Result = LoadDataFromL2ToL1(Address, Set, replace_Line);

      DCache[Set].Line[replace_Line].Valid = 1;
      DCache[Set].Line[replace_Line].Tag = Tag;
      DCache[Set].Line[replace_Line].Dirty = 0;

      // 写操作，需要将新的StoreValue更新到CacheLine中
      switch (DataSize) {
      case 1: // 1个字节
        DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF;
        break;
      case 2:                 // 2个字节
        Block = Block & 0xFE; // 需对齐到2字节边界
        DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF;
        break;
      case 4:                 // 4个字节
        Block = Block & 0xFC; // 需对齐到4字节边界
        DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF;
        break;
      case 8:                 // 8个字节
        Block = Block & 0xF8; // 需对齐到8字节边界
        DCache[Set].Line[replace_Line].Data[Block + 0] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 1] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 2] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 3] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 4] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 5] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 6] = StoreValue & 0xFF;
        StoreValue = StoreValue >> 8;
        DCache[Set].Line[replace_Line].Data[Block + 7] = StoreValue & 0xFF;
        break;
      }
      DCache[Set].Line[replace_Line].Dirty = 1;

      // 写直达，同时更新L2
      StoreDataFromL1ToL2(Address, Set, replace_Line);
    }
    UpdateAgeData(Set, replace_Line);
  }

  // 返回L1的命中/未命中标志
  return MissFlag;
}

/*
 * 访问指令缓存的主函数
 * 参数：
 *   Address - 访问的内存地址
 *   Operation - 通常只用于读取指令，但我们保留此参数以保持接口一致
 *   InstSize - 指令大小（通常为4字节，但支持1、2、4、8字节）
 *   InstResult - 指向读取结果的指针
 * 返回值：
 *   'H' - 缓存命中
 *   'M' - 缓存未命中
 */
UINT8 AccessInstCache(UINT64 Address, UINT8 Operation, UINT8 InstSize,
                      UINT64 *InstResult) {
  UINT32 set = (Address >> ICACHE_DATA_PER_LINE_ADDR_BITS) % ICACHE_SET;
  UINT8 block = Address % ICACHE_DATA_PER_LINE;
  UINT64 tag =
      Address >> (ICACHE_DATA_PER_LINE_ADDR_BITS + ICACHE_SET_ADDR_BITS);
  UINT8 HitLine;
  UINT8 MissFlag = 'M';
  UINT64 ReadValue = 0;
  UINT32 L2Result;

  *InstResult = 0;

  // 检查命中
  for (int i = 0; i < ICACHE_LINE_PER_SET; i++) {
    if (ICache[set].Line[i].Valid && ICache[set].Line[i].Tag == tag) {
      HitLine = i;
      MissFlag = 'H';
      break;
    }
  }

  if (MissFlag == 'H') {
    // 命中处理
    switch (InstSize) {
    case 1:                 // 8位指令
      block = block & 0xFF; // 对齐到1字节边界
      ReadValue = ICache[set].Line[HitLine].Data[block + 0];
      break;
    case 2:                 // 16位指令
      block = block & 0xFE; // 对齐到2字节边界
      ReadValue = ICache[set].Line[HitLine].Data[block + 1];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 0];
      break;
    case 4:                 // 32位指令
      block = block & 0xFC; // 对齐到4字节边界
      ReadValue = ICache[set].Line[HitLine].Data[block + 3];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 2];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 1];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 0];
      break;
    case 8:                 // 64位指令(如RISC-V的128位指令集扩展)
      block = block & 0xF8; // 对齐到8字节边界
      ReadValue = ICache[set].Line[HitLine].Data[block + 7];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 6];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 5];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 4];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 3];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 2];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 1];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[HitLine].Data[block + 0];
      break;
    default:
      // 不支持的指令长度
      return 'M';
    }
    *InstResult = ReadValue;
    UpdateAgeInst(set, HitLine);
  } else {
    // 未命中处理
    UINT8 replace_line = GetReplaceLineInst(set);

    // 从L2加载数据到I-Cache
    L2Result = LoadInstFromL2ToICache(Address, set, replace_line);

    // 重新读取指令
    switch (InstSize) {
    case 1:
      block = block & 0xFF;
      ReadValue = ICache[set].Line[replace_line].Data[block + 0];
      break;
    case 2:
      block = block & 0xFE;
      ReadValue = ICache[set].Line[replace_line].Data[block + 1];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 0];
      break;
    case 4:
      block = block & 0xFC;
      ReadValue = ICache[set].Line[replace_line].Data[block + 3];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 2];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 1];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 0];
      break;
    case 8:
      block = block & 0xF8;
      ReadValue = ICache[set].Line[replace_line].Data[block + 7];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 6];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 5];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 4];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 3];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 2];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 1];
      ReadValue = ReadValue << 8;
      ReadValue |= ICache[set].Line[replace_line].Data[block + 0];
      break;
    default:
      // 不支持的指令长度
      return 'M';
    }
    *InstResult = ReadValue;
    ICache[set].Line[replace_line].Valid = 1;
    ICache[set].Line[replace_line].Tag = tag;
    UpdateAgeInst(set, replace_line);
  }

  // 返回I-Cache的命中/未命中标志
  return MissFlag;
}
