Open vipoo opened 5 months ago
Last night i did an experiement with the eZ80 instruction RST.L 8
This can be used by code running in the Z80 compatible mode, to jump to a function in the firmware - outside of the 64k address range.
Its only 2 bytes long, uses the SPL stack, not the Z80 compatible 16 bit stack (SPS).
So I think i might make something like the following work :
OUT (nn), A
, we precede this will just the 2 bytes for the RST.L
instruction (bytes: $49 $CF
). OUT
as OUT ($FFnn), A
It looks like you are using the Zeta 2 MMU, which is ideal as a mechanism for this. I am? Not sure what that is. I basically just copied the standard config for RCZ80. I went through and disabled all the drivers etc for the time being. Then added a driver for the eZ80 UART. I also added a new
CPUFAM
andPLATFORM
config entries
Yes, implicitly you are. The 512K RAM/ROM module MMU is the Zeta 2 MMU.
1. In the implementation of
HBX_BNKSEL
, can I use the stack?
Yes. Since HBX_BNKSEL is a CALLed function, a valid stack must already exist (and already be in high 32K). You will notice that the API invocation and interrupt framework go to some trouble to ensure this. If a user calls HBX_BNKSEL they are required to have a stack established in high RAM.
I need to use the
OUT (C), r
instruction --- which is technicallyOUT (BC), r
.
Right.
This necessitated the use of BC register - so I had saved it onto the stack - then i was wondering if I was having a stack issue. I did try saving it in the alt registers (EXX). I think pushing onto the stack would work - but at the time of coding, I was having a hardware issue. (hardware issue since resolved). But yet to test this fully. But I do wonder if I can use the stack at all in the function? What if the function is swapping the segment with the stack ? If I cant use the stack, I can probably just use a couple of bytes in the on-chip's RAM.
Stack should be fine. It will be in high RAM.
Just as I type, I am wondering if I can implement a pseudo function to enable doing the i/o with out need to set the B register - hmmm - I think the eZ80 even has hooks for illegal instructions - so hmm wondering... thinking.... ** Further progress is being made on this point - I will post a reply on how that went - should make it much easier to decorate the code to work for the eZ80 16bit IO.
Interesting idea. Let me know.
- I created a new
CPUFAM
andPLATFORM
, but I am not sure what's the best conditional variable to use herePLATFORM .EQU PLT_RCEZ80 CPUFAM .EQU CPU_EZ80
But I have only used CPUFAM for the conditional test --- as mentioned above, not sure what would be best approach here.
You did this right. If possible, use CPUFAM for the conditionals. Ideally, over time, there would be the ability to put an eZ80 in other platforms. The use of PLT_RCEZ80 would be useful for maintaining a platform that has the eZ80 internal peripherals.
3. What function belong in the on-chip ROM and what belongs in the RomWBW image?
The eZ80 will boot into its on-chip ROM (its initially mapped at address $000000). The on-chip ROM and RAM will be super fast - with minimal wait-states, unlike the external RC2014 ram module.
So I am thinking that the 'firmware' on the eZ80 is responsible for booting, setting up RAM/IO address ranges, wait states, address modes, and the initialize all the on-chip services (uarts, timers & counters, interrupts, the RTC, etc.). It should be 'agnostic' of RC2014 module configurations.
Once its ready, it then jumps to the first byte in the external 64K RAM address.
This sounds fine to me.
Perhaps an interface within the firmware could be made available for code such as HBIOS/RomWBW to call. This will be a table of jump functions --- allowing on-chip device configurations (baud rates etc). Also maybe a feature to copy and execute a block of code in the fast on-chip RAM.
The RomWBW would just need to initiate a far call (CALL.LIL) to access these functions.
Also fine.
Dev tool chains could be targeted for the specific platform -- I understand that the preferred approach for developing eZ80 code is to use a variant of clang that targets the eZ80 -- similar to how what has been developed for the Agon. I have not got that setup yet though. Just using the Zilog IDE which has a very old version of C (C98) but it does have an assembler to target the eZ80 instructions. This IDE is windows only (wine might work) - but it does have a nifty debugger.
I don't have any immediate thoughts on this.
- No idea what I am going to do for interrupts At the moment, I disabled INTs in the configuration. But there will be some complexity with INT management. The eZ80 mixed mode might work - but the handling of the correct version of
RETI
I think will be important.I will need to do some experimenting on this.
It looks like interrupt mode 2 would work more or less as-is, no? Have I missed something?
5. Dual CPU Mode
I don't have the hardware wired up for the Dual CPU configuration. Have no idea if my idea will even work. This will be a little bit down the track. But the general idea will be the Z80 and the eZ80 can run side by side. Only 1 processor has access to the bus (the Z80 is sent the BUSREQ to remove it, but when the Z80 is controlling the bus, the eZ80 will be isolated by buffers, with it continuing to run on its internal ROM/RAM).
This sounds great, but definitely outside my area of expertise.
Thanks!
Wayne
Last night i did an experiement with the eZ80 instruction
RST.L 8
This can be used by code running in the Z80 compatible mode, to jump to a function in the firmware - outside of the 64k address range.
Ah, OK, that explains the code I saw in your fork. I was trying to understand it and thought it was something like this. I am a little unclear how the eZ80 firmware is done. I assume that code is not in your fork?
Its only 2 bytes long, uses the SPL stack, not the Z80 compatible 16 bit stack (SPS).
So I think i might make something like the following work :
- In normal RomWBW code, where we need to do a IO operation with say
OUT (nn), A
, we precede this will just the 2 bytes for theRST.L
instruction (bytes:$49 $CF
).- This causes the PC to jump to address $000008 in the on-chip ROM.
- the SPL (long stack) is pushed with the return address - the SPL is mapped into the on-chip RAM
- The handler for this trap, can walk the stack, and inspect the next instruction, and interpret the
OUT
asOUT ($FFnn), A
- It could interpret any of the I/O instructions and ensure the upper byte is always $FF
- No SPS (local stack within 64K address) is impacted or required.
- The preceding 2 bytes can be wrapped in a simple macro thats only applied for eZ80 config builds
Very creative. My only concern would be performance impact. That sounds like quite a few instructions. Not an issue in many cases, but it probably is in the bank switching. Perhaps bank switching would just use the stack to save/restore BC.
Thanks, Wayne
Very creative. My only concern would be performance impact. That sounds like quite a few instructions. Not an issue in many cases, but it probably is in the bank switching. Perhaps bank switching would just use the stack to save/restore BC.
Hmmm... what if the entire HBX_BNKSEL routine was implemented in the on-chip ROM and a single RST.L just invoked it? Not sure if that is any better than just adding a push/pop of BC in the existing routine.
Thanks, Wayne
Very creative. My only concern would be performance impact. That sounds like quite a few instructions. Not an issue in many cases, but it probably is in the bank switching. Perhaps bank switching would just use the stack to save/restore BC.
Hmmm... what if the entire HBX_BNKSEL routine was implemented in the on-chip ROM and a single RST.L just invoked it? Not sure if that is any better than just adding a push/pop of BC in the existing routine.
I think the RST.L 8
might still be good to help with porting existing code. So perhaps a mixture of approaches.
It looks like interrupt mode 2 would work more or less as-is, no? Have I missed something?
Yeah, the interrupts of the eZ80 are always invoked in ADL mode (not the Z80 compat mode). With the complexity of multiple stacks, and the fact that the interrupt might have been triggered with the processor in ADL mode or not - well I am still figuring this out... I think it would mean that the RETI needs to be changed.
This is a section from the eZ80 manual:
In mixed-ADL applications, some of these rules may represent exceptions to the eZ80® CPU’s design goal; i.e., that legacy code does not require modification to run on the eZ80® CPU. Assuming that legacy routines are not selectively converted to ADL mode and do not call newly-written routines, the only rule that could lead to such modification is Rule 5. If each legacy Z80 mode routine ends with a single RET.L at its end, this conversion is easy. Internal and conditional RETs require more careful review.
I think the
RST.L 8
might still be good to help with porting existing code. So perhaps a mixture of approaches.
Yes!
It looks like interrupt mode 2 would work more or less as-is, no? Have I missed something?
Yeah, the interrupts of the eZ80 are always invoked in ADL mode (not the Z80 compat mode). With the complexity of multiple stacks, and the fact that the interrupt might have been triggered with the processor in ADL mode or not - well I am still figuring this out... I think it would mean that the RETI needs to be changed.
This is a section from the eZ80 manual:
In mixed-ADL applications, some of these rules may represent exceptions to the eZ80® CPU’s design goal; i.e., that legacy code does not require modification to run on the eZ80® CPU. Assuming that legacy routines are not selectively converted to ADL mode and do not call newly-written routines, the only rule that could lead to such modification is Rule 5. If each legacy Z80 mode routine ends with a single RET.L at its end, this conversion is easy. Internal and conditional RETs require more careful review.
Gotcha. I also responded on the Google Group. I think we are still OK. Under RomWBW, we just need to transition back to Z80 mode at the start of the interrupt. If the ADL interrupt vectors point to corresponding CALL.L statements, we should be fine. The RETI.L at the end is easy.
Thanks, Wayne
I have posted my ez80 firmware code to a new repo: https://github.com/dinoboards/rc2014-ez80-firmware/tree/main
Its a project for the Zilog ZDS IDE. So windows and rather old school....
I have posted my ez80 firmware code to a new repo: https://github.com/dinoboards/rc2014-ez80-firmware/tree/main
Thanks!
Hi @vipoo,
I would like to make sure I understand the memory map you are using for the eZ80. I'm not sure I am looking at the right places in the firmware source.
Can you clarify/confirm the above?
Thanks! Wayne
Hi Wayne (its still me Dean - just using my alt github account that i am trying to move all my retro stuff too)
On-Chip ROM (128K) seems to be at 0x000000. I think I have that right. Yep
On-Chip RAM (8K) seems to be at 0xB7E000. Is that right? Yep
External Memory (64K window into 512K RAM/ROM) is unclear to me. I see MBASE set to 0xB9 implying 0xB90000. Is that right? Yep
The problem with the ZDS IDE is it has a lot of settings hidden in project files. Gonna refactor some of that now to be a little more readable/understandable - and use less of the IDE project's 'configuration' files
Dean
Thank you Dean. Glad I got it right. As you say, it is a little convoluted.
Thanks, Wayne
Hi Wayne,
Today i am trying to get the Compact Flash module working. But something not quite right. It seems to get the size of the unit wrong - and any attempt to initdir
or clrdir
does not seem to have any effect.
I updated the code to use ensure IO range of $FF1x for my CF module. It seems to detect there is a module installed, but it get scrambled. Its almost certainly something not implemented right be me --- but not sure what.
The CF card I have - was the one I got from spencer as part of the original kit (128Mb) - but its since been reformatted to a standard FAT image (done as part of my MSX build)
I turned on the tracing - wonder if you could parse your eye over this - and tell me what I should be expecting?
RomWBW HBIOS v3.5.0-dev.45, 2024-06-08
RCBus [RCEZ80_std] eZ80 @ 18.432MHz
0 MEM W/S, 1 I/O W/S, Z2 MMU
512KB ROM, 512KB RAM, HEAP=0x54A3
ROM VERIFY: 00 00 00 00 PASS
MD: UNITS=2 ROMDISK=384KB RAMDISK=256KB
IDE: IO=0x10 MODE=RC
IDE: RESET
IDE: SELUNIT MASTER
IDE: PROBE 50 E0 50 50 AA 55 [50 E0 00 55 AA 01 01]
IDE: INITDEV [50 E0 00 55 AA 01 01]
IDE: SETFEAT E0 01 EF --> 50
IDE: IDDEV E0 EC --> 58 GET 58
IDE: SIG=0x5A47
IDE: SELUNIT SLAVE
IDE: PROBE 58 F0 00 C1
IDE: NO MEDIA [00 C1 C1 C1 C1 C1 C1]
IDE0: ATA 8-BIT LBA BLOCKS=0x5A5A5A5A SIZE=740171MB
IDE1: NO MEDIA
Unit Device Type Capacity/Mode
---------- ---------- ---------------- --------------------
Char 0 Terminal0: RS-232 150,5,N,1
Disk 0 MD0: RAM Disk 256KB,LBA
Disk 1 MD1: ROM Disk 384KB,LBA
Disk 2 IDE0: Hard Disk 740171MB,LBA
Disk 3 IDE1: Hard Disk --
RCBus [RCEZ80_std] Boot Loader
Boot [H=Help]:
Hi Dean,
At first glance, this really looks like the frequent data transfer integrity issue that occurs with the CF Card module. Note "BLOCKS=0x8A8A8A8A". This kind of repeating data is a sign of that. Try moving the module to a different slot and/or try different media if possible. It is possible that the signaling characteristics of the eZ80 are exacerbating the common module issues.
Thanks,
Wayne
On Fri, Jun 7, 2024 at 11:30 PM Dean Netherton @.***> wrote:
Hi Wayne,
Today i am trying to get the Compact Flash module working. But something not quite right. It seems to get the size of the unit wrong - and any attempt to initdir or clrdir does not seem to have any effect.
I updated the code to use ensure IO range of $FF1x for my CF module. It seems to detect there is a module installed, but it get scrambled. Its almost certainly something not implemented right be me --- but not sure what.
The CF card I have - was the one I got from spencer as part of the original kit (128Mb) - but its since been reformatted to a standard FAT image (done as part of my MSX build)
I turned on the tracing - wonder if you could parse your eye over this - and tell me what I should be expecting?
RCBus [RCEZ80_std] eZ80 @ 18.432MHz 0 MEM W/S, 1 I/O W/S, Z2 MMU 512KB ROM, 512KB RAM, HEAP=0x54A7 ROM VERIFY: 00 00 00 00 PASS
MD: UNITS=2 ROMDISK=384KB RAMDISK=256KB IDE: IO=0x10 MODE=RC IDE: RESET IDE: SELUNIT MASTER IDE: PROBE 50 E0 50 50 AA 55 [50 E0 00 55 AA 01 01] IDE: INITDEV [50 E0 00 55 AA 01 01] IDE: SETFEAT E0 01 EF --> 50 IDE: IDDEV E0 EC --> 58 GET 58 IDE: SIG=0x8A47 IDE: SELUNIT SLAVE IDE: PROBE 58 F0 00 AA 55 [00 F0 00 55 AA 00 00] IDE: INITDEV [00 F0 00 55 AA 00 00] IDE: INITPDEV IDE: IDPKTDEV F0 A1 --> 00 IDE: NO MEDIA [00 F0 00 55 AA 00 00] IDE0: ATA 8-BIT LBA BLOCKS=0x8A8A8A8A SIZE=1134929MB IDE1: NO MEDIA
Unit Device Type Capacity/Mode
Char 0 Terminal0: RS-232 150,5,N,1 Disk 0 MD0: RAM Disk 256KB,LBA Disk 1 MD1: ROM Disk 384KB,LBA Disk 2 IDE0: Hard Disk 86353MB,LBA Disk 3 IDE1: Hard Disk --
RCBus [RCEZ80_std] Boot Loader
Boot [H=Help]:
— Reply to this email directly, view it on GitHub https://github.com/wwarthen/RomWBW/issues/400#issuecomment-2155835803, or unsubscribe https://github.com/notifications/unsubscribe-auth/AATNT2MKWGLQTG45TWPNQ4DZGKQIJAVCNFSM6AAAAABIXSN7USVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJVHAZTKOBQGM . You are receiving this because you were assigned.Message ID: @.***>
Hmm. Ok thanks. I didn't think of that. Never experienced any issue with it in a z80 config.
I will try the usual change slot change etc...
But I do wonder if it's similar to the issue I had with the 74htx670 struggling with the ez80 timing sequence.
I will do some research.
Dean
On Sun, 9 June 2024, 12:27 am Wayne Warthen, @.***> wrote:
Hi Dean,
At first glance, this really looks like the frequent data transfer integrity issue that occurs with the CF Card module. Note "BLOCKS=0x8A8A8A8A". This kind of repeating data is a sign of that. Try moving the module to a different slot and/or try different media if possible. It is possible that the signaling characteristics of the eZ80 are exacerbating the common module issues.
Thanks,
Wayne
On Fri, Jun 7, 2024 at 11:30 PM Dean Netherton @.***> wrote:
Hi Wayne,
Today i am trying to get the Compact Flash module working. But something not quite right. It seems to get the size of the unit wrong - and any attempt to initdir or clrdir does not seem to have any effect.
I updated the code to use ensure IO range of $FF1x for my CF module. It seems to detect there is a module installed, but it get scrambled. Its almost certainly something not implemented right be me --- but not sure what.
The CF card I have - was the one I got from spencer as part of the original kit (128Mb) - but its since been reformatted to a standard FAT image (done as part of my MSX build)
I turned on the tracing - wonder if you could parse your eye over this - and tell me what I should be expecting?
RCBus [RCEZ80_std] eZ80 @ 18.432MHz 0 MEM W/S, 1 I/O W/S, Z2 MMU 512KB ROM, 512KB RAM, HEAP=0x54A7 ROM VERIFY: 00 00 00 00 PASS
MD: UNITS=2 ROMDISK=384KB RAMDISK=256KB IDE: IO=0x10 MODE=RC IDE: RESET IDE: SELUNIT MASTER IDE: PROBE 50 E0 50 50 AA 55 [50 E0 00 55 AA 01 01] IDE: INITDEV [50 E0 00 55 AA 01 01] IDE: SETFEAT E0 01 EF --> 50 IDE: IDDEV E0 EC --> 58 GET 58 IDE: SIG=0x8A47 IDE: SELUNIT SLAVE IDE: PROBE 58 F0 00 AA 55 [00 F0 00 55 AA 00 00] IDE: INITDEV [00 F0 00 55 AA 00 00] IDE: INITPDEV IDE: IDPKTDEV F0 A1 --> 00 IDE: NO MEDIA [00 F0 00 55 AA 00 00] IDE0: ATA 8-BIT LBA BLOCKS=0x8A8A8A8A SIZE=1134929MB IDE1: NO MEDIA
Unit Device Type Capacity/Mode
Char 0 Terminal0: RS-232 150,5,N,1 Disk 0 MD0: RAM Disk 256KB,LBA Disk 1 MD1: ROM Disk 384KB,LBA Disk 2 IDE0: Hard Disk 86353MB,LBA Disk 3 IDE1: Hard Disk --
RCBus [RCEZ80_std] Boot Loader
Boot [H=Help]:
— Reply to this email directly, view it on GitHub https://github.com/wwarthen/RomWBW/issues/400#issuecomment-2155835803,
or unsubscribe < https://github.com/notifications/unsubscribe-auth/AATNT2MKWGLQTG45TWPNQ4DZGKQIJAVCNFSM6AAAAABIXSN7USVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJVHAZTKOBQGM>
. You are receiving this because you were assigned.Message ID: @.***>
— Reply to this email directly, view it on GitHub https://github.com/wwarthen/RomWBW/issues/400#issuecomment-2156056913, or unsubscribe https://github.com/notifications/unsubscribe-auth/BDRG3PS66KPGPOO6O6HUTHLZGMIFHAVCNFSM6AAAAABIXSN7USVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJWGA2TMOJRGM . You are receiving this because you commented.Message ID: @.***>
Hi Wayne,
I am about to go travelling for the next week. So I thought I would just share some details of the latest updates/progress I have made.
As of writing, I was unable to the get my version of the Compact Flash module to work. My module is the very first iteration - it does not have an RC to delay the control signal - nor does it have the additional timing logic that the V2. I will come back to figuring this out.
Got my RP5C01 RTC module to work. Updated the rp5rtc.asm
file to 'prefix' the OUT
and IN
operations to ensure they target the external I/O address range. All seems good.
Next I worked on my V9958 video module. Again, prefix the OUT
and IN
operators - and all good. Had the cpm console redirected to the CRT - cool! (interrupt logic disabled)
So having 2 modules working - give me confidence that many other modules will work. I had these modules interfacing just fine, despite the fact I had overclocked my eZ80 to 24Mhz. The configuration for the bus access is such, that from the individual modules perspective, the address/data and controls signals are the same as per a normal Z80 running around ~6Mhz.
I have, I think, mentioned in previous post about the configuration of the eZ80 -- below is a summary of the current config:
SPL
) - with ability to access the full 16MB linear address range.MBASE
register.config.inc
file.ADL or Z80 or Mixed Mode
I thought I would share my thinking around the possible options for configuring the CPU address/operating mode, as there are technically a few options:
Operate in ADL mode exclusively. This means all software operates on 24bit registers and addresses. Interrupts are invoked in ADL mode.
Operate in Z80 mode exclusively. This means, on poweron/reset, the code in the onboard rom ($000000), simply configures the MBASE
register - and then switches to Z80 mode. Interrupts would be invoked in Z80 mode, and operate much the same way as a Z80 processor using a vector jump table.
Operate in MADL (mixed mode). The option I have gone with.
RST.L $XX
instruction (using helper macros)RETI
instruction is changed to RET.L
Switch between ADL and Z80 mode
RST
s are invoked.I
register needs to be configured to a table of 52 16bit words for each potential interrupt.I
register would need to be a single value that would be correct for both Z80 and ADL execution modes. Interrupt now working
So given all that, I proceeded to build the interrupt support code, using the V9958's HSYNC int signal, that the tms.asm
implements to track the 50/60Hz timing counter.
The eZ80 interrupt handler for the external INT line (mapped to GPIO pin PB4), will marshal the interrupt to the RomWBW interrupt handler (by invoking RST.S %38
). The RomWBW handler now ends with a RET.L
instruction
If the interrupt was triggered when the processor was in ADL mode, then the eZ80 handler will save/restore the 24bit registers.
It does mean the interrupt processing can be a little bit slow though - all things considering. When I am back I might look at not using MADL - and just have 2 interrupt vector tables and associated handlers.
Cheers Dean
Wow, awesome progress Dean. I don't have time to fully review your comments this weekend, but will do so soon.
Thanks!
Wayne
Hi @dinoboards,
Sorry for the slow response. Thank you for the thorough description of the eZ80 project status. Seems to be going really well. I'll just comment on a couple things.
Regarding the operating mode, I like the MADL mode you are currently using. The ability to hook interrupts and RST calls with eZ80 code is very powerful. Since you have proven that the RomWBW interrupt framework can be adapted to this (via marshalling), this seems like a good way to go.
As you have pointed out, the trickiest part of this going forward is supporting the internal ROM. In addition to your valid point that the internal ROM must be properly matched with the external ROM, there is also the issue of building the internal ROM.
With respect to coordinating the ROMs, I wonder if the internal ROM could pass a version number to the external ROM when it initially transfers control? The external ROM could probably boot far enough to issue a warning if it does not like the internal ROM version.
Building the internal ROM is another question. As far as I know, the Zilog assembler is the only viable option. From what I understand this toolchain is too large to imbed in the RomWBW distribution, not to mention I think it is a Windows-only tool. The fallback solution would be to include the source in the RomWBW distribution along with a pre-built binary. Do you have any other thoughts?
Thanks, Wayne
Regarding the operating mode, I like the MADL mode you are currently using. The ability to hook interrupts and RST calls with eZ80 code is very powerful. Since you have proven that the RomWBW interrupt framework can be adapted to this (via marshalling), this seems like a good way to go.
Cool. I only have one hardware module that I can use for testing, that will generate interrupts - my V9958 VDP video module. The 50/60Hz timer. (And I have since implemented a 60Hz timer using the on-chip timers -- so a lot more efficient).
With the way the hardware/gpio pins work on the ez80, there can only be a single interrupt handler in RomWBW. No vectors or fancy interrupt mode stuff. The eZ80 can only work in IM2 mode (technically the ez80f92 chip forces the eZ80 to run only in IM2) , with the various on-chip and GPIO mapped to a specific jump address in the vector table. But as far as HBIOS is concerned, the processor is working in IM1 mode -> $0038.
With respect to coordinating the ROMs, I wonder if the internal ROM could pass a version number to the external ROM when it initially transfers control? The external ROM could probably boot far enough to issue a warning if it does not like the internal ROM version.
Yep - agree - was thinking of something like this.
Updating the eZ80 on-chip flash can only be programmed with Zilog's Acclaim smart cable (cost ~$100US).
I believe it is possible to write code to flash the chip -- so I could write a simple cp/m app to flash a new version of the firmware - but with the usual risk, that if something goes wrong during the reflashing - then the only recovery option would be to use the smart cable.
Building the internal ROM is another question. As far as I know, the Zilog assembler is the only viable option. From what I understand this toolchain is too large to imbed in the RomWBW distribution, not to mention I think it is a Windows-only tool. The fallback solution would be to include the source in the RomWBW distribution along with a pre-built binary. Do you have any other thoughts?
I agree that this code and tool-chain would not be a great fit within your repo - but perhaps a sub-module. I did manage to use wine to run the tool-chain - I may try and get my firmware repo to have a github-actions script to build the project -- using a bit of docker magic. I want to think and experiment some more with the tool chain.
I have pushed some more recent changes to the RomWBW branch, and my firmware repo. Have got things like the RTC working, a 60Hz timer and cleaned up the interfacing between HBIOS and the eZ80 firmware.
I also managed to get my Compact Flash module working (after some hardware changes). But it only works when i clock the eZ80 at 7Mhz. I think I understand why it wont work at higher clock speeds - and have some ideas to apply to the hardware to make it work.
The timing issue is not just about compatibility with CF module. -- the timing is generally a bit marginal at the moment for certain I/O writes for certain modules. Have a new PCB on the way that hopefully improves things a bit.
Cheers Dean
PS: Once I get the hardware somewhat stable, I would really like to send you an assembled/working kit -- if you would be interested....
Thanks for the update @dinoboards.
Cool. I only have one hardware module that I can use for testing, that will generate interrupts - my V9958 VDP video module. The 50/60Hz timer. (And I have since implemented a 60Hz timer using the on-chip timers -- so a lot more efficient).
Great. Does the on-chip timer need to be 60 Hz? RomWBW normally uses a 50 Hz timer mostly because it is convenient for playing audio files.
With the way the hardware/gpio pins work on the ez80, there can only be a single interrupt handler in RomWBW. No vectors or fancy interrupt mode stuff. The eZ80 can only work in IM2 mode (technically the ez80f92 chip forces the eZ80 to run only in IM2) , with the various on-chip and GPIO mapped to a specific jump address in the vector table. But as far as HBIOS is concerned, the processor is working in IM1 mode -> $0038.
I'm a little confused here. The CPU is in IM2. Are you saying that all of the vectors in the vector table point to $38 of Z80 address space? Could they point to someplace in the HBIOS proxy instead?
Updating the eZ80 on-chip flash can only be programmed with Zilog's Acclaim smart cable (cost ~$100US).
I believe it is possible to write code to flash the chip -- so I could write a simple cp/m app to flash a new version of the firmware - but with the usual risk, that if something goes wrong during the reflashing - then the only recovery option would be to use the smart cable.
I didn't realize a $100 cable is required for direct programming. Unfortunate. In-situ programming is an option, but as you say, it can be a problem if anything goes wrong.
Building the internal ROM is another question. As far as I know, the Zilog assembler is the only viable option. From what I understand this toolchain is too large to imbed in the RomWBW distribution, not to mention I think it is a Windows-only tool. The fallback solution would be to include the source in the RomWBW distribution along with a pre-built binary. Do you have any other thoughts?
I agree that this code and tool-chain would not be a great fit within your repo - but perhaps a sub-module. I did manage to use wine to run the tool-chain - I may try and get my firmware repo to have a github-actions script to build the project -- using a bit of docker magic. I want to think and experiment some more with the tool chain.
OK, something to work through.
Further commits/updates
I have pushed some more recent changes to the RomWBW branch, and my firmware repo. Have got things like the RTC working, a 60Hz timer and cleaned up the interfacing between HBIOS and the eZ80 firmware.
Nice.
I also managed to get my Compact Flash module working (after some hardware changes). But it only works when i clock the eZ80 at 7Mhz. I think I understand why it wont work at higher clock speeds - and have some ideas to apply to the hardware to make it work.
At least it is working!
The timing issue is not just about compatibility with CF module. -- the timing is generally a bit marginal at the moment for certain I/O writes for certain modules. Have a new PCB on the way that hopefully improves things a bit.
OK
PS: Once I get the hardware somewhat stable, I would really like to send you an assembled/working kit -- if you would be interested....
I would very much like to get one of these when stable and convenient. I would like to compensate your for the parts and shipping (at a minimum). No rush though.
Thanks,
Wayne
Great. Does the on-chip timer need to be 60 Hz? RomWBW normally uses a 50 Hz timer mostly because it is convenient for playing audio files.
Nop - I can change that - in fact, I think I can make it configurable as per the HBIOS configuration file.
I'm a little confused here. The CPU is in IM2. Are you saying that all of the vectors in the vector table point to $38 of Z80 address space? Could they point to someplace in the HBIOS proxy instead?
Yeah - its confusing... Only one of the vectors in the table is marshalled into HBIOS. This is ISR at vector address 38H - which is tied to a GPIO pin (PB4). And this GPIO is wired to the RCBUS's interrupt line. So when a hardware device activates the int signal, the GPIO pin's coresponding interrupt vector routine is executed, which has a handler that delegates to HBIOS.
There are only a couple of other ISR routines in the vector table - one for the on-chip UART, and one for the re-programmable timer (current set to 60hz). These 2 ISR are all managed in the on-chip ROM.
You can see the implemented ISRs in this file https://github.com/dinoboards/rc2014-ez80-firmware/blob/main/src/startup/vectors16.asm#L139
I am feeling a bit of an achievement tonight!
I have think I have solved the hardware compatibility issues, for interacting with such things as the Compact Flash Module. And the timing for the RAM/ROM bank switching ports is now not so marginal.. timings should be in spec.
I now have Spencer's Compact Flash module (version 0). Tested with eZ80 overclocked to 24Mhz.*
Got my version of CH376 USB module working at full speed. Also tested with eZ80 running at 24Mhz
UART fully implemented. I can now use apps like MODE
to change the serial baud and control parameters.
CPU clock frequency auto detected and reported during HBIOS start up.
HBIOS platform configuration can now control the Bus Cycle setting for the eZ80 memory and I/O.(there is no way to configure wait states, instead you configure the eZ80 to map clock ticks to T-STATES. So with a Bus Cycle of 4, a read/write operation will happen over the usual Z80 3 T-STATES, where each T-STATE take 4 CPU clocks. ) The current Bus Cycle setting is reported within the HBIOS boot report.
** The V2 of the Compact Flash module may prove more challenging. As this module uses the RC2014' bus clock (which is typically the CPU's clock). For the eZ80 system, I have not connected the CPU clock to the bus clock. I have used one of the Programmable Timers to create a slower bus clock.
The issue for the V2 compact flash module, will be the different phasing of the bus clock. When an I/O operation is initiated, the slower bus clock might be about to change state, or it might have just changed state....
I have purchased the V2 version, so will see if I can make it work also.
But i might work on other modules first - sounds, keyboards, etc....
Cheers Dean
Hi @dinoboards,
Thanks for the interrupt explanation. I think there might be a way to improve this to some extent in the future, but I see what is going on at this point.
Excellent progress all around!
Thanks for the update!
-Wayne
Hi Wayne,
Me again.
I have been making steady progress on the porting for eZ80 - at least for CP/M
I would expect that there would still be issues with any application or other OS systems that do any I/O - Basic for example -- its OUT/IN commands would not apply a 16bit IO address. There are a lot of services/apps etc that do direct I/O - not sure how far you would want the support for eZ80 to be extended to.
I think i have finally got the hardware design stable. The latest revisions seem good to me - (no bodges required). I had the CPU modules factory assembled now - so a bit easier to get a working system (still lots of through hole components that require soldering - to keep it fun!)
Over the weekend, I was able to get a firmware update process working - without the need for the external Zilog programmer. The eZ80 still needs an initial image programmed in. This image includes a full working firmware (with the boot loader) - it is flashed to the first 64K of ROM space in the on-chip ROM.
And then with a new CP/M application I am wiring, I can 'flash' an alternative firmware image in the 2nd 64K of the on-chip rom (0x010000-0x01FFFF).
The main image will still boot, but detect the alternative image and has been flashed, and so will switch over to it. And if this 2nd (alternative) firmware fails to boot, a reset should cause the 1st (main) firmware to be used.
Of course, there still a risk that a software error causes the on-chip firmware to be non-functioning - and the only recovery option would be the external programmer - I don't think i can totally eliminate that issue (This is the external programmer I purchased: https://au.mouser.com/ProductDetail/ZiLOG/ZUSBASC0200ZACG?qs=IPgv5n7u5QaRBsLmFgyelw%3D%3D)
I cant imagine you would be in a position to accept any PRs I generate without working hardware to review and verify yourself - so I am happy and keen, if you are happy also, to send you a working eZ80 module. Can you email me the address you would like me to post it to. (dean.netherton at gmail.com)
Dean
I do believe it will be possible to build a programmer with something like a Pi Pico or other microcontroller. The ZDI interface is similar (but sufficient different) to SPI - so I guess manually driving some GPIO should work - the registers and commands seemed to be defined sufficiently in the relevant manuals. Another future project for sure
Hi @dinoboards,
This sounds great. I am going to want one of the programmers regardless, so I will be ordering one of them. I hope that eZ80 becomes a more common alternative for RomWBW over time.
Indeed, I would prefer to have hardware sufficient to confirm things are working. I will send you an email to puruse this.
Thanks! Wayne
Hi Wayne,
I see you've merge the mega commit - wow that was fast - was expecting it would take a little while.
only had one question about your Pull Request. You have modified the Makefile's to reduce their verbosity (removed -x from .SHELLOPTIONS and added '@' in front of some commands. This certainly makes the output much cleaner, but I am a little worried it will be harder to chase down build issues in the future. Please let me know your thoughts on this.
Of course this is entirely your preference. I usually just use the command like options --debug
and/or --trace
when invoking the make command if I need to see what its doing. - or just temporarily turn em back on within a specific task if I am trying to hunt down a build issue. But as most of the time the makefiles just work - i found it far easier and quicker to see and identify any assembly errors.
I did an offline merge and found a few minor things that I needed to change to get a clean build on both Linux and Windows. Windows and Linux use different assemblers that are theoretically identical, but they both have some idiosyncracies. I had to make some adjustments due to this.
Oh yes of course - i didn't even think to check for the window builds - kind of assumed the same tool set -- bad me. Haven't look at your fixes yet, i assume this might be in regards to some of the macros I added to help target the ez80?
Hopefully this evening, my time, I will be able to pull your fixes and understand
I expect future PRs will be much smaller. Probably over the coming weekend I will get the SN76489 changes applied correctly, and submit the PR for it.
Thanks again
Hi Dean,
Your code was very clean and well segregated from the existing stuff. Not hard to work through and I was anxious to get to a merged base so we could get to incremental updates.
I just merged your PR which seems to clean up the stragglers. I have completed some cursory testing on my common test hardware with zero issues. So, I am going to go ahead and post a new Development Snapshot. I am still holding off on including pre-built binaries for eZ80. Since the hardware is not yet generally available, I think this makes sense.
I look forward to receiving my eZ80 hardware and getting up and running myself!
For now, feel free to issue incremental PRs as you like.
Thanks, Wayne
Hi @dinoboards,
Had some time today to do some compatibility testing. Here are the results along with the changes I made in some cases. Overall very good results. I will be checking in my work shortly.
I did encounter one mystery when working on the IDE driver. It appears that when doing a port read for an unoccupied port, the EZ80_IO macro winds up returning $00. However, doing an IN A,(C) with B set to $FF, returns $CD. The $CD is what I would normally expect.. It appears that port reads in ADL mode are returning $00 for unoccupied ports. I have worked around this in the IDE driver, but curious if you know why this would be.
Thanks, Wayne
Hi @wwarthen
Fantastic stuff. Exciting... Below are my thoughts
I did encounter one mystery when working on the IDE driver. It appears that when doing a port read for an unoccupied port, the EZ80_IO macro winds up returning $00. However, doing an IN A,(C) with B set to $FF, returns $CD. The $CD is what I would normally expect.. It appears that port reads in ADL mode are returning $00 for unoccupied ports. I have worked around this in the IDE driver, but curious if you know why this would be.
The macro help might be missing a scenario or just broken - i will have a look asap
IDE: works - Increased DELAY -- too short for Pico SD
Is this the extra CALL DELAY
added to VDELAY:
?
One of the things I tried to do was to verify the DELAY function does indeed delay the approx 16us - regardless of CPU frequency. If VDELAY
calls DELAY
3 times, I would think that would cause VDELAY
to be longer than specified?
Was this an issue with just the SD IDE or a more general problem?
I certainly found it challenging to introduce appropriate delays - given the way the cpu's pipelining and wait states contribute to effective execution time.
CHUSB: working in some cases CH375 works CH376 not working
Hmm - odd. I have my CH376 module - i assume its mostly the same as the other kits based around the CH376 module. I dont have a CH375. my CH376 was working - but perhaps there has been a regression, or perhaps there is a difference in the specific kits.
KBD: not working Added EZ80_IO macros throughout driver
I assume you mean its not working, despite you placing the EZ80_IO macro everywhere?
Do you think its another timing issue? Or perhaps maybe the macro helper has another bug?
Cheers Dean
Hi @dinoboards,
Well, I think the EZ80_IO macro and associated firmware code are working fine. Zero issues. It just seems to behave differently when reading an unoccupied port. Since such operations are essentially undefined, this is not an error per se. Just a curiosiry really.
Yes, I was referring to the extra calls to DELAY in VDELAY. I didn't take the time to try and be exact about it, but there is a place in the code that should try for 5 seconds. It is pretty exact on other hardware. It was about 2 seconds when run on eZ80. So, I added more calls. Feel free to take a whack at making it exact, but it was definitely "short" for me. The problem only manifested with the Pico SD in my testing, but the VDELAY routine is critical in many places in the code.
Now that I know you have a CH376 working, I may play with it some more. I need to figure out how to manipulate the I/O wait states as a start.
Correct, I was unable to get reliable communication with a keyboard using the KBD driver. Yes, I had already place the EZ80_IO macro. It felt like perhaps an issue with the I/O pulse not being long enough, but really not sure. I need to do more work.
I will puruse this, but it may be a few days before I can get back to it. Very busy weekend.
Thanks, Wayne
Changing EZ80_IO_MIN_WS from 7 to 8 in the RomWBW config resolves the issues with both the CH376 and the PS/2 KBD driver.
I realize that this implies a change from eZ80 bus cycles to Z80 bus cycles, but I don't currently know the implications of that.
Thanks, Wayne
Well, I think the EZ80_IO macro and associated firmware code are working fine. Zero issues. It just seems to behave differently when reading an unoccupied port. Since such operations are essentially undefined, this is not an error per se. Just a curiosiry really.
You are far more trusting of my code than I 😏. I would have expected my macro would do that same as your explicit code and return what ever the data lines float to. Will have a look...
Yes, I was referring to the extra calls to DELAY in VDELAY. I didn't take the time to try and be exact about it, but there is a place in the code that should try for 5 seconds. It is pretty exact on other hardware. It was about 2 seconds when run on eZ80. So, I added more calls. Feel free to take a whack at making it exact, but it was definitely "short" for me. The problem only manifested with the Pico SD in my testing, but the VDELAY routine is critical in many places in the code.
Hmm. OK. Sounds like an inconsistency between the DELAY and VDELAY's loop over DELAY not quite adding up - some overhead/pipelining causing a time-slip!
Changing EZ80_IO_MIN_WS from 7 to 8 in the RomWBW config resolves the issues with both the CH376 and the PS/2 KBD driver.
That's cool to hear.
I realize that this implies a change from eZ80 bus cycles to Z80 bus cycles, but I don't currently know the implications of that.
That's interesting. One of the issues I have with managing I/O timing is the need to stretch the positive edge hold of the IORQ requests. The PLD has a counter, that will count and raise IORQ
and WR
a cycle before the eZ80 does (for default settings)
This counter value that's used to identify when to raise the signals is hard coded in the PLD. Its currently set to 5 clock cycles.
So increasing the wait states will increase the positive-edge hold period. Which is fine and if this fixes the issue - then it implies that its needed by the KBD/CH376 driver.
The only real implication is a general performance hit - as now all IO requests will take that bit longer - including bank switching.
I guess its technically possible to change the IO wait states prior to specific io operations (eg: only have this wait state applied when doing KBD IO. Maybe another macro (EZ80_SLOW_IO
). Not sure....
Yes, I was referring to the extra calls to DELAY in VDELAY. I didn't take the time to try and be exact about it, but there is a place in the code that should try for 5 seconds. It is pretty exact on other hardware. It was about 2 seconds when run on eZ80. So, I added more calls. Feel free to take a whack at making it exact, but it was definitely "short" for me. The problem only manifested with the Pico SD in my testing, but the VDELAY routine is critical in many places in the code.
Hmm. OK. Sounds like an inconsistency between the DELAY and VDELAY's loop over DELAY not quite adding up - some overhead/pipelining causing a time-slip!
Ok - my bad - yep -- i see now. the eZ80 version of VDELAY
was not correct - and your commit fixed it.
DELAY
-> invokes the MACRO EZ80_DELAY
(RST.L $18
) - 3 are needs to get an approx 16-17us delay
VDELAY
-> also invokes said MACRO (but was only invoking it once) - as it inlines DELAY
, it needs to do three calls also
Well, I think the EZ80_IO macro and associated firmware code are working fine. Zero issues. It just seems to behave differently when reading an unoccupied port. Since such operations are essentially undefined, this is not an error per se. Just a curiosiry really.
You are far more trusting of my code than I 😏. I would have expected my macro would do that same as your explicit code and return what ever the data lines float to. Will have a look...
Hmm. I doubled check and tested the implementation for the macro for IN A, (C)
and it appears all correct.
My guess is as the read is performing a request where nothing will drive the data lines - they float - and what state they are in could be influence by what was executed before. Maybe the ADL/Z80 mode has an influence - but i doubt it.
I did a test on my rig. I queried an address with nothing connected. I placed some pull up resistors on a couple of data lines. The value returned was aligned with the pullups. So the data lines were defaulting to 0 - without the pullups.
I got the same value when running in Z80 mode and when using the helper macro (RST.L)
And I would guess that some rigs could have different experiences - depending on the capacitance/load on the data lines.
As such, I cant reproduce the issue you are having.
The only suggestion I have at this stage, is you may want to replace LD B, 0xFF
with LD B, IO_SEGMENT
Cheers
Yes, I think it is simply that the data lines are floating (normal when nothing is responding at the port address). It appears (on my system) that the floating data read when in ADL mode is different than in Z80 mode. This is entirely reasonable. I am curious what value you get if you use the RomWBW monitor to read an unoccupied port. The RomWBW monitor is 16 bit aware for port accesses, so you can use a command like "I FF55". On my system, I get CD as a result.
Yes, I will absolute change my workaround code to use IO_SEGMENT. Good catch.
Thanks, Wayne
I have a theory....
When I did as you asked, queried an unoccupied port with the monitor - I did indeed get 0xCD
I changed the code in the PIN:
function in the monitor - and got these results:
Code Snippet | Result of `I FF55` |
---|---|
IN A,(C)
CALL ....
|
0xCD |
IN A,(C)
NOP
CALL ....
| 0x00 |
PUSH BC
POP BC
CALL ...
| 0xC5 |
It appears that the IN
operation is reading the op code of the next instruction.
I wonder if this is a thing for a stock Z80 as well?
So my guess then is, when the IN A, (C) is performed in the on-chip ROM, the external address and data lines are not driven at all - the external RAM will be silent. -- so therefore it reads 0 - (or if you have pull ups on the data lines - it will read the floated data lines as high)
I am a little concerned this might be highlighting an issue with my design. What might be happening, is that as the PC counter will point to the next instruction, and a read is then requested (an I/O read), that somehow the RAM is responding - at least for a short period of time. We know the I/O's work ok - so perhaps by the time the I/O is performed the RAM has been released. But in the case of an unoccupied port that the floating data lines are just holding to the last driven value.
Not concerned so much with that, more just wonder if I might have a bus contention for a period of time. Gonna wire up the scope and do some more experiments
Of course, this might also just be the eZ80 doing it thing - it might be a function of the pipelining. As I type this - i would think that is very likely - as that its design - on each cycle, the eZ80 reads the next byte to processes through its instruction pipeline - so now i am wondering if this is just 'normal'
Learn something new every day!
Made a cup of tea - and thought about this a bit more
Not sure how i could test or verify...
But I seem to be convincing myself this is all totally fine and normal.
During the decoding and processing of the IN A,(C)
operation, the eZ80 will be reading the next byte from RAM for the instruction pipeline. Hence why the data lines would have been charged with the byte pattern of the op-code of the next instruction.
Dean
I suspect it is totally normal. I do know that a regular Z80 exhibits a similar behavior in many cases (depending on the loading of the data lines).
Thanks, Wayne
Then went through the start-up code and just wrapped my changes in #IF (CPUFAM == EZ80)....`
1. In the implementation of
HBX_BNKSEL
, can I use the stack?I need to use the
OUT (C), r
instruction --- which is technicallyOUT (BC), r
.This necessitated the use of BC register - so I had saved it onto the stack - then i was wondering if I was having a stack issue. I did try saving it in the alt registers (EXX). I think pushing onto the stack would work - but at the time of coding, I was having a hardware issue. (hardware issue since resolved). But yet to test this fully. But I do wonder if I can use the stack at all in the function? What if the function is swapping the segment with the stack ? If I cant use the stack, I can probably just use a couple of bytes in the on-chip's RAM.
Just as I type, I am wondering if I can implement a pseudo function to enable doing the i/o with out need to set the B register - hmmm - I think the eZ80 even has hooks for illegal instructions - so hmm wondering... thinking.... ** Further progress is being made on this point - I will post a reply on how that went - should make it much easier to decorate the code to work for the eZ80 16bit IO.
CPUFAM
andPLATFORM
, but I am not sure what's the best conditional variable to use hereBut I have only used CPUFAM for the conditional test --- as mentioned above, not sure what would be best approach here.
3. What function belong in the on-chip ROM and what belongs in the RomWBW image?
The eZ80 will boot into its on-chip ROM (its initially mapped at address $000000). The on-chip ROM and RAM will be super fast - with minimal wait-states, unlike the external RC2014 ram module.
So I am thinking that the 'firmware' on the eZ80 is responsible for booting, setting up RAM/IO address ranges, wait states, address modes, and the initialize all the on-chip services (uarts, timers & counters, interrupts, the RTC, etc.). It should be 'agnostic' of RC2014 module configurations.
Once its ready, it then jumps to the first byte in the external 64K RAM address.
Perhaps an interface within the firmware could be made available for code such as HBIOS/RomWBW to call. This will be a table of jump functions --- allowing on-chip device configurations (baud rates etc). Also maybe a feature to copy and execute a block of code in the fast on-chip RAM.
The RomWBW would just need to initiate a far call (CALL.LIL) to access these functions.
Dev tool chains could be targeted for the specific platform -- I understand that the preferred approach for developing eZ80 code is to use a variant of clang that targets the eZ80 -- similar to how what has been developed for the Agon. I have not got that setup yet though. Just using the Zilog IDE which has a very old version of C (C98) but it does have an assembler to target the eZ80 instructions. This IDE is windows only (wine might work) - but it does have a nifty debugger.
RETI
I think will be important.I will need to do some experimenting on this.
5. Dual CPU Mode
I don't have the hardware wired up for the Dual CPU configuration. Have no idea if my idea will even work. This will be a little bit down the track. But the general idea will be the Z80 and the eZ80 can run side by side. Only 1 processor has access to the bus (the Z80 is sent the BUSREQ to remove it, but when the Z80 is controlling the bus, the eZ80 will be isolated by buffers, with it continuing to run on its internal ROM/RAM).
Thanks again Wayne.