gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > initConsoleDefault() bug?

#138708 - Moby Disk - Tue Aug 28, 2007 3:31 am

I was pleased to find that printf() and cout work if you call initConsoleDefault() in libnds. But I did notice that if you do std::cout << std::endl; before calling initConsoleDefault() that the console does not work for the duration of the application.

Does anyone know why? How do I submit bug reports to libnds? Is there an official forum for libnds?

#138710 - tepples - Tue Aug 28, 2007 4:04 am

Short answer:
Please show us the source code that misbehaves.

Long answer:
Is there a reason that you can't make sure to call the init function before making output? Are you trying to make output in a global constructor?

But first make sure that you have a valid bug report. GCC as provided in devkitARM appears to be a "freestanding" implementation of the C language, and freestanding implementations do not have to implement I/O the way the standard recommends. For example, devkitARM+libnds provides a subset of the output to std::stdout and std::cout that a "hosted" implementation provides, allowing code that runs on a "hosted" implementation to be ported more easily, but you have to call the init functions first.

If you're confident that the issue you see is a defect in devkitARM+libnds, and you can reproduce this defect with a test case, feel free to use the official issue tracker for devkitARM, libnds, and other devkitPro projects.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#138747 - Moby Disk - Tue Aug 28, 2007 2:42 pm

Thanks for the reply!

Quote:
Is there a reason that you can't make sure to call the init function before making output? Are you trying to make output in a global constructor?

I was porting a library of mine that did console output before it made an initialization callback. I moved the consoleInitDefault() code from the callback into the top of main and that eliminated it. No global constructors so I'm safe. (Off-topic: Is there a way to tell gcc to call them in any particular order?)

I am not confident this is a defect at all - maybe just a limitation. I can definitely reproduce it, but it is probably not worth fixing - just a caveat I guess.

If I was feeling tenacious, what would I need to step into the << operator for std::cout and into the libnds console code if I wanted to see what was happening? I suppose I would need to build libnds but would I also need the source to the gcc standard library implementation? I'm not sure where I would get that.

FYI, code to reproduce, in case anyone is interested:
Code:
#include <nds.h>
#include <stdio.h>
#include <iostream>

void initTextOnBottom()
{
   videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
   vramSetBankC(VRAM_C_SUB_BG_0x06200000);

   // black backdrop
   BG_PALETTE_SUB[0]=RGB15(0,0,0);

   SUB_BG0_CR = BG_MAP_BASE(31);//use bg0 for the text
   
   BG_PALETTE_SUB[255] = RGB15(25,25,25);//by default font rendered with color 255
   
   //consoleInit() is a lot more flexible but this gets you up and running quick
   consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
}

int main()
{   
   // Turn on everything
   powerON(POWER_ALL);

   // IRQ basic setup
   irqInit();
   irqSet(IRQ_VBLANK, 0);

   // Output text - there is nowhere for this text to go anyway
   std::cout << "Before consoleInitDefault";

   // ----- Uncomment this line to break consoleInitDefault() -----
   // std::cout << std::endl;

   // Console mode
   initTextOnBottom();

   // This text will appear on the pseudo-console
   std::cout << "After consoleInitDefault" << std::endl;

   // Stop
   while(1)
   {
      swiWaitForVBlank();
   }
   
   return 0;
}

#138760 - tepples - Tue Aug 28, 2007 7:59 pm

Moby Disk wrote:
No global constructors so I'm safe. (Off-topic: Is there a way to tell gcc to call them in any particular order?)

The ISO C++ standard defines no way to specify the order of construction of global objects in general. You could try using global pointers to objects, which are implicitly initialized to NULL, and constructing the object explicitly when needed:
Code:
Foo *someGlobalObj;

Bar::Bar() {
  if (!someGlobalObj) {
    someGlobalObj = new Foo();
  }
  someGlobalObj->someMethod();
}

See "Constructors" in C++ FAQ Lite for details.

Quote:
I suppose I would need to build libnds but would I also need the source to the gcc standard library implementation?

When you write to std::cout, you are actually calling into four libraries:
  1. GNU libstdc++, where std::cout of <iostream> calls functions in <cstdio>;
  2. Newlib, where <cstdio> functions such as std::fputs() and std::fwrite() call the underlying platform's write() implementation;
  3. devkitARM's devoptab, which routes calls to write() into implementations that work on separate devices; and
  4. device drivers such as libnds's console, which handles write() by modifying VRAM, and libfat, which handles write() by writing to a file system made of flash sectors.

In order to allow step 3 to see step 4, you need to consoleInitDefault() and/or fatInitDefault() before you write().

Quote:

FYI, code to reproduce, in case anyone is interested:
Code:
#include <nds.h>
#include <stdio.h>
#include <iostream>

It is no longer "good C++" to include <iostream.h> and <stdio.h>; the new method is <iostream> and <cstdio>. The C++ compiler and library shipped in most GCC distributions provide <stdio.h> for C++ programs as an extension for backward compatibility with code written before the standardization of C++.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.