================================================================================
Note 10.0                  MicroVAX I I/O Programming                 No replies
JAWS::KAISER                                        229 lines  25-MAR-1985 09:18
--------------------------------------------------------------------------------
      +---------------+					   +-----------------+
      | d i g i t a l |					   |  uNOTE # 010    |
      +---------------+					   +-----------------+


      +----------------------------------------------------+-----------------+
      | Title: MicroVAX I/O Programming			   | Date: 27-JUL-84 |
      +----------------------------------------------------+-----------------+
      | Originator: Peter Jonhson			   | Page 1 of 5     |
      +----------------------------------------------------+-----------------+



      The Qbus MicroVax implements the full Vax memory management, so  virtual
      addresses	 are  translated  to physical addresses - just as they are for
      the Vax minicomputers.  When memory management is	 enabled,  system  and
      process  space  virtual addresses are translated into physical addresses
      and sent onto the Qbus.  Normally,  the  programmmer  need  not  concern
      himself  with  this  translation	as  this  is completely handled by the
      operating system; however, when accessing locations  in  the  I/O	 space
      directly	the  programmer	 must  concern	himself with the mapping since
      specific information must be supplied by the programmer to  MicroVMS  in
      order  for  it to successfully map the user's virtual addresses into the
      I/O space.  The process of mapping  a  virtual  address  to  a  physical
      address  must start by determining the physical address that you wish to
      access.  In our case this means that we must calculate a	Qbus  MicroVax
      physical	address	 given that we know the address that the Qbus board is
      configured to.  In order to do this we must know a few key  facts	 about
      the Qbus MicroVax architecture.




	1) The Qbus MicroVax I/O space begins at physical 20000000 (hex)

	2) The I/O space of a Qbus MicroVax is largely empty containing
	   only Q22 bus I/O space which is 8K bytes long




      Given these two pieces of information we now know that the I/O space for
      the  Qbus	 MicroVax  starts  at  physical	 20000000 (hex) and extends to
      20001FFF (hex).  This I/O space directly corresponds to the configurable
      addresses	 on  Qbus  option  boards  160000-177777  (oct).   In order to
      convert any Qbus option address to a Qbus MicroVax  address  one	simply
      subtracts	 160000	 from  the boards configured address to get its offset
      into the I/O space and then add this value  to  the  base	 of  the  Qbus
      MicroVax I/O space.  For example, let us consider a board which has been
      configured to  166540.   In  order  to  calculate	 its  equivalent  Qbus
      MicroVax address we would do the following:

								Page 2




	1) Subtract off the I/O base address for this board (160000)

			166540 (oct)
		    -	160000 (oct)
		      ---------
			  6540 (oct) -->  D60 (hex)

	2) Add the board's address offset to the Qbus MicroVax I/O space
	   base address

			20000000 (hex)
		    +	     D60 (hex)
		      ----------
			20000D60 (hex)



	   This addition results in the physical address on the Qbus MicroVax
	   system that this board would answer to.


      Now we have calculated the physical address for the board	 in  the  Qbus
      MicroVax	environment.   This value, however, is in the raw state and is
      still not usable by the uVMS software to	perform	 virtual  to  physical
      address  translation.   In  order	 for  this address to be useful to the
      software it must now be converted from a	physical  address  to  a  page
      frame  number.   The  page  is  the  basic  unit	of  memory mapping and
      protection.  A page is 512 contiguous  byte  locations.	A  page	 frame
      number  (PFN)  is	 the  address  of the first byte of a page in physical
      memory.  This means that the lsb of a PFN has the resolution of  1  page
      or  512  bytes.  It is a simple matter now to convert a physical address
      to a PFN.	 Since the lsb of a PFN	 is  1	page  to  convert  a  physical
      address to PFN just shift right the physical address 9 bits, i.e.	 shift
      off the 9 least significant bits.


	physcial 20000D60 (hex)	 shift right 9 --> PFN 100006 (hex)

      The PFN value which we have calculated is sufficient to allow the system
      to  map  a  physcial  page of addresses into your virtual address space.
      The address of the Qbus option resides somewhere in the  page  which  we
      have  mapped.   It  is the responsibility of the programmer to correctly
      offset from the beginning of the page in order to access the board  i.e.
      the  programmer  must displace from the base of the mapped page with the
      correct virtual address  offset.	 To  determine	the  offset  from  the
      beginning	 of the mapped page look to bits 0-9 of the configured address
      of the Qbus option board - this is  the  offset.	 In  our  example  the
      offset would be:

								Page 3




			166540 (oct)
			   | |
			   \ /
			    |
			    --------  540   bits 9-0 are the offset

      This offset would be  used  by  the  programmer  to  access  the	device
      registers	 on  the board.	 Failure to use the offset will usually result
      in an attempt to access non-esxistent  locations	(analagous  to	memory
      time-outs) which will result in an access violation error being returned
      to the user.  A sample program follows which illustrates the  principles
      which  have  been	 discussed.   It uses the same board address discussed
      earlier so that one can see the code needed to  acutally	implement  the
      previous example.



      The following program illustrates, in  a	raw  fashion,  how  one	 might
      actually	access	the  I/O  space	 with  software.   It  is not meant to
      illustrate good or recommended programming practice but rather  to  show
      the mechanics of accessing the I/O space of a Qbus on MicroVax I.

								Page 4




	.title	map_io_space


	;This program will allow a user with suitable privilege to access
	;device registers in the I/O space of a uVax.  This example shows
	;code which is used to extract data from a DRV11 - a general purpose
	;parallel interface which resides in I/O space.	 It is sufficiently
	;general to allow the concept to be used in other situations where
	;access to the I/O space from a user process is desireable.


	;This portion of the program is responsible for creating the
	;virtual to physical mapping required to access registers in
	;the I/O space.	 For this example the device registers are assumed to
	;start at 166540.  In order for virtual to physical mapping to occur
	;the  user must calculate the physcial page frame that the device
	;registers overlap into.  (See accompanying text for how to do this)



	;Create and map section directive does the actual work of mapping.
	;In order for this system service to work correctly the
	;use must have PFNMAP privilege

	.entry	start,^m<>

	$crmpsc_s -
	inadr = maprange, -		;Input virtual address range
	retadr = actadr, -		;Virtual address range acutally
					;mapped
	pagcnt = #1, -			;Non zero required for page frame
					;section
	flags =#<sec$m_expreg!sec$m_pfnmap!sec$m_wrt>, -
	vbn = pfn_number		;Actual page frame of I/O space
					;page which contains device registers

	blbs	r0,continue		;check the return status of create
					;and map - if successful branch

	pushl	r0			;put status onto stack
	calls	#1,g^lib$stop		;tell him what happened and
					;stop program

								Page 5



	;At this point one page of virtual addresses in the user's process
	;space is now mapped into one page of the I/O space.  Now the user
	;can access device registers by using move instructions.
	;...... ** Please note that only certain instructions are allowed when
	;doing physical I/O to the bus.	 For example a MOVL instruction is
	;NOT legal to the I/O space.


	continue:

	movl	actadr, r6		;Get starting virtual address from


					;system service and put into R6
	addl	#^x160, r6		;Add the displacement into this page
					;to access the device registers

	;Access data from the parallel interface

	tstb	(r6)			;Test for data transfer request
	bgew	10$			;If no data exit
	movw	4(r6), data_in_buffer	;Data is present - store it


	10$:
	$exit_s -			;exit gracefully
	code = #1



	;data for program ......

	maprange:	.long	^x400
			.long	^x800

	control_status	.word	0
	data_in_buffer	.word	0

	actadr:		.blkl	2		;holds returned virtual
						; address range
	pfn_number:	.long	^x100006	;actual pfn of I/O page to
						;be mapped

	.end	start

