F3U@PSUVMB.BITNET (11/04/87)
I am looking for some functions when called from a C program, will: 1) read (peek) memory directly when supplied with an address. Returns with the value at specified address. and 2) write (poke) memory directly when supplied with an address and a byte value. I am using Microsoft C 4.0 on an AT&T 6300 PLUS. Routines in C or Assembler OK. Thanks in advance. Frank F3U@PSUVMB.BITNET
kwok@iris.ucdavis.edu (Conrad Kwok) (11/07/87)
When you are using C, you don't need any special routine to read memory. All you need to do is to declare a pointer (near or far depending on the address) and then you may read or write to that location using normal assignment statements. Here is an example to read the value at location 0xC000:0x0100 char far *ptr; ptr = (char far *) 0xC0000100L; printf("Value at 0xC000:0x0100 is %d\n", *ptr); The above above should also works for Turbo C. -- Conrad internet: kwok@iris.ucdavis.edu csnet: kwok@ucd.csnet csnet: kwok%iris.ucdavis.edu@csnet.relay uucp: {seismo, uunet, lll-lcc, ...}!ucdavis!iris!kwok
platt@emory.uucp (Dan Platt) (11/08/87)
In article <24261F3U@PSUVMB> F3U@PSUVMB.BITNET writes: >I am looking for some functions when called from a C program, will: > 1) read (peek) memory directly when supplied with > an address. Returns with the value at specified address. > and > 2) write (poke) memory directly when supplied with an > address and a byte value. > >I am using Microsoft C 4.0 on an AT&T 6300 PLUS. Routines >in C or Assembler OK. The way I did it was to define a routine that loads a pointer with a value pointed to by a segment/offset... __________________________________________________________________ far char * mem_pt(seg,offst) /* this may be coerced */ short seg,offst; { union { struct { short: ofst,sg; /* these may be backwards */ } vals; far char * ptr; } pointr; pointr.vals.sg= seg; pointr.vals.ofst=offst; return(pointr.ptr); } ____________________________________________________________________ This was off the top of my head, and may be a little off on syntax, but not by much. Hope this is a help. Dan
luis@grinch.UUCP (luis) (11/08/87)
In article <447@ucdavis.ucdavis.edu> kwok@iris.UUCP (Conrad Kwok) writes: >When you are using C, you don't need any special routine to read >memory. All you need to do is to declare a pointer (near or far >depending on the address) and then you may read or write to that >location using normal assignment statements. Here is an example to >read the value at location 0xC000:0x0100 > > char far *ptr; > > ptr = (char far *) 0xC0000100L; > printf("Value at 0xC000:0x0100 is %d\n", *ptr); > >[...] Thank you for posting the example, but I have a few questions... 1. Why is there an 'L' at the end of the address? (does it stand for Long?) 2. I have been trying to access the DTR on my modem, but I don't know what the base address is. From the Technical Reference, I know that the offset is 3FE (bit 0), but can't find the base addres.. Can anyone help? ------------------------------------------------------------------------------- Luis Chanu "Live every day as if it were your last, UUCP: ...ihnp4!sun!aeras!grinch!luis because one day you will be right." UUCP: ...pyramid!wjvax!grinch!luis -Benny Hill Disk-Claimer: That's not your disk, that's my disk. -------------------------------------------------------------------------------
ljz@fxgrp.UUCP (Lloyd Zusman) (11/08/87)
In article <2312@emory.uucp> platt@emory.UUCP (Dan Platt) writes: >In article <24261F3U@PSUVMB> F3U@PSUVMB.BITNET writes: >>I am looking for some functions when called from a C program, will: >> 1) read (peek) memory directly when supplied with >> an address. Returns with the value at specified address. >> and >> 2) write (poke) memory directly when supplied with an >> address and a byte value. >> >>I am using Microsoft C 4.0 on an AT&T 6300 PLUS. Routines >>in C or Assembler OK. There already functions that do this dort of thing in Microsoft C version 4.0 ... void movedata(srcseg, srcoff, destseg, destoff, nbytes) unsigned int srcseg; unsigned int srcoff; unsigned int destseg; unsigned int destoff; unsigned int nbytes; This function copies 'nbytes' bytes of data from srcseg:srcoff to destseg:destoff. If you're in a small- or medium-model program, the 'destseg' parameter can be gotten via the segread() function (it will be the DS register value). But if your really MUST have something like peek and poke, here's a quickly-hacked (i.e., while I'm typing here right now) attempt at these. They're written to work in any memory model. There might be a bug or two, but this is the general idea ... unsigned char peek(segment, offset) unsigned int segment; unsigned int offset; { unsigned char result; unsigned long address = (unsigned long)((char far *)&result); movedata(segment, offset, address >> 16, address & 0x0000ffffL, 1); return (result); } void poke(segment, offset, byte) unsigned int segment; unsigned int offset; unsigned char byte; { unsigned long address = (unsigned long)((char far *)&byte); movedata(address >> 16, address & 0x0000ffffL, segment, offset, 1); } Shorter versions of these could be written ... unsigned char peek(segment, offset) unsigned int segment; unsigned int offset; { unsigned char result; movedata(segment, offset, (char far *)&result, 1); return (result); } void poke(segment, offset, byte) unsigned int segment; unsigned int offset; unsigned char byte; { movedata((char far *)&byte, segment, offset, 1); } However, these shorter versions violate strict typing conventions, as they make use of the fact that a "char far *" takes up the same space on the stack as two unsigned int's (on the PC). A syntax checker like 'lint' wouldn't like this code, nor would many strict-typing purists. I don't remember if the cast should be "char far *" or "char * far", so if this doesn't work, try it the other way. -- Lloyd Zusman, Master Byte Software, Los Gatos, California "We take things well in hand." ...!ames!fxgrp!ljz
flaps@utcsri.UUCP (11/10/87)
In article <447@ucdavis.ucdavis.edu> kwok@iris.UUCP (Conrad Kwok) writes: > char far *ptr; > > ptr = (char far *) 0xC0000100L; > printf("Value at 0xC000:0x0100 is %d\n", *ptr); bad style. avoid temporaries; the reader can't determine (easily) for how long the variable is used. restricting values to an expression, by not storing them in variables, is modular in the same way that restricting values to a function by storing them in local variables is. use instead: printf("contents of C000:0100 is %d\n",*(char far *)0xc0000100L); ajr
gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/10/87)
Use these sparingly! #define PEEK(loc) (*(char *)(loc)) #define POKE(loc,value) *(char *)(loc) = (value) To access a wide datum than a byte, change "char" to "short" or "long".
ljz@fxgrp.UUCP (Lloyd Zusman) (11/11/87)
In article <6662@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >#define PEEK(loc) (*(char *)(loc)) >#define POKE(loc,value) *(char *)(loc) = (value) This would only work if you are using a large data model and the 'loc' variable is of the type long (or some other 32-bit thing). If you're using Microsoft C version 4.0 (which I believe you are if I don't have you mixed up with another contributor here), use the movedata() function, which I described in a recent posting. It'll work in all memory models. -- Lloyd Zusman, Master Byte Software, Los Gatos, California "We take things well in hand." ...!ames!fxgrp!ljz
Leisner.Henr@Xerox.COM (marty) (11/11/87)
Doug, I think your peek and poke macros will cause problems on PCs due to the segmented nature of the beast. With the compiler I use (Aztec) and a large data model, in order to peek at (say) 0xf0000 absolute, the address becomes 0xf0000000 with a double word. I don't think any C compiler (at least known I know off) does the conversion from absolute addressing to segment/offset on the fly. I know Aztec provides several subroutines to do this. marty ARPA: leisner.henr@xerox.com GV: leisner.henr NS: martin leisner:henr801c:xerox UUCP: martyl@rocksvax.uucp
michael@orcisi.UUCP (11/11/87)
> union { > struct { > short: ofst,sg; /* these may be backwards */ > } vals; > far char * ptr; > } pointr; > > pointr.vals.sg= seg; > pointr.vals.ofst=offst; The MSC FP_OFF and FP_SEG macros supplied in one of the standard header files might be used here instead. Their are valid as both rvalues and lvalues.
rab@mimsy.UUCP (Bob Bruce) (11/12/87)
Followup-To: In article <261@grinch.grinch.UUCP> luis@grinch.UUCP (Luis Chanu) writes: >In article <447@ucdavis.ucdavis.edu> kwok@iris.UUCP (Conrad Kwok) writes: >> ... >> ptr = (char far *) 0xC0000100L; > > 1. Why is there an 'L' at the end of the address? (does it stand for Long?) Yes, it stands for long. Many compilers have 32 bit pointers and 16 bit int's. Appending an `L' to a constant is equivalent to casting it to a long. In an assignment, such as this, the `L' is not necessary, but it does emphasize that the constant is bigger than an int. > 2. I have been trying to access the DTR on my modem, but I don't know > what the base address is. From the Technical Reference, I know that > the offset is 3FE (bit 0), but can't find the base address. Can anyone > help? Sorry, but the 3FE is a port address, not a memory location. Check your compiler manual. It should provide some library routines for accessing I/O ports. Usually something like `outp()' and `inp()'. If these are not provided then you are going to have to write some assembly language routines.
moran@yale.UUCP (11/12/87)
From personal experience, when doing things like getting at ports (i.e. doing modem control stuff), it's better to use assembly language, and interrupts than to try to munge it out in C. William L. Moran Jr. moran@{yale.arpa, cs.yale.edu, yalecs.bitnet} ...{ihnp4!hsi,decvax}!yale!moran "The treatment lasts one second, but the effects last your lifetime." "Have you ever had a Pan-Galactic gargleblaster?" "This is worse!" "Freeowww!!" -Hitch Hiker's Guide Radio Series
chris@mimsy.UUCP (Chris Torek) (11/12/87)
In article <151@fxgrp.UUCP> ljz@fxgrp.UUCP (Lloyd Zusman) writes: [example `peek' and `poke' routines using `movedata' deleted] >Shorter versions of these could be written ... [shorter examples deleted] >However, these shorter versions violate strict typing conventions, as >they make use of the fact that a "char far *" takes up the same space >on the stack as two unsigned int's (on the PC). A syntax checker like >'lint' wouldn't like this code, nor would many strict-typing purists. `peek' and `poke' are already utterly machine dependent, hence it does not matter how machine-dependently you code them. Were I to use an IBM PC, I might write something like this: #define peek(addr) (*(unsigned char far *)(addr)) #define poke(addr, value) (*(char far *)(addr) = (value)) If I had to construct addresses from segment+offset, I might use some variation on this: #define buildaddr(seg, off) (((long)(seg) << 16) + (off)) /* I thought segments were << 4 ...? */ Using `movedata' to copy one byte from one location is overkill. Now then, as to style and machine-dependency: the routines that actually *use* peek and poke should be hidden away inside other routines that do whatever is really desired. Someone mentioned controlling DTR on an on-board modem: #define DTRADDR ((char far *)0x12345678) /* note that the L suffix is not strictly necessary */ /* the value above is certain to be wrong */ #define DTR_BIT 0x20 /* also likely wrong */ /* * Turn DTR on (if onoff!=0) or off (if onoff==0). */ set_dtr(onoff) int onoff; { if (onoff) *DTRADDR |= DTR_BIT; else *DTRADDR &= ~DTR_BIT; } => Hide machine dependent operations inside machine-independent routines. <= -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
mac3n@babbage.acc.virginia.edu (Alex Colvin) (11/13/87)
> #define PEEK(loc) (*(char *)(loc)) > #define POKE(loc,value) *(char *)(loc) = (value) > > To access a wide datum than a byte, change "char" to "short" or "long". These will work in SOME program models with SOME compilers. In the small model, a (char *) can only point within the data segment. What's probably wanted here is a pointer that can reach anywhere in memory. Because this issue isn't well defined by PDP-11 C, most PC compilers have their own way of doing this. In CII's C86 there is the movblock routine, whose arguments are offsets and segments. In uSoft C you can declare (char far*) pointers, which can point outside your data segment. Casting (loc) to a pointer is unreliable. The meaning of a such a cast is not well-defined. If loc is a 16-bit int or short, this won't get you beyond the data segment, but is probably reliable for references (offsets) within it. If loc is a 32-bit int or long (depends on your compiler), it can hold a full address. Now the question is, what's an address? Some compilers view such a cast as a simple trick on the type system, in which case (loc) should consist of a segment in the most significant 16 bits and an offset in the least significant 16 (the actual format of a far pointer). Other compilers try to make casts into conversions, and assume (loc) is a 32-bit offset from the beginning of memory, in which case (loc) has the segment number * 16 + the offset, in 32 bits. Best to find out what your compiler manual tells you. Then decorate the code with warnings and #ifdefs been burned before... mac@cs.virginia.edu
tainter@ihlpg.ATT.COM (Tainter) (11/13/87)
In article <5640@utcsri.UUCP>, flaps@utcsri.UUCP writes: > bad style. avoid temporaries; the reader can't determine (easily) for [ deletions ] > use instead: > printf("contents of C000:0100 is %d\n",*(char far *)0xc0000100L); > ajr OR, if that is too cryptic for your tastes use: function() { otherstuff; { /* restrict the scope of ptr */ char far *ptr; ptr = (char far *) 0xC0000100L; printf("Value at 0xC000:0x0100 is %d\n", *ptr); } morestuff; } --j.a.tainter
greg@gryphon.CTS.COM (Greg Laskin) (11/14/87)
>In article <24261F3U@PSUVMB> F3U@PSUVMB.BITNET writes: >>I am looking for some functions when called from a C program, will: >> 1) read (peek) memory directly when supplied with >> an address. Returns with the value at specified address. >> and >> 2) write (poke) memory directly when supplied with an >> address and a byte value. >> >>I am using Microsoft C 4.0 on an AT&T 6300 PLUS. Routines >>in C or Assembler OK. In Mircrosoft C: foo() { char huge *blat =0; char far *p; char c; int i; /* assume n is the ABSOLUTE address of an object in physical memory -- linear space, not segmented */ long n = 0x0c0000; c = blat[n]; i = ((int huge *)blat)[n]; /* huge pointers are EXPENSIVE so if you're going to do lots of stuff in a 64K segement, like video stuff, resolve the address into a far pointer and use it instead thusly */ p = &blat[0xb8000]; } Note: #ifndef M_LGDATA #define huge #define far #endif to remove the processor dependency of the code. (Yes. I know about the non-portability of the hard addressing) -- Greg Laskin "When everybody's talking and nobody's listening, how can we decide?" INTERNET: Greg.Laskin@gryphon.CTS.COM UUCP: {hplabs!hp-sdd, sdcsvax, ihnp4}!crash!gryphon!greg UUCP: {philabs, scgvaxd}!cadovax!gryphon!greg
Leisner.Henr@Xerox.COM (marty) (11/14/87)
I'm kinda getting tired of the peek and poke discussion on pee-cee. I think one of the problems with finding clean C semantics to implement peek and poke is: we're peeking and poking outside of our processes address space. Peek and poke are not thinks which should be done unless the program has a very good reason to do it. If possible, find a more standard mechanism (like a Bios interrupt which returns the requested information). If you run on a machine with memory protection, this discussion becomes moot. If you try to access memory you don't have, you get kicked out of the system. marty ARPA: leisner.henr@xerox.com GV: leisner.henr NS: martin leisner:henr801c:xerox UUCP: martyl@rocksvax.uucp
new@udel.EDU (Darren New) (11/15/87)
I think the original poster mentioned something about reading the telecom status registers somewhere in the 0x300's. Since the 8086 has the interrupt table there, and most of the other I/O goes through I/O ports, I would assume that the serial port is accessed through I/O instructions. Thus, this entire discussion is probably moot anyway.
gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/17/87)
In article <127@babbage.acc.virginia.edu> mac3n@babbage.acc.virginia.edu (Alex Colvin) writes: >> #define PEEK(loc) (*(char *)(loc)) >Some compilers view such a cast as a simple trick on the type system, ... >Other compilers try to make casts into conversions ... In C, a cast IS a conversion. However, you're right in remarking that some compilers have gotten this wrong. It is also true that conversion between a pointer and an integer of the proper size is implementation specific, although I would hope that an implementation that supports this at all would document the mapping. Portable applications will not resort to such tricks in the first place..