<commit_before>/**
 * @file Cosa/Board/ITEADStudio/Iboard.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_BOARD_ITEADSTUDIO_IBOARD_HH
#define COSA_BOARD_ITEADSTUDIO_IBOARD_HH

/* This board is based on ATmega328P */
#define BOARD_ATMEGA328P

/**
 * Compiler warning on unused varable.
 */
#if !defined(UNUSED)
#define UNUSED(x) (void) (x)
#endif

/**
 * Cosa pin symbol and hardware definitions for the ATmega328P based
 * board ITEAD Studio IBoard. Cosa does not use pin numbers as
 * Arduino/Wiring, instead strong data type is used (enum types) for
 * the specific pin classes; DigitalPin, AnalogPin, PWMPin, etc.
 *
 * The pin numbers for ATmega328P are mapped as in Arduino. The static
 * inline functions, SFR, BIT and UART, rely on compiler optimizations
 * to be reduced.
 *
 * @section Board
 * @code
 *                       ITEAD Studio Iboard
 *                  -----              --------
 *                +-|(o)|--------------| RJ45 |--+
 *                | |   |              |      |  |
 *                | -----              |      |  |
 *                |                    --------  |
 *                |                              |
 *                |                              |
 *                |                              |
 *                |                              |
 *                |                              |
 *                |                              |
 *                |ISP                 SD        |
 *                |[][]                +--------+|
 *                |[][]                |        /|
 *                |[][]*               |       | |
 *                |                    |       | |
 *         D14/A0 |[][][]              |        \|
 *         D15/A1 |[][][]              +--------+|
 *         D16/A2 |[][][]                        |
 *         D17/A3 |[][][]                        |
 *     SDA/D18/A4 |[][][]                        |
 *     SCL/D19/A5 |[][][]                        |
 *             A6 |[][][]                        |
 *             A7 |[][][]                        |
 *                +------------------------------+
 * @endcode
 */
class Board {
  friend class Pin;
  friend class UART;
private:
  /**
   * Do not allow instances. This is a static singleton; name space.
   */
  Board() {}

  /**
   * Return Special Function Register for given Arduino pin number.
   * @param[in] pin number.
   * @return special register pointer.
   */
  static volatile uint8_t* SFR(uint8_t pin)
    __attribute__((always_inline))
  {
    return (pin < 8  ? &PIND :
	    pin < 14 ? &PINB :
	               &PINC);
  }

  /**
   * Return bit position for given Arduino pin number in Special
   * Function Register.
   * @param[in] pin number.
   * @return pin bit position.
   */
  static uint8_t BIT(uint8_t pin)
    __attribute__((always_inline))
  {
    return (pin < 8  ? pin :
	    pin < 14 ? pin - 8 :
 	               pin - 14);
  }

  /**
   * Return Pin Change Mask Register for given Arduino pin number.
   * @param[in] pin number.
   * @return pin change mask register pointer.
   */
  static volatile uint8_t* PCIMR(uint8_t pin)
    __attribute__((always_inline))
  {
    return (pin < 8  ? &PCMSK2 :
	    pin < 14 ? &PCMSK0 :
	               &PCMSK1);
  }

  /**
   * Return UART Register for given Arduino serial port.
   * @param[in] port number.
   * @return UART register pointer.
   */
  static volatile uint8_t* UART(uint8_t port)
    __attribute__((always_inline))
  {
    UNUSED(port);
    return (&UCSR0A);
  }

public:
  /**
   * Initiate board ports. Disable SPI chip select pins, i.e.
   * defined as output pins and set high.
   */
  static void init();

  /**
   * Digital pin symbols
   */
  enum DigitalPin {
    D0 = 0,			// PD0/XBEE:DOUT
    D1,				// PD1/XBEE:DIN
    D2,				// PD2/NRF24L01:IRQ
    D3,				// PD3/NRF24L01:CE
    D4,				// PD4/SD:CS
    D5,				// PD5/NRF24L01:MOSI
    D6,				// PD6/NRF24L01:MISO
    D7,				// PD7/NRF24L01:SCK
    D8,				// PB0/NRF24L01:SS
    D9,				// PB1/NC
    D10,			// PB2/W5100:SS
    D11,			// PB3/MOSI
    D12,			// PB4/MISO
    D13,			// PB5/SCK
    D14,			// PC0/A0
    D15,			// PC1/A1
    D16,			// PC2/A2
    D17,			// PC3/A3
    D18,			// PC4/A4
    D19,			// PC5/A5
    LED = D13
  } __attribute__((packed));

  /**
   * Analog pin symbols (ADC channel numbers)
   */
  enum AnalogPin {
    A0 = 0,			// PC0/D14
    A1,				// PC1/D15
    A2,				// PC2/D16
    A3,				// PC3/D17
    A4,				// PC4/D18
    A5,				// PC5/D19
    A6,				// ADC6
    A7				// ADC7
  } __attribute__((packed));

  /**
   * Reference voltage; ARef pin, Vcc or internal 1V1.
   */
  enum Reference {
    APIN_REFERENCE = 0,
    AVCC_REFERENCE = _BV(REFS0),
    A1V1_REFERENCE = (_BV(REFS1) | _BV(REFS0))
  } __attribute__((packed));

  /**
   * PWM pin symbols; sub-set of digital pins to allow compile
   * time checking
   */
  enum PWMPin {
    PWM0 = D3,			// PD3 => OCR2B
    PWM1 = D5,			// PD5 => OCR0B
    PWM2 = D6,			// PD6 => OCR0A
    PWM3 = D9,			// PB1 => OCR1A
    PWM4 = D10,			// PB2 => OCR1B
    PWM5 = D11			// PB3 => OCR2A
  } __attribute__((packed));

  /**
   * External interrupt pin symbols; sub-set of digital pins
   * to allow compile time checking.
   */
  enum ExternalInterruptPin {
    EXT0 = D2,			// PD2
    EXT1 = D3			// PD3
  } __attribute__((packed));

  /**
   * Pin change interrupt (PCI) pins (as digital pin number).
   */
  enum InterruptPin {
    PCI0 = D0,			// PD0
    PCI1 = D1,			// PD1
    PCI2 = D2,			// PD2
    PCI3 = D3,			// PD3
    PCI4 = D4,			// PD4
    PCI5 = D5,			// PD5
    PCI6 = D6,			// PD6
    PCI7 = D7,			// PD7
    PCI8 = D8,			// PB0
    PCI9 = D9,			// PB1
    PCI10 = D10,		// PB2
    PCI11 = D11,		// PB3
    PCI12 = D12,		// PB4
    PCI13 = D13,		// PB5
    PCI14 = D14,		// PC0
    PCI15 = D15,		// PC1
    PCI16 = D16,		// PC2
    PCI17 = D17,		// PC3
    PCI18 = D18,		// PC4
    PCI19 = D19			// PC5
  } __attribute__((packed));

  /**
   * Size of pin maps.
   */
  enum {
    ANALOG_PIN_MAX = 8,
    DIGITAL_PIN_MAX = 20,
    EXT_PIN_MAX = 2,
    PCI_PIN_MAX = 20,
    PWM_PIN_MAX = 6
  };

  /**
   * Pins used for TWI interface (port C, analog pins A4-A5).
   */
  enum TWIPin {
    SDA = 4,			// PA4/A4
    SCL = 5			// PA4/A5
  } __attribute__((packed));

  /**
   * Pins used for SPI interface (port B, digital pins D10-D13).
   */
  enum SPIPin {
    SS = 2,			// PB2/D10
    MOSI = 3,			// PB3/D11/ICSP
    MISO = 4,			// PB4/D12/ICSP
    SCK = 5			// PB5/D13/ICSP
  } __attribute__((packed));

  /**
   * Auxiliary
   */
  enum {
    VBG = (_BV(MUX3) | _BV(MUX2) | _BV(MUX1)),
    UART_MAX = 1,
    EXT_MAX = 2,
    PCMSK_MAX = 3,
    PCINT_MAX = 24
  } __attribute__((packed));
};

/**
 * Forward declare interrupt service routines to allow them as friends.
 */
extern "C" {
  void ADC_vect(void) __attribute__ ((signal));
  void ANALOG_COMP_vect(void) __attribute__ ((signal));
  void INT0_vect(void) __attribute__ ((signal));
  void INT1_vect(void) __attribute__ ((signal));
  void PCINT0_vect(void) __attribute__ ((signal));
  void PCINT1_vect(void) __attribute__ ((signal));
  void PCINT2_vect(void) __attribute__ ((signal));
  void SPI_STC_vect(void) __attribute__ ((signal));
  void TIMER0_COMPA_vect(void) __attribute__ ((signal));
  void TIMER0_COMPB_vect(void) __attribute__ ((signal));
  void TIMER0_OVF_vect(void) __attribute__ ((signal));
  void TIMER1_CAPT_vect(void)  __attribute__ ((signal));
  void TIMER1_COMPA_vect(void) __attribute__ ((signal));
  void TIMER1_COMPB_vect(void) __attribute__ ((signal));
  void TIMER1_OVF_vect(void) __attribute__ ((signal));
  void TIMER2_COMPA_vect(void) __attribute__ ((signal));
  void TIMER2_COMPB_vect(void) __attribute__ ((signal));
  void TIMER2_OVF_vect(void) __attribute__ ((signal));
  void TWI_vect(void) __attribute__ ((signal));
  void WDT_vect(void) __attribute__ ((signal));
  void USART_RX_vect(void) __attribute__ ((signal));
  void USART_TX_vect(void) __attribute__ ((signal));
  void USART_UDRE_vect(void) __attribute__ ((signal));
}
#endif
<commit_msg>Cleanup.<commit_after>/**
 * @file Cosa/Board/ITEADStudio/IBoard.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_BOARD_ITEADSTUDIO_IBOARD_HH
#define COSA_BOARD_ITEADSTUDIO_IBOARD_HH

/* This board is based on ATmega328P */
#define BOARD_ATMEGA328P

/**
 * Compiler warning on unused varable.
 */
#if !defined(UNUSED)
#define UNUSED(x) (void) (x)
#endif

/**
 * Cosa pin symbol and hardware definitions for the ATmega328P based
 * board ITEAD Studio IBoard. Cosa does not use pin numbers as
 * Arduino/Wiring, instead strong data type is used (enum types) for
 * the specific pin classes; DigitalPin, AnalogPin, PWMPin, etc.
 *
 * The pin numbers for ATmega328P are mapped as in Arduino. The static
 * inline functions, SFR, BIT and UART, rely on compiler optimizations
 * to be reduced.
 *
 * @section Board
 * @code
 *                       ITEAD Studio IBoard
 *                  -----              --------
 *                +-|(o)|--------------| RJ45 |--+
 *                | |   |              |      |  |
 *                | -----              |      |  |
 *                |                    --------  |
 *                |                              |
 *                |                              |
 *                |                              |
 *                |                              |
 *                |                              |
 *                |                              |
 *                |ISP                 SD        |
 *                |[][]                +--------+|
 *                |[][]                |        /|
 *                |[][]*               |       | |
 *                |                    |       | |
 *         D14/A0 |[][][]              |        \|
 *         D15/A1 |[][][]              +--------+|
 *         D16/A2 |[][][]                        |
 *         D17/A3 |[][][]                        |
 *     SDA/D18/A4 |[][][]                        |
 *     SCL/D19/A5 |[][][]                        |
 *             A6 |[][][]                        |
 *             A7 |[][][]                        |
 *                +------------------------------+
 * @endcode
 */
