Merged
Merged
Prof. P. K. Biswas
Department of Electronic and Electrical Communication Engineering
Indian Institute of Technology, Kharagpur
Lecture No. # 18
Cache Memory Architecture
So, today we will discuss about the cache memory organization. Till the last class we have seen
that main memory is organized either in the form of pages or in the form of segments or if we
want to take advantage of both, the segmentation as well as paging in that case the main memory
organization that is used is paged segmented memory organization. And we have seen that what
are the advantages of different schemes in case of paged memory management or segmented
memory management or in case of paged segmented memory management. However, if you
think in depth, you will find that whichever memory architecture you use, for accessing any
particular memory location that means whenever the CPU generates the address of any memory
location. Firstly, using that address you have to check either the segment table or the page table
or the segment table and page table both in case of paged segmented memory organization
before you actually reach the physical address in the main memory.
So, naturally the question comes that if we store the page table or the segment table or both in
main memory itself in that case for every access to the main memory, we have to have one or
more additional memory access before we get the actual physical address of the memory
location, the data or the instruction from which is actually required by the CPU. So effectively
the memory access in such cases will be very slow. So we have to think of an alternative where
we have can have faster access to memory and that is what is given by the cache memory. In
case of cache memory, you get advantage in two ways. Firstly, the cache memory is
implemented using the static RAM, unlike the main memory which is implemented with the help
of dynamic RAM.
The reason being, in any system we desire that the amount of main memory should be quite large
compared to the cache memory then comes the cost involved. If we want to implement
everything with the help of static memory, the static memory is very costly compared to the
dynamic memory. So in a system if we want to have say 512 megabyte of main memory and
everything in the form of static RAM then the system cost will be very high. So instead of going
for that what is done is, when you implement the main memory, you use the dynamic RAM to
implement the main memory whereas you implement the cache memory which is much much
smaller in size compared to the main memory and the cache memory can be implemented with
the help of static RAM. So access time in case of static RAM is much less compared to that in
case of dynamic RAM but the static RAM is costlier than the dynamic RAM.
So firstly you get advantage because of the fact that cache memory is implemented with the help
of static RAM, which is faster compared to dynamic RAM and secondly you get speed
advantage because of the architecture of the static RAM or the architecture of the cache memory.
So let us see what is this cache memory and what is its architecture? When we talk about cache
memory, the cache memory can have three different kinds of architecture.
1
(Refer Slide Time: 00:04:35 min)
The first kind of architecture we can have is an associative cache memory, second kind of
architecture that can be used is called direct mapped cache and the third kind of the cache
memory that we can have is called a set associative cache. So firstly, we will consider, what is
this associative cache? The concept of cache memory is similar to the paging concept that we use
in case of the main memory. We have said that when we discussed about the demand paging or
virtual memory management, that only the page which is currently active if that resides in the
main memory then it is sufficient to execute the program. The other pages can be brought from
the secondary storage to main memory on demand or as and when it is required. So the name
came as demand paging or virtual memory management. When you talk about cache, the concept
is something similar.
Here the main memory is divided into a number of blocks may be a page or a segment will be
divided into a number of blocks. So whenever we want to transfer anything from the main
memory to the cache memory, the entire block will be transferred to the cache memory, say
block size may be say 8 bytes or 16 bytes or 32 bytes and so on. So naturally the block size is
much less than that in case of a page or the size of a segment. So this block is a superimposed on
the paging. So may be a particular page in the main memory is divided into a number of blocks.
This block division is actually done to enhance the caching, to facilitate the caching option.
Now whenever the CPU generates an address, we can say that the address is actually divided into
two fields. One field will be the block number and the other field will be identification of the
byte within the block. So as I said that whenever I want to transfer anything form the main
memory to the cache memory, one of the blocks or the entire block will be transferred to the
cache memory. So accordingly the cache memory will also have a number of blocks where the
block size is same as that in the main memory. So if we say that every block will contain 8 bytes
then in the cache memory also we will have a number of blocks where every block will be of 8
bytes. So that whenever I transfer any block from the main memory to the cache memory, the
2
entire block can be transferred to one block in the cache memory. And along with every block in
the main memory has to be identified by this block number, the block number field.
So if we assume that we have a machine whose address line is 16 bits then and I want that every
block should be of 8 bytes that means out of though 16 bits, 3 bits will be used for block, for byte
identification and the remaining 13 bits will be used for block identification. So using these 13
bits you identify one of the blocks within the main memory and using this 3-bit address, you
identify a particular byte within that 8-byte block. Now whenever I transfer a particular block
from the main memory into one of the blocks in the cache memory and I want to search for a
particular byte in the cache memory whether the requested byte is present in the cache memory
or not, in that case what I have to see is I have to check for this block number whether a block
having this particular number which is given by this 13 bit address lines is present in any of the
cache blocks or not, which means that in the cache memory, I have to have another fields or
some additional locations which will contain this block number.
So if I have say n number of blocks in the cache memory, I have to have n number of additional
entries, where every entry in this particular case will be 13 bit. So in this case I will have n
number of additional entries where every entry will have 13 bits and in this case, this 13 bit or
block number is called the tag field and the part of the memory in the cache architecture which
contains that tag field is called the tag memory. See what I have said is I am assuming that I have
a machine which is 16-bit address, which gives 16-bit address. So if I have a 16 address in that
case with the help of the 16-bit address, I can address a main memory of maximum of 2 to the
power 16, that is 64 KB. This 64 KB of main memory is divided into a number of blocks where
every block of 8 bytes, that means I can have 8 k number of blocks where every block will
contain 8 byte so total gives you 64 KB.
Now suppose the CPU generates a physical address of say some physical address. The physical
address is given by 16 bits of the main memory. Now first we will try to check whether that the
data of that particular address is available in the cache memory or not, right? So if I want to see
whether that data is available in the cache memory or not, how do I check? I know that the data
will be available in the cache memory in the form of a block. A particular byte, the block to
which that byte belongs, the entire byte should be available in the cache memory, either the
entire byte or none. So we try to check that whether the block containing that byte is available in
in the cache memory or not. So how do I check? I check the block number as I said that the main
memory address which is generated by the CPU is divided into two fields, the block number and
the byte within the block. I will check whether this block having the particular number as given
by the address lines is present in the cache or not. That means along with this cache memory
which contains the block, I have to have additional memory which will contain the block
number.
So if I want to load in some cases a 0th block from the main memory in the cache, the block
number of the 0th block will be zero, that means all these 13 bits will be 0. So if that zeroth block
is loaded in the first block in the cache memory then the first tag memory locations will contain
value 0. So you see how it is coming. The first memory address here is 0, 0, 0, 0, if I put it in the
form of hexadecimal number. the last byte that is 8th byte within this block will have a physical
address of 0, 0, 0, 7 and block address is 0, 0, 0 because you find that out of this, this is a 16-bit
3
address, out of this the more significant 13 bit gives you the block address. The least significant
3 bits gives you a particular byte within this block. So that is how these fields are been broken,
right? When I come to the next block, the starting location of the next block will be 0 0 0 8. Is it
okay? So this is the block address of the second block. Whenever this block is to be loaded into
cache memory, the data contained in this block will be in the cache part and the block address
will come to the tag memory, right? That means for every block in this cache memory, I have to
have a corresponding tag memory. The number of bits in the tag memory will be same as the
number of bits in the block number field of the address, right? Sometimes each of these blocks
in the cache memory is also called a cache line. A cache line means a block of the main memory.
So these 8 bytes taken together is also called a cache line, it’s a block in the cache or it’s a cache
line.
Now in addition to this, I also have to have an information that whether the content of a cache
line is valid or not. That means I have to have what is called a valid bit. So whenever you place
any block of the main memory into any of this cache blocks, then immediately what I have to do
is, I have to fill up the tag memory with the block address and at the same time, the valid bit of
the corresponding cache entry has to made equal to 1. it will be clear later. So initially you find
that when there is nothing in the tag memory, all the valid bits will be equal to 0. Now why this
valid bit is needed is because of the fact that tag memory can have any garbage value.
Now following some address generated by the CPU, if I want to check whether there is any tag
memory location which matches with this block number or not because of the garbage value is
contained in that cache tag memory, maybe I will get false match. But whether this is actual
match or a false match to identify that I need this valid bit. So initially all the valid bits will be
equal to 0 indicating that the cache memory does not contain anything that means even if I get a
match in the tag memory field, that is invalid. So only when I place something in the cache
memory and set the tag memory field then only the corresponding valid bit will be made equal to
1.
4
So, now what is the checking concept that we have to do? Whenever the CPU generates an
address, I want to see whether the corresponding byte or the block containing the corresponding
byte, the required byte is available in the cache memory or not. For that what I have to do? I have
to check whether there is any bit in this valid invalid bit array is equal to 1 and the corresponding
tag field matches with the block number or not. And here any block in case of associative cache,
any block from the main memory can be placed in any free block in the cache memory or any
free cache line in the cache memory.
So if I want to check then there are two concepts, either you can go for checking sequentially
that is you take the block number, try to see whether the first valid, invalid bit equal to 1. If the
first valid, invalid bit is equal to 1 then you check whether the tag memory location matches with
the block number. If not, if they don’t match come to the second location. Again if the second
field, second bit in this valid bit array is equal to 1, you check this tag memory content whether it
matches with the block number or not that means I can go for a sequential checking. And if I go
for a sequential checking, in that case obviously if there are n number of entries or n number of
blocks in the cache memory, in the worst case I have to perform n number of comparisons. And
if I go for that, obviously my main purpose, why I am going for this cache memory is to enhance
the memory access time, to reduce the memory access time that itself will be lost. So I cannot go
for this sequential changing. So what I have to do is, I have to go for what is called parallel
checking. So instead of going for software checking, the entire checking has to be done using
hardware. So how do you do that? That is what is cache memory architecture.
So I will put the cache memory like this. On this side let me have a number of cache lines, so I
will call this as cache line or it is a block in the cache memory, so these are different cache lines.
For every such cache line I have to have a tag memory field. For every tag memory field or for
every cache line, I have a corresponding valid, invalid bit. So this is valid bit, this is tag field.
Suppose the CPU generates an address and as I said that address will be broken into two
5
components, block number and byte identification within the block. Now in this architecture we
have a register which is called an argument register. The block number which is obtained from
the CPU generated address is placed in the argument register. Then from the argument register,
the argument register is hardware wise connected to each of this tag locations, where they are
compared parallelly. So the content of the argument register will be compared with the first tag
location, it will be compared with the second tag location, it will be compared with the third tag
location and so on and this comparison will be done in parallel.
Accordingly depending upon the comparison result, I will have a bit, I will generate a bit which
is called a match bit. So corresponding to every tag entry or corresponding to every cache line, I
have to have a match bit, so this is what is match bit. So when the content of the argument
register is compared with different tag locations any particular location, any particular tag array
which matches with this content of the argument register, the corresponding match bit will be
equal to 1. Now if the match bit is 1 and the corresponding valid bit is also 1, so valid bit 1
indicates that the tag field contains a valid block address. Valid bit 1 indicates that the tag bit,
field contains a valid block address and the match bit will indicate that this tag address matches
with the block number as specified in the memory address generated by the CPU. Argument
register contains the value form the block number. It is just this block number which is placed in
the argument register.
So assuming that this particular match bit has become equal to 1, that means the content of this
tag memory location has matched with this block number and the corresponding valid bit is also
equal to 1. So what I do is I simply AND these two together. So whenever this match bit has
become equal to 1, that indicates that the corresponding cache line, say this one it contains the
block containing the requested byte. So what we do is you simply pass this through a buffer and
the buffer is to be enabled by this output of the AND gate, right? So this entire cache block or
the entire cache line will be available at the output of this buffer only when output of this AND
gate is 1. If it is 0 then this will not be available at the output of the buffer, right?
So now you find that here comes the significance of this valid bit because the tag field may
contain some arbitrary value or some garbage value because of which the tag field may give a
false match with this block number. That means the corresponding match bit will be equal to 1
but if the cache line does not contain a valid block or this tag field does not contain a valid block
number, in that case valid bit will be equal to 0. So even if the match bit indicates a false match
that will be filtered out by this valid bit. So following this, what we do is you read the entire
cache line in parallel, pass it through a selector. The selector is nothing but a multiplexer, where
the multiplex select inputs will confirm the byte identification in the memory address and output
of this multiplexer, this is the desired data which can go to the CPU.
So now find that as we said, so I can simply put this part in one block and this is another block.
So this is a set of cache lines and this is the part which contains tag, match bit and valid bit. So
we find that this is being done in parallel that means for each of this match bits, I have a
corresponding handling operation with the corresponding valid bits. So I have just shown only
one of them. The corresponding AND gate output goes to the enable input of the buffer where
the buffer input comes form, the cache line and the buffer, all the buffer outputs are connected
together. This is possible if you have this buffer as a tristate buffer. So only the buffer for which
6
the enable input is active, enable input is one, only that buffer output will be valid. The outputs
of all other buffers for which the input is low, will not be valid. The outputs will be tristated, then
only I can do directly where all the outputs of all the buffers and they are simultaneously coming
to the multiplexer input.
So only the buffer which is active, the corresponding cache line will be available to the
multiplexer input and using this multiplexer, I filter out the required byte as requested by this
address. See the match bit tells you that whether the content of the argument register that is the
block number because it is the block number which we are placing in the argument register. This
is nothing but the block number. This block number is compared with all the tag fields, with all
the tag locations parallelly. We have to have n number of comparators. If there are n locations, n
entries in the tag field we have to an n number of comparators and in this case the comparators
can be EXOR gates. Say I can have an architecture something like this.
Say this is my argument register then suppose this is a particular tag location, this is the
argument register and this is say tag 1. I want to find out whether this argument register matches
with the tag 1 or not. Then what I will do is I will perform bit by bit EXOR operation, so like this
it will continue. So I can have a number of such EXOR gates. So if they match bit by bit, in that
case outputs of all this EXOR gates will be equal to 0 and after that what we will do is you just
simply place a NOR gate. So if all these EXOR gate outputs are equal to zero, the NOR gate
output will be equal to 1. So this is what is the match bit. So I have to have similar arrangement
for all the tag locations that means for every tag location if there are 13 bits, I need 13 EXOR
gates and one NOR gate.
So if there are n number of such tag locations then I need n into 13 EXOR gates and n number of
NOR gates. Yeah, 13 input NOR gate that’s true, we have to have a 13 input NOR gate. So this
is what is needed. So obviously the circuit complexity is quite high. So in case of associate
memory, you have a flexibility that any block of the main memory can be placed in any of the,
7
sorry, main is on the other side. Any block of the main memory can be placed in any of these
cache lines. So I have flexibility but at the cost of this hardware complexity, right? So to reduce
hardware complexity, what is used is another kind of cache architecture, which is called direct
mapped cache. So if the match bits, all the match bits are 0 that indicates that there is no tag field
which is matching with that block number that is the cache miss. So the hardware complexity
will be reduced, if we use another kind of cache which is called a direct mapped cache.
So the difference between the associative cache and the direct mapped cache is that in case of
associative cache, we have said that any block of the main memory can be placed in any of the
cache lines. In case of direct mapped cache, a given block of the main memory in the main
memory can be placed only in one of the cache lines. It cannot be placed anywhere. A given
block in the main memory can be placed in only one cache memory. In case of associative cache
what we have said is suppose I want to bring in a new block from the main memory where it is
quite possible that when I want to bring in the new block, as we have seen in case page
replacement in demand paging, the similar concept is also applicable in case of cache memory.
Because I have limited number of cache memories and number of blocks in the main memory is
much larger than that of the number of cache lines that we have, cache lines or cache blocks.
So whenever I want to bring in a new block from the main memory into one of this cache lines, it
is quite possible that many of the cache lines will be occupied by other blocks. So I have to
search for a block in the cache memory which is free, where I can put in this new block. In case
of associative memory that free block can be anywhere within this cache. I can place the new
block here, I can place the new block here, I can place the new block here also depending upon
whichever is available. But when I go for direct mapped cache, given a particular block number
of main memory, where it should be placed in the cache line that is fixed. So I lose the flexibility
but the advantage is the hardware complexity is much less. So let us see what is the scheme? So
in case of direct mapped cache as I said that the main memory address which is generated by the
8
CPU is divided into two fields in case of associative cache that is block number and byte within
the block.
In case of direct mapped cache, the main memory address is divided into 3 fields. Let us give the
take the same architecture that is, 16-bit address lines. I will have 3 bits, the least significant 3
bits which will identify the byte within a given block. So for this I use 3 bits, the remaining 13
bits were used as block identification number in case of associative memory. In case of direct
mapped cache, what we do is, this remaining 13 bits is again divided into two fields. One field is
used as group identification and the other field is used as tag identification. So let us assume that
out of these 13 bits, say 8 bits are used as group identification and say 5 bits are used as tag
identification. So unlike in the previous case, where every block was identified by a 13-bit
number which was the block number. Now every block is having a two component address, its
tag number and group number.
So naturally I can place these blocks in the form of a two dimensional array because every block
is identified by a two dimensional address. So I will place it them like this, say this is block
number 0, this is block number 1, this is block number 2. So likewise this is say block number
255. So on this side I have the group identification numbers group 0, group 1, group 2, so like
this it will continue up to group 255. After block number 255, the next block that is block
number 256 that will again belong to group 0, sorry this will be 256, 257 will belong to group
number 1. Now all the blocks contained in a particular column in this two dimensional array will
belong to a particular tag, so on this side horizontally I put the tag identification. So this is tag
number 0, this is tag number 1 so like this it will continue, this is tag number 31. So whenever I
identify, the address generated by the CPU gives tag number 0, group number also 0 that means
the block which is requested is block number 0.
If it is tag number 0, group number 2 that means the byte is contained in block number 2, so like
this it will continue. Accordingly, I have to have cache blocks or cache lines, so these are the
cache lines. If I have n number of groups, I have to have n number of cache lines. So total
number of cache lines that I have to have is 256 numbered from 0 to 255. So any block which
belongs to group number 0, whenever it is to be brought in the cache memory that must be
placed in cache line 0. Any block belonging to group number 1, when it is placed in cache
memory must be placed in cache line 1. Any block belonging to group 255 must be placed in
cache line 255 in the cache memory.
I also to have to have a number of tag locations, one tag for each of the cache lines. So you find
that from here, if block number 256 is placed in the cache memory, the tag field should contain
value 1 because that is the tag identification number. If say 255 is placed in cache line 255, the
corresponding tag field should contain value 0 and simultaneously I also have to have number of
valid bits, a valid bit for each of the cache lines or each of the tag memories. So I have to have
256 entries in the cache tag memory, I have to have 256 entries in the valid bit array. So given
this scheme, the architecture to find out whether a given, a requested byte is available in the
cache memory or not. What is the scheme that we should follow? The scheme will be something
like this.
9
(Refer Slide Time: 00:40:27 min)
The main address as I said is divided into 3 fields, byte field, group identification and tag field.
As per our example, the group field contains, it consists of 8 bits, right? So first what you do is
this group entry, you feed to a decoder and because here you have 8 bit, so the decoder should be
8 to 256 decoder. Depending upon the content of this group field, one out of 256 decoder output
lines will be active, so let us put it like this. There are actually 256 lines, one of which will be
active and others will be inactive depending upon what is the content of the group field. Now on
this side, we have cache tag memory. So this will also have 256 entries. What we do is, output of
this cache tag entries goes to a buffer, tristate buffer.
Now let me put it here. These are say valid invalid bits. The valid invalid bits will also be 0 or 1
depending upon whether the content of the tag field or the content of the corresponding cache
line is valid or not. So what I do is, depending upon which of the groups is active, I know that a
particular group of blocks can belong to only a particular cache line for which the tag field can
be present in only one of this tag fields, tag entries. So what I do is, suppose this output of this
decoder is active, I simply do ANDing of the corresponding valid invalid bits with this decoder
output and this AND gate output goes to the corresponding enable input of the corresponding
buffer. So once I get this then what I have is, content of this tag location is available at the output
of this buffer.
Now this buffer output is to be compared with that tag field because I know that these tag
memory locations contain the tag identification number, right? So I have one comparator which
will compare this buffer output with the tag field as specified in the memory address, right? So
now you find that I have similar arrangement for each of the entries in the cache line and all
these buffer outputs are wired OR, they are connected together because I know that only one of
the buffers will be active, all other buffers will remain inactive. This comparator will give you
two outputs either not equal or equal as we have said before also. This not equal output indicates
a cache miss, equal output indicates a cache hit, right? So whenever there is a cache hit, suppose
let me put it this way, so this is cache hit line.
10
Whenever there is a cache hit what I have to do is I have to AND, the output of this AND gate
with the cache hit line. On this side I have cache lines. Again I have a set of buffers. There are
number of cache lines, outputs of each of these cache lines are coming to a buffer input. This
AND gate output gives the enabled input of the corresponding buffer. Then again, I have a
selector or a multiplexer, the buffer output comes to the input of the multiplexer, select input to
this multiplexer comes from the byte identification number and output of this multiplexer goes to
the CPU. But that can come from anywhere, I have to identify a particular cache line…all the
buffers, I have a set of buffers here all the buffer outputs are wired together.
At the most one buffer output will the high but I have to identify which one. How do I know
that? I am selecting only that. See here I have to identify all, group identification number, tag
field. The field is compared with this. The group identification number is available from the
output of this. So only when and the corresponding valid bit is also 1. So only when all these
conditions are true that is valid bit is 1, I have to get the output from the decoder, I also have to
have a condition of cache hit then only the corresponding cache line will be read. So this is
needed because out of so many cache lines, I am interested in only one but which one? That is
given by this line. All the conditions must be true. So which one I am interested in that is given
by this AND gate output. That is ANDED with the cache hit line to give me a particular cache
line in the cache memory. So that cache line is going to the multiplexer input and the select input
to this multiplexer is coming from the byte identification number and the corresponding byte
goes to the CPU. Data is available in the cache memory. which cache line, which one? But which
cache memory, which cache line? I have similar elements for all of them; all the outputs are
wired together. I have to identify a particular cache line; I am not interested in anyone. So with
this we stop today. Thank you.
11
Digital Computer Organization
Prof. P.K. Biswas
Department of electronic & Electrical Communication Engineering
Indian Institute of Technology Kharagpur
Lecture No. # 19
Cache Memory Architecture RAM Architecture
So, we started our discussion on the cache memory. In the last class we have discussed about the
associative cache and the direct mapped cache.
In case of associative cache, we have seen that a block from the main memory can be placed in
any of the cache lines. The block address will be placed in the corresponding tag memory and the
valid bit in this tag assembly has to be made equal to 1. So whenever we want to search for a
particular block whether that block is available in the cache memory or not, the block number
has to be compared to each of this tag memory locations in parallel and depending upon the
output of this match result and whether the corresponding valid bit is equal to 1, you take out the
corresponding cache line and select one byte from the cache line through a multiplexer, by
making use of the byte identification field.
(Refer Slide Time: 00:02:06 min)
Whereas in case of direct mapped cache, we have said that a particular block of the main
memory can go into a particular cache line; unlike in case of associative cache, where a main
memory block can go in any of the cache lines. In case of direct mapped cache a block in main
memory can go only to a particular block in the cache, it cannot go anywhere else. The
advantage that we have got in case of direct mapped cache is the reduction in hardware, whereas
in case of associative cache if there are n number of cache blocks or cache lines, I have to have n
number of comparators. Whereas in case for direct mapped cache, as we have seen with the help
of the schematic diagram that the n number of comparators is replaced by a single comparator.
And this is possible because of a limitation that one block of main memory can go only to one
cache line, it cannot go to any other cache line.
But obviously you have some disadvantages. In case of associative cache because you have
flexibility that a main memory block can go to any of the cache lines, so the number of cash miss
is less in case of associative cache. Whereas in case of direct mapped cache because a particular
block of main memory can reside only in a particular cache line and it may so happen because I
have only one option, I don’t have any choice. So it is quite likely that whenever I want to bring
in a new block from the main memory and want to place it into the corresponding cache line, the
cache line may be filled up by some other block of the main memory belonging to the same
group of blocks.
(Refer Slide Time: 0:02:53.6 min)
So the number of cache miss in case of direct mapped cache is obviously higher than that in case
of the associative cache. So a solution which tries to incorporate the advantages of both, that is
we want to reduce the hardware at the same time we also want to maintain some flexibility so
that instead of having only one cache line where a block can go, I want to keep some options
may be out of 2, 3 cache lines, 1 cache line can be filled up by particular block from the main
memory. So effectively what we are trying to do is, we are trying to reduce the hardware as is
done in case of direct mapped cache. We also try to take the advantage of flexibility as in case of
associative cache.
Similarly I will have 32 tags numbering from 0 to 31. So as before, the block number 0 of the
main memory belongs to group number 0, block number 1 in the main memory belongs to group
number 1. Similarly block number 255 in the main memory belongs to group number 255, 256
belongs group number 0 but tag number 1. So it is the same arrangement of the main memory
blocks that we have done in case of direct mapped cache. The difference is, in case of direct
mapped cache, we have said that a particular block of the main memory belonging to a particular
group can go to only a particular cache line in the cache memory. In case of set associative
cache, what we do is instead of saying that this can go to only one cache line, we identify a set of
cache lines. So we say a set of cache lines may consist of say 2 cache lines, 3 cache lines, 4
cache lines and so on but normally it is 2, 4, 8 like that, as is done in binary number system.
So if a set consists of 2 cache lines then we say that any block belonging to a group can go to that
particular set and since within the set we have 2 cache lines, so any of the 2 cache lines can be
occupied a block belonging to a particular group. So following the same logic, what we do is,
now let us assume that in every set we have 2 cache lines. So Since we have say 255 groups in
the main memory, 255 groups of blocks, so let us assume that we will have 255 sets of cache
lines and every set will consist of 2 cache lines. So these two belong to the same set, this is the
cache line. Now I have 256 sets and every set consist of 2 cache line. So as I have 2 cache lines
in the same set, so accordingly in the tag memory organization, I also have to have similar
organization that is the tag memories will also be divided into a number of sets where every set
will consist of two tag memories. So let us put it this way. So these are the tag memories which
will also consist of 256 sets and every set will consist of 2 tag memories.
In the same way I will also have valid invalid bits. Now for every tag memory I have to have a
valid invalid bit that means they will also be divided into similar sets, every set consisting of two
valid invalid bits.
In tag, for every cache I have to have a tag because cache will accommodate a block of the main
memory and the tag memory will contain the block identification number. So now since we are
saying that any member of this group of a particular group will go to this particular set. Now this
set consists of two cache lines. For every cache line I have to have a tag because otherwise I
won’t be able to identify that which block of the main memory is contained in which cache line.
So that way if I decide say block number 256 will go to say this particular cache line. For block
number 256, what is the tag? Tag value is 1. So this entry, this particular tag memory will
contain a value 1 and the corresponding valid bit will also be 1.
Now if I wanted to put another block belonging to the same group also in the cache memory, you
find that the other entry of this set, other element of set is empty. So suppose this block number 0
has to be placed into the cache memory. In this case this particular entry in the cache, this
particular cache line can contain block number 0. For block number 0, tag value is 0. So this
corresponding entry in the tag memory will contain a value 0, this valid bit will be equal to 1.
Unlike in case of direct mapped cache where we had to replace this block number 256 by block
number 0 because there I didn’t have any option. So here we get some amount of flexibility not
as high as in case of associative memory but the restriction of the direct mapped cache is relaxed
to some extent. Yeah, Cache memory requirement become also doubled and since every set in
this case consists of two cache lines, this is called a two way set associative cache.
So similarly I can have 4 way set associative cache where every set will consist of 4 cache lines.
Similarly I will have for every set that has to be 4 entries, 4 tag memory locations, I have to have
4 valid invalid bits. Now what will be the architecture for this type of set associative cache
memory? It is simply the extension of direct mapped cache.
So here let us assume that as I said that even in this case that main memory address will be
having 3 fields, the byte field, the group field and the tag field. Using the same example since the
group field contains 8 bits, so this will be fed to 8 to 256 decoder and depending upon the values
in this group field one of the 256 outputs of this decoder will be high. On this side let me put the
cache memories. Now the cache memory will be organized in the form of sets where every set
will consist of two cache lines. Here let me put the valid invalid bits and the tag fields, so these
are the tag fields. In every set I have to have too entries in the tag field, I also have to have the
valid invalid bits.
When I put it like this, it means that these two belong to same set, these two belong to same set,
these two belong to same set. Now as before in case of direct mapped cache what we have seen
is, using the output of the decoder which is active, which is enabled, I enable the corresponding
tristate buffer to get the content of the tag memory location. Now in this case in case of set
associative cache, you find that whenever a particular output of a particular decoder output is
active that does not uniquely identify a particular tag memory location. It identifies a set of tag
memory locations and in this case the set consists of two tag memory locations that means I have
to compare both the tag memory locations to find out whether there is a cache hit or there is a
cache miss. So suppose this particular output of this decoder is 1, so when a particular decoder
output is 1 that indicates that there may be 2 different tag memory locations which can give a hit.
One of the two tag memory locations will be able to give a hit. So I have to compare 2 tag
memory locations unlike in case of direct mapped cache where we have to compare only one tag
memory location. So here the situation will be like this that using this same decoder output, I
have to compare two tag memory locations.
So suppose let me see that this is the tag memory location that we want to compare. So the
corresponding valid invalid bits will come here. So here also I will have two different buffers,
one of the buffer input will come from this tag memory location. Let me use some other color, it
will come from say this tag memory location and this one let us say it comes from this tag
memory location. The AND gate outputs, this AND gate output will activate this particular
buffer, this AND gate output will activate this particular buffer. So you find that any of these can
be valid and depending upon which one is valid, I have to compare the corresponding tag output.
Now it may be possible that both the bits are valid because this can contain a particular block,
this can contain another block of the same group in which case both these valid bits will be equal
to 1. so I have the possible tag values which are two in this case, out of this I have to select one
that means in this case I need 2 comparators unlike in case of direct mapped cache where I
needed only 1 comparator. So I have to have 2 comparators, this is say comparator 1, this is
comparator 2. So this output will go to one of the comparators, this output will come to another
comparators. Both the tag values are to be compared with the tag value as given in the main
memory address. Is it okay? Now I can have different combinations that is this tag value does not
match with any of these tag values.
The tag value has given in the address does not match with the content of any of these tag
memories. That means both the comparators give a signal of not equal. When such a situation
arises this means the requested block does not exist in the cache memory because if it exists, it
has to be present, the corresponding tag has to be present either in this tag memory or in this tag
memory because it does not match, this tag value does not match with content of any of these tag
memory locations that is an indication that the requested block is not available in the cache. So in
this case when both the comparators signals not equal that is a condition which is the cache miss
condition.
Similarly cache hit condition will be either this one indicates a cache hit or this one indicates a
cache hit because the requested block, the tag value of the requested block may be present either
in this or in this. So if it is present in this, in that case this comparator will signal equal. If it is
present in this one, in that case this comparator will signal equal. So if any of them gives a cache
hit that is the condition of cache hit, so I have to have an OR logic. So following the same
argument what I will do is, this is the condition of cache hit. I will take one output from here; I
will another output from here. They will be ANDded together, these two will also be ANDded
together and they will activate two different buffers. So I am considering the third entry. This
will go to the AND gate outputs, not this.
So in the same manner, I will have two different buffers. These buffer will get input from this
cache line, this buffer will get input from this cache line then this will activate this buffer, this
will activate this buffer. These buffer outputs can be connected together, output of this comes to
a multiplexer and the select input of the multiplexer comes from the byte identification line and
this is the data that has to be returned to the CPU. So you find that in this case, we have slightly
increased the hardware because in case of direct mapped cache we had only one comparator.
Now we have two comparators but it is much less than that in case of associative memory where
I had n number of comparators. Yes, both AND gate outputs will be one. There is a point, you
are right.
So what I have to do is instead of taking this cache set outputs, so this is a cache set signal. I
have to take the outputs from here, this one will go to one of the AND gates. So instead of taking
the connection from here, let me connect this here and the other one will go from this point. Is it?
So this one will be off, I have to take this output and AND with this one. Is it okay? That’s right,
thank you. See as he has pointed out and it is right that both the tag memories can contain some
valid tag value in which case both the valid bits will be equal to one. If both valid bits are 1 and I
have a cache hit then if I AND these AND gate outputs with this cache hit signal, so both of
these AND gate outputs will be equal to 1. If both of them are equal to 1, then both these buffers
will be enabled. If we enable both the buffers then there will be data clash because I have
directly connected the outputs of the buffers. Instead of that if you take the cache hit as given by
the individual comparators, AND them with these AND gate outputs in that case one of these
buffers will be enabled because both of the comparators cannot give output signal equal.
If both of them gives equal that will indicate that both of these cache lines contain the same data
block, which is not possible. So in that case only one of these buffers will be active and the
corresponding output, data from the corresponding cache line will be available at the input of the
multiplexer. So here you will find that we have been able to reduce the amount of hardware
drastically compared to the number of amount of hardware that you need in case of associative
cache, it is slightly more than that in case of direct mapped cache but we have been able to
incorporate advantages of both. To some extent we have been able to maintain the associativity
that is, now a block of the main memory can go to one of these two cache lines.
Earlier in case of direct mapped cache, it had to go to only one cache line but now I have a
choice. Any of these two, if free I can put the block in the corresponding cache line. However,
that concept can be extended instead of two way set associative, we can go for 4 way set
associative, we can go for 8 way set associative in which case every set will consist of 4 cache
lines or 8 cache lines and so on. Obviously in such cases, the number of comparators will also
increase. If it is 4 way set associative in that case I have to use 4 comparators. If it is 8 way set
associative, I have to use 8 comparators. So accordingly the scheme can be made. So after
talking about the cache architecture and as we have just said that the cache memory is usually
implemented with the help of static RAM, whereas main memory is implemented with the help
of dynamic RAM. So now let us see that what is the static RAM architecture or what is the
dynamic RAM architecture?
So now we will consider about 2 types of RAM architectures static and dynamic. You might be
knowing that every memory chip consists of n number of memory cells arranged in some
fashion.
And typically a memory cell is nothing but some sort of a flip flop. Isn’t it? So if I consider static
RAM cell, the schematic diagram is static RAM cell can be drawn like this and we will find that
it is nothing but a kind of D flip flop or a latch. So the architecture of static RAM cell is
something like this. So you find that whenever the read write signal this input is low, in that case
whatever is available at the data in that will be latched in this particular latch and the latch
consist of two nor gates. If we want to read anything from this latch or from this memory cell,
the read write bus signal has to be high.
So if the read write bus signal is high and it is selected, in that case this AND gate output will be
high. When the AND gate output is high, this activates this particular buffer and when the buffer
is activated, the output from latch will be available on the data outline. So this whole thing can
be represented as a static RAM cell. So this is a static RAM cell, in other words I can put static
RAM cell just by box like this which will have select input, a data inline, data outline and R/W
input and this is a static RAM cell D. Now if this static chip is nothing but an array of such cells
arranged in some fashion, so usually these RAM cells are arranged in the form of a two
dimensional array. It is something like this, say if I wanted to have a static RAM of say 4
locations, every location consisting of say 4 bits. So I will have a 4x4 SRAM cell or an SRAM
chip.
The organization will be something like this because I have 4 different locations and every
location will consist of 4 bits that means for every location, I have to have 4 such static RAM
cells placed in a linear order. So I can consider that this is a row of 4 such static RAM cells and
since I will have 4 locations, each consisting of 4 bits, so I will have 4 such rows, in every row I
will have 4 static RAM cells. Now to read or write a particular location in this RAM chip, I have
to select the entire row. Suppose I wanted to read the data from the zeroth row in this static RAM
chip, in that case all the cells in the zeroth row must be activated simultaneously. That means the
select inputs of all RAM cells in the zeroth row are to be selected simultaneously. Then if I want
to read the data, the read lines of all the RAM cells have to be activated simultaneously.
If I want to write data in that case this R/W line has to become low simultaneously and the data
must be available to all the RAM cells simultaneously. So I can arrange... this is just a flip flop. I
think you have done flip flop in your digital networks course. This is just a flip flop so whatever
data you feed to the flip flop that gets latched. How do you latch it? You feed some data to the
data input line. When you feed the data into the data input line, if at the same time your select
input is active and I want to write the data that means R/W signal has to be low. Here you find
that this R/W signal goes through an invertor to both these AND gates. So if this is low, this
inverter output will be high that means this AND gates will be active, will be selected provided
the select input is high and R/W signal is low. In such case whatever you feed to the data, data
input line if this is say one in that case this AND gate output will be 1, second AND gate output
will be 0.
So if this is one, you find that this NOR gate output will be zero, this nor gate output will be one
and it will remain until and unless you change this by feeding another data while that unit is
selected and R/W signal is low. That means by making R/W signal low and selecting this
particular unit, the memory cell you are writing the data into this memory cell. Now if I want to
read it, so read is clear. So every memory chip will consist of such cells arranged in some
fashion. So here we are considering a two dimensional array of such memory cells and I am
considering a 4x4 array.
(Refer Slide Time 00:38:38 min)
So let us put those cells, arrange those cells in the form of a 4x4 array. You remember that each
of cells will have those 4 signals select input, R/W signal, R/W input, data in input and data out
output. So they are, now whenever we select this memory for read or write then a particular row,
all the cells in a particular row has to be selected. So what we do is let us connect the selects
inputs of all the chips of all the cells to a common line. Say these are the select inputs.
Similarly when we want to read any particular memory location or we want to write into any
particular memory location in that case, the corresponding R/W signal has to reach all the cells
in the selected rows simultaneously or even if the R/W signal reaches all the cells, whether the
row is selected or not that does not matter because only the row which is selected that will be
affected, other rows will not be affected. So what we can do is, let us have a common R/W
signal which is connected to all the cells. So this is your R/W signal and the red lines are the
select inputs of individual rows.
Now since we have 4 different locations that means for addressing any particular location, we
need to 2 address lines. And what we can have is just a 2 to 4 decoder, say if I have a simple 2 to
4 decoder which will have input lines say A0 and A1, these are the address lines. Different
outputs of this decoder can be used to select different rows in this memory array. It’s very
simple. So this is say zeroth output, first output, second output and third output. So you find that
this particular array gets an address 0, these row gets an address 0, these row gets an address 1,
these row gets an address 2 and these two gets an address 3. Now what is left is how to connect
the data in and data out lines.
Again what we can do is, very simple, say these are data in lines. we connect the data in lines of
all the cells in a particular column together. Similarly data outlines of all the cells in a given
column together. These are the data in lines. So let me put a buffer in the inward direction, this is
data outline, so let us put a buffer in the outward direction. Now this buffer pair is feeding the
same column, so let us connect these two together. Similarly these buffer pair is connected to the
same column. Let us connect these two together. This is feeding the same pair, so let me connect
these two together. This is feeding the same pair, so let me connect these two together. Now find
that if the operation to be performed is a write operation that this is actually the external data
lines. These are external data lines let me name them as d0, d1, d2 and d3. If I have to perform a
write operation in that case d0 has to reach inputs of all these cells and this is my R/W signal.
So if this read R/W is low, in that case this buffer has to be active. If it is high then these buffer
has to be active. So when you find that the R/W signal is low in that case operation that we have
to perform is a data write operation. So whatever is the available on the external data line that
has to be written into the cell which is selected by the select line. That means the data flow is in
the inward direction, so this particular buffer has to be active. If it is a read operation in that case
data from the selected cell has to come to the external data bus, external data line. So this
particular buffer has to be active and that is set by this R/W line. So I will have single
connection to all these pairs like this and this becomes a 4x4 SRAM chip.
So you find that whenever we wants to design a chip, we have to arrange these memory cells, the
static RAM cells in the form of an array like this where every row will be selected by one of the
decoder outputs and whether it is read operation or write operation that we want to perform that
has be decided by the R/W signal. So with this we stop now.
Digital Computer Organization
Prof. P.K.Biswas
Department of Electronic and Electrical Communication Engineering
Indian Institute of Technology, Kharagpur
Lecture No. # 20
RAM Architecture
So though this architecture, two-dimensional array of RAM cells this appears to be okay
logically but practically there is some implementation problem.
The problem is like this, if we have only one decoder like this which selects one of the rows, all
the cells in a particular row then you will consider a situation so suppose I wanted to have a
memory which will have say 1M locations. So 1 M locations means, I have to have 20 address
lines. Now every location may consist of say one memory cell, it may consist of 2 memory cells,
3 memory cells and so on. But what I need is I have to have 20 address lines to address different
locations or different rows in the cell array. So if I have this 20 address lines then you consider
what is the decoder complexity. In the decoder I need 220 number of gates, AND gates because
the decoder logic is simply something like this. It is nothing but an array of AND gates. So if I
want to have simply a 2 to 4 decoder which will have 2 lines say A0 and A1, the connection will
be something like this. So when both A0 and A1 they are 0 0 in that case this output will be high.
For 0 1 this output will be high, for 1 0 this output will be high, for 1 1 this output will be high.
1
(Refer Slide Time: 00:01:25 min)
So for a 20 input decoder I have to have 220 number of AND gates. Every AND gate has to have
a fan-in of 20. Isn’t it? 20. So just like this, in this case every AND gate has 2 input lines for a
220, 20 to 220 decoder, I have 220 number of AND gates, every AND gate will have to have 20
input lines that is quite difficult. So instead of doing this, if we break the address into two
components, so this 20 address lines I break in to 2 groups, 10, 10 each and I say that out of
these, these 20 address lines, I will consider as row address and these 10 address lines I will call
as column address. And accordingly I will have 2 decoders, one of them will be called as row
address decoder other one will be called as column address decoder. So the decoder complexity
will come down drastically. For row address decoder I need 210 number of AND gates.
Each AND gate will have 10 input lines. For this I need again 210 number of AND gates which
will again need AND gates of 10 inputs each. So the number of AND gates that you need is 210 +
210, that is 211 whereas in the original configuration the number of AND gates was 220. So
number of AND gates has been reduced to a great extent not only that the fan-in of every AND
gate has also been halved.
So instead of directly trying for only one decoder, for decoding all the address lines you break
the address line into two components, one of them you call as row address and the other set you
call as column address. Accordingly, you have two decoders, one is the row address decoder
other one is the column address decoder and by making use of these two decoders, I can select
different cells in the two dimensional cell array.
2
(Refer Slide Time: 00:06:02 min)
So using this if I want to implement a memory, let us take a memory of say 64 K, where every
location will contain just one bit. So I want to have a 64K x 1 memory organization. Following
this architecture, it is 64 K means I have to have 16 address lines. So if I follow this architecture,
I need a decoder which will decode 16 to 216 outputs, for 16 inputs it will give me 216 outputs
that means I need 216 number of AND gates, every AND gate will have a fan-in of 16. Instead of
doing this I will break this 16 address lines in to 2 groups, each of 8 bits. So I will break it in to 8
+ 8 address lines. One group of 8 address lines I will call as row address and the other group of 8
address lines I will call as column address.
The cell, memory cells will again be arranged in the form of a two-dimensional array and it will
be 28 x 28, that means 256 x 256 cell array. That means every row will have 256 cells and I will
have 256 number of such cells. The 8 address lines which I call as row address that is fed to a, 8
to 28 decoder, so 8 to 256 decoder. It will have 8 address lines as input, so let me mark them as
address lines A0 to A7. The decoder has 256 output lines, depending upon the bit combination on
this 8 inputs, one of this 256 output lines will be active and the corresponding row in this two-
dimensional cell array will be selected.
So when a row is selected that means all the cells in that particular say, in that particular row will
be available either for reading operation or for writing operation. Now out of this 256 cells
belonging to a particular row, I have to select one particular cell because my organization is 256
K x 1 memory organization. So when I am selecting a particular row either for reading operation
or for writing operation, I am selecting all the 256 cells belonging to a particular row with the
help of this row address decoder. Next what I have to do is out of those 256 cells, I have to select
a particular cell for reading or writing operation and which cell I have to select that will be
dictated by the parameters that is again another 8 bits. So the arrangement in this case that can be
made is instead of simply a decoder, I can have a multiplexer demultiplexer combination. So if I
use, if I want to perform a read operation of a particular bit, I pass all this 256 cell outputs
through a 256 to 1 multiplexer.
3
If I want to select a particular cell for a write operation, at the output of this I have a single data
line. So this is line d both for reading operation and writing operation assuming that external data
bus that we have is a bi-directional data bus. So for reading operation out of this 256 cells, output
of one of them will be available on the output data bus. For writing operation, the data which is
fed to this line has to reach one out of this 256 cells. So for reading operation I need a 256 to 1
multiplexer. For writing operation, I need just the reverse 1 to 256 demultiplexer and these
demultiplexer select lines actually come from the column address. So here I will have 8 lines, 8
address lines named say A8 to A15 between the cell array and this multiplexer demultiplexer pair
I have 256 lines.
Now in addition to this address lines, I also have to have the control signals like R/W . I also
have to have another control signal which we will call as chip select. So here what we are doing
is using this row address which is 8 bits, I am selecting one of the rows in this two-dimensional
cell array. A row means 256 number of cells. When I want to read a particular location that
means I have to read a particular bit, a particular cell in that 256 cells, so which cell I want to
read that depends upon what address is being fed to A8 to A15 lines depending upon that one of
this 256 will be selected and will be available at the output of the multiplexer.
Similarly, for writing operation I am selecting an entire row but the data will reach only that
particular cell which is fed by this 1 to 256 demultiplexer. Again the selection of a particular cell
through this demultiplexer will be done by this column address lines. So you find that I gain
tremendously if I break all the address lines in to two components row address and the column
address. So this is the organization of, it is a 64 K x 1 memory chip.
The same cell array can also be thought of like this, I can with slight modification, I can make it
as a 16 K x 4 memory organization. You find that the number of cells are same. In this case also
I have 64 K cells, in the earlier case also we had 64 K cells but the cell organization in this case
4
will be slightly different. Here all the 64 K cells we can put into 4 different arrays, so I will have
four 256 x 64 cell array. So Instead of a single cell array, now we use 4 two-dimensional cell
arrays, every cell array will have 256 rows, every row will consist of 64 cells. Now because I
have 16 K locations that was number of bits needed to address these 16 K locations is 14 because
214 is 16 K. These 14 lines I break again in the form of row address and column address. I will
assume that 8 of these address lines A0 to A7 will be the row address and the remaining 6 address
lines A8 to A13 will be the column address.
So as before because I have 8 address lines identified as row address, so I have to have decoder
that is 8 to 256 decoder. These decoders will have 8 address line inputs A0 to A7, it will give 256
output lines, one of them will be active at a time depending upon this bit combination on the
input side. So whichever output line is active, the corresponding rows because now I have 4 such
cell arrays, so it will select 4 rows, one from each of the array. Here, in the earlier case we had
only one multiplexer and demultiplexer but now because we have 4 such arrays, so I need four
64 to 1 multiplexers, one multiplexer for each of the cell array. I also need four 1 to 64
demultiplexer. I will have 4 input output lines, one from each of the cell array let me mark them
as d0, d1, d2 and d3. This unit, the multiplexer demultiplexer unit will get the column address
which consists of 6 lines and the addresses from A8 to A13. It will have control inputs R/W , it
will also have control inputs a chip select and now here I need 4 such connections each of width
64.
So you find that by making use of various organizations, various kinds of chip arrays, I can go
for different kinds of memory organization but the basic structure will be like this. I have to have
a row decoder; I have to have a column decoder. The row decoder will select an entire row
consisting of a number of memory cells and the column decoder will select one or more cells
depending upon what is the memory organization from the cells coming from a particular row. Is
it okay? Now let us see practically how these cells are implemented.
5
(Refer Slide Time: 00:19:35 min)
You find that as we have said in the cell architecture, the basic storage element is only this which
stores the bit either 0 or 1 but I have a number of additional gates for every cell and the number
of gates which are used to control the cell is much more than the number of gates which are
actually used to store the value. That means the control overhead is much more than the storage
overhead. Naturally this is not an architecture which is desirable. So for implementation and
particularly many of you have become expert in VLSI by this time, so particularly for VLSI
implementation, we have to keep in mind that the number of components should be reduced as
much as possible.
6
So for practical implementation each of these cells is implemented by using a model which is
called a 6 transistor model. And it is very simple; every cell will be something like this. So it is
something like this. This is a particular cell. Now you find that this cell consists for 6 transistors
because each of this inverters can be implemented using a single transistor. Now the cell is, all
the cells belonging to a particular row is selected by this word line Wj which actually comes
from the row address decoder and using the column select, from the column address decoder
actually there are a number of columns like this, if I repeat this same architecture one after
another this becomes a number of columns and the rows will consist of these cells arranged one
over the other.
Now see that how do you write the data in to this cell or how do you read the data from this cell.
Whenever we want to write a data say data 1 in this cell, what we have to do is we have to drive
this bi line these are, this is called a dual rail. I have to drive bi line to high and bi line to low. So
with bi line to high and bi line to low, if you select this particular word line in that case, 1 will be
written in this latch. You find that this is nothing but a latch. So what is the difference? The
difference is the NOR gate has been replaced by an inverter. So, if I set this line to high and this
line to low and select this particular cell through this word line Wj in that case one will be written
in this side.
Similarly, if we want to write a 0, I have to drive the bi line to 0, bi line to high or 1 and select
this cell through this word line Wj, in that case 0 will be written in the cell. At the input you are
giving only a single bit either 0 or 1, so that bit has to be converted to a complement pair. If I
give an input one that has to be converted to 1 and 0, bi line has to be 1 and bi line has to be 0,
so which is to be done by this unit. This is actually sense write amplifier along with that this line
also performs the additional task of driving lines bi and bi both for reading purpose and writing
purpose. So I can put it, it is sense write amplifier cum driver.
Similarly if I want to read this particular memory cell in that case what I have to do is, we have
to drive both bi and bi lines halfway between 0 and 1 logic. So if the zero logic is voltage 0 and
1 logic is say voltage 5, 5 volts then for reading purpose I have to drive both the lines to
something like say 2 volts or 2.5 volts. So driving these two lines bi and bi to a voltage in
between 0 and 1 logic level and then selecting this cell through this word line Wj, you will find
that then whatever is stored in this particular cell these lines bi and bi will be driven accordingly.
So that is sensed by this sense amplifier and the corresponding output comes to this output line
di.
So if we implement the cell like this, in that case you find that the number of transistors that is
required is much less compared to the number of transistors that is required in this type of
implementation. So this is the basic architecture of static RAM cells and static memory
organization. But as we said that this static RAMs are mainly used for implementation of cache
memory, whereas whenever we go for implementation of the main memory, we don’t use static
RAMs rather we use dynamic RAMs. So lets us see what is the organization of a dynamic RAM.
In case of dynamic RAM, the RAM cells are very simple, it is simply like this.
7
(Refer Slide Time: 00:30:15 min)
So this is word line Wj and this is for a particular column say ci. The other part that is the write
sense amplifier and driver which is almost similar to that in case of static RAM cell. So this is
sense write amplifier and driver and as before I will have a number of buffers, this is connected
to output data line say di. I have the other control circuitry and here I have column select. So dual
rail in case of static memory cell is replaced by a single rail which is bi in this particular case and
this is the basic cell architecture of dynamic RAM, so this is a dynamic RAM cell. So in this
particular case a bit 1 is stored in this cell whenever this capacitor is charged to high voltage. If
the capacitor is discharged that means the bit that is stored in this cell is 0, I don’t have any latch.
So if I want to store a particular bit say 1, what I have to do is this bi line, this single rail bi has to
be driven to a high voltage and after that you have to select this particular cell through this Wj
line and since bi is driven to a high voltage and this cell is selected that means the path from this
bi line to this transistor is on, to this capacitor is on, this is the capacitor in which case the
capacitor will be charged and it will store a value 1. If I want to store a value 0, what I will do is
I will set this bi line to low after that I will select this cell through this Wj line, so if the capacitor
was charged previously, this will now be discharged, so it will store a value 0. Now if you
compare the circuit complexity of the dynamic RAM cell with the static RAM cell, this is static
RAM cell, so obviously you find that the number of components in the dynamic RAM cell in the
DRAM cell is much less than that case of SRAM cell. So that is why the packing density of the
DRAMs is much, much higher than that in case of SRAMs and that leads to cost reduction in
case of DRAM. But simultaneously I have other problem. In case of SRAM even if you read a
value from a RAM cell, the value contained in the RAM cell is not changed because the value is
already latched.
8
In case of dynamic RAM cell, you assume that the value stored in this cell was 1, that means the
capacitor was charged. Whenever I want to read this cell what I have to do is, I have to select this
cell through this line Wj then the cell will be selected, the value stored in the capacitor, the
charge stored in the capacitor will be sensed by the bi, bi line. The moment you try to sense it,
this capacitor will get discharged, that means whenever I want to read a value, the capacitor will
be discharged. So this is what is called a destructive read out. So I have to have an arrangement
that because I know that whenever I read a RAM cell, if it is storing a value 0 then there is no
problem but the problem comes if it is storing a value 1.
So whenever I want to read a RAM cell and the RAM cell was containing a value 1, the
capacitor is going to be discharged and the value is going to be lost. So I have to have an
additional facility that whenever you read any RAM cell, I should be able to refresh the RAM
cell back that means whatever value is there, the immediate next action should be you write the
same value in the same RAM cell, which is called DRAM refreshing that means after every read
operation the DRAM has to be refreshed. Not only that if I leave this RAM cell just like this
without any reading operation, even then the capacitor will be discharged because of leakage. So
even if I don’t read the DRAM location, I should refresh the DRAM at regular intervals of time.
That means I have to have a mechanism by which the DRAMs can be refreshed at regular
interval of time or it will be refreshed after every read operation. So details of all these DRAM
architecture we will see in the next time.
9
Digital Computer Organization
Prof. P.K. Biswas
Department of electronic and Electrical Communication Engineering
Indian Institute of Technology Kharagpur
Lecture No. # 21
DRAM Architecture – I
So, in the last class we were discussing about the dynamic RAM or DRAM cells and we have
said that a DRAM cell is a simple circuit like this, where you have just a charging capacitor and
a charging discharging path. So depending upon what voltage is stored on the capacitor, you
would store either bit 1 or a bit 0. So for storage or for retrieving the value that is stored on the
capacitor you have to enable the corresponding row, so the entire row of cells will be selected.
Then from that row you have to select a particular column, so one or more columns using the
column select in which the control comes here and unlike in case of static RAM where we have
said that in case of static RAM, the basic cell consists of a latch, I have that figure. So this is the
static RAM cell and since the basic cell consists of a latch, so once we store value, the value will
remain until and unless it is over written by a new value.
1
(Refer Slide Time: 00:01:54 min)
Whereas in case of a dynamic RAM, since the bit 1 or bit 0 depends upon whether the capacitor
is charged or discharged over a long period of time or even when you read the content of a
particular capacitor, if the capacitor was previously charged then because of reading operation
the capacitor will be discharged.
And not only that after storing certain value even if you don’t read the dynamic RAM for a long
period of time then the capacitor will get discharged because of leakage current. So in case of
dynamic RAM, we must have a provision of refreshing the content of capacitors at regular
intervals of time, so which is taken care of by this unit that Sense/Write Amplifier and driver.
2
So even if you read it, after reading operation you have to recharge the capacitor after amplifying
the value that has been sensed on the capacitor. Even if you don’t perform any read operation
even then it will be the responsibility of this circuit or a control circuit, in addition to this I will
come to dynamic RAM organization. There are control circuits, responsibility of the control
circuit will be to write, to read and write the content of different rows in the dynamic RAM cell
array at regular intervals of time and that has to be taken care of by an additional control unit
which is given along with the DRAM. So coming to the DRAM organization, the organization of
a DRAM is something like this. Let us consider that we have a DRAM chip having one M
location and every location consisting of one bit.
So 1 Mx1 bit DRAM chip. So because it is 1 Mx1 bit, so the typical organization of the RAM
cells can be a two dimensional organization. So the kind of organization of RAM cells that we
will consider is something like this. Let us assume that we have a two dimensional organization
of RAM cells which will have 1 K, rows every row consisting of 1 K number of cells. So we will
have 1024x1024 DRAM cell array. Now others so, because it is 1 M locations and every location
consists of 1 bit that means the number of address lines that we have to have is 20 address lines.
Now another consideration which affects the design of DRAM chips is that the market of
dynamic RAM cells is very competitive and once you design the DRAM chip then once the
RND cost is made up, later on the cost of the chip depends upon what is the fabrication cost and
the silicon cost. And silicon cost is very less because you hardly use any silicon image chip. So
what decides the cost of the, it is not only for DRAM, the cost of any chip is, what is the
fabrication cost? And fabrication cost almost increases linearly with the number of pins that you
have.
So one of the design considerations is, to reduce the number of pins which should be true for all
other chips but it is specifically important in case of DRAM because DRAM has very high
competition in the market. So, all the manufactures try to reduce the number of pins that you
have in the DRAM. So in this particular case because the number of pins needed for just feeding
3
the address lines is 20, so what manufacturers prefer is that instead of having 20 address lines, let
us have 10 address lines. And we will feed row and column addresses because we have seen in
case of other chips also, even in case of SRAM chip that the address bits that you provide that is
internally divided into two components, one is row address other one is column address. Row
address go to row decoder; column address goes to the column selectors. The row decoders
activate a particular row, out of that row the column selectors decide or take out the number of
columns which are needed.
Similarly, in this case, but in that case we don’t have any row column multiplexing but in case of
dynamic RAM because of competition, manufacturers have decided to go for row column
multiplexing. So you will assume that there are 10 address lines over which 20 address bits will
be provided and the bits will be time multiplexed. First you give the row address which is 10 bits
then you give the column address which is again 10 bits. So we will have two additional
components, one of the components we call as row latch and decoder because I have to have row
address decoder. Then among the other additional components we will have because once you
give a row address, the entire row of the cells is selected either for read operation or for write
operation and in this case every row consists of 1 k number of cells. So here I need 1024 number
of Sense/Write Amplifier and column latches. That means the entire 1024 number of cells
belonging to a particular row will be latched into this 1024 number of column latches. From this
1024 number of columns, I have to select out one particular bit which is to be done by the
column selector or a multiplexer.
So I have to have another component which will be 1024 to 1 multiplexer or demultiplexer from
1 to 1024 that will be needed for the writing operation. In addition to this I have to have a 10-bit
column address latch and here I have to have controller and these are all additional circuits which
are not needed in case of static RAM array. This controller will accept 10 bits of address A0 to
A9, in one case these 10 bits will contain row address, during other time instant these 10 bits will
contain the column address. So initially the 10 bits of row address has to go to the row address
4
latch, here also you have 10 bits and at later instant of time the 10 bits has to go to column
address latch, when you feed the 10-bit column address. In addition to this there has to be control
signal given to the sense write amplifier and column latches. We will also have control signals
coming to the 10-bit column address latch. Now inputs to this controller, so this is the control
logic.
In addition to this 10-bit address pins, we have to have some additional signals to identify that
when you feed the row address or when you feed the column address. So I have two additional
signals, one is called RAS or row address select. Normally this is given in the inverted form so
we have RAS , the other control signal is CAS or column address select bar. In addition to this
we also have to have the control signal of the R W . So when this 10-bit row address comes to
this row latch, row address latch and row address decoder this will give 210 that is 1024 number
of row select lines. So depending upon and one of these will be activated at a time and depending
upon which line of this 1024 lines is active, the corresponding row in this 1024x1024 DRAM
cell array will be selected either for read operation or for write operation. That means this entire
row will be available to this 1024 Sense/Write Amplifier and column latches.
So here also we have 1024 number of lines, from this the same 1024 lines is also available to this
multiplexer, demultiplexer as well as 10-bit column address latch unit and from here I can have
inputs and outputs. So if it is output that has to go through a output buffer, if it is for input
purpose then demultiplexer will be active which gets an input from the input buffer. These
buffers are to be activated from the control logic only depending upon whether the signal is a
read signal or a R W . So this is say dith output line and this is the output line and this is the
input data. So this is the entire unit of a RAM chip and the RAM chip organization is something
like this. So whenever you give the row and row address select, these two control signals
together, the 10-bit data which is available on this row address lines that go to row address latch
and decoder.
Depending upon the decoder output, one of the rows consisting of 1024 number of cells will be
available, will be active which comes to this Sense/Write Amplifier and column latches from
where it is available to multiplexer demultiplexer unit. now when you give the column address,
simultaneously the column address select this has to be active following which the column
address 10 bits is latched into this 10-bit column address latch and depending upon what bit you
have addressed, what 10-bit combination is latched in this column address latch unit, the
multiplexer and demultiplexer unit will act accordingly and depending upon that you have one
bit at the output or one bit is selected for writing into a particular part. Now find that as I said, I
also have to have a provision of refresh. So the refresh operation in this case can be done like
this, if I give only the row address select input with the row address, I don’t provide any column
address. In that case the operation that will be performed is read the particular row, amplify the
content and write it back. So then the unit which is active is only this part in the refreshing unit,
this part does not come into picture.
So only this is the portion along with the row latch and decoder and the control logic that takes
part in the refresh operation. This multiplexer, demultiplexer unit are 10 bit column address
latch, this unit does not take part in the refresh operation and you find that this unit is active only
5
when the CAS is active that means we provide a column address. So data from one of the cells
will be available on the output data line, when you give the proper column address along with the
column address select or data from the output will be written into one of the cells in this DRAM
cell array again when you give the column address along with this column address selected input.
And this is the line which is connecting to the external world.
So as we have seen that in case of static RAM, only when you give the chip select then only the
data lines gets physically connected. If your chip select is not active then the chip does not give
any output on the data line neither it accepts any input from the data line. The same operation is
done by column address select in this case. So in case of dynamic RAM, we don’t need any
additional chip select input. It is a column address select control input that acts the purpose of
chip select also. So in this case your operation will be, you have to provide RAS followed by
CAS when either read or write operation will be performed along with refreshing. If you provide
only RAS , no CAS then read and write operations will not be performed on this DRAM,
DRAM cell array but the operations which will be performed on the DRAM cell array is simply
refresh operation.
Say as I said that if I don’t perform any… One case is in case of DRAM cell if I perform any
read operation, the capacitors are going to be discharged. So I have to recharge it, which is done
by the Sense/Write Amplifier portion but even if I don’t perform any read operation, even then
the capacitor gets discharged if it is left untouched for a long of period of time. So I have to
perform some refreshing operation and because there is no read or write operation to be
performed on this that means CPU does not want any data from the DRAM, so CAS will not be
active. So I have to have an additional controller in the DRAM unit. What this diagram I have
given, it is only for a DRAM chip and number of such DRAM chips are to be connected together
to give you a DRAM board. I will come to that organization later.
6
In that DRAM board, I have to have an additional control unit which will generate only this RAS
signals along with the row addresses coming sequentially. So it will be responsibility of that
controller that even if the DRAM is not read or written into, the additional control unit will
provide the row addresses along with the RAS signal at regular interval so that different DRAM
locations are refreshed. But it does not generate any CAS signal because CAS signal is only
needed, this column address select, only needed when the CPU wants to read some data from the
DRAM or the CPU wants to write some data into the DRAM because CAS signal is connecting
this to the external bus. So this is the logical organization of a DRAM chip.
I will come to the DRAM board organization or the SRAM board organization now. So far what
we have discussed is individual DRAM chips or individual SRAM chips. Now when we design a
memory module or a memory board depending upon the system requirement, I will have to
connect more than one chips in proper fashion so that I can have sufficient number of locations,
memory locations not only that I can have sufficient number of bits per location. Say for
example in this case every DRAM chip will give you one bit per location but if I want to
organize this, so that every location should contain 16 bits, I have to connect so many DRAM
chips in parallel. Not only that this is also true in case of SRAM. If I have an SRAM chip which
is a nibble organized that means every location in the chip contains 4 bits but maybe my bus
width is 16 bit.
So for proper or efficient data transfer, I need that every memory location should contain 16 bits,
so that all the 16 bits can be read or written by a single memory access operation. So in such
cases I have to combine or I have to connect 4 such chips in parallel so that for every read or
write operation I get 16 bits together, I can read out 16 bits from every location or I can write 16
bits in every location of the memory. and I feel you have already done that in your previous
course that how to connect different memory chips for memory expansion. Say for example if I
have a memory chip, where every location contains let us say s number of bits. By now it should
be clear that if I have an static chip, static RAM chip then the logical diagram of a static RAM
chip is something like this. It has to have a number of address lines.
The address lines are internally divided into row address and column address part. So I have to
have a number of address lines then I have to have a R W signal, it will have one or more chip
select lines. In some chips I can have a single chip select line, in some other chips I can have
multiple number of chips select lines. and I have to have a number of output data lines, input
output data lines, so that is S. So using such a type of memory chip, if I want to have say p.s
number of bits per location then what I have to do is, I have to connect p number of such chips in
parallel. The chip select inputs of all the chips will come from a common chip select input and
this is the one which decides whether your chips are connected in parallel or the chips are
connected in serial fashion. So this is a common chip select input which selects all these chips
simultaneously.
7
(Refer Slide Time: 00:21:47 min)
Then again because we are connecting them in parallel, so zeroth address in this chip must be
same as zeroth address in this chip, it should also be same as zeroth address in this chip. That
means every location in every chip should conform each other. So what we have to do is, we
have to have common address lines which should go to all the chips in parallel. So these are the
address lines. I should also have common read write lines, so this is R W . In case of data lines
what you have to do is, they have to be concatenated. For each of the chips we have s bit data
lines, when they are concatenated they give p.s number of data lines. So this gives you the simple
parallel connection of p number of chips to expand the data bus by factor of p. So this is a simple
parallel connection.
Now if we want that we don’t want to increase the number of bits for the data bus but we want to
increase the number of locations in the memory then instead of going for such a kind of
connection, what you have to do is, we have to play with the chip select lines. So assuming that
every chip has got say m number of address lines and the number of locations that we want to
have is 2m. So what we have to do is from the CPU, we have to give an address which is k + m
number of bits, m number of bits per chip gives you 2m number of locations. I want to connect 2k
number of such chips in sequence. So total number of address lines becomes k + m, out of this k
+ m address lines, the higher address k bit addresses, I give to a k to 2k decoder. So I will have 2k
number of output lines from this decoder. I connect 2k number of chips in such a way that chip
select of every chip will come from one of the decoder outputs.
8
(Refer Slide Time: 00:26:34 min)
So maybe chip select of this chip is coming from this decoder output, chip select of this chip will
come from this decoder output. So similarly chip select of this chip will come from this decoder
output. Now once a particular chip is selected, a particular location in the chip can be selected
independently. So in that case what we will do is we will provide the address lines to all the
chips in parallel, these m bit address lines. So whenever this chip is selected, this m bit address
lines, the m bit address is effective only for this chip. Though, the address is going to all other
chips but for other chips that is not effective.
Similarly, when this is one selected, this m bit address is effective only for this chip. It is not
effective for other chips because others are not selected. What you do for read write lines? Read
write lines again can be common because that depends upon the chip select output, so I will
simply connect read write lines also in parallel. This is the R W signal and for the data lines
what you do is, you simply short all the data lines. Now in this case, it will not be concatenation
because concatenation is needed when I wanted to increase the number of bits per location. In
this case the number of bits per location will remain the same, only the number of locations has
to increase. So you simply connect all the corresponding data lines together and the number of
bits on this data line, you get s number of bits. And this connection is possible because we said,
when you discussed about the memory cell that for every input and output, for every cell we
have buffers and it is because of the buffers we can connect them together. If there was no
buffer, such a connection would not have been possible. In that such case what we would have to
go for is again a multiplexer demultiplexer there. So this kind of arrangement whether this one or
this one, they are linear arrangement.
Now if I want to have a situation that I want to increase the number of bits per location, at the
same time I also increase the number of locations in the memory board, what I have to do is, I
have to use combination of this and this. So once I, once I have this parallel combination, you
9
can think that this entire assembly looks like a memory module having, if m is the number of
address lines, 2m number of locations, every location consisting of p.s number of bits. This whole
thing I can consider a memory module of 2m locations, every location consisting of p.s number
of bits. So what I can do is, I can simply replace each of these units by this module. So in such
case I can both increase the number of bits per location, also at the same time I can increase the
number of locations in the memory module. So here you find that in this organization, I have
made use of only one chip select lines and the decoder that I have used is k to 2k decoder.
Now if this k is large in that case the decoder complexity will also be very large but we have
already seen that when we discussed about the row column decoder, in case of a memory chip
that only purpose of dividing a single decoder into two decoders is to reduce the decoder
complexity. Similar concept can also be used in case of memory board. So if the value of k is
quite large in that case the, to reduce this decoder complexity, what we can do is, we can break
this value of k, the number of bits again into two components. For each component I will use one
such decoder, so both the decoders will give you some outputs. These outputs will now be used
to activate the chips. So I can have a situation like this that instead of having say k + m number
of address lines, suppose this k is broken into p + q number of address lines plus m number of
address lines per chip.
Now I will have two decoders, one decoder will be say p to 2p decoder, here I take out p number
of address lines. Out of this q address lines can go to q to 2q decoder, so this is one decoder, this
is another decoder. Here I will have total 2q number of outputs, here I will have total 2p number
of outputs. The chips I will organize in the form of a two dimensional array. So like this, the
chips will be organized and here I assume that every chip will have two select input lines, one is
chip select one, other one is chip select two.
So now the chip select inputs can be used like this, that every decoder output will activate one of
the rows. So I connect this here, this here, this one here. Similarly, this decoder output can
10
activate the next row and this way it can continue. For column for the other select input, we will
use the output from the second decoder. So I can put it this way that this decoder output will
activate this chip, this same decoder output will activate this chip. This decoder output, the
second decoder output will activate all the chips in a particular column, so it will continue like
this. So now you find that only when this decoder output is active and this decoder output is
active then only this chip is active, other chips are not selected.
Similarly, when this is active and say this one is active, the same decoder output is active then
this chip will be selected. So this way now I can divide the memory cell array in two dimensional
cell array like this and the advantage is the complexity of the decoder is reduced to a great
extent. Regarding your address lines and other address lines, other m bit address lines they will
go parallely to all these chips, read write signals will go parallely to all the chips and the data
lines will be connected together. So unlike in the previous case where the memory chip array
was one dimensional array, in this case the memory chip array is a two dimensional array and
accordingly I have two decoders, one of them may be called as horizontal decoder, the other one
may be called as vertical decoder.
Now this same concept can also be extended in case of dynamic RAM chips. So if we want to
have a dynamic chip, RAM chip array, we have said that in case of dynamic RAM chips, the
function which is done by chip select in case of static RAM chips, the same function is
performed by CAS in case of dynamic RAM chip. And it is the dynamic RAM chips that can be
used, that can be used in a multidimensional array and the different array components can again
be selected through a number of decoders. So in case of dynamic RAM chip, the organization
can be something like this. Firstly, we have to have a CAS signal, if whenever the RAM chip is
connected to the external data bus.
11
Now this CAS signal in case of dynamic RAM can be used to activate a decoder, this is a
decoder. The decoder will have a number of data bits, number of address bits as input and it will
obviously generate some outputs. So you find that this decoder will be active only when you get
the CAS signal. Again if we want to go for a multidimensional array then what can be done is,
these outputs of the decoder can be used to activate other decoders and these decoders in turn
will get a number of other address lines. So if I assume that here I have a number of address lines
say Kc + Kr, where Kr is the number of rows, 2Kr will be number of rows and 2Kc will be number
of columns. So, total number of chips that we can address is 2Kc + Kr. So out of these address
lines, say here we give say Kc address lines and Kr number of address lines are connected to each
of these decoders, so like this it will continue. Then we will have a number of memory chip
arrays.
What I can do is, output of this decoder can be connected to CAS of this array. Similarly output
of this decoder, yeah other output can be connected to CAS of this memory chip. Similarly, this
can be connected like this, this goes to CAS of this chip. Similarly, this output can go to CAS of
other chips. So you find that when this memory chip will be selected, this decoder output is
active and also this decoder output is active. So if I say that this is zeroth output of this decoder
and this is also the zeroth output of this decoder then when both Kc and Kr, both of them are zero
then only I am selecting this particular chip. Now if this is the, I have given Kr number of bits,
address bits to this particular array, this particular decoder, so this output may be 2 Kr output,
2Kr-1 output. So this select, whenever this is active that indicates that Kc is zero and all the bits, all
these Kr bits are equal to 1 then only I am selecting this particular memory chip. And if I assume
that every location in the dynamic RAM array, in the dynamic RAM chip will be one bit and I
want to have say s number of bits then what I have to do is, I have to connect s number of such
dynamic RAM chips in parallel. So it will continue this way and CAS of all these dynamic
RAM chips will be connected in parallel.
So whenever I do this and otherwise your R W signal or the remaining m number of address
signals, similarly data bus all of them will be connected in the same way as we have done before.
So the selection mechanism which is only important is the way you select a particular dynamic
RAM chip through the CAS signals. So along with this, as we said that we have to have
something to generate and similarly RAS signal which can also go parallel to all these chips
because until and unless CAS of a corresponding, of a particular assembly is active that
particular unit will not be selected. So RAS signal can go parallely to all the chips, R W signal
can go parallely to all the chips. Then address lines can be combined depending upon the way we
want. what additional thing we have to have in the memory board is the control arrangement
which will take care of the refresh control, which will take care of how to generate the read write
signals, which will take care of the board select and chip select also of course comes from these
decoder logics. So that part we will do in the next class.
12
Digital Computer Organization
Prof. Dr. P. K. Biswas
Department of Electronic and Electrical Communication Engineering
Indian Institute of Technology, Kharagpur
Lecture No. # 22
DRAM Architecture Buffer Cache
So this is the complete three dimensional DRAM chip array that we started drawing in the last
class but we did not complete.
Here you find that you have a set of address decoders and the address decoders, one of them is a
column decoder. So this address decoder is a column decoder whereas the other address
decoders, I can have a number of such address decoders which are actually called row address
decoders. Now the number of address bits which will come to this unit is Kc + Kr. So the total
number of address bits will be Kc + Kr + m, this is the total number of address bits that will come
to this three dimensional memory chip array. Out of that Kc and Kr number of bits are used as
row address identification and column address identification whereas this m bits, m number of
bits is actually divided into two halves m and m which you have seen that when we discussed
2 2
about the DRAM chip that first you have to give the row address along with RAS signal
followed by the column address along with CAS signal. So this m number of bits, this actually
addresses different locations in the memory chip. So this is divided into two halves m and m
2 2
which is here represented as multiplexed address m number of bits. So out of this Kc and Kr
2
number of bits, Kc number of bits goes to the column address decoder and depending upon the
bit combination of this Kc number of bits, one of the columns will be active. So if all the bits are
0 in that case zeroth column is active and that will activate this particular row decoder. Similarly,
1
if Kc contains a 0 0 0 0 0 1, then the first decoder output will be active which will activate the
next row address decoder.
So once you decide, you enable a particular row address decoder then output of the row address
decoder will depend upon the Kr bit combination. So you find that when Kr, all the bits in Kr are
0 in that case the zeroth output of all these row address decoders are supposed to be active that
means we are going to activate a particular row in this two dimensional chip array. So that is
why these are row address decoders. And out of all these decoders, the decoder which will be
active, which will be enabled that depends upon the corresponding output of this column address
decoder. So you find that as we said that in case of dynamic RAM chip, we don’t need any chip
select because it is the CAS signal which gives the same function as chip select. So it is the CAS
signal which enables the column address decoder. Then output of column address decoders
activate or enables different row address decoders.
So using this Kc and Kr combination, you activate one of these memory chip combinations and
here you find that I have given, every unit is given as an array of a number of memory chips
because as we discussed that in case of dynamic RAM, if we have that every location contains
one bit, say 1 m x 1 memory organization that we discussed, there if we want to have that every
memory location should contain 8 bits in that case I can connect 8 such dynamic RAMs in
parallel. That is why I have shown each of these units as an array of memory chips where within
this all the memory chips are connected in parallel. That means they are CAS signals are
connected together, RAS signals are connected together, address signals are connected together
so that way all the chips in each of this module, each of this unit are parallel.
So once I select a particular module in that case, in that module I have to give the multiplexed
address which is m number of bits. So first we have to give m number of row addresses along
2 2
with the RAS signal. RAS signal for a particular module is also connected in parallel, so that is
how it has been shown here. So for these memory chips, you have the same RAS signal. So
when you give the row address on m number of address bits along with that the RAS signal,
2
RAS signal has to be enabled and once you give this RAS signal then with the help of the CAS
signal, the CAS of the corresponding module will also be enabled, along with that CAS signal
you also have to give the m number of bits for column address. Then if it is a read operation
2
then this R W line has to be made high. When the corresponding memory module will be read
and the output will be available on this data output lines and here you find that the data output
lines of all these chips in a particular module are also connected in parallel.
So this is how we can generate a three and I am calling it three dimensional array because each
of this modules, the memory modules are arranged in a two dimensional array. Within every
module, we have another dimension where a number of chips are connected in parallel. So the
total array, the total modules becomes a three dimensional DRAM array but still it is only the
chip organization, it is not the DRAM board because as we said that what comes from the CPU?
The CPU gives a number of address bits, the CPU gives either the read signal or the write signal
and the CPU gives a number of data bits, data lines but the CPU does not give you CAS or the
2
CPU does not give you the RAS and we can also assume that the CPU, if the CPU gives
different read line and write line then we have to combine those read lines and write lines into
R W ; R, W line into a single line.
So using such a type of three dimensional array, if we want to construct a memory module, a
memory board in that case we have to have some additional control circuits which will provide
all these signals. That means the control signals which are given by the CPU should be converted
in such a form that the control signals become compatible with this three dimensional DRAM
array. So the modules in case of a DRAM board will look like this.
First the CPU gives you a number of address lines. So initially let us have an address latch or
address register which latches the address lines or the address bits given by the CPU. So I have
to have an address register. Now all the address lines which are given by the CPU should come
to this address register. So let me assume that the CPU gives let us say K + m number of address
bits, out of which this K number of bits will be broken into 2 components Kr and Kc and they
will be used for addressing a particular module within the three dimensional DRAM chip array,
m number of bits will again be divided into two components m and m which will be used for
2 2
addressing a row and then addressing a column in a particular chip.
So this entire address will be divided into three components, in one component I will have K
number of bits then I will have m number of bits, I will have another component of m
2 2
number of bits. And suppose the DRAM chip array is placed somewhere here, this is say DRAM
chip array. Now this K number of bits will come directly to DRAM chip array and this will act
for board and within the board chip select. Of course this has to work through all these decoder
units and all those things. the remaining m and m number of bits will be used to address a
2 2
row and then address a column and not only that whenever we feed some address to this DRAM
3
chip array, we have said that I have to have some refresh controller so that at regular intervals of
time, the refresh controller can refresh different locations within every memory chip.
So for that what we will use a multiplexer, two inputs to this multiplexer will come from this
m lines so that I can select one of these m lines to address this DRAM chip. The other
2 2
possible address input to this has to come from the memory refresh controller which will give the
row address whenever the memory is to be refreshed. So for that what I have to have is a refresh
counter, this is say a refresh counter and it is the counter which generates the row addresses in
case of memory refresh. I also have a refresh clock and control unit, so here I will put a refresh
clock and control unit and it is this refresh clock and control unit which will activate the refresh
counter whenever memory refreshing is needed.
In addition to this we have to have another unit, let us call that as memory timing generator. It is
this memory timing generator which will accept the request of read from the CPU, which will
also accept the request of write from the CPU and it is the responsibility of this memory timing
generator to give out a signal called ready to the CPU because unlike in case of static RAM,
where if you give the address then followed by read or write operation, the memory is ready for
reading data of that particular location or writing the data from that particular location. But in
case of dynamic RAM it is not so, the dynamic RAM has some sequential nature that is we have
to give the row address along with the RAS signal followed by column address along with the
CAS signal.
In addition to that there is some refresh operation that may also be taking place intermittently. So
the CPU has to know that whatever operation the CPU wants to perform on the dynamic RAM
that operation is complete. So it is the responsibility of this memory timing generator to give a
ready signal to CPU and the CPU accepts the ready signal to know that the RAM is ready. So
you find that even in case of 8085 CPU, you have an input called ready input and the CPU can
continue with its work only when the ready input is high. If the ready input is low then the CPU
will incorporate wait states instead of t0 t3 t4 and all those things, after state t2 8085 will
incorporate wait states if it finds that ready line is low. So that is the purpose of this ready signal
which again has to be generated by this memory timing generator.
4
(Refer Slide Time: 18:48)
Now what are the control signals that this memory timing generator has to generate? One is the
CAS signal, so this will give you CAS signal, it also has to generate R, W combined signal
because from the CPU we get two different lines, one for the read operation and other for write
operation. but in case of DRAM chip we have seen that it needs a single line, if high then it is
read operation if low it is write operation so that has to be combined by this memory timing
generator. The other signal that this memory timing generator has to generate is RAS signal but
RAS signal is needed in two different cases. One is to perform a read operation or write
operation on this DRAM chip array and the second way when this RAS signal is needed is for
refresh operation. That means I have to have two generators for RAS signal, one from this
memory timing generator which will generate the RAS signal in case of read or write operation
and the other for refresh operation which will be generated by this refresh clock and control unit.
So I will have two sources of this RAS signal and these two RAS signals will be, let us put it this
way say logically OR together and this output becomes the RAS signal for the DRAM chip
array. Now for refresh operation what has to be done is you find that if there is a write operation
or there is a read operation, write operation means refresh is already done.
If it is read operation, then following every read operation there will be write operation or refresh
operation. But this refresh clock and control unit that works in parallel. So if the refresh interval
is say 4 ms may be at the interval of every 4 ms I have to refresh the DRAM chip. So what this
refresh control clock and control circuit will do is it will keep count of 4 ms after every refresh is
complete. At the end of that 4 ms interval, it will put a request to this memory timing generator
that there is a time for refresh. So let us put it as a refresh request. On getting this refresh request
from the refresh clock and control unit, the memory timing generator will decide whether it can
allow the refresh operation to be performed now or the refresh controller will be asked to wait.
5
So accordingly this memory timing generator will give back a signal to this refresh clock and
control unit, the signal which is called a refresh grant signal. So if the refresh grant is issued, on
getting this refresh grant, the refresh clock and control unit will ask the refresh counter unit to
generate the memory addresses which had to be refreshed and this is nothing but a sequential
counter. Say if some read operation is going on or some write operation is going on, if at the
same time this refresh control unit puts a request for a refresh. The read and write means a
refresh will automatically be done. Isn’t it? Write means it is refresh, I am writing a new data. At
the same time whenever you read the content of a particular row, we have seen that in the
DRAM chip architecture that before you come to the external data bus, the entire row is read at a
time. It goes to the sense write amplifier, output of the sense write amplifier goes to a selector
where a particular is column is selected by the column address.
So whenever you read a particular row, the entire row is read. Even if you want to read a
particular bit, the entire row containing that bit is read up to the sense write amplifier. then the
sense write amplifier itself, following that read operation writes back the entire data into the
corresponding row but to the output to the external data bus what will be available is a particular
bit because that passes through a selector or a multiplexer. So every read operation is followed
by refresh operational automatically. So only when this refresh clock and control unit gets the
grant signal from the memory timing generator then it can ask this refresh counter to generate the
refresh addresses and not only that this multiplexer also has to be set properly because now the
refresh counter has to provide the row address, the row which will be refreshed.
So this multiplexer input will get two kinds of select inputs, so you can put it this way that one
select input will come from this refresh clock and control unit and it should also get the select
input from memory timing generator. So what can be done is here this can generate one bit, this
can also generate one bit, these two are combined together to give you two bit select lines
because there, here we have 3 input lines, so for three input sources I need two bit select lines. So
those two bit select lines can be generated in this way. Then output of the multiplexer that
actually gives you the address lines for the DRAM array. So here I will have m number of
2
addresses. So in case it is memory read or memory write operation, this m addresses will come
2
either from this m lines or from this m lines depending upon whether it is the row address or
2 2
column address.
In case of refresh, m addresses will come from the refresh counter and that has to be selected
2
through this select lines. Then finally this DRAM data lines will be connected to a data register.
Here we have a data register which will either accept data from that DRAM chip array or feed
the data to the DRAM chip array and we can assume that suppose the width of this data lines is
w. If I say width data lines is w that indicates that if every location in a DRAM chip contains one
bit, so if it is a bit organized DRAM chip in that case for every such module in this diagram there
has to be w number of chips connected in parallel because my data bus width is w bits whereas
for every RAM, for every DRAM a location contains only one bit and then finally from the data
register this w by 2 number of data lines goes to the CPU. So these are the data lines of width w,
these are the address lines of width K + m.
6
(Refer Slide Time: 24:45)
So you find that how the whole thing will work whenever the CPU wants to read a particular
location from the DRAM or once you write something into the DRAM, what the CPU will do?
CPU will give the address on this address lines and either read signal or write signal. Now on
getting this address and read signal and write signal, this memory timing generator will generate
the corresponding control signals which are needed for this DRAM chip array.
These address lines out of that K number of address bits will be used for selecting a board and
within a board, a particular chip, so when I say a particular chip that means a chip module like
this. Then RAS , it can be generated either from this memory timing generator or from refresh
clock and control unit. So these two are logically OR together and that gives the RAS signal to
the DRAM chip array. CAS signal is generated by the memory timing generator, so when I say
this generated by the memory timing generator, actually internally this signal will be combined
with this because if you look at this architecture, you find that CAS actually comes from this
unit. So this CAS signal which is generated by the memory timing generator is the CAS signal
which is given here but to the actual chip, the CAS signal comes from the column and row
address decoders.
Similarly, for refresh operation whenever refresh is to be done, the address is generated by the
refresh counter and through the multiplexer it goes to the DRAM chip and then finally from the
data register, the CPU can read the data or for writing a data into the DRAM chip, the CPU will
write the data to DRAM chip array through these data registers. So we have done three kinds of
memory organizations till now, the cache memory organization, static RAM organization and
dynamic RAM organization. And I think we have said that regarding the memory hierarchy in a
computer system, usually we have a two level hierarchy that is between CPU, from CPU I have
the main memory, between main memory and then from the main memory we have the
secondary memory usually that is the hard disk.
7
Now if you put the cache memory in between the CPU and the main memory that becomes a
three lever hierarchy. so whenever the CPU wants to read something, any data or wants to write
any data, firstly it checks that the block which will be read or the block which is to be written
into whether that is available in the cache memory or not. If it is not available in cache memory,
then only the CPU will try to find out that block in the main memory. If it is not even available in
the main memory that leads to what is called page fault interrupt.
Page fault interrupt that is page which is being looked into is not available in the main memory.
Whenever you have a page fault interrupt then the required data or the required page containing
the data has to be loaded from the secondary storage into the main memory.
Now between the secondary storage and the main memory, we have another layer which is
logical not physical layer. Say for example between main memory and CPU, we have another
layer additional layer which is cache memory and that is a physical layer. Cache memory must
be physically present but between the CPU and the main memory another level of memory
which is maintained which is a part of the main memory but logically it is managed in some
other way which is called a buffer cache.
So the entire hierarchy will be something like this. At the top most level you have the CPU, CPU
directly accesses the cache memory. Of course you might be knowing that we have two different
kinds of cache memories which are called L1 cache or L2 cache. L1 cache is the cache memory
which is in built within the CPU whereas L2 cache is the cache memory which is external to the
CPU but the architecture is same as the cache memory architecture. So here we can have cache
memory which again is optional, earlier systems didn’t have this cache memory. From the cache
memory we have main memory then finally we have the secondary memory usually the hard
disk.
Now instead of directly connecting the main memory to secondary memory, a partition is
maintained in the main memory which is called a buffer cache. So I will make it attached with
8
the memory. So this is a unit which is called a buffer cache which is a part of the main memory
and directly controlled by the operating system. this is not the part of any of the user spaces that
we discussed earlier, while you talked about the memory organization, main memory
organization we have said that the main memory is divided into a number of partitions, some of
the patricians are given to the operating system whereas rest of the partitions are given to
different users.
This buffer cache is actually the operating system area; it is not the user area. So whenever
anything is to be read, is to be accessed from the secondary storage, a block containing that
required data is put into the buffer cache. From the secondary storage I cannot read a single byte
or I cannot read a single character, I have to read the entire block containing that character. The
block will go to the buffer cache; from the buffer cache it will go to the user area. So the entire
memory hierarchy will be something like this. So effectively we have 3 level hierarchy cache
memory, main memory and secondary memory between main memory and secondary memory
you have the buffer cache. So in case of page fault when the required data is not available in the
main memory, when I say not available in the main memory means user space in the main
memory.
If it is not available in the user space in the main memory then there would be a page fault,
following page fault I should go to secondary memory to get the data. now before going to the
secondary memory what the operating system does is, it tries to find out whether that data is
available in the buffer cache or not. If it is available in the buffer cache, then I don’t have to read
it from the secondary storage. From the buffer cache it can be written to main memory,
subsequently to cache memory and subsequently to the CPU. In case the required data is neither
available in the buffer cache then only we have to physically read it from the secondary storage.
Now this buffer cache is maintained as a linked list of different memory areas.
9
When I talk about the buffer cache, the buffer cache actually has two portions. It has called, it
has got a cache header. Now whenever I say cache, now it will mean buffer cache not the cache
memory. So it will consist of a cache header, it will also consist of a cache data area.
Cache header will consist of a number of fields. Initially the first few fields will contain the
device number because in a computer system, I can have more than one hard disk or even if I
have a single hard disk that can be logically divided into more than one hard disk. I can have c
drive, I can have d drive, I can have e drive and so on. Each of them will have a different device
number. So one field will contain the device number and the other field will contain the block
number. Now what are these blocks in the secondary storage, I will come to that later. So for the
timing being, you assume that every device is divided into a number of blocks. So whenever I
have to read any data from the secondary storage, of course I can have two types of devices,
some devices are block devices, some devices are character devices. For example, a printer is a
character device. Whenever I want to take some printout, I can send character by character to the
printer, I can get character by character print out.
Similarly, keyboard is a character device. I can enter a particular character; a character can be
read by the CPU through the keyboard unit. But a secondary storage it’s a block device, from the
secondary storage, I cannot write a single character to a secondary storage, I cannot read a single
character from the secondary storage. So logically I can think that a secondary storage is divided
into a number of blocks where every block will consist of a number of bytes. the length of a
block can be say 512 bytes, may be 256 bytes, may be 1 kilo byte, may be 4 kilo bytes and so on
that depends upon how the installation has been made. And whenever I have to write anything to
a particular block, suppose I want to write a single character in the particular block, I cannot
write a single character to a block physically. What I have to do is I have to read the entire block
to the buffer cache, from the buffer cache it has to be brought to user space in the main memory.
In the main memory I can modify that particular character. May be I don’t want to modify the
entire block; I want to modify a particular character in that block so that has to be done in the
main memory. Then once you modify that particular character in the main memory then you
have the entire modified block and if it is to be reflected on the secondary storage then this entire
block has to be written on the secondary storage. so these are block devices, so I have to have the
device number and block number, the block which is contained in that particular buffer. Then I
have to have another field called status field. This status field says what is the status of the
buffer? whether this buffer is being currently used by some process or locked by some process,
whether the buffer is free, whether the buffer contains some data and marked as something called
delayed write?
What is this delayed write? Suppose I have a situation in which case a particular buffer contains
some data but at some point of time, I decide that these buffer should contain some other data.
Now when the buffer has to be written by the data from some other block from the device, at that
time I have to check whether the data is there in the buffer should be saved on to the disk before
overwrite or it is not to be saved. If the data contained within the buffer is different from the disk
content of the same block, in that case before you overwrite the buffer, the buffer should saved
on to the disk because otherwise the disk will not get the updated data. whereas if the content of
the buffer and the content of this disk block is same, in that case I need not save the buffer to the
disk because copy of that is already existing on to the disk. So I can simply overwrite the data by
10
a new block. So all those information are to be contained in the status field. Then it has a number
of pointer fields. As we said that I have two areas in a buffer, I have a cache header and I have a
cache data area, this is actually the header. From the header I have to be have a pointer which
points to the data area. There are a number of other pointers, one pointer points to next buffer in
the hash queue, I will come to hash queue later on.
As I said that all the buffers are maintained in the form of a linked list, so I have to have a
number of pointers. So one pointer is pointing to the next buffer in the hash queue; another
pointer pointing to previous buffer in the hash queue. One pointer will point to next buffer in free
list and I have to have one more pointer which points to previous buffer in the free list. Now let
us see what are this hash queue and what is this free list? Hash queue is suppose, I decide that the
system should contain 1000 buffers. So for 1000 buffers I will have 1000 such headers, I will
have 1000 such data areas. So when I have 1000 buffers then there can be 1000 different data
blocks, disk blocks present in the buffer simultaneously.
Now at a particular time suppose the CPU encounters a page fault and following the page fault,
the CPU finds, the CPU determines that it is a block number 5 which has to be read from the
secondary storage. and as I said that before going to the secondary storage, before actually going
to the secondary storage, the CPU will try to find out or the OS will try to find out whether block
number 7 is present in the buffer cache or not because if it is present in the buffer cache then
time to access that particular block will be very small because this buffer cache is maintained in
the main memory. I don’t have to read it from the secondary storage.
So first, the OS will try find out whether block number 5 is present in the buffer cache or not.
How does it do it? For every buffer I have a header, the header contains block number. so the OS
can go to the head of this linked list, the first node in the linked list checks whether block number
5 is present in this buffer cache or not. If block number 5, it gets block number 5 a match then
that particular data area of the buffer can be copied to the user space and the process gets the
required data. In case it finds that block number 5 does not match with the first entry, the first
node in the linked list it has to go to the second node, if it does not match there it has to go to the
third node and so on.
So if I have 1000 number of such nodes then in the worst case, I have to have 1000 search
operations to find out whether the block exists in the buffer or not. Now in the worst case if the
block actually does not exist in the buffer, I have to have 1000 search operations because until
and unless I search for every buffer, I cannot say that the block does not exist. So on an average
the number of search operations that has to be performed, to find out a buffer is quite large and it
is linear with the number of buffers that we will have. So to reduce that what is done is this
buffers are maintained in two lists, one is the hash list and the other kind of list is free list. Now
why do you go for hash list? To reduce the search time. So if we decide that in a system, I will
have say 4 hash queues then a simple hash function that can be used is say (Block No.) mod 4 .
11
(Refer Slide Time: 00:44:06 min)
So if I perform this block number 4, block number mod 4 this can give me 4 possible values, one
of 4 possible values 0, 1, 2 and 3. So accordingly I can have 4 hash queues, every hash queue
will have a header which will identify that whether it is hash queue 0 or hash queue 1 or hash
queue 2 or hash queue 3. Whenever you search for a particular buffer, you perform the same
hash function, find out what is the hash value. If the hash value becomes 2 say for example I
want to find out whether block number 6 is present in the hash or not, so I will perform 6 mod 4
which gives me a value 2. So if block number 6 exists in the buffer, it has to exist in hash queue
number 2. It cannot exist in any other hash queue. So I will only search those buffers which are
present in hash queue number 2, I will not search in any other hash queue for block number 6, so
that can reduce the search time to a great extent. We will have more discussion on this in the next
class. Thank you.
12
Digital Computer Organization
Prof. P. K. Biswas
Department of Electronic and Electrical Communication Engineering
Indian Institute of Technology, Kharagpur
Lecture No. # 23
Buffer Cache
So, in the last class we have started our discussion on buffer cache and we have said that when
you talk about the memory, memory is basically organized in a three level hierarchy.
So at the lowest level in the hierarchy, we have the secondary memory which may be hard disk,
which may be magnetic tape, which may be floppy drive and all those things. At the higher level
we have the main memory and still higher level, we have the cache memory which has direct
access to CPU. Now we have said that in between these two levels that is main memory and
secondary memory, we introduced one more level which is called a buffer cache and this buffer
cache is actually an interface between the main memory and secondary memory and the buffer
cache is maintained in the main memory under direct control of the operating system.
So whenever we want to read any data from the secondary storage, we have already said that I
cannot access an individual character or an individual byte from the secondary storage.
Whenever I have to read any byte, I have to access the block containing that byte. This block
may be say 256 bytes, block may be 512 bytes, 1 kilo byte and so on. So whenever the user
process puts a request for any data or any instruction which is not available in the main memory
or in the cache memory that has to be read from the secondary memory, that means the block
containing that data or that instruction has to be read from the secondary memory and put to
main memory subsequently to the cache memory.
So to improve the performance of the system, what is done is in between the main memory and
secondary memory we introduce another layer that is buffer cache which is part of the main
1
memory. So whenever a block is read, the block is read from the secondary memory and put into
the buffer cache and it will remain in the buffer cache until you have a situation whether when
this buffer cache content has to be replaced or overwritten by the content of another block from
the secondary storage. So by this time it should be clear that I should not have or we cannot have
duplicate copies of a secondary block, a block of the secondary memory into the buffer cache.
There has to be only one copy of a particular block of the secondary memory into one of the
buffer caches. Then we have said for proper management of the buffer cache, the buffer cache
contains mainly two parts. One is called the buffer cache header and the other part is called the
cache data area and it is this data area which will contain the content of a particular block.
So, naturally the data area of a cache must be of same size which is the size of a block on the
secondary storage. So if the secondary storage is of 512 byte blocks, every block on the
secondary storage contains 512 bytes then the buffer, the data area in the buffer cache must be at
least of 512-byte size, it cannot be less than that. It can be more than that but the remaining part
will be wasted and we said that the cache header contains various fields. It contains a field for
the device number because in an installation, we can have more than one file systems or more
than one discs, even if it’s a single disc but logically a single disc can be partitioned into more
than one discs. So every such logical partition will have a device number. So buffer cache header
will have one field which will contain the device number then the second field will contain the
block number of that device. Then it has a status field, the status field contains various
information, for example one of the information can be whether this buffer cache is currently
being used by some process or not. So whenever any process makes use of some buffer cache
then while that buffer cache is in use by that process, the buffer cache cannot be used by any
other process until and unless it is released by the process who is using it.
So in the status field you maintained an information whether the buffer cache is free or the buffer
cache is locked. If it is locked, no other process can access it. If it is free other processes can
access it. So when a process starts using a particular buffer cache firstly, what has to be done is,
the buffer cache has to be locked then use it, then at the end you unlock the buffer cache and
2
come out. Among other information that can be stored in the status field is whether the content of
the buffer cache is valid or it is invalid. There is one bit, you set that bit equal to 1 whenever a
process uses it. See why we need the buffer cache. We need the buffer cache because from the
secondary storage, if I want to get a new block I don’t transfer the new block in single step to the
user area. I first transfer it to the buffer cache then from the buffer cache it will be transferred to
the user area and in the buffer cache, it will retained, until and unless I face a situation that I have
to bring in a new data block into the buffer cache and I don’t find any other buffer cache which is
free to contain this new data.
So only in that situation, one of the buffer caches will be overwritten by the new block content
and whenever you overwrite, so that overwriting will be done in the data area because it is the
data area which contains the content of a block. so whenever I bring in a new block content into
the buffer cache, I have to put that into the data area and at the same time all those header
information are to be modified. To increase the through put, to improve the performance of the
system. See firstly whenever a page fault occurs, firstly the kernel will try to find out whether the
data which is being asked for is present in the buffer cache or not. If it is present in the buffer
cache then from the buffer cache, the data can be transferred to the user area. So that being main
memory to main memory transfer, the time taken is very small.
In case it is not there in the buffer cache then only you go to the secondary storage because in
that case I don’t have any other option. So by introducing this buffer cache in between the main
memory, user area in the main memory and the secondary storage, the frequency of physical disc
access is reduced so that improves the performance. And locking means suppose the kernel is
making use of a buffer cache for getting the data from the secondary storage into that buffer
cache. While it is doing that, this status filed has to be, has to show the locked information
because while the data transfer is taking place between a particular buffer cache and the
secondary storage, the buffer cache, that particular buffer cache is being used by the kernel. So
until and unless copying of data is complete and the kernel releases the buffer, the buffer cannot
be used by any other process. Not only that, it can so happen that two processes are trying to
access, are trying to get the data from the same block on the secondary storage, so both the
processes and that will happen in case of page fault.
So the first process it finds that it encounters a page fault, it tries to get the data from the
secondary storage, a particular block of data from the secondary storage. So how does it do it? It
will invoke a system called for reading a block of secondary storage, following that system call
the control will be taken over by the kernel of the operating system. Now the operating system
will try to find out in the buffer pool or buffer queue whether the block which is needed exists in
any of the buffer cache or not. So for the first process it finds that the data exists in the buffer
cache. So now the data has to be transferred from the buffer cache to the user area because the
user will be operating on it, so the data has to be transferred from the buffer cache to the user
area.
Now while this transfer will take place, the status of the buffer cache has to indicate lock because
until and unless for the first process, the data is transferred to the first processes user area, the
same buffer cache cannot be used by the second process. Now once for the first process the data
has been transferred then the status field has to be marked as free, it is no more locked because if
3
it remains locked the second process will never get the access. So just after transferring the data
to the user area of the first process, the kernel will unlock this buffer so that now the request of
the second process can also be entertained, may be in the user area the first process will take a lot
of time to process that area but in the meantime the second process can also get access to these
buffer and the data can be transferred from the same buffer to the user space of the second
process.
Again while doing this transfer, the buffer has to be indicated locked so that if any other process
tries to access the buffer, during the same time there should not be time overlapped. Processing
cannot be done on the buffer area, processing can be done on the user area. But before that user
one’s area must have been overwritten by some other buffer content. It is not that whenever user
one finishes processing, it will lock the buffer because the data from the buffer is already
transferred to user one’s area. So until and unless it is requesting, user one is requesting for
another buffer, this buffer will not be locked. Whichever buffer that one puts a request that buffer
will be locked. So in the buffer pool I will have a number of buffers, different buffers will
contain different data blocks. The only purpose of putting this lock is I should not allow more
than one process to access the same buffer simultaneously.
For every buffer I will have such buffer header. If I have 1000 buffers in the system each, the
data area of each of the buffer has to be same as the block size of the secondary storage. Every
buffer will also have this header. So I will have 1000 headers, buffer headers, I will have 1000
cache data areas if there are 1000 buffers in the buffer pool. For every buffer I have to have a
header. So among other information which can also be there in the status field is whether the
content of that buffer is valid? See while processing, some process may find that there is some
data error in the data contained in the data area of some buffer. So moment it finds that it is
invalid then the content of the data has to be invalidated, content of the buffer has to be
invalidated.
4
So whenever such an invalid data is encountered, immediately some status bit in the status field
has to be marked saying that the content of this buffer is invalid, it should not be processed by
any other process. So likewise there can be many other information put in this status field that we
will come subsequently. Usually no. For the efficient utilization of the storage, that will help.
What you are saying is right but the moment I go for such a flexibility, the management becomes
too difficult. So usually what is done is for a particular file system, the block size is usually
fixed. I can have more than one devices on the system. say for example when you are working on
pc’s, you must have seen that you have c drive, you can have d drive, you can have e drive, you
can have f drive, each of them is a different file system. Logically they are taken as different
devices. Now this device number and block number taken together that uniquely identifies a
particular block in a files system. If I put only block number then I don’t know that this block
number belongs to what, whether it belongs to c drive or it belongs to d drive or b or belongs to e
drive and so on.
So these two together uniquely identify the particular block in the system and that is important.
Then among other things in the header, we have said that we have a number of pointers, one
pointer is obviously going to the data area because this is the one which actually contains the
data block. then we said that the buffers can be maintained, are maintained in two different
queues, one is the free queue that means when I said this status field, if the status field indicates
that the buffer is locked then this buffer will not be present in the free list queue. If the buffer is
unlocked or the buffer is free that is indicated in the status field, then this buffer will be existing
in the free list queue. When it exists in the free list queue that does not mean; that the data area of
this particular cache does not contain any data. It may contain a valid data which is actually copy
of block number on some device. So it will contain the valid data but the buffer is not being
currently used by any other, any process. so it will exist in the free list queue, simultaneously it
will also exist in the hash queue, so we have two pointers, pointing to hash queues and the hash
queue these pointers will determine that on which of the hash queues this buffer exists.
Now why we need hash queues? Suppose in a system, we have 1000 of buffers then following a
page fault interrupt what the kernel will do is, it will try to find out whether the block requested
is present in the buffer pool or not. For that it has to go for a linear search. So if I have say 10000
buffers in the system, the system is so configured that I have 10000 buffers in the system then in
the worst case before the kernel says that particular block does not exist in the buffer, it has to
make 10000 search operations. On an average to get a buffer, the number of search operations is
half of 10000 that is 5000. So tremendous amount of search time will be wasted just to see
whether the buffer is existing in the, whether the block exists in any of the buffer caches or not.
So to reduce the search time what is done is the same buffer is also maintained in a queue which
is called a hash queue. So this hash queue and the free list queue they are actually overlapped.
I don’t maintain separate buffers, one for the hash queue and other for the free list queue. It is the
same buffer which can simultaneously exist on a hash queue and also on a free queue.
If a buffer contains a data of any of the block, it will always be present in the hash queue but it
may not be present on the free list queue. So that is what we started saying that in a particular
implementation, if we decide that we will have say 4 number of hash queues. How do you decide
that hash queue? Whenever for the time being, let us forget about the device number, let us
5
concentrate on say suppose we have a single device in the system. So, only block number gives
you an indent unique identification of a data block on the file system.
So what we do is, we perform some hash function on this block number to decide that on which
of the hash queues, this buffer will exist, a buffer containing a particular block will exist. So the
simplest search hash function is a mod function. So suppose a process puts a request for say
block number 5 then hash function that will be performed is 5 mod 4 which gives you an output
of 1. So if there is any buffer containing block number 5 then that buffer must exist in hash
queue one, it will not exist in any other hash queues. So now instead of searching for all the
buffers, the kernel will search only buffers in hash queue one to see whether this block number 5
exists in the buffer or not. If it exists, it will exist only in hash queue one, if it does not exist in
hash queue one then there is no buffer containing that block number 5.
So the situation will be something like this. When I go for this mod 4 as a hash function then
what I will have is, I will have a number of buffers which will be placed in one of the hash
queues. So in this particular situation I will have 4 such hash queue. So this is hash queue 0, this
is hash queue 1, this is hash queue 2, this is hash queue 3. There will be 4 such hash queues
because I am making use of mod 4 as the hash function. And suppose there are a number of
buffers in this hash queue something like this. Device number is needed but that will lead to a
complicated hash function. So for simplicity I am assuming that only block number, I am having
a single device but that is needed. But the concept is still valid whether I go for a single device
case or multiple device case.
So I have situations something like this. So let me assume that I have 4 buffers in each of the
hash queues. Now this queue number 0 suppose it will contain block number say 28, say 32, 12,
64 something like this. this may contains a block number 5, block number 9, say block number
61, then tell me any number say block number 13. This may contains a block number 6, block
number 14 then say block number 38, say block number 26. This may contain block number say
6
11, block number maybe 23, maybe say 39 and say 51 something like this. So you find that if I
perform 28 mod 4 that becomes 0.
So if there is any buffer containing block number 28, it has to exist in hash queue 0. 23 mod 4
that gives you 3, so if there is any buffer containing block number 23, it has to exist in hash
queue 3. Within every hash queue, all these buffers are maintained in the form of a doubly
connected circular link list. So I can assume that these are the header nodes of every such hash
queue with these buffers connected in a doubly connected circular link list like this, so like this it
will be. So then as I said that a buffer can simultaneously exist on a hash queue and a free buffer
queue. So I also have to have a free buffer list with a header node, say this is free buffer list.
Free buffer list is also maintained in the form of a doubly connected circular link list. So here
because all these buffers are present in the hash queue, some of them will also be present in the
free list or maybe all of them will also be present in the free list, if none of these buffers are
being used by any of the process at a particular instant of time. So I can have a free list like this,
it can be present in any arbitrary form depending upon the way they are used. So all these buffers
are present in the hash queue they are also present in the free list; that indicates that these buffers
are not currently used by any of the process. Now how this buffer management is done?
Whenever a process puts a request for a particular data block following a page fault interrupt, say
for example a process has put a request for a data block let us say data block which is not present
in this buffer queue. Say for example the data block say 55 is it present? No, suppose a process
puts a request for data block 55. First, what you have to do is, you have to perform 55 mod 4 that
gives you a value 3. That means if the block, if there is any buffer containing this block number
55 it has to exist in hash queue number 3.
So I directly come to hash queue number 3, check the buffers present in the hash queue number
3. I find that there is no buffer with block number equal to 55 and this block number will be
identified by the block number field in the buffer header. So what I have to do is I have to match
this block number with the block number field in the buffer header and I find that there is no
buffer header in this hash queue which is having block number field equal to 55. So immediately
I say that this block does not exist in the buffer but the process needs this block, so I have to have
some way of getting this block from the secondary storage, put it into one of the buffers. For
doing that what the kernel will do is, it will simply check this free list because it knows that the
buffers which are present in the free list they are not used by any of the process at this moment.
And this buffer overwriting is done following LRU technique that is least recently used
technique, LRU least recently used technique.
7
(Refer Slide Time: 29:38)
Following the same logic that we have done in case of page replacement that assuming a buffer
which has been used most recently that will also be used next. So a buffer which is not used most
recently or a buffer which is used least recently that will not be used for a longer period of time.
So based on that assumption even this buffer replacement is also done following the LRU
technique. So this free list is so maintained that a buffer which is at the head of the free list that is
least recently used, a buffer which is at the tail of free list that is most recently used. When I say
head or tail that is following the forward pointer of the free list buffers. So following the forward
pointer the first buffer that you get that is the least recently used buffer and we should try to
replace the content of this buffer that is block number 11 by block number 55.
So what you have to do is we have to simply take out from this free list, replace the data content
by block number 55 and once this transferring data, copying the data from block number 5 to this
buffer is complete, we have to return this buffer to the free list until and unless it is actually
accessed by the process to transfer the data from the buffer to its user area. and when we return
this to the free list, we have to return it to the tail of the free list because now this buffer becomes
the most recently used buffer. So what you have to do is we have to simply overwrite this by
block number 55. And now which one becomes the most recently used? that is 55 which has to
come at the tail of the free list and the least recently used among all these buffers which are there
on the free list is this buffer containing block number 14 because earlier this was the least
recently used one which was at the head of the free list, now this has been taken out. So the next
buffer which is least recently used in the free buffer is block number 14. So I have to modify the
pointers like this and 55, it will appear in the same hash queue because it is hash queue number 3
only. So it will remain in the hash queue, same hash queue but its position number in the free list
will be different. Now your free list will appear something like this. The other nodes in the free
list remains intact.
So whenever a process puts a request for any of the data block, I can have one of the two
situations either the data block is present in the buffer cache in the corresponding hash queue or
8
there is no buffer containing that data block. So let us analyze these two different situations
individually. A is the most recently used.
So whenever a process puts a request for a particular data block then I can have two situations,
using this block number the kernel has to search the corresponding hash queue to find out
whether there is any buffer containing this block or not. Then I can have two situations, in one
situation the block does not exist in the hash queue and in the other situation I can have the block
existing in the hash queue. Now if the block exists in the hash queue then also I can have two
different situations that the kernel finds that the block exists in the corresponding hash queue but
the block is currently locked, the buffer is currently locked because the same buffer is being used
by some other process at that time.
So I can have a situation that it exists but locked. So if the block exists in the buffer and the
buffer is locked then the only way is because the data is already existing into the buffer, so I
cannot have another copy of the same data block into another buffer. So in this case the process
which is requesting for it that must go to sleep mode and the process will wake up when this
buffer becomes free. The second situation can be that the buffer exists and it is unlocked and that
is the situation that we expect. So if the block exists in the buffer and the buffer is unlocked or
the buffer is free then the process can use this buffer.
In the other case when the block does not exist in the buffer then also I can face various
situations. Block does not exist that means I have to physically read the block from the
secondary storage, put into one of the buffers which is free. I have to get the free buffers from
the free list, from the header of the free list. Now when I try to get this block, I can have a
situation like this that I find that the free list is empty because I can have a situation that all these
buffers which are present which are containing some data blocks they are being used at that
instant of time, all of them are being used by some process that means all the buffers are locked.
9
If all the buffers are locked, then obviously the free list will be empty because free list is a
dynamic situation. So here I can have a situation that free list empty.
So if the process finds that the free list is empty then again the process has to go to sleep mode
because I don’t have any other option because there is no free buffer where I can put this new
block. So the process has to go to sleep mode. Now there is difference between this sleep mode
and this sleep mode. What is the difference? Here when the block exists into the buffer, the
process sleeps until and unless that particular buffer becomes free and in this case the process is
looking for any buffer which is free and currently there is no buffer in the free list. So here the
process will sleep until and unless there is some buffer which becomes free. I am looking for a
free buffer, this free buffer can be taken from any of the hash queues but when the buffer
contains block number 55 then the buffer will be returned to hash queue number 3. See what I
have done here.
In this particular situation block number 11 was at the head of the hash queue, at the front of the
hash queue. So I have extracted block number 11, loaded block number 55 into this buffer. Now
incidentally in this case, the previous location of the buffer was hash queue number 3, after
loading the data from block number 55 the buffer has to be returned to hash queue number 3. So
here it remains in the same hash queue but if my situation was like this suppose this buffer was
absent. So this block number 14 a buffer containing block number 14 is at the head of the free
list. Process requests for block number 55, I have to get a free buffer from the head of the free
list. Now at the head of the free list, I have block number 14. so I have to take out the buffer,
overwrite this with block number 55 then when I return it to the hash queue, this has to come to
hash queue number 3, it cannot remain in hash queue 2 anymore.
So the new location of the buffer will be depending upon, what is the new block number that is
contained in that buffer? but this buffer, free buffer may be taken from any of the hash queues
because here we are interested in any free buffer which is at the head of the free list and that may
exist in any of the hash queues. So that is the difference between this one and this one. Here if
the kernel finds that the block exists in the hash queue but it is locked then the process has to go
to sleep mode and it will be in sleep mode until and unless that particular buffer becomes free,
not any buffer. But in this case the free list was empty and the block is not contained in any of
the buffers, so block has to be read new and any free buffer will serve the purpose because in any
case I have to read the data from the secondary storage and put into one of the free buffers. So
earlier position of the free buffer can be in any of the hash queues but the new position of the
free buffer will depend upon what is the block number that is being read. Is that okay?
So here the process goes to sleep mode until and unless any of the buffers become free. if any
buffers become free then that buffer will be returned to the free list, so free list no more is empty
and it is the same buffer which will be head of the free list as well as tail of the free list because
earlier there was no buffer in the free list, now one buffer has been retained. so whatever be the
earlier position of the hash queues, simply take out that buffer, overwrite that with the new block
and when you return to the free list of the hash queue you have to place it in the appropriate hash
queue depending upon which block has been read, clear? The other situation can be that free list
is not empty but it is marked as delayed write. Now what is this delayed write? We have said that
10
whenever we wanted to read a disc block, first we try to search that into the buffer cache just to
reduce the frequency of disc operations to be performed.
Similarly, if I want to write some data into a disc block or I modify any of the disc blocks then
first modification is done on the buffer cache, you don’t modify that immediately on to the disc.
If the data, if the corresponding block content is present in any of the buffer, you do the
modification in the buffer, don’t modify it on the disc immediately. But once you modify any of
the buffer content, you mark that buffer as delayed write and that delayed write information has
to be placed in the status field of the buffer cache. So if I modify the content of any of the cache
buffers, buffer cache then the status field of the corresponding cache header has to indicate a
delayed write mark.
Now why this delayed write is necessary because in case I have to overwrite this buffer with
another data block and maybe this happens to be the header of the buffer; the header of the free
list. As we are taking always a free buffer from the header of the free list for overwriting then
this is the block which needs to be overwritten by new data block. In that case if it is marked as
delayed write that means now the actual disc content is different from the content of the buffer.
When you read it, you copy the disc content into one of the buffers so they are identical. The
moment you modify the buffer then the content of the disc and content of the buffer are different.
So before you overwrite this buffer, what you have to do is you have to write the content of the
buffer on to the disc then only this buffer can be overwritten, otherwise all this modified data
will be lost. So if you find that the free list is not empty, the free list contained a number of free
buffers and so what I have to do is, I have to take the buffer from the header of the free list, from
the head of the free list and the buffer that I get from the head of the free list that is marked as
delayed write. if it is marked as delayed write then we have to initiate the process of writing the
content of the buffer into the corresponding disc block and this process, writing process what is
invoked is called an asynchronous writing.
Asynchronous in the sense that process who is requesting for the block has initiated this writing
operation but it does not wait for the writing operation to be complete because any free block
will meet the requirement of the process. So what the process does is it simply initiates this write
operation but without waiting for this write operation to complete, it searches for another free
block. so what will be done is in this particular case while loading this block number 55, we take
this block number 11 from the free list because block number 11 is at the header of the free list
and we find that block number 11 is marked as delayed write. So what we do is we simply
initiate writing the content of this buffer into block number 11 on the secondary storage, on the
disc but don’t wait for this buffer to become free because once you have started writing the
content of the buffer to the disc, the buffer must have been locked by the kernel. But you don’t
wait for this write operation to be complete. one way can be you let this writing operation be
complete then get this same buffer to load this block number 55 but instead of doing that because
in this case any of the free buffers will meet my requirement. So what I do is I simply start
writing this into secondary storage but without waiting for it I will try to look for whether there is
any other buffer in the free list which is free.
So initiate writing this block number 11 on to the secondary storage then you search for the free
buffer on the free list, another free buffer on the free list and you find that the next buffer is
11
block number 14 and it may so happen that block number 14 is not marked as delayed write. So
you get block number 14, write this block number 55 into block number 14. Now place this
buffer into this hash queue and return the buffer at the tail of the free list because it is the most
recently used one. But what will happen to this buffer? This buffer because we have start
initiated the process of storing this buffer back on to the secondary storage onto the disc. Now at
the completion of this write operation, the device rather will give an interrupt saying that the
writing operation is complete following that because this was locked only for storing the data on
to the secondary storage, once this writing operation is complete this block will become free but
still what I have done is, I have simply copied the data, the block still contains the data it has not
been overwritten. So it will be remaining in the same hash queue but now position in the free list
is likely to be different.
See what we are doing is every time we are returning a block to the free list, we are always
returning it to the tail of the free list because that is the most recently used block. But what is this
situation? In true sense it is not most recently used, it was least recently used in between we have
accessed this only to save the modified content onto the disc. So it is still least recently used. So
in this case what will be done is when you return this block into the free list, you don’t return it
at the tail but you return it at the head because truly speaking it is not most recently used, it is
still list recently used. So this is one situation when you returned a buffer to the free list I don’t
return it to the tail but I return it to the head. The status will be changed. The other situation is I
get a free buffer into the free list and that is not marked as delayed write. Free list and not empty
and not delayed write and obviously this is the situation that we expect when the buffer can be
used by the process to write the new data, so you can simply use the buffer. And obviously now
the new location of the buffer may be different depending upon which block is being read from
the secondary storage and put into the data area of the buffer.
So one situation we have said that when the buffer can be placed at the head of the free list, there
is another situation that a process puts a request for a block, the block exists in the buffer, the
process gets the data from that buffer puts into user space, while processing it the process finds
that the content of the buffer is not valid there is some data error. I can have a situation like this.
Now it is always expected that I should not maintain any buffer containing an invalid data. So I
should try to overwrite it as early as possible with a valid data. So in such cases also when this
buffer is to be returned to the free list, it should be returned at the head of the free list because
only the buffer which is at the head of the free list that is going to be overwritten next.
So there are two situations in which we can place a buffer at the head of the buffer list, one
situation is that when just writing operation has been complete because of delayed write, the next
situation is when the content of a buffer is found to be invalid. In all other situations we will
place the buffer at the tail of the free list but a buffer can never be inserted in middle of the free
list, it will either go to the head or to the tail not in the middle. So let us stop here today.
12
Digital Computer Organization
Prof. P. K. Biswas
Department of Electronic & Electrical Communication Engineering
Indian Institute of Technology, Kharagpur
Lecture No. # 24
Secondary Storage Organization – I
Till the last class we have discussed about the buffer cache management and in that case we have
seen that whenever a process puts a request for a block or the data contained in a particular block
then it will be the responsibility of the operating system to check in the buffer pool that whether
that particular block is present in the buffer pool or not. If it is present in the buffer pool then it
can be directly copied into a user space, user area from the buffer pool but in case it is not
available in the buffer pool, in that case the block containing the requested data has to be read
from the secondary storage and put into one of the buffer pools. Then from that buffer it can be
subsequently transferred to user space, the space which is allocated to the particular application
program which has requested for the data. Now before you go further, let us see what is meant by
a block?
For that we discuss about the secondary storage devices and you know that we can have different
kinds of secondary devices for example, we can have a storage device like magnetic tape, we can
have a storage drive of say floppy. Of course these are all magnetic materials, we can have
magnetic drum, we can have magnetic disk, the hard disk that we use is nothing but a magnetic
disk and we also have what is optical disk or compact disk. So you can have this various kinds of
secondary storage devices and whenever we want to access any data from any of the secondary
storage devices, we have to access the data in the form of a block. Either we have to write an
entire block on to the secondary storage or we have read a complete block from the secondary
storage. From the secondary storage we cannot access any particular byte or any particular
character.
Now the typical characteristics we will mainly discuss about the magnetic tape, floppy and
magnetic disk. Now as you know that this magnetic tape is nothing but a tape something like a
video tape or an audio tape which is coated with some magnetic material. So I can simply put it
in the form of a linear tape like this and this tape will consist of a number of tracks, parallel
tracks which are parallel to the length of the tape, so it is something like this. So these are a
number of parallel tracks and these are the tracks which contains the data. Typically, we have 8
tracks for containing the data bits and one track which contains the parity bit, parity to check the
correctness of the data. So 8 bits use 8 tracks containing the data bits and this additional track
contains the parity bit. Then to access any data which is stored on this magnetic tape or to write a
data on this magnetic tape what we use is a read write head and when you say that read write
head for the magnetic tape, it is also a linear array because for every track I have to have a read
write head. So for a magnetic tape which has got such 9 magnetic tracks, 9 tracks, the read write
head will be an array of 9 read write heads. So the for reading or writing anything on this
magnetic tape, the driving mechanism will pass this magnetic tape over this read write head.
So when this magnetic tape moves over this read write head, either the data can be written on to
this different tracks or the data can be read from this tracks. Now usually the way the data is
stored on this track is in the form of blocks. A block consists of a number of records. So it is
stored like this say every byte will be stored in perpendicular direction, this location will contain
one bit of a particular byte, this location will contain another bit of a particular and so on. So
when you put a number of records on this magnetic tape, a number of records forms a particular
block. Suppose this is block number one. Similarly, we have another set of records that form say
block number 2, in between two blocks, we have to have an empty space which is known as inter
record gap or IRG.
The purpose of maintaining this IRG is like this that a data can be written onto this magnetic tape
or data can be accessed from the magnetic tape only when the magnetic tape moves at a constant
velocity under this read write head and this being an electromechanical device, it will have
certain inertia. So if we assume that suppose initially the magnetic tape is halted that means tape
is not moving. Now I want to read some data, read a particular block from this magnetic tape
may be the first data that I want to read is block number one and the next block that I will be
interested to read is block number 2. So what happens is once the read request comes, the driving
mechanisms start moving this tape and because of inertia it will take a finite amount of time to
attain that particular speed, the specified speed and only when the specified speed is attained then
the read write head can start reading from the magnetic tape or it can start writing onto the
magnetic tape and the constant velocity must be maintained until and unless the last byte of the
block is read. So during this, time taken to pass this part of the magnetic tape under read write
head, the tape speed must be remaining constant.
Now once reading this block number one is complete, the tape will come to halt and again
because of inertia it will have certain deceleration and may be when the tape comes to halt in that
case the read write head will be positioned somewhere here. The next request comes is for
reading block number two. Again it will take some time to attain the specified speed before
which the read write head can read from the tape. So you have to allow certain space so that
during the time when this space is passed over the read write head, by that time the tape will
attain the constant speed.
So this read write head will be ready to read the next block from the tape and this is the purpose
of maintaining this inter record gap and obviously the length of the inter record gap will be
depending upon what is the acceleration and what is the deceleration that is provided by the
magnetic tape drive. So if the acceleration is more or the deceleration is more, may be this inter
record gap, length of the inter record gap will be less whereas if the acceleration or deceleration
is less in that case the length of the inter record gap has to be more depending upon what is the
specified velocity specific velocity at which the tape has to move under the read write head.
Now similarly coming to the floppy or the magnetic disk, as you know that floppy is nothing but
a circular plate again coated with some magnetic material and on this tape, the data tracks are
nothing but a set of concentric circles, so I have a set of concentric circles which stores the data.
Now these concentric circles are again divided radially into a number of sectors, so like this.
Again to read the data or write data on to any of the tracks, I have to have a read write head. Now
in case of magnetic tape the read write head was stationary, it was the tape which was moving
under the read write head.
Now in case of a magnetic disk like a floppy disk, this head has to access different tracks. So to
access different tracks which are placed in a concentric manner, the read write head has to move
radially over this disk and when the read write head moves over the disk, there is only a gap of
few microns between the track and the read write head. So given a particular track number from
which the data has to be read, the first operation that is to be done is you have to place the read
write head over the track and once this placed onto the track, you have to identify the sector
which is to be read. Now it is this sector which is called a block in case of a disk. So this sector
will contain a number of data, every sector will have a unique address and we refer this sector by
a block. So every block on a magnetic disk like this will have a two component address. The first
component will identify that what is the track number, track number is same for every circle and
the second component is what is the sector number. So the track number and the sector number
taken together identifies a particular block in the disk.
Now here we can have these tracks, data tracks either on single surface, one surface of the plate
of the magnetic disk or it can be on both the surfaces of the magnetic disk. So accordingly we
can have either a single sided floppy drive or we can have a double sided floppy drive. Now in
case of a magnetic disk, the disk is nothing but a stack of such magnetic plates. So what will
happen is if I place such magnetic plates, circular plates one above the other like this and fix
them by a spindle along the axis, the tracks as before will be concentric circles on these plates
may be on same side, may be on single side or both sides, like this. Now these tracks are so
placed that track number 0 on one disk is at the same spatial location as track number 0 of the
other disk. So all these tracks, concentric tracks having the same number on different disks taken
together is called a cylinder.
Now when I specify a cylinder number, it specifies this track, it specifies this track, it also
specifies this track. So as you have done in this case that the tracks are divided radially into a
number of sectors, here also every track will be divided radially into a number of sectors. The
tracks can be on both sides of the plate, they can be on a single side of the plate. Accordingly, the
number of read write heads will be different because here if I have tracks on both sides of the
plate, then I have to have two read write heads one for accessing the top surface, the other one
for accessing the bottom surface.
Similarly, here if I have three such disks which are stacked together, three such plates stacked
together to form a magnetic disk and I have tracks, magnetic tracks, data tracks on one side of
the disk, one side of every disk then I need three read write heads. Whereas if the tracks are
present on both sides of the plates in that case I need 6 read write heads, every head will have a
unique head number. So just in this case we have said that if we have a single sided disk then for
identification of a particular block or particular sector, we need the track number and the sector
number. Had it been a double sided disk, we need track number, sector number along with the
side and the side is referred as head number that which particular head has to be active for
reading that particular sector. So I will have three component address if it is a double sided disk,
one for the head number which has to be active, the other one is for the track number and the
other one is for the sector number.
Similarly, in this case, the address will be three component address, head number then as I said
that all the circles, all these circles, concentric tracks having the same number is called a
cylinder. So the next component that I need is, what is the cylinder number? and then the sector
number. So these three components taken together uniquely identifies a particular sector or a
particular block on the disk. So as we said that whenever a page fault occurs and the process
wants to read some block from the disk that means it has to supply, what is the address of that
block and the address has to come in the form of this three component address.
Now generally the process does not know, what is the address of the block which is needed? So
you might be remembering that in case of when we discussed about the page fault interrupt, we
have said, cylinder number is say all these stacks at the same spatial location, at the same
distance from the center, on different disks they form a particular cylinder. When I say cylinder
number 0, this is the track number 0 on this disk, this is track number 0 on this disk, this is track
0 on this disk, so all these three tracks taken together is called a cylinder.
Now you see that how these three component address uniquely identifies a particular sector or a
particular block. First what I have to do is I have to specify the head number, maybe I specify
head number to be three. Now a read write head which accesses the top surface of the top plate
that will be having a head number zero, a head which accesses the bottom surface of the top plate
that will be having an head number 1, similarly here head number 2, head number 3. So head
number 3 is the head which accesses the bottom surface of the second plate. So I identify the
surface on which I have to find that particular block. So once I identify the surface then I have to
identify the track on which the block is present. So in this case the track number is identical with
the cylinder number because for all the tracks at the same radial distance from the center, the
track number is same and all of them taken together is called a cylinder, so track number and
cylinder number they are identical.
So first I have identified the surface then I am interested in say zeroth track on that surface and
that is same as the cylinder number. So once I identify the track, so now I come to a particular
track, on that particular track I am interested in a particular sector, so these three taken together
uniquely identifies a particular block on the disk because as I said that this sector is equivalent to
a block. Now when a process puts a request for a particular data, for getting the data, the block
address or the block number containing the data must be known but the process application does
not know it. So when we discussed about the page fault interrupt, we have said that whenever a
page fault interrupt occurs, the operating system or the kernel refers a particular table which we
have said as file map table, FMT so it is the FMT which will indicate that what is the address of
the block which is needed.
So on getting that block address, now it will invoke the device driver to read the block from the
secondary storage and put it into the buffer, if the buffer already does not contain the data. So
this FMT is an interface between the application program and the actual hard disk, the physical
hard disk or any physical secondary storage because all this information has to come from FMT.
In some systems it is called file map table and the particular one that we will discuss in details is
called an index node or inode which is used in UNIX operating system.
Now this FMT can be maintained, file map table can be maintained in various ways so before I
go into that let us see what is a disk layout? So as we have said that the disk consists of a number
of blocks, every block is identified by a three component address that is head number, cylinder
number and sector number. So if I put all those blocks in a sequential manner say head number 0,
cylinder number 0, sector number 0, is say block number 0, head number 0, say cylinder number
0, sector number 1, is say block number 1.
(Refer Slide Time: 00:21:17 min)
So if put these blocks in a linear form, in a linear arrangement then what I will have is, on a hard
disk, I will have a series of blocks which logically can be considered as a linear array of blocks.
Few of these blocks are special blocks. For example, the zeroth block or say first few blocks
starting from the zeroth block they are known as boot blocks. These boot blocks contain the boot
program that means whenever you switch on the power or you reset the machine, a part of the
operating system which is stored in the boot block is read from the boot block and put into the
OS part, OS partition of the main memory and that becomes resident. So this boot block is used
to store the boot volume or the booting program or initialization program of the computer
system. Next few blocks one or more blocks are called super blocks.
Now this is a layout which I am taking with reference to UNIX file system layout. So the
purpose of this super block is to maintain the information of the file system itself, that is how big
the file system is, how many files it can store, where you will find the free space on the disk, so
all those informations will be maintained in this super block. I will come to details on this super
block later.
The next few blocks are called inode blocks. As I said that a part of the inode contains what we
refer to as FMT or file map table. These are called inode blocks and the remaining blocks are
actually the data block, which contain the file data. Now when I talk about the FMT or file map
table, the FMT can be maintained in various ways. See one of the way can be that on this file
system, I maintain a table common for the entire file system. What the table will do? The table
will have a list of the files or list of the directories which are present on this file system. So it can
be something like this. I have a table and in this table I store a list of files, so I can have files say
F1 F2 F3 and so on. With every file I can store a block address or a block number which contains
the initial data or the first block containing the data of that file, so here I can put the block
address. So for every file I will have a block address and this is the address of the block which
contains the starting data of the file. Now when you come to the disk as I said the disk is nothing
but consist of a number blocks.
So it will consist of a number of blocks and these are the blocks which contain the file data. So
one way to keep track of what are the blocks which contain the data of say file F1, I can go for
different kinds of block allocation. One kind of block allocation can be contiguous block
allocation that means if F1 needs 5 blocks to contain its data then this block number, it gives the
starting block number and 5 consecutive blocks starting from that block number contains the data
of file F1. So that can be one kind of allocation and this is an allocation which is possible if I
don’t have any dynamic situation that is once I create a file that will remain as it is but in case of
a dynamic situation, it may so happen that suppose I had a file of say 3 KB earlier, the 3 KB may
be taking 3 blocks assuming that every block is 1 KB size then later on, it may so happen that I
wanted to expand the file, modify the file so that the size will be changing from say 3 KB to 4
KB.
So earlier the file was needing 3 blocks, now it will need 4 blocks but once three block file was
created, 3 kilo byte file was created after that there might have been some more files created. So
the block which is next to that file has been allocated to some other file. Now if I wanted to
change the size of the file, if I want to increase the size of the file to 4 KB. So it needs 4 blocks I
find that the next block, the fourth block in the sequence is no more available. So I cannot
change the size of the file. So to avoid that problem what is done is, what can be done is even
these blocks can be maintained in a form of a link list or I will have a chain of blocks may not be
contiguous which will contain the file data.
So in such case what will happen is, this block number which is there in the file allocation table
or the file map table, it points to the first block containing the file data. Then address of the next
block which contains the same file data will be say put as a pointer in this first block itself. So
this first block can have a pointer which points to the next block containing the file data. Again
this can have a pointer which points to the next block containing the file data. This can also have
a pointer which points to the next block containing the file data and the last block will have a
null pointer. So you find that even this chained or linked list concept can also be used for storing
the file data. So now whenever a page fault interrupt occurs and the process needs a particular
block, always it has to access the first block then from the first block it gets the link to other
blocks. Then finally it will come to the desired block and read the data but the disadvantage with
this process, which is the disadvantage of all linked list implementation is that access is fully
sequential. I cannot go to say these block directly to get, to read this particular block. I always
have to come to first block then only sequentially I have to come to the desired block.
Now disadvantages can be avoided if I modify this kind of file allocation that is, in a second case
what I will have is say this block number which is specified within the file allocation table, this
points to a particular block. Now this block instead of becoming the first block in the chain of
blocks containing the file data, these blocks can contain a table. So now the concept is something
like this say I come to a particular block, this block contains a table or table of pointers. These
pointers point to different blocks which contain the file data so this block number points to a
particular block, these block actually contains a table, a table of block numbers or list of block
numbers and these blocks pointed to by these table entries actually contain the file data. So now
you find that unlike in the previous case where this access was strictly sequential, here I can have
random access but the first thing that I have to access is this table. So once I have an access to
this table then following any arbitrary pointer, any random pointer, I can come to random block
to access the data contained in that block. So the disadvantage that we had in this case has been
removed in this particular case. And it is a modification of this concept, the second concept
which is used in case of UNIX operating system and there the file map table or file allocation
table is contained in what is called an inode or index node. Now coming to what is an inode, for
a particular file system every directory or every file in that file system will have a unique inode
allocated to it. An inode is nothing but a data structure which contains along with the file map
table, various other information of the file.
So what are the different information’s that you need? The first information that is needed is the
information regarding ownership of the file that is who is the owner of that file, the user name.
The second information that is needed is group ownership. Those who are working on UNIX
operating system, you might be knowing that whenever a user account is created, the user
belongs to a particular group. So for every file or every directory, we have to have these two
information’s, that who is the ownership, what is the ownership of the file, who is owner of the
file and the group to which that owner belongs. The other information that is to be maintained in
the inode is the type because as we said that for every file or every directory on the file system, I
will have an inode.
So I have to have some indication about that these inode, is the inode of a file or inode of a
directory because the files will have some characteristics, directories are having some other
characteristics and we can say that directories are nothing but special kind of files which gives
the file system a tree like structure. Is it not? Because in case of this file system we usually have
a root directory. Under root directory we can several subdirectories say for example etc, we can
have a subdirectory bin, we can have a subdirectory usr and so on. Under this subdirectory we
can have again a number of subdirectories or number of files. Here also we can have again a
number of subdirectories or again a number of files.
So each of these nodes are basically directories and this directory is nothing but a special kind of
file which gives the file system a tree like structure like this. So I have to identify, I have to have
a demarcation about that the inode that I am talking about whether this inode, is the inode of a
file or it is the inode of a directory. Not only that the type field also contains information about
whether this inode is already allocated or inode is not yet allocated. Among the other information
we have to have the permission fields and if you give the directory listing, simply by LS
comment you find that you get this kind of directory, something like this. What does it mean? So
this permission is divided into three fields, I can three kinds of permissions on any directory or
any file Unix operating system, r indicates read permission, w indicates side permission, x
indicates execute permission.
Now first three bits indicates that, what is the permission given to the owner of the file, second
three bits again it can be rwx, read write and execute, it indicates that, what is the permission that
is given to any member of the group to which the owner belongs. So this indicates the group
permission and the third three fields, this read write and execute this indicates the permission
given to any other user of the system. The user may belong to some other group. Of course
except the super user because super user will have all the permissions read write execute. So this
is the permission which is given to the owner, this is the permission given to any other user
belonging to the same group to which the owner belongs and this three bits, this three fields
indicates the permission given to any other user of the system who does not belong to the same
group.
Now among other information’s we have to have information about file access time, that is when
the file was accessed last, we have to have information about file modification time, that is when
the file was modified last and the other information is inode modification time, that is when the
inode was modified last. Then another crucial information that is of course needed is file size,
what is the size of the file or the size of the directory, how many bytes are needed for this file or
how many bytes are needed to store this directory and the third one that comes is what we are
talking about the file map table or file allocation table that is the disk addresses of different data
blocks containing the file data and this is what is normally referred to as TOC or table of content.
So this is a data structure, TOC table of content, this last field this actually contains the addresses
of the disk blocks or the numbers of the disk blocks which contains the file data that is like this.
See here what we have said is I can have a global table, in the global table I have a block field.
The block field points to a particular block which contains the table of disk addresses or block
addresses, those blocks contain the file data. In case of Unix operating system, this table is part
of the inode. So for every file or every directory in the file system, an inode is allocated, the
inode has this fixed structure. One of the fields in the inode is this table which contains the list of
block addresses which contain the file data and this table is called the table of contents or TOC.
So now you find that because the inode has got fixed number of fields and every field is
constant, I mean not constant of fixed length. This ownership field it contains a fixed length,
group ownership field contains a fixed length, type field contains is of fixed length, permission
field is again of fixed length. So every field in the inode, inode data structure is of fixed length so
that means the number of bytes needed to store the inode is also fixed. So since the number of
bytes needed to store the inodes is also fixed, the simple way we can store this inodes on the
inode blocks is just by sequence of bytes.
So if I know that suppose I need 50 bytes to store all these fields. Then first 50 bytes in the inode
blocks will be the first inode, second fixed 50 bytes will belong to the second inode, next 50
bytes will belong to the third inode and so on. So all these inodes can simply be put in the form
of series of bytes on the disk, a particular inode will be accessed by its byte offset. Disk address
field is also of fixed type. That is taken care of by the TOC table of contents. Table of contents is
a table which contains the block addresses containing the file data. We will see how big it can be,
I will see that later. These different entries in this table of content has different meaning, let me
talk about that.
So the format of this TOC, table of content is something like this, in Unix 5 file system, the TOC
has got 13 entries, so there are 13 entries. The first 10 entries starting from entry number 0 to
entry number 9, they contain the block number of the block which contains file data. So there is a
9, so these are direct pointers to blocks which contain the file data, so this is the data block.
Similarly, this also points to a block which contains the file data, this is also a data block. Entry
number 10 is a single indirect block or single indirect pointer that means it points to a block, this
block itself contains a number of block addresses. In the first case in case of direct entries, each
of these entries are block numbers, these blocks contain the file data. This entry again contains a
block number; it points to a block. Now this block does not contain the file data, this block again
contains a set of pointers, a number of pointers or block addresses each of these blocks, so each
of these entries points to a block which contains the file data. This entry is a second indirect
entry that means these points to a block which contains a sequence of block numbers, each of
these points to a block which again contains a sequence of block numbers, each of these points to
a block which contains the file data. This is third indirect. This point to a block which contains a
set of block numbers, each of these points to a block which in turn contains a set of block
numbers, each of them points to a block which in turn contains a number of block numbers, each
of them points to a block which contains the file data. So this is the structure of the inode table of
contents in case of Unix system 5.
Now we find that if I wanted to find out that what is the file size that can accessed by such an
inode table of contents, let us assume that every block is of size 1 KB. And suppose for
addressing a particular block, I need 4 bytes. Every block is of 1 KB, for addressing a particular
block I need 4 bytes that means one block can contain 256 number of block numbers. Now
assuming this you will find that using this direct pointers, I have 10 direct pointers, entry number
0 to entry 9 they directly point to data blocks. So using this direct pointers, I can access a file of
size 10 KB. So this is what I can access using direct pointers. Using single indirect pointer, I
come to a block which contains 256 entries or 256 block numbers and these entries point to
blocks which contain the file data that means using this 256 entries, I can access 256 KB of file
data.
So using the direct pointers plus single indirect pointer, I can access 10 KB+ 256 KB of file data.
Then come to double indirect, you find that this is 256x256 KB of file data plus using triple
indirect, it will be 256x256x256 KB of file data. So this is the total size of a file that I can access
using this structure of inode. Now if you compute this, this is nothing but 224, 224 means 16 MB,
so 16 kilo MB means 16 GB, so just this triple indirect block gives you a file size of 16 GB. So a
size of file which can be accessed by this inode structure is more than 16 GB and I think this is
sufficient for most of the applications that we can think of. So let us take a break after that we
will continue.
Digital Computer Organization
Prof. P. K. Biswas
Department of Electronic & Electrical Communication Engineering
Indian Institute of Technology, Kharagpur
Lecture No. # 25
Secondary Storage Organization- II
So, what we have discussed about the fields of an inode? These are the fields which are stored on
the secondary storage. So following the same logic, why you have come to this inode is that
whenever a process puts a request for a particular data from a particular file, the first thing that
has to be done is you have to access the inode of the file. Then in the inode, you have to come to
the table of content, TOC part of the inode. From the TOC part depending upon which byte
offset of the file is interested in, you have to go to the corresponding data block may be either
following the direct pointer or single indirect pointer or double indirect pointer or triple indirect
pointer, using some of the pointers one of the pointers you have to come to a particular data
block then you have to access that data block.
So for every read operation, for every write operation on the file, you have to access the TOC
part of the inode to get the corresponding block identification number. Then once you have the
block identification number then you can check within the buffer whether that particular block is
present in the buffer or not. If it is present in the buffer you don’t have any problem, you can
simply transfer that from the buffer area to the user area. If it is not present in the buffer, then I
have to physically read that particular block from the secondary storage and put it into one of the
buffer cache. Now because you have to access the inode for every file operation whether it is
read or write whatever it is, that means once you open a file, it is quite expected that the inode of
that file will be accessed a number of times. Now for accessing the inode, if every time I have to
go to the disk then obviously the throughput of the file system will be very poor.
1
So to improve the throughput what is done is, the same concept that we have used for the buffer
cache that is, we put the data block in the buffer cache so that your physical access to the disk,
the frequency of physical access to the disk is reduced. Using the same concept whenever you
open a file, the first time you access the inode of that file from the disk and copy that inode into
main memory. So that as long as the file is open, every reference to the file will try to refer to the
inode of the file and now the inode is available in the main memory so your access time will be
quite less. So this is a copy of the inode in the main memory which is called an incore inode and
the incore inode is maintained almost in the same way as we have maintained the buffer cache
that is we will have a free incore inode list. We will also have a number of hash lists, the hash
lists consist of a number of inodes on that particular hash list. So to maintain the hash node in the
main memory in addition to these fields we need a number of additional fields, one of the field is
obviously the status field that we have also used in case of buffer cache.
So the first field in the incore copy that will be the status field and as before the status field will
contain similar kind of information that is the first information that has to be contained in the
status field is whether the inode is locked because it may so happen that more than one process
opens the same file simultaneously for reading purpose. In that case when one process say p1
wants to read a data from that file then before reading the data from the file, it has to access the
inode to find out what is the block number of the data that is requested. Once it gets that block
number then it can release the inode. So during this process the inode should remain locked, so
that during the same time if the second process also wants to access the same inode it should not
permit it.
Once the first process releases the inode, the second process can now access the inode. So one of
the field, one of the information that you have to maintain in the status field is whether the inode
is locked or inode is unlocked. Here as we have seen there is a difference that as we have seen in
the buffer cache that if the buffer is not locked that means it is free but in case of inode it is not
so.
2
Even if the inode is not locked that does not mean that inode is free, I will come to that later. So
the first information that you have to maintain in the inode is whether the inode is locked then
the next information that you have to put in the inode is similar to as you have used in case of
buffer cache that whether a process is waiting for this inode to become unlocked or not, inode to
be unlocked. Then other information that you have to maintain is whether the inode is same as
the disk copy or there has been some modification in the inode. So this information is whether
inode differs from disk copy and the other information is, one is inode differs from the disk copy
and the second information that has to be maintained is whether the file data is different or the
file data has been modified after the file has been opened. So here we have to put whether incore
file is different from disk copy, so these are the various information that you have to maintain in
the status field of the incore copy of the inode. Then obviously the other information’s will be
the device number and the device number that contains the file that is, that we are interested in.
Then the inode number itself, you find that in case of disk copy of the inode, we didn’t need this
inode number because in that case the position of the data structure in the inode blocks tells you
that what is the number of the inode. So just for example what you said is that if the inode needs
a 50 bytes for representation, if the data structure for inode needs 50 bytes in that case first 50
bytes in the inode block will belong to the first inode. Next 50 bytes will be for the second inode,
next 50 bytes will be for the third inode and so on. So it is the position of the data structure in the
inode blocks tells you that what is the inode number but in case of incore copy, we may not need
all the inodes in sequence and a particular inode may appear anywhere in the hash list or
anywhere in the free list.
So I need a specific field which will tell me that what is the number of the inode of that incore
copy, whether it is the inode number 1 or inode number 2 and so on, which is not needed in case
of disk copy. Then obviously I have to have a set of pointers, pointers to other incore inodes and
here again we can have two sets of pointers, one set of pointers will be for the free inode list and
other set of pointers will be for pointers to other inodes in the same hash queue, just as we have
done in case of buffer cache. And here I have to have an additional field which is not present in
case of buffer cache that is what is called reference count and it is the reference count which
makes it different from unlocked in case of buffer and unlocked in case of inode.
In case of buffer cache, we have said that whenever the buffer is unlocked that means the buffer
is free and it can be on the free list as well in addition to its existence on the hash queue. In case
of inode because there is the possibility that the same file may be opened simultaneously by
more than one process and we expect that as long as the file is open, its inode should be present
in the main memory. I can remove the inode from the main memory only when the file is closed
but it may so happen that two processes has opened a particular file.
The first process which opened that file first and because of that file open command, the
corresponding inode has been read from the secondary storage, from the inode block and it has
made an incore copy of time. Now the second process wants to open the same file, so it will get
the inode number of the file and after getting the inode number the first operation that will be
done is to check the incore copies of the inodes in the particular hash queue to see whether the
inode already exists in the main memory or not. If it is existing in the main memory that means
some other process had already opened it.
3
So I need not get the same inode from the disk once more because already it is present in the
main memory but what has to be done is, this reference count field has to be incremented by one.
Now when the first process closes the file but not the second process, the file is closed for the
first process but it is still open for the second process. That means though the first process will
not need the data from the file anymore but the second process will need the data from the file.
So first process has unlocked the inode, may be the second process has also unlocked the inode
because inode will be needed only to get the block address not for other purpose. So may be the
inode is unlocked for both the processes, first process and second process but the second process
has not closed the file but the first process has closed the file that means file is still open for the
second process and the second process is lightly to access the data from the same file a number
of times. So I cannot simply remove this inode from the incore copy, I can remove the inode
from the incore copy only when the second process also closes the file so that is what is
maintained in this reference count field.
When the first process opens the file, the inode corresponding to that file is read from the
secondary storage and put into main memory and the reference count field is set to one. When
the second process also tries to open the file, it finds that the inode is already present in the main
memory so it need not be read from the secondary storage but now there are two instances, two
active instances of the same inode, so reference count will be incremented by one more so now
reference count becomes equal to 2. So it is the reference count field which indicates that how
many active instances of the same file exists in the system.
Now when the first process closes the file, it simply makes the reference count decremented by
one. So earlier reference count field was equal to 2, now it becomes equal to one, because it is
one that indicates the file is still active for some other process. So I cannot simply remove the
inode from the main memory or I cannot put this inode on the free inode list because once it goes
to free inode list that indicates that this inode may be overwritten by another inode from the disk.
I can put this onto the free inode list only when the reference count field becomes equal to zero,
that means there is no other active instance of the same file. So that can only happen only when
the second process also closes the file. So after the first process, if the second process closes the
file then earlier reference count field was equal to one, now it becomes equal to zero and when
the reference count field becomes equal to zero, it can be put onto the free list. So that is the
difference between your buffer cache management and the inode management.
In case of buffer cache, we have said that whenever the buffer is unlocked, I can put it onto the
free list, may be either head of the free list or at the tail of the free list but in case of inode only
when the reference count field is equal to 0, even if the inode is unlocked. Only when the
reference count field is equal to zero then only I can put onto the free inode list otherwise I
cannot put it onto the free inode list. Other managements will be almost similar to what we have
discussed in case of buffer cache.
Now the major operation is as we have seen that for getting any data from the inode, I have to
access the inode, get the table of contents, from the table of contents I can get the block number
and once I have the block number then using that block number I can check in the buffer cache
whether it is present. If it is not present I have to access that block from the secondary storage,
put it into buffer. But what is most important is that we have not said till now is how to know the
4
inode number. Because when I execute a program or I want to open a file, I simply give the file
name or at best I can give the path name starting from the root leading to that file. But I never
specify the inode number or even the user need not know, what is the inode number? So there
comes the concept of directory. Directory plays a very, very important role in finding out the
inode number of a requested file or the inode number of a requested subject. Now what is a
directory? As we said the directory is a special kind of file, so just like file, in case of files we
have to have unique inode, every file will have to have a unique inode. Similarly, every directory
or every subject will have to have an unique inode. So I just demarcate between the inode given
to a file or an inode given to a directory only through the type field. The type field indicates
whether the inode is unallocated. I will not say free, inode is unallocated that means it has not
been allocated to any of the files or any of the directories or the inode has been allocated to a file,
regular file or the inode has been allocated to a directory or there are some special kinds of files
which are maintained whether the inode has been allocated to any special kind of file. I will
forget about this special kind of file now. Let us consider about only directory, file and the free
inode.
So whenever a process wants to open a file, usually we give the file name, just the file name if
the file exists in the current directory or we simply give the path name from the root, if the file is
not in the current directory or even if it is in the current directory then also you can specify the
path name from the root. Now what is the directory? As we said that directory is a special kind of
file which contains a list of inode number file subject pair. So if you open a directory just like a
file, you will find that it will contain two fields.
One field is for inode and the other field is for directory or file. Suppose say this is the directory
of say /etc. Under /etc we can have a number of sub directories or a number of file. For example,
under /etc, I can have a directory say bin, this directory bin, sub directory bin will have a specific
inode number let us say inode number 80. Under this I can have a file say password, this
5
password again will have a unique inode allocated to it and suppose this inode is let us assume
any numbers say 205.
Now the sequence which particular inode will be allocated to a particular file or to a particular
directory that depends upon what are the inodes unallocated at the time when this file or this
directory has been created. So, one of the inodes which is still unallocated will be allocated to the
newly created file or the newly created directory. So similarly it can have many other entries and
the corresponding inodes. So a directory is nothing but a list of inode directory file pair along
with this there may be other attributes just to identify that whether this is a file or this is a
directory, of course that is also available in this particular inode. Say 80th inode will say that bin
is a directory.
Similarly, 205th inode we will say that password is a file, it is not a directory and that will
specified, that will be specified in the type field of this particular inode. So just like this when I
say that etc is a directory that etc itself has been allocated a particular inode, a unique inode,
which is not allocated to any other file or any other directory. Then along with this there are two
special kind of entries, one entry is ., the other entry is a .., this entry . means that it gives you the
inode number of current directory. Suppose this number is 100 then as I said that this directory
etc, this is the current directory is etc, the directory etc itself is assigned an inode number 100, ..
gives you the inode number of the parent directory of this directory. So may be the parent
directory of this has been allocated an inode number of 300. So you find that from a particular
directory using ., I can find out what is the inode number of the current directory or using this ..,
I can identify, I can find out what is the inode number of its parent directory?
For any other entries whether it is a file or a directory, I can always find out what is the inode
number of the corresponding file or the inode number of the corresponding sub directory under
the current directory. Now in addition to these directories there is a root inode, there is a root
directory for every file system. Root directory is also assigned a unique inode number. Suppose
the root directory is assigned an inode number let us say any inode which is not allocated to this
say 50. So for getting the inode number of any file or any directory that is specified I need one of
the two components, either the inode number of the current directory or the inode number of the
root directory because when you specify a file path, the paths are specified from the root
directory itself or I simply specify the file name or the file directory which is under the current
directory. So, to get the inode number of the target file or the target directory if I have either the
root directory inode number, or the current directory inode number that is sufficient.
The root directory inode number is usually stored in a global variable which is accessible to all
the process but this cannot be modified. Similarly, current directory inode number is within the
directory itself. So if I give a command like say open, fopen syntax may be, may not be correct.
So if I give a command say fopen(password), when presently I am under this directory etc then
how this will be converted to the corresponding inode number? I know that because I have not
specified any path name, so these have to be found within current directory only. You simply
search the current directory, get the entry corresponding to this file name password, extract what
is the inode number of that. So once I get the inode number of this password, the next operation
what is to be done is you read this inode number. First you check whether this inode number is
present in the main memory or not or whether I have an incore copy of this inode number 205.
6
If I have an incore copy of this inode number 205, what I do is I simply increment the reference
count field of the incore copy of inode number 205 by 1 but if it does not exist in the main
memory, if I don’t have an incore copy of this inode number 205 what I have to do is, I have to
read the block from the secondary storage which contains this inode number 205 and that is very
simple because in case of inode blocks all the inodes are put in sequence. The first inode appears
first, second inode appears next, third inode appears after that and so on. So from this inode
number I can always find out that what is the block if I have more than one blocks containing the
inodes, I can always find out that which block contains this inode number 205 and what is the
byte offset within the block for this inode number 205 because I always know that what is the
starting block number of the inode blocks, what is the size for every block, what is the size of
every inode all these things are known.
So, I can always find out that what is the starting byte of this inode number 205 and which
particular block. So what I do is I simply read that block, for reading the block again I have to go
to that buffer cache management because this block has to be read and put into the buffer. Then
once it is in the buffer then only I can filter out this inode number 205 and get the inode number
and put this inode into the incore copy of the inode. On the other hand, if the command is given
like this fopen(/etc/password), so if I give a command like this then what I have to do is because
this is the path name starting from the root, I know what is the inode number of the root because
that is stored in a global variable. I have to take out this inode number, read it from the disk, put
it into incore copy or may be while booting this inode number is already present in the incore
copy.
I have to check that this is a directory not a file because there are other components on this. So if
this is a file then this path name is not valid, it has to be a directory. So I have to check that this
is a directory, on verifying this is a directory I also have to check that I have the write permission
on this directory that I have to have the search permission on this directory. So in case of
directory, search permission is equivalent to execute permission. A file can be executed but a
directory cannot be executed. So in case of a directory, the search permission is equivalent to
execute permission, so if you have execute permission on the directory then you can search that
directory. So if you have the search permission then what I have to do is, the next component is
etc, I have to check that directory. So this etc, this root stored directory will be some sort of
listing like this, I have to search for this component etc in that listing.
Once I get an entry for etc I have to take out the inode number of that. So once I get inode
number of etc and in this case the inode number of etc is 100. So I have to get inode number 100.
Again read it from the disk, put that into main memory then from that inode number I get the
disk blocks from the table of content which contains the data of the directory and data of the
directory is this list. So I have to read this list then search within this list for this entry password.
So I get this entry password, inode number of the password 205, I have to extract this 205 then
on getting this 205 inode in the incore copy, I can go to the table of contents of this inode. Then
once I have access to the table of contents of this inode, I have access to different data blocks
containing the data of this file password. So this is the very, very important step and always
whenever I want to access a file, I want to open a file or close a file or whatever I do, a user
process and application specifies the file name or the path name leading to that file. It may be file
name or even the directory. So first operation that has to be done is you convert the file name or
7
convert the path name to the target inode number and that can be performed in this manner. So
once you have access to the inode, you have access to the inode table of contents. Once you have
access to the inode table of contents, you have access to the data blocks containing data of that
file or containing data of that directory and data of the directory means simply this listing. Parent
directory of /etc is the root directory. Yes, I remember. I see it should be 50. For a root directory,
the parent directory will be root directory itself.
So now it is clear that given a path name or given a file name, how you can convert that to an
inode number. Once you have an inode number, you have access to everything in the file. Yes, I
think more time because this has to be passed. Now next thing is, so far whatever we have done,
we have assumed that an inode is already allocated to a file or inode is allocated to a directory.
The next important question is how do you allocate the inode to the directory or how do you
allocate inode to the file? For that what we need to know is, what are the free inodes when the
file is created or free means unallocated inodes because free we are using for some other
purpose.
What are the unallocated inodes in the file system, which are not yet given to any other file or
any other directory, when this new file or the new directory is been created? So for that again the
super block plays an important role. In addition to the information that are maintained in the
super block that we have said that the super block maintains information about the file system
itself that is how big is the file, how big is the file system, how may files it can store and all those
things. The super block itself contains a list of unallocated inodes that may not be an existing list
that is a sub list of the total number of unallocated inodes of the file system.
So in the super block we have a list of inodes which are unallocated at a particular instant of time
or a sub list of the inodes which are unallocated at a particular instant of time. Now let us assume
8
that at a particular instant of time, I have several inodes which are still unallocated on the file
system. The inodes may be say 100, 105, 112 like this, may be inode number 200 and in this case
this is called a super block free inode list or unallocated inode list. So this list, this list is simply
the serial number of the inodes, this is not the inode itself or it is not the data structure, inode
data structure it is simply the serial number of the inode. To access this inode number 100, I have
go to the inode block and from the byte offset of this inode number 100, I have to get that inode
that is the data structure of the inode.
Now it says that inode number 100 is not yet allocated to any other file or any other directory,
105 is not allocated to any other file or any other directory and so on. So up to this inode number
200 is maintained in the super block free inode list. There may be other inodes free on the file
system but those are not yet maintained in the super block free inode list but they will be block in
the super block free inode list, when this super block free inode list becomes empty. Now this
being the situation whenever a process puts a request for creating a particular file or creating a
particular directory, creation means this is being created for the first time. So it has to be
allocated an inode which is not yet allocated. So what it has to do is, it has to change the super
block free inode list. On checking it finds that the first inode that appears in the super block free
inode list is inode number 100 that means inode number 100 is not yet allocated to any other
process.
So this inode number 100 will be allocated to the process or allocated to the file or directory
which is being created. On allocating this inode number 100, inode number 100 will be removed
from this super block free inode list. Now once you allocate this inode number 100, this inode
number 100 has to be located on the inode block, make an incore copy of that inode so for the
inode was free that is type field was set to 0. Now the inode is no more free, that means the type
field has to be set to either regular file or directory depending upon to which it is being allocated.
Reference count has to be made to one because file has been open for creation and all this
updated information of this inode has to be written on to the disk inode. With this allocation of
this inode to the file or to the directory is complete. Then other operations on the file or directory
will continue as it is.
Next time another process tries to open a file or a directory, this inode number 105 will be
allocated so that way it will continue. Last when all these entries are empty, the last inode which
is maintained in the super block free inode list is inode number 200. So when the situation comes
that this inode number 200 is to be allocated to the requesting process then with allocation of this
inode number 200, the super block free inode list becomes empty. So when it is going to become
empty then what is done is the super block free inode list is filled up with other free inodes or
unallocated inodes on the file system. For that we have to search for the inodes which are
unallocated and the search operation will start from inode number 201. So this is an inode, that is
the last inode on the super block free inode list is called a remembered inode. That means you
have to remember this inode number for searching for other unallocated inodes on the file
system. So starting from inode number 201, you search for other unallocated inodes on the file
system and whatever inode number you get sequentially, this search is sequential, you fill up
those inode numbers in the super block free inode list and finally this remembered inode in the
super block free inode list. So there can be a situation that suppose the super block free inode list
can contain list of 100 inodes and I am starting my search operation from say inode number 201,
9
there are two situations that I have starting from 201, I have more than 100 inodes free,
unallocated or I have less than 100 inodes unallocated. So filling up of this super block free
inode list will stop when you find that you don’t have any other free inode on the super block
free inode list or the super block free inode list is filled up. So at the most I can put 100 inode
numbers or less than that if I don’t have sufficient number of inodes which are unallocated from
the file system. So this is the situation, I mean this is the way in which the inodes will be
allocated to different new files or new directories when they are created. Now the reverse process
is unallocating a particular inode. How do you unallocate a inode? An inode will be unallocated,
you find that inode becoming free whenever you close a file and the reference count becomes
zero but that is not unallocation of an inode.
In that case what you are doing is, you are simply removing the inode from the main memory,
you won’t have an incore copy of the inode but the inode is still allocated to the file and inode
has to be made free or unallocated, when the file is deleted or the directory is deleted. So when
you delete a file or you delete a directory, in that case I have to put this one in the super block
free inode list if possible. So for doing that what is done is you simply check; what is the status
of the super block free inode list. If you find that I have some empty space, an empty entry in the
super block free inode list, I can simply write the inode number which is being unallocated into
that empty entry that is one way.
If there is no space in the super block free inode list, empty, then what has to be done is the inode
number which is being unallocated, if you find that inode number is less than the remembered
inode because this remembered inode tells me that from which point I have to search for new
inodes, unallocated inode. Then you replace this remembered inode by this new inode number
sorry here the search operation will starts from inode number 200 itself. So if you find that
suppose the new inode which is being unallocated is inode number 55 and at that point, I don’t
have any free space in the super block free inode list. So what I will do is I will simply replace
this 200 by this inode number 55.
So that next time I search for free inodes, unallocated inodes, this 55 will be encountered.
Otherwise if this new inode which is becoming free is more than the remembered inode then I
simply forget it, don’t make any changes in the super block free inode list. Suppose the inode
number which is being made free is the inode number 210, this is being unallocated. My earlier
remembered inode number is 200, next time I will start searching from this inode number 200. so
210 will any way be searched, so I have these are the different possibilities whenever an inode is
unallocated that is if I have an empty space in the super block free inode list, I simply put this
new inode number which is unallocated into that empty space. In case super block free inode list
is full and the inode number that is being unallocated is less than the remembered inode, you
replace the remembered inode by this new inode number. If it is more than the remembered
inode number then, I don’t make any change in the super block free inode list. I simply mark the
inode as unallocated by setting the type field equal to 0 on the disk copy of the inode. So that
next time, the search operation starts from this remembered inode, that inode in any case be
searched. So with this I hope that allocation of an inode or unallocation of inode is clear. So next
day we will talk about management of disk blocks.
10
Digital Computer Organization
Prof. P. K. Biswas
Department of Electronic and Electrical Communication Engineering
Indian Institute of Technology, Kharagpur
Lecture No. # 26
Secondary storage Organization III
So, we are talking about the file system organization with respect to the UNIX file system and
we have said that for accessing any file, what you have to access first is the inode of the file
because it is the inode which maintains every information of the file including its ownership, the
access permissions, group ownership, the date of modification and even the table of contents that
is which part of the file is loaded in which block in the secondary storage. So in the last class we
are talking about allocation of an inode to a file or a directory that is newly created.
So whenever we want to allocate any inode to a file or a directory that is to be created, we have
to first see that what are the inodes in the file system that are still free or not yet allocated to any
of the existing files, any of the existing files or any of the existing directories. And thus for such
operation the super block plays a major role in the sense that super block contains a list of inode
numbers which are still unallocated. And we have also said that this list is not an exhaustive list
in the sense that only a subset of the inodes which are not yet allocated will be contained in the
super block free inode list. There can be other inodes in the file system which are still
unallocated but they will be brought into the super block free inode list when the super block free
inode list becomes empty. So the situation was something like this.
We can consider the super block free inode list as a list of inode numbers, so this list can be
something like this. I can have an inode number say 50, inode number 78, say inode number 90,
1
100 so like this it can continue, may be this is the inode number 201. So this is the situation when
the super block free inode list is full, so this is the super block free inode list. So whenever a
directory or a file is created for the first time, you have to allocate one of the inodes to the
directory or the file which has been created. So typically what is done is you take an inode from
this super block inode list, so here the inode 50 will be allocated to the file that is newly created
file or the directory whatever it is. And this location, once this inode 50 is allocated then this
location, this entry in the super block free inode list will be empty.
Next time another file or directory is created, you have to allocate this inode number 78 to that
file or directory. So I will have two empty entries in this super block free inode list. So this way
when we have to allocate the last inode that is the inode number 201 from this super block free
inode list, now with this after allocating this inode number 201, the entire blocks, entire super
block free inode list will be empty. So when we have to allocate this last inode remaining in the
super block free inode list in that case we have to search the file system for other inodes which
are still free. So that has to be searched from the inode blocks which will contain the list of
inodes and we have said that for searching this operation, we will just check the type field in the
inode because if the type field is equal to zero that indicates that the inode is still free it is not yet
allocated to any of the files or the directories.
So you have to search the inodes from this inode number 201 which are still free and fill up those
inode numbers in this super block inode list. And this can be, filling up can be to the extent of the
maximum capacity of the super block free inode list or until there is no other inode which are
free on the file system. So after filing up the super block free inode list then only the last inode
that is inode number 201 can be allocated to the newly created file or newly created directory
and because the search operation has to continue from this location so this inode number is also
called a remembered inode.
Similarly, in the reverse process we have said that whenever inode is made free by deleting a file
or by deleting a directory in that case we have to check what is the status of the super block free
inode list. If there is any empty entry in the super block free inode list, in that case the new inode
number which is being unallocated that numbers can simply put into the empty entry but in case
the super block free inode list is full, there is no empty entry in the super block free inode list.
Then what we have to do is we have to compare the number of the inode which is becoming free
with the remembered inode number.
So if this number which is being free is more than the remembered inode number, then I don’t
have to make any change in the super block free inode list. Only thing that I have to do is in the
inode block that corresponding inode type field has to be set equal to 0. So next time when the
kernel will search for free inodes from the inode list because the remembered inode is less than
the inode number which is becoming free so that inode number will be checked and it will be
found that inode to be free and eventually that will come into super block free inode list and
subsequently allocated. But if the newly freed inode number is less than the remembered inode
number in that case we said that we will replace this remembered inode number by this released
inode number because if we don’t put that in the super block free inode list because the newly
released inode number is less than this, when the kernel will search for other free inodes it will
skip that, that will not be taken into consideration. Whereas if I replace this remembered inode
2
by this newly released inode number, my search operation will start from the newly released
inode number for free inodes and because this remembered inode is more than that so this will
eventually be checked and subsequently allocated.
So that is why this special measure has to be taken when an inode is released because of deletion
of a file or deletion of a directory and the super block free inode list is full. So if this newly
released inode number is greater than this I don’t have to bother, I simply make the type field of
newly released inode in the inode block equal to 0 but if it is less than the remembered inode in
that case I have to replace the existing remembered inode by this new inode. So this is how the
allocation and deallocation of the inodes have to be performed.
Now similarly as we said that whenever you create a file or you modify a file, what may be
needed is, if a file is expanded you need more and more disc blocks to contain the file content
where the file content will be stored. So again you have to get new and new blocks to store the
file data and those blocks must be free. If a block is already allocated to contain some file data,
then that block cannot be allocated to a new request. So whenever a request for a new data block
is made, we have to check the file system to find out that what are the blocks which are free are
not allocated to any of the existing file or existing directory and a block from that free list has to
be allocated to the new file.
So earlier whatever we have discussed about is the inode allocation. Inode allocation will only
contain the file information, information about the file but actually data of the file will be
contained in the data blocks. For that also whenever a file is created or a file is modified it needs
more and more data blocks or the reverse process is if you delete a file then the data blocks have
to be released so which has to go to the free block list. Now maintenance of a free block list is
slightly different from the maintenance of inode list. The reason is, in case of inode simply by
checking the type field of the inode because every inode has a fixed structure, it has a fixed
number of fields every field contains a fixed number of bytes.
3
So in case of a inode simply by checking the type field, we can say that whether the inode is free
or the inode is already allocated which is not possible in case of data blocks because a block may
contain any arbitrary data. So for maintenance of free data blocks, our mechanism has to be
different from the way we maintain the free inode list. So in case of data block what is done is all
the free data blocks are maintained in the form of a link list, in case of inode we don’t use a link
list and the link list is something like this. In super block we have a free block list as in case of
free inode list. This free block list contains a list of block numbers which are free. So suppose the
block numbers are something like this 10, 11, 15 say 20, 50, 100, this is what is super block free
block list. So up to this, it is similar to what we do in case of super block free inode list.
Super block free inode list contains a list of free inode numbers. Here the super block free block
list contains a list of free block numbers but the difference is in case of free inode list, the last
inode number was called the remembered inode. This is the number which is not a pointer but in
case of super block free block list, the last number of the block is a pointer, pointed to the block
number 100. So this is block number 100. So as the super block free block list contains a list of
block numbers which are free, similarly this block number 100 will also contain a list of other
free blocks in the file system. So like this it will continue, say may be here it is 101, 110, 200 and
this way it can continue may be this is 305. Again this last entry that is 305 it is a pointer pointed
to the block number 305, again this block 305 will contain a number of block numbers which are
free. So this one may be say 310 and it can continue may be this is 400. So you find the
difference between the free inode list and the free block list. In case of free inode list we don’t
have any linked list structure, simply because by checking the type field of an inode, I can find
out whether the inode is free or the inode is allocated which is not possible in case of blocks
because a block may contain any arbitrary data.
So I don’t have any specific structure for a block so that by taking a particular field I can find out
whether the block is free or the block is allocated. So I have to have a special mechanism for
maintaining the free block list and that is done like this. The super block contains a list of free
blocks. The last block number is actually a pointer which points to the block itself. So this is
block number 100, so when I come to this block number 100 by following this pointer I come to
block number 100 physically which again contains a number of free block numbers and that way
it continues. So when the free block list is maintained in this form, how the allocation is to be
made? Whenever a process puts request for a new block you come to the super block free block
list. Take a block number, if this is not the last block number in the super block free block list
take a block number I find that here block number 10 is free, so block number 10 is allocated to
the process which has requested for a data block. Next request can be made by assigning block
number 11, next request can be made by assigning block number 15.
So this way you find that whenever I allocate a block from the super block free block list, the
corresponding location in the super block free block list becomes empty. So it will continue like
this. Finally, when it comes to the last block last block number, suppose all other locations in the
super block free block list is empty, all those blocks have been allocated. The next request has to
be made by allocation of block number 100 but if I allocate block number 100 without taking
any precaution what will be done? I will lose the pointer information to this particular block that
means though I have a number of free blocks in the file system still existing, none of those free
blocks can be allocated to any further request.
4
So whenever any block is to be allocated, you have to check whether the block number that is to
be allocated from the super block free block list is the last block or not, last block in the super
block list. If it is the last block then what we have to do is we have to copy the content of block
number 100, here it is 100 so copy the content of block number 100 in to the super block and
after that block number 100 can be allocated to the requesting process. So in effect the situation
that we will have is something like this.
Taking this same example, when block number 100 is to be allocated or situation which is
something like this, super block free block list will contain block number 101, it will contain
110, it will contain 200 like this, the last entry will be 305 which is a pointer to block number
305, block number 305 contains other block numbers say 310, continues last number is say 400,
this is a pointer to block number 400. So you find the situation that we have. In this case when
100 is the last block number present in the super block free block list and you have to allocate
block number 100. So before allocation of block number 100, what we do is, this is the content
of block 100, you simply copy the content of block 100 into a super block free block list.
Once this is copied into super block free block list then this block 100 is free and I also saved the
pointer information. So now this pointer instead of coming from block number 100, this pointer
to this block 400 will come from super block free block list. So this is precisely what we have
done here, this is our super block free block list. So simply block 100 has been removed from
this pointer and this block 100 can be allocated to the process where it is requested for a new
block and other pointer information remains intact. Next allocation can again start from 101 then
to 110, then to 200 and so on. When 305 comes then the content of this block number 305, this is
block number 305, content of 305 has to be copied into super block free block list.
So the remaining pointers now will point from the super block free block list and this block
number 305 can be allocated to the process where it has requested for. So this is how the
5
allocation of the free blocks from the file system can be done. Again the question is the reverse
process. Whenever any process releases some block and because we have said that this is the
way all the free blocks in the file system will be maintained and you know that there is an utility
program in the UNIX operating system which is called make file system or mkfs.
The responsibility of this software mkfs is to arrange all the free blocks in the file system in the
form of such a linked list. The movement any free block goes out of this linked list structure that
free block is no more accessible, I mean it cannot be allocated to any process. So to make any
free block accessible to the kernel, the free blocks must be part of such a type of linked list. So
naturally whenever a new block, a block is made free by deletion of some directory or by
deletion of some file or by truncation of some file, the block which is becoming free that has to
be coupled with this linked list somehow.
So the simplest way is whenever a block is made free, I just check the super block free block list.
If I find that there is an empty entry in the super block free block list, I simply put the number of
the block which is made free into that empty entry in the super block free block list. Then the
block becomes part of this linked list but the problem comes when I find that a block is
becoming free but the super block free block list is not there. There is no room in the super block
free block list. In such case what you do is you just copy the content of super block free block
list in the new block which is becoming free and just put the number of that block in the super
block free block list.
So in effect what I have is, if I have this kind of situation say here all the entries in the super
block free block list are full. I don’t have any empty room in the super block free block list and
in this kind of situation, if a block number say 10 becomes free, say this is block number 10
which is becoming free. And I don’t have any room in the super block free block list to put this
block number 10. If I can put block number 10 then block number 10 is part of this free list and I
don’t have any problem. So in this case what will be done is simply the content of the super
block free block list will be copied into block number 10. So block number 10 will contain 101,
110, 200 and so on last entry is 305. This 305 is pointer to block number 305 which contains
other block number say 310. It continues, this is say block number 400 which is pointed to block
number 400 and what I do in super block free block list is, just put this block number 10 as a last
entry in the super block free block list. So this is super block and this is the pointer to block
number 10.
All other entries are empty entries; there is no other entry in the super block. So you find that
now this block number 10 has become part of this free list. So whenever a process puts request
for another block in that case this block number 10 has to be allocated to that particular block but
before allocation of block number 10, the content of block number 10 will be copied into the
super block free block list and block number 10 will be allocated, so effectively, I come back to
this configuration. So whenever allocation of a block is to be made, you have to check the super
block free block list, if it is not empty just take a block number and allocate that block.
If you find that after allocation of that block, super block free block list is going to be empty, you
follow the pointer, come to the block which is next, copy content of that block into super block
free block list and after that the block number can be allocated. Similarly, while freeing the
6
blocks, if I have an empty entry in the super block free block list, I simply put the block number
in the super block free block list. If there is no empty entry, I copy the content of super block free
block list in the new block and put the number of the new block in the super block free block list.
So the entire linked list structure is maintained and this special kind of data structure has to be
maintained for data block which is not needed in case of inode blocks, inodes simply because
inodes have well defined structure but data blocks don’t have this. It will be done sequentially
because whenever you return the blocks, the return has to be done sequentially one block at a
time not a chunk of blocks simultaneously. So what is done is whenever you put a file or when
you have such a situation, there is a process called garbage collection, garbage collection. So
what garbage collection program does is it tries to find out that what are the blocks which are
reachable and makes this kind of list with only the reachable blocks and whatever is the bad
sector, I mean typically the bad sector that goes out of the list.
Initially they are in the increasing order, when the first time the mac file system works they will
be in the increasing order but after that order is not connected. I should not say order is not
important, the order is important in the sense that it determines that what is the performance of
the file system because if I can somehow ensure that different parts of the file will be stored in
subsequent blocks, the throughput of the file system will be high but if the parts of the file has
scattered in different blocks which is spread over all over the file system in that case the time to
access the different blocks will be different. So the throughput of the file system will degrade. So
what can be done? Defragmentation. When you find that the performance of the file system is
becoming worse, you just run defragmenter. Defragmenter what it will do is it will reallocate the
blocks and after that this free block list will be maintained in increasing order.
So defragmenter will try to put different parts of a file in consecutive blocks if possible but that
is not a continuous process, it has to be done intermittently and in most of the cases it is done
manually. Yes, any other question? In this scheme the block which is released most recently will
be used first but that does not matter. Yeah, not the best policy in the sense say block released
means the block does not contain any more valid data. So whichever way we allocated that does
not matter, so for us the correctness of the system is concerned but it may matter for performance
that is the throughput. Quite possible. May be possible because their reading and writing
operation is quite frequent so that is possible but so far as throughput is concerned, we always
expect that all the file systems should be clustered at the one end, so far as throughput of the
system is concerned. So in any case we have to accept it. Then we will stop here today. Thank
you.
7
Digital Computer Organization
Prof. P. K. Biswas
Department of Electronic & Electrical Communication Engineering
Indian Institute of Technology Kharagpur
Lecture No. # 27
I/O Subsystem Organization
Today we are going to discuss about what is called an input output or I/O subsystem. You know
that in any computer system, a number of input output devices including say keyboard, video
monitor, printer then even the hard disc is also considered as an input output or I/O system.
Now when we talk about this I/O subsystem, it is the unit which interacts with the input output
device. So if you look at any computer system as we have seen earlier that in a computer system
you have at the heart of the computer system which is the CPU and the CPU is connected with a
number of input output systems in addition to the main memory. So I will have a number of
buses few of the lines taken together will be called control bus then address bus and data bus. So
suppose this represents the control bus, second set of lines represents the address bus and the
third set of line may represent the data bus.
So whenever you connect to any input output device, you have to have an I/O interface unit. This
is what we will call as input output interface and this input output interface actually connect with
the input output device and as we said that this device can be of various forms. So actually this
input output interface, this is what interfaces the device with the CPU. So interface unit will have
the connection with the control bus. It will also have connection with the address bus and it will
have the connection with the data bus, so the connection will be like this. Now when we talk
about an I/O subsystem, we can have three different kinds of I/O. The first kind of I/O is called
programmed I/O that means the input output device is under direct control of the CPU, so any
software which has to be executed to access the input output device will be executed by the CPU.
1
I/O operation will be initiated by the CPU, it will also be terminated by the CPU. The second
kind of I/O that we can have is called interrupt I/O. In case of interrupt I/O whenever an I/O
operation is to be initiated, the CPU simply informs the I/O interface to start the I/O operation.
At the end of the I/O operation, the I/O interface will interrupt the CPU informing that I/O
operation is complete. Now whatever the CPU has to do with that data either received from the
I/O or sent to the I/O that the CPU can do now and the third kind of I/O is what is called DMA or
direct memory access and in this case the data is transferred between the input output device and
the main memory directly by the DMA unit. The CPU does not come into picture at all.
So if I go for this programmed I/O in that case what will be the nature of the I/O interface unit?
If I expand this I/O interface unit, the I/O interface unit will have a number of components. The
first component will be that since every I/O device will have an unique address in the system, so
I have to have an unit called address decoder. So in this I/O interface unit, I will have an unit
called address decoder and you might be knowing that there are some other units which are
known as say in register, out register. Then I have to have what is called a command word and I
have to have another one called status word. So in this I/O interface unit if I go for the
programmed I/O kind of configuration, the I/O interface unit will have an address decoder, it will
have an in register so that for any inputting operation the data which is transferred from the input
device is stored in the in register then the CPU can read the data from the in register.
Similarly, for an output device when a data is to be transmitted to the out or stored in the output
device or is to be sent to the output device, the CPU will write data into out register then from
the out register it will go to the device. Command register is mostly used to configure the I/O
operation that is at what speed the I/O should operate, what should be the word length or how
many bits will contain the data, what will be the error correcting message all those informations
will be configured in the command register. The status register will inform the status of the I/O
device. So these are the kind of things which you might have used in your microprocessor
course, say for example if you want to connect an USART that is universal synchronous
asynchronous receiver transmitter so in that case what we have to do is we have program what is
the baud rate that is at which rate the data is to be transmitted.
You also have to program that how many start bits or how many stop bits you want to have, what
is the data length whether a character will consist of 7 bits or a character will consist of 8 bits, all
those informations are to be stored or to be written into the command register and then only the
I/O interface will act accordingly. Similarly, the status register will be used, suppose the CPU
wants to read a data from an input device, so firstly by configuring the command register, it
configures that in which way the data communication will take place then the status register will
tell that whether the data which is to be read is available in the in register or not that is whether
this device is ready with the data. So that information will come from the status register and from
the status register whenever the CPU finds that the data is ready in the in register, the CPU can
read the data from in register. So for doing this after sending a command to the command
register, what the CPU has to do is the CPU has to remain in a loop always checking the
condition of the status register whether the data is ready or not. So only when it finds that the
data is ready, it reads the data from the in register and comes out.
So this is why this kind of I/O operations is called program I/O because all the input output
operations are directly done under the direct supervision of the CPU through some program.
2
Now each of this in register, out register, command register or status register they will have
different addresses, that means I have to have some connection from the address decoder to the
in register. I have to have a connection from the address decoder to the out register, I have to
have a connection from the address decoder to the command register, I also have to have a
connection from the address decoder to the address register so that I can have unique address for
each of these registers. In some of the I/O interfaces you will find that the in and out registers
they have the same address.
Similarly command and status registers they have the same address. There the idea is, suppose in
out registers they have some address say AA, AA hexadecimal, so with that AA address if I want
to write anything, the data will always come in the in register. If I want to read anything from
AA address, the data will be read from the out register sorry it is opposite. Similarly, here
suppose this has an address of AB both command register and status register, so with address AB
if anything is written into this it will be written into command register. If anything is read by the
CPU with address AB, then the information will be read from the status register that means these
registers are unidirectional. To one register you can only write, another register can only be read.
I am taking a specific case, there are a number of situations when the I/O interface unit will have
much more number of registers than this.
This I/O interface unit can have an internal memory, say for example if I want to design an I/O
interface for interacting with the key board, for interacting with the video unit in such cases the
I/O interface unit will have some internal memory in addition to these registers. So this is just a
particular example, a very simple example the system can be complicated further. Not only that,
the I/O interface unit can be a processor itself, this itself can be a sequential machine. So in some
cases if our I/O operation is very, very complex in that case such simple interface may not be
sufficient. So for every I/O operation the task can be given to the I/O interface unit or I/O
subsystem, the subsystem will take care of the task in its entirety, it will not depend upon the
3
CPU. In such cases its I/O interface unit has to be a processor by itself. In many cases such units
are called I/O channels, I/O channel.
DMA is a kind of such channel, I will come to that. So in this case this in out registers, command
registers and status registers through this you can control all the input output operations. So
obviously this address decoder it will have a connection from the address bus. All these registers
in registers, out registers, command register and status register they will have connection with
the data bus so I can put it this way and at the same time, the control signals which come, this
control signals also propagate to these registers because among the control signals we have the
read signal, write signal and all those things, so whenever a read operation is to be performed
this in register has to be activated. Whenever an output operation is to be performed or write
operation is to be performed either the out register or the command register will be activated
depending upon what address comes from the address decoder. So if you expand this I/O
interface unit, it will look like this and here I will have the I/O device and this kind of interface
unit is mostly suitable for programmed I/O kind of operation.
Now as I said that there is another kind of I/O operation which we call as interrupt I/O. In case of
interrupt I/O what is assumed is, whenever some device needs some service, so in this case the
serve was the initiated by the CPU, it was terminated by the CPU. In case of interrupt I/O we
assume that whenever a device needs some service, the device interrupts the CPU. Now the
actions or the services for different devices are different. The service needed by a hard disc will
be different from the service needed by a keyboard or the service needed by a keyboard will be
different from the service needed by an output device like printer. So in the CPU, what the CPU
will do is, on getting an interrupt it will identify that which interrupt it is and following that
identification it will execute a program which is called an interrupt service routine and it is this
interrupt service routine which meets the requirement of the device.
4
So whenever any I/O device needs some service from the CPU, it is the responsibility of the I/O
device to put the request, service request in the form of an interrupt. So I can have two different
kinds of interrupts. One kind of interrupt is called a priority interrupt, which you have done with
an 8085 microprocessor where you might be knowing that there are different types of interrupts
7.5, 6.5, 5.5, trap and all these things and there is another interrupt which is called INTR. All
these interrupts, interrupt lines have got different priorities, trap has got the highest priority,
INTR has got the lowest priority or among the vectored interrupts trap has got the highest
priority and RST 5.5 has got the lowest priority.
See if I go for this priority interrupts, what are the units that we need? Firstly, because a number
of devices can put the interrupts simultaneously to the CPU, if the interrupts are not simultaneous
then I don’t have any problem. If only one device puts an interrupt at a time, then that interrupt
can immediately be acknowledged and serviced but the problem comes when more than one
devices interrupt simultaneously. In that case a decision has to be made that out of all these
devices which device has to be serviced first. I have to set some interrupt priority level and to do
this what I need is a priority encoder, so this is what is known as a priority encoder.
Priority encoder has got a number of input interrupt lines; these lines have got different priority
levels. Now out of all these lines if more than one line’s are active simultaneously then the line
which has got highest priority among them will be selected and passed to the output of the
priority encoder. Now along with this, what is needed is because now I have a number of devices
connected together and many of them can give interrupt simultaneously, when the interrupt is
acknowledged by the CPU then the device whose interrupt is acknowledged that the device must
know so that the device can start operation. So along with this priority encoder, we also have to
have another unit, the reverse unit which we call as a decoder so this is a simple decoder.
The devices will give an interrupt suppose this is, I name this as interrupt request line and this is
the interrupt request line 0. When an acknowledgment comes, the acknowledgment should also
reach the device and the acknowledgment will be generated by the decoder unit, so this is
interrupt acknowledgment 0. Similarly, we will have interrupt request 1, interrupt
acknowledgment 1, which will also be generated by the decoder will go to the device which is
connected to this interrupt request one line, so this is interrupt acknowledgment 1.
Similarly, if there are say m number of devices then this will be interrupt request m and similarly
an interrupt acknowledgment m will be generated by the decoder. Now before an interrupt is
actually entertain by the CPU, the CPU has to compare, what is the level of the interrupt which is
coming from a device with respect to the interrupt level or priority level of a task which is under
execution? So if the CPU is executing a task of which the interrupt level is say 5, now while that
task has been executed if another device whose interrupt level is say 2 puts an interrupt then if
the priority of interrupt 2 is less than the priority interrupt 5 then this new interrupt will not be
accepted. Whereas if the priority of 2 is greater than the priority of interrupt level 5 then the new
interrupt will be accepted, so I have to have some memory element which will tell me that what
is the current priority level of a job which is under execution. So this gives you the current
priority level. I have to compare this current priority level with the new priority with which an
interrupt has come. So I must need a comparator, one of the inputs to the comparator will be
from the current priority level and the other input to this comparator will be from the new
5
interrupt priority level that has come. So this is a comparator let me call this input as A, this
input as B.
So I will have an output which will actually give the interrupt request to the CPU. So this is the
actual interrupt request to the CPU and I will generate this interrupt request following some
logic. So my logic will be that if a priority level low indicates a high priority, I can have different
types of logic. Suppose at the input I have 8 devices, so I can have priority levels from 0 to 7. I
can assume that a priority level 0 is the maximum priority or highest priority or I can also assume
that a priority level 7 is the highest priority. So accordingly this comparator has to be set.
So if I assume that the lowest priority level indicates the priority is actually high that means
whenever B < A then only then this interrupt will be generated. So it will be an output whether
B < A or not. So if B < A, then only you are generating an interrupt.
So obviously this interrupt has to be accepted by the CPU and when the interrupt is accepted by
the CPU in turn the CPU will give an interrupt acknowledgment.
On getting an interrupt acknowledgment that means the CPU is now going to take the new task.
So the current priority level which was set in this current priority register that has to be changed,
it has to get this new priority level. So along with coming to this comparator, this priority
encoder output should go to the current priority level register and this has to be loaded. So I have
to have a load input to this and this has to be loaded whenever an interrupt acknowledgment
comes, so interrupt acknowledgment will be given by the CPU. This interrupt acknowledgment
will give a load input to the current priority level, when this current priority can be loaded into
the current priority register and at the same time whenever this acknowledgement comes, it also
has to give a signal to the decoder, decoder makes use of this current priority to generate, to
activate one of the decoder output lines.
6
So whenever this acknowledgment comes from the CPU that means the new interrupt is being
accepted, when this new interrupt is accepted, the current priority is changed. The new priority
value along with this interrupt acknowledgment signal that comes to the decoder and accordingly
the decoder generates an interrupt acknowledgment signal which goes to the device which is
being selected. So this is the total scheme of an interrupt controller, if I want to use the priority
interrupt scheme. So this whole thing is the priority interrupt controller. Yes. That is what I have
assumed, it can be reverse also. For this case interrupt level 0 is of highest priority. I can have the
reverse also, I can make interrupt level 7 to be the highest priority but in this case this
comparator output will be changed instead of B < A, I have to make it B > A. That has to be
done by the device itself, device controller has to take care of that.
Say in the device controller, the device controller will put an interrupt request then it has to wait
for an interrupt acknowledgment, until and unless it gets the interrupt acknowledgment the
interrupt request line should be kept high that has to be taken care of by the device controller in
this configuration, correct. However, in case of 8085, such a type of thing is implemented in
8085. So if two interrupt comes say RST 7.5 and RST 5.5 simultaneously then RST 5.5 goes into
an interrupt, internal register. So after 7.5 is serviced, 5.5 will also be serviced. There are
additional interrupt controller chips also. Yes, some question from this side.
This is the interrupt acknowledgment, the other one is the current priority level. Say the logic is
because this decoder has to activate one of the decoder outputs. Which decoder output has to be
activated, that depends upon this priority which has been accepted. So that is why it needs this
input as well as this interrupt acknowledgment both are needed to generate an output signal high.
The other kind of interrupt which can be used is what is called a Daisy chaining.
In case of Daisy chaining we don’t have such a complicated circuit. Daisy chaining concept is
very simple, say I have a set of data lines which are connected to the CPU, I have a single
interrupt request line. So these are the data lines or data bus and this is the interrupt request line,
7
in turn an interrupt acknowledgment will come from the CPU. I will connect a number of
devices on this system. Say this is device number 0, I have device number 1 like this, I will have
say device number m. The Daisy chaining concept is, whenever a device puts an interrupt, all the
interrupts are connected to the same interrupt request line. So I can have some wired OR kind of
connection. All the devices are connected to the same data bus and this is usual, there is nothing
special about it. What is special is the way the interrupt acknowledgment signal is connected.
What is done is, whenever the CPU gives an interrupt acknowledgment, the acknowledgment
goes through the first device. From the first device, the first device gives an interrupt
acknowledgment output signal, this output is connected to the interrupt acknowledgment input of
the next device and this way it continues. The device m will get the interrupt acknowledgment
from device m-1.
Similarly, device m will give an interrupt acknowledgment out signal which will go to device m
+ 1. So this way it continues. For any device say device j the logic is like this, interrupt
acknowledgment of j will be active provided you get an interrupt acknowledgment out from
device j - 1 and interrupt request of j - 1 and enable j - 1, this is not true. So the concept is every
device will have an enable signal, so device can put the request only when the corresponding
device is enabled. Now because the acknowledgment signal moves from one device to another
device in the form of a chain, so you find that this device one can get an acknowledgment signal
from device 0 only if there was an interrupt to the CPU. The CPU gives an interrupt
acknowledgment signal, first is it reaches the device 0 but for device 0 the condition is
something like this, enable of device 0 and interrupt request of device 0 inward of this if this is
true.
This means two things either the device was not enabled or the device was enabled but it did not
put the interrupt. Only in this case the acknowledgment signal will reach device 1 from device 0
and the same logic follows. Acknowledgment signal will reach device 2 from device 1 if this is
true for device one. Similarly, device 1 can generate an output acknowledgment if it gets an input
acknowledgment and the input acknowledgment can come from device 0, if this is true for
devices 0. So we find that the acknowledgment signal flows from one device to another device in
the form of a chain. So that is why it is called a Daisy chaining priority interrupt scheme and here
of course some priority is in built because the device which is nearest to the CPU has the highest
priority. Isn’t it? Suppose both device 0 and device 1 both of them put interrupts simultaneously.
Then because device 0 is enabled and it has put the request so ireq and enable and these two
invert it, it becomes 0 that means device 1 does not get the acknowledgment signal.
So device 0 can start the operation but device 1 cannot start the operation. So some priority is
already in built in the scheme that is a device which is nearest to the CPU will get the highest
priority, device which is farthest from the CPU will get the lowest priority. You have to short
this. No, actually these adapters are like that. If you connect it, it will be through this, if you
disconnect it in that case that will be shorted, that is how the adapters are made. In fact, this kind
of scheme was used in, have you seen the earlier HP machines, HPIB called HP Hewlett Packard
interface bus or something like this. HPIB was using this kind of scheme, that is any number of
devices you just connect one device to the other device by a patch cord, that’s all. You can
connect any number of devices on the system.
8
(Refer Slide Time: 00:35:22 min)
Coming to the other kind of I/O operation that is DMA or direct memory access. Now in this
earlier scheme whether we go for programmed I/O or an interrupt I/O, our basic operation is to
transfer the data from the memory to a device or getting the data from a device storing it into
memory. In case of a programmed I/O, the CPU itself will take the initiative to read a data from
a memory, write that into an output device or read a data from an input device and write it into
memory. That means the data has to be first read by the CPU then only it has to be given to the
proper destination, transferred to the proper destination and that is true both in case of
programmed I/O as well as interrupt I/O. In case of programmed I/O the initiative is taken by the
CPU, in case of interrupt I/O, the interrupt signal tells that when that action has to be performed
but the action is done by the CPU. In case of DMA the concept is slightly different. Whenever
you have to transfer some data, may be from say an input device to the memory or from memory
to the I/O device in that case the CPU does not come into picture.
So the basic concept is whatever operation that was to be done by the CPU is now done by a
separate controller which is the DMA controller. So whenever some device puts a request to
transfer some data from the device memory to the main memory, the device puts a request signal
to the DMA controller. In turn DMA controller gives a signal to the CPU that it wants to perform
some DMA operation. On getting that signal the CPU gets a DMA acknowledgment and what is
done after the DMA acknowledgment? Whenever the CPU generates a DMA acknowledgment at
the CPU, at the same time, the CPU releases all the buses the data bus control, bus address bus
everything. Those are no more physically or logically connected to the CPU. Now this DMA
controller becomes the bus master. So what it does is it reads the data from the memory, sends
that to I/O device or reads the data from the I/O device sends that to memory. So all the
operation which otherwise would have to be done by the CPU, now it is to be done by the DMA
control.
9
So accordingly the DMA controller will have to have a number of registers because it has to
know that which device has to be activated. Simultaneously it also has to know that which
memory location is to be accessed either for reading purpose or writing purpose. So number of
units that will be present in the DMA device will be same as the number of units that you have in
the CPU, more or less same, it is not identical. So some of the units will be say memory address
register, I have to have memory address register, I also have to have an information about, what
is the length of the data that has to be transferred that is count. So if I want to transfer say 100
bytes of data from the main memory to a device, in that case what I can do is, I can simply
increment the memory register address by 1 in a loop of 100 and that can be controlled by this
count value. And similarly, I also have to have some control unit which will give the control
signals to the memory as well as the I/O device.
On the other hand, I have to have an I/O address decode, decoder because may be a number of
devices are connected to the same controller, same DMA and the DMA controller has to activate
one of the devices, so there has to be an I/O address decoder. In addition to this there has to be a
bus control unit and in addition there will be a number of other things like in some cases
whenever the data is to be transmitted by the different bytes are packed together to make a single
packet and that is transmitted. All those different additional control signals can be
accommodated in the DMA controller. So on one side the DMA controller will be interfaced
with the memory so for that we need the address lines, we need the read write signals, we need
the bus request, bus request signal which will go to the CPU following this bus request the CPU
has to give a bus grant signal, which will come to the DMA controller from the CPU and on
getting this bus grant signal from the CPU, the DMA controller can start operation and obviously
I have to have the data lines. So this is the part, this side is to interface the DMA controller with
the memory and the CPU.
On the other side the DMA controller has to be interfaced with the device so that means I will
have a number of control lines for controlling the I/O device I also have to have a number of data
lines which will carry the device data. So now we find that the responsibility of this DMA
controller will be that on one side it will be interfaced with the device, so it can get the data from
the device and on the other side it is interfaced with the memory, so it can send the data to the
memory. Similarly, it can get the data from the memory and send the data to the output device
and while performing this operation, the read and write operations by the CPU is no more
needed. Got it? And because of this additional registers in this DMA controller, the operation of
the DMA controller can be much faster than that in case of the CPU because in case of CPU
firstly the CPU has to read the data, put it, get it into its internal register then from the internal
register it has to send the data to the destination, so two cycles are always necessary if I want to
transfer the data through CPU, whereas similar operation can be done in a single cycle by
making use of this DMA controller.
Again when you come to the DMA controller, I can have two different options. As I said that I
mean this is a kind of channel because this DMA controller itself is a processor which is, which
can work independently of the CPU. So again in this case of DMA controller or channel as we
said that such kind of devices are also called channels, I can have two types of options, one is
called a selector channel and other one is called a multiplexer channel. What is the selector
10
channel and what is the multiplexer channel? Suppose I use the same DMA controller to which a
number of devices are connected.
Now a selector channel, what it will do is suppose all the devices want to get some service
simultaneously. Then a selector channel will select one of the devices that device will complete
its operation then only the operation of the other device will be initiated. In case of multiplexer
channel, the operations of different devices are time multiplexed that means if there are say 5
devices connected, first device will operate for say 1 millisecond then during second one
millisecond period the second device will operate, may be the operation of the first device is not
yet complete. So multiplexer channel multiplexes the operations of multiple devices which are
connected to the DMA controller, in case of selector channel the DMA channel, the DMA
controller selects one of the device, the device completes its operation then only the operation of
the next device is initiated. Now which type of channel we should go for? Whether we should go
for the selector channel or we should go for the multiplexer channel that depends upon device
characteristics.
Say if the devices are very fast in that case I can go for selector channel because as we have said
that once a device is selected, the device has to complete its operation then only the next device
can start operation. So if the first device takes a small amount of time then the second device can
wait until and unless the operation of the first device is complete but if the devices are very slow
in that case the waiting time may not be tolerable. So if the devices are slow, we should go for
the multiplexer channel. If the devices are fast enough then we can go for the selector channel.
So let us take some break.
11