Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support a F83 RTC and test it on GEOS #103

Closed
sy2002 opened this issue Nov 2, 2023 · 18 comments
Closed

Support a F83 RTC and test it on GEOS #103

sy2002 opened this issue Nov 2, 2023 · 18 comments
Assignees
Labels
5.1 (R4/R5 Surge) enhancement New feature or request

Comments

@sy2002
Copy link
Collaborator

sy2002 commented Nov 2, 2023

@MJoergen Please decide if you consider this as a long hanging fruit for 5.1. If not, then remove the 5.1 surge label.

This issue needs the following M2M hardware abstraction first, so that the three different RTCs on the MEGA65 are abstracted away from the C64 core (and so that other cores such as the ZX Spectrum can leverage the RTC, too):

sy2002#29

Information on how to support an RTC on the C64

@MJoergen
Copy link
Owner

MJoergen commented Nov 5, 2023

My understanding is the following:

The GEOS communicates on the cassette port and expects an F83 RTC device.

In other words, GEOS expects to be communicating with an I2C device with a specific address and a specific memory map.

Therefore, the M2M framework would need to emulate a "virtual" F83 RTC device, while at the same time communicating with the "real" RTC on the board. Essentially, the M2M framework would be the "man-in-the-middle".

@MJoergen
Copy link
Owner

MJoergen commented Nov 5, 2023

However, much simpler is to re-use MiSTer's emulation rtcF83.sv. This takes care of the I2C interface to GEOS.

The MiSTer emulation file expects a 65-bit signal containing the current date/time, with the following format (see file user_io.cpp in Main_MiSTer repo):

   -- Bits  7 -  0 : Seconds    (BCD format, 0x00-0x60)
   -- Bits 15 -  8 : Minutes    (BCD format, 0x00-0x59)
   -- Bits 23 - 16 : Hours      (BCD format, 0x00-0x23)
   -- Bits 31 - 24 : DayOfMonth (BCD format, 0x01-0x31)
   -- Bits 39 - 32 : Month      (BCD format, 0x01-0x12)
   -- Bits 47 - 40 : Year       (BCD format, 0x00-0x99)
   -- Bits 55 - 48 : DayOfWeek  (0x00-0x06)
   -- Bits 63 - 56 : 0x40
   -- Bit       64 : Toggle flag. Flips anytime there is a change in the other bits

The M2M framework would then continuously make sure this signal has the correct value, by appropriate communication with whatever RTC is present on the MEGA65 board.

MJoergen added a commit that referenced this issue Nov 7, 2023
This is part of issue #103.

Changes to CORE:
* Instantiate MiSTer file rtcF83 and connect to tape port.
  This is used by the GEOS software.

Changes to M2M:
* Add i2c_controller.vhd.
  This allows QNICE firmware to communicate with any I2C device,
  via the framework device ID C_DEV_I2C.

Interconnection between CORE and M2M:
With this commit, the CORE expects the current date/time to be
delivered via the QNICE general purpose register main_qnice_gp_reg_i.

TODO: The QNICE firmware should (after reset) read the current date/time
from the RTC device (the actual I2C address and register map is board
dependent), and then write the date/time value in this generic format:

-- Contents of RTC (see user_io.cpp in Main_MiSTer):
-- Bits  7 -  0 : Seconds    (BCD format, 0x00-0x60)
-- Bits 15 -  8 : Minutes    (BCD format, 0x00-0x59)
-- Bits 23 - 16 : Hours      (BCD format, 0x00-0x23)
-- Bits 31 - 24 : DayOfMonth (BCD format, 0x01-0x31)
-- Bits 39 - 32 : Month      (BCD format, 0x01-0x12)
-- Bits 47 - 40 : Year       (BCD format, 0x00-0x99)
-- Bits 55 - 48 : DayOfWeek  (0x00-0x06)
-- Bits 63 - 56 : 0x40
-- Bit       64 : Toggle flag. Flip whenever the values are changed
@MJoergen
Copy link
Owner

MJoergen commented Nov 7, 2023

After several attempts I have come to the conclusion that the following "hybrid" approach is best:

Firstly, the M2M framework (VHDL part) will provide a generic QNICE-memory-mapped interface to the I2C bus. In other words, via QNICE reads/writes to framework device ID C_DEV_I2C it is possible to initiate reads and writes to an arbitrary I2C device.

Secondly, the Core makes use of the same interface as on MiSTer, i.e. a 65-bit generic value describing the current date/time in BCD format. This value only needs to be presented once after reset, the core will maintain (i.e. keep up-to-date) its own local copy of the current date/time.

