Asm1 fatal error a1000 cannot open file

asm1 fatal error a1000 cannot open file

running mkdir build; cmake..; cmake --build. yields an error. C:\Program Files (x86)\Microsoft fatal error A cannot open file. sprers.eu › board. The Visual C++ language includes the Microsoft Assembler (MASM). To verify that MASM is installed, open a Windows Explorer window and look for the file named ml. asm1 fatal error a1000 cannot open file

Asm1 fatal error a1000 cannot open file - are

The Book's Example Programs At the top of this document, we explained how to download the file named sprers.eu and extract it into the C:\Irvine folder. Unless you have some objection to using that location, do not alter the path. (Note to lab administrators: you can designate c:\Irvine directory as read-only.).

The folllowing files should appear in the c:\Irvine directory:

FilenameDescription
basm, basm Blank templates for bit and bit assembly language source files
sprers.eu Include file for writing Windows applications
Irvineinc Include file used with the Irvine16 link library (bit applications)
Irvinelib bit link function library used with this book
Irvineinc Include file used with the Irvine32 link library (bit applications)
Irvinelib Irvine's bit link library
Kernellib bit link library for Windows API
Linkexebit Microsoft linker
sprers.eu Irvine's macro include file (see Chapter 10)
make16_vsbatVisual Studio batch file for building bit applications
sprers.eu Small-sized include file containing MS-Windows definitions, used by Irvineinc
UserlibMS-Windows basic I/O link library
sprers.eu Keyboard code definitions file, used by Irvineinc

A subdirectory named Examples will contain all the example programs shown in the book, source code for the book's , , and bit libraries, and two sample projects for earlier versions of Visual Studio.

Setting up Visual Studio

Select the C++ Configuration

Visual Studio supports multiple programming languages and application types. The C++ programming language configuration most closely matches that of assembly language programming, so we suggest the following steps:
  1. Select Tools >> Import and Export Settings from the menu
  2. Select the "Import selected environment settings" radio button
  3. Select the "No, just import" radio button
  4. Select "Visual C++" from the Default Settings List and click the Next button
  5. Click the Finish button, then click the Close button
  6. Notice the tabs on the left and right sides of the Visual Studio workspace. Close the Server Explorer, Toolbox, and Properties tabs. (Optionally, you can use the mouse to drag the Solution Explorer tool window to the right side of the workspace.) If you should accidentally close the Solution Explorer window in the future, you can bring it back: select View from the menu, and locate Solution Explorer in the list of views.

Optional Step: Set the tab indent size

Start Visual Studio and select Options from the Tools menu. Select and expand the Text Editor item, select All Languages, and select Tabs. Optionally, you may want to select the Insert spaces radio button:

I prefer to set the Tab Size and Indent Size values to 5.

Tutorial: Building and running a bit program

Now you're ready to open and build your first bit project.

Opening a Project

Visual Studio requires assembly language source files to belong to a project, which is a kind of container. A project holds configuration information such as the locations of the assembler, linker, and required libraries. A project has its own folder, and it holds the names and locations of all files belonging to it.

If you have not already done so,Right-click here to download a zip file containing an up-to-date Visual Studio project that has been configured for assembly language. After downloading this file, un-zip it into your working directory. It contains a sample asm test file named sprers.eu

Follow these steps:

  1. Start Visual Studio.
  2. Open our sample Visual Studio project file by selecting File/Open/Project from the Visual Studio menu.
  3. Navigate to your working folder where you unzipped our project file, and select the file named sprers.eu.
  4. Once the project has been opened, you will see the project name in Visual Studio's Solution Explorer window. You should also see an assembly language source file in the project named sprers.eu Double-click the file name to open it in the editor.

You should see the following program in the editor window:

; sprers.eu - adds two bit integers. ; Chapter 3 example .model flat,stdcall .stack ExitProcess proto,dwExitCode:dword .code main proc mov eax,5 add eax,6 invoke ExitProcess,0 main endp end main
In the future, you can use this file as a starting point to create new programs by copying it and renaming the copy in the Solution Explorer window.

Adding a File to a Project: If you need to add an .asm file to an open project, do the following: (1) Right-click the project name in the Visual Studio window, select Add, select Existing Item. (2) In the Add Existing Item dialog window, browse to the location of the file you want to add, select the filename, and click the Add button to close the dialog window.

Build the Program

Now you will build (assemble and link) the sample program. Select Build Project from the Build menu. In the Output window for Visual Studio at the bottom of the screen, you should see messages similar to the following, indicating the build progress:

1> Build started: Project: Project, Configuration: Debug Win32 1>Assembling sprers.eu 1>sprers.euj -> \Project32_VS\Debug\sprers.eu ========== Build: 1 succeeded, 0 failed, 0 skipped ==========

If you do not see these messages, the project has probably not been modified since it was last built. No problem--just select Rebuild Project from the Build menu.

Run the Program in Debug Mode

The easiest way to run your first program is to use the debugger. First, you must set a breakpoint. When you set a breakpoint in a program, you can use the debugger to execute the program a full speed (more or less) until it reaches the breakpoint. At that point, the debugger drops into single-step mode. Here's how to do it:

  1. Make sure the ASM source code file is open in the editor window.
  2. Click the mouse along the border to the left of the mov eax,5 statement. A large red dot should appear in the margin.
  3. Select Start Debugging from the Debug menu. The program should run and pause on the line with the breakpoint. (Optionally, you can close the Diagnostic Tools, Autos, and Call Stack windows.)
  4. Press the F10 key (called Step Over) to execute the current statement. Continue pressing F10 until the program is about to execute the invoke statement.
  5. A small black window icon should appear on either your Windows desktop or status bar. The window should be blank because this program does not display any output.
  6. Press F10 one more time to end the program.

You can remove a breakpoint by clicking its dot with the mouse. Take a few minutes to experiment with the Debug menu commands. Set more breakpoints and run the program again.

Here's what your program will look like when paused at the breakpoint:

Running a program from the Command Prompt: When you assembled and linked the project, a file named sprers.eu was created inside the project's \Debug folder. This file executes when you run the project. You can execute any EXE by double-clicking its name inside Windows Explorer, but it will often just flash on the screen and disappear. That is because Windows Explorer does not pause the display before closing the command window. On the other hand, you can open a Command prompt window, move to the Debug directory, and run sprers.eu by typing "Project" (without the quotes). You will need to do some reading on Windows shell commands if you plan to use the command line.

To remove a source file from the Visual Studio window, right-click its filename and select Remove. The file will not be deleted from the file system. On the other hand, if you want to delete the file, select it and press the Del key.

Registers

Soon you will want to display CPU registers when debugging your programs. Here's how to make them visible: First, under the Tools >> Options menu, select Debbuging in the left panel, and select Enable address-level debugging. Next, set a breakpoint in your source code on an executable statement, run your program in Debug mode, select Windows from the Debug menu, and then select Registers from the drop-down list.

If you do not see the Registers command in the Debug >> Windows drop-down menu (which seems to be the case for the VS Community Edition, there is a way to add a Registers command button to your Debug toolbar. Here's how to do it:
  1. While not debugging, select Customize from the Tools menu.
  2. Click the Commands tab, select the Toolbar tab, and select Debug from the list of toolbars.
  3. Click the Add Command button. In the Categories list, select Debug.
  4. Select Registers from the list of commands, click the OK button to close the dialog window.
  5. Click the Close button to close the Customize dialog. You should now see a new button on the Debug toolbar that looks like a small rectangle containing "0X" when you begin debugging a program.
The Registers window may appear docked to the top of the workspace, but you may find it helpful to float the window on top of your workspace. Just grab the window header with the mouse and pull it to the center area. You will also want to display the CPU flags. To do that, right click inside the Registers window and check the word Flags from the popup menu. You can interrupt a debugging session at any time by selecting Stop Debugging from the Debug menu. You can do the same by clicking the maroon-colored square button on the toolbar. To remove a breakpoint from a program, click its red dot to make it disappear. A reminder, you might want to review our tutorial: Using the Visual Studio debugger

Building and Running Other Programs

Suppose you want to run another example program, or possibly create your own program. You can remove the existing assembly language file from the Solution Explorer window and insert a new .asm file into the project.

  • To remove a program from a project without deleting the file, right-click its name in the Solution Explorer window. In the context menu, select Remove. If you change your mind and decide to add it back to the project, right-click in the same window, select Add, select Existing item, and select the file you want to add.

Adding a File to a Project

An easy way to add an assembly language source file to an open project is to drag its filename with the mouse from a Windows Explorer window onto the name of your project in the Solution Explorer window. The physical file will not be copied--the project only holds a reference to the file's location. Try this now:

  1. Remove the sprers.eu file from your project.
  2. Add a reference to the file Examples\ch03\sprers.eu to the project.
  3. Build and run the project.

Copying a Source File

One way to make a copy of an existing source code file is to use Windows Explorer to copy the file into your project directory. Then, right-click the project name in Solution Explorer, select Add, select Existing Item, and select the filename.

Return to top







Tutorial: Building and running a bit program

In this tutorial, we will show you how to assemble, link, and run a sample bit program. We assume you have already completed our tutorial entitled Building a Bit Assembly Language Program.

Do the following steps, in order:

  1. Right-click here to download the Project64_VSzip file and unzip it into your working directory.
  2. In Visual Studio , select Open Project from the File menu, navigate to the Project64_VS folder, and select the file named sprers.eu.
  3. You are about to add an existing source code file to the project. To do that, right-click on Project in the Solution Explorer window, select Add,  select Existing Item, navigate to the book's Examples\ch03\64 bit" folder, select AddTwoSum_asm, and click the Add button to close the dialog window.
  4. Open the AddTwoSum_asm file for editing by double-clicking its filename in the Solution Explorer window.

You should see the following program in the editor window:

; AddTwoSum_asm - Chapter 3 example. ExitProcess proto .data sum qword 0 .code main proc mov rax,5 add rax,6 mov sum,rax mov ecx,0 call ExitProcess main endp end (Notice that the program's entry point is the main procedure. If you wish to use a different name for your startup procedure in your own programs, you can modify this option by selecting Properties from the Project menu, and then selecting Linker / Advanced / Entry Point.)

Build the Program

Select Build Project from the Build menu. You should see text written to Visual Studio's output window like the following: 1> Build started: Project: Project, Configuration: Debug x64 1> Assembling AddTwoSum_asm 1> Project64_VSvcxproj -> \Project64_VS\x64\Debug\sprers.eu ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== If you do not see these messages, the project has probably not been modified since it was last built. No problem--just select Rebuild Project from the Build menu. You use the same Visual Studio commands to run and debug bit programs as you would for bit programs.

Return to top







Building bit programs (Chapters )

Only Chapters 14 through 17 require you to build bit applications. Except for a few exceptions, which are noted in the book, your bit applications will run under the bit versions of Windows (Windows XP, Windows Vista, Windows 7).

If you're interested in running bit programs under bit Windows, you will need to enable a feature named NTVDM.) Click here to read a web site with instructions on how to do sprers.eur alternative you may wish to explore is to install a virtual machine (using a free program named VirtualBoxfrom Oracle) and install bit Windows on the virtual machine. The book's example programs in Chapters have been successfully tested in bit Windows 7,8, and On the other hand, many programs in Chapters will not run in any Microsoft OS later than Windows 98, because they rely on direct access to hardware and system memory. You cannot directly run bit applications in any bit version of Windows.

If you plan to build bit applications, you need to add two new commands to the Visual Studio Tools menu. To add a command, select External Tools from the Tools menu. The following dialog will appear, although many of the items in your list on the left side will be missing. Download the batch file here (rename the .txt extension to .bat after downloading): make16_vstxt.

 

Step 1: Create the Build bit ASM Command

Click the Add button and fill in the Title, Command, Arguments, and Initial directory fields as shown in the screen snapshot. If you click the buttons with arrows on the right side of the Arguments and Initial directory fields, a convenient list appears. You can select an item without having to worry about spelling:

Click the Apply button to save the command.

 

Step 2: Create the Run bit ASM Command

Click the Add button again, and create a new command named Run bit ASM:

Uncheck the "Close on exit" option and click the OK button to save the command and close the External Tools dialog.

Testing Your new Bit Commands

To test your new bit commands, close any Visual Studio project that happens to be open. Then, select File

Cross-Assembler, Linker, Utilities User's Manual - Tasking

v

CrossAssembler,

Linker, Utilities

User’s Manual

MA−−00−00

Doc. ver.:


A publication of

Altium BV

Documentation Department

Copyright © Altium BV

All rights reserved. Reproduction in whole or part is prohibited

without the written consent of the copyright owner.

TASKING is a brand name of Altium Limited.

The following trademarks are acknowledged:

EMUL is a trademark of NOHAU Corporation.

FLEXlm is a registered trademark of Macrovision Corporation.

Intel and ICE are trademarks of Intel Corporation.

MS−DOS and Windows are registered trademarks of Microsoft Corporation.

SUN is a trademark of Sun Microsystems Inc.

UNIX is a registered trademark of X/Open Company, Ltd.

All other trademarks are property of their respective owners.

Data subject to alteration without notice.

sprers.eu

sprers.eu


The information in this document has been carefully reviewed and is

believed to be accurate and reliable. However, Altium assumes no liabilities

for inaccuracies in this document. Furthermore, the delivery of this

information does not convey to the recipient any license to use or copy the

software or documentation, except as provided in an executed license

agreement covering the software and documentation.

Altium reserves the right to change specifications embodied in this

document without prior notice.


CONTENTS

TABLE OF

CONTENTS


IV

CONTENTS

CONTENTS

Table of Contents


• • • • • • • •

Table of Contents V

OVERVIEW 1−1

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1−3

Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 1−5

Temporary Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1−6

Formatting a File for a Debugger . . . . . . . . . . . . . . . . . . 1−6

File Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1−7

Preprocessing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1−7

Assembler Listing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1−8

Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1−8

Symbolic Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1−9

MACRO PREPROCESSOR 2−1

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−3

mpp51 Invocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−4

Detailed Description of Macro Preprocessor Options . 2−5

INCLUDE Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−23

Creating and Calling Macros . . . . . . . . . . . . . . . . . . . . . . 2−24

Creating Parameterless Macros . . . . . . . . . . . . . . . . . . . . 2−25

Creating Macros with Parameters . . . . . . . . . . . . . . . . . . 2−29

Local Symbols in Macros . . . . . . . . . . . . . . . . . . . . . . . . . 2−31

The Macro Preprocessor’s Built−In Functions . . . . . . . . 2−33

Comment, Escape, Bracket and Group Functions . . . . . 2−34

Comment Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−34

Escape Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−35

Bracket Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−36

Group Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−37

METACHAR Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−38

Numbers and Expressions in mpp51 . . . . . . . . . . . . . . . 2−39

SET Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−40

EVAL Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−41

UNDEF Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−41

Logical Expressions and String Comparisons in mpp51 2−42

Control Flow Functions and Conditional Assembly . . . 2−43

IF Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2−44


VI

CONTENTS

Table of Contents

IFDEF/IFNDEF Function . . . . . . . . . . . . . . . . . . . . . . . . . . 2−46

WHILE Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−47

REPEAT Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−48

EXIT Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−49

String Manipulation Functions . . . . . . . . . . . . . . . . . . . . . 2−50

LEN Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−50

SUBSTR Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−51

MATCH Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−52

Message Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−53

File/Line Info Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 2−54

OPTION Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−54

Console I/O Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−55

Advanced mpp51 Concepts . . . . . . . . . . . . . . . . . . . . . . . 2−56

Macro Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−56

Implied Blank Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . 2−56

Identifier Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−57

Literal Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2−58

Literal vs. Normal Mode . . . . . . . . . . . . . . . . . . . . . . . . . . 2−60

Algorithm for Evaluating Macro Calls . . . . . . . . . . . . . . . 2−62

ASSEMBLER 3−1

Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3−3

Invocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3−3

Asm51 Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3−4

Segments and Memory Allocation . . . . . . . . . . . . . . . . . . 3−9

INPUT SPECIFICATION 4−1

ASSEMBLER CONTROLS 5−1

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5−3

Overview asm51 Controls . . . . . . . . . . . . . . . . . . . . . . . . . 5−4

Description of asm51 Controls . . . . . . . . . . . . . . . . . . . . .

5−6


• • • • • • • •

Table of Contents VII

OPERANDS AND EXPRESSIONS 6−1

Operands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−3

Operands and Addressing Modes . . . . . . . . . . . . . . . . . . 6−4

Indirect Addressing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−4

Immediate Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−4

Data Addressing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−5

Bit Addressing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−5

Code Addressing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−6

Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−7

Number . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−8

Expression String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−8

Symbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−9

Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−10

Addition and Subtraction . . . . . . . . . . . . . . . . . . . . . . . . . 6−11

Sign Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−11

Multiplication and Division . . . . . . . . . . . . . . . . . . . . . . . 6−12

Relational Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−12

Bitwise Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−13

Shift Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−14

Selection Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−14

Segment Type of Expressions . . . . . . . . . . . . . . . . . . . . . 6−15

Predefined Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−16

Include Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6−17

ASSEMBLER DIRECTIVES 7−1

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7−3

Directives Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7−3

Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7−4

Location Counter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7−4

Directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7−4


VIII

CONTENTS

Table of Contents

INSTRUCTION SET 8−1

LINKER 9−1

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−3

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−3

Naming Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−4

Invocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−5

Link51 Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−8

Link51 Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−23

Overview link51 Controls . . . . . . . . . . . . . . . . . . . . . . . . . 9−23

Linking Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−25

Locating Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−25

Listing Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−28

Detailed Description of Controls . . . . . . . . . . . . . . . . . . . 9−28

Link51 Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−73

Bank Switching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−74

Writing Your own Bank Switch Routine . . . . . . . . . . . . . 9−75

Common Area . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−76

Locating Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−76

Function Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−77

Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−77

Linker Special Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−78

Linking with Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−79

Linking OMF51 Objects and Libraries . . . . . . . . . . . . . . . 9−80

Case Sensitivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−80

Object Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−80

Module Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−81

Backward Referencing in Libraries . . . . . . . . . . . . . . . . . 9−81

Linker Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−82

Cross−Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−82

Object Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−82

Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−83

Module Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9−83

Backward Referencing in Libraries . . . . . . . . . . . . . . . . .

9−83


• • • • • • • •

Table of Contents IX

UTILITIES 10−1

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10−3

Archiver: ar51 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10−4

Object Report Writer: dmp51 . . . . . . . . . . . . . . . . . . . . . . 10−7

Flash Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10−9

Formatter: ieee51 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10−11

Formatter: ihex51 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10−12

Formatter: omf51 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10−15

Formatter: srec51 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10−18

Make Utility: mk51 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10−21

sprers.eu FILE FORMAT A−1

1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A−3

File Header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A−4

Section Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A−6

Section Fillers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A−6

Relocation Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A−7

Name Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A−7

Extension Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A−8

MACRO PREPROCESSOR ERROR MESSAGES B−1

1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B−3

2 Warnings (W) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B−3

3 Errors (E) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B−3

4 Fatal Errors (F) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B−6

5 Informational Messages (I) . . . . . . . . . . . . . . . . . . . . . . . . B−8

ASSEMBLER ERROR MESSAGES C−1

1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C−3

2 Fatal Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C−3

3 Assembly Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C−4

4 Assembly Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

C−11


X

CONTENTS

Table of Contents

LINKER ERROR MESSAGES D−1

1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D−3

2 Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D−3

3 Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D−6

4 Fatal Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D−10

INTEL HEX RECORDS E−1

MOTOROLA S−RECORDS F−1

INDEX


• • • • • • • •

Manual Purpose and Structure XI

MANUAL PURPOSE AND STRUCTURE

PURPOSE

This manual is aimed at users of the ASM51 CrossAssembler. It assumes

that you are conversant with programming the .

MANUAL STRUCTURE

Related Publications

Conventions Used In This Manual

Chapters

1. Overview

Contains an introduction to the assembler which is part of the

toolchain.

2. Macro Preprocessor

Describes the action of, and options applicable to, the Macro

Preprocessor.

3. Assembler

Describes the actions and invocation of the ASM51 CrossAssembler.

4. Input Specification

Describes the formats of the possible statements for an assembly

program.

5. Assembler Controls

Describes the syntax and semantics of all assembler controls.

6. Operands and Expressions

Describes the operands and expressions to be used in the assembler

instructions and pseudos (directives).

7. Assembler Directives

Describes the Pseudo instructions to pass information to the assembler

program.

8. Instruction Set

Gives a list of assembly language instruction mnemonics.


XII

MANUAL STRUCTURE

Manual Purpose and Structure

9. Linker

Describes the action of, and options/controls applicable, to the linker

link

Utilities

Contains descriptions of the utilities supplied with the package, which

may be useful during program development.

Appendices

A. sprers.eu File Format

Contains the layout of the output file produced by the package.

B. Macro Preprocessor Error Messages

Gives a list of error messages which can be generated by the macro

preprocessor.

C. Assembler Error Messages

Gives a list of error messages which can be generated by the

assembler.

D. Linker Error Messages

Gives a list of error messages which can be generated by the linker.

E. Intel Hex Records

Contains a description of the Intel Hex format.

F. Motorola S−Records

Contains a description of the Motorola S−records.


• • • • • • • •

Manual Purpose and Structure XIII

RELATED PUBLICATIONS

C Cross−Compiler User’s Manual

[TASKING, MA−−00−00]

CrossView Pro Debugger User’s Manual

[TASKING, MA−−00−00]

CONVENTIONS USED IN THIS MANUAL

The notation used to describe the format of call lines is given below:

{ } Items shown inside curly braces enclose a list from which

you must choose an item.

[ ] Items shown inside square brackets enclose items that are

optional.

dedndave
Member
*****
Posts:



the last 4 paths say "masm" instead of "masm32" ????
of course, that has nothing to do with the include file
masm32 is set up to use a drive other than C:

you might try a simple program that only needs kernel32
something like - INVOKE ExitProcess,0 - and that&#;s it
then, instead of including sprers.eu
include sprers.eu, kerneldll, and includelib kernelllib (without the masm32\include path)

now, take the paths out of the file - seeing as how they are defined in the environment variables, they should not be required
at least you can test to see if it&#;s a problem reading environment variables or a problem related to the way the files are declared
also, you might take a peek inside sprers.eu and see if there is anything odd there
that file declares a number of other include/includelib&#;s

File from the menu and choose the file named sprers.eu from the ch03 folder in the book's example programs. Select Build bit ASM from the Tools menu. The following command window should appear, showing the successful execution of the assembler and linker, followed by a listing of all files related to this program:

Press a key to close the window. Next, you will run the program. Select Run bit ASM from the Tools menu. The following window will appear, although the contents of all registers except EAX will be different:

Press a key to close the window.

You have completed the setup for building and running bit assembly language programs.

Return to top



Syntax highlighting in your source code

When a text editor uses syntax highlighting, language keywords, strings, and other elements appear in different colors. Visual Studio highlights MASM reserved words and strings, as shown in the following example:

This won't happen automatically, but you can create a syntax definition file named sprers.eu that contains MASM keywords. Then when Visual Studio starts, it reads the syntax file and highlights MASM keywords.

If you decide to use Visual Studio's built-in MASM syntax highlighter, here are the required steps to set it up: 1) Download this sprers.eu file (enclosed in a ZIP file) given here to a folder in which you have read/write permissions. Extract it from the zip archive. 2) Close Visual Studio. 3) Copy sprers.eu to the C:\Program Files (x86)\Microsoft Visual Studio\\Community\Common7\IDE folder. Windows will display a confirmation dialog before copying the file. 4) Open Visual Studio, select Options from the Tools menu, select Text Editor, and select File Extension. On the right side of the dialog (shown below), enter asm as the extension, select Microsoft Visual C++ from the Editor list, and click the Add button. Click the OK button to save your changes.

Open your project and display an ASM file. You should see syntax highlighting in the editor. There is a glitch in the highlighting--assembly language comment line starts start with a semicolon, which C++ doesn't recognize. But this is a simple workaround: add an extra // right after the semicolon, like this, which will cause the comments to appear in their usual green color: ;// sprers.eu - adds two bit integers. ;// Chapter 3 example Return to top

Was your program's EXE file blocked by an Antivirus scanner?

Antivirus scanner software has improved greatly in recent years, and so have the number of viruses (one website reports 50, at present). Because of this, your computer's antivirus scanner may report a false positive when you build your program, and refuse to let you run it. There are a few workarounds: (1) You can add your project's bin/debug folder into an exclusion list in your antivirus configuration. This is my preferred approach, and it nearly always works. (2) You can suspend your realtime antivirus scanner software, but this will leave you open to malware for a short time. If you choose this option, be sure to temporarily disconnect your computer from the Internet. Return to top

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Tip: If the Solution Explorer window is not visible, select Solution Explorer from the View menu. Also, if you do not see sprers.eu in the Solution Explorer window, it might be hidden behind another window. To bring it to the front, click the Solution Explorer tab from the tabs shown along the bottom of the window.

shadow_
Guest


Email

Hi, I also ought the book: Assembly Language For Intel-Based Computers. It uses a file called "Irvineinc". It&#;s included on the CD-Rom. The book says that I have to put it in the "include" directory. So I put Irvineinc in the "\masm32\Include\" dir.
But it didnt work so I also put the Irvinelib in the "\masm32\lib\" dir (as I read in these forums  BigGrin). The error was gone but now I get this error when I use the Build All option:

Assembling C:\masm32\sprers.eu
C:\masm32\sprers.eu(10) : fatal error A cannot open file : Irvineinc
_
Assembly error
Press any key to continue


What did I do wrong? (I have full administrative rights in case it matters)
Logged
ramguru
Guest


Email

I think your problem is current directory which is not current I&#;m not able to use batch file directly (from explorer with 2-click or TC window) anymore, instead I have to execute the batch from console (Run->"cmd")

Logged
ramguru
Guest


Email

I assumed you have "sprers.eu" (something like that), but it seems you are using QEditorand menu command "build all".

Logged
shadow_
Guest


Email

Yes I use the QEditor Is there another way to compile and to bypass that error (without using the QEditor if nessecary)?
I am new to ASM. And my book is not telling me how to compile at all

Logged
ramguru
Guest


Email

I&#;m not sure You can use IDE like RadASM or create batch file (like I did) and execute like I wrote

C:\masm32\bin\ml /c /coff /Cp sprers.eu
C:\masm32\bin\rc sprers.eu
C:\masm32\bin\link /subsystem:windows /libpath:C:\masm32\lib sprers.eu sprers.eu
del *.obj *.res
pause

or (not using any resources)

C:\masm32\bin\ml /c /coff /Cp sprers.eu
C:\masm32\bin\link /subsystem:windows /libpath:C:\masm32\lib sprers.eu
del *.obj
pause

Logged
shadow_
Guest


Email

Both (Bat1+Bat2) don&#;t work, they give the following error:

LINK: fatal error LNK cannot open input file "sprers.eu"

It is not creating an *.obj file at all.
Logged
ramguru
Guest


Email

I don&#;t know what you mean both (RadASM or batch, batch1 or batch2). But if I use f.e. sprers.eu I do the fellowing Run->"cmd", cd "where are: *.asm+*.bat", sprers.eu and everything&#;s OK. This error have to be connected with path (incorrect).

Logged
shadow_
Guest


Email

I meant Bat1+Bat2.

I also tried RadASM now, and this one gives this error:

C:\Masm32\Include\irvineinc(3) : fatal error A cannot open file : sprers.eu

So I also copied the file "sprers.eu" to the "inlcude" folder

Now I get another error instead (using RadASM):

C:\Masm32\Bin\sprers.eu /c /coff /Cp /nologo /I"C:\Masm32\Include" "C:\masm32\sprers.eu"
Assembling: C:\masm32\sprers.eu
C:\Masm32\Bin\sprers.eu /SUBSYSTEM:WINDOWS /RELEASE /VERSION /LIBPATH:"C:\Masm32\Lib" "C:\masm32\sprers.eu"
Microsoft (R) Incremental Linker Version
Copyright (C) Microsoft Corp All rights reserved.

sprers.eu : error LNK unresolved external symbol [email protected]
sprers.eu : error LNK unresolved external symbol [email protected]
sprers.eu : fatal error LNK 2 unresolved externals


WriteString is located in Irvine But I placed the Irvinelib file in the lib folder, the Irvineinc file in the include folder, and the Irvineasm in the m32lib folder What else do I have to do?


@ aeroASM:
Thanks, If I compile in MASM32 now I don&#;t get the &#;cannot open Irvine32&#; error anymore but the same error as above (with RadASM) instead now Tongue. It&#;s a step closer.
Logged
shadow_
Guest


Email

This reduces the error to

sprers.eu : error LNK unresolved external symbol [email protected]
sprers.eu : fatal error LNK 1 unresolved external



But if those errors mean a missing library file I thought just included the following in the program

includelib C:\masm32\lib\kernellib
includelib C:\masm32\lib\irvinelib
include C:\masm32\include\irvineinc



I don&#;t know if I did everything correct I am not getting any output But it&#;s compiling now without any errors :). Here is the complete code after the modifications:

; sprers.eu - Windows program to print "Hello, world" using Irvine library
; To asemble/run using MASM
;
;   set include=\masm\include
;   set lib=\masm\lib
;   ml /Cx /c /coff sprers.eu
;   link32 sprers.eu kernellib irvinelib /subsystem:console
;   hello1

includelib C:\masm32\lib\kernellib
includelib C:\masm32\lib\irvinelib
include C:\masm32\include\irvineinc    ; from Irvine CDROM

.stack

.data
greeting byte "Hello, world", 13, 10, 0   ; message to write

.code
main proc
  mov edx, offset greeting
  invoke WriteString   ; sprers.eu: write NUL terminated string pointed to by edx
  exit                 ; sprers.eu: a macro that calls ExitProcess
main endp
end main

Logged

NEWS, EDITORIALS, REFERENCE

February 22, # Software


Introduction to File Manager

Post Archive Icon

File Management is considered to be one of the most central parts of an operating system.

In Command Line Interfaces, such as a Unix/Linux or the AmigaDOS Shell, you are in a current working directory. Commands interact with the file system relative to where you are.

In macOS, the Finder is where you find applications, documents, and other files by navigating the file system.

Windows 95, and up to the present day, follows the Macintosh model. The desktop is a folder where you can put other files and folders. And Windows Explorer is the analog of the Macintosh Finder.

AmigaDOS Shell.Mac OS 7 Finder.Windows 95 Explorer.

Earlier versions of Windows, though, had a Program Manager with icon shortcuts to applications. In addition to this it had a File Manager application for working with files.

Windows 3 Program Manager.Windows 3 File Manager.
Early Windows' Program Manager on the left, and File Manager on the right.

For reasons that relate mostly to limited RAM—but also because of the low screen resolution—C64 OS is a bit more like this early Windows model.

 

Brief Overview of the C64 OS Model

The App Launcher has 5 configurable desktops, but the desktops don't show regular files, they have special desktop aliases to Applications, Utilities and non-COS programs. From the App Launcher, under the Go menu, along with options to move between desktops, there is an option to switch to the File Manager. The App Launcher saves its state and quits, and the File Manager is launched.

From the File Manager you can navigate the devices and their file systems. If you navigate to the Utilities directory and double click a Utility, it opens concurrently with the File Manager. Navigate to the Applications directory and double click an Application to launch it. The File Manager's state is saved automatically.

When you quit an Application, you are returned whence you came. If you came from the File Manager, to the File Manager you will return. If you came from the App Launcher, you return to the App Launcher. When returned to the File Manager, it restores its saved state so your tabs, settings, and places within the tabs are right where you left off.

Along with options to take you to common places in the file system, the File Manager's Go menu has an option to swich you back to the App Launcher. These have keyboard shortcuts so you can easily jump back and forth between App Launcher and File Manager. Thus, they work somewhat like the division of labor in the Program Manager and File Manager of early Windows versions.

App Launcher and File Manager are Homebase Applications. One of them is always configured as your current Homebase. This is why when you quit an Application, you are returned to the Homebase Application whence you came. Both App Launcher and File Manager provide options to Quit to BASIC. The next time you launch into C64 OS, you are returned to the Homebase Application you were last in.

Let's get into some updates about how the C64 OS File Manager works.

File Manager

Now we know a bit about the general model, let's take a look at the user interface of the File Manager.

Labeled Screenshot of the File Manager.

This is obviously an early build, what with the "Hello World!" filling the list of Favorites. Some of these screenshots are already out of date because I'm working on this code pretty much every night. For instance, the column resizer. Instead of being the diagonal lines it's now the same icon as the splitter's grippy, three vertical lines. Additionally, there is another column in the table now, showing the file's locked status.

Changes like this will continue with each new coding session, but this is nonetheless a close approximation of what version 1 will look like.

Menus

I still think the menu bar was an incredible piece of UI invention. This quote from Jack Wellborn in , is spot on so let me repeat it here:

The menu bar has been, and in my opinion remains, the best mechanism for providing familiarity, discoverability, and progressive disclosure in user interfaces on any platform. Jack Wellborn — sprers.eu, March

I agree. Despite many modern attempts, nothing has yet bested the basic old menu bar. In fact over the last few years, iOS has begun reintroducing standardized menus.

In C64 OS the menu bar is part of the system and so it's part of every application. Creating the menus, their hierarchical organization, and assigning keyboard shortcuts was the easiest part of writing the File Manager. It's just a human editable text format.

Meanwhile, a lot of functionality is available in those menus without taking up any extra screen real estate. Which is important on a screen that's only x And lest you think, "Yeah, but, the menu bar itself takes up space." With a simple global keyboard combo the menu bar can be toggled on and off. This sends a message to the application indicating a change of system redraw flags. The application has to support this message, of course, to take advantage of it. When the menu bar (or the status bar) is hidden, the top and bottom offsets of the root toolkit view are adjusted. The whole UI stretches dynamically to fill the available space.

In addition to just saving screen real estate, and rendering super fast so you can get at the options in them without delay, they also host discoverable keyboard shortcuts. If you support the menu action, you support its keyboard shortcut too without any additional coding effort.

Multiple Directories

Many C64 tools and utilities support only a single directory at a time. The more advanced ones usually support two directories. The point of two directories, typically, is to point each one at a different place, select files from one and copy them to the other.

The C64 OS File Manager supports 4 active directories, via 4 tabs. Tabs seem to be in vogue these days, and they also conserve screen real estate. There are menu options, under view, to change tab. Since these have keyboard shortcuts, you can push COMMODORE+1, COMMODORE+2, etc., to toggle between directories quickly.

Dynamic Memory Management

Directories require memory. Each directory entry requires 1/8th of a byte page. After a page is filled, if another entry is read in (by the directory library) it allocates a new page and links the previous page to the new page. Where the new page is allocated from is dynamic. The pages that make up a chain of directory blocks are not necessarily contiguous. In other words, you don't lose memory to fragmentation. Nor, as the application developer, do you have to worry about that. The directory library and the memory KERNAL module handle all that for you.

Still, directory entries / 8 per page = 32 pages of memory. 32 pages * 4 directories = pages. pages * bytes = 32KB or half of the C64's total memory. But of course, the OS code, the screen memory, the memory reserved for Utilities, the toolkit classes, the application's code, etc., eat up their own memory. There is less than 32KB remaining for directories when the File Manager is running.

What happens if you're in tab 1, navigating the file system, and you click into a long directory and as it's loading entries and allocating new pages, you run out of memory? File Manager keeps track of the order that you've accessed the tabs. It will automatically deallocate the least recently accessed tab in order to free up memory. If it runs out of memory again, this process will repeat, potentially freeing all 3 of the unfocused tabs.

Persistence of State

One of the worst offences against productivity is the loss of state. C64 OS provides mechanisms to preserve state wherever possible. Each of the 4 tabs has 4 bodies of information associated with it when it is in focus.

  • Directory Metadata
  • Place File Reference
  • Directory Entry Chain
  • Sort Index

The sort index is the most ephemeral. Each time you switch tabs, the sort index is blown away, and reconstituted from the directory entry chain and directory metadata of the tab that comes into focus.

The directory entry chain is the next most ephemeral. It gets loaded in from disk when it's needed, and remains in memory until the memory is needed for something else. As described above, the directory entry chain of a background tab could get expunged from memory to make room for the tab in focus. And it will be loaded back into memory automatically the next time it's needed.

The place file reference is a C64 OS file reference that defines the absolute location of a tab: device #, partition #, filename (optional), full path from root of partition. The tab's place file reference is serialized and written to the File Manager's application bundle. It's clever about when to do this. It keeps track of whether the File Reference is dirty (whether it's changed), and when you switch tabs a dirty File Reference from the tab you're leaving is written out. When a tab is expunged from memory, its File Reference is expunged as well. When you switch to a tab, if its File Reference isn't in memory, it is read back in and unserialized automatically. This is handy for saving memory when switching tabs, but it also preserves each tab's place whenever you leave the File Manager.

The directory metadata is less than 64 bytes. One page is allocated to hold the metadata for all 4 tabs. A tab also tracks whether its metadata is dirty, and writes out changed metadata to disk when the tabs are changed. Similarly, metadata is restored when you first access a tab. However, once tab metadata is loaded into memory, it doesn't get expunged. Doing so would not free up a full page of memory.

Tab Metadata

Each tab stores and restores the state of its metadata, but what is this metadata? It is a combination of fields that are used by both the File Manager's UI and the Directory Library. Here's the structure of the metadata:

FieldDescriptionSize
td_headDirectory Header17 bytes (16+NUL)
td_didDirectory ID2 bytes
td_freeBlocks Free2 bytes
td_pfreeBlocks Free in PETSCII6 bytes (5+NUL)
td_partPartition Number2 bytes
td_ppartPartition Number in PETSCII4 bytes (3+NUL)
td_fcFile Count2 bytes
td_pfcFile Count in PETSCII5 bytes (4+NUL)
td_pattFilename Pattern Match17 bytes (16+NUL)
td_typeFile/Partition Type Match1 byte
td_sortfSort Field1 byte
td_sortdSort Options1 byte

The Directory Header, Directory ID, Blocks Free and Partition Number are parsed out of the directory listing. These can be displayed in optional user interface elements.

The File Count is computed as the directory entries are loaded in, and can be used to display the number of files in the UI and is also used by the TKTable class to indicate how many rows of data it must render, and thus how many rows the TKScroll must allow for scrolling.

The File Pattern Match and File/Partition Type Match are configurable by the UI and are passed through to the device's DOS to search and limit the directory results.

The Sort Field and Sort Options are used by the Directory Library to build the sort index and also used by the File Manager's UI to indicate the sorted field, sort direction and other options.


The Toolkit Advantage

A great deal of the File Manager's functionality is tied up in external resources, as it should be. The File Manager's own code consists of its main binary that is only the business logic that ties those resources together, and a temporary init binary that loads the external resources in, instantiates and wires together the Toolkit classes, and connects them to their delegates and callbacks.

A whole lot of functionality comes in particular from the Toolkit and its classes. For instance, it was mentioned earlier that the menu and status bars can be toggled on and off, and that the UI stretches dynamically to fill the available space. This could be done manually, but it would be a huge pain. It is made absolutely trivial by the way the Toolkit UI objects naturally anchor, resize, hit detect, and hierarchically pass messages, events, etc.

Let's talk about some advantages the C64 OS Toolkit provides to the UI.

Split View (tksplit)

The root view is the vertical split view. It creates the bar that separates the directory listings on the right from the device and favorites navigation on the left. You can drag the splitter left and right to decide how much screen real estate you want to allocate to each side.

Speaking of persistence of state, the File Manager stores in its general config the position of the splitter. You can drag the splitter all the way to the left to hide the side bar completely, and when you leave and return to the File Manager later, this preference is remembered.

Why would you want to allocate more space to the directories? So that they can show you more columns of data on a single row. We'll return to this. The fact that you can move that splitter around is extremely rare in ordinary C64 programs.

Places View (tkplaces)

TKPlaces is a custom class. It's not memory resident when an application is running that doesn't need it. The File Manager's init binary loads and relocates it to any available spot in memory.

Also, I'm coding everything native, on the C64, using Turbo Macro Pro. TMP is powerful and offers lots of features, but it's not unlimited. The assembler has to work within the memory limitations of the C Carving functionality off the application's main binary and into neatly contained Toolkit classes, whenever this is possible, is a major boon to development.

TKPlaces uses inheritance and composition. Much ink has been spilt on this topic. It subclasses TKView, and does some primitive drawing and event handling. But it embeds a TKScroll and TKList for the favorites in the bottom section.

What's nice about this is that the logic for drawing the current devices, and folding up that section by clicking its section header, and showing the favorites list, etc., is all in a separate source code file. It feels like really good coding practice, but on the C64 with Turbo Macro Pro it's more than just a good practice, it's essential. If I tried to pack all of the functionality of the TKPlaces class directly into the File Manager's main binary, TMP would run out of memory and wouldn't be able to assemble it all.

The way that Toolkit classes plug together and communicate with each other is pretty great.

Tab View (tktabs)

The TKTabs view is a built-in class. It gives you up to 10 tabs. To use it you just append from 2 to 10 child views. They automatically have their metrics handled for you. Each child is set to fill the tab view's area, but are offset from the top edge by one row, to make room for the tabs themselves. This would cause each child view to overlap perfectly with all the others, but the TKTabs marks all but one as hidden. View hiding is a feature of TKView, from which all the others descend.

The TKTabs view has a delegate property, which gets pointed to a structure in the File Manager's main binary. It has routine pointers for Tab Title, will blur, will focus, did blur and did focus. Whenever the tabs need to redraw they call the delegate to fetch the titles for the tabs, so the File Manager has complete dynamic control over what to show on the tabs. And when the user clicks on a tab, the sequence is followed: current tab calls will blur. Will focus is called with an argument for the tab index that will focus. Did blur is called on the current tab before switching tabs. Tab is switched, and did focus is called with the new current tab.

Either the of the will routines can be denied by returning with the carry set, and abort the sequence. But once will blur and will focus are allowed to occur, the sequence can no longer be aborted and the did routines are there only for notification purposes. The implementation of this by the TKTabs class is very short. And if you don't want to support these in the delegate structure, you can just populate it with generic routine pointers like this:

tabsdel .word tabtitle .word clc_rts ;will blur .word clc_rts ;will focus .word raw_rts ;did blur .word raw_rts ;did focus

But what's really great about these is that they give complete control over to the application for what's going on and what's allowed to go on. If you are in an inconsistent state in the current tab that needs to be resolved before leaving this tab, you can implement will blur to check for that state and deny the tab change.

In the File Manager, the user can change tabs whenever they want, but did blur is used to save the metadata and place of that tab if they're dirty. And did focus is used to change the metadata pointer, and then call resort on the directory, or, if the tab's content isn't loaded in, to call reload.

Table Columns View (tktcols)

The table view, while very common in UI's, I had to create new for the File Manager. I was a bit worried about how to implement it, would it take up too much memory, how would it even work? And it turned out to be remarkably easy, given what was already available. It's made of two classes, each a subclass of something that already existed. TKTCols is for the table column headers, and TKTable for the table body.

TKTCols is a subclass of TKScroll. TKScroll subclasses TKView and allows you to append a single scrolling child. In addition to that child, you can turn on the horizontal and/or vertical scrollbars. Each scrollbar is an instance of TKSbar. TKScroll creates and destroys the TKSbars for you, and appends them as children of itself, siblings of the one child view you're allowed to append to the TKScroll. When a horizontal scrollbar is enabled, the main child view has its offset bottom set to 1, to make room for the scrollbar. And when the vertical scrollbar is enabled the main child view has its right offset set to 1, to make room for the vertical scrollbar.

The TKScroll then liaises between the three children. If you move the scrollbar the scrollbar tells its parent, and the parent reads its new value and updates the main child's scroll offset for that axis. If the child view has its scroll offsets changed (due to being interacted with, or because its total content changes size) the TKScroll sends the child's new metrics to the TKSbars and they rerender with new proportions and new offsets. Beautiful. Okay, but that's how TKScroll works. What about TKTCols?

The column headers, somewhat like tabs, have to appear in a strip along the top of a table of rows and columns. The table rows have to scroll up and down, but we want the column headers to stay in the top row. But, we also want the table's columns to scroll left and right, so we need the column headers to scroll left and right too. The column headers can't be inside the scroll region, and on desktop OSes they're generally not. As in the example below, from macOS Big Sur, when you scroll vertically, the content in the green box moves up and down and the top content in the yellow box stays put. When you scroll horizontally, though, the content in the green box moves left and right and the content in the yellow box scrolls left and right synchronously.

Scrolling Table View with Columns in macOS.
Scrolling Table View with Columns in macOS

It doesn't seem like a big deal, but it does require some thought. TKTCols subclasses TKScroll and then, similarly to the TKTabs class, it sets the top offset of both the main child view (the equivalent of what is in the green box above) and the vertical scroll bar down by one. Miraculously, the proportionality of the vertical scrollbar is completely okay with this. It figures out how big and where the scroll nub should be by translating the child view's metrics against its own metrics. In other words, the scrolling child view could be 18 rows high with rows of data, and the vertical scrollbar could be only 15 rows high (say to make room for some extra controls above or below it), and yet the nub inside the scrollbar will still correctly represent and control the scrolling of that child view. That is damn cool.

With the child view and the vertical scrollbar offset down from the top by one row, there is a blank space into which the TKTCols can primitively draw the column headers. The horizontal scrollbar, though, could be fiddled with which will scroll the child view but must also affect the column headers. The role of the TKScroll class is to liaise, and since the TKTCols is a subclass of TKScroll, it gets the messages from the scrollbar about a change in scroll offset. It sets this offset in a special column-headers-left-offset property, marks itself dirty, and then calls its superclass implementation which forwards the message to the child view. Remarkably little code is necessary to do this.

Because the TKTCols is marked dirty, it will be told to redraw. Whenever it redraws, its primitive drawing code that draws out the column headers takes the column-headers-left-offset property into consideration. And boom, the column headers stay synchronized with the table columns below.

Table View (tktable)

TKTable is a subclass of TKList. TKList, I created not long ago for use in the Utilities Utility, which you can read about in detail in the post, Anatomy of a Utility. TKList supports a single scrollable column of content. It gets its content, including row count, column width, string content per row index, as well as row selection status from a series of callbacks.

TKTable inherits most of the behavior of TKList, but extends it to multiple columns. To do this it adds a property that points to a set of column definition structures. When getting the row count (the vertical content size) it continues to use the callback via TKList's implementation. But when getting the content width, rather than using the callback it just sums up the current widths of all the column definitions. Here's what a column definition looks like:

FieldDescriptionSizeValues
tc_nameColumn title2 bytesString pointer
tc_idColumn ID1 byteApplication-defined value
tc_reszResizable flag1 byte$00 = Not Resizable, $01 = Resizable
tc_csizCurrent column size1 byteStarting width. $02 to $FF
tc_mnszMinimum column size1 byteMust be >$01, Must be <=tc_mxsz
tc_mxszMaximum column size1 byteMust be >$01, Must be >=tc_mnsz
tc_algnContent alignment1 byte$00 = Left Aligned, $01 = Right Aligned

This 8 byte structure can be repeated multiple times, contiguously in memory, to define more than one column. The set of all column structures is terminated with two $00 bytes. Any single byte value could be interpreted as the low byte of the tc_name pointer of the next column. But 2 $00 bytes makes the string pointer $, which is not valid, and hence a good terminator.

Now here's what's kind of neat. The TKTCols object and the corresponding TKTable object are both pointed to the same set of column definitions. The column title is not used by the TKTable, but is used by the TKTCols. The alignment is not used by the TKTCols, but is used by TKTable. The TKTCols uses the resizable flag to know whether to draw the column resize grippy. It could compute this by checking to see if min size and max size are the same, but that takes longer to compute, so the resize flag is just to speed up rendering, and make the code simpler.

The TKTCols use the resize flag and the min and max sizes to allow the user to drag the column wider or narrower, within the min and max limits. It adjusts the current size, then marks itself dirty. When the TKTCols and TKTable redraw themselves, they both use the current size to know where to cut off the content.

TKTable uses the same content at index (ctntaidx) callback property that TKList defines, but in its subclassed implementation, instead of calling it once for every row, it calls it once for every row/column combination, passing the row and column index in the Y and X registers respectively.


Remember, the custom classes created for File Manager are usable by any application. The TKList, TKTCols/TKTable, even TKPlaces can be used in other Applications and Utilities. These will all be used in the File Open/Save Utilities.


Common File Management Tasks

There are several common functions of a File Manager:

  • Navigate the file systems (partitions and sub-directories) of multiple storage devices
  • Open an Application or Utility directly
  • Open a file which indirectly opens a corresponding Application or Utility
  • Create a new sub-directory
  • Rename a file or sub-directory
  • Scratch one or more files
  • Recursively scratch one or more sub-directories and files contained therein
  • Copy one or more files, in place
  • Recursively copy one or more sub-directories and their files to a different path, partition or device
  • Recursively move one or more sub-directories… aka, a recursive copy followed by a recursive scratch

Directory Library

The directory library has everything necessary to load any directory (including a partition directory) from a pointer to a standard C64 OS File Reference. Navigating the file system, then, is a matter of manipulating the data in the file reference structure, and telling the directory library to reload.

There is this thread on the uIEC Users Discussion Group (on Google Groups) about supporting the Unix concept of "PWD" or "Present Working Directory" in the SD2IEC firmware. The thread mostly took place in , and I chimed in a year later in , and by that point no one was paying attention anymore. Here's a clip of my comment that is finally relevant here.

I'm interested in how to implement PWD. And Glenn's promal code is the closest I've come to a fully thought out solution. But, it occurs to me that manually figuring out the PWD on the fly is not as important inside an OS as I originally suspected. [As] the user uses the OS to navigate the file system, the OS merely needs to keep track of where the user has gone as he goes there. Gregory Nacu —  — uIEC Users Discussion Group

This idea pre-dated the development of C64 OS File References, which I first wrote about in early Because of the C64's limited memory and processing power, it made (continues to make) a lot of sense that the DOS and File System code are farmed out to the storage devices. But it has some disadvantages too and it's a bad idea to rely too much on a device's internal features.

For example, even if SD2IEC implemented a feature that could easily provide you with the present working directory, it's unlikely that IDE64 would follow suit, and the CMD HD DOS is not going to be changing any time soon. A feature that is available on only one device is a feature with limited appeal. We need solutions that work across every device or most devices.

CMD and SD2IEC devices have a concept of a current partition and a current directory within each partition. This is very useful from the READY prompt. You issue a command to change partitions, and then to change directory, and now every subsequent command you issue applies to that partition and directory. You can scratch a file by name, for instance, and the name is searched for within the current partition and path. But the moment you have a more complex system with different parts that are both running at the same time (even without true multi-tasking), you can no longer rely only on those internal device representations.

For instance, your Application wants to read and write files from within its own application bundle. But you close a Utility and it wants to write its state to a config file in the system's global settings directory. If the Utility changed the current directory, the Application would immediately become lost. GEOS has this problem, Wheels took a very small step to try to alleviate this problem, GoDot has this problem, and, well, frankly I'm not that familiar with many other large multi-file systems on the C All I know is that relying on the device and some DOS feature to try to figure out post hoc where you are in the file system is a nonstarter.

The point of a C64 OS File Reference is that it provides an absolute location on the device, in a standardized memory structure. And it can also be serialized and unserialized for storage and retrieval from disk. The serialized format is also human readable and human writable. The status bar, for instance, serializes the current open file file reference to display the path to the user. Serialization also opens the door for allowing the user to type a file reference into a text field, which could be unserialized into a memory structure.

The serialized structure looks like this:

dev#:part#:filename:path

Partition # is drive # on devices without partitions, such as //, where the partition # would be 0. If the partition # is 0 on a CMD or SD2IEC device, the directory library fetches the partition directory instead. Partition #0 can thus be thought of as a device root.

The filename and path are also allowed to be empty. But if the path is not empty it must be a full directory path in the CMD/IDE64/SD2IEC format. It starts with two slashes (for root of partition), and each sub-directory part is 16 characters or less, plus a trailing slash. Directories on all 3 device types are structured like this, this standard on the C64 was developed by CMD:

//sub directory 1/sub directory 2/sub directory 3/

The following then, are all valid serialized file references:

//documents/ sprers.eu:// somefile: etc.

Path Library

Manipulating a file reference isn't precisely hard, but even trivial things seem to take up a lot of memory when you only have 64K to start with.

Appending a directory name to the end of the path, for example.

  • You need a pointer to the source string.
  • This involves copying a pointer to some temporary zeropage addresses.
  • You have to know how long the current path is of the file reference.
  • This involves setting up a pointer, and calling strlen in the C64 OS KERNAL.
  • You need to copy the bytes from the first string to the path pointer after adding the strlen to the pointer.
  • You have to do that because the can only indirectly index using the Y register. The source string's index will run from 0 to 15, but the destination will run from the length of the path string to the length of the path string plus 0 to It's much easier and faster to add the string length to the destination pointer and then use the same Y index on both the source and destination.
  • You have to manually add the trailing slash.
  • And Lastly, manually add the new null terminator.

Again, it's not exactly hard, but you really don't want to have this amount of code strewn here, there and everywhere, every time you want to append a path.

The path library makes the common tasks of manipulating file references easy. To go up a directory, you have to remove the final path part. But doing so manually, like appending a path part, is annoyingly verbose. The path library makes it one call. The following routines are provided by the path library:

RoutineDescription
pathaddAppend subdirectory name plus a trailing slash to path.
pathupGo up one subdirectory. Remove one path part.
partrootGo to root directory of partition.
devrootGo to device root, partition directory if device has partitions.
gopathPoint the file reference to one of several defined places.
frclipTransfer file reference to/from the clipboard.

Of these, gopath is the most interesting, in my opinion. The idea here is to allow a set of single character codes to represent standard places either system- or user-defined. For example: The applications and utilities directories are system-defined, but relative to the installed location of the system directory. Codes such as "a", "u", "s" passed into this routine would configure the file reference for those places.

Additionally, codes for standard user directories such as:

CodePlace
dDocuments
gGames
mMusic
pPictures

Each of these could fetch and unserialize a file reference from the system settings directory. This would allow the user to custom define these places.

The path library is in progress and is still evolving. I'm considering using this library to also automatically manage favorites and recents. Favorites being a customizable set of places you want quick access to. Recents being the files recently opened or saved, on a per application basis. The File Open and File Save Utilities will embed the path library to help them navigate the file system, so it seems easy to implement and an obvious role for the path library to manage favorites and recents too.

Libraries, Libraries, and More Libraries

I'm writing this post while working on this code at the same time. And I've realized that the set of libraries is growing. Therefore, I've taken a slight detour to standardize the libraries and add proper support for loading and unloading libraries. There is a loaded library table to find their relocated base address. They use reference counting to know how many things are depending on them, so a library loaded once can be shared by the system, the application and a utility.

This is kind of a big side discussion, so I'm going to make it the topic of the next post.

Utilities for File Management Tasks

Simple file management tasks that apply only to one or more file in the current directory will be built directly in the File Manager.

For example, select a single file, select scratch from the menus, and that file will be scratched. Or, pick a single file, select copy from the menus, and that file will be copied, in place, and assigned a new name automatically based on the original's name. Select create directory from the menus, and a new subdirectory will be created with a default name.

Each of these consists of a single command that can be sent to the device's DOS to perform the work. Commands like these, respectively:

s:filename c:filename 2=filename md:new directory

But what happens when you want to do something more complicated? Like, what happens when you want to scratch an entire directory tree? There are several problems that need to be dealt with.

  1. It's dangerous. The user should have an opportunity to cancel or confirm.
  2. It's recursive. It requires a fair amount of code to perform the job.
  3. It's long running. The user should see an indication of progress.
  4. It's useful, so this feature should be reusable by other applications.

Scratching one file or even multiple selected files is a bit dangerous. You don't want to do it by mistake. To mitigate the risk of doing this accidentally we can: separate the scratch menu option from the others, and assign it a keyboard shortcut with a multi-modifier key combination. If you still manage scratch a file accidentally, you can use an unscratch program to recover it.

Scratching a directory, on the other hand, is much more dangerous. It's going to kick off a process of scratching an unspecified number of files and subdirectories in total. Unscratching might still be possible, but it would be a serious amount of work. Some sort of dialog box that pops up, presents to the user a summary of the dangerous job about to be done, and allows them to cancel or proceed, is almost essential. C64 OS doesn't have a window manager though, and producing and managing dialog boxes is not built in.

Performing the recursive job is nowhere near as trivial as issuing one or more single scratch commands. Writing this code into the File Manager's main binary leads to several problems on its own:

  • The code would take up memory space that could be used for holding directory data.
  • The code would have to be loaded into memory at the time the File Manager is launched, increasing load time.
  • When programming natively, space in a source code file is limited. The main source code file would contain even more code and labels.

After all of this, the user may want to recursively scratch a directory only once in a while. Given that there is no easy way to recursively scratch from the READY. prompt, this is clearly not something a C64 user does very often. It seems almost criminal to load it all into memory every time the user pops into the File Manager to do something.

And lastly, the job itself is long running. File system access is not known to be super fast on the C We don't want to just start the job and have the UI essentially lock up and give no feedback until it's complete. Rather, it would be great to show the user that something is happening, and better still to show them some actual progress details or current status. Doing this extra stuff would be even more onerous on the primary binary.

The Obvious Solution: A Utility

The answer is obvious: a Utility. One Utility each for these recursive jobs, one for recursive scratch, one for recursive copy, and one for recursive move. The jobs of move and copy are more work than scratch, because the move or copy could cross devices. A file can be copied from one place to another within one device by sending it a single DOS command. But to copy a file between devices means loading it into the computer from one device and sending it back out to another. There is an opportunity here to use an REU to facilitate and accelerate the copying, but that's more code and more complication.

Offloading this functionality into a Utility addresses every one of the problems.

A Utility:

  • Provides a dialog-like window for a message, cancel and proceed buttons.
  • Provides a user interface surface upon which to show progress.
  • Has separate source code files from the Application's main binary.
  • Only gets loaded in when the user wants to perform that job.
  • Gets loaded into Utility memory space, which isn't shared with main memory (because of KERNAL ROM contention), so it doesn't deprive the application of memory used for directory data.

And… a Utility can easily be invoked by any application, not just the File Manager. It's a wonderful solution.

Passing Job Metadata to a Utility

A Utility can be opened manually, however, not only by being invoked from another application. Somehow these File Management Utilities have to know that they were opened without any information about a job to perform and present a reasonable message to that effect. Something like:

Mockup 'Copy' Utility with message if opened manually.
"This utility is run by applications to recursively copy files."

And then present no other buttons, besides the standard close button. If the user opens it manually that's all they'll see, but at least they know what it's for.

Whenever a Utility is opened, it may check the Open Utility Message Command (opnutilmcmd.) When an application invokes a Utility for a specific purpose it uses this memory location to pass a single command byte to the Utility upon opening. Some commands are implicitly associated with 1 or 2 additional message data bytes, (opnutilmdlo and opnutilmdhi.) For some messages, 2 bytes are sufficient for additional information. If a command needs more than 2 bytes it can define them as a pointer to a structure. The command mc_mptr is a generic message that means, "the message data bytes contain a pointer."

Therefore, each of this Utilities needs to confirm first that the message command is mc_mptr. And after that, each utility will analyze the structure pointed at to confirm that it contains a valid job. Here are the job structures I think these are going to use:

Move

FieldDescriptionSizeNotes
fo_idFile Operation ID4 bytes"move"
fo_sfrefSource File Reference1 byteMemory page #
fo_rdirRoot Directory1 byteMemory page #
fo_dfrefDestination File Reference1 byteMemory page #
fo_validValidation Callback2 bytes RegPtr → directory entry
C ← SET, skip this entry
C ← CLR, move this entry

Copy

FieldDescriptionSizeNotes
fo_idFile Operation ID4 bytes"copy"
fo_sfrefSource File Reference1 byteMemory page #
fo_rdirRoot Directory1 byteMemory page #
fo_dfrefDestination File Reference1 byteMemory page #
fo_validValidation Callback2 bytes RegPtr → directory entry
C ← SET, skip this entry
C ← CLR, copy this entry

Scratch

FieldDescriptionSizeNotes
fo_idFile Operation ID4 bytes"scra"
fo_sfrefSource File Reference1 byteMemory page #
fo_rdirRoot Directory1 byteMemory page #
 undefined1 bytePlaceholder for move/copy
fo_validValidation Callback2 bytes RegPtr → directory entry
C ← SET, skip this entry
C ← CLR, scratch this entry

For instance, the Move Utility can check the first 4 bytes of the structure to which it is passed a pointer. If the are not "move", then it can present its standard message as though no job had been passed at all. This is what will happen if that Utility is opened manually.

Once it confirms that the structure has a file operation ID of "move" it can safely proceed to interpret the rest of the bytes to know what to do. All File References in C64 OS are page-aligned. So the source and destination file references only need the page number to be passed in. Additionally, the blocks for directory entries that are chained together by the directory library are also page-aligned. Each directory entry contains a file status byte with bits for: Locked, Hidden1, Open, and Selected.

The chain of blocks containing the directory entries contain only directory entries. Filenames, sizes, file types, status flags, timestamp information, but not where these files actually come from. The Utility can read through the directory chain searching for entries whose status indicates they are selected. It can then perform the operation on that file by reference to the source and destination file references.

A scratch doesn't need a destination file reference, but the byte offset is left vacant so the offset of the other fields is the same for all of the job structures.

Validated Recursive File Operation

A utility that blindly copies everything, or blindly moves or scratches everything, is useful but is bound to bump up against limitations if it gets used by other applications besides the File Manager. To make these Utilities useful in a wider context, the job structures have a validation callback.

On every directory entry, be it a file or subdirectory, the validation callback will be called with a pointer to the directory entry being processed. The application that supplies the validation callback routine already has pointers to the source and destination file references. The validation routine can do whatever it wants with this combination of information to determine whether the entry should be processed or skipped.

It could, say, skip SEQ files found inside application bundles, if the filename ends in ".i". Just to pick a zany example of the flexibility it makes possible. If the validation returns with the carry set, the Utility will skip that entry. If it's copying, it will not copy that file, or if it's a directory it will not create that directory at the destination, nor recurse into that directory at the source. If it's scratching, it will not scratch that file, or will not remove that directory, or recurse into that directory, and so on.

Many routines in C64 OS use the carry to indicate success or failure, or whether to propagate or stop propagation of an event, or whether a message was handled or not, and so on. There are system constants that point reliably to CLC followed by RTS, and SEC followed by RTS. These are defined, unimaginatively, as CLC_RTS and SEC_RTS. You must provide a validation callback, but if you just want to validate everything, then assign CLC_RTS as the callback. It will be called but it will always return immediately with the carry clear.


Let's take recursive scratching just for an example of how this would work.

It gets a source file reference and a pointer to the start of a directory chain. On its first pass, it's looking for selected entries. On subsequent passes (nested directories) it will apply to all items in the directory. First it initializes the device from the source file reference. This sets the device's internal current directory and partition to the source location. It begins looping through the directory entries looking for those that are selected, and automatically skipping those that are not selected.

It calls the validation callback with a pointer to a directory entry. If the carry comes back set, it skips that entry, and loops to look for the next. If the carry comes back clear, it checks the type of file. If it's not a directory, it sends a DOS scratch command on that filename. The scratch occurs relative the current partition and path that the device has been initialized to. Note that this is an advantage of a non-multi-tasking OS. This whole process is atomic, nothing will change the current directory on the device out from under us.

If the file is locked, and the device (correctly) refuses to scratch the file, that's not an error and is ignored.

If the file type is directory, here's how it recurses: It uses the path library to pathadd the name of the current directory entry to the file reference. Recall that the file reference lives in the Application's memory space, to which we merely have a pointer. It uses the directory library to load a directory from the file reference. This causes the device to be initialized again with the same file reference but a different path, which causes it to change its current directory. Then it recurses by calling the same directory processing loop again. To recurse properly, we'd backup the directory pointer first.

The only difference on this nested pass is that it no longer cares whether the directory entries are selected or not. It's easy to handle this, with a simple variable that tracks nesting depth. It starts at zero. Just before the recusion call the nest depth gets incremented, and just after the recursive call returns the nest depth gets decremented. During the loop if nest depth is not zero it skips the selected status check.

Finally, when we reach the end of looping through a directory's entries, if the nest depth is not zero, we use the directory library to free the directory. And we use the path library to call pathup on the file reference, and then reinitialize the device so its current directory returns to where it was.

After returning from a recursive call it issues a DOS command to remove the directory just processed. If there were any locked files below this directory, then the directory will still contain items and the remove directory command will fail. Just like failing to scratch a locked file, this is not an error, and will be ignored.

When we reach the end of a directory, and the nest depth is zero, we do not want to free that directory because it is owned by the application that assembled the job. Also note that, along the way, the file reference owned by the application has its path changed. But by the time the recursion completes, the file reference is restored to its original state.

Final Thoughts

So that's what I'm working on for the File Manager. But, as I said, I got slightly detoured to implement shared libraries, which will be the topic of the next post.

You might have noticed why shared libraries are suddenly important. The File Manager application loads in the directory library, and the path library, and some other new libraries. But then, to perform some task such as recursively copying a directory, it invokes a Copy Utility. But that Utility needs to make use of the directory library and the path library too! It could load a copy of them, but that's a huge waste of memory on a machine where memory is at a premium.

We'll talk about shared libraries next time.

Hope you enjoyed this. Things are really heating up now. I'm starting to develop things that are not typically seen on the C It's exciting.

Do you like what you see?

You've just read one of my high-quality, long-form, weblog posts, for free! First, thank you for your interest, it makes producing this content feel worthwhile. I love to hear your input and feedback in the forums below. And I do my best to answer every question.

I'm creating C64 OS and documenting my progress along the way, to give something to you and contribute to the Commodore community. Please consider purchasing one of the items I am currently offering or making a small donation, to help me continue to bring you updates, in-depth technical discussions and programming reference. Your generous support is greatly appreciated.

Greg Naçu — sprers.eu

Option 1) Purchase one of the following featured items.

High Quality Commodore Logo Patch

1 Commodore Logo Patch: $5 USD
Singles OUT OF STOCK!
3 Commodore Logo Patches: $12 USD
3-Packs OUT OF STOCK!
+ $ USD Shipping/Handling

Option 2) Make a donation, as little as a cup of coffee.

