home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / PASTUT34 / REGS.TXT < prev    next >
Text File  |  1993-06-12  |  19KB  |  509 lines

  1.                         USING REGISTERS.
  2.                         ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  3.  
  4. Before considering the use of registers in Turbo Pascal, it is useful
  5. to appreciate the function and behaviour of registers and to use the 
  6. DOS facility DEBUG to inspect both the registers and memory.
  7.  
  8. Intel 8088, 8086, 80286 and 80386 microprocessors have 14 Registers, 
  9. which are used to store and process numbers quickly, within the 
  10. Central Processor Unit (CPU) itself.  These are 16-bit registers, 
  11. although the first four may be accessed as 8-bit parts. 
  12.  
  13. The word-sized registers are as follows:
  14.  
  15. Data registers (general purpose)  - AX, BX, CX and DX
  16.  
  17. Pointer registers (Base and Stack) - BP and SP
  18.  
  19. Index registers (Source & Destination)  - SI and DI
  20.  
  21. Segment registers (Code, Data, Stack & Extra) - CS, DS, SS and ES
  22.  
  23. Instruction pointer register  - IP
  24.  
  25. Status register (Flags).
  26.  
  27. The function of each register.
  28. ══════════════════════════════
  29. The AX (Accumulator) register is used to store data prior to the
  30. execution of an instruction.
  31.  
  32. The BX (Base) register is used in some memory addressing schemes.
  33.  
  34. The CX (Count) register is often used as a loop counter.
  35.  
  36. The DX (Data) register is used to store 16-bit data or as an extension
  37. to the AX register when handling 32-bit data.
  38.  
  39. The BP (Base Pointer) and SP (Stack Pointer) registers are used to
  40. point to the Stack, a part of memory used for passing parameters to
  41. subroutines, storing return addresses and saving register values for
  42. later retrieval.
  43.  
  44. The SI (Source Index) and DI (Destination Index) registers are used in
  45. complex addressing modes and for string manipulation.
  46.  
  47. The CS (Code Segment) register identifies the segment in which the 
  48. program resides. Absolute  memory addresses of specific instructions 
  49. are calculated by combining the segment address in the CS register 
  50. with the offset address in the Instruction Pointer (IP) to get a 
  51. 20-bit absolute address of the instruction  -  CS:IP.
  52.  
  53. The DS (Data Segment) register identifies the segment in which the 
  54. data (program variables) reside. In conjunction with another register 
  55. containing the offset data item (e.g. DS:BX), this register can also 
  56. be used to find the absolute address of that data item.
  57.  
  58. The SS (Stack Segment) register points to the stack segment and is 
  59. used in conjunction with the Stack Pointer (SP).
  60.  
  61. The ES (Extra Segment) register is used by string instructions.
  62.  
  63. Memory Usage.
  64. ═════════════
  65. Referring to the Turbo Pascal Memory Map (page 210 of the Programmer's
  66. Guide), the memory is used as follows:
  67.  
  68. The data segment (addressed through DS) contains all typed constants 
  69. followed by all global variables. The DS register is never changed 
  70. during program execution.
  71.  
  72. The stack segment register (SS) and the stack pointer (SP) are loaded 
  73. on entry to the program so that SS:SP points to the first byte past 
  74. the stack segment. The SS register is never changed during program 
  75. execution, but SP can move downward until it reaches the bottom of 
  76. the segment.
  77.  
  78. The ES (Extra Segment) register points to an extra segment of memory,
  79. which may be used, with DS, to mark the source and destination of 
  80. string moves.
  81.  
  82. The IP (Instruction Pointer) register holds the offset address of the 
  83. next instruction to be executed and is used in conjunction with CS to
  84. obtain the absolute address.
  85.  
  86. The Status register is a collection of nine bits (flags), which 
  87. indicate the outcome of arithmetical and logical operation as below:
  88.  
  89. The Carry flag (bit 0) is set to 1 if add causes a carry or subtract
  90. causes a borrow.
  91.  
  92. The Parity flag (bit 2) is set to 1 for even parity, 0 for odd parity.
  93.  
  94. The Auxiliary Carry flag (bit 4) is used for BCD arithmetic.
  95.  
  96. The Zero flag (bit 6) is set to 1 if the result of an operation is 
  97. zero.
  98.  
  99. The Sign flag (bit 7) is set to 1 if the result of an arithmetical or
  100. logical operation is negative.
  101.  
  102. The Trap flag (bit 8) is set by the processor to single-step through
  103. the program instructions.
  104.  
  105. The Interrupt enable flag (bit 9) is set to 1 to enable interrupts.
  106.  
  107. The Direction flag (bit 10) is set to either increment or decrease the
  108. index register by one.
  109.  
  110. The Overflow flag (bit 11) indicates an overflow condition in 
  111. arithmetic operations with signed numbers.
  112.  
  113. The DOS Debug facility and registers.
  114. ═════════════════════════════════════
  115. A simple text program, which can be created by using the Turbo Pascal
  116. editor, can be loaded into memory by means of the DOS debug utility
  117. by typing:
  118.  
  119.    debug <filespec>
  120.  
  121. where <filespec> can be the full file specification, including drive,
  122. directory and filename.
  123.  
  124. The screen response is the minus sign (-) and then a number of debug
  125. commands can be used, such as d followed by the offset address to 
  126. 'dump' a section of memory or r to indicate the state of the various 
  127. registers as shown below: 
  128.  
  129. debug test.txt
  130.  
  131. -d 0100                                                                         
  132. 4DFC:0100  46 69 72 73 74 20 6C 69-6E 65 20 6F 66 20 74 65   First line of te   
  133. 4DFC:0110  78 74 0D 0A 53 65 63 6F-6E 64 20 6C 69 6E 65 20   xt..Second line    
  134. 4DFC:0120  66 6F 6C 6C 6F 77 73 0D-0A 54 68 69 72 64 20 6C   follows..Third l   
  135. 4DFC:0130  69 6E 65 20 69 73 20 6E-65 78 74 0D 0A 46 6F 75   ine is next..Fou   
  136. 4DFC:0140  72 74 68 20 6C 69 6E 65-20 69 73 20 6C 61 73 74   rth line is last   
  137. 4DFC:0150  0D 0A 1A 00 00 00 00 00-00 00 00 00 00 00 00 00   ................   
  138. 4DFC:0160  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
  139. 4DFC:0170  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................   
  140.  
  141.  
  142. -r                                                                              
  143. AX=0000  BX=0000  CX=0053  DX=0000  SP=2AB6  BP=0000  SI=0000  DI=0000          
  144. DS=4DFC  ES=4DFC  SS=4DFC  CS=4DFC  IP=0100   NV UP EI PL NZ NA PO NC           
  145. 4DFC:0100 46            INC     SI                                              
  146. -q
  147.  
  148. The last command q is used to quit debug.
  149.  
  150. It can be seen that the CS register displays the segment in which the
  151. code resides, whilst the IP register indicates that the code starts at
  152. the offset address 0100, which is the normal offset used by debug.
  153.  
  154. Finally, other debug commands can be used to write a new line to the
  155. file. Enter (e) is used first to add a new line and then insert a
  156. carriage return and line feed (OD OA). Then Name (n) is used to give
  157. this file a new name (test2.txt) and Write (w) is employed to write
  158. the new file, as shown below.
  159.  
  160.  
  161. -e 0152 "One more line added"
  162. -e 0165 0D 0A
  163. -r cx
  164. CX 0053
  165. :67
  166. -n test2.txt
  167. -w
  168. Writing 0067 bytes
  169.  
  170. This can then be checked as follows:
  171.  
  172. -d 0100
  173. 4DFC:0100  46 69 72 73 74 20 6C 69-6E 65 20 6F 66 20 74 65   First line of te
  174. 4DFC:0110  78 74 0D 0A 53 65 63 6F-6E 64 20 6C 69 6E 65 20   xt..Second line
  175. 4DFC:0120  66 6F 6C 6C 6F 77 73 0D-0A 54 68 69 72 64 20 6C   follows..Third l
  176. 4DFC:0130  69 6E 65 20 69 73 20 6E-65 78 74 0D 0A 46 6F 75   ine is next..Fou
  177. 4DFC:0140  72 74 68 20 6C 69 6E 65-20 69 73 20 6C 61 73 74   rth line is last
  178. 4DFC:0150  0D 0A 4F 6E 65 20 6D 6F-72 65 20 6C 69 6E 65 20   ..One more line
  179. 4DFC:0160  61 64 64 65 64 0D 0A 00-00 00 00 00 00 00 00 00   added...........
  180. 4DFC:0170  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
  181. -
  182.  
  183. Register Usage.
  184. ═══════════════
  185. There are three ways in which registers are used in Turbo Pascal.
  186.  
  187. 1. With debug to trace a Turbo Pascal program, observing the contents
  188.    of the registers, as they change with each machine code instruction.
  189.  
  190.    The contents of the registers can also be inspected from the
  191.    Integrated Development Environment by means of the Window Menu (Alt-W)
  192.    and selecting R for Registers, the contents of which are then shown
  193.    in a window at the top right of the screen. The registers can also be
  194.    inspected in the watch window, as explained later in these notes.
  195.  
  196. 2. To accept the return of function results.
  197.  
  198. 3. In conjunction with Interrupt Service Routines.
  199.  
  200.  
  201. 1. Tracing a Turbo Pascal program.
  202. ──────────────────────────────────
  203. When a Turbo Pascal program is compiled it is converted to machine code.
  204. It is then possible to use the DOS debug facility to locate this .EXE
  205. file in memory, find a particular instruction and trace its operation.
  206. It is also possible to 'unassemble' the machine code and obtain the 
  207. assembly language instructions.
  208.  
  209. The process of locating a particular instruction is facilitated by the
  210. use of a simple Inline machine code instruction, which creates three
  211. consecutive NOP instructions ( No OPeration ). In machine code this
  212. instruction is represented by the hexadecimal value 90. The occurrence 
  213. of 90 90 90 clearly indicates this point in the program. 
  214.  
  215. A very simple Turbo Pascal program is now used to illustrate this point.
  216.  
  217. program Turbo_Assembly;
  218.  
  219. var
  220.    x,y     : Integer;
  221.  
  222. begin
  223.    Inline($90/$90/$90);
  224.    x := 3;
  225.    y := x * x;
  226.    Inline($90/$90/$90)
  227. end.
  228.  
  229.  
  230. If this program is saved as RegsDemo.pas and compiled to RegsDemo.exe,
  231. it can then be studied with the DOS debug facility as shown below:
  232.  
  233. C>debug                    { run debug                            }
  234. -n RegsDemo.exe            { set file name to be used by load     }
  235. -l                         { load file                            }
  236. -s cs:0000 ffff 90 90 90   { search code segment for NOPs         }
  237. 13A0:0008                  { the first encounter                  }
  238. 13A0:001b                  { the second encounter                 }
  239. -r ip                      { request the current value of IP      }
  240. IP 0000                    { the value returned by debug          }
  241. :0008                      { debug gives : prompt for new value   }
  242. -t                         { trace request for single instruction }
  243.  
  244. At this point the contents of all the registers are shown and the next
  245. instruction - in this case NOP. 
  246.  
  247.  
  248. AX=0000  BX=0000  CX=0330  DX=0000  SP=4000  BP=0000  SI=0000  DI=0000
  249. DS=1390  ES=1390  SS=1415  CS=13A0  IP=0009   NV UP EI PL NZ NA PO NC
  250. 13A0:0009 90            NOP
  251.  
  252.  
  253. Further trace commands repeat this procedure for each instruction,
  254. until the final three NOP instructions are encountered. The displays are
  255. similar with some values remaining unchanged. The essential changes are
  256. shown below.
  257.  
  258.  
  259. -t
  260. AX......
  261. DS......                            IP=000A
  262. 13A0:000A 90            NOP 
  263.  
  264.  
  265. -t
  266. AX......
  267. DS......                            IP=000B
  268. 13A0:000B C7063E000300  MOV     WORD PTR [003E],0003         DS:003E=0000   
  269.  
  270.  
  271. -t
  272. AX......
  273. DS......                            IP=0011
  274. 13A0:0011 A13E00        MOV     AX,[003E]                    DS:003E=0003
  275.  
  276.  
  277. -t
  278. AX=0003......
  279. DS......                            IP=0014 
  280. 13A0:0014 F72E3E00      IMUL    WORD PTR [003E]
  281.  
  282.  
  283. -t
  284. AX=0009......
  285. DS......                            IP=0018               ZR   PE
  286. 13A0:0018 A34000        MOV     [0040],AX                    DS:0040=0000
  287.  
  288.  
  289. -t
  290. AX=0009......
  291. DS......                            IP=001B
  292. 13A0:001B 90            NOP
  293.  
  294.  
  295. The unassembled machine code is obtained by using the debug command 
  296. u <segment address> <offset address> as shown below:
  297.  
  298.  
  299. -u 13A0:0000
  300. 13A0:0000 9A0000A313    CALL    13A3:0000
  301. 13A0:0005 55            PUSH    BP
  302. 13A0:0006 89E5          MOV     BP,SP
  303. 13A0:0008 90            NOP
  304. 13A0:0009 90            NOP
  305. 13A0:000A 90            NOP
  306. 13A0:000B C7063E000300  MOV     WORD PTR [003E],0003
  307. 13A0:0011 A13E00        MOV     AX,[003E]
  308. 13A0:0014 F72E3E00      IMUL    WORD PTR [003E]
  309. 13A0:0018 A34000        MOV     [0040],AX
  310. 13A0:001B 90            NOP
  311. 13A0:001C 90            NOP
  312. 13A0:001D 90            NOP
  313. etc.
  314.  
  315.  
  316. Although an understanding of machine code is required to fully 
  317. appreciate the above, it can be seen that the value 0003 is sent to
  318. an address 003E and then put into the AX register and finally 
  319. (integer) multiplied  with itself to give 0009 in the AX register.
  320.  
  321.  
  322. 2. Function results in Turbo Pascal.
  323. ────────────────────────────────────
  324. Function results are returned through the  registers, not the stack,
  325. as shown in the table below:
  326.  
  327. Function result    Registers
  328. ───────────────    ─────────
  329. shortint, byte     AL
  330. integer, word      AX
  331. longint            DX:AX (most significant word: least significant word)
  332. real               DX:BX:AX (most: middle: least significant word)
  333. single, double  )
  334. extended, comp  )  Maths coprocessor top-of-stack register
  335. pointer            DX:AX (segment:offset)
  336. string             Pointer on stack to temporary storage
  337.  
  338.   ────────────────────────────────────────────────────────────────────────
  339.  
  340.  
  341. 3. Interrupt Service Routines.
  342. ──────────────────────────────
  343. Interrupts provide the means for I/O devices to communicate with the CPU.
  344. An interrupt informs the processor that an external device requires
  345. attention. This causes the processor to suspend its current activity in
  346. order to respond to the interrupt. The processor, however, finishes 
  347. executing the last instruction, saves the address of the next instruction
  348. on the stack, and then jumps to the special interrupt handling routine
  349. in a designated part of memory. After executing this routine, the 
  350. processor returns to the suspended program by 'popping' the address of 
  351. the next instruction from the stack.
  352.  
  353. The pointers (or vectors) to the interrupt routines are stored in the 
  354. lowest 1024 bytes of memory in the Vector Interrupt Table. Interrupts can 
  355. be called by the assembly language instruction INT or from Turbo Pascal
  356. by the Intr procedure.
  357.  
  358. Interrupts can be categorised as logical, hardware or software interrupts.
  359.  
  360. Logical interrupts include INT $00, divide-by-zero and INT $04, overflow.
  361.  
  362. Hardware interrupts include INT $09, keyboard and INT $0D hard disk
  363. controller.
  364.  
  365. Software interrupts include calls to BIOS and DOS routines, such as
  366. the BIOS INT $10 which relates to the Video Display and the much used 
  367. DOS INT $21, which can ascertain disk drive capacity, for example.
  368.  
  369. The BIOS and DOS interrupts require that certain values are placed in 
  370. the registers before the interrupt is called and generally return values
  371. in these registers after the interrupt. The complete detail of these 
  372. register values must be found from a suitable reference, such as
  373.  
  374. Advanced MS-DOS Programming 2nd. Ed. by Ray Duncan, published by Microsoft.
  375.  
  376. DOS and BIOS Functions. Quick Reference by Que Corporation.
  377.  
  378. Interrupts called from Assembly Language programs feature in the section
  379. on In-Line code.
  380.  
  381. For interrupts from Turbo Pascal, the Intr procedure is called (or the 
  382. MsDos procedure which is equivalent to Intr with an interrupt number of
  383. $21). The 'call' and 'return' values in the registers are facilitated
  384. by a variable of the type Registers, which is defined in the DOS unit as
  385.  
  386. type
  387.   Registers = record
  388.                  case integer of
  389.                    0: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: word);
  390.                    1: (AL,AH,BL,BH,CL,CH,DL,DH: byte);
  391.                  end;
  392.               end;
  393.  
  394. This is a variant record to map the 8-bit registers on top of their 
  395. 16-bit equivalents.
  396.  
  397. If in the VAR declaration part of the program an instance of this
  398. Registers type is declared, it is then possible to inspect the contents
  399. of the registers from the Integrated Development Environment using the
  400. Watch Window, as indicated below:
  401.  
  402.   Var
  403.     Regs : Registers;
  404.  
  405.   Then Alt-D, W, A (or Crtl-F7) to enter the watch variable as Regs,r
  406.   where the ,r indicates that the variable is a record type.
  407.  
  408.  
  409. A typical example illustrates the use of BIOS interrupt $10 with the 
  410. register AH set to $0F before the call and returns AH = number of columns
  411. on the screen, AL = the display mode and BH = the active display page.
  412. The filename for this example is INTRDEMO.PAS and it is listed below:
  413.  
  414. program GetDisplayMode;
  415.  
  416. uses DOS, Crt;
  417.  
  418. var
  419.    Regs        : Registers;    { Registers is a record defined in DOS unit }
  420.    Mode        : Byte;
  421.    Width       : Byte;
  422.    Page        : Byte;
  423.    DisplayMode : String[20];
  424.  
  425. begin
  426.    Regs.AX := $0F00;           { Sets AH = 0F for Get Display Mode function }
  427.    Intr($10,Regs);             { Interrupt 10 for ROM BIOS Video Services }
  428.    Mode  := Lo(Regs.AX);       { Display Mode returned in AL }
  429.    Width := Hi(Regs.AX);       { Screen width returned in AH }
  430.    Page  := Hi(Regs.BX);       { Screen page returned in BH }
  431.  
  432.    ClrScr;                                { Uses Crt }
  433.    Writeln('Display Mode is ',Mode);
  434.    Writeln('Screen Width is ',Width,' Columns');
  435.    Writeln('Screen Page is ',Page);
  436. end.
  437.  
  438.   ────────────────────────────────────────────────────────────────────────
  439.  
  440. Another example shows the use of a DOS interrupt $21 with the AH 
  441. register set to $1C and the DL register to the drive number before the 
  442. call. The disk capacity is returned as shown in registers AL, CX, DX and
  443. in DS:BX.
  444.  
  445.  
  446. Program  GetAllocationTableInfo;
  447.  
  448. uses DOS,Crt;
  449.  
  450. var
  451.    Regs              : Registers;
  452.    Sectors_Cluster   : Word;
  453.    Bytes_Sector      : Word;
  454.    Clusters_Disk     : Word;
  455.    Seg_Address       : Word;
  456.    Off_Address       : Word;
  457.    Disk_Type         : Word;
  458.    Drive             : Char;
  459.  
  460. begin
  461.    Write('Enter drive letter A,B or C:  ');
  462.    Readln(Drive);
  463.    Drive := UpCase(Drive);
  464.    case Drive of
  465.         'A' : Regs.DL := 1;
  466.         'B' : Regs.DL := 2;
  467.         'C' : Regs.DL := 3
  468.    end;
  469.  
  470.    Regs.AH := $1C;
  471.    Intr($21,Regs);
  472.    Sectors_Cluster := Lo(Regs.AH);
  473.    Bytes_Sector    := Regs.CX;
  474.    Clusters_Disk   := Regs.DX;
  475.    Seg_Address     := Regs.DS;
  476.    Off_Address     := Regs.BX;
  477.  
  478.    ClrScr;
  479.    
  480.    Disk_Type := MemW[Seg_Address:Off_Address];
  481.    Writeln('Disk type ');
  482.    case Disk_type of
  483.         240 : Writeln('Not identifiable');
  484.         248 : Writeln('Fixed disk');
  485.         249 : Writeln('Double sided, 9 sectors per track (720K)');
  486.         250 : Writeln('Double sided, 15 sectors per track (1.2M)');
  487.         252 : Writeln('Single sided, 9 sectors per track');
  488.         253 : Writeln('Double sided, 9 sectors per track (360K)');
  489.         254 : Writeln('Single sided, 8 sectors per track');
  490.         255 : Writeln('Double sided, 8 sectors per track')
  491.    end;
  492.    Writeln;
  493.    If Disk_Type <> 240 then
  494.         begin
  495.            Writeln('Sectors per cluster      = ',Sectors_Cluster);
  496.            Writeln('Bytes per sector         = ',Bytes_Sector);
  497.            Writeln('Clusters per disk        = ',Clusters_Disk);
  498.            Writeln('Media descriptor address = ',Seg_Address,':',Off_Address);
  499.            Writeln
  500.         end;
  501.    MemW[Seg_Address:Off_Address] := 240;
  502. end.
  503.  
  504.   ────────────────────────────────────────────────────────────────────────
  505.  
  506. REGS.TXT
  507. Revised 20.1.93
  508.  
  509.