Commit 08a5df59 authored by Tristan Gingold's avatar Tristan Gingold

Remove sw/ directory in testbench, use what is in software.

parent caa41a3d
/*
* This work is part of the White Rabbit project
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if (argc < 2)
return -1;
FILE *f = fopen(argv[1], "rb");
if (!f)
return -1;
unsigned char x[4];
int i = 0;
fseek(f, 0, SEEK_END);
int n = (ftell(f) + 3) / 4;
rewind(f);
printf("Argc: %d\n", argc);
if(argc > 2)
n = atoi(argv[2]);
while (!feof(f)) {
fread(x, 1, 4, f);
printf("write %x %02X%02X%02X%02X\n", i++, x[0], x[1], x[2],
x[3]);
}
for (; i < n;) {
printf("write %x %02X%02X%02X%02X\n", i++, 0, 0, 0, 0);
}
fclose(f);
return 0;
}
#include "rt.h"
#include "list-common.h"
#define LOOP_QUEUE_SIZE 16
static SMEM int head, tail, count;
static SMEM struct list_trigger_entry buf[16];
void loop_queue_init()
{
head = tail = count = 0;
}
void loop_queue_push(struct list_id *id, uint32_t seq, struct list_timestamp *ts)
{
if(count == LOOP_QUEUE_SIZE)
return;
buf[head].id = *id;
buf[head].seq = seq;
buf[head].ts = *ts;
head++;
if(head == LOOP_QUEUE_SIZE)
head = 0;
count++;
}
struct list_trigger_entry *loop_queue_pop()
{
if(!count)
return NULL;
struct list_trigger_entry *rv = &buf[tail];
tail++;
if(tail == LOOP_QUEUE_SIZE)
tail = 0;
count--;
return rv;
}
\ No newline at end of file
#ifndef __LOOP_QUEUE_H
#define __LOOP_QUEUE_H
#include "rt.h"
#include "list-common.h"
#define LOOP_QUEUE_SIZE 16
void loop_queue_init();
void loop_queue_push(struct list_id *id, uint32_t seq, struct list_timestamp *ts);
struct list_trigger_entry *loop_queue_pop();
#endif
/*
* Basic printf based on vprintf based on vsprintf
*
* Alessandro Rubini for CERN, 2011 -- public domain
* (please note that the vsprintf is not public domain but GPL)
*/
#include <stdarg.h>
#include <pp-printf.h>
static char print_buf[CONFIG_PRINT_BUFSIZE];
int pp_vprintf(const char *fmt, va_list args)
{
int ret;
ret = pp_vsprintf(print_buf, fmt, args);
puts(print_buf);
return ret;
}
int pp_sprintf(char *s, const char *fmt, ...)
{
va_list args;
int ret;
va_start(args, fmt);
ret = pp_vsprintf(s, fmt, args);
va_end(args);
return ret;
}
int pp_printf(const char *fmt, ...)
{
va_list args;
int ret;
va_start(args, fmt);
ret = pp_vprintf(fmt, args);
va_end(args);
return ret;
}
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* White Rabbit Node Core
*
* rt-common.c: common RT CPU functions
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "rt-mqueue.h"
#include "rt-common.h"
int puts(const char *p)
{
char c;
int i = 0;
while (c = *(p++)) {
lr_writel(c, MT_CPU_LR_REG_DBG_CHR);
++i;
}
return i;
}
.section .boot, "ax", @progbits
.global _start
_start:
j _entry
.org 0x8
.extern trap_entry
_exception_entry:
j trap_entry
_entry:
la gp, _gp # Initialize global pointer
la sp, _fstack
la t0, _fexception_stack
csrrw t0, mscratch, t0
# clear the bss segment
la t0, _fbss
la t1, _end
1:
#ifdef __riscv64
sd zero,0(t0)
addi t0, t0, 8
#else
sw zero,0(t0)
addi t0, t0, 4
#endif
bltu t0, t1, 1b
li t3,0x1000
call main
#include <stdint.h>
struct rv_trap_context {
uint32_t r[32];
uint32_t mstatus;
uint32_t mepc;
uint32_t mbadaddr;
uint32_t mcause;
};
void undefined_insn_handler( struct rv_trap_context *ctx )
{
uint32_t insn = *(volatile uint32_t *)( ctx->mepc );
ctx->r[0] = 0;
uint32_t rs1 = ctx->r[(insn >> 15) & 0x1f];
uint32_t rs2 = ctx->r[(insn >> 20) & 0x1f];
uint32_t rdi = (insn >> 7) & 0x1f;
// we support MUL natively
if ( (insn & 0xfe00707f) == 0x2001033 ) // MULH
ctx->r[rdi] = ( (int64_t)(int32_t)rs1 * (int64_t)(int32_t) rs2) >> 32;
else if ( (insn & 0xfe00707f) == 0x2002033 ) // MULHSU
ctx->r[rdi] = ((int64_t)(int32_t)rs1 * (uint64_t) rs2) >> 32;
else if ( (insn & 0xfe00707f) == 0x2003033 ) // MULHU
ctx->r[rdi] = ((uint64_t) rs1 * (uint64_t) rs2) >> 32;
else if ( (insn & 0xfe00707f) == 0x2004033 ) // DIV
ctx->r[rdi] = (int32_t)rs1 / (int32_t) rs2;
else if ( (insn & 0xfe00707f) == 0x2005033 ) // DIVU
ctx->r[rdi] = (uint32_t)rs1 / (uint32_t) rs2;
else if ( (insn & 0xfe00707f) == 0x2006033 ) // REM
ctx->r[rdi] = (int32_t)rs1 % (int32_t) rs2;
else if ( (insn & 0xfe00707f) == 0x2007033 ) // REMU
ctx->r[rdi] = (uint32_t)rs1 % (uint32_t) rs2;
ctx->mepc += 4;
asm volatile ("csrc mip, 0x4"); // clear exception
}
\ No newline at end of file
.section .text
.global trap_entry
trap_entry:
csrrw sp,mscratch,sp
addi sp,sp,-320
sw ra,4(sp)
sw gp,12(sp)
sw tp,16(sp)
sw t0,20(sp)
sw t1,24(sp)
sw t2,28(sp)
sw s0,32(sp)
sw s1,36(sp)
sw a0,40(sp)
sw a1,44(sp)
sw a2,48(sp)
sw a3,52(sp)
sw a4,56(sp)
sw a5,60(sp)
sw a6,64(sp)
sw a7,68(sp)
sw s2,72(sp)
sw s3,76(sp)
sw s4,80(sp)
sw s5,84(sp)
sw s6,88(sp)
sw s7,92(sp)
sw s8,96(sp)
sw s9,100(sp)
sw s10,104(sp)
sw s11,108(sp)
sw t3,112(sp)
sw t4,116(sp)
sw t5,120(sp)
sw t6,124(sp)
csrr t0,mscratch
csrr s0,mstatus
csrr t1,mepc
csrr t2,mbadaddr
csrr t3,mcause
sw t0,8(sp)
sw s0,128(sp)
sw t1,132(sp)
sw t2,136(sp)
sw t3,140(sp)
li t0,-1
sw t0,144(sp)
mv a0,sp
la t0, jump_table
sll t3, t3, 2
add t0, t0, t3
lw t0, 0(t0)
la ra, jump_table_return
jr t0
jump_table:
.word undefined_handler
.word undefined_handler
.word undefined_insn_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
.word undefined_handler
jump_table_return:
mv a0,sp
lw t1,128(a0)
lw t2,132(a0)
addi sp,sp,320
csrw mscratch,sp
csrw mepc,t2
lw ra,4(a0)
lw sp,8(a0)
lw gp,12(a0)
lw tp,16(a0)
lw t0,20(a0)
lw t1,24(a0)
lw t2,28(a0)
lw s0,32(a0)
lw s1,36(a0)
lw a1,44(a0)
lw a2,48(a0)
lw a3,52(a0)
lw a4,56(a0)
lw a5,60(a0)
lw a6,64(a0)
lw a7,68(a0)
lw s2,72(a0)
lw s3,76(a0)
lw s4,80(a0)
lw s5,84(a0)
lw s6,88(a0)
lw s7,92(a0)
lw s8,96(a0)
lw s9,100(a0)
lw s10,104(a0)
lw s11,108(a0)
lw t3,112(a0)
lw t4,116(a0)
lw t5,120(a0)
lw t6,124(a0)
lw a0,40(a0)
mret
.weak undefined_handler
undefined_handler:
j undefined_handler
.weak undefined_insn_handler
undefined_insn_handler:
j undefined_insn_handler
OUTPUT_FORMAT("elf32-littleriscv")
ENTRY(_start)
MEMORY
{
ram :
ORIGIN = 0x00000000,
LENGTH = 32768 - 2048
stack :
ORIGIN = 32768 - 2048,
LENGTH = 2048
smem :
ORIGIN = 0x40200000,
LENGTH = 65536
}
SECTIONS
{
/*--------------------------------------------------------------------*/
/* Code and read-only segment */
/*--------------------------------------------------------------------*/
/* Begining of code and text segment */
. = 0x00000000;
_ftext = .;
PROVIDE( eprol = . );
/* text: Program code section */
.text :
{
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
} > ram
/* init: Code to execute before main (called by crt0.S) */
.init :
{
KEEP( *(.init) )
} > ram
/* fini: Code to execute after main (called by crt0.S) */
.fini :
{
KEEP( *(.fini) )
} > ram
/* rodata: Read-only data */
.rodata :
{
*(.rdata)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
} > ram
/* End of code and read-only segment */
PROVIDE( etext = . );
_etext = .;
/*--------------------------------------------------------------------*/
/* Global constructor/destructor segement */
/*--------------------------------------------------------------------*/
/* The .ctors/.dtors sections are special sections which contain a
list of constructor/destructor function pointers. crtbegin.o
includes code in a .init section which goes through the .ctors list
and calls each constuctor. crtend.o includes code in a .fini
section which goes through the .dtors list and calls each
destructor. crtbegin.o includes a special null pointer in its own
.ctors/.dtors sections which acts as a start indicator for those
lists. crtend.o also includes a special null pointer in its own
.ctors/.dtors sections which acts as an end indictor. The linker
commands below are setup so that crtbegin.o's .ctors/.dtors
sections are always first and crtend.o's .ctors/.dtors sections are
always last. This is the only way the list of functions will have
the begin and end indicators in the right place. */
/* ctors : Array of global constructor function pointers */
/*--------------------------------------------------------------------*/
/* Initialized data segment */
/*--------------------------------------------------------------------*/
/* Start of initialized data segment */
. = ALIGN(16);
_fdata = .;
/* data: Writable data */
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
} > ram
/* End of initialized data segment */
PROVIDE( edata = . );
_edata = .;
/* Have _gp point to middle of sdata/sbss to maximize displacement range */
. = ALIGN(16);
_gp = . + 0x800;
/* Writable small data segment */
.sdata :
{
*(.sdata)
*(.sdata.*)
*(.srodata.*)
*(.gnu.linkonce.s.*)
} > ram
/*--------------------------------------------------------------------*/
/* Uninitialized data segment */
/*--------------------------------------------------------------------*/
/* Start of uninitialized data segment */
. = ALIGN(8);
_fbss = .;
/* Writable uninitialized small data segment */
.sbss :
{
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
} > ram
/* bss: Uninitialized writeable data section */
. = .;
_bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
} > ram
/* End of uninitialized data segment (used by syscalls.c for heap) */
PROVIDE( end = . );
_end = ALIGN(8);
.smem : { *(.smem) } > smem
PROVIDE(_endram = ORIGIN(stack));
PROVIDE(_fexception_stack = ORIGIN(stack) + LENGTH(stack) - 4);
PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4 - 0x400 );
}
# and don't touch the rest unless you know what you're doing.
CROSS_COMPILE ?= riscv32-elf-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
INC_CFLAGS=-I../common -I../include/ -I../../../../software/include
CFLAGS = -DWRNODE_RT -g -O2 -march=rv32im -mabi=ilp32 $(INC_CFLAGS)
OBJS += ../common/urv/crt0.o ../common/urv/irq.o ../common/urv/emulate.o ../common/rt-common.o ../common/printf.o ../common/vsprintf-xint.o
LDSCRIPT = ../common/urv/mt.ld
$(OUTPUT): $(LDSCRIPT) $(OBJS)
${CC} $(CFLAGS) -o $(OUTPUT).elf -nostartfiles $(OBJS) -T $(LDSCRIPT) -lgcc -lc
${OBJCOPY} --remove-section .smem -O binary $(OUTPUT).elf $(OUTPUT).bin
../common/urv/emulate.o: ../common/urv/emulate.c
${CC} $(CFLAGS) -march=rv32i -c $^ -o $@ -I.
%.o: %.S
${CC} $(CFLAGS) -c $^ -o $@
clean:
rm -f $(OBJS) $(OUTPUT).bin
install:
cp $(OUTPUT).bin /acc/local/share/firmware/list
#ifndef __RISCV_H
#define __RISCV_H
#ifdef __GNUC__
#define read_csr(reg) ({ unsigned long __tmp; \
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
#define write_csr(reg, val) \
asm volatile ("csrw " #reg ", %0" :: "r"(val))
#define swap_csr(reg, val) ({ long __tmp; \
asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \
__tmp; })
#define set_csr(reg, bit) ({ unsigned long __tmp; \
if (__builtin_constant_p(bit) && (bit) < 32) \
asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
else \
asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
__tmp; })
#define clear_csr(reg, bit) ({ unsigned long __tmp; \
if (__builtin_constant_p(bit) && (bit) < 32) \
asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \
else \
asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \
__tmp; })
#define rdtime() read_csr(time)
#define rdcycle() read_csr(cycle)
#define rdinstret() read_csr(instret)
#endif
#endif
/*
* vsprintf-xint: a possible free-software replacement for mprintf
*
* public domain
*/
#include <stdarg.h>
#include <stdint.h>
static const char hex[] = "0123456789abcdef";
static int number(char *out, unsigned value, int base, int lead, int wid)
{
char tmp[16];
int i = 16, ret, negative = 0;
/* No error checking at all: it is as ugly as possible */
if ((signed)value < 0 && base == 10) {
negative = 1;
value = -value;
}
while (value && i) {
tmp[--i] = hex[value % base];
value /= base;
}
if (i == 16)
tmp[--i] = '0';
if (negative && lead == ' ') {
tmp[--i] = '-';
negative = 0;
}
while (i > 16 - wid + negative)
tmp[--i] = lead;
if (negative)
tmp[--i] = '-';
ret = 16 - i;
while (i < 16)
*(out++) = tmp[i++];
return ret;
}
int pp_vsprintf(char *buf, const char *fmt, va_list args)
{
char *s, *str = buf;
int base, lead, wid;
for (; *fmt ; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
continue;
}
base = 10;
lead = ' ';
wid = 1;
repeat:
fmt++; /* Skip '%' initially, other stuff later */
switch(*fmt) {
case '\0':
goto ret;
case '0':
lead = '0';
goto repeat;
case '*':
/* should be precision, just eat it */
base = va_arg(args, int);
/* fall through: discard unknown stuff */
default:
if (*fmt >= '1' && *fmt <= '9')
wid = *fmt - '0';
goto repeat;
/* Special cases for conversions */
case 'c': /* char: supported */
*str++ = (unsigned char) va_arg(args, int);
break;
case 's': /* string: supported */
s = va_arg(args, char *);
while (*s)
*str++ = *s++;
break;
case 'n': /* number-thus-far: not supported */
break;
case '%': /* supported */
*str++ = '%';
break;
/* integers are more or less printed */
case 'p':
case 'x':
case 'X':
base = 16;
case 'o':
if (base == 10) /* yet unchaged */
base = 8;
case 'd':
case 'i':
case 'u':
str += number(str, va_arg(args, int), base, lead, wid);
break;
}
}
ret:
*str = '\0';
return str - buf;
}
......@@ -2,4 +2,10 @@ OBJS = hello.o
OUTPUT = hello
include ../common/urv/mt.mk
TRTL ?= ../../../..
TRTL_SW = $(TRTL)/software
MOCKTURTLE_LIBRARY_PRINT_ENABLE := 1
MOCKTURTLE_LIBRARY_PRINT_DEBUG_ENABLE := 0
include $(TRTL_SW)/rt/Makefile
......@@ -7,14 +7,12 @@
* Released according to the GNU GPL, version 2 or any later version.
*/
#include <string.h>
#include <stdint.h>
#include "mockturtle-rt.h"
#include "rt.h"
main()
{
pp_printf("Hello, world!\n");
void
main(void)
{
puts("Hello, world!\n");
return 0;
}
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* White Rabbit Node Core
*
* mqueue.h: MQ register definitions (Host side)
*/
#ifndef __MQUEUE_H
#define __MQUEUE_H
// Nax number of supported incoming/outgoing slots
#define MAX_MQUEUE_SLOTS 16
// HMQ base address (wrs to the base addr of the WR Node Core)
#define BASE_HMQ 0x00000
// Global Control Registers base address, relative to BASE_HMQ (SLOT_COUNT, SLOT_STATUS, interrupt control, etc).
// Common for all incoming/outgoing slots in the queue
#define MQUEUE_BASE_GCR (0x0)
// Incoming slot base address, relative to BASE_HMQ
#define MQUEUE_BASE_IN(slot) (0x4000 + (slot) * 0x400)
// Outgoung slot base address, relative to BASE_HMQ
#define MQUEUE_BASE_OUT(slot) (0x8000 + (slot) * 0x400)
// MQ slot registers, relative to the base address of each slot: MQUEUE_BASE_IN(slot_no) or MQUEUE_BASE_OUT(slot_no)
#define MQUEUE_SLOT_COMMAND 0
// Status register
#define MQUEUE_SLOT_STATUS 4
// Start of data block
#define MQUEUE_SLOT_DATA_START 8
// Layout of MQUEUE_SLOT_COMMAND register:
// Claim: prepares a slot to send a message (w/o)
#define MQUEUE_CMD_CLAIM (1<<24)
// Purge: erases all messages from a slot (w/o)
#define MQUEUE_CMD_PURGE (1<<25)
// Ready: pushes the message to the queue. (w/o)
#define MQUEUE_CMD_READY (1<<26)
// Discard: removes last message from the queue, advancing to the next one (w/o)
#define MQUEUE_CMD_DISCARD (1<<27)
// Size of the message to be sent, in words (w/o). Must be written together with the
// READY command, e.g.:
// writel (MQUEUE_CMD_READY | 10, MQUEUE_SLOT_COMMAND);
#define MQUEUE_CMD_MSG_SIZE_MASK 0xff
#define MQUEUE_CMD_MSG_SIZE_SHIFT 0
// Layout of MQUEUE_SLOT_STATUS register:
// [0] Slot is full
#define MQUEUE_SLOT_STATUS_FULL (1<<0)
// [1] Slot is empty
#define MQUEUE_SLOT_STATUS_EMPTY (1<<1)
// [15:8] Number of occupied entries
#define MQUEUE_SLOT_STATUS_OCCUPIED_SHIFT 8
#define MQUEUE_SLOT_STATUS_OCCUPIED_MASK 0xff00
// [23:16] Number of transferred words in the message currently on top of the slot
#define MQUEUE_SLOT_STATUS_MSG_SIZE_SHIFT 16
#define MQUEUE_SLOT_STATUS_MSG_SIZE_MASK 0xff0000
// [31:28] log2(number of words in the slot).
#define MQUEUE_SLOT_STATUS_LOG2_WIDTH_SHIFT 28
#define MQUEUE_SLOT_STATUS_LOG2_WIDTH_MASK 0xf0000000
// [7:2] log2(number of entries in the slot).
#define MQUEUE_SLOT_STATUS_LOG2_ENTRIES_SHIFT 2
#define MQUEUE_SLOT_STATUS_LOG2_ENTRIES_MASK 0xfc
//
// MQ Global Control Registers.Adresses relative to MQUEUE_BASE_GCR:
//
#define MQUEUE_GCR_INCOMING_STATUS_MASK (0x0000ffff)
// Number of slots in this implementation of HMQ
#define MQUEUE_GCR_SLOT_COUNT 0
// EMPTY bits of all slots in a single register (for polling/IRQ status)
#define MQUEUE_GCR_SLOT_STATUS 4
// Interrupt mask (Outgoing: EMPTY, Incoming: not EMPTY)
#define MQUEUE_GCR_IRQ_MASK 8
// IRQ Coalescing register (reserved for future use)
#define MQUEUE_GCR_IRQ_COALESCE 12
// Layout of SLOT_COUNT register
// [7:0] Number of Incoming slots
#define MQUEUE_GCR_SLOT_COUNT_N_IN_SHIFT 0
#define MQUEUE_GCR_SLOT_COUNT_N_IN_MASK 0xff
// [15:8] Number of Outgoing slots
#define MQUEUE_GCR_SLOT_COUNT_N_OUT_SHIFT 8
#define MQUEUE_GCR_SLOT_COUNT_N_OUT_MASK 0xff00
// Layout of SLOT_STATUS register
// [15:0] Outgoing slots status. Each bit indicates a NOT EMPTY status of the corresponding outgoing slot
#define MQUEUE_GCR_SLOT_STATUS_OUT_SHIFT 0
#define MQUEUE_GCR_SLOT_STATUS_OUT_MASK 0xffff
// [31:16] Incoming slots status. Each bit indicates an EMPTY status of the corresponding incoming slot
#define MQUEUE_GCR_SLOT_STATUS_IN_SHIFT 16
#define MQUEUE_GCR_SLOT_STATUS_IN_MASK 0xffff0000
// Layout of IRQ_MASK register
// [15:0] Outgoing slots status interrupt mask. Each bit enables generation of interrupt on NOT EMPTY status of the corresponding outgoing slot.
#define MQUEUE_GCR_IRQ_MASK_OUT_SHIFT 0
#define MQUEUE_GCR_IRQ_MASK_OUT_MASK 0xffff
// [31:16] Incoming slots status interrupt mask. Each bit enables generation of interrupt on EMPTY status of the corresponding incoming slot.
#define MQUEUE_GCR_IRQ_MASK_IN_SHIFT 16
#define MQUEUE_GCR_IRQ_MASK_IN_MASK 0xffff0000
// Layout of IRQ_COALSESCE register
// The register is left for future IRQ coalescing support (if ever needed)
#endif
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* LHC Instability Trigger Distribution (LIST) Firmware.
*
* list-common.h: common structures and definitions
*/
#ifndef __LIST_COMMON_H
#define __LIST_COMMON_H
#ifdef WRNODE_RT
/* Mqueue slots assigned to the TDC/FD mezzanines */
#define TDC_IN_SLOT_CONTROL 0
#define TDC_OUT_SLOT_CONTROL 0
#define FD_IN_SLOT_CONTROL 1
#define FD_OUT_SLOT_CONTROL 1
#define TDC_OUT_SLOT_LOGGING 2
#define FD_OUT_SLOT_LOGGING 3
#define TDC_OUT_SLOT_REMOTE 0
#define FD_IN_SLOT_REMOTE 0
#endif
/* Command and log message IDs */
#define ID_LOG_RAW_INPUT 0x1
#define ID_LOG_SENT_TRIGGER 0x2
#define ID_TDC_CMD_CHAN_ENABLE 0x1
#define ID_TDC_CMD_CHAN_SET_DEAD_TIME 0x2
#define ID_TDC_CMD_CHAN_SET_DELAY 0x3
#define ID_TDC_CMD_CHAN_GET_STATE 0x4
#define ID_TDC_CMD_CHAN_ARM 0x5
#define ID_TDC_CMD_CHAN_SET_MODE 0x7
#define ID_TDC_CMD_CHAN_SET_SEQ 0x8
#define ID_TDC_CMD_CHAN_ASSIGN_TRIGGER 0x9
#define ID_TDC_CMD_CHAN_SET_FLAGS 0xa
#define ID_TDC_CMD_CHAN_SET_TIMEBASE_OFFSET 0xb
#define ID_TDC_CMD_PING 0xc
#define ID_TDC_CMD_SOFTWARE_TRIGGER 0xd
#define ID_TDC_CMD_CHAN_SET_LOG_LEVEL 0xe
#define ID_TDC_CMD_CHAN_RESET_COUNTERS 0xf
#define ID_FD_CMD_CHAN_ENABLE 0x1
#define ID_FD_CMD_CHAN_ASSIGN_TRIGGER 0x2
#define ID_FD_CMD_READ_HASH 0x3
#define ID_FD_CMD_CHAN_REMOVE_TRIGGER 0x4
#define ID_FD_CMD_CHAN_GET_STATE 0x5
#define ID_FD_CMD_CHAN_SET_DELAY 0x6
#define ID_FD_CMD_CHAN_SET_WIDTH 0x7
#define ID_FD_CMD_CHAN_SET_MODE 0x8
#define ID_FD_CMD_SOFTWARE_TRIGGER 0x9
#define ID_FD_CMD_CHAN_ARM 0xa
#define ID_REP_ACK 0x100
#define ID_REP_STATE 0x101
#define ID_REP_NACK 0x102
#define ID_REP_TRIGGER_HANDLE 0x103
#define ID_REP_HASH_ENTRY 0x104
#define TDC_NUM_CHANNELS 5
#define TDC_TRIGGER_COALESCE_LIMIT 5
#define FD_NUM_CHANNELS 4
#define FD_HASH_ENTRIES 128
#define FD_MAX_QUEUE_PULSES 16
/*!..
* This enum is used by list_in_set_trigger_mode() and list_out_set_trigger_mode() to set input/output triggering mode.
*/
enum list_trigger_mode {
LIST_TRIGGER_MODE_SINGLE = 1, /*!< In SINGLE mode, the input/output will trigger only on the 1st pulse/trigger message after arming.*/
LIST_TRIGGER_MODE_AUTO = 2 /*!< In AUTO mode, the input/output will trigger on every pulse/trigger message.*/
};
/*!
* This enum is used in list_input_state / list_output_state structures to pass state information
*/
enum list_io_flags {
LIST_ENABLED = (1 << 0), /*!< I/O is physically enabled */
LIST_TRIGGER_ASSIGNED = (1 << 1), /*!< I/O is has a trigger assigned */
LIST_LAST_VALID = (1 << 2), /*!< I/O processed at least one pulse. It's timestamp/ID is in the "last" field. */
LIST_ARMED = (1 << 3), /*!< I/O is armed */
LIST_TRIGGERED = (1 << 4), /*!< I/O has triggered */
LIST_WR_TIMING_OK = (1 << 5) /*!< The output has correct WR time */
};
enum list_log_level {
LIST_LOG_NOTHING = 0,
LIST_LOG_RAW = (1 << 0), /*!< Input only: log all pulses coming to the TDC input */
LIST_LOG_SENT = (1 << 1), /*!< Input only: log all sent triggers */
LIST_LOG_PROMISC = (1 << 2), /*!< Output only: promiscious mode - log all trigger messages received from WR network */
LIST_LOG_FILTERED = (1 << 3), /*!< Output only: log all trigger messages that have been assigned to the output */
LIST_LOG_EXECUTED = (1 << 4), /*!< Output only: log all triggers executed on the output */
LIST_LOG_MISSED = (1 << 5), /*!< Output only: log all triggers missed by the output */
LIST_LOG_ALL = 0xff
};
#define HASH_ENT_EMPTY 0
#define HASH_ENT_DIRECT (1<<0)
#define HASH_ENT_CONDITION (1<<1)
#define HASH_ENT_CONDITIONAL (1<<2)
#define HASH_ENT_DISABLED (1<<3)
struct list_timestamp {
int32_t seconds;
int32_t cycles;
int32_t frac;
};
struct list_id
{
uint32_t system;
uint32_t source_port;
uint32_t trigger;
};
struct list_trigger_entry {
struct list_timestamp ts;
struct list_id id;
uint32_t seq;
};
struct list_log_entry {
uint32_t type;
uint32_t seq;
int channel;
struct list_id id;
struct list_timestamp ts;
};
#ifdef WRNODE_RT
struct list_trigger_message {
struct rmq_message_addr hdr;
uint32_t transmit_seconds;
uint32_t transmit_cycles;
int count;
struct list_trigger_entry triggers[TDC_TRIGGER_COALESCE_LIMIT];
};
#endif
#ifdef WRNODE_RT
static inline void ts_add(struct list_timestamp *a, const struct list_timestamp *b)
{
a->frac += b->frac;
if(a->frac >= 4096)
{
a->frac -= 4096;
a->cycles ++;
}
a->cycles += b->cycles;
if(a->cycles >= 125000000)
{
a->cycles -= 125000000;
a->seconds++;
}
a->seconds += b->seconds;
}
static inline void ts_sub(struct list_timestamp *a, const struct list_timestamp *b)
{
a->frac -= b->frac;
if(a->frac < 0)
{
a->frac += 4096;
a->cycles --;
}
a->cycles -= b->cycles;
if(a->cycles < 0)
{
a->cycles += 125000000;
a->seconds--;
}
a->seconds -= b->seconds;
if(a->seconds == -1)
{
a->seconds = 0;
a->cycles -= 125000000;
}
}
#endif
#endif
#ifndef __LIST_SERIALIZERS_H
#define __LIST_SERIALIZERS_H
#include "rt-mqueue.h"
struct mq_buffer {
volatile uint32_t *ctl;
volatile uint32_t *data;
int remaining_words;
int used_words;
};
static inline struct mq_buffer mq_buffer_init_in( int remote, int slot, int n_words )
{
struct mq_buffer b;
b.data = mq_map_in_buffer ( remote, slot );
b.remaining_words = n_words;
b.used_words = 0;
return b;
}
static inline struct mq_buffer mq_buffer_init_out( int remote, int slot, int n_words )
{
struct mq_buffer b;
b.data = mq_map_out_buffer ( remote, slot );
b.remaining_words = n_words;
b.used_words = 0;
return b;
}
static inline void mq_buffer_send ( struct mq_buffer *buf, int remote, int slot )
{
mq_send ( remote, slot, buf->used_words );
}
static inline void mq_buffer_require ( struct mq_buffer *buf, int n_words )
{
buf->remaining_words -= n_words;
buf->used_words += n_words;
}
static inline void bag_int ( struct mq_buffer *buf, int data )
{
mq_buffer_require ( buf, 1 );
buf->data[0] = data;
buf->data++;
}
static inline void bag_ts ( struct mq_buffer *buf, struct list_timestamp *ts )
{
mq_buffer_require ( buf, 3 );
buf->data[0] = ts->seconds;
buf->data[1] = ts->cycles;
buf->data[2] = ts->frac;
buf->data += 3;
}
static inline void bag_id ( struct mq_buffer *buf, struct list_id *id )
{
mq_buffer_require ( buf, 3 );
buf->data[0] = id->system;
buf->data[1] = id->source_port;
buf->data[2] = id->trigger;
buf->data += 3;
}
static inline void bag_trigger_entry ( struct mq_buffer *buf, struct list_trigger_entry *ent )
{
mq_buffer_require ( buf, 7 );
buf->data[0] = ent->ts.seconds;
buf->data[1] = ent->ts.cycles;
buf->data[2] = ent->ts.frac;
buf->data[3] = ent->id.system;
buf->data[4] = ent->id.source_port;
buf->data[5] = ent->id.trigger;
buf->data[6] = ent->seq;
buf->data += 7;
}
static inline void bag_skip ( struct mq_buffer *buf, int n_words )
{
mq_buffer_require ( buf, n_words );
buf->data += n_words;
}
/*int unbag_int ( struct mq_buffer *buf, int *data );
int unbag_ts ( struct mq_buffer *buf, struct list_timestamp *ts );
int unbag_trigger_entry ( struct mq_buffer *buf, struct list_trigger_entry *ent );
*/
#endif
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
#ifndef __PP_PRINTF_H
#define __PP_PRINTF_H
#include <stdarg.h>
#define CONFIG_PRINT_BUFSIZE 128
extern int pp_printf(const char *fmt, ...)
__attribute__((format(printf,1,2)));
extern int pp_sprintf(char *s, const char *fmt, ...)
__attribute__((format(printf,2,3)));
extern int pp_vprintf(const char *fmt, va_list args);
extern int pp_vsprintf(char *buf, const char *, va_list)
__attribute__ ((format (printf, 2, 0)));
/* This is what we rely on for output */
extern int puts(const char *s);
#endif
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* White Rabbit Node Core
*
* rt-common.h: common WRN CPU definitions and routines
*/
#ifndef __RT_COMMON_H
#define __RT_COMMON_H
#include <stdint.h>
#include <stdio.h>
#include "hw/mockturtle_addresses.h"
#include "hw/mockturtle_cpu_lr.h"
void rt_set_debug_slot(int slot);
static inline uint32_t dp_readl ( uint32_t reg )
{
return *(volatile uint32_t *) ( reg + TRTL_ADDR_DP_BASE );
}
static inline void dp_writel ( uint32_t value, uint32_t reg )
{
*(volatile uint32_t *) ( reg + TRTL_ADDR_DP_BASE ) = value;
}
static inline uint32_t lr_readl ( uint32_t reg )
{
return *(volatile uint32_t *) ( reg + TRTL_ADDR_LR_BASE );
}
static inline uint32_t lr_writel ( uint32_t value, uint32_t reg )
{
*(volatile uint32_t *) ( reg + TRTL_ADDR_LR_BASE ) = value;
}
static inline void gpio_set ( int pin )
{
lr_writel ( (1<<pin), MT_CPU_LR_REG_GPIO_SET );
}
static inline void gpio_clear ( int pin )
{
lr_writel ( (1<<pin), MT_CPU_LR_REG_GPIO_CLEAR );
}
/* fixme: use Timing Unit */
static inline void delay(int n)
{
int i;
for(i=0;i<n;i++) asm volatile("nop");
}
#endif
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* White Rabbit Node Core
*
* rt-message.h: Message assembling helper functions
*/
#ifndef __RT_MESSAGE_H
#define __RT_MESSAGE_H
#ifdef WRNODE_RT
#include "wrtd-common.h"
enum wrnc_msg_direction {
WRNC_MSG_DIR_SEND = 0,
WRNC_MSG_DIR_RECEIVE = 1
};
struct wrnc_msg {
uint32_t datalen; /**< payload length*/
volatile uint32_t *data; /**< payload */
uint32_t max_size; /**< maximum message size for chosen slot */
uint32_t offset; /**< serialization/deserialization offset */
enum wrnc_msg_direction direction; /**< serialization direction (used by wrnc_msg_x functions) */
int error; /** serialization error status */
int slot; /** concerned slot */
};
static inline struct wrnc_msg hmq_msg_claim_out (int slot, int max_size)
{
struct wrnc_msg b;
mq_claim(0, slot);
b.data = mq_map_out_buffer ( 0, slot );
b.direction = WRNC_MSG_DIR_SEND;
b.max_size = max_size;
b.offset = 0;
b.datalen = 0;
b.slot = slot;
return b;
}
static inline struct wrnc_msg hmq_msg_claim_in (int slot, int max_size)
{
struct wrnc_msg b;
b.data = mq_map_in_buffer ( 0, slot );
b.direction = WRNC_MSG_DIR_RECEIVE;
b.max_size = max_size;
b.datalen = max_size;
b.offset = 0;
b.slot = slot;
return b;
}
static inline void hmq_msg_send (struct wrnc_msg *buf)
{
mq_send ( 0, buf->slot, buf->datalen );
}
#endif
#endif
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* White Rabbit Node Core
*
* rt-mqueue.h: Message Queues definitions and functions
*/
#ifndef __RT_MQUEUE_H
#define __RT_MQUEUE_H
#include "hw/mockturtle_addresses.h"
#include "hw/mockturtle_queue.h"
#include "hw/mockturtle_cpu_lr.h"
static inline void mq_writel( int remote, uint32_t val, uint32_t reg )
{
uint32_t base = remote ? TRTL_ADDR_RMQ_BASE : TRTL_ADDR_HMQ_BASE;
*(volatile uint32_t *) (base + reg) = val ;
}
static inline uint32_t mq_readl( int remote, uint32_t reg )
{
uint32_t base = remote ? TRTL_ADDR_RMQ_BASE : TRTL_ADDR_HMQ_BASE;
return *(volatile uint32_t *) (base + reg) ;
}
static inline void mq_claim (int remote, int slot)
{
mq_writel (remote, MQUEUE_CMD_CLAIM,
MQUEUE_BASE_OUT(slot) + MQUEUE_SLOT_COMMAND);
}
static inline void mq_send( int remote, int slot)
{
mq_writel (remote, MQUEUE_CMD_READY,
MQUEUE_BASE_OUT(slot) + MQUEUE_SLOT_COMMAND);
}
static inline void mq_discard (int remote, int slot)
{
mq_writel (remote, MQUEUE_CMD_DISCARD,
MQUEUE_BASE_IN(slot) + MQUEUE_SLOT_COMMAND);
}
static unsigned *mq_map_out_header(int remote, int slot)
{
uint32_t base = remote ? TRTL_ADDR_RMQ_BASE : TRTL_ADDR_HMQ_BASE;
return (void *) (base + MQUEUE_BASE_OUT (slot) + MQUEUE_SLOT_HEADER_START);
}
static void *mq_map_out_buffer(int remote, int slot)
{
uint32_t base = remote ? TRTL_ADDR_RMQ_BASE : TRTL_ADDR_HMQ_BASE;
return (void *) (base + MQUEUE_BASE_OUT (slot) + MQUEUE_SLOT_DATA_START);
}
static unsigned *mq_map_in_header(int remote, int slot)
{
uint32_t base = remote ? TRTL_ADDR_RMQ_BASE : TRTL_ADDR_HMQ_BASE;
return (void *) (base + MQUEUE_BASE_IN (slot) + MQUEUE_SLOT_HEADER_START);
}
static void *mq_map_in_buffer(int remote, int slot)
{
uint32_t base = remote ? TRTL_ADDR_RMQ_BASE : TRTL_ADDR_HMQ_BASE;
return (void *) (base + MQUEUE_BASE_IN (slot) + MQUEUE_SLOT_DATA_START);
}
static inline uint32_t mq_poll(void)
{
return *(volatile uint32_t *) (TRTL_ADDR_LR_BASE + MT_CPU_LR_REG_POLL);
}
static inline uint32_t rmq_poll(int slot)
{
int ready = mq_poll() & (1 << (8 + slot));
if (ready)
{
uint32_t status = mq_readl(1, MQUEUE_BASE_IN(slot) + MQUEUE_SLOT_STATUS);
return ( status >> 16) & 0xfff;
}
return 0;
}
#endif
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* White Rabbit Node Core
*
* rt-smem.h: Shared Memory definitions & API
*/
#ifndef __WRNODE_SMEM_H
#define __WRNODE_SMEM_H
#define SMEM_RANGE_ADD 0x2000
#define SMEM_RANGE_SUB 0x4000
#define SMEM_RANGE_SET 0x6000
#define SMEM_RANGE_CLEAR 0x8000
#define SMEM_RANGE_FLIP 0xa000
#define SMEM __attribute__((section(".smem")))
static inline void smem_atomic_add(int *p, int x)
{
*(volatile int *)(p + (SMEM_RANGE_ADD >> 2)) = x;
}
static inline void smem_atomic_sub(int *p, int x)
{
*(volatile int *)(p + (SMEM_RANGE_SUB >> 2)) = x;
}
#endif
/*
* This work is part of the White Rabbit Node Core project.
*
* Copyright (C) 2013-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/*.
* White Rabbit Node Core
*
* rt.h: all common stuff in a single header
*/
#ifndef __WRN_RT_H
#define __WRN_RT_H
#include <stdint.h>
#include "rt-mqueue.h"
#include "rt-common.h"
#include "rt-smem.h"
#include "pp-printf.h"
#endif
......@@ -2,4 +2,10 @@ OBJS = verif.o
OUTPUT = verif
include ../common/urv/mt.mk
TRTL ?= ../../../..
TRTL_SW = $(TRTL)/software
MOCKTURTLE_LIBRARY_PRINT_ENABLE := 1
MOCKTURTLE_LIBRARY_PRINT_DEBUG_ENABLE := 0
include $(TRTL_SW)/rt/Makefile
......@@ -10,7 +10,9 @@
#include <string.h>
#include <stdint.h>
#include "rt.h"
#include "mockturtle-rt.h"
#include "hw/mockturtle_addresses.h"
#include "hw/mockturtle_queue.h"
#include "hw/mockturtle_cpu_lr.h"
volatile unsigned int counts[8] __attribute__((section(".smem")));
......@@ -54,13 +56,13 @@ test_hmq(void)
v = counts[cpu];
// Send a message
mq_claim(0, 0);
p = mq_map_out_buffer(0, 0);
mq_claim(TRTL_HMQ, 0);
p = mq_map_out_buffer(TRTL_HMQ, 0);
for (i = 0; i < sizeof (msg); i++)
p[i] = msg[i];
hdr = mq_map_out_header(0, 0);
hdr = mq_map_out_header(TRTL_HMQ, 0);
*hdr = (sizeof (msg) + 3) / 4;
mq_send(0, 0);
mq_send(TRTL_HMQ, 0, 0);
// Wait for answer
while((mq_poll() & 1) == 0)
......@@ -69,14 +71,14 @@ test_hmq(void)
failed();
// Read answer
hdr = mq_map_in_header(0, 0);
hdr = mq_map_in_header(TRTL_HMQ, 0);
if (*hdr != 2)
failed();
p = mq_map_in_buffer(0, 0);
p = mq_map_in_buffer(TRTL_HMQ, 0);
for (i = 0; i < sizeof (msg); i++)
if (~p[i] != msg[i])
failed();
mq_discard(0, 0);
mq_discard(TRTL_HMQ, 0);
}
static void
......@@ -91,13 +93,13 @@ test_rmq(void)
v = counts[cpu];
// Send a message
mq_claim(1, 0);
p = mq_map_out_buffer(1, 0);
mq_claim(TRTL_RMQ, 0);
p = mq_map_out_buffer(TRTL_RMQ, 0);
for (i = 0; i < sizeof (msg); i++)
p[i] = msg[i];
hdr = mq_map_out_header(1, 0);
hdr = mq_map_out_header(TRTL_RMQ, 0);
*hdr = (sizeof (msg) + 3) / 4;
mq_send(1, 0);
mq_send(TRTL_RMQ, 0, 0);
}
int
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment