¿ªÔÆÌåÓý

ctrl + shift + ? for shortcuts
© 2025 Groups.io

OTish: ROM/RAM bank switching in the 2467 et al.


 

Hey y'all,

I've always been curious to peep at the firmware in my Tek scopes, so for
giggles I installed Ghidra and pointed it at the ROMs from my 2467.
Snooping around a bit, while reading the service manual shows that the MPU
bank switches the alternate halves of two 64k ROMs into the top 32k of
address space.

What threw me for a bit of a loop is that the 2K of RAM in the scope, in
addition to being mapped from 0x0000-0x07FFF, is also mapped into the 8k of
address space from 0x8000-0x9FFFF when anything but the default ROM bank is
selected. This effectively makes it impossible to address the lowest 8k of
three out of four ROM banks, or 24k of the total 128k.

I haven't dug very deep yet, but I do e.g. see the RESET routine testing
the RAM at the 0x0000 address. It then switches ROM banks, into a routine
that tests the RAM in this alternate mapping. I also see the ROMs contain
only a copyright message and SWI instructions in these locations.
As an aside it's pretty cool to walk through the initial steps in the RESET
routine, which is about as far as I'm in right now :).

I really don't understand the advantage to this secondary mapping, which at
best just complicates the address decoding involved. The address mapping is
performed by a PAL, so maybe the additional logic is "free". At first I was
wondering whether this might be for backwards compatibility with the 2465's
option boards, but the 2465 has the RAM mapped only at address 0x0000, so
that's not it.
Do you all have any idea why Tek might have done this?

Siggi


 

Siggi,

do the locations 0x8000-0x9FFFF contain interrupt vectors which may need to be modified? That would be the main reason that I would expect random bits of memory to be remapped from ROM to RAM.

-- Jeff Dutky


 

On Wed, Nov 24, 2021 at 2:14 PM Jeff Dutky <jeff.dutky@...> wrote:

do the locations 0x8000-0x9FFFF contain interrupt vectors which may need
to be modified? That would be the main reason that I would expect random
bits of memory to be remapped from ROM to RAM.
Nope, the 6808 MPU only has 4 interrupt vectors, and they're all at the top
of memory, from 0xFFF8-0xFFFF.


 

On Wed, Nov 24, 2021 at 1:38 PM Sigur?ur ?sgeirsson <siggi@...> wrote:

I've always been curious to peep at the firmware in my Tek scopes, so for
giggles I installed Ghidra and pointed it at the ROMs from my 2467.
Incidentally there are some handy tricks in there.
As a case in point, the DAC_MSB_CLK and DAC_LSB_CLK address ranges are
defined in that order, each 0x40 bytes in length. When writing the DAC,
however, they write a 16 bit value to the last byte in the former, which
results in writing the full 16 bits with a single instruction,


 

On Wed, Nov 24, 2021 at 2:14 PM Jeff Dutky <jeff.dutky@...> wrote:

do the locations 0x8000-0x9FFFF contain interrupt vectors which may need
to be modified? That would be the main reason that I would expect random
bits of memory to be remapped from ROM to RAM.
I'm not deep into this yet, as first I needed to fix Ghidra's 6800
disassembler. The one that comes with it seems to be incomplete to plain
wrong, and so the disassembly it yielded didn't make much sense. Thankfully
there's a quite good 6809 disassembler I could water down to get most of
the 6800 op codes, then add back the handful of op codes that are different
in the 6809.

The 2465 was introduced in 1984, and I assume that much of the code I'm
looking at dates back to the original 2465. Maybe it even dates back
further to earlier microcontroller-driven scopes?
The TekWiki page on the 2465 () names
some of the engineers that worked on the hardware, I wonder if the same
people also worked on the firmware.

I haven't looked at anything like this before and I wonder what sort of
development environment the engineers had. It looks like the calling
conventions used are all over the map, which probably means this was all
hand-coded assembly. The A/B/X registers are used to pass arguments, though
not in any consistent order. Most functions seem to set a global that's
then tested or retrieved by the caller, but there are at least some utility
functions that return values through registers.
The instruction set on the 6800 is pretty minimal, and the register layout
is absolutely minimal. As a case in point, there's no way to store or load
from the upper or lower bytes of the X (or S) register, so the only way to
e.g. do 8+16 bit addition is by storing the 16 bit value to memory and
doing the sum from there.

