kRISC - kOS with a RISC heart This is a fork of the kOS Autopilot v0.9.3 in which all the code execution is done in a RISC-like CPU. I started this project as a proof of concept to see if I could write a formal grammar for the KerboScript language and ended up rewriting most of kOS itself. The parts that remains mostly unchanged are the ones in the "outer shell" or that deal directly with KSP, for example the Bindings, SpecialValues, SteeringHelper, TermWindow, etc. Highlights The script code is parsed with a LL(1) parser using a formal grammar defined for the language The parsed code is then compiled into a stack-based program similar to a RPN calculator or the NET IL itself FAST (see the Benchmarks section) Parsing and compilation The grammar was written with TinyPG which automatically generates the needed classes for the parsing with no additional dependencies. There's no need to modify these classes by hand except for removing the "Compiled" flag of the RegExs that is not supported by mono. The resulting AST from the parser is then compiled into a series of simple opcodes that the CPU can execute efficiently. Differences for the user respect to Nivekk's kOS The grammar supports numbers in scientific notation The grammar supports negative numbers / expressions (no more 0-... ). The terminal window can be scrolled via PageUp/PageDown This version does NOT include an in-game editor Syntax errors highlighted with correct line number and position Internal architecture overview A Program is simply a list of opcodes A Trigger is a function that is called on every update (commands like WAIT UNTIL, ON, WHEN are implemented this way). A ProgramContext is a class that contains a Program and related values, like the instruction pointer and its triggers. A CodePart contains tree code sections: InitializationCode, FunctionsCode and MainCode The Compiler returns a CodePart object The ProgramBuilder builds a Program from one or more CodeParts assembling the different sections in the correct order. The CPU continues the execution of the current program in every update until it finds a wait or has executed the maximum configured number of opcodes per update The BoundVariables were modified so that they query the value to KSP only once per update. There is a class called SharedObjects which contains a reference to every major piece of the mod, so instead of passing a reference to a CPU, a Vessel, etc. you pass an instance of this class. This has the advantage that when a reference changes (like the Vessel on docking) you don't need to update every reference that exists to it. Most of the classes have been designed to tolerate the lack of other pieces of the mod, and that is why the CPU can work without a binding manager or a terminal window. Locks are implemented as a call to method pointer, so when you "lock" a variable you are only updating its method pointer. The ProgramFile class replaces the File class (didn't like the name collision with System.IO) and adds the possibility to save the files of the hard disk as a zip file encoded with Base64 for file sizes that are as low as 25% of the uncompressed file. Since mono doesn't provide an implementation of System.IO.Compression an external library (SharpZipLib) was necessary. This library is not needed if file compression is not enabled (by default is not). Configuration A new "Config" class was added that handles the mod configuration (through PluginConfiguration) and since its a SpecialValue is possible to make changes in the configuration directly from the terminal window. Executing "list config" shows a list of all the (three for now) configuration options. Benchmarks To measure if this version was really faster than the others I had to add some execution statistics to all versions (code below) The statistics show the total Update time (measured in CPU::Update) and the total Execution time (measured in CommandRunFile::Update) The time was measured using the System.Diagnostics.Stopwatch class and restricting the game to use only one core (this is VERY important, otherwise the times would be distorted) The number between brackets for kRISC is the configured maximum instructions per update. The methodology for the test was as follow: Copy the corresponding version of the plugin dll to the GameData\Plugins folder Start KSP and place the test rocket in the launchpad Switch to archive, run the launch program and wait until it ends (about 2:11 in-game time) Revert to launch and repeat Close KSP and repeat from point 1 for another version [table=width: 500] [tr] [td]kOS version[/td] [td]Run 1[/td] [td]Run 2[/td] [/tr] [tr] [td]Nivekk's kOS v0.9.3*[/td] [td]18.50s[/td] [td]17.70s[/td] [/tr] [tr] [td]Erendrake's kOS v0.11.0[/td] [td]19.70s[/td] [td]18.80s[/td] [/tr] [tr] [td]kRISC (40) [/td] [td]0.70s[/td] [td]0.50s[/td] [/tr] [tr] [td]kRISC (100)[/td] [td]1.03s[/td] [td]0.98s[/td] [/tr] [tr] [td]kRISC (200)[/td] [td]0.99s[/td] [td]1.13s[/td] [/tr] [/table] *Nivekk's kOS include the 0.23 fix and the until loop lag fix These times will be different for everyone but the relation should be constant. My computer is somewhat old so that explains why kOS lags so much, but even having a fast computer everyone can benefit from having a few extra CPU cycles Versions used in the tests (include the source with the statistics modification and the matching compiled dll) Nivekk's kOS 0.9.3: link Erendrake's kOS v0.11.0: link kRISC: link Repository https://github.com/marianoapp/kRISC To comply with the rules Name and version: kRISC v0.1 based off Nivekk's kOS 0.9.3 Authors: kRISC: Mariano (me) kOS: Nivekk and everyone who collaborated in the project [*]License: Inherits kOS' GNU GPL