All files / transpiler/output/codegen/assignment/handlers RegisterUtils.ts

100% Statements 20/20
100% Branches 15/15
100% Functions 6/6
100% Lines 20/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127                          52x                                                     14x 14x 14x 14x                         12x 12x   12x           5x     7x   7x   7x 1x     6x 6x   6x   12x                           32x                         4x                         4x          
/**
 * RegisterUtils
 * Shared utilities for register assignment handlers.
 *
 * Extracted from AccessPatternHandlers.ts and RegisterHandlers.ts to reduce duplication.
 */
import BitUtils from "../../../../../utils/BitUtils";
import TypeCheckUtils from "../../../../../utils/TypeCheckUtils";
import CodeGenState from "../../../../state/CodeGenState";
import type ICodeGenApi from "../../types/ICodeGenApi";
 
/** Get typed generator reference */
function gen(): ICodeGenApi {
  return CodeGenState.generator as ICodeGenApi;
}
 
/** Result from extracting bit range expressions */
interface IBitRangeParams {
  start: string;
  width: string;
  mask: string;
}
 
/** Result from MMIO optimization attempt */
interface IOptimizationResult {
  success: boolean;
  statement?: string;
}
 
/**
 * Utilities for register access patterns
 */
class RegisterUtils {
  /**
   * Extract start, width, and mask from bit range subscripts.
   * Consolidates the common pattern of getting expressions and generating mask.
   */
  static extractBitRangeParams(
    subscripts: readonly unknown[],
  ): IBitRangeParams {
    const start = gen().generateExpression(subscripts[0]);
    const width = gen().generateExpression(subscripts[1]);
    const mask = BitUtils.generateMask(width);
    return { start, width, mask };
  }
 
  /**
   * Try to generate MMIO-optimized memory access for byte-aligned writes.
   * Returns success: true with statement if optimization applicable, false otherwise.
   */
  static tryGenerateMMIO(
    fullName: string,
    regName: string,
    subscripts: readonly unknown[],
    value: string,
  ): IOptimizationResult {
    const startConst = gen().tryEvaluateConstant(subscripts[0]);
    const widthConst = gen().tryEvaluateConstant(subscripts[1]);
 
    if (
      startConst === undefined ||
      widthConst === undefined ||
      startConst % 8 !== 0 ||
      !TypeCheckUtils.isStandardWidth(widthConst)
    ) {
      return { success: false };
    }
 
    const baseAddr = CodeGenState.symbols!.registerBaseAddresses.get(regName);
    const memberOffset =
      CodeGenState.symbols!.registerMemberOffsets.get(fullName);
 
    if (baseAddr === undefined || memberOffset === undefined) {
      return { success: false };
    }
 
    const byteOffset = startConst / 8;
    const accessType = `uint${widthConst}_t`;
    const totalOffset =
      byteOffset === 0 ? memberOffset : `${memberOffset} + ${byteOffset}`;
 
    return {
      success: true,
      statement: `*((volatile ${accessType}*)(${baseAddr} + ${totalOffset})) = (${value});`,
    };
  }
  /**
   * Check if register is write-only based on access modifier.
   *
   * Write-only registers include:
   * - 'wo': Write-only
   * - 'w1s': Write-1-to-set
   * - 'w1c': Write-1-to-clear
   */
  static isWriteOnlyRegister(accessMod: string | undefined): boolean {
    return accessMod === "wo" || accessMod === "w1s" || accessMod === "w1c";
  }
 
  /**
   * Generate write-only bit range assignment statement.
   * Pattern: regName = ((value & mask) << start)
   */
  static generateWriteOnlyBitRange(
    regName: string,
    value: string,
    mask: string,
    start: string,
  ): string {
    return `${regName} = ((${value} & ${mask}) << ${start});`;
  }
 
  /**
   * Generate read-modify-write bit range assignment statement.
   * Pattern: regName = (regName & ~(mask << start)) | ((value & mask) << start)
   */
  static generateRmwBitRange(
    regName: string,
    value: string,
    mask: string,
    start: string,
  ): string {
    return `${regName} = (${regName} & ~(${mask} << ${start})) | ((${value} & ${mask}) << ${start});`;
  }
}
 
export default RegisterUtils;