In any case, the couple of uses of this alternate RAM mapping that I've
found so far seem quite curious. Ghidra's support for memory banking
seems fairly minimal, and it's a hassle to trace the control flow when
it crosses banks, so I haven't traced more than one or two cases. I'm
tempted to backtrace and look at the 2465, as it has a simpler memory
layout without any banking.
Maybe the original design of the 2465A/B had assumed more RAM was needed
and slotted it into that part of the address space, rather than to move the
IO Register space, which abuts the RAM in the original design. Maybe there
were features planned that never made it to production, that would have
required more RAM. Maybe this was a case where it was easier to modify the
hardware to fit an existing piece of firmware, than to rewrite or patch up
the firmware. The address mapping in question is under the PAL's control so
it's a trivial hardware change to add this mapping.
Wouldn't it be fun to know...


 

Interesting.

I've looked at a DM5010 code (6809) and I can throw a few observations at you, which (time frame wise) may well be useful.

1) I think it was all handwritten assembly run through an assembler.? That would be typical of the time period, since the code would be smaller and the processor only had 64K of memory.

The 6809 has an internal RAM area, which may or may not be switched in.? IIRC, it could be battery backed up.

I've done 6502 designs, and my preference would be to have a boot ROM at the highest 16K of memory, then switch ROM banks in for the next 16K down (0x8000 to 0xBFFF).? If I were to switch in RAM, it would be from 0x4000 to 0x7FFF.

However, since neither 6809 nor 6502 have a separate IO space, some space needs to be reserved for that.

One trick to use is to overlay memory, but it needs to be done as follows:

Overlay RAM over the write only registers implemented in simple (LS374, etc) hardware.? It makes them read/modify/write since the hardware needed to make the registers can get nasty.? For chips that include R/W capability (6820, etc), the chips cannot be overlaid.

Depending on how complicated the PLD is, you can overlay everything, and then punch holes in the RAM where an I/O chip resides.

So depending on what they did with I/O, maybe remapping memory at 0x8000 makes some sense, especially if it's only a few K.

Another software consideration is that there may have been a commercial floating point package bought as assembly code from an outside vendor, since the 65xx and 68xx processors don't have floating point.

There may be some "processor sanity" programming to make sure that the processor itself is working properly.? It was common in military programming at the time, and I seem to remember that kind of thing in the 468 scope, and the DM5010.

Harvey

On 11/26/2021 1:37 PM, Siggi via groups.io wrote:
On Wed, Nov 24, 2021 at 2:14 PM Jeff Dutky <jeff.dutky@...> wrote:

do the locations 0x8000-0x9FFFF contain interrupt vectors which may need
to be modified? That would be the main reason that I would expect random
bits of memory to be remapped from ROM to RAM.
I'm not deep into this yet, as first I needed to fix Ghidra's 6800
disassembler. The one that comes with it seems to be incomplete to plain
wrong, and so the disassembly it yielded didn't make much sense. Thankfully
there's a quite good 6809 disassembler I could water down to get most of
the 6800 op codes, then add back the handful of op codes that are different
in the 6809.

The 2465 was introduced in 1984, and I assume that much of the code I'm
looking at dates back to the original 2465. Maybe it even dates back
further to earlier microcontroller-driven scopes?
The TekWiki page on the 2465 () names
some of the engineers that worked on the hardware, I wonder if the same
people also worked on the firmware.

I haven't looked at anything like this before and I wonder what sort of
development environment the engineers had. It looks like the calling
conventions used are all over the map, which probably means this was all
hand-coded assembly. The A/B/X registers are used to pass arguments, though
not in any consistent order. Most functions seem to set a global that's
then tested or retrieved by the caller, but there are at least some utility
functions that return values through registers.
The instruction set on the 6800 is pretty minimal, and the register layout
is absolutely minimal. As a case in point, there's no way to store or load
from the upper or lower bytes of the X (or S) register, so the only way to
e.g. do 8+16 bit addition is by storing the 16 bit value to memory and
doing the sum from there.

In any case, the couple of uses of this alternate RAM mapping that I've
found so far seem quite curious. Ghidra's support for memory banking
seems fairly minimal, and it's a hassle to trace the control flow when
it crosses banks, so I haven't traced more than one or two cases. I'm
tempted to backtrace and look at the 2465, as it has a simpler memory
layout without any banking.
Maybe the original design of the 2465A/B had assumed more RAM was needed
and slotted it into that part of the address space, rather than to move the
IO Register space, which abuts the RAM in the original design. Maybe there
were features planned that never made it to production, that would have
required more RAM. Maybe this was a case where it was easier to modify the
hardware to fit an existing piece of firmware, than to rewrite or patch up
the firmware. The address mapping in question is under the PAL's control so
it's a trivial hardware change to add this mapping.
Wouldn't it be fun to know...





 