class Board {
  friend class Pin;
  friend class UART;
private:
  /**
   * Do not allow instances. This is a static singleton; name space.
   */
  Board() {}

  /**
   * Return Special Function Register for given Arduino pin number.
   * @param[in] pin number.
   * @return special register pointer.
   */
  static volatile uint8_t* SFR(uint8_t pin)
    __attribute__((always_inline))
  {
    return (pin < 8  ? &PIND :
	    pin < 14 ? &PINB :
	               &PINC);
  }

  /**
   * Return bit position for given Arduino pin number in Special
   * Function Register.
   * @param[in] pin number.
   * @return pin bit position.
   */
  static uint8_t BIT(uint8_t pin)
    __attribute__((always_inline))
  {
    return (pin < 8  ? pin :
	    pin < 14 ? pin - 8 :
 	               pin - 14);
  }

  /**
   * Return Pin Change Mask Register for given Arduino pin number.
   * @param[in] pin number.
   * @return pin change mask register pointer.
   */
  static volatile uint8_t* PCIMR(uint8_t pin)
    __attribute__((always_inline))
  {
    return (pin < 8  ? &PCMSK2 :
	    pin < 14 ? &PCMSK0 :
	               &PCMSK1);
  }

  /**
   * Return UART Register for given Arduino serial port.
   * @param[in] port number.
   * @return UART register pointer.
   */
  static volatile uint8_t* UART(uint8_t port)
    __attribute__((always_inline))
  {
    UNUSED(port);
    return (&UCSR0A);
  }

public:
  /**
   * Initiate board ports. Disable SPI chip select pins, i.e.
   * defined as output pins and set high.
   */
  static void init();

  /**
   * Digital pin symbols
   */
  enum DigitalPin {
    D0 = 0,			// PD0/XBEE:DOUT
    D1,				// PD1/XBEE:DIN
    D2,				// PD2/NRF24L01:IRQ
    D3,				// PD3/NRF24L01:CE
    D4,				// PD4/SD:CS
    D5,				// PD5/NRF24L01:MOSI
    D6,				// PD6/NRF24L01:MISO
    D7,				// PD7/NRF24L01:SCK
    D8,				// PB0/NRF24L01:SS
    D9,				// PB1/NC
    D10,			// PB2/W5100:SS
    D11,			// PB3/MOSI
    D12,			// PB4/MISO
    D13,			// PB5/SCK
    D14,			// PC0/A0
    D15,			// PC1/A1
    D16,			// PC2/A2
    D17,			// PC3/A3
    D18,			// PC4/A4
    D19,			// PC5/A5
    LED = D13
  } __attribute__((packed));

  /**
   * Analog pin symbols (ADC channel numbers)
   */
  enum AnalogPin {
    A0 = 0,			// PC0/D14
    A1,				// PC1/D15
    A2,				// PC2/D16
    A3,				// PC3/D17
    A4,				// PC4/D18
    A5,				// PC5/D19
    A6,				// ADC6
    A7				// ADC7
  } __attribute__((packed));

  /**
   * Reference voltage; ARef pin, Vcc or internal 1V1.
   */
  enum Reference {
    APIN_REFERENCE = 0,
    AVCC_REFERENCE = _BV(REFS0),
    A1V1_REFERENCE = (_BV(REFS1) | _BV(REFS0))
  } __attribute__((packed));

  /**
   * PWM pin symbols; sub-set of digital pins to allow compile
   * time checking
   */
  enum PWMPin {
    PWM0 = D3,			// PD3 => OCR2B
    PWM1 = D5,			// PD5 => OCR0B
    PWM2 = D6,			// PD6 => OCR0A
    PWM3 = D9,			// PB1 => OCR1A
    PWM4 = D10,			// PB2 => OCR1B
    PWM5 = D11			// PB3 => OCR2A
  } __attribute__((packed));

  /**
   * External interrupt pin symbols; sub-set of digital pins
   * to allow compile time checking.
   */
  enum ExternalInterruptPin {
    EXT0 = D2,			// PD2
    EXT1 = D3			// PD3
  } __attribute__((packed));

  /**
   * Pin change interrupt (PCI) pins (as digital pin number).
   */
  enum InterruptPin {
    PCI0 = D0,			// PD0
    PCI1 = D1,			// PD1
    PCI2 = D2,			// PD2
    PCI3 = D3,			// PD3
    PCI4 = D4,			// PD4
    PCI5 = D5,			// PD5
    PCI6 = D6,			// PD6
    PCI7 = D7,			// PD7
    PCI8 = D8,			// PB0
    PCI9 = D9,			// PB1
    PCI10 = D10,		// PB2
    PCI11 = D11,		// PB3
    PCI12 = D12,		// PB4
    PCI13 = D13,		// PB5
    PCI14 = D14,		// PC0
    PCI15 = D15,		// PC1
    PCI16 = D16,		// PC2
    PCI17 = D17,		// PC3
    PCI18 = D18,		// PC4
    PCI19 = D19			// PC5
  } __attribute__((packed));

  /**
   * Size of pin maps.
   */
  enum {
    ANALOG_PIN_MAX = 8,
    DIGITAL_PIN_MAX = 20,
    EXT_PIN_MAX = 2,
    PCI_PIN_MAX = 20,
    PWM_PIN_MAX = 6
  };

  /**
   * Pins used for TWI interface (port C, analog pins A4-A5).
   */
  enum TWIPin {
    SDA = 4,			// PA4/A4
    SCL = 5			// PA4/A5
  } __attribute__((packed));

  /**
   * Pins used for SPI interface (port B, digital pins D10-D13).
   */
  enum SPIPin {
    SS = 2,			// PB2/D10
    MOSI = 3,			// PB3/D11/ICSP
    MISO = 4,			// PB4/D12/ICSP
    SCK = 5			// PB5/D13/ICSP
  } __attribute__((packed));

  /**
   * Auxiliary
   */
  enum {
    VBG = (_BV(MUX3) | _BV(MUX2) | _BV(MUX1)),
    UART_MAX = 1,
    EXT_MAX = 2,
    PCMSK_MAX = 3,
    PCINT_MAX = 24
  } __attribute__((packed));
};

/**
 * Forward declare interrupt service routines to allow them as friends.
 */
extern "C" {
  void ADC_vect(void) __attribute__ ((signal));
  void ANALOG_COMP_vect(void) __attribute__ ((signal));
  void INT0_vect(void) __attribute__ ((signal));
  void INT1_vect(void) __attribute__ ((signal));
  void PCINT0_vect(void) __attribute__ ((signal));
  void PCINT1_vect(void) __attribute__ ((signal));
  void PCINT2_vect(void) __attribute__ ((signal));
  void SPI_STC_vect(void) __attribute__ ((signal));
  void TIMER0_COMPA_vect(void) __attribute__ ((signal));
  void TIMER0_COMPB_vect(void) __attribute__ ((signal));
  void TIMER0_OVF_vect(void) __attribute__ ((signal));
  void TIMER1_CAPT_vect(void)  __attribute__ ((signal));
  void TIMER1_COMPA_vect(void) __attribute__ ((signal));
  void TIMER1_COMPB_vect(void) __attribute__ ((signal));
  void TIMER1_OVF_vect(void) __attribute__ ((signal));
  void TIMER2_COMPA_vect(void) __attribute__ ((signal));
  void TIMER2_COMPB_vect(void) __attribute__ ((signal));
  void TIMER2_OVF_vect(void) __attribute__ ((signal));
  void TWI_vect(void) __attribute__ ((signal));
  void WDT_vect(void) __attribute__ ((signal));
  void USART_RX_vect(void) __attribute__ ((signal));
  void USART_TX_vect(void) __attribute__ ((signal));
  void USART_UDRE_vect(void) __attribute__ ((signal));
}
#endif
<|endoftext|>


<commit_before>
// the syntax for messages is:
//   wd 'mb type buttons title message'
//
// type specifies the icon and default behaviour:
//  info      (default OK button)
//  warn      (default OK button)
//  critical  (default OK button)
//  query     (requires two or three buttons)
//
// if one button, there is no result,
// otherwise the result is the button name (ok, cancel, ...)
//
// buttons are from the set:
//  mb_ok
//  mb_cancel
//  mb_yes
//  mb_no
//  mb_save
//  mb_discard

#include <QApplication>
#include <QColorDialog>
#include <QFileDialog>
#include <QFontDialog>
#include <QMessageBox>
#include <QTextDocument>

#include "wd.h"
#include "cmd.h"
#include "../base/dialog.h"

#ifndef ANDROID
#include <QPrinter>
#include <QPrintDialog>
extern QPrinter *pprinter;
#endif

QString mbcolor();
QString mbdir();
QString mbfont();
QString mbinfo(QString);
#ifndef ANDROID
QString mbprint(bool);
QString mbprintx(bool);
QString mbprinter();
#endif
QString mbmsg();
QString mbopen();
QString mbsave();

QString fixsep(QString s);

QString type;
QStringList arg;

QMessageBox::StandardButton getdefaultbutton();
QMessageBox::StandardButton getonebutton();
QMessageBox::StandardButtons getotherbuttons();
QString getname(int);

// ---------------------------------------------------------------------
QString mb(string p)
{
  arg=qsplit(p);
  if (arg.size()<1) return mbinfo("missing mb type");

  type=arg.first();
  arg.removeFirst();
  if (type=="color")
    return mbcolor();
  if (type=="dir")
    return mbdir();
  if (type=="font")
    return mbfont();
  if (type=="open")
    return mbopen();
#ifndef ANDROID
  if (type=="print") {
    QString s=dlb(s2q(p.substr(5)));
    return mbprint('*'==s.at(0));
  }
  if (type=="printx") {
    QString s=dlb(s2q(p.substr(6)));
    return mbprintx('*'==s.at(0));
  }
#endif
  if (type=="save")
    return mbsave();
  if (type=="info"||type=="query"||type=="warn"||type=="critical")
    return mbmsg();
  return mbinfo("invalid mb type: " + type);
}

// ---------------------------------------------------------------------
QString mbmsg()
{
  int r;
  QString t,m;

  QMessageBox::StandardButton button1=getdefaultbutton();
  QMessageBox::StandardButtons buttons=getotherbuttons();

  if (arg.size()==1) {
    t="Message Box";
    m=arg.at(0);
  } else if (arg.size()==2) {
    t=arg.at(0);
    m=arg.at(1);
  } else {
    return mbinfo ("Need title and message: "+arg.join(" "));
  }

  if (button1==-1) {
    button1=QMessageBox::Ok;
    if (type=="query")
      buttons=QMessageBox::Cancel;
  }
  buttons|=button1;

  if (type=="query") {
    r=QMessageBox::question(QApplication::focusWidget(),t,m,buttons,button1);
    return getname(r);
  }
  if (type=="critical")
    QMessageBox::critical(QApplication::focusWidget(),t,m,buttons,button1);
  else if (type=="info")
    QMessageBox::information(QApplication::focusWidget(),t,m,buttons,button1);
  else if (type=="warn")
    QMessageBox::warning(QApplication::focusWidget(),t,m,buttons,button1);
  return "";
}

// ---------------------------------------------------------------------
QString mbcolor()
{
  QColor c;
  int r,g,b;

  if (arg.size()==3) {
    r=c_strtoi(q2s(arg.at(0)));
    g=c_strtoi(q2s(arg.at(1)));
    b=c_strtoi(q2s(arg.at(2)));
    c=QColor(r,g,b);
  } else
    c=Qt::white;
  c=QColorDialog::getColor(c,QApplication::focusWidget());
  if (!c.isValid()) return "";
  return s2q(i2s(c.red()) + " " + i2s(c.green()) + " " + i2s(c.blue()));
}

// ---------------------------------------------------------------------
QString mbdir()
{
  QString title,dir;
  if (arg.size()!=2)
    return mbinfo("dir needs title and directory");
  title=arg.at(0);
  dir=arg.at(1);
  return QFileDialog::getExistingDirectory(
           QApplication::focusWidget(),title,dir);
}

// ---------------------------------------------------------------------
QString mbfont()
{
  bool ok;
  QFont font, def;
  QString s;
  def.setStrikeOut(false);
  def.setUnderline(false);
  if (arg.size())
    def.setFamily(arg.at(0));
  if (arg.size()>1)
    def.setPointSize(arg.at(1).toFloat());
  for (int i=2; i<arg.size(); i++) {
    s=arg.at(i);
    if (s=="bold")
      def.setBold(true);
    if (s=="italic")
      def.setItalic(true);
    if (s=="strikeout")
      def.setStrikeOut(true);
    if (s=="underline")
      def.setUnderline(true);
  }
  font=QFontDialog::getFont(&ok,def,QApplication::focusWidget());
  if (!ok) return "";
  QString r;
  r="\"" + font.family() + "\" " + QString::number(font.pointSize());
  if (font.bold()) r+=" bold";
  if (font.italic()) r+=" italic";
  if (font.strikeOut()) r+=" strikeout";
  if (font.underline()) r+=" underline";
  return r;
}

// ---------------------------------------------------------------------
QString mbopen()
{
  QString title,dir,filter;
  if (arg.size()<2)
    return mbinfo("open needs title, directory, [filters]");
  title=arg.at(0);
  dir=arg.at(1);
  if (arg.size()==3)
    filter=fixsep(arg.at(2));
  return QFileDialog::getOpenFileName(
           QApplication::focusWidget(),title,dir,filter);
}

#ifndef ANDROID
// ---------------------------------------------------------------------
QString mbprint(bool iftext)
{
  QString s=arg.at(0);
  if (!iftext) {
    if (!cfexist(s)) {
      mbinfo("File not found: " + s);
      return "";
    }
    s=cfread(s);
  }
  QTextDocument *d=new QTextDocument(s);
  dialogprint(QApplication::focusWidget(),d);
  return "";
}
#endif

// ---------------------------------------------------------------------
QString mbprintx(bool iftext)
{
  QString s=arg.at(0);
  if (!iftext) {
    if (!cfexist(s)) {
      mbinfo("File not found: " + s);
      return "";
    }
    s=cfread(s);
  }
  QTextDocument *d=new QTextDocument(s);
  QPrinter printer(QPrinter::HighResolution);
  d->print(&printer);
  return "";
}

// ---------------------------------------------------------------------
QString mbsave()
{
  QString title,dir,filter;
  if (arg.size()<2)
    return mbinfo("save needs title, directory, [filters]");
  title=arg.at(0);
  dir=arg.at(1);
  if (arg.size()==3)
    filter=fixsep(arg.at(2));
  return QFileDialog::getSaveFileName(
           QApplication::focusWidget(),title,dir,filter);
}

// ---------------------------------------------------------------------
QString getname(int b)
{
  if (b==QMessageBox::Ok)
    return "ok";
  if (b==QMessageBox::Cancel)
    return "cancel";
  if (b==QMessageBox::Yes)
    return "yes";
  if (b==QMessageBox::No)
    return "no";
  if (b==QMessageBox::Save)
    return "save";
  if (b==QMessageBox::Discard)
    return "discard";
  return "unknown button";
}

// ---------------------------------------------------------------------
QMessageBox::StandardButton getonebutton()
{
  if (arg.isEmpty()) return QMessageBox::NoButton;
  QString s=arg.first();
  if (s=="mb_ok")
    return QMessageBox::Ok;
  if (s=="mb_cancel")
    return QMessageBox::Cancel;
  if (s=="mb_yes")
    return QMessageBox::Yes;
  if (s=="mb_no")
    return QMessageBox::No;
  if (s=="mb_save")
    return QMessageBox::Save;
  if (s=="mb_discard")
    return QMessageBox::Discard;
  return QMessageBox::NoButton;
}

// ---------------------------------------------------------------------
QMessageBox::StandardButton getdefaultbutton()
{
  QMessageBox::StandardButton r=getonebutton();
  if (r!=QMessageBox::NoButton)
    arg.removeFirst();
  return r;
}

// ---------------------------------------------------------------------
QMessageBox::StandardButtons getotherbuttons()
{
  QMessageBox::StandardButtons r=QMessageBox::NoButton;
  QMessageBox::StandardButton b;
  while (arg.size()) {
    b=getonebutton();
    if (b==QMessageBox::NoButton)
      return r;
    r|=b;
    arg.removeFirst();
  }
  return r;
}

// ---------------------------------------------------------------------
QString mbinfo(QString s)
{
  info("Message Box",s);
  return "";
}

// ---------------------------------------------------------------------
QString fixsep(QString s)
{
  return s.replace("|",";;");
}
<commit_msg>fix mbprintx<commit_after>
// the syntax for messages is:
//   wd 'mb type buttons title message'
//
// type specifies the icon and default behaviour:
//  info      (default OK button)
//  warn      (default OK button)
//  critical  (default OK button)
//  query     (requires two or three buttons)
//
// if one button, there is no result,
// otherwise the result is the button name (ok, cancel, ...)
//
// buttons are from the set:
//  mb_ok
//  mb_cancel
//  mb_yes
//  mb_no
//  mb_save
//  mb_discard

#include <QApplication>
#include <QColorDialog>
#include <QFileDialog>
#include <QFontDialog>
#include <QMessageBox>
#include <QTextDocument>

#include "wd.h"
#include "cmd.h"
#include "../base/dialog.h"

#ifndef ANDROID
#include <QPrinter>
#include <QPrintDialog>
extern QPrinter *pprinter;
#endif

QString mbcolor();
QString mbdir();
QString mbfont();
QString mbinfo(QString);
#ifndef ANDROID
QString mbprint(bool);
QString mbprintx(bool);
QString mbprinter();
#endif
QString mbmsg();
QString mbopen();
QString mbsave();

QString fixsep(QString s);

QString type;
QStringList arg;

QMessageBox::StandardButton getdefaultbutton();
QMessageBox::StandardButton getonebutton();
QMessageBox::StandardButtons getotherbuttons();
QString getname(int);

// ---------------------------------------------------------------------
QString mb(string p)
{
  arg=qsplit(p);
  if (arg.size()<1) return mbinfo("missing mb type");

  type=arg.first();
  arg.removeFirst();
  if (type=="color")
    return mbcolor();
  if (type=="dir")
    return mbdir();
  if (type=="font")
    return mbfont();
  if (type=="open")
    return mbopen();
#ifndef ANDROID
  if (type=="print") {
    QString s=dlb(s2q(p.substr(5)));
    return mbprint('*'==s.at(0));
  }
  if (type=="printx") {
    QString s=dlb(s2q(p.substr(6)));
    return mbprintx('*'==s.at(0));
  }
#endif
  if (type=="save")
    return mbsave();
  if (type=="info"||type=="query"||type=="warn"||type=="critical")
    return mbmsg();
  return mbinfo("invalid mb type: " + type);
}

// ---------------------------------------------------------------------
QString mbmsg()
{
  int r;
  QString t,m;

  QMessageBox::StandardButton button1=getdefaultbutton();
  QMessageBox::StandardButtons buttons=getotherbuttons();

  if (arg.size()==1) {
    t="Message Box";
    m=arg.at(0);
  } else if (arg.size()==2) {
    t=arg.at(0);
    m=arg.at(1);
  } else {
    return mbinfo ("Need title and message: "+arg.join(" "));
  }

  if (button1==-1) {
    button1=QMessageBox::Ok;
    if (type=="query")
      buttons=QMessageBox::Cancel;
  }
  buttons|=button1;

  if (type=="query") {
    r=QMessageBox::question(QApplication::focusWidget(),t,m,buttons,button1);
    return getname(r);
  }
  if (type=="critical")
    QMessageBox::critical(QApplication::focusWidget(),t,m,buttons,button1);
  else if (type=="info")
    QMessageBox::information(QApplication::focusWidget(),t,m,buttons,button1);
  else if (type=="warn")
    QMessageBox::warning(QApplication::focusWidget(),t,m,buttons,button1);
  return "";
}

// ---------------------------------------------------------------------
QString mbcolor()
{
  QColor c;
  int r,g,b;

  if (arg.size()==3) {
    r=c_strtoi(q2s(arg.at(0)));
    g=c_strtoi(q2s(arg.at(1)));
    b=c_strtoi(q2s(arg.at(2)));
    c=QColor(r,g,b);
  } else
    c=Qt::white;
  c=QColorDialog::getColor(c,QApplication::focusWidget());
  if (!c.isValid()) return "";
  return s2q(i2s(c.red()) + " " + i2s(c.green()) + " " + i2s(c.blue()));
}

// ---------------------------------------------------------------------
QString mbdir()
{
  QString title,dir;
  if (arg.size()!=2)
    return mbinfo("dir needs title and directory");
  title=arg.at(0);
  dir=arg.at(1);
  return QFileDialog::getExistingDirectory(
           QApplication::focusWidget(),title,dir);
}

// ---------------------------------------------------------------------
QString mbfont()
{
  bool ok;
  QFont font, def;
  QString s;
  def.setStrikeOut(false);
  def.setUnderline(false);
  if (arg.size())
    def.setFamily(arg.at(0));
  if (arg.size()>1)
    def.setPointSize(arg.at(1).toFloat());
  for (int i=2; i<arg.size(); i++) {
    s=arg.at(i);
    if (s=="bold")
      def.setBold(true);
    if (s=="italic")
      def.setItalic(true);
    if (s=="strikeout")
      def.setStrikeOut(true);
    if (s=="underline")
      def.setUnderline(true);
  }
  font=QFontDialog::getFont(&ok,def,QApplication::focusWidget());
  if (!ok) return "";
  QString r;
  r="\"" + font.family() + "\" " + QString::number(font.pointSize());
  if (font.bold()) r+=" bold";
  if (font.italic()) r+=" italic";
  if (font.strikeOut()) r+=" strikeout";
  if (font.underline()) r+=" underline";
  return r;
}

// ---------------------------------------------------------------------
QString mbopen()
{
  QString title,dir,filter;
  if (arg.size()<2)
    return mbinfo("open needs title, directory, [filters]");
  title=arg.at(0);
  dir=arg.at(1);
  if (arg.size()==3)
    filter=fixsep(arg.at(2));
  return QFileDialog::getOpenFileName(
           QApplication::focusWidget(),title,dir,filter);
}

#ifndef ANDROID
// ---------------------------------------------------------------------
QString mbprint(bool iftext)
{
  QString s=arg.at(0);
  if (!iftext) {
    if (!cfexist(s)) {
      mbinfo("File not found: " + s);
      return "";
    }
    s=cfread(s);
  }
  QTextDocument *d=new QTextDocument(s);
  dialogprint(QApplication::focusWidget(),d);
  return "";
}

// ---------------------------------------------------------------------
// print with no dialog
QString mbprintx(bool iftext)
{
  QString s=arg.at(0);
  if (!iftext) {
    if (!cfexist(s)) {
      mbinfo("File not found: " + s);
      return "";
    }
    s=cfread(s);
  }
  QTextDocument *d=new QTextDocument(s);
  QPrinter printer(QPrinter::HighResolution);
  d->print(&printer);
  return "";
}
#endif

// ---------------------------------------------------------------------
QString mbsave()
{
  QString title,dir,filter;
  if (arg.size()<2)
    return mbinfo("save needs title, directory, [filters]");
  title=arg.at(0);
  dir=arg.at(1);
  if (arg.size()==3)
    filter=fixsep(arg.at(2));
  return QFileDialog::getSaveFileName(
           QApplication::focusWidget(),title,dir,filter);
}

// ---------------------------------------------------------------------
QString getname(int b)
{
  if (b==QMessageBox::Ok)
    return "ok";
  if (b==QMessageBox::Cancel)
    return "cancel";
  if (b==QMessageBox::Yes)
    return "yes";
  if (b==QMessageBox::No)
    return "no";
  if (b==QMessageBox::Save)
    return "save";
  if (b==QMessageBox::Discard)
    return "discard";
  return "unknown button";
}

// ---------------------------------------------------------------------
QMessageBox::StandardButton getonebutton()
{
  if (arg.isEmpty()) return QMessageBox::NoButton;
  QString s=arg.first();
  if (s=="mb_ok")
    return QMessageBox::Ok;
  if (s=="mb_cancel")
    return QMessageBox::Cancel;
  if (s=="mb_yes")
    return QMessageBox::Yes;
  if (s=="mb_no")
    return QMessageBox::No;
  if (s=="mb_save")
    return QMessageBox::Save;
  if (s=="mb_discard")
    return QMessageBox::Discard;
  return QMessageBox::NoButton;
}

// ---------------------------------------------------------------------
QMessageBox::StandardButton getdefaultbutton()
{
  QMessageBox::StandardButton r=getonebutton();
  if (r!=QMessageBox::NoButton)
    arg.removeFirst();
  return r;
}

// ---------------------------------------------------------------------
QMessageBox::StandardButtons getotherbuttons()
{
  QMessageBox::StandardButtons r=QMessageBox::NoButton;
  QMessageBox::StandardButton b;
  while (arg.size()) {
    b=getonebutton();
    if (b==QMessageBox::NoButton)
      return r;
    r|=b;
    arg.removeFirst();
  }
  return r;
}

// ---------------------------------------------------------------------
QString mbinfo(QString s)
{
  info("Message Box",s);
  return "";
}

// ---------------------------------------------------------------------
QString fixsep(QString s)
{
  return s.replace("|",";;");
}
<|endoftext|>


