>>>>>>>>>>>>>>>>>>>>> CP/M-Net News <<<<<<<<<<<<<<<<<<<<<<<<

============================================================
Number 3               March, 1981         Volume 1, Issue 3
============================================================

                       In This Issue
                       =============

        The Famous UP-Arrow Story - Michael J. Karas

         CP/M Bit Map File Allocation...EXPLAINED!

  A Simple 6 Byte Hexadecimal to ASCII Conversion Routine

  A CP/M 1.4 Parameter Display Program in Microsoft Basic

 CP/M-Net 'Tip-of-the-Month', 64 character wide DDT or SID


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


              The Famous UP-Arrow Story
              =========================
                        by
                 Michael J. Karas

Some time ago,  while working at a job that I would just as
soon  forget,  the famous up-arrow incident took place.   My
desk  happened  to  be right next to that  of  Kelly  Smith,
editor of the CP/M Net (tm) News.  Kelly had been spending a
large  amount of his time working on a diagnostics  software
package for the company's business computer.  (The now known
PCC  2000.) Building a diagnostics package can  be  creative
and  on one particular day Kelly wanted to show me how  some
of  the softare worked.  In other words he wanted me to  see
some  of  the creativity that he had put into this  software
package.

I went over to his computer setup to look at the CRT screen
while  he showed me the Memory Display/Alter routine he  had
made.  After  observing for a short time I asked how do  you
back  up  to the previous memory address if  you  enter  the
wrong data. His response was that you terminated the current
entry  sequence and reentered the errored memory address.  I
decided that it would be nice if there was a key that  would
allow you to simply backup to the previous address.

After  lunch,  (Kelly  usually seemed to pound away at  the
keyboard all during lunch in those days;) Kelly asked me  if
a newly modified version of his Display Alter Routine solved
my  problem.  I  tried it out and found that while  entering
data  with the memory display/alter command that use of  the
up-arrow  (^) key would cause the displayed address to  back
up to the previous address. A very useful feature I decided.
Kelly's only comment was that some people get their gibblets
jiggled in the most strange ways.  Anyway,  to this day  the
monitors  in  all of my personal computers contain a  memory
display/alter routine with the up-arrow.

These days I don't usually use the monitors anymore due  to
the  fact that I have disks and thus access to DDT,  Digital
Research's Diagnostic Debugging Tool. The "S" command of DDT
does not have the capability to offer the up-arrow attribute
to ease the pain of putting in the wrong value for a  memory
byte.  So  I  took it upon myself to change DDT so  that  it
would do "Up-Arrow".

If  you should desire to "jiggle your giblets" while  using
the  DDT Version 1.4 debugger package then you will have  to
do  a  little  work for the "jigglin'".  The  rest  of  this
article  describes  how  to  make  DDT  react  to  up-arrow.
Operating  instructions  are at the end of the  installation
procedure.  Note that this patch is specifically tailored to
DDT  Version 1.4 and may not work with other  versions.  The
short program below should be edited into a file using  your
favorite editor with the name "DDTPATCH.ASM". It should then
be  assembled  into a ".HEX" file using  an  assembler.  Use
particular care to get all of the strange equated numbers at
the beginning exactly right.

;****************************************************************
;       PATCH TO GIVE SET MEMORY COMMAND BACKUP CAPABILITY
;       IN DDT VERSION 1.4.
;****************************************************************
;
;
WBOOT   EQU     00000H          ;WARM BOOT ENTRY ADDRESS
BDOS    EQU     00005H          ;BDOS ENTRY ADDRESS
TPA     EQU     00100H          ;START OF TRANSIENT PROGRAM
;
;
CMNDLP  EQU     06FEH           ;LOCATION OF COMMAND LOOP START
                               ;(IN ABSOLUTE DDT IMAGE)
;
DISPLP  EQU     0A7EH           ;LOCATION OF DISPLAY LOOP START
                               ;(IN ABSOLUTE DDT IMAGE)
;
PATCH   EQU     0A91H           ;LOCATION OF PATCH IN MEMORY ALTER
                               ;(IN ABSOLUTE DDT IMAGE)
;
ASCHEX  EQU     0C53H           ;LOCATION OF CONVERSION ROUTINE
                               ;(IN ABSOLUTE DDT IMAGE)
;
ENDDDT  EQU     0FD0H           ;LOCATION OF END OF DDT 1.4
                               ;(IN ABSOLUTE DDT IMAGE)
;
       ORG     TPA+1           ;FIX OLD DDT 1.4 MODULE SIZE
;
       DW      0FB6H+028H      ;NEW MODULE SIZE WITH PATCH
;
       ORG     PATCH+200H      ;OFFSET ASSEMBLY AREA
;

       POP     H
       CALL    CHARIN-200H     ;GO TO NEW ROUTINE TO GET CHAR
;
       CPI     0DH             ;IS INPUT CHAR A CARRIAGE RETURN?
       JZ      INCMADR-200H    ;GO TO INCREMENT TO NEXT ADDRESS
;
       CPI     '.'             ;IS INPUT THE EXIT PERIOD?
       JZ      CMNDLP          ;GO BACK TO DDT'S COMMAND LOOP
;
       CPI     '^'             ;IS INPUT AN UPARROW TO BACKUP
       JZ      DECMADR-200H    ;GO TO DECREMENT TO PREV ADDRESS
       CALL    ASCHEX          ;GO TO ASCII TO HEX CONVERSION
       RLC                     ;ADJUST HEX FOR HIGH NIBBLE
       RLC
       RLC
       RLC
       MOV     D,A             ;SAVE HIGH NIBBLE
       CALL    CHARIN-200H     ;GET ASCII FOR LOW CHAR
       CALL    ASCHEX          ;GO TO ASCII TO HEX CONVERSION
       ORA     D               ;COMBINE LOW AND HIGH NIBBLES
       NOP                     ;FIX PATCH SIZE TO FIT IN DDT 1.4
       MOV     M,A             ;PUT NEW VALUE INTO MEMORY
INCMADR:
       INX     H               ;INCREMENT FOR NEXT MEMORY ADDRESS
       JMP     DISPLP          ;GO DISPLAY NEXT MEM ADDRESS
;
;
;CODE TO BE PATCHED IN AT END OF DDT PROGRAM. THESE ROUTINES
;ADD THE CAPABILITY TO GET SINGLE CONSOLE CHARACTERS AND TO
;DECREMENT THE CURRENTLY DISPLAYED MEMORY ADDRESS IN THE DDT
;SET MEMORY COMMAND.
;
       ORG     ENDDDT+200H
;
CHARIN:
       PUSH    D               ;SAVE POSSIBLE HIGH NIBBLE
       PUSH    H               ;SAVE CURRENT MEMORY ADDRESS
       MVI     C,01H           ;SET BDOS FUNCTION FOR CONIN
       CALL    BDOS            ;USE BDOS FOR CONSOLE INPUT
       POP     H
       POP     D
       RET
DECMADR:
       DCX     H               ;DECREMENT MEMORY ADDRESS
       JMP     DISPLP          ;GO DISPLAY THE PREVIOUS MEM ADDRESS
;
       END
;
;

Once you have made the hex file, then put a copy of it on a
CP/M  system  disk along with your copy of DDT version  1.4.
Boot  up  this disk in drive A:  and  carefully  follow  the
installation  instructions below.  If you are not  currently
familiar  with the operation of DDT now would be a good time
to get the manual out and read it.  We will be using DDT  to
make a patched version of itself. The sequence below must be
followed  exactly.  The  notation  <cr> indicates  that  you
should enter carriage return.  The part of the text that the
system types versus the part that you type should be obvious
if you are familiar with DDT.

