Eeprom Decoder

0 views
Skip to first unread message

Concordia Zentner

unread,
Aug 5, 2024, 7:49:35 AM8/5/24
to pyobrilfiwa
Iwatched Ben eater's video about a building computer based on 6502 microprocessor and I'm stuck at Part-3 ( Assembly language VS Machine code). He was programing a 32k AT28C256 EEPROM and he programmed it by assembly to blink a LED.

It tells the assembler that the code start at address 8000 right? And I think code will save starting at 8000 but this EEPROM can't save more than 7fff address so what address it will save?

In his video I understand that there are address decoders so when the 6502 chip sends address 8000 up above it will be decoded and it enable EEPROM and send address 0000 to EEPROM, so it means that code starts saving at address 0000 but when EEPROM is programmed with Minipro there are not any address decoders so what address it will be?


Now we will connect those ten address pins directly to the lower ten address lines of a 6502's 16 bit address bus, A0 to A9, and (here's the important part) leave lines A10 to A15 unconnected.


Clearly, the microprocessor can place any value it likes on lines A10 to A15, and this will have absolutely no effect on which byte of memory is accessed. Only A0 to A9 have any influence. This has an interesting consequence, from the point of view of the microprocessor.


The effect is that the same block of 1kB of ROM appears at 64 different locations in the entire address space. The bottom 10 bits of the address bus repeatedly loop through 0x0, 0x1, 0x2 ... 0x3FF, 0x0, 0x1, 0x2 ... 0x3FF, again and again, 64 times, as the entire address bus counts from 0x0000 to 0xFFFF.


Applying this same principle to your 32kB EEPROM, which has 15 address pins A0 to A14 connected to the corresponding pins of the microprocessor's address bus, with A15 being completely unconnected and ignored, you can see that the entire EEPROM contents will be duplicated (from the processor's perspective) twice, at 0x0000-0x7FFF, and again at 0x8000-0xFFFF.


The main takeaway here is that the address of the program in ROM memory, from the perspective of the EEPROM itself, and from the EEPROM programmer, is always 0x0000 to 0x7FFF, and yet from the point of view of the processor that program can be "mapped" to appear anywhere in the entire 64kB address space, depending on how it's wired to the address bus, and how the memory's "chip enable/select" pins respond to the upper address bus bits (called "address decoding").


The ".org" directive tells the assembler how to construct machines code to make it work at a specific location within the microprocessor's entire address space, but does not it any way determine or change the physical location in the device that stores it. So, when you write the assembly code, you are writing code to work at a specific place in the overall address space, but you can store that very code anywhere in the EEPROM, as long as you wire the EEPROM to appear at the appropriate place in that space.


So, in Ben's example, he's writing code to be assembled and run at position 0x8000, but that code is stored at position zero in the EEPROM, and the EEPROM is connected to "appear" (or be enabled) at position 0x8000 (and perhaps also 0x0000, if A15 is ignored as I explained above).


The EEPROM programmer has no idea of how the program works or was assembled, doesn't care if it's designed to run at 0x8000, or 0xABCD; all it cares about is that the file you are writing to the memory device begins at the device's own 0x0000 location. It's up to you to wire that EEPROM device up so that it appears at 0x8000 from the processor's perspective.


As for what's actually stored in the EEPROM, given the program you've shown us, if I recall correctly (30 year old memories being dragged up here), the first .org will not generate data. The following program segment appears at 0x0000 in the file. The second .org $FFFC will generate almost 32kBytes of zeros, then the last .equ will place 0x00 and 0x80 in locations 0x7FFC and 0x7FFD respectively. That's the end of the file.


The way memory addressing is done on a 6502 (and many other processors) is that there are 16 address lines from the CPU, that is enough to address 64k of memory directly. But to be able to do that you would need 64k of memory with 16 address lines, and this is rarely what you would use.


Instead you usually have memory in smaller chunks, such as the 32k EEPROM mentioned. As an example, the Commodore 64 computer which used a form of the 6502 (a 6510) had two 8k ROM chips for the operating kernal and BASIC language, a 4k ROM for character generation, a 1k x 4 RAM for color memory, along with 64k of DRAM and some I/O mapped into the memory space.


