m8csim - Simulator for M8C systems
==================================

Copyright 2006 Werner Almesberger

The files in this directory are distributed under the terms of the
GNU General Public License (GPL), version 2. This license is
included in the file ../COPYING.GPLv2.


Overview
--------

The simulator loads a program in ROM, binary, or Intel Hex format, and executes
it in the simulation environment. The simulator currently only simulates the
CPU core, without interrupt handling, and GPIO pins. It currently does not
attempt to relate simulation time to real time.

The simulation is controlled by a simple script that can set and query memory
and registers, and that controls code execution. The simulator is not designed
to be interactive, but it is possible to enter the script during the simulation
run.


Usage
-----

The script is by default read from standard input. This can be changed with the
option -f. Normally, register definitions are automatically included from the
file default.mc8sim. This can be turned off with the option -n. The search path
for default.mc8sim can be extended with the option "-I directory".

The name of the chip can be specified on the command-line. The chip name is
mandatory if not using an ICE. The list of supported chips can be obtained with
the option -l.

The program file can be in ROM format, Intel Hex, or it can a raw binary.
Binary mode can be forced with the option -b. If the program file name argument
is omitted, no program is loaded. Note that standard input can only provide
either the script or the program, but not both.

If a symbol file is loaded with the option -m, symbolic names are used in the
disassembled code, and symbols can be entered instead of numbers.

The use of a DIY ICE is discussed below.


The DIY ICE
-----------

The simulator can connect to a target system and remotely control its
processor. Selected I/O operations can then be executed on the real hardware.
Use of an ICE is enabled with the option -i. Note that this only initializes
communication with the target but does not change it's I/O. To do this, I/O
lines must be assigned to the ICE with the "connect" directive in the
simulation script.

The simulator uses the regular ISSP(tm) interface for communication. It
delegates communication to the m8cprog programmer. The options "-p port",
"-d driver", -D, -P, -R, -3, and -5 are used in exactly the same way as with
m8cprog.


Scripting language
------------------

Each expression or command ends with a newline. Comments in the scripting
language are the usual forms known from C, and the semicolon from m8cas.

- If an expression is entered, it is calculated and its result is printed in
  hex and decimal. Example:

  (input)	5
  (output)	0x5 5

- Constants can be numbers in any of the formats recognized by the M8C
  assembler language, including characters.

- Read from RAM, ROM, or a register:

  [address]
  RAM[address]
  ROM[address]
  REG[address]
  A
  F
  SP
  X
  .

  The names of CPU registers and the memory type prefixes are case-insensitive.
  Register and RAM addresses span the entire address range and are not affected
  by the current I/O bank or RAM page.

  If a symbol map is loaded, symbolic names can be used as addresses and
  values. If a symbol name coincides with a keyword of the scripting language,
  it has to be put in double quotes.

- As a temporary extension, also direct accesses can be made through the ICE:

  ice REG[address]

  Note that they keyword "ice" is case-sensitive. Also note that such direct
  accesses are not synchronized with the simulator state, and can cause
  confusion when made to registers also known to the simulator. The main
  purpose of direct ICE accesses is to provide a tool for developing proper
  simulation support of the respective block in the microcontroller.

- Expressions from constants and read accesses can be formed using all
  operators recognized by m8cas. Additionally, the following operators are
  available for lvalues (register, ROM, RAM, etc.):

  lvalue[n]		accesses the n-th bit of "expression", i.e., 0 or 1
  lvalue[l:r]		accesses bits l through r of "expression", e.g.,
			0xd6[4:2] yields 5

  The unary ampersand ("&") can be used as an address operator, to extract
  the register address from a macro:

  &reg[expression]	yields " expression"

  The precedence of & and [...] is like in C. Expressions are always calculated
  as unsigned 32 bit integers.

- Assign to RAM or a register. The target name is like when reading, e.g.,

  A = 0
  [0x100] = 1

- Drive GPIO pins with an external signal (in the simulation). All the bits
  covered by the mask are affected

  drive P0 = 8		; drive P0[7:3] and P0[1:0] with "L", P0[2] with "H"
  drive P0[1] = 1 r	; drive P0[1] with a resistive low
  drive p0[1] = z	; don't drive P0[1]

  Note that driving a pin while it is connected to the ICE has no effect.

- Set GPIO pins to specific values. Drive mode bits are changed according to
  the transition that is being effected. If a change can be done either in slow
  or in fast mode, the mode currently set for the respective pins is used.

  set p0 = 0		; set P0[7:0] to a strong low
  set p0[1] = 0 r	; set P0[1] to pull down (resistive low)
  set p1[2] = z		; make P1[2] a digital input
  set p1[2] = analog	; make P1[2] an analog input

- The status of a port can be queried with

  p0
  p0[6:2]

  The characters in the output are "Z" for Hi-Z, "H" for strong 1, "L" for
  strong 0, "R" for resistive 1, and "r" for resistive 0.

- Run the program until an exception occurs or until a number of (CPUCLK)
  cycles has passed:

  run
  run CYCLES

  The current time in cycles can be obtained through the read-only variable @.
  To run the program for a N cycles, use "run @+N"

  To interrupt a running program, press Ctrl-C.

- A breakpoint can be set at any address in the program with the "break"
  command:

  break
  break ADDRESS

  The address can be any expression, including a label. If the address is
  omitted, the breakpoint is set at the current PC.

  There can be only one breakpoint at a given address. Trying to set multiple
  breakpoints at the same address yields an error. Breakpoints are only
  effective at the first byte of an instruction. A breakpoint on any other byte
  of a multi-byte instruction is ignored, unless program execution steps or
  jumps "into" that instruction.

  A breakpoint is only taken when the PC reaches its location. In particular,
  the first instruction executed by "run" may not trigger a breakpoint. If
  program execution would stop at the same location due to a breakpoint and a
  cycle limit specificied in the "run" command, the breakpoint "wins".

  Breakpoints are listed in address order with:

  break *

  Breakpoints are removed with "unbreak":

  unbreak
  unbreak ADDRESS
  unbreak *

  If the address is omitted, the breakpoint at the current PC is removed. The
  last form removes all breakpoints in the program.

- Connect I/O pins to an ICE, by port, pin, or pin range, e.g.,

  connect P2
  connect P0[0]
  connect P1[6:3]

  Writes to these pins are now propagated to the ICE, and reads of the pins use
  data obtained from the ICE. This applies to accesses from the program being
  simulated and for register accesses from the script.

  The pins used to communicate with the ICE, usually P1[0] and P1[1], cannot be
  connected. Port names are case-insensitive, so P1 is equal to p1.

- Disconnect I/O pins from the ICE, either all of them, or by port, pin, or pin
  range:

  disconnect
  disconnect P1
  disconnect P0[7]
  disconnect P5[6:0]

  Disconnected pins are turned into the Z state.

- Symbolic names for registers and fields of CY8C2xxxx chips are available as
  case-sensitive definitions.

  Register and field names follow the names in the TRM. Field names are
  constructed by appending the field name to the register name. Spaces in names
  are removed if the adjacent characters are non-numeric or differ in case.
  Otherwise, the spaces are replaced with underscores. Examples:

  "Page Bits" in IDX_PP becomes IDX_PP_PageBits
  "ECO EX" in CPU_SCR1 becomes CPU_SCR1_ECO_EX

  Registers are defined as accesses, e.g., PRT0DM0 is reg[0x100]. Likewise,
  fields are defined using the [...] operator, e.g. CPU_F_PgMode is CPU_F[7:6].

  To obtain the address of a register, use the unary & operator.

- A message can be displayed with "printf":

  printf "hello\n"		; prints "hello", followed by a newline
  printf "X=%d Y=%d\n",2,3	; prints "X=2 Y=3", followed by a newline

  The following conversion specifiers are supported:

    c  print a character
    d  print a decimal number
    o  print an octal number
    u  like "d", all numbers are unsigned
    x  print a hexadecimal number, in lower case
    X  print a hexadecimal number, in upper case
    %  print a percent sign

  The flag "0" is used to zero-pad the output.

  Furthermore, the field width can be specified.

- Execution of the script can be paused with "sleep":

  sleep			; wait until the user presses [Return]
  sleep 10		; wait ten seconds

  "sleep" can be combined with "printf", e.g.

  printf "Press [Enter] to continue "	; no \n, so we stay on the same line
  sleep

- In interactive use, leave the simulator with ^D or "quit"


Known limitations
-----------------

This is a list of some known limitations and missing "must have" features.
There are certainly many more.

- simulation time is not synchronized with real time:
  Every X cycles (configurable), check against lower/upper bound (configurable)
  of deviation from real time. If running too fast, wait. If running too slow,
  cancel the time debt and proceed.

- relation of simulation and real time is not tracked:
  When checking time, record both times, then plot at post-simulation
  analysis.

- there are no traces for intructions executed:
  Instructions are easy, data will be harder. Do data "intelligently", by
  recording just the information an instruction has destroyed ?

- there are no traces for I/O lines:
  Actually, a little GUI may be nice for once. Also add a means to override
  target lines and provide script-driven or interactive stimuli.

- should the name of the PC be "PC" (it's a register) or "." (like in the
  assembler) ?
  Or both ? For now it's ".".

- weak scripting language:
  No loops, no variables, no functions. Should I just drag over the whole
  umlsim core, any never worry again about a lack of power ?

- no quick interconnect overview:
  should support graphical (Postscript/XFig or interactive) view of
  configuration status of interconnect

- We don't detect GPIO lines in conflicting configurations.
  Should we ? (E.g., ties or any strong-strong conflict.)

- Analog Hi-Z works just like digital Hi-Z.
  Need to check what the real hardware would do.

- drive vs. ICE priority is wrong:
  It should be possible to override input from the ICE, and just use the ICE
  for output.

- simulated "drive" is not seen by target:
  So we can't just feed synthetic data to a digital block.

- cannot detach ICE under software control:
  It may be nice to be able to temporarily detach the ICE and let the program
  on the target just run, e.g., with "disconnect" and "connect". "connect"
  would require a full reset of the simulator state, though.

- is it really a good idea to make FOO do the access ?
  If it's reg[FOO] in the assembler, it should also be reg[FOO] and not just
  FOO in the simulator, no ? Makes for awkward typing, though.

- consider supporting read-modify-write operators:
  "PRT0DR ^= 0xff", anyone ?

- input error recovery is only partial

- something's still screwy with I/O bit calculation:
  example/switch.asm sort of works in the simulator with ICE connected even if
  we don't do the "and a,3", which is clearly wrong.

- it should be possible to "connect" any registers to the ICE, not only GPIO
