lccwin fails to generate NOPs

  • Thread starter Edward Rutherford
  • Start date
E

Eric Sosman

Not exactly common these days...

I am not sure which instruction is

There was SKIPN and (iirc) JUMPN. SKIPN did seem a bit pointless, but it
was
just a consequence of a particular pattern of condition codes.

In the same way many processors will have the apparently pointless
instructions MOV Rn,Rn, or EXCH Rn,Rn, otherwise there would be an untidy
hole in the opcode map.

As I said, there are various ways of constructing a no-op instruction, so
which one should be generated from an empty C statement? (Although this is
the first I've heard of such a statement having to generate a NOP
instruction.)

As has been pointed out, no C statement "has to" generate any
particular instruction. Must an expression involving multiplication
use a MUL instruction? No: Maybe it can use a shift, maybe it can
use a combination of shifts and adds, maybe it can strength-reduce
the operator and use an add alone. Maybe the compiler can determine
that the result of the multiplication is never used, and throw the
whole thing away.

The important thing is that whatever code is generated must carry
out the actions expressed by the C source (if the source code has a
defined meaning). The means by which those actions are carried out is
entirely up to the implementation. The O.P.'s source code called for
"no action," and the implementation has done what it was told to do,
that is, nothing. <BANG> Next case.
 
C

Chris H

Edward Rutherford said:
True - perhaps C needs a new nop keyword to be added.

No no no no

See the discussion on c99. They are already removing (making "optional"
) previous "Good Ideas". If you need a delay a space you need to do it
properly in ASM.
Jacob is obviously joking about "pricing"

Why? It is his time and expertise for a one off for you. It's called
consultancy
- this would be a very easy
fix, only a few minutes work,

Really? And the full set of regression tests?
and I would suggest having a compile time
option so that all users of lcc can choose how they want C empty
statements to be translated, in case some of them prefer the old
behaviour.

Well up to now only you want it so it would be a case of you turning it
on whilst the others did it properly.

BTW the Dark Star 9000 does not have a NOP so what would you implement
instead?
 
K

Keith Thompson

BartC said:
As I said, there are various ways of constructing a no-op instruction, so
which one should be generated from an empty C statement?

None of them.
(Although this is
the first I've heard of such a statement having to generate a NOP
instruction.)

And the OP still hasn't given us a clue about *why* he needs NOP
instructions.
 
G

glen herrmannsfeldt

Not exactly common these days...

There are a few emulators around, and software to run on them.

It might not take so long to port LCC to the PDP-10.
I am not sure which instruction is
There was SKIPN and (iirc) JUMPN. SKIPN did seem a bit pointless,
but it was just a consequence of a particular pattern of
condition codes.

SKIPN and JUMPN are skip and jump if ACis Not zero.

The fun thing about the PDP-10 is that the suffix indicates the
condition, and no suffix means don't do anything. The unconditional
skip and jump are SKIPA and JUMPA.
In the same way many processors will have the apparently pointless
instructions MOV Rn,Rn, or EXCH Rn,Rn, otherwise there would be an
untidy hole in the opcode map.

As I wrote, the IA32 NOP goes where EXCH AX,AX goes.
I believe the 8080 NOP is also an EXCH instruction. I don't know
why EXCH instead of MOV, though.
As I said, there are various ways of constructing a no-op
instruction, so which one should be generated from an
empty C statement? (Although this is the first I've heard
of such a statement having to generate a NOP instruction.)

It seems that some might expect it in the lowest optimization
case, though that does seem unusual.

-- glen
 
S

Seebs

As I said, there are various ways of constructing a no-op instruction, so
which one should be generated from an empty C statement? (Although this is
the first I've heard of such a statement having to generate a NOP
instruction.)

http://www.seebs.net/faqs/c-iaq.html#section-4

4.3: Is there more than one null statement?

Sort of. You can use ``;'', ``0;'', or ``1;'' - they will all act like
a null statement. Only the first is a ``true'' null statement (all
bits zero). They are basically equivalent. Note that (void *) 0; is a
null statement of type pointer to void, for instance.

-s
 
R

robertwessel2

There are a few emulators around, and software to run on them.

It might not take so long to port LCC to the PDP-10.


SKIPN and JUMPN are skip and jump if ACis Not zero.

The fun thing about the PDP-10 is that the suffix indicates the
condition, and no suffix means don't do anything.  The unconditional
skip and jump are SKIPA and JUMPA.


As I wrote, the IA32 NOP goes where EXCH AX,AX goes.
I believe the 8080 NOP is also an EXCH instruction.  I don't know
why EXCH instead of MOV, though.

"mov ax,ax" is two bytes, "xchg ax,ax" is one.
 
B

BartC

glen herrmannsfeldt said:
There are a few emulators around, and software to run on them.

Interesting. But there might still be a problem with the 18-bit addressing
restricting memory to 256K words, or just over 1MB, per task, which some
might find it challenging now. (And on our first machine, that was all the
physical memory there was. Still managed to support up to 160 simultaneous
users though; some machines with 1 or 2 GB now have trouble with just one
user...)
It might not take so long to port LCC to the PDP-10.



SKIPN and JUMPN are skip and jump if ACis Not zero.
The fun thing about the PDP-10 is that the suffix indicates the
condition, and no suffix means don't do anything. The unconditional
skip and jump are SKIPA and JUMPA.

I misremembered the N as meaning Never. And looking at some details now, the
SKIP instruction sets a condition code, but JUMP doesn't, so would be better
as a no-op. (Skip and Jump in a program listing does make it sound fun
though..)
As I wrote, the IA32 NOP goes where EXCH AX,AX goes.
I believe the 8080 NOP is also an EXCH instruction. I don't know
why EXCH instead of MOV, though.

On x86, EXCH (or XCHG) EAX,EAX is a single byte. Using other registers, or a
MOV, seems to need two bytes.

A single byte no-op is better for fine control of alignment and such.
 
R

robertwessel2

On 1/4/2011 8:57 PM, (e-mail address removed) wrote:
[...]
In the same vein, both Intel and IBM have defined explicit undefined
instructions.  Intel even gave it a mnemonic.

Well, by giving it a mnemonic, they've "reserved" that opcode more strongly
than simply saying "don't use it".


IBM's statement is a bit stronger than that. For the PofO: "Operation
code 00 hex will never be assigned to an instruction implemented in
the CPU."

Unlike, as I recall, when the 8086 first came out, one of the interrupt
vectors was marked by Intel as "reserved" or "unused".  IBM, in their
infinite wisdom, decided to use that interrupt as their "print screen"
handler.  Along comes the 80286, and Intel now uses that interrupt for some
hardware trap, leaving BIOS writers with the task of deciding "was this a
hardware trap, or a software-generated interrupt meant to 'print screen'?"


Actually Intel reserved everything below 0x20, so all of the BIOS
calls and the normal real mode vectors for IRQ0-7 are in that range.
 
G

glen herrmannsfeldt

Interesting. But there might still be a problem with the 18-bit addressing
restricting memory to 256K words, or just over 1MB, per task, which some
might find it challenging now. (And on our first machine, that was all the
physical memory there was. Still managed to support up to 160 simultaneous
users though; some machines with 1 or 2 GB now have trouble with just one
user...)

I believe that was fixed in the later processors, but I never wrote
assembly code for them, so I am not so sure how it works.

(snip)
I misremembered the N as meaning Never. And looking at some

It is, at least, for the 6809. Maybe other Morotola processors, too.
details now, the SKIP instruction sets a condition code,
but JUMP doesn't, so would be better as a no-op.
(Skip and Jump in a program listing does make it sound fun though..)

I presume there is an assembler generated NOP, but I don't know
what it is. The hardware manual doesn't explain that one.

(snip)
On x86, EXCH (or XCHG) EAX,EAX is a single byte. Using other
registers, or a MOV, seems to need two bytes.

Oh, yes. Now I remember it...
A single byte no-op is better for fine control of alignment and such.

Like the OS/360 CNOP.

-- glen
 
B

BGB

Some machines have more than one...

yep...

x86 provides additional nop-forms, mostly so that one can fill more
space with only a single instruction if needed.

there are also "nop [mem]" forms, which I have been using informally as
a machine-code annotation mechanism (the memory address can be pointed
to any relevant metadata, and any code which happens to be looking at
the code can identify the opcode and see if it points at anything relevant).

The favorite problem when writing benchmarks, of making sure that
the compiler doesn't optimize away the operations. How about

i += 0;

i *= 1;

i /= 1;

with no optimization, how many compilers will generate the
specified operation?

dunno, I usually use a few tricks involving do-nothing function calls,
and trying to avoid the compiler figuring out that the function call
does nothing.

IIRC, I have seen function calls with inline ASM for these sorts of
tasks, ...

a __nop keyword almost makes sense, since if-anything, it can tell the
compiler not to optimize it away... (vs the compiler doing its best to
figure out that "some function in another compilation unit accessed via
a function pointer and performing a few global variable assignments" is
in-fact no-op...).
 