What is left (i.e. still not done), is a purely QNICE firmware task:

  • Upon reset, the QNICE should detect which board it is running on (TBD: How is that done?)
  • Then determine the specific I2C address and register map of the corresponding RTC device.
  • Then the firmware should read the current date/time (using the generic QNICE-to-I2C mapper mentioned above)
  • Format the result according to the above description
  • Finally write the value to the control_d_o signal.

The benefit of this approach is that the same QNICE register map can be used from the monitor to debug / verify / communicate with (any) I2C devices on the board.

Since the next step is a firmware task, I'm reassigning to @sy2002

@MJoergen MJoergen assigned sy2002 and unassigned MJoergen Nov 7, 2023
@MJoergen
Copy link
Owner

MJoergen commented Nov 7, 2023

There should also be some menu options.

E.g. some users might actually have a real RTC connected via the tape port (just like on a "real" C64), while others would use the onboard RTC (i.e. emulate the GEOS-compatible RTC).

There is also the "confusion" about the "original" RTC on the R3 board, and a "modified" RTC. I don't know if it's possible to auto-detect which is the case. Probably, but if not, the user would have to make the selection.

Other TODOs for the VHDL part:

  • Provide QNICE firmware with easy information about the MEGA65 board revision (as mentioned above). EDIT: This is now implemented in commit (6be9fc3).
  • Being able to select between different I2C buses. There are several different I2C busses, that connect to different devices. EDIT: This is now implemented in commit (054dd03).

@MJoergen
Copy link
Owner

MJoergen commented Nov 7, 2023

On the R4 board, the following sequence of operations will read out the date/time from the RTC:

  1. Write 0x0005 to 0xFFF4 (Select I2C device)
  2. Write 0x0000 to 0x7000 (Prepare to write to RTC)
  3. Write 0x01A2 to 0x70F0 (Send one byte, 0x00, to RTC)
  4. Read from 0x70F1 until value is 0x0001 (I2C is idle)
  5. Write 0x07A3 to 0x70F0 (Receive seven bytes from RTC)
  6. Read from 0x70F1 until value is 0x0001 (I2C is idle)
  7. The RTC date/time can now be read from 0x7000 to 0x7006.

Similar sequence (with few alterations) should work for both R3 variants.

@MJoergen
Copy link
Owner

MJoergen commented Nov 7, 2023

One idea to auto-detect the RTC, is to monitor bit 2 of value 0x70F1 (Status.2 = NACK). This bit is set when there is no device responding.

@MJoergen
Copy link
Owner

MJoergen commented Nov 7, 2023

Regarding detecting the board revision, I propose to use the SysInfo record. Specifically to introduce a new record: C_SYS_BOARD with value 0x0040. Then address 0 could be one of:

R3 : 0x0003
R4 : 0x0004
R5 : 0x0005

The VHDL part would then be responsible for populating the correct value (based on the generic G_BOARD).

@MJoergen
Copy link
Owner

MJoergen commented Nov 7, 2023

The following lists the various I2C busses on the various board. For each bus there is a separate pair of SCL/SDA pins on the FPGA. The naming of the busses is from the schematic.

R3:

  • VGA (connect to VGA monitor)
  • HDMI (connect to HDMI monitor)
  • FPGA (connect to onboard peripherals, e.g. Audio DAC and RTC)
  • Grove (connect to PMOD)

R4:

  • VGA (connect to VGA monitor)
  • HDMI (connect to HDMI monitor)
  • Audio (connect to Audio DAC)
  • FPGA (connect to onboard peripherals, e.g. RTC).
  • Grove (connect to PMOD)

R5:

  • VGA (connect to VGA monitor)
  • HDMI (connect to HDMI monitor)
  • Audio (connect to Audio DAC)
  • I2C (connect to onboard peripherals, e.g. I/O expander and DC/DC converters).
  • FPGA (connect to onboard peripherals, e.g. RTC).
  • Grove (connect to PMOD)

In order to support RTC on the R3 board, we must be able to communicate with both the "FPGA" bus (the internal RTC), and the "Grove" bus (the external RTC connected via PMOD).

@sy2002
Copy link
Collaborator Author

sy2002 commented Nov 7, 2023

@MJoergen : Makes sense for me - let's make it so. We already have a poll-loop in the firmware, so the firmware can rather easily ensure that the output signal stays updated. I am not sure if we should use control_d_o or if it makes sense to introduce a new, dedicated signal that is meant to be used for RTCs-only.

@MJoergen
Copy link
Owner

MJoergen commented Nov 8, 2023

Since we agree so far, I've now merged the branch "mfj_rtc_support" into the "develop" branch.

@MJoergen
Copy link
Owner

MJoergen commented Nov 8, 2023

Since this whole RTC feature is very much core-dependent, I was thinking about having the necessary QNICE firmware be placed in the core-specific file CORE/m2m-rom/m2m-rom.asm.

We could do that as a first step, and if we see a recurring pattern for other cores, then we can refactor as needed.

@sy2002
Copy link
Collaborator Author

sy2002 commented Nov 8, 2023

I am not fully getting why the firmware is core specific? If we had a new dedicated VHDL signal that is provided in main.vhd and that is for example formatted like the MiSTer format: Couldn't the CPP take it from there? And then the firmware would be non-core-specific? "Formatting" or "converting" this 64 bit std_logic_vector would be something that happened inside main.vhd (or mega65.vhd) and the firmware just make sure that it is updated at least 10x per second or so.

@MJoergen
Copy link
Owner

MJoergen commented Nov 8, 2023

My bad. I agree with you. The process of reading the date/time from the (board-specific) RTC and converting to the "generic" date/time format is completely core-independent. It is only the subsequent processing of this generic date/time information from the framework, which is core-specific.

So the question remains, whether this should be presented as part of the control_d_o signal, or whether we should introduce a new dedicated signal. I guess the latter makes most sense.

@MJoergen
Copy link
Owner

MJoergen commented Nov 8, 2023

Since this is our "first" use of I2C, there are some architectural choices to be made. Specifically, should we support e.g. the Audio DAC? The Audio DAC works differently on the three boards, and it's connected differently too (i.e. different I2C bus and different I2C address). If we want to support the Audio DAC, should the "knowledge" of connectivity of the Audio DAC (i.e. which I2C bus and I2C address to use) be placed in VHDL and abstracted away, or should the QNICE firmware be in full control?

Since we're currently only using the I2C interface for the RTC, this decision is conveniently postponed. But the current implementation provides no abstraction, and expects the QNICE firmware to be in full control / knowledge of which devices (e.g. Audio DAC) are connected to which I2C busses and with which I2C addresses.

@sy2002
Copy link
Collaborator Author

sy2002 commented Nov 8, 2023

If technically possible at all going forward (and I admittedly did not think it through) I would prefer a completely board-revision agnostic firmware: Everything should be abstracted away on the VHDL part of the house. Now... ...this is my wishful thinking. You @MJoergen decide what is feasible at all. And since I will not be able to work at this issue any time soon: Feel free to refactor everything you've done so far and yes, we should add a dedicated (64-bit?) signal for RTC to the framework.

@MJoergen
Copy link
Owner

MJoergen commented Nov 8, 2023

I understand your point of view. This will require some thought, because there are many ways to do this. But I understand that the firmware just "wants" the date/time somehow, without having to worry about the implementation (i.e. board specific) details. This is really the same requirement the core has. If this is done completely, then the firmware need not be involved at all.

Thinking out loud: The VHDL code could implement a small state machine that (upon request, e.g. after reset) goes through a pre-defined (but board-specific) set of reads/writes. This will be interfacing with the RTC module over the I2C bus using the new QNICE-to-I2C wrapper (implemented in i2c_controller.vhd). In other words, we'll keep the QNICE register interface intact, because it is really useful for debugging.

So I will have three (or so) sets of QNICE accesses (read/writes), written in a small table, and fed into a small state machine. This entity would be called rtc_reader.vhd and connect to the QNICE device interface (i.e. acting as a second "master" on the QNICE device interface). The output from this file would be the 65-bit date/time signal that can be fed directly to the core.

The only thing missing here is how to arbitrate between this new rtc_reader and the existing QNICE code. I will need to write a QNICE-arbiter, that will delay one (or the other). For maximum robustness, the rtc_reader should not be interrupted while speaking with the I2C device, in case the QNICE firmware starts writing to e.g. M2M$RAMROM_DEV.

However, if I connect the arbiter only to the QNICE-2-I2C wrapper (instead of the entire general QNICE memory mapped I/O), then the QNICE firmware will not be impacted (assuming it is not itself speaking with the I2C devices). Then the memory location M2M$RAMROM_DEV will not be in use either.

In conclusion, that is entirely doable, and the work so far is not in vain. I'm re-assigning to myself again.

@MJoergen MJoergen assigned MJoergen and unassigned sy2002 Nov 8, 2023
@sy2002
Copy link
Collaborator Author

sy2002 commented Nov 8, 2023

👍🏻 Sounds promising :-)

@sy2002 sy2002 assigned sy2002 and unassigned MJoergen Jan 13, 2024
@sy2002
Copy link
Collaborator Author

sy2002 commented Jan 14, 2024

@MJoergen ✅ WORKS IN GEOS, see screenshot:

GEOS-RTC

One needs to install the RTC driver by copying the driver file on the local GEOS boot disk:
https://github.com/mister-devel/C64_MiSTer/blob/master/releases/CP-ClockF83_1.3.D64

@sy2002 sy2002 closed this as completed Jan 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
5.1 (R4/R5 Surge) enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants