The Boston Diaries

The ongoing saga of a programmer who doesn't live in Boston, nor does he even like Boston, but yet named his weblog/journal “The Boston Diaries.”

Go figure.

Friday, April 05, 2024

Matchbox cars seem to have gotten bigger in recent years

Bunny and I went to a local Toyota dealership to fix an issue with her car (it turns out it was a very unusual, but very minor, issue) and while there, we saw this on the display floor:

[A very small electric car for one] That's not a car!  That's an oversized roller skate!

Turns out, this is not a large Matchbox car, but a small electric car straight from a factory in Japan (the informational flying under the windsheid is all in Japanese). A five year old would barely fit in this thing, much less an adult. There doesn't appear to be any storage space of any significant size, and sans doors, I'm not sure this is even road legal. And the the staff there don't even know if it's for sale. Weird.

Thursday, April 04, 2024

I love it when abstractions are too abstract to be useful

I recently found an annoying aspect of Xlib—it's hard to find documentation about what keys affect the state field of the keyboard event. It's obvious that the shift keys on the keyboard will set ShiftMask, the control key will set ControlMask, and the CapsLock key will set LockMask (when I would expect it to set ShiftMask since it's just locking the shift keys to “on”), but there's little to say what keys set the Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask and Mod5Mask.

This is problematic, because I do need to check for keyboard events and this threw me for a loop—why are none of the keys working? Well, that's because my virtual Linux server on the Mac sets the NumLock key, which causes the X server to then set the Mod2Mask for all keyboard events and I wasn't expecting that.

Sigh.


Tracking down a bug

I've spent the past two days tracking down a bug, and I think it's a library issue.

So I have this program I wrote some time ago that uses Xlib and for reasons, I needed to store a 64-bit value that's related to a window. This is easy enough with setting a window property. The code for that is easy enough:

void svalue(Display *display,Window window,unsigned long long int value)
{
  assert(display != NULL);
  assert(window  != None);

  XChangeProperty(
    display,
    window,
    CALC_VALUE,
    XA_INTEGER,
    32,	/* format */
    PropModeReplace,
    (unsigned char *)&value,
    sizeof(value) / 4 /* number of 'format' units */
  );
}

CALC_VALUE is the “variable” (for lack of a better term) and XA_INTEGER is (again, for lack of a better term) the base type. Yes, this is just wrapping a single function call in a function, but it's an abstraction to make things simpler as it's called from multiple locations in the codebase.

To query the value:

unsigned long long int qvalue(Display *display,Window window)
{
  assert(display != NULL);
  assert(window  != None);
  
  unsigned long long int  value;
  Atom                    atom_got;
  unsigned char          *plong;
  int                     rc = XGetWindowProperty(
                                  display,
                                  window,
                                  CALC_VALUE,
                                  0,
                                  sizeof(unsigned long long int) / 4,
                                  False,
                                  XA_INTEGER,
                                  &atom_got,
                                  &(int){0}, /* this is don't care */
                                  &(unsigned long int){0}, /* another don't care */
                                  &(unsigned long int){0}, /* another don't care */
                                  &plong
                                );
                     
  if ((rc == Success) && (atom_got == XA_INTEGER))
  {
    memcpy(&value,plong,sizeof(unsigned long long int));
    XFree(plong);
  }
  else
    value = 0;
    
  return value;
}

Again, nothing too horrible or tricky.

The code was originally written on a 32-bit system (just after I left The Enterprise), and it worked. I then wanted to get the program working on a 64-bit system (beacuse I want to both release it and talk about it). It worked, but only for values of 31-bits or less. As soon as the value hit 32-bits, the upper 32-bits were all 1s.

I added code to dump the value just before the call to XChangeProperty() and code to dump the value just after the call to XGetWindowProperty() and somewhere, once the value was 0x00000000FFFFFFFF going into XChangeProperty(), it was 0xFFFFFFFFFFFFFFFF coming out of XGetWindowProperty().

32-bit version? No issues. 64-bit version? Issues.

I tried a different compiler, on the off chance that I might be hitting some weird compiler bug, and no go, GCC or Clang, both on the 64-bit system had the same issue. I tried using a different X server and the same results—32 bit client, fine; 64-bit client, not fine. So I think it's due to the client side on the 64-bit system where the issue lies. Also, if I change the call to XChangeProperty() to:

void svalue(Display *display,Window window,unsigned long long int value)
{
  assert(display != NULL);
  assert(window  != None);

  XChangeProperty(
    display,
    window,
    CALC_VALUE,
    XA_INTEGER,
    8, /* format, this time 8! */
    PropModeReplace,
    (unsigned char *)&value,
    sizeof(value) /* still number of 'format' units */
  );
}

That is, a format of 8 fixed the issue. Even a format of 16 worked. It's just that when I try to use a format of 32, on the 64-bit system, does it fail.

And using a format of 8 on the 32-bit system works as well, so at least I have a workaround for it. Still, it's annoying.

Wednesday, April 03, 2024

“Because this kind of battery is encrypted …”

So I'm reading the “Battery Replacement Installation Manual” for the battery I just bought and as translated instructions go, it's not that bad. But there are some choice bits though …

Why does the phone echo?

The echo of the phone may be due to the installation problem. Can you see if there are any loose parts, because the battery will not affect the quality of the phone's call unless there is no power and cause the phone shut down.

“The echo of the phone?”

Feedback? Hearing my own voice echoed back to me? Maybe?

Anyway, carrying on …

Why did I receive a swollen battery?

Because this kind of battery is encrypted …

I have no clue here. It states that swelling may occur if the temperature exceeds 158°F (70°C), and enter sleep mode if the temperature is too low, although it doesn't state what “too low” means. Fortunately, the battery I received isn't swollen, so I guess it's not encrypted?

4. Please carefully check whether there is any debris or screws falling into the battery area. If there is, please clean it up before proceeding to the next step, otherwise the sundries may pierce the battery and cause a short circuit and cause spontaneous combustion.

“Sundries.” Love it!


An excessive number of packaging layers

I ordered an item from Amazon the other day. The expected arrival time was Friday, but instead, it arrived today. On the front porch was an Amazon box, measuring 6″ × 9″ × 5″ (16cm × 23cm × 13cm for the more civilized amongst you). Inside was another box, 3″ × 4½″ × ⅜″ (7cm × 11cm × 1cm). Inside that was a slightly smaller anti-static bag. Inside that was a smaller plastic bad, and finally, inside that was the item I had purchased—a replacement battery for my old-school flip phone.

Seriously? Four layers of packaging? Sigh.

Tuesday, April 02, 2024

Dear LinkedIn, why are you still asking me these questions?

LinkedIn is still asking me to participate as an expert answering questions—this time, “You're a system architect. How do you decide which programming languages to learn?” And just below that is “Powered by AI and the LinkedIn community.”

Sigh. Eu tu, LinkedIn?

I'm still tempted to answer, but no. I can't just bear to answer this how I would want to answer it. Besides, if you know where to look, you might find my answers anyway.


It only took 25 years for my idea to catch on

I was exchanging emails with Christian about online document structure when I mentioned The Electric King James Bible and it's rather unique addressing scheme. I came up with that 25 years ago [Good Lord! Has it been that long? —Sean] [Yes. —Editor] [Yikes! —Sean] to precisely pull up Bible verses—anywhere from one verse to an entire book. Of all the Bible sites across the Intarwebs I've come across since have never used such an elegant, and to me, obvious, way of referencing the Bible online. Usually they use a URL format like <https://bible.example.org/?bible=kj&book=Genesis&chapter=1&start_verse=1&end_verse=1>.

But Christian mentioned Sefaria as using my method, and true enough, it does! <https://www.sefaria.org/Genesis.6:9-9:17> does indeed go to the Noah's Ark story. I think that's neat! I don't know if they were inspired by my site (unlikely, but not completely out of the relms of possibility) or just came up with it on their own, but it's nice to see someone else is using an easy to hack URL form for Bible references.

There are differences though—my site only brings up the requested material, whereas Sefaria implements a bidirectional “Scroll Of Doom” where additional material appears when you go up or down. I can't say I'm a fan of that, but it apparently works for them.

Monday, April 01, 2024

Notes on an overheard conversion while eating dinner at The Cracker Barrel

“Oh no. This is bad.”

“Wow! Are you sure there are no more moves you can make?”

“Nope. See?”

“How many pegs is that?”

“10.”

“Wow! You are really bad at that!”

[If you add up all the possible ways leaving just one peg in the Peg Game, including rotations, reflections and reflected rotations, you have 438,984 ways of solving the Peg Game. If you add up all the possible ways of leaving 10 pegs, including rotations, reflections and reflected rotations, you have just six solutions. It is a much harder problem leaving 10 pegs than leaving one. I'm just saying … —Editor]

Friday, March 01, 2024

The speed of Microsoft's BASIC floating point routines

I was curious about how fast Microsoft's BASIC floating point routines were. This is easy enough to test, now that I can time assembly code inside the assembler. The code calculates -2π3/3! using Color BASIC routines, IEEE-754 single precision and double precision.

First, Color BASIC:

	.tron	timing
ms_fp		ldx	#.tau
		jsr	CB.FP0fx	; FP0 = .tau
		ldx	#.tau
		jsr	CB.FMULx	; FP0 = FP0 * .tau
		ldx	#.tau
		jsr	CB.FMULx	; FP0 = FP0 * .tau
		jsr	CB.FP1f0	; FP1 = FP0
		ldx	#.fact3
		jsr	CB.FP0fx	; FP0 = 3!
		jsr	CB.FDIV		; FP0 = FP1 / FP0
		neg	CB.fp0sgn	; FP0 = -FP0
		ldx	#.answer
		jsr	CB.xfFP0	; .answer = FP0
	.troff
		rts

.tau		fcb	$83,$49,$0F,$DA,$A2 
.fact3		fcb	$83,$40,$00,$00,$00  
.answer		rmb	5
		fcb	$86,$A5,$5D,$E7,$30	; precalculated result

I can't use the .FLOAT directive here since that only supports either the Microsoft format or IEEE-754 but not both. So for this test, I have to define the individual bytes per float. The last line is what the result should be (by checking a memory dump of the VM after running). Also, .tao is , just in case that wasn't clear. This ran in 8,742 cycles, taking 2,124 instructions and 4.12 cycles per instruction (I modified the assembler to record this additional information).

Next up, IEEE-754 single precision:

	.tron	timing
ieee_single	ldu	#.tau
		ldy	#.tau
		ldx	#.answer
		ldd	#.fpcb
		jsr	REG
		fcb	FMUL	; .answer = .tau * .tau

		ldu	#.tau
		ldy	#.answer
		ldx	#.answer
		ldd	#.fpcb
		jsr	REG
		fcb	FMUL	; .answer = .answer * .tau

		ldu	#.answer
		ldy	#.fact3
		ldx	#.answer
		ldd	#.fpcb
		jsr	REG
		fcb	FDIV	; .answer = .answer / 3!

		ldy	#.answer
		ldx	#.answer
		ldd	#.fpcb
		jsr	REG
		fcb	FNEG	; .answer = -.answer
	.troff
		rts

.fpcb		fcb	FPCTL.single | FPCTL.rn | FPCTL.proj
		fcb	0
		fcb	0
		fcb	0
		fdb	0

.tau		.float	6.283185307
.fact3		.float	3!
.answer		.float	0
		.float	-(6.283185307 ** 3 / 3!)

The floating point control block (.fpcb) configures the MC6839 to use single precision, normal rounding and projective closure (not sure what that is, but it's the default value). And it does calculate the correct result. It's amazing that code written 42 years ago for an 8-bit CPU works flawlessly. What is isn't is fast. This code took 14,204 cycles over 2,932 instructions (average 4.84 cycles per instruction).

The higher than average cycle type could be due to position independent addressing modes, but I'm not entirely sure what it's doing to take nearly twice the time. The ROM does use the IEEE-754 extended format (10 bytes) internally, with more bit shifts to extract the exponent and mantissa, but twice the time?

Perhaps it's code to deal with ±∞ and NaNs.

The IEEE-754 double precision is the same, except for the floating point control block configuring double precision and the use of .FLOATD instead of .FLOAT; otherwise the code is identical. The result, however, isn't. It took 31,613 cycles over 6,865 instructions (average 4.60 cycles per instruction). And being twice the size, it took nearly twice the time as single precision, which is expected.

The final bit of code just loads the ROMs into memory, and calls each function to get the timing:

		org	$2000
		incbin	"mc6839.rom"
REG		equ	$203D	; register-based entry point

		org	$A000
		incbin	"bas12.rom"

	.opt	test	prot	rw,$00,$FF	; Direct Page for BASIC
	.opt	test	prot	rx,$2000,$2000+8192 ; MC6839 ROM
	.opt	test	prot	rx,$A000,$A000+8192 ; BASIC ROM

	.test	"BASIC"
		lbsr	ms_fp
		rts
	.endtst

	.test	"IEEE-SINGLE"
		lbsr	ieee_single
		rts
	.endtst

	.test	"IEEE-DOUBLE"
		lbsr	ieee_double
		rts
	.endtst

Really, the only surprising thing here was just how fast Microsoft BASIC was at floating point.

Wednesday, February 28, 2024

Converting IEEE-754 floating point to Color BASIC floating point

I'm still playing around with floating point on the 6809—specifically, support for floating point for the Color Computer. The format for floating point for Color BASIC (written by Microsoft) predates the IEEE-754 Floating Point Standard by a few years and thus, isn't quite compatible. It's close, though. It's defined as an 8-bit exponent, biased by 129, a single sign bit (after the exponent) and 31 bits for the mantissa (the leading one assumed). It also does not support ±∞ nor NaN. This differs from the IEEE-754 single precision that uses a single sign bit, an 8-bit exponent biased by 127 and 23 bits for the mantissa (which also assumes a leafing one) and support for infinities and NaN. The IEEE-754 double precision uses a single sign bit, an 11-bit exponent biased by 1023 and 52 bit for the mantissa (leading one assumed) plus support for infinities and NaN.

So the Color BASIC is about halfway between single precision and double precision. This lead me to use IEEE-754 double precision for the Color Computer backend (generating an error for inifinities and NaN) then massaging the resulting double into the proper format. I double checked this by finding some floating point constants in the Color BASIC ROM as shown in the book Color BASIC Unravelled II, (available on the Computer Computer Archives), like this table:

4634				* MODIFIED TAYLOR SERIES SIN COEFFICIENTS
4635	BFC7 05			LBFC7	FCB	6-1			SIX COEFFICIENTS
4636	BFC8 84 E6 1A 2D 1B	LBFC8	FCB	$84,$E6,$1A,$2D,$1B	* -((2*PI)**11)/11!
4637	BFCD 85 28 07 FB F8	LBFCD	FCB	$86,$28,$07,$FB,$F8	*  ((2*PI)**9)/9!
4638	BFD2 87 99 68 89 01	LBFD2	FCB	$87,$99,$68,$89,$01	* -((2*PI)**7)/7!
4639	BFD7 87 23 35 DF E1	LBFD7	FCB	$87,$23,$35,$DF,$E1	*  ((2*PI)**5)/5!
4640	BFDC 86 A5 5D E7 28	LBFDC	FCB	$86,$A5,$5D,$E7,$28	* -((2*PI)**3)/3!
4641	BFE1 83 49 0F DA A2	LBFE1	FCB	$83,$49,$0F,$DA,$A2	*    2*PI

Then using the byte values to populate a variable and printing it inside BASIC (this is the expression -2π3/3!):

X=0         ' CREATE A VARIABLE
Y=VARPTR(X) ' GET ITS ADDRESS
POKE Y,&H86 ' AND SET ITS VALUE
POKE Y+1,&HA5 ' THE HARD WAY
POKE Y+2,&H5D
POKE Y+3,&HE7
POKE Y+4,&H28
PRINT X ' LET'S SEE WHAT IT IS
-41.3417023

Then using that to create a floating point value:

	org	$1000
	.float	-41.3417023
	end

Checking the resulting bytes that were generated:

                         | FILE ff.a
                       1 |         org     $1000
1000: 86A55DE735       2 |         .float  -41.3417023
                       3 |         end

And adjusting the floating point constant until I got bytes that matched:

                         | FILE ff.a
                       1 |         org     $1000
1000: 86A55DE728       2 |         .float  -41.341702110
                       3 |         end

I figure it's “close enough.” The parsing code in the Color BASIC ROM is old and predates the IEEE-754 floating point standard, so a few different digits at the end I think is okay.

As a final check, I wrote the following bit of code to calculate and display -2π3/3!, display the pre-calculated result, as well as display the pre-calculated value of 2π:

		include	"Coco/basic.i"
		include	"Coco/dp.i"

CB.FSUBx	equ	$B9B9	; FP0 = X   - FP0	; addresses for
CB.FSUB		equ	$B9BC	; FP0 = FP1 - FP0	; these routines 
CB.FADDx	equ	$B9C2	; FP0 = X   + FP0	; from
CB.FADD		equ	$B9C5	; FP0 = FP1 + FP1	; Color BASIC Unravelled II
CB.FMULx	equ	$BACA	; FP0 = X   * FP0
CB.FMUL		equ	$BAD0	; FP0 = FP0 * FP1
CB.FDIVx	equ	$BB8F	; FP0 = X   / FP0
CB.FDIV		equ	$BB91	; FP0 = FP1 / FP0

CB.FP0fx	equ	$BC14	; FP0 = X
CB.xfFP0	equ	$BC35	; X   = FP0
CB.FP1f0	equ	$BC5F	; FP1 = FP0
CB.FP0txt	equ	$BDD9	; result in X, NUL terminated

		org	$4000
start		ldx	#tau		; point to 2*pi
		jsr	CB.FP0fx	; copy to FP0
		ldx	#tau		; 2PI * 2PI
		jsr	CB.FMULx
		ldx	#tau		; 2PI * 2PI * 2PI
		jsr	CB.FMULx
		jsr	CB.FP1f0	; copy fp acc to FP1
		ldx	#fact3		; point to 3!
		jsr	CB.FP0fx	; copy to FP0
		jsr	CB.FDIV		; FP0 = FP1 / FP0
		neg	CB.fp0sgn	; negate result by flippping FP0 sign
		jsr	CB.FP0txt	; generate string
		bsr	display		; display on screen

		ldx	#answer		; point to precalculated result
		jsr	CB.FP0fx	; copy to FP0
		jsr	CB.FP0txt	; generate string
		bsr	display		; display

		ldx	#tau		; now display 2*pi
		jsr	CB.FP0fx	; just to see how close
		jsr	CB.FP0txt	; it is.
		bsr	display
		rts

display.char	jsr	[CHROUT]	; display character
display		lda	,x+		; get character
		bne	.char		; if not NUL byte, display
		lda	#13		; go to next line
		jsr	[CHROUT]
		rts

tau		.float	6.283185307
fact3		.float	3!
answer		.float	-(6.283185307 ** 3 / 3!)

		end	start

The results were:

-41.3417023
-41.3417023
 6.23418531

The calculation results in -41.3417023 and the direct result stored in answer also prints out -41.3417023, so that matches and it reinforces my approach to this nominally right.

But I think Microsoft had issues with either generating some of the floating point constants for the larger terms, or transcribing the byte values of the larger terms. Take for instance -2π11/11!. The correct answer is -15.0946426, but the bytes in the ROM define the constant -14.3813907, a difference of .7. And it's not like Color BASIC can't calculate that correctly—when I typed in the expression by hand, it was able to come up with -15.0946426.

Or it could be that Walter K. Zydhek, the author of Color BASIC Unravelled II, is wrong in his interpretation of the expressions used to generate the values, or his interpretation of what the values are used for. I'm not sure who is at fault here.

Update on Friday, March 1st, 2024

I was wrong about the authorship of Color BASIC Unravelled II. It was not Walter K. Zydhek, but some unknown author of Spectral Associates, a company that is no longer in business. All Zydhek did was to transcribe a physical copy of the book (which is no longer available for purchase anywhere) into a PDF and make it available.


Discussions about this entry

Obligatory Picture

[The future's so bright, I gotta wear shades]

Obligatory Contact Info

Obligatory Feeds

Obligatory Links

Obligatory Miscellaneous

You have my permission to link freely to any entry here. Go ahead, I won't bite. I promise.

The dates are the permanent links to that day's entries (or entry, if there is only one entry). The titles are the permanent links to that entry only. The format for the links are simple: Start with the base link for this site: https://boston.conman.org/, then add the date you are interested in, say 2000/08/01, so that would make the final URL:

https://boston.conman.org/2000/08/01

You can also specify the entire month by leaving off the day portion. You can even select an arbitrary portion of time.

You may also note subtle shading of the links and that's intentional: the “closer” the link is (relative to the page) the “brighter” it appears. It's an experiment in using color shading to denote the distance a link is from here. If you don't notice it, don't worry; it's not all that important.

It is assumed that every brand name, slogan, corporate name, symbol, design element, et cetera mentioned in these pages is a protected and/or trademarked entity, the sole property of its owner(s), and acknowledgement of this status is implied.

Copyright © 1999-2024 by Sean Conner. All Rights Reserved.