You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular中优化实现RISC-V RV32I完整内存模拟?

优化RV32I Web模拟器内存实现的思路(Angular + 无数据库)

核心思路:稀疏存储+按需初始化

RV32I的4GB内存绝大多数区域在模拟过程中是未被修改的初始状态(全0),完全没必要预分配所有地址空间。只需要记录被写入过的地址,未写入的地址直接返回默认值0即可,这能把内存占用降到最低。

方案1:极简稀疏Map实现

直接用Map存储被修改过的4字节对齐地址及其值,读取时默认返回0,写入时仅在值非0时存储(值为0时可删除键进一步节省空间)。这种实现最简洁,适合大部分场景。

@Injectable({ providedIn: 'root' })
export class RiscvMemoryService {
  private memoryMap = new Map<number, number>(); // key: 4字节对齐的地址,value: 32位无符号整数

  read32(address: number): number {
    // RV32I字访问要求地址4字节对齐,可根据需求调整校验逻辑
    if (address % 4 !== 0) {
      throw new Error('Word access requires 4-byte aligned address');
    }
    // 未修改的地址返回默认值0
    return this.memoryMap.get(address) ?? 0;
  }

  write32(address: number, value: number): void {
    if (address % 4 !== 0) {
      throw new Error('Word access requires 4-byte aligned address');
    }
    const uint32Value = value & 0xFFFFFFFF; // 确保值是32位无符号整数
    if (uint32Value === 0) {
      // 写入0时删除键,避免无用存储
      this.memoryMap.delete(address);
    } else {
      this.memoryMap.set(address, uint32Value);
    }
  }
}

方案2:分块内存管理(性能优化版)

如果模拟过程中内存修改比较集中,可按固定大小的块划分内存(比如4KB块,包含1024个4字节元素),仅在块内有元素被修改时创建该块。这种方式能减少单个Map的键数量,提升查找和写入效率,同时利用Uint32Array进一步优化内存占用和访问速度。

@Injectable({ providedIn: 'root' })
export class RiscvMemoryService {
  private readonly BLOCK_ELEMENT_COUNT = 1024; // 每个块包含1024个4字节元素(4KB)
  private memoryBlocks = new Map<number, Uint32Array>(); // key: 块索引,value: 32位无符号数组

  // 计算地址对应的块索引
  private getBlockIndex(address: number): number {
    return Math.floor(address / (4 * this.BLOCK_ELEMENT_COUNT));
  }

  // 计算地址在块内的元素偏移
  private getBlockOffset(address: number): number {
    return Math.floor((address % (4 * this.BLOCK_ELEMENT_COUNT)) / 4);
  }

  read32(address: number): number {
    if (address % 4 !== 0) {
      throw new Error('Word access requires 4-byte aligned address');
    }
    const blockIndex = this.getBlockIndex(address);
    const block = this.memoryBlocks.get(blockIndex);
    // 未创建的块直接返回0
    if (!block) return 0;
    const offset = this.getBlockOffset(address);
    return block[offset];
  }

  write32(address: number, value: number): void {
    if (address % 4 !== 0) {
      throw new Error('Word access requires 4-byte aligned address');
    }
    const blockIndex = this.getBlockIndex(address);
    let block = this.memoryBlocks.get(blockIndex);
    // 块不存在则创建,初始全0
    if (!block) {
      block = new Uint32Array(this.BLOCK_ELEMENT_COUNT);
      this.memoryBlocks.set(blockIndex, block);
    }
    const offset = this.getBlockOffset(address);
    const uint32Value = value & 0xFFFFFFFF;
    block[offset] = uint32Value;

    // 可选优化:如果写入后块内全为0,删除块节省内存
    if (uint32Value === 0) {
      const isBlockAllZero = block.every(val => val === 0);
      if (isBlockAllZero) {
        this.memoryBlocks.delete(blockIndex);
      }
    }
  }
}

扩展建议

  • 如果需要支持字节/半字访问(如lb/lh/sb/sh),可扩展read8/read16/write8/write16方法,通过地址偏移提取对应字节并处理符号扩展逻辑。
  • 若需持久化内存状态(比如刷新页面后恢复),可将memoryMap或memoryBlocks序列化为JSON,存储在localStorage中,加载时反序列化即可(注意Uint32Array需要转换为普通数组再序列化)。

内容的提问来源于stack exchange,提问作者Eduardo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 12:57:36