J

John Bode

Hello

I am trying to write code that includes a certain number of NOPs in the
generated machine code, I would like to do it portably so without using
inline asm.

On lccwin, even without optimisations, no NOPs are generated.

Doesn't happen with gcc, either. For my part, I would not expect a
null statement to result in a NOP (as opposed to no code at all).

I guess my question is, why do you need the NOPs to be generated? Is
it a timing issue? If so, there may be a better way to accomplish it,
if not a more portable way (frankly, if we're talking about generating
specific opcodes, we've thrown portability out the window already).
 
B

BGB

On 1/4/2011 8:57 PM, (e-mail address removed) wrote:
[...]
In the same vein, both Intel and IBM have defined explicit undefined
instructions. Intel even gave it a mnemonic.

Well, by giving it a mnemonic, they've "reserved" that opcode more
strongly than simply saying "don't use it".

Unlike, as I recall, when the 8086 first came out, one of the interrupt
vectors was marked by Intel as "reserved" or "unused". IBM, in their
infinite wisdom, decided to use that interrupt as their "print screen"
handler. Along comes the 80286, and Intel now uses that interrupt for
some hardware trap, leaving BIOS writers with the task of deciding "was
this a hardware trap, or a software-generated interrupt meant to 'print
screen'?"

and then in the 386 and newer most of the interrupts used by the BIOS
and IRQ controllers happen to fall into the region where the CPU may
validly generate PMode exceptions (hence meaning the need to remap the
IRQ controllers for a PMode OS, and mapping them back if one for some
reason feels a need to go back into real-mode and access the BIOS, well
that or probably have remap entries in the real-mode IVT which redirect
calls to the appropriate BIOS handlers...).
 
K

Keith Thompson

BGB said:
a __nop keyword almost makes sense, since if-anything, it can tell the
compiler not to optimize it away... (vs the compiler doing its best to
figure out that "some function in another compilation unit accessed via
a function pointer and performing a few global variable assignments" is
in-fact no-op...).

I'm still trying to understand why this, or anything like it, would make
sense. What would be the benefit of forcing NOP instructions in the
object code generated by a C compiler?
 
I

Ian Collins

I'm still trying to understand why this, or anything like it, would make
sense. What would be the benefit of forcing NOP instructions in the
object code generated by a C compiler?

Poor man's delay? Sometimes hardware devices require a minimum delay
between being written and being read.
 
M

Marcin Grzegorczyk

Ben said:
The "single byte of code" part is impossible, because some
architectures have fixed-length instructions that are wider than
one byte.

And there are architectures that have variable-length instructions, but
the instruction length is always a multiple of 2. (Examples I'm
familiar with: Motorola's M68k and National Semiconductor CompactRISC.)
 
I

ImpalerCore

[...]
a __nop keyword almost makes sense, since if-anything, it can tell the
compiler not to optimize it away... (vs the compiler doing its best to
figure out that "some function in another compilation unit accessed via
a function pointer and performing a few global variable assignments" is
in-fact no-op...).

I'm still trying to understand why this, or anything like it, would make
sense.  What would be the benefit of forcing NOP instructions in the
object code generated by a C compiler?

I actually use NOP delays primarily in writing serial protocols that I
have to bit-bang myself. For example, if I'm running a
microcontroller at 32 MHz, I sometimes need to insert small NOP delays
to create a electrical signal that is slow enough to be detected by
the peripheral (in my case a temperature sensor). If I ran the
microcontroller at a slower clock speed, I wouldn't need to insert
delays. I personally haven't used anything like this outside the
embedded domain.

\code snippet
/*
* Define the baseline for the delay according to the PIC18F2X1X/4X1X
* oscillator frequency. Each instruction requires 4 clock cycles to
* complete. The table below gives the measured time used by a NOP
* instruction 'asm( "nop" )'.
*
* Osc Freq | Delay
* -------------------
* 1 MHz | 4 ms
* -------------------
* 2 MHz | 2 us
* -------------------
* 4 MHz | 1 us
* -------------------
* 8 MHz | 500 ns
* -------------------
* 16 MHz | 250 ns
* -------------------
* 32 MHz | 125 ns
* -------------------
*/
#if defined(FOSC)
# if (FOSC == 1000000)
# define delay_4us asm( "nop" )
# elif (FOSC == 2000000)
# define delay_2us asm( "nop" )
# elif (FOSC == 4000000)
# define delay_1us asm( "nop" )
# define delay_2us delay_1us; delay_1us
# elif (FOSC == 8000000)
# define delay_500ns asm( "nop" )
# define delay_1us delay_500ns; delay_500ns
# define delay_2us delay_1us; delay_1us
# elif (FOSC == 16000000)
# define delay_250ns asm( "nop" )1
# define delay_500ns delay_250ns; delay_250ns
# define delay_1us delay_500ns; delay_500ns
# define delay_2us delay_1us; delay_1us
# elif (FOSC == 32000000)
# define delay_125ns asm( "nop" )
# define delay_250ns delay_125ns; delay_125ns
# define delay_500ns delay_250ns; delay_250ns
# define delay_1us delay_500ns; delay_500ns
# define delay_2us delay_1us; delay_1us
# else
# error FOSC is not a valid clock speed
# endif
#else
# error delay.h requires FOSC to be defined
#endif
\endcode

\code snippet2
void sensibus_transmit_start( uint8_t sensor_id )
{
/* ______ ______
* DATA: |_________|
* ___ ___
* CLK : ____| |_____| |____
*/

SENSIBUS_DATA_OUT( sensor_id );
SENSIBUS_CLK = 0;
C_SET_BIT( SHT1X_SENSOR_PORT, sensor_id );
delay_1us;
SENSIBUS_CLK = 1;
delay_1us;
C_CLEAR_BIT( SHT1X_SENSOR_PORT, sensor_id );
delay_1us;
SENSIBUS_CLK = 0;
delay_us( 5 );
SENSIBUS_CLK = 1;
C_SET_BIT( SHT1X_SENSOR_PORT, sensor_id );
delay_1us;
SENSIBUS_CLK = 0;
}
\endcode

If I strip out all the delays in the sensibus_transmit_start running
at 32 MHz, the temperature sensor can't keep up.

Best regards,
John D.
 
B

BGB

I'm still trying to understand why this, or anything like it, would make
sense. What would be the benefit of forcing NOP instructions in the
object code generated by a C compiler?

mostly it would be to force delay loops to not be optimized away.

often, a C compiler will see something like:
"for(i=0; i<1000000; i++);"
and in being so clever will emit something akin to "i=1000000;" instead...


similarly:
"for(i=0; i<1000000; i++)myNop();"
will do likewise, if the compiler just happens to notice that "myNop()"
doesn't actually change any external state.

so, something like a "__nop" keyword would mostly serve as a hack to
prevent the compiler from simply optimizing away a function/loop/...
even if it sees it could otherwise do so.

granted, most real compilers can be tricked into not optimizing away a
loop with measures a little less drastic...


for most code, this is optimization perfectly reasonable, but it is not
as good when one is doing some operation a large number of times in a
loop mostly just to measure the thing (needed for micro-benchmarks,
....), where if the loop simply completes instantly it is of little use
WRT measuring its timings.

for example, one might want to time the loop by itself, and then time
the loop doing some simple task, ...

but, for other reasons, one might not want to disable compiler
optimization outright (say, they want to time an operation as it is with
the compilers' optimizations enabled, ...).

or such...
 
E

Eric Sosman

Doesn't happen with gcc, either. For my part, I would not expect a
null statement to result in a NOP (as opposed to no code at all).

I guess my question is, why do you need the NOPs to be generated? Is
it a timing issue? If so, there may be a better way to accomplish it,
if not a more portable way (frankly, if we're talking about generating
specific opcodes, we've thrown portability out the window already).

A thought: The O.P. feels that the null statement ";" should
be translated as a single no-op instruction. Why not a hundred?
Or a hundred million?
 
J

James Dow Allen

Am I the only one pretty sure that OP (and some other recent OP's
with foolish questions) are trolls? (Does Edward Rutherford
even have any prior Usenet history?)

But let me participate anyway! I'll inject some useless comments
from the distant past. On the CDC 6x00 machines, instruction
words often had to be padded out with NOP's. Was I the only
one perverse enough to note that on the 6400 one half-word
SB0 B0+0 instruction was faster than *two* quarter-word NOP's?

"DIAG" actually.  A problem for the assembler is that Diagnose doesn't
even have a defined format.

I had an unusual job for a while that meant I was coding and
even inventing Diagnose instructions for several 370 models.
IIRC, the only Diagnoses typical for O.S.'es were to specify
error-recording modes, but there were other nifty possibilities.
But I sometimes found it more convenient to associate new
diagnostic firmware functions with unused opcodes. Great fun
when maintenance personnel forgot to re-Impl before returning
machine to customer. ::whack::

James Dow Allen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,083
Messages
2,570,589
Members
47,211
Latest member
JaydenBail

Latest Threads

Top