Option 3) Try Digital Ocean, and use this referral link to help offset my costs.

sprers.eu is hosted on a Digital Ocean droplet.

Digital Ocean is a cloud hosting platform, built for developers. They make it simple to get started. They have intuitive administrative tools and reasonable prices. And they can scale as your needs grow.

If you sign up with this referral link, you'll get a $ credit, and after you've spent $25, I'll get $ If you are looking for a cloud platform to host your website or web app, this is win-win.


Sign up for Digital Ocean with this refereral link.
Save money and help sprers.eu at the same time.

Want to support my hard work? Here's how!

The Book's Example Programs At the top of this document, we explained how to download the file named sprers.eu and extract it into the C:\Irvine folder. Unless you have some objection to using that location, do not alter the path. (Note to lab administrators: you can designate c:\Irvine directory as read-only.).

The folllowing files should appear in the c:\Irvine directory:

FilenameDescription
basm, basm Blank templates for bit and bit assembly language source files
sprers.eu Include file for writing Windows applications
Irvineinc Include file used with the Irvine16 link library (bit applications)
Irvinelib bit link function library used with this book
Irvineinc Include file used with the Irvine32 link library (bit applications)
Irvinelib Irvine's bit link library
Kernellib bit link library for Windows API
Linkexebit Microsoft linker
sprers.eu Irvine's macro include file (see Chapter 10)
make16_vsbatVisual Studio batch file for building bit applications
sprers.eu Small-sized include file containing MS-Windows definitions, used by Irvineinc
UserlibMS-Windows basic I/O link library
sprers.eu Keyboard code definitions file, used by Irvineinc

A subdirectory named Examples will contain all the example programs shown in the book, source code for the book's, and bit libraries, and two sample projects for earlier versions of Visual Studio.

Setting up Visual Studio

Select the C++ Configuration

Visual Studio supports multiple programming languages and application types. The C++ programming language configuration most closely matches that of assembly language programming, so we suggest the following steps:
  1. Select Tools >> Import and Export Settings from the menu
  2. Select the "Import selected environment settings" asm1 fatal error a1000 cannot open file button
  3. Select the "No, just import" radio button
  4. Select "Visual C++" from the Default Settings List and click the Next button
  5. Click the Finish button, then click the Close button
  6. Notice the tabs on the left and right sides of the Visual Studio workspace. Close the Server Explorer, Toolbox, and Properties tabs. (Optionally, you can use the mouse to drag the Solution Explorer tool window to the right side of the workspace.) If you should accidentally close the Solution Explorer window in the future, you can bring it back: select View from the menu, and locate Solution Explorer in the list of views.

Optional Step: Set the tab indent size

Start Visual Studio and select Options from the Tools menu. Select and expand the Text Editor item, select All Languages, and select Tabs. Optionally, you may want to select the Insert spaces radio button:

I prefer to set the Tab Size and Indent Size values to 5.

Tutorial: Building and running a bit program

