While ALE was fun it was limited in that the assembly commands could only be executed in a sandboxed engine, so what if you wanted to use the assembly commands directly in your Xojo code with no engine in between, well that is what AssemblyCore is for. It currently has about 30 assembly commands implemented and I haven’t had time to document it but if you want to try it out it is available.
AssemblyCore is a set of Xojo wrappers to allow the use of assembly commands, the module is completely unlocked so you can see how it all works, it is actually insanely simple. I’d like to continue maintaining it so if you have a suggestion then pass it onto me for inclusion. It’s free to use but a small donation to help development would be appreciated but not required.
The assembly instructions can be used anywhere in your Xojo code, modifying your own variables or run on background threads or in anyway you desire. There are all the standard x86 registers and a stack should you want to pass parameters the assembly language way.
var a as Integer
mov 100, a
Of course there are some limitations as Xojo does not have the concept of labels or jump commands, but we can come pretty close.
var a, b as Integer
mov 100, a
mov 50, b
if je then yourMethod
What about Assembly language loops, without labels it seems impossible but it’s not that hard.
mov 100, ECX
You can even pass parameters in the assembly language way
var a as Integer
//Do something in your method
Have fun and let me know what you think. Just import the module into your app then away you go. The next step, other than continued improvements, is possibly calling direct OS functions, but we shall see.
I just uploaded a version with some basic documentation of the instructions. Currently only Integer parameters are supported on the instructions, registers and stack, as is generally the case with asm but I’ll look at creating overloaded methods to handle floating points if needed. I feel that if you need to do massive floating point modifications then you’d probably do that within your own code.
You may notice when you look at the instructions that they all have just a single line of code. Asm gets it speed from doing very simple things, but by chaining these simple instructions together you can do complex things.
I just uploaded version 1.1 with a few bug fixes and now with full floating point support on all methods where it was needed. This means that the registers and stack are now also floating point. I think this was really an oversight on my part, floating point is really needed.
Methods now support the following parameter combinations:
Integer to Integer
Integer to Double
Double to Double
Double to Integer
This seems to cover most requirements. I haven’t found any other situation yet, but I’ll add it when I do.
Here is a little example of using AssemblyCore in Xojo to convert a string to uppercase. I know Xojo has a method for doing this but this is a good get your head around assembly example. You’ll need to download version 1.2 for this. Version 1.2 auto updates register ESP with the stack size information.
Okay now using some labels which I didn’t know about… Thanks @Robert_Weaver
//Let do a uppercase string example
Var inString As String = "Hello world"
Var outString As String = ""
Var sPointer As Integer = 0
//Lets push all the items onto the stack for modification
For Each char As String In inString.Characters
//Lets store the size of the stack in ECX so we can loop through
//all the string characters
mov ESP, ECX
//Now we'll loop through all the character and convert them to uppercase
//Confirm characters are in the lower case range then convert to uppercase
cmp 97, stack(ecx)
If jl Then GoTo notLowerCase
cmp 122, stack(ecx)
If jg Then GoTo notLowerCase
//Upper Case the Character
r0 = stack(ecx)
sub_ 32, r0
stack(ecx) = r0
//Now we'll store the uppercase string
Len inString, ECX
outString = outString + Chr(stack(sPointer))
//Now lets erase all the information from the stack to
//Clean it up for the next task
Len inString, ECX
Xojo does in fact have a goto instruction and labels. I used this to advantage when I coded a PIC microcontroller emulator. Similar to what you have done, all of the PIC instruction codes were coded as Xojo methods. This allowed the writing of PIC assembly language code directly in the Xojo code editor and then running it. There’s a short description of the project, which I submitted in the summer 2018 Just Code Challenge. Here’s a link, and it has a link for downloading the project.
Here is example assembly code that makes use of Xojo’s goto instruction and labels:
'Volder's CORDIC rectangular to polar routine in PIC assembly language.
'It is assumed that inputs are 12 bit positive integers 0..4095.
'Hence the vector is in the first quadrant.
'The following XOJO housekeeping code sets up the various PIC registers.
dim xH,xL,yH,yL,angleH,angleL,index,count,tL,tH,vL,vH,kScale As UInt8
'dim deltaSum As Double
'Lookup table values with angles in degrees. Tables probably have more entries than necessary for 16 bit resolution
dim LU_AngleInt() As Integer = array(26,14,7,3,1,0,0,0,0,0,0,0,0,0)
dim LU_AngleFrac() As Integer = Array(144,9,32,147,202,229,114,57,28,14,7,4,2,1)
dim nTable As UInt8 = UBound(LU_AngleFrac)
'Initialize x and y variables
xH=x\256 'High byte of x coordinate
xL=x mod 256 'Low byte of x coordinate
yH=y\256 'High byte of y coordinate
yL=y mod 256 'Low byte of y coordinate
'Start of ASM code
'CORDIC ATAN2 function
'On entry, the 12 bit (0..4095) values of x and y should be in xL,xH,yL,yH
'The upper 4 bits of xH and yH must be Zero.
'On completion, the angle (in degrees) is in AngleH and AngleL
'The integer part is in AngleH, and the fractional part is in AngleL
'The radius (magnitude) is in yH,yL (integer), and xH (fraction).
'Check for all Zero input combinations
if noSkip then Return 999 'This is an error code indicating that both x an y are zero
'check if y=0
if noSkip then Return 0 'Angle is zero if y=0
'check for x=0
if noSkip then Return 90 'Angle is 90 degrees if x=0
' Scale up x and y to improve resolution
rlf xL,f 'shift xH and yH left
if noSkip then goto ScaleXY
'xH and yH are now normalized
'initialize calc loop
'calc x and y initial values
'save old x, as it will be overwritten
clrf index 'Loop counter and lookup table index
'shift x and y values
'calc x y shift
btfss yH,7 'check for negative y
if noSkip then goto ShiftLoop
if noSkip then goto ShiftLoop
'calc new xH and yH
if noSkip then goto NewXYcalc
' Sum Angle from lookup table
if noSkip then goto AddSum
'if result is Zero, then we are done
if noSkip then goto MainLoop
'The result of the preceding steps is to rotate the vector to the x axis. The rotated angle
'is the required polar angle, and the final x value is proportional to the required magnitude.
'The magnitude will be high by a factor of 1.6467743... which is the product of the cosine values
'in the lookup table. to get the true magnitude value we must scale it back by multiplying by
'1/1.6467743 or 0.607247753539552. Since we only need 16 bit precision, we can pick the simplest
'fixed shift and add routine that gives a sufficiently precise result. Multiplying by 17/28
'gives 0.6071428571 which is in error by 0.0172% which is probably good enough. However, we can
'improve the accuracy by truncating the summation after 4 terms and adding the final term twice.
'This gives a correction of 0.60725402832 for an error of 0.001%
'We use a repeating fraction multiply algorithm with parameters m=17, n=5, p=3 (for 17/28 factor)
'First multiply by m, then shift right n bits, then repeatedly shift right p bits and add to the
'n shifted value.
'start by multiplying by 17 (actually 17/4, in order to scale values to a safe range;
'the factor 4 will be removed later)
clc 'bcf status,c
if noSkip then goto MpyLoop1
movf tH,w 'copy back from t to x
'end of 17/4 scale
'repeating shift/add loop
clc 'bcf status,c
if noSkip then goto MpyLoop3
if noSkip then goto MpyLoop2
'Finally shift x into y regs
if noSkip then goto ScaleLoop
'End of asm code.
'The magnitude value is converted to a type double, and stored as a property.
'The angle is converted to a type double, and stored as a property.
angleCORDIC = angleL/256+angleH
return 1 'Error code Indicates valid result
This worked well in my situation, because these PIC processors have no conditional jump instructions, just conditional skips. So all I had to do for compatibility is have the skip instruction set or clear a flag bit, and then the following line that has the goto instruction is simply prefixed with “If noskip then”
Yeah, goto’s and labels are a tightly guarded secret, to prevent people from using them for anything except ancient legacy code compatibility.
Actually, they are in the Xojo docs. At least, they were there the last time I checked.
Yes, thanks so much, helps with ASM format so much. I found them in the documentation but they’re not obvious. I think I’ll still do my loops the same way as I like the indenting in the while statement, though I could always use a label and a conditional jump instruction instead.
I’ve started to add some of the extended x86 instructions into the module such as:
POPSC to pop a single string character off the stack and add it to the end of a string
PUSHS to push all the character values of a string onto the stack
PUSHSC to push a specified character value of a string onto the stack
All the conditional check instructions can now be pointed at a different register rather than just EAX as default, which was sorely needed. I’ve also added more floating point support to many methods which were lacking it.
I’ll upload a new version in a couple of days after some further testing, but here’s a little example of how much the changes and extra instructions have reduced the needed code. The following tiny example reverses the characters in a string. Loop_ always counts backward so we are grabbing the characters in the reverse order. Pop also always grabs and removes the last item which was added to the stack.
//Push all the characters of the string onto the stack for modification
//Now we'll store the reversed string,
Len inString, ECX
ALE with it’s highly optimised engine running compiled asm object code is certainly comparable to Xojo but it is completely sandboxed and not really available to intersperse with your Xojo code. AssemblyCore is a series of Xojo wrappers providing assembly syntax and will generally run at Xojo speed but will never out perform it. It can also be seamlessly interspersed with your Xojo code, which is something that others desired.
I could call external OS functions directly but again they would be no quicker as they have no context to each other so they wouldn’t perform like a compiled asm application, at best I suspect with the overhead of constantly calling external methods it would be slower then coding in Xojo directly. It might be a little dangerous as well.
I designed AssemblyCore because I enjoy coding in ASM but I also like to have a nice editor and a quick compile and runtime environment which Xojo provides, I have also used Xojo and its predecessors for many years so it’s comfortable. I guess the use case is that I can code in ASM and Xojo to get the result I desire and others may also do the same, based on the number of downloads, or they could use it purely as a tool to learn the concepts of assembly language or hopefully discover other ways of doing things.
I find it enjoyable and I hope others will as well. It’s always fun to learn new stuff, just not who the new Bond is going to be…