User Tools

Site Tools


features

This is an old revision of the document!


Features

Here are some of the more notable features of 10LC (both the language and the compiler) and how it differs from 9LC.

Stream and Line Comments

In addition to the standard 9LC comment feature, you can also use // for a line comment and /* */ for stream/block comments. You can also use the stream comment in the middle of a statement.

// This Is A Line Comment
 
/* And This
Is A Block
Comment */
 
If RegA == 0x42 Goto /*ThatPlace*/ ThisPlace;

Decimal and Hexadecimal Numbers

You can freely mix decimal and hexadecimal values in code, so feel free to use whatever is most convenient or appropriate.

Write @ 100 = 220;
Write @ 0x929 = 0x62; 
Write @ 0x3F33 = 227;

Enhanced Symbolic Names for Programs and Labels

9LC already supported the use of symbolic identifiers for things like Program Names and Labels. However, their use was somewhat limited.

As an example, because 9LC did not prefix hexadecimal values (see above), you could not create symbolic identifiers that consisted solely of hexadecimal digits. Also, 9LC's symbolic names only used 8 characters of significance, so it could not disambiguate identifiers like THISNAME0 and THISNAME5. With 10LC, the length of symbol names is effectively unbounded, and all characters are significant.

Lastly, note that all symbols in 10LC are case-insensitive.

Program CodeToTestInputs
Program DisplayTest
Program DeadBeef
 
:DammitJimImADoctorNotATechnician 
:ABC

Enhanced Program Numbering Support

Like with 9LC, you can force a Program to a specific program number, but with 10LC even if you do, you can also use a symbolic name at the same time. Because of this, there is little reason to force specific program numbers.

Additionally, if you specify a specific program number, you will not create “holes” in the numbering system. Unlike 9LC, 10LC numbers Programs dynamically in the order they are encountered during compilation, and they draw from a pool of available program numbers so that there are no limitations on the numbers chosen.

For example, in 9LC, the third Program below would have a value of 6, but in 10LC it will have a value of 1. Also, if you continue and create another five dynamically numbered programs, they will be numbered 2, 3, 4, 6, and 7. The manually-specified program number will not mess up the numbering.

Program TestInputs     // Create Program TestInputs, Defaults To Program 0 
Program TestDisplay 5  // Create Program TestDisplay, Sets Program Number To 5 
Program DEADBeef       // Create Program DEADBeef, Defaults To Program **1**, Not 6 

Constant Values

You can create constant values that work like register Aliases but are strictly for constant numeric values and can be used anywhere a numeric value would be allowed. Once a Const has been defined in a Program, it cannot be undefined nor redefined to another value. Constants are not global and are scoped to the Program in which they are defined.

Const JoystickNone  = 0; 
Const JoystickUp    = 0x01; 
Const JoystickDown  = 0x02; 
Const JoystickLeft  = 0x04; 
Const JoystickRight = 0x08;

Global Constant Values

You can also create global constant values that work like the above normal constant values, but are visible to all programs being compiled after the global constant has been declared.

They work the same as Const values but must be declared outside the scope of a Program. As with Const values, once defined they cannot be undefined nor redefined to another value.

Global MemMapCtrlsP1 = 0x3400;
Global MemMapCtrlsP2 = 0x3401;
Global VideoMemStart = 0x2800;
Global ColorMemStart = 0x2C00;

Register Aliases

Aliases allow you to refer to the standard register set (REG0-REGF) using symbolic names. This is similar to existing 9LC functionality but without its restrictions. Unless disabled by a compiler option, 10LC will automatically create the following legacy register aliases:

  • BITMASK = REGA
  • ROMSIG = REGB
  • STSCTL = REGC
  • BITNUM = REGD
  • DAT = REGE
  • ADR = REGF
  • PDBAT = REG0

One of the differences between 10LC's Alias statement and 9LC's ASSIGN statement is that an Alias can be created anywhere within a Program - they do not have to be all grouped together in a dedicated section at the top of the file. Once an Alias has been defined in a Program, it cannot be undefined nor redefined to another Register. Like Constants, Aliases are not global and are scoped to the Program in which they are defined. Also, you cannot create a global alias in 10LC.

Alias Control1Bits = Reg1; 
Alias Control2Bits = Reg2;

Less-Than and Less-Than-Or-Equals Tests

10LC implements LT and LTE tests by reversing the test expression and using the existing GT/GTE tests.

If Control1Bits < Control2Bits Goto TestButtons;
If Control1Bits <= Control2Bits Goto TestButtons; 

Operator Equals Shortcuts

C-style Operator-Equals expressions are supported, which may be more familiar and natural to people familiar with other programming languages.

Control1Bits = ~0x23;
Control2Bits = ~Reg5;
Control1Bits = ~Control2Bits;
Reg3 <<= 4;
Reg1 >>= 3;
Reg1 &= 0x8F;
Reg1 |= Reg5;