A>
A>DDT<cr>                     <== Invoke DDT
DDT VERS 1.4
-IDDT.COM<cr>
-R<cr>                        <== Read in a copy of DDT.COM
NEXT  PC
1400 0100
-S1308<cr>                    <== Change bit map for patch
1308 92 88<cr>
1309 08 42<cr>
130A 44 12<cr>
130B 48 02<cr>
130C 40 .<cr>
-F13AC,13B0,00<cr>            <== Fill in new zeros to map
-S13B1<cr>                    <== Add a new bit to map
13B1 00 04<cr>
13B2 00 .<cr>
-M11B6,1400,1A00<cr>          <== Move bit map out of way
-IDDTPATCH.HEX<cr>
-R<cr>                        <== OVerlay DDT.COM with patch
NEXT  PC
1400 0000
-M1A00,2000,11DE<cr>          <== Move bit map into place
-^C                           <== Bale out of DDT to System
A>SAVE 19 DDTP.COM<cr>        <== Save patched DDT

You  are now ready to try out the patched version  of  DDT.
For the most part DDT will operate just like before. The new
version  will modify the way that the "S" substitute  memory
command functions.  The command is invoked just as before (-
Saaaa<cr>  aaaa=desired address).  When DDT responds with  a
display of the memory address and its contents it will enter
a mode waiting for operator input. Four different things can
be entered at this point:

a)  A <cr> may be entered to cause the contents of the  next
   memory address to be displayed.

b)  A "." may be entered to cause DDT to return back to  the
   command mode.  Note that the patched DDT does not need a
   <cr>  after the "." to return to the command  or  prompt
   mode.

c) A "^" may be entered to cause DDT to display the contents
  of the previous memory address. This is the back-up mode.
  Note  that the backup is immediate and does not require a
  <cr> after it.

d)  A two digit hexadecimal value may be entered  to  modify
  the  contents of the currently displayed memory location.
  The  digits must be 0-9;A-F or DDT will display a "?" and
  return  to the prompt mode. The second entered digit will
  be taken immediately and will change the memory contents.
  The next higher address will then be displayed.

I hope you enjoy the up arrow feature as much as I  do.  Or
as Kelly Smith would say, "Get your gibblets jiggled."

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

         CP/M Bit Map File Allocation...EXPLAINED!
         =========================================
                           by
                       Kelly Smith


                    What It's for...

For  each  diskette  "logged-on"  to the  CP/M  Basic  Disk
Operating   System  (BDOS),   physical  diskette  space   is
dynamically  allocated  to that diskette  (for  later  write
operations)   and  maintained  in  memory  by   Bit   Mapped
Allocation.  When changing diskettes (and to avoid the "R/O"
error  message)  you  must  enter  Control-C  to  erase  the
previous  diskettes Bit Map,  and cause the BDOS to read the
file directory to establish the new Bit Map.  On  subsequent
write  operations to the diskette,  the Bit Map is modified,
and  the  diskette  File Control Block (FCB)  for  the  (now
closed file) is updated in the File Directory.

                     What It Is...

The  Bit Map is actually a tight encoding of available  (or
not)  sectors on the diskette.  The Bit Map is an  array  of
single  bits which correspond to each block of eight sectors
allocated  for usage on the diskette.  A  blank  (formatted)
diskettes Bit Map Allocation array then looks like this:

     ("Standard" Single Density IBM Format Diskette)

              GROUP ALLOCATION MAP DRIVE - B
             11000000000000000000000000000000
             00000000000000000000000000000000
             00000000000000000000000000000000
             00000000000000000000000000000000
             00000000000000000000000000000000
             00000000000000000000000000000000
             00000000000000000000000000000000
             000000000000000000
          240 GROUPS REMAINING ON DISK OUT OF 243

Notice  that two bits are 1's...this predefines  allocation
space  for  the CP/M Directory for the  diskette  (i.e.,  16
sectors or 2 groups),  and insures that the directory is not
overwritten  when creating new files.  All remaining 0's are
free  groups,  ready to become allocated in  the  directory.
When the BDOS receives a request to create a file,  it first
searches the Bit Map until it finds a bit containing a zero,
and  the number (this will be explained shortly) of this bit
is  the number of the first free group to be  allocated  for
the  file.  The BDOS sets the bit map to a one and places  a
one  byte  hexadecimal  group  number into the  FCB  of  the
directory,  created  for the new file.  As subsequent  write
operations  occur for the file,  the BDOS examines the  last
group number in the FCB (and also the Next Record count) and
from  the numbers automatically computes the  next  physical
track  and  sector  number where the diskette  write  is  to
occur.  Keeping  in mind that eight sectors equal one group,
when  all eight sectors of a group have  been  written,  the
BDOS  searches the Bit Map again for the next bit containing
a zero. When a free allocation is found, its group number is
added  to the FCB (not necessarily a sequential number)  and
the  corresponding bit is set to a one.  Also note that  the
minimum file size that a file will be,  is one  kilobyte...a
file which has seven or fewer sectors will be shown (by STAT
Filename.Typ<cr>) as utilizing one group (1k);  a file which
has  eight  sectors will be shown as utilizing  two  groups,
even though the second group is empty.

Here  is  an  example of what one sector of  the  directory
looks like, showing four FCB's for three files:

 Filename.Typ  EX RC <--------------Group-------------->
 -------------------------------------------------------
 MACRO   .LIB  00 80 45464748 494A4B4C 4D4E4F50 51525354
 MACRO   .LIB  01 08 55000000 00000000 00000000 00000000
 PLINK   .COM  00 0B 56570000 00000000 00000000 00000000
 DISKTEST.COM  00 09 58590000 00000000 00000000 00000000

Specifically,   note   that  the  file  MACRO.LIB  has  two
entries...and also the Record Count (RC) for the first entry
is set to 80 hexadecimal.  As new records are written to the
diskette,  the RC is updated by the BDOS.  When a transition
occurs  from  7F to 80,  the BDOS adds a new  FCB  into  the
directory,  and  also  creates a new extension (EX)  to  the
file.  Bit  Map  allocation  then  proceeds  from  the  next
available group.

                        And Why...

As I mentioned, the group allocations may not be sequential
(even  though my example shows sequential groups).  As files
are deleted from the diskette, they leave "holes" in the Bit
Map to make space available for any new files to be created.
The major advantage here, is that the disk is never required
to  be  "packed down" (i.e.,  for iCOM FDOS  users  or  UCSD
Pascal  users,  you  know  what I mean!).  For users  of  an
operating   system  that  utilizes  Sequential   or   Linked
Allocation methods, my heart goes out to you...nothing quite
so  "gut wrenching" as a disk error in the middle of a  pack
operation!  The  other advantage to Bit Map  Allocation,  is
true random access to sectors (no "kludge" ISAM,  as in MITS
DOS  or  BASIC and no "rewind file pointers" as in  PASCAL),
and  dynamic  allocation of file  size.  Another  source  of
frustration regarding Linked Allocations is when an isolated
sector  (which  "forward references" the next sector in  the
file)  is "bombed"...there is no way to recover  the  ENTIRE
file intact...just up to the point of the offending sector!

Now for some detail (as promised):  To determine the  group
allocation  from the Bit Map,  we must first "split" the  in
half...then  it all begins to make (I hope) good  sense.  To
find  the (hexadecimal) group number of an individual bit in
the  Bit Map,  take the first digit from the even  (or  odd)
half row and the digit from the column in the same half.  As
shown  in  the  example  below then,  the  next  free  group
allocation is 02 and the last free group is F1:

             GROUP ALLOCATION MAP DRIVE - B
Even Half Row             Columns             Odd Half Row

            0123456789ABCDEF 0123456789ABCDEF
            ---------------------------------
         0 :1100000000000000:0000000000000000: 1
         2 :0000000000000000:0000000000000000: 3
         4 :0000000000000000:0000000000000000: 5
         6 :0000000000000000:0000000000000000: 7
         8 :0000000000000000:0000000000000000: 9
         A :0000000000000000:0000000000000000: B
         C :0000000000000000:0000000000000000: D
         E :0000000000000000:00              : F
        240 GROUPS REMAINING ON DISK OUT OF 243

