home | help
tnylpo(1)		     General Commands Manual		       tnylpo(1)

NAME
     tnylpo - a utility to run programs written for CP/M-80

SYNOPSIS
     tnylpo [-abnrsw] [-c (<n> | @)] [-d <drive>] [-e [h][ b<bytes> | p<pages> |
     r<addr>-<addr>  ]	:<file> ] [-f <config-file>] [-l (<n> | @)] [-o(n|y|[y,]
     <fg>,<bg> )] [-t (<n> | @)] [-v <level>] [-y (n  |  <count>,<nanoseconds>)]
     [-z{a|e|i|n|s|x}] <command> [<arg> ...]

     tnylpo -h

DESCRIPTION
     tnylpo  allows  the execution of programs written for the CP/M-80 operating
     system in a Unix environment. To accomplish this task, tnylpo  combines  an
     emulation	of the Zilog Z80 eight-bit CPU with a software layer translating
     calls to the CP/M application programming	interface  (the  BDOS  and  BIOS
     calls  of	CP/M-80 version 2.2 plus a few BDOS calls of CP/M 3) to Unix li-
     brary and system calls.

     tnylpo doesn't even try to re-create the look-and-feel of the CP/M-80 oper-
     ating system by emulating its Console Command Processor (CCP) or  providing
     implementations  of  utility programs like PIP or STAT; in fact, its aim is
     to integrate CP/M-80 applications and compilers as much  as  possible  into
     the  Unix command line interface to allow their use in combination with the
     much more capable utilities and  editors  of  the	host  operating  system;
     tnylpo  users are supposed to use cp(1) and dd(1) instead of PIP, chmod(1),
     df(1), and ls(1) instead of STAT, and shell  scripts,  here-documents,  and
     redirections instead of SUBMIT and XSUB.

     Files in the CP/M environment are directly mapped to Unix files; while this
     comes  at	the cost of some minor incompatibilities with CP/M-80 (see below
     under NOTES), it vastly simplifies the interaction between  CP/M  and  Unix
     programs compared to the alternative approach of using disk images.

     Thanks  to  its  system call translation layer, tnylpo neither contains any
     code from the CP/M operating system nor needs any additional software apart
     from the actual applications it is meant to run.

     Since CP/M-80 programs can use eight-bit characters at best (many	of  them
     even  share  the  firm  belief of CP/M in a seven-bit ASCII world), another
     translation layer mediates between the internal one-byte-per-character text
     representation and the almost universal multibyte character (most	commonly
     UTF-8  based) approach of contemporary Unix systems. This translation layer
     affects the character orientated I/O channels of CP/M only and may be  dis-
     abled for the printer, punch, and reader devices.

     All  screen-orientated CP/M-80 programs are unable to cope with the ability
     of graphical user interfaces to resize text  windows  (in	fact,  even  the
     ability of the DEC VT100 to switch between 80 and 132 column mode overtaxes
     them);  to alleviate this problem (and to provide the capability of running
     the same CP/M application on different terminal  emulations  or  on  serial
     terminals	without  reconfiguring	the  CP/M  binaries),  tnylpo includes a
     curses based emulation of the DEC VT52 terminal (with certain extensions in
     functionality) for use as CP/M console device. tnylpo gives  the  user  the
     choice between this terminal emulation and a line orientated console device
     more suitable for programs like assemblers and compilers.

     True  to its aim of allowing the integration of CP/M programs into the Unix
     environment, tnylpo happily does away with  certain  non-essential,  rarely
     used,  or	extremely  un-Unixy  features  of CP/M-80 (some of which --to be
     frank-- would be disproportionately hard to implement  or	integrate  under
     Unix),  among them user areas, the rudimentary character device redirection
     implemented by the  I/O  byte,  file  attributes,	and  the  printer  echo.
     Whereever	some functionality has been left out, care has been taken not to
     offend CP/M programs unduly (programs may e.g. set the user  area,  and  on
     query tnylpo will report the current value back to them, but will ignore it
     otherwise). As a rule, tnylpo or Unix offer better solutions to replace the
     omitted CP/M features, e.g. different tnylpo configurations (and drives/di-
     rectories)  for  different applications or users (user areas), shell output
     redirection (I/O byte), chmod(1) (file attributes), or  script(1)	(console
     protocol).

   CPU emulation
     tnylpo  strives to provide a full implementation of both documented and un-
     documented features of the Z80 CPU; undocumented instructions and side  ef-
     fects are supported to the best of the author's knowledge.

     I/O  instructions	are available, but are dummies; writing to I/O ports has
     no direct effect, and reading them always returns a  null	byte.	Same  is
     true  for	all  interrupt related instructions (while the I register may be
     set and read and the EI and DI instructions have the expected side effects,
     no interrupt will ever occur).  Executing a HALT instruction will end  pro-
     gram  execution  (and thereby the execution of tnylpo) and is considered an
     error situation (see below under Program  termination).  Well-behaved  CP/M
     applications should never use any of these instructions anyway.

     Note  that  the  behaviour of the HALT instruction has changed from earlier
     versions of tnylpo, where it was simply ignored (resp. acted as  if  a  NMI
     had  been received immediately after entering the halt state).  This change
     allows unused memory areas to be initialized with HALT instructions,  which
     increases	the chances of detecting and stopping a runaway application pro-
     gram early.

     The R register will be increased as expected;  since  application	programs
     may  use  the  current value of the R register for the generation of random
     numbers (the Randomize procedure of Turbo Pascal seems to do this),  the  R
     register  is  initialized	with a random value (otherwise, repeated runs of
     the same program would always generate the same  sequence	of  random  num-
     bers).

     At  the start of program execution, all unused memory (i.e. the part of the
     TPA not occupied by the loaded executable as well as the  unused  parts  of
     the  zero	page and the BIOS area) are initialized with the byte value 0x76
     (the HALT instruction).  All registers apart from PC, SP, and R are set  to
     zero,  PC	is set to 0x100, and SP points to a stack area at the top of the
     TPA.

   File name translation
     In translating CP/M disk operations to Unix disk operations, tnylpo has  to
     translate	CP/M file names to Unix file names and vice versa; since CP/M de
     facto allows almost arbitrary seven-bit characters in its file  names  (in-
     cluding  null  bytes and slashes), and Unix file names are not bound to the
     8+3 character restriction of CP/M, tnylpo enforces a  common  subset:  only
     decimal digits, the 26 letters of the alphabet, the minus (-), at (@), dol-
     lar ($), and hash (#) signs are allowed in file names, which are restricted
     to  one to eight characters in length. The name may have an extension of up
     to three characters from the same set; the dot between name  and  extension
     may  only	be present if there is at least one extension character.  On the
     Unix side, all letters appear in lower case, while tnylpo accepts (and  re-
     turns) only upper case letters in CP/M FCBs. Unix files with names contain-
     ing upper case letters or otherwise not conforming to tnylpo's restrictions
     are not accessible to CP/M programs. (Dollar signs in Unix file names are a
     nuisance  in shell scripts, but since they are habitually used in CP/M tem-
     porary file names, tnylpo could not forbid them; fortunately, CP/M programs
     creating files with file names containing dollar signs usually remove  them
     before exiting.)

OPTIONS
     Many  of  tnylpo's  command  line options have corresponding entries in the
     configuration file, so they will be discussed in this  context  below  (see
     Configuration options).  Four options have no counterparts:

     -a     selects  the alternate character set from the configuration file be-
	    fore starting execution (see Character sets).

     -e [h][b<bytes>|p<pages>|r[<addr>]-<addr>]:<filename>
	    causes tnylpo to write (parts of) the CP/M memory to  the  specified
	    file after program termination (see Saving a memory image).

     -f <config-file>
	    tells tnylpo to read its configuration from the named file.

     -h     asks tnylpo to show a short command line synopsis (-h cannot be used
	    in combination with any other command line option).

   Command line arguments
     tnylpo interprets its first positional command line argument as the name of
     the  CP/M	program (.com file) it is supposed to execute.	If this argument
     contains a slash (/), it is interpreted as a Unix path name,  otherwise  it
     is treated as a CP/M file name, i.e. it may be prefixed by a drive specifi-
     cation  and  is  interpreted  as relative to the path corresponding to this
     drive or the default drive according to tnylpo's configuration (see below).
     In both cases, the suffix .com is appended if the file name  does	not  al-
     ready end in .com.

     All  further  positional  arguments are passed as command line arguments to
     the CP/M program (i.e. they are converted to upper case and copied  to  the
     default DMA area at 0x0080; additionally, the default FCB at 0x005c is ini-
     tialized according to the second and third positional arguments).

   Configuration files
     While  some  features  of tnylpo can be controlled by command line options,
     the most convenient way to configure it is by using a  configuration  file;
     if a configuration file is explicitly specified on the command line (option
     -f), it will be used; otherwise, tnylpo looks for a file named .tnylpo.conf
     in  the  current  working	directory.  If	none  is found, tnylpo looks for
     .tnylpo.conf in the user's home directory. As a last  resort,  tnylpo  uses
     its built-in defaults. If conflicting options are specified in the configu-
     ration file and on the command line, the command line takes precedence.

     A	tnylpo	configuration file is a regular text file; empty lines and lines
     starting with a hash sign (#) or a semicolon (;)  are  ignored.  All  other
     lines have the form

	    <keyword> [<token> ...]  = <token> [<token> ...]

     <token> is either a keyword (a sequence of alphanumeric characters starting
     with  a  letter),	a  number (hexadecimal, octal or decimal using the usual
     Unix convention of being prefixed by 0x, 0,  resp.  some  other  digit),  a
     string in double quotes, or a comma.

   Configuration options
     drive <drive letter> = [readonly ,] <path>

	    Up to 16 drives can be defined by repeated use of this configuration
	    option;  <drive  letter>  is a single lower case letter in the range
	    a-p, and <path> is a string containing the name of	a  directory  on
	    the host computer system. CP/M programs trying to create or access a
	    file on the corresponding disk drive will create or access a file in
	    this  directory.   Only  regular  files up to 8MB in size with names
	    corresponding to tnylpo's idea of well-behaved file  names	suitable
	    for  both CP/M and Unix (see above) are visible to CP/M programs. If
	    <path> is preceeded by the optional keyword readonly, programs  run-
	    ning on tnylpo will not be able to create new files on this drive or
	    rename,  delete,  or  modify existing files (any attempt to modify a
	    read-only drive will terminate the offending CP/M program).

	    There is no corresponding command line option. If no drive has  been
	    defined  in  the configuration file (or if there is no configuration
	    file), tnylpo will use

		   drive a = "."

	    as default, i.e. the current working directory will be  made  avail-
	    able as CP/M drive A.

     default drive = <drive letter>
     command line option -d <drive letter>

	    define  the  drive identified by <drive letter> (a single lower case
	    letter in the range a-p) as default drive, i.e.  the drive all  file
	    specifications  not  including an explicit drive name refer to. This
	    drive must be assigned to a host system directory, either implicitly
	    or by the drive configuration option. If default drive is not speci-
	    fied, tnylpo assumes drive A as default drive.

     close files = (true | false)
     command line option -n

	    If close files is set to false (or if the -n command line option  is
	    present),  files closed by the CP/M program are kept open by tnylpo,
	    i.e. the corresponding FCBs are not invalidated. This is required by
	    some CP/M programs (see File closing), but should be avoided if pos-
	    sible, since otherwise tnylpo might run out of file descriptors.  By
	    default, tnylpo actually closes files closed by the CP/M program.

     logfile = <path>

	    <path>  is	a  quoted  string containing the path of a file to which
	    tnylpo appends error messages and other logging  information  (fatal
	    error messages are also written to stderr).  If the logfile configu-
	    ration  option  is not used, no logging information will be written.
	    There is no corresponding command line option.

     loglevel = <level>
     command line option -v <level>

	    The amount of data written to  the	logfile  is  controlled  by  the
	    loglevel  configuration option resp. its command line equivalent -v.
	    Both take a numeric argument; the higher the number, the more infor-
	    mation is  written	(causing  the  emulation  to  run  progressively
	    slower).  Valid log levels are:

	    0	   write error messages only.

	    1	   additionally,  count the machine instructions executed by the
		   emulator; at program termination, tnylpo will  output  tables
		   showing which instructions have been executed how often.

	    2	   additionally,  trace  FDOS functions (i.e. BDOS functions re-
		   lated to file I/O).

	    3	   additionally, dump FCBs for FDOS functions using a FCB.

	    4	   additionally, dump file records read and written by the  FDOS
		   functions.

	    5	   additionally,  trace  all  other  system calls (BDOS and BIOS
		   functions); since all character  I/O  functions  are  traced,
		   this will produce a lot of output.

	    The  logging facility is a leftover from the development and testing
	    of tnylpo itself; since it may provide important clues  if	applica-
	    tions do not work as expected, it has been retained.

     console = (full | line)
     command line options -s or -b

	    tell  tnylpo to use the full screen VT52 emulation (full, -s) or the
	    line orientated (line, -b) console interface. Some other  configura-
	    tion  options,  e.g.  lines, columns, application cursor, and screen
	    delay are only effective in the full screen mode. By default, tnylpo
	    uses the line orientated console interface.

     screen delay = (<number> | key)
     command line option -t (<number> | @)

	    define the number of seconds tnylpo should wait between program ter-
	    mination and resetting the display. If key (resp.  @) is  specified,
	    tnylpo  waits for a key being pressed before exiting the VT52 emula-
	    tion. This option allows the user to see the final	display  of  the
	    CP/M application even if resetting the display restores the original
	    screen  contents  or  clears  the  screen. Default value is 0 (don't
	    wait).

     lines = (<number> | current)
     columns = (<number> | current)
     command line options -l (<number> | @) and -c (<number> | @)

	    define the display size used by the terminal emulation;  the  number
	    of	lines must be between 5 and 95, the number of columns between 20
	    and 95.  Using the keyword current (resp.  @ in case of the  command
	    line  options)  tells  tnylpo to use the current size of the display
	    device. If no display size is specified in the configuration file or
	    on the command line, tnylpo defaults to 24 lines of 80 columns.

     application cursor = (true | false)
     command line option -w

	    If application cursor is set to true (or the command line option  -w
	    is	present), pressing the cursor keys up, left, right, or down will
	    send the control characters ^E (0x05), ^S (0x13), ^D (0x04),  or  ^X
	    (0x18)  to the running CP/M program (i.e. the appropriate cursor mo-
	    tion commands for programs like WordStar or  Turbo	Pascal).  Other-
	    wise,  the	cursor	keys  will  generate the default VT52 escape se-
	    quences, <esc> A, <esc> D, <esc> C, and <esc>  B.	This  option  is
	    only effective in full screen console mode.

     exchange delete = (true | false)
     command line option -r

	    If	exchange delete is set to true (or the command line option -r is
	    present), the backspace (^H, 0x08) key and the delete (0x7f) key are
	    reversed in full screen mode.

     [alt] char <number> = <string>
     [alt] charset = (ascii | vt52 | latin1 | tnylpo)
     unprintable = <string>

	    serve to define the primary and alternate  character  sets	used  by
	    tnylpo;  they have no corresponding command line options and are ex-
	    plained below (see Character sets).

     (printer | punch | reader) file = <path>
     (printer | punch | reader) mode = (text | raw)

	    define the path and the format of the data	files  representing  the
	    CP/M character I/O devices LST:, PUN:, and RDR:; there are no corre-
	    sponding  command  line  options.  Details	are explained below (see
	    Character devices).

     colors = ( false | true ) [ , <fg> , <bg> ]
     command line options -on, -oy, -oy,<fg>,<bg> and -o<fg>,<bg>

	    switch color support on or off in full screen mode; optionally,  the
	    default foreground and background colors (digits in the range from 0
	    to 7) may be selected (see Color support).

     cpu delay = <count> , <nanoseconds>
     command line options -yn and -y<count>,<nanoseconds>

	    slow  down	the  emulation by adding a delay (specified by <nanosec-
	    onds>) after every <count> instructions  executed  by  the	emulated
	    CPU.  The  command line option -yn disables this delay, overriding a
	    delay specified in the configuration file. Slowing the emulation al-
	    lows using software (e.g. interactive games) which	would  otherwise
	    run  much  too  fast  on tnylpo; another application is reducing the
	    high load tnylpo puts on the host CPU.

	    Useful values for <count> and <nanoseconds> depend on the  speed  of
	    the  host  CPU,  on the host operating system, and on the particular
	    application program; they need to be determined by	experimentation.
	    Please  bear in mind that the minimal useful delay (i.e. the minimal
	    value for <nanoseconds>) depends on the host  operating  system  and
	    may be as large as several milliseconds; since smaller delays may be
	    rounded  up  to  that minimum implicitly, specifying e.g.  -y1,1 may
	    give unexpected results.

     dump = none
     dump = all
     dump = (startup | exit | error | signal) [, ...]
     command line options -zn, -za, and -z{s|x|e|i}

	    define if and when tnylpo writes a machine dump (including	register
	    values  and  the contents of main memory) to the log file.	The key-
	    words startup, exit, error, and signal (resp. the suboptions  s,  x,
	    e,	and  i)  request  a  dump at program startup (immediately before
	    passing control to the CP/M command), at program  exit,  at  program
	    exit  due to a fatal execution error, or at the receipt of a SIGUSR1
	    signal and may be arbitrarily combined (only exit and error are  mu-
	    tually  exclusive).  dump = all (resp.  -za) is a shorthand for dump
	    = startup, exit, signal (resp.  -zsxi), and dump = none (resp.  -zn)
	    turns all dumps off (this is also the default  setting).  Dumps  are
	    only written if a log file has been defined by the configuration op-
	    tion logfile.

   Terminal emulation
     tnylpo  provides  a  curses based emulation of the DEC VT52 terminal, which
     can be used instead of the default line orientated console  to  accommodate
     full-screen  applications;  this terminal emulation is selected by the com-
     mand line option -s resp. by the entry console = full in the  configuration
     file.

     tnylpo's  terminal emulation mimicks the VT52 fairly accurately, but offers
     a number of extensions, among them the ability to support screen  sizes  of
     up to 95 by 95 characters (this limitation is due to the limitations of the
     VT52 direct cursor positioning command), eight-bit operation, a dynamically
     switchable  alternate  character  set, insert and delete line commands, and
     bold, underlined, inverted, and blinking (i.e. everybody's favourite) char-
     acter rendition. To protect the CP/M application (resp. its user) from  the
     effects  of  screen  resizing, the terminal emulation provides a fixed size
     screen area (typically 80 columns by 24 lines, but this may be  changed  by
     command  line  or	configuration file options) within the actual display (a
     terminal emulator like xterm(1) or the screen of an  actual  serial  termi-
     nal).  If the display device/window is larger than this area, there will be
     blank margins to the right and below  the	VT52  display  area;  if  it  is
     smaller,  parts  of  the  output from the emulator will be invisible to the
     user, but will (re-)appear as soon as the window is enlarged.

     The terminal emulation (like the VT52) does not do an automatic  line  wrap
     (i.e.  the  cursor  will not move to the first column of the next line if a
     character is displayed in the last column of a line) and  supports  (or  at
     least tolerates) all of the VT52 control sequences:

     <bel> (0x07)
	    gives an accustic (or visual) signal.

     <bs> (0x08)
	    moves the cursor left, but stops at column 1.

     <tab> (0x09)
	    moves the cursor to the next tabulator stop if it is before the last
	    tabulator  stop  on the current line (tabulator stops are at columns
	    9, 17, 25, ...); otherwise, it moves the cursor one  column  to  the
	    right (resp.  does nothing if the cursor is already in the last col-
	    umn).

     <lf> (0x0a)
	    moves the cursor down one line and scrolls up on bottom line.

     <cr> (0x0d)
	    moves the cursor to the first column of the current line.

     <esc> (0x1b)
	    marks the start of an escape sequence (see below).

     All other characters in the ASCII control character range (0x00-0x1f, 0x7f)
     are ignored. The VT52 escape sequences are:

     <esc> ) (0x1b 0x29) and <esc> = (0x1b 0x3d)
	    switch the keypad to application resp. to regular (numeric) mode (no
	    effect in tnylpo).

     <esc> A (0x1b 0x41)
	    moves the cursor up one line, but stops at the top line.

     <esc> B (0x1b 0x42)
	    moves the cursor down one line, but stops at the bottom line.

     <esc> C (0x1b 0x43)
	    moves the cursor right one column, but stops at the last column.

     <esc> D (0x1b 0x44)
	    moves the cursor left one column, but stops at the first column.

     <esc> F (0x1b 0x46) and <esc> G (0x1b 0x47)
	    display  character codes 0x5e-0x7e as graphical resp. as ASCII char-
	    acters (see below).

     <esc> H (0x1b 0x48)
	    moves the cursor to the left top corner of the display.

     <esc> I (0x1b 0x49)
	    moves the cursor up one line and scrolls down at the first line.

     <esc> J (0x1b 0x4a)
	    clears the display from the current cursor position to  the  end  of
	    the screen.

     <esc> K (0x1b 0x4b)
	    clears  the  display  from the current cursor position to the end of
	    the line.

     <esc> Y <line> <column> (0x1b 0x59 0xYY 0xXX)
	    moves the cursor to the specified position on the display; line  and
	    column  numbers  are  given  as graphical characters in the range of
	    0x20 (position 1) to 0x7e (position 95). If  the  column  number  is
	    larger  than  the  display	width,	the  horizontal  position is not
	    changed; a line number larger than the height of the  display  moves
	    the cursor to the last line.

     <esc> Z (0x1b 0x5a)
	    identifies	the  terminal  type;  the terminal emulation responds by
	    sending the sequence <esc> / K (0x1b 0x2f 0x4b), i.e. it  identifies
	    itself as VT52 without hardcopy device.

     <esc> [ (0x1b 0x5b) and <esc> \ (0x1b 0x5c)
	    enter resp. exit "hold screen" mode (see below).

     In addition, the terminal emulation in tnylpo supports the following exten-
     sions to the VT52 escape sequences:

     <esc> E (0x1b 0x45)
	    clears  the  display, moves the cursor to the top left corner of the
	    display.

     <esc> L (0x1b 0x4c)
	    inserts a blank line at the cursor position and  moves  lines  below
	    down one line (the last line is lost).

     <esc> M (0x1b 0x4d)
	    deletes the line at the cursor position and moves lines below up one
	    line (an empty line will appear at the bottom of the display).

     <esc> N (0x1b 0x4e)
	    inserts  a	blank character at the cursor position and moves charac-
	    ters to the right one position to the right (the last  character  on
	    the line is lost).

     <esc> O (0x1b 0x4f)
	    deletes  the  character at the cursor position and	moves characters
	    to the right one position to the left (a blank character appears  in
	    the last column of the line).

     <esc> S <color> (0x1b 0x53 0xCC)
	    sets the background color of subsequent output characters; the color
	    code is described below (Color support).

     <esc> T <color> (0x1b 0x54 0xCC)
	    sets the foreground color of subsequent output characters; the color
	    code is described below (Color support).

     <esc> a (0x1b 0x61) and <esc> b (0x1b 0x62)
	    make the cursor invisible resp. visible.

     <esc> c (0x1b 0x63) and <esc> d (0x1b 0x64)
	    switch  to the alternate resp. to the primary character set (see be-
	    low).

     <esc> e (0x1b 0x65) and <esc> f (0x1b 0x66)
	    switch on resp. off bold characters.

     <esc> g (0x1b 0x67) and <esc> h (0x1b 0x68)
	    switch on resp. off underlined characters.

     <esc> i (0x1b 0x69) and <esc> j (0x1b 0x6a)
	    switch on resp. off inverted characters.

     <esc> k (0x1b 0x6a) and <esc> l (0x1b 0x6c)
	    switch on (arrgh!) resp. off (phew!) blinking characters.

     <esc> m (0x1b 0x6d)
	    switches off bold, underlined, blinking, and inverted characters  as
	    well  as  standout mode (see below); resets the foreground and back-
	    ground colors to their defaults.

     <esc> n (0x1b 0x6e) and <esc> o (0x1b 0x6f)
	    switch the cursor keys to application mode	resp.  back  to  regular
	    (VT52)  mode:  in  regular	mode, the cursor keys send the sequences
	    <esc> A (up), <esc> B (down), <esc> C (right), and <esc>  D  (left);
	    in	application mode, they send WordStar-compatible commands, namely
	    ^E (0x05, up), ^X (0x18, down), ^D	(0x04,	right),  and  ^S  (0x13,
	    left).

     <esc> p (0x1b 0x70) and <esc> q (0x1b 0x71)
	    switch on resp. off standout mode; standout mode is the most visible
	    character  attribute  provided  by	curses (this is usually inverted
	    video, so using <esc> p and <esc> q is usually equivalent  to  using
	    <esc> i and <esc> j).

     "Hold screen" mode is a feature of the VT52 terminal: it is entered and ex-
     ited either by the computer sending the relevant control sequence or by the
     user  by pressing the "hold screen" key (in tnylpo, this is the F5 key). In
     "hold screen" mode, trying to scroll up the screen (by a <lf> on the bottom
     line of the screen) blocks further output until either "hold  screen"  mode
     is  exited  or the user presses the "scroll page" key (F6 in tnylpo) or the
     "scroll line" key (F7 in tnylpo), which allow one more screenfull resp. one
     more line of output.

     Displaying graphical characters instead of ASCII characters  for  the  byte
     range 0x5e-0x7e is another feature of the VT52 terminal which allows access
     to  certain  additional  shapes like subscripted digits or the +/- sign; in
     tnylpo, graphical mode allows displaying the shapes defined for the charac-
     ter positions 0x00-0x1f and 0x7f, which cannot be displayed directly.

   Character sets
     Switching between a primary and an alternate character set is an  extension
     provided  by tnylpo: two full character sets of 256 shapes (each containing
     a separate graphical character set in the positions 0x00-0x1f and 0x7f) may
     be defined in the configuration file; programs may switch between these two
     sets by using <esc> c resp.  <esc> d.   Switching	character  sets  doesn't
     change  characters already written to the display. This feature allows pro-
     grams to use e.g. a national variant of the ISO 646 seven-bit character set
     in parallel to standard ASCII characters.

     Character set definition is done in the configuration file by using the op-
     tion

	    [alt] char <number> = <string>

     which defines <string> (a one-character string literal in double quotes) as
     representation of code <number> (a number in the range 0-255) in  the  pri-
     mary  (or alternate, if the line is prefixed by alt) character set. Charac-
     ters not explicitly defined in this way are taken from a default  character
     set, which may be selected by the option

	    [alt] charset = (ascii | vt52 | latin1 | tnylpo)

     The  possible  values correspond to the four built-in character sets ASCII,
     VT52 (ASCII plus an approximation of the VT52  graphical  characters),  the
     ISO  8859-1  (Latin 1) eight-bit character set, which supplements the ASCII
     code  by  characters  used  in  Western  European	languages  in  positions
     0xa0-0xff,  and  finally a homespun superset of Windows code page 1252 (and
     thereby a superset of ISO 8859-1 and ASCII), which supports block	graphics
     and the VT100 box drawing characters  as graphical character set.

     If no character set is specified, tnylpo uses the VT52 character set by de-
     fault.

     By  using the command line option -a, a program may be started with the al-
     ternate character set selected; the effect is almost identical to the  pro-
     gram  issuing  <esc>  c as its very first action. (There is a difference in
     full screen console mode: During screen initialization, tnylpo  passes  the
     blank  character  from the selected character set to the curses library for
     use as background character. Since the program itself can select the alter-
     nate character set only after this initialization	has  been  done,  curses
     will  receive  the blank character from the primary character set; with the
     -a command line option, it will receive the blank character from the alter-
     nate character set. This difference is mostly academic,  since  it  is  not
     recommended to redefine the blank character anyway, see below.)

     Output  characters  which are undefined in the currently selected character
     set are ignored by the terminal emulation; the configuration option

	    unprintable = <string>

     substitutes undefined characters on output by the value of <string>  (which
     must contain a single character).

   Function keys
     Apart  from  F5,  F6, and F7, which are used to implement the "hold screen"
     function of the VT52 (see above), tnylpo's terminal emulation  defines  the
     function  keys F1, F2, and F3 as equivalents of the three unlabeled keys of
     a VT52 terminal; if pressed, they return the sequences <esc> P (0x1b 0x50),
     <esc> Q (0x1b 0x51), and <esc> R (0x1b 0x52). F4 causes the terminal emula-
     tion to redraw its display, which is useful if some other	program  or  the
     host  operating  system  mess  up	the user's screen. F10 sends a SIGINT to
     tnylpo, causing the emulation to stop abruptly, but allowing tnylpo  itself
     to  exit  gracefully  (this key is meant as a last-resort way of stopping a
     CP/M program gone haywire).

   Color support
     If the  underlying  software  and	display  hardware  allow  color  output,
     tnylpo's  terminal  emulation  supports  the use of eight different colors,
     which may be selected as foreground resp. background colors of subsequently
     displayed characters. These colors are identified by the following  numeric
     codes:

	    0	 black
	    1	 blue
	    2	 red
	    3	 magenta
	    4	 green
	    5	 cyan
	    6	 yellow
	    7	 white

     By  default,  color  support is disabled even on color-capable displays; it
     must be explicitly enabled either by the configuration option

	    colors = true

     or by the command line option -oy.  Both colors = true and -oy may be  fol-
     lowed  by	two comma-separated color codes, which specify the default fore-
     ground resp. background colors of tnylpo's terminal emulation, e.g.

	    colors = true, 6, 1

     (resp.  -oy,6,1) will select yellow characters on a  blue	background.  The
     default  colors  may  be  specified  in  the configuration file by colors =
     false, 6, 1 even if color support is disabled (since this may be overridden
     by -oy).  The command line option -o6,1 is a shorthand form of -oy,6,1, and
     -on may be used to override the configuration file and disable  color  sup-
     port.  If no default colors have been specified either in the configuration
     file or on the command line, tnylpo defaults to 7 and 0, i.e. to white text
     on a black background.

     Application programs may select colors  by  issuing  the  escape  sequences
     <esc>  S  <color>	and <esc> T <color> to choose the background resp. fore-
     ground colors of subsequently displayed characters;  <color>  is  either  a
     single ASCII digit in the range from 0 to 7 (0x31 to 0x37) corresponding to
     one  of  the  colors  supported by tnylpo, or the character = (0x3d), which
     will select the respective default color. To render e.g. the text	Warning!
     in red, a program may display the character sequence

	    <esc> T 2 W a r n i n g ! <esc> T =

     on the full-screen console. Both foreground and background colors will also
     be reset to their defaults by the escape sequence <esc> m, which resets all
     text  attributes.	 On monochrome devices or if color support has been dis-
     abled, <esc> S and <esc> T will still be accepted but silently ignored.

   Character devices
     Besides the bidirectional console device,	CP/M  supports	three  unidirec-
     tional  character devices, the output-only printer and paper tape punch de-
     vices LST: and PUN: and the  input-only  paper  tape  reader  device  RDR:.
     tnylpo  represents  these	devices  by host system files, to which the data
     provided by the CP/M program are written resp. from  which  the  data  pre-
     sented to the CP/M program are read.

     These files are defined by the configuration options

	    (printer | punch | reader) file = <path>

     where <path> is a string in double quotes containing the Unix file path; in
     case  of  the output devices (LST: and PUN:), data written by the CP/M pro-
     gram are appended to the contents of the named files; RDR: input will start
     at the beginning of the reader file. If a CP/M program reads past	the  end
     of  the reader file, tnylpo will continue to return ^Z (0x1a) bytes as end-
     of-file indication.

     tnylpo's character devices can operate in two modes, depending on the  con-
     figuration options

	    (printer | punch | reader) mode = (text | raw)

     In raw mode, bytes are written to the file exactly as they are generated by
     the  CP/M program resp. passed to the CP/M program exactly as they are read
     from the file (^Z bytes are still returned  as  EOF  indication).	In  text
     mode,  tnylpo  will  translate  the characters read resp. written using the
     translation table used by the console. Character set switching by the  con-
     sole  (using  the	escape	sequences  <esc> c and <esc> d) will affect this
     translation, but switching to graphical characters (<esc> F  and  <esc>  G)
     will  not.   Moreover,  tnylpo  will convert the line end markers from CP/M
     (^M^J, 0x0d 0x0a) to Unix (^J, 0x0a) and vice versa in this mode.

   Saving a memory image
     The command line option -e causes tnylpo to save parts of the  CP/M  memory
     to  a file after a regular program termination (i.e. one that is not caused
     by a fatal error or receipt of a signal); it takes as argument a string  of
     suboptions which specify the name and the format of the output file and the
     range of CP/M memory addresses to save. Possible suboptions and their para-
     meters are

     h	    causes  the  memory  contents  to be written in Intel Hex format; if
	    this option is absent, a binary file will be written.

     b<bytes>
	    selects a number of bytes (specified  as  decimal  number)	starting
	    from address 0x100.

     p<pages>
	    selects  a number of pages (units of 256 bytes, specified as decimal
	    number) starting from address 0x100.

     r[<low-addr>]-<high-addr>
	    selects a range of addresses to save (both addresses may  be  speci-
	    fied  as  octal, hexadecimal, or decimal numbers using the Unix con-
	    vention of prefixing them with 0, 0x, or any  other  digit,  respec-
	    tively);  <high-addr>  may not be less than <low-addr>, and if <low-
	    addr> is missing, 0x100 will be assumed in its place.

     :<filename>
	    specifies the Unix file to which the memory  contents  are	written;
	    this  is  mandatory  and  must  be the very last suboption (in fact,
	    everything following the first colon in the argument of the -e  com-
	    mand line option is taken as part of the file name).

     Individual suboptions resp. suboptions and their parameters may not be sep-
     arated  by  whitespace.  The three range specifications b, p, and r may not
     exceed the range of the CP/M memory space (0x0000-0xffff) and are	mutually
     exclusive; if none of them is specified, the whole TPA (starting at address
     0x100 and including the last byte before the BDOS area) is saved.

     The  command line option -e serves as a replacement for the SAVE command of
     CP/M, which is most often used to save an executable  file  after	applying
     patches  with  a  debugger (most CP/M debuggers don't provide a command for
     writing memory contents to a disk file). Invoking	tnylpo	with  the  addi-
     tional  option  -ep34:new.com  is equivalent to issuing the command SAVE 34
     NEW.COM immediately after termination of an executable under CP/M.

   Supported system calls
     This subsection gives a list of system calls  supported  by  tnylpo.  While
     there  are  some  extensions  mainly  taken from the CP/M 3 BDOS interface,
     tnylpo prioritizes compatibilty with CP/M 2.2. All unimplemented BDOS calls
     (i.e. those not listed in this section) are tolerated and	conform  to  the
     (admittedly  suboptimal) CP/M 2.2 convention of returning 0 in registers A,
     B, and HL.

	    #0	 System Reset
	    #1	 Console Input
	    #2	 Console Output
	    #3	 Reader Input
	    #4	 Punch Output
	    #5	 List Output
	    #6	 Direct Console I/O
	    #7	 Get I/O Byte (dummy)
	    #8	 Set I/O Byte (dummy)
	    #9	 Print String
	    #10  Read Console Buffer
	    #11  Get Console Status
	    #12  Return Version Number
	    #13  Reset Disk System
	    #14  Select Disk
	    #15  Open File
	    #16  Close File
	    #17  Search for First
	    #18  Search for Next
	    #19  Delete File
	    #20  Read Sequential
	    #21  Write Sequential
	    #22  Make File
	    #23  Rename File
	    #24  Return Log-In Vector
	    #25  Return Current Disk
	    #26  Set DMA Address
	    #27  Get Addr(Alloc) (dummy)
	    #28  Write Protect Disk
	    #29  Get Read-Only Vector
	    #30  Set File Attributes (dummy)
	    #31  Get Addr(Diskparams) (dummy)
	    #32  Get/Set User Code (dummy)
	    #33  Read Random
	    #34  Write Random
	    #35  Compute File Size
	    #36  Set Random Record
	    #37  Reset Drive
	    #40  Write Random with Zero Fill
	    #49  Get/Set System Control Block (CP/M 3)
	    #101 Return Directory Label Data (CP/M 3)
	    #102 Read File Date Stamps and Password Mode (CP/M 3)
	    #105 Get Date and Time (CP/M 3)
	    #108 Get/Set Program Return Code (CP/M 3)
	    #141 Delay (MP/M)

     BDOS function #49 (Get/Set System Control Block) is only  partially  imple-
     mented: Attempts to write to the SCB are silently ignored, and only the SCB
     offsets  0x05 (BDOS version number, always 0x22), 0x10-0x11 (program return
     code), 0x1a (console columns), 0x1c (console lines),  0x37  (output  delim-
     iter,  always  0x24), 0x3c-0x3d (current DMA address), 0x3e (current disk),
     0x44 (current user number), and 0x4a (current multi sector count, always 1)
     provide meaningful information (all other byte offsets return 0).

     BDOS function #102 (Read File Date Stamps and Password Mode) always returns
     the access and modification timestamps of the  underlying	Unix  file,  and
     function  #101 (Return Directory Label Data) correspondingly always returns
     a value of 0x61.

     BDOS function #141 (Delay) delays program execution for the number of  sys-
     tem  clock  ticks	passed	in register DE; tnylpo defines a tick to last 20
     milliseconds, i.e. it emulates a ticker frequency of 50 Hertz.

     In addition to the BDOS calls, tnylpo implements all  BIOS  calls	of  CP/M
     2.2, but all disk related functions are dummies:

	    BOOT      System Cold Start Initialization
	    WBOOT     Warm Start
	    CONST     Console Input Status
	    CONIN     Console Character Input
	    CONOUT    Console Character Output
	    LIST      Printer Character Output
	    PUNCH     Paper Tape Punch Output
	    READER    Paper Tape Reader Input
	    HOME      Recalibrate Disk Drive (dummy)
	    SELDSK    Select Disk Drive (dummy)
	    SETTRK    Set Track Number (dummy)
	    SETSEC    Set Sector Number (dummy)
	    SETDMA    Set DMA Address (dummy)
	    READ      Read Selected Sector (dummy)
	    WRITE     Write Selected Sector (dummy)
	    LISTST    Printer Output Status
	    SECTRAN   Sector Number Translation (dummy)

     No  additional  BIOS  calls  from CP/M 3 have been implemented, not even as
     dummies, i.e. any attempt to call them will result in undefined program be-
     haviour.

   Program termination
     tnylpo terminates as soon as the CP/M program it executes terminates by ei-
     ther calling BDOS function #0 (System Reset) or BIOS function WBOOT;  jump-
     ing  to  address 0x0000 or using the stack area set up by tnylpo and ending
     execution by a RET instruction is equivalent to calling BIOS function WBOOT
     directly. Finally, the user may terminate a program by pressing  ^C  (0x03)
     when prompted for console input by BDOS function #10 (Read Console Buffer).
     All  these forms of program termination are considered regular for the pur-
     pose of determining the exit status from tnylpo (see below, under EXIT STA-
     TUS).

     Furthermore, a CP/M program will be terminated if	it  performs  an  action
     considered  illegal by tnylpo, like executing a HALT instruction, trying to
     write to a read-only file or to a file on a disk configured  as  read-only,
     passing  invalid arguments to system calls, accessing a disk drive not con-
     figured, or requesting an illegal sequence of operations  (like  trying  to
     read from a disk file which has already been closed).

     When  the full screen console is active, a program may be terminated by the
     user pressing the F10 key (see above, "Function keys"); this is  equivalent
     to sending a SIGINT to tnylpo from another terminal/terminal window. Press-
     ing  F10  terminates  the	CP/M program abruptly and should (like sending a
     signal to tnylpo) only be used as a last resort when dealing  with  a  hung
     application.

     Both program termination due to an illegal action and terminating a program
     by pressing F10 (or sending tnylpo a signal) are considered irregular forms
     of program termination.

EXIT STATUS
     tnylpo  exits  with  status  1 if it encountered a fatal error and status 0
     otherwise. Fatal errors are command line errors, configuration file errors,
     or an irregular termination of the CP/M program (see above).

     CP/M-80 version 2.2 has no concept of a program exit status, so there is no
     well-established way of communicating an unsuccessful CP/M  program  execu-
     tion  to the Unix environment. To alleviate this deficit, tnylpo implements
     BDOS function #108 (Get/Put Program Return Code) from CP/M  3;  if  a  CP/M
     program  sets its return code to a value in the "unsuccessful return" range
     (0xff00-0xfffe) prior to termination, tnylpo will exit with status 1.

FILES
   ./.tnylpo.conf
     The file .tnylpo.conf in the current working directory is used as	configu-
     ration  file, if it is present and no configuration file has been specified
     on the command line.

   ~/.tnylpo.conf
     The file .tnylpo.conf in the user's home directory is used as a  configura-
     tion file, if it is present, if no configuration file has been specified on
     the command line, and if there is no file .tnylpo.conf in the current work-
     ing directory.

     Using  configuration informations from a file in the current working direc-
     tory (./.tnylpo.conf) is convenient in many situations, but poses a  poten-
     tial  security  risk;  mainly for this reason, tnylpo refuses to run if its
     effective user ID is 0.

NOTES
   Differences between tnylpo and CP/M-80
     By design, there are some incompatibilities between CP/M-80 and the  emula-
     tion provided by tnylpo:

   Direct access to the BDOS and BIOS areas
     Since it doesn't contain any actual CP/M code, all programs trying to patch
     the  BDOS	or  otherwise make assumptions about the layout of the operating
     system or its internal data structures will fail while running on tnylpo.

     BDOS and BIOS function emulations are activated by the simulated  processor
     executing	a RET instruction fetched from one of the uppermost 19 addresses
     of the CP/M memory space (0xffed for the BDOS entry, 0xffee to  0xfffe  for
     the 17 BIOS entries of CP/M-80 2.2 and 0xffff for one tnylpo-specific delay
     routine  hiding  as  18th	BIOS entry); this use of "magic addresses" might
     confuse debuggers trying to trace system calls.

     The BIOS area (starting three bytes before the address stored at 0x0001) is
     page-aligned and contains the 17(+1)-element BIOS jump  vector,  the  dummy
     disk  structures  (see  below) and the above mentioned 19 RET instructions.
     The BDOS area (starting at the address stored at 0x0006) is  even	shorter,
     containing  only a jump to 0xffed and the table of target addresses for the
     four fatal BDOS error conditions (non-existing disk, bad sector,  read-only
     disk, and read-only file; these addresses may be modified by an application
     program,  but  are completely ignored by tnylpo). Any program expecting the
     BDOS or the BIOS areas to have the sizes and alignment characteristics of a
     real CP/M-80 environment will be disappointed.

     The OS serial number stored in the six bytes immediately  before  the  BDOS
     area  is  always  0x00  0x16 0x00 0xc0 0xff 0xee, a (hopefully inoffensive)
     dummy indicating BDOS version 2.2.

   Direct access to the disk drives
     All programs trying to access the CP/M disk structure directly  (e.g.  disk
     editors)  will  not  work, since there is no underlying CP/M disk structure
     (tnylpo translates FDOS calls into operations on Unix files); all disk  re-
     lated  BIOS  calls  are implemented as dummy functions (those few which can
     return an error indication --SELDSK, READ, and WRITE-- will  do  so).   The
     BDOS  functions  returning disk structure related information (#27 and #31)
     will return dummy structures containing meaningless (but consistent)  data;
     for  example,  all  disk  drives will be reported as having a block size of
     16KB, 2048 directory entries and a capacity of 8MB, of  which  8128KB  (8MB
     less  four  directory blocks) are free (to save space, all drives share the
     same dummy allocation vector, which  is  of  course  impossible  with  real
     CP/M-80).	All block information returned by the BDOS functions #17 and #18
     is meaningless; regardless of the contents of the S2 field (FCB offset 14),
     all otherwise matching files are returned only once (as opposed to once per
     physical extent under CP/M-80). Likewise, all block information in the FCBs
     of open files (FCB byte offsets 16 to 31) is meaningless (but  may  not  be
     disturbed since tnylpo stores some state information there, see below). The
     emulation	is  good enough for programs searching for file name patterns or
     just listing the disk directory, but will fail for those trying to  analyse
     the block structure of the emulated disk from the returned information.

   Console Command Processor
     tnylpo  doesn't  emulate  the  CCP, so every program using its features (by
     e.g. creating a $$$.SUB file and expecting the CCP to execute its contents)
     will not work correctly. Ending a program by simply returning to the CCP is
     supported; tnylpo initializes an 8 level CCP stack at the end  of	the  TPA
     (below  the  OS serial number) and pushes the address of the WBOOT entry in
     the BIOS vector, so a program trying to return to the  CCP  will  terminate
     correctly.

   File attributes
     File  attributes  (read-only and system attribute resp. the four attributes
     available for user programs) are not supported by tnylpo; the corresponding
     BDOS function #30 is a dummy. File names characters will always be returned
     with the most significant bits reset.

   User areas
     The concept of user areas is not implemented by tnylpo; while the user code
     may be set by BDOS function #32 (and will be returned when  queried),  this
     has no influence on file operations.

   I/O byte
     Likewise, the I/O byte functionality is not implemented; while the I/O byte
     may  be  queried and set (by BDOS functions #7 and #8) and is stored in ad-
     dress 0x0003, it has no influence on the character devices.

   FCB structures
     FDOS calls are translated into Unix file  operations.  For  this  to  work,
     tnylpo maintains a separate list of corresponding Unix files; references to
     the  entries  of  this list are stored in the FCBs of open CP/M files (a 16
     bit reference number is stored at offsets 16 and 17 in the  FCBs,	and  the
     same  number  XORed  by 0xafcb is stored at offsets 18 and 19). This allows
     programs to copy the FCBs of open files and use the copies to  further  ac-
     cess the same files (e.g. programs written in Turbo Pascal do such things).
     The drive and file name portions of a FCB are only referenced by BDOS func-
     tions #15, #17, #19, #22, #23, #30, #35, and #102, all other functions (es-
     pecially  the  read  and  write functions) use the file reference number to
     identify the relevant Unix file. The current record  number  in  sequential
     I/O  operations is stored in the FCB fields EX, S2, and RC (offsets 12, 14,
     and 32).

   Sparse files
     Since CP/M file operations are directly mapped  to  Unix  file  operations,
     some  characteristics of Unix files are visible to CP/M programs running on
     tnylpo: Trying to read a record within an unwritten block in the middle  of
     a	sparse file would result in an error indication (reading unwritten data)
     under CP/M-80, but simply returns a record of zero bytes on  tnylpo,  since
     unallocated  areas  in  the middle of a Unix file read as zero.  Hopefully,
     few programs will take offence at this difference.

   File closing
     Normally, closing a file in a CP/M program (BDOS function #16)  will  cause
     tnylpo  to close the corresponding Unix file and free its entry in the file
     list. This causes problems with certain  CP/M  software  (e.g.  dBase  II),
     which  continue to use FCBs for file operations after calling BDOS function
     #16. Since the close operation just writes the updated FCB data back to the
     disk directory (but doesn't change the FCB), this is  possible  in  CP/M-80
     (though  a  little dirty in my opinion). Contrarily, tnylpo (in addition to
     closing the corresponding Unix file) removes its file  reference  from  the
     FCB,  thereby marking it as invalid for further I/O, causing subsequent op-
     erations by the CP/M program to fail.

     To accommodate such programs, tnylpo provides the -n  command  line  option
     (and  the	corresponding  close  files = false configuration option), which
     prevent closing the Unix file and removing the file reference from the  FCB
     (effectively making BDOS function #16 a dummy operation). If many files are
     opened  (sequentially  or	concurrently)  by a CP/M program, this may cause
     tnylpo to run out of files, since the closing of all Unix files is deferred
     until program termination.

   Text file format
     Disk file I/O is always done untranslated, i.e. the contents of disk  files
     written  by programs running on tnylpo are always in the character set used
     internally by the CP/M emulation. Likewise, the line end convention in text
     files is that of CP/M (^M^J, 0x0d 0x0a) and text files not  ending  exactly
     at  the end of a 128 byte CP/M file record will contain a ^Z (0x1a) byte as
     logical EOF marker (ideally, they should be padded with  ^Z  bytes  to  the
     next record border, but in reality they usually end in a single ^Z followed
     by  arbitrary  rubbish).  This  must  be taken into account when using Unix
     utilities to process files generated by tnylpo.

     On the other hand, text files generated under Unix should be  converted  to
     the  CP/M	line end convention before processing them with programs running
     on tnylpo (the command set ff=dos might come handy for people using  Vim!).
     The  CP/M	convention for marking the logical end of text files is honoured
     automatically, since tnylpo's BDOS emulation pads Unix files  to  the  CP/M
     record size of 128 bytes with ^Z bytes.

     Text file conversion between the Unix and the CP/M formats may be done con-
     veniently using the companion program tnylpo-convert(1).

   Performance
     tnylpo  has been optimized for portability, not for performance; some parts
     of the processor emulation (e.g. the addition and	subtraction  operations)
     may be ridiculously inefficient compared to a hand-optimized assembler ver-
     sion  (or	even a C version making moderate use of platform specific things
     like byte order or number representation). On the plus side, tnylpo  should
     compile  and  run	on every Unixy platform supporting ISO C99 (for wide and
     multibyte character support), a  wide  character  capable	version  of  the
     ncurses  library  and  int  variables  with more than 16 bits. That said, I
     found tnylpo blindingly fast compared to the real thing even  on  the  out-
     dated hardware I used for its development.

   The delay routine
     Since  CP/M-80  version 2.2 offers no functions for time keeping or delays,
     programs are forced to use the cycle time of certain instructions in combi-
     nation with the CPU clock frequency if they need to  delay  program  execu-
     tion;  this  approach is doomed under an emulator, especially if it is run-
     ning on a multiprogramming system.

     To allow CP/M programs to delay execution for a defined (wall  clock)  time
     period, tnylpo supplies a delay routine masquerading as 18th BIOS entry: it
     expects  a  single parameter, an unsigned 16-bit number in register BC, and
     waits this many milliseconds before returning to the caller.

     The benefit of this routine is at best limited, but  most	likely	nonexis-
     tent;  since  it  is  an extension, no existing CP/M application (for which
     tnylpo has been created in the first place) uses it, and even in case some-
     body would develop new CP/M software,  employing  tnylpo's  delay	function
     would break compatibility with all other CP/M machines or emulators.

     As  an  alternative,  tnylpo implements function #141 (Delay) from the MP/M
     BDOS; while this function is a little more standardized than tnylpo's  pro-
     prietary extension, it is equally unavailable on real CP/M and most compat-
     ible systems and suffers from the additional drawback that it measures time
     in  system timer ticks, which are implementation dependent (tnylpo emulates
     a tick length of 20 milliseconds, i.e. a 50 Hertz timer).

   The name of the program
     "tnylpo" is a fantasy word. Neither is it an acronym nor does it  have  any
     meaning  I know of (which is the main reason I chose it).	"tnylpo" is pro-
     nounced like a native speaker of German (e.g. I)  would  naively  pronounce
     "tnulpo"  (or  like a speaker of Finnish would pronounce "tnylpo", provided
     she survives the initial consonant cluster).  In  its  formation,	"tnylpo"
     with  its	two  syllables and ending in "-po" aligns nicely with other non-
     sense words I invented earlier (like "ilpo" or "sampo") --until I moved  to
     Finland and discovered that most of these supposed nonsense words have cur-
     rency here...

BUGS
     See the remarks under NOTES. Most of them may be interpreted as bugs in the
     implementation, including the program name.

   Character set switching
     A	program running in full screen mode (VT52 emulation) may change its dis-
     play character set from the primary character set to the alternate set  and
     back by issuing an appropriate escape sequence. This switching also affects
     the  character  set translation of the other character devices (LST:, PUN:,
     and RDR:), unless they are operating in raw mode.

   Character redefinition
     It is not recommended to redefine any of the characters which may appear in
     CP/M file names, their Unix equivalents or in the file name/file  extension
     fields  of an FCB; these include the decimal digits (0x30-0x39), the upper-
     and lower case characters (0x41-0x5a and 0x61-0x7a), space  (0x20),  dollar
     sign  (0x24),  asterisk (0x2a), minus (0x2d), dot (0x2e), colon (0x3a), and
     the question mark (0x3f).

   Host system locales
     tnylpo has been implemented with the intention to work  with  all	possible
     Unix  CTYPE  locale  settings  (other aspects of the current locale are ig-
     nored); unfortunately, only ASCII based systems and locales are  supported,
     since  there  is  no character set independent way to represent some of the
     control characters relevant for CP/M (e.g.  ^C and ^Z).  Currently,  tnylpo
     always  assumes that the character codes 0x00-0x1f and 0x7f of the host op-
     erating system single- or multibyte character set correspond to  the  ASCII
     control  characters.  Frankly,  tnylpo  has only been extensively tested to
     work with UTF-8 based locales.

   File namespace clashes
     tnylpo tries to hide unsuitable files in host directories used as CP/M dri-
     ves from CP/M programs; file searches and open requests will ignore  every-
     thing  but regular files up to 8MB in size which have acceptable names. Un-
     fortunately, this attempt at hiding other objects is far  from  perfect:  a
     CP/M  program trying e.g. to create a file whose name matches the name of a
     (hidden) directory will mysteriously fail (a rename operation may meet sim-
     ilar problems). It is therefore recommended to reserve directories used  as
     CP/M  drives to conforming regular files or to give all other objects names
     not acceptable as CP/M file names (a leading dot may work wonders!).

   Color limitiations
     The color support in tnylpo's terminal emulation is constrained by the  ca-
     pabilities  of the ncurses library resp. of the display hardware. These may
     cause a limitation of the number of combinations of  foreground  and  back-
     ground  colors  (color  pairs)  which may be used on the display simultane-
     ously. If tnylpo runs out of color pairs, the  affected  combinations  will
     revert to the default foreground and background colors. This problem should
     only occur with pathological ("angry fruit salad") user interface designs.

EXAMPLES
     tnylpo -f ws.conf ws hugo.txt

     will use the configuration file ws.conf and run the program ws.com, passing
     it the string hugo.txt as command line parameter.

     If the file ws.conf contains the following lines

	    #
	    # WordStar configuration
	    #
	    drive a = "."
	    printer file = "./printer.txt"
	    printer mode = text
	    logfile = "./.tnylpo.log"
	    loglevel = 0
	    #
	    # use German character set
	    #
	    charset = ascii
	    char 0x40 = "<section>"
	    char 0x5b = "A"
	    char 0x5c = "O"
	    char 0x5d = "U"
	    char 0x7b = "a"
	    char 0x7c = "o"
	    char 0x7d = "u"
	    char 0x7e = "ss"
	    unprintable = "?"
	    console = full
	    lines = 24
	    columns = 80
	    application cursor = true
	    screen delay = 2

     tnylpo  will  search  for	ws.com (and other files) in the local directory,
     which will be used as drive A in the emulation; console I/O will be handled
     in full screen mode by the VT52 emulation which uses a screen of  24  lines
     of  80  columns.  The cursor keys will be translated to ^E (up), ^S (left),
     ^D (right), and ^X (down), and the character set  will  correspond  to  the
     German  ISO/IEC 646 variant (umlaut characters in place of the brackets and
     curly braces of ASCII). Characters in the range of 0x80  to  0xff	will  be
     displayed	as  inverted  question	marks. Printer output will be written to
     printer.txt in the current directory, will be in the Unix character set and
     will follow  Unix	line  end  conventions.   A  log  will	be  appended  to
     .tnylpo.log  in the current directory and will contain error messages only.
     After program termination, tnylpo will wait for two seconds  before  reset-
     ting the screen.

   Patching a CP/M executable
     Many  CP/M applications do not supply installation programs but rely on the
     user applying (hopefully well-documented) binary patches  to  support  e.g.
     the  control  sequences of a particular video terminal. Under CP/M, this is
     usually done using a debugger (e.g.   DDT)  in  combination  with	the  CCP
     built-in command SAVE.  The following example shall demonstrate the process
     of patching an executable using tnylpo:

	    $ ls -la
	    total 72
	    drwxr-xr-x	 7 tnylpo  users   224 Sep  5 13:04 .
	    drwxr-xr-x	39 tnylpo  users  1248 Sep  5 13:04 ..
	    -rw-r--r--	 1 tnylpo  users  8192 Sep  5 13:02 asm.com
	    -rw-r--r--	 1 tnylpo  users  4864 Sep  5 13:02 ddt.com
	    -rw-r--r--	 1 tnylpo  users  2091 Sep  4 13:08 patch.asm
	    -rw-r--r--	 1 tnylpo  users  9728 Sep  5 13:02 wm.com
	    -rw-r--r--	 1 tnylpo  users  2688 Sep  5 13:02 wm.hlp

     wm.com  is  the  binary  to be patched (wm.hlp is an associated data file).
     asm.com and ddt.com are the standard CP/M absolute assembler  and	debugger
     (ASM  and	DDT)  which  will  be  used  to  prepare  resp. apply the patch.
     patch.asm contains the assembler source file of the patch. Note the size of
     wm.com, which is 9728 bytes.

     First, the patch is assembled, which creates patch.hex, a file in the Intel
     Hex format.

	    $ tnylpo asm patch
	    CP/M ASSEMBLER - VER 2.0
	    01D8
	    000H USE FACTOR
	    END OF ASSEMBLY

     Now the debugger is started, which relocates itself to the top of	the  TPA
     and  loads  wm.com  into  the  TPA  starting  at  address 0x100. The option
     -eb9728:wmnew.com asks tnylpo to save  9728  bytes  (the  size  of  wm.com)
     starting  from  address  0x100 to the file wmnew.com after the CP/M program
     (i.e.  DDT) has terminated.

	    $ tnylpo -eb9728:wmnew.com ddt wm.com
	    DDT VERS 2.2
	    NEXT  PC
	    2700 0100

     DDT displays two hexadecimal numbers, the first of which is the first  free
     memory address after the loaded program (0x2700 is decimal 9984, i.e. 0x100
     plus  9728,  the  size of wm.com).  Now DDT is used to apply the patch: The
     command i tells DDT the name of the patch file, and the command r reads  it
     into  memory  (the Intel Hex format provides the necessary address informa-
     tion to apply the changes at the correct locations).  Finally,  g0  directs
     DDT to jump to adress 0, which causes it to terminate.

	    -ipatch.hex
	    -r
	    NEXT  PC
	    2700 0000
	    -g0

     As  soon  as  DDT terminates, tnylpo saves the memory contents as directed,
     creating a patched version of the executable, which can be tested	and  re-
     named.

	    $ ls -la wmnew.com
	    -rw-r--r--	 1 tnylpo  users  9728 Sep  5 13:06 wmnew.com

AUTHOR
     tnylpo  and  its manual page were written by Georg Brein (tnylpo@gmx.at), a
     programmer, IT systems administrator and guerrilla egyptologist.

SEE ALSO
     tnylpo-convert(1)

     The implementation of the Z80 processor emulation, especially of  the  fea-
     tures  not  covered by the official documentation (Zilog Inc., Z80 CPU User
     Manual, Revision 11: August 2016 [UM008011-0816]), is heavily influenced by
     Sean Young's The Undocumented Z80 Documented (Version 0.91, 18th  September
     2005).

     The  CP/M-80  2.2 system interface emulation is based on the CP/M Operating
     System Manual by Digital Research (Third Edition: September 1983).

     Some additional system functions are based on  their  descriptions  in  the
     CP/M  Plus  (CP/M Version 3) Operating System Programmer's Guide by Digital
     Research (Second Edition: April 1983).

				   2021-04-28			       tnylpo(1)

home | help