Memory locations used by the ROM


§1. Zero page memory locations ($A8-$AF).

 These locations are available for ROMs to use while they are running, but are not preserved
 between calls.
.tempNumberToPrintLow                       = $a8       }
.tempNumberToPrintHigh                      = $a9       } used when printing numbers
.tempNumberPrintedFlag                      = $aa       }

.gcolModeMask0                              = $a8       
.gcolModeMask1                              = $a9       
.gcolModeMask2                              = $aa       
.gcolModeMask3                              = $ab       

.currentSpriteDefinitionLow                 = $ac       
.currentSpriteDefinitionHigh                = $ad       
.seditCurrentSpriteByteLow                  = $ae       
.seditCurrentSpriteByteHigh                 = $af       

§2. OS zero page memory locations.

 These locations are owned by the OS. The GXR reads or writes them. Page 3 ($0300-$03ff) is
 where the VDU variables live: i.e. OS variables related to the graphics system.
 Locations $0328-$0349 (.vduWorkspaceA upwards) are used temporarily by the different
 graphics primitive routines.
.vduCurrentPlotByteMask                     = $d1

    The Electron has a different arrangement of zero page VDU variables
    compared to the BBC machines:
    
                                                 BBC B/B+        Electron
    .vduCurrentPlotByteMask                        $d1             $d1
    .vduGraphicsColourByteOR                       $d4             $de
    .vduGraphicsColourByteEOR                      $d5             $df
    .vduScreenAddressOfGraphicsCursorCellLow       $d6             $d4
    .vduScreenAddressOfGraphicsCursorCellHigh      $d7             $d5
    .vduTempStoreDA                                $da             $d8
    .vduTempStoreDB                                $db             $d9
    .vduTempStoreDC                                $dc             $da
    .vduTempStoreDD                                $dd             $db
    .vduTempStoreDE                                $de             $dc
    .vduTempStoreDF                                $df             $dd
    
    Unfortunately Electron temporary locations $D8 and $D9 are used to hold
    .vduWriteCursorScreenAddress{Low,High} on the BBC B/B+. This means that although the ROM
    contains code to check if it's installed on an incompatible machine, in practice an
    Electron GXR ROM installed on a BBC B/B+ will cause glitches as it scribbles over $D8
    and $D9 and the OS writes to random addresses when it thinks it's writing to the
    screen. In practice this isn't a huge problem, and it seems best not to risk accidentally
    breaking things by trying to tweak the temporary use to avoid accessing $D8 or $D9 until
    after we've successfully checked we *are* running on an Electron.
!if (MACHINE = BBC_B) | (MACHINE = BBC_B_PLUS) {
    .vduGraphicsColourByteOR                    = $d4
    .vduGraphicsColourByteEOR                   = $d5
    .vduScreenAddressOfGraphicsCursorCellLow    = $d6       } address of the top of the cell
    .vduScreenAddressOfGraphicsCursorCellHigh   = $d7       } on screen containing the
                                                            } graphics
                                                            } cursor position
    .vduTempStoreDA                             = $da       } store for temporary values,
    .vduTempStoreDB                             = $db       } used in multiple VDU related
    .vduTempStoreDC                             = $dc       } functions.
    .vduTempStoreDD                             = $dd
    .vduTempStoreDE                             = $de
    .vduTempStoreDF                             = $df
} else if (MACHINE = ELECTRON) {
    .vduGraphicsColourByteOR                    = $de
    .vduGraphicsColourByteEOR                   = $df
    .vduScreenAddressOfGraphicsCursorCellLow    = $d4       } address of the top of the cell
    .vduScreenAddressOfGraphicsCursorCellHigh   = $d5       } on screen containing the
                                                            } graphics
                                                            } cursor position

    .vduTempStoreDA                             = $d8       } store for temporary values,
    .vduTempStoreDB                             = $d9       } used in multiple VDU related
    .vduTempStoreDC                             = $da       } functions.
    .vduTempStoreDD                             = $db
    .vduTempStoreDE                             = $dc
    .vduTempStoreDF                             = $dd
} else {
    +unknown_machine
}

.osbyteA                                    = $ef       }
.oswordA                                    = $ef       } stores register values when

.osbyteX                                    = $f0       } calling .OSBYTE and OSWORD
.oswordX                                    = $f0       }

.osbyteY                                    = $f1       } stores register values when
.oswordY                                    = $f1       } calling .OSBYTE and OSWORD

