Discussion:
[hercules-390] MVCLE
kerravon86@yahoo.com.au [hercules-390]
2017-10-03 09:48:17 UTC
Permalink
I posted this about 3 hours ago, and it
still hasn't shown up, so here's a possible
duplicate ...


Hi. I'm having a problem with MVCLE.
This is the first time I've ever used it,
so it could be "operator error".

Here is the instruction:

MVCLE R8,R12,0(R13)

But due to possible macro error, it is possible
the instruction itself is wrong. Here is
the expansion:

DC 0H'0',X'A8',AL.4(R8,R12),SL2(0(R13))

which becomes:

A88CD000

Here are the registers before execution:

8 0000000002000000 9 0000000004000000
C 0000000002000000 D 0000000000000000

And here are the registers after:

8 0000000002001000 9 0000000003FFF000
C 0000000002000000 D 0000000000000000

The memory address I am interested
in is not being cleared:

r 2001000 R:02001000:K:00=02001000 00000000 00000000 00000000

but other memory, such as this:

r 2000000 R:02000000:K:00=00000000 00000000 00000000 00000000

is being cleared (I deliberately set the
first word to non-zero and it got cleared).


I am using a slightly modified Hercules 3.07,
so I first checked the source code to make
sure I hadn't modified something.

I did not see any changes from me, but I
did see this code which looked suspicious:

/* set cpu_length as shortest distance to new page */
if ((addr1 & 0xFFF) > (addr2 & 0xFFF))
cpu_length = 0x1000 - (addr1 & 0xFFF);
else
cpu_length = 0x1000 - (addr2 & 0xFFF);

dstlen=MIN(cpu_length,len1);
srclen=MIN(cpu_length,len2);
copylen=MIN(dstlen,srclen);

(you can see the full 3.07 code below).

The above code seems to truncate the
lengths to a maximum of 4096, which
is what I am seeing.

Further down I see this comment:

/* Adjust length & pointers for this cycle */
dest+=copylen;
dstlen-=copylen;
srclen-=copylen;

But I see no "cycles". ie there is no
"while" loop.

Is the cycle perhaps being done outside
of the MVCLE instruction itself, ie MVCLE
is an interruptable instruction or something
like that? If that is the case, it could well
be one of my modifications that is causing
the fault, but I'd like some hints as to which
one.

Anyway, I did a diff to the 3.13 code, and
see no change in that area:

C:\devel\hercules>diff -w 307.txt 313.txt
54c54
< dest = MADDR (addr1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey);
---
dest = MADDRL (addr1, len1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey);
So if it is indeed a Hercules bug, it has
remained undetected for a very long
time.

Could someone desk-check all the
above please? Or give me some
further tests to try?

Thanks. Paul.




/*-------------------------------------------------------------------*/
/* A8 MVCLE - Move Long Extended [RS] */
/*-------------------------------------------------------------------*/
DEF_INST(move_long_extended)
{
int r1, r3; /* Register numbers */
int b2; /* effective address base */
VADR effective_addr2; /* effective address */
int cc; /* Condition code */
VADR addr1, addr2; /* Operand addresses */
GREG len1, len2; /* Operand lengths */
BYTE pad; /* Padding byte */
size_t cpu_length; /* cpu determined length */
size_t copylen; /* Length to copy */
BYTE *dest; /* Maint storage pointers */
size_t dstlen,srclen; /* Page wide src/dst lengths */

RS(inst, regs, r1, r3, b2, effective_addr2);

ODD2_CHECK(r1, r3, regs);

/* Load padding byte from bits 24-31 of effective address */
pad = effective_addr2 & 0xFF;

/* Determine the destination and source addresses */
addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs);
addr2 = regs->GR(r3) & ADDRESS_MAXWRAP(regs);

/* Load operand lengths from bits 0-31 of R1+1 and R3+1 */
len1 = GR_A(r1+1, regs);
len2 = GR_A(r3+1, regs);

/* set cpu_length as shortest distance to new page */
if ((addr1 & 0xFFF) > (addr2 & 0xFFF))
cpu_length = 0x1000 - (addr1 & 0xFFF);
else
cpu_length = 0x1000 - (addr2 & 0xFFF);

dstlen=MIN(cpu_length,len1);
srclen=MIN(cpu_length,len2);
copylen=MIN(dstlen,srclen);

/* Set the condition code according to the lengths */
cc = (len1 < len2) ? 1 : (len1 > len2) ? 2 : 0;

/* Obtain destination pointer */
if(len1==0)
{
/* bail out if nothing to do */
regs->psw.cc = cc;
return;
}

dest = MADDR (addr1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey);
if(copylen!=0)
{
/* here if we need to copy data */
BYTE *source;
/* get source frame and copy concurrently */
source = MADDR (addr2, r3, regs, ACCTYPE_READ, regs->psw.pkey);
concpy(regs,dest,source,copylen);
/* Adjust operands */
addr2+=copylen;
len2-=copylen;
addr1+=copylen;
len1-=copylen;

/* Adjust length & pointers for this cycle */
dest+=copylen;
dstlen-=copylen;
srclen-=copylen;
}
if(srclen==0 && dstlen!=0)
{
/* here if we need to pad the destination */
memset(dest,pad,dstlen);

/* Adjust destination operands */
addr1+=dstlen;
len1-=dstlen;
}

/* Update the registers */
SET_GR_A(r1, regs,addr1);
SET_GR_A(r1+1, regs,len1);
SET_GR_A(r3, regs,addr2);
SET_GR_A(r3+1, regs,len2);
/* if len1 != 0 then set CC to 3 to indicate
we have reached end of CPU dependent length */
if(len1>0) cc=3;

regs->psw.cc = cc;

}
kerravon86@yahoo.com.au [hercules-390]
2017-10-03 12:28:11 UTC
Permalink
Post by ***@yahoo.com.au [hercules-390]
But I see no "cycles". ie there is no
"while" loop.
I had a brainwave to check older code,
and indeed, the 3.06 code (below) has
an actual loop, which seemed like a
good sign. However, I was surprised
that it STILL didn't work, and had the
same behavior as 3.07+.

This code looked suspicious:

if (i >= cpu_length)
{
cc = 3;
break;
}

so I commented it out.

And hey presto, the MVCLE started working!!!

Not sure what the proper fix should
be though. It's not good to just
semi-randomly comment out code.

BFN. Paul.





/*-------------------------------------------------------------------*/
/* A8 MVCLE - Move Long Extended [RS] */
/*-------------------------------------------------------------------*/
DEF_INST(move_long_extended)
{
int r1, r3; /* Register numbers */
int b2; /* effective address base */
VADR effective_addr2; /* effective address */
int i; /* Loop counter */
int cc; /* Condition code */
VADR addr1, addr2; /* Operand addresses */
GREG len1, len2; /* Operand lengths */
BYTE obyte; /* Operand byte */
BYTE pad; /* Padding byte */
int cpu_length; /* cpu determined length */

RS(inst, regs, r1, r3, b2, effective_addr2);

ODD2_CHECK(r1, r3, regs);

/* Load padding byte from bits 24-31 of effective address */
pad = effective_addr2 & 0xFF;

/* Determine the destination and source addresses */
addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs);
addr2 = regs->GR(r3) & ADDRESS_MAXWRAP(regs);

/* Load operand lengths from bits 0-31 of R1+1 and R3+1 */
len1 = GR_A(r1+1, regs);
len2 = GR_A(r3+1, regs);

/* set cpu_length as shortest distance to new page */
if ((addr1 & 0xFFF) > (addr2 & 0xFFF))
cpu_length = 0x1000 - (addr1 & 0xFFF);
else
cpu_length = 0x1000 - (addr2 & 0xFFF);

/* Set the condition code according to the lengths */
cc = (len1 < len2) ? 1 : (len1 > len2) ? 2 : 0;