Hi Siggi,

I looked at the address decoding about 3 years ago. The goal was clearly to be able to access all the RAM. But, as you point out, if they did it would overlay the I/O address space. I think the easiest path was to make the full 8k of RAM appear elsewhere. This would have had advantages in minimizing design changes to the hardware moving from the 2445/2465 base design and options, and also minimizing changes to driver code when ported from the 2445/2465.

I guess they thought they had plenty of EPROM, and the expanded and non-volatile RAM storage was more valuable for any futures they could cook up. And it's less bits for the PAL to look at if they tried to split up the 8k.

That's my guess, anyway. Only the original the developers could say for sure.

I think I had found a couple of instances of jumps to the higher RAM page area (0x8000-0x9FFF). Can you say self-modifying code? I didn't dig into that much further.

The 2445/2465 is a much easier place to start when trying to understand Tek's code. I was going to write a Tek-specific disassembler that understood the later model banking natively, but hadn't gotten around to it. Maybe IDA can do it?

-mark


 

On Fri, Nov 26, 2021 at 9:13 PM Mark Litwack <mlitwack@...>
wrote:

I looked at the address decoding about 3 years ago. The goal was clearly
to be able to access all the RAM. But, as you point out, if they did it
would overlay the I/O address space. I think the easiest path was to make
the full 8k of RAM appear elsewhere. This would have had advantages in
minimizing design changes to the hardware moving from the 2445/2465 base
design and options, and also minimizing changes to driver code when ported
from the 2445/2465.
Ah - somehow I totally overlooked the fact that the 2465A/2467 et al have
8K of RAM, whereas the original address mapping only allotted 2K of address
space. So the answer was staring me in the face the whole time :).
I believe option boards also have ROM, so maybe the existing option boards
rely on the location of the IO range?


 

Hi Siggi,

The option boards do indeed have their own ROM, and some (like the GPIB option) even have their own additional RAM.

The service manual says that 0x1000-0x7FFF are "Reserved for Options". A quick look through the theory of operation for the various options for both the plain and A/B models says that the ROM and various control registers are all overlayed within this area. To resolve the conflict, each option board is assigned a unique bit at address 0x7FFF to enable or disable it. For example, the GPIB board is controlled by bit 0, the TV board is controlled with bit 5, and so on.

It seems that there are also some fixed allocations as well (not overlayed). For example, the buffer board has a ROM that goes from 0x1000-0x1FFF and is not paged. And similarly, the GPIB board has a ROM that goes from 0x2000-0x3BFF that is not paged. But the GPIB board also has another ROM that IS paged (meaning can be enabled and disabled via 0x7FFF) from 0x4000-0x7fff. I'm guessing the GPIB interface needed an "always-ON" ROM so it could more quickly handle interrupts emanating from the GPIB controller.

And then for added fun, they added the A5 main board ROM banking in the A/B models.

It's crazy complicated, but fortunately well-documented in the address decoding tables in all the option theory sections.

-mark

On Sat, Nov 27, 2021 at 11:24 AM, Siggi wrote:

On Fri, Nov 26, 2021 at 9:13 PM Mark Litwack <mlitwack@...>
wrote:

I looked at the address decoding about 3 years ago. The goal was clearly
to be able to access all the RAM. But, as you point out, if they did it
would overlay the I/O address space. I think the easiest path was to make
the full 8k of RAM appear elsewhere. This would have had advantages in
minimizing design changes to the hardware moving from the 2445/2465 base
design and options, and also minimizing changes to driver code when ported
from the 2445/2465.
Ah - somehow I totally overlooked the fact that the 2465A/2467 et al have
8K of RAM, whereas the original address mapping only allotted 2K of address
space. So the answer was staring me in the face the whole time :).
I believe option boards also have ROM, so maybe the existing option boards
rely on the location of the IO range?


 

On Fri, Nov 26, 2021 at 9:13 PM Mark Litwack <mlitwack@...>
wrote:

I was going to write a Tek-specific disassembler that understood the later
model banking natively, but hadn't gotten around to it. Maybe IDA can do
it?
I'm using Ghidra, which almost certainly will allow automating the task of
resolving function references through bank switching. The problem is that
I'm a total Ghidra n00b :).
It looks like the 6800 disassembler I ginned up (
) is correctly
lifting the instructions to P-code, and from there it should be possible to
script up something that creates the right references.

