I have found over the years that except in speed-critical or multi-master applications, it's actually easier to bit-bang an I2C master than to try to use the I2C facilities built into many chips.
Note that if a device uses clock stretching, any time you release SCK, you must wait for it to actually go high. For simplicity, such delays are omitted from the following descriptions, but should be included if appropriate in your "release_SCK()" routine.
To start an I2C transaction, release SCK (if it isn't already) and, if the data line is low, assert SCK (drive it low), release SDA (if it isn't already), and release the SCK. Repeat this process up to nine times until SDA is high. If SDA is still low after nine repetitions, the bus is unusable.
To output each byte (including the address byte), assert SDA, and then for each bit repeat the sequence (assert SCK; set SDA high or low to match next bit of data; release SCK) eight times. After the last bit, assert SCK, release SDA, and release SCK. If SDA is low, a slave is acknowledging; if SDA is high, no slave is acknowledging and the transaction should be aborted.
When all output is complete, assert SCK, then SDA, and then release SCK, then SDA.
To input each byte, assert SDA, then release SCK if it isn't already (it will be for the first byte, but not others). Then reassert SCK, release SDA, and repeat the sequence (release SCK, read data bit, assert SCK) eight times. Note that at the end of this sequence, unlike when outputting a byte, SCK will be left asserted.
When all input is complete, release SDA (it should already already be released) and SCK.
Note that because the clock is left asserted after inputting each byte, it's not necessary to specify whether the byte should be ack'ed or nak'ed. If you read another byte, the last byte read will be nak'ed. If you terminate the read, it will be nak'ed.
Start; send address; write one byte, finish
SCK - -__-__-__-__-__-__-__-__-__-- -__-__-__-__-__-__-__-__-__--- -__--
SDA(M) - __777666555444333222111___--- --777666555444333222111000---- --__-
SDA(S) - -------------------------??AA A------------------------??AAA A----
Start; send address; read two bytes; finish
SCK - -__-__-__-__-__-__-__-__-__--- -__--_--_--_--_--_--_--_--__ -__--_--_--_--_--_--_--_--__ _-
SDA(M) - __777666555444333222111------- __-------------------------- __-------------------------- --
SDA(S) - -------------------------??AAA A??77?66?55?44?33?22?11?00?? -??77?66?55?44?33?22?11?00?? ?-
I put on my teacher/professor hat.
your text mentions an 8Kb RAM, your diagram shows 16Kb.
your ROM has 32 locations, hence it needs more than the 2 address lines you connect to it. Even if you intend to connect some lines to a fixed value, you should how that.
the question explicitly asks for the PROM content, which you don't give. Yes, it is a 32x8 table of 1's and 0's, but the point is which value you put at each location! You won't need to specify all of the 32x8 locations.
I suggest you draw yourself a memory map. The smallest item you must map is 8Kb, so how many blocks will it have to cover 64Kb? How many address lines are involved in selecting one block? If less than the number required by the ROM, what are you going to do with the others? For each block, note the value of those address lines, and the value of the two select output bits. Now it is almost trivial to write out the content of the PROM. It will contain a lot of "don't care" bits.
Side note: only archaeologists make such systems from separate chips these days, and even micro*controllers* are switching from 8 bit to 32 bit. But the design of something like this is still a good test of your general knowledge of digital logic.
Best Answer
If this is the whole code and not a pseudo code trimmed for this post, it is clear that you have a problem with newlib implementation.
The quick solution is making your own macro using clock()