Re: Fair comparison C vs HLASM
(snip on optimizing and compilers) On January 24, 2018 at 8:54 PM Paul Raulerson wrote: Of course, the C compiler took this: #include int main(int argc, char *argv[]) { int c=0; int x=0; for (x=0; x< 1; x++) { c++; } printf ("\nThe final value is [%d]\n", c); } and optimized it during compile time. In fact it optimized it so much it simply generated a LHI of a register with 1 in it. (grin) Needless to say, it ran somewhat faster than my friend’s program. Even counting the screen print. :) ite: http://www.gkc.org.uk/gkc | Erdos number: 4 There is a story from the OS/360 days of a popular Fortran benchmark that evaluated complicated math functions and such, all done using statement functions. It seems that Fortran H expands statement functions inline, and also does constant evaluation at compile time. As in the above example, the compiler evaluated the whole thing at compile time (very slowly) and at run time printed out the precomputed value (fast). If Fortran H could do it 40 years ago, C compilers should do it today. (But I don't know that Fortran H did loop evaluation.) -- glen
Re: Fair comparison C vs HLASM
On January 25, 2018 at 10:57 AM Bernd Oppolzer wrote: (snip) I would like to add: Mainframe ASSEMBLER IMHO is the only Assembler language (or the only instruction set) where humans can write reasonably programs in. All other Assemblers or instruction sets lack the same user friendliness and orthogonality that this platform has from the early days of the 360 system. VAX is pretty human readable, too. That was considered important at the time, though just at the transition away from mostly writing OS in assembler. But yes, RISC assembler programs are not so readable, and also x86 (for any value of x) are not so readable. (snip) BTW: I know of an old PL/1 compiler (Multics), which did the same loop unrolling and outperformed ASSEMBLER programmers this way; my example goes like this: SUM = 0; DO I = 1 to 1; SUM = SUM + I; END; PUT SKIP DATA (SUM); Loop unrolling was a favorite example for the PL/I preprocessor. change to %DO and %END and you have an unrolled loop.
Re: Fair comparison C vs HLASM
The 360/20 has MVC and CLC, but, strangely, not LR. (You can use SR and AR instead, so no need for LR.)
Re: Fair comparison C vs HLASM
On January 31, 2018 at 8:06 AM Kirk Wolf wrote: On Tue, Jan 30, 2018 at 9:39 PM, Jon Perryman wrote: C is a byte by byte language. Anything not hidden in a primitive or function must be processed byte by byte. In primitives and functions, the compiler can choose how to implement it. The point is C programmers must process byte by byte unless they can find a function. I'm sorry, but can't agree with anything of this. 1) Compilers can generate machine instruction implementations that take advantage of the instructions and architecture available. Even if you write byte-by-byte code, a compiler may rewrite it to use zArch instructions that are not byte-by-byte but equivalent. This is distinctly different from how assemblers work. I think I at least somewhat understand what he means. It occurred to me some time ago, that there is no C library routine to do what MVCIN does. Not that it is hard to do, but there just isn't one. I doubt many compilers compile the appropriate for loop into MVCIN. 2) The "C Standard Library" is part of the C language standard(s). For all of the supposed byte-by-byte C programmers that can't find any functions to use, here are links to the XL/C++ documentation, where the "Runtime Library Reference" can be found: https://www-01.ibm.com/support/docview.wss?uid=swg27036892 The bottom line is that this: memcpy(field1, field2, sizeof(field1)); generates an MVC instruction (or several or a loop or an unrolled loop of MVC instructions). To say that the "C Language" is byte-by-byte is pedantic. It does. But note that C doesn't have some statements that other languages have, that generate a lot of code from a small statement. No array expressions, for example. 3) I also do not agree with your repeated assertion that it means something significant that C was originally developed on a RISC machine ( I believe that it was a PDP-7) with only certain instructions. The RISC/CISC idea didn't come until later. Machines like the PDP-7 have simpler instructions to keep costs down, and make them easier to build. I would have thought that this kind of argument about the relative benefits of assemblers vs compilers (or assembler vs C) would have been over a couple of decades ago. A more current argument is static vs dynamic (VM+JIT) compilation.
OOP
Someone wrote: "OOP is, I think, quite a bit more than a calling standard - it boils down to an abstracted thought process that you simply cannot do in Assembler. As noted however, you an certainly write a dynamite compiler in HLASM that compiles a OOP language. " You can write OOP in Fortran 66, as I have known it done, and you can also do it in HLASM. Yes it is an abstraction, and yes Fortran 66 and HLASM don't help you so much, but the abstraction itself can be written in pretty much any language. Some languages have protection that stops you from cheating, but you can decide not to cheat. Some have features that help with readability, but again HLASM doesn't.
tail recursion
Someone wrote: "yes, I Had to do the Same, when I implemented Quicksort in REXX, because the OS/2 Implementation of REXX only supported some 32 nesting Levels." The usual way to write recursive quicksort is to take advantage of tail recursion. Each call will generate two recursive calls for two partitions of the input. One is done with an actual recursive call, and the other, which would normally occur just before return, is done with a branch back to the top. This is tail recursion elimination. If the smaller partition is done with a recursive call, it is guaranteed to be smaller than half the input, so at most log2(N) levels of recursion.
local labels
I believe that some DEC assemblers allow local labels of the form d$ where d is a digit from 0 to 9. Local labels need to be unique between any two normal labels. References to them would, then, only work between those same labels. -- glen
Re: Why is division by zero permitted?
>From C28-6514-5 on bitsavers, on page 16: "Division by zero is permitted and yields a zero result." After that, (and presumably also earlier) it has to stay that way as code (macros) might depend on that. There is no reason given. -- glen
Re: OT: SI units and precision
Someone wrote: > At least that explains I don't need to worry that km is > not suddenly 1024m as soon as I carry a storage device ;-) Reminds me that I used to wonder if IBM sold computers in units of $1024, that is, k$. I presume everyone here knows that the serial numbers on S/370 CPUs are in hex. -- glen
architecture book
My favorite book describing the variety of computer architectures is the Blaauw & Brooks book. Many of the examples have a little more detail for S/360 and S/370, but they have all of the important details for many other older and newer systems. Otherwise, the previously mentioned book seems to be available in the paperback international version for a lower price, and used in the hardback not so much more. -- glen
Trial execution
Someone wrote: "The problem with TRT is it validates the whole TRT table before it starts to do the TRT." As far as I know, TR, but not TRT, can do a trial execution. First, it is only needed if the translate table starts within 256 bytes before a page boundary. But it is needed for TR, as TR modifies the first argument before it knows the extent (on both sides of the boundary) of the second argument. TRT does not modify its argument, and so doesn't have that problem. It might be also for ED and EDMK, though I have never used either. The other SS instructions know the extent of both operands before any data is modified, and can generate the page fault interrupt at that time. -- glen
Decimal intructions, was: Redesigning POps.
Gary wrote: > I have heard that only one machine was ever delivered without the > decimal set, but it may have just been rumour. All the 360/91's were delivered without the decimal instructions. The OS emulates them when the illegal instruction exception is generated. But maybe you meant only on machines where decimal was in option. The 360/20 has the decimal instructions except for SRP, but not most of the binary instructions. (It has MP and DP but not M, MR, D, or DR.) Without having ever looked at it, I presume that RPG does mostly decimal arithmetic, other than address calculations. -- glen
Reference summary for 360/20
The mention of instruction sets and green cards reminds me, does anyone have a (scan of) a 360/20 Reference Summary? Some places indicate that it might be yellow or red. -- glen
new instructions (was: LZRG ...)
(snip, someone wrote) >> And POPCNT is another one. Why do I need to >> know the number of 1 bits in each individual byte in a GPR? On 2015-03-11, at 08:49, John McKown wrote: > Because CDC had it first? I suspect that it became a built-in > function in Pascal, CARD(), because Pascal was developed on a > CDC which had the hardware. As I understand it, it is used in cryptography. Also, it can be done fast in hardware and isn't that hard if you want to do it. > Is POPCNT an inexpensive extension of the Wallace Tree? The ones I know of use a carry save adder tree. I think that is related to the Wallace tree, but I forget the exact way they work. > And I suspect FORTRAN's transfer-of-sign, SIGNF() happened > because it was a hardware instruction on the 704. I suppose. But now that IEEE cares about negative zero, it has an extra use. Even without the special instruction, it is easy to do with bitwise AND and OR and most hardware. (Though you have to be able to get floating point values in a place where you can do bitwise operations.) -- glen
CE key
I wonder if anyone knows where to find CE keys for S/360 CPUs. thanks, -- glen
Re: CE key
> If you're talking about the CE key that switched metering from > customer to IBM, I have no idea. Those were a real pin-tumbler lock; > not just a simple latch. They may even have been unique to each > machine, though I think it would've been impractical to have each CE > carry a jangling bunch of them around. I've never seen one on eBay, > but then there's precious little S/360 stuff on there of any kind. Yes, that one. I know that DEC used the same key for all the CPUs, and was guessing that IBM did, too. Also, I don't know if it would match the blank that ordinary locksmiths would sell. thanks, -- glen
Re: CE key
Here are pictures of the key switch: https://commons.wikimedia.org/wiki/File:Customer_Engineer_Key_Switch_for_IBM_S-360_computer,_view_1.JPG https://commons.wikimedia.org/wiki/File:Customer_Engineer_Key_Switch_for_IBM_S-360_computer,_view_2.JPG
Re: TOD
"Thanks you all very much, and I didn't realize it was in micro seconds. Thanks for that info." Bit 51 is in microseconds, so times 4096,or 2**(63-51). So, 5 seconds is 5*1000*1000*4096 or, as someone else indicated, X'4C4B4' Note that bit 31 is not so far from one second, being 2**20 us. -- glen
Intel Virtualization
> As for the ISA, Intel seems to be very "ad hoc" compared to the z > architecture. Especially in the virtualization arena. Basically, > the z has a _single_ virtualization instruction: SIE. > Intel has I don't know how many different versions of different > instructions to let hypervisors run at all. I don't > know how efficient vitualization actually is on Intel. > But it wouldn't surprise me if it were a pig. As far as I know, the biggest advantage z/ has over Intel (and many others) is the wait state. It is sometimes difficult for virtualization to figure out when the guest isn't doing anything. Most other systems use a null process with a small loop, while waiting for an interrupt. (But if you know you are running virtual, there might be some way around it.) I beleive that the wait state came from the days of usage meters, when the meter would stop while the processor was waiting. If not for rentals of S/360, it might not have had the wait state. -- glen
Re: Option to Prevent Data Loss Due to Truncation of Nominal Value
Seems to me what would be nice is a way to use the length of the second operand as the length for MVC or CLC. If you are copying into a buffer, it is the length of the source, not the length of the buffer, that you want to use. Once you do that, the given problem goes away. (You might then want a warning if the length was longer than the first operand, though.) -- glen
USING 0,0
I wonder if USING 0,0 and USING 4096,1 should work correctly. I have tried it with START 1000, and START 5000, respectively, such that addresses are in the appropriate range, but, using the Tachyon assembler, get addressability errors. Or maybe there is an assembler option to allow this that I don't see. This is my first time trying to assemble for absolute addresses. -- glen
absolute addressing example doesn't work
In the HLASM release 5 manual, there is an example: "If a register is specified with base address zero, the assembler will use it in preference to the default use of register zero. For example: | USING 3,0 | LA 7,5 | generates the instruction X'41703005'; in the absence of | the USING statement, the generated instruction would | be X'4175'. I suppose that works if it said "USING 0,3" but what I really want to know how to do is to generate real absolute addresses. I now have an example from Tachyonsoft that looks like: MYCODE START 1000 USING MYCODE,0 LOOP MP X,Y DP X,Z ZAP X,X(13) B LOOP XDC PL16'8000' YDC PL3'8001' ZDC PL3'8000' END LOOP which seems to work. It does generate offsets from zero, instead of from 1000 that it looks like it would. I still don't know why it doesn't subtract 1000 from the displacements. -- glen
absolute addressing
Roger wrote: > I don't think R0 has ever worked as a base register. Try another. (after I wrote) >> I wonder if USING 0,0 and USING 4096,1 should work correctly. >> I have tried it with START 1000, and START 5000, respectively, >> such that addresses are in the appropriate range, but, using >> the Tachyon assembler, get addressability errors. R0 works fine in the first 4K of core, which happens half the time on an 8K core machine. Convincing the assembler that you aren't using relative addressing is harder. From Tachyonsoft, and it seems to work like: MYPROG START 1000 USING MYPROG,0 seems to work. It looks to me like it should generate displacements from 1000 (the address of MYPROG), but it generates them from zero. The program is then loaded into core starting at 1000, and addressing works just fine. I haven't tried this in an IBM assembler yet, though. -- glen
absolute addressing
(snip, I wrote) >>I wonder if USING 0,0 and USING 4096,1 should work correctly. >What are you trying to accomplish? There are three forms of USING, >and all three require an address as the first operand. This is given as >a label to tell the assembler that the address of that label is in the >register specified. The assembler then computes the displacements >for other operands based upon the value that you have told the >assembler that you have placed in the register. >>I have tried it with START 1000, and START 5000, respectively, >What do you hope to accomplish with that? >>This is my first time trying to assemble for absolute addresses. >Do you mean that you are not using labels? If so, why? >What do you mean by absolute addresses? Do you intend that your >program will be loaded into a specific location in memory, determined >at assembly time? Yes, it will be loaded into the address specified at assembly. If I say: START 1000 the assembler generates addresses starting from 1000, and the program is loaded into those addresses. >In z/Architecture, and dating back to System/370, there >are three kinds of addresses: Dating back to S/360, actually... >o Virtual addresses. These are the addresses that programs normally > work with. >o Real addresses. These are the result of Dynamic Address > Translation of a virtual address. >o Absolute addresses. These are the result of applying the Prefix > register to a real address. Well, real addresses also work with DAT off, or on machines that don't have DAT. For actual use with OS/360, this likely only happens in an FLIH, (First Level Interrupt Handler), and the routine that first gets control on IPL, but the assemblers have to be able to do that. Someone from Tachyonsoft has told me the answer, though I am still not sure that I understand it. It goes like: XXX START 1000 USING XXX,0 In the usual case, the displacement is computed by subtracting the desired offset from the offset in the base register, 1000 in this case. But it seems that the assembler instead subtracts zero. I haven't yet tried: USING XXX,0,1 to see if it subtracts 4096, and generates displacements from register 1. -- glen
absolute addressing, continued
Thanks all for the help with this one. I have known for a long time that the assembler could generate absolute addresses, but never asked why. For those still following, here is the program that reads the object deck: BASR 11,0-2: 0DB0 XIO 78(19,11),80 0: D012B04E0050 BCR 5,11 6: 075B TIOB 8(11),16 8: 9A10B008 TIOB 68(11),1 C: 9A11B044 CLI 78(11),210: 9502B04E BNER 11 14: 077B LH12,84(11) 16: 48C0B054 CLI 80(11),X'D5'1A: 95D5B050 BER 15 1E: 078F CLI 80(11),X'E7'20: 95E7B050 BNER 11 24: 077B LH15,88(11) 26: 48F0B058 AH15,74(11) 2A: 4AF0B04A STH 15,50(11) 2E: 40F0B032 MVC 0(28,12),94(11) 32: D21BC000B05E BASR 15,11 38: 0DFB XIO 76(21,11),1 3A: D014B04C0001 BCR 5,1540: 075F BR12 42: 07FC HPR 2 44: 9902 BR11 48: 07FB DCX'D1FF' 4A: D1FF which runs on a real 360/20, though not, so far, with a real card reader. (Instead, I have an FPGA based virtual card reader.) I didn't write this one, it seems that it is related to HASP, and a program to make a 360/20, or larger 360, into an RJE station. (There is a different loader for other 360's, which I didn't disassemble. For those following such things, the PSW in the 360/20 does have an A bit, and I have run some decimal instructions with it set. -- glen
unusual instructions
"The OP said he was working with code for a model 20." That was only barely a true S360 and had a few instructions peculiar to it." Yes. XIO is the I/O instruction that reads or writes. Like other 360's, I/O is asynchronous. You have to test (with TIOB) to see if it is done yet. With 8K core, half the core is available without a base register. As I understand it, many were only 4K. It does have some fairly complex instructions, such as DP, ED, and TR, and leaves out some simple ones like L and LR. Registers are 16 bits, so LH, AH, SH, CH, and STH are there. AR and SR, but not most of the other RR instructions. PACK, UNPK, MVO, ZAP, AP, SP, CP, MP, DP so full decimal arithmetic. MVI, MVN, MVZ, CLI, MVC, CLC, NI, OI, ED, BR, B, BASR, BAS. and then the model 20 specific: XIO, TIOB, HPR, SPSW. -- glen
360/20 instructions
The detail on the instructions are in: httt://www.bitsavers.org/pdf/ibm/360/funcChar/A26-5847-3_360-20_funChar_Apr67.pdf The HRTBP360 program that IBM still distributes, I am told, with HASP, uses macros for the 360/20 specific instructions. (It was written to assembler with OS/360 or OS/VS2 assemblers.) The macros seem to still work with new assemblers. -- glen
BASR
(someone wrote) "I may be wrong but I have the Impression hat the 360/20 version of BAS/BASR (that machine's equivalent to BAL/BALR had a different op code from the current BAS/BASR." I have assembled BAS and BASR with the Tachyon assemmbler with the right X'4D' and X'0D' opcodes. I believe these are from the 360/67. There are some other diagnoses. I believe one jumps to a specified address in microcode, but the useful addresses aren't well documented. More are for the later serial numbers, with microcode in core. -- glen
360/20 instruction macros
OK, here are the macros as I use them, with the test for host machine removed. They come from the HRTPB360 program that is part of HASP. Note that OS/360 assemblers support BAS and BASR, possibly for the 360/67. -- glen *** V0082000 TITLE 'H A S P / R T P *MACRO DEFINITIONS*(MODEL 20 INSTS.)' V0083000 * V0084000 * V0115000 * CIO* CONTROL I/O V0116000 * V0117000 MACRO V0118000 &NAMECIO &A,&BV0119000 GBLA &MACHINE V012 &NAMENULL V0121000 DCX'9B'V0123000 DCAL1(&B) V0124000 DCS(&A)V0125000 AGO .END V0126000 EJECT V0133000 * V0134000 *DIALS READ MOD 20 DIALSV0135000 * DATA 1,2 IN LOC 252 V0136000 * ADDRESS 1,2,3,4 IN 253-254 DEC V0137000 MACRO V0138000 &NAMEDIALS &NULLV0139000 &NAMEDS0H V014 DCX'83000300' � READ DIALS INTO CORE V01410 00 MEND V0142000 SPACE 4V0143000 * V0144000 * HPR* HALT AND PROCEED V0145000 * V0146000 * V0147000 MACRO V0148000 &NAMEHPR &NUM V0149000 GBLA &MACHINE V015 &NAMENULL V0151000 DCX'9900',S(&NUM) V0153000 .END MEND V0156000 SPACE 4V0157000 * V0158000 * TIOB * TEST I/O AND BRANCH V0159000 * V016 * V0161000 MACRO V0162000 &NAMETIOB &A,&BV0163000 GBLA &MACHINE V0164000 &NAMENULL V0165000 DCX'9A'V0167000 DCAL1(&B) V0168000 AIF ('&A' EQ '*').A2 V0169000 DCS(&A)V017 AGO .END V0171000 .A2 ANOP V0172000 DCS(*-2) V0173000 .END MEND V0177000 EJECT V0178000 SPACE 16 V0179000 * V018* XIO* TRANSFER I/O V0181000 *
local labels
someone wrote: > I was raised to do single-instruction branches thus: > TM FLAG,BIT Is the flag bit set? > BO*+8Yes, skip next instruction > L R15,SOMEVALNo, get the value > *+8 DS0H > Yes, of course I realize that the "DS 0H" is meaningless, but it helps > readability. > My question is whether folks see this as: > - useful As long as you count right, and don't add/subract instructions. > - common I believe that they weren't so unusual in IBM written code. It might be that they assemble faster, and with the slow assemblers on early systems that might have been important. > - overly clever Only if you use even more tricks at the same time. > - evil > ...or what? > I've often wished for an assembly option that would note "*+n" branches and > warn if they were not skipping one instruction (and doing so *exactly*!). I suppose for branching instructions, but how about for memory referenc instructions? Some DEC assemblers have local labels, with a form like: 1$: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: (the : indicates it is a label). Local labels are unique only between two ordinary labels, making them convenient for the little branches like this discussion. That is a little easier than thinking up new names for each label. I don't know if anyone ever did it for S/360 and descendants, but: TM FLAG,BIT Is the flag bit set? BO*+10 Yes, skip A R15,ONE Add one NOPX'6F0' or Subtract one. But no-one would do that, right? -- glen
Re: local labels
As well as I know it, Macro-11, the assembler for the PDP-11, has local labels with the scope delimited by non-local labels. From: https://en.wikipedia.org/wiki/MACRO-11 .TITLE HELLO WORLD .MCALL .TTYOUT,.EXIT HELLO:: MOV #MSG,R1 ;STARTING ADDRESS OF STRING 1$: MOVB(R1)+,R0 ;FETCH NEXT CHARACTER BEQ DONE ;IF ZERO, EXIT LOOP .TTYOUT ;OTHERWISE PRINT IT BR 1$ ;REPEAT LOOP DONE: .EXIT MSG:.ASCIZ /Hello, world!/ .ENDHELLO The double colon makes an external label, single colon an ordinary non-extern label, and the 1$: is a local label, with scope between the HELLO:: and DONE:. The scope is delimited by ordinary labels, .PSECT, .CSECT, or .ASECT directives, but not equate symbol assignment. More convenient than thinking up dumb names for things that don't really need a name. http://bitsavers.trailing-edge.com/pdf/dec/pdp11/rsx11/RSX11M_V2/DEC-11-OIMRA-A-D_MACRO_75.pdf -- glen
Re: Branch table
> "Tony Harminc" wrote: (snip) >L R14,R4 (snip) > This sets R14 to the address of the adcon in the entry you just found > in the table (or it would if the above-mentioned boundary alignment > problem wasn't there). You need No, this loads R14 from an address near the beginning of memory. Pretty sneaky calling it R4, but the value is 4, so the result is actually L R14,4 or more precisely L R14,4(0,0) (unless you are on a PDP-10, where the registers are addressable as the first 16 locations in memory). -- glen
Re: Branch Table
Remembering how the bits are stored in the FAT12 table, you could alternate between entries with the A first and last. It makes the table lookup code slightly more complicated, but allows for aligned A entries. This probably only makes sense for really big tables with hundreds or thousands of entries, though. A macro that expanded with the C and A in appropriate order would make it easier. -- glen From: "Bernd Oppolzer" To: ASSEMBLER-LIST@LISTSERV.UGA.EDU Sent: Saturday, October 3, 2015 3:21:40 AM Subject: Re: Branch Table or:make the length of the function name a multiple of 4, since it is a design decision. 16 or 24 comes to mind ... some modern environments have even longer function names (64). When you have really large branch tables with hundreds of functions, sequential table lookup will be a performance problem. Then you should consider binary search etc. Kind regards Bernd Am 03.10.2015 um 11:56 schrieb mar...@pi-sysprog.de: > ah forgot. > > the table should be AL4(xxx) to avoid alignment
Re: Question of curiosity: Why are IVSK and TPROT instrictions privileged?
As mentioned previously, the ability to virtualize depends on instructions that can tell problem from supervisor state need to trap in problem state. The instruction I remember wondering most about when I was first learning S/370 assembler is STIDP. But that was before I knew about virtualization. I suppose virtual STIDP is useful. On the other hand, STCK not being privileged made Y2K testing harder, as one couldn't virtualize the clock. Also, and back to the 360/67, why is LRA privileged? Again, I presume virtualization, but I don't see any security problems with LRA, but on the other hand, there isn't any real use for it. -- glen
Assembler callable analogue of C/C++ time()
> SRLG uses a "source" and "target" register as well as #bits. > STCKE MILLSECS > LG R1,MILLSECS # IGNORE SECOND DOUBLE WORD > SRLG R1,R1,5 # SCOOT RIGHT 5 BITS > DSGF R1,=F'100' # DIVIDE BY A MILLION > CGHI R0,50 # COMPARE TO 1/2 MILLION > JL NOADD #DON'T ADD ONE TO RESULT > AGHI R1,1# ROUND UP > NOADD DS 0H > STG R1,DOUBLETIME Seems easier to divide by 3200 instead of shift and divide. Also, just add the 50 before divide if you want rounding. By the way, time() is Posix, not C/C++. (That is, it ins't part of the C standard, but a separate standard.) Also, the usual epoch is different from the STCKE epoch, so add another constant for that one. (Before or after divide.) -- glen
posix time epoch
For those doing time conversion, posix (used by most unix systems) uses the epoch of Jan. 1st, 1970. To convert from Jan 1st, 1900 to 1970, add -2208988790 seconds. I found this from: http://www.epochconverter.com/ But otherwise, it is 70 years with 17 leap days. -- glen
Re: Load module
> Sorry for the confusion caused. I strongly agree this is a basic question > and I too understand the Static, all the loads will be loaded in to main > memory and the load will be placed in to the main memory during execution > time, Dynamic. We can give Call macro and Load macro for the same. My > question was, what are all the possible options where we can say Static / > Dynamic by seeing anything? once again, am sorry for the confusion caused. There may be other explanations, but I usually think about the way the Fortran and PL/I (F) compilers are written. Fortran H uses the usual OS/360 static overlay system, which all goes into one load module. PL/I (F) uses a dynamic overlay, with around 100 load modules with names starting with IEM, and the first being IEMAA. Others have names like IEMAB, IEMAC, etc. So, it isn’t that one load module is dynamic, but the set of 100 all together.
Re: Load module
> Yes. My question was "In a called module, how do we determine > if it was called dynamically or statically” The whole design, since OS/360, is that you don’t. If you want to know, pass an argument to the load module that has a different value for the dynamic case. Using LINK, your module is called by the system in pretty much the same way as any other module is called. The only difference is in the arguments, which for statically called (or the first of dynamic) is the PARM string. If another load module calls you, with one argument that is a string after a two byte length, you should work exactly the same way as if you were not called from another load module.
Re: SDWA - SDWACMPC conversion
> Maybe I'm missing something, as this is a bit trickier than the usual > shlop, but wouldn't it be more efficient to OI the last byte of &TARGET > with x'F0', and skip the MVZ? Using =C'0123...'-C'0' for the TR table of > course. Maybe you are planning to do this a few billion times. Otherwise, do you mean more efficient in execution time, memory used, or time spent coding and debugging? Using the offset translation table requires that the origin is appropriate, such that the displacement isn’t negative. As a general purpose macro, when you can’t be sure where or when it might be used, that could be a problem. In addition, note the trial execution required when the translate table crosses a page boundary. But most likely more time has been spent discussing the efficiency than lost by any inefficiencies in the macro. —glen
Re: Count Words?
Nothing against discussions on how to write fast code, but I don’t believe that this is normally necessary. About 20 years ago, I was counting words, not just how many, but how many of each word, on gigabytes of text. (Full text US patents for two years.) I did it in Java (with JIT compiler on), and it was plenty fast enough. I did it using the Java StringTokenizer: https://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html which takes a regular expression for the delimiter. Then each word found was either added to a HashTable, or the count for it was incremented. As computers are much faster now, it should be able to do terabytes of text, today. There was one non-obvious thing about the Java code, though. It seems that the way Java normally does substrings is with a reference to the whole character array, which in my case was a line of text. That filled up memory faster than it should have. Using new String() on each word, fixed that problem. (It only does that for the actual entry in the hash table.) But if you do have exabytes of text, then there might be need for assembly speed-up. Well, OK, petabytes are enough. Oh, you might also look at the unix wc command, which counts words. (More specifically, the GNU utilities version, with source available.) About 25 years ago, I compiled the GNU utilities (as they then existed) to run on my OS/2 system. (That is before Linux, and such, that are so convenient today.)
S0C1
Shmuel (Seymour J.) Metz wrote: > No; it is guarantied to generate a program 001 interrupt. > You only get an ABEND S0C1 if there is no SPIE/ESPIE exit. I suspect that some use S0C1 as shorthand, and as you note incorrect, description for program interrupt 1.j It might be that some SPIE routines handle the interrupt, maybe print a message, and then allow it through to the OS. I do still remember S0C0 from the 360/91 days, which doesn’t mean program interrupt 0, though the low bits will be . Dreaded by anyone debugging from a hex dump. > I've written code that distinguished[1] between a S/360 and a S/370 > with a SPIE[2] for codes 1 and 2; the exit assumed that it was a S/370 > if the code was 2. I wouldn’t have thought of that one. Pretty neat.
debuggers
Bernd wrote: > We also had a self-written batch debugger, which relied completely on > S0C1 and SPIE to do its instrumentation and implement the breakpoints; > at least in the first version. Reminds me of a debugger I used with Orvyl/370 in S/370 days. I believe it used SVC 255 for breakpoints, which was fine. The when you continue from the breakpoint, it has to somehow execute the instruction at the breakpoint before continuing. I had put a breakpoint on a BR 0 instruction, which was common in the object code from PL/I (F). The debugger branched to the address in register 0. Fortunately, I knew who to contact to fix the bug. No-one had ever tried that before.
D
Someone wrote: > Thought it was a double word > As in DS D It is a doubleword, specifically a long (64 bit) floating point type. And yes, DS D and DS 0D are commonly used when floating point is not intended. And as Fortran programmers would know, E is the short (32 bit) floating point type. Now that I think about it, I don’t remember the assembler notation for 128 bit (extended precision) floating point constants, though am pretty sure that it isn’t the Q that IBM and DEC Fortran uses. I suppose I don’t see anything wrong with 0D for doubleword alignment, even when not for floating point data. Probably better not to use D or 2D or others, though. D would be the one that needed doubleword alignment for OS/360, and so its use goes back that far. One could use FL8 for fixed point data, but I suspect without doubleword alignment.
Re: CDS and alignment question
It is the address in memory that matters. This reminds me of programs with two base registers, using LA to set the registers such that the offset of the second is 4095 from the first. All instruction addresses (an branch instructions) will then have an odd offset, legal but it looks funny. On the other hand, consider all the wasted bits in even offset branch instructions. -- glen
Re: Any ideas on how to know if a DDNAME is input or output?
The reminds me of some problems with Fortran many years ago. (Before OPEN was added, though I believe it is still optional.) It seems that Fortran opens the DDNAME for INOUT by default. That is true even if the first operation is READ, as one is allowed to REWIND (or BACKSPACE) and then WRITE. There were some cases where that was not desired, and the solution, if I remember it right, is LABEL=(,,,IN). (I could get out a JCL book.) As for the question, I don't know how common it is to open for INOUT (or OUTIN), but that will restrict the ability to test for input only. -- glen
Edit instruction
The book "Computer Architecture: Concepts and Evolution" by Blaauw and Brooks has many descriptions on how instructions got to be the way they did. The book covers a wide variety of machines, though S/360 is a favorite example. (Blaauw was the main designer of S/360, so it isn't so surprising.) There is a small description of EDIT in section 5.1.3. They trace back to "Store for Print" on the 702. Then explain that EDIT is rarely used by COBOL or Fortran for print conversions, and that it is best that it should be left out of instruction sets. If you like asking questions like that, especially for a variety of different machines, you should get the book. -- glen
Re: EDIT instruction
>(after I wrote) >> The book "Computer Architecture: Concepts and Evolution" by >> Blaauw and Brooks has many descriptions on how instructions got >> to be the way they did. >> The book covers a wide variety of machines, though S/360 is >> a favorite example. (Blaauw was the main designer of S/360, >> so it isn't so surprising.) >> There is a small description of EDIT in section 5.1.3. >> They trace back to "Store for Print" on the 702. >> Then explain that EDIT >The instruction is ED, not EDIT,; its companion is EDMK. You want to argue with Blaauw on the name of an S/360 instruction? The instruction is EDIT, the assembler nmemonic is ED. >> is rarely used by COBOL or Fortran >> for print conversions, >That's probably because the instruction was optional >on the small early models of S/360 >and the software was written to use basic instructions. >Nevertheless, there's no reason for not using it, >because the small machines that didn't have those instructions >have long since passed to computer heaven. For hand coded assembler, it isn't bad, but for high-level languages it is easier to write a software loop than to conform to the instruction. Much of S/360, as with VAX, was designed around assembler programmers. Later it was found that compilers only generated a small fraction of the instruction set on most machines. >That said, I understand that IBM 360 compilers didn't use TRT, >which IIRC was a standard instruction. >BTW, EDMK was used for all decimal output in the optimising >XPL compiler. >> and that it is best that it should be left out of instruction sets. >A bad recommendation, because so much is done by ED and EDMK, >and with little effort and even less overhead compared with alternatives. A reasonable cost/benefit analysis of the actual use, done some years later. >> If you like asking questions like that, especially for a variety >> of different machines, you should get the book. >I wouldn't bother, if that is the level of its advice. If you don't believe Blaauw regarding S/360, then who do you believe? -- glen
Instruction selection
Someone wrote: > Should we have machine instructions to compute a polynome of grade n? > I don't think so (but there were machines in the 60s which did just that, > and - in that period - they were faster by using such instructions). VAX had polynomial evaluation in the 1980's, and it was well known to be slower than doing it with separate instructions. For that reason, it was likely rarely used, even if it got faster in later versions. The VAX instruction for doing subscript calculations, including bounds checking, was also known to be slower than doing the same thing without the special instruction. RISC or CISC, if some operation is done often enough it makes sense to have a special instruction. As Blaauw did much of the design of the S/360 architecture, in many cases he is criticizing himself. It would be rare for ED or EDMK to be used enough in a program to make a significant contribution to the CPU usage. (Most likely even in 1963.) Decisions that make sense one year might not the next. The S/360 instructions have done well over the years. -- glen
Re: EDIT instruction
(previously I wrote) >> The book "Computer Architecture: Concepts and Evolution" by >> Blaauw and Brooks has many descriptions on how instructions got >> to be the way they did. >> (Blaauw was the main designer of S/360... > I thought that Gene Amdahl was the principle architect of 360. > A search to check my facts seems to reveal that Amdahl, Blaauw > and Brooks led the design team. I don't know the actual hierarchy, but yes it was those three. My feeling was that Blaauw made the higher level decisions (should we have an EDIT instruction) and Amdahl the lower level decisions (can we really implement this, how many digits can it do, etc.) Both are pretty important. Brooks, at least as described in "Mythical Man Month," led the OS/360 project. In the above mentioned book Blaauw takes the blames for what he considers his mistake in adding the EDIT instruction. As to programming, microcode is now usually considered firmware, though the term is likely more recent than S/360. The microcode of most S/360 models was actually hardware, physical capacitors or transformers. The floppy disk was origially meant to load the microcode store in S/370 models, replacing the hardware microcode storage. More recently, hardware is designed in verilog or VHDL, hardware descriptor languages. Logic gates can be written out as easily as software. As the cost of masks has increased, hardware is more often done through programmable logic where bits activate gates on a chip. Even more, there are system that allow for dynamic reconfiguration, the hardware equivalent of self-modifying code! -- glen
calling convention
(someone wrote) > My understanding is that the C standard calls for all parameters > to be passed by value. My experience is that IBM's C usually > passes parameters by reference except that if a parameter is a > pointer it gets passed by value. Go figger. That is most consistent with the way it was traditionally done. The requirement is for "as if" to work. It should be possible to pass the addresses and the callee makes a local copy, or pass addresses of copies. The OS/360 Fortran compilers (G and H) make local copies of scalar variables, and then copy them back before return. (Usually described as call by value result.) That is legal Fortran. For a Fortran call, local variables will have compile time (relocatable) address constants, but dummy arguments arrays will use the address passed in with the call. PL/I passes the address of a temporary variable for expression arguments, or arguments known to have different attributes. To be most consistent with the OS/360 calling conventions, as a series of A-type address constants, the last with the high bit set, one would either pass addresses of copies, or expect the called routine to make copies. That would allow for calls between C and other languages. -- glen
Re: calling convention
(snip, I wrote) >> The OS/360 Fortran compilers (G and H) make local copies of scalar >> variables, and then copy them back before return. (Usually >> described as call by value result.) That is legal Fortran. > FORTRAN tries pretty hard to accommodate the idiosyncrasies > of various implementations. I suppose that to make this all > work the Standard must contain a statement that if a variable > is passed as a parameter but the called routine modifies it > via a COMMON block, the effect is implementation-dependent. There are a number of cases, most of which come out as anti-aliasing rules. Partly it is to allow for optimization, when the optimizer shouldn't have to figure out when something might change. That applies both to argument also in common, and repeated use of the same argument. >> For a Fortran call, local variables will have compile time >> (relocatable) address constants, but dummy arguments arrays >> will use the address passed in with the call. >> PL/I passes the address of a temporary variable for expression >> arguments, or arguments known to have different attributes. >> To be most consistent with the OS/360 calling conventions, >> as a series of A-type address constants, the last with the high >> bit set, one would either pass addresses of copies, or expect >> the called routine to make copies. That would allow for calls >> between C and other languages. > But it doesn't. If the actual parameter is a pointer, IBM's > C places not the address of that parameter but its value on > the stack (or in the parameter block). Note that Fortran places the address in the parameter block, either a compile time constant or run time passed argument. The important point being that, at least with the traditional convention, the parameter block values aren't modified. It is non-standard to mix pointers and integers without a cast on function call, though many old C programs did it. So, you should be able to use a different calling method for pointers and non-pointers. It gets more complicated in the varargs case, but I believe it still works. Having the calling routine pass the address of a copy should always work, though it a little less convenient and probably slower in some cases. Having the called routine make the copy allows for no copy in the case where the (pass by) value isn't changed. Note that C allows structures, including structs holding arrays, as arguments, but not, pass by value, arrays. (An array name, by itself, means the array address.) Passing the address for pointers and arrays in the parameter block allows for calls to/from Fortran where the dummy argument or actual argument (Fortran terms) are arrays. For scalars passed between C and Fortran, it is natural to instead pass a pointer. Fortran will do this by default, C with the & operator. Though Fortran now allows for call by value with the VALUE attribute, most likely the common convention being to pass the address. -- glen
Fortran II functions
> Finally, ISTR, but can find no references, that FORTRAN II had > a two argument SGNF(X,Y) defined as the magnitude of X with the > sign of Y. A plausible motivation is this was a single machine > instruction on the IBM 70x series -- doubleword shift with a > count of zero. The SIGN function is still in Fortran, along with the more specific functions ISIGN and DSIGN (for integer and double precision). (Fortran II function names had to end in F, a restriction removed for Fortran IV and the ANSI Fortran 66 version.) (Newer standards include the effect when X is zero on machines supporting a negative floating point zero.) The arithmetic IF is still in Fortran, though its use is discourage and it is, I believe, on the obsolescence list. -- glen
Re: FORTRAN II functions
(snip, someone wrote) > o IBM hexadecimal floating-point, HFP, > o ANSI binary floating-point, BFP, and > o ANSI decimal floating-point, DFP. > Of these the first two, HFP and BFP, make zeros positive; but the > third, DFP, supports both positive and negative zeros. The change to the Fortran standard comes, I believe, from support for IEEE binary floating point, which is what went into IBM's BFP. Among others, the reciprocal of -Infinity is supposed to be negative zero. DFP, from the new IEEE standard, should also include all the negative zero properties of the old standard. (snip, someone else wrote) > What is x'8000 ' interpreted as HFP? I do remember that LNER and LCER generate negative zero, but I am not sure about some other cases. How about: X=-1e73 Y=1e-10/X with exponent underflow mask bit off? In any case, in all three (HFP, BFP, and DFP) negative zero and positive zero compare as equal. It is only with tests like SIGN(X) in Fortran that you can detect negative zero. Many years ago, I learned that the CALL/OS Fortran compiler (or, more likely, library) would print +0.0 if given a negative zero. No sign was printed for positive zero. -- glen
Underscore character
(snip, someone wrote) > You've sometimes admonished me for taking the synchronic view > rather than the diachronic. But here, you're being narrowly > synchronic. In the Bad Old Days of Yore, mechanical serial > printers could be commanded to underscore with the sequence > . In this > diachronic perspective, "underscore" is not a misnomer, merely > antiquated. No, you write a second line with a '+' as carriage control character. This is even so popular as to be a special case for the 3800, which otherwise does not allow writing two characters on one print column. Presumably it builds a record in a buffer, allowing overprint with different fonts, and a special bit to indicate underlining. With ink and ribbon printers, you can get darker print (bold-like) by overprinting the same characters using '+', though I believe that the 3800 also doesn't do that. -- glen
Re: How bad is the EX instruction?
> For short EX MVC's the burden of getting stuff in the right registers > makes MVCL less interesting. As I understand it, and doesn't seem to have been mentioned, the big effect on EX has to do with caching. I believe that it should be near code and not data. (That is, it goes into the instruction cache instead of the data cache.) Then again, I could have that backwards. Other than cache, it should be plenty fast enough. > My preoccupation with this is mostly on Friday ;-) And I guess I > should not write real code on Friday 13th anyway... > The EX CLC is in fact in loop scanning a linked list for the right > entry among 100-200 elements. My big savings were moving the TRT etc > out of the loop. I was tempted to also take the decision between CLC > and EX CLC out of the loop, but didn't for ease of maintenance. I usually use a hash table. Especially if speed is important. You could also do binary search, which will find the right entry with about log(n) comparisons. -- glen
Re: MNEMONICS
(someone wrote) > IHMO, the mnemonic for BCT was not well-chosen. > Better might have been DBZ > for Decrement and Branch on Zero. That would be Decrement and Branch on Not Zero, DBNZ, and also DBNZR. Sounds too much like DEC to me.(*) I believe none of the S/360 instructions are more than four letters long, though. >As for the below case of BALR, clearly, there needed to >be yet another instruction :- (*) I was doing S/370 assembly programming for a few years before I first programmed a DEC system, a PDP-10 running TOPS-10. The DEC mnemonics are a little different, but the decrement and skip/jump are usual. Note that on the PDP-10, the JUMP instruction doesn't jump, the JUMPA instruction actually does, but usually JRST is used instead. -- glen
bit masking
> I am working with some IPv6 addresses that are 128 bits long. > The input to the program is an ip name or address and the > number of high bits that I need to use for a compare against > another ip address. > So, I want to create run time routine to build the a > 16 byte 'and' bit field based on the input number of bits. > (I will then 'and' both addresses and then use a simple CLC.) There is no double 64 bit (that is, 128 bit) shift instruction as far as I know. Most obvious is to store the bits in some number of bytes, halfwords, words, or doublewords. Then, based on the shift amount, fill some with all ones, and use a shift instruction (or smaller table) for the boundary case. I would probably choose words. Using shift and mask, split the shift amount into 32's and a remainder (or use Divide). For bytes in memory, EX an MVC, or a loop of MVI, to fill the high bytes. Use a table of bytes to IC and STC the boundary byte. -- glen
more than one base register
Someone wrote: > MYCSECT CSECT > USING *,R15 > B BYID > ID DCC'module-name' > BASESDCA(MYCSECT) > DCA(MYCSECT+4096) > DCA(MYCSECT+2*4096) > DCA(MYCSECT+3*4096) > BYID DS0H > LMR9,R12,BASES > DROP R15 > USING MYCSECT,R9,R10,R11,R12 This looks more like compiler generated code than what I would expect from a person. Then again, my start on learning assembler was reading the LIST output from the compilers. When I saw the 4095 in the subject, I was expecting the old: L 12,4095(15) L 11,4095(12) L 10,4095(11) USING MYCSECT,15 USING MYCSECT+4095,12 USING MYCSECT+2*4095,11 USING MYCSECT+3*4095,10 The LM form seems to waste fewer bytes loading the base registers (including the A constants), especially if one already has the branch around the csect name. But, why the DS 0H instead of putting the label on the LM? -- glen
DS 0H
(snip, I wrote) >> But, why the DS 0H instead of putting the label on the LM? > I do the same thing for "labels" to "code". Why? Hum, I guess > from reading the HASP code long ago. Also, it makes it > easier to insert a new instruction at that logical point in > the program without remembering to remove the label from the > old instruction and move it to the new one. That I don't disagree with, but what is the probability of wanted to add new code between the B and the LM? I suppose one still has over 4000 bytes of code (not counting data references) before one needs the next base register, but, really, what else would you want to do there? Now that I write that, where is the STM 14,12,12(13)? Still, that isn't the kind of change I would plan ahead for. At the time, I was considering differences between compiler generated and human generated code. I suppose that one isn't a very good test, though. > In addition, if you use SUPERC to compare the two sources > (before & after), then the old instruction does not show > up an a "delete" and "add". Only the new inst ruction shows up > as an "add". Remember the days of IEBUPDTE to update source. > Fewer updated cards means fewer mistakes. Oh, yes, in the general case I agree. It just seemed unneeded in this specific case. -- glen
Re: OPSYN self execution
Jonathan Scott wrote: > If you want to modify DC, you need to define an opcode which > refers to the original DC first so that you can invoke it from > within the macro. > DC_ OPSYN DC Set up alias for original DC > DC OPSYN MYDCRedirect DC to my macro > Then within the macro you can use > DC_ &whatever Issue real DC But John Ehrman's method is neater, as it doesn't require a special OPSYN from the outside. Some one could directly call MYDC, or use OPSYN, either way it would work. I have never used OPSYN, but I have written postscript programs that redefined the \def operator. Now, what happens if OPSYN is OPSYNed? -- glen
Re: Instruction Lists/Counts.
Instructions are hard to count, though instruction count isn't a very good way to determine CISCness. RISC tends to have a small number of instruction lengths, often 1. S/360 through z/ have three lengths. Not too CISCy, but not RISC. (VAX might have 14 or so, from one byte on up.) RISC tends to minimize address modes. Some have been added lately, but the largest fraction of instructions executed should still be RR or RX. Not too CISCy, but not so RISCy, either. VAX has many address modes, 21 on the list that I have, but 14 of those also have an indexed mode, so it should be 35. And there can be more than one such address per instruction. (Many operands are register only, but I am pretty sure that there are some where two operands can have one of those 35.) Many RISC systems try to execute every instruction in one cycle. That brought things like MULTIPLY_STEP, an instruction that did part of a multiply, but that had to be executed many times to do an actual multiply. Most try to avoid this now. There are some pretty complicated instructions even from S/360, and many complicated ones added later, which are pretty CISCy. Still, in terms of instruction length and address modes, not so bad. Since S/360 through z/ use different opcodes for different addressing modes of the same instruction, do you count those as separate instructions, or just one? (Compare to VAX, where there is an opcode byte and address mode byte.) -- glen
Re: handling a remainder form a DP
> My result from a DP in dividing 1300 by 3 is 00 00 00 43 3C 00 1C > but on a calculator it is displayed as 433.3 - which is what > I want to display in a field on a screen. How do I turn that > remainder of 1C into the decimal value ? You should have enough to do it as scaled decimal. Consider the dividend as 1300., divide by 3 and you get 433. ( and remainder 0.0001) Multiply the dividend by 1 (probably with SRP) then do the divide, and the quotient will have four digits after the decimal point. Print at appropriately. If you don't have enough digits to do that, you can convert the already computed remainder by muliplying it by 1 (SRP) and then dividing it by the original divisor, 3, to get remainder 1. That is, considering the shift, 0. remainder 0.0001. -- glen