Tatara

Chapter 29
Scratch variables shared through a transient segment

A program often has variables that only one part of it uses, and only while that part runs: a buffer for a line being read, another for a line being written. When the two parts never run at the same time, the two buffers can share the same memory. A transient segment (section 10.6) does that, and this chapter follows it through LAYOUT, the example in A:\TATARA\EXAMPLES\LAYOUT: the source, the symbol table TATARA makes of it, and the maps TANREN makes when it links it at two different addresses.

29.1 The example

LAYOUT is one module, LAYOUT.AS, and a BUILD.BAT. The program itself only prints a line:

A:\TATARA\EXAMPLES\LAYOUT>layout 
Code here, data elsewhere.
 

What the example is for is where its bytes go. It has code, two plain variables, and a transient segment, SCRATCH, with two groups of variables that share the same memory. BUILD.BAT writes the symbol table and two maps into files, so that they can be read after the build.

29.2 The source

; LAYOUT.AS - where the bytes go. 
; 
; Three kinds of relocatable space, and the options that place them: 
; 
;   CSEG                        code            TANREN /P:<addr> 
;   DSEG                        data            TANREN /D:<addr> 
;   DSEG <name>,TRANSIENT       overlaid data   one GROUP at a time 
; 
; A SEGMENT MAY BE NAMED, and a named one keeps its own counter: two 
; CSEG MUSIC lines in different files contribute to one segment. 
; 
; A TRANSIENT DSEG is space that is used by one part of a program at a 
; time. Every GROUP in it starts at the same address, so the segment is 
; as large as its largest group and not as large as their sum. Labels 
; in two different groups cannot be subtracted from each other, 
; because nothing says which of them is in memory. 
; 
; The absolute kind, ASEG, is in the BINARY and ROM examples - a fixed 
; address in a .COM would make the file span everything from 0100h up 
; to it. 
 
                include msxdos.inc      ; _STROUT, _TERM0 and "system" 
                include ascii.inc       ; CHR_CR and CHR_LF 
 
                cseg 
 
start:          ld      hl,runs         ; a byte in the plain DSEG 
                inc     (hl) 
                ld      de,msg 
                system  _STROUT 
                system  _TERM0 
 
msg:            db      "Code here, data elsewhere.",CHR_CR,CHR_LF,"$" 
 
                dseg                    ; the plain data segment: the 
runs:           ds      1               ;   linker puts it after the code 
lastkey:        ds      1               ;   unless /D: says where 
 
                dseg    SCRATCH,TRANSIENT 
                group   READING         ; 66 bytes... 
inbuf:          ds      64 
inlen:          ds      2 
                group   WRITING         ; ...and 34, at the same address, 
outbuf:         ds      32              ;   so SCRATCH is 66 bytes and not 
outlen:         ds      2               ;   100 
 
                end     start
 

The source has three parts, one for each kind of segment:

The program does not use the two groups; they are there to show where they go. A real program would use READING while it reads a line, and WRITING while it writes one, and never both at once: writing to outbuf overwrites inbuf (section 10.6).

29.3 Building it

rem BUILD.BAT - EXAMPLE: LAYOUT 
rem 
rem This example is about the two maps it writes, not about the 
rem program, which only prints a line. 
rem 
rem   TATARA /S   the symbol table: every name, by segment, with its 
rem               offset inside that segment 
rem   TANREN /M   the segment and group tables: where each segment 
rem               ended up, how big it is, and which groups share it 
rem 
rem It links twice. The first is an ordinary .COM at 0100h. The second 
rem puts the code at 8000h and the data at C000h - a real MSX layout, 
rem code in the top pages with its variables above it, and not 
rem something MSX-DOS can run as a command, so it goes to a .BIN that 
rem nobody is asked to run. 
 
rem The headers are in A:\TATARA\INCLUDE and are not copied here. 
rem TATARA is rule 3 of the include search - see the DIRS example. 
rem CHANGE THE PATH BELOW if you put the tree somewhere else. 
 
set TATARA=a:\tatara\include 
 
echo === Assembling, keeping the symbol table 
tatara /q /s layout.as layout.tro > layout.sym 
 