Now you're ready to open and build your first bit project.

Opening a Project

Visual Studio requires assembly language source files to belong to a project, which is a kind of container. A project holds configuration information such as the locations of the assembler, linker, and required libraries. A project has its own folder, and it holds the names and locations of all files belonging to it.

If you have not already done so,Right-click here to download a zip file containing an up-to-date Visual Studio project that has been configured for assembly language. After downloading this file, un-zip it into your working directory. It contains a sample asm test file named sprers.eu

Follow these steps:

  1. Start Visual Studio.
  2. Open our sample Visual Studio project file by selecting File/Open/Project from the Visual Studio menu.
  3. Navigate to your working folder where you unzipped our project file, and select the file named sprers.eu.
  4. Once the project has been opened, you will see the project name in Visual Studio's Solution Explorer window. You should also see an assembly language source file in the project named sprers.eu Double-click the file name to open it in the editor.

You should see the following program in the editor window:

; sprers.eu - adds two bit integers. ; Chapter 3 example .model flat,stdcall .stack ExitProcess proto,dwExitCode:dword .code main proc mov eax,5 add eax,6 invoke ExitProcess,0 main endp end main
In the future, you can use this asm1 fatal error a1000 cannot open file as a starting point to create new programs by copying it and renaming the copy in the Solution Explorer window.

Adding a File to a Project: If you need to add an .asm file to an open project, do the following: (1) Right-click the project name in the Visual Studio window, select Add, select Existing Item. (2) In the Add Existing Item dialog window, browse to the location of the file you want to add, select the filename, and click the Add button to close the dialog window.

Build the Program

Now you will build (assemble and link) the sample program. Select Build Project from the Build menu. In the Output window for Visual Studio at the bottom of the screen, you should see messages similar to the following, indicating the build progress:

1> Build started: Project: Project, Configuration: Debug Win32 1>Assembling sprers.eu 1>sprers.euj -> \Project32_VS\Debug\sprers.eu ========== Build: 1 succeeded, 0 failed, 0 skipped ==========

If you do not see these messages, the project has asm1 fatal error a1000 cannot open file not been modified since it was last built. No problem--just select Rebuild Project from the Build menu.

Run the Program in Debug Mode

The easiest way to run your first program is to use the debugger. First, you must set a breakpoint. When you set a breakpoint in a program, you can use the debugger to execute the program a full speed (more or less) until it reaches the breakpoint. At that point, the debugger drops into single-step mode. Here's how to do it:

  1. Make sure the ASM source code file is open in the editor window.
  2. Click the mouse along the border to the left of the mov eax,5 statement. A large red dot should appear in the margin.
  3. Select Start Debugging from the Debug menu. The program should run and pause on the line with the breakpoint. (Optionally, you can close the Diagnostic Tools, Autos, and Call Stack windows.)
  4. Press the F10 key (called Step Over) to execute the current statement. Continue pressing F10 until the program is about to execute the invoke statement.
  5. A small black window icon should appear on either your Windows desktop or status bar. The window should be blank because this program does not display any output.
  6. Press F10 one more time to end the program.

You can remove a breakpoint by clicking its dot with the mouse. Take a few minutes to experiment with the Debug menu commands. Set more breakpoints and run the program again.

Here's what your program will look like when paused at the breakpoint:

Running a program from the Command Prompt: When you assembled and linked the project, a file named sprers.eu was created inside the project's \Debug folder. This file executes when you run the project. You can execute any EXE by double-clicking its name inside Windows Explorer, but it will often just flash on the screen and disappear. That is because Windows Explorer does not pause the display before closing the command window. On the other hand, you can open a Command prompt window, move to the Debug directory, and run sprers.eu by typing "Project" (without the quotes). You will need to do some reading on Windows shell commands if you plan to use the command line.

To remove a source file from the Visual Studio window, right-click its filename and select Remove. The file will not be deleted from the file system. On the other hand, if you want to delete the file, select it and press the Del key.

Registers

Soon you will want to display CPU registers when debugging your programs. Here's how to make them visible: First, under the Tools >> Options menu, asm1 fatal error a1000 cannot open file, select Debbuging in the left panel, and select Enable address-level debugging. Next, set a breakpoint in your source code on an executable statement, run your program in Debug mode, select Windows from the Debug menu, and then select Registers from the drop-down list.

