@@ -57,6 +57,84 @@ static const Uint8 cpld_firmware_version[] = { 'N','o','w','!' };
5757 return; } while(0)
5858
5959
60+ // ------------------ BEGIN: VDC specific ------------------
61+
62+
63+ static Uint8 vdc_reg_sel = 0 ;
64+ #define VDC_ENABLED () ((D7XX[0x10] & 4) && !in_hypervisor)
65+ static Uint8 vdc_regs [0x40 ];
66+
67+
68+ //#define VDC_DEBUG DEBUGPRINT
69+ #define VDC_DEBUG (...)
70+
71+ static XEMU_INLINE Uint8 * vdc2vicptr ( const Uint16 vdc_address )
72+ {
73+ // The logic here is from mega65-core's VHDL source
74+ const unsigned int line = vdc_address / 80U ;
75+ const unsigned int col = vdc_address % 80U ;
76+ const unsigned int viciv_line = line / 8U ;
77+ const unsigned int result = (viciv_line * 640U ) + (line % 8U ) + (col * 8U );
78+ // Assuming hires bitmap screen always at address $40000
79+ return main_ram + result + 0x40000U ;
80+ }
81+
82+
83+ static inline Uint8 vdc_read_register ( const Uint8 reg )
84+ {
85+ VDC_DEBUG ("VDC: reading register $%02X" NL , reg );
86+ if (reg == 0x1F ) { // reading the data register which means reading a byte through VDC
87+ Uint16 vdc_mem_addr = (vdc_regs [0x12 ] << 8 ) + vdc_regs [0x13 ];
88+ VDC_DEBUG ("VDC: reading VRAM at VDC address $%04X" NL , vdc_mem_addr );
89+ const Uint8 result = * vdc2vicptr (vdc_mem_addr ++ );
90+ vdc_regs [0x12 ] = vdc_mem_addr >> 8 ;
91+ vdc_regs [0x13 ] = vdc_mem_addr & 0xFF ;
92+ return result ;
93+ }
94+ return vdc_regs [reg ];
95+ }
96+
97+
98+ static inline void vdc_write_register ( const Uint8 reg , const Uint8 data )
99+ {
100+ VDC_DEBUG ("VDC: writing register $%02X with data $%02X" NL , reg , data );
101+ vdc_regs [reg ] = data ;
102+ if (reg == 0x1F ) { // writing the data register which means writing a byte through VDC
103+ Uint16 vdc_mem_addr = (vdc_regs [0x12 ] << 8 ) + vdc_regs [0x13 ];
104+ VDC_DEBUG ("VDC: writing VRAM at VDC address $%04X with data $%02X" NL , vdc_mem_addr , data );
105+ * vdc2vicptr (vdc_mem_addr ++ ) = data ;
106+ vdc_regs [0x12 ] = vdc_mem_addr >> 8 ;
107+ vdc_regs [0x13 ] = vdc_mem_addr & 0xFF ;
108+ return ;
109+ }
110+ // FIXME: this block copy/write emulation is really bad. Though I am unsure if anyone ever uses/used it. If so, it must be fixed in the future.
111+ if (reg == 0x1E ) { // writing the count register triggers a block write or block copy operation
112+ // NOTE: block commands are totally not tested and missing many parts!!! Like the busy check
113+ // And maybe block "dimensions" as well. Also these ops are done in one step, stalling emulation. VERY BAD!
114+ Uint16 vdc_mem_addr = (vdc_regs [0x12 ] << 8 ) + vdc_regs [0x13 ]; // VDC memory update address
115+ int vdc_word_count = data ; // block copy fill/word count (the current register value: reg $1E)
116+ if (vdc_regs [0x18 ] & 0x80 ) { // ---[ BLOCK COPY OPERATION ]----------
117+ Uint16 vdc_mem_addr_src = (vdc_regs [0x20 ] << 8 ) + vdc_regs [0x21 ]; // block copy source address
118+ VDC_DEBUG ("VDC: block copy of VRAM at VDC addresses $%04X -> $%04X with count = $%X" NL , vdc_mem_addr_src , vdc_mem_addr , vdc_word_count );
119+ while (vdc_word_count -- > 0 )
120+ * vdc2vicptr (vdc_mem_addr ++ ) = * vdc2vicptr (vdc_mem_addr_src ++ );
121+ vdc_regs [0x20 ] = vdc_mem_addr_src >> 8 ;
122+ vdc_regs [0x21 ] = vdc_mem_addr_src & 0xFF ;
123+ } else { // ---[ BLOCK WRITE OPERATION ]---------
124+ VDC_DEBUG ("VDC: block write of RAM at VDC address $%04X with data = $%02X and count = $%X" NL , vdc_mem_addr , vdc_regs [0x1F ], vdc_word_count );
125+ while (vdc_word_count -- > 0 )
126+ * vdc2vicptr (vdc_mem_addr ++ ) = vdc_regs [0x2A ]; // normally attrib control, but on block write, this is the data to be written
127+ }
128+ vdc_regs [0x12 ] = vdc_mem_addr >> 8 ;
129+ vdc_regs [0x13 ] = vdc_mem_addr & 0xFF ;
130+ return ;
131+ }
132+ }
133+
134+
135+ // ------------------ END: VDC specific ------------------
136+
137+
60138static XEMU_INLINE void update_hw_multiplier ( void )
61139{
62140 register const Uint32 input_a = xemu_u8p_to_u32le (D7XX + 0x70 );
@@ -189,6 +267,8 @@ Uint8 io_read ( unsigned int addr )
189267 case 0x36 : // $D600-$D6FF ~ M65 I/O mode
190268 case 0x26 :
191269 addr &= 0xFF ;
270+ if (addr <= 1 && VDC_ENABLED ()) // $D600 or $D601 if VDC is enabled
271+ return addr ? vdc_read_register (vdc_reg_sel ) : 0x80 ; // 0x80 = always return with "READY" as VDC status if $D600 is read
192272 if (addr < 9 )
193273 RETURN_ON_IO_READ_NOT_IMPLEMENTED ("UART" , 0xFF ); // FIXME: UART is not yet supported!
194274 if (addr >= 0x80 && addr <= 0x93 ) // SDcard controller etc of MEGA65
@@ -445,6 +525,13 @@ void io_write ( unsigned int addr, Uint8 data )
445525 case 0x36 : // $D600-$D6FF ~ M65 I/O mode
446526 case 0x26 :
447527 addr &= 0xFF ;
528+ if (addr <= 1 && VDC_ENABLED ()) { // $D600 or $D601 if VDC is enabled
529+ if (addr )
530+ vdc_write_register (vdc_reg_sel , data ); // register data to be written ($D601)
531+ else
532+ vdc_reg_sel = data & 0x3F ; // register selection (on write of $D600): bit7&6 are not used though
533+ return ;
534+ }
448535 if (!in_hypervisor && addr >= 0x40 && addr <= 0x7F ) {
449536 // In user mode, writing to $D640-$D67F (in VIC4 iomode) causes to enter hypervisor mode with
450537 // the trap number given by the offset in this range
0 commit comments