|
MISCELLANEOUS NOTES
5.1 ROUNDING NUMBERS IN BASIC-86 The following is a short program to illustrate one technique for rounding numbers to any number of decimal places, (within the limits of the machine). 10 DEFINT N
20 DEFDBL X
30 INPUT "ENTER NUMBER TO BE ROUNDED";X
40 IF X<1 OR X>7 GOTO 110
50 INPUT "ENTER NUMBER OF DECIMAL PLACES";N
60 A$=STR$(X+.5*10^-N*SGN(X))
70 N0=INSTR(A$,".")
80 X1=VAL(LEFT$(A$,N+N0))
90 PRINT "X=;X,"X1=";X1
100 GOTO 30
110 PRINT "END"
120 END
Rounding to zero decimal places can of course be achieved by using the INT function. Rounding numbers to be output to the screen, printer or file can be achieved by the use of PRINT USING. The routine given above can easily be simplified if it is always required that numbers be rounded to a fixed number of decimal places (eg. 2). 5.2 Undocumented Commands and Functions of the BASIC86 Interpreter5.2.1 DATE$ The DATE$ function returns a ten character string variable that has the following format: MM-DD-YYYY
where:
MM = month (1 - 12)
DD = day (1 - 31)
YYYY = year (1980 - 2099)
The delimiter is either - or /.
The date can be set through BASIC86, when doing so, the leading zeros are presumed for single months and days. The year can be entered as a 2 digit number. Examples:
PRINT DATE$
DATE$="10-6-83"
DATE$="10/06/83"
DATE$="10-06-83"
DATE$=VAR$
5.2.2 TIME$
The TIME$ function returns an eight character string variable, 2 of which are delimiters. It takes the following format: HH:MM:SS
where:
HH = hour of day (0-23)
MM = minutes (0-59)
SS = seconds (0-59)
delimiter is :
The Time can be altered within BASIC86, when doing so minutes and seconds are optional and so are leading zeros. The time is being constantly incremented by a hardware clock. Examples:
PRINT TIME$
TIME$="15:10:40"
TIME$="7:5"
TIME$="8"
NOW$="14:15:06"
TIME$=NOW$
5.2.3 DATE
The DATE variable contains the numbers of days since the beginning of the year. (Does not work on compiler) Example: PRINT DATE5.2.4 TIME The TIME variable contains the number of seconds since midnight (00:00:00). (Does not work on compiler) Examples:
PRINT TIME
The following is a self-timing program:
10 X=TIME
20 FOR I=1 TO 10000
30 NEXT I
40 PRINT TIME-X
5.2.5 BLOAD
Format:
BLOAD <filespec>[,<offset>]
Purpose: Loads a memory image into memory. <filespec> is a string expression returning a valid file specification as described in "Input and Output," except for the extension. If the device name is omitted, the current diskette drive is assumed. The only valid extensions are: (none) (no extension)
.B for Basic programs in the internal format
(created with the SAVE command).
.P for protected Basic programs in the internal
format (created with SAVE ,P command).
.A for Basic programs in ASCII format (created
with SAVE ,A command).
.M for memory image files (created with BSAVE
command).
.D for data files (created by OPEN followed by
output statements.
<offset> is a numeric expression in the range 0 to 65535. This is the address at which the loading is to start, specified as an offset into the segment declared by the last DEF SEG statement. If the <offset> is omitted, the <offset> specified in the last BSAVE is assumed. WARNING: BLOAD does not perform address range checking. That is, it is possible to BLOAD anywhere in memory! You should be absolutely sure you are not overwriting the operating system, Basic, or your own program. EXAMPLE 10 'LOAD AN ASSEMBLY PROGRAM INTO BASIC DS ASSUMING 20 'NO PROGRAM HAS BEEN LOADED. 30 DEF SEG 'SET THE DATA SEGMENT TO BASIC'S 40 BLOAD "MOVE",0 'LOAD THE CALLABLE PROGRAM.5.2.6 BSAVE Format BSAVE <filespec>,<offset>,<length> Purpose: Allows you to save portions of the computer's memory on the specified device. <filespec> is a string expression returning a valid file specification as described in BLOAD. <offset> is a numeric expression in the range 0 to 65535. This is the address at which the saving is to start, specified as an offset into the segment declared by the last DEF SEG statement. <length> is a valid numeric expression returning an unsigned integer in the range 1 to 65535. This is the length of the memory image to be saved. Example: 10 'save the first 100 bytes of memory located 20 'at the start of Basic's Data Segment. 30 DEF SEG 40 BSAVE "PROGRAM.M",0,1005.2.7 OPEN In addition to the syntax described in the MS-BASIC manual, MS- BASIC supports the more powerful GW-BASIC syntax described in the Graphics Toolkit. Format
OPEN [
Purpose: The OPEN statement establishes addressability between a physical device and an I/O buffer in the data pool. Remarks <ev> is optionally part of the file name string and conforms to the description in section 3.12. <filename> is a valid string literal or variable optionally containing a <dev>. If <dev> is omitted, disc A: is assumed. Disc file names follow the normal MS-DOS naming conventions. <mode> determines the initial positioning within the file and the action to be taken if the file does not exist. The valid modes and actions taken are: INPUT Position to the beginning of an existing file.
The "File Not Found" error is given if the file
does not exist.
OUTPUT Position to the beginning of the file. If the
file does not exist, one is created.
APPEND Position to the end of the file. If the file does
not exist, one is created.
If the FOR <mode> clause is omitted, the initial position is at the beginning of the file. If the file is not found, one is created. This is the Random I/O mode. That is, records can be read or written at will at any position within the file. <file number> is an integer expression returning a number in the range 1 through 15. The number is used to associate an I/O buffer with a disc file or device. This association exists until a CLOSE <file number> or CLOSE statement is executed. <lrecl> is an integer expression in the range 2 to 32768. This value sets the record length to be used for random files. If omitted, the record length defaults to 128-byte records. When a disc file is OPENed FOR APPEND, the position is initially at the end of the file and the record number is set to the last record of the file (LOF(x)/128). PRINT, WRITE or PUT then extends the file. The program can position elsewhere in the file with a GET statement. If this is done, the mode is changed to random and the position moves to the record indicated. Once the position is moved from the end of the file, additional records can be appended to the file by executing a GET #x,LOF(x)/<lrecl>. 5.3 An Example of Calling an Assembler routine from the MS-BASIC Compiler (For an example of calling an Assembler routine from the Interpreter, see Section 10.5)The Assembler routine is coded and written to disc as a .ASM FILE using EDLIN or PMATE (fig 1). This is then assembled using MACRO-86 (fig 2). The Basic program is coded and written to disc with the BASIC interpreter (ie. 'SAVED' with the ',A' option to produce an ASCII text file), (fig 3). This is then compiled using BASCOM (fig 4). The object (.OBJ) modules produced by MACRO-86 and BASCOM are then linked using MS-LINK (fig 5). The Assembler object module must precede the Basic object module in the Link statement. The resultant Run file (.EXE) may then be run simply by typing the name given to it during the link. When writing the 'CALL' statement in BASIC the name used (lines 160, 220, and 280) must be the name that appears in the 'PUBLIC' statement in the assembler code and must also be the label used in the assembler code 'PROC' statement. See also section 10.5 and chapter 11 for further examples. b:asmex.asm
NAME EXAMPLE
CGROUP GROUP CODE
CODE SEGMENT PUBLIC 'CODE'
ASSUME CS:CGROUP,DS:CGROUP
PUBLIC PFKDI
PFKDI PROC FAR
PUSH DS ;save BASIC DS
MOV AX,CS ;set-up DS for this module
MOV DS,AX
MOV DX,OFFSET LINE
MOV AH,9
INT 21H
POP DS ;restore BASIC DS & return to
RET ;caller
LINE DB 1BH,78H,31H
DB 1BH,59H,38H,20H
DB 20H,20H,1BH,70H
DB ' F KEY 1 '
DB 1BH,71H,20H,20H,1BH,70H
DB ' F KEY 2 '
DB 1BH,71H,20H,20H,1BH,70H
DB ' F KEY 3 '
DB 1BH,71H,20H,20H,1BH,70H
DB ' F KEY 4 '
DB 1BH,71H,20H,20H,1BH,70H
DB ' F KEY 5 '
DB 1BH,71H,20H,20H,1BH,70H
DB ' F KEY 6 '
DB 1BH,71H,20H,20H,1BH,70H
DB ' F KEY 7 '
DB 1BH,71H,20H,20H,20H
DB 1BH,48H
DB 1BH,79H,31H
DB 1BH,45H
DB '$'
PFKDI ENDP
CODE ENDS
END
FIG. 1 SAMPLE ASSEMBLY MODULE
A>MACRO86 B:ASMEX; The Microsoft MACRO Assembler Version 1.00 (C)Copyright Microsoft 1981 Warning Severe Errors Errors 0 0FIG 2. INVOCATION OF MACRO-86 TO PRODUCE .OBJ FILE b:msbex.bas 100 FOR X=1 TO 10 110 PRINT "THIS IS TEST LINE A 1234567890" 120 PRINT "THIS IS TEST LINE B 1234567890" 130 PRINT "THIS IS TEST LINE C 1234567890" 140 PRINT "THIS IS TEST LINE D 1234567890" 150 PRINT "THIS IS TEST LINE E 1234567890" 160 CALL PFKDI 170 FOR D=1 TO 250 : NEXT 180 PRINT "THIS IS TEST LINE F 0987654321" 190 PRINT "THIS IS TEST LINE G 0987654321" 200 PRINT "THIS IS TEST LINE H 0987654321" 210 PRINT "THIS IS TEST LINE I 0987654321" 220 CALL PFKDI 230 FOR D=1 TO 250 : NEXT 240 PRINT "THIS IS TEST LINE J ABCDEFGHIJ" 250 PRINT "THIS IS TEST LINE K ABCDEFGHIJ" 260 PRINT "THIS IS TEST LINE L ABCDEFGHIJ" 270 PRINT "THIS IS TEST LINE M ABCDEFGHIJ" 280 CALL PFKDI 290 FOR D=1 TO 250 : NEXT 300 NEXTFIG. 3. SAMPLE BASIC MODULE A>bascom b:msbex;
Microsoft BASIC Compiler
Version 5.32
(C)Copyright Microsoft Corp 1982
24241 Bytes Available
23463 Bytes Free
0 Warning Error(s)
0 Severe Error(s)
FIG. 4. INVOCATION OF BASIC COMPILER TO PRODUCE .OBJ FILE
A>link b:asmex+b:msbex
Microsoft Object Linker V1.08
(C) Copyright 1981 by Microsoft Inc.
Run file [A:ASMEX.EXE]: b:msbatst.exe
List file [NUL.MAP]: b:msbatst.map
Libraries [.LIB]:
FIG. 5. INVOCATION OF MS-LINK TO PRODUCE .EXE FILE
5.4 Program Size Limitations The following limitations apply to program size as indicated:
CBASIC 62K
MS-BASIC INTERPRETER 62K
MS-BASIC COMPILER 64K code
64K data
MS PASCAL 64K object code
64K default data segment
32767 lines of source code
MS FORTRAN 64K object code
64K each named common block
64K all local variables
32767 lines of source code
In FORTRAN and Pascal you can compile any number of compilands separately and link them together later; the real limit on program size is thus determined by the capability of the linker (MS-LINK) which is approximately 386K. In CBASIC and both MS-BASIC's, multiple programs may be linked together using the CHAIN command. 5.4.1 Memory Usage outside the default 64K segment in MSBASICThe following routine is an example of the use of extra memory. The DEF SEG statement defines a segment address for POKEing to. In this case, the address chosen is the start of the second memory board. 10 DEF SEG=&H2000 20 FOR I%=0 TO 20000 30 POKE I%,65 40 NEXT I% 50 FOR I%=0 TO 20000 60 J%=PEEK(I%) 70 A$=CHR$(J%) 80 PRINT "BYTE NUMBER ";I%;" - VALUE =";A$ 90 NEXT I% 100 END5.4.2 Memory Usage outside of the default 64K segment in MS-Pascal A technique to access more than 64K of data space in MS-Pascal is to use the ADS facility of the language implementation. Due to the storage mechanism of the language it is impossible to change segment under program control as in BASIC or to use named common blocks as in FORTRAN. ADS gives a method of creating, manipulating and dereferencing actual machine addresses. Examples of ADS are given in the Pascal Reference Manual, (Section 8, in V3.04 "Reference Types") and a more complete program listing using ADS and ADR is given on the following page. NOTE. Great care must be taken with the use of this facility as you do deal with actual memory locations and, as no memory map is available for use at run-time the decision on where to store variables etc.... requires a great deal of thought. TYPE B:MEM64S
{
PROGRAM TO TEST THE ALLOCATION OF STORAGE AREAS OUTSIDE OF THE
DEFAULT 64K SEGMENT OF MEMORY.
DETAILS OF THE FUNCTIONS USED ARE FOUND IN SECTION 6 OF THE
SIRIUS MS-PASCAL MANUAL.
}
PROGRAM MEM64(INPUT,OUTPUT);
VAR
INT_VAR : INTEGER;
REAL_VAR : REAL;
A_INT : ADR OF INTEGER; {relative machine address of
integer}
AS_REAL : ADS OF REAL; {segmented machine address of real}
BEGIN
INT_VAR :=1;
REAL_VAR :=3.1415;
A_INT : ADR INT_VAR; {A_INT=relative machine address of
INT_VAR}
AS_REAL :=ADS REAL_VAR {AS_REAL=segmented machine address
of REAL_VAR}
WRITELN (A_INT^,AS_REAL^); {write values pointed at by A_INT
and AS_REAL}
AS_REAL.S := 16#0006; {change AS_REAL segment pointer to
0006 HEX}
AS_REAL^ :=REAL_VAR; {load address pointed at by AS-REAL
with REAL_VAR}
REAL_VAR := 9.81;
WRITELN (REAL_VAR,AS_REAL^); {write REAL_VAR and the value
pointed at by AS_REAL}
AS_REAL.S := 16#0007; {change AS_REAL segment pointer to
0007 HEX}
AS_REAL^ := REAL_VAR; {load address pointed at by AS_REAL
with REAL_VAR}
REAL_VAR := 1.0;
WRITELN (REAL_VAR,AS_REAL^); {write REAL_VAR and the value
pointed at by AS_REAL}
AS_REAL.S := 16#0008; {etc......... }
AS_REAL^ := REAL_VAR;
REAL_VAR := 0.15;
WRITELN (REAL_VAR,AS_REAL^)
END.
{ THIS PROGRAMME IS BASED ON THE EXAMPLE GIVEN ON PAGE 6.38 OF THE
PASCAL REFERENCE MANUAL. }
B:MEM64
1 3.1415000E+00
9.8099990E+00 3.1415000E+00
1.0000000E+00 9.8099990E+00
1.5000000E+01 1.0000000E+00
A>
5.4.3 Memory usage outside of the default 64K segment in MS-FORTRAN
A technique to access more than 64K of data space in MS-FORTRAN is shown below. Named COMMON blocks, each of which may be up to 64K bytes in size can be used. In the example, three COMMON blocks are used, each with 10,000 elements of four bytes each, thus allowing access to 120,000 bytes of data storage. $STORAGE:2
PROGRAM BIGMEM
COMMON /COM1/ARRAY1(10000)
COMMON /COM2/ARRAY2(10000)
COMMON /COM3/ARRAY3(10000)
DO 10 I=1,10000
ARRAY1(I)=I
ARRAY2(I)=I+10000
ARRAY3(I)=I+20000
10 CONTINUE
OPEN(1,FILE='LST')
DO 20 I=1,10000,1000
WRITE(1,100)'ARRAY1(I)=',ARRAY1(I),'ARRAY2(I)=',ARRAY2(I),
1'ARRAY3(I)=',ARRAY3(I)
20 CONTINUE
100 FORMAT(1X,A11,F7.0,A11,F7.0,A11,F7.0)
END
5.5 Fix for ASYNC so it will load default file ASYN.IEM when
running under MS-DOS.
Using DDT: .CW10 -rasync.mnu START END 02C8:0000 02C8:51FF -d5100 02C8:5100 3B 53 0B 49 1E 49 45 54 52 53 44 3F 1B 6E 49 6E ;S.I.IETRSD?.nIn 02C8:5110 49 6E 49 6E 49 6E 49 AC 49 A9 49 7F 03 05 08 0A InInInI.I.I..... 02C8:5120 0D 12 15 18 1B 17 55 24 55 CA 54 17 55 CA 54 CA ......U$U.T.U.T. 02C8:5130 54 D2 54 01 55 01 55 F8 54 00 49 45 2F 4D 4F 44 T.T.U.U.T.IE/MOD * 02C8:5140 45 4D 49 45 4D 00 00 00 00 13 14 15 16 00 02 1F EMIEM........... 02C8:5150 01 7E 4E FA 8E 03 1F 05 9A 00 00 00 00 32 30 54 .~N..........20T 02C8:5160 31 32 33 34 35 36 37 33 30 30 00 31 32 33 34 35 1234567300.12345 02C8:5170 36 37 38 31 32 33 01 24 0D 23 01 D3 4E BF 91 0E 678123.$.#..N... 02C8:5180 23 01 D3 4E 0A 92 04 49 01 D3 4E 93 8F 05 49 01 #..N...I..N...I. 02C8:5190 D3 4E DE 8F 06 49 01 D3 4E 29 90 07 49 01 D3 4E .N...I..N)..I..N 02C8:51A0 74 90 08 49 01 D3 4E BF 90 0C 49 01 D3 4E 9A 91 t..I..N...I..N.. 02C8:51B0 0D 49 01 D3 4E E5 91 OE 49 01 D3 4E 30 92 41 44 .I..N...I..N0.AD -s513a 02C8:513A 49 41 02C8:513B 45 53 02C8:513C 2F 59 02C8:513D 4D 4e 02C8:513E 4F 43 02C8:513F 44 20 02C8:5140 45 20 02C8:5141 4D 20 02C8:5142 49 ^Z E>d5100 02C8:5100 3B 53 0B 49 1E 49 45 54 52 53 44 3F 1B 6E 49 6E ;S.I.IETRSD?.nIn 02C8:5110 49 6E 49 6E 49 6E 49 AC 49 A9 49 7F 03 05 08 0A InInInI.I.I..... 02C8:5120 0D 12 15 18 1B 17 55 24 55 CA 54 17 55 CA 54 CA ......U$U.T.U.T. 02C8:5130 54 D2 54 91 55 91 55 F8 54 00 41 53 59 4E 43 20 T.T.U.U.T.ASYNC ** 02C8:5140 20 20 49 45 4D 00 00 00 00 13 14 15 16 00 02 1F IEM........... 02C8:5150 01 7E 4E FA 8E 03 1F 05 9A 00 00 00 00 32 30 54 .~N..........20T 02C8:5160 31 32 33 34 35 56 57 33 30 30 00 31 32 33 34 35 1234567300.12345 02C8:5170 36 37 38 31 32 33 01 24 0D 23 01 D3 4E BF 91 0E 678123.$.#..N... 02C8:5180 23 01 D3 4E 0A 92 04 49 01 D3 4F 93 8F 05 49 01 #..N...I..N...I. 02C8:5190 D3 4E DE 8F 06 49 01 D3 4E 29 90 07 49 01 D3 4E .N...I..N)..I..N 02C8:51A0 74 90 08 49 01 D3 4E BF 90 0C 49 01 D3 4E 9A 91 t..I..N...I..N.. 02C8:51B0 0D 49 01 D3 4E E5 91 0E 49 01 D3 4E 30 92 41 44 .I..N...I..N0.AD ? -wasync.mnu -^C * No "/" allowed under MS-DOS ** Fixed5.6 Creating ASCII Text Files Under MS-DOS it is possible to create an ASCII text file (such as a batch file) directly from the keyboard. From the A> prompt type: COPY CON A:FILENAME.EXT This will allow you to type onto the screen, the text you wish to create. After each line hit the RETURN key. You can edit the current line you are typing by back spacing over any errors. When finished do a control-Z [^Z] then press RETURN. This will then close the disk file. For CP/M-86 you will need PIP: PIP A:FILENAME.EXT=CON:" PIP will then allow you to create a file as above but with the exception that after each line is entered and the RETURN key hit you must also do a control-J [^J] to force a line feed. When finished do a control-Z [^Z] to close the file. 5.7 CODEC PROGRAMMINGThis describes what needs to be done in order to generate sound using the codec audio section of the Sirius 1. Refer to technical reference manual for technical explanation of the CODEC. Software has control over the following functions:
Volume is controlled by the duty cycle of the ultra-audio chopper. The chop rate is generated by a 6522 VIA. This clock can be set once and left. The clock rate should be set at a rate above 20khz in order not to be heard as a tone in the audio output. The system normally sets this clock to the maximum rate the 6522 will generate. Volume clock rate setup example:
INIT_VOLUME_CLOCK: proc;
port$ptr= via_20;
/* set shift register mode in acr to shift out on t2 */
via(acr)= (via(acr) and not(1ch)) or 10h;
/* set t2 to fastest clock rate */
via(t2)= 1;
/* init volume level to off value, 0= max,ff= off */
/* 00,01,03,07,0f,3f,7f,ff are valid volume values */
via(sr)= 0ffh;
end INIT_VOLUME-CLOCK;
Volume level set example:
SET_VOLUME: proc(level);
dcl level byte;
port$ptr= via_20;
/* move new level into sr to control duty cycle */
via(sr)= level;
end SET_VOLUME
5.7.2 CODEC Clock
The codec clock rate determines the quality of the recorded message. The higher the clock rate the higher the quality. This clock should be adjusted to fit the need of the application as far as quality and data space require. Typical clock rate is 16khz for good speech, and 32khz for very good speech quality. The data rate at 16khz is 2k bytes/second and at 32khz it is 4k bytes/second. The codec clock is generated by a 6522 via using timer 1. The value stored in the 6522 timer is one half the period of the codec clock. N= ( 500,000/(F*8) )-1 or N= (62500/F)-1
N is the 6522 timer value
F is the desired clock frequency in Hz
Codec clock setup example:
/* freq is the desired clock rate in hz */
SET_CODEC_CLOCK: proc(freq);
dcl freq word;
port$ptr= via_80;
/* set new timer value for freq */
via(tl)= (62500/freq)-1;
end SET_CODEC_CLOCK;
5.7.3 Codec Mode Control
The codec can both encode speech input to digital data, and decode stored digital data back to speech output. The mode control for the codec is supplied by using the SM/DTR output of the SDA chip. Example of codec mode control: /* set mode of code to play or record */
/* 0 is play 1 is record */
SET_CODEC_MODE: proc(mode);
dcl mode byte;
if mode=0 then
do;
sda.r0=0; /* select control reg 2 */
sda.r1=5bh; /* this sets SM/DTR low */
end;
else
do;
sda.r0=0; /* select control reg 2 */
sda.r1=58h; /* this sets SM/DTR high */
end;
end SET_CODEC_MODE;
5.7.4 SDA Initialisation
The SDA performs the parallel to serial conversion and data buffering function for the CPU. This helps cut down the amount of time needed to service the CODEC data feeding and reading. The SDA must be initialised before any other codec operation is performed. The functions that are setup are:
SDA initialisation example: SDA_INIT: proc;
/* set word length to 8,play mode,2 byte ready */
sda.r0=0; /* select control reg 2 */
sda.r1=5bh;
/* set sync code to 0aah for quite pattern on underflow */
sda.r0=80h; /* select sync code */
sda.r1=0aah;
/* set external sync mode for par to ser operation */
sda.r0=40h; /* select control reg 3 */
sda.r1=0dh; /* clear TUF and CTS */
sda.r0=40h;
sda.r1=01h; /* enable TUF and CTS*/
end SDA_INIT;
5.7.5 SDA Data Transfer
The SDA is the interface the CPU uses to generate sound from the codec. This example is for educational purposes and is NOT the only method that can be used to drive the codec. In order to record speech from the codec the CPU must:
Example of recording data from codec: /* record a buffer of codec data at buf$ptr */
/* record count bytes of data */
RECORD: proc(buf$ptr,count);
dcl buf$ptr pointer;
dcl count word;
dcl buffer(1) based buf$ptr;
dcl i word;
call SET_VOLUME(0ffh); /* set volume off */
call SET_MODE(1); /* set to record mode */
i=0;
do while (count [ | 0); /* read in count bytes of data */
/* wait for receive byte ready in r0 */
do while (sda.r0 and 1) [|1; end;
buffer(i)=dsa.r1; /* read and store data byte */
i=i+1;
end;
call SET_MODE(0);
end RECORD;
Play back of codec data example:
/* play a buffer of codec data back */
/* buffer pointed at by buf$ptr */
/* play count bytes */
PLAY; proc(buf$ptr,count);
dcl buf$ptr pointer;
dcl count word;
dcl i word;
call SET_MODE(0); /* set play mode */
do i=0 to count;
/* wait for ready to send flag */
do while (sda.r0 and 2)=0; end;
sda.rl= buffer(i); /* store next byte */
end;
end PLAY;
5.8 Data Security
This sample program appends characters to a file. It closes the file and then re-opens it after writing every character to ensure that at most one character is lost if the system crashes. name test
code segment public 'code'
assume cs:code, ds:code
; NOTE: This program assumes that an ASCII file named TEST is
; located on the default drive. TEST is the file that the data
; is appended to.
lf equ 0ah
cr equ 0dh
altz equ 1ah
dir_con_io equ 06h
print equ 09h
open equ 0fh
close equ 10h
write equ 15h
setdma equ 1ah
test :
push es ;save ptr to base page
mov ax,code ;set up DS
mov ds,ax
lea dx, buffer ;set up dma
mov ah, setdma
int 21h
open_it:
lea dx, fcb
mov ah, open ;open file
int 21h
inc al
jz file_not_found
mov fcb_recsize, 1 ;set record size to 1 byte
; set the current block and current record to point at the last
; byte of the file since we want to append it.
mov ax, fcb_filesize
xor dx, dx
mov cx, 128
div cx
mov fcb_cur_block, ax
mov fcb_cur_rec, dl
-- listing continued on next page --
; get a character from the keyboard
get_char_from_kb:
mov ah, dir_con_io
mov dl, 0ffh
int 21h
jz get_char_from_kb
; if the character is ALT-Z, then stop
cmp al, altz
jz end_prog
; write the character to the file
mov buffer, al
mov ah, write
lea dx, fcb
int 21h
; if the character was a carriage return, then write a line feed
; also
cmp byte ptr buffer, cr
jnz close_it
mov byte ptr buffer, lf
mov ah, write
lea dx, fcb
int 21h
; close the file to save what we just wrote in case the system
; crashes
close_it:
mov ah, close
lea dx, fcb
int 21h
; go to open the file and get the next character
jmp open_it
file_not_found:
lea dx, not_found_msg
mov ah, print
int 21h
end_prog:
return proc far
; do a far return to the first byte of the basepage, which
; contains an int 20 operation to terminate the program
-- listing continued on next page --
xor ax, ax
push ax
ret
return endp
fcb db 0
fcb_name db 'TEST '
fcb_cur_block dw ?
fcb_recsize dw ?
fcb_filesize dw ?
dw ?
fcb_date dw ?
fcb_time dw ?
fcb_reserved db 8 dup (?)
fcb_cur_rec db ?
fcb_rel_rec db 4 dup (?)
buffer db 0
not_found_msg db 13,10,'The sample file TEST was not
found.',13,10,'$'
code ends
end
5.9 MS-Pascal Date and Time Program (input, output)
This program demonstrates the use of the MS-Pascal Date and Time procedures, as well as showing how to change the date by using the MS-DOS 1.25 Set Date function with the DOSXQQ function call. PROGRAM Date_Time (INPUT,OUTPUT);
PROCEDURE DATE(VAR s: STRING ); EXTERNAL;
PROCEDURE TIME(VAR s: STRING );EXTERNAL;
FUNCTION DOSXQQ( command,parameter: WORD): BYTE;EXTERNAL;
VAR date_str,time_str: LSTRING(8);
FUNCTION Set_Date(CONST date_str: STRING):BOOLEAN;
(* Changes the system date if date_str is valid, otherwise
returns FALSE. *)
CONST setdate = QN2B;
VAR month_word,day_word,year_word,param: WORD;
date_lstr: LSTRING(2);
date_status,month_byte,day_byte: BYTE;
BEGIN
Set_date: = FALSE;
date_lstr.LEN: = 2;
FOR VAR l:= 1 TO 2 DO date_lstr[l]: = date_str[l];
IF NOT DECODE(date_lstr,month_word) THEN RETURN;
FOR VAR l: = 4 TO 5 DO date_lstr[1-3]: = date_str[l];
IF NOT DECODE(date_lstr,day_word) THEN RETURN;
month_byte:= LOBYTE(month_word);
day_byte:= LOBYTE(day_word);
param:= BYWORD(month_byte,day_byte);
FOR VAR l:= 7 TO 8 DO date_lstr[1-6]:= date_str[l];
IF NOT DECODE(date_lstr,year_word) THEN RETURN;
year_word:= year_word + 1900;
CRCXQQ:= year_word;
date_status:= DOSXQQ(setdate,param);
IF date_status <> QNFF THEN
Set_Date:= TRUE;
END;
BEGIN
time_str.LEN:= 8;
TIME(time_str);
WRITELN('The current system time is ',time_str);
date_str.LEN:= 8;
DATE(date_str);
WRITELN('The current system date is ',date_str);
WRITE('Enter a new date (mm-dd-yy) to change the date, or
else
5.10 Accessing System Time in dBASE II
ENTRY:BX - Pointer to length byte at start of string
- 11 byte (space) string passed from dBASE
EXIT: string is passed back to dBASE with time
CHANGE: All registers destroyed, but dBASE will return machine's
state when it regains control.
This program takes an 11 byte long string from dBASE and puts the MS-DOS time into it. The string must be of character type. If the string is not 11 bytes long, the routine is exited with no change. By typing DTIME at the system prompt before entering dBASE, the first part of the program loads the second half at address 65024 decimal in the current program segment. (Actually, any location above A400H is okay. Further, the dBASE command load [filename] could load an assembly language routine within dBase). This address is then used inside dBASE as the argument for the SET CALL TO command. Because the 1/100th seconds clock in MS-DOS returns either 00 or 50 it was felt to be of limited use and was not included in this program. A 12 hour clock with an AM or PM tag at the end was employed for ease of use. If a 24 hour clock is desired the conversion code can easily be eliminated. A SORT routine might overwrite the time code if it is large enough. If this is a problem, the code can be modified to use INT 27H to create a protected area in MS-DOS. A common sequence of commands to get the time would be: A>DTIME
A>DBASE
Copyright (C) 1982 RSP Inc.
*** dBASE II/86 Ver 2.4 1 July 1983
.STORE"12345678901" TO TIME
12345678901
.SET CALL TO 65024
.CALL TIME
? TIME
5:23:00 PM
STOUT GROUP CODE
ASSUME CS:STOUT,DS:STOUT ;"STring OUT"
This first part loads GETTIME
CODE SEGMENTPUBLIC 'CODE'
ORG 100H ;load over PSP
MOV CX,0A6H ;prepare to move A6H bytes
LEA SI,GETTIME ;put start of time code in SI
MOV DI,0FE00H ;set destination above dBASE
CLD
REP MOVSB ;move it
INT 20H ;terminate
This is the actual time code
GETTIME PROC NEAR
NOP ; entry target
MOV DI,BX ;put address of length byte in DI
XOR BX,BX ;clear it
MOV BL,0BH ;put expected length in BL
CMP [DI],BL ;is it 11 bytes long?
JNZ SHORT DONE ;no, exit with no change
INC DI ;move DI to start of string
MOV AH,2CH ;get time in CX and DX request
INT 21H ;get it
MOV AL,CH ;put hours in AL
CMP AL,0CH ;after 12:00 noon?
JGE AMPM_FLAG ;keep under 12, flag as PM
CMP AL,00 ;is it zero o'clock?
JZ SHORT MIDNIGHT ;make it midnight
CONHOURS: CALL CONVERT ;convert to ASCII
MOV BH,0FFH ;flag to OUT that this is hours
CALL OUT ;put hours in string
MOV AL,C ;put minutes in AL
CALL CONVERT
CALL OUT
MOV AL,DH ;put seconds in AL
CALL CONVERT
MOV BH,0AAH ;flag for OUT
CALL OUT
CMP BL,0FFH ;is it night?
JZ SHORT POUT
MOV [DI],BYTE PTR 'A' ;give me an A
MOUT: INC DI
MOV [DI],BYTE PTR 'M' ;give me an M
JMP SHORT DONE
POUT: MOV [DI],BYTE PTR 'P' ;give me a P
JMP SHORT MOUT
DONE: RET ;all finished
CONVERT: XOR BH,BH ;clear counter
PUSH BX ;save AM/PM flag
CONVERT2: AAM ;unpack AL
ADD AL,30H ;bump to ASCII
ADD BH,01 ;loop count
CMP AH,0 ;quotient zero?
JZ SHORT CVRTDONE ;then we're through
MOV BL,AL ;save LSD
MOV AL,AH ;for next unpack
JMP SHORT CONVERT2 ;do it again
ONEDIGIT: MOV AH,30H ;MSD is zero
POP BX
RET
CVRTDONE: CMP BH,01 ;one digit number?
JZ SHORT ONEDIGIT ;put '0' in AH
MOV AH,AL ;put MSD in AL for OUT
MOV AL,BL ;put LSD in AL for OUT
POP BX
RET
AMPM_FLAG: MOV BL,0FFH ;flag as PM
CMP AL,0CH ;is it after 12 noon?
JG SHORT CHOP ;then keep hours under 12
JMP SHORT CONHOURS
CHOP: SUB AL,0CH
JMP SHORT CONHOURS
MIDNIGHT: MOV AL,0CH
JMP SHORT CONHOURS
OUT: CMP BH,0FFH ;is it hours?
JZ SHORT ZEROKILL ;might kill first zero
OUT2: MOV [DI],AH ;move out first digit
INC DI ;point to next string position
MOV [DI],AL ;move out second digit
INC DI ;point to next string position
CMP BH,0AAH ;is it end of time numbers?
JZ SHORT BLANKOUT ;send a space
MOV [DI],BYTE PTR ':' ;send out colon
INC DI ;advance to next position
OUT3: RET
ZEROKILL: XOR BH,BH ;clear flag that got us here
CMP AH,'0'
JZ SHORT ZEROFF
JMP SHORT OUT2
ZEROFF: MOV AH,' '
JMP SHORT OUT2
BLANKOUT: XOR BH,BH ;clear flag that got us here
MOV [DI],BYTE PTR ' ' ;send space
INC DI
JMP SHORT OUT3
GETTIME ENDP
CODE ENDS
END
5.11 Programming the 8253 Timer
The 8253 Timer, counter 2 is used for timer interrupt. Clock rate from Sirius hardware is 100 kHz. For example, to obtain 100 microsecond interrupts we need to divide by 10. The 8253 can be used in a BCD or binary mode. In assembler: org 100h
start:
mov bx,0e000h ; ES points to I/O
mov es,bx
mov bx,23h ; address mode register
mov al,0b5h ; counter 2, mode 2, BCD
mov es:[bx],al ; write mode word
mov bx,22h ; address counter 2
mov al,10h ; least significant byte (LSB)
mov es:[bx],al
mov al,0 ; most significant byte (MSB)
mov es:[bx],al
The result is a 10 microsecond pulse every 100 microseconds.
Maximum time = 620 milliseconds (ms) approx. (MSB=0, LSB=0)
Minimum time = 20 microseconds (us) approx. (MSB=0, LSB=2)
(Binary mode)
10^4 = 100 ms (0,0)
10^3 = 10 ms (10h,0)
10^2 = 1 ms (1,0)
10^1 = 100 us (0,10h)
5.12 Manipulating a Batch File
100 '---------------------------------------------------------------------- 110 '--- START.BAS by Keith Pickup --- 120 '--- Barson Computers (Sydney - Australia) --- 130 '--- --- 140 '--- This program manipulates a batch file so that programs --- 150 '--- may be executed by selecting them from a master menu. --- 160 '--- Parameters may be passed to the command string by tagging --- 170 '--- them to the program name string as in lines 710 & 720 --- 180 '--- The program could also be compiled which would help --- 190 '--- speed it up. --- 200 '--- --- 210 '--- This program requires an AUTOEXEC.BAT file to be created --- 220 '--- which contains the command 'MENU'. --- 230 '--- MENU is in fact MENU.BAT which contains the following --- 240 '--- --- 250 '--- MSBASIC START (or just START if compiled) --- 260 '--- OPTION (which is a dummy command) --- 270 '--- PAUSE **** Program Terminated **** --- 280 '--- MENU (which calls the original .BAT file --- 290 '--- --- 300 '--- The PAUSE allows programs like CHKDSK to display their --- 310 '--- information and wait for a response from the keyboard --- 320 '--- before re-loading the master menu program --- 330 '--- --- 340 '--- Lastly there is a file called FINISH.BAT which contains --- 350 '--- no commands at all therefore allowing exit to the system --- 360 '--- --- 370 '--- NOTE: The command 'dir/w|sort|more' relates to DOS 2.0 --- 380 '--- --- 390 '---------------------------------------------------------------------- 400 ' 410 ' *** define program variables *** 420 ' 430 WIDTH 255:HEADING$=" **** MASTER MENU **** " 440 ESC$=CHR$(27):REV$=ESC$+"p":ROFF$=ESC$+"q":CLR$=ESC$+"z":HOME$=ESC$+"H" 450 DIM SELECT$(10),PROG$(7),TEMP$(4),FK$(7):TOTAL.OPTIONS=7 460 FOR K%=1 TO TOTAL.OPTIONS:READ SELECT$(K%):NEXT K% 470 DATA "Sorted Directory Listing","Check disk space","Format new disk" 480 DATA "Copy diskettes","Edit ASCII file","Microsoft Basic" 490 DATA "Return to Operating System" 500 PAUSE$="pause **** Program Terminated ****" 510 PROG$(1)="dir/w|sort|more":PROG$(2)="chkdsk":PROG$(3)="format/e" 520 PROG$(4)="dcopy/e":PROG$(5)="edlin":PROG$(6)="msbasic":PROG$(7)="finish" 530 ' 540 ' *** read current contents of the MENU.BAT file *** 550 ' 560 OPEN "I",#1,"MENU.BAT" 570 FOR K%=1 TO 4 580 INPUT #1,TEMP$(K%) 590 NEXT K%:CLOSE 1 600 ' 610 ' *** display menu for selection of option *** 620 ' 630 PRINT CLR$;:KEYBASE=1:GOSUB 820 640 PRINT HOME$;TAB(40-(LEN(HEADING$)/2)+.5) REV$;HEADING$;ROFF$:PRINT:PRINT 650 FOR K%=1 TO TOTAL.OPTIONS 660 PRINT TAB(25);REV$;K%;ROFF$;" ";SELECT$(K%):PRINT 670 NEXT K% 680 PRINT:PRINT TAB(25) "Please select option required "; 690 IP$="":IP$=INKEY$:IF IP$="" THEN 690 700 IP=VAL(IP$):IF IP < 1 OR IP > TOTAL.OPTIONS THEN 690 710 IF IP=5 THEN PRINT:PRINT TAB(25);:INPUT "Edit file name ";FILE.NAME$ 720 IF IP=5 THEN PROG$(5)=PROG$(5)+" "+FILE.NAME$ 730 TEMP$(2)=PROG$(IP):TEMP$(3)=PAUSE$ 735 FOR I%=1 TO 7:PRINT ESC$+"41"+CHR$(I%)+CHR$(&HF0+I%):NEXT I% 740 ' 750 ' *** write out new batch file replacing 'option' with program name *** 760 ' 770 OPEN "O",#1,"MENU.BAT" 780 FOR K%=1 TO 4 790 PRINT #1,TEMP$(K%) 800 NEXT K%:CLOSE 1 810 PRINT CLR$:SYSTEM 820 ' 830 ' *** set up for the 25th line *** 840 ' 850 IF KEYBASE=1 THEN RESTORE 1010 860 IF KEYBASE=2 THEN RESTORE 1020 870 IF KEYBASE=3 THEN RESTORE 1030 880 FOR I%=1 TO 7:PRINT ESC$+"41"+CHR$(I%)+CHR$(&H30+I%):NEXT I% 890 READ FKCT 900 FOR I%=1 TO FKCT:READ FK$(I%):NEXT I% 910 GOSUB 920:RETURN 920 FKSZ=INT((80-(FKCT-1))/FKCT) 930 X9$="":C9$=ESC$+"q"+" "+ESC$+"p" 940 FOR I%=1 TO FKCT 950 B9$=LEFT$(FK$(I%),FKSZ):J9%=INT((FKSZ-LEN(B9$)+1)/2) 960 X9$=X9$+C9$+LEFT$(SPACE$(J9%)+B9$+SPACE$(FKSZ),FKSZ) 970 NEXT I% 980 X9$=ESC$+"p"+X9$+ESC$+"q" 990 PRINT ESC$"x1";ESC$"j";ESC$"Y8 ";ESC$"l";X9$;ESC$"Y ";ESC$"k"; 1000 RETURN 1010 DATA 7,"SORT DIR","CHK DISK","FORMAT","DCOPY","EDIT","MSBASIC","EXIT" 1020 DATA 7," "," "," "," "," "," "," " 1030 DATA 7," "," "," "," "," "," "," "5.13 CALC (or UDCCALC) - Calculator Function CALC, the calculator function (version 1.1 or later) on both MS- DOS and CP/M-86 work as follows: Call up the calculator function by typing: CALC and striking SHIFT with CALC key. Division - no quirks eg. 9:-6 (CALC KEY) Multiplication - one quirk - Your X key on the keyboard may not be configured so use the * key instead. (ie. SHIFT and 8 key). eg. 9 X 6 (CALC KEY) or 9 * 6 (CALC KEY) Addition and Subtraction - many quirks - Do not use the (CALC KEY) for the equal sign as it does not work. Only use it to clear the accumulator. eg. 9 + 6 = would be 9 + 6 + 9 - 6 = would be 9 - 6 - 5.14 Directory EntriesThe maximum number of directory entries in each version of the operating system is as follows:
CP/M 1.0 128
CP/M 1.1 128
MS-DOS 1.25/2.5 or earlier (floppy discs) 128
MS-DOS 1.25/2.5 (hard discs) no
practical
upper
limit
Notes
The directory of a CP/M-86 disc contains an entry for each extent of each file. Therefore a file with more than one extent will have a multiple directory entry for each file displayed. Floppy disc The CP/M-86 operating system blocks individual records into multiples of 128 bytes. eg. An 80 character record will always occupy 128 bytes of disc space. MS-DOS on the other hand, does not do this. It does however, group records together into blocks or allocation units of 2K bytes (2048 bytes). These are the smallest units that can be written to or read from disc at any one time. Therefore a file will always occupy multiples of 2K bytes. example A file with fixed length records of 80 characters, containing 150 records. Data file = 80 * 150 bytes
= 12000 bytes
The disc space will then be allocated as follows: Number of 2K byte blocks = size of data file divided by 2048
= 12000 divided by 2048
= 5.859
= 6 (rounding upwards to the nearest
whole block)
Total disc space = 6 * 2K blocks
= 6 * 2048 bytes
= 12228 bytes
The DIR command will give the file size as 12000 bytes however, the actual amount of disc space allocated for the file is 12228 bytes. The CHKDSK command will give the sum of the actual disc space allocated for the files. FILES DIRECTORY SIZE DISC SPACE
------------------------------------------------------------
COMMAND.COM 5737 6144
SETIO.COM 1012 2048
CHKDSK.COM 1976 2048
DCOPY.COM 15776 16384
FORMAT.COM 17132 18432
RDCPM.COM 11214 12288
MSBASIC.COM 31360 32768
UDCCALC.COM 4917 6144
EDLIN.COM 2432 4096
DISKID 1536 2048
----- ------
93092 102400
----- ------
CHKDSK gives the value of 102400 bytes. Hard Disc The only difference with the Internal Winchester Sirius and the floppy disc drive Sirius is the size of the allocation units. On the floppy disc drive the allocation unit size is fixed at 2K. On the hard disc the user can specify different allocation units for each volume. Therefore files on disc can be multiples of 2K, 4K, 8K etc. |