Skip to main content
Glama
simen

VICE C64 Emulator MCP Server

by simen

readVicState

Retrieve and interpret VIC-II video chip state to understand Commodore 64 display configuration, including colors, graphics modes, memory locations, and raster position.

Instructions

Read the full VIC-II state with interpreted values.

Returns all VIC-II registers with semantic meaning:

  • Border and background colors (with names)

  • Graphics mode (text, bitmap, multicolor, etc.)

  • Screen and character memory locations

  • Scroll values

  • Raster position

  • Sprite enable bits

This is the high-level view of the video chip. Use for understanding display configuration.

Related tools: readScreen, readSprites, readMemory (for $D000-$D02E)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The core handler function for the 'readVicState' tool. Registers the tool with MCP server and implements the logic: reads VIC-II registers, computes bank/video addresses, graphics mode, sprite visibility, formats colors, and returns structured state with hints.
    server.registerTool(
      "readVicState",
      {
        description: `Read the full VIC-II state with interpreted values.
    
    Returns all VIC-II registers with semantic meaning:
    - Border and background colors (with names)
    - Graphics mode (text, bitmap, multicolor, etc.)
    - Screen and character memory locations
    - Scroll values
    - Raster position
    - Sprite enable bits
    
    This is the high-level view of the video chip. Use for understanding display configuration.
    
    Related tools: readScreen, readSprites, readMemory (for $D000-$D02E)`,
      },
      async () => {
        try {
          // Read all VIC registers $D000-$D02E (47 bytes)
          const vicData = await client.readMemory(0xd000, 0xd02e);
    
          // Read CIA2 for bank info
          const cia2Data = await client.readMemory(0xdd00, 0xdd00);
          const bankInfo = getVicBank(cia2Data[0]);
    
          const d011 = vicData[0x11];
          const d016 = vicData[0x16];
          const d018 = vicData[0x18];
    
          const graphicsMode = getGraphicsMode(d011, d016);
          const videoAddrs = getVideoAddresses(d018, bankInfo.baseAddress);
    
          // Raster position (9-bit)
          const rasterLine = vicData[0x12] | ((d011 & 0x80) << 1);
    
          // Sprite enable and visibility check
          const spriteEnable = vicData[0x15];
          const spriteXMsb = vicData[0x10];
          const enabledSprites: number[] = [];
          const visibleSprites: number[] = [];
    
          for (let i = 0; i < 8; i++) {
            if (spriteEnable & (1 << i)) {
              enabledSprites.push(i);
              // Check visibility
              const xLow = vicData[i * 2];
              const xHigh = (spriteXMsb & (1 << i)) ? 256 : 0;
              const x = xLow + xHigh;
              const y = vicData[i * 2 + 1];
              const visibility = isSpriteVisible(x, y, true);
              if (visibility.visible) {
                visibleSprites.push(i);
              }
            }
          }
    
          // Display enable
          const displayEnabled = !!(d011 & 0x10);
    
          const response = {
            // Colors
            borderColor: getColorInfo(vicData[0x20]),
            backgroundColor: [
              getColorInfo(vicData[0x21]),
              getColorInfo(vicData[0x22]),
              getColorInfo(vicData[0x23]),
              getColorInfo(vicData[0x24]),
            ],
    
            // Graphics mode
            graphicsMode: graphicsMode.mode,
            displayEnabled,
            bitmap: graphicsMode.bitmap,
            multicolor: graphicsMode.multicolor,
            extendedColor: graphicsMode.extendedColor,
    
            // Screen geometry
            rows: d011 & 0x08 ? 25 : 24,
            columns: d016 & 0x08 ? 40 : 38,
            scrollX: d016 & 0x07,
            scrollY: d011 & 0x07,
    
            // Memory setup
            vicBank: {
              bank: bankInfo.bank,
              baseAddress: {
                value: bankInfo.baseAddress,
                hex: `$${bankInfo.baseAddress.toString(16).padStart(4, "0")}`,
              },
            },
            screenAddress: {
              value: videoAddrs.screenAddress,
              hex: `$${videoAddrs.screenAddress.toString(16).padStart(4, "0")}`,
            },
            charAddress: {
              value: videoAddrs.charAddress,
              hex: `$${videoAddrs.charAddress.toString(16).padStart(4, "0")}`,
            },
    
            // Raster
            rasterLine,
    
            // Sprites summary
            spriteEnable: {
              value: spriteEnable,
              binary: spriteEnable.toString(2).padStart(8, "0"),
              enabledSprites,
              enabledCount: enabledSprites.length,
              visibleSprites,
              visibleCount: visibleSprites.length,
            },
    
            // Sprite multicolor registers
            spriteMulticolor0: getColorInfo(vicData[0x25]),
            spriteMulticolor1: getColorInfo(vicData[0x26]),
    
            hint: !displayEnabled
              ? "Display is blanked (DEN=0) - screen shows border color only"
              : enabledSprites.length > 0
              ? visibleSprites.length < enabledSprites.length
                ? `${graphicsMode.mode} mode, ${enabledSprites.length} sprite(s) enabled but only ${visibleSprites.length} visible. Use readSprites() for details.`
                : `${graphicsMode.mode} mode, ${enabledSprites.length} sprite(s) enabled and visible.`
              : `${graphicsMode.mode} mode, no sprites enabled.`,
          };
    
          return formatResponse(response);
        } catch (error) {
          return formatError(error as ViceError);
        }
      }
    );
  • Key helper used by readVicState to parse VIC-II graphics mode from D011 and D016 registers.
    export function getGraphicsMode(d011: number, d016: number): {
      mode: string;
      bitmap: boolean;
      multicolor: boolean;
      extendedColor: boolean;
    } {
      const ecm = !!(d011 & 0x40);
      const bmm = !!(d011 & 0x20);
      const mcm = !!(d016 & 0x10);
    
      let mode = "standard text";
      if (ecm && !bmm && !mcm) mode = "extended background color";
      else if (!ecm && !bmm && mcm) mode = "multicolor text";
      else if (!ecm && bmm && !mcm) mode = "standard bitmap";
      else if (!ecm && bmm && mcm) mode = "multicolor bitmap";
      else if (ecm) mode = "invalid (ECM + other modes)";
    
      return {
        mode,
        bitmap: bmm,
        multicolor: mcm,
        extendedColor: ecm,
      };
    }
  • Helper to compute VIC-II memory bank from CIA2 $DD00 port A value, used in readVicState.
    export function getVicBank(cia2PortA: number): { bank: number; baseAddress: number } {
      // CIA2 port A bits 0-1 (inverted) select the bank
      const bankBits = (~cia2PortA) & 0x03;
      return {
        bank: bankBits,
        baseAddress: bankBits * 0x4000,
      };
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/simen/vice-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server