## 6 Experiments and Results  
### Experimental Setup, Tools, and Evolutionary Parameters  
All experiments for this work were conducted using a setup that integrates Icarus Verilog (a Verilog/SV simulator) with Grammatical Algorithms in Python for Evolution(GRAPE) [63], a Python-based implementation of GE. The solutions evolved in GRAPE and were evaluated for each generation using Icarus Verilog to calculate the fitness value. The experiments were performed on a Dell OptiPlex 5070 (sourced from Dell Technologies Customer Solution Center, Limerick, Ireland) desktop computer with a 1 TB HDD, 256 GB SSD, a single 16 GB RAM module, and a 64-bit quad-core 9 th-generation i7 processor with a 12 MB cache. The processor's standard operating frequency is 3.0 GHz, which can boost up to 4.7 GHz in turbo mode. The system uses the operating system Ubuntu 22.04.4 LTS. The hyperparameters used in this work are detailed in Table 1. All experiments initially used a population of 1000 and ran for 30 generations. However, these parameters were increased for some experiments, with results presented according to the respective population size and maximum number of generations in Table 2. The experimental setup is designed to run 12 runs in parallel on 12 threads of the processor. The grammar used in this study is shown in Figure 5. This work focuses on evolving the HDL code for a 6-state MSD, which is more complex than the previously evolved FSM for a 6-bit SD discussed in [44]. The increased complexity arises from the MSD's ability to track two sequences. We have evolved not only the system's next state and the values of two respective outputs--confirmation of payment and refund amount--but also the current state, input variables, and the values for input variables, which were not addressed in the previous work. This grammar facilitates the generation of the HDL module, which is simulated using Icarus Verilog. The first production rule connects the \(<parameters>\) to \(<sequential>\), where \(<parameters>\) defines hardcoded state parameters by assigning them 3-bit values. The \(<sequential>\) block contains the entire always block that implements the FSM. Within this always block, if the system is not undergoing a _reset_, the \(<states\_block>\) selects the appropriate _if-else if_ statement according to the system's current state (which is also evolved) and then enters \(<conditional>\). The \(<conditional>\) block further selects the respective _if-else if_ condition based on the evolved input variable and its evolved value, assigning the evolved next state and evolved outputs to the system. If the system is in a _reset_ state, \(<last\_else>\) is chosen within the always block, assigning hardcoded values to the next state and outputs, as specified in the grammar. The last three non-terminals only have terminals on the RHS, which are used throughout to evolve the current state, next state, input variable and its value, and the value of the outputs. In this work, the primary evaluation metric used during the evolutionary process is the fitness score. The fitness score measures how accurately an evolved individual solves the target FSM problem by comparing its outputs against the expected outputs for a predefined set of TCs. A total of 16 TCs divided into 64 3-bit vectors (as shown in Section 5) are used, where each case represents a specific input sequence and the corresponding expected output behaviour. For each 3-bit vector that the evolved individual resolves correctly, it is awarded a score of '1'. If the output for a vector does not match the expected behaviour, a score of '0' is assigned for that vector. The overall fitness score is computed by summing the individual scores across all 16 12-bit TCs or all 64 3-bit vectors. Therefore, the maximum achievable fitness score for an individual is '64', indicating perfect performance on all TCs. <final> ::= <parameters> <sequential> <parameters> ::= reg [2:0]state;  parameter SO = 3'b000; .