I'm following root42's videos about DOS programming using Turbo C 2.01. I've written my own Soundblaster 1.xx driver following the Creative Labs documentation, and I'm confused about memory allocation. I'm working in real mode in the large model.
To play sound through the SB using DMA, the source memory block must be wholly contained in one memory segment (that is, the linear address of the first and last bytes of the block & 0xFFFF0000
must be equal).
In root42's video, they use the following code to allocate a 32768 byte block:
void assign_dma_buffer()
{
unsigned char* temp_buf;
long linear_address;
short page1, page2;
temp_buf = (char *) malloc(32768);
linear_address = FP_SEG(temp_buf);
linear_address = (linear_address << 4)+FP_OFF(temp_buf);
page1 = linear_address >> 16;
page2 = (linear_address + 32767) >> 16;
if( page1 != page2 ) {
dma_buffer = (char *)malloc(32768);
free( temp_buf );
} else {
dma_buffer = temp_buf;
}
linear_address = FP_SEG(dma_buffer);
linear_address = (linear_address << 4)+FP_OFF(dma_buffer);
page = linear_address >> 16;
offset = linear_address & 0xFFFF;
}
This looks like it allocates memory, examines the resulting absolute address to determine whether both end-points lie within the same segment, and if so places the address in page
and offset
global variables for use by DMA later, otherwise it has a second attempt and returns that unconditionally.
What would happen if the second attempt was also straddling a segment boundary? I think this code works on the assumption that malloc returns consecutive, contiguous blocks of memory.
Is there some Turbo C / MS-DOS specific way I can request a block of memory that's guaranteed to lie within just one segment? Or, even better, just request the whole segment?