From: "French Luser" Newsgroups: comp.os.cpm Subject: Header Record of CP/M-86 (Plus) Date: Fri, 26 Nov 2004 12:52:37 +0100 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2800.1158 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165 Lines: 455 Message-ID: <41a71871$0$25111$8fcfb975@news.wanadoo.fr> Organization: les newsgroups par Wanadoo NNTP-Posting-Host: APoitiers-106-2-3-49.w81-248.abo.wanadoo.fr X-Trace: 1101469810 news.wanadoo.fr 25111 81.248.43.49:21824 X-Complaints-To: abuse@wanadoo.fr HEADER.TXT by Emmanuel ROCHE ---------- Everything you wanted to know about the Header Record, but were too afraid to ask... The more I work with CP/M-86 (Plus) ComManD files, the more often I need to know what is inside its Header Record. For the record, a CMD file generally has 2 or 3 parts, which can be described thus: +---------------+ | Header Record | +---------------+ | Segments Used | +---------------+ | Footer Record | (If RSX(s) present) +---------------+ The Header Record contains a description of the Segments used by the program, that the loader of the CP/M-86 (Plus) Operating System will use to allocate memory and load the program in the TPA. As its name implies, it is 128 bytes long, or one record. It contains Group Descriptors at the beginning. A first byte of zero in a Group Descriptor indicates that no more Group Descriptors follows. The rest of the record is filled with null bytes (00h), except the 5 last bytes, which will be explained later. The Segments Used part of the CMD file are those segments, up to 8. The Footer Record is a record containing the names or the addresses/names of the RSXs linked/attached (up to 8) to this CMD file. This record does not exist if the CMD file has no RSX. Enough theory, let us see some Header Records. A>mbasic header BASIC-86 Rev. 5.22 [CP/M-86 Plus] Copyright 1977-1982 (C) by Microsoft Created: 5-Mar-82 62390 Bytes free HEADER> Enter CMD File Name: ? CMD1 G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0018 | 0000 | 0018 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 00 (8080 Memory Model) Ok run HEADER> Enter CMD File Name: ? CMD2 G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0018 | 0000 | 0018 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 00 (Small Memory Model) Ok run HEADER> Enter CMD File Name: ? CMD3 G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0018 | 0000 | 0018 | 0000 | +-------+--------+--------+--------+--------+ (Extra) | 03h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 00 (Compact Memory Model) Ok run HEADER> Enter CMD File Name: ? CMD4 G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0018 | 0000 | 0018 | 0000 | +-------+--------+--------+--------+--------+ (Extra) | 03h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Stack) | 04h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 00 (Compact Memory Model) Ok run HEADER> Enter CMD File Name: ? CMDX1 G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0018 | 0000 | 0018 | 0000 | +-------+--------+--------+--------+--------+ (Extra) | 03h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Stack) | 04h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Aux.1) | 05h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 00 (Compact Memory Model) Ok run HEADER> Enter CMD File Name: ? CMDX2 G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0018 | 0000 | 0018 | 0000 | +-------+--------+--------+--------+--------+ (Extra) | 03h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Stack) | 04h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Aux.1) | 05h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ (Aux.2) | 06h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 00 (Compact Memory Model) Ok run HEADER> Enter CMD File Name: ? CMDX3 G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0018 | 0000 | 0018 | 0000 | +-------+--------+--------+--------+--------+ (Extra) | 03h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Stack) | 04h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Aux.1) | 05h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ (Aux.2) | 06h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ (Aux.3) | 07h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 00 (Compact Memory Model) Ok run HEADER> Enter CMD File Name: ? CMDX4 G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0018 | 0000 | 0018 | 0000 | +-------+--------+--------+--------+--------+ (Extra) | 03h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Stack) | 04h | 0008 | 0000 | 0008 | 0000 | +-------+--------+--------+--------+--------+ (Aux.1) | 05h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ (Aux.2) | 06h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ (Aux.3) | 07h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ (Aux.4) | 08h | 0000 | 0000 | 0040 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 00 (Compact Memory Model) Ok run HEADER> Enter CMD File Name: ? CALLVERS G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0002 | 0000 | 0002 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0012 | 0000 | 0012 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0400 Offset of Fixups Record: 0000 Program Flag: 00 (Small Memory Model) Ok run HEADER> Enter CMD File Name: ? ECHOVERS G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0006 | 0000 | 0006 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0012 | 0000 | 0012 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 0000 Program Flag: 10 (Small Memory Model) Ok run HEADER> Enter CMD File Name: ? TESTGIOS G-Form G-Length A-Base G-Min G-Max +-------+--------+--------+--------+--------+ (Code) | 01h | 0298 | 0000 | 0298 | 0000 | +-------+--------+--------+--------+--------+ (Data) | 02h | 0058 | 0000 | 0058 | 0000 | +-------+--------+--------+--------+--------+ (Extra) | 03h | 0006 | 0000 | 0006 | 0000 | +-------+--------+--------+--------+--------+ (Stack) | 04h | 0094 | 0000 | 0094 | 0000 | +-------+--------+--------+--------+--------+ Offset of Footer Record: 0000 Offset of Fixups Record: 7300 Program Flag: 80 (Large Memory Model) Ok From the above, some things become clear: when there is only one Code segment, it is a "8080 Memory model CMD file". When there are 2 segments (but only if they are Code and Data), then it is a "Small Memory model CMD file". When there are more than 2 segments, it is a "Compact Memory model CMD file". Historically, those were the 3 kinds of Memory Models described in the CP/M-86 Version 1.x technical documentation by Digital Research. Under CP/M-86 Plus, RSXes exist. ECHOVERS is an example of such an RSX. As you can see, its Program Flag contains 10h. CALLVERS, the CMD file calling it, has its "Offset to Footer Record" field containing the value 0400h. But, what is this "Large Memory model CMD file", TESTGIOS, we have seen last? With Concurrent CP/M Version 1.0, Digital Research introduced in the Summer of 1983 a new kind of CMD file, where each segment can be up to 1 Megabyte in length... (Previously, they could only be 64k long, at the maximum.) But, to be compatible with all the CMD files produced until then, they had to choose a way to let the CMD file loader of the operating system knows that this CMD file was of the new kind. Since they could not modify the format of the Group Descriptors, they chose to use a byte inside the Header Record. Over the years, this byte came to be used as flags for 4 things: Bit: 7 6 5 4 3 2 1 0 +-----------------+ | 1 1 1 1 1 1 1 1 | +-----------------+ | | | | | | | | | | | | | | | +--> Bit 0: Not used | | | | | | +----> Bit 1: Not Used | | | | | +------> Bit 2: Not used | | | | +--------> Bit 3: Not used | | | +----------> Bit 4: RSX Footer Record Flag | | +------------> Bit 5: 8087 Present Flag | +--------------> Bit 6: 8087 Support Flag +----------------> Bit 7: Large Memory Model Flag Program Flag format The last 2 CMD files that we examined (ECHOVERS and TESTGIOS) displayed 10h and 80h; that is to say: Bits 4 and 7 set. But what is the purpose of Bits 5 and 6? Searching for clues in later Digital Research guides, I finally found the following paragraph in the "Concurrent CP/M Release 3.1 Programmer's Reference Guide": 3.1.2 8087 support ------------------ Concurrent CP/M provides optional 8087 support for systems that use the 8087 processor. This support is indicated by the Program Flag, byte 127 (7Fh), of the CMD file Header Record. Setting bit 6 (bit 0 is least significant bit) of the Program Flag indicates optional 8087 support, which means that, if the 8087 is present, the program uses it; otherwise, the program will emulate it. If bit 5 of the Program Flag is set, it indicates that the 8087 must be present in order for the program to run. If no 8087 is present and bit 5 of the Program Flag is set, the system returns an error when it tries to load the program. The CHSET utility can be used to set the program's header record for optional or required 8087 support. ----------------- So, you now know what would mean a Program Flag with a value of 20h or 40h. Now that we have explained everything known about the Header Record, here is the BASIC program used to learn all this: list 10 REM HEADER.BAS by Emmanuel ROCHE 20 : 30 PRINT 40 INPUT "HEADER> Enter CMD File Name: " ; file1$ 50 PRINT 60 file1$ = file1$ + ".CMD" 70 : 80 group$ (1) = "(Code) " 90 group$ (2) = "(Data) " 100 group$ (3) = "(Extra)" 110 group$ (4) = "(Stack)" 120 group$ (5) = "(Aux.1)" 130 group$ (6) = "(Aux.2)" 140 group$ (7) = "(Aux.3)" 150 group$ (8) = "(Aux.4)" 160 : 170 ruler$ = "+-------+--------+--------+--------+--------+" 180 : 190 PRINT TAB(9) " G-Form G-Length A-Base G-Min G-Max" 200 PRINT TAB(9) ruler$ 210 : 220 OPEN "R", #1, file1$, 9 230 FIELD #1, 1 AS gform1$, 2 AS glength1$, 2 AS abase1$, 2 AS gmin1$, 2 AS gmax1$ 240 GET #1 250 : 260 gform1 = ASC (gform1$) 270 IF gform1 = 0 THEN GOTO 420 280 NrSeg1 = NrSeg1 + 1 290 PRINT group$ (gform1) TAB(9) "| " ; 300 PRINT RIGHT$ ("0" + HEX$ (gform1), 2) "h | " ; 310 glength1 = CVI (glength1$) 320 PRINT RIGHT$ ("000" + HEX$ (glength1), 4) " | " ; 330 abase1 = CVI (abase1$) 340 PRINT RIGHT$ ("000" + HEX$ (abase1), 4) " | " ; 350 gmin1 = CVI (gmin1$) 360 PRINT RIGHT$ ("000" + HEX$ (gmin1), 4) " | " ; 370 gmax1 = CVI (gmax1$) 380 PRINT RIGHT$ ("000" + HEX$ (gmax1), 4) " |" 390 PRINT TAB(9) ruler$ 400 GOTO 240 410 : 420 CLOSE #1 430 OPEN "R", #1, file1$, 1 440 FIELD #1, 1 AS byte1$ 450 GET #1, &H7B 460 : 470 PRINT 480 GET #1 : lofo = ASC (byte1$) 490 GET #1 : hifo = ASC (byte1$) 500 fo = hifo + 256 * lofo 510 PRINT "Offset of Footer Record: " ; 520 PRINT RIGHT$ ("000" + HEX$ (fo), 4) 530 GET #1 : lofi = ASC (byte1$) 540 GET #1 : hifi = ASC (byte1$) 550 fi = hifi + 256 * lofi 560 PRINT "Offset of Fixups Record: " ; 570 PRINT RIGHT$ ("000" + HEX$ (fi), 4) 580 GET #1 : fl = ASC (byte1$) 590 PRINT "Program Flag: " ; 600 PRINT RIGHT$ ("0" + HEX$ (fl), 2) 610 : 620 PRINT 630 PRINT "(" ; 640 IF fl > &H7F THEN PRINT "Large" ; : GOTO 680 650 IF NrSeg1 = 1 THEN PRINT "8080" ; : GOTO 680 660 IF NrSeg1 = 2 THEN PRINT "Small" ; : GOTO 680 670 IF NrSeg1 > 2 THEN PRINT "Compact" ; 680 PRINT " Memory Model)" 690 : 700 PRINT 710 CLOSE 720 END system A>That's all, folks! Yours Sincerely, "French Luser" EOF