I updated the assembler code. I did not remember having programmed so much, it must be the reason why I have no clear recollection of 2010 The asm is really extended, with use of the DMA and a lot of the PPU is implemented. However it does not work wel, I will try those debuggers. But enough for now.

Feel free to look at the asm files and memap.txt and comment the design choices.

It was a bug, it compared the long int CRC 0xFFFFFFFFECDA4EDD with 0x0000000ECDA4EDD. It should work now, however I did not recompile the windows binaries.I will recompile the sources on Sunday, but today I am struggling with too much shit.

Actually upernes recompiles only the code to the code bank and uses the original prg rom in the data bank. However doing this does not work with SMB1 because the routine addresses are stored as data, and the call to the routines uses the jsr return address as base address. But upernes moves this jsr instruction and therefore, not only the jumpEngine points on anything, but also the displayed supposedly unknown indirect jump addresses are wrong.

Solutions

Case 1: using the BRQ instruction.

Therefore the original routine addresses and data could be kept in order to handle any indirect jump problem.The replaced instructions are like: sta/stx/sty to an IO port and lda/ldy/ldx from an IO port, plus the indirect jumps.BRK takes 2 bytes, but the sta/lda to IO regiters and jmp indirect take 3 bytes. We can use the 2 extra bytes to store the replaced opcode. Opcodes for lda ldx ldy sta stx sty jmp could be coded on 4 bits and one byte to code the IO port or the indirect jump code. The 3 bytes opcodes are replaced with BRK XX XX and therefore, the original code keeps the same size.

The interrupt vectors must then point to an area where we have nothing on the nes. From here it goes to native mode and it changes bank to execute the IO port or jump emulation code (which only checks that the jump address was known at conversion time).The code in ram could be a native mode change plus a jsl (jump subroutine long) going to another bank.It will be needed to handle all the emulation mode interrupts the same way because the super mario data goes up to the interrupt vectors and leaves no room for the native vectors.

Case 2: the recompiled code must be at a known addresses.The jump engine calls must be at the same offset as in the original prg rom. His address will be indicated in the indirect jumps file and once known every call to it will be correct.But this could not work for other games.

Case 3: a mix between the two, every routine call address is kept at his original address. The assembler must copy the emulation code in the blank spaces left over were the data was. I assume it won't be possible.

Case 1 seems to be mandatory. I do not know if it can be done from bank 1 in emulation mode because interrupts seem to be only in bank 0?Will it be possible to boot on the bank0 and process interrupts from bank 1 or 2 while in the CPU emulation mode?

It seems that in order to run the routines at the same address, the patched code must be in bank zero in order to execute interrupts properly. And this will give little space for the snes init and IO emulation code, it will be in another bank.Bank 0: patched PRG ROMBank 1: original PRG ROM for dataBank 2: init and IO snes code

It boots on bank zero where it goes to code installed in a data 'hole' and then to the nes init vector:

Code:

free@:sei ; native modeclcxcejml SnesInit ; long jump to the other bank

Then it initialises everything in SnesInit form bank 2, and calls jml EndSnesInit

Code:

EndSnesInit:secxce ; emulation modejmp NesInitVector

This will take 11bytes somewhere in the bank zero

And the BRK code will work on the same principle, jumping to bank 2 in native mode and going back to bank 0 for an RTS in emulation mode.

The other solution if I want to run the nes prg from another bank, is to replace the rti instructions with a custom code going back to the proper bank. I found out that all the 256 65C816 instructions are available in emulation, maybe it can help.Having the patched prg rom in bank 1 or 2 would make interrupts easier (Reset, NMI and BRK). I prefer this solution, but I must find a clean way to 'rti' back to the original code once in bank 0.

Edit: When an interrupt occurs in emulation from a PRG bank other than bank 0, the original bank is lost. Following the Programer's manual, a long jump to the rti in the original bank will work, restoring the bank number.And for BRK, the rti will return on the byte after the BRK opcode, hence on the last "parameter" byte. And therefore, a pull of registers and a long jump to the saved return address + 2 should do it. The tricky part is to do it while in emulation mode???

Edit2:I tried this code

Code:

secxce ; Emulationjml next.ENDS

.BANK 3.ORG 0.SECTION "Other" next:

And it compiles, I assume that a long jump works also in emulation. And because it does not change the status registers it could be used to go to a static address like the nes reset vector while in emulation.And the "Absolute Indirect Long Addressing" jump could be used to come back from a BRK while in emulation.This looks promising, it would allow to have the SMB1 patched PRG in bank 1 or 2 and run the emulation on bank 0.

I worked on the BRK patching method. But I believe it will not work because a BRK cannot occur while interrupts are disabled.Maybe I should use a replacement like this: jsr stalongjump going to a data area of the code and put a jml there going to the first bank and returning to the jsr area.Therefore: emulation code in bank one, patched PRG in bank 2, and original PRG in bank 3.

Edit:Maybe I do not need to use two PRG banks, I use one patched PRG bank with jumps to code in the snes ram instead of a BRK #Code, NOP.The patch would replace lda $2000 with something like jsr $08A0 ($08A0 in ram). And the ram area would contain the binary codes for something like:

Code:

php, pha, sta #signaturecode, jml staticRoutineAddress

It would take 8 bytes and be faster and safer than the BRK solution.And staticRoutineAddress will call the proper emulation routine given the signaturecode in A.The return would be made with a return long prepared on the stack by pulling the return address to add the bank prior to RTL.

Second edit:Each signaturecode must have his routine, therefore it will use a lot of ram like more than 200bytes. But it will fit in wram.This binary file would be created by upernes.exe, stored in the last bank and loaded at boot.

Just coded the RAM jump approach. And it seems to be much better, but nothing on screen yet. It goes to the emulation code in BANK0 and comes back to the patched PRG in BANK1. It is quicker than the BRK method.

The code in ram from patched IO accesses technique works. It takes a lot of ram (more than 200bytes) but it works. I have a problem somewhere, but it shows the title screen of Balloon fight.This should solve the jump machine problem for SMB.

The bit instruction takes ldy #$04 as operand. And because lda sets the flags again, it is like jumping over the ldy instruction.But when I disassemble the shit, my program gets confused when it finds a jump to the MoveSpritesOffscreen label becaus it is like jumping in the middle of an instruction.I should use an alternative path to handle it. However because I patch the ROM, it is not critical.I will assume that every label after this bit instruction is not an indirect jump or an access to an IO port. And just write a warning on the console.

I'm still an idiot when it comes to makefiles, but I gave it a shot, and this is the error I get:

Code:

mingw32-make: *** No rule to make target 'init.asm', needed by 'init.o'. Stop.

I'm on Win7-64, I have the WLA files in the path, I copied my NES file to workdir, ran "convert.sh rom.nes", then "mingw32-make" and I get that error. I'm also running mingw32-make instead of make, because I have some weird old version of make.exe file in my path that I haven't bothered to remove.

First, I checked if a new fresh clone worked on my system, and it works.I use Msys2. And it is scripted a lot, the makefile is called by convert.sh and the file names are passed through the environment. The makefile takes $(ROM_NAME) as parameter.The script makes a copy of asm file from ../asm/, then calls make and finally deletes the asm files. This is why the call to make directly does not find init.asm.Convert.sh from the source/workdir/ directory should do all the work. You should find a 'romname'.fig in the directory. There is no need to call make after convert.sh. It is simpler like this, because otherwise I was sometimes editing the wrong files and compiling a mess from different roms (like running Balloon Fight with the CHR data of SMB1).

I am glad you follow the project Memblers, because I must add your APU emulator to it.

Now I must find a solution to update the nametable data quickly enough. I use a 4KB ram buffer to store the nametable data and I make a copy of it using DMA during VBlank. This is slow, I would prefer to update it when the IO port is accessed on the nes but it does not seem to work other than during Vblank on the snes. Plus, the ram method is clean. But I must find a way to update only what changed (even donkey kong is slow). Maybe with a 8bit bitmask per line x 30 lines x 2 Banks, 60Bytes of bitmask. And take profit of the DMA.

Who is online

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum