diff --git a/software/unb_osy/io2_copy.S b/software/unb_osy/io2_copy.S new file mode 100644 index 0000000000000000000000000000000000000000..7826c86bbd9606f674c9885b6f728364ab895904 --- /dev/null +++ b/software/unb_osy/io2_copy.S @@ -0,0 +1,32 @@ + .file "io2_copy.c" + .section .text + .align 2 + .global io2_copy + .type io2_copy, @function +io2_copy: + andi r2, r4, 3 + ldw r3, 0(sp) + bne r2, zero, .L2 + andi r2, r5, 3 + bne r2, zero, .L2 + beq r6, zero, .L5 + add r2, r7, r7 + add r3, r3, r3 + add r7, r2, r2 + add r3, r3, r3 + mov r8, zero +.L7: + ldwio r2, 0(r5) + stwio r2, 0(r4) + addi r8, r8, 1 + add r5, r5, r7 + add r4, r4, r3 + bne r8, r6, .L7 +.L5: + movi r2, 1 + ret +.L2: + mov r2, zero + ret + .size io2_copy, .-io2_copy + .ident "GCC: (Altera 10.1 Build 153) 4.1.2" diff --git a/software/unb_osy/io2_copy.h b/software/unb_osy/io2_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..20b3d774b7ed9d5d1d8cf4449aea897fb813e070 --- /dev/null +++ b/software/unb_osy/io2_copy.h @@ -0,0 +1,7 @@ +#ifndef IO2_COPY_H +#define IO2_COPY_H +#include <alt_types.h> +// mind you: to + from are taken to be pointers to 32-bit words; +// sinc and dinc are increments in *units of words* (ie 4bytes) +alt_u32 io2_copy(void* to, void* from, unsigned int n, unsigned int sinc, unsigned int dinc); +#endif diff --git a/software/unb_osy/main.c b/software/unb_osy/main.c new file mode 100644 index 0000000000000000000000000000000000000000..78d573621c06db7627497c41cc33d55bd1b8bbb9 --- /dev/null +++ b/software/unb_osy/main.c @@ -0,0 +1,130 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2010 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +#include "system.h" +#include "sys/alt_irq.h" + +#if defined(COMPILE_FOR_QSYS) +# include "altera_nios2_qsys_irq.h" +#elif defined(COMPILE_FOR_GEN2_UNB2) +# include "altera_nios2_gen2_irq.h" +#else +# include "altera_nios2_irq.h" +#endif + +#include "osx_timer.h" +#include "unbosx_types.h" +#include "unbos_eth.h" +#include "unbos_i2c.h" +#include "packet.h" +#include "osx_stdio.h" +#include "altera_avalon_jtag_uart_regs.h" +/* Compile switches. */ + +#define BUILD 1 +#undef ATEST +void main(void) __attribute__((weak, alias("alt_main"))); + + +/*----------------------------------------------------------------------------- + * Function name: main + * Parameters: - + * Return: - + * Description: Deal with incoming command packets + * Remark: Use the 1ms system tick to initiate actions in a loop. + * The tasks in the loop are blocking. + *----------------------------------------------------------------------------- + */ +#if defined(COMPILE_FOR_QSYS) +#warning "Compiling for QSYS" +ALTERA_NIOS2_QSYS_IRQ_INSTANCE ( CPU_0, cpu_0); +#elif defined(COMPILE_FOR_GEN2_UNB2) +#warning "Compiling for GEN2_UNB2" +ALTERA_NIOS2_GEN2_IRQ_INSTANCE ( CPU_0, cpu_0); +#else +#warning "Compiling for SOPC" +ALTERA_NIOS2_IRQ_INSTANCE ( CPU_0, cpu_0); +#endif + +void alt_main(void) { + clock_t nof_ticks_wdi; +#ifdef ATEST + alt_u32 atest = 0, oatest = 0; +#endif +#if defined(COMPILE_FOR_QSYS) + ALTERA_NIOS2_QSYS_IRQ_INIT ( CPU_0, cpu_0); +#elif defined(COMPILE_FOR_GEN2_UNB2) + ALTERA_NIOS2_GEN2_IRQ_INIT ( CPU_0, cpu_0); +#else + ALTERA_NIOS2_IRQ_INIT ( CPU_0, cpu_0); +#endif + alt_irq_cpu_enable_interrupts(); + OSX_TIMER_INIT ( TIMER_0, timer_0); + + // Clear the AC(cess) bit in the JTAG UART. + // If there *is* JTAG activity (ie a host-PC + // reading out the JTAG) then it will be set to + // '1'. Our output routine will detect activity + // (or lack thereof). + // We must write '1' to clear the bit. + IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE, ALTERA_AVALON_JTAG_UART_CONTROL_AC_MSK); + + osx_printf("unb_osy %d\n", BUILD); +#ifdef ATEST + osx_printf("%x\n", &atest); +#endif + + // Set up networking environment + UNBOSX_NET_Setup(); + + // Take care of setting up I2C - works wether we + // have it or not + UNBOS_i2c_init(); + + // force watchdog reset asap + nof_ticks_wdi = osx_clock(); + // prepare for entering mainloop + while( 1 ) { + clock_t now = osx_clock(); + + // Reset WDI every 1000 clockticks (1 second) + if( (now-nof_ticks_wdi) >= 1000 ) { + UNBOSX_ResetWatchdog(); + nof_ticks_wdi = now; + } + + // Task: Ethernet traffic + if( RXAVAIL(eth_status) ) { + unsigned int replysize; + if( (replysize=handlePacket())>0 ) + UNBOSX_NET_Send(replysize+2); + else + UNBOSX_NET_Discard(); + } +#if ATEST + if( oatest!=atest ) { + osx_printf("%x -> %x\n", oatest, atest); + oatest = atest; + } +#endif + } +} diff --git a/software/unb_osy/modules/common_types.h b/software/unb_osy/modules/common_types.h new file mode 100644 index 0000000000000000000000000000000000000000..f3e562b5abe55e49577c11de7457e6c9642c23d0 --- /dev/null +++ b/software/unb_osy/modules/common_types.h @@ -0,0 +1,88 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +#ifndef COMMON_TYPES_H +#define COMMON_TYPES_H + +/* includes */ +#include "alt_types.h" + + +/* public constants */ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define HALF_WORD_SZ 2 +#define WORD_SZ 4 +#define LONG_WORD_SZ 8 +#define NIBBLE_W 4 +#define BYTE_W 8 +#define OCTET_W 8 +#define HALF_WORD_W (BYTE_W * HALF_WORD_SZ) +#define WORD_W (BYTE_W * WORD_SZ) +#define LONG_WORD_W (BYTE_W * LONG_WORD_SZ) + + +/* public macros */ + + +/* public types */ + +/* Map to + * %QUARTUS_ROOTDIR%/../ip/altera/nios2_ip/altera_nios2/HAL/inc/alt_type.h + */ +typedef alt_32 TBool; // b +typedef alt_8 TInt8; // c : signed char +typedef alt_16 TInt16; // i : signed short +typedef alt_32 TInt32; // l : signed long +typedef alt_64 TInt64; // h : signed long long +typedef alt_u8 TUInt8; // uc : unsigned char +typedef alt_u16 TUInt16; // ui : unsigned short +typedef alt_u32 TUInt32; // ul : unsigned long +typedef alt_u64 TUInt64; // uh : unsigned long long + +typedef float TFloat32; // f +typedef double TFloat64; // d +typedef char TStr8[9]; // sz +typedef char TStr32[33]; // sz +typedef char TStr64[65]; // sz +typedef char TStr128[129]; // sz +typedef char TStr256[257]; // sz +typedef char TStr512[513]; // sz + + +/* public variables */ + +/* public function protos */ + +#endif + diff --git a/software/unb_osy/modules/common_util.c b/software/unb_osy/modules/common_util.c new file mode 100644 index 0000000000000000000000000000000000000000..9c2dc782a2ef4a104fa7133d297b1b7eba3f0106 --- /dev/null +++ b/software/unb_osy/modules/common_util.c @@ -0,0 +1,94 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +/* Compile switches. */ + + +/* includes */ +#include <stdio.h> +#include "common_types.h" +#include "common_util.h" + + +/* private constants (#define) */ + +/* private types */ + +/* private function protos */ + +/* private constants (const) */ + +/* private variables */ + +/* public variables */ + +/* public function implements */ + +/*----------------------------------------------------------------------------- + * Function name: UTIL_swapl + * Parameters: in_dat = 4 byte long input word + * Return: out_dat = byte swapped word + * Description: + *----------------------------------------------------------------------------- + */ +TUInt32 UTIL_swapl(TUInt32 in_dat) +{ + TUInt32 out_dat; + TUInt8 *pInByte; + TUInt8 *pOutByte; + + pInByte = (TUInt8 *)&in_dat; + pOutByte = (TUInt8 *)&out_dat + 3; + + *pOutByte-- = *pInByte++; + *pOutByte-- = *pInByte++; + *pOutByte-- = *pInByte++; + *pOutByte = *pInByte; + + return out_dat; +} + + +/*----------------------------------------------------------------------------- + * Function name: UTIL_swaps + * Parameters: in_dat = 2 byte long input half word + * Return: out_dat = byte swapped half word + * Description: + *----------------------------------------------------------------------------- + */ +TUInt16 UTIL_swaps(TUInt16 in_dat) +{ + TUInt16 out_dat; + TUInt8 *pInByte; + TUInt8 *pOutByte; + + pInByte = (TUInt8 *)&in_dat; + pOutByte = (TUInt8 *)&out_dat + 1; + + *pOutByte-- = *pInByte++; + *pOutByte = *pInByte; + + return out_dat; +} + + +/* private function implements */ diff --git a/software/unb_osy/modules/common_util.h b/software/unb_osy/modules/common_util.h new file mode 100644 index 0000000000000000000000000000000000000000..7495831872fc3b9329f2f620783595524bbbebdc --- /dev/null +++ b/software/unb_osy/modules/common_util.h @@ -0,0 +1,78 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +#ifndef COMMON_UTIL_H +#define COMMON_UTIL_H + + +/* includes */ +#include "common_types.h" + + +/* public constants */ + +// Define UTIL_HOST_IS_LITTLE_ENDIAN if the host is little endian, comment if +// the host is big endian. +// . Network communication is big endian (MSByte is 'big end first'). +// . The Nios II architecture is little endian (LSByte is 'little end first'). +#define UTIL_HOST_IS_LITTLE_ENDIAN + +#ifndef UTIL_HOST_IS_LITTLE_ENDIAN +#define UTIL_HOST_IS_BIG_ENDIAN +#endif + +/* public macros */ + +// Define host to network big endian 'b' and host 'h' to little endian 'l' for +// 32 bit 'l' and for 16 bit 's' +#ifdef UTIL_HOST_IS_LITTLE_ENDIAN +#define UTIL_htoll(a) (a) +#define UTIL_htols(a) (a) +#define UTIL_htobl(a) (UTIL_swapl(a)) +#define UTIL_htobs(a) (UTIL_swaps(a)) +#else +#define UTIL_htoll(a) (UTIL_swapl(a)) +#define UTIL_htols(a) (UTIL_swaps(a)) +#define UTIL_htobl(a) (a) +#define UTIL_htobs(a) (a) +#endif +// For completeness also define equivalent 'n' to 'h' and 'l' to 'h' for +// 32 bit and 16 bit +#define UTIL_ltohl(a) (UTIL_htoll(a)) +#define UTIL_ltohs(a) (UTIL_htols(a)) +#define UTIL_btohl(a) (UTIL_htobl(a)) +#define UTIL_btohs(a) (UTIL_htobs(a)) + +#define UTIL_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define UTIL_SEL_A_B(sel, a, b) ((sel) ? (a) : (b)) + + +/* public types */ + +/* public variables */ + +/* public function protos */ +TUInt32 UTIL_swapl(TUInt32 in_dat); +TUInt16 UTIL_swaps(TUInt16 in_dat); + +#endif + diff --git a/software/unb_osy/modules/i2c_ltc4260.h b/software/unb_osy/modules/i2c_ltc4260.h new file mode 100644 index 0000000000000000000000000000000000000000..9431c494b05451777b6b89d83155293114b86a16 --- /dev/null +++ b/software/unb_osy/modules/i2c_ltc4260.h @@ -0,0 +1,78 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +// Positive High Voltage Hot Swap Controller with I2C Compatible Monitoring + +#ifndef I2C_LTC4260_H +#define I2C_LTC4260_H + +/* includes */ +#include "common_types.h" + +/* public constants */ + +// Mass write address (broadcast) +#define I2C_LTC4260_ADR_MW 0x5F +// Alert response address +#define I2C_LTC4260_ADR_AR 0x0C +// Other addresses +#define I2C_LTC4260_ADR_LOW_LOW_LOW 0x44 + +// Use SMBUS Write Byte or Read Byte to access the command registers +#define I2C_LTC4260_CMD_CONTROL 0 +#define I2C_LTC4260_CMD_ALERT 1 +#define I2C_LTC4260_CMD_STATUS 2 +#define I2C_LTC4260_CMD_FAULT 3 +#define I2C_LTC4260_CMD_SENSE 4 +#define I2C_LTC4260_CMD_SOURCE 5 +#define I2C_LTC4260_CMD_ADIN 6 + +// Voltage measurement units, use float for ease and accuracy or int for speed +// 0.3 mV over Rs (e.g. 10 mOhm) for current sense +#define I2C_LTC4260_V_UNIT_SENSE ((TFloat32)0.0003) +#define I2C_LTC4260_uV_UNIT_SENSE ((TUInt32)300) +// 400 mV supply voltage (e.g +48 V) +#define I2C_LTC4260_V_UNIT_SOURCE ((TFloat32)0.4) +#define I2C_LTC4260_mV_UNIT_SOURCE ((TUInt32)400) +// 10 mV ADC +#define I2C_LTC4260_V_UNIT_ADIN ((TFloat32)0.01) +#define I2C_LTC4260_mV_UNIT_ADIN ((TUInt32)10) + +// 0x1B = 00 = power good +// & 0 = disable test mode +// & 1 = Enable massa write +// & 1 = turn FET On +// & 0 = Overcurrent Autoretry Disabled +// & 1 = Undervoltage Autoretry Enabled +// & 1 = Overvoltage Autoretry Enabled +#define I2C_LTC4260_CONTROL_DEFAULT 0x1B + +/* public macros */ + +/* public types */ + +/* public variables */ + +/* public function protos */ + +#endif + diff --git a/software/unb_osy/modules/i2c_max1617.h b/software/unb_osy/modules/i2c_max1617.h new file mode 100644 index 0000000000000000000000000000000000000000..399f2aa03e4a1fac0688b2e1aafbbf5449081f54 --- /dev/null +++ b/software/unb_osy/modules/i2c_max1617.h @@ -0,0 +1,93 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +// This also applies to MAX1618. The adavantage of the MAX1618 over the +// MAX1617A is that the MAX1618 has a thermostat mode, which changes the +// function of the ALERT output from a latched interrupt-type output to a +// selfclearing thermostat for fan control. + +#ifndef I2C_MAX1617_H +#define I2C_MAX1617_H + +/* includes */ + +/* public constants */ +// ADD0_ADD1 +#define I2C_MAX1617_ADR_LOW_LOW 0x18 +#define I2C_MAX1617_ADR_LOW_MID 0x19 +#define I2C_MAX1617_ADR_LOW_HIGH 0x1A +#define I2C_MAX1617_ADR_MID_LOW 0x29 +#define I2C_MAX1617_ADR_MID_MID 0x2A +#define I2C_MAX1617_ADR_MID_HIGH 0x2B +#define I2C_MAX1617_ADR_HIGH_LOW 0x4C +#define I2C_MAX1617_ADR_HIGH_MID 0x4D +#define I2C_MAX1617_ADR_HIGH_HIGH 0x4E + +#define I2C_MAX1617_CMD_READ_LOCAL_TEMP 0 +#define I2C_MAX1617_CMD_READ_REMOTE_TEMP 1 +#define I2C_MAX1617_CMD_READ_STATUS 2 +#define I2C_MAX1617_CMD_READ_CONFIG 3 +#define I2C_MAX1617_CMD_READ_RATE 4 +#define I2C_MAX1617_CMD_READ_LOCAL_HIGH 5 +#define I2C_MAX1617_CMD_READ_LOCAL_LOW 6 +#define I2C_MAX1617_CMD_READ_REMOTE_HIGH 7 +#define I2C_MAX1617_CMD_READ_REMOTE_LOW 8 + +#define I2C_MAX1617_CMD_WRITE_CONFIG 9 +#define I2C_MAX1617_CMD_WRITE_RATE 10 +#define I2C_MAX1617_CMD_WRITE_LOCAL_HIGH 11 +#define I2C_MAX1617_CMD_WRITE_LOCAL_LOW 12 +#define I2C_MAX1617_CMD_WRITE_REMOTE_HIGH 13 +#define I2C_MAX1617_CMD_WRITE_REMOTE_LOW 14 + +#define I2C_MAX1617_CMD_ONE_SHOT 15 + +#define I2C_MAX1617_RATE_0_0625 0 +#define I2C_MAX1617_RATE_0_125 1 +#define I2C_MAX1617_RATE_0_25 2 +#define I2C_MAX1617_RATE_0_5 3 +#define I2C_MAX1617_RATE_1 4 +#define I2C_MAX1617_RATE_2 5 +#define I2C_MAX1617_RATE_4 6 +#define I2C_MAX1617_RATE_8 7 + +#define I2C_MAX1617_CONFIG_ID 0x08 +#define I2C_MAX1617_CONFIG_THERM 0x10 +#define I2C_MAX1617_CONFIG_POL 0x20 +#define I2C_MAX1617_CONFIG_RUN_STOP 0x40 +#define I2C_MAX1617_CONFIG_MASK 0x80 + +#define I2C_MAX1617_STATUS_BUSY 0x80 +#define I2C_MAX1617_STATUS_RHIGH 0x10 +#define I2C_MAX1617_STATUS_RLOW 0x08 +#define I2C_MAX1617_STATUS_DIODE 0x04 + +/* public macros */ + +/* public types */ + +/* public variables */ + +/* public function protos */ + +#endif + diff --git a/software/unb_osy/osx_stdio.c b/software/unb_osy/osx_stdio.c new file mode 100644 index 0000000000000000000000000000000000000000..a059038d80d77c87ca24749f82df74cfb51550e2 --- /dev/null +++ b/software/unb_osy/osx_stdio.c @@ -0,0 +1,217 @@ +/****************************************************************************** +* * +* License Agreement * +* * +* Copyright (c) 2006 Altera Corporation, San Jose, California, USA. * +* All rights reserved. * +* * +* Permission is hereby granted, free of charge, to any person obtaining a * +* copy of this software and associated documentation files (the "Software"), * +* to deal in the Software without restriction, including without limitation * +* the rights to use, copy, modify, merge, publish, distribute, sublicense, * +* and/or sell copies of the Software, and to permit persons to whom the * +* Software is furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in * +* all copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * +* DEALINGS IN THE SOFTWARE. * +* * +* This agreement shall be governed in all respects by the laws of the State * +* of California and by the laws of the United States of America. * +* * +* Altera does not recommend, suggest or require that this reference design * +* file be used in conjunction or combination with any other product. * +******************************************************************************/ + +/* + * This file provides a very minimal printf implementation for use with very + * small applications. Only the following format strings are supported: + * %x + * %s + * %c + * %% + */ +#include <system.h> +#include <osx_stdio.h> +#include "altera_avalon_jtag_uart_regs.h" + +typedef void (*output_fn)(char , char*); + + +/* soo = start of output */ +int fmt_function(output_fn out, char* soo, const char* fmt, va_list args) { + char c; + const char* w; + const char* const p = soo; + + /* Process format string. */ + w = fmt; + while( (c=*w++)!=0 ) { + /* If not a format escape character, just print */ + /* character. Otherwise, process format string. */ + if( c!='%' ) { + out(c, soo++); + } else { + /* Get format character. If none */ + /* available, processing is complete. */ + if( (c=*w++)==0 ) + break; + /* Bollox. Need to to woik! */ + switch( c ) { + case '%': + /* Process "%" escape sequence. */ + out(c, soo++); + break; + + case 'c': + { + int v = va_arg(args, int); + out((char)v, soo++); + } + break; + + case 'x': + { + /* Process hexadecimal number format. */ + int digit_shift; + unsigned long v = va_arg(args, unsigned long); + unsigned long digit; + + out('0', soo++); + out('x', soo++); + + /* If the number value is zero, just print and continue. */ + if( v==0 ) { + out('0', soo++); + break; + } + + /* Find first non-zero digit. */ + digit_shift = 28; + while( !(v & (0xF<<digit_shift)) ) + digit_shift -= 4; + + /* Print digits. */ + for( ; digit_shift>=0; digit_shift-=4 ) { + digit = (v & (0xF << digit_shift)) >> digit_shift; + if( digit<=9 ) + c = '0' + digit; + else + c = 'a' + digit - 10; + out(c, soo++); + } + } + break; + + case 'd': + { + int v = va_arg(args, int); + char digitbuf[ ((sizeof(int) * 8)/3) + 1 ]; + char* dptr = &digitbuf[0]; + + /* we must, in this case, print at least one digit */ + if( v==0 ) + *dptr++ = '0'; + /* figure out which digits to print. + * this will only do something if v!=0 yet + */ + while( v ) { + *dptr++ = '0' + (v%10); + v /= 10; + } + /* the digits we must output are now in reverse order + * so we print them starting from the end. + * Note: dptr points one *past* the character to + * output! + */ + while( --dptr>=&digitbuf[0] ) + out(*dptr, soo++); + } + break; + + case 's': + { + /* Process string format. */ + char *s = va_arg(args, char *); + + while( *s ) + out(*s++, soo++); + } + break; + + default: + break; + } + } + } + out('\0', soo++); + return (int)(soo-p); +} + +/* Put functions: to stdout or to string */ +void osx_putchar(char c, char* _ptr) { + unsigned int ntry = 32; + volatile unsigned int control; + if( c!='\0' ) { + do { + control = IORD_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE); + + if( (control&ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK)!=0 ) { + IOWR_ALTERA_AVALON_JTAG_UART_DATA(JTAG_UART_0_BASE, c); + break; + } +#if 0 + else { + // buffer was full - apparently - so if we do not + // detect JTAG activity since previous I/O we + // do not output this character but carry on + // (otherwise the firmware would hang) + if( (control&ALTERA_AVALON_JTAG_UART_CONTROL_AC_MSK)==0 ) { + // AC(tivity) bit NOT set -> no-one is lissnin! + break; + } + } +#endif + } while( --ntry ); + } + // Reset the ACtivity bit (by writing a '1') so we can always detect if someone + // starts lissnin +// IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE, ALTERA_AVALON_JTAG_UART_CONTROL_AC_MSK); + return; +} + +#if 0 +void osx_sputchar(char c, char* ptr) { + *ptr = c; +} + +int osx_vsprintf(char* str, const char* fmt, va_list args ) { + return fmt_function(osx_sputchar, str, fmt, args); +} + +/* OSX sprintf function */ +int osx_sprintf(char* str, const char* fmt, ... ) { + int r; + va_list args; + va_start(args, fmt); + r = fmt_function(osx_sputchar, str, fmt, args); + va_end(args); + return r; +} +#endif +int osx_printf(const char* fmt, ...) { + int r; + va_list args; + va_start(args, fmt); + r = fmt_function(osx_putchar, 0, fmt, args); + va_end(args); + return r; +} + diff --git a/software/unb_osy/osx_stdio.h b/software/unb_osy/osx_stdio.h new file mode 100644 index 0000000000000000000000000000000000000000..44f30a6e10bc3818c74c9837bdabee7482e1e720 --- /dev/null +++ b/software/unb_osy/osx_stdio.h @@ -0,0 +1,7 @@ +#ifndef OSX_STDIO_H +#define OSX_STDIO_H +#include <stdarg.h> +int osx_vsprintf(char* str, const char* fmt, va_list args ); +int osx_sprintf(char* str, const char* fmt, ... ); +int osx_printf(const char* fmt, ...); +#endif diff --git a/software/unb_osy/osx_timer.c b/software/unb_osy/osx_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..bb42c9930e5e57a2f9e658820178a3f1e7119719 --- /dev/null +++ b/software/unb_osy/osx_timer.c @@ -0,0 +1,66 @@ +#include "sys/alt_irq.h" +//#include "osx_irq.h" + +#include "osx_timer.h" +#include "altera_avalon_timer_regs.h" + +#include "alt_types.h" +#include "unbosx_types.h" + +volatile clock_t _osx_nticks = 0; + +clock_t osx_clock( void ) { + return _osx_nticks; +} +/* + * osx_timer_sc_irq() is the interrupt handler used for the system + * clock. This is called periodically when a timer interrupt occurs. The + * function first clears the interrupt condition, and then calls the + * alt_tick() function to notify the system that a timer tick has occurred. + * + * alt_tick() increments the system tick count, and updates any registered + * alarms, see alt_tick.c for further details. + */ +#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT +static void osx_timer_sc_irq (void* base) +#else +static void osx_timer_sc_irq (void* base, alt_u32 id) +#endif +{ + /* clear the interrupt */ + IOWR_ALTERA_AVALON_TIMER_STATUS (base, 0); + + /* + * Dummy read to ensure IRQ is negated before the ISR returns. + * The control register is read because reading the status + * register has side-effects per the register map documentation. + */ + IORD_ALTERA_AVALON_TIMER_CONTROL (base); + + _osx_nticks++; +} + +/* + * osx_timer_sc_init() is called to initialise the timer that will be + * used to provide the periodic system clock. This is called from the + * auto-generated alt_sys_init() function. + */ + +void osx_timer_sc_init (void* base, alt_u32 irq_controller_id, + alt_u32 irq, alt_u32 freq) +{ + /* set to free running mode */ + + IOWR_ALTERA_AVALON_TIMER_CONTROL (base, + ALTERA_AVALON_TIMER_CONTROL_ITO_MSK | + ALTERA_AVALON_TIMER_CONTROL_CONT_MSK | + ALTERA_AVALON_TIMER_CONTROL_START_MSK); + + /* register the interrupt handler, and enable the interrupt */ +#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT + alt_ic_isr_register(irq_controller_id, irq, osx_timer_sc_irq, + base, NULL); +#else + alt_irq_register (irq, base, osx_timer_sc_irq); +#endif +} diff --git a/software/unb_osy/osx_timer.h b/software/unb_osy/osx_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..24485163a3c8b25a28c7294b6c088c10147d7bef --- /dev/null +++ b/software/unb_osy/osx_timer.h @@ -0,0 +1,135 @@ +#ifndef OSX_TIMER_H +#define OSX_TIMER_H + +#include "unbosx_types.h" +#include "sys/alt_warning.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +#define __ALT_COUNTER_SIZE(name) name##_COUNTER_SIZE +#define _ALT_COUNTER_SIZE(name) __ALT_COUNTER_SIZE(name) + +#define ALT_SYS_CLK_COUNTER_SIZE _ALT_COUNTER_SIZE(ALT_SYS_CLK) +#define ALT_TIMESTAMP_COUNTER_SIZE _ALT_COUNTER_SIZE(ALT_TIMESTAMP_CLK) + +#if (ALT_SYS_CLK_COUNTER_SIZE == 64) +#define alt_sysclk_type alt_u64 +#else +#define alt_sysclk_type alt_u32 +#endif + +typedef alt_sysclk_type clock_t; + +clock_t osx_clock( void ); + +/* + * The function alt_avalon_timer_sc_init() is the initialisation function for + * the system clock. It registers the timers interrupt handler, and then calls + * the system clock regestration function, alt_sysclk_init(). + */ + +extern void osx_timer_sc_init (void* base, alt_u32 irq_controller_id, + alt_u32 irq, alt_u32 freq); + + +/* + * ALTERA_AVALON_TIMER_INSTANCE is the macro used by alt_sys_init() to + * allocate any per device memory that may be required. In this case no + * allocation is necessary. + */ + +#define ALTERA_AVALON_TIMER_INSTANCE(name, dev) extern int alt_no_storage + +/* + * Macro used to calculate the timer interrupt frequency. Although this is + * somewhat fearsome, when compiled with -O2 it will be resolved at compile + * time to a constant value. + */ +#define OSX_TIMER_FREQ(freq, period, units) \ + ((units[0]=='s')?(((freq + (period - 1))/period)): \ + ( \ + (units[0]=='m')?((1000 + (period - 1))/period):\ + ( \ + (units[0]=='u')?((1000000 + (period - 1))/period):1 \ + ) \ + )\ + ) + +/* + * Construct macros which contain the base address of the system clock and the + * timestamp device. These are used below to determine which driver to use for + * a given timer. + */ + +#define __ALT_CLK_BASE(name) name##_BASE +#define _ALT_CLK_BASE(name) __ALT_CLK_BASE(name) + +#define ALT_SYS_CLK_BASE _ALT_CLK_BASE(ALT_SYS_CLK) +#define ALT_TIMESTAMP_CLK_BASE _ALT_CLK_BASE(ALT_TIMESTAMP_CLK) + +/* + * If there is no system clock, then the above macro will result in + * ALT_SYS_CLK_BASE being set to none_BASE. We therefore need to provide an + * invalid value for this, so that no timer is wrongly identified as the system + * clock. + */ + +#define none_BASE 0xffffffff + +/* + * ALTERA_AVALON_TIMER_INIT is the macro used by alt_sys_init() to provide + * the run time initialisation of the device. In this case this translates to + * a call to alt_avalon_timer_sc_init() if the device is the system clock, i.e. + * if it has the name "sysclk". + * + * If the device is not the system clock, then it is used to provide the + * timestamp facility. + * + * To ensure as much as possible is evaluated at compile time, rather than + * compare the name of the device to "/dev/sysclk" using strcmp(), the base + * address of the device is compared to SYSCLK_BASE to determine whether it's + * the system clock. Since the base address of a device must be unique, these + * two aproaches are equivalent. + * + * This macro performs a sanity check to ensure that the interrupt has been + * connected for this device. If not, then an apropriate error message is + * generated at build time. + */ + + +#define OSX_TIMER_INIT(name, dev) \ + if (name##_BASE == ALT_SYS_CLK_BASE) \ + { \ + if (name##_IRQ == ALT_IRQ_NOT_CONNECTED) \ + { \ + ALT_LINK_ERROR ("Error: Interrupt not connected for " #dev ". " \ + "The system clock driver requires an interrupt to be " \ + "connected. Please select an IRQ for this device in " \ + "SOPC builder."); \ + } \ + else \ + { \ + osx_timer_sc_init((void*) name##_BASE, \ + name##_IRQ_INTERRUPT_CONTROLLER_ID, \ + name##_IRQ, \ + OSX_TIMER_FREQ(name##_FREQ, \ + name##_PERIOD, \ + name##_PERIOD_UNITS));\ + } \ + } else { \ + ALT_LINK_ERROR ("Not a system timer"); \ + } + +/* + * + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __ALT_AVALON_TIMER_H__ */ diff --git a/software/unb_osy/packet.c b/software/unb_osy/packet.c new file mode 100644 index 0000000000000000000000000000000000000000..9aad88bc17c1ff9ff2b4ef0e0978e291861041eb --- /dev/null +++ b/software/unb_osy/packet.c @@ -0,0 +1,422 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2010 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +/* Compile switches. */ + +/* includes */ +#include <system.h> +#include <packet.h> +#include <unbos_pps.h> +#include <unbos_eth.h> +#include <unbosx_util.h> +#include <io2_copy.h> + +/* Wether or not we actually _have_ flash, for bookeepingssake + * we remember wether we tried to initialize it. + * 42 is the signal that no-one has tried to init it. + * Otherwise it contains the actual initialization result + * (0 => OK, -1 => Dang!) + */ +static int didInitFlash = 42; + +/* Support this on designs that have it */ +#ifdef __ALTERA_AVALON_EPCS_FLASH_CONTROLLER +#include <altera_avalon_epcs_flash_controller.h> + +static alt_flash_epcs_dev tFlashDev = { +{ + ALT_LLIST_ENTRY, + "flash_dev", + NULL, /*open*/ + NULL, /*close*/ + alt_epcs_flash_write, /*write*/ + alt_epcs_flash_read, /*read*/ + alt_epcs_flash_get_info, /*get info*/ + alt_epcs_flash_erase_block, + alt_epcs_flash_write_block, + ((void*)EPCS_FLASH_CONTROLLER_0_BASE) + }, + EPCS_FLASH_CONTROLLER_0_REGISTER_OFFSET + EPCS_FLASH_CONTROLLER_0_BASE +}; +#else +// No flash in this design - supply default implementations +// of functions used below: keeps linker happy AND if they +// would happen to be called, they return error. +typedef int alt_flash_dev; +typedef int alt_flash_epcs_dev; +static alt_flash_epcs_dev tFlashDev; + +int alt_epcs_flash_init(alt_flash_epcs_dev* p) { + return -1; +} +int alt_epcs_flash_query(alt_flash_epcs_dev* p) { + return -1; +} +int alt_epcs_flash_write_block(alt_flash_dev* p, int notused, int i, const void* s, int l) { + return -1; +} +int alt_epcs_flash_read(alt_flash_dev* p, int i, const void* s, int l) { + return -1; +} +int alt_epcs_flash_erase_block(alt_flash_dev* p, int b) { + return -1; +} + +#endif + +#define PKT_SIZE 1500 + +// The UniBoard defined opcodes +#define CONFIGE ((alt_u32)0x8) +#define CONFIGR ((alt_u32)0x7) +#define CONFIGW ((alt_u32)0x6) +#define READN ((alt_u32)0x1) +#define WRITEN ((alt_u32)0x2) +#define ANDN ((alt_u32)0x3) +#define ORN ((alt_u32)0x4) +#define XORN ((alt_u32)0x5) +#define FREADN ((alt_u32)0x9) +#define FWRITEN ((alt_u32)0xa) +#define BITWRITEN ((alt_u32)0xb) +#define WAITPPS ((alt_u32)0xffffffff) + +/* implicit external bitmask for updating bitfields, + * used by bit_write_f */ +alt_u32 bitfield_mask; + +/* for dealing with flash ... */ +int init_flash(); +alt_u32 init_flash_first_w(void* to, void* from); +alt_u32 init_flash_first_r(void* to, void* from); +alt_u32 init_flash_first_e(void* sectoraddr); +alt_u32 flash_write_page(void* to, void* from); +alt_u32 flash_read_page(void* to, void* from); +alt_u32 flash_erase_sector(void* sectoraddr); +alt_u32 no_flash_available(void* to, void* from); +alt_u32 no_flash_available1(void* to); + +// Function pointer to the actual flash-write function. +// We let it point at the initialization routine first +static alt_u32 (*flash_writer)(void*, void*) = init_flash_first_w; +static alt_u32 (*flash_reader)(void*, void*) = init_flash_first_r; +static alt_u32 (*flash_eraser)(void*) = init_flash_first_e; + + +// Packet handler +unsigned int handlePacket() { + if( !NET_IS_CONTROLPKT(eth_frmInfo) ) + return 0; + + TUInt32 tmp; + unsigned int replySz; + const unsigned int hdrSzByte = ((4/*eth*/ + 5/*ip*/ + 2/*udp*/)*4); + + // Start processing commands. They start immediately following + // the UDP/IP header. Write the results into the reply packet, + // immediately following the UDP header + replySz = proc_packet( (alt_u32 volatile*)((unsigned char volatile* const)rx+hdrSzByte), + (alt_u32 volatile*)((unsigned char volatile* const)tx+hdrSzByte) ); + // replySz is now in units of words. We need bytes + replySz *= 4; + + // Update the IP and UDP headers with the reply size + // IP: TOTAL LENGTH field is lower 16 bits in header word 4 + // it is ip hdr + udp hdr + udp payload = + // |---28 bytes --| + payloadsize + // UDP: SIZE is upper 16 bits in word 10 of the header + // its value is udp hdr + udp payload + // | 8 byte| + udp payload + + // Get word 4 from the header (note: they are still in + // network byte order), clear the lower 16bits + // tmp = ntohl(NET_HDRWORD(ptReply, 4)); + tmp = UNBOSX_UTIL_ntohl(tx[4]); + tmp &= 0xffff0000; + tmp |= ((28+replySz)&0x0000ffff); + tx[4] = UNBOSX_UTIL_htonl(tmp); + + // Id. for the UDP header + // tmp = ntohl(NET_HDRWORD(ptReply, 10)); + tmp = UNBOSX_UTIL_ntohl(tx[10]); + tmp &= 0x0000ffff; + tmp |= (((8+replySz)&0x0000ffff)<<16); + tx[10] = UNBOSX_UTIL_htonl(tmp); + + // return the total replysize + return (44 + replySz); +} + + +alt_u32 and_f(alt_u32 l, alt_u32 r) { + return (l&r); +} +alt_u32 or_f(alt_u32 l, alt_u32 r) { + return (l|r); +} +alt_u32 xor_f(alt_u32 l, alt_u32 r) { + return (l^r); +} + +/* Implicitly make use of the externally provided mask ... */ +alt_u32 bit_write_f(alt_u32 l, alt_u32 r) { + /* Clear the bitpositions in the current value */ + l &= (~bitfield_mask); + return (l | (r&bitfield_mask)); +} + +alt_u32 apply(alt_u32* dst, alt_u32* src, unsigned int n, alt_u32 (*f)(alt_u32, alt_u32)); + +static char const* const pps0 = "0PPS"; +static char const* const pps1 = "1PPS"; +/* start processing commands startting at "sop" (start of packet) + * building up the reply starting at "reply". + * processing stops when a 0x00 command is encountered + * Returns the size of the reply + * + * As per the revised command format, all fields are by definition + * a multiple of four bytes AND the addresses are four-byte aligned. + * This makes processing a pakkit of commands mighty simple: we + * do not have to copy field into local storage before we can use + * them, we can create pointers and directly de-reference them! + * w00t. + */ +alt_u32 proc_packet(alt_u32 volatile* sop, alt_u32 volatile* reply) { + alt_u32 nitem; + alt_u32 address; + alt_u32* data; + alt_u32 sinc, dinc; + alt_u32 volatile* begin_of_reply = reply; + + /* Copy over the PSN */ + + *reply++ = *sop++; + while( *sop ) { + /* start with default source-inc and dest-inc of '1' */ + sinc = dinc = 1; + switch( *sop ) { + + case WAITPPS: + if( UNBOS_pps_wait() ) + *((alt_u32*)reply) = *((alt_u32*)&pps1[0]); + else + *((alt_u32*)reply) = *((alt_u32*)&pps0[0]); + reply++; + sop++; + break; + + case FREADN: + /* FIFO Read: do not increment source address */ + sinc = 0; + case READN: + /* read n 32bit words, starting at address address */ + /* N is the word following the READ command, the start address + * follows after that + * READN (32bit) N (32bit) ADDRESS (32bit) + */ + nitem = *(sop+1); + address = *(sop+2); + if( io2_copy((void*)(reply+1), (void*)address, nitem, sinc, dinc)==0 ) { + /* indicate failure */ + address = ~address; + nitem = 0; + } + *reply = address; + reply += (nitem+1); + /* Update pointer to start of next command */ + sop += 3; + break; + + case BITWRITEN: + /* modify n 32bit words from the packet to the range starting at address address, + * using mask to update only part of the bits + * BITWRITEN (32bit) N (32bit) ADDRESS (32bit) MASK(32bit) DATA (N*32bit) + */ + nitem = *(sop+1); + address = *(sop+2); + /* set global bitfield mask before entering the apply function!*/ + bitfield_mask = (alt_u32)(*(sop+3)); + data = (alt_u32*)(sop+4); + if( apply((alt_u32*)address, data, nitem, bit_write_f)==0 ) + address = ~address; + *reply++ = address; + sop += (4+nitem); + break; + + case FWRITEN: + /* FIFO Write: do not increment dest address */ + dinc = 0; + case WRITEN: + case ANDN: + case ORN: + case XORN: + /* modify n 32bit words from the packet to the range starting at address address + * WRITEN (32bit) N (32bit) ADDRESS (32bit) DATA (N*32bit) + */ + nitem = *(sop+1); + address = *(sop+2); + data = (alt_u32*)(sop+3); + if( ((*sop==WRITEN || *sop==FWRITEN) && io2_copy((void*)address, (void*)data, nitem, sinc, dinc)==0) || + ((*sop==ANDN) && apply((alt_u32*)address, data, nitem, and_f)==0) || + ((*sop==ORN) && apply((alt_u32*)address, data, nitem, or_f)==0) || + ((*sop==XORN) && apply((alt_u32*)address, data, nitem, xor_f)==0) ) { + /* indicate failure */ + address = ~address; + } + *reply++ = address; + sop += (nitem+3); + break; + + case CONFIGW: + // write a single page of config data. + // command format is + // CONFIGW (32bit) ADDRESS(32bit) DATA(256 bytes) + address = *(sop+1); + data = (alt_u32*)(sop+2); + if( (*flash_writer)((void*)address, (void*)data)==0 ) + address = ~address; + *reply++ = address; + sop += (2 + (256/sizeof(alt_u32))); + break; + + case CONFIGR: + // read a single page of config data. + // command format is + // CONFIGR (32bit) ADDRESS(32bit) + // Skip one word in the reply (for the address or + // ~address) at which we write the actual data + address = *(sop+1); + data = (alt_u32*)(reply+1); + if( (*flash_reader)((void*)data, (void*)address)==0 ) { + *reply++ = ~address; + } else { + *reply++ = address; + reply += (256/sizeof(alt_u32)); + } + // Skip over to the next command in the input sequence + sop += 2; + break; + + case CONFIGE: + // erase the config sector where the ADDRESS points into + // command format is + // CONFIGE (32bit) ADDRESS(32bit) + address = *(sop+1); + if( (*flash_eraser)((void*)address)==0 ) + address = ~address; + *reply++ = address; + sop += 2; + break; + + default: + break; + } + } + return (alt_u32)(reply - begin_of_reply); +} + + + +alt_u32 apply(alt_u32* dst, alt_u32* src, unsigned int n, alt_u32 (*f)(alt_u32, alt_u32)) { + alt_u32 tmp; + + if( (((alt_u32)dst) & 0x3) || (((alt_u32)src) & 0x3) ) + return 0; + + while( n-- ) { + tmp = IORD(dst, 0); + tmp = f(tmp, *src); + IOWR(dst, 0, tmp); + dst++; src++; + } + return 1; +} + +int init_flash() { + if( didInitFlash==42 ) + didInitFlash = alt_epcs_flash_init(&tFlashDev); + return didInitFlash; +} + +alt_u32 init_flash_first_w(void* to, void* from) { + // depending on wether we succesfully initialized the + // flash device, set the actual flash-writer function + // and delegate the actual writing to there + if( init_flash()<0 ) { + flash_writer = no_flash_available; + } else { + flash_writer = flash_write_page; + } + return (*flash_writer)(to, from); +} +alt_u32 init_flash_first_r(void* to, void* from) { + // depending on wether we succesfully initialized the + // flash device, set the actual flash-writer function + // and delegate the actual writing to there + if( init_flash()<0 ) { + flash_reader = no_flash_available; + } else { + flash_reader = flash_read_page; + } + return (*flash_reader)(to, from); +} +alt_u32 init_flash_first_e(void* sectoraddress) { + // depending on wether we succesfully initialized the + // flash device, set the actual flash-eraser function + // and delegate the actual erasing to there + if( init_flash()<0 ) { + flash_eraser = no_flash_available1; + } else { + flash_eraser = flash_erase_sector; + } + return (*flash_eraser)(sectoraddress); +} + +// write one page of flashdata to the FLASH-address "to" +// the pages are 256 bytes each +alt_u32 flash_write_page(void* to, void* from) { + if( alt_epcs_flash_write_block((alt_flash_dev*)&tFlashDev, 0, (int)to, from, 256)<0 ) + return 0; + return 1; +} +// read one page of flashdata from the FLASH-address "from" +// the pages are 256 bytes each +alt_u32 flash_read_page(void* to, void* from) { + if( alt_epcs_flash_read((alt_flash_dev*)&tFlashDev, (int)from, to, 256)<0 ) + return 0; + return 1; +} +// erase the sector that sectoroffset is in +alt_u32 flash_erase_sector(void* sectoroffset) { + if( alt_epcs_flash_erase_block((alt_flash_dev*)&tFlashDev, (int)sectoroffset)<0 ) + return 0; + return 1; +} + +// the design has no flash - indicate failure +alt_u32 no_flash_available(void* i, void* o) { + return 0; +} + +alt_u32 no_flash_available1(void* i) { + return no_flash_available(i, (void*)0); +} + diff --git a/software/unb_osy/packet.h b/software/unb_osy/packet.h new file mode 100644 index 0000000000000000000000000000000000000000..1cf515d8d39e0d422c3618abb3c8d072cd963875 --- /dev/null +++ b/software/unb_osy/packet.h @@ -0,0 +1,8 @@ +/* process a network packet */ +#include <alt_types.h> + +unsigned int handlePacket(); + +alt_u32 proc_packet(alt_u32 volatile* sop, alt_u32 volatile* reply); + + diff --git a/software/unb_osy/unbos_eth.c b/software/unb_osy/unbos_eth.c new file mode 100644 index 0000000000000000000000000000000000000000..bfb8d5611b9ece122fccc539b5edbba817e546e7 --- /dev/null +++ b/software/unb_osy/unbos_eth.c @@ -0,0 +1,462 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +/* Compile switches. */ + +/* includes */ +#include <unbos_eth.h> +#include <unbos_i2c.h> +#include <osx_stdio.h> +#include <sys/alt_irq.h> +#include <altera_avalon_pio_regs.h> +#include <unbosx_eth_regs.h> +#include <io2_copy.h> + +TUInt32 netIP = 0; +TUInt32 netIP_nwbo = 0; +volatile TUInt32 eth_status = 0; +volatile TUInt32 eth_frmInfo = 0; +TUInt32 volatile* const rx = (TUInt32 volatile* const)(AVS_ETH_0_MMS_RAM_BASE+ETH_RX_RAM_BASE); +TUInt32 volatile* const tx = (TUInt32 volatile* const)(AVS_ETH_0_MMS_RAM_BASE+ETH_TX_RAM_BASE); + + +void UNBOSX_NET_Send(unsigned int nbyte) { + TUInt32 words, empty, ctrl = AVS_ETH_REG_CONTROL_RX_EN_BIT_MASK; + + // assume outsize is already including 2byte padding + words = nbyte/4; + empty = (4 - nbyte%4); + + // If the packet extends into a word (not filling it) + // we must inc the number of words and set the number + // of empty bytes accordingly + words += ((empty==4)?0:1); + empty = ((empty==4)?0:empty); + + // prepare the new control-register-variable + ctrl |= (words << AVS_ETH_REG_CONTROL_TX_NOF_WORDS_BIT_OFST); + ctrl |= (empty << AVS_ETH_REG_CONTROL_TX_EMPTY_BIT_OFST); + ctrl |= AVS_ETH_REG_CONTROL_TX_EN_BIT_MASK; + + // Now write new value of control register and the continue reg + WRREG(AVS_ETH_REG_CONTROL_WI, ctrl); + // clear global status + eth_status = 0; + eth_frmInfo = 0; + WRREG(AVS_ETH_REG_CONTINUE_WI, 0); +} + +void UNBOSX_NET_Discard() { + // Now write new value of control register and the continue reg + WRREG(AVS_ETH_REG_CONTROL_WI, AVS_ETH_REG_CONTROL_RX_EN_BIT_MASK); + // clear global status + eth_status = 0; + eth_frmInfo = 0; + WRREG(AVS_ETH_REG_CONTINUE_WI, 0); +} + +#if 0 +// IPv4 address is at maximum 4*3 digits + 3 dots + 1 NUL character = 16 characters +char const* NET_inet_ntoa(const TUInt32 ipv4addr) { + static char buffer[16]; + unsigned const char* const ip = (unsigned const char* const)(&ipv4addr); + osx_sprintf(buffer, "%d.%d.%d.%d", ip[3], ip[2], ip[1], ip[0]); + return &buffer[0]; +} +#endif +#if 0 +// Return the timedifference in clock_t ticks +// between new and old. +clock_t delta_t(clock_t old_t, clock_t new_t) { + const clock_t cClockMax = ~((~(clock_t)0)+1); + // if new_t < old_t assume the counter wrapped + if( new_t<old_t ) + return cClockMax - (old_t-new_t); + else + return new_t - old_t; +} +#endif + +#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT +static void net_isr(void* context); +#else +static void net_isr(void* context, alt_u32 id); +#endif + +/* Set up the network card */ +void UNBOSX_NET_Setup() { + TUInt32 netMAChi = UNB_ETH_SRC_MAC_BASE_HI; + TUInt32 netMAClo = (UNB_ETH_SRC_MAC_BASE_LO<<16); + TUInt32 base_ip = (TUInt32)AVS_ETH_REG_RD(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_CONFIG_WI+2); + +#if defined(COMPILE_FOR_GEN2_UNB2) +#warning "Compiling for UNB2" + const TUInt32 node = UNBOSX_unb2_GetNodeNumber(); + const TUInt32 backplane = UNBOSX_unb2_GetBackplaneId(); + osx_printf("backplane %d node %cN %d\n", + backplane, + (UNBOSX_unb2_IsBacknode()?'B':'F'), + node); +#else +#warning "Compiling for UNB1" + const TUInt32 node = UNBOSX_GetNodeNumber(); + const TUInt32 backplane = UNBOSX_GetBackplaneId(); + osx_printf("backplane %d node %cN %d\n", + backplane, + (UNBOSX_IsBacknode()?'B':'F'), + node); +#endif + + /* Use the ip range 10.99.xx.yy where + * xx = UNB_System_Info.bck_id [backplane ID] + * yy = (UNB_System_Info.id + 1) + * [0-3] = frontnode + * [4-7] = backnode + */ + if (base_ip==0) { + netIP = (TUInt32)0x0a630000 + (backplane<<8) + node + 1; + } else { + netIP = base_ip + (backplane<<8) + node + 1; + } + + netIP_nwbo = UNBOSX_UTIL_htonl(netIP); + netMAClo = (UNB_ETH_SRC_MAC_BASE_LO<<16) + (backplane<<8) + node; + + /* Now it's time to actually set things up */ + UNBOSX_ETH_Init_ISR(net_isr, 0); + UNBOSX_ETH_Setup(UNBOSX_G_SIM(), + netMAChi, netMAClo, ETH_FRAME_LENGTH, + netIP, 5000 /*UNB_UDP_PORT_CTRL*/, 0, 0, 0); + + osx_printf("setup_tse: ip=%d.%d.%d.%d\n", + netIP>>24, (netIP>>16)&0xff, (netIP>>8)&0xff, netIP&0xff); + + // and switch on rx_enable + WRREG(AVS_ETH_REG_CONTROL_WI, AVS_ETH_REG_CONTROL_RX_EN_BIT_MASK); + WRREG(AVS_ETH_REG_CONTINUE_WI, 0); + return; +} + +/* If it is an IPv4-ARP packet then word 4 in the rx buffer + * should look like this in NetworkByteOrder. + * This can be precomputed such that the ISR doesn't have + * to swap bytes */ +static const TUInt32 IPv4Arp_nwbo = (UNBOSX_UTIL_htonl(((1<<16)+0x0800))); +static const TUInt32 ArpReqMsk_nwbo = (UNBOSX_UTIL_htonl(0x0000ffff)); +static const TUInt32 ArpReqOne_nwbo = (UNBOSX_UTIL_htonl(1)); + +#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT +static void net_isr(void* context) { +#else +static void net_isr(void* context, alt_u32 id) { +#endif + /* + * If the ctrl reg at some point becomes !0 this indicates + * that WE (the ISR) have handled the packet - so we write + * it back to the hardware + * If the frmInfo != 0 at the end of the ISR, this means + * that that the user has to deal with the packet and + * we don't do nothing + */ + TUInt32 ctrl = 0; + volatile TUInt32 tmp; + + eth_status = RDREG(AVS_ETH_REG_STATUS_WI); + eth_frmInfo = (TUInt32)RDREG(AVS_ETH_REG_FRAME_WI); + // If there was in incoming packet, check if we deal with it *now* + if( RXAVAIL(eth_status) ) { + // If someone was looking for US (ARP request with us as target) + // then handle it here rather than passing it up the chain + TUInt32 isARP = NET_FLAGCHECK(eth_frmInfo, IS_ARP_BIT_MASK); + TUInt32 isICMP = NET_FLAGCHECK(eth_frmInfo, IS_ICMP_BIT_MASK); + + + // Only look at IP ARP requests + // Note: do not check the MAC_ADDRESS_MATCH_BIT_MASK in the + // status reg - ARP requests are typically eth broadcasts. + // If the ARP-IP-REQUEST-FOR-OUR-IP did not come from + // an ethernet broadcast ... who cares! + if( isARP ) { + // Check if: + // - It *is* an ARP request AND + // - Target Protocol == IPv4 AND + // - Target Protocol Address == Our IP Address + + // We recognized this packet as ARP - it may or may + // not be for us that's not important right now + // We *always* handle these packets - so we *always* must + // write the control register since either: + // * we want to send the cooked reply, or, + // * we want to discard it and immediately go back to + // receiving the next packet + // This is done by setting the RX_ENABLE bit. + // The TX enable bit will be set conditionally + ctrl = AVS_ETH_REG_CONTROL_RX_EN_BIT_MASK; + + if( (RDRX(4)==IPv4Arp_nwbo) && + ((RDRX(5)&ArpReqMsk_nwbo)==ArpReqOne_nwbo) && + (RDRX(10)==netIP_nwbo) ) { + // Great. Someone was loox0ring just for US. + // The hardware (thanks Eric!) has prepared the answer + // already in the TX buffer. Set it off and let the rest + // of the system forget about this pakkit + // send whatever is in the TX buffer + // The ip arp packet is exactly 11 32bit words long + // (so make sure the "empty" bit field contains 0) + ctrl |= (11 << AVS_ETH_REG_CONTROL_TX_NOF_WORDS_BIT_OFST); + ctrl &= ~AVS_ETH_REG_CONTROL_TX_EMPTY_BIT_MASK; + ctrl |= AVS_ETH_REG_CONTROL_TX_EN_BIT_MASK; + } + eth_frmInfo = 0; + eth_status = 0; + } + + // Or ICMP ECHO? directed at us + if( isICMP ) { + // Packet is ICMP - update stats. It may or may not be for us + // but that doesn't matter right now + // Indicate we already dealt with this'un + + // Again, as with the ARP thingy, we *always* tell the h/w + // what to do next. Sending the precooked reply is optional. + // + // Sending the reply depends, critically, on wether it was an ICMP echo request + // directed at us + ctrl = AVS_ETH_REG_CONTROL_RX_EN_BIT_MASK; + + if( NET_FLAGCHECK(eth_frmInfo, MAC_ADDRESS_MATCH_BIT_MASK) && /* our MAC, so far so good */ + NET_FLAGCHECK(eth_frmInfo, IP_ADDRESS_MATCH_BIT_MASK) && /* our IP! */ + ((UNBOSX_UTIL_ntohl(RDRX(9))>>24)==8) /* ICMP code 8 == "ECHO?" */ ) { + // Cool. The request was and ECHO REQUEST directed directly at US + // So 'code' becomes 0 (== ECHO REPLY) + // But the hardware has already done that. + // The hardware has NOT copied the payload across yet so we must do that + // (NOTE: it _has_ already copied over the first 11 words) + io2_copy(tx+11, rx+11, NWORD(eth_status)-11, 1, 1); + + // All that's left is to make sure that the number of + // bytes in the control reg are set correctly + ctrl |= ((NWORD(eth_status)-1) << AVS_ETH_REG_CONTROL_TX_NOF_WORDS_BIT_OFST); + ctrl |= (NEMPTY(eth_status) << AVS_ETH_REG_CONTROL_TX_EMPTY_BIT_OFST); + ctrl |= AVS_ETH_REG_CONTROL_TX_EN_BIT_MASK; + } + eth_frmInfo = 0; + eth_status = 0; + } + } + + // Write a '0' in order to clear the in-tar-upt source + WRREG(AVS_ETH_REG_STATUS_WI, 0); + // wait until interrupt source has cleared + do { + tmp = RDREG(AVS_ETH_REG_STATUS_WI); + } while( tmp!=0 ); + // Now write new value of control register and the continue reg + // (ctrl != 0 => the h/w should continue) + if( eth_frmInfo==0 ) { + WRREG(AVS_ETH_REG_CONTROL_WI, ctrl|AVS_ETH_REG_CONTROL_RX_EN_BIT_MASK); + WRREG(AVS_ETH_REG_CONTINUE_WI, 0); + } +} + + +/* ... */ +void UNBOSX_ETH_Init_ISR(isr_func_type isr_fn, void *p_isr_context) { + // Hook the ISR +#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT + alt_ic_isr_register(AVS_ETH_0_MMS_REG_IRQ_INTERRUPT_CONTROLLER_ID, + AVS_ETH_0_MMS_REG_IRQ, + isr_fn, + p_isr_context, + (void*)0); +#else + alt_irq_register(AVS_ETH_0_MMS_REG_IRQ, p_isr_context, isr_fn); +#endif +} + +/* announce prototype */ +static void UNBOSX_TSE_Setup(TBool g_sim, TUInt32 src_mac_hi, TUInt32 src_mac_lo, TUInt32 frm_length); + +/*------------------------------------------------------------------------------ + * Function name: ETH_Setup + * Parameters: g_sim = When true then running in simulation, else on hardware + * src_mac_hi = 0x1234, + * src_mac_lo = 0x56789ABC for MAC address 12-34-56-78-9A-BC + * frm_length = 1518 octets for ethernet, up to 9000 for jumbo + * src_ip = 0x07060504; -- = 07:06:05:04 + * udp_port_ctrl = Control UDP port number + * udp_port_data0 = Streaming data UDP port 0 number + enable bit mask + * udp_port_data1 = Streaming data UDP port 1 number + enable bit mask + * udp_port_data2 = Streaming data UDP port 2 number + enable bit mask + * Return: - + * Description: Set up the ETH registers, similar to p_eth_control in + * modules\tse\src\vhdl\tb_eth.vhd and call TSE_Setup to set up + * the TSE MAC. + *------------------------------------------------------------------------------ + */ +void UNBOSX_ETH_Setup(TBool g_sim, + TUInt32 src_mac_hi, TUInt32 src_mac_lo, TUInt32 frm_length, TUInt32 src_ip, TUInt32 udp_port_ctrl, + TUInt32 udp_port_data0, TUInt32 udp_port_data1, TUInt32 udp_port_data2) +{ + // Setup the DEMUX UDP + AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_DEMUX_WI+0, udp_port_data0); + AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_DEMUX_WI+1, udp_port_data1); + AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_DEMUX_WI+2, udp_port_data2); + + // Setup the RX CONFIG + AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_CONFIG_WI+0, src_mac_lo); + AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_CONFIG_WI+1, src_mac_hi); + AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_CONFIG_WI+2, src_ip); + AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_CONFIG_WI+3, udp_port_ctrl); + + // Enable RX + AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, AVS_ETH_REG_CONTROL_WI, AVS_ETH_REG_CONTROL_RX_EN_BIT_MASK); + + // Setup the TSE MAC + UNBOSX_TSE_Setup(g_sim, src_mac_hi, src_mac_lo, frm_length); +} + +/*------------------------------------------------------------------------------ + * Function name: TSE_Setup + * Parameters: g_sim = When true then running in simulation, else on hardware + * src_mac_hi = 0x1234, + * src_mac_lo = 0x56789ABC for MAC address 12-34-56-78-9A-BC + * frm_length = 1518 octets for ethernet, up to 9000 for jumbo + * Return: - + * Description: Set up the TSE MAC, similar to proc_tse_setup in + * modules\tse\src\vhdl\tb_tse(pkg).vhd. The read accesses + * are void, because the result is not used further. + *------------------------------------------------------------------------------ + */ +static void UNBOSX_TSE_Setup(TBool g_sim, TUInt32 src_mac_hi, TUInt32 src_mac_lo, TUInt32 frm_length) { + TUInt16 pcs_data; + TUInt32 mac_data; + TUInt32 mac_0; + TUInt32 mac_1; + + // PSC control + pcs_data = AVS_ETH_TSE_PCS_RD(AVS_ETH_0_MMS_TSE_BASE, 0x22); // REV --> 0x0901 + AVS_ETH_TSE_PCS_WR(AVS_ETH_0_MMS_TSE_BASE, 0x28, 0x0008); // IF_MODE <-- 0x0008 = Enable 1000BASE-X gigabit mode and gigabit speed + pcs_data = AVS_ETH_TSE_PCS_RD(AVS_ETH_0_MMS_TSE_BASE, 0x00); // CONTROL --> 0x1140 = Gigabit speed and full duplex (RO), auto-negotiation enabled (RW) + pcs_data = AVS_ETH_TSE_PCS_RD(AVS_ETH_0_MMS_TSE_BASE, 0x02); // STATUS --> 0x002D + #if ETH_LOOPBACK_PCS == FALSE + #define LOOP_PCS 0 + #else + #define LOOP_PCS (0x4000) + #endif + if (g_sim==FALSE) { + AVS_ETH_TSE_PCS_WR(AVS_ETH_0_MMS_TSE_BASE, 0x00, 0x1140 + LOOP_PCS); // CONTROL <-- Keep auto negotiate enabled (is reset default) + } else { + AVS_ETH_TSE_PCS_WR(AVS_ETH_0_MMS_TSE_BASE, 0x00, 0x0140 + LOOP_PCS); // CONTROL <-- In simulation disable auto negotiate + } + + // MAC control + mac_data = AVS_ETH_TSE_MAC_RD(AVS_ETH_0_MMS_TSE_BASE, 0x000); // REV --> CUST_VERSION & 0x0901 + + // COMMAND_CONFIG bits + // Only the bits relevant to UniBoard are explained here, others are 0 + // [ 0] = TX_ENA = 1, enable tx datapath + // [ 1] = RX_ENA = 1, enable rx datapath + // [ 2] = XON_GEN = 0 + // [ 3] = ETH_SPEED = 1, enable 1GbE operation + // [ 4] = PROMIS_EN = 0, when 1 then receive all frames + // [ 5] = PAD_EN = 0, when 1 enable receive padding removal (requires ethertype=payload length) + // [ 6] = CRC_FWD = 1, enable receive CRC forward + // [ 7] = PAUSE_FWD = 0 + // [ 8] = PAUSE_IGNORE = 0 + // [ 9] = TX_ADDR_INS = 0, when 1 then MAX overwrites tx SRC MAC with mac_0,1 or one of the supplemental mac + // [ 10] = HD_ENA = 0 + // [ 11] = EXCESS_COL = 0 + // [ 12] = LATE_COL = 0 + // [ 13] = SW_RESET = 0, when 1 MAC disables tx and rx, clear statistics and flushes receive FIFO + // [ 14] = MHAS_SEL = 0, select multicast address resolutions hash-code mode + // [ 15] = LOOP_ENA = 0 + // [18-16] = TX_ADDR_SEL[2:0] = 000, TX_ADDR_INS insert mac_0,1 or one of the supplemental mac + // [ 19] = MAGIC_EN = 0 + // [ 20] = SLEEP = 0 + // [ 21] = WAKEUP = 0 + // [ 22] = XOFF_GEN = 0 + // [ 23] = CNT_FRM_ENA = 0 + // [ 24] = NO_LGTH_CHECK = 1, when 0 then check payload length of received frames (requires ethertype=payload length) + // [ 25] = ENA_10 = 0 + // [ 26] = RX_ERR_DISC = 0, when 1 then discard erroneous frames (requires store and forward mode, so rx_section_full=0) + // when 0 then pass on with rx_err[0]=1 + // [ 27] = DISABLE_RD_TIMEOUT = 0 + // [30-28] = RSVD = 000 + // [ 31] = CNT_RESET = 0, when 1 clear statistics + #if ETH_LOOPBACK_MAC==FALSE + #define LOOP_ENA 0 + #else + #define LOOP_ENA (0x00008000) + #endif + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x008, 0x0100004B + LOOP_ENA); // COMMAND_CONFIG <-- + + // The SRC_MAC address for the TSE MAC needs to be in big endian + // Example: + // - MAC address 12-34-56-78-9A-BC + // - Input little endian: + // . src_mac_lo = 0x56789ABC + // . src_mac_hi = 0x1234 + // - Output big endian: + // . mac_0 = 0x78563412 + // . mac_1 = 0xBC9A + mac_0 = UNBOSX_UTIL_htonl(((src_mac_hi << 16) + (src_mac_lo >> 16))); + mac_1 = UNBOSX_UTIL_htonl(src_mac_lo << 16); + + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x00C, mac_0); // MAC_0 + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x010, mac_1); // MAC_1 + + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x05C, 0x0000000C); // X_IPG_LENGTH <-- interpacket gap = 12 + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x014, frm_length); // FRM_LENGTH <-- receive max frame length = 1518 + + // FIFO legenda: + // . Tx section full = There is enough data in the FIFO to start reading it, when 0 then store and forward. + // . Rx section full = There is enough data in the FIFO to start reading it, when 0 then store and forward. + // . Tx section empty = There is not much empty space anymore in the FIFO, warn user via ff_tx_septy + // . Rx section empty = There is not much empty space anymore in the FIFO, inform remote device via XOFF flow control + // . Tx almost full = Assert ff_tx_a_full and deassert ff_tx_rdy. Furthermore TX_ALMOST_FULL = c_tx_ready_latency+3, + // so choose 3 for zero tx ready latency + // . Rx almost full = Assert ff_rx_a_full and if the user is not ready ff_rx_rdy then: + // --> break off the reception with an error to avoid FIFO overflow + // . Tx almost empty = Assert ff_tx_a_empty and if the FIFO does not contain a eop yet then: + // --> break off the transmission with an error to avoid FIFO underflow + // . Rx almost empty = Assert ff_rx_a_empty + // Typical FIFO values: + // . TX_SECTION_FULL = 16 > 8 = TX_ALMOST_EMPTY + // . RX_SECTION_FULL = 16 > 8 = RX_ALMOST_EMPTY + // . TX_SECTION_EMPTY = D-16 < D-3 = Tx FIFO depth - TX_ALMOST_FULL + // . RX_SECTION_EMPTY = D-16 < D-8 = Rx FIFO depth - RX_ALMOST_FULL + // . c_tse_tx_fifo_depth = 1 M9K = 256*32b = 1k * 8b is sufficient when the Tx user respects ff_tx_rdy, to store a complete + // ETH packet would require 1518 byte, so 2 M9K = 2k * 8b + // . c_tse_rx_fifo_depth = 1 M9K = 256*32b = 1k * 8b is sufficient when the Rx user ff_rx_rdy is sufficiently active + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x01C, AVS_ETH_TSE_RX_FIFO_DEPTH-16); // RX_SECTION_EMPTY <-- default FIFO depth - 16, >3 + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x020, 16); // RX_SECTION_FULL <-- default 16 + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x024, AVS_ETH_TSE_TX_FIFO_DEPTH-16); // TX_SECTION_EMPTY <-- default FIFO depth - 16, >3 + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x028, 16); // TX_SECTION_FULL <-- default 16, >~ 8 otherwise no tx + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x02C, 8); // RX_ALMOST_EMPTY <-- default 8 + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x030, 8); // RX_ALMOST_FULL <-- default 8 + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x034, 8); // TX_ALMOST_EMPTY <-- default 8 + AVS_ETH_TSE_MAC_WR(AVS_ETH_0_MMS_TSE_BASE, 0x038, AVS_ETH_TSE_TX_READY_LATENCY+3); // TX_ALMOST_FULL <-- default 3 + + mac_data = AVS_ETH_TSE_MAC_RD(AVS_ETH_0_MMS_TSE_BASE, 0x0E8); // TX_CMD_STAT --> 0x00040000 : [18]=1 TX_SHIFT16, [17]=0 OMIT_CRC + mac_data = AVS_ETH_TSE_MAC_RD(AVS_ETH_0_MMS_TSE_BASE, 0x0EC); // RX_CMD_STAT --> 0x02000000 : [25]=1 RX_SHIFT16 +} diff --git a/software/unb_osy/unbos_eth.h b/software/unb_osy/unbos_eth.h new file mode 100644 index 0000000000000000000000000000000000000000..1a16a87f039dfd870d39070b00c804fe7785d5d7 --- /dev/null +++ b/software/unb_osy/unbos_eth.h @@ -0,0 +1,131 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ +#ifndef UNBOS_ETH_H +#define UNBOS_ETH_H + +/* includes */ +#include <system.h> +#include <unbosx_types.h> +#include <unbosx_eth_regs.h> +#include <unbosx_util.h> + +/* We ABSOLUTELY need the AVS_ETH thingamabob so we're not going to + * conditionally compile this file */ + +// Start address of the rx and tx frame in the frame buffer +#define ETH_RX_RAM_BASE 0 +#define ETH_TX_RAM_BASE (AVS_ETH_0_MMS_RAM_SPAN/2) +#define ETH_FRAME_LENGTH 1518 +#define UNB_ETH_SRC_MAC_BASE ((TUInt32)0x00228608) +#define UNB_ETH_SRC_MAC_BASE_HI ((UNB_ETH_SRC_MAC_BASE >> 16) & 0xFFFF) +#define UNB_ETH_SRC_MAC_BASE_LO ( UNB_ETH_SRC_MAC_BASE & 0xFFFF) + +#if 0 +/* translate an ip number to ASCII 'dotted quad' format */ +char const* NET_inet_ntoa(const TUInt32 ipv4addr); +#endif + +/* Initialize the ETH hardware and this module */ +void UNBOSX_NET_Setup(void); + +/* send nbyte from TX buffer to network. + * it is YOUR responsibility to make sure there is + * a valid packet there + * + * NOTE: you HAVE to take into account that the + * first two bytes in the TX buffer are padding bytes + * so the amount of bytes you wish to send should + * be 2 larger than you actually think + */ +void UNBOSX_NET_Send(unsigned int nbyte); + +/* this lets the main loop decide to not send a reply but + * discard whatever's in the TX buffer. Reenables RX'ing + * packets. TX buffer contents will be lost. + */ +void UNBOSX_NET_Discard(); +/* Uses the WORDS and EMPTY fields in the status to work out how many + * bytes were received */ +//unsigned int NET_BytesReceived(TUInt32 status); + +// The AVS ETH has two regs: a control and a status one +// Upon receipt of a packet eth_frmInfo != 0 +extern volatile TUInt32 eth_status; +extern volatile TUInt32 eth_frmInfo; + +/* + * Two buffers: one for RX and one for TX + * * Remember the actual start of the ethernetheader + * (the first header you must write in the + * packetbuffer) starts at byte #2. Byte 0 and 1 + * in the buffer are padding bytes in order to + * make, eventually, the IP and/or UDP payloads + * start at a 4-byte-aligned address. + * * When done, set the member to the full + * packetssize + 2 bytes (for the padding, remember). + */ + +extern TUInt32 volatile* const rx; +extern TUInt32 volatile* const tx; + +// Shorthands for inspecting/extracting bits from the status register +#define TXAVAIL(status) ((status&AVS_ETH_REG_STATUS_TX_AVAIL_BIT_MASK)==AVS_ETH_REG_STATUS_TX_AVAIL_BIT_MASK) +#define RXAVAIL(status) ((status&AVS_ETH_REG_STATUS_RX_AVAIL_BIT_MASK)==AVS_ETH_REG_STATUS_RX_AVAIL_BIT_MASK) +#define NWORD(status) ((status&AVS_ETH_REG_STATUS_RX_NOF_WORDS_BIT_MASK)>>AVS_ETH_REG_STATUS_RX_NOF_WORDS_BIT_OFST) +#define NEMPTY(status) ((status&AVS_ETH_REG_STATUS_RX_EMPTY_BIT_MASK)>>AVS_ETH_REG_STATUS_RX_EMPTY_BIT_OFST) + +// Shorthands for reading/writing regiters and RAM buffers +#define RDRX(idx) ((TUInt32)AVS_ETH_RAM_RD(AVS_ETH_0_MMS_RAM_BASE+ETH_RX_RAM_BASE, idx)) +#define RDTX(idx) ((TUInt32)AVS_ETH_RAM_RD(AVS_ETH_0_MMS_RAM_BASE+ETH_TX_RAM_BASE, idx)) +#define WRTX(idx, w) (AVS_ETH_RAM_WR(AVS_ETH_0_MMS_RAM_BASE+ETH_TX_RAM_BASE, idx, w)) +#define RDREG(idx) ((TUInt32)AVS_ETH_REG_RD(AVS_ETH_0_MMS_REG_BASE, idx)) +#define WRREG(idx, w) (AVS_ETH_REG_WR(AVS_ETH_0_MMS_REG_BASE, idx, w)) + +// The AVS_ETH module sets flags in the frameInfo register depending on what kind of +// packet is received. Use these shorthands for easy access to them. +#define NET_FLAGCHECK(frameInfo,flag) \ + ((frameInfo&AVS_ETH_REG_FRAME_##flag)==AVS_ETH_REG_FRAME_##flag) +#define NET_CHECK(frameInfo,flag) \ + NET_FLAGCHECK(frameInfo,flag) +#define NET_IS_ARP(frameInfo) NET_CHECK(frameInfo, IS_ARP_BIT_MASK) +#define NET_IS_IP(frameInfo) NET_CHECK(frameInfo, IS_IP_BIT_MASK) +#define NET_IPCHECKSUM_OK(frameInfo) NET_CHECK(frameInfo, IP_CHECKSUM_OK_BIT_MASK) +#define NET_IS_ICMP(frameInfo) NET_CHECK(frameInfo, IS_ICMP_BIT_MASK) +#define NET_IS_UDP(frameInfo) NET_CHECK(frameInfo, IS_UDP_BIT_MASK) +#define NET_IS_CONTROLPKT(frameInfo) NET_CHECK(frameInfo, IS_UDP_CTRL_PORT_BIT_MASK) + +/* depending on what kind of interrupt API we set the type of ISR function pointer we expect */ +#ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT +typedef void (*isr_func_type)(void*); +#else +typedef void (*isr_func_type)(void*, alt_u32); +#endif + +/* Init + install the ISR of your choice */ +void UNBOSX_ETH_Init_ISR(isr_func_type isr_fn, void *p_isr_context); + +/* Setup the AVS_ETH module with a MAC address and other IP properties */ +void UNBOSX_ETH_Setup(TBool g_sim, + TUInt32 src_mac_hi, TUInt32 src_mac_lo, TUInt32 frm_length, TUInt32 src_ip, TUInt32 udp_port_ctrl, + TUInt32 udp_port_data0, TUInt32 udp_port_data1, TUInt32 udp_port_data2); + +#endif // UNBOS_ETH_H diff --git a/software/unb_osy/unbos_i2c.c b/software/unb_osy/unbos_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..fdda6037a875a842f9289ea6613dea309c6a3991 --- /dev/null +++ b/software/unb_osy/unbos_i2c.c @@ -0,0 +1,69 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ +#include <unbos_i2c.h> + +/* Compile switches. */ + +/* includes */ +#include "system.h" + +#ifdef __AVS_I2C_MASTER + // System has I2C + + /* private constants (#define) */ + + /* private macros */ + + /* private types */ + + /* private function protos */ + #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT + static void i2c_isr(void* p) + #else + static void i2c_isr(void* p, alt_u32 id) + #endif + { + // Read the control register to clear the in-tar-upt + AVS_I2C_MASTER_REG_RD_CONTROL(AVS_I2C_MASTER_SENS_CONTROL_BASE); + } + + /* private constants (const) */ + + /* private variables */ + + /* public variables */ + + /* public function implements */ + void UNBOS_i2c_init(void) { + #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT + alt_ic_isr_register(AVS_I2C_MASTER_SENS_CONTROL_IRQ_INTERRUPT_CONTROLLER_ID, + AVS_I2C_MASTER_SENS_CONTROL_IRQ, + i2c_isr, + (void *)0, + (void *)0); + #else + alt_irq_register(AVS_I2C_MASTER_SENS_CONTROL_IRQ, (void *)0, i2c_isr); + #endif + } + +#endif // __AVS_I2C_MASTER + diff --git a/software/unb_osy/unbos_i2c.h b/software/unb_osy/unbos_i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..1ddda57a32510bbe349c863c9cdfd4ce8139f62a --- /dev/null +++ b/software/unb_osy/unbos_i2c.h @@ -0,0 +1,61 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ +#ifndef UNBOS_I2C_H +#define UNBOS_I2C_H + +/* Compile switches. */ + +/* includes */ +#include <system.h> + +#ifdef __AVS_I2C_MASTER + // System has I2C + #include <sys/alt_irq.h> +// #include <osx_irq.h> + #include <alt_types.h> + #include <avs_i2c_master_regs.h> + + /* private constants (#define) */ + + /* private macros */ + + /* private types */ + + /* private function protos */ + + /* private constants (const) */ + + /* private variables */ + + /* public variables */ + + /* public function implements */ + void UNBOS_i2c_init(void); + +#else + + /* system does NOT have I2C */ + #define UNBOS_i2c_init() do { } while( 0 ); + +#endif + +#endif // UNBOS_I2C_H diff --git a/software/unb_osy/unbos_pps.c b/software/unb_osy/unbos_pps.c new file mode 100644 index 0000000000000000000000000000000000000000..48df35aaf69572223686876b0ceac773ae5ae956 --- /dev/null +++ b/software/unb_osy/unbos_pps.c @@ -0,0 +1,25 @@ +#include <unbos_pps.h> +#include <osx_timer.h> +#include <unbosx_util.h> + +// Only do an implementation if there is one +#ifdef PIO_PPS_BASE + +// Poll the PPS-level (bit 31) for it +// to toggle. Do not forget to yank the +// watchdog every now and then ... +int UNBOS_pps_wait( void ) { + alt_u32 pps_info, pps_level; + clock_t stop = TIMER_0_TICKS_PER_SEC + (TIMER_0_TICKS_PER_SEC>>7); + + pps_info = IORD_ALTERA_AVALON_PIO_DATA(PIO_PPS_BASE); + pps_level = pps_info & 0x80000000; + stop += osx_clock(); + do { + pps_info = IORD_ALTERA_AVALON_PIO_DATA(PIO_PPS_BASE); + pps_info &= 0x80000000; + UNBOSX_ResetWatchdog(); + } while( (pps_info^pps_level)==0 && osx_clock()<stop ); + return (pps_info^pps_level); +} +#endif diff --git a/software/unb_osy/unbos_pps.h b/software/unb_osy/unbos_pps.h new file mode 100644 index 0000000000000000000000000000000000000000..f5874957f5fb0656034674f0f399577a978eca23 --- /dev/null +++ b/software/unb_osy/unbos_pps.h @@ -0,0 +1,61 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ +#ifndef UNBOS_PPS_H +#define UNBOS_PPS_H + +/* Compile switches. */ + +/* includes */ +#include <system.h> + +/* If "system.h" defines PIO_PPS_BASE it's safe to + * assume the system has the PPS PIO register in it ... */ +#ifdef PIO_PPS_BASE + // System has PPS + #include <alt_types.h> + #include <altera_avalon_pio_regs.h> + + /* private constants (#define) */ + + /* private macros */ + + /* private types */ + + /* private function protos */ + + /* private constants (const) */ + + /* private variables */ + + /* public variables */ + + /* public function implements */ + int UNBOS_pps_wait(void); + +#else + + /* system does NOT have a 1PPS */ + #define UNBOS_pps_wait() 0 + +#endif + +#endif // UNBOS_PPS_H diff --git a/software/unb_osy/unbosx_eth_regs.h b/software/unb_osy/unbosx_eth_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..f79e53535f6e2b6112e3b2133df984a53fd94fc6 --- /dev/null +++ b/software/unb_osy/unbosx_eth_regs.h @@ -0,0 +1,148 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2010 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +#ifndef AVS_ETH_REGS_H +#define AVS_ETH_REGS_H + +/* includes */ +#include "io.h" + +/* public constants */ + +// TSE MAC registers +#define AVS_ETH_TSE_PCS_ADDR_BASE (0x200) +#define AVS_ETH_TSE_RX_FIFO_DEPTH 256 +#define AVS_ETH_TSE_TX_FIFO_DEPTH 256 +#define AVS_ETH_TSE_TX_READY_LATENCY 1 + +#define AVS_ETH_TSE_PCS_LINK_STATUS_BIT (0x4) + +// ETH registers +#define AVS_ETH_DEMUX_NOF_UDP_PORTS 4 + +#define AVS_ETH_REG_DEMUX_NOF_WORDS AVS_ETH_DEMUX_NOF_UDP_PORTS +#define AVS_ETH_REG_CONFIG_NOF_WORDS 4 +#define AVS_ETH_REG_CONTROL_NOF_WORDS 1 +#define AVS_ETH_REG_FRAME_NOF_WORDS 1 +#define AVS_ETH_REG_STATUS_NOF_WORDS 1 + +#define AVS_ETH_REG_DEMUX_WI 0 +#define AVS_ETH_REG_CONFIG_WI (AVS_ETH_REG_DEMUX_WI + AVS_ETH_REG_DEMUX_NOF_WORDS) +#define AVS_ETH_REG_CONTROL_WI (AVS_ETH_REG_CONFIG_WI + AVS_ETH_REG_CONFIG_NOF_WORDS) +#define AVS_ETH_REG_FRAME_WI (AVS_ETH_REG_CONTROL_WI + AVS_ETH_REG_CONTROL_NOF_WORDS) +#define AVS_ETH_REG_STATUS_WI (AVS_ETH_REG_FRAME_WI + AVS_ETH_REG_FRAME_NOF_WORDS) +#define AVS_ETH_REG_CONTINUE_WI (AVS_ETH_REG_STATUS_WI + AVS_ETH_REG_STATUS_NOF_WORDS) + +// AVS_ETH_REG_DEMUX fields +#define AVS_ETH_UDP_PORT_MASK (0xFFFF) +#define AVS_ETH_UDP_PORT_OFST 0 +#define AVS_ETH_UDP_PORT_EN_BIT_MASK (0x10000) +#define AVS_ETH_UDP_PORT_EN_BIT_OFST 16 + +// AVS_ETH_REG_CONFIG words +#define AVS_ETH_REG_CONFIG_SRC_MAC_LO AVS_ETH_REG_CONFIG_WI +#define AVS_ETH_REG_CONFIG_SRC_MAC_HI (AVS_ETH_REG_CONFIG_WI + 1) +#define AVS_ETH_REG_CONFIG_SRC_IP (AVS_ETH_REG_CONFIG_WI + 2) +#define AVS_ETH_REG_CONFIG_CTRL (AVS_ETH_REG_CONFIG_WI + 3) + +// AVS_ETH_REG_CONTROL fields +#define AVS_ETH_REG_CONTROL_RX_EN_BIT_MASK (0x1) +#define AVS_ETH_REG_CONTROL_RX_EN_BIT_OFST 0 +#define AVS_ETH_REG_CONTROL_TX_EN_BIT_MASK (0x2) +#define AVS_ETH_REG_CONTROL_TX_EN_BIT_OFST 1 +#define AVS_ETH_REG_CONTROL_TX_REQUEST_BIT_MASK (0x4) +#define AVS_ETH_REG_CONTROL_TX_REQUEST_BIT_OFST 2 +#define AVS_ETH_REG_CONTROL_TX_EMPTY_BIT_MASK (0x30000) +#define AVS_ETH_REG_CONTROL_TX_EMPTY_BIT_OFST 16 +#define AVS_ETH_REG_CONTROL_TX_NOF_WORDS_BIT_MASK (0xFFFC0000) +#define AVS_ETH_REG_CONTROL_TX_NOF_WORDS_BIT_OFST 18 + +// AVS_ETH_REG_FRAME fields +#define AVS_ETH_TSE_MAC_ERROR_BIT_MASK (0x1) +#define AVS_ETH_TSE_MAC_ERROR_BIT_OFST 0 +#define AVS_ETH_TSE_MAC_ERROR_LENGTH_BIT_MASK (0x2) +#define AVS_ETH_TSE_MAC_ERROR_LENGTH_BIT_OFST 1 +#define AVS_ETH_TSE_MAC_ERROR_CRC_BIT_MASK (0x4) +#define AVS_ETH_TSE_MAC_ERROR_CRC_BIT_OFST 2 +#define AVS_ETH_TSE_MAC_ERROR_FIFO_BIT_MASK (0x8) +#define AVS_ETH_TSE_MAC_ERROR_FIFO_BIT_OFST 3 +#define AVS_ETH_TSE_MAC_ERROR_PHY_GMII_BIT_MASK (0x10) +#define AVS_ETH_TSE_MAC_ERROR_PHY_GMII_BIT_OFST 4 +#define AVS_ETH_TSE_MAC_ERROR_COLLISION_BIT_MASK (0x20) +#define AVS_ETH_TSE_MAC_ERROR_COLLISION_BIT_OFST 5 + +#define AVS_ETH_REG_FRAME_MAC_ADDRESS_MATCH_BIT_MASK (0x80) +#define AVS_ETH_REG_FRAME_MAC_ADDRESS_MATCH_BIT_OFST 7 +#define AVS_ETH_REG_FRAME_IS_ARP_BIT_MASK (0x100) +#define AVS_ETH_REG_FRAME_IS_ARP_BIT_OFST 8 +#define AVS_ETH_REG_FRAME_IS_IP_BIT_MASK (0x200) +#define AVS_ETH_REG_FRAME_IS_IP_BIT_OFST 9 +#define AVS_ETH_REG_FRAME_IP_CHECKSUM_OK_BIT_MASK (0x400) +#define AVS_ETH_REG_FRAME_IP_CHECKSUM_OK_BIT_OFST 10 +#define AVS_ETH_REG_FRAME_IP_ADDRESS_MATCH_BIT_MASK (0x800) +#define AVS_ETH_REG_FRAME_IP_ADDRESS_MATCH_BIT_OFST 11 +#define AVS_ETH_REG_FRAME_IS_ICMP_BIT_MASK (0x1000) +#define AVS_ETH_REG_FRAME_IS_ICMP_BIT_OFST 12 +#define AVS_ETH_REG_FRAME_IS_UDP_BIT_MASK (0x2000) +#define AVS_ETH_REG_FRAME_IS_UDP_BIT_OFST 13 +#define AVS_ETH_REG_FRAME_IS_UDP_CTRL_PORT_BIT_MASK (0x4000) +#define AVS_ETH_REG_FRAME_IS_UDP_CTRL_PORT_BIT_OFST 14 + +// AVS_ETH_REG_STATUS fields +#define AVS_ETH_REG_STATUS_RX_AVAIL_BIT_MASK (0x1) +#define AVS_ETH_REG_STATUS_RX_AVAIL_BIT_OFST 0 +#define AVS_ETH_REG_STATUS_TX_DONE_BIT_MASK (0x2) +#define AVS_ETH_REG_STATUS_TX_DONE_BIT_OFST 1 +#define AVS_ETH_REG_STATUS_TX_AVAIL_BIT_MASK (0x4) +#define AVS_ETH_REG_STATUS_TX_AVAIL_BIT_OFST 2 +#define AVS_ETH_REG_STATUS_RX_EMPTY_BIT_MASK (0x30000) +#define AVS_ETH_REG_STATUS_RX_EMPTY_BIT_OFST 16 +#define AVS_ETH_REG_STATUS_RX_NOF_WORDS_BIT_MASK (0xFFFC0000) +#define AVS_ETH_REG_STATUS_RX_NOF_WORDS_BIT_OFST 18 + +// ETH frame +#define AVS_ETH_TYPE_MASK (0xFFFF) + + +/* public macros */ + +// usage: fill in base address from system.h +// . pcs_addr half word address as defined in table 4.9 in ug_ethernet.pdf +// . mac_addr byte address as defined in table 4.17 in ug_ethernet.pdf +// TSE MAC uses byte unit addressing +#define AVS_ETH_TSE_PCS_RD(base, pcs_addr) IORD((base), (AVS_ETH_TSE_PCS_ADDR_BASE + (pcs_addr)*2)) +#define AVS_ETH_TSE_PCS_WR(base, pcs_addr, data) IOWR((base), (AVS_ETH_TSE_PCS_ADDR_BASE + (pcs_addr)*2), (data)) +#define AVS_ETH_TSE_MAC_RD(base, mac_addr) IORD((base), (mac_addr)) +#define AVS_ETH_TSE_MAC_WR(base, mac_addr, data) IOWR((base), (mac_addr), (data)) +// ETH REG and ETH RAM use word unit addressing +#define AVS_ETH_REG_RD(base, reg_wi) IORD((base), (reg_wi)) +#define AVS_ETH_REG_WR(base, reg_wi, data) IOWR((base), (reg_wi), (data)) +#define AVS_ETH_RAM_RD(base, ram_wi) IORD((base), (ram_wi)) +#define AVS_ETH_RAM_WR(base, ram_wi, data) IOWR((base), (ram_wi), (data)) + +/* public types */ + +/* public variables */ + +/* public function protos */ + +#endif // AVS_ETH_REGS_H diff --git a/software/unb_osy/unbosx_types.h b/software/unb_osy/unbosx_types.h new file mode 100644 index 0000000000000000000000000000000000000000..4cb41918c7db65580586664b3fce5049dc67a290 --- /dev/null +++ b/software/unb_osy/unbosx_types.h @@ -0,0 +1,14 @@ +#ifndef UNBOSX_TYPES_H +#define UNBOSX_TYPES_H + +#include <alt_types.h> + +#define FALSE 0 +#define TRUE 1 +#define NULL ((void*)0) +#define ALT_IRQ_NOT_CONNECTED (-1) +typedef alt_32 TBool; +typedef alt_u16 TUInt16; +typedef alt_u32 TUInt32; + +#endif diff --git a/software/unb_osy/unbosx_util.h b/software/unb_osy/unbosx_util.h new file mode 100644 index 0000000000000000000000000000000000000000..e5b55b2505330405815a4afc30c1fbe9438658fd --- /dev/null +++ b/software/unb_osy/unbosx_util.h @@ -0,0 +1,86 @@ +/* ----------------------------------------------------------------------------- + * + * Copyright (C) 2009 + * ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> + * JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> + * P.O.Box 2, 7990 AA Dwingeloo, The Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ---------------------------------------------------------------------------- */ + +#ifndef UNBOSX_UTIL_H +#define UNBOSX_UTIL_H + + +/* includes */ +#include <system.h> +#include <unbosx_types.h> +#include <altera_avalon_pio_regs.h> + + +/* The NiosII CPU is little endian so we + * must swap going from host -> network and from network -> host byteorder + * since networkbyteorder is big endian + */ + +/* 16 bit swap */ +#define UNBOSX_UTIL_ntohs(x) ((((x) >> 8) & 0xff) | \ + (((x) << 8) & 0xff00)) +#define UNBOSX_UTIL_htons(x) UNBOSX_UTIL_ntohs(x) + +/* 32 bit swap */ +#define UNBOSX_UTIL_ntohl(x) ((((x >> 24) & 0x000000ff)) | \ + (((x >> 8) & 0x0000ff00)) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) +#define UNBOSX_UTIL_htonl(a) UNBOSX_UTIL_ntohl(a) + + + + +/* UNB1: */ +/* [7:0] = id : UniBoard FPGA node ID in entire multi subrack system: + * [2:0] = nodenumber (0 -> 7) + * [2] => if '1' this implies it's a backnode (ie: 4, 5, 6, 7) + * [7:3] = backplaneid + */ +#define UNBOSX_GetNodeNumber() (IORD_ALTERA_AVALON_PIO_DATA(PIO_SYSTEM_INFO_BASE)&0x7) +#define UNBOSX_GetBackplaneId() ((IORD_ALTERA_AVALON_PIO_DATA(PIO_SYSTEM_INFO_BASE)&0xff)>>3) +#define UNBOSX_IsBacknode() ((IORD_ALTERA_AVALON_PIO_DATA(PIO_SYSTEM_INFO_BASE)&0x4)==0x4) + + + +/* UNB2: */ +/* [7:0] = id : UniBoard FPGA node ID in entire multi subrack system: + * [1:0] = nodenumber (0 -> 3) + * [7:2] = backplaneid + */ +#define UNBOSX_unb2_GetNodeNumber() (IORD_ALTERA_AVALON_PIO_DATA(PIO_SYSTEM_INFO_BASE)&0x3) +#define UNBOSX_unb2_GetBackplaneId() ((IORD_ALTERA_AVALON_PIO_DATA(PIO_SYSTEM_INFO_BASE)&0xff)>>2) +#define UNBOSX_unb2_IsBacknode() (0) + + + +#define UNBOSX_G_SIM() ((IORD_ALTERA_AVALON_PIO_DATA(PIO_SYSTEM_INFO_BASE)&0x400)!=0) + +#define UNBOSX_ResetWatchdog() (IOWR_ALTERA_AVALON_PIO_DATA(PIO_WDI_BASE, !((IORD_ALTERA_AVALON_PIO_DATA(PIO_WDI_BASE))&0x1))) +/* public types */ + +/* public variables */ + +/* public function protos */ + +#endif +