.stringInputBufferAddressLow                = $f2       } Start address of input string
.stringInputBufferAddressHigh               = $f3       }

.currentlySelectedROM                       = $f4       current paged ROM selected

.privateWorkspaceLow                        = $f8       (OS does not use this location)
.privateWorkspaceHigh                       = $f9       (OS does not use this location)

.escapeFlag                                 = $ff       the ESCAPE flag
                                                        this is set when an ESCAPE character
                                                        (normally .charESCAPE) is entered
                                                        into an input buffer.
                                                        it should be acknowledged using
                                                        .OSBYTE 126. This tells the second
                                                        processor of the event and clears
                                                        the flag.

.page1Start                                 = $0100     page 1 is used for reporting errors

.vectorWRCHVLow                             = $020e     OSWRCH vector
.vectorWRCHVHigh                            = $020f     OSWRCH vector

.vectorVDUVLow                              = $0226     unrecognised PLOT / VDU 23 commands
.vectorVDUVHigh                             = $0227     unrecognised PLOT / VDU 23 commands

.lastResetType                              = $028d     what type of reset was last done?
                                                               0    Soft reset (BREAK)
                                                               1    Power on
                                                               2    Hard reset (CTRL-BREAK)

§3. Page Three.

.vduVariablesStart                          = $0300     

.vduGraphicsWindowPixelsLeftLow             = $0300     }
.vduGraphicsWindowPixelsLeftHigh            = $0301     }
.vduGraphicsWindowPixelsBottomLow           = $0302     }
.vduGraphicsWindowPixelsBottomHigh          = $0303     }
.vduGraphicsWindowPixelsRightLow            = $0304     } graphics window in pixels
.vduGraphicsWindowPixelsRightHigh           = $0305     }
.vduGraphicsWindowPixelsTopLow              = $0306     }
.vduGraphicsWindowPixelsTopHigh             = $0307     }

.vduOldGraphicsCursorPixelsXLow             = $0314     }
.vduOldGraphicsCursorPixelsXHigh            = $0315     } old graphics cursor in pixels
.vduOldGraphicsCursorPixelsYLow             = $0316     }
.vduOldGraphicsCursorPixelsYHigh            = $0317     }

.vduGraphicsCursorVerticalOffsetInCell      = $031A     offset within a character cell of
                                                        the current graphics cursor Y
                                                        coordinate

.vdu23NParameter                            = .vduQueueEndByte - 7  VDU 23,N
.vdu23SChooseOrSGetSpriteNumberParameter    = .vduQueueEndByte - 6  VDU 23,27,N

.vdu25ParameterPlotType                     = .vduQueueEndByte - 4
.vdu25ParameterXLow                         = .vduQueueEndByte - 3
.vdu25ParameterXHigh                        = .vduQueueEndByte - 2
.vdu25ParameterYLow                         = .vduQueueEndByte - 1
.vdu25ParameterYHigh                        = .vduQueueEndByte

.vduQueueEndByte                            = $0323     } nine bytes for vdu queue (end)

.vduGraphicsCursorPixelsXLow                = $0324     current graphics cursor position in
.vduGraphicsCursorPixelsXHigh               = $0325     pixels
.vduGraphicsCursorPixelsYLow                = $0326     
.vduGraphicsCursorPixelsYHigh               = $0327     

§4. vduWorkspaceA.

 VDU variables used by the GXR ROM for general workspace use when plotting or sprite editing.
 We give more helpful names to these workspace variables for specific routines.
.vduWorkspaceA                              = $0328     
.vduWorkspaceB                              = $0329     
.vduWorkspaceC                              = $032A     
.vduWorkspaceD                              = $032B     
.vduWorkspaceE                              = $032C     
.vduWorkspaceF                              = $032D     
.vduWorkspaceG                              = $032E     
.vduWorkspaceH                              = $032F     
.vduWorkspaceI                              = $0330     
.vduWorkspaceJ                              = $0331     
.vduWorkspaceK                              = $0332     
.vduWorkspaceL                              = $0333     
.vduWorkspaceM                              = $0334     
.vduWorkspaceN                              = $0335     
.vduWorkspaceO                              = $0336     
.vduWorkspaceP                              = $0337     
.vduWorkspaceQ                              = $0338     
.vduWorkspaceR                              = $0339     
.vduWorkspaceS                              = $033A     
.vduWorkspaceT                              = $033B     
.vduWorkspaceU                              = $033C     
.vduWorkspaceV                              = $033D     
.vduWorkspaceW                              = $033E     
.vduWorkspaceX                              = $033F     
.vduWorkspaceY                              = $0340     
.vduWorkspaceZ                              = $0341     
.vduWorkspaceAA                             = $0342     
.vduWorkspaceBB                             = $0343     
.vduWorkspaceCC                             = $0344     
.vduWorkspaceDD                             = $0345     

