D - Export and Volatile
- Luigi (6/6) Sep 09 2002 Hello,
- Walter (5/6) Sep 09 2002 No, export means it is made available to users of the DLL. There is no
- Luigi (3/6) Sep 09 2002 Ok, thanks
- Robert W. Cunningham (46/49) Sep 09 2002 Arrgh! This is true only from the perspective of a single program
- Walter (11/59) Sep 09 2002 Ah, I was hoping for a discussion!
- Joe Battelle (4/9) Sep 10 2002 What happens when the memory is just memory-mapped I/O on an add-in card...
- Walter (11/15) Sep 10 2002 Every
- Burton Radons (9/35) Sep 10 2002 There could be a single throttle point; that would stick everything in
- Walter (3/11) Sep 10 2002 Yes, that might be a better way to do it.
- Joe Battelle (3/8) Sep 10 2002 Your function approach works, but it is really nice to be able to lay a
- Robert W. Cunningham (25/34) Sep 10 2002 Same here!
- Walter (13/24) Sep 10 2002 monitor a
- Joe Battelle (44/46) Sep 11 2002 I won't steal Robert's thunder, but I guess I don't understand what your
- Walter (10/48) Sep 11 2002 registers all
- Joe Battelle (7/11) Sep 11 2002 OK. I guess my point is that it doesn't have to. I mean, I think witho...
- Walter (25/36) Sep 11 2002 because
- Russell Lewis (3/3) Sep 11 2002 What about defining a class with gettors and settors? You would still
- Robert W. Cunningham (11/14) Sep 11 2002 That's still a function call, which amount to nothing more than a PEEK o...
- Walter (6/9) Sep 14 2002 I've got the "volatile" statement now implemented, as in:
- Burton Radons (23/37) Sep 14 2002 Uh...
- Walter (4/25) Sep 14 2002 volatile return data.a;
- Burton Radons (10/44) Sep 15 2002 Oh... kay. So what's the advantage over a function? Why does it earn
- Walter (11/25) Sep 15 2002 It's more convenient. No dummy functions.
- Robert W. Cunningham (15/24) Sep 15 2002 Hmmm... That's very different from what I'm used to.
- Walter (18/43) Sep 15 2002 needed
- Robert W. Cunningham (28/50) Sep 15 2002 It seems you may have a biased view of the vast array of caching strateg...
- Walter (12/25) Sep 15 2002 only
- Robert W. Cunningham (42/69) Sep 17 2002 I don't keep this stuff in my head! Back in the day, I'd go to the proc...
- Mark Evans (10/10) Sep 17 2002 I've scanned the postings on this subject and tried to follow them. I d...
- Walter (15/41) Sep 18 2002 is
- Walter (4/7) Sep 10 2002 intrinsics.
- Sean L. Palmer (5/12) Sep 11 2002 If you can have it work as a storage class that may be good enough.
- Walter (7/21) Sep 11 2002 While const will work as a storage class, it doesn't really extend to
- Sean L. Palmer (7/32) Sep 11 2002 You can have pointers to constants too. How do you deal with that?
- Walter (15/18) Sep 11 2002 D doesn't have pointers to constants as a type. I eventually abandoned a...
- Robert W. Cunningham (22/40) Sep 11 2002 I agree! Let's replace "const" with "ROM", just to make the difference
- Walter (17/37) Sep 12 2002 to
- Robert W. Cunningham (16/18) Sep 13 2002 Yup! But only if there was no other way to obtain it. Since a compiler...
- Sean L. Palmer (20/38) Sep 12 2002 So there's nothing preventing you from writing code like this?
- Pavel Minayev (9/22) Sep 12 2002 You cannot write such code in D. You simply can't take address of
- Sean L. Palmer (20/42) Sep 13 2002 So it's not possible to force the compiler to pass a large constant by
- Walter (20/35) Sep 14 2002 I agree const as a type modifier does have some utility, I argue that it...
Hello, I have one simple question: Export in D, is equal to volatile in C++ Thanks -- Luigi
Sep 09 2002
"Luigi" <igiul.reverse email.it> wrote in message news:alisiu$2599$1 digitaldaemon.com...Export in D, is equal to volatile in C++No, export means it is made available to users of the DLL. There is no volatile in D, as in my opinion volatile is next to useless in real applications.
Sep 09 2002
No, export means it is made available to users of the DLL. There is no volatile in D, as in my opinion volatile is next to useless in real applications.Ok, thanks -- Luigi
Sep 09 2002
Walter wrote:There is no volatile in D, as in my opinion volatile is next to useless in real applications.Arrgh! This is true only from the perspective of a single program running on a memory-protected system. The vast majority of the code I write runs on systems with no MMU, on systems where multiple processors share the same memory, and on systems where applications need direct access to hardware. In all these cases, and in all their possible intersections and unions, "volatile" is useful simply to tell the compiler to NEVER enregister a variable. That is, all references to a given variable should go "to the metal" every time. No caching of such data items anywhere, ever. With "volatile", I can use any level of abstraction to represent my data. I can map a structure over raw memory or hardware, and I can pass pointers to such data that retain the volatile property. When working with compilers that lacked a fully functional "volatile" (sometimes ignored by compilers, like its anti-twin "register") I've had to resort to cumbersome indirect dynamic dereferences or inline assembler just to bypass a compiler "feature". And in order to guarantee I was smarter than the peep-hole optimizer, I'd still have to disassemble the binary to be sure. (Note: The common practice of examining the compiler assembly output is insufficient: Many assemblers, most notably Intel's, also have peep-hole optimizers!) It gets worse: Most CPUs do some form of data bus caching, even those without MMUs. On such platforms, "volatile" must also ensure it correctly drills through the hardware cache. "Volatile" may be an unnecessary feature to many, but if D is to truly be a "systems programming language", it is a mandatory requirement. Unless, of course, the equivalent functionality already exists in D, and this discussion is really about syntactic sugar. In which case, I say give me my sugar! I'm used to having it in C. Otherwise, it seems to me it will be impossible to use D to write any "serious" low-level code, not even a simple DMA handler (often needed when working with custom hardware in FPGAs because it is a simple and powerful interface). Without that capability, just what kind of "systems programming language" could D really be? C++ lets me write device drivers. Java doesn't. Focusing on system programming capabilities alone (not implementation), which one is D going to be most like? My entire interest in D focuses on pushing the power of "reasonable" OOP and "useful" GC further down in to embedded systems. Ideally, over 99% of all the programming could be done in D, using or avoiding D language features as appropriate to the context, with just a minimal smattering of assembler "glue" code (preferably inlined in D as well). Embedded apps are like small operating systems in that they need to be able to marshall all the resources of the system. Could I write an OS 99% in D? -BobC
Sep 09 2002
"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D7D3F59.E537224C users.sourceforge.net...Walter wrote:Ah, I was hoping for a discussion!There is no volatile in D, as in my opinion volatile is next to useless in real applications.Arrgh! This is true only from the perspective of a single program running on a memory-protected system.The vast majority of the code I write runs on systems with no MMU, on systems where multiple processors share the same memory, and on systems where applications need direct access to hardware.Ok.In all these cases, and in all their possible intersections and unions, "volatile" is useful simply to tell the compiler to NEVER enregister a variable. That is, all references to a given variable should go "to the metal" every time. No caching of such data items anywhere, ever. With "volatile", I can use any level of abstraction to represent my data. I can map a structure over raw memory or hardware, and I can pass pointers to such data that retain the volatile property. When working with compilers that lacked a fully functional "volatile" (sometimes ignored by compilers, like its anti-twin "register") I've had to resort to cumbersome indirect dynamic dereferences or inline assembler just to bypass a compiler "feature". And in order to guarantee I was smarter than the peep-hole optimizer, I'd still have to disassemble the binary to be sure. (Note: The common practice of examining the compiler assembly output is insufficient: Many assemblers, most notably Intel's, also have peep-hole optimizers!)The Digital Mars inline assembler is w-y-w-i-w-y-g.It gets worse: Most CPUs do some form of data bus caching, even those without MMUs. On such platforms, "volatile" must also ensure it correctly drills through the hardware cache. "Volatile" may be an unnecessary feature to many, but if D is to truly be a "systems programming language", it is a mandatory requirement. Unless, of course, the equivalent functionality already exists in D, and this discussion is really about syntactic sugar. In which case, I say give me my sugar! I'm used to having it in C.I've always found I needed to use a LOCK prefix anyway, so resorted to inline assembler.Otherwise, it seems to me it will be impossible to use D to write any "serious" low-level code, not even a simple DMA handler (often needed when working with custom hardware in FPGAs because it is a simple and powerful interface).Why? What volatility does a DMA handler have?Without that capability, just what kind of "systems programming language" could D really be? C++ lets me write device drivers. Java doesn't. Focusing on system programming capabilities alone (not implementation), which one is D going to be most like?You can still read/write to any memory address, including I/O ports.My entire interest in D focuses on pushing the power of "reasonable" OOP and "useful" GC further down in to embedded systems. Ideally, over 99% of all the programming could be done in D, using or avoiding D language features as appropriate to the context, with just a minimal smattering of assembler "glue" code (preferably inlined in D as well). Embedded apps are like small operating systems in that they need to be able to marshall all the resources of the system. Could I write an OS 99% in D?I don't see why not. I've looked at the linux kernel sources, and don't see anything there D can't do.
Sep 09 2002
What happens when the memory is just memory-mapped I/O on an add-in card? Every memory read gives you new volatile data. There is no LOCK prefix needed in this case, but you need to be able to tell the compiler not to enregister this data and to go get it again on each reference.Without that capability, just what kind of "systems programming language" could D really be? C++ lets me write device drivers. Java doesn't. Focusing on system programming capabilities alone (not implementation), which one is D going to be most like?You can still read/write to any memory address, including I/O ports.
Sep 10 2002
"Joe Battelle" <Joe_member pathlink.com> wrote in message news:all4et$2qg8$1 digitaldaemon.com...What happens when the memory is just memory-mapped I/O on an add-in card?Everymemory read gives you new volatile data. There is no LOCK prefix neededin thiscase, but you need to be able to tell the compiler not to enregister thisdataand to go get it again on each reference.That can be resolved by crafting a function like: byte read_byte_from_volatile_location(byte *p); For efficiency, the compiler can even make it an intrinsic function (like sin(), cos(), etc.). It solves the problem without the volatile type modifier permeating the type system and adding pages of complexity to overloading, type deduction, partial specialization, partial ordering, etc.
Sep 10 2002
Walter wrote:"Joe Battelle" <Joe_member pathlink.com> wrote in message news:all4et$2qg8$1 digitaldaemon.com...There could be a single throttle point; that would stick everything in one section of the code generator and a small expression type, using a "volatile" intrinsic: int mouse_x; /* This is volatile */ int a, b; a = volatile (mouse_x); b = volatile (mouse_x); Afterwards, a and b are potentially different.What happens when the memory is just memory-mapped I/O on an add-in card?Everymemory read gives you new volatile data. There is no LOCK prefix neededin thiscase, but you need to be able to tell the compiler not to enregister thisdataand to go get it again on each reference.That can be resolved by crafting a function like: byte read_byte_from_volatile_location(byte *p); For efficiency, the compiler can even make it an intrinsic function (like sin(), cos(), etc.). It solves the problem without the volatile type modifier permeating the type system and adding pages of complexity to overloading, type deduction, partial specialization, partial ordering, etc.
Sep 10 2002
"Burton Radons" <loth users.sourceforge.net> wrote in message news:3D7E85CB.2030805 users.sourceforge.net...There could be a single throttle point; that would stick everything in one section of the code generator and a small expression type, using a "volatile" intrinsic: int mouse_x; /* This is volatile */ int a, b; a = volatile (mouse_x); b = volatile (mouse_x); Afterwards, a and b are potentially different.Yes, that might be a better way to do it.
Sep 10 2002
Your function approach works, but it is really nice to be able to lay a structure over a portion of memory-mapped I/O, call the whole darn thing volatile and reference away. I much prefer this to introducing more intrinsics.a = volatile (mouse_x); b = volatile (mouse_x); Afterwards, a and b are potentially different.Yes, that might be a better way to do it.
Sep 10 2002
Joe Battelle wrote:Same here! In the old days, we had to write lots of #defines and do peeks and pokes to access hardware from userland. Walter's function-based approach would force us back to those bad old days (with better naming, but the same functionality). Being able to overlay an intricate structure over a hardware interface abstracts away a huge portion of the hassle of writing to the bare metal. Lack of a true volatile attribute will exclude D from use on any system I build. It is that important to what I do and how I do it. D has to win HANDS DOWN over C in every domain to break into embedded systems. Don't think small in this area, unless you are prepared to abandon it. C++ has only a limited presence in embedded systems, and poses no competition to D. Unless, of course, D lacks volatile. Then C++ wins, despite the hassle and baggage. Just today I had to write a routine to talk to a "gas gauge" chip used to monitor a Li-ion battery. I simply declared a struct that mapped 1:1 to the device's registers, declared a pointer to a volatile instance of that structure (different, of course, from a volatile pointer to an instance), and was programming the device in C within minutes. The whole thing, including the time needed to read the cryptic spec sheet, examine the board schematics, verify the chip select address decode logic in the FPGA, craft the struct and write the code, was done in about 4 hours. Without volatile, it could easily have taken that long just to write all the #defines for the gas gauge register locations and content. Ugh. Don't even try to make me go back to #defines and PEEK/POKE! -BobCYour function approach works, but it is really nice to be able to lay a structure over a portion of memory-mapped I/O, call the whole darn thing volatile and reference away. I much prefer this to introducing more intrinsics.a = volatile (mouse_x); b = volatile (mouse_x); Afterwards, a and b are potentially different.Yes, that might be a better way to do it.
Sep 10 2002
"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D7E9EF8.3A33B3C2 users.sourceforge.net...Just today I had to write a routine to talk to a "gas gauge" chip used tomonitor aLi-ion battery. I simply declared a struct that mapped 1:1 to thedevice'sregisters, declared a pointer to a volatile instance of that structure(different,of course, from a volatile pointer to an instance), and was programmingthe devicein C within minutes. The whole thing, including the time needed to readthecryptic spec sheet, examine the board schematics, verify the chip selectaddressdecode logic in the FPGA, craft the struct and write the code, was done inabout 4hours. Without volatile, it could easily have taken that long just to write allthe#defines for the gas gauge register locations and content. Ugh. Don'teven try tomake me go back to #defines and PEEK/POKE!Ok, but why did it need to be volatile access? I'm not trying to be obtuse here, I'm trying to understand the problem you're solving.
Sep 10 2002
Ok, but why did it need to be volatile access? I'm not trying to be obtuse here, I'm trying to understand the problem you're solving.I won't steal Robert's thunder, but I guess I don't understand what your objection is to the volatile construct. When interfacing using memory-mapped I/O (as opposed to Port I/O) you frequently deal with pointers to structs that aren't pointing to main memory. The "memory" is just some latch on the other side of an address decoder that has a transient value. The data shouldn't ever be cached. Think of a simple data acquisition system that has three hardware registers all memory-mapped on a PCI-bus card. Look at the following example: timestamp and data dereferences better not be enregistered or hoisted outside the loop or you're in trouble. volatile struct DataAcq { int timestamp; // Base+0 int count; // Base+4 int data; // Base+8 } DataAcq * p = cast(DataAcq *) 0xF0000000; // Base address int[] log; for (int i = 0; i < p.count; ++i) { if (p.timestamp < endtime) log[i] = p.data; else break; } ---------------------- Now I would be just as happy doing this: for (int i = 0; i < p.count; ++i) { volatile(p) { if (p.timestamp < endtime) log[i] = p.data; else break; } } ----------------------- or even just something generic that says don't enregister or hoist any pointer dereferences in the block of code. for (int i = 0; i < p.count; ++i) { volatile() { if (p.timestamp < endtime) log[i] = p.data; else break; } }
Sep 11 2002
"Joe Battelle" <Joe_member pathlink.com> wrote in message news:almuqb$22cm$1 digitaldaemon.com...Think of a simple data acquisition system that has three hardwareregisters allmemory-mapped on a PCI-bus card. Look at the following example: timestampanddata dereferences better not be enregistered or hoisted outside the looporyou're in trouble.Ok, but in the particular example here it cannot be hoisted anyway because the assignment to the array log[] invalidates all pointer references.volatile struct DataAcq { int timestamp; // Base+0 int count; // Base+4 int data; // Base+8 } DataAcq * p = cast(DataAcq *) 0xF0000000; // Base address int[] log; for (int i = 0; i < p.count; ++i) { if (p.timestamp < endtime) log[i] = p.data; else break; } ---------------------- Now I would be just as happy doing this: for (int i = 0; i < p.count; ++i) { volatile(p) { if (p.timestamp < endtime) log[i] = p.data; else break; } } ----------------------- or even just something generic that says don't enregister or hoist anypointerdereferences in the block of code. for (int i = 0; i < p.count; ++i) { volatile() { if (p.timestamp < endtime) log[i] = p.data; else break; } }That's probably a better solution. The trouble with volatile as a type modifier is its ripple effects throughout the typing system.
Sep 11 2002
Ok, but in the particular example here it cannot be hoisted anyway because the assignment to the array log[] invalidates all pointer references.OK. I guess my point is that it doesn't have to. I mean, I think without the volatile specifier, it would be natural for an optimizer to deref p.data once above the loop and put it in a register. I don't see how assigning the deref'd value to an array element would keep the deref (not the assignment) from being hoisted in all D implementations.That's probably a better solution. The trouble with volatile as a type modifier is its ripple effects throughout the typing system.Understood. And I think it's very reasonable to do things differently than in C++ if it keeps the complexity of the compiler down.
Sep 11 2002
"Joe Battelle" <Joe_member pathlink.com> wrote in message news:alnutu$i46$1 digitaldaemon.com...becauseOk, but in the particular example here it cannot be hoisted anywaythethe assignment to the array log[] invalidates all pointer references.OK. I guess my point is that it doesn't have to. I mean, I think withoutvolatile specifier, it would be natural for an optimizer to deref p.dataonceabove the loop and put it in a register. I don't see how assigning thederef'dvalue to an array element would keep the deref (not the assignment) frombeinghoisted in all D implementations.The optimizer has to be painfully conservative. In this case, there's no way the optimizer can verify that the array log[] does not overlap whatever p points to. Do people write code like that? Often enough - and the people that do are usually the ones unable to figure out why their code breaks when optimized and they blame the compiler. It's the famed C 'aliasing' problem.than inThat's probably a better solution. The trouble with volatile as a type modifier is its ripple effects throughout the typing system.Understood. And I think it's very reasonable to do things differentlyC++ if it keeps the complexity of the compiler down.Yes. Glad you understand! It's important for me, in designing a language, to: 1) understand what the problem is, not just implement a solution If I understand the problem correctly, I have a chance at implementing a better solution. 2) recognize the scope of the problem If the scope of the problem is fairly small, it can justify a more targetted solution. For example, volatile permeates partial specialization rules in C++ templates - but why on earth would you be using such to access hardware registers? But you can't get away from it because volatile is a type modifier, so everything that uses types must account for it. It's using a sledgehammer to squash a flea.
Sep 11 2002
What about defining a class with gettors and settors? You would still have to do some of the hard work, but it would allow you to have something like a struct with volatile members...
Sep 11 2002
Russell Lewis wrote:What about defining a class with gettors and settors? You would still have to do some of the hard work, but it would allow you to have something like a struct with volatile members...That's still a function call, which amount to nothing more than a PEEK or POKE. Plus, whatever you do within the gettor/settor could still get cached! You really need to be able to "drill-down" to the physical environment. That is, if I want a bus cycle to occur (read or write), then by God it must occur when and how I want it to! Presently, not only does D not allow you to prevent enregistration, it does not allow you to atomically bypass the CPU cache. Both are needed tigether in order to obtain true "volatile" behavior. -BobC
Sep 11 2002
"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D7FD186.4480CC4A users.sourceforge.net...Presently, not only does D not allow you to prevent enregistration, it does not allow you to atomically bypass the CPU cache. Both are needed tigether in order to obtain true "volatile" behavior.I've got the "volatile" statement now implemented, as in: volatile a = *p; It will prevent any caching of values into and out of the volatile statement.
Sep 14 2002
Walter wrote:"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D7FD186.4480CC4A users.sourceforge.net...Uh... struct Registers { struct Data { int a; } Data data; int a () { return volatile data.a; } void a (int value) { data.a = value; } } Would that work, or would the get property have to be: int a () { int value; volatile value = data.a; return value; } If so, that's pretty heavy stuff for what will be the most common usage. I'd rather have a function that's turned intrinsic in semantic0, as it retains the "easy to parse dumbly" rule and doesn't have bad worst cases for syntax.Presently, not only does D not allow you to prevent enregistration, it does not allow you to atomically bypass the CPU cache. Both are needed tigether in order to obtain true "volatile" behavior.I've got the "volatile" statement now implemented, as in: volatile a = *p; It will prevent any caching of values into and out of the volatile statement.
Sep 14 2002
"Burton Radons" <loth users.sourceforge.net> wrote in message news:3D842697.6080208 users.sourceforge.net...struct Registers { struct Data { int a; } Data data; int a () { return volatile data.a; } void a (int value) { data.a = value; } } Would that work, or would the get property have to be: int a () { int value; volatile value = data.a; return value; } If so, that's pretty heavy stuff for what will be the most common usage. I'd rather have a function that's turned intrinsic in semantic0, as it retains the "easy to parse dumbly" rule and doesn't have bad worst cases for syntax.volatile return data.a; should work fine.
Sep 14 2002
Walter wrote:"Burton Radons" <loth users.sourceforge.net> wrote in message news:3D842697.6080208 users.sourceforge.net...Oh... kay. So what's the advantage over a function? Why does it earn its additional parsing complexity? This also requires the compiler to have knowledge of every statement and expression and how to make it non-caching; the function-based method is just a guaranteed dereference. The property-based read is going to be the most common - I'd even predict that using stuff like "volatile for..." will be consigned to the criminally insane, as leaving it to the caller to manage volatile is a bad idea (but as a property it's fine). So supporting it doesn't look to have much particular extra value.struct Registers { struct Data { int a; } Data data; int a () { return volatile data.a; } void a (int value) { data.a = value; } } Would that work, or would the get property have to be: int a () { int value; volatile value = data.a; return value; } If so, that's pretty heavy stuff for what will be the most common usage. I'd rather have a function that's turned intrinsic in semantic0, as it retains the "easy to parse dumbly" rule and doesn't have bad worst cases for syntax.volatile return data.a; should work fine.
Sep 15 2002
"Burton Radons" <loth users.sourceforge.net> wrote in message news:3D8466B4.3080008 users.sourceforge.net...It's more convenient. No dummy functions.volatile return data.a; should work fine.Oh... kay. So what's the advantage over a function?Why does it earn its additional parsing complexity?Not sure what you mean. A volatile statement is almost no code to implement.This also requires the compiler to have knowledge of every statement and expression and how to make it non-caching; the function-based method is just a guaranteed dereference.No, it's pretty trivial to implement. It requires no knowledge of the statements being processed. Each statement gets processed into a sequence of basic blocks. The compiler just marks those blocks as being conceptually like asm blocks - already taken care of within the optimizer.The property-based read is going to be the most common - I'd even predict that using stuff like "volatile for..." will be consigned to the criminally insane, as leaving it to the caller to manage volatile is a bad idea (but as a property it's fine). So supporting it doesn't look to have much particular extra value.I was thinking it would be good for things like: for (int i = 0; i < 1000; i++) volatile sum += *p;
Sep 15 2002
Walter wrote:"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D7FD186.4480CC4A users.sourceforge.net...Hmmm... That's very different from what I'm used to. I'd prefer to be able to say "when taking the value of this thing, treat it as volatile, no matter how it is dereferenced, or when, or where". Suppse I have a global pointer to a hardware register (say, a 32-bit real-time clock/counter). Adding "volatile" to each and every use will be a nightmare. Missing just one could ruin an entire application, and be next to impossible to detect and debug. Which means all my volatile items would probably need to be single-reference, and thus need to be wrapped within a function call or an object. I'd need an explicit "inline" statement to ensure I can access the dereferenced pointer value in "real-time". Unless I have misunderstood the meaning and use, this interpretation of "volatile" looks like a non-starter to me. -BobCPresently, not only does D not allow you to prevent enregistration, it does not allow you to atomically bypass the CPU cache. Both are needed tigether in order to obtain true "volatile" behavior.I've got the "volatile" statement now implemented, as in: volatile a = *p; It will prevent any caching of values into and out of the volatile statement.
Sep 15 2002
"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D84342E.948C934 users.sourceforge.net...Walter wrote:needed"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D7FD186.4480CC4A users.sourceforge.net...Presently, not only does D not allow you to prevent enregistration, it does not allow you to atomically bypass the CPU cache. Both areIt is a different way of looking at the issue, but I think it does address your concerns.Hmmm... That's very different from what I'm used to.tigether in order to obtain true "volatile" behavior.I've got the "volatile" statement now implemented, as in: volatile a = *p; It will prevent any caching of values into and out of the volatile statement.I'd prefer to be able to say "when taking the value of this thing, treatitas volatile, no matter how it is dereferenced, or when, or where".That's the type modifier approach.Suppse I have a global pointer to a hardware register (say, a 32-bit real-time clock/counter). Adding "volatile" to each and every use will be a nightmare. Missing just one could ruin an entire application, and be next to impossible to detect and debug.The compiler isn't that good at caching values. <g> Caching is nearly always very localized, and is flushed anyway when any assignments through a pointer are done. The only time this can be an issue is if two reads are done with no intervening indirect assignments of any sort. That includes assigning to any globals/statics, assigning to arrays, or calling functions.Which means all my volatile items would probably need to be single-reference, and thus need to be wrapped within a function call or an object.You could do it that way - and is a common oo technique with property gettors and settors. The gettors and settors get inline expanded, so there's no performance penalty for using them.I'd need an explicit "inline" statement to ensure I can access the dereferenced pointer value in "real-time".I think that would be unnecessary. Even the most basic inlining capability will inline a function that consists of nothing but return *p;Unless I have misunderstood the meaning and use, this interpretation of "volatile" looks like a non-starter to me.Can you post a bit of code that would cause particular grief?
Sep 15 2002
Walter wrote:"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D84342E.948C934 users.sourceforge.net...It seems you may have a biased view of the vast array of caching strategies used by the wide variety of processors out there! Generally, read and write (and instruction fetch) caching are handled by separate, independent hardware subsystems. Whatever caching the compiler may or may not do is secondary to whatever hardware caching may be going on. I don't really care all that much about assignment (write) caching (for the hardware, I configure it when the processor boots and can generally forget about it). I do care very much about access (read) caching (since the hardware read cache is always enabled, and I want to bypass it when I need to). So, I do agree that compiler caching isn't much of an issue. But that is only a small part of what "volatile" must handle.Suppse I have a global pointer to a hardware register (say, a 32-bit real-time clock/counter). Adding "volatile" to each and every use will be a nightmare. Missing just one could ruin an entire application, and be next to impossible to detect and debug.The compiler isn't that good at caching values. <g> Caching is nearly always very localized, and is flushed anyway when any assignments through a pointer are done. The only time this can be an issue is if two reads are done with no intervening indirect assignments of any sort. That includes assigning to any globals/statics, assigning to arrays, or calling functions.Other than they are MUCH heavier than simply having a *p wherever I need to access a volatile value. A typical snippet, say for a timer: if (*p > last_time) { ... } I do this all the time in C. It is especially handy when many items need to be tested very quickly. Such as an array of 8000 IPC mailboxes. If any access were to fetch a prior value from a hardware cache or a CPU register, the program would not be getting the data it needs (which is a true read cycle to the hardware).Which means all my volatile items would probably need to be single-reference, and thus need to be wrapped within a function call or an object.You could do it that way - and is a common oo technique with property gettors and settors. The gettors and settors get inline expanded, so there's no performance penalty for using them.It just seems like extra window dressing (baggage) and ahssle for D to do something that is so easy in C. It's like training a dog: If I say "fetch" and the dog doesn't fetch, the dog will be disciplined. Well, OK, it's not exactly like training a dog: If I say "fetch" and my compiler doesn't do a true "fetch", the compiler will be taken out and shot. -BobCI'd need an explicit "inline" statement to ensure I can access the dereferenced pointer value in "real-time".I think that would be unnecessary. Even the most basic inlining capability will inline a function that consists of nothing but return *p;
Sep 15 2002
"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D8571DA.5BAE5977 users.sourceforge.net...So, I do agree that compiler caching isn't much of an issue. But that isonlya small part of what "volatile" must handle.How should code be generated differently?Other than they are MUCH heavier than simply having a *p wherever I needtoaccess a volatile value. A typical snippet, say for a timer: if (*p > last_time) { ... } I do this all the time in C. It is especially handy when many items needto betested very quickly. Such as an array of 8000 IPC mailboxes. If any access were to fetch a prior value from a hardware cache or a CPU register, the program would not be getting the data it needs (which is atrueread cycle to the hardware).p.get() is only 5 characters more, and no extra code is actually generated.It just seems like extra window dressing (baggage) and ahssle for D to do something that is so easy in C.The trouble is how it percolates through the typing system, affecting everything from function overloading to template partial ordering to template argument deduction to template partial specialization. It just winds up adding a great deal of complexity.
Sep 15 2002
Walter wrote:"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D8571DA.5BAE5977 users.sourceforge.net...I don't keep this stuff in my head! Back in the day, I'd go to the processor manual and look it up. And I haven't used an x86 processor on an embedded project since the 8086. But I do know that "volatile" works just fine on an x86! I don't have to look at CPU manuals any more: These days, GCC does "volatile" well on all platforms I use it on. Which probably means that GCC-D will likely have a "proper" volatile, since GCC itself already has the code to handle it on all platforms. That's good enough for me!So, I do agree that compiler caching isn't much of an issue. But that isonlya small part of what "volatile" must handle.How should code be generated differently?But how much more code is generated? More importantly, how many times longer does it take to execute that code compared to "*p"? If there is absolutely zero difference (it is one or two instructions), then you and I are describing identical functionality, only from different perspectives. But if there is any difference, then your version of volatile will be both "big" and "slow", and not all that useful for systems programming.Other than they are MUCH heavier than simply having a *p wherever I needtoaccess a volatile value. A typical snippet, say for a timer: if (*p > last_time) { ... } I do this all the time in C. It is especially handy when many items needto betested very quickly. Such as an array of 8000 IPC mailboxes. If any access were to fetch a prior value from a hardware cache or a CPU register, the program would not be getting the data it needs (which is atrueread cycle to the hardware).p.get() is only 5 characters more, and no extra code is actually generated.Then simply outlaw "volatile" for ALL those uses! I want a fast, simple, clean volatile. Not a new type (sub)system. I only need "volatile" for specific pointers that, when dereferenced, will ALWAYS drill through the cache and read the hardware directly. It need not be elegant or general: "Possible" and "fast" will suffice. Hmmm... If the implementation of your proposed volatile syntax is both light and fast, I suppose I could make your initial proposal meet my needs, but I'd need to add a notational layer that would need to be handled by a preprocessor. If that will work, I'm fine with it. For example, I'd place my "volatile" declarations in encoded comments, use an initial preprocessor pass to extract the list of variable names that are "volatile", then use a final preprocessor pass to wrap all references with your notation. So long as I don't have to do it manually, it will probably work for me. I've written several such systems that used encoded comments. The key is to do so in a way that keeps debugging sane enough to use the original source file (instead of the post-processed file). I don't see that being a problem here. But I'd much prefer a solution that didn't demand preprocessing for it to be both general and robust. Preprocessing would kill one of D's special characteristics. But it would be OK if it enabled the use of D for direct hardware-level programming. Hmmmm.... I could do that same transformation if I had access to your parse tree. Which means your compiler should be able to do it just as easily. -BobCIt just seems like extra window dressing (baggage) and ahssle for D to do something that is so easy in C.The trouble is how it percolates through the typing system, affecting everything from function overloading to template partial ordering to template argument deduction to template partial specialization. It just winds up adding a great deal of complexity.
Sep 17 2002
I've scanned the postings on this subject and tried to follow them. I do appreciate the need for direct hardware access. Thanks Walter for taking time with this subject and putting volatile into D. Someone should take the D compiler and attempt to port one of the free embedded operating systems to D. It would have to be customized hardware, not something like PC/104 which is just a PC in a different mechanical form factor. Of course it would have to run an Intel CPU for the time being. http://rome.sourceforge.net/ Many others exist. Mark
Sep 17 2002
"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D87F4A4.D37093A8 users.sourceforge.net...Walter wrote:is"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D8571DA.5BAE5977 users.sourceforge.net...So, I do agree that compiler caching isn't much of an issue. But thatprocessoronlyI don't keep this stuff in my head! Back in the day, I'd go to thea small part of what "volatile" must handle.How should code be generated differently?manual and look it up. And I haven't used an x86 processor on an embedded project since the 8086. But I do know that "volatile" works just fine onanx86!All it does is prevent caching of loads in a register, and prevent elimination of dead stores.generated.p.get() is only 5 characters more, and no extra code is actuallyBut how much more code is generated? More importantly, how many timeslongerdoes it take to execute that code compared to "*p"?No difference at all.If there is absolutely zero difference (it is one or two instructions),thenyou and I are describing identical functionality, only from different perspectives.Yes.But if there is any difference, then your version of volatile will be both "big" and "slow", and not all that useful for systems programming.There should not be any difference.Offhand, I think it would be hard (meaning kludgy compiler code) to distinguish them.The trouble is how it percolates through the typing system, affecting everything from function overloading to template partial ordering to template argument deduction to template partial specialization. It just winds up adding a great deal of complexity.Then simply outlaw "volatile" for ALL those uses! I want a fast, simple, clean volatile. Not a new type (sub)system.
Sep 18 2002
"Joe Battelle" <Joe_member pathlink.com> wrote in message news:alm5h9$15fv$1 digitaldaemon.com...Your function approach works, but it is really nice to be able to lay a structure over a portion of memory-mapped I/O, call the whole darn thing volatile and reference away. I much prefer this to introducing moreintrinsics. The downside is the huge increase in complexity of the type system.
Sep 10 2002
If you can have it work as a storage class that may be good enough. I'm not sure it's possible! Sean "Walter" <walter digitalmars.com> wrote in message news:almj8g$1k8u$1 digitaldaemon.com..."Joe Battelle" <Joe_member pathlink.com> wrote in message news:alm5h9$15fv$1 digitaldaemon.com...Your function approach works, but it is really nice to be able to lay a structure over a portion of memory-mapped I/O, call the whole darn thing volatile and reference away. I much prefer this to introducing moreintrinsics. The downside is the huge increase in complexity of the type system.
Sep 11 2002
While const will work as a storage class, it doesn't really extend to volatile. This is because it's easy to think of constants, but with volatiles you'll have pointers to volatiles. "Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:aln4pi$292b$1 digitaldaemon.com...If you can have it work as a storage class that may be good enough. I'm not sure it's possible! Sean "Walter" <walter digitalmars.com> wrote in message news:almj8g$1k8u$1 digitaldaemon.com...a"Joe Battelle" <Joe_member pathlink.com> wrote in message news:alm5h9$15fv$1 digitaldaemon.com...Your function approach works, but it is really nice to be able to laythingstructure over a portion of memory-mapped I/O, call the whole darnvolatile and reference away. I much prefer this to introducing moreintrinsics. The downside is the huge increase in complexity of the type system.
Sep 11 2002
You can have pointers to constants too. How do you deal with that? I'm sorry... I don't have a problem with C++ type modifiers. In fact I'd rather have more modifiers, even user-defined ones. Sean "Walter" <walter digitalmars.com> wrote in message news:alnshj$4fo$3 digitaldaemon.com...While const will work as a storage class, it doesn't really extend to volatile. This is because it's easy to think of constants, but with volatiles you'll have pointers to volatiles. "Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:aln4pi$292b$1 digitaldaemon.com...layIf you can have it work as a storage class that may be good enough. I'm not sure it's possible! Sean "Walter" <walter digitalmars.com> wrote in message news:almj8g$1k8u$1 digitaldaemon.com..."Joe Battelle" <Joe_member pathlink.com> wrote in message news:alm5h9$15fv$1 digitaldaemon.com...Your function approach works, but it is really nice to be able toathingstructure over a portion of memory-mapped I/O, call the whole darnvolatile and reference away. I much prefer this to introducing moreintrinsics. The downside is the huge increase in complexity of the type system.
Sep 11 2002
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:alnu26$e30$1 digitaldaemon.com...You can have pointers to constants too. How do you deal with that?D doesn't have pointers to constants as a type. I eventually abandoned all use of const pointers in my C++ code, having discovered: 1) It never once saved me from a bug. 2) There was a significant nuisance involved in getting it all const-correct. 3) The optimizer can't make use of const info, since one can legitimately cast away const-ness. 4) I write compilers, and I still have a hard time remembering if the const goes to the left of the * or the right, or exactly where it goes in more complex type declarations. While const as a storage class makes sense, and is implemented in D, const as a type does not.I'm sorry... I don't have a problem with C++ type modifiers. In fact I'd rather have more modifiers, even user-defined ones.Ok <g>.
Sep 11 2002
Walter wrote:"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:alnu26$e30$1 digitaldaemon.com...I agree! Let's replace "const" with "ROM", just to make the difference perfectly clear. The implementation should simply disallow write cycles to that location. This can be supported in the compiler, but it can be absolutely guaranteed by placing consts in a separate memory area/page and setting the appropriate MMU bits! Similarly, the compiler can support "volatile", but volatile items should be assigned MMU protection flags that force cache invalidation upon access (which is how hardware does volatile). When there is no MMU, forcing "read-thru" on a cache can be a bit harder, but most embedded CPUs allow you to enable cache for only a specified memory range. Anything outside that range (no matter if it is RAM, ROM or hardware) cannot and will not be cached. Just be sure the hardware designers keep all the cacheable stuff contiguous within the memory map, and all will be well. For example, on my embedded multiprocessor projects, I often intentionally place part of the RAM outside the cache. It may then be used as mailboxes and semaphores by all processors, with the guarantee the all processors have the same view of that memory at all times. (And all embedded processors I'm aware of support an atomic read-modify-write cycle, so again hardware helps.) The central OS has to enforce the "guarantee" for processes residing in common memory that is cached. All RTOS's I've used do this quite well. -BobCYou can have pointers to constants too. How do you deal with that?D doesn't have pointers to constants as a type. I eventually abandoned all use of const pointers in my C++ code, having discovered: 1) It never once saved me from a bug. 2) There was a significant nuisance involved in getting it all const-correct. 3) The optimizer can't make use of const info, since one can legitimately cast away const-ness. 4) I write compilers, and I still have a hard time remembering if the const goes to the left of the * or the right, or exactly where it goes in more complex type declarations. While const as a storage class makes sense, and is implemented in D, const as a type does not.I'm sorry... I don't have a problem with C++ type modifiers. In fact I'd rather have more modifiers, even user-defined ones.Ok <g>.
Sep 11 2002
"Robert W. Cunningham" <FlyPG users.sourceforge.net> wrote in message news:3D7FD42F.DA459077 users.sourceforge.net...I agree! Let's replace "const" with "ROM", just to make the difference perfectly clear. The implementation should simply disallow write cyclestothat location. This can be supported in the compiler, but it can be absolutely guaranteed by placing consts in a separate memory area/page and setting the appropriate MMU bits!That's how const works as a storage class now - but it is up to the implementation if it wants to place them in ROM or not.Similarly, the compiler can support "volatile", but volatile items shouldbeassigned MMU protection flags that force cache invalidation upon access(whichis how hardware does volatile). When there is no MMU, forcing "read-thru" on a cache can be a bit harder,butmost embedded CPUs allow you to enable cache for only a specified memory range. Anything outside that range (no matter if it is RAM, ROM orhardware)cannot and will not be cached. Just be sure the hardware designers keepallthe cacheable stuff contiguous within the memory map, and all will bewell.For example, on my embedded multiprocessor projects, I often intentionally place part of the RAM outside the cache. It may then be used as mailboxesandsemaphores by all processors, with the guarantee the all processors havethesame view of that memory at all times. (And all embedded processors I'mawareof support an atomic read-modify-write cycle, so again hardware helps.)Thecentral OS has to enforce the "guarantee" for processes residing in common memory that is cached. All RTOS's I've used do this quite well.Do you see a "volatile" segment in the executable, analogously to a "rom" segment?
Sep 12 2002
Walter wrote:Do you see a "volatile" segment in the executable, analogously to a "rom" segment?Yup! But only if there was no other way to obtain it. Since a compiler has to be targeted for its platform (CPU + OS), that targeting would have to provide the most logical implementation of volatile for that platform. Some CPU instruction sets have instruction prefixes that flag the associated data access(es) as "read-thru". For such CPUs, D could handle the entire issue itself, with no need for a volatile segment in the executable or OS support. The problem with volatile segments is that many of the standard executable formats don't allow for it, so it can't be presented to the loader. Fortunately, most platforms where this might be needed have implemented suitable extensions to the executable format. Extensions which, unfortunately, tend to be proprietary. Most platforms provide an OS call to map any memory segment as desired, so the needed logic can generally be added to the program startup code (the venerable cstart.a on C systems, which I've hacked many a time). -BobC
Sep 13 2002
So there's nothing preventing you from writing code like this? void BreakStuff(char* c) { *c = 2; } int main() { const char s = 1; BreakStuff(&s); printf("now it's %d\n",s); // prints 2. } Yeah that const storage class really does a lot of good. You say const pointers never once saved you from a bug. Congratulations. They certainly help me out, if only as sanity checks. If I can get the compiler to verify any part of the correctness of my code, that's great. Sean "Walter" <walter digitalmars.com> wrote in message news:alo3rr$1ab1$1 digitaldaemon.com..."Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:alnu26$e30$1 digitaldaemon.com...constYou can have pointers to constants too. How do you deal with that?D doesn't have pointers to constants as a type. I eventually abandoned all use of const pointers in my C++ code, having discovered: 1) It never once saved me from a bug. 2) There was a significant nuisance involved in getting it all const-correct. 3) The optimizer can't make use of const info, since one can legitimately cast away const-ness. 4) I write compilers, and I still have a hard time remembering if thegoes to the left of the * or the right, or exactly where it goes in more complex type declarations. While const as a storage class makes sense, and is implemented in D, const as a type does not.I'dI'm sorry... I don't have a problem with C++ type modifiers. In factrather have more modifiers, even user-defined ones.Ok <g>.
Sep 12 2002
Sean L. Palmer wrote:So there's nothing preventing you from writing code like this? void BreakStuff(char* c) { *c = 2; } int main() { const char s = 1; BreakStuff(&s); printf("now it's %d\n",s); // prints 2. }You cannot write such code in D. You simply can't take address of a constant, because constants don't have addresses - they are just values, inserted in-place where constant is used. There is no such C++ nonsense as "constant variable" in D. Constant is a constant. Variable is a variable. You cannot use variables where constants are expected (in case-block, for example). Nor can you use constants where variables (and lvalues in general) are required - as out arguments etc
Sep 12 2002
So it's not possible to force the compiler to pass a large constant by reference? It's often tricky to initialize something using initializer syntax. How will you build complex constants? Do constants then always have to be known at compile time? If what you're saying is true I'd expect not to be able to build any kind of structure out of constants such as a static const linked list. Can't take addresses, can't have lists. Or graphs. I suppose if nobody modifies a thing, and nobody externally can modify a thing (not public) then for all intents and purposes it is const, but it's sure nice to be able to keep people from modifying stuff without the no-address restriction. Is there a way to get around this? People will abuse it (witness mutable in C++, a way to declare a something as constant to everyone but me. Not constant so much as read-only;. at least to you.) I guess there are two different things people use const for... real constants (forever unchanging values) and read-only access protection. D only supports the former. Sean "Pavel Minayev" <evilone omen.ru> wrote in message news:alqlrj$26ks$1 digitaldaemon.com...Sean L. Palmer wrote:So there's nothing preventing you from writing code like this? void BreakStuff(char* c) { *c = 2; } int main() { const char s = 1; BreakStuff(&s); printf("now it's %d\n",s); // prints 2. }You cannot write such code in D. You simply can't take address of a constant, because constants don't have addresses - they are just values, inserted in-place where constant is used. There is no such C++ nonsense as "constant variable" in D. Constant is a constant. Variable is a variable. You cannot use variables where constants are expected (in case-block, for example). Nor can you use constants where variables (and lvalues in general) are required - as out arguments etc
Sep 13 2002
"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:alqi86$1pla$1 digitaldaemon.com...So there's nothing preventing you from writing code like this? void BreakStuff(char* c) { *c = 2; } int main() { const char s = 1; BreakStuff(&s); printf("now it's %d\n",s); // prints 2. } Yeah that const storage class really does a lot of good. You say const pointers never once saved you from a bug. Congratulations. They certainly help me out, if only as sanity checks. If I can get the compiler to verify any part of the correctness of my code, that's great.I agree const as a type modifier does have some utility, I argue that it is minor compared with the cost of it. Some other points: o D does not allow taking the address of a const. Storage is not necessarilly even allocated for a const. o While D allows one to pass pointers around, it is almost never necessary to do so. Use out and inout parameters, which should give an error when used with const variables. o In D, if you do wind up using a pointer, it is for either interfacing with C or for doing something unusual that presumptively you're careful with. You can do anything with pointers in D - they're meant as a way around the typing system. o C doesn't help much there anyway, nothing stops casting away const'ness and modifying it. o The example will still print 1, not 2, because the implementation assumes that s is 1 and will substitute in the 1 in the printf. This is unlike C, since because const isn't guaranteed to be immutable, the compiler cannot make such an assumption.
Sep 14 2002