/*
 * besm6_punch.c: BESM-6 punchtape output
 *
 * Copyright (c) 2020, Leonid Broukhis
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * SERGE VAKULENKO OR LEONID BROUKHIS BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
 * OR OTHER DEALINGS IN THE SOFTWARE.

 * Except as contained in this notice, the name of Leonid Broukhis or
 * Serge Vakulenko shall not be used in advertising or otherwise to promote
 * the sale, use or other dealings in this Software without prior written
 * authorization from Leonid Broukhis and Serge Vakulenko.
 */
#include "besm6_defs.h"

t_stat pl_event (UNIT *u);

UNIT pl_unit [] = {
    { UDATA (pl_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
    { UDATA (pl_event, UNIT_SEQ+UNIT_ATTABLE, 0) },
};

#define PL1_READY 04000
#define PL2_READY 02000

#define SET_RDY2(x)      do READY2 |= x; while (0)
#define CLR_RDY2(x)      do READY2 &= ~(x); while (0)
#define ISSET_RDY2(x)    ((READY2 & (x)) != 0)
#define ISCLR_RDY2(x)    ((READY2 & (x)) == 0)

#define PL_RATE         (int)(12.5*MSEC)

unsigned char PL[2];

t_stat pl_reset (DEVICE *dptr);
t_stat pl_attach (UNIT *uptr, CONST char *cptr);
t_stat pl_detach (UNIT *uptr);

DEVICE pl_dev = {
    "PL", pl_unit, NULL, NULL,
    2, 8, 19, 1, 8, 50,
    NULL, NULL, &pl_reset, NULL, &pl_attach, &pl_detach,
    NULL, DEV_DISABLE | DEV_DEBUG
};

t_stat pl_reset (DEVICE *dptr)
{
    sim_cancel (&pl_unit[0]);
    sim_cancel (&pl_unit[1]);
    CLR_RDY2(PL1_READY | PL2_READY);
    if (pl_unit[0].flags & UNIT_ATT) {
        SET_RDY2(PL1_READY);
    }
    if (pl_unit[1].flags & UNIT_ATT) {
        SET_RDY2(PL2_READY);
    }
    if (pl_dev.dctrl)
        besm6_debug("reset READY2 := %08o", READY2);
    return SCPE_OK;
}

t_stat pl_attach (UNIT *u, CONST char *cptr)
{
    t_stat s;
    int num = u - pl_unit;
    s = attach_unit (u, cptr);
    if (s != SCPE_OK)
        return s;
    SET_RDY2(PL1_READY >> num);
    if (pl_dev.dctrl)
        besm6_debug("attach READY2 := %08o", READY2);
    return SCPE_OK;
}

t_stat pl_detach (UNIT *u)
{
    int num = u - pl_unit;
    CLR_RDY2(PL1_READY >> num);
    if (pl_dev.dctrl)
        besm6_debug("detach READY2 := %08o", READY2);
    return detach_unit (u);
}

void pl_control (int num, uint32 cmd)
{
    UNIT *u = &pl_unit[num];
    FILE *f = u->fileref;

    if (! ISSET_RDY2(PL1_READY >> num)) {
        if (pl_dev.dctrl)
            besm6_debug("<<< PL80-%d not ready", num);
        return;
    }
    putc(cmd & 0xff, f);
    PRP &= ~(PRP_PTAPE1_PUNCH >> num);
    CLR_RDY2(PL1_READY >> num);
    sim_activate_after(u, PL_RATE);
    if (pl_dev.dctrl) {
        besm6_debug("PL%d: punching %03o", num, cmd & 0xff);
        besm6_debug("punch READY2 := %08o", READY2);
    }
}

unsigned char unicode_to_gost (unsigned short val);

/*
 * The UPP code is the GOST 10859 code with odd parity.
 * UPP stood for "unit for preparation of punchards".
 */
static unsigned char unicode_to_upp (unsigned short ch) {
    unsigned char ret;
    ch = ret = unicode_to_gost (ch);
    ch = (ch & 0x55) + ((ch >> 1) & 0x55);
    ch = (ch & 0x33) + ((ch >> 2) & 0x33);
    ch = (ch & 0x0F) + ((ch >> 4) & 0x0F);
    return (ch & 1) ? ret : ret | 0x80;
}

t_stat pl_event (UNIT *u)
{
    int num = u - pl_unit;
    PRP |= PRP_PTAPE1_PUNCH >> num;
    SET_RDY2(PL1_READY >> num);
    if (pl_dev.dctrl) {
        besm6_debug("PL%d event, READY2 := %08o", num, READY2);
    }
    return SCPE_OK;
}
