Thinking about making an NES Z-Machine

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Thinking about making an NES Z-Machine

Post by FrankenGraphics »

nocash wrote:And MMC5 might be more common & more widely supported for large memory. But either one should be fine for getting started.
Quoting INL:s shop page:
Mapper 5: MMC5 ExROM
A simplified version that supports large memories of MMC5 may be possible with current boards. Full fledged version pending an entire new PCB design.

So not quite as readily available as MMC1. Either way, you could ask for a quote.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Thinking about making an NES Z-Machine

Post by lidnariq »

The full MMC5 is much more than you need, but a subset that just handles banking of PRG RAM should be cheap.

The only downside to targeting an MMC5 subset is that a third party seeking to make a hardware reproduction may think they have to destroy an original cart instead.

So either way, set it up so that the part of your code that deals with the cartridge hardware can be easily replaced. Novel hardware can easily be designed once you know everything you need.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Thinking about making an NES Z-Machine

Post by Pokun »

halkun wrote: Oh and text input would either use the NES keyboard, or an on screen equivalent.
Both software keyboard and the Family BASIC keyboard support would be desirable (and maybe Subor keyboard for famiclone people). Family BASIC keyboards are common and dirt cheap nowdays, but NES people would need an ENIO-like adapter.
zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

Re: Thinking about making an NES Z-Machine

Post by zzo38 »

I have worked on Famicom Z-machine implementation some time ago, although I have since stopped (I have not bothered to install the software on this new computer, which is Linux rather than Windows). Here is a link to some further information: http://wiki.nesdev.com/w/index.php/User ... _Z-machine Maybe some of this might be found to be useful for your NES Z-machine.
(Free Hero Mesh - FOSS puzzle game engine)
halkun
Posts: 45
Joined: Mon Jul 18, 2011 10:04 pm

Re: Thinking about making an NES Z-Machine

Post by halkun »

Neat! Another Z-machine to poke at!

I've got my environment almost set up. I'm going with a SXROM but having issues getting an emulator to take my header.
I'm going with a 512K PRG-ROM with 32K PRG-RAM and an 8K CHR-ROM

My header looks like this

Code: Select all

.byte "NES",$1A			; "NES"^Z
.byte $20               ; 4 - ines prg  - Specifies the number of 16k prg banks.
.byte $01            	; 5 - ines chr  - Specifies the number of 8k chr banks.
.byte %00010001  	    ; 6 - MMC1 and vert mirror 
.byte %00001000			; 7 - nes2.0 header 
.byte $00  				; 8 - ines map  - Specifies the NES mapper used.
.byte $00 ; flags 9
.byte $00 ; flags 10
.byte $00 ; flags 11
.byte $00 ; flags 12
.byte $00 ; flags 13
.byte $00 ; flags 14
.byte $00 ; flags 15
and my nes.ini config file I'm feeding into ld65 with -c looks like this.

Code: Select all


MEMORY {
  ZP:     start = $0, size = $ff, type = rw;
  HEADER: start = 0, size = $0010, type = ro, file = %O, fill=yes;
  RAM:    start = $0300, size = $0500, type = rw;
  ROM00:    start = $8000, size = $4000, type = ro, file = %O, fill=yes, fillval=$FF;
  ROM01:    start = $8000, size = $4000, type = ro, file = %O, fill=yes, fillval=$FF;
  ROM02:    start = $8000, size = $4000, type = ro, file = %O, fill=yes, fillval=$FF;
  (They repeat here... you get the picture)
  ROM31:    start = $C000, size = $4000, type = ro, file = %O, fill=yes, fillval=$FF;
}

SEGMENTS {
  INESHDR:  load = HEADER, type = ro;
  ZEROPAGE: load = ZP, type = zp;
  BSS:      load = RAM, type = bss, define = yes, align = $100;
  DMC:      load = ROM31, type = ro, align = 64, optional = yes;
  CODE:     load = ROM31, type = ro, align = $100;
  RODATA:   load = ROM31, type = ro, align = $100;
  VECTORS:  load = ROM31, type = ro, start = $FFFA;
}

FILES {
  %O: format = bin;
}
I also have a 8k char file (It has the text) I append to the end of the .NES file with a copy /b command
Both NO$NES and FECUX are telloing my header is invalid
What's the proper format?

