fnuecke / Circuity

Other
10 stars 0 forks source link

[RFC] API, Structure, Devices, Implementation #15

Open fnuecke opened 8 years ago

fnuecke commented 8 years ago

I'd love to get some feedback on pretty much everything in the mod at this point, but in particular the bus API and the bus controller behavior. I think it's headed in a reasonable direction that will give sufficient freedom, but my knowledge about other CPU architectures is rather limited.

Pinging @asiekierka, @iamgreaser, @ds84182, @magik6k.

If anyone else needs needs pinging, please do.

I can do a write-up of the current state and my thoughts, if you like, but that'll take a bit of time, so I'd like to see if there's interest at all, first :P

If anyone of you is interested in contributing, let me know, and I'll probably just give you push access to the repo.

fnuecke commented 8 years ago

FWIW, if you want to do some messing around with it as it is now, here's the files I've been testing with: https://gist.github.com/fnuecke/c9d28e9a81bf218ad6591fdbb50916b7

Using this in the CPU init code to actually load more than a few KB from an EEPROM (and not having to mess with stuff in the worlds dir :P) https://github.com/fnuecke/Circuity/blob/c33c0f65a0ce03ba532e3d202a9776f90af0bd8c/src/main/java/li/cil/circuity/common/ecs/component/BusDeviceZ80Processor.java#L83

iamgreaser commented 8 years ago

You will need to remap as per this commit: https://github.com/fnuecke/Circuity/commit/0f5407940856110260422ea659af33dd7f256a32

I think this is the new mapping:

__sfr __at 0x000A DeviceAddress2;
__sfr __at 0x0009 DeviceAddress1;
__sfr __at 0x0008 DeviceAddress0;
__sfr __at 0x000D DeviceName;

0x0004 through 0x0007 would be a good place to put a 4-char device ID, and I've freed up the space there for that purpose.

Also, for "Reset device name pointer", would it make more sense to have it as a write strobe instead of a read strobe? If that approach is taken then it could share an address with DeviceName.

As for detecting bus conflicts I'll probably put that puzzle on hold for now.

On a side note, for the Z80, do we really need to read the upper address byte for the I/O bus? I believe it should be ignored, as otherwise doing OUT a, (0x20) is going to write to I/O address 0x2020, not 0x0020 as the code currently does, and it also screws up the ability to use OUTI/OUTD/OTIR/OTDR properly. (EDIT: I am now taking the liberty to make this correct AND mask out the upper address byte.)

ds84182 commented 8 years ago

Hmm, what about the possibility for different bus bitwidths? 8-bit writes on ARM are extremely weird (since memory is handled as 4 bytes together instead of 4 sets of bytes to increase memory bandwidth) and unaligned reads are processor specific (and even today with armv7 an application can crash due to unaligned memory accesses).

fnuecke commented 8 years ago

Also, for "Reset device name pointer", would it make more sense to have it as a write strobe instead of a read strobe? If that approach is taken then it could share an address with DeviceName.

I don't know why I didn't do it that way in the first place... yes. Definitely.

On a side note, for the Z80, do we really need to read the upper address byte for the I/O bus?

It's an artifact of mapping the IO bus to 0x1????. I'm not even sure if I like for that to stay that way, or rather have some way to support multiple address spaces. It just worked for the time being :P

Hmm, what about the possibility for different bus bitwidths?

Absolutely. Also see #11 (and #12 for that matter). Though for memory mapped 32-bit someone will need to provide an efficient way to do that. The mapping right now only can go up to 20-bit (well, more precisely I don't want it to go higher, because it's just an array mapping every possible address to its device, and it'd use more memory than I'm comfortable with otherwise).

iamgreaser commented 8 years ago

By upper address byte I mean what the bus controller gets for A15-A8. The bit above that is fine (IORQ -> A16).

Though for memory mapped 32-bit...

My MIPS3 implementation supports up to 36 physical address bits (and 40 virtual, but the bus controller does not need to care about that in the slightest), and can do 64-bit reads/writes. Consider longs.

Speaking of MIPS, which of these would you rather I did right now?

