Wednesday, September 23, 2009

Google Search Defaults To Wrong Country TLD in Opera

Opera 10.0 on OS X remembers the non-default country specific google TLD the first time Google redirects it to such a TLD. Having recently visited Australia, my Google search from the toolbar was stuck on google.com.au; clearing cookies and private data didn't help with that.

The culprit is the following line in ~/Library/Preferences/Opera Preferences:

$ cd ~/Library/Preferences/Opera\ Preferences/
$ grep -r 'TLD Default' *
[...]
operaprefs.ini:Keyboard Configuration={Resources}defaults/standard_keyboard.ini
operaprefs.ini:Mouse Configuration={Resources}defaults/standard_mouse.ini
operaprefs.ini:Show Default Browser Dialog=0
operaprefs.ini:Google TLD Default=.google.com.au


All it takes to restore the default google TLD (the US one, in my case) is to quit Opera and remove the highlighted line in operaprefs.ini. Due to this browser's cross-platform nature, it's likely that same approach will work on Windows and Linux. Hopefully it will save some traveller a bit of head scratching.

The ~/ refers to your home folder, it a Unix equivalent of Windows's %USERPROFILE% environment variable.

Saturday, September 05, 2009

Pascal-Style Local Functions in C (for Z8 Encore!)

When I was a kid, I used Turbo Pascal. It had one feature that I sorely miss in every embedded C compiler: local functions. Local, as in local to a block. Those become a necessity to maintain decent code performance and avoid the penalty of passing duplicate data via parameters. They also help maintain readable, decently factorized code.

A local function, were C to have it, would look like this:

void fun1(void) {
 int a;
 void fun2(void) {
   a = 0;
 }
}

I hope you see that fun2() is local to the main block of fun1(), and that the variable a is in scope within fun2().

A somewhat less clean, but equally well performing way of accomplishing this would be:

extern int a;
void fun2(void) {
  a = 0;
}
void fun1(void) {
...
  fun2();
}

Now the question remains: where do we actually define the variable a, which is supposed to be local to fun1?

It becomes easy if your compiler supports static frames. Static frames are, as their name implies, allocated statically by the linker, and are overlaid according to the call tree. With usual dynamic frames, automatic variables end up on the stack. It should not be any harder to do with dynamic frames, but I haven't checked it out yet.

ZDS II, the C IDE for Zilog's Z8 Encore! and ZNEO products, supports static frames at the assembler and linker level. A frame ends up defining a near and far segment; for a function called fun1 those segments are called ?_n_fun1 and ?_f_fun1, respectively.

Assuming our code is in a file named file.c, and we're compiling for large model, we get

// file.c
extern int a;

#pragma asm segment ?_f_fun1
#pragma asm _a ds 2
#pragma asm segment file_TEXT

void fun2(void) {
  a = 0;
}

void fun1(void) {
...
  fun2();
}

Here, we manually allocate storage for a in fun1's far frame (due to model being large). This method can be used to bring back the nifty (albeit buggy) feature of ZDS II 4.9.x, which got abandoned and is no more present in ZDS II 4.11.0: arbitrary far/near automatic variables.

The syntax used to look like this:

void fun(void) {
  near int a;
  far int b;
  ...
}

The near/far storage specification was ignored when using dynamic frames, but for static frames it allowed you selecting whether given automatic variable would be stored in near or far memory space. Accesses to far variables take an extra clock cycle per byte, and can bring an extra load penalty in some cases, where the data has to be transferred from far memory to a register using LDX, before being useable by the target opcode.

We implement this functionality as follows:

// file.c

#pragma asm segment ?_n_fun
#pragma asm _a ds 2
#pragma asm segment ?_f_fun
#pragma asm _b ds 2
#pragma asm segment file_TEXT

void fun(void) {
  extern near int a;
  extern far int b;
  ...
}

The main drawback of this method, besides it being prone to typos and suffering from relegating part of the compiler to the wrong side of the keyboard, is that the assembly-level symbols _a and _b really have file scope due to the fact that assembler sees it so. Thus, the canonical way of using this trick is to have a complete tree of nested functions all in one C source file, and having unique names for all the automatic variables that have to be accessed by the local functions.

We shoot two birds with one stone here: we regain the foreign-model automatic variables of ZDS II 4.9.x vintage, and we Pascal-style local functions, which can access the automatic variables present in the scope of the caller's call site. Naturally, this is a hack which should only be used where performance or storage limitations demand it. It could be implemented with an extra C preprocessor.

Thursday, September 03, 2009

Asterisk 1.4 Update Woes

I admin a CentOS 5 server with Asterisk 1.4 on it, hooked up to an XO T1 link. The repo I use for this is atrpms, which has been pretty much problem-free.

After a most recent upgrade, asterisk would fail to load the dahdi channel driver, with the following in /var/log/asterisk/messages:
WARNING[pid] loader.c: Error loading module 'chan_dahdi.so': /usr/lib/asterisk/modules/chan_dahdi.so: undefined symbol: ast_smdi_interface_unref
The solution, as hinted by Chris Maciejewski, is to load the res_smdi.so module. For whatever reason, my /etc/asterisk/modules.conf had the following line:
noload => res_smdi.so
Changing it to "load => ..." fixed the problem.

Tuesday, September 01, 2009

Zilog's Encore!: Changes for Change's Sake, and When Simple Won't Do

I have been using Zilog's Z8 Encore! chips since the first marketed silicon release of Z8F4801, Rev AA. The chip is a nice 8-bit MCU. As nice and useful as it is, its history can't but highlight concerning lack of vision and direction in Zilog's marketing and development efforts.

Let's start with a rather simple thing: the tool used to interface with the chip's one-wire DBG pin. It's nothing more than an autobauding half-duplex asynchronous port, in CMOS voltage levels. Such simplicity was reflected in Zilog's first debug "tool" sold with the early Z8F6401 development kits. It was a small board (approx 1 sq in), with a TTL-to-RS232 converter chip (MAX232, IIRC), a diode standing in for an open-drain driver, the DBG line pull-up, and some decoupling and charge pump capacitors, and two connectors -- one for the 6-pin target header, another for the serial cable.

Soon thereafter it became obvious that RS232 serial ports are being phased out from newly made PCs. In keeping with the times, Zilog switched to a USB-based "smart cable". This came in a plastic enclosure, and had a Zilog MCU, a USB interface chip, and assorted other circuitry. Naturally, it was undocumented, and to use it you had two choices: use the driver and DLLs that Zilog furnished, or reverse-engineer the protocol. The latter was not very attractive since the replacement was almost a no-brainer: a USB-to-serial converter, and the simple serial-to-DBG interface.

Some of you will now think: well, wait a moment, didn't the "smart" cable provide some extra functionality, compared to the crude serial-port-based interface? Oh yes, it did provide extra functionality: it could also drive the target's RESET# line. That's about it. Never mind that the DTR line could be used for the same purpose. Of course the original "dumb" cable didn't have the DTR-to-RESET# connection. I can almost visualize the development tools division manager in a meeting with Encore! line strategist and upper management: we will make a new "smart" cable provide the RESET# signal to the newfinagled 8-pin XP series MCUs, and besides it will make things much faster.

In less than a decade, Zilog has managed to put out at least four versions of the DBG-to-PC interface: the "dumb" one using MAX232, two USB smart cables, and an Ethernet smart cable. Timing full-chip program loads using the DLLs and drivers provided with most recent version of ZDS II, the "dumb" interface wins hands down, providing 25-50% speedup on programming, and snappier behavior during debugging sessions. So, a lot of engineering effort for naught. Note that the "dumb" solution can be trivially ported to USB, and even isolated, all at a rather minimal cost, even if one would like to have an option of powering the target from the USB.

In that same decade, Zilog managed to change the logo stamped on their Encore! chips no less than three times. When I get back from my travel, I have to snap some pictures, as it is somewhat entertaining. I have a cache of single pieces from various Encore! lots.

In the same decade, they managed to keep shipping a free, but admittedly rather botched C compiler/IDE combo, called Zilog Developer Studio II. During this period of time, the rather obscene code generation bugs have been left alone, while one quite useful feature was dropped, other useful features added, and generally the development progressed at a glacial pace when compared with say gcc. The ZDS II woes almost warrant another post, but I'll much rather let the sleeping dogs lie.

Some straight priorities of Zilog, if you ask me.

I will finish with rather technical look at the real (vs. Zilog-imagined) needs of a "smart" cable for Zilog's DBG pin protocol.

As it turns out, whatever "smarts" the smart cable had were wholly unnecessary. You see, Zilog's chip design folks have very thoughtfully made the half-duplex DBG pin protocol inherently streaming-friendly. Save for the oddball whole-ROM CRC calculation, every command is executed in real time and requires no pacing/waiting. The reply bytes closely follow the command bytes. By "closely" I mean a delay of a couple of system clock cycles. As expected, a full erase-upload-verify cycle on a Z8F4821, done via the FT232R USB-to-serial interface, takes a whopping couple of seconds, when done at ~150kbaud (that's 15k bytes per second using 8-N-1 format).

One thinks, of course: is it possible to really speed it up any, and would placing a CPU between the USB-to-serial chip and the DBG line really help? Yes, somewhat. Let's assume we're using FTDI's interface chips, like FT232R. Those have a small, 384 byte buffer. Since the OS can sometimes starve the USB devices of USB read transfers, it could help to have an extra layer of buffering between the stream reflected from DBG pin, and FT232R, obviously with RTS/CTS handshaking enabled.

The USB transfers are paced with a 1ms USB frame period. This means that a turnaround from the PC to the target and back is no shorter than ~1ms; in practice it is 3ms since the FTDI chip, faced with no further activity on the input, will purge the receive buffer after an extra delay of 2ms.

First the PC sends a read command to the target, the half-duplex interface reflects the command back, and the target appends results of the read. Before subsequent commands can be sent, the PC must receive the results.

This can be worked around by providing a method of pacing the transmission so that the reply will have a place to "fit in". At "slow" baud rates, such pacing should require no extra effort: we send 0xFF (all data bits set), and the target pulls some of the bits low with its open drain driver. I haven't checked if the target's contention-detection circuit gets tripped by that, though. At "fast" baud rates, where we could reasonably expect the skew in target's reply bitstream to be significant enough to corrupt the bitstream, this of course becomes problematic.

This can be "fixed" by inserting an MCU between the USB-to-serial interface, and the target. The MCU would perform only two functions:

  1. buffering the data when the host keeps RTS# deasserted, to prevent data loss due to overruns,
  2. inserting a "sense" delay between bytes coming from the host being equal to 0xFF, and other bytes.
The second function would ensure that if the host is sending 0xFF, the target is given perhaps a bit period or two time to start replying -- if so, then the 0xFF byte from the host is discarded. If the target doesn't reply on its own, it's a fair assumption that the 0xFF byte was the part of the command stream destined to the target, and must be sent to the target. Thus the host PC has an easy way of pacing its data stream to accommodate replies from the target, all without losing streaming.

Moreover, any host software can easily accommodate this functionality being absent by either enforcing a roundtrip latency -- following an FT_Write() by FT_Read(), or by selecting a lower baud rate (I'll have to check that!).