'=========================================================================== ' Subject: PC MAGAZINE'S POKES & PEEKS Date: 11-12-85 (19:44) ' Author: David I. Schneider Code: TEXT ' Origin: Rolf@ice.prima.ruhr.de Packet: MEMORY.ABC '=========================================================================== * * * POKES & PEEKS * * * Did you know that there is a lot of information that may be accessed from the ROM BIOS area in your IBM PC regarding the operating characteristics and options found on your own IBM PC? After careful analysis of data found in the IBM Technical Reference manual a summary of the most useful information and where and how it may be referenced has been prepared. By specifying a DEF SEG=&H40 in any BASIC program, it is possible to reference the following vectors (fields) in the ROM BIOS area by using a PEEK function and the following offsets from the current segment as defined by the DEF SEG statement. &H0 - RS232 Addresses on your IBM PC. This will allow you to tell how many (up to four) async cards are attached, if any. &H8 - Printer Addresses on your IBM PC. This will tell you what printer addresses, and how many (up to four) exist. Each is addressed by a two-byte hex value. &H10 - Equipment Flag. This field describes the setting of the options switches. It describes what optional devices are attached to the system. The following lists the bit-significance of this field: Bit 0 - indicates that there are disk drives on the system Bit 1 - not used Bit 2,3 - Planar Ram Size (00=16K 10=32K 01=48K 11=64K) Bit 4,5 - Initial Video Mode (00=Unused; 10=40x25 Color 01=80x25 Color 1; 1=80x25 Mono) Bit 6,7 - Number of Disk Drives (00=1; 10=2; 01=3; 11=4 only if bit 0 = 1) Bit 8 - Unused Bit 9,10,11 - Number of RS232 Cards attached Bit 12 - Game I/O Attached Bit 13 - Not used Bit 14,15 - Number of printers attached &H13 - Memory Size in K bytes &H15 - I/O RAM Size in K bytes &H17 - Keyboard Flag. The following lists the masks set to describe current keyboard status: Byte 1: &H80 - Insert state active &H40 - CapsLock state has been toggled &H20 - NumLock state has been toggled &H10 - ScrollLock state has been toggled &H08 - Alternate shift key depressed &H04 - Control shift key depressed &H02 - Left shift key depressed &H01 - Right shift key depressed Byte 2: &H80 - Insert key is depressed &H40 - CapsLock key is depressed &H20 - NumLock key is depressed &H10 - ScrollLock key is depressed &H08 - Suspend key has been toggled &H49 - Current CRT mode &H00 - 40x25 BW &H01 - 40x25 Color &H02 - 80x25 BW &H03 - 80x25 Color &H04 - 320x200 Color &H05 - 320x200 BW &H06 - 640x200 BW &H07 - 80x25 B&W Card -- speS)CG\+MF;uuse, used internal to the video routines. &H4A - Number of CRT columns &H50 - Cursor Position (one of eight) &H60 - Current cursor mode &H6C - Low word of Timer count &H6E - High word of Timer count &H71 - &H07 - Break key de8gIae--UROeTBHg 44E - Beginning of character regen memory &HFF53 - PrtSc routine address ----------------------------------------------------------------- PEEKing at Your PC's Memory (PC Magazine Vol 4 No 23 Nov 12, 1985 by David I. Schneider) Would you like to know the next number that will be generated by BASIC's random number generator? Would you like to know the date 1,000 days from now? Would you like to determine which of your printers is on-line? Or have six palettes at your disposal in medium-resolution graphics mode instead of the normal two? These and many more tasks are easily accomplished by PEEKing (looking into a memory location), POKEing (placing a number into a memory location), INPing (reading a number from a port), or OUTing (sending a number to a port). This article attempts to give a thorough documentation of the varied uses of these statements. While the explanations are in BASIC, most of the information is applicable to every programming language. - - - - - Before You Start: Before entering and executing any of the PEEK and POKE statements in this article, be sure this statement is executed first: DEF SEG = 0. PC Magazine tried the PEEKs and POKEs in this article on standard IBM equipment, and they worked flawlessly. However, since they bypass many built-in safeguards to work directly with your system's memory, playing with them carelessly or on non-IBM equipment is like playing with fire, so type them in carefully, observe the proper DEF SEG, and don't try any variations unless you know what you're doing. - - - - - PEEKs, POKEs, INPs and OUTs reveal the inner workings of the computer and thus give the programmer direct control. IBM discourages the use of PEEK, POKE, INP and OUT, however, since the company cannot guarantee that future releases of DOS or future ROM chips will use the current memory locations. Also, ports associated with nonstandard hardware might function in different ways. To be safe, widely distributed and commercial programs should avoid such undocumented features. On the other hand, IBM has been quite consistent so far. Most of the memory locations and ports presented in this article hold for all existing versions of DOS and BASIC. Of course, this might change with some future release. Theoretically, the IBM PC can directly address 1048576 memory locations, numbered 0 through 1048575. Normally, a maximum of 640K locations of RAM is available for user programs. The remainder consists of ROM or is otherwise reserved for present or future system applications. A segment is a 64K portion of memory beginning at a location that is a multiple of 16. Segment 0 consists of memory locations 0, 1, 2, 3, ...65535. Segment 1 consists of memory locations 16, 17, 18, ... 65551. Segment 2 consists of memory locations 32, 33, 34, ...65567. In general, then, segment m consists of memory locations 16*m, 16*m+1, 16*m+2, ...16*m+65535. Within each segment, the first memory location is said to have offset 0, the second memory location is at offset 1, and so forth; the last memory location is said to have an offset of 65535. Memory locations are specified by giving a segment that contains the location, together with the offset of that location within the segment. Most memory locations can thus be specified in many ways. For instance, the designations "segment 0:offset 34," "segment 1:offset 18," and "segment 2:offset 2" actually refer to the same memory location. Each memory location holds a number from 0 to 255. These numbers are often called bytes. In BASIC (either in immediate mode or in a program), to read the number in the memory location segment m:offset n, you execute: DEF SEG = m : PRINT PEEK (n). The DEF SEG statement specifies the mth segment as the current segment, and the value of PEEK(n) is the number contained in the memory location of offset n in the current segment. In a similar way, to insert the number r into the memory location segment m:offset n, you execute: DEG SEG = m : POKE n,r. This POKE statement places the number r into the memory location of offset n in the mth segment. The PC's microprocessor receives data from and sends data to the various components of the computer through ports. There are ports associated with the keyboard, the disk drives, the speaker, and the screen, for example. A byte of data consists of a number from 0 to 255, and each port has a number assigned to it. The value of the function INP(n) is the value of the byte read from port n. The statement OUT n,m sends byte m to port n. The listings presented here deal with memory locations in segment 0, which is often referred to as low memory. The program, LOMEMRY.BAS, illustrates many of the applications. Two important procedural considerations must be stressed if you intend to enter the listings from the keyboard to try them out. First, the statement: DEF SEG = 0 should be executed before the PEEK and POKE statements in this section are executed. Second, to prevent a Syntax Error message, remember to type PRINT before each of the PEEK statements, so the result will be displayed on the screen. The words AND and OR in these listings are logical operators and do not mean "the sum of" or "an alternative to." KEYBOARD 1. The following statements are used to set or determine the status of the keyboard toggle keys. CapsLock Key: "PEEK (1047) AND 64" has a value of 0 if the keyboard is in lowercase mode and a value of 64 if the uppercase mode is active. To specify lowercase: POKE 1047, PEEK(1047) AND 191. To specify uppercase: POKE 1047, PEEK(1047) OR 64. To toggle between upper and lowercase: POKE 1074, PEEK(1047) XOR 64. The statement "PEEK(1048) AND 64" has a value of 64 if the key is pressed, 0 otherwise. NumLock Key: The statement "PEEK(1047) AND 32" has a 0 value in the cursor-control mode and a value of 32 for the numeric-keybad state. To specify the cursor-control state: POKE 1047,PEEK(1047) AND 223. To specify the numeric-keypad state: POKE 1047,PEEK(1047) OR 32. To toggle between states: POKE 1047,PEEK(1047) XOR 32. The statement "PEEK(1048) AND 32" has a value of 32 if the key is pressed and a value of 0 otherwise. Ins Key: The statement "PEEK(1047) AND 128" has a value of 128 for the insert state, 0 otherwise. To specify the insert mode: POKE 1047,PEEK(1047) OR 128. To specify noninsert mode: POKE 1047, PEEK(1047) AND 127. To toggle the state: POKE 1047,PEEK(1047) XOR 128. The statement "PEEK(1048) AND 128" has a value of 128 if the key is pressed a a 0 value otherwise. ScrollLock Key: The statement "PEEK(1047) AND 16" has a value of 16 when ScrollLock is on and a value of 0 otherwise. To specify the ScrollLock state: POKE 1047,PEEK(1047) OR 16. To specify the alternate state: POKE 1047,PEEK(1047) AND 239. To toggle states: POKE 1047,PEEK(1047) XOR 16. The statement "PEEK(1048) AND 16" has a value of 16 if the key is pressed a a value of 0 otherwise. 2. The following statements test the status of some special keys. The statement "PEEK(1047) AND 8" has a value of 8 if the Alt key is pressed and a value of 0 otherwise. The statement "PEEK(1047) AND 4" has a value of 4 if the Ctrl key is pressed, 0 otherwise. The statement "PEEK(1047) AND 1" has a value of 1 if the right Shift key is pressed and a 0 value otherwise. The statement "PEEK(1047) AND 3" has a value of 0 if neither shift key is pressed. The statement "PEEK(1048) AND 4" has a value of 4 if the Sys Req key is pressed; otherwise its value is 0 (PC AT only). 3. In the numeric keypad state, the character with an ASCII value n can be displayed on the screen by holding down the Alt key, typing the number n on the numeric keypad, and they releasing the Alt key. PEEK(1049) has a value of n from the time the number is typed until the Alt key is released. 4. The circular keyboard buffer begins at location PEEK(1050) + 1024 and ends (possibly after cycling back to location 1054) at location PEEK(1052)+1023. Ordinary characters use every other location. Extended characters use two locations, the first location containing the null character (CHR$(0)). The statement "POKE 1050, PEEK(1052)" clears the keyboard buffer. The contents of the buffer can be read by PEEK without first being removed from the buffer. Further, characters can be POKEd into the buffer to ensure the continuation of a program even if a program-terminating statement is executed. For instance, if the string: "GOTO 99" + CHR$(13) is POKEd into the buffer and a LIST command is executed, the program will continue execution at line 99 after the LISTing has been completed, which overcomes BASIC's annoying habit of stopping dead after certain operations. 5. With PCs whose motherboard can hold 256K bytes of RAM, the keyboard buffer can be assigned a different location and length. The following program places the beginning of the keyboard buffer at memory location 1024 + B and gives it the capacity of holding L characters. 10 DEG SEG=0:H=INT(B/256) 20 POKE 1152,B-H*256:POKE 1153,H 30 T=B+2*L+2:H=INT(T/256) 40 POKE 1154,T=H*256:POKE 1155,H 50 POKE 1050,PEEK(1152):POKE 1051,PEEK(1153) 60 POKE 1052,PEEK(1152):POKE 1053,PEEK(1153) The buffer contents always begin at: PEEK(1050)+256*PEEK(1051)+1024 and end (possibly after cycling back from location 1085 to location 1024+B) at location: PEEK(1052)+256*PEEK(1053)+1024. You must use case in choosing B and L. Two possibilities are B=144, L<55 and B=301,L<233. 6. To disable Ctrl-Break, enter: FOR I=0 TO 3:POKE(108+I), PEEK(112+I):NEXT I. Before disabling Ctrl-Break, use PEEK to record the bytes in locations 108-111. You can then POKE these bytes back in to reenable Ctrl-Break. 7. The statement "PEEK(1137) AND 128" has a the value of 128 if the Ctrl-Break sequence has been used since startup to terminate the execution of a program. 8. To disable the keyboard (PC & XT only), send "OUT 97, INP(97) OR 128". Remember that when the keyboard is disabled, subsequent keystrokes are ignored. 9. To reenable the keyboard (PC & XT only), send "OUT 97, INP(97) AND 127". 10. To disable all keyboard interrupts: OUT 33,130. If keys are pressed after the interrupts are disabled, the scan codes of the first 20 keys will be held in a buffer located in the keyboard unit. These codes will be read after the interrupts are reenabled. 11. To reenable keyboard interrupts: OUT 33,128. 12. Each key has an identifying number called its scan code. The following program will usually obtain the scan code of a key. After typing RUN, you must press the Enter key quickly. They press any key to obtain its scan code. (The program will not work on the PC AT or certain IBM PC-compatibles.) 10 OUT 33,130 20 WHILE INP(96)=0:WEND 30 PRINT INP(96) 40 OUT 33,128 13. For the PC AT only, when a key is held down for more than 1/2 second (the default delay time), it repeats ten times per second (the default typematic rate). To change the delay rate do d quarter-seconds (d=1,2,3 or 4) and the typematic rate to approximately r repetitions per second (r between 2 and 30), you would enter: OUT 96,243:OUT 96,n where n = (d-1) * 32 + CINT(11.5 * LOG(29/r)). Conversely, the statement: OUT 96,243:OUT 96,n with n=0,1, ...127, specifies a delay rate of 1+(n\32) quarter seconds and a typematic rate of 1/((8+(n MOD 8))*2^((n AND 24)/8)*.00417) repetitions per second. The default state corresponds to n=44. 14. For the PC AT only, the green lights that indicate CapsLock, NumLock and ScrollLock status can be turned on and off without altering any of the states. The statement: OUT 96,237:OUT 96,n produces the following results: n = 7 all indicators on n = 6 ScrollLock indicator off, others on n = 5 NumLock indicator off, others on n = 4 CapsLock indicator on, others off n = 3 CapsLock indicator off, others on n = 2 NumLock indicator on, others off n = 1 ScrollLock indicator on, others off n = 0 all indicators off MONITOR STATUS 1. To check the type of display: PEEK(1040) AND 48 = 0 is no monitors PEEK(1040) AND 48 = 16 is a 40 x 25 graphics monitor PEEK(1040) AND 48 = 32 is a 80 x 25 graphics monitor PEEK(1040) AND 48 = 48 is a monochrome display 2. To select a display: Monochrome POKE 1040,PEEK(1040) OR 48 Graphics POKE 1040,(PEEK(1040) AND 207) OR 16 The first POKE should be followed by: SCREEN 0:WIDTH 40:WIDTH 80: LOCATE ,,1,12,13. The second should be followed by: SCREEN 1,0,0,0: SCREEN 0:WIDTH 40:LOCATE ,,1,7,7. Before switching monitor types, it is a good idea to record (in an array) the numbers that are contained in memory locations 1097 to 1126. These values can then be confidently restored after the return to the first display. 3. To check screen mode: PEEK(1097) = 0 text mode, WIDTH 40, color disabled PEEK(1097) = 1 text mode, WIDTH 40, color enabled PEEK(1097) = 2 text mode, WIDTH 80, color disabled PEEK(1097) = 3 text mode, WIDTH 80, color enabled PEEK(1097) = 4 medium resolution graphics, color enabled PEEK(1097) = 5 medium resolution graphics, color disabled PEEK(1097) = 6 high-resolution graphics PEEK(1097) = 7 monochrome display PEEK(1098)+256*PEEK(1099) gives the width in columns. Color can be suppressed only on composite monitors. RGB monitors will display color even if you are in one of the color-disabled modes listed above. 4. Subscripts and superscripts can be displayed in the top half of the graphics screens. The following programs place the string B$ as a subscript of the string A$. The value of R must be between 1 and 12, and the value of C can be at most one more than the width of the screen minus the sum of the lengths of the two strings. To display B$ as a superscript of A$, replace the R in line 40 by R-1. 10 SCREEN 1:CLS 10 SCREEN 2:CLS 20 LOCATE R,C:PRINT A$; 20 LOCATE R,C:PRINT A$; 30 POKE 1098,20 30 POKE 1098,40 40 LOCATE 2*R:PRINT B$ 40 LOCATE 2*R:PRINT B$ 50 POKE 1098,40 50 POKE 1098,80 5. The contents of the graphics screen are stored in a buffer beginning at offset: PEEK(1102)+256*PEEK(1103) in a portion of memory that physically resides on a graphics board. The size of this buffer is given by: PEEK(1100)+256*PEEK(1101) 6. When using text mode with a graphics monitor, there are several memory pages at your disposal. The cursor locations for the various pages are given as follows: Let CR(n) and CC(n) be the Cursor Row and Cursor Column for page n. Then: PEEK(1105)+2*n) has a value of CR(n)-1, and: PEEK(1104+2*n) has a value of CC(n)-1. 7. The shape of the cursor can be set with a statement of the form: LOCATE ,,,I,J. In this LOCATE statement, "PEEK(1121) AND 31" has value I, and "PEEK(1120) AND 31" has value J. If "PEEK(1121) AND 32" has a value of 32, then the cursor is not displayed. 8. To obtain the number of the visual page (that is, the page currently being displayed), you simply "PEEK(1122)". 9. The adapter boards can be given instructions by OUTing to ports on a chip known as the CRT controller chip. To determine the number of the index register port for the adapter board currently in use, "PEEK(1123)+256*PEEK(1124)". The value will be 948 for the monochrome display board and 980 for the color/graphics adapter. 10. The following statements check the mode settings on the CRT mode register currently in use: PEEK(1125) AND 1 has value 1 if in text mode, width 80 PEEK(1125) AND 2 has value 2 if in graphics mode PEEK(1125) AND 4 has value 4 if color is disabled (for instance, if the statement SCREEN 1,1 has been executed) PEEK(1125) AND 8 has value 8 if video is enabled, that is, not blanked PEEK(1125) AND 16 has value 16 if in high-resolution graphics mode PEEK(1125) AND 32 has value 32 if blinking is enabled The value of PEEK(1125) will change after appropriate SCREEN or WIDTH statements are executed. It is not affected by OUT statements, however. It will not always reflect the true status of the monitor, therefore, unless it is updated after OUTs to port 984 or 952. 11. In the medium-resolution graphics mode, the background color and palette are selected by the statement COLOR b,p. The statement "PEEK(1126) AND 15" will have the balue b, and "(PEEK(1126) AND 32)/32" will have the value p. In text mode, with a color monitor, the value of "PEEK(1126) MOD 16" will be the border color and "PEEK(1126) AND 16" will be 16 if the current color was specified by a statement of the form COLOR f,b in which f is 0 through 15 and b>7. The value of PEEK(1126) will change after appropriate SCREEN or COLOR statements are executed. However, it is not affected by OUT statements. Therefore, it will not always reflect the true status of the monitor unless it is updated after OUTs to port 985. 12. In graphics mode, the statement "PRINT CHR$(n)" where n is a number from 128 to 254, causes the computer to display the character in an 8 by 8 rectangle of pixels. Each character is described by a sequence of eight bytes. The eight bytes describing CHR$(128) are contained in the eight successive memory locations beginning with the location at offset "PEEK(124)+256*PEEK(125)" in segment "PEEK(126)+ 256*PEEK(127)". The pattern for CHR$(129) is contained in the next eight locations, and so on. To create a character set for ASCII values from 128 to 254: a. Select the portion of memory to hold the bytes describing the characters. b. POKE the pattern for character 128 into the first eight memory locations, the pattern for character 129 into the next eight locations, and so on. c. POKE the offset and segment of the first byte into locations 124 to 127. 13. The video parameter table consists of 64 bytes beginning at memory location of offset "PEEK(116)+256*PEEK(117)" in segment "PEEK(118)+256*PEEK(119)". The first 16 bytes are numbers that are OUTed to registers on the color/graphics adapter board when the 40 by 25 text mode is initialized. The next two 16-byte sequences are associated with the 80 by 25 text and graphics modes on the color/ graphics adapter. The final sequence of 16 bytes is used to initialize the monochrome display. You must be very careful when changing these bytes. Certain values for the first 10 bytes in each sequence could damage your monitor. PRINTER 1. The number of printer adapters installed is given by "(PEEK (1041) AND 192)/64". 2. To determine the first port associated with LPTn, "PEEK(1030 +2*n)+256*PEEK(1031+2*n)". If this number is 0, then LPTn is not available. To swap two printers, interchange their initial port numbers. Denote the first port associated with LPTn by Pn. The value of P1 will by 956 if LPT1 is attached to the IBM monochrome display and parallel printer adapter. 3. The ASCII value of the last character sent to the printer by LPRINT or PRINT# is: INP(Pn). 4. To determine printer status: LET X = INP(Pn+1) X AND 128 has value 128 if the printer is busy or off line X AND 64 has value 0 if the printer has acknowledged that data has been sent and is ready to receive more X AND 32 has value 32 if the printer is out of paper X AND 16 has value 16 if the printer is on-line X AND 8 has value 0 if there is an I/O error 5. To initialize the printer, send: OUT Pn+2,8:OUT Pn+2,12 6. With PCs having 256K RAM motherboards, the parallel printer timeout values can be read and set. The timeout value for LPTn is approximately: 1.6*PEEK(1143+n) seconds. To set the timeout value for LPTn to S seconds: POKE 1143+n,.64*S. DISK DRIVES 1. To determine the number of diskette drives: (PEEK(1040) AND 1)*(1+PEEK(1040)\64). 2. In determining the status of a drive motor: PEEK(1087) AND 128 has a value of 128 when a disk drive is being written to, and: PEEK(1087) AND 15 has a value of 0 when no drive motor is running. If drive L is running, then the value of "PEEK(1087) AND 2 ^ (ASC ("L")-65)" will be 1. Drive L here is A, B, C or D, and the letter must be typed in uppercase. These value are not affected if an OUT was used to turn on the motor. 3. To turn on drive L for n seconds, where n is at most 14: POKE 1088,18.2*n:OUT 1010,2^(ASC("L")-61)+ASC("L")-53. Location 1088 holds the countdown, in clock ticks, until the diskette motor is shut off. 4. To turn off all drives, send: OUT 1010,12 5. To determine the diskette track that was last accessed, use: PEEK(1093). 6. To determine which diskette head (0 or 1) was last accessed, use: PEEK(1094). 7. Similarly, to determine which diskette sector was last accessed: PEEK(1095). When single-sided diskettes are used, items 5, 6 and 7 above may specify the sector following the one most recently accessed. 8. The number of bytes per sector on a diskette is given by: 128*2^PEEK(1096). 9. The diskette parameter table consists of 11 bytes. To explore this: LET D = PEEK(120)+256*PEEK(121). Then, after executing: DEF SEG = PEEK(122)+256*PEEK(123) you can derive the following table: (PEEK(D) AND 240)\8 is the time (in milliseconds) required for the diskette drive to move from track to track (PEEK(D) AND 15)*32 is the head unload time (in milliseconds) after a read or write operation has occurred (PEEK(D+1) AND 240)\4 is the head load time (in milliseconds) PEEK(D+1) AND 15 is the Direct Memory Access mode PEEK(D+2) is the wait time until turning the motor off PEEK(D+3) is the number of bytes per sector on the disk; a value of v specifies 128*2^v bytes per sector, for v=0 to 3 PEEK(D+4) is the number of sectors per track, usually 8 or 9 PEEK(D+5) is the gap length (in bytes) between sectors PEEK(D+6) is the data length that you read out or write into a sector when the sector length is not specified PEEK(D+7) is the gap length used when formatting PEEK(D+8) is the value the format operation uses to initialize diskette sectors, usually 256 PEEK(D+9) is the number of milliseconds allowed for the heads to stabilize PEEK(D+10) is the number of eighths of a second to allow for motor startup Changing the values of PEEK(D+3) and PEEK(D+4) can modify the way that diskettes are read and might require you to format your diskettes manually. 10. The number of hard disks on a PC-XT can be found with: PEEK(1141). 11. If a single diskette drive is used for both drives A: and B:, its current roles is: CHR$(65 + PEEK(1284)) RS-232 INTERFACE 1. The number of RS-232 cards attached can be found with: (PEEK(1041) AND 14)/2 2. To determine the first of the seven ports associated with COMn: PEEK(1022+2*n)+256*PEEK(1023+2*n). If this number is 0, then COMn is not available. To swap two RS-232 interfaces, interchange their initial port numbers. Denote the initial port associated with COMn by Pn. Normally, the value of P1 is 1016 and the value of P2 is 760. 3. Interrupt enabling: OUT Pn+1,1 enables an interrupt when a character has been received OUT Pn+1,2 enables an interrupt when a character has been transmitted OUT Pn+1,4 enables an interrupt when an error has occurred OUT Pn+1,8 enables an interrupt when the modem status has changed To enable several of the above interrupts at the same time, OUT the sum of the associated numbers to port Pn+1. 4. To identify interrupts, use the port number determined above (Pn) and: LET X = INP(Pn+2). "X AND 1" has a value of 1 as long as no interrupts have been issued because of communications port activity. Similarly, "X AND 6" is used to identify the highest priority interrupt pending, as indicated in the table "Interrupt Control Functions" in the IBM Technical Reference manual. 5. To establish the number of data bits (d), the number of stop bits (s), and the parity (p=0 for no parity, p=1 for odd parity, p=3 for even parity), send: OUT Pn+3, d-5 + 4*(s-1) + 8 * p. 6. To establish the baud rate: H=INP(Pn+3):OUT Pn+3,H OR 128: OUT Pn,DL:OUT Pn+1,DH:OUT Pn+3,H. Use values DL=128 and DH=1 for 300 baud, and DL=96 and DH=0 for baud rate 1200. Otherwise, DL=d MOD 256 and DH=d\256, where d is the divisor number given by the IBM Technical Reference manual in the table "Baud Rate at 1.853 MHz." 7. To produce a break signal: X=INP(Pn+3):OUT Pn+3,X OR 64:PLAY "MF":SOUND 32767,6:SOUND 32767,1:OUT Pn+3,X. The PLAY and SOUND statements produce a delay of 1/3 second. 8. To control the modem, use: OUT Pn+4,1 to assert that the data terminal is ready (DTR) OUT Pn+4,2 to raise a request to send (RTS) OUT Pn+4,16 to perform loopback testing To accomplish several of the above tasks simultaneously, OUT the sum of the associated numbers to port Pn+4. 9. To determine the status of data transfer, begin with: LET X = INP(Pn+5). Now: X AND 64 has a value of 64 if the transmitter shift register is idle X AND 32 is 32 if the transmitter holding register is ready to accept a character for transmission X AND 16 has the value 16 if the received data input is held in the spacing state too long (that is, if a break was received) X AND 8 has the value 8 if the received character did not have a valid stop bit; that is, if a framing error occurred X AND 4 has the value 4 if the received character does not have the correct parity X AND 2 is 2 if the received data destroyed the previous character (an overrun error) X AND 1 has value 1 if a character is ready to be read from the received buffer register 10. INP(Pn) will read the ASCII value of a character from the serial port, provided: (INP(Pn+5) AND 1) = 1 11. You can use OUT Pn,m to write the character with ASCII value m to the serial port, provided that: (INP(Pn+5) AND 32) = 32 12. To determine the status of the modem, use: X = INP(Pn+6). Then: X AND 128 has the value 128 if a Carrier signal has been detected X AND 64 is 64 if the modem is ringing X AND 32 has a value of 32 if the modem has asserted Data Set Ready X AND 16 is 16 if the modem has asserted Clear to Send X AND 8 is 8 if the Carrier Detect has changed state X AND 4 has the value 4 if the Ring Indicator input has changed from On to Off X AND 2 is 2 if the Data Set Ready input has changed state since the last time it was read X AND 1 has a value of 1 if the Clear to Send input has changed state since it was last read SPEAKER 1. The timer chip determines the frequency of the sound produced by the speaker. To prepare to send a value to the timer chip, send: OUT 67,182 2. The human ear can perceive sounds varying in frequency from about 20 to 20,000 Hz. To set the timer chip to produce a frequency of F Hz: A=INT(1193182/F):H=INT(a/256):L=A-H*256:OUT 66,L:OUT 66,H 3. To turn the speaker on, use: OUT 97,INP(97) OR 3 4. Conversely, to turn the speaker off: OUT 97,INP(97) AND 252 CASETTE PORT CONTROL 1. To turn the cassette motor on: OUT 97,INP(97) AND 247 2. To turn the cassette motor off: OUT 97,INP(97) OR 8 Even if a cassette player is not attached, toggling the cassette motor produces a clicking sound. Repeated togglings can produce interesting sound effects, but since the relay involved is not designed as a musical instrument, excessive use may cause its failure. MISCELLANEOUS 1. The number of game adapters attached is shown with: (PEEK (1041) AND 16)/16 2. To find the size of RAM in kilobytes, use: PEEK(1043) + 256*PEEK(1044) 3. The internal clock ticks 18.20648 times per second. The number of ticks that have occurred since midnight is given by: PEEK(1132)+256*PEEK(1133)+65536PEEK(1134). This value increases until it reaches 1,533,039 (an instant before midnight), and at midnight it is reset to 0. The value of PEEK(1136) is increased by 1 as a result of the reset. Executing either TIME$ or DATE$ changes the value of PEEK(1136) back to 0. To determine the date N days from now, execute: FOR I=1 TO N: POKE 1136,1:A$=DATE$:NEXT I:PRINT DATE$. With versions of DOS prior to 3.0, when N is less than 256, the entire FOR...NEXT loop can be replaced by POKE 1136,N. 4. Memory locations 1264 to 1279 are not used by either DOS or BASIC. Data can be passed from one program to another by POKEing it into these locations and PEEKing it later. 5. To exit BASIC and complicate reinvoking it, you can: POKE 1295,2:SYSTEM. Memory location 1295 is set to 2 when the BASIC command SHELL is executed. 6. The segment number of BASIC's data segment may be found with: PEEK(1296)+256*PEEK(1297) 7. To disable the nth interrupt: POKE n*4,83:POKE n*4+1,255: POKE n*4+2,0:POKE n*4+3,240. Prior to executing these statements, use PEEK to record the contents of the four memory locations. To reenable the interrupt, use POKE to restore these locations to their original state. This part of the article is divided into sections that each deal with the memory locations found in a specified, common segment. When typing in the applications that follow, you must be careful to execute the proper DEF SEG statement for each section and to preface each PEEK with a PRINT statement. The three programs, DEMO1.BAS, DEMO2.BAS and DEMO3.BAS illustrate many of these applications. BASIC's Data Segment Prefix with DEF SEG unless otherwise noted The segment of memory that is allocated to BASIC is referred to as BASIC's Data Segment. When BASIC is first invoked, it is the current segment. Also, the BASIC statement DEF SEG, when used without any additional address, specifies this memory segment. BASIC's Data Segment is partitioned into seven regions. The first of these is the interpreter work area; the remaining six regions will be referred to as BASIC's storage area. A. Interpreter Work Area In the following discussion, Classic PCs are the original PCs, produced in 1981 and 1982, with a maximum of 64K bytes of RAM on the motherboard. Their ROM chips are usually dated 4/24/81 or 10/19/81. New PCs consist of all subsequent PCs, including the XT and the AT. 1. With a New PC, using BASIC versions 2.0, 2.1 or 3.0, you can determine the last random number to be generated with (1+PEEK(11)+256*PEEK(12)+65536*PEEK(13))/2^24 When using a Classic PC or using a New PC with BASIC 3.1, do not add in the initial number 1. The procedure above assumes that RANDOMIZE has not been executed since the last random number was generated. On a New PC, the result will occasionally differ from the actual value of RND in the last digit. The number 1 was added in the formula for New PCs to reduce round-off errors. 2. To determine the next random number to be generated: Successive random numbers are generated by a formula involving two parameters, A# and B#, below. These two numbers vary according to the type of PC and the version of BASIC. Some combinations are: A# = 214013, B# = 13737667 (a New PC and a version of BASIC prior to 3.1); A# = 17405, B# = 10395331 (a Classic PC and a version of BASIC prior to 3.1); A# = 214013, B# = 2531011 (a New PC and BASIC 3.1); and A# = 214013, B# = 10395331 (A Classic PC and BASIC 3.1). The following program will compute the numbers A# and B# for your particular configuration. Record the values of A# and B# for future use. 10 POKE 11,0:POKE 12,0:POKE 13,0:T=RND 20 B#=PEEK(11)+256*PEEK(12)+65536#*PEEK(13) 30 POKE 11,1:POKE 12,0:POKE 13,0:T=RND 40 A#=PEEK(11)+256*PEEK(12)+65536#*PEEK(13)-B# 50 PRINT "A# =";A#;"B# =";B# AT any time, the following program will determine the next random number to be generated by a Classic PC using any version of BASIC or a New PC using BASIC 3.1. 10 S#=PEEK(11)+256*PEEK(12)+65536#*PEEK(13) 20 X#=A#*S#+B# 30 T#=X#-2#^24*INT(X#/2#^24) 40 PRINT "The next random number will be";CSNG(T#/2#^24) For a New PC and a version of BASIC preceding 3.1, replace lines 10 and 30 with: 10 S#=PEEK(11)+256#*PEEK(12) 30 T#=1+x#-2#^24*INT(X#/2#^24) POKEing numbers into locations 11, 12 and 13 reseeds the random-number generator. 3. PEEK(40) returns the number of the most recent error message. 4. Normally, the first 24 lines of the screen scroll as the screen fills. However, the scrolling portion of the screen can consist of any rectangular portion beginning on the left side of the screen. The following statements specify that the scrolling portion of the screen consists of the first c positions of lines a through b. Once the cursor has been moved to this region, it will be confined there. POKE 41,c:POKE 91,a:POKE 92,b To prevent all scrolling, even when characters are PRINTed into the last line, execute: POKE 92.0. (Be careful to POKE another number into location 92 before the program terminates.) To scroll all 25 lines, execute: KEY OFF:POKE 92,25 5. For the current BASIC line number, PEEK(46)+256*PEEK(47) 6. To determine the screen mode, PEEK(72) = 0 text mode, WIDTH 40, color burst disabled = 1 text mode, WIDTH 40, color burst enabled = 2 text mode, WIDTH 80, color burst disabled = 3 text mode, WIDTH 80, color burst enabled = 4 medium-resolution graphics, color burst enabled = 5 medium-resolution graphics, color burst disabled = 6 high-resolution graphics, color burst disabled = 7 monochrome display 7. To determine the text-mode foreground color, PEEK(75) 8. For the text-mode background color, PEEK(76) 9. For the text-mode border color, PEEK(77) 10. For medium-resolution text color, PEEK(78) AND 3 11. To set the text color in medium-resolution graphics mode to color c of the current palette (c = 1, 2 or 3), POKE 78,c 12. For the medium-resolution background color, PEEK(81) AND 15 13. For the medium-resolution palette, PEEK(82) MOD 2 14. The row number of the cursor is given by, PEEK(86). The column number is given by, PEEK(87). 15. For the WIDTH of each line printed on LPT1, PEEK(98). To set the WIDTH to w, execute: POKE(98),w. 16. The position of the print head within the buffer of LPT1 is given by: PEEK(99). To move the print head to position n, execute: PEEK(99),n 17. PEEK(100) returns a value of 1 if the cassette motor is off, 0 if the motor is on. 18. To determine if the soft keys are displayed on line 25: PEEK(113) = 0 not displayed = 1 displayed ever since BASIC was invoked = 255 displayed as a result of executing KEY ON If the soft keys are displayed and 0 is POKEd into location 113, the keys will continue to be displayed. However, the combination of LOCATE and PRINT will be able to display characters on the 25th line, and CLS will erase the 25th line. 19. To determine the exact user response to an INPUT, LINE INPUT, INPUT#, or LINE INPUT# statement, use: A$="":N=503:WHILE PEEK(N)<>0:A$=A$+CHR$(PEEK(N)):N=N+1:WEND:? A$ (Note: This line must be part of a program. If executed in direct mode, it will just read itself. While numeric responses are often rounded, truncated, or converted to floating-point form, the string A$ will consist of the exact digits typed.) 20. To show the location of the end of the last statement executed: PEEK(835)+256*PEEK(836). (Note: This pointer points to either the null character at the end of a line or to the colon separating a pair of statements.) 21. The memory location pointed to by the BASIC stack pointer is returned by: PEEK(837)+256*PEEK(838) 22. The line number of the last BASIC error is shown by: PEEK(839)+256*PEEK(840) 23. For the location of the program line n specified in an ON ERROR GOTO n statement: PEEK(845)+256*PEEK(846) 24. The segment number of BASIC's Data Segment is returned by: PEEK(848)+256*PEEK(849). Machine language programs must be POKEd into an unused portion of memory where they can be CALLed. One safe place is the segment whose number is 4096 higher than the segment number of BASIC's Data Segment. The available space can be determined by executing: DEF SEG=0:PRINT PEEK(1043)+256*PEEK(1044). This returns the size of the random access memory in kilobytes. 25. The memory location (in the text of a program) of the byte following the most recently READ piece of DATA is shown by: PEEK(862)+256*PEEK(863) 26. The minimum allowable value for array subscripts is at: PEEK(1116) 27. To protect the current program so that it cannot be LISTed or EDITed: POKE 1125,255 28. To determine if the current program is protected: PEEK(1124) has value 0 if the program is not protected; the message "Illegal function call" is produced if the program is protected. 29. To show the number of files specified by the /F option when BASIC was invoked, use: PEEK(1247) 30. To determine the File Control Blocks: LET X=PEEK(1248) + 256*PEEK(1249). Then the File Control Block for the nth file begins at the location shown by: PEEK(X+2*n)+256*PEEK(X+2*n+1). Bytes 3 through 13 of the File Control Block contain the name of the file. The drive containing the file is: CHR$(64+PEEK(2nd location)). 31. The disk drive containing the file most recently accessed by BASIC is: CHR$(64+PEEK(1264)) 32. The name of the file most recently accessed by BASIC is given by: FOR I=0 TO 10:PRINT CHR$(PEEK(1265+I));:NEXT I 33. For the coordinates of the last point referenced: PEEK(1341) +256*PEEK(1342) is the x coordinate; PEEK(1339)+256*PEEK(1340) is the y coordinate. 34. To set the coordinates of the last point referenced to (a,b), use: POKE 1341,a MOD 256:POKE 1342,a\256 POKE 1339,b MOD 256:POKE 1340,b\256 35. Strings of up to 15 characters can be assigned to the function keys with the KEY statement. These strings are stored in the 160 memory locations beginning with the location of offset 1619. Every 16th memory location and the unused locations contain a null character. You can use this information, in conjunction with redefining the scroll window, to customize the display that normally occupies the 25th line of the screen. 36. The current color to be used by DRAW statements is returned by: PEEK(1782) AND 3. To change the color to color c of the current palette, execute: POKE 1782,85*c. (Note: Any graphics statement containing a color parameter changes the value of PEEK(1782) AND 3 to the specified color.) 37. BASIC's environment begins at offset 0 in segment ENV, where the numeric value of ENV can be determined with the following program. Each equation in the environment is followed by a null character, and the final equation is followed by two null characters. 10 DEF SEG 20 PSP=PEEK(1794)+256*PEEK(1795) 'Program Segment Prefix 30 DEF SEG=PSP 40 ENV=PEEK(44)+256*PEEK(45) 38. The following listing will show the program that was executed and the options (such as /F:4) that were specified when BASIC was invoked. 10 DEF SEG 20 PSP=PEEK(1794)+256*PEEK*1795) 'Program Segment Prefix 30 DEF SEG=PSP 40 FOR I=130 TO 129+PEEK(128) 50 PRINT CHR$(PEEK(I)); 60 NEXT 39. The buffer size for random files specified by the /S option when BASIC was invoked is returned by: PEEK(N)+256*PEEK(N+1) where N = 1851, 1854, 1858 and 1858 for BASIC Versions 2.0, 2.1, 3.0, and 3.1, respectively. 40. Similarly, for the communications buffer size specified by the /C: option when BASIC is invoked: PEEK(N)+256*PEEK(N+1) where N = 1861, 1864, 1868 and 1870 for BASIC Versions 2.0, 2.1, 3.0, and 3.1, respectively. 41. To locate the communications buffer in BASICA 2.1: LET X=PEEK(1866)+256*PEEK(1867) for COM1: LET X=PEEK(1868)+256*PEEK(1869) for COM2: The buffer for receiving data when using the Asynchronous Communications Adapter begins at location PEEK(X+1)+256*PEEK(X+2) and it ends at PEEK(X+3)+256*PEEK(X+4)-1. The buffer for transmitting data begins at location PEEK(X+5)+256*PEEK(X+6) and ends at PEEK(X+7)+256*PEEK(X+8)-1. The numbers 1866-1869 should be changed to 1863-1866, 1870-1873, and 1872-1875 for BASICA Versions 2.0, 3.0, and 3.1, respectively. 42. The position of the print head within the buffer of LPT2 is returned by PEEK(N) where N = 1875, 1878, 1882, and 1884 in BASIC Versions 2.0, 2.1, 3.0, and 3.1, respectively. To move the print head to position n, execute POKE N,n. 43. Similarly, the position of the print head within the buffer of LPT3 is returned by PEEK(N) where N = 1876, 1879, 1883, and 1885 in BASIC Versions 2.0, 2.1, 3.0, and 3.1, respectively. To move the print head to position n, execute POKE N,n. 44. For the WIDTH of each line printed by LPT2: PEEK(N) where N = 1877, 1880, 1884, and 1886 in BASIC Versions 2.0, 2.1, 3.0, and 3.1, respectively. To set the WIDTH to w, execute POKE N,w. 45. Similarly, for the WIDTH of each line printed by LPT3: PEEK(N) where N = 1878, 1881, 1885, and 1887 in BASIC Versions 2.0, 2.1, 3.0, and 3.1, respectively. To set the WIDTH to w, execute POKE N,w. 46. In direct mode, pressing Ctrl-PrtSc causes the printer to print all output as it appears on the screen. This is referred to as an echo to the printer. In program (or direct) mode, the statement POKE N,255 turns on echoing and the statement POKE N,0 turns off echoing, where N = 1880, 1883, 1887, or 1889 in BASIC Versions 2.0, 2.1, 3.0, or 3.1, respectively. 47. To determine the music parameters in BASICA 2.1: PEEK(2140) has value 0 for the Music Foreground mode and values 1 or 255 for the Music Background mode. PEEK(2141) is the current octave number. PEEK(2142) is the current tempo in quarters per minute. PEEK(2143) is the reciprocal of the length of a standard note. It is set by the statement PLAY "Ln". PEEK(2145) has the value 1, 2, or 3 to demote Music Legato, Music Staccato, or Music Normal, respectively. The numbers 2140-2145 should be changed to 2144-2149 and 2149-2154 for BASICA Versions 3.0 and 3.1, respectively. In BASICA Version 2.0, 2141-2145 should be changed to 2136-2140, and 2140 should be changed to 2141. 48. PEEK(N) shows the scale to be used by DRAW, where N = 2161, 2163, 2167, and 2172 in BASICA Versions 2.0, 2.1, 3.0, and 3.1, respectively. To set the scale to n, execute POKE N,n. 49. Use the following statements to determine the angle at which future DRAWings will be turned in BASICA 2.1. (Such angles are set by the statement DRAW "TA n", where n is the number of degrees in the angle.) PEEK(2165) is the low byte in the integer representation of n. (Hence, if n is between 0 and 255 degrees, PEEK(2165)=n.) CVS(CHR$(PEEK(2166))+CHR$(PEEK(2167))+CHR$(PEEK(2168))+CHR$(PEEK(2169))) is the cosine of the angle n. CVS(CHR$(PEEK(2170))+CHR$(PEEK(2171))+CHR$(PEEK(2172))+CHR$(PEEK(2173))) is -1/1.2 times the sine of the angle in SCREEN mode 1. CVS(CHR$(PEEK(2174))+CHR$(PEEK(2175))+CHR$(PEEK(2176))+CHR$(PEEK(2177))) is 1.2 times the sine of the angle in SCREEN mode 1. Replace 1.2 with 2.4 for SCREEN mode 2. This information can be used to compute the cosine and sine of the angle, and hence the value of the angle. The numbers 2165-2177 should be chanted to 2163-2175, 2169-2181, and 2174-2186 for BASICA Versions 2.0, 3.0, and 3.1, respectively. 50. To determine status of light-pen trapping in BASICA 2.1, use: PEEK(2203) = 0 if trapping of light pen is OFF = 1 if trapping of light pen is ON = 2 if trapping of light pen is STOPped while OFF = 3 if trapping of light pen is STOPpen while ON Activating the light pen causes the program to branch to the program line stored at location PEEK(2204)+256*PEEK(2205). The numbers 2203- 2205 should be changed to 2201-2203, 2207-2209, and 2212-2214 for BASICA Versions 2.0, 3.0, and 3.1, respectively. 51. To determine the status of key-trapping in BASICA 2.1, use: PEEK(2203+3*n) = 0 if trapping of key n is OFF = 1 if trapping of key n is ON = 2 if trapping of key n is STOPped while OFF = 3 if trapping of key n is STOPped while ON Pressing key n causes the program to branch to the program line stored at location PEEK(2204+3*n)+256*PEEK(2205+3*n). The numbers 2203-2205 should be changed to 2201-2203, 2207-2209, and 2212-2214 for BASICA Versions 2.0, 3.0, and 3.1, respectively. 52. To determine the status of joystick-button trapping in BASICA 2.1, use: PEEK(2266+3*n/2) = 0 if trapping of button n is OFF = 1 if trapping of button n is ON = 2 if trapping of button n is STOPped while OFF = 3 if trapping of button n is STOPped while ON Buttons 0 and 4 are the lower and upper buttons of the first joystick, and buttons 2 and 6 are the lower and upper buttons of the second joystick. Pressing button n causes the program to branch to the line stored at location PEEK(2267+3*n/2)+256*PEEK(2268+3*n/2). The numbers 2266-2268 should be changed to 2264-2266, 2270-2272, and 2275-2277 for BASICA Versions 2.0, 3.0, and 3.1, respectively. 53. To determine the status of ON PLAY(n) trapping BASICA 2.1: PEEK(2278) = 0 if trapping is OFF = 1 if trapping is ON = 2 if trapping is STOPped while OFF = 3 if trapping is STOPped while ON When the changing of the number of notes in the music background buffer from n to n-1 is trapped, the program branches to the program line stored at location PEEK(2279)+256*PEEK(2280). The numbers 2278-2280 should be changed to 2276-2278, 2282-2284, and 2287-2289 for BASICA Versions 2.0, 3.0, and 3.1, respectively. The value of n is PEEK(N), where N = 2142, 2146, 2150, and 2155 in BASICA Versions 2.0, 2.1, 3.0, and 3.1, respectively. 54. To determine the status of the ON TIMER(n) trapping in BASICA 2.1: PEEK(2281) = 0 if trapping is OFF = 1 if trapping is ON = 2 if trapping is STOPped while OFF = 3 if trapping is STOPped while ON The elapsing of n seconds causes the program to branch to the program line stored at location PEEK(2282)+256*PEEK(2283). The numbers 2281- 2283 should be changed to 2279-2281, 2285-2287, and 2290-2292 for BASICA Versions 2.0, 3.0, and 3.1, respectively. The value of n is PEEK(N)+256*PEEK(N+1)+65536*PEEK(N+2), where N = 2145, 2149, 2153, and 2158 in BASICA Versions 2.0, 2.1, 3.0, and 3.1, respectively. At any time, the number of seconds remaining until a branching occurs is PEEK(n+3)+256*PEEK(N+4). To induce a branching as soon as possible, execute POKE N+4,0:POKE N+3,1. (Note: For values of n between 65536 and 86400, the ON TIMER statement causes a branching after just n-65536 seconds.) 55. To determine the keys or key combinations associated with the user-defined key traps in BASICA Version 2.1: If PEEK(2284)+2*(n-15))= 0, then the key with scan code PEEK(2285+2*(n-15)) is associated with Fn. (Here n = 15, 16, ....or 20.) Otherwise, the key combination consisting of one or more latched keys along with the key having scan code PEEK(2285+2*(n-15)) is associated with Fn. The following table gives the latched keys included in the combination. Let L% = PEEK(2284+2*(n-15)). L% AND 3 = 3 Shift key L% AND 4 = 4 Ctrl key L% AND 8 = 8 Alt key L% AND 32 = 32 NumLock key L% AND 64 = 64 CapsLock key The numbers 2284-2285 should be changed to 2282-2283, 2288-2289, and 2293-2294 for BASICA Versions 2.0, 3.0, and 3.1, respectively. 56. To determine the status of a VIEWport in BASICA Versions 2.1: If PEEK(2323) = 1, a viewport has been established If PEEK(2324) = 0, then VIEW has been executed If PEEK(2324) = 1, then VIEW SCREEN has been executed The x coordinates of the points in the viewpoint are stored in the range from PEEK(2315)+256*PEEK(2316) to PEEK(2317)+256*PEEK(2318), and the y coordinates range from PEEK(2319)+256*PEEK(2320) to PEEK(2321)+ 256*PEEK(2322). The numbers 2315-2324 should be changed to 2313-2322, 2319-2328, and 2324-2333 for BASICA Versions 2.0, 3.0, and 3.1, respectively. 57. In the world coordinate system of BASICA 2.1, PEEK(2359) has the value 1 if a WINDOW statement has been executed. If so, the coordinate system is right-handed if PEEK(2360)=0 and left-handed if PEEK(2360)=1. The x coordinates range from x1 to x2, and the y coordinates range from y1 to y2, where x1 = CVS(CHR$(PEEK(2361))+CHR$(PEEK(2362))+CHR$(PEEK(2363))+CHR$ (PEEK(2364))) y1 = CVS(CHR$(PEEK(2365))+CHR$(PEEK(2366))+CHR$(PEEK(2367))+CHR$ (PEEK(2368))) x2 = CVS(CHR$(PEEK(2369))+CHR$(PEEK(2370))+CHR$(PEEK(2371))+CHR$ (PEEK(2372))) y2 = CVS(CHR$(PEEK(2373))+CHR$(PEEK(2374))+CHR$(PEEK(2375))+CHR$ (PEEK(2376))) To return the physical coordinate system: POKE 2359,0. The numbers 2359-2376 should be changed to 2357-2374, 2363-2380, and 2368-2385 for BASICA Versions 2.0, 3.0, and 3.1, respectively. The world coordinates can be altered by appropriate POKEing.) 58. The music buffer is a circular buffer analagous to the keyboard buffer. In BASICA 2.1 it consists of the number of bytes returned by PEEK(2417)+256*PEEK(2418), and it extends from the location PEEK(2427)+256*PEEK(2428) to the location preceding PEEK(2425)+256* PEEK(2426). The notes to be played are stored in the bytes extending from PEEK(2421)+256*PEEK(2422) (the head) to the location preceding PEEK(2423)+256*PEEK(2424) (the tail), after possibly cycling back to the beginning of the buffer. Each note is described by 4 bytes. The duration of the note is (256*[1st byte]+[2nd byte])/583 seconds and the frequency is 596591/(256*[3rd byte]+[4th byte]) Hertz. In Music Background mode, the number of bytes remaining in the buffer at any time is given by PEEK(2419)+256*PEEK(2420). (Note: The beginning and end of the buffer are also given by PEEK(2394)+256*PEEK(2395) and PEEK(2396)+256*PEEK(2397)). The numbers 2394-2428 should be changed to 2420-2454, 2398-2432, and 2403-2437 for BASICA Versions 2.0, 3.0, and 3.1, respectively. The music buffer can be enlarged and relocated by POKEing into the above-mentioned memory locations. The buffer normally holds 32 notes. The program DEMO1.BAS shows how to create a buffer capable of holding N = 125 notes. By changing the value of N (which appears twice in the program), you can create even larger buffers. (Note: In the Music Normal or Music Staccato modes, the pause between successive notes is counted as a note.) B. BASIC's Storage Area The six regions in BASIC's storage area hold the text of the program, the values of the variables, and BASIC's stack. 1. The program text begins at PEEK(48)+256*PEEK(49) and ends, with a terminating null character appended at PEEK(854)+256*PEEK(855). (Note: The second value will be zero unless requested in direct mode after the execution of the program. From within the program mode it can be computed as PEEK(856)+256*PEEK(857)-3.) Key words are tokenized, and each 2-byte line number is preceeded with the 2-byte offset of the beginning of the next line. This information can be used to recover a program after NEW has been executed, provided you know the first line. To illustrate, suppose that the first line of a program is: 0 REM Can unNEW. This line is stored in 16 bytes: 2 bytes for the pointer to the location of the next line, 2 bytes for the line number, 1 byte for the token of REM, 1 byte for the space after REM, 9 bytes for "Can unNEW", and 1 null byte at the end of the line. To recover the program, a) Execute PRINT PEEK(48)+256*PEEK(49) (This is referred to as the number X, but be sure not to declare it as a variable, X.) b) Execute POKE X,(X+16) MOD 256:POKE *x+1,(X+16)\256 c) SAVE the program in ASCII format. d) LOAD the program. e) LIST the program. Every line will appear. (Note: As a precaution against losing a program, then, you can always make the first line 0 REM Can unNEW. Otherwise, in step (b), replace 16 with the number of bytes needed to store the first line of your program.) 2. Simple variables (that is, all variables except arrays) are stored beginning at PEEK(856)+256*PEEK(857). This region contains the values of the numeric variables and pointers to the locations of the string variables. 3. Array variables are stored beginning at PEEK(858)+256*PEEK(859) 4. Free space begins at PEEK(860)+256*PEEK(861). New variables take locations from the beginning of free space and new strings take locations from the end. 5. String space occupies the region extending from PEEK(815)+ 256*PEEK(816) to PEEK(778)+256*PEEK(779). New strings are added to the bottom of string space by taking memory locations from free space. 6. The space allocated for BASIC's stack follows the sgring space and extends to PEEK(44)+256*PEEK(45), the end of the portion of memory available to BASIC. (Normally, it is the end of BASIC's Data Segment, but it can be restricted by a CLEAR statement.) At any time, the byte on the top of the stack is in location PEEK(837)+256*PEEK(838). Monochrome Display DEF SEG = 45056 The 4000 memory locations at the beginning of segment &HB000 reside on the monochrome display adapter board and hold the contents of the screen. Each of the following PEEK and POKE statements should be preceded by DEF SEG = 45056 (or DEF SEG = &HB000). (Caution: The OUTs discussed in this section might cause physical damage if executed with a board other than the IBM monochrome display adapter.) 1. To place the character having ASCII value n in row r, column c: POKE 2*(80(r-1)+(c-1)),n To define the attribute for this character: POKE 2*(80(r-1)+(c-1))+1,a where a = 7 when normal (that is, white on black) = 1 when normal and underlined = 112 when reverse video (that is, black on white). Add 8 to each of the first two numbers to obtain high-intensity white and add 128 to any of the numbers to cause the characters to blink. (Note: When POKEd, the ASCII values 7, 9, 10, 11, 12, 13, 28, 29, 30, and 31 produce symbols.) 2. To disable blinking: OUT 952,15 3. To blank the screen: OUT 952,1 4. To restore the screen (and enable blinking): OUT 952,255 5. To turn off all but the first n rows of the screen: OUT 948,6:OUT 949,n Graphics Monitor DEF SEG = 47104 The 16K memory locations at the beginning of segment &HB800 reside on the color/graphics adapter board and hold the contents of the screen. The graphics screen has three modes: text, medium-resolution graphics, and high-resolution graphics. Each of the following PEEK or POKE statements should be preceded by DEF SEG = 47104 (of DEF SEG = &HB800). (Caution: The OUTs discussed in this section might cause physical damage if executed with a board other than the IBM color/ graphics adapter.) A. Text Mode In text mode (invoked by the statement SCREEN 0), characters can be displayed in rows of either 40 characters (invoked by the statement WIDTH 40) or 80 characters (invoked by the statement WIDTH 80). 1. To place the character having ASCII value n in row r, column c, with foreground color f and background color b: POKE a,n:POKE a+1,k where a = 160*(r-1)+2*(c-1) in WIDTH 80 and = 80*(r-1)+2*(c-1) in WIDTH 40, and where k = 16*b+f if the foreground should not blink and = 16*b+f+128 if the foreground should blink. The number f ranges from 0 to 15, and b ranges from 0 to 7. (Note: These locations correspond to page 0. To obtain the analogous results for page p, add p*4096 to a in WIDTH 80 and add p*2048 to a in WIDTH 40.) 2. To disable blinking: OUT 984,8 in width 40 OUT 948,9 in width 80 (Note: With blinking disabled, the number b in item 1 can range from 0 to 15.) 3. To blank the screen: OUT 984,32 in width 40 OUT 984,33 in width 80 4. To restore the screen: OUT 984,40 width 40, blinking enabled OUT 984,8 width 40, blinking disabled OUT 984,41 width 80, blinking enabled OUT 984,9 width 80, blinking disabled 5. To set the border color to d: OUT 985,d 6. The color/graphics adapter board contains 16K bytes of memory. Each pair of locations holds the information for one character. (The first location holds the ASCII value of the chracter and the second holds the attribute.) Any consecutive block of 2000 (in 40 by 25 mode) or 4000 pairs (in 80 by 25 mode) can be used to determine the characters appearing on the screen. To display the characters determined by pairs N, N+1, N+2, ...: OUT 980,12:OUT 981,N\256:OUT 980,13:OUT 981,N MOD 256 (To display the pth page in 40 by 25 mode, use N = p*2048. In 80 by 25 mode, use N = p*4096.) B. Medium-Resolution Graphics Mode In medium-resolution graphics mode, which is invoked by the statement SCREEN 1, the screen is partitioned into 320 by 200 pixels. 1. To turn on the pixel with coordinates x,y in color c of the current palette: Z=40*y+x\4+8152*(y MOD 2):W=2^(6-2*(x MOD 4)):POKE Z,(PEEK(Z) AND (255-3*W))+c*W 2. To use background color c and palette p: OUT 984,c+32*p The palette colors can be intensified by adding 16 to the number c+32*p. Therefore, four different palettes are available. 3. With an RGB monitor, an undocumented palette (and its intensified version) is available. To obtain the background color c and a palette consisting of the colors cyan, red, and white: OUT 984,46:OUT 985,c (Note: The palette colors can be intensified by adding 16 to the number c. Hence, there are actually 6 palettes available with an RGB monitor.) 4. To reverse the foreground and background colors (and interchange colors 1 and 2 of the palette) on the current display, use: FOR I% = 0 TO 16191:POKE I%,PEEK(I%) XOR 255:NEXT (Note: This procedure is sometimes valuable before doing a graphics dump to the printer.) 5. To blank the screen: OUT 984,2 6. To restore the screen: OUT 984,10 C. High-Resolution Graphics Mode In high-resolution graphics mode (invoked by the statement SCREEN 2), the screen is partitioned into 640 by 200 pixels. 1. To turn on the pixel with coordinates x,y: Z=40y+x\8+8152*(y MOD 2):POKE Z,PEEK(Z) OR 2^(7-x MOD 8) 2. To turn off the pixel with coordinates x,y: Z=40y+x\8+8152*(y MOD 2):POKE Z,PEEK(Z) AND (255-2^(7-x MOD 8)) 3. To change the foreground color to c: OUT 985,c (The background color is normally black.) 4. To reverse the foreground and background colors of the current display, use: FOR I% = 0 TO 16191: POKE I%,PEEK(I%) XOR 255:NEXT 5. To blank the screen: OUT 984,18 6. To restore the screen: OUT 984,26 D. Low-Resolution Graphics Mode The following programs set up a 160 by 100 pseudo-graphics mode with background color B. 10 KEY OFF:SCREEN 0,0,0:WIDTH 80 20 OUT 984,9 30 OUT 980,4:OUT 981,127 40 OUT 980,6:OUT 981,100 50 OUT 980,7:OUT 981,112 60 OUT 980,9:OUT 981,1 70 DEF SEG=&HB800 80 FOR I%=0 TO 16382 STEP 2 90 POKE I%,222:POKE I%+1,17*B 100 NEXT Although text cannot be PRINTed and pixels cannot be lit with PSET, the point with coordinates X,Y can be turned on in any one 16 colors, C, by executing: 200 S=X AND 1 210 A=160*Y+(X OR 1) 220 POKE A,(PEEK(A) AND (15+S*225))+(C*(16-15*S)) E. All Modes 1. The following program allows a graphics monitor and a monochrome display to be used at the same time. Suppose that BASIC is currently writing to the monochrome display. After this program is executed, data can be PRINTed onto the monochrome display and POKEd into the color/graphics adapter as in sections A, B, C, and D of the Graphics Monitor portion of this article. 10 FOR R=0 TO 15 20 READ V:OUT 980,R:OUT 981,V 30 NEXT 40 READ M:OUT 984,M 50 DATA 56,40,45,10,127,6,100,112,2,1,6,7,0,0,0,0,42 This program results in medium-resolution graphics. To obtain high-resolution graphics, replace the last number in the DATA statement with 26. To obtain text mode with 40 characters per line, replace line 50 with: 50 DATA 56,40,45,10,31,6,25,28,2,7,6,7,0,0,0,0,40 and to obtain text mode with 80 characters per line, replace line 50: 50 DATA 113,80,90,10,127,6,100,112,2,1,6,7,0,0,0,0,9 2. To move the screen horizontally by approximately h characters from the standard position: OUT 980,2:OUT 981,45+h in width 40 OUT 980,2:OUT 981,90+h in width 80 (Note: If h is positive, the screen moves left; if h is negative, the screen moves right.) 3. To move the screen vertically by about v pixels or characters from the standard position: OUT 980,7:OUT 981,112+v in graphics mode OUT 980,7:OUT 981,28+v in text mode (NOte: If v is positive, the screen moves up; if v is negative, the screen moves down.) 4. To turn off all but the first n rows of the screen: OUT 980,6:OUT 981,n 5. To decrease the amount of snow on the screen when POKEing characters or pixels into the screen, precede each POKE (or small group of POKEs) with: WHILE 1 AND INP(986):WEND:WHILE NOT(1 AND INP(986)):WEND Read Only Memory DEF SEG = 61440 The following memory locations are part of read only memory (ROM). Each PEEK in this section should be preceded by DEF SEG = 61440 (or DEF SEG = &HF000). 1. Error messages with numbers ranging from 1 to 30 and 50 to 67 are stored in ROM in the 741 memory locations beginning with the location at offset 25525. A null character appears at the end of each message, and question marks serve as place holders for the numbers with no messages. This information can be used, with ON ERROR and ERR, to display the nature of an error without first terminating the program currently in operation. 2. The strings that are assigned to the ten function keys when BASIC is first invoked are stored in ROM in the 71 memory locations beginning with the location of offset 44269. A null character appears at the end of each string. This information can be used to restore the original values to the function keys in the even that reassignments have been made with the KEY statement. 3. To determine possible parameters for BASIC's random number generator: PEEK(49771)+256*PEEK(49772)+65536*PEEK(49773)=214013 PEEK(49774)+256*PEEK(49775)+65536*PEEK(49776)=2531011 These numbers sometimes serve as parameters for the random number generator. In particular, they are the values of A# and B# for a New PC using BASIC 3.1. 4. In graphics mode, each character is displayed in an 8 by 8 array of pixels that can be stored as a sequence of 8 bytes. The bytes for the characters having ASCII values 0 to 127 are stored in the memory locations having offsets from 64110 to 65113. This information can be used to write a program that will display characters upside- down, enlarged, or sideways and to create banners with a printer. 5. To obtain the machine part number: FOR I=57344 TO 57350:PRINT CHR$(PEEK(I));:NEXT I 6. To obtain the IBM copyright notice: FOR I=57352 TO 57365:PRINT CHR$(PEEK(I));:NEXT I (Note: This information can be used to determine if the computer is an IBM or an IBM compatible.) 7. To obtain the version date of the ROM BIOS: FOR I=65525 TO 65532:PRINT CHR$(PEEK(I));:NEXT I (Note: Certain hardware, such as the IBM enhanced graphics monitor, can be used only if this date is sufficiently recent.) 8. To determine the computer being used: PEEK(65534) = 255 PC = 254 PC-XT or Portable PC = 253 PCjr = 252 PC AT (Note: The identification numbers of PC compatibles will most likely differ from these numbers. Some early XTs have a machine ID code of 255.) Exceptions for the PCjr The PEEKs, POKEs, INs, and OUTs presented in this article hold for the IBM PC, XT and AT; however, many of the items do not hold for the PCjr, such as outs to the color/graphics adapter and the POKEs that relocate the music buffer. And for non-IBM compatibles, remember that compatible is as compatible does.