OpenCores
URL https://opencores.org/ocsvn/s6soc/s6soc/trunk

Subversion Repositories s6soc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /s6soc/trunk
    from Rev 52 to Rev 53
    Reverse comparison

Rev 52 → Rev 53

/sw/dev/asmstartup.h File deleted
/sw/dev/Makefile
45,8 → 45,9
################################################################################
##
##
# Declare "all" to be the default target
all:
PROGRAMS := helloworld doorbell doorbell2 kptest blinky
PROGRAMS := helloworld doorbell doorbell2 kptest blinky cputest uartecho
all: $(OBJDIR)/ $(PROGRAMS)
 
 
61,14 → 62,16
# Not for build, for for building tags and dependency files, we need to know
# what the sources and headers are
DEVDRVR:= keypad.c display.c rtcsim.c txfns.c
SOURCES:= helloworld.c doorbell.c doorbell2.c kptest.c $(DEVDRVR)
SOURCES:= helloworld.c doorbell.c doorbell2.c kptest.c uartecho.c $(DEVDRVR)
HEADERS:= board.h
OBJDRVR := $(addprefix $(OBJDIR)/,$(subst .c,.o,$(DEVDRVR)))
 
CPPFLAGS := -I../zipos -I.
DUMPFLAGS := # -fdump-rtl-all
CFLAGS := $(CPPFLAGS) $(DUMPFLAGS) -O3 -Wall -Wextra -nostdlib -fno-builtin -Wa,-nocis
CFLAGS := $(CPPFLAGS) $(DUMPFLAGS) -O3 -Wall -Wextra -nostdlib -fno-builtin
LDFLAGS = -T cmod.ld -Wl,-Map,$(OBJDIR)/$@.map -Wl,--unresolved-symbols=report-all -nostdlib
STARTUP := resetdump.s
STARTOBJ:= $(addprefix $(OBJDIR)/,$(subst .s,.o,$(STARTUP)))
 
$(OBJDIR)/:
$(mk-objdir)
78,9 → 81,18
$(OBJDIR)/%.o: %.c
$(mk-objdir)
$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR)/cputest.o: cputest.c
$(mk-objdir)
$(CC) $(CFLAGS) -Wa,-nocis -c $< -o $@
$(OBJDIR)/cputestcis.o: cputest.c
$(mk-objdir)
$(CC) $(CFLAGS) -Wa,-cis -c $< -o $@
$(OBJDIR)/%.o: ../zipos/%.c
$(mk-objdir)
$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR)/%.o: %.s
$(mk-objdir)
$(AS) -nocis $< -o $@
 
$(OBJDIR)/%.s: %.c
$(mk-objdir)
93,29 → 105,38
$(OBJDUMP) -Dr $< > $@
 
 
helloworld: $(OBJDIR)/helloworld.o cmod.ld
$(CC) $(LDFLAGS) $(OBJDIR)/helloworld.o -o $@
helloworld: $(OBJDIR)/helloworld.o $(STARTOBJ) cmod.ld
$(CC) $(LDFLAGS) $(STARTOBJ) $(OBJDIR)/helloworld.o -o $@
$(OBJDIR)/helloworld.txt: helloworld
$(OBJDUMP) -dr $^ > $@
 
doorbell: $(OBJDIR)/doorbell.o cmod.ld
$(CC) $(LDFLAGS) $(OBJDIR)/doorbell.o -o $@
uartecho: $(OBJDIR)/uartecho.o $(STARTOBJ) cmod.ld
$(CC) $(LDFLAGS) $(STARTOBJ) $(OBJDIR)/uartecho.o -o $@
 
doorbell2: $(OBJDIR)/doorbell2.o $(OBJDRVR) $(OBJDIR)/string.o cmod.ld
$(CC) $(LDFLAGS) $(OBJDIR)/doorbell2.o $(OBJDRVR) $(OBJDIR)/string.o -o $@
doorbell: $(OBJDIR)/doorbell.o $(STARTOBJ) cmod.ld
$(CC) $(LDFLAGS) $(STARTOBJ) $(OBJDIR)/doorbell.o -o $@
 
doorbell2: $(OBJDIR)/doorbell2.o $(OBJDRVR) $(STARTOBJ) $(OBJDIR)/string.o cmod.ld
$(CC) $(LDFLAGS) $(STARTOBJ) $(OBJDIR)/doorbell2.o $(OBJDRVR) $(OBJDIR)/string.o -o $@
$(OBJDIR)/doorbell2.txt: doorbell2
$(OBJDUMP) -dr $^ > $@
 
KPSRCS := kptest.c keypad.c txfns.c
KPOBJS := $(addprefix $(OBJDIR)/,$(subst .c,.o,$(KPSRCS)))
kptest: $(KPOBJS) cmod.ld
$(CC) $(LDFLAGS) $(KPOBJS) -o $@
kptest: $(KPOBJS) $(STARTOBJ) cmod.ld
$(CC) $(LDFLAGS) $(STARTOBJ) $(KPOBJS) -o $@
$(OBJDIR)/kptest.txt: kptest
$(OBJDUMP) -dr $^ > $@
 
blinky: $(OBJDIR)/blinky.o cmod.ld
$(CC) $(LDFLAGS) $(OBJDIR)/blinky.o -o $@
$(CC) $(LDFLAGS) $(STARTOBJ) $(OBJDIR)/blinky.o -o $@
 
cputest: $(OBJDIR)/cputest.o cmod.ld
$(CC) $(LDFLAGS) $(OBJDIR)/cputest.o -o $@
 
cputestcis: $(OBJDIR)/cputestcis.o cmod.ld
$(CC) $(LDFLAGS) $(OBJDIR)/cputestcis.o -o $@
 
define mk-objdir
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi"
endef
/sw/dev/asmstartup.s
0,0 → 1,58
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Filename: asmstartup.s
;;
;; Project: CMod S6 System on a Chip, ZipCPU demonstration project
;;
;; Purpose: A small assembly routine, designed to place the startup code
;; into the very beginning of the program space (i.e. crt0.s).
;; This startup code *must* start at the RESET_ADDRESS of the ZipCPU. It
;; does two things: 1) loads a valid stack pointer, and 2) jumps to the
;; entry point in the program which (as a result of this startup code)
;; may be anywhere in the address space.
;;
;; Creator: Dan Gisselquist, Ph.D.
;; Gisselquist Technology, LLC
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Copyright (C) 2015-2017, Gisselquist Technology, LLC
;;
;; 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
;; 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory, run make with no
;; target there if the PDF file isn't present.) If not, see
;; <http://www.gnu.org/licenses/> for a copy.
;;
;; License: GPL, v3, as defined and found on www.gnu.org,
;; http://www.gnu.org/licenses/gpl.html
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;
.section .start,"ax",@progbits
.global _start
.type _start,@function
_start:
NDUMP
LDI 255,R0 ; Turn all the LEDs on
SW R0,(SPIO)
MOV kernel_exit(PC),uPC
LDI _top_of_stack,SP
JSR entry
NEXIT R0 ; Exit on return if in a simulator
kernel_exit:
HALT ; Otherwise just halt the CPU
BRA kernel_exit ; In case were called from user mode
 
.set SPIO, 0x0414
/sw/dev/blinky.c
38,27 → 38,10
////////////////////////////////////////////////////////////////////////////////
//
//
// #include "asmstartup.h"
#include "board.h"
 
void zip_idle(void);
 
asm("\t.section\t.start\n"
"\t.global\t_start\n"
"\t.type\t_start,@function\n"
"_start:\n"
"\tMOV\tkernel_exit(PC),uPC\n"
"\tLDI 104,R0\n"
"\tSW R0,0x41c\n"
"\tLDI 0xff,R0\n"
"\tSW R0,0x414\n"
"\tLDI\t_top_of_stack,SP\n"
"\tJSR\tentry\n"
"\tNEXIT\tR0\n"
"kernel_exit:\n"
"\tBUSY\n"
"\t.section\t.text");
 
void entry(void) {
const char *msg = "Hello, World!\r\n", *ptr = msg;
int count = 0;
/sw/dev/board.h
109,13 → 109,32
#define IOADDR 0x000400
#define SCOPEADDR 0x000800
// #define FCTLADDR 0x000c00 // Flash control, depends upon write capability
#define RAMADDR 0x004000
#define BKRAM (void *)0x004000
#define FLASH (void *)0x1000000
#define SDRAM (void *)0
#define RAMSZ (RAMADDR)
#define FLASHADDR 0x1000000
#define FLASHSZ (FLASHADDR)
#define MEMLEN 0x04000
#define FLASHLEN 0x1000000
#define RESET_ADDR 0x1200000
#define FLASHSZ (FLASHADDR)
 
#define CLOCKFREQHZ 80000000
#define CLOCKFREQ_HZ CLOCKFREQHZ
 
static volatile IOSPACE *const _sys = (IOSPACE *)IOADDR;
#define _ZIP_HAS_WBUARTRX
#define _uartrx _sys->io_uart
#define _ZIP_HAS_LONELY_UART
#define LONELY_UART
#define _uart _sys->io_uart
 
static volatile WBSCOPE *const _scope = (WBSCOPE *)SCOPEADDR;
 
#define SYSTIMER _sys->io_timer
#define SYSPIC _sys->io_pic
 
#define valid_ram_region(PTR,LN) (((int)(PTR)>=RAMADDR)&&((int)(PTR+LN)<RAMADDR+RAMSZ))
#define valid_flash_region(PTR,LN) (((int)(PTR)>=FLASHADDR)&&((int)(PTR+LN)<FLASHADDR+FLASHSZ))
#define valid_mem_region(PTR,LN) ((valid_ram_region(PTR,LN))||(valid_flash_region(PTR,LN)))
 
#endif
/sw/dev/cmod.ld
38,14 → 38,36
flash (rx) : ORIGIN = 0x1000000, LENGTH = 0x1000000
}
 
_flash = ORIGIN(flash);
_blkram = ORIGIN(blkram);
_sdram = 0;
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 4;
_sdram_image_start = 0;
_sdram_image_end = 0;
 
SECTIONS
{
. = 0x1200000;
.rocode 0x1200000 : { *(.start) *(.text*)
*(.rodata*)
*(.strings*) } > flash
.data : { *(.fixdata*) *(.data*) *(COMMON*) *(.bss*) } > blkram
_top_of_heap = .;
.rocode 0x1200000 : ALIGN(4) {
_boot_address = .;
*(.start) *(.boot*)
*(.text*)
*(.rodata*)
*(.strings*)
__rocode_alignment = (. + 3) & ~ 3;
. = __rocode_alignment;
} > flash
_kernel_image_start = . ;
.data : ALIGN_WITH_INPUT {
*(.kernel*)
*(.fixdata*)
*(.data*)
*(COMMON*)
_kernel_image_end = . ;
}> blkram AT> flash
_blkram_image_end = . ;
.bss : ALIGN_WITH_INPUT {
*(.bss*)
_bss_image_end = . ;
} > blkram
_top_of_heap = .;
}
/sw/dev/cputest.c
0,0 → 1,1473
///////////////////////////////////////////////////////////////////////////////
//
// Filename: cputest.c
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: To test the CPU, it's instructions, cache, and pipeline, to make
// certain that it works. This includes testing that each of the
// instructions works, as well as any strange instruction combinations.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// 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
// 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 MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////////
//
//
#include "../zlib/zipcpu.h"
#include "board.h"
 
#ifndef NULL
#define NULL (void *)0
#endif
 
#define PIC SYSPIC
#define TIMER SYSTIMER
 
#define HAVE_SCOPE
#define SCOPEc _scope->s_ctrl
#define SCOPE_DELAY 4
#define TRIGGER_SCOPE_NOW (WBSCOPE_TRIGGER|SCOPE_DELAY)
#define PREPARE_SCOPE SCOPE_DELAY
 
unsigned zip_ucc(void);
unsigned zip_cc(void);
void zip_save_context(int *);
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"
"\t.global\t_start\n"
"\t.type\t_start,@function\n"
"_start:\n"
"\tCLR\tR0\n"
"\tCLR\tR1\n"
"\tCLR\tR2\n"
"\tCLR\tR3\n"
"\tCLR\tR4\n"
"\tCLR\tR5\n"
"\tCLR\tR6\n"
"\tCLR\tR7\n"
"\tCLR\tR8\n"
"\tCLR\tR9\n"
"\tCLR\tR10\n"
"\tCLR\tR11\n"
"\tCLR\tR12\n"
"\tLDI\t_top_of_stack,SP\n"
"\tCLR\tCC\n"
"\tMOV\tbusy_failure(PC),R0\n"
"\tBRA\tentry\n"
"busy_failure:\n"
"\tBUSY\n"
"\t.section\t.text");
 
#ifdef COUNTER
#define MARKSTART start_time = COUNTER
#define MARKSTOP stop_time = COUNTER
#else
#ifdef TIMER
#define MARKSTART start_time = TIMER
#define MARKSTOP stop_time = TIMER
#else
#define MARKSTART
#define MARKSTOP
#endif
#endif
 
 
extern int run_test(void *pc, void *stack);
asm("\t.text\n\t.global\trun_test\n"
"\t.type\trun_test,@function\n"
"run_test:\n"
"\tCLR\tR3\n"
"\tMOV\ttest_return(PC),uR0\n"
"\tMOV\tR3,uR1\n"
"\tMOV\tR3,uR2\n"
"\tMOV\tR3,uR3\n"
"\tMOV\tR3,uR4\n"
"\tMOV\tR3,uR5\n"
"\tMOV\tR3,uR6\n"
"\tMOV\tR3,uR7\n"
"\tMOV\tR3,uR8\n"
"\tMOV\tR3,uR9\n"
"\tMOV\tR3,uR10\n"
"\tMOV\tR3,uR11\n"
"\tMOV\tR3,uR12\n"
"\tMOV\tR2,uSP\n" // uSP = stack
"\tMOV\t0x20+R3,uCC\n" // Clear uCC of all but the GIE bit
"\tMOV\tR1,uPC\n" // uPC = pc
"\tRTU\n"
"test_return:\n"
"\tMOV\tuR1,R1\n"
"\tAND\t0xffffffdf,CC\n"
// Works with 5 NOOPS, works with 3 NOOPS, works with 1 NOOP
"\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);
asm("\t.text\n\t.global\tbreak_one\n"
"\t.type\tbreak_one,@function\n"
"break_one:\n"
"\tLDI\t0,R1\n"
"\tBREAK\n"
"\tLDI\t1,R1\n" // Test fails
"\tJMP\tR0");
 
void break_two(void);
// Can we stop a break before we hit it?
asm("\t.text\n\t.global\tbreak_two\n"
"\t.type\tbreak_two,@function\n"
"break_two:\n"
"\tLDI\t0,R1\n"
"\tJMP\tR0\n"
"\tBREAK\n");
 
void break_three(void);
// Can we jump to a break, and still have the uPC match
asm("\t.text\n\t.global\tbreak_three\n"
"\t.type\tbreak_three,@function\n"
// R1 = 0 by default from calling. This will return as though
// we had succeeded.
"break_three:\n"
"\tBREAK\n");
 
void early_branch_test(void);
asm("\t.text\n\t.global\tearly_branch_test\n"
"\t.type\tearly_branch_test,@function\n"
"early_branch_test:\n"
"\tLDI\t1,R1\n"
"\tBRA\t_eb_a\n"
"\tBREAK\n"
"_eb_a:\n"
"\tLDI\t2,R1\n"
"\tBRA\t_eb_b\n"
"\tNOP\n"
"\tBREAK\n"
"_eb_b:\n"
"\tLDI\t3,R1\n"
"\tBRA\t_eb_c\n"
"\tNOP\n"
"\tNOP\n"
"\tBREAK\n"
"_eb_c:\n"
"\tLDI\t4,R1\n"
"\tBRA\t_eb_d\n"
"\tNOP\n"
"\tNOP\n"
"\tNOP\n"
"\tBREAK\n"
"_eb_d:\n"
"\tLDI\t5,R1\n"
"\tBRA\t_eb_e\n"
"\tNOP\n"
"\tNOP\n"
"\tNOP\n"
"\tNOP\n"
"\tBREAK\n"
"_eb_e:\n"
"\tLDI\t6,R1\n"
"\tBRA\t_eb_f\n"
"\tNOP\n"
"\tNOP\n"
"\tNOP\n"
"\tNOP\n"
"\tNOP\n"
"\tBREAK\n"
"_eb_f:\n"
"\tLDI\t0,R1\n"
"\tJMP\tR0");
 
void trap_test_and(void);
asm("\t.text\n\t.global\ttrap_test_and\n"
"\t.type\ttrap_test_and,@function\n"
"trap_test_and:\n"
"\tLDI\t0,R1\n"
"\tAND\t0xffffffdf,CC\n"
"\tLDI\t1,R1\n" // Test fails
"\tJMP\tR0");
 
void trap_test_clr(void);
asm("\t.text\n\t.global\ttrap_test_clr\n"
"\t.type\ttrap_test_clr,@function\n"
"trap_test_clr:\n"
"\tLDI\t0,R1\n"
"\tCLR\tCC\n"
"\tLDI\t1,R1\n" // Test fails
"\tJMP\tR0");
 
void overflow_test(void);
asm("\t.text\n\t.global\toverflow_test\n"
"\t.type\toverflow_test,@function\n"
"overflow_test:\n"
"\tLDI\t0,R1\n"
"\tLDI\t0,R3\n" // Clear our scorecard
// First test: does adding one to the maximum integer cause an overflow?
"\tLDI\t-1,R2\n"
"\tLSR\t1,R2\n"
"\tADD\t1,R2\n"
"\tOR.V\t1,R3\n"
// Second test: does subtracting one to the minimum integer cause an overflow?
"\tLDI\t0x80000000,R2\n"
"\tSUB\t1,R2\n"
"\tOR.V\t2,R3\n"
// Third test, overflow from LSR
"\tLDI\t0x80000000,R2\n"
"\tLSR\t1,R2\n" // Overflows 'cause the sign changes
"\tOR.V\t4,R3\n"
// Fourth test, overflow from LSL
"\tLDI\t0x40000000,R2\n"
"\tLSL\t1,R2\n"
"\tOR.V\t8,R3\n"
// Fifth test, overflow from LSL, negative to positive
"\tLDI\t0x80000000,R2\n"
"\tLSL\t1,R2\n"
"\tOR.V\t16,R3\n"
// Record our scores
"\tXOR\t31,R3\n"
"\tOR\tR3,R1\n"
// And return the results
"\tJMP\tR0");
 
 
void carry_test(void);
asm("\t.text\n\t.global\tcarry_test\n"
"\t.type\tcarry_test,@function\n"
"carry_test:\n"
"\tLDI\t0,R1\n"
"\tLDI\t0,R3\n"
// First, in adding
"\tLDI\t-1,R2\n"
"\tADD\t1,R2\n"
"\tOR.C\t1,R3\n"
// Then, in subtraction
"\tSUB\t1,R2\n"
"\tOR.C\t2,R3\n"
// From a right shift
"\tLDI\t1,R2\n"
"\tLSR\t1,R2\n"
"\tOR.C\t4,R3\n"
"\tLDI\t1,R2\n"
"\tASR\t1,R2\n"
"\tOR.C\t8,R3\n"
// Or from a compare
"\tLDI\t0,R2\n"
"\tCMP\t1,R2\n"
"\tOR.C\t16,R3\n"
// Set our return and clean up
"\tXOR\t31,R3\n"
"\tOR\tR3,R1\n"
"\tJMP\tR0");
 
void loop_test(void);
asm("\t.text\n\t.global\tloop_test\n"
"\t.type\tloop_test,@function\n"
"loop_test:\n"
"\tLDI\t0,R1\n"
// Let's try a loop: for(i=0; i<5; i++)
"\tLDI\t0,R2\n"
"\tLDI\t0,R3\n"
"\tCMP\t5,R2\n"
"\tBGE\tend_for_loop_test\n"
"for_loop_test:"
"\tADD\t1,R2\n"
"\tADD\t1,R3\n"
"\tCMP\t5,R2\n"
"\tBLT\tfor_loop_test\n"
"end_for_loop_test:"
"\tCMP\t5,R3\n"
"\tOR.NZ\t1,R1\n"
// How about a reverse do{} while loop? These are usually cheaper than for()
// loops.
"\tLDI\t0,R2\n"
// What if we use >=?
"\tLDI\t5,R3\n"
"bge_loop_test:\n"
"\tADD\t1,R2\n"
"\tSUB\t1,R3\n"
"\tBGE\tbge_loop_test\n"
"\tCMP\t6,R2\n"
"\tOR.NZ\t4,R1\n"
// Once more with the reverse loop, this time storing the loop variable in
// memory
"\tSUB\t4,SP\n"
"\tLDI\t0,R2\n"
"\tLDI\t4,R3\n"
"\tSW\tR3,(SP)\n"
"mem_loop_test:\n"
"\tADD\t1,R2\n" // Keep track of the number of times loop is executed
"\tADD\t14,R3\n"
"\tLW\t(SP),R3\n"
"\tSUB\t1,R3\n"
"\tSW\tR3,(SP)\n"
"\tBGE\tmem_loop_test\n"
"\tCMP\t5,R2\n"
"\tOR.NZ\t8,R1\n"
"\tADD\t4,SP\n"
//
"\tJMP\tR0\n");
 
// Test whether or not LSL, LSR, and ASR instructions work, together with their
// carry flags
void shift_test(void);
asm("\t.text\n\t.global\tshift_test\n"
"\t.type\tshift_test,@function\n"
"shift_test:\n"
"\tLDI\t0,R1\n" // Bit-field of tests that have failed
"\tLDI\t0,R3\n" // Bit-field of tests that have worked
"\tLDI\t0,R4\n" // Upper 16-bits of the same bit field
"\tLDI\t0,R5\n" // Upper 16-bits of tests that have failed
// Does shifting right by 32 result in a zero?
"\tLDI\t-1,R2\n"
"\tLSR\t32,R2\n"
"\tOR.Z\t1,R3\n"
"\tOR.C\t2,R3\n"
"\tCMP\t0,R2\n"
"\tOR.Z\t4,R3\n"
// Does shifting a -1 right arithmetically by 32 result in a -1?
"\tLDI\t-1,R2\n"
"\tASR\t32,R2\n"
"\tOR.LT\t8,R3\n"
"\tOR.C\t16,R3\n"
"\tCMP\t-1,R2\n"
"\tOR.Z\t32,R3\n"
// Does shifting a -4 right arithmetically by 2 result in a -1?
"\tLDI\t-4,R2\n"
"\tASR\t2,R2\n"
"\tOR.LT\t64,R3\n"
"\tOR.C\t128,R1\n"
"\tOR\t128,R3\n" // Artificially declare passing, so as not to fail it
"\tCMP\t-1,R2\n"
"\tOR.Z\t256,R3\n"
// Does one more set the carry flag as desired?
"\tASR\t1,R2\n"
"\tOR.LT\t512,R3\n"
"\tOR.C\t1024,R3\n"
"\tCMP\t-1,R2\n"
"\tOR.Z\t2048,R3\n"
// Does shifting -1 left by 32 result in a zero?
"\tLDI\t-1,R2\n"
"\tLSL\t32,R2\n"
"\tOR.Z\t4096,R3\n"
"\tOR.C\t8192,R3\n"
"\tCMP\t0,R2\n"
"\tOR.Z\t16384,R3\n"
// How about shifting by zero?
"\tLDI\t-1,R2\n"
"\tASR\t0,R2\n"
"\tOR.C\t32768,R1\n"
"\tOR\t32768,R3\n"
"\tCMP\t-1,R2\n"
"\tOR.Z\t1,R4\n"
//
"\tLSR\t0,R2\n"
"\tLDI\t131072,R5\n"
"\tOR.C\tR5,R1\n"
"\tCMP\t-1,R2\n"
"\tOR.Z\t2,R4\n"
//
"\tLSL\t0,R2\n"
"\tLDI\t524288,R5\n"
"\tOR.C\tR5,R1\n"
"\tCMP\t-1,R2\n"
"\tOR.Z\t4,R4\n"
// Tally up our results and return
"\tXOR\t7,R4\n"
"\tXOR\t65535,R3\n"
"\tLSL\t16,R4\n"
"\tOR\tR4,R3\n"
"\tOR\tR3,R1\n"
"\tJMP\tR0");
 
int sw_brev(int v);
asm("\t.text\n\t.global\tsw_brev\n"
"\t.type\tsw_brev,@function\n"
"sw_brev:\n"
"\tSUB\t8,SP\n"
"\tSW\tR2,(SP)\n"
"\tSW\tR3,4(SP)\n"
"\tLDI\t-1,R2\n"
"\tCLR\tR3\n"
"sw_brev_loop:\n"
"\tLSL\t1,R3\n"
"\tLSR\t1,R1\n"
"\tOR.C\t1,R3\n"
"\tLSR\t1,R2\n"
"\tBZ\tsw_brev_endloop\n"
"\tBRA\tsw_brev_loop\n"
"sw_brev_endloop:\n"
"\tMOV\tR3,R1\n"
"\tLW\t(SP),R2\n"
"\tLW\t4(SP),R3\n"
"\tADD\t8,SP\n"
"\tJMP\tR0");
 
void pipeline_stack_test(void);
asm("\t.text\n\t.global\tpipeline_stack_test\n"
"\t.type\tpipeline_stack_test,@function\n"
"pipeline_stack_test:\n"
"\tSUB\t4,SP\n"
"\tSW\tR0,(SP)\n"
"\tLDI\t0,R0\n"
"\tMOV\t1(R0),R1\n"
"\tMOV\t1(R1),R2\n"
"\tMOV\t1(R2),R3\n"
"\tMOV\t1(R3),R4\n"
"\tMOV\t1(R4),R5\n"
"\tMOV\t1(R5),R6\n"
"\tMOV\t1(R6),R7\n"
"\tMOV\t1(R7),R8\n"
"\tMOV\t1(R8),R9\n"
"\tMOV\t1(R9),R10\n"
"\tMOV\t1(R10),R11\n"
"\tMOV\t1(R11),R12\n"
"\tMOV\tpipeline_stack_test_component_return(PC),R0\n"
// "\tLJMP\tpipeline_stack_test_component\n"
"\tBRA\tpipeline_stack_test_component\n"
"pipeline_stack_test_component_return:\n"
"\tCMP\t1,R1\n"
"\tLDI.Z\t0,R1\n"
"\tCMP\t2,R2\n"
"\tCMP.Z\t3,R3\n"
"\tCMP.Z\t4,R4\n"
"\tCMP.Z\t5,R5\n"
"\tCMP.Z\t6,R6\n"
"\tCMP.Z\t7,R7\n"
"\tCMP.Z\t8,R8\n"
"\tCMP.Z\t9,R9\n"
"\tCMP.Z\t10,R10\n"
"\tCMP.Z\t11,R11\n"
"\tCMP.Z\t12,R12\n"
"\tBREV.NZ\t-1,R1\n"
"\tLW\t(SP),R0\n"
"\tADD\t4,SP\n"
"\tJMP\tR0\n"
);
 
void pipeline_stack_test_component(void);
asm("\t.text\n\t.global\tpipeline_stack_test_component\n"
"\t.type\tpipeline_stack_test_component,@function\n"
"pipeline_stack_test_component:\n"
"\tSUB\t52,SP\n"
"\tSW\tR0,(SP)\n"
"\tSW\tR1,4(SP)\n"
"\tSW\tR2,8(SP)\n"
"\tSW\tR3,12(SP)\n"
"\tSW\tR4,16(SP)\n"
"\tSW\tR5,20(SP)\n"
"\tSW\tR6,24(SP)\n"
"\tSW\tR7,28(SP)\n"
"\tSW\tR8,32(SP)\n"
"\tSW\tR9,36(SP)\n"
"\tSW\tR10,40(SP)\n"
"\tSW\tR11,44(SP)\n"
"\tSW\tR12,48(SP)\n"
"\tXOR\t-1,R0\n"
"\tXOR\t-1,R1\n"
"\tXOR\t-1,R2\n"
"\tXOR\t-1,R3\n"
"\tXOR\t-1,R4\n"
"\tXOR\t-1,R5\n"
"\tXOR\t-1,R6\n"
"\tXOR\t-1,R7\n"
"\tXOR\t-1,R8\n"
"\tXOR\t-1,R9\n"
"\tXOR\t-1,R10\n"
"\tXOR\t-1,R11\n"
"\tXOR\t-1,R12\n"
"\tLW\t(SP),R0\n"
"\tLW\t4(SP),R1\n"
"\tLW\t8(SP),R2\n"
"\tLW\t12(SP),R3\n"
"\tLW\t16(SP),R4\n"
"\tLW\t20(SP),R5\n"
"\tLW\t24(SP),R6\n"
"\tLW\t28(SP),R7\n"
"\tLW\t32(SP),R8\n"
"\tLW\t36(SP),R9\n"
"\tLW\t40(SP),R10\n"
"\tLW\t44(SP),R11\n"
"\tLW\t48(SP),R12\n"
"\tADD\t52,SP\n"
"\tJMP\tR0\n");
 
//mpy_test
void mpy_test(void);
asm("\t.text\n\t.global\tmpy_test\n"
"\t.type\tmpy_test,@function\n"
"mpy_test:\n"
"\tCLR\tR1\n"
// First test: let's count multiples of 137
"\tLDI\t137,R2\n" // What we're doing multiples of
"\tCLR\tR3\n" // Our accumulator via addition
"\tCLR\tR4\n" // Our index for multiplication
"mpy_137_test_loop:\n"
"\tMOV\tR2,R5\n"
"\tMPY\tR4,R5\n"
"\tCMP\tR3,R5\n"
"\tBNZ\tend_mpy_137_test_loop_failed\n"
// Let's try negative while we are at it
"\tMOV\tR2,R6\n"
"\tNEG\tR6\n"
"\tMPY\tR4,R6\n"
"\tNEG\tR6\n"
"\tCMP\tR3,R6\n"
"\tBNZ\tend_mpy_137_test_loop_failed\n"
"\tCLR\tR6\n"
"\tTEST\t0xffff0000,R3\n"
"\tBNZ\tend_mpy_137_test_loop\n"
"\tADD\tR2,R3\n"
"\tADD\t1,R4\n"
"\tBRA\tmpy_137_test_loop\n"
"end_mpy_137_test_loop_failed:\n"
"\tOR\t1,R1\n"
"end_mpy_137_test_loop:\n"
// Second test ... whatever that might be
"\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"
"\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.
SCOPEc = 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;
unsigned rhi, rlhi, rllo;
 
alo = (a & 0x0ffff);
ahi = (a>>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;
}
 
int div_test(void);
asm("\t.text\n\t.global\tdiv_test\n"
"\t.type\tdiv_test,@function\n"
"div_test:\n"
"\tLDI\t0x4881a7,R4\n"
"\tLDI\t0x2d5108b,R2\n"
"\tLDI\t10,R3\n"
"\tDIVU\tR3,R2\n"
"\tCMP\tR4,R2\n"
"\tLDILO.NZ\t1,R1\n"
"\tRETN.NZ\n"
"\tLDI\t0x2d5108b,R2\n"
"\tDIVU\t10,R2\n"
"\tCMP\tR4,R2\n"
"\tLDILO.NZ\t1,R1\n"
"\tRETN\n");
 
//brev_test
//pipeline_test -- used to be called pipeline memory race conditions
void pipeline_test(void);
asm("\t.text\n\t.global\tpipeline_test\n"
"\t.type\tpipeline_test,@function\n"
"pipeline_test:\n"
"\tSUB\t12,SP\n"
// Test setup
"\tLDI\t275,R2\n"
"\tSW\tR2,4(SP)\n"
"\tMOV\t4(SP),R2\n"
"\tSW\tR2,(SP)\n"
"\tCLR\tR2\n"
//
"\tMOV\tSP,R2\n"
"\tLW\t(R2),R2\n"
"\tLW\t(R2),R2\n"
"\tCMP\t275,R2\n"
"\tOR.NZ\t1,R1\n"
//
"\tMOV\tSP,R2\n"
// Here's the test sequence
"\tLW\t(R2),R3\n"
"\tLW\t4(R2),R4\n"
"\tSW\tR4,4(R3)\n"
// Make sure we clear the load pipeline
"\tLW\t(R2),R3\n"
// Load our written value
"\tLW\t8(R2),R4\n"
"\tCMP\t275,R4\n"
"\tOR.NZ\t2,R1\n"
//
//
// Next (once upon a time) failing sequence:
// LOD -x(R12),R0
// LOD y(R0),R0
"\tMOV\tSP,R2\n"
"\tMOV\t4(R2),R3\n"
"\tSW\tR3,4(R2)\n"
"\tLDI\t3588,R4\n" // Just some random value
"\tSW\tR4,8(R2)\n"
"\tMOV\tR2,R3\n"
// Here's the test sequence
"\tLW\t(R2),R3\n"
"\tLW\t4(R3),R3\n"
"\tCMP\tR4,R3\n"
"\tOR.NZ\t4,R1\n"
//
"\tADD\t12,SP\n"
"\tJMP\tR0\n");
 
//mempipe_test
void mempipe_test(void);
asm("\t.text\n\t.global\tmempipe_test\n"
"\t.type\tmempipe_test,@function\n"
"mempipe_test:\n"
"\tSUB\t16,SP\n"
"\tSW\tR0,(SP)\n"
"\tLDI\t0x1000,R11\n"
// Test #1 ... Let's start by writing a value to memory
"\tLDI\t-1,R2\n"
"\tCLR\tR3\n"
"\tSW\tR2,8(SP)\n"
"\tLW\t8(SP),R3\n"
"\tCMP\tR3,R2\n"
"\tOR.NZ\t1,R1\n"
// Test #2, reading and then writing a value from memory
"\tNOOP\n"
"\tNOOP\n"
"\tCLR\tR2\n"
"\tCLR\tR3\n"
"\tLW\t8(SP),R2\n" // This should load back up our -1 value
"\tSW\tR2,12(SP)\n"
// Insist that the pipeline clear
"\tLW\t8(SP),R2\n"
// Now let's try loading into R3
"\tNOOP\n"
"\tNOOP\n"
"\tNOOP\n"
"\tNOOP\n"
"\tLW\t12(SP),R3\n"
"\tCMP\tR3,R2\n"
"\tOR.NZ\t2,R1\n"
//
"\tLW\t(SP),R0\n"
"\tADD\t16,SP\n"
"\tJMP\tR0\n");
 
//cexec_test
void cexec_test(void);
asm("\t.text\n\t.global\tcexec_test\n"
"\t.type\tcexec_test,@function\n"
"cexec_test:\n"
"\tSUB\t4,SP\n"
"\tSW\tR0,(SP)\n"
//
"\tXOR\tR2,R2\n"
"\tADD.Z\t1,R2\n"
"\tADD.NZ\t1,R1\n"
"\tCMP.Z\t0,R2\n"
"\tOR.Z\t2,R1\n"
//
"\tLW\t(SP),R0\n"
"\tADD\t4,SP\n"
"\tJMP\tR0\n");
 
// 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
// 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
// whether this bypass logic works.
//
//nowaitpipe_test
void nowaitpipe_test(void);
asm("\t.text\n\t.global\tnowaitpipe_test\n"
"\t.type\tnowaitpipe_test,@function\n"
"nowaitpipe_test:\n"
"\tSUB\t8,SP\n"
//
// Let's start with ALU-ALU testing
// AA: result->input A
"\tLDI\t-1,R2\n"
"\tCLR\tR2\n"
"\tADD\t1,R2\n"
"\tCMP\t1,R2\n"
"\tOR.NZ\t1,R1\n"
//
// AA: result -> input B
"\tCLR\tR2\n"
"\tCLR\tR3\n"
"\tADD\t1,R2\n"
"\tCMP\tR2,R3\n"
"\tOR.Z\t2,R1\n"
// AA: result -> input A on condition
"\tXOR\tR2,R2\n"
"\tADD.Z\t5,R2\n"
"\tCMP\t5,R2\n"
"\tOR.NZ\t4,R1\n"
// AA: result -> input B on condition
"\tCLR\tR2\n"
"\tXOR\tR3,R3\n"
"\tADD.Z\t5,R2\n"
"\tCMP\tR2,R3\n"
"\tOR.Z\t8,R1\n"
// AA: result->input B plus offset
"\tCLR\tR2\n"
"\tXOR\tR3,R3\n"
"\tADD\t5,R2\n"
"\tCMP\t-5(R2),R3\n"
"\tOR.NZ\t16,R1\n"
// AA: result->input B plus offset on condition
"\tCLR\tR2\n"
"\tXOR\tR3,R3\n"
"\tADD.Z\t5,R2\n"
"\tCMP\t-5(R2),R3\n"
"\tOR.NZ\t32,R1\n"
//
// Then we need to do the ALU-MEM input testing
//
"\tCLR\tR2\n"
"\tSW\tR2,4(SP)\n"
"\tLDI\t8352,R2\n"
"\tLW\t4(SP),R2\n"
"\tTST\t-1,R2\n"
"\tOR.NZ\t64,R1\n"
// Let's try again, this time with something that's not zero
"\tLDI\t937,R2\n"
"\tSW\tR2,4(SP)\n"
"\tNOOP\n"
"\tLW\t4(SP),R2\n"
"\tCMP\t938,R2\n"
"\tOR.GE\t128,R1\n"
"\tCMP\t936,R2\n"
"\tOR.LT\t256,R1\n"
// Mem output->ALU input testing
// Okay, we just did that as part of our last test
// Mem output->mem input testing
"\tLDI\t5328,R2\n"
"\tLW\t4(SP),R2\n"
"\tSW\tR2,4(SP)\n"
"\tLW\t4(SP),R3\n"
"\tCMP\t937,R3\n"
"\tOR.NZ\t512,R1\n"
//
"\tADD\t8,SP\n"
"\tJMP\tR0\n");
 
//bcmem_test
void bcmem_test(void);
asm("\t.text\n\t.global\tbcmem_test\n"
"\t.type\tbcmem_test,@function\n"
"bcmem_test:\n"
"\tSUB\t4,SP\n"
"\tCLR\tR1\n"
"\tCLR\tR2\n"
"\tLDI\t-1,R3\n"
"\tLDI\t0x13000,R4\n"
"\tSW\tR2,(SP)\n"
"\tLW\t(SP),R3\n"
"\tCMP\tR2,R3\n"
"\tOR.NZ\t1,R1\n"
"\tCMP\t0x13000,R4\n"
"\tBZ\tbcmem_test_cmploc_1\n"
"\tSW\tR4,(SP)\n"
"bcmem_test_cmploc_1:\n"
"\tLW\t(SP),R2\n"
"\tCMP\tR2,R4\n"
"\tOR.Z\t2,R1\n"
"\tCLR\tR2\n"
"\tCMP\tR2,R4\n"
"\tBZ\tbcmem_test_cmploc_2\n"
"\tSW.NZ\tR4,(SP)\n"
"bcmem_test_cmploc_2:\n"
"\tLW\t(SP),R2\n"
"\tCMP\tR2,R4\n"
"\tOR.NZ\t4,R1\n"
//
"\tADD\t4,SP\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\t.global\till_test\n"
"\t.type\till_test,@function\n"
"ill_test:\n" // 0.111_1.110_11......
"\t.int\t0x7ec00000\n"
"\tJMP\tR0\n");
 
// Are sim instructions considered valid? Just hit the illegal instruction
// so we can report the result
void sim_test(void);
asm("\t.text\n\t.global\tsim_test\n"
"\t.type\tsim_test,@function\n"
"sim_test:\n" // 0.111_1.111_10......
"\t.int\t0x7f800000\n"
"\tJMP\tR0\n");
 
// Are CIS instructions considered valid? Try two compare instructions to
// see if they are built into our CPU.
void cis_test(void);
asm("\t.text\n\t.global\tcis_test\n"
"\t.type\tcis_test,@function\n"
"cis_test:\n" // 1.000_0.011._1.101_0.000 ... 1.000_1.011._1.110_0.000
"\t.int\t0x83d08be0\n"
"\tJMP\tR0\n");
 
void cmpeq_test(void);
asm("\t.text\n\t.global\tcmpeq_test\n"
"\t.type\tcmpeq_test,@function\n"
"cmpeq_test:\n"
"\tCMP\tR1,R2\n"
"\tCMP.Z\tR3,R4\n"
"\tLDILO.NZ\t1,R1\n"
"\tJMP\tR0\n");
 
void cmpneq_test(void);
asm("\t.text\n\t.global\tcmpneq_test\n"
"\t.type\tcmpneq_test,@function\n"
"cmpneq_test:\n"
"\tLDI\t1,R4\n"
"\tCMP\tR1,R2\n"
"\tCMP.Z\tR3,R4\n"
"\tLDILO.Z\t1,R0\n"
"\tJMP\tR0\n");
//
// The CC register has some ... unique requirements associated with it.
// Particularly, flags are unavailable until after an ALU operation completes,
// 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
// 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
// and even have effects--like sending the CPU to supervisor mode or
// alternatively to sleep.
//
// Here, let's see if our pipeline can successfully navigate any of these
// issues.
//
void ccreg_test(void);
asm("\t.text\n\t.global\tccreg_test\n"
"\t.type\tccreg_test,@function\n"
"ccreg_test:\n"
// First test: If we try to change the fixed bits, will they change
// because the pipeline tries to bypass the write-back stage
"\tCLR\tR1\n" // We'll start with an "answer" of success
"\tMOV\tCC,R2\n"
"\tMOV\tR2,R4\n" // Keep a copy
"\tBREV\t0x0ff,R3\n" // Attempt to change the top fixed bits
"\tXOR\tR3,R2\n" // Arrange for the changes
"\tMOV\tR2,CC\n" // Set the changes (they won't take)
"\tMOV\tCC,R5\n" // See if the pipeline makes them take
"\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
//
// Test #2: Can we set the flags?
"\tMOV\tCC,R6\n"
"\tOR\t15,R6\n"
"\tMOV\tR6,CC\n"
"\tMOV\tCC,R7\n"
"\tAND\t15,R7\n"
"\tCMP\t15,R7\n"
"\tOR.NZ\t2,R1\n"
//
// Test #3: How about setting specific flags, and immediately acting
// on them?
"\tXOR\t1+R8,R8\n" // Turn off the Z bit
"\tOR\t1,CC\n" // Turn on the Z bit
"\tOR.NZ\t4,R1\n"
//
// Test #4: Can we load the CC plus a value into a register?
// I don't think so ...
"\tJMP\tR0\n");
 
// Multiple argument test
__attribute__((noinline))
int multiarg_subroutine(int a, int b, int c, int d, int e, int f, int g) {
if (a!=0) return 1;
if (b!=1) return 2;
if (c!=2) return 4;
if (d!=3) return 8;
if (e!=4) return 16;
if (f!=5) return 32;
if (g!=6) return 64;
return 0;
}
 
int multiarg_test(void) {
return multiarg_subroutine(0,1,2,3,4,5,6);
}
 
__attribute__((noinline))
void wait(unsigned int msk) {
PIC = 0x7fff0000|msk;
asm("MOV\tidle_task(PC),uPC\n");
PIC = 0x80000000|(msk<<16);
asm("WAIT\n");
PIC = 0; // Turn interrupts back off, lest they confuse the test
}
 
asm("\n\t.text\nidle_task:\n\tWAIT\n\tBRA\tidle_task\n");
 
__attribute__((noinline))
void txchr(char v) {
if (zip_cc() & CC_GIE) {
if (PIC & INT_UARTTX)
PIC = INT_UARTTX;
while((PIC & INT_UARTTX)==0)
;
} else
wait(INT_UARTTX);
_uart = v;
}
 
void wait_for_uart_idle(void) {
PIC = INT_UARTTX;
while((PIC & INT_UARTTX)==0)
;
}
 
__attribute__((noinline))
void txstr(const char *str) {
const char *ptr = str;
while(*ptr)
txchr(*ptr++);
}
 
__attribute__((noinline))
void txhex(int num) {
for(int ds=28; 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 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) {
txstr(name); // 4 characters
txstr("0x"); // 2 characters
txhex(val); // 8 characters
txstr(" "); // 4 characters
}
 
__attribute__((noinline))
void save_context(int *context) {
zip_save_context(context);
}
 
__attribute__((noinline))
void test_fails(int start_time, int *listno) {
int context[16], stop_time;
 
// Trigger the scope, if it hasn't already triggered. Otherwise,
// if it has triggered, don't clear it.
#ifdef HAVE_SCOPE
SCOPEc = TRIGGER_SCOPE_NOW;
#endif
 
MARKSTOP;
save_context(context);
*listno++ = context[1];
*listno++ = context[14];
*listno++ = context[15];
#ifdef HAVE_COUNTER
*listno = stop_time;
#endif
 
txstr("FAIL!\r\n\r\n");
txstr("Between 0x"); txhex(start_time);
txstr(" and 0x"); txhex(stop_time); txstr("\r\n\r\n");
txstr("Core-dump:\r\n");
txreg("uR0 : ", context[0]);
txreg("uR1 : ", context[1]);
txreg("uR2 : ", context[2]);
txreg("uR3 : ", context[3]);
txstr("\r\n");
 
txreg("uR4 : ", context[4]);
txreg("uR5 : ", context[5]);
txreg("uR6 : ", context[6]);
txreg("uR7 : ", context[7]);
txstr("\r\n");
 
txreg("uR8 : ", context[8]);
txreg("uR9 : ", context[9]);
txreg("uR10: ", context[10]);
txreg("uR11: ", context[11]);
txstr("\r\n");
 
txreg("uR12: ", context[12]);
txreg("uSP : ", context[13]);
txreg("uCC : ", context[14]);
txreg("uPC : ", context[15]);
txstr("\r\n\r\n");
 
wait_for_uart_idle();
asm("NEXIT -1");
// 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) {
const int WIDTH=32;
txstr(str);
const char *ptr = str;
int i = 0;
while(0 != *ptr++)
i++;
i = WIDTH-i;
while(i-- > 0)
txchr(' ');
}
 
int testlist[32];
 
void entry(void) {
int context[16];
int user_stack[256], *user_stack_ptr = &user_stack[256];
int start_time, i;
int cc_fail, cis_insns = 0;
 
 
for(i=0; i<32; i++)
testlist[i] = -1;
 
#ifdef TIMER
TIMER = 0x7fffffff;
#endif
#ifdef COUNTER
COUNTER = 0;
#endif
#ifdef HAVE_SCOPE
SCOPEc = PREPARE_SCOPE;
#endif
 
// *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
//
 
txstr("\r\n");
txstr("Running CPU self-test\r\n");
txstr("-----------------------------------\r\n");
 
int tnum = 0;
 
// Check whether or not this CPU correctly identifies SIM instructions
// as illegal instructions
testid("SIM Instructions"); MARKSTART;
cc_fail = CC_MMUERR|CC_FPUERR|CC_DIVERR|CC_BUSERR|CC_TRAP|CC_STEP|CC_SLEEP;
if ((run_test(sim_test, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
else if (zip_ucc() & CC_ILL) {
txstr("Pass\r\n"); testlist[tnum++] = 0; // 0
} else
txstr("Is this a simulator?\r\n");
 
testid("CIS Instructions"); MARKSTART;
cc_fail = CC_MMUERR|CC_FPUERR|CC_DIVERR|CC_BUSERR|CC_STEP|CC_SLEEP;
if ((run_test(cis_test, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
else if (zip_ucc() & CC_ILL)
txstr("Not supported\r\n");
else {
txstr("Supported\r\n");
cis_insns = 1;
}
 
// Test break instruction in user mode
// Make sure the break works as designed
testid("Break test #1"); MARKSTART;
 
cc_fail = CC_MMUERR|CC_FPUERR|CC_DIVERR|CC_BUSERR|CC_TRAP|CC_ILL|CC_STEP|CC_SLEEP;
if ((run_test(break_one, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
save_context(context);
if ((context[15] != (int)break_one+4)||(0==(zip_ucc()&CC_BREAK)))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #1
 
 
// Test break instruction in user mode
// Make sure that a decision on the clock prior won't still cause a
// break condition
cc_fail = CC_MMUERR|CC_FPUERR|CC_DIVERR|CC_BUSERR|CC_ILL|CC_BREAK|CC_STEP|CC_SLEEP;
testid("Break test #2"); MARKSTART;
if ((run_test(break_two, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #2
 
// Test break instruction in user mode
// Make sure that a decision on the clock prior won't still cause a
// break condition
cc_fail = (CC_FAULT)|CC_MMUERR|CC_TRAP|CC_STEP|CC_SLEEP;
testid("Break test #3"); MARKSTART;
run_test(break_three, user_stack_ptr);
save_context(context);
if ((context[15] != (int)break_three) // Insist we stop at the break
||(0==(zip_ucc()&CC_BREAK))//insn,that the break flag is
||(zip_ucc()&cc_fail)) // set, and no other excpt flags
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #3
 
// LJMP test ... not (yet) written
 
// Test the early branching capability
// Does it successfully clear whatever else is in the pipeline?
testid("Early Branch test"); MARKSTART;
if ((run_test(early_branch_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #4
 
// TRAP test
testid("Trap test/AND"); MARKSTART;
if ((run_test(trap_test_and, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
if ((zip_ucc() & 0x0200)==0)
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #5
 
testid("Trap test/CLR"); MARKSTART;
if ((run_test(trap_test_clr, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
if ((zip_ucc() & 0x0200)==0)
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #6
 
// Overflow test
testid("Overflow test"); MARKSTART;
if ((run_test(overflow_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #7
 
// Carry test
testid("Carry test"); MARKSTART;
if ((run_test(carry_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #8
 
// LOOP_TEST
testid("Loop test"); MARKSTART;
if ((run_test(loop_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #9
 
// SHIFT_TEST
testid("Shift test"); MARKSTART;
if ((run_test(shift_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #10
 
// BREV_TEST
//testid("BREV/stack test"); MARKSTART;
//if ((run_test(brev_test, user_stack_ptr))||(zip_ucc()&0x01d90))
//test_fails(start_time); // #10
//txstr("Pass\r\n");
 
// PIPELINE_TEST
testid("Pipeline test"); MARKSTART;
if ((run_test(pipeline_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #11
 
// MEM_PIPELINE_STACK_TEST
testid("Mem-Pipeline test"); MARKSTART;
if ((run_test(mempipe_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #12
 
// CONDITIONAL EXECUTION test
testid("Conditional Execution test"); MARKSTART;
if ((run_test(cexec_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #13
 
// NOWAIT pipeline test
testid("No-waiting pipeline test"); MARKSTART;
if ((run_test(nowaitpipe_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #14
 
// BCMEM test
testid("Conditional Branching test"); MARKSTART;
if ((run_test(bcmem_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #15
 
// Illegal Instruction test
testid("Ill Instruction test, NULL PC"); MARKSTART;
if ((run_test(NULL, user_stack_ptr))||((zip_ucc()^CC_ILL)&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #16
 
// Illegal Instruction test
cc_fail = CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_BREAK|CC_MMUERR;
testid("Ill Instruction test, two"); MARKSTART;
if ((run_test(ill_test, user_stack_ptr))||(zip_ucc()&cc_fail))
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; // #17
 
// Compare EQuals test
cc_fail = CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_BREAK|CC_MMUERR|CC_ILL;
testid("Comparison test, =="); MARKSTART;
if ((run_test(cmpeq_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #18
 
// Compare !EQuals test
cc_fail = CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_BREAK|CC_MMUERR|CC_ILL;
testid("Comparison test, !="); MARKSTART;
if ((run_test(cmpneq_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #19
 
// Pipeline memory race condition test
// DIVIDE test
 
// CC Register test
testid("CC Register test"); MARKSTART;
if ((run_test(ccreg_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #20
 
// Multiple argument test
testid("Multi-Arg test"); MARKSTART;
if ((run_test(multiarg_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #21
 
// MPY_TEST
testid("Multiply test"); MARKSTART;
if ((run_test(mpy_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #22
 
// MPYxHI_TEST
testid("Multiply HI-word test"); MARKSTART;
if ((run_test(mpyhi_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #23
 
// DIV_TEST
testid("Divide test");
if ((zip_cc() & 0x20000000)==0) {
txstr("No divide unit installed\r\n");
} else { MARKSTART;
if ((run_test(div_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
} txstr("Pass\r\n"); testlist[tnum++] = 0; // #24
 
 
txstr("\r\n");
txstr("-----------------------------------\r\n");
txstr("All tests passed. Halting CPU.\r\n");
wait_for_uart_idle();
for(int k=0; k<50000; k++)
asm("NOOP");
asm("NEXIT 0");
zip_halt();
}
 
// To build this:
// 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
//
/sw/dev/doorbell.c
36,7 → 36,6
////////////////////////////////////////////////////////////////////////////////
//
//
#include "asmstartup.h"
#include "board.h"
 
#include "samples.c"
/sw/dev/doorbell2.c
50,7 → 50,6
////////////////////////////////////////////////////////////////////////////////
//
//
#include "asmstartup.h"
#include "board.h"
#include "rtcsim.h"
#include "display.h"
59,8 → 58,6
 
#include "samples.c"
 
void zip_halt(void);
 
void build_dpymsg(char *msg, unsigned clkval);
void build_uartmsg(char *msg, unsigned clkval);
void showval(int val);
/sw/dev/helloworld.c
46,7 → 46,6
////////////////////////////////////////////////////////////////////////////////
//
//
#include "asmstartup.h"
#include "board.h"
 
const char msg[] = "Hello, world!\r\n";
55,8 → 54,13
volatile IOSPACE *const sys = (IOSPACE *)IOADDR;
int ledset = 0;
 
sys->io_spio = 0x0f0;
sys->io_pic = 0x07fffffff; // Acknowledge and turn off all ints
 
// sys->io_watchdog = TM_ONE_SECOND * 2;
_scope->s_ctrl = 2 | WBSCOPE_NO_RESET;
 
sys->io_spio = 0x0fc;
 
/// Turn off timer B
sys->io_watchdog = 0;
 
64,6 → 68,7
const char *ptr;
sys->io_timer = TM_ONE_SECOND; // Ticks per second, 80M
sys->io_pic = 0x07fffffff; // Acknowledge and turn off all ints
sys->io_pic = INT_ENABLEV(INT_BUTTON);
 
ptr = msg;
while(*ptr) {
72,6 → 77,7
// Wait while our transmitter is busy
while((sys->io_pic & INT_UARTTX)==0)
;
 
sys->io_uart = iv; // Transmit our character
sys->io_pic = INT_UARTTX; // Clear the int flag
}
93,6 → 99,7
sys->io_spio = ledset&0x0f5;
else
sys->io_spio = ledset;
sys->io_watchdog = 0;
}
}
 
/sw/dev/kptest.c
35,7 → 35,6
////////////////////////////////////////////////////////////////////////////////
//
//
#include "asmstartup.h"
#include "board.h"
#include "keypad.h"
#include "txfns.h"
/sw/dev/resetdump.s
0,0 → 1,491
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;//
;;
;; Filename: resetdump.s
;;
;; Project: CMod S6 System on a Chip, ZipCPU demonstration project
;;
;; Purpose: While most of my ZipCPU programs to date have started with a
;; simple assembly script to load the stack and call the program
;; entry point, this is different. This is a very complicated startup
;; script designed to dump all of the internal information to the CPU
;; to a UART output port. This is on purpose. Indeed, this may be my
;; only means of debugging the device once it goes bad:
;;
;; - To set a breakpoint
;; at the location desired call kpanic(), the CPU will dump its
;; variables and wait for a button press to restart.
;; sometime before the desired clock, set the watchdog timer.
;; When the watchdog expires, the CPU will restart.
;; Adjusting the watchdog will adjust how long the CPU
;; waits before restarting, and may also adjust what
;; instructions you find going on
;;
;; - In hardware, you can also set the scope. On boot up, this resetdump
;; startup will dump the value of the scope to the UART.
;;
;; Of course, this all depends upon someone listening on the uart. That's
;; the purpose of the dumpuart.cpp program in the sw/host directory.
;; That file will capture the dump so it can be examined later.
;;
;; Creator: Dan Gisselquist, Ph.D.
;; Gisselquist Technology, LLC
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;//
;;
;; Copyright (C) 2015-2017, Gisselquist Technology, LLC
;;
;; 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
;; 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory, run make with no
;; target there if the PDF file isn't present.) If not, see
;; <http://www.gnu.org/licenses/> for a copy.
;;
;; License: GPL, v3, as defined and found on www.gnu.org,
;; http://www.gnu.org/licenses/gpl.html
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;//
;;
;;
.section .start
.global _start
.type _start,@function
_start:
; Upon reset, we must output our registers to the UART, lest we reset because
; of a crash
SW R0,(DBG)
LDI 0x00000002,R0
SW R0,(SCOPE)
JSR internal_kpanic
LDI _top_of_stack,SP
LDI gostr,R1
JSR raw_put_string
LDI 0x7fffffff,R1
SW R1,(PIC)
; ; Turn on the button interrupt--so we can stop on interrupt
; LDI 0x80010001,R1
; SW R1,(PIC)
;LDI 0xff000002,R1
;SW R1,(SCOPE)
; For running in supervisor mode:
; JSR entry
; otherwise ..
MOV entry(PC),uPC
MOV SP,uSP
RTU
JMP kpanic
 
.global kpanic
.type kpanic,@function
kpanic:
SW R0,(DBG)
SW R1,4(DBG)
SW R2,8(DBG)
LDI panicstr, R1
JSR raw_put_string
LW 4(DBG),R1
LW 8(DBG),R2
JSR internal_kpanic
kpanic_wait_for_button_release:
LW (SPIO),R0
TEST 0x010,R0
BNZ kpanic_wait_for_button_release
kpanic_wait_for_button:
LW (SPIO),R0
TEST 0x010,R0
BZ kpanic_wait_for_button
BRA _start
HALT
internal_kpanic:
; The original R0 is stored in (DBG)
SW R1,4(DBG)
SW R2,8(DBG)
SW R0,12(DBG) ; Our return address
 
; Make sure the watchdog is off
LDI 0,R1
SW R1,0x40c
 
; R0
LDI 0,R1
LW (DBG),R2
JSR uart_put_reg_value
 
; R1
LDI 1,R1
LW 4(DBG),R2
JSR uart_put_reg_value
; R2
LDI 2,R1
LW 8(DBG),R2
JSR uart_put_reg_value
; R3
LDI 3,R1
MOV R3,R2
JSR uart_put_reg_value
 
; R4
LDI 4,R1
MOV R4,R2
JSR uart_put_reg_value
 
; R5
LDI 5,R1
MOV R5,R2
JSR uart_put_reg_value
 
; R6
LDI 6,R1
MOV R6,R2
JSR uart_put_reg_value
 
; R7
LDI 7,R1
MOV R7,R2
JSR uart_put_reg_value
 
; R8
LDI 8,R1
MOV R8,R2
JSR uart_put_reg_value
 
; R9
LDI 9,R1
MOV R9,R2
JSR uart_put_reg_value
 
; R10
LDI 10,R1
MOV R10,R2
JSR uart_put_reg_value
 
; R11
LDI 11,R1
MOV R11,R2
JSR uart_put_reg_value
 
; R12
LDI 12,R1
MOV R12,R2
JSR uart_put_reg_value
 
; SP
LDI 13,R1
MOV R13,R2
JSR uart_put_reg_value
 
; uR0
LDI 16,R1
MOV uR0,R2
JSR uart_put_reg_value
 
; uR1
LDI 17,R1
MOV uR1,R2
JSR uart_put_reg_value
 
LDI 18,R1
MOV uR2,R2
JSR uart_put_reg_value
 
LDI 19,R1
MOV uR3,R2
JSR uart_put_reg_value
 
LDI 20,R1
MOV uR4,R2
JSR uart_put_reg_value
 
LDI 21,R1
MOV uR5,R2
JSR uart_put_reg_value
 
LDI 22,R1
MOV uR6,R2
JSR uart_put_reg_value
 
LDI 23,R1
MOV uR7,R2
JSR uart_put_reg_value
 
LDI 24,R1
MOV uR8,R2
JSR uart_put_reg_value
 
LDI 25,R1
MOV uR9,R2
JSR uart_put_reg_value
 
LDI 26,R1
MOV uR10,R2
JSR uart_put_reg_value
 
LDI 27,R1
MOV uR11,R2
JSR uart_put_reg_value
 
LDI 28,R1
MOV uR12,R2
JSR uart_put_reg_value
 
; uSP
LDI 29,R1
MOV uSP,R2
JSR uart_put_reg_value
 
; uCC
LDI 30,R1
MOV uCC,R2
JSR uart_put_reg_value
 
; uPC
LDI 31,R1
MOV uPC,R2
JSR uart_put_reg_value
 
;stack_mem_dump:
; LDI 0,R4
; LDI _top_of_stack,R5
;stack_mem_dump_loop:
; MOV R4,R1
; LW (R5),R2
; JSR uart_put_stack_value
; ADD 4,R4
; SUB 4,R5
; CMP 256,R4
; BLT stack_mem_dump_loop
 
; Get prepared for a proper start by setting our stack register
LDI _top_of_stack,SP
 
BRA dump_scope
; BRA end_internal_panic
 
; Now, do a full dump of all memory--all registers are available to us
dump_memory:
LDI RAM,R5
LDI 0x0fff,R6
LDI 0x0f8,R7
SW R7,(SPIO)
full_mem_dump_loop:
MOV R5,R1
LW (R5),R2
JSR uart_dump_mem_value
LDI 0x0f2,R7
SW R7,(SPIO)
 
ADD 4,R5
SUB 1,R6
BGE full_mem_dump_loop
 
LDI 0x0f5,R7
SW R7,(SPIO)
 
dump_scope:
; Finally, do a full dump of the scope--if it had triggered
; First, dump the scope control word
LDI SCOPE,R7 ; R7 = Debugging scope address
MOV R7,R1
LW (R7),R2
MOV R2,R5 ; R5 will not be changed by a subroutine
JSR uart_dump_mem_value
; Then test whether or not the scope has stopped
LDI 0x40000000,R1
TEST R1,R5
; If not, start our kernel.
BZ dump_buserr
; Otherwise, calculate the size of the scope
LSR 20,R5
AND 0x1f,R5
LDI 1,R6
LSL R5,R6 ; R6 is now the size (number of words) of the scope
SUB 1,R6 ; Now it is one less than the size,2 support the BGE l8r
; And start dumping
ADD 4,R7 ; Get the scope data address
dump_scope_loop:
MOV R7,R1
LW (R7),R2
JSR uart_dump_mem_value
SUB 1,R6
BGE dump_scope_loop
 
dump_buserr:
; Dump a bus error address, if used
LDI buserr_header, R1
JSR raw_put_string
LDI BUSERR,R1
LW (R1),R2
JSR uart_dump_mem_value
 
end_internal_panic:
LDI doublenewline,R1
JSR raw_put_string
LDI 0x0ff,R7
SW R7,(SPIO)
LW 12(DBG),PC
RTN
 
; R0 is return address
; R1 is register ID
; R2 is register value to output
uart_put_reg_value:
SW R0,16(DBG)
SW R2,20(DBG)
SW R3,24(DBG)
MOV R1,R2
LDI 'u',R1
CMP 16,R2
LDILO.LT 's',R1
SUB.GE 16,R2
JSR raw_put_uart
LDI '0',R1
CMP 10,R2
LDILO.GE '1',R1
SUB.GE 10,R2
JSR raw_put_uart
MOV R2,R1
AND 15,R1
JSR get_hex
JSR raw_put_uart
LDI ':',R1
JSR raw_put_uart
LW 20(DBG),R2
LDI 8,R3
uart_put_loop:
MOV R2,R1
LSR 28,R1
LSL 4,R2
JSR get_hex
JSR raw_put_uart
SUB 1,R3
BNZ uart_put_loop
LDI newline, R1
JSR raw_put_string
LW 16(DBG),R0
LW 20(DBG),R2
LW 24(DBG),R3
RTN
 
uart_dump_mem_value:
; R0 = return address
; R1 = Memory address
; R2 = Memory Value
; Local: R3 = working value
SW R0,28(DBG)
MOV R1,R3 ; R3 = Memory address
MOV R2,R4 ; R4 = Memory Value
LDI memopenstr,R1
JSR raw_put_string
; Set up a loop to dump things
LSL 16,R3 ; Ignore the first 16 bits
LDI 4,R2 ; We're going to do four hex digits here
;
uart_put_mem_address_loop:
MOV R3,R1
LSR 28,R1
LSL 4,R3
JSR get_hex
JSR raw_put_uart
SUB 1,R2
BNZ uart_put_mem_address_loop
; Put some transition characters
LDI memmidstr,R1
JSR raw_put_string
 
; Set up a loop to dump the memory value now
LDI 8,R2
uart_put_mem_value_loop:
MOV R4,R1
LSR 28,R1
LSL 4,R4
JSR get_hex
JSR raw_put_uart
SUB 1,R2
BNZ uart_put_mem_value_loop
; Clear the line
LDI newline,R1
JSR raw_put_string
; And return from our subroutine
LW 28(DBG),R0
RTN
 
get_hex:
ADD 0x30,R1
CMP 0x3a,R1
ADD.GE 7,R1 ; Add 'A'-'0'-10
JMP R0
 
; R0 is the return address
; R1 is the string address
raw_put_string:
SW R0,36(DBG)
SW R2,40(DBG)
MOV R1,R2
raw_put_string_next:
LB (R2),R1
CMP 0,R1
LW.Z 36(DBG),R0
LW.Z 40(DBG),R2
RTN.Z
ADD 1,R2
MOV raw_put_string_next(PC),R0
BRA raw_put_uart
; R0 is return address,
; R1 is value to transmit
raw_put_uart:
SW R2,32(DBG)
LDI INT_UARTTX,R2
SW R2,(PIC) ; Clear the PIC, turn off interrupts, etc.
raw_put_uart_retest:
LW (PIC),R2
TEST INT_UARTTX,R2
BZ raw_put_uart_retest
SW R1,(UART)
LW 32(DBG),R2
JMP R0
 
.section .fixdata
DBG:
.int 0,0,0,0,0,0,0,0,0,0
 
.set INT_UARTRX, 0x040
.set INT_UARTTX, 0x080
.set PIC, 0x0400
.set BUSERR, 0x0404
.set TMRA, 0x0408
.set TMRB, 0x040c
.set PWM, 0x0410
.set SPIO, 0x0414
.set GPIO, 0x0418
.set UART, 0x041c
.set VERSION, 0x0420
.set SCOPE, 0x0800
.set SCOPED, 0x0804
.set RAM, 0x8000
.section .rodata
doublenewline:
.ascii "\r\n"
newline:
.asciz "\r\n"
buserr_header:
.string "BusErr: "
panicstr:
.string "Panic: \r\n"
memopenstr:
.string "M[0x"
memmidstr:
.string "]: "
gostr:
.string "Go!\r\n"
 
/sw/dev/uartecho.c
0,0 → 1,58
////////////////////////////////////////////////////////////////////////////////
//
// Filename: uartecho.c
//
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
//
// Purpose: To simply test if both parts of the UART work. All this file
// does is attempt to receive a character from the UART, and if
// successful, print it back out the UART.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
//
// 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
// 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 MERCHANTIBILITY 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. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include "board.h"
 
void entry(void) {
SYSPIC = INT_CLEARPIC;
 
while(1) {
int ch;
 
SYSPIC = INT_UARTRX;
while((SYSPIC & INT_UARTRX)==0)
;
ch = _uart & 0x0ff;
 
SYSPIC = INT_UARTTX;
while((SYSPIC & INT_UARTTX)==0)
;
_uart = ch;
}
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.