1.0 INTRODUCTION LINX III terminal memory is divided into 3 basic ...

yakconspiracyΛογισμικό & κατασκευή λογ/κού

14 Δεκ 2013 (πριν από 7 χρόνια και 8 μήνες)

398 εμφανίσεις




• Revision Date: October 2000

Article 12

HOW TO FIT YOUR LINXBASIC

PROGRAM INTO MEMORY


625 Digital Drive, Plano, TX 75075 Tel: (972) 964
-
7090 Fax: (972) 964
-
7643 Web Page: www.linxdata.com

1.0

INTRODUCTION


LINX III terminal memory is divided into 3 basic portions (sizes are approximate, and depend on
the particular terminal type and firmware version):





























The bottom 3 areas are
fixed

in size.

That is, you cannot purchase additional memory for the
terminal and expand the areas. Only the RAM file/Host queue area can be extended by adding
memory.


This means that a 128K terminal has the same amount of
program space

as a 768K terminal: around
13.
7K bytes.



13K

Application Program

8K
Overhead

128K

BASIC RAM

64K EP
ROM BOOT ROM

User RAM &
Files

11K
-

747K

768K

TOTAL RAM

2.0

DIAGNOSING A MEMORY SHORTAGE


2.1

At Compile
-
Time


When possible, you should try to prevent out
-
of
-
memory conditions from occurring at run
-
time by
keeping an eye on your total program size as you develop and expand your program. You can

get a
feel for your program size by using this command option to invoke the LinxBASIC compiler:




LXB pgmname,pgmname,pgmname
-
f


The last page of pgmname.LST will then give a summary of the compiler statistics, including the
program size. A sample sum
mary page is illustrated below. We have highlighted in
bold

the line
showing the program pseudo
-
code size.

----------------------------------------------------------------------------

PAGE 2 LinxBASIC Compiler Thu Apr 30 13:49:01 19
92


COMPILER STATISTICS


Source filename: DEFAULT.BAS

File size: 25766

File timestamp: Thu Apr 30 09:08:28 1992

Compiled on: Thu Apr 30 13:49:01 1992


Download filename: DEFAULT.LXE

Program checksum A99F

Program pseudo
-
code size: 6006 bytes which is
37% of compiler capacity

Array descriptors: 6 words which is 6% of compiler capacity

Static memory allocation for data 182 bytes

Peak dynamic (run
-
time) memory allocation 46 bytes in procedure READSTRFIELD

Peak compiler symbol table useage 490 symbols in
procedure (module
-
level)


which is 61% of compiler capacity

Peak compiler name table useage 1646 bytes in procedure (module
-
level)


which is 32% of compiler capacity

Procedure prototypes: 73 which is 29% of compiler capacity

Compiler version timesta
mp: Oct 4 1991 12:25:24

Pseudo code version 02

Compiler ran 3 seconds

Compiler emits pseudo
-
code for the Linx data collection terminal from:


Linx Data Terminals, Inc.


625 Digital Drive, Suite 100


Plano, TX 75075


(214) 964
-
7090


NO ERRORS DE
TECTED

------------------------------------------------------------------------------


But, that's not all. To the program pseudo
-
code size we must add several other memory allocations.
Add in the values given by
Static Memory Allocation

and
Peak Dynamic

Memory Allocation

to get
a better picture of the memory usage. In the above example, 6,006 + 182 + 46 bytes = 6,234 bytes.
So, the program can be expected to use
at least

6,234 bytes at runtime. In practice, these compiler
statistics do not tell the wh
ole story, and a program of this size might allocate an additional 1000
bytes or so while running. For example, in a test with the above program after downloading and
running, the program space had been decremented by 7,731 bytes.



2.2

At Run
-
Time


A run
-
time program memory shortage will always result in a crash. LINX programs crash with one
of the following error messages when they run out of memory:




PS Stack Overflow/Underflow



Pseudo
-
PC


Under certain conditions, you may get a different error mess
age which was also due to a memory
shortage. You may also get one of the above message for a totally different problem, because these
error messages result from a problem with stack allocation.


So, to make a more certain determination of whether your pro
gram crashed due to an out
-
of
-
memory condition, use Status Display #6 (see
LINX III User's Guide
) to view the various memory
sizes. The display may look something like this:






128 245 147


1
0946 7654


Status Display #6


The
top middle

value (in this case 245) is the
current

program memory remaining. In an empty
terminal, this value has been observed to be around 13,900 bytes. The
top right

value indicates the
maxi
mum

program memory usage since the last reset to factory defaults. During the program run,
subroutines may be called which would increase the program memory utilization, causing both
figures to decrement. When that space is de
-
allocated after a RETURN fr
om the subroutine, the
middle figure will increase, but the right figure will remain at its lowest level.


If either value gets as low as in the illustration above, you may have run out of memory. You may
be out of memory even if the value is over several

hundred bytes. The exact cutoff value is
determined by the particular stack, string, and array utilization of your specific program at the time
the memory space was required. For example, the value might be at 1,000 bytes, just as you attempt
to allocat
e a string array of 1,001 bytes, and the program would crash, showing 1,000 bytes in both
of the memory values in Status Display #6.




If your error message was:




File Memory


then you are not out of program space, but rather you have exceeded the maxi
mum amount of space
available in the RAM file and host queue space. This could be due to one of these problems:



1. Continued storage of data in the host queue while the host is offline;


2. Record numbers specified in PUT statements are too high;


3. Us
ing PRINT or WRITE to extend a sequential file beyond memory limit;


File Memory errors are outside the scope of this document. If you have a problem that cannot be
reduced to a simple program logic error or mishandling of available RAM file space ordered

on the
terminal, please feel free to contact our Technical Support department as described on the last page
of this document.



3.0

THE CULPRITS


This document does not address the problem of insufficient file memory, since that can be easily
solved by p
urchasing additional memory. But running out of program memory is serious because
the only remedy is a modification to the program to make it smaller
-

you cannot expand the fixed
boundaries at the bottom portion of the memory map or purchase more memory
to improve your
program space.


There are, however, some very well
-
known culprits in this war against wasted memory, and the
remedies are not terribly difficult. Here are some of the problems
-

we will discuss solutions
afterward, in Chapter 4.




3.1

Str
ing Literals


String literals are big program memory hogs. Consider, for example, the program memory usage
for these BASIC statement:




PRINT








9 bytes



PRINT "1"







15 bytes



PRINT "1234567890"






24 bytes



PRINT "Scanner Station
-

Please
scan your badge"


54 bytes


When string literals get over about 4 characters long, they exceed the memory required for the
PRINT statement.



3.2

String Arrays


String arrays can get out of control quickly. For example, this innocuous little statement:




DIM A$(10,10)


reserves 100 string array pointers! If you start assigning values to those array elements, you may
find yourself out of memory quickly.


Worse yet is this little gem:




DIM A$(8,8,8)


It looks like a small array, but in fact, when you mul
tiply it out, it contains 512 elements!



3.3

Excesses in LINX Application Library Subroutines


LINX Data Terminals, Inc. encourages the use of its
Application Library

of subroutines, stored in
the ENV.BAS, MENU.BAS, READ.BAS, MATH.BAS, and TRIG.BAS progr
am files. However,
if you do not use any of the MENU functions, including the MENU.BAS file will eat up precious
program space.


Furthermore, if you never use a bar code reader, you may want to eliminate those portions of code
in the TestEvent function wh
ich refer to the bar code devices, the "BAR" device, etc.


Judicious trimming of these Application Library subroutines can save you several hundred or even
thousand bytes. But make sure you don't edit the original sources for these files! You may need
th
ose subroutines later on, and if you make a mistake, you will need to be able to go back to the
original source to see what went wrong.


4.0

SOLUTIONS


The basic principle of reducing LINX program memory usage is to eliminate the culprits
and replace them

with alternative code. This is not necessarily as difficult as it may seem.
Here are some ideas, listed in priority order.



4.1

Eliminate duplicate string literals by using DIM SHARED


If your program has many small literals, combine them into a single

DIM SHARED
variable which is initialized once in the program. Let's illustrate this with a somewhat
absurd program segment which, nevertheless, illustrates the point well:



X$ = " " + DATE$ + ", " + TIME$ + ", " + Empl$ + ", " + Qty$ + "," + GooGoo$


X$

= " " + DATE$ + ", " + TIME$ + ", " + Empl$ + ", " + Qty$ + "," + GooGoo$


X$ = " " + DATE$ + ", " + TIME$ + ", " + Empl$ + ", " + Qty$ + "," + GooGoo$


X$ = " " + DATE$ + ", " + TIME$ + ", " + Empl$ + ", " + Qty$ + "," + GooGoo$


X$ = " " + DATE$ + ", "
+ TIME$ + ", " + Empl$ + ", " + Qty$ + "," + GooGoo$


The above block of code
-

while not terribly useful
-

uses 240 bytes of program space.


If that block is replaced by the following sequence:



DIM SHARED Cma$


DIM SHARED Spc$


DIM SHARED CmaSpc$


Cma$
= ","


Spc$ = " "


CmaSpc$ = Cma$ + Spc$


X$ = Spc$+ DATE$+ CmaSpc$+ TIME$+ CmaSpc$+ Empl$+ CmaSpc$+ Qty$+ Cma$+ GooGoo$


X$ = Spc$+ DATE$+ CmaSpc$+ TIME$+ CmaSpc$+ Empl$+ CmaSpc$+ Qty$+ Cma$+ GooGoo$


X$ = Spc$+ DATE$+ CmaSpc$+ TIME$+ CmaSpc$+ Empl$+ CmaS
pc$+ Qty$+ Cma$+ GooGoo$