The CPU address lines are put through some decoding logic that generates signals to enable each memory IC depending on the address range, so where each ROM appears in the address space depends on how the address lines are decoded.


With a 6502, ROM is usually put somewhere high in memory because the last couple of memory addresses ($FFFE, $FFFF) are used as a vector to tell the CPU where it should start executing instructions. When the CPU starts up it reads these addresses and whatever data it finds there is loaded into the program counter and code execution starts there. Some other processors such as the Z80 put the ROM at the beginning of memory and start execution at address 0x0000.


The assembler needs to know where in the CPU's address space the ROM is going to be located so that it can use the correct addresses for any labels in the code that reference locations in the ROM itself. For example, if the ROM is to be mapped from $8000 to $FFFF and there is some code like this:


will tell the compiler that the code is starting at $8000 so when an address in the ROM is referenced through a label it will be able to calculate the correct address, if the .ORG address and the address the ROM is physically mapped to do not match the assembled code would reference the wrong location.


The alternative would be to make the code relocatable, that is, write the code so there are no absolute references like this, all address references would be relative. Then the code can be put anywhere in memory and still work.


In some 6502 computers where the address decoding is made as simple as possible, a memory IC can appear in multiple places. A ROM might be able to be addressed at any multiple of 8k for example, so you could use address $2000, $4000, $6000, etc. in your code and they'd all access the same ROM location. This was often done for computers that didn't need a lot of memory so it didn't matter if these redundant 'ghost' addresses existed.


Each data program or data block has an associated control block, which says where to find the program or data block in the file, how long it is, and which address it should start loading at into memory.


The effect of ORG is to set the loading address in a control block, for the code or data block that it refers to: the first byte of that code or data block will be loaded into memory at the address specified in the control block.


But unlike a file, a ROM chip corresponds to a single combined code & init-data block, and there are no control blocks. Instead the ORG statement must agree with the "low" address that is established by the chip select circuitry, so that jump statements and other references will resolve correctly at run-time.


Instead, it is usual for the ROM & RAM to take its address lines directly from the lowest of those provided by the CPU, while the other (higher) lines select which device (ROM, RAM, IO) is accessed. As a result, each device can only appear at an address that is some multiple of its own size.


More complex CPUs may have Memory Management Units that perform sophisticated address translation and access rights enforcement, in which case the ORG statement has to allow for whatever memory address mappings are loaded before that piece of code runs.


If you define a label at the start of the program, and then jump to the label, the assembler has to know that the CPU thinks the label's address is $8000 so it writes the instruction JMP $8000 and not JMP $0000, and then the CPU jumps to the label which it thinks is at $8000. That's what the .org is for. It tells the assembler how the CPU will see the program.


I think in the example it makes no difference because there are no labels. Except the assembler does calculate the difference between $8000 and $fffc, but you could write $0000 and $7ffc and get the exact same program. That would be different if the program used any labels.


ORG gives the position of the given address in the whole address space - in the stack of "books etc.". How this maps to an address in one book depends on how the books are set up in the stack (address space).


I am attempting to make an automatic bird caller that will play bird call mp3s (or other audio file). The device will only have one file to play that never changes so I am trying to avoid adding in an entire SD card reader, and want to save the mp3 files on an EEPROM or other in-circuit memory device. I am planning on using a DAC to play the audio files from the arduino memory to a small speaker. However, I have read that the EEPROM may be too slow to read for audio playing. Does anyone have any advice on this matter or have a link to a good article about it?


EEPROM will be fast enough - the onchip memory is just too small, mere fractions of a second can be stored. Consider that .wav files (basically CD files) use 44100 16-bit samples/second.

The '328P doesn't do MP3 decoding, you need an external device for that.


MDFLY is a trusted online retailer that offers electronics goods at incredible prices. We offer a array of high quality goods including training, evaluation, development board, programmer, electronic component, hardware, electronic kits, we also are...


Are you referring to the DAC that is needed to pass the mp3 to the speaker? Or is there a different decoding device specifically for Mp3 handling? If so, can you provide me a model number or link in the right direction? I was planning on adding my own 16bit DAC (MAX5541) for the signal processing out of the Arduino.

3a8082e126
Reply all
Reply to author
Forward
0 new messages