By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,852 Members | 945 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,852 IT Pros & Developers. It's quick & easy.

CPU simulator written in C

P: n/a
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.

Any help (links, tricks/tips...)
would be really appreciated.

Thanks in advance.
Nov 14 '05 #1
Share this Question
Share on Google+
61 Replies


P: n/a
In 'comp.lang.c', /* frank */ <__*******@despammed.com> wrote:
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents
It's a design question. There is no particular problem with that. It's just
another interpreter.
I tried to search con google with no success.


Better to dig your brain. The answer is there.

BTW, what is your question about the C-language?

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=c99
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/
Nov 14 '05 #2

P: n/a
/* frank */ <__*******@despammed.com> wrote:
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.


Your assignment said: "_make_ a CPU simulator". Not "copy a CPU
simulator". There is a very good reason for this. How do you expect to
learn anything if you just hand in someone else's work?

Richard
Nov 14 '05 #3

P: n/a
/* frank */ wrote:
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.

Any help (links, tricks/tips...)
would be really appreciated.


The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable. Now you should create
mappings for registers, .... It's not that complicated.

HTH

Case

Nov 14 '05 #4

P: n/a
Case ha scritto:
It's not that complicated.


Thanks a lot.

I was searching only for a "starting input" .
Nov 14 '05 #5

P: n/a
/* frank */ wrote:
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.

Any help (links, tricks/tips...)
would be really appreciated.


You are searching with the wrong target word. The proper word is emulate,
not simulate.

To simulate is to try to predict how fast some CPU design (probably unbuilt)
will be. To emulate is to produce the effect on computer B that a program
was run on computer A. If you do not have source code for A, there are not
too many alternatives. In the real world you would have machine code, not
an asm file - which is a different thing. But it is easier to communicate
between humans with asm than with machine code.
Nov 14 '05 #6

P: n/a
In <2j*************@uni-berlin.de> /* frank */ <__*******@despammed.com> writes:
I have to do a homework: make a CPU simulator using C language.
Well, C is particularly suitable for such an exercise.
I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.

Any help (links, tricks/tips...)
would be really appreciated.


Apart from being lazy, you're also stupid if you can expect any help
without specifying the CPU being emulated and the format of the .asm
files. I hope they're containing machine code and not assembly code,
because assemblying the code is, by far, the most difficult part of the
exercise.

Anyway, you can't expect any help until you describe your design and
ask very specific questions about its implementation.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #7

P: n/a
/* frank */ wrote:
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.

Any help (links, tricks/tips...)
would be really appreciated.

Thanks in advance.


Ha! I wrote something like this at the University.

I also wrote another one at my current worksite.

Here are some techniques:
1. Allocate variables for all registers.

2. You may need variables for the databus(es) too.

3. Write a simple program that executes a simple
instruction, such as adding two registers.

3.1 This may involve writing a function that simulates
a hardware adder. In my case, I had to put a value
onto a databus, have the adder retrieve from the
databus and repeat for the other argument. Another
function would trigger the actual addition, then
another function puts the sum onto the databus.

4. Once you get the above working, add a new feature
and test it. The paradigm of "Test Driven Development"
says to write the test first and expect the first
invocation to fail, since you haven't written the
code yet.

If you have a windowing operating system, you could
display the register contents and the databus contents
in separate windows.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book

Nov 14 '05 #8

P: n/a
/* frank */ wrote:
Case ha scritto:
It's not that complicated.

I was searching only for a "starting input" .


That's what I thought. Good luck!

Case

Nov 14 '05 #9

P: n/a
On Wed, 23 Jun 2004 07:35:41 +0200, /* frank */
<__*******@despammed.com> wrote:
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.

Any help (links, tricks/tips...)
would be really appreciated.

Thanks in advance. I googled eax ebx ecx edx ax bx in com.lang.c
-->
_______________________
In article <19*******************@darwin.ntu.edu.au> cj*@dme.nt.gov.au
writes:I have repeatedly come across declarations of
the type 'struct REGS' (i think that was what was called,
have seen a few variations) and was wondering if
someone could tell me it's contents, and what it is used for.
I only have a very basic shareware compiler (for my PC anyway,
and I have never seen it under Unix) and it has no mention of this
structure.

Could someone enlighten me ?


This is not a Unix item but strictly a PC item as follows:

union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};

struct WORDREGS {
unsigned int ax, bx, cx, dx;
unsigned int si, di, cflag, flags;
};

struct BYTEREGS {
unsigned char al, ah, bl, bh;
unsigned char cl, ch, dl, dh;
};

These structures allow C programs on PCs to access the CPU registers.

AX,BX,CX,DX,SI,DI,CF(carry flag),and FLAGS are all Intel 80x86
registers
AL/AH,BL/BH,CL/CH,DL/DH are pseudo 8 bit registers which are derived
from the
AL = Low half of AX, AH = High half of AX, etc.

The basic registers are 16 bits while the extended registers are 32
bits
EAX,EBX,ECX,EDX, etc.

In addition you have the segment registers CS,DS,ES,SS and the
pointers
SP,BP plus the index registers SI,DI and on the 80386 and above you
also
have debug registers.

In protected mode the segment registers become selector registers.

The segments are as follows:
CS code segment
DS data segment
ES extra segment
SS stack segment

The pointers are:
SP stack pointer
BP base pointer
--
Scott Hopson (sc****@filenet.com)
____________________________________________

Hi,

I am not really familiar with interrupt calls, especially when done in
a 32 Bit OS enviroment.

I using the WatCom C Compiler Ver. 11b building 32 Bit Dos
applications.

I am trying to call interrupt 2FH, function 0DH for detecting the
driveletters of all connected cdroms.

I programmed this under 16bit dos and it works well, but I am not sure
how to adapt it for 32 Bit.

I have enclosed the code for 16 Bit. I would be pleased if anyone can
give advice.

Thanks a lot in advance.

Philipp

{
union REGS regs;
struct SREGS sregs;
char driveLetters [27];

regs.x.ax = 0x150D;
sregs.es = FP_SEG (driveLetters);
regs.x.bx = FP_OFF (driveLetters);
int86x (0x2F, &regs, &regs, &sregs);
}

**********************
* Auszug aus <i86.h> *
**********************
struct DWORDREGS {
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
unsigned int esi;
unsigned int edi;
unsigned int cflag;
};
struct WORDREGS {
unsigned short ax; __FILLER(_1)
unsigned short bx; __FILLER(_2)
unsigned short cx; __FILLER(_3)
unsigned short dx; __FILLER(_4)
unsigned short si; __FILLER(_5)
unsigned short di; __FILLER(_6)
#if defined(__WINDOWS_386__)
unsigned short cflag;
#else
unsigned int cflag;
#endif
};
struct BYTEREGS {
unsigned char al, ah; __FILLER(_1)
unsigned char bl, bh; __FILLER(_2)
unsigned char cl, ch; __FILLER(_3)
unsigned char dl, dh; __FILLER(_4)
};
union REGS {
#if defined(__386__) && !defined(__WINDOWS_386__)
struct DWORDREGS x;
#else
struct WORDREGS x;
#endif
struct WORDREGS w;
struct BYTEREGS h;
};
struct SREGS {
unsigned short es, cs, ss, ds;
#if defined(__386__)
unsigned short fs, gs;
#endif
};
Nov 14 '05 #10

P: n/a
/* frank */ <__*******@despammed.com> wrote in message news:<2j*************@uni-berlin.de>...
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.

Any help (links, tricks/tips...)
would be really appreciated.

Thanks in advance.


didn't you get *any* hints at all on how to takle this?
Out of the goodness of my heart:-

typedef unsigned char Byte;
typedef unsigned long Register;

Byte memory [1024};

Register rA; /* accumulator */
Register pc; /* program counter */
Register rI; /* instruction register */
Register fetch32 (void)
{
Register f;

f = *pc++;
f = (f << 8) & *pc++;
f = (f << 8) & *pc++;
f = (f << 8) & *pc++;
}
void execute (void)
{
rI = fetch32 (); /* 32-bit fetch */

while (rI != HALT)
{
/* identify the instruction */
/* process the instruction */
}
}

int main (void)
{
/* load memory somehow */
pc = memory;
execute ();
}
this is untested. It hasn't even been compiled.
Nov 14 '05 #11

P: n/a
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:
The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.


An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #12

P: n/a
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:

The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.

An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.


<OT degree="severe">

I once worked on an actual machine whose program counter
registers (there were two) were signed -- the explanation
given was that the same circuitry implemented all the machine's
registers, so the signedness of the PCs was just a by-product
of parsimonious hardware design. However, only the low-order
bits of the active PC participated in address generation; the
sign bits and high-order bits were simply ignored.

So far, just an amusing peculiarity. But the really odd
thing was that the operation of "increment the program counter"
was implemented as the arithmetic operation "add one to the
program counter" -- so if the PC contained a negative value,
the effect was that the program ran backwards! I got some
diversion out of dreaming up a code sequence that executed
in the usual fashion for a while and then negated the PC and
"backed out" by re-executing the preceding instructions in
reverse order ...

</OT>

--
Er*********@sun.com

Nov 14 '05 #13

P: n/a
In <2j*************@uni-berlin.de> "osmium" <r1********@comcast.net> writes:
/* frank */ wrote:
I have to do a homework: make a CPU simulator using C language.

I have a set of asm instructions so I have to write a program
that should:
- load .asm file
- view .asm file
- do a step by step simulation
- display registers contents

I tried to search con google with no success.

Any help (links, tricks/tips...)
would be really appreciated.


You are searching with the wrong target word. The proper word is emulate,
not simulate.

To simulate is to try to predict how fast some CPU design (probably unbuilt)
will be. To emulate is to produce the effect on computer B that a program
was run on computer A.


You're splitting hairs. Try googling for "8051 simulator".

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #14

P: n/a
Nick Keighley wrote:
/* frank */ <__*******@despammed.com> wrote in message news:<2j*************@uni-berlin.de>...
I have to do a homework: make a CPU simulator using C language. Out of the goodness of my heart:-

typedef unsigned char Byte;
typedef unsigned long Register;

Byte memory [1024};


Typo here }

Register rA; /* accumulator */
Register pc; /* program counter */
Register rI; /* instruction register */
Register fetch32 (void)
{
Register f;

f = *pc++;
To do this, pc should at least be a pointer.
f = (f << 8) & *pc++;
f = (f << 8) & *pc++;
f = (f << 8) & *pc++;
Of course you mean: f = (f << 8) | *pc++;
}
void execute (void)
{
rI = fetch32 (); /* 32-bit fetch */

while (rI != HALT)
{
/* identify the instruction */
/* process the instruction */
}
}

int main (void)
{
/* load memory somehow */
pc = memory;
Because memory is unsigned char[] (or IAW unsigned char *)
and pc is unsigned long, this will not work.
execute ();
}
this is untested. It hasn't even been compiled.


Will not compile, and doesn't compute either ;-)

<OT>
Why not simply use the pc as an index in memory? This
would allow you to write memory[pc]. And doesn't this
perfectly match what a PC does, being an index into a
block of data?
<\OT>

Case

Nov 14 '05 #15

P: n/a
/* frank */ wrote:
Case ha scritto:
It's not that complicated.

Thanks a lot.

I was searching only for a "starting input" .


I write a lot of these. Here are some hints.

1. I would skip the .asm part unless you have some sort of class
assignment going on that requires it. Its an unecessary complication
to have to assemble the code yourself. Better is to figgure out how
to get a "straight binary image" from a standard assembler and use
that. A binary image would contain only the code, without symbols
and other window dressing.

2. Contructing C structures or variables that contain the registers
and flags for the target CPU, these will "overflow" in C without
error. However, you will still need to make a routine that checks
what flags were set during that operation. Typically this is done
by examining the result and the operands, and checking if the result
makes sense. For example, adding two positive numbers and getting
a negative result means an overflow occurred.

3. Although common instruction sets today can be quite large, say
32 bits or more for an instruction, there is typically a much
shorter section of the instruction that determines what instruction
type is being processed. Your typical "execute" case statement
will extract that field and form a case based on that. Be prepared
for a large case statement on most current CPUs. This is good,
because it means your emulator will be fast.

Luck !

--
Samiam is Scott A. Moore

Personal web site: http:/www.moorecad.com/scott
My electronics engineering consulting site: http://www.moorecad.com
ISO 7185 Standard Pascal web site: http://www.moorecad.com/standardpascal
Classic Basic Games web site: http://www.moorecad.com/classicbasic
The IP Pascal web site, a high performance, highly portable ISO 7185 Pascal
compiler system: http://www.moorecad.com/ippas

Being right is more powerfull than large corporations or governments.
The right argument may not be pervasive, but the facts eventually are.
Nov 14 '05 #16

P: n/a
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:

The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.

An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.


I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)

Yes, you're right, the PC is best typed as unsigned. I'm not sure
about the registers. Values in registers are seen as 2-s complement
by instruction in at least some CPU's (e.g., MIPS has pairs of
similar instructions for singed and unsigned register operand).

Case

Nov 14 '05 #17

P: n/a
Case - wrote:
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:

The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.


An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.

I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)

Yes, you're right, the PC is best typed as unsigned. I'm not sure
about the registers. Values in registers are seen as 2-s complement
by instruction in at least some CPU's (e.g., MIPS has pairs of
similar instructions for singed and unsigned register operand).


Note that you must issue the occasional no-op when
using instructions of the first type, to give the singed
registers time to cool.

--
Er*********@sun.com

Nov 14 '05 #18

P: n/a
for me it is difficult write a portable and *fast* x86 cpu in C
(it has to execute an OS)
I'm a beginner but I would 'solve' the problem in this way:

___________________________________
#include <stdio.h>
#include <stdint.h> /* or stddef don't remember for uintxx_t */

struct r16{
uint8_t rl; /* uintXX_t would be in the standard c c89 */
uint8_t rh; /* so it is portable: it is ok in every cpu */
}; /* but in the x86 cpu a register is good for
signed
and unsigned calculation */
struct r32{
struct r16 ac;
uint16_t sn;
};
/* all global */
struct r32 eax_={0}, ebx_={0}, ecx_={0}, edx_={0};

/* they are static so until I don't write ={0} they are ={0} ie all 0
at the start of prog */

struct r32 esi_, edi_, ebp_, esp_, eip_;
uint16_t cs_, ds_, es_, ss_, fs_, gs_, flags_;

struct r32 *eax= &eax_, *ebx= &ebx_, *ecx= &ecx_, *edx= &edx_;
struct r32 *esi= &esi_, *edi= &edi_, *ebp= &ebp_, *esp= &esp_,
*eip = &eip_;
uint16_t *cs=&cs_, *ds=&ds_, *es=&es_, *ss=&ss_, *fs=&fs_,
*gs=&gs_, *falgs=&flags_;
#define ax eax->ac
#define al eax->ac.rl
#define ah eax->ac.rh

#define bx ebx->ac
#define bl ebx->ac.rl
#define bh ebx->ac.rh

#define cx ecx->ac
#define cl ecx->ac.rl
#define ch ecx->ac.rh

#define dx edx->ac
#define dl edx->ac.rl
#define dh edx->ac.rh

#define sp esp->ac
#define bp ebp->ac
#define si esi->ac
#define di edi->ac
#define ip eip->ac
#define U unsigned
#define P printf

void assign(struct r32* a, uint32_t b)
{uint8_t l, h;
/*--------------*/
(*a).sn = (b>>16) & 0xFFFF;
(*a).ac.rl = b & 0xFF;
(*a).ac.rh = b>>8;
}

void Pr(struct r32* a)
{uint32_t b;
/*----------------*/
b=(*a).sn;
//P("a.sn=%u", (U) a.sn);
b <<= 16;
b |= ((uint32_t) (*a).ac.rh << 8 ) | (*a).ac.rl;
printf("%x", (int) b);
fflush(stdout);
}

void somma(struct r32* a,struct r32* b)
{uint32_t bb, aa;
/*----------------*/
aa =(*a).sn; aa <<= 16;
aa |= ((uint32_t) (*a).ac.rh << 8 ) | (*a).ac.rl;
bb = b->sn; bb <<= 16;
bb |= ((uint32_t) b->ac.rh << 8 ) | b->ac.rl;
bb += aa;
assign(a, bb);
}

/* it is difficult but main() has to
1) read in a file in binary form a instructon
2) perform that istruction in the program
*/

int main(void)
{
assign( eax , 0xFEFEFEFE); assign( ebx , 0xFAFAFAFA);
P("eax="); Pr(eax); P(" ebx="); Pr(ebx); P("\n");
assign(ecx, 50000); assign(edx, 512341);
somma(ecx, edx);
P("ecx="); Pr(ecx); P(" edx="); Pr(edx); P("\n");
printf("somma=%x", (int)(50000 + 512341) );
return 0;
}

/*
eax=fefefefe ebx=fafafafa
ecx=894a5 edx=7d155
somma=894a5
*/

Nov 14 '05 #19

P: n/a
>This is not a Unix item but strictly a PC item as follows:

union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};

struct WORDREGS {
unsigned int ax, bx, cx, dx;
unsigned int si, di, cflag, flags;
};

struct BYTEREGS {
unsigned char al, ah, bl, bh;
unsigned char cl, ch, dl, dh;
};

These structures allow C programs on PCs to access the CPU registers.

AX,BX,CX,DX,SI,DI,CF(carry flag),and FLAGS are all Intel 80x86
registers
AL/AH,BL/BH,CL/CH,DL/DH are pseudo 8 bit registers which are derived
from the
AL = Low half of AX, AH = High half of AX, etc.
I have to really wonder about this design for a CPU emulator. Some
of the registers listed above share storage (for example, ax consists
of ah and al concatenated, and eax contains ax). Every time you
change one register (e.g. eax, ax, al, or ah), you have to change
all of them, or keep track of which one is more up to date. This
tends to make things slow. and bug-prone, if you're not careful.
Assembly code WILL occasionally make use of this fact, for example,
loading ah with 0 to do an unsigned-extension of al into ax may be
the fastest way to accomplish this.

There may also be reasons for representing some of the registers as an
array. For example, the field in a machine instruction that specifies
a register may be consistent enough that isolating that field and using
it as an array index may be useful.
The basic registers are 16 bits while the extended registers are 32
bits
EAX,EBX,ECX,EDX, etc.

In addition you have the segment registers CS,DS,ES,SS and the
pointers
SP,BP plus the index registers SI,DI and on the 80386 and above you
also
have debug registers.

In protected mode the segment registers become selector registers.


There are a number of registers not mentioned above in the *86
architecture (and this isn't complete either). I realize the above
wasn't intended to be a complete list.

- EFLAGS, EIP, EDI, ESI, ESP, EBP
- Segment registers FS and GS
- Floating point registers
- Control registers
- Machine specific registers
- Portions of the "hidden" part of selector registers can become visible
under the right circumstances.
- GDTR, IDTR, Task register, and LDTR
- MMX and XMM registers (which may overlap with others)
Gordon L. Burditt
Nov 14 '05 #20

P: n/a
><OT>
Why not simply use the pc as an index in memory? This
would allow you to write memory[pc]. And doesn't this
This is a great idea for simpler CPUs without memory management
hardware, and especially for CPUs where the maximum addressable
memory of the emulated CPU (e.g. Z80 or 8086) is small (e.g. 64k
bytes or even 1MB) compared to the available RAM of the host CPU
running the emulation.
perfectly match what a PC does, being an index into a
block of data?
Yes, given the absence of memory management. Just Intel segment-register
mappings don't make it THAT hard, but protected-mode memory management
can make it much harder. With memory management, things get
complicated all of a sudden, especially if it's allowed for a
multi-byte integer fetch to straddle memory-management pages, and
where multiple very-different addresses can refer to the same block
of memory.
<\OT>


Gordon L. Burditt
Nov 14 '05 #21

P: n/a
Gordon Burditt wrote:
<OT>
Why not simply use the pc as an index in memory? This
would allow you to write memory[pc]. And doesn't this


This is a great idea for simpler CPUs without memory management
hardware, and especially for CPUs where the maximum addressable
memory of the emulated CPU (e.g. Z80 or 8086) is small (e.g. 64k
bytes or even 1MB) compared to the available RAM of the host CPU
running the emulation.
perfectly match what a PC does, being an index into a
block of data?


Yes, given the absence of memory management. Just Intel segment-register
mappings don't make it THAT hard, but protected-mode memory management
can make it much harder. With memory management, things get
complicated all of a sudden, especially if it's allowed for a
multi-byte integer fetch to straddle memory-management pages, and
where multiple very-different addresses can refer to the same block
of memory.


I didn't think of this in the context of OP's homework
assignment. Thanks for the extra info! CPU (and virtual
machine) design is and remains a very interesting subject.

Case
<\OT>


Nov 14 '05 #22

P: n/a
In article <40**************@sun.com>,
Eric Sosman <Er*********@Sun.COM> wrote:
SNIP....`

I once worked on an actual machine whose program counter
registers (there were two) were signed -- the explanation
given was that the same circuitry implemented all the machine's
registers, so the signedness of the PCs was just a by-product
of parsimonious hardware design. However, only the low-order
bits of the active PC participated in address generation; the
sign bits and high-order bits were simply ignored.

So far, just an amusing peculiarity. But the really odd
thing was that the operation of "increment the program counter"
was implemented as the arithmetic operation "add one to the
program counter" -- so if the PC contained a negative value,
the effect was that the program ran backwards! I got some
diversion out of dreaming up a code sequence that executed
in the usual fashion for a while and then negated the PC and
"backed out" by re-executing the preceding instructions in
reverse order ...


Huh?

0x8000 = -32768
0x8000 + 1 = 0x8001 = -32767
0x8001 + 1 = 0x8002 = -32766
....

Show me where adding 1 to a negative binary number will cause the low
order bits to "run backwards" compared to adding 1 to an unsigned binary
number.
Nov 14 '05 #23

P: n/a
Dan Pop

OP:> >> I tried to search con google with no success.

Osmium:> >You are searching with the wrong target word. The proper word is
emulate,
not simulate.

POP:> You're splitting hairs. Try googling for "8051 simulator".

If you think you will shock me by revealing that people sometimes use the
wrong word, you have failed miserably.

When using something such as google, where the basic commodity is the right
word spelled properly, it is best to use the right word if you know it. If
you consider that hair splitting, feel free to continue to think so.
Nov 14 '05 #24

P: n/a
jd*@smof.fiawol.org (John Cochran) wrote in message news:<cb**********@smof.fiawol.org>...
0x8000 = -32768
0x8000 + 1 = 0x8001 = -32767
0x8001 + 1 = 0x8002 = -32766
...

Show me where adding 1 to a negative binary number will cause the low
order bits to "run backwards" compared to adding 1 to an unsigned binary
number.


Repeat your demonstration using sign and magnitude representation in
place of two's complement.
Nov 14 '05 #25

P: n/a
On Wed, 23 Jun 2004 19:10:38 GMT, RoSsIaCrIiLoIA <n@esiste.ee> wrote:
for me it is difficult write a portable and *fast* x86 cpu in C
(it has to execute an OS)
I'm a beginner but I would 'solve' the problem in this way:

___________________________________
#include <stdio.h>
#include <stdint.h> /* or stddef don't remember for uintxx_t */

struct r16{
uint8_t rl; /* uintXX_t would be in the standard c c89 */
uint8_t rh; /* so it is portable: it is ok in every cpu */
}; /* but in the x86 cpu a register is good for
signed
and unsigned calculation */
struct r32{
struct r16 ac;
uint16_t sn;
};
/* all global */
struct r32 eax_={0}, ebx_={0}, ecx_={0}, edx_={0};

/* they are static so until I don't write ={0} they are ={0} ie all 0
at the start of prog */

struct r32 esi_, edi_, ebp_, esp_, eip_;
uint16_t cs_, ds_, es_, ss_, fs_, gs_, flags_;

struct r32 *eax= &eax_, *ebx= &ebx_, *ecx= &ecx_, *edx= &edx_;
struct r32 *esi= &esi_, *edi= &edi_, *ebp= &ebp_, *esp= &esp_,
*eip = &eip_;
uint16_t *cs=&cs_, *ds=&ds_, *es=&es_, *ss=&ss_, *fs=&fs_,
*gs=&gs_, *falgs=&flags_;


But I prefer this:

#include <stdio.h>
#include <stdint.h> /* or stddef don't remember for uintxx_t */

struct r32{
uint32_t e;
uint16_t x;
uint8_t h;
uint8_t l;
};
/* all global */
struct r32 eax_={0}, ebx_={0}, ecx_={0}, edx_={0};
struct r32 esi_, edi_, ebp_, esp_, eip_;
uint16_t cs_, ds_, es_, ss_, fs_, gs_, flags_;

struct r32 *eax= &eax_, *ebx= &ebx_, *ecx= &ecx_, *edx= &edx_;
struct r32 *esi= &esi_, *edi= &edi_, *ebp= &ebp_, *esp= &esp_, *eip
= &eip_;
uint16_t *cs=&cs_, *ds=&ds_, *es=&es_, *ss=&ss_, *fs=&fs_,
*gs=&gs_, *falgs=&flags_;
#define ax eax->x
#define al eax->l
#define ah eax->h

#define bx ebx->x
#define bl ebx->l
#define bh ebx->h

#define cx ecx->x
#define cl ecx->l
#define ch ecx->h

#define dx edx->x
#define dl edx->l
#define dh edx->h

#define sp esp->x
#define bp ebp->x
#define si esi->x
#define di edi->x
#define ip eip->x
#define U unsigned
#define P printf

void assign(struct r32* a, uint32_t b)
{uint8_t l, h;
/*--------------*/
a->e = b;
a->x = (b>>16) & 0xFFFF;
a->h = (b>>8) & 0xFF;
a->l = b & 0xFF;
}
void Pr(struct r32* a)
{printf("%x", (int) a->e);
fflush(stdout);
}

void somma(struct r32* a,struct r32* b)
{assign(a, a->e + b->e);}

int main(void)
{
assign( eax , 0xFEFEFEFE); assign( ebx , 0xFAFAFAFA);
P("eax="); Pr(eax); P(" ebx="); Pr(ebx); P("\n");
assign(ecx, 50000); assign(edx, 512341);
somma(ecx, edx);
P("ecx="); Pr(ecx); P(" edx="); Pr(edx); P("\n");
printf("somma=%x", (int)(50000 + 512341) );
return 0;
}
Nov 14 '05 #26

P: n/a
On Thu, 24 Jun 2004 07:28:14 GMT, RoSsIaCrIiLoIA <n@esiste.ee> wrote:
But I prefer this:

#include <stdio.h>
#include <stdint.h> /* or stddef don't remember for uintxx_t */

struct r32{
uint32_t e;
uint16_t x;
uint8_t h;
uint8_t l;
};
/* all global */
struct r32 eax_={0}, ebx_={0}, ecx_={0}, edx_={0};
struct r32 esi_, edi_, ebp_, esp_, eip_;
uint16_t cs_, ds_, es_, ss_, fs_, gs_, flags_;


better this:

#include <stdio.h>
#include <stdint.h> /* or stddef don't remember for uintxx_t */
/* all global */
uint32_t eax, ebx, ecx, edx;
uint32_t esi, edi, ebp, esp, eip;
uint16_t cs, ds, es, ss, fs, gs, flags;

union u{
uint32_t e;
uint16_t x;
uint8_t l;
};

#define ax (eax & 0xFFFF)
#define al (eax & 0xFF )
#define ah ( (eax >>8) & 0xFF )

#define bx (ebx & 0xFFFF)
#define bl (ebx & 0xFF )
#define bh ( (ebx >>8) & 0xFF )

#define cx (ecx & 0xFFFF)
#define cl (ecx & 0xFF )
#define ch ( (ecx >>8) & 0xFF )

#define dx (edx & 0xFFFF)
#define dl (edx & 0xFF )
#define dh ( (edx >>8) & 0xFF )

#define sp esp & 0xFFFF
#define bp ebp & 0xFFFF
#define si esi & 0xFFFF
#define di edi & 0xFFFF
#define ip eip & 0xFFFF
#define U unsigned
#define P printf

void inc_x(uint32_t* a)
{uint16_t r;
/*-------------*/
r = *a & 0xFFFF; ++r;
// P(" r=%x ", (int) r );
*a = *a & ((uint32_t) 0xFFFF0000 | r);
}

void inc_l(uint32_t* a)
{uint8_t r;
/*-------------*/
r = *a & 0xFF; ++r;
*a = *a & ((uint32_t)0xFFFFFF00 | r);
}

/* don't know if it is ok */
void inc_l1(uint32_t* a)
{++( (*(union u*)a).l );}

/* don't know if it is ok */
void inc_x1(uint32_t* a)
{++( (*(union u*)a).x );}

void inc_h(uint32_t* a)
{uint8_t r;
/*-------------*/
r = (*a>>8) & 0xFF; ++r;
*a = *a & ( 0xFFFF00FF | (uint32_t) r << 8 );
}

int main(void)
{
eax = 0xFEFEFEFE; ebx = 0xFAFAFAFA;
P("eax=0x%x ebx=Ox%x\n", (int) eax, (int) ebx);
ecx=50000; edx=512341;
ecx += edx;
printf("somma=0x%x\n", (int)(50000 + 512341) );
eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_x(&eax); /* inc ax */
P("inc ax -> eax=0x%x ax=0x%x\n", (int) eax, (int) ax );

eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_x1(&eax); /* inc ax [& union] */
P("inc ax -> eax=0x%x ax=0x%x\n", (int) eax, (int) ax );

eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_l(&eax); /* inc al */
P("inc ax -> eax=0x%x al=0x%x\n", (int) eax, (int) al );

eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_h(&eax); /* inc ah */
P("inc ah -> eax=0x%x ah=0x%x\n", (int) eax, (int) ah );

return 0;
}

Nov 14 '05 #27

P: n/a
"Case -" <no@no.no> wrote in message
news:40**********************@dreader2.news.tiscal i.nl...
Dan Pop wrote:
An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.
I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)


;-)
Yes, you're right, the PC is best typed as unsigned. I'm not sure
about the registers. Values in registers are seen as 2-s complement
by instruction in at least some CPU's (e.g., MIPS has pairs of
similar instructions for singed and unsigned register operand).


It's straightforward to simulate a 2's complement CPU using unsigned
integers, with the semantics C guarantees. This is for the same reason that
2's complement is popular.

Alex
Nov 14 '05 #28

P: n/a
In <2j*************@uni-berlin.de> "osmium" <r1********@comcast.net> writes:
Dan Pop

OP:> >> I tried to search con google with no success.

Osmium:> >You are searching with the wrong target word. The proper word is
emulate,
>not simulate.

POP:> You're splitting hairs. Try googling for "8051 simulator".

If you think you will shock me by revealing that people sometimes use the
wrong word, you have failed miserably.


Many of these people were vendors of such products. But, of course,
you know better than them...

If you were capable to conceive the notion that you might be wrong, the
google exercise would have been quite useful to you.

Contrary to your narrow ideas, there are many levels of software
CPU simulation, serving different purposes, and none of them is less
entitled to the name "simulation" than the others:

- sub-transistor level simulation: used for checking the correctness of
the chip design.

- transistor level simulation: used for checking the correctness of the
CPU implementation.

- gate level simulation: used for checking the correctness of the CPU
design.

- register to register transfer level simulation: used to evaluate the
CPU design performance.

- functional simulation, kernel mode: used for developing operating
system kernels and freestanding applications.

- functional simulation, user mode: used for developing hosted
applications (much faster than kernel mode simulation, as the OS kernel
functionality is provided by the simulator, instead of having the
simulated processor execute kernel code).

The last two simulation levels are *also* called emulation. In the case
of some very popular embedded control CPUs, hardware emulation is often
used for software development purposes instead of the real processor,
because it has much better debugging capabilities.

The Linux to Itanium port was done using "ski", a functional simulator
developed by HP and gcc as a cross-compiler on x86 hardware.
The kernel people used ski in kernel mode, the glibc people used it in
user mode. Everything was ready by the time Intel produced the first
silicon prototypes of Itanium. I don't remember anyone calling ski
"emulator", although it wouldn't have been technically incorrect.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #29

P: n/a
Eric Sosman wrote:
Case - wrote:
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:
The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.


An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.


I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)

Yes, you're right, the PC is best typed as unsigned. I'm not sure
about the registers. Values in registers are seen as 2-s complement
by instruction in at least some CPU's (e.g., MIPS has pairs of
similar instructions for singed and unsigned register operand).

Note that you must issue the occasional no-op when
using instructions of the first type, to give the singed
registers time to cool.


Is this some kind of joke?

Case

Nov 14 '05 #30

P: n/a
Eric Sosman wrote:
Case - wrote:
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:
The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.


An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.


I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)

Yes, you're right, the PC is best typed as unsigned. I'm not sure
about the registers. Values in registers are seen as 2-s complement
by instruction in at least some CPU's (e.g., MIPS has pairs of
similar instructions for singed and unsigned register operand).

Note that you must issue the occasional no-op when
using instructions of the first type, to give the singed
registers time to cool.


I've worked on a MIPS assembler for a short while, and know
all about NOPs in delay slots; but I can't remember to have
seen any code in that assembler generating cooling NOPs.

So, is this somekind of joke, or a cool feature? :-)

Case

Nov 14 '05 #31

P: n/a
In <40**********************@dreader2.news.tiscali.nl > Case - <no@no.no> writes:
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:

The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.

An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.


I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)


Nope, in C int is a synonym for signed int:

2 At least one type specifier shall be given in the declaration
specifiers in each declaration, and in the specifier-qualifier
list in each struct declaration and type name. Each list of
type specifiers shall be one of the following sets (delimited
by commas, when there is more than one set on a line); the type
specifiers may occur in any order, possibly intermixed with the
other declaration specifiers.
....
- int, signed, or signed int
....

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #32

P: n/a
In <40**********************@dreader2.news.tiscali.nl > Case - <no@no.no> writes:
Yes, you're right, the PC is best typed as unsigned. I'm not sure
about the registers.
I am. Think hard about the properties of two's complement arithmetic and
the semantics of unsigned arithmetic in C.
Values in registers are seen as 2-s complement
by instruction in at least some CPU's (e.g., MIPS has pairs of
similar instructions for singed and unsigned register operand).


That's why you want unsigned, which nicely simulates two's complement
behaviour.

CISC CPUs using two's complement have only one ADD instruction and set
their flags according to the result (if the Carry flag is set, unsigned
overflow occured, if the Overflow flag is set, signed overflow occured).
If no flag is set, the result is correct if interpreted as both signed
and unsigned. Implementing this in C, using unsigned arithmetic, is left
as an exercise for the reader.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #33

P: n/a
Case wrote:
Eric Sosman wrote:
Case - wrote:
Dan Pop wrote:
.... snip ...
Yes, you're right, the PC is best typed as unsigned. I'm not sure
about the registers. Values in registers are seen as 2-s complement
by instruction in at least some CPU's (e.g., MIPS has pairs of
similar instructions for singed and unsigned register operand).


Note that you must issue the occasional no-op when
using instructions of the first type, to give the singed
registers time to cool.


I've worked on a MIPS assembler for a short while, and know
all about NOPs in delay slots; but I can't remember to have
seen any code in that assembler generating cooling NOPs.

So, is this somekind of joke, or a cool feature? :-)


It's a cool feature, else those singed registers are liable to
char, which would make them incapable of holding anything
passively unsinged.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #34

P: n/a
Dan Pop wrote:
.... snip ...
Many of these people were vendors of such products. But, of
course, you know better than them...

^^^^
Aha! Finally caught in an English inaccuracy. They. :-)

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #35

P: n/a
John Cochran wrote:
In article <40**************@sun.com>,
Eric Sosman <Er*********@Sun.COM> wrote:
SNIP....`
I once worked on an actual machine whose program counter
registers (there were two) were signed -- the explanation
given was that the same circuitry implemented all the machine's
registers, so the signedness of the PCs was just a by-product
of parsimonious hardware design. However, only the low-order
bits of the active PC participated in address generation; the
sign bits and high-order bits were simply ignored.

So far, just an amusing peculiarity. But the really odd
thing was that the operation of "increment the program counter"
was implemented as the arithmetic operation "add one to the
program counter" -- so if the PC contained a negative value,
the effect was that the program ran backwards! I got some
diversion out of dreaming up a code sequence that executed
in the usual fashion for a while and then negated the PC and
"backed out" by re-executing the preceding instructions in
reverse order ...

Huh?

0x8000 = -32768
0x8000 + 1 = 0x8001 = -32767
0x8001 + 1 = 0x8002 = -32766
...

Show me where adding 1 to a negative binary number will cause the low
order bits to "run backwards" compared to adding 1 to an unsigned binary
number.


It seems I neglected to mention that the machine used
signed magnitude representation for negative integers:

-32768 = 0x800000008000
-32768 + 1 = -32767 = 0x800000007FFF
-32767 + 1 = -32766 = 0x800000007FFE
...

Sorry for the omission. Honeywell 8200, IIRC, and I think
the year was 1968.

--
Er*********@sun.com

Nov 14 '05 #36

P: n/a
In <40***************@yahoo.com> CBFalconer <cb********@yahoo.com> writes:
Dan Pop wrote:

... snip ...

Many of these people were vendors of such products. But, of
course, you know better than them...

^^^^
Aha! Finally caught in an English inaccuracy. They. :-)


If this is my first English inaccuracy you've caught in one of my posts,
you must be *really* reading them with your brain firmly set into Neutral.

Given that I've never even tried to learn the proper English grammar and
that I'm posting quite a lot, there *must* be several English mistakes in
my daily output... (without even mentioning typos and omitted words)

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #37

P: n/a
On 23 Jun 2004 19:57:26 GMT, (Gordon Burditt) wrote:
This is not a Unix item but strictly a PC item as follows:

union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};

struct WORDREGS {
unsigned int ax, bx, cx, dx;
unsigned int si, di, cflag, flags;
};

struct BYTEREGS {
unsigned char al, ah, bl, bh;
unsigned char cl, ch, dl, dh;
};

These structures allow C programs on PCs to access the CPU registers.

AX,BX,CX,DX,SI,DI,CF(carry flag),and FLAGS are all Intel 80x86
registers
AL/AH,BL/BH,CL/CH,DL/DH are pseudo 8 bit registers which are derived
from the
AL = Low half of AX, AH = High half of AX, etc.


I have to really wonder about this design for a CPU emulator. Some
of the registers listed above share storage (for example, ax consists
of ah and al concatenated, and eax contains ax). Every time you
change one register (e.g. eax, ax, al, or ah), you have to change
all of them, or keep track of which one is more up to date. This
tends to make things slow. and bug-prone, if you're not careful.
Assembly code WILL occasionally make use of this fact, for example,
loading ah with 0 to do an unsigned-extension of al into ax may be
the fastest way to accomplish this.


