Would you like to react to this message? Create an account in a few clicks or log in to continue.

You are not connected. Please login or register

Implementing processor Z80

3 posters

Go to page : 1, 2  Next

Go down  Message [Page 1 of 2]

1Implementing processor Z80 Empty Implementing processor Z80 Fri Apr 08, 2022 4:32 pm

vranik



Hi, I would like to try implement processor Z80. It is a processor only without any peripheral neither memory. In fact it is only sequential logic. The reset signal is asynchronous only. Other signals are clock driven. I looked into source core and It seems to me that it should be based on class Chip or LogicComponent. Which one is better?

Fizik_S and Alex68 like this post

2Implementing processor Z80 Empty Re: Implementing processor Z80 Fri Apr 08, 2022 5:16 pm

arcachofo

arcachofo

Hi.
I would implement it as an MCU.
For this you need to implement the instructon set.

As an example have a look at src/mcusim/cores/i51/i51core.cpp
That is the instruction set for 8051.

Fizik_S and Alex68 like this post

3Implementing processor Z80 Empty Re: Implementing processor Z80 Fri Apr 08, 2022 8:11 pm

vranik



I think that the implementation as an MCU is not suitable. This processor Z80 does not contain any memory and it is necessary to simulate also reading and writing signals from external memory. An example is in the picture below. All the signals are external pins of the processor. The Op Code Fetch is consisted of four cycles. The first cycle is setting address for external memory, the second cycle is reading instruction from the memory, the third cycle is executing the instruction and the fourth cycle is refreshing external dynamic memory. During every cycle the external signals are set or read and it is more often than once per instruction. Does the MCU allow this behaviour?

Implementing processor Z80 Ca84o10

4Implementing processor Z80 Empty Re: Implementing processor Z80 Sat Apr 09, 2022 7:49 pm

arcachofo

arcachofo

...
Does the MCU allow this behaviour?
Not yet, but external memory access must be implemented for 8051 as well.

In any case this must be implemented, using MCU or Logic Components.

