diff --git a/lab2/src/main/scala/riscv/core/Execute.scala b/lab2/src/main/scala/riscv/core/Execute.scala index 702bb14..96ac0c8 100644 --- a/lab2/src/main/scala/riscv/core/Execute.scala +++ b/lab2/src/main/scala/riscv/core/Execute.scala @@ -72,7 +72,7 @@ class Execute extends Module { ) io.if_jump_address := io.immediate + Mux(opcode === Instructions.jalr, io.reg1_data, io.instruction_address) io.mem_alu_result := alu.io.result - // lab2(CLINTCSR) + //lab2(CLINTCSR) /* io.csr_reg_write_data := */ diff --git a/misc/autoans.py b/misc/autoans.py new file mode 100644 index 0000000..5f66224 --- /dev/null +++ b/misc/autoans.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python3 +""" +Code Auto-Filler Tool + +This tool reads a YAML configuration file containing code snippets and operations, +then applies them to target files. It supports two main operations: +1. Adding import statements at the beginning of files +2. Inserting code blocks after specific anchor comments +""" + +import yaml +import os +import sys +import argparse +from pathlib import Path +from typing import Dict, List, Optional + + +class CodeFiller: + def __init__(self, config_file: str, base_path: str = "."): + """ + Initialize the code filler. + + Args: + config_file: Path to the YAML configuration file + base_path: Base directory for resolving relative target file paths + """ + self.config_file = config_file + self.base_path = Path(base_path).resolve() + self.config = self._load_config() + + def _load_config(self) -> Dict: + """Load and parse the YAML configuration file.""" + try: + with open(self.config_file, 'r', encoding='utf-8') as f: + config = yaml.safe_load(f) + return config + except FileNotFoundError: + print(f"Error: Configuration file '{self.config_file}' not found.") + sys.exit(1) + except yaml.YAMLError as e: + print(f"Error parsing YAML file: {e}") + sys.exit(1) + + def _resolve_target_path(self, target_file: str) -> Path: + """Resolve the target file path relative to base path.""" + if os.path.isabs(target_file): + return Path(target_file) + return self.base_path / target_file + + def _backup_file(self, file_path: Path) -> None: + """Create a backup of the original file.""" + backup_path = file_path.with_suffix(file_path.suffix + '.backup') + if file_path.exists(): + with open(file_path, 'r', encoding='utf-8') as src: + with open(backup_path, 'w', encoding='utf-8') as dst: + dst.write(src.read()) + print(f" Backup created: {backup_path}") + + def _add_imports(self, lines: List[str], imports: List[str]) -> List[str]: + """ + Add import statements after the package declaration. + + Args: + lines: Original file lines + imports: List of import statements to add + + Returns: + Modified file lines with imports added + """ + # Find the insertion point (after package declaration) + insert_index = 0 + + # Find package declaration + for i, line in enumerate(lines): + stripped = line.strip() + if stripped.startswith('package '): + insert_index = i + 1 + break + + # Insert imports after package declaration + new_lines = lines[:insert_index] + + # Add the imports + for import_stmt in imports: + new_lines.append(import_stmt + '\n') + + # Add a blank line after imports if there are remaining lines + if insert_index < len(lines): + new_lines.append('\n') + + new_lines.extend(lines[insert_index:]) + + print(f" Added {len(imports)} import statement(s)") + + return new_lines + + def _insert_after_anchor(self, lines: List[str], anchor: str, code: str) -> List[str]: + """ + Insert code after a specific anchor comment. + + Args: + lines: Original file lines + anchor: The anchor comment to search for + code: The code block to insert + + Returns: + Modified file lines with code inserted + + Raises: + ValueError: If the anchor comment is not found in the file + """ + anchor_found = False + new_lines = [] + + for i, line in enumerate(lines): + new_lines.append(line) + + if anchor.strip() in line.strip(): + anchor_found = True + + # Extract indentation from the anchor line + anchor_indent = "" + for char in line: + if char in [' ', '\t']: + anchor_indent += char + else: + break + + # Add the code block after the anchor with proper indentation + code_lines = code.strip().split('\n') + for code_line in code_lines: + # Apply anchor indentation to non-empty lines + if code_line.strip(): + indented_line = anchor_indent + code_line + else: + indented_line = code_line # Keep empty lines as-is + new_lines.append(indented_line + '\n') + print(f" Inserted code after anchor: {anchor.strip()}") + + if not anchor_found: + raise ValueError(f"Anchor '{anchor.strip()}' not found in file") + + return new_lines + + def _process_file(self, target_file: str, operations: Dict) -> None: + """ + Process a single target file with the specified operations. + + Args: + target_file: Path to the target file + operations: Dictionary containing imports and anchors operations + """ + file_path = self._resolve_target_path(target_file) + print(f"Processing: {file_path}") + + # Check if file exists + if not file_path.exists(): + print(f" Warning: Target file does not exist, creating new file") + file_path.parent.mkdir(parents=True, exist_ok=True) + with open(file_path, 'w', encoding='utf-8') as f: + f.write('') + + # Create backup + self._backup_file(file_path) + + # Read the original file + with open(file_path, 'r', encoding='utf-8') as f: + lines = f.readlines() + + modified_lines = lines[:] + + # Process imports + if 'imports' in operations and operations['imports']: + modified_lines = self._add_imports(modified_lines, operations['imports']) + + # Process anchor insertions + if 'anchors' in operations and operations['anchors']: + for anchor, config in operations['anchors'].items(): + if 'code' in config: + try: + modified_lines = self._insert_after_anchor( + modified_lines, anchor, config['code'] + ) + except ValueError as e: + raise ValueError(f"Failed to process file '{target_file}': {e}") from e + + # Write the modified file + with open(file_path, 'w', encoding='utf-8') as f: + f.writelines(modified_lines) + + print(f" ✓ File processed successfully") + + def fill_codes(self, dry_run: bool = False) -> None: + """ + Execute the code filling process for all files in the configuration. + + Args: + dry_run: If True, only show what would be done without making changes + """ + if 'files' not in self.config: + print("Error: No 'files' section found in configuration") + return + + if dry_run: + print("DRY RUN MODE - No files will be modified\n") + + print(f"Base directory: {self.base_path}") + print(f"Configuration: {self.config_file}\n") + + for target_file, operations in self.config['files'].items(): + if dry_run: + print(f"Would process: {target_file}") + if 'imports' in operations: + print(f" Would add {len(operations['imports'])} import(s)") + if 'anchors' in operations: + print(f" Would process {len(operations['anchors'])} anchor(s)") + print() + else: + try: + self._process_file(target_file, operations) + print() + except ValueError as e: + print(f" ✗ {e}") + print(f"\nExecution stopped due to configuration error.") + sys.exit(1) + except Exception as e: + print(f" ✗ Unexpected error processing file: {e}") + print(f"\nExecution stopped due to unexpected error.") + sys.exit(1) + + if not dry_run: + print("Code filling completed!") + + +def main(): + parser = argparse.ArgumentParser( + description="Automatically fill code into target files based on YAML configuration" + ) + parser.add_argument( + 'config_file', + help='Path to the YAML configuration file' + ) + parser.add_argument( + '-b', '--base-path', + default='.', + help='Base directory for resolving target file paths (default: current directory)' + ) + parser.add_argument( + '-d', '--dry-run', + action='store_true', + help='Show what would be done without making any changes' + ) + parser.add_argument( + '-v', '--version', + action='version', + version='Code Auto-Filler 1.0.0' + ) + + args = parser.parse_args() + + # Create and run the code filler + filler = CodeFiller(args.config_file, args.base_path) + filler.fill_codes(dry_run=args.dry_run) + + +if __name__ == '__main__': + main() diff --git a/misc/example_codes.yaml b/misc/example_codes.yaml new file mode 100644 index 0000000..0902b48 --- /dev/null +++ b/misc/example_codes.yaml @@ -0,0 +1,43 @@ +# Example configuration file for code insertion +# Format: target_file -> operations + +files: + # Example target file 1 + "src/main/scala/MyModule.scala": + imports: + - "import chisel3.util._" + - "import chisel3.experimental._" + + anchors: + "// INSERT_REGISTERS_HERE": + code: | + val regA = RegInit(0.U(32.W)) + val regB = RegInit(0.U(32.W)) + val counter = RegInit(0.U(8.W)) + + "// INSERT_LOGIC_HERE": + code: | + when(io.enable) { + regA := io.dataIn + counter := counter + 1.U + }.otherwise { + regA := 0.U + } + + # Example target file 2 + "src/test/scala/MyModuleTest.scala": + imports: + - "import chiseltest._" + - "import org.scalatest.flatspec.AnyFlatSpec" + + anchors: + "// INSERT_TEST_CASE": + code: | + it should "handle basic operations" in { + test(new MyModule) { dut => + dut.io.enable.poke(true.B) + dut.io.dataIn.poke(42.U) + dut.clock.step() + dut.io.dataOut.expect(42.U) + } + } diff --git a/misc/requirements.txt b/misc/requirements.txt new file mode 100644 index 0000000..c1a201d --- /dev/null +++ b/misc/requirements.txt @@ -0,0 +1 @@ +PyYAML>=6.0