Mastering Sideways ROM & RAM - Module 11 - Private workspace ------------------------------------------------------------ It is often necessary for SWR programs to use RAM workspace to store various values and addresses. The RAM within the SWR bank can only be used for this purpose if it is not write protected and if the values stored do not need to be accessed by other paged ROMs. If you intend to write software for ROMs rather than sideways RAM you must use RAM outside the 16K allocated to the paged ROMs. If you intend to write a program which, for example, uses an Osword in the DFS then the Osword parameter block must be in an area of memory accessable to both your ROM image and the DFS. It is usually possible to find an area of memory which can be used as workspace by your SWR programs. If you use a disc based BBC B you might consider using pages &09 and &0A. These pages are usually defined as cassette or RS423 output and input buffers but, when they are not used for their designated purpose, they may be available to your programs. The really big problem with using these two pages as workspace is that you will not be the first person to have had the idea. There are dozens of ROMs which use this area of memory as workspace. If your SWR programs use it as well you have to be aware that this area of RAM will not necessarily be available for exclusive use by your program and any data you store in it could become corrupted by other ROMs, by using the serial port, or by the Acorn speech system. Whatever area of memory you choose to use as workspace could become corrupted by other ROMs unless your program claims and uses private workspace. Private workspace starts at &1700 in BBC B computers with the Acorn DFS and at &E00 in the BBC B without a DFS. The Master computer makes private workspace available in paged memory overlaid on the MOS as well as from &E00 in main memory. In this module I will explain and demonstrate how to claim and use private workspace in main memory. At the end of the module I will explain how to modify these techniques to use the alternative paged memory private workspace available in the Master computer. In order to claim private workspace your SWR interpreter has to intercept the private workspace service call. To demonstrate the private workspace service call load the object code generated by the program TRACE into SWR and press the Break key (Ctrl+Break on the Master). A list of service calls similar to the one in figure 11.1 will be printed on the screen. Unless you use a BBC B with an Acorn 6502 Second Processor, Acorn DNFS and sideways RAM in socket &0F your trace will be different from the one in figure 11.1, but in all BBC computers you will find service call 2, the private workspace claim, somewhere in the list. A=19 X=0F Y=FF SPOOL/EXEC file closure A=0F X=0F Y=FF Vectors claimed A=FF X=0F Y=FF Tube system main init. A=01 X=0F Y=0E Abs. workspace claim A=02 X=0F Y=17 Private workspace claim A=FE X=0F Y=FF Tube system post init. A=11 X=0F Y=1F Font implode/explode Acorn TUBE 6502 64K A=03 X=0F Y=08 Auto-boot Acorn DFS A=10 X=0F Y=EE SPOOL/EXEC file closure A=0F X=0F Y=30 Vectors claimed A=0A X=0F Y=D4 Claim static workspace BASIC > Figure 11.1 Service call trace after Break ------------------------------------------- In figure 11.1 you can see that the private workspace claim, service call 2, is made with Y=&17. Private workspace starts at page &17 in the BBC B with the Acorn DFS. If the trace is run from a lower priority ROM than the DFS ROM then service call 2 will be made with Y=&19 indicating that the DFS has claimed pages &17 and &18 as private workspace. If the trace is run on a BBC B without a DFS then service call 2 is made with Y=&0E indicating that private workspace is available from &E00. The Master also makes service call 2 with Y=&0E indicating that, if private workspace is claimed in main memory rather than in paged memory, it also starts at &E00. Service call 2 is issued to all the paged ROMs, starting with ROM &0F. It gives the ROMs the opportunity to claim their own private workspace. Private workspace is allocated in pages of 256 bytes and is exclusive to the ROM claiming it. Service call 2 is made to each ROM with its ROM number in the X register and the first page number of the workspace available to it in the Y register. A ROM can claim private workspace by saving the contents of the Y register (ie. the most significant byte of the address of the start of private workspace) in the paged ROM workspace table from &DF0 to &DFF (one byte per ROM for ROMs &00 to &0F respectively). It must then increment the Y register once for each page of private workspace required. The Y register must never be decremented when service call 2 has been intercepted. The example coding in figure 11.2 could be used to claim one page of private workspace. .service PHA \ push accumulator on stack CMP #2 \ is it service call 2? BNE nottwo \ branch if not 2 TYA \ prepare to store start of workspace STA &DF0,X \ store start address in workspace table INY \ claim 1 page of workspace PLA \ restore accumulator RTS \ return to MOS .nottwo Figure 11.2 Claiming private workspace --------------------------------------- For obvious reasons page &0D of the I/O processor memory should never be corrupted by using it to run programs. Whenever a ROM needs to use its private workspace it should look up the most significant byte of the start address of the workspace in the paged ROM workspace table and access the workspace with indirect addressing. The ROM must not refer to the workspace directly because its start address will depend on the amount of workspace claimed by higher priority ROMs. If a ROM claims private workspace in main memory the value of the Oshwm and PAGE will be raised. If, for example, your program claims 2 pages of private workspace then Oshwm and PAGE will be raised, on a BBC B with DFS, from &1900 to &1B00. In this example, the private workspace could start at either &1700 or &1900 depending on the priority of your ROM with respect to the DFS ROM. Your program will work properly from all ROM sockets if it accesses the private workspace indirectly after looking up the most significant byte of the start address of private workspace in the paged ROM workspace table. This technique is illustrated in figure 11.3 which shows how your SWR program can use post-indexed indirect addressing to read the contents of the first byte of its private workspace. LDX &F4 \ load X with ROM number LDA &DF0,X \ find most sig. byte of workspace address STA &A9 \ store it for indirect addressing LDA #0 \ workspace always starts at a page boundary STA &A8 \ store least sig. byte of workspace address TAY \ Y = 0 LDA (&A8),Y \ Read first byte of private workspace Figure 11.3 Reading private workspace -------------------------------------- The techniques illustrated in figures 11.2 and 11.3 have been used in the program PRIVATE. This program claims one page of private workspace to use for an Osword parameter block. Osword &7D, one of the DFS Oswords, is used to demonstrate how your SWR programs can use Osword routines in other paged ROMs. In order to use Osword calls in this way the parameter block must be accessed by both ROMs, it cannot be within the paged RAM bank used by the SWR program. Private workspace in main memory is claimed by the program PRIVATE but it is made available to the DFS by specifying its address in the X and Y registers before calling Osword &7D. The private workspace will not be available to the DFS, or any other ROM, unless the program which claimed the workspace makes it available in this way. Osword &7D reads the catalogue for the current default disc drive. from this it extracts the number of times that disc has been written. This is known as the disc cycles. The number of cycles is available as a binary coded decimal number in a one byte parameter block specified by the X and Y registers on entry to Osword &7D. To use the program PRIVATE load the object code it generates into SWR and press the Break key. Type PRINT ~ PAGE and press Return. You will see that PAGE has been raised from &1900 to &1A00 (BBC B with Acorn DFS). Type *CYCLES and press Return. The program will read the current default disc drive and print the number of cycles. The program uses the unrecognised * command interpreter (lines 410-680) and error routine (lines 1080-1230) introduced in earlier modules of the course. One page of private workspace is claimed in lines 330 to 400. The start of the workspace is stored in the paged ROM workspace table (line 370) and the Y register is incremented once (line 380) to indicate that the minimum one page of private workspace is required. Only one byte of the one page is used by the program but workspace is only available in units of 256 bytes. When the unrecognised * command interpreter recognises the command *CYCLES control is passed to the label ".found" (line 690). The program stores the contents of the two zero page bytes it uses by pushing them on the stack (lines 700-730) and then uses Osargs to see if the DFS is active (lines 740-790). If the DFS is not active control is passed to the error routine (lines 1080-1230) which, after restoring the zero page bytes, halts the program and prints an error message. If the DFS is active the most significant byte of the address of the start of private workspace is read from the paged ROM workspace table (lines 800-810) and stored in the most significant of the two zero page bytes (line 820). These two zero page bytes are used later in the program to read the contents of the parameter block. The accumulator is transfered to the Y register (line 830) to make the most significant byte of the parameter block address available to Osword. The X register is loaded with zero (line 840) to make the least significant byte of the parameter block address available to Osword and X is stored in the least significant byte of the two zero page bytes (line 850). Osword &7D is called (lines 860-870) and the result is read from the parameter block in the first byte of the private workspace (lines 880-890). The result is printed (line 900 and lines 1240-1390) with a suitable message (lines 910-970). The zero page memory locations are restored (lines 990-1020), the stack is balanced (lines 1030-1050) and control is returned to the MOS after reseting the accumulator to zero to indicate that the command has been recognised (lines 1060-1070). 10 REM: PRIVATE 20 MODE7 30 HIMEM=&3C00 40 DIM save 50 50 diff=&8000-HIMEM 60 address=&A8 70 comvec=&F2 80 errstack=&100 90 ROMnumber=&F4 100 workspace=&DF0 110 gsread=&FFC5 120 osargs=&FFDA 130 osasci=&FFE3 140 osword=&FFF1 150 oscli=&FFF7 160 FOR pass = 0 TO 2 STEP 2 170 P%=HIMEM 180 [ OPT pass 190 BRK 200 BRK 210 BRK 220 JMP service+diff 230 OPT FNequb(&82) 240 OPT FNequb((copyright+diff) MOD 256) 250 BRK 260 .title 270 OPT FNequs("CYCLES") 280 .copyright 290 BRK 300 OPT FNequs("(C)1987 Gordon Horsington") 310 BRK 320 .service 330 PHA 340 CMP #2 350 BNE tryfour 360 TYA 370 STA workspace,X 380 INY 390 PLA 400 RTS 410 .tryfour 420 CMP #4 430 BEQ unrecognised 440 PLA 450 RTS 460 .unrecognised 470 TXA 480 PHA 490 TYA 500 PHA 510 LDX #&FF 520 .comloop 530 INX 540 LDA title+diff,X 550 BEQ found 560 LDA (comvec),Y 570 INY 580 CMP #ASC(".") 590 BEQ found 600 AND #&DF 610 CMP title+diff,X 620 BEQ comloop 630 PLA 640 TAY 650 PLA 660 TAX 670 PLA 680 RTS 690 .found 700 LDA address 710 PHA 720 LDA address+1 730 PHA 740 LDA #0 750 TAX 760 TAY 770 JSR osargs 780 CMP #4 \ Is DFS selected? 790 BNE error 800 LDX ROMnumber 810 LDA workspace,X \ MSB of workspace 820 STA address+1 830 TAY \ MSB for Osword 840 LDX #0 \ LSB of workspace 850 STX address 860 LDA #&7D 870 JSR osword \ Read disc cycles 880 LDY #0 890 LDA (address),Y \ Read result 900 JSR hexbyte+diff 910 LDX #&FF 920 .printloop 930 INX 940 LDA message+diff,X 950 BEQ quit 960 JSR osasci 970 JMP printloop+diff 980 .quit 990 PLA 1000 STA address+1 1010 PLA 1020 STA address 1030 PLA 1040 PLA 1050 PLA 1060 LDA #0 1070 RTS 1080 .error 1090 LDA #(wrong+diff) MOD 256 1100 STA address 1110 LDA #(wrong+diff) DIV 256 1120 STA address+1 1130 LDY #&FF 1140 .errorloop 1150 INY 1160 LDA (address),Y 1170 STA errstack,Y 1180 BPL errorloop 1190 PLA 1200 STA address+1 1210 PLA 1220 STA address 1230 JMP errstack 1240 .hexbyte 1250 PHA 1260 LSR A 1270 LSR A 1280 LSR A 1290 LSR A 1300 JSR nybble+diff 1310 PLA 1320 .nybble 1330 AND #&0F 1340 SED 1350 CLC 1360 ADC #&90 1370 ADC #&40 1380 CLD 1390 JMP osasci 1400 .message 1410 OPT FNequs(" Disc cycles") 1420 OPT FNequb(&0D) 1430 BRK 1440 .wrong 1450 BRK 1460 OPT FNequb(&FE) 1470 OPT FNequs("DFS not selected") 1480 BRK 1490 OPT FNequb(&FF) 1500 .lastbyte 1510 ] 1520 NEXT 1530 INPUT'"Save filename = "filename$ 1540 IF filename$="" END 1550 $save="SAVE "+filename$+" "+STR$~(HIMEM)+" "+STR$~(las tbyte)+" FFFF8000 FFFF8000" 1560 X%=save 1570 Y%=X% DIV 256 1580 *OPT1,2 1590 CALL oscli 1600 *OPT1,0 1610 END 1620 DEFFNequb(byte) 1630 ?P%=byte 1640 P%=P%+1 1650 =pass 1660 DEFFNequw(word) 1670 ?P%=word 1680 P%?1=word DIV 256 1690 P%=P%+2 1700 =pass 1710 DEFFNequd(double) 1720 !P%=double 1730 P%=P%+4 1740 =pass 1750 DEFFNequs(string$) 1760 $P%=string$ 1770 P%=P%+LEN(string$) 1780 =pass The techniques illustrated in figures 11.2 and 11.3 and demonstrated in the program PRIVATE need to be modified to use the alternative paged memory private workspace available in the Master series of computers. In Module 1 of the course I explained how setting bit 3 of the paged memory select register at &FE34 can be used to overlay the paged memory from &C000 to &DFFF onto the MOS so that it appears above the currently selected paged ROM. The paged memory private workspace is available in this area of paged memory. The Master uses service call &24 to give the ROMs the opportunity to request paged private workspace followed by service call &22 to claim the requested paged private workspace. The coding in figure 11.2 and 11.3 needs to be modified as shown in figures 11.4 and 11.5 if your Master SWR program needs to use paged private workspace. .service CMP #&24 \ is it service call &24? BNE try22 \ branch if not &24 INY \ request 1 page of workspace RTS \ and return .try22 CMP #&22 \ is it service call &22? BNE not22 \ branch if not &22 PHA \ push accumulator on stack TYA \ prepare to store start of workspace STA &DF0,X \ store start of workspace PLA \ restore accumulator RTS \ return to MOS .not22 Figure 11.4 Claiming paged private workspace on the Master. ------------------------------------------------------------ Claiming paged memory private workspace is a bit more involved than claiming private workspace in user memory. Your Master SWR program has to intercept service calls &24 and &22 instead of service call 2. Service calls &24 and &22 are not issued on the BBC B. Intercepting service calls &24 and &22 is illustrated in figure 11.4. If your SWR program uses paged private workspace it must use service call &22 to claim only the number of pages requested with service call &24. The amount of claimed paged private workspace must agree with the amount of requested paged private workspace. A Master SWR program must not use both service call 2 and service calls &24 and &22 to claim private workspace. You should also be aware that, if you use service calls &24 and &22 to request and claim more paged private workspace than is available in the paged memory, private workspace will be claimed from user memory starting at &E00. This has the effect of raising Oshwm and PAGE even when paged private workspace is requested and claimed. Using paged memory private workspace in the Master is a bit more complicated than claiming it. Before attempting to read or write the contents of the paged private workspace, the SWR program must first set bit 3 of the paged memory select register at &FE34 to switch the paged memory into the main memory map. To set bit 3 of &FE34 load the accumulator with &08 (0000 1000 binary), OR the accumulator with the contents of &FE34 and store the accumulator in &FE34. To switch the paged private workspace out of the main memory map it is necessary to clear bit 3 of the paged memory select register. To clear bit 3 of &FE34 load the accumulator with &F7 (1111 0111 binary), AND the accumulator with the contents of &FE34 and store the accumulator in &FE34. If you use the subroutines illustrated in figure 11.5 the paged memory can be switched in and out of the main memory map without altering any of the other bits in the paged memory select register. LDX &F4 \ load X with ROM number LDA &DF0,X \ find most sig. byte of workspace address STA &A9 \ store it for indirect addressing LDA #0 \ workspace always starts at a page boundary STA &A8 \ store least sig. byte of workspace address JSR pagein \ switch paged workspace in LDY #0 LDA (address),Y \ Read first byte of private workspace JSR pageout \ switch paged workspace out . . . .pagein PHA LDA #8 \ 0000 1000 binary TSB &FE34 \ set bit 3 of &FE34 PLA \ restore accumulator RTS .pageout PHA LDA #&8 \ 0000 1000 binary TSB &FE34 \ clear bit 3 of &FE34 PLA \ restore accumulator RTS Figure 11.5 Reading paged private workspace on the Master. ----------------------------------------------------------- Figure 11.5 illustrates how the two subroutines, pagein and pageout, should be used to switch the paged memory in and out of the main memory map when reading the contents of the paged private workspace in the Master series computers. After switching the paged memory into the main memory map you must be very careful about using MOS subroutines because the bottom 8K of the MOS has been replaced with the paged memory. You would be wise not to use the MOS at all until it has been restored by calling pageout.