JavaによるVMEアクセス


はじめに

Java言語を使ってVMEへアクセスする方法を提供します。そのためには まずJavaの開発環境を整える必要があります。 Java2 Platform, standard editonを SunのJavaサイトからダウンロードし、整備します。
それが済んだら、C言語で書かれたVMEライブラリをダウンロードし、整備します。 ここでは KEK標準VMEライブラリを用います。
それが済めばいよいよJava Native Interface(JNI)プログラムの書き方に入ります。

VMEアクセスに必要なJava Native Interface関連ソフトウエア

KEK標準VMEライブラリは下記のJavaメソッドによりアクセスされます。 この中で、mapOpenとmapCloseメソッドはVMEライブラリの下記の関数を 直接呼んでいます。 通常C言語では関数を使わずポインタを利用してVMEへアクセスするので 特に関数は用意されていませんが、Javaの場合はポインタを利用した VMEへのアクセス法は許していませんので、Javaのためにメソッドが 必要になります。上記のその他のJavaメソッドはそのような理由で 作られました。

VMEクラスを定義するJavaプログラム

VME.java:

public class VME {

    public synchronized native int mapOpen(int mode, int vmeaddr, int size);
    public synchronized native int mapClose(int viraddr, int mode);
    public synchronized native void writeByte(int viraddr, byte data);
    public synchronized native void writeShort(int viraddr, short data);
    public synchronized native void writeInt(int viraddr, int data);
    public synchronized native byte readByte(int viraddr);
    public synchronized native short readShort(int viraddr);
    public synchronized native int readInt(int viraddr);

    static {
        System.loadLibrary("JavaVME");
    }
}

CとJavaを結びつけるJNI


#include 
#include "VME.h"
#include "vmelib.h"

int vme_mapopen( jint mode, jint vmeaddr, jint size);
int vme_mapclose( jint viraddr, jint mode);
void writeByte( jint viraddr, jbyte data);
void writeShort( jint viraddr, jshort data);
void writeInt( jint viraddr, jint data);
jbyte readByte( jint viraddr );
jshort readShort( jint viraddr );
jint readInt( jint viraddr );

JNIEXPORT jint JNICALL
Java_VME_mapOpen(JNIEnv *env, jobject obj, jint mode, jint vmeaddr, jint size) {
    return vme_mapopen( mode, vmeaddr, size);
}
JNIEXPORT jint JNICALL
Java_VME_mapClose(JNIEnv *env, jobject obj, jint viraddr, jint mode) {
    return vme_mapclose(viraddr, mode);
}

JNIEXPORT void JNICALL
Java_VME_writeByte(JNIEnv *env, jobject obj, jint viraddr,
                 jbyte data) {
    jbyte *data_pointer = (jbyte *)viraddr;
    *data_pointer = data;
}
JNIEXPORT void JNICALL
Java_VME_writeShort(JNIEnv *env, jobject obj, jint viraddr,
                 jshort data) {
    jshort *data_pointer = (jshort *)viraddr;
    *data_pointer = data;
}

JNIEXPORT void JNICALL
Java_VME_writeInt(JNIEnv *env, jobject obj, jint viraddr,
                 jint data) {
    jint *data_pointer = (jint *)viraddr;
    *data_pointer = data;
}
JNIEXPORT jbyte JNICALL
Java_VME_readByte(JNIEnv *env, jobject obj, jint viraddr) {
    jbyte *data_pointer = (jbyte *)viraddr;
    return *data_pointer;
}
JNIEXPORT jshort JNICALL
Java_VME_readShort(JNIEnv *env, jobject obj, jint viraddr) {
    jshort *data_pointer = (jshort *)viraddr;
    return *data_pointer;
}
JNIEXPORT jint JNICALL
Java_VME_readInt(JNIEnv *env, jobject obj, jint viraddr) {
    jint *data_pointer = (jint *)viraddr;
    return *data_pointer;
}

VMEクラス用のJNIライブラリを作るMakefile

SHELL   = /bin/sh

