LOGIN   :::   RECOVER PASS   :::   GET ACCOUNT    
Browse
  • Projects
  • Code (CVS)
  • Forums
  • News
  • Articles
  • Polls
  •  
    OpenCores
  • FAQ
  • CVS HowTo
  • Mission
  • Media
  • Tools
  • Advertise
  • Mirrors
  • Logos
  • Contact us
  • Job Opportunity
  •  
    Tools
  • Search
      
  • Download Cores (CVSGet)
  •  
    More
  • Wishbone
  • Perlilog
  • EDA tools
  • OpenTech CD
  •  
    Navigation: All forums > Cvs-checkins > Message List > Message Post

    Message

    Reply | Reply all
    Date Prev | Date Next | Thread Prev | Thread Next Date Index | Thread Index

    From: cvs at opencores.org<cvs@o...>
    Date: Wed Jul 23 10:46:02 CEST 2008
    Subject: [cvs-checkins] MODIFIED: jop ...
    Top
    Date: 00/08/07 23:10:46

    Modified: jop/java/target/src/common/com/jopdesign/sys JVMHelp.java
    RtThreadImpl.java Startup.java
    Added: jop/java/target/src/common/com/jopdesign/sys Scheduler.java
    Log:
    New scheduler to allow CMP scheulding.


    Revision Changes Path
    1.36 jop/java/target/src/common/com/jopdesign/sys/JVMHelp.java

    http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/com/jopdesign/sys/JVMHelp.java.diff?r1=1.35&r2=1.36

    (In the diff below, changes in quantity of whitespace are not shown.)

    Index: JVMHelp.java
    ===================================================================
    RCS file: /cvsroot/martin/jop/java/target/src/common/com/jopdesign/sys/JVMHelp.java,v
    retrieving revision 1.35
    retrieving revision 1.36
    diff -u -b -r1.35 -r1.36
    --- JVMHelp.java 3 Jul 2008 14:37:09 -0000 1.35
    +++ JVMHelp.java 23 Jul 2008 08:46:02 -0000 1.36
    @@ -27,44 +27,45 @@
    public class JVMHelp {

    /**
    - * The list of the interrupt handlers.
    + * The list of the interrupt handlers for all cores.
    *
    - * TODO: How do we handle this for a CMP version of JOP?
    + * We cannot use HW object in clinit as they depend on JVMHelp.
    */
    - static Runnable ih[] = new Runnable[Const.NUM_INTERRUPTS];
    + static Runnable ih[][] = new Runnable[Native.rdMem(Const.IO_CPUCNT)][Const.NUM_INTERRUPTS];
    static Runnable dh;
    static {
    dh = new DummyHandler();
    + for (int core=0; core<Native.rdMem(Const.IO_CPUCNT); ++core) {
    for (int var=0; var<Const.NUM_INTERRUPTS; ++var) {
    - JVMHelp.addInterruptHandler(var, dh);
    + JVMHelp.addInterruptHandler(core, var, dh);
    + }
    }
    }

    - /**
    - * time stamp variable for measuerments
    - */
    - public static int ts;

    //
    // DON'T change order of first functions!!!
    // interrupt gets called from jvm.asm
    //
    + /**
    + * Dispatch an interrupt to the handler according to the core
    + * and the interrupt number. Interrupt 0 is the scheduler.
    + */
    static void interrupt() {

    - // take a time stamp
    - ts = Native.rdMem(Const.IO_CNT);
    -
    - int nr = Native.rd(Const.IO_INTNR);
    +// int nr = Native.rd(Const.IO_INTNR);
    + ih[Native.rd(Const.IO_CPU_ID)][Native.rd(Const.IO_INTNR)].run();
    +// Native.wr(1, Const.IO_INT_ENA); // for sure?
    // wr('!');
    // wr('0'+nr);
    - if (nr==0) {
    - RtThreadImpl.schedule();
    - } else {
    - ih[nr].run();
    - // enable interrupts again
    - // each interrupt handler shall do it - we do it here for sure
    - Native.wr(1, Const.IO_INT_ENA);
    - }
    +// if (nr==0) {
    +// RtThreadImpl.schedule();
    +// } else {
    +// ih[sys.cpuId][nr].run();
    +// // enable interrupts again
    +// // each interrupt handler shall do it - we do it here for sure
    +// Native.wr(1, Const.IO_INT_ENA);
    +// }
    }


    @@ -219,13 +220,25 @@
    }

    /**
    - * Add a Runnable as a first level interrupt handler
    + * Add a Runnable as a first level interrupt handler.
    + * Use the current core.
    * @param nr interrupt number
    * @param r Runnable the represents the interrupt handler
    */
    public static void addInterruptHandler(int nr, Runnable r) {
    if (nr>=0 && nr<ih.length) {
    - ih[nr] = r; + ih[Native.rdMem(Const.IO_CPU_ID)][nr] = r; + } + } + /** + * Add a Runnable as first level interrupt handler for an individual core. + * @param core + * @param nr + * @param r + */ + public static void addInterruptHandler(int core, int nr, Runnable r) { + if (nr>=0 && nr<ih.length) { + ih[core][nr] = r; } } /** @@ -234,7 +247,7 @@ */ public static void removeInterruptHandler(int nr) { if (nr>=0 && nr<ih.length) { - ih[nr] = dh; + ih[Native.rdMem(Const.IO_CPU_ID)][nr] = dh; } } @@ -295,6 +308,7 @@ static void intVal(int val) { + // tmp is used before clazzinit runs if (tmp==null) tmp = new int[MAX_TMP]; int i; if (val<0) { 1.17 jop/java/target/src/common/com/jopdesign/sys/RtThreadImpl.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/com/jopdesign/sys/RtThreadImpl.java.diff?r1=1.16&r2=1.17 (In the diff below, changes in quantity of whitespace are not shown.) Index: RtThreadImpl.java =================================================================== RCS file: /cvsroot/martin/jop/java/target/src/common/com/jopdesign/sys/RtThreadImpl.java,v retrieving revision 1.16 retrieving revision 1.17 diff -u -b -r1.16 -r1.17 --- RtThreadImpl.java 26 Jun 2008 18:43:45 -0000 1.16 +++ RtThreadImpl.java 23 Jul 2008 08:46:02 -0000 1.17 @@ -24,8 +24,10 @@ package com.jopdesign.sys; -import joprt.RtThread; +import com.jopdesign.io.IOFactory; +import com.jopdesign.io.SysDevice; +import joprt.RtThread; /** * @author Martin @@ -35,6 +37,52 @@ */ public class RtThreadImpl { + /** + * Helper class to start the other CPUs in a CMP system + * @author martin + * + */ + static class CMPStart implements Runnable { + + volatile boolean started; + + /* (non-Javadoc) + * @see java.lang.Runnable#run() + */ + public void run() { + + // Disable all interrupts globally and local - for sure + Native.wr(0, Const.IO_INT_ENA); + Native.wr(0, Const.IO_INTMASK); + + // startThread for all threads that belong to this CPU. + // This thread is already in state READY and not started. + Scheduler s = Scheduler.sched[sys.cpuId]; + for (int i=0; i<s.cnt; ++i) { + s.ref[i].startThread(); + } + // add scheduler for the core s + JVMHelp.addInterruptHandler(sys.cpuId, 0, s); + + started = true; + + // clear all pending interrupts (e.g. timer after reset) + Native.wr(1, Const.IO_INTCLEARALL); + // schedule timer in 10 ms + Native.wr(RtThreadImpl.startTime, Const.IO_TIMER); + Native.wr(1, Const.IO_INTCLEARALL); + + // enable all interrupts + Native.wr(-1, Const.IO_INTMASK); + Native.wr(1, Const.IO_INT_ENA); + + // nothing to do in the main thread for the CMP cores 1 .. n-1 + for (;;) { + ; + } + } + } + // usual priority levels of java.lang.Thread public final static int MIN_PRIORITY = 1; public final static int NORM_PRIORITY = 5; @@ -44,50 +92,39 @@ protected final static int RT_BASE = 2; protected final static int RT_IDLE = 1; - protected final static int IDL_TICK = 10000; private RtThread rtt; // reference to RtThread's run method private int priority; private int period; // period in us private int offset; // offset in us + private boolean isEvent; // it's a software event - // index in next, ref and event - int nr; - private int[] stack; - private int sp; - // allocated and set in startMission - // ordered by priority - private static int next[]; // next time to change to state running - private static RtThreadImpl[] ref; // references to threads - - final static int NO_EVENT = 0; - final static int EV_FIRED = 1; - final static int EV_WAITING = 2; - static int event[]; // state of an event - boolean isEvent; + // only used in startMission + final static int CREATED = 0; + final static int READY = 1; // READY means ready to run. + final static int WAITING = 2; // active is the running thread. + final static int DEAD = 3; + int state; - private static int cnt; - private static int active; // active thread number + int cpuId; // core that the thread is running on + // index in next, ref and event + int nr; + int[] stack; + int sp; // linked list of threads in priority order + // used only at initialization time to collect the threads private RtThreadImpl lower; private static RtThreadImpl head; - // only used in startMission - protected final static int CREATED = 0; - protected final static int READY = 1; // READY means ready to run. - protected final static int WAITING = 2; // active is the running thread. - protected final static int DEAD = 3; - private int state; - -// private final static int MAX_STACK = 128; - private static boolean initDone; + static boolean initDone; static boolean mission; - protected static Object monitor; + static SysDevice sys = IOFactory.getFactory().getSysDevice(); + // no synchronization necessary: // doInit() is called on first new RtThread() => @@ -101,69 +138,36 @@ initDone = true; mission = false; - monitor = new Object(); + // create scheduler objects for all cores + for (int i=0; i<sys.nrCpu; ++i) { + new Scheduler(i); - active = 0; // main thread (or idl thread) is first thread - cnt = 1; // stays 1 till startMission - - next = new int[1]; - ref = new RtThreadImpl[1]; + } head = null; - // thread struct for main - ref[0] = new RtThreadImpl(NORM_PRIORITY, 0); - ref[0].state = READY; // main thread is READY - next[0] = 0; - - // create one idle thread with Thread prio 0 - // If we have a main thread with 'active' (yielding) - // sleep() this is not necessary. - // - // Should be replaced by a Thread scheduler with - // RT_IDLE priority -/* main is now our idle task - new RtThread(0, 0) { - public void run() { - for (;;) { - util.Dbg.wr('i'); - } - } - }; -*/ - // We have now more than one thread => // If we have 'normal' Threads we should start the timer! } - // not necessary - // private RtThread() {}; - - private RtThreadImpl(int prio, int us) { + RtThreadImpl(int prio, int us) { this(null, prio, us, 0); } public RtThreadImpl(RtThread rtt, int prio, int us, int off) { -//System.out.print("new Thread w prio "); -//System.out.println(prio); -//System.out.println("a"); if (!initDone) { init(); } -//System.out.println("b"); stack = new int[Const.STACK_SIZE-Const.STACK_OFF]; sp = Const.STACK_OFF; // default empty stack for GC before startMission() -// System.out.print(MAX_STACK); -// System.out.println("c"); + for (int i=0; i<Const.STACK_SIZE-Const.STACK_OFF; ++i) { -// System.out.print(i); stack[i] = 1234567; } -//System.out.println("d"); this.rtt = rtt; @@ -171,7 +175,7 @@ offset = off; if (us==0) { // this is NOT a RT thread priority = prio; - } else { // RT prio is above Thread prios. + } else { // RT priority is above Thread priorities priority = prio+MAX_PRIORITY+RT_BASE; } state = CREATED; @@ -195,6 +199,13 @@ } } + /** + * Set the processor number + * @param id + */ + public void setProcessor(int id) { + cpuId = id; + } private static void genInt() { @@ -204,123 +215,14 @@ for (int j=0;j<10;++j) ; } - -// time stamps: -public static int ts0, ts1, ts2, ts3, ts4; - - private static int s1; // helper var - - private static int tim; // next timer value - // timer offset to ensure that no timer int happens just - // after monitorexit in this method and the new thread - // has a minimum time to run. - private final static int TIM_OFF = 20; -// private final static int TIM_OFF = 2; // for 100 MHz version 20 or even lower - // 2 is minimum - - // this is the one and only function to - // switch threads. - // schedule() is called from JVMHelp.interrupt() - // and should NEVER be called from somewhere - // else. - // Interrupts (also yield/genInt()) should NEVER - // ocour befor startMission is called (ref and active are set) - static void schedule() { - - int i, j, k; - int diff; - - // we have not called doInit(), which means - // we have only one thread => just return - if (!initDone) return; - - Native.wr(0, Const.IO_INT_ENA); - // synchronized(monitor) { - // save stack - i = Native.getSP(); - RtThreadImpl th = ref[active]; - th.sp = i; - Native.int2extMem(Const.STACK_OFF, th.stack, i-Const.STACK_OFF+1); // cnt is i-Const.STACK_OFF+1 - - // SCHEDULE - // cnt should NOT contain idle thread - // change this some time - k = IDL_TICK; - - // this is now - j = Native.rd(Const.IO_US_CNT); - - for (i=cnt-1; i>0; --i) { - - if (event[i] == EV_FIRED) { - break; // a pending event found - } else if (event[i] == NO_EVENT) { - diff = next[i]-j; // check only periodic - if (diff < TIM_OFF) { - break; // found a ready task - } else if (diff < k) { - k = diff; // next int time of higher prio task - } - } - } - // i is next ready thread (index in new list) - // If none is ready i points to idle task or main thread (fist in the list) - active = i; - - // set next int time to now+(min(diff)) (j, k) - tim = j+k; - - // restore stack - s1 = ref[i].sp; - Native.setVP(s1+2); // +2 for sure ??? - Native.setSP(s1+7); // +5 locals, take care to use only the first 5!! - - i = s1; - // can't use s1-127 as count, - // don't know why I have to store it in a local. - Native.ext2intMem(ref[active].stack, Const.STACK_OFF, i-Const.STACK_OFF+1); // cnt is i-Const.STACK_OFF+1 - - j = Native.rd(Const.IO_US_CNT); - // check if next timer value is too early (or allready missed) - // ack int and schedule timer - if (tim-j<TIM_OFF) { - // set timer to now plus some short time - Native.wr(j+TIM_OFF, Const.IO_TIMER); - } else { - Native.wr(tim, Const.IO_TIMER); - } - Native.setSP(i); - // only return after setSP! - // WHY should this be true? We need a monitorexit AFTER setSP(). - // It compiles to following: - // invokestatic #32 <Method void setSP(int)> - // aload 5 - // monitorexit - // goto 283 - // ... - // 283 return - // - // for a 'real monitor' we have a big problem: - // aload 5 loads the monitor from the OLD stack!!! - // - // we can't access any 'old' locals now - // - // a solution: don't use a monitor here! - // disable and enable INT 'manual' - // and DON'T call a method with synchronized - // it would enable the INT on monitorexit - Native.wr(1, Const.IO_INT_ENA); - // } - } - private void startThread() { - if (state!=CREATED) return; // allread called start + if (state!=CREATED) return; // already called start - // if we have int enabled we have to synchronize + // if we have interrupts enabled we have to synchronize if (period==0) { - state = READY; // for the idle thread + state = READY; // for the idle thread, but we're not using one } else { state = WAITING; } @@ -337,7 +239,7 @@ for (;;) { // This will not work if we change stack like in Thread.java. // Then we have no reference to this. - next[nr] = Native.rd(Const.IO_US_CNT) + 2*IDL_TICK; + Scheduler.sched[sys.cpuId].next[nr] = Native.rd(Const.IO_US_CNT) + 2*Scheduler.IDL_TICK; genInt(); } } @@ -384,93 +286,138 @@ // ; // nothing to do // } + /** + * Static start time of scheduling used by all cores + */ + static int startTime; public static void startMission() { - int i, c, startTime; - RtThreadImpl th, mth; + int i, j, c; + RtThreadImpl th; + Scheduler s; if (!initDone) { init(); } + // TODO: we also disable acquiring the global lock - a running GC + // (on a different core) is not + // protected for the write barriers at this time + // Disable all interrupts globally and local - for sure + Native.wr(0, Const.IO_INT_ENA); + Native.wr(0, Const.IO_INTMASK); + + + // if we have int's enabled for Thread scheduling + // or using the Scheduler interrupt // we have to place a monitorenter here + + // Collect number of thread for each core th = head; for (c=0; th!=null; ++c) { + Scheduler.sched[th.cpuId].cnt++; th = th.lower; } - mth = ref[0]; // this was our main thread - - ref = new RtThreadImpl[c]; - next = new int[c]; - event = new int[c]; + for (i=0; i<sys.nrCpu; ++i) { + Scheduler.sched[i].allocArrays(); + } - th = head; - // array is order according priority + // list is ordered with increasing priority + // array is reverse priority ordered per core // top priority is last! - for (i=c-1; th!=null; --i) { - ref[i] = th; - th.nr = i; + for (th = head; th!=null; th = th.lower) { + s = Scheduler.sched[th.cpuId]; + s.ref[s.tmp] = th; + th.nr = s.tmp; if (th.isEvent) { - event[i] = EV_WAITING; + s.event[s.tmp] = Scheduler.EV_WAITING; } else { - event[i] = NO_EVENT; + s.event[s.tmp] = Scheduler.NO_EVENT; } - th = th.lower; + s.tmp--; } - // change active if a lower priority - // thread is befor main - active = mth.nr; + for (i=0; i<sys.nrCpu; ++i) { + Scheduler.sched[i].addMain(); + } // running threads (state!=CREATED) // are not started // TODO: where are 'normal' Threads placed? - for (i=0; i<c; ++i) { - ref[i].startThread(); + s = Scheduler.sched[sys.cpuId]; + for (i=0; i<s.cnt; ++i) { + s.ref[i].startThread(); } - // wait 100 ms (for main Thread.debug()) - startTime = Native.rd(Const.IO_US_CNT)+100000; - for (i=0; i<c; ++i) { - next[i] = startTime+ref[i].offset; + // wait 10 ms for the real start if the mission + startTime = Native.rd(Const.IO_US_CNT)+10000; + for (i=0; i<sys.nrCpu; ++i) { + s = Scheduler.sched[i]; + for (j=0; j<s.cnt; ++j) { + s.next[j] = startTime+s.ref[j].offset; + } + } + + // add scheduler for the first core + JVMHelp.addInterruptHandler(0, 0, Scheduler.sched[0]); + + + CMPStart cmps[] = new CMPStart[sys.nrCpu-1]; + // add the Runnables to start the other CPUs + for (i=0; i<sys.nrCpu-1; ++i) { + cmps[i] = new RtThreadImpl.CMPStart(); + Startup.setRunnable(cmps[i], i); + + } + + // start the other CPUs + sys.signal = 1; + + // busy wait for start threads of other cores + for (;;) { + boolean ready = true; + for (i=0; i<sys.nrCpu-1; ++i) { + ready = ready && cmps[i].started; + } + if (ready) { + break; + } } - cnt = c; mission = true; - // set moncnt in jvm.asm to zero to enable int's - // on monitorexit from now on - Native.wrIntMem(0, 5); // clear all pending interrupts (e.g. timer after reset) Native.wr(1, Const.IO_INTCLEARALL); - // schedule timer in 100 ms + // schedule timer in 10 ms Native.wr(startTime, Const.IO_TIMER); - // enable all interrupts int + // enable all interrupts Native.wr(-1, Const.IO_INTMASK); Native.wr(1, Const.IO_INT_ENA); - } public boolean waitForNextPeriod() { - synchronized(monitor) { int nxt, now; + Scheduler s = Scheduler.sched[sys.cpuId]; - nxt = next[nr] + period; + Native.wr(0, Const.IO_INT_ENA); + + nxt = s.next[nr] + period; now = Native.rd(Const.IO_US_CNT); if (nxt-now < 0) { // missed time! - next[nr] = now; // correct next + s.next[nr] = now; // correct next // next[nr] = nxt; // without correction! + Native.wr(1, Const.IO_INT_ENA); return false; } else { - next[nr] = nxt; + s.next[nr] = nxt; } // state is not used in scheduling! // state = WAITING; @@ -478,10 +425,14 @@ // just schedule an interrupt // schedule() gets called. Native.wr(0, Const.IO_SWINT); + // will arrive before return statement, + // just after interrupt enable + // TODO: do we really need this loop? for (int j=0;j<10;++j) ; - // will arrive befor return statement, - // just after monitorexit - } + Native.wr(1, Const.IO_INT_ENA); + + // This return should only be executed when we are + // scheduled again return true; } @@ -490,15 +441,19 @@ } public void fire() { - event[this.nr] = EV_FIRED; + Scheduler.sched[this.cpuId].event[this.nr] = Scheduler.EV_FIRED; // if prio higher... // should not be allowed befor startMission + // TODO: for cross CPU event fire we need to generate the interrupt + // for the other core! genInt(); } public void blockEvent() { - event[this.nr] = EV_WAITING; + Scheduler.sched[this.cpuId].event[this.nr] = Scheduler.EV_WAITING; + // TODO: for cross CPU event fire we need to generate the interrupt + // for the other core! genInt(); } @@ -551,62 +506,24 @@ // stack while assembling it. Then some writebarrier should protect the // references and downgrade the GC state from black to grey? + // TODO: make it CMP aware static int[] getStack(int num) { - return ref[num].stack; + return Scheduler.sched[0].ref[num].stack; } static int getSP(int num) { - return ref[num].sp; + return Scheduler.sched[0].ref[num].sp; } static int getCnt() { - return cnt; + return Scheduler.sched[0].cnt; } static int getActive() { - return active; + return Scheduler.sched[0].active; } -// WARNING: debug can take a long time (xx ms) -public static void debug() { - - synchronized(monitor) { - - - int i, j; - for (i=cnt-1; i>=0; --i) { - - util.Dbg.wr('\n'); - util.Dbg.intVal(ref[i].sp); - util.Dbg.wr('\n'); - for (j=0; j<=ref[i].sp-Const.STACK_OFF; ++j) { - util.Dbg.intVal(ref[i].stack[j]); - } - util.Dbg.wr('\n'); -trace(ref[i].stack, ref[i].sp); - } -/* - int i, tim; - - tim = Native.rd(Native.IO_US_CNT); - util.Dbg.wr(' '); - util.Dbg.intVal(active); - util.Dbg.wr('-'); - util.Dbg.wr(' '); - for (i=0; i<cnt; ++i) { - util.Dbg.intVal(ref[i].nr); - util.Dbg.intVal(ref[i].priority); - util.Dbg.intVal(ref[i].state); - util.Dbg.intVal(next[i]-tim); - } - util.Dbg.wr('\n'); - tim = Native.rd(Native.IO_US_CNT)-tim; - util.Dbg.intVal(tim); - util.Dbg.wr('\n'); -*/ - } -} static void trace(int[] stack, int sp) { 1.36 jop/java/target/src/common/com/jopdesign/sys/Startup.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/com/jopdesign/sys/Startup.java.diff?r1=1.35&r2=1.36 (In the diff below, changes in quantity of whitespace are not shown.) Index: Startup.java =================================================================== RCS file: /cvsroot/martin/jop/java/target/src/common/com/jopdesign/sys/Startup.java,v retrieving revision 1.35 retrieving revision 1.36 diff -u -b -r1.35 -r1.36 --- Startup.java 26 Jun 2008 18:43:45 -0000 1.35 +++ Startup.java 23 Jul 2008 08:46:02 -0000 1.36 @@ -44,9 +44,19 @@ final static int MAX_STACK = 100; static int sp, pc, cp; + /** + * How needs this field, and why? + */ static boolean started; /** + * The start method for CPU 1 to n-1. + * + * Public just for a quick test. + */ + static Runnable[] cpuStart; + + /** * called from jvm.asm as first method. * Do all initialization here and call main method. */ @@ -55,10 +65,8 @@ // use local variable - statics are not CMP save! int val; - // set moncnt in jvm.asm to zero to enable int's - // on monitorexit from now on - Native.wrIntMem(0, 5); // disable all interrupts locally + // global enable and disable on monitorenter/exit don't hurt Native.wr(0, Const.IO_INTMASK); // only CPU 0 does the initialization stuff @@ -78,6 +86,8 @@ version(); started = true; clazzinit(); + + cpuStart = new Runnable[Native.rdMem(Const.IO_CPUCNT)-1]; } // clear all pending interrupts (e.g. timer after reset) @@ -85,11 +95,24 @@ // set global enable Native.wr(1, Const.IO_INT_ENA); - // call main() + // request CPU id + val = Native.rdMem(Const.IO_CPU_ID); + + if (val==0) { + // only CPU 0 invokes main() val = Native.rdMem(1); // pointer to 'special' pointers - val = Native.rdMem(val+3); // pointer to main method struct + val = Native.rdMem(val+3); // pointer to main method structure Native.invoke(0, val); // call main (with null pointer on TOS exit(); + } else { + // other CPUs invoke a Runnable + if (cpuStart[val-1]!=null) { + cpuStart[val-1].run(); + } + for (;;) { + ; // busy loop for other CPUs exit + } + } } @@ -100,6 +123,15 @@ } /** + * Add a Runnable for the other CPUs + * @param r + * @param index + */ + public static void setRunnable(Runnable r, int index) { + cpuStart[index] = r; + } + + /** * @return RAM size in 32 bit words */ static int getRamSize(int offset) { 1.5 jop/java/target/src/common/com/jopdesign/sys/Scheduler.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/com/jopdesign/sys/Scheduler.java.diff?r1=1.4&r2=1.5 (In the diff below, changes in quantity of whitespace are not shown.) Index: Scheduler.java =================================================================== RCS file: Scheduler.java diff -N Scheduler.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Scheduler.java 23 Jul 2008 08:46:02 -0000 1.5 @@ -0,0 +1,200 @@ +package com.jopdesign.sys; + +import com.jopdesign.io.IOFactory; +import com.jopdesign.io.SysDevice; + +/** + * Represent the scheduler and thread queue for one CPU. + * Created and set in startMisison() + * + * @author martin + * + */ +class Scheduler implements Runnable { + // allocated and set in startMission + // ordered by priority + int next[]; // next time to change to state running + RtThreadImpl[] ref; // references to threads + + final static int NO_EVENT = 0; + final static int EV_FIRED = 1; + final static int EV_WAITING = 2; + int event[]; // state of an event + + int cnt; // number of threads + int active; // active thread number + + int tmp; // counter to build the thread list + + static SysDevice sys = IOFactory.getFactory().getSysDevice(); + static Scheduler[] sched = new Scheduler[sys.nrCpu]; + + Scheduler(int core) { + active = 0; // main thread (or idle thread) is first thread + cnt = 0; // stays 0 till startMission + +// next = new int[1]; +// ref = new RtThreadImpl[1]; + + sched[core] = this; + } + + final static int IDL_TICK = 10000; + + // use local memory for two values + private final static int TIM_VAL_ADDR = 0x1e; + private final static int SP_VAL_ADDR = 0x1f; + + // timer offset to ensure that no timer interrupt happens just + // after monitorexit in this method and the new thread + // has a minimum time to run. + private final static int TIM_OFF = 200; +// private final static int TIM_OFF = 20; +// private final static int TIM_OFF = 2; // for 100 MHz version 20 or even lower + // 2 is minimum + /** + * This is the scheduler invoked as a plain interrupt handler + * from JVMHelp.interrupt(). It gets invoked with interrupts + * globally disabled. + * + * This is the one and only function to switch threads + * and should NEVER be called from somewhere else. + * + * Interrupts (also yield/genInt()) should NEVER occur + * before startMission is called (ref and active are set) + * + */ + public void run() { + + int i, j, k; + int diff; + Scheduler s; + RtThreadImpl th; + + // we have not called doInit(), which means + // we have only one thread => just return + // Should actually not happen. + if (!RtThreadImpl.initDone) return; + + // take care to NOT invoke a method with monitorexit + // can happen on the write barrier on reference assignment + + // save stack + i = Native.getSP(); + th = ref[active]; + th.sp = i; + Native.int2extMem(Const.STACK_OFF, th.stack, i-Const.STACK_OFF+1); // cnt is i-Const.STACK_OFF+1 + + // SCHEDULE + // cnt should NOT contain idle thread + // change this some time + k = IDL_TICK; + + // this is now + j = Native.rd(Const.IO_US_CNT); + + for (i=cnt-1; i>0; --i) { + + if (event[i] == EV_FIRED) { + break; // a pending event found + } else if (event[i] == NO_EVENT) { + diff = next[i]-j; // check only periodic + if (diff < TIM_OFF) { + break; // found a ready task + } else if (diff < k) { + k = diff; // next interrupt time of higher priority thread + } + } + } + // i is next ready thread (index into the list) + // If none is ready i points to idle task or main thread (fist in the list) + active = i; + + // set next interrupt time to now+(min(diff)) (j, k) + // use JVM locals to get time and sp over the stack exchange + Native.wrIntMem(j+k, TIM_VAL_ADDR); + + + // restore stack + // We cannot use statics in a CMP setting! + Native.wrIntMem(ref[i].sp, SP_VAL_ADDR); + Native.setVP(Native.rdIntMem(SP_VAL_ADDR)+2); // +2 for sure ??? + // +7 locals, take care to use only the first 1+6!! + // so +9 should be ok, but it works only with +10 when + // using all locals + Native.setSP(Native.rdIntMem(SP_VAL_ADDR)+10); + + // all locals are lost now, even this - reassign them + // get this back form the array of Schedulers + s = sched[sys.cpuId]; + th = s.ref[s.active]; + i = Native.rdIntMem(SP_VAL_ADDR); + + // can't use s1-127 as count, + // don't know why I have to store it in a local. + + Native.ext2intMem(th.stack, Const.STACK_OFF, i-Const.STACK_OFF+1); // cnt is i-Const.STACK_OFF+1 + + j = Native.rd(Const.IO_US_CNT); + // check if next timer value is too early (or already missed) + // ack timer interrupt and schedule timer + if (Native.rdIntMem(TIM_VAL_ADDR)-j<TIM_OFF) { + // set timer to now plus some short time + Native.wr(j+TIM_OFF, Const.IO_TIMER); + } else { + Native.wr(Native.rdIntMem(TIM_VAL_ADDR), Const.IO_TIMER); + } + Native.setSP(i); + // only return after setSP! + // WHY should this be true? We need a monitorexit AFTER setSP(). + // It compiles to following: + // invokestatic #32 <Method void setSP(int)> + // aload 5 + // monitorexit + // goto 283 + // ... + // 283 return + // + // for a 'real monitor' we have a big problem: + // aload 5 loads the monitor from the OLD stack!!! + // + // we can't access any 'old' locals now + // + // a solution: don't use a monitor here! + // disable and enable INT 'manual' + // and DON'T call a method with synchronized + // it would enable the INT on monitorexit + Native.wr(1, Const.IO_INT_ENA); + } + + /** + * Allocate arrays for the thread list. One more than cnt for + * the initial main/Runnable + */ + void allocArrays() { + + // change active if a lower priority + // thread is before main +// tq.active = tq.ref[0].nr; // this was our main thread + + // cnt one higher for start thread (main or Runnable) + ++cnt; + ref = new RtThreadImpl[cnt]; + next = new int[cnt]; + event = new int[cnt]; + tmp = cnt-1; + } + + /** + * Add main or Runnable to the list as last thread. + */ + public void addMain() { + + // thread structure for main and the start Runnables + // TODO: do we need to do a startThread for the CMP start Runnable? + ref[0] = new RtThreadImpl(RtThreadImpl.NORM_PRIORITY, 0); + ref[0].state = RtThreadImpl.READY; // main thread is READY + next[0] = 0; + ref[0].nr = 0; + } +} \ No newline at end of file

     
    Copyright (c) 1999 OPENCORES.ORG. All rights reserved.