mirror of https://github.com/contiki-ng/mspsim
439 lines
10 KiB
C
439 lines
10 KiB
C
/*
|
|
* Copyright (c) 2007, Swedish Institute of Computer Science.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the Institute nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
*
|
|
* $Id: cputest.c,v 1.19 2007/10/24 22:17:46 nfi Exp $
|
|
*
|
|
* -----------------------------------------------------------------
|
|
*
|
|
* Author : Adam Dunkels, Joakim Eriksson, Niclas Finne
|
|
* Created : 2006-03-07
|
|
* Updated : $Date: 2007/10/24 22:17:46 $
|
|
* $Revision: 1.19 $
|
|
*/
|
|
|
|
#include "msp430setup.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#if __MSPGCC__
|
|
#include <msp430.h>
|
|
#include <legacymsp430.h>
|
|
#define eint() __eint()
|
|
#define dint() __dint()
|
|
#else /* __MSPGCC__ */
|
|
#include <signal.h>
|
|
#include <io.h>
|
|
#endif /* __MSPGCC__ */
|
|
|
|
/* From Adams test-suite */
|
|
#define TEST(...) if(__VA_ARGS__) { \
|
|
printf("OK: " #__VA_ARGS__ " passed at %s:%d\n", __FILE__,__LINE__); \
|
|
} else { \
|
|
printf("FAIL: " #__VA_ARGS__ " failed at %s:%d\n", __FILE__,__LINE__); \
|
|
}
|
|
|
|
#define TEST2(text,...) if(__VA_ARGS__) { \
|
|
printf("OK: " #text " passed at %s:%d\n", __FILE__,__LINE__); \
|
|
} else { \
|
|
printf("FAIL: " #text " failed at %s:%d\n", __FILE__,__LINE__); \
|
|
}
|
|
|
|
#define assertTrue(...) TEST(__VA_ARGS__)
|
|
#define assertFalse(...) TEST(!(__VA_ARGS__))
|
|
|
|
#define assertTrue2(text,...) TEST2(text,__VA_ARGS__)
|
|
#define assertFalse2(text,...) TEST2(text,!(__VA_ARGS__))
|
|
|
|
static int testzero(int hm)
|
|
{
|
|
return hm > 0;
|
|
}
|
|
|
|
static int caseID = 0;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int pos = 0;
|
|
static unsigned int times[10];
|
|
interrupt(TIMERB1_VECTOR) timerb1 (void)
|
|
{
|
|
if(TBIV == 2) {
|
|
if(pos < 10) {
|
|
times[pos] = TBR;
|
|
pos++;
|
|
TBCCR1 = TBCCR1 + 100;
|
|
}
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void initTest() {
|
|
caseID = 0;
|
|
}
|
|
|
|
static void testCase(char *description) {
|
|
caseID++;
|
|
printf("-------------\n");
|
|
printf("TEST %d: %s\n", caseID, description);
|
|
}
|
|
|
|
static void testSimple() {
|
|
int a,b,c;
|
|
a = 1; b = 2; c = 4;
|
|
testCase("Arithmetic Operations");
|
|
|
|
assertTrue((a << b) == 4);
|
|
assertTrue((c >> a) == 2);
|
|
|
|
assertFalse(0 > 0);
|
|
assertFalse(a > b);
|
|
|
|
assertFalse(testzero(0));
|
|
}
|
|
|
|
static void testIntegers() {
|
|
int a,b,c;
|
|
int t[3];
|
|
testCase("Integer Operations");
|
|
a = 1; b = 2; c = -42;
|
|
t[0] = 1;
|
|
t[1] = 2;
|
|
t[2] = 3;
|
|
assertTrue(a == 1);
|
|
assertTrue((b + c) == -40);
|
|
assertTrue(t[0] == 1);
|
|
assertTrue(t[1] == 2);
|
|
assertTrue(t[t[0]] == 2);
|
|
assertTrue((a+b) == 3);
|
|
assertTrue((b-a) == 1);
|
|
assertTrue((a-b) == -1);
|
|
assertTrue((a*b) == 2);
|
|
assertTrue(a > 0);
|
|
assertTrue(b > a);
|
|
assertTrue(b != a);
|
|
assertTrue((a ^ b) == 3);
|
|
assertTrue((a ^ 4) == 5);
|
|
assertTrue((a ^ a) == 0);
|
|
assertFalse(a > b);
|
|
|
|
a = 15;
|
|
b = 17;
|
|
assertTrue((a & ~b) == 14);
|
|
}
|
|
|
|
static void testFloats() {
|
|
int i;
|
|
float f;
|
|
i = 2;
|
|
f = 0.5;
|
|
testCase("Float Operations");
|
|
assertTrue((i * f) == 1);
|
|
i++;
|
|
assertTrue((i * f) == 1.5);
|
|
}
|
|
|
|
static void testStrings() {
|
|
char buf[10];
|
|
|
|
testCase("String Operations");
|
|
sprintf(buf, "test");
|
|
assertTrue2("test => test", strcmp(buf, "test") == 0);
|
|
sprintf(buf, "%c", 'a');
|
|
assertTrue2("buf == 'a'", strcmp(buf, "a") == 0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
static int id(int first, ...)
|
|
{
|
|
va_list marker;
|
|
va_start( marker, first );
|
|
first = va_arg( marker, int);
|
|
va_end( marker );
|
|
return first;
|
|
}
|
|
|
|
static void testFunctions() {
|
|
volatile int i;
|
|
|
|
testCase("Functions");
|
|
i = 47;
|
|
|
|
/* printf("i=%d i+1=%d id(i)=%d\n", i, i + 1, id(0, i)); */
|
|
|
|
assertTrue(i == 47);
|
|
assertTrue(id(0,47) == 47);
|
|
assertTrue(id(0,i) == 47);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
static void testModulo() {
|
|
int c;
|
|
testCase("Modulo");
|
|
|
|
for(c = 2; c >= 0; c--) {
|
|
if((c % 5) == 0) {
|
|
assertTrue(c != 1);
|
|
}
|
|
/* printf("(%d,%d,%d)\n", c, (c % 5), c==1); */
|
|
/* printf("(%d,%d,%d)\n", c, (c % 5), c==1); */
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* Bit field tests */
|
|
|
|
static struct {
|
|
char green:4, yellow:4, red:4;
|
|
} leds;
|
|
|
|
static struct {
|
|
char green:2, yellow:2, red:2; /* These bit fields should really be
|
|
only one bit wide, but that
|
|
crashed gcc... */
|
|
} invert;
|
|
|
|
#ifndef BV
|
|
#define BV(n) (1 << (n))
|
|
#endif
|
|
|
|
void testBis() {
|
|
P4DIR |= BV(2) | BV(5) | BV(6);
|
|
assertTrue(P4DIR == 100);
|
|
}
|
|
|
|
static void testBitFields() {
|
|
static int pelle = 0;
|
|
|
|
testCase("Bit field Operations");
|
|
|
|
P4DIR = 0;
|
|
testBis();
|
|
|
|
leds.green = 1;
|
|
leds.yellow = 1;
|
|
leds.red = 1;
|
|
|
|
assertTrue(leds.green > 0);
|
|
assertTrue(leds.yellow > 0);
|
|
assertTrue(leds.red > 0);
|
|
|
|
leds.green -= 1;
|
|
assertTrue(leds.green == 0);
|
|
|
|
pelle = 0x4711;
|
|
|
|
invert.green = 1;
|
|
invert.yellow = 1;
|
|
invert.red = 1;
|
|
|
|
assertTrue(invert.green > 0);
|
|
assertTrue(invert.yellow > 0);
|
|
assertTrue(invert.red > 0);
|
|
|
|
invert.green ^= 1;
|
|
assertTrue(invert.green == 0);
|
|
|
|
assertTrue(pelle == 0x4711);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int flag;
|
|
interrupt(UART0TX_VECTOR) usart_tx_test0 (void)
|
|
{
|
|
printf("*IRQ: Flags:%d %d\n", IFG1, UTCTL0);
|
|
flag++;
|
|
}
|
|
|
|
static void testUSART() {
|
|
int delay = 10000;
|
|
testCase("Bit USART Operations");
|
|
flag = 0xff;
|
|
UCTL0 = CHAR; /* 8-bit character */
|
|
UTCTL0 = SSEL1; /* UCLK = MCLK */
|
|
ME1 |= (UTXE0 | URXE0); /* Enable USART0 TXD/RXD */
|
|
IE1 |= UTXIE0; /* Enable USART0 TX interrupt */
|
|
TXBUF_0 = 'a';
|
|
|
|
while(flag == 0) {
|
|
}
|
|
while(delay-- > 0);
|
|
|
|
printf("output finished...\n");
|
|
}
|
|
|
|
static void testTimer() {
|
|
int i;
|
|
unsigned int time;
|
|
int result;
|
|
pos = 0;
|
|
dint();
|
|
/* Select SMCLK (2.4576MHz), clear TAR; This makes the rtimer count
|
|
the number of processor cycles executed by the CPU. */
|
|
//TBCTL = TBSSEL1 | TBCLR;
|
|
/* Select ACLK 32768Hz clock, divide by 1 (was ID_3 / 8 previously) */
|
|
TBCTL = TBSSEL0 | TBCLR | ID_0;
|
|
|
|
/* Start Timer_B in continuous mode. */
|
|
TBCTL |= MC1;
|
|
|
|
TBR = 0;
|
|
TBCCR1 = 100;
|
|
|
|
/* CCR1 interrupt enabled, interrupt occurs when timer equals CCR1. */
|
|
/* Should be set here, since setting TBR to zero can cause triggering */
|
|
/* if CCR1 = 0 */
|
|
TBCCTL1 = CCIE;
|
|
|
|
/* Enable interrupts. */
|
|
eint();
|
|
|
|
while (pos < 10) {
|
|
printf(".");
|
|
}
|
|
printf("\n");
|
|
|
|
for (i = 0; i < pos; i++) {
|
|
unsigned int t = 100 + i * 100;
|
|
printf("Trigg time %d => %u\n", i + 1, times[i]);
|
|
assertTrue(times[i] >= t && times[i] < t + 2);
|
|
}
|
|
|
|
printf("Start modulo\n");
|
|
time = TBR;
|
|
result = 47;
|
|
for (i = 0; i < 1000; i++) {
|
|
result = result + i % 27;
|
|
}
|
|
printf("Elapsed %i %i\n",TBR - time, result);
|
|
|
|
|
|
}
|
|
|
|
#define TARGET_DCO_KHZ 4096
|
|
#define ACLK_KHZ 32
|
|
#define ACLK_CALIB_PERIOD 8
|
|
#define TARGET_DCO_DELTA (TARGET_DCO_KHZ / ACLK_KHZ) * ACLK_CALIB_PERIOD
|
|
|
|
void set_dco_calib( int calib )
|
|
{
|
|
BCSCTL1 = (BCSCTL1 & ~0x07) | ((calib >> 8) & 0x07);
|
|
DCOCTL = calib & 0xff;
|
|
}
|
|
|
|
uint16_t test_calib_busywait_delta( int calib )
|
|
{
|
|
int8_t aclk_count = 2;
|
|
uint16_t dco_prev = 0;
|
|
uint16_t dco_curr = 0;
|
|
|
|
set_dco_calib( calib );
|
|
|
|
while( aclk_count-- > 0 )
|
|
{
|
|
TBCCR0 = TBR + ACLK_CALIB_PERIOD; // set next interrupt
|
|
TBCCTL0 &= ~CCIFG; // clear pending interrupt
|
|
while( (TBCCTL0 & CCIFG) == 0 ); // busy wait
|
|
dco_prev = dco_curr;
|
|
dco_curr = TAR;
|
|
}
|
|
return dco_curr - dco_prev;
|
|
}
|
|
|
|
// busyCalibrateDCO
|
|
// Should take about 9ms if ACLK_CALIB_PERIOD=8.
|
|
// DCOCTL and BCSCTL1 are calibrated when done.
|
|
void busyCalibrateDco()
|
|
{
|
|
// --- variables ---
|
|
int calib;
|
|
int step;
|
|
int tmp;
|
|
// --- calibrate ---
|
|
|
|
// --- setup ---
|
|
|
|
TACTL = TASSEL1 | MC1; // source SMCLK, continuous mode, everything else 0
|
|
TBCTL = TBSSEL0 | MC1; // Aclk?
|
|
BCSCTL1 = XT2OFF | RSEL2;
|
|
BCSCTL2 = 0;
|
|
TBCCTL0 = CM0;
|
|
|
|
// Binary search for RSEL,DCO,DCOMOD.
|
|
// It's okay that RSEL isn't monotonic.
|
|
|
|
for( calib=0,step=0x800; step!=0; step>>=1 )
|
|
{
|
|
// if the step is not past the target, commit it
|
|
printf(" step: %d\n", step);
|
|
if((tmp = test_calib_busywait_delta(calib|step)) <= TARGET_DCO_DELTA )
|
|
{
|
|
calib |= step;
|
|
printf(" committed: tmp = %d\n", tmp);
|
|
}
|
|
}
|
|
|
|
// if DCOx is 7 (0x0e0 in calib), then the 5-bit MODx is not useable, set it to 0
|
|
if( (calib & 0x0e0) == 0x0e0 )
|
|
calib &= ~0x01f;
|
|
|
|
set_dco_calib( calib );
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
msp430_setup();
|
|
|
|
initTest();
|
|
|
|
testSimple();
|
|
testIntegers();
|
|
testFloats();
|
|
testStrings();
|
|
testBitFields();
|
|
testFunctions();
|
|
testModulo();
|
|
testUSART();
|
|
testTimer();
|
|
busyCalibrateDco();
|
|
/* printf("PROFILE\n"); */
|
|
printf("EXIT\n");
|
|
|
|
/* Short delay to allow serial output to finish */
|
|
__delay_cycles(2000);
|
|
|
|
return 0;
|
|
}
|