Systems - iS-DOS/TASiS: how to write games for iS-DOS/TASiS (part 2).

Info Guide #11
iS-DOS/TASiS part 2
 How to “unplug” from the system
 and turn it back on. Loading principle
    block of codes and return to the shell

   Now, based on the above, we
we have enough information to
write games for iS-DOS/TASiS, practically
without looking back at such memory limitations─
ty, such as the presence in RAM of the OS kernel or system
variables. You can even write universal
games that can be run under any
iS-DOS, even under TR-DOS. For all this
it is only necessary that the resulting "code" files
were formed separately (as in old flax─
exact versions, and for the main RAM
files separately and for recording overlays in
pages are also separate files). Then for
versions for different OSes you just need to─
write your own bootloaders (in the case of TR-DOS
- directly in BASIC via RANDOMIZE USR
15619:REM:LOAD 'filename" CODE adress ), and
done (for 128K and higher versions of games
It would be nice to provide a flexible table
used pages with port settings
management). As for iS-DOS,
then here is the algorithm.
   To turn off the system and go to
"full" use of everything available─
A large address space is enough:
 1.Disable interrupts,keeping the knowledge─
value of the vector used by the system 
jerking for subsequent recovery, and 
then reassign it for use 
in user interrupts. 
 2.Save the stack pointer somewhere
in the system and reassign where you need the field─ 
to the caller. 
 3.Save in upper memory (by
easy copying or switching 
pages) the core of the system and, if necessary, 
provide at address #C000 or page 
0, or a page from the lower 128 KB. If 
it is possible to preserve the core, not in size 
exceeding 16 KB (i.e. fits into 
page in the area with #C000), then before that 
necessary by means of the system (about which 
will be discussed in the appropriate section─ 
le) organize a check of the value of the lower 
core boundaries. 
 4.If necessary, then use
data from system vector - restore 
standard RAM configuration with BASIC- 
48. TASiS may require a transition 
to screen mode 6912 and standard pali─ 
labor If this is done through the system 
(for which there are corresponding system 
calls), then this must be done before disconnecting 
kernels. 

   Accordingly, to turn on the system
back you need:
 1.Restore the kernel in the required country─
site at #C000 (for TASiS this is 
page 0). 
 2.Restore the necessary for Chic co─
memory configuration (enable RAM at address 
#0000 according to the system vector). 
 3.Restore saved pointer
stack and interrupt vector. Allow pre─ 
tearing. 
 4.In the case of TASiS, if necessary
restore the previous screen mode and pa─ 
liter (after completing step 3 this is already 
can be done through system calls). 
 5.If necessary, exit back to
system shell (more on this below). In case 
exit to the shell in the TASiS system, previous 
system screen mode and palette recovery─ 
are poured automatically, which means step 4 
disappears. 

   And now more specifically.
   For 48K toys that don't know about the creature─
port#7FFD, alternative screen
and other things, everything is extremely simple: do not use─
use page#00 (or the page that
enabled normally from the address#C000 ) in general.
Instead, just substitute lyu there─
buoyanother page or with pre-
with the game code uploaded there, or from a copy─
placed there after substitution. More precisely,
if a block of game codes temporarily fits into
the gap between the end of the bootloader and hell─
resom#C000, then the algorithm is as follows:
 1.Check whether the core is sticking out below
#C000. 
 2.Uploading a block of codes to a free site─
earlyness 
 3.Disable interrupts, reassign
stack and interrupt vector. 
 4.Include a free page in #C000 and
transported via LDIR or LDDR (or 
unpacking) block of game codes for the necessary hell─ 
res, and then - reconfiguring the address─ 
space, graphics and palette, and 
CALL game. 

   If the block of codes is too long and not
fits into free space, then
we do it differently. Call system means─
they can upload files in parts to any pro─
in arbitrary sequence and in chunks
selected length. Algorithm in the case of iS-DOS
Chic is like this:
 1.Check whether the core is sticking out below
#C000. 
 2.We load the “tail” of the code block, which
should be locatedabove #C000 in freedom─ 
new space and then copy it to 
page that will be included instead 
core pages. 
 3.We load the rest of the code block from
download addresses up to #C000. 
 4.Disable interrupts, reassign
stack and interrupt vector. 
 5.Include that free country in #C000─
tsu, where the “tail” of the code file was loaded, and 
then we reconfigure hell─ 
natural space, graphics and palette, and 
CALL game. 

   The procedure is very similar for
programs that use 128KB pages. Exactly
also code blocks in the form of overlays
files are pre-loaded into the required
pages. At the same time, it is necessary to exclude from the system
using the page with the core, or time─
but save it in the upper memory.

   Let me illustrate the above information─
mation in code examples. As I already mentioned─
it turns out that the system is called through a single
entry pointRST #10. In this case, the function number─
tions are contained in registerC, and in the rest
registers, if necessary, are transferred up to─
additional data. At the output we get
signNC - the call was processed successfully. In OS─
tal registers can be used if necessary
return data is located.  If
at the output signC, then this is an error sign─
ki, then in registerA is the error number. If
When exiting the shell, set the flagC and
into the registerA write any number, then output
in the shell will occur with the message"Error
{specified number}".  So, for example, number
out of memory errors -130.

   We need the next challenge to pre─
preliminary assessment of the environment (in this case
to determine whether the core has sunk
below#C000 ):
 Restart $g_cnfg (register C=#10).Input─
there are no other parameters. At the exit to alterna─
tive registerHL' address of the config vector─
OS kernel radios (in other words - pointer
on the location of system variables). There
there are a lot of useful things. But now we are inter─
resect data at offset5 - it is stored therepointer to the lower cache level (below the
where the user area begins).
Knowing this, we can organize a check
free space:

freesp
LD C,$g_cnfg;or you can directly LD C,#10
RST #10
 EXX;"open" alternative
        ;registers for accessing HL'
LD BC,5+1;+1 instead of INC HL below
ADD HL,BC;set the pointer
          ;system vector to cache boundary
    ;INC HL ;address high byte
LD A,(HL)
CP #C0;if cache boundary < #C000,
           ;then setting flag C
LD A,130;error message number
             ;(low memory)
 RET C;exit to shell with message
          ;about an error in case of shortage
 ...;if everything is OK, continue the program
        ;(if necessary)
 RET;necessary if we design it as
        ;subroutine

   And the main body of the block loader itself
codes (for simplicity we take only 48K VA─
riant) and shutting down the system will look like─
something like this:

ORG 24000;beginning of the COM file
 CALL freesp;checking the lower bound of the kernel
 RET C; if not enough, we exit with error 130
         ;(set in subroutine)
 CALL loadfl;load the code block into
                ;user area
                ;(we'll look at it separately)
 RET C;return to shell if
          ;there was an error loading
 CALL scrpal; enable 6912 mode and
                ;standard palette
 DI;start the shutdown procedure
       ;systems
 LD (buffer),SP
LD SP,...;reassign the stack
LD A,#3B
 LD I,A
 IM 1
LD A,#11
LD BC,#7FFD
 OUT (C),A; turn on ROM-48 and page
              ;RAM #01 (for example)
LD HL,...
 LD DE,usrbuf
LD BC,...
LDIR;or LDDR. Moving the loaded
         ;game code to its “rightful” place
EI
 CALL usrbuf;start the game

;well, here, if the toy is from a block of codes 
;exit back via simple RET, 
;there may be a return procedure in 
;TASiS shell: 
DI
 XOR A
 LD I,A
IM 2
LD A,#08
LD BC,#7FFD
 OUT (C),A; turn on BAS-128, where instead
;he's been around for a long timeRAM page configured, 
;alternate screen page 
;and RAM 0 at address #C000 
LD SP,(buffer);recovering the stack
EI;now the system is working again
 XOR A; set the Z flag
          ;(to be executed by the shell
          ;related command)
    ;OR A ;reset the CY flag for
          ;"error-free" output
LD A,#F4;shell command for
             ;redrawing the panel (after all, on
             ;screen after the game - "garbage")
 RET;exit to the shell. Graphic
     ;mode and palette in TASiS
     ;will be restored automatically
buffer
 DEFW 0
 ...
usrbuf

   If for some reason you restore
stack is impossible, then instead of finalRET
you can use direct restart you─
call of the shell, having previously done you─
The above manipulations with flagsZ, CY and
registerA:
Restart$shout (register C=#84).Exit to
shell with execution of a special command. Login─
data: if the flagCY is set, then
register A - error code (error handling
we looked at the example of a shortage error
memory130 ). And if the CY flag is reset, and
Z - raised, then exit to the shell
with execution of the special command specified in re─
gistre A. In our case, it is enough for us
commands #F4 - panel reprint. In this
in this case, the system itself will restore the one it needs
stack pointer. There is only one minus here -
will not be able to be launched from BAT files.
More precisely, it’s possible, but after coming out like that “cree─
in this way, further execution of BAT-
file will simply be interrupted, and you will find yourself in
shell.

   TASiS has another way to access
shell. It should be used in those situations─
teas, when, for example, you adapted
under the system is a regular ZX toy, which is not
knows no way out of itself back─
but in the block of codes that called itsubroutine
but just “fixated” in my gaming environment─
de. In this case, it is simply necessary to restore
using a resident is an opportunity for you─
call of the user program hosted
in the upper memory in the pageRAM #1F def─
divided by pressing a button
"RESET". Specifically, the structure of the resident
next page.
   So that a program placed on a page
#1F, was recognized as a resident, she
must be designed in a special way.
In accordance with this, the page has the following─
blowing structure (hereinafter indicated by displacement─
from the beginning of the page):

#0000 - code #C3 (command JP nnnn)
#0001-#0002 - transition address for JP nnnn
 (calculated by the formula:
     #C000+relative start address
     programs on the page).
#0003-#ЗFFC - free space
 directly under the program.
#ЗFFD - checksum (CS) of the entire
 pages (that is, from #0000 to #ЗFFF).
#ЗFFE - must always be equal to #55.
#ЗFFF - must always be equal to #AA.

   When creating a resident, the CC calculates─
Xia by addition without taking into account the transfer (then
eat by ADD command) one after another
all the bytes of the page and then subtract
the resulting amount from zero (by command NEG
processor). At the same time, since in the process
It has not yet calculated the checksum─
hay per byte#ЗFFD, before starting under─
score KS should be equal to#00(!). And this one
the moment must be taken into account when
when there is a need to recalculate the COP.

   The page laid out this way
will be successfully recognized as resident,
and the ROM firmware will begin the startup procedure
resident, which consists of the following:
 1)The resident is turned on at address #C000─
page #1F. 
 2)At address #8000 in both memory cards─
ty (both at ROM2=0 and at ROM2=1) is turned on 
RAM page #02. 
 3)Control is transferred to the resident on
address #C000, where the co─ should be located 
resident mand JP nnnn. 

   After transferring control to resident ar─
The architecture looks like this:
 1)Stack location (SP value) -
not defined. Remains ondiscretion re─ 
Zidenta. 
 2)Memory card in addition to address #8000 -
#BFFF (and pages #1F with resid running─ 
ntom at address #C000) - not defined. So─ 
remains at the discretion of the resident. 
 3)The state of the palette is not defined.
It is also at the discretion of the resident. 
 4)Interrupts are in IM 2 mode,
included. The interrupt vector is #82FF 
(I=#82).  Thus, interruptions are necessary 
either prohibit it, or, if working with them is 
a short period of work for a resident (while he 
installs the main program) necessary─ 
Dima, for example, to set the palette, then 
you need to set the address under─ to #82FF-#8300 
interrupt handler programs. In pain─ 
Dente Honey Commander there is a sign there 
to the nearest RET. 

   Thus, the programmer when developing
The resident’s bot is not bound by any rules─
mi and restrictions, since the resident is not
tied to any operating system
and is not obliged to take into account its features. Ka─
what will be the computer configuration after
restart to resident is determined by yourself
resident

   In our case, it will be necessary to
save the initial game loading procedure in
page #1F resident subroutine,
data aboutstack value, interrupt mode─
tions, address space configurations and
calculate the checksum.  And then
after the "RESET" command, this subroutine
the saved data will install the kernel for a month─
then it will reassign the memory card. In general -
will do almost everything that is described
higher when exiting to the shell. There's plenty left─
It turns out that as a standard, residents in TASiS co─
store the RAM area from #C000 to #FFFF in
page#1C, therefore without the presence of additional─
recommended if necessary
their programs when creating a resident also
use this page.
   Now in order to successfully write
and run your own game under iS-DOS/
TASiS, all we have to do is sort out the whole thing─
how many system calls.

    Opening and loading files in iS-DOS

   In the bootloader example above
we temporarily bypassed issues of our own─
actually loading data from disk and switching─
graphics, leaving them for last and about─
meaning they are calls to routines like"CALL
loadfl" and"CALL scrpal" respectively. Those─ 
let's look at them specifically. For
started about booting from disk.
   There are many ways and possibilities─
features of operating files, directories,
subdirectories and fragments of files for free─
bykhlogical disk devices (outside
depending on physical media, so
how all the main work goes through accordingly─
available drivers), including search, sort─
taste according to template, create, delete, rename─
newing, adding and “cutting off” parts,
sequential and random access and
much more. But a description of all is possible─
tey is a separate work of large volume.
Those interested in the system can ─
you can study all the restarts yourself,
fortunately the system is well documented and
description available online. And the given
In this article, examples will help you understand the OS─
new principles and will continue to grow confidently─
expand your skills on your own. Therefore
Next we will look at downloading files using
simplified diagram.
   Namely, it is assumed that everything is valid─
events occur in the current subdirectory,
where the control code was loaded from
COM file of our executable program (and by
By default, restarts work exactly like this
subdirectory), we know in advance the name and
file size, and we also know where it goes
or parts thereof to ship.
   Uploading a file (like any other opera─
tion with files) consists in iS-DOS of two
stages: searching/opening the file and actually
operation of exchanging data with it. Compliance─
It is to these stages that we present systemic challenges─
you:

   Restart$fopen (register C=#25).Search and
opening a fileby name and extension. On
inputHL - pointer to 11-byte address─
vogo (8 bytes name and 3 bytes extension)
file descriptor. Generally a standard opi─
The file size is 32 bytes (their descriptions─
below), but only ─
to 11 bytes directly of the name. If the file
found, then it opens. If found
file is a subdirectory, then it opens─
tie and transition into it. Output: if everything
passed without errors (flagCY is reset), then
registerA:
A=#00 - file is open;
A=#20 - the directory is open.
In alternative registerHL' - decree─
tel to the address of the system 32-byte opi─
file file, where based on the results of the rest─
mouth contains the data of the currently opened
file.
   Possible errors (flagCY is set):
A=81 - file not found;
A=85 - broken segment descriptor block
 (current or search directory);
A=86 - broken directory.
Errors 85 and 86 may occur in the case of
in case of damage to the file system on the device
as a result of some other, external to the pro─
grams of circumstances and under normal conditions
should not arise.
   32-byte file descriptor values
the following:

+0 (8 bytes) - name.
+8 (3 bytes) - extension.
+11 (1 byte) - flag status register
 file. Bits (0/1):
 0 -deleted/exists
 2 -read protected (1)
 3 -write protected (1)
 4 -visible/hidden file
 5 -file/directory (root file)
 6 -segmented/continuous
 7 -protected from deletion (1)
+12 (2 bytes) - default download address
+14 (3 bytes) - length in bytes.
+17 (2 bytes) - number of the seg descriptor blockment (for a continuous file - number
  zero block of the file).
+19 (1 byte) - "Special" byte: uses─
 as a rule, in system files for
  bootstrap or reconfigured─
  niya.As a rule, bits0..2 (range of values─
 0..7) contain the system level number
  we are in SYS files when loading/replacing but─
  levels to the core. In TASiS bit3 (meaning
 byte=8) - the output attribute is not proper─
  private, and internal 38-byte name
  to the shell file panel.
+20 (2 bytes) - not used in regular files─
 is used. In the OS kernel system file (opi─
  satelis_dos.sys )contains the used
 loader SP stack installation address.
+22 (1 byte) - not used in regular files─
 is called. In the OS kernel system file (opi─
  satelis_dos.sys )contains the value ve─
 interrupt maker in the system, transmitted
  into register I by the bootloader at initial─
  installation of the system (#3B in Classic,
  #06 in Chic, #00 in TASiS).
+23 (3 bytes) - reserve.
+26 (2 bytes) - file checksum.
+28 (2 bytes) - time.
+30 (2 bytes) - date.

   Restart$rpart (register C=#29 ). Reading
file or its fragment.
   Input data:
DE - how many bytes are read
AHL - offset from the beginning of the file in bytes,
 where we start reading,
IX - address in RAM where we read.
Possible output errors (flagCY=1):
A=100 - attempt to read beyond the end of the file
 (i.e. AHL+DE is greater than the file length, which─
   ryu, as described above, can be obtained from
   descriptor in HL'+14).
A=106 - file is not open.
A=170 - reading 0 bytes (DE=0).
A=171 - the file is read-protected.
A=7 - read/write error (usually
 physical. Returned by driver bottom─
   whomlevel).

   We would like to remind you that this restart
does not check which system area of RAM is in
we are uploading the file. And determine whether it will get overwritten
file is the core of the system, the programmer must. If
Are you confident in your actions and in
that the downloaded file does not cost anything extra─
rubs, then the procedure for loading a file “from scratch”
in RAM (assuming that its length is not more than
exceeds 65535 bytes, i.e. it takes no more
16 bits in the descriptor) will look like this:

loadfl
 LD HL,filename;pointer to 11-byte─
                   ;new file name template
LD C,$fopen;or you can directly LD C,#25
RST #10
 RET C;if error, exit
 EXX;get a pointer to the descriptor
PUSH HL;open file
 POP IX; move the pointer for
           ;convenience in the index register

;if desired, we can arrange an inspection 
;checksum of the file in case it is possible─ 
;noy substitution (checksum can be 
;find out using OS system utilities) 
LDA,(filename+26);take the 1st byte
                ;checksum pattern
CP (IX+26);compare with similar
               ;byte from descriptor
               ;open file
JP NZ,error;go to the procedure
                ;exit by error (which
                ;sets the required flags and
                ;register values)
 LD A,(filename+27)
 CP (IX+27)
JP NZ,error;similar to the second
                ;checksum byte

;preparing data for loading: 
LD E,(IX+14);take it from the descriptor
                 ;file length (less than
                 ;than 65536 bytes)
LD D,(IX+15);if we know in advance
                ;length of the downloaded file,
          ;then we just do LD DE,filesize
 XOR A; write zeros to the offset from
          ;beginning of the file. If we
LD HL,0;load part of the file (for example,
          ;for transfer to RAM page),;then write down the corresponding
          ;values in AHL (offset)
          ;and DE (length).
LD IX,ramadr;where we load. If
               ;planned to call
               ;loading in parts
               ;several times, value IX
               ;needs to be temporarily saved.
LD C,$rpart;or you can directly LD C,#29
RST #10
 RET;file loaded, return to
       ;the original program from the subroutine
       ;downloads. At the exit there should be
     ;checking the CY flag for errors.
;If the subroutine plans 
;continuation, for example to load another 
;file fragment, then here you need to put 
;RET C - exit by error 

error
;error exit handler control. amounts 
 SCF; set the error flag -
        ;flag CY=1
LD A,81;indicate that "file not found"
 RET
filename
 ...;11 (minimum) or more (up to 32);file name pattern byte

   Thus, knowing the structure of the descriptor
files and the two above disassembled system re─
start, we can upload in whole or by
parts of any file. At the end of the section only
As an example, I’ll give a similar restart on
writing to an already existing file is defined─
no length:
   Restart$wpart (register C=#2A) - write
DE byte to the current open file with offset─
nia AHL byte from the beginning of the file from the address in
IX. It, like other recording capabilities
and creating files, it is proposed to study
on your own.

Share your thoughts about the article