<commit_before>/* This file is part of Mapnik (c++ mapping toolkit)
 * Copyright (C) 2005 Artem Pavlenko
 *
 * Mapnik 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 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id: style.hh 60 2004-11-04 09:40:49Z artem $

#ifndef STYLE_HH
#define STYLE_HH

#include "color.hh"
#include "ptr.hh"
#include "symbolizer.hh"

#include <vector>
#include <algorithm>
#include <functional>

namespace mapnik
{

    class IsActive : public std::unary_function<ref_ptr<Symbolizer>, bool>
    {
    private:
	double scale_;
    public:
	IsActive(double scale)
	    : scale_(scale) {}
	bool operator()(const ref_ptr<Symbolizer>& symbol)
	{
	    return symbol->active(scale_);
	}
    };

    class Style
    {
	typedef std::vector<ref_ptr<Symbolizer> >::const_iterator Iterator;
    private:
	std::vector<ref_ptr<Symbolizer> > symbols_;
	static ref_ptr<Symbolizer> zero_symbol_;
    public:
	Style() {}

	Style(const ref_ptr<Symbolizer>& symbol)
	{
	    symbols_.push_back(symbol);
	}

	~Style() {}

	Style(const Style& rhs)
	    : symbols_(rhs.symbols_) {}

	Style& operator=(const Style& rhs)
	{
	    if (this==&rhs) return *this;
	    symbols_=rhs.symbols_;
	    return *this;
	}

	void add(const ref_ptr<Symbolizer>& symbol)
	{
	    symbols_.push_back(symbol);
	}

	Iterator find(double scale) const
	{
	    return std::find_if(symbols_.begin(),symbols_.end(),IsActive(scale));
	}

	Iterator end() const
	{
	    return symbols_.end();
	}
    };
}

#endif                                            //STYLE_HH
<commit_msg>public typedef to keep gcc3.3.3 happy<commit_after>/* This file is part of Mapnik (c++ mapping toolkit)
 * Copyright (C) 2005 Artem Pavlenko
 *
 * Mapnik 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 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id$

#ifndef STYLE_HH
#define STYLE_HH

#include "color.hh"
#include "ptr.hh"
#include "symbolizer.hh"

#include <vector>
#include <algorithm>
#include <functional>

namespace mapnik
{

    class IsActive : public std::unary_function<ref_ptr<Symbolizer>, bool>
    {
    private:
	double scale_;
    public:
	IsActive(double scale)
	    : scale_(scale) {}
	bool operator()(const ref_ptr<Symbolizer>& symbol)
	{
	    return symbol->active(scale_);
	}
    };

    class Style
    {
    private:
	std::vector<ref_ptr<Symbolizer> > symbols_;
	static ref_ptr<Symbolizer> zero_symbol_;
    public:
	typedef std::vector<ref_ptr<Symbolizer> >::const_iterator Iterator;

	Style() {}

	Style(const ref_ptr<Symbolizer>& symbol)
	{
	    symbols_.push_back(symbol);
	}

	~Style() {}

	Style(const Style& rhs)
	    : symbols_(rhs.symbols_) {}

	Style& operator=(const Style& rhs)
	{
	    if (this==&rhs) return *this;
	    symbols_=rhs.symbols_;
	    return *this;
	}

	void add(const ref_ptr<Symbolizer>& symbol)
	{
	    symbols_.push_back(symbol);
	}

	Iterator find(double scale) const
	{
	    return std::find_if(symbols_.begin(),symbols_.end(),IsActive(scale));
	}

	Iterator end() const
	{
	    return symbols_.end();
	}
    };
}

#endif                                            //STYLE_HH
<|endoftext|>


<commit_before>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018-19  gatecat <gatecat@ds0.me>
 *  Copyright (C) 2021  William D. Jones <wjones@wdj-consulting.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <algorithm>
#include <iterator>
#include "cells.h"
#include "design_utils.h"
#include "log.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

// Pack LUTs and LUT-FF pairs
static void pack_lut_lutffs(Context *ctx)
{
    log_info("Packing LUT-FFs..\n");

    pool<IdString> packed_cells;
    std::vector<std::unique_ptr<CellInfo>> new_cells;
    for (auto &cell : ctx->cells) {
        CellInfo *ci = cell.second.get();
        if (ctx->verbose)
            log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
        if (is_lut(ctx, ci)) {
            std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC");
            for (auto &attr : ci->attrs)
                packed->attrs[attr.first] = attr.second;

            packed_cells.insert(ci->name);
            if (ctx->verbose)
                log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
            // See if we can pack into a DFF. Both LUT4 and FF outputs are
            // available for a given slice, so we can pack a FF even if the
            // LUT4 drives more than one FF.
            NetInfo *o = ci->ports.at(id_Z).net;
            CellInfo *dff = net_only_drives(ctx, o, is_ff, id_DI, false);
            auto lut_bel = ci->attrs.find(ctx->id("BEL"));
            bool packed_dff = false;

            if (dff) {
                if (ctx->verbose)
                    log_info("found attached dff %s\n", dff->name.c_str(ctx));
                auto dff_bel = dff->attrs.find(ctx->id("BEL"));
                if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) {
                    // Locations don't match, can't pack
                } else {
                    lut_to_lc(ctx, ci, packed.get(), false);
                    dff_to_lc(ctx, dff, packed.get(), LutType::Normal);
                    if (dff_bel != dff->attrs.end())
                        packed->attrs[ctx->id("BEL")] = dff_bel->second;
                    packed_cells.insert(dff->name);
                    if (ctx->verbose)
                        log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx));
                    packed_dff = true;
                }
            }
            if (!packed_dff) {
                lut_to_lc(ctx, ci, packed.get(), true);
            }
            new_cells.push_back(std::move(packed));
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
    for (auto &ncell : new_cells) {
        ctx->cells[ncell->name] = std::move(ncell);
    }
}

static void pack_remaining_ffs(Context *ctx)
{
    log_info("Packing remaining FFs..\n");

    pool<IdString> packed_cells;
    std::vector<std::unique_ptr<CellInfo>> new_cells;

    for (auto &cell : ctx->cells) {
        CellInfo *ci = cell.second.get();

        if (is_ff(ctx, ci)) {
            if (ctx->verbose)
                log_info("cell '%s' of type '%s remains unpacked'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));

            std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC");
            for (auto &attr : ci->attrs)
                packed->attrs[attr.first] = attr.second;

            auto dff_bel = ci->attrs.find(ctx->id("BEL"));

            dff_to_lc(ctx, ci, packed.get(), LutType::None);

            if (dff_bel != ci->attrs.end())
                packed->attrs[ctx->id("BEL")] = dff_bel->second;
            packed_cells.insert(ci->name);
            if (ctx->verbose)
                log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));

            new_cells.push_back(std::move(packed));
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
    for (auto &ncell : new_cells) {
        ctx->cells[ncell->name] = std::move(ncell);
    }
}

// Merge a net into a constant net
static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
{
    (void)constval;

    pool<IdString> packed_cells;
    std::vector<std::unique_ptr<CellInfo>> new_cells;

    orig->driver.cell = nullptr;
    for (auto user : orig->users) {
        if (user.cell != nullptr) {
            CellInfo *uc = user.cell;
            if (ctx->verbose)
                log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));

            if (uc->type == id_FACADE_FF && user.port == id_DI) {
                log_info("FACADE_FF %s is driven by a constant\n", uc->name.c_str(ctx));

                std::unique_ptr<CellInfo> lc = create_machxo2_cell(ctx, id_FACADE_SLICE, uc->name.str(ctx) + "_CONST");
                for (auto &attr : uc->attrs)
                    lc->attrs[attr.first] = attr.second;

                dff_to_lc(ctx, uc, lc.get(), LutType::PassThru);
                packed_cells.insert(uc->name);

                lc->ports[id_A0].net = constnet;
                user.cell = lc.get();
                user.port = id_A0;

                new_cells.push_back(std::move(lc));
            } else {
                uc->ports[user.port].net = constnet;
            }

            constnet->users.push_back(user);
        }
    }
    orig->users.clear();

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
    for (auto &ncell : new_cells) {
        ctx->cells[ncell->name] = std::move(ncell);
    }
}

// Pack constants (based on simple implementation in generic).
// VCC/GND cells provided by nextpnr automatically.
static void pack_constants(Context *ctx)
{
    log_info("Packing constants..\n");

    std::unique_ptr<CellInfo> const_cell = create_machxo2_cell(ctx, id_FACADE_SLICE, "$PACKER_CONST");
    const_cell->params[id_LUT0_INITVAL] = Property(0, 16);
    const_cell->params[id_LUT1_INITVAL] = Property(0xFFFF, 16);

    std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(new NetInfo);
    gnd_net->name = ctx->id("$PACKER_GND_NET");
    gnd_net->driver.cell = const_cell.get();
    gnd_net->driver.port = id_F0;
    const_cell->ports.at(id_F0).net = gnd_net.get();

    std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(new NetInfo);
    vcc_net->name = ctx->id("$PACKER_VCC_NET");
    vcc_net->driver.cell = const_cell.get();
    vcc_net->driver.port = id_F1;
    const_cell->ports.at(id_F1).net = vcc_net.get();

    std::vector<IdString> dead_nets;

    for (auto &net : ctx->nets) {
        NetInfo *ni = net.second.get();
        if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
            IdString drv_cell = ni->driver.cell->name;
            set_net_constant(ctx, ni, gnd_net.get(), false);
            dead_nets.push_back(net.first);
            ctx->cells.erase(drv_cell);
        } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) {
            IdString drv_cell = ni->driver.cell->name;
            set_net_constant(ctx, ni, vcc_net.get(), true);
            dead_nets.push_back(net.first);
            ctx->cells.erase(drv_cell);
        }
    }

    ctx->cells[const_cell->name] = std::move(const_cell);
    ctx->nets[gnd_net->name] = std::move(gnd_net);
    ctx->nets[vcc_net->name] = std::move(vcc_net);

    for (auto dn : dead_nets) {
        ctx->nets.erase(dn);
    }
}

static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
{
    return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
           cell->type == ctx->id("$nextpnr_iobuf");
}

static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cell->type == id_FACADE_IO; }

// Pack IO buffers- Right now, all this does is remove $nextpnr_[io]buf cells.
// User is expected to manually instantiate FACADE_IO with BEL/IO_TYPE
// attributes.
static void pack_io(Context *ctx)
{
    pool<IdString> packed_cells;

    log_info("Packing IOs..\n");

    for (auto &cell : ctx->cells) {
        CellInfo *ci = cell.second.get();
        if (is_nextpnr_iob(ctx, ci)) {
            for (auto &p : ci->ports)
                disconnect_port(ctx, ci, p.first);
            packed_cells.insert(ci->name);
        } else if (is_facade_iob(ctx, ci)) {
            // If FACADE_IO has LOC attribute, convert the LOC (pin) to a BEL
            // attribute and place FACADE_IO at resulting BEL location. A BEL
            // attribute already on a FACADE_IO is an error. Attributes on
            // the pin attached to the PAD of FACADE_IO are ignored by this
            // packing phase.
            auto loc_attr_cell = ci->attrs.find(ctx->id("LOC"));
            auto bel_attr_cell = ci->attrs.find(ctx->id("BEL"));

            if (loc_attr_cell != ci->attrs.end()) {
                if (bel_attr_cell != ci->attrs.end()) {
                    log_error("IO buffer %s has both a BEL attribute and LOC attribute.\n", ci->name.c_str(ctx));
                }

                log_info("found LOC attribute on IO buffer %s.\n", ci->name.c_str(ctx));
                std::string pin = loc_attr_cell->second.as_string();

                BelId pinBel = ctx->getPackagePinBel(pin);
                if (pinBel == BelId()) {
                    log_error("IO buffer '%s' constrained to pin '%s', which does not exist for package '%s'.\n",
                              ci->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
                } else {
                    log_info("pin '%s' constrained to Bel '%s'.\n", ci->name.c_str(ctx), ctx->nameOfBel(pinBel));
                }
                ci->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
            }
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
}

// Main pack function
bool Arch::pack()
{
    Context *ctx = getCtx();
    try {
        log_break();
        pack_constants(ctx);
        pack_io(ctx);
        pack_lut_lutffs(ctx);
        pack_remaining_ffs(ctx);
        ctx->settings[ctx->id("pack")] = 1;
        ctx->assignArchInfo();
        log_info("Checksum: 0x%08x\n", ctx->checksum());
        return true;
    } catch (log_execution_error_exception) {
        return false;
    }
}

NEXTPNR_NAMESPACE_END
<commit_msg>machxo2: Add packing logic to forbid designs lacking FACADE_IO top-level ports.<commit_after>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018-19  gatecat <gatecat@ds0.me>
 *  Copyright (C) 2021  William D. Jones <wjones@wdj-consulting.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <algorithm>
#include <iterator>
#include "cells.h"
#include "design_utils.h"
#include "log.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

// Pack LUTs and LUT-FF pairs
static void pack_lut_lutffs(Context *ctx)
{
    log_info("Packing LUT-FFs..\n");

    pool<IdString> packed_cells;
    std::vector<std::unique_ptr<CellInfo>> new_cells;
    for (auto &cell : ctx->cells) {
        CellInfo *ci = cell.second.get();
        if (ctx->verbose)
            log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
        if (is_lut(ctx, ci)) {
            std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC");
            for (auto &attr : ci->attrs)
                packed->attrs[attr.first] = attr.second;

            packed_cells.insert(ci->name);
            if (ctx->verbose)
                log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
            // See if we can pack into a DFF. Both LUT4 and FF outputs are
            // available for a given slice, so we can pack a FF even if the
            // LUT4 drives more than one FF.
            NetInfo *o = ci->ports.at(id_Z).net;
            CellInfo *dff = net_only_drives(ctx, o, is_ff, id_DI, false);
            auto lut_bel = ci->attrs.find(ctx->id("BEL"));
            bool packed_dff = false;

            if (dff) {
                if (ctx->verbose)
                    log_info("found attached dff %s\n", dff->name.c_str(ctx));
                auto dff_bel = dff->attrs.find(ctx->id("BEL"));
                if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) {
                    // Locations don't match, can't pack
                } else {
                    lut_to_lc(ctx, ci, packed.get(), false);
                    dff_to_lc(ctx, dff, packed.get(), LutType::Normal);
                    if (dff_bel != dff->attrs.end())
                        packed->attrs[ctx->id("BEL")] = dff_bel->second;
                    packed_cells.insert(dff->name);
                    if (ctx->verbose)
                        log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx));
                    packed_dff = true;
                }
            }
            if (!packed_dff) {
                lut_to_lc(ctx, ci, packed.get(), true);
            }
            new_cells.push_back(std::move(packed));
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
    for (auto &ncell : new_cells) {
        ctx->cells[ncell->name] = std::move(ncell);
    }
}

static void pack_remaining_ffs(Context *ctx)
{
    log_info("Packing remaining FFs..\n");

    pool<IdString> packed_cells;
    std::vector<std::unique_ptr<CellInfo>> new_cells;

    for (auto &cell : ctx->cells) {
        CellInfo *ci = cell.second.get();

        if (is_ff(ctx, ci)) {
            if (ctx->verbose)
                log_info("cell '%s' of type '%s remains unpacked'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));

            std::unique_ptr<CellInfo> packed = create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC");
            for (auto &attr : ci->attrs)
                packed->attrs[attr.first] = attr.second;

            auto dff_bel = ci->attrs.find(ctx->id("BEL"));

            dff_to_lc(ctx, ci, packed.get(), LutType::None);

            if (dff_bel != ci->attrs.end())
                packed->attrs[ctx->id("BEL")] = dff_bel->second;
            packed_cells.insert(ci->name);
            if (ctx->verbose)
                log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));

            new_cells.push_back(std::move(packed));
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
    for (auto &ncell : new_cells) {
        ctx->cells[ncell->name] = std::move(ncell);
    }
}

// Merge a net into a constant net
static void set_net_constant(Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
{
    (void)constval;

    pool<IdString> packed_cells;
    std::vector<std::unique_ptr<CellInfo>> new_cells;

    orig->driver.cell = nullptr;
    for (auto user : orig->users) {
        if (user.cell != nullptr) {
            CellInfo *uc = user.cell;
            if (ctx->verbose)
                log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));

            if (uc->type == id_FACADE_FF && user.port == id_DI) {
                log_info("FACADE_FF %s is driven by a constant\n", uc->name.c_str(ctx));

                std::unique_ptr<CellInfo> lc = create_machxo2_cell(ctx, id_FACADE_SLICE, uc->name.str(ctx) + "_CONST");
                for (auto &attr : uc->attrs)
                    lc->attrs[attr.first] = attr.second;

                dff_to_lc(ctx, uc, lc.get(), LutType::PassThru);
                packed_cells.insert(uc->name);

                lc->ports[id_A0].net = constnet;
                user.cell = lc.get();
                user.port = id_A0;

                new_cells.push_back(std::move(lc));
            } else {
                uc->ports[user.port].net = constnet;
            }

            constnet->users.push_back(user);
        }
    }
    orig->users.clear();

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
    for (auto &ncell : new_cells) {
        ctx->cells[ncell->name] = std::move(ncell);
    }
}

// Pack constants (based on simple implementation in generic).
// VCC/GND cells provided by nextpnr automatically.
static void pack_constants(Context *ctx)
{
    log_info("Packing constants..\n");

    std::unique_ptr<CellInfo> const_cell = create_machxo2_cell(ctx, id_FACADE_SLICE, "$PACKER_CONST");
    const_cell->params[id_LUT0_INITVAL] = Property(0, 16);
    const_cell->params[id_LUT1_INITVAL] = Property(0xFFFF, 16);

    std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(new NetInfo);
    gnd_net->name = ctx->id("$PACKER_GND_NET");
    gnd_net->driver.cell = const_cell.get();
    gnd_net->driver.port = id_F0;
    const_cell->ports.at(id_F0).net = gnd_net.get();

    std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(new NetInfo);
    vcc_net->name = ctx->id("$PACKER_VCC_NET");
    vcc_net->driver.cell = const_cell.get();
    vcc_net->driver.port = id_F1;
    const_cell->ports.at(id_F1).net = vcc_net.get();

    std::vector<IdString> dead_nets;

    for (auto &net : ctx->nets) {
        NetInfo *ni = net.second.get();
        if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
            IdString drv_cell = ni->driver.cell->name;
            set_net_constant(ctx, ni, gnd_net.get(), false);
            dead_nets.push_back(net.first);
            ctx->cells.erase(drv_cell);
        } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) {
            IdString drv_cell = ni->driver.cell->name;
            set_net_constant(ctx, ni, vcc_net.get(), true);
            dead_nets.push_back(net.first);
            ctx->cells.erase(drv_cell);
        }
    }

    ctx->cells[const_cell->name] = std::move(const_cell);
    ctx->nets[gnd_net->name] = std::move(gnd_net);
    ctx->nets[vcc_net->name] = std::move(vcc_net);

    for (auto dn : dead_nets) {
        ctx->nets.erase(dn);
    }
}

static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
{
    return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
           cell->type == ctx->id("$nextpnr_iobuf");
}

static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cell->type == id_FACADE_IO; }

static bool nextpnr_iob_connects_only_facade_iob(Context *ctx, CellInfo *iob, NetInfo *&top) {
    NPNR_ASSERT(is_nextpnr_iob(ctx, iob));

    if(iob->type == ctx->id("$nextpnr_ibuf")) {
        NetInfo *o = iob->ports.at(id_O).net;
        top = o;

        CellInfo *fio = net_only_drives(ctx, o, is_facade_iob, id_PAD, true);
        return fio != nullptr;
    } else if(iob->type == ctx->id("$nextpnr_obuf")) {
        NetInfo *i = iob->ports.at(id_I).net;
        top = i;

        // If connected to a FACADE_IO PAD, the net attached to an I port of an
        // $nextpnr_obuf will not have a driver, only users; an inout port
        // like PAD cannot be a driver in nextpnr. So net_driven_by won't
        // return anything. We exclude the IOB as one of the two users because
        // we already know that the net drives the $nextpnr_obuf.
        CellInfo *fio = net_only_drives(ctx, i, is_facade_iob, id_PAD, true, iob);
        return fio != nullptr;
    } else if(iob->type == ctx->id("$nextpnr_iobuf")) {
        NetInfo *o = iob->ports.at(id_O).net;
        top = o;

        // When split_io is enabled in a frontend (it is for JSON), the I and O
        // ports of a $nextpnr_iobuf are split; the I port connects to the
        // driver of the original net before IOB insertion, and the O port
        // connects everything else. Because FACADE_IO PADs cannot be a driver
        // in nextpnr, the we can safely ignore the I port of an $nextpnr_iobuf
        // for any JSON input we're interested in accepting.
        CellInfo *fio_o = net_only_drives(ctx, o, is_facade_iob, id_PAD, true);
        return fio_o != nullptr;
    }

    // Unreachable!
    NPNR_ASSERT(false);
}

// Pack IO buffers- Right now, all this does is remove $nextpnr_[io]buf cells.
// User is expected to manually instantiate FACADE_IO with BEL/IO_TYPE
// attributes.
static void pack_io(Context *ctx)
{
    pool<IdString> packed_cells;

    log_info("Packing IOs..\n");

    for (auto &cell : ctx->cells) {
        CellInfo *ci = cell.second.get();
        if (is_nextpnr_iob(ctx, ci)) {
            NetInfo *top;

            if(!nextpnr_iob_connects_only_facade_iob(ctx, ci, top))
                log_error("Top level net '%s' is not connected to a FACADE_IO PAD port.\n", top->name.c_str(ctx));

            if (ctx->verbose)
                log_info("Removing top-level IOBUF '%s' of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));

            for (auto &p : ci->ports)
                disconnect_port(ctx, ci, p.first);
            packed_cells.insert(ci->name);
        } else if (is_facade_iob(ctx, ci)) {
            // If FACADE_IO has LOC attribute, convert the LOC (pin) to a BEL
            // attribute and place FACADE_IO at resulting BEL location. A BEL
            // attribute already on a FACADE_IO is an error. Attributes on
            // the pin attached to the PAD of FACADE_IO are ignored by this
            // packing phase.
            auto loc_attr_cell = ci->attrs.find(ctx->id("LOC"));
            auto bel_attr_cell = ci->attrs.find(ctx->id("BEL"));

            if (loc_attr_cell != ci->attrs.end()) {
                if (bel_attr_cell != ci->attrs.end()) {
                    log_error("IO buffer %s has both a BEL attribute and LOC attribute.\n", ci->name.c_str(ctx));
                }

                log_info("found LOC attribute on IO buffer %s.\n", ci->name.c_str(ctx));
                std::string pin = loc_attr_cell->second.as_string();

                BelId pinBel = ctx->getPackagePinBel(pin);
                if (pinBel == BelId()) {
                    log_error("IO buffer '%s' constrained to pin '%s', which does not exist for package '%s'.\n",
                              ci->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
                } else {
                    log_info("pin '%s' constrained to Bel '%s'.\n", ci->name.c_str(ctx), ctx->nameOfBel(pinBel));
                }
                ci->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
            }
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
}

// Main pack function
bool Arch::pack()
{
    Context *ctx = getCtx();
    try {
        log_break();
        pack_constants(ctx);
        pack_io(ctx);
        pack_lut_lutffs(ctx);
        pack_remaining_ffs(ctx);
        ctx->settings[ctx->id("pack")] = 1;
        ctx->assignArchInfo();
        log_info("Checksum: 0x%08x\n", ctx->checksum());
        return true;
    } catch (log_execution_error_exception) {
        return false;
    }
}

NEXTPNR_NAMESPACE_END
<|endoftext|>


<commit_before>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"

#include "util.h"
#include "utilstrencodings.h"

#include <stdio.h>

#include <boost/foreach.hpp>
#include <boost/thread.hpp>

#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
    LogPrintf("LOCKCONTENTION: %s\n", pszName);
    LogPrintf("Locker: %s:%d\n", pszFile, nLine);
}
#endif /* DEBUG_LOCKCONTENTION */

#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
//    Thread 1 locks  A, then B, then C
//    Thread 2 locks  D, then C, then A
//     --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread tries to lock in a different order.
//

struct CLockLocation {
    CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
    {
        mutexName = pszName;
        sourceFile = pszFile;
        sourceLine = nLine;
        fTry = fTryIn;
    }

    std::string ToString() const
    {
        return mutexName + "  " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
    }

    std::string MutexName() const { return mutexName; }

    bool fTry;
private:
    std::string mutexName;
    std::string sourceFile;
    int sourceLine;
};

typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
typedef std::set<std::pair<void*, void*> > InvLockOrders;

struct LockData {
    // Very ugly hack: as the global constructs and destructors run single
    // threaded, we use this boolean to know whether LockData still exists,
    // as DeleteLock can get called by global CCriticalSection destructors
    // after LockData disappears.
    bool available;
    LockData() : available(true) {}
    ~LockData() { available = false; }

    LockOrders lockorders;
    InvLockOrders invlockorders;
    boost::mutex dd_mutex;
} static lockdata;

boost::thread_specific_ptr<LockStack> lockstack;

static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
    // We attempt to not assert on probably-not deadlocks by assuming that
    // a try lock will immediately have otherwise bailed if it had
    // failed to get the lock
    // We do this by, for the locks which triggered the potential deadlock,
    // in either lockorder, checking that the second of the two which is locked
    // is only a TRY_LOCK, ignoring locks if they are reentrant.
    bool firstLocked = false;
    bool secondLocked = false;
    bool onlyMaybeDeadlock = false;

    LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
    LogPrintf("Previous lock order was:\n");
    BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
        if (i.first == mismatch.first) {
            LogPrintf(" (1)");
            if (!firstLocked && secondLocked && i.second.fTry)
                onlyMaybeDeadlock = true;
            firstLocked = true;
        }
        if (i.first == mismatch.second) {
            LogPrintf(" (2)");
            if (!secondLocked && firstLocked && i.second.fTry)
                onlyMaybeDeadlock = true;
            secondLocked = true;
        }
        LogPrintf(" %s\n", i.second.ToString());
    }
    firstLocked = false;
    secondLocked = false;
    LogPrintf("Current lock order is:\n");
    BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
        if (i.first == mismatch.first) {
            LogPrintf(" (1)");
            if (!firstLocked && secondLocked && i.second.fTry)
                onlyMaybeDeadlock = true;
            firstLocked = true;
        }
        if (i.first == mismatch.second) {
            LogPrintf(" (2)");
            if (!secondLocked && firstLocked && i.second.fTry)
                onlyMaybeDeadlock = true;
            secondLocked = true;
        }
        LogPrintf(" %s\n", i.second.ToString());
    }
    assert(onlyMaybeDeadlock);
}

static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
{
    if (lockstack.get() == NULL)
        lockstack.reset(new LockStack);

    boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);

    (*lockstack).push_back(std::make_pair(c, locklocation));

    if (!fTry) {
        BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) {
            if (i.first == c)
                break;

            std::pair<void*, void*> p1 = std::make_pair(i.first, c);
            if (lockdata.lockorders.count(p1))
                continue;
            lockdata.lockorders[p1] = (*lockstack);

            std::pair<void*, void*> p2 = std::make_pair(c, i.first);
            lockdata.invlockorders.insert(p2);
            if (lockdata.lockorders.count(p2))
                potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
        }
    }
}

static void pop_lock()
{
    (*lockstack).pop_back();
}

void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
    push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
}

void LeaveCritical()
{
    pop_lock();
}

std::string LocksHeld()
{
    std::string result;
    BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
        result += i.second.ToString() + std::string("\n");
    return result;
}

void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
    BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
        if (i.first == cs)
            return;
    fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
    abort();
}

void DeleteLock(void* cs)
{
    if (!lockdata.available) {
        // We're already shutting down.
        return;
    }
    boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
    std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
    LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
    while (it != lockdata.lockorders.end() && it->first.first == cs) {
        std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
        lockdata.invlockorders.erase(invitem);
        lockdata.lockorders.erase(it++);
    }
    InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
    while (invit != lockdata.invlockorders.end() && invit->first == cs) {
        std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
        lockdata.lockorders.erase(invinvitem);
        lockdata.invlockorders.erase(invit++);
    }
}

#endif /* DEBUG_LOCKORDER */
<commit_msg>Always enforce lock strict lock ordering (try or not)<commit_after>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"

#include "util.h"
#include "utilstrencodings.h"

#include <stdio.h>

#include <boost/foreach.hpp>
#include <boost/thread.hpp>

#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
    LogPrintf("LOCKCONTENTION: %s\n", pszName);
    LogPrintf("Locker: %s:%d\n", pszFile, nLine);
}
#endif /* DEBUG_LOCKCONTENTION */

#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
//    Thread 1 locks  A, then B, then C
//    Thread 2 locks  D, then C, then A
//     --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread tries to lock in a different order.
//

struct CLockLocation {
    CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
    {
        mutexName = pszName;
        sourceFile = pszFile;
        sourceLine = nLine;
        fTry = fTryIn;
    }

    std::string ToString() const
    {
        return mutexName + "  " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
    }

    std::string MutexName() const { return mutexName; }

    bool fTry;
private:
    std::string mutexName;
    std::string sourceFile;
    int sourceLine;
};

typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
typedef std::set<std::pair<void*, void*> > InvLockOrders;

struct LockData {
    // Very ugly hack: as the global constructs and destructors run single
    // threaded, we use this boolean to know whether LockData still exists,
    // as DeleteLock can get called by global CCriticalSection destructors
    // after LockData disappears.
    bool available;
    LockData() : available(true) {}
    ~LockData() { available = false; }

    LockOrders lockorders;
    InvLockOrders invlockorders;
    boost::mutex dd_mutex;
} static lockdata;

boost::thread_specific_ptr<LockStack> lockstack;

static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
    LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
    LogPrintf("Previous lock order was:\n");
    BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
        if (i.first == mismatch.first) {
            LogPrintf(" (1)");
        }
        if (i.first == mismatch.second) {
            LogPrintf(" (2)");
        }
        LogPrintf(" %s\n", i.second.ToString());
    }
    LogPrintf("Current lock order is:\n");
    BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
        if (i.first == mismatch.first) {
            LogPrintf(" (1)");
        }
        if (i.first == mismatch.second) {
            LogPrintf(" (2)");
        }
        LogPrintf(" %s\n", i.second.ToString());
    }
    assert(false);
}

static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
{
    if (lockstack.get() == NULL)
        lockstack.reset(new LockStack);

    boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);

    (*lockstack).push_back(std::make_pair(c, locklocation));

    if (!fTry) {
        BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) {
            if (i.first == c)
                break;

            std::pair<void*, void*> p1 = std::make_pair(i.first, c);
            if (lockdata.lockorders.count(p1))
                continue;
            lockdata.lockorders[p1] = (*lockstack);

            std::pair<void*, void*> p2 = std::make_pair(c, i.first);
            lockdata.invlockorders.insert(p2);
            if (lockdata.lockorders.count(p2))
                potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
        }
    }
}

static void pop_lock()
{
    (*lockstack).pop_back();
}

void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
    push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
}

void LeaveCritical()
{
    pop_lock();
}

std::string LocksHeld()
{
    std::string result;
    BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
        result += i.second.ToString() + std::string("\n");
    return result;
}

void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
    BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
        if (i.first == cs)
            return;
    fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
    abort();
}

void DeleteLock(void* cs)
{
    if (!lockdata.available) {
        // We're already shutting down.
        return;
    }
    boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
    std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
    LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
    while (it != lockdata.lockorders.end() && it->first.first == cs) {
        std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
        lockdata.invlockorders.erase(invitem);
        lockdata.lockorders.erase(it++);
    }
    InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
    while (invit != lockdata.invlockorders.end() && invit->first == cs) {
        std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
        lockdata.lockorders.erase(invinvitem);
        lockdata.invlockorders.erase(invit++);
    }
}

#endif /* DEBUG_LOCKORDER */
<|endoftext|>


<commit_before>/**
 * @author Andrew Stone <a@stoney.io>
 * @copyright 2015 Andrew Stone
 *
 * This file is part of paratec and is released under the MIT License:
 * http://opensource.org/licenses/MIT
 */

#include "test.hpp"

namespace pt
{

sp<const Test> Test::bindTo(int64_t i, sp<const Opts> opts) const
{
	void *vitem = this->vec_ == nullptr ? nullptr : ((char *)this->vec_);
	auto test = mksp<Test>(static_cast<const _paratec &>(*this), i, vitem);

	test->opts_ = std::move(opts);
	const auto &filts = test->opts_->filter_.filts_;

	// By default, not disabled. Once matched in a negative filter, however,
	// can't be re-enabled.
	bool disabled = false;

	// If there are no filters, everything is enabled.
	bool enabled = filts.size() == 0;

	// Every test becomes disabled by default if a single positive filter is
	// given. Only things that pass the filter run.
	bool hasPosFilt = false;

	for (const auto &f : filts) {
		bool matches = strstr(test->name(), f.c_str()) == test->name();

		hasPosFilt |= !f.neg_;
		if (matches) {
			disabled |= f.neg_;
			enabled |= !f.neg_;
		}
	}

	if (hasPosFilt) {
		test->enabled_ = !disabled && enabled;
	} else {
		test->enabled_ = !disabled;
	}

	return test;
}

time::duration Test::bench(uint32_t n) const
{
	time::point start;
	time::point end;

	if (this->setup_ != NULL) {
		this->setup_();
	}

	start = time::now();
	this->fn_(this->i_, n, this->vitem_);
	end = time::now();

	if (this->teardown_ != NULL) {
		this->teardown_();
	}

	return end - start;
}

void Test::run() const
{
	if (this->setup_ != NULL) {
		this->setup_();
	}

	this->fn_(this->i_, 0, this->vitem_);

	if (this->teardown_ != NULL) {
		this->teardown_();
	}
}

void Test::cleanup() const
{
	if (this->cleanup_ != nullptr) {
		this->cleanup_();
	}
}
}
<commit_msg>Fix function name shadowing<commit_after>/**
 * @author Andrew Stone <a@stoney.io>
 * @copyright 2015 Andrew Stone
 *
 * This file is part of paratec and is released under the MIT License:
 * http://opensource.org/licenses/MIT
 */

#include "test.hpp"

