@(#)os: OS/A65 - a Multitasking/Multithreading Operating System for 6502 Computers by Andre Fachat (a.fachat@physik.tu-chemnitz.de) http://www.tu-chemnitz.de/~fachat @(A): Introduction In 1989, I first thought about building a self-designed computer. I already had some experience with 6502 based computers. A friend of mine and I had been trying to build a telephone line switch computer based on the 6502. Although the project never succeeded (well, to a certain extent= it worked, but then we always got new ideas...), the project gave me an idea of what an OS should be capable of. With my homebrew computer, I not only wanted to implement one of those 'simple' OSes as in the C64 or other 6502 based computer, but I also wanted to go a step further and do a real multitasking, microkernel design OS. This constrained the hardware design to allow memory mapping of key memory locations, including the 6502 zero-page and stack. @(A): What Should a Real OS Do? A real operating system has four major parts that handle the input/output, filesystems, memory management and process handling. At the very least, a "real" OS includes some form of multitasking :-) Process management forms one block of an OS. A multitasking operating system requires more administration than a single-tasking OS. A process, or task, can be seen as a set of allocated resources. These resources include memory pages, swap pages, open files, and even the CPU, if the task is active. The CPU is the processing element that executes the given= program using the allocated resources. Therefore, the CPU state has to be= saved if a task is interrupted. This allows undisturbed continuation after the interruption is handled. For each task, the allocated resources= have to be registered and freed. As the CPU can be allocated to only a single task at a given time, it must be shared among all the active processes. So, in order to create the illusion of executing multiple processes at the same time (pseudo-parallelism), the CPU has to be assigned to one task after another, at a speed that achieves this illusion. If the assignments happen too slow, the illusion is lost, but if the speed is too fast, the CPU spends all of its time administering the tasks and not enough time executing the tasks. The same concepts hold true for multiprocessor computers, except that such a machine can achieve parallel operation on as many tasks as there are CPUs in the system. A scheduler interrupts the CPU after a certain time to allow the CPU to be assigned to another task. If the scheduler interrupts the task itself to schedule a new task, the system is called preemptive. If the task has to give the CPU back to the system, it is called cooperative multitasking, like in MS Windows (tm). of the two, preemptive is preferred, as cooperative multitasking fails when a single process forgets or is unable to relinquish control of the CPU. If such a scenario occurs, the computer is "blocked". As the second part, I/O provides a uniform interface to all peripherals, including character devices (serial lines, parallel printers), or block devices (disk drives). These services are normally provided by device drivers, which, in some operating systems, are even loadable. One problem= is the communication between device interrupt routines and the rest of the system. Andrew Tanenbaum, in _Operating Systems, Design and Implementation_, says that, "Interrupts are an unpleasant fact of life. They should be hidden away, deep in the bowels of the system, so that as little of the system as possible knows about them." Nevertheless, interrupts are necessary to handle time critical operations, like providing new data to serial lines. Provisions must be taken to avoid data corruption by an interrupt routine and a program (or the kernel) using the same memory locations at the same time. So, even if you don't like interrupts, you have to use them. As the third part, the filesystem provides user-level abstraction of I/O.= Files store information of any kind. It is the most visible part of the OS. The naming conventions make a big part of the OS view for the normal user. (Remember the 8+3 character filename length restriction in MS-DOS filesystems?) The filesystem itself provides a standard interface to the user, although the underlying structure (i.e. how files are stored) may differ on different devices. In UNIX operating systems, even devices can be used as files and are represented by special entries in the directory structure (on the newest version of Linux (pre2.0.) even files can be used as filesystem (that hold files that can be used as filesystem (that hold files.. Ooops ;-))). I will not go further into this issue, but how a filesystem is organized can sometimes become a religious war among their respective followers. Since a filesystem keeps all internal structures to itself, it is possible to mount differently structured filesystems in one system. As the final part, memory management keeps track of which parts of the memory are in use and which are not. Memory can be allocated when needed and is freed for other uses when no longer needed. Modern systems use the= concept of virtual memory. Virtual memory specifies a system that uses a translation table between the CPU and the real memory locations. When the CPU tries to access a certain memory address, the address given in the opcode does not reflect the real address used to access the memory chips. Instead, the translation table is used to look up the real memory= address from the `virtual' address given in the opcode. So, if there is no appropriately sized contiguous memory block available in real memory, such a block can be built using smaller chunks by setting up the translation table for the task. The lookup is done by the memory management unit (MMU). Software called a memory mapper is used to load and change the table. It loads the table with the values set up for each task. So the same opcode address in two different tasks accesses very different memory locations in the RAM. More sophisticated memory managers even do swapping. The memory manager allows a task to allocate more memory than actually available. If a memory location that is not available is accessed, the CPU is trapped (the ability to do this cleanly was one of the (IMHO very few) additions from the Motorola 68000 to the 68010 CPU). The memory manager then saves (swaps out) another memory page to disk and uses the now free memory. The= CPU can then continue. If a swapped out memory address is accessed, the CPU is halted again and the page is swapped in again - swapping out another page if necessary. Clearly this slows the whole thing down, but then virtual addresses are a very nice feature. You can hide the pages used by other tasks or map the same memory to several tasks, making it shared memory. These inclusion of these features implies that all resources can be assigned equally to each task. As there are problems with this in the 6502 (think of the stack), another concept should at least be mentioned. The IBM `Virtual Machine' (VM/*) series of operating systems emulates the= entire computer's hardware resources for a single task (i.e. a task doesn't talk to the system via system calls, but by writing data into some I/O registers). These register accesses are trapped and appropriate= action is taken. This means that the task can behave as if it owns the entire machine. This also means it must load its own OS to handle disk and other I/O (the second part of the "VM/*" naming scheme). The Commodore PET and its successors, the VIC, C64 and 128, already contain some functionality of a "real" OS. On these machines, a single interface allows uniform file access across different devices (tape, disk, console). All of them are accessed via the standard OPEN / CKOUT / CHKIN / CLOSE system calls. However, I/O comprises only one part of an OS, as defined above. The Commodore 8 bit computers are single CPU, singletasking systems (for exceptions see below). Therefore, no process management is necessary. In addition, there is no memory management. All memory is assigned to the single running process. (Although sometimes the= need for multiple $cXXX pages seems pressing.) The filesystem, an important part of an OS, is put into the floppy drive on Commodore 8-bit computers and is accessed via standard I/O over the IEEE bus. One interesting exception is the old (IEEE488) Commodore disk drives. These drives have not one but two processors: one 6502 and a 6504 that run in parallel and share some memory. The 6504 is used as a floppy drive= controller that handles the low level disk I/O. The 6502 gets the commands from the bus and processes the `filesystem' task. By writing low= level commands to certain memory locations, it sends commands to the floppy drive controller (the 6504) that in turn reads and writes the disk= blocks. If you look at the 1541, for example, you can see that this concept still holds true. However, in the 1541, the interrupt routine takes the role of the drive controller. Ironically, this reduction in CPUs was done to save 1541. In its effort to cut costs, Commodore forced= the single CPU of the 1541 to multitask, creating a bare operating system= to support drive operation. @(A): Modern Kernel Design Early operating systems started with a monolithic approach. i.e. all the system functions were provided with one big binary. Modern UNIX systems- even Linux, which is not derived from the original UNIX source- use this concept. A modern kernel instead has a microkernel design. A microkernel only provides the means of communication between different processes, not doing much itself. Some implementations even have the scheduler (!) or memory manager (!) running as a separate task. The kernel calls these processes to find out about free memory pages and which task to start next. This reduces the size of the kernel and allows greater flexibility.= On the downside, the microkernel designs forces more messages to be transferred, slowing down operation somewhat. One `famous' microkernel implementation is the current Mach microkernel. This kernel, and its derivatives, has been ported to many platforms. The PowerPC Platform OS/2 is based on a mach derived microkernel, as well as Linux for PowerPC Macintosh (mklinux). But, these are relatively simple ports of already existing operating systems. These mach `single servers' don't allow alternate OS system to run alongside or instead of themselves. On the other hand, the GNU Hurd operating system exploits the mach design to allow any server to be replaced by another. @(A): The OS/A65 Operating System Now let's get from the theory to practice... @(A): The Kernel Implementation When it comes to hardware design, the 6502 has a big advantage: It is a very simple CPU. With only a few support ICs, it is possible to build a fully functional computer (neglecting video and sound capabilities). On the other hand, the simplicity of the CPU has drawbacks. The 6502 has only three multi-purpose registers, and all are 8 bits. As such, none can hold a complete 16 bit 6502 memory location. Even the stack pointer is 8 bits, restricting the stack to the 256 bytes from $0100 to $01ff. The stack size and the absolute addresses are a severe limitation if you intend to develop a multitasking OS on this machine. Because I was developing a new system, I could do anything I wanted to get around this problem. I solved the stack problem by using an MMU, a Memory Management Unit. (Although the used chip, the 74ls610 is stated to= be a `Memory Mapper' for paged memory mapping, I call it a `Memory Management Unit'...). The upper 4 address bits are used to select one of 16 8-bit registers. (The 74ls610 has 12-bit registers, buonly 8 bits are used, for obvious reasons.) The output of the registers were then used as the upper 8 address bits, extending the total accessible memory to 1 MByte. The CPU could switch each 4 kByte page to any of the 256 pages available by changing the register values in the MMU. Oops - just introduced virtual addresses to the 6502 ;-) For each task, new memory is allocated and saved in the task's page table. When a task is activated, the MMU registers are loaded with these values, giving each task its own memory environment. In the described OS,= the memory `manager' is part of the kernel, although a quite independent part. The virtual addresses in the opcodes are translated to the real addresses through the contents of the MMU registers. The tasks are handled by the environment routines. These routines set up the environment tables used by the scheduler. The (round robin) scheduler= performs the task switching and decides which task to run next. Preemptive multitasking is achieved by using the interrupt to switch between different tasks. The most important routines are the two kernel entry and exit routines. These sub-routines have to switch the pages and the stack pointer as well as preserve all other register values. The tasks providing filesystem services register with the filesystem manager. They are then assigned drive numbers. Although UNIX filesystems= are virtual, where a user can reconfigure the system at any time, developing such a system for the 6502 would overly complicate matters. Different filesystems can then be used at the same time with different drive numbers. The drive numbers are translated by the filesystem manager= when passing the message through to the filesystem task. Currently `fsiec' for IEEE488 (parallel IEC-bus) interfaced CBM disk drives, `fsibm' (for PC style disks) and `fsdev' for using devices as files are provided. The interface to the hardware is provided by the devices. Devices are simply stripped off tasks and are called as subroutines only. A device- filesystem (`fsdev') task translates filesystem requests to the device interface, so that any device can be used like a file. The general structure can be seen in Fig.1. ---------- --------- --------- ------ ------- | fsdev | | fsiec | | fsibm | | sh | | mon | tasks... ---------- --------- --------- ------ ------- ---------------------------- -------------- ----- ---------- -------- | | | | fsm | | | | | | | | | env | -------------- | | | | | | | | ------------------ | | stream | | mem | | | | | | | | | -------------------------------------- | | | | | devices | | | | | ------------------------------------------------- ---------- -------- --------- ------- ----------- ---------- | video | | par | | spooler | | serial | devices... --------- ------- ----------- ---------- Fig.1: General OS structure. The devices and tasks make up the features of the system, while the kernel provides communications. (fsm =3D filesystem manager, env =3D environment handling, task switcher) In addition to executing code within the task, tasks also need to execute to communicate with other tasks or components of the OS. To communicate between tasks, a send/receive interface is provided. Using a rendezvous technique (the sender blocks till the message can directly be copied to the receiver and vice versa) the mechanism is kept simple, as no buffering is involved. Semaphores can be used for synchronization between different tasks. Data streams are used to pass data between tasks, and even between tasks and devices. Each task has a standard input, output, and error streams opened upon creation, analogous to the stream in UNIX systems. The shell can even redirect or pipe the output. @(A): Program examples The shell is a good example to show some of the capabilities of the system. As already mentioned, each task has three specially assigned streams. Filesystem tasks don't use them (and have them set to an ignored= stream), but shells normally get started with these streams connected to a terminal device or a serial line device. The streams are normally opened by the task that `forks' the new task. On boot, the ROM contains some hints about which device number to open for a program. When= a new task is started with a shell command, the shell has to open the devices. Normally the standard input and output streams used by the shell itself are registered for the new task. However, if given on the command line, other files can be opened and the streams for these files used as stdio streams. When a file has to be opened, an OPEN message is sent to the filesystem manager. This part of the kernel translates the drive number and forwards= the message to the filesystem task. The filesystem then tries to open the= file and sends a reply message. The originating task provides a stream number with its first message. If the filesystem task succeeds in opening the file, it uses the provided stream to read or write the data to. If the file ends, the writing task closes the stream, which is recognized by the other end when there's nothing more to read. This works for read only and write only opens, but not for read/write opens. @(A): Problems Bootstrapping was the first major problem. How do you start a new computer and debug its OS if don't have an OS on the computer? From earlier systems I already had a small monitor program - directly burned into an EPROM - able to load binaries through a serial line. Getting the MMU (74ls610) was the second problem, because it was on the CoCom list, and it was not allowed to export to eastern countries. (Although I don't live in an eastern country, this posed some difficulties...) After defining the necessary interfaces between kernel and tasks and kernel and devices, the design was quite straightforward, actually. One problem was the small number of registers in the 6502. For some of the kernel routines, as well as for the send/receive interface it was necessary to define a special buffer. This buffer is at an absolute address at $02XX, which is the same for each task. For systems with an MMU, this is not a problem after all. But it showed out to be a significant problem when porting the OS to systems without MMU, like the C64 (see below). @(A): Operation without an MMU After the system worked well with an MMU, I decided to build a stripped down version for systems without an MMU to better fit some `embedded applications' I had in mind. The system without an MMU is much more a multithreading than a multitasking system. Threads, as opposed to tasks, share the same memory, thus being able to change variables and data of other threads. But, on the other hand, two identical programs cannot run at the same time as with an MMU, unless they know they will together ahead of time. The problem lies within the limited stack size of the 6502. Without an MMU, it is not possible to remap memory pages, especially the page with the stack in it. So the stack is divided into several parts, limiting the= stack size of each thread, of course. Another problem is global, absolute= addresses - like the send/receive buffer for example. As it would be too much of a rewrite and memory wastage to give each thread its own buffer, the send/receive buffer is now protected by a semaphore. A sempahore is a= construct that allows exactly one thread to be in a certain routine or manipulate the protected data at a time. Semaphores originate from the railways, where it is important not to have two trains on the same rail, running in opposite directions... @(A): Port to the C64 In addition to lacking an MMU, the Commodore 64 posed other porting problems. Only small changes had to be made to the kernel. The C64 kernel required an interrupt source for task switching. The video device had to be changed to support the C64 keyboard map and video interface. The hardware cursor used in my homebrew computer was replaced by a software cursor. The IEEE488 filesystem was first ported to the IEEE488 interface for the C64 and then to the C64 serial port. When stress testing the system I realized that I still hadn't ported the STDIO library - a few low level subroutines that make life easier. The library was mapped to most tasks and was called from the task environment, not from inside the kernel. Unfortunately, it used global variables - which broke the library when running on a multithreaded system without an MMU. Therefore, some routines have been changed, while others can only be protected by a semaphore. @(A): Port to the C128? Well, the C128 has more memory and even the capability of remapping the stack and zero page to other locations. In a simple expansion of the C64 version, this could be a way to raise the limited stack size to the full possible 256 bytes. Then, other ideas come to mind. The original memory management is made for a system with MMU and is quite useless without an MMU. What is missing is a call to get a contiguous memory block of more than a memory page in size. Then such a large block could be allocated for a new task to load the binary. The binary itself must then be relocated to fit the new address range. Unfortunately, plans to extend the system calls or add relocation capabilities do not exist at this time. @(A): Conclusion The OS/A65 operating system provides multitasking and multithreading capabilities with a modern kernel design for a 6502 CPU. The OS can be used from embedded applications to desktop systems. A shell provides modern I/O redirection and piping capabilities. Filesystems for Commodore= disk drives and PC-style floppies are available. For me, it was a real adventure to design a completely new computer and operating system the way I wanted them designed. I also learned a lot about operating system design - maybe you have learned a bit as well. If you are interested in it, more information is available at: http://www.tu-chemnitz.de/~fachat. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D @(#)usenet: UseNuggets COMP.SYS.CBM: The breeding ground of programmers and users alike. Let's see what topics are showing up this month: @(A): Let's Poll Together Throughout the past few months, Paul Allen Panks has been conducting a poll on Commodore Business Machines' greatest success stories and most momentous flops. Although some biased opinions exist, many have agreed that the C64 was a success, while the 264 series (Plus/4 and C16) was a flop. After that, however, and few agree. @(A): Ymodem vs. FX, Round -1 The many people who use Craig Bruce's ACE environment know that he recent= ly added support for a special transfer protocol, FX. Proprietary in nature= , FX supports very large buffer sizes and can achieve throughput of 200% or more over standard protocols like Ymodem or Xmodem. The downside of FX is the necessity of compiling an FX "server" on a UNIX host in order to utilize the protocol. While not newsworthy in itself, a discussion about which standard protocols are fastest kicked up some dust. Many were inquiring about DesTerm support for Zmodem, causing Ismael Cordeiro to note that the DesTerm protocol implementors chose to optimize existing protocols rather than introduce new ones. A lively debate started, as Craig Bruce noted that even the fastest implementations of Ymodem were no match for FX. Ismael countered by calling the comparison unfair. Ismael noted the drawbacks of FX being proprietary and not available for all Commodore users. Also, Ismael explained the reasons for FX's increase in throughput over standard protocols. Packet size was a large factor, as FX uses a much larger buffer size. However, FX suffers when retransmissions are necessa= ry, since the time between handshakes (which occur between packets) is much longer. When using a comparable packet size, FX and Ymodem are competitive. @(A): Operating System Support In last issue's USENuggets, we discussed the conversations stemming from = the proliferation of operating system ideas on comp.sys.cbm. (C=3DH#12, Reference: usenet) We noted that many expressed a need for programmers to support the ACE computing environment, written by Craig Bruce. Upon noticing this, Craig responded: "I, of course, support the idea of other people building more applications for the ACE environment. I also support the idea of using ACE applications with other operating systems. ACE was built on the idea of providing a well-defined Application-Program Interface (API), and any alternative OS that can emulate the ACE interface (usin= g a "middle-ware" layer of software) can run all of the existing ACE applications. Thus, a new operating system can have a base of (a few) high-quality programs available instantly (high-enough quality that ev= en _I_ use them). Admittedly, I have to update the documentation on the ACE API, since it changed in Release #15, but the basic functionality will always be the same. In addition, I also support the idea of other people using ACE code inside of their own operating systems. Why re-invent the wheel? Especially useful may be the dynamic-memory stuff and some device drivers. ACE is Public Domain software, so you can do with it whatever you please." @(A): The "More Power" Swiftlink (An Update) As well, Craig followed up to our story last issue on the "hacked" Swiftlink that could do 115,200 bps. (C=3DH #12, Reference: usenet) Craig noted that ACE #15 supports the modified Swiftlink and that the code in ACE handles the new speeds "flawlessly". @(A): And Speaking of Operating Systems... Since the last issue of Commodore Hacking, at least two more operating systems have been announced. One, OS/A65, is detailed in this issue of Commodore Hacking (Reference: os). Another, called COMMIX 2, will encompass an object oriented operating system. The system is comprised of multiple sub parts, including: Networked X Input/Output (nXIO), the communications sub system COMMIX Object Format (CXOF), an object and code description format nXIOtee, the object oriented programming language. For more information on this networked OS design, check out its WWW site at: http://www.cynapses.com/ry/cx2/cx2home.html =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D @(#)uqwk: Using UQWK with QWKRR128 by Gaelyne R. Moranec (gaelyne@cris.com) @(A): Introduction One of my first priorities when joining an Internet service was to find a way to utilize the QWKRR128 offline mail and news reader to read Internet email and USENET newsgroups. Like all QWK offline readers, QWKRR128 is commonly used with Bulletin Board Systems (BBS). A user dials into a BBS, selects which groups and what email to download. The BBS program then gathers and compresses the user's requested messages int= o a file called a QWK packet. The user downloads the resulting packet, and then runs QWKR128 or some other QWK reader on the packet. Thus, users can read email and news offline and reduce connect time. Replies are also handled in much the same way, allowing the user to read and reply to messages without tying up the phone. What happens when we replace the BBS with the Internet? Well, for a while, making the switch meant shelving QWK offline readers. However, as with all problems that occur on the Internet, this deficiency was soon remedied by Steve Belzack, who wrote the Unix QWK system, called UQWK. It allows Internet users to package up Internet email and USENET newsgroups into QWK packets for use with QWK readers like QWKR128. Like its BBS counterpart, UQWK also handles reply packets from the QWK reader. @(A): Finding UQWK You can find out if your system already has UQWK by typing any of the following - if one command doesn't work try the next one. where uqwk whereis uqwk which uqwk find uqwk If your system has UQWK installed, DON'T run the program until after you've read the manual for it. UQWK requires command line switches to work and defaults to emptying your mail box, which isn't nice. To read the manual, type: man uqwk It's a good idea to create a text file in your home directory with the manual so you can download, print, and review it offline. The command to do this is: man uqwk >> uqwk.manual Then, to read it you type: more uqwk.manual To download it with Ymodem, the command is: sb uqwk.manual If your system doesn't already have UQWK available, you may be able to get the file and compile it for your personal use. Because there are so many versions of Unix to deal with, I cannot help you with compiling it for use on your system. If in doubt, give the file to your system administrator and ask him or her to install it. The FTP site is: gte.com Directory: /pub/uqwk/uqwk1.8.tar.Z Be sure to get both UQWK and the README file. The text file will tell you step by step how to set it up on your account. @(A): Using UQWK I use two Unix script files when I use UQWK, named "getmail.script" and "sendmail.script". I keep these text files in my home directory. I had to change the permissions on them so Unix would see them as "executable" files. The command for this is: chmod +x filename or chmod 700 filename You will need to make changes in the files so that they represent the BBSID used on your system. For instance, CRISINET is the BBSID on my system and is used in the examples below. When you use the getmail.script the first time, just use an arbitrary name for the name of the .qwk packet, but change your script after you know the correct BBSID to use. Be sure to use proper upper or lower case *exactly* as it appears in your control.dat file for any references to your .REP and .msg files. This may not always work, however, as it depends on your terminal program. Some CBM term programs will maintain the same casing as is used by PETSCII, while others will convert them to ASCII. If yours changes the filename, be sure to change the appropriate lines in your script files so UQWK and other utilities can find it. @(A): Scripts To Get You Started # ---------------- # getmail.script # rm crisinet.qwk uqwk +r +m +n +e arc a crisinet.qwk *.dat *.ndx sb crisinet.qwk rm messages.dat *.ndx # ---------------- Notes: rm crisinet.qwk - This removes any previously created .qwk packet. it is in lower case, as since we name this file ourselves, there's no need to make it uppercase. =09 uqwk +r +m +n +e - The command to tell UQWK what you want it to do. +r keeps UQWK from deleting your Email and marking your newsgroup messages as read. +m process Email. +n process newsgroups +e tells it to create a control.dat file listing ONLY those subscribed newsgroups. * Also you can use -m or -n so UQWK won't process * mail or newsgroups. UQWK defaults to doing * Email, but not newsgroups. (+m and -not) * The +e switch is a must for QWKRR users, as * this list gets loaded into memory and reduces * the amount available for reading messages. arc a crisinet.qwk *.dat *.ndx - This creates an ARC archive of the files UQWK has created. QWKRR users don't need to include the *.ndx files, but it's included here for those who use other offline mail readers. ... Heathens! :-) As mentioned previously, although the BBSID is "CRISINET", since we are creating the archived file, we can leave it in lower case for our own convenience. sb crisinet.qwk - This begins a Ymodem download of your QWK packet. Y= ou have to start the transfer with your terminal program manually. rm messages.dat *.ndx - This removes the messages.dat and *.ndx files from your directory. If you have sensitive Email you don't wish others to view, this prevents anyone from reading it. # ---------------- # sendmail.script # rb unzip CRISINET.rep uqwk -m -n -Rcrisinet.msg rm CRISINET.rep # ---------------- Notes: rb - This begins a Ymodem upload so you can upload your Reply packet. You have to start the upload with your term program manually. unzip CRISINET.rep - If you've ipped your reply packet, this is the command to unzip it. When QWKRR creates the file= , it honours the case of the BBSID, so the filename is in upper case. uqwk -m -n -Rcrisinet.msg - This is UQWK command to process a reply packet. The -m and -m switches tell it NOT to process your Email or newsgroups in= to a new batch of mail to download. This file (crisinet.msg) is within the "REP" packet. It is lower case. rm CRISINET.rep - This deletes the .rep file from your directory. UQWK automatically deletes the *.msg file. You can also create these scripts with your term program. Either way works. When you review the UQWK manual, you'll see the commands and should be able to follow the script file and make adjustments to suit your needs. You can have UQWK create QWK packets for Email, newsgroups, or both. Also, you can have one script file that sends your replies then creates the next batch of QWK mail for you.