Using Logic Components you need to implement everything.
But MCUs already have some base "infrastructure" that can be used: Clock, Reset, I/O Ports, Interrupts, memory (don't you need registers?), stack, status register...

MCUs also allow to create derivatives using the same CPU.

In any case for your original question:
I looked into source core and It seems to me that it should be based on class Chip or LogicComponent. Which one is better?
"Chip" is only a "package", it just provides a way to define pins, size and background in an xml file.
It is used by subcircuits and MCUs.

Logic Component is a base class for an actual component with I/O pins and Clock Pin.
This is the one to use for creating new components.


5Implementing processor Z80 Empty Re: Implementing processor Z80 Sat Aug 06, 2022 7:18 pm

vranik



I am still working on implementation of Z80 CPU. The core works and now I working on exact timing. I am nearly finished, but I would like to clarify some things.
There are two methods for component inicialization. The first is initialize() and the second is stamp(). What is the purpose of the methods and what is expected they should do? I would like to have possibility of internal clock therefore it is necessary to call addEvent() during inicialization. Where is the right place for it?
Other thing is that I implemented propagation delay when the external clock is used. How do you deal with the situation when the external clock is faster than propagation delay. I mean situantion when the voltChanged() is called by clock change earlier than runEvent(). Is it possible to add more events and distinguis between them?

6Implementing processor Z80 Empty Re: Implementing processor Z80 Sun Aug 07, 2022 12:14 am

arcachofo

arcachofo

I am still working on implementation of Z80 CPU. The core works and now I working on exact timing. I am nearly finished
Cool!

There are two methods for component inicialization. The first is initialize() and the second is stamp(). What is the purpose of the methods and what is expected they should do? I would like to have possibility of internal clock therefore it is necessary to call addEvent() during inicialization. Where is the right place for it?
initialize()
- Is called at simulation start and at simulation stop.
- At simulation start it is called before eNode initialization, so nothing related with eNodes should be done here.

stamp()
- Is called only at simulation start
- Is called after eNode initialization, so anything related with eNodes should be done here.

As a general rule: use stamp() unless you want it done also at simulation end.

Other thing is that I implemented propagation delay when the external clock is used. How do you deal with the situation when the external clock is faster than propagation delay. I mean situantion when the voltChanged() is called by clock change earlier than runEvent().
This depends on what exactly are you doing.
Do you have your code available somewhere?
Or explain some case with more detail?

A questions that comes to my mind:
Why are the propagation delays so long?
How long are the propagation delays?

Is it possible to add more events and distinguis between them?
It is not possible to add more events and distinguish between them directly by Simulator::addEvent().
New events will be ignored and a warning shown in bottom panel.
You can "reshedule" events by Simulator::cancelEvents() and then Simulator::addEvent() with a new time.

But you can use IoComponent::sheduleOutPuts() to change output states faster than propagation delay.
You can see how it works in most Logic Components, for example Gates.

7Implementing processor Z80 Empty Re: Implementing processor Z80 Mon Aug 08, 2022 5:52 pm

vranik



I attached the source code of Z80 CPU. There are still some macros for debugging and Z80 CPU Monitor is disabled, because it is not finished yet (I am not familiar with Qt libraries). If you have any idea how to improve it or use more classes from simulide let me know.

I wanted to use IoComponent::sheduleOutPuts(), but it is quite limited. It can set outputs only and there is no support for bidirectional data bus and for high impedance state. I use outputs for address bus, inputs for data bus and others pins for control signals. The inputs can change direction to outputs and nearly all of the signals have possibilities to set to high impedance state.

Finally, unfortunately, I found out that the simulation is quite slow. My idea was to simulate 8bit computers and they use clock for CPU more than 1 MHz.

n3645 likes this post

8Implementing processor Z80 Empty Re: Implementing processor Z80 Mon Aug 08, 2022 8:12 pm

n3645



vranik wrote:I attached the source code of Z80 CPU.

It seems there is no attachment..

Check the length of the zip, need to be less than 50k. It is small footprint, but that is what it is.

If it is not a zip, then be sure that extension is acceptable as well. There is no info that the attachment is acceptable or not, it is necessary to check the post...

9Implementing processor Z80 Empty Re: Implementing processor Z80 Mon Aug 08, 2022 8:17 pm

vranik



I'm sorry. Now it should be attached.
Attachments
Implementing processor Z80 Attachmentz80cpu.zip
Z80CPU source code
You don't have permission to download attachments.
(39 Kb) Downloaded 7 times

10Implementing processor Z80 Empty Re: Implementing processor Z80 Tue Aug 09, 2022 6:13 pm

arcachofo

arcachofo

I attached the source code of Z80 CPU. There are still some macros for debugging and Z80 CPU Monitor is disabled, because it is not finished yet (I am not familiar with Qt libraries). If you have any idea how to improve it or use more classes from simulide let me know.
Nice, I will have a look.

Finally, unfortunately, I found out that the simulation is quite slow. My idea was to simulate 8bit computers and they use clock for CPU more than 1 MHz.
Simulations at these clock speeds will be slow.
The main reason is the use of external memory: every time a pin changes state, the circuit must be recalculated.

11Implementing processor Z80 Empty Re: Implementing processor Z80 Tue Aug 09, 2022 7:09 pm

arcachofo

arcachofo

If you have any idea how to improve it or use more classes from simulide let me know.
The first thing that comes to my mind is the "Memory controller".

This could be a separate object with methods to read, write, set the timings, etc.
This takes lots of complexity from the cpu class and it has it's own events, so probably most of the problems you mentioned with propagation delays could be solved.

I recently created a generic/configurable Memory controller for 8051 and 6502 ( src/mcusim/modules/memory/extmem.cpp ).
It is still very raw and it would need some modifications but you get the idea.
And I'm not sure if it's worth having a "generic" one or creating one for each device or type of memory.

In this case I would create a new one for dynamic memory.
In a first step something specific for the Z80, and maybe later it could be used to create a generic one.


Some problems I see:
- The Mcu Monitor should be the one in simulide, we can't create an Mcu Monitor for each Microprocessor/Microcontroller.

- Debugging this device is not possible as it is now.

- There is no "DIP" package, only "Logic simbol".

I have been working to expand the capabilities of the "MCU" framework in simulide to be able to create devices like this.
As a proof of concept I used the 6502.
The Mcu Monitor and many other details still need some work,  but it is roughly working.

So the only good solution I see is eventually porting your implementation to the current "MCU" framework.
Which souldn't be too hard:
- The files you sent would be the "core" files (with some modifications).
- Packages, Ports and some other details would be defined in xml files.
- Other problems can be solved by modifying the current "MCU" framework.


EDIT:
I have been thinking about this and have a general idea:

- New "MPU" component: a variant of MCU without "load Firmware" and other things.
I will create a new class hierarchy to accommodate both variants in a way that all can use "Mcu Monitor", debugger, etc.

- Configurable "Mcu Monitor" that can be used for MCUs, MPUs and other.
I will wait for your implementation of "Z80 Monitor" and see what ideas come from that.

12Implementing processor Z80 Empty Re: Implementing processor Z80 Wed Aug 10, 2022 8:25 pm

vranik



I looked into file Memory controller (extmem.cpp) and it looks that it is not general memory controller, but controller only for 6502. There are defined exact signals, which are not compatible with Z80 CPU. It uses bus not only for memory access, but also for access to I/O devices (signal MREQ vs IORQ). Address and data bus are shared, but it use different control signal and little different timing. Further more there is external WAIT signal which can pause reading or writing (used for slow memories and slow I/O devices).

Z80CPU use several timing of the bus. Timing is different for reading instruction from memory from reading instruction operands. There is also possibility to stop processor and set whole bus to high impedance mode and release it for DMA transfer (Z80 DMA). If you are interested in look into Z80CPU datasheet in chapter Timing.

The memory controller for Z80 CPU should be rather programmable logic waveform generator with possibility to insert wait cycles and call events at defined waveform point.

I will try to define Z80 CPU in similar way as you did 8051 or 6502. It takes some time.

The Z80CPU Monitor only shows registers and internal states of Z80 CPU. Nothing more. I already have it, but it crash very ofter and I don't know why. I am not very familiar with Qt and I must have done some critical mistake.

13Implementing processor Z80 Empty Re: Implementing processor Z80 Thu Aug 11, 2022 12:25 am

arcachofo

arcachofo

I looked into file Memory controller (extmem.cpp) and it looks that it is not general memory controller, but controller only for 6502. There are defined exact signals, which are not compatible with Z80 CPU. It uses bus not only for memory access, but also for access to I/O devices (signal MREQ vs IORQ). Address and data bus are shared, but it use different control signal and little different timing. Further more there is external WAIT signal which can pause reading or writing (used for slow memories and slow I/O devices).

Z80CPU use several timing of the bus. Timing is different for reading instruction from memory from reading instruction operands. There is also possibility to stop processor and set whole bus to high impedance mode and release it for DMA transfer (Z80 DMA). If you are interested in look into Z80CPU datasheet in chapter Timing.
It is used by 6502 and 8051 and can be used by other devices.
- Timing is configurable.
- Control pins can be used or not depending on what you need.
- There are methods to directly set values for Data and Address Ports and direction for data port.
- Other features like pause operation or new control Pins could be added.

In any case, my suggestion was that the memory controller is a separate object and take that complexity and the timings out of the cpu object.
By using the current implementation, modifying it or creating a new one.

I will try to define Z80 CPU in similar way as you did 8051 or 6502. It takes some time.
I think that by now it is not worth to change your Z80 implementation:

Currently MPUs are not really supported in simulide.
Implementing 6502 was a way to find out what I need to make easy to create MPUs in simulide.
This is changing and still undefined, so any work you do now will need to be changed very soon.

Right now I am working to create a new class structure that allows to create MPUs in the same way than MCUs but specific for MPUs.
I have the general idea but the real challenge is in the details.

The main challenge right now is about "Mcu Monitor".
I opened a discussion to talk about this, your opinion and experience implementing Z80 could be quite useful:
https://simulide.forumotion.com/t946-redesigning-mcu-monitor#4396


In conclusion:
Let me create the infrastructure for MPUs and then let's port your Z80 to it.
First step: define a new "Monitor" that can be used for MCUs, MPUs, an other devices.

14Implementing processor Z80 Empty Re: Implementing processor Z80 Sat Aug 13, 2022 10:58 pm

arcachofo

arcachofo

About MPUs:
I tried to implement the new  class structure but it becomes really complex and many problems arise.
By now I'm leaving it as it is and implement MPUs just like MCUs without Memory or peripherals.

I solved some of the problems:
MPUs don't show "Load Firmware" and other MCU specific stuff in the context menu and properties.
And a bunch of minor issues like not checking for PGM boundaries if PGM is external, etc.

Also added a "CPU" section to the Mcu Monitor to show cpu registers and other stuff.


About Z80:
Now I see the problems you mentioned about runEvent() and propagation delay.
One solution is separating the "Memory Controller" to another object, but as you mentioned, wait states and differentiation
betwen IO read/write and MEM read/write, etc. makes it complicated.

But using the "MCU infrastructure" has an advantage:
You don't need to use runEvent() to generate the half clock cycles, the cpu will be called periodically every cycle (or half cycle).
So runEvent() is free to be used as a delayed routine to set all the Pins.

The idea I have now is implementing all the pin manipulation not in a separate object but in a separate class that can be reused by other similar cpus.
So Z80 will be a child of this new class (but same object) and other cpus can subclass it an inherit all the bus and control  manipulation functionality.

I'm working in this, but Z80 is a hell of complicated cpu.
So my plan is to create a new Z80 integrated in the "MCU infrastructure" with this new class for bus and control pins.
Most likely it will not work correctly, but you can take on it, see the idea, and make it work.

About Z80 Monitor chashing:
I think the problem is that you are calling Monitor->update() from the cpu.
You can't call anything related with the GUI from the simulation thread.

Instead, it must be done in updateStep():
- Add Z80 to "updateList":
  In constructor add: Simulator::self()->addToUpdateList( this );

- Add in header public section: virtual void updateStep() override;

- In the implementation of updateStep() call Monitor->update() or whatever you want to do related to the GUI.

15Implementing processor Z80 Empty Re: Implementing processor Z80 Sun Aug 14, 2022 11:48 am

vranik



I'm working in this, but Z80 is a hell of complicated cpu.
That was the reason why I choose the logic component instead of the MCU. It is not compatible with actual implementation of the MCU. It is up to you if it worths implementing more general.
By the way the internal timing is not accurate. If it was accurate it would be even more complicated. Threrefore the instructions are executed at the last T state of machine cycle instead of distribution over all T states. Timing of external signals and behaviour for software should be accurate.

About Z80 Monitor chashing:
I think the problem is that you are calling Monitor->update() from the cpu.
You can't call anything related with the GUI from the simulation thread.
You are right. I fixed it according to your advice and it magically started working. Smile Thank you.

16Implementing processor Z80 Empty Re: Implementing processor Z80 Sun Aug 14, 2022 1:42 pm

arcachofo

arcachofo

That was the reason why I choose the logic component instead of the MCU. It is not compatible with actual implementation of the MCU. It is up to you if it worths implementing more general.
The only option is integrating it in the structure of the program.
If the program needs to be modified to accommodate it, let's do it.

By the way the internal timing is not accurate. If it was accurate it would be even more complicated. Threrefore the instructions are executed at the last T state of machine cycle instead of distribution over all T states. Timing of external signals and behaviour for software should be accurate.
Yes, that's what matters: what the circuit "sees".

You are right. I fixed it according to your advice and it magically started working. Smile Thank you.
Nice to know!

17Implementing processor Z80 Empty Re: Implementing processor Z80 Mon Aug 15, 2022 10:39 am

arcachofo

arcachofo

I added the new Z80 MPU at Rev 1329.
Your original implementation is also there so it can be compared.

The code is at src/mcusim/cores/z80/
It is still very rough but seems to work, at least it generates the same signals:

Implementing processor Z80 Z8010

I messed up all your code, but you can get the idea of how it's implemented.
It should work with your exact code as well, just changing a few things.

Note that by now it only works with external clock.
And Control Pins are NOT inverted, it uses inverted logic internally.

I moved all the Pin manipulation to another class: Z80io
And the table for machine cycles to another file: z80cycles.h


Next I want to improve some things in McuMonitor, specially the ability to add more data types (currently it is limited to uint8).
This will be useful not only for this processor, also for the existing microcontrollers.

I have not tried to debug code, but this could help a lot to test it.
What is a good/popular/recommended assembler for Z80?

As I said it is still very rough, there are many details to solve.

18Implementing processor Z80 Empty Re: Implementing processor Z80 Tue Aug 16, 2022 7:24 pm

vranik



And Control Pins are NOT inverted, it uses inverted logic internally.
I inverted it only because of schematic symbol to add circles to pins. No other reason.

I have not tried to debug code, but this could help a lot to test it.
I will do it, but I don't know when. Very Happy

What is a good/popular/recommended assembler for Z80?
I recommend to use SjASMPlus.

I noticed that you renamed it from Z80CPU to Z80 only. I recommend to use Z80CPU because there are other chips from Zilog family - Z80DMA, Z80CTC, Z80PIO, Z80SIO, etd.



Last edited by vranik on Tue Aug 16, 2022 7:37 pm; edited 1 time in total (Reason for editing : Added information about chip name)

19Implementing processor Z80 Empty Re: Implementing processor Z80 Tue Aug 16, 2022 10:35 pm

arcachofo

arcachofo

I inverted it only because of schematic symbol to add circles to pins. No other reason.
That is the correct way to do in that case, I just wanted to inform you that I changed it.

This is one of the problems to solve:
For Logic components and "MCUs" if you invert the Pin, it adds the circle, and it inverts the signal.
But for Subcircuits it just adds a circle because there is nothing to invert, that pin is just a connection.

In Logic Components you can't change the "package", but in Subcircuits and MCUs you can.
In Subcircuits you can use inverted in one package and not-inverted in the other.
But in MCUs you must use the same in both because those Pins are IO Pins, not just connections.
By now the only solution is using not inverted Pins in both packages.

I recommend to use SjASMPlus.
Thanks, I will have a look.

I noticed that you renamed it from Z80CPU to Z80 only. I recommend to use Z80CPU because there are other chips from Zilog family - Z80DMA, Z80CTC, Z80PIO, Z80SIO, etd.
Ok,  good to know.
By now I have to use another name because your original version is still there.
When there is only one I will change the name.

20Implementing processor Z80 Empty Re: Implementing processor Z80 Wed Aug 17, 2022 5:56 am

arcachofo

arcachofo

Warning: right now it is not possible to debug z80.

I will let you know when all the issues are solved.

21Implementing processor Z80 Empty Re: Implementing processor Z80 Mon Sep 12, 2022 10:25 am

vranik



I updated the Z80 core to be better readable. I didn't change comments yet. I will do  it later. It is based on trunk revision 1331. If you have any other idea how to improve readability let me know.
Attachments
Implementing processor Z80 Attachmentz80core.zip
You don't have permission to download attachments.
(22 Kb) Downloaded 3 times

arcachofo likes this post

22Implementing processor Z80 Empty Re: Implementing processor Z80 Sun Sep 18, 2022 3:55 am

arcachofo

arcachofo

I updated Z80 with your code and did some changes (Rev 1340):
- Unified Z80Core and Z80Io (similar to your original implementation).
- Now using IoPort instead of McuPort.
- Using fast set Pin state.
- Enum Properties fixed ("Producer" is working now).


You can add information to Mcu Monitor, it is not as nice as your Z80 Monitor, but it's a consistent interface for all devices.
Look at Z80 constructor, there you can add "Registers" and "Variables" to the lists in "CPU" section in Mcu Monitor.
"Registers" and "Variables" can be any information you want, it just correspond to upper and lower lists in "CPU" section;

Mcu Monitor will call these functions to get values for those "Registers" and "Variables":
int Z80Core::getCpuReg( QString reg ) // Called by Mcu Monitor to get Integer values
QString Z80Core::getStrReg( QString reg ) // Called by Mcu Monitor to get String values

You need to implement that part too.

23Implementing processor Z80 Empty Re: Implementing processor Z80 Sat Oct 22, 2022 8:34 am

vranik



I added registers and variables to MCU monitor and fixed some errors in timing. In addition I put classes with flags and 16 bits registers to separate file for better readability. I am not sure if I should keep decoding instruction opcode into string in file z80core.cpp. This feature is not implemented for AVRs thus I can't copy it. Smile The attached source code is based on trunk revision 1341. I still didn't change comments yet.

By the way I found an error in file ioport.cpp where the variables "changed" should be type uint32_t instead of uint8_t.

For debugging I would appriciate that the logic analyser would be able to display values of data and address bus as a number not only logic state of individual bits.
Attachments
Implementing processor Z80 Attachmentz80core_R1341.zip
You don't have permission to download attachments.
(27 Kb) Downloaded 3 times

24Implementing processor Z80 Empty Re: Implementing processor Z80 Sat Oct 22, 2022 9:33 am

arcachofo

arcachofo

Thanks.

Your changes applied at Rev 1373.
IoPort issue solved at Rev 1374.

I am not sure if I should keep decoding instruction opcode into string in file z80core.cpp. This feature is not implemented for AVRs thus I can't copy it.
I think it is ok by now.
Maybe we can implement this for all CPUs.

For debugging I would appriciate that the logic analyser would be able to display values of data and address bus as a number not only logic state of individual bits.
I have this feature in mind.
Still thinking about how to implement it, there are many issues to solve.





25Implementing processor Z80 Empty Re: Implementing processor Z80 Sat Jul 08, 2023 6:33 am

vranik



Would it be possible to rename component Z80 to Z80CPU now? There are exists other chips as Z80DMA, Z80CTC, Z80PIO, Z80SIO, ... And would it be possible to swap position of pins /RD a /WR in Z80 logic symbol? Thanks.

Sponsored content



Back to top  Message [Page 1 of 2]

Go to page : 1, 2  Next

Permissions in this forum:
You cannot reply to topics in this forum