Skip to content

In Which WiringMVS Punches Through TK4- Hercules


Ok. I now have Hercules built to run the TK4- environment properly and I have ported my SVC 255 bodge to that version. This is a change to the emulation of the supervisor call instruction that causes it to execute my C++ code instead of running an MVS operating system routine if a program calls SVC 255 with 0x42 in register 0. My C++ code interprets registers 1 and 2 to call the appropriate wiringPi routine e.g. R1=0 R2=1 is equivalent to pinMode(1,INPUT); R1=5 R2=12345 is a delay of 12345 MS.

Below is the jobstream submitted in the demo video and the MVS console after the job ends. There’s nothing very exciting in these baby steps but I am closing in on submitting a batch job and having the rogue 370 driving a robot car.

Advertisements

Olduino/370 Goes Rogue

I’m planning to use the olduino/370 in a couple of projects where it will have to be mobile. It needs a case, and I think it would be funny to have a robot car running around with a miniature mainframe on top.

Accordingly, I am retcon-ing the IBM 370/158 mobile edition. This would’ve been a special purpose mainframe optimized for battery power and use in the field. It has the full 370 instructions set but only limited I/O and it’s meant to be set up in something like a FEMA field camp for keeping track of people and possessions.

The real /158 had a dedicated 3270-type terminal on a separate table and didn’t have much of a control panel. My reimagined version has the screen built into the front of the CPU and an IPL control panel in the bottom right. Only the power button is set up high to keep kids from fiddling with it. Once it’s IPL’d and running the control panel is disabled with a key switch. There’s a running status display on the integrated 3270 but all user interaction is through separate terminals connected through packet radio and the arpanet.

The original is 61 inches high 32 inches wide and quite deep. I am aiming for something like three inches high, 1.5 inches wide, and 1.5 deep mostly so it will be sort of proportional with a little oled display set into the front. The control panel is shown larger than life because I want at least some of the buttons to actually be functional and maybe show some lights behind it.

There would be bags of room inside for a Pi zero and batteries and probably a solderless breadboard for mounting things like the motor controller for the robot car. Not sure about mounting sensors but may be a blue coloured breadboard on top wouldn’t be crazy.

I did this with paper because I have access to a colour printer and it was easy, I am hoping I can find a 3-D printable raspberry pi case that I can adapt to my dimensions.

I found some good pictures and size information for the /148 on the Computer History Museum web site. Below there’s an image of a full /148 computer room and of a museum artifact that shows the outlines of it. I wouldn’t mind profiling the front the way the 148 panel is fitted.

MVS On the Pi 3B

img_2584
The Pi 3 B is faster than the Zero by a fair margin. 1.2MHz vs 700MHz. It’s also four cores vs the single core Zero although i wouldn’t expect it to make a difference running my single instance of Hercules/MVS. I suspect that there are details that make the single core performance better though. The Pi 3 B cranked out 100,000 Dhrystone passes in about 10 seconds. 10K/sec is 5-6 MIPS vs the Zero’s 2 MIPS.
It’s noticeably faster running the work as well and more responsive on TSO.

Starting Fresh

18-09-11 frontpanel
18-09-11 baseline version
I’m starting a fresh build with a new SD card in a Raspberry Pi 3 model B
This involves:

  • the latest raspbian zip file(2018-06-27-raspbian-stretch-lite.zip)
    from https://www.raspberrypi.org/downloads/raspbian/
  • burned to a 16GB SD card with etcher
  • an empty file named ssh and a complete wpa_supplicant.conf in the boot partition
  • find the ip address with arp-scan from another pi (192.168.1.246)
  • logon and change the pi password with “sudo passwd”
  • download the current TK4- with
    “wget http://wotho.ethz.ch/tk4-/tk4-_v1.00_current.zip”
  • unzip with “unzip tk4-_v1.00_current.zip”
  • start mvs with ./mvs

I got the version info above by accessing 192.168.1.246:8038 from chrome on windows

My Own Private Hercules – Rebuilding Hercules for TK4-

18-09-11 frontpanel
18-09-13 my version
I got instructions from the developer responsible for the TK4- package for rebuilding it as follows:
18-09-07 buildinst
I got a good description of the recommended process from this web site: https://robots.thoughtbot.com/the-magic-behind-configure-make-make-install

There were only 3 files in the Architecture_dependencies folder that had to be copied into the source folder as below:

pi@raspberrypi:~/mvs4mod/hercules/source4mods$ ls
Architecture_dependencies  Hercules_for_TK4-_Update_08
pi@raspberrypi:~/mvs4mod/hercules/source4mods$ cd Hercules_for_TK4-_Update_08/
pi@raspberrypi:~/mvs...$ cp /Architecture_dependencies/32-bit_dyn75.c dyn75.c
pi@raspberrypi:~/mvs...$ cp /Architecture_dependencies/32-bit_tcpip.c tcpip.c
pi@raspberrypi:~/mvs...$ cp /Architecture_dependencies/ARM_cmpsctst.h cmpsctst.h

I then had to run automake –add-missing before ./autogen.sh would work


pi@raspberrypi:~/mvs...$ automake --add-missing
pi@raspberrypi:~/mvs...$ ./autogen.sh

aclocal...    OK.  (25% done)
autoheader... OK.  (50% done)
automake...   OK.  (75% done)
autoconf...   OK.  (100% done)
All processing sucessfully completed.
You may now run ./configure in order to create a custom Makefile
that is suitable for your platform and environment.

I was then able to run ./configure which generated makefiles.

The generated Makefiles caused a compile error with GCC to do with the CPU type. I reran make as “make -j 4 CFLAGS=”-W -w -O3 -frename-registers”

Because the make file expected to delete some files I had to create nl.gmo and de.gmo (“touch nl.gmo de.gmo”) to get it to run.

After that, “make install” moved the generated binaries into /usr/local/bin and /usr/local/lib.

To get TK4- started with my binaries i edited the MVS batch script (saving it as MVS2) and forced those directories into PATH and LD_LIBRARY_PATH as follows(around line 20)
case $system in
linux)
force_arch=
export PATH=/usr/local/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/lib/hercules:$LD_LIBRARY_PATH

I spent some time dinking around “touch”ing various things co convince myself my build was running and finally changed version.c to include a line of my own around line 225
“BUILT BY BILL!”,

Now it works and, although it identifies itself as the base Hercules rather than the version for TK4- I can see my BUILT text. It ipls MVS, shows its console on :8038, and accepts and runs batch jobs which is all i really wanted.

Faster But Flakier – Punching Through Hercules

I hacked the SVC processing code of the Hercules Emulator to let me get at the hardware of the Raspberry Pi. I’m using the WiringPi library so it’s not super fast but with minimal processing on the 370 side I can flip the GPIO in around 1.4 uS which is probably fine. Some function of Hercules is generating an interrupt every 10mS which takes control for 300 uS or so. You wouldn’t want to be driving a servo or reading an ultrasonic sensor but it should be fine for general use. I assume I can use native Pi or WiringPi functions in those cases.
The images blow show the interruption every 10mS and the fine-grained square wave in between.

I’m pretty sure that the interruption is in hercules code rather than linux because it always happens right after a 370 branch instruction is processed.

My 370 test code is very hard core – just a dozen instructions banged into low memory. I’m doing this because it’s kind of fun and also because the version of hercules that i’ve modified doesn’t run MVS TK4- properly yet. Once I get that figured out i’ll develop some C wrappers for the SVC calls.
18-08-19 dwon
I have to say i’m a bit amazed that i can program 370 machine language 40 years after my stint as a system programmer. Not just to remember that the opcode for LOAD Address is 41 but that 41 10 0002 would load a 2 into register 1 or that an unconditional branch is 47F0xxxx.

The code below is my first crack at letting a 370 program access the underlying Raspberry Pi. This is inserted in module general2.c around line 1300 where the Supervisor Call is emulated. Normally an SVC would cause the emulated CPU to pick up the address of some 370 code from fixed 370 memory locations and branch to that code but with this mod the emulator directly performs some function based on the 370 register contents and returns to the emulated program. It’s nasty but it gets the job done. As long i don’t expect my modfied hercules to work anywhere other than on the Pi it should be fine.

int wiringMVS(int function, int parameter){//implements wiringPi functions for MVS
	static int wiringPiIsSetup=0;
	static FILE* wiringMVSLog;
	int result=0;
	if (!wiringPiIsSetup){
 		printf("Setup() sez %d\n",wiringPiSetup ());
		wiringPiIsSetup=1;
	}
	switch (function){
		case 0:	//pinmode INPUT
			pinMode(parameter,INPUT);
			break;
		case 1: //pinmode output
			pinMode(parameter,OUTPUT);
			break;
		case 2: //digitalWrite(LOW)
			digitalWrite(parameter,LOW);
			break;
		case 3: //digitalWrite(HIGH)
			digitalWrite(parameter,HIGH);
			break;
		case 4: //digitalRead
			result=digitalRead(parameter);
		case 5: //
			delay(parameter);
			break;
		case 6: //
			if (wiringPiIsSetup!=1){
 				printf("Setup() sez %d\n",wiringPiIsSetup,wiringPiSetup ());
				wiringPiIsSetup=1;
			}
break;
	}
	return result;
}

 

---Near the top of the file
#include
#if !defined(_GENERAL2_C_)
#define _GENERAL2_C_
#include "wiringMVS.c" //WJR
#endif
---Near line 1335
/*-------------------------------------------------------------------*/
/* 0A   SVC   - Supervisor Call                                 [RR] */
/*-------------------------------------------------------------------*/
DEF_INST(supervisor_call)
{
BYTE    i;                              /* Instruction byte 1        */
PSA    *psa;                            /* -> prefixed storage area  */
RADR    px;                             /* prefix                    */
int     rc;                             /* Return code               */

    RR_SVC(inst, regs, i);
//following 12 lines per wjr 18-07-28
#if 1
//printf("bingo! i=%x, regs->GR_L(0)=%x\n",i,regs->GR_L(0));
/* if we have an SVC 255 and R0 is set to a magic number, then
we invoke the wiringpi code for MVS */
if ((i == 255) && (regs->GR_L(0) == 0x00000042))
	{
	regs->GR_L(15)=wiringMVS(regs->GR_L(1),regs->GR_L(2));
    	PERFORM_SERIALIZATION (regs);
    	PERFORM_CHKPT_SYNC (regs);
    	RETURN_INTCHECK(regs);
	}
#endif

In addition to those source code changes I had to install wiringPi itself from http://wiringpi.com/download-and-install/ and change the LIBS line in the makefile (around line 823) to
LIBS = -lrt -lz -lresolv -lnsl -lm -ldl -pthread -lwiringPi
Obviously I’d rather no diddle the generated makefile but I’m not clear how to pass that from the command line.

Whoah That’s Slow! – Just How Bad Was My Blinker

A while ago I perpetrated a LED blinker under MVS. The MVS program was writing to an emulated printer on unit 30F. Hercules was piping the output to a program called leder.c that would write the passed data to a raspberry pi LED via the file system. I figured it would be too slow for practical use but i didn’t really know. I tried it today and found that it took 10+ seconds to cycle the LED 1000 times. To avoid a startup effect i tried it 2000 times and it took 20 seconds. I got the same sort of timing when i directed the output to a real file without the pipe and even when i sent it to /dev/null. If I change the MVS JCL to DD DUMMY(the MVS equivalent of /dev/null) the time goes to near zero which is more what i would expect. It’s actually pretty stunningly slow. I’m not sure whether the time is being spent emulating 370 instructions or just running hercules I/O on the Pi.

It’s not really straightforward to access the GPIO’s from C code on the Pi. One option is wiringPi which implements an arduino type environment.

I’m able to build hercules from source although it’s not the version used by the TK4- turnkey MVS setup. I can run simple code in it from the console but i haven’t tried to bring up MVS.

As an experiment i’ve goobered the SVC instruction to blink my LED using wiringPi. I’m hacking at hyperion/general2.c changing code around line 1335 as below:

/*-------------------------------------------------------------------*/
/* 0A   SVC   - Supervisor Call                                 [RR] */
/*-------------------------------------------------------------------*/
DEF_INST(supervisor_call)
{
BYTE    i;                              /* Instruction byte 1        */
PSA    *psa;                            /* -> prefixed storage area  */
RADR    px;                             /* prefix                    */
int     rc;                             /* Return code               */

    RR_SVC(inst, regs, i);
//following 18 lines per wjr 18-07-28
#if 1
//printf("bingo! i=%x, regs->GR_L(0)=%x\n",i,regs->GR_L(0));
/* if we have an SVC 255 and R0 is set to a magic number, then
we have ignition */
if ((i == 255) && (regs->GR_L(0) == 0x00000042))
	{
	//printf("bango! i=%x, regs->GR_L(0)=%x\n",i,regs->GR_L(0));
	if (~wiringPiIsSetup){
 		printf("Setup() sez %d\n",wiringPiSetup ());
                wiringPiIsSetup=1;
	}
  	pinMode (1, OUTPUT) ;         // aka BCM_GPIO pin 18
	digitalWrite (1, 1) ;       // On
	delay(5000);
    	digitalWrite (1, 0) ;       // Off
    	PERFORM_SERIALIZATION (regs);
    	PERFORM_CHKPT_SYNC (regs);

    	RETURN_INTCHECK(regs);
	}
#endif

To get that to compile and link i had to manually edit build/cmakecache.txt changing line 83 to CMAKE_EXE_LINKER_FLAGS:STRING=”-lwiringPi” Then in the build directory the usual cmake –build . did the rest. Changing the cache caused a full rebuild but i’ve made a couple of simple changes since and they just rebuilt the affected modules.

This is pretty workable although it means goobering code that would be used by mainline MVS and it takes it out of the I/O realm altogether. It’s not completely clear to me whether my one-time initialization test is working or not but it doesn’t blow up, so that’s something.

I guess to continue this path I would need a little protocol and a “safe” svc – also a way of only compiling this for the raspberry Pi architecture.

I guess pinMode, digitalWrite, digitalRead would be a start.

Hardcore Hercules Hello World

I found a great web site with an excellent discussion of bare metal programming a 370 processor under hercules. One of his first steps is to make an IPL’able card deck.  I adapted his example to do a Hello World program.

The program is written in 370 assembler and nicely illustrates what an ipl’able program has to do.  There are 5 “cards” in the deck: The first two include channel commands to read the last three which are the actual executable code.  To prepare the code for ipl’ing there’s a prefix of more assembly code that punches out the card images.

I run the assembly and execution under MVS then boot another hercules instance from a card reader pointed at the “punched” output.  The result is not terribly dramatic but i can look at the emulated printer output file and see my HELLO WORLD text.

//ASMHW JOB CLASS=A,MSGCLASS=A,REGION=4096K
//ASM EXEC ASMFCLG
**********************************************************************  00010000
* punchHW.jcl                                                                00020000
*                                                                       00030000
* PUNCH OUT A CARD DECK THAT WILL IPL AND THEN PRINT HELLO WORLD        00040000
*                                                                       00060000
**********************************************************************  00070000
PCHHW    CSECT ,                                                        00080000
         STM   R14,R12,12(R13)    SAVE CALLERS REGISTERS                00090000
         LR    R12,R15            R12 IS PROGRAM BASE                   00100000
         USING PCHHW,R12                                                00110000
	 B     PASTID
	 DC    'PCHW'
PASTID   DS    0H
*                                                                       00120000
         LA    R1,SAVEA           POINT TO NEW SAVE AREA                00130000
         ST    R1,8(,R13)         CHAIN                                 00140000
         ST    R13,4(,R1)              ON                               00150000
         LR    R13,R1                    SAVEAREA                       00160000
*                                                                       00170000
*                                                                       00180000
         OPEN  (PUNCH,OUTPUT)     OPEN OUTPUT FILE                      00190000
**********************************************************************  00200000
*  WRITE FIRST IPL CARD WITH 24 BYTES OF DATA (PSW,CCW,CCW)             00210000
**********************************************************************  00220000
         PUT   PUNCH,CARD0        WRITE INITIAL IPL RECORD              00230000
**********************************************************************  00240000
*  WRITE SECOND IPL CARD WITH ADDITIONAL READ CCW'S                     00250000
**********************************************************************  00260000
         PUT   PUNCH,CARD1        WRITE SECOND IPL RECORD               00270000
**********************************************************************  00280000
*  WRITE 3 CARDS CONTAINING EXECUTABLE CODE                             00290000
**********************************************************************  00300000
         PUT   PUNCH,CARD2        WRITE DATA                            00310000
         PUT   PUNCH,CARD2+80     WRITE DATA                            00320000
         PUT   PUNCH,CARD2+160    WRITE DATA                            00330000
*                                                                       00510000
         CLOSE (PUNCH)                                                  00520000
*                                                                       00530000
*                                                                       00540000
         L     R13,4(,R13)        PREV SAVE AREA                        00550000
         LM    R14,R12,12(R13)    RESTORE CALLERS REGISTERS             00560000
         SLR   R15,R15            RC=0                                  00570000
         BR    R14                                                      00580000
*                                                                       00590000
         LTORG ,                                                        00600000
*                                                                       00610000
BUF      DS    CL80               CARD BUFFER                           00620000
*                                                                       00630000
SAVEA    DS    18F                SAVEA AREA                            00640000
*                                                                       00650000
*                                                                       00660000
         PRINT NOGEN                                                    00670000
PUNCH    DCB   DSORG=PS,MACRF=PM,BLKSIZE=80,LRECL=80,RECFM=F,          +00680000
               DDNAME=PUNCH                                             00690000
         PRINT GEN                                                      00700000
*                                                                       00710000
*                                                                       00720000
         DROP  R12                                                      00730000
**********************************************************************  00740000
**********************************************************************  00750000
** FIRST CARD OF OUR IPL DECK                                           00760000
**    IT CONTAINS 24 BYTES - PSW AND TWO CCW'S                          00770000
**********************************************************************  00780000
**********************************************************************  00790000
*                                                                       00800000
         DS    0D                                                       00810000
CARD0    DC    80XL1'00'          INITIAL IPL CARD                      00820000
         ORG   CARD0                                                    00830000
*                                                                       00840000
**********************************************************************  00850000
*        PSW                                                            00860000
**********************************************************************  00870000
*                                                                       00880000
IPLPSW   DC    X'00'              I/O & EXT INTERRUPTS DISABLED         00890000
         DC    X'00'              KEY=0; BC; EXT INT DISABLED; SUP      00900000
         DC    X'0000'                                                  00910000
         DC    X'00'              PROG INT DISABLED                     00920000
         DC    AL3(1024)          INITIAL EXECUTION ADDRESS             00930000
*                                                                       00940000
**********************************************************************  00950000
*        CCW                                                            00960000
**********************************************************************  00970000
*                                                                       00980000
CCW1     DC    X'02'              READ                                  00990000
         DC    AL3(512)           ADDRESS FOR DATA                      01000000
         DC    X'60'              CC + SLI                              01010000
         DC    X'00'                                                    01020000
         DC    AL2(80)            LENGTH                                01030000
*                                                                       01040000
**********************************************************************  01050000
*        CCW                                                            01060000
**********************************************************************  01070000
*                                                                       01080000
CCW2     DC    X'08'              TIC                                   01090000
         DC    AL3(512)           NEXT CCW ADDRESS                      01100000
         DC    X'00'              CC + SLI                              01110000
         DC    X'00'                                                    01120000
         DC    AL2(0)             LENGTH                                01130000
*                                                                       01140000
*                                                                       01150000
         ORG   ,                  RESTORE LOC TO HIGHEST                01160000
*                                                                       01170000
**********************************************************************  01180000
**********************************************************************  01190000
** SECOND CARD OF OUR IPL DECK                                          01200000
**    IT CONTAINS THREE CCW'S                                           01210000
**    THESE CCW'S READ THE THREE CARDS CONTAINING EXECUTABLE CODE       01220000
**********************************************************************  01230000
**********************************************************************  01240000
         DS    0D                                                       01250000
CARD1    DC    80XL1'00'          SECOND IPL CARD                       01260000
         ORG   CARD1                                                    01270000
*                                                                       01280000
**********************************************************************  01290000
*        CCW                                                            01300000
**********************************************************************  01310000
*                                                                       01320000
CCW3     DC    X'02'              READ                                  01330000
         DC    AL3(1024)          ADDRESS FOR DATA                      01340000
         DC    X'60'              CC + SLI                              01350000
         DC    X'00'                                                    01360000
         DC    AL2(80)            LENGTH                                01370000
*                                                                       01380000
**********************************************************************  01390000
*        CCW                                                            01400000
**********************************************************************  01410000
*                                                                       01420000
CCW4     DC    X'02'              READ                                  01430000
         DC    AL3(1024+80)       ADDRESS FOR DATA                      01440000
         DC    X'60'              CC + SLI                              01450000
         DC    X'00'                                                    01460000
         DC    AL2(80)            LENGTH                                01470000
*                                                                       01480000
**********************************************************************  01490000
*        CCW                                                            01500000
**********************************************************************  01510000
*                                                                       01520000
CCW5     DC    X'02'              READ                                  01530000
         DC    AL3(1024+160)      ADDRESS FOR DATA                      01540000
         DC    X'20'              SLI                                   01550000
         DC    X'00'                                                    01560000
         DC    AL2(80)            LENGTH                                01570000
*                                                                       01580000
*                                                                       01590000
*                                                                       01600000
*                                                                       01610000
         ORG   ,                  RESTORE LOC TO HIGHEST                01620000
*                                                                       01630000
**********************************************************************  01640000
**********************************************************************  01650000
** THIRD, FOURTH AND FIFTH CARDS OF IPL DECK                            01660000
**    IT CONTAINS THE EXECUTABLE PROGRAM                                01670000
**********************************************************************  01680000
**********************************************************************  01690000
         ORG   PCHHW+1024         MAKE LISTING MATCH MEMORY             01700000
CARD2    DS    0X                 SECOND IPL CARD                       01710000
**********************************************************************  01720000
*        EXECUTABLE PROGRAM BEGINS HERE                                 01730000
**********************************************************************  01740000
BEGIN    DS    0H                                                       01750000
         BALR  R10,0              ESTABLISH BASE REG                    01760000
         USING *,R10                                                    01770000
*                                                                       01780000
**********************************************************************  01790000
*        GET DEVICE PHYSICAL ADDRESSES R3=RDR R4=PRT                    01800000
**********************************************************************  01810000
*                                                                       01820000
         SLR   R3,R3              CLEAR R3                              01830000
         ICM   R3,B'0011',2       GET IPL DEVICE (CARD RDR)             01840000
         LA    R4,X'E'            ASSUME PRINTER AT 00E                 01850000
*                                                                       01860000
**********************************************************************  01870000
*        PUT THE I/O BUFFER ADDRESS INTO THE CCW'S                      01880000
**********************************************************************  01890000
*                                                                       01900000
         LA    R1,HWTXT           HELLO WORLD TEXT                      01910000
         STCM  R1,B'0111',PRCCW+1 ADDRESS TO PRINT CCW                  01930000
*                                                                       01940000
**********************************************************************  01950000
*        PROGRAM MAIN LOOP                                              01960000
**********************************************************************  01970000
*                                                                       01980000
PRT      DS    0H                                                       02250000
*                                                                       02280000
**********************************************************************  02290000
*        SET UP CAW FOR PRINT                                           02300000
**********************************************************************  02310000
*                                                                       02320000
         LA    R1,PRCCW           POINT TO PRINT CCW                    02330000
         ST    R1,72              SAVE ADDRESS IN CAW                   02340000
*                                                                       02350000
         SIO   0(R4)              PRINT LINE                            02360000
         BNZ   ERR3               BRANCH IF ERROR                       02370000
*                                                                       02380000
**********************************************************************  02390000
*        WAIT FOR I/O TO COMPLETE                                       02400000
**********************************************************************  02410000
*                                                                       02420000
PRTTIO   DS    0H                                                       02430000
         TIO   0(R4)              CHECK FOR I/O COMPLETE                02440000
         BZ    OKWAIT               DONE - LOAD ENABLED WAIT PSW        02450000
         BC    1,ERR4             BRANCH IF ERROR                       02460000
*                                                                       02470000
OKWAIT  DS     0H							02499999
	LPSW   PSWNOERR		  LOAD SUCCESS WAIT STATE PSW           02500000
**********************************************************************  02550000
*        CCW'S TO READ AND PRINT                                        02560000
**********************************************************************  02570000
*                                                                       02580000
*                                                                       02590000
         DS    0D                                                       02600000
PRCCW    DC    X'09',AL3(0),X'0000',AL2(80)                             02620000
*                                                                       02630000
*                                                                       02640000
**********************************************************************  02650000
*        ERROR ROUTINES                                                 02660000
*           LOAD PSW WITH WAIT BIT SET TO ONE                           02670000
**********************************************************************  02680000
*                                                                       02690000
*                                                                       02700000
ERR0     MVC   PSWERR0+6(2),68                                          02710000
         LPSW  PSWERR0                                                  02720000
ERR1     LPSW  PSWERR1                                                  02730000
ERR2     LPSW  PSWERR2                                                  02740000
ERR3     LPSW  PSWERR3                                                  02750000
ERR4     LPSW  PSWERR4                                                  02760000
*                                                                       02770000
*                                                                       02780000
**********************************************************************  02790000
*        WAIT PSW'S                                                     02800000
**********************************************************************  02810000
*                                                                       02820000
*                                                                       02830000
         DS    0D                                                       02840000
PSWERR0  DC    X'00',X'02',X'0000',X'00',X'000000'                      02850000
PSWERR1  DC    X'00',X'02',X'0000',X'00',X'EE0001'                      02860000
PSWERR2  DC    X'00',X'02',X'0000',X'00',X'EE0002'                      02870000
PSWERR3  DC    X'00',X'02',X'0000',X'00',X'EE0003'                      02880000
PSWERR4  DC    X'00',X'02',X'0000',X'00',X'EE0004'                      02890000
*                                                                       02900000
PSWNOERR DC    X'00',X'02',X'0000',X'00',X'420042'  DISABLED WAIT       02890000
*                                                                       02910000
**********************************************************************  02920000
*        CHANNEL END + DEVICE END                                       02930000
**********************************************************************  02940000
*                                                                       02950000
*                                                                       02960000
CEDE     DC    X'0C00'            CHANNEL END + DEVICE END              02970000
*                                                                       02980000
*                                                                       02990000
**********************************************************************  03000000
*        HELLO WORLD TEXT                                               03010000
**********************************************************************  03020000
*                                                                       03030000
HWTXT    DC CL80'HELLO WORLD'                                           03040000
*                                                                       03170000
*                                                                       03180000
FILL     DC CL240' '              FILLER SO WE HAVE 3 CARDS WORTH       03185000
**********************************************************************  03190000
*        REGISTER EQUATES                                               03200000
**********************************************************************  03210000
*                                                                       03220000
*                                                                       03230000
R0       EQU   0                                                        03240000
R1       EQU   1                                                        03250000
R2       EQU   2                                                        03260000
R3       EQU   3                                                        03270000
R4       EQU   4                                                        03280000
R5       EQU   5                                                        03290000
R6       EQU   6                                                        03300000
R7       EQU   7                                                        03310000
R8       EQU   8                                                        03320000
R9       EQU   9                                                        03330000
R10      EQU   10                                                       03340000
R11      EQU   11                                                       03350000
R12      EQU   12                                                       03360000
R13      EQU   13                                                       03370000
R14      EQU   14                                                       03380000
R15      EQU   15                                                       03390000
*                                                                       03400000
*                                                                       03410000
         END   ,                                                        03420000
//GO.PUNCH DD UNIT=00D

 

 

Hardcore Hercules Hacking

This is my first small attempt at bare metal programming the emulated 370 CPU. I started the hercules emulator with no operating system then poked in a small program with the console v command which alters storage directly. The program I put in sets R15 to 0 then just loops incrementing it.  The image shows my 12 byte program disassembled by the Hercules “u” command. The status line shows that the system is running 8 emulated mips so it’s doing my two instruction loop 4,000,000 times a second.

I don’t know why the status bar is red.  The hercules documentation seems to say that it means one or more CPU’s is in a wait state.
18-07-28 hardcore

1802 Admitted to IEEE Chip Hall of Fame

18-07-04 IEEEhttps://spectrum.ieee.org/semiconductors/processors/chip-hall-of-fame-rca-cdp-1802

In Which I Am Blown Away By the TK4 MVS Package

I did a little experiment today that impressed the heck out of me. I downloaded the turnkey MVS system zip file from http://wotho.ethz.ch/tk4-/tk4-_v1.00.zip
and unzipped the contents onto a little USB drive as folder TK4. I was able to mount the same drive in my raspberry pi and in windows. In each case the command MVS started the hercules emulator and MVS.


In both cases I could submit work to ip-address:3505 to run it under MVS and i could see the hercules console at ip-address:8038.

The same drive and commands also worked in my macbook. I realize this is just packaging multiple binaries with some scripts but it’s pretty slick.

The Pi Piper – Blinking a LED From an MVS Application Program


I had managed to blink a LED the other day but it involved running in supervisor state to get hercules to issue a shell command and it was just pretty icky. I tried to sanitize it by directing the output of one of MVSs printers to a raspi LED but I kept getting I/O errors – the GPIO server looks like a dumb file at /sys/class/gpio/gpio18/value but while it happily responds to 1’s and 0’s it throws an error for anything else and i seemed always to get a blank or some other garbage at the end of a run.

I got around it by writing a small program to scrub the output and send only valid commands to the LED. I got the GPIO access code from this page and an example of the piping code from this one.

This is still a lot of moving parts, it’s output only, and probably unacceptably slow for any serious GPIO access but it’s a good place to stop. I’m going to see about putting a hook into the hercules emulator source to either do more direct passthrough or direct access to the GPIO’s.

So It Works, But the Software is NOT Happy! – Blinking a LED From MVS


The hercules configuration file connects 370 unit addresses to linux files and the raspberry pi GPIO pins can be controlled with environment variables that can be written to like files. I tried defining one of the gpio pins as a printer to get a connection from MVS to the raspi hardware. It sort of works but hercules is not happy about something and he makes MVS unhappy so the whole thing abends. I still think there’s the germ of an idea here and my LED IS on so…

AS1802 and ASLINK

One of the things that the 1802 historically lacks is a linker to combine and relocate pre-compiled object modules.  LCC1802 combines everything at the source level and compiles/assembles it every time.  This has the advantage of clarity but it does make the output bulkier.

Through an odd happenstance I came across AS1802 and ASLINK which accompanies it.  AS1802 is part of the ASxxxx series of cross assemblers which are also used by SDCC.

I downloaded the assembler and linker and tried them out today. I created assembly modules fblink.asm which calls an external routine _onems, and delay.asm which contains that routine.  I assembled the two generating files fblink.rel and delay.rel with commands like “as1802 fblink.asm”.

	.globl _onems
label1:	seq
	sep call
	.dw _onems
	req
	sep call
	.dw _onems
	br label1
	.BNDRY  8
	.globl	_onems
_onems:		;execute 1ms worth of instructions including call(15)/return(10) sequence. takes about 1 ms
;subroutine overhead soaks up 27 instruction time.
;each loop is 2 instruction times
;so the number of loops needed is 
;CPU speed/16000 less the 27 all divide by two
  .IFNDEF LCC1802CPUSPEED
LCC1802CPUSPEED .EQU 1600	;1.6MHZ default
  .ENDIF
  
  .IFLT LCC1802CPUSPEED-8000
	ldi	((LCC1802CPUSPEED/16)-15-10-2)/2
1$:	smi	1
	bnz	1$
  .ELSE
	ldi	((LCC1802CPUSPEED/16)-15-10-2)/4
2$:	smi	1
	sex	sp
	sex	sp
	bnz	2$
  .ENDIF
	sep	return

I created a library file basic.lib which just contains one line with delay.rel on it.

The link command “aslink -i -u -l basic.lib fblink.rel” loads the fblink program, notices the reference to _onems and goes through the files pointed to by basic.lib finding it in delay.rel.

The result goes into fblink.ihx with fblink at 0000 and _onems at 0010.  This is actually pretty magnificent. It would be an awful lot of work to convert from using my current assembler to AS1802 but if i ever get ambitious i might think about using it as a back end to the ASW macro-processor.

:0A0000007BD400107AD40010300009
:07001000F824FF013A12D5AC
:00000001FF

It occurs to me that this is a fairly dumb example. The onems routine really needs to be compiled each time so that changes in cpu speed can be accommodated. I can see separately building it in a makefile but it wouldn’t be a good library candidate. Better examples would be the 16 bit math routines which are always compiled and included even if they’re not needed.

Odious Comparisons – RCA 1802 vs IBM 370

Now that I have a C compiler on the emulated /370 I of course had to benchmark it. I was faintly worried that even though the Raspberry Pi host is fast that the emulated /370 would be too slow to be fun. That turns out not to be the case at all. I ran the Dhrystone benchmark which I’ve used for the 1802/1806. The emulated 370 ran 100,000 passes in 28 seconds for a score of 3570/Dhrystones per second – nominally about two MIPS. The best I’ve gotten out of an 1802/1806 is a bit over 200 Dhrystones/sec at 12MHz. (A Z80 at 4MHz scores about 300 by the way)

I was curious about the underpinnings so i looked at the generated code for the whole of the Dhrystone suite and a couple of the procedures in it.

    1. For the whole 540 lines of C the 370 compiler generates 1360 lines of assembler vs about 3500 for the 1802. Not all of either of those counts is executed in a benchmark pass – there’s a lot of printing and labels and data definitions.
    2. The first three functions in the C code(PROC_6, PROC_7, and PROC_8) total about 70 lines of C and generate 205 lines of 370 assembly and 920 for the 1802.
    3. Because the 1802’s instruction set is so simple and regular I know it is executing right around 3600 instructions for each pass.  For the 370 I am reduced to saying that if 1757 Dhrystones/sec is one MIP then each pass is about 570 instructions.
    4. A corollary of 3. above is that the 17:1 speed advantage of the emulated 370 comes from about a 7:1 advantage in instruction power and a 2.5:1 advantage in execution rate.
    5. As a parting shot I compiled the Dhrystone benchmark native on the Raspery Pi Zero.  The smallest number of passes that had a detectable pause was 10,000,000 and i had to run 100,000,000 to actually clock it at about 770 THOUSAND Dhrystones/sec or a nominal 215 MIPS. I had seen big numbers for the Pi but i didn’t really believe them until this.
    6. The 370 load module was about 17,000 bytes, the 1802 assembly about 14,000 and the Raspberry Pi just a bit smaller at 13,500 bytes.
    7. On the Pi, because it was easy I re-ran the compile with the optimizer turned on.  This cut the time for 100,000,000 passes down to about 4 seconds(vs 13 seconds unoptimized) but you really cant use that figure for MIPS. The -O3 sped the 370 version up but not nearly as much (100,000 passes in 20 seconds vs 28) and of course the 1802 compiler was already trying as hard as it could.

 

Below is the first procedure in the benchmark(PROC_6) rendered as 31 lines of C, 80 lines of 370 assembly, and 290 lines of 1802 code. In defense of the 1802 and my compiler I’ve also included the actual LCC1802 compiler output which uses a lot of macros to make the code manageable.

Probably the most striking thing about all this(well, beside the speed of the Pi) is that it’s possible at all.  The same C code compiles and runs on wildly different architectures.

 

Proc_6 (Enum_Val_Par, Enum_Ref_Par)
/*********************************/
    /* executed once */
    /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */

Enumeration  Enum_Val_Par;
Enumeration *Enum_Ref_Par;
{
  *Enum_Ref_Par = Enum_Val_Par;
  if (! Func_3 (Enum_Val_Par))
    /* then, not executed */
    *Enum_Ref_Par = Ident_4;
  switch (Enum_Val_Par)
  {
    case Ident_1:
      *Enum_Ref_Par = Ident_1;
      break;
    case Ident_2:
      if (Int_Glob > 100)
        /* then */
      *Enum_Ref_Par = Ident_1;
      else *Enum_Ref_Par = Ident_4;
      break;
    case Ident_3: /* executed */
      *Enum_Ref_Par = Ident_2;
      break;
    case Ident_4: break;
    case Ident_5:
      *Enum_Ref_Par = Ident_3;
      break;
  } /* switch */
} /* Proc_6 */
* X-func Proc_6 prologue
PROC@6   PDPPRLG CINDEX=0,FRAME=96,BASER=12,ENTRY=YES
         B     @@FEN0
         LTORG
@@FEN0   EQU   *
         DROP  12
         BALR  12,0
         USING *,12
@@PG0    EQU   *
         LR    11,1
         L     10,=A(@@PGT0)
* Function Proc_6 code
         L     2,4(11)
         MVC   0(4,2),0(11)
         MVC   88(4,13),0(11)
         LA    1,88(,13)
         L     15,=V(FUNC@3)
         BALR  14,15
         LR    2,15
         LTR   2,2
         BNE   @@L2
         L     2,4(11)
         MVC   0(4,2),=F'3'
@@L2     EQU   *
         L     2,0(11)
         LA    3,4(0,0)
         CLR   2,3
         BH    @@L3
         L     3,=A(@@L11)
         L     2,0(11)
         MH    2,=H'4'
         L     2,0(2,3)
         BR    2
         DS    0F
         DS    0F
         DS    0F
         LTORG
         DS    0F
@@L11    EQU   *
         DC    A(@@L4)
         DC    A(@@L5)
         DC    A(@@L8)
         DC    A(@@L3)
         DC    A(@@L10)
@@L4     EQU   *
         L     2,4(11)
         MVC   0(4,2),=F'0'
         B     @@L3
@@L5     EQU   *
         L     2,=A(INT@GLOB)
         L     2,0(2)
         LA    3,100(0,0)
         CR    2,3
         BNH   @@L6
         L     2,4(11)
         MVC   0(4,2),=F'0'
         B     @@L3
@@L6     EQU   *
         L     2,4(11)
         MVC   0(4,2),=F'3'
         B     @@L3
@@L8     EQU   *
         L     2,4(11)
         MVC   0(4,2),=F'1'
         B     @@L3
@@L10    EQU   *
         L     2,4(11)
         MVC   0(4,2),=F'2'
@@L3     EQU   *
         LR    15,2
* Function Proc_6 epilogue
         PDPEPIL
* Function Proc_6 literal pool
         DS    0F
         LTORG
* Function Proc_6 page table
         DS    0F
@@PGT0   EQU   *
         DC    A(@@PG0)
         DS    0F
;$$function start$$ _Proc_6
_Proc_6:                ;framesize=10
        glo     R6
        stxd
        ghi     R6
        stxd
        glo     R7
        stxd
        ghi     R7
        stxd
        dec sp
        dec sp
        dec sp
        dec sp
        glo     SP
        adi     ((10+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((10+1))>>8; was/256
        phi     MEMADDR
        ghi     R12
        str     memAddr
        inc     memAddr
        glo     R12
        str     memAddr
        inc memaddr                             ;opt16.1
        ghi     R13
        str     MEMADDR
        glo     R13
        inc     MEMADDR
        str     MEMADDR
        dec     MEMADDR
        glo     SP
        adi     ((10+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((10+1))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R7
        ldn     memAddr
        plo     R7
;{
;  *Enum_Ref_Par = Enum_Val_Par;
        glo     SP
        adi     ((12+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((12+1))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        ghi     R7
        str     R11
        glo     R7
        inc     R11
        str     R11
        dec     R11
;  if (! Func_3 (Enum_Val_Par))
        glo     R7
        plo     R12
        ghi     R7
        phi     R12
        sep     RCALL
        dw      _FUNC_3
        glo     R15
        bnz    L8
        ghi     R15
        bnz    L8
;    *Enum_Ref_Par = Ident_4;
        glo     SP
        adi     ((12+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((12+1))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        ldi     (3)>>8; top byte
        str     R11
        inc     R11
        ldi     (3) & 255;low byte
        str     R11
        dec     R11
L8:
;  switch (Enum_Val_Par)
        glo     R7
        plo     R6
        ghi     R7
        phi     R6
        glo     R6
        smi     (0)#256
        ghi     R6
        smbi    (0)>>8; was/256      ;that's a standard signed subtraction
        ghi     R6 ;
        xri     (0)>>8; was/256      ;sets the top bit if the signs are different
        shlc          ;the original df is now in bit 0 and df=1 if signs were different
        lsnf    ;bypass the df flip if signs were the same
        xri     01     ;invert original df if signs were different
        shrc           ;put it back in df
        LBNF    L10  ;execute
        glo     R6
        sdi     (4)#256      ;subtract d FROM immediate value
        ghi     R6
        sdbi    (4)>>8; was/256      ;that's a standard signed subtraction (of register FROM immediate)
        ghi     R6 ;
        xri     (4)>>8; was/256      ;sets the top bit if the signs are different
        shlc          ;the original df is now in bit 0 and df=1 if signs were different
        lsnf    ;bypass the df flip if signs were the same
        xri     01     ;invert original df if signs were different
        shrc           ;put it back in df
        LBNF    L10  ;execute
        glo     R6
        shl
        plo     R11
        ghi     R6
        shlc
        phi     R11
        glo     R11
        adi     ((L20))#256
        plo     MEMADDR
        ghi     R11
        adci    ((L20))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        glo     R6
        stxd
        ghi     R6
        stxd
        glo     R11
        plo     R6
        ghi     R11
        phi     R6
        sep     RRET
L20:
        dw L13
        dw L14
        dw L17
        dw L11
        dw L19
;  {
L13:
;      *Enum_Ref_Par = Ident_1;
        glo     SP
        adi     ((12+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((12+1))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        ldi     (0)>>8; top byte
        str     R11
        inc     R11
        ldi     (0) & 255;low byte
        str     R11
        dec     R11
;      break;
        br L11
L14:
;      if (Int_Glob > 100)
        ldi     ((_INT_GLOB))&255
        plo     MEMADDR
        ldi     ((_INT_GLOB))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        glo     R11
        sdi     (100)#256      ;subtract d FROM immediate value
        ghi     R11
        sdbi    (100)>>8; was/256      ;that's a standard signed subtraction (of register FROM immediate)
        ghi     R11 ;
        xri     (100)>>8; was/256      ;sets the top bit if the signs are different
        shlc          ;the original df is now in bit 0 and df=1 if signs were different
        lsnf    ;bypass the df flip if signs were the same
        xri     01     ;invert original df if signs were different
        shrc           ;put it back in df
        bdf    L15  ;execute
;      *Enum_Ref_Par = Ident_1;
        glo     SP
        adi     ((12+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((12+1))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        ldi     (0)>>8; top byte
        str     R11
        inc     R11
        ldi     (0) & 255;low byte
        str     R11
        dec     R11
        br L11
L15:
;      else *Enum_Ref_Par = Ident_4;
        glo     SP
        adi     ((12+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((12+1))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        ldi     (3)>>8; top byte
        str     R11
        inc     R11
        ldi     (3) & 255;low byte
        str     R11
        dec     R11
;      break;
        br L11
L17:
;      *Enum_Ref_Par = Ident_2;
        glo     SP
        adi     ((12+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((12+1))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        ldi     (1)>>8; top byte
        str     R11
        inc     R11
        ldi     (1) & 255;low byte
        str     R11
        dec     R11
;      break;
        br L11
;    case Ident_4: break;
L19:
;      *Enum_Ref_Par = Ident_3;
        glo     SP
        adi     ((12+1))#256
        plo     MEMADDR
        ghi     SP
        adci    ((12+1))>>8; was/256
        phi     MEMADDR
        lda     memAddr
        phi     R11
        ldn     memAddr
        plo     R11
        ldi     (2)>>8; top byte
        str     R11
        inc     R11
        ldi     (2) & 255;low byte
        str     R11
        dec     R11
;      break;
L10:
L11:
        ldi     0
        plo     R15
        phi     R15
;} /* Proc_6 */
L7:
        inc sp
        inc sp
        inc sp
        inc sp
        inc     sp
        lda     sp
        phi     R7
        lda     sp
        plo     R7
        lda     sp
        phi     R6
        ldn     sp
        plo     R6
        sep     RRET
;$$function end$$ _Proc_6
;$$function start$$ _Proc_6
_Proc_6:		;framesize=10
	pushr R6
	pushr R7
	reserve 4; save room for outgoing arguments
	st2 R12,'O',sp,(10+1); flag1
	st2 R13,'O',sp,(12+1); flag1
	ld2 R7,'O',sp,(10+1) ;reg:INDIRI2(addr)
;{
;  *Enum_Ref_Par = Enum_Val_Par;
	ld2 R11,'O',sp,(12+1) ;reg:INDIRP2(addr)
	st2 R7,'O',R11,0; ASGNI2(addr,reg)
;  if (! Func_3 (Enum_Val_Par))
	cpy2 R12,R7 ;LOADI2(reg)
	Ccall _Func_3; CALLI2(ar)
	jnzU2 R15,L8; NE 0
;    *Enum_Ref_Par = Ident_4;
	ld2 R11,'O',sp,(12+1) ;reg:INDIRP2(addr)
	st2I 3,'O',R11,0; ASGNI2(addr,acon)
L8:
;  switch (Enum_Val_Par)
	cpy2 R6,R7 ;LOADI2(reg)
	jcI2I R6,0,lbnf,L10  ;LT=lbnf i.e. subtract immedB from A and jump if borrow
	jnI2I R6,4,lbnf,L10; GT reverse  the subtraction
	cpy2 R11,R6
	shl2I R11,1
	ld2 R11,'O',R11,(L20) ;reg:INDIRP2(addr)
	jumpv R11; JUMPV(reg)
L20:
	dw L13
	dw L14
	dw L17
	dw L11
	dw L19
;  {
L13:
;      *Enum_Ref_Par = Ident_1;
	ld2 R11,'O',sp,(12+1) ;reg:INDIRP2(addr)
	st2I 0,'O',R11,0; ASGNI2(addr,acon)
;      break;
	lbr L11
L14:
;      if (Int_Glob > 100)
	ld2 R11,'D',(_Int_Glob),0 ;reg:INDIRI2(addr)
	jnI2I R11,100,lbdf,L15 ;LEI2 100 11 L15; LE is flipped test & subtraction
;      *Enum_Ref_Par = Ident_1;
	ld2 R11,'O',sp,(12+1) ;reg:INDIRP2(addr)
	st2I 0,'O',R11,0; ASGNI2(addr,acon)
	lbr L11
L15:
;      else *Enum_Ref_Par = Ident_4;
	ld2 R11,'O',sp,(12+1) ;reg:INDIRP2(addr)
	st2I 3,'O',R11,0; ASGNI2(addr,acon)
;      break;
	lbr L11
L17:
;      *Enum_Ref_Par = Ident_2;
	ld2 R11,'O',sp,(12+1) ;reg:INDIRP2(addr)
	st2I 1,'O',R11,0; ASGNI2(addr,acon)
;      break;
	lbr L11
;    case Ident_4: break;
L19:
;      *Enum_Ref_Par = Ident_3;
	ld2 R11,'O',sp,(12+1) ;reg:INDIRP2(addr)
	st2I 2,'O',R11,0; ASGNI2(addr,acon)
;      break;
L10:
L11:
	ld2z R15
;} /* Proc_6 */
L7:
	release 4; release room for outgoing arguments
	popr R7
	popr R6
	Cretn

;$$function end$$ _Proc_6

And Hello World!

18-04-15 WTO

Another baby step: A C program with inline 370 Assembler. After a fair bit of self-inflicted fumbling around and some help from the Hercules-OS380 mailing list I can run a C program with embedded assembler code.

//GCCMVS2 JOB CLASS=A,MSGCLASS=A,REGION=4096K
//S1 EXEC GCCCLG,COS1='-S',PARM.ASM='DECK,LIST'
//SYSIN DD *
int main(){
	asm(" WTO 'OH HELLO' ");
	return 42;
}

A few notes:

    • The C is in upper and lower case as usual but the assembly part is strictly uppercase
    • The JCL and assembly use single quotes ( ‘ )
    • To get the asm() recognized i needed to override the compiler options in COS1=’-S’ the default is COS1=’-ansi -S -Wpedanticerrors’
    • To see the assembly output and any errors I had to specify PARM.ASM=’LIST,DECK’, the default is ‘DECK,NOLIST’
    • I’m submitting the jobs from windows using netcat which works wonderfully.
    • I’m retrieving the output from the MVS printer using a homebrew awk program that splits the output by job and pipes the last one to more(see below)
    • I’m running hercules/mvs in the background on linux (started with mvs&)

     

     

     

We Have Blinkenlights


This is a desperate travesty of my rusty system programming skills but it works.

I started out wanting to write a C program using GCCMVS and inline assembly language to toggle a LED on the Pi. I can get GCCMVS to run but it doesn’t recognize the asm() constructs. I ended up writing the whole thing in Assembly.

To get the led to blink the easiest approach was to get the hercules emulator to issue a shell command “echo X > /sys/class/gpio/gpio18/value ” where X is 1 to turn it on or 0 to turn it off.

A program under MVS can get the emulator to issue a command by passing it via “DIAG 8”. Hercules wants you to be in supervisor state so i needed to use modeset which wants you to be APF authorized so the program had to go into sys1.linklib.

I stole the bulk of the code from a program called MDDIAG8 by Mark Dickinson.
The shell commands to manipulate a GPIO pin came from here

#   Exports pin to userspace
echo "18" > /sys/class/gpio/export                  

# Sets pin 18 as an output
echo "out" > /sys/class/gpio/gpio18/direction

# Sets pin 18 to high
echo "1" > /sys/class/gpio/gpio18/value

# Sets pin 18 to low
echo "0" > /sys/class/gpio/gpio18/value 

We Have Ignition – GCCMVS Submitted From Windows

18-04-11 RC42

//GCCMVS JOB CLASS=A,MSGCLASS=A,REGION=4096K
//S1 EXEC GCCCLG
//SYSIN DD *
int main(){
	return 42;
}
//STEPLIB DD DSN=SYS2.LINKLIB,DISP=SHR
//

This is not a big deal but it’s a step on the way.  Much easier to edit code on Windows and submit via the socket reader and netcat.

the textpad macro contains

c:appsnetcatnc -w1 192.168.0.104 3505 <$filename

and i'm reading the output on the pi with

 tail -300 prt/prt00e.txt | more

sadly, i forget where i got netcat – google it.

Using an AWS Tape Image

  • enter mvs commands on the hercules console with: / e.g. /d u,dasd
  • put the aws dataset into the mvs/tapes/ directory on the pi e.g. mvs/tapes/herccmd.aws
  • Vary a tape drive online in mvs with: /v 480,online
  • submit your job and wait for the mount request
  • “mount the tape” with: devinit 480 tapes/herccmd.aws

 

Olduino/370


I love the 1802 but my native instructon set was the 360/370 and I worked as a system programmer for years so I’d love to do an Olduino/370. I played with the MVS Tur(n)key system a long time ago but when it got to wanting JCL I shut it down. Now I realize the real fun is in blinking LEDS. I figure the credit-card size Raspberry Pi W might be the starting point. I’m sure the pi-arduino shield space is well covered so i just need a 370 emulator with a boot-loader and a PC based C compiler for it.

I came across the Mainframe Pi group on facebook where someone mentioned the Hercules Emulator running MVS on a Pi and I’m in!