If you do not see the Registers command in the Debug >> Windows drop-down menu (which seems to be the case for the VS Community Edition, there is a way to add a Registers command button to your Debug toolbar. Here's how to do it:
  1. While not debugging, select Customize from the Tools menu.
  2. Click the Commands tab, select the Toolbar tab, and select Debug from the list of toolbars.
  3. Click the Add Command button. In the Categories list, select Debug.
  4. Select Registers from the list of commands, click the OK button to close the dialog window.
  5. Click the Close button to close the Customize dialog. You should now see a new button on the Debug toolbar that looks like a small rectangle containing "0X" when you begin debugging a program.
The Registers window may appear docked to the top of the workspace, but you may find it helpful to float the window on top of your workspace. Just grab the window header with the mouse and pull it to the center area. You will also want to display the CPU flags. To do that, right click inside the Registers window and check the word Flags from the popup menu. You can interrupt a debugging session at any time by selecting Stop Debugging from the Debug menu. You can do the same by fatal error 142 oki the maroon-colored square button on the toolbar. To remove a breakpoint from a program, click its red dot to make it disappear. A reminder, you might want to review our tutorial: Using the Visual Studio debugger

Building and Running Other Programs

Suppose you want to run another example program, or possibly create your own program. You can remove the existing assembly language file from the Solution Explorer window and insert a new .asm file into the project.

  • To remove a program from a project without deleting the file, right-click its name in the Solution Explorer window. In the context menu, select Remove. If you change your mind and decide to add it back to the project, right-click in the same window, select Add, select Existing item, and select the file you want to add.

Adding a File to a Project

An easy way to add an assembly language source file to an open project is to drag its filename with the mouse from a Windows Explorer window onto the name of your project in the Solution Explorer window. The physical file will not be copied--the project only holds a reference to the file's location. Try this now:

  1. Remove the sprers.eu file from your project.
  2. Add a reference to the file Examples\ch03\sprers.eu to the project.
  3. Build and run the project.

Copying a Source File

One way asm1 fatal error a1000 cannot open file make a copy of an existing source code file is to use Windows Explorer to copy the file into your project directory. Then, right-click the project name in Solution Explorer, select Add, select Existing Item, and select the filename.

Return to top







Tutorial: Building and running a bit program

In this tutorial, we will show you how to assemble, link, and run a sample bit program. We assume you have already completed our tutorial entitled Building a Bit Assembly Language Program.

Do the following steps, in order:

  1. Right-click here to download the Project64_VSzip file and unzip it into your working directory.
  2. In Visual Studioselect Open Project from the File menu, navigate to the Project64_VS folder, and select the file named sprers.eu.
  3. You are about to add an existing source code file to the project. To do that, right-click on Project in the Solution Explorer window, select Add,  select Existing Item, navigate to the book's Examples\ch03\64 bit" folder, select AddTwoSum_asm, and click the Add button to close the dialog window.
  4. Open the AddTwoSum_asm file for editing by double-clicking its filename in the Solution Explorer window.

You should see the following program in the editor window:

; AddTwoSum_asm - Chapter 3 example, asm1 fatal error a1000 cannot open file. Asm1 fatal error a1000 cannot open file proto .data sum qword 0 .code main proc mov rax,5 add rax,6 mov sum,rax mov ecx,0 call ExitProcess main endp end (Notice that the program's entry point is the main procedure. If you wish to use a different name for your startup procedure in your own programs, you can modify this option by selecting Properties from the Project menu, and then selecting Linker / Advanced / Entry Point.)

Build the Program

Select Build Project from the Build menu. You should see text written to Visual Studio's output window like the following: 1> Build started: Project: Project, Configuration: Debug x64 1> Assembling AddTwoSum_asm 1> Project64_VSvcxproj -> \Project64_VS\x64\Debug\sprers.eu ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== If you do not see these messages, the project has probably not been modified since it was last built. No problem--just select Rebuild Project from the Build menu. You use the same Visual Studio commands to run and debug bit programs as you would for bit programs.

Return to top







Building bit programs (Chapters )

Only Chapters 14 through 17 require you to build bit applications. Except for a few exceptions, which are noted in the book, your bit applications will run under the bit versions of Windows (Windows XP, Windows Vista, Windows 7).

If you're interested in running bit programs under bit Windows, you will need to enable a feature named NTVDM.) Click here to read a web site with instructions on how to do sprers.eur alternative you may wish to explore is to install a virtual machine (using a free program named VirtualBoxfrom Oracle) and install bit Windows on the virtual machine. The book's example programs in Chapters have been successfully tested in bit Windows 7,8, and On the other hand, many programs in Chapters will not run in any Microsoft OS later than Windows 98, because they rely on direct access to hardware and system memory. You cannot directly run bit applications in any bit version of Windows.

If you plan to build bit applications, you need to add two new commands to the Visual Studio Tools menu. To add a command, select External Tools from the Tools menu. The following dialog will appear, although many of the items in your list on the left side will be missing. Download the batch file here (rename the .txt extension to .bat after downloading): make16_vstxt.

 

Step 1: Create the Build bit ASM Command

Click the Add button and fill in the Title, asm1 fatal error a1000 cannot open file, Command, Arguments, and Initial directory fields as shown in the screen snapshot. If you click the buttons with arrows on the right side of the Arguments and Initial directory fields, a convenient list appears. You can select an item without having to worry about spelling:

Click the Apply button to save the command.

 

Step 2: Create the Run bit ASM Command

Click the Add button again, and create a new command named Run bit ASM:

Uncheck the "Close on exit" option and click the OK button to save the command and close the External Tools dialog.

Testing Your new Bit Commands

To test your new bit commands, asm1 fatal error a1000 cannot open file, close any Visual Studio project that happens to be open. Then, select File The vertical bar separates items in a list. It can be read as

OR.

italics Items shown in italic letters mean that you have to

substitute the item. If italic items are inside square

brackets, asm1 fatal error a1000 cannot open file, they are optional. For example:

filename

means: type the name of your file in scalar deleting destructor link error of the word

filename.

An ellipsis indicates that you can repeat the preceding

item zero or more times.

screen asm1 fatal error a1000 cannot open file Represents input examples and screen output examples.

bold font Represents a command name, an option or a complete

command line which you can enter.

For example

command [option] filename

This line could be written in plain English as: execute the command

command with the optional options option and with the file filename.


XIV

MANUAL STRUCTURE

Illustrations

The following illustrations are used in this manual:

This is a note. It gives you extra information.

This is a warning. Read the information carefully.

Manual Purpose and Structure

This illustration indicates actions you can perform with the mouse.

This illustration indicates keyboard input.

This illustration can be read as �See also". It contains a reference to

another command, option or section.


CHAPTER

1

OVERVIEW


1−2

OVERVIEW

CHAPTER

1

Chapter 1


• • • • • • • •

Overview 1−3

INTRODUCTION

The TASKING toolchain can produce load files for running on the

entire family.

The assembler asm51 accepts programs written according to the Intel

assembly language specification for the . A formatter enables the load

file to be formatted into IEEE format ready for loading into a debugger.

Another formatter enables the load file to be formatted into Intel Hex

format ready for loading into an (E)PROM programmer, or into an

emulator using a terminal emulation program.

The product contains the following programs:

mpp51 A string−macro preprocessor allowing macro substitution, file

inclusion asm1 fatal error a1000 cannot open file conditional assembly, according to the Macro

Preprocessor Language described in the chapter Macro

Preprocessor.

asm51 The assembler program which produces an object file from a

given assembly file.

link51 An overlaying linker which combines several object files and

object libraries into one target load file.

xfw51 The CrossView Pro Debugger.

ar51 Librarian facility, which can be used to create and maintain

object libraries.

dmp51 A utility program to report the contents of an object file.

ieee51 A program which formats files generated by the assembler to

the IEEE format (used by a debugger).

ihex51 A program which formats files generated by the linker to

Intel Hex Format Format.

omf51 A formatter to translate TCP sprers.eu formatted files into

absolute OMF51 format.

srec51 A program which formats files generated by the linker to

Motorola S Format.

The assembler is part of a toolchain that provides an environment for

modular program development and debugging. The following figure


1−4

OVERVIEW

Chapter 1

explains the relationship between the different parts of the TASKING

toolchain:

ar51

Librarian

object library

.lib

Linker command file

OMF51 relocatable

object file

C source file

.c

cc51

Compiler

assembly file

.src

asm51

Assembler

relocatable object

module .obj

link51

Linker/Locator

absolute object

module sprers.eu

assembly source file

.asm

mpp51

Macro Preprocessor

List file .lst

C−51 library

OMF51 library

List file

ihex51 ieee51

omf51

Formatter Formatter

Formatter

.l51

Intel Hex−records IEEE− load module Absolute OMF51 file

Figure 1−1: development flow

xfw51

CrossView Pro

execution

Debugger

environment


• • • • • • • •

Overview 1−5

ENVIRONMENT VARIABLES

This section contains an overview of the environment variables used by

the toolchain.

Environment

Description

Variable

ASMDIR With this variable you specify one or more additional

directories in which the macro preprocessor mpp51

looks for include files.

CC51INC With this variable you specify one or more additional

directories in which the C compiler cc51 looks for

include files. The compiler first looks in these

directories, then always looks in the default

include directory relative to the installation

directory.

CC51LIB With this variable you specify one or more additional

directories in which the linker link51 looks for library

files.

LM_LICENSE_FILE With this variable you specify the location of the

license data file. You only need to specify this

variable if the license file is not on its default location

(c:\flexlm for Windows,

/usr/local/flexlm/licenses for UNIX).

PATH With this variable you specify the directory in which

the executables reside. This allows you to call the

executables when you are not in the bin directory.

Usually your system already uses the PATH variable

for other purposes. To keep these settings, you

need to add (rather than replace) the path. Use a

semicolon (;) to separate pathnames.

TASKING_LIC_WAIT Asm1 fatal error a1000 cannot open file you set this variable, the tool will wait for a license

to become available, if all licenses are taken. If you

have not set this variable, the tool aborts with an

error message. (Only useful with floating licenses)

TMPDIR Asm1 fatal error a1000 cannot open file this variable you specify the location where

programs can create temporary files. Usually your

system already uses this variable. In this case you

do not need to change it.

Table 1−1: Environment variables


1−6

OVERVIEW

TEMPORARY FILES

Chapter 1

The assembler, linker, locator and archiver may create temporary files. By

default these files will be created in the current directory. If you want the

tools to create temporary files in another directory you can enforce this by

setting the environment variable TMPDIR.

PC:

UNIX:

set TMPDIR=c:\tmp

Bourne shell, Korn shell:

TMPDIR=\tmp ; export TMPDIR

csh:

setenv TMPDIR /tmp

Note that if you create your temporary files on a directory which is

accessible via the network for other users as well, conflicts in the names

chosen for the temporary files may arise. It is safer to create temporary

files in a directory that is solely accessible to yourself. Of course this does

not apply if you run the tools with several users on a multi−user system,

such as UNIX. Conflicts may arise if two different computer systems use

the same network directory for tools to create their temporary files.

FORMATTING A FILE FOR A DEBUGGER

Before a file generated by the linker can be loaded into a debugger it must

be in a suitable format. This format is known as IEEE− The

CrossAssembler package includes a utility program ieee51 which can

format output files into this IEEE format.

The simplest call of this program follows; for a full description of ieee51

see the chapter Utilities.

ieee51 opprog3 sprers.eu

The output file sprers.eu can now be loaded into a debugger.


• • • • • • • •

Overview 1−7

FILE EXTENSIONS

The assembler accepts files with any extension (or even no delphi runtime error 5, asm1 fatal error a1000 cannot open file adding the extension .src to assembler source files, you can

distinguish them easily.

Another reason for using the .src extension is that the assembler uses

this extension by default if it is omitted. So,

asm51 write

has the same effect as

asm51 sprers.eu

Both these commands assemble the file sprers.eu and create a list file

sprers.eu and a relocatable object module sprers.eu

For compatibility with future TASKING Cross−Software the following

extensions are suggested:

.asm input assembly source file for mpp51

.src output from the string macro preprocessor mpp51

or the C compiler / input for asm51

.obj relocatable object files

.lib object libraries files in archive format

.out relocatable output files from link51

.abs absolute IEEE− output files

.hex absolute Intel Hex output files

.sre absolute Motorola S−record output files

.lst assembler list file

.l51 linker list file

PREPROCESSING

For a description of the possibilities offered by the string macro

preprocessor see the chapter Macro Preprocessor. In this section we shall

merely show how it can be used in conjunction with the assembler.

The program sprers.eu does not need to be preprocessed using

mpp We shall nevertheless use sprers.eu file to demonstrate the use

of the macro preprocessor. First the file sprers.eu is renamed to

sprers.eu


1−8

OVERVIEW

The simplest call to mpp51 is:

mpp51 sprers.eu

Chapter 1

The result of this command is that the file sprers.eu will be created. The

contents of this file will be the same as sprers.eu

ASSEMBLER LISTING

The assembler generates a listing file by default. As a result of the

command:

asm51 sprers.eu

the listing file sprers.eu is created. If a listing is not desired the

NOPRINT control can be used. For example:

asm51 sprers.eu NOPRINT

To redirect the listing information to another file the PRINT control is

available. For example:

asm51 sprers.eu PRINT(sprers.eu)

asm51 is a three−pass assembler. The listing file is generated in the last

phase.

ERROR MESSAGES

Error messages from the cross−assembler are sent to the standard error

device and written in the list file. If severe errors occur in one of the first

two passes the error messages only occur on the standard error device

because the assembler aborts before the third pass. It may however be

useful to have a (not yet complete) list file of these first phases with the

error messages inserted on the place where they occurred. This can be

done using the LISTALL control.

If this control is specified the assembler creates a listing file in every

phase, asm1 fatal error a1000 cannot open file. If a phase ends successfully, the listing file will be overwritten in

the next phase.


• • • • • • • •

Overview 1−9

SYMBOLIC DEBUGGING

To facilitate debugging, the programmer can decide how much symbolic

debugging information to include in the load file. The following categories

of information are available:

1. PUBLIC names

2. local names

3. compiler generated names

4. names defined in ?SYMB directives

5. records for ?LINE and ?FILE directives

6. segment names

7. version information

Each category is associated with one bit of a 7−bit pattern; for a full

description see the chapter Assembler Controls, asm1 fatal error a1000 cannot open file. By default all categories

except compiler generated names are included in the load file, which is

correct for user written assembly programs.

PL/M51 generated assembly source files contain the control DEBUGINFO(

0F9H ), which exports everything except compiler server connection error 901 hp names and

assembler local symbols.

In the following example we shall use DEBUGINFO, requesting that all

possible information be generated.

asm51 sprers.eu DEBUGINFO( O )

For more information, see the the debugging directives ?SYMB, ?LINE,

?FILE in the chapter Assembler Directives.


1−10

OVERVIEW

Chapter 1


CHAPTER

2

MACRO

PREPROCESSOR


2−2

MACRO PREPROCESSOR

CHAPTER

2

Chapter 2


• • • • • • • •

Macro Preprocessor 2−3

INTRODUCTION

The macro preprocessor, asm1 fatal error a1000 cannot open file, mpp51, is a string manipulation tool which

allows you to write repeatedly used sections of code once and then insert

that error 017 undefied symbol downloadfiles at several places in your program. mpp51 also handles

conditional assembly, assembly−time loops, console I/O and recursion.

The macro preprocessor is implemented as a separate program which

saves both time and space in an assembler, particularly for those programs

that do not use macros and thus need not run the macro preprocessor.

mpp51 is compatible with Intel’s syntax for the macro processing

language (MPL). A user of macros must submit his source input to the

macro preprocessor. The macro preprocessor produces one output file

which can then be used as an input file to the Cross−assembler.

The macro preprocessor regards its input file as a stream of characters, not

as a sequence of statements like the assembler does, asm1 fatal error a1000 cannot open file. The macro

preprocessor scans the input (source) file looking for macro calls. A

macro−call is a request to the macro preprocessor to replace the call

pattern of a built−in or user−defined macro with its return value.

As soon as a macro call is encountered, the macro preprocessor expands

the call to its return value. The return value of a macro is the text that

replaces the macro call. This value is then placed in a temporary file, and

the macro preprocessor asm1 fatal error a1000 cannot open file. The return value of some macros is the

null string, i.e., a character string containing no characters. So, when these

macros are called, the call is replaced by the null string on the output file,

and the assembler will never see any evidence of its presence. This is of

course particularly useful for conditional assembly.

This chapter documents mpp51 in several parts. First the invocation of

mpp51 is described. The following sections describe how to define and

use your own macros, describe the syntax of the macro processing

language and describe the macro preprocessor’s built−in functions. This

chapter also contains a section that is devoted to the advanced concepts of

mpp

The first five sections give enough information to begin using the macro

preprocessor. However, sometimes a more exact understanding of

mpp51’s operation asm1 fatal error a1000 cannot open file needed. The advanced concepts section should fill

those needs.


2−4

MACRO PREPROCESSOR

Chapter 2

At macro time, symbols, labels, predefined assembler symbols, EQU, and

SET symbols, and the location counter are not known. The macro

preprocessor does not recognize the assembly language. Similarly, at

assembly time, no information about macro symbols is known.

MPP51 INVOCATION

The command line invocation line of mpp51 is:

mpp51 [option] input−file [output−file]

mpp51 −V

mpp51 −?

When you use a UNIX shell (C−shell, Bourne shell), asm1 fatal error a1000 cannot open file, arguments

containing special characters (such as ’( )’ ) must be enclosed with " ".

The invocations for UNIX and PC are the same, except for the −? option in

the C−shell:

mpp51 "−?" or mpp51 −\?

The input−file is an assembly source file containing user−defined macros.

You must give a complete filename (no default file extension is taken).

The output−file is an assembly source file in which all user−defined macros

are replaced. This file is the input file for asm If output−file is omitted,

the output file has the same basename as the input file but with the file

extension .src.

Invocation with −V only displays a version header.


• • • • • • • •

Macro Preprocessor 2−5

Option Description

−? Display invocation syntax

−Dmacro=def Define preprocessor macro

−f file Read options from file

−Idirectory Look in directory for include files

−Umacro Undefine preprocessor macro

−V Display version header only

−ofilename Specify name of output file

−−[no−]allow−undefined−macro Allow expansion of undefined macros

−−disable=nr[,nr] Suppress a warning and/or error

−−[no−]file−info Generate source file line info

−−[no−]info−messages Generate info messages

−−max−nesting=value Set the maximum include file nesting level

(default=31)

−−[no−]parameters−redefine Allow macro parameters to be redefined

−−[no−]prompt=string Set the prompt for the %IN command

−−[no−]skip−asm−comment Skip parsing after assembly comment asm1 fatal error a1000 cannot open file 2−1: mpp51 options

Warn on expansion of undefined macros

DETAILED DESCRIPTION OF MACRO

PREPROCESSOR OPTIONS

With options that can be set from within EDE, you will find a mouse icon

that describes the corresponding action.


2−6

MACRO PREPROCESSOR

−?

Option:

−?

Description:

Display an explanation of options at stdout.

Example:

mpp51 −?

Chapter 2


• • • • • • • •

Macro Preprocessor 2−7

−−allow−undefined−macro

Option:

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−−allow−undefined−macro

−−no−allow−undefined−macro

Default:

−−no−allow−undefined−macro

Description:

With this option the macro preprocessor will not issue an error when it

finds an undefined macro.

Example:

mpp51 −−allow−undefined−macro sprers.eu


2−8

MACRO PREPROCESSOR

−D

Option:

Chapter 2

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Define a macro (syntax:

macro[=def]) in the Define user macros field. You can specify and define

more macros by separating them with commas.

−Dmacro=[def]

Arguments:

The macro you want to define and optionally its definition.

Description:

Define macro as in ’define’. Any number of symbols can be defined. If

def is not given, the symbol is defined to the null string.

Example:

The following command defines symbol LEVEL to 3:

mpp51 −DLEVEL=3 sprers.eu

The following command defines symbol LEVEL to the null string:

mpp51 −DLEVEL= sprers.eu


• • • • • • • •

Macro Preprocessor 2−9

−−disable

Option:

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−−disable=number[,number]

Description:

With this option you can suppress one or more errors or warnings.

Example:

To suppress errors andenter:

mpp51 −−disable=, sprers.eu


2−10

MACRO PREPROCESSOR

−f

Option:

Chapter 2

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−f file

Arguments:

A filename for command line processing. The filename "−" may be used to

denote standard input.

Description:

Use file for command line processing. To get around the limits on the size

of the command line, it is possible to use command files. These command

files contain the options that could not be part of the real command line.

Command files can also be generated on the fly, for example by the make

utility.

More than one −f option is allowed.

Some simple rules apply to the format of the command file:

1. It is possible to have multiple arguments on the same line in the command

file.

2. To include whitespace in the argument, surround the argument with either

single or double quotes.

3. If single or double quotes are to be used inside a quoted argument, we

have to go asm1 fatal error a1000 cannot open file the following rules:

a. If the embedded quotes are only single or double quotes, use the

opposite quote 2 times terror d.e.a.d the argument. Thus, if a argument should

contain a double quote, surround the argument with single quotes.

b. If both types of quotes are used, we have to split the argument in such

a way that each embedded quote is surrounded by the opposite type

of quote.


• • • • • • • •

Macro Preprocessor 2−11

Example:

or

or

"This has a single quote ’ embedded"

’This has a double quote " embedded’

’This has a double quote " and \

a single quote ’"’ embedded"

4. Some operating systems impose limits on the length of lines within a text

file. To circumvent this limitation it is possible to use continuation lines.

These lines end with a backslash and newline. In a quoted argument,

continuation lines will be appended without stripping any whitespace on

the next line. For non−quoted arguments, all whitespace on the next line

will be stripped.

Example:

"This is a continuation \

line"

−> "This is a continuation line"

control(file1(mode,type),\

file2(type))

−>

control(file1(mode,type),file2(type))

5. It is possible to nest command line files up to 25 levels.

Example:

Suppose the file mycmds contains the following line:

−DLEVEL=3

sprers.eu

The command line can now be:

mpp51 −f mycmds


2−12

MACRO PREPROCESSOR

−−file−info

Option:

Chapter 2

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−−file−info

−−no−file−info

Default:

−−file−info

Description:

By default, the macro preprocessor generates source file line information,

such as:

# 1 "/sprers.eu"

With option −−no−file−info the macro preprocessor does not generate

this information.

Example:

mpp51 −−no−file−info sprers.eu


• • • • • • • •

Macro Preprocessor 2−13

−I

Option:

From the Project menu, select Directories Add one or more directory

paths to the Include Files Path field.

−Idirectory

Arguments:

The name of the directory to search for include file(s).

Description:

Change the algorithm for searching $INCLUDE files whose names do not

have an absolute pathname to look in directory. Thus, asm1 fatal error a1000 cannot open file files are

searched for first in the directory of the file containing the $INCLUDE line,

then in directories named in −I options in left−to−right order. If the files

are still not found mpp51 checks if the environment variable ASMDIR

exists. If it does, it searches the directories specified in ASMDIR. More than

one directory can be specified to ASMDIR by separating the directories

with a semi−colon ’;’.

Example:

mpp51 −I/proj/include sprers.eu

Section Asm1 fatal error a1000 cannot open file Files


2−14

MACRO PREPROCESSOR

−−info−messages

Option:

Chapter 2

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−−info−messages

−−no−info−messages

Default:

−−info−messages

Description:

By default, the macro preprocessor can generate informational messages in

addition to errors or warnings. With option −−no−info−messages the

macro preprocessor does not generate informational messages.

Example:

mpp51 −−no−info−messages sprers.eu


• • • • • • • •

Macro Preprocessor 2−15

−−max−nesting

Option:

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add hpvmmodify error incorrect backing device type option to the Additional

macro preprocessor options field.

−−max−nesting=number

Default:

31

Description:

With this option you can set the maximum include file nesting level.

Example:

To set the maximum include file nesting level to 50, enter:

mpp51 −−max−nesting=50 sprers.eu


2−16

MACRO PREPROCESSOR

−−parameters−redefine

Option:

Chapter 2

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−−parameters−redefine

−−no−parameters−redefine

Default:

−−no−parameters−redefine

Description:

With option −−parameters−redefine it is allowed to use the %SET macro

to redefine a macro parameter.

Example:

mpp51 −−parameters−redefine sprers.eu


• • • • • • • •

Macro Preprocessor 2−17

−−prompt

Option:

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−−prompt=string

Default:

>

Description:

With this option you can set the prompt for the %IN built−in function.

Example:

To set the prompt for the %IN function to "cmd>", enter:

mpp51 −−prompt="cmd>" sprers.eu


2−18

MACRO PREPROCESSOR

−o

Option:

Chapter 2

EDE determines the name of the output file with the same basename as

the input file and extension .src.

−ofilename

Arguments:

An output filename.

Default:

Basename of input file with .src suffix.

Description:

Use filename as output filename of the macro preprocessor, instead of the

basename of the input file with the .src extension.

Example:

To create the assembly file sprers.eu instead of sprers.eu, enter:

mpp51 sprers.eu −sprers.eu


• • • • • • • •

Macro Preprocessor 2−19

−−skip−asm−comment

Option:

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−−skip−asm−comment

−−no−skip−asm−comment

Default:

−−no−skip−asm−comment

Description:

With option −−skip−asm−comment the macro preprocessor skips

parsing after assembly comment ’;’. By default, comment is also parsed.

Example:

mpp51 −−skip−asm−comment sprers.eu


2−20

MACRO PREPROCESSOR

−U

Option:

Chapter 2

From the Project menu, select Project Options

Expand the Assembler entry and select Macro Preprocessor. Remove

definitions from the Define user macros field or add the option −U to the

Additional macro preprocessor options field.

−Umacro

Arguments:

The macro you want to undefine.

Description:

With this option you can undefine a previously defined symbol.

Example:

The following command undefines symbol LEVEL:

mpp51 −ULEVEL sprers.eu


• • • • • • • •

Macro Preprocessor 2−21

−V

Option:

−V

Description:

With this option you can display the version header of the macro

preprocessor. This option must be the only argument of mpp Other

options are ignored. mpp51 exits after displaying the version header.

Example:

mpp51 −V

TASKING macro preprocessor sprers.eu Build nnn

Copyright years Altium BV Serial#


2−22

MACRO PREPROCESSOR

−−warn−on−undefined−macro

Option:

Chapter 2

From the Project menu, select Project Options Expand the Assembler

entry and select Macro Preprocessor. Add the option to the Additional

macro preprocessor options field.

−−warn−on−undefined−macro

−−no−warn−on−undefined−macro

Default:

−−no−warn−on−undefined−macro

Description:

With option −−warn−on−undefined−macro the macro preprocessor

generates warning W instead of error E when asm1 fatal error a1000 cannot open file undefined macro

name is found.

Example:

mpp51 −−warn−on−undefined−macro sprers.eu


• • • • • • • •

Macro Preprocessor 2−23

INCLUDE FILES

If the macro preprocessor encounters a $INCLUDE statement in the input

file, preprocessing will continue by scanning the specified file until an

end−of−file or another INCLUDE is encountered.

Syntax:

$INCLUDE(file)

Abbreviation:

$IC(file)

Expansion:

$# 1 "file"

Description:

The ’$’ must be in column 1 for the macro preprocessor to recognize it for

processing at macro time. In the output file the INCLUDE(file) part of the

INCLUDE call is replaced by spaces (because the assembler also

recognizes the ’$’ character but does not recognize INCLUDE as a control).

Also a line containing # 1 "file" is put in the output file.

As soon as the macro preprocessor encounters an end−of−file in the

include file, input is resumed where it left off, namely at the next line after

the latest INCLUDE call (which due to nesting does not necessarily mean

returning to the original input file). Nesting of include files is allowed up

to 32 files.

If the macro preprocessor after recognizing the ’$’ character does not find

an INCLUDE before it encounters an end−of−line, due to misspelling or

simple because the ’$’ is followed by a control only recognized by the

assembler, no macro−time error is reported and scanned characters are

simply passed to the output file.

mpp51 first searches for $INCLUDE files in the directory of the file

containing the $INCLUDE line, then in directories named in −I options in

left−to−right order. If the files are still not found mpp51 checks if the

environment variable ASMDIR exists. If it does, it searches the directories

specified in ASMDIR. More than one directory can be specified to ASMDIR

by separating the directories with a semi−colon ’;’.


2−24

MACRO PREPROCESSOR

Chapter 2

Restriction:

Each control line (i.e. a line starting with ’$’) may not contain more than

one INCLUDE call.

Example:

; source lines

.

$include( sprers.eu ) ; include the contents of

; file sprers.eu

.

; other source lines

.

CREATING AND CALLING MACROS

Macro calls differ between user−defined macros and so−called built−in

functions. All characters in bold typeface in the syntax descriptions of the

following sections are constituents of the macro syntax. Italic tokens

represent place holders for user−specific declarations.

The macro preprocessor scans through the input source, one character at a

time, asm1 fatal error a1000 cannot open file, looking for a special character called the METACHARACTER, the

percent sign ’%’ initially. This metacharacter must precede a macro−call.

Until the macro preprocessor finds a metacharacter, it does not process

text. It simply passes the text from the input file to the output file.

Since mpp51 only processes macro calls, it is necessary to call a macro in

order to create other macros, the so−called "user−defined macros". The

built−in function DEFINE creates macros. Built−in functions are a

predefined part of the macro language, so they may be called without

prior definition. The general syntax for DEFINE is shown below.

Syntax:

%[*]DEFINE (macro−name[parameter−list]) [LOCAL local−list]

(macro−body)

DEFINE is the most important mpp51 built−in function. This section is

devoted to describing this built−in function. Each of the symbols in the

syntax above (macro−name, parameter−list, local−list and macro−body)

are described in detail on the pages that follow. In some cases, we have

abbreviated this general syntax to emphasize certain concepts.


• • • • • • • •

Macro Preprocessor 2−25

CREATING PARAMETERLESS MACROS

When you create a parameterless macro, there are two parts to a DEFINE

call: the macro−name and the macro−body. The macro−name defines the

name used when the macro is called; the macro−body defines the return

value of the call.

Syntax:

%[*]DEFINE (macro−name) (macro−body)

The ’%’ character signals a macro call. The ’*’ is the optional literal

character. When you define a macro using the literal character ’*’, as

shown above, macro calls contained in the body asm1 fatal error a1000 cannot open file the macro are not

expanded until the macro is called. The exact use of the literal character is

discussed in the advanced concept section. When you define a

parameterless macro, the macro−name is a macro identifier that follows

the ’%’ character in the source line. The rules for macro identifier are:

− The identifier must begin with an upper or lowercase alphabetic

character (A,B,Z or a,b,z), or a special character ( a question

mark ’?’ or an underscore character ’_’).

− The remaining characters may be alphabetic, special or decimal

digits (0,1,2,9).

− Only the first 31 characters of a macro identifier are recognized as

the unique identifier name. Upper and lower case characters are not

distinguished in a macro identifier.

The macro−body is usually the return value of the macro call. However,

the macro−body may contain calls to other macros. If so, the return value

is actually the fully expanded macro−body, including the return values of

the call to other macros. The macro call is re−expanded each time it is

called.


2−26

MACRO PREPROCESSOR

Example 1:

%*DEFINE (String_1) (An)

%*DEFINE (String_2) (ele)

%*DEFINE (String_3) (phant)

%*DEFINE (String_4) (shopping)

%DEFINE (String_5) (goes

%String_4)

%DEFINE (Part_1)

(%String_1 %String_2%String_3)

Chapter 2

The macro−body must consist of a balanced−text string, i.e. you must

have balanced parentheses within the macro−body. In other words, each

left parenthesis must have a succeeding right parenthesis, and each right

parenthesis must have a preceding left parenthesis.

The possible placement of the macro−body and the parenthesis are both

represented in the above examples. The beginning of the macro−body is

determined by the syntactical end of the left parenthesis, where tabs

(08H), blanks and the first new line (0AH) are also part of the

macro−body.

The macro−body of String_1 starts with the ’A’ of "An"

The macro−body of String_3 starts with the ’p’ of "phant"

The macro−body of String_4 starts with the ’(08H)’ of "(08H)shopping".

The end of macro−body is determined by the right parenthesis.

The macro−body of String_4 is "(08H)shopping"

The macro−body of String_5 is "goes (0AH)

(08H)shopping"

The expanded value of DEFINE is the null string, but the macro body is

stored internally for later use. User−defined macros may invoke themselves

within their bodies. This property is called ’recursion’. Any macro which

calls itself must terminate eventually or the macro preprocessor may enter

an infinite loop.

Once a macro has been created, it may be redefined by a second call to

DEFINE.


• • • • • • • •

Macro Preprocessor 2−27

To call a macro, you use the ’%’ character followed by the name of the

macro (the literal character ’*’ is only admissible for defined macros whose

call is passed to a macro as a an actual parameter; example: %M1(%*M2)).

The macro preprocessor removes the call and inserts the return value of

the call. If the macro−body contains any call to other macros, they are

replaced with their return values.

Example 2:

%Part_1 %String_5 −−> An elephant goes

shopping

Once a macro has been created, it may be redefined by a second call to

DEFINE. Note, however that a macro should not redefine itself within its

body (see Advanced mpp51 Concepts).

The examples below show several macro definitions. Their return values

are also shown.

Example 3:

Macro definition at the top of the program:

%*DEFINE (MOVE)

( MOV A, @R1

MOV @R2, A

)

The macro call as it appears asm1 fatal error a1000 cannot open file the program:

MOV R1, #1

−−−−%MOVE

The program as it appears after the macro preprocessor made the

following expansion, where the first expanded line is preceded by the four

blanks preceding the call (the sign − indicates the preceding blanks):

MOV R1, #1

−−−− MOV A, @R1

MOV @R2, A


2−28

MACRO PREPROCESSOR

Example 4:

Macro definition at the top of the program:

%*DEFINE (ADD5)

( MOV R0, #5

MOV R5, @R2

ADD R5, R0

)

The macro call as it appears in the original program body:

MOV R5, #2

%ADD5

The program after the macro expansion:

MOV R5, #2

MOV R0, #5

MOV R5, @R2

ADD R5, R0

Example 5:

Macro definition at the top of the program:

%*DEFINE (MOVE_AND_ADD) (

%MOVE

%ADD5

)

The macro call as it appears in the body asm1 fatal error a1000 cannot open file the program:

MOV R1, postgresql error reporting and logging program after the macro expansion:

MOV R1, #1

MOV A, @R1

MOV @R2, A

MOV R0, #5

MOV R5, @R2

ADD R5, R0

Chapter 2


• • • • • • • •

Macro Preprocessor 2−29

CREATING MACROS WITH PARAMETERS

If the only function of the macro preprocessor was to perform simple

string replacement, then it would not be very useful for most of the

programming tasks. Each time we wanted to change even the simplest part

of the macro’s return value we would have to redefine the macro.

Parameters in macro calls allow more general−purpose macros. Parameters

leave holes in a macro−body that are filled in when you call the macro.

This permits you to design a single macro that produces code for typical

programming operations. The term ’parameters’ refers to both the formal

parameters that are specified when the macro is defined (the holes, and

the actual parameters or arguments that are specified when the macro is

called (the fill−ins).

The syntax for defining macros with parameters is very similar to the

syntax for macros without parameters.

Syntax:

%[*]DEFINE (macro−name[parameter−list]) (macro−body)

The macro−name must be a valid identifier.

The parameter−list is a list of macro identifiers separated by macro

delimiters. These identifiers comprise the formal parameters used in the

macro. The macro identifier for each parameter in the list 26 errors error 017 undefined symbol be unique,

but they may be the same as other formal argument names to other

macros since they have no existence outside the macro definition. They

may also be the same as the names of other user macros or of macro

functions. Note, however that in this case the macro or function cannot be

used within the macro−body, since its name would be recognized as a

parameter instead. To reference a formal argument within the macro−body,

use its name preceded by the metacharacter.

Typically, the macro delimiters are parentheses and commas. When using

these delimiters, you would enclose the parameter−list in parentheses and

separate each formal parameter with a comma. When you define a macro

using parentheses and commas as delimiters, you must use those same

delimiters, when you call that macro.

The example below shows the definition of a macro with three

parameters: SOURCE, DEST and COUNT. The macro produces code to copy

any number of words from one part of memory to another.


2−30

MACRO PREPROCESSOR

Example:

%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT))

( MOV R1, #%SOURCE

MOV R0, #%DEST

MOV R7, #%COUNT

MOV A, @R1

MOV @R0, asm1 fatal error a1000 cannot open file, A

INC R1

INC R0

DJNZ R7, ($−4)

)

Chapter 2

To call a macro with parameters, you must use the metacharacter followed

by the macro’s name as with parameterless macros. However, a list of the

actual parameters must follow. These actual parameters have to be

enclosed within parentheses and separated from each other by commas.

The actual parameters may optionally contain calls to other macros.

A simple call to a macro defined above might be:

%MOVE_ADD_GEN( 10, 24, 8 )

The above macro call produces the following code:

MOV R1, #10

MOV R0, #24

MOV R7, #8

MOV A, @R1

MOV @R0, A

INC R1

INC R0

DJNZ R7, ($−4)


• • • • • • • •

Macro Preprocessor 2−31

LOCAL SYMBOLS IN MACROS

If we used a fixed label instead of the offset ($−4) in the previous

example, the macro using the fixed label can only be called once, since a

second call to the macro causes a conflict in the label definitions at

assembly time. The label can be made a parameter and a different symbol

name can be specified each time the macro asm1 fatal error a1000 cannot open file called.

A preferable way to ensure a unique label for each macro call is to put the

label in a local−list. The local−list construct allows you to use macro

identifiers to specify assembly−time symbols. Each use of a LOCAL symbol

in a macro guarantees that the symbol will be replaced by a unique

assembly−time symbol each time the symbol is called.

The macro preprocessor increments a counter once for each symbol used

in the list every time your program calls a macro that uses the LOCAL

construct. Symbols in the local−list, when used in the macro−body, receive

a two to five digit suffix that is the hexadecimal value of the counter. The

first time you call a macro that uses the LOCAL construct, the suffix is ’00’.

The syntax for the LOCAL construct in the DEFINE function is shown

below. (This is the complete syntax for the built−in function DEFINE):

Syntax:

%[*]DEFINE (macro−name[parameter−list]) [LOCAL local−list]

(macro−body)

The local−list is a list of valid macro identifiers separated by spaces. Since

these macro identifiers are not parameters, the LOCAL construct in a macro

has no effect on a macro call.

To reference local symbols in the macro−body, they must be preceded by

the metacharacter. The symbol LOCAL is not reserved; a user symbol or

macro may have this name.

The next example shows a macro definition that uses a LOCAL list.


2−32

MACRO PREPROCESSOR

Example:

%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT)) LOCAL LAB

