home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / Basic / QBXM10.ZIP / QBXMAPND.DOC < prev    next >
Encoding:
Text File  |  1991-06-18  |  24.1 KB  |  489 lines

  1.  
  2.                                                              QBXM ver 1.0
  3.                                                                Appendix A
  4.  
  5.  
  6.                      EMS Specification vs XMS Specification
  7.  
  8.                                 Allocation Units.
  9.  
  10.         The  EMS  specification calls for a minimum  allocation  unit  of
  11.         16,384 bytes, called a page.  All memory size specifications  are
  12.         expressed in these 16k pages.  The XMS specification calls for  a
  13.         1024 byte minimum unit, so any allocation needs to be a  multiple
  14.         of 1k.  QBXM converts calls for a page within an XMS  environment
  15.         to  16k  multiples and uses the 'page' concept  throughout.   For
  16.         example,  when a call is made to QBXM to allocate 1 page,  in  an
  17.         XMS  environment,  the  page count is multiplied by  16  and  the
  18.         request is passed through to the driver for 16k.
  19.  
  20.  
  21.                                  Handle Counts.
  22.  
  23.         There  are  both a default number of handles  available  in  both
  24.         specifications and a maximum count allowed.  With EMS the maximum
  25.         number  of handles is 256, with handle 0 being reserved  for  the
  26.         operating  system.   XMS allows for a number of handles  I  can't
  27.         find  in  the documentation, but HIMEM.SYS will allow up  to  128
  28.         maximum.   Since HIMEM.SYS will only allow a maximum of 128  han-
  29.         dles,  that is also the maximum handles for QBXM.
  30.  
  31.         HIMEM.SYS  defaults to 32 handles, and the count can be  adjusted
  32.         with  the  /NUMHANDLES= command line parameter.  EMS  drivers,  I
  33.         believe, may vary in the number of default handles.  QEMM which I
  34.         use,  and an AST driver that I use on an AT&T 6300, both  default
  35.         to 64 handles.  Setting the number of handles desired is a  func-
  36.         tion of each EMS driver, and is done via a command line switch in
  37.         the CONFIG.SYS file.
  38.  
  39.  
  40.                                 File Buffer Space
  41.  
  42.         This  may be tedious for the reader, but here I go.   When  using
  43.         EMS, there is a 64k block of conventional memory between 640k and
  44.         1  megabyte available that is called the page  frame.   Different
  45.         sections  of  expanded memory can be moved into and out  of  this
  46.         space, and any application can address this space, including  DOS
  47.         and  BIOS  routines.   When the Load (or Save)  File  routine  is
  48.         called, a buffer is needed to read the disk data into.  If EMS is
  49.         in  use,  16k of this section of memory is used as  a  buffer  by
  50.         QBXM.   The  data is moved from disk to the buffer  and  then  to
  51.         expanded memory in 16k chunks.  No memory need be taken from  the
  52.         BASIC data area.
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.                                         1
  63.  
  64.  
  65.                                                              QBXM ver 1.0
  66.                                                                Appendix A
  67.  
  68.         Within  the XMS specification, four types of memory are  defined.
  69.         Conventional  from 0k to 640k, Upper Memory from 640k  to  1024k,
  70.         High  Memory  from 1024k-16 to 1088K, and  Extended  Memory  from
  71.         1088k  to the top of installed memory.  The upper memory area  is
  72.         the  only  one (other than conventional) that could  be  reliably
  73.         used as a buffer area for disk transfers.  The XMS specification,
  74.         written  by Microsoft, Lotus, Intel and AST  Research,  specifies
  75.         calls  to  allocate and deallocate portions of the  upper  memory
  76.         block.  This should allow QBXM to handle disk transfers in an XMS
  77.         environment the same as it does for EMS.  However, Microsoft does
  78.         not  implement the upper memory calls in HIMEM.SYS.  I  know,  if
  79.         they had a hand in writing the spec, why don't they implement all
  80.         it's features?  Who knows?  They use the high memory area  exten-
  81.         sively with Windows (with 2.0 first?), but I think they wanted to
  82.         avoid stepping on a possibly loaded EMS manager.  The high memory
  83.         area  cannot be used for disk transfer buffers however,  DOS  and
  84.         the BIOS may not correctly handle the addresses.
  85.  
  86.         This  left me in a quandary.  When running under XMS, QBXM  would
  87.         need a buffer area for the file transfer, and it would have to be
  88.         allocated from the BASIC data area.  Three alternatives presented
  89.         themselves.
  90.  
  91.         One, I could have written the code to use a buffer area  supplied
  92.         by  the  calling program from it's data area, and read  the  disk
  93.         file into it, then transferred from that buffer into extra  memo-
  94.         ry.   If I did that though, then the 64k buffer available to  EMS
  95.         implementations would not have been used, and memory cramp  might
  96.         ensue in some situations.  Just seems to be a waste of a resource
  97.         that  might be available, and required the passing of three  more
  98.         parameters, the segment, offset and length of the buffer.
  99.  
  100.         Two,  taking  the  above a step further, I could  have  the  QBXM
  101.         routine  check  for EMS or XMS.  If EMS I would  load  from  disk
  102.         into the EMS page frame's 64k at 16k per loop, and from there  to
  103.         extra memory.  If XMS was in use, then the calling BASIC  program
  104.         would  have  to  allocate the buffer (an array of  x  bytes)  and
  105.         specify  where the  buffer was allocated (VARSEG and  VARPTR)  in
  106.         the  BASIC  data space, and the size of the buffer.   The  buffer
  107.         could  be  larger than 16k to speed things up a bit, but  a  disk
  108.         transfers only at such and such a speed.  This presents some com-
  109.         plexities in that there would be the DIM'ing of the buffer  (only
  110.         for  XMS)  and  the  passing of  three  extra  parameters  for  a
  111.         load/save file call, regardless of which type of extra memory was
  112.         installed  at  run time.  To be honest, it is  a  more  efficient
  113.         method  than  what  I implemented, but I am trying  to  keep  the
  114.         interface as simple as possible.  The code in BASIC would require
  115.         something like what's on the following page.
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.                                         2
  125.  
  126.  
  127.                                                              QBXM ver 1.0
  128.                                                                Appendix A
  129.  
  130.         rLen = LEN(record)
  131.  
  132.         IF ems THEN
  133.              bSeg = 0
  134.              bOfs = 0
  135.              bytes = 0
  136.              CALL LoadFileXM (f$,rlen,bseg,bofs,bytes,handle,recs&,eCode)
  137.         ELSEIF xms THEN
  138.              x& = FRE(-1)
  139.              .... that gives you the free memory from which you
  140.              .... would calculate the number of elements to DIM an
  141.              .... array based on the memory available.  Elements
  142.              .... would vary based on the type of array of course..
  143.              DIM temp(1 TO elements)
  144.              bSeg = VARSEG(temp(1))
  145.              bOfs = VARPTR(temp(1))
  146.              bytes = elements * bytesPerElement
  147.              CALL LoadFileXM (f$,rlen,bseg,bofs,bytes,handle,recs&,eCode)
  148.              ERASE temp
  149.         END IF
  150.  
  151.  
  152.         The  third  option, and the one I settled on, was to  allocate  a
  153.         1024 byte buffer area within the QBXM code.  This 1k buffer comes
  154.         out  of  the data area that would normally be available  to  your
  155.         BASIC program, and is only used when XMS is in use, though it  is
  156.         allocated regardless of the extra memory type.  This seemed to be
  157.         an acceptable trade off, because EMS is more common than XMS,  it
  158.         does not use very much of the data space available, and QBXM does
  159.         try  to  allocate some upper memory first, before using  this  1k
  160.         buffer.  Let's just say I'm hopeful that upper memory support may
  161.         be  out  there in a driver other then HIMEM, or  HIMEM  may  soon
  162.         implement it.  It doesn't in DOS 5 by the way.  Anyway, the  code
  163.         tries  for a 16k upper memory block buffer, and if the  block  is
  164.         not  available, or upper memory blocks are not  implemented,  the
  165.         code falls back to using the 1k internal buffer.
  166.  
  167.         What this boils down to is that a file load loop using EMS  would
  168.         read  16384 bytes of the file, then transfer 16384 to  EMS  extra
  169.         memory  with  each loop.  The same loop using XMS  would  require
  170.         roughly  16  times as many loops.  This sounds  terrible  on  the
  171.         surface,  but  assembly loops being quicker than  the  equivalent
  172.         BASIC  loops,  and trying to preserve memory  available  to  your
  173.         BASIC program, it might not seem so terrible.
  174.  
  175.         Bottom  line is that I would like to hear from users  on  whether
  176.         they agree with my logic.  Maybe I was to conservative on the  1k
  177.         buffer?   Maybe a 4k buffer would be acceptable?  Maybe a  second
  178.         object  file and routine that used 8k at a clip, and  if  testing
  179.         showed  memory  cram,  you could fall back to  the  1k  routines?
  180.         Maybe the extended calling routine, where the buffer is allocated
  181.         from within the calling program?  Self doubt is a terrible thing,
  182.         tell me what you think!
  183.  
  184.  
  185.  
  186.                                         3
  187.  
  188.  
  189.                                                              QBXM ver 1.0
  190.                                                                Appendix A
  191.  
  192.                            QBXM & EVEN Length Records
  193.  
  194.         At  first  glance, the insistence that record lengths  and  block
  195.         moves be an even number of bytes may seem odd.  Read on.
  196.  
  197.         EMS was developed to extend the useful life of PC and XT  comput-
  198.         ers.   PC and XT class machines use an eight bit data bus.  So  a
  199.         byte transfer is no problem, a byte being eight bits.
  200.  
  201.         Extended memory is a different matter though.  Extended memory is
  202.         only available on AT class machines which have as a minimum, a 16
  203.         bit  data bus.  Data transfers being more efficient with 16  bits
  204.         at  a time than with 8 bits, and not being available on an 8  bit
  205.         machine,  why  the  heck should the Extended  Memory  Spec  (XMS)
  206.         bother  with  byte  sized transfers?   Exactly,  so  it  doesn't.
  207.         Interesting thing is that XMS memory moves are specified in bytes
  208.         instead of words.  Probably thought it was a more common unit  of
  209.         measurement for programers.
  210.  
  211.         Therefore,  there is no choice but to write QBXM to use  word  (2
  212.         byte)  sized memory moves.  This includes user defined  types  of
  213.         course.
  214.  
  215.         The  best  way to handle odd length records?  Maybe  DIM  an  odd
  216.         length  record to 2 elements, two times anything seems to  be  an
  217.         even number.  Then tell QBXM that all records are two times there
  218.         actual length and adjust accordingly.  For example:
  219.  
  220.         TYPE AddressRecord
  221.              Name AS STRING * 26
  222.              Addr AS STRING * 26
  223.              Town AS STRING * 14
  224.              St   AS STRING * 2
  225.              Zip  AS STRING * 5
  226.         END TYPE
  227.  
  228.         '  That zip code will get you each time!
  229.         '  A record length here works out to 73 bytes.
  230.  
  231.         DIM SHARED address AS AddressRecord
  232.         DIM SHARED tempAddress(0 TO 1) AS AddressRecord
  233.  
  234.         rLen = LEN(address) * 2       'This is the value you pass to QBXM
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.                                         4
  249.  
  250.  
  251.                                                              QBXM ver 1.0
  252.                                                                Appendix A
  253.  
  254.         ' For any given record number, actualRecord, you use the follow-
  255.         ' ing formulas:
  256.  
  257.         getRecord& = ((actualRecord - 1) \ 2) + 1
  258.         '  Which results in the following:
  259.         '    actualRecord:  ((actualRecord - 1) \ 2) +   1 = getRecord:
  260.         '       1             ((    0      ) \ 2) =  0  +  1  =    1
  261.         '       2             ((    1      ) \ 2) =  0  +  1  =    1
  262.         '       3             ((    2      ) \ 2) =  1  +  1   =   2
  263.         '       4             ((    3      ) \ 2) =  1  +  1   =   2
  264.         '       5             ((    4      ) \ 2) =  2  +  1   =   3
  265.         '       6             ((    5      ) \ 2) =  2  +  1   =   3
  266.         '   etc...
  267.  
  268.         Then  you use GetRecXM to retrieve the record from QBXM's  record
  269.         orientated  routines,  and access the final desired  record  like
  270.         this:
  271.  
  272.              vSeg = VARSEG(tempAddress(0))
  273.              vPtr = VARSEG(tempAddress(0))
  274.              GetRecXM (handle, getRecord&, vSeg, vPtr, errCode)
  275.  
  276.              address = tempAddress((actualRecord + 1) MOD 2)
  277.  
  278.         '  Which results in the following:                   Element
  279.         '    actualRecord:  (actualRecord+1) MOD 2   =     Returned:
  280.         '       1           (      2       ) MOD 2   =             0
  281.         '       2           (      3       ) MOD 2   =             1
  282.         '       3           (      4       ) MOD 2   =             0
  283.         '       4           (      5       ) MOD 2   =             1
  284.         '       5           (      6       ) MOD 2   =             0
  285.         '       6           (      7       ) MOD 2   =             1
  286.         '   etc...
  287.  
  288.         If you have a more compact, efficient method, let me know, it  is
  289.         late as I write this.
  290.  
  291.         Putting a record would require the reverse logic.
  292.  
  293.              tempAddress((actualRecord + 1) MOD 2) = address
  294.  
  295.         '  Which results in the following:                   Element
  296.         '    actualRecord:  (actualRecord+1) MOD 2   =     Returned:
  297.         '       1           (      2       ) MOD 2   =             0
  298.         '       2           (      3       ) MOD 2   =             1
  299.         '       3           (      4       ) MOD 2   =             0
  300.         '       4           (      5       ) MOD 2   =             1
  301.         '       5           (      6       ) MOD 2   =             0
  302.         '       6           (      7       ) MOD 2   =             1
  303.         '   etc...
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.                                         5
  311.  
  312.  
  313.                                                              QBXM ver 1.0
  314.                                                                Appendix A
  315.  
  316.         putRecord& = ((actualRecord - 1) \ 2) + 1
  317.  
  318.         '  Which results in the following:
  319.         '    actualRecord:  ((actualRecord - 1) \ 2) +   1 = putRecord:
  320.         '       1             ((    0      ) \ 2) =  0  +  1  =    1
  321.         '       2             ((    1      ) \ 2) =  0  +  1  =    1
  322.         '       3             ((    2      ) \ 2) =  1  +  1   =   2
  323.         '       4             ((    3      ) \ 2) =  1  +  1   =   2
  324.         '       5             ((    4      ) \ 2) =  2  +  1   =   3
  325.         '       6             ((    5      ) \ 2) =  2  +  1   =   3
  326.         '   etc...
  327.  
  328.         Then  you  use PutRecXM to store the record  into  extra  memory:
  329.  
  330.              vSeg = VARSEG(tempAddress(0))
  331.              vPtr = VARSEG(tempAddress(0))
  332.              PutRecXM (handle, getRecord&, vSeg, vPtr, errCode)
  333.         I  hate putting an important warning at the start of a new  page,
  334.         when it applies to a previous page, but I've no choice here.
  335.  
  336.         NOTE:     When using a 'doubled' type variable as in the previous
  337.         example, remember not to destroy the data in extra memory for the
  338.         element not being worked on.
  339.  
  340.         What's that?  Well for each actual element or record you retrieve
  341.         there is an innocent bystander with it.  Take for example, a case
  342.         where  you need to retrieve the first record from  extra  memory.
  343.         The  record you want to work with will be in element zero of  the
  344.         double  record, and valid data will also be in element  one.   If
  345.         you destroy the temporary double record after extracting  element
  346.         zero, work with it, then DIM the double record again, insert  the
  347.         revised data in element zero and write the double element back to
  348.         extra  memory, actual record two (element one in the  double  re-
  349.         cord)  is  all zeros.  Your extra memory 'file' now has  a  blank
  350.         record  in it.  If you, as I did in the example, dim  the  double
  351.         record as a SHARED variable, and keep in mind that there is extra
  352.         data  all  the time you're working with the  double  record,  all
  353.         should be OK.
  354.  
  355.         A  better  method for storing data may be to force  a  read  (Ge-
  356.         tRecXM)  immediately before a write (PutRecXM),  calculations  as
  357.         before:
  358.  
  359.              Calculate the double size record number.
  360.              Retrieve it from extra memory.
  361.              Calculate the element (0 or 1) in the double record.
  362.              Update the proper element (0 or 1).
  363.              Write the double record back to extra memory.
  364.  
  365.  
  366.         All in all, a great argument can be made for padding your records
  367.         with one byte to assure they are an even length.
  368.  
  369.  
  370.  
  371.  
  372.                                         6
  373.  
  374.  
  375.                                                              QBXM ver 1.0
  376.                                                                Appendix A
  377.  
  378.                         Extended Memory and Vdisk et al.
  379.  
  380.         When  the AT was introduced with it's extended memory, an  inter-
  381.         rupt, 15 hex, was supplied in the BIOS to make limited use of the
  382.         extended memory available.  INT 15 hex can be called to determine
  383.         the  amount  of  extended memory installed.  At  the  same  time,
  384.         VDISK.SYS was distributed with PC-DOS 3.0+, which  took advantage
  385.         of extended memory also.
  386.  
  387.         These  two items presented two different ways to access  extended
  388.         memory.  The "INT 15 method" is one, and what the basic implemen-
  389.         tation  consists  of is that a program (a TSR  maybe)  that  uses
  390.         extended  memory would call INT 15 to find out how much  extended
  391.         memory  was available.  Next it would deduct what it needed  from
  392.         'the top' so to speak, then intercept any other calls to the  INT
  393.         15 "How much Extended is there?" function.  When an intercept  is
  394.         made, the program returns the reduced amount to any  applications
  395.         that ask.
  396.  
  397.         VDISK.SYS  was distributed with it's source code in  PC-DOS,  and
  398.         used  a different allocation method.  It took what was needed  of
  399.         extended  memory from the bottom of extended memory  (1024k)  and
  400.         worked upward.  If you look back a page or two, you might  notice
  401.         I mentioned the High Memory Area defined in the XMS includes  the
  402.         extended  memory from 1024k - 16 bytes to 1088k.  Opps.  This  is
  403.         the  same area VDISK would start allocating from,  and  Microsoft
  404.         wants  to use with Windows!  Since the source code to  VDISK  was
  405.         distributed  with PC-DOS, a lot of developers followed it's  lead
  406.         in  allocating  memory  from the 'bottom up' with  a  few  twists
  407.         thrown  in to make sure the chain of extended  memory  allocation
  408.         remained intact.  You could load multiple copies of VDISK.SYS for
  409.         example  to create multiple ram disks.  Only problem is, not  all
  410.         software  follows  the  VDISK check and double  check  system  of
  411.         memory allocation and use.  Some extended memory compatible TSR's
  412.         and  application  programs will use the "VDISK method"  and  even
  413.         identify themselves as "VDISK" to maintain compatibility  (though
  414.         limited)  with that method.  Try a text scan of your  hard  drive
  415.         for  "VDISK", you may be surprised at the number of  applications
  416.         that  include  the text string, which is loaded  into  memory  to
  417.         identify it as a VDISK type memory allocator.
  418.  
  419.         I find myself getting off track all of a sudden.  So we have  two
  420.         methods  for  allocating extended memory.  One is  from  the  top
  421.         down,  where each application that takes some  memory  intercepts
  422.         queries  about how much is there and reports the amount it  knows
  423.         of,  less  what  it's using.  Then VDISK,  which  if  implemented
  424.         properly  works  from the bottom up, and gives an  indication  of
  425.         where it's extended memory use ends.  A program that wants to use
  426.         extended memory is supposed to follow this chain of VDISK  blocks
  427.         up, and calculate how much is left.  Of course there's no guaran-
  428.         tee that the memory chain is implemented properly along the  way.
  429.         When XMS was developed, I suppose that the this VDISK  allocation
  430.         system  had been used and abused, thus the XMS fellows  said  the
  431.         heck  with  it.  If an XMS driver finds a "VDISK"  type  extended
  432.  
  433.  
  434.                                         7
  435.  
  436.  
  437.                                                              QBXM ver 1.0
  438.                                                                Appendix A
  439.         memory  manager in use when it's loaded from CONFIG.SYS, the  XMS
  440.         manager won't load.  If a "VDISK" type driver is loaded after the
  441.         XMS  driver, it will be detected on an XMS call.   This  checking
  442.         for  a  "post XMS driver installation of a  VDISK"  type  program
  443.         impresses  me  as meaning they are something to stay  away  from.
  444.         After  the reading I've done on the various memory  related  sub-
  445.         jects I can see why.
  446.  
  447.         With  almost  every product that  includes  HIMEM.SYS,  Microsoft
  448.         includes RAMDRIVE.SYS, a fully compatible XMS application.   Just
  449.         be sure RAMDRIVE is loaded after HIMEM.SYS in the CONFIG.SYS file
  450.         and you've got a non-interfering ram disk instead of using VDISK.
  451.  
  452.         When  it  came to accessing extended memory with QBXM, I  had  to
  453.         decide  just  how to implement it.  Follow the INT  15  or  VDISK
  454.         methods  if an XMS driver wasn't there, and extended  memory  was
  455.         installed.  Or insist on using a formal specification?  True,  if
  456.         I  used the INT 15 top down approach, there would be no  need  to
  457.         specify that an XMS driver such as HIMEM.SYS be installed.  If  I
  458.         included the INT 15 method after a check for EMS and then XMS, it
  459.         would eliminate the HIMEM.SYS requirement.  Of course that  means
  460.         I could  also allow you to walk down in memory right over a VDISK
  461.         type  ram disk or cache or whatever in extended memory.  Call  me
  462.         dull, but I figured a specification of one type was better than a
  463.         "custom" of another.
  464.  
  465.  
  466.                           Extended Memory And The 80286
  467.  
  468.         When  INTEL  designed the 80286, they made the chip power  up  in
  469.         real  mode,  where  it would act just  like  an  8088/8086  chip.
  470.         Included  on the chip is a method to switch from real  mode  into
  471.         protected  mode.  Protected mode was (and is) considered so  much
  472.         more efficient than real mode, a method of switching back to real
  473.         mode  was  not  considered to be a need.  A work  around  to  the
  474.         problem involves some tricky stuff that I'm not altogether  clear
  475.         on but what I think happens is interesting.  When the BIOS  wants
  476.         to switch out of protected mode and back to real mode, it  writes
  477.         a 'magic' value to a specific location in memory.  Next it  sends
  478.         a  command to the keyboard controller that causes the  controller
  479.         to  issue  a warm boot instruction, as if you  hit  Ctrl-Alt-Del.
  480.         When  the ROM BIOS starts it's warm boot routine, it  checks  for
  481.         that  'magic value' in memory.  If it finds it, then the  machine
  482.         is not really being reset, just the processor is.  Somehow memory
  483.         is  preserved through all this, and the processor picks  up  from
  484.         where  it should in your program code.  Interesting trivia  true,
  485.         but the thing to keep in mind is how much is going on.  When  you
  486.         access  extended memory on an 80286, it's going to be slow.   The
  487.         XMS manager takes care of everything painlessly for the  program-
  488.         mer, but it's a real workout for the hardware.
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.                                         8
  497.  
  498.  
  499.