view label.c @ 4:0990d9322fc8

Implement address-ranged labels. Breaks compatibility of label files.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 25 Feb 2015 04:15:07 +0200
parents ec2f8f6f1dc9
children 122134900c0e
line wrap: on
line source

/*\
 *  dxa v0.1.1 -- symbolic 65xx disassembler
 *
 *  Copyright (C) 1993, 1994 Marko M\"akel\"a
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Contacting the author:
 *
 *   Via Internet E-mail:
 *      <Marko.Makela@FTP.FUNET.FI>
 *
 *   Via Snail Mail:
 *      Marko M\"akel\"a
 *      Sillitie 10 A
 *      FIN-01480 VANTAA
 *      Finland
\*/

#define _LABEL_C_

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "proto.h"
#include "options.h"
#include "opcodes.h"

label *labeltable;
char defaultlabel[512];
unsigned numLabels = 0;


void AddLabel(ADDR_T address, char *name, int is_range, ADDR_T len)
{
  label * entry = numLabels ?
    realloc (labeltable, (numLabels + 1) * sizeof *entry) :
    malloc (sizeof *entry);

  if (!entry) return;

  labeltable = entry;
  entry = &labeltable[numLabels++];

  entry->address = address;
  entry->name = strdup(name);
  entry->is_range = is_range;
  entry->len = len;
}

int IsInsideRegion(ADDR_T address)
{
  label *entry;

  for (entry = &labeltable[numLabels]; entry-- > labeltable;)
  {
    int offs = address - entry->address;
    if (entry->is_range && offs > 0 && offs < entry->len)
      return TRUE;
  }
  return FALSE;
}


char *Label(ADDR_T address, int admode, int allow_range)
{
  label *entry;
  int match = 0;

  if (!IsLabeled (address)) {
    // dirty kludge to allow zero page stuff to still work. this sometimes
    // guesses wrong
    if (admode == zp)
      snprintf(defaultlabel, sizeof(defaultlabel), "$%02x", address);
    else
      snprintf(defaultlabel, sizeof(defaultlabel), "$%04x", address);

    return defaultlabel;
  }

  for (entry = &labeltable[numLabels]; entry-- > labeltable;)
  {
    int offs = address - entry->address;

    if (entry->address == address)
      return entry->name;

    if (entry->is_range && offs >= 0 && offs < entry->len)
    {
      match = 1;
      if (allow_range)
      {
        snprintf(defaultlabel, sizeof(defaultlabel),
          (offs < 16) ? "%s + %d" : "%s + $%x",
          entry->name, offs);
        return defaultlabel;
      }
      else
        break;
    }
  }

  if (match)
    snprintf(defaultlabel, sizeof(defaultlabel), "XXX_%x", address);
  else
    snprintf(defaultlabel, sizeof(defaultlabel), "l_%x", address);

  return defaultlabel;
}


void Collect (void)
{
  unsigned counter = 0;
  table *entry = NULL, *entry2;
  label *labels;

  if (fVerbose)
    fprintf (stderr, "%s: collecting garbage.\n", prog);

  while ((entry = entry2 = FindNextEntryType (entry, 0, 0))) {
    counter++;

    PutLabel (entry->address);
    PutLowByte (entry->address);
    PutHighByte (entry->address);

    while ((entry2 = FindNextEntry (entry2, entry->address,
                                    ~0, entry->type)))
      DeleteEntry (entry2); /* remove duplicate warnings */
  }

  if ((entry = malloc (counter * sizeof *entry))) { /* compact the table */
    entrycount = counter;

    for (entry2 = scantable; counter; entry2++) {
      if (!entry2->type) continue;

      memcpy (&entry[--counter], entry2, sizeof *entry);
    }

    free (scantable);
    scantable = entry;
  }

  for (labels = &labeltable[numLabels]; labels-- > labeltable;)
    if ((ADDR_T)(labels->address - StartAddress) <
        (ADDR_T)(EndAddress - StartAddress)) {
      PutLabel (labels->address);
      PutLowByte (labels->address);
      PutHighByte (labels->address);
    }
}