TLB Entries:
Vir. Page Phy. Page Valid Present R/W
20'h0 20'h0
1 1 0
20'h2 20'h2
1 1 1
20'h4 20'h5
1 1 1
20'hb 20'h4
1 1 1
20'hc 20'h7
1 1 1
20'ha 20'h5
1 1 1
There are eight entries total. The other two entries are not defined for the test programs, but you may use them for testing your I/O devices. For the final testing, the valid bits of these two entries should be zero.
The IDT base register is 0x3000. This means 0x3000 is the physical address of the base of the Interrupt Descriptor Table. The code for the service routines will be in one of the pages listed above.
Segment Limits
CS: 0x4fff
DS: 0x11ff
SS: 0x4000
ES: 0x43ff
FS: 0x3ff
GS: 0x7ff
Effective addresses larger than the limit will cause a general protection
exception (except for the SS limit, which you aren't required to implement).
Main Memory should be 32 KB in size. Because different groups may use different memory configurations, the input file format may be different for each group. Before the final testing, I will create input files that are easily readable for your memory configurations, and I will let you know which areas of memory should be initialized. (Each test case will only use a small portion of the memory, so there is no point in initializing all 256 SRAM modules.)
EFLAGS
You will need to support at least the following Flags: OF, SF, ZF,
AF, CF, and PF.
Interrupts, Exceptions
You may assume that an exception will not occur while transferring
control to the exception handler or servicing an interrupt or exception.
General
There will be no self-modifying code.
Operand and Address sizes
- 32-bit addresses
- operand sizes:
- 8-bit (if specified by the opcode)
- 16-bit (with operand size override prefix)
- 32-bit (default)
Operand Addressing Modes
- immediate
- register
- ModR/M: all 32-bit addressing forms
- SIB: all except Base = (100 or 101)
- far pointers (ptr16:16, ptr16:32)
Prefixes
- operand size override prefix
- segment override prefixes
Instruction Subset
ADD,BSWAP,BTS,HLT,INC,IRETD,JNB,JNE,NOP,NOT,POP,PUSH,RET,ROR,SAL,SAR,XCHG:
all addressing modes indicated above
MOV : all forms listed on page 3-402 except "moffs" format
JMP,CALL : all formats except m16:16 and m16:32
Memory Hierarchy
Instruction and data caches should each contain a total of 1KB of data
store, but you may configure them any way you wish. The tag and data
store should be made out of the RAM (not SRAM) parts. Since valid
bits must be initialized to 0, you can use registers for these bits if
you wish.
Main memory should be made out of the SRAM parts. The size and configuration will be determined later.
You will need to design a bus to connect main memory, the processor, and I/O devices. You can decide how wide to make this bus and what type of arbitration scheme you use.
Segmentation
Linear addresses are calculated by adding the 32-bit effective address
to the 16-bit value in a segment register shifted left by four bits (i.e.
{12'b0, segment[15:0], 4'b0}) to form a 32-bit linear address. Associated
with each segment is a segment limit. The values of the segment limits
will be constant, so they can be hardwired into your design. I will
specify the values of the segment limits at a later date. If an effective
address exceeds the segment limit, a general protection exception should
be taken. Note that if you access a word or doubleword, none of the
bytes accessed can exceed the segment limit.
Virtual Memory
Virtual memory will be divided into pages of size 4KB. You will
implement a TLB to translate virtual page numbers (specified by the upper
20 bits of the address) to physical page numbers. In addition to
the virtual and physical translations, each TLB should also have at least
three additional fields: a Valid bit, a Present flag, and a R/W (read /
write) flag. The Present flag indicates if the page being pointed
to is currently present in physical memory. The valid bit determines
if the TLB entry is being used. The R/W flag determines read / write
permissions of the page. When the R/W flag is clear, the page is
read only; when it is set, the page can be written or read.
You may need to support other flags such as PCD (page-level cache disable) for memory-mapped I/O, or if you are implementing a DMA controller. Descriptions of other flags in x86 page table entries is given in Section 3.6 of Volume 3 of the Intel Architecture Software Developer's Manual. You will not be required to support these other flags, though.
The TLB will have eight entries, and both the virtual page numbers and the corresponding physical page numbers will be hardcoded. The values to be hardcoded in six of the page table entries will be specified at a later date. The two remaining entries can be used for memory-mapped I/O or anything needed for individual projects. If the processor attempts to write to a read-only page, a general protection exception should be taken. If the processor attempts to access either a page with a clear present bit or a page not in the TLB, a page fault should be taken. (Note: in a real machine, a TLB miss would cause a page table lookup. However, you are not required to implement the x86 page directory table for this project. )
I/O Devices
You should support at least two simple I/O devices such as memory-mapped
monitor and keyboard registers. These may access the same bus as
main memory. You may optionally support a more sophisticated I/O
device such as a DMA controller.
Exceptions and Interrupts
You should support at least one (external) interrupt that is triggered
by the I/O devices.
The exceptions that you must support are general protection exceptions (vector no. 13) and page faults (vector no. 14). Both instruction and data accesses may cause exceptions.
Exception Handling is outlined in Chapter 4 of Volume 1 of the Intel Architecture Software Developer's Manual. Each type of interrupt has a vector number that is an offset into the Interrupt Descriptor Table (IDT). Each entry of the IDT is a 4-byte far pointer (16-bit code segment and 16-bit IP). This far pointer is used as a jump target which will take the processor to an interrupt service routine. The address of the IDT entry is calculated as: <vector_number> * 4 + IDT_base, where IDT_base is the *physical* address of the IDT. Since IDT is located in physical memory, your interrupt handler must have a way of bypassing the TLB. The vector numbers are listed in table 4-1.
In your project, you should do the following when calling the interrupt
or exception handler:
1. Push EFLAGS on the stack
2. Push CS
3. Push EIP
4. Calculate the address of the IDT entry containing the far
pointer that points to the service routine. Load the contents of
the CS and EIP with the far pointer in the IDT entry.
The IRETD at the end of a service routine will pop EIP, CS, and EFLAGS, in that order.
The base address of the IDT will be specified later.
You will not be required to write service routines for general protection
exceptions or page faults. You may need to write service routines
to demonstrate the functionality of your I/O devices, though.