X$ = Spc$+ DATE$+ CmaSpc$+ TIME$+ CmaSpc$+ Empl$+ CmaSpc$+ Qty$+ Cma$+ GooGoo$


X$ = Spc$+ DATE$+ CmaSpc$+ TIME$+ CmaSpc$+ Empl$+ CmaSpc$+ Qty$+ Cma$+ GooGoo$


The above block of code requires only 228 bytes.


Obviously, there is
a certain amount of overhead associated with a DIM SHARED
statement and an initialization of the variable. But, when that variable takes the place of
several repetitions of a string literal, it saves memory.


The DIM SHARED declarations must be made in th
e outer module. Do not make the
mistake of using CONSTants in place of the DIM SHAREDs. This will not save you any
memory, because the CONST is replaced at compile
-
time with the actual string literal, and
you will have accomplished nothing!

4.2

Eliminat
e long string literals by using a RAM file


Since the most restricted memory area is the program space, and the area which can be
most easily expanded is the RAM file space, it follows that we would want to move
everything we can out of the program space,
into the RAM file space.


Fortunately, this can be done fairly easily for one class of culprits common in most LINX
III programs: String Literal Prompts.


Take this example:



PRINT "Please scan your badge"


'This takes up much program memory


PRINT "And e
nter the quantity"


'So does this


We can rewrite this way to save memory:



x$ = Prompt$(1)


PRINT x$


x$ = Prompt$(2)


PRINT x$


and create a new function called PROMPT$ to read those records from a data file.


Then we build a sequential file on the host

computer using a simple text editor,
containing all the desired prompts, error messages, and other long text strings. In
the above example, the file PROMPTS would contain:



Please scan your badge


And enter the quantity


Prompt 3


Prompt 4


Etc.


Now, d
ownload the PROMPTS file to the terminal's RAM file memory, then
download the program and start it up. The effect will be the same as if you had
hard
-
coded all the prompts, with one difference: a tremendous space savings!
Again,
small

programs may not be
nefit from this because of the overhead involved
in coding the Prompt$() function.


A by
-
product of this mechanism is the ability to easily construct a bi
-
lingual
prompt set. You can download a FRENCH file, an ENGLISH file, and a SPANISH
file, and allow t
he operator to select which language he wants the prompts and
error messages to appear in! (The terminal holds up to 15 files.)

Here is a sample of the Prompt$ function to read the prompt records from the file:


FUNCTION Prompt$(recNbr)


OPEN "Prompts" F
OR INPUT AS #PromptFileNbr


IF recNbr > 1 THEN



FOR i = 1 TO recNbr
-
1




LINE INPUT #PromptFileNbr, x$


'Eat unused records



NEXT i


ENDIF


LINE INPUT #PromptFileNbr, a$




'Read desired record


Prompt$ = a$


CLOSE #PromptFileNbr

END FUNCTION


A natural
question here is: why don't you use a RANDOM file, and just GET
directly to the desired record. The answer is that
sequential

files can be downloaded
directly using network directives, without requiring any special programming,
whereas a
random access

fil
e would require a special subroutine in the application
program to read from the host and write to the RANDOM file using PUTs.


You could, however, define the record using a TYPE statement to consist of fixed
length records, terminated by carriage return a
nd line feed as below:


TYPE MyRecordType


TextString AS STRING * 40


CRLF AS STRING * 2

END TYPE

DIM SHARED MyRecord AS MyRecordType


Now, when you create your PROMPTS file, all records MUST be the same length,
or you will have skewed data. B
ut, it will allow you to simplify the Prompt$
function as follows (note the differences highlighted):


FUNCTION Prompt$(recNbr)


OPEN "Prompts" FOR
RANDOM

AS #PromptFileNbr


GET #PromptFileNbr, recNbr, MyRecord


Prompt$ =
RTRIM$(MyRecord.TextString)


CLOSE

#PromptFileNbr

END FUNCTION

4.3

Good programming techniques


Common sense should prevail when you are writing LINX III programs. This
should include:



Combining duplicate code sections into common subroutines and functions


Combining duplicate strings
into common DIM SHARED variables


Using DIM SHARED variables in place of lengthy subroutine parameters



which use up stack space


Not nesting too deeply, which uses up stack space



5.0

IF THE PROGRAM IS STILL ENORMOUS


Some programs just cannot be pared

down to a suitable size, no matter how much
you trim and chop, slice and combine. If that is the case with your program, you
may have to break it up into at least 2, and possible more independent programs,
and allow each one to CHAIN to the others when n
eeded.


CHAINing is not something to be taken lightly. It requires some redesign of the
program in order to be able to pass all the required variables from one program to
the next. If you think your program is going to ultimately exceed available
memory,

you should plan to CHAIN right from the start
-

in the design phase, if
possible.


If you do need to CHAIN, please request our Technical Information:
Chaining
Programs in LinxBASIC,

which discusses the techniques and prerequisites for
successful CHAINing.