***** Line drawing/tracking variables *****
.line1StartPointX                           = $0328     initial and current point X [2 bytes]
.line1StartPointY                           = $032a     initial and current point Y [2 bytes]
.line1AbsDeltaX                             = $032c     abs(deltaX)                 [2 bytes]
.line1AbsDeltaY                             = $032e     abs(deltaY)                 [2 bytes]
.line1ErrorTerm                             = $0330     Bresenham error term        [2 bytes]
.line1Signs                                 = $0332     signs of deltaY (top bit) and deltaX
                                                        (bit 6) [1 byte]

.line2StartPointX                           = $0334     initial and current point X [2 bytes]
.line2StartPointY                           = $0336     initial and current point Y [2 bytes]
.line2AbsDeltaX                             = $0338     abs(deltaX)                 [2 bytes]
.line2AbsDeltaY                             = $033a     abs(deltaY)                 [2 bytes]
.line2ErrorTerm                             = $033c     Bresenham error term        [2 bytes]
.line2Signs                                 = $033e     signs of deltaY (top bit) and deltaX
                                                        (bit 6) [1 byte]

.line3StartPointX                           = $033f     initial and current point X [2 bytes]
.line3StartPointY                           = $0341     initial and current point Y [2 bytes]
.line3AbsDeltaX                             = $0343     abs(deltaX)                 [2 bytes]
.line3AbsDeltaY                             = $0345     abs(deltaY)                 [2 bytes]
.line3ErrorTerm                             = $0347     Bresenham error term        [2 bytes]
.line3Signs                                 = $0349     signs of deltaY (top bit) and deltaX
                                                        (bit 6) [1 byte]

***** Triangle drawing variables *****
.triangleRowLeftPointX                      = $032c     }
.triangleRowLeftPointY                      = $032e     } the current row has a leftmost
.triangleRowRightPointX                     = $0330     } and rightmost pixel to fill
.triangleRowRightPointY                     = $0332     }

***** Circle drawing variables *****
.circlePointLeftXLow                        = $032c     }
.circlePointLeftXHigh                       = $032d     }
.circlePointLeftYLow                        = $032e     }
.circlePointLeftYHigh                       = $032f     } the current row has a leftmost
.circlePointRightXLow                       = $0330     } and a rightmost point to fill
.circlePointRightXHigh                      = $0331     }
.circlePointRightYLow                       = $0332     }
.circlePointRightYHigh                      = $0333     }

***** Move/copy rectangle variables *****
.rectSourceLeft                             = $0328     left   edge of src rect [2 bytes]
.rectSourceBottom                           = $032a     bottom edge of src rect [2 bytes]
.rectSourceRight                            = $032c     right  edge of src rect [2 bytes]
.rectSourceTop                              = $032e     top    edge of src rect [2 bytes]

.rectDestinationLeft                        = $0334     left   edge of dest rect [2 bytes]
.rectDestinationBottom                      = $0336     bottom edge of dest rect [2 bytes]
.rectDestinationRight                       = $0338     right  edge of dest rect [2 bytes]
.rectDestinationTop                         = $033a     top    edge of dest rect [2 bytes]

.rectCopyShiftToNextByte                    = $0342     
.rectCopyNumberOfTimesToShiftByte           = $0343     number of times to shift right each
                                                        byte when copying/moving
.rectCopyByteWidth                          = $0344     width in bytes of area to copy / move
.rectCopyPlotType                           = $0345     
.rectCopyByteMask                           = $0346     byte mask for writing the
                                                        initial/final byte of a row
.rectCopyShiftingLeftFlag                   = $0347     top bit set means we are shifting
                                                        pixels left within each byte

***** Sprite editing variables *****
.seditCurrentVisibleX                       = $033C     X offset within the visible area
                                                        of the current cursor
.seditCurrentVisibleY                       = $033D     Y offset within visible area of
                                                        the current cursor
.seditCurrentVisibleByteMask                = $033E     a bitmask for the current pixel
                                                        within the current sprite byte
.seditCurrentX                              = $033F     left pixel coordinate of large sprite
.seditCurrentSpriteVisibleWidth             = $0340     width of visible area of sprite (in
                                                        sprite pixels)
.seditCurrentY                              = $0341     bottom pixel coordinate of large
                                                        sprite
.seditCurrentSpriteVisibleHeight            = $0342     height of visible area of sprite (in
                                                        sprite pixels)
.seditScreenXOffsetWithinCurrentByte        = $0343     Screen X offset within the current
                                                        sprite byte scaled up to screen
                                                        coordinates for the large sprite.
                                                        (in increments of
                                                        '.seditXCoordinateIncrement')

.plotPointXLow                              = $0344     }
.plotPointXHigh                             = $0345     } screen coordinates when PLOTting
.plotPointYLow                              = $0346     } (e.g. in the sprite editor)
.plotPointYHigh                             = $0347     }

.seditBackgroundColour                      = $0348     

***** Ellipse variables *****
.ellipse256AspectRatioLow                   = $0328     
.ellipse256AspectRatioMid                   = $0329     256 * (height / centre row width)
.ellipse256AspectRatioHigh                  = $032a     

.ellipse256ShearLow                         = $032b     
.ellipse256ShearMid                         = $032c     256 * abs(top X - centre X)
.ellipse256ShearHigh                        = $032d     

.ellipseHalfHeightCounterLow                = $032e     half the height of the ellipse
.ellipseHalfHeightCounterHigh               = $032f     

.ellipseHalfHeightSquaredLow                = $0330     
.ellipseHalfHeightSquaredMid1               = $0331     (half the height) squared
.ellipseHalfHeightSquaredMid2               = $0332     
.ellipseHalfHeightSquaredHigh               = $0333     

.ellipsePointCLow                           = $0334     
.ellipsePointCHigh                          = $0335     
.ellipsePointDLow                           = $0336     
.ellipsePointDHigh                          = $0337     

.ellipseLeftPointLow                        = $0338     
.ellipseLeftPointHigh                       = $0339     

.ellipseRightPointLow                       = $033a     
.ellipseRightPointHigh                      = $033b     

.ellipsePointALow                           = $033c     
.ellipsePointAHigh                          = $033d     
.ellipsePointBLow                           = $033e     
.ellipsePointBHigh                          = $033f     

.ellipsePointELow                           = $0340     
.ellipsePointEHigh                          = $0341     

.ellipseCurrentOffsetXLow                   = $0342     
.ellipseCurrentOffsetXHigh                  = $0343     

.ellipsePointFLow                           = $0344     
.ellipsePointFHigh                          = $0345     

§5. Regular OS variables.

.vduBytesPerCharacterRowLow                 = $0352     
.vduBytesPerCharacterRowHigh                = $0353     
.vduScreenSizeHighByte                      = $0354     
.vduCurrentScreenMODE                       = $0355     

.vduForegroundGraphicsColour                = $0359     } byte the given colour
.vduBackgroundGraphicsColour                = $035A     }
.vduForegroundGCOLMode                      = $035B     GCOL foreground mode
                                                        (0=Normal, 1=OR, 2=AND, 3=EOR,
                                                        4=Invert)
.vduBackgroundGCOLMode                      = $035C     GCOL background mode
                                                        (0=Normal, 1=OR, 2=AND, 3=EOR,
                                                        4=Invert)
.vduJumpVectorLow                           = $035D     
.vduJumpVectorHigh                          = $035E     

.vduNumberOfLogicalColoursMinusOne          = $0360     
.vduPixelsPerByteMinusOne                   = $0361     

.vduColourMaskLeft                          = $0362     colour mask left.  Bits for the
                                                        setting the leftmost pixel of a
                                                        byte to white:
                                                        MODE 0,3,4,6,7    = $80
                                                        MODE 1,5          = $88
                                                        MODE 2            = $AA
.vduColourMaskRight                         = $0363     colour mask right. Bits for the
                                                        setting the rightmost pixel of a
                                                        byte to white:
                                                        MODE 0,3,4,6,7    = $01
                                                        MODE 1,5          = $11
                                                        MODE 2            = $55