echo === Linking at 0100h, keeping the map 
tanren /q /m /o:layout.com layout.tro > layout.map 
 
echo === Linking again, code at 8000h and data at C000h 
tanren /q /m /o:layout8.bin /p:8000 /d:c000 layout.tro > layout8.map 
 
echo === Done. Read LAYOUT.SYM, LAYOUT.MAP and LAYOUT8.MAP. 
 
set TATARA=
 

Each command sends what it prints to a file with >. With /Q, TATARA and TANREN print no banner and no summary, so the files hold only the symbol table (/S, chapter 19) and the maps (/M, section 25.7). The second link puts the code at 8000h and the data at C000h (section 24.3). Its output file, LAYOUT8.BIN, is not a program that MSX-DOS can run, and is not meant to be run: it is there for its map.

A:\TATARA\EXAMPLES\LAYOUT>build 
=== Assembling, keeping the symbol table 
=== Linking at 0100h, keeping the map 
=== Linking again, code at 8000h and data at C000h 
=== Done. Read LAYOUT.SYM, LAYOUT.MAP and LAYOUT8.MAP.
 

29.4 Reading the symbol table

LAYOUT.SYM starts with the absolute section, which holds every EQU of MSXDOS.INC and ASCII.INC, more than a hundred lines, cut here. The sections for the program’s own names follow it:

A:\TATARA\EXAMPLES\LAYOUT>type layout.sym 
ASEG - absolute 
 
0000h             CHR_NUL 
0000h             _TERM0 
... 
007Fh             CHR_DEL 
 
CSEG - default code segment, 002Eh bytes 
 
0000h             start 
0011h             msg 
 
DSEG - default data segment, 0002h bytes 
 
0000h             runs 
0001h             lastkey 
 
SCRATCH - named data segment, transient, 0000h bytes 
 
(no symbols) 
 
SCRATCH - named data segment, transient, group READING, 0042h bytes 
 
0000h             inbuf 
0040h             inlen 
 
SCRATCH - named data segment, transient, group WRITING, 0022h bytes 
 
0000h             outbuf 
0020h             outlen
 

Each value is an offset inside its section. SCRATCH has three sections: one for the part of the segment outside every group, which is empty here, and one for each group. inbuf and outbuf are both at 0000h, each in its own group: the symbol table cannot say yet that they will be at the same address, because only TANREN places the groups.

29.5 Reading the maps

LAYOUT.MAP is the map of the .COM program:

A:\TATARA\EXAMPLES\LAYOUT>type layout.map 
Modules: 1 
Groups: 
  READING 
  WRITING 
Segments: 
  flags 00 group FF base 0100 size 002E end 012D  C 
  flags 01 group FF base 012E size 0002 end 012F  D 
  flags 03 group 00 base 0130 size 0042 end 0171 SCRATCH 
  flags 03 group 01 base 0130 size 0022 end 0151 SCRATCH 
Symbols:
 

The code starts at 0100h and takes 2Eh bytes; the two plain variables follow it at 012Eh; and SCRATCH comes last, with a line for each group. Both lines have the same base, 0130h: READING runs to 0171h, and WRITING, the smaller, to 0151h. Symbols: is empty, because the module declares no public or external names.

LAYOUT8.MAP is the map of the second link:

A:\TATARA\EXAMPLES\LAYOUT>type layout8.map 
Modules: 1 
Groups: 
  READING 
  WRITING 
Segments: 
  flags 00 group FF base 8000 size 002E end 802D  C 
  flags 01 group FF base C000 size 0002 end C001  D 
  flags 03 group 00 base C002 size 0042 end C043 SCRATCH 
  flags 03 group 01 base C002 size 0022 end C023 SCRATCH 
Symbols:
 

The segments are the same, and so are their sizes; only the addresses change. The code is at 8000h, and all the data, the plain variables and SCRATCH, at C000h. Figure 29.1 shows both links.

PIC

Figure 29.1: LAYOUT linked at 0100h, and with the code at 8000h and the data at C000h. In both, the two groups of SCRATCH start at the same address.

