I have no idea what you guys are talking about (never continued to study electronic ^^;;) but it great to see the enthusiasm for trying to find as much information about this mapper!
Good work

Moderators: B00daW, Moderators
It's got one major advantage - the MMC5 PCM channel is 8 bits, whereas the 2A03 DPCM channel is 7 bits. Right?Ben Boldt wrote:Why go so far as to add a big expensive DAC that has basically no advantage over the one built-in to the NES's CPU?
Indeed, that's the only advantage I can think off, and also the MMC5 PCM can be used while a DPCM sample is playing for example.LightStruk wrote:It's got one major advantage - the MMC5 PCM channel is 8 bits, whereas the 2A03 DPCM channel is 7 bits. Right?
4 cycles saved, not just 1. Still not a meaningful difference, compared to the cost of IRQ entry, exit, and the pointer math to update things.Ben Boldt wrote:If you are in read mode, and you are updating the DAC by means of reading, why not just check the value read? It is like a 1 cycle savings per sound sample, paid back by extra checks in the IRQ handler.
My random guess is that Nintendo had something better in mind, but the development wasn't finished when it was time to manufacture the MMC5 chip, so they left and unfinished feature in the chip. It seems likely to me that automatic playback of 8-bit samples at selectable rate without CPU intervention was going to be implemented. It's the same for the square waves who are missing the sweep mode, and other strange things in MMC5 which smells like unfinished work.Ben Boldt wrote:Yes I agree that those are advantages, but the NES pretty much has to stop everything else in order to use this DAC -- that seems to really limit the usefulness. Also, the interrupt seems to not be useful. If you are in read mode, and you are updating the DAC by means of reading, why not just check the value read? It is like a 1 cycle savings per sound sample, paid back by extra checks in the IRQ handler. That doesn't make much sense to me.
This is unrelated but now that you mention it I clearly remember Just Breed using an unknown MMC5 register, maybe it was $5800 or similar. It was really strange and unexplainable.Banshaku wrote:Game don't always uses all the features of the mapper so looking at the code may help find things but the document is the best (but unavailable) source of information.
Cool - do you think you could find that again? I will have a look tonight. I would like to at least list it on the MMC5 wiki page as an unknown write-only register.Bregalad wrote:This is unrelated but now that you mention it I clearly remember Just Breed using an unknown MMC5 register, maybe it was $5800 or similar. It was really strange and unexplainable.Banshaku wrote:Game don't always uses all the features of the mapper so looking at the code may help find things but the document is the best (but unavailable) source of information.
Code: Select all
A:17 X:05 Y:17 S:EB P:nvUbdIzc $E14F:A9 03 LDA #$03
A:03 X:05 Y:17 S:EB P:nvUbdIzc $E151:8D 00 58 STA $5800 = #$03
A:03 X:05 Y:17 S:EB P:nvUbdIzc $E154:A9 01 LDA #$01
A:01 X:05 Y:17 S:EB P:nvUbdIzc $E156:8D 00 58 STA $5800 = #$01
A:01 X:05 Y:17 S:EB P:nvUbdIzc $E159:68 PLA
A:17 X:05 Y:17 S:EC P:nvUbdIzc $E15A:A5 BC LDA $00BC = #$FA
A:FA X:05 Y:17 S:EC P:NvUbdIzc $E15C:48 PHA
A:FA X:05 Y:17 S:EB P:NvUbdIzc $E15D:A5 BD LDA $00BD = #$FB
A:FB X:05 Y:17 S:EB P:NvUbdIzc $E15F:48 PHA
A:FB X:05 Y:17 S:EA P:NvUbdIzc $E160:A9 FC LDA #$FC
A:FC X:05 Y:17 S:EA P:NvUbdIzc $E162:20 9C EB JSR $EB9C
A:FC X:05 Y:17 S:E8 P:NvUbdIzc $EB9C:85 BD STA $00BD = #$FB
A:FC X:05 Y:17 S:E8 P:NvUbdIzc $EB9E:8D 15 51 STA $5115 = #$BD
A:FC X:05 Y:17 S:E8 P:NvUbdIzc $EBA1:60 RTS (from $EB9C) ---------------------------
A:FC X:05 Y:17 S:EA P:NvUbdIzc $E165:A5 E5 LDA $00E5 = #$01
A:01 X:05 Y:17 S:EA P:nvUbdIzc $E167:F0 32 BEQ $E19B
A:01 X:05 Y:17 S:EA P:nvUbdIzc $E169:20 57 A7 JSR $A757
A:01 X:05 Y:17 S:E8 P:nvUbdIzc $A757:A9 00 LDA #$00
A:00 X:05 Y:17 S:E8 P:nvUbdIZc $A759:8D 03 20 STA PPU_OAM_ADDR = #$00
A:00 X:05 Y:17 S:E8 P:nvUbdIZc $A75C:A9 02 LDA #$02
A:02 X:05 Y:17 S:E8 P:nvUbdIzc $A75E:8D 14 40 STA OAM_DMA = #$02
A:02 X:05 Y:17 S:E8 P:nvUbdIzc $A761:60 RTS (from $A757) ---------------------------
A:02 X:05 Y:17 S:EA P:nvUbdIzc $E16C:20 CD AF JSR $AFCD
A:02 X:05 Y:17 S:E8 P:nvUbdIzc $AFCD:A5 E6 LDA $00E6 = #$00
A:00 X:05 Y:17 S:E8 P:nvUbdIZc $AFCF:F0 08 BEQ $AFD9
A:00 X:05 Y:17 S:E8 P:nvUbdIZc $AFD9:AD 02 20 LDA PPU_STATUS = #$90
A:90 X:05 Y:17 S:E8 P:NvUbdIzc $AFDC:A9 3F LDA #$3F
A:3F X:05 Y:17 S:E8 P:nvUbdIzc $AFDE:8D 06 20 STA PPU_ADDRESS = #$A0
A:3F X:05 Y:17 S:E8 P:nvUbdIzc $AFE1:A9 10 LDA #$10
A:10 X:05 Y:17 S:E8 P:nvUbdIzc $AFE3:8D 06 20 STA PPU_ADDRESS = #$A0
A:10 X:05 Y:17 S:E8 P:nvUbdIzc $AFE6:A2 00 LDX #$00
A:10 X:00 Y:17 S:E8 P:nvUbdIZc $AFE8:BD 90 03 LDA $0390,X @ $0390 = #$0F
A:0F X:00 Y:17 S:E8 P:nvUbdIzc $AFEB:8D 07 20 STA PPU_DATA = #$00
etc.
Code: Select all
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E16F:A5 83 LDA $0083 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E171:8D 20 51 STA $5120 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E174:A5 84 LDA $0084 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E176:8D 21 51 STA $5121 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E179:A5 85 LDA $0085 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E17B:8D 22 51 STA $5122 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E17E:A5 86 LDA $0086 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E180:8D 23 51 STA $5123 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E183:A5 87 LDA $0087 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E185:8D 24 51 STA $5124 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E188:A5 88 LDA $0088 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E18A:8D 25 51 STA $5125 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E18D:A5 89 LDA $0089 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E18F:8D 26 51 STA $5126 = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E192:A5 8A LDA $008A = #$00
A:00 X:10 Y:17 S:EA P:nvUbdIZC $E194:8D 27 51 STA $5127 = #$00
Code: Select all
A:00 X:00 Y:17 S:E8 P:nvUbdiZC $E911:A5 5B LDA $005B = #$00
A:00 X:00 Y:17 S:E8 P:nvUbdiZC $E913:8D 05 20 STA PPU_SCROLL = #$00
A:00 X:00 Y:17 S:E8 P:nvUbdiZC $E916:A5 5C LDA $005C = #$EF
A:EF X:00 Y:17 S:E8 P:NvUbdizC $E918:8D 05 20 STA PPU_SCROLL = #$00
A:EF X:00 Y:17 S:E8 P:NvUbdizC $E91B:A5 00 LDA $0000 = #$A8
A:A8 X:00 Y:17 S:E8 P:NvUbdizC $E91D:8D 00 20 STA PPU_CTRL = #$A8
Code: Select all
private void testFillRam()
{
data_queue = new byte[60];
data_queue_index = 0;
string s = "";
// ** Initialize **
readAndRefreshGraphics();
data_queue[data_queue_index] = 0x03; // Set M2 fast mode
data_queue_index++;
data_queue[data_queue_index] = 0x00; // Set M2 Low
data_queue_index++;
data_queue[data_queue_index] = 0xFF; // Rise CPU R/W
data_queue_index++;
operation_setCpuAddressBusDirection(false); // Set CPU address bus as output.
// Write mode value $02 to register $5102:
operation_setCpuAddress(0x5102);
operation_writeCpuData(0x02);
// Write mode value $01 to register $5103:
operation_setCpuAddress(0x5103);
operation_writeCpuData(0x02);
// Write Extended RAM mode value $02 to register $5104:
operation_setCpuAddress(0x5104);
operation_writeCpuData(0x02);
sendOperationQueueToDsPic();
readResultsFromDsPic(0); // Run the queue.
// ** End Initialize **
// Write non-zero, non-FF, non-negative data to entire expansion RAM:
int i_start = 0x5C00;
int i_end = 0x6000;
byte data_to_write = 0x10;
for (int i = i_start; i < i_end; i++)
{
operation_setCpuAddress((UInt16)i);
operation_writeCpuData(data_to_write);
data_to_write++;
if (data_to_write > 0x7F)
{
data_to_write = 0x10;
}
sendOperationQueueToDsPic();
readResultsFromDsPic(0); // Run the queue.
// Update progress bar in GUI:
SetProgressThreadable(i, i_start, i_end, 100);
}
// Read back entire expansion RAM
i_start = 0x5C00;
i_end = 0x6000;
for (int i = i_start; i < i_end; i++)
{
operation_setCpuAddress((UInt16)i);
operation_readCpuData();
sendOperationQueueToDsPic();
byte[] readback = readResultsFromDsPic(1);
s += i.ToString("X4") + ",";
s += readback[0].ToString("X2") + "\r\n";
SetProgressThreadable(i, i_start, i_end, 100);
}
// Log to File:
filename = "MMC5 Expansion RAM Fill " + DateTime.Now.ToString("MM.dd.yy hh.mm.ss tt");
using (StreamWriter outfile = new StreamWriter(folderName + filename + ".csv", true))
{
outfile.WriteLine(s);
}
SetProgressThreadable(0, 0, 0, 1);
}
Code: Select all
private void operation_writeCpuData( byte data )
{
data_queue[data_queue_index] = 0x01; // Set M2 High
data_queue_index++;
data_queue[data_queue_index] = 0xFE; // set CPU R/W low
data_queue_index++;
data_queue[data_queue_index] = 0x56; // Write byte to CPU data bus
data_queue_index++;
data_queue[data_queue_index] = data; // ^ (data)
data_queue_index++;
data_queue[data_queue_index] = 0x66; // Set as output from IO expander to MMC5
data_queue_index++;
data_queue[data_queue_index] = 0x00; // ^ (Output)
data_queue_index++;
data_queue[data_queue_index] = 0x00; // Set M2 Low -- Registers the write on falling edge. (I think???)
data_queue_index++;
data_queue[data_queue_index] = 0x66; // Set as input to IO expander from MMC5
data_queue_index++;
data_queue[data_queue_index] = 0xFF; // ^ (Input)
data_queue_index++;
data_queue[data_queue_index] = 0xFF; // CPU R/W high
data_queue_index++;
}