/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2007 Michael Sevakis * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "plugin.h" PLUGIN_HEADER PLUGIN_IRAM_DECLARE static unsigned int cop_thread_id; static struct event_queue cop_queue NOCACHEBSS_ATTR; static struct queue_sender_list cop_queue_senders NOCACHEBSS_ATTR; static int cop_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)] __attribute__((aligned(16))); static uint8_t cached_buf[16] __attribute__((aligned(16))); static uint8_t uncached_buf[16] NOCACHEBSS_ATTR; static uint8_t cop_buf[16] NOCACHEBSS_ATTR; #if 0 void cachy(void *start, void *end, bool invalidate) ICODE_ATTR; void cachy(void *start, void *end, bool invalidate) { static int i; unsigned s = (unsigned)start & 0xffff0000; unsigned e = (unsigned)end & 0xffff0000; unsigned r1 = e;//0x10000000 - e; unsigned r2 = s + e - 1; unsigned r0; // if ((r2 & r1) != s) // { // rb->splash(0, "woops! %08x %08x %08x", s, e, r1 & r2); // return; // } int oldlevel = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); outl(s | (r1 >> 16), 0xf000f048); outl(inl(0xf000f044) | (invalidate ? 0x6 : 0x2), 0xf000f044); while ((CACHE_CTL & 0x8000) != 0); if (invalidate != false) { for (i = 0x10000000; i < 0x10002000; i += 16) inb(i); } outl(0, 0xf000f048); set_interrupt_status(oldlevel, IRQ_FIQ_STATUS); } #endif void cop_thread(void) { int i; struct queue_event ev; while (1) { rb->queue_wait_w_tmo(&cop_queue, &ev, 3600*HZ); rb->cpucache_invalidate(); switch (ev.id) { case 0: /* avoid memcpy/memcmp to help localize code execution */ for (i = 0; i < 16; i++) { if (cached_buf[i] != uncached_buf[i]) { for (i = 0; i < 16; i++) { /* copy what COP sees to an uncacheable buffer */ cop_buf[i] = cached_buf[i]; } /* return failure */ rb->queue_reply(&cop_queue, -1); break; } } break; case 666: /* commanded to exit */ return; } } } enum plugin_status plugin_start(const void *parameter) { int ret; unsigned char buf[64]; unsigned int rand; unsigned int test_num = 0; PLUGIN_IRAM_INIT(rb); rand = *rb->current_tick; ret = 0; rb->queue_init(&cop_queue, false); rb->queue_enable_queue_send(&cop_queue, &cop_queue_senders, 0); rb->cpucache_flush(); cop_thread_id = rb->create_thread(cop_thread, cop_thread_stack, sizeof(cop_thread_stack), 0, "cop_thread", PRIORITY_SYSTEM IF_COP(, COP)); rb->lcd_setfont(FONT_SYSFIXED); rb->lcd_puts(0, 0, "Test running..."); rb->lcd_puts(0, 1, "Will dump upon byte mismatch."); rb->lcd_update(); while (rb->button_get(false) == BUTTON_NONE) { int i; test_num++; for (i = 0; i < 16; i++) { unsigned val; rand = rand*0x0019660dL + 0x3c6ef35fL; val = rand & 0xff; cached_buf[i] = val; uncached_buf[i] = val; } rb->cpucache_flush(); ret = rb->queue_send(&cop_queue, 0, 0); if (ret < 0) break; rb->yield(); } if (ret < 0) { int i, x, y = 0; rb->lcd_clear_display(); rb->snprintf(buf, 64, "Test #%u failed:", test_num); rb->lcd_puts(0, y++, buf); rb->lcd_puts(0, y, "cached_buf"); rb->lcd_puts(0, y+3, "uncached_buf"); rb->lcd_puts(0, y+6, "cop_buf"); for (i = 0, x = 0, y = 2; i < 16; i++, x += 3) { if (i % 8 == 0) x = 0, y++; /* show bytes in the shared, cached buffer */ rb->snprintf(buf, 64, "%02X ", cached_buf[i]); rb->lcd_puts(x, y+0, buf); /* show bytes in the shared, uncached buffer */ rb->snprintf(buf, 64, "%02X ", uncached_buf[i]); rb->lcd_puts(x, y+3, buf); /* show bytes that cop saw in the shared, cached buffer */ rb->snprintf(buf, 64, "%02X ", cop_buf[i]); rb->lcd_puts(x, y+6, buf); } rb->lcd_update(); while (rb->button_get(true) == BUTTON_NONE); } /* tell cop thread to exit */ rb->queue_post(&cop_queue, 666, 0); /* wait for thread to finish */ rb->thread_wait(cop_thread_id); return PLUGIN_OK; (void)parameter; }