You are on page 1of 10

CODE 8032 IN MTK1389 FIRMWARE

Contents Preface Banking mechanism Runtime routines Startup VFD interface I2C interface EEPROM interface FLASH interface Remote controller interface ARM processor interface OSD interface ARM memory

Preface
To study the 8032 code one should read application notes at www.keil.com/c51 and elsewhere on the web, about the C51 compiler and runtime. A51 assembler and BL51, the Banked Linker. Knowledge of Intel series 8051 processor is needed. Tools of interest are: disassembler (D52, IDA,...) , Hex-editor (ultra-edit,..). This is just a personal study project to learn about the processor and C programming language. Dont expect it to be error free. Use it on your own risk. lisatv october 2004 lisatv_ (at sign) hotmail.com Thanks to Casimir, MaB, Cachirulo, Camomille .. This note comes with Names.xls and Port8032.xls. Examples shown are from Yamada DVX6600 beta 2 firmware. Other MTK1389 firmwares have the same construction , but addresses differ. Other , minor, differences are: 1) VFD chip type 2) Size/Type of Flash memory 3) Remote controller 4) Version of the MT1389 chip .. The 8032 coding part of the firmware is from address 0 to address in location 200,201,203 minus 1. From Zdvx6600.bin:
00000200h: 04 B6 04

8032 code is from address 0 to address 4B603.

Banking mechanism.

The 8032 processor has 16 address lines, to address 64KB program space.. For disassembling the 8032 part must be divided into 64KB pages. Address from-to 0x00000-0x0FFFF 0x10000-0x1FFFF 0x20000-0x2FFFF 0x30000-0x3FFFF 0x40000-0x4B603 size 0x10000 0x10000 0x10000 0x10000 0x0B604 name bank0.bin bank1.bin bank2.bin bank3.bin bank4.bin

To transfer over the 64KB border 3 extra address bits/lines are used, P1.0, P1.1 and P1.2. Max code space is 2 exp 3 = 8 times 64KB = 512KB. To support this the module L51_bank.A51 must be configured:
?B_NBANKS P1 ?B_PORT ?B_FIRSTBIT EQU DATA EQU EQU 8 90H P1 0 ; ; ; ; Define maximum Number of Banks I/O Port Address default is P1 default is Bit 0

Bank Transfer Routines (BTR) (in module L51_bank.A51) ?B_BANK0 to ?B_BANK7 push the transfer address on the stack, load P1.0, P1.1 and P1.2 with the desired bank number and then do a RET, which jumps using a 19 (16+3) bit address. The source of the 8032 part is probebly a Common.c module, and bank0.c till bank4.c. Common is linked into every bank, the others are tied to their executable, bank0.c to bank0.bin etc. If one bank module calls a subroutine in another, the linker will insert it into the Bank Transfer Table (BTT). An entry of this table looks like:
ROM:02F5 ROM_2F5: ROM:02F5 ROM:02F8 mov ljmp DPTR, #0x38C0 ?B_BANK3

The BTT is present in every executable bank. E.g. lcall ROM_2F5, no matter where, will transfer to 0x338C0. Many firmwares have a BTT with 596 entries.

Runtime routines
The 8032 is a 8 bit processor. Manipulation of bigger objects (int, long, pointer,..) needs a library routine. (IMUL,LMUL, IDIV.LDIV, PLDxxx pointer load, PSTxxx pointer store). When case arguments are unstructured, library calls CCASE,ICASE,LCASE are used. And many more. IDA disassembler will recognise the runtime routines if the appropriate signature files are loaded. Some signature files can be found on MTK and Divx player forums.

Some library calls have inline data, U need to know when disassembling code or data, ?C?CASE,?C?ICASE,?C?LCASE: Following lcall ?C?.CASE is a jump table. For CCASE (char): 2 byte transfer address, 1 byte value For ICASE (int): 2 byte transfer address, 2 byte value For LCASE (long): 2 byte transfer address, 4 byte value All end with double zero followed by default transfer address. Data following LSTKXDATA and LSTKIDATA calls is 4 bytes.
ROM:6BF5 ROM:6BF8 ROM:6BFB ROM:6BFC ROM:6BFD ROM:6BFE ROM:6BFF code ... mov DPTR, #0xFBA6 lcall ?C?LSTKXDATA .byte 0 .byte 0 .byte 0xE .byte 0xA6

This translates to:

xdata long xramFBA6; XramFBA6 = 0x00000EA6;

There are a few float numbers in the firmware, near the lcalls of ?C?FPSUB, ?C? FPMUL, ?C?FPCMP. The floats are 4 bytes, loaded into R0 till R3. R3= C5 9A AE 00 R2= 34 99 47 00 R1= D1 D9 85 02 R0= 40 3F 41 43 float= 6.5376915 1.7 16.66 130.0

Startup.
In headlines: address 0 of every bank jumps to label STARTUP1 of the STARTUP.A51 module. This one jumps to the ?C_START label in the INIT module. The last part of INIT jumps to the main procedure.
ROM:0000 ROM:22B6 STARTUP1: ROM:22B6 ROM:22B9 ... more ... ROM:22E4 ROM:22E7 ROM:22EA ljmp mov movx mov mov ljmp STARTUP1 DPTR, #0xF86C A, @DPTR P2, #0xF9 SP, #INTMEM_AA ?C_START

ROM:2328 ?C_START: ROM:2328 ROM:232B ROM:232B ROM_232B: ROM:232B ROM:232B ROM:232C ROM:232E ROM:232F ROM:2331 ... more ... ROM:2586 ROM_2586: ROM:2587 ROM:2588 ROM:2589 ... more ... ROM:22ED ROM_22ED: C_START+7 ROM:22ED

mov

; CODE XREF: ROM:22EA DPTR, #ROM_2586 ; CODE XREF: ROM:2300 ; ROM:231E

clr mov movc jz inc

A R6, #1 A, @A+DPTR ROM_22ED DPTR ; DATA XREF: ?C_START

.byte 0x41 .byte 0xFC .byte 0x20 .byte 0

; CODE XREF: ? ljmp ROM_10E1

Above we see: startup vector at address 0: jmp to STARTUP1 in STARTUP.A51 module. This module is user written. Copy the assembler source from label STARTUP1 till ljmp ?C_START and put it in file STARTUP.A51. Then we jump to ?C_START. This is the INIT module, the Linker will insert it. The table at ROM_2586 (?C_INITSEG) is used to initialize internal and external RAM. The first entry (0x41,0xFC,0x20,0x00) decodes as xramFC20 = 0;. When the table is done the jz ROM_22ED is taken. Then ljmp ROM_10E1 will jump, thru the BTT, to the main procedure. Every executable bank has a copy of Startup vector, STARTUP module, INIT module and table. There is only one main. For Yamada 6600 main is in bank0, address CA62.
ROM:10E1 ROM_10E1: ROM:10E1 ROM:10E4 mov ljmp ; CODE XREF: ROM:22ED DPTR, #0xCA62 ?B_BANK0

VFD interface
VFD = Vacuum Fluoricent Display , on the front of the player. Some players have complete subsystems to do this task. For simplicity i still call them VFD interface. This interface uses 3 lines CLK, CS, DI/DO for the VFD signals: 1) Clock , 2)Chip select and 3) Data in/Data out. Port8032.xls shows which port is which line.

Basic VFD tasks: 1) display a string (predefined strings are in table VFD_CharString) 2) light a symbol 3) scan the buttons on the player Display a string On the lowest level we have void VFD_Write(unsigned char). It sends a byte to the VFD, byte can be commands, address, data. A character on the VFD is made up of 7 segments. a f g e d A byte = 8 bits: b7=0, b6=seg g, b5=seg f, b4=seg e, b3=seg d, b2=seg c, b1=seg b, b0=seg a. The character table (VFD_CharSet) in the Yamada firmware:
Bits 00111111 01011011 01100110 01111101 01111111 00000000 01111100 01011000 01111001 01101111 00110000 00111000 00111111 01100111 01101101 00111110 01101110 10110110 00000000 01011100 Hex 3F 5B 66 7D 7F 00 7C 58 79 6F 30 38 3F 67 6D 3E 6E B6 00 5C Char Char# 0 00 2 02 4 04 6 06 8 08 space 0A b 0C c 0E E 10 g 12 I 14 L 16 O 18 q 1A S 1C U 1E y 20 | | 22 space 24 sqr 25 Bits 00000110 01001111 01101101 00000111 01101111 01110111 00111001 01011110 01110001 01110110 00011111 00110111 01110011 01010000 01111000 01100110 00001000 10001100 00000000 Hex 06 4F 6D 07 6F 77 39 5E 71 76 1F 37 73 50 78 66 08 86 00 Char Char# 1 01 3 03 5 05 7 07 9 09 A 0D C 0D d 0F F 11 H 13 J 15 n 17 P 19 r 1B t 1D 4 1F _ 21 | 23 space 24

Light a symbol

These are symbols like DVD, the rotating disk, Send to the VFD: Display-led-command and the led-bits. Routine: VFD_WriteLed. Scan the buttons First write scan keys command (0x42) to the VFD Scan keys in a loop of 24 times. If a button is pushed, the loop number is the button number. Button value = VFD_ButTab[button number] Routine: VFD_ScanBut. VFD_ButTab is at 0x42ACD:
5C 16 5D 15 14 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF

How to find VFD_ButTab. Look for this instruction sequence


ROM:9C66 ROM:9C68 ROM:9C69 ROM:9C6B ROM:9C6C ROM:9C6E ROM:9C6F ROM:9C72 ROM:9C75 ROM:9C76 clr nop clr nop setb nop jnb jb mov mov P1.3 P1.3 P1.3 P1.5 or P1.4, ROM INTMEM , ROM A, R7 DPTR, #ROM_XXXX C2 00 C2 00 D2 00 .. .. EF 90 93 93 93 .. .. .. .. XX XX

The VFD_ButTab is at address XXXX in the same bank as these instructions.

I2C interface
The I2C protocol is used to access the EEPROM and in some firmwares the Audio DAC. I2C is a serial interface using 2 i/o lines (P1.6, P1.7). The basics of this protocol (find a full description on the web) are 1) start sequence 2) identification and read/write mode 3) address & read/write a byte 4) acking/nacking and 5) stop sequence. Prototypes: bit I2C_Start(unsigned char) bit I2C_Write(unsigned char) void I2C_Read(unsigned char *) void I2C_Stop(void); bit I2C_GetChar (unsigned char, unsigned char, unsigned char) bit I2C_PutChar (unsigned char, unsigned char, unsigned char)

The I2C address identifies the other side of the I2C session. For EEPROM this is 0x50, for Audio DAC 0x10. Input to I2C_Start is the I2C address (7 bits) plus the read/write bit. I2C_Start() Who How 0x20 Audio DAC Write 0x21 Audio DAC Read 0xA0 EEPROM Write 0xA1 EEPROM Read

EEPROM interface
A small EEPROM is used to store preferences. It stores 128 bytes, addresses 0x00 to 0x7F. The 8032 code has a table with initial preferences , they are written to the EEPROM. At 0x129DA for Yamada:
00 00 00 00 D4 80 98 DE 00 00 00 00 0A 18 3C 00 1B 1B 1B 1B E0 80 A0 80 00 00 00 00 7E 7C 7D 7F 00 00 00 00 E0 DE DF E1

FLASH interface
The current FLASH memories are 1 MB and 2 MB in size, bigger ones are foreseen At firmware update coding and data are flashed into it. To address the Flash, bits of location xramF86C are used. xramF86C bit 0 = A16, bit 1 = A17 , bit 2 = A18 , bit 3 = A19, bit 4 = A20 ... Port P3.2 triggers the flash memory into flash mode. The FLASH_Upgrade procedure in short: first a Chip erase is done, then many bytes are flashed. Finally FLASH_Reset which will do ljmp 0000 to start executing from the just flashed coding. Prototypes: FLASH_Upgrade FLASH_Erase FLASH_Program FLASH_Reset Most flashes are erased/programmed in 16 bits mode, a few in 8 bits mode.

Remote Controller interface


The remote controller (RC) has keys, which are numbered. After an external interrupt, the

key number is available to the 8032 processor, in a byte. First thing is convert key number to key value using a table in 8032 coding. Then invoke the appropriate procedures. The RC key numbers and key value tables (RC_Tab) are very different among players. RC_Tab starts (the ones I have seen) at 0x01471 and goes on till U encounter ASCII string MT.
00001471h: 00001481h: 00001491h: 000014a1h: 33 29 FF 1B FF 01 4E 30 19 05 FF 2C 2E 06 FF FF 3D 28 FF 0D 18 04 FF 0A 37 08 FF 34 17 09 FF FF 50 2B 38 16 14 07 1A 0E 15 00 3B FF 23 22 FF FF 5B 4F 20 0F 5C 60 5E 10 02 FF FF FF 03 52 FF FF

The numeric keys 0 til 9 decode to values 0x00 til 0x09. The 2 bytes before RC_Tab, at 146F and 1470 (0x04,0xFB) is the RC indentifier! (RC_Id). At address 0006 of every bank is the password for Parental Control (4 or 5 digits).

ARM processor interface


Communication with the ARM processor is done thru dedicated memory locations. XramLoc F860 F861 F862 F863 F864 Name ARM_syn ARM_com ARM_adh ARM_adl ARM_data Purpose Sync bit 5 = 0 = ARM is ready to work Command Address high Address low Data byte

Read ARM memory: Unsigned char ARM_GetChar (unsigned int) Input is int address of location to read, return char , the contents of that location + 0xC400 Routines ARM_GetChar1C, ARM_GetInt1C, ARM_GetLong1C will read a char, int or long using ARM_GetChar but with an extra address offset of 0x1C00. Write ARM memory: Void ARM_PutChar(unsigned int, unsigned char) Write char into location int + 0xC400 Routines ARM_PutChar1C, ARM_PutInt1C, ARM_PutLong1C will write a char, int or long using ARM_PutChar but with an extra address offset of 0x1C00.

OSD interface
The data for the OSD is in Data Part OSD Block OSD 2 Languages of the firmware. This is a collection of OSD strings numbered from 0. For Yamada beta 2 from 0x0000 till 0x042E. This string number is used in the 8032 coding to identify a OSD string, this is a direct relation!. Look at the OSD_xxxx routines in Names.xls.

ARM memory
The 8032 processor sees (at least) 2 memory areas: Area A Read by ARM_GetChar, write by ARM_PutChar These routines add 0xC400 or 0xCC00 to all addresses, depending on the firmware. 0xC400 in Yamada6600, Amstrad3016, HB3220, 0xCC00 in Nevir, Area B Read by ARM_GetChar1C, ARM_GetInt1C and ARM_GetLong1C. Write by ARM_PutChar1C, ARM_PutInt1C and ARM_PutLong1C. This area has an offset of 0x1C00 to area A. Address Area A: ======== 0x0013 Start ARM address ARM_StartARM 3 bytes
0x0013 contents of 0x0202 in the firmware 0x0014 - contents of 0x0201 in the firmware 0x0015 - contents of 0x0200 in the firmware

Comment Name - Size

0x0081

0x00 0x02 0x03 0x04 0x05 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x11 0x12

Disk format ARM_DiskType 1 byte


DVD-Video MiniDVD VCD 3.0 VCD 2.0 VCD 1.1 SVCD CVD CD HDCD DTS CD CD-G KODAK Picture CD SACD (Nevir) SACD (Yamada)

0x00C3
0x00, 0x03 0x04, 0x05, 0x06 0x08, 0x0B 0x0C 0x0F 0x10

Number of Audio channels ARM_ NbAudioCh - 1 byte


0x01, 0x02 0x09 0x0A 0x0E 1CH 2CH 3CH 4CH 2.1CH 4.1CH 5CH 6CH 5.1CH 6.1CH

0x00C6
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x09 0x0A

Audio format ARM_AudioFormat 1 byte


MPG DTS LPCM / PCM Dolby Digital / AC3 SDDS MP3 WAV HDCD AAC

0x03E0 0x03E8 0x03F0 0x03F4 0x04E0 0x0500 Area B: ========

Version ARM_Version 4 bytes 8032 Version ARM_8032Version 4 bytes Servo Version ARM_ServoVersion 4 bytes Sub Version ARM_SubVersion 4 bytes Firmware Id ARM_FirmId x bytes, until null char Firmware FileName ARM_FirmFile x bytes, until null char

(to be continued)

You might also like