Skip to content

This Little Pi-guy Went To Florida But Its IP Connection Stayed Home


I brought a couple of Pi’s with me to play with over the winter months including the Olduino/370 dressed in its mini-370 case. Both were used regularly on my home wifi. I updated the wpa_supplicant.conf to reflect the apartment’s wifi but then got stuck. I’m used to having to fumble around to find the IP address on new networks but this setup seems resistant to my fumbling. I don’t have a password for the router so i can’t look at its tables and all of the scanners i tried come up dry showing only my own PC’s address. I finally resorted to lighting up a hotspot access point on my windows box using the same ssid and password as my home router(yes, clever, i know) and the Pi which normally uses a static IP at home popped up although with a dhcp-assigned address.

So now i have one Pi up on my faux-home win10 hosted network and another one that won’t connect to either my faux-home or the apartment network. Possibly:
-finger problems overall
-the apartment router won’t serve the pi an ip address but windows will
-something stops the PI’s from using the wpa_supplicant.conf that i put in the boot directory of the SD card. **Seems very likely – see below**

As an extra bit of fun i don’t find ping works on the apartment network. I can’t ping one windows laptop from another, ping my phone etc.

Reference:
here‘s the site i got the static ip info from.

interface wlan0

static ip_address=192.168.0.203/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1 8.8.8.8
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="therowes24"
    psk="********"
    scan_ssid=1
}
network={
    ssid="doodle"
    psk="*********"
    scan_ssid=1
}
Advertisements

Yippee – In Which I Improve My Workflow With “cat”

yikes

I’ve been doing a lot of compile/link/test sequences with wiringMVS.  The workflow consists of:

  • editing the C program along with its JCL and submitting it to MVS from textpad
  • switching over to putty and watching the MVS console to guess whether the compile worked based on: how long it runs, number of lines produced etc.
  • if i think it failed switching to winscp and reloading the printer output screen
  • switching to textpad again to bumble through multiple jobs output looking for error messages
  • rinse and repeat

I had the idea that if i could compile/assemble/link on windows it would be more interactive.  GCCMVS runs well enough and i can get the C errors out of the way but copying the assembler output into a job stream and submitting that is a bit painful and then i’m guessing again because sometimes i’ll get assembler errors and missing functions can show up in the link step.  I’ve been pursuing the Z390 assembler as an alternative but i’m not there yet.

In the meantime i had a bit of a brainstorm.  I set up a Hercules printer as a pipe to “cat”.  An MVS job sends output to the printer, hercules pipes it to “cat”, and cat sends it back to its stdout which Hercules displays on the console.  Bingo – instant interactive output!

I haven’t done it yet but it should be easy to direct the assembler and lked diagnostic steps to the same “printer”. I could even allocate it to JES2 and establish a “print to console” class!

I also added a couple of crude notification job steps at the end: YIKESC runs only if the compiler step fails and sends a message to the console, and YIPPEE runs only if all steps succeed and again sends a message. I sould clean them up with a stored PROC but the overall result is pretty gratifying.

//GPIOMULE JOB CLASS=A,MSGCLASS=A,REGION=4096K,
// MSGLEVEL=(1,1),
// USER=HERC01,PASSWORD=CUL8TR
//S1 EXEC GCCCLF,COS1='-S',
// PARM.ASM='DECK,NOLIST,TEST,TERM,NOXREF,NOMLOGIC,NORLD',
// PARM.LKED='TERM,TEST'
//COMP.INCLUDE DD DSN=HERC01.WIRINGMV.INCLUDE,DISP=SHR
//SYSIN DD *
pigs=undef(); //deliberate error
  ...
  ...
  rest of program