The PHYSICAL relationship of sectors to groups is such that
Group  02  starts at Track 2/Sector 20,  Group 03 starts  at
Track 02/Sector 13 (YES!  Sector 13, because of the diskette
"skew factor"...hmmm,  a good topic for yet another  mundane
article on my part...OK, OK,...BORING!), and so on.

In conclusion,  Digital Research's CP/M BDOS makes the most
efficient  use  of available space on  the  diskette.  Other
operating systems (let's cuss MITS DOS again!) often require
that  the  file size be specified by the  user...overcaution
(and  much  guessing)  results in large  amounts  of  unused
diskette  space that is NOT AVAILABLE to other  files.  This
space  can  only be recovered by copying the data to  a  new
diskette with the proper file size specified, and WHATS EVEN
WORSE is that this same procedure must be followed to EXPAND
a  file  that  has already  utilized  the  space  originally
allocated to it! So anyway...NICE JOB Dr. Kildall!

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


  A Simple 6 Byte Hexadecimal to ASCII Conversion Routine
  =======================================================
                           by
        Kelly Smith (originator of routine unknown)

Only  six  bytes  of  8080  (or Z80)  code  can  perform  a
hexadecimal (0 to F) to ASCII conversion.  Assuming that the
hexadecimal digit is in t
he A register, then:

hex$to$ascii:       ; convert low nibble hex digit in the
                   ; the A reg., to ASCII character in the
                   ; A reg.
         adi  90h  ; first add
         daa       ; adjust result, if carry
         aci  40h  ; second add, adjust to ASCII
         daa       ; adjust result, if carry
         .
         .
         .

How  does  it work?  There are two main considerations  for
hexadecimal to ASCII conversion: Is the A register less than
ten, or is the A register greater than or equal to ten?

The first DAA instruction (which operates on the lower four
bits   (low  nibble)),   adjusts  the  result  of  the   ADI
instruction  to  less than ten.  Then  the  ACI  instruction
operates  on the upper four bits (high nibble) by adding the
carry  out of the lower nibble.  The second DAA  instruction
then adjusts the results of the high nibble to less than 10.

If the A register is initially less than ten, the first add
results in 9Xh...in this case, the DAA does not affect the A
register. The second add (with carry) results in 9Xh+40h=DXh
(D Hex = 13 Dec).  After the second DAA,  the result is  3Xh
where 'X' is the decimal digits 0 through 9;  thus the ASCII
representation   for   decimal   digit  9  results   in   39
hexadecimal.

If  the A register is initially ten or greater,  the  first
add results in 9Xh (same as before),  but the result of  the
foqst DAA is 0Yh (i.e.,  Yh=Xh-10d) and includes the setting
of  the  carry  flag.  The next add (with  carry)  gives  us
oYh+40h+1=4Zh, where Z=Y+1. The last DAA has no affect...The
hexadecimal  digits 41 to 46 represent the ASCII alphabetics
A to F...for example,  let X=10d=Ah,  then Y=X-10d=10d-10d=0
and  Z=Y+1=0+1=1...the result is 41 hexadecimal,  the  ASCII
symbol   for   'A'...the  routine  is   simpler   than   the
explanation!

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


 A CP/M 1.4 Parameter Display Program in Microsoft Basic
 =======================================================
                          by
        Kelly Smith (from a program by Rod Hart)

Its  not  often that you find a really unique utility  that
"crosses  boundries"  between  an  operating  system  and  a
computer  language...this one,  is particularly "cute"  (and
useful),  that  I  downloaded with XMODEM  from  Rod  Hart's
system...nice  job Rod!  My only changes were to make it all
fit on a 24 by 80 screen display, without using clear screen
codes that are terminal sensitive.  Note also, this WILL NOT
WORK on CP/M 2.2 parameters! So put your "thinking caps" on,
write a version for CP/M 2.2, XMODEM it to Rod or myself and
become FAMOUS (if not rich)!

10 REM CP/M Version 1.4 System Parameter Display Program
20 REM by Roderick W. Hart (WA3MEZ)
30 REM December 23, 1979
40 REM modified February 8, 1981 by Kelly Smith, CP/M-Net
50 PRINT TAB( 10) "Parameters unique to your CP/M Version 1.4 are:"
60 BD=PEEK(7)*256
70 SP=PEEK(BD+&H3A)
80 RB=PEEK(BD+&H3C)
90 LS=PEEK(BD+&H3D)
100 LB=PEEK(BD+&H3E)
110 DL=PEEK(BD+&H3F)
120 DT=PEEK(BD+&H40)
130 RE=PEEK(BD+&H3B)
140 TR=PEEK(BD+&H40)
150 MT=(BD+&H1A)
160 PRINT:PRINT TAB( 10) "Your BDOS starts at ";HEX$(BD);" hex"
180 PRINT TAB( 10) "Your sector map table is located at ";HEX$(MT);" hex"
190 PRINT TAB( 10) "Your directory allocation mask is ";HEX$(DL);" hex"
200 PRINT TAB( 10) "You have";TR;"tracks reserved for the system"
210 PRINT TAB( 10) "You have";SP;"sectors per track"
220 PRINT TAB( 10) "You have";RE;"records per extent"
230 PRINT TAB( 10) "You have";RB;"records per block"
240 PRINT TAB( 10) "Last sector in block is";LS
250 PRINT TAB( 10) "Last block on the disk is";LB
290 PRINT:PRINT TAB( 24);"Sector Map Table"
300 PRINT TAB( 24);"------ --- -----"
310 PRINT
320 FOR X=0 TO (SP-1)
330 MP=PEEK(MT+X)
340 Z=Z+5
350 IF Z<60 THEN 360 ELSE 390
360 PRINT TAB( Z);MP;
370 IF X=(SP-1) THEN 410
380 NEXT X
390 Z=5:PRINT CHR$(15)
400 GOTO 360
410 END

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


                CP/M-Net "Tip-of-the-Month"
                ===========================
                            by
                Kelly Smith and Eddie Currie

Are  you one of the "poor unfortunates" that has to contend
with  a 64 character wide screen display,  and  bashes  your
head  against the CRT in front of you (while mumbeling  "why
did  I  EVER  BUY this #`!%&$ THING...it SCREWS UP  the  DDT
'DUMP' display so badly,  I can't even use it!").  Well,  no
more  tears  on  the  keyboard my  friend...just  put  these
patches into DDT or SID,  and as if by magic (at no time  do
my  fingers  leave my hands),  VOILA...a 64  character  wide
'DUMP' that you can actually READ!!!...follow along:

For users of DDT.COM version 1.4 or 2.2, make the following
substitution...

A>ddt ddt.com<cr>   <--- patch DDT.COM using DDT
DDT VER 2.2         <--- DDT announcing itself
NEXT  PC
1400 0100           <--- DDT telling us it's used 19 pages
-sa17<cr>           <--- Substitute at address 0A17 hex...
0A17 05 08<cr>      <--- ...08 instead of 05!
0A18 08 .<cr>       <--- end the substitution
-g0<cr>             <--- exit DDT and return to CP/M
A>save 19 ddt64.com<cr> <--- save the 64 wide DDT.COM

And for users of SID.COM...
A>sid sid.com<cr>   <--- patch SID.COM using SID
SID VER 1.4         <--- SID announcing itself
NEXT  PC  END
2D00 0100 B3FF      <--- SID telling us it's used 44 pages
#saa5<cr>           <--- Substitute at address 0AA5 hex...
0AA5 93 96<cr>      <--- ...96 instead of 93!
0AA6 08 .<cr>       <--- end the substitution
#g0<cr>             <--- exit SID and return to CP/M
A>save 44 sid64.com<cr> <--- save the 64 wide SID.COM

What these patches do, is to throw out the space characters
between  each  display of the hexadecimal representation  of
each  memory content of the DDT or SID  'DUMP'  display...it
crunches the display format, and make it READABLE!

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++