/* Process operands from left to right */
for (i = 0; len1 > 0; i++)
{
/* If cpu determined length has been moved, exit with cc=3 */
if (i >= cpu_length)
{
cc = 3;
break;
}

/* Fetch byte from source operand, or use padding byte */
if (len2 > 0)
{
obyte = ARCH_DEP(vfetchb) ( addr2, r3, regs );
addr2++;
addr2 &= ADDRESS_MAXWRAP(regs);
len2--;
}
else
obyte = pad;

/* Store the byte in the destination operand */
ARCH_DEP(vstoreb) ( obyte, addr1, r1, regs );
addr1++;
addr1 &= ADDRESS_MAXWRAP(regs);
len1--;

/* Update the registers */
SET_GR_A(r1, regs,addr1);
SET_GR_A(r1+1, regs,len1);
SET_GR_A(r3, regs,addr2);
SET_GR_A(r3+1, regs,len2);

} /* end for(i) */

regs->psw.cc = cc;

}
Joe Monk joemonk64@gmail.com [hercules-390]
2017-10-03 12:41:10 UTC
Permalink
"o I commented it out.

And hey presto, the MVCLE started working!!!

Not sure what the proper fix should
be though. It's not good to just
semi-randomly comment out code."

And by so doing ... you broke the MVCLE instruction. MVCLE BY IBM's DESIGN
does not operate on more than 4K at a time...

Joe
Post by ***@yahoo.com.au [hercules-390]
Post by ***@yahoo.com.au [hercules-390]
But I see no "cycles". ie there is no
"while" loop.
I had a brainwave to check older code,
and indeed, the 3.06 code (below) has
an actual loop, which seemed like a
good sign. However, I was surprised
that it STILL didn't work, and had the
same behavior as 3.07+.
if (i >= cpu_length)
{
cc = 3;
break;
}
so I commented it out.
And hey presto, the MVCLE started working!!!
Not sure what the proper fix should
be though. It's not good to just
semi-randomly comment out code.
BFN. Paul.
/*----------------------------------------------------------*/
/* A8 MVCLE - Move Long Extended [RS] */
/*----------------------------------------------------------*/
DEF_INST(move_long_extended)
{
int r1, r3; /* Register numbers */
int b2; /* effective address base */
VADR effective_addr2; /* effective address */
int i; /* Loop counter */
int cc; /* Condition code */
VADR addr1, addr2; /* Operand addresses */
GREG len1, len2; /* Operand lengths */
BYTE obyte; /* Operand byte */
BYTE pad; /* Padding byte */
int cpu_length; /* cpu determined length */
RS(inst, regs, r1, r3, b2, effective_addr2);
ODD2_CHECK(r1, r3, regs);
/* Load padding byte from bits 24-31 of effective address */
pad = effective_addr2 & 0xFF;
/* Determine the destination and source addresses */
addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs);
addr2 = regs->GR(r3) & ADDRESS_MAXWRAP(regs);
/* Load operand lengths from bits 0-31 of R1+1 and R3+1 */
len1 = GR_A(r1+1, regs);
len2 = GR_A(r3+1, regs);
/* set cpu_length as shortest distance to new page */
if ((addr1 & 0xFFF) > (addr2 & 0xFFF))
cpu_length = 0x1000 - (addr1 & 0xFFF);
else
cpu_length = 0x1000 - (addr2 & 0xFFF);
/* Set the condition code according to the lengths */
cc = (len1 < len2) ? 1 : (len1 > len2) ? 2 : 0;
/* Process operands from left to right */
for (i = 0; len1 > 0; i++)
{
/* If cpu determined length has been moved, exit with cc=3 */
if (i >= cpu_length)
{
cc = 3;
break;
}
/* Fetch byte from source operand, or use padding byte */
if (len2 > 0)
{
obyte = ARCH_DEP(vfetchb) ( addr2, r3, regs );
addr2++;
addr2 &= ADDRESS_MAXWRAP(regs);
len2--;
}
else
obyte = pad;
/* Store the byte in the destination operand */
ARCH_DEP(vstoreb) ( obyte, addr1, r1, regs );
addr1++;
addr1 &= ADDRESS_MAXWRAP(regs);
len1--;
/* Update the registers */
SET_GR_A(r1, regs,addr1);
SET_GR_A(r1+1, regs,len1);
SET_GR_A(r3, regs,addr2);
SET_GR_A(r3+1, regs,len2);
} /* end for(i) */
regs->psw.cc = cc;
}
Martin Truebner Martin@pi-sysprog.de [hercules-390]
2017-10-03 13:01:43 UTC
Permalink
Without checking the bible (PoOp)

could it be that MVCLE should be followed by a JO *-4 ?

the CC=3 does look like just that is needed (and documented
in PoOPs ?)

Martin
kerravon86@yahoo.com.au [hercules-390]
2017-10-03 13:21:49 UTC
Permalink
Post by Martin Truebner ***@pi-sysprog.de [hercules-390]
Without checking the bible (PoOp)
could it be that MVCLE should be followed by a JO *-4 ?
the CC=3 does look like just that is needed (and documented
in PoOPs ?)
Thanks Joe and Martin.

I checked the ESA POP and yes, it sounds
like I need something like that.

That's great that it's not a "hardware" problem.
I should be up and running properly soon.

BFN. Paul.
Joe Monk joemonk64@gmail.com [hercules-390]
2017-10-03 10:43:48 UTC
Permalink
Page 7-141:
http://www-01.ibm.com/support/docview.wss?uid=isg26480faec85f44e2385256d5200627dee&aid=1

"The amount of processing that results in the setting of condition code 3
is determined by the CPU on the basis of improving system performance, and
it may be a different amount each time the instruction is executed. The
maximum amount is approximately 4K bytes of either operand."

Page 7-142:

"When condition code 3 is set, the program can simply branch back to the
instruction to continue the movement. The program need not determine the
number of bytes that were moved.

The function of not processing more than approximately 4K bytes of either
operand is intended to permit software polling of a flag that may be set by
a program on another CPU during long operations."

So, the hercules max is 4096 bytes... exactly as it is supposed to be
according to POO.

Joe
Post by ***@yahoo.com.au [hercules-390]
I posted this about 3 hours ago, and it
still hasn't shown up, so here's a possible
duplicate ...
Hi. I'm having a problem with MVCLE.
This is the first time I've ever used it,
so it could be "operator error".
MVCLE R8,R12,0(R13)
But due to possible macro error, it is possible
the instruction itself is wrong. Here is
DC 0H'0',X'A8',AL.4(R8,R12),SL2(0(R13))
A88CD000
8 0000000002000000 9 0000000004000000
C 0000000002000000 D 0000000000000000
8 0000000002001000 9 0000000003FFF000
C 0000000002000000 D 0000000000000000
The memory address I am interested
r 2001000 R:02001000:K:00=02001000 00000000 00000000 00000000
r 2000000 R:02000000:K:00=00000000 00000000 00000000 00000000
is being cleared (I deliberately set the
first word to non-zero and it got cleared).
I am using a slightly modified Hercules 3.07,
so I first checked the source code to make
sure I hadn't modified something.
I did not see any changes from me, but I
/* set cpu_length as shortest distance to new page */
if ((addr1 & 0xFFF) > (addr2 & 0xFFF))
cpu_length = 0x1000 - (addr1 & 0xFFF);
else
cpu_length = 0x1000 - (addr2 & 0xFFF);
dstlen=MIN(cpu_length,len1);
srclen=MIN(cpu_length,len2);
copylen=MIN(dstlen,srclen);
(you can see the full 3.07 code below).
The above code seems to truncate the
lengths to a maximum of 4096, which
is what I am seeing.
/* Adjust length & pointers for this cycle */
dest+=copylen;
dstlen-=copylen;
srclen-=copylen;
But I see no "cycles". ie there is no
"while" loop.
Is the cycle perhaps being done outside
of the MVCLE instruction itself, ie MVCLE
is an interruptable instruction or something
like that? If that is the case, it could well
be one of my modifications that is causing
the fault, but I'd like some hints as to which
one.
Anyway, I did a diff to the 3.13 code, and
C:\devel\hercules>diff -w 307.txt 313.txt
54c54
< dest = MADDR (addr1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey);
---
dest = MADDRL (addr1, len1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey);
So if it is indeed a Hercules bug, it has
remained undetected for a very long
time.
Could someone desk-check all the
above please? Or give me some
further tests to try?
Thanks. Paul.
/*----------------------------------------------------------*/
/* A8 MVCLE - Move Long Extended [RS] */
/*----------------------------------------------------------*/
DEF_INST(move_long_extended)
{
int r1, r3; /* Register numbers */
int b2; /* effective address base */
VADR effective_addr2; /* effective address */
int cc; /* Condition code */
VADR addr1, addr2; /* Operand addresses */
GREG len1, len2; /* Operand lengths */
BYTE pad; /* Padding byte */
size_t cpu_length; /* cpu determined length */
size_t copylen; /* Length to copy */
BYTE *dest; /* Maint storage pointers */
size_t dstlen,srclen; /* Page wide src/dst lengths */
RS(inst, regs, r1, r3, b2, effective_addr2);
ODD2_CHECK(r1, r3, regs);
/* Load padding byte from bits 24-31 of effective address */
pad = effective_addr2 & 0xFF;
/* Determine the destination and source addresses */
addr1 = regs->GR(r1) & ADDRESS_MAXWRAP(regs);
addr2 = regs->GR(r3) & ADDRESS_MAXWRAP(regs);
/* Load operand lengths from bits 0-31 of R1+1 and R3+1 */
len1 = GR_A(r1+1, regs);
len2 = GR_A(r3+1, regs);
/* set cpu_length as shortest distance to new page */
if ((addr1 & 0xFFF) > (addr2 & 0xFFF))
cpu_length = 0x1000 - (addr1 & 0xFFF);
else
cpu_length = 0x1000 - (addr2 & 0xFFF);
dstlen=MIN(cpu_length,len1);
srclen=MIN(cpu_length,len2);
copylen=MIN(dstlen,srclen);
/* Set the condition code according to the lengths */
cc = (len1 < len2) ? 1 : (len1 > len2) ? 2 : 0;
/* Obtain destination pointer */
if(len1==0)
{
/* bail out if nothing to do */
regs->psw.cc = cc;
return;
}
dest = MADDR (addr1, r1, regs, ACCTYPE_WRITE, regs->psw.pkey);
if(copylen!=0)
{
/* here if we need to copy data */
BYTE *source;
/* get source frame and copy concurrently */
source = MADDR (addr2, r3, regs, ACCTYPE_READ, regs->psw.pkey);
concpy(regs,dest,source,copylen);
/* Adjust operands */
addr2+=copylen;
len2-=copylen;
addr1+=copylen;
len1-=copylen;
/* Adjust length & pointers for this cycle */
dest+=copylen;
dstlen-=copylen;
srclen-=copylen;
}
if(srclen==0 && dstlen!=0)
{
/* here if we need to pad the destination */
memset(dest,pad,dstlen);
/* Adjust destination operands */
addr1+=dstlen;
len1-=dstlen;
}
/* Update the registers */
SET_GR_A(r1, regs,addr1);
SET_GR_A(r1+1, regs,len1);
SET_GR_A(r3, regs,addr2);
SET_GR_A(r3+1, regs,len2);
/* if len1 != 0 then set CC to 3 to indicate
we have reached end of CPU dependent length */
if(len1>0) cc=3;
regs->psw.cc = cc;
}
kerravon86@yahoo.com.au [hercules-390]
2017-10-03 14:19:22 UTC
Permalink
Ok, cool. Anyway, we're up and running
with this code now:

LUPDELUP MVCLE R8,R12,0(R13)
BO LUPDELUP

And with the old "hardware" it is now
working fine, although it's still running
the exhaustive testing at the moment.

Thanks again everyone and sorry for
the noise.

BFN. Paul.




---In hercules-***@yahoogroups.com, <***@...> wrote :

Page 7-141: http://www-01.ibm.com/support/docview.wss?uid=isg26480faec85f44e2385256d5200627dee&aid=1 http://www-01.ibm.com/support/docview.wss?uid=isg26480faec85f44e2385256d5200627dee&aid=1

"The amount of processing that results in the setting of condition code 3 is determined by the CPU on the basis of improving system performance, and it may be a different amount each time the instruction is executed. The maximum amount is approximately 4K bytes of either operand."


Page 7-142:


"When condition code 3 is set, the program can simply branch back to the instruction to continue the movement. The program need not determine the number of bytes that were moved.


The function of not processing more than approximately 4K bytes of either operand is intended to permit software polling of a flag that may be set by a program on another CPU during long operations."


So, the hercules max is 4096 bytes... exactly as it is supposed to be according to POO.


Joe

Loading...