|
Nice ideas. I have experimented myself a bit with an extended ISA. Here are some of my thoughts:
The number of possible additional instructions is not that small: 3*2^13=24,576 (100, 101, 110 prefixes) - not taking into account the unspecified ALU combinations, which would complicate the decoding significantly. If that is not enough, you can go with variable instruction length and use one or more bits of your new ISA to indicate instructions consisting of more then one 16-bit word.
I'm not sure why the one instruction per cycle should be a requirement. In fact, if you implement the memory with an SDRAM controller, this will be hard to maintain. Even if the internal memory blocks of the FPGA are large enough to hold the whole ROM, RAM and VRAM, you will run into issues here:
AM=M+1
D=M
(You need to write the ALU value from M+1 to the "old" address of A while the next read cycle requires the new address). Unless you add complex write-back caches this will likely and frequently result in a wait-state. I don't see a problem here, though.
The most relevant hardware extension from my perspective would be a simple interrupt process and some timing information (i.e. a memory-mapped cycle-count or a hardware clock). For an interrupt driven mechanism, the CPU would need to add functionality to save the state (interrupting to a handler at a certain system-defined address will change the program counter). The old PC must be saved somewhere. Same applies at least to the A-register, because it cannot be saved by the interrupt handler without destroying A or D. The best would probably be to keep them inside the CPU in separate registers until some IRET instruction is executed. Or you go for a micro-coded approach and push everything to the stack.
To run multiple programs, this is not required though in theory, if you go for cooperative multitasking and/or a software-based approach (assuming that the memory is sufficient for all programs...) A purely OS-based idea to implement this could be to extend the convention of your OS so that every routine of the Hack OS will call a (assembler-coded) task-manager routine before returning which updates an internal counter and after a threshold has been reached switches to another task (switching the context, specifically maintaining different stacks). This requires that programs need to ensure that they call OS routines frequently - though I guess that is very likely the case anyway since even multiplication will result in such a call.
Memory protection and more addressable space is probably best to be solved with some kind of bank switching mechanism. Making the instruction are writable (RAM) would make the Hack computer more of a Von-Neumann-Architecture instead of Harvard. That's nice to have, but not absolutely necessary. If you stick to 32k x 16-bit for "ROM" and RAM, you could address the ROM by using bit 15 (requiring 2 Hack instructions to load A though). To bypass the Harvard-Architecture restrictions, you could also just implement an interpreter/emulator in the ROM, that executes code from the RAM. I have implemented a simple BASIC interpreter which effectively does that.
Byte addressability and lack of shift routines are indeed a bit nasty, but couldn't you map individual bytes from I/O devices to different addresses, just wasting the upper 8 bits for each?
If you are thinking about extending the ISA anyway, how about hardware commands for MUL/DIV, SHL/SHR and also adding some hardware registers? I did that with a simple micro-coded approach - slow, but working; similar to the 70s/80s CPUs like the 8088.
Or you go directly for RISC-V ;-)
|