It's a bit of a complication that a call through a bank switch is typically
done through a thunking routine that sits across the two banks, something
like:

SERVICE_FUNCTION_IN_BANK1_THUNK:
Bank0: JSR SWITCH_BANK1
Bank1: JSR ACTUAL_SERVICE_FUNCTION
Bank1: JMP SWITCH_BANK0

where the successive instructions above are on back-to-back addresses, but
in alternate ROM banks.

A call from bank0 to bank1 is then as simple as:
Bank0: JSR SERVICE_FUNCTION_IN_BANK1_THUNK

I think it would be ideal if the notion and particulars of the bank
switching could be plugged into Ghidras existing analysis mplementation, as
that way it would seamlessly trace control flow across the bank switching.
After thinking on it a little bit, I think it'd be reasonably
straightforward to abuse the processor description by adding a banking
register (BR) to the processor, and change all PC addressing to reference
BR+PC. This would make it possible to describe the ROM layout in an
extended, flat address space.

Another way to crack this would be to write an emulator. Mame has a 6800
CPU implementation, and the 2400 memory map and registers are sufficiently
documented that emulating them should be feasible. This would at least
expose all instructions and control flow for features that are exercised in
the emulator run.


 

Hi Siggi,

I think writing an emulator would be a monumental task considering all the hardware registers that can affect the execution path. I think it would be easier to hook up a logic analyzer and work on the real thing. All the state inputs for the analyzer are exposed and can be probed directly (like the ROM and PAGE signals). I've done this on several occasions for the 2465 and the 2445A to try to learn how some of the code works.

Introducing two more bits to encompass all the available memory, I agree, is probably the easiest way. I don't know anything about ghidra, but maybe it has a configurable MMU that could map the overlayed addresses using the two extra bits?

When working with the logic analyzer, I created two additional high-order address bits called R and P, for ROM and PAGE. It really helps to add some sanity while examining the disassembled execution trace.

I think you've already figured this out, but here is a little bit of a dive into the PAL decode which might be useful:



-mark

On Sat, Nov 27, 2021 at 02:53 PM, Siggi wrote:

On Fri, Nov 26, 2021 at 9:13 PM Mark Litwack <mlitwack@...>
wrote:

I was going to write a Tek-specific disassembler that understood the later
model banking natively, but hadn't gotten around to it. Maybe IDA can do
it?
I'm using Ghidra, which almost certainly will allow automating the task of
resolving function references through bank switching. The problem is that
I'm a total Ghidra n00b :).
It looks like the 6800 disassembler I ginned up (
) is correctly
lifting the instructions to P-code, and from there it should be possible to
script up something that creates the right references.

It's a bit of a complication that a call through a bank switch is typically
done through a thunking routine that sits across the two banks, something
like:

SERVICE_FUNCTION_IN_BANK1_THUNK:
Bank0: JSR SWITCH_BANK1
Bank1: JSR ACTUAL_SERVICE_FUNCTION
Bank1: JMP SWITCH_BANK0

where the successive instructions above are on back-to-back addresses, but
in alternate ROM banks.

A call from bank0 to bank1 is then as simple as:
Bank0: JSR SERVICE_FUNCTION_IN_BANK1_THUNK

I think it would be ideal if the notion and particulars of the bank
switching could be plugged into Ghidras existing analysis mplementation, as
that way it would seamlessly trace control flow across the bank switching.
After thinking on it a little bit, I think it'd be reasonably
straightforward to abuse the processor description by adding a banking
register (BR) to the processor, and change all PC addressing to reference
BR+PC. This would make it possible to describe the ROM layout in an
extended, flat address space.

Another way to crack this would be to write an emulator. Mame has a 6800
CPU implementation, and the 2400 memory map and registers are sufficiently
documented that emulating them should be feasible. This would at least
expose all instructions and control flow for features that are exercised in
the emulator run.


 

Guys, this is a really interesting thread. I wish I had more time to lend a hand!

--Victor


 

On Sun, Nov 28, 2021 at 4:40 PM Mark Litwack <mlitwack@...>
wrote:

I think writing an emulator would be a monumental task considering all the
hardware registers that can affect the execution path. I think it would be
easier to hook up a logic analyzer and work on the real thing. All the
state inputs for the analyzer are exposed and can be probed directly (like
the ROM and PAGE signals). I've done this on several occasions for the
2465 and the 2445A to try to learn how some of the code works.
I guess it depends on what sort of tools you're used to working with. I'm a
"recovering software engineer", so my handiest hammer will probably always
be software. I've looked at MAME, which is primarily used to emulate arcade
games, but it has all the infrastructure already made for building an
emulator, so to build an emulator for the 2400 scopes would be mostly about
writing up the register emulation. It doesn't look too daunting from afar
:).


