;;;; Understanding notes. ;;; ;;; VM. ;;; Storage bases correspond mostly to physical storage resources. Storage classes define representations. We need SC's because VOP arguments and results are in terms of TN's, and these are values represented in some way. That is, the SC a TN is in tells the compiler how to interpret the value represented by the TN. Stack classes. On the control stack there is one representation -- descriptor. On the number stack (non-descriptor), we have many classes to tell us how to interpret the bits sitting there. The TN has an SC, and it says whether the bits are a character, fixnum, SAP, etc. Ditto for register classes (see stack classes). When defining a class, the :constant-scs are representations that the compiler can arrange to massage into the defining class or representation. The :alternate-scs are representation we can "move to and move from". ;;; You may not need to say anything about moving between representations for some classes since they talk about representations used only as temporaries within VOP's. Primitive type specs in the VM definition bridge between the representations of data and the high-level Lisp object notions. These are like funnels of Lisp types into SC's. ;;; Primitive type aliases are notation conveniences for specifying VOP arguments. Instead of saying the arg is '(or ...), you can say it is a foo primitive-type. ;;; These tend to be data format specific, not port dependent. You want to define constants that hold the constant offset in the register storage base for. You can use these in VOP's to make TN's when outputting instructions that take register arguments. For TN's handled outside the compiler's register allocator, you can define "constant" (paramters) that hold these for convenient reference. You have to make them explicitly for other registers because the register allocator needs to know you're using it in the VOP. Must define C::IMMEDIATE-CONSTANT-SC which the compiler expects. This takes a constant the compiler picked up and it tells the compiler where to best put the thing, in what representation or SC. ;;; ;;; Instructions ;;; When using loading instructions, we'll supply constant indexes as the constant minus the pointer tag. For example, if other-pointers are tagged with a three bits forming 7, and we know we want the third byte, we'll index with -4. The tag makes the pointer effectively point past the beginning of the object. When using SAP's and calculated interior pointers (for indexing arrays with non-constant index values), we can use the loading instructions with constant zero offsets. Therefore, we may want to define a variant of the instruction that allows us to leave the offset unspecified, defaulting it to zero. You can't do this for other kinds of pointers since they have type tags. When extracting type tags, which we think of as occurring in the low-end of a word, we have to be aware of whether this is the zero'th or the third byte -- little-endian or big-endian. [RT SPECIFIC] Some instructions take registers and interpret register zero specially. When the register is identified as zero, the instruction uses the address zero instead of the contents of R0. We can use this to absolutely index low memory, but we currently have no use for that with the current data formats or memory layouts. [RT SPECIFIC] Make sure all branch delay slots have one 32-bit wide instruction. When defining argument/field types, try to set them up so you can use DEFINE-INSTRUCTION to define multiple flavors of one instruction (for example, the long and the short offsets of loads). If the short takes four bits of offset, but the instruction uses these as a six bit value, shifting the immediate data to the left, then use a member type, and supply a function to massage the values into the correct range for the immediate data. This way, when you specify this particular instruction with INST in a VOP, the assembler will pick the first instruction described in the DEFINE-INSTRUCTION form, which should be the shorter instruction that will handle the offset. [RT SPECIFIC] To store 32-bit constants, store the halves with CAU and then CAL. ;;; ;;; VOP's ;;; ;;;; BASICALLY starting a port. Modify vm.lisp (tells compiler where different data can be stored and how to represent it) and parms.lisp (architecture and data format constants and details). Define instructions to assembler. Convert utility macros. These are assembler macros written in Lisp that make defining VOP's easier. Modify call.lisp (frames and calling conventions). This is mostly VOP's. Verify that genesis works with changes to parms.lisp. Get Lisp startup code running. This needs to be modified to know where the C stack and friends are, etc. First testing level: Load above stuff into existing core (sort of). This breaks that core's compiler, but makes the compiler spit new fasl files. Compile a file with something like this: (defun foo () :bar) Then load genesis into a new core and point it at your new fasl files. Then run ldb on resulting core. Spend lots of time fixing call. A likely following order is this: arith cell ... whatever is interesting. ;;;; Random notes to flesh out for beginners. Move function vs. move vops. Relationship of SCs, VOPs, primitive types and issues of VOP arguments, results, and coercions (between alternate SCs and within primitive types). Allocating VOP temps for use within an assembler routine invoked and the issue of using dedicated registers via their hardwired or constant TNs even though you can't actually allocate another temp legally within the compiler. This happens for a couple reasons: 1] The compiler thinks you are out of a particular type of register (descriptor or non-descriptor), but even though it won't allocate you one, you can slime one into use if you know you can use a dedicated register at the time a particular VOP is emitted. 2] You can do this in assembler routines instead of declaring VOP temps to get your hands on a particular register. That is, use the constant TN instead of declaring a temp with a particular offset. How to interpret compiler printing of TNs. What tools do you use to find where the lossage is such as C::ID-TN, C::PRINT-VOPS, DESCRIBE looking for the reads and writes of TNs involved in the error message.