§6. GXR workspace at $0c00-$0c66.

 Page C normally holds soft character definitions for chars 224-255 but for the duration of
 a PLOT command the range $0c00-$0c66 is cached in private workspace. Thus we can use the
 start of page C as workspace, detailed below.
.softCharacterDefinitions                   = $0c00     
.fillPattern                                = $0c00     current fill pattern [8 bytes]
.currentDotDashPattern                      = $0c08     current dot-dash pattern [8 bytes]

.currentDotDashPatternBitLength             = $0c10

Temporary current dot-dash line state [3 bytes]
.currentDotDashPatternNumBitsRemaining      = $0c11
.currentDotDashPatternBitMask               = $0c12
.currentDotDashPatternByte                  = $0c13

.gxrScratchspace1                           = $0c14
.gxrScratchspace2                           = $0c15
.gxrScratchspace3                           = $0c16

$0c17 onwards holds temporary variables that are not remembered between calls to the ROM.
They are used for multiple purposes, so have different names with the same addresses.
.gxrCurrentPattern                          = $0c17     current fill pattern [8 bytes]
.rectCopyRowCache                           = $0c17     the current row data stored during
                                                        a rectangle copy ($0c17-$0c66)
                                                        [80 bytes]

General purpose temporary variables e.g. Used when sorting vertices for triangle or
parallelogram
.gxrTemp1                                   = $0c17
.gxrTemp2                                   = $0c18
.gxrTemp3                                   = $0c19
.gxrTemp4                                   = $0c1a
.gxrTemp5                                   = $0c1b
.gxrTemp6                                   = $0c1c
.gxrTemp7                                   = $0c1d

***** For multiply *****
.multiplicand0                              = $0c17
.multiplicand1                              = $0c18
.multiplicand2                              = $0c19

.multiplier0                                = $0c1a
.multiplier1                                = $0c1b
.multiplier2                                = $0c1c

.product0                                   = $0c1a
.product1                                   = $0c1b
.product2                                   = $0c1c
.product3                                   = $0c1d
.product4                                   = $0c1e
.product5                                   = $0c1f

***** For square root *****
.sqrtResult0                                = $0c17
.sqrtResult1                                = $0c18
.sqrtResult2                                = $0c19

.sqrtNumber0                                = $0c1a     }
.sqrtNumber1                                = $0c1b     }
.sqrtNumber2                                = $0c1c     } 48 bit number to sqrt
.sqrtNumber3                                = $0c1d     }
.sqrtNumber4                                = $0c1e     }
.sqrtNumber5                                = $0c1f     }

.sqrtRemainder0                             = $0c20
.sqrtRemainder1                             = $0c21
.sqrtRemainder2                             = $0c22
.sqrtRemainder3                             = $0c23

.sqrtTemp0                                  = $0c24
.sqrtTemp1                                  = $0c25
.sqrtTemp2                                  = $0c26
.sqrtTemp3                                  = $0c27

$0c28-$0c2b [4 bytes] are not used

***** For division *****
.dividend0                                  = $0c2c
.dividend1                                  = $0c2d
.dividend2                                  = $0c2e

.divisor0                                   = $0c2f
.divisor1                                   = $0c30
.divisor2                                   = $0c31

.quotient0                                  = $0c32     24 bit quotient for divide
.quotient1                                  = $0c33     24 bit quotient for divide
.quotient2                                  = $0c34     24 bit quotient for divide

.divideTemp0                                = $0c35     temporary value during divide
.divideTemp1                                = $0c36     
.divideTemp2                                = $0c37     

***** For circle drawing *****
.circleTrackingLeftmostChordPoint           = $0c2c     index of the leftmost chord
                                                        point, or zero if we are not
                                                        tracking the chord
.circleTrackingSecondLineInQuadrant         = $0c2d     index of the second line in the
                                                        quadrant, or zero if we are not
                                                        tracking
.circleRadialLine                           = $0c2e     another temporary line index
.circleTrackingRightmostChordPoint          = $0c2f     index of the rightmost chord
                                                        point, or zero if we are not
                                                        tracking the chord

.circlePointXLow                            = $0c30     
.circlePointXHigh                           = $0c31     

.circlePointYLow                            = $0c32     
.circlePointYHigh                           = $0c33     
.circleFillRowFlag                          = $0c34     set if we are on a new row to be
                                                        plotted, clear if just updating
                                                        position this time around the loop