JC      = javac
JH      = javah
CC      = gcc

JFLAGS  = -O
CFLAGS  = -O -shared -Wall

JINCLUDE= -I/usr/local/src/jdk1.3/include -I/usr/local/src/jdk1.3/include/linux
CINCLUDE= -I../vmelib/include -I.
INCLUDE = $(JINCLUDE) $(CINCLUDE)
LIBDIR  = ../lib
CLASSDIR= ../classes
CAMLIB  = ../vmelib/lib
CLASS   = VME
STUB    = VME.class
LIBRARY = libJavaVME.so

all     : stub lib
clean   :
        rm -f \#* *~ rm -f *.class $(CLASS).c $(CLASS).h libJavaVME.so
        rm -f $(CLASSDIR)/$(CLASS).class
        rm -f $(LIBDIR)/$(LIBRARY)

stub    : $(CLASSDIR)/$(CLASS).class

lib     : $(CLASS).class $(CLASS).imp.c
        $(CC) -o $(LIBRARY) $(CFLAGS) $(INCLUDE) $(CLASS).imp.c \
                 -L$(CAMLIB) -lvmelib
        cp -p $(LIBRARY) $(LIBDIR)

$(CLASSDIR)/$(CLASS).class      : $(CLASS).java
        $(JC) $(JFLAGS) $(CLASS).java
        $(JH) -jni $(CLASS)
        if [ ! -e $(CLASS).imp.c ] ; then touch $(CLASS).imp.c ; fi
        if [ ! -e $(CLASS).imp.h ] ; then touch $(CLASS).imp.h ; fi
        cp -p $(CLASS).class $(CLASSDIR)

上記のMakefileは下記のファイル群を利用しています。
src:
Makefile  VME.imp.c  VME.imp.h  VME.java

vmelib:
doc/  example/  include/  lib/

doc:
README  install.txt  usage.html

example:
Makefile       dmatest*   intreg.c  intreg2.c  vscaler.h
Makefile.orig  dmatest.c  intreg.h  vscaler.c

include:
vme_common.h  vme_config.h  vmelib.h

lib:
Makefile  libvmelib.a  vmelib.c  vmelib.o

上記のディレクトリ中に含まれるdmaxxxはVMEのDMAをサポートする 関数群ですが、ここでは扱っていません。

例題

class ForceMemTest{

  public static void main(String argv[]){

    int a16d16mode = 1;
    int a16d32mode = 2;
    int a24d16mode = 3;
    int a24d32mode = 4;
    int a32d32mode = 5;
    int a32d16mode = 6;
    int vme_addr = 0x11000000;
    int vir_addr;
    int status, data;
    int length = 240;

    VME vme = new VME();

    vir_addr = vme.mapOpen(a32d32mode, vme_addr, length);
    System.out.println("mapOpen : virtual address =" + vir_addr);

    for( int i = 0; i < 1; i++)
        for( int j = 0; j < length/4; j++ ) {
            vme.writeInt(vir_addr, j);
            data = vme.readInt(vir_addr);
            if( data != j ) {
                System.out.println("Written data = "+j+"  Read Data = "+data);
                break;
            }
        }
    status = vme.mapClose(vir_addr, length);
    System.out.println("mapClose : status =" + status);
  }
}

例題のコンパイルと実行

さて例題をコンパイルし実行させるためにはJavaの開発環境を整備する 必要があります。大事な環境変数である、CLASSPATH, LD_LIBRARY_PATHを セットします。 以下はこの例題を実行させるために必要な手続きです。
setup.csh:

#!/bin/csh

setenv CLASSPATH $CLASSPATH\:/home/yasu/java/vme/classes\:/home/yasu/java/vme/examples\:/usr/local/java/vme/lib
setenv LD_LIBRARY_PATH $LD_LIBRARY_PATH\:/home/yasu/java/vme/lib

このコマンドを実行させてから上記のテストプログラムを走らせます。
% ./setup.csh
% javac ForceMemTest
% java ForceMemTest