Files
org-hyperion-cules/cmpsc.c
Fish (David B. Trout) d4a1b5e109 New 2012 CMPSC instruction implementation is now the default:
Original/legacy cmpsc.c implementation moved to altcmpsc.dll module.

Refer to Release Notes and/or README.CMPSC documents for more details.
2014-12-29 17:17:01 -08:00

2011 lines
80 KiB
C

/* CMPSC.C (c) Bernard van der Helm, 2000-2014 */
/* S/390 compression call instruction */
/*----------------------------------------------------------------------------*/
/* Implementation of the S/390 compression call instruction described in */
/* SA22-7208-01: Data Compression within the Hercules S/390 emulator. */
/* This implementation couldn't be done without the test programs from */
/* Mario Bezzi. Thanks Mario! Also special thanks to Greg Smith who */
/* introduced iregs, needed when a page fault occurs. */
/* */
/* Please pay attention to the Q Public License Version 1. This is open */
/* source, but you are not allowed to "reuse" parts for your own purpose */
/* without the author's written permission! */
/* */
/* Implemented "unique" features: */
/* 8 index symbol block fetching and storing, preventing cbn calculations. */
/* Expand symbol translation caching. */
/* Compression dead end determination and elimination. */
/* Proactive dead end determination and elimination. */
/* */
/* (c) Copyright Bernard van der Helm, 2000-2014 */
/* Noordwijkerhout, The Netherlands. */
/* */
/*----------------------------------------------------------------------------*/
#include "hstdinc.h" // (MUST be first #include in EVERY source file)
#if !defined(_HENGINE_DLL_)
#define _HENGINE_DLL_
#endif
#ifndef _CMPSC_C_
#define _CMPSC_C_
#endif /* #ifndef _CMPSC_C_ */
#if !defined( NOT_HERC ) // (building Hercules?)
#include "hercules.h"
#include "opcode.h"
#include "inline.h"
#endif
#ifdef FEATURE_COMPRESSION
/*============================================================================*/
/* Common */
/*============================================================================*/
/*----------------------------------------------------------------------------*/
/* Debugging options: */
/*----------------------------------------------------------------------------*/
#if 0
#define OPTION_CMPSC_DEBUG
#define TRUEFALSE(boolean) ((boolean) ? "True" : "False")
#endif /* #if 0|1 */
/*----------------------------------------------------------------------------*/
/* After a successful compression of characters to an index symbol or a */
/* successful translation of an index symbol to characters, the registers */
/* must be updated. */
/*----------------------------------------------------------------------------*/
#define ADJUSTREGS(r, regs, iregs, len) \
{ \
SET_GR_A((r), (iregs), (GR_A((r), (iregs)) + (len)) & ADDRESS_MAXWRAP((regs))); \
SET_GR_A((r) + 1, (iregs), GR_A((r) + 1, (iregs)) - (len)); \
}
/*----------------------------------------------------------------------------*/
/* Commit intermediate registers */
/*----------------------------------------------------------------------------*/
#ifdef OPTION_CMPSC_DEBUG
#define COMMITREGS(regs, iregs, r1, r2) \
__COMMITREGS((regs), (iregs), (r1), (r2)) \
logmsg("*** Regs committed\n");
#else
#define COMMITREGS(regs, iregs, r1, r2) \
__COMMITREGS((regs), (iregs), (r1), (r2))
#endif /* ifdef OPTION_CMPSC_DEBUG */
#define __COMMITREGS(regs, iregs, r1, r2) \
{ \
SET_GR_A(1, (regs), GR_A(1, (iregs))); \
SET_GR_A((r1), (regs), GR_A((r1), (iregs))); \
SET_GR_A((r1) + 1, (regs), GR_A((r1) + 1, (iregs))); \
SET_GR_A((r2), (regs), GR_A((r2), (iregs))); \
SET_GR_A((r2) + 1, (regs), GR_A((r2) + 1, (iregs))); \
}
/*----------------------------------------------------------------------------*/
/* Commit intermediate registers, except for GR1 */
/*----------------------------------------------------------------------------*/
#ifdef OPTION_CMPSC_DEBUG
#define COMMITREGS2(regs, iregs, r1, r2) \
__COMMITREGS2((regs), (iregs), (r1), (r2)) \
logmsg("*** Regs committed\n");
#else
#define COMMITREGS2(regs, iregs, r1, r2) \
__COMMITREGS2((regs), (iregs), (r1), (r2))
#endif /* #ifdef OPTION_CMPSC_DEBUG */
#define __COMMITREGS2(regs, iregs, r1, r2) \
{ \
SET_GR_A((r1), (regs), GR_A((r1), (iregs))); \
SET_GR_A((r1) + 1, (regs), GR_A((r1) + 1, (iregs))); \
SET_GR_A((r2), (regs), GR_A((r2), (iregs))); \
SET_GR_A((r2) + 1, (regs), GR_A((r2) + 1, (iregs))); \
}
/*----------------------------------------------------------------------------*/
/* Initialize intermediate registers */
/*----------------------------------------------------------------------------*/
#define INITREGS(iregs, regs, r1, r2) \
{ \
(iregs)->gr[1] = (regs)->gr[1]; \
(iregs)->gr[(r1)] = (regs)->gr[(r1)]; \
(iregs)->gr[(r1) + 1] = (regs)->gr[(r1) + 1]; \
(iregs)->gr[(r2)] = (regs)->gr[(r2)]; \
(iregs)->gr[(r2) + 1] = (regs)->gr[(r2) + 1]; \
}
#if __GEN_ARCH == 900
#undef INITREGS
#define INITREGS(iregs, regs, r1, r2) \
{ \
(iregs)->gr[1] = (regs)->gr[1]; \
(iregs)->gr[(r1)] = (regs)->gr[(r1)]; \
(iregs)->gr[(r1) + 1] = (regs)->gr[(r1) + 1]; \
(iregs)->gr[(r2)] = (regs)->gr[(r2)]; \
(iregs)->gr[(r2) + 1] = (regs)->gr[(r2) + 1]; \
(iregs)->psw.amode64 = (regs)->psw.amode64; \
}
#endif /* #if __GEN_ARCH == 900 */
/*----------------------------------------------------------------------------*/
/* General Purpose Register 0 macro's (GR0) */
/*----------------------------------------------------------------------------*/
/* cdss : compressed-data symbol size */
/* e : expansion operation */
/* f1 : format-1 sibling descriptors */
/* st : symbol-translation option */
/* zp : zero padding */
/* */
/* We recognize the zp flag and do conform POP nothing! We do something */
/* better: Eight index symbol processing. It saves a lot of time in cbn */
/* processing, index symbol fetching and storing. Please contact me if a */
/* 100% equal functionality is needed. I doubt it! */
/*----------------------------------------------------------------------------*/
#define GR0_cdss(regs) (((regs)->GR_L(0) & 0x0000F000) >> 12)
#define GR0_e(regs) ((regs)->GR_L(0) & 0x00000100)
#define GR0_f1(regs) ((regs)->GR_L(0) & 0x00000200)
#define GR0_st(regs) ((regs)->GR_L(0) & 0x00010000)
#define GR0_zp(regs) ((regs)->GR_L(0) & 0x00020000)
/*----------------------------------------------------------------------------*/
/* General Purpose Register 0 macro's (GR0) derived */
/*----------------------------------------------------------------------------*/
/* dcten : # dictionary entries */
/* dctsz : dictionary size */
/* smbsz : symbol size */
/*----------------------------------------------------------------------------*/
#define GR0_dcten(regs) (0x100 << GR0_cdss((regs)))
#define GR0_dctsz(regs) (0x800 << GR0_cdss((regs)))
#define GR0_smbsz(regs) (GR0_cdss((regs)) + 8)
/*----------------------------------------------------------------------------*/
/* General Purpose Register 1 macro's (GR1) */
/*----------------------------------------------------------------------------*/
/* cbn : compressed-data bit number */
/* dictor: compression dictionary or expansion dictionary */
/* sttoff: symbol-translation-table offset */
/*----------------------------------------------------------------------------*/
#define GR1_cbn(regs) (((regs)->GR_L(1) & 0x00000007))
#define GR1_dictor(regs) (GR_A(1, (regs)) & ((GREG) 0xFFFFFFFFFFFFF000ULL))
#define GR1_sttoff(regs) (((regs)->GR_L(1) & 0x00000FF8) << 4)
/*----------------------------------------------------------------------------*/
/* Set the compressed bit number in GR1 */
/*----------------------------------------------------------------------------*/
#define GR1_setcbn(regs, cbn) ((regs)->GR_L(1) = ((regs)->GR_L(1) & 0xFFFFFFF8) | ((cbn) & 0x00000007))
/*----------------------------------------------------------------------------*/
/* Constants */
/*----------------------------------------------------------------------------*/
#define MINPROC_SIZE 32768 /* Minumum processing size */
/*----------------------------------------------------------------------------*/
/* Typedefs and prototypes */
/*----------------------------------------------------------------------------*/
#ifndef NO_2ND_COMPILE
struct cc /* Compress context */
{
BYTE *cce; /* Character entry under investigation */
unsigned dctsz; /* Dictionary size */
BYTE deadadm[8192][0x100 / 8]; /* Dead end administration */
BYTE deadend; /* Dead end indicator */
BYTE *dest; /* Destination MADDR address */
BYTE *dict[32]; /* Dictionary MADDR addresses */
GREG dictor; /* Dictionary origin */
BYTE *edict[32]; /* Expansion dictionary MADDR addrs */
int f1; /* Indication format-1 sibling descr */
REGS *iregs; /* Intermediate registers */
U16 is[8]; /* Cache for 8 index symbols */
unsigned ofst; /* Latest fetched offset */
int r1; /* Guess what */
int r2; /* Yep */
REGS *regs; /* Registers */
BYTE searchadm[1][0x100 / 8]; /* Search administration */
unsigned smbsz; /* Symbol size */
BYTE *src; /* Source MADDR page address */
unsigned srclen; /* Source length left in page */
BYTE st; /* Symbol translation */
};
struct ec /* Expand context */
{
BYTE *dest; /* Destination MADDR page address */
BYTE *dict[32]; /* Dictionary MADDR addresses */
GREG dictor; /* Dictionary origin */
BYTE ec[8192 * 7]; /* Expanded index symbol cache */
int eci[8192]; /* Index within cache for is */
int ecl[8192]; /* Size of expanded is */
int ecwm; /* Water mark */
REGS *iregs; /* Intermediate registers */
BYTE oc[8 * 260]; /* Output cache */
unsigned ocl; /* Output cache length */
int r1; /* Guess what */
int r2; /* Yep */
REGS *regs; /* Registers */
unsigned smbsz; /* Symbol size */
BYTE *src; /* Source MADDR page address */
#ifdef OPTION_CMPSC_DEBUG
unsigned dbgac; /* Alphabet characters */
unsigned dbgbi; /* bytes in */
unsigned dbgbo; /* bytes out */
unsigned dbgch; /* Cache hits */
unsigned dbgiss; /* Expanded iss */
#endif /* #ifdef OPTION_CMPSC_DEBUG */
};
#endif /* #ifndef NO_2ND_COMPILE */
static void ARCH_DEP(cmpsc_compress)(int r1, int r2, REGS *regs, REGS *iregs);
static int ARCH_DEP(cmpsc_compress_single_is)(struct cc *cc);
static void ARCH_DEP(cmpsc_expand)(int r1, int r2, REGS *regs, REGS *iregs);
static void ARCH_DEP(cmpsc_expand_is)(struct ec *ec, U16 is);
static int ARCH_DEP(cmpsc_expand_single_is)(struct ec *ec);
static BYTE *ARCH_DEP(cmpsc_fetch_cce)(struct cc *cc, unsigned index);
static int ARCH_DEP(cmpsc_fetch_ch)(struct cc *cc);
static int ARCH_DEP(cmpsc_fetch_is)(struct ec *ec, U16 *is);
static void ARCH_DEP(cmpsc_fetch_iss)(struct ec *ec, U16 is[8]);
#ifdef OPTION_CMPSC_DEBUG
static void cmpsc_print_cce(BYTE *cce);
static void cmpsc_print_ece(BYTE *ece);
static void cmpsc_print_sd(int f1, BYTE *sd1, BYTE *sd2);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
static int ARCH_DEP(cmpsc_search_cce)(struct cc *cc, U16 *is);
static int ARCH_DEP(cmpsc_search_sd)(struct cc *cc, U16 *is);
static int ARCH_DEP(cmpsc_store_is)(struct cc *cc, U16 is);
static void ARCH_DEP(cmpsc_store_iss)(struct cc *cc);
static int ARCH_DEP(cmpsc_test_ec)(struct cc *cc, BYTE *cce);
static int ARCH_DEP(cmpsc_vstore)(struct ec *ec, BYTE *buf, unsigned len);
/*----------------------------------------------------------------------------*/
/* B263 CMPSC - Compression Call [RRE] */
/*----------------------------------------------------------------------------*/
DEF_INST(legacy_cmpsc)
{
REGS iregs; /* Intermediate registers */
int r1; /* Guess what */
int r2; /* Yep */
RRE(inst, regs, r1, r2);
#ifdef OPTION_CMPSC_DEBUG
logmsg("CMPSC: compression call\n");
logmsg(" r1 : GR%02d\n", r1);
logmsg(" address : " F_VADR "\n", regs->GR(r1));
logmsg(" length : " F_GREG "\n", regs->GR(r1 + 1));
logmsg(" r2 : GR%02d\n", r2);
logmsg(" address : " F_VADR "\n", regs->GR(r2));
logmsg(" length : " F_GREG "\n", regs->GR(r2 + 1));
logmsg(" GR00 : " F_GREG "\n", regs->GR(0));
logmsg(" zp : %s\n", TRUEFALSE(GR0_zp(regs)));
logmsg(" st : %s\n", TRUEFALSE(GR0_st(regs)));
logmsg(" cdss : %d\n", GR0_cdss(regs));
logmsg(" f1 : %s\n", TRUEFALSE(GR0_f1(regs)));
logmsg(" e : %s\n", TRUEFALSE(GR0_e(regs)));
logmsg(" GR01 : " F_GREG "\n", regs->GR(1));
logmsg(" dictor: " F_GREG "\n", GR1_dictor(regs));
logmsg(" sttoff: %08X\n", GR1_sttoff(regs));
logmsg(" cbn : %d\n", GR1_cbn(regs));
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Check the registers on even-odd pairs and valid compression-data symbol size */
if(unlikely(r1 & 0x01 || r2 & 0x01 || !GR0_cdss(regs) || GR0_cdss(regs) > 5))
ARCH_DEP(program_interrupt)(regs, PGM_SPECIFICATION_EXCEPTION);
/* Check for empty input */
if(unlikely(!GR_A(r2 + 1, regs)))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg(" Zero input, returning cc0\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
regs->psw.cc = 0;
return;
}
/* Check for empty output */
if(unlikely(!GR_A(r1 + 1, regs)))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg(" Zero output, returning cc1\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
regs->psw.cc = 1;
return;
}
/* Initialize intermediate registers */
INITREGS(&iregs, regs, r1, r2);
/* Now go to the requested function */
if(likely(GR0_e(regs)))
ARCH_DEP(cmpsc_expand)(r1, r2, regs, &iregs);
else
ARCH_DEP(cmpsc_compress)(r1, r2, regs, &iregs);
}
/*============================================================================*/
/* Compress */
/*============================================================================*/
/*----------------------------------------------------------------------------*/
/* Compression Character Entry macro's (CCE) */
/*----------------------------------------------------------------------------*/
/* act : additional-extension-character count */
/* cct : child count */
/* cptr : child pointer; index of first child */
/* d : double-character entry */
/* x(i) : examine child bit for children 1 to 5 */
/* y(i) : examine child bit for 6th/13th and 7th/14th sibling */
/*----------------------------------------------------------------------------*/
#define CCE_act(cce) ((cce)[1] >> 5)
#define CCE_cct(cce) ((cce)[0] >> 5)
#define CCE_cptr(cce) ((((cce)[1] & 0x1f) << 8) | (cce)[2])
#define CCE_d(cce) ((cce)[1] & 0x20)
#define CCE_x(cce, i) ((cce)[0] & (0x10 >> (i)))
#define CCE_y(cce, i) ((cce)[1] & (0x80 >> (i)))
/*----------------------------------------------------------------------------*/
/* Compression Character Entry macro's (CCE) derived */
/*----------------------------------------------------------------------------*/
/* cc(i) : child character */
/* ccc(i) : indication consecutive child character */
/* ccs : number of child characters */
/* ec(i) : additional extension character */
/* ecs : number of additional extension characters */
/* mcc : indication if siblings follow child characters */
/*----------------------------------------------------------------------------*/
#define CCE_cc(cce, i) ((cce)[3 + CCE_ecs((cce)) + (i)])
#define CCE_ccc(cce, i) (CCE_cc((cce), (i)) == CCE_cc((cce), 0))
#define CCE_ccs(cce) (CCE_cct((cce)) - (CCE_mcc((cce)) ? 1 : 0))
#define CCE_ec(cce, i) ((cce)[3 + (i)])
#define CCE_ecs(cce) ((CCE_cct((cce)) <= 1) ? CCE_act((cce)) : (CCE_d((cce)) ? 1 : 0))
#define CCE_mcc(cce) ((CCE_cct((cce)) + (CCE_d((cce)) ? 1 : 0) == 6))
/*----------------------------------------------------------------------------*/
/* Format-0 Sibling Descriptors macro's (SD0) */
/*----------------------------------------------------------------------------*/
/* sct : sibling count */
/* y(i) : examine child bit for siblings 1 to 5 */
/*----------------------------------------------------------------------------*/
#define SD0_sct(sd0) ((sd0)[0] >> 5)
#define SD0_y(sd0, i) ((sd0)[0] & (0x10 >> (i)))
/*----------------------------------------------------------------------------*/
/* Format-0 Sibling Descriptors macro's (SD0) derived */
/*----------------------------------------------------------------------------*/
/* ccc(i) : indication consecutive child character */
/* ecb(i) : examine child bit, if y then 6th/7th fetched from parent */
/* msc : indication if siblings follows last sibling */
/* sc(i) : sibling character */
/* scs : number of sibling characters */
/*----------------------------------------------------------------------------*/
#define SD0_ccc(sd0, i) (SD0_sc((sd0), (i)) == SD0_sc((sd0), 0))
#define SD0_ecb(sd0, i, cce, y) (((i) < 5) ? SD0_y((sd0), (i)) : (y) ? CCE_y((cce), ((i) - 5)) : 1)
#define SD0_msc(sd0) (!SD0_sct((sd0)))
#define SD0_sc(sd0, i) ((sd0)[1 + (i)])
#define SD0_scs(sd0) (SD0_msc((sd0)) ? 7 : SD0_sct((sd0)))
/*----------------------------------------------------------------------------*/
/* Format-1 Sibling Descriptors macro's (SD1) */
/*----------------------------------------------------------------------------*/
/* sct : sibling count */
/* y(i) : examine child bit for sibling 1 to 12 */
/*----------------------------------------------------------------------------*/
#define SD1_sct(sd1) ((sd1)[0] >> 4)
#define SD1_y(sd1, i) ((i) < 4 ? ((sd1)[0] & (0x08 >> (i))) : ((sd1)[1] & (0x800 >> (i))))
/*----------------------------------------------------------------------------*/
/* Format-1 Sibling Descriptors macro's (SD1) derived */
/*----------------------------------------------------------------------------*/
/* ccc(i) : indication consecutive child character */
/* ecb(i) : examine child bit, if y then 13th/14th fetched from parent */
/* msc : indication if siblings follows last sibling */
/* sc(i) : sibling character */
/* scs : number of sibling characters */
/*----------------------------------------------------------------------------*/
#define SD1_ccc(sd1, sd2, i) (SD1_sc((sd1), (sd2), (i)) == SD1_sc((sd1), (sd2), 0))
#define SD1_ecb(sd1, i, cce, y) (((i) < 12) ? SD1_y((sd1), (i)) : (y) ? CCE_y((cce), ((i) - 12)) : 1)
#define SD1_msc(sd1) ((SD1_sct((sd1)) == 15))
#define SD1_sc(sd1, sd2, i) ((i) < 6 ? (sd1)[2 + (i)] : (sd2)[(i) - 6])
#define SD1_scs(sd1) (SD1_msc((sd1)) ? 14 : SD1_sct((sd1)))
/*----------------------------------------------------------------------------*/
/* Format independent sibling descriptor macro's */
/*----------------------------------------------------------------------------*/
#define SD_ccc(f1, sd1, sd2, i) ((f1) ? SD1_ccc((sd1), (sd2), (i)) : SD0_ccc((sd1), (i)))
#define SD_ecb(f1, sd1, i, cce, y) ((f1) ? SD1_ecb((sd1), (i), (cce), (y)) : SD0_ecb((sd1), (i), (cce), (y)))
#define SD_msc(f1, sd1) ((f1) ? SD1_msc((sd1)) : SD0_msc((sd1)))
#define SD_sc(f1, sd1, sd2, i) ((f1) ? SD1_sc((sd1), (sd2), (i)) : SD0_sc((sd1), (i)))
#define SD_scs(f1, sd1) ((f1) ? SD1_scs((sd1)) : SD0_scs((sd1)))
/*----------------------------------------------------------------------------*/
/* ADJUSTREGS in compression context */
/*----------------------------------------------------------------------------*/
#define ADJUSTREGSC(cc, r, regs, iregs, len) \
{ \
ADJUSTREGS((r), (regs), (iregs), (len)) \
if(likely((cc)->srclen > (len))) \
{ \
(cc)->src += (len); \
(cc)->srclen -= (len); \
} \
else \
{ \
(cc)->src = NULL; \
(cc)->srclen = 0; \
} \
}
#define BIT_get(array, is, ch) ((array)[(is)][(ch) / 8] & (0x80 >> ((ch) % 8)))
#define BIT_set(array, is, ch) ((array)[(is)][(ch) / 8] |= (0x80 >> ((ch) % 8)))
/*============================================================================*/
/*----------------------------------------------------------------------------*/
/* cmpsc_compress */
/*----------------------------------------------------------------------------*/
static void ARCH_DEP(cmpsc_compress)(int r1, int r2, REGS *regs, REGS *iregs)
{
struct cc cc; /* Compression context */
int i; /* Index */
U16 is; /* Last matched index symbol */
int j; /* Index */
GREG srclen; /* Source length */
/* Initialize compression context */
cc.dctsz = GR0_dctsz(regs);
memset(cc.deadadm, 0, sizeof(cc.deadadm));
cc.dest = NULL;
memset(cc.dict, 0, sizeof(cc.dict));
memset(cc.edict, 0, sizeof(cc.edict));
cc.dictor = GR1_dictor(iregs);
cc.f1 = GR0_f1(regs);
cc.iregs = iregs;
cc.r1 = r1;
cc.r2 = r2;
cc.regs = regs;
cc.smbsz = GR0_smbsz(regs);
cc.src = NULL;
cc.srclen = 0;
cc.st = GR0_st(regs) ? 1 : 0;
/* Initialize values */
srclen = GR_A(cc.r2 + 1, cc.iregs);
/*--------------------------------------------------------------------------*/
/* Process individual index symbols until cbn becomes zero */
while(unlikely(GR1_cbn(cc.iregs)))
{
if(unlikely(ARCH_DEP(cmpsc_compress_single_is)(&cc)))
return;
}
/*--------------------------------------------------------------------------*/
/* Block processing, cbn stays zero */
while(likely(GR_A(cc.r1 + 1, cc.iregs) >= cc.smbsz))
{
for(i = 0; i < 8; i++)
{
/* Get the next character, return on end of source */
if(unlikely(!cc.src && ARCH_DEP(cmpsc_fetch_ch)(&cc)))
{
/* Write individual found index symbols */
for(j = 0; j < i; j++)
ARCH_DEP(cmpsc_store_is)(&cc, cc.is[j]);
COMMITREGS(cc.regs, cc.iregs, cc.r1, cc.r2);
return;
}
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_ch : %02X at " F_VADR "\n", *cc.src, GR_A(cc.r2, cc.iregs));
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Set the alphabet entry and adjust registers */
is = *cc.src;
ADJUSTREGSC(&cc, cc.r2, cc.regs, cc.iregs, 1);
/* Check for alphabet entry ch dead end combination */
if(unlikely(!(cc.src && BIT_get(cc.deadadm, is, *cc.src))))
{
/* Get the alphabet entry and try to find a child */
cc.cce = ARCH_DEP(cmpsc_fetch_cce)(&cc, is);
while(ARCH_DEP(cmpsc_search_cce)(&cc, &is))
{
/* Check for other dead end combination */
if(unlikely(cc.src && BIT_get(cc.deadadm, is, *cc.src)))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("dead end : %04X %02X encountered\n", is, *cc.src);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
break;
}
}
/* Registrate possible found dead ends */
if(unlikely(cc.deadend && cc.src))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("dead end : %04X in combination with", is);
for(j = 0; j < 0x100; j++)
{
if(!(j % 16))
logmsg("\n :");
if(BIT_get(cc.searchadm, 0, j))
logmsg(" ");
else
logmsg(" %02X", j);
}
logmsg("\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Registrate all discovered dead ends */
for(j = 0; j < 0x100 / 8; j++)
cc.deadadm[is][j] = ~cc.searchadm[0][j];
}
}
#ifdef OPTION_CMPSC_DEBUG
else
logmsg("dead end : %04X %02X encountered\n", is, *cc.src);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Write the last match */
cc.is[i] = is;
#ifdef OPTION_CMPSC_DEBUG
logmsg("compress : is %04X (%d)\n", is, i);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
}
/* Write index symbols and commit */
ARCH_DEP(cmpsc_store_iss)(&cc);
COMMITREGS2(cc.regs, cc.iregs, cc.r1, cc.r2);
/* Return with cc3 on interrupt pending after a minumum size of processing */
if(unlikely(srclen - GR_A(cc.r2 + 1, cc.iregs) >= MINPROC_SIZE && INTERRUPT_PENDING(cc.regs)))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("Interrupt pending, commit and return with cc3\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
cc.regs->psw.cc = 3;
return;
}
}
/*--------------------------------------------------------------------------*/
/* Process individual index symbols until end of destination (or source) */
while(!likely(ARCH_DEP(cmpsc_compress_single_is)(&cc)));
}
/*----------------------------------------------------------------------------*/
/* cmpsc_compress_single_is */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_compress_single_is)(struct cc *cc)
{
int i; /* Index */
U16 is; /* index symbol */
/* Get the next character, return -1 on end of source */
if(unlikely(!cc->src && ARCH_DEP(cmpsc_fetch_ch)(cc)))
return(-1);
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_ch : %02X at " F_VADR "\n", *cc->src, GR_A(cc->r2, cc->iregs));
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Set the alphabet entry and adjust registers */
is = *cc->src;
ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, 1);
/* Search for child when no src and no dead end combination */
if(unlikely(!(cc->src && BIT_get(cc->deadadm, is, *cc->src))))
{
/* Get the alphabet entry and try to find a child */
cc->cce = ARCH_DEP(cmpsc_fetch_cce)(cc, is);
while(ARCH_DEP(cmpsc_search_cce)(cc, &is))
{
/* Check for (found cce entry + ch) dead end combination */
if(unlikely(cc->src && BIT_get(cc->deadadm, is, *cc->src)))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("dead end : %04X %02X encountered\n", is, *cc->src);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
break;
}
}
/* Registrate possible found dead ends */
if(unlikely(cc->deadend && cc->src))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("dead end : %04X in combination with", is);
for(i = 0; i < 0x100; i++)
{
if(!(i % 16))
logmsg("\n :");
if(BIT_get(cc->searchadm, 0, i))
logmsg(" ");
else
logmsg(" %02X", i);
}
logmsg("\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Registrate all discovered dead ends */
for(i = 0; i < 0x100 / 8; i++)
cc->deadadm[is][i] = ~cc->searchadm[0][i];
}
}
#ifdef OPTION_CMPSC_DEBUG
else
logmsg("dead end : %04X %02X encountered\n", is, *cc->src);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Write the last match, return on end of destination */
if(unlikely(ARCH_DEP(cmpsc_store_is)(cc, is)))
return(-1);
/* Commit registers */
COMMITREGS(cc->regs, cc->iregs, cc->r1, cc->r2);
return(0);
}
/*----------------------------------------------------------------------------*/
/* cmpsc_fetch_cce (compression character entry) */
/*----------------------------------------------------------------------------*/
static BYTE *ARCH_DEP(cmpsc_fetch_cce)(struct cc *cc, unsigned index)
{
BYTE *cce; /* Compression child entry */
unsigned cct; /* Child count */
index *= 8;
if(unlikely(!cc->dict[index / 0x800]))
cc->dict[index / 0x800] = MADDR((cc->dictor + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs, ACCTYPE_READ, cc->regs->psw.pkey);
cce = &cc->dict[index / 0x800][index % 0x800];
ITIMER_SYNC((cc->dictor + index) & ADDRESS_MAXWRAP(cc->regs), 8 - 1, cc->regs);
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_cce: index %04X\n", index / 8);
cmpsc_print_cce(cce);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Check for data exception */
cct = CCE_cct(cce);
if(cct < 2)
{
if(unlikely(CCE_act(cce) > 4))
{
cc->regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt)(cc->regs, PGM_DATA_EXCEPTION);
}
}
else
{
if(!CCE_d(cce))
{
if(unlikely(cct == 7))
{
cc->regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt)(cc->regs, PGM_DATA_EXCEPTION);
}
}
else
{
if(unlikely(cct > 5))
{
cc->regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt)(cc->regs, PGM_DATA_EXCEPTION);
}
}
}
return(cce);
}
/*----------------------------------------------------------------------------*/
/* cmpsc_fetch_ch (character) */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_fetch_ch)(struct cc *cc)
{
/* Check for end of source condition */
if(unlikely(!GR_A(cc->r2 + 1, cc->iregs)))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_ch : reached end of source\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
cc->regs->psw.cc = 0;
return(-1);
}
/* Calculate source length in page */
cc->srclen = 0x800 - (GR_A(cc->r2, cc->iregs) & 0x7ff);
if(unlikely(GR_A(cc->r2 + 1, cc->iregs) < cc->srclen))
cc->srclen = (unsigned int) (GR_A(cc->r2 + 1, cc->iregs));
/* Get address */
cc->src = MADDR(GR_A(cc->r2, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs, ACCTYPE_READ, cc->regs->psw.pkey);
return(0);
}
#ifndef NO_2ND_COMPILE
#ifdef OPTION_CMPSC_DEBUG
/*----------------------------------------------------------------------------*/
/* cmpsc_print_cce (compression character entry) */
/*----------------------------------------------------------------------------*/
static void cmpsc_print_cce(BYTE *cce)
{
int j; /* Index */
int prt_detail; /* Switch for detailed printing */
logmsg(" cce : ");
prt_detail = 0;
for(j = 0; j < 8; j++)
{
if(!prt_detail && cce[j])
prt_detail = 1;
logmsg("%02X", cce[j]);
}
logmsg("\n");
if(prt_detail)
{
logmsg(" cct : %d\n", CCE_cct(cce));
switch(CCE_cct(cce))
{
case 0:
{
logmsg(" act : %d\n", (int) CCE_act(cce));
if(CCE_act(cce))
{
logmsg(" ec(s) :");
for(j = 0; j < CCE_ecs(cce); j++)
logmsg(" %02X", CCE_ec(cce, j));
logmsg("\n");
}
break;
}
case 1:
{
logmsg(" x1 : %c\n", (int) (CCE_x(cce, 0) ? '1' : '0'));
logmsg(" act : %d\n", (int) CCE_act(cce));
logmsg(" cptr : %04X\n", CCE_cptr(cce));
if(CCE_act(cce))
{
logmsg(" ec(s) :");
for(j = 0; j < CCE_ecs(cce); j++)
logmsg(" %02X", CCE_ec(cce, j));
logmsg("\n");
}
logmsg(" cc : %02X\n", CCE_cc(cce, 0));
break;
}
default:
{
logmsg(" x1..x5 : ");
for(j = 0; j < 5; j++)
logmsg("%c", (int) (CCE_x(cce, j) ? '1' : '0'));
logmsg("\n y1..y2 : ");
for(j = 0; j < 2; j++)
logmsg("%c", (int) (CCE_y(cce, j) ? '1' : '0'));
logmsg("\n d : %s\n", TRUEFALSE(CCE_d(cce)));
logmsg(" cptr : %04X\n", CCE_cptr(cce));
if(CCE_d(cce))
logmsg(" ec : %02X\n", CCE_ec(cce, 0));
logmsg(" ccs :");
for(j = 0; j < CCE_ccs(cce); j++)
logmsg(" %02X", CCE_cc(cce, j));
logmsg("\n");
break;
}
}
}
}
/*----------------------------------------------------------------------------*/
/* cmpsc_print_sd (sibling descriptor) */
/*----------------------------------------------------------------------------*/
static void cmpsc_print_sd(int f1, BYTE *sd1, BYTE *sd2)
{
int j; /* Index */
int prt_detail; /* Switch for detailed printing */
if(f1)
{
logmsg(" sd1 : ");
prt_detail = 0;
for(j = 0; j < 8; j++)
{
if(!prt_detail && sd1[j])
prt_detail = 1;
logmsg("%02X", sd1[j]);
}
for(j = 0; j < 8; j++)
{
if(!prt_detail && sd2[j])
prt_detail = 1;
logmsg("%02X", sd2[j]);
}
logmsg("\n");
if(prt_detail)
{
logmsg(" sct : %d\n", SD1_sct(sd1));
logmsg(" y1..y12: ");
for(j = 0; j < 12; j++)
logmsg("%c", (SD1_y(sd1, j) ? '1' : '0'));
logmsg("\n sc(s) :");
for(j = 0; j < SD1_scs(sd1); j++)
logmsg(" %02X", SD1_sc(sd1, sd2, j));
logmsg("\n");
}
}
else
{
logmsg(" sd0 : ");
prt_detail = 0;
for(j = 0; j < 8; j++)
{
if(!prt_detail && sd1[j])
prt_detail = 1;
logmsg("%02X", sd1[j]);
}
logmsg("\n");
if(prt_detail)
{
logmsg(" sct : %d\n", SD0_sct(sd1));
logmsg(" y1..y5 : ");
for(j = 0; j < 5; j++)
logmsg("%c", (SD0_y(sd1, j) ? '1' : '0'));
logmsg("\n sc(s) :");
for(j = 0; j < SD0_scs(sd1); j++)
logmsg(" %02X", SD0_sc(sd1, j));
logmsg("\n");
}
}
}
#endif /* #ifdef OPTION_CMPSC_DEBUG */
#endif /* #ifndef NO_2ND_COMPILE */
/*----------------------------------------------------------------------------*/
/* cmpsc_search_cce (compression character entry) */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_search_cce)(struct cc *cc, U16 *is)
{
BYTE *ccce; /* Child compression character entry */
int ccs; /* Number of child characters */
int i; /* Child character index */
int ind_search_siblings; /* Indicator for searching siblings */
/* Initialize values */
ccs = CCE_ccs(cc->cce);
/* Get the next character when there are children */
if(likely(ccs))
{
if(unlikely(!cc->src && ARCH_DEP(cmpsc_fetch_ch(cc))))
return(0);
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_ch : %02X at " F_VADR "\n", *cc->src, GR_A(cc->r2, cc->iregs));
#endif /* #ifdef OPTION_CMPSC_DEBUG */
memset(cc->searchadm, 0, sizeof(cc->searchadm));
cc->deadend = 1;
ind_search_siblings = 1;
/* Now check all children in parent */
for(i = 0; i < ccs; i++)
{
/* Stop searching when child tested and no consecutive child character */
if(unlikely(!ind_search_siblings && !CCE_ccc(cc->cce, i)))
return(0);
/* Compare character with child */
if(unlikely(*cc->src == CCE_cc(cc->cce, i)))
{
/* Child is tested, so stop searching for siblings and no dead end */
ind_search_siblings = 0;
cc->deadend = 0;
/* Check if child should not be examined */
if(unlikely(!CCE_x(cc->cce, i)))
{
/* No need to examine child, found the last match */
ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, 1);
*is = CCE_cptr(cc->cce) + i;
return(0);
}
/* Found a child get the character entry and check if additional extension characters match */
ccce = ARCH_DEP(cmpsc_fetch_cce)(cc, CCE_cptr(cc->cce) + i);
if(likely(!CCE_ecs(ccce) || !ARCH_DEP(cmpsc_test_ec)(cc, ccce)))
{
/* Set last match */
ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, (U32) CCE_ecs(ccce) + 1);
*is = CCE_cptr(cc->cce) + i;
#ifdef OPTION_CMPSC_DEBUG
logmsg("search_cce index %04X parent\n", *is);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Found a matching child, make it parent and keep searching */
cc->cce = ccce;
return(1);
}
}
BIT_set(cc->searchadm, 0, CCE_cc(cc->cce, i));
}
/* Are there siblings? */
if(likely(CCE_mcc(cc->cce)))
return(ARCH_DEP(cmpsc_search_sd)(cc, is));
}
else
{
/* No children, no extension character, always a dead end */
if(!CCE_act(cc->cce))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("dead end : %04X permanent dead end discovered\n", *is);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
memset(&cc->deadadm[*is], 0xff, 0x100 / 8);
}
cc->deadend = 0;
}
/* No siblings, write found index symbol */
return(0);
}
/*----------------------------------------------------------------------------*/
/* cmpsc_search_sd (sibling descriptor) */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_search_sd)(struct cc *cc, U16 *is)
{
BYTE *ccce; /* Child compression character entry */
int i; /* Sibling character index */
int ind_search_siblings; /* Indicator for keep searching */
U16 index; /* Index within dictionary */
int scs; /* Number of sibling characters */
BYTE *sd1; /* Sibling descriptor fmt-0|1 part 1 */
BYTE *sd2 = NULL; /* Sibling descriptor fmt-1 part 2 */
int sd_ptr; /* Pointer to sibling descriptor */
int searched; /* Number of children searched */
int y_in_parent; /* Indicator if y bits are in parent */
/* Initialize values */
ind_search_siblings = 1;
sd_ptr = CCE_ccs(cc->cce);
searched = sd_ptr;
y_in_parent = 1;
do
{
/* Get the sibling descriptor */
index = (CCE_cptr(cc->cce) + sd_ptr) * 8;
if(unlikely(!cc->dict[index / 0x800]))
cc->dict[index / 0x800] = MADDR((cc->dictor + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs, ACCTYPE_READ, cc->regs->psw.pkey);
sd1 = &cc->dict[index / 0x800][index % 0x800];
ITIMER_SYNC((cc->dictor + index) & ADDRESS_MAXWRAP(cc->regs), 8 - 1, cc->regs);
/* If format-1, get second half from the expansion dictionary */
if(cc->f1)
{
if(unlikely(!cc->edict[index / 0x800]))
cc->edict[index / 0x800] = MADDR((cc->dictor + cc->dctsz + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs, ACCTYPE_READ, cc->regs->psw.pkey);
sd2 = &cc->edict[index / 0x800][index % 0x800];
ITIMER_SYNC((cc->dictor + cc->dctsz + index) & ADDRESS_MAXWRAP(cc->regs), 8 - 1, cc->regs);
#ifdef OPTION_CMPSC_DEBUG
/* Print before possible exception */
logmsg("fetch_sd1: index %04X\n", CCE_cptr(cc->cce) + sd_ptr);
cmpsc_print_sd(1, sd1, sd2);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Check for data exception */
if(unlikely(!SD1_sct(sd1)))
{
cc->regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt)((cc->regs), PGM_DATA_EXCEPTION);
}
}
#ifdef OPTION_CMPSC_DEBUG
else
{
logmsg("fetch_sd0: index %04X\n", CCE_cptr(cc->cce) + sd_ptr);
cmpsc_print_sd(0, sd1, sd2);
}
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Check all children in sibling descriptor */
scs = SD_scs(cc->f1, sd1);
for(i = 0; i < scs; i++)
{
/* Stop searching when child tested and no consecutive child character */
if(unlikely(!ind_search_siblings && !SD_ccc(cc->f1, sd1, sd2, i)))
return(0);
if(unlikely(*cc->src == SD_sc(cc->f1, sd1, sd2, i)))
{
/* Child is tested, so stop searching for siblings and no dead end */
ind_search_siblings = 0;
cc->deadend = 0;
/* Check if child should not be examined */
if(unlikely(!SD_ecb(cc->f1, sd1, i, cc->cce, y_in_parent)))
{
/* No need to examine child, found the last match */
ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, 1);
*is = CCE_cptr(cc->cce) + sd_ptr + i + 1;
return(0);
}
/* Found a child get the character entry and check if additional extension characters match */
ccce = ARCH_DEP(cmpsc_fetch_cce)(cc, CCE_cptr(cc->cce) + sd_ptr + i + 1);
if(likely(!CCE_ecs(ccce) || !ARCH_DEP(cmpsc_test_ec)(cc, ccce)))
{
/* Set last match */
ADJUSTREGSC(cc, cc->r2, cc->regs, cc->iregs, (U32) CCE_ecs(ccce) + 1);
*is = CCE_cptr(cc->cce) + sd_ptr + i + 1;
#ifdef OPTION_CMPSC_DEBUG
logmsg("search_sd: index %04X parent\n", *is);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Found a matching child, make it parent and keep searching */
cc->cce = ccce;
return(1);
}
}
BIT_set(cc->searchadm, 0, SD_sc(cc->f1, sd1, sd2, i));
}
/* Next sibling follows last possible child */
sd_ptr += scs + 1;
/* test for searching child 261 */
searched += scs;
if(unlikely(searched > 260))
{
cc->regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt)((cc->regs), PGM_DATA_EXCEPTION);
}
/* We get the next sibling descriptor, no y bits in parent for him */
y_in_parent = 0;
}
while(ind_search_siblings && SD_msc(cc->f1, sd1));
return(0);
}
/*----------------------------------------------------------------------------*/
/* cmpsc_store_is (index symbol) */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_store_is)(struct cc *cc, U16 is)
{
unsigned cbn; /* Compressed-data bit number */
U32 set_mask; /* Mask to set the bits */
BYTE work[3]; /* Work bytes */
/* Initialize values */
cbn = GR1_cbn(cc->iregs);
/* Can we write an index or interchange symbol */
if(unlikely(GR_A(cc->r1 + 1, cc->iregs) < 3 && ((cbn + cc->smbsz - 1) / 8) >= GR_A(cc->r1 + 1, cc->iregs)))
{
cc->regs->psw.cc = 1;
#ifdef OPTION_CMPSC_DEBUG
logmsg("store_is : end of output buffer\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
return(-1);
}
/* Check if symbol translation is requested */
if(unlikely(cc->st))
{
/* Get the interchange symbol */
ARCH_DEP(vfetchc)(work, 1, (cc->dictor + GR1_sttoff(cc->iregs) + is * 2) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs);
#ifdef OPTION_CMPSC_DEBUG
logmsg("store_is : %04X -> %02X%02X\n", is, work[0], work[1]);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* set index_symbol to interchange symbol */
is = (work[0] << 8) + work[1];
}
/* Allign set mask */
set_mask = ((U32) is) << (24 - cc->smbsz - cbn);
/* Calculate first byte */
if(likely(cbn))
{
work[0] = ARCH_DEP(vfetchb)(GR_A(cc->r1, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs);
work[0] |= (set_mask >> 16) & 0xff;
}
else
work[0] = (set_mask >> 16) & 0xff;
/* Calculate second byte */
work[1] = (set_mask >> 8) & 0xff;
/* Calculate possible third byte and store */
if(unlikely((cc->smbsz + cbn) > 16))
{
work[2] = set_mask & 0xff;
ARCH_DEP(vstorec)(work, 2, GR_A(cc->r1, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs);
}
else
ARCH_DEP(vstorec)(work, 1, GR_A(cc->r1, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs);
/* Adjust destination registers */
ADJUSTREGS(cc->r1, cc->regs, cc->iregs, (cbn + cc->smbsz) / 8);
/* Calculate and set the new Compressed-data Bit Number */
GR1_setcbn(cc->iregs, (cbn + cc->smbsz) % 8);
#ifdef OPTION_CMPSC_DEBUG
logmsg("store_is : %04X, cbn=%d, GR%02d=" F_VADR ", GR%02d=" F_GREG "\n", is, GR1_cbn(cc->iregs), cc->r1, cc->iregs->GR(cc->r1), cc->r1 + 1, cc->iregs->GR(cc->r1 + 1));
#endif /* #ifdef OPTION_CMPSC_DEBUG */
return(0);
}
/*----------------------------------------------------------------------------*/
/* cmpsc_store_iss (index symbols) */
/*----------------------------------------------------------------------------*/
static void ARCH_DEP(cmpsc_store_iss)(struct cc *cc)
{
GREG dictor; /* Dictionary origin */
int i;
U16 *is; /* Index symbol array */
unsigned len1; /* Length in first page */
BYTE *main1; /* Address first page */
BYTE mem[13]; /* Build buffer */
unsigned ofst; /* Offset within page */
BYTE *sk; /* Storage key */
/* Check if symbol translation is requested */
if(unlikely(cc->st))
{
dictor = cc->dictor + GR1_sttoff(cc->iregs);
for(i = 0; i < 8; i++)
{
/* Get the interchange symbol */
ARCH_DEP(vfetchc)(mem, 1, (dictor + cc->is[i] * 2) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs);
#ifdef OPTION_CMPSC_DEBUG
logmsg("store_iss: %04X -> %02X%02X\n", cc->is[i], mem[0], mem[1]);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* set index_symbol to interchange symbol */
cc->is[i] = (mem[0] << 8) + mem[1];
}
}
/* Calculate buffer for 8 index symbols */
is = cc->is;
switch(cc->smbsz)
{
case 9: /* 9-bits */
{
/* 0 1 2 3 4 5 6 7 8 */
/* 012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 012345678012345678012345678012345678012345678012345678012345678012345678 */
/* 0 1 2 3 4 5 6 7 */
mem[0] = (BYTE) ( (is[0] >> 1));
mem[1] = (BYTE) ((is[0] << 7) | (is[1] >> 2));
mem[2] = (BYTE) ((is[1] << 6) | (is[2] >> 3));
mem[3] = (BYTE) ((is[2] << 5) | (is[3] >> 4));
mem[4] = (BYTE) ((is[3] << 4) | (is[4] >> 5));
mem[5] = (BYTE) ((is[4] << 3) | (is[5] >> 6));
mem[6] = (BYTE) ((is[5] << 2) | (is[6] >> 7));
mem[7] = (BYTE) ((is[6] << 1) | (is[7] >> 8));
mem[8] = (BYTE) ((is[7]) );
break;
}
case 10: /* 10-bits */
{
/* 0 1 2 3 4 5 6 7 8 9 */
/* 01234567012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
/* 0 1 2 3 4 5 6 7 */
mem[0] = (BYTE) ( (is[0] >> 2));
mem[1] = (BYTE) ((is[0] << 6) | (is[1] >> 4));
mem[2] = (BYTE) ((is[1] << 4) | (is[2] >> 6));
mem[3] = (BYTE) ((is[2] << 2) | (is[3] >> 8));
mem[4] = (BYTE) ((is[3]) );
mem[5] = (BYTE) ( (is[4] >> 2));
mem[6] = (BYTE) ((is[4] << 6) | (is[5] >> 4));
mem[7] = (BYTE) ((is[5] << 4) | (is[6] >> 6));
mem[8] = (BYTE) ((is[6] << 2) | (is[7] >> 8));
mem[9] = (BYTE) ((is[7]) );
break;
}
case 11: /* 11-bits */
{
/* 0 1 2 3 4 5 6 7 8 9 a */
/* 0123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a */
/* 0 1 2 3 4 5 6 7 */
mem[ 0] = (BYTE) ( (is[0] >> 3));
mem[ 1] = (BYTE) ((is[0] << 5) | (is[1] >> 6));
mem[ 2] = (BYTE) ((is[1] << 2) | (is[2] >> 9));
mem[ 3] = (BYTE) ( (is[2] >> 1));
mem[ 4] = (BYTE) ((is[2] << 7) | (is[3] >> 4));
mem[ 5] = (BYTE) ((is[3] << 4) | (is[4] >> 7));
mem[ 6] = (BYTE) ((is[4] << 1) | (is[5] >> 10));
mem[ 7] = (BYTE) ( (is[5] >> 2));
mem[ 8] = (BYTE) ((is[5] << 6) | (is[6] >> 5));
mem[ 9] = (BYTE) ((is[6] << 3) | (is[7] >> 8));
mem[10] = (BYTE) ((is[7]) );
break;
}
case 12: /* 12-bits */
{
/* 0 1 2 3 4 5 6 7 8 9 a b */
/* 012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab */
/* 0 1 2 3 4 5 6 7 */
mem[ 0] = (BYTE) ( (is[0] >> 4));
mem[ 1] = (BYTE) ((is[0] << 4) | (is[1] >> 8));
mem[ 2] = (BYTE) ((is[1]) );
mem[ 3] = (BYTE) ( (is[2] >> 4));
mem[ 4] = (BYTE) ((is[2] << 4) | (is[3] >> 8));
mem[ 5] = (BYTE) ((is[3]) );
mem[ 6] = (BYTE) ( (is[4] >> 4));
mem[ 7] = (BYTE) ((is[4] << 4) | (is[5] >> 8));
mem[ 8] = (BYTE) ((is[5]) );
mem[ 9] = (BYTE) ( (is[6] >> 4));
mem[10] = (BYTE) ((is[6] << 4) | (is[7] >> 8));
mem[11] = (BYTE) ((is[7]) );
break;
}
case 13: /* 13-bits */
{
/* 0 1 2 3 4 5 6 7 8 9 a b c */
/* 01234567012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc */
/* 0 1 2 3 4 5 6 7 */
mem[ 0] = (BYTE) ( (is[0] >> 5));
mem[ 1] = (BYTE) ((is[0] << 3) | (is[1] >> 10));
mem[ 2] = (BYTE) ( (is[1] >> 2));
mem[ 3] = (BYTE) ((is[1] << 6) | (is[2] >> 7));
mem[ 4] = (BYTE) ((is[2] << 1) | (is[3] >> 12));
mem[ 5] = (BYTE) ( (is[3] >> 4));
mem[ 6] = (BYTE) ((is[3] << 4) | (is[4] >> 9));
mem[ 7] = (BYTE) ( (is[4] >> 1));
mem[ 8] = (BYTE) ((is[4] << 7) | (is[5] >> 6));
mem[ 9] = (BYTE) ((is[5] << 2) | (is[6] >> 11));
mem[10] = (BYTE) ( (is[6] >> 3));
mem[11] = (BYTE) ((is[6] << 5) | (is[7] >> 8));
mem[12] = (BYTE) ((is[7]) );
break;
}
}
/* Fingers crossed that we stay within one page */
ofst = GR_A(cc->r1, cc->iregs) & 0x7ff;
if(likely(ofst + cc->smbsz <= 0x800))
{
if(unlikely(!cc->dest))
cc->dest = MADDR((GR_A(cc->r1, cc->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs, ACCTYPE_WRITE, cc->regs->psw.pkey);
memcpy(&cc->dest[ofst], mem, cc->smbsz);
ITIMER_UPDATE(GR_A(cc->r1, cc->iregs) & ADDRESS_MAXWRAP(cc->regs), cc->smbsz - 1, cc->regs);
/* Perfect fit? */
if(unlikely(ofst + cc->smbsz == 0x800))
cc->dest = NULL;
}
else
{
/* We need 2 pages */
if(unlikely(!cc->dest))
main1 = MADDR((GR_A(cc->r1, cc->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs, ACCTYPE_WRITE_SKP, cc->regs->psw.pkey);
else
main1 = cc->dest;
sk = cc->regs->dat.storkey;
len1 = 0x800 - ofst;
cc->dest = MADDR((GR_A(cc->r1, cc->iregs) + len1) & ADDRESS_MAXWRAP(cc->regs), cc->r1, cc->regs, ACCTYPE_WRITE, cc->regs->psw.pkey);
memcpy(&main1[ofst], mem, len1);
memcpy(cc->dest, &mem[len1], cc->smbsz - len1);
*sk |= (STORKEY_REF | STORKEY_CHANGE);
}
ADJUSTREGS(cc->r1, cc->regs, cc->iregs, cc->smbsz);
#ifdef OPTION_CMPSC_DEBUG
logmsg("store_iss:");
for(i = 0; i < 8; i++)
logmsg(" %04X", cc->is[i]);
logmsg(", GR%02d=" F_VADR ", GR%02d=" F_GREG "\n", cc->r1, cc->iregs->GR(cc->r1), cc->r1 + 1, cc->iregs->GR(cc->r1 + 1));
#endif /* #ifdef OPTION_CMPSC_DEBUG */
}
/*----------------------------------------------------------------------------*/
/* cmpsc_test_ec (extension characters) */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_test_ec)(struct cc *cc, BYTE *cce)
{
BYTE buf[4]; /* Cross page buffer */
BYTE *src; /* Source pointer */
/* No dead end */
cc->deadend = 0;
/* Get address of source */
if(likely(cc->srclen > (unsigned) CCE_ecs(cce)))
{
src = &cc->src[1];
ITIMER_SYNC((GR_A(cc->r2, cc->iregs) + 1) & ADDRESS_MAXWRAP(cc->regs), CCE_ecs(cce) - 1, cc->regs);
}
else
{
/* Return nomatch on end of source condition */
if(unlikely(GR_A(cc->r2 + 1, cc->iregs) <= (unsigned) CCE_ecs(cce)))
return(1);
/* Get the cross page data */
ARCH_DEP(vfetchc)(buf, CCE_ecs(cce) - 1, (GR_A(cc->r2, cc->iregs) + 1) & ADDRESS_MAXWRAP(cc->regs), cc->r2, cc->regs);
src = buf;
}
/* Return results compare */
return(memcmp(src, &CCE_ec(cce, 0), CCE_ecs(cce)));
}
/*============================================================================*/
/* Expand */
/*============================================================================*/
/*----------------------------------------------------------------------------*/
/* Expansion Character Entry macro's (ECE) */
/*----------------------------------------------------------------------------*/
/* bit34 : indication of bits 3 and 4 (what else ;-) */
/* csl : complete symbol length */
/* ofst : offset from current position in output area */
/* pptr : predecessor pointer */
/* psl : partial symbol length */
/*----------------------------------------------------------------------------*/
#define ECE_bit34(ece) ((ece)[0] & 0x18)
#define ECE_csl(ece) ((ece)[0] & 0x07)
#define ECE_ofst(ece) ((ece)[7])
#define ECE_pptr(ece) ((((ece)[0] & 0x1f) << 8) | (ece)[1])
#define ECE_psl(ece) ((ece)[0] >> 5)
/*----------------------------------------------------------------------------*/
/* cmpsc_expand */
/*----------------------------------------------------------------------------*/
static void ARCH_DEP(cmpsc_expand)(int r1, int r2, REGS *regs, REGS *iregs)
{
GREG destlen; /* Destination length */
struct ec ec; /* Expand cache */
int i; /* Index */
U16 iss[8] = {0}; /* Index symbols */
/* Initialize values */
destlen = GR_A(r1 + 1, iregs);
/* Initialize expansion context */
ec.dest = NULL;
ec.dictor = GR1_dictor(iregs);
memset(ec.dict, 0, sizeof(ec.dict));
/* Initialize expanded index symbol cache and prefill with alphabet entries */
memset(ec.ecl, 0, sizeof(ec.ecl));
for(i = 0; i < 256; i++) /* Alphabet entries */
{
ec.ec[i] = i;
ec.eci[i] = i;
ec.ecl[i] = 1;
}
ec.ecwm = 256; /* Set watermark after alphabet part */
ec.iregs = iregs;
ec.r1 = r1;
ec.r2 = r2;
ec.regs = regs;
ec.smbsz = GR0_smbsz(regs);
ec.src = NULL;
#ifdef OPTION_CMPSC_DEBUG
ec.dbgac = 0;
ec.dbgbi = 0;
ec.dbgbo = 0;
ec.dbgch = 0;
ec.dbgiss = 0;
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/*--------------------------------------------------------------------------*/
/* Process individual index symbols until cbn becomes zero */
while(unlikely(GR1_cbn(ec.iregs)))
{
if(unlikely(ARCH_DEP(cmpsc_expand_single_is)(&ec)))
return;
}
/*--------------------------------------------------------------------------*/
/* Block processing, cbn stays zero */
while(likely(GR_A(ec.r2 + 1, ec.iregs) >= ec.smbsz))
{
ARCH_DEP(cmpsc_fetch_iss)(&ec, iss);
ec.ocl = 0; /* Initialize output cache */
for(i = 0; i < 8; i++)
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("expand : is %04X (%d)\n", iss[i], i);
ec.dbgiss++;
#endif /* #ifdef OPTION_CMPSC_DEBUG */
if(unlikely(!ec.ecl[iss[i]]))
ARCH_DEP(cmpsc_expand_is)(&ec, iss[i]);
else
{
memcpy(&ec.oc[ec.ocl], &ec.ec[ec.eci[iss[i]]], ec.ecl[iss[i]]);
ec.ocl += ec.ecl[iss[i]];
#ifdef OPTION_CMPSC_DEBUG
if(iss[i] < 0x100)
ec.dbgac++;
else
ec.dbgch++;
#endif /* #ifdef OPTION_CMPSC_DEBUG */
}
}
#ifdef OPTION_CMPSC_DEBUG
ec.dbgbi += ec.smbsz;
ec.dbgbo += ec.ocl;
logmsg("Stats: iss %6u; ach %6u: %3d%; hts %6u: %3d%; bin %6u, out %6u: %6d%\n", ec.dbgiss, ec.dbgac, ec.dbgac * 100 / ec.dbgiss, ec.dbgch, ec.dbgch * 100 / ec.dbgiss, ec.dbgbi, ec.dbgbo, ec.dbgbo * 100 / ec.dbgbi);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Write and commit, cbn unchanged, so no commit for GR1 needed */
if(unlikely(ARCH_DEP(cmpsc_vstore)(&ec, ec.oc, ec.ocl)))
return;
/* Commit registers */
COMMITREGS2(ec.regs, ec.iregs, ec.r1, ec.r2);
/* Return with cc3 on interrupt pending */
if(unlikely(destlen - GR_A(ec.r1 + 1, ec.iregs) >= MINPROC_SIZE && INTERRUPT_PENDING(ec.regs)))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("Interrupt pending, commit and return with cc3\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
ec.regs->psw.cc = 3;
return;
}
}
/*--------------------------------------------------------------------------*/
/* Process individual index symbols until end of source (or destination) */
while(likely(!ARCH_DEP(cmpsc_expand_single_is)(&ec)));
}
/*----------------------------------------------------------------------------*/
/* cmpsc_expand_is (index symbol) */
/*----------------------------------------------------------------------------*/
static void ARCH_DEP(cmpsc_expand_is)(struct ec *ec, U16 is)
{
int csl; /* Complete symbol length */
unsigned cw; /* Characters written */
BYTE *ece; /* Expansion Character Entry */
U16 index; /* Index within dictionary */
int psl; /* Partial symbol length */
/* Initialize values */
cw = 0;
/* Get expansion character entry */
index = is * 8;
if(unlikely(!ec->dict[index / 0x800]))
ec->dict[index / 0x800] = MADDR((ec->dictor + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs, ACCTYPE_READ, ec->regs->psw.pkey);
ece = &ec->dict[index / 0x800][index % 0x800];
ITIMER_SYNC((ec->dictor + index) & ADDRESS_MAXWRAP(ec->regs), 8 - 1, ec->regs);
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_ece: index %04X\n", is);
cmpsc_print_ece(ece);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Process preceded entries */
psl = ECE_psl(ece);
while(likely(psl))
{
/* Count and check for writing child 261 and check valid psl */
cw += psl;
if(unlikely(cw > 260 || psl > 5))
{
ec->regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt)((ec->regs), PGM_DATA_EXCEPTION);
}
/* Process extension characters in preceded entry */
memcpy(&ec->oc[ec->ocl + ECE_ofst(ece)], &ece[2], psl);
/* Get preceding entry */
index = ECE_pptr(ece) * 8;
if(unlikely(!ec->dict[index / 0x800]))
ec->dict[index / 0x800] = MADDR((ec->dictor + (index / 0x800) * 0x800) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs, ACCTYPE_READ, ec->regs->psw.pkey);
ece = &ec->dict[index / 0x800][index % 0x800];
ITIMER_SYNC((ec->dictor + index) & ADDRESS_MAXWRAP(ec->regs), 8 - 1, ec->regs);
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_ece: index %04X\n", index / 8);
cmpsc_print_ece(ece);
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Calculate partial symbol length */
psl = ECE_psl(ece);
}
/* Count and check for writing child 261, valid csl and invalid bits */
csl = ECE_csl(ece);
cw += csl;
if(unlikely(cw > 260 || !csl || ECE_bit34(ece)))
{
ec->regs->dxc = DXC_DECIMAL;
ARCH_DEP(program_interrupt)((ec->regs), PGM_DATA_EXCEPTION);
}
/* Process extension characters in unpreceded entry */
memcpy(&ec->oc[ec->ocl], &ece[1], csl);
/* Place within cache */
memcpy(&ec->ec[ec->ecwm], &ec->oc[ec->ocl], cw);
ec->eci[is] = ec->ecwm;
ec->ecl[is] = cw;
ec->ecwm += cw;
/* Commit in output buffer */
ec->ocl += cw;
}
/*----------------------------------------------------------------------------*/
/* cmpsc_expand_single_is (index symbol) */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_expand_single_is)(struct ec *ec)
{
U16 is; /* Index symbol */
if(unlikely(ARCH_DEP(cmpsc_fetch_is)(ec, &is)))
return(-1);
if(!ec->ecl[is])
{
ec->ocl = 0; /* Initialize output cache */
ARCH_DEP(cmpsc_expand_is)(ec, is);
if(unlikely(ARCH_DEP(cmpsc_vstore)(ec, ec->oc, ec->ocl)))
return(-1);
}
else
{
if(unlikely(ARCH_DEP(cmpsc_vstore)(ec, &ec->ec[ec->eci[is]], ec->ecl[is])))
return(-1);
}
/* Commit, including GR1 */
COMMITREGS(ec->regs, ec->iregs, ec->r1, ec->r2);
return(0);
}
/*----------------------------------------------------------------------------*/
/* cmpsc_fetch_is (index symbol) */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_fetch_is)(struct ec *ec, U16 *is)
{
unsigned cbn; /* Compressed-data bit number */
U32 mask; /* Working mask */
BYTE work[3]; /* Working field */
/* Initialize values */
cbn = GR1_cbn(ec->iregs);
/* Check if we can read an index symbol */
if(unlikely(GR_A(ec->r2 + 1, ec->iregs) < 3 && ((cbn + ec->smbsz - 1) / 8) >= GR_A(ec->r2 + 1, ec->iregs)))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_is : reached end of source\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
ec->regs->psw.cc = 0;
return(-1);
}
/* Clear possible fetched 3rd byte */
work[2] = 0;
ARCH_DEP(vfetchc)(&work, (ec->smbsz + cbn - 1) / 8, GR_A(ec->r2, ec->iregs) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs);
/* Get the bits */
mask = work[0] << 16 | work[1] << 8 | work[2];
mask >>= (24 - ec->smbsz - cbn);
mask &= 0xFFFF >> (16 - ec->smbsz);
*is = mask;
/* Adjust source registers */
ADJUSTREGS(ec->r2, ec->regs, ec->iregs, (cbn + ec->smbsz) / 8);
/* Calculate and set the new compressed-data bit number */
GR1_setcbn(ec->iregs, (cbn + ec->smbsz) % 8);
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_is : %04X, cbn=%d, GR%02d=" F_VADR ", GR%02d=" F_GREG "\n", *is, GR1_cbn(ec->iregs), ec->r2, ec->iregs->GR(ec->r2), ec->r2 + 1, ec->iregs->GR(ec->r2 + 1));
#endif /* #ifdef OPTION_CMPSC_DEBUG */
return(0);
}
/*----------------------------------------------------------------------------*/
/* cmpsc_fetch_iss */
/*----------------------------------------------------------------------------*/
static void ARCH_DEP(cmpsc_fetch_iss)(struct ec *ec, U16 is[8])
{
BYTE buf[13]; /* Buffer for Index Symbols */
#ifdef OPTION_CMPSC_DEBUG
int i;
#endif /* #ifdef OPTION_CMPSC_DEBUG */
unsigned len1; /* Lenght in first page */
BYTE *mem; /* Pointer to maddr or buf */
unsigned ofst; /* Offset in first page */
/* Fingers crossed that we stay within one page */
ofst = GR_A(ec->r2, ec->iregs) & 0x7ff;
if(unlikely(!ec->src))
ec->src = MADDR((GR_A(ec->r2, ec->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs, ACCTYPE_READ, ec->regs->psw.pkey);
if(likely(ofst + ec->smbsz <= 0x800))
{
ITIMER_SYNC(GR_A(ec->r2, ec->iregs) & ADDRESS_MAXWRAP(ec->regs), ec->smbsz - 1, ec->regs);
mem = &ec->src[ofst];
/* Perfect fit? */
if(unlikely(ofst + ec->smbsz == 0x800))
ec->src = NULL;
}
else
{
/* We need data spread over 2 pages */
len1 = 0x800 - ofst;
memcpy(buf, &ec->src[ofst], len1);
ec->src = MADDR((GR_A(ec->r2, ec->iregs) + len1) & ADDRESS_MAXWRAP(ec->regs), ec->r2, ec->regs, ACCTYPE_READ, ec->regs->psw.pkey);
memcpy(&buf[len1], ec->src, ec->smbsz - len1);
mem = buf;
}
/* Calculate the 8 index symbols */
switch(ec->smbsz)
{
case 9: /* 9-bits */
{
/* 0 1 2 3 4 5 6 7 8 */
/* 012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 012345678012345678012345678012345678012345678012345678012345678012345678 */
/* 0 1 2 3 4 5 6 7 */
is[0] = ((mem[0] << 1) | (mem[1] >> 7));
is[1] = ((mem[1] << 2) | (mem[2] >> 6)) & 0x01ff;
is[2] = ((mem[2] << 3) | (mem[3] >> 5)) & 0x01ff;
is[3] = ((mem[3] << 4) | (mem[4] >> 4)) & 0x01ff;
is[4] = ((mem[4] << 5) | (mem[5] >> 3)) & 0x01ff;
is[5] = ((mem[5] << 6) | (mem[6] >> 2)) & 0x01ff;
is[6] = ((mem[6] << 7) | (mem[7] >> 1)) & 0x01ff;
is[7] = ((mem[7] << 8) | (mem[8] )) & 0x01ff;
break;
}
case 10: /* 10-bits */
{
/* 0 1 2 3 4 5 6 7 8 9 */
/* 01234567012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
/* 0 1 2 3 4 5 6 7 */
is[0] = ((mem[0] << 2) | (mem[1] >> 6));
is[1] = ((mem[1] << 4) | (mem[2] >> 4)) & 0x03ff;
is[2] = ((mem[2] << 6) | (mem[3] >> 2)) & 0x03ff;
is[3] = ((mem[3] << 8) | (mem[4] )) & 0x03ff;
is[4] = ((mem[5] << 2) | (mem[6] >> 6));
is[5] = ((mem[6] << 4) | (mem[7] >> 4)) & 0x03ff;
is[6] = ((mem[7] << 6) | (mem[8] >> 2)) & 0x03ff;
is[7] = ((mem[8] << 8) | (mem[9] )) & 0x03ff;
break;
}
case 11: /* 11-bits */
{
/* 0 1 2 3 4 5 6 7 8 9 a */
/* 0123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a */
/* 0 1 2 3 4 5 6 7 */
is[0] = ((mem[0] << 3) | (mem[ 1] >> 5) );
is[1] = ((mem[1] << 6) | (mem[ 2] >> 2) ) & 0x07ff;
is[2] = ((mem[2] << 9) | (mem[ 3] << 1) | (mem[4] >> 7)) & 0x07ff;
is[3] = ((mem[4] << 4) | (mem[ 5] >> 4) ) & 0x07ff;
is[4] = ((mem[5] << 7) | (mem[ 6] >> 1) ) & 0x07ff;
is[5] = ((mem[6] << 10) | (mem[ 7] << 2) | (mem[8] >> 6)) & 0x07ff;
is[6] = ((mem[8] << 5) | (mem[ 9] >> 3) ) & 0x07ff;
is[7] = ((mem[9] << 8) | (mem[10] ) ) & 0x07ff;
break;
}
case 12: /* 12-bits */
{
/* 0 1 2 3 4 5 6 7 8 9 a b */
/* 012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab0123456789ab */
/* 0 1 2 3 4 5 6 7 */
is[0] = ((mem[ 0] << 4) | (mem[ 1] >> 4));
is[1] = ((mem[ 1] << 8) | (mem[ 2] )) & 0x0fff;
is[2] = ((mem[ 3] << 4) | (mem[ 4] >> 4));
is[3] = ((mem[ 4] << 8) | (mem[ 5] )) & 0x0fff;
is[4] = ((mem[ 6] << 4) | (mem[ 7] >> 4));
is[5] = ((mem[ 7] << 8) | (mem[ 8] )) & 0x0fff;
is[6] = ((mem[ 9] << 4) | (mem[10] >> 4));
is[7] = ((mem[10] << 8) | (mem[11] )) & 0x0fff;
break;
}
case 13: /* 13-bits */
{
/* 0 1 2 3 4 5 6 7 8 9 a b c */
/* 01234567012345670123456701234567012345670123456701234567012345670123456701234567012345670123456701234567 */
/* 0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc0123456789abc */
/* 0 1 2 3 4 5 6 7 */
is[0] = ((mem[ 0] << 5) | (mem[ 1] >> 3) );
is[1] = ((mem[ 1] << 10) | (mem[ 2] << 2) | (mem[ 3] >> 6)) & 0x1fff;
is[2] = ((mem[ 3] << 7) | (mem[ 4] >> 1) ) & 0x1fff;
is[3] = ((mem[ 4] << 12) | (mem[ 5] << 4) | (mem[ 6] >> 4)) & 0x1fff;
is[4] = ((mem[ 6] << 9) | (mem[ 7] << 1) | (mem[ 8] >> 7)) & 0x1fff;
is[5] = ((mem[ 8] << 6) | (mem[ 9] >> 2) ) & 0x1fff;
is[6] = ((mem[ 9] << 11) | (mem[10] << 3) | (mem[11] >> 5)) & 0x1fff;
is[7] = ((mem[11] << 8) | (mem[12] ) ) & 0x1fff;
break;
}
}
/* Adjust source registers */
ADJUSTREGS(ec->r2, ec->regs, ec->iregs, ec->smbsz);
#ifdef OPTION_CMPSC_DEBUG
logmsg("fetch_iss:");
for(i = 0; i < 8; i++)
logmsg(" %04X", is[i]);
logmsg(", GR%02d=" F_VADR ", GR%02d=" F_GREG "\n", ec->r2, ec->iregs->GR(ec->r2), ec->r2 + 1, ec->iregs->GR(ec->r2 + 1));
#endif /* #ifdef OPTION_CMPSC_DEBUG */
}
#ifndef NO_2ND_COMPILE
#ifdef OPTION_CMPSC_DEBUG
/*----------------------------------------------------------------------------*/
/* cmpsc_print_ece (expansion character entry) */
/*----------------------------------------------------------------------------*/
static void cmpsc_print_ece(BYTE *ece)
{
int i; /* Index */
int prt_detail; /* Switch detailed printing */
logmsg(" ece : ");
prt_detail = 0;
for(i = 0; i < 8; i++)
{
if(!prt_detail && ece[i])
prt_detail = 1;
logmsg("%02X", ece[i]);
}
logmsg("\n");
if(prt_detail)
{
if(ECE_psl(ece))
{
logmsg(" psl : %d\n", ECE_psl(ece));
logmsg(" pptr : %04X\n", ECE_pptr(ece));
logmsg(" ecs :");
for(i = 0; i < ECE_psl(ece); i++)
logmsg(" %02X", ece[i + 2]);
logmsg("\n");
logmsg(" ofst : %02X\n", ECE_ofst(ece));
}
else
{
logmsg(" psl : %d\n", ECE_psl(ece));
logmsg(" bit34 : %s\n", TRUEFALSE(ECE_bit34(ece)));
logmsg(" csl : %d\n", ECE_csl(ece));
logmsg(" ecs :");
for(i = 0; i < ECE_csl(ece); i++)
logmsg(" %02X", ece[i + 1]);
logmsg("\n");
}
}
}
#endif /* #ifdef OPTION_CMPSC_DEBUG */
#endif /* #ifndef NO_2ND_COMPILE */
/*----------------------------------------------------------------------------*/
/* cmpsc_vstore */
/*----------------------------------------------------------------------------*/
static int ARCH_DEP(cmpsc_vstore)(struct ec *ec, BYTE *buf, unsigned len)
{
unsigned len1; /* Length in first page */
unsigned len2; /* Length in second page */
BYTE *main1; /* Address first page */
unsigned ofst; /* Offset within page */
BYTE *sk; /* Storage key */
#ifdef OPTION_CMPSC_DEBUG
unsigned i; /* Index */
unsigned j; /* Index */
static BYTE pbuf[2060]; /* Print buffer */
static unsigned plen = 2061; /* Impossible value */
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Check destination size */
if(unlikely(GR_A(ec->r1 + 1, ec->iregs) < len))
{
#ifdef OPTION_CMPSC_DEBUG
logmsg("vstore : Reached end of destination\n");
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Indicate end of destination */
ec->regs->psw.cc = 1;
return(-1);
}
#ifdef OPTION_CMPSC_DEBUG
if(plen == len && !memcmp(pbuf, buf, plen))
logmsg(F_GREG " - " F_GREG " Same buffer as previously shown\n", ec->iregs->GR(ec->r1), ec->iregs->GR(ec->r1) + len - 1);
else
{
for(i = 0; i < len; i += 32)
{
logmsg(F_GREG, ec->iregs->GR(ec->r1) + i);
if(i && i + 32 < len && !memcmp(&buf[i], &buf[i - 32], 32))
{
for(j = i + 32; j + 32 < len && !memcmp(&buf[j], &buf[j - 32], 32); j += 32);
if(j > 32)
{
logmsg(": Same line as above\n" F_GREG, ec->iregs->GR(ec->r1) + j);
i = j;
}
}
logmsg(": ");
for(j = 0; j < 32; j++)
{
if(!(j % 8))
logmsg(" ");
if(i + j >= len)
logmsg(" ");
else
logmsg("%02X", buf[i + j]);
}
logmsg(" | ");
for(j = 0; j < 32; j++)
{
if(i + j >= len)
logmsg(" ");
else
{
if(isprint(guest_to_host(buf[i + j])))
logmsg("%c", guest_to_host(buf[i + j]));
else
logmsg(".");
}
}
logmsg(" |\n");
}
memcpy(pbuf, buf, len);
plen = len;
}
#endif /* #ifdef OPTION_CMPSC_DEBUG */
/* Fingers crossed that we stay within one page */
ofst = GR_A(ec->r1, ec->iregs) & 0x7ff;
if(likely(ofst + len <= 0x800))
{
if(unlikely(!ec->dest))
ec->dest = MADDR((GR_A(ec->r1, ec->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(ec->regs), ec->r1, ec->regs, ACCTYPE_WRITE, ec->regs->psw.pkey);
memcpy(&ec->dest[ofst], buf, len);
ITIMER_UPDATE(GR_A(ec->r1, ec->iregs) & ADDRESS_MAXWRAP(ec->regs), len - 1, ec->regs);
/* Perfect fit? */
if(unlikely(ofst + len == 0x800))
ec->dest = NULL;
}
else
{
/* We need multiple pages */
if(unlikely(!ec->dest))
main1 = MADDR((GR_A(ec->r1, ec->iregs) & ~0x7ff) & ADDRESS_MAXWRAP(ec->regs), ec->r1, ec->regs, ACCTYPE_WRITE_SKP, ec->regs->psw.pkey);
else
main1 = ec->dest;
sk = ec->regs->dat.storkey;
len1 = 0x800 - ofst;
ec->dest = MADDR((GR_A(ec->r1, ec->iregs) + len1) & ADDRESS_MAXWRAP(ec->regs), ec->r1, ec->regs, ACCTYPE_WRITE, ec->regs->psw.pkey);
memcpy(&main1[ofst], buf, len1);
len2 = len - len1; /* We always start with a len2 */
do
{
memcpy(ec->dest, &buf[len1], (len2 > 0x800 ? 0x800 : len2));
*sk |= (STORKEY_REF | STORKEY_CHANGE);
if(unlikely(len2 >= 0x800))
{
len1 += 0x800;
len2 -= 0x800;
/* Perfect fit? */
if(unlikely(!len2))
ec->dest = NULL;
else
ec->dest = MADDR((GR_A(ec->r1, ec->iregs) + len1) & ADDRESS_MAXWRAP(ec->regs), ec->r1, ec->regs, ACCTYPE_WRITE, ec->regs->psw.pkey);
sk = ec->regs->dat.storkey;
}
else
len2 = 0;
}
while(len2);
}
ADJUSTREGS(ec->r1, ec->regs, ec->iregs, len);
return(0);
}
#define NO_2ND_COMPILE
#endif /* FEATURE_COMPRESSION */
#ifndef _GEN_ARCH
#ifdef _ARCHMODE2
#define _GEN_ARCH _ARCHMODE2
#include "cmpsc.c"
#endif /* #ifdef _ARCHMODE2 */
#ifdef _ARCHMODE3
#undef _GEN_ARCH
#define _GEN_ARCH _ARCHMODE3
#include "cmpsc.c"
#endif /* #ifdef _ARCHMODE3 */
#if !defined( NOT_HERC ) // (building Hercules?)
HDL_DEPENDENCY_SECTION;
{
HDL_DEPENDENCY( HERCULES );
HDL_DEPENDENCY( REGS );
}
END_DEPENDENCY_SECTION;
HDL_INSTRUCTION_SECTION;
{
char info[256];
const char* fn = NULL;
if (!fn) fn = strrchr( __FILE__, '\\' );
if (!fn) fn = strrchr( __FILE__ , '/' );
if (!fn) fn = __FILE__ ; else fn++;
#ifdef __TIMESTAMP__
MSGBUF( info, "%s version %s last updated on %s", fn, VERSION, __TIMESTAMP__ );
#else
MSGBUF( info, "%s version %s compiled on %s at %s", fn, VERSION, __DATE__, __TIME__ );
#endif
WRMSG( HHC01417, "I", info );
HDL_DEFINST( HDL_INSTARCH_390 | HDL_INSTARCH_900, 0xB263, legacy_cmpsc );
}
END_INSTRUCTION_SECTION;
#endif // !defined( NOT_HERC ) // (building Hercules?)
#endif /* #ifndef _GEN_ARCH */