From 301dbb53e3aa320ef6b8e635257a2acee1409f9c Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Wed, 22 Jan 2003 13:51:44 +0000 Subject: Add support for the PharLap ETS tools. (Charles Crain) --- doc/man/scons.1 | 2 + etc/TestSCons.py | 20 ++ src/CHANGES.txt | 2 + src/engine/MANIFEST.in | 3 + src/engine/SCons/Tool/386asm.py | 72 +++++++ src/engine/SCons/Tool/PharLapCommon.py | 124 +++++++++++ src/engine/SCons/Tool/PharLapCommonTests.py | 55 +++++ src/engine/SCons/Tool/__init__.py | 6 +- src/engine/SCons/Tool/linkloc.py | 107 ++++++++++ test/PharLap.py | 309 ++++++++++++++++++++++++++++ 10 files changed, 697 insertions(+), 3 deletions(-) create mode 100644 src/engine/SCons/Tool/386asm.py create mode 100644 src/engine/SCons/Tool/PharLapCommon.py create mode 100644 src/engine/SCons/Tool/PharLapCommonTests.py create mode 100644 src/engine/SCons/Tool/linkloc.py create mode 100644 test/PharLap.py diff --git a/doc/man/scons.1 b/doc/man/scons.1 index 002793c..c10b729 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -788,6 +788,7 @@ be redetected. SCons supports the following tool specifications out of the box on all platforms: .ES +386asm ar dvipdf dvips @@ -801,6 +802,7 @@ gcc gnulink latex lex +linkloc masm mingw mslib diff --git a/etc/TestSCons.py b/etc/TestSCons.py index 658496b..e8bac90 100644 --- a/etc/TestSCons.py +++ b/etc/TestSCons.py @@ -167,6 +167,26 @@ class TestSCons(TestCmd.TestCmd): except KeyError: return None + def detect_tool(self, tool, prog=None): + """ + Given a tool (i.e., tool specification that would be passed + to the "tools=" parameter of Environment()) and one a program that + corresponds to that tool, return true if and only if we can find + that tool using Environment.Detect(). + + By default, progs is set to the value passed into the tools parameter. + """ + + if not prog: + prog = tool + import SCons.Environment + import SCons.Errors + try: + env=SCons.Environment.Environment(tools=[tool]) + except (SCons.Errors.UserError, SCons.Errors.InternalError): + return None + return env.Detect([prog]) + def wrap_stdout(self, build_str = "", read_str = ""): """Wraps standard output string(s) in the normal "Reading ... done" and "Building ... done" strings diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 83dbc9a..1f5a6d5 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -15,6 +15,8 @@ RELEASE 0.11 - XXX - Added new AddPreAction() and AddPostAction() functions that support taking additional actions before or after building specific targets. + - Add support for the PharLap ETS tool chain. + From Steven Knight: - Allow Python function Actions to specify a list of construction diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in index cf27274..a51277b 100644 --- a/src/engine/MANIFEST.in +++ b/src/engine/MANIFEST.in @@ -30,6 +30,7 @@ SCons/Sig/MD5.py SCons/Sig/TimeStamp.py SCons/Taskmaster.py SCons/Tool/__init__.py +SCons/Tool/386asm.py SCons/Tool/ar.py SCons/Tool/default.py SCons/Tool/dvipdf.py @@ -44,6 +45,7 @@ SCons/Tool/ifl.py SCons/Tool/ilink.py SCons/Tool/latex.py SCons/Tool/lex.py +SCons/Tool/linkloc.py SCons/Tool/masm.py SCons/Tool/mingw.py SCons/Tool/mslib.py @@ -52,6 +54,7 @@ SCons/Tool/msvc.py SCons/Tool/nasm.py SCons/Tool/pdflatex.py SCons/Tool/pdftex.py +SCons/Tool/PharLapCommon.py SCons/Tool/tar.py SCons/Tool/tex.py SCons/Tool/yacc.py diff --git a/src/engine/SCons/Tool/386asm.py b/src/engine/SCons/Tool/386asm.py new file mode 100644 index 0000000..c07f856 --- /dev/null +++ b/src/engine/SCons/Tool/386asm.py @@ -0,0 +1,72 @@ +"""SCons.Tool.386asm + +Tool specification for the 386ASM assembler for the Phar Lap ETS embedded +operating system. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os.path +import string +import re + +import SCons.Action +import SCons.Defaults +import SCons.Tool + +from SCons.Tool.PharLapCommon import addPharLapPaths + +ASSuffixes = ['.s', '.asm', '.ASM'] +ASPPSuffixes = ['.spp', '.SPP'] +if os.path.normcase('.s') == os.path.normcase('.S'): + ASSuffixes.extend(['.S']) +else: + ASPPSuffixes.extend(['.S']) + +def generate(env, platform): + """Add Builders and construction variables for ar to an Environment.""" + static_obj, shared_obj = SCons.Tool.createObjBuilders(env) + + for suffix in ASSuffixes: + static_obj.add_action(suffix, SCons.Defaults.ASAction) + + for suffix in ASPPSuffixes: + static_obj.add_action(suffix, SCons.Defaults.ASPPAction) + + env['AS'] = '386asm' + env['ASFLAGS'] = '' + env['ASCOM'] = '$AS $ASFLAGS $SOURCES -o $TARGET' + env['ASPPCOM'] = '$CC $ASFLAGS $CPPFLAGS $SOURCES -o $TARGET' + + addPharLapPaths(env) + +def exists(env): + return env.Detect('386asm') diff --git a/src/engine/SCons/Tool/PharLapCommon.py b/src/engine/SCons/Tool/PharLapCommon.py new file mode 100644 index 0000000..ddcaba6 --- /dev/null +++ b/src/engine/SCons/Tool/PharLapCommon.py @@ -0,0 +1,124 @@ +"""SCons.Tool.PharLapCommon + +This module contains common code used by all Tools for the +Phar Lap ETS tool chain. Right now, this is linkloc and +386asm. + +""" + +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os +import os.path +import SCons.Errors +import SCons.Util +import re +import string + +def getPharLapPath(): + """Reads the registry to find the installed path of the Phar Lap ETS + development kit. + + Raises UserError if no installed version of Phar Lap can + be found.""" + + if not SCons.Util.can_read_reg: + raise SCons.Errors.InternalError, "No Windows registry module was found" + try: + k=SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, + 'SOFTWARE\\Pharlap\\ETS') + val, type = SCons.Util.RegQueryValueEx(k, 'BaseDir') + + # The following is a hack...there is (not surprisingly) + # an odd issue in the Phar Lap plug in that inserts + # a bunch of junk data after the phar lap path in the + # registry. We must trim it. + idx=val.find('\0') + if idx >= 0: + val = val[:idx] + + return os.path.normpath(val) + except SCons.Util.RegError: + raise SCons.Errors.UserError, "Cannot find Phar Lap ETS path in the registry. Is it installed properly?" + +REGEX_ETS_VER = re.compile(r'#define\s+ETS_VER\s+([0-9]+)') + +def getPharLapVersion(): + """Returns the version of the installed ETS Tool Suite as a + decimal number. This version comes from the ETS_VER #define in + the embkern.h header. For example, '#define ETS_VER 1010' (which + is what Phar Lap 10.1 defines) would cause this method to return + 1010. Phar Lap 9.1 does not have such a #define, but this method + will return 910 as a default. + + Raises UserError if no installed version of Phar Lap can + be found.""" + + include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h")) + if not os.path.exists(include_path): + raise SCons.Errors.UserError, "Cannot find embkern.h in ETS include directory.\nIs Phar Lap ETS installed properly?" + mo = REGEX_ETS_VER.search(open(include_path, 'r').read()) + if mo: + return int(mo.group(1)) + # Default return for Phar Lap 9.1 + return 910 + +def addPathIfNotExists(env_dict, key, path, sep=os.pathsep): + """This function will take 'key' out of the dictionary + 'env_dict', then add the path 'path' to that key if it is not + already there. This treats the value of env_dict[key] as if it + has a similar format to the PATH variable...a list of paths + separated by tokens. The 'path' will get added to the list if it + is not already there.""" + try: + paths = string.split(env_dict[key], sep) + if not os.path.normcase(path) in map(os.path.normcase, paths): + env_dict[key] = string.join([ path ] + paths, sep) + except KeyError: + env_dict[key] = path + +def addPharLapPaths(env): + """This function adds the path to the Phar Lap binaries, includes, + and libraries, if they are not already there.""" + ph_path = getPharLapPath() + + try: + env_dict = env['ENV'] + except KeyError: + env_dict = {} + env['ENV'] = env_dict + addPathIfNotExists(env_dict, 'PATH', + os.path.join(ph_path, 'bin')) + addPathIfNotExists(env_dict, 'INCLUDE', + os.path.join(ph_path, 'include')) + addPathIfNotExists(env_dict, 'LIB', + os.path.join(ph_path, 'lib')) + addPathIfNotExists(env_dict, 'LIB', + os.path.join(ph_path, os.path.normpath('lib/vclib'))) + + env['PHARLAP_PATH'] = getPharLapPath() + env['PHARLAP_VERSION'] = str(getPharLapVersion()) + diff --git a/src/engine/SCons/Tool/PharLapCommonTests.py b/src/engine/SCons/Tool/PharLapCommonTests.py new file mode 100644 index 0000000..663b25e --- /dev/null +++ b/src/engine/SCons/Tool/PharLapCommonTests.py @@ -0,0 +1,55 @@ +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import unittest +import os.path +import os +import sys + +import SCons.Errors +from SCons.Tool.PharLapCommon import * + +class PharLapCommonTestCase(unittest.TestCase): + def test_addPathIfNotExists(self): + """Test the addPathIfNotExists() function""" + env_dict = { 'FOO' : os.path.normpath('/foo/bar') + os.pathsep + \ + os.path.normpath('/baz/blat'), + 'BAR' : os.path.normpath('/foo/bar') + os.pathsep + \ + os.path.normpath('/baz/blat') } + addPathIfNotExists(env_dict, 'FOO', os.path.normpath('/foo/bar')) + addPathIfNotExists(env_dict, 'BAR', os.path.normpath('/bar/foo')) + addPathIfNotExists(env_dict, 'BAZ', os.path.normpath('/foo/baz')) + + assert env_dict['FOO'] == os.path.normpath('/foo/bar') + os.pathsep + \ + os.path.normpath('/baz/blat'), env_dict['FOO'] + assert env_dict['BAR'] == os.path.normpath('/bar/foo') + os.pathsep + \ + os.path.normpath('/foo/bar') + os.pathsep + \ + os.path.normpath('/baz/blat'), env_dict['BAR'] + assert env_dict['BAZ'] == os.path.normpath('/foo/baz'), env_dict['BAZ'] + +if __name__ == "__main__": + suite = unittest.makeSuite(PharLapCommonTestCase, 'test_') + if not unittest.TextTestRunner().run(suite).wasSuccessful(): + sys.exit(1) diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py index 3621826..50ab456 100644 --- a/src/engine/SCons/Tool/__init__.py +++ b/src/engine/SCons/Tool/__init__.py @@ -145,9 +145,9 @@ def tool_list(platform, env): # the tool files themselves. if str(platform) == 'win32': "prefer Microsoft tools on Windows" - linkers = ['mslink', 'gnulink', 'ilink'] - c_compilers = ['msvc', 'mingw', 'gcc', 'icc'] - assemblers = ['masm', 'nasm', 'gas'] + linkers = ['mslink', 'gnulink', 'ilink', 'linkloc' ] + c_compilers = ['msvc', 'mingw', 'gcc', 'icc' ] + assemblers = ['masm', 'nasm', 'gas', '386asm' ] fortran_compilers = ['g77', 'ifl'] ars = ['mslib', 'ar'] elif str(platform) == 'os2': diff --git a/src/engine/SCons/Tool/linkloc.py b/src/engine/SCons/Tool/linkloc.py new file mode 100644 index 0000000..51ce60c --- /dev/null +++ b/src/engine/SCons/Tool/linkloc.py @@ -0,0 +1,107 @@ +"""SCons.Tool.linkloc + +Tool specification for the LinkLoc linker for the Phar Lap ETS embedded +operating system. + +There normally shouldn't be any need to import this module directly. +It will usually be imported through the generic SCons.Tool.Tool() +selection method. + +""" + +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os.path +import string +import re + +import SCons.Action +import SCons.Defaults +import SCons.Errors +import SCons.Util + +from SCons.Platform.win32 import TempFileMunge +from SCons.Tool.msvc import get_msdev_paths +from SCons.Tool.PharLapCommon import addPharLapPaths + +_re_linker_command = re.compile(r'(\s)@\s*([^\s]+)') + +def repl_linker_command(m): + # Replaces any linker command file directives (e.g. "@foo.lnk") with + # the actual contents of the file. + try: + f=open(m.group(2), "r") + return m.group(1) + f.read() + except IOError: + # the linker should return an error if it can't + # find the linker command file so we will remain quiet. + # However, we will replace the @ with a # so we will not continue + # to find it with recursive substitution + return m.group(1) + '#' + m.group(2) + +class LinklocGenerator: + def __init__(self, cmdline): + self.cmdline = cmdline + + def __call__(self, env, target, source, for_signature): + if for_signature: + # Expand the contents of any linker command files recursively + subs = 1 + strsub = env.subst(self.cmdline) + while subs: + strsub, subs = _re_linker_command.subn(repl_linker_command, strsub) + return strsub + else: + return TempFileMunge(env, string.split(self.cmdline), 0) + +_linklocLinkAction = SCons.Action.Action(SCons.Action.CommandGenerator(LinklocGenerator("$LINK $LINKFLAGS $( $_LIBDIRFLAGS $) $_LIBFLAGS -exe $TARGET $SOURCES"))) +_linklocShLinkAction = SCons.Action.Action(SCons.Action.CommandGenerator(LinklocGenerator("$SHLINK $SHLINKFLAGS $( $_LIBDIRFLAGS $) $_LIBFLAGS -dll $TARGET $SOURCES"))) + +def generate(env, platform): + """Add Builders and construction variables for ar to an Environment.""" + env['BUILDERS']['SharedLibrary'] = SCons.Defaults.SharedLibrary + env['BUILDERS']['Program'] = SCons.Defaults.Program + + env['SHLINK'] = '$LINK' + env['SHLINKFLAGS'] = '$LINKFLAGS' + env['SHLINKCOM'] = _linklocShLinkAction + env['SHLIBEMITTER']= None + env['LINK'] = "linkloc" + env['LINKFLAGS'] = '' + env['LINKCOM'] = _linklocLinkAction + env['LIBDIRPREFIX']='-libpath ' + env['LIBDIRSUFFIX']='' + env['LIBLINKPREFIX']='-lib ' + env['LIBLINKSUFFIX']='$LIBSUFFIX' + + include_path, lib_path, exe_path = get_msdev_paths() + env['ENV']['LIB'] = lib_path + env['ENV']['PATH'] = exe_path + + addPharLapPaths(env) + +def exists(env): + return env.Detect('linkloc') diff --git a/test/PharLap.py b/test/PharLap.py new file mode 100644 index 0000000..d9f8993 --- /dev/null +++ b/test/PharLap.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os +import os.path +import string +import sys +import TestSCons +import time + +test = TestSCons.TestSCons() + +if sys.platform != 'win32': + test.pass_test() + +test.no_result(not test.detect_tool('linkloc')) +test.no_result(not test.detect_tool('386asm')) + +# From the Phar Lap minasm example program... +test.write("minasm.asm", r""" +; +; MINASM.ASM - A minimal assembly language program which runs +; under ToolSuite. You can use this program as a framework +; for large assembly language programs. +; +.386 + +; +; Segmentation and segment ordering. +; +; First comes the code segment. +; +_TEXT segment use32 byte public 'CODE' +_TEXT ends + +; +; The data segment contains initialized RAM based data. It will automatically +; be placed in the ROM at link time and unpacked into RAM at run-time +; by the __pl_unpackrom function. +; +; If you do not need any initialized data in your assembly language program, +; you can leave this segment empty and remove the call to __pl_unpackrom. +; +; +_DATA segment use32 dword public 'DATA' + +loopcount dd 10d +rammessage db 'This message is in RAM memory',0dh,0ah,0 + +_DATA ends + +; +; The BSS segment contains RAM based variables which +; are initialized to zero at run-time. Putting unitialized +; variables which should start at zero here saves space in +; the ROM. +; +; If you do not need any zero-initialized data in your assembly language +; program, you can leave this segment empty (and optionally remove the +; instructions below which initialize it). +; +; The segment name must be lower case for compatibility with the linker +; +_bss segment use32 dword public 'BSS' +dummy_bss db 32 dup(?) ; Use a little bit of BSS just to test it +_bss ends + +; +; The const segment contains constants which will never +; change. It is put in the ROM and never copied to RAM. +; +; If you do not need any ROM based constants in your assembly language +; program, you can leave this segment empty. +; +_CONST segment use32 dword public 'CONST' +rommessage db 'This message is in ROM memory',0dh,0ah,0 +_CONST ends + +; +; We're in flat model, so we'll put all the read-only segments we know about +; in a code group, and the writeable segments in a data group, so that +; we can use assume to easily get addressability to the segments. +; +CGROUP group _TEXT, _CONST +DGROUP group _DATA, _bss + + assume cs:CGROUP,ds:DGROUP +_TEXT segment + +; +; _main - the main routine of this program. +; +; We will display the RAM and ROM messages the number of times +; specified in the loopcount variable. This proves that we can +; initialize RAM data out of ROM and the fact that we can +; modify the loop count in memory verifies that it actually ends +; up in RAM. +; + public _main +_main proc near + + mov cl,0ah ; Skip a line before we start + call PutCharTarget ; +main_loop: + cmp loopcount,0 ; Are we at the end of our loop? + je short done_main ; yes. + lea edx,rommessage ; EDX -> ROM message + call WriteStringTarget ; Display it + lea edx,rammessage ; EDX -> RAM message + call WriteStringTarget ; Display it + dec loopcount ; + jmp main_loop ; Branch back for next loop iteration +done_main: + ret ; That's it! + +_main endp + +; +; WriteStringTarget - Display a string on the target console +; +; Inputs: +; EDX -> Null terminated ASCII string to display +; +; Outputs: +; All registers preserved +; +WriteStringTarget proc near + + push ecx ; Save registers + push edx ; + +write_loop: + movzx ecx,byte ptr [edx] ; Get a character + jecxz done_str ; Branch if end of string + call PutCharTarget ; Display this character + inc edx ; Bump scan pointer + jmp write_loop ; And loop back for next character + +done_str: + pop edx ; Restore registers + pop ecx ; + ret ; and return + +WriteStringTarget endp + +; +; PutCharTarget - Write a character on the target console +; +; This routine displays a character on the target console by using +; the PutChar kernel service available through int 254. +; +; Inputs: +; CL = character to display +; +; Outputs: +; All registers preserved +; +PutCharTarget proc near + + push eax ; Save registers + push ebx ; + push edx ; + + mov ax,254Ah ; Request Kernel Service + mov bx,1 ; service code 1 = PutChar + movzx edx,cl ; EDX = character to display + int 0FEh ; Int 254 is for kernel services + + pop edx ; Restore registers + pop ebx ; + pop eax ; + ret ; and return + +PutCharTarget endp + +; +; The __pl_unpackrom unpacks initialized RAM based data variables +; out of the ROMINIT segment into their RAM area. They are put +; in the ROMINIT segment with the -ROMINIT switch in the link file. +; +extrn __pl_unpackrom:near + +; +; The _EtsExitProcess function is used to terminate our program +; +extrn _EtsExitProcess:near + +; +; The linker will define symbols for the beginning and end of the +; BSS segment. +; +extrn __p_SEG__bss_BEGIN:dword +extrn __p_SEG__bss_END:dword + +; +; __p_start -- The entry point for our assembly language program. +; We unpack the RAM based variables out of the ROM and clear the +; BSS to zero, then call _main where the real work happens. When +; _main returns, we call EtsExitProcess(0) to terminate. +; +public __p_start +__p_start proc near + pushad ; save initial regs + push es ; + call __pl_unpackrom ; Call the unpacker + cld ; Clear direction flag + + lea eax,__p_SEG__bss_END ; load end address and + lea ebx,__p_SEG__bss_BEGIN ; subtract start to get size + sub eax,ebx + mov ecx,eax ; This is size + inc ecx + lea edi,__p_SEG__bss_BEGIN ; Zero from start address + mov al,0 ;Zero out BSS and C_COMMON + rep stosb + + pop es ; restore initial regs + popad + call _main ; go do some work +stopme: + xor eax,eax ; Call _EtsExitProcess(0) + push eax ; + call _EtsExitProcess ; + pop eax ; + jmp stopme ; .. in a loop just in case it ever + ; comes back + +__p_start endp + +TD_hack: + mov eax, __p_tdhack ; force reference to TD-hack symbol + +_TEXT ends + +; +; Hack for Turbo Debugger/TDEMB - TD will fault if the .exe being +; debugged doesn't have an import table. (TD looks for the address of +; the table, then dereferences that address wihtout checking for NULL). +; +; This symbol, __p_tdhack, must be declared as an import in all the +; .emb files shipped. IE: +; +; -implib embkern.lib +; -import __p_tdhack +; +; This forces the creation of an import table within the .EXE. +_DATA segment +extrn __p_tdhack:dword +_DATA ends + end __p_start +""") + +test.write("foo.lnk",""" +@baz\\bar.lnk +""") + +test.subdir("baz") +test.write([ "baz", "bar.lnk"],""" +@asm.emb +""") + +test.write("SConstruct", """ +env=Environment(tools = [ 'linkloc', '386asm' ], + ASFLAGS='-twocase -cvsym', + LINKFLAGS='@foo.lnk') +env.Program(target='minasm', source='minasm.asm') +""") + +test.run(arguments='.') + +# Assume .exe extension...this test is for Win32 only. +test.fail_test(not os.path.exists('minasm.exe')) +test.up_to_date(arguments='.') + +# Updating a linker command file should cause a rebuild! +test.write([ "baz", "bar.lnk"],""" +-cvsym +@asm.emb +""") + +oldtime = os.path.getmtime(test.workpath('minasm.exe')) +time.sleep(2) # Give the time stamp time to change +test.run(arguments = '.') +test.fail_test(oldtime == os.path.getmtime(test.workpath('minasm.exe'))) + +test.pass_test() -- cgit v0.12