Global control block

From BeebWiki
Revision as of 21:24, 3 July 2016 by Jgharston (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

When calling MOS functions from BASIC you often need to pass a control block pointed to by X% and Y%. A common method of doing this is to use code similar to:

     DIM ctrl% 31
     :
     DEFPROCgbpb(in%,addr%,num%)
     LOCAL A%,X%,Y%
     ?ctrl%=in%
     ctrl%!1=addr%
     ctrl%!5=num%
     X%=ctrl% AND 255
     Y%=ctrl% DIV 256
     A%=2
     CALL &FFD1
     ENDPROC

Doing this involves setting X% and Y% every time a MOS routine is called. A neater and more compact method is to use X% to point to the control block instead of the control block name itself:

     DIM ctrl% 31:X%=ctrl%:Y%=X% DIV 256
     :
     ?X%=in%
     X%!1=addr%
     X%!5=num%
     A%=2:CALL &FFF1

This has several advantages. It removes all the repetitions of X%=ctrl% AND 255:Y%=ctrl% DIV 256 and LOCAL X%,Y% inside procedure and functions; and indexing into the control block with X% is more compact and neater. Additionally, with X% holding the whole address of the control block, and not just the bottom 8 bits, ensures that when running versions of BASIC with more than 64K of memory (such as 32016, ARM, 80x86) the control block is passed to the MOS call wherever it is in memory, not just in the first 64K of memory. (If X% is less than 256, BBC BASIC V looks for higher-order parts of the address in Y%, for compatibility with the usual expressions.)

X% and Y% should be set at the start of the program and at the start of any main program loop. Otherwise, any calls to OSBYTE may overwrite the values in X% and Y% if an error occurs. Use code constructed similar to the following:

     DIM ctrl% 31:X%=ctrl%:Y%=X%DIV256
     ON ERROR IF FNerr:PROCexit(ERR):END
     REPEAT:X%=ctrl%:Y%=X%DIV256

All the BASIC libraries at mdfs.net expect X% and Y% to point to a global control block in this way.

By JGH, Jun-2007