10

In C, how do I write to a particular memory location e.g. video memory b800, in DOS (real DOS, MS DOS 6.22)

I understand that C doesn't have anything built in to do that, but that there may be some platform specific e.g. DOS specific API functions that can.

A small demo program that does it would be great.

I have Turbo C (TCC.EXE - not tiny c compiler, Turbo C compiler)

I know debug can do it (e.g. some of the tiny bit of debug that I know) -f b800:0 FA0 21 CE (that writes some exclamation marks to the command line). But i'd like a C program to write to b800:0

barlop
  • 12,887
  • 8
  • 80
  • 109
  • 4
    could those voting to close, state a reason? – barlop Oct 06 '15 at 14:25
  • @dawg **DOS** means segmentation – fjardon Oct 06 '15 at 14:31
  • 7
    So cool to write into `B800:0000h` in 2015! – Stas Oct 06 '15 at 14:38
  • 3
    I think that text interface of DOS applications was more useful than many of today's GUI applications. Everything is "keyboard-optimized", everything is precisely located at exact char position and look the same on any monitor. However, using big memory objects with 16-bit segments is hell :) – i486 Oct 06 '15 at 14:51
  • 3
    @Stas for more coolness see what this guy does with qbasic in 2015: https://www.youtube.com/watch?v=HQYsFshbkYw – fjardon Oct 06 '15 at 14:52

3 Answers3

14

The address b800:0000 uses a segment of 0xb800 and an offset of 0x0000. This corresponds to the linear address 0xb8000 (note the extra 0, as the segment is shifted left by 4 bits).

To create a pointer to this address in protected mode, you'd use

char *p = (char *)0xb8000;

However, you are most likely in real mode, so you need to construct a far pointer:

char far *p = (char far *)0xb8000000;

The 32 bit value is split in two 16 bit values, which are assigned to segment and offset.

You can use this pointer normally, then:

*p = '!';
Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • 2
    To be certain to actually *see* something, it is better to set the character attribute. – fjardon Oct 06 '15 at 14:41
  • 2
    @fjardon is right. You may want to add an example for a "string write with color" function. The OP may be unaware of the interleaving of character and attribute data. – Jongware Oct 06 '15 at 15:01
  • I am sure I had this working in Windows 7 command prompt. codeblocks IDE launches a command console to run programs. But now I try it, I get these errors http://i.imgur.com/7jtfbca.png gcc gives the same errors. http://pastebin.com/raw.php?i=AtscYUJW Certainly win7 32bit had debug.exe which let you` -f b800:0 FA0 21 CE` So I can't see why it doesn't compile in Win7? i'm sure it did – barlop Oct 19 '15 at 03:39
  • And if it's the far that shouldn't be used within windows.. I tried this line `char *p = (char *)0xb8000; *p='!';` but the EXE crashed – barlop Oct 19 '15 at 03:48
  • It will only work on 32 bit Win7, because 64 bit does not have 16 bit emulation anymore. Also, the EXE needs to be compiled for DOS, so the emulation layer is set up. – Simon Richter Oct 19 '15 at 15:49
  • @Jongware can say *p=0x21; *(p+1)=0xCE I am aware of char with color, I mentioned 21 CE in my q. – barlop Oct 21 '15 at 00:12
  • Is it really impossible to write to that cmd video memory area of memory in 64bit OS? Why? Do you really need emulation to write to memory? surely cmd doesn't work completely different on 64bit than on 32bit.. so then it should sitll have some memory that if written to will appear in the cmd window – barlop Oct 21 '15 at 00:15
  • 3
    No, the emulation is required because Windows does not give your program direct hardware access. If writing to the character buffer works on Windows, it is because the emulation layer catches the access and interprets your intention, then uses the accelerated graphics driver to render the character to an off-screen bitmap, which is then copied on-screen after the next vertical refresh. If you really want direct hardware access, you need to boot DOS. – Simon Richter Oct 21 '15 at 13:04
  • cmd.exe never writes to video memory -- it gives the string to the console host (conhost.exe) that renders to bitmaps. – Simon Richter Oct 21 '15 at 13:05
  • if, besides DOS, this works in win7 32bit(but not 64bit), can you add that to your answer? thanks – barlop Mar 01 '20 at 21:28
5

Can you try this (untested as I don't have my old PC)

char far* video = 0xb8000000L;
*(video++) = '!';
*(video++) = 0x0A;
fjardon
  • 7,921
  • 22
  • 31
4

Just create a pointer to the base address and then access the memory like it's an array. Recall that in text mode, there are two bytes for each character shown on screen. The first, holds the character itself. The second holds the attribute. The high-order 4 bits are the background attribute and the low 4 are the foreground. Setting the highest bit in the foreground attribute makes it a high-intensity colour, while setting the high order bit in the background attribute causes the foreground to flash. This means that there are 8 colours available for the background, 16 available for the foreground and finally the ability to make the text blink.

E.g for mode 0x13 stuff: char far *graphScreen = (char far*) 0xA0000000;

And for text mode stuff, char far *textScreen = (char far*) 0xB8000000;

To write to screen memory is then as simple as textScreen[ someIndex ] = someChar; textScreen[ someIndex+1 ] = someAttrib;

enhzflep
  • 12,927
  • 2
  • 32
  • 51