*/
//COMP.SYSPRINT DD DUMMY
//COMP.SYSTERM DD UNIT=30F
//LKED.SYSLMOD DD DSN=HERC01.LOAD(GPIO3),DISP=SHR
//YIPPEE EXEC PGM=IKJEFT01,PARM='SEND ''YIPPEE''',
// COND=((0,NE,S1.COMP),(0,NE,S1.ASM),(0,NE,S1.LKED))
//SYSPRINT DD DUMMY
//SYSOUT   DD DUMMY
//SYSTSPRT DD DUMMY
//SYSIN    DD DUMMY
//SYSTSIN  DD DUMMY
//YIKESC EXEC PGM=IKJEFT01,PARM='SEND ''YIKES THE COMPILER''',
// COND=((0,EQ,S1.COMP))
//SYSPRINT DD DUMMY
//SYSOUT   DD DUMMY
//SYSTSPRT DD DUMMY
//SYSIN    DD DUMMY
//SYSTSIN  DD DUMMY

MK48Z02 Non-Volatile RAM for the Boyd Calculator

My last effort with the Boyd used the onboard 64 byte ram memory with a 2732 eprom in an adapter.  I wasn’t hitting the ram limit but i thought using a non-volatile ram chip as primary memory would give me more flexibility.  I got an old signetics part from eBay to try out and today i got around to comparing the pinouts to the 2532 that’s original to the Boyd.

As usual the data and address lines are more-or-less ok.  The 4K 2532 has one extra address line A11 which would hit /CE on the nvram but that’s ok because it would just deselect the nvram for addresses above 2K.  The PD/PGM on the 2532 seems ominous but it really just acts as a low-going chip enable and connects to /G which is /output enable on the nvram.  again VPP sounds ominous but i bet it’s tied to +V in the Boyd – it connects to /write on the nvram.

So to use the nvram fully, I would need to connect /mwrite to pin 21 and /mread to pin 20.  I don’t think either of those would interfere with the normal 2532 chip.

I currently have a 2732 adapter in the boyd.  I should look hard at the 2732 pinout but it looks like i would have to remove A11 from pin 21 and supply /mwrite instead.  this is a bit simpler but the adapter is already high and putting the tall nvram on top of it would probably break the camel’s back.

18-12-11 TMS2732

Carbot/370 State of Play

As of today the Carbot hardware and software are basically functional, if rough.  The control program written in C runs on the MVS operating system on a simulated IBM 370 computer under the Hercules emulator running on a raspberry Pi Zero W.  The Pi is housed in a miniature mainframe case with an infrared rangefinder mounted on it and rides on a converted radio control car chassis.  The car’s motors are controlled by a pimoroni explorer pHAT mounted on the Pi.

I’m missing the side facing sensor needed for wall following and I’m using direct drive for the motors rather than using PWM to modulate them.  I do think it’s funny to see the mini-mainframe darting around getting stuck under the furniture.

I had been worried that running the motors from the same 5V supply as the Pi would be a problem but it seems not to be an issue so far.

 The Carbot software is pretty simple at the moment it’s meant to be run as a TSO command or a batch job and it does one action per run as controlled by parameters on the command line for example “carbot f” as a TSO command or // EXEC PGM=CARBOT,PARM=’F’ will each start the motors going forward. In the demo video “carbot g” starts a “Go” routine that runs forward and turns left when it sees an obstacle.

void go(int ttl){
    int maxprox=7500,tprox=7000;
    int fprox,now,start=millis();
    fprox=analogRead(0); //read front sensor
    printf("Go starts at %d\n",start);
    while (now-start< ttl){
    	if (fproxtprox) &&(now-start<ttl)){
    	    	drive(1,0,0,1); //hardleft
	    	now=millis();
	    	fprox=analogRead(0);
    	    }
    	    drive(0,0,0,0);
    	}
    	now=millis();
    	fprox=analogRead(0);
    }
    drive(0,0,0,0);
}

The "drive(r1,r2,l1,l2)" routine used above controls the right and left motors such that drive(1,0,1,0) starts both motors going forward while drive(1,0,0,1) runs lthe right motor full forward and the left motor full reverse so we get a hard left turn.

//CARBOT01 JOB CLASS=A,MSGCLASS=A,REGION=4096K,MSGLEVEL=(0,0),
// USER=HERC01,PASSWORD=CUL8TR
//S1 EXEC GCCCL,COS1='-S',
// PARM.ASM='DECK,NOLIST,TEST,NOXREF,NOMLOGIC,NORLD',
// PARM.LKED='TEST'
//COMP.INCLUDE DD DSN=HERC01.WIRINGMV.INCLUDE,DISP=SHR
//SYSIN DD *
#include 
#include 
#include "wiring.h"
int rfw=24,lfw=25; // forward right and left wheels
int rrv=28,lrv=29; // reverse right and left wheels
void init(){
  printf("init\n");
  pinMode(rfw,OUTPUT);pinMode(lfw,OUTPUT);
  pinMode(rrv,OUTPUT);pinMode(lrv,OUTPUT);
}
void drive(int rf,int rr,int lf,int lr){
    digitalWrite(rfw,rf);digitalWrite(rrv,rr);
    digitalWrite(lfw,lf);digitalWrite(lrv,lr);
}
void keepaway(int ttl){
    int minprox=5000, maxprox=8000;
    int fprox,now,start=millis();
    fprox=analogRead(0); //read front sensor
    printf("keepaway starts at %d\n",start);
    while (now-start< ttl){
    	//printf("keepaway at t=%d, prox is %d\n",now,fprox);
    	if (fproxmaxprox){
    	    drive(0,1,0,1);
    	} else {
    	    drive(0,0,0,0);
    	}
    	delay(100);
    	now=millis();
    	fprox=analogRead(0);
    }
    drive(0,0,0,0);
}
void go(int ttl){
    int maxprox=7500,tprox=7000;
    int fprox,now,start=millis();
    fprox=analogRead(0); //read front sensor
    printf("Go starts at %d\n",start);
    while (now-start< ttl){
    	if (fproxtprox) &&(now-start<ttl)){
    	    	drive(1,0,0,1); //hardleft
	    	now=millis();
	    	fprox=analogRead(0);
    	    }
    	    drive(0,0,0,0);
    	}
    	now=millis();
    	fprox=analogRead(0);
    }
    drive(0,0,0,0);
}

int main(int argc, char *argv[]){   
    int retval=42;
    int fprox=43;
    printf("Oh Hello - Carbot Here\n");
    init();
    switch(argv[1][0]){
    case 'G': case 'g': //"Go" for 3 seconds
        go(3000);    
        break;
    case 'K': case 'k': //play keepaway for 10 seconds
        keepaway(10000);    
        break;
    case '?': //read the front sensor
        fprox=analogRead(0);    
        printf("front sensor says %d\n",fprox);
        break;
    case 'T': case 't':
        drive(1,0,0,1);    
        break;
    case 'F': case 'f':
        drive(1,0,1,0);    
        break;
    case 'R': case 'r':
        drive(0,1,0,1);    
        break;
    case 'X': case 'x': //stop
        drive(0,0,0,0);
        break;
    default:
        printf("not doing %s(%x %x) \n",argv[1],argv[1][0],argv[1][1]);
    }
    //asm(" WTO 'OK Bye' ");
    return retval;
}
//LKED.SYSLMOD DD DSN=HERC01.LOAD(CARBOT),DISP=SHR
//* DISP=(,CATLG),
//* UNIT=SYSDA,SPACE=(TRK,(10,5,5)),
//* DCB=(RECFM=U,BLKSIZE=19069)
//*     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

I had to update the SVC intercept hook code in Hercules and the wiring.h GCCMVS macros to support the millis() call.

//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 *
  //18-12-06 including millis() code 9
#define INPUT 0
#define OUTPUT 1
#define LOW 0
#define HIGH 1
int adcSetup(){
    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 millis(){
    int retval='R';
    asm(" LA 2,0 \n"
        " LA 1,9\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
        :); //no inputs to asm()
    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));
}
//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 *
  //18-12-06 including millis() code 9
