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

100% Statements 19/19
100% Branches 15/15
100% Functions 5/5
100% Lines 19/19

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 128 129                                                                    17x     17x     17x 17x                         12x     12x       12x           5x     7x   7x   7x 1x     6x 6x   6x   12x                           35x                         4x                         7x          
/**
 * 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";
 
/** 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 = CodeGenState.requireGenerator().generateExpression(
      subscripts[0],
    );
    const width = CodeGenState.requireGenerator().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 = CodeGenState.requireGenerator().tryEvaluateConstant(
      subscripts[0],
    );
    const widthConst = CodeGenState.requireGenerator().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;