Git Product home page Git Product logo

riscv-probe's Introduction

riscv-probe

Simple machine mode program to probe RISC-V control and status registers.

riscv-probe currently builds for Spike, QEMU and the SiFive E21 core. riscv-probe is a testing tool designed be used to compare CSRs (Control and Status Registers) between mutliple RISC-V simulators and RISC-V hardware implementations.

riscv-probe contains libfemto which is a lightweight bare-metal C library conforming to a reduced set ot the POSIX.1-2017 / IEEE 1003.1-2017 standard. libfemto can be used as a starting point for bare metal RISC-V programs that require interrupt handling, basic string routines and printf.

Dependencies

A recent version of riscv-tools with a multilib build of RISC-V GCC.

Build

The build system uses CROSS_COMPILE as the toolchain prefix and expects the toolchain to be present in the PATH environment variable. The default value for CROSS_COMPILE is riscv64-unknown-elf- however this can be overridden e.g. make CROSS_COMPILE=riscv64-unknown-linux-gnu-. The build system expects a multilib toolchain as it uses the same toolchain to build for riscv32 and riscv64. Make sure to use --enable-multilib when configuring riscv-gnu-toolchain. The examples are all built with -nostartfiles -nostdlib -nostdinc so either the RISC-V GCC Newlib toolchain or RISC-V GCC Glibc Linux toolchain can be used.

To build the examples after environent setup, type:

make

Invocation

To invoke the probe example in spike and RISC-V QEMU:

  • $ spike --isa=RV32IMAFDC build/bin/rv32imac/spike/probe
  • $ spike --isa=RV64IMAFDC build/bin/rv64imac/spike/probe
  • $ qemu-system-riscv32 -nographic -machine spike -kernel build/bin/rv32imac/spike/probe -bios none
  • $ qemu-system-riscv64 -nographic -machine spike -kernel build/bin/rv64imac/spike/probe -bios none
  • $ qemu-system-riscv32 -nographic -machine virt -kernel build/bin/rv32imac/virt/probe -bios none
  • $ qemu-system-riscv64 -nographic -machine virt -kernel build/bin/rv64imac/virt/probe -bios none
  • $ qemu-system-riscv32 -nographic -machine sifive_e -kernel build/bin/rv32imac/qemu-sifive_e/probe -bios none
  • $ qemu-system-riscv64 -nographic -machine sifive_e -kernel build/bin/rv64imac/qemu-sifive_e/probe -bios none
  • $ qemu-system-riscv32 -nographic -machine sifive_u -kernel build/bin/rv32imac/qemu-sifive_u/probe -bios none
  • $ qemu-system-riscv64 -nographic -machine sifive_u -kernel build/bin/rv64imac/qemu-sifive_u/probe -bios none

libfemto

libfemto is a lightweight bare-metal C library for embedded RISC-V development. libfemto provides:

  • Reduced set of the POSIX.1-2017 / IEEE 1003.1-2017 standard
  • Simple lightweight hardware configuration mechanism
  • RISC-V machine mode functions and macros
  • Console and power device drivers

libfemto implements a reduced set of the POSIX.1-2017 / IEEE 1003.1-2017 standard, with the addition of glibc's getauxval API to access hardware configuration in an auxiliary vector (__auxv) that contains tuples describing the target environment. The auxiliary vector is intended as a lightweight mechanism to pass dynamic configuration information on embedded targets, serving as an alternative to compile time constants used during hardware initialization. The auxiliary vector API has been repurposed to allow retrieval of hardware configuration parameters such as clock frequencies and device base addresses for use as a compact alternative to (DTB) Device Tree Binary, which is not available on small embedded targets.

libfemto contains the following device drivers:

  • HTIF (Host Target Interface)
  • NS16550A UART Console
  • SiFive UART Console
  • SiFive Test Device
  • Semihosting Syscalls

Environments

This project contains a simple build system that allows building applications targeting multiple embedded environments. A distinguishing characteristic of the build system is that program objects do not need to be recompiled to target a different environment, rather they are relinked with a different hardware configuration and setup function. The config object causes the correct drivers to be linked via compile time dependencies expressed by symbol references. The following environments are currently supported:

  • default - environment where IO defaults to ebreak
  • spike- the RISC-V ISA Simulator Golden Model
  • virt - the RISC-V VirtIO Virtual Machine
  • qemu-sifive_e - QEMU Functional Model of the SiFive E Series
  • qemu-sifive_u - QEMU Functional Model of the SiFive U Series
  • coreip-e2-arty - SiFive E2 CoreIP Arty A7 FPGA evaluation image

To create a new environment simply add a directory to env with two files:

  • default.lds - linker script describing the target's memory layout
  • config.c - environment specific configuration

The following is an example configuration from env/<boardname>/config.c showing the auxiliary vector used by getauxval via the setup function called by _start before entering main.

auxval_t __auxv[] = {
    { UART0_CLOCK_FREQ,         32000000   },
    { UART0_BAUD_RATE,          115200     },
    { SIFIVE_UART0_CTRL_ADDR,   0x20000000 },
    { SIFIVE_TEST_CTRL_ADDR,    0x4000     },
    { 0, 0 }
};

void setup()
{
    /*
     * clock setup code should be placed here and should modify the
     * uart clock speed before calling register_console, which calls
     * uart_init and reads the uart clock speed from the config array.
     */
    register_console(&console_sifive_uart);
    register_poweroff(&poweroff_sifive_test);
}

Examples

The build system automatically includes any directory added to examples which contains a rules.mk file.

hello

The following is the rules.mk file from the hello example:

$ cat examples/hello/rules.mk 
hello_objs = hello.o

and hello.c

$ cat examples/hello/hello.c 
#include <stdio.h>

int main(int argc, char **argv)
{
	printf("hello\n");
}

symbols

libfemto linker scripts define the following special symbols:

Symbol Value
_text_start start of .text section
_text_end end of .text section
_rodata_start start of .rodata section
_rodata_end end of .rodata section
_data_start start of .data section
_data_end end of .data section
_bss_start start of .bss section
_bss_end end of .bss section
_memory_start start of RAM
_memory_end end of RAM

The symbols example program shows how to access these special symbols. They can be used for example to locate data section in a flat image in ROM to copy into memory and to zero the bss section.

user

Simple example program that sets up PMP (Physical Memory Protection) to allow all memory accesses and then switches to U mode. The code to set up PMP to allow all memory access is pmp_allow_all() in machine.h. The code is derived from bbl.

Note: PMP is enabled by default on systems that implement it, so it is mandatory to include code to configure PMPs to allow memory access when switching from M mode to S mode or U mode, otherwise memory accesses will trap.

enclave

Simple enclave example using RISC-V PMP (Physical Memory Protection)

Physical memory protection is enabled for the program text (RX) program data (RW), UART, and the hart is switch to U mode, however, there is only one program and the default trap vector points into the executable text, so traps are handled in M mode, in the same executable text segment.

A future example will load a second process and provide ecall APIs to the process running in the protected enclave.

probe

riscv-probe is a utility that probes the Control and Status Register address space of a RISC-V emulator, FPGA or board:

qemu-system-riscv32

$ qemu-system-riscv32 -nographic -machine spike_v1.10 -kernel build/bin/rv32/spike/probe
isa: rv32imafdcsu
csr: fflags          illegal_instruction cause=0x00000002 mtval=0x00000000
csr: frm             illegal_instruction cause=0x00000002 mtval=0x00000000
csr: fcsr            illegal_instruction cause=0x00000002 mtval=0x00000000
csr: mcycle          0xdbfa9cbd
csr: minstret        0xdc03f6a4
csr: mcycleh         0x0007c452
csr: minstreth       0x0007c452
csr: cycle           0xdc1d7e08
csr: time            illegal_instruction cause=0x00000002 mtval=0x00000000
csr: instret         0xdc393bf6
csr: cycleh          0x0007c452
csr: timeh           illegal_instruction cause=0x00000002 mtval=0x00000000
csr: instreth        0x0007c452
csr: mvendorid       0x00000000
csr: marchid         0x00000000
csr: mimpid          0x00000000
csr: mhartid         0x00000000
csr: mstatus         0x00000000
csr: misa            0x4014112d
csr: medeleg         0x00000000
csr: mideleg         0x00000000
csr: mie             0x00000000
csr: mtvec           0x80000004
csr: mcounteren      0x00000000
csr: mscratch        0x00000000
csr: mepc            0x800002a4
csr: mcause          0x00000002
csr: mtval           0x00000000
csr: mip             0x00000000
csr: sstatus         0x00000000
csr: sedeleg         illegal_instruction cause=0x00000002 mtval=0x00000000
csr: sideleg         illegal_instruction cause=0x00000002 mtval=0x00000000
csr: sie             0x00000000
csr: stvec           0x00000000
csr: scounteren      0x00000000
csr: sscratch        0x00000000
csr: sepc            0x00000000
csr: scause          0x00000000
csr: stval           0x00000000
csr: sip             0x00000000
csr: satp            0x00000000
csr: pmpcfg0         0x00000000
csr: pmpcfg1         0x00000000
csr: pmpcfg2         0x00000000
csr: pmpcfg3         0x00000000
csr: pmpaddr0        0x00000000
csr: pmpaddr1        0x00000000
csr: pmpaddr2        0x00000000
csr: pmpaddr3        0x00000000
csr: pmpaddr4        0x00000000
csr: pmpaddr5        0x00000000
csr: pmpaddr6        0x00000000
csr: pmpaddr7        0x00000000
csr: pmpaddr8        0x00000000
csr: pmpaddr9        0x00000000
csr: pmpaddr10       0x00000000
csr: pmpaddr11       0x00000000
csr: pmpaddr12       0x00000000
csr: pmpaddr13       0x00000000
csr: pmpaddr14       0x00000000
csr: pmpaddr15       0x00000000

qemu-system-riscv64

$ qemu-system-riscv64 -nographic -machine spike_v1.10 -kernel build/bin/rv64/spike/probe
isa: rv64imafdcsu
csr: fflags          illegal_instruction cause=0x00000002 mtval=0x00000000
csr: frm             illegal_instruction cause=0x00000002 mtval=0x00000000
csr: fcsr            illegal_instruction cause=0x00000002 mtval=0x00000000
csr: mcycle          0x0007c452dfeeddd3
csr: minstret        0x0007c452dff8a765
csr: mcycleh         illegal_instruction cause=0x00000002 mtval=0x00000000
csr: minstreth       illegal_instruction cause=0x00000002 mtval=0x00000000
csr: cycle           0x0007c452e01f105f
csr: time            illegal_instruction cause=0x00000002 mtval=0x00000000
csr: instret         0x0007c452e03d0a50
csr: cycleh          illegal_instruction cause=0x00000002 mtval=0x00000000
csr: timeh           illegal_instruction cause=0x00000002 mtval=0x00000000
csr: instreth        illegal_instruction cause=0x00000002 mtval=0x00000000
csr: mvendorid       0x0000000000000000
csr: marchid         0x0000000000000000
csr: mimpid          0x0000000000000000
csr: mhartid         0x0000000000000000
csr: mstatus         0x0000000000000000
csr: misa            0x800000000014112d
csr: medeleg         0x0000000000000000
csr: mideleg         0x0000000000000000
csr: mie             0x0000000000000000
csr: mtvec           0x0000000080000004
csr: mcounteren      0x0000000000000000
csr: mscratch        0x0000000000000000
csr: mepc            0x00000000800002f4
csr: mcause          0x0000000000000002
csr: mtval           0x0000000000000000
csr: mip             0x0000000000000000
csr: sstatus         0x0000000000000000
csr: sedeleg         illegal_instruction cause=0x00000002 mtval=0x00000000
csr: sideleg         illegal_instruction cause=0x00000002 mtval=0x00000000
csr: sie             0x0000000000000000
csr: stvec           0x0000000000000000
csr: scounteren      0x0000000000000000
csr: sscratch        0x0000000000000000
csr: sepc            0x0000000000000000
csr: scause          0x0000000000000000
csr: stval           0x0000000000000000
csr: sip             0x0000000000000000
csr: satp            0x0000000000000000
csr: pmpcfg0         0x0000000000000000
csr: pmpcfg1         0x0000000000000000
csr: pmpcfg2         0x0000000000000000
csr: pmpcfg3         0x0000000000000000
csr: pmpaddr0        0x0000000000000000
csr: pmpaddr1        0x0000000000000000
csr: pmpaddr2        0x0000000000000000
csr: pmpaddr3        0x0000000000000000
csr: pmpaddr4        0x0000000000000000
csr: pmpaddr5        0x0000000000000000
csr: pmpaddr6        0x0000000000000000
csr: pmpaddr7        0x0000000000000000
csr: pmpaddr8        0x0000000000000000
csr: pmpaddr9        0x0000000000000000
csr: pmpaddr10       0x0000000000000000
csr: pmpaddr11       0x0000000000000000
csr: pmpaddr12       0x0000000000000000
csr: pmpaddr13       0x0000000000000000
csr: pmpaddr14       0x0000000000000000
csr: pmpaddr15       0x0000000000000000

riscv-probe's People

Contributors

alistair23 avatar michaeljclark avatar vppillai 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

riscv-probe's Issues

Not able to run the examples with spike to probe the csr

I am trying to use the riscv-probe with spike simulator. I cloned riscv-probe and then ran the make command, to generate object files.
Then I ran the command

$ spike --isa=RV64IMAFDC build/bin/rv64imac/spike/probe
isa: rv64imafdcsu
csr: fflags          illegal_instruction cause=2 mtval=0x0000000000000000
csr: frm             illegal_instruction cause=2 mtval=0x0000000000000000
csr: fcsr            illegal_instruction cause=2 mtval=0x0000000000000000
csr: mcycle          0x0000000000123d27
csr: minstret        0x0000000000154a64
csr: mcycleh         illegal_instruction cause=2 mtval=0x0000000000000000
csr: minstreth       illegal_instruction cause=2 mtval=0x0000000000000000
csr: cycle           0x0000000000237bbf
csr: time            illegal_instruction cause=2 mtval=0x0000000000000000
csr: instret         0x00000000002c1b12
csr: cycleh          illegal_instruction cause=2 mtval=0x0000000000000000
csr: timeh           illegal_instruction cause=2 mtval=0x0000000000000000
csr: instreth        illegal_instruction cause=2 mtval=0x0000000000000000
csr: mvendorid       0x0000000000000000
csr: marchid         0x0000000000000005
csr: mimpid          0x0000000000000000
csr: mhartid         0x0000000000000000
csr: mstatus         0x0000000a00000080
csr: misa            0x800000000014112d
csr: medeleg         0x0000000000000000
csr: mideleg         0x0000000000000000
csr: mie             0x0000000000000000
csr: mtvec           0x000000008000002c
csr: mcounteren      0x0000000000000000
csr: mscratch        0x0000000000000000
csr: mepc            0x00000000800002c4
csr: mcause          0x0000000000000002
csr: mtval           0x0000000000000000
csr: mip             0x0000000000000080
csr: sstatus         0x0000000200000000
csr: sedeleg         illegal_instruction cause=2 mtval=0x0000000000000000
csr: sideleg         illegal_instruction cause=2 mtval=0x0000000000000000
csr: sie             0x0000000000000000
csr: stvec           0x0000000000000000
csr: scounteren      0x0000000000000000
csr: sscratch        0x0000000000000000
csr: sepc            0x0000000000000000
csr: scause          0x0000000000000000
csr: stval           0x0000000000000000
csr: sip             0x0000000000000000
csr: satp            0x0000000000000000
csr: pmpcfg0         0x000000000000001f
csr: pmpcfg1         illegal_instruction cause=2 mtval=0x0000000000000000
csr: pmpcfg2         0x0000000000000000
csr: pmpcfg3         illegal_instruction cause=2 mtval=0x0000000000000000
csr: pmpaddr0        0xffffffffffffffff
csr: pmpaddr1        0x0000000000000000
csr: pmpaddr2        0x0000000000000000
csr: pmpaddr3        0x0000000000000000
csr: pmpaddr4        0x0000000000000000
csr: pmpaddr5        0x0000000000000000
csr: pmpaddr6        0x0000000000000000
csr: pmpaddr7        0x0000000000000000
csr: pmpaddr8        0x0000000000000000
csr: pmpaddr9        0x0000000000000000
csr: pmpaddr10       0x0000000000000000
csr: pmpaddr11       0x0000000000000000
csr: pmpaddr12       0x0000000000000000
csr: pmpaddr13       0x0000000000000000
csr: pmpaddr14       0x0000000000000000
csr: pmpaddr15       0x0000000000000000

Succesfully getting all the CSR, but I wasn't able to run any of the examples, since I am new to spike simulator I couldn't find steps or commands in your documentation to run any of your examples.

Still I tried running the examples as,
1)

 $ spike build/obj/rv64imac/examples/hello/hello.o 
warning: tohost and fromhost symbols not in ELF; can't communicate with target
$ spike  build/obj/rv64imac/examples/hello/hello.o 
warning: tohost and fromhost symbols not in ELF; can't communicate with target

$ spike $(which pk)  build/obj/rv64imac/examples/hello/hello.o --isa=RV64IMAFDC build/bin/rv64imac/spike/probe 
z  0000000000000000 ra 0000000000000000 sp 000000007f7e9af0 gp 0000000000000000
tp 0000000000000000 t0 0000000000000000 t1 0000000000000000 t2 0000000000000000
s0 0000000000000000 s1 0000000000000000 a0 0000000000000000 a1 0000000000000000
a2 0000000000000000 a3 0000000000000000 a4 0000000000000000 a5 0000000000000000
a6 0000000000000000 a7 0000000000000000 s2 0000000000000000 s3 0000000000000000
s4 0000000000000000 s5 0000000000000000 s6 0000000000000000 s7 0000000000000000
s8 0000000000000000 s9 0000000000000000 sA 0000000000000000 sB 0000000000000000
t3 0000000000000000 t4 0000000000000000 t5 0000000000000000 t6 0000000000000000
pc 0000000000000000 va 0000000000000000 insn       ffffffff sr 8000000200046020
User fetch segfault @ 0x0000000000000000

Unfortunately I am not able to run any of your example code's object file using spike or even with spike-pk It would be great if you could help me out, in running the riscv-probe properly, since my application requires to run and probe the CSR registers.
It would be also great if you could include it in README file, for everyone to use.

SiFive Unleashed U5 hardware support

I'm trying to get some baremetal code running on the SiFive Unleashed board, enough to provide some two-way communication over the virtual comm serial port (sifive UART) with printf/getchar function calls.

I have been trying to compare the differences between the hardware E2 core and the qemu E2 core folders to try and see if I can adopt the qemu U5 core to work on the actual unleashed board U5 hardware, but I just can't see to get it working. Looking in the memory layout of the E2 hardware default.lds I see,

flash (rxai!w) : ORIGIN = 0x40400000, LENGTH = 128M
ram   (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 64K

I have tried changing it to:

ram   (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M
flash (rxai!w) : ORIGIN = 0x10000, LENGTH = 64M

but no luck. any idea on how I could get my code which is working on the qemu simulation of U5 to work on actual hardware? There already is E2 qemu to hardware parity, so I must be missing something very small.

Unable to build the project

I was trying the project, but was unable to build using the latest toolchain version.

/opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/bin/ld: build/lib/rv32imac/libfemto.a(trap.o):(.data.riscv_intr_names+0x0): multiple definition of `riscv_intr_names'; build/lib/rv32imac/libfemto.a(memory.o):(.bss.riscv_intr_names+0x0): first defined here
/opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/bin/ld: build/lib/rv32imac/libfemto.a(trap.o):(.data.riscv_excp_names+0x0): multiple definition of `riscv_excp_names'; build/lib/rv32imac/libfemto.a(memory.o):(.bss.riscv_excp_names+0x0): first defined here
collect2: error: ld returned 1 exit status
Makefile:126: recipe for target 'build/bin/rv32imac/default/memory' failed
make: *** [build/bin/rv32imac/default/memory] Error 1

My GCC version is:

$ riscv64-unknown-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=riscv64-unknown-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/opt/riscv/libexec/gcc/riscv64-unknown-linux-gnu/10.2.0/lto-wrapper
Target: riscv64-unknown-linux-gnu
Configured with: /home/nxf45729/riscv-gnu-toolchain/riscv-gcc/configure --target=riscv64-unknown-linux-gnu --prefix=/opt/riscv --with-sysroot=/opt/riscv/sysroot --with-system-zlib --enable-shared --enable-tls --enable-languages=c,c++,fortran --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libsanitizer --disable-nls --disable-bootstrap --src=.././riscv-gcc --enable-multilib --with-abi=lp64d --with-arch=rv64imafdc --with-tune=rocket 'CFLAGS_FOR_TARGET=-O2   -mcmodel=medlow' 'CXXFLAGS_FOR_TARGET=-O2   -mcmodel=medlow'
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (GCC)

Thanks

missing puts and question on csr_enum_array

I am new to RISCV but hope to work with it a lot more in the future. I am trying to learn
the tools and build environment. I am using Ubuntu 18 64-bit on Intel as a test platform
(and soon to try with Fedora 28).

As a test, I copied riscv-probe and made a very simple main. It failed to build because
puts was not defined (I guess printf("string") gets converted to puts("string"). I added:
int puts(const char *s) {
putstring(s);
}

This built, but failed to run. I needed to include csr_enum_array():
qemu-system-riscv32 -nographic -machine spike_v1.10 -kernel build/bin/rv32/test2-spike
qemu-system-riscv32: Trying to execute code outside RAM or ROM at 0x80000000
This usually means one of the following happened:....

By defining puts and the csr_enum_array() my simple hello world program worked.

#include "femto.h"
int main()
{
int *csrenum = csr_enum_array();
putstring("Test123\n");
printf("Hello World\n");
printf("\n");
}

How to achieve get_time() without reading time CSR

1ใ€I want to implement video_write function, but I can't find the pointer to framebuffer. I have read wiki and manual carefully, but I fail to find the answer. Maybe I missed something critical. So, where is the framebuffer, or which document should I seek for it.
2ใ€I use the getchar function in your riscv-probe repo. But I found that some key can't be captured, such as F1, CapsLock, etc. I see that only tohost and fromhost are used in the communication between user and device. So far I have not realized how they work. In order to capture other keys, how could I do?

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.