From
Alexander Bondarenko
→
To
All
22 April 2004
*** Also sent to CODE.ZX (For those who know how to code...)
*** Also sent to ZXNET.SOFT (Softina...)
*** Also posted in EKB.PROGRAMMING (Online programming.)
Hello, All!
To build the capacity of a "smart" library of procedures under
I need help from coders. Need ideas, suggestions, etc.
I provide a brief description of the library for those who are interested.
==================================================================================
LIB+
The LIB+ library (currently in
development) is a collection of all sorts of useful
procedures and subroutines, so far there are only about 30 of them. She
designed for assembler alasm - as the only one in real life, on
currently an assembler that supports conditional translation.
The general organization of the library is such that the programmer cannot
you need to monitor it in no way, except how to determine
one service variable (and only if it is needed). For
To “call” the library you just need to enter at the end of the program:
INCLUDE "LIB+"
In this case, it will automatically be determined which procedures
need to compile and which ones don't. The program itself has enough
explicitly indicate the procedure label somewhere so that it can be used later
linked:
CALL Procedure
or
LD BC,Procedure
LIB+ file - the main module of the library, defines the statelabel and in case it is used but not defined,
makes an INCLUDE of the auxiliary file, which contains
procedure.
Library auxiliary files contain procedures
a certain topic. Total currently exists
the following set of these files:
SCREEN_P - procedures for working with screen addresses
WINFX_R - procedures for various effects with windows on the screen.
PR_R - three printing procedures, respectively on 42, 51
and 64 characters per line. Option - for character by character
prints, fast. But for text leaflets
Another option is preferable - lowercase.
MEM128_P - procedures for working with upper memory pages
(currently - only for 128k)
WINMAN_P - window manager, allows you to specify such and such a window
as the current one, or “clear” the parameters of the current window
PRNMAN_R - print procedure manager, allows you to set
print procedure as current, print from it to
current window and immediately switch to others
printing procedures. Automatically pairs with
WINMAN_R.
INPUT_P - keyboard polling procedures (via 48th ROM)
These files can be called in a program separately from LIB+,
which will allow you to compile sets specific to the topic
procedures to a specific place in the code. You can refuse altogetherLIB+, but then you will have to monitor the compilation process yourself.
Letter R or P at the end of the auxiliary file name
means whether it can exist independently, without
the need for other supporting files. If the name
ends with _P, which means it can. Library hierarchy:
+----->WINMAN_P
|
|
PRNMAN_R-----+ WINFX_R------>SCREEN_P
| ^
| |
+----------->PR_R------------+--->FONT42, FONT51, FONT64
MEM128_P
INPUT_P
When using LIB+, you can specify the page after INCLUDE,
where the entire set will be loaded during compilation. There is
also the ability to load LIB+ in one place, and auxiliary
files - to another. This is set by the _LPG1 variable. If she
defined, then all auxiliary files will be loaded into
page whose number is contained in _LPG1. This is made for
partial acceleration of the compilation process.
Individual procedures may be modified depending on
whether any other procedures are used, more or less
related to these. For example, the SET_WIN procedure (task
current window), when using the PRNMAN__R module, there will be, in addition
setting the screen window itself, recalculating and forcurrent printing procedure. If the PRNMAN_R module is not
is used, then in SET_WIN there will not even be a hint of code,
involved in this recalculation. Or - all special effects procedures
with a window, when using WINMAN_R, are endowed with a second point
input (CW_ + name of the special effect procedure) - for working with
current window (does not require explicitly setting window parameters). But this
"endowment" occurs again if it is somewhere
was called.
The library allows you to organize the source code of the program more
culturally and in some places even “thinks” a little for the programmer.
Here is a list of library procedures:
SCREEN_P - working with screen addresses
SCRADR - calculation of the address on the screen using familiar coordinates
in DE (YX) and placing it in HL
ATRADR - the same, but for the address in the attributes
SCPXADR - the same, but for the address on the screen and by pixel
coordinates
SCR2ATR - convert screen address to HL for
the corresponding attribute.
DNHL - recalculation of the screen address in HL by the line below
UPHL - the same, but the line is higher
DN8HL - the same, but 8 lines lower
UP8HL - the same, but 8 lines higher
PR_R - printing procedures
This module requires 3 font files for procedures -
FONT42, FONT51 and FONT64. If labels of the same name are already defined,
then the font will not be loaded, which also allows
link fonts manually to a specific place in the program.PR42, PR51, PR64 - symbol printing procedures. Printable
symbol - in A.
GTXY42, GTXY51, GTXY64 - positioning procedures
"carriages". DE - print coordinates in matrices.
PRLIN42, PRLIN51, PRLIN64 - print one line of a character. A-
symbol, DE - print coordinates in matrices, B - line number in
familiarity, H is the address of the symbol line. Auxiliary procedures.
WINFX_R - a set of special effects. For these procedures, the window coordinates
are specified in DE (YX), window dimensions - in BC (height/length). Everything according to
acquaintances.
CLRSWN (window version - CW_CLRSWN) - clear screen
window area
FILAWN (CW_FILAWN) - fill the attribute area with a byte
windows
RMKWIN (CW_RMKWIN) - draw a frame around the window. Frame -
rectangular line 1 pixel thick, filled with 0 - around
windows (work is carried out on the area bordering the window, so
a window should always have this area around it if it is
adjacent to the screen border, there will be glitches), and the same line -
along the bottom and right border of the window rectangle, filled with 1.
SLC_WIN_UP (CW_SLC_WIN_UP) - scrolling the window up by
familiar place, with attributes.
SLP_WIN_UP (CW_SLP_WIN_UP) - scrolling the window up by a pixel
SLP_WIN_DN (CW_SLP_WIN_DN) - scrolling the window down by pixel
MEM128_P - procedures for working with upper memory pages.
SET_PG - set current page to A
PUSH_PG - store the current page number on the stackPOP_PG - restore page number from stack and set
her
WINMAN_P - small window manager
SET_WIN - set the current window (DE - YX, BC -
height/length). If the window extends somewhere beyond the screen, then it will
adjusted to its size.
GET_WIN_INFO - get the parameters of the current window.
PRNMAN_R
SET_CUR_PR - set the current printing procedure (address - in
HL)
PR_WIN - print the character (A) in the window
PR_STR_WIN - print a string (address in HL, ends with 0 or
13)
GTXY_WIN - positioning the carriage inside the window
INPUT_P - keyboard polling via 48th ROM
INKEY48 - number of the pressed key in A
==================================================================================
In general, what exists at the moment is by no means
helicopter, there is still plenty of work to be done on the library.
I hope for the support of the people.
Best regards,
Alexander.
From
Kirill Frolov
→
To
Alexander Bondarenko
5 May 2004
Press RESET immediately, Alexander Bondarenko!
On Thu, 22 Apr 04 13:58:20 +0400, Alexander Bondarenko wrote:
AB> To build the capacity of the "smart" library of procedures under
AB> I need help from coders. Need ideas, suggestions, etc.
AB> Here is a brief description of the library for those who are interested.
AB> ================================================================================
AB> LIB+
AB> LIB+ library (currently in state
AB> developments) is a collection of all sorts of useful
AB> procedures and subroutines, so far there are only about 30 of them. She
I somehow have similar thoughts, but nothing moves.
At the moment there are:
1) integer mathematics.
2) ASCIIZ strings.
3) text console (alas, not compatible with either ANSI or VT100).
4) absolutely minimum for the output in step 3.
5) the beginnings of dynamically loaded modules (DLL)
Planned:
6) mathematics with floating point (the code actually already exists)
7) memory manager
8) "Pascal" strings, associative arrays and others
data structures (need point 7)
9) file system...10) object implementation of everything else... (instead of point 5.)
11) creation of a simple interpreted language based on 10
clause 7. puzzling... There is a debugged C analogue, it needs to be transferred to
Z80 assembler.
AB> is designed for alasm assembler - as the only one in real life, on
AB> currently an assembler that supports conditional translation.
Alas, the glitches there are through the roof. And most importantly, a number of such stupid
restrictions that they simply do not allow them to be used (64 characters per
line, write only in capital letters - even though I can’t cut it...)
I'm counting on ZAS (C) Hitech Software for PC, C preprocessor,
and I have SED scripts for converting sources to ZASM or ALASM. Since in
"converter" gets pre-processed text, special
requirements for the assembler in terms of conditional compilation and all that already
not presented. On the other hand, the Spectrum version of the code
It turns out that it is only suitable for compilation, it cannot be edited.
Well, not everything there is transferred “head-on” either...
AB> The general organization of the library is such that it is not possible for the programmer
AB> you need to monitor it in any way, except how to determine it
AB> one service variable (and only if it is needed). For AB> "calling" the library just needs to be entered at the end of the program:
AB> INCLUDE "LIB+"
Yes, in Spectrum (as opposed to pisishnoy, for ZAS, although it
in CP/M and on Spectrum you can...) versions I do the same. Otherwise
no way. But there are also inconveniences: you need to recompile everything at once,
symbols from different modules get mixed up. Actually, this is the reason for the bias
towards the DLL - actually the only point of contact
library and program, its interface remains, but what’s inside already
It doesn't matter at all.
AB> In this case, it will be automatically determined which procedures
AB> should be compiled and which ones should not. The program itself has enough
Alas. Fuck it! If there are any fairly complex dependencies,
this is bound to cause problems. Like A depends on B
and B depends on C. You include A. You include C in the text before
inclusions A. It will be a bummer. You have to include one source by N
just write (in ZXASM notation) these horrors:
IFNDEF blablabla
IFUSED blablabla
blablabla:
function code
ENDIF
ENDIF
Well, often if one function lasts, then the entire module is needed.
Lots of inconvenience...
AB> SCRADR - calculation of the address on the screen using familiar coordinates
AB> in DE (YX) and placing it in HL AB> ATRADR - the same, but for the address in the attributes
AB> SCPXADR - the same, but for the address on the screen and by pixel
AB> coordinates
AB> SCR2ATR - converting screen address to HL for
AB> corresponding attribute.
AB> DNHL - recalculation of the screen address in HL by the line below
AB> UPHL - the same, but with a line higher
AB> DN8HL - the same, but 8 lines lower
AB> UP8HL - the same, but 8 lines higher
This should be done exclusively with macros! Only 28 per CALL
There are the same number of clock cycles for juggling registers. What will remain?
AB> In general, what exists at the moment is by no means
AB> helicopter, there is still plenty of work on the library.
AB> I hope for the support of the people.
I think the library is useless. Its /Spectrum/ assembler
impossible to assemble (in writing this is a standard feature). Yes and
the possibilities are very limited. I already talked about the advantages of DLL
I described it, but there are plenty of problems there too. You need Spectrum COM!
(with an eye on Microsoft). But how can this be realized without thoseI don’t even know the crutches that Microsoft came up with. As long as there is a system
modules, but it is already clear that it is missing many things, although he himself
principle, in general this is the technical side of the issue, the principle itself
combining the code of two programs through a predefined interface
it is the same everywhere (see the next letter).
A short list (a detailed list does not fit in SPBZXNET’s letter) of my
"libraries":
[[[ note: in general, many functions in terms of arguments and their purpose
compatible with the standard C library. So if it's not clear
what a specific function does, I advise you to look at man, or what
do you have there...
]]]
exit_48
exit_128
exit_trdos
exit_run
call_magic ; Simulates pressing the Magic button.
setim2vec ; Setting the interrupt vector for IM2 mode.
im2_enter ; The function stores the contents of all registers on the stack...
im2_leave ; The function restores the contents of all registers...
setjmp ; The function saves the program context for return...
longjmp ; The function returns to the point where setjmp... was called.
case ; The case function navigates through the table depending...
findfile ; The function searches for a file on the current disk whose name is specified...
findfirst ; The function searches on the current disk for the first file specified by the mask...
findnext ; The function searches the disk for the next file after...
fcbtoname ; The function transfers the file name from the FCB specified by the register...nametofcb ; Функция переносит имя файла из строки заданной регистром...
isalnum ; A=char -> A=char, Z=1 if A is digit or letter
isalpha ; A=char -> A=char, Z=1 if A is letter
isascii ; A=char -> A=char, Z=1 if A is ascii char.
isblank ; A=char -> A=char, Z=1 if A is space or tab.
isdigit ; A=char -> A=char, Z=1 if A is digit
islower ; A=char -> A=char, Z=1 if A is lowercase letter
isprint ; A=char -> A=char, Z=1 if A is printable
ispunct ; A=char -> A=char, Z=1 if A is puntuation char.
isspace ; A=char -> A=char, Z=1 if A is space
isupper ; A=char -> A=char, Z=1 if A is uppercase letter
isxdigit ; A=char -> A=char, Z=1 if A is hexadermal digit
memcmp ; memcmp(DE=*src, HL=*src, BC=size)
memmove ; memmove(DE=*dst, HL=*src, BC=size)
strglob ; HL=*string, DE=*mask -> Z=1 if found
strstr ; HL=*string, DE=*search -> Z=1 & HL=*ptr
strlcpy ; strlcpy(DE=*dst, HL=*src, BC=maxsize) -> HL=*0(dst)
strlcat ; strlcat(DE=*dst, HL=*src, BC=dstsize) -> HL=*0(dst)
strcat ; strcpy(DE=*dst, HL=*src) -> HL=*0(dst)
strcpy ; strcpy(DE=*dst, HL=*src) -> HL=*0(dst)
strncpy ; strncpy(DE=*dst, HL=*src, BC=maxsize) -> HL=*0(dst)
strncat ; strncat(DE=*dst, HL=*src, BC=size) -> HL=*0(dst)
strlen ; HL=*string -> HL=BC=length (without term. 0)
strchr ; strchr(HL=*str, A=char) -> Z=1 & HL=*char
strcmp ; strcmp(DE=*str1, HL=*str2) -> ZF, CF, SFstrncmp ; strncmp(DE=*str1, HL=*str2, BC=size) -> ZF,CF,SF
strcmpi ; strcmpi(DE=*str1, HL=*str2) -> ZF,CF,NF
strncmpi ; strncmpi(DE=*str1, HL=*str2, BC=size) -> flags
strreverse ; reverse string, HL=*string
strlower ; convert to lowercase HL=*string
strupper ; convert string to uppercase HL=*string
strcspn ; HL=*string, DE=*separators -> BC=HL=count
strpbrk ; HL=*string, DE=*separators -> Z=1 & HL=*char
strrchr ; HL=*string, A=char -> Z=1 & HL=*char
strrpbrk ; HL=*string, DE=*separators -> Z=1 & HL=*char
strrspnp ; HL=*string, DE=*separators -> Z=1 & HL=*char
strsep ; HL=*string, DE=*separators -> Z=1 & HL=*token & DE=*next
strspn ; HL=*string, DE=*separators -> BC=HL=count
strspnp ; HL=*string, DE=*separators -> Z=1 & HL=*char
swab ; swap byte pairs HL=*src, DE=*dst, BC=size
tolower ; A=char -> A=lower case char
toupper ; A=char -> A=upper case char
atow ; HL=*str -> HL=number, DE=*last_char+1 || error CF=1, HL=*err_pos
htoa ; hex2ascii A=0..0ffh, HL=str[3] -> HL=*0(str)
wtoa ; decimal2ascii HL=string[6], DE=number -> HL=*0(string)
ltoa ; long2ascii (DE,BC) HL=string[11] -> HL=*0
amul ; hl = hl + a*de ~338 takts.
crc16 ; ix=*data, bc=size, de=polynom, hl=crc -> hl=crc
crc16_init ; de=*(512bytes), bc=polynom
crc16_fast ; ix=*data, bc=size, de=tab*512, hl=crc -> hl=crc
div ; hl = de/bc de = de%bc ~840 takts.
flatcher ; ix=data, bc=size -> hl=code
i2bcd ; bin(HL) -> bcd(E,H,L)
l2bcd ; long_bin(DE,HL) -> bcd(C,D,E,H,L)
labs ; long (HL
From
Kirill Frolov
→
To
Alexander Bondarenko
5 May 2004
Press RESET immediately, Alexander Bondarenko!
On Thu, 22 Apr 04 13:58:20 +0400, Alexander Bondarenko wrote:
So about the modules:
Introduction
There is a lot of system-independent code that can be written without
modifications, or with minimal effort, used as in TR-DOS
programs, both in Aqua-OS and in other D2k and X-DOS, BeeOS...
pseudo-operating systems for ZX-Spectrum.
Of course, you can always pick up the source texts, but they may be
are not available, this may require a certain version of assembler,
incompatible with the one used (such as ZASM and ALASM), finally
dynamic becomes unavailable (at the time of program execution)
uploading code, nor sharing it among several
programs. What happens is that programs increase in size, with
the fact that they contain almost the same code. And their support, in case
when parts of code from different people are used, it becomes simple
impossible - for example, if one author released a new version
device driver, then how will it force another author to use
it in your program, instead of the old version, if the latter does not want
engage in any modernization of your program? So there is a real one
an example of how to integrate the NEMO-IDE driver into the CD-Walk program
it took about 2 years, approximately.What this means is that libraries are needed. Dynamically
Loadable, that is, loaded during program execution.
Something like *.dll in a Windows environment or *.so in Unix, only simpler, with
adjusted for Spectrum specifics and limited resources.
For example, now in many programs for the Spectrum (for 2000-2003
year) the so-called memory driver is used, the real clock
time ("CMOS"), disk drive driver... On every computer
practically the same “driver” with different modifications is built in
into each program, or is loaded when the program starts. B
in the latter case, almost all programs use an incompatible
driver among themselves, despite the fact that all drivers have approximately
the same functionality. So why not finally get to
dynamic loading of code and a unified method (format) of presentation
this code?
In the opinion of the author, the requirements for the library are, first of all,
extremely easy to download. So that three hundred bytes of code are not required to download
a whole OS like Windows-XP(TM) was needed. This is extremely important for
library support in the TR-DOS environment and for adapting old programs.
The second point is compatibility: there should be enough traditional
for Spectrum tools such as ALASM or ZASM, both for creating andand to load the library. However, there is still something to think about...
For the IDE controller driver in the CD-Hack program, the author used
some kind of dynamically loaded *.dll library in Windows, which
allowed:
1. Completely separate programs using the *.dll file and the
library - now both the library and the program can develop
separately from each other (that is, releasing a new version of the driver does not
you have to think about updating the program, and vice versa).
2. Get the ability to dynamically (roughly speaking, they are possible on
change) loading any of the available modules of a certain
class (in this case, IDE driver).
3. Get the ability to download several different ones at the same time
instances of modules of the same class (it is possible to load all at once
drivers and use them simultaneously on a machine with several
IDE controllers).
4. The same module can be freely used in different
programs, which greatly simplifies its maintenance and saves space
on disk.
A list of advantages over statically inline code can be found
continue for a long time... There are also disadvantages. This is still some
complication of the program, increasing its volume (for example, due to
module loader) and ineffective, from the point of view of optimalcoding, library and program interface. For IDE drivers
the author had to invent a simple executable file format
libraries that would allow:
1. Specify a list of imported modules and functions, a list
exported functions.
2. Loading by absolute and relative (movable module)
address.
3. Specify information about the module, such as its class, name and version
(it was assumed that there would be a single hierarchical
class system so that any program can define
purpose of the module).
It seems that the described version of *.dll files is not the last, and for now there is
opportunity for significant change.
For programmers and other "coders" I would suggest in more detail
discuss this topic and approve a single format dynamically
loadable modules. I wanted to have a more specific list of requirements
to the module, and implementation options. My version can be seen at
example of IDE drivers...
Dynamically loaded module file structure
The downloadable module consists of the following parts:
* Header containing information necessary for loading the module.
* Program code (text) and data.
* Information necessary to configure the module to the execution address.
Only the title is required. Other parts mayabsent. So, for example, in a module that assumes loading by
The absolute address does not need any adjustment to the execution address at all.
Module title
In the current version, the header is a static record consisting of
The 11 fields indicated in the table below, as well as several
records of variable length: module name and class, lists of imported
and exported functions, strings of text description of the module, and code
initialization functions.
Static header part
The “name” column shows the designation of certain language marks
assembler, which serves to access individual fields of the module header. B
The "offset from beginning" column indicates the field offset, in bytes, from
the beginning of the file or relative to the module's load address in memory. In the column
"data type" denotes the data type of the field in C language notation.
The types int, unsigned and void* are assumed to be limited to 16
discharges.
Table 1. Module header fields
+----------------------------------------------------------+
| | offset from | | |
| name | began, in | data type | description |
| | bytes | | |
|--------------+------------+------------+----------------------------|| | | | File label (signature) |
| | | | allowing you to distinguish the file |
| mod_magic | 0 | char[4] | modules from other types |
| | | | files. Any module |
| | | | starts with 4 characters in |
| | | | ASCII code: <>. |
|--------------+------------+------------+----------------------------|
| | | | Current header version |
| | | | module and bootloader. Module |
| | | | can only be downloaded |
| | | | in case version |
| | | | module and bootloader |
| | | | his program used |
| | | | match. Version number |
| mod_modver | 4 | unsigned | defined by unsigned |
| | | | 16-bit number. Version |
| | | | consists of both senior and junior || | | | parts, senior 8 categories |
| | | | number defining number |
| | | | versions determine the major one |
| | | | part of the version number, minor |
| | | | 8 digits - the lowest part. |
|--------------+------------+------------+----------------------------|
| | | | Module properties bit field. |
| mod_flags | 6 | unsigned | Currently defined |
| | | | just one practically no |
| | | | flag used. |
|--------------+------------+------------+----------------------------|
| | | | Module loading address. All |
| | | | remaining header fields |
| | | | containing addresses will be |
| | | | valid only if |
| | | | the module will be loaded by |
| mod_load | 8 | void * | this address, or if || | | | addresses will be special |
| | | | adjusted in a way (for |
| | | | this is what the third serves |
| | | | component of the module - |
| | | | information for setting up |
| | | | download address). |
|--------------+------------+------------+----------------------------|
| | | | Function pointer |
| | | | initialization. Given |
| mod_start | 10 | void | function must be called |
| | | (*init)() | after loading the module and |
| | | | setting it to address |
| | | | downloads. |
|--------------+------------+------------+----------------------------|
| | | | At this address |
| | | | information for |
| mod_end | 12 | void * | module settings to address || | | | downloads, and after setup |
| | | | memory can be |
| | | | released. |
|--------------+------------+------------+----------------------------|
| | | | Pointer to list |
| mod_export | 14 | void * | exported by the module |
| | | | functions. |
|--------------+------------+------------+----------------------------|
| | | | Pointer to list |
| mod_import | 16 | void * | imported libraries and |
| | | | functions. |
|--------------+------------+------------+----------------------------|
| | | | Pointer to text |
| mod_name | 18 | char * | class and name string |
| | | | module. |
|--------------+------------+------------+----------------------------|
| | | | Binary version number || | | | module. Module version |
| | | | consists of the lowest (low) and |
| | | | senior (high) part, and |
| mod_version | 20 | unsigned | calculated by the formula: |
| | | | version = high*256+low. |
| | | | Modules with the same major |
| | | | part of the version number |
| | | | are considered compatible. |
|--------------+------------+------------+----------------------------|
| mod_text | 22 | char * | Pointer to string |
| | | | text description of the module. |
+----------------------------------------------------------+
All module header fields that have a pointer type, except the mod_load field,
contain valid values only after loading and configuration
module to the download address. Before setting the module to the download address, these
fields contain values valid if the module were loaded by
the address specified in the mod_load field.
Module header version
The mod_modver field, a static part of the module header, containsan unsigned 16-bit number specifying the header version number and
module loader compatible with it. The bootloader can download
module only if its version number exactly matches
with the module version number.
The current module header version is 0x0101 (decimal 257).
There is a certain assembly language mark whose meaning is
installed according to the current version of the module loader:
MODULE_HEADER_VER equ 0x0101
The version number is divided into major and minor parts, which, when
Records are usually separated by a dot. High part of the module version number
is determined by the most significant 8 digits of the version number, and the least significant
part - lower 8 digits. So the current version is
module header 0x0101 (decimal 257) can be written as
"1.1", where the one to the left of the dot determines the high part of the number
versions.
Module properties
As stated above, the mod_flags bit field contains information about
certain properties of the module. Each property is defined by one
set or cleared bit. There are language tags
assembler that defines the bitmask of each property bit. On
At the moment, one single property is defined:
MOD_ABSOLUTE equ 1
This property means when a module has it (the correspondingthe least significant bit of the properties bit field is set) that the module
can only be loaded at an absolute address defined by
the contents of the mod_load field.
Variable Length Records
Module name and class
Each module must have its own unique name and is associated with
the corresponding class of modules. This allows, on the one hand,
distinguish between different modules, and on the other hand, determine
modules with the same software interface. At the moment, everything
this information is encoded into a single text string as a set of classes and
module names separated by '/'. So, for example, the driver module
The IDE interface for the SMUC controller has the name: "trdos/ide/smuc".
The substring after the last character '/' is the name of the module, that's all
the rest is class.
List of exported functions
The list of export functions consists of a number indicating the quantity
exported functions, as well as an array of pointers to exported
Features:
Table 2. List of exported functions
+----------------------------------------------------------+
| offset from | data type | description |
| start, in bytes | | |
|------------------+------------+---------------------------------------|| | | Maximum number exported |
| | | functions. Numbering starts from zero, |
| 0 | int | like this when exporting just one function |
| | | this field will contain 0. The module is not |
| | | can export less than one |
| | | functions. |
|------------------+------------+---------------------------------------|
| | | Pointer to the exported function, |
| | | in other words, the memory address, by |
| | | which this |
| | | function. The pointer is |
| 2+2*N | void (*f)() | valid only after setting |
| | | module to the download address. If |
| | | the contents of this field are 0, which means |
| | | this function number is free and not |
| | | exports no function. |
+----------------------------------------------------------+
Import listThe import list is an array of records, each of which
represents the name of the imported module and a list (by number) of functions
required in this module (in reality this is a transition table, see
next message)
Text description string
ASCIIZ string, no more than 255 characters... Doesn't make much sense.
Module initialization function
Called once after loading the module...
Relocation table
Can be cut off from the module after it has been loaded and configured to
work address. Consists of an entry indicating the total number of configurable
addresses and a list of these addresses relative to the download address specified
in the mod_load field (see above). After configuring the module, all addresses in
the header will be directly (i.e. will contain absolute
addresses) point to the records corresponding to them. Customization for everyone
addresses, assumes that the configured address is necessarily a word (16
bit) and the setting is performed according to the formula (in C language notation):
(uint16_t *)A[0] - mod_load + real_load_address
Well, that's all for now. The rest is not written, but it gives an idea,
probably...
From
Kirill Frolov
→
To
Alexander Bondarenko
5 May 2004
Press RESET immediately, Alexander Bondarenko!
On Thu, 22 Apr 04 13:58:20 +0400, Alexander Bondarenko wrote:
So I continue about modules. In the previous letter there was a description,
It may not be entirely clear from it how it all works. I'll try
explain. So there is 1) a program, 2) a module. Separate from each other.
The module contains functions called by the program. FUNCTIONS ONLY. If
the address of a variable is required, you will have to define a function,
returning this address upon request. But the entire interface consists
EXCLUSIVELY FROM FUNCTIONS.
So that the program can be compiled successfully (even in ZXASM),
and somehow all this could be combined, instead of those functions that are in
module, the following are substituted into the program at the compilation stage:
"stubs":
function1:
JP function1_no
function2:
JP function2_no
...
Here "function1_no" is the function number in the module. ALL FUNCTIONS
IDENTIFIED BY NUMBERS. And "function1" is the actual name
functions. Such a “stub” is included as a library, of course
In addition, the module loader is turned on... Actually, this is what it looks like
stub, this is an element of the module import table (see previous.
message). It's all about the bootloader: after loading the module, all numbers
functions are replaced by their addresses! In total we have only 10 cycles
"overhead" for each function call. Well, there are still many possibilitiesopen, like switching cans on the go, or “transparent”
call traces...
Now regarding the OOP region. This is made a little more complicated,
when it comes to virtual functions. Multiple inheritance
impossible, but I don’t even know where to apply it... The gist is this:
if the function is non-virtual, then it is called that way (yes, I’m talking about assembler
I’m still saying!), but for convenience, it is given a name: classname_functionname.
Simply a reference to the object is passed to HL. Nothing new... If the function
virtual, then again a “plug” similar to the one given above is used:
virtual_function1:
ld a, virtual_function1_num * 3
jp call_virtual
virtual_function2:
ld a, virtual_function2_num * 3
jp call_virtual
...
Similarly, here virtual_function1 is the name of the function, and the file with such
definitions is included as a library. And virtual_function1_num is
function number, not in the module, but in the class. Everyone in every class
virtual functions are numbered. When a class is inherited, the number is only
increases and you can add new virtual functions, nothing
it is no longer possible to exclude, replace, or change numbers (therefore
multiple inheritance is not possible, as in C++). The number is multiplied
by 3 for ease of calculation, and the most interesting thing next is the function
call_virtual. It is used to call virtual functions by number,
here is its text:call_virtual:
push hl
push af
ld a, (hl)
inc hl
ld h, (hl)
ld l, a
pop af
add a,l
ld l, a
subl
ld h, a
ex (sp), hl
ret
At the input, a pointer to an object is passed in the HL register (as when calling
any functions of the class), and in register A - the number of the virtual function.
The remaining registers and stack can be used to transfer
function arguments. And here it is necessary to say the most important thing - every
an instance of a class that has virtual functions must have a certain
structure, namely a table of addresses of virtual functions. It is believed
that the class has a virtual function, the first word (two bytes)
uses a pointer to a table of virtual functions. This
necessarily. And the virtual function table itself represents
something like this (hence, by the way, the number is multiplied by 3):
class_vtbl:
jp vfunction1
jp vfunction2
...
Here vfunction1 is already the absolute address of the function. This table
it is common for the entire class, but may differ for inherited classes
(only in the larger direction, see above). Thus, really, "overhead"
From memory it turns out 2 bytes per object and table per class. And by beats
it turns out to be as much as a hundred cycles. But how quickly and noticeable inconvenience
I don't know.
Well, the object itself, from the assembler point of view, looks like this:
org 0 ; this is so that it is convenient to calculate the offsets,; class definitions are included before
; all other code (as opposed to
; libraries)
class_pvtbl dw class_vtbl ; pointer to virtual function table
class_blablala db 0
class_bablablabla dw 0 ; data...
class_sizeofequ$; class instance size
Instead of "class" you should substitute the name of the class. To create a new one
instance, you just need to allocate memory and call the constructor
(or delegate memory allocation to the constructor... if it knows how to do it)
-- the constructor cannot be virtual in any case. Destructor
maybe. The constructor must fill in the fields of the structure...
The class is inherited simply:
org 0
class2_blablabla dw 0 ; data...
class2_sizeofequ $
Well, here it’s somehow inconvenient with the assembler, it’s not thought out, there is
something else to think about...
So this is what I mean: I would like to unite the object paradigm (I
just showed how it is implemented in Z80 assembler) and the system
modules. And besides, endow them (the system of modules) with properties
COM-specific: unambiguous identification of compatible interfaces
(although I don't like it with UUID...), selecting one specific interface
of several provided by the module, representing the interface as
class, with the expectation that there may be several independentits instances (in the example with CD-Hack - two controllers at the same time)
etc... Well, of course you need some kind of directory of these modules, so what?
I've made Microsoft and I don't like it at all anymore. Maybe my idea with
In terms of names/classes, it's not that bad. I don't even know. Then
I would like to be able to have an interface with named
functions to be called from a scripting language. Because by numbers if necessary
all these classes have definitions. Uncomfortable...
From
Alexander Bondarenko
→
To
Kirill Frolov
9 May 2004
*Hello, Kirill!*
Catch my ideas about the subject "Re: Suggestion for coders on alasm",
about which your footcloth to comrade was chattering on May 05, 2004. Alexander Bondarenko.
AB>> LIB+ library (currently in state
AB>> developments) is a collection of all sorts of useful
AB>> procedures and subroutines, so far there are only about 30 of them. She
KF> I have similar thoughts, but nothing moves.
KF> Currently there are:
KF> 1) integer mathematics.
[cut]
KF> 11) creation of a simple interpreted language based on 10
In principle, I also lead to the fact that we should have something like this.
KF> clause 7. puzzling... There is a debugged C analogue, it is necessary
KF> transfer to Z80 assembler.
Can you tell me more about this manager?
AB>> is designed for alasm assembler - as the only one in real life, on
AB>> currently an assembler that supports conditional translation.
KF> Alas, the glitches there are through the roof. And most importantly, a number of these KF> stupid restrictions that simply don’t allow them to use (64
KF> character in a line, write only in capital letters - at least don’t cut
KF> I can...)
Well, that's understandable. In the alasma of logs there is tyeva hycha. But unfortunately he (of all
existing in real life) - the most advanced and popular. So for now I'm on it
I'm still doing it. If only because you shouldn’t forget about real people either.
KF> I'm counting on ZAS (C) Hitech Software for PC, sish
KF> preprocessor, and I have SED scripts for converting sources to ZASM
KF> or ALASM.
Everything is fine, but in order to see after compilation what you got there, you need
write files to trdshniki, launch emul, launch from it already
compiled program.
And if suddenly some glitch arose, but the program is healthy... In alasma it’s just
You launch STS, which also shows labels instead of addresses. What to do here? Hy
You can launch STS too, but there will be no markers.
KF> Since pre-processed text gets into the "converter",
KF> special requirements for the assembler in terms of conditional compilation and everything
KF> this is no longer presented. On the other hand, "Spectrum" KF> the version of the code is suitable only for compilation, it
KF> cannot be edited. Well, not everything there is transferred “head-on” either...
Still tempting. :)
AB>> The general organization of the library is such that it is not possible for the programmer
AB>> you need to monitor it in any way, except how to determine it
AB>> one service variable (and only if it is needed). For
AB>> “calling” the library just needs to be entered at the end of the program:
AB>> INCLUDE "LIB+"
KF> Yes, in Spectrum (as opposed to writing, for ZAS, although it
KF> in CP/M and on the Spectrum you can...) versions I do the same. Otherwise
KF> nothing. But there are also inconveniences here: you need to recompile everything at once
KF> symbols from different modules get mixed up. Actually, this is the reason for the bias
KF> towards the DLL - actually the only point of contact
KF> of the library and program, its interface remains, but what’s already inside
KF> not important at all.
AB>> In this case, it will be automatically determined which proceduresAB>> need to be compiled and which ones should not. The program itself has enough
KF> Alas. Fuck it! If there are any fairly complex dependencies,
KF> this is bound to cause problems. Like A depends on B
KF> and B depends on C. You include A. You include C in the text before
KF> inclusions A. It will be a bummer. You have to include one source by N
KF> just write (in ZXASM notation) these horrors:
KF> IFNDEF blablabla
KF> IFUSED blablabla
KF> blablabla:
KF> function code
KF> ENDIF
KF> ENDIF
Yes, there is such nonsense there... :)
And in Alaska this is organized simply:
IF (?blablalbla-1)
blablabla
function code
ENDIF
"?blablabla" gives 1 if blablabla above was accessed somewhere, but
This label has not yet been defined. If we define it, then ?blablabla will give
0. Hy and if blablabla was not called or defined, then ?blablabla will give
#ffff. Not a standard syntax, but it works. :)
And about the fact that one thing depends on the other. First, a simple development option
events. My procedures are divided into files not only by topic, but also byin terms of levels of dependence. And the library control file (which includes
these auxiliary files) is included at the very end of the program, when
it is known what needs to be turned on. First level (generally independent procedures)
They are compiled as a last resort. And first of all, those are compiled
procedures (read - subprograms), which have the highest level of dependence
tall. Therefore, if it turns out that blablabla calls ogogo, then after
compilation blablabla the value ?ogogo will be equal to 1. And if this ogogo is called
separately from blablabla, then everything will be fine too. It's all the same until the mark
defined, but used, the compiler remembers the places where it is addressed. A
then, at the end of the compilation, it arranges the value of this label accordingly.
places, if she has decided by this moment.
Well, a difficult option (just yours) - then it should also fail here. C because y
us will already be defined, so when compiling B into a call there are no problems
address C will be substituted.
KF> Well, often if one function is needed, then the entire module is needed.
KF> A lot of inconvenience...
It depends on the internal structure of this module... You can also place
there the procedures are in order of "dependency".
AB>> SCRADR - calculation of the address on the screen using familiar coordinates
[cut] AB>> UP8HL - the same, but 8 lines higher
KF> This should be done exclusively with macros! For one CALL only
KF> 28 cycles, the same amount of register juggling. What will remain?
This is understandable. I haven’t implemented the macro part of the library yet, but just in case
The case included these cases in the form of procedures.
AB>> In general, what exists at the moment is by no means
AB>> helicopter, there is still plenty of work on the library.
AB>> I hope for the support of the people.
KF> I think the library is useless.
No, for those who code purely in alasma, it can be useful. At least
at least, besides me, who wants it :), there are a dozen more personalities (were in our
talking time).
KF> It is impossible to assemble it with the /Spectrum/ assembler (in written form
KF> standard feature). And the possibilities are very limited. About
KF> I have already described the advantages of DLL, but there are also problems there
KF> is enough. You need Spectrum COM! (with an eye on Microsoft).
Accordingly, an axis is needed.
KF> But how can this be implemented without the crutches that I came up with KF> I don’t even know the microsoftware. As long as there is a system
KF> modules, but it is already clear that it lacks many things, although itself
KF> principle, in general this is the technical side of the issue, the principle itself
KF> combining the code of two programs through a predefined interface
KF> it is the same everywhere (see the next letter).
KF> A short list (a detailed list does not fit in SPBZXNET's letter) of mine
KF> "libraries":
Can I get a detailed list for e-soap?
[further cut]
Thank you, I will keep all these benefits in mind.
/That’s all, Kirill, you can scroll further.../
pese: Of course, I understand everything about ZAS’s coolness. I'm crazy myself. Yes, if only everything
coders climbed onto it overnight, most likely, the effect of this would be
more than positive. But for now, the majority of people are sitting behind the alyasm.
Even some emulators.
From
Alexander Bondarenko
→
To
Kirill Frolov
10 May 2004
*Hello, Kirill!*
Catch my ideas about the subject "Re: Suggestion for coders on alasm",
about which your footcloth to comrade was chattering on May 05, 2004. Alexander Bondarenko.
Damn, you still come to the conclusion: it’s easy to complicate, it’s difficult to simplify.
;)))))))))
/That’s all, Kirill, you can scroll further.../