Discussion:
Gotchas when coding for RT11
(too old to reply)
j***@mdfs.net
2020-05-20 02:20:53 UTC
Permalink
This has been tearing my hair out for days, and I have found
zero mention of the issues I was getting.

** When making an RT11 EMT call, there is restriction on where
the stack may be. **

My code calls SETTOP to grab memory, then naturally I put SP at
the top of memory. All EMT 375 calls bombed out with Odd Address
errors. Annoyingly, it worked on the Soviet UKNC running its RT11
clone.

I stripped my code down to the minimum example, and weirdly, it
worked. So I gradually added bits of the environment of the
full program until it died.

I make the EMT call by pushing the parameters on the stack and
them MOV SP,R0; EMT &o375. I tried everything I could think of,
not stacking the arguments, not stacking the filename, not
stacking either, the only time it worked was when I did:
EMT SETTOP
;MOV R0,SP ; comment out

I don't know what the explict restriction is, but by trial and
error I've concluded that if I want to make any RT11 EMT calls
the stack must be in the "initial stack area" at &o1000 downwards.

So I've replaced my EMT &o375 calls with a JSR to:
mov sp,510
mov #510,sp
emt &o375
mov 510,sp
rts pc

Are there any other gotchas that may trip me up?

jgh
Jerry Weiss
2020-05-20 22:09:02 UTC
Permalink
This post might be inappropriate. Click to display it.
j***@mdfs.net
2020-05-21 20:37:53 UTC
Permalink
Post by Jerry Weiss
Post by j***@mdfs.net
I make the EMT call by pushing the parameters on the stack and
them MOV SP,R0; EMT &o375.
A bit more info on what the EMT 375 calls are would help.
LOOKUP and GETTIM (I actually thought I'd included that bit in
the above quoted section, but I trimmed out the relevant bit:
clr -(sp) ; seq=0
mov r2,-(sp) ; r2=>fname
bis r0,1*256 ; 1=LOOKUP
mov r0,-(sp) ; LOOKUP+CHAN
mov sp,r0 ; r0=>params
emt &o375
)
Post by Jerry Weiss
Many of the EMT 375 calls that involve file operations and
will trigger the USR to load. Since there is no free memory,
part of your program (code or data) will be swapped out to
disk and the USR loaded temporarily.
Thanks. I was starting to suspect something towards that, I'd
concluded "anything with a parameter block in memory rather
than registers" which is close enough. eg TTYIN and TTYOUT
work fine.

jgh
Jerry Weiss
2020-05-22 00:39:50 UTC
Permalink
Post by j***@mdfs.net
Post by Jerry Weiss
Post by j***@mdfs.net
I make the EMT call by pushing the parameters on the stack and
them MOV SP,R0; EMT &o375.
A bit more info on what the EMT 375 calls are would help.
LOOKUP and GETTIM (I actually thought I'd included that bit in
clr -(sp) ; seq=0
mov r2,-(sp) ; r2=>fname
bis r0,1*256 ; 1=LOOKUP
mov r0,-(sp) ; LOOKUP+CHAN
mov sp,r0 ; r0=>params
emt &o375
)
Post by Jerry Weiss
Many of the EMT 375 calls that involve file operations and
will trigger the USR to load. Since there is no free memory,
part of your program (code or data) will be swapped out to
disk and the USR loaded temporarily.
Thanks. I was starting to suspect something towards that, I'd
concluded "anything with a parameter block in memory rather
than registers" which is close enough. eg TTYIN and TTYOUT
work fine.
jgh
LOOKUP will load the USR. As will many directory file type and handler operations.

If you have a section of memory that is not involved in this function, enter the address into location 46 (octal - $UFLOA). The size needed is found at location 374 offset in the monitor (use .GVAL). Also, check location 50 to see the actual high memory address granted your program.

Web search the following documents, which give more insight as to how the USR is involved in certain functions.
AA-PD6NA-TC_RT-11_System_Internals_Manual_Aug91
AA-PD6LA-TC_RT-11_System_Macro_Library_Manual_Aug91 see page 1-16.

Jerry
j***@mdfs.net
2020-05-23 00:17:51 UTC
Permalink
Post by Jerry Weiss
Web search the following documents, which give more insight as to how
the USR is involved in certain functions.
AA-PD6NA-TC_RT-11_System_Internals_Manual_Aug91
AA-PD6LA-TC_RT-11_System_Macro_Library_Manual_Aug91 see page 1-16.
Ta, I'd been trawling through those and hadn't managed to find anything
explicit enough to explain what was happening until by trial and error
I worked out what was happening, and then the table on page 1-16 made
sense.

I now have a working generic OPENFILE function that LOOKsUP a file
supplied in plain ACSII, that returns a FOUND/NOTFOUND result, and
not only doesn't bomb out, it also doesn't bomb out if the device
doesn't exist with a pre-check via DSTATUS.

But, phew, it was a learning experience. Unix just lets you do
TRAP open,filename and does all the juggling behind the scenes
itself.

jgh
Jerry Weiss
2020-05-23 15:24:27 UTC
Permalink
Post by j***@mdfs.net
Post by Jerry Weiss
Web search the following documents, which give more insight as to how
the USR is involved in certain functions.
AA-PD6NA-TC_RT-11_System_Internals_Manual_Aug91
AA-PD6LA-TC_RT-11_System_Macro_Library_Manual_Aug91 see page 1-16.
Ta, I'd been trawling through those and hadn't managed to find anything
explicit enough to explain what was happening until by trial and error
I worked out what was happening, and then the table on page 1-16 made
sense.
I now have a working generic OPENFILE function that LOOKsUP a file
supplied in plain ACSII, that returns a FOUND/NOTFOUND result, and
not only doesn't bomb out, it also doesn't bomb out if the device
doesn't exist with a pre-check via DSTATUS.
But, phew, it was a learning experience. Unix just lets you do
TRAP open,filename and does all the juggling behind the scenes
itself.
jgh
Congrats on sorting it out.

RT-11 and UNIX are at separate ends of the operating system spectrum.

RT-11 targeted single user and real time response. Small OS footprint, low overhead, dependable response time, direct access to hardware controls and interrupts. Rough edges of both hardware and software are exposed to the developer. Easy to write loadable handlers, a very basic directory and asynchronous file IO system. Basic tools and features. The system documentation is both a good reference and an educational source.

Unix was multiuser and was driven by its philosophy which originally centered around support program development. Limited access to hardware, more sophisticated directory and mostly synchronous IO. Ever expanding set of modular tools and features.

It is always nice to have different types of "hammers" !
Bob Eager
2020-05-23 16:54:19 UTC
Permalink
Post by Jerry Weiss
Post by j***@mdfs.net
Post by Jerry Weiss
Web search the following documents, which give more insight as to how
the USR is involved in certain functions.
AA-PD6NA-TC_RT-11_System_Internals_Manual_Aug91
AA-PD6LA-TC_RT-11_System_Macro_Library_Manual_Aug91 see page 1-16.
Ta, I'd been trawling through those and hadn't managed to find anything
explicit enough to explain what was happening until by trial and error
I worked out what was happening, and then the table on page 1-16 made
sense.
I now have a working generic OPENFILE function that LOOKsUP a file
supplied in plain ACSII, that returns a FOUND/NOTFOUND result, and not
only doesn't bomb out, it also doesn't bomb out if the device doesn't
exist with a pre-check via DSTATUS.
But, phew, it was a learning experience. Unix just lets you do TRAP
open,filename and does all the juggling behind the scenes itself.
jgh
Congrats on sorting it out.
RT-11 and UNIX are at separate ends of the operating system spectrum.
RT-11 targeted single user and real time response. Small OS footprint,
low overhead, dependable response time, direct access to hardware
controls and interrupts. Rough edges of both hardware and software are
exposed to the developer. Easy to write loadable handlers, a very basic
directory and asynchronous file IO system. Basic tools and features.
The system documentation is both a good reference and an educational
source.
Unix was multiuser and was driven by its philosophy which originally
centered around support program development. Limited access to
hardware, more sophisticated directory and mostly synchronous IO. Ever
expanding set of modular tools and features.
It is always nice to have different types of "hammers" !
I agree.

