Commit work-in-progress.

Much better BBU pinout chart, lots of notes learned from Guide to the
Macintosh family hardware.
This commit is contained in:
Andrew Makousky 2020-11-18 10:21:05 -06:00
parent 12eb917c24
commit 62d2e920e7
3 changed files with 513 additions and 431 deletions

View File

@ -48,7 +48,7 @@ a huge number of pins, its purpose can be summarized as follows.
* 0x000000 - 0x3fffff: RAM/ROM (switches based on overlay)
* 0x400000 - 0x4fffff: ROM
* 0x580000 - 0x5fffff: 5380 NCR/Symbios SCSI peripherals chip
* 0x600000 - 0x6fffff: RAM, boot-time overlay only
* 0x600000 - 0x7fffff: RAM, boot-time overlay only
* 0x900000 - 0x9fffff: Zilog 8530 SCC (Serial Control Chip) Read
* 0xb00000 - 0xbfffff: Zilog 8530 SCC (Serial Control Chip) Write
* 0xd00000 - 0xdfffff: IWM (Integrated Woz Machine; floppy)
@ -298,6 +298,12 @@ Peripheral device signals, input or output?
----------
Please note: Information on how the older compact Macintosh PAL gates
worked, which provide nearly identical functionality of the BBU.
20201116/http://www.retro.co.za/ccc/mac/ReverseEngineering/PALs.html
20201116/https://web.archive.org/web/20170726142931/http://www.mactech.com/articles/mactech/Vol.01/01.11/PAL/index.html
There is still more to learn/investigate relating to unspecified
signals.

View File

