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