This repository has been archived on 2026-04-18. You can view files and clone it, but cannot push or open issues or pull requests.
Virtual-Memory-Demo/Assets/Scripts/UI/SimulationConfigInputView.cs

233 lines
7.8 KiB
C#

using TMPro;
using UnityEngine;
using UnityEngine.UI;
using VMdemo.Core;
using System;
namespace VMdemo.UI
{
public class SimulationConfigInputView : MonoBehaviour
{
[Header("Fixed Core Spec")] [SerializeField]
private TMP_Text fixedCoreSpecText;
[SerializeField] private TMP_InputField accessCountInput;
[SerializeField] private TMP_InputField pageFaultPenaltyInput;
[SerializeField] private TMP_Dropdown addressModeDropdown;
[SerializeField] private TMP_InputField arrayLengthBytesInput;
[SerializeField] private TMP_InputField arrayElementBytesInput;
[SerializeField] private TMP_InputField arrayBaseAddressInput;
[SerializeField] private Button saveButton;
[SerializeField] private Button cancelButton;
[SerializeField] private GameObject panelRoot;
public event Action SaveClicked;
public event Action CancelClicked;
public bool IsPanelVisible => panelRoot != null ? panelRoot.activeInHierarchy : gameObject.activeInHierarchy;
private void Awake()
{
BindButtons();
ApplyFixedCoreSpecVisual();
}
public bool TryBuildConfig(out SimulationConfig config, out string errorMessage)
{
config = new SimulationConfig
{
machineBits = SimulationConfig.FixedMachineBits,
vaBits = SimulationConfig.FixedVaBits,
pageSizeKB = SimulationConfig.FixedPageSizeKB,
physicalMemoryMB = SimulationConfig.FixedPhysicalMemoryMB,
tlbEntries = SimulationConfig.FixedTlbEntries,
accessCount = ParseInt(accessCountInput, 100),
pageFaultPenalty = ParseInt(pageFaultPenaltyInput, 100),
addressGenerationMode = ReadAddressGenerationMode(),
arrayLengthBytes = ParseInt(arrayLengthBytesInput, 256),
arrayElementBytes = ParseInt(arrayElementBytesInput, 4),
arrayBaseAddress = ParseInt(arrayBaseAddressInput, 0)
};
config.ApplyFixedCoreSpec();
return ConfigValidator.TryValidate(config, out errorMessage);
}
public void PopulateFromConfig(SimulationConfig config)
{
if (config == null)
{
return;
}
SetInputText(accessCountInput, config.accessCount);
SetInputText(pageFaultPenaltyInput, config.pageFaultPenalty);
SetAddressGenerationMode(config.addressGenerationMode);
SetInputText(arrayLengthBytesInput, config.arrayLengthBytes);
SetInputText(arrayElementBytesInput, config.arrayElementBytes);
SetInputText(arrayBaseAddressInput, config.arrayBaseAddress);
ApplyFixedCoreSpecVisual();
}
public void SetPanelVisible(bool visible)
{
if (panelRoot != null)
{
panelRoot.SetActive(visible);
if (visible)
{
ApplyFixedCoreSpecVisual();
}
return;
}
gameObject.SetActive(visible);
if (visible)
{
ApplyFixedCoreSpecVisual();
}
}
private void BindButtons()
{
if (saveButton != null)
{
saveButton.onClick.RemoveAllListeners();
saveButton.onClick.AddListener(() => SaveClicked?.Invoke());
}
if (cancelButton != null)
{
cancelButton.onClick.RemoveAllListeners();
cancelButton.onClick.AddListener(() => CancelClicked?.Invoke());
}
}
private void ApplyFixedCoreSpecVisual()
{
if (fixedCoreSpecText != null)
{
fixedCoreSpecText.text =
$"{SimulationConfig.FixedMachineBits}位机\n" +
$"VA {SimulationConfig.FixedVaBits}位\n" +
$"页大小 {SimulationConfig.FixedPageSizeKB}KB\n" +
$"物理内存 {SimulationConfig.FixedPhysicalMemoryMB}MB\n" +
$"TLB {SimulationConfig.FixedTlbEntries}条全相联";
}
}
private static void SetInputText(TMP_InputField input, int value)
{
if (input != null)
{
input.text = value.ToString();
}
}
private static void SetInteractable(Selectable selectable, bool interactable)
{
if (selectable != null)
{
selectable.interactable = interactable;
}
}
private AddressGenerationMode ReadAddressGenerationMode()
{
if (addressModeDropdown == null || addressModeDropdown.options == null ||
addressModeDropdown.options.Count == 0)
{
return AddressGenerationMode.SequentialArrayLoop;
}
// Preferred convention:
// index 0 = RandomUniform, index 1 = SequentialArrayLoop.
if (addressModeDropdown.options.Count >= 2)
{
return addressModeDropdown.value == 0
? AddressGenerationMode.RandomUniform
: AddressGenerationMode.SequentialArrayLoop;
}
var option = addressModeDropdown.options[addressModeDropdown.value].text;
if (IsRandomOption(option))
{
return AddressGenerationMode.RandomUniform;
}
if (IsSequentialOption(option))
{
return AddressGenerationMode.SequentialArrayLoop;
}
return AddressGenerationMode.SequentialArrayLoop;
}
private void SetAddressGenerationMode(AddressGenerationMode mode)
{
if (addressModeDropdown == null || addressModeDropdown.options == null ||
addressModeDropdown.options.Count == 0)
{
return;
}
if (addressModeDropdown.options.Count >= 2)
{
addressModeDropdown.value = mode == AddressGenerationMode.RandomUniform ? 0 : 1;
addressModeDropdown.RefreshShownValue();
return;
}
for (var i = 0; i < addressModeDropdown.options.Count; i++)
{
var option = addressModeDropdown.options[i].text;
if ((mode == AddressGenerationMode.RandomUniform && IsRandomOption(option)) ||
(mode == AddressGenerationMode.SequentialArrayLoop && IsSequentialOption(option)))
{
addressModeDropdown.value = i;
addressModeDropdown.RefreshShownValue();
return;
}
}
}
private static bool IsRandomOption(string optionText)
{
if (string.IsNullOrEmpty(optionText))
{
return false;
}
return optionText.Contains("Random") ||
optionText.Contains("随机") ||
optionText.Contains("rand");
}
private static bool IsSequentialOption(string optionText)
{
if (string.IsNullOrEmpty(optionText))
{
return false;
}
return optionText.Contains("Sequential") ||
optionText.Contains("ArrayLoop") ||
optionText.Contains("数组") ||
optionText.Contains("顺序") ||
optionText.Contains("for");
}
private static int ParseInt(TMP_InputField input, int fallback)
{
if (input == null)
{
return fallback;
}
return int.TryParse(input.text, out var value) ? value : fallback;
}
}
}