The "union r32" in my PC seems like a x86 general pourpose register
Are you agree?

#include <stdio.h>
#include <stdint.h> /* or stddef don't remember for uintxx_t */
union r32
{
union
{
struct
{
uint8_t l;
uint8_t h;
}b;
uint16_t val;
}w;
uint32_t val;
};
/* all global */
union r32 eax_, ebx_, ecx_, edx_;
union r32 esi_, edi_, ebp_, esp_, eip_;
uint16_t cs, ds, es, ss, fs, gs, flags;

#define eax (eax_.val)
#define ax (eax_.w.val)
#define al (eax_.w.b.l)
#define ah (eax_.w.b.h)

#define ebx (ebx_.val)
#define bx (ebx_.w.val)
#define bl (ebx_.w.b.l)
#define bh (ebx_.w.b.h)

#define ecx (ecx_.val)
#define cx (ecx_.w.val)
#define cl (ecx_.w.b.l)
#define ch (ecx_.w.b.h)

#define edx (edx_.val)
#define dx (edx_.w.val)
#define dl (edx_.w.b.l)
#define dh (edx_.w.b.h)

#define sp (esp_.w)
#define bp (ebp_.w)
#define si (esi_.w)
#define di (edi_.w)
#define ip (eip_.w)
#define U unsigned
#define P printf
void inc_w(union r32* a)
{++ a->w.val;}

void inc_l(union r32* a)
{++ a->w.b.l;}

void inc_h(union r32* a)
{++ a->w.b.h;}
int main(void)
{
eax = 0xFEFEFEFE; ebx = 0xFAFAFAFA;
P("eax=0x%x ebx=Ox%x\n", (int) eax, (int) ebx);
ecx=50000; edx=512341;
ecx += edx;
printf("somma=0x%x ecx=0x%x\n", (int)(50000 + 512341), (int) ecx );
eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_w(&eax); /* inc ax ; or I would have to write inc_x(&eax_) ? */
P("inc ax -> eax=0x%x ax=0x%x\n", (int) eax, (int) ax );

eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_l(&eax); /* inc al */
P("inc ax -> eax=0x%x al=0x%x\n", (int) eax, (int) al );

eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_h(&eax); /* inc ah */
P("inc ah -> eax=0x%x ah=0x%x\n", (int) eax, (int) ah );

return 0;
}

/*
eax=0xfefefefe ebx=Oxfafafafa
somma=0x894a5 ecx=0x894a5
eax=0xffffffff inc ax -> eax=0xffff0000 ax=0x0
eax=0xffffffff inc ax -> eax=0xffffff00 al=0x0
eax=0xffffffff inc ah -> eax=0xffff00ff ah=0x0
*/

Nov 14 '05 #38

P: n/a
On Thu, 24 Jun 2004 09:31:24 GMT, RoSsIaCrIiLoIA <n@esiste.ee> wrote:

This would be portable.

#include <stdio.h>
#include <stdint.h> /* or stddef don't remember for uintxx_t */

union r32{
uint8_t l;
uint16_t x;
uint32_t val;
};
/* all global */
union r32 eax_, ebx_, ecx_, edx_;
union r32 esi_, edi_, ebp_, esp_, eip_;
uint16_t cs, ds, es, ss, fs, gs, flags;

#define eax (eax_.val)
#define ax (eax_.x)
#define al (eax_.l)
#define ah ( (eax_.x>>8) & 0xFF ) /* not lvalue :-( */

#define ebx (ebx_.val)
#define bx (ebx_.x)
#define bl (ebx_.l)
#define bh ( (ebx_.x>>8) & 0xFF ) /* not lvalue */

#define ecx (ecx_.val)
#define cx (ecx_.x)
#define cl (ecx_.l)
#define ch ( (ecx_.x>>8) & 0xFF ) /* not lvalue */
#define edx (edx_.val)
#define dx (edx_.x)
#define dl (edx_.l)
#define dh ( (edx_.x>>8) & 0xFF ) /* not lvalue */

#define sp (esp_.x)
#define bp (ebp_.x)
#define si (esi_.x)
#define di (edi_.x)
#define ip (eip_.x)
#define U unsigned
#define P printf
void inc_x(union r32* a)
{++ a->x;}

void inc_l(union r32* a)
{++ a->l;}

void inc_h(union r32* a)
{uint8_t r;
/*-------------*/
r = ( a->x >>8) & 0xFF; ++r;
a->val = a->val & ( 0xFFFF00FF | (uint32_t) r << 8 );
}
int main(void)
{
eax = 0xFEFEFEFE; ebx = 0xFAFAFAFA;
P("eax=0x%x ebx=Ox%x\n", (int) eax, (int) ebx);
ecx=50000; edx=512341;
ecx += edx;
printf("somma=0x%x ecx=0x%x\n", (int)(50000 + 512341), (int) ecx );
eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_x(&eax); /* inc ax ; or I would have to write inc_x(&eax_) ? */
P("inc ax -> eax=0x%x ax=0x%x\n", (int) eax, (int) ax );

eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_l(&eax); /* inc al */
P("inc ax -> eax=0x%x al=0x%x\n", (int) eax, (int) al );

eax=0xFFFFFFFF;
printf("eax=0x%x ", (int) eax );
inc_h(&eax); /* inc ah */
P("inc ah -> eax=0x%x ah=0x%x\n", (int) eax, (int) ah );

return 0;
}
Nov 14 '05 #39

P: n/a
Eric Sosman wrote:
Case - wrote:
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:
The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.


An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.


I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)

Yes, you're right, the PC is best typed as unsigned. I'm not sure
about the registers. Values in registers are seen as 2-s complement
by instruction in at least some CPU's (e.g., MIPS has pairs of
similar instructions for singed and unsigned register operand).

Note that you must issue the occasional no-op when
using instructions of the first type, to give the singed
registers time to cool.


You are talking about signed registers. I was talking about the
way a CPU may 'see' the value contained in a register. And we
are talking in the context of mapping CPU to C. Evidently,
reading other posts, you have much much more experience in CPU
design issues. I don't get your point, could you please elaborate?

Case

Nov 14 '05 #40

P: n/a
Dan Pop wrote:
In <40**********************@dreader2.news.tiscali.nl > Case - <no@no.no> writes:
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:
The key idea is to map all parts of a CPU on C structures
and routines. For example: the program counter (PC) can
be simply mapped to an int variable.

An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.


I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)


Nope, in C int is a synonym for signed int:


I was writing English, not C.

Case

Nov 14 '05 #41

P: n/a
Case wrote:
Eric Sosman wrote:

.... snip ...

Note that you must issue the occasional no-op when
using instructions of the first type, to give the singed
registers time to cool.


You are talking about signed registers. I was talking about the


No, he's talking about singed registers.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #42

P: n/a
CBFalconer wrote:
Case wrote:
Eric Sosman wrote:


... snip ...
Note that you must issue the occasional no-op when
using instructions of the first type, to give the singed
registers time to cool.


You are talking about signed registers. I was talking about the

No, he's talking about singed registers.


Sure. Would you care to tell me what singed registers are?
(It takes pecial effort to deliberately type ng.)

Case

Nov 14 '05 #43

P: n/a
Case wrote:
CBFalconer wrote:
Case wrote:
Eric Sosman wrote:


... snip ...
Note that you must issue the occasional no-op when
using instructions of the first type, to give the singed
registers time to cool.

You are talking about signed registers. I was talking about the


No, he's talking about singed registers.


Sure. Would you care to tell me what singed registers are?
(It takes pecial effort to deliberately type ng.)


I expect they are registers that have been exposed to sufficient
heat to singe them. For a definitive answer you will probably
have to ask whomever Eric Sosman was originally responding to.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #44

P: n/a
In article <40**********************@dreader2.news.tiscali.nl > Case - <no@no.no> writes:
Dan Pop wrote:

Nope, in C int is a synonym for signed int:


I was writing English, not C.


"int" is not a word in English.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Nov 14 '05 #45

P: n/a
Case - <no@no.no> wrote:
Dan Pop wrote:
In <40**********************@dreader2.news.tiscali.nl > Case - <no@no.no> writes:
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:
>The key idea is to map all parts of a CPU on C structures
>and routines. For example: the program counter (PC) can
>be simply mapped to an int variable.

An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.

I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)


Nope, in C int is a synonym for signed int:


I was writing English, not C.


"int" is not a word in English. It is a technical term in C, and
therefore can only be interpreted, on comp.lang.c, as the C int.

Richard
Nov 14 '05 #46

P: n/a
Case <no@no.no> wrote:
CBFalconer wrote:
No, he's talking about singed registers.


Sure. Would you care to tell me what singed registers are?
(It takes pecial effort to deliberately type ng.)


It didn't seem to be a problem for you in
<40**********************@dreader2.news.tiscali.nl >...

Richard
Nov 14 '05 #47

P: n/a
CBFalconer wrote:
Case wrote:
CBFalconer wrote:
Case wrote:
Eric Sosman wrote:
... snip ...
> Note that you must issue the occasional no-op when
>using instructions of the first type, to give the singed
>registers time to cool.

You are talking about signed registers. I was talking about the

No, he's talking about singed registers.


Sure. Would you care to tell me what singed registers are?
(It takes pecial effort to deliberately type ng.)


I expect they are registers that have been exposed to sufficient
heat to singe them. For a definitive answer you will probably
have to ask whomever Eric Sosman was originally responding to.


He told me it was just a typo. And that he was wondering if this
was all, or that there might be something to learn from the well
repected Eric Sosman. But I geuss that's not the case for Case
in this case.

Case

Nov 14 '05 #48

P: n/a
Richard Bos wrote:
Case <no@no.no> wrote:
CBFalconer wrote:
No, he's talking about singed registers.


Sure. Would you care to tell me what singed registers are?
(It takes pecial effort to deliberately type ng.)


It didn't seem to be a problem for you in
<40**********************@dreader2.news.tiscali.nl >...


Does not compute, because initially it was not deliberate. :-)

Case

Nov 14 '05 #49

P: n/a
In <40**********************@dreader2.news.tiscali.nl > Case - <no@no.no> writes:
Dan Pop wrote:
In <40**********************@dreader2.news.tiscali.nl > Case - <no@no.no> writes:
Dan Pop wrote:
In <40***********************@news.xs4all.nl> Case <no@no.no> writes:
>The key idea is to map all parts of a CPU on C structures
>and routines. For example: the program counter (PC) can
>be simply mapped to an int variable.

An usigned integer type would be a much better choice for the program
counter. Ditto for the other integer registers.

I didn't say what kind of int, so technically what you propose
is covered by my statement ;-)


Nope, in C int is a synonym for signed int:


I was writing English, not C.


Main Entry: int
Function: abbreviation
intelligence, intercept, interest, interim, interior, interjection,
intermediate, internal, international, interpreter, intersection,
interval, interview, intransitive

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #50

61 Replies

This discussion thread is closed

Replies have been disabled for this discussion.