5

I got an EEPROM AT28C64 and loaded it with instructions with my handmade STM32 EEPROM programmer, the instructions are very simple:

  1. Load A register with decimal number 85 which is, in binary, 01010101, then
  2. output that A register on port zero, then
  3. jumping back to step 1.

I have hard coded this my elf in the beginning then used an assembler but here is my first line of code:

         /* 0      1     2     3     4     5     6 */
/* 0000 */  0x3e, 0x55, 0xd3, 0x00, 0xc3, 0x00, 0x00,

in assembly that is:

LD  A, 85
OUT (0), a
JP  0000h

Now I actually don't have any I/O IC or anything hooked, my only goal is just to see the 8 LEDs hooked to the data bus to show the pattern 01010101 twice; once when loading register A and again when the CPU is writing to the port, but unfortunately the first time the CPU writes to the port it writes a wrong value 01011001. When the CPU jumps back and repeats the process it does output the correct number while writing. When I changed my power supply it outputs random fluctuating values.

Is that normal? I tried with registers A, B, and C three of them while outputting they output wrong values.

Concerning my EEPROM Programmer, I checked it and it does write data correctly. I verified each byte of data the first time I tested it. The data bus outputs the same data I burned the EEPROM with so my programmer isn't to blame. The CPU I got is actually quite old it was manufactured in 1989 but it does execute opcodes like NOP or HALT so I don't think the CPU is not working.

Here is a diagram of the values shown on LEDs

WR, RD are active low

Data-bus readings are taken each RD or WR tick (being low)

Here is a link to a Google Photos video. (See the comment on the video for identifying the LEDs)

Results:

 _______________________________________
| D7 D6 D5 D4 D3 D2 D1 D0 HEX | WR | RD |
|_______________________________________|
| 0  0  1  1  1  1  1  0  3E  | 1  | 0  |          
|_______________________________________|
| 0  1  0  1  0  1  0  1  55  | 1  | 0  |
|_______________________________________|          
| 1  1  0  1  0  0  1  1  D3  | 1  | 0  |
|_______________________________________|          
| 0  0  0  0  0  0  0  0  00  | 1  | 0  |
|_______________________________________|          
| 0  1  0  1  1  0  0  1  59  | 0  | 1  |
|_______________________________________|          
| 1  1  0  0  0  0  1  1  C3  | 1  | 0  |
|_______________________________________|        
| 0  0  0  0  0  0  0  0  00  | 1  | 0  |
|_______________________________________|          
| 0  0  0  0  0  0  0  0  00  | 1  | 0  |
|_______________________________________|   

So does anyone knows why this is happening? When outputting the registers why is the wrong value outputted?

I have noticed that after a couple of tries with different power supplies, that the pattern written is changed so it is not only 01011001 but sometimes some random value. I thought maybe the instruction didn't reach the CPU or due to lose wires yet to be sure from that the LEDs I take readings from are connected at the same connections for each digital pin in the CPU so LED won't turn on or off except if that digital pin on the CPU is turned on or off correspondingly. At the beginning I didn't have any capacitors or anything in my circuit for decoupling so maybe this is the problem? I remember that when working with an ATMega328p MCU I should put I think a 100 nano-farad capacitor between GND and VCC as close as possible to the MCU so I tried that solution with the Z80 but all what happened is the pattern is changed and sometimes the WR and IOREQ becomes active without writing anything to the data-bus, so does anyone have suggestions? I already:

  1. pulled-up all CPU control signals (RESET, WAIT, INT, NMI, BUSRQ) to prevent them from floating
  2. Tried both Green LEDs and Red LEDs both connected to 10Kohm resistors (Red LED drained only 0.341 mA - so the LEDs won't effect this?)
  3. Tried using a cheap 5V power supply and an original 5V phone charger
  4. Connect the Z80 to a 7.164 Hz clock generated from a 555 timer (tried slower speeds, it also fails)
  5. lastly tried hooking decoupling capacitors as near to the CPU as possible and as far as possible and all values I found affecting and different kinds (100nF cermaic, 0.1uF or 1uF electrolytic)

Is there anything missing that could affect these types of instructions specifically?

enter image description here

This is the CPU details, hooked to the EEPROM and the 555 Timer for generating 7Hz clock signal.

enter image description here

This is my full setup.

  • Hard to give any definitive answer without more information. For example IORQ and MREQ. How is the Z80 traced, an at what point (clock) is the value recorded? A Z80 instruction like OUT takes 11 cycles, so what is recorded when? So far the table seams a mixup. Entries 1-3 and 5-7 seams to be opcode/operand fetches, but the operand that would follow the OUT at entry 3 is missing. So maybe you could provide a full description of how and were the data is gathered (and please, for clarity, reduce the non related parts) – Raffzahn Jun 8 at 18:57
  • Thank you for your note, but may I post a video for that ? because writing that table again is prettty not easy :) I can post a small video that has the IOREQ and RD and WR and CLOCK very clear. – Shams El-Deen Jun 8 at 19:00
  • 2
    Don't get me wrong, this is in no way meant to treat you. Exact measurement and recording is simply the base of all understanding. With experience shortcuts may come, but they are guesswork. For a good result, one always has to start with detailed and complete recordings of the object to be studied. Skipping that is the way of a tinkerer, while the true engineer will stick to data. – Raffzahn Jun 8 at 19:52
  • 2
    What is your clock rate? You have NMOS Z80 chip, which is dynamic, i.e. it should have some minimal clock frequency, otherwise it WILL fail. As a simplest thing, swap that to Z84C0008 chip, which is CMOS and static. – lvd Jun 9 at 14:53
  • 3
    @ShamsEl-Deen zilog.com/docs/z80/ps0178.pdf check this, page 34. Maximum width of clock=1 and clock=0 states is 2us each, so if your clock is slower than 250 kHz, NMOS Z80 will fail. – lvd Jun 9 at 16:48
11

I/O port data should be latched by the I/O device on the rising edge of /WR signal. On the falling edge, the only thing that is stable is the I/O port address.

EDIT: just noticed you said you are clocking your Z80 at 7 Hz. By the picture you have posted, you are using a NMOS Z80 (Z0840004PSC. CMOS Z80s start with Z084C.....). These cannot work below the minimum clock frequency stated in its datasheet:

Z80 clock specification

The maximum allowable period is determined by equation (12), which yields 202.6 us, or about 5 kHz. At 7 Hz, the device will behave in unexpected manners, or won't work at all.

| improve this answer | |
  • Thank you very much, but I have a small question, what you say means that at least while the writing process for a fraction of a second the pattern should be shown on the date bus right ? I have my clock running at around 7 Hertz and have taken a video for the process but I didn't find the pattern at all except if it's really a fraction of a second on a 7 Hertz clock and my eye and camera couldn't get it. – Shams El-Deen Jun 9 at 6:19
  • 2
    7 Hz with a NMOS device? That cannot work at all. – mcleod_ideafix Jun 9 at 23:01
5

It's possible that on the CPU you have the program counter (PC) and internal status register (for HALT) are implemented using static latches (SRAM) whereas, e.g. the bus drivers are using dynamic RAM (with no refresh). That would explain why instructions that only depend on the PC (NOP, JP) or status register (HALT) work properly but OUT instructions fail (and in an inconsistent manner). For a fully-static CPU all registers and internal buffers would use SRAM.

I'd suggest substantially increasing the clock rate (>250 kHz, as mentioned by @lvd). I don't know what you're using for a clock signal but you mentioned using an ATMega328p in the past; that chip could probably be programmed to generate an appropriate high-frequency clock signal for the Z80. In addition I'd place an 8-bit latch on the data lines. Something like a 74573 with some glue circuitry between the /WR and /LE pins would probably suffice (I'm sure there are reference designs readily available on the 'net).

Alternatively you could use a loop (or nested set of loops) to keep the LEDs on the data bus lit for more than a single bus cycle (albeit with a lot of flicker).

| improve this answer | |
  • Yeah I see your point, it can be the problem, but it would be excellent of you if you could provide a small assembly program that have the loops to keep LEDs on, because I am not that advanced in assembly, and I can raise clock rate to 10KHz. Thank you very much, and I am sorry if my request is a bit off topic. – Shams El-Deen Jun 9 at 15:57
  • Honestly, I can't write Z80 assembler (though I can read it). My answer is based on my knowledge of CPU design (and electronics in general). Some pseudo-Z80 assembler to do this though would be: "lbl_top: LD A, 85 ; LD B,255 ; lbl_b1: LD C, 255 ; lbl_c1: OUT 0, A ; DEC C ; JR Z, lbl_c1 ; DEC B; JR Z, lbl_b1 ; LD A, 0 ; LD B,255 ; lbl_c2: LD C, 255 ; lbl_c2: OUT 0, A ; DEC C ; JR Z, lbl_c2 ; DEC B ; JR Z, lbl_b2; JP lbl_top". What it's supposed to do is hold the value 85 on port 0 for 65025 bus cycles (255*255) then set it to 0 for the same period of time. – Alex Hajnal Jun 9 at 16:19
  • 1
    ... You should expect to see a lot of flickering on the LEDs because instruction fetches will also be running across the data bus. Adding a latch (as suggested by @mcleod_ideafix) such as a 74573 or 742573 would be a proper long-term solution. You should see what a recommended latch circuit for the Z80 is since I think simply connecting the /WR pin to the /LE pin of one of the chips I suggested would latch the value at the wrong time (an inverter is probably needed between them). – Alex Hajnal Jun 9 at 16:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.