Memory locations used by the ROM
- §1. Zero page memory locations ($A8-$AF)
- §2. OS zero page memory locations
- §3. Page Three
- §4. vduWorkspaceA
- §5. Regular OS variables
- §6. GXR workspace at $0c00-$0c66
- §7. Extended Vector Table
- §8. OS routines and tables
- §9. romSelectRegister
- §10. extendedVectorTableVDUV
- §11. Regular OS entry points
§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)
.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
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
.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 }
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
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 }
.romSelectRegister = $fe30
.extendedVectorTableVDUV = $ff39
.OSFIND = $ffce .OSBGET = $ffd7 .OSARGS = $ffda .OSFILE = $ffdd .OSRDCH = $ffe0 .OSNEWL = $ffe7 .OSWRCH = $ffee .OSBYTE = $fff4