home *** CD-ROM | disk | FTP | other *** search
- BASIC And Machine Code Interfacing
-
- Mark Bridger
- The Boston Computer Society
- IBM PC Users' Group
-
- While BASIC has many deficiencies as
- a programming language, it is the
- most popular and simplest language to
- use. In fact, IBM chose to
- concentrate most of the PC's special
- effects in ROM BASIC. However, if one
- wants the features of BASIC, plus
- speed, control or extra effects not
- provided by IBM BASIC, the only
- alternative is to interface with
- assembly language. This raises the
- problem of how to link and call an
- assembly language routine from a
- BASIC program. Appendix C of the IBM
- BASIC Manual gives a rather sketchy
- account of this. This article will
- try to explain the BASIC to machine
- language interface procedure.
-
- Fundamentally, the problems of
- linkage are as follows:
-
- o Problem 1: BASIC can only call a
- routine which is loaded into
- memory somewhere. So - how to
- load, and where?
-
- o Answer 1: Use the BLOAD
- statement, and make sure that the
- subroutine does not overlap
- either BASIC or your program
- (more of this later).
-
- o Problem 2: You can only BLOAD
- something which has been BSAVEd.
- To BSAVE something, you must:(a)
- be in BASIC and (b) have that
- something in memory at the same
- time.
-
- o Answer 2: The only way to do this
- is by using that all-purpose
- tool, DEBUG. To illustrate the
- procedure in detail, we shall
- construct a small program which
- does something that can't be done
- from BASIC alone; namely, write a
- character in color on the
- graphics screen. The reader
- should be somewhat familiar with
- PC assembly language.
-
- The BASIC part of the package is the
- small program called "SMALL.BAS",
- listed in figure 1. The assembly
- language part is the code which
- contains the procedure
- "writechar",listed in figure 2.
- Notice that the BASIC program refers
- to the file "write.srt" as well as
- the procedure writechar; it is the
- construction of this file we will
- examine first.
-
- Figure 1:Basic program small.bas
-
- 10 CLS: KEY OFF
- 20 SCREEN 1,0: COLOR 1,1 'blue
- graphics screen
- 30 INPUT "Choose color 0,1,2,3:";HUE%
- 40 HUE% = HUE% - 4*INT(HUE%/4)
- 50 X$ = INKEY$: IF X$ = ""GOTO 50
- 60 IF ASC(X$) = 0 GOTO 50 'only ASCII
- 70 CHAR% = ASC(X$):CLS
- 80 DEF SEG = &HFCO 'reserve top of
- memory
- 90 BLOAD "write.srt",0
- 100 WRITECHAR% = 0
- 110 CALL WRITECHAR%(CHAR%,HUE%)
- 120 END
-
- Figure 2: Assembly Lang- WRITE.ASM
- stack segment para public 'stack'
- stack ends
-
- cseg segment para public 'code'
- assume cs:c ss:stack
-
- ;procedure writechar (var char,
- ;hue:byte) This procedure prints a
- ;single character, whose ASCII code
- ;is char, in the color specified by
- ;its parameter "hue". In graphics mode
- ;this is one of the four palette
- ;colors.
-
- public writechar
- writechar proc far
-
- push bp ;save bp
- mov bp,sp ;bp points to stack
- push ax ;save ax
- push bx ;save bx
- push cx ;save cx
- push si ;save si
- sti ;enable interrupts
- mov ah,9 ;prepare to write
- mov si,[bp+8] ;si gets address of cha
- mov al,[si] ;al gets value of char
- mov si,[bp+6] ;si gets address of hue
- mov bl,[si] ;bl gets value of hue
- mov cx,1 ;write only once
- mov bh,0 ;graphics mode
- int 10h ;do it!
- pop si ;restore registers
- pop cx
- pop bx
- pop ax
- pop bp
- ret 4 ;pop addresses, return
- writechar endp
- cseg ends
- end
-
- Proceed as follows:
-
- 1. Type the contents of figure2
- under the filename write.asm.
-
- 2. Run this through the Assembler to
- produce the file called
- write.obj. This is machine code
- which must be linked.
-
- As mentioned previously, we want
- to have the program and BASIC in
- memory at the same time so we can
- BSAVE it. To do this we must make
- sure that it is loaded fairly low
- in memory; we also want to make
- sure that our procedure write
- gets loaded 'high' in memory by
- DEBUG. One way to do this is to
- use the Linker with the 'H'
- option. This is done as follows:
-
- 3. Call up the Linker by typing LINK
- at the DOS prompt.
-
- 4. Answer its first question (for an
- object file) with WRITE/h and
- press Enter. Continue until the
- Linker runs out of questions. It
- will probably give you an error
- message that there is no stack
- segment. That's OK. It will
- create a file called WRITE.EXE
- which is what we want. For
- simplicity's sake, assume from
- now on that all files mentioned
- are on the same disk in drive A
- (the default).
-
- 5. Now for the debugger. At the A>,
- type DEBUG BASIC.COM and press
- ENTER. This loads BASIC into
- memory. (You can also use
- BASICA.) To see the exact memory
- locations, at the DEBUG
- prompt-hyphen, type r and press
- ENTER. You will see a display in
- hex of the contents of all the
- registers.
-
- 6. Important: Make a note of the
- contents of the segment registers
- DS,ES,CS,SS (they should all be
- the same; mine read 052A). The
- instruction pointer (IP) should
- be 0100.
-
- 7. Quit DEBUG by entering q.
-
- 8. It is now time to load the
- subroutine. Type DEBUG WRITE.EXE
- and press ENTER.
-
- 9. To look at the registers again,
- enter r and press ENTER.
-
- 10. Important: Make note of the
- contents of CS (segment
- location), IP (offset), and CX
- (length). CS should be fairly
- large (mine reads 4FFD), IP
- should be 0000, and CX should be
- 0030 for the file write.exe
- (length = 30HEX bytes = 48
- bytes).
-
- 11. Now, load BASIC exactly as it
- would have been if write.exe had
- not been loaded.
-
- 12. Make sure that DS,ES,CS,SSS and
- IP are exactly the same as when
- BASIC was loaded initially. That
- is why you made note of the
- registers. DS and ES are probably
- OK, but CS,SS, and IP must be
- changed. To change CS, for
- example, respond to the DEBUG
- hyphen with r cs and press Enter.
- DEBUG will display a colon. You
- type in the correct value and
- enter. Fix SS and IP also. Don't
- leave the debugger!
-
- 13. Reload BASIC as follows. After
- the hyphen type n basic.com and
- press Enter. This names the
- file. Then type L and press
- Enter. This loads the file. If
- all has gone well, the two files
- should be loaded into disjoint
- parts of memory whose locations
- we know from the CS and IP
- settings.
-
- 14. Now run BASIC from the debugger.
- Respond to the hyphen with
- g=(BASIC's CS):(BASIC's IP) and
- press Enter. You should get a
- "direct statement in file"
- message and BASIC's familiar OK
-
- 15. Now from BASIC we want to BSAVE
- our subroutine.
-
- o Set the default segment to
- the value of write.exe's CS
- register as follows:
-
- Type:def seg = &H(CS value).
- Then press Enter.
-
- o Think of a name for the
- subroutine. In the example,
- we used the unimaginative
- name of write.srt.
-
- o BSAVE it as follows:
-
- bsave "name, &H(IP value),
- &H(CX value)
- (Hex numbers require the
- prefix'&H' in BASIC.)
-
- Let's take a brief look at the BASIC
- call procedure. One of the problems
- with BASIC is where to put its
- machine language program. The BASIC
- work segment is the first 64K bytes
- of memory. If you have more than 64K,
- you can BLOAD machine language
- anywhere above this segment:&H1700 is
- a popular choice. If you a have a
- color graphics card (we're assuming
- you do here) you can even put
- programs fewer than 192 bytes at
- &H1F40 (between the even and odd
- buffers). Assumming 64K, we located
- the subroutine in the top 1K, in
- step 8. To be perfectly safe, you can
- reserve this space by beginning the
- program with a CLEAR,&H8C00 command.
- (BASIC and DOS take up about 28K
- leaving 36K. Then 36K - 1K = 35K =
- Hex 8C00). Step 9, the BLOAD command,
- actually puts our subroutine in the
- default segment with an offset of 0
- (Hex FC00).
-
- That's about it. Further details
- about the BASIC 'CALL' command are in
- the BASIC Manual. Two clearly written
- books about assembly language are:
- "The iAPX Book (Intel) and "IBM PC
- Assembly Language" (L. Scanlon, Brady
- Publishing Co.,1983). (Editor's
- note: Another excellent book on this
- subject is "IBM PC Assembly Language
- Programming" by Dave Bradley.)