From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.7 required=5.0 tests=BAYES_00,GAPPY_SUBJECT, INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!mips!news.cs.indiana.edu!arizona.edu!east.pima.edu!rharwood From: rharwood@east.pima.edu Newsgroups: comp.lang.ada Subject: Re: Types defining h/w r/o or w/o registers Message-ID: <1991Jun2.095459.1@east.pima.edu> Date: 2 Jun 91 16:54:59 GMT References: <3949@titan.tsd.arlut.utexas.edu> List-Id: In article <3949@titan.tsd.arlut.utexas.edu>, gardner@titan.tsd.arlut.utexas.edu (Don Gardner) writes: > Is there some way to define a type such that all variables of that > type can be only read or only written? For instance, I have a type that > defines the status register of some peripheral which can only be > read. It would be best if the compiler could flag any assignments > to variables of such a type as errors. > > Is there some other means for commonly handling this problem? The > compiler being used is VADSWorks, if an implementation-defined solution > is required. Well, it's been 2.5 years since I did this, but IMHO "the right way" to do what you are trying is to encapsulate the READ operation in a FUNCTION and the WRITE operation in a one-parameter procedure. Several replies to your message correctly stated that you should "hide the operations in a package," but didn't show how to implement the desired functionality. Naturally, you'd have to change/define types as appropriate, but here's a sample of how I've done it (from memory... don't expect perfect recall!). (Before anyone attacks the "obvious inefficiencies" here, try inserting "PRAGMA INLINE"s for the subprograms and COMPILE it on YOUR compiler, then look at generated assembler code when you CALL them. I believe the compiler we had did almost exactly what the assembler programmer would have done: a direct read from the IO location.) Obviously, you should check the performance issues for YOUR compiler! This is a bit long... but I hope it's helpful. ============================ package spec Package My_Device_Controller is -- -- Your "read-only" register interface: -- -- Define the possible status returned as enumerated: Type Status is (Device_Busy, Device_Idle, Device_Error); -- etc.... -- And attach the appropriate "real" values: For Status use (Device_Busy => 16#01#, -- Define as appropriate Device_Idle => 16#08#, -- for YOUR controller Device_Error => 16#F0#); -- -- Here's the function which provides a "read-only" status value... -- See implementation in package body below. Function device_status return status; -- -- Now, the "write-only" register interface: -- -- Define the possible control values, also enumerated: -- (I'm assuming "read" and "write" commands are concerned with reading/ -- writing device DATA, not CONTROL information.) Type controls is (Write_Command, Read_Command, -- Etc.... add others Status_Command, Reset_Command); -- if needed -- Define the "real values": For Controls use (Write_Command => 16#01#, -- Again, use whatever Read_Command => 16#04#, -- your hardware dudes Status_Command => 16#14#, -- give you (normally Reset_Command => 16#F9#); -- in HEX!) Procedure Device_Command ( command : in controls ); end My_Device_Controller; ============================ package body With Low_Level_IO; -- or maybe you use Memory-Mapped... that's a bit trickier, -- but I've done that too. (Not here, for brevity!) Package Body My_Device_Controller is -- The LRM 14.6 defines Low_Level_IO, but does not explicitly -- define type "device_type"; an exercise for the interested... Status_Register : constant Low_level_IO.Device_type := 16#F001#; Control_Register : constant Low_level_IO.Device_type := 16#F003#; Function device_status return status is results : Low_Level_IO.data_type; begin Low_Level_IO.Receive_Control(Device=> Status_Register, Data => results); Return Results; -- You may need some UNCHECKED_CONVERSION here... end device_status; Procedure Device_Command ( command : in controls ) is begin -- Again, you may need a little CONVERSION... Low_Level_IO.Send_Control(Device=> Control_Register, Data => Command); end Device_Command; end My_Device_Controller; ============================ code usage fragment With My_Device_Controller; Use My_Device_Controller; .. .. Device_Command (Status_command); -- tell the device to report! Case device_Status is When Device_idle => process_whatever_you_want; When Device_busy => dont_do_anything_now; When Device_error => Device_Command(reset_command); -- or whatever! end case; .. .. Device_Command(Write_command); Device_Command(Read_command); ..