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,
      };
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It effectively describes the tool's behavior: it's a read operation (implied by 'Read'), returns interpreted/decoded register values (not raw data), and provides a high-level view. However, it doesn't mention potential limitations like performance impact or error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and concise. It starts with the core purpose, lists what's returned in a clear bulleted format, provides usage guidance, and ends with related tools. Every sentence adds value without repetition or fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read tool with no annotations or output schema, the description is quite complete. It explains what the tool does, what it returns, when to use it, and how it relates to other tools. The only minor gap is lack of explicit mention of return format (e.g., JSON structure), though the bulleted list implies it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters (schema coverage 100%), so the baseline is 4. The description appropriately doesn't discuss parameters, focusing instead on what the tool returns. This is efficient and avoids redundancy.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the tool's purpose: 'Read the full VIC-II state with interpreted values.' It specifies the exact resource (VIC-II state/registers) and verb (read), and distinguishes it from siblings by listing related tools (readScreen, readSprites, readMemory) that handle subsets of this data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage guidance: 'Use for understanding display configuration.' It explicitly lists related tools (readScreen, readSprites, readMemory) as alternatives for more specific tasks, helping the agent choose when to use this comprehensive tool versus more focused ones.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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