#define INPUT 0
#define OUTPUT 1
#define LOW 0
#define HIGH 1
int adcSetup(){
    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 millis(){
    int retval='R';
    asm(" LA 2,0 \n"
        " LA 1,9\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
        :); //no inputs to asm()
    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));
}

It Phits! (In which I Cram Everything In)

img_3008
Here’s Carbot/370 more or less slung together. All the wiring is there except the power and the only component missing is the sideways looking sensor. When complete the Carbot will be able navigate a simple arena like a wall-following racer. This is the same as previous incarnations of the Carbot except that the navigation and motor control will be done by MVS batch jobs.

Conceptually this is a variant of the IBM 370/158M (mobile edition). The self driving capability might have been used within a city but for longer moves I’m sure FEMA would have used trucks.

From the rear you can see the Pimoroni Explorer phat with the Raspberry Pi Zero W underneath it. The IR distance sensor on top is jumper wired to the phat analog inputs and the motor wires go to the phat’s motor control outputs. The OLED screen is connected to the I2C pins of the Pi although I had to solder to the stubs left exposed of the phat’s header which otherwise hides those pins.

Phinally! (In Which I Get the Pimoroni Explorer PHAT working)

3018-03
A while ago I bought a little circuit board that seemed perfect for the Olduino/370 Carbot.  It fits onto the Raspberry Pi Zero and provides motor drivers, analog-digital conversion, and buffered 5v i/o.  I put it aside because it started to seem like too much trouble to work with: it uses chips i’m not familiar with, all the examples and libraries are in python rather than C, and it sits over all the GPIO pins making it hard to connect other peripherals. (I’m a fan of python but i’m integrating with the C code base of Hercules and wiringPi so its’ just an added headache to convert).

Today, though, everything clicked into place.  The interfaces I need are:

  • The motor driver pins
  • The ADC converter

I got the motor driver pins figured out finally by running a python example and checking the state of the likely seeming pins.  I was quickly(well, not quickly) able to identify the left hand motor pins as 24&28, and the right hand pins as 25&29. i.e. if 24 is high and 28 low, the left motor runs forward full speed; reversing those causes the motor to run backwards; and pwm-cycling the high pin can modulate the speed.  These results are solid but they’ll have to be adjusted for final wiring.

#!/usr/bin/env python
import sys
import explorerhat as eh
eh.motor.one.invert()
def setmotor(m2,m1):
  if (m1>=0):
    eh.motor.one.forward(m1)
  else:
    eh.motor.one.backward(-1*m1)
  if (m2>=0):
    eh.motor.two.forward(m2)
  else:
    eh.motor.two.backward(-1*m2)
line=sys.stdin.readline()
while(line != ''):
  if line.startswith('0'):
    setmotor(0,0)
  elif line.startswith('1'):
    setmotor(0,100)
  elif line.startswith('2'):
    setmotor(100,0)
  elif line.startswith('3'):
    setmotor(100,100)
  elif line.startswith('-'):
    setmotor(0,-100)
  elif line.startswith('!'):
    setmotor(-100,0)
  line=sys.stdin.readline()
 #print("bye")

I’m reading the ADS1015 analog-digital-converter through an extension of wiringPi meant for the very similar ADS1115. The trickiest bit is that the 12 bits returned by the ADC get munged by the wiringPi code which expects 16 bits. I forget how i came to this but the answer was to readjust the result provided by wiringPi after the fact. Also, the ADS1015 is 4 channels but I’ve only found the channels labelled “1” and “4” available as analogRead(3) and (0) respectively.

//ads1015 test raspi adc from explorer phat
#include 
#include 
#include 
#define MY_BASE 2222
void main(){
  float v;
  ads1115Setup (MY_BASE, 0x48) ;
  int ch0 = analogRead (MY_BASE + 0) ;
  int ch3 = analogRead (MY_BASE + 3) ;
  printf("ch0 sez %d\n",ch0);
  printf("ch3 sez %d\n",ch3);
  if (ch3>0x7ff0) ch3-=0x10000;
  v=((float)(ch3>>4)/0x7ff)*5.0;
  if (ch0>0x7ff0) ch0-=0x10000;
  printf("channel 0 voltage is %f\n",((float)(ch0>>4)/0x7ff)*5.0);
  printf("channel 3 voltage is %f\n",((float)(ch3>>4)/0x7ff)*5.0);
}

Bundling this for execution meant simple changes to the wiringMVS.c code that gets copied into general2.c of the Hercules emulator.

//18-11-23 remove automatic inline setup calls
//         comment out most verbose msgs
//18-11-30 changed analogread setup and code to use the ads1115 extension rather than MCP3002
#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;
	//printf("wiringMVS sez: function=%x,parameter=%x, setup@%X=%d\n",function,parameter,&wiringPiSetuped,wiringPiSetuped);
	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()
			result=wiringPiSetup ();
			if (result!=0)
 				printf("wiringMVS Setup() sez %d\n",result);
			break;
		case 7: // mcp3002Setup()
			result=ads1115Setup (MY_PIN_BASE,0x48);
			if (result0x7ff0) result-=0x10000;
			break;
	}
	//printf("wiringMVS sez %d\n",result);
	return result;
}

Oh, also, I’m normally an SVN user on windows but i decided to try git for tracking changes to the olduino/370 components. For the ads1015c test module it was as simple as
git init
git add ads1015.c
git commit ads1015.c
This is not very sophisticated source code management but it saves me keeping multiple copies of my work for backing off.
 

In which Big Brother Gets His Eyes On

Here I’ve got the forward distance sensor mounted on top of the Rogue 370.

img_2982

When running the Carbot I will need a second sensor mounted on the car body.

img_2981

img_2980

The pi is actually inside there along with the mcp3002 adc chip and the motor driver although none of the motor wiring is in place.

img_2984img_2988

wiringMvs State of Play

“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

Initializing wiringMvs/wiringPi

Right now my code has a couple of explicit initialization paths in it (cases 6 and 7 below)

int wiringMVS(int function, int parameter){//implements wiringPi functions for MVS
	int result=0;

	switch (function){
		case 0:	//pinmode INPUT
			pinMode(parameter,INPUT);
			break;
		.
		.
		.
		case 6: // setup()
			result=wiringPiSetup ();
			if (result!=0)
 				printf("wiringMVS Setup() sez %d\n",result);
			break;
		case 7: // mcp3002Setup()
			result=mcp3002Setup (MY_PIN_BASE,SPI_CHAN);
			if (result<0)
 				printf("wiringMVS mcp3002Setup() sez %d\n",result);
			break;
		.
		.
		.
	}
	return result;
}

I would like to replace them with automatic initialization using static variables as below:

int wiringMVS(int function, int parameter){//implements wiringPi functions for MVS
	static int init=0;
	int result=0;
	if (!init){
		init=1;
		result=wiringPiSetup ();
		if (result!=0) printf("wiringMVS Setup() sez %d\n",result);
	}
	switch (function){
		case 0:	//pinmode INPUT
			pinMode(parameter,INPUT);
			break;
		.
		.
		.
		case 7: // mcp3002Setup()
			result=mcp3002Setup (MY_PIN_BASE,SPI_CHAN);
			if (result<0)
 				printf("wiringMVS mcp3002Setup() sez %d\n",result);
			break;
		.
		.
		.
	}
	return result;
}

UPDATE: I decided this wasn't a good idea and I kept the explicit initialization. I need to arrange for something to run when MVS starts to make the init cals.

It’s Alive! Olduino/370 Carbot Spins its Wheels!


I was amazed that the MVS part of this worked so easily. I had made some simple C wrappers for the wiringMVS pinMode, digitalWrite, and delay functions. Once I got the Pi hooked correctly to the motor driver board I was easily able to run a batch job to access the robot car wheel motors.