@ -118,102 +118,13 @@
TODO Abbreviations legend, here since they are not noted elsewhere:
RA = RAM Address
RDQ = RAM Data Value
PMCYC = Processor Memory Cycle
PINOUT:
Undocumented signal but assumed to exist:
RA0 79
RA1 78
RA2 76
RA3 73
RA4 71
RA5 70
RA6 68
RA8 67
RA7 66
RA9 65
*CAS1L 16
*CAS0L 15
RAM R/*W 14
*RAS 20
*CAS1H 19
*CAS0H 18
RDQ0 69
RDQ1 72
RDQ2 74
RDQ3 75
RDQ4 77
RDQ5 80
RDQ6 83
RDQ7 2
RDQ8 3
RDQ9 4
RDQ10 5
RDQ11 6
RDQ12 7
RDQ13 8
RDQ14 9
RDQ15 10
*EN245 12
*DTACK 38
R/*W 47
*IPL1 30
*LDS 33
*VPA 36
*C8M 37
VCC 22
VCC 64
VCC 42
VCC 84
MBRAM 17
GND 1
GND 21
GND 43
GND 63
ROW2 13
*EXTDTK 11
A23 23
A22 24
A21 25
A20 26
A19 27
A17 28
A9 29
*PMCYC 81
C2M 82
*RES 59
C16MRSF2 44
C3.7M 40
*ROMEN 39
*SCCRD 46
PWM 49
SCSIDRQ 55
*IWM 48
*SCCEN 45
*SCSI 57
*DACK 56
SNDRES 50
VIA.CS1 58
VIDPG2 53
*EAREN 52
*AS 41
*BERR 34
SND 51
*VSYNC 61
*IOW 54
*HSYNC 60
*VIAIRQ 32
VIDOUT 62
*IPL0 31
*UDS 35
Undocumented but assumed to exist:
64KRAM ???
Note that *IOW controls both *SCSI.IOW and *SCC.WR.
64KRAM: Here we assign it to pin 21 for our own experimentation, a
pin that is specified as just tied to ground.
*/
module bbu_master_ctrl
// Essential sequential logic RESET and clock signals
@ -250,21 +161,17 @@ module bbu_master_ctrl
n_extdtk, n_earen,
);
// TODO FIXME: Signals missing-in-action: OVERLAY, SNDPG2. It's
// possible that the Macintosh SE uses a magic address access to
// obviate the need for consuming a VIA pin for OVERLAY, but I have
// no idea what this address would be. Has support for the second
// sound page been dropped in the Macintosh SE? Yes, indeed it has
// been. Nevertheless... for the sake of possibly making
// quasi-hardware replicas of earlier Macintosh computers easier,
// we will preserve an implementation here anyways. As for the
// OVERLAY signal, we'll have to use Mini vMac's guess on how to
// implement it. At boot, the ROM exclusively accesses the ROM
// overlay addresses and the remapped RAM address when setting up.
// When it is done, it jumps into the standard ROM address access.
// As soon as the BBU detects this memory access (any address in
// the standard ROM address space), it switches the overlay, and it
// cannot be switched back except by a RESET signal.
// The Macintosh SE deprecated SNDPG2. Nevertheless... for the
// sake of possibly making quasi-hardware replicas of earlier
// Macintosh computers easier, we will preserve an implementation
// here anyways. As for the OVERLAY signal, we'll have to use Mini
// vMac's guess on how to implement it. At boot, the ROM
// exclusively accesses the ROM overlay addresses and the remapped
// RAM address when setting up. When it is done, it jumps into the
// standard ROM address access. As soon as the BBU detects this
// memory access (any address in the standard ROM address space),
// it switches the overlay, and it cannot be switched back except
// by a RESET signal.
// So yes... it turns out the BBU must actually do address bus
// snooping.
@ -272,9 +179,9 @@ module bbu_master_ctrl
// Essential sequential logic RESET and clock signals
input wire n_res; // *RESET signal
input wire c16m; // 15.667200 MHz master clock input
output reg c8m; // 7.8336 MHz clock output
output reg c3_7m; // 3.672 MHz clock output
output reg c2m; // 1.9584 MHz clock output
output wire c8m; // 7.8336 MHz clock output
output wire c3_7m; // 3.672 MHz clock output
output wire c2m; // 1.9584 MHz clock output
// RAM configuration pins
input wire row2; // 1/2 rows of RAM SIMMs jumper
@ -284,40 +191,42 @@ module bbu_master_ctrl
// MC68000 signals
input wire a9, a17, a19, a20, a21, a22, a23;
input wire r_n_w, n_as, n_uds, n_lds;
output reg n_dtack, n_ipl0, n_ipl1;
inout wire n_dtack;
output wire n_ipl0;
input wire n_ipl1;
output wire n_berr;
input wire n_vpa;
// DRAM signals
inout wire ra0, ra1, ra2, ra3, ra4, ra5, ra6, ra8;
output reg ra7, ra9;
output reg n_cas1l, n_cas0l, ram_r_n_w, n_ras, n_cas1h, n_cas0h;
output wire ra7, ra9;
output wire n_cas1l, n_cas0l, ram_r_n_w, n_ras, n_cas1h, n_cas0h;
inout wire rdq0, rdq1, rdq2, rdq3, rdq4, rdq5, rdq6, rdq7,
rdq8, rdq9, rdq10, rdq11, rdq12, rdq13, rdq14, rdq15;
output reg n_en245, n_pmcyc;
output wire n_en245, n_pmcyc;
// ROM and memory overlay signals
output reg n_romen;
output wire n_romen;
// VIA signals
output reg via_cs1;
output wire via_cs1;
input wire n_viairq;
// Video signals
input wire vidpg2; // VIDPG2 signal
output reg vidout; // VIDOUT signal
output reg n_hsync; // *HSYNC signal
output reg n_vsync; // *VSYNC signal
output wire vidout; // VIDOUT signal
output wire n_hsync; // *HSYNC signal
output wire n_vsync; // *VSYNC signal
// Sound and disk speed signals
input wire sndres;
output reg snd, pwm;
output wire snd, pwm;
// IWM signals
output reg n_iwm;
output wire n_iwm;
// SCC signals
output reg n_sccen, n_sccrd, n_iow;
output wire n_sccen, n_sccrd, n_iow;
// SCSI signals
output reg n_scsi;
output wire n_scsi;
input wire scsidrq;
output reg n_dack;
// PDS signals
@ -326,8 +235,6 @@ module bbu_master_ctrl
// Note tristate inout ... 'bz for high impedance. 8'bz for wide.
// Boot-time memory overlay switch, 1 = enable, 0 = disable.
reg boot_overlay;
// In order to implement the memory overlay switch, we must snoop
// the address bus. These are the registers we use to store the
// address multiplexor outputs.
@ -336,115 +243,51 @@ module bbu_master_ctrl
// Installed RAM size.
wire [23:0] ramsz;
// C16M pixel clock (0.064 us per pixel).
// 512 horizontal draw pixels, 192 horizontal blanking pixels.
// 342 scan lines, 28 scan lines vertical blanking.
// 60.15 Hz vertical scan rate.
// (512 + 192) * (342 + 28) = 260480 pixel clock ticks per frame.
// Total screen buffer size = 10944 words. High-order bit of each
// 16-bit word is the leftmost pixel, low-order bit is the
// rightmost pixel. Words in ascending order move from left to
// right in the scan line, first scan line is topmost and then
// moves downward.
// *HSYNC and *VSYNC counters are negative during blanking.
reg [15:0] vidout_sreg; // VIDOUT shift register
reg [4:0] vidout_cntr; // VIDOUT remaining counter
reg [9:0] vid_hsync_cntr; // *HSYNC counter
reg [8:0] vid_vsync_cntr; // *VSYNC counter
wire [23:0] vid_main_addr; // Address of main video buffer
wire [23:0] vid_alt_addr; // Address of alternate video buffer
// Sound and disk speed buffers are scanned 370 words per video
// frame, and the size of both buffers together is 370 words. Or,
// 260480 pixel clock ticks / 370 = 704 pixel clock ticks per word.
// In a single scan line, (512 + 192) / 704 = 704 / 704 = exactly 1
// word is read. The sound byte is the most significant byte, the
// disk speed byte is the least significant byte. Both the sound
// sample and disk speed represent a PCM amplitude value, this is
// used to generate a PDM waveform that can be processed by a
// low-pass filter to generate the analog signal.
// Well, at least in concept... Inside Macintosh claims that only a
// single pulse is generated, so this is not quite your typical PDM
// audio circuit. Nevertheless, the sample rate is 22.2555 kHz, so
// it's not too bad overall for generating lo-fi audio. But, good
// point to ponder, this is an area of improvement where a
// different algorithm can generate better audio quality.
reg [15:0] snddsk_reg; // PCM sound sample and disk speed register
wire [23:0] snddsk_main_addr; // Address of main sound/disk buffer
wire [23:0] snddsk_alt_addr; // Address of alternate sound/disk buffer
// We must be careful that the sound circuitry does not attempt to
// access RAM at the same time as the video circuitry. Because the
// phases are coherent, we can simply align the sound and disk
// speed RAM fetch to be at a constant offset relative to the video
// RAM fetch.
// PLEASE NOTE: We must carefully time our RAM accesses since they
// have delays and we don't want the screen bits shift register
// buffer to run empty before we have the next word available from
// RAM. Our ideal is that the next word is available from RAM just
// as we are shifting out the last pixel, so that we can use a
// non-blocking assign and the new first pixel will be available
// right at the start of the next pixel clock cycle. Otherwise,
// less ideal but easier to program would be to use two 16-bit
// buffers as a FIFO.
// SCC access notes: Even byte accesses are a read, odd byte
// accesses are a write. Namely: `*LDS` == 0 == write, `*UDS` == 0
// == read. Remember, it's big endian. What about the separate
// address regions? Well, I say just ignore those, it's there for
// a convenient convention, but it's not the officially documented
// hardware protocol.
// VIA support: Simply handle chip select, and issue an MC68000
// interrupt priority zero if we receive an interrupt signal from
// the VIA.
// SCSI support: Handle chip select, and handle DMA.
// NOTE: For all peripherals, we must set `*DTACK` from the BBU
// upon successful access condition and time durations because it
// is not set by the device itself.
// Important! How to handle SCSI DMA... according to Guide to the
// Macintosh family hardware, page 126, this is "pseudo-DMA" mode.
// The BBU does not assert `*DTACK` until `SCSIDRQ` is received to
// indicate the DMA transfer is complete. And again, noting from
// page 126, . Likewise, `*DTACK` is asserted for all addresses in
// range, even if nothing is mapped. No stringent bus error
// control here, that's a hobbyist extension. And again, inded
// `*DTACK` is tri-stated according to the manual when `*EXTDTK`
// (`*EXT.DTACK`) is asserted.
// Now, here's the golden rule: "If any access has not terminated
// within 265 ms, the BBU asserts the bus error signal /BERR."
// There you go, that's how it is driven. So, another thing,
// yes... there must be at least a nominal delay to assert `*DTACK`
// to allow PDS cards to intervene by asserting `*EXTDTK` first.
// TODO MOVE DOCUMENTATION: PLEASE NOTE, PDS cards can also access
// DRAM, not just the CPU. This is mainly a matter of bus
// arbitration, then as far s the BBU is concerned, PDS access to
// DRAM should appear identical to CPU access to DRAM. Guide to
// the Macintosh Family hardware, page 84.
//////////////////////////////////////////////////
// Pure combinatorial logic is defined first.
// TODO: Assert `*IPL0` if we receive an interrupt signal from the
// VIA or SCSI. However, do not assert `*IPL0` if the SCC asserts
// `*IPL1`. Guide to the Macintosh family hardware, page 113.
// SCSI interrupts are signaled only on IRQ from the SCSI
// controller. DRQ is not attached to MC68000 interrupt lines
// whatsoever, it must be polled by software and is only used by
// the BBU as specified in the other section. TODO CONFIRM: The
// SCSI IRQ line attaches directly to `*IPL0`?
assign n_ipl0 = ~n_ipl1 | n_viairq;
//////////////////////////////////////////////////
// Sub-modules are instantiated here.
// The remainder of definitions are for sequential logic.
always @(negedge n_res) begin
// Initialize all output registers on RESET.
n_dtack <= 1; n_ipl0 <= 1; n_ipl1 <= 1;
ra7 <= 0; ra9 <= 0;
n_cas1l <= 1; n_cas0l <= 1;
ram_r_n_w <= 0; n_ras <= 1;
n_cas1h <= 1; n_cas0h <= 1;
n_en245 <= 1;
n_pmcyc <= 1;
vidout <= 0; n_hsync <= 1; n_vsync <= 1;
snd <= 0; pwm <= 0;
n_iwm <= 1; n_sccen <= 1; n_sccrd <= 1; n_iow <= 1;
n_scsi <= 1; n_dack <= 1;
n_dack <= 1;
n_earen <= 1;
// Initialize all internal registers on RESET.
boot_overlay <= 1;
vidout_sreg <= 0;
vidout_cntr <= 0;
vid_hsync_cntr <= 0;
vid_vsync_cntr <= 0;
snddsk_reg <= 0;
end
always @(posedge c16m) begin
@ -541,88 +384,113 @@ Write down all my questions thus far about the BBU:
// Clock divider module. Generate the frequency-divided clock
// signals.
module clock_div (n_res, c16m, c8m, c3_7m, c2m, n_pmcyc);
module clock_div (n_res, c16m, c8m, c3_7m, c2m_e, n_pmcyc, pmcyc_pt);
input wire n_res;
input wire c16m;
output reg c8m;
output reg c3_7m;
// c2m is now controlled by the DRAM controller state machine.
input wire c2m;
output reg n_pmcyc;
// This is just an I/O argument placeholder. We still generate the
// signal internally, though.
input wire c2m_e;
output wire n_pmcyc;
// *PMCYC "pre-trigger": will the *PMCYC state be negated on the
// next cycle?
output wire pmcyc_pt;
// TODO FIXME: `*PMCYC` should not be a strict 1MHz clock, because
// during vertical blanking, all cycles (except for horizontal
// blanking sound cycles) are fair game for CPU use. PLEASE NOTE:
// According to Guide to the Macintosh family hardware, page 194,
// the process of scanning the screen buffer also refreshes the
// DRAM. But I don't quite understand how this works, wouldn't you
// need to access more addresses to refresh all the DRAM? But,
// PLEASE NOTE. Macintosh SE/30 takes one access cycle every
// 15.6us for DRAM refresh.
///////////////////////////////////////////////////////////
// 15.6672 / 3.6720 = 9792/2295 = (51*2^6*3)/(51*3^2*5)
// = (2^6)/(3*5) = 64/15
/* Inside Macintosh claims that the serial clock is 3.672 MHz.
Clock multiplication (via PLL) and division can be used to
generate this from the 15.6672 MHz clock as follows:
// So, here's how we implement the frequency divider to generate
// the 3.672 MHz clock. Initialize to 64 - 15 = 49, and keep
// subtracting 15 until we reach zero or less. Then, add back 49,
// and toggle the C3.7M output.
15.6672 / 3.6720 = 9792/2295 = (51*2^6*3)/(51*3^2*5)
= (2^6)/(3*5) = 64/15
// TODO FIXME: The complex frequency divider will not work
// correctly: Since the base frequency is not high enough, there
// will be terrible aliasing artifacts. Divide by 4 is a bit too
// fast, divide by 5 is a bit too slow, but that's the best we can
// do without PLL clock frequency multiplication.
//
// PLL clock frequency synthesis inside the BBU is conceivable to
// believe, however, considering that the the GLUE chip in the
// Macintosh SE/30 doubles the 16 MHz crystal input to 32 MHz.
// Easiest method, we want the least common multiple between these
// two frequencies. So, back to where we started.
//
// 15.6672 / 3.6720 = 16/16 * 9792/2295 = (51*2^10*3)/(51*2^4*3^2*5)
// LCM: 51*2^10*3^2*5 = 2350080 -> 235.0080 MHz
// 235.0080 / 15.6672 = 15
// 235.0080 / 3.6720 = 64
//
// So, this is how we synthesize the perfect 3.6720 MHz clock
// signal. Multiply the source frequency of 15.6672 MHz by 15 via
// a PLL to get an intermediate clock frequency of 235.0080 MHz,
// then divide by 64 to get the target 3.6720 MHz clock signal.
// Yes, we could really just use divide-by-four (3.9168 MHz) if
// going a tad bit faster wasn't an issue.
//
// How about this, 16 / (64 * 16/15) ~= 16/68. Multiply by 16,
// divide by 68. PLL = 250.6752 MHz, result = 3.6864 MHz. I guess
// that's a lot better. Alternatively, PLL = 250 MHz, result =
// 3.6765 MHz. Even better.
This would entail a PLL clock running at 235.008 MHz inside the
BBU, which was impractical for the technology available during
the 1980s. But if that were configured, a simple divide-by-64
frequency counter would yield a perfect clock signal.
// TODO: Optimize this to minimize the number of register bits
// required, while still preserving ideal frequency division and
// synchronization behavior.
As it turns out, the actual Macintosh did not use a true,
constant-period 15.6672 MHz clock, but rather a 3.686 MHz clock
with a phase/period error of up to 1 clock cycle of the 15.6672
MHz clock. Sequential logic is used to effect a principal
divide-by-four clock cycle format, and at every fourth 3.686 MHz
clock cycle, one extra 15.6672 MHz clock cycle is slipped in on
the last low-edge half-period of the 3.686 MHz clock. Over a
long period of time, this effects an average frequency division
factor of 4.25.
And yes, even with that introduced phase/period error, the
downstream hardware apparently still works just fine, thanks to
the divide-by-16 in front of the SCC's internal baud rate
generator. This gives you a max baud of 230 kbits/sec, with a
phase/period error of 1/(16*16) = 0.39%.
*/
// TODO EVALUATE: Optimize this to minimize the number of register
// bits required, while still preserving ideal frequency division
// and synchronization behavior. Maybe not... less registers
// entails more combinatorial logic delay.
// We use shift registers or 1-bit inverters for high performance,
// minimal cycle overhead.
reg [5:0] c16m_div4_cntr; // Complex C16M -> C3_7M divider counter
// reg [3:0] c16m_div8_cntr; // C16M / 8 counter
reg c16m_div4_cntr; // C16M / 4 counter
// Complex C16M -> C3_7M divider counter, principal divide-by-4
reg c16m_div4_0_cntr;
// Complex C16M -> C3_7M divider counter, counter for slipping in
// extra cycle
reg [16:0] c16m_div4_25_cntr;
reg [3:0] c16m_div8_cntr; // C16M / 8 counter
reg [7:0] c16m_div16_cntr; // C16M / 16 counter
reg c4m;
reg c2m;
reg c1m;
assign pmcyc_pt = c16m_div16_cntr[7];
// assign c2m_e = c2m;
assign n_pmcyc = c1m;
always @(negedge n_res) begin
// Initialize all output registers on RESET.
c8m <= 0;
c4m <= 0;
c3_7m <= 0;
// c2m <= 0;
n_pmcyc <= 1;
c2m <= 0;
c1m <= 0;
// Initialize all internal registers on RESET.
c16m_div4_cntr <= 1;
// c16m_div8_cntr <= 1;
c16m_div4_cntr <= 0;
c16m_div4_0_cntr <= 0;
c16m_div4_25_cntr <= 1;
c16m_div8_cntr <= 1;
c16m_div16_cntr <= 1;
end
always @(posedge c16m) begin
if (n_res) begin
c8m <= ~c8m;
if (c16m_div4_cntr[1]) begin
c3_7m <= ~c3_7m;
c16m_div4_cntr <= 1;
if (c16m_div4_cntr) c4m <= ~c4m;
c16m_div4_cntr <= ~c16m_div4_cntr;
if (~c16m_div4_25_cntr[16]) begin
if (c16m_div4_0_cntr) c3_7m <= ~c3_7m;
c16m_div4_0_cntr <= ~c16m_div4_0_cntr;
end
else
c16m_div4_cntr <= { c16m_div4_cntr[4:0], c16m_div4_cntr[5] };
// if (c16m_div8_cntr[3]) c2m <= ~c2m;
// c16m_div8_cntr <= { c16m_div8_cntr[2:0], c16m_div8_cntr[3] };
if (c16m_div16_cntr[7]) n_pmcyc <= ~n_pmcyc;
// else Slip in the extra cycle by not incrementing the
// principal divide-by-4 counter.
c16m_div4_25_cntr <= { c16m_div4_25_cntr[15:0],
c16m_div4_25_cntr[16] };
if (c16m_div8_cntr[3]) c2m <= ~c2m;
c16m_div8_cntr <= { c16m_div8_cntr[2:0], c16m_div8_cntr[3] };
if (c16m_div16_cntr[7]) c1m <= ~c1m;
c16m_div16_cntr <= { c16m_div16_cntr[6:0], c16m_div16_cntr[7] };
end
end
@ -784,7 +652,7 @@ endmodule
* 0x000000 - 0x3fffff: RAM/ROM (switches based on overlay)
* 0x400000 - 0x4fffff: ROM
* 0x580000 - 0x5fffff: 5380 NCR/Symbios SCSI peripherals chip
* 0x600000 - 0x6fffff: RAM, boot-time overlay only
* 0x600000 - 0x7fffff: RAM, boot-time overlay only
* 0x900000 - 0x9fffff: Zilog 8530 SCC (Serial Control Chip) Read
* 0xb00000 - 0xbfffff: Zilog 8530 SCC (Serial Control Chip) Write
* 0xd00000 - 0xdfffff: IWM (Integrated Woz Machine; floppy)
@ -792,58 +660,143 @@ endmodule
* 0xf00000 - 0xffffef: ??? (the ROM appears to be accessing here)
* 0xfffff0 - 0xffffff: Auto Vector
This address map has also been confirmed with Guide to the
Macintosh family hardware, page 127. PLEASE NOTE: In SCC Read
zone, if A0 == 1, then that is an SCC RESET. IWM must be A0 == 1,
VIA must be A0 == 0, SCC write must be A0 == 1. SCSI read A0 == 0,
SCSI write A0 == 1.
SCC access notes: In the Macintosh Plus and older, even byte
accesses are a read, odd byte accesses are a write. Namely: `*LDS`
== 0 == write, `*UDS` == 0 == read. Remember, it's big endian.
What about the separate address regions? Well, I say just ignore
those, it's there for a convenient convention, but it's not the
officially documented hardware protocol.
In the Macintosh SE, this behavior is somewhat changed. Now `*IOW`
controls both `*SCSI.IOW` and `*SCC.WR`, and `*SCCRD` is wired
directly from the BBU to `*SCC.RD`. `*UDS` is used to trigger
`*SCSI.IOR`.
PLEASE NOTE: Guide to the Macintosh family hardware, page 121.
Rather than signaling bus errors for out of range RAM addresses,
overflow accesses should just wrap around and repeat access to the
same RAM.
PLEASE NOTE: Guide to the Macintosh family hardware, page 122. "A
word-wide access to any SCC address causes a phase shift in the
processor clock, and is used by the operating system to correct the
phase when necessary."
"At system startup, the operating system reads an address in the
range $F0 0000 through $F7 FFFF (labeled _Phase read_ in Gifgures
3-1 and 3-2) to determine whether the computer's high-frequency
timing signals are correctly in phase. When the timing signals are
not in phase, RAM accesses are not timed correctly, causing an
unstable video display, RAM errors, and VIA errors." Well, I can
see how that would be happening with just a bunch of PALs, but I
don't think it still needs to be that way when you have the BBU in
charge, you can do better! And indeed, that note only appears to
apply to the Macintosh Plus, not the Macintosh SE, as it is listed
in that section.
TODO FIXME: Guide to the Macintosh family hardware, page 127.
Okay, so this is how to interpret the information about the
boot-time overlay for the alternate RAM location. Only a 2MB zone
is exposed, even though you may have up to 4MB of RAM. So, 2.5MB
and 4MB RAM configurations need to be treated specially. In
particular, only the "upper row" of RAM is accessible greater than
or equal to the address 0x680000. Below that address, you get
access to the first 512K of RAM. Macintosh Plus actually uses the
same overlay map too. That's a defect in MESS/MAME source code but
apparently it's not important, interestingly enough. Okay, I guess
I don't really quite understand, though, sorry. Okay, this means,
the first row, right? "If 2.5 or 4 MB only upper row is
accessible" page 127.
The signal *VPA is asserted in address range 0xe00000 - 0xffffff,
optionally excluding invalid addresses when a bus error signal is
generated. This is for synchronous I/O devices accessed in the old
6800 fashion.
*/
module decode_devaddr (n_ramen, n_romen, n_scsi, n_sccen, n_sccrd,
n_iwm, via_cs1, n_berr, a23_19,
boot_overlay, r_n_w, reg_romen, reg_ram_w);
module decode_devaddr (n_res, clk, n_ramen, n_romen, n_scsi,
n_sccen, n_sccrd, n_iow, n_iwm, via_cs1, n_vpa,
n_berr, n_as, a23_19, berr_ram, n_extdtk,
boot_overlay, r_n_w, reg_romen, reg_ram_w,
n_dtack_peri);
input wire n_res;
input wire clk;
output wire n_ramen;
output wire n_romen;
output wire n_scsi;
output wire n_sccen;
output wire n_sccrd;
output wire n_iow;
output wire n_iwm;
output wire via_cs1;
output wire n_vpa;
output wire n_berr;
input wire n_as;
input wire [4:0] a23_19;
input wire berr_ram; // Would this RAM address be a bus error?
input wire n_extdtk;
input wire boot_overlay;
input wire r_n_w;
// Have we attempted to write to the regular RAM address zone?
output wire reg_ram_w;
// Has an address access to the regular *ROMEN zone occurred? This
// signal is used to disable the boot-time memory overlay.
output wire reg_romen;
// Have we attempted to write to the regular RAM address zone?
output wire reg_ram_w;
output wire n_dtack_peri; // *DTACK for peripherals
wire berr_ram;
wire reg_ram, reg_ram_r;
wire scsi, sccrd, sccwr;
wire berr_scc;
wire n_dtack_peri_pt; // *DTACK peripherals "pre-trigger"
reg n_dtack_peri_bf; // *DTACK for peripherals buffer
// If the boot-time overlay is enabled but we attempt to write to
// the regular RAM region, then this is a *RAMEN trigger. The
// overlay control logic will zero the switch on the next cycle,
// but we use combinatorial logic here to act immediately.
assign reg_ram_w = (~r_n_w & (a23_19[4:3] == 2'b00));
assign n_ramen = ~((boot_overlay) ? (a23_19[4:1] == 4'b0110) :
(a23_19[4:3] == 2'b00)) &
~reg_ram_w;
assign reg_romen = (a23_19[4:1] == 4'h4);
// Only trigger *ROMEN for reads, not writes.
assign n_romen = ~(reg_romen |
(boot_overlay & r_n_w & (a23_19[4:3] == 2'b00)));
assign n_scsi = ~(a23_19[4:0] == 5'b01011);
assign n_sccen = ~((a23_19[4:1] == 4'h9) |
(a23_19[4:1] == 4'hb));
assign n_sccrd = ~(a23_19[4:1] == 4'h9);
assign n_iwm = ~(a23_19[4:1] == 4'hd);
assign via_cs1 = (a23_19[4:0] == 5'b11101);
// TODO: We don't currently implement Auto Vector, but neither does
// MESS/MAME but its emulation still works just fine? There could
// be ROM patch hacks...
assign reg_ram = ~n_as & (a23_19[4:3] == 2'b00);
assign reg_ram_r = (r_n_w & reg_ram);
assign reg_ram_w = (~r_n_w & reg_ram);
assign n_ramen = ~((boot_overlay) ?
((~n_as & ((a23_19[4:1] == 4'h6) |
(a23_19[4:1] == 4'h7))) | reg_ram_w) :
reg_ram);
assign reg_romen = ~n_as & (a23_19[4:1] == 4'h4);
// Only trigger *ROMEN for reads, not writes, in overlay zone.
assign n_romen = ~(reg_romen | (boot_overlay & reg_ram_r));
assign scsi = ~n_as & (a23_19[4:0] == 5'b01011);
assign n_scsi = ~scsi;
assign sccrd = ~n_as & (a23_19[4:1] == 4'h9);
assign sccwr = ~n_as & (a23_19[4:1] == 4'hb);
assign n_sccen = ~(sccrd | sccwr);
assign n_sccrd = ~sccrd;
assign n_iow = ~((scsi & ~r_n_w) | sccwr);
assign n_iwm = ~(~n_as & (a23_19[4:1] == 4'hd));
assign via_cs1 = ~n_as & (a23_19[4:0] == 5'b11101);
assign n_vpa = ~(via_cs1 | (~n_as & (a23_19[4:1] == 4'hf)));
// N.B.: According to Guide to the Macintosh family hardware, page
// 126, the implementation of Auto Vector is easy and
// straightforward for the BBU. Just assert `*VPA` in the address
// range. The CPU sets address lines A3 - A1, and this causes the
// CPU to automatically jump to the memory location containing the
// interrupt handler.
// TODO: Signal a bus error for out-of-range RAM addresses. Make
// sure to also signal errors in the boot-time overlay when booting
// with less than 1 MB of RAM. This would require decoding more
// address bits, though.
assign berr_ram = 0;
// Optionally trigger bus errors if a read is attempted from the
// write-only SCC address space, and vice versa.
assign berr_scc = (sccrd & ~r_n_w) | (sccwr & r_n_w);
assign n_berr = ~(berr_ram |
// Note that if the PDS card asserts *EXTDTK, we also must not
// drive *BERR. TODO EVALUATE: Should we wait a cycle before
// asserting *BERR to give the PDS card time to respond first?
assign n_berr = n_as | ~n_extdtk |
~((~n_ramen & berr_ram) |
berr_scc |
(a23_19[4:0] == 5'b01010) |
(a23_19[4:1] == 4'h7) |
(a23_19[4:1] == 4'h8) |
@ -851,21 +804,88 @@ module decode_devaddr (n_ramen, n_romen, n_scsi, n_sccen, n_sccrd,
(a23_19[4:1] == 4'hc) |
(a23_19[4:0] == 5'b11100));
// TODO: Also flag bus errors for the final address zone.
// NOTE: For all peripherals, we must set `*DTACK` from the BBU
// upon successful access condition and time durations because it
// is not set by the device itself. From the time *AS is asserted,
// we simply wait one clock cycle on whatever clock is given to us
// before we trigger *DTACK for the peripheral.
// N.B.: According to Guide to the Macintosh family hardware,
// `*DTACK` is not used to respond to addresses in the range
// 0xe00000 - 0xffffff, only below that. `*VPA` alone is used to
// respond to these addresses. So therefore, we exclude `VIA.CS1`.
assign n_dtack_peri_pt = n_scsi & n_sccen & n_iwm;
// N.B. We use combinatorial logic here to deassert *DTACK for
// peripherals as soon as *AS is released.
assign n_dtack_peri = n_as | n_dtack_peri_bf;
always @(negedge n_res) begin
n_dtack_peri_bf <= 1;
end
always @(posedge clk) begin
if (n_res) begin
if (n_as)
n_dtack_peri_bf <= 1;
else begin
if (n_dtack_peri_pt)
n_dtack_peri_bf <= 0;
else
n_dtack_peri_bf <= 1;
end
end
else
; // Nothing to be done during RESET.
end
endmodule
// Determine if a RAM address is out of range and should therefore
// signal a bus error.
module berr_ram_logic (a0_21, ramsz, /*ramsz_en,*/ berr_ram);
input wire [21:0] a0_21;
input wire [23:0] ramsz;
// input wire [6:0] ramsz_en;
output wire berr_ram;
// We could either use arithmetic comparison (easiest to code in
// Verilog), or bit-wise comparisons (possibly more efficient in
// hardware). We may simply consider implementing this logic in a
// separate module.
// 4MB valid: 0x000000 - 0x3fffff
// 4MB invalid: None!
// 2.5MB valid: 0x000000 - 0x27ffff
// 2.5MB invalid: 0x280000 - 0x3fffff
// 2MB valid: 0x000000 - 0x1fffff
// 2MB invalid: 0x200000 - 0x3fffff
// 1MB valid: 0x000000 - 0x0fffff
// 1MB invalid: 0x100000 - 0x3fffff
// 512K valid: 0x000000 - 0x07ffff
// 512K invalid: 0x080000 - 0x3fffff
// 256K valid: 0x000000 - 0x03ffff
// 256K invalid: 0x040000 - 0x3fffff
// 128K valid: 0x000000 - 0x01ffff
// 128K invalid: 0x020000 - 0x3fffff
// N.B. Verilog comparison is unsigned by default.
assign berr_ram = { 1'b0, a0_21[21:17] } < ramsz[22:17];
endmodule
// Boot-time memory overlay register and controlling logic. This is
// fairly straightforward to implement once you see all the other
// logic of the BBU in place.
module overlay_logic (n_res, clk, overlay, reg_romen, reg_ram_w);
module overlay_logic (n_res, clk, boot_overlay, reg_romen, reg_ram_w);
input wire n_res;
input wire clk;
output reg overlay;
// Boot-time memory overlay switch, 1 = enable, 0 = disable.
output reg boot_overlay;
input wire reg_romen;
input wire reg_ram_w;
always @(negedge n_res) begin
// Initialize the overlay switch to ENABLED on RESET.
overlay <= 1;
boot_overlay <= 1;
end
always @(posedge clk) begin
@ -874,13 +894,12 @@ module overlay_logic (n_res, clk, overlay, reg_romen, reg_ram_w);
// address zone. And, according to MESS/MAME, also disable
// on the first attempt to write the regular RAM zone.
if (reg_romen | reg_ram_w)
overlay <= 0;
boot_overlay <= 0;
else
; // Nothing to be done.
end
end
endmodule // btm_overlay
endmodule
// Column address strobe decode logic. Determine which column access
// strobe line to assert based off of the installed RAM, high-order
@ -1324,39 +1343,96 @@ endmodule
// determine where we are on the screen, which buffer address to fetch
// next, and so on.
module avtimers ();
input wire n_res;
input wire c16m;
// Video signals
input wire vidpg2; // VIDPG2 signal
output reg vidout; // VIDOUT signal
output reg n_hsync; // *HSYNC signal
output reg n_vsync; // *VSYNC signal
// Sound and disk speed signals
input wire sndres;
output reg snd, pwm;
// C16M pixel clock (0.064 us per pixel).
// 512 horizontal draw pixels, 192 horizontal blanking pixels.
// 342 scan lines, 28 scan lines vertical blanking.
// 60.15 Hz vertical scan rate.
// (512 + 192) * (342 + 28) = 260480 pixel clock ticks per frame.
// Total screen buffer size = 10944 words. High-order bit of each
// 16-bit word is the leftmost pixel, low-order bit is the
// rightmost pixel. Words in ascending order move from left to
// right in the scan line, first scan line is topmost and then
// moves downward.
// *HSYNC and *VSYNC counters are negative during blanking.
reg [15:0] vidout_sreg; // VIDOUT shift register
reg [4:0] vidout_cntr; // VIDOUT remaining counter
reg [9:0] vid_hsync_cntr; // *HSYNC counter
reg [8:0] vid_vsync_cntr; // *VSYNC counter
wire [23:0] vid_main_addr; // Address of main video buffer
wire [23:0] vid_alt_addr; // Address of alternate video buffer
// Sound and disk speed buffers are scanned 370 words per video
// frame, and the size of both buffers together is 370 words. Or,
// 260480 pixel clock ticks / 370 = 704 pixel clock ticks per word.
// In a single scan line, (512 + 192) / 704 = 704 / 704 = exactly 1
// word is read. The sound byte is the most significant byte, the
// disk speed byte is the least significant byte. Both the sound
// sample and disk speed represent a PCM amplitude value, this is
// used to generate a PDM waveform that can be processed by a
// low-pass filter to generate the analog signal.
// Well, at least in concept... Inside Macintosh claims that only a
// single pulse is generated, so this is not quite your typical PDM
// audio circuit. Nevertheless, the sample rate is 22.2555 kHz, so
// it's not too bad overall for generating lo-fi audio. But, good
// point to ponder, this is an area of improvement where a
// different algorithm can generate better audio quality.
reg [15:0] snddsk_reg; // PCM sound sample and disk speed register
wire [23:0] snddsk_main_addr; // Address of main sound/disk buffer
wire [23:0] snddsk_alt_addr; // Address of alternate sound/disk buffer
// We must be careful that the sound circuitry does not attempt to
// access RAM at the same time as the video circuitry. Because the
// phases are coherent, we can simply align the sound and disk
// speed RAM fetch to be at a constant offset relative to the video
// RAM fetch.
// PLEASE NOTE: We must carefully time our RAM accesses since they
// have delays and we don't want the screen bits shift register
// buffer to run empty before we have the next word available from
// RAM. Our ideal is that the next word is available from RAM just
// as we are shifting out the last pixel, so that we can use a
// non-blocking assign and the new first pixel will be available
// right at the start of the next pixel clock cycle. Otherwise,
// less ideal but easier to program would be to use two 16-bit
// buffers as a FIFO.
always @(negedge n_res) begin
// Initialize all output registers on RESET.
vidout <= 0; n_hsync <= 1; n_vsync <= 1;
snd <= 0; pwm <= 0;
// Initialize all internal registers on RESET.
vidout_sreg <= 0;
vidout_cntr <= 0;
vid_hsync_cntr <= 0;
vid_vsync_cntr <= 0;
snddsk_reg <= 0;
end
endmodule
/* TODO: Summary of what is missing and left to implement: DRAM
initialization pulses, DRAM refresh, video, disk, and audio
scanout, SCSI DMA, EXTDTK yielding, double-check SCC read/write
logic. */
/*
TODO: Okay, we really have a plan now to try to make my code modular
and easy to understand. The original probably wasn't too nice since
it was only written by really one person working by themself, but hey,
let's go better a second time around. So, yes, this is the plan. See
that nice, clean, simple DRAM controller main state advancement
module? My goal is to create just a series of modules like that, they
plug together to create the full integrated system. We use
combinatorial logic and rerouting wires as necessary to get the final
intended behavior.
One thing to remember is that we have monopoly control over the output
logic of RA7 and RA9. We never need to yield high-impedance on this.
So we just use combinatorial logic to set this as we please, from
jumpers, internal registers, and the like. Yes, namely the configured
installed RAM mode.
To keep the main DRAM controller simple, we can use combinatorial
logic spelled out separately and `n_cas` as a register to trigger the
proper CAS lines on the individual DRAM SIMMs. This is also where we
handle *LDS and *UDS.
Since we use a module for the DRAM controller main loop, we can use
wires and other modules to feed it whatever state advancement clock we
want. That's really good! That solves a problem I was worrying
about.
*/
initialization pulses, DRAM refresh, detect 2.5MB of RAM and
configure address buffers accordingly, video, disk, and audio
scanout, SCSI DMA, EXTDTK yielding, interrupt propagation,
double-check SCC read/write logic. */

View File

@ -1,85 +1,85 @@
BBU Pin,Signal Name,Description,Device Connection,Device Pin
1,GND,,,
2,RD7,,,
3,RD8,,,
4,RD9,,,
5,RD10,,,
6,RD11,,,
7,RD12,,,
8,RD13,,,
9,RD14,,,
10,RD15,,,
11,EXTPDS,,,
12,EN245,Select Data Buffer,74LS245,
13,VCC,,,
14,/WR,,,
15,/CAS-SIMM3,,SIMM3,2
16,/CAS-SIMM1,,SIMM1,2
17,/EOP,,53C80,
18,/CAS-SIMM4,,SIMM4,2
19,/CAS-SIMM2,,SIMM2,2
20,/RAS,,,
21,GND,,,
22,VCC,,,
23,A23,,,
24,A22,,,
25,A21,,,
26,A20,,,
27,A19,,,
28,A17,,,
29,A9,,,
30,/IPL1,,68000,
31,/IPL0,,68000,
32,IRQ,,65C22/6523,
33,/LDS,,68000,
34,/BERR,,68000,
35,/UDS,,,
36,/VPA,,68000,
37,CK,,68000,
38,/DTACK,,68000,
39,SELROM,Select ROM,ROM,"20 on ROM HI, LO"
40,"RTxCB, PCLK, ADB CLK",All the things,"85C30, ADB, GLU","20 & 28 on 85C30, 16 on ADB, 9 on GLU"
41,/AS,,,
42,VCC,,,
43,GND,,,
44,FCLK,,"SWIM, GLU","24 on SWIM, 19 on GLU"
45,SELSCC,Select SCC,85C30,32 on /CE
46,/RD,,85C30,
47,R/W,,,
48,SELSWIM,Select SWIM,SWIM,7 on /DEV
49,EXTFLP,PWM,External Floppy,10 on PWM
50,PB7,,65C22/6523,
51,SELSND,Select Sound,SND,
52,EXTPDS,,,
53,PA6,,65C22/6523,
54,/LDS,,,
55,DRQ,,53C80,22 on DRQ
56,/DACK,,53C80,26 on /DACK
57,SELSCSI,Select SCSI,53C80,21 on /CS
58,SELVIA,Select VIA,65C22/6523,24 on RS0
59,/RST,,,
60,HSYNC,Horizontal Sync,J12,Pin 10 on J12
61,VSYNC,Veritcal Sync,"J12, 65C22/6523","Pin 11 on J12, 40 on DB7"
62,VIDOUT,Composite Video Out,"J12, 65C22/6523","Pin 9 on J12, 28 on PC3"
63,GND,,,
64,VCC,,,
65,RA9,,,
66,RA7,,,
67,RA8,,,
68,RA6,,,
69,RD0,,,
70,RA5,,,
71,RA4,,,
72,RD1,,,
73,RA3,,,
74,RD2,,,
75,RD3,,,
76,RA2,,,
77,RD4,,,
78,RA1,,,
79,RA0,,,
80,RD5,,,
81,/PMCYC,,74F257,/OE
82,EN257,Select Address Buffer,74F257,
83,RD6,,,
84,VCC,,,
Verilog,Signal,Pin,Description,Direction,Device Connection,Device Pin,Device Signal
ra0,RA0,79,RAM Address bit 0,inout,DRAM SIMMs
ra1,RA1,78,RAM Address bit 1,inout,DRAM SIMMs
ra2,RA2,76,RAM Address bit 2,inout,DRAM SIMMs
ra3,RA3,73,RAM Address bit 3,inout,DRAM SIMMs
ra4,RA4,71,RAM Address bit 4,inout,DRAM SIMMs
ra5,RA5,70,RAM Address bit 5,inout,DRAM SIMMs
ra6,RA6,68,RAM Address bit 6,inout,DRAM SIMMs
ra8,RA8,67,RAM Address bit 8,inout,DRAM SIMMs
ra7,RA7,66,RAM Address bit 7,output,DRAM SIMMs
ra9,RA9,65,RAM Address bit 9,output,DRAM SIMMs
n_cas1l,*CAS1L,16,DRAM Column Access Strobe row #2 low-byte SIMM,output,DRAM SIMMs
n_cas0l,*CAS0L,15,DRAM Column Access Strobe row #1 low-byte SIMM,output,DRAM SIMMs
ram_r_n_w,RAM R/*W,14,DRAM read/write,output,DRAM SIMMs
n_ras,*RAS,20,DRAM Row Access Strobe,output,DRAM SIMMs
n_cas1h,*CAS1H,19,DRAM Column Access Strobe row #2 high-byte SIMM,output,DRAM SIMMs
n_cas0h,*CAS0H,18,DRAM Column Access Strobe row #1 high-byte SIMM,output,DRAM SIMMs
rdq0,RDQ0,69,RAM Data Value bit 0,inout,DRAM SIMMs
rdq1,RDQ1,72,RAM Data Value bit 1,inout,DRAM SIMMs
rdq2,RDQ2,74,RAM Data Value bit 2,inout,DRAM SIMMs
rdq3,RDQ3,75,RAM Data Value bit 3,inout,DRAM SIMMs
rdq4,RDQ4,77,RAM Data Value bit 4,inout,DRAM SIMMs
rdq5,RDQ5,80,RAM Data Value bit 5,inout,DRAM SIMMs
rdq6,RDQ6,83,RAM Data Value bit 6,inout,DRAM SIMMs
rdq7,RDQ7,2,RAM Data Value bit 7,inout,DRAM SIMMs
rdq8,RDQ8,3,RAM Data Value bit 8,inout,DRAM SIMMs
rdq9,RDQ9,4,RAM Data Value bit 9,inout,DRAM SIMMs
rdq10,RDQ10,5,RAM Data Value bit 10,inout,DRAM SIMMs
rdq11,RDQ11,6,RAM Data Value bit 11,inout,DRAM SIMMs
rdq12,RDQ12,7,RAM Data Value bit 12,inout,DRAM SIMMs
rdq13,RDQ13,8,RAM Data Value bit 13,inout,DRAM SIMMs
rdq14,RDQ14,9,RAM Data Value bit 14,inout,DRAM SIMMs
rdq15,RDQ15,10,RAM Data Value bit 15,inout,DRAM SIMMs
n_en245,*EN245,12,Enable LS245 DRAM to CPU data bus switch,output,LS245,19,*EO
n_dtack,*DTACK,38,CPU Data Transfer Acknowledge,inout,68000,10,*DTACK
r_n_w,R/*W,47,CPU memory read/write,input,68000,9,R/*W
n_ipl1,*IPL1,30,CPU Interrupt Priority Level bit 1,input,68000,24,*IPL1
n_lds,*LDS,33,CPU Lower Data Strobe,input,68000,8,*LDS
n_vpa,*VPA,36,CPU Valid Peripheral Address,output,68000,21,*VPA
c8m,C8M,37,8MHz clock,output,68000,15,CLK
null,VCC,22,+5V power,power
null,VCC,64,+5V power,power
null,VCC,42,+5V power,power
null,VCC,84,+5V power,power
mbram,MBRAM,17,1MB RAM SIMMs jumper,input,Jumper J16
null,GND,1,Ground,power
s64kram,64KRAM,21,UNOFFICIAL 64K RAM SIMMs jumper,input
null,GND,43,Ground,power
null,GND,63,Ground,power
row2,ROW2,13,2 rows of RAM SIMMs jumper,input,Jumper J16
n_extdtk,*EXTDTK,11,External PDS will drive *DTACK,input,PDS slot J13,B28,*EXT.DTACK
a23,A23,23,CPU Address bit 23,input,68000,52,A23
a22,A22,24,CPU Address bit 22,input,68000,51,A22
a21,A21,25,CPU Address bit 21,input,68000,50,A21
a20,A20,26,CPU Address bit 20,input,68000,48,A20
a19,A19,27,CPU Address bit 19,input,68000,47,A19
a17,A17,28,CPU Address bit 17,input,68000,45,A17
a9,A9,29,CPU Address bit 9,input,68000,37,A9
n_pmcyc,*PMCYC,81,Processor Memory CYCle,output,F257,15,*OE
c2m,C2M,82,~2MHz DRAM row/column address selector clock,output,F257,1,S
n_res,*RES,59,RESet,input,68000,18,*RES
c16m,C16MRSF2,44,Filtered 16MHz clock input,input,GLU,19,FCLK
c3_7m,C3.7M,40,~3.7MHz clock,output,"8530, ADB, GLU","20 & 28 on 8530, 16 on ADB, 9 on GLU",RTXCB
n_romen,*ROMEN,39,ROM ENable,output,ROM,20,*CE
n_sccrd,*SCCRD,46,Serial Communications Controller ReaD,output,8530,36,*RD
pwm,PWM,49,Pulse Width Modulation floppy disk drive motor speed control,output,External Floppy,10,PWM
scsidrq,SCSIDRQ,55,SCSI DMA ReQuest,input,5380,22,DRQ
n_iwm,*IWM,48,Integrated Wozniak Machine floppy disk controller chip enable,output,IWM,7,*DEV
n_sccen,*SCCEN,45,Serial Communications Controller chip ENable,output,8530,33,*CE
n_scsi,*SCSI,57,SCSI chip select,output,5380,21,*CS
n_dack,*DACK,56,SCSI DMA ACKnowledge,output,5380,26,*DACK
sndres,SNDRES,50,SouND RESet,input,6522,17,PB7 vSndEnb
via_cs1,VIA.CS1,58,VIA Chip Select 1,output,6522,24,CS1
vidpg2,VIDPG2,53,VIDeo framebuffer PaGe 2,input,6522,8,PA6 vPage2
n_earen,*EAREN,52,Unknown reserved PDS input signal,output,PDS slot J13,B11,Reserved
n_as,*AS,41,CPU Address Strobe,input,68000,6,*AS
n_berr,*BERR,34,CPU Bus ERRor,output,68000,22,*BERR
snd,SND,51,PWM SouND output,output,Sound filter circuit
n_vsync,*VSYNC,61,Video Vertical Synchronization control,output,Analog board J12,11 on J12 and 40 on 6522,CA1
n_iow,*IOW,54,SCSI and Serial Communications Controller I/O Write,output,5380 and 8530,29 on 5380 and 35 on 8530,*IOW on 5380 and *WR on 8530
n_hsync,*HSYNC,60,Video Horizontal Synchronization control,output,Analog board J12,10 on J12
n_viairq,*VIAIRQ,32,VIA Interrupt ReQuest,input,6522,21,*IRQ
vidout,VIDOUT,62,VIDeo OUTput,output,Analog board J12,9 on J12
n_ipl0,*IPL0,31,CPU Interrupt Priority Level bit 0,output,68000,25,*IPL0
n_uds,*UDS,35,CPU Upper Data Strobe,input,68000,7,*UDS

Can't render this file because it has a wrong number of fields in line 2.