OpenThreads

XCore Project reviews, ideas, videos and proposals.
Post Reply
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

OpenThreads

Post by Folknology »

I have started the OpenThreads project:
Project Overview
Inspired by the successful OpenCores idea, this project aims to provide an opensource commons of reuseable modules or components to run on the event driven model. I did initial think about calling it OpenXcores but figured that that was just a little too cheeky, also I think OpenThreads expresses how many of these modules will interact via using threads rather than more declarative nature of HDLs in the FPGAS world.

How we make these contributions reusable and so they can slot together will be the ongoing conversation until we draft the basic APIs which allow this to happen for version 0.1. In addition I am creating a git repository to hold the code and documentation so bear with me on that. For now this is just a place holder for the idea
So I would like to open the discussion here as to how we get these modules constructed in a way so they can be happy bed fellows. There are a number of issues such as memory usage, shared resources such as inter-core streaming channels and core ports, as well as managing the way these modules interact. A safe way would be to state all shared resources being passed in. This isn't an issue for ports and to a degree streaming channels but could pose issues with memory for example. But lets put the memory issue aside for the moment and imagine how it could work. I would imagine that the main thread provides a supervisor thread, this helps us structure the problem and also provides a nice model for any subsequent shared resources. It also enables some basic module life-cycle management of the modules and the possibility of dealing with errant modules.

Best way to start in my opinion is with some code examples so here is my first pass of pseudo code for module foo which would be called by the supervisor (main perhaps in a Par):

Code: Select all

#define RESET 1;
#define START 2;
#define STOP 3;

#define READY 0;


void foo_mod(chanend control, chanend tick, struct config)
  int Status = READY;
  foo_config(config);
  while(1) {
   tick <: status;//let supervisor know your ok, keep ticking
   select {
   case control :> mode :
     switch(mode){ // decode supervisor instructions to change mode
     case RESET : // Reset state of module
       reset_foo();
       status = RESET;
       break;
     case START : // start modules main function
       start_foo();
       status = START;
       break;
     case STOP : // Stop main function + threads, clean up used resources & return
       release_foo();
       status = STOP;
       return state;
     }
     break;
   case process_foo_port_inputs();// deal with other timers or port inputs could be multiple selects of select functions
     break;
   case process_foo_channel_inputs();// Deal with any other input channel work, like streaming channels from other threads.
     break;
   ...
   default:
     process_foo_outputs();// deal with actual production and outputs to other ports or channels
   }
 }

Here the supervisor is able to configure foo initially by the first call to foo_mod, passing in modular controls and foo'f configuration struct, initially foo configures itself using this struct.

The module then uses a non blocking select arrangement to either do its normal operation, or it responds to commands from the supervisor over the control channel. On receiving supervisory mode commands it switch into the relevant modes. In this case I am assuming simple modes like start and stop. IT also supports resetting of state via a rest command which could be handy in some situations.

Anyhow its just a starter to get the juices flowing, what do you think, is this a good way of doing it, can it be improved what about the other issues around dynamic storage etc..?

Lets work it out?


User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Thanks for addressing the question, since I have ask myself the same quest many times.
It's common that parallel tasks has totally different "clocks". For an example Audio and Video.
What is the best solution if you want to stream the Audio to a LCD-display and show some type of visual information in realtime? The Audio streaming cannot be blocked - and the LCD will only fetch some parts of the Audio when drawing a new frame!

Myself I do not feel forced to use channels if I can choose between channel or SRAM. I like to mix them as smart as possible.

As I understood it from a IRC chat: There is only one ALU per core that uses time slots @400/500 MHz, and the pipeline can never fetch SRAM data in parallel from several threads. e.g. one SRAM-memorycell cannot be address from several threads at the same time, even if you make overrule of the XC parallel usage rules.

I made some testcode where all Audio is handled on core 2, all LCD by core 3 and DSP on Core 0 & 2.
The Audiodata streams from Core 2 (and to DSP parts as well is the intention), to a thread on Core 3 that recieves the streaming data and make some processing then stores the result in a small array. The LCD routine can fetch the data from the array exactly at the time for drawing a LCD-pixel and thereafter zero it's memory-contents. The latest available information will therefor be displayed on the LCD. (In my case it stores the maximum level [dB] of all samples since last videoframe for each channel)

I do not have any other Audio or Video buffers - and I never have any stalling of Audio or the LCD routine (I think it's cool since you a used from any-OS based systems that the screen might lag during CPU-load). It's perfectly smooth VU meters showing all 6in / 8out XAI channels, updated at every LCD frame without any lag :) me - like!

But the instruction-list for channel communication is dense - so maybe there is different ways that isn't possible to address from XC directly !?
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

I have been working on the module examples a bit more here is a pseudo code version of an SPI master module:

Code: Select all

#define RESET 1;
#define START 2;
#define STOP 3;

#define RUNNING 1;

#define CCOM 0
#define CSTATUS 1

select control(chanend command, &status, &spiconf){
   case command :> mode :
     switch(mode){ // decode supervisor instructions to change mode
     case RESET : // Reset state of module
       status = RUNNING;
       break;
     case START : // start modules main function
       init_spi(spiconf); // spi_init()
       status = START;
       break;
     case STOP : // Stop main function + threads, clean up used resources & return
       release_spi(spiconf);
       return 0;
     }
}

select read(chanend sockets[], &status, &spiconf){
   case sockets[REQ] :> bytes :
     switch(bytes){ // decode request
     case BYTE : // Read single byte
       sockets[OUT] <: spi_in(spiconf);
       break;
     case SHORT : // Read Short
       sockets[OUT] <: spi_in_short(spiconf);
       break;
     case WORD : // Read Word
       sockets[OUT] <: spi_in_word(spiconf);
       break;
     default : // Read buffered
       master spi_in_buffered(sockets[OUTBUFFERED],bytes)
       break;
     }
}

transaction tx_packet(chanend c, byte data[], int size){
  for(int i = 0; i < size; i++)
    c <: data[i];
}

transaction rx_packet(chanend c, byte data[], int size){
  for(int i = 0; i < size; i++)
    c :> data[i];
}


void spi_master_mod(chanend controls[],chanend sockets[],struct &spiconf){
  int status = RUNNING;
  byte x;
  while(1) {
    controls[CSTATUS] <: status;
    select {
      case control(chanend controls[CCOM],status,spiconf);
      case sockets[INBYTE] :> x :
        spi_out(x,spiconf);
        break;
      case slave { rx_packet(sockets[INBUFFER],spiconf.packet,spiconf.bufsize); } :
        spi_out_buffered(spiconf);
        break;
      case read(chanend sockets[], status, spiconf);
    
    }
  }
}
Obviously I have excluded chip selects and low level IOs for simplicity.
Post Reply