233 lines
7.8 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|