The Frazzled Programmer

Thursday, February 7, 2008

D Programming Tutorials: Inline Assembly

Inline Assembly

One of the really neat features of D is the ability to put assembly language directly inline with the rest of your code. For systems programmers, this could potentially save them a bit of time when optimizing their code. Below is a commented example of how inline assembly works in D:


// I based this sample off of a test case walter bright wrote. I added the 
// XOR operation and comments.
import std.stdio;
import std.string;
 
// use the version command to see if this is an x86 or x86/64 architecture
version(D_InlineAsm_X86)
{
version = runInineX86AssemblyTest;
}
else version(D_InlineAsm_X86_64)
{
version = runInineX86AssemblyTest;
}
else
{
static assert(0, "DSTRESS{XFAIL}: no inline x86 Assembly support");
}
 
// If x86 is the architecture, run the code in this block
version(runInineX86AssemblyTest)
{
ubyte b = 0xAA;
 
int main()
{
void* x = &b; // This is a pointer to b (an unsigned byte with the value 10101010)
void* y;  // This is a null void pointer
 
writeln("Addresses Before: x=" ~ toString(cast(long)x) ~ ", y=" ~ toString(cast(long)y));
writeln("Values Before: *x=" ~ toString(*cast(ubyte*)x) ~ ", *y=(null pointer exception)");
 
writeln(`
Using Assembly Language, XOR variable b (170) and value 0xFF (255).
10101010 xor 11111111 = 01010101 = 64 + 16 + 4 + 1 = 85
Then copy the address of b to the void pointer y.
`
);

static if(size_t.sizeof == 4) // 4 byte pointer (32 bit OS)
{
asm
{
mov EAX, offsetof b; // Move the address of b to the EAX register
xor [EAX], 255;   // Reverse the bits by doing an XOR on 0xFF.
mov y, EAX; // Copy the address in EAX to y
}
}
else static if(size_t.sizeof == 8) // 8 byte pointer (64 bit OS)
{
asm
{
mov RAX, offsetof b; // Move the address of b to the RAX register
xor [RAX], 255;   // Reverse the bits by doing an XOR on 0xFF.
mov y, RAX; // Copy the address in RAX to y
}
}
else
{
pragma(msg, "DSTRESS{ERROR}: unsupported pointer size");
static assert(0);
}
 
if(x != y)
{
assert(0);
}

writeln("Addresses After: x=" ~ toString(cast(long)x) ~ ", y=" ~ toString(cast(long)y));
writeln("Values After: *x=" ~ toString(*cast(ubyte*)x) ~ ", *y=" ~ toString(*cast(ubyte*)y));
 
getc(stdin);
return 0;
}
}

And here is the programs output:


Addresses Before:  x=4296832, y=0
Values Before:    *x=170, *y=(null pointer exception)

Using Assembly Language, XOR variable b (170) and value 0xFF (255). 
10101010  xor 11111111 = 01010101 = 64 + 16 + 4 + 1 = 85
Then copy the address of b to the void pointer y.

Addresses After:   x=4296832, y=4296832
Values After:     *x=85, *y=85

Tuesday, February 5, 2008

D To HTML Converter

I've just completed a D to HTML converter (written in D) as an educational exercise. It's an executable (run from the command line) that will traverse your directory structure and convert all ".d" files into ".d.html" files. Along with the html files comes an "index.html" file to navigate through all of your code in a browser.


Downloads: (version 0.2)

DToHtml.zip - Executable Only
DToHtmlWithSrc.zip - Executable and Source

Instructions:

  1. Place the d2html.exe file in the base directory that contains your D code.
  2. Run d2html.exe
  3. Open up the index.html file that is created in the same directory as the d2html executable.


Command Line Options:

----------------------------------------------------------------

Command line usage:

----------------------------------------------------------------



File or Recursive convertion Modes:

-file <filename>

-dir <directory> (default - current directory)



D Code or Program Output Modes:

-code (default - d code formatting)

-outfile (raw console program output)



Replacement Options: (Escape sequeces \r, \n, and \t work here)

-space <space string> (default "&nbsp;")

-tab <tab string> (default "&#009;")

-newline <newline string> (default "<br>")



Other Options:

-copyto <directory> (copy html files to target directory)

-? (console help - duh)



----------------------------------------------------------------

Examples:

----------------------------------------------------------------



REM This recusively converts all d programs to html in the current directory

d2html.exe



REM This recusively converts all d programs to html in the passed in directory

d2html.exe -dir "c:\pub\src\dprojects"



REM This converts the passed in file to html

d2html.exe -file "c:\pub\src\dprojects\sampleprogram.d"



REM This converts the passed in program output file to html

