* Is there a better (Ada) way? @ 2003-10-22 18:56 Mike Silva 2003-10-22 19:33 ` sk ` (3 more replies) 0 siblings, 4 replies; 10+ messages in thread From: Mike Silva @ 2003-10-22 18:56 UTC (permalink / raw) I've started writing a little CPU simulator, just for fun and to be doing *something* in Ada, and I want to make sure I'm not writing "C in Ada" when it comes to all the bit, bitfield and register manipulations. Below is a typical question. I need to add a 5-bit signed offset to a 16-bit register. The way I came up with is shown on the last line of the example code, but I want to find out if there's a more Ada-ish way to do what I'm doing. Any comments about any part of the example code are welcome. Mike -------- example code -------- procedure test is type Reg16_t is mod 2**16; -- 16 bit register for Reg16_t'Size use 16; type Offset5_t is range -2**4..2**4-1; -- 5 bit signed offset for Offset5_t'Size use 5; type Dummy_t is mod 2**3; -- just take up extra 3 bits in byte, for this example for Dummy_t'Size use 3; type Postbyte_t is -- typical opcode postbyte record dummy : Dummy_t; offset5 : Offset5_t; end record; for Postbyte_t use record dummy at 0 range 5..7; offset5 at 0 range 0..4; end record; for Postbyte_t'Size use 8; R16 : Reg16_t; PB : Postbyte_t; begin .... R16 := R16 + Reg16_t( Integer( PB.offset5 ) mod Reg16_t'Modulus ); -- the above line works, but is it good Ada, or C-in-Ada? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-22 18:56 Is there a better (Ada) way? Mike Silva @ 2003-10-22 19:33 ` sk 2003-10-23 18:33 ` Mike Silva 2003-10-22 20:50 ` Robert I. Eachus ` (2 subsequent siblings) 3 siblings, 1 reply; 10+ messages in thread From: sk @ 2003-10-22 19:33 UTC (permalink / raw) To: comp.lang.ada Mike Silva <snarflemike@yahoo.com>: > ... sure I'm not writing "C in Ada" ... I was playing with an assembler written in Ada a while ago. I also played with a small kernel. After trying many awkward Ada ways, I came to the conclusion that sometimes the "C" (masking, shifting etc) way was a lot cleaner to look at, read and maintain than hammering it into an "Ada way" of doing it. So maybe, at the bit-twiddling level, C-in-Ada might not be a bad way to go. -- ------------------------------------------------- -- Merge vertically for real address -- -- s n p @ t . o -- k i e k c c m ------------------------------------------------- ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-22 19:33 ` sk @ 2003-10-23 18:33 ` Mike Silva 0 siblings, 0 replies; 10+ messages in thread From: Mike Silva @ 2003-10-23 18:33 UTC (permalink / raw) sk <noname@myob.com> wrote in message news:<mailman.179.1066850672.25614.comp.lang.ada@ada-france.org>... > Mike Silva <snarflemike@yahoo.com>: > > ... sure I'm not writing "C in Ada" ... > > I was playing with an assembler written in Ada a while > ago. I also played with a small kernel. > > After trying many awkward Ada ways, I came to the > conclusion that sometimes the "C" (masking, shifting > etc) way was a lot cleaner to look at, read and maintain > than hammering it into an "Ada way" of doing it. > > So maybe, at the bit-twiddling level, C-in-Ada might > not be a bad way to go. > I understand what you're saying, but I do want to force myself to do this in the spirit of Ada for the learning value. Maybe I'll learn that you're right! :) ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-22 18:56 Is there a better (Ada) way? Mike Silva 2003-10-22 19:33 ` sk @ 2003-10-22 20:50 ` Robert I. Eachus 2003-10-23 16:57 ` Mike Silva 2003-10-23 3:12 ` Steve 2003-10-24 22:20 ` Nick Roberts 3 siblings, 1 reply; 10+ messages in thread From: Robert I. Eachus @ 2003-10-22 20:50 UTC (permalink / raw) Mike Silva wrote: > I've started writing a little CPU simulator, just for fun and to be > doing *something* in Ada, and I want to make sure I'm not writing "C > in Ada" when it comes to all the bit, bitfield and register > manipulations. > > Below is a typical question. I need to add a 5-bit signed offset to a > 16-bit register. The way I came up with is shown on the last line of > the example code, but I want to find out if there's a more Ada-ish way > to do what I'm doing. Any comments about any part of the example code > are welcome. > R16 : Reg16_t; > PB : Postbyte_t; > begin > .... > R16 := R16 + Reg16_t( Integer( PB.offset5 ) mod Reg16_t'Modulus ); > -- the above line works, but is it good Ada, or C-in-Ada? Probably not. R16 := R16 + Reg16_t(PB.offset5); Should do exactly the same thing--but it doesn't. I would probably write: R16 := Reg16_t(Integer(R16) + Integer(PB.offset5)); However, you need to think about what you want to happen when you add a positive offset to R16'Last, or a negative offset to Reg16'First. If you do want wraparound semantics, you can probably suppress Constraint_Error and use the first line I supplied. And incidently, it is pretty common in Ada when doing things like this that you have to think about which exceptional cases you don't want detected, instead of which special cases you do want to handle. -- Robert I. Eachus "Quality is the Buddha. Quality is scientific reality. Quality is the goal of Art. It remains to work these concepts into a practical, down-to-earth context, and for this there is nothing more practical or down-to-earth than what I have been talking about all along...the repair of an old motorcycle." -- from Zen and the Art of Motorcycle Maintenance by Robert Pirsig ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-22 20:50 ` Robert I. Eachus @ 2003-10-23 16:57 ` Mike Silva 2003-10-23 21:42 ` Robert I. Eachus 0 siblings, 1 reply; 10+ messages in thread From: Mike Silva @ 2003-10-23 16:57 UTC (permalink / raw) "Robert I. Eachus" <rieachus@comcast.net> wrote in message news:<3F96ED50.2040009@comcast.net>... > > R16 := R16 + Reg16_t( Integer( PB.offset5 ) mod Reg16_t'Modulus ); > > -- the above line works, but is it good Ada, or C-in-Ada? > > R16 := R16 + Reg16_t(PB.offset5); > > Should do exactly the same thing--but it doesn't. Do you mean that the language should have been defined so that the conversion in the 2nd line acts like the 1st, with negative numbers? Or ??? Mike ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-23 16:57 ` Mike Silva @ 2003-10-23 21:42 ` Robert I. Eachus 2003-10-24 1:42 ` Mike Silva 0 siblings, 1 reply; 10+ messages in thread From: Robert I. Eachus @ 2003-10-23 21:42 UTC (permalink / raw) Mike Silva wrote: > "Robert I. Eachus" <rieachus@comcast.net> wrote in message news:<3F96ED50.2040009@comcast.net>... > >>> R16 := R16 + Reg16_t( Integer( PB.offset5 ) mod Reg16_t'Modulus ); >>>-- the above line works, but is it good Ada, or C-in-Ada? >> >> R16 := R16 + Reg16_t(PB.offset5); >> >>Should do exactly the same thing--but it doesn't. > > > Do you mean that the language should have been defined so that the > conversion in the 2nd line acts like the 1st, with negative numbers? > Or ??? > > Mike Yes. I believe that this will be "fixed" in the next version of the standard, but for now you will find compilers that raise Constraint_Error when converting a negative value to a modular type. Suppressing Constraint_Error for this one line makes it all come out right, if there is nothing that should be a Constraint_Error. It is one of those nasty complex glitches that make language definition so hard. There may not be a valid representation for a negative value of an unsigned type, so it looks like the "right" rule. But in reality, there must be a valid representation of the current value--the current one--and arithmetic works correctly after a possible sign extension for modular types with binary modulii. Incidently I thought of what may be a better way to do it, but to do it efficiently is tricky. Define a sign extention intrinsic operation, then do a normal addition. This works great on most hardware. Do a left shift that puts the bits in the high order position, then a sign extending right shift. Not great on a Pentium 4, but most other processors have a barrel-shifter that can do the two instructions quickly. And you can always write: if PB.offset5 >= 0 then R16 := R16 + Reg16_t(PB.offset5); else R16 := R16 - Reg16_t(-PB.offset5); end if; On some compilers you will get better performance than the version with the explicit mod operation, since even 16-bit division tends to be slow. But as I said the best code is probably to use pragma Suppress(Range_Check, Reg16_t); I can't imagine any case other than this where you might want the check to be made for a binary modular type like Reg16_t, so you can probably put the pragma with the type declaration. Hmmm, thinking more about it, the compiler is not required to do the sign extension in that case, but the following should always work right: function To_Reg16(Value: in Offset5_t) return Reg16_t is type Integer16 is range -2**15..2**15-1; for Integer16'Size use 16; function UC is new Ada.Unchecked_Conversion(Integer16, Reg16_t); begin return UC(Integer16(Value)); end To_Reg16; pragma Inline(To_Reg16); A lot of work to eliminate one mod operation, but now you can write: R16 := To_Reg16(PB.offset5); And be sure it is portable. If you have a lot of these operations, it may be worth it. Of course, it will take an awful lot of instances to justify all this analysis, but I think this is all covered under the learning experience heading. The lesson that should be coming through is that Ada programmers care a lot about making the code look pretty and easy to read and understand. That doesn't mean that we don't care about efficiency. We just go out of our way to hide the messy parts of the code in some function hidden in some package body. Oh, and that Ada programmers tend to have trouble sleeping if they write code that is compiler dependent when it doesn't have to be. ;-) -- Robert I. Eachus "Quality is the Buddha. Quality is scientific reality. Quality is the goal of Art. It remains to work these concepts into a practical, down-to-earth context, and for this there is nothing more practical or down-to-earth than what I have been talking about all along...the repair of an old motorcycle." -- from Zen and the Art of Motorcycle Maintenance by Robert Pirsig ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-23 21:42 ` Robert I. Eachus @ 2003-10-24 1:42 ` Mike Silva 0 siblings, 0 replies; 10+ messages in thread From: Mike Silva @ 2003-10-24 1:42 UTC (permalink / raw) "Robert I. Eachus" <rieachus@comcast.net> wrote in message news:<3F984AF5.6030703@comcast.net>... > Mike Silva wrote: > > "Robert I. Eachus" <rieachus@comcast.net> wrote in message news:<3F96ED50.2040009@comcast.net>... > > > >>> R16 := R16 + Reg16_t( Integer( PB.offset5 ) mod Reg16_t'Modulus ); > >>>-- the above line works, but is it good Ada, or C-in-Ada? > >> > >> R16 := R16 + Reg16_t(PB.offset5); > >> > >>Should do exactly the same thing--but it doesn't. > > > > > > Do you mean that the language should have been defined so that the > > conversion in the 2nd line acts like the 1st, with negative numbers? > > Or ??? > > > > Mike > > Yes. I believe that this will be "fixed" in the next version of the > standard, but for now you will find compilers that raise <good stuff snipped> Robert, thanks a bunch for your insights. Although I'm doing this mostly for my own amusement/edification, I also want to do this cleanly enough that it "shows off" Ada to those who would never imagine looking at Ada for bit-twiddling. BTW, the processor I'm simulating is my favorite 8-bitter, the ill-fated 6809. Thanks again. Mike ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-22 18:56 Is there a better (Ada) way? Mike Silva 2003-10-22 19:33 ` sk 2003-10-22 20:50 ` Robert I. Eachus @ 2003-10-23 3:12 ` Steve 2003-10-23 18:30 ` Mike Silva 2003-10-24 22:20 ` Nick Roberts 3 siblings, 1 reply; 10+ messages in thread From: Steve @ 2003-10-23 3:12 UTC (permalink / raw) I don't know if its really more "Ada like" but here is the approach I would take. Rougly following your conventions I would add a type definition: type SReg16_T is range -2**15..2**15-1; for SReg16_T'size use 16; Then use a type conversion for a sign extend: SReg16_T( PB.Offset5 ) And an instance of unchecked conversion to convert to a SReg16_T to a Reg16_T: function To_Reg16_T is new Ada.Unchecked_Conversion( SReg16_T, Reg16_T ); Then the expression in your example would read: R16 := R16 + To_Reg16_T( SReg16_T( PB.Offset5 ) ); Another approach would be to use a lookup table indexed by the offset giving the amount to change the index. Something like: type RegOff_T is array( Offset5_T ) of Reg16_T; Reg_Offset : constant RegOff_T := ( -16 => 16#FFF0#, -15 => 16#FFF1#, -14 => 16#FFF2#, -13 => 16#FFF3#, -12 => 16#FFF4#, -11 => 16#FFF5#, -10 => 16#FFF6#, -9 => 16#FFF7#, -8 => 16#FFF8#, -7 => 16#FFF9#, -6 => 16#FFFA#, -5 => 16#FFFB#, -4 => 16#FFFC#, -3 => 16#FFFD#, -2 => 16#FFFE#, -1 => 16#FFFF#, 0 => 16#0000#, 1 => 16#0001#, 2 => 16#0002#, 3 => 16#0003#, 4 => 16#0004#, 5 => 16#0005#, 6 => 16#0006#, 7 => 16#0007#, 8 => 16#0008#, 9 => 16#0009#, 10 => 16#000A#, 11 => 16#000B#, 12 => 16#000C#, 13 => 16#000D#, 14 => 16#000E#, 15 => 16#000F# ); Then the expression in your example would read: R16 := R16 + Reg_Offset( PB.Offset5 ); If you actually want to try to run the simulator, I'd try a few approaches and pick the one that is faster. BTW: There is a nice module built in to Ada95 called "Interfaces" it defines stuff like Unsigned_16, etc. I prefer to use that over defining my own similar types. Steve (The Duck) "Mike Silva" <snarflemike@yahoo.com> wrote in message news:20619edc.0310221056.4c92d10c@posting.google.com... > I've started writing a little CPU simulator, just for fun and to be > doing *something* in Ada, and I want to make sure I'm not writing "C > in Ada" when it comes to all the bit, bitfield and register > manipulations. > [snip] > .... > R16 := R16 + Reg16_t( Integer( PB.offset5 ) mod Reg16_t'Modulus ); > -- the above line works, but is it good Ada, or C-in-Ada? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-23 3:12 ` Steve @ 2003-10-23 18:30 ` Mike Silva 0 siblings, 0 replies; 10+ messages in thread From: Mike Silva @ 2003-10-23 18:30 UTC (permalink / raw) "Steve" <nospam_steved94@comcast.net> wrote in message news:<%GHlb.1106$mZ5.9467@attbi_s54>... > I don't know if its really more "Ada like" but here is the approach I would > take. > > Rougly following your conventions I would add a type definition: > > type SReg16_T is range -2**15..2**15-1; > for SReg16_T'size use 16; > > Then use a type conversion for a sign extend: > SReg16_T( PB.Offset5 ) > > And an instance of unchecked conversion to convert to a SReg16_T to a > Reg16_T: > > function To_Reg16_T is new Ada.Unchecked_Conversion( SReg16_T, Reg16_T ); > > Then the expression in your example would read: > > R16 := R16 + To_Reg16_T( SReg16_T( PB.Offset5 ) ); > Yes, I like this better -- in fact, I came up with the same thing myself last night in trying various alternatives. Thanks for confirming my instincts! (I also have to deal with signed 8-bit offsets, which pretty much puts the array method out of the running for me...) Mike ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Is there a better (Ada) way? 2003-10-22 18:56 Is there a better (Ada) way? Mike Silva ` (2 preceding siblings ...) 2003-10-23 3:12 ` Steve @ 2003-10-24 22:20 ` Nick Roberts 3 siblings, 0 replies; 10+ messages in thread From: Nick Roberts @ 2003-10-24 22:20 UTC (permalink / raw) Mike Silva wrote: > I've started writing a little CPU simulator, just for fun and to be > doing *something* in Ada, and I want to make sure I'm not writing "C > in Ada" when it comes to all the bit, bitfield and register > manipulations. > > Below is a typical question. I need to add a 5-bit signed offset to a > 16-bit register. The way I came up with is shown on the last line of > the example code, but I want to find out if there's a more Ada-ish way > to do what I'm doing. Any comments about any part of the example code > are welcome. > > Mike > > -------- example code -------- > > procedure test is > type Reg16_t is mod 2**16; -- 16 bit register > for Reg16_t'Size use 16; > > type Offset5_t is range -2**4..2**4-1; -- 5 bit signed offset > for Offset5_t'Size use 5; > > type Dummy_t is mod 2**3; -- just take up extra 3 bits > in byte, for this example > for Dummy_t'Size use 3; > > type Postbyte_t is -- typical opcode postbyte > record > dummy : Dummy_t; > offset5 : Offset5_t; > end record; > > for Postbyte_t use > record > dummy at 0 range 5..7; > offset5 at 0 range 0..4; > end record; > > for Postbyte_t'Size use 8; > > R16 : Reg16_t; > PB : Postbyte_t; > begin > .... > R16 := R16 + Reg16_t( Integer( PB.offset5 ) mod Reg16_t'Modulus ); > -- the above line works, but is it good Ada, or C-in-Ada? I would be inclined to create an explicit signed integer type of the appropriate size: procedure test is type Unsigned_16 is mod 2**16; for Unsigned_16'Size use 16; type Offset_5 is range -2**4..2**4-1; for Offset_5'Size use 5; type Signed_16 is range -2**15..2**15-1; for Signed_16'Size use 16; type Jump_Postbyte is record Offset: Offset_5; end record; for Jump_Postbyte use record Offset at 0 range 0..4; end record; for Jump_Postbyte'Size use 8; R16 : Unsigned_16; PB : Jump_Postbyte; begin .... R16 := R16 + Unsigned_16( Signed_16(PB.Offset)+2**4 ) - 2**4; This formulation gives wrap-around semantics, which is the likely choice for a hard implementation. Ada 95 doesn't provide signed-to-modular integer addition. Perhaps the next revision should. (There's a thought ;-) -- Nick Roberts ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2003-10-24 22:20 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2003-10-22 18:56 Is there a better (Ada) way? Mike Silva 2003-10-22 19:33 ` sk 2003-10-23 18:33 ` Mike Silva 2003-10-22 20:50 ` Robert I. Eachus 2003-10-23 16:57 ` Mike Silva 2003-10-23 21:42 ` Robert I. Eachus 2003-10-24 1:42 ` Mike Silva 2003-10-23 3:12 ` Steve 2003-10-23 18:30 ` Mike Silva 2003-10-24 22:20 ` Nick Roberts
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox