/* CODING.TXT - General coding rules for KLH10 */ /* $Id: coding.txt,v 2.4 2001/11/10 21:24:21 klh Exp $ */ /* Copyright © 1992, 1993, 2001 Kenneth L. Harrenstien ** All Rights Reserved ** ** This file is part of the KLH10 Distribution. Use, modification, and ** re-distribution is permitted subject to the terms in the file ** named "LICENSE", which contains the full text of the legal notices ** and should always accompany this Distribution. */ KLH10 General coding rules STYLE AND STANDARDS =================== The style rule is simple: use the existing style. There is no religious reason for this particular style, but it is always best for edits and additions to remain consistent with what's already there. All code should conform to the first ANSI C Standard (ANS X3.159-1989, also called the 1990 Standard). Do not use or assume features from later versions of the C Standard, or from any specific compiler, unless conditionalized such that everything will still build without those features. This specifically includes pragmas; none are currently used. Similarly, the "long long" datatype cannot be assumed to exist. Do not use C++. Eventually this may become unavoidable for GUI wrappers, but the existing core code must remain in C. Simply using ANSI C is not enough to ensure code is portable. You must also be careful about any assumptions regarding the host CPU: little-endian vs big-endian, integer type sizes, printf arguments, and so on. This is a long and complex topic that boils down to "don't do stupid things". PORTING AND OSD CODE ==================== OSD means "Operating System Dependent". To make it easier to port the KLH10 to new platforms, all system calls or non-ANSI library facilities should be encapsulated within one or more of the OSD*.C modules, and accessed only by facilities with an "os" name prefix. The bulk of this code is presently in OSDSUP.H and OSDSUP.C, which is dedicated to the KN10 component and not used by any other programs. The only exceptions are DPSUP.C and the separate DP* programs that use it, but even those may be changed in the future to follow the same conventions. This should be done even for system calls that are considered "standard" for all Unix systems, such as read(), because of the existence of certain popular non-Unix platforms. New platforms will almost certainly require new Makefiles. Try to follow the scheme already in place. WORD MANIPULATION ================= NEVER, ever, operate on a PDP-10 word (w10_t) except with the macros provided from k10ops.h and word10.h. The only things you can do to words without macros are pointing to them (&) or copying (by assignment or parameter passing). The KLH10 is designed to be portable to environments where the longest native integer type is 32 bits, so a w10_t may actually be a structure or union rather than an integer. An important ramification of this is that any arithmetic done on values that might exceed 32 bits must always provide special handling; you cannot merrily assume that a sufficiently large "long long" will always be available. Even when it is, the "native" arithmetic may not be as efficient as a 32-bit algorithm! ARG/RET CHECKS ============== An important rule for macros and functions: Arguments are always *assumed* to be correctly formatted or masked. Results are always *guaranteed* to be correctly formatted or masked. This is important in order to maintain consistency and avoid redundant operations. The rule permits incorrect values to be generated or maintained, as long as they are corrected before being given to other facilities. There are only two known exceptions to this rule: mr_PC and E. * mr_PC is not masked during the normal execution loop, to save time. This may change for the KLX version. * E is not masked when provided to instruction routines, also to save time where the mask isn't needed. FLOATING POINT ============== Do not use it. No native implementation corresponds exactly with that of the PDP-10, and floating point results are inherently unportable, especially for extreme operands that may even trap. In theory it may be possible to accelerate some PDP-10 floating point operations with carefully selected uses of native FP operations or libraries, but this will take a VERY large amount of work to verify that the results remain bit-identical with those of a real PDP-10. CODING INSTRUCTION ROUTINES =========================== All instruction routines must be declared in this way: insdef(i_xxx) { /* Function code */ } The "insdef" macro declares the function with the following three args: int op; /* 9-bit opcode of instruction */ int ac; /* 4-bit AC field of instruction */ vaddr_t e; /* Effective Address calculated from I(X)Y */ (WARNING! for KS10 may have junk in high bits!) The op and ac values have already been masked. Note that someday "op" may go away. All memory references should be checked BEFORE anything is modified either in memory or the ACs! Actually, it is good practice to verify the memory reference before even starting the computation, especially if there's a chance that PC flags such as TRAP1 might be set. This ensures that abnormal termination (due to page failure or PI interrupt) doesn't leave anything messed up. Exceptions are BLT and IDBP/ILDB which know how to back out. Normal memory operand reads and writes should be done with: word = vm_read(e); - Read word, may page-fail! vm_write(e, word); - Write word, may page-fail! Halfword variants vm_{read,write}{lh,rh}() also exist, but note that they operate on h10_t integer values, not w10_t words. If the same memory location is to be read-modified (both read and written) then these should be used: vmptr_t p; p = vm_modmap(e); - Get phys mem ptr (may page-fail!) word = vm_pget(p); - Read word from phys mem (won't fail) vm_pset(p, word); - Write word to phys mem (won't fail) BLT, Stack, and Byte operations do special-case memory referencing to allow for previous-context mappings by PXCT. AC reads and writes are done with: word = ac_get(ac); - Read AC ac_set(ac, word); - Set AC Halfword AC reads and writes have ac_{set,get}{lh,rh}() but note that they operate on h10_t integer values, not w10_t words. Multi-word operations (in particular the double-word instructions) must reference each word individually, because AC+1 may wrap around (modulo 020) and E+1 may likewise either wrap or cross a page boundary. The return value is added to the PC, so normally this will be 1 except for jumps (0) and skips (2). The macro definitions PCINC_n are used for this purpose; someday they may have different values. Instructions which set any of the PC flags should do so with the macro PCFSET(flags) to ensure that various transition subtleties are handled properly. PRINTF ARGS =========== This is a generic portability tidbit. All printf-style references to integer variables of unknown size (that is, defined by typedefs) must promote the value to long and use %l in the format string. In particular, h10_t and vaddr_t types require this. MISCELLANY ========== To keep some strict compiler modes happy, all functions with external linkage must have a prototype declaration prior to their definition. This is not needed for static functions, unless of course they are referenced prior to their definition.