Dot Commands - the final word
Posted: Thu Aug 23, 2018 6:23 pm
This seems like a topic that never ends
But I think the end is here now as the main facilities of NextZXOS are finalizing.
This post is about dot commands in general and dot command generation by z88dk in particular. There are other posts here talking about dot command generation with z88dk but this one will supersede those and I'll edit the others to point here.
There are a number of issues that come up with dot commands - how to parse the command line, how to report errors back to basic, how to check core and nextzxos versions if needed, how to ensure basic is not contaminated, how to write large dot commands of any size. So this will be mentioned in the course of this post.
But first, a review of what a dot command is.
Dot commands are a means to execute a small program that returns to basic cleanly without interfering with basic's state. They are loaded and run from a divmmc page overlapping the rom at address 0x2000-0x3fff. While the dot command runs, the lower 8k is occupied by the esxdos page. So the rom is completely invisible and the dot command itself sits below main ram so it doesn't interfere with basic at all.
Below is a somewhat technical discussion of some things. You can skip forward to --> if you like.
Since esxdos is present in the lower 8k, dot commands can use the esxdos api as normal through "rst 8". However, where parameters are documented to be passed using IX, these are instead passed through HL. When the basic rom is present, IX must be used to pass parameters because code used to bring the esxdos page into the 0-8k area uses HL so what happens is after esxdos is brought in, IX is copied into HL so that the esxdos routines see the parameter in HL and not IX. While the dot command runs, the esxdos page is already there so those parameters are expected in HL. Most people put those parameters in both HL and IX so their generic routines always work. This is the case for the z88dk's c esxdos api as well.
Because the 48k spectrum rom is not visible while a dot command runs, you can't call rom routines directly. Instead there are two special rst to help with interaction with the rom. One is "rst 0x10" which will print the ascii code in register A to screen just like the standard rom's "rst 0x10". The esxdos page contains code at address 0x10 to do the necessary banking to call the rom 0x10 and return properly to the dot command. The second special rst is "rst 0x18" which allows the dot command to call the address specified after the rst. So eg "rst 0x18, defw ROM_ADDR" would call ROM_ADDR in the rom. esxdos has code at address 0x18 to handle all the necessary banking. One caveat - the rom routine cannot see your dot command's memory space so if memory addresses are passed to the rom routine, those must be in main ram. You can create space on the stack that doesn't interfere with basic and another way is to use the rom routine BC_SPACES to create space underneath the program. The advantage of the latter is that the basic system will automatically free the space reserved by BC_SPACES when the dot command returns to basic. Note that if BC_SPACES fails due to insufficient memory, the basic system will generate a "4 Out of memory" error and will not return to your dot command.
-->
Because dot commands are intended to provide facilities available from basic, they are not normally meant to change the existing basic environment. So it is normal to use "rst 0x10" to print information so that it works seemlessly with basic. On exit, the dot command reports an error to basic. No error, a canned esxdos error, or a custom error string (with final char having bit 7 set) can be returned. There are a few lines documenting the exit condition here ( https://github.com/z88dk/z88dk/blob/mas ... sm.m4#L864 ). An error returned will result in a basic error with the appropriate error message printed at the bottom of the screen.
Dot commands are so-called because they are started with a leading dot. A typical invoke might look like:
.test This is the command line
These can also be put into basic statements:
10 .test look at my command line: PRINT "hello"
When the leading dot is seen by basic, the dot command will be launched. In the examples above the binary "TEST" in directory /bin (esxdos) or /dot (nextzxos) will be loaded to address 0x2000 in divmmc memory and executed. Notice the different directories used by esxdos and nextzxos - this is something new with NextZXOSv1.99I - and this allows esxdos and nextzxos dot commands to be separated so there is no issue with esxdos-only or nextzxos-only dot commands being accidentally executed in the other operating system, possibly leading to a crash. esxdos dot commands wanted in the nextzxos environment should be copied into the /dot directory.
The dot command is started with a pointer to the command line. Both esxdos and nextzxos will pass a pointer to the first non-whitespace character following the dot command name in HL. In the cases above, HL will point to the letter "T" or "l" after ".test".
Notice that HL is pointing into the basic area. This means you must not modify the command line so that the basic area is not corrupted. Because this is a basic area, the end of the command line can be marked by 0, ':' or 0x0d. (HL itself may also be zero if there is no command line).
Nextzxos dot commands are also passed the complete command line including the current dot name in register BC. So in the above examples, BC points at the "t" in ".test". (Again BC may be zero if there is no command line).
Under esxdos, dot commands are limited in size to about 7k. The exact number varies with esxdos version because esxdos places some data at the top of the 8k divmmc page. Dot commands that are too large will crash or behave improperly.
Under nextzxos, dot commands can occupy the entire 8k space.
So those are the basics of dot commands as created by esxdos.
NextZXOS adds a new element. Because nextzxos manages allocation of memory pages, it is possible to create dot commands of any size without interfering with basic. z88dk calls these dotn commands and it will automatically generate these. This will be discussed in a following post.
Why the attention to both esxdos and nextzxos? Both will be used on the zx next. The nextzxos esx api (which is an expanded esxdos api) is only present when the system boots up as a zx next. If you boot up as a 48k or 128k spectrum, nextzxos is not there but esxdos is. Similary, when new cores appear, for example there may be uno or bare 48k/128k cores that come along, all these systems will use esxdos. But the zx next is a much more capable machine and using the nextzxos esx api in ways incompatible with esxdos (and other machines running esxdos) will be a thing to make the most use of the machine.

This post is about dot commands in general and dot command generation by z88dk in particular. There are other posts here talking about dot command generation with z88dk but this one will supersede those and I'll edit the others to point here.
There are a number of issues that come up with dot commands - how to parse the command line, how to report errors back to basic, how to check core and nextzxos versions if needed, how to ensure basic is not contaminated, how to write large dot commands of any size. So this will be mentioned in the course of this post.
But first, a review of what a dot command is.
Dot commands are a means to execute a small program that returns to basic cleanly without interfering with basic's state. They are loaded and run from a divmmc page overlapping the rom at address 0x2000-0x3fff. While the dot command runs, the lower 8k is occupied by the esxdos page. So the rom is completely invisible and the dot command itself sits below main ram so it doesn't interfere with basic at all.
Below is a somewhat technical discussion of some things. You can skip forward to --> if you like.
Since esxdos is present in the lower 8k, dot commands can use the esxdos api as normal through "rst 8". However, where parameters are documented to be passed using IX, these are instead passed through HL. When the basic rom is present, IX must be used to pass parameters because code used to bring the esxdos page into the 0-8k area uses HL so what happens is after esxdos is brought in, IX is copied into HL so that the esxdos routines see the parameter in HL and not IX. While the dot command runs, the esxdos page is already there so those parameters are expected in HL. Most people put those parameters in both HL and IX so their generic routines always work. This is the case for the z88dk's c esxdos api as well.
Because the 48k spectrum rom is not visible while a dot command runs, you can't call rom routines directly. Instead there are two special rst to help with interaction with the rom. One is "rst 0x10" which will print the ascii code in register A to screen just like the standard rom's "rst 0x10". The esxdos page contains code at address 0x10 to do the necessary banking to call the rom 0x10 and return properly to the dot command. The second special rst is "rst 0x18" which allows the dot command to call the address specified after the rst. So eg "rst 0x18, defw ROM_ADDR" would call ROM_ADDR in the rom. esxdos has code at address 0x18 to handle all the necessary banking. One caveat - the rom routine cannot see your dot command's memory space so if memory addresses are passed to the rom routine, those must be in main ram. You can create space on the stack that doesn't interfere with basic and another way is to use the rom routine BC_SPACES to create space underneath the program. The advantage of the latter is that the basic system will automatically free the space reserved by BC_SPACES when the dot command returns to basic. Note that if BC_SPACES fails due to insufficient memory, the basic system will generate a "4 Out of memory" error and will not return to your dot command.
-->
Because dot commands are intended to provide facilities available from basic, they are not normally meant to change the existing basic environment. So it is normal to use "rst 0x10" to print information so that it works seemlessly with basic. On exit, the dot command reports an error to basic. No error, a canned esxdos error, or a custom error string (with final char having bit 7 set) can be returned. There are a few lines documenting the exit condition here ( https://github.com/z88dk/z88dk/blob/mas ... sm.m4#L864 ). An error returned will result in a basic error with the appropriate error message printed at the bottom of the screen.
Dot commands are so-called because they are started with a leading dot. A typical invoke might look like:
.test This is the command line
These can also be put into basic statements:
10 .test look at my command line: PRINT "hello"
When the leading dot is seen by basic, the dot command will be launched. In the examples above the binary "TEST" in directory /bin (esxdos) or /dot (nextzxos) will be loaded to address 0x2000 in divmmc memory and executed. Notice the different directories used by esxdos and nextzxos - this is something new with NextZXOSv1.99I - and this allows esxdos and nextzxos dot commands to be separated so there is no issue with esxdos-only or nextzxos-only dot commands being accidentally executed in the other operating system, possibly leading to a crash. esxdos dot commands wanted in the nextzxos environment should be copied into the /dot directory.
The dot command is started with a pointer to the command line. Both esxdos and nextzxos will pass a pointer to the first non-whitespace character following the dot command name in HL. In the cases above, HL will point to the letter "T" or "l" after ".test".
Notice that HL is pointing into the basic area. This means you must not modify the command line so that the basic area is not corrupted. Because this is a basic area, the end of the command line can be marked by 0, ':' or 0x0d. (HL itself may also be zero if there is no command line).
Nextzxos dot commands are also passed the complete command line including the current dot name in register BC. So in the above examples, BC points at the "t" in ".test". (Again BC may be zero if there is no command line).
Under esxdos, dot commands are limited in size to about 7k. The exact number varies with esxdos version because esxdos places some data at the top of the 8k divmmc page. Dot commands that are too large will crash or behave improperly.
Under nextzxos, dot commands can occupy the entire 8k space.
So those are the basics of dot commands as created by esxdos.
NextZXOS adds a new element. Because nextzxos manages allocation of memory pages, it is possible to create dot commands of any size without interfering with basic. z88dk calls these dotn commands and it will automatically generate these. This will be discussed in a following post.
Why the attention to both esxdos and nextzxos? Both will be used on the zx next. The nextzxos esx api (which is an expanded esxdos api) is only present when the system boots up as a zx next. If you boot up as a 48k or 128k spectrum, nextzxos is not there but esxdos is. Similary, when new cores appear, for example there may be uno or bare 48k/128k cores that come along, all these systems will use esxdos. But the zx next is a much more capable machine and using the nextzxos esx api in ways incompatible with esxdos (and other machines running esxdos) will be a thing to make the most use of the machine.