I need now a good solid mount for the Pi as well as getting the input functions working. I’m using the adapter board from the 1802 carbot because it’s handy but it’s striking how the Pi needs many of the same crutches as the 1802 did including software PWM, an outboard analog-digital conversion, and extra resistors to access the ultrasonic range finder.
img_2783
In the still image, the pi is in the lower left with eight leads going up to the adapter board. The motor power pack is below and behind it. The car body on the right came from an RC car with two independent rear motors, the four leads going left to the motor driver board are motor power, the two on the right are connected to the logic power pack which isn’t hooked to anything.

For each motor, the driver board takes three inputs, for the right side it’s PWMA, AIN1, and AIN2. AIN1 and AIN2 determine the direction the motor rotates and PWMA determines how hard it spins. In this case I’m just setting the PWM to full on but I can cycle it off and on to control speed.

The adapter board also has spots to attach an ultrasonic sideways sensor and an IR forward distance sensor with an ADC converter. It has a spot for a boost converter to generate 5V for the logic from two AA batteries. Probably the simplest approach is to make something similar but smaller and more suited to the Pi’s form factor. If it can fit into the 370 case, great.

//MOTOMULE JOB CLASS=A,MSGCLASS=A,REGION=4096K
//S1 EXEC GCCCLG,COS1='-S',PARM.ASM='DECK,LIST'
//SYSIN DD *
#include 
#define INPUT 0
#define OUTPUT 1
#define LOW 0
#define HIGH 1
int setup(){
	int retval='s';
	asm(" LA 0,X'42' FLAG FOR SVC 255 ");
	asm(" LA 1,6 SETUP ");
	asm(" SVC 255 ISSUE SVC\n" 
	    " LR %0,15"
	    : "=r" (retval));
	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!=0)+2));
}
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));
}
int main(int argc, char *argv[])
{	
	int retval=43;
	//int pwmb=0,bin1=2,bin2=3; //speed and direction control for left side motor
	//int pwma=1,ain1=4,ain2=3; //speed and direction control for right side motor
	asm(" WTO 'Hello Moto!' ");
	retval=setup();
	pinMode(0,OUTPUT);pinMode(2,OUTPUT);pinMode(3,OUTPUT); //Left side motor
	digitalWrite(0,LOW);
	pinMode(1,OUTPUT);pinMode(4,OUTPUT);pinMode(5,OUTPUT); //Right side motor
	digitalWrite(1,LOW);

	//drive left side forward for 1.5 sec
	digitalWrite(2,LOW);digitalWrite(3,HIGH);
	digitalWrite(1,HIGH);
	delay(1500);
	digitalWrite(1,LOW);

	asm(" WTO 'OK Bye' ");
   	return retval;
}

3D Printed Case For the Olduino/370

Like everything else in the world, 3D printing is a lot more trouble than you’d think. Anyway, here’s the rogue /158 complete with bogus IPL messages. The Pi is actually hidden behind the chassis although there’s certainly room inside it.

Just For the Record – the OLED

18-10-12 oled
This is based on code from: https://github.com/iliapenev/ssd1306_i2c compied with
gcc pipetext.c ssd1306_i2c.c -lwiringPi -o pipetext
and tested with
echo “Hello World!” | ./pipetext

to use it with Hercules I’ll attach it to a printer as I did with the led pipe.

I’ll use it to pipe output from a hercules printer to the display – i’m imagining something that will echo the stepname and completion code for the last job run.

/******
Pipe text to the ssd1306 i2c driver for  Raspberry Pi
******/
#include 
#include 

#include "ssd1306_i2c.h"

void main() {
        printf("printer pipe to ssd1306\n");

        ssd1306_begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);

        ssd1306_display(); //Adafruit logo is visible

  while(!feof(stdin))
  {
        char line[200];
        char ss[200];
        fgets(line, 200, stdin);
        printf("%d: %2x %2x %2x\n",strlen(line),line[0],line[1],line[2]);
        ssd1306_clearDisplay();
        //char* text = "Hello World!";
        ssd1306_drawString(line);
        ssd1306_display();
  }
}

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.

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&#8221;
  • 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