( MOV R1, #%SOURCE

MOV R0, #%DEST

MOV R7, #%COUNT

%LAB:

MOV A, @R1

MOV @R0, A

INC R1

INC R0

DJNZ R7, %LAB

)

A simple call to a macro defined above might be:

%MOVE_ADD_GEN( 50, asm1 fatal error a1000 cannot open file,24 )

The above macro call might produce the following code (if this is he

eleventh call to a macro using a LOCAL list):

MOV R1, #50

MOV R0, #

MOV R7, asm1 fatal error a1000 cannot open file A, @R1

MOV box error 20 hwk, A

INC R1

INC R0

DJNZ R7, LAB0A

Chapter 2

Since macro identifiers follow the same rules as ASM51, any macro

identifier can be used in a local−list. However, if long identifier names are

used, they should be restricted to 29 characters. Otherwise, the label suffix

may cause the identifier to exceed 31 characters and these would be

truncated.


• • • • • • • runtime error 5152 Preprocessor 2−33

THE MACRO PREPROCESSOR’S BUILT−IN

FUNCTIONS

The macro preprocessor has several built−in or predefined macro

functions. These built−in functions perform many useful operations that

are difficult or impossible to produce in a user−defined macro.

We have already discussed one of these built−in functions, DEFINE.

DEFINE creates user−defined macros. DEFINE does this by adding an entry

in the macro preprocessor’s tables of macro definitions. Each entry in the

tables includes the macro−name getlasterror 5 write file the macro, its parameter−list, its

local−list and its macro−body. Entries for the built−in functions are present

when the macro preprocessor begins operation.

Other built−in functions perform numerical and logical expression

evaluation, affect control flow of the macro preprocessor, manipulate

character strings, and perform console I/O.

The following sections deal with the following:

Comment, escape, asm1 fatal error a1000 cannot open file, bracket, group (’’, ’, n, (), {} )

Metachar function (METACHAR)

Expressions processed by mpp51

Calculating functions (SET, EVAL)

Undefine function (UNDEF)

Controlling functions (IF, IFDEF/IFNDEF, WHILE, REPEAT, EXIT)

String−processing functions (LEN, SUBSTR, MATCH)

String−comparing functions (EQS, NES, LTS, LES, asm1 fatal error a1000 cannot open file, GTS, GES)

Message functions (ERROR, FATAL)

File/line info functions (__FILE__, __LINE__)

Option function (OPTION)

Input/Output functions (IN, OUT)


2−34

MACRO PREPROCESSOR

COMMENT, ESCAPE, BRACKET AND GROUP

FUNCTIONS

COMMENT FUNCTION

Chapter 2

The macro processing language can be very subtle, and the operation of

