ANY Definition v0.0.2 by Mark Ormston Created: December 23rd, 2006 Last Modified: April 9th, 2007 *************************************************************************************************** TABLE OF CONTENTS 1 What is ANY? 2 Goals of ANY 2.1 Hardware Independence 2.2 ANY Means Any Programming Language 2.3 It's Free! 2.4 Easy to Use 2.5 Open Source A1 An Example of AnyASM at Work A1.1 AnyASM Result A1.2 16bit x86 Assembly Version A1.3 32bit x86 Assembly Version A1.4 68000 (MC68K) Assembly Version *************************************************************************************************** 1 What is ANY? ANY is a new programming infrastructure aimed to permit programmers to write software that may immediately run on as much hardware as possible. A psuedo-assembly language known as AnyAssembly (or AnyASM for short) is used to permit software to be ported to other systems. To support this functionality, most of the ANY platform itself will have to be designed for specific processors, hardware and operating systems so that AnyASM code doesn't have to. The final result is attained through various sets of programs: final assemblers, libraries, cross assemblers, end-user interfaces and AnyASM assemblers. "Final Assemblers" are programs that are processor specific. These programs will convert AnyASM programs to their native processor's byte code so that only fully compiled source is ever run on a system. These programs will be also provide an interface between the AnyASM source and the libraries to support the platform on which they lie. "Libraries" are essentially a set of functions and data designed to give a transparent layer between the AnyASM source and the hardware of the computer it is being executed on. The importance of optimization in these files cannot be stressed enough! They can either make or break implementation of ANY on the hardware they are designed for. "Cross Assemblers" are a special version of Final Assembler that are designed to assembly AnyASM files to the native processor byte code of a system they are not run on. This is particularly useful to release binaries of software on systems where the full ANY platform may be too bulky or impossible to implement, such as cell-phones, game consoles, dedicated systems, etc. "End-User Interfaces" are a means to give easy access to end-users to the benefits of ANY. Essentially, it should be a layer between the AnyASM source they receive and the Final Assembler and Libraries of their hardware. "AnyASM Assemblers" are a set of programs designed to convert high level (or maybe even low level?) programs into AnyASM. Their purpose and existance are to allow programmers to use any language they wish to program their software by converting everything to the hardware-independent AnyASM language. It is the author's wish that many AnyASM Assemblers will become available by third parties to support their favorite brand of programming. An example of a AnyASM Assembler would be to convert MSDOS-based ANSI C programs into AnyASM, thereby permitting those programs to be run anywhere ANY is available. Unlike the other sets of programs, AnyASM Assemblers may actually be programmed in ANY itself and run on almost any system that ANY supports since, in reality, they're just changing text files to more text files! To help explain things in a completely different perspective, lets take a simple example: We decide to make a Solitaire card game and write it in ANSI C. The process of programming the game would be: 1) Create the graphics for the game (the cards). 2) Design how the interface and game will function. 3) Program the game using ANSI C. 4) Test and compile the game using an AnyASM Assembler to convert the ANSI C code to AnyASM, then running that AnyASM through a Final Assembler. A programming interface will be provided to permit command line passing of data to the assemblers, making this step significantly easier than it sounds (more on this later). Also, there will be support for separate files to be fully compiled so that unnecessary recompiling is avoided. [THIS STEP IS IN STILL IN THE WORKS AND IS IN NEED OF FUTURE ATTENTION] 5) When the game is fully tested and complete, create a single AnyASM file for the entire program. 6) This final AnyASM file, along with any data files (graphics, high score lists, etc.) will be given or sold to end-users. At this point, a user "runs" the program by say, double-clicking with their mouse on the .Any file. This will cause the End-User Interface to popup, telling the user the requirements of the program (minimum to display the graphics and a mouse are required) and possibly any settings, if desired. Then, the Final Assembler for their computer will convert the .Any file to a local-system executable file (such as an ELF binary in Linux or an EXE file in Windows) that uses their system's Libraries. After the .Any file has been assembled, the new binary is executed every subsequent time the .Any file is executed unless the system detects that it has been changed so that recompiling is never needlessly necessary. *************************************************************************************************** 2 Goals of ANY ANY is designed, from the ground up, to do the following (not necessarily in order of priority): 1) Allow programming to be done with complete hardware, processor and device independence, as much as possible. 2) Replace traditional style programming that is typically done for specific hardware, processors, or operating systems. 3) Create an infrastructure that (hopefully) any programming language can be converted to. 4) Provide tools for programmers to extend it's programming language support, as well as promoting contributions to the base system. 5) Be free for everybody. 6) Be so easy to use that everybody will want it. 7) Be a user-driven product. ___________________________________________________________________________________________________ 2.1 Hardware Independence 1) Allow programming to be done with complete hardware, processor and device independence, as much as possible. 2) Replace traditional style programming that is typically done for specific hardware, processors or operating systems. The sounds like a daunting task. After all, no one programming language has ever been able to truly do this task. However, some such as Java have come close. Unlike Java, ANY works off of compiled code. Hardware-specific Final Assemblers make this possible, by converting the AnyASM source files to native code. Hardware-specific Libraries are designed to streamline interaction between the software and the hardware. To attain these goals, each ANY program will have a list of system requirements. For example, a Solitaire card game may require graphics support for 16 or more colors at 640x480 or higher resolution and a mouse. A text-editing program, on the other hand, would only require text-mode support (??? I don't really know if this can't be done or emulated on any system... even TI calculators could work though, theoretically...) and a keyboard (or possibly even a keyboard emulation for, say, game systems). Granted, higher-end software with more steep requirements will not run on lower-end hardware, but this will be a hardware limitation and hopefully not a limitation in the ANY implementation. ___________________________________________________________________________________________________ 2.2 ANY Means Any Programming Language 3) Create an infrastructure that (hopefully) any programming language can be converted to. 4) Provide tools for programmers to extend it's programming language support, as well as promoting contributions to the base system. The AnyASM language is devised to be a go-between between virtually any programming language and the final product (binary code on a end-user system). A common pool of library and function calls exist to permit ties between the ANY interface and whatever the originating programming language used. Of course there will be limitations, but those hurdles may hopefully be circumvented when they are reached. The goal of ANY is far beyond the capabilities of only one programmer. The hope is that, with easy to use API support, other developers will contribute AnyASM Assemblers to convert their favorite (or most used if they hate it and are forced to use it like me and Visual Basic) to AnyASM. See the example in A1 which shows how a QuickBASIC for DOS program might be translated to AnyASM and then subsequentally to 16bit x86, 32bit x86 and MC68K assembly. ___________________________________________________________________________________________________ 2.3 It's Free! 5) Be free for everybody. Why restrict who can use something that is potentially this important? ANY is an open source software platform. This means that it is free for anybody. Please see the full license for details. ___________________________________________________________________________________________________ 2.4 Easy to Use 6) Be so easy to use that everybody will want it. This of course relates to the End-User Interface. We want everybody to be able to reap the benefits of ANY, so an easy to use system has been developed to install and run ANY software. Developers would provide users with a link to either the .Any file (in the case of operating systems that can tie to a file extension and would load the AnyScript End-User Interface) or to a command line batch-style link that would cause the ANY End-User Interface to tie to the .Any file. The End-User Interface would then handle compilation only as necessary and will provide a transparent layer between the .Any file and the actual source. ___________________________________________________________________________________________________ 2.5 Open Source 7) Be a user-driven product. ANY is an open source software platform. This means that it is free for anybody to obtain the source code. Please see the full license for details. *************************************************************************************************** A1 An Example of ANY at Work If we wrote a simple program in Microsoft QuickBASIC for DOS that draws some lines in 320x200 256 color mode, waits for a keypress, then exits, we may have source that looks like: BEGIN CODE ======================================================================================== DEFINT A-Z ' Variables are integers unless otherwise specified SCREEN 13 ' Switch to 320x200 256 color mode FOR q = 0 TO 199 ' | LINE (0, q) - (319, 199 - q), q ' +-> Draw lines NEXT ' | c$ = INPUT$(1) ' Wait for a keypress SYSTEM ' Exit to the system END CODE ========================================================================================== While our example below won't change the palette to match the (IMHO, very ugly) default colors in QuickBASIC, this will show you how the process works. ___________________________________________________________________________________________________ A1.1 AnyASM Result The resulting program, when sent to AnyASM, may look like: BEGIN CODE ======================================================================================== Region Code // Use the predefined @@Init function to setup QBScreen as our global screen object Function @@Init() Format Fast, Returns Nothing; // Get the primary screen object as QBScreen Call @@QBScreen.GetPrimaryScreen(); // Set the screen to an 8bit color text mode of at least 80x25 resolution Call @@QBScreen.SetScreenMode(80, 25, 8, 0x01); EndFunction; // Execution begins here Function Main() Format Fast, Returns Nothing; VarLocal S16 @q; // Create q, a signed 16bit integer value VarLocal String @c; // Create c, a string object //= SCREEN 13 // Set the screen to a graphics mode of at least 320x200 pixels 8bits per pixel Call @@QBScreen.SetScreenMode(320, 200, 8); //= FOR q = 0 TO 199 Move @q, 0; // Set q = 0 (first part of the FOR) @@Label_Main_0: // Label for the FOR Compare @q, 199; // Compare q to 199 JumpIf Greater, @@Label_Main_1; // Signed test for q <= 199 to loop //= LINE (0, q) - (319, 199 - q), q RegisterLocal ProcInt RegA; Move RegA, 199; Subtract RegA, @q; // Set our temporary register to 199 - q Call @@QBScreen.DrawLine(0, @q, 319, RegA, @q); // Draw the line ClearRegisters RegA; // Let the assembler know that we no longer need RegA //= NEXT Inc @q; // Increment q Jump @@Label_Main_0; @@Label_Main_1: //= c$ = INPUT$(1) Call Base.GetKey(), @c; // Read in a key //= SYSTEM EndFunction; Region EmptyData // Create our global screen object Var ScreenObject @@QBScreen; END CODE ========================================================================================== ___________________________________________________________________________________________________ A1.2 16bit x86 Assembly Version When assembled to 16bit x86 assembly, the end result would look something like (this is VERY MUCH simplified): NOTE: You do not see a single system-specific function call in the assembly! This is all handled by the library files that this will be linked to. The handling of the display, the key input, memory allocation, etc. is system specific and showing their implementation here would be completely useless. This is only designed to show how the assembly might be generated from the AnyASM listed above. This could be running in MS-DOS, 16bit Windows, 16bit x86 Linux or any other computer that uses 16bit x86 executables and supports 320x200 or higher with 256 or more colors. This is using yasm/nasm assembly syntax. BEGIN CODE ======================================================================================== BITS 16 ; Include the external function links and parameters for AnyASM %INCLUDE "anyasm.inc" ; For the string object %INCLUDE "objects/string.inc" ; For the screen object %INCLUDE "objects/screen.inc" ;= Region Code SECTION .text ;= Function @@Init() Format Fast, Returns Nothing; ??Init: push es ; This is added automatically by the assembler to initialize our global objects ; Create the screen object push ds push ??QBScreen call ScreenObject_New add sp, 4 ;= Call @@QBScreen.GetPrimaryScreen(); mov di, word ptr [??QBScreen] push word ptr [??QBScreen + 2] pop es call far es:(di + SCREENOBJECT_M_GETPRIMARYSCREEN) ;= Call @@QBScreen.SetScreenMode(80, 25, 8, 0x01); push 1 push 8 push 25 push 80 call far es:(di + SCREENOBJECT_M_SETSCREENMODE) add sp, 8 ;= EndFunction; ; Restore ES pop es retf .ENDFUNC ??DeInit: ; This is added automatically by the assembler to deinitialize global objects push es mov di, word ptr [??QBScreen] push word ptr [??QBScreen + 2] pop es call far es:(di + SCREENOBJECT_M_DELETE) pop es retf .ENDFUNC ;= Function Main() Format Fast, Returns Nothing; ?Main: ;= VarLocal S16 @q; %define ?LOCAL_VARMOD0 2 ;= VarLocal String @c; %define ?LOCAL_VARMOD1 6 ; Local variable setup %define ?LOCAL_VAR_SIZE 6 push bp mov bp, sp sub sp, ?LOCAL_VAR_SIZE ; Allocate the string object lea ax, [bp - ?LOCAL_VARMOD1] push ds push ax call StringObject_New add sp, 4 ;= Call @@QBScreen.SetScreenMode(320, 200, 8); push es mov di, word ptr [??QBScreen] push word ptr[??QBScreen + 2] pop es push 0 push 8 push 200 push 320 call far es:(di + SCREENOBJECT_M_SETSCREENMODE) add sp, 8 pop es ;= Move @q, 0; mov word ptr [bp - ?LOCAL_VARMOD0], 0 ;= @@Label_Main_0: .l0: ;= Compare @q, 199; cmp word ptr [bp - ?LOCAL_VARMOD0], 199 ;= JumpIf Greater, @@Label_Main_1; jg > .l1 ;= RegisterLocal ProcInt RegA; ; cx assigned ;= Move RegA, 199; mov cx, 199 ;= Subtract RegA, @q; sub cx, word ptr [bp - ?LOCAL_VARMOD0] ;= Call @@QBScreen.DrawLine(0, @q, 319, RegA, @q); push es mov di, word ptr [??QBOurScreen] push word ptr [??QBOurScreen + 2] pop es push word ptr [bp - ?LOCAL_VARMOD0] push cx push 319 push word ptr [bp - ?LOCAL_VARMOD0] push 0 call far es:(di + SCREENOBJECT_M_DRAWLINEPNT) add sp, 10 pop es ;= ClearRegisters RegA; ; cx is no longer assigned ;= Inc @q; inc word ptr [bp - ?LOCAL_VARMOD0] ;= Jump @@Label_Main_0; jmp < .l0 ;= @@Label_Main_1: .l1: ;= Call Base.GetKey(), @c; call ??Base_GeyKey ; The following uses the value in ax in the CharToString function (which converts a single ; letter to a string) push es mov di, word ptr [bp - ?LOCAL_VARMOD1] push word ptr [bp - ?LOCAL_VARMOD1 + 2] pop es push ax call far es:(di + STRINGOBJECT_M_CHARTOSTRING) add sp, 2 pop es ;= EndFunction; push es ; Deinitialize our string object mov di, word ptr [bp - ?LOCAL_VARMOD1] push word ptr [bp - ?LOCAL_VARMOD1 + 2] pop es call far es:(di + STRINGOBJECT_M_DELETE) pop es mov sp, bp pop bp retf .ENDFUNC SECTION .data ??QBScreen DD 0 ; Our screen object pointer END CODE ========================================================================================== ___________________________________________________________________________________________________ A1.3 32bit x86 Assembly Version When assembled to 32bit x86 assembly, the end result would look something like (this is VERY MUCH simplified): NOTE: You do not see a single system-specific function call in the assembly! This is all handled by the library files that this will be linked to. The handling of the display, the key input, memory allocation, etc. is system specific and showing their implementation here would be completely useless. This is only designed to show how the assembly might be generated from the AnyASM listed above. This could be running in MS-DOS (with a DOS-Extender), 32bit Windows, 32bit x86 Linux or any other computer that uses 32bit x86 executables (the new Apples???) and supports 320x200 or higher with 256 or more colors. This is using yasm/nasm assembly syntax. BEGIN CODE ======================================================================================== BITS 32 ; Include the external function links and parameters for AnyASM %INCLUDE "anyasm.inc" ; For the string object %INCLUDE "objects/string.inc" ; For the screen object %INCLUDE "objects/screen.inc" SECTION .text ;= Function @@Init() Format Fast, Returns Nothing; ??Init: ; This is added automatically by the assembler to initialize our global objects ; Create the screen object push ??QBScreen call ScreenObject_New add esp, 4 ;= Call @@QBScreen.GetPrimaryScreen(); mov edi, dword ptr [??QBScreen] call (edi + SCREENOBJECT_M_GETPRIMARYSCREEN) ;= Call @@QBScreen.SetScreenMode(80, 25, 8, 0x01); push 1 push 8 push 25 push 80 call (edi + SCREENOBJECT_M_SETSCREENMODE) add esp, 16 ;= EndFunction; ret .ENDFUNC ??DeInit: ; This is added automatically by the assembler to deinitialize global objects mov edi, dword ptr [??QBScreen] call (di + SCREENOBJECT_M_DELETE) ret .ENDFUNC ;= Function Main() Format Fast, Returns Nothing; ?Main: ;= VarLocal S16 @q; ;= VarLocal String @c; %define ?LOCAL_VARMOD1 4 %define ?LOCAL_VARMOD0 6 // This is actually q, it's bumped to the end for aligment reasons ; Local variable setup %define ?LOCAL_VAR_SIZE 8 push ebp mov ebp, esp sub esp, ?LOCAL_VAR_SIZE ; Allocate the string object lea eax, [ebp - ?LOCAL_VARMOD1] push eax call StringObject_New add esp, 4 ;= Call @@QBScreen.SetScreenMode(320, 200, 8); mov edi, dword ptr [??QBScreen] push 0 push 8 push 200 push 320 call (edi + SCREENOBJECT_M_SETSCREENMODE) add esp, 8 ;= Move @q, 0; mov word ptr [ebp - ?LOCAL_VARMOD0], 0 ;= @@Label_Main_0: .l0: ;= Compare @q, 199; cmp word ptr [ebp - ?LOCAL_VARMOD0], 199 ;= JumpIf Greater, @@Label_Main_1; jg > .l1 ;= RegisterLocal ProcInt RegA; ; ecx assigned ;= Move RegA, 199; mov ecx, 199 ;= Subtract RegA, @q; xor eax, eax mov ax, word ptr [bp - ?LOCAL_VARMOD0] sub ecx, eax ;= Call @@QBScreen.DrawLine(0, @q, 319, RegA, @q); mov edi, dword ptr [??QBOurScreen] push eax ; eax is still @q from above push ecx push 319 push eax ; eax is still @q from above push 0 call (edi + SCREENOBJECT_M_DRAWLINEPNT) add esp, 20 ;= ClearRegisters RegA; ; ecx is no longer assigned ;= Inc @q; inc word ptr [bp - ?LOCAL_VARMOD0] ;= Jump @@Label_Main_0; jmp < .l0 ;= @@Label_Main_1: .l1: ;= Call Base.GetKey(), @c; call ??Base_GeyKey ; The following uses the value in eax in the CharToString function (which converts a single ; letter to a string) mov edi, dword ptr [bp - ?LOCAL_VARMOD1] push eax call (edi + STRINGOBJECT_M_CHARTOSTRING) add esp, 4 ;= EndFunction; ; Deinitialize our string object mov edi, dword ptr [ebp - ?LOCAL_VARMOD1] call (edi + STRINGOBJECT_M_DELETE) mov esp, ebp pop ebp ret .ENDFUNC SECTION .data ??QBScreen DD 0 ; Our screen object pointer END CODE ========================================================================================== ___________________________________________________________________________________________________ A1.4 68000 (MC68K) Assembly Version When assembled to MC68K assembly, the end result would look something like (this is VERY MUCH simplified): NOTE: You do not see a single system-specific function call in the assembly! This is all handled by the library files that this will be linked to. The handling of the display, the key input, memory allocation, etc. is system specific and showing their implementation here would be completely useless. This is only designed to show how the assembly might be generated from the AnyASM listed above. This may be running on an Atari TT or on a Macintosh or any other system that uses a 68K processor and supports 320x200 or higher with 256 or more colors. NOTE 2: I do not currently have a 68K cross assembler, so some of the syntax below is "made up", like how to use .inc files. As soon as I know better, this will be amended. Also, I am no master at 68000 programming so I'm certain I'm doing SOMETHING wrong or non-optimized here. The point isn't to be perfect in an example, but rather to show how the exact same code can operate in many different environments. NOTE 3: You may notice that 16bit integers are used in some places that the 32bit x86 uses 32bit integers. This is due to the fact that, though the 68K processors support 32bit operations internally, there is a big timing hit for using 32bit vs 16bit operations, therefore we consider the native Processor Integer size on the 68k to be 16bit. Since the Processor Integer size is 16bit or higher, we really don't care about it's size (as long as it's 16bit or higher) and thus use what is most efficient for the processor. BEGIN CODE ======================================================================================== ; Include the external function links and parameters for AnyASM INCLUDE "anyasm.inc" ; For the string object INCLUDE "objects/string.inc" ; For the screen object INCLUDE "objects/screen.inc" Section Code ;= Function @@Init() Format Fast, Returns Nothing; Procedure @@Function_Init ; This is added automatically by the assembler to initialize our global objects ; Create the screen object move.l #@@QBScreen, -(a7) jsr ScreenObject_New add.l #4, a7 ;= Call @@QBScreen.GetPrimaryScreen(); move.l @@QBScreen, a5 jsr (SCREENOBJECT_M_GETPRIMARYSCREEN, a5).l ;= Call @@QBScreen.SetScreenMode(80, 25, 8, 0x01); move.w #1, -(a7) move.w #8, -(a7) move.w #25, -(a7) move.w #80, -(a7) jsr (SCREENOBJECT_M_SETSCREENMODE, a5).l add.l #8, a7 ;= EndFunction; rts EndProcedure Procedure @@Function_DeInit: ; This is added automatically by the assembler to deinitialize global objects move.l @@QBScreen, a5 jsr (SCREENOBJECT_M_DELETE, a5).l rts EndProcedure ;= Function Main() Format Fast, Returns Nothing; Procedure Function_Main ;= VarLocal S16 @q; ;= VarLocal String @c; DEFINE ?LOCAL_VARMOD0 2 DEFINE ?LOCAL_VARMOD1 6 ; Local variable setup DEFINE ?LOCAL_VAR_SIZE 6 move.l a6, -(a7) move.l a7, a6 sub.l a7, #?LOCAL_VAR_SIZE ; Allocate the string object lea (?LOCAL_VARMOD1, a6), d0 move.l d0, -(a7) jsr #StringObject_New add.l #4, a7 ;= Call @@QBScreen.SetScreenMode(320, 200, 8); move.l @@QBScreen, a5 move.w #8, -(a7) move.w #200, -(a7) move.w #320, -(a7) move.w #1, -(a7) jsr (SCREENOBJECT_M_SETSCREENMODE, a5).l add.l #8, a7 ;= Move @q, 0; move.w #0, (?LOCAL_VARMOD0, a6) ;= @@Label_Main_0: l0: ;= Compare @q, 199; cmpi.w #199, (?LOCAL_VARMOD0, a6) ;= JumpIf Greater, @@Label_Main_1; bgt > l1 ;= RegisterLocal ProcInt RegA; ; d2 assigned ;= Move RegA, 199; move.w #199, d2 ;= Subtract RegA, @q; sub.w (?LOCAL_VARMOD0, a6), d2 ;= Call @@QBScreen.DrawLine(0, @q, 319, RegA, @q); move.l @@QBScreen, a5 move.w (?LOCAL_VARMOD0, a6), -(a7) move.w d2, -(a7) move.w #319, -(a7) move.w (?LOCAL_VARMOD0, a6), -(a7) move.w #0, -(a7) jsr (SCREENOBJECT_M_DRAWLINE, a5).l add #10, a7 ;= ClearRegisters RegA; ; d2 is no longer assigned ;= Inc @q; addq.w #1, (?LOCAL_VARMOD0, a6) ;= Jump @@Label_Main_0; jmp < l0 ;= @@Label_Main_1: l1: ;= Call Base.GetKey(), @c; jsr #Base_GetKey ; The following uses the value in d0 in the CharToString function (which converts a single ; letter to a string) move.l (?LOCAL_VARMOD1, a6), a5 move.w d0, -(a7) jsr (STRINGOBJECT_M_CHARTOSTRING, a5).l add.l #2, a7 ;= EndFunction; move.l (uservar_c), a5 jsr (STRINGOBJECT_M_DELETE, a5).l move.l a6, a7 move.l (a7)+, a6 rts EndProcedure Section Data @@QBScreen DC.L 0 ; Our global screen object pointer END CODE ========================================================================================== *************************************************************************************************** Updates v0.0.1 2006-12-24 to 2007-03-15 Original version, giving a brief description of the ANY Platform v0.0.2 2007-04-09 Now that the AnyASM language is essentially done, the examples had to be massively rewritten to match. Though the final assembly is rather rough (and not tested), it is enough to get a general idea of how AnyASM will translate to REAL assembly 32bit x86, 64bit x64 and MC68K assembly versions are planned to be the earliest versions supported for Windows, Linux, Mac, old Macintosh, Atari ST and Amiga.