fnuecke commented 8 years ago

Ah, you mean it passing along BC instead of just C? Hmm. I think I remember reading the Z80 actually did put both on the address bus, but typically only the lower byte was used? In that case adding a mask to the access wrapper seems like a good place to filter that out, possibly make it configurable via the component (where it's instantiated).

Longs... sure. Not that it can technically be fully used (because computers sadly aren't bigger on the inside), but it'll make for good future-proofing. I'll just do a quick performance test first, tho (zexdoc before and after I guess), because if longs would make everything significantly slower, that'd kinda suck.

MIPS: push it to master, I'd say, then any refactors I might make won't generate unnecessary busywork for you. Also yay!

iamgreaser commented 8 years ago

BC vs 0C

The Z80 does typically pass both along the address bus, even though this is undocumented behaviour. It also duplicates the immediate address byte for immediate IN/OUT ops. There's a patch applied to ioRead/ioWrite (or whatever they're called) which masks out the high byte.

On a tangentially related note, we can always pretend that the DRAM refresh feature isn't a thing. We aren't trying to recreate the ZX80/81 here ;) (honestly, that was one of the most gloriously disgusting hacks ever)

long physbits

You'll never fill all those addresses, but with a flexible bus controller you could map some RAM or devices into addresses outside of a 16-bit/20-bit/24-bit/32-bit/36-bit/48-bit address range if you want to keep it out of range of those specific kinds of CPUs, and to keep it in range of CPUs which would benefit.

performance test

I don't think it'd be significantly slower (after all, instruction decoding is going to be notably slower than a few 32-to-64 sign-extensions) but still, check the speed anyway.

MIPS: push it to master

Done.

fnuecke commented 8 years ago

masking in ioRead/Write

Allright then. I might still move it to the access wrapper if there's not strong reason not to (is there?), just because I feel it'd be more logical to place it there. Yes/no/maybe?

DRAM refresh feature

I don't even know what that means :P

longs

Pretty much everything uses longs now; except local addressing. Unless there's a sane use-case where any single device would need more than INT_MAX addresses? Then that could also be changed. Just seems more... practical for most cases (e.g. no need to cast to int in the device implementation when using it to index an array like RAM does).

performance

Yeah, no measurable difference at all. Pretty much expected, but I was curious ;)

iamgreaser commented 8 years ago

It should be fine to put the I/O masking into the access wrapper. So yeah, go ahead.

The DRAM refresh feature: after spending I think 2 clocks in the M1 cycle actually fetching the op (M1 + MREQ + RD asserted), it spends another 2 cycles doing a DRAM refresh (RFSH asserted, not sure what else), and then increments the lower 7 bits of the R register (the top bit is unaffected). Considering that in a real system this can be filtered out, we can pretty much ignore it.


As for local addressing still being ints... I'd still make those longs just for consistency. I'm not sure if I can introduce a particularly good argument for actually utilising this w/o bringing up a multi-CPU scenario (the argument that you might just want to put some stuff into high memory so certain CPUs can't reach it).

I see the argument surrounding longs for addresses this way:

Yes, 32 address bits should technically be enough, but it's a cheap upgrade to just provision for 64. And hey, maybe some crazy bastard will decide to make 1048576 RAM blocks just so their computer can have 4GB. Maybe we should allow that to be possible. (Server admins: You do check before letting people play in creative, do you? Also could be worth having a "max amount of RAM" config option. Which we should just set to 64GB to make people remember to change it.)

The extreme end of the scale would require a lot of blocks, and I suspect that if you had that much RAM you could boil the oceans. And of course, Java not having native 128-bit types would mean that going one step further than 64-bit would also be very very cumbersome.

So I suspect we'd all agree that going above 64 physbits is a bad idea. Although I'd still argue for 62 being the absolute maximum for a maximum, just so you don't get nasty sign-related issues.

fnuecke commented 8 years ago

Hrm. Will see. My main reason for hesitating isn't really that it's "too much" or such, rather that it's potentially annoying having to cast the longs to ints all the time, with no-one actually needing the longs :P But then again, I suppose one could just make a super-class that does the casting once...