COMPUTER EMULATION FRAMEWORK SPECIFICATION
Specification Version: 2.0
Last Modification: 10-February-2007
Note
This specification is NOT backward-compatible with earlier versions (earlier than 2.0).
Introduction
The Computer Emulation Framework (CEF) is an application framework and specification for the purposes of emulating various computer hardware configurations in software. The goals are:
1) to provide a framework which is at a low-enough level to allow accurate emulation and simulation of any hardware that exists to this time, but without being so low level that the speed of emulation makes the resulting application useless.
2) to provide a consistent base user interface for emulators.
3) to speed development of emulators by providing several general-use components and a generic interface.
Uses for CEF include low-level debugging, simulation of unavailable hardware, and emulation of one computer on another.
Platform
There is no inherent hardware or software platform requirement for CEF but, in practice, the platforms of implementation will be Linux and MS Windows.
Technology prerequisites
CEF makes use of the following software components:
UEH The Unified Error Handler
Further, the MS Windows implementations make use of the Common Object Model (COM).
Description
CEF is a series of specifications designed to provide an easy-to-use and easy-to-understand emulation of computer systems. The only required specification is the CEF Core Specification, which defines the component types, their interfaces, and corresponding file formats, as well as the semantic information necessary to create compatible CEF components. Additional optional specifications provide useful, but not essential, specifications for classes and other resources which help speed the development of components. The two CEF specifications described herein are the CEF Core Specification and the CEF Utilities Specification.
Versions and backwards compatibility
With Version 2, the specification supports a means of providing backwards compatibility and interoperability between components of different versions. Most classes provide a Version method which indicates which version of the CEF specification they conform to. This version number is major.minor, times 10. For instance a value of 21 would indicate version 2.1. Within a major version, all versions must work with each other. That means, any new methods are added to the end of the VMT, and descendants must maintain the VMT layout. Before calling any method which is not present in the version 2.0 interface, the caller must check the version of the object to make sure it can make the call. Methods may not be removed from a class.
Terminology
Hereafter, the following terminology will be used:
Application |
a CEF application. |
Boolean |
an integer with a value of 0 for false, and anything else for true. |
Component |
a CEF software component. |
Environment |
a software emulated hardware environment. |
Hardware |
component a hardware component. |
Hardware |
environment a specific computer hardware implementation. |
Int64 |
an 8-byte (64-bit) signed integer (2's complement). |
Integer |
a 4-byte signed integer (2's-complement). |
Marshalling |
creation of an instance of a component and connection of it to other components. |
String |
a pointer to a null-terminated ASCII string (char*). |
Void |
Indicates a procedure. That is, a method which returns no result. |
CEF CORE SPECIFICATION
Overview
CEF is the framework specification, allowing mixing and matching of components in CEF applications. A CEF application is an application which uses one or more CEF components (usually a CPU component at least), and may use some generic components.
Components
A CEF component is a software analogy to the hardware components of a computer, such as the CPU, memory, IO devices, and buses. A CEF component serves up a standard interface that allows the various devices to be connected in either a dynamic or static way (or some combination thereof). The CEF application marshalls the various components, initializing instances of them and connecting the instances to each other to configure an emulated computer environment. Components are described in greater detail in the section titled "Components".
There are two relationships that components have with each other: connections and ownership. A connection indicates an emulated connection between two components through which data is transferred, but implies no hierarchy or ownership. An ownership relationship indicates that one component "owns" another. An owner component (hereinafter referred to as the parent component) creates its owned component (hereinafter referred to as the child component), terminates it, and manages connections to it. For instance, a bus and a memory component are connected, but a motherboard owns a CPU.
Data transfer size
All data transfers between components are byte-aligned. This refers to the actual CEF architecture and has no effect on the emulation. A component which implements a word size not exactly equal to a multiple of 8 bits will transfer data using the number of bytes necessary to contain all of the bits, with the extra bits being unused and undefined. For instance, a CPU with a word size of 36 bits would transfer data in 5-byte quantities with the uppermost 4 bits of the last byte ignored. From an emulation standpoint, the transfer is 36 bits, but the actual implementation code uses bytes for consistency.
Address Space
Address Space is a concept that is supported by CEF, but not required. The idea is that a component may support several address "spaces", each of which can be accessed via a 64-bit integer value. Space 0 is the default. All other address spaces are optional and defined by the component. For instance, a CPU may support both a Code segment and a Data segment - each with the same range of addresses. Both segments represent different address spaces. This is used in breakpoints, profiling, and other cases where it is necessary to distinguish between the different spaces.
Signals and States
Signals are inputs and outputs that are unique to a specific component implementation. For instance, an Interrupt signal on a CPU. Signals for a component have a textual name, an integer index, a state (true for High, false for Low), and an indication of whether or not the signal is active low. When signals change, a notice is sent to the UI, which passes it on to any component which has requested to be notified of signal changes.
States are flags indicating the internal state of a component. States have textual names, an integer index, and a state (true or false). Like Signals, State changes are only reported to the UI. Unlike Signals, State changes are not passed to other components by the UI. Examples of states are "Fetch", "Handling Interrupt", and "Priority".
Typical configuration
All applications must have a TUI_Interface object, an optional Master clock object, a memory component, and a CPU component, as a minimum. The CPU and memory are connected together in this simplest of configurations.
For more detailed simulation, a bus component may exist between the CPU and memory objects. Or, a motherboard object may be used in place of a CPU object (in which case, it marshalls its own CPU - and other - components).
For multi-processor systems, several instances of a CPU object may be created. However, in order for simulation of multi-processing to work, the master clock object MUST be used and the CPU objects must block themselves appropriately.
Master Clock
The Master Clock is used to simulate hardware timing issues. In many cases, this is not needed for adequate emulation. When not needed, the master clock instance can simply return the same Time_Index at all times, and immediately Wake a component upon a Block request. In any case, components should block themselves when starting (or completing) an operation that takes a known amount of time. For instance, when a CPU executes an instruction, it should block for the amount of time that the instruction should take. Blocking is accomplished by calling the master clock's Block method. The component should cease doing any further (time-related) processing until it is woken.
TMaster_Clock has the following methods:
void Block( TComponent*, int64 Time_Delta )
This procedure registers a request for a component to receive a Wake signal at the specified time delta (in picoseconds).
TDebug_Interface* Debugger()
This method returns an instance of a debug interface for the clock. If the clock component doesn't support debugging, the method returns NULL.
void Initialize( TUI_Interface* )
Initializes the clock to time index 0 and sets the UI interface.
int64 Get_Time_Index()
This function returns the current simulated master clock (which is measured in picoseconds) time index.
integer Serial_Number()
Returns the value passed at creation time (see Make_Instance).
boolean Support_Feature( integer ID )
Returns True if the clock supports the specified feature. This is reserved for future use.
integer Version()
Returns the version of the CEF specification that the object adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
UI Interface
The application must supply all components with a UI interface. This UI interface is the TUI_Interface class. It is used to communicate asynchronous events and communications back to the application and, in certain cases, between different components.
TUI_Interface consists of the following methods:
void Block( TComponent* Component, boolean Blocked )
This method is called whenever a component blocks (Blocked is true) or unblocks (Blocked is false). Component is the component in question.
boolean Breakpoint_Notice( int64 Address, boolean Physical, integer Space, TComponent* CPU )
This method is called when a CPU triggers a breakpoint. The method returns True if the CPU is to continue execution of the instruction or False if not. CPU is the CPU component which triggered the breakpoint, Address is the execution address, and Physical indicates whether the address is physical or virtual. Space indicates the address space for the breakpoint.
TMaster_Clock* Clock()
This function returns the instance of the Master clock object for the application. NULL is a valid return value and should be tested by any code calling this program (indicating that there is no master clock and timing issues are to be ignored).
TDebug_Interface* Debugger()
Returns a pointer to a debug interface for the UI Interface object. If debugging into the UI Interface is not supported, this returns NULL.
TCOM_Stream* Get_File_Stream( string Name )
Returns a stream for the passed (partial or full) filename. If the file cannot be opened/accessed, NULL is returned.
void Hide( bool Value )
Sets the UI visible state to Value. That is if Value is true, the UI is made visible. If Value is false, the UI is hidden.
void Idle( TComponent* Component )
Called by a blocked component (such as a CPU in wait state).
void Log_Error( TComponent* Component, string Text, integer Severity )
This logs an actual program error (exception or warning) from the specified component. Severity is one of the following values:
0 = Informational message
1 = Warning
2 = Non-fatal error
3 = Fatal error. The application should shut down.
void Log_Simulated_Error( TComponent* Component, string Text, integer Severity )
This logs a simulated hardware error from the specified component. Severity is one of the following values:
0 = Informational message
1 = Warning
2 = Non-fatal error
3 = Fatal simulated hardware failure.
void Log_Status( string Text, integer Index )
A component calls this method in response to a Show_Status request. Each call provides one line of status information. Index is 0 for the first line, 1 for the second, etc.
void Log_Trace( TComponent* Component, string Description )
Logs a trace event for the specified component.
void Signal_Change_Notice( TComponent* Component, integer Index, bool Active )
Called when a component changes a signal state. Index is the state index. Active is true if the new state of the signal is active.
void Signal_Exception( TComponent* Component, string Description, integer Index )
Called when a component suffers some form of exceptional condition in emulation that doesn't qualify as a hardware failure (which is reported via Log_Simulated_Error). Note that CPUS that support exception handling must report these exceptions via State_Change_Notice.
For instance, assume that a CPU encountered an invalid instruction. If the CPU handles this condition in a special manner (such as an "exception"), this would result in a state change, which is reported via State_Change_Notice. However, if the result of the CPU operation in this case is undefined, it should report the condition via this method and then continue on as the actual hardware would.
void State_Change_Notice( TComponent* Component, integer Index, bool Active )
Called when a state change occurs for the specified component. Index is the signal's index. Active is true if the state is true.
void Terminate
Destroys the component, which may terminate the application.
void Toggle_Embed( TComponent* Component )
Called when the specified visual component, via user action, requests a change to its embedded state. An embedded component may be stand- alone or embedded within the application (such as in a tabbed window). The UI may ignore this request.
integer Version()
Returns the version of the CEF specification that the UI adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
void Want_Signals( TComponent* Component, bool Value )
Notifies that UI that the specified component wants (Value true) or does not want (Value false) to receive Signal change notifications.
void Watchpoint_Notice( int64 Address, integer Access, integer Tag, TComponent* Component )
This method is called when a component triggers a watchpoint. Address is the address that triggered the watchpoint. Access indicates the type of access:
2 = Read (input)
3 = Write (output)
Tag is dependent upon the component and Component is the component which triggered the watchpoint.
Streaming interface
A stream is a collection of data that is accessed as an array of bytes. Some components may be able to save and/or restore their current states and/or contents. Also, assemblers may take a stream interface to a file in certain circumstances. The mechanism used to access a stream is the TCOM_Stream class. The methods in this class are:
TUEC Initialize()
Initializes the stream object.
TUEC Terminate()
Frees the stream object. No other method of object destruction may be used on the object. After this call, the instance is no longer valid. Note that Attach and Detach should be used as the means of object destruction.
void Attach()
Increments the reference count to the object.
void Detach()
Decrements the reference count to the object. If the reference count goes to zero, the object is destructed.
integer Interface_Version()
Returns the version of the interface to which the object conforms.
integer Facility_ID()
Returns facility ID for this streamer (see UEH).
integer Facility_Version()
Returns the version of the facility.
TDebug_Interface* Debugger()
Returns a debugging interface to the object. Returns NULL if not supported.
void* Extension()
Returns an extended interface. For now, this always returns NULL.
boolean At_End()
Returns True if there is no more data in the stream to read.
void Last_Error( TUEC& UEC )
Returns the last error code, and clears the error code.
TUEC Read( pointer Buffer, integer &Size )
Reads the specified number of bytes from the stream. Size is modified to be the actual bytes transferred. The read starts at the current position. After the read, the current position will be one byte past the end of the read data.
TUEC Read_Line( pointer Buffer, integer &Size )
Reads one line of input, up to the size of the buffer. The line is assumed to end at an ASCII 13 code. The ASCII 13 code is not included in the returned data. Size is modified to be the actual bytes transferred.
void Seek( integer Position )
Positions to the specified byte offset within the stream. The next read or write operation will start from this position.
integer Size()
Returns the size of the stream data, in bytes. -1 is returned if the size is unknown or larger than 2,147,483,647 bytes.
TUEC Write( pointer Buffer, integer size )
Writes the specified buffer, of the specified size in bytes, to the stream. The write operation starts at the current position and sets the current position to the byte immediately after the last written byte.
TUEC Write_Line( pointer Buffer )
Writes the specified null-terminated text to the stream. An ASCII code 13 is appended to the text on output.
Component interface
All component providers (eg DLLs) provide three API functions. The API definition is:
Integer Facility_Code()
This function returns a UEH facility code for the component class provided by Make_Instance.
pointer Make_Instance( integer Serial_Number, TUI_Interface* UI )
Make_Instance is responsible for creating an instance of the component and associating the UI Interface with the component. This instance is an object which is a descendant of the TComponent class. Serial_Number is a numeric value which is accessible via the Tcomponent's Serial_Number method. This can be used for any purpose desired and need not be unique.
integer Version()
Returns the version of the CEF specification that the API adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
Components
All components are instances of TComponent. The TComponent class defines the features common to all components and consists of the methods described in this section. Features that are unique to certain kinds of components (such as CPUs or memories), are accessed via another class whose methods handle those features. TComponent provides instances of these classes where appropriate. For instance, the CPU method provides a TCPU object for this component. However, if the component is not a CPU, this method would return a NULL. Note that it is possible for a component to provide a User_Interface object as well as one of the others. The methods specific to certain classes are:
Cable
CPU
Keyboard
Memory
User_Interface
TUEC Initialize( TUI_Interface* )
Reinitializes the component. Note that this is not a constructor! It is not necessary for the application to call this method, since Make_Instance should have initialized the component appropriately. This simply allows the component to be initialized again.
TUEC Terminate()
Terminates the component. Note that this is not a destructor, although it should eventually cause the instance to be destructed. By convention, once this method is called, the instance is no longer valid.
integer Serial_Number()
This method returns the number passed during creation (see Make_Instance).
TUEC Add_Notification( TComponent* Component )
Adds the specified component to the list of components to notify along with Parent in Child_Notifications.
TCable Cable()
Returns the TCable interface for a cable component. If the component is not a cable, this method returns NULL.
TComponent* Child_Component( integer Index )
This method returns the Indexth child component for this component. It returns NULL if Index is outside of the range: 0 <= n < Max_child_component. Child components are components owned by this component (such as a motherboard would own the CPU component).
void Child_Notification( TComponent* Child, longint &Notice, int64 ¶ms )
This is called by a component's child components to notify the parent asynchronously of some change. The usage of the params parameter depends upon the notice code. It is ignored unless otherwise specified. The Notice codes are:
0 = Child is about to terminate. As soon as the call returns, the child component will destruct.
1 = Child is requesting termination. If the Notice parameter is unchanged when the call returns, the child will go ahead and terminate. If Notice is set to 0 on return, the child will not terminate. Typically termination is cancelled when the parent component wishes to terminate the child itself.
2 = Child has received asynchronous data.
TUEC Clear_Watchpoint( int64 Address, boolean Memory, integer Access )
Clears a watchpoint at the specified address. Access is the type of access:
1 = Read or write (input or output)
2 = Read (input)
3 = Write (output)
integer Component_Type()
This method returns a value indicating the type of the component, as follows:
0 = Unknown (TComponent)
1 = CPU
2 = Bus
3 = Memory
4 = Motherboard
5 = I/O device
6 = User Interface
7 = Cable
8 = Keyboard
TUEC Connect_Input( TComponent* Component )
For components which accept input, this connects another component to this component's default input port.
TUEC Connect_Output( TComponent* Component )
For components which generate output, this connnects another component to this component's default output port.
TCPU* CPU()
Returns an instance of a TCPU object for this component. If the component is not a CPU, this method returns NULL. This is a reference to an object managed by this component and should not be freed or destructed by calling code.
TDebug_Interface* Debugger()
Returns a pointer to a debugger interface for this component. If the component doesn't support a debugger interface, this method returns NULL.
TUEC Delete_Notification( TComponent* Component )
This removes the specified component from the list of components to be notified. The component must have been added via Add_Notification.
TUEC Deposit( int64 Address, integer Size, pointer Buffer, boolean Memory )
This method writes Size bits of data from the specified address from the specified buffer. Memory is True if this is a memory write versus a I/O write. This is solely for the UI, and the write does no trigger watchpoints or have any other side-effects other than changing the contents of the component.
TUEC Disconnect_Input( TComponent* Component )
This disconnects the specified component from this component's default input port.
TUEC Disconnect_Output( TComponent* Component )
This disconnects the specified component from this component's default output port.
TUEC Examine( int64 Address, integer &Size, pointer Buffer, boolean Memory )
This method reads Size bits of data from the specified address into the specified buffer. Size is updated with the actual number of bits copied. Memory is True if this is a memory read versus an I/O read. This is solely for the UI - the read triggers no watchpoints and must have no other side-effects. In the case where an actual read would result in a change to a component's state, the examine must not make that change and the returned data should reflect what would be returned if a Read were done. Finally, access modes are ignored since this operation must always succeed if the address is valid.
integer Get_Access_Mode( int64 Address, boolean Memory )
Returns the access mode of the specified address. Return values are:
0 = Not supported (address out of range, etc.)
1 = Read/Write (I/O)
2 = Read-only (input-only)
3 = Write-only (write-only)
Memory is true if address is a memory address and false if it is an I/O address. See Set_Access_Mode for more details.
string Get_Exception_Description( integer Index )
Returns a description of the exception with the given index. If the index is invalid, the function returns NULL.
TComponent* Get_Parent()
Returns the parent component of this component. Returns NULL if there is no parent.
boolean Get_Profiling
Returns True if profiling for this component is on.
integer Get_Read_Latency()
Returns the component's default read latency. If the component doesn't support latency, this should return 0.
boolean Get_Signal( string Name, boolean& state )
Returns the state of a signal with the specified name. If the component recognizes the signal name, it returns True. Otherwise it returns False. If the result is True, state is set to the current state of the signal.
string Get_State_Name( integer index )
Returns the name of the state with the specified index. If the index is invalid, the function returns NULL.
integer Get_Tag()
Returns the component's tag value. See Set_Tag for details.
boolean Get_Trace()
Returns True if the component has tracing turned on.
integer Get_Write_Latency()
Returns the component's default write latency. If the component doesn't support latency, this should return 0.
TComponent* Input_Component( integer Index )
This method returns the Indexth input component for this component. It returns NULL if Index is outside of the range: 0 <= n < Max_input_component
TKeyboard* Keyboard()
Returns the TKeyboard interface for a keyboard component. If the component is not a keyboard, this method returns NULL.
TMemory Memory()
Returns the TMemory interface for a memory component. If the component is not memory, this method returns NULL.
string Name()
This method returns a string containing the name of this component.
TComponent* Output_Component( integer Index )
This method returns the Indexth output component for this component. It returns NULL if Index is outside of the range: 0 <= n < Max_output_component
TProfiler* Profiler()
Returns a profiler interface for the component. Profilers are described in another section.
boolean Read( int64 Address, integer Size, integer IO_Type )
Calling this method requests the component to transmit data to its default output port. Size is the number of bits being requested (0=default for component). The component should verify that the address is within its range before responding. If not, it should do nothing. If the component will respond to the request, the method returns true, otherwise it returns false. For CPUs, this reads the internal CPU memory cache. If the CPU doesn't have an internal memory cache, it should return False. IO_Type indicates the type of read operation:
0 = Memory read
1 = Port input
void Reset()
Reset the component. The behavior is implementation dependent.
TUEC Restore_Contents( TCOM_Stream* )
This method causes the component to restore its contents (but NOT state) from the passed stream. It is the responsibility of the component to restore the contents of any child components (but not attached components). For CPUs, the purpose of this is to restore cache contents.
TUEC Restore_State( TCOM_Stream* )
This method causes the component to restore its current state (but NOT contents) from the passed stream. It is the responsibility of the component to restore the state of any child components (but not attached components).
TUEC Save_Contents( TCOM_Stream* )
This method causes the component to save its contents (but NOT state) to the passed stream. It is the responsibility of the component to save the contents of any child components (but not attached components). For CPUs, the purpose of this is to store cache contents.
TUEC Save_State( TCOM_Stream* )
This method causes the component to save its current state (but NOT contents) to the passed stream. It is the responsibility of the component to save the state of any child components (but not attached components).
TUEC Set_Access_Mode( int64 Low, int64 High, boolean Memory. integer Type )
Sets the access mode of the specified address range (Low to High, inclusive). Type is:
1 = Read/Write (I/O)
2 = Read-only (input-only)
3 = Write-only (write-only)
Memory is true if address is a memory address and false if it is an I/O address. Note that a memory component has the same access mode for all addresses it handles, so if the address range overlaps that of the memory component, the new access mode applies to the entire address range of the component. The address range is n ot saved in the component, so if the valid address range is changed after the mode is set, the mode will remain as it was last set.
void Set_Parent( TComponent component )
Sets the component's parent. This value can be queried with Get_Parent.
void Set_Profiling( boolean On, boolean Children )
Turns profiling for this component on or off. Profiling is off by default. If Children is true, all child components will be assigned the same profiling value (this doesn't affect input or output components).
void Set_Read_Latency( integer Value )
Sets the component's default read latency in nanoseconds. If the component supports latency, it should block by this amount on each read.
void Set_Signal( string Name, boolean State )
Sets the state of a signal with the specified name. This should only be called with the signal actually changes state. That is, the value of state should never be the same on two consecutive calls. If it is, behavior is undefined.
void Set_Tag( integer Value )
Sets a user-defined value for the component, which can be queried via Get_Tag. The component does nothing with this value other than store it for retrieval with Get_Tag.
void Set_Trace( boolean Value )
Turns the component trace mode on if Value is True, and off otherwise.
void Set_Up( string Value )
Provides a means for a component-specific initialization string to be sent to the component after initialization. The format of this value and the component's behavior are implementation-specific.
TUEC Set_Watchpoint( int64 Address, boolean Memory, integer Access )
Sets a watchpoint at the specified address. When the component is about to access this address, it will generate a watchpoint notice to the UI interface. Access is the type of access:
1 = Read or write (input or output)
2 = Read (input)
3 = Write (output)
void Set_Write_Latency( integer Value )
Sets the component's default write latency in nanoseconds. If the component supports latency, it should block by this amount on each write.
void Show_Status()
Calling this method causes the component to report its status to the UI interface, in a human-readable form. For instance, a CPU component would report its registers and their contents.
void Signal_Change_Notice( TComponent* Component, integer Index, boolean Active )
Called when the specified component has a signal change. This is only called if the receiving component requested signal notices from the UI. Index is the signal index from the specified component.
integer Signal_Count()
Returns the number of signals defined (the maximum index plus 1).
string Signal_Name( integer Index )
Returns the name of the signal with the specified index. If the index is invalid, NULL is returned.
integer Signal_Index( string Name )
Returns the index of the signal with the specified name. If the name is invalid, -1 is returned.
boolean Signal_Out( integer Index )
Returns True if the signal is an output from the component. If the signal is an input to the component, the function returns False. If the index is invalid, the result is undefined.
boolean Signal_Active_Low( integer Index )
Returns True if the signal with the specified index is active when low (false). The Result is undefined if the index is invalid.
boolean Support_Feature( integer ID )
This method is reserved for future use.
TUser_Interface User_Interface()
Returns a TUser_Interface interface to the component. If the component is not a user interface, the method returns NULL.
integer Version()
Returns the version of the CEF specification that the UI adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
void Wake()
Calling this allows a component to resume its activity after it sends a Block request to the Master clock.
TUEC Write( int64 Address, integer Value, integer Size, integer IO_Type )
Calling this method writes Value to the component's input port with the specified address. Size is the number of bits in Value to write (0=default for component) and may be 0 to 32, inclusive. The component should verify that the address is within its range before responding. If not, it should do nothing. For CPUs, this writes to the internal CPU memory cache. If the CPU has no internal memory cache, it should return success. IO_Type indicates the type of write operation:
0 = Memory write
1 = Port output
TUEC Write_String( int64 Address, string Value, integer Size, integer IO_Type )
This is the same as calling Write_Byte once for each byte in the string, incrementing Address once per byte. It is provided to allow more efficient means of transmitting large amounts of data. Size is the number of bits in Value to write (0=default for component). The component should verify that the address is within its range before responding. If not, it should do nothing. For CPUs, this writes to the internal CPU memory cache. If the CPU has no internal memory cache, it should return success. IO_Type indicates the type of write operation:
0 = Memory write
1 = Port output
Profilers
A profiler is an interface to profiling information in a component. An instance of a profiler is requested from the component whose profile data is required. The profiler can then be queried for profile information. Integral to the design of profilers is the concept of domains. A profiler domain is a specific type of profiling data. A profiler may provide zero, one, or more domains. Examples of domains from a CPU component are numbers of calls to specific instructions, number of accesses to specific ports, and number of accesses to specific memory addresses. However, it should be noted that no component, including CPUs, are required to provide any profiling information or any specific domains. The methods of the TProfiler class are:
void Clear( integer Domain )
Clears all profiling information for the specified domain. If Domain is -1, all domains are cleared. The call is ignored if Domain is out of the range of valid domains.
string Domain_Name( integer Index )
Returns the domain name for the specified index. If the index is not a valid domain, the method returns NULL. The first domain is index 0.
string Report_Line( integer Domain, integer Index )
Returns a line of textual information associated with the specified domain. Index is the line of information to retrieve. The first line is index 0. If an invalid domain or index is passed, the method returns NULL.
integer Version()
Returns the version of the CEF specification that the object adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
CPUs
CPUs differ from most other components in that they usually take over the operation of the application once Marshalling is complete. Initialization of the CPU component doesn't begin operation (the TCPU.Run method does). That way, Marshalling can be completed prior to the CPU beginning operation. Functions unique to CPUs are accessed via the TCPU object, provided via the Tcomponent.CPU method.
CPUs support the concept of address spaces. There is always at least one address space (index 0), which is the default address space. An address space is a range of memory addresses. Some CPUs may only support a single address space which is accessed via the Program Counter (or Instruction Pointer). Other CPUs with virtual memory mapping may support a number of address spaces, each of which is indexed via a different register.
CPU's examine/deposit methods access the internal cache of the CPU (if Memory parameter is true) or the registers of the CPU (if Memory parameter is false). See the TCPU.Register_Name and TCPU.Register_Size methods for more information on the CPU registers. A CPU component returns a TCPU* instance when the CPU() method is called.
The TCPU class has the following methods:
boolean Big_Endian()
Returns True if the CPU processes data in a big-endian manner (most-significant bytes at lower addresses), or False if the CPU processes data in a little-endian manner (least significant bytes a re lower addresses).
TUEC Cancel_Breakpoint( int64 Address, integer Space, boolean Physical )
Clears a breakpoint at the specified address in the specified address space. If Physical is true, the address is a physical address, otherwise it is a virtual address.
TUEC Clear_Internal_Watchpoint( int64 Address, boolean Memory, integer Access )
Clears a watchpoint at the specified address. Access is the type of access:
1 = Read or write (input or output)
2 = Read (input)
3 = Write (output)
If Memory is true, the address is an internal cache address. Otherwise it is a register index.
integer Default_Base()
Indicates the specified base used by the CPU instruction set.
tUEC Disassemble( int64 Address, integer Base, integer Size, TCOM_Stream* )
Disassembles the instructions at the specified address, for the specified number of bytes and directs the output to the passed stream. Constants are shown in the specified base. If Base is 0, the CPUs default base is used.
integer Facility_Code()
This method returns the facility code for this object.
TAssembler* Get_Assembler( TMaster_Assembler* )
This method returns an assembler object for this CPU. It is passed a TMaster_Assembler object. See the section on the Assembler fo details.
integer Get_Clock_Speed()
Returns the CPU clock speed (in KHz).
int64 Get_Current_Address( integer Space, boolean Physical )
Returns the current CPU memory position for the specified address space.
int64 Get_Low_Memory()
Indicates the lowest physical memory address accessible by the CPU.
int64 Get_High_Memory()
Indicates the highest physical memory address accessible by the CPU.
int64 Get_Low_Port()
Indicates the lowest port address accessible by the CPU.
int64 Get_High_Port()
Indicates the highest port address accessible by the CPU.
int64 Get_Low_Virtual_Memory()
Indicates the lowest virtual memory address accessible by the CPU.
int64 Get_High_Virtual_Memory()
Indicates the highest virtual memory address accessible by the CPU.
void Halt()
Halts CPU execution. The effect upon the CPU is implementation-dependent.
boolean Halted()
Returns true if the CPU is in a halted state (non-execution mode).
string Memory_Space_Description( integer Index, boolean Physical )
Returns a description of the memory space with the specified index. It returns NULL for any invalid index. Physical is True for physical memory space and false for virtual address space. Most CPUs make no distinction between physical and virtual memory in this method.
integer Page_Size()
Returns the CPU's memory page size, in bytes. If the CPU doesn't support paging, this returns 0.
string Register_Description( integer Index )
Returns a description of the register associated with the specified index (0 is the first valid index). If the index is not valid, the function returns NULL. This is not the register name, but some additional information about the register. For instance, for a flags register, this would be a break-out of the flags in the register.
string Register_Name( integer Index )
Returns the name corresponding to the register index passed. A null string or NULL result indicates that the index is out of range. Note that all registers start at offset 0. Register 0 is always the current Instruction pointer (IP, PC, etc) and register 1 is always the current Stack pointer (SP).
integer Register_Size( integer Index )
Returns the size (in bits) of the register associated with the passed index. A result of 0 indicates that the index is out of range.
void Restart
Performs a power-on (cold) reset.
void Run()
Begins CPU execution from the current CPU state. Typically one instruction is executed, and then the CPU requests a block from the master clock.
void Run_From_Stream( TCOM_Stream* )
The causes the CPU to execute instructions directly from the passed stream. This is usually for immediate instruction execution from the user interface, thus no profiling is done, no breakpoints apply, and single-stepping does not occur.
TUEC Set_Breakpoint( int64 Address, integer Space, boolean Physical )
Sets a breakpoint at the specified address in the specified address space. When the CPU is about to begin execution at this address, it will generate a breakpoint notice to the UI interface. If Physical is true, the address is a physical address, otherwise it is a virtual address.
void Set_Clock_Speed( integer value )
Sets the CPU clock speed (in KHz).
void Set_Current_Address( integer Space, boolean Physical, int64 Value )
Sets the current CPU memory position for the specified address space. If Physical is true, the address is a physical address, otherwise it is a virtual address.
TUEC Set_Internal_Watchpoint( int64 Address, boolean Memory, integer Access )
Sets a watchpoint at the specified address. When the CPU is about to access this address, it will generate a watchpoint notice to the UI interface. Access is the type of access:
1 = Read or write (input or output)
2 = Read (input)
3 = Write (output)
If Memory is true, the address applies to internal cache. If Memory is false, address is the register.
void Step( boolean Into )
Executes a single instruction based on the current CPU context. This is the same as Run(), but execution doesn't continue after the CPU is unblocked. If Into is true, only a single instruction is excecuted. If Into is false, and the instruction to be executed is a nested instruction (such as a subroutine call), execution continues until the execution returns to the instruction following the call.
void Stop()
Stops CPU execution.
boolean Support_Virtual_Address()
Returns True if the CPU supports virtual address mapping.
int64 Top_Of_Stack( integer Index )
Returns the address of the top of the stack with the specified index. The first valid stack index is 0. For CPUs with only one stack, the stack is index 0.
int64 Translate( integer Space, int64 Address )
Returns the physical address for the passed virtual address in the passed address space. For a CPU with no virtual addresses, this returns the value passed.
integer Version()
Returns the version of the CEF specification that the object adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
Cable components
Cable components emulate a hardware cable, which connects other components. More specifically, this indicates one side of a cable, with the states matching the port that the cable is connected to. Simple cables, such as RS-232 serial cables, are usually connected to a port on one side and to another cable end on the other. Some cables have addresses (such as SCSI) and the normal Write operations should be used to supply an address in these cases. These cables are typically connected to multiple components, addressed via those addresses. Functions unique to cables are accessed via the TCable object, provided via the TComponent.Cable method.
The TCable class has the following methods:
Boolean Serial()
Returns true if this is a serial cable. False if parallel.
String Protocol()
Returns name of the protocol supported by this cable. Returns empty string if generic.
TUEC Transmit( int64 Speed, integer Value, integer Data_Size, integer Stop_Bits )
Calling this method transmits Value to the component. Speed is the transfer rate in bits/second. A speed of 0 indicates automatic speed matching between both ends of the cable. Data_Size is the number of bits in Value to write (0=default for component) and may be 0 to 32, inclusive. Stop bits indicate the number of stop bits for serial transfers. This calls Receive on connected cable components.
TUEC Transmit_String( int64 Speed, string Value, integer Data_Size, integer Stop_Bits )
This is the same as calling Transmit once for each byte in the string. It is provided to allow more efficient means of transmitting large amounts of data. Speed is the transfer rate in bits/second. A speed of 0 indicates automatic speed matching between both ends of the cable. Size is the number of bits in Value for each transmission (0=default for component). Stop_Bits indicates the number of stop bits for each transmit on serial transfers.
void Receive( TComponent Source, int64 Speed, integer Value, integer Data_Size, integer Stop_Bits )
Called by a Transmit from a connected cable component. Speed is the transfer rate in bits/second. A speed of 0 indicates automatic speed matching between both ends of the cable. Data_Size is the number of bits in Value to write (0=default for component) and may be 0 to 32, inclusive. Stop bits indicate the number of stop bits for serial transfers. THe component that the transmission is received from is passed in Source.
boolean Get_Data( int64 &Speed, integer &Value, integer &Data_Size, integer &Stop_Bits )
Returns the data last received. The function returns False if no data has been received since the last call to Get_Data. The parameters are ignored on call. On a successful return the parameters are filled with the data from the last Receive call.
Memory components
A Memory component is a data storage and retrieval component. Functions unique to memories are accessed via the TMemory object, provided via the TComponent.Memory method.
The TMemory class has the following methods:
void Dump( int64 Start, int64 Size, pointer Buffer )
Dumps an image of memory between Start and Start + Size - 1, inclusive, to the passed buffer, which must be large enough to hold Size bytes. Any range of addresses that are outside of the memory component's range are zero-filled.
void Get_Address_Range( int64& Low, int64& High )
Returns the set of addresses that this component responds to.
void Load( int64 Start, int64 Size, pointer Buffer )
Loads memory between Start and Start + Size - 1, inclusive, with data in the passed buffer. Any data outside of the memory component's range is ignored.
TUEC Set_Address_Range( int64 Low, int64 High )
Defines the set of addresses that this component responds to.
integer Version()
Returns the version of the CEF specification that the object adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
Assembler Status
Instances of the assembler status class are used to record the status of an assembly operation. The instance is created by the code that calls the master assembler's Assemble() method.
The TAssembler_Status class contains the following methods:
string Filename()
Returns the name of the current file being assembled.
boolean Get_Aborted()
Returns the current aborted state. Initially it is false but can be set via Set_Aborted.
int64 Get_Code()
Returns the number of bytes of generated Code.
int64 Get_Data()
Returns the number of bytes of generated Data.
integer Get_Errors()
Returns the count of serious and/or fatal errors.
integer Get_Warnings()
Returns the count of warnings.
string Get_Error_Text()
Returns the default error text set via Set_Error_Text.
void Set_Aborted( boolean Value )
Sets the aborted state.
void Set_Code( int64 Value )
Sets the code size, in bytes.
void Set_Data( int64 Value )
Sets the data size, in bytes.
void Set_Errors( integer Value )
Set error count.
void Set_Warnings( integer Value )
Set warning count.
void Set_Error_Text( string Value )
Sets the default error text.
void Get_Error( integer Index, string& Text, string& Filename, integer& Line, integer& Severity )
Retrieves the error information from the error list at the specified index (0 is the first). If the index is invalid the text will be set to NULL.
void Log_Error( string Text, string Filename, integer Line, integer Severity )
Add an error to the error list with the specified text, filename, line number and severity. If Line is -1, the current line is used. The current line is set via Set_Line. Severity is one of the following values:
0 = Informational message
1 = Warning
2 = Non-fatal error
3 = Fatal error
void Set_Line( integer Value )
Sets the current line number.
User Interface Components
User Interface components should not be confused with the TUI_Component object which is the interface between TComponent descendants and the main application. User Interface components are Components which provide a visual interface for the user. They operate in one of two modes: stand-alone and embedded. When embedded, user interface components are shown inside the application (assuming the application supports that). In Stand-alone mode the component shows apart from the application. Functions unique to User Interfaces are accessed via the TUser_Interface object, provided via the TComponent.User_Interface method.
The TUser_Interface class has the following methods:
boolean Get_Hidden()
Returns True if the component is currently visible.
void Set_Hidden( boolean Value )
Sets the component to hidden (if Value is true) or visible (if Value is false).
integer Get_Parent_Window()
Returns the handle of the component's parent window.
void Set_Parent_Window( integer Value )
Sets the component's parent to the window with the passed handle.
string Get_Caption()
Returns the caption of the component.
void Set_Caption( string Value )
Sets the caption of the component.
void Set_Size( integer Height, integer Width )
Sets the visual size of the component to the passed height and width, in pixels.
integer Optimal_Height()
Returns the optimal height of the component, in pixels.
integer Optimal_Width()
Returns the optimal width of the component, in pixels.
integer Version()
Returns the version of the CEF specification that the object adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
Keyboard Components
A keyboard component is a visual component that represents a particular keyboard layout. A CEF keyboard component doesn't send data associated with keystrokes, but rather uses key names. For some keys, names are simply "A", or "1". For others, the name represents the glyph or function of the key - for instance, "LEFT" or "BREAK". Each key name also has a corresponding index. A series of individual keys can be pressed together (for instance, SHIFT and a letter). Such a combination of keys is called a "keystroke". A keystroke ends when all keys are no longer pressed by the user. Note that some keys can lock into a down position and in a down state do not prevent a keystroke from completing. The keyboard component can notify connected components of key state changes, but the keyboard can also be queried for keystroke state. These operations operate in parallel and the application can use the component in a polled or interrupt fashion. However, when used in an interrupt fashion, the keyboard should be polled to clear its queue of keystrokes and prevent excessive memory usage.
The convention of a "NKP_" prefix is used for otherwise normal characters that occur on a numeric keypad. Thus "1" indicates a normal "1" key, but "NKP_1" indicates a "1" key from a numeric keypad. Any receiver of data from a keyboard component should strip "NKP_" from the front of a key name when interpreting keys UNLESS that receiver wishes to specifically distinguish between the two keys. Likewise, "LEFT_" prior to a key name indicates the left of two instances of a key (for instance, SHIFT), and "RIGHT_" indicates the right of the two keys. These conditions should be handled appropriately.
When a key is pressed or released, the component does a port write to connected components where the port number is the key index and the data is 1 for keydown or 0 for keyup.
TKeyboard provides special functions for accessing simple LEDs on the keyboard. For more complicated displays, the Write method should be used. Functions unique to keyboards are accessed via the TKeyboard object, provided via the TComponent.Keyboard method.
The TKeyboard class has the following methods:
PChar Get_Key()
Retrieves the next key in a keystroke from the keyboard. Returns NULL if no more keystrokes or a null string if end of current keystroke. Note that all keys returned by this method are appropriate for any corresponding key states. For instance, when the "A" key is pressed then if SHIFT is down, the returned key will be "A". If SHIFT is up, the returned key will be "a".
Boolean Get_Key_Down( string Name )
Returns True if the specified key is down in the pending keystroke. If Name is NULL, returns True if any key is down in the pending keystroke. It also returns False if the key name is unknown.
void Set_Key_Down( string Name, Boolean State )
Sets the state of a given key to up or down. The key is reset when the next keystroke is returned. This can be used to synchronize the keyboard component's visible state with the physical keyboard.
string Get_Key_Name( integer Index )
Returns the name of the key associated with the passed index. Returns NULL if the index is invalid. It is valid for different indexes to refer to the same key name. Typically this occurs for corresponding upper and lower-case letters.
boolean Get_LED_State( string Name )
Returns True if the specified LED is lit. If the LED name is not recognized, the function returns false.
void Set_LED_State( string Name, boolean State ) ;
Sets the state of a given LED to lit or not. This can be used to synchronize the keyboard component's visible state with the physical keyboard.
string Get_LED_Name( integer Index )
Returns the name of the LED associated with the passed index. Returns NULL if the index is invalid.
integer Version()
Returns the version of the CEF specification that the object adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
Further, keyboard components have special meanings for TComponent methods, as follows:
Reset()
Clears all pending keystrokes and sets all keys to the default state (usually up). A given implementation may also perform other functions during a Reset.
The Assembler
The process of assembly (compilation of CPU instructions) requires the cooperation of two objects: one TAssembler and one TMaster_Assembler. The master assembler controls the assembly process, but the TAssembler does the actual translation of CPU instructions into machine code. The scope of responsibility for each component is thus: the master assembler is responsible for all file I/O, including source, listings, and binaries. It is also responsible for handling general directives and formatting of output. The TAssembler is responsible for handling any unique directives, translation of synonym directives, and compiling the actual CPU instructions. All source tokens are passed first to the TAssembler. Anything it doesn't handle must be passed back to the Master Assembler (via the Expand method of the latter).
TAssembler methods:
void Initialize( TMaster_Assembler* )
Informs the assembler the a new assembly operation is beginning. This assembly will use the passed master assembler.
void Terminate
Informs the assembler that the current assembly operation is now complete.
TUEC Assemble( string inputs, string &outputs, string &machines, integer &machinel, int64 &address, integer &Segment, TAssembler_Status* Status )
This method assembles the source code in the inputs string. If inputs is a null string, the assembler should fetch the data from the master assembler (Get_Token method). Formatted output (if any) is returned in outputs, which is assumed to be in a human-readable form. Upon return, machines contains the generated machine code for the instruction(s) passed. machinel is the length of the data in machines. address is the target memory address where the machines data is to go. Segment is the current destination segment for the data in machines. It has the following values:
0 = Default code segment
1 = Default data segment
other = CPU-dependent or user-defined segments
machinel, address, and Segment are passed the current values from the master assembler, but the called assembler may change them. address is virtual (physical if virtual addressing not supported by CPU). Status is the status object to be used to log assembly status.
integer Default_Radix()
Returns the default radix (base) of numeric literals.
integer Default_Size()
Returns the default size of numeric literals, in bits.
integer Facility_Code()
Returns the facility code for this assembler (see UEH).
string Source_Extensions()
Returns a bar-delimited list of source file extensions. The first one is the default. Example: "asm|mac|txt"
string Valid_Symbol_Initial()
Returns a list of valid characters for starting a symbol name.
string Valid_Symbol_After()
Returns a list of valid characters for a symbol name, past the first.
integer Version()
Returns the version of the CEF specification that the object adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
Master Assembler
The master assembler provides the following services:
1) maintains a back-patch table so that symbols can be forward referenced.
2) manages a scoped symbol table. Adds and deletes are always done from the current scope, but reads look at previous scopes if the symbol is not found in the current scope.
3) manages the token stream passed to the Assemble() method.
4) provides standard directive and macro handling.
5) provides a means of mapping token positions to addresses.
TMaster_Assembler contains the following methods:
void Add_Reference( string Name, integer Size, int64 Address )
Adds a named reference to the back-patch table.
TUEC Add_Symbol( string Name, TSymbol_Record* P )
Adds a symbol to symbol table in the current scope. Name contains the name of the symbol and P contains specific information about the symbol.
TUEC Assemble( TCOM_Stream* Input, TCOM_Stream* Output, TCOM_Stream* Listing, TAssembler_Status* Status )
Assembles code from the Input stream, directing the image data to the Output stream, and placing any list output to the Listing stream. Note that Listing can be NULL if no listing is desired. Output can be NULL to do a syntax-check-only assembly. Status is used to log information.
void Backpatch( TAssembler_Status* Status, TCOM_Stream* Stream )
Apply all items in the back-patch table. Should be called after assembly is complete.
TUEC Evaluate( string X, int64& Value )
Evaluates an expression, returning the numeric value in Value.
TUEC Expand( string Source, string Res, integer& Res_Length, TAssembler_Status* Status )
This method is used during assembly by a TAssembler to insert assembly source in-place. For instance, translating a directive into a standard directive, or doing macro expansions, etc. If the expanded item is a directive that results in output, Res will be that output and Res_Length will be the size of that data, in bytes. Use In_Line if several lines of assembly (such as a macro definition) need to be inserted.
integer Facility_Code()
Returns the facility code for this assembler (see UEH).
boolean Get_Case_Sensitive()
Returns True if case sensitivity to identifier names is on.
TSymbol_Record* Get_Symbol( string Name )
Returns the symbol record for the identifier in Name. Returns NULL, if Name is undeclared.
string Get_Token()
Returns the next token in the input stream during an assembly. Returns a null string if an error occurs (such as no more input). This is useful for assemblers which need more input for a directive which is continued on additional lines.
string Grab_Line()
Returns entire current (remaining) input line from the token stream.
void In_Line( TCom_Stream* Input )
Inserts the data from the passed stream into the current token stream. Used Expand to insert only a single line.
void Log_Error( string Text, integer Severity )
Logs an assembly error. Severity indicates the seriousness of the error:
0 = Informational
1 = Warning
2 = Error
3 = Fatal error (abort assembly)
void Map( int64 Address )
Map current token position to the passed address.
string Peek_Token( boolean Same-Line )
Returns the next token from the token stream without removing the token from the stream.
void Pop_Scope()
Ends the current symbol table scope. All Symbols in the current scope are lost and the previous scope becomes the current scope.
void Push_Scope()
Begins a new symbol table scope.
void Put_Token( string Token )
Returns a token to the input stream during an assembly.
void Set_Case_Sensitive( boolean C )
Sets case sensitivity on identifier names.
void UnMap()
Removes the previous mapping added with Map().
integer Version()
Returns the version of the CEF specification that the object adheres to. This is the major.minor version times 10. For instance, a value of 20 indicates version 2.0.
TSymbol_Record is defined as follows:
Name |
Type |
Description |
Address |
Int64 |
Address of identifier's storage within segment. |
Segment |
integer |
Segment for identifier. |
Size |
Integer |
Size of identifier's data, in bits. |
Type |
integer |
Data type of identifier: 0 = Undefined 1 = Integer 2 = IEEE double-precision floating point 3 = string 4 = boolean 5 = character other = other |
Flags |
integer |
Flags for identifier and 1 = Constant and 2 - 32768 = reserved other = other |
Data |
Int64 |
Actual value of identifier, if < 65 bits |
DataP |
pointer |
Pointer to value, if > 64 bits |
The standard CEF directives are:
.ADDRESS directive
Format: .ADDRESS n
Defines data the size of the virtual address space. For instance, if the CPU maximum virtual address is FFFF (hex), this will define two bytes containing value "n".
.ALIGN directive
Format; .ALIGN {n}
Synonym: ALIGN
Align to next n bytes. n can be either a number or one of the following values:
BYTE
WORD
LONG
QUAD
OCTA
PARAGRAPH
PAGE
If a numeric value is specified, the byte alignment is equal to 2^n bytes. For instance, "ALIGN 2" would align to a 4 byte boundary. PARAGRAPH and OCTA are equivalent. PAGE depends on the CPU page size. If "n" is omitted, the directive is equivalent to "ALIGN PAGE".
.ASCIC directive
Format: .ASCIC s
ASCII data with length prefix byte. "s" is a string literal. See the .ASCII directive for details on its format.
.ASCII directive
Format: .ASCII s
ASCII data. "s" is a string literal. This literal must be delimited by a non-space character. The delimiter is whichever non-space character immediately follows the directive. The delimiter must occur at the end of the string as well. Multiple strings can follow so long as each is delimited. Examples:
.ASCII "This is text"
.ASCII <Some more text<
.ASCII 'This ''is ''also ''text'
.ASCIZ directive
Format: .ASCIZ s
ASCII data with terminating null byte. "s" is a string literal. See the .ASCII directive for details on its format.
.BCD directive
Format: .BCD n
Defines a Binary-coded Decimal formatted value of value n. Example:
.BCD 8228
.BLKA directive
Format: .BLKA n
Reserves n * x bytes of uninitialized data where "x" is the size of the virtual address space. For instance, assume that the CPU has a maximum virtual address of FFFF (hex). Thus, ".BLKA 3" would reserve 6 bytes.
.BLKB directive
Format: .BLKB n
Synonyms: DS n
.DS n
DEFS n
.DEFS n
Reserves n bytes of uninitialized data.
.BLKD directive
Format: .BLKD n
Reserves n * 8 bytes of uninitialized (double-precision floating-point) data.
.BLKF directive
Format: .BLKF n
Reserves n * 4 bytes of uninitialized (floating-point) data.
.BLKL directive
Format: .BLKL n
Reserves n * 4 bytes of uninitialized (long) data.
.BLKO directive
Format: .BLKO n
Reserves n * 16 bytes of uninitialized (octa) data.
.BLKQ directive
Format: .BLKQ n
Reserves n * 8 bytes of uninitialized (quad) data.
.BLKW directive
Format: .BLKW n
Reserved n * 2 bytes of uninitialized data.
.DB directive
Format: .DB n
Synonyms: DB n
DEFB n
.DEFB n
.BYTE n
.SIGNED_BYTE n
Format: .DB "n"
Synonyms: DB "n"
Reserves 1 byte of data. DB and .DB can be followed by a quoted single character. Otherwise the directive must be followed by an expression. The expression can include quoted characters. See the section on expressions for more details. Examples:
.DB '#'
.DB '0' - 32
.BYTE 33
.DEFINE directive
Format: .DEFINE s
Defines a conditional symbol. "s" is the symbol name. Example:
.DEFINE Test_Mode
.DEFM directive
Format: .DEFM "s"
Synonyms: DEFM "s"
Stores ASCII data. The ASCII data must be delimited by double quotes (") or single quotes ('). Multiple delimited strings may appear after the directive. Examples:
.DEFM 'This is ASCII text'
.DEFM 'He said, "It'"'s too bad"'"'
The second example stores the following:
He said, "It's too bad"
.DOUBLE directive
Format: .DOUBLE n
Synonyms: .D_FLOATING n
Defines Double-precision floating point data (8 bytes). "n" is a floating-point numeric value. Examples:
.DOUBLE 3.14159
.DWORD directive
Format: .DWORD n
Synonyms: DD n
.DD n
DEFD n
.DEFD n
Stores "n" as a 4 byte value. Example:
.DWORD 32767.
.ELSE directive
Format: .ELSE
This is used in conditional assembly. It is only valid within IF block. See the section on conditional assembly for details.
.END directive
Format: .END {a}
Synonyms: END {a}
End of assembly source. The assembler does not process any text past this directive. The optional address defines where code execution will begin.
.ENDC directive
Format: .ENDC
End conditional. Terminates an IF block. See the section on conditional assembly for details..
.ENDM directive
Format: .ENDM
Ends a macro. See the section on macros for details.
.ENDR directive
Format: .ENDR
Ends a repeat block started by .REPEAT, .IRP, or .IRPC.
.EOT directive
Format: .EOT
Null directive. Has no effect.
EQU directive
Format: s EQU v
Synonym: s = v
Equate symbol s to value v. Example:
Space EQU 32
Exclamation = 33
.ERROR directive
Format: .ERROR {s;}m
Generates an assembly-time error with text "m". An optional expression "s" is evaluated and shown as well.
.EVEN directive
Format: .EVEN
Synonyms: .ALIGN 1
Adjusts to an even address. If on an odd address, a byte of 0 is inserted.
.IIF directive
Format: .IIF condition {,}arguments, statement
Immediate conditional assembly. The condition and argument(s) must be separated by a space, tab, or comma. The arguments depend upon the condition. See the section on conditional assembly for details on conditions. If the condition is true, the statement will be assembled.
Example:
.IIF DEFINED Test_Mode, .DEFM "Testing"
.IF directive
Format: .IF condition arguments
Begins conditional assembly. See the section on conditional assembly for details.
.IF_ directives
.IF_TRUE conditional assembly. .IFT
.IF_FALSE conditional assembly. .IFF
.IF_TRUE_FALSE conditional assembly. .IFTF
Used to switch within an IF block. See the section on conditional assembly for details.
.INCLUDE directive
Format: .INCLUDE x
Synonyms: INCLUDE x
Includes another file at the current position. "x" is the name of the file to include. The entire remainder of the line after the directive is considered to be the file name.
.IRP directive
Format: .IRP symbol, arguments
Indefinite repeat. "symbol" is a symbol that is replaced with successive arguments within the repeat block, which is ended by the .ENDR directive. "arguments" is one or more areguments separeted by commas. The argument list is delimited by angle brackets (<>) or matched delimiters. Matched delimiters are indicated by using a circumflex (^) followed by the delimiter. Examples:
.IRP ARG,<32,33>
.BYTE ARG
.ENDR
.IRP ARG,^X0,64,127,129X
.BYTE ARG
.ENDR
.IRPC directive
Format: .IRPC symbol,string
Indefinite repeats characters in "string". "symbol" is a symbol that is replaced with successive chraracters within the repeat block, which is ended by the .ENDR directive. The string may be delimited as defined in the .IRP directive description. However, it is not required that the string be delimited. Examples:
.IRPC ARG,SYMBOL
.DB 'ARG'
.ENDR
.IRPC ARG,<TopsyTurvey>
.DB 'ARG'
.EDNR
.MACRO directive
Format: .MACRO name
Begins a macro definition. See the section on macros for details.
.MDELETE directive
Format: .MDELETE x
Deletes the macro named "x". This can be used within the named macro to allow it to execute only once.
.MEXIT directive
Format: .MEXIT
Exit a macro expansion before the .ENDM.
.NARG directive
Format: .NARG s
Determine number of macro arguments. The number of arguments passed
to the current macro is assigned to symbol "s". This is only valid
within a macro block. See the section on macros for more details.
.NCHR directive
Format: .NCHR symbol, string
Counts the number of characters in "string" and assigns that value to symbol "symbol". The primary purpose is for determining the length of macro arguments. "string" does not have to be delimited unless it starts with "<" or "^". It can be delimited between "<" and ">", or with any other character if that character is preceeded with a circumflex (^). Examples:
.NCHR COUNT, ARG
.NCHR COUNT, <How many?>
.NCHR C, ^XHow many?X
.ODD directive
Format: .ODD
Align to odd byte address.
ORG directive
Format: ORG a
Position the current instruction position to address "a". Also sets the destination address of subsequent assembled code.
.PACKED directive
Format: .PACKED n
Store a packed BCD value for n. Example:
.PACKED 123.45
.RADIX directive
Format: .RADIX n
Use base n for numeric literals. n must be in the range 2<=n<=36
.RADIX50 directive
Format: .RADIX50 s
Store radix-50 data for the string "s". Multiple strings, delimited by commas, may be specified. Example:
.RADIX50
.REF directives
Format: .REF1 n
Synonym: .BYTE n
Store 1 byte of data of value n. n must be an integer value.
Format: .REF2 n
Synonym: .WORD n
Store 2 bytes of data of value n. n must be an integer value.
Format: .REF4 n
Synonym: .LONG n
Store 4 bytes of data of value n. n must be an integer value.
Format: .REF8 n
Synonym: .QUAD n
Store 8 bytes of data of value n. n must be an integer value.
Format: .REF16 n
Synonym: .OCTA n
Store 16 bytes of data of value n. n must be an integer value.
.REMARK directive
Format: .REM{ARK}
Synonym: COMMENT
Source comment line. The entire line after the directive is ignored as a comment.
.REPEAT directive
Format: .REPEAT n
Synonym: .REPT n
Repeat a block n times, where n is an integer. The block is terminated with .ENDR.
.SINGLE directive
Format: .SINGLE n
Synonyms: .FLOAT n
.S_FLOATING n
Stores a single-precision (4 byte) floating-point value. Example:
.FLOAT 2.46E+10
.UNDEFINE directive
Format: .UNDEFINE s
Undefines symbol "s". The symbol is removed from the symbol table.
.WARN directive
Format: .WARN {s,}m
Synonym: .WARNING {s,}m
Generates an assembly-time warning with text "m". An optional expression "s" is evaluated and shown as well.
.WORD directive
Format: .WORD n
Synonyms: DW n
.DW n
DEFW n
.DEFW n
.SIGNED_WORD n
Stores 2 bytes of data of value n, where n is an integer.
The following symbols are defined:
Symbol |
Meaning |
. |
Current position. |
Numeric literals are assumed to be in the default radix unless their radix is overriden with one of the following suffixes:
Suffix |
Radix |
B |
2 |
D |
10 |
H |
16 |
O |
8 |
Q |
8 |
Any symbol followed by a colon is defined as a local address equivalent to its location. Any symbol followed by a double colon (::) is defined as a global address equivalent to its location.
Conditional assembly:
Conditional assembly is accomplished via the .IIF and .IF directives. The .IF directive begins a conditional block which is terminated with the .ENDC directive. .IF and .IIF use condition tests to determine if the conditional block is assembled. The valid conditional tests are as follows:
Conditional |
Synonym |
Complement |
Complement |
Description |
EQUAL |
EQ |
NOT_EQUAL |
NE |
Expression is equal to 0/not equal to 0. |
GREATER |
GT |
LESS_EQUAL |
LE |
Expression is greater than 0/less than or equal to 0. |
LESS_THAN |
LT |
GREATER_EQUAL |
GE |
Expression is less than 0/ greater than or equal to 0. |
DEFINED |
DF |
NOT_DEFINED |
NDF |
Symbol is defined/not defined. |
BLANK |
B |
NOT_BLANK |
NB |
Argument is blank/non blank. This is intended for use in macro definitions. |
IDENTICAL |
ODN |
DIFFERENT |
DIF |
Arguments are different/identical. This is intended for use in macro definitions. This uses two arguments instead of 1. |
Between the .IF and .ENDC directives, one or more conditional modifier directives can be used. The conditional modifier directives are .ELSE, .IF_TRUE, .IF_FALSE, and .IF_TRUE_FALSE. the .ELSE directive can be used to complement (invert) the conditional check. Also, the .IF_TRUE, .IF_FALSE, and .IF_TRUE_FALSE directives can be used to change what code gets assembled. The effect of a conditional modifier directive lasts until the next conditional modifier directive (or .ENDC) is encountered. Examples:
.IF DEFINED TEST
.BYTE 0
.ELSE
.BYTE 23
.IF EQUAL A
.INCLUDE special.asm
.ENDC
.IF_FALSE
.INCLUDE myfile.asm
.ENDC
.ENDC
Macros:
A macro definition starts with the .MACRO directive and ends with the .ENDM directive. A macro reference is simply the name of a previously-defined macro. A Macro definition may contain one or more formal arguments. Format:
.MACRO name {argument1{,argument2{...}}}
.
.
.
.ENDM
Macro names can include any character which allows macros to look like CPU instructions or even new directives. Macros are always checked before directives are processed, and before assembly is passed to the CPU assembler. Macros allow a single line in the source file to insert an arbitrarily long sequence of source lines into the source. This is properly called an in-line expansion. The assembler replaces the line containing the macro reference with the contents of the macro. It replaces any occurrence of formal arguments in the macro with the actual arguments specified on the macro line. This is called argument substitution.
Macros have two types of arguments: actual and formal. Actual arguments are the string literal values that follow the name of the macro on the line that references the macro name. Formal arguments are those that are specified in the definition of the macro. Formal and actual arguments have a strict positional relationship. In other words, the first actual argument replaces all occurrences of the first formal argument in the macro definition. The second actual argument replaces the second formal argument, and so forth. The number of actual arguments must be equal to, or less than, the number of formal arguments. If there are more actual arguments than formal arguments, the assembler reports an error. Both actual and formal arguments are separated with commas.
Note that string literals for actual parameters can contain commas as part of the literal if the string is delimited by single (') or double (") quotes. However, the quotes will be part of the string literal during argument substitution.
Default values can be specified in the macro definition. If no corresponding actual argument is supplied, the default value specified for the formal argument is used as the actual argument. Default values have the format:
formal_argument_name = default_value
For example:
.MACRO REC ARG1=0,ARG2=128,ARG3=255
.BYTE ARG1
.BYTE ARG2
.LONG ARG3
.ENDM
Assuming the above macro definition, the following line:
REC 1,2
would be expanded as:
.BYTE 1
.BYTE 2
.LONG 255
Actual arguments are substituted literally unless the argument is a symbol name preceded by a backslash (\), in which case the numeric value of the symbol is used instead. Example:
REC \A,2
Arguments can be concatenated within the macro by enclosing the formal argument within single quotes ('). Normally argument substitution is only done when the formal argument is found as a separate token in the macro definition. The apostrophes must delimit the text in the macro. Note that the apostrophes themselves do not appear in the macro expansion. For instance, if ARG1 is a format argument and TEST is used as the corresponding actual argument, then ABC'ARG1' in the macro block will be expanded to ABCTEST. Example of concatenation:
.MACRO CAT SIZE,NUM
.REF'SIZE' NUM
.ENDM
Labels can be used in macro blocks, however if the macro with labels is expanded more than once, duplicate label symbol errors will occur. Macros can create unique labels if the label is specified as a formal parameter preceeded by a question mark (?). Created unique labels range from 30000$ to 65535$. Each time a created unique label is required, the numeric part is incremented by 1. If the formal argument has a matching actual argument, that argument is used. Otherwise a label is created. Example of definition:
.MACRO CHOOSE ARG1,?LABEL
LABEL: .BYTE ARG1
.ENDM
The following shows two calls and the macro expansions for those calls, based on the foregoing definition:
CHOOSE 12
30000$: .BYTE 12
CHOOSE 32,10$
10$: .BYTE 32
Macros can be deleted with .MDELETE. They can also be nested. That is, a macro definition can contain a reference to another macro - even itself. However, one should be careful to avoid infinite recursion. The expansion of macros within macros only happens when the outer macro is expanded and the internal macro reference is assembled.
Expressions:
CEF master assemblers support the following arithmetic operators in places where expressions are allowed. Note that conforming implementations may provide supersets of this functionality.
Operator |
Description |
+ |
Addition |
- |
Subtraction or unary minus |
/ |
Division |
* |
Multiplication |
^ |
Exponentiation |
() |
Parentheses for evaluation ordering. |
Emulator Definition Files
Emulator definition files contain a series of commands used to marshall and configure a set of components to emulate a specific hardware platform. These files have a default extension of "CEF". They are plain text and contain one or more commands. Only one command may occur on a line and commands may not span lines. Blank lines are ignored by the application. If the application doesn't support a command, it may ignore it, but should not report an error (warnings are allowed). The valid commands are:
ASCII command
Format: ASCII
Changes memory display to ASCII from EBCDIC.
BYTE command
Format: BYTE
Changes memory display to BYTE view.
CAPTION command
Format: CAPTION text
Changes the application caption to the passed text. All text following the command on the line is used as the caption text.
CONNECT command
Format: CONNECT component1 component2
Connects two components. The outputs of component1 are connected to the inputs of component2. "component1" and "component2" are the names of loaded components. If the names contain spaces, the entire name must be enclosed by single quotes (') or double quotes (").
DISCONNECT command
Format; DISCONNECT component1 component2
Removes all connections between the two specified components. If the names contain spaces, the entire name must be enclosed by single quotes (') or double quotes (").
DOUBLE command
Format: DOUBLE
Changes memory display to double-long (8 byte) integers.
EBCDIC command
Format: EBCDIC
Changes memory display to EBCDIC from ASCII.
HIGH command
Format: HIGH address
Changes the highest shown address to the specified address.
LOAD command
Format: LOAD filespec{/NAME=name} {startup}
Loads a component from the specified file. The optional /NAME switch can be used to rename the component. It is this name that must be used in subsequent UNLOAD, CONNECT, and DISCONNECT commands. "startup" is a startup command to pass to the component. The text in the command is dependant upon the specific component being loaded. If the startup command contains any spaces, it must be delimited with a single (') or double (") quote.
LONG command
Format: LONG
Changes memory display to long (4 byte) integers.
LOW command
Format: LOW address
Changes the lowest shown address to the specified address.
RADIX command
Format: RADIX base
Changes the memory display to the specified base. The value must be between 2 and 36, inclusive, although a given application may support additional bases.
SIGNED command
Format: SIGNED
Changes the memory display to signed integers.
UNLOAD_ALL command
Format: UNLOAD_ALL
Unloads all components.
UNLOAD command
Format: UNLOAD name
Unloads the component with the specified name.
UNSIGNED command
Format: UNSIGNED
Changes the memory display to unsigned integers.
WORD command
Format: WORD
Changes memory display to 2 byte integers.
Application User Interface
The standard CEF user interface is defined in this section. The form of the interface is not described, only its base functionality. Extensions to the base functionality are allowed, and expected. The operations required are:
Assemble
The user must be able to assemble, via the CPU object, both an external file and input. Output may be directed to memory or to an external file.
Breakpoint
The user must be able to set a breakpoint on physical and virtual memory addresses.
Deposit
The user must be able to write to any component which accepts writes. He must be able to specify the address, value, and size of the write.
Disassemble
The user must be able to disassemble an address, or range of addresses, to the screen or to a file. The disassembly must be in a form which is syntactically acceptable by the Assembler.
Examine
The user must be able to read from any component which accepts reads. He must be able to specify the address or address range. The reads must be non-destructive. The output may be directed to the screen (classic examine), or to an external file (dump).
Exit
The user must be able to exit the emulator when he desires.
Help
The emulator must provide some form of instructions about its operation.
Load
The user must be able to restore the state and/or contents of any component from an external file created by the Save operation.
Halt
The user must be able to halt the CPU, as if a hardware halt.
Pause
The user must be able to asynchronously pause the CPU.
Profile
The user must be able to turn profiling on and off for any or all components. When on, the emulator must provide statistics on the usage of the components for whom profiling is enabled.
Reset
The user must be able to reset any component or the entire environment. There must be a means for reseting the CPU to a valid execution state should it not be in one (such as halted).
Run
The user must be able to start or resume CPU execution as desired, assuming the CPU is in a valid execution state (not halted, for instance).
Save
The user must be able to save the state and/or contents of any component, or of the entire environment to an external file for later loading.
Show
The user must be able to see a list of breakpoints and watches.
Step
The user must be able to execute a single instruction at the current CPU context. This can be of two modes: INTO means that no more than one instruction will execute. OVER means that execution continues until it returns to the next logical instruction.
Trace
The user must be able to log the execution trail to a file for later analysis.
Watch
The user must be able to set breakpoints on changed component states, specifically (at a minimum) memory contents, and CPU register contents.
Debug Interface
TDebug_Interface is used when debugging the component code itself by providing a way of examining the internals of the software component. For production versions of components, this is often not supported. The interface assumes a hierarchical form with the root of a component returning children representing internal objects. Each of those objects may have children, and so forth. TDebug_Interface is the class for this interface and has the following methods:
Integer Count()
Returns the number of child components under this level. If this is a terminal (leaf) node, the method returns 0.
String Get_Title()
Returns text representing this level (such as "Cached data").
boolean Has_Children()
Returns True if this node has children.
void Set_Title( string Value )
Sets the text representing this level.
void Activate()
Indicates that the user wished to activate this level. The behavior is undefined and up to the implementor. Typically, this does nothing unless this level is a terminal representing some complex data which is not viewable in a hierarchical form.
boolean Can_Change()
Returns True if this level can be modified.
TDebug_Interface Child( Integer Ordinal )
Returns a debug interface for the specified child level (first child level is 0).
void Kill()
Tells object to destroy itself.
string Modify( string Data, integer Size )
Modifies data. If Size is -1, Data is assumed to be null-terminated and its length is automatically determined. The result will be NULL or a pointer to a null string to indicate success and error text otherwise.
integer Get_Context()
Returns the context set via Set_Context().
void Set_Context( integer Value )
Sets a user-defined integer value. The debugger does nothing with this context except return it via Get_Context().
CEF Emulator Files
Files with an extension of ".cef" are supported to provide high-level definitions of emulators. These files need not be supported, but if they are then they must conform to the description in this section.
The files are plain-text files which contain space-delimited tokens defining commands and parameters. White space is ignored except as a means of separating tokens. In order to use white space for other means, it must be enclosed within a quoted token. A quoted token starts with a quote and ends when the same quote character is encountered again. Everything within the quotes, and the quote characters themselves, is considered part of the token. The double quote character (") and single quote (') are valid quote characters. One type of quote can be enclosed within a token delimited by the other type of quote. Since either may be used to quote a token, the other may be enclosed as literal text.
A given implementation may add additional commands to its definition file processing, but must support the following. It would be wise for such extensions to use command tokens containing dollar signs ($) or underscores (_) to avoid conflicts with future extensions to this specification, as those characters will never be used in anything required by future specifications. These are the required commands that supported by CEF Emulator Files.
Command |
Description |
CONNECT x y |
Connect component named x to component named y. Component y is connected to the output of x. Both components must be loaded. If the names contain spaces, they should be enclosed in quotes. |
DISCONNECT x y |
Disconnect component named x from component named y. If the names contain spaces, they should be enclosed in quotes. |
LOAD x {y} |
Load component from file named x. Optionally a command line can be passed to the component as y. If the command line contains spaces, it must be enclosed in quotes. "/NAME=z" may be appended to the end of the line, where z is the name by which this component will be referenced. |
RUN |
Starts execution of the (default) CPU. |
UNLOAD_ALL |
Removes all loaded components. |
UNLOAD x |
Removes component named x. If x contains spaces, it must be enclosed in quotes. |
File layouts
CEF defines the layout of State files and Dump files. A State file is used to save the emulated environment's state current state in such a way that the state can be reloaded at a later time and execution continue from that point as if it had never been interrupted. A Dump file is a dump of the contents of a component for various uses, including analysis and image save/restore. Both files begin with a 256-byte header. The following defines the layouts for file version 0.0.
Dump file layout:
Byte(s) |
Description |
0 |
255 |
1 |
255 |
0 |
(CEF) |
3 |
File format version number times 10 (1.2=12) |
4 |
0 (Dump file) |
5-8 |
Packed date/time stamp (optional - may be 0). |
9-16 |
First address in file. |
17-255 |
Reserved (should be 0). |
256+ |
Dump image. |
State file layout:
Byte(s) |
Description |
0 |
255 |
1 |
255 |
2 |
0 (CEF) |
3 |
File format version number times 10 (1.2=12). |
4 |
1 (State file) |
5-8 |
Packed date/time stamp (optional – can be 0). |
9-255 |
Reserved. Should be 0. |
256+ |
State image. |
The state image consists of a series of variable-length records, one after another, each starting with the following:
Byte(s) |
Description |
0-3 |
Facility code of component. |
4-7 |
Serial number of component. |
8+ |
State image. |
CEF UTILITIES SPECIFICATION
Introduction
The CEF Utilities Specification defines helpful classes, their semantics, and corresponding file formats. These utilities are provided to speed development of emulation and provide consistent behavior between them beyond that required by the CEF Core Specification. Note that this specification is build upon the CEF Core Specification. The implementation of this specification is contained within a single module with the following API:
integer Version()
This function returns a number indicating which version of the specification that this module implements, times 10. For instance 16 indicates version 1.6.
TCEF_Watchpoint_Manager Get_Watchpoint_Manager()
This creates a watchpoint manager and returns the instance to the caller.
TCEF_Character_Set Get_Character_Set()
This creates a character set and returns the instance to the caller.
TCEF_Key_Mapper Get_Key_Mapper()
This creates and returns a Key mapper object.
Watchpoints
The TCEF_Watchpoint class implements a single address watchpoint. And contains the following methods.
int64 Get_Address()
Returns the address of the watchpoint.
integer Get_Access()
Returns the CEF access code for the watchpoint.
void Set_Access( integer Value )
Sets the access code for the watchpoint.
PChar Serialize()
Returns a string containing the watchpoint in XML.
void Deserialize( PChar Image )
Creates the watchpoint from a serialized XML string.
Watchpoint Manager
The TCEF_Watchpoint_Manager class manages a set of watchpoints. They consist of the following methods.
void Clear ;
Deletes all watchpoints managed by this object.
TUEC Clear_Watchpoint( int64 Address, integer Access )
Removes the watchpoint for the address with the access code(s).
TCEF_Watchpoint Create_Watchpoint( int64 Address, integer Access )
Creates a watchpoint for the specified address with the specified access code(s). The watchpoint is returned.
integer Count()
Returns the number of watchpoint addresses being managed.
void Deserialize( PChar Source )
Creates watchpoints from a serialized XML string.
PChar Serialize()
Returns a string containing all of the watchpoints in XML.
void Terminate()
Destroys the object.
TCEF_Watchpoint Watchpoint_At( int64 Address )
Returns a watchpoint for the specified address with all access codes for that address set.
Key Mapping
The TCEF_Key_Mapper class is used to manage key-to-action mappings for the host system. For instance, on a Microsoft Windows system the F1 key could be mapped to some functionality. Key names are case-insensitive, but the mapping string is stored and returned as-is. In summary, the class manages a list of key name strings, a list of valid mapping strings, and a set of strings that contain the current mapping for a given key.
This class consists of the following methods:
void Add_Key( PChar Name )
Adds a key name to the object.
void Add_Mapping( PChar Name )
Adds a valid mapping that the user can choose.
void Clear_Keys( boolean Mapping_Only )
Deletes all key names, and associated mapping text. If Mapping_Only is true, the keys are left but current mapping text is cleared.
void Clear_Mappings()
Deletes all valid mappings.
boolean Query()
Queries the user for key remapping. Returns True if the user Okayed his changes and false otherwise.
PChar Mapping( PChar Name )
Returns the text associated with the given key name. If the key is not defined, the function returns NULL.
void Set_Mapping( PChar Key, PChar Mapping )
Associates a mapping to a key. If the specified key is not defined, this does nothing.
void Terminate()
Destructs the object.
Character Sets
The TCEF_Character_Set class manages a set of characters for use on screen or terminal components. Up to 256 glyphs can be defined in a character set, with the first having an index of 0. If asked to render a glyph with an index greater than 127 and the correspoding glyph does not exist, the object will attempt to render the glyph with Index - 128. In the case of an index less than 128, nothing happens if the requested glyph doesn't exist. The maximum glyph width supported by this component is 32 pixels. The maximum height is 64 pixels. The component doesn't support differing glyph heights and the height of the glyphs in the character set is defined by the last defined glyph in the set. Attempts to load a character set file with differing glyph heights will result in unpredictable behavior. The glyphs in the set are assumed to contain blank scan lines for inter-line spacing.
This class consists of the following methods.
boolean Get_Invert()
Returns True if the object is set to render characters in inverted video.
void Set_Invert( boolean Value )
If Value is True, the object is set to render characters in inverted video.
void Clear()
Deletes all glyphs in the character set.
boolean Draw( Handle, X, Y, Index : integer )
Renders character glyph Index on the window specified by Handle, at position X, Y.
boolean Has_Glyph( integer Index )
Returns True if a glyph with the specified index is defined in the character set.
integer Height()
Returns the height of the glyphs in the set, in pixels (or scan lines).
void Initialize()
Initializes the object.
void Load( string Name ) ;
Loads a character set from the file specified in Name. This only supports CEF character files (*.c).
void Terminate()
Destructs the object.
integer Width( integer Index )
Returns the width of the specified glyph, in pixels.
CEF Character files
These files define monochrome raster glyphs for character sets. The default extension is "c". These files are text files with optional header lines. Each glyph definition is on its own line and each line is terminated with a CRLF (new line). The first glyph encountered is assigned to index 0, the next to index 1, and so forth. There is no limit as to the number of glyphs defined in the file, but some character set classes may have limits as to the number of glyphs that can be defined.
If present, the header file consists of two lines. The first is
RASTER
and the second is a number indicating the maximum width of glyphs, in pixels. In the absence of a header, the glyphs are assumed to be 8 pixels wide.
All lines following the header define glyphs. A blank line will define a blank glyph, otherwise the lines contain information defining the pixels that make up the glyph. A line may end with a comment. Comments begin with a semicolon (;). Everything from the semicolon to the end of the line are ignored by the software. Each scan line of the glyph is delimited by a comma in the file line. The scan line is a number whose 2's-complement bit layout defines the pixels that are set on that scan line of the glyph. The number is interpreted depending upon the prefix for the number, as follows:
Prefix |
Meaning |
0b |
Rest of number is interpreted as binary. |
0B |
Same as 0b. |
0x |
Rest of number is interpreted as hexadecimal. |
0X |
Same as 0x. |
0 |
Number is interpreted as octal. |
Any other value is interpreted as a decimal numeric value.
Example lines defining glyphs with 11 scan lines:
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; Space
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00 ; ! (exclamation)