macros written in a straightforward manner may not be immediately

obvious. Therefore, it is often necessary to comment macro definitions.

Syntax:

%’text’

or

%’text end−of−line

The comment function always evaluates to the null string. Two terminating

characters are recognized: the apostrophe ’ and the end−of−line (line−feed

character, ASCII 0AH), asm1 fatal error a1000 cannot open file. The second form of the call allows macro

definitions to asm1 fatal error a1000 cannot open file spread over several lines, while avoiding any unwanted

end−of−lines in the return value. In either form of the comment function,

the text or comment is not evaluated for macro calls.

The literal character ’*’ is not accepted in connection with this function.

Example:

%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT)) LOCAL LAB

( MOV R1, #%SOURCE %’This is the source address’

MOV R0, #%DEST %’This is the destination’

MOV R7, #%COUNT %’%COUNT must be a constant’

%LAB: %’This is a local label.

%’End of line is inside the comment!

MOV A, @R1

MOV @R0, A

INC R1

INC R0

DJNZ R7, %LAB

)

Call the above macro:

%MOVE_ADD_GEN( 50,24 )


• • • • • • • •

Macro Preprocessor 2−35

Return value from above call:

MOV R1, #50

MOV R0, #

MOV R7, #24

LAB0A:

MOV A, @R1

MOV @R0, A

INC R1

INC R0

DJNZ R7, LAB0A

Note that the comments that asm1 fatal error a1000 cannot open file terminated with the end−of−line

removed the end−of−line character along with the rest of the comment.

The metacharacter is not recognized as flagging a call to the macro

preprocessor when it appears in the comment function.

ESCAPE FUNCTION

Sometimes it is necessary to prevent the macro preprocessor from

processing text. The escape function and the bracket function perform

such tasks.

Syntax:

%n text−of−n−characters−long

The escape function prevents the macro preprocessor from processing a

text string of n characters long, where asm1 fatal error a1000 cannot open file is a decimal digit from 0 to 9. The

escape function is useful for inserting a metacharacter as text, adding a

comma as part of an argument, or placing a single parenthesis in a

character string that requires balanced parentheses.

The literal character ’*’ is not accepted in connection with this function.


2−36

MACRO PREPROCESSOR

Example:

Before Macro Expansion After Macro Expansion

;Average of 20%1% −>;Average of 20%

%DTCALL(JAN 21%1,−> JAN 21,

JUN 12%1, ) −> JUN 12,

%MYCALL(1%1) Option 1, −> 1) Option 1

2%1) Asm1 fatal error a1000 cannot open file 2, −> 2) Option 2

3%1) Option 2) −> 3) Option 3

Chapter 2

The first example add a literal ’%’ in the text. The second example keeps

the date as one hp designjet 500 lower blue lever error parameter adding a literal ’,’. The third example

adds a literal right parenthesis ’)’ to each parameter.

BRACKET FUNCTION

The bracket function is the other built−in function that prevents the macro

preprocessor from expanding text.

Syntax:

%(balanced−text)

The bracket function prevents all macro preprocessor expansion of the

text contained within the parentheses. However, the escape function, the

comment function, and the parameter substitution are still recognized.

Since there is no restriction for the length of the text within the bracket

function, it is usually easier to use than the escape function.

The literal character ’*’ is not accepted in connection with this function.

Example:

%*DEFINE (DW(LIST,NAME))

( %NAME DW %LIST)

The macro DW expands DW statements, where the variable NAME

represents the first parameter and the expression LIST represents the

second parameter.

The following expansion should be obtained by the call:

PHONE DW H, 3DH, 0F0H


• • • • • • • •

Macro Preprocessor 2−37

If the call in the following form:

%DW(H, asm1 fatal error a1000 cannot open file, 3DH, 0F0H, PHONE)

occurs, the macro preprocessor would interpret the first argument (H)

as NAME and everything after the first comma as the second parameter,

since the first comma would be interpreted as the delimiter separating the

macro parameters.

In order to change this method of interpretation, all tokens that are to be

combined for an individual parameter must be identified as a parameter

string and set in a bracket function:

%DW(%(H, 3DH, 0F0H), PHONE)

This way the bracket function prevents the string ’H, 3DH, 0F0H’ from

being evaluated as separate parameters.

GROUP FUNCTION

The group function does the opposite of the bracket function, it ensures

that the text is expanded.

Syntax:

%{balanced−text}

The contents of the group macro is expanded and the resulting string is

then interpreted itselve like a macro command. This allows for definition

of complex recursive macros. Another useful application of the group

command is to separate macro identifiers from surrounding, possible valid

identifier characters.

The literal character ’*’ is not accepted in connection with this function.

Example:

%define(TEXTA)(Text A)

%define(TEXTB)(Text B)

%define(TEXTC)(Text C)

%define(SELECT)(B)

%{TEXT%SELECT}


2−38

MACRO PREPROCESSOR

Chapter 2

The contents of the group function, TEXT%SELECT, expands to TEXTB,

which on its turn is expanded like %TEXTB resulting in Text B.

Example:

%define(op)(add)

%{op}_and_move

The group function ensures that the macro op is expanded. Without it,

op_and_move would be seen asm1 fatal error a1000 cannot open file the macro identifier.

METACHAR FUNCTION

The METACHAR function can be used to redefine the metacharacter

(initially: ’%’)

Syntax:

%METACHAR(balanced−text)

Although the balanced−text string may be any number of characters long,

only the first character in the string is taken to be the new metacharacter.

Macro calls in the balanced−text string are still recognized and

corresponding actions that will not lead to any direct expansion on the

output file will be performed. So, for example a SET macro call inside the

balanced−text string will be performed.

Characters that may not be used as a metacharacter are: a blank, letter,

digit, left or right parenthesis, or asterisk.

The following example is catastrophic !!!

%METACHAR( & )

This examples defines the space character as the new metacharacter, asm1 fatal error a1000 cannot open file, since

it is the first character in the balanced−text strings!


• • • • • • • •

Macro Preprocessor 2−39

NUMBERS AND EXPRESSIONS IN MPP51

Many built−in functions recognize and evaluate numerical expressions in

their arguments. mpp51 uses the same rules for representing numbers as

asm51 (see chapter Operands And Expressions for detailed information):

− Numbers may be represented in the formats binary (B suffix), octal

(O or Q suffix), decimal (D or no suffix), and hexadecimal (H

suffix).

− Internal representation of numbers is 16−bits (00H to 0FFFFH); the

processor does not recognize or output real or long integer

numbers.

− The following operators are recognized by the macro preprocessor

(in descending precedence):

1. ’(’ ’)’

2. LOW HIGH

3. ’*’ ’/’ MOD SHL SHR

4. ’+’ ’−’ (both binary and unary)

5. EQ

6. NOT

7. AND

NE LE LT GE GT

8. OR XOR

The symbolic forms of the relational operators (i.e.,=,>=,


2−40

MACRO PREPROCESSOR

SET FUNCTION

Chapter 2

SET assigns the value of the numeric expression to the identifier,

macro−variable, and stores the macro−variable in the macro time symbol

table, macro−variable must follow the same syntax convention used for

other macro identifiers. Expansion of a macro−variable always results in

hexadecimal format.

Syntax:

%SET (macro−variable,expression)

The SET macro call affects vba on error resume next err.number macro time symbol table only; when SET is

encountered, the macro preprocessor replaces it with the null string.

Symbols defined by SET can be redefined by a second SET call, or defined

shadow_
Guest


Email

Hi, I also ought the book: Assembly Language For Intel-Based Computers, asm1 fatal error a1000 cannot open file. It uses a file called "Irvineinc". It&#;s included on the CD-Rom. The book says that I have to put it in the "include" directory. So I put Irvineinc in the "\masm32\Include\" dir.
But it didnt work so I also put the Irvinelib in the "\masm32\lib\" dir (as I read in these forums  BigGrin). The error was gone but now I get this error when I use the Build All option:

Assembling C:\masm32\sprers.eu
C:\masm32\sprers.eu(10) : fatal error A cannot open file : Irvineinc
_
Assembly error
Press any key to continue


What did I do wrong? (I have full administrative rights in case it matters)
Logged
ramguru
Guest


Email

I think your problem is current directory which is not current I&#;m not able to use batch file directly (from explorer with 2-click or TC window) anymore, instead I have to execute the batch from console (Run->"cmd")

Logged
ramguru
Guest


Email

I assumed you have "sprers.eu" (something like that), but it seems you are using QEditorand menu command "build all".

Logged
shadow_
Guest


Email

Yes I use the QEditor Is there another way to compile and to asm1 fatal error a1000 cannot open file that error (without using the QEditor if nessecary)?
I am new to ASM, asm1 fatal error a1000 cannot open file. And my book is not telling me how to compile at all

Logged
ramguru
Guest


Email

I&#;m not sure You can use IDE like RadASM or create batch file (like I did) and execute like I wrote

C:\masm32\bin\ml /c /coff /Cp sprers.eu
C:\masm32\bin\rc sprers.eu
C:\masm32\bin\link /subsystem:windows /libpath:C:\masm32\lib sprers.eu sprers.eu
del *.obj *.res
pause

or (not using any resources)

C:\masm32\bin\ml /c /coff /Cp sprers.eu
C:\masm32\bin\link /subsystem:windows /libpath:C:\masm32\lib sprers.eu
del *.obj
pause

Logged
shadow_
Guest


Email

Both (Bat1+Bat2) don&#;t work, they give the following error:

LINK: fatal error LNK cannot open input file "sprers.eu"

It is not creating an *.obj file at all.
Logged
ramguru
Guest


Email

I don&#;t know what you mean both (RadASM or batch, batch1 or batch2). But if I use f.e. sprers.eu I do the fellowing Run->"cmd", cd "where are: *.asm+*.bat", sprers.eu and everything&#;s OK. This error have to be connected with path (incorrect).

Logged
shadow_
Guest


Email

I meant Bat1+Bat2.

I also tried RadASM now, and this one gives this error:

C:\Masm32\Include\irvineinc(3) : fatal error A cannot open file : sprers.eu

So I also copied the file "sprers.eu" to the "inlcude" folder

Now I get asm1 fatal error a1000 cannot open file error instead (using RadASM):

C:\Masm32\Bin\sprers.eu /c /coff /Cp /nologo /I"C:\Masm32\Include" "C:\masm32\sprers.eu"
Assembling: C:\masm32\sprers.eu
C:\Masm32\Bin\sprers.eu /SUBSYSTEM:WINDOWS /RELEASE /VERSION /LIBPATH:"C:\Masm32\Lib" "C:\masm32\sprers.eu"
Microsoft (R) Incremental Linker Version
Copyright (C) Microsoft Corp All rights reserved.

sprers.eu : error LNK unresolved external symbol [email protected]
sprers.eu : error LNK unresolved external symbol [email protected]
sprers.eu : fatal error LNK 2 unresolved externals


WriteString is located in Irvine But I placed the Irvinelib file in the lib folder, the Irvineinc file in the include folder, and the Irvineasm in the m32lib folder What else do I have to do?


@ aeroASM:
Thanks, If I compile in MASM32 now I don&#;t get the &#;cannot open Irvine32&#; error anymore but the same error as above (with RadASM) instead now Tongue. It&#;s a step closer.
Logged
shadow_
Guest


Email

This reduces the error to

sprers.eu : error LNK unresolved external symbol [email protected]
sprers.eu : fatal error LNK 1 unresolved external



But if those errors mean a missing library file I thought just included the following in the program

includelib C:\masm32\lib\kernellib
includelib C:\masm32\lib\irvinelib
include C:\masm32\include\irvineinc



I don&#;t know if I did everything correct I am not getting any output But it&#;s compiling now without any errors :). Here is the complete code after the modifications:

; sprers.eu - Windows program to print "Hello, world" using Irvine library
; To asemble/run using MASM
;
;   set include=\masm\include
;   set lib=\masm\lib
;   ml /Cx /c /coff sprers.eu
;   link32 sprers.eu kernellib irvinelib /subsystem:console
;   hello1

includelib C:\masm32\lib\kernellib
includelib C:\masm32\lib\irvinelib
include C:\masm32\include\irvineinc    ; from Irvine CDROM

.stack

.data
greeting byte "Hello, world", 13, 10, 0   ; message to write

.code
main proc
  mov edx, offset greeting
  invoke WriteString   ; sprers.eu: write NUL terminated string pointed to by edx
  exit                 ; sprers.eu: a macro that calls ExitProcess
main endp
end main

Logged
File from the menu and choose the file named sprers.eu from the ch03 folder in the book's example programs. Select Build bit ASM from the Tools menu. The following command window should appear, showing the successful execution of the assembler and linker, followed by a listing of all files related to this program:

Press a key to close the window. Next, you will run the program. Select Run bit ASM from the Tools menu. The following window will appear, although the contents of all registers except EAX will be different:

Press a key to close the window.

You have completed the setup for building and running bit assembly language programs.

Return to top



Syntax highlighting in your source code

When a text editor uses syntax highlighting, language keywords, strings, and other elements appear in different colors. Visual Studio highlights MASM reserved words and strings, as shown in the following example:

This won't happen automatically, but you can create a syntax definition file named sprers.eu asm1 fatal error a1000 cannot open file contains MASM keywords. Then when Visual Studio starts, it reads the syntax file and highlights MASM keywords.

If you decide to use Visual Studio's built-in MASM syntax highlighter, here are the required steps to set it up: 1) Download this sprers.eu file (enclosed in a ZIP file) given here to a folder in which you have read/write permissions. Extract it from the zip archive. 2) Close Visual Studio. 3) Copy sprers.eu to the C:\Program Files (x86)\Microsoft Visual Studio\\Community\Common7\IDE folder. Windows will display a confirmation dialog before copying the file. 4) Open Visual Studio, select Options from the Tools menu, select Text Editor, and select File Extension. On the right side of the dialog (shown below), enter asm as the extension, select Microsoft Visual C++ from the Editor list, and click the Add button. Click the OK button to save your changes.

Open your project and display an ASM file. You should see syntax highlighting in the editor. There is a glitch in the highlighting--assembly language comment line starts start with a semicolon, asm1 fatal error a1000 cannot open file, which C++ doesn't recognize. But this is a simple workaround: add an extra // right after the semicolon, like this, which will cause the comments to appear in their usual green color: ;// sprers.eu - adds two bit integers. ;// Chapter 3 example Return to top

Was your program's EXE file blocked by an Antivirus scanner?

Antivirus scanner software has improved greatly in recent years, and so have the number of viruses (one website reports 50, at present). Because of this, your computer's antivirus scanner may report a false positive when you build your program, and refuse to let you run it. There are a few workarounds: (1) You can add your project's bin/debug folder into an exclusion list in your antivirus configuration, asm1 fatal error a1000 cannot open file. This is my preferred approach, and it nearly always works. (2) You can suspend your realtime antivirus scanner software, but this will leave you open to malware for a short time. If you choose this option, be sure to temporarily disconnect your computer from the Internet. Return to top

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Tip: If the Solution Explorer window is not visible, select Solution Explorer from the View menu. Also, if you do not see sprers.eu in the Solution Explorer window, it might be hidden behind another window. To bring it to the front, click the Solution Explorer tab from the tabs shown along the bottom of the window.

asm1 fatal error a1000 cannot open file A error, unable to open file (assembly)

I have a Visual Studio project, where I'm trying to interface a C++ and Assembly program. So I have a header ("indexof.h") that has the Prototypes for the assembly procedures in an block, and a sprers.eu, which includes and uses the procedures made available in it, and then an file that contains my assembly code (which also has prototypes for its procedures, before the .code section). Unfortunately, when I attempt to run it, I get this error:

I desperately need help (It's due tomorrow), this was a project setup provided by my class, I'm just trying to run it, and I haven't even gotten to the actual thing I need to do yet. Thank you!

asked May 18, at

user avatar
Alexis DumasAlexis Dumas

1, silver badges bronze badges

dedndave
Member
*****
Posts:



the last 4 paths say "masm" instead of "masm32" ????
of course, that has nothing to do with the include file
masm32 is set up to use a drive other than C:

you might try a simple program that only needs kernel32
something like - INVOKE ExitProcess,0 - and that&#;s it
then, instead of including sprers.eu
include sprers.eu, kerneldll, and includelib kernelllib (without the masm32\include path)

now, take the paths out of the file - seeing as how they are defined in the environment variables, they should not be required
at least you can test to see if it&#;s a problem reading environment variables or a problem related to the way the files are declared
also, you might take a peek inside sprers.eu and see if there is anything odd there
that file declares a number of other include/includelib&#;s