Add test for EM _rck_. Fix traps in PowerPC ncg.

The new test rck_e.e segfaults on PowerPC unless I make some changes.
The inline code for _rck_ was wrong because it didn't allow the trap
handler to return.  _sig_ forgot to push the old trap handler.

Move plat/linuxppc/libsys/trap.s to mach/powerpc/libem/trp.s and
rewrite it with simplified/extended mnemonics.  Remove .trap alias for
.trp procedure.  Add a missing `mtspr lr, r0` so we can return from
the trap handler.  Call write() and _exit() so trp.s works with both
linuxppc and osxppc.  Before, Mac OS X was wrongly using the trap.s
for Linux.

In powerpc/libem, simplify .aar4; teach .csa and .csb to raise the
trap if the default target is zero.

C programs don't need these changes.  You may relink your C programs
with the changed .csa and .csb, but C code doesn't raise the trap.
Modula-2 code can raise traps, so you may want to relink your Modula-2
programs with the changed libem, but you might keep your old .o files
from Modula-2.  You may need to recompile your Pascal programs (delete
old .o files from Pascal) because the Pascal compiler might use _rck_.
This commit is contained in:
George Koehler 2017-12-24 22:37:52 -05:00
parent 5f2a7b260f
commit 26de4c1ab1
12 changed files with 285 additions and 162 deletions

View file

@ -8,21 +8,17 @@
.define .aar4 .define .aar4
.aar4: .aar4:
lis r0, hi16[.trap_earray]
ori r0, r0, lo16[.trap_earray]
mtspr ctr, r0 ! load CTR with trap address
lwz r4, 0(sp) ! r4 = address of descriptor lwz r4, 0(sp) ! r4 = address of descriptor
lwz r5, 4(sp) ! r5 = index lwz r5, 4(sp) ! r5 = index
lwz r6, 8(sp) ! r6 = address of array lwz r6, 8(sp) ! r6 = address of array
lwz r0, 0(r4) lwz r0, 0(r4)
subf. r5, r0, r5 ! subtract lower bound from index subf. r5, r0, r5 ! subtract lower bound from index
bltctr ! check lower bound blt .trap_earray ! check lower bound
lwz r0, 4(r4) lwz r0, 4(r4)
cmplw r5, r0 cmplw r5, r0
bgtctr ! check upper bound bgt .trap_earray ! check upper bound
lwz r3, 8(r4) ! r3 = size of element lwz r3, 8(r4) ! r3 = size of element
mullw r5, r5, r3 ! scale index by size mullw r5, r5, r3 ! scale index by size
@ -30,3 +26,7 @@
stw r6, 8(sp) ! push address of element stw r6, 8(sp) ! push address of element
addi sp, sp, 8 addi sp, sp, 8
blr blr
.trap_earray:
li r3, 0 ! EARRAY = 0 in h/em_abs.h
b .trp

View file

@ -6,7 +6,7 @@ for _, plat in ipairs(vars.plats) do
acklibrary { acklibrary {
name = "lib_"..plat, name = "lib_"..plat,
srcs = { srcs = {
"./*.s", -- exg.s "./*.s", -- trp.s
}, },
vars = { plat = plat }, vars = { plat = plat },
deps = { deps = {
@ -15,4 +15,3 @@ for _, plat in ipairs(vars.plats) do
} }
} }
end end

View file

@ -13,22 +13,21 @@
lwz r4, 4(sp) lwz r4, 4(sp)
addi sp, sp, 8 addi sp, sp, 8
lwz r5, 0(r3) ! load default lwz r5, 0(r3) ! r5 = default target
mtspr ctr, r5
lwz r5, 4(r3) ! fetch lower bound lwz r6, 4(r3) ! fetch lower bound
subf. r4, r5, r4 ! adjust value subf. r4, r6, r4 ! adjust value
bltctr ! jump to default if out of range blt 1f ! jump to default if out of range
lwz r5, 8(r3) ! fetch range lwz r6, 8(r3) ! fetch range
cmplw r4, r5 cmplw r4, r6
bgtctr ! jump to default if out of range bgt 1f ! jump to default if out of range
addi r3, r3, 12 ! skip header addi r3, r3, 12 ! skip header
slwi r4, r4, 2 ! scale value (<<2) slwi r4, r4, 2 ! scale value (<<2)
lwzx r5, r3, r4 ! load target lwzx r5, r3, r4 ! r5 = new target
mtspr ctr, r5
or. r5, r5, r5 ! test it 1: mtspr ctr, r5
mr. r5, r5 ! test it
bnectr ! jump to target if non-zero bnectr ! jump to target if non-zero
b .trap_ecase ! otherwise trap b .trap_ecase ! otherwise trap

View file

@ -13,23 +13,20 @@
lwz r4, 4(sp) lwz r4, 4(sp)
addi sp, sp, 8 addi sp, sp, 8
lwz r5, 0(r3) ! load default lwz r5, 0(r3) ! r5 = default target
mtspr ctr, r5
lwz r6, 4(r3) ! fetch count lwz r6, 4(r3) ! fetch count
mr. r6, r6 ! skip loop if count is zero
1: beq 3f ! (needed by Modula-2 "CASE i OF END")
or. r6, r6, r6 ! test count mtspr ctr, r6
beqctr ! exit if zero 1: lwzu r7, 8(r3) ! fetch target index, increment pointer
addi r6, r6, -1 ! otherwise decrement
lwzu r7, 8(r3) ! fetch target index, increment pointer
cmpw r4, r7 ! compare with value cmpw r4, r7 ! compare with value
bne 1b ! if not equal, go again beq 2f
bdnz 1b ! if not equal, go again
b 3f
lwz r7, 4(r3) ! fetch target address 2: lwz r5, 4(r3) ! r5 = new target
mtspr ctr, r7 3: mtspr ctr, r5
mr. r5, r5 ! test target
or. r7, r7, r7 ! test it
bnectr ! jump to target if non-zero bnectr ! jump to target if non-zero
b .trap_ecase ! otherwise trap b .trap_ecase ! otherwise trap

View file

@ -18,3 +18,7 @@
bgt .trap_erange bgt .trap_erange
blr blr
.trap_erange:
li r3, 1 ! ERANGE = 1 in h/em_abs.h
b .trp

56
mach/powerpc/libem/trp.s Normal file
View file

@ -0,0 +1,56 @@
.sect .text
.define .trap_ecase
.trap_ecase:
li r3, 20 ! ECASE = 20 in h/em_abs.h
! FALLTHROUGH to .trp
! Raises an EM trap.
! Expects r3 = trap number.
.define .trp
.trp:
cmplwi r3, 15 ! traps > 15 can't be ignored
bgt 1f
lis r4, ha16[.ignmask]
lwz r4, lo16[.ignmask](r4) ! load ignore mask
srw r4, r4, r3
andi. r4, r4, 1
bnelr ! return if ignoring trap
1: lis r4, ha16[.trppc]
lwz r5, lo16[.trppc](r4) ! r5 = user trap routine
mr. r5, r5
beq 2f ! if no user trap routine, bail out
mtspr ctr, r5
mfspr r6, lr
li r0, 0
stwu r3, -8(sp) ! push trap number
stw r0, lo16[.trppc](r4) ! reset trap routine
stw r6, 4(sp) ! save old lr
bctrl ! call trap routine
lwz r0, 4(sp)
mtspr lr, r0
addi sp, sp, 8 ! retract over stack usage
blr
2: ! No trap handler. Write error message, exit.
li r3, 2
stwu r3, -12(sp)
lis r4, ha16[message]
addi r4, r4, lo16[message]
li r5, 6
stw r4, 4(sp)
stw r5, 8(sp)
bl _write ! write(2, message, 6)
li r3, 1
stw r3, 0(sp)
bl __exit ! _exit(1)
.sect .rom
message:
.ascii "TRAP!\n"

View file

@ -2168,10 +2168,13 @@ PATTERNS
pat trp /* Raise EM trap */ pat trp /* Raise EM trap */
with REG3 with REG3
kills ALL kills ALL
gen bl {LABEL, ".trap"} gen bl {LABEL, ".trp"}
pat sig /* Set trap handler */ pat sig /* Set trap handler, yield old */
leaving ste ".trppc" leaving
loe ".trppc"
exg 4
ste ".trppc"
pat rtt /* Return from trap */ pat rtt /* Return from trap */
leaving ret 0 leaving ret 0
@ -2216,22 +2219,14 @@ PATTERNS
with REG with REG
gen move %1, sp gen move %1, sp
pat lae rck $2==4 /* Range check */ pat rck $1==4 /* Range check */
with REG leaving cal ".rck"
kills ALL
gen
cmpwi %1, {C, rom($1, 1)}
blt {LABEL, ".trap_erange"}
cmpwi %1, {C, rom($1, 2)}
bgt {LABEL, ".trap_erange"}
yields %1
/* Single-precision floating-point */ /* Single-precision floating-point */
pat zrf $1==4 /* Push zero */ pat zrf $1==4 /* Push zero */
leaving leaving loe ".fs_00000000"
loe ".fs_00000000"
pat adf $1==4 /* Add single */ pat adf $1==4 /* Add single */
with FSREG FSREG with FSREG FSREG

View file

@ -4,7 +4,6 @@ acklibrary {
"./_syscall.s", "./_syscall.s",
"./sigaction.s", "./sigaction.s",
"./signal.c", "./signal.c",
"./trap.s",
"plat/linux/libsys/_exit.c", "plat/linux/libsys/_exit.c",
"plat/linux/libsys/_hol0.s", "plat/linux/libsys/_hol0.s",
"plat/linux/libsys/close.c", "plat/linux/libsys/close.c",

View file

@ -1,112 +0,0 @@
#
! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_syscall.s,v $
! $State: Exp $
! $Revision: 1.1 $
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#define IFFALSE 4
#define IFTRUE 12
#define ALWAYS 20
#define LT 0
#define GT 1
#define EQ 2
#define OV 3
EARRAY = 0
ERANGE = 1
ESET = 2
EIOVFL = 3
EFOVFL = 4
EFUNFL = 5
EIDIVZ = 6
EFDIVZ = 7
EIUND = 8
EFUND = 9
ECONV = 10
ESTACK = 16
EHEAP = 17
EILLINS = 18
EODDZ = 19
ECASE = 20
EMEMFLT = 21
EBADPTR = 22
EBADPC = 23
EBADLAE = 24
EBADMON = 25
EBADLIN = 26
EBADGTO = 27
EUNIMPL = 63 ! unimplemented em-instruction called
! EM trap handling.
.define .trap_ecase
.trap_ecase:
addi r3, r0, ECASE
b .trap
.define .trap_earray
.trap_earray:
addi r3, r0, EARRAY
b .trap
.define .trap_erange
.trap_erange:
addi r3, r0, ERANGE
b .trap
.define .trp
.define .trap
.trp:
.trap:
cmpi cr0, 0, r3, 15 ! traps >15 can't be ignored
bc IFTRUE, LT, 1f
addi r4, r0, 1
rlwnm r4, r4, r3, 0, 31 ! calculate trap bit
li32 r5, .ignmask
lwz r5, 0(r5) ! load ignore mask
and. r4, r4, r5 ! compare
bclr IFFALSE, EQ, 0 ! return if non-zero
1:
li32 r4, .trppc
lwz r5, 0(r4) ! load user trap routine
or. r5, r5, r5 ! test
bc IFTRUE, EQ, fatal ! if no user trap routine, bail out
addi r0, r0, 0
stw r0, 0(r4) ! reset trap routine
mfspr r0, lr
stwu r0, -4(sp) ! save old lr
stwu r3, -4(sp)
mtspr ctr, r5
bcctrl ALWAYS, 0, 0 ! call trap routine
lwz r0, 4(sp) ! load old lr again
addi sp, sp, 8 ! retract over stack usage
bclr ALWAYS, 0, 0 ! return
fatal:
addi r3, r0, 1
li32 r4, message
addi r5, r0, 6
addi r0, r0, 4 ! write()
sc 0
addi r0, r0, 1 ! exit()
sc 0
.sect .rom
message:
.ascii "TRAP!\n"

View file

@ -19,7 +19,6 @@ acklibrary {
"./sigaction.s", "./sigaction.s",
"./stat.s", "./stat.s",
"./write.s", "./write.s",
"plat/linuxppc/libsys/trap.s",
"plat/osx/libsys/brk.c", "plat/osx/libsys/brk.c",
"plat/osx/libsys/creat.c", "plat/osx/libsys/creat.c",
"plat/osx/libsys/isatty.c", "plat/osx/libsys/isatty.c",

View file

@ -13,6 +13,7 @@ definerule("plat_testsuite",
"tests/plat/dup_e.e", "tests/plat/dup_e.e",
"tests/plat/exg_e.e", "tests/plat/exg_e.e",
"tests/plat/inn_e.e", "tests/plat/inn_e.e",
"tests/plat/rck_e.e",
"tests/plat/rotate_e.e", "tests/plat/rotate_e.e",
"tests/plat/*.p", "tests/plat/*.p",
"tests/plat/b/*.b", "tests/plat/b/*.b",

186
tests/plat/rck_e.e Normal file
View file

@ -0,0 +1,186 @@
#
mes 2, EM_WSIZE, EM_PSIZE
/*
* Uses _rck_ for range checks. Catches the EM trap if a value is out
* of range, and continues with the next instruction after _rck_.
*
* Some back ends, like i80, ignore _rck_, so this test fails.
*/
testnr
con 1 ; test number
caught
con 0 ; number of caught traps
inp $next
inp $catch
inp $never
exp $_m_a_i_n
pro $_m_a_i_n,0
lim ; load ignore mask
loc 2
and EM_WSIZE ; check bit 1 << ERANGE
zeq *1 ; fail if ignoring ERANGE
.1
rom 1I4
lae .1
loi 4
cal $fail
asp 4
1
cal $next ; increment testnr, catch next trap
loc 10125
.2
rom 4283, 13644
lae .2
rck EM_WSIZE ; testnr 2 in range
asp EM_WSIZE
cal $next
loc 4282
lae .2
rck EM_WSIZE ; testnr 3 out of range
asp EM_WSIZE
cal $next
loc 4283
lae .2
rck EM_WSIZE ; testnr 4 in range
asp EM_WSIZE
cal $next
loc 13644
lae .2
rck EM_WSIZE ; testnr 5 in range
asp EM_WSIZE
cal $next
loc 13655
lae .2
rck EM_WSIZE ; testnr 6 out of range
asp EM_WSIZE
cal $next
loc -13015
.7
rom -31344, -1898
lae .7
rck EM_WSIZE ; testnr 7 in range
asp EM_WSIZE
cal $next
loc 8580
.8
rom -26315, 4588
lae .8
rck EM_WSIZE ; testnr 8 out of range
asp EM_WSIZE
; The last test raised a trap, so now there is no trap handler.
lpi $never
sig ; push old trap handler
loc 0
loc EM_WSIZE
loc EM_PSIZE
cuu ; push NULL pointer
cmp
zeq *17 ; fail unless old handler is NULL
.17
rom 17I4
lae .17
loi 4
cal $fail
asp 4
17
; Change the trap handler from $never to $catch.
lpi $catch
sig
lpi $never
cmp
zeq *18
.18
rom 18I4
lae .18
loi 4
cal $fail
asp 4
18
; Begin ignoring range traps.
loc 2 ; 1 << ERANGE
sim
loc 18
ste testnr
loc 8580
lae .8
rck EM_WSIZE ; testnr 18 out of range but ignored
; Fail if we caught the wrong number of traps.
loe caught
loc 3
beq *20
.20
rom 20I4
lae .20
loi 4
cal $fail
asp 4
20
cal $finished
end
pro $next,0
ine testnr ; next test
lpi $catch
sig ; catch next EM trap (only one trap)
asp EM_PSIZE
ret 0
end
pro $catch,0
ine caught ; count this trap
lol 0 ; load trap number
loc 1
beq *1 ; fail if trap != ERANGE
.101
rom 257I4
lae .101
loi 4
cal $fail
; Wrong type of trap. _rtt_ might not work, so exit now.
cal $finished
1
; Fail if the wrong test raised this trap.
loe testnr
loc 3
beq *2
loe testnr
loc 6
beq *2
loe testnr
loc 8
beq *2
loc 256
loe testnr
adi EM_WSIZE ; 0x100 + testnr
loc EM_WSIZE
loc 4
cuu
cal $fail
asp 4
2
rtt ; return from trap handler
end
pro $never,0
.200
rom 200I4
lae .200
loi 4
cal $fail
asp 4
rtt
end