Author Topic: 3478A cal RAM readout idea  (Read 11665 times)

0 Members and 1 Guest are viewing this topic.

Offline wolfalex

  • Regular Contributor
  • *
  • Posts: 81
  • Country: at
    • My hobby electronics website
Re: 3478A cal RAM readout idea
« Reply #25 on: June 27, 2015, 04:18:41 am »

I have already learned that the 8048 can adress 4K of ROM by using 2 different pages. But the ROM is twice as big, and the adress bit A12 is controlled with a line on port2.
Does the firmware of the 3478A in normal run mode use all 8k of ROM for program execution?

Technically it should be possible that the firmware changes the level on A12 via a P2 port write, and then it does simply a JMP to the new target adress in the upper ROM area, or?
The CPU would not know that it actually executes from another memory area, but in this way probably the useable program memory was increased.

Could this be? I was just wondering how much program code is stored in the area between 4k and 8k when I looked at the disassembly results from the 3478A firmware.

Offline Sailor

  • Regular Contributor
  • *
  • Posts: 170
Re: 3478A cal RAM readout idea
« Reply #26 on: June 27, 2015, 11:53:42 pm »
Terminology - the 2k segments of a 'standard' 4k program memory address space are called banks. A page is a 256-byte segment of the address space.
Blocks are selected by the SEL MB0 and SEL MB1 instructions. Those instructions merely set or clear a flop that they somewhat euphemistically call 'bit 11 of the program counter'. It isn't really a part of the PC, it's simply a bank-select flop. Importantly, it only comes into play during JMP and CALL instruction execution - you can set or clear it whenever and as many times as you like while executing 'normal' code without it having any effect whatsoever. Pages are accessed via the MOVP and MOVP3 instructions. These limited addressing capabilities mean that you need to get fairly creative when writing a large program.

The use of the Port 2 bit to provide additional addressing range is dramatically different. The 8039/8048 architecture does not have any knowledge of such a feature, so it isn't a case of 'and then it does simply a JMP to the new target adress in the upper ROM area'. A change of the ROM address bit 12 by writing to Port 2 causes an instantaneous transfer of control to the other 4k memory segment at the address following the instruction that altered Port 2. i.e. you don't have a choice of a destination address like you do in a normal JMP or CALL. This means that you need to guarantee the placement of your code in the 'other' 4k bank is such that program execution continues in the manner that you expect. These same considerations apply when / if you want to return to the original code, which is why you will generally see the following sort of construct:

Assume  we are in the lower 4k region

0x345    ORL P2, #0x40                  ;set address bit 12
0x347    NOP
0x348    xxx                                    ;code continues after returning from upper 4k

In the upper 4k region we see

0x345    ANL P2, #0xbf                   ;clear address bit 12
0x347    NOP
0x348    xxx                                    ;code to be executed in upper 4k

             JMP 0x345                          ;go clear address<12> and 'return' to lower 4k region

Of course, there is no particular reason why a routine in one region should 'return' to carry on in the other region, and you will see examples where the code in one region is obviously crafted to expect 'jumps' to arrive from anywhere, be it from the same region via a JMP, or from the other region via address<12> manipulation.

Another thing that must be kept in mind while working like this is that the Bank-Select state transfers (i.e. continues) when swapping regions, and furthermore the stack contents (which also include the Bank-Select bit) continue to be in play, so that if a RET/RETR is executed in the 'other' region, it will transfer control to the appropriate address of the upper or lower bank within that region. So, once again, your code must be placed correctly to ensure that things work as planned.

It's messy!


Offline wolfalex

  • Regular Contributor
  • *
  • Posts: 81
  • Country: at
    • My hobby electronics website
Re: 3478A cal RAM readout idea
« Reply #27 on: June 28, 2015, 12:14:58 am »

Thank you so much for the time you spend explaining this in detail to me. I must confess I have not really used assembler much in my live (instead I use C on microcontrollers on a daily basis). But I still think that I can read an assembler program and that I bascially know what it does and why.

After dissassembling the 3478A ROM and my first looks at the output listing I must say that the whole code looked really strange to me... random single NOPs between a long list of "normal" commands, and then weird JMP commands all over the place. I think after knowing now how much black magic the had to use to increase the program space and to
make it work on the 8039 (which I also do not know much yet) I also understand now why the assembler code looked so strange to me.

Now I also know why the emulator jumped just weirdly through the 3478 firmware :) It has basically no chance to run through the program normally.

How were you able to locate the ROM checksum routine in the disassembler listing? Yesterday I tried to locate the place in the firmware where the LCD communication takes place and it was very difficult to do so.

Offline Sailor

  • Regular Contributor
  • *
  • Posts: 170
Re: 3478A cal RAM readout idea
« Reply #28 on: June 28, 2015, 12:56:10 am »
I'll be busy for the next 6 hours or so. Then I will show you the reasoning that led me to the checksum routine in the 3468, then how it is different in the 3478. In the meantime, try and think about what the routine has to do, and (given the limited addressing capabilities of the 8039) how it might achieve it.

Offline wolfalex

  • Regular Contributor
  • *
  • Posts: 81
  • Country: at
    • My hobby electronics website
Re: 3478A cal RAM readout idea
« Reply #29 on: June 28, 2015, 04:40:38 am »
My thought process is the following: I learnt two commands are for program memory access: MOVP and MOVP3.
MOVP3 seems to allow access to page 3 of the program memory.. but that means it can not access all of program memory if I am not wrong.
So it is not useful for this purpose.

so this leaves only the MOVP command... but the problem is MOVP only allows to access  program code in an area of one page around
the current program counter value. So this is a big limitation.

Initially I was searching for a construct with for-loops and a single read program memory command which access all of ROM.....
like I would do it in C. But now given the limitations of MOVP I actually think the only way to achieve the checksum over the whole ROM is
to split and spread the checksum calculation routine over the whole ROM (each page must contain one part of the routine).
And then each part of the routine has a jump command to the next part. 

I think the following codes parts take part in the ROM checksum calculation: (3 example blocks)

00FC : FF      " "      mov   a,r7
00FD : A3      " "      movp   a,@a
00FE : 7E      "~"      addc   a,r6
00FF : AE      " "      mov   r6,a
0100 : FF      " "      mov   a,r7
0101 : A3      " "      movp   a,@a
0102 : 7E      "~"      addc   a,r6
0103 : AE      " "      mov   r6,a
0104 : 44 FC      "D "      jmp   L02FC

02FC            L02FC:
02FC : FF      " "      mov   a,r7
02FD : A3      " "      movp   a,@a
02FE : 7E      "~"      addc   a,r6
02FF : AE      " "      mov   r6,a
0300 : FF      " "      mov   a,r7
0301            L0301:
0301 : A3      " "      movp   a,@a
0302 : 7E      "~"      addc   a,r6
0303 : AE      " "      mov   r6,a
0304 : 84 FC      "  "      jmp   L04FC

04FC            L04FC:
04FC : FF      " "      mov   a,r7
04FD : A3      " "      movp   a,@a
04FE : 7E      "~"      addc   a,r6
04FF : AE      " "      mov   r6,a
0500 : FF      " "      mov   a,r7
0501 : A3      " "      movp   a,@a
0502 : 7E      "~"      addc   a,r6
0503 : AE      " "      mov   r6,a
0504 : C4 FD      "  "      jmp   L06FD

as can be seen one block jumps to the next block. you also wrote that the checksum is done by adding up to a sum, and also that the carry is added to the next byte.
So after the movp is an addition which fits to your description. Simular blocks like above can also be found at other program memory locations.

But unfortunetly I am not able right now to see the big picture, i mean I do not know where the routine starts and where it actually ends.
It is pretty complicated to try and find the red line through the code. And I am also not sure if there are actually enough blocks like above to reach all parts of the ROM.
I also tried to search for "OUTL P2, #0BFH" commands to alter A12, but there are to many to use them as an orientation point.

