2020-01-04: MemAccess wiring bug fixed: JSRg instruction now works
What to do with direct addressing modes?
There are two of them: local and global, local meaning only a page of 256 word is accessible, while global instructions can access any memory location, with a penalty of instruction being 2 words long and takes 1 clock cycle longer to execute.
As jumps are used fairly frequently (in integer calculator they are encountered once per 5-10 instructions), leaving out the local instructions will bloat code 10 to 20%, and slow the execution by somewhere near 5% in terms of clock counts (this should be measured, for now it is a guess after looking at the code).
But these local jumps and load/stores are real pain in the ass when the program exceeds 256 words in length, because one should be careful that all of them are restricted to their local page and not try to reach adjacent one, as this will surely fail.
If to make a more sophisticated assembler, which will automatically check for this locality, and automatically choose global or local memory access/jump, this will make the assembly a highly iterative process -- as these kinds of instructions are differing in length, each change will affect all the addresses and alignment of the following code.
PC-relative addressing -- not appealing.
Making these local references to be PC-relative rather than absolute will ameliorate the problem slightly, but this is not solving the issue with changing code length and jump/memory access lengths in the process of adjustment.
Padding with "holes", with saving the page alignment -- this might actually be of some use.
Part of the solution would be to make holes in code, so parts which fit inside one page would have all internal references local, while references to other parts of program would be global. If the part of program is not taking up the full page, all the rest locations will be filled with zeros until the start of new page. Such padding would be quite a waste of memory space, but will offer slightly faster execution without complications caused by shifting code across page boundaries.
Thoughts on byte addressing
This starts to seem inevitable that byte addressing should be added. This will ask for hardware update, so special instructions for byte loads and stores could be done (memory addressing circuitry mainly, but also changes to memaccess decoder), as well as update to the assembler.
Right now the machine is happily working in word addressing mode, but this seem only good for number crunching; while working with characters had not yet been explored. This now seem that it could bite me in the ass in the future.
Byte addressing is implemented.
Simulation now in its version 5.0
Version incremented due to addition of new functionality -- namely, byte addressing.
Comment by Ken Yap regarding lack of byte addressing provoked thoughts on this topic. Although in my reply I wrote that this seems to be of no big consequence, afterwards I started to think about this deeper. So far I am implementing a calculator program, and it cannot care less if byte addressing is present or not, as it works with words. But to make programming for other problems easier on this computer, adding byte addressing seemed better and better idea. There are thoughts of implementing C compiler for it in some distant future, and it is the kind of thing which would benefit from ability to address individual bytes.
So, as of right now, I implemented it. On one hand, this was not as difficult as I thought it would be. On the other hand, some sacrifices were made (not that these were real): total addressable memory has been reduced at least 4 times: first, halved because now addressable unit is 8-bit byte instead of 16-bit machine word; second, I need additional bit in instruction word for loads and stores to indicate that I want load or store individual byte (and there were no available bits in high half of instruction). So, instead of possible 16MWords (32MB) I now can only address 8MB of memory directly. On the other hand, at least for now, I don't think there will be need for more. But if such need arise, in some far future time, the solution will be found. Right now my calculator program is just over 1kB in size.
Addition of byte addressing, and particularly, of the ability to manipulate individual bytes, have lead to thoughts in other direction: maybe add ability to load/store and push/pop multiple words in one instruction? Especially push/pop entire register file, all 8 registers in one instruction. This will be neat capability, when used in conjunction with subroutine jumps and interrupt service routines.
For this implementation following changes were made:
As Program Counter and Stack Pointer are implemented as actual counters, to make them increment by two instead of one, bus was shifted on them, so the least significant bit bypasses the counters and is not affected by counting. This least significant bit of address is ignored on most instructions except in byte loads and stores.
The memory subsystem was redone as 8-bit units. The ROM is 8-bit, and RAM is two 8-bit elements. Circuitry for optional single byte selection was added.
Memory access operation decoder was augmented slightly to accommodate single-byte loads and stores. Now, single-byte directly addressable stores and loads are possible, as well as byte stores/loads using register and register-memory indirect modes.
Assembler: the addresses now calculated taking into account that individual bytes are counted. The output now produces a column of 2-digit hex numbers, instead of 4-digit ones, so as to fit in ROM with 8-bit data output.
The simulation, version 5 is added to files.