2

I want to write a game loop on CP/M 2.X (Z80) and would need to wait for some time e.g. a second. I've looked at BDOS but did not find a function, a loop depends on processor (emulation speed), interrupts like vertical blank do not exist.

Any ideas on how to write a game loop?

[Edit]

The z88dk CP/M lib says

Not (of course) CPM 1.x and 2.x, which have no real-time functions; ,nor QX/M, its clock is not BCD based.

There were action games like LADDER so there should be a way for a game loop.

[Edit2]

I could let the user check 5 secs with two keypresses and measure the speed (double loop) once to config the game - but only as a last resort.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
KingOfCoders
  • 2,253
  • 2
  • 23
  • 34
  • Looking through the BDOS call list, I don't see anything that would help (DELAY isn't in Z80 CP/M). You may be able to get an estimate of how long to wait by getting the date and time again, waiting some large but arbitrary number of cycles (on the order of 10s) and getting the time again. This would however be slow, given the long time with nothing happening, and rely on few/no interrupts taking up cycles. If you're targeting something more specific (e.g. RomWBW) you should be able to get something semi-portable. – Thomas Jager Jan 18 '21 at 16:10
  • How would I get the time in a portable way? (e.g. NC 100, PC 1600, Emulator) - Also Turbo Pascal has delay(t) but I don't find the source. – KingOfCoders Jan 18 '21 at 16:13
  • My bad, I didn't even check that CP/M Z80 had it, I assumed that it was basic enough to be supported. – Thomas Jager Jan 18 '21 at 16:20
  • 2
    You might have better luck on [Retrocomputing](https://retrocomputing.stackexchange.com/questions) with a question like this. – tum_ Jan 18 '21 at 17:36
  • So you're using an OS that literally doesn't have a clock or any way to find out the current time? Like there aren't even file timestamps? If the OS really doesn't have a real-time clock, you might need to access a hardware timer if there is one. But seriously, are you sure you want to try to do real-time stuff like a game on an (emulated) system that makes it that hard? Perhaps just for the challenge, I guess. – Peter Cordes Jan 18 '21 at 17:39
  • 1
    There's no standard clock or timer functionality in CP/M 2.2. Your going to have to assume some clock speed or rely on machine dependent hardware. – Ross Ridge Jan 18 '21 at 17:47
  • Thanks @tum_ I will also ask on Retrocomputing, good idea. – KingOfCoders Jan 18 '21 at 17:53
  • @PeterCordes I don't know what is available. – KingOfCoders Jan 18 '21 at 17:54
  • 1
    I've implemented a CP/M; I can confirm there really is no timing information available. No clock, no timestamps. And between the 8080, the Z80A and B, and the V20, and including painfully crippled machines like the Commodore C128, there's a fairly broad range of performances out there. – Tommy Jan 19 '21 at 15:19

3 Answers3

7

There's no portable way of waiting for a certain amount of time under CP/M 2.2. CP/M doesn't require or use a real time clock or any kind of timer, and so you can't even assume one is present in the system, let alone that it uses any kind of common interface.

Turbo Pascal's Delay function worked by assuming a certain CPU frequency, one that was configured when Turbo Pascal was installed. The CP/M game Ladder was written in Turbo Pascal and used its Delay function, so it also assumed a certain CPU frequency. If you played on a faster or slower CPU the game would play faster or slower than intended.

The simplest solution would be to implement your own delay function that assumed a certain CPU frequency. I believe 4 MHz was the most common Z80 speed for CP/M. You can make this a configurable option so users can change the assumed CPU speed. You're probably also going to want to give users the option of changing the terminal type, just like Ladder did, as there are many possible terminals that can be used with CP/M.

ecm
  • 2,583
  • 4
  • 21
  • 29
Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
1

Yes, CP/M 2.x has no such mechanism. CP/M 3 (a.k.a. CP/M Plus) however, DOES have a date/time mechanism that can be utilized for this purpose.

It is BDOS function 105 (69h): Get date & time. Unfortunately the granularity is only per second (returned in the accumulator when called).

You can do a call to this function, grab the value of the accumulator, then loop the call again until the accumulator changes. Voila: a 1 second wait.

  • 1
    That would wait until the "seconds" counter ticked. The wait time depends on how close to the end of the current wall-clock second you are, and could be as short as the next call. – Peter Cordes Aug 11 '23 at 14:34
  • Longer delays would be fine, though: you can wait for `n` seconds plus an unknown time from 0.00001 to .99999 seconds or something like that. Or if you want to display something on the screen every second, waiting until the start of the next second will lock your screen updates to 1 second intervals. But you can't do a 1-second sleep from an arbitrary start point by polling a 1-second-granularity clock. – Peter Cordes Sep 02 '23 at 07:44
1

z88dk provides sleep(n), msleep(n), csleep(n). In such cases the delay does not depend on a hardware clock, is calibrated on a hardcoded value defining the CPU speed.

For CP/M it is set to 4000000. You can personalize it by editing: {z88dk}/lib/target/cpm/classic/cpm_crt0.asm

You can also leave it untouched and tune the parameters of the functions: supposing you have a 2mhz CPU (half speed than a 4mhz system), mleep(1000) would take 2 seconds.

Stefano
  • 11
  • 1