Introducing two more bits to encompass all the available memory, I agree,
is probably the easiest way. I don't know anything about ghidra, but maybe
it has a configurable MMU that could map the overlayed addresses using the
two extra bits?
When working with the logic analyzer, I created two additional high-order
address bits called R and P, for ROM and PAGE. It really helps to add some
sanity while examining the disassembled execution trace.
Yeah, that I can see already.


I think you've already figured this out, but here is a little bit of a
dive into the PAL decode which might be useful:



Ah, that's cool. Did you reverse the full definition of the PAL?


 

I did. It was a bit of tedious work to derive the equations from the gate programming. Afterwards I noticed the source where I got the JEDEC file had also posted the original equations from which the JEDEC file was generated (doh!).

Can't wait to see your GUI rendering of a 24xx front panel in MAME!

-mark

On Mon, Nov 29, 2021 at 01:06 PM, Siggi wrote:
...

Ah, that's cool. Did you reverse the full definition of the PAL?


 

On Mon, Nov 29, 2021 at 1:06 PM Sigur?ur ?sgeirsson <siggi@...> wrote:

On Sun, Nov 28, 2021 at 4:40 PM Mark Litwack <mlitwack@...>
wrote:

I think writing an emulator would be a monumental task considering all
the hardware registers that can affect the execution path. I think it
would be easier to hook up a logic analyzer and work on the real thing.
All the state inputs for the analyzer are exposed and can be probed
directly (like the ROM and PAGE signals). I've done this on several
occasions for the 2465 and the 2445A to try to learn how some of the code
works.
I guess it depends on what sort of tools you're used to working with. I'm
a "recovering software engineer", so my handiest hammer will probably
always be software. I've looked at MAME, which is primarily used to emulate
arcade games, but it has all the infrastructure already made for building
an emulator, so to build an emulator for the 2400 scopes would be mostly
about writing up the register emulation. It doesn't look too daunting from
afar :).
So I started writing a MAME driver for the 2465, since it's "uncomplicated"
in terms of memory accesses. I discovered that there are actually several
tek device drivers in MAME already, notably

Driver tek4051 (Tektronix 4051):
Driver tek4052a (Tektronix 4052A):
Driver tek4107a (Tektronix 4107A):
Driver tek4109a (Tektronix 4109A):

I don't know to what level of completion or accuracy these devices are
emulated.

In any case, my embryonic emulator is currently stuck in initialization,
where it appears the firmware is wiggling DAC levels while polling the
display sequencer for trigger status. Presumably this is the self-test that
validates triggering against the line input.

I have a vague recollection of a power-up hang in these scopes when the
display sequencer or the trigger hybrid are bad. Does anyone here remember
this sort of powerup hang?


 

On Mon, Dec 20, 2021 at 6:19 PM Siggi via groups.io <siggi=
[email protected]> wrote:

In any case, my embryonic emulator is currently stuck in initialization,
where it appears the firmware is wiggling DAC levels while polling the
display sequencer for trigger status. Presumably this is the self-test that
validates triggering against the line input.

I have a vague recollection of a power-up hang in these scopes when the
display sequencer or the trigger hybrid are bad. Does anyone here remember
this sort of powerup hang?
Looks like I've cleared the hang which was most likely due to confused
front panel scanning. Since I hadn't written that part of the emulation,
the firmware saw pretty much all front panel keys pressed at the same time.
I'm still tripping a power up self test as I have to press the (simulated)
A/B trig button after startup. To be continued ...


 

On Wed, Dec 22, 2021 at 4:46 PM Siggi via groups.io <siggi=
[email protected]> wrote:

Looks like I've cleared the hang which was most likely due to confused
front panel scanning. Since I hadn't written that part of the emulation,
the firmware saw pretty much all front panel keys pressed at the same time.
I'm still tripping a power up self test as I have to press the (simulated)
A/B trig button after startup. To be continued ...
I have enough hardware emulated now that I can see what I'm failing at
least: /g/TekScopes/photo/271013/3355271. Not a surprise
to fail the EAROM checksum test, given that I have random data in the
simulated EAROM. I expect populating the EAROM data with a good image will
clear that, no problem.
Clearing the 05 tests is going to be a whole other kettle of wax, however,
because that's where the firmware meets with the analog for the first time
:).