But Mini-UNIX (which I once ran on an 11/20) is somewhere in between!
--
Using UNIX since v6 (1975)...

Use the BIG mirror service in the UK:
http://www.mirrorservice.org
j***@mdfs.net
2020-05-26 00:10:21 UTC
Permalink
Post by Jerry Weiss
Congrats on sorting it out.
RT-11 and UNIX are at separate ends of the operating system spectrum.
RT-11 targeted single user and real time response.
Yes, I'm finding the RT11 file system API offers even less than CP/M.
I find I'm inevitably writing essentially a full filing system with
RT11 being essentially the "block access API", rather that writing a
file system interface.
Don North
2020-05-26 04:22:36 UTC
Permalink
Post by j***@mdfs.net
Post by Jerry Weiss
Congrats on sorting it out.
RT-11 and UNIX are at separate ends of the operating system spectrum.
RT-11 targeted single user and real time response.
Yes, I'm finding the RT11 file system API offers even less than CP/M.
I find I'm inevitably writing essentially a full filing system with
RT11 being essentially the "block access API", rather that writing a
file system interface.
That seems strange to me.

Why do you find .LOOKUP/.ENTER, .READW/.WRITW, then .CLOSE insufficient?

Granted RT-11 has a very simple on-disk native flat file system with
contiguous block allocation, but it was found useful by many, many folks.

I wrote many apps (40 years ago) that used it from Macro11 (and a few from
Fortran).
j***@mdfs.net
2020-05-26 04:47:07 UTC
Permalink
Post by Don North
Post by j***@mdfs.net
Yes, I'm finding the RT11 file system API offers even less than CP/M.
I find I'm inevitably writing essentially a full filing system with
RT11 being essentially the "block access API", rather that writing a
file system interface.
That seems strange to me.
Why do you find .LOOKUP/.ENTER, .READW/.WRITW, then .CLOSE insufficient?
I can't do handle=open("readme.txt") I have to do
translate("readme.txt") to Radix50
if device="", make device="dk"
maintain a list of handles
pick a free handle
check device for radixname exists
lookfor(radixname,handle)

I can't do read(handle,memory,1) to read a byte, I have to do
allocate some memory for a file buffer
maintain a file pointer
if (filepointer && 511)=0 read(handle, buffer, 1 block, filepointer DIV 512)
get byte from buffer
increment file pointer

...at least that's what I'm finding I'm having to do. Similar to what I've
had to do in CP/M. But with the complication that RT11 seems to bomb out
to the monitor if you make the slightest assumption about something that
turns out to be absent, insead of returning some sort of 'not found'
status return.

Just as I thought I was getting CLOSE working, it's suddenly decided to
die and drop to the monitor with KMON-F-Bad channel errors - instead of
/returning/ a 'bad channel' status to me.

(I'm only doing this because I'm increasingly running out of things to
keep me occupied through Lockdown. ;) There's only so much rewiring I
can do to the flat, and so much weeding I can do in the garden.)

jgh
Jerry Weiss
2020-05-26 05:35:16 UTC
Permalink
Post by j***@mdfs.net
...
I can't do handle=open("readme.txt") I have to do
translate("readme.txt") to Radix50
if device="", make device="dk"
maintain a list of handles
pick a free handle
check device for radixname exists
lookfor(radixname,handle)
Look the the .GTLIN, .CSIGEN or .CSISPC Macros. They may (greatly) simplify the work above.
Post by j***@mdfs.net
I can't do read(handle,memory,1) to read a byte, I have to do
allocate some memory for a file buffer
maintain a file pointer
if (filepointer && 511)=0 read(handle, buffer, 1 block, filepointer DIV 512)
get byte from buffer
increment file pointer
Well, this is by design for RT-11. A good real time system has low overhead and repeatable response. If you add byte or record based buffering, you start to complicate things. Most of the languages and compliers implement these features or have libraries that support them.

In contrast RSX-11M standardizes record operations in its FCS and F11ACP components. A bit more complexity and overhead, but still a very responsive system.
Post by j***@mdfs.net
...at least that's what I'm finding I'm having to do. Similar to what I've
had to do in CP/M. But with the complication that RT11 seems to bomb out
to the monitor if you make the slightest assumption about something that
turns out to be absent, insead of returning some sort of 'not found'
status return.
Just as I thought I was getting CLOSE working, it's suddenly decided to
die and drop to the monitor with KMON-F-Bad channel errors - instead of
/returning/ a 'bad channel' status to me.
Most of the RT-11 has no protection against insults a program may inflict. KMON aka Keyboard Monitor (loaded when a program exits) errors like this are likely due to some corruption in the RMON (resident part of monitor). The RT–11 System Message Manual can be helpful here.
Post by j***@mdfs.net
(I'm only doing this because I'm increasingly running out of things to
keep me occupied through Lockdown. ;) There's only so much rewiring I
can do to the flat, and so much weeding I can do in the garden.)
jgh
TSX+ might interest you if you have at least 256K of memory, a CPU with memory management and a few MB of disk space. It uses most of the Utilities, Handlers and EMT's of RT-11 and adds multiuser/multisession and protected operating system features. Very easy to build (easier than RT-11 Sysgen). I used it quite successfully for real time data acquisition. TSX+ has been released for hobbyist type use - see http://tsxplus.classiccmp.org/.

Jerry
j***@mdfs.net
2020-06-10 23:53:33 UTC
Permalink
TSX+ might interest you if you have at least 256K of memory ...
Ah but the Electronica UKNC boots into RT11 not TSX.


I've got everything working now, it is very much like coding
for CP/M, but the one remaining thing I'm stuck on is doing
the equivalent of C's system(). I don't have an RT11 C compiler,
so I can't work out how to do it by compiling a one-line
program as I did for Unix. All I've been able to work out is
how to *terminate* and run something else, but I need to be
able to run something else, *and* *then* *continue* my
program. To be able to do something like:

while (fibble) {
...
switch (thing) {
....
case foo:
printf("-> ");
scanf("%s", string);
system(string);
break;
...
}
}


It looks like this is going to be another CP/M-ism, in that
my code is going to have to have its own DIR command and its
own RENAME command and its own DELETE command and have psychic
abilities to work out what else the monitor implements and
duplicate it. :(

jgh
Jerry Weiss
2020-06-11 04:44:34 UTC
Permalink
Post by j***@mdfs.net
TSX+ might interest you if you have at least 256K of memory ...
Ah but the Electronica UKNC boots into RT11 not TSX.
I've got everything working now, it is very much like coding
for CP/M, but the one remaining thing I'm stuck on is doing
the equivalent of C's system(). I don't have an RT11 C compiler,
so I can't work out how to do it by compiling a one-line
program as I did for Unix. All I've been able to work out is
how to *terminate* and run something else, but I need to be
able to run something else, *and* *then* *continue* my
while (fibble) {
...
switch (thing) {
....
printf("-> ");
scanf("%s", string);
system(string);
break;
...
}
}
It looks like this is going to be another CP/M-ism, in that
my code is going to have to have its own DIR command and its
own RENAME command and its own DELETE command and have psychic
abilities to work out what else the monitor implements and
duplicate it. :(
jgh
I am not aware of good way to do a unix like system() in RT-11. The .CHAIN function is quite limited and similar to what CP/M has, as you probably have discovered.

Jerry
Ian Hammond
2020-11-18 12:15:10 UTC
Permalink
With regard to the original question: all RT-11 EMT calls are free to modify R0.

In many cases it is used to return status or data.

Loading...