TweetFollow Us on Twitter

SCSI Intro
Volume Number:3
Issue Number:3
Column Tag:Forth Forum

Introduction to SCSI Devices

By Jörg Langowski, MacTutor Editorial Board, Grenoble, France

In this article Jörg introduces us to the SCSI routines. Last month, Tim Standing began a series on building a hard disk. Next month, Tim Standing will continue his series with the SCSI driver and formatting program that detects bad disk blocks for his hrad disk project. Until then, this article should help us prepare for the world of SCSI devices from the Forth perspective.

If you have investigated the possibility of building the hard disk published last month, then you know that prices for SCSI hard disks have gone down rapidly even as I write this. And, starting with a naked hard disk drive, a controller card and a power supply, it shouldn't be that difficult to get a hard disk system going, since an example of a (buggy) SCSI driver has already been published several months ago in the Software Supplement by Apple. While we wait for Tim Standing's SCSI example, here are some of my thoughts on the several obstacles that have to be overcome by the naive-thinking person (like me) who just wants to plug it all together and have those 20, 40 or more megabytes of extra space (in my case, it was an 80 megabyte unit from Quantum Co. with an integrated SCSI interface). The first problem, and the major one, is to write a driver for the particular SCSI device. Even though starting from Apple's example makes the job easier, it is by no means trivial to adapt the generic driver to your particular kind of disk reliably.

We'll return to that point later; first, I have to apologize for not being able to print the source code of Apple's SCSI driver in our magazine (for copyright reasons). However, for anybody interested this code should be easy to come by, either from the Software Supplement or by downloading it from Delphi or Compuserve. For those of you familiar with drivers, I'll give a short description of what it does; we'll start with a review of the organization of an SCSI device (also given in IM).

SCSI devices on the Mac+

The SCSI driver resides on the SCSI disk at a position given in the device descriptor map (DDM), which is always block 0 of the SCSI device. Here, the positions and lengths of the drivers available on the disk are stored. Inside Mac describes its format:

( ***The layout of blk 0 of a bootable SCSI device*** )
( Forth Format )
HEX 
 4552   CONSTANT SBSigWord( block 0 signature   )       
    0   CONSTANT SBSig    (  signature word )            
    2   CONSTANT SBBlkSize( block size of device )   
    4   CONSTANT SBBlkCount ( # blocks on device )        
    8   CONSTANT SBDevType( device type code )          
   A    CONSTANT SBDevID
   C    CONSTANT SBData   ( start of data section  )    
   10   CONSTANT SBDrvCount ( # drivers to follow )       
   12   CONSTANT SBDrvrs         ( start of driver descriptors )
( Driver descriptors)
    0   CONSTANT DDBlock  ( physical block of driver )  
    4   CONSTANT DDSize   ( block count of driver   )   
    6   CONSTANT DDType   ( Processor type of driver  ) 

( Macintosh = 1 )

Block 1 of the disk is supposed to contain the device partition map (DPM), which describes the various partitions into which the disk may be split up. (In our case, we'll work with one partition only). The format of the DPM is as follows:

( ***The layout of blk 1 of a bootable SCSI device*** )
( in Forth format   )
HEX
 5453   CONSTANT   PDSigWord  ( block 1 signature   )       
    0   CONSTANT   PDSig  ( PDSigWord goes here )
    2   CONSTANT   PDStart    ( starting block of partition )
    6   CONSTANT   PDSize ( # blocks in partition )     
    A   CONSTANT   PDFSID     
 ( File System ID of partition creator or NIL )
 (  'TFS1' for Macintosh )

In the case of a disk which will only be accessed by a Macintosh, block 2 and the following blocks then contain the disk driver code.

As you may recall, the standard format of a driver consists of a header in which offsets to the five driver routines Open, Close, Control, Status and Prime are kept, followed by the routines themselves (see my last article). The SCSI driver, however, must contain not only those routines, but also some means to install itself at the time the system boots up, so that the hard disk will be bootable.

Therefore the SCSI driver code starts with a JMP instruction to the installation routine. The routine that Apple provides will check whether the SCSI disk is compatible with the Macintosh operating system ( that means that the 'signatures' of block 0 and 1 are correct, the driver type is =1, and the file system ID is 'TFS1'), and if so, create a device control entry for the driver and install it. The system then knows that a new disk is present and will make it available for use.

Other routines provided in the generic driver code are those for opening, block read/write, eject and getting the SCSI disk icon. See Apple's source code for a detailed description.

The important part that will concern us here is how to read or write a block on an SCSI disk, which leads us to the second problem that one encounters when trying to hook up a hard disk to the Mac Plus.

SCSI input/output - a quick overview

Apple, in its infinite wisdom, has decided to leave two important things open as an 'exercise to the reader' (sound familiar?). First, there is no utility that detects (maybe on boot-up?) whether an SCSI device is present, and initialize it using the standard initialization dialog. For doing this, of course, a general purpose SCSI driver would have to be contained in either the System file or in ROM that can then be used for accessing the disk. But since SCSI devices are not quite standardized well enough, Apple might have left that out on purpose.

Second, the SCSI routines in ROM provide only very low-level support. Since, as you'll soon see, the same SCSI command sequences occur over and over again when working with the SCSI bus, Apple should have provided a routine that puts it all together (and they promise to do so, actually, in one of their next System releases, perhaps in the new Macs, recently announced).

Since such support was not available at the time I wrote this, I wrote some routines that simplify SCSI handling; this shall be the subject of this month's column.

SCSI command sequence

The sequence of commands that has to be executed to transfer information to or from an SCSI device is quite complicated. This has to do with the fact the the SCSI bus can be in different 'phases' depending on the state of the control lines. I'll not discuss the electronic details here, but just give a description of the events as they happen one after the other.

First, the device which initiates the transfer (the 'initiator') has to get control of the bus. This is done by executing the SCSIGet command from the SCSI manager. Only one device can have control of the bus at each time; in our case this will most probably be the Macintosh. The initiator then selects a target to transfer data to or from; this is done by calling SCSISelect with the target's address as a parameter. Each address corresponds to one bit of the data bus, so there may be a maximum of eight SCSI devices on one bus. The Macintosh has address 7, corresponding to the highest bit. Usually, if only one SCSI device is connected, it'll have address 6. All of the following examples refer to this setup.

Once SCSIGet and SCSISelect have been called, the link between two devices is established and data transfer may begin. The story becomes more complicated here since there are four types of data that are transferred: commands, 'real' data, status information and messages. Data are always exchanged byte-wise using two command lines for a handshake protocol. The type of the data is determined by the setting of other control lines on the bus.

The transfer sequence generally proceeds in the following way: The initiator sends a command to the target. After the command has been accepted by the target there can be an exchange of 'real' data on the bus, either from the target to the initiator (Read) or the other way (Write). There are also commands that are not followed by any data transfer.

When the data has been exchanged, the target will have some additional information ready as to whether the command has been completed successfully, and for more complicated commands, extra messages.

Again, SCSI manager routines are provided for each step of this sequence. The command is sent by the means of the SCSICommand routine, which accepts as parameters the address of a command block and its total length in bytes. After execution, it will return a status code which is zero if the command has been sent successfully.

Typical command blocks are given in listing 1. All the blocks defined there are preceded by their length; a convention that is used by my routines. The SCSI commands are standardized in some way: a Read command, for any device, will be six bytes long, the command code in the first byte is always $08, and the start position and the number of bytes to transfer are always kept in the same fields of the command block.

When a Read command has been issued, the target will be ready for transferring the requested number of bytes. The Macintosh gets the data through either of two commands: SCSIRead or SCSIRBlind. For a normal Read a handshake is performed on every byte transfer; for a blind Read the Mac just assumes that the target is ready to provide the data at the maximum speed with which it can be read, which is 384 KBytes/sec. This often works, but has to be tested in each individual case.

Commands that transfer data from the initiator to the target are handled by SCSIWrite or SCSIWBlind in an analogous manner.

The parameter that is passed to the SCSI read/write routines is the address of a transfer instruction block, a short sequence of instructions, each 10 bytes long, that form a pseudoprogram. That way one single read may be executed in chunks of - for example - 512 bytes each. As an example let's look at the SCInc instruction: it consists of the command word ($0002), a long word buffer address addr, and a long word byte count n. When this instruction is executed by the SCSIRead command, n bytes will be transferred to/from the buffer starting at addr, and the buffer address - in the pseudoprogram - will be incremented by n. For the SCNoInc instruction, the buffer address is left unchanged.

The pseudoprogram may contain looping instructions so that the same sequence of transfers is executed a defined number of times. In the simple example, I'm not using any of those instructions, but only an SCNoInc followed by an SCStop. This is what Apple recommends you to do in any case, because there is a bug in the SCSI handler in ROM that screws up multi-block transfers. This bug is supposed to be fixed by a patch in System 3.2, but I still had problems even with 3.2.

In summary, to read n bytes from an SCSI device into a buffer starting at addr one would have to:

- store addr and n in the appropriate fields of the pseudoprogram block,

- call SCSICmd with a pointer to the command block for the Read command and the command length on the stack,

- call SCSIRead or SCSIRBlind with a pointer to the pseudoprogram block on the stack.

After executing this sequence, the transfer would either have been completed successfully, or the target would have some extra information waiting about what went wrong. In order to check successful execution of the command, SCSIComplete is called. This routine takes three parameters, a tick count, and the addresses of two variables, message and status. The tick count is the timeout that the Macintosh should allow for completion of the command (successful or non-successful). After completion, two additional types of information are transferred over the bus, namely status information and messages from the target to the identifier. The status information is always one byte which is zero when everything went o.k., the message may consist of several bytes, but in our case is always one byte =0.

The most common status apart from zero (=OK) is status=2, which means check condition. You should the issue a Request Sense command to the SCSI device in that case to find out exactly what unusual condition occurred. The format and meaning of the data returned by Request Sense varies depending on the device. A common condition that occurs with some newer SCSI controllers directly after a reset of the bus (by the SCSIReset command) is Unit attention, which is meant to tell the system that this particular unit needs attention because - for example - it just came back from a reset or power-up. The problem here is that on boot-up, the Macintosh resets the SCSI bus and expects to be able to read immediately from the hard disk. Since no Request Sense has been issued, however, the read fails and the Mac can never boot from the hard disk. The only remedy is to use a controller on which the Unit Attention feature either isn't installed or can be disabled.

After a successfully completed SCSI command, however, SCSIComplete should return zeroes in both message and status.

Let's summarize the complete SCSI command sequence:

• SCSIGet gets control of the bus for the Mac,

• SCSISelect selects the target device,

• SCSICmd issues a command to the target,

• SCSIRead, SCSIRBlind, SCSIWrite, SCSIWblind are used - if necessary - to transfer data to/from the target,

• SCSIComplete waits until the data transfer is completed or a timeout has expired and returns the status and message bytes of the target.

In order to facilitate the handling of this command sequence, five higher-level words are defined in listing 1: doscsi for commands that require no data transfer, doscsi.r and doscsi.rb for normal and blind reads, and doscsi.w and doscsi.wb for normal and blind writes. The parameters to those routines are, from bottom to top on the stack:

- the timeout tick count;

- a pointer to the command block, the first byte of this block must contain the length of the command following it;

- the device number;

and in addition for the data transferring commands

- a pointer to the data buffer;

- the number of bytes to transfer.

A number of standard SCSI command blocks are also predefined in the listing. Using these commands and the high-level words, SCSI handling becomes much easier.

You can now go ahead and try to install your hard disk driver (as mentioned earlier, you should get the generic driver source from Apple for this purpose). The strategy is as follows:

Read the resource that contains the assembled driver code into memory. Using the write.block word, write the driver from memory to the disk, starting at block 2. Verify (by re-reading with read.block and a quick dump) that the blocks were written OK.

Now define a device descriptor map (DDM), using the format given above, and a device partition map (DPM). Write the DDM and DPM to blocks 0 and 1 of the SCSI disk.

Call mount.scsi. This word reserves a system heap block for the driver code and moves the code into that block, then emulates what is happening on boot-up by jumping to the installation routine. Since the driver looks at the system event mask to determine whether we're in the boot up phase, we have to set this mask to zero temporarily to fool the driver installation code. (Note that we'd be in trouble if we didn't reset it afterwards). The driver installation routine also takes a number of input parameters that are not mentioned in Inside Macintosh, but only in the driver source code by Apple: A0 contains a pointer to the device partition map (which therefore should have been read first), and D5 contains the SCSI ID of the device to be installed. The glue routine call.driver is used to call the installation routine.

Assuming you have started from a factory-fresh disk, it still remains to install the boot blocks and basic dirctory structure. This can be done with the disk initialization package, using its function DIZero. Although I'll leave the Forth code to do the initialization for my next column, I'll shortly describe the strategy. DIZero needs a drive number and a disk name to initialize the disk. The disk name can be chosen freely; the drive number has to be found. What is the drive number of the SCSI disk?

Since we just installed the driver, the SCSI disk will be the last element in the drive queue. Therefore, we look in the QTail field of the drive queue header (system global $308) for the queue element, which contains the drive number in its dQDrive field. Actually, the drive number of the first SCSI disk installed is 5.

More about SCSI installation in my next column. We'll change subjects a little and hear about an interesting aspect of the new Mach 2.1 update.

A0 optimizer in Mach 2.1

As you might have noticed when disassembling Forth code (be it Mach 2, MacForth or any other Forth), the machine is often forced to do unnecessary register saves and loads. This happens for instance when at the end of one word the contents of D0 are pushed on the stack, only to pop them off again into D0 at the beginning of the next word! (See listing 2). When each Forth word is called as a subroutine, or through an address interpreter, such behavior is a necessary consequence of the threaded-code structure. But in a system like Mach2 where many words lead to inline 68000 code generation, this leads to ridiculous code sequences like

 MOVE.L    D0,-(A6) 
 MOVE.L    (A6)+,D0   

which translates to: "Give me a break, I have to leave this number somewhere for a while... ah... there's the stack... might just as well drop it there... ... ... OK, now let's pick it up again and go on." Not really necessary, is it. (Things like that are known to happen in some Pascal code, too).

The new release of Mach 2, 2.1, automatically recognizes some of those situations, especially when D0 is involved, and removes redundant code (listing 2a). With registers other than D0, some optimization is done, too, but you can still find some 'one-hand juggling' like MOVE.L D1,D1.

I'll write more about the Mach 2.1 update and about MacForth Plus in my next column. MacForth Plus just arrived here, and it seems like a major change and major improvement over the older MacForth versions. Wait for a comparison of the two Forth systems in the next issue of MacTutor.

FindWindow trick

One last remark regarding my last column on writing a desk accessory in Mach2. You remember that I rewrote the zoom box and size box recognition parts of the mouse click handler, because FindWindow always returns a part code =2 if you click in a desk accessory window.

Here's a very clever trick from Kamal Gaddas of our developer's club: Before you call FindWindow, change the WindowKind field of the desk accessory's window record to a value 8 to indicate that this is a normal application-created window, and the correct part code will be returned. Then change the WindowKind back to the (negative) desk accessory reference number.

{1}
Listing 1 :   Mach 2 routines for simplified SCSI bus handling
( Forth SCSI routines, J. Langowski Dec. 1986 )
only forth also mac also assembler

CODE SCSIReset
 CLR.W -(A7)
 MOVE.W #0,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

CODE SCSIGet
 CLR.W -(A7)
 MOVE.W #1,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

CODE SCSISelect ( TargetID -- SCSIErrorResult )
 MOVE.L (A6)+,D0
 CLR.W -(A7)
 MOVE.W D0,-(A7)
 MOVE.W #2,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

CODE SCSICmd  ( buffer count -- SCSIErrorResult )
 MOVE.L (A6)+,D0
 MOVE.L (A6)+,D1
 CLR.W -(A7)
 MOVE.L D1,-(A7)
 MOVE.W D0,-(A7)
 MOVE.W #3,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

CODE SCSIComplete ( waitTicks mess stat -- SCSIErrorResult )
 CLR.W -(A7)
 MOVE.L (A6)+,-(A7)
 MOVE.L (A6)+,-(A7)
 MOVE.L (A6)+,-(A7)
 MOVE.W #4,-(A7)
 _SCSIDispatch
 MOVE.W (A7)+,D0
 EXT.L  D0
 MOVE.L D0,-(A6)
 RTS
END-CODE

1 CONSTANT SCInc
2 CONSTANT SCnoInc
3 CONSTANT SCAdd
4 CONSTANT SCMove
5 CONSTANT SCLoop
6 CONSTANT SCNop
7 CONSTANT SCStop
8 CONSTANT SCComp

variable scbuf 2048 vallot  ( general purpose SCSI buffer )
variable scmess  variable scstat 
 ( used only within the lower-level routines )

create SCSIProg
 scnoinc w, 
 0 , ( buffer address )   
 0 , ( # of bytes to transfer )
 scstop  w,

: >scbuf scsiprog  2+ ! ;
: >sc#bytes scsiprog 6 + ! ;

( lower level SCSI routines )

: initiate.scsi ( cmdblk device# -- )
 SCSIGet abort"  get error"
 ( dev# ) SCSISelect abort"  select error"
 ( cmdblk ) dup 1+ swap c@ SCSICmd abort"  cmd error"
;

: finish.scsi ( #ticks -- message status )
 ( #ticks )  
 scmess scstat SCSIComplete abort"  complete error"
 scmess w@ scstat w@
;

( general purpose SCSI handler routines )
( five different words are provided, depending on whether )
( - no data phase is necessary :  DOSCSI )
( - data will be transferred TO the initiator, i.e. the Mac : )
(   DOSCSI.R for normal reads, DOSCSI.RB for blind reads )
( - data will be transferred FROM the initiator : )
(   DOSCSI.W for normal writes, DOSCSI.WB for blind writes )

: doscsi ( #ticks cmdblk device# -- message status )
 initiate.scsi
 finish.scsi
;

: doscsi.r 
 ( #ticks cmdblk device# buf #bytes -- message status )
 >sc#bytes  >scbuf 
 initiate.scsi
 SCSIProg call SCSIRead abort" SCSI read error"
 finish.scsi
;

: doscsi.w 
 ( #ticks cmdblk device# buf #bytes -- message status )
 >sc#bytes  >scbuf 
 initiate.scsi
 SCSIProg call SCSIWrite abort" SCSI write error"
 finish.scsi
;

: doscsi.rb 
 ( #ticks cmdblk device# buf #bytes -- message status )
 >sc#bytes  >scbuf 
 initiate.scsi
 SCSIProg call SCSIRBlind abort" SCSI read blind error"
 finish.scsi
;

: doscsi.wb 
 ( #ticks cmdblk device# buf #bytes -- message status )
 >sc#bytes  >scbuf 
 initiate.scsi
 SCSIProg call SCSIWBlind abort" SCSI write blind error"
 finish.scsi
;

HEX
( SCSI command block definitions )
( first byte contains command length, 
 following bytes the command )

create test.rdy.blk
 6 c,
 0 c, ( test unit ready )
 0 , 
 0 w, ( word align )

create rezero.blk
 6 c,
 1 c, ( rezero unit )
 0 , 0 w,

create reqsense.blk
 6 c,
 3 c, ( request sense )
 13 , ( 19 bytes of sense data )
 0 w,

create format.blk
 6 c,
 4 c, ( format unit )
 0 c, ( default formatting )
 0 c, ( data pattern )
 0 w, ( interleave, ignored by Q200 )
 0 w,

create init.blk ( for erasing and initializing unit )
 6 c,
 4 c, ( format unit )
 10 c,  ( format using defect list )
 0 c, ( data pattern )
 0 w, ( interleave, ignored by Q200 )
 0 w,

create init.dlist ( defect list for initializing unit )
 1 w, ( data pattern bit set )
 0 w,

create reassign.blk
 6 c,
 7 c, ( reassign blocks )
 0 , 0 w,

create read.blk
 6 c,
 8 c, ( read )
 0 w, 0 c, ( logical block address )
 0 c, ( # blocks to transfer )
 0 w,

create write.blk
 6 c,
 A c, ( write )
 0 w, 0 c, ( logical block address )
 0 c, ( # blocks to transfer )
 0 w,

create seek.blk
 6 c,
 B c, ( seek )
 0 w, 0 c, ( logical block address )
 0 c,
 0 w,

create inquiry.blk
 6 c,
 12 c,  ( inquiry )
 0 w, 0 c,
 34 c,  ( 34 device bytes returned )
 0 w,

create modesel.blk
 6 c,
 15 c,  ( mode select )
 0 w, 0 c,
 0 c, ( param list length )
 0 w,

( reserve, release, copy - not yet implemented )

create modesense.blk
 6 c,
 1A c,  ( mode sense )
 0 c,
 0 c, ( page code )
 0 c,
 0 c, ( allocation length )
 0 w,

create startstop.blk
 6 c,
 1B c,  ( start/stop unit )
 0 c, ( bit 0 = IMMED )
 0 c, 0 c,
 0 c,   ( bit 0 = START )
 0 w,

( receive/send diagnostics - not yet implemented )

create readcap.blk
 A c,
 25 c,  ( read capacity )
 0 c, ( bit 0 = RELADR )
 0 c, 0 w, 0 c,  ( 4 bytes logical block address )
 0 c, 0 c,
 0 c, ( bit 0 = PMI )
 0 w,

create readext.blk
 A c,
 28 c,  ( read extended )
 0 c, ( bit 0 = RELADR )
 0 c, 0 w, 0 c,  ( 4 bytes logical block address )
 0 c, 
 0 w, ( 2 bytes transfer length )
 0 w,

create writext.blk
 A c,
 2A c,  ( write extended )
 0 c, ( bit 0 = RELADR )
 0 c, 0 w, 0 c,  ( 4 bytes logical block address )
 0 c, 
 0 w, ( 2 bytes transfer length )
 0 w,

create seekext.blk
 A c,
 2B c,  ( seek extended )
 0 c, ( bit 0 = RELADR )
 0 c, 0 w, 0 c,  ( 4 bytes logical block address )
 0 c, 
 0 ,
 
( compare - not yet implemented )

create verify.blk
 A c,
 2F c,  ( verify )
 0 c, ( bit 0 = RELADR, bit 1 = BYTCHK )
 0 c, 0 w, 0 c,  ( 4 bytes logical block address )
 0 c, 
 0 w, ( verification length )
 0 w,

( read defect data, read/write data buffer - not yet implemented )

DECIMAL

6 CONSTANT myDisk( SCSI address of my Disk )

variable numstring 20 vallot
: input-number numstring 1+ 20 expect  numstring number? drop ;
 
: wait { nticks | #ticks -- }
 call tickcount -> #ticks
 BEGIN pause
 call tickcount #ticks -
 nticks >
 UNTIL
;

( SCSI routines follow )

: disp.s.m  ." Stat, Mess = " . . cr ;

: rsc scsireset ." reset code = " . cr ;

: format 600 format.blk myDisk doscsi disp.s.m ;

: vfy { | start -- }
 ." enter start block : " input-number 256 /mod 
 verify.blk 2+ ! verify.blk 6 + c!  
 0 verify.blk 2+ c!
 ." enter # blocks : "   input-number verify.blk 8 + w! 
 6000 verify.blk myDisk doscsi  disp.s.m
;

: modesense
 63 modesense.blk 3 + c!
 84 modesense.blk 5 + c!
 120 modesense.blk myDisk scbuf 84 doscsi.rb
 disp.s.m
;

: reqsense
 120 reqsense.blk myDisk scbuf 19 doscsi.rb
 disp.s.m
 hex 
 20 0 do scbuf i + c@ . loop 
 decimal
;
 
: sense modesense scbuf 100 dump ;

: read.block ( block# -- )
 256 /mod read.blk 2+ w! read.blk 4 + c!
 1 read.blk 5 + c!
 120 read.blk myDisk scbuf 512 doscsi.r
 disp.s.m
;

: seek.block ( block# -- )
 256 /mod seek.blk 2+ w! seek.blk 4 + c!
 120 seek.blk myDisk doscsi
 disp.s.m
;

: write.block ( block# -- )
 256 /mod write.blk 2+ w! write.blk 4 + c!
 1 write.blk 5 + c!
 120 write.blk myDisk scbuf 512 doscsi.w
 disp.s.m
;

create ddm 512 allot
create dpm 512 allot
create driver.block 2048 allot

: read.ddm
 0 read.blk 2+ w! 0 read.blk 4 + c!
 1 read.blk 5 + c!
 120 read.blk myDisk ddm 512 doscsi.r
 2drop
;

: read.dpm
 0 read.blk 2+ w! 1 read.blk 4 + c!
 1 read.blk 5 + c!
 120 read.blk myDisk dpm 512 doscsi.r
 2drop
;

.TRAP   _newptr,sys     $A51E
hex 144 CONSTANT SysEvtMask decimal

VARIABLE syshp.drvr

: install.driver { | dstart dlength dbytes pointer -- }
 read.ddm 
 ddm 18 +  @ -> dstart
 ddm 22 + w@ -> dlength
 dlength 512 * -> dbytes
 dstart 256 /mod read.blk 2+ w! read.blk 4 + c!
 dlength read.blk 5 + c!
 120 read.blk myDisk driver.block 512 dlength * doscsi.r
 2drop
 dbytes MOVE.L (A6)+,D0
      _newptr,sys ( get memory block in system heap )
      MOVE.L A0,-(A6)   -> pointer
 pointer 
 IFdriver.block pointer dbytes cmove
 pointer syshp.drvr !
      ELSE ." Not enough system heap for installation." cr
      THEN
;

CODE call.driver
 MOVE.L D5,-(A7)
 MOVE.L (A6)+,D5
 MOVE.L (A6)+,A0
 execute
 MOVE.L (A7)+,D5
 RTS
END-CODE
 
: rdy.scsi
 scsireset drop
 240 wait ( until disk has finished resetting )
 120 reqsense.blk myDisk scbuf 19 doscsi.rb 2drop
;

: mount.scsi
 rdy.scsi
 install.driver 
 read.dpm
 SysEvtMask @
 0 SysEvtMask !
 syshp.drvr @ dpm myDisk call.driver
 SysEvtMask !
;

: test.blks 10 0 do i read.block scbuf 64 dump cr loop ;

: mount.n.bye mount.scsi bye ;

: read.cap
 120 readcap.blk myDisk scbuf 8 doscsi.rb
 abort" Can't read capacity" drop
 cr
 ." This disk contains " scbuf @ dup . 
 ."  blocks of " scbuf 4 + @ dup . ."  bytes." cr
 ." Total capacity is " 1024 */ . ."  Kbytes." cr
;
{2}
Listing 2:  Example of code optimization under Mach 2.1
a. using built-in words

: test   3   ;
: test1   swap   ;
: test2   3   swap   ;

' test 10 il 
( output by the Mach 2.1 disassembler )
test
01D664:     MOVEQ.L   #$3,D0     $3 
01D666:     MOVE.L    D0,-(A6)                            
01D668:     RTS                                           
test1
01D66A:     MOVE.L    (A6)+,D0                            
01D66C:     MOVE.L    (A6)+,D1                            
01D66E:     MOVE.L    D0,-(A6)                            
01D670:     MOVE.L    D1,-(A6)                            
01D672:     RTS                                           
test2
01D674:     MOVEQ.L   #$3,D0 

( the following code would have been generated here under the 
  previous version and is deleted by the 2.1 optimizer )
 MOVE.L    D0,-(A6) 
 MOVE.L    (A6)+,D0   
                           
01D676:     MOVE.L    (A6)+,D1                            
01D678:     MOVE.L    D0,-(A6)                            
01D67A:     MOVE.L    D1,-(A6)                            
01D67C:     RTS                   

b. using newly defined words

CODE test2+
 move.l (a6)+,d0
 addq.l #2,d0
 move.l d0,-(a6)
 rts
END-CODE MACH

: test1 test2+  test 2+ ;

CODE testa2+
 move.l (a6)+,d1
 addq.l #2,d1
 move.l d1,-(a6)
 rts
END-CODE MACH

: test2 testa2+ testa2+ ;

- Disassembler output -

test2+
01D6C4: MOVE.L (A6)+,D0       
01D6C6: ADDQ.L #$2,D0       
01D6C8: MOVE.L D0,-(A6)       
01D6CA: RTS       
test1
01D6CC: MOVE.L (A6)+,D0       
01D6CE: ADDQ.L #$2,D0       
01D6D0: ADDQ.L #$2,D0       
01D6D2: MOVE.L D0,-(A6)       
01D6D4: RTS       
testa2+
01D6D6: MOVE.L (A6)+,D1       
01D6D8: ADDQ.L #$2,D1       
01D6DA: MOVE.L D1,-(A6)       
01D6DC: RTS       
test2
01D6DE: MOVE.L (A6)+,D1       
01D6E0: ADDQ.L #$2,D1       
01D6E2: MOVE.L D1,D1  (!)
01D6E4: ADDQ.L #$2,D1       
01D6E6: MOVE.L D1,-(A6)       
01D6E8: RTS       
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

NetShade 6.3.1 - Browse privately using...
NetShade is an anonymous proxy and VPN app+service for Mac. Unblock your Internet through NetShade's high-speed proxy and VPN servers spanning seven countries. NetShade masks your IP address as you... Read more
Dragon Dictate 4.0.7 - Premium voice-rec...
With Dragon Dictate speech recognition software, you can use your voice to create and edit text or interact with your favorite Mac applications. Far more than just speech-to-text, Dragon Dictate lets... Read more
Persecond 1.0.2 - Timelapse video made e...
Persecond is the easy, fun way to create a beautiful timelapse video. Import an image sequence from any camera, trim the length of your video, adjust the speed and playback direction, and you’re done... Read more
GIMP 2.8.14p2 - Powerful, free image edi...
GIMP is a multi-platform photo manipulation tool. GIMP is an acronym for GNU Image Manipulation Program. The GIMP is suitable for a variety of image manipulation tasks, including photo retouching,... Read more
Sandvox 2.10.2 - Easily build eye-catchi...
Sandvox is for Mac users who want to create a professional looking website quickly and easily. With Sandvox, you don't need to be a Web genius to build a stylish, feature-rich, standards-compliant... Read more
LibreOffice 5.0.1.2 - Free, open-source...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
f.lux 36.1 - Adjusts the color of your d...
f.lux makes the color of your computer's display adapt to the time of day, warm at night and like sunlight during the day. Ever notice how people texting at night have that eerie blue glow? Or wake... Read more
VirtualBox 5.0.2 - x86 virtualization so...
VirtualBox is a family of powerful x86 virtualization products for enterprise as well as home use. Not only is VirtualBox an extremely feature rich, high performance product for enterprise customers... Read more
File Juicer 4.43 - Extract images, video...
File Juicer is a drag-and-drop can opener and data archaeologist. Its specialty is to find and extract images, video, audio, or text from files which are hard to open in other ways. In computer... Read more
Apple MainStage 3.2 - Live performance t...
MainStage 3 makes it easy to bring to the stage all the same instruments and effects that you love in your recording. Everything from the Sound Library and Smart Controls you're familiar with from... Read more

ReBoard: Revolutionary Keyboard (Utilit...
ReBoard: Revolutionary Keyboard 1.0 Device: iOS Universal Category: Utilities Price: $1.99, Version: 1.0 (iTunes) Description: Do everything within the keyboard without switching apps! If you are in WhatsApp, how do you schedule a... | Read more »
Tiny Empire (Games)
Tiny Empire 1.1.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1.3 (iTunes) Description: Launch cannonballs and blow tiny orcs into thousands of pieces in this intuitive fantasy-themed puzzle shooter! Embark on an... | Read more »
Astropad Mini (Productivity)
Astropad Mini 1.0 Device: iOS iPhone Category: Productivity Price: $4.99, Version: 1.0 (iTunes) Description: *** 50% off introductory price! ​*** Get the high-end experience of a Wacom tablet at a fraction of the price with Astropad... | Read more »
Emo Chorus (Music)
Emo Chorus 1.0.0 Device: iOS Universal Category: Music Price: $1.99, Version: 1.0.0 (iTunes) Description: Realistic Choir simulator ranging from simple Chorus emulation to full ensemble Choir with 128 members. ### introductory offer... | Read more »
Forest Spirit (Games)
Forest Spirit 1.0.5 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.5 (iTunes) Description: | Read more »
Ski Safari 2 (Games)
Ski Safari 2 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: The world's most fantastical, fun, family-friendly skiing game is back and better than ever! Play as Sven's sister Evana, share... | Read more »
Lara Croft GO (Games)
Lara Croft GO 1.0.47768 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.47768 (iTunes) Description: Lara Croft GO is a turn based puzzle-adventure set in a long-forgotten world. Explore the ruins of an ancient... | Read more »
Whispering Willows (Games)
Whispering Willows 1.23 Device: iOS Universal Category: Games Price: $4.99, Version: 1.23 (iTunes) Description: **LAUNCH SALE 50% OFF** - Whispering Willows is on sale for 50% off ($4.99) until September 9th. | Read more »
Calvino Noir (Games)
Calvino Noir 1.1 Device: iOS iPhone Category: Games Price: $3.99, Version: 1.1 (iTunes) Description: The film noir stealth game. Calvino Noir is the exploratory, sneaking adventure through the 1930s European criminal underworld.... | Read more »
Angel Sword (Games)
Angel Sword 1.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.0 (iTunes) Description: Prepare to adventure in the most epic full scale multiplayer 3D RPG for mobile! Experience amazing detailed graphics in full HD.... | Read more »

Price Scanner via MacPrices.net

Big Grips Lift Handle For iPad Air and iPad A...
KEM Ventures, Inc. which pioneered the extra-large, super-protective iPad case market with the introduction of Big Grips Frame and Stand in 2011, is launching Big Grips Lift featuring a new super-... Read more
Samsung Launches Galaxy Tab S2, Its Most Powe...
Samsung Electronics America, Inc. has announced the U.S. release of the Galaxy Tab S2, its thinnest, lightest, ultra-fast tablet. Blending form and function, elegant design and multitasking power,... Read more
Tablet Screen Sizes Expanding as iPad Pro App...
Larger screen sizes are gaining favor as the tablet transforms into a productivity device, with shipments growing 185 percent year-over-year in 2015. According to a new Strategy Analytics’ Tablet... Read more
Today Only: Save US$50 on Adobe Elements 13;...
Keep the memories. lose the distractions. Summer’s winding down and it’s time to turn almost perfect shots into picture perfect memories with Elements 13. And get the power to edit both photos and... Read more
1.4GHz Mac mini on sale for $449, save $50
Best Buy has the 1.4GHz Mac mini on sale for $50 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Price for online orders only, in-store price may vary... Read more
12-inch 1.1GHz Gold MacBook on sale for $1149...
B&H Photo has the 12″ 1.1GHz Gold Retina MacBook on sale for $1149.99 including free shipping plus NY sales tax only. Their price is $150 off MSRP, and it’s the lowest price available for this... Read more
27-inch 3.3GHz 5K iMac on sale for $1849, sav...
Best Buy has the 27″ 3.3GHz 5K iMac on sale for $1849.99. Their price is $150 off MSRP, and it’s the lowest price available for this model. Choose free shipping or free local store pickup (if... Read more
Worldwide Tablet Shipments Expected to Declin...
Does Apple badly need a touchscreen convertible/hybrid laptop MacBook? Yes, judging from a new market forecast from the International Data Corporation (IDC) Worldwide Quarterly Tablet Tracker, which... Read more
Continued PC Shipment Shrinkage Expected Thro...
Worldwide PC shipments are expected to fall by -8.7 percent in 2015 and not stabilize until 2017, according to the latest International Data Corporation (IDC) Worldwide Quarterly PC Tracker data. The... Read more
Imminent iPhone 6s Announcement Leads To 103%...
NextWorth Solutions, with its online and in-store electronics trade-in programs including http://NextWorth.com, reports that it has experienced a 103 percent surge in quoted trade-in values over the... Read more

Jobs Board

*Apple* Music, Business Operations - Apple I...
Changing the world is all in a day039s work at Apple . If you love innovation, here039s your chance to make a career of it. You039ll work hard. But the job comes with Read more
WW *Apple* Retail Online Store: Customer In...
**Job Summary** The Apple Retail - Online Store is seeking an experienced web merchandising analytics professional to join the Customer Insights Team. The Web Read more
Senior Payments Security Manager - *Apple*...
**Job Summary** Apple , Inc. is looking for a highly motivated, innovative and hands-on senior payments security manager to join the Apple Pay security team. You will Read more
Software QA Engineer, *Apple* Pay Security...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Business Process Engineer ( *Apple* Online S...
**Job Summary** The Apple Online Support Planning team is looking for an experienced Business Process engineer to lead key business process improvement initiatives Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.