Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


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

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

       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

       tnylpo allows the execution of programs written for the CP/M-80 operat-
       ing  system in a	Unix environment. To accomplish	this task, tnylpo com-
       bines 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 library and system calls.

       tnylpo  doesn't	even try to re-create the look-and-feel	of the CP/M-80
       operating 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

       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 soft-
       ware 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 char-
       acter (most commonly UTF-8 based) approach of  contemporary  Unix  sys-
       tems. This translation layer affects the	character orientated I/O chan-
       nels of CP/M only and may be  disabled  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 ca-
       pability	of running the same CP/M application on	different terminal em-
       ulations	or on serial terminals without reconfiguring  the  CP/M	 bina-
       ries),  tnylpo includes a curses	based emulation	of the DEC VT52	termi-
       nal (with certain extensions in functionality) for use as CP/M  console
       device.	tnylpo	gives the user the choice between this terminal	emula-
       tion 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	 inte-
       grate under Unix), among	them user areas, the rudimentary character de-
       vice 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/directories) for  different  applica-
       tions  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
       undocumented  features  of  the	Z80 CPU; undocumented instructions and
       side effects 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	regis-
       ter  may	 be  set  and read and the EI and DI instructions have the ex-
       pected side effects, no interrupt will ever occur).  Executing  a  HALT
       instruction  will  end  program 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  ear-
       lier 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 in-
       structions, which increases the chances of  detecting  and  stopping  a
       runaway application program early.

       The  R  register	 will be increased as expected;	since application pro-
       grams 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 se-
       quence of random	numbers).

       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 (including	null bytes and slashes), and Unix file names  are  not
       bound  to the 8+3 character restriction of CP/M,	tnylpo enforces	a com-
       mon subset: only	decimal	digits,	the 26 letters of  the	alphabet,  the
       minus  (-),  at (@), dollar ($),	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 returns) only upper case  letters
       in  CP/M	 FCBs.	Unix files with	names containing 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  temporary  file
       names,  tnylpo could not	forbid them; fortunately, CP/M programs	creat-
       ing files with file names containing dollar signs usually  remove  them
       before exiting.)

       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
	      before 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	speci-
	      fied 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 pre-
       fixed by	a drive	specification 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 already 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 initialized according to the second and third positional  ar-

   Configuration files
       While  some  features  of  tnylpo can be	controlled by command line op-
       tions, the most convenient way to configure it is by using a configura-
       tion  file; if a	configuration file is explicitly specified on the com-
       mand 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 configuration 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  configu-
	      ration  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	running	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 con-
	      figuration file),	tnylpo will use

		     drive a = "."

	      as default, i.e. the current  working  directory	will  be  made
	      available	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 re-
	      fer to. This drive must be assigned to a host system  directory,
	      either  implicitly  or by	the drive configuration	option.	If de-
	      fault drive is not specified, tnylpo assumes drive A as  default

       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  possible,  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 (fa-
	      tal  error messages are also written to stderr).	If the logfile
	      configuration 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 information is written (causing the emulation to  run  pro-
	      gressively 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

	      2	     additionally, trace FDOS functions	(i.e.  BDOS  functions
		     related 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 applications 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
	      configuration 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
	      termination  and	resetting  the	display.  If key (resp.	 @) is
	      specified, tnylpo	waits for a key	being pressed  before  exiting
	      the VT52 emulation. 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. De-
	      fault 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 num-
	      ber of lines must	be between 5 and 95, the number	of columns be-
	      tween 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 ap-
	      propriate	cursor motion commands for programs like  WordStar  or
	      Turbo  Pascal). Otherwise, the cursor keys will generate the de-
	      fault VT52 escape	sequences, <esc> A,  <esc>  D,	<esc>  C,  and
	      <esc>  B.	  This option is only effective	in full	screen console

       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
	      explained	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 corresponding command line options. Details are explained be-
	      low (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
	      _nanoseconds_) 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  allows  using  software (e.g. interactive	games)
	      which would otherwise run	much too fast on tnylpo;  another  ap-
	      plication	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  par-
	      ticular  application  program; they need to be determined	by ex-
	      perimentation. 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 implic-
	      itly, 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  reg-
	      ister  values  and the contents of main memory) to the log file.
	      The keywords startup, exit, error, and signal (resp. the	subop-
	      tions s, x, e, and i) request a dump at program startup (immedi-
	      ately 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 mutually	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 option	logfile.

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

       tnylpo's	terminal emulation mimicks the VT52 fairly accurately, but of-
       fers 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 limi-
       tations of the VT52 direct cursor positioning command), eight-bit oper-
       ation,  a  dynamically  switchable  alternate character set, insert and
       delete line commands, and  bold,	 underlined,  inverted,	 and  blinking
       (i.e.  everybody's  favourite) character	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 col-
       umns by 24 lines, but this may be changed by command line or configura-
       tion  file options) within the actual display (a	terminal emulator like
       xterm(1)	or the screen of an actual serial terminal).  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 sup-
       ports (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 col-
	      umn to the right (resp.  does nothing if the cursor  is  already
	      in the last column).

       <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
	      characters (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 dis-
	      play 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 identi-
	      fies 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
       extensions 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 be-
	      low 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 dis-

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

       <esc> O (0x1b 0x4f)
	      deletes the character at the cursor position and	moves  charac-
	      ters  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

       <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
	      background 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  com-
	      mands,  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  equiva-
	      lent to using <esc> i and	<esc> j).

       "Hold screen" mode is a feature of the VT52 terminal: it	is entered and
       exited 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 ei-
       ther "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 al-
       lows access to certain additional shapes	like subscripted digits	or the
       +- sign;	in tnylpo, graphical mode allows displaying the	shapes defined
       for the character positions 0x00-0x1f and 0x7f, which  cannot  be  dis-
       played directly.

   Character sets
       Switching between a primary and an alternate character set is an	exten-
       sion 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 programs to use e.g. a	national vari-
       ant 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

	      [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 primary (or alternate, if the line	is  prefixed  by  alt)
       character  set. Characters 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 charac-
       ters), the ISO 8859-1 (Latin 1) eight-bit character set,	which  supple-
       ments  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 sup-
       ports 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

       By using	the command line option	-a, a program may be started with  the
       alternate character set selected; the effect is almost identical	to the
       program issuing <esc> c as its very first action. (There	is  a  differ-
       ence  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 it-
       self can	select the alternate character set only	after this initializa-
       tion  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 alternate	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 charac-
       ter 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  se-
       quences	<esc>  P  (0x1b	 0x50),	<esc> Q	(0x1b 0x51), and <esc> R (0x1b
       0x52). F4 causes	the terminal emulation 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	subse-
       quently	displayed  characters. These colors are	identified by the fol-
       lowing 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
       followed	by two comma-separated color codes, which specify the  default
       foreground 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 on to override	the configuration file
       and disable color support. If no	default	colors have been specified ei-
       ther  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.
       foreground colors of subsequently displayed characters; _color_ is  ei-
       ther  a single ASCII digit in the range from 0 to 7 (0x31 to 0x37) cor-
       responding 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  disabled,  <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
       devices 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 program 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
       configuration options

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

       In  raw	mode, bytes are	written	to the file exactly as they are	gener-
       ated 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 indica-
       tion). In text mode, tnylpo will	translate the  characters  read	 resp.
       written	using the translation table used by the	console. Character set
       switching by the	console	(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 mem-
       ory 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 out-
       put file	and the	range of CP/M memory addresses to save.	Possible  sub-
       options and their parameters are

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

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

	      selects a	number of pages	(units of 256 bytes, specified as dec-
	      imal number) starting from address 0x100.

	      selects a	range of addresses to  save  (both  addresses  may  be
	      specified	 as  octal,  hexadecimal, or decimal numbers using the
	      Unix convention of prefixing them	 with  0,  0x,	or  any	 other
	      digit,  respectively);  _high-addr_  may	not be less than _low-
	      addr_, and if _low-addr_ is missing, 0x100 will  be  assumed  in
	      its place.

	      specifies	 the  Unix file	to which the memory contents are writ-
	      ten; this	is mandatory and must be the very last	suboption  (in
	      fact,  everything	 following  the	first colon in the argument of
	      the -e command line option is taken as part of the file name).

       Individual suboptions resp. suboptions and their	parameters may not  be
       separated 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 (start-
       ing 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  ap-
       plying  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  additional option 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  im-
       plemented:  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 delimiter, 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 re-
       turns 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
       system 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

   Program termination
       tnylpo terminates as soon as the	CP/M program it	executes terminates by
       either calling BDOS function #0 (System Reset) or BIOS function	WBOOT;
       jumping	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 con-
       sidered regular for the purpose of determining  the  exit  status  from
       tnylpo (see below, under	EXIT STATUS).

       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  configured,	 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.	Pressing  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 ir-
       regular forms of	program	termination.

       tnylpo exits with status	1 if it	encountered a fatal error and status 0
       otherwise. Fatal	errors are command line	errors,	configuration file er-
       rors, 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  pro-
       gram  execution	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 "un-
       successful return" range	(0xff00-0xfffe)	prior to  termination,	tnylpo
       will exit with status 1.

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

       The file	.tnylpo.conf in	the user's home	directory is used as a config-
       uration file, if	it is present, if no configuration file	has been spec-
       ified  on the command line, and if there	is no file .tnylpo.conf	in the
       current working directory.

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

   Differences between tnylpo and CP/M-80
       By design, there	are some incompatibilities between CP/M-80 and the em-
       ulation 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  run-
       ning on tnylpo.

       BDOS  and  BIOS function	emulations are activated by the	simulated pro-
       cessor 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 vec-
       tor, 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-ex-
       isting disk, bad	sector,	read-only disk,	and read-only file; these  ad-
       dresses	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 environ-
       ment 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 inof-
       fensive)	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  related 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 in-
       formation (#27 and #31) will return dummy structures  containing	 mean-
       ingless (but consistent)	data; for example, all disk drives will	be re-
       ported as having	a block	size of	16KB, 2048 directory entries and a ca-
       pacity  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  dis-
       turbed  since  tnylpo  stores some state	information there, see below).
       The emulation is	good enough for	programs searching for file name  pat-
       terns  or just listing the disk directory, but will fail	for those try-
       ing to analyse the block	structure of the emulated disk	from  the  re-
       turned 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  con-
       tents) will not work correctly. Ending a	program	by simply returning to
       the CCP is supported; tnylpo initializes	a 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 at-
       tributes	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 address 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;	refer-
       ences 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 access	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 functions #15, #17, #19,	#22,  #23,  #30,  #35,
       and #102, all other functions (especially 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  dif-

   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). Contrar-
       ily, tnylpo (in addition	to closing the corresponding  Unix  file)  re-
       moves  its  file	 reference from	the FCB, thereby marking it as invalid
       for further I/O,	causing	subsequent operations by the CP/M  program  to

       To  accommodate	such programs, tnylpo provides the -n command line op-
       tion (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 pro-
       gram, 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 con-
       vention 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 con-
       tain 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
       conveniently using the companion	program	tnylpo-convert(1).

       tnylpo has been optimized for portability, not  for  performance;  some
       parts of	the processor emulation	(e.g. the addition and subtraction op-
       erations) may be	ridiculously inefficient compared to a	hand-optimized
       assembler  version (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 outdated hardware I used for its development.

   The delay routine
       Since  CP/M-80  version 2.2 offers no functions for time	keeping	or de-
       lays, programs are forced to use	the cycle time of certain instructions
       in  combination with the	CPU clock frequency if they need to delay pro-
       gram execution; this approach is	doomed under an	 emulator,  especially
       if it is	running	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 reg-
       ister BC, and waits this	many  milliseconds  before  returning  to  the

       The  benefit of this routine is at best limited,	but most likely	nonex-
       istent; 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 somebody would develop new CP/M software, employing	tnylpo's delay
       function	would break compatibility with all other CP/M machines or emu-

       As an alternative, tnylpo implements function  #141  (Delay)  from  the
       MP/M  BDOS;  while  this	 function  is  a little	more standardized than
       tnylpo's	proprietary extension, it is equally unavailable on real  CP/M
       and  most  compatible  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 pronounced 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 nonsense words	I invented  earlier  (like  "ilpo"  or
       "sampo")	 --until  I moved to Finland and discovered that most of these
       supposed	nonsense words have currency here...

       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
       display 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  de-
       vices (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 ap-
       pear 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	possi-
       ble Unix	CTYPE locale settings (other aspects of	the current locale are
       ignored); unfortunately,	only ASCII based systems and locales are  sup-
       ported,	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	operating 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
       drives  from CP/M programs; file	searches and open requests will	ignore
       everything but regular files up to 8MB in size  which  have  acceptable
       names.  Unfortunately, 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 oper-
       ation may meet similar problems). It is therefore  recommended  to  re-
       serve 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 lead-
       ing dot may work	wonders!).

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

       tnylpo -f ws.conf ws hugo.txt

       will use	the configuration file ws.conf and  run	 the  program,
       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 (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 conven-
       tions.	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	resetting 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
	      -rw-r--r--   1 tnylpo  users  4864 Sep  5	13:02
	      -rw-r--r--   1 tnylpo  users  2091 Sep  4	13:08 patch.asm
	      -rw-r--r--   1 tnylpo  users  9728 Sep  5	13:02
	      -rw-r--r--   1 tnylpo  users  2688 Sep  5	13:02 wm.hlp is the binary to be patched (wm.hlp is an	associated data	file). and are the standard CP/M absolute assembler and	debug-
       ger (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, 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
	      000H USE FACTOR

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

	      $	tnylpo ddt
	      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  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 nec-
       essary address information to apply the changes at  the	correct	 loca-
       tions).	 Finally,  g0 directs DDT to jump to adress 0, which causes it
       to terminate.

	      NEXT  PC
	      2700 0000

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

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

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


       The  implementation  of	the Z80	processor emulation, especially	of the
       features	not covered by the official documentation (Zilog Inc., Z80 CPU
       User  Manual, Revision 11: August 2016 [UM008011-0816]),	is heavily in-
       fluenced	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 Operat-
       ing 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 Digi-
       tal Research (Second Edition: April 1983).

				  2020-10-26			     tnylpo(1)


Want to link to this manual page? Use this URL:

home | help