Skip to content

Commit 6bec644

Browse files
authored
Merge pull request #9 from FPGAArcade/dyn_clock_freq
Add support for updating the 68060 CPU clock
2 parents befca17 + dffea6e commit 6bec644

File tree

3 files changed

+149
-7
lines changed

3 files changed

+149
-7
lines changed

Replay_Boot/fpga.c

+38-7
Original file line numberDiff line numberDiff line change
@@ -751,9 +751,11 @@ void FPGA_ClockMon(status_t* currentStatus)
751751

752752
if (stat != old_stat) {
753753
old_stat = stat;
754-
DEBUG(0, "Clock change : %02X", stat);
754+
DEBUG(0, "RTG Clock change : %02X", stat);
755755
DEBUG(0, " status %04X", (uint16_t)OSD_ConfigReadStatus());
756756

757+
clockconfig_t clkcfg = currentStatus->clock_cfg; // copy
758+
757759
if (stat == 0 || stat == 8) { // default clock
758760
// (RTG enabled with sys clock is 8, but we could change the filters etc)
759761

@@ -768,8 +770,6 @@ void FPGA_ClockMon(status_t* currentStatus)
768770

769771
Configure_VidBuf(3, currentStatus->filter_cfg.stc, currentStatus->filter_cfg.lpf, currentStatus->filter_cfg.mode);
770772

771-
Configure_ClockGen(&currentStatus->clock_cfg);
772-
773773
} else {
774774

775775
// coder off
@@ -780,9 +780,6 @@ void FPGA_ClockMon(status_t* currentStatus)
780780
Configure_VidBuf(2, 0, 3, 3);
781781
Configure_VidBuf(3, 0, 3, 3);
782782

783-
// jump to light speed
784-
clockconfig_t clkcfg = currentStatus->clock_cfg; // copy
785-
786783
switch (stat & 0x07) { // ignore top bit
787784
//27 * 280/ 33 N/M
788785
case 6 : // 114.50 MHz
@@ -835,9 +832,11 @@ void FPGA_ClockMon(status_t* currentStatus)
835832

836833
}
837834

838-
Configure_ClockGen(&clkcfg);
839835
}
840836

837+
// Configure_ClockGen(&clkcfg);
838+
UpdatePLL(3, clkcfg.pll3_m, clkcfg.pll3_n, clkcfg.p_sel[4], clkcfg.p_div[4], 4);
839+
841840
// let clock settle
842841
Timer_Wait(100);
843842

@@ -866,6 +865,38 @@ void FPGA_ClockMon(status_t* currentStatus)
866865
OSD_Reset(OSDCMD_CTRL_RES_VID);
867866

868867
}
868+
869+
870+
static uint8_t old_cpu = 0x00;
871+
uint8_t cpu = (OSD_ConfigReadStatus()) & 0xff;
872+
873+
if (cpu != old_cpu) {
874+
old_cpu = cpu;
875+
DEBUG(0, "CPU Clock change : %02X", cpu);
876+
DEBUG(0, " status %04X", (uint16_t)OSD_ConfigReadStatus());
877+
878+
clockconfig_t clkcfg = currentStatus->clock_cfg; // copy
879+
880+
if (cpu != 0)
881+
{
882+
uint32_t div = 2;
883+
while(cpu*div < 80)
884+
div++;
885+
886+
DEBUG(0, "CPU Freq: %d", cpu);
887+
DEBUG(0, "DIV: %d", div);
888+
DEBUG(0, "N2: %d", cpu*div);
889+
890+
clkcfg.pll2_m = 27;
891+
clkcfg.pll2_n = cpu*div;
892+
clkcfg.p_sel[2] = 2; // pll2
893+
clkcfg.p_div[2] = div; // div
894+
clkcfg.y_sel[2] = 1; // on
895+
896+
}
897+
898+
UpdatePLL(2, clkcfg.pll2_m, clkcfg.pll2_n, clkcfg.p_sel[2], clkcfg.p_div[2], 2);
899+
}
869900
}
870901

871902
//

Replay_Boot/twi.c

+109
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,115 @@ void Configure_ClockGen(const clockconfig_t* config)
421421
// 74.25 M= 2 N=11 Fvco=148.5 p=2 output = 74.25 (vfo=0)
422422
}
423423

424+
void UpdatePLL(uint32_t pll, uint32_t m, uint32_t n, uint32_t pll_sel, uint32_t div, uint32_t y)
425+
{
426+
// pll = {1,2,3}
427+
// m = {1,511}
428+
// n = {1,4095}
429+
// div = {1,127}
430+
// y = {0,5}
431+
/*
432+
1. Disable Y output
433+
2. Bypass PLLx
434+
3. Write new N/M values
435+
4. Disable bypass
436+
5. Set source PLL (Switch A)
437+
6. Write new Ydiv value
438+
7. Wait some arbitrary amount of time
439+
8. Re-enable Y (Switch B)
440+
*/
441+
DEBUG(0, "SetPLL(pll = %d, m = %d, n= %d, pll_sel = %d, div = %d, y = %d)", pll, m, n, pll_sel, div, y);
442+
443+
// This PLL bit position is used in both register 3 and register 6
444+
const uint8_t pll_conf_bit = 1 << (8-pll);
445+
446+
DEBUG(2, "Reading regs before switch");
447+
for (uint8_t addr = 0; addr < 24; addr++) {
448+
Read_CDCE906(addr+1);
449+
}
450+
451+
DEBUG(2, "Making the switch");
452+
453+
// Disable Y (keep nominal slew, non-inverted; Y div selection is reset)
454+
Write_CDCE906(19 + y, 0x30);
455+
456+
// Bypass PLLx (read/modify/write to enable VCO bypass in the PLL MUX)
457+
uint8_t reg3 = Read_CDCE906(3);
458+
reg3 |= pll_conf_bit;
459+
Write_CDCE906(3, reg3);
460+
461+
// Update M/N
462+
uint8_t lo_m = m & 0xff; // separate lower bytes
463+
uint8_t lo_n = n & 0xff;
464+
465+
uint8_t hi_m = (m >> 8) & 1; // isolate upper bits (1 for M, 4 for N)
466+
uint8_t hi_n = (n >> (8-1)) & (0xf << 1); // and move into place
467+
468+
uint8_t mn_base = 1+(pll-1)*3; // base register for PLL M/N settings
469+
470+
// read/modify/write keeping the upper 3 bits, which holds MUX/fVCOsel/PLL selection
471+
uint8_t hi = Read_CDCE906(mn_base+2) & 0xe0;
472+
473+
Write_CDCE906(mn_base+0, lo_m);
474+
Write_CDCE906(mn_base+1, lo_n);
475+
Write_CDCE906(mn_base+2, hi | hi_n | hi_m);
476+
477+
// Update VCO filter (read/modify/write, above 190Mhz we enable the fVCO filter)
478+
const uint32_t fvco = 27000 * n / m;
479+
DEBUG(0, "freq = %d", fvco/div);
480+
uint8_t reg6 = Read_CDCE906(6);
481+
reg6 &= ~pll_conf_bit;
482+
reg6 |= (fvco > 190000) ? pll_conf_bit : 0;
483+
Write_CDCE906(6, reg6);
484+
485+
// Update source PLL (setting is split over registers 9 through 12)
486+
uint8_t regPx = 9+y;
487+
uint8_t shiftPx = 5;
488+
switch(y)
489+
{
490+
case 2: // reg 11
491+
case 3: // reg 11
492+
case 4: // reg 12
493+
case 5: // reg 12
494+
regPx = 11+y/4; // write reg 11/12
495+
shiftPx = ((y&1) ? 3 : 0); // odd Px in upper position
496+
break;
497+
}
498+
499+
// Read/modify/write, updating the SWAPxy /Px
500+
uint32_t valPx = Read_CDCE906(regPx);
501+
valPx &= ~(0x7 << shiftPx);
502+
valPx |= (pll_sel << shiftPx);
503+
Write_CDCE906(regPx, valPx);
504+
505+
// Update Ydiv
506+
Write_CDCE906(13 + y, (div & 0x7f));
507+
508+
// let clock settle
509+
Timer_Wait(100);
510+
511+
// Disable bypass PLLx (read/modify/write to mask the VCO bypass bit)
512+
reg3 = Read_CDCE906(3);
513+
reg3 &= ~pll_conf_bit;
514+
Write_CDCE906(3, reg3);
515+
516+
// let clock settle
517+
Timer_Wait(100);
518+
519+
// Enable Y (nominal slew, non-inverted, static Ydiv selection, Yx enabled)
520+
Write_CDCE906(19 + y, 0x30 | 0x08 | (y & 7));
521+
522+
// let clock settle
523+
Timer_Wait(100);
524+
525+
DEBUG(2, "Reading regs after switch");
526+
for (uint8_t addr = 0; addr < 24; addr++) {
527+
Read_CDCE906(addr+1);
528+
}
529+
530+
DEBUG(1, "Switch done");
531+
}
532+
424533
void Write_CH7301(uint8_t address, uint8_t data)
425534
{
426535
uint8_t rab = 0x80 | (address & 0x7F);

Replay_Boot/twi.h

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ void Write_CDCE906(uint8_t Address, uint8_t Data);
7676
void Configure_VidBuf(uint8_t chan, uint8_t stc, uint8_t lpf, uint8_t mode);
7777
void Configure_ClockGen(const clockconfig_t* config);
7878

79+
void UpdatePLL(uint32_t pll, uint32_t m, uint32_t n, uint32_t pll_sel, uint32_t div, uint32_t y);
80+
7981
void Write_CH7301(uint8_t address, uint8_t data);
8082
uint8_t Read_CH7301(uint8_t address);
8183
void Configure_CH7301(const vidconfig_t* config);

0 commit comments

Comments
 (0)