Skip to content

wiringMvs State of Play

November 26, 2018

“wiring” is the project that spawned the Arduino.  It is where constructions like digitalWrite(), digitalRead(), delay(), etc. came from.  wiringMVS is my attempt to port those sorts of functions to programs running under the MVS operating system from the 1970’s.  My instance of MVS is running on the Hercules emulator using the Tk4- Tur(n)key setup which i heartily recommend.  Because my emulator is running on a Raspberry Pi I am using the excellent wiringPi as the basis for my work.

So far I have implemented digitalRead, AnalogRead, digitalWrite, and delay functions.  I have not tried it yet but I believe analog(pwm)Write should be fairly easy.  These combined should be enough to let me program a car type robot driven by a MVS batch job. It will monitor it’s environment with a sharp infrared distance sensor. 

There are a number of parts to the work

  1. The “hook” in Hercules that invokes wiringPi functions
  2. A set of C functions that implement digitalRead() etc
  3. An MVS program called “gpio” that can exercise and test the functions.

---Near the top of the file
#include
#if !defined(_GENERAL2_C_)
#define _GENERAL2_C_
#include  //WJR
#include  //WJR
#include  //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);
//BEGINNING OF WIRINGPI CODE BY WJR 18-09-21
#if 1 
/* if we have an SVC 255 and R0 is set to a magic number(0x42), 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
//END OF WIRINGPI CODE BY WJR 18-09-21

//18-11-23 remove automatic inline setup calls
//         comment out most verbose msgs
#define SPI_CHAN        0
#define MY_PIN_BASE     5555    // Anything >= 64
int wiringMVS(int function, int parameter){//implements wiringPi functions for MVS
	static int mcp3002_pinbase=0,wiringPiSetuped=0;
	int result=0;
	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);
			//printf("digitalRead(%d) sez %d\n",parameter,result);
			break;
		case 5: //
			delay(parameter);
			break;
		case 6: // setup()
			wiringPiSetuped=1;
			result=wiringPiSetup ();
			if (result!=0)
 				printf("wiringMVS Setup() sez %d\n",result);
			break;
		case 7: // mcp3002Setup()
			mcp3002_pinbase=MY_PIN_BASE;
			result=mcp3002Setup (MY_PIN_BASE,SPI_CHAN);
			if (result<0)
 				printf("wiringMVS mcp3002Setup() sez %d\n",result);
			break;
		case 8: //analogRead
			result=analogRead(MY_PIN_BASE+parameter);
			//printf("analogRead sez %d\n",result);
			break;
	}
	//printf("wiringMVS sez %d\n",result);
	return result;
}

The C functions get placed in an MVS dataset: herc01.include(wiringMVS) and are copied into a program compiled with GCCMVS by #include “wiringmvs.h”.

//INCLUDE JOB CLASS=A,MSGCLASS=A,REGION=4096K,
// USER=HERC01,PASSWORD=CUL8TR
//*ALLOC EXEC PGM=IEFBR14
//*SYSUT2   DD  DSNAME=HERC01.WIRINGMV.INCLUDE,DISP=(,CATLG),
//*             UNIT=SYSDA,SPACE=(TRK,(10,5,5)),
//*             DCB=(RECFM=VB,LRECL=255,BLKSIZE=6233)
//LOAD EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=A
//SYSIN DD DUMMY
//SYSUT2 DD DSNAME=HERC01.WIRINGMV.INCLUDE(WIRING),DISP=SHR
//SYSUT1 DD *
#define INPUT 0
#define OUTPUT 1
#define LOW 0
#define HIGH 1
int mcpSetup(){
    int retval='s';
    asm(" LA 0,X'42' FLAG FOR SVC 255 ");
    asm(" LA 1,7 MCP3003 ADC SETUP ");
    asm(" LA 2,0 ");
    asm(" SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval));
    if((retval<0)){
        printf("mcp3002Setup return value is %d\n",retval);
    }
    return retval;
}
int analogRead(int pin){
    int retval='R';
    asm(" LR 2,%1 \n"
        " LA 1,8\n" //code for analog read
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval) //returned value
        : "r" (pin));
    return retval;
}
int setup(){
    int retval='s';
    asm(" LA 0,X'42' FLAG FOR SVC 255 ");
    asm(" LA 1,6 SETUP ");
    asm(" LA 2,0 ");
    asm(" SVC 255 ISSUE SVC\n"
        " LR %0,15"
        : "=r" (retval));
    if((retval!=0) && (retval!=180923)){
        printf("setup return value is %d\n",retval);
    }
    return retval;
}
int digitalWrite(int pin, int value){
    asm(" LR 2,%0 \n"
        " LR 1,%1\n"
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (pin), "r" (value+2));//((value!=0)+2));
}
int digitalRead(int pin){
    int retval='R';
    asm(" LR 2,%0 \n"
        " LA 1,4\n" //code for read
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval) //returned value
        : "r" (pin));
    return retval;
}
int pinMode(int pin, int value){
    asm(" LR 2,%0 \n" //pin
        " LR 1,%1\n"  //value
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (pin), "r" ((value!=0)));
}
void delay(int value){
    asm(" LR 2,%0 \n" //ddelay time in MS
        " LA 1,5\n"   //code for delay
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (value));
}

The demo program GPIO is compiled into sys1.linklib to make it easily accessible. It can run as a batch job or TSO command. It responds to a set of commands to exercise wiringMVS

  • gpio read
  • gpio write high/low/0/1
  • gpio analogread
  • gpio delay

It is really only checking the first letter of the command so “m” will do instead of mcp3002setup.  The two setup calls have to be made before anything else will work. If nothing else, this is a good illustration of how to compile and run GCCMVScode.

//GPIOMULE JOB CLASS=A,MSGCLASS=A,REGION=4096K,
// USER=HERC01,PASSWORD=CUL8TR
//S1 EXEC GCCCL,COS1='-S',
// PARM.ASM='DECK,LIST,TEST,NOXREF,NOMLOGIC,NORLD',
// PARM.LKED='TEST'
//COMP.INCLUDE DD DSN=HERC01.WIRINGMV.INCLUDE,DISP=SHR
//SYSIN DD *
#include 
#include 
#include "wiring.h"

int main(int argc, char *argv[]){   
    int retval=42;
    int pin,hilo, delaytime;
    switch(argv[1][0]){
    case 'D': case 'd':
        delaytime=atoi(argv[2]);
        delay(delaytime);    
        break;
    case 'w': case 'W': //write
        pin=atoi(argv[2]);
        pinMode(pin,OUTPUT);
        switch(argv[3][0]){
        case 'h': case 'H': case '1':
            hilo=HIGH;
            break;
        case 'l': case 'L': case '0':
            hilo=LOW;
            break;
        default:
            return 12;
        }
        printf("setting %d to %d\n",pin,hilo);
        digitalWrite(pin,hilo);
        break;
    case 'R': case 'r':
        pin=atoi(argv[2]);
        retval=digitalRead(pin);    
        printf("pin %d reads %d\n",pin,retval);
        break;
    case 'A': case 'a':
        pin=atoi(argv[2]);
        retval=analogRead(pin);    
        printf("pin %d analogReads %d\n",pin,retval);
        break;
    case 'S': case 's':
        retval=setup();
        break;
    case 'M': case 'm':
        retval=mcpSetup();
        break;
    default:
        printf("not doing %s\n",argv[1]);
    }
    return retval;
}
//LKED.SYSLMOD DD DSN=SYS1.LINKLIB(GPIO),DISP=SHR
//*     EXEC PGM=*.S1.LKED.SYSLMOD,
//*     PARM='write 0 low'
//*SYSPRINT DD SYSOUT=*
//*SYSTERM DD SYSOUT=*
//*SYSIN DD DUMMY
//*     EXEC PGM=*.S1.LKED.SYSLMOD,
//*     PARM='read 0'
//*SYSPRINT DD SYSOUT=*
//*SYSTERM DD SYSOUT=*
//*SYSIN DD DUMMY
Advertisements

From → Olduino/370

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: