GithubHelp home page GithubHelp logo

gnupru's Introduction

build status

Port of GNU GCC and Binutils for the TI PRU I/O processor.

Table Of Contents

Introduction

This is a collection of documentation and build scripts for the GNU toolchain targeting the PRU I/O CPU. PRU cores present in TI Sitara AM33xx and later SoCs are supported.

Support for older PRU core versions is not planned.

A simulator is used to execute the GCC C regression test suite. Results are posted daily to https://gcc.gnu.org/pipermail/gcc-testresults/ .

Bug reports should be filed in https://github.com/dinuxbg/gnupru/issues . For general questions please use https://forum.beagleboard.org/ .

This project has no relation to the TI PRU C compiler. ABI differences between GCC PRU and TI PRU C are tracked in https://github.com/dinuxbg/gnupru/wiki

Examples

There are several examples to get started:

Getting The Cross Toolchain

Several methods to acquire the PRU cross toolchain are listed below, ordered by most convenient first.

Installing On Beagleboard Debian

If you are running a Beagleboard Debian Image, then installation is simple:

sudo apt-get update
sudo apt-get install gcc-pru gnuprumcu

Prebuilt Tarballs

Latest releases provide prebuilt tarballs for several hosts: amd64 Linux, armhf Linux, Windows. Simply download, untar and use them when:

  • You want to cross-compile PRU firmware from amd64 Linux or Windows host.
  • You are using an armhf distribution other than Beagleboard Debian Image.

Note for maintainers: These prebuilt release tarballs are prepared using the build-crosstool-ng.sh script.

Building Using Crosstool-ng

Recently crosstool-ng acquired pru support. Provided you build top-of-tree crosstool-ng, you should be able to:

$ ct-ng pru
$ ct-ng build
$ PATH=$HOME/x-tools/pru-elf/bin:$PATH

Building From Sources

The custom build scripts are should work on any recent Linux distro. They are intended to be simple enough, so that they can act as a documentation how to cross-compile a toolchain. They intentionally lack some features:

  • Downloaded source tarballs are not verified.
  • Host binaries are not stripped, leading to bigger host executables sizes. Target firmware size is not affected, though!
  • Code complexity is kept at only about 100 lines of simple BASH statements.

Users may find that Beagleboard Debian Packages, or prebuilt releases or crosstool-ng are instead more suitable for production.

You'll need some prerequisites. For a Debian host:

sudo apt-get install build-essential libmpfr-dev libgmp-dev libmpc-dev texinfo libncurses5-dev bison flex texinfo

Alternatively, for a Fedora host:

sudo dnf install @development-tools g++ mpfr-devel gmp-devel libmpc-devel texinfo texinfo-tex texlive-cm-super* texlive-ec ncurses-devel bison flex

Then it should be a simple matter of:

export PREFIX=$HOME/bin/pru-gcc   # Define where to install the toolchain
./download-and-prepare.sh         # Download and prepare the sources
./build.sh                        # Build

Acknowledgements

  • GCC/Binutils Nios2 port was taken as a base for the PRU port.

gnupru's People

Contributors

dinuxbg avatar robertcnelson avatar waddlesplash avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gnupru's Issues

Add support for TI debug info relocations

Currently, for GCC to be able to link TI CGT object files, TI CGT must be passed the --symdebug:none option. Otherwise GCC/Binutils cannot handle the TI debug info relocations.

Add LDI32 pseudo support to GAS and LD

LDI32 support would require:

  1. PRU GAS backend to start outputting 64-bit instructions (the two LDIs will be presented as one "big" instruction).
  2. PRU LD to add support for relaxation and LDI32 relocations.

Compiler defined compiler macros

Does pru-gcc have any kind of compiler defined macros, like when i pass -mmcu=am335x.pru0 or am335x.pru1, is there some way i could so something like this:

#ifdef __PRU0__
    #define HOSTINT (uint32_t) 1 << 30
#elif __PRU1__
    #define HOSTINT (uint32_t) 1 << 31
#else 

Cleanup the GCC test report

There are a few failing tests when running the GCC testsuite using a PRU simulator. Almost all of them are due to core bugs in obscure extensions (e.g. __builtin_apply) or do not affect the generated code. If a fix is not feasible, then use "contrib/dg-cmp-results.sh" to track for regressions.

TI ABI: Enable REL relocations in GNU LD

Turns out that different TI CGT versions output either REL or RELA ELF relocations. TI CGT linker seems to ingest both types.

Right now PRU GNU LD supports only RELA types. REL should be added to be more compatible with TI CGT

Resolve label-vs-register ambiguity in pru-gas

The following C source will produce invalid machine code:

extern void fp(void)
main()
{
    fp();
}

Because pru-gas syntax is amguous:

   call fp    ; Is it register FP or label FP???

Possible solutions:

  • Prefix all C symbols with an underscore. But this will not solve the problem for assembler programmers.
  • Prefix all registers with a dollar sign.
  • "Fork" the jmp/jal instructions (and the call macro). Jmp/jal/call will work only with labels. The indirect variants ijmp/ijal/icall will work only with registers.

Finish GDB support for PRU

Explore GDB PRU port feasibility. So far there is a very rough GDB backend for the PRU simulator target.

The following items remain to be implemented:

  • Stack unwiding support. This is needed for source-level GDB debugging.
  • Real target backend support via remoteproc framework, preferably without an intermediate gdbserver.

Cleanup TODOs in GCC port

Several small cleanups and investigations have been suggested during mainline review. All of them have been marked with TODO in the source code. Go through, root cause, and fix them.

Fold all mov patterns into a single one for each mode size

Per comment on mailing list

On Monday, 8/20/2018 11:12:23 EEST Jeff Law wrote:
Note that in general both reload and LRA require that the movXX patterns
be unified for any given mode. Reload and LRA can change the operands
without re-recognizing the pattern. You might be getting away with not
adhering to that requirement because you're just dealing with constant
source operands (most of the problems I've run into through the years
involve memory operands). But be aware you may need to twiddle this and
fold those patterns back into your movXX patterns.

LD: Add support for TI's debug REL relocation

It appears that code and data relocations are RELA. But the DWARF debug information generated by TI's CLPRU uses REL. It would be nice to have this support in LD, so that users can intermix object files.

Define Carry bit in GCC PRU port

  1. Experiment to check the semantics of PRU Carry bit: Is it the same for add/sub, is it set/cleared by adc/subc instructions.
  2. Define it in GCC PRU port and replace the hardcoded adddi/subdi patterns with carry-based ones.

Signed integer comparison is totally broken

The cbranch pattern is totally broken for signed comparisons. First, we really support only equal length parameters. And second, the algorithm for turning signed into unsigned comparison is flawed.

Issue with autoconf, when adding pru-gcc as a dependency that needs to be checked

I am trying to setup autotools to compile a pru project, it fails at ./configure step. Following are my files and error logs

commands

aclocal
autoconf
automake --add-missing
./configure

configure.ac

AC_PREREQ([2.69])
AC_INIT([libprurpmsg], [1.0], [https://github.com/VedantParanjape/simppru/issues])
AC_CONFIG_SRCDIR([pru_virtqueue.c])

# Checks for programs.
AC_PROG_CC([pru-gcc])
AC_PROG_RANLIB([pru-gcc-ranlib])
AM_PROG_AR([pru-gcc-ar])

# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT16_T
AC_TYPE_INT32_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT8_T

# Checks for library functions.

AC_CONFIG_FILES([Makefile])
AC_OUTPUT

config.log

This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.

It was created by libprurpmsg configure 1.0, which was
generated by GNU Autoconf 2.69.  Invocation command line was

  $ ./configure --disable-option-checking --prefix=/usr/local --cache-file=/dev/null --srcdir=.

## --------- ##
## Platform. ##
## --------- ##

hostname = veware
uname -m = x86_64
uname -r = 5.4.0-40-generic
uname -s = Linux
uname -v = #44-Ubuntu SMP Tue Jun 23 00:01:04 UTC 2020

/usr/bin/uname -p = unknown
/bin/uname -X     = unknown

/bin/arch              = unknown
/usr/bin/arch -k       = unknown
/usr/convex/getsysinfo = unknown
/usr/bin/hostinfo      = unknown
/bin/machine           = unknown
/usr/bin/oslevel       = unknown
/bin/universe          = unknown

PATH: /home/vedant/gems/bin
PATH: /home/vedant/spicetify-cli
PATH: /home/vedant/gems/bin
PATH: /home/vedant/esp/esp-idf/components/esptool_py/esptool
PATH: /home/vedant/esp/esp-idf/components/espcoredump
PATH: /home/vedant/esp/esp-idf/components/partition_table/
PATH: /home/vedant/.espressif/tools/xtensa-esp32-elf/esp-2019r2-8.2.0/xtensa-esp32-elf/bin
PATH: /home/vedant/.espressif/tools/xtensa-esp32s2-elf/esp-2019r2-8.2.0/xtensa-esp32s2-elf/bin
PATH: /home/vedant/.espressif/tools/esp32ulp-elf/2.28.51.20170517/esp32ulp-elf-binutils/bin
PATH: /home/vedant/.espressif/tools/openocd-esp32/v0.10.0-esp32-20190708/openocd-esp32/bin
PATH: /home/vedant/.espressif/python_env/idf4.1_py2.7_env/bin
PATH: /home/vedant/esp/esp-idf/tools
PATH: /home/vedant/bin
PATH: /home/vedant/.local/bin
PATH: /usr/local/sbin
PATH: /usr/local/bin
PATH: /usr/sbin
PATH: /usr/bin
PATH: /sbin
PATH: /bin
PATH: /usr/games
PATH: /usr/local/games
PATH: /snap/bin
PATH: /usr/local/go/bin
PATH: /home/vedant/x-tools/arm-kindle5-linux-gnueabi/bin
PATH: /home/vedant/pru-gcc/bin


## ----------- ##
## Core tests. ##
## ----------- ##

configure:1798: checking for pru-gcc
configure:1814: found /home/vedant/pru-gcc/bin/pru-gcc
configure:1825: result: pru-gcc
configure:1856: checking for C compiler version
configure:1865: pru-gcc --version >&5
pru-gcc (GCC) 10.1.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

configure:1876: $? = 0
configure:1865: pru-gcc -v >&5
Using built-in specs.
COLLECT_GCC=pru-gcc
COLLECT_LTO_WRAPPER=/home/vedant/pru-gcc/libexec/gcc/pru/10.1.0/lto-wrapper
Target: pru
Configured with: /home/vedant/Programming/contributing/gnupru/src/gcc/configure --target=pru --prefix=/home/vedant/pru-gcc --disable-nls --with-newlib --with-bugurl=https://github.com/dinuxbg/gnupru/issues --without-headers --enable-languages=c : (reconfigured) /home/vedant/Programming/contributing/gnupru/src/gcc/configure --target=pru --prefix=/home/vedant/pru-gcc --disable-nls --with-newlib --with-bugurl=https://github.com/dinuxbg/gnupru/issues --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 10.1.0 (GCC) 
configure:1876: $? = 0
configure:1865: pru-gcc -V >&5
pru-gcc: error: unrecognized command-line option '-V'
pru-gcc: fatal error: no input files
compilation terminated.
configure:1876: $? = 1
configure:1865: pru-gcc -qversion >&5
pru-gcc: error: unrecognized command-line option '-qversion'; did you mean '--version'?
pru-gcc: fatal error: no input files
compilation terminated.
configure:1876: $? = 1
configure:1896: checking whether the C compiler works
configure:1918: pru-gcc    conftest.c  >&5
configure:1922: $? = 0
configure:1970: result: yes
configure:1973: checking for C compiler default output file name
configure:1975: result: a.out
configure:1981: checking for suffix of executables
configure:1988: pru-gcc -o conftest    conftest.c  >&5
configure:1992: $? = 0
configure:2014: result: 
configure:2036: checking whether we are cross compiling
configure:2044: pru-gcc -o conftest    conftest.c  >&5
/home/vedant/pru-gcc/lib/gcc/pru/10.1.0/../../../../pru/bin/ld: conftest section `.text' will not fit in region `imem'
/home/vedant/pru-gcc/lib/gcc/pru/10.1.0/../../../../pru/bin/ld: region `imem' overflowed by 456 bytes
collect2: error: ld returned 1 exit status
configure:2048: $? = 1
configure:2055: ./conftest
./configure: line 2057: ./conftest: No such file or directory
configure:2059: $? = 127
configure:2066: error: in `/home/vedant/Programming/projects/simpPRU/generated_code':
configure:2068: error: cannot run C compiled programs.
If you meant to cross compile, use `--host'.
See `config.log' for more details

## ---------------- ##
## Cache variables. ##
## ---------------- ##

ac_cv_env_CC_set=
ac_cv_env_CC_value=
ac_cv_env_CFLAGS_set=
ac_cv_env_CFLAGS_value=
ac_cv_env_CPPFLAGS_set=
ac_cv_env_CPPFLAGS_value=
ac_cv_env_LDFLAGS_set=
ac_cv_env_LDFLAGS_value=
ac_cv_env_LIBS_set=
ac_cv_env_LIBS_value=
ac_cv_env_build_alias_set=
ac_cv_env_build_alias_value=
ac_cv_env_host_alias_set=
ac_cv_env_host_alias_value=
ac_cv_env_target_alias_set=
ac_cv_env_target_alias_value=
ac_cv_prog_ac_ct_CC=pru-gcc

## ----------------- ##
## Output variables. ##
## ----------------- ##

AR=''
CC='pru-gcc'
CFLAGS=''
CPPFLAGS=''
DEFS=''
ECHO_C=''
ECHO_N='-n'
ECHO_T=''
EXEEXT=''
LDFLAGS=''
LIBOBJS=''
LIBS=''
LTLIBOBJS=''
OBJEXT=''
PACKAGE_BUGREPORT='https://github.com/VedantParanjape/simppru/issues'
PACKAGE_NAME='libprurpmsg'
PACKAGE_STRING='libprurpmsg 1.0'
PACKAGE_TARNAME='libprurpmsg'
PACKAGE_URL=''
PACKAGE_VERSION='1.0'
PATH_SEPARATOR=':'
RANLIB=''
SHELL='/bin/bash'
ac_ct_AR=''
ac_ct_CC='pru-gcc'
bindir='${exec_prefix}/bin'
build_alias=''
datadir='${datarootdir}'
datarootdir='${prefix}/share'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
dvidir='${docdir}'
exec_prefix='NONE'
host_alias=''
htmldir='${docdir}'
includedir='${prefix}/include'
infodir='${datarootdir}/info'
libdir='${exec_prefix}/lib'
libexecdir='${exec_prefix}/libexec'
localedir='${datarootdir}/locale'
localstatedir='${prefix}/var'
mandir='${datarootdir}/man'
oldincludedir='/usr/include'
pdfdir='${docdir}'
prefix='/usr/local'
program_transform_name='s,x,x,'
psdir='${docdir}'
runstatedir='${localstatedir}/run'
sbindir='${exec_prefix}/sbin'
sharedstatedir='${prefix}/com'
sysconfdir='${prefix}/etc'
target_alias=''

## ----------- ##
## confdefs.h. ##
## ----------- ##

/* confdefs.h */
#define PACKAGE_NAME "libprurpmsg"
#define PACKAGE_TARNAME "libprurpmsg"
#define PACKAGE_VERSION "1.0"
#define PACKAGE_STRING "libprurpmsg 1.0"
#define PACKAGE_BUGREPORT "https://github.com/VedantParanjape/simppru/issues"
#define PACKAGE_URL ""

configure: exit 1

shift right pessimization

With this test case:

typedef unsigned char uint8_t;

extern void func2(uint8_t);

void func1(uint8_t v) {
    func2((v & 2) ? 1 : 0);
}

I see the following:

$ pru-gcc --version
pru-gcc (GCC) 7.0.0 20161219 (experimental)

$ pru-gcc -Wall -O2 -g -c test.c

$ pru-objdump -dr test.o

00000000 <func1>:
   0:   0504e2e2        sub     sp, sp, 4
   4:   240001ef        ldi     r15, 1
   8:   13000eee        mov     r14, r14.b0
   c:   e1002283        sbbo    ra.b0, sp, 0, 4
  10:   230000c3        call    0 <func1>
                        10: R_PRU_U16_PMEMIMM   __ashrsi3
  14:   1101eeee        and     r14, r14, 1
  18:   f1002283        lbbo    ra.b0, sp, 0, 4
  1c:   0104e2e2        add     sp, sp, 4
  20:   21000000        jmp     0 <func1>
                        20: R_PRU_U16_PMEMIMM   func2

gcc converts the "(v & 2) ? 1 : 0" code to a shift right operation,
but oddly chooses an arithmetic shift right.

I expected gcc to produce code with a QBBS instruction or a LSR
instruction. The call to __ashrsi3 is non-optimal and less efficient
than a straight forward translation of the original C code.

Interestingly, gcc produces code using LSR if the above C code is
changed to "!!(v & 2)" or if v is defined as an "unsigned int".

Registers R30 and R31 access

While the current method in pru/io.h for accessing R30 and R31 works well, I have had success using

register unsigned int __R30 asm ("r30");
register unsigned int __R31 asm ("r31");

instead. That way, __R30 and __R31 can be used like any other unsigned int variable from both C and C++ programs.

Use containers to build binary release tarballs

Fully automate the building of prebuilt toolchains for gnupru releases. Use podman containers in order to provide a stable and known host environment where to run crosstool-ng for a given release tag.

The following release tarballs must be produced:

  • Linux armhf debian buster
  • Linux amd64 debian buster
  • Linux arm64 debian buster (a nice to have)
  • Windows

Constructors are not called by CRT

Static/global constructors (attribute(constructor) in C) are not being called by CRT on start. Basic tests like gcc.dg/constructor-1.c fail.

The ELF parser from the example loader erroneously skips BSS section

BSS DMEM contents are not cleared by the example pruss_uio firmware loader.

The example pload.c loader should use the ELF Program Header Table instead of the ELF Section Header. The default linker scripts declare text, bss, data and ro.data sections that are moved into two text and data segments. The segments should be read when loading the firmware.

Simplify Debian packaging for PRU GCC toolchain

Current debian packaging rules on https://github.com/beagleboard/repos are derived from Debian's avr-gcc. The rules are rather complicated, and result in clashes (e.g. you can install either pru-gcc or avr-gcc, but not both).

pru-gcc could be packaged more easily if it is installed into a separate directory, and only create symbolic links for /usr/bin/pru-gcc and the rest of the tools' executables. See some initial ideas here: https://github.com/dinuxbg/repos/tree/wip-revamp-debian-rules

Unlike issue #20 which has an ambition to include pru-gcc into official Debian, this issue is smaller in scope and should be easier to implement.

Add linker relaxation support for PMEM DIFF relocations

The following code snippet will throw "expression too complex" error when relaxation is enabled:
.word %pmem(L1 - L2)
Note that with relaxation disabled, there is no issue.

Note: This causes GCC gcc.c-torture/execute/pr70460.c test case to fail.

Solution is to add PRU_32_PMEMDIFF and PRU_16_PMEMDIFF relocations.

help with program-memory-overflow

Hi @dinuxbg,

this is less a bugreport, more like a support question. We currently port our firmware and hoped GCC would produce more efficient code. It worked before for us, but one PRU-codebase is overflowing IMEM by 33 % while LTO and -Os is enabled. It fits and works when compiling it with CGT.

The project uses c99, no float, but u64-math on the overflowing PRU0. u64-math is also the reason we want to switch to GCC, as the CGT shows some flaws there.

We tried enabling -mabi=ti to get closer to CGT-behaviour (especially the smaller pointers), but the linker complained about undefined references to memcpy and memset (which our code-base does not directly use).

Do you have any hints how to solve or approach this?

I read through the gnupru github issues and large parts of the gcc documentation and even started comparing parts of the assembly from both compilers but found no hints yet.

BSS segment not cleared on firmware load

BSS segment is not cleared by the Linux kernel firmware loader.

Host: Linux BeagleBone 5.10.120-ti-arm64-r63 #1bullseye SMP Fri Sep 2 01:18:17 UTC 2022 aarch64 GNU/Linux

Cleanup the debian packages

The current debian packages were hastily prepared to allow easy pru-gcc installation from official Beagleboard images. While functional, the packages do not meet many requirements for inclusion into Debian mainline. At least the following fixes are needed:

  • Package PRU Simulator from an official GDB source tarball release.
  • Separate G++ and Newlib in their own packages. This may or may not be possible, or practical. Probably need to contact Debian Developer lists for help.
  • Switch to quilt 3.0 format?
  • Remove all lintian errors
  • Separate documentation in separate packages, to address Debian licensing concerns. This is not needed because Binutils and GCC provide decent online documentation.
  • Include packages into Debian mainline.

Implementation of PRU LMBD (Left-most bit detect) OPCODE

The documentation states that all the standard PRU core V3 opcodes (as implemented by the pasm assembler) were being implemented. Is there a strong reason why LMBD was not implemented? From the pasm source code, it appears to be clear that the LMBD instruction began to be implemented in the PRU core v1 and is still implemented in V3. I hand-coded the instruction into the PRU instruction memory to test whether this still works on the AM3358 of the Beaglebone Black, and yes, it is supported just fine on this PRU core.

Doing some preliminary changes (basedlined from the master branch at sourceware.org/git/binutils-gdb.git), it looks pretty simple to implement the LMBD instruction. Here is is the diff of my attempt:

gas-pru-lmbd-intruction.patch.gz

Or see patch from forked repository: olsonse/binutils-gdb@128fd3e

Best areas for helping with open source PRU development tools.

Hi,

I've been using the PRU in the BBB for awhile now. All in asm using the pasm tool. I'm interested in possibly helping here and just wanted to check first what would be good areas to contribute to.

Two areas that seem interesting is finishing gdb and cleaning up the debian packages. These are areas I can probably contribute to quite easily and I've been unable to find a working software debugger for the PRU on the web. I know TI does support hardware JTAG based debugging but it's a bit expensive and a software tool would be great as a first try debugging tool.

BTW, I am a bit curious of the purpose of GCC though. Most of the strength of the PRU is the single cycle execution, predictability, and specialization of the instruction set and that often requires writing in ASM to leverage.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.