OpenCores
URL https://opencores.org/ocsvn/zipcpu/zipcpu/trunk
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Filename: test.S ; ; Project: Zip CPU -- a small, lightweight, RISC CPU soft core ; ; Purpose: A disorganized test, just showing some initial operation of ; the CPU. As a disorganized test, it doesn't prove anything ; beyond the generic operation of the CPU. ; ; Status: As of August, 2015, this file assembles, builds, and passes ; all of its tests in the Verilator simulator. ; ; Okay, as of 15 August, there are now some tests that don't pass. ; In particular, the #include test used to pass but didn't pass today. ; Likewise the PUSH() macro test hasn't passed yet. Finally, be aware ; that this implementation is specific to where it loads on a board. ; I tried loading it on my Basys development board, where I had placed ; RAM in a different location and ... things didn't work out so well. ; So grep the __here__ line and adjust it for where you intend to load ; this file. ; ; In general, as I'm building the CPU, I'm modifying this file to place ; more and more capability tests within the file. If the Lord is ; willing, this will become the proof that the CPU completely works. ; ; ; Creator: Dan Gisselquist, Ph.D. ; Gisselquist Tecnology, LLC ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Copyright (C) 2015, 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 "sys.i" sys.bus equ 0xc0000000 sys.breaken equ 0x080 sys.step equ 0x040 sys.gie equ 0x020 sys.sleep equ 0x010 sys.ccv equ 0x008 sys.ccn equ 0x004 sys.ccc equ 0x002 sys.ccz equ 0x001 sys.cctrap equ 0x200 sys.bu.pic equ 0x000 sys.bus.wdt equ 0x001 sys.bus.cache equ 0x002 sys.bus.ctrpic equ 0x003 sys.bus.tma equ 0x004 sys.bus.tmb equ 0x005 sys.bus.tmc equ 0x006 sys.bus.jiffies equ 0x007 sys.bus.mtask equ 0x008 sys.bus.mpstl equ 0x009 sys.bus.mastl equ 0x00a sys.bus.mstl equ 0x00b sys.bus.utask equ 0x00c sys.bus.upstl equ 0x00d sys.bus.uastl equ 0x00e sys.bus.ustl equ 0x00f #define DO_TEST_ASSEMBLER #define BREAK_TEST #define OVERFLOW_TEST #define CARRY_TEST #define LOOP_TEST #define SHIFT_TEST #define TRAP_TEST #define MPY_TEST // #define PUSH_TEST test: #ifdef DO_TEST_ASSEMBLER ; We start out by testing our assembler. We give it some instructions, which ; are then manually checked by disassembling/dumping the result and making ; certain they match. This is not an automated test, but it is an important ; one. noop bra continue_test_with_testable_instructions break wait break busy rtu continue_test_with_testable_instructions: ; Now, let's place the assembler into a known state clr r0 clr r1 clr r2 clr r3 clr r4 clr r5 clr r6 clr r7 clr r9 clr r10 clr r11 clr r12 clr r13 ; Don't clear the CC register ; Don't clear the SP register ; And repeat for the user registers mov R0,uR0 mov R0,uR1 mov R0,uR2 mov R0,uR3 mov R0,uR4 mov R0,uR5 mov R0,uR6 mov R0,uR7 mov R0,uR8 mov R0,uR9 mov R0,uR10 mov R0,uR11 mov R0,uR12 mov R0,uR13 mov R0,uCC ; Don't clear the user PC register ; Now, let's try loading some constants into registers ; Specifically, we're testing the LDI, LDIHI, and LDILO instructions dead_beef equ 0xdeadbeef ldi 0x0dead,r5 ldi 0x0beef,r6 ldi 0xdeadbeef,r7 ldihi 0xdead, r8 ldilo 0xbeef, r8 ldi dead_beef,r9 cmp r5,r6 bz test_failure cmp r7,r8 bnz test_failure ldi $deadbeefh,r7 ; Try loading with the $[HEX]h mneumonic cmp r7,r8 bnz test_failure cmp r7,r9 bnz test_failure bra skip_dead_beef dead_beef.base: word 0 fill 5,dead_beef word 0 dead_beef.zero equ 0 dead_beef.values equ 1 skip_dead_beef: lod dead_beef.base(pc),r10 ; Should load a zero here cmp r10,r11 ; r11 should still be zero from init abv bnz test_failure mov dead_beef.base(pc),r10 ; Now, let's get the address lod dead_beef.values(r10),r10 ; r10 now equals 0xdeadbeef cmp r10,r9 bnz test_failure ; Test whether or not we can properly decode OCTAL values clr r0 ; Re-clear our register set first clr r1 clr r2 clr r3 clr r4 clr r5 clr r6 clr r7 clr r9 clr r10 clr r11 clr r12 clr r13 ; ldi $024o,r0 ldi $20,r1 cmp r0,r1 bnz test_failure ldi $024,r0 cmp r0,r1 bnz test_failure clr r0 clr r1 mov $1+r0,r2 mov $2+r0,r3 mov $22h+r0,r4 mov $377h+r0,ur5 noop nop add r2,r0 add $32,r0 add $-33,r0 bnz test_failure not.z r0 bge test_failure junk_address: clrf r0 bnz test_failure ldi $5,r1 cmp $0+r0,r1 not.lt r0 not.ge r1 mov junk_address(pc),r2 ; Test pc-relative addressing mov junk_address(pc),r3 cmp r2,r3 bnz test_failure lod junk_address(pc),r5 ; Test loads with pc-relative addressing lod junk_address(pc),r6 cmp r5,r6 bnz test_failure #endif #ifdef NOONE // Testing comments after ifdef #else ; After else #endif /* and after endif */ #ifdef BREAK_TEST breaktest: bra breaksupervisor breakuser: clr r0 mov 1+r0,r1 mov 1+r1,r2 mov 1+r2,r3 break ; At address 0x0100097 mov 1+r4,r5 mov 1+r5,r6 clr cc busy breaksupervisor: ldi -1,r0 mov breakuser(pc),upc rtu ; Should just keep returning immediately mov upc,r0 rtu rtu mov upc,r1 cmp r0,r1 bnz test_failure #endif #ifdef TRAP_TEST traptest: bra traptest_supervisor busy traptest_user: trap 0 busy traptest_supervisor: mov traptest_user(pc),upc rtu mov cc,r0 tst sys.cctrap,r0 bz test_failure #endif testbench: // Let's build a software test bench. ldi $c0000000h,r12 ; Set R12 to point to our peripheral address mov r12,ur12 mov test_start(pc),upc ldi 0x8000ffff,r0 ; Clear interrupts, turn all vectors off sto r0,(r12) rtu mov ucc,r0 cmp sys.cctrap,r0 bnz test_failure halt // Go into an infinite loop if the trap fails // Permanent loop instruction -- a busy halt if you will test_failure: busy ; Now for a series of tests. If the test fails, call the trap ; interrupt with the test number that failed. Upon completion, ; call the trap with #0. ; Test LDI to PC ; Some data registers test_data: .dat __here__+0x0100000+5 test_start: ldi $0x01000,r11 lod test_data+pc,pc clr r11 noop cmp $0,r11 trap.z r11 add $1,r0 add $1,r0 #ifdef OVERFLOW_TEST // Let's test whether overflow works ldi $0x02000,r11 ldi $-1,r0 lsr $1,r0 add $1,r0 bv first_overflow_passes trap r11 first_overflow_passes: // Overflow set from subtraction ldi $0x03000,r11 ldi $1,r0 rol $31,r0 ; rol $31,r0 sub $1,r0 bv subtraction_overflow_passes trap r11 subtraction_overflow_passes: // Overflow set from LSR ldi $0x04000,r11 ldi $1,r0 rol $31,r0 ; rol $31,r0 lsr $1,r0 bv lsr_overflow_passes trap r11 lsr_overflow_passes: // Overflow set from LSL ldi $0x05000,r11 ldi $1,r0 rol $30,r0 lsl $1,r0 bv lsl_overflow_passes trap r11 lsl_overflow_passes: // Overflow set from LSL, negative to positive ldi $0x06000,r11 ldi $1,r0 rol $31,r0 lsl $1,r0 bv second_lsl_overflow_passes trap r11 #endif // OVERFLOW_TEST #ifdef CARRY_TEST second_lsl_overflow_passes: // Test carry ldi $0x07000,r11 ldi $-1,r0 add $1,r0 tst $2,cc trap.z r11 // and carry from subtraction ldi $0x08000,r11 clr r0 sub $1,r0 tst $2,cc trap.z r11 #endif #ifdef LOOP_TEST // Let's try a loop: for i=0; i<5; i++) // We'll use R0=i, Immediates for 5 ldi $0x09000,r11 clr r0 for_loop: noop add $1,r0 cmp $5,r0 blt for_loop // // Let's try a reverse loop. Such loops are usually cheaper to // implement, and this one is no different: 2 loop instructions // (minus setup instructions) vs 3 from before. // R0 = 5; (from before) // do { // } while (R0 > 0); ldi $0x0a000,r11 bgt_loop: noop sub $1,r0 bgt bgt_loop // How about the same thing with a >= comparison? // R1 = 5; // Need to do this explicitly // do { // } while(R1 >= 0); ldi $20,r0 ldi $5,r1 bge_loop: noop sub $1,r1 bge bge_loop // Let's try the reverse loop again, only this time we'll store our // loop variable in memory. // R0 = 5; (from before) // do { // } while (R0 > 0); ldi $0x0b000,r11 bra mem_loop_test loop_var: .dat 0 mem_loop_test: mov loop_var(pc),r1 ldi $5,r0 clr r2 sto r0,(r1) mem_loop: add $1,r2 add $14,r0 lod (r1),r0 sub $1,r0 sto r0,(r1) bgt mem_loop cmp $5,r2 trap.ne r11 #endif #ifdef SHIFT_TEST ; Now, let's test whether or not our LSR and carry flags work ldi $0x0c000,r11 ldi -1,r0 ; First test: shifting all the way should yield zero lsr 32,r0 cmp 0,r0 bnz test_failure ldi -1,r0 ; Second test: anything greater than zero should set lsr 0,r0 ; the carry flag bc test_failure lsr 1,r0 tst sys.ccc,cc ; FAILS HERE!!! @0x010007c bz test_failure lsr 31,r0 tst sys.ccc,cc bz test_failure lsr 1,r0 bc test_failure ; Now repeat the above tests, looking to see whether or not ASR works ldi -1,r0 asr 32,r0 cmp -1,r0 bnz test_failure ldi -1,r0 asr 0,r0 bc test_failure cmp -1,r0 bnz test_failure asr 1,r0 tst sys.ccc,r14 bz test_failure asr 30,r0 tst sys.ccc,r14 bz test_failure // Let's test whether LSL works ldi 0x035,r2 lsl 8,r2 ldi 0x03500,r1 cmp r2,r1 trap.ne r11 ldi 0x074,r0 and 0x0ff,r0 or r0,r2 cmp 0x03574,r2 trap.ne r11 #endif #ifdef MPY_TEST // We have two multiply instructions. Let's see if those work ldi $0x0d000,r11 // Mark our test ldi 23171,r0 // = sqrt(2)/2 * 32768 mpyu r0,r0 // Should = 2/4 * 2^30 = 2^29 or thereabouts ldi 536895241,r2 cmp r0,r2 trap.ne r11 ldi 0x0ffff,r0 mpyu r0,r0 ldi 0xfffe0001,r1 cmp r1,r0 trap.ne r11 ldi 0x08001,r0 ldi 0x07fff,r1 mpys r0,r1 // FAILS: result is 0x008001 ??? (pipeline prob) ldi 0x3fff0001,r2 neg r2 cmp r2,r1 // @0x010011c trap.ne r11 //TRAP FAILS TO TRIGGER ????? (R2=0x0c000ffff,R1=0x0008001 -- did mpy even happen?) mpys r0,r0 // FAILS: result is 0x40010001 ldi 0x3fff0001,r2 cmp r2,r0 trap.ne r11 // TRAP FAILS TO TRIGGER AGAIN ldi 0x08000,r0 mpys r0,r0 // R0 now equals 0x40000000 ldi 0x40000000,r1 cmp r0,r1 trap.ne r11 #endif // Return success / Test the trap interrupt clr r11 trap r11 noop noop busy // And, in case we miss a halt ... halt // Now, let's test whether or not we can handle a subroutine #ifdef PUSH_TEST reverse_bit_order: PUSH(R1,SP) PUSH(R2,SP) LDI 32,R1 CLR R2 LSL 1,R2 LSR 1,R0 OR.C 1,R2 SUB 1,R1 BNZ reverse_bit_order_loop MOV R2,R0 POP(R2,SP) POP(R1,SP) RET #endif fill 512,0 stack: word 0

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [sw/] [zasm/] [test.S] - Blame information for rev 27

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line

powered by: WebSVN 2.1.0

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