d2html.exe -outfile -file "c:\pub\src\dprojects\sampleprogram.output"



REM This recusively converts all d programs to html in the current directory, using the following character replacements for space, tab, and return chars.

d2html.exe -code -space " " -tab " " -newline "\r\n<br>"



REM This recusively converts all d programs to html in the passed in directory, then copies all of the html file tree to another directory

d2html.exe -dir "c:\pub\src\dprojects" -copyto "c:\pub\src\dprojects\HTML"



View Sample Code (Click here)


Friday, January 11, 2008

D Programming Tutorials: Primitive Types

Exploring Primitive Data Types

Follow the procedures in D Introduction Part 2 to setup a new project in Poseidon.

The things to note here are the properties on each type, such as:

[type].init - returns the initial value of the type when it is created.
[type].min/max - returns the minimum/maximum value for the type.
[type].stringof - returns the type's name in string form.
[type].alignof - returns the size boundary the type needs to be aligned on.
[var].sizeof - returns the size in bytes of the variable.
[var].ptr - returns a pointer to the variable.

Also, note how casting works:

cast([type]) [var]

And a neat feature is type inference:

auto [var] = [literal|var];

Paste the code below into a new D file in Poseidon and Rebuild All/Execute:


import std.stdio;
import std.string;
 
int main()
{
bool boolTest = bool.init; // boolean value (8 bits)

byte byteTest = byte.init; // signed 8 bits
auto ubyteTest = ubyte.init; // unsigned 8 bits

auto shortTest = short.init; // signed 16 bits
auto ushortTest = ushort.init; // unsigned 16 bits

int intTest = int.init; // signed 32 bits
uint uintTest = 4_294_967U; // unsigned 32 bits

auto longTest = long.init; // signed 64 bits
auto ulongTest = 0xFFFF_FFFF_FFFF_FFFFUL; // unsigned 64 bits
 
auto floatTest = float.init; // 32 bits
auto doubleTest = double.max; // 64 bits
real realTest = real.init; // 80 bits
 
// Imaginary Numbers
auto ifloatTest = ifloat.init;
auto idoubleTest = idouble.init;
auto irealTest = ireal.init;
 
// Complex Numbers
auto cfloatTest = cfloat.init;
auto cdoubleTest = cdouble.init;
auto crealTest = creal.init;
 
// Character data
auto charTest = char.init; // 8 bit UTF-8
auto wcharTest = wchar.init; // 16 bit UTF-16
auto dcharTest = dchar.init; // 32 bit UTF-32
 
// Properties of data types
writepair("short.init", toString(short.init));
writepair("short.max", toString(short.max));
writepair("short.min", toString(short.min));
writepair("short.stringof", short.stringof);
writepair("short.mangleof", short.mangleof);

writepair("shortTest.sizeof", toString(shortTest.sizeof));

writepair("shortTest.alignof", toString(shortTest.alignof));
writepair("shortTest.mangleof", shortTest.mangleof);
writepair("shortTest.stringof", shortTest.stringof);
writepair("typeof(shortTest).stringof", typeof(shortTest).stringof);
 

writepair("float.init", toString(float.init));
writepair("float.infinity", toString(float.infinity));
writepair("float.nan", toString(float.nan));
 
// number of decimal digits for var floatTest:
writepair("floatTest.dig", toString(floatTest.dig));
 
// smalles increment to the value 1 for var floatTest:
writepair("floatTest.epsilon", toString(floatTest.epsilon));
 
// number of mantissa bits for var floatTest
writepair("floatTest.mant_dig", toString(floatTest.mant_dig));

writepair("float.max_10_exp", toString(float.max_10_exp));
writepair("float.max_exp", toString(float.max_exp));
writepair("float.min_10_exp", toString(float.min_10_exp));
writepair("float.min_exp", toString(float.min_exp));
writepair("float.max", toString(float.max));
writepair("float.min", toString(float.min));
writepair("floatTest.re", toString(floatTest.re));
writepair("floatTest.im", toString(floatTest.im));

// Pointers/Addresses of stack types
writepair("shortTest", toString(shortTest));
writepair("cast(long)&shortTest", toString(cast(long)&shortTest));
 
short* shortTestPointer = &shortTest;
writepair("cast(long)shortTestPointer", toString(cast(long)shortTestPointer));
 
// Use of void pointer
writepair("doubleTest", toString(doubleTest));

void* voidStackPtr2dblTest = &doubleTest;
writepair("cast(long)voidStackPtr2dblTest", toString(cast(long)voidStackPtr2dblTest));
 
// cast the void pointer to a doulbe pointer, then get it's
// value (confusing, but appearantly useful at times)
writepair("*cast(double*)voidStackPtr2dblTest)", toString(*cast(double*)voidStackPtr2dblTest));

getc(stdin);

return 0;
}
 
void writepair(string a, string b) 
{
writefln( rjustify(a, 40) ~ " = " ~ ljustify(b, 20) );
}

And here is the programs output:


                              short.init = 0             
short.max = 32767
short.min = -32768
short.stringof = short
short.mangleof = s
shortTest.sizeof = 2
shortTest.alignof = 2
shortTest.mangleof = s
shortTest.stringof = shortTest
typeof(shortTest).stringof = short
float.init = nan
float.infinity = inf
float.nan = nan
floatTest.dig = 6
floatTest.epsilon = 1.19209e-07
floatTest.mant_dig = 24
float.max_10_exp = 38
float.max_exp = 128
float.min_10_exp = -37
float.min_exp = -125
float.max = 3.40282e+38
float.min = 1.17549e-38
floatTest.re = nan
floatTest.im = 0
shortTest = 0
cast(long)&shortTest = 1244872
cast(long)shortTestPointer = 1244872
doubleTest = 1.79769e+308
cast(long)voidStackPtr2dblTest = 1244880
*cast(double*)voidStackPtr2dblTest) = 1.79769e+308

Tuesday, January 8, 2008

D Programming Introduction: Part 2

[Part 1] [Part 2] [Part 3]

Build & Execute a New Project

Configure Posieden

  1. Open Poseiden.
  2. Go to the main menu and select: Tools - Options...
  3. Fill in the paths to the Compiler, Linker, and tools.
  4. Close the Options dialog.
Create a new Project

  1. Open Poseiden (if not already open)
  2. Go to the main menu and select: File - New Project
  3. Fill out the project properties (see the screenshot below).
  4. Go to the Include and Libs tab and add the Phobos library.
  5. Now, add a file by right clicking on the Sources tree item and add select New - File from the context menu.
  6. Now use the following source to the file "first.d":

import std.stdio;

int main()
{
writefln("Hello World!");
getc(stdin);

return 0;
}


Execute the Project

  1. Simply go to the main menu and select: Build - Build and Run.

Thursday, January 3, 2008

D Programming Introduction: Part 1

[Part 1] [Part 2] [Part 3]

Installation and Configuration

Required Files


Installation Steps


Installation Instructions from DigitalMars.

  1. Unzip dmd.zip into the root of your C drive.
  2. Unzip dmc.zip into the root of your C drive.
  3. Unzip ddbg-latest.zip into c:\dmd\bin\.
  4. Copy bud_win_3.04.exe to c:\dmd\bin\.
  5. Run the xn_resourceeditor_setup.exe installer.
  6. Set the Environment variable "LIB" equal to "\dmd\lib;\dm\lib". This can be done by right clickong on "My Computer", select "Properties" from the context menu, go to the "Advanced" tab, and finally click on the "Environment Variables" button
  7. Run the Poseidon Installer.
  8. Note: Tango will be installed after we learn to use Phobos (the standard D library).

Programming References


My Favorite Free/Open Source Tools

Here is a list of my favorite open source/freeware programs. It really is amazing how much you can do without spending a dime. I'll probably update this when I find new tools in the future.

Software Development Tools:
Text Editor: Notepad++
Source Control Client: Tortoise SVN/CVS
Install System: NSIS Installer
Code Generator: MyGeneration
IDE (MS.Net win32 dev): Visual C# Express
IDE (D Programming): Posieden
IDE (C++/D): Code::Blocks
IDE (C/C++): Dev-C++
Server Database (MS.Net): Sql Express & SSMS
File Database: SQLite
Server Database: PostgreSQL

Standard Applications/Utilities:
Password Management: KeePass & KeeForm
Personal Task Mangement: Task Coach
Email: Mozilla Thunderbird
Webmail POP Integration: FreePOPs
Web Browser: Firefox
Compression: 7-zip
Instant Messaging: Pidgin
Graphics (2-D Non Vector): Gimp 2
Screenshots: MWSnap
CD/DVD Burning: ImgBurn, CDBurnerXP & InfraRecorder
DVD Video Burner (from video files): DVDFlick
Backup DVD Movies: DVD Decrypter, DVD2one, DVDShrink [?]

My Favorite Software Emulators

I have a huge collection of emulators that I maintain and play with on a regular basis. Here is an alphabetical list of all of the emulators I use (they all run on the Windows platform).

1964 - Nintendo 64
80five - Nintendo NES
AdriPSX - Playstation
AppleWin - Apple IIe
Arculator - Acorn Archimedes
Atari++ - Atari 400, 800, 400XL, 800XL, 130XE, and 5200
B-EM - BBC Micro
BasicBoy - GameBoy
BGB - GameBoy
Bliss - Mattel Intellivision
BlueMSX - MSX
Bochs - IA-32
BoycottAdvance - Gameboy Advance
Bsnes - Nintendo SNES
Caprice32 - Amstrad CPC
CaSTaway - Atari ST
CCS64 - Commodore 64
CpcAlive - Amstrad CPC
CPCE - Amstrad CPC
CPS3 - Arcade (CPS3)
DCMOTO - Thomson MO5, MO5E, MO5NR, MO6, T9000, TO7, TO7/70, TO8, TO8D, TO9, TO9+ et Olivetti Prodest PC128
DeSmuME - Nintendo DS
Dolphin - Nintendo GameCube
DOSBox - DOS
DreamGBA - GameBoy Advance
DreamGBC - GameBoy Color
DSP - ZX Spectrum
Dualis - Nintendo DS
EightyOne - Sinclair ZX80/ZX81/ZX/16k/48k/128k/+2/+2a/+3, Timex TS1000/TS2068/TS2068/TC2048, Lambda 8300, Ringo R470, MicroDigital TK85, Jupiter ACE
Elkulator - Acorn Electron
ePSXe - Playstation
FakeNES - Nintendo NES
FCEUltra - Nintendo NES
Freedo - 3DO
FreezeSMS - Sega SMS, GameGear, SG1000, ColecoVision, Nintendo NES
Fusion - Sega SG1000, SC3000, SMS, GameGear, Genesis/Megadrive, SegaCD/MegaCD and 32X
GCube - Nintendo GameCube
Gemulator - Apple Macintosh, Atari ST, and Atari 8-bit
Gens32Surreal - Sega Genesis
Gens - Sega Genesis
GEST - GameBoy
Handy - Atari Lynx
Hox64 - Commodore 64
IDeaS - Nintendo DS
Jnes - Nintendo NES
kigb - GameBoy
Makaron - Sega Dreamcast
MAME - Arcade (Check the website)
ManiacNES - Nintendo NES
Mednafen - Atari Lynx, GameBoy, GameBoy Advance, NES, TurboGrafx 16, SuperGrafx, Neo Geo Pocket, PC-FX, and WonderSwan
Meka - Sega SG-1000, SC-3000, SF-7000, + FM Unit, SMS, GameGear, ColecoVision, Othello Multivision
MESS - LOTS!! (Check the website)
Mini-vMac - Macintosh
Model2Emulator - Arcade (Model2)
Mupen64 - Nintendo 64
Nebula - Arcade (CAPCOM CPS2 Boards)
NekoProjectII - PC-9801E
NeonDS - Nintendo DS
NeoPop - NeoGeo Pocket
NESten - Nintendo NES
NesterJ - Nintendo NES
NesticleWin - Nintendo NES
Nestopia - Nintendo NES
NeuSneM - Nintendo SNES
Nintendulator - Nintendo NES
No$CPC - Amstrad CPC
No$GBA - GameBoy Advance, Nintendo DS
No$MSX - MSX
Nostalgia - Mattel Intellivision
NullDC - Sega Dreamcast
O2EM - Odyssey
Olafnes - Nintendo NES
Ootake - TurboGrafx 16
OpenMSX - MSX
Osmose - Sega SMS, Sega GameGear
Oswan - Wonderswan
PCSX2 - Playstation 2
PlayGuy - GameBoy
Plus4emu - Commodore C16, C116, and Plus/4
Project64 - Nintendo 64
pSX - Playstation
Raine - NeoGeo Arcade
RascalBoy - GameBoy Advance
RedDragon - Nintendo Virtual Boy
RockNES - Nintendo NES
SainT - Atari ST
Satourne - Sega Saturn
ScummVM - Scumm (Lucas-Arts Virtual Machine)
SegaLi - Nintendo NES
SimCoupe - SAM Coupe
SMSPLUS - Sega SMS, GameGear
SNES9x - Nintendo SNES
SNESGT - Nintendo SNES
SoftMac - Macintosh
SSF - Sega Saturn
STEem - Atari ST
Stella - Atari 2600
TGBDual - GameBoy
VirtualColecoVision - ColecoVision
VirtualJaguar - Atari Jaguar
VirtuaNES - Nintendo NES
VisualBoyAdvance - GameBoy, GameBoy Advance
VitualE - Nintendo Virtual Boy
vMac - Macintosh
WinAPE - Amstrad CPC
WinKawaks - Arcade CPS2
WinUAE - Commodore Amiga
WinVICE - Commodore 64/128
XE - Many (Check the website)
Xebra - Playstation
Xformer - Atari 800
Yabause - Sega Saturn
Yape - Commodore C16-Plus/4
Z26 - Atari 2600
Zsnes - Nintendo SNES

About Me