Also is there a way to "include" my char rom at compile time so I don't need to append it with a copy command afterwards?
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Thinking about making an NES Z-Machine

Post by lidnariq »

halkun wrote:32K PRG-RAM
[...]
.byte %00001000 ; 7 - nes2.0 header
.byte $00 ; 8 - ines map - Specifies the NES mapper used.
.byte $00 ; flags 9
.byte $00 ; flags 10
You're not succeeding at making the right header there
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Thinking about making an NES Z-Machine

Post by tokumaru »

You need to specify the amount of PRG-RAM (i.e. WRAM). Also, I don't think SXROM was ever used with CHR-ROM in commercial releases, so emulators might be rejecting your ROM for not using a standard configuration. Try with CHR-RAM (i.e. 0 CHR-ROM pages) and set the size in byte 11 to see if that changes anything.

As for including the CHR file during assembly time, sure, you can use the .incbin directive, but you have to create the corresponding MEMORY and SEGMENT definitions in your config file to hold that data. Not that you'd be doing this for CHR-RAM, of course.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Thinking about making an NES Z-Machine

Post by koitsu »

halkun wrote:I also have a 8k char file (It has the text) I append to the end of the .NES file with a copy /b command
...
Also is there a way to "include" my char rom at compile time so I don't need to append it with a copy command afterwards?
Example for 2 CHR-ROM banks:

Code: Select all

ld65 config:

MEMORY {
  ; ...all your existing stuff (ex. ZP, RAM, header, PRG banks)...
  ;
  CHR00:     start = $0000, size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
  CHR01:     start = $0000, size = $2000, type = ro, file = %O, fill = yes, fillval = $00;
}
SEGMENTS {
  ; ...all your existing stuff...
   CHR00:    load = CHR00, type = ro, define = no;
   CHR01:    load = CHR01, type = ro, define = no;
}

somewhere in your code (ex. main.asm or whatever):

.scope CHR00
	.segment "CHR00"
	.incbin "chr00.chr"
.endscope
.scope CHR01
	.segment "CHR01"
	.incbin "chr01.chr"
.endscope
You can omit the .incbin line if you want to make a CHR bank filled with nothing but zeros (i.e. placeholder for future CHR files); the ld65 config will take care of filling the space with zeros (fill = yes, fillval = $00).

It's still up to you to make sure your header etc. refers to the correct number of CHR banks (should always be a 2^n number, ex. 1, 2, 4, 8). Same goes for PRG. fillval = $00 or fillval = $ff can be used (I recommend the former for debugging/testing, then before final release switching to the latter (to be nicer on EPROM/EEPROMs) but it really doesn't matter since people aren't making mask ROMs of homebrew).

If your mapper uses a CHR-ROM bank size that differs from the 8KByte header size (ex. MMC3 using 1KByte or 2KByte CHR banks), then things get a bit more complicated. There's multiple ways to solve this, but I'd suggest keeping size = $2000 (to ensure the resulting ROM file gets 8KByte CHR, per the header requirement), then using multiple .incbin statements within the appropriate scope/segment area. You may have to refactor the code a little bit here if you want to dynamically calculate CHR bank number. Others here might have some advice on how to do that; if their recommendation differs from mine, follow what they say instead.
halkun
Posts: 45
Joined: Mon Jul 18, 2011 10:04 pm

Re: Thinking about making an NES Z-Machine

Post by halkun »

Cool, I got the CHR-ROM appended, but it's still rejecting my header

Code: Select all

.byte "NES",$1A			; "NES"^Z
.byte $20               ; 4 - ines prg  - Specifies the number of 16k prg banks.
.byte $01            	; 5 - ines chr  - Specifies the number of 8k chr banks.
.byte %00010011  	    ; 6 - MMC1 and vert mirror + SRAM
.byte %00001000			; 7 - nes2.0 header 
.byte $00  				; 8 - ines submap.
.byte $00 ; flags 9
.byte %0001001 ; flags 10  ; 10 - 32K PRG-RAM
.byte $00 ; flags 11 
.byte $00 ; flags 12
.byte $00 ; flags 13
.byte $00 ; flags 14
.byte $00 ; flags 15
When I run the NES Mapper program, I get this...
Image
So it looks OK....

and the error I get in FECUX is "FDS BIOS ROM image missing"
no$NES say "invalid cartridge header" and just exits
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Thinking about making an NES Z-Machine

Post by tokumaru »

One inconsistency I see there is that you marked the battery-backed WRAM bit, but the amount of battery-backed PRG-RAM below is 0. Do you need it to be battery-backed or not? Either clear the battery bit or specify the 32KB of PRG-RAM as battery-backed.

That being said, I find it very weird that FECUX brought the FDS into this...
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Thinking about making an NES Z-Machine

Post by koitsu »

Do NO$NES and FCEUX support NES 2.0 headers? FCEUX will throw said error message if the NES header is omitted or ROM identifier string is wrong.

That said, I notice this in your screenshot of whatever that GUI tool is:

CE C5 D3 1A 20 01 ...

Those first 3 bytes are not "NES" (that would be 4E 45 53), and they're outside of the ASCII range -- all of your string-based bytes have bit 7 set for some reason! However, they are all the "correct deltas" from one another. Could this potentially be a locale/code page/character set problem, where string "NES" is somehow being moved into a non-ASCII region? I clearly see .byte "NES",$1A in your code, but obviously something is stomping over that with some other data, or something is being assembled oddly.

Try replacing .byte "NES",$1A with .byte $4E,$45,$53,$1A and see if that helps. I bet it does. If it does, you're going to need to figure out what's causing this oddity (setting bit 7 of your strings), as that's probably going to cause you problems.

Other oddities I see:

- MEMORY section, ZP: size = $ff is wrong, ZP is 256 ($100) bytes, not 255 ($ff) bytes.
- MEMORY section, RAM: start is at $0300, while actual RAM starts at $0200 (and is thus $600 bytes in size). If this is intentional, then ignore this
- SEGMENTS section, HEADER: try adding align = $10

I would also suggest, when linking your program with ld65, using -m map.txt and then looking at its contents when finished. e.g.:

Code: Select all

ca65 main.s
ld65 -C ld65.cfg -m map.txt -o game.nes main.o
Last edited by koitsu on Sat Feb 02, 2019 11:12 pm, edited 1 time in total.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Thinking about making an NES Z-Machine

Post by lidnariq »

koitsu wrote:Those first 3 bytes are not "NES" (that would be 4E 45 53)
... revenge of PETSCII.

https://forums.nesdev.com/viewtopic.php ... 24#p233224
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Thinking about making an NES Z-Machine

Post by koitsu »

lidnariq wrote:
koitsu wrote:Those first 3 bytes are not "NES" (that would be 4E 45 53)
... revenge of PETSCII.

https://forums.nesdev.com/viewtopic.php ... 24#p233224
Ah ha. So it sounds like further CPU configuration is incorrect in the assembler. Would .setcpu "6502" at the very top of the main code (i.e. before the header segment) rectify this? The ca65 documentation implies doing this can "override" whatever -t/--target is, which defaults to none but maybe not in this case? -t nes would ideally work too, I think. The OP has not reported what arguments they're using to ca65/ld65.

Edit: oh, I see. cl65 defaults to a target type of c64, which I think would cause this problem (see PETSCII chart); while ca65 defaults to a target type of none. I didn't know cl65 was being used here. Best to use -t nes to either utility.
halkun
Posts: 45
Joined: Mon Jul 18, 2011 10:04 pm

Re: Thinking about making an NES Z-Machine

Post by halkun »

It was the PETSCII - I got no$nes to load the file (FCEUX - not so much, but it's a start) Sadly, that means the .byte psudo-op is useless for text
I can't use -t nes because I'm using -C for my config file and you can't use both at the same time. I could simply put the CHR-ROM in PETSCII order, but I'd much rather use ASCII
Also, no$nes sees all 512KB of PRG-ROM, but not too sure on the PRG-RAM, I may need to tweak the header further.

==EDIT==
cl65 does allow "-t none -C file.ini" at the same time and I have my precious ASCII table back.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Thinking about making an NES Z-Machine

Post by tokumaru »

You can also use the .charmap directive to map the characters however you want.
Post Reply