import original from hpcalc.org

This commit is contained in:
Gwenhael Le Moine 2022-03-21 11:05:59 +01:00
commit d7531876d4
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
125 changed files with 43983 additions and 0 deletions

85
BUGS.txt Normal file
View file

@ -0,0 +1,85 @@
2000-12-21 Ivan Cibrario Bertolotti <cibrario@refolo.iriti.cnr.it>
* >4.1, BUG: add installation support for IRIX and Ultrix
* >4.1, BUG: 'pack' exits with 'Chf initialization failed'
if setlocale() fails during Chf initialization; apply the same
patch as 'saturn'.
Reported by Julian Einwag <julian@brightstar.swin.de>
* >4.1, BUG: Bad interaction with 'Emulate3Buttons' option
of XFree86; need key memory or key dispatch delay.
Reported by Dean Darlison <dean@dasco.ltd.uk>
2000-11-30 Ivan Cibrario Bertolotti <cibrario@refolo.iriti.cnr.it>
* >3.17: with HP49 ROM 1.19-4, command-line activity
results in a lot of late hits during unconfig. Investigate
why, in this case, late hits do not result in immediate hits
in subsequent unconfigs.
* >3.17, Saturn.ad, BUG: some X Terminals, e.g. VXT2000,
don't have an Escape key; the existing conventions,
e.g. F11 for Escape on VXT2000, conflicts with the
existing shortcuts.
2000-11-28 Ivan Cibrario Bertolotti <cibrario@refolo.iriti.cnr.it>
* >3.17, Saturn.ad, BUG: some X Terminals, e.g. VXT2000, only have a
Delete (*not* BackSpace) key; make sure that backspace shortcut
is available anyway in baseTranslations.
2000-11-21 Ivan Cibrario Bertolotti <cibrario@refolo.iriti.cnr.it>
* >3.15, BUG: xmodem file transfers don't work with
big binary objects (like lib 258); flow control?
(Fixed in 3.17)
2000-11-20 Ivan Cibrario Bertolotti <cibrario@refolo.iriti.cnr.it>
* >3.15: Revise init/reset sequence to be ready to accept
interrupt requests during module initialization.
* >3.15: Reset bank switcher when '-reset' is asserted
2000-11-16 Ivan Cibrario Bertolotti <cibrario@refolo.iriti.cnr.it>
* >3.15, serial.c: Implement hangup on exit on pty;
kermit insists that 'A serial connection might still be active'
even when the emulator is no longer running.
(Possibly not a bug)
* >3.15: IRIX support
(Implemented in 3.16)
* >3.15, sutil: update with =recover code for HP49
(Updated in 4.1)
* >3.15, sutil: implement for HP48
(Implemented in 4.1)
* >=3.15, config.h, Ultrix: usleep() not supported;
disable REAL_CPU_SPEED on this platform
(Implemented in 3.16)
(NEW_FILE: config_x.h)
* >=3.15, Imakefile, Ultrix: EXTRA_TAIL_LIBRARIES = -li
(Implemented in 3.16)
* >=3.15, Chf, Ultrix: add default compile mode for unsupported
platforms
(Implemented in 3.16)
* =3.15, using.texi: pty name message no longer signaled
(Fixed in 3.16)
* >=3.15, serial.c: remove #error and install a dummy handler instead
(Fixed in 3.16; tested on already supported platforms and Ultrix)
* >=3.15, Saturn.ad, Ultrix: Keypad's numeric keys don't work;
they work removing the leading ':' specifier
(Fixed in 3.16, both code and documentation; tested on all platforms)
* =3.15, x11.c: remove XmNapplyCallback from file_sel_box
(Fixed in 3.16; tested on supported platforms)

10
Chf/Bugs Normal file
View file

@ -0,0 +1,10 @@
2001-01-25 Ivan Cibrario Bertolotti <cibrario@brontolo.iriti.cnr.it>
* Win32 support is limited to the Windows CE platform
* _REENTRANT is not supported on Win32.
2000-05-29 Ivan Cibrario Bertolotti <cibrario@brontolo.cstv.to.cnr.it>
* chf.texi: Bad punctuation characters after xref.
(Fixed in 2.2)

371
Chf/Chf.h Normal file
View file

@ -0,0 +1,371 @@
/* .+
.identifier : $Id: Chf.h,v 2.2 2001/01/25 11:56:44 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: Chf.h,v $, main header
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 2-May-1996
.keywords : *
.description :
This is the main header of the Condition Handling Facility
.include : stdio.h setjmp.h (Win32: tchar.h)
.notes :
$Log: Chf.h,v $
Revision 2.2 2001/01/25 11:56:44 cibrario
Added partial Win32 support (Windows CE only).
Revision 2.1 2000/05/26 14:10:08 cibrario
- Revised unwind context passing mechanism; redefined CHF_NULL_CONTEXT
- New macros: CHF_NULL_HANDLER, CHF_MAJOR_RELEASE_NUMBER,
CHF_MINOR_RELEASE_NUMBER
- New ChfAction value: CHF_UNWIND_KEEP; fixed spelling of ChfAction value:
CHF_SIGNALLING -> CHF_SIGNALING
- Added structured condition handling macros: ChfTry, ChfCatch, ChfEndTry
Revision 1.6 1997/01/15 13:41:20 cibrario
Defined the new data type ChfPointer, a generic (void *) pointer. Each
condition handler can have a private handler context pointer, of type
ChfPointer, that the function ChfPushHandler() stores and that is passed
to the handler when it's activated.
Fixed a wrong adjustment of the condition handlers stack pointer after
an unwind operation.
Revision 1.5 1996/10/04 09:45:30 cibrario
Updated the condition message format in the private header ChfPriv.h to
improve internationalization
Revision 1.4 1996/09/25 13:21:11 cibrario
Added macro CHF_LIBRARY_ID; it contains the current ID of the CHF library.
The module chf_init.o will contain it as a static char[] variable.
Revision 1.2 1996/06/11 13:02:10 cibrario
Added prototype for ChfGetTopCondition()
Revision 1.1 1996/05/28 12:56:47 cibrario
Initial revision
.- */
/* -------------------------------------------------------------------------
Win32 & UNICODE support
------------------------------------------------------------------------- */
#ifdef _WIN32
#define ChfChar TCHAR
#define ChfText(x) _T(x)
#define ChfSigjmp_buf jmp_buf
#define ChfSigsetjmp(x,y) setjmp(x)
#define ChfSiglongjmp(x,y) longjmp(x,y)
#else
#define ChfChar char
#define ChfText(x) x
#define ChfSigjmp_buf sigjmp_buf
#define ChfSigsetjmp(x,y) sigsetjmp(x,y)
#define ChfSiglongjmp(x,y) siglongjmp(x,y)
#endif
/* -------------------------------------------------------------------------
CHF implementation limits and other symbolic constants
------------------------------------------------------------------------- */
#define CHF_MAX_MESSAGE_LENGTH 256
#define CHF_UNKNOWN_LINE_NUMBER (-1)
#define CHF_UNKNOWN_FILE_NAME (ChfChar *)NULL
#define CHF_NULL_DESCRIPTOR (ChfDescriptor *)NULL
#define CHF_NULL_CONTEXT (void *)NULL
#define CHF_NULL_POINTER (ChfPointer *)NULL
#define CHF_NULL_HANDLER (ChfHandler)NULL
#define CHF_LIBRARY_ID ChfText("$Id: Chf.h,v 2.2 2001/01/25 11:56:44 cibrario Exp $")
#define CHF_MAJOR_RELEASE_NUMBER 2
#define CHF_MINOR_RELEASE_NUMBER 2
#define CHF_MODULE_NAMES_SET 1
#define CHF_SET 2
#define CHF_ERRNO_SET 3
/* -------------------------------------------------------------------------
Condition codes
------------------------------------------------------------------------- */
#define CHF_S_OK 0
#define CHF_F_COND_STACK_FULL 1 /* Condition stack is full */
#define CHF_F_HDLR_STACK_FULL 2 /* Handler stack is full */
#define CHF_F_HDLR_STACK_EMPTY 3 /* Handler stack is empty */
#define CHF_F_BAD_STATE 4 /* Bad CHF state for req. operation */
#define CHF_F_INVALID_ACTION 5 /* Invalid action from handler: %d */
#define CHF_F_MALLOC 6 /* Dynamic memory allocation failed */
#define CHF_F_NOT_AVAILABLE 7 /* Function not available */
#define CHF_F_SETLOCALE 10 /* setlocale() failed */
#define CHF_F_CATOPEN 11 /* catopen() failed */
/* -------------------------------------------------------------------------
Type definitions
------------------------------------------------------------------------- */
typedef enum /* Condition severity codes */
{
CHF_SUCCESS,
CHF_INFO,
CHF_WARNING,
CHF_ERROR,
CHF_FATAL
}
ChfSeverity;
typedef enum /* Condition handler action codes */
{
CHF_CONTINUE, /* Continue application */
CHF_RESIGNAL, /* Resignal to next handler */
CHF_UNWIND, /* Stack unwind */
CHF_UNWIND_KEEP /* Unwind, keep last cond. group */
}
ChfAction;
typedef int /* CHF options */
ChfOptions;
#define CHF_DEFAULT 0x0000 /* default flags */
#define CHF_ABORT 0x0001 /* use abort() instead of exit() */
typedef enum /* Current CHF state */
{
CHF_UNKNOWN,
CHF_IDLE,
CHF_SIGNALING,
CHF_UNWINDING,
CHF_SIGNAL_UNWINDING
}
ChfState;
typedef struct ChfDescriptor_S /* Condition descriptor */
{
int module_id; /* Module identifier */
int condition_code; /* Condition code */
ChfSeverity severity; /* Severity */
int line_number; /* Line # or CHF_UNK_LINE_NUMBER */
const ChfChar *file_name; /* File name or CHF_UNK_FILE_NAME */
ChfChar message[CHF_MAX_MESSAGE_LENGTH]; /* Partial message */
struct ChfDescriptor_S *next; /* Link to next descriptor */
}
ChfDescriptor;
typedef struct ChfTable_S /* Standalone message table */
{
int module; /* Module identifier */
int code; /* Condition code */
ChfChar *msg_template; /* Message template */
}
ChfTable;
typedef /* Generic pointer */
void *ChfPointer;
typedef /* Condition handler */
ChfAction (*ChfHandler)(
const ChfDescriptor *,
const ChfState,
ChfPointer
);
typedef /* Message retrieval 'get_message' function */
const ChfChar * (*ChfMrsGet)(
void *,
const int,
const int,
const ChfChar *default_message
);
typedef /* Message retrieval 'exit' function */
void (*ChfMrsExit)(
void *
);
/* -------------------------------------------------------------------------
Condition generation macros
------------------------------------------------------------------------- */
#if defined(CHF_EXTENDED_INFO)
#define ChfCondition \
ChfGenerate( \
CHF_MODULE_ID, \
ChfText(__FILE__), __LINE__,
#ifdef _WIN32
#define ChfErrnoCondition
#else
#define ChfErrnoCondition \
ChfGenerate( \
CHF_ERRNO_SET, \
ChfText(__FILE__), __LINE__, \
errno, \
CHF_ERROR \
)
#endif
#else
#define ChfCondition \
ChfGenerate( \
CHF_MODULE_ID, \
CHF_UNKNOWN_FILE_NAME, CHF_UNKNOWN_LINE_NUMBER,
#ifdef _WIN32
#define ChfErrnoCondition
#else
#define ChfErrnoCondition \
ChfGenerate( \
CHF_ERRNO_SET, \
CHF_UNKNOWN_FILE_NAME, CHF_UNKNOWN_LINE_NUMBER, \
errno, \
CHF_ERROR \
)
#endif
#endif
#define ChfEnd \
)
/* -------------------------------------------------------------------------
Structured condition handling
------------------------------------------------------------------------- */
#define ChfTry \
{\
ChfSigjmp_buf _chf_sigjmp_buf;\
if(ChfSigsetjmp(_chf_sigjmp_buf, 1) == 0)\
{\
ChfPushHandler(CHF_NULL_HANDLER, _chf_sigjmp_buf, CHF_NULL_POINTER);
#define ChfCatch \
ChfPopHandler();\
}\
else\
{
#define ChfEndTry \
ChfDiscard();\
}\
}
/* -------------------------------------------------------------------------
Other macros
------------------------------------------------------------------------- */
#define ChfGetNextDescriptor(d) (d)->next
#define ChfGetModuleId(d) (d)->module_id
#define ChfGetConditionCode(d) (d)->condition_code
#define ChfGetSeverity(d) (d)->severity
#define ChfGetLineNumber(d) (d)->line_number
#define ChfGetFileName(d) (d)->file_name
#define ChfGetPartialMessage(d) (d)->message
/* -------------------------------------------------------------------------
Function prototypes
------------------------------------------------------------------------- */
int ChfInit( /* Generic initialization */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
void *mrs_data, /* Message retrieval private data */
ChfMrsGet mrs_get, /* 'GetMessage' function */
ChfMrsExit mrs_exit, /* 'Exit' function */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
);
int ChfMsgcatInit( /* Initialization with msgcat subsystem */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
const ChfChar *msgcat_name, /* Name of the message catalog */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
);
int ChfStaticInit( /* Initialization with static message tables */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
const ChfTable *table, /* Static message table */
const size_t table_size, /* Size of the message table */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
);
int ChfWin32Init( /* Initialization within _WIN32 */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
#ifndef _WIN32
void *instance, /* Fake arguments */
#else
HINSTANCE instance, /* App. instance handle */
#endif
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
);
void ChfExit( /* Exit */
void
);
void ChfAbort( /* Abort application */
const int abort_code
);
void ChfPushHandler( /* Push a new handler into the stack */
ChfHandler new_handler, /* Handler to be added */
void *unwind_context, /* Unwind context */
ChfPointer handler_context /* Private handler context */
);
void ChfPopHandler( /* Pop a handler */
void
);
ChfChar *ChfBuildMessage( /* Build a condition message */
const ChfDescriptor *descriptor
);
void ChfSignal( /* Signal the current conditions */
void
);
void ChfDiscard( /* Discard the current conditions */
void
);
void ChfGenerate( /* Generate a condition into the stack */
const int module_id,
const ChfChar *file_name,
const int line_number,
const int condition_code,
const ChfSeverity severity,
...
);
const ChfChar *ChfGetMessage( /* Retrieve a condition message */
const int module_id,
const int condition_code,
const ChfChar *default_message
);
const ChfDescriptor *ChfGetTopCondition( /* Retrieve top condition */
void
);

155
Chf/ChfPriv.h Normal file
View file

@ -0,0 +1,155 @@
/* .+
.identifier : $Id: ChfPriv.h,v 2.2 2001/01/25 11:57:57 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: ChfPriv.h,v $, main header
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 2-May-1996
.keywords : *
.description :
This is the private header of the Condition Handling Facility
.include : *
.notes :
$Log: ChfPriv.h,v $
Revision 2.2 2001/01/25 11:57:57 cibrario
Added partial Win32 support (Windows CE only).
Revision 2.1 2000/05/26 14:14:36 cibrario
- Defined new abort codes: CHF_ABORT_GET_CONTEXT, CHF_ABORT_PTHREAD
- Redefined .unwind_context field of ChfHandlerDescriptor
- Conditional retarget of chf_context for multithreading support
- Declared new private function: _ChfGetContext() (mt support only)
Revision 1.6 1997/01/15 13:38:24 cibrario
Added the new field .handler_context to struct ChfHandlerDescriptor_S, to
store, for each condition handler, the private handler context pointer.
Revision 1.5 1996/10/04 09:43:51 cibrario
Updated the condition message format to improve internationalization
Revision 1.1 1996/05/28 12:56:37 cibrario
Initial revision
.- */
/* -------------------------------------------------------------------------
Macros
------------------------------------------------------------------------- */
#define CHF_MODULE_ID CHF_SET
#define CHF_TMP_MESSAGE_LENGTH (2*CHF_MAX_MESSAGE_LENGTH)
#define CHF_DEF_MESSAGE_LENGTH 40
#define CHF_DEF_PARTIAL_MSG_FMT ChfText("Code <%d>d")
#define CHF_DEF_MID_MSG_FMT ChfText("Mid <%d>d")
#define CHF_EXTENDED_INFO_FMT ChfText("(%s,%d)")
#define CHF_SEVERITY_NAMES \
{ ChfText("S"), ChfText("I"), ChfText("W"), ChfText("E"), ChfText("F") }
#define CHF_UNKNOWN_SEVERITY ChfText("?")
#define CHF_MESSAGE_SEPARATOR ChfText("-")
#define CHF_MESSAGE_TERMINATOR ChfText("\n")
#define CHF_ABORT_HEADER ChfText("ChfAbort-F-")
#define CHF_ABORT_BAD_CODE_FMT ChfText("Bad abort code <%d>d\n")
#define CHF_ABORT_GOOD_CODE_FMT ChfText("%s\n")
/* -------------------------------------------------------------------------
Abort codes used with ChfAbort()
------------------------------------------------------------------------- */
#define CHF_ABORT_SILENT 0
#define CHF_ABORT_INIT 1
#define CHF_ABORT_MSG_OVF 2
#define CHF_ABORT_INVALID_ACTION 3
#define CHF_ABORT_DUP_INIT 4
#define CHF_ABORT_ALREADY_UNWINDING 5
#define CHF_ABORT_IMPROPERLY_HANDLED 6
#define CHF_ABORT_FATAL_UNWINDING 7
#define CHF_ABORT_COND_STACK_OVF 8
#define CHF_ABORT_GET_CONTEXT 9
#define CHF_ABORT_PTHREAD 10
/* -------------------------------------------------------------------------
Type definitions
------------------------------------------------------------------------- */
typedef struct ChfHandlerDescriptor_S
{
ChfHandler handler;
void *unwind_context;
ChfPointer handler_context;
}
ChfHandlerDescriptor;
typedef struct ChfContext_S /* CHF Context */
{
ChfState state; /* Current CHF state */
const ChfChar *app_name; /* Application's name */
ChfOptions options; /* Options */
void *mrs_data; /* Message retrieval private data */
ChfMrsGet mrs_get; /* 'GetMessage' function */
ChfMrsExit mrs_exit; /* 'Exit' function */
int condition_stack_size; /* Size of the condition stack */
int handler_stack_size; /* Size of the handler stack */
int exit_code; /* Abnormal exit code */
ChfDescriptor *condition_stack; /* Condition stack */
ChfDescriptor *condition_base; /* Current condition stack base */
ChfDescriptor *condition_sp; /* Current condition stack pointer */
ChfHandlerDescriptor *handler_stack; /* Handler stack */
ChfHandlerDescriptor *handler_sp; /* Current handler stack pointer */
ChfChar *message_buffer; /* Message buffer */
}
ChfContext;
/* -------------------------------------------------------------------------
Multithreading support
------------------------------------------------------------------------- */
#ifdef _REENTRANT
#define chf_context (*_ChfGetContext())
#else
#define chf_context _chf_context
#endif
/* -------------------------------------------------------------------------
Global variables
------------------------------------------------------------------------- */
extern ChfContext _chf_context; /* CHF Context */
/* -------------------------------------------------------------------------
Private function prototypes
------------------------------------------------------------------------- */
#ifdef _REENTRANT
ChfContext *_ChfGetContext(void);
#endif
/* -------------------------------------------------------------------------
Private redirection of stdlib functions needed by Win32
------------------------------------------------------------------------- */
#ifdef _WIN32
#define ChfStrlen _tcslen
#define ChfStrcpy _tcscpy
#define ChfStrcat _tcscat
#define ChfStrncpy _tcsncpy
#define ChfSprintf _stprintf
#define ChfVsprintf _vstprintf
#else
#define ChfStrlen strlen
#define ChfStrcpy strcpy
#define ChfStrcat strcat
#define ChfStrncpy strncpy
#define ChfSprintf sprintf
#define ChfVsprintf vsprintf
#endif

209
Chf/Makefile Normal file
View file

@ -0,0 +1,209 @@
# ICB, 2-Oct-2000
# Minor off-line changes to support stand-alone build in saturn
#
# ICB, 16-Nov-2000
# Off-line change: added default compile mode for unsupported platforms
# .+
#
# .identifier : $Id: Makefile,v 2.1 2000/05/29 13:53:07 cibrario Rel $
# .context : CHF, Condition Handling Facility
# .title : $RCSfile: Makefile,v $, Makefile
# .kind : Makefile
# .author : Ivan Cibrario B.
# .site : CSTV-CNR
# .creation : 3-May-1996
# .keywords : *
# .description :
# Makefile for the CHF library
# .notes :
# $Log: Makefile,v $
# Revision 2.1 2000/05/29 13:53:07 cibrario
# - Deep revision to support transparent, multi-platform builds
# - Added multithreading support
# - New/revised targets: test, doc, clean
#
# Revision 1.2 1996/06/11 13:03:06 cibrario
# Added new module chf_top.c
#
# Revision 1.1 1996/05/29 09:12:10 cibrario
# Initial revision
#
#
# .-
#
# Platform-dependent definitions. Edit when required, for example to
# add a new platform.
#
# There is a set of definitions per platform; the prefix or the definition
# names is the value returned by a plain 'uname' on that platform.
#
# CC: cc compiler
# TS_CFLAGS: cc flags to enable multithreading
# TS_LOADLIBES: ld flags and additional libraries to enable multithreading
# F_CFLAGS: cc feature test macros
# O_CFLAGS: cc optimization control flags and other, additional flags
#
# Supported platforms:
# OSF1 Digital UNIX v4.0
# SunOS Solaris v2.6
# Linux Linux 2.1
#
# In addition, if the first build fails, a second attempt is made
# using the X_CC and X_CFLAGS fallback values.
OSF1_CC = cc
OSF1_TS_CFLAGS = -pthread
OSF1_TS_LOADLIBES = -pthread
OSF1_F_CFLAGS = "-D_POSIX_C_SOURCE=199506L -D_XOPEN_SOURCE"
OSF1_O_CFLAGS = "-O3 -std1"
SunOS_CC = gcc
SunOS_TS_CFLAGS = -D_REENTRANT
SunOS_TS_LOADLIBES = -lpthread
SunOS_F_CFLAGS = -D_POSIX_C_SOURCE=199506L
SunOS_O_CFLAGS = "-O3 -ansi -pedantic"
Linux_CC = cc
Linux_TS_CFLAGS = -D_REENTRANT
Linux_TS_LOADLIBES = -lpthread
Linux_F_CFLAGS = -D_POSIX_C_SOURCE=199506L
Linux_O_CFLAGS = "-O3 -ansi -pedantic"
#
# Destination paths for library objects, C headers, binaries, message catalog
# sources and X resource files. Edit as required.
#
DESTLIBDIR = $(HOME)/lib
DESTHDRDIR = $(HOME)/include
DESTBINDIR = $(HOME)/bin
DESTMSFDIR = $(HOME)/msf
DESTRESDIR = $(HOME)/res
#
# The default target recursively invokes make defining UNAME to the
# string returned by uname; this is used to make appropriate
# platform-dependent definitions above.
#
all:
@$(MAKE) UNAME=`uname` build || \
$(MAKE) UNAME=Unknown CC='"$(X_CC)"' O_CFLAGS='"$(X_CFLAGS)"' build
#
# Vectored definitions; see above and do not edit.
#
CC = $($(UNAME)_CC)
TS_CFLAGS = $($(UNAME)_TS_CFLAGS)
TS_LOADLIBES = $($(UNAME)_TS_LOADLIBES)
F_CFLAGS = $($(UNAME)_F_CFLAGS)
O_CFLAGS = $($(UNAME)_O_CFLAGS)
#
# Include common definitions
#
include Makefile_def
#
# Build directories for single-threaded and multi-threaded lib versions
#
ST_BUILD_DIR = ./st_build
MT_BUILD_DIR = ./mt_build
#
# Library names
#
ST_LIB_NAME = libChf.a
MT_LIB_NAME = libChf_r.a
#
# Library paths
#
ST_LIB_PATH = $(ST_BUILD_DIR)/$(ST_LIB_NAME)
MT_LIB_PATH = $(MT_BUILD_DIR)/$(MT_LIB_NAME)
#
# build: Create and populate build directories; for each build directory,
# make dependencies and rebuild
#
build: $(ST_LIB_PATH) $(MT_LIB_PATH)
#
# test: Build and executes test programs
#
test:
@$(MAKE) UNAME=`uname` do_test
@echo "All tests completed successfully"
do_test: $(ST_LIB_PATH) $(MT_LIB_PATH)
@cd $(ST_BUILD_DIR) && \
$(MAKE) test CC=$(CC) LIB=$(ST_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) > test.log 2>&1
@cd $(MT_BUILD_DIR) && \
$(MAKE) test CC=$(CC) LIB=$(MT_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) \
TS_CFLAGS=$(TS_CFLAGS) TS_LOADLIBES=$(TS_LOADLIBES) >> test.log 2>&1
#
# doc: Make documentation files
#
doc:
makeinfo chf.texi
texi2dvi chf.texi; dvips -o chf.ps chf.dvi
#
# clean: Remove build directories
#
clean:
rm -rf $(ST_BUILD_DIR) $(MT_BUILD_DIR)
#
# install: Move all files to their directories
# ICB, 23-Oct-2000: Do nothing
#
install: $(ST_LIB_PATH) $(MT_LIB_PATH) $(HDR) $(MSF) $(RES)
#
# Prepare the build directories for use
#
# ICB, 16-Nov-2000
# Off-line change: Force the build to fail with exit 1 if CC is undefined
#
$(ST_BUILD_DIR) $(MT_BUILD_DIR):
@[ "$(CC)" = "" ] && \
{ echo "Warning: using X_ defaults"; exit 1; } ; \
mkdir $@ && \
cd $@ && \
ln -s ../Makefile_sub Makefile && \
for s in $(SRC) $(TSRC) $(HDR) $(MSF) $(TMSF) $(RES) ; do \
ln -s ../$$s $$s ; \
done
#
# Make the libraries; the rebuild is forced here because only the
# sub-makes have module dependencies.
#
# ICB, 16-Nov-2000
# Off-line change: Force the build to fail with exit 1 if CC is undefined
#
$(ST_LIB_PATH): $(ST_BUILD_DIR) force
@[ "$(CC)" = "" ] && \
{ echo "Warning: using X_ defaults"; exit 1; } ; \
cd $(ST_BUILD_DIR) && \
$(MAKE) depend CC=$(CC) LIB=$(ST_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) && \
$(MAKE) all CC=$(CC) LIB=$(ST_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS)
$(MT_LIB_PATH): $(MT_BUILD_DIR) force
@[ "$(CC)" = "" ] && \
{ echo "Warning: using X_ defaults"; exit 1; } ; \
cd $(MT_BUILD_DIR) && \
$(MAKE) depend CC=$(CC) LIB=$(MT_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) \
TS_CFLAGS=$(TS_CFLAGS) TS_LOADLIBES=$(TS_LOADLIBES) && \
$(MAKE) all CC=$(CC) LIB=$(MT_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) \
TS_CFLAGS=$(TS_CFLAGS) TS_LOADLIBES=$(TS_LOADLIBES)
force:

68
Chf/Makefile_def Normal file
View file

@ -0,0 +1,68 @@
# .+
#
# .identifier : $Id: Makefile_def,v 2.2 2001/01/25 11:59:19 cibrario Exp $
# .context : CHF, Condition Handling Facility
# .title : $RCSfile: Makefile_def,v $, Makefile
# .kind : Makefile
# .author : Ivan Cibrario B.
# .site : CSTV-CNR
# .creation : 22-May-2000
# .keywords : *
# .description :
# Makefile for CHF library common definitions; no platform dependencies here.
# .notes :
# $Log: Makefile_def,v $
# Revision 2.2 2001/01/25 11:59:19 cibrario
# Added partial Win32 support (Windows CE only).
#
# Revision 2.1 2000/05/29 13:08:39 cibrario
# *** empty log message ***
#
#
# .-
#
# Source files
#
SRC = chf_init.c chf_gen.c chf_sig.c chf_abrt.c chf_hdlr.c \
chf_msgc.c chf_st.c \
chf_top.c \
chf_win32.c
TSRC = test01.c test02.c test03.c test04.c test05.c test06.c \
test07.c
HDR = Chf.h ChfPriv.h
MSF = chf.msf
TMSF = test01.msf
RES =
#
# Target object files
#
OBJ = $(SRC:.c=.o)
#
# Target test programs
#
TBIN = $(TSRC:.c=)
#
# Other definitions
#
HPATH = -I.
LPATH = -L.
CFLAGS = $(F_CFLAGS) $(O_CFLAGS) $(TS_CFLAGS) $(U_CFLAGS) $(HPATH)
LFLAGS = $(F_CFLAGS) $(L_CFLAGS) $(TS_LFLAGS) $(U_CFLAGS) $(HPATH)
LDFLAGS = $(LPATH)
LOADLIBES = $(LIB) $(TS_LOADLIBES) $(I_LOADLIBES) $(U_LOADLIBES)
#
# Solaris spelling of LOADLIBES
#
LDLIBS = $(LOADLIBES)

40
Chf/Makefile_sub Normal file
View file

@ -0,0 +1,40 @@
# .+
#
# .identifier : $Id: Makefile_sub,v 2.1 2000/05/29 13:08:51 cibrario Rel $
# .context : CHF, Condition Handling Facility
# .title : $RCSfile: Makefile_sub,v $, Makefile
# .kind : Makefile
# .author : Ivan Cibrario B.
# .site : CSTV-CNR
# .creation : 22-May-2000
# .keywords : *
# .description :
# Makefile for CHF library subdirectories
# .notes :
# $Log: Makefile_sub,v $
# Revision 2.1 2000/05/29 13:08:51 cibrario
# *** empty log message ***
#
#
# .-
#
# Include common definitions
#
include ../Makefile_def
#
# Targets
#
all: $(LIB)
$(LIB): $(OBJ)
$(AR) $(ARFLAGS) $@ $?
test: $(TBIN)
@for b in $(TBIN) ; do \
./$$b ; \
done
depend: $(SRC)
@makedepend $(HPATH) $(SRC)

52
Chf/RCS/Bugs,v Normal file
View file

@ -0,0 +1,52 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @# @;
2.2
date 2001.01.25.11.53.35; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.29.14.44.41; author cibrario; state Rel;
branches;
next ;
desc
@@
2.2
log
@*** empty log message ***
@
text
@2001-01-25 Ivan Cibrario Bertolotti <cibrario@@brontolo.iriti.cnr.it>
* Win32 support is limited to the Windows CE platform
* _REENTRANT is not supported on Win32.
2000-05-29 Ivan Cibrario Bertolotti <cibrario@@brontolo.cstv.to.cnr.it>
* chf.texi: Bad punctuation characters after xref.
(Fixed in 2.2)
@
2.1
log
@*** empty log message ***
@
text
@d1 6
d10 1
a10 1
@

611
Chf/RCS/Chf.h,v Normal file
View file

@ -0,0 +1,611 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @ @;
2.2
date 2001.01.25.11.56.44; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.26.14.10.08; author cibrario; state Rel;
branches;
next 1.6;
1.6
date 97.01.15.13.41.20; author cibrario; state Exp;
branches;
next 1.5;
1.5
date 96.10.04.09.45.30; author cibrario; state Beta;
branches;
next 1.4;
1.4
date 96.09.25.13.21.11; author cibrario; state Exp;
branches;
next 1.2;
1.2
date 96.06.11.13.02.10; author cibrario; state Exp;
branches;
next 1.1;
1.1
date 96.05.28.12.56.47; author cibrario; state Exp;
branches;
next ;
desc
@This is the main header of the Condition Handling Facility
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: Chf.h,v 2.1 2000/05/26 14:10:08 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: Chf.h,v $, main header
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 2-May-1996
.keywords : *
.description :
This is the main header of the Condition Handling Facility
.include : stdio.h setjmp.h (Win32: tchar.h)
.notes :
$Log: Chf.h,v $
Revision 2.1 2000/05/26 14:10:08 cibrario
- Revised unwind context passing mechanism; redefined CHF_NULL_CONTEXT
- New macros: CHF_NULL_HANDLER, CHF_MAJOR_RELEASE_NUMBER,
CHF_MINOR_RELEASE_NUMBER
- New ChfAction value: CHF_UNWIND_KEEP; fixed spelling of ChfAction value:
CHF_SIGNALLING -> CHF_SIGNALING
- Added structured condition handling macros: ChfTry, ChfCatch, ChfEndTry
Revision 1.6 1997/01/15 13:41:20 cibrario
Defined the new data type ChfPointer, a generic (void *) pointer. Each
condition handler can have a private handler context pointer, of type
ChfPointer, that the function ChfPushHandler() stores and that is passed
to the handler when it's activated.
Fixed a wrong adjustment of the condition handlers stack pointer after
an unwind operation.
Revision 1.5 1996/10/04 09:45:30 cibrario
Updated the condition message format in the private header ChfPriv.h to
improve internationalization
Revision 1.4 1996/09/25 13:21:11 cibrario
Added macro CHF_LIBRARY_ID; it contains the current ID of the CHF library.
The module chf_init.o will contain it as a static char[] variable.
Revision 1.2 1996/06/11 13:02:10 cibrario
Added prototype for ChfGetTopCondition()
Revision 1.1 1996/05/28 12:56:47 cibrario
Initial revision
.- */
/* -------------------------------------------------------------------------
Win32 & UNICODE support
------------------------------------------------------------------------- */
#ifdef _WIN32
#define ChfChar TCHAR
#define ChfText(x) _T(x)
#define ChfSigjmp_buf jmp_buf
#define ChfSigsetjmp(x,y) setjmp(x)
#define ChfSiglongjmp(x,y) longjmp(x,y)
#else
#define ChfChar char
#define ChfText(x) x
#define ChfSigjmp_buf sigjmp_buf
#define ChfSigsetjmp(x,y) sigsetjmp(x,y)
#define ChfSiglongjmp(x,y) siglongjmp(x,y)
#endif
/* -------------------------------------------------------------------------
CHF implementation limits and other symbolic constants
------------------------------------------------------------------------- */
#define CHF_MAX_MESSAGE_LENGTH 256
#define CHF_UNKNOWN_LINE_NUMBER (-1)
#define CHF_UNKNOWN_FILE_NAME (ChfChar *)NULL
#define CHF_NULL_DESCRIPTOR (ChfDescriptor *)NULL
#define CHF_NULL_CONTEXT (void *)NULL
#define CHF_NULL_POINTER (ChfPointer *)NULL
#define CHF_NULL_HANDLER (ChfHandler)NULL
#define CHF_LIBRARY_ID ChfText("$Id: Chf.h,v 2.1 2000/05/26 14:10:08 cibrario Exp $")
#define CHF_MAJOR_RELEASE_NUMBER 2
#define CHF_MINOR_RELEASE_NUMBER 2
#define CHF_MODULE_NAMES_SET 1
#define CHF_SET 2
#define CHF_ERRNO_SET 3
/* -------------------------------------------------------------------------
Condition codes
------------------------------------------------------------------------- */
#define CHF_S_OK 0
#define CHF_F_COND_STACK_FULL 1 /* Condition stack is full */
#define CHF_F_HDLR_STACK_FULL 2 /* Handler stack is full */
#define CHF_F_HDLR_STACK_EMPTY 3 /* Handler stack is empty */
#define CHF_F_BAD_STATE 4 /* Bad CHF state for req. operation */
#define CHF_F_INVALID_ACTION 5 /* Invalid action from handler: %d */
#define CHF_F_MALLOC 6 /* Dynamic memory allocation failed */
#define CHF_F_NOT_AVAILABLE 7 /* Function not available */
#define CHF_F_SETLOCALE 10 /* setlocale() failed */
#define CHF_F_CATOPEN 11 /* catopen() failed */
/* -------------------------------------------------------------------------
Type definitions
------------------------------------------------------------------------- */
typedef enum /* Condition severity codes */
{
CHF_SUCCESS,
CHF_INFO,
CHF_WARNING,
CHF_ERROR,
CHF_FATAL
}
ChfSeverity;
typedef enum /* Condition handler action codes */
{
CHF_CONTINUE, /* Continue application */
CHF_RESIGNAL, /* Resignal to next handler */
CHF_UNWIND, /* Stack unwind */
CHF_UNWIND_KEEP /* Unwind, keep last cond. group */
}
ChfAction;
typedef int /* CHF options */
ChfOptions;
#define CHF_DEFAULT 0x0000 /* default flags */
#define CHF_ABORT 0x0001 /* use abort() instead of exit() */
typedef enum /* Current CHF state */
{
CHF_UNKNOWN,
CHF_IDLE,
CHF_SIGNALING,
CHF_UNWINDING,
CHF_SIGNAL_UNWINDING
}
ChfState;
typedef struct ChfDescriptor_S /* Condition descriptor */
{
int module_id; /* Module identifier */
int condition_code; /* Condition code */
ChfSeverity severity; /* Severity */
int line_number; /* Line # or CHF_UNK_LINE_NUMBER */
const ChfChar *file_name; /* File name or CHF_UNK_FILE_NAME */
ChfChar message[CHF_MAX_MESSAGE_LENGTH]; /* Partial message */
struct ChfDescriptor_S *next; /* Link to next descriptor */
}
ChfDescriptor;
typedef struct ChfTable_S /* Standalone message table */
{
int module; /* Module identifier */
int code; /* Condition code */
ChfChar *msg_template; /* Message template */
}
ChfTable;
typedef /* Generic pointer */
void *ChfPointer;
typedef /* Condition handler */
ChfAction (*ChfHandler)(
const ChfDescriptor *,
const ChfState,
ChfPointer
);
typedef /* Message retrieval 'get_message' function */
const ChfChar * (*ChfMrsGet)(
void *,
const int,
const int,
const ChfChar *default_message
);
typedef /* Message retrieval 'exit' function */
void (*ChfMrsExit)(
void *
);
/* -------------------------------------------------------------------------
Condition generation macros
------------------------------------------------------------------------- */
#if defined(CHF_EXTENDED_INFO)
#define ChfCondition \
ChfGenerate( \
CHF_MODULE_ID, \
ChfText(__FILE__), __LINE__,
#ifdef _WIN32
#define ChfErrnoCondition
#else
#define ChfErrnoCondition \
ChfGenerate( \
CHF_ERRNO_SET, \
ChfText(__FILE__), __LINE__, \
errno, \
CHF_ERROR \
)
#endif
#else
#define ChfCondition \
ChfGenerate( \
CHF_MODULE_ID, \
CHF_UNKNOWN_FILE_NAME, CHF_UNKNOWN_LINE_NUMBER,
#ifdef _WIN32
#define ChfErrnoCondition
#else
#define ChfErrnoCondition \
ChfGenerate( \
CHF_ERRNO_SET, \
CHF_UNKNOWN_FILE_NAME, CHF_UNKNOWN_LINE_NUMBER, \
errno, \
CHF_ERROR \
)
#endif
#endif
#define ChfEnd \
)
/* -------------------------------------------------------------------------
Structured condition handling
------------------------------------------------------------------------- */
#define ChfTry \
{\
ChfSigjmp_buf _chf_sigjmp_buf;\
if(ChfSigsetjmp(_chf_sigjmp_buf, 1) == 0)\
{\
ChfPushHandler(CHF_NULL_HANDLER, _chf_sigjmp_buf, CHF_NULL_POINTER);
#define ChfCatch \
ChfPopHandler();\
}\
else\
{
#define ChfEndTry \
ChfDiscard();\
}\
}
/* -------------------------------------------------------------------------
Other macros
------------------------------------------------------------------------- */
#define ChfGetNextDescriptor(d) (d)->next
#define ChfGetModuleId(d) (d)->module_id
#define ChfGetConditionCode(d) (d)->condition_code
#define ChfGetSeverity(d) (d)->severity
#define ChfGetLineNumber(d) (d)->line_number
#define ChfGetFileName(d) (d)->file_name
#define ChfGetPartialMessage(d) (d)->message
/* -------------------------------------------------------------------------
Function prototypes
------------------------------------------------------------------------- */
int ChfInit( /* Generic initialization */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
void *mrs_data, /* Message retrieval private data */
ChfMrsGet mrs_get, /* 'GetMessage' function */
ChfMrsExit mrs_exit, /* 'Exit' function */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
);
int ChfMsgcatInit( /* Initialization with msgcat subsystem */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
const ChfChar *msgcat_name, /* Name of the message catalog */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
);
int ChfStaticInit( /* Initialization with static message tables */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
const ChfTable *table, /* Static message table */
const size_t table_size, /* Size of the message table */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
);
int ChfWin32Init( /* Initialization within _WIN32 */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
#ifndef _WIN32
void *instance, /* Fake arguments */
#else
HINSTANCE instance, /* App. instance handle */
#endif
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
);
void ChfExit( /* Exit */
void
);
void ChfAbort( /* Abort application */
const int abort_code
);
void ChfPushHandler( /* Push a new handler into the stack */
ChfHandler new_handler, /* Handler to be added */
void *unwind_context, /* Unwind context */
ChfPointer handler_context /* Private handler context */
);
void ChfPopHandler( /* Pop a handler */
void
);
ChfChar *ChfBuildMessage( /* Build a condition message */
const ChfDescriptor *descriptor
);
void ChfSignal( /* Signal the current conditions */
void
);
void ChfDiscard( /* Discard the current conditions */
void
);
void ChfGenerate( /* Generate a condition into the stack */
const int module_id,
const ChfChar *file_name,
const int line_number,
const int condition_code,
const ChfSeverity severity,
...
);
const ChfChar *ChfGetMessage( /* Retrieve a condition message */
const int module_id,
const int condition_code,
const ChfChar *default_message
);
const ChfDescriptor *ChfGetTopCondition( /* Retrieve top condition */
void
);
@
2.1
log
@- Revised unwind context passing mechanism; redefined CHF_NULL_CONTEXT
- New macros: CHF_NULL_HANDLER, CHF_MAJOR_RELEASE_NUMBER,
CHF_MINOR_RELEASE_NUMBER
- New ChfAction value: CHF_UNWIND_KEEP; fixed spelling of ChfAction value:
CHF_SIGNALLING -> CHF_SIGNALING
- Added structured condition handling macros: ChfTry, ChfCatch, ChfEndTry
@
text
@d3 1
a3 1
.identifier : $Id: Chf.h,v 1.6 1997/01/15 13:41:20 cibrario Exp cibrario $
d14 1
a14 1
.include : stdio.h setjmp.h
d18 8
d53 19
d77 1
a77 1
#define CHF_UNKNOWN_FILE_NAME (char *)NULL
d82 1
a82 1
#define CHF_LIBRARY_ID "$Id: Chf.h,v 1.6 1997/01/15 13:41:20 cibrario Exp cibrario $"
d85 1
a85 1
#define CHF_MINOR_RELEASE_NUMBER 1
d103 1
d153 2
a154 2
const char *file_name; /* File name or CHF_UNK_FILE_NAME */
char message[CHF_MAX_MESSAGE_LENGTH]; /* Partial message */
d163 1
a163 1
char *template; /* Message template */
d178 1
a178 1
const char * (*ChfMrsGet)(
d182 1
a182 1
const char *default_message
d199 1
a199 1
__FILE__, __LINE__,
d201 3
d207 1
a207 1
__FILE__, __LINE__, \
d211 1
d219 3
d229 1
d243 2
a244 2
sigjmp_buf _chf_sigjmp_buf;\
if(sigsetjmp(_chf_sigjmp_buf, 1) == 0)\
d279 1
a279 1
const char *app_name, /* Application's name */
d290 1
a290 1
const char *app_name, /* Application's name */
d292 1
a292 1
const char *msgcat_name, /* Name of the message catalog */
d299 1
a299 1
const char *app_name, /* Application's name */
d308 13
d339 1
a339 1
char *ChfBuildMessage( /* Build a condition message */
d353 1
a353 1
const char *file_name,
d360 1
a360 1
const char *ChfGetMessage( /* Retrieve a condition message */
d363 1
a363 1
const char *default_message
@
1.6
log
@Defined the new data type ChfPointer, a generic (void *) pointer. Each
condition handler can have a private handler context pointer, of type
ChfPointer, that the function ChfPushHandler() stores and that is passed
to the handler when it's activated.
Fixed a wrong adjustment of the condition handlers stack pointer after
an unwind operation.
@
text
@d3 1
a3 1
.identifier : $Id: Chf.h,v 1.5 1996/10/04 09:45:30 cibrario Beta cibrario $
d18 8
d52 1
a52 1
#define CHF_NULL_CONTEXT (jmp_buf *)NULL
d54 5
a58 1
#define CHF_LIBRARY_ID "$Id: Chf.h,v 1.5 1996/10/04 09:45:30 cibrario Beta cibrario $"
d98 2
a99 1
CHF_UNWIND /* Stack unwind */
d113 1
a113 1
CHF_SIGNALLING,
d202 23
d282 1
a282 1
jmp_buf *unwind_context, /* Unwind context */
@
1.5
log
@Updated the condition message format in the private header ChfPriv.h to
improve internationalization
@
text
@d3 1
a3 1
.identifier : $Id: Chf.h,v 1.4 1996/09/25 13:21:11 cibrario Exp cibrario $
d18 4
d45 2
a46 1
#define CHF_LIBRARY_ID "$Id: Chf.h,v 1.4 1996/09/25 13:21:11 cibrario Exp cibrario $"
d126 3
d132 2
a133 1
const ChfState
d246 2
a247 1
jmp_buf *unwind_context /* Unwind context */
@
1.4
log
@Added macro CHF_LIBRARY_ID; it contains the current ID of the CHF library.
The module chf_init.o will contain it as a static char[] variable.
@
text
@d3 1
a3 1
.identifier : $Id: Chf.h,v 1.2 1996/06/11 13:02:10 cibrario Exp cibrario $
d18 4
d41 1
a41 1
#define CHF_LIBRARY_ID "$Id$"
@
1.2
log
@Added prototype for ChfGetTopCondition()
@
text
@d3 1
a3 1
.identifier : $Id: Chf.h,v 1.1 1996/05/28 12:56:47 cibrario Exp cibrario $
d18 3
d37 1
@
1.1
log
@Initial revision
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$, main header
d17 3
a19 1
$Log$
d21 1
d262 4
@

298
Chf/RCS/ChfPriv.h,v Normal file
View file

@ -0,0 +1,298 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @ @;
2.2
date 2001.01.25.11.57.57; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.26.14.14.36; author cibrario; state Rel;
branches;
next 1.6;
1.6
date 97.01.15.13.38.24; author cibrario; state Exp;
branches;
next 1.5;
1.5
date 96.10.04.09.43.51; author cibrario; state Beta;
branches;
next 1.1;
1.1
date 96.05.28.12.56.37; author cibrario; state Exp;
branches;
next ;
desc
@This is the private header of the Condition Handling Facility
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: ChfPriv.h,v 2.1 2000/05/26 14:14:36 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: ChfPriv.h,v $, main header
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 2-May-1996
.keywords : *
.description :
This is the private header of the Condition Handling Facility
.include : *
.notes :
$Log: ChfPriv.h,v $
Revision 2.1 2000/05/26 14:14:36 cibrario
- Defined new abort codes: CHF_ABORT_GET_CONTEXT, CHF_ABORT_PTHREAD
- Redefined .unwind_context field of ChfHandlerDescriptor
- Conditional retarget of chf_context for multithreading support
- Declared new private function: _ChfGetContext() (mt support only)
Revision 1.6 1997/01/15 13:38:24 cibrario
Added the new field .handler_context to struct ChfHandlerDescriptor_S, to
store, for each condition handler, the private handler context pointer.
Revision 1.5 1996/10/04 09:43:51 cibrario
Updated the condition message format to improve internationalization
Revision 1.1 1996/05/28 12:56:37 cibrario
Initial revision
.- */
/* -------------------------------------------------------------------------
Macros
------------------------------------------------------------------------- */
#define CHF_MODULE_ID CHF_SET
#define CHF_TMP_MESSAGE_LENGTH (2*CHF_MAX_MESSAGE_LENGTH)
#define CHF_DEF_MESSAGE_LENGTH 40
#define CHF_DEF_PARTIAL_MSG_FMT ChfText("Code <%d>d")
#define CHF_DEF_MID_MSG_FMT ChfText("Mid <%d>d")
#define CHF_EXTENDED_INFO_FMT ChfText("(%s,%d)")
#define CHF_SEVERITY_NAMES \
{ ChfText("S"), ChfText("I"), ChfText("W"), ChfText("E"), ChfText("F") }
#define CHF_UNKNOWN_SEVERITY ChfText("?")
#define CHF_MESSAGE_SEPARATOR ChfText("-")
#define CHF_MESSAGE_TERMINATOR ChfText("\n")
#define CHF_ABORT_HEADER ChfText("ChfAbort-F-")
#define CHF_ABORT_BAD_CODE_FMT ChfText("Bad abort code <%d>d\n")
#define CHF_ABORT_GOOD_CODE_FMT ChfText("%s\n")
/* -------------------------------------------------------------------------
Abort codes used with ChfAbort()
------------------------------------------------------------------------- */
#define CHF_ABORT_SILENT 0
#define CHF_ABORT_INIT 1
#define CHF_ABORT_MSG_OVF 2
#define CHF_ABORT_INVALID_ACTION 3
#define CHF_ABORT_DUP_INIT 4
#define CHF_ABORT_ALREADY_UNWINDING 5
#define CHF_ABORT_IMPROPERLY_HANDLED 6
#define CHF_ABORT_FATAL_UNWINDING 7
#define CHF_ABORT_COND_STACK_OVF 8
#define CHF_ABORT_GET_CONTEXT 9
#define CHF_ABORT_PTHREAD 10
/* -------------------------------------------------------------------------
Type definitions
------------------------------------------------------------------------- */
typedef struct ChfHandlerDescriptor_S
{
ChfHandler handler;
void *unwind_context;
ChfPointer handler_context;
}
ChfHandlerDescriptor;
typedef struct ChfContext_S /* CHF Context */
{
ChfState state; /* Current CHF state */
const ChfChar *app_name; /* Application's name */
ChfOptions options; /* Options */
void *mrs_data; /* Message retrieval private data */
ChfMrsGet mrs_get; /* 'GetMessage' function */
ChfMrsExit mrs_exit; /* 'Exit' function */
int condition_stack_size; /* Size of the condition stack */
int handler_stack_size; /* Size of the handler stack */
int exit_code; /* Abnormal exit code */
ChfDescriptor *condition_stack; /* Condition stack */
ChfDescriptor *condition_base; /* Current condition stack base */
ChfDescriptor *condition_sp; /* Current condition stack pointer */
ChfHandlerDescriptor *handler_stack; /* Handler stack */
ChfHandlerDescriptor *handler_sp; /* Current handler stack pointer */
ChfChar *message_buffer; /* Message buffer */
}
ChfContext;
/* -------------------------------------------------------------------------
Multithreading support
------------------------------------------------------------------------- */
#ifdef _REENTRANT
#define chf_context (*_ChfGetContext())
#else
#define chf_context _chf_context
#endif
/* -------------------------------------------------------------------------
Global variables
------------------------------------------------------------------------- */
extern ChfContext _chf_context; /* CHF Context */
/* -------------------------------------------------------------------------
Private function prototypes
------------------------------------------------------------------------- */
#ifdef _REENTRANT
ChfContext *_ChfGetContext(void);
#endif
/* -------------------------------------------------------------------------
Private redirection of stdlib functions needed by Win32
------------------------------------------------------------------------- */
#ifdef _WIN32
#define ChfStrlen _tcslen
#define ChfStrcpy _tcscpy
#define ChfStrcat _tcscat
#define ChfStrncpy _tcsncpy
#define ChfSprintf _stprintf
#define ChfVsprintf _vstprintf
#else
#define ChfStrlen strlen
#define ChfStrcpy strcpy
#define ChfStrcat strcat
#define ChfStrncpy strncpy
#define ChfSprintf sprintf
#define ChfVsprintf vsprintf
#endif
@
2.1
log
@- Defined new abort codes: CHF_ABORT_GET_CONTEXT, CHF_ABORT_PTHREAD
- Redefined .unwind_context field of ChfHandlerDescriptor
- Conditional retarget of chf_context for multithreading support
- Declared new private function: _ChfGetContext() (mt support only)
@
text
@d3 1
a3 1
.identifier : $Id: ChfPriv.h,v 1.6 1997/01/15 13:38:24 cibrario Exp cibrario $
d18 6
d45 11
a55 10
#define CHF_DEF_PARTIAL_MSG_FMT "Code <%d>d"
#define CHF_DEF_MID_MSG_FMT "Mid <%d>d"
#define CHF_EXTENDED_INFO_FMT "(%s,%d)"
#define CHF_SEVERITY_NAMES { "S", "I", "W", "E", "F" }
#define CHF_UNKNOWN_SEVERITY "?"
#define CHF_MESSAGE_SEPARATOR "-"
#define CHF_MESSAGE_TERMINATOR "\n"
#define CHF_ABORT_HEADER "ChfAbort-F-"
#define CHF_ABORT_BAD_CODE_FMT "Bad abort code <%d>d\n"
#define CHF_ABORT_GOOD_CODE_FMT "%s\n"
d91 1
a91 1
const char *app_name; /* Application's name */
d104 1
a104 1
char *message_buffer; /* Message buffer */
d132 21
@
1.6
log
@Added the new field .handler_context to struct ChfHandlerDescriptor_S, to
store, for each condition handler, the private handler context pointer.
@
text
@d3 1
a3 1
.identifier : $Id: ChfPriv.h,v 1.5 1996/10/04 09:43:51 cibrario Beta cibrario $
d18 4
d64 2
d76 1
a76 1
jmp_buf *unwind_context;
d103 10
d116 1
a116 1
extern ChfContext chf_context; /* CHF Context */
d120 1
a120 1
Function prototypes
d122 3
@
1.5
log
@Updated the condition message format to improve internationalization
@
text
@d3 1
a3 1
.identifier : $Id: ChfPriv.h,v 1.1 1996/05/28 12:56:37 cibrario Exp cibrario $
d18 3
d71 1
@
1.1
log
@Initial revision
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$, main header
d17 3
a19 1
$Log$
d21 1
d35 1
a35 2
#define CHF_SEVERITY_NAMES { "success", \
"info", "warning", "error", "fatal" }
d37 1
a37 1
#define CHF_MESSAGE_SEPARATOR ": "
d39 1
a39 1
#define CHF_ABORT_HEADER "ChfAbort: "
@

333
Chf/RCS/Makefile,v Normal file
View file

@ -0,0 +1,333 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @# @;
2.1
date 2000.05.29.13.53.07; author cibrario; state Rel;
branches;
next 1.2;
1.2
date 96.06.11.13.03.06; author cibrario; state Beta;
branches;
next 1.1;
1.1
date 96.05.29.09.12.10; author cibrario; state Exp;
branches;
next ;
desc
@Makefile for the CHF library
@
2.1
log
@- Deep revision to support transparent, multi-platform builds
- Added multithreading support
- New/revised targets: test, doc, clean
@
text
@# .+
#
# .identifier : $Id: Makefile,v 1.2 1996/06/11 13:03:06 cibrario Beta cibrario $
# .context : CHF, Condition Handling Facility
# .title : $RCSfile: Makefile,v $, Makefile
# .kind : Makefile
# .author : Ivan Cibrario B.
# .site : CSTV-CNR
# .creation : 3-May-1996
# .keywords : *
# .description :
# Makefile for the CHF library
# .notes :
# $Log: Makefile,v $
# Revision 1.2 1996/06/11 13:03:06 cibrario
# Added new module chf_top.c
#
# Revision 1.1 1996/05/29 09:12:10 cibrario
# Initial revision
#
#
# .-
#
# Platform-dependent definitions. Edit when required, for example to
# add a new platform.
#
# There is a set of definitions per platform; the prefix or the definition
# names is the value returned by a plain 'uname' on that platform.
#
# CC: cc compiler
# TS_CFLAGS: cc flags to enable multithreading
# TS_LOADLIBES: ld flags and additional libraries to enable multithreading
# F_CFLAGS: cc feature test macros
# O_CFLAGS: cc optimization control flags and other, additional flags
#
# Supported platforms:
# OSF1 Digital UNIX v4.0
# SunOS Solaris v2.6
# Linux Linux 2.1
#
OSF1_CC = cc
OSF1_TS_CFLAGS = -pthread
OSF1_TS_LOADLIBES = -pthread
OSF1_F_CFLAGS = "-D_POSIX_C_SOURCE=199506L -D_XOPEN_SOURCE"
OSF1_O_CFLAGS = "-O3 -std1"
SunOS_CC = gcc
SunOS_TS_CFLAGS = -D_REENTRANT
SunOS_TS_LOADLIBES = -lpthread
SunOS_F_CFLAGS = -D_POSIX_C_SOURCE=199506L
SunOS_O_CFLAGS = "-O3 -ansi -pedantic"
Linux_CC = cc
Linux_TS_CFLAGS = -D_REENTRANT
Linux_TS_LOADLIBES = -lpthread
Linux_F_CFLAGS = -D_POSIX_C_SOURCE=199506L
Linux_O_CFLAGS = "-O3 -ansi -pedantic"
#
# Destination paths for library objects, C headers, binaries, message catalog
# sources and X resource files. Edit as required.
#
DESTLIBDIR = $(HOME)/lib
DESTHDRDIR = $(HOME)/include
DESTBINDIR = $(HOME)/bin
DESTMSFDIR = $(HOME)/msf
DESTRESDIR = $(HOME)/res
#
# The default target recursively invokes make defining UNAME to the
# string returned by uname; this is used to make appropriate
# platform-dependent definitions above.
#
default:
@@$(MAKE) UNAME=`uname` all
#
# Vectored definitions; see above and do not edit.
#
CC = $($(UNAME)_CC)
TS_CFLAGS = $($(UNAME)_TS_CFLAGS)
TS_LOADLIBES = $($(UNAME)_TS_LOADLIBES)
F_CFLAGS = $($(UNAME)_F_CFLAGS)
O_CFLAGS = $($(UNAME)_O_CFLAGS)
#
# Include common definitions
#
include Makefile_def
#
# Build directories for single-threaded and multi-threaded lib versions
#
ST_BUILD_DIR = ./st_build
MT_BUILD_DIR = ./mt_build
#
# Library names
#
ST_LIB_NAME = libChf.a
MT_LIB_NAME = libChf_r.a
#
# Library paths
#
ST_LIB_PATH = $(ST_BUILD_DIR)/$(ST_LIB_NAME)
MT_LIB_PATH = $(MT_BUILD_DIR)/$(MT_LIB_NAME)
#
# all: Create and populate build directories; for each build directory,
# make dependencies and rebuild
#
all: $(ST_LIB_PATH) $(MT_LIB_PATH)
#
# test: Build and executes test programs
#
test:
@@$(MAKE) UNAME=`uname` do_test
@@echo "All tests completed successfully"
do_test: $(ST_LIB_PATH) $(MT_LIB_PATH)
@@cd $(ST_BUILD_DIR) && \
$(MAKE) test CC=$(CC) LIB=$(ST_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) > test.log 2>&1
@@cd $(MT_BUILD_DIR) && \
$(MAKE) test CC=$(CC) LIB=$(MT_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) \
TS_CFLAGS=$(TS_CFLAGS) TS_LOADLIBES=$(TS_LOADLIBES) >> test.log 2>&1
#
# doc: Make documentation files
#
doc:
makeinfo chf.texi
texi2dvi chf.texi; dvips -o chf.ps chf.dvi
#
# clean: Remove build directories
#
clean:
rm -rf $(ST_BUILD_DIR) $(MT_BUILD_DIR)
#
# install: Move all files to their directories
#
install: $(ST_LIB_PATH) $(MT_LIB_PATH) $(HDR) $(MSF) $(RES)
chmod u+w $(ST_LIB_PATH) $(MT_LIB_PATH) $(BIN) $(HDR) $(MSF) $(RES)
cp $(ST_LIB_PATH) $(MT_LIB_PATH) $(DESTLIBDIR)
cp $(HDR) $(DESTHDRDIR)
cp $(MSF) $(DESTMSFDIR)
echo cp $(RES) $(DESTRESDIR)
#
# Prepare the build directories for use
#
$(ST_BUILD_DIR) $(MT_BUILD_DIR):
@@mkdir $@@ && \
cd $@@ && \
ln -s ../Makefile_sub Makefile && \
for s in $(SRC) $(TSRC) $(HDR) $(MSF) $(TMSF) $(RES) ; do \
ln -s ../$$s $$s ; \
done
#
# Make the libraries; the rebuild is forced here because only the
# sub-makes have module dependencies.
#
$(ST_LIB_PATH): $(ST_BUILD_DIR) force
@@cd $(ST_BUILD_DIR) && \
$(MAKE) depend CC=$(CC) LIB=$(ST_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) && \
$(MAKE) all CC=$(CC) LIB=$(ST_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS)
$(MT_LIB_PATH): $(MT_BUILD_DIR) force
@@cd $(MT_BUILD_DIR) && \
$(MAKE) depend CC=$(CC) LIB=$(MT_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) \
TS_CFLAGS=$(TS_CFLAGS) TS_LOADLIBES=$(TS_LOADLIBES) && \
$(MAKE) all CC=$(CC) LIB=$(MT_LIB_NAME) \
F_CFLAGS=$(F_CFLAGS) O_CFLAGS=$(O_CFLAGS) \
TS_CFLAGS=$(TS_CFLAGS) TS_LOADLIBES=$(TS_LOADLIBES)
force:
@
1.2
log
@Added new module chf_top.c
@
text
@d3 1
a3 1
# .identifier : $Id: Makefile,v 1.1 1996/05/29 09:12:10 cibrario Exp cibrario $
d15 3
d25 37
d63 1
a63 1
# sources and X resource files.
d72 9
a80 1
# Source files
d82 5
a86 3
SRC = chf_init.c chf_gen.c chf_sig.c chf_abrt.c chf_hdlr.c \
chf_msgc.c chf_st.c \
chf_top.c
d88 4
a91 1
HDR = Chf.h ChfPriv.h
d93 5
a97 1
MSF = chf.msf
d99 5
a103 1
RES =
d106 1
a106 1
# Targets
d108 2
a109 3
OBJ = $(SRC:.c=.o)
LIB = libChf.a
BIN =
d111 5
d118 1
a118 1
# Other definitions
d120 3
a122 3
HPATH = -I. -I$(DESTHDRDIR)
LPATH = -L. -L$(DESTLIBDIR)
OFLAG = -O
d124 8
a131 2
CFLAGS = $(OFLAG) $(U_CFLAGS) $(HPATH)
LDFLAGS = $(LPATH)
d134 1
a134 3
# setenv U_LOADLIBES "-li" on Ultrix
# setenv U_LOADLIBES "" on Digital UNIX
# setenv U_LOADLIBES "-lintl" on SCO UNIX
d136 3
a138 1
LOADLIBES = $(LIB) $(U_LOADLIBES)
d141 1
a141 1
# Targets
d143 2
a144 1
all: $(LIB) $(BIN)
d146 6
a151 4
install: $(LIB) $(BIN) $(HDR) $(MSF)
chmod u+w $(LIB) $(BIN) $(HDR) $(MSF)
cp $(LIB) $(DESTLIBDIR)
echo cp $(BIN) $(DESTBINDIR)
d156 30
a185 8
depend: $(SRC)
makedepend $(HPATH) $(SRC)
lint:
$(LINT) -u $(CFLAGS) $(SRC)
$(LIB): $(OBJ)
$(AR) $(ARFLAGS) $@@ $?
d187 1
a187 1
test: test.c $(LIB)
@
1.1
log
@Initial revision
@
text
@d3 1
a3 1
# .identifier : $Id$
d5 1
a5 1
# .title : $RCSfile$, Makefile
d14 3
a16 1
# $Log$
d18 1
d35 2
a36 1
chf_msgc.c chf_st.c
@

116
Chf/RCS/Makefile_def,v Normal file
View file

@ -0,0 +1,116 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @# @;
2.2
date 2001.01.25.11.59.19; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.29.13.08.39; author cibrario; state Rel;
branches;
next ;
desc
@@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@# .+
#
# .identifier : $Id: Makefile_def,v 2.1 2000/05/29 13:08:39 cibrario Rel cibrario $
# .context : CHF, Condition Handling Facility
# .title : $RCSfile: Makefile_def,v $, Makefile
# .kind : Makefile
# .author : Ivan Cibrario B.
# .site : CSTV-CNR
# .creation : 22-May-2000
# .keywords : *
# .description :
# Makefile for CHF library common definitions; no platform dependencies here.
# .notes :
# $Log: Makefile_def,v $
# Revision 2.1 2000/05/29 13:08:39 cibrario
# *** empty log message ***
#
#
# .-
#
# Source files
#
SRC = chf_init.c chf_gen.c chf_sig.c chf_abrt.c chf_hdlr.c \
chf_msgc.c chf_st.c \
chf_top.c \
chf_win32.c
TSRC = test01.c test02.c test03.c test04.c test05.c test06.c \
test07.c
HDR = Chf.h ChfPriv.h
MSF = chf.msf
TMSF = test01.msf
RES =
#
# Target object files
#
OBJ = $(SRC:.c=.o)
#
# Target test programs
#
TBIN = $(TSRC:.c=)
#
# Other definitions
#
HPATH = -I.
LPATH = -L.
CFLAGS = $(F_CFLAGS) $(O_CFLAGS) $(TS_CFLAGS) $(U_CFLAGS) $(HPATH)
LFLAGS = $(F_CFLAGS) $(L_CFLAGS) $(TS_LFLAGS) $(U_CFLAGS) $(HPATH)
LDFLAGS = $(LPATH)
LOADLIBES = $(LIB) $(TS_LOADLIBES) $(I_LOADLIBES) $(U_LOADLIBES)
#
# Solaris spelling of LOADLIBES
#
LDLIBS = $(LOADLIBES)
@
2.1
log
@*** empty log message ***
@
text
@d3 1
a3 1
# .identifier : $Id$
d5 1
a5 1
# .title : $RCSfile$, Makefile
d14 3
a16 1
# $Log$
d18 1
d26 2
a27 1
chf_top.c
@

62
Chf/RCS/Makefile_sub,v Normal file
View file

@ -0,0 +1,62 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @# @;
2.1
date 2000.05.29.13.08.51; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@# .+
#
# .identifier : $Id$
# .context : CHF, Condition Handling Facility
# .title : $RCSfile$, Makefile
# .kind : Makefile
# .author : Ivan Cibrario B.
# .site : CSTV-CNR
# .creation : 22-May-2000
# .keywords : *
# .description :
# Makefile for CHF library subdirectories
# .notes :
# $Log$
#
# .-
#
# Include common definitions
#
include ../Makefile_def
#
# Targets
#
all: $(LIB)
$(LIB): $(OBJ)
$(AR) $(ARFLAGS) $@@ $?
test: $(TBIN)
@@for b in $(TBIN) ; do \
./$$b ; \
done
depend: $(SRC)
@@makedepend $(HPATH) $(SRC)
@

109
Chf/RCS/chf.msf,v Normal file
View file

@ -0,0 +1,109 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @$ . @;
2.2
date 2001.01.25.12.00.19; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.26.14.17.21; author cibrario; state Rel;
branches;
next 1.1;
1.1
date 96.05.28.12.57.06; author cibrario; state Beta;
branches;
next ;
desc
@Message source file for the CHF conditions
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@$ .+
$ .
$ .identifier : $Id: chf.msf,v 2.1 2000/05/26 14:17:21 cibrario Rel cibrario $
$ .context :
$ .title : $RCSfile: chf.msf,v $
$ .kind : Makefile
$ .author : Ivan Cibrario B.
$ .site : CSTV-CNR
$ .creation : 27-May-1996
$ .keywords : *
$ .description :
$ . Message source file for the CHF conditions
$ .notes :
$ . $Log: chf.msf,v $
$ . Revision 2.1 2000/05/26 14:17:21 cibrario
$ . Updated documentation block and RCS log message header to prevent
$ . gencat warnings on Linux boxes
$ .
$ . Revision 1.1 1996/05/28 12:57:06 cibrario
$ . Initial revision
$ .
$ .-
$set 1
2 Chf
3 Errno
$set 2
1 Condition stack is full
2 Handler stack is full
3 Handler stack is empty
4 Wrong Chf state for requested operation
5 Invalid action code from handler (code=<%d>d)
6 Dynamic memory allocation failed
7 Function not implemented
10 setlocale() failed
11 catopen() failed
@
2.1
log
@Updated documentation block and RCS log message header to prevent
gencat warnings on Linux boxes
@
text
@d3 1
a3 1
$ .identifier : $Id: chf.msf,v 1.1 1996/05/28 12:57:06 cibrario Beta cibrario $
d15 4
d35 1
@
1.1
log
@Initial revision
@
text
@d2 2
a3 2
$
$ .identifier : $Id$
d5 1
a5 1
$ .title : $RCSfile$
d12 1
a12 1
$ Message source file for the CHF conditions
d14 4
a17 2
$ $Log$
$
@

123
Chf/RCS/chf.rc,v Executable file
View file

@ -0,0 +1,123 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2;
locks; strict;
comment @# @;
2.2
date 2001.01.25.12.00.46; author cibrario; state Exp;
branches;
next ;
desc
@@
2.2
log
@*** empty log message ***
@
text
@//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
1002 "Chf"
END
STRINGTABLE DISCARDABLE
BEGIN
2001 "Condition stack is full"
2002 "Handler stack is full"
2003 "Handler stack is empty"
2004 "Wrong state for requested operation"
2005 "Invalid action code from handler (code=<%d>d)"
2006 "Dynamic memory allocation failed"
2007 "Function not available"
2010 "setlocale() failed"
2011 "catopen() failed"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Italian (Italy) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
#ifdef _WIN32
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Italian (Italy) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
@

2677
Chf/RCS/chf.texi,v Normal file

File diff suppressed because it is too large Load diff

312
Chf/RCS/chf_abrt.c,v Normal file
View file

@ -0,0 +1,312 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @ @;
2.2
date 2001.01.25.12.08.24; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.26.14.22.07; author cibrario; state Rel;
branches;
next 1.1;
1.1
date 96.05.28.12.53.26; author cibrario; state Beta;
branches;
next ;
desc
@This module implements the CHF function ChfAbort()
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: chf_abrt.c,v 2.1 2000/05/26 14:22:07 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_abrt.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module implements the CHF function ChfAbort()
.include : Chf.h
.notes :
$Log: chf_abrt.c,v $
Revision 2.1 2000/05/26 14:22:07 cibrario
- Conditional inclusion of pthread.h (mt support)
- Expanded abort message table with mt support messages
- ChfAbort() with CHF_ABORT flag clear and mt support enabled now
exits invoking thread only
Revision 1.1 1996/05/28 12:53:26 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_abrt.c,v 2.1 2000/05/26 14:22:07 cibrario Rel cibrario $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
#ifdef _REENTRANT
#include <pthread.h>
#endif
/* Abort codes message table; the relative position of the messages must
match the numeric codes CHF_ABORT_xxxx defined in ChfPriv.h
*/
static const ChfChar *message_table[] =
{
(const ChfChar *)NULL,
ChfText("Not initialized"),
ChfText("Temporary message buffer overflow"),
ChfText("Invalid action from last chance handler"),
ChfText("Already initialized"),
ChfText("Unwind request while unwinding"),
ChfText("Improperly handled condition"),
ChfText("Fatal condition while unwinding"),
ChfText("Condition stack overflow"),
ChfText("Can't prime a new Chf context"),
ChfText("Pthread interaction failed")
};
#define MESSAGE_TABLE_SIZE (sizeof(message_table)/sizeof(const ChfChar *))
/* .+
.title : ChfAbort
.kind : C function
.creation : 13-May-1996
.description :
This function prints the message associated with 'abort_code' and then
immediately aborts either the application (when multithreading support not
enabled or CHF_ABORT set) or the invoking thread only (multithreading
support enabled and CHF_ABORT not set). The abort is performed either:
- using abort() if either CHF has not been correctly initialized or
the chf_context.options flag CHF_ABORT is set
- using exit(chf_context.exit_code) (multithreading support not enabled)
or pthread_exit(chf_context.exit_code) (multithreading support enabled)
if the flag is clear
No message is printed if the abort code is CHF_ABORT_SILENT; this code
is used, for example, by the default condition handler to terminate the
application when a CHF_FATAL condition occours.
NOTE: This function must be called only when either a serious internal CHF
failure occurs or it's necessary to abort the application.
WIN32:
- stderr stream is not supported; the abort message is displayed in a
message box only if Chf has been correctly initialized, otherwise the
abort will be done silently
- abort() is not supported and has been replaced by exit(EXIT_FAILURE)
.call :
ChfAbort(abort_code);
.input :
const int abort_code, abort_code
.output :
void
.status_codes :
none
.notes :
1.1, 13-May-1996, creation
2.1, 19-May-2000, update:
- added multithreading support
2.2, 22-Jan-2001, update:
- added Win32 support
.- */
void ChfAbort( /* Abort application */
const int abort_code
)
{
#ifdef _WIN32
if(abort_code != CHF_ABORT_SILENT)
{
TCHAR abort_msg[CHF_MAX_MESSAGE_LENGTH];
HWND active_window;
/* stderr not available;
put complaint in a message box and display it
*/
if(abort_code < 0 || abort_code >= MESSAGE_TABLE_SIZE)
_stprintf(abort_msg,
CHF_ABORT_BAD_CODE_FMT, abort_code);
else
_stprintf(abort_msg,
CHF_ABORT_GOOD_CODE_FMT, message_table[abort_code]);
/* Return value of MessageBox() ignored, because there is only
one available choice (abort) here. Avoid using a NULL handle.
*/
if(chf_context.state != CHF_UNKNOWN
&& (active_window = GetActiveWindow()) != (HWND)NULL)
(void)
MessageBox(active_window,
abort_msg,
chf_context.app_name,
MB_OK
|MB_ICONERROR
|MB_APPLMODAL|MB_SETFOREGROUND);
}
/* Immediately exit the application with exit code EXIT_FAILURE
if CHF_ABORT option is set or if something is wrong with Chf state.
*/
if(chf_context.state == CHF_UNKNOWN || chf_context.options & CHF_ABORT)
exit(EXIT_FAILURE);
else
/* Else, exit the application anyway, but with the exit code
registered by the application. Don't use PostQuitMessage(),
because the contract is that ChfAbort() never returns to the caller.
*/
#ifndef _REENTRANT
exit(chf_context.exit_code);
#else
#error "_REENTRANT not supported yet"
#endif
#else
if(abort_code != CHF_ABORT_SILENT)
{
fputs(CHF_ABORT_HEADER, stderr);
if(abort_code < 0 || abort_code >= MESSAGE_TABLE_SIZE)
fprintf(stderr, CHF_ABORT_BAD_CODE_FMT, abort_code);
else
fprintf(stderr, CHF_ABORT_GOOD_CODE_FMT, message_table[abort_code]);
}
if(chf_context.state == CHF_UNKNOWN || chf_context.options & CHF_ABORT)
abort();
else
#ifndef _REENTRANT
exit(chf_context.exit_code);
#else
pthread_exit((void *)(chf_context.exit_code));
#endif
#endif
}
@
2.1
log
@- Conditional inclusion of pthread.h (mt support)
- Expanded abort message table with mt support messages
- ChfAbort() with CHF_ABORT flag clear and mt support enabled now
exits invoking thread only
@
text
@d3 1
a3 1
.identifier : $Id: chf_abrt.c,v 1.1 1996/05/28 12:53:26 cibrario Beta cibrario $
d18 6
d31 1
a31 1
static char rcs_id[] = "$Id: chf_abrt.c,v 1.1 1996/05/28 12:53:26 cibrario Beta cibrario $";
d36 1
d38 1
d41 5
d57 1
a57 1
static const char *message_table[] =
d59 11
a69 11
(const char *)NULL,
"Not initialized",
"Temporary message buffer overflow",
"Invalid action from last chance handler",
"Already initialized",
"Unwind request while unwinding",
"Improperly handled condition",
"Fatal condition while unwinding",
"Condition stack overflow",
"Can't prime a new Chf context",
"Pthread interaction failed"
d72 1
a72 1
#define MESSAGE_TABLE_SIZE (sizeof(message_table)/sizeof(const char *))
d96 9
a104 1
failure occours or it's necessary to abort the application.
d118 2
d126 49
d195 1
@
1.1
log
@Initial revision
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$, condition generation
d17 3
a19 1
$Log$
d21 1
d25 1
a25 1
static char rcs_id[] = "$Id$";
d36 4
d54 3
a56 1
"Condition stack overflow"
d69 3
a71 1
immediately aborts the application. The abort is performed either:
d74 3
a76 1
- using exit(chf_context.exit_code) if the flag is clear
d95 2
d118 1
d120 3
@

253
Chf/RCS/chf_gen.c,v Normal file
View file

@ -0,0 +1,253 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:1.1;
locks; strict;
comment @ @;
2.2
date 2001.01.25.12.10.22; author cibrario; state Exp;
branches;
next 1.1;
1.1
date 96.05.28.12.53.59; author cibrario; state Rel;
branches;
next ;
desc
@This module contains the condition generation function of CHF
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: chf_gen.c,v 1.1 1996/05/28 12:53:59 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_gen.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module contains the condition generation function of CHF
.include : Chf.h
.notes :
$Log: chf_gen.c,v $
Revision 1.1 1996/05/28 12:53:59 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_gen.c,v 1.1 1996/05/28 12:53:59 cibrario Rel cibrario $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <stdarg.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* .+
.title : ChfGenerate
.kind : C function
.creation : 3-May-1996
.description :
This function generates a condition descriptor for the condition described
by 'module_id', 'file_name', 'line_number', 'condition_code' and 'severity',
and the partial message associated with it, specialized with the additional
arguments '...'; the new condition descriptor is put onto the top of the
condition stack.
If the condition stack is full, this function generates the condition
CHF_F_COND_STACK_FULL and immediately invokes ChfSignal() for the current
condition stack.
NOTE: This function calls the CHF function 'ChfAbort()' to
abort the application if either:
- CHF has not been initialized correctly (abort code CHF_ABORT_INIT)
- there is an overflow in the internal buffer used during the
generation of the partial message associated with the condition
(abort code CHF_ABORT_MSG_OVF)
- there was an attempt to generate a condition while the CHF condition
CHF_F_COND_STACK_FULL (condition stack full) was being signalled
(abort code CHF_ABORT_COND_STACK_OVF)
.call :
ChfGenerate(module_id, file_name, line_number,
condition_code, severity, ...);
.input :
const int module_id, module identifier
const char *file_name, file name
const int line_number, line number
const int condition_code, condition code
const ChfSeverity severity, severity
..., additional arguments
.output :
void
.status_codes :
(*) CHF_F_COND_STACK_FULL, the condition stack is full
.notes :
1.1, 3-May-1996, creation
.- */
void ChfGenerate( /* Generate a condition into the stack */
const int module_id,
const ChfChar *file_name,
const int line_number,
const int condition_code,
const ChfSeverity severity,
...
)
{
ChfDescriptor *new_descriptor;
va_list aux_arg;
/* Check that CHF has been correctly initialized */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
/* Prepare the additional arguments list */
va_start(aux_arg, severity);
if((new_descriptor = chf_context.condition_sp) -
chf_context.condition_stack >= chf_context.condition_stack_size)
{
/* The condition stack is full;
generate the CHF_F_COND_STACK_FULL condition and signal it immediately,
using the last available slot of the stack, if it's still empty,
otherwise abort the application.
*/
if(new_descriptor - chf_context.condition_stack ==
chf_context.condition_stack_size)
{
new_descriptor->module_id = CHF_MODULE_ID;
new_descriptor->condition_code = CHF_F_COND_STACK_FULL;
new_descriptor->severity = CHF_FATAL;
new_descriptor->line_number = CHF_UNKNOWN_LINE_NUMBER;
new_descriptor->file_name = CHF_UNKNOWN_FILE_NAME;
ChfStrncpy(new_descriptor->message,
ChfGetMessage(CHF_MODULE_ID, CHF_F_COND_STACK_FULL,
ChfText("Condition stack is full")), CHF_MAX_MESSAGE_LENGTH-1);
new_descriptor->message[CHF_MAX_MESSAGE_LENGTH-1] = '\0';
new_descriptor->next = CHF_NULL_DESCRIPTOR;
chf_context.condition_sp++;
ChfSignal();
}
else
ChfAbort(CHF_ABORT_COND_STACK_OVF);
}
else
{
ChfChar def_message[CHF_DEF_MESSAGE_LENGTH];
ChfChar tmp_message[CHF_TMP_MESSAGE_LENGTH];
new_descriptor->module_id = module_id;
new_descriptor->condition_code = condition_code;
new_descriptor->severity = severity;
new_descriptor->line_number = line_number;
new_descriptor->file_name = file_name;
/* Generate the default message */
ChfSprintf(def_message, CHF_DEF_PARTIAL_MSG_FMT, condition_code);
/* Generate the partial message associated with the condition using a
temporary area
*/
if(
ChfVsprintf(tmp_message,
ChfGetMessage(module_id, condition_code, def_message), aux_arg) >=
CHF_TMP_MESSAGE_LENGTH)
ChfAbort(CHF_ABORT_MSG_OVF);
/* Copy the message into the condition descriptor */
ChfStrncpy(new_descriptor->message, tmp_message, CHF_MAX_MESSAGE_LENGTH-1);
new_descriptor->message[CHF_MAX_MESSAGE_LENGTH-1] = '\0';
/* Link the new descriptor with the current descriptor list, if it
isn't the first descriptor of the list
*/
new_descriptor->next = (new_descriptor == chf_context.condition_base)
? CHF_NULL_DESCRIPTOR : new_descriptor - 1;
chf_context.condition_sp++;
}
}
@
1.1
log
@Initial revision
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$, condition generation
d17 3
a19 1
$Log$
d21 1
d25 1
a25 1
static char rcs_id[] = "$Id$";
d30 1
d32 1
d37 5
d93 1
a93 1
const char *file_name,
d126 1
a126 1
strncpy(new_descriptor->message,
d128 1
a128 1
"Condition stack is full"), CHF_MAX_MESSAGE_LENGTH-1);
d143 2
a144 2
char def_message[CHF_DEF_MESSAGE_LENGTH];
char tmp_message[CHF_TMP_MESSAGE_LENGTH];
d153 1
a153 1
sprintf(def_message, CHF_DEF_PARTIAL_MSG_FMT, condition_code);
d159 1
a159 1
vsprintf(tmp_message,
d165 1
a165 1
strncpy(new_descriptor->message, tmp_message, CHF_MAX_MESSAGE_LENGTH-1);
@

407
Chf/RCS/chf_hdlr.c,v Normal file
View file

@ -0,0 +1,407 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @ @;
2.2
date 2001.01.25.12.12.46; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.26.14.45.04; author cibrario; state Rel;
branches;
next 1.6;
1.6
date 97.01.15.13.44.39; author cibrario; state Exp;
branches;
next 1.1;
1.1
date 96.05.28.12.54.28; author cibrario; state Beta;
branches;
next ;
desc
@This module implements the CHF functions ChfPushHandler() and
ChfPopHandler()
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: chf_hdlr.c,v 2.1 2000/05/26 14:45:04 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_hdlr.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module implements the CHF functions ChfPushHandler() and
ChfPopHandler()
.include : Chf.h
.notes :
$Log: chf_hdlr.c,v $
Revision 2.1 2000/05/26 14:45:04 cibrario
- Implemented StructuredHelper(), the structured condition handling
helper handler
- Updated ChfPushHandler() to push the structured condition handling
helper when new_handler is CHF_NULL_HANDLER
- unwind_context is now a sigjmp_buf, passed as argument directly,
that is, without additional address operators
- improved documentation of ChfPopHandler()
Revision 1.6 1997/01/15 13:44:39 cibrario
The function ChfPushHandler() has the new argument 'handler_context'.
Revision 1.1 1996/05/28 12:54:28 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_hdlr.c,v 2.1 2000/05/26 14:45:04 cibrario Rel cibrario $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* .+
.title : StructuredHelper
.kind : C function
.creation : 19-May-2000
.description :
This function is the structured condition handling helper of CHF.
It's automatically pushed into the condition handler stack by
ChfPushHandler() when its 'new_handler' argument is CHF_NULL_HANDLER,
and performs the following functions:
- if called during an ordinary signalling operation with a
CHF_FATAL condition, it requests the action CHF_UNWIND_KEEP
- if called when Chf is in any other state, or with a
severity less than CHF_FATAL, it requests the action CHF_RESIGNAL
The structured condition handling helper currently makes no use of
handler_context.
.call :
action = StructuredHelper(desc, state, context);
.input :
const ChfDescriptor *desc, condition descriptor
const ChfState state, current CHF state
.output :
ChfAction action, action requested by the handler
.status_codes :
none
.notes :
2.1, 19-May-2000, creation
.- */
static ChfAction StructuredHelper(
const ChfDescriptor *desc,
const ChfState state,
ChfPointer handler_context
)
{
ChfAction action;
const ChfDescriptor *d;
return((state == CHF_SIGNALING && ChfGetSeverity(desc) == CHF_FATAL)
? CHF_UNWIND_KEEP : CHF_RESIGNAL);
}
/* .+
.title : ChfPushHandler
.kind : C function
.creation : 13-May-1996
.description :
This function pushes the new condition handler 'new_handler' with its
associated longjmp context pointed by 'unwind_context' into the handler
stack and returns CHF_S_OK to the caller. If 'new_handler' is
CHF_NULL_HANDLER, the special structured condition handling helper
'StructuredHelper()' is pushed instead.
Moreover, this function saves a copy of the pointer 'handler_context'; it
will be passed to 'new_handler' upon each subsequent activation, and
therefore can be used as a private handler context pointer. The user must
assure that the information pointed by 'handler_context', if any, will
remain valid until 'new_handler' is popped from the condition stack.
'handler_context' may be set to the special (null) value CHF_NULL_POINTER to
indicate that the handler hasn't any private context information.
If, in the future, the handler will request the CHF_UNWIND action, the
setjmp() function invocation that established 'unwind_context' will appear
to return again.
'unwind_context' can be the reserved (null) pointer CHF_NULL_CONTEXT; in
this case, if the handler will request the CHF_UNWIND_ACTION, the
application will be silently terminated calling ChfAbort() with abort code
CHF_ABORT_SILENT.
If some error occours during the execution, the function will generate
and immediately signal one of the conditions listed below and marked with
(*). The function will never return dorectly to the caller, since all
conditions are CHF_FATAL.
NOTE: This function calls ChfAbort() with abort code CHF_ABORT_INIT if
the CHF subsystem has not been initialized.
.call :
ChfPushHandler(new_handler, unwind_context);
.input :
ChfHandler new_handler, new condition handler
void *unwind_context, handler unwind context pointer
ChfPointer handler_context, private handler context pointer
.output :
void
.status_codes :
(*) CHF_F_BAD_STATE, bad CHF state for requested operation
(*) CHF_F_HDLR_STACK_FULL, the handler stack is full
.notes :
1.1, 13-May-1996, creation
1.6, 15-Jan-1997, update:
- added the argument 'handler_context'
- improved documentation
2.1, 19-May-2000, update:
- now using sigjmp_buf as unwind_context
- added StructuredHelper handling
.- */
void ChfPushHandler( /* Push a new handler into the stack */
ChfHandler new_handler,
void *unwind_context,
ChfPointer handler_context
)
{
/* Make sure that CHF has been correctly initialized and is idle */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
if(chf_context.state != CHF_IDLE)
{
ChfCondition CHF_F_BAD_STATE, CHF_FATAL
ChfEnd;
ChfSignal();
}
/* Check if the handler stack is full */
else if(chf_context.handler_sp - chf_context.handler_stack >=
chf_context.handler_stack_size)
{
ChfCondition CHF_F_HDLR_STACK_FULL, CHF_FATAL
ChfEnd;
ChfSignal();
}
else
{
chf_context.handler_sp->unwind_context = unwind_context;
chf_context.handler_sp->handler_context = handler_context;
chf_context.handler_sp->handler =
((new_handler == CHF_NULL_HANDLER) ? StructuredHelper : new_handler);
chf_context.handler_sp++;
}
}
/* .+
.title : ChfPopHandler
.kind : C function
.creation : 13-May-1996
.description :
This function pops the topmost condition handler from the handler stack and
returns to the caller.
If some error occours during the execution, the function will generate
and immediately signal one of the conditions listed below and marked with
(*). The function will never return directly to the caller, since all
conditions are CHF_FATAL.
NOTE: This function calls ChfAbort() with abort code CHF_ABORT_INIT if
the CHF subsystem has not been initialized.
.call :
ChfPopHandler();
.input :
void
.output :
void
.status_codes :
CHF_F_BAD_STATE, bad CHF state for requested operation
CHF_F_HDLR_STACK_FULL, the handler stack is full
.notes :
1.1, 13-May-1996, creation
1.6, 15-Jan-1997, update:
- improved documentation
2.1, 19-May-2000, update:
- improved documentation
.- */
void ChfPopHandler( /* Pop a handler */
void
)
{
/* Make sure that CHF has been correctly initialized and is idle */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
if(chf_context.state != CHF_IDLE)
{
ChfCondition CHF_F_BAD_STATE, CHF_FATAL
ChfEnd;
ChfSignal();
}
/* Check if the handler stack is empty */
else if(chf_context.handler_sp == chf_context.handler_stack)
{
ChfCondition CHF_F_HDLR_STACK_EMPTY, CHF_FATAL
ChfEnd;
ChfSignal();
}
/* Discard the topmost condition handler */
else
--chf_context.handler_sp;
}
@
2.1
log
@- Implemented StructuredHelper(), the structured condition handling
helper handler
- Updated ChfPushHandler() to push the structured condition handling
helper when new_handler is CHF_NULL_HANDLER
- unwind_context is now a sigjmp_buf, passed as argument directly,
that is, without additional address operators
- improved documentation of ChfPopHandler()
@
text
@d3 1
a3 1
.identifier : $Id: chf_hdlr.c,v 1.6 1997/01/15 13:44:39 cibrario Exp cibrario $
d19 9
d38 1
a38 1
static char rcs_id[] = "$Id: chf_hdlr.c,v 1.6 1997/01/15 13:44:39 cibrario Exp cibrario $";
d43 1
d45 1
d48 5
@
1.6
log
@The function ChfPushHandler() has the new argument 'handler_context'.
@
text
@d3 1
a3 1
.identifier : $Id: chf_hdlr.c,v 1.1 1996/05/28 12:54:28 cibrario Beta $
d19 3
d29 1
a29 1
static char rcs_id[] = "$Id: chf_hdlr.c,v 1.1 1996/05/28 12:54:28 cibrario Beta $";
d43 47
d96 3
a98 1
stack and returns CHF_S_OK to the caller.
d129 1
a129 1
jmp_buf *unwind_context, handler unwind context pointer
d141 3
d148 1
a148 1
jmp_buf *unwind_context,
d177 2
a178 1
chf_context.handler_sp->handler = new_handler;
d202 1
a202 1
ChfPopHandler(new_handler);
d204 1
a204 1
const int abort_code, abort_code
d214 2
@
1.1
log
@Initial revision
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$, condition generation
d18 3
a20 1
$Log$
d22 1
d26 1
a26 1
static char rcs_id[] = "$Id$";
d47 8
d74 1
a74 1
cc = ChfPushHandler(new_handler, unwind_context);
d76 3
a78 3
ChfHandler new_handler,
jmp_buf *unwind_context
const int abort_code, abort_code
d80 1
a80 1
int cc, condition code
d86 3
d93 2
a94 1
jmp_buf *unwind_context
d121 1
d150 1
a150 1
int cc, condition code
a153 1
CHF_I_UNWIND_DONE, unwind succesfully completed
d156 2
@

1074
Chf/RCS/chf_init.c,v Normal file

File diff suppressed because it is too large Load diff

292
Chf/RCS/chf_msgc.c,v Normal file
View file

@ -0,0 +1,292 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:1.3;
locks; strict;
comment @ @;
2.2
date 2001.01.25.14.06.47; author cibrario; state Exp;
branches;
next 1.3;
1.3
date 96.06.21.14.19.22; author cibrario; state Rel;
branches;
next 1.1;
1.1
date 96.05.28.12.55.15; author cibrario; state Exp;
branches;
next ;
desc
@This module contains the CHF initialization function ChfMsgcatInit()
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: chf_msgc.c,v 1.3 1996/06/21 14:19:22 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_msgc.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 17-May-1996
.keywords : *
.description :
This module contains the CHF initialization function ChfMsgcatInit()
.include : Chf.h
.notes :
$Log: chf_msgc.c,v $
Revision 1.3 1996/06/21 14:19:22 cibrario
Bug fix: the private context of the message retrieval facility was
never freed by ExitMessage()
Revision 1.1 1996/05/28 12:55:15 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_msgc.c,v 1.3 1996/06/21 14:19:22 cibrario Rel cibrario $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifndef _WIN32
#include <locale.h>
#include <nl_types.h>
#endif
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Global and static variables
------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
Private type definitions
------------------------------------------------------------------------- */
#ifndef _WIN32
typedef struct
{
nl_catd catalog; /* Message catalog descriptor */
}
ChfMsgcatContext;
#endif
/* -------------------------------------------------------------------------
Private functions
------------------------------------------------------------------------- */
#ifndef _WIN32
static const char *GetMessage(
void *private_context,
const int module_id,
const int condition_code,
const char *default_message
)
{
return(catgets(((ChfMsgcatContext *)private_context)->catalog, module_id,
condition_code, default_message));
}
static void ExitMessage(
void *private_context
)
{
(void)catclose(((ChfMsgcatContext *)private_context)->catalog);
free(private_context);
}
#endif
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfMsgcatInit
.kind : C function
.creation : 17-May-1996
.description :
This function initializes CHF and returns to the caller a condition code;
that code will be either CHF_S_OK if the initialization was succesful,
or one of the other values listed below.
It's necessary to invoke succesfully either ChfMsgcatInit() or one of the
other CHF initialization routines before using any other CHF function.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_DUP_INIT
if CHF has already been initialized before.
WIN32:
- this function is not available due to lack of system support, and
always returns CHF_F_NOT_AVAILABLE
.call :
cc = ChfMsgcatInit(app_name, options,
msgcat_name,
condition_stack_size, handler_stack_size,
exit_code);
.input :
const char *app_name, Application's name
const ChfOptions options, Options
const char *msgcat_name, Name of the message catalog
const int condition_stack_size, Size of the condition stack
const int handler_stack_size, Size of the handler stack
const int exit_code, Abnormal exit code
.output :
int cc, condition code
.status_codes :
CHF_F_SETLOCALE, setlocale() failed
CHF_F_CATOPEN, catopen() failed
CHF_F_MALLOC, FATAL, memory allocation failed
CHF_F_NOT_AVAILABLE, FATAL, function not available
.notes :
1.1, 17-May-1996, creation
2.2, 22-Jan-2001, update:
- added Win32 support
.- */
int ChfMsgcatInit( /* Initialization with msgcat subsystem */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
const ChfChar *msgcat_name, /* Name of the message catalog */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
)
{
#ifdef _WIN32
/* This function always fails in _WIN32, because message catalogs
are not supported.
*/
return CHF_F_NOT_AVAILABLE;
#else
ChfMsgcatContext *private_context;
int cc;
if((private_context =
(ChfMsgcatContext *)malloc(sizeof(ChfMsgcatContext))) ==
(ChfMsgcatContext *)NULL)
cc = CHF_F_MALLOC;
else if(setlocale(LC_ALL, "") == (char *)NULL)
{
free(private_context);
cc = CHF_F_SETLOCALE;
}
else if((private_context->catalog = catopen(msgcat_name, 0)) ==
(nl_catd)(-1))
{
free(private_context);
cc = CHF_F_CATOPEN;
}
else if((cc = ChfInit(app_name, options, (void *)private_context,
GetMessage, ExitMessage, condition_stack_size, handler_stack_size,
exit_code)) != CHF_S_OK)
{
(void)catclose(private_context->catalog);
free(private_context);
}
else
cc = CHF_S_OK;
return cc;
#endif
}
@
1.3
log
@Bug fix: the private context of the message retrieval facility was
never freed by ExitMessage()
@
text
@d3 1
a3 1
.identifier : $Id: chf_msgc.c,v 1.1 1996/05/28 12:55:15 cibrario Exp cibrario $
d18 4
d29 1
a29 1
static char rcs_id[] = "$Id: chf_msgc.c,v 1.1 1996/05/28 12:55:15 cibrario Exp cibrario $";
d34 1
d36 1
d39 1
d42 1
d44 5
d61 1
d67 1
d75 1
d94 1
d117 5
d140 1
d143 2
d148 1
a148 1
const char *app_name, /* Application's name */
d150 1
a150 1
const char *msgcat_name, /* Name of the message catalog */
d156 7
d196 2
@
1.1
log
@Initial revision
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$, condition generation
d17 3
a19 1
$Log$
d21 1
d25 1
a25 1
static char rcs_id[] = "$Id$";
d76 1
@

546
Chf/RCS/chf_sig.c,v Normal file
View file

@ -0,0 +1,546 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @ @;
2.2
date 2001.01.25.14.07.42; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.26.14.31.28; author cibrario; state Rel;
branches;
next 1.6;
1.6
date 97.01.15.13.34.45; author cibrario; state Exp;
branches;
next 1.1;
1.1
date 96.05.28.12.55.51; author cibrario; state Beta;
branches;
next ;
desc
@This module implements the condition signalling function of CHF
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: chf_sig.c,v 2.1 2000/05/26 14:31:28 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_sig.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module implements the condition signalling function of CHF
.include : Chf.h
.notes :
$Log: chf_sig.c,v $
Revision 2.1 2000/05/26 14:31:28 cibrario
- Fixed spelling of CHF_SIGNALLING -> CHF_SIGNALING
- Replaced longjmp() with siglongjmp()
- New ChfAction code CHF_UNWIND_KEEP: ChfSignal() unwinds the
execution stack, but keeps the topmost condition group on the
condition stack
Revision 1.6 1997/01/15 13:34:45 cibrario
Fixed a wrong adjustment of the condition handler stack pointer after
an unwind operation.
Updated the condition handler calls in order to pass to the handlers the
private handler context pointer.
Revision 1.1 1996/05/28 12:55:51 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_sig.c,v 2.1 2000/05/26 14:31:28 cibrario Rel cibrario $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* .+
.title : ChfSignal
.kind : C function
.creation : 10-May-1996
.description :
This function signals the topmost condition group currently in the
condition stack, and performs the actions requested by the condition
handlers.
NOTE: This function uses the CHF function 'ChfAbort()' to
abort the application if either
- CHF has not been initialized correctly (abort code CHF_ABORT_INIT)
- the last handler on the handler stack has returned an invalid action
code (abort code CHF_ABORT_INVALID_ACTION)
- one of the handlers has requested the CHF_UNWIND action while
CHF was already unwinding (abort code CHF_ABORT_ALREADY_UNWINDING)
- a CHF_FATAL condition was signalled while CHF was unwinding
(abort code CHF_ABORT_FATAL_UNWINDING)
- all the handlers refused to handle a condition (abort code
CHF_ABORT_IMPROPERLY_HANDLED)
.call :
ChfSignal();
.input :
void
.output :
void
.status_codes :
(*) CHF_F_COND_STACK_FULL, the condition stack is full
(*) CHF_F_INVALID_ACTION, invalid handler action (%d)
.notes :
1.1, 10-May-1996, creation
1.6, 15-Jan-1997, update & bug fix:
- fixed a wrong adjustment of the condition handler stack pointer after
an unwind operation.
- updated the condition handler calls in order to pass to the handlers the
private handler context pointer, too.
2.1, 19-May-2000, update:
- added support for structured condition handling
.- */
void ChfSignal(
void
)
{
ChfState saved_state;
ChfDescriptor *saved_condition_base;
ChfDescriptor *current_condition;
ChfHandlerDescriptor *saved_handler_sp;
ChfHandlerDescriptor *handler_up;
ChfHandlerDescriptor *unwind_handler;
ChfAction handler_result;
/* Check that CHF has been correctly initialized and save the current CHF
state. If CHF was CHF_IDLE change state to CHF_SIGNALING, else if CHF was
CHF_UNWINDING change to CHF_SIGNAL_UNWINDING, otherwise remain in the
previous state (that must be CHF_SIGNALING)
*/
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
saved_state = chf_context.state;
if(chf_context.state == CHF_IDLE)
chf_context.state = CHF_SIGNALING;
else if(chf_context.state == CHF_UNWINDING)
chf_context.state = CHF_SIGNAL_UNWINDING;
if(chf_context.condition_sp > chf_context.condition_base)
{
/* Save the base of the current condition group and then update it in
order to allow further generation of conditions inside the condition
handlers that will be called soon.
*/
current_condition = chf_context.condition_sp-1;
saved_condition_base = chf_context.condition_base;
chf_context.condition_base = chf_context.condition_sp;
/* Save the current condition handler pointer */
saved_handler_sp = chf_context.handler_sp;
/* Call the condition handlers; the loop will exit either:
- when the handler stack is empty, or
- when the current handler returns either CHF_CONTINUE or CHF_UNWIND
*/
handler_result = CHF_RESIGNAL;
while(handler_result == CHF_RESIGNAL &&
chf_context.handler_sp > chf_context.handler_stack)
{
chf_context.handler_sp--;
/* The current condition handler, described by chf_context.handler_sp,
can recursively invoke ChfGenerate() and ChfSignal().
ChfGenerate() will store the new condition group starting from
chf_context.condition_sp, that points to the first free slot
of the condition stack. During the first generation, since
chf_context.condition_sp == chf_context.condition_base, the
link pointer of the condition will be NULL and, therefore,
the condition will be the first of a new condition group.
ChfSignal() will signal the condition group described by the
stack block from chf_context.condition_base to
chf_context.condition_sp-1, if it contains at least one condition;
it will call the handlers starting from chf_context.handler_sp-1,
that describes the handler immediately preceding the current handler.
*/
handler_result = chf_context.handler_sp->handler(
current_condition, chf_context.state,
chf_context.handler_sp->handler_context);
/* When the CHF state is CHF_SIGNALING, any condition group generated
but not yet signalled when the current handler exits must be merged
with the condition group currently being signalled, in order to allow
the condition handlers to add their own conditions to the condition
group. If the severity of the previous condition group was CHF_FATAL,
the severity of the new group is forced to CHF_FATAL, too.
When the CHF state is CHF_UNWINDING, the condition group for
which the UNWIND has been requested is 'frozen', no further
modifications are allowed on it, and the condition group is simply
discarded.
*/
if(chf_context.condition_sp > chf_context.condition_base)
{
if(chf_context.state == CHF_SIGNALING)
{
/* Force the new severity to CHF_FATAL if necessary */
if(ChfGetSeverity(current_condition) == CHF_FATAL)
ChfGetSeverity(chf_context.condition_sp-1) = CHF_FATAL;
/* Link together the condition groups */
chf_context.condition_base->next = current_condition;
current_condition = chf_context.condition_sp-1;
chf_context.condition_base = chf_context.condition_sp;
}
else
chf_context.condition_sp = chf_context.condition_base;
}
/* The action CHF_CONTINUE is not allowed if the current condition
severity is CHF_FATAL; it's automatically changed to CHF_RESIGNAL
*/
if(handler_result == CHF_CONTINUE &&
ChfGetSeverity(current_condition) == CHF_FATAL)
handler_result = CHF_RESIGNAL;
}
/* Perform the action requested by the last condition handler invoked */
switch(handler_result)
{
case CHF_CONTINUE:
{
/* Restore the handler stack pointer; the next ChfSignal() invoked
from our same nesting level will invoke our same handler chain
again.
*/
chf_context.handler_sp = saved_handler_sp;
/* Discard the current condition group */
chf_context.condition_base = chf_context.condition_sp =
saved_condition_base;
/* Restore che saved CHF state */
chf_context.state = saved_state;
/* Continue from the instruction following the ChfSignal() */
break;
}
case CHF_UNWIND:
case CHF_UNWIND_KEEP:
{
/* Unwind the execution stack. Check that another unwind isn't
already in progress
*/
if(chf_context.state == CHF_UNWINDING)
ChfAbort(CHF_ABORT_ALREADY_UNWINDING);
else
{
/* Change CHF state */
chf_context.state = CHF_UNWINDING;
/* chf_context.handler_sp points to the condition handler that
has requested the unwind; call all the handlers again, starting
from saved_handler_sp (top of the handler stack) up to and
including chf_context.handler_sp.
*/
handler_up = saved_handler_sp;
while(handler_up > chf_context.handler_sp)
{
ChfAction unw_handler_result;
handler_up--;
/* The current condition handler, described by handler_up
can recursively invoke ChfGenerate() and ChfSignal().
ChfGenerate() will store the new condition group starting from
chf_context.condition_sp, that points to the first free slot
of the condition stack. During the first generation, since
chf_context.condition_sp == chf_context.condition_base, the
link pointer of the condition will be NULL and, therefore,
the condition will be the first of a new condition group.
ChfSignal() will generate the condition group described by the
stack block from chf_context.condition_base to
chf_context.condition_sp-1, if it contains at least one
condition; it will call the handlers starting from
chf_context.handler_sp-1, that describes the handler
immediately preceding the handler that has requested the unwind.
Further unwind requests are not allowed, and will trigger
the condition CHF_F_UNWINDING
*/
unw_handler_result = handler_up->handler(
current_condition, chf_context.state,
handler_up->handler_context);
/* When the CHF state is CHF_UNWINDING, any condition group
generated but not yet signalled when the current handler
returns must be discarded
*/
chf_context.condition_sp = chf_context.condition_base;
}
/* Restore the handler stack pointer, discarding the unwinded
condition handlers. chf_context.handler_sp points to the
handler that requested the unwind; that handler has been
unwinded and its location is now the first free slot in the
condition handler stack.
*/
unwind_handler = chf_context.handler_sp;
if(handler_result == CHF_UNWIND)
{
/* Normal unwind:
restore the condition stack pointers, discarding all condition
groups.
*/
chf_context.condition_base = chf_context.condition_sp =
chf_context.condition_stack;
}
else
{
/* Special unwind for structured condition handling:
restore the condition_base pointer only, to keep the
topmost condition group on the condition stack. This way,
the condition group remains accessible after the unwind.
*/
chf_context.condition_base = saved_condition_base;
}
/* Change the CHF state to CHF_IDLE, and execute longjmp().
If the handler hasn't a valid unwind_context associated with it,
simply abort the application.
*/
chf_context.state = CHF_IDLE;
if(unwind_handler->unwind_context == CHF_NULL_CONTEXT)
ChfAbort(CHF_ABORT_SILENT);
else
ChfSiglongjmp(unwind_handler->unwind_context, 1);
}
break;
}
case CHF_RESIGNAL:
{
ChfAbort(
(chf_context.state == CHF_SIGNALING) ?
CHF_ABORT_IMPROPERLY_HANDLED : CHF_ABORT_FATAL_UNWINDING);
break;
}
default:
{
/* Invalid handler action detected; generate and immediately signal a
condition if the broken handler isn't the last handler on the stack,
otherwise call ChfAbort()
*/
if(chf_context.handler_sp > chf_context.handler_stack)
{
ChfCondition CHF_F_INVALID_ACTION, CHF_FATAL, handler_result
ChfEnd;
ChfSignal();
}
else
ChfAbort(CHF_ABORT_INVALID_ACTION);
break;
}
}
}
/* Restore the old CHF state */
chf_context.state = saved_state;
}
/* .+
.title : ChfDiscard
.kind : C function
.creation : 17-May-1996
.description :
This function discards the topmost condition group currently in the
condition stack, without signalling it. The function does nothing if
the condition stack is empty.
NOTE: This function uses the CHF function 'ChfAbort()' to
abort the application if either
- CHF has not been initialized correctly (abort code CHF_ABORT_INIT)
.call :
ChfDiscard();
.input :
void
.output :
void
.status_codes :
none
.notes :
1.1, 17-May-1996, creation
.- */
void ChfDiscard( /* Discard the current conditions */
void
)
{
/* Check that CHF has been correctly initialized */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
/* Reset the current condition stack pointer to the current condition
stack base pointer
*/
chf_context.condition_sp = chf_context.condition_base;
}
@
2.1
log
@- Fixed spelling of CHF_SIGNALLING -> CHF_SIGNALING
- Replaced longjmp() with siglongjmp()
- New ChfAction code CHF_UNWIND_KEEP: ChfSignal() unwinds the
execution stack, but keeps the topmost condition group on the
condition stack
@
text
@d3 1
a3 1
.identifier : $Id: chf_sig.c,v 1.6 1997/01/15 13:34:45 cibrario Exp cibrario $
d18 7
d38 1
a38 1
static char rcs_id[] = "$Id: chf_sig.c,v 1.6 1997/01/15 13:34:45 cibrario Exp cibrario $";
d43 1
d45 1
d48 5
d320 1
a320 1
siglongjmp(unwind_handler->unwind_context, 1);
@
1.6
log
@Fixed a wrong adjustment of the condition handler stack pointer after
an unwind operation.
Updated the condition handler calls in order to pass to the handlers the
private handler context pointer.
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$, condition generation
d17 7
a23 1
$Log$
d31 1
a31 1
static char rcs_id[] = "$Id$";
d81 2
d98 1
a98 1
state. If CHF was CHF_IDLE change state to CHF_SIGNALLING, else if CHF was
d100 1
a100 1
previous state (that must be CHF_SIGNALLING)
d106 1
a106 1
chf_context.state = CHF_SIGNALLING;
d153 1
a153 1
/* When the CHF state is CHF_SIGNALLING, any condition group generated
d167 1
a167 1
if(chf_context.state == CHF_SIGNALLING)
d214 1
d236 1
d259 1
a259 1
handler_result = handler_up->handler(
d278 18
a295 5
/* Restore the condition stack pointers, discarding all condition
groups.
*/
chf_context.condition_base = chf_context.condition_sp =
chf_context.condition_stack;
d306 1
a306 1
longjmp(*(unwind_handler->unwind_context), 1);
d315 1
a315 1
(chf_context.state == CHF_SIGNALLING) ?
@
1.1
log
@Initial revision
@
text
@d18 2
d21 1
d70 5
d142 2
a143 1
current_condition, chf_context.state);
d250 2
a251 1
current_condition, chf_context.state);
d262 3
a264 2
handler that requested the unwind and must be adjusted to
point to the handler that immediately precedes it.
d266 1
a266 1
unwind_handler = chf_context.handler_sp--;
@

295
Chf/RCS/chf_st.c,v Normal file
View file

@ -0,0 +1,295 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:1.1;
locks; strict;
comment @ @;
2.2
date 2001.01.25.14.08.45; author cibrario; state Exp;
branches;
next 1.1;
1.1
date 96.05.28.12.56.14; author cibrario; state Rel;
branches;
next ;
desc
@This module implements the CHF initialization function ChfStaticInit()
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: chf_st.c,v 1.1 1996/05/28 12:56:14 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_st.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 24-May-1996
.keywords : *
.description :
This module implements the CHF initialization function ChfStaticInit()
.include : Chf.h
.notes :
$Log: chf_st.c,v $
Revision 1.1 1996/05/28 12:56:14 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_st.c,v 1.1 1996/05/28 12:56:14 cibrario Rel cibrario $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Global and static variables
------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
Private type definitions
------------------------------------------------------------------------- */
typedef struct
{
const ChfTable *table;
size_t size;
}
ChfStaticContext;
/* -------------------------------------------------------------------------
Private functions
------------------------------------------------------------------------- */
#ifdef _WIN32
/* Win32 does not have bsearch();
provide a simple one from glibc here.
*/
static void *bsearch(
const void *key,
const void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *)
)
{
size_t l, u, idx;
const void *p;
int comparison;
l = 0;
u = nmemb;
while (l < u)
{
idx = (l + u) / 2;
p = (void *) (((const char *) base) + (idx * size));
comparison = (*compar) (key, p);
if (comparison < 0)
u = idx;
else if (comparison > 0)
l = idx + 1;
else
return (void *) p;
}
return NULL;
}
#endif
#define GT 1
#define LT -1
#define EQ 0
static int Search(
const void *l,
const void *r
)
{
if(((ChfTable *)l)->module > ((ChfTable *)r)->module)
return(GT);
else if(((ChfTable *)l)->module < ((ChfTable *)r)->module)
return(LT);
else if(((ChfTable *)l)->code > ((ChfTable *)r)->code)
return(GT);
else if(((ChfTable *)l)->code < ((ChfTable *)r)->code)
return(LT);
return(EQ);
}
static const ChfChar *StGetMessage(
void *private_context,
const int module_id,
const int condition_code,
const ChfChar *default_message
)
{
ChfTable key;
ChfTable *res;
key.module = module_id;
key.code = condition_code;
if((res = bsearch(&key, ((ChfStaticContext *)private_context)->table,
((ChfStaticContext *)private_context)->size, sizeof(ChfTable), Search)) ==
(void *)NULL)
return(default_message);
return(((ChfTable *)res)->msg_template);
}
static void ExitMessage(
void *private_context
)
{
}
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfStaticInit
.kind : C function
.creation : 24-May-1996
.description :
This function initializes CHF and returns to the caller a condition code;
that code will be either CHF_S_OK if the initialization was succesful,
or one of the other values listed below.
It's necessary to invoke succesfully either ChfStaticInit() or one of the
other CHF initialization routines before using any other CHF function.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_DUP_INIT
if CHF has already been initialized before.
.call :
cc = ChfStaticInit(app_name, options,
table, table_size,
condition_stack_size, handler_stack_size,
exit_code);
.input :
const char *app_name, Application's name
const ChfOptions options, Options
const ChfTable *table, pointer to the static message table
const size_t table_size, size of the table (# of entries)
const int condition_stack_size, Size of the condition stack
const int handler_stack_size, Size of the handler stack
const int exit_code, Abnormal exit code
.output :
int cc, condition code
.status_codes :
CHF_F_MALLOC, FATAL, memory allocation failed
.notes :
1.1, 27-May-1996, creation
.- */
int ChfStaticInit( /* Initialization with static message tables */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
const ChfTable *table, /* Static message table */
const size_t table_size, /* Size of the message table */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
)
{
ChfStaticContext *private_context;
int cc;
if((private_context =
(ChfStaticContext *)malloc(sizeof(ChfStaticContext))) ==
(ChfStaticContext *)NULL)
cc = CHF_F_MALLOC;
else if((cc = ChfInit(app_name, options, (void *)private_context,
StGetMessage, ExitMessage, condition_stack_size, handler_stack_size,
exit_code)) != CHF_S_OK)
free(private_context);
else
{
private_context->table = table;
private_context->size = table_size;
cc = CHF_S_OK;
}
return cc;
}
@
1.1
log
@Initial revision
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$, condition generation
d17 3
a19 1
$Log$
d21 1
d25 1
a25 1
static char rcs_id[] = "$Id$";
d30 1
d32 1
d36 5
d65 35
d124 1
a124 1
static const char *GetMessage(
d128 1
a128 1
const char *default_message
d142 1
a142 1
return(((ChfTable *)res)->template);
d194 1
a194 1
const char *app_name, /* Application's name */
d212 1
a212 1
GetMessage, ExitMessage, condition_stack_size, handler_stack_size,
@

192
Chf/RCS/chf_top.c,v Normal file
View file

@ -0,0 +1,192 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2
Rel_2_1:2.1;
locks; strict;
comment @ @;
2.2
date 2001.01.25.14.09.21; author cibrario; state Exp;
branches;
next 2.1;
2.1
date 2000.05.26.14.23.33; author cibrario; state Rel;
branches;
next 1.2;
1.2
date 96.06.11.12.47.17; author cibrario; state Beta;
branches;
next ;
desc
@This module implements the CHF function ChfGetTopCondition()
@
2.2
log
@Added partial Win32 support (Windows CE only).
@
text
@/* .+
.identifier : $Id: chf_top.c,v 2.1 2000/05/26 14:23:33 cibrario Rel cibrario $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_top.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 5-Jun-1996
.keywords : *
.description :
This module implements the CHF function ChfGetTopCondition()
.include : Chf.h
.notes :
$Log: chf_top.c,v $
Revision 2.1 2000/05/26 14:23:33 cibrario
ChfGetTopCondition() used to return a pointer to the wrong condition
descriptor; fixed.
Revision 1.2 1996/06/11 12:47:17 cibrario
file creation
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_top.c,v 2.1 2000/05/26 14:23:33 cibrario Rel cibrario $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfGetTopCondition
.kind : C function
.creation : 5-Jun-1996
.description :
This function returns to the caller a pointer to the top condition of
the current condition group. It generates and immediately signals the
condition CHF_F_BAD_STATE if the current condition group is empty.
NOTE: During condition signalling, CHF creates a new, empty, condition group
immediately before starting the invocation sequence of the condition
handlers, as described in the documentation. Therefore
ChfGetTopCondition(), if called from a condition handler, will return
a pointer to the top condition generated during the handling ONLY, and
NOT to the top condition of the condition group being signalled. The
latter pointer is directly available, as an argument, to the condition
handlers.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_INIT
if CHF hasn't been correctly initialized.
NOTE: The returned pointer is no longer valid when any other CHF function
is called after ChfGetTopCondition().
.call :
d = ChfGetTopCondition();
.input :
void
.output :
const ChfDescriptor *d, condition descriptor
.status_codes :
.notes :
1.2, 17-May-1996, creation
2.1, 24-May-2000, bug fix:
- condition stack referenced incorrectly
.- */
const ChfDescriptor *ChfGetTopCondition( /* Retrieve top condition */
void
)
{
ChfDescriptor *d;
/* Check that CHF has been correctly initialized */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
if((d = chf_context.condition_sp) == chf_context.condition_base)
{
ChfCondition CHF_F_BAD_STATE, CHF_FATAL ChfEnd;
ChfSignal();
}
/* The top element of the condition group is the element immediately
below the stack pointer.
*/
return d-1;
}
@
2.1
log
@ChfGetTopCondition() used to return a pointer to the wrong condition
descriptor; fixed.
@
text
@d3 1
a3 1
.identifier : $Id: chf_top.c,v 1.2 1996/06/11 12:47:17 cibrario Beta cibrario $
d18 4
d29 1
a29 1
static char rcs_id[] = "$Id: chf_top.c,v 1.2 1996/06/11 12:47:17 cibrario Beta cibrario $";
d34 1
d36 1
d40 5
@
1.2
log
@file creation
@
text
@d3 1
a3 1
.identifier : $Id$
d5 1
a5 1
.title : $RCSfile$
d17 3
a19 1
$Log$
d21 1
d25 1
a25 1
static char rcs_id[] = "$Id$";
d78 2
d97 4
a100 1
return d;
@

212
Chf/RCS/chf_win32.c,v Normal file
View file

@ -0,0 +1,212 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2;
locks; strict;
comment @ * @;
2.2
date 2001.01.25.14.11.58; author cibrario; state Exp;
branches;
next ;
desc
@@
2.2
log
@*** empty log message ***
@
text
@/* .+
.identifier : $Id$
.context : CHF, Condition Handling Facility
.title : $RCSfile$, Win32 initialization function
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 19-Jan-2001
.keywords : *
.description :
This module contains the CHF initialization function ChfWin32Init()
.include : Chf.h
.notes :
$Log$
.- */
#ifndef lint
static char rcs_id[] = "$Id$";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Global and static variables
------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
Private type definitions
------------------------------------------------------------------------- */
#ifdef _WIN32
typedef struct
{
HINSTANCE instance; /* App. instance handle */
ChfChar buffer[CHF_MAX_MESSAGE_LENGTH]; /* Temporary buffer */
}
ChfWin32Context;
#endif
/* -------------------------------------------------------------------------
Private functions
------------------------------------------------------------------------- */
#ifdef _WIN32
static const ChfChar *Win32GetMessage(
void *private_context,
const int module_id,
const int condition_code,
const ChfChar *default_message
)
{
if(!LoadString(
((ChfWin32Context *)private_context)->instance,
module_id*1000 + condition_code,
((ChfWin32Context *)private_context)->buffer,
CHF_MAX_MESSAGE_LENGTH-1))
return default_message;
return ((ChfWin32Context *)private_context)->buffer;
}
static void ExitMessage(
void *private_context
)
{
free(private_context);
}
#endif
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfWin32Init
.kind : C function
.creation : 19-Jan-2001
.description :
This function initializes CHF and returns to the caller a condition code;
that code will be either CHF_S_OK if the initialization was succesful,
or one of the other values listed below.
It's necessary to invoke succesfully either ChfWin32Init() or one of the
other CHF initialization routines before using any other CHF function.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_DUP_INIT
if CHF has already been initialized before.
WIN32:
- This function is available in Win32 only; it will return
CHF_F_NOT_AVAILABLE on Unix platforma.
- message retrieval is done through the LoadString() Win32 function.
This function does not support message sets, so the linear message id
passed to it is made by module_id*1000 + condition_code. The following
limits are in effect:
0 <= condition_code <= 999
0 <= module_id <= 64
.call :
cc = ChfWin32Init(app_name, options,
msgcat_name,
condition_stack_size, handler_stack_size,
exit_code);
.input :
const ChfChar *app_name, Application's name
const ChfOptions options, Options
HINSTANCE instance, App. instance handle
const int condition_stack_size, Size of the condition stack
const int handler_stack_size, Size of the handler stack
const int exit_code, Abnormal exit code
.output :
int cc, condition code
.status_codes :
CHF_F_MALLOC, FATAL, memory allocation failed
CHF_F_NOT_AVAILABLE, FATAL, function not available
.notes :
2.2, 19-Jan-2001, creation
.- */
int ChfWin32Init( /* Initialization within _WIN32 */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
#ifndef _WIN32
void *instance, /* Fake arguments */
#else
HINSTANCE instance, /* App. instance handle */
#endif
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
)
{
#ifndef _WIN32
/* This function is available only in Win32 */
return CHF_F_NOT_AVAILABLE;
#else
ChfWin32Context *private_context;
int cc;
if((private_context =
(ChfWin32Context *)malloc(sizeof(ChfWin32Context))) ==
(ChfWin32Context *)NULL)
cc = CHF_F_MALLOC;
else if((cc = ChfInit(app_name, options, (void *)private_context,
Win32GetMessage, ExitMessage, condition_stack_size, handler_stack_size,
exit_code)) != CHF_S_OK)
{
free(private_context);
}
else
{
/* Save Win32 specific context items into private Chf context */
private_context->instance = instance;
cc = CHF_S_OK;
}
return cc;
#endif
}
@

509
Chf/RCS/libChf.vcp,v Executable file
View file

@ -0,0 +1,509 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2;
locks; strict;
comment @# @;
2.2
date 2001.01.25.14.12.47; author cibrario; state Exp;
branches;
next ;
desc
@@
2.2
log
@*** empty log message ***
@
text
@# Microsoft eMbedded Visual Tools Project File - Name="libChf" - Package Owner=<4>
# Microsoft eMbedded Visual Tools Generated Build File, Format Version 6.02
# ** DO NOT EDIT **
# TARGTYPE "Win32 (WCE x86em) Static Library" 0x7f04
# TARGTYPE "Win32 (WCE ARM) Static Library" 0x8504
CFG=libChf - Win32 (WCE ARM) Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libChf.vcn".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libChf.vcn" CFG="libChf - Win32 (WCE ARM) Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libChf - Win32 (WCE ARM) Release" (based on "Win32 (WCE ARM) Static Library")
!MESSAGE "libChf - Win32 (WCE ARM) Debug" (based on "Win32 (WCE ARM) Static Library")
!MESSAGE "libChf - Win32 (WCE x86em) Release" (based on "Win32 (WCE x86em) Static Library")
!MESSAGE "libChf - Win32 (WCE x86em) Debug" (based on "Win32 (WCE x86em) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
# PROP ATL_Project 2
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ARMRel"
# PROP BASE Intermediate_Dir "ARMRel"
# PROP BASE CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}"
# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ARMRel"
# PROP Intermediate_Dir "ARMRel"
# PROP CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}"
# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP Target_Dir ""
CPP=clarm.exe
# ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "NDEBUG" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /Oxs /M$(CECrtMT) /c
# ADD CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "NDEBUG" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /Oxs /M$(CECrtMT) /c
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "ARMDbg"
# PROP BASE Intermediate_Dir "ARMDbg"
# PROP BASE CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}"
# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "ARMDbg"
# PROP Intermediate_Dir "ARMDbg"
# PROP CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}"
# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP Target_Dir ""
CPP=clarm.exe
# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /M$(CECrtMTDebug) /c
# ADD CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /M$(CECrtMTDebug) /c
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "X86EMRel"
# PROP BASE Intermediate_Dir "X86EMRel"
# PROP BASE CPU_ID "{D6518FF4-710F-11D3-99F2-00105A0DF099}"
# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "X86EMRel"
# PROP Intermediate_Dir "X86EMRel"
# PROP CPU_ID "{D6518FF4-710F-11D3-99F2-00105A0DF099}"
# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP Target_Dir ""
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "WIN32" /D "STRICT" /D "_WIN32_WCE_EMULATION" /D "INTERNATIONAL" /D "USA" /D "INTLMSG_CODEPAGE" /D "$(CePlatform)" /D "i486" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "NDEBUG" /D "_LIB" /YX /Oxs /Gz /c
# ADD CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "WIN32" /D "STRICT" /D "_WIN32_WCE_EMULATION" /D "INTERNATIONAL" /D "USA" /D "INTLMSG_CODEPAGE" /D "$(CePlatform)" /D "i486" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "NDEBUG" /D "_LIB" /YX /Oxs /Gz /c
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "X86EMDbg"
# PROP BASE Intermediate_Dir "X86EMDbg"
# PROP BASE CPU_ID "{D6518FF4-710F-11D3-99F2-00105A0DF099}"
# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "X86EMDbg"
# PROP Intermediate_Dir "X86EMDbg"
# PROP CPU_ID "{D6518FF4-710F-11D3-99F2-00105A0DF099}"
# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP Target_Dir ""
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "WIN32" /D "STRICT" /D "_WIN32_WCE_EMULATION" /D "INTERNATIONAL" /D "USA" /D "INTLMSG_CODEPAGE" /D "$(CePlatform)" /D "i486" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_LIB" /YX /Gz /c
# ADD CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "WIN32" /D "STRICT" /D "_WIN32_WCE_EMULATION" /D "INTERNATIONAL" /D "USA" /D "INTLMSG_CODEPAGE" /D "$(CePlatform)" /D "i486" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_LIB" /FR /YX /Gz /c
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
!ENDIF
# Begin Target
# Name "libChf - Win32 (WCE ARM) Release"
# Name "libChf - Win32 (WCE ARM) Debug"
# Name "libChf - Win32 (WCE x86em) Release"
# Name "libChf - Win32 (WCE x86em) Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\chf_abrt.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_A=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_A=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_A=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_A=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_gen.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_G=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_G=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_G=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_G=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_hdlr.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_H=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_H=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_H=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_H=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_init.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_I=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_I=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_I=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_I=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_msgc.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_M=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_M=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_M=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_M=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_sig.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_S=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_S=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_S=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_S=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_st.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_ST=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_ST=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_ST=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_ST=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_top.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_T=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_T=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_T=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_T=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_win32.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_W=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_W=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_W=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_W=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\Chf.h
# End Source File
# Begin Source File
SOURCE=.\ChfPriv.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "rc"
# Begin Source File
SOURCE=.\chf.rc
# End Source File
# End Group
# End Target
# End Project
@

39
Chf/RCS/resource.h,v Executable file
View file

@ -0,0 +1,39 @@
head 2.2;
access;
symbols
V4_1_1_1:2.2;
locks; strict;
comment @ * @;
2.2
date 2001.01.25.14.13.01; author cibrario; state Exp;
branches;
next ;
desc
@@
2.2
log
@*** empty log message ***
@
text
@//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by chf.rc
//
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
@

118
Chf/RCS/test01.c,v Normal file
View file

@ -0,0 +1,118 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @ * @;
2.1
date 2000.05.29.13.55.50; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@/* $Id$
Chf test program.
Simple initialization.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
int main(int argc, char *argv[])
{
int st;
const char *msg;
const ChfDescriptor *d, *e;
puts("test01");
system("gencat test01.cat test01.msf");
system("gencat test01.cat chf.msf");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat", 50, 10, 1))
exit(st);
/* ChfGetMessage:
message (CHF_MODULE_ID, 1) exists, (CHF_MODULE_ID, 2) does not
*/
msg = ChfGetMessage(CHF_MODULE_ID, 1, "Default_1");
if(strcmp(msg, "Set_255,Message_1")) exit(EXIT_FAILURE);
msg = ChfGetMessage(CHF_MODULE_ID, 2, "Default_2");
if(strcmp(msg, "Default_2")) exit(EXIT_FAILURE);
/* Generate a condition and check descriptor; this is line 46 */
ChfCondition 3, CHF_WARNING, 456 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 3
|| d->severity != CHF_WARNING
|| d->line_number != 46
|| strcmp(d->file_name, "test01.c")
|| strcmp(d->message, "Set_255,Arg_456,Message_3")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Generate another condition and check; this is line 60 */
ChfCondition 4, CHF_INFO, "arg" ChfEnd;
if((e = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
e->module_id != CHF_MODULE_ID
|| e->condition_code != 4
|| e->severity != CHF_INFO
|| e->line_number != 60
|| strcmp(e->file_name, "test01.c")
|| strcmp(e->message, "Set_255,Arg_arg,Message_4")
|| e->next != d
) exit(EXIT_FAILURE);
/* Discard the previous condition group and create a new one */
ChfDiscard();
/* This is line 77 */
ChfCondition 5, CHF_ERROR, 456, 789 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 5
|| d->severity != CHF_ERROR
|| d->line_number != 77
|| strcmp(d->file_name, "test01.c")
|| strcmp(d->message, "Set_255,Arg_456-789,Message_5")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Exit Chf */
ChfExit();
exit(EXIT_SUCCESS);
}
@

43
Chf/RCS/test01.msf,v Normal file
View file

@ -0,0 +1,43 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @# @;
2.1
date 2000.05.29.13.09.38; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@$set 1
255 Chf Test
$set 255
1 Set_255,Message_1
3 Set_255,Arg_%d,Message_3
4 Set_255,Arg_%s,Message_4
5 Set_255,Arg_%d-%d,Message_5
6 Set_255,Message_6 (thread %d, sub-condition)
7 Set_255,Message_7 (thread %d, main)
8 Set_255,Message_8 (thread %d, main)
9 Set_255,Message_9
10 Invalid descriptor link detected
11 Bad hdlr stack push count %d; should be %d
12 Bad cond stack push count %d; should be %d
20 Structured exc handling test cond
@

146
Chf/RCS/test02.c,v Normal file
View file

@ -0,0 +1,146 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @ * @;
2.1
date 2000.05.29.13.56.44; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@/* $Id: test02.c,v 2.1 2000/05/29 13:09:53 cibrario Exp cibrario $
Chf test program.
Simple initialization - multithreaded.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
void *task(void *arg)
{
const char *msg;
const ChfDescriptor *d, *e;
printf("\tThread %d\n", (int)arg);
/* message (CHF_MODULE_ID, 1) exists, (CHF_MODULE_ID, 2) does not */
msg = ChfGetMessage(CHF_MODULE_ID, 1, "Default_1");
if(strcmp(msg, "Set_255,Message_1")) exit(EXIT_FAILURE);
msg = ChfGetMessage(CHF_MODULE_ID, 2, "Default_2");
if(strcmp(msg, "Default_2")) exit(EXIT_FAILURE);
/* Generate a condition and check descriptor; this is line 36 */
ChfCondition 3, CHF_WARNING, 456 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 3
|| d->severity != CHF_WARNING
|| d->line_number != 36
|| strcmp(d->file_name, "test02.c")
|| strcmp(d->message, "Set_255,Arg_456,Message_3")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Generate another condition and check; this is line 50 */
ChfCondition 4, CHF_INFO, "arg" ChfEnd;
if((e = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
e->module_id != CHF_MODULE_ID
|| e->condition_code != 4
|| e->severity != CHF_INFO
|| e->line_number != 50
|| strcmp(e->file_name, "test02.c")
|| strcmp(e->message, "Set_255,Arg_arg,Message_4")
|| e->next != d
) exit(EXIT_FAILURE);
/* Discard the previous condition group and create a new one */
ChfDiscard();
/* This is line 67 */
ChfCondition 5, CHF_ERROR, 456, 789 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 5
|| d->severity != CHF_ERROR
|| d->line_number != 67
|| strcmp(d->file_name, "test02.c")
|| strcmp(d->message, "Set_255,Arg_456-789,Message_5")
|| d->next != NULL
) exit(EXIT_FAILURE);
return (void *)0;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test02");
#ifdef _REENTRANT
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat", 50, 10, 1))
exit(st);
/* Create */
for(i=0; i<N_THREADS; i++)
if(st = pthread_create(&(t[i]), NULL, task, (void *)i))
{
printf("pthread_create: error %d", st);
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
if(st = pthread_join(t[i], &ret))
{
printf("pthread_join: error %d", st);
exit(EXIT_FAILURE);
}
/* Exit Chf */
ChfExit();
#endif
exit(EXIT_SUCCESS);
}
@

112
Chf/RCS/test03.c,v Normal file
View file

@ -0,0 +1,112 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @ * @;
2.1
date 2000.05.29.13.10.29; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@/* $Id$
Chf test program.
Generation and signal - single and multithreaded
$Log$
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
void *task(void *arg)
{
const char *msg;
const ChfDescriptor *d, *e;
/* The sleep() is here to increase contention between threads */
sleep(1);
printf("\tThread %d\n", (int)arg);
/* Generate a condition group and signal it */
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
/* The sleep() is here to increase contention between threads */
sleep(1);
ChfSignal();
return (void *)0;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test03");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat", 50, 10, 1))
exit(st);
#ifdef _REENTRANT
/* Create */
for(i=0; i<N_THREADS; i++)
if(pthread_create(&(t[i]), NULL, task, (void *)i))
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
if(pthread_join(t[i], &ret))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
#else
task((void *)0);
#endif
/* Exit Chf */
ChfExit();
exit(EXIT_SUCCESS);
}
@

353
Chf/RCS/test04.c,v Normal file
View file

@ -0,0 +1,353 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @ * @;
2.1
date 2000.05.29.13.10.38; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@/* $Id$
Chf test program.
General condition handling - single and multithreaded
$Log$
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
struct tdata_s
{
const ChfDescriptor *d, *e;
int phase;
};
ChfAction h1(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
struct tdata_s *tdata_p = (struct tdata_s *)p;
ChfAction action;
if(c != tdata_p->e ||
ChfGetNextDescriptor(c) != tdata_p->d)
{
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
action = CHF_CONTINUE;
return action;
}
ChfAction h2(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
struct tdata_s *tdata_p = (struct tdata_s *)p;
ChfAction action;
switch(s)
{
case CHF_SIGNALING:
{
if(c != tdata_p->e
|| ChfGetNextDescriptor(c) != tdata_p->d
|| (tdata_p->phase != 2 && tdata_p->phase != 4))
{
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
{
action = (ChfGetConditionCode(c) != 8 ? CHF_CONTINUE : CHF_UNWIND);
}
break;
}
case CHF_UNWINDING:
{
if(tdata_p->phase != 4) exit(EXIT_FAILURE);
tdata_p->phase = 5;
action = CHF_CONTINUE;
break;
}
default:
{
exit(EXIT_FAILURE);
}
}
return action;
}
ChfAction h3(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
struct tdata_s *tdata_p = (struct tdata_s *)p;
ChfAction action;
/* This handler must be invoked only during the first signal */
if(tdata_p->phase != 3) exit(EXIT_FAILURE);
switch(s)
{
case CHF_SIGNALING:
{
if(ChfGetConditionCode(c) != 9 ||
ChfGetNextDescriptor(c) != NULL)
{
exit(EXIT_FAILURE);
}
else
{
tdata_p->phase = 4;
action = CHF_CONTINUE;
}
break;
}
default:
{
exit(EXIT_FAILURE);
}
}
return action;
}
ChfAction h4(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
struct tdata_s *tdata_p = (struct tdata_s *)p;
ChfAction action;
/* This handler must be invoked only during the first signal */
if(tdata_p->phase != 2) exit(EXIT_FAILURE);
switch(s)
{
case CHF_SIGNALING:
{
if(c != tdata_p->e
|| ChfGetNextDescriptor(c) != tdata_p->d)
{
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
{
/* This generates a new group and signals it */
tdata_p->phase = 3;
ChfCondition 9, CHF_INFO ChfEnd;
ChfSignal();
if(tdata_p->phase != 4) exit(EXIT_FAILURE);
tdata_p->phase = 5;
if(c != tdata_p->e
|| ChfGetNextDescriptor(c) != tdata_p->d)
{
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
action = CHF_CONTINUE;
}
break;
}
default:
{
exit(EXIT_FAILURE);
}
}
return action;
}
void *task(void *arg)
{
volatile struct tdata_s tdata;
/* The sleep() is here to increase contention between threads */
sleep(1);
printf("\tThread %d\n", (int)arg);
/* Push the handler */
ChfPushHandler(h1, NULL, (ChfPointer)(&tdata));
/* Generate a condition group and signal it */
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* The sleep() is here to increase contention between threads */
sleep(1);
ChfSignal();
/* Pop the handler */
ChfPopHandler();
/* Generate a new condition group with (apparently) wrong linkage
and signal it; this checks that the handler has actually been
removed.
*/
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = NULL;
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
tdata.e = NULL;
ChfSignal();
/* Conditional unwind test */
{
sigjmp_buf jb;
tdata.phase = 0;
if(setjmp(jb) == 0)
{
ChfPushHandler(h2, jb, (ChfPointer)(&tdata));
/* Generate a condition group and signal it */
tdata.phase = 1;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* This does not trigger an unwind */
tdata.phase = 2;
ChfSignal();
tdata.phase = 3;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 8, CHF_INFO, (int)arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* This MUST trigger an unwind */
tdata.phase = 4;
ChfSignal();
exit(EXIT_FAILURE);
}
else
{
/* Unwind */
if(tdata.phase != 5)
exit(EXIT_FAILURE);
ChfPopHandler();
}
}
/* Condition generation and signal while a signal is in progress;
this requires two handlers.
*/
{
tdata.phase = 0;
ChfPushHandler(h3, NULL, (ChfPointer)&tdata);
ChfPushHandler(h4, NULL, (ChfPointer)&tdata);
tdata.phase = 1;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
tdata.e = ChfGetTopCondition();
tdata.phase = 2;
ChfSignal();
if(tdata.phase != 5)
exit(EXIT_FAILURE);
ChfPopHandler();
ChfPopHandler();
}
return (void *)0;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test04");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat", 50, 10, 1))
exit(st);
#ifdef _REENTRANT
/* Create */
for(i=0; i<N_THREADS; i++)
if(pthread_create(&(t[i]), NULL, task, (void *)i))
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
if(pthread_join(t[i], &ret))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
#else
task((void *)0);
#endif
/* Exit Chf */
ChfExit();
exit(EXIT_SUCCESS);
}
@

269
Chf/RCS/test05.c,v Normal file
View file

@ -0,0 +1,269 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @ * @;
2.1
date 2000.05.29.13.10.46; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@/* $Id$
Chf test program.
Condition & Handler stacks oveflow checks - single and multithreaded
$Log$
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
#define H_STACK_SIZE 10
#define C_STACK_SIZE 30
/* Dummy handler; pushed only to verify that the handler stack overflow
checks are correct.
*/
ChfAction h1(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
return CHF_RESIGNAL;
}
/* Overflow check handler; it unwinds if the CHF_F_HDLR_STACK_FULL
condition is signalled exactly after H_STACK_SIZE-2 invocations
of ChfPushHandler(), it resignals a modified condition if the
condition is signalled too early
*/
ChfAction h2(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
int push_count = *((int *)p);
ChfAction action;
if(s == CHF_SIGNALING)
{
if(ChfGetModuleId(c) == CHF_SET
&& ChfGetConditionCode(c) == CHF_F_HDLR_STACK_FULL)
{
/* Handler stack is full; check correctness of the descriptor */
if(push_count == H_STACK_SIZE-2
&& ChfGetNextDescriptor(c) == NULL
&& ChfGetSeverity(c) == CHF_FATAL)
action = CHF_UNWIND;
else
{
ChfCondition 11, CHF_FATAL, push_count, H_STACK_SIZE-2
ChfEnd;
action = CHF_RESIGNAL;
}
}
}
else
action = CHF_RESIGNAL;
return action;
}
/* Overflow check handler; it unwinds if the CHF_F_COND_STACK_FULL
condition is signalled exactly after C_STACK_SIZE invocations
of ChfCondition, it resignals a modified condition if the
condition is signalled too early
*/
ChfAction h3(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
int push_count = *((int *)p);
ChfAction action;
if(s == CHF_SIGNALING)
{
if(ChfGetModuleId(c) == CHF_SET
&& ChfGetConditionCode(c) == CHF_F_COND_STACK_FULL)
{
/* Handler stack is full; check correctness of the descriptor */
if(push_count == C_STACK_SIZE
&& ChfGetNextDescriptor(c) == NULL
&& ChfGetSeverity(c) == CHF_FATAL)
action = CHF_UNWIND;
else
{
ChfCondition 12, CHF_FATAL, push_count, C_STACK_SIZE
ChfEnd;
action = CHF_RESIGNAL;
}
}
}
else
action = CHF_RESIGNAL;
return action;
}
void *task(void *arg)
{
int push_count = 0;
sigjmp_buf jb;
/* The sleep() is here to increase contention between threads */
sleep(1);
printf("\tThread %d\n", (int)arg);
/* Check handler stack overflow checks */
if(sigsetjmp(jb, 1) == 0)
{
int i;
/* Push the handler */
ChfPushHandler(h2, jb, (ChfPointer)(&push_count));
/* The sleep() is here to increase contention between threads */
sleep(1);
/* Push dummy handlers until an error should occur */
for(; push_count<H_STACK_SIZE-1; push_count++)
ChfPushHandler(h1, NULL, NULL);
/* No error? Bad! */
return (void *)EXIT_FAILURE;
}
/* Flow control returns here if 'handler stack full' was signalled
at the correct place.
Check condition stack overflow checks
*/
push_count = 0;
if(sigsetjmp(jb, 1) == 0)
{
int i;
/* Push the handler */
ChfPushHandler(h3, jb, (ChfPointer)(&push_count));
/* The sleep() is here to increase contention between threads */
sleep(1);
/* Push dummy conditions until an error should occur */
for(; push_count<=C_STACK_SIZE; push_count++)
ChfCondition 1, CHF_INFO ChfEnd;
/* No error? Bad! */
return (void *)EXIT_FAILURE;
}
/* Flow control returns here if 'condition stack full' was signalled
at the correct place.
Check condition stack overflow again, to ensure that no spurious
conditions were left out in the previous check.
*/
push_count = 0;
if(sigsetjmp(jb, 1) == 0)
{
int i;
/* Push the handler */
ChfPushHandler(h3, jb, (ChfPointer)(&push_count));
/* The sleep() is here to increase contention between threads */
sleep(1);
/* Push dummy conditions until an error should occur */
for(; push_count<=C_STACK_SIZE; push_count++)
ChfCondition 1, CHF_INFO ChfEnd;
/* No error? Bad! */
return (void *)EXIT_FAILURE;
}
return (void *)EXIT_SUCCESS;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test05");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat",
C_STACK_SIZE, H_STACK_SIZE, EXIT_FAILURE))
exit(st);
#ifdef _REENTRANT
/* Create */
for(i=0; i<N_THREADS; i++)
if(pthread_create(&(t[i]), NULL, task, (void *)i))
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
{
if(pthread_join(t[i], &ret))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
else if((int)ret != EXIT_SUCCESS)
exit((int)ret);
}
st = EXIT_SUCCESS;
#else
st = (int)task((void *)0);
#endif
/* Exit Chf */
ChfExit();
exit(st);
}
@

160
Chf/RCS/test06.c,v Normal file
View file

@ -0,0 +1,160 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @ * @;
2.1
date 2000.05.29.13.10.55; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@/* $Id$
Chf test program.
Structured condition handling - single and multithreaded
$Log$
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
#define H_STACK_SIZE 10
#define C_STACK_SIZE 30
void *task(void *arg)
{
volatile int phase = 0;
ChfTry
{
phase = 1;
ChfCondition 20, CHF_SUCCESS ChfEnd;
ChfSignal();
phase = 2;
ChfCondition 20, CHF_INFO ChfEnd;
ChfSignal();
phase = 3;
ChfCondition 20, CHF_WARNING ChfEnd;
ChfSignal();
phase = 4;
ChfCondition 20, CHF_ERROR ChfEnd;
ChfSignal();
phase = 5;
ChfCondition 20, CHF_FATAL ChfEnd;
ChfSignal();
/* Should not be reached */
return (void *)EXIT_FAILURE;
}
ChfCatch
{
/* Catched an exception; check descriptor */
const ChfDescriptor *d = ChfGetTopCondition();
if(d == NULL
|| ChfGetNextDescriptor(d) != NULL
|| ChfGetModuleId(d) != CHF_MODULE_ID
|| ChfGetConditionCode(d) != 20)
return (void *)EXIT_FAILURE;
}
ChfEndTry;
/* Check that the condition stack actually is empty after catch */
ChfTry
{
volatile const ChfDescriptor *e = ChfGetTopCondition();
}
ChfCatch
{
const ChfDescriptor *d = ChfGetTopCondition();
if(d == NULL
|| ChfGetNextDescriptor(d) != NULL
|| ChfGetModuleId(d) != CHF_SET
|| ChfGetConditionCode(d) != CHF_F_BAD_STATE)
return (void *)EXIT_FAILURE;
}
ChfEndTry;
return (void *)EXIT_SUCCESS;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test06");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat",
C_STACK_SIZE, H_STACK_SIZE, EXIT_FAILURE))
exit(st);
#ifdef _REENTRANT
/* Create */
for(i=0; i<N_THREADS; i++)
if(pthread_create(&(t[i]), NULL, task, (void *)i))
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
{
if(pthread_join(t[i], &ret))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
else if((int)ret != EXIT_SUCCESS)
exit((int)ret);
}
st = EXIT_SUCCESS;
#else
st = (int)task((void *)0);
#endif
/* Exit Chf */
ChfExit();
exit(st);
}
@

128
Chf/RCS/test07.c,v Normal file
View file

@ -0,0 +1,128 @@
head 2.1;
access;
symbols
V4_1_1_1:2.1
Rel_2_1:2.1;
locks; strict;
comment @ * @;
2.1
date 2000.05.29.13.57.17; author cibrario; state Rel;
branches;
next ;
desc
@@
2.1
log
@*** empty log message ***
@
text
@/* $Id: test07.c,v 2.1 2000/05/29 13:11:01 cibrario Exp cibrario $
Chf test program.
Simple initialization.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
extern ChfTable message_table[];
extern size_t message_table_size;
int main(int argc, char *argv[])
{
int st;
const char *msg;
const ChfDescriptor *d, *e;
puts("test07");
/* Initialization */
if(st = ChfStaticInit(argv[0], CHF_DEFAULT,
message_table, message_table_size, 50, 10, 1))
exit(st);
/* ChfGetMessage:
message (CHF_MODULE_ID, 1) exists, (CHF_MODULE_ID, 2) does not
*/
msg = ChfGetMessage(CHF_MODULE_ID, 1, "Default_1");
if(strcmp(msg, "Set_255,Message_1")) exit(EXIT_FAILURE);
msg = ChfGetMessage(CHF_MODULE_ID, 2, "Default_2");
if(strcmp(msg, "Default_2")) exit(EXIT_FAILURE);
/* Generate a condition and check descriptor; this is line 46 */
ChfCondition 3, CHF_WARNING, 456 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 3
|| d->severity != CHF_WARNING
|| d->line_number != 46
|| strcmp(d->file_name, "test07.c")
|| strcmp(d->message, "Set_255,Arg_456,Message_3")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Generate another condition and check; this is line 60 */
ChfCondition 4, CHF_INFO, "arg" ChfEnd;
if((e = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
e->module_id != CHF_MODULE_ID
|| e->condition_code != 4
|| e->severity != CHF_INFO
|| e->line_number != 60
|| strcmp(e->file_name, "test07.c")
|| strcmp(e->message, "Set_255,Arg_arg,Message_4")
|| e->next != d
) exit(EXIT_FAILURE);
/* Discard the previous condition group and create a new one */
ChfDiscard();
/* This is line 77 */
ChfCondition 5, CHF_ERROR, 456, 789 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 5
|| d->severity != CHF_ERROR
|| d->line_number != 77
|| strcmp(d->file_name, "test07.c")
|| strcmp(d->message, "Set_255,Arg_456-789,Message_5")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Exit Chf */
ChfExit();
exit(EXIT_SUCCESS);
}
ChfTable message_table[] =
{
{ CHF_MODULE_ID, 1, "Set_255,Message_1" },
{ CHF_MODULE_ID, 3, "Set_255,Arg_%d,Message_3" },
{ CHF_MODULE_ID, 4, "Set_255,Arg_%s,Message_4" },
{ CHF_MODULE_ID, 5, "Set_255,Arg_%d-%d,Message_5" }
};
size_t message_table_size = sizeof(message_table)/sizeof(message_table[0]);
@

40
Chf/chf.msf Normal file
View file

@ -0,0 +1,40 @@
$ .+
$ .
$ .identifier : $Id: chf.msf,v 2.2 2001/01/25 12:00:19 cibrario Exp $
$ .context :
$ .title : $RCSfile: chf.msf,v $
$ .kind : Makefile
$ .author : Ivan Cibrario B.
$ .site : CSTV-CNR
$ .creation : 27-May-1996
$ .keywords : *
$ .description :
$ . Message source file for the CHF conditions
$ .notes :
$ . $Log: chf.msf,v $
$ . Revision 2.2 2001/01/25 12:00:19 cibrario
$ . Added partial Win32 support (Windows CE only).
$ .
$ . Revision 2.1 2000/05/26 14:17:21 cibrario
$ . Updated documentation block and RCS log message header to prevent
$ . gencat warnings on Linux boxes
$ .
$ . Revision 1.1 1996/05/28 12:57:06 cibrario
$ . Initial revision
$ .
$ .-
$set 1
2 Chf
3 Errno
$set 2
1 Condition stack is full
2 Handler stack is full
3 Handler stack is empty
4 Wrong Chf state for requested operation
5 Invalid action code from handler (code=<%d>d)
6 Dynamic memory allocation failed
7 Function not implemented
10 setlocale() failed
11 catopen() failed

99
Chf/chf.rc Executable file
View file

@ -0,0 +1,99 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
1002 "Chf"
END
STRINGTABLE DISCARDABLE
BEGIN
2001 "Condition stack is full"
2002 "Handler stack is full"
2003 "Handler stack is empty"
2004 "Wrong state for requested operation"
2005 "Invalid action code from handler (code=<%d>d)"
2006 "Dynamic memory allocation failed"
2007 "Function not available"
2010 "setlocale() failed"
2011 "catopen() failed"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Italian (Italy) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
#ifdef _WIN32
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Italian (Italy) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

2053
Chf/chf.texi Normal file

File diff suppressed because it is too large Load diff

199
Chf/chf_abrt.c Normal file
View file

@ -0,0 +1,199 @@
/* .+
.identifier : $Id: chf_abrt.c,v 2.2 2001/01/25 12:08:24 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_abrt.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module implements the CHF function ChfAbort()
.include : Chf.h
.notes :
$Log: chf_abrt.c,v $
Revision 2.2 2001/01/25 12:08:24 cibrario
Added partial Win32 support (Windows CE only).
Revision 2.1 2000/05/26 14:22:07 cibrario
- Conditional inclusion of pthread.h (mt support)
- Expanded abort message table with mt support messages
- ChfAbort() with CHF_ABORT flag clear and mt support enabled now
exits invoking thread only
Revision 1.1 1996/05/28 12:53:26 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_abrt.c,v 2.2 2001/01/25 12:08:24 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
#ifdef _REENTRANT
#include <pthread.h>
#endif
/* Abort codes message table; the relative position of the messages must
match the numeric codes CHF_ABORT_xxxx defined in ChfPriv.h
*/
static const ChfChar *message_table[] =
{
(const ChfChar *)NULL,
ChfText("Not initialized"),
ChfText("Temporary message buffer overflow"),
ChfText("Invalid action from last chance handler"),
ChfText("Already initialized"),
ChfText("Unwind request while unwinding"),
ChfText("Improperly handled condition"),
ChfText("Fatal condition while unwinding"),
ChfText("Condition stack overflow"),
ChfText("Can't prime a new Chf context"),
ChfText("Pthread interaction failed")
};
#define MESSAGE_TABLE_SIZE (sizeof(message_table)/sizeof(const ChfChar *))
/* .+
.title : ChfAbort
.kind : C function
.creation : 13-May-1996
.description :
This function prints the message associated with 'abort_code' and then
immediately aborts either the application (when multithreading support not
enabled or CHF_ABORT set) or the invoking thread only (multithreading
support enabled and CHF_ABORT not set). The abort is performed either:
- using abort() if either CHF has not been correctly initialized or
the chf_context.options flag CHF_ABORT is set
- using exit(chf_context.exit_code) (multithreading support not enabled)
or pthread_exit(chf_context.exit_code) (multithreading support enabled)
if the flag is clear
No message is printed if the abort code is CHF_ABORT_SILENT; this code
is used, for example, by the default condition handler to terminate the
application when a CHF_FATAL condition occours.
NOTE: This function must be called only when either a serious internal CHF
failure occurs or it's necessary to abort the application.
WIN32:
- stderr stream is not supported; the abort message is displayed in a
message box only if Chf has been correctly initialized, otherwise the
abort will be done silently
- abort() is not supported and has been replaced by exit(EXIT_FAILURE)
.call :
ChfAbort(abort_code);
.input :
const int abort_code, abort_code
.output :
void
.status_codes :
none
.notes :
1.1, 13-May-1996, creation
2.1, 19-May-2000, update:
- added multithreading support
2.2, 22-Jan-2001, update:
- added Win32 support
.- */
void ChfAbort( /* Abort application */
const int abort_code
)
{
#ifdef _WIN32
if(abort_code != CHF_ABORT_SILENT)
{
TCHAR abort_msg[CHF_MAX_MESSAGE_LENGTH];
HWND active_window;
/* stderr not available;
put complaint in a message box and display it
*/
if(abort_code < 0 || abort_code >= MESSAGE_TABLE_SIZE)
_stprintf(abort_msg,
CHF_ABORT_BAD_CODE_FMT, abort_code);
else
_stprintf(abort_msg,
CHF_ABORT_GOOD_CODE_FMT, message_table[abort_code]);
/* Return value of MessageBox() ignored, because there is only
one available choice (abort) here. Avoid using a NULL handle.
*/
if(chf_context.state != CHF_UNKNOWN
&& (active_window = GetActiveWindow()) != (HWND)NULL)
(void)
MessageBox(active_window,
abort_msg,
chf_context.app_name,
MB_OK
|MB_ICONERROR
|MB_APPLMODAL|MB_SETFOREGROUND);
}
/* Immediately exit the application with exit code EXIT_FAILURE
if CHF_ABORT option is set or if something is wrong with Chf state.
*/
if(chf_context.state == CHF_UNKNOWN || chf_context.options & CHF_ABORT)
exit(EXIT_FAILURE);
else
/* Else, exit the application anyway, but with the exit code
registered by the application. Don't use PostQuitMessage(),
because the contract is that ChfAbort() never returns to the caller.
*/
#ifndef _REENTRANT
exit(chf_context.exit_code);
#else
#error "_REENTRANT not supported yet"
#endif
#else
if(abort_code != CHF_ABORT_SILENT)
{
fputs(CHF_ABORT_HEADER, stderr);
if(abort_code < 0 || abort_code >= MESSAGE_TABLE_SIZE)
fprintf(stderr, CHF_ABORT_BAD_CODE_FMT, abort_code);
else
fprintf(stderr, CHF_ABORT_GOOD_CODE_FMT, message_table[abort_code]);
}
if(chf_context.state == CHF_UNKNOWN || chf_context.options & CHF_ABORT)
abort();
else
#ifndef _REENTRANT
exit(chf_context.exit_code);
#else
pthread_exit((void *)(chf_context.exit_code));
#endif
#endif
}

179
Chf/chf_gen.c Normal file
View file

@ -0,0 +1,179 @@
/* .+
.identifier : $Id: chf_gen.c,v 2.2 2001/01/25 12:10:22 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_gen.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module contains the condition generation function of CHF
.include : Chf.h
.notes :
$Log: chf_gen.c,v $
Revision 2.2 2001/01/25 12:10:22 cibrario
Added partial Win32 support (Windows CE only).
Revision 1.1 1996/05/28 12:53:59 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_gen.c,v 2.2 2001/01/25 12:10:22 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <stdarg.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* .+
.title : ChfGenerate
.kind : C function
.creation : 3-May-1996
.description :
This function generates a condition descriptor for the condition described
by 'module_id', 'file_name', 'line_number', 'condition_code' and 'severity',
and the partial message associated with it, specialized with the additional
arguments '...'; the new condition descriptor is put onto the top of the
condition stack.
If the condition stack is full, this function generates the condition
CHF_F_COND_STACK_FULL and immediately invokes ChfSignal() for the current
condition stack.
NOTE: This function calls the CHF function 'ChfAbort()' to
abort the application if either:
- CHF has not been initialized correctly (abort code CHF_ABORT_INIT)
- there is an overflow in the internal buffer used during the
generation of the partial message associated with the condition
(abort code CHF_ABORT_MSG_OVF)
- there was an attempt to generate a condition while the CHF condition
CHF_F_COND_STACK_FULL (condition stack full) was being signalled
(abort code CHF_ABORT_COND_STACK_OVF)
.call :
ChfGenerate(module_id, file_name, line_number,
condition_code, severity, ...);
.input :
const int module_id, module identifier
const char *file_name, file name
const int line_number, line number
const int condition_code, condition code
const ChfSeverity severity, severity
..., additional arguments
.output :
void
.status_codes :
(*) CHF_F_COND_STACK_FULL, the condition stack is full
.notes :
1.1, 3-May-1996, creation
.- */
void ChfGenerate( /* Generate a condition into the stack */
const int module_id,
const ChfChar *file_name,
const int line_number,
const int condition_code,
const ChfSeverity severity,
...
)
{
ChfDescriptor *new_descriptor;
va_list aux_arg;
/* Check that CHF has been correctly initialized */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
/* Prepare the additional arguments list */
va_start(aux_arg, severity);
if((new_descriptor = chf_context.condition_sp) -
chf_context.condition_stack >= chf_context.condition_stack_size)
{
/* The condition stack is full;
generate the CHF_F_COND_STACK_FULL condition and signal it immediately,
using the last available slot of the stack, if it's still empty,
otherwise abort the application.
*/
if(new_descriptor - chf_context.condition_stack ==
chf_context.condition_stack_size)
{
new_descriptor->module_id = CHF_MODULE_ID;
new_descriptor->condition_code = CHF_F_COND_STACK_FULL;
new_descriptor->severity = CHF_FATAL;
new_descriptor->line_number = CHF_UNKNOWN_LINE_NUMBER;
new_descriptor->file_name = CHF_UNKNOWN_FILE_NAME;
ChfStrncpy(new_descriptor->message,
ChfGetMessage(CHF_MODULE_ID, CHF_F_COND_STACK_FULL,
ChfText("Condition stack is full")), CHF_MAX_MESSAGE_LENGTH-1);
new_descriptor->message[CHF_MAX_MESSAGE_LENGTH-1] = '\0';
new_descriptor->next = CHF_NULL_DESCRIPTOR;
chf_context.condition_sp++;
ChfSignal();
}
else
ChfAbort(CHF_ABORT_COND_STACK_OVF);
}
else
{
ChfChar def_message[CHF_DEF_MESSAGE_LENGTH];
ChfChar tmp_message[CHF_TMP_MESSAGE_LENGTH];
new_descriptor->module_id = module_id;
new_descriptor->condition_code = condition_code;
new_descriptor->severity = severity;
new_descriptor->line_number = line_number;
new_descriptor->file_name = file_name;
/* Generate the default message */
ChfSprintf(def_message, CHF_DEF_PARTIAL_MSG_FMT, condition_code);
/* Generate the partial message associated with the condition using a
temporary area
*/
if(
ChfVsprintf(tmp_message,
ChfGetMessage(module_id, condition_code, def_message), aux_arg) >=
CHF_TMP_MESSAGE_LENGTH)
ChfAbort(CHF_ABORT_MSG_OVF);
/* Copy the message into the condition descriptor */
ChfStrncpy(new_descriptor->message, tmp_message, CHF_MAX_MESSAGE_LENGTH-1);
new_descriptor->message[CHF_MAX_MESSAGE_LENGTH-1] = '\0';
/* Link the new descriptor with the current descriptor list, if it
isn't the first descriptor of the list
*/
new_descriptor->next = (new_descriptor == chf_context.condition_base)
? CHF_NULL_DESCRIPTOR : new_descriptor - 1;
chf_context.condition_sp++;
}
}

264
Chf/chf_hdlr.c Normal file
View file

@ -0,0 +1,264 @@
/* .+
.identifier : $Id: chf_hdlr.c,v 2.2 2001/01/25 12:12:46 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_hdlr.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module implements the CHF functions ChfPushHandler() and
ChfPopHandler()
.include : Chf.h
.notes :
$Log: chf_hdlr.c,v $
Revision 2.2 2001/01/25 12:12:46 cibrario
Added partial Win32 support (Windows CE only).
Revision 2.1 2000/05/26 14:45:04 cibrario
- Implemented StructuredHelper(), the structured condition handling
helper handler
- Updated ChfPushHandler() to push the structured condition handling
helper when new_handler is CHF_NULL_HANDLER
- unwind_context is now a sigjmp_buf, passed as argument directly,
that is, without additional address operators
- improved documentation of ChfPopHandler()
Revision 1.6 1997/01/15 13:44:39 cibrario
The function ChfPushHandler() has the new argument 'handler_context'.
Revision 1.1 1996/05/28 12:54:28 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_hdlr.c,v 2.2 2001/01/25 12:12:46 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* .+
.title : StructuredHelper
.kind : C function
.creation : 19-May-2000
.description :
This function is the structured condition handling helper of CHF.
It's automatically pushed into the condition handler stack by
ChfPushHandler() when its 'new_handler' argument is CHF_NULL_HANDLER,
and performs the following functions:
- if called during an ordinary signalling operation with a
CHF_FATAL condition, it requests the action CHF_UNWIND_KEEP
- if called when Chf is in any other state, or with a
severity less than CHF_FATAL, it requests the action CHF_RESIGNAL
The structured condition handling helper currently makes no use of
handler_context.
.call :
action = StructuredHelper(desc, state, context);
.input :
const ChfDescriptor *desc, condition descriptor
const ChfState state, current CHF state
.output :
ChfAction action, action requested by the handler
.status_codes :
none
.notes :
2.1, 19-May-2000, creation
.- */
static ChfAction StructuredHelper(
const ChfDescriptor *desc,
const ChfState state,
ChfPointer handler_context
)
{
ChfAction action;
const ChfDescriptor *d;
return((state == CHF_SIGNALING && ChfGetSeverity(desc) == CHF_FATAL)
? CHF_UNWIND_KEEP : CHF_RESIGNAL);
}
/* .+
.title : ChfPushHandler
.kind : C function
.creation : 13-May-1996
.description :
This function pushes the new condition handler 'new_handler' with its
associated longjmp context pointed by 'unwind_context' into the handler
stack and returns CHF_S_OK to the caller. If 'new_handler' is
CHF_NULL_HANDLER, the special structured condition handling helper
'StructuredHelper()' is pushed instead.
Moreover, this function saves a copy of the pointer 'handler_context'; it
will be passed to 'new_handler' upon each subsequent activation, and
therefore can be used as a private handler context pointer. The user must
assure that the information pointed by 'handler_context', if any, will
remain valid until 'new_handler' is popped from the condition stack.
'handler_context' may be set to the special (null) value CHF_NULL_POINTER to
indicate that the handler hasn't any private context information.
If, in the future, the handler will request the CHF_UNWIND action, the
setjmp() function invocation that established 'unwind_context' will appear
to return again.
'unwind_context' can be the reserved (null) pointer CHF_NULL_CONTEXT; in
this case, if the handler will request the CHF_UNWIND_ACTION, the
application will be silently terminated calling ChfAbort() with abort code
CHF_ABORT_SILENT.
If some error occours during the execution, the function will generate
and immediately signal one of the conditions listed below and marked with
(*). The function will never return dorectly to the caller, since all
conditions are CHF_FATAL.
NOTE: This function calls ChfAbort() with abort code CHF_ABORT_INIT if
the CHF subsystem has not been initialized.
.call :
ChfPushHandler(new_handler, unwind_context);
.input :
ChfHandler new_handler, new condition handler
void *unwind_context, handler unwind context pointer
ChfPointer handler_context, private handler context pointer
.output :
void
.status_codes :
(*) CHF_F_BAD_STATE, bad CHF state for requested operation
(*) CHF_F_HDLR_STACK_FULL, the handler stack is full
.notes :
1.1, 13-May-1996, creation
1.6, 15-Jan-1997, update:
- added the argument 'handler_context'
- improved documentation
2.1, 19-May-2000, update:
- now using sigjmp_buf as unwind_context
- added StructuredHelper handling
.- */
void ChfPushHandler( /* Push a new handler into the stack */
ChfHandler new_handler,
void *unwind_context,
ChfPointer handler_context
)
{
/* Make sure that CHF has been correctly initialized and is idle */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
if(chf_context.state != CHF_IDLE)
{
ChfCondition CHF_F_BAD_STATE, CHF_FATAL
ChfEnd;
ChfSignal();
}
/* Check if the handler stack is full */
else if(chf_context.handler_sp - chf_context.handler_stack >=
chf_context.handler_stack_size)
{
ChfCondition CHF_F_HDLR_STACK_FULL, CHF_FATAL
ChfEnd;
ChfSignal();
}
else
{
chf_context.handler_sp->unwind_context = unwind_context;
chf_context.handler_sp->handler_context = handler_context;
chf_context.handler_sp->handler =
((new_handler == CHF_NULL_HANDLER) ? StructuredHelper : new_handler);
chf_context.handler_sp++;
}
}
/* .+
.title : ChfPopHandler
.kind : C function
.creation : 13-May-1996
.description :
This function pops the topmost condition handler from the handler stack and
returns to the caller.
If some error occours during the execution, the function will generate
and immediately signal one of the conditions listed below and marked with
(*). The function will never return directly to the caller, since all
conditions are CHF_FATAL.
NOTE: This function calls ChfAbort() with abort code CHF_ABORT_INIT if
the CHF subsystem has not been initialized.
.call :
ChfPopHandler();
.input :
void
.output :
void
.status_codes :
CHF_F_BAD_STATE, bad CHF state for requested operation
CHF_F_HDLR_STACK_FULL, the handler stack is full
.notes :
1.1, 13-May-1996, creation
1.6, 15-Jan-1997, update:
- improved documentation
2.1, 19-May-2000, update:
- improved documentation
.- */
void ChfPopHandler( /* Pop a handler */
void
)
{
/* Make sure that CHF has been correctly initialized and is idle */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
if(chf_context.state != CHF_IDLE)
{
ChfCondition CHF_F_BAD_STATE, CHF_FATAL
ChfEnd;
ChfSignal();
}
/* Check if the handler stack is empty */
else if(chf_context.handler_sp == chf_context.handler_stack)
{
ChfCondition CHF_F_HDLR_STACK_EMPTY, CHF_FATAL
ChfEnd;
ChfSignal();
}
/* Discard the topmost condition handler */
else
--chf_context.handler_sp;
}

780
Chf/chf_init.c Normal file
View file

@ -0,0 +1,780 @@
/* .+
.identifier : $Id: chf_init.c,v 2.2 2001/01/25 14:05:23 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_init.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module implements the CHF initialization function ChfInit()
.include : Chf.h
.notes :
$Log: chf_init.c,v $
Revision 2.2 2001/01/25 14:05:23 cibrario
Added partial Win32 support (Windows CE only).
Revision 2.1 2000/05/26 15:30:42 cibrario
- Renamed static context chf_context to _chf_context; it is now in
actual use only when mt support is not enabled, otherwise it is
used only as a prototype to prime the per-thread contexts on demand
- Conditional definition of mt support static variables
(context_mutex to access the static master context, fputs_mutex to
ensure the atomicity of DefaultHandler() while it is printing a
sequence of grouped condition messages) and functions (DestroyContext()
to destroy a per-thread context when the owning thread terminates)
- Deeply revised ChfInit() and ChfExit() to implement multithreading
support
- Implemented function _ChfGetContext() to return a pointer to the
per-thread Chf context, creating them on-demand.
Revision 1.6 1997/01/15 13:37:19 cibrario
The Chf condition handlers now have a third argument: the private handler
context pointer; the code has been updated accordingly.
Revision 1.4 1996/09/25 13:29:01 cibrario
Added static char[] variable rcs_lib_id; it contains the value of the
CHF_LIBRARY_ID macro. The header Chf.h sets that macro to its RCS Id,
that is also the Id of the whole Chf library.
Revision 1.1 1996/05/28 12:54:58 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_init.c,v 2.2 2001/01/25 14:05:23 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Global and static variables
------------------------------------------------------------------------- */
/* Chf Library Id */
#ifndef lint
static ChfChar rcs_lib_id[] = CHF_LIBRARY_ID;
#endif
/* CHF context */
ChfContext _chf_context;
/* Message separator and severity names for ChfBuildMessage() */
static const ChfChar separator[] = CHF_MESSAGE_SEPARATOR;
static const ChfChar *severity_name[] = CHF_SEVERITY_NAMES;
/* -------------------------------------------------------------------------
Multithreading support
------------------------------------------------------------------------- */
#ifdef _REENTRANT
#include <pthread.h>
/* Mutex to access chf_context during initialization and exit;
mutex to puts condition messages on stderr (DefaultHandler)
*/
static pthread_mutex_t context_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t fputs_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Chf data key */
static pthread_key_t data_key;
/* This function is called to destroy a Chf context when the owning
thread terminated.
*/
static void DestroyContext(void *context)
{
free(((ChfContext *)context)->message_buffer);
free(((ChfContext *)context)->handler_stack);
free(((ChfContext *)context)->condition_stack);
free(context);
}
#endif
/* -------------------------------------------------------------------------
Private functions
------------------------------------------------------------------------- */
/* .+
.title : DefaultHandler
.kind : C function
.creation : 17-May-1996
.description :
This function is the default condition handler of CHF. It's automatically
pushed into the condition handler stack by ChfInit() and performs the
following functions:
- if called during an unwind, it returns immediately to the caller,
requesting the action CHF_RESIGNAL, else
- if the severity of the condition being signalled is greater than
CHF_SUCCESS, it prints the messages associated with the entire
condition group on stderr using the standard function
ChfBuildMessage() to build the messages.
- if the severity of the condition being signalled is less than
CHF_FATAL, it returns to the caller requesting the action
CHF_CONTINUE, else
- if the CHF_FATAL condition was NOT signalled during an unwind
operation, it returns to the caller requesting the action
CHF_UNWIND, otherwise it requests the action CHF_RESIGNAL.
WIN32:
- stderr stream is not available and modal MessageBox require the
parent's handle to work reliably; the default handler does not print
anything
.call :
action = DefaultHandler(desc, state, context);
.input :
const ChfDescriptor *desc, condition descriptor
const ChfState state, current CHF state
.output :
ChfAction action, action requested by the handler
.status_codes :
none
.notes :
1.1, 16-May-1996, creation
1.6, 15-Jan-1997, update:
- the Chf condition handlers now have a third argument: the private
handler context pointer.
2.1, 25-May-2000, update:
- added multithreading support
2.2, 22-Jan-2001, update:
- added Win32 support
.- */
static ChfAction DefaultHandler(
const ChfDescriptor *desc,
const ChfState state,
ChfPointer handler_context
)
{
ChfAction action;
const ChfDescriptor *d;
if(state == CHF_UNWINDING)
/* If CHF is unwinding, do nothing */
action = CHF_RESIGNAL;
else
{
/* Print the condition messages, if necessary. The sequence of fputs()
is done atomically if multithreading support is enabled.
In Win32, the default handler does not print anything.
*/
if(ChfGetSeverity(desc) > CHF_SUCCESS)
{
#ifdef _REENTRANT
if(pthread_mutex_lock(&fputs_mutex)) ChfAbort(CHF_ABORT_PTHREAD);
#endif
#ifndef _WIN32
for(d = desc; d != CHF_NULL_DESCRIPTOR; d = ChfGetNextDescriptor(d))
fputs(ChfBuildMessage(d), stderr);
#endif
#ifdef _REENTRANT
if(pthread_mutex_unlock(&fputs_mutex)) ChfAbort(CHF_ABORT_PTHREAD);
#endif
}
/* Determine the handler action */
switch(ChfGetSeverity(desc))
{
case CHF_SUCCESS:
case CHF_INFO:
case CHF_WARNING:
case CHF_ERROR:
{
/* Continue execution if the severity is less than CHF_FATAL */
action = CHF_CONTINUE;
break;
}
default:
{
/* The severity of the condition is CHF_FATAL; appempt to unwind if
the fatal condition wasn't signalled during another unwind.
*/
action = ((state == CHF_SIGNAL_UNWINDING) ? CHF_RESIGNAL: CHF_UNWIND);
break;
}
}
}
/* Return the action code to the Chf handler dispatcher */
return action;
}
/* .+
.title : scopy
.kind : C function
.creation : 16-May-1996
.description :
This function writes the NUL-terminated string pointed by 'q' starting
from 'p', including the NUL terminator and without trepassing 'p_end'.
The function returns a pointer to the NUL-terminator just written.
.call :
np = scopy(p, q, p_end);
.input :
char *p, starting position for the write
const char *q, pointer to the string to be copied
char *p_end, pointer to the end of the output area
.output :
char *np, pointer to the NUL-terminator just written
.status_codes :
none
.notes :
1.1, 16-May-1996, creation
.- */
static ChfChar *scopy(
ChfChar *p,
const ChfChar *q,
ChfChar *p_end
)
{
size_t q_len = ChfStrlen(q);
size_t p_avail = p_end - p;
if(q_len < p_avail)
{
ChfStrcpy(p, q);
p += q_len;
}
else if(p_avail > 1)
{
ChfStrncpy(p, q, p_avail-2);
p[p_avail-1] = '\0';
p = p_end;
}
return p;
}
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfGetMessage
.kind : C function
.creation : 17-May-1996
.description :
This function retrieves the message associated with the pair
('module_id', 'condition_code') and returns a pointer to it. The function
will return 'default_message' if it isn't able to retrieve the message.
If module_id==CHF_ERRNO_SET, the function will use strerror(), if
necessary, to retrieve the requested message.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_INIT
if CHF hasn't been correctly initialized.
NOTE: The returned pointer points to per-thread static storage, which will be
overwritten by subsequent calls to this function.
WIN32:
- strerror() is not supported; the last-chance translation of condition
codes in CHF_ERRNO_SET is not performed
.call :
message = ChfGetMessage(module_id, condition_code,
default_message);
.input :
const int module_id, module identifier
const int condition_code, condition code
const char *default_message, default message
.output :
const char *message, pointer to the retrieved message
.status_codes :
none
.notes :
1.1, 17-May-1996, creation
2.2, 22-Jan-2001, update:
- added Win32 support
.- */
const ChfChar *ChfGetMessage( /* Retrieve a condition message */
const int module_id,
const int condition_code,
const ChfChar *default_message
)
{
const ChfChar *message;
/* Check that CHF has been correctly initialized */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
if((message = chf_context.mrs_get(chf_context.mrs_data,
module_id, condition_code, default_message)) == default_message &&
module_id == CHF_ERRNO_SET)
# ifdef _WIN32
message = default_message;
# else
message = strerror(condition_code);
# endif
return(message);
}
/* .+
.title : ChfBuildMessage
.kind : C function
.creation : 16-May-1996
.description :
This function builds the message associated with the given condition
descriptor and returns a pointer to a string containing it.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_INIT
if CHF hasn't been correctly initialized.
NOTE: The returned pointer points to per-thread static storage, which will be
overwritten by subsequent calls to this function.
WIN32:
- to save space, the application's name and severity code are not
included in the message
.call :
msg = ChfBuildMessage(descriptor);
.input :
const ChfDescriptor *descriptor, condition descriptor
.output :
char *msg, pointer to the message associated with 'descriptor'
.status_codes :
none
.notes :
1.1, 16-May-1996, creation
2.2, 22-Jan-2001, update:
- added Win32 support
.- */
ChfChar *ChfBuildMessage( /* Build a condition message */
const ChfDescriptor *descriptor
)
{
ChfChar *tmp_p;
ChfChar *tmp_end;
ChfChar def_message[CHF_DEF_MESSAGE_LENGTH];
ChfSeverity severity;
/* Check that CHF has been correctly initialized */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
/* Set appropriate pointers to the start/end of the message buffer */
tmp_p = chf_context.message_buffer;
tmp_end = tmp_p + CHF_MAX_MESSAGE_LENGTH;
#ifndef _WIN32
/* The message starts with "<app_name>: " if the condition is the first of
its condition group, with "\t" if not.
*/
if(descriptor == chf_context.condition_sp-1)
{
tmp_p = scopy(tmp_p, chf_context.app_name, tmp_end);
tmp_p = scopy(tmp_p, separator, tmp_end);
}
else
tmp_p = scopy(tmp_p, ChfText("\t"), tmp_end);
#endif
/* The message continues with the module name */
ChfSprintf(def_message, CHF_DEF_MID_MSG_FMT, ChfGetModuleId(descriptor));
tmp_p = scopy(tmp_p,
ChfGetMessage(CHF_MODULE_NAMES_SET, ChfGetModuleId(descriptor),
def_message), tmp_end);
/* Add also the extended information, if any */
if(ChfGetLineNumber(descriptor) != CHF_UNKNOWN_LINE_NUMBER)
{
tmp_p = scopy(tmp_p, ChfText(" "), tmp_end);
ChfSprintf(def_message, CHF_EXTENDED_INFO_FMT,
ChfGetFileName(descriptor), ChfGetLineNumber(descriptor));
tmp_p = scopy(tmp_p, def_message, tmp_end);
}
tmp_p = scopy(tmp_p, separator, tmp_end);
#ifndef _WIN32
/* Add the severity code of the message */
tmp_p = scopy(tmp_p,
((severity = ChfGetSeverity(descriptor)) < CHF_SUCCESS ||
severity > CHF_FATAL) ? CHF_UNKNOWN_SEVERITY : severity_name[severity],
tmp_end);
tmp_p = scopy(tmp_p, separator, tmp_end);
#endif
/* The message ends with the partial message from the descriptor */
tmp_p = scopy(tmp_p, ChfGetPartialMessage(descriptor), tmp_end);
(void)scopy(tmp_p, CHF_MESSAGE_TERMINATOR, tmp_end);
return chf_context.message_buffer;
}
/* .+
.title : ChfInit
.kind : C function
.creation : 13-May-1996
.description :
This function initializes CHF and returns to the caller a condition code;
that code will be either CHF_S_OK if the initialization was succesful,
or one of the other values listed below.
It's necessary to invoke succesfully ChfInit() before using any other CHF
function.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_DUP_INIT
if CHF has already been initialized before.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_PTHREAD
if a pthread operation fails.
.call :
cc = ChfInit(app_name, options,
mrs_data, mrs_get, mrs_exit,
condition_stack_size, handler_stack_size,
exit_code);
.input :
const char *app_name, Application's name
const ChfOptions options, Options
void *mrs_data, Message retrieval private data
ChfMrsGet mrs_get, 'GetMessage' function
ChfMrsExit mrs_exit, 'Exit' function
const int condition_stack_size, Size of the condition stack
const int handler_stack_size, Size of the handler stack
const int exit_code, Abnormal exit code
.output :
int cc, condition code
.status_codes :
CHF_F_MALLOC, FATAL, dynamic memory allocation failed
.notes :
1.1, 13-May-1996, creation
1.6, 15-Jan-1997, update:
- updated the call to ChfPushHandler() to accomodate its new interface.
2.1, 19-May-2000, update:
- added multithreading support
2.2, 22-Jan-2001, update:
- added Win32 support; a malloc() call was not portable.
.- */
int ChfInit( /* Generic initialization */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
void *mrs_data, /* Message retrieval private data */
ChfMrsGet mrs_get, /* 'GetMessage' function */
ChfMrsExit mrs_exit, /* 'Exit' function */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
)
{
int cc;
/* Check that CHF has not been initialized yet */
#ifndef _REENTRANT
if(_chf_context.state != CHF_UNKNOWN) ChfAbort(CHF_ABORT_DUP_INIT);
#else
/* Reentrant check; lock context_mutex first */
if(pthread_mutex_lock(&context_mutex)) ChfAbort(CHF_ABORT_PTHREAD);
if(_chf_context.state != CHF_UNKNOWN)
{
if(pthread_mutex_unlock(&context_mutex)) ChfAbort(CHF_ABORT_PTHREAD);
ChfAbort(CHF_ABORT_DUP_INIT);
}
#endif
#ifndef _REENTRANT
if((_chf_context.condition_stack =
(ChfDescriptor *)
malloc((size_t)(condition_stack_size+1)*sizeof(ChfDescriptor))) ==
CHF_NULL_DESCRIPTOR)
cc = CHF_F_MALLOC;
else if((_chf_context.handler_stack =
(ChfHandlerDescriptor *)
malloc((size_t)handler_stack_size*sizeof(ChfHandlerDescriptor))) ==
(ChfHandlerDescriptor *)NULL)
{
free(_chf_context.condition_stack);
cc = CHF_F_MALLOC;
}
else if((_chf_context.message_buffer =
(ChfChar *)malloc(
(size_t)(CHF_MAX_MESSAGE_LENGTH) * sizeof(ChfChar))) == (ChfChar *)NULL)
{
free(_chf_context.condition_stack);
free(_chf_context.handler_stack);
cc = CHF_F_MALLOC;
}
else
#else
/* Reentrant init: condition_stack, handler_stack, message_buffer
are not needed in the master Chf context.
Init the Chf data key instead.
*/
_chf_context.condition_stack = CHF_NULL_DESCRIPTOR;
_chf_context.handler_stack = (ChfHandlerDescriptor *)NULL;
_chf_context.message_buffer = (char *)NULL;
if(pthread_key_create(&data_key, DestroyContext))
ChfAbort(CHF_ABORT_PTHREAD);
#endif
{
/* Initialize the CHF context */
_chf_context.app_name = app_name;
_chf_context.options = options;
_chf_context.mrs_data = mrs_data;
_chf_context.mrs_get = mrs_get;
_chf_context.mrs_exit = mrs_exit;
_chf_context.condition_stack_size = condition_stack_size;
_chf_context.handler_stack_size = handler_stack_size;
_chf_context.exit_code = exit_code;
_chf_context.condition_base = _chf_context.condition_sp =
_chf_context.condition_stack;
_chf_context.handler_sp = _chf_context.handler_stack;
_chf_context.state = CHF_IDLE;
#ifndef _REENTRANT
/* Push the default handler; in the reentrant case, this will be
done once per thread, when the thread-specific context is primed.
*/
ChfPushHandler(DefaultHandler, CHF_NULL_CONTEXT, CHF_NULL_POINTER);
#endif
cc = CHF_S_OK;
}
#ifdef _REENTRANT
if(pthread_mutex_unlock(&context_mutex)) ChfAbort(CHF_ABORT_PTHREAD);
#endif
return cc;
}
/* .+
.title : ChfExit
.kind : C function
.creation : 24-May-1996
.description :
This function shuts down CHF and returns nothing to the caller; after
calling ChfExit() the application can continue, but any subsequent call
to any other CHF function, except the inizialization functions, will abort
the application using ChfAbort() with abort code CHF_ABORT_INIT.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_INIT
if CHF hasn't been initialized.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_PTHREAD
if a pthread operation fails.
.call :
ChfExit();
.input :
void
.output :
void
.status_codes :
none
.notes :
1.1, 24-May-1996, creation
2.1, 19-May-2000, update:
- added multithreading support
.- */
void ChfExit(
void
)
{
/* Check that CHF has been correctly initialized */
#ifndef _REENTRANT
if(_chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
#else
/* Reentrant check; lock context_mutex first */
if(pthread_mutex_lock(&context_mutex)) ChfAbort(CHF_ABORT_PTHREAD);
if(_chf_context.state == CHF_UNKNOWN)
{
if(pthread_mutex_unlock(&context_mutex)) ChfAbort(CHF_ABORT_PTHREAD);
ChfAbort(CHF_ABORT_INIT);
}
#endif
/* Destroy the context associated with this thread now; this is necessary
to ensure that the context is actually destroyed when a single-threaded
application links with the multithreaded version of Chf: in this case,
pthread_exit() is called *after* ChfExit(), the Chf data key no longer
exists when pthread_exit() is called and the destructor registered
with pthread_key_create() does not take place.
The data pointer associated with the Chf data key is set to NULL to
avoid any subsequent reactivation of the destructor.
*/
#ifdef _REENTRANT
DestroyContext(&chf_context);
if(pthread_setspecific(data_key, (void *)NULL))
{
(void)pthread_mutex_unlock(&context_mutex);
ChfAbort(CHF_ABORT_PTHREAD);
}
#endif
/* Shut down the message retrieval subsystem first */
_chf_context.mrs_exit(_chf_context.mrs_data);
#ifndef _REENTRANT
/* Free the dynamic memory previously allocated */
free(_chf_context.message_buffer);
free(_chf_context.handler_stack);
free(_chf_context.condition_stack);
#else
/* Destroy the Chf data key */
if(pthread_key_delete(data_key)) ChfAbort(CHF_ABORT_PTHREAD);
#endif
/* Reset CHF state to prevent subsequent calls to ChfExit() itself */
_chf_context.state = CHF_UNKNOWN;
#ifdef _REENTRANT
if(pthread_mutex_unlock(&context_mutex)) ChfAbort(CHF_ABORT_PTHREAD);
#endif
}
/* .+
.title : _ChfGetContext
.kind : C function
.creation : 19-May-2000
.description :
This function dynamically primes a new Chf context for the calling
thread (if necessary), and returns a pointer to that context to
the caller. If something does wrong, it aborts the application
with ChfAbort(CHF_ABORT_GET_CONTEXT).
Results are unpredictable if this function is called before a
successful call to ChfInit().
.call :
context = _ChfGetContext(void);
.input :
.output :
ChfContext *context, per-thread Chf context
.status_codes :
none
.notes :
2.1, 19-May-2000, creation
.- */
ChfContext *_ChfGetContext(
void
)
{
ChfContext *context;
#ifndef _REENTRANT
/* This function is doomed to fail if _REENTRANT is not defined */
ChfAbort(CHF_ABORT_GET_CONTEXT);
return((ChfContext *)NULL);
#else
/* Get the thread-specific context pointer associated with the
CHF data key */
if((context = (ChfContext *)pthread_getspecific(data_key))
== (ChfContext *)NULL)
{
/* No context pointer; prime a new one, cloning the master context */
if((context = (ChfContext *)malloc(sizeof(ChfContext)))
== (ChfContext *)NULL)
ChfAbort(CHF_ABORT_GET_CONTEXT);
memcpy(context, &_chf_context, sizeof(ChfContext));
/* Allocate per-thread stacks and message buffer */
if((context->condition_stack =
(ChfDescriptor *)
malloc((size_t)(context->condition_stack_size+1)
*sizeof(ChfDescriptor))) == CHF_NULL_DESCRIPTOR)
ChfAbort(CHF_ABORT_GET_CONTEXT);
if((context->handler_stack =
(ChfHandlerDescriptor *)
malloc((size_t)(context->handler_stack_size)
*sizeof(ChfHandlerDescriptor))) == (ChfHandlerDescriptor *)NULL)
{
free(context->condition_stack);
ChfAbort(CHF_ABORT_GET_CONTEXT);
}
if((context->message_buffer =
(char *)
malloc((size_t)(CHF_MAX_MESSAGE_LENGTH))) == (char *)NULL)
{
free(context->condition_stack);
free(context->handler_stack);
ChfAbort(CHF_ABORT_GET_CONTEXT);
}
/* Initialize stack pointers */
context->condition_base = context->condition_sp =
context->condition_stack;
context->handler_sp = context->handler_stack;
/* Set the thread-specific context pointer; this must be done
before invoking any other function using the context,
including ChfPushHandler() below.
*/
if(pthread_setspecific(data_key, context))
ChfAbort(CHF_ABORT_GET_CONTEXT);
/* Push the default handler */
ChfPushHandler(DefaultHandler, CHF_NULL_CONTEXT, CHF_NULL_POINTER);
}
return context;
#endif
}

201
Chf/chf_msgc.c Normal file
View file

@ -0,0 +1,201 @@
/* .+
.identifier : $Id: chf_msgc.c,v 2.2 2001/01/25 14:06:47 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_msgc.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 17-May-1996
.keywords : *
.description :
This module contains the CHF initialization function ChfMsgcatInit()
.include : Chf.h
.notes :
$Log: chf_msgc.c,v $
Revision 2.2 2001/01/25 14:06:47 cibrario
Added partial Win32 support (Windows CE only).
Revision 1.3 1996/06/21 14:19:22 cibrario
Bug fix: the private context of the message retrieval facility was
never freed by ExitMessage()
Revision 1.1 1996/05/28 12:55:15 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_msgc.c,v 2.2 2001/01/25 14:06:47 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifndef _WIN32
#include <locale.h>
#include <nl_types.h>
#endif
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Global and static variables
------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
Private type definitions
------------------------------------------------------------------------- */
#ifndef _WIN32
typedef struct
{
nl_catd catalog; /* Message catalog descriptor */
}
ChfMsgcatContext;
#endif
/* -------------------------------------------------------------------------
Private functions
------------------------------------------------------------------------- */
#ifndef _WIN32
static const char *GetMessage(
void *private_context,
const int module_id,
const int condition_code,
const char *default_message
)
{
return(catgets(((ChfMsgcatContext *)private_context)->catalog, module_id,
condition_code, default_message));
}
static void ExitMessage(
void *private_context
)
{
(void)catclose(((ChfMsgcatContext *)private_context)->catalog);
free(private_context);
}
#endif
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfMsgcatInit
.kind : C function
.creation : 17-May-1996
.description :
This function initializes CHF and returns to the caller a condition code;
that code will be either CHF_S_OK if the initialization was succesful,
or one of the other values listed below.
It's necessary to invoke succesfully either ChfMsgcatInit() or one of the
other CHF initialization routines before using any other CHF function.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_DUP_INIT
if CHF has already been initialized before.
WIN32:
- this function is not available due to lack of system support, and
always returns CHF_F_NOT_AVAILABLE
.call :
cc = ChfMsgcatInit(app_name, options,
msgcat_name,
condition_stack_size, handler_stack_size,
exit_code);
.input :
const char *app_name, Application's name
const ChfOptions options, Options
const char *msgcat_name, Name of the message catalog
const int condition_stack_size, Size of the condition stack
const int handler_stack_size, Size of the handler stack
const int exit_code, Abnormal exit code
.output :
int cc, condition code
.status_codes :
CHF_F_SETLOCALE, setlocale() failed
CHF_F_CATOPEN, catopen() failed
CHF_F_MALLOC, FATAL, memory allocation failed
CHF_F_NOT_AVAILABLE, FATAL, function not available
.notes :
1.1, 17-May-1996, creation
2.2, 22-Jan-2001, update:
- added Win32 support
.- */
int ChfMsgcatInit( /* Initialization with msgcat subsystem */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
const ChfChar *msgcat_name, /* Name of the message catalog */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
)
{
#ifdef _WIN32
/* This function always fails in _WIN32, because message catalogs
are not supported.
*/
return CHF_F_NOT_AVAILABLE;
#else
ChfMsgcatContext *private_context;
int cc;
if((private_context =
(ChfMsgcatContext *)malloc(sizeof(ChfMsgcatContext))) ==
(ChfMsgcatContext *)NULL)
cc = CHF_F_MALLOC;
else if(setlocale(LC_ALL, "") == (char *)NULL)
{
free(private_context);
cc = CHF_F_SETLOCALE;
}
else if((private_context->catalog = catopen(msgcat_name, 0)) ==
(nl_catd)(-1))
{
free(private_context);
cc = CHF_F_CATOPEN;
}
else if((cc = ChfInit(app_name, options, (void *)private_context,
GetMessage, ExitMessage, condition_stack_size, handler_stack_size,
exit_code)) != CHF_S_OK)
{
(void)catclose(private_context->catalog);
free(private_context);
}
else
cc = CHF_S_OK;
return cc;
#endif
}

402
Chf/chf_sig.c Normal file
View file

@ -0,0 +1,402 @@
/* .+
.identifier : $Id: chf_sig.c,v 2.2 2001/01/25 14:07:42 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_sig.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 3-May-1996
.keywords : *
.description :
This module implements the condition signalling function of CHF
.include : Chf.h
.notes :
$Log: chf_sig.c,v $
Revision 2.2 2001/01/25 14:07:42 cibrario
Added partial Win32 support (Windows CE only).
Revision 2.1 2000/05/26 14:31:28 cibrario
- Fixed spelling of CHF_SIGNALLING -> CHF_SIGNALING
- Replaced longjmp() with siglongjmp()
- New ChfAction code CHF_UNWIND_KEEP: ChfSignal() unwinds the
execution stack, but keeps the topmost condition group on the
condition stack
Revision 1.6 1997/01/15 13:34:45 cibrario
Fixed a wrong adjustment of the condition handler stack pointer after
an unwind operation.
Updated the condition handler calls in order to pass to the handlers the
private handler context pointer.
Revision 1.1 1996/05/28 12:55:51 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_sig.c,v 2.2 2001/01/25 14:07:42 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* .+
.title : ChfSignal
.kind : C function
.creation : 10-May-1996
.description :
This function signals the topmost condition group currently in the
condition stack, and performs the actions requested by the condition
handlers.
NOTE: This function uses the CHF function 'ChfAbort()' to
abort the application if either
- CHF has not been initialized correctly (abort code CHF_ABORT_INIT)
- the last handler on the handler stack has returned an invalid action
code (abort code CHF_ABORT_INVALID_ACTION)
- one of the handlers has requested the CHF_UNWIND action while
CHF was already unwinding (abort code CHF_ABORT_ALREADY_UNWINDING)
- a CHF_FATAL condition was signalled while CHF was unwinding
(abort code CHF_ABORT_FATAL_UNWINDING)
- all the handlers refused to handle a condition (abort code
CHF_ABORT_IMPROPERLY_HANDLED)
.call :
ChfSignal();
.input :
void
.output :
void
.status_codes :
(*) CHF_F_COND_STACK_FULL, the condition stack is full
(*) CHF_F_INVALID_ACTION, invalid handler action (%d)
.notes :
1.1, 10-May-1996, creation
1.6, 15-Jan-1997, update & bug fix:
- fixed a wrong adjustment of the condition handler stack pointer after
an unwind operation.
- updated the condition handler calls in order to pass to the handlers the
private handler context pointer, too.
2.1, 19-May-2000, update:
- added support for structured condition handling
.- */
void ChfSignal(
void
)
{
ChfState saved_state;
ChfDescriptor *saved_condition_base;
ChfDescriptor *current_condition;
ChfHandlerDescriptor *saved_handler_sp;
ChfHandlerDescriptor *handler_up;
ChfHandlerDescriptor *unwind_handler;
ChfAction handler_result;
/* Check that CHF has been correctly initialized and save the current CHF
state. If CHF was CHF_IDLE change state to CHF_SIGNALING, else if CHF was
CHF_UNWINDING change to CHF_SIGNAL_UNWINDING, otherwise remain in the
previous state (that must be CHF_SIGNALING)
*/
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
saved_state = chf_context.state;
if(chf_context.state == CHF_IDLE)
chf_context.state = CHF_SIGNALING;
else if(chf_context.state == CHF_UNWINDING)
chf_context.state = CHF_SIGNAL_UNWINDING;
if(chf_context.condition_sp > chf_context.condition_base)
{
/* Save the base of the current condition group and then update it in
order to allow further generation of conditions inside the condition
handlers that will be called soon.
*/
current_condition = chf_context.condition_sp-1;
saved_condition_base = chf_context.condition_base;
chf_context.condition_base = chf_context.condition_sp;
/* Save the current condition handler pointer */
saved_handler_sp = chf_context.handler_sp;
/* Call the condition handlers; the loop will exit either:
- when the handler stack is empty, or
- when the current handler returns either CHF_CONTINUE or CHF_UNWIND
*/
handler_result = CHF_RESIGNAL;
while(handler_result == CHF_RESIGNAL &&
chf_context.handler_sp > chf_context.handler_stack)
{
chf_context.handler_sp--;
/* The current condition handler, described by chf_context.handler_sp,
can recursively invoke ChfGenerate() and ChfSignal().
ChfGenerate() will store the new condition group starting from
chf_context.condition_sp, that points to the first free slot
of the condition stack. During the first generation, since
chf_context.condition_sp == chf_context.condition_base, the
link pointer of the condition will be NULL and, therefore,
the condition will be the first of a new condition group.
ChfSignal() will signal the condition group described by the
stack block from chf_context.condition_base to
chf_context.condition_sp-1, if it contains at least one condition;
it will call the handlers starting from chf_context.handler_sp-1,
that describes the handler immediately preceding the current handler.
*/
handler_result = chf_context.handler_sp->handler(
current_condition, chf_context.state,
chf_context.handler_sp->handler_context);
/* When the CHF state is CHF_SIGNALING, any condition group generated
but not yet signalled when the current handler exits must be merged
with the condition group currently being signalled, in order to allow
the condition handlers to add their own conditions to the condition
group. If the severity of the previous condition group was CHF_FATAL,
the severity of the new group is forced to CHF_FATAL, too.
When the CHF state is CHF_UNWINDING, the condition group for
which the UNWIND has been requested is 'frozen', no further
modifications are allowed on it, and the condition group is simply
discarded.
*/
if(chf_context.condition_sp > chf_context.condition_base)
{
if(chf_context.state == CHF_SIGNALING)
{
/* Force the new severity to CHF_FATAL if necessary */
if(ChfGetSeverity(current_condition) == CHF_FATAL)
ChfGetSeverity(chf_context.condition_sp-1) = CHF_FATAL;
/* Link together the condition groups */
chf_context.condition_base->next = current_condition;
current_condition = chf_context.condition_sp-1;
chf_context.condition_base = chf_context.condition_sp;
}
else
chf_context.condition_sp = chf_context.condition_base;
}
/* The action CHF_CONTINUE is not allowed if the current condition
severity is CHF_FATAL; it's automatically changed to CHF_RESIGNAL
*/
if(handler_result == CHF_CONTINUE &&
ChfGetSeverity(current_condition) == CHF_FATAL)
handler_result = CHF_RESIGNAL;
}
/* Perform the action requested by the last condition handler invoked */
switch(handler_result)
{
case CHF_CONTINUE:
{
/* Restore the handler stack pointer; the next ChfSignal() invoked
from our same nesting level will invoke our same handler chain
again.
*/
chf_context.handler_sp = saved_handler_sp;
/* Discard the current condition group */
chf_context.condition_base = chf_context.condition_sp =
saved_condition_base;
/* Restore che saved CHF state */
chf_context.state = saved_state;
/* Continue from the instruction following the ChfSignal() */
break;
}
case CHF_UNWIND:
case CHF_UNWIND_KEEP:
{
/* Unwind the execution stack. Check that another unwind isn't
already in progress
*/
if(chf_context.state == CHF_UNWINDING)
ChfAbort(CHF_ABORT_ALREADY_UNWINDING);
else
{
/* Change CHF state */
chf_context.state = CHF_UNWINDING;
/* chf_context.handler_sp points to the condition handler that
has requested the unwind; call all the handlers again, starting
from saved_handler_sp (top of the handler stack) up to and
including chf_context.handler_sp.
*/
handler_up = saved_handler_sp;
while(handler_up > chf_context.handler_sp)
{
ChfAction unw_handler_result;
handler_up--;
/* The current condition handler, described by handler_up
can recursively invoke ChfGenerate() and ChfSignal().
ChfGenerate() will store the new condition group starting from
chf_context.condition_sp, that points to the first free slot
of the condition stack. During the first generation, since
chf_context.condition_sp == chf_context.condition_base, the
link pointer of the condition will be NULL and, therefore,
the condition will be the first of a new condition group.
ChfSignal() will generate the condition group described by the
stack block from chf_context.condition_base to
chf_context.condition_sp-1, if it contains at least one
condition; it will call the handlers starting from
chf_context.handler_sp-1, that describes the handler
immediately preceding the handler that has requested the unwind.
Further unwind requests are not allowed, and will trigger
the condition CHF_F_UNWINDING
*/
unw_handler_result = handler_up->handler(
current_condition, chf_context.state,
handler_up->handler_context);
/* When the CHF state is CHF_UNWINDING, any condition group
generated but not yet signalled when the current handler
returns must be discarded
*/
chf_context.condition_sp = chf_context.condition_base;
}
/* Restore the handler stack pointer, discarding the unwinded
condition handlers. chf_context.handler_sp points to the
handler that requested the unwind; that handler has been
unwinded and its location is now the first free slot in the
condition handler stack.
*/
unwind_handler = chf_context.handler_sp;
if(handler_result == CHF_UNWIND)
{
/* Normal unwind:
restore the condition stack pointers, discarding all condition
groups.
*/
chf_context.condition_base = chf_context.condition_sp =
chf_context.condition_stack;
}
else
{
/* Special unwind for structured condition handling:
restore the condition_base pointer only, to keep the
topmost condition group on the condition stack. This way,
the condition group remains accessible after the unwind.
*/
chf_context.condition_base = saved_condition_base;
}
/* Change the CHF state to CHF_IDLE, and execute longjmp().
If the handler hasn't a valid unwind_context associated with it,
simply abort the application.
*/
chf_context.state = CHF_IDLE;
if(unwind_handler->unwind_context == CHF_NULL_CONTEXT)
ChfAbort(CHF_ABORT_SILENT);
else
ChfSiglongjmp(unwind_handler->unwind_context, 1);
}
break;
}
case CHF_RESIGNAL:
{
ChfAbort(
(chf_context.state == CHF_SIGNALING) ?
CHF_ABORT_IMPROPERLY_HANDLED : CHF_ABORT_FATAL_UNWINDING);
break;
}
default:
{
/* Invalid handler action detected; generate and immediately signal a
condition if the broken handler isn't the last handler on the stack,
otherwise call ChfAbort()
*/
if(chf_context.handler_sp > chf_context.handler_stack)
{
ChfCondition CHF_F_INVALID_ACTION, CHF_FATAL, handler_result
ChfEnd;
ChfSignal();
}
else
ChfAbort(CHF_ABORT_INVALID_ACTION);
break;
}
}
}
/* Restore the old CHF state */
chf_context.state = saved_state;
}
/* .+
.title : ChfDiscard
.kind : C function
.creation : 17-May-1996
.description :
This function discards the topmost condition group currently in the
condition stack, without signalling it. The function does nothing if
the condition stack is empty.
NOTE: This function uses the CHF function 'ChfAbort()' to
abort the application if either
- CHF has not been initialized correctly (abort code CHF_ABORT_INIT)
.call :
ChfDiscard();
.input :
void
.output :
void
.status_codes :
none
.notes :
1.1, 17-May-1996, creation
.- */
void ChfDiscard( /* Discard the current conditions */
void
)
{
/* Check that CHF has been correctly initialized */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
/* Reset the current condition stack pointer to the current condition
stack base pointer
*/
chf_context.condition_sp = chf_context.condition_base;
}

227
Chf/chf_st.c Normal file
View file

@ -0,0 +1,227 @@
/* .+
.identifier : $Id: chf_st.c,v 2.2 2001/01/25 14:08:45 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_st.c,v $, condition generation
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 24-May-1996
.keywords : *
.description :
This module implements the CHF initialization function ChfStaticInit()
.include : Chf.h
.notes :
$Log: chf_st.c,v $
Revision 2.2 2001/01/25 14:08:45 cibrario
Added partial Win32 support (Windows CE only).
Revision 1.1 1996/05/28 12:56:14 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_st.c,v 2.2 2001/01/25 14:08:45 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Global and static variables
------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
Private type definitions
------------------------------------------------------------------------- */
typedef struct
{
const ChfTable *table;
size_t size;
}
ChfStaticContext;
/* -------------------------------------------------------------------------
Private functions
------------------------------------------------------------------------- */
#ifdef _WIN32
/* Win32 does not have bsearch();
provide a simple one from glibc here.
*/
static void *bsearch(
const void *key,
const void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *)
)
{
size_t l, u, idx;
const void *p;
int comparison;
l = 0;
u = nmemb;
while (l < u)
{
idx = (l + u) / 2;
p = (void *) (((const char *) base) + (idx * size));
comparison = (*compar) (key, p);
if (comparison < 0)
u = idx;
else if (comparison > 0)
l = idx + 1;
else
return (void *) p;
}
return NULL;
}
#endif
#define GT 1
#define LT -1
#define EQ 0
static int Search(
const void *l,
const void *r
)
{
if(((ChfTable *)l)->module > ((ChfTable *)r)->module)
return(GT);
else if(((ChfTable *)l)->module < ((ChfTable *)r)->module)
return(LT);
else if(((ChfTable *)l)->code > ((ChfTable *)r)->code)
return(GT);
else if(((ChfTable *)l)->code < ((ChfTable *)r)->code)
return(LT);
return(EQ);
}
static const ChfChar *StGetMessage(
void *private_context,
const int module_id,
const int condition_code,
const ChfChar *default_message
)
{
ChfTable key;
ChfTable *res;
key.module = module_id;
key.code = condition_code;
if((res = bsearch(&key, ((ChfStaticContext *)private_context)->table,
((ChfStaticContext *)private_context)->size, sizeof(ChfTable), Search)) ==
(void *)NULL)
return(default_message);
return(((ChfTable *)res)->msg_template);
}
static void ExitMessage(
void *private_context
)
{
}
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfStaticInit
.kind : C function
.creation : 24-May-1996
.description :
This function initializes CHF and returns to the caller a condition code;
that code will be either CHF_S_OK if the initialization was succesful,
or one of the other values listed below.
It's necessary to invoke succesfully either ChfStaticInit() or one of the
other CHF initialization routines before using any other CHF function.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_DUP_INIT
if CHF has already been initialized before.
.call :
cc = ChfStaticInit(app_name, options,
table, table_size,
condition_stack_size, handler_stack_size,
exit_code);
.input :
const char *app_name, Application's name
const ChfOptions options, Options
const ChfTable *table, pointer to the static message table
const size_t table_size, size of the table (# of entries)
const int condition_stack_size, Size of the condition stack
const int handler_stack_size, Size of the handler stack
const int exit_code, Abnormal exit code
.output :
int cc, condition code
.status_codes :
CHF_F_MALLOC, FATAL, memory allocation failed
.notes :
1.1, 27-May-1996, creation
.- */
int ChfStaticInit( /* Initialization with static message tables */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
const ChfTable *table, /* Static message table */
const size_t table_size, /* Size of the message table */
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
)
{
ChfStaticContext *private_context;
int cc;
if((private_context =
(ChfStaticContext *)malloc(sizeof(ChfStaticContext))) ==
(ChfStaticContext *)NULL)
cc = CHF_F_MALLOC;
else if((cc = ChfInit(app_name, options, (void *)private_context,
StGetMessage, ExitMessage, condition_stack_size, handler_stack_size,
exit_code)) != CHF_S_OK)
free(private_context);
else
{
private_context->table = table;
private_context->size = table_size;
cc = CHF_S_OK;
}
return cc;
}

115
Chf/chf_top.c Normal file
View file

@ -0,0 +1,115 @@
/* .+
.identifier : $Id: chf_top.c,v 2.2 2001/01/25 14:09:21 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_top.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 5-Jun-1996
.keywords : *
.description :
This module implements the CHF function ChfGetTopCondition()
.include : Chf.h
.notes :
$Log: chf_top.c,v $
Revision 2.2 2001/01/25 14:09:21 cibrario
Added partial Win32 support (Windows CE only).
Revision 2.1 2000/05/26 14:23:33 cibrario
ChfGetTopCondition() used to return a pointer to the wrong condition
descriptor; fixed.
Revision 1.2 1996/06/11 12:47:17 cibrario
file creation
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_top.c,v 2.2 2001/01/25 14:09:21 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfGetTopCondition
.kind : C function
.creation : 5-Jun-1996
.description :
This function returns to the caller a pointer to the top condition of
the current condition group. It generates and immediately signals the
condition CHF_F_BAD_STATE if the current condition group is empty.
NOTE: During condition signalling, CHF creates a new, empty, condition group
immediately before starting the invocation sequence of the condition
handlers, as described in the documentation. Therefore
ChfGetTopCondition(), if called from a condition handler, will return
a pointer to the top condition generated during the handling ONLY, and
NOT to the top condition of the condition group being signalled. The
latter pointer is directly available, as an argument, to the condition
handlers.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_INIT
if CHF hasn't been correctly initialized.
NOTE: The returned pointer is no longer valid when any other CHF function
is called after ChfGetTopCondition().
.call :
d = ChfGetTopCondition();
.input :
void
.output :
const ChfDescriptor *d, condition descriptor
.status_codes :
.notes :
1.2, 17-May-1996, creation
2.1, 24-May-2000, bug fix:
- condition stack referenced incorrectly
.- */
const ChfDescriptor *ChfGetTopCondition( /* Retrieve top condition */
void
)
{
ChfDescriptor *d;
/* Check that CHF has been correctly initialized */
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
if((d = chf_context.condition_sp) == chf_context.condition_base)
{
ChfCondition CHF_F_BAD_STATE, CHF_FATAL ChfEnd;
ChfSignal();
}
/* The top element of the condition group is the element immediately
below the stack pointer.
*/
return d-1;
}

191
Chf/chf_win32.c Normal file
View file

@ -0,0 +1,191 @@
/* .+
.identifier : $Id: chf_win32.c,v 2.2 2001/01/25 14:11:58 cibrario Exp $
.context : CHF, Condition Handling Facility
.title : $RCSfile: chf_win32.c,v $, Win32 initialization function
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 19-Jan-2001
.keywords : *
.description :
This module contains the CHF initialization function ChfWin32Init()
.include : Chf.h
.notes :
$Log: chf_win32.c,v $
Revision 2.2 2001/01/25 14:11:58 cibrario
*** empty log message ***
.- */
#ifndef lint
static char rcs_id[] = "$Id: chf_win32.c,v 2.2 2001/01/25 14:11:58 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <errno.h>
#endif
#include <setjmp.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#endif
#include "Chf.h"
#include "ChfPriv.h"
/* -------------------------------------------------------------------------
Global and static variables
------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
Private type definitions
------------------------------------------------------------------------- */
#ifdef _WIN32
typedef struct
{
HINSTANCE instance; /* App. instance handle */
ChfChar buffer[CHF_MAX_MESSAGE_LENGTH]; /* Temporary buffer */
}
ChfWin32Context;
#endif
/* -------------------------------------------------------------------------
Private functions
------------------------------------------------------------------------- */
#ifdef _WIN32
static const ChfChar *Win32GetMessage(
void *private_context,
const int module_id,
const int condition_code,
const ChfChar *default_message
)
{
if(!LoadString(
((ChfWin32Context *)private_context)->instance,
module_id*1000 + condition_code,
((ChfWin32Context *)private_context)->buffer,
CHF_MAX_MESSAGE_LENGTH-1))
return default_message;
return ((ChfWin32Context *)private_context)->buffer;
}
static void ExitMessage(
void *private_context
)
{
free(private_context);
}
#endif
/* -------------------------------------------------------------------------
Public functions
------------------------------------------------------------------------- */
/* .+
.title : ChfWin32Init
.kind : C function
.creation : 19-Jan-2001
.description :
This function initializes CHF and returns to the caller a condition code;
that code will be either CHF_S_OK if the initialization was succesful,
or one of the other values listed below.
It's necessary to invoke succesfully either ChfWin32Init() or one of the
other CHF initialization routines before using any other CHF function.
NOTE: This function will call ChfAbort() with abort code CHF_ABORT_DUP_INIT
if CHF has already been initialized before.
WIN32:
- This function is available in Win32 only; it will return
CHF_F_NOT_AVAILABLE on Unix platforma.
- message retrieval is done through the LoadString() Win32 function.
This function does not support message sets, so the linear message id
passed to it is made by module_id*1000 + condition_code. The following
limits are in effect:
0 <= condition_code <= 999
0 <= module_id <= 64
.call :
cc = ChfWin32Init(app_name, options,
msgcat_name,
condition_stack_size, handler_stack_size,
exit_code);
.input :
const ChfChar *app_name, Application's name
const ChfOptions options, Options
HINSTANCE instance, App. instance handle
const int condition_stack_size, Size of the condition stack
const int handler_stack_size, Size of the handler stack
const int exit_code, Abnormal exit code
.output :
int cc, condition code
.status_codes :
CHF_F_MALLOC, FATAL, memory allocation failed
CHF_F_NOT_AVAILABLE, FATAL, function not available
.notes :
2.2, 19-Jan-2001, creation
.- */
int ChfWin32Init( /* Initialization within _WIN32 */
const ChfChar *app_name, /* Application's name */
const ChfOptions options, /* Options */
#ifndef _WIN32
void *instance, /* Fake arguments */
#else
HINSTANCE instance, /* App. instance handle */
#endif
const int condition_stack_size, /* Size of the condition stack */
const int handler_stack_size, /* Size of the handler stack */
const int exit_code /* Abnormal exit code */
)
{
#ifndef _WIN32
/* This function is available only in Win32 */
return CHF_F_NOT_AVAILABLE;
#else
ChfWin32Context *private_context;
int cc;
if((private_context =
(ChfWin32Context *)malloc(sizeof(ChfWin32Context))) ==
(ChfWin32Context *)NULL)
cc = CHF_F_MALLOC;
else if((cc = ChfInit(app_name, options, (void *)private_context,
Win32GetMessage, ExitMessage, condition_stack_size, handler_stack_size,
exit_code)) != CHF_S_OK)
{
free(private_context);
}
else
{
/* Save Win32 specific context items into private Chf context */
private_context->instance = instance;
cc = CHF_S_OK;
}
return cc;
#endif
}

485
Chf/libChf.vcp Executable file
View file

@ -0,0 +1,485 @@
# Microsoft eMbedded Visual Tools Project File - Name="libChf" - Package Owner=<4>
# Microsoft eMbedded Visual Tools Generated Build File, Format Version 6.02
# ** DO NOT EDIT **
# TARGTYPE "Win32 (WCE x86em) Static Library" 0x7f04
# TARGTYPE "Win32 (WCE ARM) Static Library" 0x8504
CFG=libChf - Win32 (WCE ARM) Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libChf.vcn".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libChf.vcn" CFG="libChf - Win32 (WCE ARM) Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libChf - Win32 (WCE ARM) Release" (based on "Win32 (WCE ARM) Static Library")
!MESSAGE "libChf - Win32 (WCE ARM) Debug" (based on "Win32 (WCE ARM) Static Library")
!MESSAGE "libChf - Win32 (WCE x86em) Release" (based on "Win32 (WCE x86em) Static Library")
!MESSAGE "libChf - Win32 (WCE x86em) Debug" (based on "Win32 (WCE x86em) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
# PROP ATL_Project 2
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ARMRel"
# PROP BASE Intermediate_Dir "ARMRel"
# PROP BASE CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}"
# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ARMRel"
# PROP Intermediate_Dir "ARMRel"
# PROP CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}"
# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP Target_Dir ""
CPP=clarm.exe
# ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "NDEBUG" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /Oxs /M$(CECrtMT) /c
# ADD CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "NDEBUG" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /Oxs /M$(CECrtMT) /c
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "ARMDbg"
# PROP BASE Intermediate_Dir "ARMDbg"
# PROP BASE CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}"
# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "ARMDbg"
# PROP Intermediate_Dir "ARMDbg"
# PROP CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}"
# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP Target_Dir ""
CPP=clarm.exe
# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /M$(CECrtMTDebug) /c
# ADD CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /M$(CECrtMTDebug) /c
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "X86EMRel"
# PROP BASE Intermediate_Dir "X86EMRel"
# PROP BASE CPU_ID "{D6518FF4-710F-11D3-99F2-00105A0DF099}"
# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "X86EMRel"
# PROP Intermediate_Dir "X86EMRel"
# PROP CPU_ID "{D6518FF4-710F-11D3-99F2-00105A0DF099}"
# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP Target_Dir ""
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "WIN32" /D "STRICT" /D "_WIN32_WCE_EMULATION" /D "INTERNATIONAL" /D "USA" /D "INTLMSG_CODEPAGE" /D "$(CePlatform)" /D "i486" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "NDEBUG" /D "_LIB" /YX /Oxs /Gz /c
# ADD CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "WIN32" /D "STRICT" /D "_WIN32_WCE_EMULATION" /D "INTERNATIONAL" /D "USA" /D "INTLMSG_CODEPAGE" /D "$(CePlatform)" /D "i486" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "NDEBUG" /D "_LIB" /YX /Oxs /Gz /c
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "X86EMDbg"
# PROP BASE Intermediate_Dir "X86EMDbg"
# PROP BASE CPU_ID "{D6518FF4-710F-11D3-99F2-00105A0DF099}"
# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "X86EMDbg"
# PROP Intermediate_Dir "X86EMDbg"
# PROP CPU_ID "{D6518FF4-710F-11D3-99F2-00105A0DF099}"
# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
# PROP Target_Dir ""
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "WIN32" /D "STRICT" /D "_WIN32_WCE_EMULATION" /D "INTERNATIONAL" /D "USA" /D "INTLMSG_CODEPAGE" /D "$(CePlatform)" /D "i486" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_LIB" /YX /Gz /c
# ADD CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "WIN32" /D "STRICT" /D "_WIN32_WCE_EMULATION" /D "INTERNATIONAL" /D "USA" /D "INTLMSG_CODEPAGE" /D "$(CePlatform)" /D "i486" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_LIB" /FR /YX /Gz /c
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
!ENDIF
# Begin Target
# Name "libChf - Win32 (WCE ARM) Release"
# Name "libChf - Win32 (WCE ARM) Debug"
# Name "libChf - Win32 (WCE x86em) Release"
# Name "libChf - Win32 (WCE x86em) Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\chf_abrt.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_A=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_A=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_A=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_A=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_gen.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_G=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_G=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_G=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_G=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_hdlr.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_H=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_H=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_H=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_H=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_init.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_I=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_I=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_I=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_I=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_msgc.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_M=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_M=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_M=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_M=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_sig.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_S=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_S=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_S=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_S=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_st.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_ST=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_ST=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_ST=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_ST=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_top.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_T=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_T=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_T=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_T=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\chf_win32.c
!IF "$(CFG)" == "libChf - Win32 (WCE ARM) Release"
DEP_CPP_CHF_W=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE ARM) Debug"
DEP_CPP_CHF_W=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Release"
DEP_CPP_CHF_W=\
".\Chf.h"\
".\ChfPriv.h"\
!ELSEIF "$(CFG)" == "libChf - Win32 (WCE x86em) Debug"
DEP_CPP_CHF_W=\
".\Chf.h"\
".\ChfPriv.h"\
!ENDIF
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\Chf.h
# End Source File
# Begin Source File
SOURCE=.\ChfPriv.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "rc"
# Begin Source File
SOURCE=.\chf.rc
# End Source File
# End Group
# End Target
# End Project

15
Chf/resource.h Executable file
View file

@ -0,0 +1,15 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by chf.rc
//
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

93
Chf/test01.c Normal file
View file

@ -0,0 +1,93 @@
/* $Id: test01.c,v 2.1 2000/05/29 13:55:50 cibrario Rel $
Chf test program.
Simple initialization.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
int main(int argc, char *argv[])
{
int st;
const char *msg;
const ChfDescriptor *d, *e;
puts("test01");
system("gencat test01.cat test01.msf");
system("gencat test01.cat chf.msf");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat", 50, 10, 1))
exit(st);
/* ChfGetMessage:
message (CHF_MODULE_ID, 1) exists, (CHF_MODULE_ID, 2) does not
*/
msg = ChfGetMessage(CHF_MODULE_ID, 1, "Default_1");
if(strcmp(msg, "Set_255,Message_1")) exit(EXIT_FAILURE);
msg = ChfGetMessage(CHF_MODULE_ID, 2, "Default_2");
if(strcmp(msg, "Default_2")) exit(EXIT_FAILURE);
/* Generate a condition and check descriptor; this is line 46 */
ChfCondition 3, CHF_WARNING, 456 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 3
|| d->severity != CHF_WARNING
|| d->line_number != 46
|| strcmp(d->file_name, "test01.c")
|| strcmp(d->message, "Set_255,Arg_456,Message_3")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Generate another condition and check; this is line 60 */
ChfCondition 4, CHF_INFO, "arg" ChfEnd;
if((e = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
e->module_id != CHF_MODULE_ID
|| e->condition_code != 4
|| e->severity != CHF_INFO
|| e->line_number != 60
|| strcmp(e->file_name, "test01.c")
|| strcmp(e->message, "Set_255,Arg_arg,Message_4")
|| e->next != d
) exit(EXIT_FAILURE);
/* Discard the previous condition group and create a new one */
ChfDiscard();
/* This is line 77 */
ChfCondition 5, CHF_ERROR, 456, 789 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 5
|| d->severity != CHF_ERROR
|| d->line_number != 77
|| strcmp(d->file_name, "test01.c")
|| strcmp(d->message, "Set_255,Arg_456-789,Message_5")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Exit Chf */
ChfExit();
exit(EXIT_SUCCESS);
}

18
Chf/test01.msf Normal file
View file

@ -0,0 +1,18 @@
$set 1
255 Chf Test
$set 255
1 Set_255,Message_1
3 Set_255,Arg_%d,Message_3
4 Set_255,Arg_%s,Message_4
5 Set_255,Arg_%d-%d,Message_5
6 Set_255,Message_6 (thread %d, sub-condition)
7 Set_255,Message_7 (thread %d, main)
8 Set_255,Message_8 (thread %d, main)
9 Set_255,Message_9
10 Invalid descriptor link detected
11 Bad hdlr stack push count %d; should be %d
12 Bad cond stack push count %d; should be %d
20 Structured exc handling test cond

121
Chf/test02.c Normal file
View file

@ -0,0 +1,121 @@
/* $Id: test02.c,v 2.1 2000/05/29 13:56:44 cibrario Rel $
Chf test program.
Simple initialization - multithreaded.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
void *task(void *arg)
{
const char *msg;
const ChfDescriptor *d, *e;
printf("\tThread %d\n", (int)arg);
/* message (CHF_MODULE_ID, 1) exists, (CHF_MODULE_ID, 2) does not */
msg = ChfGetMessage(CHF_MODULE_ID, 1, "Default_1");
if(strcmp(msg, "Set_255,Message_1")) exit(EXIT_FAILURE);
msg = ChfGetMessage(CHF_MODULE_ID, 2, "Default_2");
if(strcmp(msg, "Default_2")) exit(EXIT_FAILURE);
/* Generate a condition and check descriptor; this is line 36 */
ChfCondition 3, CHF_WARNING, 456 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 3
|| d->severity != CHF_WARNING
|| d->line_number != 36
|| strcmp(d->file_name, "test02.c")
|| strcmp(d->message, "Set_255,Arg_456,Message_3")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Generate another condition and check; this is line 50 */
ChfCondition 4, CHF_INFO, "arg" ChfEnd;
if((e = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
e->module_id != CHF_MODULE_ID
|| e->condition_code != 4
|| e->severity != CHF_INFO
|| e->line_number != 50
|| strcmp(e->file_name, "test02.c")
|| strcmp(e->message, "Set_255,Arg_arg,Message_4")
|| e->next != d
) exit(EXIT_FAILURE);
/* Discard the previous condition group and create a new one */
ChfDiscard();
/* This is line 67 */
ChfCondition 5, CHF_ERROR, 456, 789 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 5
|| d->severity != CHF_ERROR
|| d->line_number != 67
|| strcmp(d->file_name, "test02.c")
|| strcmp(d->message, "Set_255,Arg_456-789,Message_5")
|| d->next != NULL
) exit(EXIT_FAILURE);
return (void *)0;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test02");
#ifdef _REENTRANT
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat", 50, 10, 1))
exit(st);
/* Create */
for(i=0; i<N_THREADS; i++)
if(st = pthread_create(&(t[i]), NULL, task, (void *)i))
{
printf("pthread_create: error %d", st);
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
if(st = pthread_join(t[i], &ret))
{
printf("pthread_join: error %d", st);
exit(EXIT_FAILURE);
}
/* Exit Chf */
ChfExit();
#endif
exit(EXIT_SUCCESS);
}

90
Chf/test03.c Normal file
View file

@ -0,0 +1,90 @@
/* $Id: test03.c,v 2.1 2000/05/29 13:10:29 cibrario Rel $
Chf test program.
Generation and signal - single and multithreaded
$Log: test03.c,v $
Revision 2.1 2000/05/29 13:10:29 cibrario
*** empty log message ***
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
void *task(void *arg)
{
const char *msg;
const ChfDescriptor *d, *e;
/* The sleep() is here to increase contention between threads */
sleep(1);
printf("\tThread %d\n", (int)arg);
/* Generate a condition group and signal it */
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
/* The sleep() is here to increase contention between threads */
sleep(1);
ChfSignal();
return (void *)0;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test03");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat", 50, 10, 1))
exit(st);
#ifdef _REENTRANT
/* Create */
for(i=0; i<N_THREADS; i++)
if(pthread_create(&(t[i]), NULL, task, (void *)i))
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
if(pthread_join(t[i], &ret))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
#else
task((void *)0);
#endif
/* Exit Chf */
ChfExit();
exit(EXIT_SUCCESS);
}

331
Chf/test04.c Normal file
View file

@ -0,0 +1,331 @@
/* $Id: test04.c,v 2.1 2000/05/29 13:10:38 cibrario Rel $
Chf test program.
General condition handling - single and multithreaded
$Log: test04.c,v $
Revision 2.1 2000/05/29 13:10:38 cibrario
*** empty log message ***
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
struct tdata_s
{
const ChfDescriptor *d, *e;
int phase;
};
ChfAction h1(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
struct tdata_s *tdata_p = (struct tdata_s *)p;
ChfAction action;
if(c != tdata_p->e ||
ChfGetNextDescriptor(c) != tdata_p->d)
{
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
action = CHF_CONTINUE;
return action;
}
ChfAction h2(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
struct tdata_s *tdata_p = (struct tdata_s *)p;
ChfAction action;
switch(s)
{
case CHF_SIGNALING:
{
if(c != tdata_p->e
|| ChfGetNextDescriptor(c) != tdata_p->d
|| (tdata_p->phase != 2 && tdata_p->phase != 4))
{
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
{
action = (ChfGetConditionCode(c) != 8 ? CHF_CONTINUE : CHF_UNWIND);
}
break;
}
case CHF_UNWINDING:
{
if(tdata_p->phase != 4) exit(EXIT_FAILURE);
tdata_p->phase = 5;
action = CHF_CONTINUE;
break;
}
default:
{
exit(EXIT_FAILURE);
}
}
return action;
}
ChfAction h3(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
struct tdata_s *tdata_p = (struct tdata_s *)p;
ChfAction action;
/* This handler must be invoked only during the first signal */
if(tdata_p->phase != 3) exit(EXIT_FAILURE);
switch(s)
{
case CHF_SIGNALING:
{
if(ChfGetConditionCode(c) != 9 ||
ChfGetNextDescriptor(c) != NULL)
{
exit(EXIT_FAILURE);
}
else
{
tdata_p->phase = 4;
action = CHF_CONTINUE;
}
break;
}
default:
{
exit(EXIT_FAILURE);
}
}
return action;
}
ChfAction h4(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
struct tdata_s *tdata_p = (struct tdata_s *)p;
ChfAction action;
/* This handler must be invoked only during the first signal */
if(tdata_p->phase != 2) exit(EXIT_FAILURE);
switch(s)
{
case CHF_SIGNALING:
{
if(c != tdata_p->e
|| ChfGetNextDescriptor(c) != tdata_p->d)
{
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
{
/* This generates a new group and signals it */
tdata_p->phase = 3;
ChfCondition 9, CHF_INFO ChfEnd;
ChfSignal();
if(tdata_p->phase != 4) exit(EXIT_FAILURE);
tdata_p->phase = 5;
if(c != tdata_p->e
|| ChfGetNextDescriptor(c) != tdata_p->d)
{
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
action = CHF_CONTINUE;
}
break;
}
default:
{
exit(EXIT_FAILURE);
}
}
return action;
}
void *task(void *arg)
{
volatile struct tdata_s tdata;
/* The sleep() is here to increase contention between threads */
sleep(1);
printf("\tThread %d\n", (int)arg);
/* Push the handler */
ChfPushHandler(h1, NULL, (ChfPointer)(&tdata));
/* Generate a condition group and signal it */
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* The sleep() is here to increase contention between threads */
sleep(1);
ChfSignal();
/* Pop the handler */
ChfPopHandler();
/* Generate a new condition group with (apparently) wrong linkage
and signal it; this checks that the handler has actually been
removed.
*/
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = NULL;
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
tdata.e = NULL;
ChfSignal();
/* Conditional unwind test */
{
sigjmp_buf jb;
tdata.phase = 0;
if(setjmp(jb) == 0)
{
ChfPushHandler(h2, jb, (ChfPointer)(&tdata));
/* Generate a condition group and signal it */
tdata.phase = 1;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* This does not trigger an unwind */
tdata.phase = 2;
ChfSignal();
tdata.phase = 3;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 8, CHF_INFO, (int)arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* This MUST trigger an unwind */
tdata.phase = 4;
ChfSignal();
exit(EXIT_FAILURE);
}
else
{
/* Unwind */
if(tdata.phase != 5)
exit(EXIT_FAILURE);
ChfPopHandler();
}
}
/* Condition generation and signal while a signal is in progress;
this requires two handlers.
*/
{
tdata.phase = 0;
ChfPushHandler(h3, NULL, (ChfPointer)&tdata);
ChfPushHandler(h4, NULL, (ChfPointer)&tdata);
tdata.phase = 1;
ChfCondition 6, CHF_INFO, (int)arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, (int)arg ChfEnd;
tdata.e = ChfGetTopCondition();
tdata.phase = 2;
ChfSignal();
if(tdata.phase != 5)
exit(EXIT_FAILURE);
ChfPopHandler();
ChfPopHandler();
}
return (void *)0;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test04");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat", 50, 10, 1))
exit(st);
#ifdef _REENTRANT
/* Create */
for(i=0; i<N_THREADS; i++)
if(pthread_create(&(t[i]), NULL, task, (void *)i))
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
if(pthread_join(t[i], &ret))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
#else
task((void *)0);
#endif
/* Exit Chf */
ChfExit();
exit(EXIT_SUCCESS);
}

247
Chf/test05.c Normal file
View file

@ -0,0 +1,247 @@
/* $Id: test05.c,v 2.1 2000/05/29 13:10:46 cibrario Rel $
Chf test program.
Condition & Handler stacks oveflow checks - single and multithreaded
$Log: test05.c,v $
Revision 2.1 2000/05/29 13:10:46 cibrario
*** empty log message ***
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
#define H_STACK_SIZE 10
#define C_STACK_SIZE 30
/* Dummy handler; pushed only to verify that the handler stack overflow
checks are correct.
*/
ChfAction h1(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
return CHF_RESIGNAL;
}
/* Overflow check handler; it unwinds if the CHF_F_HDLR_STACK_FULL
condition is signalled exactly after H_STACK_SIZE-2 invocations
of ChfPushHandler(), it resignals a modified condition if the
condition is signalled too early
*/
ChfAction h2(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
int push_count = *((int *)p);
ChfAction action;
if(s == CHF_SIGNALING)
{
if(ChfGetModuleId(c) == CHF_SET
&& ChfGetConditionCode(c) == CHF_F_HDLR_STACK_FULL)
{
/* Handler stack is full; check correctness of the descriptor */
if(push_count == H_STACK_SIZE-2
&& ChfGetNextDescriptor(c) == NULL
&& ChfGetSeverity(c) == CHF_FATAL)
action = CHF_UNWIND;
else
{
ChfCondition 11, CHF_FATAL, push_count, H_STACK_SIZE-2
ChfEnd;
action = CHF_RESIGNAL;
}
}
}
else
action = CHF_RESIGNAL;
return action;
}
/* Overflow check handler; it unwinds if the CHF_F_COND_STACK_FULL
condition is signalled exactly after C_STACK_SIZE invocations
of ChfCondition, it resignals a modified condition if the
condition is signalled too early
*/
ChfAction h3(
const ChfDescriptor *c,
const ChfState s,
ChfPointer p
)
{
int push_count = *((int *)p);
ChfAction action;
if(s == CHF_SIGNALING)
{
if(ChfGetModuleId(c) == CHF_SET
&& ChfGetConditionCode(c) == CHF_F_COND_STACK_FULL)
{
/* Handler stack is full; check correctness of the descriptor */
if(push_count == C_STACK_SIZE
&& ChfGetNextDescriptor(c) == NULL
&& ChfGetSeverity(c) == CHF_FATAL)
action = CHF_UNWIND;
else
{
ChfCondition 12, CHF_FATAL, push_count, C_STACK_SIZE
ChfEnd;
action = CHF_RESIGNAL;
}
}
}
else
action = CHF_RESIGNAL;
return action;
}
void *task(void *arg)
{
int push_count = 0;
sigjmp_buf jb;
/* The sleep() is here to increase contention between threads */
sleep(1);
printf("\tThread %d\n", (int)arg);
/* Check handler stack overflow checks */
if(sigsetjmp(jb, 1) == 0)
{
int i;
/* Push the handler */
ChfPushHandler(h2, jb, (ChfPointer)(&push_count));
/* The sleep() is here to increase contention between threads */
sleep(1);
/* Push dummy handlers until an error should occur */
for(; push_count<H_STACK_SIZE-1; push_count++)
ChfPushHandler(h1, NULL, NULL);
/* No error? Bad! */
return (void *)EXIT_FAILURE;
}
/* Flow control returns here if 'handler stack full' was signalled
at the correct place.
Check condition stack overflow checks
*/
push_count = 0;
if(sigsetjmp(jb, 1) == 0)
{
int i;
/* Push the handler */
ChfPushHandler(h3, jb, (ChfPointer)(&push_count));
/* The sleep() is here to increase contention between threads */
sleep(1);
/* Push dummy conditions until an error should occur */
for(; push_count<=C_STACK_SIZE; push_count++)
ChfCondition 1, CHF_INFO ChfEnd;
/* No error? Bad! */
return (void *)EXIT_FAILURE;
}
/* Flow control returns here if 'condition stack full' was signalled
at the correct place.
Check condition stack overflow again, to ensure that no spurious
conditions were left out in the previous check.
*/
push_count = 0;
if(sigsetjmp(jb, 1) == 0)
{
int i;
/* Push the handler */
ChfPushHandler(h3, jb, (ChfPointer)(&push_count));
/* The sleep() is here to increase contention between threads */
sleep(1);
/* Push dummy conditions until an error should occur */
for(; push_count<=C_STACK_SIZE; push_count++)
ChfCondition 1, CHF_INFO ChfEnd;
/* No error? Bad! */
return (void *)EXIT_FAILURE;
}
return (void *)EXIT_SUCCESS;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test05");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat",
C_STACK_SIZE, H_STACK_SIZE, EXIT_FAILURE))
exit(st);
#ifdef _REENTRANT
/* Create */
for(i=0; i<N_THREADS; i++)
if(pthread_create(&(t[i]), NULL, task, (void *)i))
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
{
if(pthread_join(t[i], &ret))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
else if((int)ret != EXIT_SUCCESS)
exit((int)ret);
}
st = EXIT_SUCCESS;
#else
st = (int)task((void *)0);
#endif
/* Exit Chf */
ChfExit();
exit(st);
}

138
Chf/test06.c Normal file
View file

@ -0,0 +1,138 @@
/* $Id: test06.c,v 2.1 2000/05/29 13:10:55 cibrario Rel $
Chf test program.
Structured condition handling - single and multithreaded
$Log: test06.c,v $
Revision 2.1 2000/05/29 13:10:55 cibrario
*** empty log message ***
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
#define H_STACK_SIZE 10
#define C_STACK_SIZE 30
void *task(void *arg)
{
volatile int phase = 0;
ChfTry
{
phase = 1;
ChfCondition 20, CHF_SUCCESS ChfEnd;
ChfSignal();
phase = 2;
ChfCondition 20, CHF_INFO ChfEnd;
ChfSignal();
phase = 3;
ChfCondition 20, CHF_WARNING ChfEnd;
ChfSignal();
phase = 4;
ChfCondition 20, CHF_ERROR ChfEnd;
ChfSignal();
phase = 5;
ChfCondition 20, CHF_FATAL ChfEnd;
ChfSignal();
/* Should not be reached */
return (void *)EXIT_FAILURE;
}
ChfCatch
{
/* Catched an exception; check descriptor */
const ChfDescriptor *d = ChfGetTopCondition();
if(d == NULL
|| ChfGetNextDescriptor(d) != NULL
|| ChfGetModuleId(d) != CHF_MODULE_ID
|| ChfGetConditionCode(d) != 20)
return (void *)EXIT_FAILURE;
}
ChfEndTry;
/* Check that the condition stack actually is empty after catch */
ChfTry
{
volatile const ChfDescriptor *e = ChfGetTopCondition();
}
ChfCatch
{
const ChfDescriptor *d = ChfGetTopCondition();
if(d == NULL
|| ChfGetNextDescriptor(d) != NULL
|| ChfGetModuleId(d) != CHF_SET
|| ChfGetConditionCode(d) != CHF_F_BAD_STATE)
return (void *)EXIT_FAILURE;
}
ChfEndTry;
return (void *)EXIT_SUCCESS;
}
#define N_THREADS 50
int main(int argc, char *argv[])
{
int st;
int i;
void *ret;
#ifdef _REENTRANT
pthread_t t[N_THREADS];
#endif
puts("test06");
/* Initialization */
if(st = ChfMsgcatInit(argv[0], CHF_DEFAULT, "./test01.cat",
C_STACK_SIZE, H_STACK_SIZE, EXIT_FAILURE))
exit(st);
#ifdef _REENTRANT
/* Create */
for(i=0; i<N_THREADS; i++)
if(pthread_create(&(t[i]), NULL, task, (void *)i))
{
perror("pthread_create");
exit(EXIT_FAILURE);
}
/* Join */
for(i=0; i<N_THREADS; i++)
{
if(pthread_join(t[i], &ret))
{
perror("pthread_join");
exit(EXIT_FAILURE);
}
else if((int)ret != EXIT_SUCCESS)
exit((int)ret);
}
st = EXIT_SUCCESS;
#else
st = (int)task((void *)0);
#endif
/* Exit Chf */
ChfExit();
exit(st);
}

103
Chf/test07.c Normal file
View file

@ -0,0 +1,103 @@
/* $Id: test07.c,v 2.1 2000/05/29 13:57:17 cibrario Rel $
Chf test program.
Simple initialization.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
#include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
extern ChfTable message_table[];
extern size_t message_table_size;
int main(int argc, char *argv[])
{
int st;
const char *msg;
const ChfDescriptor *d, *e;
puts("test07");
/* Initialization */
if(st = ChfStaticInit(argv[0], CHF_DEFAULT,
message_table, message_table_size, 50, 10, 1))
exit(st);
/* ChfGetMessage:
message (CHF_MODULE_ID, 1) exists, (CHF_MODULE_ID, 2) does not
*/
msg = ChfGetMessage(CHF_MODULE_ID, 1, "Default_1");
if(strcmp(msg, "Set_255,Message_1")) exit(EXIT_FAILURE);
msg = ChfGetMessage(CHF_MODULE_ID, 2, "Default_2");
if(strcmp(msg, "Default_2")) exit(EXIT_FAILURE);
/* Generate a condition and check descriptor; this is line 46 */
ChfCondition 3, CHF_WARNING, 456 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 3
|| d->severity != CHF_WARNING
|| d->line_number != 46
|| strcmp(d->file_name, "test07.c")
|| strcmp(d->message, "Set_255,Arg_456,Message_3")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Generate another condition and check; this is line 60 */
ChfCondition 4, CHF_INFO, "arg" ChfEnd;
if((e = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
e->module_id != CHF_MODULE_ID
|| e->condition_code != 4
|| e->severity != CHF_INFO
|| e->line_number != 60
|| strcmp(e->file_name, "test07.c")
|| strcmp(e->message, "Set_255,Arg_arg,Message_4")
|| e->next != d
) exit(EXIT_FAILURE);
/* Discard the previous condition group and create a new one */
ChfDiscard();
/* This is line 77 */
ChfCondition 5, CHF_ERROR, 456, 789 ChfEnd;
if((d = ChfGetTopCondition()) == NULL) exit(EXIT_FAILURE);
if(
d->module_id != CHF_MODULE_ID
|| d->condition_code != 5
|| d->severity != CHF_ERROR
|| d->line_number != 77
|| strcmp(d->file_name, "test07.c")
|| strcmp(d->message, "Set_255,Arg_456-789,Message_5")
|| d->next != NULL
) exit(EXIT_FAILURE);
/* Exit Chf */
ChfExit();
exit(EXIT_SUCCESS);
}
ChfTable message_table[] =
{
{ CHF_MODULE_ID, 1, "Set_255,Message_1" },
{ CHF_MODULE_ID, 3, "Set_255,Arg_%d,Message_3" },
{ CHF_MODULE_ID, 4, "Set_255,Arg_%s,Message_4" },
{ CHF_MODULE_ID, 5, "Set_255,Arg_%d-%d,Message_5" }
};
size_t message_table_size = sizeof(message_table)/sizeof(message_table[0]);

80
INSTALL.txt Normal file
View file

@ -0,0 +1,80 @@
$Id: INSTALL.txt,v 4.1 2000/12/11 09:54:19 cibrario Rel $
Quick build/installation instructions; shell commands are preceded by '$':
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
To build saturn from the source distribution, follow these steps:
0) Create an empty directory, and unpack the source distribution archive
into it, for example:
$ mkdir build_dir
$ cd build_dir
$ gunzip < ../saturn_src_V4_1.tar.gz | tar xf - .
If you are reading this notice, you probably have already done this...
1) Generate the platform-specific Makefile:
$ xmkmf
On Solaris platforms, if gcc is your default (or only) compiler,
you may need to force its selection, using the following
command instead of xmkmf:
$ imake -DUseInstalled -DHasGcc -I/usr/openwin/lib/X11/config
2) Generate module dependencies:
$ make depend
3) Build saturn:
$ make
4) Build the documentation.
You need a working Texinfo system to do this:
$ make doc
5) Optionally, install saturn systemwide (you need root privileges
to do this):
$ make install
6) Enjoy

229
Imakefile Normal file
View file

@ -0,0 +1,229 @@
# .+
#
# .identifier : $Id: Imakefile,v 4.1 2000/12/11 09:54:19 cibrario Rel $
# .context : SATURN, Saturn CPU / HP48 emulator
# .title : $RCSfile: Imakefile,v $
# .kind : Makefile
# .author : Ivan Cibrario B.
# .site : CSTV-CNR
# .creation : *
# .keywords : *
# .description :
# Imakefile.
# .notes :
# $Log: Imakefile,v $
# Revision 4.1 2000/12/11 09:54:19 cibrario
# Public release.
#
# Revision 3.16 2000/11/21 16:37:20 cibrario
# Ultrix/IRIX support:
# - Propagate CC and CFLAGS to Chf library as fallback values
# - Added -li library for Ultrix
# - Use RM directly if needed macros are not available
#
# Revision 3.14 2000/11/13 10:24:52 cibrario
# Implemented fast load/save; improved keyboard interface emulation at
# high emulated CPU speed:
#
# - New file disk_io_obj.c
#
# Revision 3.13 2000/11/09 11:14:50 cibrario
# Revised to add file selection box GUI element, CPU halt/run
# requests and emulator's extended functions:
#
# - New files: x_func.h, x_func.c, x_func.msf
#
# Revision 3.9 2000/10/24 16:12:55 cibrario
# Added Texinfo documentation targets
#
# Revision 3.8 2000/10/23 13:18:58 cibrario
# Bug fixes:
# - saturn.cat did not contain Chf messages
# - extended 'clean' target to remove saturn.cat as well
# - CatDestination was wrong on Debian GNU/Linux
#
# Revision 3.6 2000/10/02 13:54:04 cibrario
# ROM handling utilities:
# - Added support for stand-alone build of Chf library in its subdirectory
# - Added build commands for 'pack' utility
#
# Revision 3.5 2000/10/02 09:55:10 cibrario
# Linux support:
# - openpty() is in -lutil
# - message catalog must be installed in /usr/lib/locale/C
#
# Revision 3.3 2000/09/26 15:26:07 cibrario
# Revised to implement Flash ROM write access:
# - Added new files flash49.c and flash49.msf
#
# Revision 3.2 2000/09/22 13:21:33 cibrario
# Implemented preliminary support of HP49 hw architecture:
# - added new modules hw_config.c and romram49.c to SRCS list
#
# Revision 2.5 2000/09/14 15:41:16 cibrario
# Added new files serial.c and serial.msf
#
# Revision 2.1 2000/09/08 15:39:34 cibrario
# Added automatic installation of application default file and
# message catalog; removed platform-dependent options.
#
# Revision 1.1 1998/02/19 12:03:28 cibrario
# Initial revision
#
#
# .-
#
# Stand-alone build of Chf library in its subdirectory
#
# 3.16: Propagate CC and CFLAGS to Chf library as fallback values
#
#define IHaveSubdirs
#define PassCDebugFlags X_CC="$(CC)" X_CFLAGS="$(CFLAGS)"
SUBDIRS = Chf
MakeSubdirs($(SUBDIRS))
#
# Programs built by this Imakefile
#
PROGRAMS= saturn pack
#
# Source/object files
# Each row corresponds to a group of files; each group has its own
# CHF module identifier and message catalog source file.
#
SRCS1= debug.c \
cpu.c dis.c emulator.c monitor.c \
modules.c hw_config.c romram.c romram49.c hdw.c keyb.c \
disk_io.c disk_io_obj.c \
display.c x11.c \
serial.c flash49.c x_func.c\
saturn.c
#
# Message catalog source files for the modules defined above.
#
MSFS= debug.msf \
cpu.msf \
modules.msf \
disk_io.msf \
x11.msf \
serial.msf flash49.msf x_func.msf\
saturn.msf util.msf \
Chf/chf.msf
#
# Source/object files of secondary target
#
SRCS2= pack.c
#
# Automatic generation of object file list
#
OBJS1= $(SRCS1:.c=.o)
OBJS2= $(SRCS2:.c=.o) disk_io.o debug.o
#
# Now, some extras... bring the Chf library in.
#
EXTRA_INCLUDES = -I./Chf
EXTRA_LOAD_FLAGS = -L./Chf/st_build
# 3.5: Added linux support; openpty() is in -lutil
#
#if defined(LinuxArchitecture)
EXTRA_ARCH_LIBRARIES = -lutil
#endif
# 3.16: Added Ultrix support; catopen() is in -li
#
#if defined(UltrixArchitecture)
EXTRA_TAIL_LIBRARIES = -li
#endif
EXTRA_LIBRARIES = $(EXTRA_ARCH_LIBRARIES) \
-lXm $(XTOOLLIB) $(XLIB) -lChf \
$(EXTRA_TAIL_LIBRARIES)
#
# Main Target
#
ComplexProgramTarget_1(saturn,NullParameter,NullParameter)
#
# Main Target
#
ComplexProgramTarget_2(pack,NullParameter,NullParameter)
#
# Installation of the application default file; primary target only.
#
InstallAppDefaults(Saturn)
#
# Special message catalog targets
#
saturn.cat: $(MSFS)
for msf in $? ; \
do gencat saturn.cat $$msf ; \
done
all:: saturn.cat
#
# 3.16: Use RM directly if macro is not available
#
#ifdef ImakeConfigRelease
clean::
RemoveFile(saturn.cat)
#else
clean::
$(RM) saturn.cat
#endif
#
# Determine destination of saturn.cat; for now, few architectures are
# supported.
#
#if defined(AlphaArchitecture)
#define CatDestination /usr/lib/nls/msg/C
#elif defined(SunArchitecture)
#define CatDestination /usr/lib/locale/C/LC_MESSAGES
#elif defined(LinuxArchitecture)
#define CatDestination /usr/share/locale/C/LC_MESSAGES
#endif
#if defined(CatDestination)
InstallNonExecFile(saturn.cat,CatDestination)
#else
install::
echo "*** Can't determine CatDestination; install saturn.cat manually"
#endif
#
# TexInfo Documentation
#
MAKEINFO= makeinfo
TEXI2DVI= texi2dvi
DVIPS= dvips
doc:
$(MAKEINFO) saturn.texi
$(TEXI2DVI) saturn.texi && $(DVIPS) -o saturn.ps saturn.dvi
@echo "*** Install saturn.info manually, please"
#
# 3.16: Use RM directly if macro is not available
#
#ifdef ImakeConfigRelease
clean::
RemoveFiles(*.aux *.cp *.cps *.dvi *.fn *.info *.ky *.log *.pg)
RemoveFiles(*.ps *.toc *.tp *.vr)
#else
clean::
$(RM) *.aux *.cp *.cps *.dvi *.fn *.info *.ky *.log *.pg
$(RM) *.ps *.toc *.tp *.vr
#endif

49
README.txt Normal file
View file

@ -0,0 +1,49 @@
$Id: README.txt,v 4.1 2000/12/11 09:54:19 cibrario Rel $
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
To get started with the saturn software, follow these steps:
- If you have an user-level binary distribution, read the file
BUILD_INFO.txt and check that the platform on which the
saturn software was built is compatible with yours.
- If you have a source distribution, follow the instructions
of INSTALL.txt to build the binaries and, optionally,
to install them.
- Read the documentation of the saturn software, above all chapter 2.
You must build the documentation yourself as explained in INSTALL.txt
if you have a source distribution; instead, if you have a binary
distribution, both info and PostScript files are already there.
- If you are in a real hurry and wish to emulate an HP49 as soon
as possible, run the ./quick_start shell script.

2422
Saturn.ad Normal file

File diff suppressed because it is too large Load diff

100
args.h Normal file
View file

@ -0,0 +1,100 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: args.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: args.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 19-Jan-1998
.keywords : *
.description :
This header declares a global data structure containing the emulator
invocation arguments; this data structure is initialized before startup,
either by means of argc/argv or in other ways.
.include : config.h
.notes :
$Log: args.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.15 2000/11/15 14:03:06 cibrario
GUI enhancements and assorted bug fixes:
- added .batchXfer boolean (corresponding to command-line option
-batchXfer) to struct Args
Revision 3.10 2000/10/24 16:14:25 cibrario
Added/Replaced GPL header
Revision 2.1 2000/09/08 14:45:06 cibrario
Added the following fields to 'struct Args': reset, monitor, hw.
The latter mimes the setting of the -hw command line option and
of the *hw top-level application resource; the former two have
been added to export them cleanly from the GUI modules.
* Revision 1.1 1998/02/17 11:58:37 cibrario
* Initial revision
*
.- */
/*---------------------------------------------------------------------------
Data type definitions - require config.h
---------------------------------------------------------------------------*/
struct Args
{
int reset; /* 2.1: Force emulator reset */
int monitor; /* 2.1: Call monitor() on startup */
int batchXfer; /* 3.15: Non-interactive file transfers */
char *mod_file_name;
char *cpu_file_name;
char *hdw_file_name;
char *rom_file_name;
char *ram_file_name;
char *port_1_file_name;
char *port_2_file_name;
char *hw; /* 2.1: Hardware configuration (unused) */
};
/*---------------------------------------------------------------------------
Global variables
---------------------------------------------------------------------------*/
extern struct Args args;

5
cindex.texi Normal file
View file

@ -0,0 +1,5 @@
@c $Id: cindex.texi,v 4.1 2000/12/11 09:54:19 cibrario Rel $
@node Concept Index, , GNU GENERAL PUBLIC LICENSE, Top
@unnumbered Concept Index
@printindex cp

148
clopt.texi Normal file
View file

@ -0,0 +1,148 @@
@c $Id: clopt.texi,v 4.1 2000/12/11 09:54:19 cibrario Rel $
@node Command Line Options, Customizing saturn, Using the Emulator, Top
@chapter Command Line Options
@cindex Command Line Options
The @code{saturn} program accepts the command line options listed below;
notice that recent versions of the X Toolkit allow you to abbreviate
option's names to their shortest, non-ambiguous prefix.
@table @code
@item -reset
This option instructs @code{saturn} to reset the emulated CPU,
by forcing a jump to address @code{0}, before starting execution.
It should be useful when the emulated calculator ``gets stuck'', since
it has the same effect as pressing the reset switch on the real
calculator.
@item -monitor
This option instructs @code{saturn} to enter the monitor/debugger
during startup; since this feature of @code{saturn} is pitiful,
use of this option is strongly discouraged for now.
@item -batchXfer
When this option is present on the command line, all fast file
transfers requested through the @code{sutil} library will be
made in batch mode, that is, @code{saturn} will always load and save
files in the current directory and will use the default file names
given by the calculator, without any user interaction.
@item -stateDir @var{dir_name}
This option must be followed by the name of a directory, @var{dir_name};
@code{saturn} will use this directory to load/save the calculator's
state. By specifying different state directories, you can emulate
multiple calculator models and/or multiple instances of the same
calculator, even simultaneously. However, keep in mind that
calculator's state files are @strong{not} platform-independent, so you
cannot share them among different platforms. The default value of this
option is @code{.}, that is, by default @code{saturn} places its
state files in the current directory.
@item -cpu @var{cpu_state}
This option must be followed by the name of a file, @var{cpu_state},
relative to the emulator's state directory; @code{saturn} will use
this file to load/save the calculator's emulated CPU state.
The default value of this option is @code{cpu}.
@item -mod @var{mod_state}
This option must be followed by the name of a file, @var{mod_state},
relative to the emulator's state directory; @code{saturn} will use
this file to load/save the calculator's emulated peripheral modules
state.
The default value of this option is @code{mod}.
@item -hdw @var{hdw_state}
This option must be followed by the name of a file, @var{hdw_state},
relative to the emulator's state directory; @code{saturn} will use
this file to load/save the calculator's emulated peripheral devices
state.
The default value of this option is @code{hdw}.
@item -rom @var{rom_image}
This option must be followed by the name of a file, @var{rom_image},
relative to the emulator's state directory; @code{saturn} will use
this file to load (and save, when emulating an HP49) the calculator's
ROM image.
The default value of this option is @code{rom}.
@item -ram @var{ram_image}
This option must be followed by the name of a file, @var{ram_image},
relative to the emulator's state directory; @code{saturn} will use
this file to load/save the calculator's main RAM image.
The default value of this option is @code{ram}.
@item -port1 @var{port1_image}
This option must be followed by the name of a file, @var{port1_image},
relative to the emulator's state directory; @code{saturn} will use
this file to load/save the calculator's port 1 image.
The default value of this option is @code{port1}.
This option is meaningful only when emulating an HP48GX.
@item -port2 @var{port2_image}
This option must be followed by the name of a file, @var{port2_image},
relative to the emulator's state directory; @code{saturn} will use
this file to load/save the calculator's port 2 image.
The default value of this option is @code{port2}.
This option is meaningful only when emulating an HP48GX.
@item -face @var{face_name}
This option must be followed by the name of a faceplate, @var{face_name},
defined in the application resources of @code{saturn}. The faceplate
defines the ``look'' of the emulated calculator, such as its color
and the size and position of its keys, the mapping between
calculator's keys and IN/OUT codes seen by the CPU, and keyboard
shortcuts. Each user can define its own faceplates for @code{saturn},
and use them without rebuilding the executable; for more information
see @ref{Customizing saturn}. The application resource file
distributed with @code{saturn} defines the following faceplates:
@table @code
@item hp48
Naive HP48GX faceplate
@item hp49
Naive HP49 faceplate
@item hp40
Naive HP40 faceplate
@end table
The default value of this option is @code{hp48}, corresponding
to a naive HP48GX faceplate in the default application resource
file distributed with @code{saturn}.
@item -hw @var{hw_name}
This option must be followed by the name of an hardware configuration,
@var{hw_name}, chosen among those supported by @code{saturn}.
The hardware configuration defines things like ROM/RAM sizes, bank
switching mechanism, and so on. Currently, @code{saturn} supports two
hardware configurations:
@table @code
@item hp48
HP48GX calculator
@item hp49
HP49 calculator, also suitable to emulate the HP40
@end table
Even if @code{saturn} has a modular structure, unfortunately
general users cannot add custom hardware architectures to it
without rebuilding the executable. Moreover, since I am a lazy guy,
the steps required to do this are not documented at all.
@end table
In addition, @code{saturn} understands all standard X Toolkit command-line
options, and does its best to honor them. Among such options, the
most useful ones are:
@table @code
@item -display @var{display_name}
This option must be followed by a valid X display name, and instructs
the emulator to use that display to show its windows. If this option
is not present on the command line the default display, that is,
the display named by the @code{DISPLAY} environment variable, is used.
@item -xrm @var{resource_spec}
This option must be followed by a valid X resource specifier, and
allows you to add/override one or more @code{saturn}'s X resources
``on-the-fly''.
@end table

267
config.h Normal file
View file

@ -0,0 +1,267 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: config.h,v 4.1.1.1 2002/11/11 16:13:29 cibrario Exp $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: config.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 28-Jan-1998
.keywords : *
.description :
This file configures the Saturn / HP48 emulator.
.include : *
.notes :
$Log: config.h,v $
Revision 4.1.1.1 2002/11/11 16:13:29 cibrario
Small screen support; preliminary
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.16 2000/11/21 16:38:23 cibrario
Ultrix/IRIX support:
- Include config_x.h (automatic exceptions to user configuration)
Revision 3.14 2000/11/13 10:23:43 cibrario
Implemented fast load/save; improved keyboard interface emulation at
high emulated CPU speed:
- New configuration option: CPU_SLOW_IN (enabled by default)
Revision 3.13 2000/11/09 11:21:18 cibrario
Revised to add file selection box GUI element, CPU halt/run
requests and emulator's extended functions:
- Updated documentation of CPU_SPIN_SHUTDN and REAL_CPU_SPEED
- Defined new Chf module identifier: X_FUNC_CHF_MODULE_ID
Revision 3.10 2000/10/24 16:14:25 cibrario
Added/Replaced GPL header
Revision 3.6 2000/10/02 13:52:32 cibrario
ROM handling utilities:
- Added new Chf module identifier: UTIL_CHF_MODULE_ID
Revision 3.5 2000/10/02 09:40:35 cibrario
Linux support:
- documented new compile-time option: REAL_CPU_SPEED
Revision 3.3 2000/09/26 15:24:20 cibrario
Revised to implement Flash ROM write access:
- Added new Chf module identifier FLASH_CHF_MODULE_ID
* Revision 3.2 2000/09/22 13:34:43 cibrario
* Implemented preliminary support of HP49 hw architecture:
* - Re-enabled DEBUG
* - Documented new HP49_SUPPORT option, and enabled it by default
*
* Revision 3.1 2000/09/20 14:15:42 cibrario
* Revised to implement passive CPU shutdown:
* - disabled DEBUG option by default
* - enhanced documentation of CPU_SPIN_SHUTDN; this option is now
* disabled by default.
*
* Revision 2.6 2000/09/15 09:28:48 cibrario
* Enhanced documentation of serial emulation options; added
* template of SERIAL_FORCE_STREAMSPTY definition (commented out
* by default)
*
* Revision 2.5 2000/09/14 15:40:24 cibrario
* - Added description and default values of configuration options
* SERIAL_FORCE_OPENPTY and SERIAL_FORCE_STREAMSPTY.
* - Added new Chf module identifier SERIAL_CHF_MODULE_ID, used by the
* serial port emulation modules.
*
* Revision 2.4 2000/09/12 15:50:40 cibrario
* Added description and default definition of N_PORT_2_BANK
*
* Revision 2.1 2000/09/08 15:43:46 cibrario
* Disabled DEBUG option by default; documented new GUI option
* FORCE_NONMODAL.
*
* Revision 1.1 1998/02/17 14:57:15 cibrario
* Initial revision
*
.- */
/* CHF_EXTENDED_INFO:
Define this symbol if extended information is desired during condition
handling; this is usually useful only for debugging purposes.
*/
/* #define CHF_EXTENDED_INFO */
/* DEBUG:
Define this symbol to include the debugging code for all source modules
in the executable image.
At run-time, the debug level can be set using the function SetDebugLevel();
the initial debug level is set to the value of the symbol DEBUG_LEVEL,
if it is defined, otherwise it is set to zero.
*/
/* #define DEBUG */
/* DEBUG_LEVEL:
When this symbol is defined and the debugging code has been included
in the executable image (DEBUG symbol set), the initial debug level
is set to its value.
The value must be the bitwise OR of zero or more of the symbols
DEBUG_C_<> defined in debug.h; each of them corresponds to a class
of debugging conditions that can be individually enabled or disabled.
*/
#define DEBUG_LEVEL DEBUG_C_REVISION
/* CPU_SPIN_SHUTDN
If this symbol is defined, the cpu module implements the SHUTDN
instruction as a spin loop; when the instruction is encountered in the
run stream, the program counter is reset to the starting nibble of its
opcode.
If this symbol is not defined, the cpu module implements the SHUTDN
instruction signaling a Chf condition; the main emulator loop
condition handler works in concert with the GUI module to implement
an idle loop when this condition is handled.
This option MUST be defined if the revision of either the cpu emulation
module (cpu.c) or the GUI module (x11.c) is less than 3.1.
Starting from release 3.1, this option is disabled by default, to
waste as little (real) cpu time as possible; however, expect a
loss of timing accuracy.
Notice also that when this function is defined the CpuHaltRequest()
and CpuRunRequest() functions are disabled; as a consequence, all
interactive emulator's extended functions will be disabled as well.
*/
/* #define CPU_SPIN_SHUTDN */
/* 2.1: FORCE_NONMODAL
If this symbol is defined, nonmodal navigation is forced in the
OSF/Motif GUI, by setting navigationType to XmNONE and traversalOn
to False at the source code level.
*/
/* #define FORCE_NONMODAL */
/* 2.4: N_PORT_2_BANK
This symbol is used to dimension the HP48GX Port_2: it denotes the
number of 128 Kbyte banks the port must have and must be a power of 2
between 1 and 32, inclusive. When undefined, Port_2 is not emulated at all.
The default value is 8, that is, Port_2 is emulated and its size is 1Mbyte.
*/
#define N_PORT_2_BANK 8
/* 2.5: SERIAL_FORCE_OPENPTY, SERIAL_FORCE_STREAMSPTY
Optionally define exactly one of these symbols to force the use of a
particular pty implementation; if no symbols are defined, the
serial port emulation modules will do their best to automatically
determine the most appropriate implementation for the platform at hand.
*/
/* #define SERIAL_FORCE_OPENPTY */
/* #define SERIAL_FORCE_STREAMSPTY */
/* 3.2: HP49_SUPPORT
Define this symbol to enable HP49-specific support code in the
emulator; it does not harm if this symbol is defined when emulating
a HP48, too, since all changed should be backward-compatible.
*/
#define HP49_SUPPORT
/* 3.13: REAL_CPU_SPEED
Define this symbol (recommended) to force the emulated CPU to run
no faster than a software-controlled limit; by default, the limit
is close to the real CPU speed.
*/
#define REAL_CPU_SPEED
/* 3.14: CPU_SLOW_IN
Define this symbol (recommended) to slow down the A=IN and C=IN
instructions depending on the current emulated CPU speed.
The value of the macro determines the gain of the relation between
CPU speed and slow down ratio.
*/
#define CPU_SLOW_IN 16
/* 4.1.1.1: LCD_MAG
This symbol represents the magnification ratio of the emulated LCD pixels
when drawn on the emulated display; supported values are 1 and 2; 2 is the
default. Currently, the value cannot be set at runtime for performance
reasons.
*/
#define LCD_MAG 1
/* 4.1.1.1: When defined, this symbol represents the threshold of the long
key pression. When the mouse button is kept pressed on a calculator's key
for more than LONG_PRESS_THR milliseconds, the key stays pressed after
release.
*/
#define LONG_PRESS_THR 1000
/* Chf Module Identifiers:
Each main module of the emulator has its own Chf Module Identifier; the
values defined here must match those actually used in the message catalogs.
*/
#define MAIN_CHF_MODULE_ID 10
#define CPU_CHF_MODULE_ID 11
#define MOD_CHF_MODULE_ID 12
#define DISK_IO_CHF_MODULE_ID 13
#define X11_CHF_MODULE_ID 14
#define SERIAL_CHF_MODULE_ID 15 /* 2.5 */
#define FLASH_CHF_MODULE_ID 16 /* 3.3 */
#define UTIL_CHF_MODULE_ID 17 /* 3.6 */
#define X_FUNC_CHF_MODULE_ID 18 /* 3.13 */
#define DEBUG_CHF_MODULE_ID 30
/* 3.16: Include automatic exceptions to user configuration */
#include "config_x.h"

65
config_x.h Normal file
View file

@ -0,0 +1,65 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: config_x.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HPxx emulator
.title : $RCSfile: config_x.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 20-Nov-2000
.keywords : *
.description :
This file is included by config.h and automatically disables any
user configuration option known to be unsupported on the current platform.
.include : *
.notes :
$Log: config_x.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.16 2000/11/21 16:38:44 cibrario
*** empty log message ***
.- */
/* REAL_CPU_SPEED is not supported on ultrix, because there is no usleep() */
#ifdef ultrix
#undef REAL_CPU_SPEED
#endif

3185
cpu.c Normal file

File diff suppressed because it is too large Load diff

352
cpu.h Normal file
View file

@ -0,0 +1,352 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: cpu.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: cpu.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : *
.keywords : *
.description :
Main header for the Saturn CPU emulation modules. References:
SASM.DOC by HP (HORN disk 4)
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
x48 source code by Eddie C. Dost (ecd@dressler.de)
.include : config.h machdep.h
.notes :
$Log: cpu.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.14 2000/11/13 11:31:16 cibrario
Implemented fast load/save; improved keyboard interface emulation at
high emulated CPU speed:
- Revision number bump with no changes
Revision 3.13 2000/11/09 11:27:14 cibrario
Revised to add file selection box GUI element, CPU halt/run
requests and emulator's extended functions:
- Added new fields:
struct CpuStatus.halt (number of pending halt requests)
struct CpuStatus.inner_loop_max (upper limit of inner_loop)
- New condition codes: CPU_I_HALT, CPU_I_RUN, CPU_E_NO_HALT
- New prototypes: CpuHaltRequest(), CpuRunRequest(), CpuHaltAllowed()
Revision 3.10 2000/10/24 16:14:31 cibrario
Added/Replaced GPL header
Revision 3.8 2000/10/23 13:13:08 cibrario
Bug fix:
Adjusted INNER_LOOP_MAX and INNER_LOOP_MED to get closer to
real CPU speed.
Revision 3.5 2000/10/02 09:43:37 cibrario
Linux support:
- Added definition of INNER_LOOP_MAX; it is used to give an upper limit
to the emulated CPU speed on fast machines, when REAL_CPU_SPEED is
defined.
Revision 3.1 2000/09/20 13:42:30 cibrario
Revised to implement passive CPU shutdown:
- new status codes CPU_I_TIMER_ST, CPU_I_TIMER_EXP, CPU_I_IDLE_X_LOOP,
CPU_I_ELAPSED
* Revision 2.4 2000/09/12 15:19:47 cibrario
* Added definition of XAddress (extended address) data type; it is
* required to implement emulation of Port 1 and 2.
*
* Revision 2.1 2000/09/08 14:48:52 cibrario
* - Declared prototypes of new functions EmulatorInit() and EmulatorExit()
* - Defined new 'enum ExitOption' data type, used by EmulatorExit()
*
* Revision 1.1 1998/02/18 11:50:43 cibrario
* Initial revision
*
.- */
/*---------------------------------------------------------------------------
Macro/Data type definitions - require machdep.h
N_SCRATCH_REGISTER_ALL, used during scratch register space allocation
is larger than necessary to avoid additional checks on the validity of
the R register index fields during emulation
---------------------------------------------------------------------------*/
/* General */
#define NIBBLE_PER_REGISTER 16
#define N_WORKING_REGISTER 4
#define N_SCRATCH_REGISTER 5
#define N_SCRATCH_REGISTER_ALL 8
#define N_DATA_POINTER_REGISTER 2
#define RETURN_STACK_SIZE 8
#define NIBBLE_VALUES 16
#define INT_HANDLER_PC ((Address)0x0000F)
#define DISASSEMBLE_OB_SIZE 128
#define DUMP_CPU_STATUS_OB_SIZE 512
#define CPU_RCS_INFO "$Revision: 4.1 $ $State: Rel $"
/* Instruction opcode access macros:
GetFS(f) returns the short field-selector value from the
given nibble (bits 2..0)
GetImmFS(f) returns the immediate-field-selector flag from the
given nibble (bit 3)
=0: regular field selector
!=0: immediate field selector
GetOC_1(o) returns the short operation code from the given
nibble (bits 3..2 >>2)
GetOC_2(f, o) returns the long operation code from the given
nibbles (f bit 3, o bits 3..2)
GetOC_3b(o) returns the long operation code from the given
nibble (bits 2..0)
GetRP(o) returns the register-pair identifier from the given
nibble (bits 1..0)
GetRn(r) returns the R register index from the given nibble
(bits 2..0)
GetAC(r) returns the A/C register flag from the given nibble
(bit 3)
=0: register A
!=0: register C
GetAS(r) returns the add/subtract flag from the given nibble
(bit 3)
=0: add
!=0: subtract
*/
#define GetFS(f) ((f) & 0x7)
#define GetImmFS(o) ((o) & 0x8)
#define GetOC_1(o) (((o) & 0xC)>>2)
#define GetOC_2(f, o) ((((f) & 0x8)>>1) | (((o) & 0xC)>>2))
#define GetOC_3b(o) ((o) & 0x7)
#define GetRP(o) ((o) & 0x3)
#define GetRn(r) ((r) & 0x7)
#define GetAC(r) ((r) & 0x8)
#define GetAS(r) ((r) & 0x8)
/* Field selector codes */
#define FS_P 0
#define FS_WP 1
#define FS_XS 2
#define FS_X 3
#define FS_S 4
#define FS_M 5
#define FS_B 6
#define FS_W 7
#define FS_A 15
#define N_FS 16 /* Total # of FS codes */
/* Register pair codes */
#define RP_AB 0
#define RP_BC 1
#define RP_CA 2
#define RP_DC 3
#define N_RP 4 /* Total # of RP codes */
/* Masks */
#define NIBBLE_MASK ((Nibble)0xF)
#define ADDRESS_MASK ((Address)0xFFFFF)
#define CLRST_MASK ((ProgramStatusRegister)0xF000)
#define D_S_MASK ((Address)0xF0000)
#define RETURN_SP_MASK 0x7
typedef int1 Bit;
typedef int4 Nibble;
typedef int20 Address;
typedef int12 OutputRegister;
typedef int16 InputRegister;
typedef int16 ProgramStatusRegister;
typedef Nibble DataRegister[NIBBLE_PER_REGISTER];
/* The XAddress data type holds extended addresses used to access Port 2 */
typedef int32 XAddress;
enum IntRequest
{
INT_REQUEST_NONE,
INT_REQUEST_IRQ,
INT_REQUEST_NMI
};
struct CpuStatus
{
DataRegister work[N_WORKING_REGISTER];
#define A work[0]
#define B work[1]
#define C work[2]
#define D work[3]
DataRegister R[N_SCRATCH_REGISTER_ALL];
#define R0 R[0]
#define R1 R[1]
#define R2 R[2]
#define R3 R[3]
#define R4 R[4]
Address DAT[N_DATA_POINTER_REGISTER];
#define D0 DAT[0]
#define D1 DAT[1]
Nibble P;
Address PC;
InputRegister IN;
OutputRegister OUT;
ProgramStatusRegister ST;
Nibble HST;
#define HST_MP_MASK 0x08
#define HST_SR_MASK 0x04
#define HST_SB_MASK 0x02
#define HST_XM_MASK 0x01
Address return_stack[RETURN_STACK_SIZE];
int return_sp;
int fs_idx_lo[N_FS];
int fs_idx_hi[N_FS];
int hexmode; /* DEC/HEX mode, 1=HEX */
int carry; /* Carry bit 1=set */
int shutdn; /* SHUTDN flag, 1=executed */
int halt; /* 3.13: # of pending Halt */
int int_enable; /* Int. enable, 1=enabled */
int int_service; /* Int. service, 1=service */
enum IntRequest int_pending; /* Pending interrupt request */
/* 3.13: inner_loop_max gives the upper limit of the CPU speed if the
compile-time option REAL_CPU_SPEED is defined. When the CPU is reset
it has the default value INNER_LOOP_MAX, that should be close to the
real cpu speed (~4MHz).
*/
int inner_loop; /* Inner loop multiplier */
int inner_loop_max; /* Max value of inner_loop */
#define INNER_LOOP_MAX 26
#define INNER_LOOP_MED 13
#define INNER_LOOP_MIN 2
#ifdef CPU_SPIN_LOOP
int reset_req; /* Reset req. after shutdn */
#endif
};
enum ExitOption /* 2.1: EmulatorExit() option */
{
IMMEDIATE_EXIT,
SAVE_AND_EXIT
};
/*---------------------------------------------------------------------------
Global variables
---------------------------------------------------------------------------*/
extern struct CpuStatus cpu_status;
/*---------------------------------------------------------------------------
Chf condition codes
---------------------------------------------------------------------------*/
#define CPU_I_CALLED 101 /* Function %s called */
#define CPU_I_EXECUTING 102 /* Executing @PC %X */
#define CPU_I_SHUTDN 103 /* Shutdown */
#define CPU_I_WAKE 104 /* Wake */
#define CPU_I_INT 105 /* %s request accepted */
#define CPU_I_INT_PENDING 106 /* %s request pending */
#define CPU_I_RTI_LOOP 107 /* RTI loop to service %s */
#define CPU_I_RTI_END 108 /* RTI returning */
#define CPU_I_INTON 109 /* INTON servicing %s */
#define CPU_I_REVISION 110 /* CPU emulation revision: %s */
#define CPU_I_TIMER1_EX 111 /* Timer 1 expired; ctrl=%x */
#define CPU_I_TIMER2_EX 112 /* Timer 1 expired; ctrl=%x */
#define CPU_I_EMULATOR_INT 113 /* Emulator interrupt req. detected */
#define CPU_I_TIMER_ST 114 /* 3.1: Timer %s st: ctrl %x, val %x */
#define CPU_I_TIMER_EXP 115 /* 3.1: Timer %s expiration %d ms */
#define CPU_I_IDLE_X_LOOP 116 /* 3.1: Start idle loop, t/out %d ms */
#define CPU_I_ELAPSED 117 /* 3.1: Spent %d us in idle loop */
#define CPU_I_HALT 118 /* 3.13: CPU halted */
#define CPU_I_RUN 119 /* 3.13: CPU running */
#define CPU_W_RESETTING 201 /* Resetting CPU */
#define CPU_W_BAD_MONITOR_CMD 202 /* Bad monitor command: %s */
#define CPU_E_BAD_OPCODE 301 /* Bad opc. pc=%x, value=%x */
#define CPU_E_SAVE 302 /* Can't save CPU status */
#define CPU_E_NO_HALT 303 /* 3.13: Halt/Run not allowed */
#define CPU_F_INTERR 401 /* Internal error %s */
#define CPU_F_BAD_SHUTDN 402 /* Unexpected CPU shutdown */
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
void CpuInit(void);
void CpuReset(void);
void CpuSave(void);
void OneStep(void);
void CpuIntRequest(enum IntRequest ireq);
void CpuWake(void);
void Emulator(void);
void EmulatorIntRequest(void);
void EmulatorInit(void); /* 2.1 */
void EmulatorExit(enum ExitOption opt); /* 2.1 */
int CpuHaltRequest(void); /* 3.13 */
int CpuRunRequest(void); /* 3.13 */
int CpuHaltAllowed(void); /* 3.13 */
Address Disassemble(Address pc, char ob[DISASSEMBLE_OB_SIZE]);
void DumpCpuStatus(char ob[DUMP_CPU_STATUS_OB_SIZE]);

64
cpu.msf Normal file
View file

@ -0,0 +1,64 @@
$ .+
$ .identifier : $Id: cpu.msf,v 4.1 2000/12/11 09:54:19 cibrario Rel $
$ .context : SATURN, Saturn CPU / HP48 emulator
$ .title : $RCSfile: cpu.msf,v $
$ .kind : Message catalog source
$ .author : Ivan Cibrario B.
$ .site : CSTV-CNR
$ .creation : 13-Feb-1998
$ .keywords : *
$ .description :
$ Message catalog source file for the CPU emulation modules.
$ .notes :
$ . $Log: cpu.msf,v $
$ . Revision 4.1 2000/12/11 09:54:19 cibrario
$ . Public release.
$ .
$ . Revision 3.13 2000/11/09 11:27:48 cibrario
$ . Revised to add file selection box GUI element, CPU halt/run
$ . requests and emulator's extended functions:
$ .
$ . - New messages: 118, 119, 303
$ .
$ . Revision 3.8 2000/10/19 14:56:52 cibrario
$ . Bug fix:
$ . Removed lines with empty directives
$ .
$ Revision 3.1 2000/09/20 13:44:30 cibrario
$ Revised to implement passive CPU shutdown:
$ - new messages 114, 115, 116, 117
$ .
$ Revision 1.1 1998/02/18 11:50:36 cibrario
$ Initial revision
$ .-
$set 1
11 Cpu
$set 11
101 Function [%s] called
102 Executing @ PC[%05X]
103 CPU shutdown executed
104 CPU wake-up executed
105 %s request accepted
106 %s request pending
107 RTI loop to service %s
108 RTI returning
109 INTON servicing %s
110 CPU emulator [%s]
111 Timer1 expired CTRL[%01X]
112 Timer2 expired CTRL[%01X]
113 Emulator interrupt request detected
114 Timer[%s] Ctrl[%01X] Val[%08X]
115 Timer[%s] expires in [%d]d ms
116 Starting idle loop, timeout [%d]d ms
117 Spooling up after [%d]d us in idle loop
118 CPU halted by CpuHaltRequest()
119 CPU awoken by CpuRunRequest()
201 Can't restore CPU status from disk; resetting CPU
202 Monitor command syntax error [%s]
301 Bad opcode @ PC[%05X], N[%01X]
302 Can't save CPU status to disk
303 Halt/Run requests not allowed; #undef CPU_SPIN_SHUTDN
401 Internal error [%s]
402 Unexpected CPU shutdown

393
custom.texi Normal file
View file

@ -0,0 +1,393 @@
@c $Id: custom.texi,v 4.1 2000/12/11 09:54:19 cibrario Rel $
@node Customizing saturn, The sutil Library, Command Line Options, Top
@chapter Customizing saturn
@cindex Customizing saturn
The @code{saturn} program uses OSF/Motif widgets to make up its
user interface, and supports the standard X application
resource mechanism for customization; in addition, it is fully
internationalized and uses a message catalog to retrieve almost
all error and informational messages the user will ever see.
Therefore, you can modify the ``look and feel'' of @code{saturn}
to fit your preferences to a great extent, without touching
the source code and/or rebuilding the executable.
This chapter deals with advanced customization, that is, X resources,
message catalog, and so on, and does not discuss the command-line
options of @code{saturn}; see @ref{Command Line Options}, for more
information about command-line options.
@menu
* Widget Tree::
* Custom Resources::
* Application Actions::
* Message Catalog::
* Environment Variables::
* Customizing the Translation Table::
* Customizing the Font Size::
* Configuration Options::
@end menu
@node Widget Tree, Custom Resources, Customizing saturn, Customizing saturn
@section Widget Tree
@cindex Widget Tree
This is @code{saturn}'s widget tree; all widgets are standard Motif
widgets. See the Motif documentation for more information about
standard widget's resources.
@table @code
@item main (XmMainWindow)
This is the emulator's main window, and is a child of the main
application shell.
@item *fsb (XmFileSelectionBox)
This is the file selection box that pops up when a fast load/save
operation is started. Notice the star; it is there because this
widget is wrapped in a dialog.
@item *error (XmMessageBox)
This is the message box that pops up when @code{saturn} wants to tell
something to the user, usually when an error occurs. Notice the star; it
is there because this widget is wrapped in a dialog.
@item main.@var{faceplate} (XmRowColumn)
This container contains all widgets of the calculator's faceplate.
The name of this widget, @var{faceplate}, depends on the value
of the custom resource @code{.face}; this way you can define
a different set of resources for each faceplate.
@item main.@var{faceplate}.kbd (XmForm)
This form contains all calculator's keys.
@item main.@var{faceplate}.kbd.@var{n} (XmForm)
Another @code{XmForm}, containing all widgets pertaining to calculator's
key number @var{n}.
@item main.@var{faceplate}.kbd.@var{n}.ul (XmLabel)
@itemx main.@var{faceplate}.kbd.@var{n}.ur (XmLabel)
@itemx main.@var{faceplate}.kbd.@var{n}.ll (XmLabel)
@itemx main.@var{faceplate}.kbd.@var{n}.lr (XmLabel)
These widgets contain, respectively, the upper-left, upper-right,
lower-left, and lower-right label of calculator's key number @var{n}.
@item main.@var{faceplate}.kbd.@var{n}.btn (XmToggleButton)
This widget represents calculator's key number @var{n}.
@item main.@var{faceplate}.frame (XmFrame)
This widget encloses the LCD display area.
@item main.@var{faceplate}.frame.lcd (XmDrawingArea)
This widget is the LCD display area of the emulated calculator.
@item main.@var{faceplate}.msg (XmTextField)
This text field is used by the emulator to display its most important
messages; for example, it is used to display the name of the
emulator's pseudo-terminal.
@end table
In the list above:
@table @var
@item faceplate
is the name of the active calculator's faceplate selected by the
@code{.face} custom resource.
@item n
is the ASCII decimal representation of a non-negative integer number,
that identifies a calculator's key uniquely; its value goes from
@code{0} to the value of the @var{faceplate}.@code{nKeys} resource minus
one, inclusive.
@end table
@node Custom Resources, Application Actions, Widget Tree, Customizing saturn
@section Custom Resources
@cindex Custom Resources
In addition to standard Motif resources, @code{saturn} has the
following custom resources:
@table @code
@item main.@var{faceplate}.nKeys
This resource must translate into an integer, representing the number of
keys that faceplate @var{faceplate} has.
@item main.@var{faceplate}.kbd.@var{n}.btn.inOut
This resource associates calculator's key number @var{n} with a
combination of IN/OUT codes seen by the emulated CPU. It is a
string, and can be either:
@table @code
@item @var{o}/@var{i}
When pressed, the key activates the bit(s) of the IN register specified
by the @var{i} bit @strong{mask}, when bit @strong{number} @var{o} is
set in the OUT register. Both @var{i} and @var{o} are hexadecimal
constants. For example, on the HP49 the calculator's function key
@code{F1} sets the IN bit mask @code{01} when OUT bit number @code{5} is set;
accordingly, the IN/OUT mapping of this key is @code{5/01}.
@item *
This special value uniquely identifies the ON/Cancel key.
@end table
@item *compoundString
This custom resource can be set for @code{XmLabel} and
@code{XmToggleButton} widgets only and, when set, overrides the standard
resource @code{labelString}. Its value is a string with the
following syntax:
@example
@var{compoundString}: ([# @var{fontlist_tag}] @var{string})*
@end example
Here, @var{string} is a sequence of ordinary characters,
excluding @code{#}, and @var{fontlist_tag} can be:
@table @code
@item #
Put a single @code{#} character in current compound string segment.
@item @var{space}
Create a new compound string segment using @code{XmFONTLIST_DEFAULT_TAG}
as tag.
@item @var{tag}
Create a new segment using @var{tag} as tag; @var{tag} can be
any single character, except @code{#} and @var{space}.
@end table
Each segment is limited to @code{MAX_CS_SEGMENT_LEN} characters; longer
segments are silently truncated.
The resource is scanned from left to right according to the syntax
described above. The result is a compound string (@code{XmString})
that becomes the @code{labelString} resource of the target widget.
The original value of the @code{labelString} resource is discarded
when @code{compoundString} is defined. This resource allows you
to have more than one font in button labels.
@end table
In the list above:
@table @var
@item faceplate
is the name of the calculator's faceplate selected by the
@code{.face} custom resource.
@item n
is the ASCII decimal representation of a non-negative integer number
that uniquely identifies a calculator's key; its value goes from
@code{0} to the value of the @var{faceplate}.@code{nKeys} resource minus
one, inclusive.
@end table
Notice also that all command-line options are mapped into custom
top-level application resources, too; in this case, the name of the
resource is the same as the name of the option. For example,
the @code{-face} command-line option is mapped to the custom
resource @code{.face}.
@node Application Actions, Message Catalog, Custom Resources, Customizing saturn
@section Application Actions
@cindex Application Actions
The emulator installs the application actions listed below:
@table @code
@item kbdKeyPress
@itemx kbdKeyRelease
Both actions accept one string as argument; the string represents an
IN/OUT mapping with the same syntax already described for the
@code{inOut} custom resource. These functions command the emulation of
a key press and key release event, respectively.
@end table
These actions are useful to define keyboard shortcuts. For example, on
the HP49 the calculator's function key @code{F1} sets the IN bit mask
@code{01} when OUT bit number @code{5} is set; accordingly, the IN/OUT
mapping of this key is @code{5/01}.
If you want to define the X keysym @code{F1} to act as a shortcut for
this calculator's key, simply add the following two lines to the
@code{translations} resource of your faceplate:
@example
...
<KeyDown>F1: kbdKeyPress(5/01) \n\
<KeyUp>F1: kbdKeyRelease(5/01) \n\
...
@end example
@node Message Catalog, Environment Variables, Application Actions, Customizing saturn
@section Message Catalog
@cindex Message Catalog
The @code{saturn} emulator opens the message catalog @code{saturn.cat}
during startup, and retrieves all its messages from there. Internally,
@code{saturn} uses a pair of integers to uniquely identify a message.
By default, that is, when the @code{NLSPATH} environment variable is not
set, @code{saturn} first attempts to locate the message catalog in the
system's default location of such files; if this first attempt fails,
@code{saturn} prints a warning and generates an alternate catalog name
using the directory name found in @code{argv[0]}; if even this second
attempt fails, @code{saturn} tries again using the @code{C} locale
instead of the current one. If all attempts fail, @code{saturn}
terminated.
The @code{.msf} files found in the source distribution of @code{saturn}
list all message codes and translate them into human-readable english
messages; they can be used as a starting point to prepare message
catalogs for additional languages. See the documentation of
@code{gencat}, for more information about how to process them to
generate a @code{.cat} file.
@node Environment Variables, Customizing the Translation Table, Message Catalog, Customizing saturn
@section Environment Variables
@cindex Environment Variables
The @code{saturn} emulator looks at the following environment variables:
@table @code
@item NLSPATH
@itemx LC_ALL
@itemx LC_MESSAGES
@itemx LANG
These environment variables are used to locate the @code{saturn}'s
message catalog, and to specialize the load paths of application
resources; see the documentation of @code{catopen()} and
@code{XtResolvePathname()}, for more information.
@item DISPLAY
This variable contains the default X display name used by @code{saturn}.
@item XENVIRONMENT
This variable is used to locate the per-host user environment
resources; see the documentation of @code{XtDisplayInitialize()}, for
more information.
@item XUSERFILESEARCHPATH
@itemx XAPPLRESDIR
These variables control the loading process of the user's application
resource file; see the documentation of @code{XtDisplayInitialize()}, for
more information.
@item XFILESEARCHPATH
This variable controls the loading process of the application class
resource file; see the documentation of @code{XtDisplayInitialize()}, for
more information.
@end table
@node Customizing the Translation Table, Customizing the Font Size, Environment Variables, Customizing saturn
@section Customizing the Translation Table
@cindex Customizing the Translation Table
As said before, all widgets in a given faceplate have their own
translation table; this table is useful to define keyboard
shortcuts. The default application resource file distributed
with the emulator, @file{Saturn.ad}, already contains a
predefined set of shortcuts; to customize it, proceed
as follows:
@itemize @bullet
@item
Locate the translation table of the faceplate you are interested in.
For example, the predefined HP49's faceplate name is @code{hp49}; the X
resource specifier of its base translation table is:
@example
*hp49*baseTranslations
@end example
@item
This resource has two lines of text for each key on the real keyboard
you want to map on the emulated keyboard; for example, these lines map
the @code{0} keypad key to the @code{0} key of the calculator:
@example
<KeyDown>KP_0: kbdKeyPress(3/01) \n\
<KeyUp>KP_0: kbdKeyRelease(3/01) \n\
@end example
@item
Here, @code{KP_0} is the name of the X keysym (representing a keyboard
key or a combination of keys) that is currently mapped to the @code{0}
key (@code{3/01} are the OUT/IN bit masks of the @code{0} key on the
calculator, reflecting its wiring on the calculator's keyboard). To
change the mapping to another key, simply replace the old X keysym name
with the new one. For example, if you want to remap the @code{F8} key
to the @code{0} key, update the lines above as follows:
@example
<KeyDown>F8: kbdKeyPress(3/01) \n\
<KeyUp>F8: kbdKeyRelease(3/01) \n\
@end example
If you want to keep the existing mapping, too, duplicate the existing
lines and change the X keysym on the duplicate only.
@item
To get the keysym name of a given key you can use, for example, the
@code{xev} utility: when you start it, it opens a small window on your
screen and starts dumping on stdout all X events that window receives.
Give the focus to the @code{xev} window, press the key you are
interested in and look at its output; you should see something like:
@example
KeyPress event, serial 22, synthetic NO, window 0x4800001,
root 0x26, subw 0x0, time 18446744071995733347, (77,-9),
root:(123,37),
state 0x1, keycode 34 (keysym 0x7b, braceleft), same_screen YES,
XLookupString gives 1 characters: "@{"
@end example
Here, I pressed the @code{@{} key, and @code{xev} is telling me that its
keysym name is @code{braceleft}. Use that name if you want to put the
@code{@{} key in translations.
@item
Be careful with continuation characters: each line of the translation
table resource except the last one must end with @code{\n\}
@item
Keep in mind that this is a simple example; actually, since
@code{saturn} leverages the standard X Toolkit translation table parser
and translator, it accepts the @strong{full} translation table syntax
described in MIT documents, that is much more complex and powerful than
this.
@end itemize
@node Customizing the Font Size, Configuration Options, Customizing the Translation Table, Customizing saturn
@section Customizing the Font Size
@cindex Customizing the Font Size
The simplest way to change the size of the @code{saturn}'s main window
is to change the size of the fonts it uses. To do this, locate the
@code{fontList} resources of the faceplate you want to modify in your
application resource file. For example, the default application
resource file sets the following resources for the @code{hp49}
faceplate:
@example
*hp49.kbd*fontList: *helvetica-*-r-*-*-12-*,*symbol-*-*-*-*-12-*=S
*hp49.kbd*btn.fontList: *helvetica-*-r-*-*-14-*,*symbol-*-*-*-*-14-*=S
@end example
Fonts are selected with their standard XLFD font designators;
in the above lines, @code{12} and @code{14} are the @code{pxlsz} specifiers.
Make them smaller to reduce the font size; make them bigger to
enlarge the font size. For example:
@example
*hp49.kbd*fontList: *helvetica-*-r-*-*-8-*,*symbol-*-*-*-*-8-*=S
*hp49.kbd*btn.fontList: *helvetica-*-r-*-*-10-*,*symbol-*-*-*-*-10-*=S
@end example
reduces the window size to about 400x700 pixels on my system.
If this is not enough, you can define a brand new keyboard layout;
again, no need to touch the source code, only resources must be
updated. Hint: for each key, its @code{topPosition},
@code{bottomPosition}, @code{leftPosition} and @code{rightPosition}
resources determine where the key is located on the keyboard faceplate.
@node Configuration Options, , Customizing the Font Size, Customizing saturn
@section Configuration Options
@cindex Configuration Options
In addition to the run-time customization methods mentioned above,
@code{saturn} has build-time configuration options, too. See the
documentation embedded in the source file @code{config.h}, for more
information. Of course, you can change these options only if you build
@code{saturn} yourself from the source distribution.

127
debug.c Normal file
View file

@ -0,0 +1,127 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: debug.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: debug.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 28-Jan-1998
.keywords : *
.description :
Debugging support.
.include : debug.h
.notes :
$Log: debug.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:32 cibrario
Added/Replaced GPL header
Revision 1.1 1998/02/17 11:42:30 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: debug.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "debug.h"
#define CHF_MODULE_ID DEBUG_CHF_MODULE_ID
#include <Chf.h>
/*---------------------------------------------------------------------------
Static/Global variables
---------------------------------------------------------------------------*/
#ifdef DEBUG
#ifdef DEBUG_LEVEL
int debug_level = DEBUG_LEVEL;
#else
int debug_level = 0;
#endif
#endif
/*---------------------------------------------------------------------------
Public functions
---------------------------------------------------------------------------*/
/* .+
.title : SetDebugLevel
.kind : C function
.creation : 28-Jan-1998
.description :
If runtime debug support is enabled (symbol DEBUG defined during executable
image build) this function updates the 'debug_level' flag, otherwise
it signals a condition and does nothing more.
.call :
SetDebugLevel(new_level)
.input :
int new_level, new value of the debug_level flag
.output :
void
.status_codes :
DEBUG_W_NOT_SUPPORTED
.notes :
1.1, 28-Jan-1998, creation
.- */
void SetDebugLevel(int new_level)
{
#ifdef DEBUG
debug_level = new_level;
#else
ChfCondition DEBUG_W_NOT_SUPPORTED, CHF_WARNING ChfEnd;
ChfSignal();
#endif
}

173
debug.h Normal file
View file

@ -0,0 +1,173 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: debug.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: debug.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 19-Jan-1998
.keywords : *
.description :
This header defines the following macros:
- debug0(debug_class, condition_code)
- debug1(debug_class, condition_code, arg_1)
- debug2(debug_class, condition_code, arg_1, arg_2)
- debug3(debug_class, condition_code, arg_1, arg_2, arg_3)
used throughout the source code for debugging purposes.
If the DEBUG cpp symbol is defined, each invocation of these macros is
expanded into a block of code that, at runtime, checks if the global
variable 'debug_level' has set at least one of the bit 'debug_class' has
set (in other words, it checks if the current debug level enables at
least one of the classes to which the debugging condition belongs).
If this condition is met, the code generates and immediately signals
the given condition code using the Chf facility, with severity CHF_INFO,
otherwise nothing is done.
The arguments arg_1, arg_2, and arg_3 are used as additional arguments
of the condition.
If the DEBUG cpp symbol is not defined, the macros are defined as a null
macros.
.include : Chf.h
.notes :
$Log: debug.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.13 2000/11/09 11:28:34 cibrario
Revised to add file selection box GUI element, CPU halt/run
requests and emulator's extended functions:
- Added new debug class: DEBUG_C_X_FUNC
Revision 3.10 2000/10/24 16:14:32 cibrario
Added/Replaced GPL header
Revision 3.3 2000/09/26 15:20:40 cibrario
Revised to implement Flash ROM write access:
- Added new debug class: DEBUG_C_FLASH
* Revision 2.7 2000/09/19 10:51:13 cibrario
* Added new debug class: DEBUG_C_MOD_CACHE
*
* Revision 2.5 2000/09/14 14:34:13 cibrario
* Added new debug class: DEBUG_C_SERIAL
*
* Revision 1.1 1998/02/18 11:54:33 cibrario
* Initial revision
*
.- */
#ifdef DEBUG
#define debug_preamble(debug_class, condition_code) \
{ \
extern int debug_level; \
if(debug_level & (debug_class)) \
{ \
ChfCondition (condition_code), CHF_INFO
#define debug_postamble \
ChfEnd; \
ChfSignal(); \
} \
}
#define debug0(debug_class, condition_code) \
debug_preamble(debug_class, condition_code) \
debug_postamble
#define debug1(debug_class, condition_code, arg_1) \
debug_preamble(debug_class, condition_code), arg_1 \
debug_postamble
#define debug2(debug_class, condition_code, arg_1, arg_2) \
debug_preamble(debug_class, condition_code), arg_1, arg_2 \
debug_postamble
#define debug3(debug_class, condition_code, arg_1, arg_2, arg_3) \
debug_preamble(debug_class, condition_code), arg_1, arg_2, arg_3 \
debug_postamble
#else
#define debug0(debug_class, condition_code)
#define debug1(debug_class, condition_code, arg_1)
#define debug2(debug_class, condition_code, arg_1, arg_2)
#define debug3(debug_class, condition_code, arg_1, arg_2, arg_3)
#endif
/*---------------------------------------------------------------------------
Debug classes
---------------------------------------------------------------------------*/
#define DEBUG_C_TRACE 0x8000 /* Function Call trace */
#define DEBUG_C_MODULES 0x4000 /* Modules configuration */
#define DEBUG_C_DISPLAY 0x2000 /* Display activity */
#define DEBUG_C_INT 0x1000 /* Interrupt activity */
#define DEBUG_C_TIMERS 0x0800 /* Timers activity */
#define DEBUG_C_SERIAL 0x0400 /* 2.5: Serial port activity */
#define DEBUG_C_MOD_CACHE 0x0200 /* 2.7: Module cache */
#define DEBUG_C_IMPLEMENTATION 0x0100 /* Feature implementation */
#define DEBUG_C_FLASH 0x0080 /* 3.3: Flash ROM */
#define DEBUG_C_X_FUNC 0x0040 /* 3.13: Extended functions */
#define DEBUG_C_REVISION 0x0010 /* Revision information */
#define DEBUG_C_X11 0x0001 /* X11 Interface */
/*---------------------------------------------------------------------------
Chf condition codes
---------------------------------------------------------------------------*/
#define DEBUG_W_NOT_SUPPORTED 201 /* Debug not supported */
#define DEBUG_W_BAD_CMD 202 /* Invalid command */
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
void SetDebugLevel(int new_level);

29
debug.msf Normal file
View file

@ -0,0 +1,29 @@
$ .+
$ .identifier : $Id: debug.msf,v 4.1 2000/12/11 09:54:19 cibrario Rel $
$ .context : SATURN, Saturn CPU / HP48 emulator
$ .title : $RCSfile: debug.msf,v $
$ .kind : Message catalog source
$ .author : Ivan Cibrario B.
$ .site : CSTV-CNR
$ .creation : 13-Feb-1998
$ .keywords : *
$ .description :
$ Message catalog source file for the debugging support modules.
$ .notes :
$ . $Log: debug.msf,v $
$ . Revision 4.1 2000/12/11 09:54:19 cibrario
$ . Public release.
$ .
$ . Revision 3.8 2000/10/19 14:55:10 cibrario
$ . Bug fix:
$ . Removed lines with empty directives
$ .
$ Revision 1.1 1998/02/18 11:54:02 cibrario
$ Initial revision
$ .-
$set 1
30 Debug
$set 30
201 Debug not supported; Rebuild with -DDEBUG

2407
dis.c Normal file

File diff suppressed because it is too large Load diff

322
disk_io.c Normal file
View file

@ -0,0 +1,322 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: disk_io.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: disk_io.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 23-Jan-1998
.keywords : *
.description :
This module implements the disk I/O functions used by the emulator to
save and restore the machine status to/from disk files.
.include : config.h, machdep.h, cpu.h, disk_io.h
.notes :
$Log: disk_io.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:36 cibrario
Added/Replaced GPL header
Revision 1.1 1998/02/17 11:54:38 cibrario
Initial revision
.- */
#ifndef lint
static char rcs_id[] = "$Id: disk_io.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <errno.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "disk_io.h"
#include "debug.h"
#define CHF_MODULE_ID DISK_IO_CHF_MODULE_ID
#include <Chf.h>
/* .+
.title : ReadNibblesFromFile
.kind : C function
.creation : 11-Feb-1998
.description :
This function reads 'size' nibbles from the disk file named 'name',
and stores them into main memory starting from 'dest'. It returns to the
caller a status code.
.call :
st = ReadNibbledFromFile(name, size, dest);
.input :
const char *name, file name
int size, size of the file (nibbles, NOT bytes)
.output :
Nibble *dest, pointer to the destination memory area
int st, status code
.status_codes :
DISK_IO_I_CALLED (signalled)
DISK_IO_E_OPEN
DISK_IO_E_GETC
.notes :
1.1, 11-Feb-1998, creation
.- */
int ReadNibblesFromFile(const char *name, int size, Nibble *dest)
{
FILE *f;
int i;
int by;
int st = DISK_IO_S_OK;
debug1(DEBUG_C_TRACE, DISK_IO_I_CALLED, "ReadNibblesFromFile");
if((f = fopen(name, "rb")) == (FILE *)NULL)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_OPEN, CHF_ERROR, name ChfEnd;
}
else
{
for(i=0; i<size;)
{
by = getc(f);
if(by == -1)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_GETC, CHF_ERROR, name ChfEnd;
break;
}
dest[i++] = (Nibble)(by & 0x0F);
dest[i++] = (Nibble)((by & 0xF0) >> 4);
}
(void)fclose(f);
}
return st;
}
/* .+
.title : WriteNibblesToFile
.kind : C function
.creation : 11-Feb-1998
.description :
This function writes 'size' nibbles taken from 'src' into the file 'name'.
It returns to the caller a status code
.call :
st = WriteNibblesToFile(src, size, name);
.input :
const Nibble *src, pointer to data to be written
int size, # of nibble to write
const char *name, file name
.output :
int st, status code
.status_codes :
DISK_IO_I_CALLED (signalled)
DISK_IO_E_OPEN
DISK_IO_E_PUTC
DISK_IO_E_CLOSE
.notes :
1.1, 11-Feb-1998, creation
.- */
int WriteNibblesToFile(const Nibble *src, int size, const char *name)
{
FILE *f;
int i;
int by;
int st = DISK_IO_S_OK;
debug1(DEBUG_C_TRACE, DISK_IO_I_CALLED, "WriteNibblesToFile");
if((f = fopen(name, "wb")) == (FILE *)NULL)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_OPEN, CHF_ERROR, name ChfEnd;
}
else
{
for(i=0; i<size;)
{
by = (int)src[i++];
by |= (int)src[i++] << 4;
if(putc(by, f) == EOF)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_PUTC, CHF_ERROR, name ChfEnd;
break;
}
}
if(fclose(f) == EOF)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_CLOSE, CHF_ERROR, name ChfEnd;
}
}
return st;
}
/* .+
.title : ReadStructFromFile
.kind : C function
.creation : 11-Feb-1998
.description :
This function reads the contents of the structure 's', with size 's_size',
from the disk file 'name' and returns a status code to the caller.
.call :
st = ReadStructFromFile(name, s_size, s);
.input :
const char *name, file name
size_t s_size, structure size
.output :
void *s, pointer to the structure
.status_codes :
DISK_IO_I_CALLED (signalled)
DISK_IO_E_OPEN
DISK_IO_E_READ
.notes :
1.1, 11-Feb-1998, creation
.- */
int ReadStructFromFile(const char *name, size_t s_size, void *s)
{
FILE *f;
int st = DISK_IO_S_OK;
debug1(DEBUG_C_TRACE, DISK_IO_I_CALLED, "ReadStructFromFile");
if((f = fopen(name, "rb")) == (FILE *)NULL)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_OPEN, CHF_ERROR, name ChfEnd;
}
else
{
if(fread(s, s_size, (size_t)1, f) != 1)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_READ, CHF_ERROR, name ChfEnd;
}
(void)fclose(f);
}
return st;
}
/* .+
.title : WriteStructToFile
.kind : C function
.creation : 11-Feb-1998
.description :
This function writes the structure 's', with size 's_size', to the file
'name' and returns to the caller a status code.
.call :
st =WriteStructToFile(s, s_size, name);
.input :
const void *s, pointer to the structure to be written
size_t s_size, structure size
const char *name, output file name
.output :
int st, status code
.status_codes :
DISK_IO_I_CALLED (signalled)
DISK_IO_E_OPEN
DISK_IO_E_WRITE
DISK_IO_E_CLOSE
.notes :
1.1, 11-Feb-1998, creation
.- */
int WriteStructToFile(const void *s, size_t s_size, const char *name)
{
FILE *f;
int st = DISK_IO_S_OK;
debug1(DEBUG_C_TRACE, DISK_IO_I_CALLED, "WriteStructToFile");
if((f = fopen(name, "wb")) == (FILE *)NULL)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_OPEN, CHF_ERROR, name ChfEnd;
}
else
{
if(fwrite(s, s_size, (size_t)1, f) != 1)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_WRITE, CHF_ERROR, name ChfEnd;
}
if(fclose(f) == EOF)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_CLOSE, CHF_ERROR, name ChfEnd;
}
}
return st;
}

100
disk_io.h Normal file
View file

@ -0,0 +1,100 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: disk_io.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: disk_io.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 28-Jan-1998
.keywords : *
.description :
This header declares the disk I/O functions used by the emulator to
save/restore the machine stats to/from disk files.
.include : config.h machdep.h cpu.h
.notes :
$Log: disk_io.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.14 2000/11/13 10:31:16 cibrario
Implemented fast load/save; improved keyboard interface emulation at
high emulated CPU speed:
- New condition codes: DISK_IO_E_BAD_HDR, DISK_IO_E_SIZE
- New prototypes: ReadObjectFromFile(), WriteObjectToFile()
Revision 3.10 2000/10/24 16:14:36 cibrario
Added/Replaced GPL header
Revision 1.1 1998/02/17 11:55:02 cibrario
Initial revision
.- */
/*---------------------------------------------------------------------------
Chf condition codes
---------------------------------------------------------------------------*/
#define DISK_IO_S_OK 0 /* Function completed succesfully */
#define DISK_IO_I_CALLED 101 /* Function %s called */
#define DISK_IO_E_OPEN 401 /* Open file %s failed */
#define DISK_IO_E_GETC 402 /* getc() from file %s failed */
#define DISK_IO_E_PUTC 403 /* putc() to file %s failed */
#define DISK_IO_E_READ 404 /* fread() from file %s failed */
#define DISK_IO_E_WRITE 405 /* fwrite() to file %s failed */
#define DISK_IO_E_CLOSE 406 /* Close file %s failed */
#define DISK_IO_E_BAD_HDR 407 /* File %s has a bad header */
#define DISK_IO_E_SIZE 408 /* File %s too large */
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
int ReadNibblesFromFile(const char *name, int size, Nibble *dest);
int WriteNibblesToFile(const Nibble *src, int size, const char *name);
int ReadStructFromFile(const char *name, size_t s_size, void *s);
int WriteStructToFile(const void *s, size_t s_size, const char *name);
int ReadObjectFromFile(
const char *name, const char *hdr, Address start, Address end);
int WriteObjectToFile(
Address start, Address end, const char *hdr, const char *name);

44
disk_io.msf Normal file
View file

@ -0,0 +1,44 @@
$ .+
$ .identifier : $Id: disk_io.msf,v 4.1 2000/12/11 09:54:19 cibrario Rel $
$ .context : SATURN, Saturn CPU / HP48 emulator
$ .title : $RCSfile: disk_io.msf,v $
$ .kind : Message catalog source
$ .author : Ivan Cibrario B.
$ .site : CSTV-CNR
$ .creation : 13-Feb-1998
$ .keywords : *
$ .description :
$ Message catalog source file for the disk I/O functions.
$ .notes :
$ . $Log: disk_io.msf,v $
$ . Revision 4.1 2000/12/11 09:54:19 cibrario
$ . Public release.
$ .
$ . Revision 3.14 2000/11/13 10:32:24 cibrario
$ . Implemented fast load/save; improved keyboard interface emulation at
$ . high emulated CPU speed:
$ .
$ . - Fixed spelling error in message 405
$ . - Added new messages: 407, 408
$ .
$ . Revision 3.8 2000/10/19 14:58:41 cibrario
$ . Bug fix:
$ . Removed lines with empty directives
$ .
$ Revision 1.1 1998/02/17 11:54:49 cibrario
$ Initial revision
$ .-
$set 1
13 Disk_IO
$set 13
101 Function [%s] called
401 Can't open file [%s]
402 getc() failed reading file [%s]
403 putc() failed writing file [%s]
404 fread() failed reading file [%s]
405 fwrite() failed writing file [%s]
406 Close file [%s] failed
407 File [%s] has a bad header
408 File [%s] is too large

317
disk_io_obj.c Normal file
View file

@ -0,0 +1,317 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: disk_io_obj.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HPxx emulator
.title : $RCSfile: disk_io_obj.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : IRITI-CNR
.creation : 10-Nov-2000
.keywords : *
.description :
This module implements the disk I/O functions used by the emulator to
save and restore an object to/from disk files.
.include : config.h, machdep.h, cpu.h, disk_io.h
.notes :
$Log: disk_io_obj.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.14 2000/11/13 11:24:20 cibrario
*** empty log message ***
.- */
#ifndef lint
static char rcs_id[] = "$Id: disk_io_obj.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <errno.h>
#include <string.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "disk_io.h"
#include "debug.h"
#define CHF_MODULE_ID DISK_IO_CHF_MODULE_ID
#include <Chf.h>
/* .+
.title : ReadObjectFromFile
.kind : C function
.creation : 10-Nov-2000
.description :
This function reads an object from file 'name' and stores it into
the calculator's memory from nibble address 'start' inclusive to nibble
address 'end' exclusive.
The presence of header 'hdr' in the disk file is checked, then the
header is stripped before starting the transfer. In 'hdr', '?'
is a wildcard character that matches any input character.
Objects with an odd number of nibbles are padded to an even
size adding a 0 nibble to their end; the trailing zero *is* stored
in calculator's memory.
When the object size exceeds the available space this function
transfers its head anyway, thereby corrupting the calculator's
memory between 'start' and 'end', except the first N_SAVE_AREA nibbles.
This function returns to the caller a status code.
.call :
st = ReadObjectFromFile(name, hdr, start, end);
.input :
const char *name, input file name
const char *hdr, file header
Address start, start address (inclusive)
Address end, end address (exclusive)
.output :
int st, status code
.status_codes :
DISK_IO_I_CALLED (signalled)
DISK_IO_E_OPEN
DISK_IO_E_GETC
DISK_IO_E_BAD_HDR
DISK_IO_E_SIZE
.notes :
3.14, 10-Nov-2000, creation
.- */
int ReadObjectFromFile(
const char *name, const char *hdr, Address start, Address end)
{
size_t hdr_len = strlen(hdr);
FILE *f;
int i;
int by;
Address cur;
#define N_SAVE_AREA 10
Nibble save_area[N_SAVE_AREA];
int st = DISK_IO_S_OK;
debug1(DEBUG_C_TRACE, DISK_IO_I_CALLED, "ReadObjectFromFile");
/* Save first nibbles of target space into save_area */
for(cur=start, i=0; cur < end && i<N_SAVE_AREA; cur++, i++)
save_area[i] = ReadNibble(cur);
if((f = fopen(name, "rb")) == (FILE *)NULL)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_OPEN, CHF_ERROR, name ChfEnd;
}
else
{
/* Check and skip header */
for(i=0; i<hdr_len; i++)
{
by = getc(f);
if(by == EOF)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_GETC, CHF_ERROR, name ChfEnd;
break;
}
else if(hdr[i] != '?' && by != hdr[i])
{
ChfCondition st=DISK_IO_E_BAD_HDR, CHF_ERROR, name ChfEnd;
break;
}
}
if(st == DISK_IO_S_OK)
{
cur = start;
/* Header check/skip OK; transfer */
while((by = getc(f)) != EOF)
{
/* Next byte available in by; check available space */
if(cur >= end-1)
{
ChfCondition st=DISK_IO_E_SIZE, CHF_ERROR, name ChfEnd;
break;
}
/* Store it */
WriteNibble(cur++, (Nibble)(by & 0x0F));
WriteNibble(cur++, (Nibble)((by & 0xF0) >> 4));
}
/* Check why getc() failed */
if(ferror(f) && !feof(f))
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_GETC, CHF_ERROR, name ChfEnd;
}
/* Recover from save_area if transfer failed */
if(st)
for(cur=start, i=0; cur < end && i<N_SAVE_AREA; cur++, i++)
WriteNibble(cur, save_area[i]);
}
(void)fclose(f);
}
return st;
}
/* .+
.title : WriteObjectToFile
.kind : C function
.creation : 10-Nov-2000
.description :
This function writes an object located in calculator's memory,
from nibble address 'start' inclusive to nibble address 'end' exclusive,
into the file 'name'. The header 'hdr' is prepended to the actual
object and objects with an odd number of nibbles are padded to an even
size adding a 0 nibble to their end. In 'hdr', the wildcard character
'?' is replaced by 'S' when the header is written on disk.
This function returns to the caller a status code.
.call :
st = WriteObjectToFile(start, end, hdr, name);
.input :
Address start, start address (inclusive)
Address end, end address (exclusive)
const char *hdr, file header
const char *name, output file name
.output :
int st, status code
.status_codes :
DISK_IO_I_CALLED (signalled)
DISK_IO_E_OPEN
DISK_IO_E_PUTC
DISK_IO_E_CLOSE
.notes :
3.14, 10-Nov-2000, creation
.- */
int WriteObjectToFile(
Address start, Address end, const char *hdr, const char *name)
{
size_t hdr_len = strlen(hdr);
FILE *f;
int i;
int by;
Address cur;
int st = DISK_IO_S_OK;
debug1(DEBUG_C_TRACE, DISK_IO_I_CALLED, "WriteObjectFromFile");
if((f = fopen(name, "wb")) == (FILE *)NULL)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_OPEN, CHF_ERROR, name ChfEnd;
}
else
{
/* Write header; replace wildcard character '?' with 'S' */
for(i=0; i<hdr_len; i++)
{
if(putc(hdr[i] == '?' ? 'S' : hdr[i], f) == EOF)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_PUTC, CHF_ERROR, name ChfEnd;
break;
}
}
if(st == DISK_IO_S_OK)
{
cur = start;
while(cur < end-1)
{
/* Make a byte with two nibbles */
by = (int)ReadNibble(cur++);
by |= (int)ReadNibble(cur++) << 4;
if(putc(by, f) == EOF)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_PUTC, CHF_ERROR, name ChfEnd;
break;
}
}
/* Write the last odd nibble, if necessary */
if(st == DISK_IO_S_OK && cur == end-1)
{
by = (int)ReadNibble(cur++);
if(putc(by, f) == EOF)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_PUTC, CHF_ERROR, name ChfEnd;
}
}
}
/* Close the output file anyway */
if(fclose(f) == EOF)
{
ChfErrnoCondition;
ChfCondition st=DISK_IO_E_CLOSE, CHF_ERROR, name ChfEnd;
}
}
return st;
}

628
display.c Normal file
View file

@ -0,0 +1,628 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: display.c,v 4.1.1.1 2002/11/11 16:12:46 cibrario Exp $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: display.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 29-Jan-1998
.keywords : *
.description :
This source module emulates the Lcd driver of the Yorke chip.
References:
SASM.DOC by HP (HORN disk 4)
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
x48 source code by Eddie C. Dost (ecd@dressler.de)
NOTE: In the current (r1.1) implementation, the control fields
mod_status.hdw.lcd_offset and mod_status.hdw.lcd_contrast are
not supported. Therefore, the emulation accuracy is sometimes
poor; for example, the Equation Writer does not work well with
large equations.
.include : config.h, machdep.h, cpu.h, modules.h, display.h
.notes :
$Log: display.c,v $
Revision 4.1.1.1 2002/11/11 16:12:46 cibrario
Small screen support; preliminary
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:37 cibrario
Added/Replaced GPL header
Revision 3.8 2000/10/23 13:15:36 cibrario
Bug fix:
In InitLcd(), added a clip rectangle to GC, to avoid drawing non-existent
pixels, that is, pixels that *do* exist in the frame buffer, but should
never be viewed on screen.
Revision 3.5 2000/10/02 09:44:42 cibrario
Linux support:
- gcc does not like array subscripts with type 'char', and it is right.
Revision 3.1 2000/09/20 13:47:58 cibrario
Minor updates and fixes to avoid gcc compiler warnings on Solaris
when -ansi -pedantic -Wall options are selected.
* Revision 1.1 1998/02/17 14:14:39 cibrario
* Initial revision
*
.- */
#ifndef lint
static char rcs_id[] = "$Id: display.c,v 4.1.1.1 2002/11/11 16:12:46 cibrario Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h> /* 3.1: memset() */
#include <X11/Xlib.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "display.h"
#include "x11.h"
#include "debug.h"
#define CHF_MODULE_ID X11_CHF_MODULE_ID
#include <Chf.h>
#ifndef LCD_MAG
# define LCD_MAG 2 /* 4.1.1.1: Compat. default */
#endif
#define NIBBLES_PER_ROW 34 /* 136 pixel total */
#define MAX_ROWS 64 /* 64 rows total */
#define N_ANN 6 /* # of annunciators */
#define LCD_X_ORIGIN 1+4*(LCD_MAG-1) /* x origin */
#if LCD_MAG==1
# define LCD_Y_ORIGIN 14 /* y origin */
#else
# define LCD_Y_ORIGIN 20 /* y origin */
#endif
/* 3.8: Origin and size of clip rectangle */
#define LCD_CLIP_X_ORIGIN LCD_X_ORIGIN
#define LCD_CLIP_Y_ORIGIN 0 /* Don't clip annunciators */
#define LCD_CLIP_WIDTH 131*LCD_MAG
#define LCD_CLIP_HEIGHT LCD_Y_ORIGIN+64*LCD_MAG
#define MASK_ANN_LEFT 0x81 /* Annunciator's bit masks */
#define MASK_ANN_RIGHT 0x82
#define MASK_ANN_ALPHA 0x84
#define MASK_ANN_BATTERY 0x88
#define MASK_ANN_BUSY 0x90
#define MASK_ANN_IO 0xA0
/*---------------------------------------------------------------------------
Static/Global variables
---------------------------------------------------------------------------*/
static /*const*/ char nibble_bitmap_data[NIBBLE_VALUES][LCD_MAG] =
{
#if LCD_MAG==1
{ 0x00 }, /* ---- */
{ 0x01 }, /* *--- */
{ 0x02 }, /* -*-- */
{ 0x03 }, /* **-- */
{ 0x04 }, /* --*- */
{ 0x05 }, /* *-*- */
{ 0x06 }, /* -**- */
{ 0x07 }, /* ***- */
{ 0x08 }, /* ---* */
{ 0x09 }, /* *--* */
{ 0x0a }, /* -*-* */
{ 0x0b }, /* **-* */
{ 0x0c }, /* --** */
{ 0x0d }, /* *-** */
{ 0x0e }, /* -*** */
{ 0x0f } /* **** */
#elif LCD_MAG==2
{ 0x00, 0x00 }, /* ---- */
{ 0x03, 0x03 }, /* *--- */
{ 0x0c, 0x0c }, /* -*-- */
{ 0x0f, 0x0f }, /* **-- */
{ 0x30, 0x30 }, /* --*- */
{ 0x33, 0x33 }, /* *-*- */
{ 0x3c, 0x3c }, /* -**- */
{ 0x3f, 0x3f }, /* ***- */
{ 0xc0, 0xc0 }, /* ---* */
{ 0xc3, 0xc3 }, /* *--* */
{ 0xcc, 0xcc }, /* -*-* */
{ 0xcf, 0xcf }, /* **-* */
{ 0xf0, 0xf0 }, /* --** */
{ 0xf3, 0xf3 }, /* *-** */
{ 0xfc, 0xfc }, /* -*** */
{ 0xff, 0xff } /* **** */
#else
# error "Bad LCD_MAG; supported values are 1 and 2"
#endif
};
static /*const*/ struct
{
int mask; /* Bit mask */
int x, y; /* Position */
int w, h; /* Width, Height */
char bitmap_data[24]; /* Bitmap data */
}
#define ANN_X(i) (8*LCD_MAG+(22*LCD_MAG+1)*i)
#define ANN_Y(i) (1+3*(LCD_MAG-1))
ann_data[N_ANN] =
{
{ MASK_ANN_LEFT,
ANN_X(0), ANN_Y(0),
15, 12,
{ 0xfe, 0x3f, 0xff, 0x7f, 0x9f, 0x7f, 0xcf, 0x7f, 0xe7, 0x7f, 0x03, 0x78,
0x03, 0x70, 0xe7, 0x73, 0xcf, 0x73, 0x9f, 0x73, 0xff, 0x73, 0xfe, 0x33
}
},
{ MASK_ANN_RIGHT,
ANN_X(1), ANN_Y(1),
15, 12,
{ 0xfe, 0x3f, 0xff, 0x7f, 0xff, 0x7c, 0xff, 0x79, 0xff, 0x73, 0x0f, 0x60,
0x07, 0x60, 0xe7, 0x73, 0xe7, 0x79, 0xe7, 0x7c, 0xe7, 0x7f, 0xe6, 0x3f
}
},
{ MASK_ANN_ALPHA,
ANN_X(2), ANN_Y(2),
15, 12,
{ 0xe0, 0x03, 0x18, 0x44, 0x0c, 0x4c, 0x06, 0x2c, 0x07, 0x2c, 0x07, 0x1c,
0x07, 0x0c, 0x07, 0x0c, 0x07, 0x0e, 0x0e, 0x4d, 0xf8, 0x38, 0x00, 0x00
}
},
{ MASK_ANN_BATTERY,
ANN_X(3), ANN_Y(3),
15, 12,
{ 0x04, 0x10, 0x02, 0x20, 0x12, 0x24, 0x09, 0x48, 0xc9, 0x49, 0xc9, 0x49,
0xc9, 0x49, 0x09, 0x48, 0x12, 0x24, 0x02, 0x20, 0x04, 0x10, 0x00, 0x00
}
},
{ MASK_ANN_BUSY,
ANN_X(4), ANN_Y(4),
15, 12,
{ 0xfc, 0x1f, 0x08, 0x08, 0x08, 0x08, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01,
0x40, 0x01, 0x20, 0x02, 0x10, 0x04, 0xc8, 0x09, 0xe8, 0x0b, 0xfc, 0x1f
}
},
{ MASK_ANN_IO,
ANN_X(5), ANN_Y(5),
15, 12,
{ 0x0c, 0x00, 0x1e, 0x00, 0x33, 0x0c, 0x61, 0x18, 0xcc, 0x30, 0xfe, 0x7f,
0xfe, 0x7f, 0xcc, 0x30, 0x61, 0x18, 0x33, 0x0c, 0x1e, 0x00, 0x0c, 0x00
}
}
};
static Nibble lcd_buffer[MAX_ROWS][NIBBLES_PER_ROW];
static int ann_buffer;
static int clean;
static Display *display;
static Window window;
static GC gc;
static unsigned long fg_pixel, bg_pixel;
static unsigned int depth;
static Pixmap nibble_pixmap[NIBBLE_VALUES];
static Pixmap ann_pixmap[N_ANN];
/*---------------------------------------------------------------------------
Private functions
---------------------------------------------------------------------------*/
/* .+
.title : InitPixmaps
.kind : C function
.creation : 29-Jan-1998
.description :
This function initializes the pixmaps for the Lcd screen elements and
stores them into the appropriate global variables.
.call :
InitPixmaps();
.input :
void
.output :
void
.status_codes :
X11_I_CALLED
X11_F_X_ERROR
.notes :
1.1, 29-Jan-1998, creation
.- */
static void InitPixmaps(void)
{
int i;
debug1(DEBUG_C_TRACE, X11_I_CALLED, "InitPixmaps");
/* Initialize nibble_pixmap */
for(i=0; i<NIBBLE_VALUES; i++)
{
if((nibble_pixmap[i] =
XCreatePixmapFromBitmapData(
display, window, nibble_bitmap_data[i], 4*LCD_MAG, LCD_MAG,
fg_pixel, bg_pixel, depth
)) ==
None)
{
ChfCondition X11_F_X_ERROR, CHF_FATAL ChfEnd;
ChfSignal();
}
}
/* Initialize ann_pixmap */
for (i=0; i<N_ANN; i++)
{
if((ann_pixmap[i] =
XCreatePixmapFromBitmapData(display, window,
ann_data[i].bitmap_data, ann_data[i].w, ann_data[i].h,
fg_pixel, bg_pixel, depth
)) ==
None)
{
ChfCondition X11_F_X_ERROR, CHF_FATAL ChfEnd;
ChfSignal();
}
}
}
/* .+
.title : ClearLcd
.kind : C function
.creation : 29-Jan-1998
.description :
This function clears the Lcd screen
.call :
ClearLcd();
.input :
void
.output :
void
.status_codes :
X11_I_CALLED
.notes :
1.1, 29-Jan-1998, creation
.- */
static void ClearLcd(void)
{
debug1(DEBUG_C_TRACE, X11_I_CALLED, "ClearLcd");
/* Clear Lcd display */
(void)memset((void *)lcd_buffer, 0, sizeof(lcd_buffer));
ann_buffer = 0;
XClearWindow(display, window);
XFlush(display);
}
/*---------------------------------------------------------------------------
Public funcitons
---------------------------------------------------------------------------*/
/* .+
.title : InitLcd
.kind : C function
.creation : 29-Jan-1998
.description :
This function initializes the Lcd driver emulator and prepares it for use.
The LCD screen is initially cleared.
.call :
InitLcd(lcd_display, lcd_window, lcd_fg_pixel, lcd_bg_pixel);
.input :
Display *lcd_display, X display
Window lcd_window, X window to be used for display
unsigned long lcd_fg_pixel, foreground color to be used
unsigned long lcd_bg_pixel, background color to be used
.output :
void
.status_codes :
X11_I_CALLED
X11_F_X_ERROR
.notes :
1.1, 29-Jan-1998, creation
3.8, 23-Oct-2000, bug fix:
- added clip rectangle to GC, to avoid drawing non-existent pixels.
.- */
void InitLcd(Display *lcd_display, Window lcd_window,
unsigned long lcd_fg_pixel, unsigned long lcd_bg_pixel)
{
XWindowAttributes xwa;
XGCValues gc_values;
debug1(DEBUG_C_TRACE, X11_I_CALLED, "InitLcdWindow");
display = lcd_display;
window = lcd_window;
fg_pixel = lcd_fg_pixel;
bg_pixel = lcd_bg_pixel;
/* Get window attributes and initialize window depth */
if(XGetWindowAttributes(display, window, &xwa) == 0)
{
ChfCondition X11_F_X_ERROR, CHF_FATAL ChfEnd;
ChfSignal();
}
depth = xwa.depth;
/* Create GC */
gc_values.function = GXcopy;
gc_values.plane_mask = AllPlanes;
gc_values.subwindow_mode = IncludeInferiors;
gc_values.foreground = lcd_fg_pixel;
gc_values.background = lcd_bg_pixel;
gc_values.graphics_exposures = False;
gc = XCreateGC(display, window,
GCFunction|GCPlaneMask|GCForeground|GCBackground|GCSubwindowMode|
GCGraphicsExposures,
&gc_values);
{
/* 3.8: This clip rectangle prevents XCopyArea() (in DrawLcd()) from
drawing non-visible pixels
*/
XRectangle rect[1];
rect[0].x = LCD_CLIP_X_ORIGIN; /* This is the clip rectangle */
rect[0].y = LCD_CLIP_Y_ORIGIN;
rect[0].width = LCD_CLIP_WIDTH;
rect[0].height = LCD_CLIP_HEIGHT;
XSetClipRectangles(
display, gc,
0, 0, /* Alsolute clip X,Y origin */
rect, 1, YXBanded);
}
/* Initialize Pixmaps */
InitPixmaps();
/* Clear screen and initialize the static memory areas */
ClearLcd();
/* Set the 'display is clean' flag */
clean = 1;
}
/* .+
.title : DrawLcd
.kind : C function
.creation : 29-Jan-1998
.description :
This function redraws the Lcd screen from the information contained in
the mod_status.hdw structure.
.call :
DrawLcd();
.input :
void
.output :
void
.status_codes :
X11_I_CALLED
X11_I_LCD_PAR
.notes :
1.1, 29-Jan-1998, creation
.- */
void DrawLcd(void)
{
Address addr = mod_status.hdw.lcd_base_addr;
int y, x;
Nibble v;
debug1(DEBUG_C_TRACE, X11_I_CALLED, "DrawLcd");
/* If the debug class DEBUG_C_DISPLAY is enabled, print the display
parameters
*/
debug2(DEBUG_C_DISPLAY, X11_I_LCD_PAR, "_base_addr",
(int)mod_status.hdw.lcd_base_addr);
debug2(DEBUG_C_DISPLAY, X11_I_LCD_PAR, "_on",
(int)mod_status.hdw.lcd_on);
debug2(DEBUG_C_DISPLAY, X11_I_LCD_PAR, "_contrast",
(int)mod_status.hdw.lcd_contrast);
debug2(DEBUG_C_DISPLAY, X11_I_LCD_PAR, "_vlc",
(int)mod_status.hdw.lcd_vlc);
debug2(DEBUG_C_DISPLAY, X11_I_LCD_PAR, "_offset",
(int)mod_status.hdw.lcd_offset);
debug2(DEBUG_C_DISPLAY, X11_I_LCD_PAR, "_line_offset",
(int)mod_status.hdw.lcd_line_offset);
debug2(DEBUG_C_DISPLAY, X11_I_LCD_PAR, "_menu_addr",
(int)mod_status.hdw.lcd_menu_addr);
debug2(DEBUG_C_DISPLAY, X11_I_LCD_PAR, "_ann",
(int)mod_status.hdw.lcd_ann);
/* Check if display is on */
if(!mod_status.hdw.lcd_on)
{
/* Display is off; clear lcd if necessary */
if(!clean)
{
/* Set the 'display is clean' flag and clear the screen */
clean = 1;
ClearLcd();
}
return;
}
/* The display is on and will be no longer clean */
clean = 0;
/* Scan active display rows */
for(y=0; y<=mod_status.hdw.lcd_vlc; y++)
{
/* Scan columns */
for(x=0; x<NIBBLES_PER_ROW; x++)
{
v = FetchNibble(addr++);
if( v != lcd_buffer[y][x] )
{
lcd_buffer[y][x] = v;
XCopyArea(display, nibble_pixmap[(int)v], window, gc,
0, 0, /* src_x, src_y */
4*LCD_MAG, LCD_MAG, /* width, height */
x*4*LCD_MAG + LCD_X_ORIGIN,
y*LCD_MAG + LCD_Y_ORIGIN
);
}
}
addr += mod_status.hdw.lcd_line_offset;
}
/* Scan menu display rows */
addr = mod_status.hdw.lcd_menu_addr;
for(; y<MAX_ROWS; y++)
{
/* Scan columns */
for(x=0; x<NIBBLES_PER_ROW; x++)
{
v = FetchNibble(addr++);
if( v != lcd_buffer[y][x] )
{
lcd_buffer[y][x] = v;
XCopyArea(display, nibble_pixmap[(int)v], window, gc,
0, 0, /* src_x, src_y */
4*LCD_MAG, LCD_MAG, /* width, height */
x*4*LCD_MAG + LCD_X_ORIGIN,
y*LCD_MAG + LCD_Y_ORIGIN
);
}
}
}
/* Scan annunciators */
if(mod_status.hdw.lcd_ann != ann_buffer)
{
ann_buffer = mod_status.hdw.lcd_ann;
for(y=0; y<N_ANN; y++)
{
if((ann_buffer & ann_data[y].mask) == ann_data[y].mask)
{
XCopyArea(display, ann_pixmap[y], window, gc,
0, 0, /* src_x, src_y */
ann_data[y].w, ann_data[y].h, /* width, height */
ann_data[y].x,
ann_data[y].y
);
}
else
{
XClearArea(display, window,
ann_data[y].x, ann_data[y].y,
ann_data[y].w, ann_data[y].h,
False /* No exposures */
);
}
}
}
/* Flush display */
XFlush(display);
}
/* .+
.title : RefreshLcd
.kind : C function
.creation : 17-Feb-1998
.description :
This function refreshes the Lcd screen after a X Window Expose event.
.call :
RefreshLcd();
.input :
void
.output :
void
.status_codes :
X11_I_CALLED
.notes :
1.1, 17-Feb-1998, creation
.- */
void RefreshLcd(void)
{
debug1(DEBUG_C_TRACE, X11_I_CALLED, "RefreshLcd");
ClearLcd();
DrawLcd();
}

93
display.h Normal file
View file

@ -0,0 +1,93 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: display.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: display.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 28-Jan-1998
.keywords : *
.description :
This header contains all definitions and declarations related to the
HP48's LCD display emulator. References:
SASM.DOC by HP (HORN disk 4)
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
x48 source code by Eddie C. Dost (ecd@dressler.de)
.include : config.h, machdep.h, cpu.h, modules.h, X11/Xlib.h
.notes :
$Log: display.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:38 cibrario
Added/Replaced GPL header
Revision 1.1 1998/02/17 11:51:31 cibrario
Initial revision
.- */
/*---------------------------------------------------------------------------
Data type definitions - require config.h, machdep.h, cpu.h
---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
Macros
---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
Global variables
---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
void InitLcd(Display *lcd_display, Window lcd_window,
unsigned long lcd_fg_pixel, unsigned long lcd_bg_pixel);
void DrawLcd(void);
void RefreshLcd(void);

701
emulator.c Normal file
View file

@ -0,0 +1,701 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: emulator.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: emulator.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 2-Feb-1998
.keywords : *
.description :
This file contains the main loop of the emulator. For efficiency reasons,
this module also emulates both T1 and T2 timers. References:
SASM.DOC by HP (HORN disk 4)
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
x48 source code by Eddie C. Dost (ecd@dressler.de)
.include : config.h, machdep.h, cpu.h
.notes :
$Log: emulator.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.13 2000/11/09 11:30:40 cibrario
Revised to add file selection box GUI element, CPU halt/run
requests and emulator's extended functions:
- The upper limit to the CPU speed can now be changed at runtime.
- Fixed a bug in EmulatorLoopHandler(): it could return an invalid
Chf action code.
Revision 3.10 2000/10/24 16:14:39 cibrario
Added/Replaced GPL header
Revision 3.5 2000/10/02 09:48:04 cibrario
Linux support:
- EmulatorLoop(): revised to force an upper limit to the CPU speed if
the compile-time option REAL_CPU_SPEED is defined: inner_loop is
limited to INNER_LOOP_MAX and the excess time is spent sleeping.
Revision 3.2 2000/09/22 13:43:09 cibrario
Implemented preliminary support of HP49 hw architecture:
- EmulatorInit() now invokes ModSelectDescription() to select
the appropriate calculator's hw configuration depending on the
setting of the 'hw' user option.
* Revision 3.1 2000/09/20 14:12:45 cibrario
* Revised to implement passive CPU shutdown:
* - enhanced EmulatorLoopHandler() to handle the CPU_I_SHUTDN condition
* when CPU_SPIN_SHUTDN is not defined.
*
* Revision 2.5 2000/09/14 14:45:37 cibrario
* Added call to HandleSerial() in EmulatorLoop(), in order to
* handle external events related to serial port emulation.
*
* Revision 2.4 2000/09/12 15:17:18 cibrario
* Updated EmulatorInit() in order to invoke CpuInit() before ModInit(),
* so that interrupt requests generated by ModInit() are honored as
* they should. This is required to implement emulation of Port 1 and 2.
*
* Revision 2.1 2000/09/08 14:57:49 cibrario
* - Removed explicit cast of second argument from calls to gettimeofday()
* - Minor fixes needed by Chf Release 2
* - Defined new convenience functions EmulatorInit() and EmulatorExit();
* they can be invoked to reset/initialize the emulation core and
* to prepare it to exit, respectively.
*
* Revision 1.1 1998/02/18 11:49:21 cibrario
* Initial revision
*
.- */
#ifndef lint
static char rcs_id[] = "$Id: emulator.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "display.h"
#include "x11.h"
#include "serial.h"
#include "args.h"
#include "debug.h"
#define CHF_MODULE_ID CPU_CHF_MODULE_ID
#include <Chf.h>
/*---------------------------------------------------------------------------
Private macros / variables / functions
---------------------------------------------------------------------------*/
#define T1_MULTIPLIER (8192/16) /* T2/T1 increment ratio */
#define T1_INTERVAL 62500 /* us per T1 increment */
#define T2_INTERVAL 122 /* us per T2 increment */
/* 3.1: MAX_IDLE_X_LOOP_TIMEOUT must be low enough to prevent overflow
of an int when computing the difference in microseconds between two
struct timeval and to avoid starvation of the serial port emulation
module (*); T1_MS_MULTIPLIER and T2_MS_DIVISOR are approximate
values used only to compute e reasonable timeout for IdleXLoop();
the actual update of timers is carried out using T1_INTERVAL
and T2_INTERVAL, and should be more accurate.
(*) XXX This constraint will be removed when the serial port emulation
module will support asynchronous selection on pty fd and will
be able to interact with the GUI's select mechanism.
*/
#define T1_MS_MULTIPLIER 63 /* 3.1: Milliseconds per T1 tick (~) */
#define T2_MS_DIVISOR 8 /* 3.1: T2 ticks per millisecond (~) */
#define MAX_IDLE_X_LOOP_TIMEOUT 1000 /* 3.1: Max timeout for IdleXLoop() */
#define T1_OVF_MASK NIBBLE_MASK /* 3.1: Timer overflow masks */
#define T2_OVF_MASK 0xFFFFFFFF
#define LCD_T1_MASK 0x3 /* LCD refresh timing mask */
#define INT_T1_MASK 0xF /* Int. req. timing mask */
static int emulator_int_req = 0; /* Interrupt request flag */
/* This function contains the main emulator loop; under normal conditions,
it never returns to the caller. The only way to exit this function is
to signal a Chf condition that triggers an unwind operation.
*/
static void EmulatorLoop(void)
{
struct timeval old_t, cur_t;
int ela;
int inner_loop = cpu_status.inner_loop;
int t1_count = 0;
int i, j;
debug1(DEBUG_C_TRACE, CPU_I_CALLED, "EmulatorLoop");
/* Ignore past interrupt requests */
emulator_int_req = 0;
/* Get current time of day */
gettimeofday(&old_t, NULL);
while(1)
{
/* T1 loop */
for(j=0; j<T1_MULTIPLIER; j++)
{
/* Inner loop */
for(i=0; i<inner_loop; i++) OneStep();
/* T2 update */
if(mod_status.hdw.t2_ctrl & T2_CTRL_TRUN)
{
if(--mod_status.hdw.t2_val == 0xFFFFFFFF)
{
debug1(DEBUG_C_TIMERS, CPU_I_TIMER2_EX, mod_status.hdw.t2_ctrl);
mod_status.hdw.t2_ctrl |= T2_CTRL_SREQ;
if(mod_status.hdw.t2_ctrl & T2_CTRL_WAKE)
CpuWake();
if(mod_status.hdw.t2_ctrl & T2_CTRL_INT)
CpuIntRequest(INT_REQUEST_IRQ);
}
}
}
/* T1 update */
mod_status.hdw.t1_val = (mod_status.hdw.t1_val - 1) & NIBBLE_MASK;
if(mod_status.hdw.t1_val == 0xF)
{
debug1(DEBUG_C_TIMERS, CPU_I_TIMER1_EX, mod_status.hdw.t1_ctrl);
mod_status.hdw.t1_ctrl |= T1_CTRL_SREQ;
if(mod_status.hdw.t1_ctrl & T1_CTRL_WAKE)
CpuWake();
if(mod_status.hdw.t1_ctrl & T1_CTRL_INT)
CpuIntRequest(INT_REQUEST_IRQ);
}
/* LCD update */
if((t1_count++ & LCD_T1_MASK) == 0) DrawLcd();
/* Emulator Interrupt Request */
if((t1_count & INT_T1_MASK) == 0 && emulator_int_req)
{
ChfCondition CPU_I_EMULATOR_INT, CHF_INFO ChfEnd;
ChfSignal();
}
/* X Events handling */
HandleXEvents();
/* Handle serial port */
HandleSerial();
/* Adjust inner_loop limit */
gettimeofday(&cur_t, NULL);
ela = (cur_t.tv_sec - old_t.tv_sec) * 1000000 +
(cur_t.tv_usec - old_t.tv_usec);
inner_loop = inner_loop * T1_INTERVAL / ela;
if(inner_loop < INNER_LOOP_MIN) inner_loop = INNER_LOOP_MIN;
#ifdef REAL_CPU_SPEED
/* 3.13: Force an upper limit to the CPU speed if the compile-time option
REAL_CPU_SPEED is defined: inner_loop is limited to
cpu_status.inner_loop_max
and the excess time, if any, is spent sleeping; usleep() is
BSD 4.3-specific, but most recent systems should offer it anyway,
well, I hope.
The special value cpu_status.inner_loop_max==0 gives maximum speed.
*/
if(cpu_status.inner_loop_max != 0
&& inner_loop >= cpu_status.inner_loop_max)
{
inner_loop = cpu_status.inner_loop_max;
if(T1_INTERVAL > ela) usleep(T1_INTERVAL - ela);
}
#endif
cpu_status.inner_loop = inner_loop;
old_t = cur_t;
}
}
/* Condition handler for the EmulatorLoop */
static ChfAction EmulatorLoopHandler(
const ChfDescriptor *d,
const ChfState s,
ChfPointer ctx
)
{
ChfAction act;
/* Check Chf state */
switch(s)
{
/* 2.1: Chf release 2 fixed the spelling of 'SIGNALING' */
case CHF_SIGNALING:
/* ChfSignal() in progress */
if(ChfGetModuleId(d) == CPU_CHF_MODULE_ID)
{
/* Condition from CPU modules; check Condition Code */
switch(ChfGetConditionCode(d))
{
#ifdef CPU_SPIN_SHUTDN
case CPU_I_SHUTDN:
/* CPU shutdown signalled with CPU_SPIN_SHUTDN defined;
Fatal error.
*/
ChfCondition CPU_F_BAD_SHUTDN, CHF_FATAL ChfEnd;
ChfSignal();
act = CHF_RESIGNAL;
break;
#else
case CPU_I_SHUTDN:
{
/* 3.1: CPU_SPIN_SHUTDN is not defined, and the cpu emulator
has just executed a shutdown instruction.
Let's do something a little tricky here:
1- redraw the LCD
2- handle serial port activities
3- determine which timer will expire first, and
compute an approximate value of the maximum duration
of the shutdown --> ms
4- handle serial port activities
5- enter the inner idle loop; it breaks when either an
X Event occurred (possibly clearing the shutdown) or
the shutdown timeout elapses
6- determine the actual time we spend in the idle loop
(X timeouts are not accurate enough for this purpose)
7- update T1 and T2, check their state and wake/interrupt
the CPU if necessary
Activities 3-7 above are enclosed in an outer loop because we
cannot be absolutely sure of the actual time spent
in the idle loop; moreover, not all X Events actually
spool up the CPU. The outer loop breaks when the CPU is
actually brought out of shutdown.
frac_t1 and frac_t2 contain the number of microseconds
not accounted for in the last T1/T2 update, respectively;
they help minimize the cumulative timing error induced
by executing the outer idle loop more than once.
*/
struct timeval start_idle, end_idle;
int frac_t1=0, frac_t2=0;
gettimeofday(&start_idle, NULL);
/* Redraw the LCD immediately before entering idle loop;
this ensures that the latest LCD updated actually
get to the screen.
*/
DrawLcd();
/* Handle serial port activity before entering the outer idle
loop, because this could possibly bring the cpu out of
shutdown right now.
*/
HandleSerial();
/* XXX
If either timer has a pending service request,
process it immediately. It is not clear why it was
not processed *before* shutdown, though.
*/
if(mod_status.hdw.t1_ctrl & T1_CTRL_SREQ)
{
if(mod_status.hdw.t1_ctrl & T1_CTRL_WAKE)
CpuWake();
if(mod_status.hdw.t1_ctrl & T1_CTRL_INT)
CpuIntRequest(INT_REQUEST_IRQ);
}
if(mod_status.hdw.t2_ctrl & T2_CTRL_SREQ)
{
if(mod_status.hdw.t2_ctrl & T2_CTRL_WAKE)
CpuWake();
if(mod_status.hdw.t2_ctrl & T2_CTRL_INT)
CpuIntRequest(INT_REQUEST_IRQ);
}
while(cpu_status.shutdn)
{
unsigned long ms = MAX_IDLE_X_LOOP_TIMEOUT;
unsigned long mst;
int ela;
int ela_ticks;
debug3(DEBUG_C_TIMERS, CPU_I_TIMER_ST, "T1 (during SHUTDN)",
mod_status.hdw.t1_ctrl, mod_status.hdw.t1_val);
debug3(DEBUG_C_TIMERS, CPU_I_TIMER_ST, "T2 (during SHUTDN)",
mod_status.hdw.t2_ctrl, mod_status.hdw.t2_val);
/* Determine which timer will expire first */
if(mod_status.hdw.t1_ctrl & (T1_CTRL_INT|T1_CTRL_WAKE))
{
/* T1 will do something on expiration */
mst = ((unsigned long)mod_status.hdw.t1_val + 1)
* T1_MS_MULTIPLIER;
debug2(DEBUG_C_TIMERS, CPU_I_TIMER_EXP, "T1", mst);
if(mst < ms) ms = mst;
}
if((mod_status.hdw.t2_ctrl & T2_CTRL_TRUN)
&& (mod_status.hdw.t2_ctrl & (T2_CTRL_INT|T2_CTRL_WAKE)))
{
/* T2 is running and will do something on expiration */
mst = ((unsigned long)mod_status.hdw.t2_val + 1)
/ T2_MS_DIVISOR;
debug2(DEBUG_C_TIMERS, CPU_I_TIMER_EXP, "T2", mst);
if(mst < ms) ms = mst;
}
/* Handle serial port activities at each iteration of
the outer idle loop; this ensures that the serial
port emulation will not starve.
*/
HandleSerial();
/* Enter idle loop, possibly with timeout;
The loop breaks when:
- any X Event occurs (possibly clearing the shutdown)
- the given timeout expires
*/
debug1(DEBUG_C_TIMERS, CPU_I_IDLE_X_LOOP, ms);
IdleXLoop(ms);
/* End of idle loop; compute actual elapsed time */
gettimeofday(&end_idle, NULL);
ela = (end_idle.tv_sec - start_idle.tv_sec) * 1000000 +
(end_idle.tv_usec - start_idle.tv_usec);
/* Update start_idle here to contain lag */
start_idle = end_idle;
debug1(DEBUG_C_TIMERS, CPU_I_ELAPSED, ela);
/* Update timers and act accordingly */
ela_ticks = ((ela+frac_t1) + T1_INTERVAL/2) / T1_INTERVAL;
frac_t1 = (ela+frac_t1) - ela_ticks * T1_INTERVAL;
if(ela_ticks > mod_status.hdw.t1_val)
{
debug1(DEBUG_C_TIMERS, CPU_I_TIMER1_EX,
mod_status.hdw.t1_ctrl);
mod_status.hdw.t1_ctrl |= T1_CTRL_SREQ;
if(mod_status.hdw.t1_ctrl & T1_CTRL_WAKE)
CpuWake();
if(mod_status.hdw.t1_ctrl & T1_CTRL_INT)
CpuIntRequest(INT_REQUEST_IRQ);
}
mod_status.hdw.t1_val =
(mod_status.hdw.t1_val - ela_ticks) & T1_OVF_MASK;
if(mod_status.hdw.t2_ctrl & T2_CTRL_TRUN)
{
ela_ticks = ((ela+frac_t2) + T2_INTERVAL/2) / T2_INTERVAL;
frac_t2 = (ela+frac_t2) - ela_ticks * T2_INTERVAL;
if(ela_ticks > mod_status.hdw.t2_val)
{
debug1(DEBUG_C_TIMERS, CPU_I_TIMER2_EX,
mod_status.hdw.t2_ctrl);
mod_status.hdw.t2_ctrl |= T2_CTRL_SREQ;
if(mod_status.hdw.t2_ctrl & T2_CTRL_WAKE)
CpuWake();
if(mod_status.hdw.t2_ctrl & T2_CTRL_INT)
CpuIntRequest(INT_REQUEST_IRQ);
}
mod_status.hdw.t2_val =
(mod_status.hdw.t2_val - ela_ticks) & T2_OVF_MASK;
}
}
debug3(DEBUG_C_TIMERS, CPU_I_TIMER_ST, "T1 (after SHUTDN)",
mod_status.hdw.t1_ctrl, mod_status.hdw.t1_val);
debug3(DEBUG_C_TIMERS, CPU_I_TIMER_ST, "T2 (after SHUTDN)",
mod_status.hdw.t2_ctrl, mod_status.hdw.t2_val);
act = CHF_CONTINUE;
}
break;
#endif
case CPU_I_EMULATOR_INT:
/* Emulator interrupt; unwind */
act = CHF_UNWIND;
break;
default:
/* Condition Code not handled; resignal */
act = CHF_RESIGNAL;
}
}
else
/* Condition from other modules; resignal */
act = CHF_RESIGNAL;
break;
default:
/* Other states; resignal the condition */
act = CHF_RESIGNAL;
break;
}
return act;
}
/*---------------------------------------------------------------------------
Public functions
---------------------------------------------------------------------------*/
/* .+
.title : Emulator
.kind : C function
.creation : 17-Feb-1998
.description :
This function implements the main emulator loop. For efficiency reasons,
it also emulates both T1 and T2 timers. Under normal conditions, this
function returns to the caller only when an emulator interrupt request
has been posted using EmulatorIntRequest().
The only way to exit this function (with a non-local jump) is to signal
a Chf Condition that triggers an unwind operation.
.call :
Emulator();
.input :
void
.output :
void
.status_codes :
CPU_I_CALLED
CPU_I_TIMER1_EX
CPU_I_TIMER2_EX
Other conditions signalled by lower level modules
.notes :
1.1, 17-Feb-1998, creation
.- */
void Emulator(void)
{
jmp_buf unwind_context;
debug1(DEBUG_C_TRACE, CPU_I_CALLED, "Emulator");
/* Setup unwind_context */
if(setjmp(unwind_context) == 0)
{
/* Push condition handler, with NULL context */
ChfPushHandler(EmulatorLoopHandler, &unwind_context, (ChfPointer)NULL);
/* Activate emulator loop */
EmulatorLoop();
}
else
{
/* Unwinding after an emulator interrupt */
}
}
/* .+
.title : EmulatorIntRequest
.kind : C function
.creation : 18-Feb-1998
.description :
This function posts an interrupt request for the running emulator loop.
The request will be satisfied as soon as possible and Emulator() will
return to the caller.
.call :
EmulatorIntRequest();
.input :
void
.output :
void
.status_codes :
*
.notes :
1.1, 18-Feb-1998, creation
.- */
void EmulatorIntRequest(void)
{
emulator_int_req = 1;
}
/* .+
.title : EmulatorInit
.kind : C function
.creation : 8-Sep-2000
.description :
This function initializes the cpu and modules emulator subsystems;
if the reset emulator option is set, a reset is forced on both
subsystems, too.
.call :
EmulatorInit();
.input :
void
.output :
void
.status_codes :
* Status codes signaled by CpuInit() and CpuReset()
* Status codes signaled by ModInit() and ModReset()
.notes :
2.1, 8-Sep-2000, creation
2.4, 12-Sep-2000, update
- invoke CpuInit() before ModInit() so that interrupt requests
generated by ModInit() are honored as they should.
3.2, 21-Sep-2000, update:
- now invoking ModSelectDescription(args.hw) to select and
register an appropriate module description table depending on
args.hw option.
.- */
void EmulatorInit(void)
{
/* Select a module description table */
ModSelectDescription(args.hw);
/* Initialize cpu and modules subsystems */
CpuInit();
ModInit();
/* Reset if appropriate */
if(args.reset)
{
CpuReset();
ModReset();
}
}
/* .+
.title : EmulatorExit
.kind : C function
.creation : 8-Sep-2000
.description :
This function prepares the emulator to exit. If 'opt' is SAVE_AND_EXIT,
it also attempts to save the emulator's state on mass storage. Notice
that this function never exits the application directly, but always
returns to the caller unless an unrecoverable error occurs.
.call :
EmulatorExit(opt);
.input :
enum ExitOption opt, emulator exit option
.output :
void
.status_codes :
* Status codes signaled by CpuSave() and ModSave()
.notes :
2.1, 8-Sep-2000, creation
.- */
void EmulatorExit(enum ExitOption opt)
{
switch(opt)
{
case SAVE_AND_EXIT:
/* Save state of cpu and modules subsystems */
ModSave();
CpuSave();
break;
default:
/* Default behavior; do nothing */
break;
}
}

525
flash49.c Normal file
View file

@ -0,0 +1,525 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: flash49.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HPxx emulator
.title : $RCSfile: flash49.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 25-Sep-2000
.keywords : *
.description :
This module emulates the Internal Flash Rom of the HP49.
References:
28F160S5/28F320S5 Data Sheet, by Intel Corp.
.include : config.h, machdep.h, cpu.h, modules.h flash49.h
.notes :
$Log: flash49.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:40 cibrario
Added/Replaced GPL header
Revision 3.5 2000/10/02 09:49:18 cibrario
Linux support:
- added a default case in StoreData()'s switch; this is cleaner, and
makes gcc happier.
Revision 3.3 2000/09/26 15:30:14 cibrario
*** empty log message ***
.- */
#ifndef lint
static char rcs_id[] = "$Id: flash49.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "flash49.h"
#include "debug.h"
#include "args.h"
#define CHF_MODULE_ID FLASH_CHF_MODULE_ID
#include <Chf.h>
/*---------------------------------------------------------------------------
Private Macro/Data type definitions
---------------------------------------------------------------------------*/
#define BLOCK_SIZE 0x10000
#define BLOCK_BASE_MASK 0xFFFF
#define ByteAddress(address) ((address) >> 1)
#define NibbleAddress(address) ((address) << 1)
#define BlockBase(address) ((address) & ~BLOCK_BASE_MASK)
#define IsOdd(address) ((address) & 0x1)
#define LowNibble(d) ((Nibble)((d) & NIBBLE_MASK))
#define HighNibble(d) ((Nibble)(((d) >> 4) & NIBBLE_MASK))
#define ShiftHigh(d) ((d) << 4)
/* Flash cycle types */
enum FlashCycle
{
FLASH_CYCLE_READ = 0,
FLASH_CYCLE_WRITE,
FLASH_CYCLE_N /* Total # of cycle types */
};
/* State transition function */
typedef int (*FlashF)
(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data);
/*---------------------------------------------------------------------------
Private state variables
---------------------------------------------------------------------------*/
/* External storage */
extern struct ModStatus_49 *mod_status_49;
static int r_buffer; /* Nibble buffer during read */
static int w_buffer; /* Nibble buffer during write */
static enum FlashState fsm_state; /* FSM state */
/* Write buffer */
#define WB_COUNT_MASK 0x1F
#define WB_SIZE 0x20
static int wb_count; /* Counter for Write to Buffer */
static int wb_cdown; /* Count down */
static XAddress wb_start; /* Start address for Write to Buffer */
static int wb[WB_SIZE]; /* Write buffer */
/*---------------------------------------------------------------------------
State transition private functions
---------------------------------------------------------------------------*/
/* This function is called by default for unhandled state transitions */
static int BadCommand(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
/* Unknown command: signal and reset state to FLASH_ST_READ_ARRAY */
ChfCondition FLASH_W_BAD_CMD, CHF_WARNING,
*state, cycle, address, data
ChfEnd;
ChfSignal();
*state = FLASH_ST_READ_ARRAY;
return 0; /* Dummy result */
}
/* This function is called to read the Flash Rom array */
static int ReadArray(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
/* Read a byte from the array; no state transitions */
return
mod_status_49->flash[NibbleAddress(address)]
| ShiftHigh(mod_status_49->flash[NibbleAddress(address)+1]);
}
/* This function is called to parse the first byte of any command */
static int ParseCommand(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
switch(data)
{
case FLASH_CMD_READ_ARRAY:
/* Transition to FLASH_ST_READ_ARRAY state */
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Read Array");
*state = FLASH_ST_READ_ARRAY;
break;
case FLASH_CMD_CLR_SR:
/* Clear status register; section 4.5 on Data Sheet.
The current implementation does nothing, because
the value of the status register is fixed. No state transitions.
*/
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Clear Status");
break;
case FLASH_CMD_WRITE_BUFFER:
/* Write to Buffer; section 4.8 on Data Sheet.
Transition to FLASH_ST_READ_XSR state.
*/
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Write to Buffer (start)");
*state = FLASH_ST_READ_XSR;
break;
case FLASH_CMD_READ_SR:
/* Read Status; section 4.4 on Data Sheet.
Transition to FLASH_ST_READ_SR state.
*/
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Read Status");
*state = FLASH_ST_READ_SR;
break;
case FLASH_CMD_BL_ERASE:
/* Block Erase; section 4.6 on Data Sheet.
Transition to FLASH_ST_BL_ERASE state.
Consistency of block addresses is not checked.
*/
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Erase Block (start)");
*state = FLASH_ST_BL_ERASE;
break;
default:
/* Unknown command; signal, ignore, keep current state. */
ChfCondition FLASH_W_BAD_CMD, CHF_WARNING,
*state, cycle, address, data
ChfEnd;
ChfSignal();
break;
}
return 0; /* No result; this is a write cycle */
}
/* This function returns to the caller the value of XSR */
static int ReadXSR(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
/* Return XSR status; a buffer is always available in the current
emulation scheme. Keep current state.
*/
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Read XSR");
return FLASH_XSR_WBS;
}
/* This function returns to the caller the value of SR */
static int ReadSR(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
/* Return SR status; the WSM executes in zero time in the current
emulation scheme. Keep current state.
*/
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Read SR");
return FLASH_SR_WSMS;
}
/* This function is called to store the WRITE_BUFFER byte count;
both wb_count and wb_cdown are set; StoreData() decrements the
latter, WriteConfirm() uses the former to determine how many bytes
must write to the Flash array.
*/
static int StoreCount(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
/* Store WRITE_BUFFER count; next state is FLASH_ST_WRITE_DATA */
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Write to Buffer (count)");
wb_count = wb_cdown = data & WB_COUNT_MASK;
*state = FLASH_ST_WRITE_DATA_1;
return 0; /* No result; this is a write cycle */
}
/* This function is called to store a byte into the write buffer.
The first write cycle also sets the buffer's base address (wb_start).
The function transitions to state FLASH_ST_WRITE_CONFIRM when all
bytes have been stored.
*/
static int StoreData(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
int index;
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Write to Buffer (data)");
/* Store WRITE_BUFFER data; the first write also stores the
buffer starting address.
*/
switch(*state)
{
case FLASH_ST_WRITE_DATA_1:
wb_start = address;
wb[0] = data;
*state = FLASH_ST_WRITE_DATA_N;
break;
case FLASH_ST_WRITE_DATA_N:
index = address - wb_start;
if(index < 0 || index >= WB_SIZE)
{
ChfCondition FLASH_W_BAD_ADDRESS, CHF_WARNING,
*state, cycle, address, data
ChfEnd;
ChfSignal();
}
else
wb[index] = data;
break;
default:
*state = FLASH_ST_READ_ARRAY;
break;
}
if(--wb_cdown < 0)
*state = FLASH_ST_WRITE_CONFIRM;
return 0; /* No result; this is a write cycle */
}
/* This function expects a Write to Buffer confirmation command
(FLASH_CMD_WRITE_BUFFER_2); if it is received, the write buffer
is copied into the Flash Rom array, otherwise the write cycle is
aborted. In both cases, the new state is FLASH_ST_READ_ARRAY.
*/
static int WriteConfirm(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Write to Buffer (end)");
/* Expect Write to Buffer confirmation code */
if(data == FLASH_CMD_WRITE_BUFFER_2)
{
int i;
/* Confirmation OK; write.
Remember that wb_count is the byte count MINUS 1.
*/
for(i=0; i<=wb_count; i++)
{
mod_status_49->flash[NibbleAddress(wb_start+i)]
= LowNibble(wb[i]);
mod_status_49->flash[NibbleAddress(wb_start+i)+1]
= HighNibble(wb[i]);
}
}
*state = FLASH_ST_READ_ARRAY;
return 0; /* No result */
}
/* If the FLASH_CMD_BL_ERASE_2 command is received, this function erases
the block pointed by the current address; otherwise the block erase
operation is aborted.
In both cases, the new state is FLASH_ST_READ_SR.
*/
static int BlockErase(enum FlashState *state, enum FlashCycle cycle,
XAddress address, int data)
{
debug1(DEBUG_C_FLASH, FLASH_I_FSM_OP, "Block Erase (end)");
/* Expect Write to Buffer confirmation code */
if(data == FLASH_CMD_BL_ERASE_2)
{
XAddress block_base = BlockBase(address);
int i;
/* Confirmation OK; erase */
for(i=0; i<BLOCK_SIZE; i++)
{
mod_status_49->flash[
NibbleAddress(block_base+i)] = (Nibble)0xF;
mod_status_49->flash[
NibbleAddress(block_base+i)+1] = (Nibble)0xF;
}
}
*state = FLASH_ST_READ_SR;
return 0; /* No result */
}
/*---------------------------------------------------------------------------
FSM state diagram; two-dimensional array of FlashF; each function
is invoked when the FSM is in a given state (first index), and
a particular cycle (second index) is requested.
---------------------------------------------------------------------------*/
static FlashF F[FLASH_ST_N][FLASH_CYCLE_N] =
{
{ ReadArray, ParseCommand }, /* FLASH_ST_READ_ARRAY */
{ ReadSR, ParseCommand }, /* FLASH_ST_READ_SR */
{ ReadXSR, StoreCount }, /* FLASH_ST_READ_XSR */
{ BadCommand, StoreData }, /* FLASH_ST_WRITE_DATA_1 */
{ BadCommand, StoreData }, /* FLASH_ST_WRITE_DATA_N */
{ BadCommand, WriteConfirm }, /* FLASH_ST_WRITE_CONFIRM */
{ BadCommand, BlockErase } /* FLASH_ST_BL_ERASE */
};
/*---------------------------------------------------------------------------
Other private functions
---------------------------------------------------------------------------*/
/* This function invokes the FSM to execute the given 'cycle',
with 'address' and 'data' as arguments. Returns the
result of the FSM, if any.
*/
static int FSM(enum FlashCycle cycle, XAddress address, int data)
{
int result;
debug2(DEBUG_C_FLASH, FLASH_I_FSM, fsm_state, cycle);
debug2(DEBUG_C_FLASH, FLASH_I_FSM_AD, address, data);
result = F[fsm_state][cycle](&fsm_state, cycle, address, data);
debug2(DEBUG_C_FLASH, FLASH_I_FSM_RESULT, fsm_state, result);
return result;
}
/*---------------------------------------------------------------------------
Public functions
---------------------------------------------------------------------------*/
/* .+
.title : FlashRead49
.kind : C function
.creation : 25-Sep-2000
.description :
This function reads the nibble @address from Flash Rom and returns it
to the caller.
This function DOES NOT supports even/odd nibble accesses at non-contiguous
addresses.
.call :
n = FlashRead49(address);
.input :
XAddress address
.output :
Nibble n
.status_codes :
FLASH_I_READ
FLASH_I_FSM_OP
FLASH_W_BAD_CMD
.notes :
3.3, 25-Sep-2000, creation
.- */
Nibble FlashRead49(XAddress address)
{
Nibble result;
if(IsOdd(address))
/* Odd address, return buffered data from previous read */
result = HighNibble(r_buffer);
else
{
/* Even address, invoke FSM */
r_buffer = FSM(FLASH_CYCLE_READ, ByteAddress(address), 0);
result = LowNibble(r_buffer);
}
debug2(DEBUG_C_TRACE|DEBUG_C_FLASH, FLASH_I_READ, address, result);
return result;
}
/* .+
.title : FlashWrite49
.kind : C function
.creation : 25-Sep-2000
.description :
This function writes nibble datum @address into Flash Rom.
This function DOES NOT supports even/odd nibble accesses at non-contiguous
addresses.
.call :
FlashWrite49(address, datum);
.input :
XAddress address
Nibble datum
.output :
void
.status_codes :
FLASH_I_WRITE
FLASH_I_FSM_OP
FLASH_W_BAD_CMD
FLASH_W_BAD_ADDRESS
.notes :
3.3, 25-Sep-2000, creation
.- */
void FlashWrite49(XAddress address, Nibble datum)
{
debug2(DEBUG_C_TRACE|DEBUG_C_FLASH, FLASH_I_WRITE, address, datum);
if(IsOdd(address))
/* Odd address, invoke FSM; ignore result */
FSM(FLASH_CYCLE_WRITE, ByteAddress(address),
w_buffer|ShiftHigh(datum));
else
/* Even address, buffer datum */
w_buffer = datum;
}

164
flash49.h Normal file
View file

@ -0,0 +1,164 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: flash49.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HPxx emulator
.title : $RCSfile: flash49.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 25-Sep-2000
.keywords : *
.description :
This header contains all definitions and declarations related to the
Internal Flash ROM emulation module of the HP49. References:
Known deficiencies of the current Flash ROM emulation:
- some (many) commands are not emulated, even BCS ones.
- program/erase times are not emulated
- suspension is not supported
References:
28F160S5/28F320S5 Data Sheet, by Intel Corp.
.include : config.h machdep.h cpu.h modules.h
.notes :
$Log: flash49.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:41 cibrario
Added/Replaced GPL header
Revision 3.3 2000/09/26 15:30:07 cibrario
*** empty log message ***
.- */
/*---------------------------------------------------------------------------
Macro/Data type definitions
---------------------------------------------------------------------------*/
#define FLASH49_RCS_INFO "$Revision: 4.1 $ $State: Rel $"
/* Command Set Definitions, Table 3 on Data Sheet.
Both BCS and SCS commands are listed here; commands marked with
(*) are not implemented.
The last fixed byte of multibyte commands has a '_2' suffix.
*/
#define FLASH_CMD_READ_ARRAY 0xFF /* BCS */
#define FLASH_CMD_READ_ID 0x90 /* BCS (*) */
#define FLASH_CMD_READ_QUERY 0x98 /* SCS (*) */
#define FLASH_CMD_READ_SR 0x70 /* BCS */
#define FLASH_CMD_CLR_SR 0x50 /* BCS */
#define FLASH_CMD_WRITE_BUFFER 0xE8 /* SCS */
# define FLASH_CMD_WRITE_BUFFER_2 0xD0
#define FLASH_CMD_BW_PGM 0x40 /* BCS (*) */
#define FLASH_CMD_BW_PGM_ALT 0x10 /* BCS, alternate (*) */
#define FLASH_CMD_BL_ERASE 0x20 /* BCS */
# define FLASH_CMD_BL_ERASE_2 0xD0
#define FLASH_CMD_SUSPEND 0xB0 /* BCS (*) */
#define FLASH_CMD_RESUME 0xD0 /* BCS (*) */
#define FLASH_CMD_STS_CONFIG 0xB8 /* SCS (*) */
#define FLASH_CMD_BL_LB 0x60 /* SCS (*) */
# define FLASH_CMD_BL_LB_SET 0x01
# define FLASH_CMD_BL_LB_CLR 0xD0
#define FLASH_CMD_CHIP_ERASE 0x30 /* SCS (*) */
# define FLASH_CMD_CHIP_ERASE_2 0xD0
/* Status Register bit masks, Table 15 on Data Sheet
*/
#define FLASH_SR_WSMS 0x80 /* WSM state, 0=busy, 1=ready */
#define FLASH_SR_ESS 0x40 /* Erase suspend, 1=suspended */
#define FLASH_SR_ECLBS 0x20 /* 1=Error during erasure */
#define FLASH_SR_BWSLBS 0x10 /* 1=Error during program */
#define FLASH_SR_VPPS 0x08 /* 1=Vpp error */
#define FLASH_SR_BWSS 0x04 /* Program suspend, 1=suspended */
#define FLASH_SR_DPS 0x02 /* 1=Lock encountered */
/* Extended Status Register bit masks, Table 16 on Data Sheet
*/
#define FLASH_XSR_WBS 0x80 /* Write buffer status 1=available */
/* State of the Flash FSM, derived from command descriptions on
pages 16...28 and from flowcharts on Figure 6...12 of Data Sheet
*/
enum FlashState
{
FLASH_ST_READ_ARRAY = 0, /* Read Array after CMD_READ_ARRAY */
FLASH_ST_READ_SR, /* Read Status Reg. after CMD_READ_SR */
FLASH_ST_READ_XSR, /* Read XSR after CMD_WRITE_BUFFER */
FLASH_ST_WRITE_DATA_1, /* Write data after ST_WRITE_COUNT */
FLASH_ST_WRITE_DATA_N, /* Write data after first write */
FLASH_ST_WRITE_CONFIRM, /* Write confirmation after (ST_WRITE_DATA)* */
FLASH_ST_BL_ERASE, /* Block erase started */
FLASH_ST_N /* Total # of FSM states */
};
/*---------------------------------------------------------------------------
Chf condition codes
---------------------------------------------------------------------------*/
#define FLASH_I_READ 101 /* Read from address %x: %d */
#define FLASH_I_WRITE 102 /* Write address %x, datum %x */
#define FLASH_I_FSM 103 /* FSM from state %d, cycle %d */
#define FLASH_I_FSM_AD 104 /* FSM address %x, data %x */
#define FLASH_I_FSM_RESULT 105 /* FSM next state %d, result %x */
#define FLASH_I_FSM_OP 106 /* FSM operation %s */
#define FLASH_W_BAD_CMD 201 /* Bad cmd st%d, cycle%d, a%x, d%d */
#define FLASH_W_BAD_ADDRESS 202 /* Bad addr st%d, cycle%d, a%x, d%d */
#define FLASH_E_xxx 301
#define FLASH_F_xxx 401
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/* Read/Write operations, nibble-by-nibble */
Nibble FlashRead49(XAddress address);
void FlashWrite49(XAddress address, Nibble datum);

38
flash49.msf Normal file
View file

@ -0,0 +1,38 @@
$ .+
$ .identifier : $Id: flash49.msf,v 4.1 2000/12/11 09:54:19 cibrario Rel $
$ .context : SATURN, Saturn CPU / HPxx emulator
$ .title : $RCSfile: flash49.msf,v $
$ .kind : Message catalog source
$ .author : Ivan Cibrario B.
$ .site : CSTV-CNR
$ .creation : 25-Sep-2000
$ .keywords : *
$ .description :
$ Message catalog source file for the flash rom emulator.
$ .notes :
$ . $Log: flash49.msf,v $
$ . Revision 4.1 2000/12/11 09:54:19 cibrario
$ . Public release.
$ .
$ . Revision 3.8 2000/10/19 15:00:41 cibrario
$ . Bug fix:
$ . Removed lines with empty directives
$ .
$ Revision 3.3 2000/09/26 15:30:28 cibrario
$ *** empty log message ***
$ .-
$set 1
16 Flash
$set 16
101 Read (Nibble) A[%08X] D[%01X]
102 Write (Nibble) A[%08X] D[%01X]
103 FSM STATE[%d] CYCLE[%d]
104 \tFSM Args: (Byte)A[%08X] D[%02X]
105 \tFSM Next: STATE[%d] RESULT[%02X]
106 \tFSM Operation: [%s]
201 Command unknown/not implemented - FSM Info:\n\
\tSTATE[%d] CYCLE[%d] A[%08X] D[%02X]
202 Invalid address in Write to Buffer - FSM Info:\n\
\tSTATE[%d] CYCLE[%d] A[%08X] D[%02X]

392
gpl.texi Normal file
View file

@ -0,0 +1,392 @@
@node GNU GENERAL PUBLIC LICENSE, Concept Index, Tips Tricks and Known Bugs, Top
@unnumbered GNU GENERAL PUBLIC LICENSE
@center Version 2, June 1991
@c This file is intended to be included in another file.
@display
Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@end display
@unnumberedsec Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software---to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
@iftex
@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@end iftex
@ifinfo
@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@end ifinfo
@enumerate 0
@item
This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The ``Program'', below,
refers to any such program or work, and a ``work based on the Program''
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term ``modification''.) Each licensee is addressed as ``you''.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
@item
You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
@item
You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
@enumerate a
@item
You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
@item
You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
@item
If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
@end enumerate
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
@item
You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
@enumerate a
@item
Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
@item
Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
@item
Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
@end enumerate
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
@item
You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
@item
You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
@item
Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
@item
If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
@item
If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
@item
The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and ``any
later version'', you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
@item
If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
@iftex
@heading NO WARRANTY
@end iftex
@ifinfo
@center NO WARRANTY
@end ifinfo
@item
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
@item
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
@end enumerate
@iftex
@heading END OF TERMS AND CONDITIONS
@end iftex
@ifinfo
@center END OF TERMS AND CONDITIONS
@end ifinfo
@page
@unnumberedsec Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the ``copyright'' line and a pointer to where the full notice is found.
@smallexample
@var{one line to give the program's name and a brief idea of what it does.}
Copyright (C) 19@var{yy} @var{name of author}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@end smallexample
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
@smallexample
Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@end smallexample
The hypothetical commands @samp{show w} and @samp{show c} should show
the appropriate parts of the General Public License. Of course, the
commands you use may be called something other than @samp{show w} and
@samp{show c}; they could even be mouse-clicks or menu items---whatever
suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a ``copyright disclaimer'' for the program, if
necessary. Here is a sample; alter the names:
@example
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
@var{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
@end example
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

78
gpl_replace Executable file
View file

@ -0,0 +1,78 @@
#!/bin/csh
#
# $Id: gpl_replace,v 4.1 2000/12/11 09:54:19 cibrario Rel $
#
# This script adds/replaces the GPL header $gpl_template in
# all .c and .h files in the RCS repository. Must be executed on
# a clean (no locked files) repository.
#
# Arguments:
#
# argv[1]: -r argument to ci
# argv[2]: -m argument to ci, default provided
if( $#argv < 1 ) then
echo "gpl_replace: missing target release number"
exit 1
endif
if( $#argv == 1 ) then
set argv = ($argv "Added/Replaced GPL header")
endif
set gpl_template = gpl_template
set rcs_flist = `ls RCS/*.[ch],v`
set exit_code = 0
co $gpl_template
if( $status != 0 ) then
echo "gpl_replace: co ${gpl_template} failed"
exit 9
endif
foreach rcs_file ($rcs_flist)
set file = `basename $rcs_file ,v`
set s_file = "${file}_s"
set j_file = "${file}_j"
set b_file = "${file}_b"
# Extract file from repository
co -l $file
if( $status != 0 ) then
echo "gpl_replace: ${file}: checkout failed; edit manually"
set exit_code = 2
continue
endif
sed -e '/.*+-+.*/,$\!d' $file > $s_file
if( -z $s_file ) then
# File does not contain the template yet; add
cat $gpl_template - $file > $j_file <<EOF
/* +-+ */
EOF
else
# File did contain an older template; replace
cat $gpl_template - $s_file > $j_file <<EOF
EOF
endif
rm $s_file
mv $file $b_file
mv $j_file $file
ci -r$argv[1] -m"$argv[2]" $file
# Remove backup file only if update was ok
if( $status == 0 ) then
rm $b_file
else
echo "gpl_replace: ${file}: ci failed; backup in ${b_file}"
rcs -u $file
set exit_code = 3
continue
endif
end
exit $exit_code

30
gpl_template Normal file
View file

@ -0,0 +1,30 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */

565
hdw.c Normal file
View file

@ -0,0 +1,565 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: hdw.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: hdw.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 23-Jan-1998
.keywords : *
.description :
This module emulates the Hdw peripheral module, that controls all
peripheral devices of the HP48. The Hdw Read/Write functions simply update
the contents of the mod_status.hdw structure to reflect the contents of the
actual Hdw registers. The actual emulation of the devices is performed
by other source modules. References:
SASM.DOC by HP (HORN disk 4)
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
x48 source code by Eddie C. Dost (ecd@dressler.de)
.include : config.h, machdep.h, cpu.h, modules.h
.notes :
$Log: hdw.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.13 2000/11/09 11:32:05 cibrario
Revised to add file selection box GUI element, CPU halt/run
requests and emulator's extended functions:
- Added code to trampoline to ExtendedFunction() when the calculator
writes something into the lower nibble of the serial port's
Receiver Buffer Register.
Revision 3.10 2000/10/24 16:14:42 cibrario
Added/Replaced GPL header
Revision 3.2 2000/09/22 13:46:30 cibrario
Implemented preliminary support of HP49 hw architecture:
- The HP49 firmware (1.19-4) reads a nibble from 0x30 for unknown reasons;
conditionally (#ifdef HP49_SUPPORT) enabled reads from relative
addresses 0x30..0x34 without signaling a warning.
* Revision 3.1 2000/09/20 13:48:52 cibrario
* Minor updates and fixes to avoid gcc compiler warnings on Solaris
* when -ansi -pedantic -Wall options are selected.
*
* Revision 2.5 2000/09/14 15:08:59 cibrario
* Update HdwRead() and HdwWrite() to support serial port emulation;
* read/write from/to serial port register are mapped into invocation
* of functions in the serial port emulation module. This module
* merely provides buffering for multi-nibble hdw registers.
*
* Revision 2.4 2000/09/12 15:24:27 cibrario
* Bug fix and update required to implement emulation of Port 1 and 2:
* - fixed an improper memset() call in HdwInit()
* - HdwRead() now returns the value of mod_status.hdw_card_status when
* relative address 0x0F is read from.
*
* Revision 1.1 1998/02/17 11:49:59 cibrario
* Initial revision
*
.- */
#ifndef lint
static char rcs_id[] = "$Id: hdw.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h> /* 3.1: memset() */
#include <errno.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "disk_io.h"
#include "serial.h" /* 2.5: Serial port emulation module */
#include "x_func.h" /* 3.13: Extended emulator functions */
#include "debug.h"
#include "args.h"
#define CHF_MODULE_ID MOD_CHF_MODULE_ID
#include <Chf.h>
static const int addr_mask[] = { 0x0000F, 0x000F0, 0x00F00, 0x0F000, 0xF0000 };
static const int32 int32_mask[] =
{ 0x0000000F, 0x000000F0, 0x00000F00, 0x0000F000,
0x000F0000, 0x00F00000, 0x0F000000, 0xF0000000 };
/* .+
.title : HdwInit
.kind : C function
.creation : 23-Jan-1998
.description :
This function initializes the Hdw module, restoring the status of the
peripheral devices associated to it from disk.
.call :
HdwInit();
.input :
void
.output :
void
.status_codes :
MOD_I_CALLED
MOD_W_HDW_INIT
.notes :
1.1, 23-Jan-1998, creation
2.4, 11-Sep-2000, bug fix:
memset() invocation was improper, and could lead to memory corruption
.- */
void HdwInit(void)
{
debug1(DEBUG_C_TRACE, MOD_I_CALLED, "HdwInit");
if(ReadStructFromFile(args.hdw_file_name, sizeof(mod_status.hdw),
&mod_status.hdw))
{
ChfCondition MOD_W_HDW_INIT, CHF_WARNING ChfEnd;
ChfSignal();
(void)memset(&mod_status.hdw, 0, sizeof(mod_status.hdw));
}
}
/* .+
.title : HdwSave
.kind : C function
.creation : 11-Feb-1998
.description :
This function saves the current status of the peripheral devices associated
to the Hdw module to disk.
.call :
HdwSave();
.input :
void
.output :
void
.status_codes :
MOD_I_CALLED
MOD_E_HDW_SAVE
.notes :
1.1, 11-Feb-1998, creation
.- */
void HdwSave(void)
{
debug1(DEBUG_C_TRACE, MOD_I_CALLED, "HdwSave");
if(WriteStructToFile(&mod_status.hdw, sizeof(mod_status.hdw),
args.hdw_file_name))
{
ChfCondition MOD_E_HDW_SAVE, CHF_ERROR ChfEnd;
ChfSignal();
}
}
/* .+
.title : HdwRead
.kind : C function
.creation : 23-Jan-1998
.description :
This function reads a nibble from the Hdw module.
.call :
d = HdwRead(rel_address);
.input :
Address rel_address, relative address
.output :
Nibble d, data
.status_codes :
MOD_I_CALLED
MOD_W_HDW_READ
.notes :
1.1, 23-Jan-1998, creation
2.4, 11-Sep-2000, update
- read from rel_address 0x0F now returns the current value of
mod_status.hdw.card_status; its value is set during the
initialization of other peripheral modules.
2.5, 14-Sep-2000, update
- added support for serial port emulation
.- */
Nibble HdwRead(Address rel_address)
{
debug1(DEBUG_C_TRACE, MOD_I_CALLED, "HdwRead");
/* In the following switch, each case corresponds to one hdw register.
If the register must be read from the shadow space mod_status.hdw.hdw[],
simply put a break in the case, otherwise code any special action for
the register and end the case with a return.
*/
switch(rel_address)
{
case 0x00: /* LCD driver registers */
case 0x01:
case 0x02:
case 0x03:
case 0x0B:
case 0x0C:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
break;
case 0x04: /* CRC register */
case 0x05:
case 0x06:
case 0x07:
return (Nibble)((mod_status.hdw.crc >> ((rel_address-0x04)*4)) & 0x0F);
case 0x08: /* Power status */
/* No power status related interrupt have occoured */
return (Nibble)0;
case 0x09: /* Power control */
break;
case 0x0D: /* Serial port baud-rate register */
break;
case 0x10: /* Serial port interrupt and I/O control register */
return Serial_IOC_Read();
case 0x11: /* Serial port receiver control/status register */
return Serial_RCS_Read();
case 0x12: /* Serial port transmitter control/status register */
return Serial_TCS_Read();
/* Serial port receiver buffer register; the actual read takes place
when the LS nibble is read; serial_rbr buffers the MS nibble.
*/
case 0x14:
return (mod_status.hdw.serial_rbr = Serial_RBR_Read()) & 0x0F;
case 0x15:
return (mod_status.hdw.serial_rbr >> 4) & 0x0F;
case 0x0E: /* Card interface */
break;
case 0x0F: /* Card interface */
/* 2.4: Return current card status */
return mod_status.hdw.card_status;
case 0x18: /* Service request */
case 0x19:
break;
case 0x1A: /* IR registers */
case 0x1C:
case 0x1D:
break;
case 0x1B: /* Base nibble offset */
break;
case 0x1E: /* Scratch pad */
break;
case 0x1F: /* Base Nibble */
break;
case 0x2E: /* Timer 1 Control */
return mod_status.hdw.t1_ctrl;
case 0x2F: /* Timer 2 Control */
return mod_status.hdw.t2_ctrl;
#ifdef HP49_SUPPORT
/* 3.2: The HP49 firmware (1.19-4) reads a nibble from 0x30 */
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
return (Nibble)0x0;
#endif
case 0x37: /* Timer 1 value */
return mod_status.hdw.t1_val;
case 0x38: /* Timer 2 value */
case 0x39:
case 0x3A:
case 0x3B:
case 0x3C:
case 0x3D:
case 0x3E:
case 0x3F:
return
(Nibble)((mod_status.hdw.t2_val >> ((rel_address-0x38)*4)) & 0x0F);
default:
ChfCondition MOD_W_HDW_READ, CHF_WARNING, rel_address ChfEnd;
ChfSignal();
return (Nibble)0xF;
}
/* Read from hdw register array */
return mod_status.hdw.hdw[rel_address];
}
/* .+
.title : HdwWrite
.kind : C function
.creation : 23-Jan-1998
.description :
This function writes a nibble to the Hdw module.
.call :
HdwWrite(rel_address, data);
.input :
Address rel_address, relative address
Nibble data, data to be written
.output :
void
.status_codes :
MOD_I_CALLED
MOD_W_HDW_WRITE
.notes :
1.1, 23-Jan-1998, creation
2.5, 14-Sep-2000, update
- added support for serial port emulation
.- */
void HdwWrite(Address rel_address, Nibble data)
{
debug1(DEBUG_C_TRACE, MOD_I_CALLED, "HdwWrite");
/* This switch has a case for each 'known' hdw register. The code inside the
case performs the actions specific for that register; the code following
the switch, instead, simply takes care to shadow the hdw register into
the mod_status.hdw.hdw[] array
*/
switch(rel_address)
{
case 0x00: /* LCD horizontal offset, LCD enable flag */
mod_status.hdw.lcd_offset = (int)data & 0x07;
mod_status.hdw.lcd_on = ((data & 0x08) != 0);
break;
case 0x01: /* LCD contrast, LS nibble */
mod_status.hdw.lcd_contrast &= 0x10;
mod_status.hdw.lcd_contrast |= (int)data;
break;
case 0x02: /* LCD contrast, MS bit */
mod_status.hdw.lcd_contrast &= 0x0F;
mod_status.hdw.lcd_contrast |= (((int)data & 0x01) << 4);
break;
case 0x03: /* LCD test control */
break;
case 0x04: /* CRC register */
case 0x05:
case 0x06:
case 0x07:
mod_status.hdw.crc &= ~addr_mask[rel_address-0x04];
mod_status.hdw.crc |= ((int)data << ((rel_address-0x04)*4));
break;
case 0x08: /* Power status and power control */
case 0x09:
break;
case 0x0B: /* LCD annunciator control (low nibble) */
mod_status.hdw.lcd_ann &= 0xF0;
mod_status.hdw.lcd_ann |= (int)data;
break;
case 0x0C: /* LCD annunciator control (high nibble) */
mod_status.hdw.lcd_ann &= 0x0F;
mod_status.hdw.lcd_ann |= ((int)data << 4);
break;
case 0x0D: /* Serial port baud rate */
break;
case 0x0E: /* Card interface */
case 0x0F:
break;
case 0x10: /* Serial port interrupt and I/O control/status */
Serial_IOC_Write(data);
break;
case 0x11: /* Serial port receiver control/status register */
Serial_RCS_Write(data);
break;
case 0x12: /* Serial port transmitter control/status register */
Serial_TCS_Write(data);
break;
case 0x13: /* Clear serial port receive error */
Serial_CRER_Write(data);
break;
/* 3.13: A write operation into the receiver buffer register
triggers an extended emulator function.
*/
case 0x14:
ExtendedFunction(data);
break;
/* Serial port transmitter buffer; the actual write takes place
when the MS nibble is written; serial_tbr buffers the LS nibble.
*/
case 0x16:
mod_status.hdw.serial_tbr =
(mod_status.hdw.serial_tbr & 0xF0) | (int8)data;
break;
case 0x17:
mod_status.hdw.serial_tbr =
(mod_status.hdw.serial_tbr & 0x0F) | ((int8)data << 4);
Serial_TBR_Write(mod_status.hdw.serial_tbr);
break;
case 0x18: /* Service request */
case 0x19:
break;
case 0x1A: /* IR Control Register */
break;
case 0x1B: /* Base nibble offset */
break;
case 0x1C: /* IR Status Register */
break;
case 0x1D: /* IR Led Buffer */
break;
case 0x1E: /* Scratch Pad */
break;
case 0x1F: /* Base Nibble */
break;
case 0x20: /* LCD base address register (write only) */
case 0x21:
case 0x22:
case 0x23:
case 0x24:
mod_status.hdw.lcd_base_addr &= ~addr_mask[rel_address-0x20];
mod_status.hdw.lcd_base_addr |= ((int)data << ((rel_address-0x20)*4));
break;
case 0x25: /* LCD line offset register */
case 0x26:
case 0x27:
mod_status.hdw.lcd_line_offset &= ~addr_mask[rel_address-0x25];
mod_status.hdw.lcd_line_offset |= ((int)data << ((rel_address-0x25)*4));
break;
case 0x28: /* LCD vertical line count (low nibble) */
mod_status.hdw.lcd_vlc &= 0x30;
mod_status.hdw.lcd_vlc |= (int)data;
break;
case 0x29: /* LCD vertical line count (higher 2 bits), others (TBD) */
mod_status.hdw.lcd_vlc &= 0x0F;
mod_status.hdw.lcd_vlc |= (((int)data & 0x03) << 4);
case 0x2E: /* Timer 1 Control */
mod_status.hdw.t1_ctrl = data;
break;
case 0x2F: /* Timer 2 Control */
mod_status.hdw.t2_ctrl = data;
break;
case 0x30: /* LCD menu address register (write only) */
case 0x31:
case 0x32:
case 0x33:
case 0x34:
mod_status.hdw.lcd_menu_addr &= ~addr_mask[rel_address-0x30];
mod_status.hdw.lcd_menu_addr |= ((int)data << ((rel_address-0x30)*4));
break;
case 0x37: /* Timer 1 value */
mod_status.hdw.t1_val = data;
break;
case 0x38: /* Timer 2 value */
case 0x39:
case 0x3A:
case 0x3B:
case 0x3C:
case 0x3D:
case 0x3E:
case 0x3F:
mod_status.hdw.t2_val &= ~int32_mask[rel_address-0x38];
mod_status.hdw.t2_val |= ((int32)data << ((rel_address-0x38)*4));
break;
default:
ChfCondition MOD_W_HDW_WRITE, CHF_WARNING, rel_address, (int)data ChfEnd;
ChfSignal();
}
/* Save copy into hdw register array */
mod_status.hdw.hdw[rel_address] = data;
}

317
hw_config.c Normal file
View file

@ -0,0 +1,317 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: hw_config.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HPxx emulator
.title : $RCSfile: hw_config.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 21-Sep-2000
.keywords : *
.description :
This module contains the module description tables for all HPxx
hardware configurations currently supported. Moreover, it implements
the function ModSelectDescription(hw), to select and register a
module description table depending on an hardware configuration
selection string (hw). References:
Guide to the Saturn Processor Rev. 1.0b by Matthew Mastracci
HP49 Memory Explained, USENET post, by Steve Sousa.
.include : config.h machdep.h, cpu.h, modules.h
.notes :
$Log: hw_config.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:43 cibrario
Added/Replaced GPL header
Revision 3.3 2000/09/26 15:18:16 cibrario
Revised to implement Flash ROM write access:
- updated description of ModDescription table components
- the HP49 NCE3 controller now has MOD_MAP_FLAGS_ABS set in .map_flags
* Revision 3.2 2000/09/22 14:40:18 cibrario
* *** empty log message ***
*
.- */
#ifndef lint
static char rcs_id[] = "$Id: hw_config.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "debug.h"
#define CHF_MODULE_ID MOD_CHF_MODULE_ID
#include <Chf.h>
/*---------------------------------------------------------------------------
Module description tables
---------------------------------------------------------------------------*/
extern void RomInit(void);
extern void HdwInit(void);
extern void RamInit(void);
extern void Ce1Init(void);
extern void Ce2Init(void);
extern void NCe3Init(void);
extern void RomSave(void);
extern void HdwSave(void);
extern void RamSave(void);
extern void Ce1Save(void);
extern void Ce2Save(void);
extern void NCe3Save(void);
extern Nibble RomRead(Address);
extern Nibble HdwRead(Address);
extern Nibble RamRead(Address);
extern Nibble Ce1Read(Address);
extern Nibble Ce2Read(Address);
extern Nibble NCe3Read(Address);
extern void RomWrite(Address, Nibble);
extern void HdwWrite(Address, Nibble);
extern void RamWrite(Address, Nibble);
extern void Ce1Write(Address, Nibble);
extern void Ce2Write(Address, Nibble);
extern void NCe3Write(Address, Nibble);
extern void RomInit49(void);
extern void HdwInit49(void);
extern void RamInit49(void);
extern void Ce1Init49(void);
extern void Ce2Init49(void);
extern void NCe3Init49(void);
extern void RomSave49(void);
extern void HdwSave49(void);
extern void RamSave49(void);
extern void Ce1Save49(void);
extern void Ce2Save49(void);
extern void NCe3Save49(void);
extern Nibble RomRead49(Address);
extern Nibble HdwRead49(Address);
extern Nibble RamRead49(Address);
extern Nibble Ce1Read49(Address);
extern Nibble Ce2Read49(Address);
extern Nibble NCe3Read49(Address);
extern void RomWrite49(Address, Nibble);
extern void HdwWrite49(Address, Nibble);
extern void RamWrite49(Address, Nibble);
extern void Ce1Write49(Address, Nibble);
extern void Ce2Write49(Address, Nibble);
extern void NCe3Write49(Address, Nibble);
static const struct
{
const char *hw;
ModDescription description;
}
table[] =
{
/*---------------------------------------------------------------------------
HP48
---------------------------------------------------------------------------*/
{
"hp48",
{
/* name, id, access_prio,
init, save,
read, write,
r_config, r_abs_base_addr, r_size,
map_flags
*/
{ "ROM (ROM)", 0x00, 0,
RomInit, RomSave,
RomRead, RomWrite,
MOD_CONFIGURED, 0x00000, 0xFFFFF,
},
{ "Hardware Regs. (HDW)", 0x19, 5,
HdwInit, HdwSave,
HdwRead, HdwWrite,
MOD_SIZE_CONFIGURED, 0x00000, 0x00040,
},
{ "Internal RAM (RAM)", 0x03, 4,
RamInit, RamSave,
RamRead, RamWrite,
MOD_UNCONFIGURED, 0, 0,
},
{ "Bank Select (CE1)", 0x05, 2,
Ce1Init, Ce1Save,
Ce1Read, Ce1Write,
MOD_UNCONFIGURED, 0, 0,
},
{ "Port 1 Control (CE2)", 0x07, 3,
Ce2Init, Ce2Save,
Ce2Read, Ce2Write,
MOD_UNCONFIGURED, 0, 0,
},
{ "Port 2 Control (NCE3)", 0x01, 1,
NCe3Init, NCe3Save,
NCe3Read, NCe3Write,
MOD_UNCONFIGURED, 0, 0,
}
}},
/*---------------------------------------------------------------------------
HP49
---------------------------------------------------------------------------*/
{
"hp49",
{
/* name, id, access_prio,
init, save,
read, write,
r_config, r_abs_base_addr, r_size,
map_flags
*/
{ "ROM (ROM)", 0x00, 0,
RomInit49, RomSave49,
RomRead49, RomWrite49,
MOD_CONFIGURED, 0x00000, 0xFFFFF,
},
{ "Hardware Regs. (HDW)", 0x19, 5,
HdwInit, HdwSave,
HdwRead, HdwWrite,
MOD_SIZE_CONFIGURED, 0x00000, 0x00040,
},
{ "IRAM (RAM)", 0x03, 4,
RamInit49, RamSave49,
RamRead49, RamWrite49,
MOD_UNCONFIGURED, 0, 0,
},
{ "Bank Select (CE1)", 0x05, 2,
Ce1Init49, Ce1Save49,
Ce1Read49, Ce1Write49,
MOD_UNCONFIGURED, 0, 0,
},
{ "ERAM Bank 0 (CE2)", 0x07, 3,
Ce2Init49, Ce2Save49,
Ce2Read49, Ce2Write49,
MOD_UNCONFIGURED, 0, 0,
},
{ "ERAM Bank 1 (NCE3)", 0x01, 1,
NCe3Init49, NCe3Save49,
NCe3Read49, NCe3Write49,
MOD_UNCONFIGURED, 0, 0,
MOD_MAP_FLAGS_ABS
}
}}
};
#define N_DESCRIPTIONS (sizeof(table)/sizeof(table[0]))
/*---------------------------------------------------------------------------
Public functions
---------------------------------------------------------------------------*/
/* .+
.title : ModSelectDescription
.kind : C function
.creation : 21-Sep-2000
.description :
This function selects and registers (invoking ModRegisterDescription())
a module description table depending on the hardware configuration
string passed as argument.
.call :
ModSelectDescription(hw)
.input :
const char *hw, hardware configuration string
.output :
void
.status_codes :
MOD_I_CALLED
MOD_E_NO_MATCH
.notes :
1.1, 28-Jan-1998, creation
.- */
void ModSelectDescription(const char *hw)
{
int i;
debug1(DEBUG_C_TRACE, MOD_I_CALLED, "ModSelectDescription");
for(i=0; i<N_DESCRIPTIONS && strcmp(hw, table[i].hw); i++);
if(i==N_DESCRIPTIONS)
{
ChfCondition MOD_E_NO_MATCH, CHF_ERROR, hw ChfEnd;
ChfSignal();
}
else
ModRegisterDescription(table[i].description);
}

128
introd.texi Normal file
View file

@ -0,0 +1,128 @@
@c $Id: introd.texi,v 4.1 2000/12/11 09:54:19 cibrario Rel $
@node Introduction and License Conditions, Preparing saturn for Use, Top, Top
@chapter Introduction and License Conditions
@cindex Introduction
@cindex License Conditions
The @code{saturn} software is a poor-man's emulator of the HP48GX, HP49,
and HP40 calculators made by Hewlett-Packard. It should compile and run
on any recent, XPG4-UNIX compliant, Unix-like system with a working X
Window System interface and OSF/Motif-compatible libraries. For
example, @code{saturn} is known to work on the following systems:
@itemize @bullet
@item
Digital UNIX V4.0D on a Digital AlphaStation 200 4/100
@item
Solaris 2.6 on a Sun Ultra 5, GNU gcc compiler
@item
Debian GNU/Linux 2.1v0 with LessTif 0.91.8 on a HP Kayak XU
@item
Ultrix 4.4 on a Digital DECsystem 5500, GNU make@footnote{Limited
support: REAL_CPU_SPEED build option and serial port emulation
are not available}
@item
IRIX 6.5 on a SiliconGraphics Octane
@end itemize
If you succeed in building @code{saturn} on a system not mentioned
above, plase drop an email to the author, so that this documentation
can be updated.
@strong{Important notice:} I, the author, wrote the source code of
@code{saturn} in my spare time and, more often than not, while I was in
a hurry; therefore, it neither is nor intends to be a shiny reference
about good programming practice and so on. The documentation embedded
in the source code often is sparse, incomplete and not much useful; even
the structure of the code itself and some design choices, seen in
retrospective, are not so appropriate.
The @code{saturn} software is ``free''; this means that everyone is free to
use it and free to redistribute it on a free basis. However,
@code{saturn} is @strong{not} in the public domain; it is copyrighted
and there are restrictions on its distribution, but these restrictions
are designed to permit everything that a good cooperating citizen would
want to do. What is not allowed is to try to prevent others from
further sharing any version of these programs that they might get from
you.
Also, for my own protection, I must make certain that everyone finds
out that there is no warranty for the @code{saturn} software. If this
program is modified by someone else and passed on, I want their
recipients to know that what they have is not what I distributed, so
that any problems introduced by others will not reflect on my
reputation.
The precise conditions of the licenses for the programs currently
being distributed that relate to @code{saturn} are found in the General Public
License. For more information, see @ref{GNU GENERAL PUBLIC LICENSE}.
In addition, the name of IRITI-CNR shall not be used in advertising
or publicity pertaining to distribution of the software or of any
derived work without specific, written prior permission.
Bug reports or suggestions for @code{saturn} are most welcome. To do
this, please contact the author, preferably by email, at the following
address:
@sp 2
@center Ivan Cibrario Bertolotti
@center IRITI - National Research Council
@center c/o IEN "Galileo Ferraris"
@center Strada delle Cacce, 91
@center 10135 - Torino (ITALY)
@center email: cibrario@@iriti.cnr.it
@sp 2
For bug reports and/or build problems, please include at least:
@itemize @bullet
@item
the release number of the @code{saturn} component involved.
@item
hardware, operating system, and compiler versions.
@item
for bugs, the calculator model on which the bug arises,
the release number of the calculator's ROM image you have,
a thorough description of the problem and, if possible,
a patch.
@item
for build problems, a transcript of the build session,
preferably made by @code{script} and, if possible,
a patch.
@item
anything else that you think would be helpful, provided
its size is reasonable. In particular, do @strong{not}
send me your ROM images; this is not only a copyright violation,
it will also hog my mailbox.
@end itemize
Last, but not least, I wish to thank the following
people; without their help, @code{saturn} would probably
not exist:
@sp 2
@center My little twin sons, Samuele and Guglielmo
@center (I denied them the time I spent developing @code{saturn})
@sp 1
@center Jean-Yves Avenard
@center (No need to say why...)
@sp 1
@center Bernard Parisse
@center (Instant-load code, beta test and good advice)
@sp 1
@center Matthew Mastracci
@center (author of the "Guide to the Saturn Processor")
@sp 1
@center Eddie C. Dost
@center (author of @code{x48})
@sp 1
@c A simple ligature requires much work iftex...
@iftex
@center Sebastien Carlier and Christoph Gie@ss elink
@end iftex
@ifinfo
@center Sebastien Carlier and Christoph Giesselink
@end ifinfo
@center (respectively, author and maintainer of @code{emu48}).

341
keyb.c Normal file
View file

@ -0,0 +1,341 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: keyb.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: keyb.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 29-Jan-1998
.keywords : *
.description :
This module emulates the keyboard interface of the Yorke chip.
References:
SASM.DOC by HP (HORN disk 4)
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
x48 source code by Eddie C. Dost (ecd@dressler.de)
NOTE: In the current (r1.1) implementation,
the emulation accuracy could be poor.
.include : config.h, machdep.h, cpu.h, modules.h, keyb.h
.notes :
$Log: keyb.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.13 2000/11/09 11:32:49 cibrario
Revised to add file selection box GUI element, CPU halt/run
requests and emulator's extended functions:
- Implemented KeybReset()
Revision 3.10 2000/10/24 16:14:44 cibrario
Added/Replaced GPL header
Revision 2.1 2000/09/08 15:17:32 cibrario
Deep revision to accommodate the new GUI: all facilities to map a
key code (enum Key) into an IN/OUT pair have been removed,
because the GUI now does this function itself; KeybPress() and
KeybRelease() now directly accept an IN/OUT pair as input.
* Revision 1.1 1998/02/17 11:53:23 cibrario
* Initial revision
*
.- */
#ifndef lint
static char rcs_id[] = "$Id: keyb.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "keyb.h"
#include "debug.h"
#define CHF_MODULE_ID MOD_CHF_MODULE_ID
#include <Chf.h>
#define OUT_BITS 12
/* cur_in:
This array contains the current value the CPU IN register will assume
for each bit set in the OUT register.
*/
static InputRegister cur_in[OUT_BITS];
/* .+
.title : KeybRSI
.kind : C function
.creation : 11-Feb-1998
.description :
This function is called by the CPU emulator when the RSI instruction is
executed. It resets the keyboard interrupt system and posts a maskable
interrupt request if any key is pressed.
NOTE: This function currently (r1.1) always posts an IRQ request; perhaps,
if the ON key is down, a NMI request should be posted instead.
.call :
KeybRSI();
.input :
void
.output :
void
.status_codes :
*
.notes :
1.1, 17-Feb-1998, creation
.- */
void KeybRSI(void)
{
/* Post an IRQ if the IN register is not zero */
CpuIntRequest(KeybIN((OutputRegister)0x1FF) != (InputRegister)0 ?
INT_REQUEST_IRQ : INT_REQUEST_NONE);
}
/* .+
.title : KeybIn
.kind : C function
.creation : 11-Feb-1998
.description :
This function is called by the CPU emulator when either a C=IN or a A=IN
instruction is executed. It scans the keyboard and returns the current
value of the IN register for the given value of the OUT reguster.
.call :
in = KeybIN(out);
.input :
OutputRegister out, current value of the OUT register
.output :
InputRegister in, computed value of the IN register
.status_codes :
*
.notes :
1.1, 17-Feb-1998, creation
.- */
InputRegister KeybIN(OutputRegister out)
{
/* Compute the current value of the IN register */
InputRegister in = (InputRegister)0;
int bit;
/* For each bit set in the 'out' register, OR the corresponding IN register
value into 'in'
*/
for(bit=0; bit<OUT_BITS; bit++)
{
if(out & 0x01) in |= cur_in[bit];
out >>= 1;
}
return in;
}
/* .+
.title : KeybPress
.kind : C function
.creation : 11-Feb-1998
.description :
This function tells to the keyboard emulator that key 'key' has been
pressed. It updates the internal keyboard status information and, if
necessary, posts an interrupt request to the CPU.
.call :
KeybPress(key);
.input :
const char *key, identifies the key that has been pressed.
.output :
void
.status_codes :
MOD_W_BAD_KEY
MOD_W_BAD_OUT_BIT
.notes :
1.1, 17-Feb-1998, creation
2.1, 6-Sep-2000,
deeply revised to accomodate the new GUI
.- */
void KeybPress(const char *key)
{
if(strcmp(key, "*") == 0)
{
/* This is the ON key */
int i;
/* Set all 0x8000 lines */
for(i=0; i<OUT_BITS; i++) cur_in[i] |= 0x8000;
/* Post an interrupt request to the CPU */
CpuIntRequest(INT_REQUEST_NMI);
}
else
{
int in_val, out_bit;
if(sscanf(key, "%x/%x", &out_bit, &in_val) != 2)
{
ChfCondition MOD_W_BAD_KEY, CHF_WARNING, key ChfEnd;
ChfSignal();
}
else if(out_bit < 0 || out_bit >= OUT_BITS)
{
ChfCondition MOD_W_BAD_OUT_BIT, CHF_WARNING, out_bit ChfEnd;
ChfSignal();
}
else
{
/* Update the cur_in array */
cur_in[out_bit] |= in_val;
/* Post an interrupt request to the CPU */
CpuIntRequest(INT_REQUEST_NMI);
}
}
}
/* .+
.title : KeybRelease
.kind : C function
.creation : 11-Feb-1998
.description :
This function tells to the keyboard emulator that key 'key' has been
released. It updates the internal keyboard status information.
.call :
KeybRelease(key);
.input :
const char *key, identifies the key that has been released.
.output :
void
.status_codes :
MOD_W_BAD_KEY
MOD_W_BAD_OUT_BIT
.notes :
1.1, 17-Feb-1998, creation
2.1, 6-Sep-2000,
deeply revised to accomodate the new GUI
.- */
void KeybRelease(const char *key)
{
if(strcmp(key, "*") == 0)
{
/* This is the ON key */
int i;
/* Reset all 0x8000 lines */
for(i=0; i<OUT_BITS; i++) cur_in[i] &= 0x7FFF;
}
else
{
int in_val, out_bit;
if(sscanf(key, "%x/%x", &out_bit, &in_val) != 2)
{
ChfCondition MOD_W_BAD_KEY, CHF_WARNING, key ChfEnd;
ChfSignal();
}
else if(out_bit < 0 || out_bit >= OUT_BITS)
{
ChfCondition MOD_W_BAD_OUT_BIT, CHF_WARNING, out_bit ChfEnd;
ChfSignal();
}
else
{
/* Update the cur_in array */
cur_in[out_bit] &= ~in_val;
}
}
}
/* .+
.title : KeybReset
.kind : C function
.creation : 7-Nov-2000
.description :
This function resets the emulated keyboard; all keys are released.
.call :
KeybReset();
.input :
void
.output :
void
.status_codes :
.notes :
3.13, 7-Nov-2000, creation
.- */
void KeybReset(void)
{
int i;
/* Reset all 0x8000 lines */
for(i=0; i<OUT_BITS; i++) cur_in[i] = 0;
}

88
keyb.h Normal file
View file

@ -0,0 +1,88 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: keyb.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: keyb.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 17-Feb-1998
.keywords : *
.description :
Header for the keyboard emulation module. References:
SASM.DOC by HP (HORN disk 4)
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
x48 source code by Eddie C. Dost (ecd@dressler.de)
.include : config.h, machdep.h, cpu.h, modules.h
.notes :
$Log: keyb.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.13 2000/11/09 11:33:28 cibrario
Revised to add file selection box GUI element, CPU halt/run
requests and emulator's extended functions:
- Added prototype of KeybReset()
Revision 3.10 2000/10/24 16:14:45 cibrario
Added/Replaced GPL header
Revision 2.1 2000/09/08 15:02:14 cibrario
Updated prototypes of KeybPress() and KeybRelease() to accommodate
the new GUI. As a consequence, suppressed the definition of
'enum Key', no longer needed.
* Revision 1.1 1998/02/17 11:53:34 cibrario
* Initial revision
*
.- */
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
void KeybRSI(void);
InputRegister KeybIN(OutputRegister out);
void KeybPress(const char *key);
void KeybRelease(const char *key);
void KeybReset(void);

75
machdep.h Normal file
View file

@ -0,0 +1,75 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: machdep.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: machdep.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 28-Jan-1998
.keywords : *
.description :
Machine-dependent type definitions.
.include : config.h
.notes :
$Log: machdep.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:45 cibrario
Added/Replaced GPL header
Revision 1.1 1998/02/17 11:58:48 cibrario
Initial revision
.- */
/*---------------------------------------------------------------------------
Data type definitions
All Data types must be SIGNED
---------------------------------------------------------------------------*/
typedef char int1;
typedef char int4;
typedef char int8;
typedef int int12;
typedef int int16;
typedef int int20;
typedef int int32;

9
make_dist Executable file
View file

@ -0,0 +1,9 @@
#!/bin/sh
#
# $Id: make_dist,v 4.1 2000/12/11 09:54:19 cibrario Rel $
#
# This script builds the RCS distribution tar, saturn_RCS.tar;
# to do this, it first executes a 'make clean'.
make clean
tar cf saturn_RCS.tar RCS/* Chf/*

44
make_src_dist Executable file
View file

@ -0,0 +1,44 @@
#!/bin/csh
#
# $Id: make_src_dist,v 4.1 2000/12/11 09:54:19 cibrario Rel $
#
# This script builds the source distribution tar, saturn_src_....tar;
# the source distribution contains a snapshot of the RCS repository
# for release $argv[1]. The name of the source distribution tar
# includes $argv[1] as its last component.
if( $#argv < 1 ) then
echo "make_src_dist: missing target release number"
exit 1
endif
set rel = $argv[1]
set target_tar = saturn_src_$rel.tar
set rcs_flist = (RCS/*,v)
set flist = ""
set exit_code = 0
foreach rcs_file ($rcs_flist)
set file = `basename $rcs_file ,v`
# Extract file from repository
co -r$rel $file
if( $status != 0 ) then
echo "make_src_dist: ${file}: checkout failed for release $rel"
set exit_code = 2
continue
endif
# Add file to file list
set flist = ($flist $file)
end
make clean
tar cf $target_tar $flist Chf/*
if( $status != 0 ) then
echo "make_src_dist: tar failed"
set exit_code = 3
endif
exit $exit_code

102
make_ubin_dist Executable file
View file

@ -0,0 +1,102 @@
#!/bin/csh
#
# $Id: make_ubin_dist,v 4.1 2000/12/11 09:54:19 cibrario Rel $
#
# This script builds a user-level binary distribution for release
# $argv[1]. The name of the binary distribution tar
# includes $argv[1] as its last component.
#
# $argv[2] contains the make Makefile command
if( $#argv < 1 ) then
echo "make_ubin_dist: missing target release number"
exit 1
endif
if( $#argv < 2 ) then
echo "make_ubin_dist: missing make Makefile command"
exit 1
endif
set rel = $argv[1]
set src_tar = saturn_src_$rel.tar
set ubin_tar = saturn_ubin_$rel.tar
set special_flist = (sutil_48.lib sutil_49.lib)
set bin_flist = (README.txt BUILD_INFO.txt saturn Saturn.ad saturn.cat run_saturn quick_start saturn.ps saturn.info pack)
./make_src_dist $rel
if( $status != 0 && $status != 2 ) then
echo "make_ubin_dist: make_src_dist failed"
exit 2
endif
mkdir tmp_ubin; cd tmp_ubin
tar xvf ../$src_tar
if( $status != 0 ) then
echo "make_ubin_dist: source tar extract failed"
exit 3
endif
cat - > BUILD_INFO.txt <<EOF
This is a user-level binary distribution of saturn release $rel.
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
The distribution was created on:
`date`
The build host was (uname -a):
`uname -a`
EOF
if( $status != 0 ) then
echo "make_ubin_dist: can't create BUILD_INFO.txt"
exit 4
endif
$argv[2]
make depend; make; make doc
# Special: Copy special binaries down
foreach special ($special_flist)
cp ../$special .
end
tar cvf ../$ubin_tar $bin_flist $special_flist
if( $status != 0 ) then
echo "make_ubin_dist: can't create binary tar"
exit 5
endif
cd ..
rm -rf tmp_ubin

1742
modules.c Normal file

File diff suppressed because it is too large Load diff

616
modules.h Normal file
View file

@ -0,0 +1,616 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: modules.h,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: modules.h,v $
.kind : C header
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 28-Jan-1998
.keywords : *
.description :
This header contains all definitions and declarations related to the
peripheral modules of the HP48. References:
SASM.DOC by HP (HORN disk 4)
Guide to the Saturn Processor Rev. 0.00f by Matthew Mastracci
entries.srt by Mika Heiskanen (mheiskan@vipunen.hut.fi)
x48 source code by Eddie C. Dost (ecd@dressler.de)
.include : config.h machdep.h cpu.h
.notes :
$Log: modules.h,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:50 cibrario
Added/Replaced GPL header
Revision 3.3 2000/09/26 15:10:22 cibrario
Revised to implement Flash ROM write access:
- Added .map_flags field to struct ModDescriptionEntry
- New status code MOD_E_ROM_SAVE
* Revision 3.2 2000/09/22 14:05:32 cibrario
* Implemented preliminary support of HP49 hw architecture:
* - moved ROM/RAM storage areas in ModStatus into private,
* configuration-specific, dynamically allocated data structures.
* - added flash-rom access accelerators for the hp49 hw configuration
* - added new status codes: MOD_E_NO_MATCH, MOD_F_MOD_STATUS_ALLOC,
* MOD_F_NO_DESCRIPTION
* - added prototype of new functions: ModSelectDescription(),
* ModRegisterDescription()
*
* Revision 3.1 2000/09/20 14:00:40 cibrario
* Minor updates and fixes to avoid gcc compiler warnings on Solaris
* when -ansi -pedantic -Wall options are selected.
*
* Revision 2.7 2000/09/19 11:12:46 cibrario
* Deeply revised to implement module config/unconfig cache.
*
* Revision 2.5 2000/09/14 15:20:18 cibrario
* Added serial port buffer registers .serial_rbr and .serial_tbr
* in struct ModHdw; the hdw module uses them to buffer nibbles
* to/from multi-nibble registers.
*
* Revision 2.4 2000/09/12 15:47:32 cibrario
* The follwing updates were required to implement emulation of Port 1
* and 2, and to prepare the support of additional hw configurations:
* - added an hw configuration-dependent field to struct ModHdw: .accel;
* this field holds information useful to accelerate frequently executed
* operations on a given hw architecture.
* In the current hw configuration, it is used to hold the last
* address extension loaded into the bank switcher's F/F.
* The .accel_valid field indicates whether .accel is valid or not;
* .accel_valid is cleared when the ModHdw structure has not been read
* back correctly from mass storage.
* - added a new member to ModHdw: .card_status;
* it represent the current card status (HDW relative address 0x0F).
* - added storage space in struct ModStatus to accommodate Port 1 and 2.
* - added new status codes: MOD_I_BS_ADDRESS, MOD_I_PORT_1_WP,
* MOD_I_PORT_2_WP, MOD_W_PORT_1_INIT, MOD_W_PORT_2_INIT,
* MOD_E_PORT_1_SAVE, MOD_E_CE1_WRITE, MOD_E_PORT_2_SAVE,
* MOD_E_NCE3_READ, MOD_E_NCE3_WRITE.
*
* Revision 2.1 2000/09/08 15:20:50 cibrario
* Updated template of MOD_W_BAD_KEY status code; added new status
* code MOD_W_BAD_OUT_BIT. Both changes reflect the updates made to
* the keyboard emulation module in order to accommodate the new GUI.
*
* Revision 1.1 1998/02/17 14:55:04 cibrario
* Initial revision
*
.- */
/*---------------------------------------------------------------------------
Data type definitions - require config.h, machdep.h, cpu.h
---------------------------------------------------------------------------*/
#define N_MOD 6
#define N_PAGE_TABLE_ENTRIES 16384
#define N_ROM_SIZE 512*1024*2
#define N_RAM_SIZE 128*1024*2
#define N_FLASH_SIZE_49 2048*1024*2 /* 3.2 */
#define N_RAM_SIZE_49 512*1024*2 /* 3.2 */
/* 2.4: Port_1 (CE2) size */
#define N_PORT_1_SIZE 128*1024*2
/* 2.4: Port_2 (NCE3) size */
#define N_PORT_2_SIZE N_PORT_2_BANK*128*1024*2
#define N_HDW_SIZE 256
#define MOD_MAP_CHECK_OB_SIZE 128
#define MOD_MAP_TABLE_OB_SIZE 512
/* 2.7: Number of entries in module config cache */
#define N_MOD_CACHE_ENTRIES 8
#define MOD_RCS_INFO "$Revision: 4.1 $ $State: Rel $"
/*---------------------------------------------------------------------------
Macros
ModAddress returns the base address of a page, given its number (Address)
ModOffset returns the page offset of an address (int)
ModPage returns the page number of an address (Address)
---------------------------------------------------------------------------*/
#define ModAddress(page) ((Address)(page) << 6)
#define ModPage(address) ((int)(((address) & 0xFFFC0) >> 6))
#define ModOffset(address) ((address) & 0x0003F)
/*
ModDescription
This const array contains an entry for each peripheral module connected
to the peripheral bus of the Saturn CPU; the entry describes the
characteristics of the module.
name: the mnemonic name of the module; the Saturn CPU doesn't
actually use this information, but it's still useful during
debugging.
id: the ID of the module, returned by the C=ID instruction
when the module is unconfigured.
access_prio: the access priority of the module, when the address spaces of
more than one module overlap. Higher values correspond to
higher priorities.
The configuration priority of the module, when there is more
than one unconfigured module on the peripheral bus, is
determined implicitly by the order in which the module
descriptions into the array. The modules that come first
in the array are configured first.
init: this function is called, without arguments, during VM startup
to initialize the device. For example, the initialization
function for the ROM module will read the ROM image from
disk and store them into the module status structure.
read: this function reads a nibble from the module. It receives the
relative address of the nibble to be read. The read function
can return an interrupt request for the CPU.
write: this function writes a nibble to the module. It receives the
relative address and the value of the nibble to be written.
The write function can return an interrupt request for the CPU.
r_config: this flag contains the configuration status of the module after
a bus reset. If the after-reset configuration status is
MOD_CONFIGURED, the module can never be unconfigured.
r_abs_base_addr: absolute base address of the module after a bus reset.
It should be set only if the module is at least partially
configured automatically after a bus reset.
r_size: size of the address window of the module after a bus reset.
It should be set only if the module is at least partially
configured automatically after a bus reset.
map_flags: special map flags:
MOD_MAP_FLAGS_ABS pass absolute addresses to module
read/write functions
Notice that the current implementation requires that the index of
the HDW registers in the mod_description table must be fixed
and equal to MOD_HDW_INDEX... this is unfortunate.
*/
typedef void (*ModInitFunction)(void);
typedef void (*ModSaveFunction)(void);
typedef Nibble (*ModReadFunction)(Address rel_addr);
typedef void (*ModWriteFunction)(Address rel_addr, Nibble data);
enum ModConfig
{
MOD_UNCONFIGURED,
MOD_SIZE_CONFIGURED,
MOD_CONFIGURED
};
struct ModDescriptionEntry
{
char *name;
Address id;
int access_prio;
#define MOD_MIN_ACCESS_PRIO (-1)
ModInitFunction init;
ModSaveFunction save;
ModReadFunction read;
ModWriteFunction write;
enum ModConfig r_config;
Address r_abs_base_addr;
Address r_size;
int map_flags; /* 3.3 */
#define MOD_MAP_FLAGS_ABS 0x1 /* Abs addresses to r/w */
};
#define MOD_HDW_INDEX 1
typedef const struct ModDescriptionEntry ModDescription[N_MOD];
/*
ModMapInfo
This array contains an entry for each peripheral module connected
to the peripheral bus of the Saturn CPU; the entry describes the
dynamic mapping information of the module:
config: contains the current configuration status of the module.
abs_base_addr: contains the current absolute base address of the module.
It's valid only if the module is currently configured.
size: contains the current size of the address window of the module.
It's valid only if the module is currently configured.
*/
struct ModMapInfoEntry
{
enum ModConfig config;
Address abs_base_addr;
Address size;
};
typedef struct ModMapInfoEntry ModMapInfo[N_MOD];
/*
ModPageTable
This array contains an entry (of type ModPageTableEntry) for each 'page'
(of size #40 nibbles) of the Saturn CPU physical address space. For
each page, the following information is stored:
index: the index of the module that responds to the address range of
the page in the ModDescription table.The special value
MOD_NO_MOD_INDEX indicates that no module responds to the
address range.
rel_base_addr: the relative base address of the page in the address
space of the module that responds to the address range of
the page, if any.
read, write: the read/write functions of the module that responds to the
address range of the page, if any.
Relative address calculation for module access
The Saturn Physical Address (SPA) is divided into two portions:
* Page Index (PI): PI = (SPA & 0xFFFC0) >> 6
* Offset (OFF): OFF = (SPA & 0x0003F)
The Page Index determines which module will respond to the module
access operation. ModPageTable[PI] contains the following information:
* Relative Base Address (RBA)
The relative address (RA) therefore will be RA = RBA | OFF; then, the
appropriate module access function, found again in ModPageTable[PI],
is called.
*/
struct ModPageTableEntry
{
int index;
#define MOD_NO_MOD_INDEX (-1)
Address rel_base_addr;
ModReadFunction read;
ModWriteFunction write;
};
typedef struct ModPageTableEntry ModPageTable[N_PAGE_TABLE_ENTRIES];
/* struct ModCache (2.7)
This structure holds the caching information for module config/unconfig.
The .config field is an array of ModCacheConfigEntry, and contains
the module configuration cache information. Each entry is a pair
(tag, map_ptr). The map_ptr field, when non-null,
points to the struct ModMap to be used when a module config command,
with the given tag address as argument, is executed.
The .victim field points to the entry of .config to be used
whenever a new fresh cache entry is needed after a cache miss.
Currently, It is incremented by one at each replacement, thus
implementing a very simple fifo replacement policy.
The .unconfig field is an array of struct ModMap pointers, and
contains the module unconfiguration cache information.
The .unconfig[i] array element, when non-null, points to the
struct ModMap to be used when a module unconfig command, unconfiguring
the i-th module, is executed.
The .config_point field is set if the struct ModMap is a point
of the module configuration tree where a config was completed.
It it used to walk back correctly when caching an unconfig.
This .ref_count is incremented by one when the struct ModMap
is referenced by an unconfig link; it is used to avoid freeing
referenced structures.
The .link field links all cached struct ModMap together.
*/
struct ModCacheTableEntry
{
Address tag;
struct ModMap *map_ptr;
};
struct ModCache
{
struct ModCacheTableEntry config[N_MOD_CACHE_ENTRIES];
int victim;
struct ModMap *(unconfig[N_MOD]);
int config_point;
int ref_count;
struct ModMap *link;
};
/*
struct ModMap
This structure contains all the mapping information about the peripheral
modules of the Saturn CPU. Its components are:
map_info: this array describes the dynamic mapping information of
each module connected to the Saturn peripheral bus.
page_table: this array describes the current layout of the address space
of the Saturn CPU.
cache (2.7): this structure holds caching information used to speed up
module config/unconfig instructions
*/
struct ModMap
{
ModMapInfo map_info;
ModPageTable page_table;
struct ModCache cache;
};
/*
struct ModStatus
This structure contains the actual status of all peripheral modules of the
Saturn CPU. The status of all modules is centralized to allow any device
to easily access the status of other devices.
struct ModHdw
This substructure contains the status of all peripheral devices controlled
by the hdw module.
3.2: To support the HP49 hw configuration, the original ModStatus structure
has been splitted in two:
- (new) struct ModStatus: contains configuration-independent status
information (.hdw), and configuration-dependent accelerators (.hdw.accel).
The overall layout of the structure is the same for all configurations,
and it is publicily accessible.
- struct ModStatus_xx (corresponding to all fields of the original
ModStatus structure except .hdw): contains the storage areas for
ROM and RAM in configuration 'xx', and is private to the
configuration-specific ROM/RAM emulation module.
*/
struct ModHdw48Accel
{
XAddress bs_address; /* Bank Switcher ext. address */
};
struct ModHdw49Accel
{
XAddress view[2]; /* Base of Flash views */
};
struct ModHdw
{
Nibble hdw[N_HDW_SIZE]; /* HDW registers */
/* LCD driver */
Address lcd_base_addr; /* LCD driver base address */
int lcd_on; /* LCD driver enable flag */
int lcd_contrast; /* LCD contrast value */
int lcd_vlc; /* LCD vertical line count */
int lcd_offset; /* LCD horizontal offset */
int lcd_line_offset; /* LCD line offset */
Address lcd_menu_addr; /* LCD menu base address */
int lcd_ann; /* LCD annunciators status */
/* Timers */
Nibble t1_ctrl; /* Timer 1 control */
#define T1_CTRL_EXTRA 0x01
#define T1_CTRL_INT 0x02
#define T1_CTRL_WAKE 0x04
#define T1_CTRL_SREQ 0x08
Nibble t2_ctrl; /* Timer 2 control */
#define T2_CTRL_TRUN 0x01
#define T2_CTRL_INT 0x02
#define T2_CTRL_WAKE 0x04
#define T2_CTRL_SREQ 0x08
Nibble t1_val; /* Timer 1 value */
int32 t2_val; /* Timer 2 value */
/* 2.4: New member required to support Port emulation */
Nibble card_status; /* Card status (hdw register 0x0F) */
#define NCE3_CARD_PRESENT 0x01
#define CE2_CARD_PRESENT 0x02
#define NCE3_CARD_WE 0x04
#define CE2_CARD_WE 0x08
/* 2.4: Hw configuration-specific members used as accelerators;
accel_valid is non-zero if the accelerators are valid
*/
int accel_valid;
union
{
struct ModHdw48Accel a48;
struct ModHdw49Accel a49;
} accel;
/* 2.5: Serial port buffer registers */
int8 serial_rbr;
int8 serial_tbr;
/* Misc */
int16 crc; /* CRC */
};
struct ModStatus
{
struct ModHdw hdw; /* HDW status */
};
struct ModStatus_48
{
Nibble rom[N_ROM_SIZE]; /* Internal ROM */
Nibble ram[N_RAM_SIZE]; /* Internal RAM */
Nibble port_1[N_PORT_1_SIZE]; /* 2.4: Port_1 (CE2) storage */
/* 2.4: Port_2 (NCE3) storage; only needed if N_PORT_2_BANK is defined */
#ifdef N_PORT_2_BANK
Nibble port_2[N_PORT_2_SIZE];
#endif
};
struct ModStatus_49
{
Nibble flash[N_FLASH_SIZE_49]; /* Internal Flash ROM */
Nibble ram[N_RAM_SIZE_49]; /* Internal RAM */
Nibble *ce2, *nce3; /* ERAM bases */
};
/*---------------------------------------------------------------------------
Global variables
---------------------------------------------------------------------------*/
extern struct ModStatus mod_status;
/*---------------------------------------------------------------------------
Chf condition codes
---------------------------------------------------------------------------*/
#define MOD_I_CALLED 101 /* Function %s called */
#define MOD_I_INITIALIZING 102 /* Initializing module %s */
#define MOD_I_RESETTING 103 /* Resetting module %s */
#define MOD_I_GET_ID 106 /* ModGetID returning %x */
#define MOD_I_CONFIG 107 /* ModConfig %s %x %x completed */
#define MOD_I_UNCONFIG 108 /* ModUnconfig %s %x %x completed */
#define MOD_I_SAVING 109 /* Saving status of module %s */
#define MOD_I_NOT_IMPLEMENTED 110 /* Function %s not implemented */
#define MOD_I_REVISION 111 /* Modules revision: %s */
#define MOD_I_BS_ADDRESS 112 /* 2.4: Bank Switcher address: %x */
#define MOD_I_PORT_1_WP 113 /* 2.4: Port 1 is write protected */
#define MOD_I_PORT_2_WP 114 /* 2.4: Port 2 is write protected */
#define MOD_I_PERF_CTR 115 /* 2.7: Value of PerfCtr %s is %d */
#define MOD_I_CACHED_UNCONFIG 116 /* 2.7: Cached ModUnconfig completed */
#define MOD_I_CACHED_CONFIG 117 /* 2.7: Cached ModConfig %x comp. */
#define MOD_I_UNCONFIG_L_HIT 118 /* 2.7: Late unconfig hit */
#define MOD_I_UNCONFIG_L_MISS 119 /* 2.7: Late unconfig miss */
#define MOD_W_BAD_CONFIG 202 /* Bad ModConfig %x ignored */
#define MOD_W_BAD_UNCONFIG 203 /* Bad ModUnconfig %x ignored */
#define MOD_W_HDW_WRITE 204 /* Bad HdwWrite %x, %x */
#define MOD_W_HDW_READ 205 /* Bad HdwRead %x */
#define MOD_W_RESETTING_ALL 206 /* Resetting all modules */
#define MOD_W_RAM_INIT 207 /* Can't initialize internal RAM */
#define MOD_W_HDW_INIT 208 /* Can't initialize HDW */
#define MOD_W_BAD_KEY 209 /* 2.1: Bad key %s ignored */
#define MOD_W_BAD_OUT_BIT 210 /* 2.1: Bad out_bit %x ignored */
#define MOD_W_PORT_1_INIT 211 /* 2.4: Can't initialize Port 1 */
#define MOD_W_PORT_2_INIT 212 /* 2.4: Can't initialize Port 2 */
#define MOD_W_NO_VICTIM 213 /* 2.7: No cache victim; flush/retry */
#define MOD_E_BAD_READ 301 /* Read unmapped addr %x */
#define MOD_E_BAD_WRITE 302 /* Write unmapped addr %x datum %x */
#define MOD_E_ROM_WRITE 303 /* Write into ROM addr %x datum %x */
#define MOD_E_RAM_SAVE 304 /* Can't save internal RAM status */
#define MOD_E_HDW_SAVE 305 /* Can't save HDW status */
#define MOD_E_PORT_1_SAVE 306 /* 2.4: Can't save Port 1 status */
#define MOD_E_CE1_WRITE 307 /* 2.4: Ce1Write addr %x datum %x */
#define MOD_E_PORT_2_SAVE 308 /* 2.4: Can't save Port 2 status */
#define MOD_E_NCE3_READ 309 /* 2.4: Read from NCE3 addr %x */
#define MOD_E_NCE3_WRITE 310 /* 2.4: Wr. to NCE3 addr %x datum %x */
#define MOD_E_NO_MATCH 311 /* 3.2: Hw desription %s not found */
#define MOD_E_ROM_SAVE 312 /* 3.3: Can't save Flash ROM */
#define MOD_F_MAP_SAVE 401 /* Can't save mod_map information */
#define MOD_F_ROM_INIT 402 /* Can't initialize internal ROM */
#define MOD_F_MAP_ALLOC 403 /* Dynamic map allocation failed */
#define MOD_F_BAD_ALLOC_C 404 /* 2.7: Bad alloc_c %d aft FlushCache*/
#define MOD_F_CHAIN_CORRUPTED 405 /* 2.7: ModMap chain corrupted */
#define MOD_F_NO_VICTIM 406 /* 2.7: No cache victim after flush */
#define MOD_F_MOD_STATUS_ALLOC 407 /* 3.2: ModStatus_xx alloc failed %d */
#define MOD_F_NO_DESCRIPTION 408 /* 3.2: No module description */
#define MOD_M_NOT_MAPPED 501 /* Address %x not mapped */
#define MOD_M_MAPPED 502 /* Address %x mapped to %s:%x */
#define MOD_M_MAP_TABLE_TITLE 503 /* */
#define MOD_M_MAP_TABLE_ROW 504 /* %s %x %x %s */
#define MOD_M_MAP_CONFIGURED 505 /* Configured */
#define MOD_M_MAP_SZ_CONFIGURED 506 /* Size configured */
#define MOD_M_MAP_UNCONFIGURED 507 /* Unconfigured */
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/* Initialization */
void ModSelectDescription(const char *hw);
void ModRegisterDescription(ModDescription p);
void ModInit(void);
void ModSave(void);
void ModReset(void);
/* Configuration */
Address ModGetID(void);
void ModConfig(Address config_info);
void ModUnconfig(Address unconfig_info);
/* Read/Write */
Nibble FetchNibble(Address addr);
Nibble ReadNibble(Address addr);
void WriteNibble(Address addr, Nibble datum);
/* Monitor */
void ModMapCheck(Address addr, char ob[MOD_MAP_CHECK_OB_SIZE]);
void ModMapTable(char ob[MOD_MAP_TABLE_OB_SIZE]);

103
modules.msf Normal file
View file

@ -0,0 +1,103 @@
$ .+
$ .identifier : $Id: modules.msf,v 4.1 2000/12/11 09:54:19 cibrario Rel $
$ .context : SATURN, Saturn CPU / HP48 emulator
$ .title : $RCSfile: modules.msf,v $
$ .kind : Message catalog source
$ .author : Ivan Cibrario B.
$ .site : CSTV-CNR
$ .creation : 13-Feb-1998
$ .keywords : *
$ .description :
$ Message catalog source file for the peripheral modules emulator.
$ .notes :
$ . $Log: modules.msf,v $
$ . Revision 4.1 2000/12/11 09:54:19 cibrario
$ . Public release.
$ .
$ . Revision 3.8 2000/10/19 14:58:01 cibrario
$ . Bug fix:
$ . Removed lines with empty directives
$ .
$ Revision 3.3 2000/09/26 15:05:33 cibrario
$ Revised to implement Flash ROM write access:
$ - Added message 312
$ .
$ Revision 3.2 2000/09/22 14:07:04 cibrario
$ Implemented preliminary support of HP49 hw architecture:
$ - added new messages: 311, 407, 408
$ .
$ Revision 2.7 2000/09/19 11:13:12 cibrario
$ Deeply revised to implement config/unconfig cache.
$ .
$ Revision 2.4 2000/09/12 15:48:57 cibrario
$ Added messages 112, 113, 114, 211, 212, 306, 307, 308, 309, 310
$ .
$ Revision 2.1 2000/09/08 15:22:17 cibrario
$ Updated message 209; added message 210. Both updates reflect the
$ changes made to the keyboard emulation module in order to
$ accommodate the new GUI.
$ .
$ Revision 1.1 1998/02/17 14:53:53 cibrario
$ Initial revision
$ .-
$set 1
12 Modules
$set 12
101 Function [%s] called
102 Initializing module [%s]
103 Resetting module [%s]
106 ModGetID -> [%05X]
107 CONFIG M[%s] A[%05X] S[%05X]
108 UNCNFG M[%s] A[%05X] S[%05X]
109 Saving module [%s]
110 Function [%s] not implemented
111 Modules emulator: [%s]
112 Bank Switcher F/F set to A[%05X]
113 Port 1 has been write-protected
114 Port 2 has been write-protected
115 >>> PerfCtr [%s]=[%d]
116 Cached UNCNFG completed
117 Cached CONFIG A[%05X] completed
118 Late UNCNFG cache hit
119 Late UNCNFG cache miss
202 Bad ModConfig [%05X] ignored
203 Bad ModUnconfig [%05X] ignored
204 Bad HdwWrite A[%05X] N[%01X]
205 Bad HdwRead A[%05X]
206 Resetting all modules
207 Can't initialize internal RAM from disk
208 Can't initialize HDW from disk
209 Bad key [%s] ignored
210 Bad out_bit [%x] ignored
211 Can't initialize Port 1 from disk
212 Can't initialize Port 2 from disk
213 Unable to find CONFIG cache victim; flushing cache
301 Read from unmapped A[%05X]
302 Write to unmapped A[%05X] N[%01X]
303 Write into ROM A[%05X] D[%01X]
304 Can't save internal RAM status to disk
305 Can't save HDW status to disk
306 Can't save Port 1 status to disk
307 Write into CE1 A[%05X] D[%01X]
308 Can't save Port 1 status to disk
309 Read from NCE3 A[%05X] when Port 2 is not present
310 Write into NCE3 A[%05X] D[%01X] when Port 2 is not present
311 Hardware configuration [%s] not supported
312 Can't save Flash ROM status to disk
401 Can't save module mapping info
402 Can't initialize internal ROM
403 Dynamic allocation of ModMap failed
404 Bad alloc_c [%d] after FlushCache()
405 Cached struct ModMap chain corrupted; freeing unlinked entry
406 Unable to find CONFIG cache victim after cache flush
407 Allocation of ModStatus_xx failed ([%d]d bytes needed)
408 ModInit() invoked without registering a ModDescription first
501 A[%05X] -> *Not Mapped*
502 A[%05X] -> M[%s] R[%05X]
503 Device\t\t\tAddress\tSize\tStatus
504 %s\t%05X\t%05X\t%s
505 Configured
506 Size_configured
507 *Unconfigured*

379
monitor.c Normal file
View file

@ -0,0 +1,379 @@
/* -------------------------------------------------------------------------
saturn - A poor-man's emulator of some HP calculators
Copyright (C) 1998-2000 Ivan Cibrario Bertolotti
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the documentation of this program; if not, write to
the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
For more information, please contact the author, preferably by email,
at the following address:
Ivan Cibrario Bertolotti
IRITI - National Research Council
c/o IEN "Galileo Ferraris"
Strada delle Cacce, 91
10135 - Torino (ITALY)
email: cibrario@iriti.cnr.it
------------------------------------------------------------------------- */
/* +-+ */
/* .+
.identifier : $Id: monitor.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $
.context : SATURN, Saturn CPU / HP48 emulator
.title : $RCSfile: monitor.c,v $
.kind : C source
.author : Ivan Cibrario B.
.site : CSTV-CNR
.creation : 28-Jan-1998
.keywords : *
.description :
This file implements a simple interactive monitor, useful during
test & debug.
.include : config.h, machdep.h, cpu.h
.notes :
$Log: monitor.c,v $
Revision 4.1 2000/12/11 09:54:19 cibrario
Public release.
Revision 3.10 2000/10/24 16:14:51 cibrario
Added/Replaced GPL header
Revision 3.1 2000/09/20 13:52:42 cibrario
Minor updates and fixes to avoid gcc compiler warnings on Solaris
when -ansi -pedantic -Wall options are selected.
* Revision 1.1 1998/02/18 11:49:53 cibrario
* Initial revision
*
.- */
#ifndef lint
static char rcs_id[] = "$Id: monitor.c,v 4.1 2000/12/11 09:54:19 cibrario Rel $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <X11/Xlib.h>
#include "config.h"
#include "machdep.h"
#include "cpu.h"
#include "modules.h"
#include "args.h"
#include "debug.h"
#define CHF_MODULE_ID CPU_CHF_MODULE_ID
#include <Chf.h>
/*---------------------------------------------------------------------------
Macro & Data type definitions
---------------------------------------------------------------------------*/
#define LINE_BUFFER_SIZE 512
#define TOK_DELIMITERS " \t\n"
#define ADDRESS_FMT "%x"
#define COUNT_FMT "%d"
#define PROMPT "> "
#define OK 0
#define FAILED 1
/*---------------------------------------------------------------------------
Private functions - Command line parse
---------------------------------------------------------------------------*/
/* Read an Address from the command line */
static int ReadHexAddress(Address *addr)
{
char *p = strtok((char *)NULL, TOK_DELIMITERS);
return (p == (char *)NULL ||
sscanf(p, ADDRESS_FMT, addr) != 1) ? FAILED : OK;
}
/* Read a Nibble from the command line */
static int ReadHexDatum(Nibble *n)
{
Address addr;
int st;
if((st = ReadHexAddress(&addr)) == OK) *n = (Nibble)addr;
return st;
}
/* Read a DECIMAL count from the command line */
static int ReadCount(int *count)
{
char *p = strtok((char *)NULL, TOK_DELIMITERS);
return (p == (char *)NULL || sscanf(p, COUNT_FMT, count) != 1 ||
*count <= 0) ? FAILED : OK;
}
/*---------------------------------------------------------------------------
Private functions - Command execution
---------------------------------------------------------------------------*/
/* Run the emulator; this function exits normally only when an
EmulatorIntRequest() is posted and satisfied
*/
static int run(void)
{
Emulator();
return OK;
}
/* Set the debug level */
static int debug(void)
{
Address addr;
if(ReadHexAddress(&addr)) return FAILED;
SetDebugLevel((int)addr);
return OK;
}
/* Check the mapping of an Address and print */
static int map_check(void)
{
Address addr;
char ob[MOD_MAP_CHECK_OB_SIZE];
if(ReadHexAddress(&addr)) return FAILED;
ModMapCheck(addr, ob);
puts(ob);
return OK;
}
/* Print the current module map table */
static int map(void)
{
char ob[MOD_MAP_TABLE_OB_SIZE];
ModMapTable(ob);
puts(ob);
return OK;
}
/* Write nibbles into memory */
static int w(void)
{
Address addr;
Nibble n;
if(ReadHexAddress(&addr)) return FAILED;
while(ReadHexDatum(&n) == OK) WriteNibble(addr++, n);
return OK;
}
/* Read nibbles from memory */
static int r(void)
{
Address addr;
int count;
if(ReadHexAddress(&addr)) return FAILED;
if(ReadCount(&count)) count=1;
while(count-->0)
{
printf("A_%05X\t%X\n", addr, (int)FetchNibble(addr));
addr++;
}
return OK;
}
/* Disassemble */
static int d(void)
{
Address addr;
int count;
char ob[DISASSEMBLE_OB_SIZE];
if(ReadHexAddress(&addr)) return FAILED;
if(ReadCount(&count)) count=1;
while(count-->0)
{
addr = Disassemble(addr, ob);
puts(ob);
}
return OK;
}
/* Print CPU status */
static int cpu(void)
{
char ob[DUMP_CPU_STATUS_OB_SIZE];
DumpCpuStatus(ob);
puts(ob);
return OK;
}
/* Reset CPU */
static int reset(void)
{
CpuReset();
return OK;
}
/* Save & Exit */
static int mon_exit(void)
{
ModSave();
CpuSave();
exit(EXIT_SUCCESS);
return OK; /* 3.1: Keep compiler happy */
}
/* Quit without saving */
static int mon_quit(void)
{
exit(EXIT_SUCCESS);
return OK; /* 3.1: Keep compiler happy */
}
/*---------------------------------------------------------------------------
Command table
---------------------------------------------------------------------------*/
struct TEntry
{
char *name;
char *desc;
int (*function)(void);
};
#define TableSize(t) (sizeof(t)/sizeof(struct TEntry))
/* Forward declaration for the Help funcion */
static int Help(void);
static const struct TEntry table[] =
{
{ "help", "Print this information", Help },
{ "run", "Run the emulator with current CPU status", run },
{ "?", "<addr>, Check address mapping", map_check },
{ "r", "<addr> [count], Read nibbles from memory", r },
{ "w", "<addr> [n]..., Write nibbles into memory", w },
{ "d", "<addr> [count], Disassemble starting from 'addr'", d },
{ "cpu", "Print CPU status", cpu },
{ "map", "Print the contents of the module map table", map },
{ "debug", "Set the debugging level", debug },
{ "reset", "Reset CPU", reset },
{ "exit", "Save emulator state & exit", mon_exit },
{ "quit", "Quit emulator WITHOUT saving its state", mon_quit }
};
/* Invoke the command 'tk' and return a status code */
static int InvokeCommand(char *tk)
{
int i;
for(i=0; i<TableSize(table) && strcmp(tk, table[i].name); i++);
return i==TableSize(table) ? FAILED : table[i].function();
}
/* Print help information */
static int Help(void)
{
int i;
for(i=0; i<TableSize(table); i++)
printf("%s\t\t%s\n", table[i].name, table[i].desc);
return OK;
}
/* Handler for SIGINT during monitor execution */
static void sigint_handler(int s)
{
EmulatorIntRequest();
}
/*---------------------------------------------------------------------------
Public functions
---------------------------------------------------------------------------*/
/* .+
.title : Monitor
.kind : C function
.creation : 18-Feb-1998
.description :
This function implements a very simple interactive monitor.
.call :
Monitor();
.input :
void
.output :
void
.status_codes :
CPU_W_BAD_MONITOR_CMD
From lower level modules
.notes :
1.1, 18-Feb-1998, creation
.- */
void Monitor(void)
{
char cmd[LINE_BUFFER_SIZE];
char old_cmd[LINE_BUFFER_SIZE];
char *tk;
/* Clear old_cmd buffer */
strcpy(old_cmd, "");
/* Establish SIGINT handler */
signal(SIGINT, sigint_handler);
/* Infinite loop; it's exited only when a condition is signalled */
while(1)
{
/* Write prompt */
fputs(PROMPT, stdout);
fflush(stdout);
if(fgets(cmd, LINE_BUFFER_SIZE, stdin) == (char *)NULL ||
(tk = strtok(cmd, TOK_DELIMITERS)) == (char *)NULL)
{
/* New command empty; try old command */
if((tk = strtok(old_cmd, TOK_DELIMITERS)) != (char *)NULL)
if(InvokeCommand(tk))
ChfCondition CPU_W_BAD_MONITOR_CMD, CHF_WARNING, tk ChfEnd;
ChfSignal();
}
else
{
/* Save command */
strcpy(old_cmd, cmd);
/* New command */
if(InvokeCommand(tk))
{
ChfCondition CPU_W_BAD_MONITOR_CMD, CHF_WARNING, tk ChfEnd;
ChfSignal();
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more