Line 6... |
Line 6... |
;
|
;
|
; 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 July, 2015, the assembler isn't sophisticated enough
|
; Status: As of August, 2015, this file assembles, builds, and passes
|
; to handle the address resolution needed to assemble this file.
|
; all of its tests in the Verilator simulator.
|
;
|
;
|
; Creator: Dan Gisselquist, Ph.D.
|
; Creator: Dan Gisselquist, Ph.D.
|
; Gisselquist Tecnology, LLC
|
; Gisselquist Tecnology, LLC
|
;
|
;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
Line 32... |
Line 32... |
; http://www.gnu.org/licenses/gpl.html
|
; http://www.gnu.org/licenses/gpl.html
|
;
|
;
|
;
|
;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;
|
;
|
|
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.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
|
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
|
|
busy
|
|
rtu
|
|
continue_test_with_testable_instructions:
|
|
; Now, let's place the assembler into a known state
|
clr r0
|
clr r0
|
mov r0,r1
|
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
|
|
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 $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
|
not.z r0
|
not.z r0
|
|
bge test_failure
|
|
junk_address:
|
clrf r0
|
clrf r0
|
|
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
|
lod $-7+pc,r2
|
mov junk_address(pc),r2 ; Test pc-relative addressing
|
ldihi $deadh,r3
|
mov junk_address(pc),r3
|
ldihi $beefh,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
|
|
; Now, let's test whether or not our LSR and carry flags work
|
|
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
|
|
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
|
|
#endif
|
|
|
|
#ifdef NOONE // Testing comments after ifdef
|
|
#else ; After else
|
|
#endif /* and after endif */
|
testbench:
|
testbench:
|
// Let's build a software test bench.
|
// Let's build a software test bench.
|
clr r12 ; R12 will point to our peripherals
|
ldi $c0000000h,r12 ; Set R12 to point to our peripheral address
|
ldihi $c000h,r12
|
|
mov r12,ur12
|
mov r12,ur12
|
mov test_start,upc
|
mov test_start(pc),upc
|
ldihi $8001,r0
|
ldi 0x8000ffff,r0 ; Clear interrupts, turn all vectors off
|
ldilo $-1,r0
|
sto r0,(r12)
|
sto r0,$1+r12
|
|
rtu
|
rtu
|
lod r12,r0
|
mov ucc,r0
|
cmp $0,r0
|
tst -256,r0
|
bnz $1
|
bnz test_failure
|
halt
|
halt
|
|
// Go into an infinite loop if the trap fails
|
|
// Permanent loop instruction -- a busy halt if you will
|
|
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.
|
|
|
; 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
|
; Test LDI to PC
|
; Some data registers
|
; Some data registers
|
.dat __here__+5
|
test_data:
|
|
.dat __here__+0x0100000+5
|
test_start:
|
test_start:
|
ldi $2,r11
|
ldi $0x0100,r11
|
lod $-3+pc,pc
|
lod test_data+pc,pc
|
clr r11
|
clr r11
|
noop
|
noop
|
cmp $0,r11
|
cmp $0,r11
|
sto.z r11,(r12)
|
trap.z r11
|
add $1,r0
|
add $1,r0
|
add $1,r0
|
add $1,r0
|
|
|
// Let's test whether overflow works
|
// Let's test whether overflow works
|
ldi $3,r11
|
ldi $0x0200,r11
|
ldi $-1,r0
|
ldi $-1,r0
|
lsr $1,r0
|
lsr $1,r0
|
add $1,r0
|
add $1,r0
|
bv $1
|
bv first_overflow_passes
|
sto r11,(r12)
|
trap r11
|
|
first_overflow_passes:
|
// Overflow set from subtraction
|
// Overflow set from subtraction
|
ldi $4,r11
|
ldi $0x0300,r11
|
ldi $1,r0
|
ldi $1,r0
|
.dat 0x5000001f ; rol $31,r0
|
rol $31,r0 ; rol $31,r0
|
sub $1,r0
|
sub $1,r0
|
bv $1
|
bv subtraction_overflow_passes
|
sto r11,(r12)
|
trap r11
|
|
subtraction_overflow_passes:
|
// Overflow set from LSR
|
// Overflow set from LSR
|
ldi $5,r11
|
ldi $0x0400,r11
|
ldi $1,r0
|
ldi $1,r0
|
.dat 0x5000001f ; rol $31,r0
|
rol $31,r0 ; rol $31,r0
|
lsr $1,r0
|
lsr $1,r0
|
bv $1
|
bv lsr_overflow_passes
|
sto r11,(r12)
|
trap r11
|
|
lsr_overflow_passes:
|
// Overflow set from LSL
|
// Overflow set from LSL
|
ldi $6,r11
|
ldi $0x0500,r11
|
ldi $1,r0
|
ldi $1,r0
|
.dat 0x5000001e
|
rol $30,r0
|
lsl $1,r0
|
lsl $1,r0
|
bv $1
|
bv lsl_overflow_passes
|
sto r11,(r12)
|
trap r11
|
|
lsl_overflow_passes:
|
// Overflow set from LSL, negative to positive
|
// Overflow set from LSL, negative to positive
|
ldi $7,r11
|
ldi $0x0600,r11
|
ldi $1,r0
|
ldi $1,r0
|
.dat 0x5000001f; // E: ROL $30,R0
|
rol $31,r0
|
lsl $1,r0
|
lsl $1,r0
|
bv $1
|
bv second_lsl_overflow_passes
|
sto r11,(r12)
|
trap r11
|
|
second_lsl_overflow_passes:
|
// Test carry
|
// Test carry
|
ldi $0x010,r11
|
ldi $0x0700,r11
|
ldi $-1,r0
|
ldi $-1,r0
|
add $1,r0
|
add $1,r0
|
tst $2,cc
|
tst $2,cc
|
sto.z r11,(r12)
|
trap.z r11
|
// and carry from subtraction
|
// and carry from subtraction
|
ldi $17,r11
|
ldi $0x0800,r11
|
sub $1,r0
|
sub $1,r0
|
tst $2,cc
|
tst $2,cc
|
sto.z r11,(r12)
|
trap.z r11
|
|
|
// 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
|
for_loop:
|
ldi $0x0800,r11
|
ldi $18,r11
|
|
clr r0
|
clr r0
|
|
for_loop:
|
noop
|
noop
|
add $1,r0
|
add $1,r0
|
cmp $5,r0
|
cmp $5,r0
|
blt for_loop
|
blt for_loop
|
//
|
//
|
Line 156... |
Line 328... |
// 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 $0x0900,r11
|
bgt_loop:
|
bgt_loop:
|
ldi $19,r11
|
|
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,r00
|
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
|
Line 178... |
Line 350... |
// 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 $21,r11
|
ldi $0x0a00,r11
|
bra $1
|
bra mem_loop_test
|
loop_var:
|
loop_var:
|
.dat 0
|
.dat 0
|
mem_loop:
|
mem_loop_test:
|
mov $-2+pc,r1
|
mov loop_var(pc),r1
|
clr r2
|
|
ldi $5,r0
|
ldi $5,r0
|
sto r1,(r0)
|
clr r2
|
|
sto r0,(r1)
|
|
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
|
bgt $-6
|
sto r0,(r1)
|
|
bgt mem_loop
|
cmp $5,r2
|
cmp $5,r2
|
sto.ne r11,(r12)
|
trap.ne r11
|
|
|
// Return success / Test the trap interrupt
|
// Return success / Test the trap interrupt
|
clr r11
|
clr r11
|
sto r11,(r12)
|
trap r11
|
noop
|
noop
|
noop
|
noop
|
|
|
// Go into an infinite loop if the trap fails
|
|
// Permanent loop instruction -- a busy halt if you will
|
|
busy
|
busy
|
|
|
// And, in case we miss a halt ...
|
// And, in case we miss a halt ...
|
halt
|
halt
|