namespace pt
{

sp<const Test> Test::bindTo(int64_t i, sp<const Opts> opts) const
{
	void *vitem = this->vec_ == nullptr ? nullptr : ((char *)this->vec_);
	auto test = mksp<Test>(static_cast<const _paratec &>(*this), i, vitem);

	test->opts_ = std::move(opts);
	const auto &filts = test->opts_->filter_.filts_;

	// By default, not disabled. Once matched in a negative filter, however,
	// can't be re-enabled.
	bool disable = false;

	// If there are no filters, everything is enabled.
	bool enable = filts.size() == 0;

	// Every test becomes disabled by default if a single positive filter is
	// given. Only things that pass the filter run.
	bool hasPosFilt = false;

	for (const auto &f : filts) {
		bool matches = strstr(test->name(), f.c_str()) == test->name();

		hasPosFilt |= !f.neg_;
		if (matches) {
			disable |= f.neg_;
			enable |= !f.neg_;
		}
	}

	if (hasPosFilt) {
		test->enabled_ = !disable && enable;
	} else {
		test->enabled_ = !disable;
	}

	return test;
}

time::duration Test::bench(uint32_t n) const
{
	time::point start;
	time::point end;

	if (this->setup_ != NULL) {
		this->setup_();
	}

	start = time::now();
	this->fn_(this->i_, n, this->vitem_);
	end = time::now();

	if (this->teardown_ != NULL) {
		this->teardown_();
	}

	return end - start;
}

void Test::run() const
{
	if (this->setup_ != NULL) {
		this->setup_();
	}

	this->fn_(this->i_, 0, this->vitem_);

	if (this->teardown_ != NULL) {
		this->teardown_();
	}
}

void Test::cleanup() const
{
	if (this->cleanup_ != nullptr) {
		this->cleanup_();
	}
}
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <new>
#include <algorithm>
#include <ctime>
#include <climits>
#include <unistd.h>
#include <cstring>

#include "Swimd.h"

using namespace std;

void fillRandomly(unsigned char* seq, int seqLength, int alphabetLength);
int * createSimpleScoreMatrix(int alphabetLength, int match, int mismatch);
int calculateSW(unsigned char query[], int queryLength, unsigned char ** db, int dbLength, int dbSeqLengths[],
                int gapOpen, int gapExt, int * scoreMatrix, int alphabetLength, int scores[]);
int calculateGlobal(unsigned char query[], int queryLength, unsigned char ** db, int dbLength, int dbSeqLengths[],
                    int gapOpen, int gapExt, int * scoreMatrix, int alphabetLength, int scores[], const char*);
void printInts(int a[], int aLength);
int maximum(int a[], int aLength);

int main(int argc, char * const argv[]) {

    char mode[32] = "SW"; // "SW", "NW", "HW" or "OV"
    int option;
    if (argc > 1) {
        strcpy(mode, argv[1]);
    }

    clock_t start, finish;
    srand(time(NULL));

    int alphabetLength = 4;
    int gapOpen = 11;
    int gapExt = 1;

    // Create random query
    int queryLength = 300;
    unsigned char query[queryLength];
    fillRandomly(query, queryLength, alphabetLength);

    // Create random database
    int dbLength = 5000;
    unsigned char * db[dbLength];
    int dbSeqsLengths[dbLength];
    for (int i = 0; i < dbLength; i++) {
        dbSeqsLengths[i] = 150 + rand()%200;
        db[i] = new unsigned char[dbSeqsLengths[i]];
        fillRandomly(db[i], dbSeqsLengths[i], alphabetLength);
    }

    /*
      printf("Query:\n");
      for (int i = 0; i < queryLength; i++)
      printf("%d ", query[i]);
      printf("\n");

      printf("Database:\n");
      for (int i = 0; i < dbLength; i++) {
      printf("%d. ", i);
      for (int j = 0; j < dbSeqsLengths[i]; j++)
      printf("%d ", db[i][j]);
      printf("\n");
      }
    */

    // Create score matrix
    int * scoreMatrix = createSimpleScoreMatrix(alphabetLength, 2, -1);

    // Run Swimd
    printf("Starting Swimd!\n");
    start = clock();
    int scores[dbLength];
    int resultCode;
    if (!strcmp(mode, "SW")) {
        resultCode = swimdSearchDatabase(query, queryLength, db, dbLength, dbSeqsLengths,
                                         gapOpen, gapExt, scoreMatrix, alphabetLength, scores);
    } else {
        resultCode = swimdSearchDatabaseGlobal(query, queryLength, db, dbLength, dbSeqsLengths,
                                               gapOpen, gapExt, scoreMatrix, alphabetLength, scores);
    }
    finish = clock();
    double time1 = ((double)(finish-start))/CLOCKS_PER_SEC;
    printf("Time: %lf\n", time1);

    if (resultCode != 0) {
        printf("Overflow happened!");
        exit(0);
    }
    // Print result
    printf("Result: ");
    printInts(scores, dbLength);
    printf("Maximum: %d\n", maximum(scores, dbLength));

    // Run normal SW
    printf("Starting normal!\n");
    start = clock();
    int scores2[dbLength];
    if (!strcmp(mode, "SW")) {
        resultCode = calculateSW(query, queryLength, db, dbLength, dbSeqsLengths,
                                 gapOpen, gapExt, scoreMatrix, alphabetLength, scores2);
    } else {
        resultCode = calculateGlobal(query, queryLength, db, dbLength, dbSeqsLengths,
                                     gapOpen, gapExt, scoreMatrix, alphabetLength, scores2, mode);
    }
    finish = clock();
    double time2 = ((double)(finish-start))/CLOCKS_PER_SEC;
    printf("Time: %lf\n", time2);

    // Print result
    printf("Result: ");
    printInts(scores2, dbLength);
    printf("Maximum: %d\n", maximum(scores2, dbLength));

    // Print differences in results (hopefully there are none!)
    printf("Diff: ");
    for (int i = 0; i < dbLength; i++)
        if (scores[i] != scores2[i]) {
            printf("%d (%d,%d)  ", i, scores[i], scores2[i]);
        }
    printf("\n");

    printf("Times faster: %lf\n", time2/time1);

    // Free allocated memory
    for (int i = 0; i < dbLength; i++) {
        delete[] db[i];
    }
    delete[] scoreMatrix;
}

void fillRandomly(unsigned char* seq, int seqLength, int alphabetLength) {
    for (int i = 0; i < seqLength; i++)
        seq[i] = rand() % 4;
}

int * createSimpleScoreMatrix(int alphabetLength, int match, int mismatch) {
    int * scoreMatrix = new int[alphabetLength*alphabetLength];
    for (int i = 0; i < alphabetLength; i++) {
        for (int j = 0; j < alphabetLength; j++)
            scoreMatrix[i * alphabetLength + j] = (i==j ? match : mismatch);
    }
    return scoreMatrix;
}

int calculateSW(unsigned char query[], int queryLength, unsigned char ** db, int dbLength, int dbSeqLengths[],
                int gapOpen, int gapExt, int * scoreMatrix, int alphabetLength, int scores[]) {
    int prevHs[queryLength];
    int prevEs[queryLength];

    for (int seqIdx = 0; seqIdx < dbLength; seqIdx++) {
        int maxH = 0;
        // Initialize all values to 0
        for (int i = 0; i < queryLength; i++) {
            prevHs[i] = prevEs[i] = 0;
        }

        for (int c = 0; c < dbSeqLengths[seqIdx]; c++) {
            int uF, uH, ulH;
            uF = uH = ulH = 0;

            for (int r = 0; r < queryLength; r++) {
                int E = max(prevHs[r] - gapOpen, prevEs[r] - gapExt);
                int F = max(uH - gapOpen, uF - gapExt);
                int score = scoreMatrix[query[r] * alphabetLength + db[seqIdx][c]];
                int H = max(0, max(E, max(F, ulH+score)));
                maxH = max(H, maxH);
                uF = F;
                uH = H;
                ulH = prevHs[r];

                prevHs[r] = H;
                prevEs[r] = E;
            }
        }

        scores[seqIdx] = maxH;
    }

    return 0;
}

int calculateGlobal(unsigned char query[], int queryLength, unsigned char ** db, int dbLength, int dbSeqLengths[],
                    int gapOpen, int gapExt, int * scoreMatrix, int alphabetLength, int scores[], const char* mode) {
    int prevHs[queryLength];
    int prevEs[queryLength];

    const int LOWER_SCORE_BOUND = INT_MIN + gapExt;

    for (int seqIdx = 0; seqIdx < dbLength; seqIdx++) {
        // Initialize all values to 0
        for (int i = 0; i < queryLength; i++) {
            prevHs[i] = 0;  // Or -gapOpen - i * gapExt if bounded
            prevEs[i] = LOWER_SCORE_BOUND;
        }
        int maxLastRowH = INT_MIN;

        int maxH; // max H in column
        for (int c = 0; c < dbSeqLengths[seqIdx]; c++) {
            int uF, uH, ulH;
            int H;
            uF = LOWER_SCORE_BOUND;
            uH = 0;
            ulH = 0; // TODO: Set it specially to zero for first cell of first column
            maxH = INT_MIN;

            for (int r = 0; r < queryLength; r++) {
                int E = max(prevHs[r] - gapOpen, prevEs[r] - gapExt);
                int F = max(uH - gapOpen, uF - gapExt);
                int score = scoreMatrix[query[r] * alphabetLength + db[seqIdx][c]];
                H = max(E, max(F, ulH+score));
                maxH = max(H, maxH);
                uF = F;
                uH = H;
                ulH = prevHs[r];

                prevHs[r] = H;
                prevEs[r] = E;
            }
            maxLastRowH = max(maxLastRowH, H);
        }

        scores[seqIdx] = max(maxLastRowH, maxH);
    }

    return 0;
}

void printInts(int a[], int aLength) {
    for (int i = 0; i < aLength; i++)
        printf("%d ", a[i]);
    printf("\n");
}

int maximum(int a[], int aLength) {
    int maximum = 0;
    for (int i = 0; i < aLength; i++)
        if (a[i] > maximum)
            maximum = a[i];
    return maximum;
}
<commit_msg>Now I have normal OV, NW and HW<commit_after>#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <new>
#include <algorithm>
#include <ctime>
#include <climits>
#include <unistd.h>
#include <cstring>

#include "Swimd.h"

using namespace std;

void fillRandomly(unsigned char* seq, int seqLength, int alphabetLength);
int * createSimpleScoreMatrix(int alphabetLength, int match, int mismatch);
int calculateSW(unsigned char query[], int queryLength, unsigned char ** db, int dbLength, int dbSeqLengths[],
                int gapOpen, int gapExt, int * scoreMatrix, int alphabetLength, int scores[]);
int calculateGlobal(unsigned char query[], int queryLength, unsigned char ** db, int dbLength, int dbSeqLengths[],
                    int gapOpen, int gapExt, int * scoreMatrix, int alphabetLength, int scores[], const char*);
void printInts(int a[], int aLength);
int maximum(int a[], int aLength);

int main(int argc, char * const argv[]) {

    char mode[32] = "SW"; // "SW", "NW", "HW" or "OV"
    int option;
    if (argc > 1) {
        strcpy(mode, argv[1]);
    }

    clock_t start, finish;
    srand(time(NULL));

    int alphabetLength = 4;
    int gapOpen = 11;
    int gapExt = 1;

    // Create random query
    int queryLength = 300;
    unsigned char query[queryLength];
    fillRandomly(query, queryLength, alphabetLength);

    // Create random database
    int dbLength = 500;
    unsigned char * db[dbLength];
    int dbSeqsLengths[dbLength];
    for (int i = 0; i < dbLength; i++) {
        dbSeqsLengths[i] = 150 + rand()%200;
        db[i] = new unsigned char[dbSeqsLengths[i]];
        fillRandomly(db[i], dbSeqsLengths[i], alphabetLength);
    }

    /*
      printf("Query:\n");
      for (int i = 0; i < queryLength; i++)
      printf("%d ", query[i]);
      printf("\n");

      printf("Database:\n");
      for (int i = 0; i < dbLength; i++) {
      printf("%d. ", i);
      for (int j = 0; j < dbSeqsLengths[i]; j++)
      printf("%d ", db[i][j]);
      printf("\n");
      }
    */

    // Create score matrix
    int * scoreMatrix = createSimpleScoreMatrix(alphabetLength, 2, -1);

    // Run Swimd
    printf("Starting Swimd!\n");
    start = clock();
    int scores[dbLength];
    int resultCode;
    /*if (!strcmp(mode, "SW")) {
        resultCode = swimdSearchDatabase(query, queryLength, db, dbLength, dbSeqsLengths,
                                         gapOpen, gapExt, scoreMatrix, alphabetLength, scores);
    } else {
        resultCode = swimdSearchDatabaseGlobal(query, queryLength, db, dbLength, dbSeqsLengths,
                                               gapOpen, gapExt, scoreMatrix, alphabetLength, scores);
                                               }*/
    resultCode = 0;
    finish = clock();
    double time1 = ((double)(finish-start))/CLOCKS_PER_SEC;
    printf("Time: %lf\n", time1);

    if (resultCode != 0) {
        printf("Overflow happened!");
        exit(0);
    }
    // Print result
    printf("Result: ");
    printInts(scores, dbLength);
    printf("Maximum: %d\n", maximum(scores, dbLength));

    // Run normal SW
    printf("Starting normal!\n");
    start = clock();
    int scores2[dbLength];
    if (!strcmp(mode, "SW")) {
        resultCode = calculateSW(query, queryLength, db, dbLength, dbSeqsLengths,
                                 gapOpen, gapExt, scoreMatrix, alphabetLength, scores2);
    } else {
        resultCode = calculateGlobal(query, queryLength, db, dbLength, dbSeqsLengths,
                                     gapOpen, gapExt, scoreMatrix, alphabetLength, scores2, mode);
    }
    finish = clock();
    double time2 = ((double)(finish-start))/CLOCKS_PER_SEC;
    printf("Time: %lf\n", time2);

    // Print result
    printf("Result: ");
    printInts(scores2, dbLength);
    printf("Maximum: %d\n", maximum(scores2, dbLength));

    // Print differences in results (hopefully there are none!)
    printf("Diff: ");
    for (int i = 0; i < dbLength; i++)
        if (scores[i] != scores2[i]) {
            printf("%d (%d,%d)  ", i, scores[i], scores2[i]);
        }
    printf("\n");

    printf("Times faster: %lf\n", time2/time1);

    // Free allocated memory
    for (int i = 0; i < dbLength; i++) {
        delete[] db[i];
    }
    delete[] scoreMatrix;
}

void fillRandomly(unsigned char* seq, int seqLength, int alphabetLength) {
    for (int i = 0; i < seqLength; i++)
        seq[i] = rand() % 4;
}

int * createSimpleScoreMatrix(int alphabetLength, int match, int mismatch) {
    int * scoreMatrix = new int[alphabetLength*alphabetLength];
    for (int i = 0; i < alphabetLength; i++) {
        for (int j = 0; j < alphabetLength; j++)
            scoreMatrix[i * alphabetLength + j] = (i==j ? match : mismatch);
    }
    return scoreMatrix;
}

int calculateSW(unsigned char query[], int queryLength, unsigned char ** db, int dbLength, int dbSeqLengths[],
                int gapOpen, int gapExt, int * scoreMatrix, int alphabetLength, int scores[]) {
    int prevHs[queryLength];
    int prevEs[queryLength];

    for (int seqIdx = 0; seqIdx < dbLength; seqIdx++) {
        int maxH = 0;
        // Initialize all values to 0
        for (int i = 0; i < queryLength; i++) {
            prevHs[i] = prevEs[i] = 0;
        }

        for (int c = 0; c < dbSeqLengths[seqIdx]; c++) {
            int uF, uH, ulH;
            uF = uH = ulH = 0;

            for (int r = 0; r < queryLength; r++) {
                int E = max(prevHs[r] - gapOpen, prevEs[r] - gapExt);
                int F = max(uH - gapOpen, uF - gapExt);
                int score = scoreMatrix[query[r] * alphabetLength + db[seqIdx][c]];
                int H = max(0, max(E, max(F, ulH+score)));
                maxH = max(H, maxH);
                uF = F;
                uH = H;
                ulH = prevHs[r];

                prevHs[r] = H;
                prevEs[r] = E;
            }
        }

        scores[seqIdx] = maxH;
    }

    return 0;
}

int calculateGlobal(unsigned char query[], int queryLength, unsigned char ** db, int dbLength, int dbSeqLengths[],
                    int gapOpen, int gapExt, int * scoreMatrix, int alphabetLength, int scores[], const char* mode) {
    int prevHs[queryLength];
    int prevEs[queryLength];

    const int LOWER_SCORE_BOUND = INT_MIN + gapExt;
    printf("Mode: %s\n", mode);

    for (int seqIdx = 0; seqIdx < dbLength; seqIdx++) {
        // Initialize all values to 0
        for (int r = 0; r < queryLength; r++) {
            // Query has fixed start and end if not OV
            prevHs[r] = !strcmp(mode, "OV") ? 0 : -1 * gapOpen - r * gapExt;
            prevEs[r] = LOWER_SCORE_BOUND;
        }
        int maxLastRowH = INT_MIN;

        int maxH; // max H in column
        int H;
        for (int c = 0; c < dbSeqLengths[seqIdx]; c++) {
            int uF, uH, ulH;
            uF = LOWER_SCORE_BOUND;
            if (!strcmp(mode, "NW")) { // Database sequence has fixed start and end only in NW
                uH = -1 * gapOpen - c * gapExt;
                ulH = uH + gapExt;
            } else {
                uH = ulH = 0;
            }
            if (c == 0)
                ulH = 0;

            maxH = INT_MIN;
            for (int r = 0; r < queryLength; r++) {
                int E = max(prevHs[r] - gapOpen, prevEs[r] - gapExt);
                int F = max(uH - gapOpen, uF - gapExt);
                int score = scoreMatrix[query[r] * alphabetLength + db[seqIdx][c]];
                H = max(E, max(F, ulH+score));
                maxH = max(H, maxH);
                uF = F;
                uH = H;
                ulH = prevHs[r];

                prevHs[r] = H;
                prevEs[r] = E;
            }
            maxLastRowH = max(maxLastRowH, H);
        }

        if (!strcmp(mode, "OV")) scores[seqIdx] = max(maxLastRowH, maxH);
        else if (!strcmp(mode, "HW")) scores[seqIdx] = maxLastRowH;
        else if (!strcmp(mode, "NW")) scores[seqIdx] = H;
        else return 1;
    }

    return 0;
}

void printInts(int a[], int aLength) {
    for (int i = 0; i < aLength; i++)
        printf("%d ", a[i]);
    printf("\n");
}

int maximum(int a[], int aLength) {
    int maximum = 0;
    for (int i = 0; i < aLength; i++)
        if (a[i] > maximum)
            maximum = a[i];
    return maximum;
}
<|endoftext|>