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 code, in the default code segment: it adds one to runs, prints msg with the MSX-DOS function _STROUT, and ends.
- Two plain variables, runs and lastkey, in the default data segment. Each has a byte of its own.
- The transient segment SCRATCH, with two groups. READING holds a buffer for a line being read and its length, 66 bytes. WRITING holds a buffer for a line being written and its length, 34 bytes. Both groups start at the beginning of SCRATCH, so inbuf and outbuf are the same address, and SCRATCH takes 66 bytes, not 100.
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.
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).