Standalone Unary Operators

The Complement, Increment and Decrement operations can be written using a unary shorthand.

~reg3;
++Reg5;
--Control1Bits;
Reg5--;
Control2Bits++;

(Since statements each execute atomically, there is no difference between prefix or postfix notation for increment and decrement.)

READ INTO Shortcut

The READ statement normally reads values into Register E (REGE), so if you want to preserve the value you just obtained and perform another READ, you have to copy the value into another register. The READ INTO variation of the READ statement automatically inserts this copy code for you:

Read From 0x3200 Into Control1Bits; 
Read From 0x3201 Into Control2Bits;

Compiler Directives

You can add special directives to your code to change the behavior of the compiler. For example, any compiler option can be enabled or disabled in code via a special directive. This can be used to do things like temporarily disable optimizations to help ensure that a block of code runs exactly as you have written it.

Options/Features are enabled by adding a plus character to the end of the option/feature and are disabled by adding a minus character.

#DisableOptimizations+
#EnableIntrinsicCommands+

Optimizations

The 10LC compiler will perform a few optimizations when it detects static constant tests or redundant code. For example, assigning a register to itself usually does nothing other than waste code space and will be optimized away by the compiler. Likewise, an IF expression that will always be true will optimize to the resulting GOTO statement, and an IF expression that is always false will be optimized away entirely.

Value = Value;                           /* Will Be Optimized Away */
If ~Reg1 == ~Reg1 Goto OptimizedLabel;   /* True-Optimized To Just The GOTO */
If ~Reg1 < ~Reg1 Goto OptimizedLabel;    /* False-Optimized Away*/

Debugging Steps

A “step over pause” can be simulated by inserting code in-between each compiled statement that calls a program that shows the source code line number and pauses execution until you press Yes/Enter. This feature is enabled and disabled by compiler directives in your code. For example, the following code would cause cause a pause and the line number to be shown before the execution of each of the last two WRITE operations.

Write @ 0x2323 = 127;
Write @ 0x2324 = 128;
#DebugStep+
Write @ 0x2325 = 0x20;
Write @ 0x2326 = 0x40;
#DebugStep-

Address Range Validation

If you specify the SetupPod statement and select a Pod, information about that Pod's CPU is used to do things like validate address values. For example, if you select a Pod whose CPU only has a 14-bit address space, and then in a program you specify an address that exceeds that 14-bit range, a warning is issued by the compiler. This can help you find out-of-range addresses before you actually run your code.

Checksum Calculation

The compiler executable has the feature of being able to calculate 9010A checksum values. It can do this with single files, multiple files, and even files contained within ZIP archives. It can output information in one of three ways: standard, minimal or CSV.

Example of standard output from calculating signatures on galaxian.zip:

Extracting files from D:\MAME\roms\galaxian.zip
D:\MAME\roms\galaxian.zip - 2048 bytes
1h.bin: 0x1BB5
D:\MAME\roms\galaxian.zip - 2048 bytes
1k.bin: 0xE28A
D:\MAME\roms\galaxian.zip - 32 bytes
6l.bpr: 0xC471
D:\MAME\roms\galaxian.zip - 2048 bytes
7l: 0x804C
D:\MAME\roms\galaxian.zip - 2048 bytes
galmidw.u: 0xFFDE
D:\MAME\roms\galaxian.zip - 2048 bytes
galmidw.v: 0x4055
D:\MAME\roms\galaxian.zip - 2048 bytes
galmidw.w: 0xFCD2
D:\MAME\roms\galaxian.zip - 2048 bytes
galmidw.y: 0x317B

Example of minimal output from calculating signatures on galaxian.zip:

1h.bin: 0x1BB5
1k.bin: 0xE28A
6l.bpr: 0xC471
7l: 0x804C
galmidw.u: 0xFFDE
galmidw.v: 0x4055
galmidw.w: 0xFCD2
galmidw.y: 0x317B

Example of CSV output from calculating signatures on galaxian.zip:

Source,Filename,Signature
"D:\MAME\roms\galaxian.zip","1h.bin","7093",
"D:\MAME\roms\galaxian.zip","1k.bin","57994",
"D:\MAME\roms\galaxian.zip","6l.bpr","50289",
"D:\MAME\roms\galaxian.zip","7l","32844",
"D:\MAME\roms\galaxian.zip","galmidw.u","65502",
"D:\MAME\roms\galaxian.zip","galmidw.v","16469",
"D:\MAME\roms\galaxian.zip","galmidw.w","64722",
"D:\MAME\roms\galaxian.zip","galmidw.y","12667",
features.1581793840.txt.gz · Last modified: 2020/02/15 13:10 by adminz