Am I on the right track with my assumptions? I can not wait to read your answer and to see if I am correct or not. Unfortunetly I have to go to bed now and I will only
be able to answer again in 8 hours... it seems we are maybe in different time zones :(

Thank you very much again for your insight, it makes a lot of fun to go through the code and try to find the things you describe or point out.

Offline Sailor

  • Regular Contributor
  • *
  • Posts: 170
Re: 3478A cal RAM readout idea
« Reply #30 on: June 28, 2015, 08:38:46 am »

Very good, Alex. As you surmise, the code has to be distributed, and you have done well to identify the method so quickly. I said earlier that I would show you the way the 3468A did it, and the differences to the 3478A. But I'm not going to keep my end of the bargain (at least, not just yet), and I'll tell you why.

I have been writing assembler (and other languages) for mainframes, minis, and micros since the mid-1960s, and I strongly believe that EEs should have a good background in the real nut'n'bolts of embedded micros. Unfortunately, it seems to be a dying art, so when someone shows not only interest, but also ability, I want to encourage them.

To that end:
Doing is 1000 times better than being shown.
Doing and succeeding is extremely satisfying.
Doing promotes remembering.

So, getting back to the questions:

I am not able right now to see the big picture, i mean I do not know where the routine starts and where it actually ends.

You obviously have a disassembler that produces a usable file. And an editor with search capabilities. And you have identified a string of code-segments that are connected by JMPs. The last of those segments ends with a ???
So, how did the first segment get executed?
How much of the memory did one execution of these code segments cover?
What is the significance of r7?

When you have the checksum routine sorted out (I don't think it will take you long), I think you will find it both interesting and instructive to trace the first ~ 100 instructions (and their subroutine calls, etc) following a RESET. Code execution begins at the start of the upper 4k of ROM.

BTW, what disassembler are you using?


Offline wolfalex

  • Regular Contributor
  • *
  • Posts: 81
  • Country: at
    • My hobby electronics website
Re: 3478A cal RAM readout idea
« Reply #31 on: June 28, 2015, 05:58:24 pm »

 Sorry for the late answer, but my 7 month old daughter uses most of my freetime now :) I used a program called "DASMx" Version 1.4 from Conquest Consultants I found online for the disassembly.

I also attached the result I got to this email if somebody is interested.

Thank you for your nice words. Without your hints it would also most likely have taken way longer to find the ROM checksum parts (because I would not have expected that this code is distributed over the whole code). Thanks to you I also now know that the program starts in the higher 4k of ROM. I completely forgot that A12 is high after uP reset, and that this actually means execution does not start in the lower 4k. Until now I always started to read the firmware from the wrong adress :) (this explains also why it did not make sense at all).

I will take the new information and look again at the firmware in the next hours when I have more time. And I will try to look at the first 100 instructions as you have pointed out. Will be very interesting.
What I would like to achieve at the end is to find the RAM checksum calculation in the firmware.

I agree on your points made about programmers/EE today concerning uC. What I see every day is that there seems to be 2 groups of programmers out there: one (like me) which handles the uC from the EE point of view: bits, switches, logic gates, timing: If I use a functional block for example I start with the description from the block in the datasheet, then I write an init routine to set every needed bit in the block, and then I go from there...

The other group comes more from the PC side of things, and the often start using some sort of libraries or finished routines. And I guess the often do not start with the functional diagram of the block itself, or the do not really care about the bit level/circuitry so much.

For me I prefer option one. For me it is fun to understand the blocks more in detail and use them from scratch. And I also think this leads to much better/more reusable code in most of the cases.

Offline Sailor

  • Regular Contributor
  • *
  • Posts: 170
Re: 3478A cal RAM readout idea
« Reply #32 on: June 29, 2015, 02:10:38 am »
To all those who may be interested, and who may be able to offer some insights, here is the format of the data contained in the 3478A Cal RAM. The attached image is a dump of data kindly provided by MarkL :-+ . Starting from offset 01 there are eighteen 13-byte (nibble) records, with the first few plus the last one outlined. Each record consists of 11 nibbles of data plus two nibbles which are concatenated to form an 8-bit checksum. Note that these two are presented in the order most-significant _ least-significant nibble e.g. the 8-bit checksum of the first record is 0xd2 (and there is no funny 'carry' as in the ROM checksums).

I do not know the significance of the data values - at a guess, I would suspect they are ADC count errors, but... :-// There are a number of questions surrounding them; are they signed values (doesn't allow much range)? Why eleven values? Why eighteen records? Given the number of functions to be calibrated (DCV, ACV, DCA, ACA, and Ohms), and the number of points at which those functions are calibrated, I don't see how it ties up. Furthermore, the method of referencing the records is odd. In the main ROM there is a table of the offsets of records in the Cal RAM, despite the fact that the records are of a known size at known, computable, locations. Added to that is that the ROM table is 50 elements in size, quite a few of which are zero (denoting a non-record), and several of which are duplicates. The table is shown below (I have added decimal equivalents for the RAM offset values because I inadvertently displayed decimal offsets in the WinHex image).

R        R
O       A
M       M

A       O
d       f
d       f
r        s
e       e
s       t
0e0f - 00       0
0e10 - 01       1
0e11 - 0e       14
0e12 - 1b       27
0e13 - 28       40
0e14 - 35       53
0e15 - 00       0
0e16 - 00       0
0e17 - 00       0
0e18 - 4f       79
0e19 - 4f       79
0e1a - 4f       79
0e1b - 4f       79
0e1c - 00       0
0e1d - 00       0
0e1e - 00       0
0e1f - 00       0
0e20 - 5c       92
0e21 - 69       105
0e22 - 76       118
0e23 - 83       131
0e24 - 90       144
0e25 - 9d       157
0e26 - aa       170
0e27 - 00       0
0e28 - 5c       92
0e29 - 69       105
0e2a - 76       118
0e2b - 83       131
0e2c - 90       144
0e2d - 9d       157
0e2e - aa       170
0e2f - 00       0
0e30 - b7       183
0e31 - c4       196
0e32 - 00       0
0e33 - 00       0
0e34 - 00       0
0e35 - 00       0
0e36 - 00       0
0e37 - 00       0
0e38 - de       222
0e39 - de       222
0e3a - 00       0
0e3b - 00       0
0e3c - 00       0
0e3d - 00       0
0e3e - 00       0
0e3f - 00       0
0e40 - aa       170

One option that may help is if my 3468A has a similar format, I could do a 'bad' calibration and see how the number change. A better solution
is to understand how the values are used, but so far I haven't traced the ADC functions in the code.

All suggestions welcome!

« Last Edit: June 29, 2015, 02:15:52 am by Sailor »

Offline wolfalex

  • Regular Contributor
  • *
  • Posts: 81
  • Country: at
    • My hobby electronics website
Re: 3478A cal RAM readout idea
« Reply #33 on: June 29, 2015, 04:14:41 am »

Thank you very much for your fantastic job on finding out more about the cal RAM checksum and structure. I find this information very interesting. Also a big thanks again to MarkL for providing the readout data. I can not wait to see what other additional findings we will get from this.

 Unfortunetly I had no time today to revisit the Rom checksum routine in detail, but I will try to do that tomorrow.

Offline Sailor

  • Regular Contributor
  • *
  • Posts: 170
Re: 3478A cal RAM readout idea
« Reply #34 on: June 29, 2015, 05:45:28 am »
Alex, I had a look at the disassembly listing that you attached earlier, and downloaded the DASMx archive. I suspect that the disassembler that I use (D48), and yours, both have the same origins. Yours may even be a later, glossier development of D48. I presume that you have read the section in DASMx.pdf regarding their 'code threading' and 8048 disassembly operations, and that you have disabled it. While I agree completely with the difficulties that can be encountered with the (internal, 2k) bank switching in the 8048, I find that it is more of a help than it is a hindrance. D48 doesn't have the ability to turn the threading on or off - it may not even perform the thread-following algorithm (I haven't looked at the source code) - but it does handle the SEL1 / SEL0 influence on the destinations of CALLs and JMPs made local to the SELx instructions, and I find that to be useful.

It is undoubtedly safer to 'handle it yourself' either with pencil and paper, notes made in your disassembly file, or a (very) good memory. Nevertheless, I prefer to let the machine do as much as it can for me, and if I find it reports a destination address that doesn't look rational I simply backtrack a little to determine which SEL state is in effect. The very limited stack depth in the 8039/8048 means that the depth of subroutine CALLs is very shallow, so it's not a huge burden.

Just my thoughts. YMMV.  :)
« Last Edit: June 29, 2015, 05:48:04 am by Sailor »

Offline Sailor

  • Regular Contributor
  • *
  • Posts: 170
Re: 3478A cal RAM readout idea
« Reply #35 on: June 29, 2015, 06:54:44 am »
I've just been reading DASMx.pdf again, and it isn't specifically linking code threading to SELx handling. It's worse than that! This extract from page 16:

" it is advised that code threading be not used if the size of the 8048 source image exceeds 2 Kbytes. If images greater than this are disassembled, even with threading disabled, some errors in automatically generated labels may be expected."

seems to mean that it doesn't handle SELx at all! The following is an extract from your disassembly listing:

0421 : F0              " "      mov   a,@r0
0422 : 12 59      " Y"      jb0   L0459
0424 : F5              " "      sel   mb1
0425 : D4 00      "  "      call   L0600
0427 : E5              " "      sel   mb0
0428 : A8              " "      mov   r0,a

The CALL at location 425 is to a destination at 0x0e00, not 0600 i.e. DASMx didn't take any notice of the SEL1 instruction. This is fine if you are prepared to be vigilant and do the address modification yourself every time. The danger arises (as in this case) when the non-adjusted destination leads to apparently rational code:

0600            L0600:
0600 : A5              " "      clr   f1
0601 : 8A 80      "  "      orl   p2,#080H
0603 : B8 00      "  "      mov   r0,#000H
0605            L0605:
0605 : 46 0B      "F "      jnt1   L060B
0607 : E8 05      "  "      djnz   r0,L0605
0609 : C4 2D      " -"      jmp   L062D
060B            L060B:
060B : 35              "5"      dis   tcnti


instead of the correct code at

0E00 : 8A 0F      "  "      orl   p2,#00FH
0E02 : 9A F7      "  "      anl   p2,#0F7H
0E04 : B8 3F      " ?"      mov   r0,#03FH
0E06 : F0              " "      mov   a,@r0
0E07 : 77              "w"      rr   a
0E08 : 77              "w"      rr   a
0E09 : 53 3F      "S?"      anl   a,#03FH
0E0B : 03 07      "  "      add   a,#007H
0E0D : A3              " "      movp   a,@a
0E0E : 93              " "      retr

I'm afraid that I find life easier (I'm lazy) with the following output of D48:

   mov   a,@r0      ; 0421 - f0   p
   jb0   X0459      ; 0422 - 12 59   .Y
   sel   mb1              ; 0424 - f5   u
   call   X0e00      ; 0425 - d4 00   T.
   sel   mb0              ; 0427 - e5   e
   mov   r0,a              ; 0428 - a8   (


X0e00:   orl   p2,#0fh      ; 0e00 - 8a 0f   ..
           anl   p2,#0f7h           ; 0e02 - 9a f7   .w
           mov   r0,#3fh      ; 0e04 - b8 3f   8?
           mov   a,@r0      ; 0e06 - f0   p
           rr   a              ; 0e07 - 77   w
           rr   a              ; 0e08 - 77   w
           anl   a,#3fh      ; 0e09 - 53 3f   S?
           add   a,#7              ; 0e0b - 03 07   ..
X0e0d:   movp   a,@a   ; 0e0d - a3   #
           retr                 ; 0e0e - 93   .

Either way, it's a personal choice.


Offline wolfalex

  • Regular Contributor
  • *
  • Posts: 81
  • Country: at
    • My hobby electronics website
Re: 3478A cal RAM readout idea
« Reply #36 on: June 30, 2015, 02:38:33 am »

The problem is at the point in time when I downloaded the disassembler and the emulator I was not yet aware about all the specialities of the 8048 and how complex the adressing is.
My only knowledge at this point in time was derived from my experience with the 8051, and there in comparision it is quite simple: one program counter with full width, no sel commands and so on. So at this point in time I still thought the disassembler output must be ok, despite the fact that I already saw that the listing does not always seen to make sense.

After your explainations, after I saw that the use A12 for program memory switching and the usage of sel commands I was already  afraid that the disassembler maybe does not do a good job. But after your last post I am now really aware of the problem. I also already tried to follow the code from the start and at the first sel command and call I saw already how difficult it is to calculate the correct jump adress yourself. First you must know the current logic state of the A12 line, then the last sel command issued, and then also take in account the adress of the call command itself.

Offline wolfalex

  • Regular Contributor
  • *
  • Posts: 81
  • Country: at
    • My hobby electronics website
Re: 3478A cal RAM readout idea
« Reply #37 on: June 30, 2015, 03:29:51 am »
I have now installed d48 instead the disassembler I have used until now. Thanks for correcting my mistake.

If I get now the following output: (the same location you have shown above)

X041f:   mov   r0,#41h      ; 041f - b8 41   8A
                  mov   a,@r0      ; 0421 - f0   p
           jb0   X0459      ; 0422 - 12 59   .Y
          sel   mb1      ; 0424 - f5   u
          call   X0e00      ; 0425 - d4 00   T.

Can I now simply follow the target adresses in the listing for all the calls (like 0e00 at location 0425), or do I have to calculate the target adresses again myself. It seems the sel mb1in the line before is already taken into account in the adress call target adress 0e00, isnĀ“t it?

I guess the only bit that has to be corrected by me is the MSB of the call adress, because the disassembler can not be aware of the current state of bit A12, or?

Sorry for asking the same questions over and over again, but I want to prevent that I make another mistake again, and I am really interested into learning more about how to use the output of the disassembler :) Thank you very much.


I added an example what I mean: right at the start of the firmware I see a jmp at adr 1001 to adr X082a. But I also know that A12 on the ROM is still high -> so I would expect now that the next adress I have to go to in the listing is 182a.

org   1000h
   clr   f0      ; 1000 - 85   .
   jmp   X082a      ; 1001 - 04 2a   .*

but then if I try to locate adr 182a in the disassembler output i can not find it. There is only a command one byte before and afterwards of this adress. So clearly I must be wrong with my assumption, or?

   jnc   X182b      ; 1827 - e6 2b   f+
   jb1   X18f2      ; 1829 - 32 f2   2r
   jb1   X1833      ; 182b - 32 33   23
   jb3   X1890      ; 182d - 72 90   r.
   jb4   X1890      ; 182f - 92 90   ..
   jb2   X188a      ; 1831 - 52 8a   R.

« Last Edit: June 30, 2015, 03:45:08 am by wolfalex »

Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo