HP12C+ Modding Assets

This page is still under construction…

1. General Info

Hardware information: Known Revisions and Their Modding Potentials:

(An addendum for http://www.brouhaha.com/~eric/hpcalc/voyager/variants.html )

Older 12C Versions: 3 x LR44 or 1 x CR2032, Injection Molded Keyboard, Nut processor, not moddable.

12C+ Rev.1: Gold, New Keyboard Mold with printed lettering, Elongated %-symbol, 2 x CR2032 Cells, Revised but apparently the same LCD,  AT91SAM7L SoC with ARM7TDMI Processor.

12C+ Rev.2: Identical to Rev.1. but with “Rev.2” tucked somewhere in the labels on the back. SAM4LC2C SoC with ARM Cortex-M4 Processor, With USB footprint on the PCB.

12C+ Rev.2: Later Revision, Identical to Rev.1. but with “Rev.2” tucked somewhere in the labels on the back. SAM4LC2C SoC with ARM Cortex-M4 Processor, no USB footprint on the PCB.

12C+ Anniversary Edition: I don’t own, AT91SAM7L SoC with ARM7TDMI Processor.

15C Limited Edition: I don’t own, AT91SAM7L SoC with ARM7TDMI Processor.

12C Platinium: Silver Color or Silver+Black, New HP Logo, New LCD Design, Mask-ROM 6502 SoC, not moddable.

2. Hardware

Rev. 1 SDK:

2.1. 12C+ Rev 1 & 2 Display Mapping:

Rev. 2 LCD panel (and wiring) is identical to that of Rev. 1.

The LCD is controlled entirely and automatically by the LCDC peripheral built into the SAM4LC SoC.

… More info coming soon …

2.2. 12C+ Rev2 Keyboard

Keyboard code snippet for rev2, converting the keyboard readings to Nut Keycode:

//     1  2  3  4  5  6  7  8  9  0
// 1 - 13 33 73 c3 83 82 c2 72 32 12
// 2 - 10 30 70 c0 80 87 c7 77 37 17
// 3 - 11 31 73 c1 81 84 c4 74 34 14
// 4 - 18 38 78 c8 88    c5 75 35 15
//
//
//                           0     1     2     3     4     5     6     7     8     9     10    11    12    13    14    15    16
const uint8_t KBB_kclut[] = {0x00, 0x10, 0x30, 0x00, 0x70, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, \
                                   0xC0, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
const uint8_t KBB_krlut[] = {0,0,3,2,0,7,1,4,8,5};

// ....
		GPIO->GPIO_PORT[2].GPIO_ODERC = BIT(3)|BIT(4)|BIT(5)|BIT(6);
		GPIO->GPIO_PORT[2].GPIO_ODERS = BIT((2+i));
		delay_us(1);
		uint8_t t_PA = GPIO->GPIO_PORT[0].GPIO_PVR;
		uint8_t t_PB = GPIO->GPIO_PORT[1].GPIO_PVR;
		uint8_t t_PC = GPIO->GPIO_PORT[2].GPIO_PVR;
		scancode = ((~t_PC&BIT(7))>>3)|((~t_PA&BIT(7))>>4)|((~t_PB&0x30)>>3)|(~t_PB&BIT(0));
		if(scancode) {
			scancode = KBB_kclut[15+scancode]|KBB_krlut[(i<<1)];
			break;
			} else {
			scancode = ((~t_PB&0x04)<<2)|(~t_PB&0x08)|(~t_PC&0x07);
			if(scancode) {
				scancode = KBB_kclut[scancode]|KBB_krlut[(i<<1)+1];
				break;
			}
		}
// ....
Long-Press for Command Catalog? You bet!

2.3. HP Nut 12C Display Implementation (RAM-ROM-Display-Driver aka. R2D2):

It seems that the detail of this display chip is first discovered using HP15C synthetics programming.

Display Mapping in Register 9 & 10 [http://www.brouhaha.com/~eric/hpcalc/]

But the numbering for each decimal digit is different due to the difficulty of LCD wiring. A better way to look at this is to read the implementation in the source code of the Nonpareil emulator.

However, that implementation has a serious flaw: the letter “r” can sometimes be shifted upwards (as seen in “Pr Error” vs. “running”) on the original device. This behavior is not modeled in Nonpareil, and this discrepancy can also be found in any microcode emulator out there. You can also use this discrepancy to differentiate an emulator (runs the original microcode) from a simulator (simulates the original behavior but doesn’t use the original code)

To this day we still don’t know how R2D2 actually works, maybe we need to dig deeper into the binary of 12C+ to find the answer (Thumb assembly is not that easy to read anyway), or decapping an original chip. Maybe that data is stored in some of the unused areas of reg9 & 10, I’m not sure.

Here’s my Z80 Implementation of the display decoding routine: Converts R2D2 Data to 7-seg For Rendering.

	; A: Intermediate
	; B: Position Counter
	; C: Intermediate
	; D: OH Counter
	; E: Byte Emitter
	; HL: lcLCDD pointer holder
	; IY: register 9~10 pointer holder
	; IX: Unused
	PUSH IY
	LD D, 1
	LD B, 0
	LD IY, lcLCDD
_seg_loop:
	; LD HL, rlcREG9
	LD  HL, lcTest
	LD  A, (HL)
	ADD A, L
	LD  L, A
	XOR A
	ADC A, H
	LD  H, A
	LD  C, (HL)			; BCD digit is extracted into C
	INC IY
	LD  A, (IY)			; Bit Pattern in A
	AND A, C			;
	JR  Z, _skip_seg 	; No bit, or
	LD  A, D			; Scan Hit, Emit Bit
	OR  A, E			; |
	LD  E, A			; /
_skip_seg:
	LD A, D				; Increase OH counter
	SCF					; |
	CCF					; |
	RLA					; |
	JR  C, _digit_done	; Overflowing, the working 8-bit pattern is done	
	LD  D, A			; Otherwise continue to work on the current digit
	JR  _seg_loop		;
_digit_done:			; E contains the finished 8-bit pattern
	LD  A, E
	POP HL
	CALL draw7Seg
	INC HL
	PUSH HL
	INC B
	LD  A, B
	CP  A, $10
	JR  Z, _done
	JR  _seg_loop
_done:
	POP IY
	RET
	
	
	
	
lcTest:
	.db $00, $08, $02, $02, $0E, $0F, $0F, $0F, $0F, $00, $0F, $0F, $0F, $03 
	.db $00, $08, $0F, $0B, $0C, $0F, $0C, $0F, $08, $08, $02, $00, $0C, $0C

lcBitPat:
	.db $01, $02, $04, $08, $10, $20, $40, $80
	
	; Register 9 and 10 are combined into one
	; Digits
lcLCDD:
;       A        B        C        D        E        F        G        H
	.db  $0, $0,  $0, $0,  $0, $0,  $0, $0,  $0, $0,  $0, $0,  $0, $0,  $0, $0; -
	.db  $5, $2,  $5, $8,  $4, $8, $11, $8,  $4, $4,  $5, $1,  $5, $4,  $9, $8; *
	.db  $6, $8,  $7, $2,  $6, $2,  $4, $2,  $6, $1,  $6, $4,  $7, $1,  $3, $8; U
	.db $12, $8, $13, $2, $12, $2,  $3, $2, $12, $2, $12, $4, $13, $1, $13, $8; f
	.db  $8, $2,  $8, $8,  $7, $8,  $2, $2,  $7, $4,  $8, $1,  $8, $4,  $9, $2; g
	.db $10, $8, $11, $2, $10, $2,  $1, $8, $10, $1, $10, $4, $11, $1,  $2, $8; B
	
	.db $16, $8, $17, $2, $16, $2, $17, $8, $16, $1, $17, $4, $17, $1, $18, $2; G
	.db $19, $2, $19, $8, $18, $8, $15, $8, $18, $4, $19, $1, $19, $4, $20, $1; R
	.db $21, $2, $21, $8, $20, $8, $23, $8, $20, $4, $21, $1, $21, $4, $23, $2; D
	.db $25, $8, $26, $8, $25, $2, $22, $2, $25, $1, $25, $4, $26, $1, $22, $8; C
	.db $27, $2, $27, $8, $26, $8, $24, $2, $26, $4, $27, $1, $27, $4, $24, $8; P
	; Commas
	; Added separately after the digits are done
	; Reduces the 7seg-to-bitmap LUT to 128 entries
lcLCDC:
;       H (Dot)  I (Tail)
	.db  $0, $0,  $0, $0 ; - Always disabled
	.db  $9, $8,  $9, $4 ; *
	.db  $3, $8,  $3, $4 ; U
	.db $13, $8, $13, $4 ; f
	.db  $9, $2,  $9, $1 ; g
	.db  $2, $8,  $2, $4 ; B
	
	; The lower half is saved for another day.
	

	; Annunciators
	; Probably hardcode this part
lcLCDA:
	.db  $0, $0 ; 
	.db  $0, $0 ; * is hardware controlled
	.db  $4, $1 ; USER
	.db  $3, $1 ; f
	.db  $2, $1 ; g
	.db  $1, $4 ; BEGIN
	.db $17, $4 ; G.
	.db $15, $4 ; RAD
	.db $21, $4 ; C
	.db $24, $1 ; PRGM

3. Flashing 10C, 11C, 16C ROM