forked from M-Labs/artiq
1
0
Fork 0
artiq/soc/runtime/main.c

238 lines
4.3 KiB
C
Raw Normal View History

2014-07-04 23:49:08 +08:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2014-07-07 03:06:53 +08:00
#include <stdarg.h>
2014-07-24 09:12:22 +08:00
#include <crc.h>
2014-07-04 23:49:08 +08:00
#include <irq.h>
#include <uart.h>
#include <console.h>
#include <system.h>
2014-07-24 01:49:48 +08:00
#include <hw/common.h>
2014-07-04 23:49:08 +08:00
#include <generated/csr.h>
#include "elf_loader.h"
2014-07-08 01:13:43 +08:00
enum {
MSGTYPE_REQUEST_IDENT = 0x01,
MSGTYPE_LOAD_KERNEL = 0x02,
MSGTYPE_KERNEL_FINISHED = 0x03,
MSGTYPE_RPC_REQUEST = 0x04,
2014-07-08 01:13:43 +08:00
};
static int receive_int(void)
{
unsigned int r;
int i;
r = 0;
for(i=0;i<4;i++) {
r <<= 8;
r |= (unsigned char)uart_read();
}
return r;
}
static char receive_char(void)
{
return uart_read();
}
static void send_int(int x)
{
int i;
for(i=0;i<4;i++) {
uart_write((x & 0xff000000) >> 24);
x <<= 8;
}
}
static void send_sint(short int i)
{
uart_write((i >> 8) & 0xff);
uart_write(i & 0xff);
}
static void send_char(char c)
{
uart_write(c);
}
2014-07-04 23:49:08 +08:00
static void receive_sync(void)
{
char c;
int recognized;
recognized = 0;
2014-07-08 01:13:43 +08:00
while(recognized < 4) {
c = uart_read();
if(c == 0x5a)
2014-07-04 23:49:08 +08:00
recognized++;
2014-07-08 01:13:43 +08:00
else
2014-07-04 23:49:08 +08:00
recognized = 0;
}
}
2014-07-08 01:13:43 +08:00
static void send_sync(void)
2014-07-04 23:49:08 +08:00
{
2014-07-08 01:13:43 +08:00
send_int(0x5a5a5a5a);
2014-07-04 23:49:08 +08:00
}
static int ident_and_download_kernel(void *buffer, int maxlength)
2014-07-04 23:49:08 +08:00
{
int length;
2014-07-24 09:12:22 +08:00
unsigned int crc;
2014-07-04 23:49:08 +08:00
int i;
char msgtype;
2014-07-04 23:49:08 +08:00
unsigned char *_buffer = buffer;
while(1) {
receive_sync();
msgtype = receive_char();
if(msgtype == MSGTYPE_REQUEST_IDENT) {
send_int(0x41524f52); /* "AROR" - ARTIQ runtime on OpenRISC */
send_int(1000000000000LL/identifier_frequency_read()); /* RTIO clock period in picoseconds */
} else if(msgtype == MSGTYPE_LOAD_KERNEL) {
length = receive_int();
2014-07-24 09:12:22 +08:00
if(length > maxlength) {
send_char(0x4c); /* Incorrect length */
return -1;
2014-07-24 09:12:22 +08:00
}
crc = receive_int();
for(i=0;i<length;i++)
_buffer[i] = receive_char();
2014-07-24 09:12:22 +08:00
if(crc32(buffer, length) != crc) {
send_char(0x43); /* CRC failed */
return -1;
}
send_char(0x4f); /* kernel reception OK */
return length;
} else
return -1;
}
2014-07-04 23:49:08 +08:00
}
2014-07-07 03:06:53 +08:00
static int rpc(int rpc_num, int n_args, ...)
{
2014-07-08 01:13:43 +08:00
send_sync();
send_char(MSGTYPE_RPC_REQUEST);
send_sint(rpc_num);
send_char(n_args);
2014-07-07 03:06:53 +08:00
va_list args;
va_start(args, n_args);
while(n_args--)
2014-07-08 01:13:43 +08:00
send_int(va_arg(args, int));
2014-07-07 03:06:53 +08:00
va_end(args);
2014-07-08 01:13:43 +08:00
return receive_int();
}
2014-07-21 08:28:56 +08:00
static void gpio_set(int channel, int value)
2014-07-06 04:46:43 +08:00
{
2014-07-23 00:45:59 +08:00
static int csr_value;
if(value)
csr_value |= 1 << channel;
else
csr_value &= ~(1 << channel);
leds_out_write(csr_value);
2014-07-21 08:28:56 +08:00
}
static void rtio_set(long long int timestamp, int channel, int value)
2014-07-21 08:28:56 +08:00
{
rtio_reset_write(0);
2014-07-21 08:28:56 +08:00
rtio_chan_sel_write(channel);
rtio_o_timestamp_write(timestamp);
rtio_o_value_write(value);
while(!rtio_o_writable_read());
rtio_o_we_write(1);
2014-07-06 04:46:43 +08:00
}
2014-07-23 01:36:54 +08:00
static void rtio_sync(int channel)
{
rtio_chan_sel_write(channel);
while(rtio_o_level_read() != 0);
}
2014-07-24 07:10:49 +08:00
#define DDS_FTW0 0x0a
#define DDS_FTW1 0x0b
#define DDS_FTW2 0x0c
#define DDS_FTW3 0x0d
2014-07-24 01:49:48 +08:00
#define DDS_FUD 0x40
#define DDS_GPIO 0x41
2014-07-24 07:10:49 +08:00
#define DDS_READ(addr) \
MMPTR(0xb0000000 + (addr)*4)
2014-07-24 01:49:48 +08:00
2014-07-24 07:10:49 +08:00
#define DDS_WRITE(addr, data) \
MMPTR(0xb0000000 + (addr)*4) = data
2014-07-24 01:49:48 +08:00
static void dds_program(int channel, int ftw)
{
2014-07-24 07:10:49 +08:00
DDS_WRITE(DDS_GPIO, channel);
DDS_WRITE(DDS_FTW0, ftw & 0xff);
DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff);
DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff);
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
DDS_WRITE(DDS_FUD, 0);
2014-07-24 01:49:48 +08:00
}
static const struct symbol syscalls[] = {
2014-07-07 03:06:53 +08:00
{"__syscall_rpc", rpc},
2014-07-06 04:46:43 +08:00
{"__syscall_gpio_set", gpio_set},
2014-07-21 08:28:56 +08:00
{"__syscall_rtio_set", rtio_set},
2014-07-23 01:36:54 +08:00
{"__syscall_rtio_sync", rtio_sync},
2014-07-24 01:49:48 +08:00
{"__syscall_dds_program", dds_program},
{NULL, NULL}
};
2014-07-24 07:10:49 +08:00
static void dds_init(void)
{
int i;
DDS_WRITE(DDS_GPIO, 1 << 7);
for(i=0;i<8;i++) {
DDS_WRITE(DDS_GPIO, i);
DDS_WRITE(0x00, 0x78);
DDS_WRITE(0x01, 0x00);
DDS_WRITE(0x02, 0x00);
DDS_WRITE(0x03, 0x00);
DDS_WRITE(DDS_FUD, 0);
}
}
2014-07-06 04:47:23 +08:00
typedef void (*kernel_function)(void);
2014-07-04 23:49:08 +08:00
int main(void)
{
unsigned char kbuf[256*1024];
unsigned char kcode[256*1024];
kernel_function k = (kernel_function)kcode;
int length;
irq_setmask(0);
irq_setie(1);
uart_init();
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
2014-07-21 08:28:56 +08:00
2014-07-04 23:49:08 +08:00
while(1) {
length = ident_and_download_kernel(kbuf, sizeof(kbuf));
2014-07-04 23:49:08 +08:00
if(length > 0) {
2014-07-08 01:13:43 +08:00
if(load_elf(syscalls, kbuf, length, kcode, sizeof(kcode))) {
flush_cpu_icache();
2014-07-24 07:10:49 +08:00
dds_init();
2014-07-08 01:13:43 +08:00
k();
2014-07-21 08:28:56 +08:00
rtio_reset_write(1);
2014-07-08 01:13:43 +08:00
send_sync();
send_char(MSGTYPE_KERNEL_FINISHED);
}
2014-07-04 23:49:08 +08:00
}
}
return 0;
}