Actions

Difference between revisions of "Advanced IC10 Programming"

From Unofficial Stationeers Wiki

(Somewhat advanced tips for developing code for the IC10)
(Use proper/better category -> IC10)
 
(8 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 +
[[Category:IC10 Programming]]
 +
= VS code extension =
 +
'''For convenient operation, there is an extension for the visual studio code IDE''' [https://marketplace.visualstudio.com/items?itemName=Traineratwot.stationeers-ic10 Link]
 +
 +
Web version: https://ic10.dev/
 +
 +
and compiler [http://traineratwot.aytour.ru/wiki/icx ICX]
 +
 
= Flow Control And Data Manipulation =
 
= Flow Control And Data Manipulation =
''NOTE: This level of coding is NOT needed to play the to game to it's full extent. it's aimed at people looking for custom, self-inspired challenges.''
+
 
 +
''NOTE: This level of coding is NOT needed to play the game to it's full extent. it's aimed at people looking for custom, self-inspired challenges.''
 +
 
 +
== Devices By Register ==
 +
 
 +
<p>You can use a register to access the device based on pin number.</p>
 +
 
 +
<div style="background: #000000;>
 +
<p style="float: none; white-space: pre; line-height: 1; color: #FFFFFF; background: #000000; font-size: 110%;font-family: Consolas; margin-left: 10px;>
 +
<span style="color: #FF0000;">move</span> r0 0
 +
next:
 +
<span style="color: #FF0000;">s</span> dr0 Horizontal 0
 +
<span style="color: #FF0000;">s</span> dr0 Vertical 0
 +
<span style="color: #FF0000;">s</span> dr0 On 0
 +
<span style="color: #FF0000;">add</span> r0 r0 1
 +
<span style="color: #FF0000;">blt</span> r0 6 next
 +
 
 +
</p>
 +
</div>
  
 
== Functions ==
 
== Functions ==
[[File:Function.png|thumb|left]]<br><br><br><br><br><br><br><br>
+
 
 +
<div style="background: #000000;>
 +
<p style="float: none; white-space: pre; line-height: 1; color: #FFFFFF; background: #000000; font-size: 110%;font-family: Consolas; margin-left: 10px;><span>main:</span><span>
 +
</span><span style="color: #FF0000;">jal</span><span> </span><span>MyFunction</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>main</span><span>
 +
 
 +
</span><span>MyFunction:</span><span>
 +
</span><span>...</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>ra</span><span>
 +
 
 +
</span>
 +
</p>
 +
</div>
 
A function is just a label we jump to, but using the -al version of branch instructions (jal, beqzal) as they store the return address into the special '''ra''' register.
 
A function is just a label we jump to, but using the -al version of branch instructions (jal, beqzal) as they store the return address into the special '''ra''' register.
 
When calling a function from another function (or from itself), ra will be overwritten so we have to store it in the stack and take it out when the function completes:
 
When calling a function from another function (or from itself), ra will be overwritten so we have to store it in the stack and take it out when the function completes:
[[File:EmbeddedFunction.png|thumb|left]]<br><br><br><br><br><br><br><br><br><br><br><br>
+
 
If we hadn't used the stack, the jump at line 10 would take us to line 9 instead of 4.
+
<div style="background: #000000; float: none">
 +
<p style="float: none; white-space: pre; line-height: 1; color: #FFFFFF; background: #000000; font-size: 110%;font-family:Consolas; margin-left: 10px;><span>main:</span><span>
 +
</span><span style="color: #FF0000;">jal</span><span> </span><span>_MyFunction</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>main</span><span>
 +
 
 +
</span><span>_MyFunction:</span><span>
 +
</span><span style="color: #6666FF;">push</span><span> </span><span>ra</span><span>
 +
</span><span style="color: #FF0000;">jal</span><span> </span><span>_MySecondFunction</span><span>
 +
</span><span style="color: #6666FF;">pop</span><span> </span><span>ra</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>ra</span><span>
 +
 
 +
</span><span>_MySecondFunction:</span><span>
 +
</span><span>...</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>ra</span><span>
 +
 
 +
</span>
 +
</p>
 +
</div>
 +
If we hadn't used the stack, the jump at the end of _MyFunction would take us to the call of _MySecondFunction instead of the main section.
  
 
== Loops ==
 
== Loops ==
  
[[File:Loop.png|thumb|left]]<br><br><br><br><br><br><br><br><br><br>
+
<div style="background: #000000; float: none">
 +
<p style="float: none; white-space: pre; line-height: 1; color: #FFFFFF; background: #000000; font-size: 110%;font-family:Consolas; margin-left: 10px;><span style="color: #00FFFF;">alias</span><span> </span><span>rIterator</span><span> </span><span>r0</span><span>
 +
</span><span>main:</span><span>
 +
</span><span style="color: #6666FF;">move</span><span> </span><span>rIterator</span><span> </span><span>0</span><span>
 +
</span><span>Loop:</span><span>
 +
</span><span>...</span><span>
 +
</span><span style="color: #6666FF;">add</span><span> </span><span>rIterator</span><span> </span><span>rIterator</span><span> </span><span>1</span><span>
 +
</span><span style="color: #FF0000;">bgt</span><span> </span><span>rIterator</span><span> </span><span>3</span><span> </span><span>Loop_End</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Loop</span><span>
 +
</span><span>Loop_End:</span><span>
 +
 
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>main</span><span>
 +
 
 +
</span>
 +
</p>
 +
</div>
 
The challenge with loops is to keep them clean. Relative jumps are a great way to save lines but they can quickly turn code messy and adding lines might break them if you overlook them. If code length is not an issue, stick to labels where possible.
 
The challenge with loops is to keep them clean. Relative jumps are a great way to save lines but they can quickly turn code messy and adding lines might break them if you overlook them. If code length is not an issue, stick to labels where possible.
  
 
== Indexing With Relative Jump ==
 
== Indexing With Relative Jump ==
  
[[File:Selector.png|thumb|left]]<br><br><br><br><br><br><br><br><br><br><br><br><br><br>
+
<div style="background: #000000; float: none">
 +
<p style="float: none; white-space: pre; line-height: 1; color: #FFFFFF; background: #000000; font-size: 110%;font-family:Consolas; margin-left: 10px;><span style="color: #00FFFF;">alias</span><span> </span><span>rIndex</span><span> </span><span>r0</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>rTemp</span><span> </span><span>r1</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>rValue</span><span> </span><span>r2</span><span>
 +
 
 +
</span><span>main:</span><span>
 +
</span><span style="color: #6666FF;">move</span><span> </span><span>rIndex</span><span> </span><span>1</span><span>
 +
</span><span style="color: #6666FF;">mul</span><span> </span><span>rTemp</span><span> </span><span>rIndex</span><span> </span><span>2</span><span>
 +
</span><span style="color: #6666FF;">add</span><span> </span><span>rTemp</span><span> </span><span>rTemp</span><span> </span><span>1</span><span>
 +
</span><span style="color: #FF0000;">jr</span><span> </span><span>rTemp</span><span>
 +
</span><span style="color: #6666FF;">move</span><span> </span><span>rValue</span><span> </span><span>123</span><span> </span><span style="color: #FF8000;">#Index 0
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Select_end</span><span>
 +
</span><span style="color: #6666FF;">move</span><span> </span><span>rValue</span><span> </span><span>456</span><span> </span><span style="color: #FF8000;">#Index 1
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Select_end</span><span>
 +
</span><span style="color: #6666FF;">move</span><span> </span><span>rValue</span><span> </span><span>789</span><span> </span><span style="color: #FF8000;">#Index 2
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Select_end</span><span>
 +
</span><span>...</span><span>
 +
</span><span>Select_end:</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>main</span><span>
 +
 
 +
</span>
 +
</p>
 +
</div>
 
Use this to set one or more parameters or call functions using an index number you calculated (or read from a dial button). We multiply it by 2 because we need space for a jump after each move command so we don't run the subsequent ones and we add 1 because for a 0 index "jr 0" would lock up our IC.
 
Use this to set one or more parameters or call functions using an index number you calculated (or read from a dial button). We multiply it by 2 because we need space for a jump after each move command so we don't run the subsequent ones and we add 1 because for a 0 index "jr 0" would lock up our IC.
  
Line 23: Line 116:
 
Say you have a complex function that manipulates a device (reads/writes multiple parameters, controls timing etc) and you want to reuse it for multiple devices. You could copy paste the whole function, or you could redefine the alias you used and point it to another device, like this:
 
Say you have a complex function that manipulates a device (reads/writes multiple parameters, controls timing etc) and you want to reuse it for multiple devices. You could copy paste the whole function, or you could redefine the alias you used and point it to another device, like this:
  
[[File:Aliases.png|thumb|left]]<br><br><br><br><br><br>
+
<div style="background: #000000; float: none">
 +
<p style="float: none; white-space: pre; line-height: 1; color: #FFFFFF; background: #000000; font-size: 110%;font-family:Consolas; margin-left: 10px;><span>main:</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>dCurrent</span><span> </span><span>d0</span><span>
 +
</span><span style="color: #FF0000;">jal</span><span> </span><span>_MyFunction</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>dCurrent</span><span> </span><span>d1</span><span>
 +
</span><span style="color: #FF0000;">jal</span><span> </span><span>_MyFunction</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>main</span><span>
 +
 
 +
</span>
 +
</p>
 +
</div>
 
''NOTE: This wouldn't work in real languages since aliases and defines are just directives for the (pre)compiler, they're not evaluated during runtime by the CPU''
 
''NOTE: This wouldn't work in real languages since aliases and defines are just directives for the (pre)compiler, they're not evaluated during runtime by the CPU''
  
 
You can combine this with a loop and indexing to run your function on multiple devices automatically.
 
You can combine this with a loop and indexing to run your function on multiple devices automatically.
[[File:LoopingAlias.png|thumb|left]]<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
+
<div style="background: #000000; float: none">
 +
<p style="float: none; white-space: pre; line-height: 1; color: #FFFFFF; background: #000000; font-size: 110%;font-family:Consolas; margin-left: 10px;><span style="color: #00FFFF;">alias</span><span> </span><span>rIterator</span><span> </span><span>r0</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>rTemp</span><span> </span><span>r1</span><span>
 +
</span><span>main:</span><span>
 +
</span><span style="color: #6666FF;">move</span><span> </span><span>rIterator</span><span> </span><span>0</span><span>
 +
</span><span>Loop:</span><span>
 +
</span><span style="color: #FF0000;">jal</span><span> </span><span>_UpdateReference</span><span>
 +
</span><span style="color: #FF0000;">jal</span><span> </span><span>_FunctionForDevice</span><span>
 +
</span><span style="color: #6666FF;">add</span><span> </span><span>rIterator</span><span> </span><span>rIterator</span><span> </span><span>1</span><span>
 +
</span><span style="color: #FF0000;">bgt</span><span> </span><span>rIterator</span><span> </span><span>3</span><span> </span><span>Loop_End</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Loop</span><span>
 +
</span><span>Loop_End:</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>main</span><span>
 +
 
 +
</span><span>_UpdateReference:</span><span>
 +
</span><span style="color: #6666FF;">mul</span><span> </span><span>rTemp</span><span> </span><span>rIterator</span><span> </span><span>2</span><span>
 +
</span><span style="color: #6666FF;">add</span><span> </span><span>rTemp</span><span> </span><span>rTemp</span><span> </span><span>1</span><span>
 +
</span><span style="color: #FF0000;">jr</span><span> </span><span>rTemp</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>dCurrentDevice</span><span> </span><span>d0</span><span> </span><span style="color: #FF8000;">#Index 0
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Select_end</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>dCurrentDevice</span><span> </span><span>d1</span><span> </span><span style="color: #FF8000;">#Index 1
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Select_end</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>dCurrentDevice</span><span> </span><span>d2</span><span> </span><span style="color: #FF8000;">#Index 2
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Select_end</span><span>
 +
</span><span style="color: #00FFFF;">alias</span><span> </span><span>dCurrentDevice</span><span> </span><span>d3</span><span> </span><span style="color: #FF8000;">#Index 3
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>Select_end</span><span>
 +
</span><span>Select_end:</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>ra</span><span>
 +
 
 +
</span><span>_FunctionForDevice:</span><span>
 +
</span><span style="color: #FF8000;">#Manipulate dCurrentDevice
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>ra</span><span>
 +
 
 +
</span>
 +
</p>
 +
</div>
  
 
= Device Manipulation =
 
= Device Manipulation =
Line 34: Line 172:
  
 
Some devices don't react well to having parameters changed while they're performing an action such as import or export. Notable mentions are the stacker, sorter and the vending machine. You can avoid them locking up (or getting jammed with items) either by adding delays (yield, sleep) or by actively waiting for their slots to become unoccupied, or their Activation to become 0.
 
Some devices don't react well to having parameters changed while they're performing an action such as import or export. Notable mentions are the stacker, sorter and the vending machine. You can avoid them locking up (or getting jammed with items) either by adding delays (yield, sleep) or by actively waiting for their slots to become unoccupied, or their Activation to become 0.
[[File:Busy.png|thumb|left]]<br><br><br><br><br><br>
+
<div style="background: #000000; float: none">
 +
<p style="float: none; white-space: pre; line-height: 1; color: #FFFFFF; background: #000000; font-size: 110%;font-family:Consolas; margin-left: 10px;><span>WaitForDevices:</span><span>
 +
</span><span>yield</span><span>
 +
</span><span style="color: #00FFFF;">ls</span><span> </span><span>rBusy</span><span> </span><span>dSorter</span><span> </span><span>0</span><span> </span><span>Occupied</span><span>
 +
</span><span style="color: #FF0000;">bgtz</span><span> </span><span>rBusy</span><span> </span><span>WaitForDevices</span><span>
 +
</span><span style="color: #00FFFF;">ls</span><span> </span><span>rBusy</span><span> </span><span>dSorter</span><span> </span><span>1</span><span> </span><span>Occupied</span><span>
 +
</span><span style="color: #FF0000;">bgtz</span><span> </span><span>rBusy</span><span> </span><span>WaitForDevices</span><span>
 +
</span><span style="color: #00FFFF;">ls</span><span> </span><span>rBusy</span><span> </span><span>dSorter</span><span> </span><span>2</span><span> </span><span>Occupied</span><span>
 +
</span><span style="color: #FF0000;">bgtz</span><span> </span><span>rBusy</span><span> </span><span>WaitForDevices</span><span>
 +
</span><span style="color: #00FFFF;">ls</span><span> </span><span>rBusy</span><span> </span><span>dVender</span><span> </span><span>0</span><span> </span><span>Occupied</span><span>
 +
</span><span style="color: #FF0000;">bgtz</span><span> </span><span>rBusy</span><span> </span><span>WaitForDevices</span><span>
 +
</span><span style="color: #00FFFF;">ls</span><span> </span><span>rBusy</span><span> </span><span>dVender</span><span> </span><span>1</span><span> </span><span>Occupied</span><span>
 +
</span><span style="color: #FF0000;">bgtz</span><span> </span><span>rBusy</span><span> </span><span>WaitForDevices</span><span>
 +
</span><span style="color: #FF0000;">j</span><span> </span><span>ra</span><span>
 +
</span>
 +
</p>
 +
</div>
 +
 
 
'''NOTE:''' The slot reader labels slots from 1 but in the IC they start at 0. It is also a good idea to check any device involved in your solution with both a logical and slot reader as the current databases may not list all existing slots or parameters. You should always make use of all data available from devices as they may greatly simplify your project.
 
'''NOTE:''' The slot reader labels slots from 1 but in the IC they start at 0. It is also a good idea to check any device involved in your solution with both a logical and slot reader as the current databases may not list all existing slots or parameters. You should always make use of all data available from devices as they may greatly simplify your project.
  
 
Using delays is convenient, but has downsides. You're giving up real-time control over the process and may miss certain events or react too late and cause a device to jam. You also need to consider that code takes time to run, and for example if you have a complicated condition for setting the output of a sorter depending on the item that entered it, it may be better to leave it OFF by default and only turn it on once the output is correctly set. (Devices react differently to being fed items while powered down. ie the stacker will keep it in the Import slot but the vending machine will completely import it, so make sure to manually test everything you can prior to automating it)
 
Using delays is convenient, but has downsides. You're giving up real-time control over the process and may miss certain events or react too late and cause a device to jam. You also need to consider that code takes time to run, and for example if you have a complicated condition for setting the output of a sorter depending on the item that entered it, it may be better to leave it OFF by default and only turn it on once the output is correctly set. (Devices react differently to being fed items while powered down. ie the stacker will keep it in the Import slot but the vending machine will completely import it, so make sure to manually test everything you can prior to automating it)
 +
= Sample Projects =
 +
 +
== Vending Machine Exporter ==
 +
 +
[[Vending_Machine_Export_IC10]]

Latest revision as of 12:06, 23 May 2024

VS code extension[edit]

For convenient operation, there is an extension for the visual studio code IDE Link

Web version: https://ic10.dev/

and compiler ICX

Flow Control And Data Manipulation[edit]

NOTE: This level of coding is NOT needed to play the game to it's full extent. it's aimed at people looking for custom, self-inspired challenges.

Devices By Register[edit]

You can use a register to access the device based on pin number.

move r0 0 next: s dr0 Horizontal 0 s dr0 Vertical 0 s dr0 On 0 add r0 r0 1 blt r0 6 next

Functions[edit]

main: jal MyFunction j main MyFunction: ... j ra

A function is just a label we jump to, but using the -al version of branch instructions (jal, beqzal) as they store the return address into the special ra register. When calling a function from another function (or from itself), ra will be overwritten so we have to store it in the stack and take it out when the function completes:

main: jal _MyFunction j main _MyFunction: push ra jal _MySecondFunction pop ra j ra _MySecondFunction: ... j ra

If we hadn't used the stack, the jump at the end of _MyFunction would take us to the call of _MySecondFunction instead of the main section.

Loops[edit]

alias rIterator r0 main: move rIterator 0 Loop: ... add rIterator rIterator 1 bgt rIterator 3 Loop_End j Loop Loop_End: j main

The challenge with loops is to keep them clean. Relative jumps are a great way to save lines but they can quickly turn code messy and adding lines might break them if you overlook them. If code length is not an issue, stick to labels where possible.

Indexing With Relative Jump[edit]

alias rIndex r0 alias rTemp r1 alias rValue r2 main: move rIndex 1 mul rTemp rIndex 2 add rTemp rTemp 1 jr rTemp move rValue 123 #Index 0 j Select_end move rValue 456 #Index 1 j Select_end move rValue 789 #Index 2 j Select_end ... Select_end: j main

Use this to set one or more parameters or call functions using an index number you calculated (or read from a dial button). We multiply it by 2 because we need space for a jump after each move command so we don't run the subsequent ones and we add 1 because for a 0 index "jr 0" would lock up our IC.

Redefining Aliases[edit]

Say you have a complex function that manipulates a device (reads/writes multiple parameters, controls timing etc) and you want to reuse it for multiple devices. You could copy paste the whole function, or you could redefine the alias you used and point it to another device, like this:

main: alias dCurrent d0 jal _MyFunction alias dCurrent d1 jal _MyFunction j main

NOTE: This wouldn't work in real languages since aliases and defines are just directives for the (pre)compiler, they're not evaluated during runtime by the CPU

You can combine this with a loop and indexing to run your function on multiple devices automatically.

alias rIterator r0 alias rTemp r1 main: move rIterator 0 Loop: jal _UpdateReference jal _FunctionForDevice add rIterator rIterator 1 bgt rIterator 3 Loop_End j Loop Loop_End: j main _UpdateReference: mul rTemp rIterator 2 add rTemp rTemp 1 jr rTemp alias dCurrentDevice d0 #Index 0 j Select_end alias dCurrentDevice d1 #Index 1 j Select_end alias dCurrentDevice d2 #Index 2 j Select_end alias dCurrentDevice d3 #Index 3 j Select_end Select_end: j ra _FunctionForDevice: #Manipulate dCurrentDevice j ra

Device Manipulation[edit]

Timing And Parameters[edit]

Some devices don't react well to having parameters changed while they're performing an action such as import or export. Notable mentions are the stacker, sorter and the vending machine. You can avoid them locking up (or getting jammed with items) either by adding delays (yield, sleep) or by actively waiting for their slots to become unoccupied, or their Activation to become 0.

WaitForDevices: yield ls rBusy dSorter 0 Occupied bgtz rBusy WaitForDevices ls rBusy dSorter 1 Occupied bgtz rBusy WaitForDevices ls rBusy dSorter 2 Occupied bgtz rBusy WaitForDevices ls rBusy dVender 0 Occupied bgtz rBusy WaitForDevices ls rBusy dVender 1 Occupied bgtz rBusy WaitForDevices j ra

NOTE: The slot reader labels slots from 1 but in the IC they start at 0. It is also a good idea to check any device involved in your solution with both a logical and slot reader as the current databases may not list all existing slots or parameters. You should always make use of all data available from devices as they may greatly simplify your project.

Using delays is convenient, but has downsides. You're giving up real-time control over the process and may miss certain events or react too late and cause a device to jam. You also need to consider that code takes time to run, and for example if you have a complicated condition for setting the output of a sorter depending on the item that entered it, it may be better to leave it OFF by default and only turn it on once the output is correctly set. (Devices react differently to being fed items while powered down. ie the stacker will keep it in the Import slot but the vending machine will completely import it, so make sure to manually test everything you can prior to automating it)

Sample Projects[edit]

Vending Machine Exporter[edit]

Vending_Machine_Export_IC10