///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: cputest.c
|
// Filename: cputest.c
|
//
|
//
|
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
|
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
|
//
|
//
|
// Purpose: To test the CPU, it's instructions, cache, and pipeline, to make
|
// Purpose: To test the CPU, it's instructions, cache, and pipeline, to make
|
// certain that it works. This includes testing that each of the
|
// certain that it works. This includes testing that each of the
|
// instructions works, as well as any strange instruction combinations.
|
// instructions works, as well as any strange instruction combinations.
|
//
|
//
|
//
|
//
|
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This program is free software (firmware): you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License as published
|
// 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
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
//
|
//
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// http://www.gnu.org/licenses/gpl.html
|
// http://www.gnu.org/licenses/gpl.html
|
//
|
//
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
//
|
//
|
|
#ifndef NULL
|
#define NULL (void *)0
|
#define NULL (void *)0
|
|
#endif
|
|
|
volatile int *const UARTTX = (volatile int *)0x010b,
|
volatile int *const UARTTX = (volatile int *)0x010b,
|
* const UART_CTRL = (int *)0x0107;
|
* const UART_CTRL = (int *)0x0107;
|
// #define ZIPSYS
|
// #define ZIPSYS
|
#ifdef ZIPSYS
|
#ifdef ZIPSYS
|
#define HAVE_COUNTER
|
#define HAVE_COUNTER
|
volatile int * const PIC = (volatile int *)0xc0000000;
|
volatile int * const PIC = (volatile int *)0xc0000000;
|
const int INT_UARTTX = 0x2000;
|
const int INT_UARTTX = 0x2000;
|
volatile int *const COUNTER = (volatile int *)0xc0000008;
|
volatile int *const COUNTER = (volatile int *)0xc0000008;
|
|
|
#define HAVE_SCOPE
|
#define HAVE_SCOPE
|
|
|
#else
|
#else
|
volatile int * const PIC = (volatile int *)0x0102;
|
volatile int * const PIC = (volatile int *)0x0102;
|
const int INT_UARTTX = 0x080;
|
const int INT_UARTTX = 0x080;
|
volatile int *const TIMER = (volatile int *)0x0104;
|
volatile int *const TIMER = (volatile int *)0x0104;
|
#define HAVE_TIMER
|
#define HAVE_TIMER
|
#endif
|
#endif
|
|
|
#ifdef HAVE_SCOPE
|
#ifdef HAVE_SCOPE
|
volatile int *const SCOPE = (volatile int *)0x011e;
|
volatile int *const SCOPE = (volatile int *)0x011e;
|
#endif
|
#endif
|
|
|
unsigned zip_ucc(void);
|
unsigned zip_ucc(void);
|
void zip_save_context(int *);
|
void zip_save_context(int *);
|
void zip_halt(void);
|
void zip_halt(void);
|
|
|
|
|
|
void txchr(char v);
|
|
void txstr(const char *str);
|
|
void txhex(int num);
|
|
void tx4hex(int num);
|
|
|
|
|
asm("\t.section\t.start\n"
|
asm("\t.section\t.start\n"
|
"\t.global\t_start\n"
|
"\t.global\t_start\n"
|
"\t.type\t_start,@function\n"
|
"\t.type\t_start,@function\n"
|
"_start:\n"
|
"_start:\n"
|
#ifdef HAVE_SCOPE
|
#ifdef HAVE_SCOPE
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tLOD\t286,R0\n"
|
"\tLOD\t286,R0\n"
|
"\tROL\t16,R0\n"
|
"\tROL\t16,R0\n"
|
"\tTST\t0x1000,R0\n"
|
"\tTST\t0x1000,R0\n"
|
"\tBZ\t_start\n"
|
"\tBZ\t_start\n"
|
"\tOR\t0x0f00,R0\n"
|
"\tOR\t0x0f00,R0\n"
|
"\tROL\t16,R0\n"
|
"\tROL\t16,R0\n"
|
"\tSTO\tR0,286\n"
|
"\tSTO\tR0,286\n"
|
#endif
|
#endif
|
"\tCLR\tR0\n"
|
"\tCLR\tR0\n"
|
"\tCLR\tR1\n"
|
"\tCLR\tR1\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR3\n"
|
"\tCLR\tR3\n"
|
"\tCLR\tR4\n"
|
"\tCLR\tR4\n"
|
"\tCLR\tR5\n"
|
"\tCLR\tR5\n"
|
"\tCLR\tR6\n"
|
"\tCLR\tR6\n"
|
"\tCLR\tR7\n"
|
"\tCLR\tR7\n"
|
"\tCLR\tR8\n"
|
"\tCLR\tR8\n"
|
"\tCLR\tR9\n"
|
"\tCLR\tR9\n"
|
"\tCLR\tR10\n"
|
"\tCLR\tR10\n"
|
"\tCLR\tR11\n"
|
"\tCLR\tR11\n"
|
"\tCLR\tR12\n"
|
"\tCLR\tR12\n"
|
"\tLDI\t_top_of_stack,SP\n"
|
"\tLDI\t_top_of_stack,SP\n"
|
"\tCLR\tCC\n"
|
"\tCLR\tCC\n"
|
"\tMOV\tbusy_failure(PC),R0\n"
|
"\tMOV\tbusy_failure(PC),R0\n"
|
"\tBRA\tentry\n"
|
"\tBRA\tentry\n"
|
"busy_failure:\n"
|
"busy_failure:\n"
|
"\tBUSY\n"
|
"\tBUSY\n"
|
"\t.section\t.text");
|
"\t.section\t.text");
|
|
|
#ifdef HAVE_COUNTER
|
#ifdef HAVE_COUNTER
|
#define MARKSTART start_time = *COUNTER
|
#define MARKSTART start_time = *COUNTER
|
#define MARKSTOP stop_time = *COUNTER
|
#define MARKSTOP stop_time = *COUNTER
|
#else
|
#else
|
#ifdef HAVE_TIMER
|
#ifdef HAVE_TIMER
|
#define MARKSTART start_time = *TIMER
|
#define MARKSTART start_time = *TIMER
|
#define MARKSTOP stop_time = *TIMER
|
#define MARKSTOP stop_time = *TIMER
|
#else
|
#else
|
#define MARKSTART
|
#define MARKSTART
|
#define MARKSTOP
|
#define MARKSTOP
|
#endif
|
#endif
|
#endif
|
#endif
|
|
|
|
|
extern int run_test(void *pc, void *stack);
|
extern int run_test(void *pc, void *stack);
|
asm("\t.global\trun_test\n"
|
asm("\t.text\n\t.global\trun_test\n"
|
"\t.type\trun_test,@function\n"
|
"\t.type\trun_test,@function\n"
|
"run_test:\n"
|
"run_test:\n"
|
"\tCLR\tR3\n"
|
"\tCLR\tR3\n"
|
"\tMOV\ttest_return(PC),uR0\n"
|
"\tMOV\ttest_return(PC),uR0\n"
|
"\tMOV\tR3,uR1\n"
|
"\tMOV\tR3,uR1\n"
|
"\tMOV\tR3,uR2\n"
|
"\tMOV\tR3,uR2\n"
|
"\tMOV\tR3,uR3\n"
|
"\tMOV\tR3,uR3\n"
|
"\tMOV\tR3,uR4\n"
|
"\tMOV\tR3,uR4\n"
|
"\tMOV\tR3,uR5\n"
|
"\tMOV\tR3,uR5\n"
|
"\tMOV\tR3,uR6\n"
|
"\tMOV\tR3,uR6\n"
|
"\tMOV\tR3,uR7\n"
|
"\tMOV\tR3,uR7\n"
|
"\tMOV\tR3,uR8\n"
|
"\tMOV\tR3,uR8\n"
|
"\tMOV\tR3,uR9\n"
|
"\tMOV\tR3,uR9\n"
|
"\tMOV\tR3,uR10\n"
|
"\tMOV\tR3,uR10\n"
|
"\tMOV\tR1,uR11\n"
|
"\tMOV\tR3,uR11\n"
|
"\tMOV\tR1,uR12\n"
|
"\tMOV\tR3,uR12\n"
|
"\tMOV\tR2,uSP\n"
|
"\tMOV\tR2,uSP\n" // uSP = stack
|
"\tMOV\t0x20+R3,uCC\n"
|
"\tMOV\t0x20+R3,uCC\n" // Clear uCC of all but the GIE bit
|
"\tMOV\tR1,uPC\n"
|
"\tMOV\tR1,uPC\n" // uPC = pc
|
"\tRTU\n"
|
"\tRTU\n"
|
"test_return:\n"
|
"test_return:\n"
|
"\tMOV\tuR1,R1\n"
|
"\tMOV\tuR1,R1\n"
|
"\tAND\t0xffffffdf,CC\n"
|
"\tAND\t0xffffffdf,CC\n"
|
// Works with 5 NOOPS, works with 3 NOOPS, works with 1 NOOP
|
// Works with 5 NOOPS, works with 3 NOOPS, works with 1 NOOP
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
|
extern int idle_test(void);
|
|
asm("\t.text\n\t.global\tidle_test\n"
|
|
"\t.type\tidle_test,@function\n"
|
|
"idle_test:\n"
|
|
"\tCLR\tR1\n"
|
|
"\tMOV\tidle_loop(PC),uR0\n"
|
|
"\tMOV\tR1,uR1\n"
|
|
"\tMOV\tR1,uR2\n"
|
|
"\tMOV\tR1,uR3\n"
|
|
"\tMOV\tR1,uR4\n"
|
|
"\tMOV\tR1,uR5\n"
|
|
"\tMOV\tR1,uR6\n"
|
|
"\tMOV\tR1,uR7\n"
|
|
"\tMOV\tR1,uR8\n"
|
|
"\tMOV\tR1,uR9\n"
|
|
"\tMOV\tR1,uR10\n"
|
|
"\tMOV\tR1,uR11\n"
|
|
"\tMOV\tR1,uR12\n"
|
|
"\tMOV\tR1,uSP\n"
|
|
"\tMOV\t0x20+R1,uCC\n"
|
|
"\tMOV\tidle_loop(PC),uPC\n"
|
|
"\tWAIT\n"
|
|
"\tMOV uPC,R1\n"
|
|
"\tCMP idle_loop(PC),R1\n"
|
|
"\tLDI 0,R1\n"
|
|
"\tLDI.NZ 1,R1\n"
|
|
"\nRETN\n"
|
|
"idle_loop:\n"
|
|
"\tWAIT\n"
|
|
"\tBRA idle_loop\n");
|
|
|
void break_one(void);
|
void break_one(void);
|
asm("\t.global\tbreak_one\n"
|
asm("\t.text\n\t.global\tbreak_one\n"
|
"\t.type\tbreak_one,@function\n"
|
"\t.type\tbreak_one,@function\n"
|
"break_one:\n"
|
"break_one:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
"\tBREAK\n"
|
"\tBREAK\n"
|
"\tLDI\t1,R1\n" // Test fails
|
"\tLDI\t1,R1\n" // Test fails
|
"\tJMP\tR0");
|
"\tJMP\tR0");
|
|
|
void break_two(void);
|
void break_two(void);
|
// Can we stop a break before we hit it?
|
// Can we stop a break before we hit it?
|
asm("\t.global\tbreak_two\n"
|
asm("\t.text\n\t.global\tbreak_two\n"
|
"\t.type\tbreak_two,@function\n"
|
"\t.type\tbreak_two,@function\n"
|
"break_two:\n"
|
"break_two:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
"\tJMP\tR0\n"
|
"\tJMP\tR0\n"
|
"\tBREAK\n");
|
"\tBREAK\n");
|
|
|
void early_branch_test(void);
|
void early_branch_test(void);
|
asm("\t.global\tearly_branch_test\n"
|
asm("\t.text\n\t.global\tearly_branch_test\n"
|
"\t.type\tearly_branch_test,@function\n"
|
"\t.type\tearly_branch_test,@function\n"
|
"early_branch_test:\n"
|
"early_branch_test:\n"
|
"\tLDI\t1,R1\n"
|
"\tLDI\t1,R1\n"
|
"\tBRA\t_eb_a\n"
|
"\tBRA\t_eb_a\n"
|
"\tBREAK\n"
|
"\tBREAK\n"
|
"_eb_a:\n"
|
"_eb_a:\n"
|
"\tLDI\t2,R1\n"
|
"\tLDI\t2,R1\n"
|
"\tBRA\t_eb_b\n"
|
"\tBRA\t_eb_b\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tBREAK\n"
|
"\tBREAK\n"
|
"_eb_b:\n"
|
"_eb_b:\n"
|
"\tLDI\t3,R1\n"
|
"\tLDI\t3,R1\n"
|
"\tBRA\t_eb_c\n"
|
"\tBRA\t_eb_c\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tBREAK\n"
|
"\tBREAK\n"
|
"_eb_c:\n"
|
"_eb_c:\n"
|
"\tLDI\t4,R1\n"
|
"\tLDI\t4,R1\n"
|
"\tBRA\t_eb_d\n"
|
"\tBRA\t_eb_d\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tBREAK\n"
|
"\tBREAK\n"
|
"_eb_d:\n"
|
"_eb_d:\n"
|
"\tLDI\t5,R1\n"
|
"\tLDI\t5,R1\n"
|
"\tBRA\t_eb_e\n"
|
"\tBRA\t_eb_e\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tBREAK\n"
|
"\tBREAK\n"
|
"_eb_e:\n"
|
"_eb_e:\n"
|
"\tLDI\t6,R1\n"
|
"\tLDI\t6,R1\n"
|
"\tBRA\t_eb_f\n"
|
"\tBRA\t_eb_f\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tNOP\n"
|
"\tBREAK\n"
|
"\tBREAK\n"
|
"_eb_f:\n"
|
"_eb_f:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
"\tJMP\tR0");
|
"\tJMP\tR0");
|
|
|
void trap_test_and(void);
|
void trap_test_and(void);
|
asm("\t.global\ttrap_test_and\n"
|
asm("\t.text\n\t.global\ttrap_test_and\n"
|
"\t.type\ttrap_test_and,@function\n"
|
"\t.type\ttrap_test_and,@function\n"
|
"trap_test_and:\n"
|
"trap_test_and:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
"\tAND\t0xffffffdf,CC\n"
|
"\tAND\t0xffffffdf,CC\n"
|
"\tLDI\t1,R1\n" // Test fails
|
"\tLDI\t1,R1\n" // Test fails
|
"\tJMP\tR0");
|
"\tJMP\tR0");
|
|
|
void trap_test_clr(void);
|
void trap_test_clr(void);
|
asm("\t.global\ttrap_test_clr\n"
|
asm("\t.text\n\t.global\ttrap_test_clr\n"
|
"\t.type\ttrap_test_clr,@function\n"
|
"\t.type\ttrap_test_clr,@function\n"
|
"trap_test_clr:\n"
|
"trap_test_clr:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
"\tCLR\tCC\n"
|
"\tCLR\tCC\n"
|
"\tLDI\t1,R1\n" // Test fails
|
"\tLDI\t1,R1\n" // Test fails
|
"\tJMP\tR0");
|
"\tJMP\tR0");
|
|
|
void overflow_test(void);
|
void overflow_test(void);
|
asm("\t.global\toverflow_test\n"
|
asm("\t.text\n\t.global\toverflow_test\n"
|
"\t.type\toverflow_test,@function\n"
|
"\t.type\toverflow_test,@function\n"
|
"overflow_test:\n"
|
"overflow_test:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R3\n" // Clear our scorecard
|
"\tLDI\t0,R3\n" // Clear our scorecard
|
// First test: does adding one to the maximum integer cause an overflow?
|
// First test: does adding one to the maximum integer cause an overflow?
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tLSR\t1,R2\n"
|
"\tLSR\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tOR.V\t1,R3\n"
|
"\tOR.V\t1,R3\n"
|
// Second test: does subtracting one to the minimum integer cause an overflow?
|
// Second test: does subtracting one to the minimum integer cause an overflow?
|
"\tLDI\t0x80000000,R2\n"
|
"\tLDI\t0x80000000,R2\n"
|
"\tSUB\t1,R2\n"
|
"\tSUB\t1,R2\n"
|
"\tOR.V\t2,R3\n"
|
"\tOR.V\t2,R3\n"
|
// Third test, overflow from LSR
|
// Third test, overflow from LSR
|
"\tLDI\t0x80000000,R2\n"
|
"\tLDI\t0x80000000,R2\n"
|
"\tLSR\t1,R2\n" // Overflows 'cause the sign changes
|
"\tLSR\t1,R2\n" // Overflows 'cause the sign changes
|
"\tOR.V\t4,R3\n"
|
"\tOR.V\t4,R3\n"
|
// Fourth test, overflow from LSL
|
// Fourth test, overflow from LSL
|
"\tLDI\t0x40000000,R2\n"
|
"\tLDI\t0x40000000,R2\n"
|
"\tLSL\t1,R2\n"
|
"\tLSL\t1,R2\n"
|
"\tOR.V\t8,R3\n"
|
"\tOR.V\t8,R3\n"
|
// Fifth test, overflow from LSL, negative to positive
|
// Fifth test, overflow from LSL, negative to positive
|
"\tLDI\t0x80000000,R2\n"
|
"\tLDI\t0x80000000,R2\n"
|
"\tLSL\t1,R2\n"
|
"\tLSL\t1,R2\n"
|
"\tOR.V\t16,R3\n"
|
"\tOR.V\t16,R3\n"
|
// Record our scores
|
// Record our scores
|
"\tXOR\t31,R3\n"
|
"\tXOR\t31,R3\n"
|
"\tOR\tR3,R1\n"
|
"\tOR\tR3,R1\n"
|
// And return the results
|
// And return the results
|
"\tJMP\tR0");
|
"\tJMP\tR0");
|
|
|
|
|
void carry_test(void);
|
void carry_test(void);
|
asm("\t.global\tcarry_test\n"
|
asm("\t.text\n\t.global\tcarry_test\n"
|
"\t.type\tcarry_test,@function\n"
|
"\t.type\tcarry_test,@function\n"
|
"carry_test:\n"
|
"carry_test:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R3\n"
|
"\tLDI\t0,R3\n"
|
// First, in adding
|
// First, in adding
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tOR.C\t1,R3\n"
|
"\tOR.C\t1,R3\n"
|
// Then, in subtraction
|
// Then, in subtraction
|
"\tSUB\t1,R2\n"
|
"\tSUB\t1,R2\n"
|
"\tOR.C\t2,R3\n"
|
"\tOR.C\t2,R3\n"
|
// From a right shift
|
// From a right shift
|
"\tLDI\t1,R2\n"
|
"\tLDI\t1,R2\n"
|
"\tLSR\t1,R2\n"
|
"\tLSR\t1,R2\n"
|
"\tOR.C\t4,R3\n"
|
"\tOR.C\t4,R3\n"
|
"\tLDI\t1,R2\n"
|
"\tLDI\t1,R2\n"
|
"\tASR\t1,R2\n"
|
"\tASR\t1,R2\n"
|
"\tOR.C\t8,R3\n"
|
"\tOR.C\t8,R3\n"
|
// Or from a compare
|
// Or from a compare
|
"\tLDI\t0,R2\n"
|
"\tLDI\t0,R2\n"
|
"\tCMP\t1,R2\n"
|
"\tCMP\t1,R2\n"
|
"\tOR.C\t16,R3\n"
|
"\tOR.C\t16,R3\n"
|
// Set our return and clean up
|
// Set our return and clean up
|
"\tXOR\t31,R3\n"
|
"\tXOR\t31,R3\n"
|
"\tOR\tR3,R1\n"
|
"\tOR\tR3,R1\n"
|
"\tJMP\tR0");
|
"\tJMP\tR0");
|
|
|
void loop_test(void);
|
void loop_test(void);
|
asm("\t.global\tloop_test\n"
|
asm("\t.text\n\t.global\tloop_test\n"
|
"\t.type\tloop_test,@function\n"
|
"\t.type\tloop_test,@function\n"
|
"loop_test:\n"
|
"loop_test:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
// Let's try a loop: for(i=0; i<5; i++)
|
// Let's try a loop: for(i=0; i<5; i++)
|
"\tLDI\t0,R2\n"
|
"\tLDI\t0,R2\n"
|
"\tLDI\t0,R3\n"
|
"\tLDI\t0,R3\n"
|
"\tCMP\t5,R2\n"
|
"\tCMP\t5,R2\n"
|
"\tBGE\tend_for_loop_test\n"
|
"\tBGE\tend_for_loop_test\n"
|
"for_loop_test:"
|
"for_loop_test:"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R3\n"
|
"\tADD\t1,R3\n"
|
"\tCMP\t5,R2\n"
|
"\tCMP\t5,R2\n"
|
"\tBLT\tfor_loop_test\n"
|
"\tBLT\tfor_loop_test\n"
|
"end_for_loop_test:"
|
"end_for_loop_test:"
|
"\tCMP\t5,R3\n"
|
"\tCMP\t5,R3\n"
|
"\tOR.NZ\t1,R1\n"
|
"\tOR.NZ\t1,R1\n"
|
// How about a reverse do{} while loop? These are usually cheaper than for()
|
// How about a reverse do{} while loop? These are usually cheaper than for()
|
// loops.
|
// loops.
|
"\tLDI\t0,R2\n"
|
"\tLDI\t0,R2\n"
|
"\tLDI\t5,R3\n"
|
"\tLDI\t5,R3\n"
|
"bgt_loop_test:\n"
|
"bgt_loop_test:\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tSUB\t1,R3\n"
|
"\tSUB\t1,R3\n"
|
"\tBGT\tbgt_loop_test\n"
|
"\tBGT\tbgt_loop_test\n"
|
"\tCMP\t5,R2\n"
|
"\tCMP\t5,R2\n"
|
"\tOR.NZ\t2,R1\n"
|
"\tOR.NZ\t2,R1\n"
|
// What if we use >=?
|
// What if we use >=?
|
"\tLDI\t0,R2\n"
|
"\tLDI\t0,R2\n"
|
"\tLDI\t5,R3\n"
|
"\tLDI\t5,R3\n"
|
"bge_loop_test:\n"
|
"bge_loop_test:\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tSUB\t1,R3\n"
|
"\tSUB\t1,R3\n"
|
"\tBGE\tbge_loop_test\n"
|
"\tBGE\tbge_loop_test\n"
|
"\tCMP\t6,R2\n"
|
"\tCMP\t6,R2\n"
|
"\tOR.NZ\t4,R1\n"
|
"\tOR.NZ\t4,R1\n"
|
// Once more with the reverse loop, this time storing the loop variable in
|
// Once more with the reverse loop, this time storing the loop variable in
|
// memory
|
// memory
|
"\tSUB\t1,SP\n"
|
"\tSUB\t1,SP\n"
|
"\tLDI\t0,R2\n"
|
"\tLDI\t0,R2\n"
|
"\tLDI\t5,R3\n"
|
"\tLDI\t5,R3\n"
|
"\tSTO\tR3,(SP)\n"
|
"\tSTO\tR3,(SP)\n"
|
"mem_loop_test:\n"
|
"mem_loop_test:\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t14,R3\n"
|
"\tADD\t14,R3\n"
|
"\tLOD\t(SP),R3\n"
|
"\tLOD\t(SP),R3\n"
|
"\tSUB\t1,R3\n"
|
"\tSUB\t1,R3\n"
|
"\tSTO\tR3,(SP)\n"
|
"\tSTO\tR3,(SP)\n"
|
"\tBGT\tmem_loop_test\n"
|
"\tBGT\tmem_loop_test\n"
|
"\tCMP\t5,R2\n"
|
"\tCMP\t5,R2\n"
|
"\tOR.NZ\t8,R1\n"
|
"\tOR.NZ\t8,R1\n"
|
"\tADD\t1,SP\n"
|
"\tADD\t1,SP\n"
|
//
|
//
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
// Test whether or not LSL, LSR, and ASR instructions work, together with their
|
// Test whether or not LSL, LSR, and ASR instructions work, together with their
|
// carry flags
|
// carry flags
|
void shift_test(void);
|
void shift_test(void);
|
asm("\t.global\tshift_test\n"
|
asm("\t.text\n\t.global\tshift_test\n"
|
"\t.type\tshift_test,@function\n"
|
"\t.type\tshift_test,@function\n"
|
"shift_test:\n"
|
"shift_test:\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R1\n"
|
"\tLDI\t0,R3\n"
|
"\tLDI\t0,R3\n"
|
"\tLDI\t0,R4\n"
|
"\tLDI\t0,R4\n"
|
// Does shifting right by 32 result in a zero?
|
// Does shifting right by 32 result in a zero?
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tLSR\t32,R2\n"
|
"\tLSR\t32,R2\n"
|
"\tOR.Z\t1,R3\n"
|
"\tOR.Z\t1,R3\n"
|
"\tOR.C\t2,R3\n"
|
"\tOR.C\t2,R3\n"
|
"\tCMP\t0,R2\n"
|
"\tCMP\t0,R2\n"
|
"\tOR.Z\t4,R3\n"
|
"\tOR.Z\t4,R3\n"
|
// Does shifting a -1 right arithmetically by 32 result in a -1?
|
// Does shifting a -1 right arithmetically by 32 result in a -1?
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tASR\t32,R2\n"
|
"\tASR\t32,R2\n"
|
"\tOR.LT\t8,R3\n"
|
"\tOR.LT\t8,R3\n"
|
"\tOR.C\t16,R3\n"
|
"\tOR.C\t16,R3\n"
|
"\tCMP\t-1,R2\n"
|
"\tCMP\t-1,R2\n"
|
"\tOR.Z\t32,R3\n"
|
"\tOR.Z\t32,R3\n"
|
// Does shifting a -4 right arithmetically by 2 result in a -1?
|
// Does shifting a -4 right arithmetically by 2 result in a -1?
|
"\tLDI\t-4,R2\n"
|
"\tLDI\t-4,R2\n"
|
"\tASR\t2,R2\n"
|
"\tASR\t2,R2\n"
|
"\tOR.LT\t64,R3\n"
|
"\tOR.LT\t64,R3\n"
|
"\tOR.C\t128,R1\n"
|
"\tOR.C\t128,R1\n"
|
"\tOR\t128,R3\n" // Artificially declare passing, so as not to fail it
|
"\tOR\t128,R3\n" // Artificially declare passing, so as not to fail it
|
"\tCMP\t-1,R2\n"
|
"\tCMP\t-1,R2\n"
|
"\tOR.Z\t256,R3\n"
|
"\tOR.Z\t256,R3\n"
|
// Does one more set the carry flag as desired?
|
// Does one more set the carry flag as desired?
|
"\tASR\t1,R2\n"
|
"\tASR\t1,R2\n"
|
"\tOR.LT\t512,R3\n"
|
"\tOR.LT\t512,R3\n"
|
"\tOR.C\t1024,R3\n"
|
"\tOR.C\t1024,R3\n"
|
"\tCMP\t-1,R2\n"
|
"\tCMP\t-1,R2\n"
|
"\tOR.Z\t2048,R3\n"
|
"\tOR.Z\t2048,R3\n"
|
// Does shifting -1 left by 32 result in a zero?
|
// Does shifting -1 left by 32 result in a zero?
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tLSL\t32,R2\n"
|
"\tLSL\t32,R2\n"
|
"\tOR.Z\t4096,R3\n"
|
"\tOR.Z\t4096,R3\n"
|
"\tOR.C\t8192,R3\n"
|
"\tOR.C\t8192,R3\n"
|
"\tCMP\t0,R2\n"
|
"\tCMP\t0,R2\n"
|
"\tOR.Z\t16384,R3\n"
|
"\tOR.Z\t16384,R3\n"
|
// How about shifting by zero?
|
// How about shifting by zero?
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tASR\t0,R2\n"
|
"\tASR\t0,R2\n"
|
"\tOR.C\t32768,R1\n"
|
"\tOR.C\t32768,R1\n"
|
"\tOR\t32768,R3\n"
|
"\tOR\t32768,R3\n"
|
"\tCMP\t-1,R2\n"
|
"\tCMP\t-1,R2\n"
|
"\tOR.Z\t1,R4\n"
|
"\tOR.Z\t1,R4\n"
|
//
|
//
|
"\tLSR\t0,R2\n"
|
"\tLSR\t0,R2\n"
|
"\tOR.C\t131072,R1\n"
|
"\tOR.C\t131072,R1\n"
|
"\tCMP\t-1,R2\n"
|
"\tCMP\t-1,R2\n"
|
"\tOR.Z\t2,R4\n"
|
"\tOR.Z\t2,R4\n"
|
//
|
//
|
"\tLSL\t0,R2\n"
|
"\tLSL\t0,R2\n"
|
"\tOR.C\t524288,R1\n"
|
"\tOR.C\t524288,R1\n"
|
"\tCMP\t-1,R2\n"
|
"\tCMP\t-1,R2\n"
|
"\tOR.Z\t4,R4\n"
|
"\tOR.Z\t4,R4\n"
|
// Tally up our results and return
|
// Tally up our results and return
|
"\tXOR\t7,R4\n"
|
"\tXOR\t7,R4\n"
|
"\tXOR\t65535,R3\n"
|
"\tXOR\t65535,R3\n"
|
"\tLSL\t16,R4\n"
|
"\tLSL\t16,R4\n"
|
"\tOR\tR4,R3\n"
|
"\tOR\tR4,R3\n"
|
"\tOR\tR3,R1\n"
|
"\tOR\tR3,R1\n"
|
"\tJMP\tR0");
|
"\tJMP\tR0");
|
|
|
int sw_brev(int v);
|
int sw_brev(int v);
|
asm("\t.global\tsw_brev\n"
|
asm("\t.text\n\t.global\tsw_brev\n"
|
"\t.type\tsw_brev,@function\n"
|
"\t.type\tsw_brev,@function\n"
|
"sw_brev:\n"
|
"sw_brev:\n"
|
"\tSUB\t2,SP\n"
|
"\tSUB\t2,SP\n"
|
"\tSTO\tR2,(SP)\n"
|
"\tSTO\tR2,(SP)\n"
|
"\tSTO\tR3,1(SP)\n"
|
"\tSTO\tR3,1(SP)\n"
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tCLR\tR3\n"
|
"\tCLR\tR3\n"
|
"sw_brev_loop:\n"
|
"sw_brev_loop:\n"
|
"\tLSL\t1,R3\n"
|
"\tLSL\t1,R3\n"
|
"\tLSR\t1,R1\n"
|
"\tLSR\t1,R1\n"
|
"\tOR.C\t1,R3\n"
|
"\tOR.C\t1,R3\n"
|
"\tLSR\t1,R2\n"
|
"\tLSR\t1,R2\n"
|
"\tBZ\tsw_brev_endloop\n"
|
"\tBZ\tsw_brev_endloop\n"
|
"\tBRA\tsw_brev_loop\n"
|
"\tBRA\tsw_brev_loop\n"
|
"sw_brev_endloop:\n"
|
"sw_brev_endloop:\n"
|
"\tMOV\tR3,R1\n"
|
"\tMOV\tR3,R1\n"
|
"\tLOD\t(SP),R2\n"
|
"\tLOD\t(SP),R2\n"
|
"\tLOD\t1(SP),R3\n"
|
"\tLOD\t1(SP),R3\n"
|
"\tADD\t2,SP\n"
|
"\tADD\t2,SP\n"
|
"\tJMP\tR0");
|
"\tJMP\tR0");
|
|
|
void pipeline_stack_test(void);
|
void pipeline_stack_test(void);
|
asm("\t.global\tpipeline_stack_test\n"
|
asm("\t.text\n\t.global\tpipeline_stack_test\n"
|
"\t.type\tpipeline_stack_test,@function\n"
|
"\t.type\tpipeline_stack_test,@function\n"
|
"pipeline_stack_test:\n"
|
"pipeline_stack_test:\n"
|
"\tSUB\t1,SP\n"
|
"\tSUB\t1,SP\n"
|
"\tSTO\tR0,(SP)\n"
|
"\tSTO\tR0,(SP)\n"
|
"\tLDI\t0,R0\n"
|
"\tLDI\t0,R0\n"
|
"\tMOV\t1(R0),R1\n"
|
"\tMOV\t1(R0),R1\n"
|
"\tMOV\t1(R1),R2\n"
|
"\tMOV\t1(R1),R2\n"
|
"\tMOV\t1(R2),R3\n"
|
"\tMOV\t1(R2),R3\n"
|
"\tMOV\t1(R3),R4\n"
|
"\tMOV\t1(R3),R4\n"
|
"\tMOV\t1(R4),R5\n"
|
"\tMOV\t1(R4),R5\n"
|
"\tMOV\t1(R5),R6\n"
|
"\tMOV\t1(R5),R6\n"
|
"\tMOV\t1(R6),R7\n"
|
"\tMOV\t1(R6),R7\n"
|
"\tMOV\t1(R7),R8\n"
|
"\tMOV\t1(R7),R8\n"
|
"\tMOV\t1(R8),R9\n"
|
"\tMOV\t1(R8),R9\n"
|
"\tMOV\t1(R9),R10\n"
|
"\tMOV\t1(R9),R10\n"
|
"\tMOV\t1(R10),R11\n"
|
"\tMOV\t1(R10),R11\n"
|
"\tMOV\t1(R11),R12\n"
|
"\tMOV\t1(R11),R12\n"
|
"\tMOV\tpipeline_stack_test_component_return(PC),R0\n"
|
"\tMOV\tpipeline_stack_test_component_return(PC),R0\n"
|
// "\tLJMP\tpipeline_stack_test_component\n"
|
// "\tLJMP\tpipeline_stack_test_component\n"
|
"\tBRA\tpipeline_stack_test_component\n"
|
"\tBRA\tpipeline_stack_test_component\n"
|
"pipeline_stack_test_component_return:\n"
|
"pipeline_stack_test_component_return:\n"
|
"\tCMP\t1,R1\n"
|
"\tCMP\t1,R1\n"
|
"\tLDI.Z\t0,R1\n"
|
"\tLDI.Z\t0,R1\n"
|
"\tCMP\t2,R2\n"
|
"\tCMP\t2,R2\n"
|
"\tCMP.Z\t3,R3\n"
|
"\tCMP.Z\t3,R3\n"
|
"\tCMP.Z\t4,R4\n"
|
"\tCMP.Z\t4,R4\n"
|
"\tCMP.Z\t5,R5\n"
|
"\tCMP.Z\t5,R5\n"
|
"\tCMP.Z\t6,R6\n"
|
"\tCMP.Z\t6,R6\n"
|
"\tCMP.Z\t7,R7\n"
|
"\tCMP.Z\t7,R7\n"
|
"\tCMP.Z\t8,R8\n"
|
"\tCMP.Z\t8,R8\n"
|
"\tCMP.Z\t9,R9\n"
|
"\tCMP.Z\t9,R9\n"
|
"\tCMP.Z\t10,R10\n"
|
"\tCMP.Z\t10,R10\n"
|
"\tCMP.Z\t11,R11\n"
|
"\tCMP.Z\t11,R11\n"
|
"\tCMP.Z\t12,R12\n"
|
"\tCMP.Z\t12,R12\n"
|
"\tBREV.NZ\t-1,R1\n"
|
"\tBREV.NZ\t-1,R1\n"
|
"\tLOD\t(SP),R0\n"
|
"\tLOD\t(SP),R0\n"
|
"\tADD\t1,SP\n"
|
"\tADD\t1,SP\n"
|
"\tJMP\tR0\n"
|
"\tJMP\tR0\n"
|
);
|
);
|
|
|
void pipeline_stack_test_component(void);
|
void pipeline_stack_test_component(void);
|
asm("\t.global\tpipeline_stack_test_component\n"
|
asm("\t.text\n\t.global\tpipeline_stack_test_component\n"
|
"\t.type\tpipeline_stack_test_component,@function\n"
|
"\t.type\tpipeline_stack_test_component,@function\n"
|
"pipeline_stack_test_component:\n"
|
"pipeline_stack_test_component:\n"
|
"\tSUB\t13,SP\n"
|
"\tSUB\t13,SP\n"
|
"\tSTO\tR0,(SP)\n"
|
"\tSTO\tR0,(SP)\n"
|
"\tSTO\tR1,1(SP)\n"
|
"\tSTO\tR1,1(SP)\n"
|
"\tSTO\tR2,2(SP)\n"
|
"\tSTO\tR2,2(SP)\n"
|
"\tSTO\tR3,3(SP)\n"
|
"\tSTO\tR3,3(SP)\n"
|
"\tSTO\tR4,4(SP)\n"
|
"\tSTO\tR4,4(SP)\n"
|
"\tSTO\tR5,5(SP)\n"
|
"\tSTO\tR5,5(SP)\n"
|
"\tSTO\tR6,6(SP)\n"
|
"\tSTO\tR6,6(SP)\n"
|
"\tSTO\tR7,7(SP)\n"
|
"\tSTO\tR7,7(SP)\n"
|
"\tSTO\tR8,8(SP)\n"
|
"\tSTO\tR8,8(SP)\n"
|
"\tSTO\tR9,9(SP)\n"
|
"\tSTO\tR9,9(SP)\n"
|
"\tSTO\tR10,10(SP)\n"
|
"\tSTO\tR10,10(SP)\n"
|
"\tSTO\tR11,11(SP)\n"
|
"\tSTO\tR11,11(SP)\n"
|
"\tSTO\tR12,12(SP)\n"
|
"\tSTO\tR12,12(SP)\n"
|
"\tXOR\t-1,R0\n"
|
"\tXOR\t-1,R0\n"
|
"\tXOR\t-1,R1\n"
|
"\tXOR\t-1,R1\n"
|
"\tXOR\t-1,R2\n"
|
"\tXOR\t-1,R2\n"
|
"\tXOR\t-1,R3\n"
|
"\tXOR\t-1,R3\n"
|
"\tXOR\t-1,R4\n"
|
"\tXOR\t-1,R4\n"
|
"\tXOR\t-1,R5\n"
|
"\tXOR\t-1,R5\n"
|
"\tXOR\t-1,R6\n"
|
"\tXOR\t-1,R6\n"
|
"\tXOR\t-1,R7\n"
|
"\tXOR\t-1,R7\n"
|
"\tXOR\t-1,R8\n"
|
"\tXOR\t-1,R8\n"
|
"\tXOR\t-1,R9\n"
|
"\tXOR\t-1,R9\n"
|
"\tXOR\t-1,R10\n"
|
"\tXOR\t-1,R10\n"
|
"\tXOR\t-1,R11\n"
|
"\tXOR\t-1,R11\n"
|
"\tXOR\t-1,R12\n"
|
"\tXOR\t-1,R12\n"
|
"\tLOD\t(SP),R0\n"
|
"\tLOD\t(SP),R0\n"
|
"\tLOD\t1(SP),R1\n"
|
"\tLOD\t1(SP),R1\n"
|
"\tLOD\t2(SP),R2\n"
|
"\tLOD\t2(SP),R2\n"
|
"\tLOD\t3(SP),R3\n"
|
"\tLOD\t3(SP),R3\n"
|
"\tLOD\t4(SP),R4\n"
|
"\tLOD\t4(SP),R4\n"
|
"\tLOD\t5(SP),R5\n"
|
"\tLOD\t5(SP),R5\n"
|
"\tLOD\t6(SP),R6\n"
|
"\tLOD\t6(SP),R6\n"
|
"\tLOD\t7(SP),R7\n"
|
"\tLOD\t7(SP),R7\n"
|
"\tLOD\t8(SP),R8\n"
|
"\tLOD\t8(SP),R8\n"
|
"\tLOD\t9(SP),R9\n"
|
"\tLOD\t9(SP),R9\n"
|
"\tLOD\t10(SP),R10\n"
|
"\tLOD\t10(SP),R10\n"
|
"\tLOD\t11(SP),R11\n"
|
"\tLOD\t11(SP),R11\n"
|
"\tLOD\t12(SP),R12\n"
|
"\tLOD\t12(SP),R12\n"
|
"\tADD\t13,SP\n"
|
"\tADD\t13,SP\n"
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
//mpy_test
|
//mpy_test
|
void mpy_test(void);
|
void mpy_test(void);
|
asm("\t.global\tmpy_test\n"
|
asm("\t.text\n\t.global\tmpy_test\n"
|
"\t.type\tmpy_test,@function\n"
|
"\t.type\tmpy_test,@function\n"
|
"mpy_test:\n"
|
"mpy_test:\n"
|
"\tCLR\tR1\n"
|
"\tCLR\tR1\n"
|
// First test: let's count multiples of 137
|
// First test: let's count multiples of 137
|
"\tLDI\t137,R2\n" // What we're doing multiples of
|
"\tLDI\t137,R2\n" // What we're doing multiples of
|
"\tCLR\tR3\n" // Our accumulator via addition
|
"\tCLR\tR3\n" // Our accumulator via addition
|
"\tCLR\tR4\n" // Our index for multiplication
|
"\tCLR\tR4\n" // Our index for multiplication
|
"mpy_137_test_loop:\n"
|
"mpy_137_test_loop:\n"
|
"\tMOV\tR2,R5\n"
|
"\tMOV\tR2,R5\n"
|
"\tMPY\tR4,R5\n"
|
"\tMPY\tR4,R5\n"
|
"\tCMP\tR3,R5\n"
|
"\tCMP\tR3,R5\n"
|
"\tBNZ\tend_mpy_137_test_loop_failed\n"
|
"\tBNZ\tend_mpy_137_test_loop_failed\n"
|
// Let's try negative while we are at it
|
// Let's try negative while we are at it
|
"\tMOV\tR2,R6\n"
|
"\tMOV\tR2,R6\n"
|
"\tNEG\tR6\n"
|
"\tNEG\tR6\n"
|
"\tMPY\tR4,R6\n"
|
"\tMPY\tR4,R6\n"
|
"\tNEG\tR6\n"
|
"\tNEG\tR6\n"
|
"\tCMP\tR3,R6\n"
|
"\tCMP\tR3,R6\n"
|
"\tBNZ\tend_mpy_137_test_loop_failed\n"
|
"\tBNZ\tend_mpy_137_test_loop_failed\n"
|
"\tCLR\tR6\n"
|
"\tCLR\tR6\n"
|
"\tTEST\t0xffff0000,R3\n"
|
"\tTEST\t0xffff0000,R3\n"
|
"\tBNZ\tend_mpy_137_test_loop\n"
|
"\tBNZ\tend_mpy_137_test_loop\n"
|
"\tADD\tR2,R3\n"
|
"\tADD\tR2,R3\n"
|
"\tADD\t1,R4\n"
|
"\tADD\t1,R4\n"
|
"\tBRA\tmpy_137_test_loop\n"
|
"\tBRA\tmpy_137_test_loop\n"
|
"end_mpy_137_test_loop_failed:\n"
|
"end_mpy_137_test_loop_failed:\n"
|
"\tOR\t1,R1\n"
|
"\tOR\t1,R1\n"
|
"end_mpy_137_test_loop:\n"
|
"end_mpy_137_test_loop:\n"
|
// Second test ... whatever that might be
|
// Second test ... whatever that might be
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
|
unsigned soft_mpyuhi(unsigned, unsigned);
|
|
int soft_mpyshi(int,int);
|
|
|
|
unsigned hard_mpyuhi(unsigned, unsigned);
|
|
asm("\t.text\n\t.global\thard_mpyuhi\n"
|
|
"\t.type\thard_mpyuhi,@function\n"
|
|
"hard_mpyuhi:\n"
|
|
"\tNOOP\n"
|
|
"\tNOOP\n"
|
|
"\tMPYUHI\tR2,R1\n"
|
|
"\tRETN\n");
|
|
|
|
int hard_mpyshi(int, int);
|
|
asm("\t.text\n\t.global\thard_mpyshi\n"
|
|
"\t.type\thard_mpyshi,@function\n"
|
|
"hard_mpyshi:\n"
|
|
"\tMPYSHI\tR2,R1\n"
|
|
"\tRETN\n");
|
|
|
|
void debugmpy(char *str, int a, int b, int s, int r) {
|
|
#ifdef HAVE_SCOPE
|
|
// Trigger the scope, if it hasn't been triggered yet
|
|
// but ... dont reset it if it has been.
|
|
*SCOPE = TRIGGER_SCOPE_NOW;
|
|
#endif
|
|
txstr("\r\n"); txstr(str); txhex(a);
|
|
txstr(" x "); txhex(b);
|
|
txstr(" = "); txhex(s);
|
|
txstr("(Soft) = "); txhex(r);
|
|
txstr("(Hard)\r\n");
|
|
}
|
|
|
|
int mpyhi_test(void) {
|
|
int a = 0xf97e27ab, b = 0;
|
|
|
|
while(b<0x6fffffff) {
|
|
int r, sr;
|
|
|
|
sr = soft_mpyuhi(a, b);
|
|
r = hard_mpyuhi(a,b);
|
|
if (r != sr) {
|
|
debugmpy("MPYUHI: ", a,b,sr,r);
|
|
return 1;
|
|
}
|
|
|
|
sr = soft_mpyshi(a, b);
|
|
r = hard_mpyshi(a,b);
|
|
if (r != sr) {
|
|
debugmpy("MPYSHI: ", a,b,sr,r);
|
|
return 2;
|
|
}
|
|
|
|
sr = soft_mpyshi(-a, b);
|
|
r = hard_mpyshi(-a,b);
|
|
if (r != sr) {
|
|
debugmpy("MPYSHI-NEG: ", -a,b,sr,r);
|
|
return 3;
|
|
}
|
|
|
|
b += 0x197e2*7;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned soft_mpyuhi(unsigned a, unsigned b) {
|
|
unsigned alo, ahi, blo, bhi;
|
|
unsigned rhi, rlhi, rllo;
|
|
|
|
alo = (a & 0x0ffff);
|
|
ahi = (a>>16)& 0x0ffff;
|
|
blo = (b & 0x0ffff);
|
|
bhi = (b>>16)& 0x0ffff;
|
|
|
|
rhi = 0;
|
|
rlhi = 0;
|
|
rllo = 0;
|
|
|
|
for(int i=0; i<16; i++) {
|
|
if (b&(1<<i)) {
|
|
unsigned slo, shi, sup;
|
|
slo = (alo << i);
|
|
shi = (ahi << i);
|
|
shi |= (slo>>16) & 0x0ffff;
|
|
slo &= 0x0ffff;
|
|
sup = (shi>>16)&0x0ffff;
|
|
shi &= 0x0ffff;
|
|
|
|
rhi += sup;
|
|
rlhi += shi;
|
|
rllo += slo;
|
|
|
|
rlhi += (rllo >> 16)&0x0ffff;
|
|
rllo &= 0x0ffff;
|
|
|
|
rhi += (rlhi >> 16)&0x0ffff;
|
|
rlhi &= 0x0ffff;
|
|
}
|
|
}
|
|
|
|
for(int i=16; i<32; i++) {
|
|
if (b&(1<<i)) {
|
|
unsigned slo, shi, sup;
|
|
slo = (alo << (i-16));
|
|
shi = (ahi << (i-16));
|
|
shi |= (slo>>16) & 0x0ffff;
|
|
slo &= 0x0ffff;
|
|
sup = (shi>>16)&0x0ffff;
|
|
shi &= 0x0ffff;
|
|
|
|
rhi += sup << 16;
|
|
rhi += shi;
|
|
rlhi += slo;
|
|
|
|
rhi += (rlhi >> 16)&0x0ffff;
|
|
rlhi &= 0x0ffff;
|
|
}
|
|
}
|
|
|
|
return rhi;
|
|
}
|
|
|
|
int soft_mpyshi(int a, int b) {
|
|
unsigned sgn, r, p;
|
|
|
|
sgn = ((a^b)>>31)&0x01;
|
|
|
|
if (a<0) a = -a;
|
|
if (b<0) b = -b;
|
|
|
|
p = a * b;
|
|
|
|
// This will only fail if the lower 32-bits of of a*b are 0,
|
|
// at which point our following negation won't capture the carry it
|
|
// needs.
|
|
r = soft_mpyuhi(a, b);
|
|
|
|
r = (sgn)?(r^-1):r;
|
|
if ((sgn)&&(p==0))
|
|
r += 1;
|
|
return r;
|
|
}
|
|
|
//brev_test
|
//brev_test
|
//pipeline_test -- used to be called pipeline memory race conditions
|
//pipeline_test -- used to be called pipeline memory race conditions
|
void pipeline_test(void);
|
void pipeline_test(void);
|
asm("\t.global\tpipeline_test\n"
|
asm("\t.text\n\t.global\tpipeline_test\n"
|
"\t.type\tpipeline_test,@function\n"
|
"\t.type\tpipeline_test,@function\n"
|
"pipeline_test:\n"
|
"pipeline_test:\n"
|
"\tSUB\t2,SP\n"
|
"\tSUB\t2,SP\n"
|
// Test setup
|
// Test setup
|
"\tLDI\t275,R2\n"
|
"\tLDI\t275,R2\n"
|
"\tSTO\tR2,1(SP)\n"
|
"\tSTO\tR2,1(SP)\n"
|
"\tMOV\t1(SP),R2\n"
|
"\tMOV\t1(SP),R2\n"
|
"\tSTO\tR2,(SP)\n"
|
"\tSTO\tR2,(SP)\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
//
|
//
|
"\tMOV\tSP,R2\n"
|
"\tMOV\tSP,R2\n"
|
"\tLOD\t(R2),R2\n"
|
"\tLOD\t(R2),R2\n"
|
"\tLOD\t(R2),R2\n"
|
"\tLOD\t(R2),R2\n"
|
"\tCMP\t275,R2\n"
|
"\tCMP\t275,R2\n"
|
"\tOR.NZ\t1,R1\n"
|
"\tOR.NZ\t1,R1\n"
|
//
|
//
|
"\tMOV\tSP,R2\n"
|
"\tMOV\tSP,R2\n"
|
// Here's the test sequence
|
// Here's the test sequence
|
"\tLOD\t(R2),R3\n"
|
"\tLOD\t(R2),R3\n"
|
"\tLOD\t1(R2),R4\n"
|
"\tLOD\t1(R2),R4\n"
|
"\tSTO\tR4,1(R3)\n"
|
"\tSTO\tR4,1(R3)\n"
|
// Make sure we clear the load pipeline
|
// Make sure we clear the load pipeline
|
"\tLOD\t(R2),R3\n"
|
"\tLOD\t(R2),R3\n"
|
// Load our written value
|
// Load our written value
|
"\tLOD\t2(R2),R4\n"
|
"\tLOD\t2(R2),R4\n"
|
"\tCMP\t275,R4\n"
|
"\tCMP\t275,R4\n"
|
"\tOR.NZ\t2,R1\n"
|
"\tOR.NZ\t2,R1\n"
|
//
|
//
|
//
|
//
|
// Next (once upon a time) failing sequence:
|
// Next (once upon a time) failing sequence:
|
// LOD -x(R12),R0
|
// LOD -x(R12),R0
|
// LOD y(R0),R0
|
// LOD y(R0),R0
|
"\tMOV\tSP,R2\n"
|
"\tMOV\tSP,R2\n"
|
"\tMOV\t1(R2),R3\n"
|
"\tMOV\t1(R2),R3\n"
|
"\tSTO\tR3,1(R2)\n"
|
"\tSTO\tR3,1(R2)\n"
|
"\tLDI\t3588,R4\n" // Just some random value
|
"\tLDI\t3588,R4\n" // Just some random value
|
"\tSTO\tR4,2(R2)\n"
|
"\tSTO\tR4,2(R2)\n"
|
"\tMOV\tR2,R3\n"
|
"\tMOV\tR2,R3\n"
|
// Here's the test sequence
|
// Here's the test sequence
|
"\tLOD\t(R2),R3\n"
|
"\tLOD\t(R2),R3\n"
|
"\tLOD\t1(R3),R3\n"
|
"\tLOD\t1(R3),R3\n"
|
"\tCMP\tR4,R3\n"
|
"\tCMP\tR4,R3\n"
|
"\tOR.NZ\t4,R1\n"
|
"\tOR.NZ\t4,R1\n"
|
//
|
//
|
"\tADD\t2,SP\n"
|
"\tADD\t2,SP\n"
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
//mempipe_test
|
//mempipe_test
|
void mempipe_test(void);
|
void mempipe_test(void);
|
asm("\t.global\tmempipe_test\n"
|
asm("\t.text\n\t.global\tmempipe_test\n"
|
"\t.type\tmempipe_test,@function\n"
|
"\t.type\tmempipe_test,@function\n"
|
"mempipe_test:\n"
|
"mempipe_test:\n"
|
"\tSUB\t4,SP\n"
|
"\tSUB\t4,SP\n"
|
"\tSTO\tR0,(SP)\n"
|
"\tSTO\tR0,(SP)\n"
|
"\tLDI\t0x1000,R11\n"
|
"\tLDI\t0x1000,R11\n"
|
// Test #1 ... Let's start by writing a value to memory
|
// Test #1 ... Let's start by writing a value to memory
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tCLR\tR3\n"
|
"\tCLR\tR3\n"
|
"\tSTO\tR2,2(SP)\n"
|
"\tSTO\tR2,2(SP)\n"
|
"\tLOD\t2(SP),R3\n"
|
"\tLOD\t2(SP),R3\n"
|
"\tCMP\tR3,R2\n"
|
"\tCMP\tR3,R2\n"
|
"\tOR.NZ\t1,R1\n"
|
"\tOR.NZ\t1,R1\n"
|
// Test #2, reading and then writing a value from memory
|
// Test #2, reading and then writing a value from memory
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR3\n"
|
"\tCLR\tR3\n"
|
"\tLOD\t2(SP),R2\n" // This should load back up our -1 value
|
"\tLOD\t2(SP),R2\n" // This should load back up our -1 value
|
"\tSTO\tR2,3(SP)\n"
|
"\tSTO\tR2,3(SP)\n"
|
// Insist that the pipeline clear
|
// Insist that the pipeline clear
|
"\tLOD\t2(SP),R2\n"
|
"\tLOD\t2(SP),R2\n"
|
// Now let's try loading into R3
|
// Now let's try loading into R3
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tLOD\t3(SP),R3\n"
|
"\tLOD\t3(SP),R3\n"
|
"\tCMP\tR3,R2\n"
|
"\tCMP\tR3,R2\n"
|
"\tOR.NZ\t2,R1\n"
|
"\tOR.NZ\t2,R1\n"
|
//
|
//
|
"\tLOD\t(SP),R0\n"
|
"\tLOD\t(SP),R0\n"
|
"\tADD\t4,SP\n"
|
"\tADD\t4,SP\n"
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
//cexec_test
|
//cexec_test
|
void cexec_test(void);
|
void cexec_test(void);
|
asm("\t.global\tcexec_test\n"
|
asm("\t.text\n\t.global\tcexec_test\n"
|
"\t.type\tcexec_test,@function\n"
|
"\t.type\tcexec_test,@function\n"
|
"cexec_test:\n"
|
"cexec_test:\n"
|
"\tSUB\t1,SP\n"
|
"\tSUB\t1,SP\n"
|
"\tSTO\tR0,(SP)\n"
|
"\tSTO\tR0,(SP)\n"
|
//
|
//
|
"\tXOR\tR2,R2\n"
|
"\tXOR\tR2,R2\n"
|
"\tADD.Z\t1,R2\n"
|
"\tADD.Z\t1,R2\n"
|
"\tADD.NZ\t1,R1\n"
|
"\tADD.NZ\t1,R1\n"
|
"\tCMP.Z\t0,R2\n"
|
"\tCMP.Z\t0,R2\n"
|
"\tOR.Z\t2,R1\n"
|
"\tOR.Z\t2,R1\n"
|
//
|
//
|
"\tLOD\t(SP),R0\n"
|
"\tLOD\t(SP),R0\n"
|
"\tADD\t1,SP\n"
|
"\tADD\t1,SP\n"
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
// Pipeline stalls have been hideous problems for me. The CPU has been modified
|
// Pipeline stalls have been hideous problems for me. The CPU has been modified
|
// with special logic to keep stages from stalling. For the most part, this
|
// with special logic to keep stages from stalling. For the most part, this
|
// means that ALU and memory results may be accessed either before or as they
|
// means that ALU and memory results may be accessed either before or as they
|
// are written to the register file. This set of code is designed to test
|
// are written to the register file. This set of code is designed to test
|
// whether this bypass logic works.
|
// whether this bypass logic works.
|
//
|
//
|
//nowaitpipe_test
|
//nowaitpipe_test
|
void nowaitpipe_test(void);
|
void nowaitpipe_test(void);
|
asm("\t.global\tnowaitpipe_test\n"
|
asm("\t.text\n\t.global\tnowaitpipe_test\n"
|
"\t.type\tnowaitpipe_test,@function\n"
|
"\t.type\tnowaitpipe_test,@function\n"
|
"nowaitpipe_test:\n"
|
"nowaitpipe_test:\n"
|
"\tSUB\t2,SP\n"
|
"\tSUB\t2,SP\n"
|
//
|
//
|
// Let's start with ALU-ALU testing
|
// Let's start with ALU-ALU testing
|
// AA: result->input A
|
// AA: result->input A
|
"\tLDI\t-1,R2\n"
|
"\tLDI\t-1,R2\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tCMP\t1,R2\n"
|
"\tCMP\t1,R2\n"
|
"\tOR.NZ\t1,R1\n"
|
"\tOR.NZ\t1,R1\n"
|
//
|
//
|
// AA: result -> input B
|
// AA: result -> input B
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR3\n"
|
"\tCLR\tR3\n"
|
"\tADD\t1,R2\n"
|
"\tADD\t1,R2\n"
|
"\tCMP\tR2,R3\n"
|
"\tCMP\tR2,R3\n"
|
"\tOR.Z\t2,R1\n"
|
"\tOR.Z\t2,R1\n"
|
// AA: result -> input A on condition
|
// AA: result -> input A on condition
|
"\tXOR\tR2,R2\n"
|
"\tXOR\tR2,R2\n"
|
"\tADD.Z\t5,R2\n"
|
"\tADD.Z\t5,R2\n"
|
"\tCMP\t5,R2\n"
|
"\tCMP\t5,R2\n"
|
"\tOR.NZ\t4,R1\n"
|
"\tOR.NZ\t4,R1\n"
|
// AA: result -> input B on condition
|
// AA: result -> input B on condition
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tXOR\tR3,R3\n"
|
"\tXOR\tR3,R3\n"
|
"\tADD.Z\t5,R2\n"
|
"\tADD.Z\t5,R2\n"
|
"\tCMP\tR2,R3\n"
|
"\tCMP\tR2,R3\n"
|
"\tOR.Z\t8,R1\n"
|
"\tOR.Z\t8,R1\n"
|
// AA: result->input B plus offset
|
// AA: result->input B plus offset
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tXOR\tR3,R3\n"
|
"\tXOR\tR3,R3\n"
|
"\tADD\t5,R2\n"
|
"\tADD\t5,R2\n"
|
"\tCMP\t-5(R2),R3\n"
|
"\tCMP\t-5(R2),R3\n"
|
"\tOR.NZ\t16,R1\n"
|
"\tOR.NZ\t16,R1\n"
|
// AA: result->input B plus offset on condition
|
// AA: result->input B plus offset on condition
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tXOR\tR3,R3\n"
|
"\tXOR\tR3,R3\n"
|
"\tADD.Z\t5,R2\n"
|
"\tADD.Z\t5,R2\n"
|
"\tCMP\t-5(R2),R3\n"
|
"\tCMP\t-5(R2),R3\n"
|
"\tOR.NZ\t32,R1\n"
|
"\tOR.NZ\t32,R1\n"
|
//
|
//
|
// Then we need to do the ALU-MEM input testing
|
// Then we need to do the ALU-MEM input testing
|
//
|
//
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tSTO\tR2,1(SP)\n"
|
"\tSTO\tR2,1(SP)\n"
|
"\tLDI\t8352,R2\n"
|
"\tLDI\t8352,R2\n"
|
"\tLOD\t1(SP),R2\n"
|
"\tLOD\t1(SP),R2\n"
|
"\tTST\t-1,R2\n"
|
"\tTST\t-1,R2\n"
|
"\tOR.NZ\t64,R1\n"
|
"\tOR.NZ\t64,R1\n"
|
// Let's try again, this time with something that's not zero
|
// Let's try again, this time with something that's not zero
|
"\tLDI\t937,R2\n"
|
"\tLDI\t937,R2\n"
|
"\tSTO\tR2,1(SP)\n"
|
"\tSTO\tR2,1(SP)\n"
|
"\tNOOP\n"
|
"\tNOOP\n"
|
"\tLOD\t1(SP),R2\n"
|
"\tLOD\t1(SP),R2\n"
|
"\tCMP\t938,R2\n"
|
"\tCMP\t938,R2\n"
|
"\tOR.GE\t128,R1\n"
|
"\tOR.GE\t128,R1\n"
|
"\tCMP\t936,R2\n"
|
"\tCMP\t936,R2\n"
|
"\tOR.LT\t256,R1\n"
|
"\tOR.LT\t256,R1\n"
|
// Mem output->ALU input testing
|
// Mem output->ALU input testing
|
// Okay, we just did that as part of our last test
|
// Okay, we just did that as part of our last test
|
// Mem output->mem input testing
|
// Mem output->mem input testing
|
"\tLDI\t5328,R2\n"
|
"\tLDI\t5328,R2\n"
|
"\tLOD\t1(SP),R2\n"
|
"\tLOD\t1(SP),R2\n"
|
"\tSTO\tR2,1(SP)\n"
|
"\tSTO\tR2,1(SP)\n"
|
"\tLOD\t1(SP),R3\n"
|
"\tLOD\t1(SP),R3\n"
|
"\tCMP\t937,R3\n"
|
"\tCMP\t937,R3\n"
|
"\tOR.NZ\t512,R1\n"
|
"\tOR.NZ\t512,R1\n"
|
//
|
//
|
"\tADD\t2,SP\n"
|
"\tADD\t2,SP\n"
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
//bcmem_test
|
//bcmem_test
|
void bcmem_test(void);
|
void bcmem_test(void);
|
asm("\t.global\tbcmem_test\n"
|
asm("\t.text\n.global\tbcmem_test\n"
|
"\t.type\tbcmem_test,@function\n"
|
"\t.type\tbcmem_test,@function\n"
|
"bcmem_test:\n"
|
"bcmem_test:\n"
|
"\tSUB\t1,SP\n"
|
"\tSUB\t1,SP\n"
|
"\tCLR\tR1\n"
|
"\tCLR\tR1\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tLDI\t-1,R3\n"
|
"\tLDI\t-1,R3\n"
|
"\tLDI\t0x13000,R4\n"
|
"\tLDI\t0x13000,R4\n"
|
"\tSTO\tR2,(SP)\n"
|
"\tSTO\tR2,(SP)\n"
|
"\tLOD\t(SP),R3\n"
|
"\tLOD\t(SP),R3\n"
|
"\tCMP\tR2,R3\n"
|
"\tCMP\tR2,R3\n"
|
"\tOR.NZ\t1,R1\n"
|
"\tOR.NZ\t1,R1\n"
|
"\tCMP\t0x13000,R4\n"
|
"\tCMP\t0x13000,R4\n"
|
"\tBZ\tbcmem_test_cmploc_1\n"
|
"\tBZ\tbcmem_test_cmploc_1\n"
|
"\tSTO\tR4,(SP)\n"
|
"\tSTO\tR4,(SP)\n"
|
"bcmem_test_cmploc_1:\n"
|
"bcmem_test_cmploc_1:\n"
|
"\tLOD\t(SP),R2\n"
|
"\tLOD\t(SP),R2\n"
|
"\tCMP\tR2,R4\n"
|
"\tCMP\tR2,R4\n"
|
"\tOR.Z\t2,R1\n"
|
"\tOR.Z\t2,R1\n"
|
"\tCLR\tR2\n"
|
"\tCLR\tR2\n"
|
"\tCMP\tR2,R4\n"
|
"\tCMP\tR2,R4\n"
|
"\tBZ\tbcmem_test_cmploc_2\n"
|
"\tBZ\tbcmem_test_cmploc_2\n"
|
"\tSTO.NZ\tR4,(SP)\n"
|
"\tSTO.NZ\tR4,(SP)\n"
|
"bcmem_test_cmploc_2:\n"
|
"bcmem_test_cmploc_2:\n"
|
"\tLOD\t(SP),R2\n"
|
"\tLOD\t(SP),R2\n"
|
"\tCMP\tR2,R4\n"
|
"\tCMP\tR2,R4\n"
|
"\tOR.NZ\t4,R1\n"
|
"\tOR.NZ\t4,R1\n"
|
//
|
//
|
"\tADD\t1,SP\n"
|
"\tADD\t1,SP\n"
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
|
// The illegal instruction test. Specifically, illegal instructions cannot be
|
|
// allowed to execute. The PC must, upon completion, point to the illegal
|
|
// instruction that caused the exception.
|
|
//
|
|
// To create our illegal instruction, we assume that the only the three
|
|
// operations without arguments are NOOP, BREAK, LOCK, and so we envision a
|
|
// fourth instruction to create.
|
|
void ill_test(void);
|
|
asm("\t.text\n.global\till_test\n"
|
|
"\t.type\till_test,@function\n"
|
|
"ill_test:\n"
|
|
"\t.word\t0x7ff00000\n"
|
|
"\tJMP\tR0\n");
|
|
|
//
|
//
|
// The CC register has some ... unique requirements associated with it.
|
// The CC register has some ... unique requirements associated with it.
|
// Particularly, flags are unavailable until after an ALU operation completes,
|
// Particularly, flags are unavailable until after an ALU operation completes,
|
// and they can't really be bypassed for the CC register. After writeback,
|
// and they can't really be bypassed for the CC register. After writeback,
|
// the "new" CC register isn't really available for another clock. Trying to
|
// the "new" CC register isn't really available for another clock. Trying to
|
// bypass this extra clock can have problems, since ... some bits are fixed,
|
// bypass this extra clock can have problems, since ... some bits are fixed,
|
// some bits can only be changed by the supervisor, and others can/will change
|
// some bits can only be changed by the supervisor, and others can/will change
|
// and even have effects--like sending the CPU to supervisor mode or
|
// and even have effects--like sending the CPU to supervisor mode or
|
// alternatively to sleep.
|
// alternatively to sleep.
|
//
|
//
|
// Here, let's see if our pipeline can successfully navigate any of these
|
// Here, let's see if our pipeline can successfully navigate any of these
|
// issues.
|
// issues.
|
//
|
//
|
void ccreg_test(void);
|
void ccreg_test(void);
|
asm("\t.global\tccreg_test\n"
|
asm("\t.text\n.global\tccreg_test\n"
|
"\t.type\tccreg_test,@function\n"
|
"\t.type\tccreg_test,@function\n"
|
"ccreg_test:\n"
|
"ccreg_test:\n"
|
// First test: If we try to change the fixed bits, will they change
|
// First test: If we try to change the fixed bits, will they change
|
// because the pipeline tries to bypass the write-back stage
|
// because the pipeline tries to bypass the write-back stage
|
"\tCLR\tR1\n" // We'll start with an "answer" of success
|
"\tCLR\tR1\n" // We'll start with an "answer" of success
|
"\tMOV\tCC,R2\n"
|
"\tMOV\tCC,R2\n"
|
"\tMOV\tR2,R4\n" // Keep a copy
|
"\tMOV\tR2,R4\n" // Keep a copy
|
"\tBREV\t0x0ff,R3\n" // Attempt to change the top fixed bits
|
"\tBREV\t0x0ff,R3\n" // Attempt to change the top fixed bits
|
"\tXOR\tR3,R2\n" // Arrange for the changes
|
"\tXOR\tR3,R2\n" // Arrange for the changes
|
"\tMOV\tR2,CC\n" // Set the changes (they won't take)
|
"\tMOV\tR2,CC\n" // Set the changes (they won't take)
|
"\tMOV\tCC,R5\n" // See if the pipeline makes them take
|
"\tMOV\tCC,R5\n" // See if the pipeline makes them take
|
"\tXOR\tR4,R5\n" // Let's look for anything that has changed
|
"\tXOR\tR4,R5\n" // Let's look for anything that has changed
|
"\tOR.NZ\t1,R1\n" // If anything has changed, then we fail the tst
|
"\tOR.NZ\t1,R1\n" // If anything has changed, then we fail the tst
|
//
|
//
|
// Test #2: Can we set the flags?
|
// Test #2: Can we set the flags?
|
"\tMOV\tCC,R6\n"
|
"\tMOV\tCC,R6\n"
|
"\tOR\t15,R6\n"
|
"\tOR\t15,R6\n"
|
"\tMOV\tR6,CC\n"
|
"\tMOV\tR6,CC\n"
|
"\tMOV\tCC,R7\n"
|
"\tMOV\tCC,R7\n"
|
"\tAND\t15,R7\n"
|
"\tAND\t15,R7\n"
|
"\tCMP\t15,R7\n"
|
"\tCMP\t15,R7\n"
|
"\tOR.NZ\t2,R1\n"
|
"\tOR.NZ\t2,R1\n"
|
//
|
//
|
// Test #3: How about setting specific flags, and immediately acting
|
// Test #3: How about setting specific flags, and immediately acting
|
// on them?
|
// on them?
|
"\tXOR\t1+R8,R8\n" // Turn off the Z bit
|
"\tXOR\t1+R8,R8\n" // Turn off the Z bit
|
"\tOR\t1,CC\n" // Turn on the Z bit
|
"\tOR\t1,CC\n" // Turn on the Z bit
|
"\tOR.NZ\t4,R1\n"
|
"\tOR.NZ\t4,R1\n"
|
//
|
//
|
// Test #4: Can we load the CC plus a value into a register?
|
// Test #4: Can we load the CC plus a value into a register?
|
// I don't think so ...
|
// I don't think so ...
|
"\tJMP\tR0\n");
|
"\tJMP\tR0\n");
|
|
|
// Multiple argument test
|
// Multiple argument test
|
__attribute__((noinline))
|
__attribute__((noinline))
|
int multiarg_subroutine(int a, int b, int c, int d, int e, int f, int g) {
|
int multiarg_subroutine(int a, int b, int c, int d, int e, int f, int g) {
|
if (a!=0) return 1;
|
if (a!=0) return 1;
|
if (b!=1) return 2;
|
if (b!=1) return 2;
|
if (c!=2) return 4;
|
if (c!=2) return 4;
|
if (d!=3) return 8;
|
if (d!=3) return 8;
|
if (e!=4) return 16;
|
if (e!=4) return 16;
|
if (f!=5) return 32;
|
if (f!=5) return 32;
|
if (g!=6) return 64;
|
if (g!=6) return 64;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int multiarg_test(void) {
|
int multiarg_test(void) {
|
return multiarg_subroutine(0,1,2,3,4,5,6);
|
return multiarg_subroutine(0,1,2,3,4,5,6);
|
}
|
}
|
|
|
__attribute__((noinline))
|
__attribute__((noinline))
|
void wait(unsigned int msk) {
|
void wait(unsigned int msk) {
|
*PIC = 0x7fff0000|msk;
|
*PIC = 0x7fff0000|msk;
|
asm("MOV\tidle_task(PC),uPC\n");
|
asm("MOV\tidle_task(PC),uPC\n");
|
*PIC = 0x80000000|(msk<<16);
|
*PIC = 0x80000000|(msk<<16);
|
asm("WAIT\n");
|
asm("WAIT\n");
|
*PIC = 0; // Turn interrupts back off, lest they confuse the test
|
*PIC = 0; // Turn interrupts back off, lest they confuse the test
|
}
|
}
|
|
|
asm("\nidle_task:\n\tWAIT\n\tBRA\tidle_task\n");
|
asm("\n\t.text\nidle_task:\n\tWAIT\n\tBRA\tidle_task\n");
|
|
|
__attribute__((noinline))
|
__attribute__((noinline))
|
void txchr(char v) {
|
void txchr(char v) {
|
|
if (zip_cc() & CC_GIE) {
|
|
while(*UARTTX & 0x100)
|
|
;
|
|
} else
|
wait(INT_UARTTX);
|
wait(INT_UARTTX);
|
*UARTTX = v;
|
*UARTTX = v;
|
}
|
}
|
|
|
__attribute__((noinline))
|
__attribute__((noinline))
|
void txstr(const char *str) {
|
void txstr(const char *str) {
|
const char *ptr = str;
|
const char *ptr = str;
|
while(*ptr)
|
while(*ptr)
|
txchr(*ptr++);
|
txchr(*ptr++);
|
}
|
}
|
|
|
__attribute__((noinline))
|
__attribute__((noinline))
|
void txhex(int num) {
|
void txhex(int num) {
|
for(int ds=28; ds>=0; ds-=4) {
|
for(int ds=28; ds>=0; ds-=4) {
|
int ch;
|
int ch;
|
ch = (num >> ds)&0x0f;
|
ch = (num >> ds)&0x0f;
|
if (ch >= 10)
|
if (ch >= 10)
|
ch = 'A'+ch-10;
|
ch = 'A'+ch-10;
|
else
|
else
|
ch += '0';
|
ch += '0';
|
txchr(ch);
|
txchr(ch);
|
}
|
}
|
}
|
}
|
|
|
__attribute__((noinline))
|
__attribute__((noinline))
|
|
void tx4hex(int num) {
|
|
if (num & 0xffff0000){
|
|
txhex(num);
|
|
return;
|
|
} for(int ds=12; ds>=0; ds-=4) {
|
|
int ch;
|
|
ch = (num >> ds)&0x0f;
|
|
if (ch >= 10)
|
|
ch = 'A'+ch-10;
|
|
else
|
|
ch += '0';
|
|
txchr(ch);
|
|
}
|
|
}
|
|
|
|
__attribute__((noinline))
|
void txreg(const char *name, int val) {
|
void txreg(const char *name, int val) {
|
txstr(name); // 4 characters
|
txstr(name); // 4 characters
|
txstr("0x"); // 2 characters
|
txstr("0x"); // 2 characters
|
txhex(val); // 8 characters
|
txhex(val); // 8 characters
|
txstr(" "); // 4 characters
|
txstr(" "); // 4 characters
|
}
|
}
|
|
|
__attribute__((noinline))
|
__attribute__((noinline))
|
void save_context(int *context) {
|
void save_context(int *context) {
|
zip_save_context(context);
|
zip_save_context(context);
|
}
|
}
|
|
|
__attribute__((noinline))
|
__attribute__((noinline))
|
void test_fails(int start_time, int *listno) {
|
void test_fails(int start_time, int *listno) {
|
int context[16], stop_time;
|
int context[16], stop_time;
|
|
|
// Trigger the scope, if it hasn't already triggered. Otherwise,
|
// Trigger the scope, if it hasn't already triggered. Otherwise,
|
// if it has triggered, don't clear it.
|
// if it has triggered, don't clear it.
|
#ifdef HAVE_SCOPE
|
#ifdef HAVE_SCOPE
|
*SCOPE = 0x8f000004;
|
*SCOPE = TRIGGER_SCOPE_NOW;
|
#endif
|
#endif
|
|
|
MARKSTOP;
|
MARKSTOP;
|
save_context(context);
|
save_context(context);
|
*listno++ = context[1];
|
*listno++ = context[1];
|
*listno++ = context[14];
|
*listno++ = context[14];
|
*listno++ = context[15];
|
*listno++ = context[15];
|
#ifdef HAVE_COUNTER
|
#ifdef HAVE_COUNTER
|
*listno = stop_time;
|
*listno = stop_time;
|
#endif
|
#endif
|
|
|
txstr("FAIL!\r\n\r\n");
|
txstr("FAIL!\r\n\r\n");
|
txstr("Between 0x"); txhex(start_time);
|
txstr("Between 0x"); txhex(start_time);
|
txstr(" and 0x"); txhex(stop_time); txstr("\r\n\r\n");
|
txstr(" and 0x"); txhex(stop_time); txstr("\r\n\r\n");
|
txstr("Core-dump:\r\n");
|
txstr("Core-dump:\r\n");
|
txreg("uR0 : ", context[0]);
|
txreg("uR0 : ", context[0]);
|
txreg("uR1 : ", context[1]);
|
txreg("uR1 : ", context[1]);
|
txreg("uR2 : ", context[2]);
|
txreg("uR2 : ", context[2]);
|
txreg("uR3 : ", context[3]);
|
txreg("uR3 : ", context[3]);
|
txstr("\r\n");
|
txstr("\r\n");
|
|
|
txreg("uR4 : ", context[4]);
|
txreg("uR4 : ", context[4]);
|
txreg("uR5 : ", context[5]);
|
txreg("uR5 : ", context[5]);
|
txreg("uR6 : ", context[6]);
|
txreg("uR6 : ", context[6]);
|
txreg("uR7 : ", context[7]);
|
txreg("uR7 : ", context[7]);
|
txstr("\r\n");
|
txstr("\r\n");
|
|
|
txreg("uR8 : ", context[8]);
|
txreg("uR8 : ", context[8]);
|
txreg("uR9 : ", context[9]);
|
txreg("uR9 : ", context[9]);
|
txreg("uR10: ", context[10]);
|
txreg("uR10: ", context[10]);
|
txreg("uR11: ", context[11]);
|
txreg("uR11: ", context[11]);
|
txstr("\r\n");
|
txstr("\r\n");
|
|
|
txreg("uR12: ", context[12]);
|
txreg("uR12: ", context[12]);
|
txreg("uSP : ", context[13]);
|
txreg("uSP : ", context[13]);
|
txreg("uCC : ", context[14]);
|
txreg("uCC : ", context[14]);
|
txreg("uPC : ", context[15]);
|
txreg("uPC : ", context[15]);
|
txstr("\r\n\r\n");
|
txstr("\r\n\r\n");
|
|
|
asm("\tBUSY");
|
// While previous versions of cputest.c called zip_busy(), here we
|
|
// reject that notion for the simple reason that zip_busy may not
|
|
// necessarily halt any Verilator simulation. Instead, we try to
|
|
// halt the CPU.
|
|
while(1)
|
|
zip_halt();
|
}
|
}
|
|
|
void testid(const char *str) {
|
void testid(const char *str) {
|
const int WIDTH=32;
|
const int WIDTH=32;
|
txstr(str);
|
txstr(str);
|
const char *ptr = str;
|
const char *ptr = str;
|
int i = 0;
|
int i = 0;
|
while(0 != *ptr++)
|
while(0 != *ptr++)
|
i++;
|
i++;
|
i = WIDTH-i;
|
i = WIDTH-i;
|
while(i-- > 0)
|
while(i-- > 0)
|
txchr(' ');
|
txchr(' ');
|
}
|
}
|
|
|
int testlist[32];
|
int testlist[32];
|
|
|
void entry(void) {
|
void entry(void) {
|
int context[16];
|
int context[16];
|
int user_stack[256], *user_stack_ptr = &user_stack[256];
|
int user_stack[256], *user_stack_ptr = &user_stack[256];
|
int start_time, i;
|
int start_time, i;
|
|
|
for(i=0; i<32; i++)
|
for(i=0; i<32; i++)
|
testlist[i] = -1;
|
testlist[i] = -1;
|
|
|
#ifdef HAVE_TIMER
|
#ifdef HAVE_TIMER
|
*TIMER = 0x7fffffff;
|
*TIMER = 0x7fffffff;
|
#endif
|
#endif
|
#ifdef HAVE_COUNTER
|
#ifdef HAVE_COUNTER
|
*COUNTER = 0;
|
*COUNTER = 0;
|
#endif
|
#endif
|
|
#ifdef HAVE_SCOPE
|
// #define STACKTEST asm("CMP\t16108,SP\n\tHALT.NZ\n")
|
*SCOPE = PREPARE_SCOPE;
|
#define STACKTEST
|
#endif
|
STACKTEST;
|
|
|
|
// *UART_CTRL = 8333; // 9600 Baud, 8-bit chars, no parity, one stop bit
|
// *UART_CTRL = 8333; // 9600 Baud, 8-bit chars, no parity, one stop bit
|
*UART_CTRL = 25; // 9600 Baud, 8-bit chars, no parity, one stop bit
|
*UART_CTRL = 25; // 9600 Baud, 8-bit chars, no parity, one stop bit
|
//
|
//
|
STACKTEST;
|
|
|
|
txstr("\r\n");
|
txstr("\r\n");
|
txstr("Running CPU self-test\n");
|
txstr("Running CPU self-test\r\n");
|
txstr("-----------------------------------\r\n");
|
txstr("-----------------------------------\r\n");
|
|
|
int tnum = 0;
|
int tnum = 0;
|
STACKTEST;
|
|
|
|
// Test break instruction in user mode
|
// Test break instruction in user mode
|
// Make sure the break works as designed
|
// Make sure the break works as designed
|
testid("Break test #1"); MARKSTART;
|
testid("Break test #1"); MARKSTART;
|
STACKTEST;
|
|
|
|
if ((run_test(break_one, user_stack_ptr))||(zip_ucc()&0x1f50))
|
if ((run_test(break_one, user_stack_ptr))||(zip_ucc()&0x1f50))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
STACKTEST;
|
|
|
|
save_context(context);
|
save_context(context);
|
if ((context[15] != (int)break_one+1)||(0==(zip_ucc()&0x80)))
|
if ((context[15] != (int)break_one+1)||(0==(zip_ucc()&0x80)))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // 0
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // 0
|
|
|
STACKTEST;
|
|
|
|
// Test break instruction in user mode
|
// Test break instruction in user mode
|
// Make sure that a decision on the clock prior won't still cause a
|
// Make sure that a decision on the clock prior won't still cause a
|
// break condition
|
// break condition
|
testid("Break test #2"); MARKSTART;
|
testid("Break test #2"); MARKSTART;
|
if ((run_test(break_two, user_stack_ptr))||(zip_ucc()&0x1d90))
|
if ((run_test(break_two, user_stack_ptr))||(zip_ucc()&0x1d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #1
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #1
|
|
|
// LJMP test ... not (yet) written
|
// LJMP test ... not (yet) written
|
|
|
// Test the early branching capability
|
// Test the early branching capability
|
// Does it successfully clear whatever else is in the pipeline?
|
// Does it successfully clear whatever else is in the pipeline?
|
testid("Early Branch test"); MARKSTART;
|
testid("Early Branch test"); MARKSTART;
|
if ((run_test(early_branch_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(early_branch_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #2
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #2
|
|
|
// TRAP test
|
// TRAP test
|
testid("Trap test/AND"); MARKSTART;
|
testid("Trap test/AND"); MARKSTART;
|
if ((run_test(trap_test_and, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(trap_test_and, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
if ((zip_ucc() & 0x0200)==0)
|
if ((zip_ucc() & 0x0200)==0)
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #3
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #3
|
|
|
testid("Trap test/CLR"); MARKSTART;
|
testid("Trap test/CLR"); MARKSTART;
|
if ((run_test(trap_test_clr, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(trap_test_clr, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
if ((zip_ucc() & 0x0200)==0)
|
if ((zip_ucc() & 0x0200)==0)
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #4
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #4
|
|
|
// Overflow test
|
// Overflow test
|
testid("Overflow test"); MARKSTART;
|
testid("Overflow test"); MARKSTART;
|
if ((run_test(overflow_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(overflow_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #5
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #5
|
|
|
// Carry test
|
// Carry test
|
testid("Carry test"); MARKSTART;
|
testid("Carry test"); MARKSTART;
|
if ((run_test(carry_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(carry_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #6
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #6
|
|
|
// LOOP_TEST
|
// LOOP_TEST
|
testid("Loop test"); MARKSTART;
|
testid("Loop test"); MARKSTART;
|
if ((run_test(loop_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(loop_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #7 -- FAILS
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #7 -- FAILS
|
|
|
// SHIFT_TEST
|
// SHIFT_TEST
|
testid("Shift test"); MARKSTART;
|
testid("Shift test"); MARKSTART;
|
if ((run_test(shift_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(shift_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #8
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #8
|
|
|
// MPY_TEST
|
|
testid("Multiply test"); MARKSTART;
|
|
if ((run_test(mpy_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
|
test_fails(start_time, &testlist[tnum]);
|
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #9
|
|
|
|
// BREV_TEST
|
// BREV_TEST
|
//testid("BREV/stack test"); MARKSTART;
|
//testid("BREV/stack test"); MARKSTART;
|
//if ((run_test(brev_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
//if ((run_test(brev_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
//test_fails(start_time);
|
//test_fails(start_time);
|
//txstr("Pass\r\n");
|
//txstr("Pass\r\n");
|
|
|
// PIPELINE_TEST
|
// PIPELINE_TEST
|
testid("Pipeline test"); MARKSTART;
|
testid("Pipeline test"); MARKSTART;
|
if ((run_test(pipeline_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(pipeline_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #10
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #10
|
|
|
// MEM_PIPELINE_STACK_TEST
|
// MEM_PIPELINE_STACK_TEST
|
testid("Mem-Pipeline test"); MARKSTART;
|
testid("Mem-Pipeline test"); MARKSTART;
|
if ((run_test(mempipe_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(mempipe_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #11
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #11
|
|
|
// CONDITIONAL EXECUTION test
|
// CONDITIONAL EXECUTION test
|
testid("Conditional Execution test"); MARKSTART;
|
testid("Conditional Execution test"); MARKSTART;
|
if ((run_test(cexec_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(cexec_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #12 -- FAILS
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #12 -- FAILS
|
|
|
// NOWAIT pipeline test
|
// NOWAIT pipeline test
|
testid("No-waiting pipeline test"); MARKSTART;
|
testid("No-waiting pipeline test"); MARKSTART;
|
if ((run_test(nowaitpipe_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(nowaitpipe_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #13
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #13
|
|
|
// BCMEM test
|
// BCMEM test
|
testid("Conditional Branching test"); MARKSTART;
|
testid("Conditional Branching test"); MARKSTART;
|
if ((run_test(bcmem_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(bcmem_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #14
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #14
|
|
|
// Illegal Instruction test
|
// Illegal Instruction test
|
testid("Illegal Instruction test"); MARKSTART;
|
testid("Ill Instruction test, NULL PC"); MARKSTART;
|
if ((run_test(NULL, user_stack_ptr))||((zip_ucc()^0x100)&0x01d90))
|
if ((run_test(NULL, user_stack_ptr))||((zip_ucc()^0x100)&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0;
|
txstr("Pass\r\n"); testlist[tnum++] = 0;
|
|
|
|
// Illegal Instruction test
|
|
testid("Ill Instruction test, two"); MARKSTART;
|
|
if ((run_test(ill_test, user_stack_ptr))||((zip_ucc()^0x100)&0x01d90))
|
|
test_fails(start_time, &testlist[tnum]);
|
|
save_context(context);
|
|
if (context[15] != (int)&ill_test)
|
|
test_fails(start_time, &testlist[tnum]);
|
|
txstr("Pass\r\n"); testlist[tnum++] = 0;
|
|
|
// Pipeline memory race condition test
|
// Pipeline memory race condition test
|
// DIVIDE test
|
// DIVIDE test
|
|
|
// CC Register test
|
// CC Register test
|
testid("CC Register test"); MARKSTART;
|
testid("CC Register test"); MARKSTART;
|
if ((run_test(ccreg_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(ccreg_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0;
|
txstr("Pass\r\n"); testlist[tnum++] = 0;
|
|
|
// Multiple argument test
|
// Multiple argument test
|
testid("Multi-Arg test"); MARKSTART;
|
testid("Multi-Arg test"); MARKSTART;
|
if ((run_test(multiarg_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
if ((run_test(multiarg_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
test_fails(start_time, &testlist[tnum]);
|
test_fails(start_time, &testlist[tnum]);
|
txstr("Pass\r\n"); testlist[tnum++] = 0;
|
txstr("Pass\r\n"); testlist[tnum++] = 0;
|
|
|
|
// MPY_TEST
|
|
testid("Multiply test"); MARKSTART;
|
|
if ((run_test(mpy_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
|
test_fails(start_time, &testlist[tnum]);
|
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #9
|
|
|
|
// MPYxHI_TEST
|
|
testid("Multiply HI-word test"); MARKSTART;
|
|
if ((run_test(mpyhi_test, user_stack_ptr))||(zip_ucc()&0x01d90))
|
|
test_fails(start_time, &testlist[tnum]);
|
|
txstr("Pass\r\n"); testlist[tnum++] = 0; // #9
|
txstr("\r\n");
|
txstr("\r\n");
|
txstr("-----------------------------------\r\n");
|
txstr("-----------------------------------\r\n");
|
txstr("All tests passed. Halting CPU.\n");
|
txstr("All tests passed. Halting CPU.\r\n");
|
zip_halt();
|
zip_halt();
|
}
|
}
|
|
|
// To build this:
|
// To build this:
|
// zip-gcc -O3 -Wall -Wextra -nostdlib -fno-builtin -T xula.ld -Wl,-Map,cputest.map cputest.cpp -o cputest
|
// zip-gcc -O3 -Wall -Wextra -nostdlib -fno-builtin -T xula.ld -Wl,-Map,cputest.map cputest.cpp -o cputest
|
// zip-objdump -D cputest > cputest.txt
|
// zip-objdump -D cputest > cputest.txt
|
//
|
//
|
|
|