Is fdisk divides address space for created partition? - linux

On my system, it has one mem node created already in /dev (/dev/pmem). then i use fdisk command for creating a partition
After creating partition I apply lsblk command and my result is
pmem1 259:4 0 15.8G 0 disk
└─pmem1p2 259:7 0 14.3G 0 part
After that, I write mmap code (Refer devmam library) just like
off_t address = 0x00;
int width = 10;
void *virtladdr, *phyaddr;
int a = 5;
int *lendata = &a;
int main(void)
{
int mode = 0x0777;
char *filename = "/dev/pmem0";
int fdout;
if ((fdout = open (filename, O_RDWR | O_CREAT | O_TRUNC, mode )) < 0)//edited here
{
printf ("can't create file");
return 0;
}
mapped_size = page_size = getpagesize();
offset_in_page = (uint64_t)address & (page_size - 1);
if (offset_in_page + (width * 8) > page_size) {
mapped_size *= 2;
}
printf("map size %ld\n", mapped_size);
phyaddr = mmap(0, mapped_size, (PROT_READ | PROT_WRITE), MAP_SHARED, fdout, address & ~(off_t)(page_size - 1));
1 = I write value 10 on 0x00 address for /dev/pmem1
2 = I write value 20 on 0x00 address for /dev/pmem1p2
Then after I Read mmap
off_t address = 0x00;
int width = 10;
int main(void)
{
int retVal = -1;
int fd;
unsigned long mapped_size, page_size, offset_in_page;
void *virtladdr, *phyaddr;
fd = open("/dev/pmem0", O_RDWR | O_SYNC);
if(fd < 0)
{
printf("file not open \n");
}
mapped_size = page_size = getpagesize();
offset_in_page = (uint64_t)address & (page_size - 1);
if (offset_in_page + (width * 8) > page_size) {
mapped_size *= 2;
}
/* Map one page */
phyaddr = mmap(0, mapped_size, PROT_READ,MAP_PRIVATE , fd, address & ~(off_t)(page_size - 1));
1 = Read 0x00 address from /dev/pmem1 My output is 10
2 = Read 0x00 address from /dev/pmem1p2 My output is 20
So what happened here why 0th address value is different? Is fdisk create two partitions which address starts from 0x00? Or I am in the wrong way?

Related

How does Linux truncate core dumps?

Core dump size can be restricted using limits (ulimit, rlimit, etc...).
What I'm wondering is how this is actually implemented - for instance: Is the core dump generation smart enough to prioritize the stack? Memory referenced by local variable pointers? Or is it literally the entire address space of the process, truncated at N bytes?
As I recently faced a core dump truncation in some process, I can share my experience on this. The Linux kernel reports a core dump in the context of the crashing process. In the Linux kernel source code, the transfer of the core dump from the kernel to user space area is done by several calls to dump_emit() in fs/coredump.c:
/*
* Core dumping helper functions. These are the only things you should
* do on a core-file: use only these functions to write out all the
* necessary info.
*/
int dump_emit(struct coredump_params *cprm, const void *addr, int nr)
{
struct file *file = cprm->file;
loff_t pos = file->f_pos;
ssize_t n;
if (cprm->written + nr > cprm->limit)
return 0;
while (nr) {
if (dump_interrupted())
return 0;
n = __kernel_write(file, addr, nr, &pos);
if (n <= 0)
return 0;
file->f_pos = pos;
cprm->written += n;
cprm->pos += n;
nr -= n;
}
return 1;
}
EXPORT_SYMBOL(dump_emit);
The above function checks two main things:
Is the current size of the core dump still under the configured limit for the process ?
if (cprm->written + nr > cprm->limit)
Is there a pending signal for the current process?
if (dump_interrupted())
If one of the above check fails, the core dump transfer from kernel to user space is interrupted and so, the resulting core file is truncated at any point. In a ELF configured kernel, the above service is for example called by elf_core_dump() from fs/binfmt_elf.c:
/*
* Actual dumper
*
* This is a two-pass process; first we find the offsets of the bits,
* and then they are actually written out. If we run out of core limit
* we just truncate.
*/
static int elf_core_dump(struct coredump_params *cprm)
{
int has_dumped = 0;
mm_segment_t fs;
int segs, i;
size_t vma_data_size = 0;
struct vm_area_struct *vma, *gate_vma;
struct elfhdr *elf = NULL;
loff_t offset = 0, dataoff;
struct elf_note_info info = { };
struct elf_phdr *phdr4note = NULL;
struct elf_shdr *shdr4extnum = NULL;
Elf_Half e_phnum;
elf_addr_t e_shoff;
elf_addr_t *vma_filesz = NULL;
/*
* We no longer stop all VM operations.
*
* This is because those proceses that could possibly change map_count
* or the mmap / vma pages are now blocked in do_exit on current
* finishing this core dump.
*
* Only ptrace can touch these memory addresses, but it doesn't change
* the map_count or the pages allocated. So no possibility of crashing
* exists while dumping the mm->vm_next areas to the core file.
*/
/* alloc memory for large data structures: too large to be on stack */
elf = kmalloc(sizeof(*elf), GFP_KERNEL);
if (!elf)
goto out;
/*
* The number of segs are recored into ELF header as 16bit value.
* Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
*/
segs = current->mm->map_count;
segs += elf_core_extra_phdrs();
gate_vma = get_gate_vma(current->mm);
if (gate_vma != NULL)
segs++;
/* for notes section */
segs++;
/* If segs > PN_XNUM(0xffff), then e_phnum overflows. To avoid
* this, kernel supports extended numbering. Have a look at
* include/linux/elf.h for further information. */
e_phnum = segs > PN_XNUM ? PN_XNUM : segs;
/*
* Collect all the non-memory information about the process for the
* notes. This also sets up the file header.
*/
if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs))
goto cleanup;
has_dumped = 1;
fs = get_fs();
set_fs(KERNEL_DS);
offset += sizeof(*elf); /* Elf header */
offset += segs * sizeof(struct elf_phdr); /* Program headers */
/* Write notes phdr entry */
{
size_t sz = get_note_info_size(&info);
sz += elf_coredump_extra_notes_size();
phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
if (!phdr4note)
goto end_coredump;
fill_elf_note_phdr(phdr4note, sz, offset);
offset += sz;
}
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
if (segs - 1 > ULONG_MAX / sizeof(*vma_filesz))
goto end_coredump;
vma_filesz = vmalloc((segs - 1) * sizeof(*vma_filesz));
if (!vma_filesz)
goto end_coredump;
for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
unsigned long dump_size;
dump_size = vma_dump_size(vma, cprm->mm_flags);
vma_filesz[i++] = dump_size;
vma_data_size += dump_size;
}
offset += vma_data_size;
offset += elf_core_extra_data_size();
e_shoff = offset;
if (e_phnum == PN_XNUM) {
shdr4extnum = kmalloc(sizeof(*shdr4extnum), GFP_KERNEL);
if (!shdr4extnum)
goto end_coredump;
fill_extnum_info(elf, shdr4extnum, e_shoff, segs);
}
offset = dataoff;
if (!dump_emit(cprm, elf, sizeof(*elf)))
goto end_coredump;
if (!dump_emit(cprm, phdr4note, sizeof(*phdr4note)))
goto end_coredump;
/* Write program headers for segments dump */
for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
struct elf_phdr phdr;
phdr.p_type = PT_LOAD;
phdr.p_offset = offset;
phdr.p_vaddr = vma->vm_start;
phdr.p_paddr = 0;
phdr.p_filesz = vma_filesz[i++];
phdr.p_memsz = vma->vm_end - vma->vm_start;
offset += phdr.p_filesz;
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
if (vma->vm_flags & VM_WRITE)
phdr.p_flags |= PF_W;
if (vma->vm_flags & VM_EXEC)
phdr.p_flags |= PF_X;
phdr.p_align = ELF_EXEC_PAGESIZE;
if (!dump_emit(cprm, &phdr, sizeof(phdr)))
goto end_coredump;
}
if (!elf_core_write_extra_phdrs(cprm, offset))
goto end_coredump;
/* write out the notes section */
if (!write_note_info(&info, cprm))
goto end_coredump;
if (elf_coredump_extra_notes_write(cprm))
goto end_coredump;
/* Align to page */
if (!dump_skip(cprm, dataoff - cprm->pos))
goto end_coredump;
for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
unsigned long addr;
unsigned long end;
end = vma->vm_start + vma_filesz[i++];
for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
struct page *page;
int stop;
page = get_dump_page(addr);
if (page) {
void *kaddr = kmap(page);
stop = !dump_emit(cprm, kaddr, PAGE_SIZE);
kunmap(page);
put_page(page);
} else
stop = !dump_skip(cprm, PAGE_SIZE);
if (stop)
goto end_coredump;
}
}
dump_truncate(cprm);
if (!elf_core_write_extra_data(cprm))
goto end_coredump;
if (e_phnum == PN_XNUM) {
if (!dump_emit(cprm, shdr4extnum, sizeof(*shdr4extnum)))
goto end_coredump;
}
end_coredump:
set_fs(fs);
cleanup:
free_note_info(&info);
kfree(shdr4extnum);
vfree(vma_filesz);
kfree(phdr4note);
kfree(elf);
out:
return has_dumped;
}

I2C communication using MSP432G2553 and HMC5883L

I am trying to interface my HMC5883L magnetometer with my MSP432G2553 to get continuous readings on x,y and z axis to provide orientation for a device.
I am having problem getting data using the i2c communication. I am trying to get the x,y and z data but I am not getting anything from my code. I would appreciate any feedback, I am new to the I2C communication.
I found a code online and have been using it and modifying it. Here is the code:
main code:
#include <msp430g2553.h>
#include "my_types.h"
#include "i2c.h"
#define M_PI 3.14159265358979323846264338327950288
int TXByteCtr;
unsigned char PRxData;
int Rx = 0;
char WHO_AM_I = 0x1E;
char itgAddress = 0x69;
const uchar setup_hmc5883[] = {0x00, 0x70};
const uchar gain_hmc5883[] = {0x01, 0xA0};
const uchar continuous_hmc5883[] = {0x02, 0x00};
const uchar base_hmc5883[] = {0x03};
char readBuffer [6];
void init_I2C(void);
void Transmit(void);
void Receive(void);
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
int x, y, z ;
float heading ;
float headingDegrees ;
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
BCSCTL1 = CALBC1_16MHZ ;
DCOCTL = CALDCO_16MHZ ;
init_I2C();
Rx = 0;
TXByteCtr = 1;
writei2c(0x3C,setup_hmc5883,2);
TXByteCtr = 1;
writei2c(0x3C,gain_hmc5883,2);
TXByteCtr = 1;
writei2c(0x3C,continuous_hmc5883,2);
while(1){
writei2c(0x3C, base_hmc5883, 1);
__delay_cycles(100000);
readi2c(0X3D, readBuffer, 6);
x = readBuffer[0] ;
x |= readBuffer[1] << 8 ;
z = readBuffer[2] ;
z |= readBuffer[3] << 8 ;
y = readBuffer[4] ;
y |= readBuffer[5] << 8 ;
heading = atan2(y, x);
if(heading < 0) heading += 2*M_PI;
headingDegrees = heading * 180/M_PI;
}
}
//-------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move received data from the I2C slave
// to the MSP430 memory. It is structured such that it can be used to receive
//-------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
if(Rx == 1){ // Master Recieve?
PRxData = UCB0RXBUF; // Get RX data
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
else{ // Master Transmit
if (TXByteCtr) // Check TX byte counter
{
if ((IFG2 & UCB0TXIFG) || (IFG2 & UCB0RXIFG))
i2cDataInterruptService();
TXByteCtr--; // Decrement TX byte counter
if(!TXByteCtr)
{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
}
}
void init_I2C(void) {
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = itgAddress; // Slave Address is 069h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0RXIE + UCB0TXIE; //Enable RX and TX interrupt
}
i2c.c:
#include "i2c.h"
volatile char i2cBusy = 0;
volatile unsigned char i2cBufferLength = 0 ;
unsigned char * i2cBufferPtr ;
volatile char txDone = 1 ;
volatile char rxDone = 1 ;
void initi2c(unsigned int divider){
P1SEL |= BIT6 + BIT7 ;
P1SEL2 |= BIT6 + BIT7 ;
UCB0CTL1 |= UCSWRST ;
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC ;
UCB0CTL1 = UCSSEL_2 + UCSWRST ;
UCB0BR0 = divider & 0x00FF ;
UCB0BR1 = ((divider & 0xFF00) >> 8) ;
UCB0I2CSA = 0x069 ;
UCB0I2CIE = UCNACKIE | UCALIE;
UCB0CTL1 &= ~UCSWRST ;
IE2 |= UCB0TXIE | UCB0RXIE ;
}
char writei2c(unsigned char addr, unsigned char * data, unsigned char nbData){
UCB0I2CSA = addr ;
i2cBusy = 0 ;
i2cBufferPtr = data ;
i2cBufferLength = nbData ;
txDone = 0 ;
UCB0CTL1 |= UCTR + UCTXSTT;
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
//while(txDone == 0) ;
//return txDone ;
}
char readi2c(unsigned char addr, unsigned char * data, unsigned char nbData){
UCB0I2CSA = addr ;
i2cBusy = 0 ;
i2cBufferPtr = data ;
i2cBufferLength = nbData ;
rxDone = 0 ;
UCB0CTL1 &= ~UCTR;
UCB0CTL1 |= UCTXSTT;
while(UCB0CTL1 & UCTXSTT);
UCB0CTL1 |= UCTXSTP ;
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
while(rxDone == 0) ;
return rxDone ;
}
inline void i2cDataInterruptService(void){
if ((IFG2 & UCB0TXIFG) != 0 || (IFG2 & UCB0RXIFG) != 0){
if((UCB0CTL1 & UCTR) != 0){
if(i2cBusy >= i2cBufferLength){
UCB0CTL1 |= UCTXSTP ;
i2cBusy = 0 ;
txDone = 1 ;
IFG2 &= ~UCB0TXIFG;
}else{
UCB0TXBUF = i2cBufferPtr[i2cBusy] ;
i2cBusy ++ ;
}
}else{
if((i2cBufferLength - i2cBusy) == 1){ // may generate a repeated stop condition
UCB0CTL1 |= UCTXSTP ;
}
i2cBufferPtr[i2cBusy] = UCB0RXBUF;
i2cBusy ++ ;
if(i2cBusy >= i2cBufferLength){
i2cBusy = 0 ;
rxDone = 1 ;
}
}
}
}
inline void i2cErrorInterruptService(void){
if ((UCB0STAT & UCNACKIFG) != 0) {
UCB0CTL1 |= UCTXSTP;
UCB0STAT &= ~UCNACKIFG;
i2cBusy = -1;
txDone = -1 ;
rxDone = -1 ;
}else if ((UCB0STAT & UCALIE) != 0) {
UCB0CTL1 |= UCTXSTP;
UCB0STAT &= ~UCALIE;
i2cBusy = -1;
txDone = -1 ;
rxDone = -1 ;
}
}

Linux-0.11, the code of the function of file_write is error in the File_dev.c

int file_write(struct m_inode * inode, struct file * filp, char * buf, int count){
off_t pos;
int block,c;
struct buffer_head * bh;
char * p;
int i=0;
.......
if (!(filp->f_flags & O_APPEND)) {
filp->f_pos = pos;
inode->i_ctime = CURRENT_TIME;
}
}
I think:
int file_write(struct m_inode * inode, struct file * filp, char * buf, int count){
off_t pos, tmp;
int block,c;
struct buffer_head * bh;
char * p;
int i=0;
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
pos = filp->f_pos;
tmp = pos;
.......
if (!(filp->f_flags & O_APPEND)) {
filp->f_pos = tmp;
inode->i_ctime = CURRENT_TIME;
}
}
otherwise int the file_read filp->pos is error.
please Verify my ideas!
Thank you!
As far as I understand, if opened as O_APPEND, file_write always writes to the end of the file (so at offset i_size) and updates i_size. And if not opened as O_APPEND, file_write writes to wherever f_pos is, and updates f_pos.
I think you expect file_write when not opened as O_APPEND to keep f_pos constant, which is not how it works I think.

DirectX 11 changing the pixel bytes

Followed this guide here
I am tasked with "using map and unmap methods to draw a line across the screen by setting pixel byte data to rgb red values".
I have the sprite and background displaying but have no idea how to get the data.
I also tried doing this:
//Create device
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
desc.Width = 500;
desc.Height = 300;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
m_d3dDevice->CreateTexture2D(&desc, nullptr, &texture);
m_d3dDevice->CreateShaderResourceView(texture, 0, &textureView);
// Render
D3D11_MAPPED_SUBRESOURCE mapped;
m_d3dContext->Map(texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
data = (BYTE*)mapped.pData;
rows = (BYTE)sizeof(data);
std::cout << "hi" << std::endl;
m_d3dContext->Unmap(texture, 0);
Problem is that in that case data array is size 0 but has a pointer. This means that I am pointing to a texture that doesn't have any data or am I not getting this?
Edit:
currently I found
D3D11_SHADER_RESOURCE_VIEW_DESC desc;
m_background->GetDesc(&desc);
desc.Buffer; // buffer
I felt the need to create an Answer for this as when I searched for how do this. This question pops up first and the supplied answer didn't really solve the problem for me and wasn't quite the way I wanted to do it anyways...
In my program I have a method as below.
void ContentLoader::WritePixelsToShaderIndex(uint32_t *data, int width, int height, int index)
{
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA initData;
initData.pSysMem = data;
initData.SysMemPitch = width * 4;
initData.SysMemSlicePitch = width * height * 4;
Microsoft::WRL::ComPtr<ID3D11Texture2D> tex;
Engine::device->CreateTexture2D(&desc, &initData, tex.GetAddressOf());
Engine::device->CreateShaderResourceView(tex.Get(), NULL, ContentLoader::GetTextureAddress(index));
}
Then using the below code I tested drawing a Blue Square with a White Line. And it works perfectly fine. The issue I was getting was setting the System Mem Slice and Mem Pitch after looking in the WICTextureLoader class I was able to figure out how the data is stored. So it appears the
MemPitch = The Row's Size in Bytes.
MemSlice = The Total Image Pixels Size In Bytes.
const int WIDTH = 200;
const int HEIGHT = 200;
const uint32_t RED = 255 | (0 << 8) | (0 << 16) | (255 << 24);
const uint32_t WHITE = 255 | (255 << 8) | (255 << 16) | (255 << 24);
const uint32_t BLUE = 0 | (0 << 8) | (255 << 16) | (255 << 24);
uint32_t *buffer = new uint32_t[WIDTH * HEIGHT];
bool flip = false;
for (int X = 0; X < WIDTH; ++X)
{
for (int Y = 0; Y < HEIGHT; ++Y)
{
int pixel = X + Y * WIDTH;
buffer[pixel] = flip ? BLUE : WHITE;
}
flip = true;
}
WritePixelsToShaderIndex(buffer, WIDTH, HEIGHT, 3);
delete [] buffer;
First of all, most of those functions return HRESULT values that you are ignoring. That's not safe as you will miss important errors that invalidate the remaining code. You can use if(FAILED(...)) if you want, or you can use ThrowIfFailed, but you can't just ignore the return value in a functioning app.
HRESULT hr = m_d3dDevice->CreateTexture2D(&desc, nullptr, &texture);
if (FAILED(hr))
// error!
hr = m_d3dDevice->CreateShaderResourceView(texture, 0, &textureView);
if (FAILED(hr))
// error!
// Render
D3D11_MAPPED_SUBRESOURCE mapped;
hr = m_d3dContext->Map(texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
if (FAILED(hr))
// error!
Second, you should enable the Debug Device and look for diagnostic output which will likely point you to the reason for the failure.
sizeof(data) is always going to be 4 or 8 since data is a BYTE* i.e. the size of a pointer. It has nothing to do with the size of your data array. The locked buffer pointed to by mapped.pData is going to be mapped.RowPitch * desc.Height bytes in size.
You have to copy your pixel data into it row-by-row. Depending on the format and other factors, mapped.RowPitch is not necessarily going to be 4 * desc.Width--4 bytes per pixel is because you are using a format of DXGI_FORMAT_B8G8R8A8_UNORM. It should be at least that big, but it could be bigger to align the overall size.
This is pseudo-code and not necessarily an efficient way to do it, but:
for(UINT y = 0; y < desc.Height; ++y )
{
for(UINT x = 0; x < desc.Width; ++x )
{
// Find the memory location of the pixel at (x,y)
int pixel = y * mapped.RowPitch + (x*4)
BYTE* blue = data[pixel];
BYTE* green = data[pixel] + 1;
BYTE* red = data[pixel] + 2;
BYTE* alpha = data[pixel] + 3;
*blue = /* value between 0 and 255 */;
*green = /* value between 0 and 255 */;
*red = /* value between 0 and 255 */;
*alpha = /* value between 0 and 255 */;
}
}
You should take a look at DirectXTex which does a lot of this kind of row-by-row processing.

Convert extended precision float (80-bit) to double (64-bit) in MSVC

What is the most portable and "right" way to do conversion from extended precision float (80-bit value, also known as long double in some compilers) to double (64-bit) in MSVC win32/win64?
MSVC currently (as of 2010) assumes that long double is double synonym.
I could probably write fld/fstp assembler pair in inline asm, but inline asm is not available for win64 code in MSVC. Do I need to move this assembler code to separate .asm file? Is that really so there are no good solution?
Just did this in x86 code...
.686P
.XMM
_TEXT SEGMENT
EXTRN __fltused:DWORD
PUBLIC _cvt80to64
PUBLIC _cvt64to80
_cvt80to64 PROC
mov eax, dword ptr [esp+4]
fld TBYTE PTR [eax]
ret 0
_cvt80to64 ENDP
_cvt64to80 PROC
mov eax, DWORD PTR [esp+12]
fld QWORD PTR [esp+4]
fstp TBYTE PTR [eax]
ret 0
_cvt64to80 ENDP
ENDIF
_TEXT ENDS
END
If your compiler / platform doesn't have native support for 80 bit floating point values, you have to decode the value yourself.
Assuming that the 80 bit float is stored within a byte buffer, located at a specific offset, you can do it like this:
float64 C_IOHandler::readFloat80(IColl<uint8> buffer, uint32 *ref_offset)
{
uint32 &offset = *ref_offset;
//80 bit floating point value according to the IEEE-754 specification and the Standard Apple Numeric Environment specification:
//1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa
float64 sign;
if ((buffer[offset] & 0x80) == 0x00)
sign = 1;
else
sign = -1;
uint32 exponent = (((uint32)buffer[offset] & 0x7F) << 8) | (uint32)buffer[offset + 1];
uint64 mantissa = readUInt64BE(buffer, offset + 2);
//If the highest bit of the mantissa is set, then this is a normalized number.
float64 normalizeCorrection;
if ((mantissa & 0x8000000000000000) != 0x00)
normalizeCorrection = 1;
else
normalizeCorrection = 0;
mantissa &= 0x7FFFFFFFFFFFFFFF;
offset += 10;
//value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383)
return (sign * (normalizeCorrection + (float64)mantissa / ((uint64)1 << 63)) * g_Math->toPower(2, (int32)exponent - 16383));
}
This is how I did it, and it compiles fine with g++ 4.5.0. It of course isn't a very fast solution, but at least a functional one. This code should also be portable to different platforms, though I didn't try.
I've just written this one. It constructs an IEEE double number from IEEE extended precision number using bit operations. It takes the 10 byte extended precision number in little endian format:
typedef unsigned long long uint64;
double makeDoubleFromExtended(const unsigned char x[10])
{
int exponent = (((x[9] << 8) | x[8]) & 0x7FFF);
uint64 mantissa =
((uint64)x[7] << 56) | ((uint64)x[6] << 48) | ((uint64)x[5] << 40) | ((uint64)x[4] << 32) |
((uint64)x[3] << 24) | ((uint64)x[2] << 16) | ((uint64)x[1] << 8) | (uint64)x[0];
unsigned char d[8] = {0};
double result;
d[7] = x[9] & 0x80; /* Set sign. */
if ((exponent == 0x7FFF) || (exponent == 0))
{
/* Infinite, NaN or denormal */
if (exponent == 0x7FFF)
{
/* Infinite or NaN */
d[7] |= 0x7F;
d[6] = 0xF0;
}
else
{
/* Otherwise it's denormal. It cannot be represented as double. Translate as singed zero. */
memcpy(&result, d, 8);
return result;
}
}
else
{
/* Normal number. */
exponent = exponent - 0x3FFF + 0x03FF; /*< exponent for double precision. */
if (exponent <= -52) /*< Too small to represent. Translate as (signed) zero. */
{
memcpy(&result, d, 8);
return result;
}
else if (exponent < 0)
{
/* Denormal, exponent bits are already zero here. */
}
else if (exponent >= 0x7FF) /*< Too large to represent. Translate as infinite. */
{
d[7] |= 0x7F;
d[6] = 0xF0;
memset(d, 0x00, 6);
memcpy(&result, d, 8);
return result;
}
else
{
/* Representable number */
d[7] |= (exponent & 0x7F0) >> 4;
d[6] |= (exponent & 0xF) << 4;
}
}
/* Translate mantissa. */
mantissa >>= 11;
if (exponent < 0)
{
/* Denormal, further shifting is required here. */
mantissa >>= (-exponent + 1);
}
d[0] = mantissa & 0xFF;
d[1] = (mantissa >> 8) & 0xFF;
d[2] = (mantissa >> 16) & 0xFF;
d[3] = (mantissa >> 24) & 0xFF;
d[4] = (mantissa >> 32) & 0xFF;
d[5] = (mantissa >> 40) & 0xFF;
d[6] |= (mantissa >> 48) & 0x0F;
memcpy(&result, d, 8);
printf("Result: 0x%016llx", *(uint64*)(&result) );
return result;
}
Played with the given answers and ended up with this.
#include <cmath>
#include <limits>
#include <cassert>
#ifndef _M_X64
__inline __declspec(naked) double _cvt80to64(void* ) {
__asm {
// PUBLIC _cvt80to64 PROC
mov eax, dword ptr [esp+4]
fld TBYTE PTR [eax]
ret 0
// _cvt80to64 ENDP
}
}
#endif
#pragma pack(push)
#pragma pack(2)
typedef unsigned char tDouble80[10];
#pragma pack(pop)
typedef struct {
unsigned __int64 mantissa:64;
unsigned int exponent:15;
unsigned int sign:1;
} tDouble80Struct;
inline double convertDouble80(const tDouble80& val)
{
assert(10 == sizeof(tDouble80));
const tDouble80Struct* valStruct = reinterpret_cast<const tDouble80Struct*>(&val);
const unsigned int mask_exponent = (1 << 15) - 1;
const unsigned __int64 mantissa_high_highestbit = unsigned __int64(1) << 63;
const unsigned __int64 mask_mantissa = (unsigned __int64(1) << 63) - 1;
if (mask_exponent == valStruct->exponent) {
if(0 == valStruct->mantissa) {
return (0 != valStruct->sign) ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
}
// highest mantissa bit set means quiet NaN
return (0 != (mantissa_high_highestbit & valStruct->mantissa)) ? std::numeric_limits<double>::quiet_NaN() : std::numeric_limits<double>::signaling_NaN();
}
// 80 bit floating point value according to the IEEE-754 specification and
// the Standard Apple Numeric Environment specification:
// 1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa
const double sign(valStruct->sign ? -1 : 1);
//If the highest bit of the mantissa is set, then this is a normalized number.
unsigned __int64 mantissa = valStruct->mantissa;
double normalizeCorrection = (mantissa & mantissa_high_highestbit) != 0 ? 1 : 0;
mantissa &= mask_mantissa;
//value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383)
return (sign * (normalizeCorrection + double(mantissa) / mantissa_high_highestbit) * pow(2.0, int(valStruct->exponent) - 16383));
}

Resources