/****************************************************************************\ * Apple Lisa 2 Emulator * * Internal Project Name: Mona Lisa Overdrive * * [ name will be changed upon final release possibly to LisaWorks] * * * * Copyright (C) 1998 Ray A. Arachelian * * All Rights Reserved * * * * Project Documentation for Developers * * * \****************************************************************************/ Document Description and Purpose: This file attempts to document the Lisa Emulator Project - a work in progress to developers so as to provide a background of the source code. This is meant as an internal developer only document and not for public consumption. All trademarks are assumed to be owned by their respective owners. This document does not attempt to annotate each trade marked name with a (tm) symbol except in spirit. That is, wherever you see the word "Lisa" visualize a TM symbol as appropriate and think "Lisa is a trademark of Apple Computer, Inc." This project began on February 16, 1998 with an email being sent from me to several people whom I thought would be able to provide technical documentation for the Lisa computer. By February 17th, I had caught David T. Craig's attention and he has since provided numerous documents, a few of which I've made available online only to the project members (Since the documents are internal Apple technical docs, they really shouldn't be spread around publicly.) On September 23, I've contacted the LisaWorks emulation team and proposed a joining of forces as they were just getting started. This document is intended to get the programmers of the LisaWorks team up to speed with the internals of my source code. Introduction: The Apple Lisa personal computer was available between 1982 until 1985. It was one of the shortest lived computers ever, but it was a first step towards a graphical user interface and many of its features are barely just now becoming common place. It is not the purpose of this document to describe the Lisa from this point of view. There are several great references online which fit this purpose, one of which is David T. Craig's "The Lisa Legacy" paper. Several Lisa Sites exist on the web with various bits of information. Links to most of these (I say most since sites go up and down all the time) are available off of my emulator page: http://www.sundernet.com/lisaem and its sub pages. Rather than document the Lisa computer from a user's point of view, I will briefly summarize some of the more interesting hardware features from an emulator writer's point of view. Further, this document may cover topics in brief or surface detail that are better explained by the Lisa Hardware Guide which is required reading to understanding this Emulator. >From a hardware point of view, the Lisa has a high quality design. All the components that are safe for a technician as well as a user to access and replace. Since the components are properly designed, there is no need for a fan to aid cooling; the Lisa uses convection cooling. Every component is modular in design. Overview of Design: The same concept was applied in the organization of this emulator. When I originally started the emulator this wasn't quite true, but the number of .c and .h files was so huge that it needed to be reorganized. In the Lisa there are four boards inside of a cage like motherboard. The I/O board contains the two VIA 6522 chips, a COPS 421 micro controller and a 6504 CPU with its own ROM and 4K of RAM. The 6504's ROM is known as the I/O Rom. The shared 1024 byte area of memory between the 68000 and the 6504 is battery backed up by a 4 AA NiCad pack and holds the Lisa's equivalent of the PRAM (Parameter RAM on Macintoshes.) The CPU board contains the Motorola 68000 which is clocked at 5 MHz rather than 8 MHz because of the video display circuitry with which it shares access to the main memory. The CPU board contains the MMU subsystem, various latches, system ROM, as well as a Video State ROM which in truth contains the serial number. The two remaining boards are memory boards and are treated identically and can be swapped. The Lisa computer, like all 68000 based machines, uses memory mapped I/O. That is all of the I/O devices eat up space in memory. The Lisa however, uses a custom built Memory Management Unit (MMU) to control access to the I/O space. This means that any I/O done by the 68000, must first go through the MMU. (Any memory access at all must first go through the MMU.) In terms of accessing the various hardware, most of the accesses are done through the two VIA 6522 chips, except for the floppy controller. The floppy controller shares 1024 bytes of battery backed up memory with the 68000 CPU. The first few bytes of this memory as well as a 524 byte area are used as communications between the two processors. The remaining space is used by the 68000 to store PRAM information about the system. The 6504 boots up from ROM and runs a state machine that handles access to the floppy disk(s). When the 6504 completes its task, it can interrupt the 68000 to let it know that the data is ready. The 68000 can enable or disable the floppy IRQ by changing settings on the VIA's. If the floppy IRQ is disabled, then the 68000 can simply poll the results area of the shared memory to know that the request has either completed or resulted in an error. One of the command codes that can be sent to the 6504 CPU is an execute command. This command will not be supported by this emulator. If I discover that there exists crucial software that uses the 6504 in this way, I can always add a full 6504 emulator (6504 is a slightly crippled 6502) or find out what exactly this software does. One of the goals of this project is to have an emulator that does not require any actual Lisa ROM's, as doing so will prevent issues with Copyright or Licensing the ROM's from Apple, so hopefully we won't need to emulate the 6504 as that would require a copy of the I/O ROM for a functioning emulator. The bulk of the remaining I/O is handled by the two VIA 6522 controllers, and the Zilog 8530 SCC for the two serial ports. The VIA's are labeled the Parallel Port VIA, and the Keyboard VIA. The Parallel Port Via: (profile hard drives) The Parallel Port VIA simply talks to the parallel port, however for the purposes of this emulator, there will be a Profile State Machine listening for commands at this end. The Parallel Port VIA code is cloned and reused for emulating any expansion bus dual Parallel Port cards. Up to three dual parallel port cards may be added to a Lisa, therefore a Lisa can handle up to seven Profile drives. Since I do not own a Widget drive (internal hard drive) I'm not familiar with how a Lisa would talk to one other than to assume that it would do so in the same way as to a Profile. It may be possible to support two "large floppies" depending on whether or not the OS will recognize it, since the floppy controller can support two internal floppy drives. Originally in the Lisa 1, two Twiggy drives were used, later a single 400k drive was used with the possibility of a Widget drive. It is likely that the OS can see a second floppy if attached. It is also possible that we may be able to build a "floppy" image up to 24mb, but this is uncertain at this time and highly dependent on the OS. Certainly, the profile drives can easily go as high as 32mb, possibly 64mb though only 5mb and 10mb models were available. The Keyboard VIA: (COPS 421 controller, keyboard, mouse, RTC, etc.) The Keyboard VIA is slightly more complex since it connects to the COPS 421 micro controller which handles the keyboard, the mouse, and the real time clock, and the soft power switch. The COPS controller is always turned on and running. It gets its power from the power supply which means that a Lisa that looks like its off is actually just sleeping. To really turn a Lisa off, you must disconnect the power plug. (This is a big huge reason as to why you should never do work on a Lisa without unplugging the power cable. Still, there are two internal switches that cut power as soon as either the front panel or the back panel are removed.) The COPS controller also runs its own state machine, however there is no way to reprogram this controller to do anything different. Just about the only thing you could tell this controller to do is to set an alarm to turn on the Lisa at a specified time. So we don't have to worry about not having any documentation for the COPS 421. To talk to this controller, the 68000 goes through the MMU, to the Keyboard VIA and then sends commands or reads information from it. The Lisa keyboard itself contains a second COPS 421 controller which we don't have to worry about. Among other things I/O COPS controller sends back key down, key up events to the system, and mouse movement events. In terms of emulating the keyboard, we simply accept ASCII codes from the host computer and turn them into several key up/down event codes for the Lisa. Pressing the power switch, the mouse button, or if an alarm is triggered will cause special key scan codes to be sent. For example, if a user types in an upper case letter "A", we might send Left Shift Down, A down, A up, Left Shift Up as the sequence. This will work very well for most host computers and most software to run on the Lisa, however, it may be problematic to games where reading the actual scan codes is of importance. I may revisit this later if it becomes an issue. The mouse events are sent as a pair of single signed byte messages representing the relative motion of the mouse in X,Y coordinates. If the Lisa does not read them immediately, the COPS controller will add to the returned values. For example if the user moves the mouse +6,-5, but the 68000 doesn't see it, then the user moves +2,+2 pixels, the COPS will return +8,-3 when asked. The COPS421 also handles the RTC (Real Time Clock) which has a span of 15 years. Consequently this was set for 1980 to 1995, which means that it'll be really interesting to set dates such as 1998. Talk about Y2K premonition! I wonder what Apple was thinking... The Serial Ports: Modems, ImageWriters: To control the two serial ports, a Zilog 8530 SCC was used. This is a very standard and very common chip, and many online references can be found as to how to make it work, in Adobe Acrobat PDF format. It is my intention to have the option of "connecting" an ImageWriter emulator to this. The ImageWriter emulator currently spits out bands of bit mapped gray scale data which I intend to write a convert to PostScript for Unix hosts. Printing from the emulator under MacOS or Windows is trivial. We can treat the output simply as graphics. If the user has a real ImageWriter attached to one of the serial ports, we can "connect" a local serial port to what the emulator sees. Modems will be treated as devices attached directly to one of the host computer's serial ports, so the emulator will simply pass data back and forth. "But wait a second, weren't the ImageWriter printers black and white, why are we treating them as grayscale?" you might ask. Sure, IW's are 1 pixel output devices, however it is possible to write over the same spot over and over again and thus darken it. The IW emulator handles this. The IW will also have bitmapped copies of IW fonts and will be able to use these when printing in text or draft mode. The IW emulator is now in Beta. It can generate Adobe PostScript, HP PCL, and an X window for output. Video Display: The Lisa uses a high quality (for its time) paper white 1 bit bit mapped display (720x360) whose memory is shared by the system RAM. Consequently, it is possibly to display any "video page" block in the entire RAM space on the display, and the Lisa Pascal Workshop uses this feature for the debugger to switch between screen buffers. I've only written code to handle the drawing of this display for unix systems using X11R5 or better with XLib. No handling of screen refreshes, nor animation were done as I don't have a working emulator to experiment with. One interesting issue is that the Lisa's display has a different aspect ratio than most of today's machines, including the Macintosh which will cause the horizontal dimension to be overly stretched. One thing that we can do is to double the pixel height, which almost gets the right aspect ratio, but not quite. It is impossible to properly get the same exact aspect ratio as a real Lisa on today's monitors. Perhaps some sort of anti-aliasing done in true color might help, but will be blurry. In either case, we need to display slightly bluish phosphorous white pixels to give the actual feel of a real Lisa. Perhaps 0xAAAAFF could be used for the RGB values. Perhaps 0x8888FF. This has to be experimented with. Latches: There are several flip flops hanging out in special I/O address space memory which are used to turn on or shut off various functions. The strange thing about these is that they are turned on by accessing a certain memory location, then shut off by accessing a different memory address. By access I mean either read or write to this memory address. The contents of the data is of no importance. The actual access is what triggers the changing of the flop. The Memory Management Unit: All memory access done by the 68000 is handled by a an MMU composed of a set of discreet logic components rather than by a dedicated I.C. The MMU has its own set of 1024 12 bit registers that it uses to map out various areas of memory. At any given point one of four cached maps may be in use. This allows for memory maps of the OS and three processes to be quickly switched. The MMU has various settings for different types of memory including the Special I/O space, user memory, and stacks. Only the OS is allowed to access the I/O spaces. Should a user process attempt to access memory outside it's allowed range, an interrupt will occur preventing (or delaying) the access. The Operating System will then decide whether or not to complete the request or to kill the process. Memory allocations are automatically done when an application accesses memory not yet allocated. The OS will then allocate memory for the process. This is also true of stacks in order to prevent stack overflows. 100% Hardware Emulation: It is impossible to achive 100% Hardware Emulation. To do so one would have to emulate every single electron flowing through the various atoms of the various molecules. So obviously, while 100% Hardware Emulation is the goal of any emulator writer, some compromises must be decided on. In our case, the Lisa Emulator, it is not necessary to emulate the workings of every bit of the hardware. The Lisa is a very complex machine and therefore is too complex to emulate 100% in hardware, however, we can achieve excellent results if we specify a point of view. We will use the point of view of the 68000 processor which is the central core of the emulator. The 68k talks to the various I/O devices through the MMU, so the flow of I/O must always be done through this bit of software. The MMU code will analyze every read and every write to see what context we are in (memory or I/O space) and then decide what memory address is truly accessed (translation.) If the I/O space is selected, the MMU code calls the device being accessed whether it is one of the VIA's, or the 8530, or a direct write the floppy controller shared RAM. The rest of the I/O is handled from that bit of code. Just as the MMU is a gateway into I/O space, the VIA's are gateways to other components of the system. So the flow of the code is as follows: 68000 emulator core access memory address | +-->MMU multiplexes access to real memory and I/O space. +---> Memory +---> Parallel Port VIA on motherboard | +---> Profile State Machine +---> Keyboard VIA | +---> COPS421 code to handle mouse/keyboard/etc. +---> Floppy memory space | +---> Floppy State Machine +---> Z8530SCC | +---> Local port on host machine or | +---> ImageWriter State Machine. +---> Special Latches +---> whatever latch was changed. Interrupt ReQuests (IRQ's): In real life when the Lisa's 68000 CPU requests some I/O functionality, it does not expect the result instantly, nor does it wait for the result. It merely sends the request, and then blocks the currently I/O bound process and runs another process instead. Once the I/O device has an answer for the request, the devices generates an interrupt request or IRQ. This is called asynchronous I/O. The opposite of this is Synchronous I/O where the Lisa would sit around waiting for a response from the I/O device. This is much slower and much less efficient. However, my emulator is not multi threaded, this is because not all host computers can handle multi threaded code (i.e. MacOS.) and because writing a multi-threaded emulator is far more difficult, unnecessary, and even more CPU intensive. In this emulator when the Lisa requests something of an I/O device, the result is returned instantly (i.e. a disk read block request.) In order to give the appearance of a real computer, that is one where such requests take time and aren't instant, we delay the IRQ by means of an IRQ buffer. The IRQ buffer consists of a FIFO buffer containing the IRQ and a delay value. The delay value is measured in instruction cycles of the 68000. This gives the software driver code enough time to go through whatever loops it expects and at the quickest possible time have the result returned. The delay values must be hand tuned for the best performance and also to prevent the computer from deadlocking while waiting for a result. (i.e. the driver expects an IRQ later, but hasn't yet unmasked IRQ's, so the IRQ occurs immediatly, but is ignored. The driver waits forever for the IRQ that has already been ignored, or times out without result.) Source Code Organization: Project Docs ./doc Host Code ./host Unix X Win Code ./host/xlib Unix Keyboard ./host/keyboard Lisa Keycodes ./host/keyboard/keytable-final.c Unix Mouse Code ./host/mouse Lisa Hardware ./hw Lisa Itself ./hw/lisa stub dir ./hw/lisa/slots/README System Boards ./hw/lisa/boards I/O board devs ./hw/lisa/boards/io Z8530SCC code ./hw/lisa/boards/io/serial.c ./hw/lisa/boards/io/serial.h COPS421 code ./hw/lisa/boards/io/cops.h ./hw/lisa/boards/io/cops.c VIA code (both) ./hw/lisa/boards/io/via6522.c Video routines ./hw/lisa/boards/video ./hw/lisa/boards/video/video.c misplaced file ./hw/lisa/boards/profile.c stub dir ./hw/lisa/boards/mem/README CPU board ./hw/lisa/boards/cpu IRQ handler ./hw/lisa/boards/cpu/irq.c Serial # code ./hw/lisa/boards/cpu/videostaterom.c MMU code ./hw/lisa/boards/cpu/mmu.c CPU Core ./hw/lisa/boards/cpu/M68000 misplaced file ./hw/lisa/boards/profile.h floppy driver ./hw/lisa/floppy ./hw/lisa/floppy/floppy.c ./hw/lisa/floppy/floppy.h Profile driver ./hw/profile ./hw/profile/profile.c ./hw/profile/profile.c.new stub ./hw/modem shared vars ./hw/vars.c printers ./hw/printer ./hw/printer/imagewriter IW driver ./hw/printer/imagewriter/imagewriter.c Status of proj ./status.txt common title ./header.c support tools ./tools ./tools/README Future additions to this document will further document the actual functions and variables used throughout the code. Currently there are very few header (.h) files, these must be generated and included in the main /hw/vars.c file. All of the sources must later include a /hw/vars.h file so that they may communicate with all the other parts. This vars.h should also include function prototypes for the entire emulator. Current Vars in vars.c : Triggers are pop up messages telling the user (or developer) that the Lisa tried to do something unexpected. Trigger Message contains a string to display to the user, it can either point to trigger buffer or a static string. triggerevent; // code of the event that occured. *triggermessage; // pointer to trigger msg could point to triggerbuff triggerbuffer[256]; // scratch space for trigger pop ups Did an interrupt just happen? (these are obsolete.) volatile uint32 IRQHIT; // 0 if no IRQ, IRQ source otherwise #define IRQFLAG IRQHIT // synonym. How many opcodes to wait for before firing the floppy answer IRQ. This likely should be much larger than 10 cycle... #define IRQFLOPPYCYCLES 10 Various IRQ Id's: #define IRQ_FLOPPY 1 #define IRQ_FDIR_ON 401 #define IRQ_FDIR_OFF 400 #define IRQ_SCC 6 #define IRQ_VIA1 2 #define IRQ_VIA2 10 // this will map out is IRQ 1 to the lisa, // done to avoid conflict with floppy. #define IRQ_MMU_SEG 9 #define IRQ_MMU_BUS 8 #define IRQ_SLOT0 5 #define IRQ_SLOT1 4 #define IRQ_SLOT2 3 Actual Lisa IRQ's: /* * 7 NMI - Highest Priority * * 6 RS-232 Ports * * 5 Expansion Slot 0 * * 4 Expansion Slot 1 * * 3 Expansion Slot 2 * * 2 Keyboard * * 1 All other internal interrupts -- lowest priority * How big is our IRQ FIFO: #define MAXIRQQUEUE 2048 What's the IRQ FIFO elements: typedef struct { uint16 cycles; // how many cycles before this interrupt happens. uint16 irql; // what interrupt is supposed to happen? uint32 address; // some irq's are memory faults, what's the address of the fault } IRQRingBufferType; Your usual ring buffer: IRQRingBufferType irqRB[MAXIRQQUEUE]; uint16 IRQIdx; uint16 IRQSize; /***************************************************************************** This macro is used by the 68000 emulator module to see if an interrupt has occured. The reason we are using a ring buffer here is so that we can allow emulated devices to interrupt the CPU after a certain number of cycles. For example, our 6504 floppy emulator actually reads/writes sectors in what the 68000 would see as a single cycle. But since the 68000 expects to be irq'd once the 6504 is done, this isn't very cool. So this mechanism takes care of that. The minimal num of cycles MUST be 1! if you set it to zero, the CPU module will wait 65535 cycles! ******************************************************************************/ #define IRQCycleRingBuffer(){if (IRQSize){if(!(irqRB[IRQIdx].cycles--))IRQHIT|=1;} void IRQRingBufferDelete(void) int8 IRQRingBufferAdd(uint16 cycles, uint16 irql, uint32 address) // hexidecimal conversion table table. char *hex="0123456789abcdef"; // triggers are events that stop the 68k emulator and go to an event handler... Generic Trigger is simply a note to the user. The NMI key isn't used as far as I know, I'm curious to see what the Lisa does with it. #define NMI_INTERRUPT 0x00000001 #define COPSOVERFLOW 10001 #define GENERICTRIGGER -1 The COPS 421 also uses a queue, but this one is filled with COPS421 keyboard, mouse, date, reset codes. #define MAXCOPSQUEUE 512 char copsqueue[MAXCOPSQUEUE]; uint16 copsqueuelen; uint8 NMIKEY=0; uint8 cops_powerset, cops_clocksetmode, cops_timermode; Profile Hard Drive state Machine vars. Each profile drive must have its own state machine vars, hence we define this as a structure. #define PROFILE_IMG_HEADER_SIZE 2048 typedef struct { uint8 Command; // what command is the profile doing: // -1=disabled, -2=idle, 1=read, 2=write, 3=write verify // uint8 StateMachineStep; // what step of Command is the state machine of this profile in? uint8 DataBlock[4+8+532+8+2]; // 4 status bytes, command block, data block, 2 for good luck uint16 indexread; // indeces into the buffer for the Lisa to Read or Write uint16 indexwrite; uint32 blocktowrite; // used by the write command to store the block number to write uint32 numblocks; // (24 bit value!) size of this profile in blocks. // (9728=5mb, 532 bytes/sector) // We shouldn't make this more than 10Mb until we've tried it. // Control Lines from 6522 (except OCDLine which is Command=-1) uint8 CMDLine; // set by Lisa uint8 BSYLine; // set by ProFile uint8 DENLine; // set by Lisa (drive enabled) uint8 RRWLine; // set by Lisa (read or write) uint8 VIA_PA; // data to from VIA PortA (copied to/from V->via[0]) FILE *ProFileHandle; // file handle to disk image char ProFileFileName[256]; // the file name for this Profile disk image to open; } ProFileType; Ditto for the VIA's since we have 2 on the motherboard, and up to 6 more on expansion slots. /*************** VIA types, defines, and protos *******************************/ typedef struct { uint8 active; // is this VIA active? (except via1 and via2 s/b always active) // make sure that the initialization code sets these anyway!!! uint8 via[16]; // standard via registers uint8 viar[2]; // T1 timer latches (as loaded by the CPU) ProFileType profile; // If there's a ProFile attached, this structure deals with it. } viatype; /*********************************************************************************************************/ Finally a table of sector numbers to translate with for twiggies and sony 400k floppies. Basically Lisa sez I want sector 5 on track 2 of side 1 and this table returns the actual block number to fseek to on the disk image. extern uint16 floppy_sony_table[2][80][13]; extern uint16 floppy_twiggy_table[2][46][24]; ******************************************************************************* ******************************************************************************* # ##### ##### ##### # # # ##### ## # # # # # # ## ## ## # # # # # # # # # # # # # # # # # # ###### ###### ##### # # # ##### # # # # # # # # # # # # # # # # # # # # # ##### ##### ##### ##### ##### ##### ##### ##### ******************************************************************************* ******************************************************************************* lisaem/hw/lisa/boards/cpu/videostaterom.c: This file simply contains a couple of serial numbers in comments. There are no real functions for any of this yet, but likely the only thing this file will contain is an array that will hold the serial number. These will be used by reads from the Status register through the MMU code. This should simply contain the serialnum array and the supporting variables: serialnumshiftcount, serialnumshift, and perhaps some functions that are intitialized when the emulator starts to read in the user's selected serial number. lisaem/hw/lisa/boards/cpu/mmu.c This file is the gateway for all I/O on a Lisa as it is directly called by the 68000 CPU to access memory. Several functions are internal to this file, however memory is accessed through a single function. The mmutype mmu[4][128] array is an array of four contexts of 128 different mmu registers that are possible. Each element is composed of two MMU registers that are stored as 16 bit ints on the emulator, but 12 bit memory on a real lisa: sorg and slim. See the LisaHWG's for info on these. Basically one is the segment origin, the other the segment limit. Several variables are provides to work as the motherboard latches. These are the two diag flops, the two segment register flops, soft and hard memory error and last memory error, the vertical retrace register, the video page address, and the status register (from where the serial number is read.) Various defines are provided so that the source code can be a bit more friendly when we detect I/O access from the code. Perhaps some of this can be somewhat more optimized than a bunch of if statements over ranges followed by switch statements. ** Initialization of the MMU: When the system first starts, it needs to allocate memory for the lisa. We do that from the mmu.c allocate_memory(); This function also allocates the ROM memory and the I/O space memory. Most of that space is of course wasted since we're not going to use real ROM's, and I/O space doesn't always need real memory. The parameter passed here is the number of kilobytes to allocate, which simply gets malloc'ed. Personally I've had bad experiences with older operating systems when malloc and free were heavily relied on, so I generally try to avoid allocating memory with malloc, however allocating two megs of memory is much better handled by malloc than by a static array. The function that is available for use by the 68000 is: dolisamemaccess(uint32 xaddress,uint8 xwrite, uint32 *xvalue, uint8 xsize) All memory access must go through here. One thing to note is that this entire dispatch process is fairly slow since it has to go through many levels of tests. Perhaps we can speed this up in the future by modifying this routine to cache memory segment ranges and track the most commonly used, so we don't have to go through the entire flow. The remaining functions are internal to mmu.c and should not be called by anything outside: inline function lisa_io_space_access() accepts no parameters but dispatches the I/O command/status based on the global variables: address, premmuaddress, value, write, and size. This function is inline in an attempt to reuse it in several places, though most likely most compilers won't allow such huge inlines to happen and likely it'll be turned into a normal function. Address is the cooked address of the access, that is after the MMU recalucates it, premmu is what the 68000 tried to accessed before the MMU transform. The value is used for both reading and writing. Writing is controlled by the write flag, size indicates a byte, 16 bit word, or 32 bit long word. lisa_rom_access will allow reads into the ROM space, flag write attempts to the user (developer for now). Later we can work on emulating the ROM calls if they're accessed for execution by checking if the read was caused by an instruction fetch. lisa_ram_access will do an actual memory access (read or write and based on the size) warping the high 8 bits by and'ing them into a 24 bit address (That's what the 68000 does since it can only support an 8mb memory address range.) lisa_mem_access_via_mmu allows us to trap and access the MMU registers when the 68000 is accessing the special I/O space containing the MMU regs, normal memory, ROM's, stacks, etc. lisa_special_io_access allows us to actually modify or read the MMU registers, it's dispatched by lisa_mem_access_via_mmu as needed. /lisaem/hw/lisa/boards/cpu/irq.c This file is the main IRQ handler and like mmu.c, it needs to interface with the 68000 code. The main function to insert new IRQ's is: IRQRingBufferAdd(uint16 cycles, uint16 irql, uint32 address) Where cycles is the countdown to CPU cycles before the IRQ is triggered, a 1 here indicates the instruction will immediatly trigger the IRQ, a 1 indicates a trigger on the next instruction, etc... Note that a 0 indicates a wait of 65535 instructions as this is decremented to zero. IRQRingBufferDelete() is used by the CPU to discard an IRQ off the IRQ Buffer ring by the 68000, and possibly by other functions if we need to undo an IRQ. /lisaem/hw/lisa/boards/cpu/MC68000 This directory (will) contain(s) the 68000 emulator. /lisaem/hw/lisa/boards/io/cops.c This file contains handling routines for the COPS 421 processor. Again, it doesn't actually emulate a real COPS microcontroller, but rather emulates the functionality that Apple burned into these beasts. It includes the keytable-final.c which it uses to accept keystrokes from the user. These are in a translation table from ASCII to arrays of Lisa Keycodes. The cops.c file also contains various scan code defines for use within the emulator as needed. These defines should be moved to vars.h at the root of the lisa source tree. The COPS 421 controller is simulated by use of another ring buffer which contains a list of keyboard scan codes, "reset codes" (which are special conditions) and mouse movements. This file should interface with the host computer's user interface and translate. This is generic code that does not do any of that (yet). The host OS code needs to feed keystrokes to the COPS queue by calling: keystroke_cops(unsigned char c) where the parameter is the ASCII code of the key. This gets expanded into several key strokes as needed. The host OS may call presspowerswitch() to indicate that the user has pressed the power switch and should tell the Lisa to shut down. This can be graphically represented to the user, and this function gets called when the user presses the glowing yellow button. :) The host OS may call cops_fire_clock_timer_irq when the timer/clock alarm gets fired (if any is programmed by the OS...) One of the first things the emulator should do when it starts up is to call cops_keyboard_id() so that the keyboard ID code is available to the boot ROM. cops_unplug_keyboard() and unplugplugmouse() are not likely to be useful unless we provide the user with such features. If they are, they're likely to be used only as a joke or only to show that we have an emulator approaching 100% harware emulation. I suppose we could allow the user to drag the keyboard cable out with the mouse. :) It would be a fun easter egg to implement. The host os must call mouseposition(uint16 x, uint16 y, int8 button) as the mouse is moved within the Lisa emulator window so as to let the Lisa know the mouse position. The mouse routines aren't perfect as mice a relative position devices, that is they tell us the user moved n pixels to the left. They don't tell us the absolute position. The lisa works in this way. However, the host operating system will tell us the absolute coordinates. The problem is that the emulator does not know where the Lisa is displaying the mouse! After the emulator is completed, we'll have to do a bit of hacking and hope that somewhere in a fixed memory area, hopefully the low memory area (like on a Mac) will contain this info, so we can "synch" the two mouse pointers. Reading the ROM source code will likely provide this, but it is uncertain whether or not the Lisa OS will keep the same data in the same place, and we'd have to also worry about other OS's such as MacWorks. We'll deal with that once we have a working emulator. The via1_ora(uint8 data,uint8 regnum) and via1_ira(uint8 regnum) functions are called by the via.c file in I/O space to communicate with the COPS controller. They are not to be dispatched by the host OS. The ORA is Output Register A, the IRA is Input Register A, these correspond to the VIA's I/O ports to which the COPS is attached to. The IRA is simply called when the OS wants to read from the COPS. i.e. wants to read a keystroke, mouse movement, the data and time, etc. /lisaem/hw/lisa/boards/io/serial.c This file contains the Zilog 8530 emulator. Be aware that currently as of this writing this code is unfinished. The structures define most of the 8530 registers. The 68000 accesses these through the: SCC8530_write(uint32 address) and SCC8530_read(uint32 address) functions. (The source code is messed up here and has two write functions, one of which should be a read.) /lisaem/hw/lisa/boards/io/via6522.c This file contains of course the source code for handling the Versatile Interface Chip 6522 emulation. Since there are two VIA's on the Lisa motherboard, there are two main functions to handle reading and writing from them. There is also a set of generic functions for talking to parallel ports on the expansion port slot. The defines define the VIA registers and VIA memory addresses. These functions are dispatched by the MMU I/O space dispatcher functions. The VIA's are allocated from a typedef that defines each VIA into the following: via1, via2 for the built in keyboard and parallel port VIA's, via0l, via0h, // slot 0 VIA's. via1l, via1h, // slot 1 VIA's. via2l, via2h; // slot 2 VIA's. For the expansion slot parallel port VIA's. Now VIA's also have special programmable timer's built into them, so incase the Lisa's OS's will use them, we have: the via_run(viatype *V) function which takes one of the 8 VIA structures and runs them, whether to do shifts, or timer operations. These should be called from some routine that runs from the HOST OS side functions on a regular timed basis with the folllowing code: via_run(via1); via_run(via2); via_run(via0h); via_run(via0l); via_run(via1h); via_run(via1l); via_run(via2h); via_run(via2l); The via_irb and via_orb functions are called for the parallel port via's (the keyboard cops via respective functions live in cops.c) to read/write from the parallel port VIA's. lisa_via1(int8 regnum,uint32 xaddress,uint8 xwrite, uint32 *xvalue, uint8 xsize) Is called by the MMU to access the keyboard (cops) motherboard VIA. lisa_via2(int8 regnum,uint32 xaddress,uint8 xwrite, uint32 *xvalue, uint8 xsize) Is called by the MMU to access the parallel port motherboard VIA. int8 lisa_viaPP(viatype *V, regnum,uint32 xaddress,uint8 xwrite, uint32 *xvalue, uint8 xsize) Is called by the MMU to access one of the six parallel port VIA's. /lisaem/hw/lisa/boards/video The gen directory contains various code for generating the colortabs and "dimming" code for the display. This is independant code from the source tree currently, it should join the tree later. The file video.c contains the code to blast the display to the screen. The color tabs code contains a 24 bit rendering array of 8 bit blocks. The Lisa's actual display will be used as an index into this array. That is we'll read 8 pixels at a time (as a byte), we'll then read the 8 pixel pattern from the array to display it in 24 bit color. Thus we avoid much AND'ing and shifting of bits and speed up the display. The function plot must be implemented in the HOST OS support files for this to work. /lisaem/hw/lisa/floppy This directory contains the driver for the floppy controller. Perhaps this code should be moved back under /lisaem/hw/lisa/boards/io/floppy instead since on the Lisa, the actual floppy controller lives in the I/O board. Floppy_sec_tab_1.c and Floppy_sec_tab_2.c are the floppy sector translation tables. That is feed them the physical head, track, and sector number, and you get back an index into a floppy image. I'm not sure which of these two is the correct table, we can take a closer look later. The genfloppy.c is an applicationt that generates the above files. The floppy.c file contains many defines needed to understand the shared memory addresses of the controller and the commands and responses. The floppy_type structure is used to define both the upper and lower floppies and their parameters. The internal getmaxsector(int type, int track) function returns back the maximum number of sectors for a given track. The internal getsectornum(Floppy_Type F, uint8 side, track, uint8 sec) function is used by the code to get a virtual sector number. It uses the tables from Floppy_sec_tab_?.c to do the translation. The FloppyIRQ(uint8 RWTS) generates a floppy interrupt (i.e. request completed) so that the 68000 can come and get the data. If the parameter RWTS is set to one the INTSTAT shared param is also set. The floppy_go6504(void) function checks for a command from the 68000 in it's shared memory command block, and then executes the command. When the command is completed an IRQ is generated. The floppy_disk_copy_image_open(Floppy_Type *F,uint8 *tempbuff) is used to mount a Mac generated Disk Copy 4.2 disk image. The floppy_DTC1_image_open(FloppyType F,char *tempbuff) is used to mount a disk image created by David T. Craig's disk image tool. The floppy_return(FloppyType *F, uint8 boot, uint8 status) is used to return the status back to the 68000 and to clear unused or no longer needed memory. floppy_insert(uint8 floppynum) should be called by the HOST OS functions when the user inserts a disk into one of the two floppy drives. The floppy_button(uint8 floppynum) should be called by the HOST OS functions when the user pushes the floppy drive's button. The Sony 400k disks do not have such buttons, so this is for Twiggy drives only. The effects of pushing the button line for Sony 400k drives is unknown and should be tried. The floppy_checksum(FloppyType F, uint32 offset, uint32 tagoffset, uint8 write) and floppy_write_chksum(FileType F, uint32 chksum, uint32 tagchksum) are used when closing the disk image by the emulator. The emulator doesn't really use the checksums, and I'm not certain that these are correct, but we should write back a correct checksum when we write to a disk image so that it can be rewritten to a floppy and used on a real Lisa. /lisaem/hw/lisa/slots is an empty stub directory used to represent expansion ports. /lisaem/hw/modem is an empty stub directory used to represent a modem. /lisaem/hw/printer/imagewriter/imagewriter.c This is the begninign of the ImageWriter rendering code used to emulate an ImageWriter printer. It is incompleted code. The IW_MAX_BLACK define defines the maximum black depth. I doubt an IW would overwrite the same pixels 16x, so this might be better set to say 4. The IW_FONT_SIZE defines how many printable chars exist in a given text font. How wide is each char in the font (pixels): iw_char_widths[IW_FONT_SIZE]; Which row does each char start on? iw_char_rowstart[IW_FONT_SIZE] (some chars such as q's drop lower so they start 1 down.) Actual font bitmaps for each char. iw_char_bitmaps[IW_FONT_SIZE][16]; DTC provided me with good quality IW fonts printed on good paper which I've scanned in as GIFs, we need to convert these to binary bitmaps and populate these arrays with. The following array holds a bitmap for the currently printing tractor print head line: iw_current_line_buffer[9][136*8]; //8 lines 136 dots/in*8 inches at 9bits! What byte of the current line are we on - this is the print head cursor: uint16 iw_current_line_ptr; What vertical pixel are we looking at (line 0..9) uint16 iw_current_vert_ribbon; What's the maximum black pixel value we've printed over. We'll use this to represent pure black (RGB: 0x000000) and we'll use this to scale the lesser values of black. Dot Matrix printers make stuff bold by printing over and over a spot. That's what this is used for. uint8 iw_max_black; iw_clear_page(void) clears the page. initialize_image_writer(void) -- currently a synonim for clear page, but later we might need to get more initialization code done. Basically this should be called to reset the IW setting to the defaults before printing. iw_clear_buffer(void) - clears the current line. iw_write_vert_line(uint8 data, uint8 offset) -- writes a font character's vertical line into the line buffer. iw_feed_line(void) - this saves the current line buffer out to the printing device. The rest of the IW emulator is incomplete, we need a state machine to accept characters from the Lisa's serial port and render them out. Finnaly we need graphics routines that capture an entire 8.5"x11" paper and allow the user to preview it, then we'll send it to the local printer. On the Mac this is very easy to do. On unix we'll need to write a bitmap to postscript translator. /lisaem/hw/profile/profile.c This implements the profile hard drive state machine. Each profile disk image will have a 2048 byte header indicating various info about the disk image and the attached profile. The ProfileType type definition is applied to each profile. This structure contains all the settings and info for the state machine. The ProFile_Spare_table array is a virtual block that's returned to the Lisa when the Lisa wants to get info on the profile. (will ask for sector -1 to get this info.) There are no used spare sectors as this is a virtual profile and so it's "perfect." do_profile_read(uint32 block) do_profile_write(uint32 block) These functions are internal and do the actual block reads and writes. They're dispatched by the profile state machine. Profile_Reset(ProfileType *P) should be called for each attached Profile drive when the emulator starts up, and is called when the Lisa sends a reset signal to the profile. ProfileLoop(ProfileType *P, int event) is dispatched by the VIA and this implements the ProfileState machine. See the actual file for the Profile protocol. /lisaem/tools This is a currently empty directory that will be populated with assorted tools to help with the Lisa emulator, including DTC's disk imager. The /lisaem/debug will contain the built in 68k debugger. /lisaem/doc contains various internal documentation, in the final version, application documentation. /lisaem/files.txt is a computer generate file listing. /lisaem/status.txt is my status file indicating progress. /lisaem/LisaProjectDocs.txt is this file.