Neither file holds SCRATCH: its bytes are reserved with DS, which puts nothing in the file (section 24.1.1). LAYOUT.COM is 46 bytes, from 0100h to 012Dh.

29.6 Things to try

The files below are not part of the example: make them in its directory, with TATARA set as in BUILD.BAT.

29.6.1 Subtract a label in one group from a label in another

; SUBGRP.AS - a label from each group of one transient segment, 
; in one expression. 
                dseg    SCRATCH,TRANSIENT 
                group   READING 
inbuf:          ds      64 
                group   WRITING 
outbuf:         ds      32 
                cseg 
                ld      hl,outbuf-inbuf 
                end
 
A:\TATARA\EXAMPLES\LAYOUT>tatara subgrp.as subgrp.tro 
... 
SUBGRP.AS(9): ERROR: relocation error - a segment-relative value is not allowed here.
 

Both labels are at offset 0000h, but in different groups, and TATARA treats them as two unrelated addresses (section 10.6).

29.6.2 Add a group in another module

PARSE.AS adds a third group, PARSING, of 80 bytes:

; PARSE.AS - a third group of SCRATCH, larger than the other two. 
                public  tokens 
                dseg    SCRATCH,TRANSIENT 
                group   PARSING 
tokens:         ds      80 
                end
 
A:\TATARA\EXAMPLES\LAYOUT>tatara /q parse.as parse.tro 
A:\TATARA\EXAMPLES\LAYOUT>tanren /m /o:lp.com layout parse 
... 
Groups: 
  READING 
  WRITING 
  PARSING 
Segments: 
  flags 00 group FF base 0100 size 002E end 012D  C 
  flags 01 group FF base 012E size 0002 end 012F  D 
  flags 03 group 00 base 0130 size 0042 end 0171 SCRATCH 
  flags 03 group 01 base 0130 size 0022 end 0151 SCRATCH 
  flags 03 group 02 base 0130 size 0050 end 017F SCRATCH 
Symbols: 
  D- 0130 tokens 
2 modules, 20 records, ends at EOF. 
Wrote LP.COM, 0100-012D (46 bytes), entry 0100.
 

PARSING starts at 0130h too, and, being the largest group, makes SCRATCH 80 bytes long, to 017Fh. The groups of a transient segment overlay each other across modules (section 24.4).

29.6.3 Add to a group from another module

READ2.AS adds a variable to READING, the group that is already in LAYOUT.AS:

; READ2.AS - more variables for the group READING, from another module. 
                public  linenum 
                dseg    SCRATCH,TRANSIENT 
                group   READING 
linenum:        ds      2 
                end
 
A:\TATARA\EXAMPLES\LAYOUT>tatara /q read2.as read2.tro 
A:\TATARA\EXAMPLES\LAYOUT>tanren /m /o:lr.com layout read2 
... 
Segments: 
  flags 00 group FF base 0100 size 002E end 012D  C 
  flags 01 group FF base 012E size 0002 end 012F  D 
  flags 03 group 00 base 0130 size 0044 end 0173 SCRATCH 
  flags 03 group 01 base 0130 size 0022 end 0151 SCRATCH 
Symbols: 
  D- 0172 linenum 
2 modules, 20 records, ends at EOF. 
Wrote LR.COM, 0100-012D (46 bytes), entry 0100.
 

A group of the same name in another module is the same group. Its variables follow the ones before it, as in any segment: linenum comes after inbuf and inlen, at 0172h, and READING grows to 44h bytes. This is how the parts of a large program share scratch memory: each module that works with lines being read adds its variables to READING, and none of them needs to know about the others.

29.6.4 Forget TRANSIENT

PLAIN.AS declares SCRATCH without TRANSIENT:

; PLAIN.AS - SCRATCH again, but not transient. 
                public  plainv 
                dseg    SCRATCH 
plainv:         ds      10 
                end
 
A:\TATARA\EXAMPLES\LAYOUT>tatara /q plain.as plain.tro 
A:\TATARA\EXAMPLES\LAYOUT>tanren /m /o:lpl.com layout plain 
... 
PLAIN.TRO: ERROR: segment SCRATCH is declared differently.
 

A segment has to be declared the same way in every module (section 27.4).