mirror of
https://github.com/rdolbeau/VintageBusFPGA_Common.git
synced 2026-01-11 23:42:48 +00:00
updated ROM for automated makefile paramters, settable pixel clock
This commit is contained in:
parent
e9af161c35
commit
76527c00d9
4
.gitignore
vendored
4
.gitignore
vendored
@ -3,4 +3,6 @@ blit_goblin
|
||||
blit_goblin.o
|
||||
blit_goblin.s
|
||||
blit_goblin_nubus.raw
|
||||
blit_goblin_sbus.raw
|
||||
blit_goblin_sbus.raw
|
||||
**~
|
||||
DeclROM/vid_decl_rom.elf
|
||||
|
||||
@ -10,17 +10,19 @@ ARCHFLAGS=-march=68020 -mcpu=68020
|
||||
CFLAGS=-O2 -mpcrel
|
||||
FEATURES=
|
||||
|
||||
TARGET=NUBUSFPGA
|
||||
#TARGET=NUBUSFPGA
|
||||
#
|
||||
#ifeq (${TARGET},NUBUSFPGA)
|
||||
# FEATURES+=-DNUBUSFPGA -DENABLE_RAMDSK -DENABLE_HDMIAUDIO # -DENABLE_SDCARD
|
||||
#endif
|
||||
#ifeq (${TARGET},IISIFPGA)
|
||||
# FEATURES+=-DIISIFPGA -DENABLE_HDMIAUDIO
|
||||
#endif
|
||||
#ifeq (${TARGET},QUADRAFPGA)
|
||||
# FEATURES+=-DQUADRAFPGA -DENABLE_HDMIAUDIO
|
||||
#endif
|
||||
|
||||
ifeq (${TARGET},NUBUSFPGA)
|
||||
FEATURES+=-DNUBUSFPGA -DENABLE_RAMDSK -DENABLE_HDMIAUDIO # -DENABLE_SDCARD
|
||||
endif
|
||||
ifeq (${TARGET},IISIFPGA)
|
||||
FEATURES+=-DIISIFPGA -DENABLE_HDMIAUDIO
|
||||
endif
|
||||
ifeq (${TARGET},QUADRAFPGA)
|
||||
FEATURES+=-DQUADRAFPGA -DENABLE_HDMIAUDIO
|
||||
endif
|
||||
include ../../decl_rom_config.mak
|
||||
|
||||
CFLAGS+=${FEATURES}
|
||||
HOSTCFLAGS+=${FEATURES}
|
||||
@ -31,8 +33,8 @@ PROCESS_ROM=${NS816DECLROMDIR}/process_rom
|
||||
|
||||
APPLEINCS=${NS816DECLROMDIR}/atrap.inc ${NS816DECLROMDIR}/declrom.inc ${NS816DECLROMDIR}/globals.inc
|
||||
|
||||
HRES=1920
|
||||
VRES=1080
|
||||
#HRES=1920
|
||||
#VRES=1080
|
||||
QEMU=no
|
||||
ifeq ($(QEMU),yes)
|
||||
CFLAGS+=-DQEMU
|
||||
|
||||
@ -83,15 +83,15 @@ struct MyGammaTbl {
|
||||
};
|
||||
|
||||
#define nativeVidMode ((unsigned char)0x80)
|
||||
/* alternate resolution in 0x81...0x8f */
|
||||
#define diskResource ((unsigned char)0x90)
|
||||
/* alternate resolution in 0x81...0x9f */
|
||||
#define diskResource ((unsigned char)0xF0)
|
||||
|
||||
struct NuBusFPGADriverGlobals {
|
||||
AuxDCEPtr dce; // unused
|
||||
SlotIntQElement *siqel;
|
||||
//unsigned char shadowClut[768];
|
||||
unsigned short hres[16]; /* HW max in 0 */
|
||||
unsigned short vres[16]; /* HW max in 0 */
|
||||
unsigned short hres[32]; /* HW max in 0, WB in even, HW in odd */
|
||||
unsigned short vres[32]; /* HW max in 0, WB in even, HW in odd */
|
||||
unsigned short curPage;
|
||||
unsigned char maxMode;
|
||||
unsigned char curMode; /* mode ; this is resolution (which can't be changed in 7.1 except via reboot ?) */
|
||||
@ -123,8 +123,6 @@ static inline unsigned int read_reg(AuxDCEPtr dce, unsigned int reg) {
|
||||
return *((volatile unsigned int*)(dce->dCtlDevBase+GOBOFB_BASE+reg));;
|
||||
}
|
||||
|
||||
/* ASM */
|
||||
extern SlotIntServiceProcPtr interruptRoutine;
|
||||
/* ctrl */
|
||||
void linearGamma(NuBusFPGADriverGlobalsPtr dStore) __attribute__ ((section (".text.fbdriver")));
|
||||
OSErr changeIRQ(AuxDCEPtr dce, char en, OSErr err) __attribute__ ((section (".text.fbdriver")));
|
||||
|
||||
@ -366,6 +366,26 @@ OSErr cNuBusFPGACtl(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_HDMI_ALT_CHANGE)
|
||||
#if defined(NUBUSFPGA)
|
||||
#include "../../nubusfpga_csr_goblin.h"
|
||||
#include "../../nubusfpga_csr_crg.h"
|
||||
#elif defined(IISIFPGA)
|
||||
#include "../../iisifpga_csr_goblin.h"
|
||||
#include "../../iisifpga_csr_crg.h"
|
||||
#elif defined(QUADRAFPGA)
|
||||
#include "../../quadrafpga_csr_crg.h"
|
||||
#include "../../quadrafpga_csr_goblin.h"
|
||||
#else
|
||||
#error "no board defined"
|
||||
#endif
|
||||
|
||||
|
||||
// access to the MMCM
|
||||
#include "NuBusFPGADrvr_MMCM.h"
|
||||
|
||||
#endif
|
||||
|
||||
OSErr reconfHW(AuxDCEPtr dce, unsigned char mode, unsigned char depth, unsigned short page) {
|
||||
NuBusFPGADriverGlobalsHdl dStoreHdl = (NuBusFPGADriverGlobalsHdl)dce->dCtlStorage;
|
||||
NuBusFPGADriverGlobalsPtr dStore = *dStoreHdl;
|
||||
@ -409,7 +429,11 @@ OSErr reconfHW(AuxDCEPtr dce, unsigned char mode, unsigned char depth, unsigned
|
||||
}
|
||||
|
||||
SwapMMUMode ( &busMode );
|
||||
|
||||
write_reg(dce, GOBOFB_VIDEOCTRL, 0); // here we know we're going to change something, disable video */
|
||||
|
||||
if (mode != dStore->curMode) {
|
||||
UInt8 id = mode - nativeVidMode;
|
||||
unsigned short i;
|
||||
for (i = nativeVidMode ; i <= dStore->maxMode ; i++) {
|
||||
// disable spurious resources, enable only the right one
|
||||
@ -422,16 +446,126 @@ OSErr reconfHW(AuxDCEPtr dce, unsigned char mode, unsigned char depth, unsigned
|
||||
}
|
||||
dce->dCtlSlotId = mode; // where is that explained ? cscSwitchMode is not in DCDMF3, and you should'nt do that anymore says PDCD...
|
||||
|
||||
UInt8 id = mode - nativeVidMode;
|
||||
unsigned int ho = ((dStore->hres[0] - dStore->hres[id]) / 2);
|
||||
unsigned int vo = ((dStore->vres[0] - dStore->vres[id]) / 2);
|
||||
/* write_reg(dce, GOBOFB_VIDEOCTRL, 0); */
|
||||
|
||||
#if defined(ENABLE_HDMI_ALT_CHANGE)
|
||||
// we have the ability to change the hardware resolution
|
||||
uint32_t a32 = dce->dCtlDevBase;
|
||||
|
||||
// here so that data aren't global
|
||||
// timings for the VTG
|
||||
#include "NuBusFPGADrvr_Timings.h"
|
||||
|
||||
const uint8_t reg_addr[12] = { DIV_REG, CLKFBOUT_REG1, CLKFBOUT_REG2,
|
||||
LOCK_REG1, LOCK_REG2, LOCK_REG3,
|
||||
FILT_REG1, FILT_REG2,
|
||||
CLKOUT0_REG1, CLKOUT0_REG2,
|
||||
CLKOUT1_REG1, CLKOUT1_REG2 };
|
||||
const uint16_t reg_mask[12] = { KEEP_IN_DIV, KEEP_IN_MUL_REG1, KEEP_IN_MUL_REG2,
|
||||
LOCK1_MASK, LOCK23_MASK, LOCK23_MASK,
|
||||
FILT1_MASK, FILT2_MASK,
|
||||
REG1_FREQ_MASK & REG1_PHASE_MASK, REG2_FREQ_MASK & REG2_PHASE_MASK,
|
||||
REG1_FREQ_MASK & REG1_PHASE_MASK, REG2_FREQ_MASK & REG2_PHASE_MASK };
|
||||
|
||||
#if defined(ENABLE_HDMI_ALT_CHANGE_54MHZ)
|
||||
const uint16_t freq_25175000[12] = {0x1041, 0x28b, 0x80, 0x1db, 0x7c01, 0x7fe9, 0x9000, 0x100, 0x597, 0x80, 0x105, 0x80};
|
||||
const uint16_t freq_40000000[12] = {0x41, 0x493, 0x80, 0xfa, 0x7c01, 0x7fe9, 0x900, 0x1000, 0x30d, 0x80, 0x83, 0x80};
|
||||
const uint16_t freq_65000000[12] = {0x1041, 0x249, 0x0, 0x226, 0x7c01, 0x7fe9, 0x9900, 0x1100, 0x1c8, 0x80, 0x42, 0x80};
|
||||
const uint16_t freq_108000000[12] = {0x1041, 0x28a, 0x0, 0x1f4, 0x7c01, 0x7fe9, 0x9000, 0x100, 0x145, 0x0, 0x41, 0x0};
|
||||
const uint16_t freq_148500000[12] = {0x82, 0x6dc, 0x80, 0xfa, 0x7c01, 0x7fe9, 0x1100, 0x1800, 0x83, 0x80, 0x41, 0x40};
|
||||
#elif defined(ENABLE_HDMI_ALT_CHANGE_48MHZ)
|
||||
#error "Untested input clock for MMCM"
|
||||
const uint16_t freq_25175000[12] = {0x1041, 0x28b, 0x80, 0x1db, 0x7c01, 0x7fe9, 0x9000, 0x100, 0x514, 0x0, 0x104, 0x0};
|
||||
const uint16_t freq_40000000[12] = {0x1041, 0x30d, 0x80, 0x190, 0x7c01, 0x7fe9, 0x1100, 0x9000, 0x3cf, 0x0, 0xc3, 0x0};
|
||||
const uint16_t freq_65000000[12] = {0x41, 0x34e, 0x80, 0x15e, 0x7c01, 0x7fe9, 0x900, 0x1000, 0x145, 0x0, 0x41, 0x0};
|
||||
const uint16_t freq_108000000[12] = {0x41, 0x597, 0x80, 0xfa, 0x7c01, 0x7fe9, 0x800, 0x8000, 0x145, 0x0, 0x41, 0x0};
|
||||
const uint16_t freq_148500000[12] = {0x41, 0x3d0, 0x80, 0x12c, 0x7c01, 0x7fe9, 0x900, 0x1000, 0x83, 0x80, 0x41, 0x40};
|
||||
#else
|
||||
#error "Unknown input clock for MMCM"
|
||||
#endif
|
||||
|
||||
short timeout = 1000;
|
||||
while ((read_reg(dce, GOBOFB_VIDEOCTRL) & 0x2 != 0) && timeout) {
|
||||
/* wait for the reset process to be over */
|
||||
/* otherwise without a clock it won't finish */
|
||||
timeout --;
|
||||
delay(100);
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
err = ioErr;
|
||||
// first reset the MCMM and set new values
|
||||
litex_clk_assert_reg(DRP_RESET);
|
||||
|
||||
const uint16_t* freq = freq_148500000;
|
||||
const struct vtg_timing_regs *vtgtr = &vtg_1920x1080_60Hz;
|
||||
|
||||
if (id & 0x1) {
|
||||
switch (dStore->hres[id]) {
|
||||
case 640:
|
||||
freq = freq_25175000;
|
||||
vtgtr = &vtg_640x480_60Hz;
|
||||
ho = 0; /* full screen, not centered */
|
||||
vo = 0;
|
||||
break;
|
||||
case 800:
|
||||
freq = freq_40000000;
|
||||
vtgtr = &vtg_800x600_60Hz;
|
||||
ho = 0;
|
||||
vo = 0;
|
||||
break;
|
||||
case 1024:
|
||||
freq = freq_65000000;
|
||||
vtgtr = &vtg_1024x768_60Hz;
|
||||
ho = 0;
|
||||
vo = 0;
|
||||
break;
|
||||
case 1280:
|
||||
freq = freq_108000000;
|
||||
vtgtr = &vtg_1280x1024_60Hz;
|
||||
ho = 0;
|
||||
vo = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; (i < 12) && (err == noErr); i++) {
|
||||
err = litex_clk_change_value_norst(a32,
|
||||
reg_mask[i], freq[i],
|
||||
reg_addr[i]);
|
||||
if (err != noErr) goto mmcmdone;
|
||||
}
|
||||
|
||||
litex_clk_deassert_reg(DRP_RESET);
|
||||
|
||||
err = litex_clk_wait(dce->dCtlDevBase, DRP_LOCKED);
|
||||
if (err != noErr) goto mmcmdone;
|
||||
|
||||
/* the clock should be back we can finish */
|
||||
|
||||
// second fully reconfigure the VTG
|
||||
goblin_video_framebuffer_vtg_hres_write(a32, vtgtr->hres);
|
||||
goblin_video_framebuffer_vtg_hsync_start_write(a32, vtgtr->hsync_start);
|
||||
goblin_video_framebuffer_vtg_hsync_end_write(a32, vtgtr->hsync_end);
|
||||
goblin_video_framebuffer_vtg_hscan_write(a32, vtgtr->hscan);
|
||||
goblin_video_framebuffer_vtg_vres_write(a32, vtgtr->vres);
|
||||
goblin_video_framebuffer_vtg_vsync_start_write(a32, vtgtr->vsync_start);
|
||||
goblin_video_framebuffer_vtg_vsync_end_write(a32, vtgtr->vsync_end);
|
||||
goblin_video_framebuffer_vtg_vscan_write(a32, vtgtr->vscan);
|
||||
|
||||
mmcmdone:
|
||||
; /* nothing */
|
||||
#endif
|
||||
/* center picture in frame */
|
||||
write_reg(dce, GOBOFB_HRES_START, __builtin_bswap32(ho));
|
||||
write_reg(dce, GOBOFB_VRES_START, __builtin_bswap32(vo));
|
||||
write_reg(dce, GOBOFB_HRES_END, __builtin_bswap32(ho + dStore->hres[id]));
|
||||
write_reg(dce, GOBOFB_VRES_END, __builtin_bswap32(vo + dStore->vres[id]));
|
||||
/* write_reg(dce, GOBOFB_VIDEOCTRL, 1); */
|
||||
}
|
||||
|
||||
if (depth != dStore->curDepth) {
|
||||
switch (depth) {
|
||||
case kDepthMode1:
|
||||
@ -460,6 +594,16 @@ OSErr reconfHW(AuxDCEPtr dce, unsigned char mode, unsigned char depth, unsigned
|
||||
dStore->curMode = mode;
|
||||
dStore->curDepth = depth;
|
||||
dStore->curPage = page; /* FIXME: HW */
|
||||
|
||||
short timeout = 1000;
|
||||
while ((read_reg(dce, GOBOFB_VIDEOCTRL) & 0x2 != 0) && timeout) {
|
||||
/* wait for the reset process to be over */
|
||||
timeout --;
|
||||
}
|
||||
if (timeout == 0)
|
||||
err = ioErr;
|
||||
|
||||
write_reg(dce, GOBOFB_VIDEOCTRL, 1); // restart the video with the new parameters
|
||||
|
||||
SwapMMUMode ( &busMode );
|
||||
|
||||
@ -506,7 +650,7 @@ OSErr updatePRAM(AuxDCEPtr dce, unsigned char mode, unsigned char depth, unsigne
|
||||
pram.depth = depth;
|
||||
pram.page = page;
|
||||
spb.spSlot = dce->dCtlSlot;
|
||||
spb.spsPointer = &pram;
|
||||
spb.spsPointer = (Ptr)&pram;
|
||||
err = SPutPRAMRec(&spb);
|
||||
}
|
||||
return err;
|
||||
|
||||
216
DeclROM/NuBusFPGADrvr_MMCM.h
Normal file
216
DeclROM/NuBusFPGADrvr_MMCM.h
Normal file
@ -0,0 +1,216 @@
|
||||
|
||||
|
||||
|
||||
/* MMCM specific numbers */
|
||||
#define CLKOUT_MAX 7
|
||||
#define DELAY_TIME_MAX 63
|
||||
#define PHASE_MUX_MAX 7
|
||||
#define HIGH_LOW_TIME_REG_MAX 63
|
||||
#define PHASE_MUX_RES_FACTOR 8
|
||||
|
||||
/* DRP registers index */
|
||||
#define DRP_RESET 0
|
||||
#define DRP_LOCKED 1
|
||||
#define DRP_READ 2
|
||||
#define DRP_WRITE 3
|
||||
#define DRP_DRDY 4
|
||||
#define DRP_ADR 5
|
||||
#define DRP_DAT_W 6
|
||||
#define DRP_DAT_R 7
|
||||
|
||||
|
||||
/* Register values */
|
||||
#define FULL_REG_16 0xFFFF
|
||||
#define ZERO_REG 0x0
|
||||
#define KEEP_IN_MUL_REG1 0xF000
|
||||
#define KEEP_IN_MUL_REG2 0xFF3F
|
||||
#define KEEP_IN_DIV 0xC000
|
||||
#define REG1_FREQ_MASK 0xF000
|
||||
#define REG2_FREQ_MASK 0x803F
|
||||
#define REG1_DUTY_MASK 0xF000
|
||||
#define REG2_DUTY_MASK 0xFF7F
|
||||
#define REG1_PHASE_MASK 0x1FFF
|
||||
#define REG2_PHASE_MASK 0xFCC0
|
||||
#define FILT1_MASK 0x66FF
|
||||
#define FILT2_MASK 0x666F
|
||||
#define LOCK1_MASK 0xFC00
|
||||
#define LOCK23_MASK 0x8000
|
||||
/* Control bits extraction masks */
|
||||
#define HL_TIME_MASK 0x3F
|
||||
#define FRAC_MASK 0x7
|
||||
#define EDGE_MASK 0x1
|
||||
#define NO_CNT_MASK 0x1
|
||||
#define FRAC_EN_MASK 0x1
|
||||
#define PHASE_MUX_MASK 0x7
|
||||
|
||||
/* Bit groups start position in DRP registers */
|
||||
#define HIGH_TIME_POS 6
|
||||
#define LOW_TIME_POS 0
|
||||
#define PHASE_MUX_POS 13
|
||||
#define FRAC_POS 12
|
||||
#define FRAC_EN_POS 11
|
||||
#define FRAC_WF_R_POS 10
|
||||
#define EDGE_POS 7
|
||||
#define NO_CNT_POS 6
|
||||
#define EDGE_DIVREG_POS 13
|
||||
#define NO_CNT_DIVREG_POS 12
|
||||
#define DELAY_TIME_POS 0
|
||||
|
||||
/* MMCM Register addresses */
|
||||
#define POWER_REG 0x28
|
||||
#define DIV_REG 0x16
|
||||
#define LOCK_REG1 0x18
|
||||
#define LOCK_REG2 0x19
|
||||
#define LOCK_REG3 0x1A
|
||||
#define FILT_REG1 0x4E
|
||||
#define FILT_REG2 0x4F
|
||||
#define CLKOUT0_REG1 0x08
|
||||
#define CLKOUT0_REG2 0x09
|
||||
#define CLKOUT1_REG1 0x0A
|
||||
#define CLKOUT1_REG2 0x0B
|
||||
#define CLKOUT2_REG1 0x0C
|
||||
#define CLKOUT2_REG2 0x0D
|
||||
#define CLKOUT3_REG1 0x0E
|
||||
#define CLKOUT3_REG2 0x0F
|
||||
#define CLKOUT4_REG1 0x10
|
||||
#define CLKOUT4_REG2 0x11
|
||||
#define CLKOUT5_REG1 0x06
|
||||
#define CLKOUT5_REG2 0x07
|
||||
#define CLKOUT6_REG1 0x12
|
||||
#define CLKOUT6_REG2 0x13
|
||||
#define CLKFBOUT_REG1 0x14
|
||||
#define CLKFBOUT_REG2 0x15
|
||||
|
||||
#define litex_clk_set_reg(a, b) *((volatile uint32_t*)(a32 + CSR_CRG_VIDEO_PLL_##a##_ADDR + 0)) = __builtin_bswap32(b)
|
||||
#define litex_clk_get_reg(a) __builtin_bswap32(*((volatile uint32_t*)(a32 + CSR_CRG_VIDEO_PLL_##a##_ADDR)))
|
||||
#define litex_clk_assert_reg(a) *((volatile uint32_t*)(a32 + CSR_CRG_VIDEO_PLL_##a##_ADDR + 0)) = ((uint32_t)(-1))
|
||||
#define litex_clk_deassert_reg(a) *((volatile uint32_t*)(a32 + CSR_CRG_VIDEO_PLL_##a##_ADDR + 0)) = ((uint32_t)(0))
|
||||
|
||||
#define __ASSERT(a, b)
|
||||
#define LOG_WRN(a, b)
|
||||
|
||||
static inline void mmcm_waitSome(unsigned long bound) {
|
||||
unsigned long i;
|
||||
for (i = 0 ; i < bound ; i++) {
|
||||
asm volatile("nop");
|
||||
}
|
||||
}
|
||||
static inline void delay(int d) {
|
||||
mmcm_waitSome(d * 20); // improveme
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int litex_clk_wait(uint32_t a32, uint32_t reg)
|
||||
{
|
||||
uint32_t timeout;
|
||||
|
||||
__ASSERT(reg == DRP_LOCKED || reg == DRP_DRDY, "Unsupported register! Please provide DRP_LOCKED or DRP_DRDY");
|
||||
|
||||
if (reg == DRP_LOCKED) {
|
||||
timeout = 1000 /* ldev->timeout.lock */;
|
||||
while (!litex_clk_get_reg(DRP_LOCKED) && timeout) {
|
||||
timeout--;
|
||||
/* k_sleep(K_MSEC(1)); */
|
||||
delay(5);
|
||||
}
|
||||
} else {
|
||||
timeout = 1000 /* ldev->timeout.drdy */;
|
||||
while (!litex_clk_get_reg(DRP_DRDY) && timeout) {
|
||||
timeout--;
|
||||
/* k_sleep(K_MSEC(1)); */
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
/*Waiting for signal to assert in reg*/
|
||||
/* macro... can't use 'reg' */
|
||||
/* while (!litex_clk_get_reg(reg) && timeout) { */
|
||||
/* timeout--; */
|
||||
/* /\* k_sleep(K_MSEC(1)); *\/ */
|
||||
/* delay(5); */
|
||||
/* } */
|
||||
if (timeout == 0) {
|
||||
LOG_WRN("Timeout occured when waiting for the register: 0x%x", reg);
|
||||
return ioErr;
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
/* Read value written in given internal MMCM register*/
|
||||
static inline int litex_clk_get_DO(uint32_t a32, uint8_t clk_reg_addr, uint16_t *res)
|
||||
{
|
||||
int ret = noErr;
|
||||
|
||||
litex_clk_set_reg(DRP_ADR, clk_reg_addr);
|
||||
litex_clk_assert_reg(DRP_READ);
|
||||
|
||||
litex_clk_deassert_reg(DRP_READ);
|
||||
ret = litex_clk_wait(a32, DRP_DRDY);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*res = litex_clk_get_reg(DRP_DAT_R);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
/* Sets calculated DI value into DI DRP register */
|
||||
static inline int litex_clk_set_DI(uint32_t a32, uint16_t DI_val)
|
||||
{
|
||||
int ret = noErr;
|
||||
|
||||
litex_clk_set_reg(DRP_DAT_W, DI_val);
|
||||
litex_clk_assert_reg(DRP_WRITE);
|
||||
litex_clk_deassert_reg(DRP_WRITE);
|
||||
ret = litex_clk_wait(a32, DRP_DRDY);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns raw value ready to be written into MMCM */
|
||||
static inline uint16_t litex_clk_calc_DI(uint16_t DO_val, uint16_t mask,
|
||||
uint16_t bitset)
|
||||
{
|
||||
uint16_t DI_val;
|
||||
|
||||
DI_val = DO_val & mask;
|
||||
DI_val |= bitset;
|
||||
|
||||
return DI_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change register value as specified in arguments
|
||||
*
|
||||
* mask: preserve or zero MMCM register bits
|
||||
* by selecting 1 or 0 on desired specific mask positions
|
||||
* bitset: set those bits in MMCM register which are 1 in bitset
|
||||
* clk_reg_addr: internal MMCM address of control register
|
||||
*
|
||||
*/
|
||||
static inline int litex_clk_change_value_norst(uint32_t a32,
|
||||
uint16_t mask, uint16_t bitset,
|
||||
uint8_t clk_reg_addr)
|
||||
{
|
||||
uint16_t DO_val, DI_val;
|
||||
int ret = noErr;
|
||||
|
||||
// litex_clk_assert_reg(DRP_RESET);
|
||||
|
||||
ret = litex_clk_get_DO(a32, clk_reg_addr, &DO_val);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
DI_val = litex_clk_calc_DI(DO_val, mask, bitset);
|
||||
ret = litex_clk_set_DI(a32, DI_val);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
#ifdef CONFIG_CLOCK_CONTROL_LOG_LEVEL_DBG
|
||||
DI_val = litex_clk_get_reg(DRP_DAT_W);
|
||||
LOG_DBG("set 0x%x under: 0x%x", DI_val, clk_reg_addr);
|
||||
#endif
|
||||
litex_clk_deassert_reg(DRP_DAT_W);
|
||||
// litex_clk_deassert_reg(DRP_RESET);
|
||||
// ret = litex_clk_wait(DRP_LOCKED);
|
||||
return ret;
|
||||
}
|
||||
@ -21,7 +21,7 @@ __attribute__ ((section (".text.fbdriver"))) short fbIrq(const long sqParameter)
|
||||
ret = 0;
|
||||
irq = (*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+GOBOFB_INTR_CLEAR)));
|
||||
if (irq & 1) {
|
||||
vblproto myVbl = *(vblproto**)0x0d28;
|
||||
vblproto myVbl = *(vblproto*)0x0d28;
|
||||
*((volatile unsigned int*)(sqParameter+GOBOFB_BASE+GOBOFB_INTR_CLEAR)) = 0;
|
||||
myVbl((sqParameter>>24)&0xf); // cleaner to use dStore->slot ? but require more code...
|
||||
ret = 1;
|
||||
@ -88,7 +88,7 @@ OSErr cNuBusFPGAOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
|
||||
/* ... from ~mac68k, you need option "-mpcrel", and it works */
|
||||
/* SlotIntServiceProcPtr sqAddr; */
|
||||
/* asm("lea %%pc@(fbIrq),%0\n" : "=a"(sqAddr)); */
|
||||
siqel->sqAddr = fbIrq;
|
||||
siqel->sqAddr = (void (*)())fbIrq;
|
||||
/* siqel->sqParm = (long)dce; */
|
||||
siqel->sqParm = (long)dce->dCtlDevBase;
|
||||
dStore->siqel = siqel;
|
||||
@ -115,7 +115,7 @@ OSErr cNuBusFPGAOpen(IOParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
|
||||
while ((err == noErr) &&
|
||||
(spb.spSlot == dce->dCtlSlot) &&
|
||||
(((UInt8)spb.spID) > (UInt8)0x80) &&
|
||||
(((UInt8)spb.spID) < (UInt8)0x90)) {
|
||||
(((UInt8)spb.spID) < (UInt8)0xA0)) {
|
||||
/* write_reg(dce, GOBOFB_DEBUG, 0xBEEF0020); */
|
||||
/* write_reg(dce, GOBOFB_DEBUG, spb.spID); */
|
||||
/* write_reg(dce, GOBOFB_DEBUG, err); */
|
||||
|
||||
@ -71,15 +71,15 @@ OSErr cNuBusFPGAStatus(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
|
||||
case cscGetPageCnt: /* 4 == cscGetPages */
|
||||
{
|
||||
VDPageInfo *vPInfo = (VDPageInfo *)*(long *)pb->csParam;
|
||||
if ((vPInfo->csMode != kDepthMode1) &&
|
||||
(vPInfo->csMode != kDepthMode2) &&
|
||||
(vPInfo->csMode != kDepthMode3) &&
|
||||
(vPInfo->csMode != kDepthMode4) &&
|
||||
(vPInfo->csMode != kDepthMode5) &&
|
||||
(vPInfo->csMode != kDepthMode6)) {
|
||||
ret = paramErr;
|
||||
goto done;
|
||||
}
|
||||
if ((vPInfo->csMode != kDepthMode1) &&
|
||||
(vPInfo->csMode != kDepthMode2) &&
|
||||
(vPInfo->csMode != kDepthMode3) &&
|
||||
(vPInfo->csMode != kDepthMode4) &&
|
||||
(vPInfo->csMode != kDepthMode5) &&
|
||||
(vPInfo->csMode != kDepthMode6)) {
|
||||
ret = paramErr;
|
||||
goto done;
|
||||
}
|
||||
vPInfo->csPage = (vPInfo->csMode == kDepthMode5) ? 1 : 2;
|
||||
ret = noErr;
|
||||
}
|
||||
@ -252,25 +252,34 @@ OSErr cNuBusFPGAStatus(CntrlParamPtr pb, /* DCtlPtr */ AuxDCEPtr dce)
|
||||
}
|
||||
if (((UInt8)vdres->csPreviousDisplayModeID) == dStore->maxMode)
|
||||
vdres->csDisplayModeID = kDisplayModeIDNoMoreResolutions;
|
||||
else
|
||||
else {
|
||||
/* some of the odd numbered modes are missing */
|
||||
vdres->csDisplayModeID = ((UInt8)vdres->csPreviousDisplayModeID) + 1;
|
||||
vdres->csHorizontalPixels = dStore->hres[((UInt8)vdres->csDisplayModeID) - nativeVidMode];
|
||||
vdres->csVerticalLines = dStore->vres[((UInt8)vdres->csDisplayModeID) - nativeVidMode];
|
||||
vdres->csRefreshRate = 60 << 16; /* Fixed(Point) 16+16 */
|
||||
vdres->csMaxDepthMode = kDepthMode6;
|
||||
while ((dStore->hres[((UInt8)vdres->csDisplayModeID) - nativeVidMode] == 0) &&
|
||||
(((UInt8)vdres->csPreviousDisplayModeID) < dStore->maxMode))
|
||||
vdres->csDisplayModeID ++;
|
||||
}
|
||||
if (vdres->csDisplayModeID >= dStore->maxMode) {
|
||||
vdres->csDisplayModeID = kDisplayModeIDNoMoreResolutions;
|
||||
} else {
|
||||
vdres->csHorizontalPixels = dStore->hres[((UInt8)vdres->csDisplayModeID) - nativeVidMode];
|
||||
vdres->csVerticalLines = dStore->vres[((UInt8)vdres->csDisplayModeID) - nativeVidMode];
|
||||
vdres->csRefreshRate = (60 << 16) + (vdres->csDisplayModeID & 1); /* Fixed(Point) 16+16 */
|
||||
vdres->csMaxDepthMode = kDepthMode6;
|
||||
}
|
||||
break;
|
||||
case kDisplayModeIDFindFirstResolution:
|
||||
vdres->csDisplayModeID = nativeVidMode;
|
||||
vdres->csHorizontalPixels = dStore->hres[0];
|
||||
vdres->csVerticalLines = dStore->vres[0];
|
||||
vdres->csRefreshRate = 60 << 16; /* Fixed(Point) 16+16 */
|
||||
vdres->csRefreshRate = (60 << 16) + (vdres->csDisplayModeID & 1); /* Fixed(Point) 16+16 */
|
||||
vdres->csMaxDepthMode = kDepthMode6;
|
||||
break;
|
||||
case kDisplayModeIDCurrent:
|
||||
vdres->csDisplayModeID = dStore->curMode;
|
||||
vdres->csHorizontalPixels = dStore->hres[dStore->curMode - nativeVidMode];
|
||||
vdres->csVerticalLines = dStore->vres[dStore->curMode - nativeVidMode];
|
||||
vdres->csRefreshRate = 60 << 16; /* Fixed(Point) 16+16 */
|
||||
vdres->csRefreshRate = (60 << 16) + (vdres->csDisplayModeID & 1); /* Fixed(Point) 16+16 */
|
||||
vdres->csMaxDepthMode = kDepthMode6;
|
||||
break;
|
||||
}
|
||||
|
||||
110
DeclROM/NuBusFPGADrvr_Timings.h
Normal file
110
DeclROM/NuBusFPGADrvr_Timings.h
Normal file
@ -0,0 +1,110 @@
|
||||
struct vtg_timing_regs {
|
||||
unsigned short hres;
|
||||
unsigned short hsync_start;
|
||||
unsigned short hsync_end;
|
||||
unsigned short hscan;
|
||||
unsigned short vres;
|
||||
unsigned short vsync_start;
|
||||
unsigned short vsync_end;
|
||||
unsigned short vscan;
|
||||
};
|
||||
struct vtg_timing_regs vtg_640x480_60Hz = {
|
||||
.hres = 640,
|
||||
.hsync_start = 656,
|
||||
.hsync_end = 752,
|
||||
.hscan = 800,
|
||||
.vres = 480,
|
||||
.vsync_start = 490,
|
||||
.vsync_end = 492,
|
||||
.vscan = 525
|
||||
};
|
||||
struct vtg_timing_regs vtg_640x480_75Hz = {
|
||||
.hres = 640,
|
||||
.hsync_start = 656,
|
||||
.hsync_end = 720,
|
||||
.hscan = 840,
|
||||
.vres = 480,
|
||||
.vsync_start = 481,
|
||||
.vsync_end = 484,
|
||||
.vscan = 500
|
||||
};
|
||||
struct vtg_timing_regs vtg_800x600_60Hz = {
|
||||
.hres = 800,
|
||||
.hsync_start = 840,
|
||||
.hsync_end = 968,
|
||||
.hscan = 1056,
|
||||
.vres = 600,
|
||||
.vsync_start = 601,
|
||||
.vsync_end = 605,
|
||||
.vscan = 628
|
||||
};
|
||||
struct vtg_timing_regs vtg_800x600_75Hz = {
|
||||
.hres = 800,
|
||||
.hsync_start = 816,
|
||||
.hsync_end = 896,
|
||||
.hscan = 1056,
|
||||
.vres = 600,
|
||||
.vsync_start = 601,
|
||||
.vsync_end = 604,
|
||||
.vscan = 625
|
||||
};
|
||||
struct vtg_timing_regs vtg_1024x768_60Hz = {
|
||||
.hres = 1024,
|
||||
.hsync_start = 1048,
|
||||
.hsync_end = 1184,
|
||||
.hscan = 1344,
|
||||
.vres = 768,
|
||||
.vsync_start = 771,
|
||||
.vsync_end = 777,
|
||||
.vscan = 806
|
||||
};
|
||||
struct vtg_timing_regs vtg_1024x768_75Hz = {
|
||||
.hres = 1024,
|
||||
.hsync_start = 1040,
|
||||
.hsync_end = 1136,
|
||||
.hscan = 1312,
|
||||
.vres = 768,
|
||||
.vsync_start = 769,
|
||||
.vsync_end = 772,
|
||||
.vscan = 800
|
||||
};
|
||||
struct vtg_timing_regs vtg_1280x720_60Hz = {
|
||||
.hres = 1280,
|
||||
.hsync_start = 1500,
|
||||
.hsync_end = 1540,
|
||||
.hscan = 1650,
|
||||
.vres = 720,
|
||||
.vsync_start = 725,
|
||||
.vsync_end = 730,
|
||||
.vscan = 750
|
||||
};
|
||||
struct vtg_timing_regs vtg_1280x1024_60Hz = {
|
||||
.hres = 1280,
|
||||
.hsync_start = 1328,
|
||||
.hsync_end = 1440,
|
||||
.hscan = 1688,
|
||||
.vres = 1024,
|
||||
.vsync_start = 1025,
|
||||
.vsync_end = 1028,
|
||||
.vscan = 1066
|
||||
};
|
||||
struct vtg_timing_regs vtg_1920x1080_30Hz = {
|
||||
.hres = 1920,
|
||||
.hsync_start = 2448,
|
||||
.hsync_end = 2492,
|
||||
.hscan = 2640,
|
||||
.vres = 1080,
|
||||
.vsync_start = 1084,
|
||||
.vsync_end = 1089,
|
||||
.vscan = 1125
|
||||
};
|
||||
struct vtg_timing_regs vtg_1920x1080_60Hz = {
|
||||
.hres = 1920,
|
||||
.hsync_start = 2008,
|
||||
.hsync_end = 2052,
|
||||
.hscan = 2200,
|
||||
.vres = 1080,
|
||||
.vsync_start = 1084,
|
||||
.vsync_end = 1089,
|
||||
.vscan = 1125
|
||||
};
|
||||
17
DeclROM/gen_liteeth_param.sh
Executable file
17
DeclROM/gen_liteeth_param.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
/bin/rm -f liteeth_param.inc
|
||||
|
||||
touch liteeth_param.inc
|
||||
|
||||
echo -n 'liteethmac_base = ' >> liteeth_param.inc
|
||||
grep -q csr_base,ethmac ../../csr.csv || echo "0x0" >> liteeth_param.inc
|
||||
grep csr_base,ethmac ../../csr.csv | awk -F, '{ print $3}' | sed -e 's/0x[fF]0a0/0x00a0/' >> liteeth_param.inc
|
||||
|
||||
echo -n 'liteethphy_base = ' >> liteeth_param.inc
|
||||
grep -q csr_base,ethphy ../../csr.csv || echo "0x0" >> liteeth_param.inc
|
||||
grep csr_base,ethphy ../../csr.csv | awk -F, '{ print $3}' | sed -e 's/0x[fF]0a0/0x00a0/' >> liteeth_param.inc
|
||||
|
||||
echo -n 'liteethmac_memory = ' >> liteeth_param.inc
|
||||
grep -q memory_region,ethmac ../../csr.csv || echo "0x0" >> liteeth_param.inc
|
||||
grep memory_region,ethmac ../../csr.csv | awk -F, '{ print $3}' | sed -e 's/0x[fF]0c0/0x00c0/' >> liteeth_param.inc
|
||||
@ -7,37 +7,38 @@ struct one_res {
|
||||
const unsigned short hres;
|
||||
const unsigned short vres;
|
||||
const unsigned char native_only;
|
||||
const unsigned char has_hw;
|
||||
};
|
||||
|
||||
#define NUM_RES 16
|
||||
#if 1
|
||||
static struct one_res res_db[NUM_RES] = {
|
||||
{ 1920, 1080, 0 },
|
||||
{ 1680, 1050, 0 }, // should be unsuitable
|
||||
{ 1600, 900, 1 }, // freaks out my monitor on 1920x1080, it thinks it's 1680x1050...
|
||||
{ 1440, 900, 0 },
|
||||
{ 1920, 1080, 0, 0}, /* 148.5 */
|
||||
{ 1680, 1050, 0, 0}, // should be unsuitable
|
||||
{ 1600, 900, 1, 0}, // freaks out my monitor on 1920x1080, it thinks it's 1680x1050...
|
||||
{ 1440, 900, 0, 0},
|
||||
|
||||
{ 1280, 1024, 0 },
|
||||
{ 1280, 960, 0 },
|
||||
{ 1280, 800, 0 },
|
||||
{ 1152, 870, 0 },
|
||||
{ 1280, 1024, 0, 1},
|
||||
{ 1280, 960, 0, 0},
|
||||
{ 1280, 800, 0, 0},
|
||||
{ 1152, 870, 0, 0},
|
||||
|
||||
{ 1152, 864, 0 },
|
||||
{ 1024, 768, 0 },
|
||||
{ 832, 624, 0 },
|
||||
{ 800, 600, 0 },
|
||||
{ 1152, 864, 0, 0},
|
||||
{ 1024, 768, 0, 0},
|
||||
{ 832, 624, 0, 0},
|
||||
{ 800, 600, 0, 1},
|
||||
|
||||
{ 768, 576, 0 },
|
||||
{ 640, 480, 0 },
|
||||
{ 512, 384, 0 },
|
||||
{ 0, 0, 0 }
|
||||
{ 768, 576, 0, 0},
|
||||
{ 640, 480, 0, 1}, /* 25.125 */
|
||||
{ 512, 384, 0, 0},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
#else
|
||||
static struct one_res res_db[NUM_RES] = {
|
||||
{ 1920, 1080, 0 },
|
||||
{ 1600, 900, 1 },
|
||||
/* { 640, 480, 0 }, */
|
||||
{ 0, 0, 0}
|
||||
{ 1920, 1080, 0, 0 },
|
||||
{ 1600, 900, 1, 0 },
|
||||
/* { 640, 480, 0, 0 }, */
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -59,7 +60,7 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr, "Resolution: %hu x %hu\n", maxhres, maxvres);
|
||||
|
||||
id = 0x80;
|
||||
for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) && (id < 0x90); i++) { // 0x90 is the ram disk
|
||||
for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) && (id < 0xA0); i++) { // 0xA0 is audio
|
||||
char filename[512];
|
||||
const unsigned short hres = res_db[i].hres;
|
||||
const unsigned short vres = res_db[i].vres;
|
||||
@ -81,7 +82,6 @@ int main(int argc, char **argv) {
|
||||
return -1;
|
||||
}
|
||||
enabled[i] = 1;
|
||||
id ++;
|
||||
|
||||
for (j = 0 ; j < 6 ; j++) {
|
||||
char modename[128];
|
||||
@ -90,7 +90,7 @@ int main(int argc, char **argv) {
|
||||
snprintf(modename, 128, "R%hux%huD%d", hres, vres, depth);
|
||||
|
||||
fprintf(fd, "\tALIGN 2\n");
|
||||
fprintf(fd, "_%sModes: /* id 0x%02x */\n", modename, id-1);
|
||||
fprintf(fd, "_%sModes: /* id 0x%02x */\n", modename, id);
|
||||
fprintf(fd, "\tOSLstEntry\tmVidParams,_%sParms\t/* offset to vid parameters */\n", modename);
|
||||
fprintf(fd, "\tDatLstEntry\tmPageCnt,%d\t/* number of video pages */\n", (depth == 32) ? 1 : 2);
|
||||
fprintf(fd, "\tDatLstEntry\tmDevType,%s\t/* device type */\n", depth <= 8 ? "clutType" : "directType");
|
||||
@ -112,13 +112,47 @@ int main(int argc, char **argv) {
|
||||
fprintf(fd, "\t.long\t0\t/* bmPlaneBytes */\n"); // defmPlaneBytes
|
||||
fprintf(fd, "_End%sParms:\n\n",modename);
|
||||
}
|
||||
|
||||
if (res_db[i].has_hw) {
|
||||
for (j = 0 ; j < 6 ; j++) {
|
||||
char modename[128];
|
||||
const unsigned short depth = depthdb[j];
|
||||
const unsigned short rowBytes = (hres * depth) / 8;
|
||||
snprintf(modename, 128, "R%hux%huDHW%d", hres, vres, depth);
|
||||
|
||||
fprintf(fd, "\tALIGN 2\n");
|
||||
fprintf(fd, "_%sModes: /* id 0x%02x */\n", modename, id + 1);
|
||||
fprintf(fd, "\tOSLstEntry\tmVidParams,_%sParms\t/* offset to vid parameters */\n", modename);
|
||||
fprintf(fd, "\tDatLstEntry\tmPageCnt,%d\t/* number of video pages */\n", (depth == 32) ? 1 : 2);
|
||||
fprintf(fd, "\tDatLstEntry\tmDevType,%s\t/* device type */\n", depth <= 8 ? "clutType" : "directType");
|
||||
fprintf(fd, "\t.long\tEndOfList\t/* end of list */\n");
|
||||
fprintf(fd, "_%sParms:\n", modename);
|
||||
fprintf(fd, "\t.long\t_End%sParms-_%sParms\t/* physical block size */\n", modename, modename);
|
||||
fprintf(fd, "\t.long\t0\t/* QuickDraw base offset ; vpBaseOffset */\n"); // defmBaseOffset
|
||||
fprintf(fd, "\t.word\t%hu\t/* physRowBytes ; vpRowBytes */\n", rowBytes);
|
||||
fprintf(fd, "\t.word\t0,0,%hu,%hu\t/* vpBounds */\n", vres, hres);
|
||||
fprintf(fd, "\t.word\tdefVersion\t/* bmVersion ; vpVersion */\n");
|
||||
fprintf(fd, "\t.word\t0\t/* packType not used ; vpPackType */\n");
|
||||
fprintf(fd, "\t.long\t0\t/* packSize not used ; vpPackSize */\n");
|
||||
fprintf(fd, "\t.long\tdefmHRes\t/* bmHRes */\n");
|
||||
fprintf(fd, "\t.long\tdefmVRes\t/* bmVRes */\n");
|
||||
fprintf(fd, "\t.word\t%s\t/* bmPixelType */\n", depth <= 8 ? "ChunkyIndexed" : "ChunkyDirect");
|
||||
fprintf(fd, "\t.word\t%d\t/* bmPixelSize */\n", depth);
|
||||
fprintf(fd, "\t.word\t%d\t/* bmCmpCount */\n", depth <= 8 ? 1 : 3);
|
||||
fprintf(fd, "\t.word\t%d\t/* bmCmpSize */\n", depth <= 8 ? depth : (depth == 32 ? 8 : 5));
|
||||
fprintf(fd, "\t.long\t0\t/* bmPlaneBytes */\n"); // defmPlaneBytes
|
||||
fprintf(fd, "_End%sParms:\n\n",modename);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
|
||||
id += 2 ; // even are 'windowboxed' // here we are 'enabled'
|
||||
}
|
||||
|
||||
{
|
||||
char filename[512];
|
||||
FILE *fd;
|
||||
id = 0x80;
|
||||
snprintf(filename, 512, "VidRomRes.s");
|
||||
fd = fopen(filename, "w");
|
||||
if (fd == NULL) {
|
||||
@ -167,10 +201,37 @@ int main(int argc, char **argv) {
|
||||
fprintf(fd, "_ScreenNameGoboFB_R%hux%hu:\n", hres, vres);
|
||||
fprintf(fd, "\t.long\t_ScreenNameGoboFB_R%hux%huEnd - _ScreenNameGoboFB_R%hux%hu\n", hres, vres, hres, vres);
|
||||
fprintf(fd, "\t.word\t0\n");
|
||||
fprintf(fd, "\t.string\t\"GoblinFB %hux%hu%s\\0\"\n", hres, vres, native ? " (N)": "");
|
||||
fprintf(fd, "\t.string\t\"GoblinFB %hux%hu%s\\0\"\n", hres, vres, native ? " (N)" : "");
|
||||
fprintf(fd, "_ScreenNameGoboFB_R%hux%huEnd:\n", hres, vres);
|
||||
}
|
||||
}
|
||||
if (res_db[i].has_hw) {
|
||||
fprintf(fd, "\tALIGN 2\n");
|
||||
fprintf(fd, "_VModeName:\n");
|
||||
|
||||
for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) ; i++) {
|
||||
const unsigned short hres = res_db[i].hres;
|
||||
const unsigned short vres = res_db[i].vres;
|
||||
if (enabled[i]) {
|
||||
fprintf(fd, "\tOSLstEntry\tsRsrc_GoboFB_R%hux%huHW,_ScreenNameGoboFB_R%hux%huHW\n", hres, vres, hres, vres);
|
||||
}
|
||||
}
|
||||
fprintf(fd, "\tDatLstEntry endOfList, 0\n");
|
||||
|
||||
for (i = 0 ; (res_db[i].hres != 0) && (res_db[i].vres != 0) ; i++) {
|
||||
const unsigned short hres = res_db[i].hres;
|
||||
const unsigned short vres = res_db[i].vres;
|
||||
if (enabled[i]) {
|
||||
int native = (hres == maxhres) && (vres == maxvres);
|
||||
fprintf(fd, "\tALIGN 2\n");
|
||||
fprintf(fd, "_ScreenNameGoboFB_R%hux%huHW:\n", hres, vres);
|
||||
fprintf(fd, "\t.long\t_ScreenNameGoboFB_R%hux%huHWEnd - _ScreenNameGoboFB_R%hux%huHW\n", hres, vres, hres, vres);
|
||||
fprintf(fd, "\t.word\t0\n");
|
||||
fprintf(fd, "\t.string\t\"GoblinFB %hux%hu%s\\0\"\n", hres, vres, " HW");
|
||||
fprintf(fd, "_ScreenNameGoboFB_R%hux%huHWEnd:\n", hres, vres);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
@ -207,6 +268,26 @@ int main(int argc, char **argv) {
|
||||
fprintf(fd, "\tOSLstEntry\tfifthVidMode,_R%hux%huD32Modes\t/* offset to 24/32 Bit Mode parms */\n", hres, vres);
|
||||
fprintf(fd, "\tOSLstEntry\tsixthVidMode,_R%hux%huD16Modes\t/* offset to 15/16 Bit Mode parms */\n", hres, vres);
|
||||
fprintf(fd, "\t.long EndOfList\t/* end of list */\n\n");
|
||||
if (res_db[i].has_hw) {
|
||||
fprintf(fd, "\tALIGN 2\n");
|
||||
fprintf(fd, "_sRsrc_GoboFB_R%hux%huHW:\n", hres, vres);
|
||||
fprintf(fd, "\tOSLstEntry\tsRsrcType,_GoboFBType\t/* video type descriptor */\n");
|
||||
fprintf(fd, "\tOSLstEntry\tsRsrcName,_GoboFBName\t/* offset to driver name string */\n");
|
||||
fprintf(fd, "\tOSLstEntry\tsRsrcDrvrDir,_GoboFBDrvrDir /* offset to driver directory */\n");
|
||||
fprintf(fd, "\tDatLstEntry\tsRsrcFlags,%d\t/* force 32 bits mode & open (native) - or not (others)*/\n", native ? 6 : 0);
|
||||
fprintf(fd, "\tDatLstEntry\tsRsrcHWDevId,1\t/* hardware device ID */\n");
|
||||
fprintf(fd, "\tOSLstEntry\tMinorBaseOS,_MinorBase\t/* offset to frame buffer array */\n");
|
||||
fprintf(fd, "\tOSLstEntry\tMinorLength,_MinorLength\t/* offset to frame buffer length */\n");
|
||||
fprintf(fd, "\t/* OSLstEntry\tsGammaDir,_GammaDirS\t/* directory for 640x480 monitor */\n");
|
||||
fprintf(fd, "/* Parameters */\n");
|
||||
fprintf(fd, "\tOSLstEntry\tfirstVidMode,_R%hux%huDHW8Modes\t/* offset to 8 Bit Mode parms */\n", hres, vres);
|
||||
fprintf(fd, "\tOSLstEntry\tsecondVidMode,_R%hux%huDHW4Modes\t/* offset to 4 Bit Mode parms */\n", hres, vres);
|
||||
fprintf(fd, "\tOSLstEntry\tthirdVidMode,_R%hux%huDHW2Modes\t/* offset to 2 Bit Mode parms */\n", hres, vres);
|
||||
fprintf(fd, "\tOSLstEntry\tfourthVidMode,_R%hux%huDHW1Modes\t/* offset to 1 Bit Mode parms */\n", hres, vres);
|
||||
fprintf(fd, "\tOSLstEntry\tfifthVidMode,_R%hux%huDHW32Modes\t/* offset to 24/32 Bit Mode parms */\n", hres, vres);
|
||||
fprintf(fd, "\tOSLstEntry\tsixthVidMode,_R%hux%huDHW16Modes\t/* offset to 15/16 Bit Mode parms */\n", hres, vres);
|
||||
fprintf(fd, "\t.long EndOfList\t/* end of list */\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
@ -215,7 +296,6 @@ int main(int argc, char **argv) {
|
||||
{
|
||||
char filename[512];
|
||||
FILE *fd;
|
||||
unsigned char id = 0x80;
|
||||
snprintf(filename, 512, "VidRomDir.s");
|
||||
fd = fopen(filename, "w");
|
||||
if (fd == NULL) {
|
||||
@ -244,7 +324,10 @@ int main(int argc, char **argv) {
|
||||
const unsigned short hres = res_db[i].hres;
|
||||
const unsigned short vres = res_db[i].vres;
|
||||
if (enabled[i]) {
|
||||
fprintf(fd, "sRsrc_GoboFB_R%hux%hu = 0x%02hhx\n", hres, vres, id++);
|
||||
fprintf(fd, "sRsrc_GoboFB_R%hux%hu = 0x%02hhx\n", hres, vres, id);
|
||||
if (res_db[i].has_hw)
|
||||
fprintf(fd, "sRsrc_GoboFB_R%hux%huHW = 0x%02hhx\n", hres, vres, id+1);
|
||||
id += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,6 +350,9 @@ int main(int argc, char **argv) {
|
||||
const unsigned short vres = res_db[i].vres;
|
||||
if (enabled[i]) {
|
||||
fprintf(fd, "\tOSLstEntry\tsRsrc_GoboFB_R%hux%hu,_sRsrc_GoboFB_R%hux%hu/* video sRsrc List */\n", hres, vres, hres, vres);
|
||||
if (res_db[i].has_hw) {
|
||||
fprintf(fd, "\tOSLstEntry\tsRsrc_GoboFB_R%hux%huHW,_sRsrc_GoboFB_R%hux%huHW/* video sRsrc List */\n", hres, vres, hres, vres);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_RAMDSK
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
|
||||
sRsrc_Board = 1 /* board sResource (>0 & <128) */
|
||||
.include "VidRomDef.s"
|
||||
sRsrc_RAMDsk = 0x90 /* functional sResources */
|
||||
sRsrc_SDCard = 0x91 /* functional sResources */
|
||||
sRsrc_RAMDsk = 0xF0 /* functional sResources */
|
||||
sRsrc_SDCard = 0xF1 /* functional sResources */
|
||||
sRsrc_HDMIAudio = 0xA0 /* functional sResources */
|
||||
|
||||
.global DeclROMDir
|
||||
|
||||
@ -48,8 +48,6 @@ class VideoFrameBufferMultiDepth(Module, AutoCSR):
|
||||
print(f"FRAMEBUFFER: dram_port.data_width = {dram_port.data_width}, {hres}x{vres}, 0x{base:x}, in {clock_domain}, clock_faster_than_sys={clock_faster_than_sys}")
|
||||
|
||||
vga_sync = getattr(self.sync, clock_domain) # usually should be named hdmi_sync, really...
|
||||
|
||||
npixels = hres * vres # default to max
|
||||
|
||||
# if 0, 32-bits mode
|
||||
# should only be changed while in reset
|
||||
@ -150,7 +148,7 @@ class VideoFrameBufferMultiDepth(Module, AutoCSR):
|
||||
self.submodules.fb_dma = LiteDRAMFBDMAReader(dram_port,
|
||||
fifo_depth = fifo_depth//(dram_port.data_width//8),
|
||||
default_base = base,
|
||||
default_length = npixels)
|
||||
default_length = (hres * vres)) # default to max
|
||||
|
||||
# If DRAM Data Width > 8-bit and Video clock is faster than sys_clk:
|
||||
# actually always use that case to simplify the design
|
||||
@ -393,7 +391,7 @@ class GoblinAlt(Module, AutoCSR):
|
||||
|
||||
name = "video_framebuffer"
|
||||
# near duplicate of plaform.add_video_framebuffer
|
||||
# Video Timing Generator. Interface, we only keep the CSR & timingd stuff for compatibility
|
||||
# Video Timing Generator. Interface, we only keep the CSR & timings stuff for compatibility
|
||||
vtg = FBVideoTimingGeneratorInterface(default_video_timings=timings if isinstance(timings, str) else timings[1])
|
||||
vtg = ClockDomainsRenamer(clock_domain)(vtg)
|
||||
setattr(self.submodules, f"{name}_vtg", vtg)
|
||||
@ -455,6 +453,7 @@ class GoblinAlt(Module, AutoCSR):
|
||||
bt_addr = Signal(8, reset = 0) # reg 0x14 ; lut itself in reg 0x18
|
||||
bt_cmap_state = Signal(2, reset = 0)
|
||||
m_vbl_disable = Signal(reset = 1) # reg 0x4
|
||||
bt_upd = Signal()
|
||||
|
||||
# for sub-resolution
|
||||
hres_start = Signal(hbits, reset = 0)
|
||||
@ -464,6 +463,8 @@ class GoblinAlt(Module, AutoCSR):
|
||||
vres_upd = Signal()
|
||||
|
||||
videoctrl = Signal() # reg 0x8
|
||||
videoctrl_upd = Signal()
|
||||
videoctrl_busy = Signal()
|
||||
|
||||
vbl_signal = Signal(reset = 0) # reg 0xC
|
||||
self.comb += irq_line.eq(~vbl_signal | m_vbl_disable) # irq_line is active low
|
||||
@ -485,11 +486,13 @@ class GoblinAlt(Module, AutoCSR):
|
||||
Case(bus.adr[0:18], {
|
||||
"default": [],
|
||||
# gobofb_mode
|
||||
0x0: [ NextValue(bt_mode, bus.dat_w[low_byte]), ],
|
||||
0x0: [ NextValue(bt_mode, bus.dat_w[low_byte]),
|
||||
NextValue(bt_upd, 1), ],
|
||||
# set vbl
|
||||
0x1: [ NextValue(m_vbl_disable, ~bus.dat_w[low_bit]), ],
|
||||
# gobofb on/off
|
||||
0x2: [ NextValue(videoctrl, bus.dat_w[low_bit]), ],
|
||||
0x2: [ NextValue(videoctrl, bus.dat_w[low_bit]),
|
||||
NextValue(videoctrl_upd, 1), ],
|
||||
# clear irq
|
||||
0x3: [ NextValue(vbl_signal, 0), ],
|
||||
# 0x4: reset in SW
|
||||
@ -548,7 +551,7 @@ class GoblinAlt(Module, AutoCSR):
|
||||
Case(bus.adr[0:18], {
|
||||
# bt_addr
|
||||
0x0: [ NextValue(bus.dat_r[low_byte], bt_mode), ],
|
||||
0x2: [ NextValue(bus.dat_r[low_byte], videoctrl), ],
|
||||
0x2: [ NextValue(bus.dat_r[low_byte], Cat(videoctrl, videoctrl_busy)), ],
|
||||
0x3: [ NextValue(bus.dat_r[low_byte], ~irq_line), ], # irq_line is active low
|
||||
"default": [ NextValue(bus.dat_r, 0xDEADBEEF)],
|
||||
0x10: [ NextValue(bus.dat_r, hres), ], # hres (r/o) # FIXME: endianess
|
||||
@ -565,8 +568,7 @@ class GoblinAlt(Module, AutoCSR):
|
||||
)
|
||||
# mode switch logic
|
||||
#npixels = hres * vres
|
||||
npixels = Signal(hbits + vbits +1, reset = (hres * vres))
|
||||
old_bt_mode = Signal(8) # different from bt_mode
|
||||
npixels = Signal(hbits + vbits + 1, reset = (hres * vres))
|
||||
in_reset = Signal()
|
||||
post_reset_ctr = Signal(3)
|
||||
previous_videoctrl = Signal()
|
||||
@ -582,16 +584,18 @@ class GoblinAlt(Module, AutoCSR):
|
||||
handle_truecolor_bit = [ self.video_framebuffer.use_indexed.eq(~bt_mode[4:5]) ]
|
||||
else:
|
||||
handle_truecolor_bit = [ ]
|
||||
|
||||
|
||||
# this has grown complicated and should be a FSM...
|
||||
self.sync += [ old_bt_mode.eq(bt_mode),
|
||||
If((old_bt_mode != bt_mode) | vres_upd,
|
||||
self.sync += [ If(bt_upd | vres_upd,
|
||||
bt_upd.eq(0),
|
||||
vres_upd.eq(0),
|
||||
in_reset.eq(1),
|
||||
post_reset_ctr.eq(0),
|
||||
videoctrl.eq(0), # start a disabling cycle, or stay disabled
|
||||
previous_videoctrl.eq(videoctrl), # preserve old state for restoration later
|
||||
videoctrl_upd.eq(1), # start a disabling cycle, or stay disabled
|
||||
previous_videoctrl.eq(videoctrl | previous_videoctrl), # preserve old state for restoration later, if 'previous' is already set then we just had an update in the middle of an update...
|
||||
),
|
||||
If(in_reset & ~vtg_enable, # we asked for a reset and by now, the VTG has been turned off (or was off)
|
||||
If(~bt_upd & ~vres_upd & in_reset & ~vtg_enable, # we asked for a reset and by now, the VTG has been turned off (or was off)
|
||||
self.video_framebuffer.indexed_mode.eq(bt_mode[0:2]),
|
||||
*handle_truecolor_bit,
|
||||
in_reset.eq(0),
|
||||
@ -602,7 +606,7 @@ class GoblinAlt(Module, AutoCSR):
|
||||
vtg._vres_start.eq(vres_start),
|
||||
vtg._vres_end.eq( vres_end),
|
||||
),
|
||||
If(post_reset_ctr == 4, # now reconfigure the DMA
|
||||
If(~bt_upd & ~vres_upd & (post_reset_ctr == 4), # now reconfigure the DMA
|
||||
If(bt_mode[4:5],
|
||||
Case(bt_mode[0:2], {
|
||||
0x0: self.video_framebuffer.fb_dma.length.eq(npixels << 2),
|
||||
@ -617,11 +621,13 @@ class GoblinAlt(Module, AutoCSR):
|
||||
}),
|
||||
),
|
||||
),
|
||||
If(post_reset_ctr == 1, # we've waited for the mode switch so restore video mode
|
||||
videoctrl.eq(previous_videoctrl),
|
||||
If(~bt_upd & ~vres_upd & (post_reset_ctr == 1) & previous_videoctrl, # we've waited for the mode switch so restore video ctrl if set
|
||||
videoctrl.eq(1),
|
||||
videoctrl_upd.eq(1),
|
||||
previous_videoctrl.eq(0), # reset, ow that the update is finished
|
||||
),
|
||||
If(post_reset_ctr != 0,
|
||||
post_reset_ctr.eq(post_reset_ctr - 1),
|
||||
If(~bt_upd & ~vres_upd & (post_reset_ctr != 0),
|
||||
post_reset_ctr.eq(post_reset_ctr - 1),
|
||||
),
|
||||
]
|
||||
|
||||
@ -630,29 +636,40 @@ class GoblinAlt(Module, AutoCSR):
|
||||
videoctrl_starting = Signal()
|
||||
videoctrl_stopping = Signal()
|
||||
self.sync += [
|
||||
If(~videoctrl_starting & ~videoctrl_stopping, # while we're changing state, delay any new request for change
|
||||
old_videoctrl.eq(videoctrl),
|
||||
),
|
||||
# turn on
|
||||
If(videoctrl & ~old_videoctrl, # pos edge
|
||||
self.video_framebuffer.fb_dma.enable.eq(1), # enable DMA
|
||||
videoctrl_starting.eq(1),
|
||||
If(videoctrl & videoctrl_upd & ~videoctrl_starting & ~videoctrl_stopping,
|
||||
If(~old_videoctrl,
|
||||
self.video_framebuffer.fb_dma.enable.eq(1), # enable DMA
|
||||
videoctrl_starting.eq(1),
|
||||
videoctrl_upd.eq(0),
|
||||
).Else( # already on, ignore?
|
||||
videoctrl_upd.eq(0),
|
||||
)
|
||||
),
|
||||
If(videoctrl & (self.video_framebuffer.fb_dma.rsv_level != 0),
|
||||
If(videoctrl_starting & (self.video_framebuffer.fb_dma.rsv_level != 0),
|
||||
vtg_enable.eq(1), # there's some data requested, good to go
|
||||
videoctrl_starting.eq(0),
|
||||
old_videoctrl.eq(1), # we're on
|
||||
videoctrl_starting.eq(0), # starting finished
|
||||
),
|
||||
# turn off
|
||||
If(~videoctrl & old_videoctrl, # neg edge
|
||||
self.video_framebuffer.fb_dma.enable.eq(0), # disable DMA
|
||||
videoctrl_stopping.eq(1),
|
||||
If(~videoctrl & videoctrl_upd & ~videoctrl_starting & ~videoctrl_stopping, # neg edge
|
||||
If(old_videoctrl,
|
||||
self.video_framebuffer.fb_dma.enable.eq(0), # disable DMA
|
||||
videoctrl_stopping.eq(1),
|
||||
videoctrl_upd.eq(0),
|
||||
).Else( # already off, ignore?
|
||||
videoctrl_upd.eq(0),
|
||||
)
|
||||
),
|
||||
If(~videoctrl & (self.video_framebuffer.fb_dma.rsv_level == 0) & (self.video_framebuffer.underflow),
|
||||
If(videoctrl_stopping & (self.video_framebuffer.fb_dma.rsv_level == 0) & (self.video_framebuffer.underflow),
|
||||
vtg_enable.eq(0), # the DMA FIFO is purged, stop vtg
|
||||
old_videoctrl.eq(0),
|
||||
videoctrl_stopping.eq(0),
|
||||
),
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
self.comb += [ videoctrl_busy.eq(videoctrl_starting | videoctrl_stopping | in_reset | (post_reset_ctr != 0) | videoctrl_upd) ]
|
||||
|
||||
# VBL logic
|
||||
self.sync += [
|
||||
If(self.video_framebuffer.vblping == 1,
|
||||
|
||||
84
goblin_fb.py
84
goblin_fb.py
@ -45,9 +45,7 @@ class VideoFrameBufferMultiDepth(Module, AutoCSR):
|
||||
|
||||
print(f"FRAMEBUFFER: dram_port.data_width = {dram_port.data_width}, {hres}x{vres}, 0x{base:x}, in {clock_domain}, clock_faster_than_sys={clock_faster_than_sys}")
|
||||
|
||||
vga_sync = getattr(self.sync, clock_domain)
|
||||
|
||||
npixels = hres * vres # default to max
|
||||
vga_sync = getattr(self.sync, clock_domain) # usually should be named hdmi_sync, really...
|
||||
|
||||
# if 0, 32-bits mode
|
||||
# should only be changed while in reset
|
||||
@ -55,6 +53,7 @@ class VideoFrameBufferMultiDepth(Module, AutoCSR):
|
||||
# mode, as x in 2^x (so 1, 2, 4, 8 bits)
|
||||
# should only be changed while in reset
|
||||
self.indexed_mode = Signal(2, reset = 0x3)
|
||||
# for the VBL interrupt
|
||||
self.vblping = Signal(reset = 0)
|
||||
|
||||
if (hwcursor):
|
||||
@ -146,7 +145,7 @@ class VideoFrameBufferMultiDepth(Module, AutoCSR):
|
||||
self.submodules.fb_dma = LiteDRAMFBDMAReader(dram_port,
|
||||
fifo_depth = fifo_depth//(dram_port.data_width//8),
|
||||
default_base = base,
|
||||
default_length = npixels)
|
||||
default_length = (hres * vres)) # default to max
|
||||
|
||||
# If DRAM Data Width > 8-bit and Video clock is faster than sys_clk:
|
||||
# actually always use that case to simplify the design
|
||||
@ -463,6 +462,7 @@ class Goblin(Module, AutoCSR):
|
||||
bt_addr = Signal(8, reset = 0) # reg 0x14 ; lut itself in reg 0x18
|
||||
bt_cmap_state = Signal(2, reset = 0)
|
||||
m_vbl_disable = Signal(reset = 1) # reg 0x4
|
||||
bt_upd = Signal()
|
||||
|
||||
# for sub-resolution
|
||||
hres_start = Signal(hbits, reset = 0)
|
||||
@ -472,6 +472,8 @@ class Goblin(Module, AutoCSR):
|
||||
vres_upd = Signal()
|
||||
|
||||
videoctrl = Signal() # reg 0x8
|
||||
videoctrl_upd = Signal()
|
||||
videoctrl_busy = Signal()
|
||||
|
||||
vbl_signal = Signal(reset = 0) # reg 0xC
|
||||
self.comb += irq_line.eq(~vbl_signal | m_vbl_disable) # irq_line is active low
|
||||
@ -493,11 +495,13 @@ class Goblin(Module, AutoCSR):
|
||||
Case(bus.adr[0:18], {
|
||||
"default": [],
|
||||
# gobofb_mode
|
||||
0x0: [ NextValue(bt_mode, bus.dat_w[low_byte]), ],
|
||||
0x0: [ NextValue(bt_mode, bus.dat_w[low_byte]),
|
||||
NextValue(bt_upd, 1), ],
|
||||
# set vbl
|
||||
0x1: [ NextValue(m_vbl_disable, ~bus.dat_w[low_bit]), ],
|
||||
# gobofb on/off
|
||||
0x2: [ NextValue(videoctrl, bus.dat_w[low_bit]), ],
|
||||
0x2: [ NextValue(videoctrl, bus.dat_w[low_bit]),
|
||||
NextValue(videoctrl_upd, 1), ],
|
||||
# clear irq
|
||||
0x3: [ NextValue(vbl_signal, 0), ],
|
||||
# 0x4: reset in SW
|
||||
@ -556,7 +560,7 @@ class Goblin(Module, AutoCSR):
|
||||
Case(bus.adr[0:18], {
|
||||
# bt_addr
|
||||
0x0: [ NextValue(bus.dat_r[low_byte], bt_mode), ],
|
||||
0x2: [ NextValue(bus.dat_r[low_byte], videoctrl), ],
|
||||
0x2: [ NextValue(bus.dat_r[low_byte], Cat(videoctrl, videoctrl_busy)), ],
|
||||
0x3: [ NextValue(bus.dat_r[low_byte], ~irq_line), ], # irq_line is active low
|
||||
"default": [ NextValue(bus.dat_r, 0xDEADBEEF)],
|
||||
0x10: [ NextValue(bus.dat_r, hres), ], # hres (r/o) # FIXME: endianess
|
||||
@ -573,8 +577,7 @@ class Goblin(Module, AutoCSR):
|
||||
)
|
||||
# mode switch logic
|
||||
#npixels = hres * vres
|
||||
npixels = Signal(hbits + vbits +1, reset = (hres * vres))
|
||||
old_bt_mode = Signal(8) # different from bt_mode
|
||||
npixels = Signal(hbits + vbits + 1, reset = (hres * vres))
|
||||
in_reset = Signal()
|
||||
post_reset_ctr = Signal(3)
|
||||
previous_videoctrl = Signal()
|
||||
@ -590,16 +593,18 @@ class Goblin(Module, AutoCSR):
|
||||
handle_truecolor_bit = [ self.video_framebuffer.use_indexed.eq(~bt_mode[4:5]) ]
|
||||
else:
|
||||
handle_truecolor_bit = [ ]
|
||||
|
||||
|
||||
# this has grown complicated and should be a FSM...
|
||||
self.sync += [ old_bt_mode.eq(bt_mode),
|
||||
If((old_bt_mode != bt_mode) | vres_upd,
|
||||
self.sync += [ If(bt_upd | vres_upd,
|
||||
bt_upd.eq(0),
|
||||
vres_upd.eq(0),
|
||||
in_reset.eq(1),
|
||||
post_reset_ctr.eq(0),
|
||||
videoctrl.eq(0), # start a disabling cycle, or stay disabled
|
||||
previous_videoctrl.eq(videoctrl), # preserve old state for restoration later
|
||||
videoctrl_upd.eq(1), # start a disabling cycle, or stay disabled
|
||||
previous_videoctrl.eq(videoctrl | previous_videoctrl), # preserve old state for restoration later, if 'previous' is already set then we just had an update in the middle of an update...
|
||||
),
|
||||
If(in_reset & ~vtg_enable, # we asked for a reset and by now, the VTG has been turned off (or was off)
|
||||
If(~bt_upd & ~vres_upd & in_reset & ~vtg_enable, # we asked for a reset and by now, the VTG has been turned off (or was off)
|
||||
self.video_framebuffer.indexed_mode.eq(bt_mode[0:2]),
|
||||
*handle_truecolor_bit,
|
||||
in_reset.eq(0),
|
||||
@ -610,7 +615,7 @@ class Goblin(Module, AutoCSR):
|
||||
vtg._vres_start.eq(vres_start),
|
||||
vtg._vres_end.eq( vres_end),
|
||||
),
|
||||
If(post_reset_ctr == 4, # now reconfigure the DMA
|
||||
If(~bt_upd & ~vres_upd & (post_reset_ctr == 4), # now reconfigure the DMA
|
||||
If(bt_mode[4:5],
|
||||
Case(bt_mode[0:2], {
|
||||
0x0: self.video_framebuffer.fb_dma.length.eq(npixels << 2),
|
||||
@ -625,11 +630,13 @@ class Goblin(Module, AutoCSR):
|
||||
}),
|
||||
),
|
||||
),
|
||||
If(post_reset_ctr == 1, # we've waited for the mode switch so restore video mode
|
||||
videoctrl.eq(previous_videoctrl),
|
||||
If(~bt_upd & ~vres_upd & (post_reset_ctr == 1) & previous_videoctrl, # we've waited for the mode switch so restore video ctrl if set
|
||||
videoctrl.eq(1),
|
||||
videoctrl_upd.eq(1),
|
||||
previous_videoctrl.eq(0), # reset, ow that the update is finished
|
||||
),
|
||||
If(post_reset_ctr != 0,
|
||||
post_reset_ctr.eq(post_reset_ctr - 1),
|
||||
If(~bt_upd & ~vres_upd & (post_reset_ctr != 0),
|
||||
post_reset_ctr.eq(post_reset_ctr - 1),
|
||||
),
|
||||
]
|
||||
|
||||
@ -638,29 +645,40 @@ class Goblin(Module, AutoCSR):
|
||||
videoctrl_starting = Signal()
|
||||
videoctrl_stopping = Signal()
|
||||
self.sync += [
|
||||
If(~videoctrl_starting & ~videoctrl_stopping, # while we're changing state, delay any new request for change
|
||||
old_videoctrl.eq(videoctrl),
|
||||
),
|
||||
# turn on
|
||||
If(videoctrl & ~old_videoctrl, # pos edge
|
||||
self.video_framebuffer.fb_dma.enable.eq(1), # enable DMA
|
||||
videoctrl_starting.eq(1),
|
||||
If(videoctrl & videoctrl_upd & ~videoctrl_starting & ~videoctrl_stopping,
|
||||
If(~old_videoctrl,
|
||||
self.video_framebuffer.fb_dma.enable.eq(1), # enable DMA
|
||||
videoctrl_starting.eq(1),
|
||||
videoctrl_upd.eq(0),
|
||||
).Else( # already on, ignore?
|
||||
videoctrl_upd.eq(0),
|
||||
)
|
||||
),
|
||||
If(videoctrl & (self.video_framebuffer.fb_dma.rsv_level != 0),
|
||||
If(videoctrl_starting & (self.video_framebuffer.fb_dma.rsv_level != 0),
|
||||
vtg_enable.eq(1), # there's some data requested, good to go
|
||||
videoctrl_starting.eq(0),
|
||||
old_videoctrl.eq(1), # we're on
|
||||
videoctrl_starting.eq(0), # starting finished
|
||||
),
|
||||
# turn off
|
||||
If(~videoctrl & old_videoctrl, # neg edge
|
||||
self.video_framebuffer.fb_dma.enable.eq(0), # disable DMA
|
||||
videoctrl_stopping.eq(1),
|
||||
If(~videoctrl & videoctrl_upd & ~videoctrl_starting & ~videoctrl_stopping, # neg edge
|
||||
If(old_videoctrl,
|
||||
self.video_framebuffer.fb_dma.enable.eq(0), # disable DMA
|
||||
videoctrl_stopping.eq(1),
|
||||
videoctrl_upd.eq(0),
|
||||
).Else( # already off, ignore?
|
||||
videoctrl_upd.eq(0),
|
||||
)
|
||||
),
|
||||
If(~videoctrl & (self.video_framebuffer.fb_dma.rsv_level == 0) & (self.video_framebuffer.underflow),
|
||||
If(videoctrl_stopping & (self.video_framebuffer.fb_dma.rsv_level == 0) & (self.video_framebuffer.underflow),
|
||||
vtg_enable.eq(0), # the DMA FIFO is purged, stop vtg
|
||||
old_videoctrl.eq(0),
|
||||
videoctrl_stopping.eq(0),
|
||||
),
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
self.comb += [ videoctrl_busy.eq(videoctrl_starting | videoctrl_stopping | in_reset | (post_reset_ctr != 0) | videoctrl_upd) ]
|
||||
|
||||
# VBL logic
|
||||
self.sync += [
|
||||
If(self.video_framebuffer.vblping == 1,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user