Date: 19950723 From: more@power.globalnews.com [gone!] To: Jaap van Ganswijk Subject: 8506 WRITING FCODE PROGRAMS FOR PCI WRITING FCODE PROGRAMS FOR PCI US$60 plus s/h and tax (where applicable) Published September, 1994 FirmWorks To assist PCI developers in creating Open Firmware compliant products, FirmWorks has created the book "Writing FCode Programs for PCI". This manual, available exclusively from FirmWorks, is an adaptation of previously-existing FCode programming documentation that has been made compliant with IEEE Standard 1275-1994 and has been customized for Open Firmware and PCI. If you are making the move to Open Firmware on PCI, this book will help you make a smooth transition. Ordering Information We accept orders by mail, email, phone or fax. Payment can be made by check or credit card (Visa/MasterCard/Diners Club/Carte Blanche/JCB). If paying by credit card, be sure to include the card's expiration date and the billing address of the card if it is different from the shipping address. Please also include your phone number, in case we have a question about your order. Normally, shipment to US addresses is by Priority Mail and to all other destinations is by airmail. On request, we will also ship by overnight carrier for $5 handling plus our cost [specify carrier and rate (e.g. overnight/second day/economy)]. Name: _________________________________________________________________ Company: _________________________________________________________________ Address 1: _________________________________________________________________ Address 2: _________________________________________________________________ City: __________________________________ State: ____ Zip: _____________ Country: _________________________________________________________________ Phone: ____________________ (In case we have questions about your order) ______ copies @ US$60.00 $_______ Shipping and handling $_______ (15% of book total for U.S. and Canada; 30% elsewhere; overnight for $5 plus actual cost) Subtotal $_______ Sales tax (7.75% for California residents) $_______ Total (in US dollars) $_______ Shipping method __ Standard __ Expedited (Specify carrier/rate __________________________) Method of payment: __ Visa __ MasterCard __ Diners Club __ Carte Blanche __ JCB __ Check Card Number: _____________________________________________ Expires: ______ Signature: _____________________________________________________________ FirmWorks Suite 230 480 San Antonio Road Mountain View, CA 94040-1218 Tel: (415) 917-0100 Fax: (415) 917-6990 See also FirmWorks products - text item 4993) - POWERPC OPEN FIRMWARE EVALUATION SOFTWARE AVAILABLE FROM FIRMWORKS The following are extracts from the book. ---------------------------------------------------------------------------- CONTENTS Preface xi Chapter 1: PCI Cards and FCode 1 The Purpose of FCode 1 Locating the FCode Program 1 FCode Program Functions 2 FCode ROM Format 3 Interpreting FCode 3 Device Identification 3 Creating and Executing FCode Definitions 4 Chapter 2: Elements of FCode Programming 5 Colon Definitions 6 Stack Operations 6 Additional Information 7 Programming Style 7 Commenting Code 7 Coding Style 8 Short Definitions 8 Stack Comments 8 A Minimum FCode Program 10 FCode Classes 11 Primitive FCode Functions 12 System FCode Functions 12 Interface FCode Functions 13 Local FCode Functions 13 Chapter 3: Testing FCode Programs 15 FCode Source 15 Tokenizing FCode Source 16 FCode Binary Format 16 Testing FCode Programs on the Target Machine 17 Configuring the Target Machine 17 Setting Appropriate Configuration Parameters 17 Modifying the Expansion Bus Probe Sequence 18 Getting to the User Interface 18 Using the Command Line Editor of the User Interface 18 Using the User Interface to Test FCode Programs 21 Using dl to Load From a Serial Port 22 Using the User Interface to Interpret an FCode Program 23 Using the User Interface to Browse a Device Node 25 Using the User Interface to Test a Device Driver 26 Device Node Methods 26 Testing FCode Programs in Source Form 30 Producing an FCode ROM 30 Exercising an Installed FCode ROM 30 Chapter 4: Packages 33 Package Definitions, Package Instances, and Device Nodes 33 Package Data 34 Static and Instance-specific Methods 34 Execution Tokens 35 Intra-package Calling Methods 35 Accessing Other Packages 35 Inter-package Calling Methods 37 execute-device-method and apply 39 Plug-in Device Drivers 40 Common Package Methods 40 Basic Methods 41 Supplemental Methods 41 Package Data Definitions 42 Instance Arguments and Parameters 43 Package Mappings 45 nvramrc 45 Modifying Package Properties 46 Standard Support Packages 46 Disk-Label Support Package 46 TFTP Booting Support Package 47 Deblocker Support Package 48 Chapter 5: Properties 49 Standard FCode Properties 51 Standard Property Names 51 Display Device Properties 51 Network Device Properties 52 Memory Device Properties 52 General Properties For Parent Nodes 52 Properties For PCI Parent Nodes 53 Properties for PCI Child Nodes 53 Detailed Descriptions of Standard Properties 54 Manipulating Properties 68 Property Creation and Modification 68 Property Values 69 Property Encoding 69 Property Retrieval 69 Property Decoding 70 Property-Specific FCodes 70 Chapter 6: Block and Byte Devices 73 Block Devices 73 Byte Devices 73 Required Methods 74 Required Properties 75 Device Driver Examples 75 Simple Block Device Driver 76 Extended Block Device Driver 76 Complete Block and Byte Device Driver 82 Chapter 7: Display Devices 91 Required Methods 91 Required Properties 91 Device Driver Examples 92 Simple Display Device Driver 92 Extended Display Device Driver 92 Complete Display Device Driver 96 Chapter 8: Memory-Mapped Buses 101 Required Methods 101 PCI Bus Addressing 104 PCI Required Properties 104 SBus Addressing 105 SBus Required Properties 105 VMEBus Addressing 105 VMEBus Required Properties 105 Chapter 9: Network Devices 107 Required Methods 108 Required Device Properties 109 Optional Device Properties 109 Device Driver Examples 109 Simple Network Device Example 109 Sample Driver With Test and Debugging Methods 111 Bootable Network Device Driver Example 121 Chapter 10: Serial Devices 143 Required Methods 143 Required Properties 144 Device Driver Examples 144 Simple Serial FCode Program 144 Extended Serial FCode Program 144 Complete Serial FCode Program 146 Chapter 11: Open Firmware Dictionary 151 Appendix A: FCode Reference 325 FCode Primitives 325 FCodes by Function 326 FCodes by Byte Value 344 FCodes by Name 355 Appendix B: FCode Memory Allocation 367 Appendix C: PCI Bus Binding to Open Firmware 369 Appendix D: Coding Style 393 Index 399 ---------------------------------------------------------------------------- PREFACE This manual, "Writing FCode Programs for PCI", is derived from the Sun Microsystems manual "Writing FCode Programs" with adaptations specific to IEEE Standard 1275-1994 and to PCI FCode drivers. Who Should Use This Book This manual is written for designers of PCI interface cards and other devices that use the FCode programming language. It assumes that you have some familiarity with PCI card design requirements and Forth programming. The material covered in this manual is specifically for those developing FCode applications for PCI peripherals. The FCode language is defined by IEEE Standard 1275-1994 Standard for Boot Firmware (hereafter referred to as Open Firmware). This manual also assumes that you have read and understood PCI Local Bus Specification 2.0 (or later) and PCI Bus Binding to IEEE Standard 1275-1994 1.2 (or later). How This Book Is Organized * Chapter 1 "PCI Cards and FCode", introduces the basic relationships between FCode device drivers and the hardware that they control. * Chapter 2 "Elements of FCode Programming", introduces the basic elements of FCode, stack notation, and programming style. * Chapter 3 "Testing FCode Programs", describes the process of producing FCode programs, from source file to testing working programs. * Chapter 4 "Packages", describes the basic units of FCode program function. * Chapter 5 "Properties", describes properties, which define how an FCode device driver program "sees" the hardware that it controls. * Chapter 6 "Block and Byte Devices" through Chapter 10 "Serial Devices" describe currently-defined device types, programming requirements, and give some examples of device drivers for the various device types. * Chapter 11 "Open Firmware Dictionary", describes currently-defined FCode words, their functions and use, with brief programming examples. * Appendix A, "FCode Reference", lists all currently-defined Fcode words according to functional grouping, name, and byte value. * Appendix B, "FCode Memory Allocation", describes guidelines for memory allocation and de-allocation in FCode. * Appendix C, "PCI Bus Binding to Open Firmware", contains the text of PCI Bus Binding to IEEE Standard 1275-1994, Revision 1.2. * Appendix D, "Coding Style", contains an Open Firmware coding guideline. Related Books This manual does not pretend to cover everything you need to know to write FCode drivers for PCI cards. You'll have to read some other books, too. For information about PCI and Open Firmware, see the following manuals: * IEEE Standard 1275-1994 Standard for Boot (Initialization Configuration) Firmware, Core Requirements and Practices * PCI Bus Binding to IEEE Standard 1275-1994 1.2 (or later) * PCI Local Bus Specification 2.0 (or later) For more information about Forth and Forth programming, see: * Programming Languages - Forth, American National Standards Institute, Inc. * Forth: A Text and Reference, Mahlon G. Kelly and Nicholas Spies. Prentice Hall. * Starting FORTH, Leo Brody. FORTH, Inc., second edition, 1987. * Forth: The New Model, Jack Woehr. M & T Books, 1992. Code Examples All the sample drivers shown in this manual are available in machine-readable form. Development Tools FirmWorks has available a PCI Developer's Kit that allows PCI drivers to be developed and tested on a 486DX-33 PCI machine running MS-DOS. If you don't have the PCI Developer's Kit and would like more information about it, contact FirmWorks at info@firmworks.com. ---------------------------------------------------------------------------- CHAPTER 1: PCI Cards and FCode The Purpose of FCode Each PCI card identifies itself with a set of up to 64, 32-bit "configuration registers". The purpose of these registers is to provide a standard set of descriptive information in a known place. The configuration registers contain data identifying the type of card, its manufacturer and various other characteristics of the card. In addition, a PCI card can have an "expansion ROM" containing additional information such as a BIOS extension for the card or an FCode program. A BIOS extension provides a driver for the card to be used when the card is installed in a system that uses an Intel x86 compatible processor. An FCode program provides, at a minimum, additional descriptive information beyond that provided by the configuration registers and can provide a processor-independent boot-time driver for use in non-x86-based systems. An FCode program can also contain (or can help the operating system to locate) processor-specific and operating system-specific OS drivers. Locating the FCode Program The first 16 PCI configuration registers are collectively known as the configuration address space header. Included within this header is the expansion ROM base address register. If Bit 0 of this register is reset, the PCI card has no expansion ROM. If Bit 0 is set, the PCI card has one or more expansion ROMs whose base address is specified by Bits 11 - 31 of the register. The ROM(s) can contain several different images to accommodate different machine and processor architectures. As shown in Figure 1, each such ROM image has a header record and a PCI Data Structure that together describe the image. The header record is located at the start of the image and contains a pointer to the PCI Data Structure. The PCI Data Structure, in turn, contains a number of fields including: * A code type field This field identifies the type of code contained within the image * An image length field This field defines the length of the image in integral multiples of 512 bytes. * An indicator field This field defines whether there are additional images located after this image. FCode Program Functions If the code type field has a value of 1, the ROM contains an FCode Program that, at a minimum, identifies the device and its characteristics. An FCode Program may also include an optional software driver that lets you use the card as a boot device or a display device during booting. The software driver may also include diagnostic selftest code. In addition to designing hardware, the process of developing PCI devices may include writing, testing, and installing FCode drivers for the device. These drivers, if present, serve three functions: * To exercise the device during development, and to verify its functionality. * To provide the necessary driver to be used by the system boot ROM during power-up. * To provide device configuration information. In practice, these functions overlap substantially. The same code needed by the system boot ROM usually serves to significantly test the device as well. The ROM code is used before and during the boot sequence. After the boot sequence finishes, and while not using the Open Firmware User Interface, most PCI devices are controlled with operating system device drivers. FCode Programs are written in the FCode programming language, which is similar to ANS Forth. FCode is described in more detail in Chapter 2 "Elements of FCode Programming". FCode ROM Format An FCode ROM image is located within the PCI Expansion ROM on a 512 byte boundary. Its size typically ranges from 60 bytes (for a simple card that identifies itself but does not need a driver) to 1-4K bytes (for a card with a simple boot driver) to 10K bytes (for a device with a complex boot driver). It is good practice to make FCode boot drivers as short as is practical. An FCode ROM image for PCI is organized as follows: * Header (26 bytes: consisting of ROM signature and a pointer to the associated PCI Data Structure) * PCI Data Structure (24 bytes: See the PCI Local Bus Specification for details) * Body (FCode program; 0 or more bytes). * End Token (either End0, a zero byte, or End1, an alternative all 1's byte). Interpreting FCode For each PCI slot containing a card, the following process is followed during boot-up to find and interpret any FCode programs: * Scan all slots in numerical order. * For each slot read the header type field. * If the header field type indicates a multi-function device, perform the following sequence for each function that is present. * Otherwise, perform the following sequence for the card's Function 0. * Create a number of properties from the information contained in the PCI configuration registers. (See the PCI Bus Binding to IEEE Standard 1275-1994 for the details.) * Determine whether the device contains an expansion ROM and, if so, whether that ROM contains an image containing an FCode program. * If an FCode program is present, copy the FCode program into RAM and evaluate it * If the function does not have an FCode program: * Create the "reg" and "name" properties from the information in the PCI configuration registers. * If possible, create the "power-consumption" property from the state of the PRSNT1# and PRSNT2# connector. * Disable fixed address response by clearing the PCI configuration address header's command register. * Enable Memory Space response by setting Bit 1 in the command register. Device Identification An FCode ROM must identify its device. This identification must include, at a minimum, the device name. Identification information may include additional characteristics of the device for the benefit of the operating system and the CPU boot ROM. The CPU's FCode interpreter stores each device's identification information in a device tree that has a node for each device. Each device node has a property list that identifies and describes the device. The property list is created as a result of interpreting the program in the FCode ROM. Each property has a name and a value. The name is a string and the value is an array of bytes, which may encode strings, numbers, and various other data types. See Chapter 5 "Properties" for more information. Creating and Executing FCode Definitions Many FCode programs create executable routines, called methods, that typically read from and write to device locations to control device functions. These definitions are also stored in the device tree node for that device. Once defined, these routines may be executed under any of the following circumstances: * Interactively through the Open Firmware User Interface's ok prompt (for selftest or other purposes). * By the Open Firmware Client Interface (for using this boot or display during system start-up). * Automatically by the Open Firmware Device Interface during FCode interpretation (for power-on initialization or other purposes). ---------------------------------------------------------------------------- CHAPTER 7: Display Devices The display device type applies to framebuffers and other devices that appear to be memory to the processor with associated hardware to convert the memory image to a visual display. Display devices can be used as console output devices. Required Methods The display device's FCode must declare the display device type, and must implement the methods open and close. System defer words are loaded by appropriate routines. is-install, is-remove and is-selftest are used to create the open, close and selftest routines. set-font initializes the values of frame-buffer-adr, char-height and char-width, all of which are built into the system ROM and can be used by any display device driver. For display devices, created methods interact with Open Firmware commands in a way that is different from that of other device types. Other device types provide methods that are found by dictionary searches looking for specific names. Some FCodes are specifically designed for display devices. See Table 68 through Table 74 in Appendix A, "FCode Reference". Required Properties Table 22 Required Display Device Properties ---------------------------------------------------------------------------- Property Name Typical Value ---------------------------------------------------------------------------- name " INTL,cgsix" ---------------------------------------------------------------------------- reg list of registers {device dependent} ---------------------------------------------------------------------------- device_type " display" {required for display devices} ---------------------------------------------------------------------------- Device Driver Examples Simple Display Device Driver This is a sample FCode program for a display device that does not need to be usable as a console display device during system power-up. Code Example 7-1 Basic Display Device Driver Example \ Basic display device driver \ This version doesn't use the graphics accelerator because of conflicts \ with the window system's use of same. hex " INTL,cgsix" name " INTL,501-xxxx" model h# 20.0000 constant dac-offset h# 10 constant /dac h# 30.0000 constant fhc-offset h# 10 constant /fhc h# 30.1800 constant thc-offset h# 20 constant /thc h# 70.0000 constant fbc-offset h# 10 constant /fbc h# 70.1000 constant tec-offset h# 10 constant /tec h# 80.0000 constant fb-offset h# 10.0000 constant /frame : >reg-spec ( offset size -- encoded-reg ) >r 0 my-address d+ my-space encode-phys 0 encode-int encode+ r> encode-int encode+ ; 0 0 >reg-spec \ Configuration space registers dac-offset /dac >reg-spec encode+ fhc-offset /fhc >reg-spec encode+ thc-offset /thc >reg-spec encode+ fbc-offset /fbc >reg-spec encode+ tec-offset /tec >reg-spec encode+ fb-offset /frame >reg-spec encode+ " reg" property end0 ---------------------------------------------------------------------------- CHAPTER 11: Open Firmware Dictionary This dictionary describes all of the words defined by IEEE Standard 1275-1994. Included within this dictionary are all of the pre-defined FCode words that you can use as part of FCode source code programs. Appendix A, "FCode Reference", contains a command summary, with words grouped by function. The dictionary also includes assembler directives, debugger commands, tokenizer directives and macros, configuration variables, properties, standard methods, nvedit commands, Client Interface commands and User Interface commands. The words are given alphabetically in this chapter, sorted by the first alphabetic character in the word's name. For example, the words mod and */mod are adjacent to each other. Words having no alphabetic characters in their names are placed at the beginning of the chapter, in ASCII order. The boot ROM and tokenizer are case-insensitive (all Forth words are converted to lowercase internally). The only exceptions are literal text, such as text inside " strings and text arguments to the ascii command, which are left in the original form. In general, you may use either uppercase or lowercase. By convention, Open Firmware drivers are written in lowercase. All arithmetic uses 32-bit signed values, unless otherwise specified. Defining words create a header by calling external-token, named-token, or new-token. See the definitions of these words for more details. All FCode byte values listed in this chapter are given in hexadecimal. The dictionary definitions have the following form: name "pronunciation" stack: ( stack diagram ) code: FCode# generates: tokenizer macro (if applicable) Prose description. ! "store" stack: ( x a-addr -- ) code: 72 Stores x at a-addr. For more portable code, use l! if you explicitly want a 32-bit access. a-addr must be aligned as given by variable. See also: c!, w!, l!, rb!, rw!, rl! " "quote" stack: ( [text<">< >] -- text-str text-len ) code: none generates: b(") len-byte xx-byte - xx-byte Gathers the immediately following text string or hex data until reaching the terminator ". At execution time, the address and length of the string is left on the stack. For example: " AAPL,new-model" encode-string " model" property You can embed control characters and 8-bit binary numbers within strings. This is similar in principle to the \n convention in C, but syntactically tuned for Forth. This feature applies to the string arguments of the words " and ." The escape character is `"'. Here is the list of escape sequences: Table 29 Escape Sequences in Text Strings ------------------------------------------------------------------ Syntax Function ------------------------------------------------------------------ "" quote (") ------------------------------------------------------------------ "n newline ------------------------------------------------------------------ "r carriage return ------------------------------------------------------------------ "t tab ------------------------------------------------------------------ "f formfeed ------------------------------------------------------------------ "l linefeed ------------------------------------------------------------------ "b backspace ------------------------------------------------------------------ "! bell ------------------------------------------------------------------ "^x control x, where x is any printable character ------------------------------------------------------------------ "(hh hh) Sequence of bytes, one byte for each pair of hex digits hh . Non-hex characters will be ignored ------------------------------------------------------------------ " followed by any other printable character not mentioned above is equivalent to that character. "( means to start parsing pairs of hexadecimal digits as one or more 8-bit characters in the range 0x00 through 0xFF, delimited by a trailing ) and ignoring non-hexadecimal digits between pairs of hexadecimal digits. Both uppercase and lowercase hexadecimal digits are recognized. Since non-hex characters (such as space or comma) are ignored between "( and ), these characters make useful delimiters. (The "makearray" tool can be used in conjunction with this syntax to easily incorporate large binary data fields into any FCode Program.) Any characters thus recognized are appended to any previous text in the string being assembled. After the ) is recognized, text assembly continues until a trailing ". For example: " This is "(01 32,8e)abc"nA test xyzzy "!"! abcdefg""hijk"^bl" ^^^^^^^^ ^ ^ ^ ^ ^ 3 bytes newline 2 bells " control b Note - The use of "n for line breaks is discouraged. The preferred method is to use cr, rather than embedding the line break character inside a string. Use of cr results in more accurate display formatting, because Forth updates its internal line counter when cr is executed. When " is used outside a colon definition, only two interpreted strings of up to 80 characters each can be assembled concurrently. This limitation does not apply in colon definitions. See also: b(") # stack: ( ud1 -- ud2 ) code: C7 Converts a digit ud1 in pictured numeric output conversion. Typically used between <# and #>. #> stack: ( ud -- str len ) code: C9 Ends pictured numeric output conversion. str is the address of the resulting output array. len is the number of characters in the output array. str and len together are suitable for type. See (.) and (u.) for typical usages. ' "tick" stack: ( "old-name< >" -- xt ) code: none generates: b(') old-FCode# Generates the execution token (xt) of the word immediately following ' in the input stream. ' should only be used outside of definitions. See b('), ['] for more details. For example: defer opt-word ( -- ) ' noop is opt-word ----------------------------------------------------------------------------