(MESS) VK100: Correctly hooked up vsync interrupt to crtc instead of video subsystem; Figured out the low two bits of SYSTAT_A from tracing and hooked both up, and updated the SYSTAT_A documentation comments. Additional documentation comments for the SMC COM5016T baud rate divider. Made the DU/DVM/DIR/WOPS 8*4bit register file an actual 4-entry array, to simplify address decoding later. [Lord Nightmare]

This commit is contained in:
Jonathan Gevaryahu 2012-09-06 20:08:05 +00:00
parent 5dabd67b34
commit f9903caa1a

View File

@ -4,13 +4,14 @@
12/05/2009 Skeleton driver. 12/05/2009 Skeleton driver.
28/07/2009 added Guru-readme(TM) 28/07/2009 added Guru-readme(TM)
08/01/2012 Fleshed out driver.
Todo: Todo:
* fix vector generator hardware enough to pass the startup self test * fix vector generator hardware enough to pass the startup self test
the tests are described on page 6-5 thru 6-8 of the tech reference the tests are described on page 6-5 thru 6-8 of the tech reference
* hook up the direction and sync prom to the sync counter * hook up the direction and sync prom to the sync counter
* figure out the correct meaning of systat b register - needed for communications selftest * figure out the correct meaning of systat b register - needed for communications selftest
* hook up smc_5016t baud generator to i8251 rx and tx clocks - begun * hook up smc com5016t baud generator to i8251 rx and tx clocks - begun
Tony DiCenzo, now the director of standards and architecture at Oracle, was on the team that developed the VK100 Tony DiCenzo, now the director of standards and architecture at Oracle, was on the team that developed the VK100
see http://startup.nmnaturalhistory.org/visitorstories/view.php?ii=79 see http://startup.nmnaturalhistory.org/visitorstories/view.php?ii=79
@ -154,6 +155,7 @@ public:
UINT8* m_trans; UINT8* m_trans;
UINT8* m_pattern; UINT8* m_pattern;
UINT8* m_dir; UINT8* m_dir;
UINT8 m_vsync; // vsync pin of crtc
UINT16 m_vgX; UINT16 m_vgX;
UINT16 m_vgY; UINT16 m_vgY;
UINT16 m_vgERR; // error register can cause carries which need to be caught UINT16 m_vgERR; // error register can cause carries which need to be caught
@ -163,10 +165,11 @@ public:
UINT8 m_vgPMUL; // reload value for PMUL_Count UINT8 m_vgPMUL; // reload value for PMUL_Count
UINT8 m_vgPMUL_Count; UINT8 m_vgPMUL_Count;
UINT8 m_vgDownCount; // down counter = number of pixels, loaded from vgDU on execute UINT8 m_vgDownCount; // down counter = number of pixels, loaded from vgDU on execute
UINT8 m_vgDU; #define VG_DU m_regfile[0]
UINT8 m_vgDVM; #define VG_DVM m_regfile[1]
UINT8 m_vgDIR; #define VG_DIR m_regfile[2]
UINT8 m_vgWOPS; #define VG_WOPS m_regfile[3]
UINT8 m_regfile[4];
UINT8 m_VG_MODE; // 2 bits, latched on EXEC UINT8 m_VG_MODE; // 2 bits, latched on EXEC
UINT8 m_vgGO; // activated on next SYNC pulse after EXEC UINT8 m_vgGO; // activated on next SYNC pulse after EXEC
UINT8 m_ACTS; UINT8 m_ACTS;
@ -243,7 +246,7 @@ static void vram_write(running_machine &machine, UINT8 data)
block |= data<<(nybbleNum*4); // write the new part block |= data<<(nybbleNum*4); // write the new part
// NOTE: this next part may have to be made conditional on VG_MODE // NOTE: this next part may have to be made conditional on VG_MODE
// check if the attribute nybble is supposed to be modified, and if so do so // check if the attribute nybble is supposed to be modified, and if so do so
if (state->m_vgWOPS&0x08) block = (block&0x0FFF)|(((UINT16)state->m_vgWOPS&0xF0)<<8); if (state->VG_WOPS&0x08) block = (block&0x0FFF)|(((UINT16)state->VG_WOPS&0xF0)<<8);
state->m_vram[(EA<<1)+1] = block&0xFF; // write block back to vram state->m_vram[(EA<<1)+1] = block&0xFF; // write block back to vram
state->m_vram[(EA<<1)] = (block&0xFF00)>>8; // '' state->m_vram[(EA<<1)] = (block&0xFF00)>>8; // ''
} }
@ -253,7 +256,7 @@ static TIMER_CALLBACK( execute_vg )
vk100_state *state = machine.driver_data<vk100_state>(); vk100_state *state = machine.driver_data<vk100_state>();
UINT8 thisNyb = vram_read(machine); // read in the nybble UINT8 thisNyb = vram_read(machine); // read in the nybble
// pattern rom addressing is a complex mess. see the pattern rom def later in this file. // pattern rom addressing is a complex mess. see the pattern rom def later in this file.
UINT8 newNyb = state->m_pattern[((state->m_vgPAT&state->m_vgPAT_Mask)?0x200:0)|((state->m_vgWOPS&7)<<6)|((state->m_vgX&3)<<4)|thisNyb]; // calculate new nybble based on pattern rom UINT8 newNyb = state->m_pattern[((state->m_vgPAT&state->m_vgPAT_Mask)?0x200:0)|((state->VG_WOPS&7)<<6)|((state->m_vgX&3)<<4)|thisNyb]; // calculate new nybble based on pattern rom
// finally write the block back to ram depending on the VG_MODE (sort of a hack until we get the vector and synd and dir roms all hooked up) // finally write the block back to ram depending on the VG_MODE (sort of a hack until we get the vector and synd and dir roms all hooked up)
switch (state->m_VG_MODE) switch (state->m_VG_MODE)
{ {
@ -305,7 +308,7 @@ static TIMER_CALLBACK( execute_vg )
*/ */
//UINT8 direction_rom = state->m_dir[]; //UINT8 direction_rom = state->m_dir[];
// HACK: we need the proper direction rom dump for this! // HACK: we need the proper direction rom dump for this!
switch(state->m_vgDIR&0x7) switch(state->VG_DIR&0x7)
{ {
case 0: case 0:
state->m_vgX++; state->m_vgX++;
@ -423,27 +426,27 @@ WRITE8_MEMBER(vk100_state::vgPMUL)
/* port 0x60: "DU" load vg vector major register */ /* port 0x60: "DU" load vg vector major register */
WRITE8_MEMBER(vk100_state::vgDU) WRITE8_MEMBER(vk100_state::vgDU)
{ {
m_vgDU = data; VG_DU = data;
#ifdef VG60_VERBOSE #ifdef VG60_VERBOSE
logerror("VG: 0x60: DU Reg loaded with %02X\n", m_vgDU); logerror("VG: 0x60: DU Reg loaded with %02X\n", VG_DU);
#endif #endif
} }
/* port 0x61: "DVM" load vg vector minor register */ /* port 0x61: "DVM" load vg vector minor register */
WRITE8_MEMBER(vk100_state::vgDVM) WRITE8_MEMBER(vk100_state::vgDVM)
{ {
m_vgDVM = data; VG_DVM = data;
#ifdef VG60_VERBOSE #ifdef VG60_VERBOSE
logerror("VG: 0x61: DVM Reg loaded with %02X\n", m_vgDVM); logerror("VG: 0x61: DVM Reg loaded with %02X\n", VG_DVM);
#endif #endif
} }
/* port 0x62: "DIR" load vg Direction register */ /* port 0x62: "DIR" load vg Direction register */
WRITE8_MEMBER(vk100_state::vgDIR) WRITE8_MEMBER(vk100_state::vgDIR)
{ {
m_vgDIR = data; VG_DIR = data;
#ifdef VG60_VERBOSE #ifdef VG60_VERBOSE
logerror("VG: 0x62: DIR Reg loaded with %02X\n", m_vgDIR); logerror("VG: 0x62: DIR Reg loaded with %02X\n", VG_DIR);
#endif #endif
} }
@ -455,10 +458,10 @@ WRITE8_MEMBER(vk100_state::vgDIR)
*/ */
WRITE8_MEMBER(vk100_state::vgWOPS) WRITE8_MEMBER(vk100_state::vgWOPS)
{ {
m_vgWOPS = data; VG_WOPS = data;
#ifdef VG60_VERBOSE #ifdef VG60_VERBOSE
static const char *const functions[] = { "Overlay", "Replace", "Complement", "Erase" }; static const char *const functions[] = { "Overlay", "Replace", "Complement", "Erase" };
logerror("VG: 0x64: WOPS Reg loaded with %02X: KGRB %d%d%d%d, AttrChange %d, Function %s, Negate %d\n", data, (m_vgWOPS>>7)&1, (m_vgWOPS>>6)&1, (m_vgWOPS>>5)&1, (m_vgWOPS>>4)&1, (m_vgWOPS>>3)&1, functions[(m_vgWOPS>>1)&3], m_vgWOPS&1); logerror("VG: 0x64: WOPS Reg loaded with %02X: KGRB %d%d%d%d, AttrChange %d, Function %s, Negate %d\n", data, (VG_WOPS>>7)&1, (VG_WOPS>>6)&1, (VG_WOPS>>5)&1, (VG_WOPS>>4)&1, (VG_WOPS>>3)&1, functions[(VG_WOPS>>1)&3], VG_WOPS&1);
#endif #endif
} }
@ -475,7 +478,7 @@ WRITE8_MEMBER(vk100_state::vgEX)
#endif #endif
m_vgPMUL_Count = m_vgPMUL; // load PMUL_Count m_vgPMUL_Count = m_vgPMUL; // load PMUL_Count
m_vgPAT_Mask = 0x80; m_vgPAT_Mask = 0x80;
m_vgDownCount = m_vgDU; // set down counter to length of major vector m_vgDownCount = VG_DU; // set down counter to length of major vector
m_VG_MODE = offset&3; m_VG_MODE = offset&3;
m_vgGO = 1; m_vgGO = 1;
machine().scheduler().timer_set(attotime::zero, FUNC(execute_vg)); machine().scheduler().timer_set(attotime::zero, FUNC(execute_vg));
@ -501,9 +504,32 @@ WRITE8_MEMBER(vk100_state::KBDW)
#endif #endif
} }
/* port 0x6C: "BAUD" controls the smc5016t dual baud generator which /* port 0x6C: "BAUD" controls the smc com5016t dual baud generator which
* controls the divisors for the rx and tx clocks on the 8251 from the * controls the divisors for the rx and tx clocks on the 8251 from the
* 5.0688Mhz cpu xtal : 5.0688Mhz cpu xtal.
It has 5v,12v on pins 2 and 9, pin 10 is NC.
* A later part that replaced this on the market is SMC COM8116(T)/8136(T), which
was a 5v-only part (pin 9 and 10 are NC, 10 is a clock out on the 8136.
* Note that even on the SMC COM5016T version, SMC would allow the user
to mask their own dividers on custom ordered chips if desired.
* The COM8116(T)/8136(T) came it at least 4 mask rom types meant for different
input clocks:
-000 or no mark for 5.0688Mhz (which exactly matches the table below)
-003 is for 6.01835MHz
-005 is for 4.915200Mhz
-006 is for 5.0688Mhz but omits the 2000 baud entry, instead has 200,
and output frequencies are 2x as fast (meant for a 32X clock uart)
-013 is for 2.76480MHz
-013A is for 5.52960MHz
(several other unknown refclock masks appear on partscalper sites)
GI also made a clone of the 8116 5v chip called the AY-5-8116(T)/8136(T)
which had at least two masks: -000/no mark and -005, matching speeds above
WD made the WD1943 which is similarly 5v compatible, with -00, -05, -06 masks
The COM8046(T) has 5 bits for selection instead of 4, but still expects
a 5.0688MHz reference clock, and the second half of the table matches the
values below; the first half of the table is the values below /2, rounded
down (for uarts which need a clock rate of 32x baud instead of 16x).
WD's BR1941 is also functionally compatible but uses 5v,12v,-5v on pins 2,9,10
* The baud divisor lookup table has 16 entries, but only entries 2,5,6,7,A,C,E,F are documented/used in the vk100 tech manual * The baud divisor lookup table has 16 entries, but only entries 2,5,6,7,A,C,E,F are documented/used in the vk100 tech manual
* The others are based on page 13 of http://www.hartetechnologies.com/manuals/Tarbell/Tarbell%20Z80%20CPU%20Board%20Model%203033.pdf * The others are based on page 13 of http://www.hartetechnologies.com/manuals/Tarbell/Tarbell%20Z80%20CPU%20Board%20Model%203033.pdf
* D C B A Divisor Expected Baud * D C B A Divisor Expected Baud
@ -537,19 +563,18 @@ WRITE8_MEMBER(vk100_state::BAUD)
} }
/* port 0x40-0x47: "SYSTAT A"; various status bits, poorly documented in the tech manual /* port 0x40-0x47: "SYSTAT A"; various status bits, poorly documented in the tech manual
* /GO BIT3 BIT2 BIT1 BIT0 Dip ? ? * /GO BIT3 BIT2 BIT1 BIT0 Dip RST7.5 GND
* Switch * Switch VSYNC
* d7 d6 d5 d4 d3 d2 d1 d0 * d7 d6 d5 d4 d3 d2 d1 d0
* bit3, 2, 1, 0 are the last 4 bits read by the vector generator from VRAM bit3, 2, 1, 0 are the 4 bits output from the VRAM 12->4 multiplexer
* note: if the vector generator is not running, reading SYSTAT A will which are also inputs to the pattern rom; they are constantly updated
* supposedly FORCE the vector generator to read one nybble from the by the sync rom and related circuitry.
* current x,y! (how does this work schematicwise??? it may just read This is the only way the vram can be read by the cpu.
* the last nybble read by the constantly running sync counter, in d7 is from the /Q output of the GO latch
* which case the hack here sort of works as well) d6,5,4,3 are from the 74ls298 at ic4 (right edge of pcb)
* this appears to be the only way the vram can be READ by the cpu d2 is where the dipswitch values are read from, based on the offset
d2 is where the dipswitch values are read from, based on the offset d1 is connected to 8085 rst7.5 (pin 7) and crtc pin 40 (VSYNC) [verified via tracing]
d1 is unknown d0 is tied to GND [verified via tracing]
d0 is unknown
31D reads and checks d7 in a loop 31D reads and checks d7 in a loop
205 reads, xors with 0x55 (from reg D), ANDS result with 0x78 and branches if it is not zero (checking for bit pattern 1010?) 205 reads, xors with 0x55 (from reg D), ANDS result with 0x78 and branches if it is not zero (checking for bit pattern 1010?)
@ -562,7 +587,7 @@ READ8_MEMBER(vk100_state::SYSTAT_A)
#ifdef SYSTAT_A_VERBOSE #ifdef SYSTAT_A_VERBOSE
if (cpu_get_pc(m_maincpu) != 0x31D) logerror("0x%04X: SYSTAT_A Read!\n", cpu_get_pc(m_maincpu)); if (cpu_get_pc(m_maincpu) != 0x31D) logerror("0x%04X: SYSTAT_A Read!\n", cpu_get_pc(m_maincpu));
#endif #endif
return ((m_vgGO?0:1)<<7)|(vram_read(machine())<<3)|(((ioport("SWITCHES")->read()>>dipswitchLUT[offset])&1)?0x4:0)|0x3; return ((m_vgGO?0:1)<<7)|(vram_read(machine())<<3)|(((ioport("SWITCHES")->read()>>dipswitchLUT[offset])&1)?0x4:0)|(m_vsync?0x2:0);
} }
/* port 0x48: "SYSTAT B"; NOT documented in the tech manual at all. /* port 0x48: "SYSTAT B"; NOT documented in the tech manual at all.
@ -853,6 +878,7 @@ static MACHINE_RESET( vk100 )
output_set_value("hardcopy_led", 1); output_set_value("hardcopy_led", 1);
output_set_value("l1_led", 1); output_set_value("l1_led", 1);
output_set_value("l2_led", 1); output_set_value("l2_led", 1);
state->m_vsync = 0;
state->m_vgX = 0; state->m_vgX = 0;
state->m_vgY = 0; state->m_vgY = 0;
state->m_vgERR = 0; state->m_vgERR = 0;
@ -862,10 +888,10 @@ static MACHINE_RESET( vk100 )
state->m_vgPMUL = 0; state->m_vgPMUL = 0;
state->m_vgPMUL_Count = 0; state->m_vgPMUL_Count = 0;
state->m_vgDownCount = 0; state->m_vgDownCount = 0;
state->m_vgDU = 0; state->VG_DU = 0;
state->m_vgDVM = 0; state->VG_DVM = 0;
state->m_vgDIR = 0; state->VG_DIR = 0;
state->m_vgWOPS = 0; state->VG_WOPS = 0;
state->m_VG_MODE = 0; state->m_VG_MODE = 0;
state->m_vgGO = 0; state->m_vgGO = 0;
state->m_ACTS = 1; state->m_ACTS = 1;
@ -873,11 +899,11 @@ static MACHINE_RESET( vk100 )
state->m_TXDivisor = 6336; state->m_TXDivisor = 6336;
} }
static INTERRUPT_GEN( vk100_vertical_interrupt ) static WRITE_LINE_DEVICE_HANDLER(crtc_vsync)
{ {
vk100_state *state = device->machine().driver_data<vk100_state>(); vk100_state *m_state = device->machine().driver_data<vk100_state>();
device_set_input_line(state->m_maincpu, I8085_RST75_LINE, ASSERT_LINE); device_set_input_line(m_state->m_maincpu, I8085_RST75_LINE, state? ASSERT_LINE : CLEAR_LINE);
device_set_input_line(state->m_maincpu, I8085_RST75_LINE, CLEAR_LINE); m_state->m_vsync = state;
} }
static WRITE_LINE_DEVICE_HANDLER(i8251_rxrdy_int) static WRITE_LINE_DEVICE_HANDLER(i8251_rxrdy_int)
@ -958,7 +984,7 @@ static const mc6845_interface mc6845_intf =
DEVCB_NULL, DEVCB_NULL,
DEVCB_NULL, DEVCB_NULL,
DEVCB_NULL, DEVCB_NULL,
DEVCB_NULL, DEVCB_LINE(crtc_vsync),
NULL NULL
}; };
@ -982,7 +1008,6 @@ static MACHINE_CONFIG_START( vk100, vk100_state )
MCFG_CPU_ADD("maincpu", I8085A, XTAL_5_0688MHz) MCFG_CPU_ADD("maincpu", I8085A, XTAL_5_0688MHz)
MCFG_CPU_PROGRAM_MAP(vk100_mem) MCFG_CPU_PROGRAM_MAP(vk100_mem)
MCFG_CPU_IO_MAP(vk100_io) MCFG_CPU_IO_MAP(vk100_io)
MCFG_CPU_VBLANK_INT("screen", vk100_vertical_interrupt)
MCFG_MACHINE_RESET(vk100) MCFG_MACHINE_RESET(vk100)