.circlePixelShapeCurrentOffset              = $0c35     tracks offset within current pixel
                                                        shape when drawing circle (for
                                                        double width / height)


.circlePixelShapeForCurrentMODE             = $0c36     pixel shape:
                                                          bit 0 set = double width (MODE 2,5)
                                                          bit 1 set = half width   (MODE 0)

.circleSlopeTestLow                         = $0c37     
.circleSlopeTestMid1                        = $0c38     
.circleSlopeTestMid2                        = $0c39     
.circleSlopeTestHigh                        = $0c3a     

.circleRadiusSquaredLow                     = $0c37     
.circleRadiusSquaredMid1                    = $0c38     
.circleRadiusSquaredMid2                    = $0c39     
.circleRadiusSquaredHigh                    = $0c3a     

.circleDiameterCountdownLow                 = $0c3d     } counts down from (diameter-1) in
                                                        } steps of two
.circleDiameterCountdownHigh                = $0c3e     }

.circleDecisionLow                          = $0c3f     } decision variable used in circle
                                                        } algorithm
.circleDecisionHigh                         = $0c40     }

.circleCountOddNumbersLow                   = $0c41     } counts up from one in steps of two
.circleCountOddNumbersHigh                  = $0c42     }

.circleChordLine                            = $0c43     offset of chord line variables from
                                                        .vduVariablesStart

.circleLine2Quadrant                        = $0c48
.circleLine3Quadrant                        = $0c49
.circleChordDestinationPoint                = $0c4a     end point of chord line
.circleQuadrants                            = $0c4b     [4 bytes] See
                                                        
                                                        .circleDoLineAndQuadrantInitialisation
.circleSecondaryLine                        = $0c4f     if one line is in the quadrant, this
                                                        is the other line that may not be in
                                                        the quadrant
.circleCurrentQuadrant                      = $0c50     current quadrant
.circleQuadrantDataShifter                  = $0c51     how many times to shift the quadrant
                                                        data when starting to track the chord
.circleFlag                                 = $0c52

***** For ellipse drawing *****
.ellipseSignFlag                            = $0c38     sign for shear

.ellipseAccumulatedShearLow                 = $0c39     adds the shear value each row.
.ellipseAccumulatedShearMid                 = $0c3a     
.ellipseAccumulatedShearHigh                = $0c3b     

.ellipseCountOddNumbersLow                  = $0c3c     counts the odd numbers from 1
.ellipseCountOddNumbersMid1                 = $0c3d     
.ellipseCountOddNumbersMid2                 = $0c3e     
.ellipseCountOddNumbersHigh                 = $0c3f     

.ellipseCountSquaresLow                     = $0c40     counts up in square numbers by
.ellipseCountSquaresMid1                    = $0c41     adding next the odd number in
.ellipseCountSquaresMid2                    = $0c42     sequence from 1.
.ellipseCountSquaresHigh                    = $0c43     

.ellipseCountHeightLow                      = $0c44     loop counter
.ellipseCountHeightHigh                     = $0c45     

.ellipseTempA                               = $0c44     }
.ellipseTempB                               = $0c45     } temporary variables while drawing
.ellipseTempY                               = $0c46     } ellipse
.ellipseTempX                               = $0c47     }

§7. Extended Vector Table.

 To redirect the VDU vector to this GXR ROM we use the extended vector table (See NAUG p312)
.extendedVDUVLow                            = $0dd8     }
.extendedVDUVHigh                           = $0dd9     } Extended vector table
.extendedVDUVROM                            = $0dda     }

This memory is a table indexed by ROM number. Each ROM gets one byte to store information.
We usually store the page number of the private workspace. During a reset, it stores 1
to indicate the GXR is becoming active, or 0 for inactive.
.romWorkspaceBytes                          = $0df0     ROM workspace bytes

§8. OS routines and tables.

 This ROM calls directly into the OS to perform functions, and also reads OS ROM based
 tables. Each machine has a different set of addresses.
!if (MACHINE = BBC_B) {
    .sixteenColourMODEMaskTable                         = $c407
    .gcolPlotOptionsTable                               = $c41c
    .twoColourMODEParameterTable                        = $c424
    .vdu22EntryPoint                                    = $c8eb
    .vdu25EntryPoint                                    = $c98c

    OS routine to swap two bytes in VDU variables (e.g. one 16 bit coordinate)
    On Entry:
          X is the offset to the first variable
          Y is the offset to the second variable
    .exchangeTwoVDUBytes                                = $cdde

    OS routine to plot a single point
    Given the current screen address details, renders the pixel by writing to the screen
    address, applying the colour masks and plot type.
    On Entry:
          Y is the vertical offset within the current cell
    .plotPointWithinBoundsAtY                           = $d0f3

    OS routine to check that the graphics point given by offset X is within the graphics
    window
    On Entry:
      X: offset to the point to check ('gpoint')
    On Exit:
      .vduTempStoreDA is zero if the gpoint is within the graphics window, or the four low
    bits
                   indicate which regions failed:
    
          %0000   success (gpoint is within window)
          %0001   gpoint X is left of  the left   edge of the graphics window
          %0010   gpoint X is right of the right  edge of the graphics window
          %0100   gpoint Y is below    the bottom edge of the graphics window
          %1000   gpoint Y is above    the top    edge of the graphics window
    .checkPointXIsWithinGraphicsWindow                  = $d10f

    OS routine to check coordinate of a point is in the window bounds (horizontal or
    vertical)
    On Entry:
          X is the offset to the coordinate to check minus two bytes
          Y is the offset to the second variable to check (0 for horizontal or 2 for
    vertical)
    On Exit:
          .vduTempStoreDA is the error code (0 = no error, 1 = first check failed, 2 =
    second check
          failed)
          Zero flag set if no error
    .checkPointIsWithinWindowHorizontalOrVertical       = $d128

    OS routine to convert external relative coordinates to pixels
    Convert pair of external coordinates to pixels (horizontal and vertical)
    On Entry:
          X is the offset in vdu variables to the coordinate to convert
    .plotConvertExternalRelativeCoordinatesToPixels     = $d14d

    Move graphics cursor up a cell
    .moveGraphicsCursorAddressUpOneCharacterCell        = $d3d3

    OS routine to update the mask value, and move graphics cursor address on to next cell to
    the right
    On Entry:
          Carry always SET
    .moveGraphicsCursorAddressTotheRightAndUpdateMask   = $d3ed

    OS routine to move the graphics cursor address on to next cell to the right
    On Entry:
          Carry always SET
    .moveGraphicsCursorAddressTotheRight                = $d3f2

    OS routine to update the mask value, and move graphics cursor address on to previous
    cell to the left
    On Entry:
          Carry always SET
    .moveGraphicsCursorAddressTotheLeftAndUpdateMask    = $d3fd

    OS routine to copy eight bytes (four coordinates) of VDU variables
    On Entry:
          X = source (offset from .vduVariablesStart)
          Y = destination (offset from .vduVariablesStart)
    .copyEightBytesWithinVDUVariables                   = $d47c

    OS routine to copy two bytes (one coordinate) of VDU variables
    On Entry:
          X = source (offset from .vduVariablesStart)
          Y = destination (offset from .vduVariablesStart)
    .copyTwoBytesWithinVDUVariables                     = $d482

    OS routine to copy four bytes of VDU variables
    On Entry:
          X = source (offset from .vduVariablesStart)
          Y = destination (offset from .vduVariablesStart)
    .copyFourBytesWithinVDUVariables                    = $d48a

    OS routine to fill a single horizontal row of pixels
    Used as part of clearing the graphics window or filling a triangle.
    On Entry:
          X = offset into VDU variables for one extreme graphics pixel X coordinate
          Y = offset into VDU variables for the other extreme graphics pixel X coordinate
    .fillRow                                            = $d6a6

    OS routine to set screen address
    On Entry:
          X is the vdu variables offset to the graphics point to check
    On Exit:
          .vduScreenAddressOfGraphicsCursorCellLow/High is the screen address
          Y is the vertical offset within the character cell (0-7)
          Preserves X
    .setScreenAddress                                   = $d864
} else if (MACHINE = BBC_B_PLUS) {
    .sixteenColourMODEMaskTable                         = $c3fe
    .gcolPlotOptionsTable                               = $c413
    .twoColourMODEParameterTable                        = $c41b
    .vdu25EntryPoint                                    = $c939
    .vdu22EntryPoint                                    = $caee
    .exchangeTwoVDUBytes                                = $cda6
    .plotPointWithinBoundsAtY                           = $d0bf
    .checkPointXIsWithinGraphicsWindow                  = $ca79
    .checkPointIsWithinWindowHorizontalOrVertical       = $d0d9
    .plotConvertExternalRelativeCoordinatesToPixels     = $d0fe
    .moveGraphicsCursorAddressUpOneCharacterCell        = $d34b
    .moveGraphicsCursorAddressTotheRightAndUpdateMask   = $d365
    .moveGraphicsCursorAddressTotheRight                = $d36a
    .moveGraphicsCursorAddressTotheLeftAndUpdateMask    = $d375
    .copyEightBytesWithinVDUVariables                   = $d3f4
    .copyTwoBytesWithinVDUVariables                     = $d3fb
    .copyFourBytesWithinVDUVariables                    = $d403
    .fillRow                                            = $d62e
    .setScreenAddress                                   = $d7ed

    For the B+ we need to execute LDA (.vduScreenAddressOfGraphicsCursorCellLow),Y
                              and STA (.vduScreenAddressOfGraphicsCursorCellLow),Y
    from within the OS address space in order to access main or shadow RAM as appropriate.
    There isn't a bare LDA (.vduScreenAddressOfGraphicsCursorCellLow),Y:RTS we can use, so
    we do the best we can, which requires a bit of fiddling around in the GXR code compared
    to the model B case.
    .plotFast                                           = $d0cd write byte to screen
    .plotByte                                           = $d0d0 write byte to screen with
                                                                GCOL mode
    .checkPixelIsBackgroundColourFast                   = $d427 read byte from screen

    For reference, here is the relevant code from the B+ OS ROM:
    
          .plotFast
    d0cd      STA (.vduScreenAddressOfGraphicsCursorCellLow),Y    ; put it back again
    d0cf      RTS                                                 ;
    
          .plotByte
    d0d0      LDA (.vduScreenAddressOfGraphicsCursorCellLow),Y    ;
    d0d2      ORA .vduGraphicsColourByteOR                        ;
    d0d4      EOR .vduGraphicsColourByteEOR                       ;
    d0d6      STA (.vduScreenAddressOfGraphicsCursorCellLow),Y    ;
    d0d8      RTS                                                 ;
    ...
          .checkPixelIsBackgroundColourFast
    d427      LDA (.vduScreenAddressOfGraphicsCursorCellLow),Y    ; get byte from current
    graphics
    d429      EOR .vduBackgroundGraphicsColour                    ; cell, compare with
    current
    d42c      STA .vduTempStoreDA                                 ; background colour and
    store it
    d42e      RTS                                                 ;

} else if (MACHINE = ELECTRON) {
    .sixteenColourMODEMaskTable                         = $c3c2
    .gcolPlotOptionsTable                               = $c3d7
    .twoColourMODEParameterTable                        = $c3df
    .vdu25EntryPoint                                    = $c986
    .vdu22EntryPoint                                    = $c8ec
    .exchangeTwoVDUBytes                                = $cd1a
    .plotPointWithinBoundsAtY                           = $d004
    .checkPointXIsWithinGraphicsWindow                  = $d020
    .checkPointIsWithinWindowHorizontalOrVertical       = $d039
    .plotConvertExternalRelativeCoordinatesToPixels     = $d05e
    .moveGraphicsCursorAddressUpOneCharacterCell        = $d2ea
    .moveGraphicsCursorAddressTotheRightAndUpdateMask   = $d304
    .moveGraphicsCursorAddressTotheRight                = $d309
    .moveGraphicsCursorAddressTotheLeftAndUpdateMask    = $d314
    .copyEightBytesWithinVDUVariables                   = $d393
    .copyTwoBytesWithinVDUVariables                     = $d399
    .copyFourBytesWithinVDUVariables                    = $d3a1
    .fillRow                                            = $d5bc
    .setScreenAddress                                   = $d77a
    .selectRom                                          = $e3a0
} else {
    +unknown_machine
}

§9. romSelectRegister.

.romSelectRegister                          = $fe30

§10. extendedVectorTableVDUV.

.extendedVectorTableVDUV                    = $ff39

§11. Regular OS entry points.

.OSFIND                                     = $ffce
.OSBGET                                     = $ffd7
.OSARGS                                     = $ffda
.OSFILE                                     = $ffdd
.OSRDCH                                     = $ffe0
.OSNEWL                                     = $ffe7
.OSWRCH                                     = $ffee
.OSBYTE                                     = $fff4