Documente Academic
Documente Profesional
Documente Cultură
Steven Bell
16 December 2010
CENG-3013
Oklahoma Christian University
CONTENTS
CONTENTS
Contents
1 Introduction
1.1
Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chip-level IO
2.2
Instruction set
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1
NOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.2
ADD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.3
SUB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.4
MUL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.5
AND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.6
OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.7
LSR
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.8
LSL
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.9
ASR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.10 ASL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.11 COMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.12 NEG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.13 LOAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.14 STORE
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.15 MOVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.16 Jump
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.17 HALT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 Module design
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.1.1
Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.2
Testing
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Program counter
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2.1
Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2.2
Testing
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3.1
Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3.2
Testing
9
9
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
10
3.4.1
Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
3.4.2
Testing
11
ALU Latch
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
3.5.1
Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
3.5.2
Testing
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
Datapath
3.6.1
Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
3.6.2
Testing
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
Control module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
3.7.1
State machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
3.7.2
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
3.8
Address multiplexer
3.9
Memory IO
3.9.1
Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.9.2
Testing
19
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.10.1 Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
CONTENTS
CONTENTS
3.10.2 Testing
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 Hardware implementation
20
20
4.1
20
4.2
Part selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
4.3
PCB Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
4.4
Breadboard layout
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
4.4.1
Pin mapping
5 Assembler
23
6 Conclusion
23
6.1
Current status
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
6.2
Future improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
24
25
A.1
Global constants
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
A.2
26
A.3
Program counter
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
A.4
ALU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
A.5
ALU latch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
A.6
A.7
Datapath
A.8
Address Multiplexer
A.9
Memory IO
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
35
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
A.12 CPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
43
B.1
43
B.2
Program counter
44
B.3
ALU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
B.4
ALU latch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
B.5
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
B.6
Datapath
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
B.7
61
B.8
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
B.9
CPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
C Output waveforms
D PCB diagrams
76
110
D.1
D.2
E Assembler code
112
130
135
INTRODUCTION
Introduction
The objective of this course (CENG-3013, Integrated Circuit Design) is to design an 8-bit microprocessor,
model and simulate it using the Verilog hardware description language, and nally to implement it in
hardware using a programmable logic device (PLD). This document describes my microprocessor design, the
test code used to verify it, and the physical hardware implementation.
Three things make my work unique:
Rather than using ABEL test vectors to test each Verilog module, I wrote all of my testbench code in
Verilog. This had several advantages.
Using an all-Verilog approach enabled me to use tools other than Lattice ispLEVER Classic, most
of which were far superior. I primarily used Icarus Verilog (http://www.icarus.com/eda/
verilog/)
combined with a Bash build script to automate the build and test process for all of
the modules. Rather than having to build and test each module independently, I was able to run
all of the tests at once and see the pass/fail results immediately. The build script also performed
macro substitution, so a test failure message could refer to a specic line of code, rather than
merely printing out a simulation timestep.
Verilog testbenches are vastly more exible and ecient for testing large and complex modules.
The CPU testbench simulates a block of ROM, which is loaded from a separate le. This makes
it very easy to write additional test vectors and to copy the test code into the physical EEPROM.
Likewise, the control module test consists of a short segment of Verilog code coupled with an easyto-read text le containing the test process.
Both Icarus Verilog and Aldec ActiveHDL perform functional simulation rather than gate-level
simulation. This let me focus rst on whether the code worked correctly, rather than puzzling
over why the optimizer had removed my registers or combined all of my signals. Once the code
worked, I could synthesize it with Synplicity and work out synthesis bugs.
I constructed my own board using a Lattice MachXO PLD instead of using an LSI5512. The latter
are no longer available, and have been replaced by the costly and already-outdated Mach4000 series.
The MachXO parts are much less expensive, and (until the upcoming release of the MachXO2) are
Lattice's agship CPLD, with solid tool support and documentation.
To circumvent the painstaking process of creating hexadecimal opcodes for the nal test program, I
wrote an assembler for my microprocessor which parses an input le and creates output les for Verilog
simulation and EEPROM programming.
1.1
Requirements
The requirements in this section are taken from the project specication posted at the beginning of the
semester:
Eight 8-bit general purpose registers which can be used in pairs as four 16-bit registers.
15
14
13
12
11
Opcode
10
Source type
Destination
Source
Destination
type
register
register
Condition
Opcode
Operands
NOP
0x00
Add
0x01
reg, reg/imm
Subtract
0x02
reg, reg/imm
Multiply
0x03
reg, reg/imm
Logical AND
0x04
reg, reg/imm
Logical OR
0x05
reg, reg/imm
0x06
reg
0x07
reg
Complement bits
0x08
reg
Load
0x10
reg, imm/address
Store
0x11
address, reg
Move
0x12
address, address
Jump
0x0F
address, condition
Halt
0x1F
Condition
Bit designation
Always
00
Carry
01
Zero
10
Negative
11
Where multi-byte values are used, they are stored in big-endian format, with the bits ordered from most
signicant to least signicant. The processor has an 8-bit internal data bus which transfers data between
the individual modules and connects to external RAM and ROM.
2.1
Chip-level IO
Memory write - Active high signal which switches the direction of the bidirectional buer
Write
2.2
Instruction set
2.2
Instruction set
This section briey describes each of the instructions. Operations are considered to be 8-bit operations with
8-bit results, except for the multiply, which produces a 16-bit result. For each operation, the zero ag is set
if the result contains all zeros.
The negative ag mirrors the most signicant bit in the result. In the two's complement number system,
this is equivalent to telling whether the value is positive or negative. Mathematical operations are performed
exactly the same as for unsigned values, and the programmer can even choose to ignore the negative ag and
work with the unsigned values (Wakerly, J. Digital Design Principles and Practices, 4th Ed., pp 37-43). In
the event that a subraction causes a borrow, the carry bit will be set, and this can be used to determine if
a larger value was subtracted from a smaller value. This design is patterned after the operation of the negative
ag in the Motorola M68HC11 (www.freescale.com/les/microcontrollers/doc/ref_manual/M68HC11RM.pdf,
page 204).
2.2.1 NOP
No operation. After reading this instruction, the processor continues immediately to the next instruction
without any extra clock cycles.
2.2.2 ADD
Adds a value to a register.
immediate. The carry ag is set if a one was carried out of the highest bit. The negative ag is set if the
highest bit is a 1, and the zero ag is set if the result is zero.
2.2.3 SUB
Subtracts a value from a register. The source value can be another register, a memory location, or an 8-bit
immediate. The carry ag is set if a one was borrowed. The negative ag is set if the highest bit is a 1, and
the zero ag is set if the result is zero. Note that because the values are only 8 bits wide, 0x00 - 0x81 gives
0x80, which is not a negative number. Thus, the negative ag will not be set, but the carry bit will.
2.2.4 MUL
Multiplies an 8-bit register by an 8-bit value, producing a 16-bit result. The source value can be another
register, a memory location, or an immediate. The result will be written to the destination register and its
16-bit pair, i.e, multiplying register
by register
and
is to load both operands into a single register pair, so that no registers with other data are accidentally
overwritten.
2.2.5 AND
Performs a bitwise AND between a register and a value. The source value can be another register, a memory
location, or an 8-bit immediate. The negative ag is set if the highest bit is a 1, and the zero ag is set if
the result is zero.
2.2.6 OR
Performs a bitwise OR between a register and a value. The source value can be another register, a memory
location, or an 8-bit immediate. The negative ag is set if the highest bit is a 1, and the zero ag is set if
the result is zero.
2.2.7 LSR
Performs a logical right-shift on a register and stores the result in the same register. All eight bits are shifted,
and a zero is shifted into the top bit position. The carry ag is set if a 1 was shifted out. The negative ag
is set if the highest bit is a 1, and the zero ag is set if the result is zero.
2.2
Instruction set
2.2.8 LSL
Performs a logical left-shift on a register and stores the result in the same register. All eight bits are shifted,
and a zero is shifted into the lowest bit position. The carry ag is set if a 1 was shifted out. The negative
ag is set if the highest bit is a 1, and the zero ag is set if the result is zero.
2.2.9 ASR
Performs an arithmetic right-shift on a register. Only the lower seven bytes are shifted; a copy of the sign bit
is shifted into the bit position below the sign bit. The carry ag is set if a 1 was shifted out. The negative
ag is set if the highest bit is a 1, and the zero ag is set if the result is zero.
2.2.10 ASL
Performs an arithmetic left-shift on a register. Only the lower seven bytes are shifted; a zero is shifted into
the lowest bit position. The carry ag is set if a 1 was shifted out. The negative ag is set if the highest bit
is a 1, and the zero ag is set if the result is zero.
2.2.11 COMP
Complements all of the bits in a register and stores the result in the same register. The negative ag is set
if the highest bit is a 1, and the zero ag is set if the result is zero.
2.2.12 NEG
Performs a 2's complement (binary negation) on a register and stores the result in the same register. The
negative ag is set if the highest bit is a 1, and the zero ag is set if the result is zero.
2.2.13 LOAD
Loads a value into a register. The source value can be a memory location or an immediate. The source can
also be another register, which is also handled internally with the LOAD opcode. The assembler uses the
mnemonic COPY to refer to loading one register into another.
2.2.14 STORE
Stores a register to RAM. A memory address is required.
2.2.15 MOVE
Copies the contents of one memory address to another. Two addresses are required; the register contents are
not aected.
2.2.16 Jump
A jump relocates the current program counter to the memory location specied. After the jump completes,
the processor immediately continues executing instructions at the new memory location.
The processor can jump:
Always, regardless of ALU ags. This uses the assembler mnemonic JMP
If the ALU carry bit was set in the last ALU operation. This uses the assembler mnemonic JCAR
If the ALU zero bit was set in the last ALU operation. This uses the assembler mnemonic JZERO
If the ALU negative bit was set in the last ALU operation. This uses the assembler mnemonic JNEG
MODULE DESIGN
2.2.17 HALT
Halts the processor's operation. No more instructions are read and the processor stays in the HALT state
until it is reset.
Module design
3.1
A 16-bit register is used three times in the design: the jump register, the memory address register, and the
instruction register. The same module is instantiated in all three of these cases.
3.1.1 Design
The module has an 8-bit input, which in all three instantiations comes from the data bus.
setHigh
and
setLow
Two signals,
determine whether this input is stored in the top half or bottom half of the register.
setHigh
setLow
halfValueIn
8
clock
reset
16-bit register
16
3.1.2 Testing
Since this was the rst module coded, the test code was written in ABEL. It used the following procedure:
1. Reset the module, and ensure that the output is zero.
2. Load the high half of the register
3. Load the low half of the register
4. Load the high half while performing a reset. The reset should take precedence and the output should
be zero.
The testbench code is shown in Appendix B.1 on page 43.
3.2
Program counter
3.2
MODULE DESIGN
Program counter
3.2.1 Design
The program counter holds the address of the next instruction byte and is used to index ROM when fetching
instructions. It increases the output count by on the rising edge of the clock when the
is high.
When the
set
increment
signal
signal is asserted, it loads the value from the jump register through the input
newCount.
increment
set
newCount
16
clock
reset
Program Counter
count
16
3.2.2 Testing
The test uses the following procedure:
1. Perform a reset and check that the output is zero.
2. Leave the increment signal low and ensure that the counter does not increment and remains at zero.
3. Load the value 0xFFFE into the counter and check that the output equals 0xFFFE and was not
incremented on this clock cycle.
4. Increment the counter and check that it equals 0xFFFF.
5. Increment the counter again and check that it rolls over to 0x0000.
The testbench code is shown in Appendix B.2 on page 44.
3.3
The general-purpose register block contains 8 eight-bit registers which are used for data manipulation. They
are grouped into pairs, creating 4 sixteen-bit registers which can receive the result of a multiply operation.
3.3.1 Design
Values are only stored on the rising edge of the clock, but the outputs are set via combinational logic. This
means that the outputs are available immediately so register-to-register copies and ALU operations from
the registers take place immediately without having to wait an additional clock cycle for the data to become
available.
3.4
MODULE DESIGN
The register block has three 3-bit address inputs which are used to index the registers. The
input_select
read_data is high; output_select
determines which register is written when write_data is high. The alu_output_value bus goes directly to the ALU and is always active. The alu_output_select address determines which register is
input determines which register receives a value from the data bus if
input_select
3
clock
output_select
3
alu_output_select
3
General-purpose registers
a
read_data
write_data
reset
Data bus
8
alu_output_value
8
3.3.2 Testing
The test uses the following procedure:
1. Perform a reset.
2. Read all of the registers out and check that they read zero.
3. Sequentially load values into each of the registers.
4. Iterate back through the registers, read out their values, and check that they match what was stored.
The testbench code is shown in Appendix B.5 on page 52
3.4
The arithmetic logic unit implements all of the arithmetic operations specied: addition, subtraction, multiplication, logical AND and OR, left and right logical shifts, left and right arithmetic shifts, bitwise complement, and negation. It also contains a passthrough instruction so that the ALU latch can be used as a
temporary register for the MOVE operation. Output ags are set based on the results of the operation.
10
3.5
ALU Latch
MODULE DESIGN
3.4.1 Design
The ALU consists entirely of combinational logic and operations are performed whenever the inputs change.
This wastes a tiny bit of power due to unnecessary gate switching, but simplies the design. The output
is only 8 bits, except for the multiply, which is 16 bits. The zero ag is dened for every operation: if the
result is all zeros, the ag is set. Likewise, the negative ag is set whenever the highest bit of the result is
a 1, which indicates a negative number in the two's complement system. The behavior and meaning of the
carry ag is dependant on the operation. For add and subtract, it indicates a carry out or borrow in; for
shifts, it indicates the bit that was shifted out.
primary
operand
secondary
operand
carry
reset
ALU
operation
zero
negative
result
16
3.4.2 Testing
The ALU test consists of running a set of possible inputs and checking the result and the output ags. Each
instruction is tested with several operations. The complete code is shown in Appendix B.3 on page 46.
3.5
ALU Latch
The ALU latch grabs the result of the ALU operation, holds it, and then puts it on the databus when the
store signals are asserted. It also latches the ags, so that a jump operates based on the last time the result
was grabbed.
3.5.1 Design
The ALU latch uses a simple sequential design. The
of the clock if
grab
alu_result
and
flags
is high. Combinational logic is used to determine which half of the stored value is put
out to the data bus. If neither store signal is high, the output is high-z. The
flags_out
output is always
enabled.
11
3.6
Datapath
store_high
store_low
grab
alu_result
16
MODULE DESIGN
ags
3
clock
ALU Latch
reset
out
8
ags_out
3
3.5.2 Testing
The test uses the following procedure:
1. Perform a reset.
2. Grab a value from the
alu_result
bus and hold it without putting the value on the data bus. The
3.6
Datapath
3.6.1 Design
The datapath module combines the program counter, jump register, general-purpose registers, ALU, ALU
latch, memory address register, and instruction register into a single unit connected by a data bus. The data
bus is a bidirectional module port, so data can be brought in and out of the chip. A block diagram of the
datapath is shown in Figure 3.6.
12
3.6
Datapath
clock
reset
read_data
write_data
setLow
General-purpose registers
reset
pc_set
pc_increment
setHigh
halfValueIn
clock
jr_low_high
jr_set_high
ir_set_high
alu_output_select
ir_low_high
gp_alu_output_select
output_select
3
mar_low_high
gp_output_select
mar_set_high
gp_input_select
gp_write
gp_read
alu_operation
latch_alu
alu_store_low
alu_store_high
input_select
3
MODULE DESIGN
clock
Memory address
register
Data bus
reset
16
halfValueIn
setHigh
setLow
8
8
register
operand
clock
8
Instruction
register
reset
carry
reset
negative
operation
16
store_high
grab
store_low
alu_result
ags
Data Bus
ALU
16
zero
setHigh
halfValueIn
setLow
clock
Jump register
reset
clock
ALU Latch
reset
ags_out
3
out
increment
set
16
clock
reset
Program Counter
count
mar_value
pc_count
ir_value
data_bus
ags
16
3.6.2 Testing
The test uses the following procedure:
1. Perform a reset.
2. Load instruction register from the data bus (high and low).
3. Loading the jump register from the data bus (high and low).
4. Load program counter from jump register.
5. Iterate through each register and load a value from the data bus.
6. Iterate back through the registers and write it back to the data bus.
13
3.7
Control module
MODULE DESIGN
3.7
Control module
The control module consists of two separate modules: a state machine which reads the output of the instruction register and determines what to do on the next clock cycle, and a signal translation module which
maps the control state into controls signals for all of the other modules.
The state diagram for the state machine is shown in Figure 3.8.
instruction
16
clock
reset
Control state
machine
state
5
14
3.7
Control module
Figure 3.8: Control module state transition diagram. Each state takes exactly one clock cycle.
3
MODULE DESIGN
15
3.7
Control module
Testing
MODULE DESIGN
The testbench for the control state machine uses an external le which contains instruction bytes
interleaved with the sequence of states which the module must go through.
of the le and checks that the current state matches the expected state. If the state is either FETCH_1
or FETCH_2, a hexadecimal byte is provided in the le and the testbench loads this into the simulated
instruction register. Lines ending in a # symbol are comments and are ignored. A sample segment of the
test le is shown below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
NOP#
FETCH_1
00
FETCH_2
00
Add#
FETCH_1
08
FETCH_2
20
ALU_OPERATION
STORE_RESULT_1
Multiply#
FETCH_1
18
FETCH_2
20
ALU_OPERATION
STORE_RESULT_1
STORE_RESULT_2
The test le checks every path of the state machine and ensures that each one works correctly.
assign
statements was used to produce the proper outputs. The general-purpose register addresses are taken directly
from the opcode, except where the destination address is modied to produce a 16-bit store for the multiply
operation. The ALU operation is taken directly from opcode bits [14:11].
16
3.7
Control module
MODULE DESIGN
RESET
FETCH_1
FETCH_2
FETCH_IMMEDIATE
ALU_OPERATION
ALU_IMMEDIATE
STORE_RESULT
STORE_RESULT_2
COPY_REGISTER_1
COPY_REGISTER_2
FETCH_ADDRESS_1
FETCH_ADDRESS_2
FETCH_MEMORY
STORE_MEMORY
TEMP_FETCH
FETCH_ADDRESS_3
FETCH_ADDRESS_4
TEMP_STORE
LOAD_JUMP_1
LOAD_JUMP_2
EXECUTE_JUMP
HALT
0
0
0
?
0
0
1
1
0
1
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
1
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
1
1
1
0
1
0
0
0
0
1
1
0
0
0
1
1
0
1
1
0
0
0
1
1
1
0
0
0
0
0
0
1
1
1
0
1
1
1
0
1
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
1
0
0
0
0
0
0
0
0
1
1
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
mar_load_low
mar_load_high
jr_load_low
jr_load_high
ir_load_low
ir_load_high
alu_store_low
alu_store_high
latch_alu
mem_write
mem_read
pc_increment
pc_set
gp_read
gp_write
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
1
0
0
0
0
0
The module also handles jump evaluation and execution. If the operation is a jump and the condition
code is always, then the program counter
set
code is carry, and the carry ag is set, then the signal is asserted. The same logic is used for the carry and
zero jumps. No additional clock cycles are necessary for evaluting the jump.
17
opcode
state
MODULE DESIGN
ags
16
mar_load_high
Address multiplexer
jr_load_low
3.8
mar_load_low
jr_load_high
alu_store_low
alu_store_high
latch_alu
mem_write
mem_read
pc_increment
pc_set
gp_write
gp_read
ir_load_low
ir_load_high
gp_alu_output_select
gp_output_select
gp_input_select
alu_operation
The module code for the control signal translation module is shown in Appendix A.11 on page 37.
Testing
The testbench simply iterates through all of the states, setting the input state and then checking
all of the outputs against those expected from the table. The testbench code is shown in B.8 on page 65.
3.8
Address multiplexer
The address multiplexer switches the output address between the program counter and memory address
register based on the state. If the processor is performing a load or store using a memory location, the MAR
address is used; otherwise, the program counter is used.
page 33. The address multiplexer was tested as part of the CPU.
pc_value
mar_value
16
16
state
5
Address Multiplexer
address_bus
16
3.9
Memory IO
The memory IO module performs memory mapping to locate the ROM and RAM in address space, and
translates the read and write signals into ROM and RAM chip enable signals.
18
3.10
Complete chip
MODULE DESIGN
3.9.1 Design
Because the program counter's reset is at 0x0000, it needs to nd its rst instruction at that memory location.
This is done by memory-mapping the ROM to 0x0000 through 0x1FFF. The 8 by 8K RAM can occupy any
portion of the address space; it was arbitrarily placed at 0x2000 through 0x3FFF. The module's operation
is summarized in Table 5.
readmemory
writememory
= 1
rom_enable =
ram_enable =
write = 0
= 1
both low
read
memory
0x2000 - 0x13FFFF
0,
rom_enable =
ram_enable =
write = 0
rom_enable =
ram_enable =
write = 1
rom_enable =
ram_enable =
write = 0
1,
Invalid
rom_enable =
ram_enable =
write = 0
1,
1,
address_in
write
memory
16
1,
0,
1,
0,
1,
1,
internal
data_path
8
clock
Memory IO
reset
RAM
enable
ROM
enable
write
write
address_out
16
external
data_path
8
3.9.2 Testing
The memory IO unit was tested as part of the CPU.
3.10
Complete chip
3.10.1 Design
The CPU module includes all of the other modules. It connects the control state machine to the datapath
via the state translation module, connects the datapath to the outside using the address multiplexer and
memory IO module. A block diagram of the CPU is shown in Figure 3.12. For clarity, the datapath control
signals are collapsed into a single representative bus.
19
HARDWARE IMPLEMENTATION
instruction
16
clock
Control state
machine
reset
state
5
opcode
ags
16
Datapath
reset
reset
pc_value
mar_value
16
16
state
5
Address Multiplexer
read
memory
internal
data_path
write
memory
internal_address_bus
16
clock
Memory IO
reset
RAM
enable
ROM
enable
write
write
external
data_path
8
address_bus
16
3.10.2 Testing
Rather than run a specic set of test vectors on the CPU, the testbench simulates RAM and ROM and
eectively lets the chip run on its own. The inital ROM conguration is read in from a le produced by the
assembler or by hand. The le contains a series of hexadecimal bytes, one per line. Lines beginning with
the # symbol are comments and are ignored by the testbench.
After performing a reset, the testbench simply reads the address bus and memory enable lines and returns
the appropriate value.
4
4.1
Hardware implementation
Motivation and design criteria
It was clear at the beginning of the class that many people would be competing for time on the implementation
board, and its feature set and design are completely xed. For these reasons, I decided early in the semester
20
4.2
Part selection
HARDWARE IMPLEMENTATION
FPGBA socket is dicult and messy at best, and a debugging nightmare at worst. I desired some sort of
breakout board which could interface easily with a breadboard.
4.2
Part selection
I researched several part familes from Lattice, Xilinx, and Altera, comparing logic capacity, prices, IDE
support, and other factors.
The Lattice 4000V series (specically the LC4512V) is the nominal successor to the discontinued
LSI5000 series.
It is compatible with the Lattice download cables in the Digital lab and is similar
The Xilinx CoolRunner XC2C512 is moderately priced at $40, and comes with a very powerful and
polished IDE (Xilix ISE WebPack), which Xilinx distributes for free. However, we do not have any
download cables or programmers for the chip.
In comparison to the CoolRunner CPLDs, Xilinx FPGAs are much cheaper and have an order of
magnitude more gates.
Digilent makes several inexpensive ($100-$200) boards which contain a Xilinx Spartan FPGA and
hardware to run them, including a USB-JTAG interface. This would be a simple and practical solution,
but it is rather expensive and doesn't provide a simple interface to a breadboard.
The Altera MAX II series is inexpensive ($20), and has a free and powerful IDE. However, it requires
a $150 download cable.
The Lattice MachXO series costs less than $20 and works with programming cables in the Digital lab.
It is fully supported by Lattice's newest IDE, known as Lattice Diamond. Although it does not seem
as powerful as Xilinx ISE, Diamond is far superior to ispLEVER Classic.
My nal selection was to use a MachXO series chip with a custom PCB.
The MachXO series uses a dierent architecture than traditional CPLDs which uses lookup tables rather
than macrocells. The LCMXO-2280 has 2,280 lookup tables, which Lattice equates to 1140 macrocells. Early
synthesis reports of my datapath showed approximately 200 macrocells used, and previous designs t in the
512 macrocell LSI5512, so I was condent that my design would t easily within the logic constraints of the
LCMXO-2280.
4.3
PCB Design
I designed a 2-layer breakout PCB for the LCMXO-2280 using Eagle and had it fabricated by Advanced
Circuits (www.4pcb.com). The only other parts on the board were 16 eight-terminal female headers (Newark
part #08N6773). One header is set up so that the ispDownload cable can be directly connected to the board
(http://www.latticesemi.com/lit/docs/devtools/dlcable.pdf ); a second header contains the
VCC , VIO ,
and
ground connections for the device. The remaining headers are connected directly to the PLD's IO pins. The
Eagle schematic and PCB layout are shown in Appendix D on page 110.
4.4
Breadboard layout
The breadboard was laid out as shown in Figure 4.1. A pair of 74HC245 buers was used in series on the
data bus to ensure that the 5 V external signals did not damage the chip. The data bus connects to a buer
running at 3.3 V, which connects to a buer at 5 V, which connects to the RAM and ROM. Because each
21
4.4
Breadboard layout
HARDWARE IMPLEMENTATION
buer has a delay of approximately 100ns, the maximum clock speed of the processor is reduced to about 2
MHz. 74HC244 unidirectional buers were used on the address bus.
address_bus[15:8]
address_bus[8:0]
SRAM
EEPROM
74HC245
74HC245
data_bus
74HC244
CPLD
74HC244
Custom PCB
Wires were color-coded using red for +3.3 V and +5 V, black for ground, blue for the address bus, orange
for the data bus, green for other signals, and yellow for test points to the logic analyzer.
A photograph of the board is shown in Figure 4.2.
22
CONCLUSION
Port
Type
Pin
Port
Direction
Pin
clock
clock
address_bus_15
output
134
reset
input
76
address_bus_14
output
133
ram_enable
output
104
address_bus_13
output
132
rom_enable
output
105
address_bus_12
output
131
write
output
103
address_bus_11
output
130
write
output
102
address_bus_10
output
127
external_data_bus_7
bidirectional
95
address_bus_9
output
126
external_data_bus_6
bidirectional
94
address_bus_8
output
125
external_data_bus_5
bidirectional
92
address_bus_7
output
113
external_data_bus_4
bidirectional
91
address_bus_6
output
112
external_data_bus_3
bidirectional
90
address_bus_5
output
111
external_data_bus_2
bidirectional
89
address_bus_4
output
110
external_data_bus_1
bidirectional
87
address_bus_3
output
109
external_data_bus_0
bidirectional
86
address_bus_2
output
108
address_bus_1
output
107
address_bus_0
output
106
Assembler
The assembler is a command-line program written in C++ using the Qt framework. It takes an input le
with assembly code based very loosely on Motorola 68HC11 assembly, and produces a Motorola SREC (.S19)
le along with a hex dump which can be fed into the CPU simulation testbench. The assembler can handle
labels as memory addresses, which is particularly useful for jump operations.
The assembler operates as follows:
1. The conguration is set up based on command-line parameters and the input le is opened.
2. One line of the le is read, broken up into individual tokens, and parsed.
3. If a label is encountered, the parser stores its memory address in a hash table for later reference.
4. If a label is referenced, the parser inserts the appropriate address.
5. If a label which has not yet been encountered is referenced, the parser adds the label to a table of
unknown labels.
6. When the parser reaches the end of the le, it goes back through the unknown label list and lls in
the remaining label references. If a label is still not dened, the assembler prints an error message.
7. The parser writes out the Motorola SREC le and, if requested, the simulation memory dump.
The complete assembler source code is given in Appendix E on page 112. Examples of the assembly source
code which is parses are given in Appendix F on page 130.
6
6.1
Conclusion
Current status
The required test program detailed in F on page 130 works correctly in simulation and in hardware. Captured
waveforms from the logic analyzer are shown in Appendix G on page 135.
23
6.2
Future improvements
CONCLUSION
There is a bug in the ALU on certain multiplications: When a positive value is multiplied by a negative
value to give a (e.g, -10 and 6, equivalent to 0xF5 and 0x06), the result is eectively treated as an 8-bit value
but is put into the 16-bit register. Thus, rather than giving a 16-bit signed value, it returns an 8-bit signed
value.
Arithmetic shifts are not working properly in the ALU, due to the way Verilog handles the arithmetic
shift operator. The solution is to write a bit-level assignment to perform the arithmetic shift.
6.2
Future improvements
Several things could be improved on the current design. As my understanding of the Verilog language grew
over the course of the semester, my coding style and practices evolved slightly. Were I to start again from
scratch, I would:
Watch more closely for inferred latches and make sure to clock every module with storage. During the
implementation phase, I had to x several bugs related to inferred latches and unclocked operation.
Run all of my testbenches based on the positive clock edges. Ultimately, my entire chip operates on
the rising edge of the clock; nothing happens on the falling edge.
my modules assuming that inputs changed on the negative edges and that they did their work on the
rising edge. This obscured my understanding of what was actually happening when I assembled the
complete chip.
Use port names to connect modules rather than argument order. This small syntactical feature was
particularly useful at the CPU level, but would have been advantagous even for small modules.
Dene all constants in a single header le (with a .h extension) before writing my ALU and control
state machine. I went through several iterations of merging and renaming les as I added new constants
and switched build environments.
24
A
A.1
1
2
3
4
5
6
7
8
ifndef _CONSTANTS_V_
define _CONSTANTS_V_
9
10
11
12
define ZEROFLAG 2
define CARRYFLAG 1
define NEGFLAG 0
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// ALU Opcodes
// These are the four lower bits from the opcode (instruction bits 14-11)
define ALU_PASSTHROUGH 4b1100
define ALU_ADD 4b0001
define ALU_SUBTRACT 4b0010
define ALU_MULTIPLY 4b0011
define ALU_AND 4b0100
define ALU_OR 4b0101
define ALU_LOGICAL_SHIFT_RIGHT 4b0110
define ALU_LOGICAL_SHIFT_LEFT 4b0111
define ALU_ARITH_SHIFT_RIGHT 4b1001
define ALU_ARITH_SHIFT_LEFT 4b1010
define ALU_TWOS_COMPLEMENT 4b1011
define ALU_COMPLEMENT 4b1000
// Room for 2 more, 4b1101 and 4b1110
// 4b0000 is taken for NOP 4b1111 for JUMP - these will give a 0 result
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
25
A.2
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
endif
A.2
1
2
3
4
5
6
7
/* register_16bit.v
* Implements a generic 16-bit register which is loaded in two
* sequential 8-byte actions.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 16 September 2010
* $LastChangedDate: 2010-09-23 08:44:58 -0500 (Thu, 23 Sep 2010) $
*/
8
9
10
11
12
13
14
15
16
17
18
19
20
26
A.3
21
22
23
24
25
26
27
28
29
Program counter
30
31
endmodule
A.3
1
2
3
4
5
6
Program counter
/* program_counter.v
* Implements the 16-bit loadable program counter.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 11 September 2010
* $LastChangedDate: 2010-11-23 09:34:58 -0600 (Tue, 23 Nov 2010) $
*/
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Clocked operation
always @(posedge clock) begin
if(~reset) begin // If the reset line is low, then zero the counter
count <= 0;
end
else if(set) begin // If set is high, then load a new value into the
counter
count <= new_count;
end
else if(increment) begin // Otherwise, if increment is high, add one to
the counter
count <= count + 1;
end
end // END always
32
33
endmodule
A.4
1
2
ALU
/* alu.v
* Arithmetic logic unit.
27
A.4
3
4
5
6
ALU
7
8
include "constants.v"
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
28
A.4
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
ALU
flags[CARRYFLAG] = 1b0;
flags[NEGFLAG] = result[7];
end
ALU_OR: begin
result[7:0] = primaryOperand | secondaryOperand;
flags[CARRYFLAG] = 1b0;
flags[NEGFLAG] = result[7];
end
ALU_LOGICAL_SHIFT_RIGHT: begin
result[7:0] = primaryOperand >> 1;
flags[CARRYFLAG] = primaryOperand[0]; // Set the carry to be the
that got shifted out
flags[NEGFLAG] = result[7]; // This will always be 0; perhaps we
should set it explicitly?
end
ALU_LOGICAL_SHIFT_LEFT: begin
result[7:0] = primaryOperand << 1;
flags[CARRYFLAG] = primaryOperand[7]; // Set the carry to be the
that got shifted out
flags[NEGFLAG] = result[7];
end
ALU_ARITH_SHIFT_RIGHT: begin
result[7:0] = primaryOperand >>> 1;
flags[CARRYFLAG] = primaryOperand[0]; // Set the carry to be the
that got shifted out
flags[NEGFLAG] = result[7];
end
ALU_ARITH_SHIFT_LEFT: begin
result[7:0] = primaryOperand <<< 1;
flags[CARRYFLAG] = primaryOperand[7]; // Set the carry to be the
that got shifted out
flags[NEGFLAG] = result[7];
end
ALU_TWOS_COMPLEMENT: begin
result = ~primaryOperand; // Complement
result = result + 8d1; // and add one
flags[CARRYFLAG] = 1b0;
flags[NEGFLAG] = result[7];
end
ALU_COMPLEMENT: begin
result = ~primaryOperand;
flags[CARRYFLAG] = 1b0;
flags[NEGFLAG] = result[7];
end
default: begin
result[15:0] = 15d0;
flags[CARRYFLAG] = 1b0;
flags[NEGFLAG] = 1b0;
end
endcase
bit
bit
bit
bit
95
96
97
98
29
A.5
99
100
101
102
ALU latch
else begin
flags[ZEROFLAG] = (result[7:0] == 8h00) ? 1b1 : 1b0;
end // if(operation == MULTIPLY)
end //always @(posedge clock)
103
104
endmodule
A.5
1
2
3
4
5
6
ALU latch
/* alu_latch.v
* Grabs the result from the ALU and puts it on the data bus
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 11 October 2010
* $LastChangedDate: 2010-12-13 18:04:13 -0600 (Mon, 13 Dec 2010) $
*/
7
8
9
10
11
12
13
14
15
16
17
18
module alu_latch(
input clock,
input reset,
input[15:0] alu_result, // Result from the ALU
input[2:0] flags, // ALU flags which must also be latched
input grab, // Active-high signal telling us whether or not to latch the
value
input store_high, // Put the top 8 bytes on the data bus (only used for
multiply)
input store_low, // Put the low 8 bytes on the data bus
output reg[7:0] out,
output reg[2:0] flags_out
);
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
30
A.6
44
end
45
46
endmodule
A.6
1
2
3
4
5
6
/* gp_registers.v
* 8x8 bit general purpose register set.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 23 September 2010
* $LastChangedDate: 2010-12-14 09:01:55 -0600 (Tue, 14 Dec 2010) $
*/
7
8
9
10
11
12
13
14
15
module gp_registers
(
input clock,
input reset, // Active-low synchronous reset
input read_data, // Flag telling us whether or not to load a register value
from the data bus (active high)
input write_data, // Flag telling us whether or not to write a register to
the data bus (active high)
// Well just leave the ALU output always enabled, since it cant mess
things up and we
// dont care about the slight increase in power consumption due to flipping
unnecessary gates.
16
17
18
19
20
21
22
23
24
25
26
27
28
integer i; // Used for iterating through the registers when resetting them
29
30
31
32
33
34
35
36
37
38
39
31
A.7
40
41
Datapath
end
end // always
42
43
44
45
46
47
48
49
endmodule
A.7
1
2
3
4
5
6
7
Datapath
/* datapath.v
* Datapath which includes the general purpose registers, special purpose
* registers, ALU, and the connections between them.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 6 October 2010
* $LastChangedDate: 2010-12-13 18:04:13 -0600 (Mon, 13 Dec 2010) $
*/
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
module datapath(
input clock,
input reset,
input pc_increment,
input pc_set,
input gp_read,
input gp_write,
input[2:0] gp_input_select,
input[2:0] gp_output_select,
input[2:0] gp_alu_output_select,
input[3:0] alu_operation,
input latch_alu,
input alu_store_high,
input alu_store_low,
input mar_set_high,
input mar_set_low,
input ir_set_high,
input ir_set_low,
input jr_set_high,
input jr_set_low,
29
30
31
32
33
output
output
output
output
34
35
36
inout[7:0] data_bus
);
37
38
39
// Shared connections
wire[7:0] register_operand; // Bus from the general-purpose registers to the
ALU
32
A.8
40
41
42
Address Multiplexer
43
44
45
// Program counter (only reads from jump register, not data bus)
program_counter m_program_counter(clock, reset, pc_increment, pc_set,
pc_jump_count, pc_count);
46
47
48
// Jump register which holds the value for the program counter to jump to
register_16bit m_jump_register(clock, reset, jr_set_high, jr_set_low,
data_bus, pc_jump_count);
49
50
51
// General-purpose registers
gp_registers m_gp_registers(clock, reset, gp_read, gp_write, gp_input_select
, gp_output_select, gp_alu_output_select, data_bus, register_operand);
52
53
54
55
56
57
58
59
60
61
// Instruction register
register_16bit m_instruction_register(clock, reset, ir_set_high, ir_set_low,
data_bus, ir_value);
62
63
64
65
endmodule
A.8
1
2
3
4
5
6
Address Multiplexer
/* address_mux.v Multiplexer that picks the output address bus value from
either the MAR or
the program counter based the control module state.
*
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 6 December 2010
* $LastChangedDate: 2010-12-16 17:48:32 -0600 (Thu, 16 Dec 2010) $
*/
7
8
include "constants.v"
9
10
11
12
13
14
15
module address_mux(
input[15:0] pc_value,
input[15:0] mar_value,
input[4:0] state,
output[15:0] address_bus
);
16
33
A.9
17
18
19
2
3
4
5
6
7
A.9
1
Memory IO
Memory IO
/* memio.v Memory IO module which performs memory mapping and holds the
* digital IO banks.
*
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 5 December 2010
* $LastChangedDate$
*/
8
9
10
11
12
13
module memio(
input read_memory,
input write_memory,
inout[7:0] internal_data_path,
inout[7:0] external_data_path,
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
endmodule
34
A.10
A.10
1
2
3
4
5
6
7
/* control.v
* Control module which fetches instructions and drives all of the other
* modules.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 28 October 2010
* $LastChangedDate: 2010-12-13 18:04:13 -0600 (Mon, 13 Dec 2010) $
*/
8
9
include "constants.v"
10
11
12
13
14
15
16
17
module control
(
input clock,
input reset,
input[15:0] instruction, // Value from the instruction register
output reg[4:0] state // Current control state
);
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
35
A.10
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
end
else if(instruction[15:11] == LOAD) begin
if(instruction[10:9] == SOURCE_REGISTER) begin
state <= S_COPY_REGISTER;
end
else if(instruction[10:9] == SOURCE_IMMEDIATE) begin
state <= S_FETCH_IMMEDIATE;
end
else if(instruction[10:9] == SOURCE_MEMORY) begin
state <= S_FETCH_ADDRESS_1;
end
end
else if(instruction[15:11] == STORE ||
instruction[15:11] == MOVE) begin
state <= S_FETCH_ADDRESS_1;
end
else if(instruction[15:11] == S_HALT) begin
state <= S_HALT;
end
else begin
state <= S_HALT;
end
71
72
73
S_ALU_OPERATION:
state <= S_STORE_RESULT_1;
74
75
76
S_ALU_IMMEDIATE:
state <= S_STORE_RESULT_1;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
S_STORE_RESULT_1:
// If the operation was a multiply, we have to do 2 stores
if(instruction[15:11] == MULTIPLY) begin
state <= S_STORE_RESULT_2;
end
// Otherwise, were ready for the next operation
else begin
state <= S_FETCH_1;
end
S_STORE_RESULT_2:
state <= S_FETCH_1;
S_FETCH_IMMEDIATE:
// Because this state is used both for storing immediates into the
registers
// and for grabbing immediate values for the ALU, this state loads the
immediate
// value into the register. It will be overwritten by the ALU result
if there is one.
// This could be fixed by creating a separate state for loading
immediates.
if(instruction[15:11] == LOAD) begin
state <= S_FETCH_1;
end
else begin
state <= S_ALU_OPERATION;
36
A.11
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
end
S_COPY_REGISTER:
state <= S_FETCH_1;
S_FETCH_ADDRESS_1:
state <= S_FETCH_ADDRESS_2;
S_FETCH_ADDRESS_2:
if(instruction[15:11] == LOAD) begin
state <= S_FETCH_MEMORY;
end
else if(instruction[15:11] == STORE) begin
state <= S_STORE_MEMORY;
end
else if(instruction[15:11] == MOVE) begin
state <= S_TEMP_FETCH;
end
S_FETCH_MEMORY:
state <= S_FETCH_1;
S_STORE_MEMORY:
state <= S_FETCH_1;
S_TEMP_FETCH:
state <= S_FETCH_ADDRESS_3;
S_FETCH_ADDRESS_3:
state <= S_FETCH_ADDRESS_4;
S_FETCH_ADDRESS_4:
state <= S_TEMP_STORE;
S_TEMP_STORE:
state <= S_FETCH_1;
S_LOAD_JUMP_1:
state <= S_LOAD_JUMP_2;
S_LOAD_JUMP_2:
state <= S_EXECUTE_JUMP;
S_EXECUTE_JUMP:
state <= S_FETCH_1;
S_HALT:
state <= S_HALT; // Just stay put!
endcase
135
136
137
138
if(reset == 0) begin
state <= S_RESET;
end
139
140
end
141
142
143
endmodule
A.11
1
2
3
4
5
/* control_signals.v
* Module which translates the control module state into the set of control
signals
* for the rest of the chip.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 24 November 2010
37
A.11
6
7
* $LastChangedDate$
*/
8
9
include "constants.v"
10
11
12
13
14
module control_signals(
input[4:0] state, // State from the control state machine
input[15:0] opcode, // Full 16-bit opcode from the instruction register
input[2:0] alu_flags, // Carry/Zero/Negative flags from ALU
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
output ir_load_high, // Load the high 8 bits of the instruction from the
data bus
output ir_load_low, // Load the low 8 bits of the instruction
output gp_read, // Read a value from the data bus into a register
output gp_write, // Write a value from the register onto the data bus
output pc_set, // Set the program counter from the jump register
output pc_increment, // Increment the program counter
output mem_read, // Read a value from memory onto the data bus
output mem_write, // Write a value from the data bus out to memory (RAM)
output latch_alu,
output alu_store_high, // Write the high 8 bits of the ALU result to the
data bus
output alu_store_low, // Write the low 8 bits of the ALU result to the data
bus
output jr_load_high, // Load the high 8 bits of the jump destination into
the jump register
output jr_load_low, // Load the low 8 bits of the jump destination
output mar_load_high, // Load the high 8 bits of the memory address into the
MAR
output mar_load_low, // Load the low 8 bits of the memory address
31
32
33
34
35
36
output[3:0]
output[2:0]
output[2:0]
bus
output[2:0]
directly
);
alu_operation,
gp_input_select,
gp_output_select, // Register select for GP registers to data
gp_alu_output_select // Register select for GP registers
to ALU
37
38
39
40
41
42
43
44
45
46
47
48
38
A.11
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
39
A.12
88
89
CPU
90
91
92
endmodule
A.12
1
2
3
4
5
CPU
6
7
8
9
10
11
12
13
14
15
16
17
module cpu(
input clock,
input reset,
inout[7:0] external_data_bus,
output[15:0] address_bus,
output ram_enable,
output rom_enable,
output write,
output write_bar,
output[4:0] state
);
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
40
A.12
45
CPU
46
47
48
//wire[4:0] state;
wire[15:0] address_mux_out;
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
datapath dp(.clock(clock),
.reset(reset),
.pc_increment(pc_increment),
.pc_set(pc_set),
.gp_read(gp_read),
.gp_write(gp_write),
.gp_input_select(gp_input_select),
.gp_output_select(gp_output_select),
.gp_alu_output_select(gp_alu_output_select),
.alu_operation(alu_operation),
.latch_alu(latch_alu),
.alu_store_high(alu_store_high),
.alu_store_low(alu_store_low),
.mar_set_high(mar_set_high),
.mar_set_low(mar_set_low),
.ir_set_high(ir_set_high),
.ir_set_low(ir_set_low),
.jr_set_high(jr_set_high),
.jr_set_low(jr_set_low),
.pc_count(pc_count),
.mar_value(mar_value),
.ir_value(ir_value),
.flags(alu_flags),
.data_bus(data_bus));
74
75
76
77
78
control cm(.clock(clock),
.reset(reset),
.instruction(ir_value),
.state(state));
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
control_signals cs(.state(state),
.opcode(ir_value),
.alu_flags(alu_flags),
.ir_load_high(ir_set_high),
.ir_load_low(ir_set_low),
.gp_read(gp_read),
.gp_write(gp_write),
.pc_set(pc_set),
.pc_increment(pc_increment),
.mem_read(mem_read),
.mem_write(mem_write),
.latch_alu(latch_alu),
.alu_store_high(alu_store_high),
.alu_store_low(alu_store_low),
.jr_load_high(jr_set_high),
.jr_load_low(jr_set_low),
.mar_load_high(mar_set_high),
.mar_load_low(mar_set_low),
.alu_operation(alu_operation),
41
A.12
CPU
99
.gp_input_select(gp_input_select),
.gp_output_select(gp_output_select),
.gp_alu_output_select(gp_alu_output_select));
100
101
102
103
104
105
106
address_mux am(.pc_value(pc_count),
.mar_value(mar_value),
.state(state),
.address_bus(address_mux_out));
107
108
109
110
111
112
113
114
115
116
117
118
memio mem(.read_memory(mem_read),
.write_memory(mem_write),
.internal_data_path(data_bus),
.external_data_path(external_data_bus),
.address_in(address_mux_out),
.address_out(address_bus),
.ram_enable(ram_enable),
.rom_enable(rom_enable),
.write(write),
.write_bar(write_bar));
119
120
endmodule
42
B.1
1
2
3
4
5
//
//
//
//
//
register_16bit_test.abv
ABEL test vector file for register_16_bit.v
Author: Steven Bell <steven.bell@student.oc.edu>
Date: 16 September 2010
$LastChangedDate: 2010-09-23 08:44:58 -0500 (Thu, 23 Sep 2010) $
6
7
MODULE register_16bit
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Inputs
clock pin;
reset pin;
setHigh pin;
setLow pin;
instructionByteIn_7_
instructionByteIn_6_
instructionByteIn_5_
instructionByteIn_4_
instructionByteIn_3_
instructionByteIn_2_
instructionByteIn_1_
instructionByteIn_0_
pin;
pin;
pin;
pin;
pin;
pin;
pin;
pin;
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Outputs
instructionOut_15_ pin;
instructionOut_14_ pin;
instructionOut_13_ pin;
instructionOut_12_ pin;
instructionOut_11_ pin;
instructionOut_10_ pin;
instructionOut_9_ pin;
instructionOut_8_ pin;
instructionOut_7_ pin;
instructionOut_6_ pin;
instructionOut_5_ pin;
instructionOut_4_ pin;
instructionOut_3_ pin;
instructionOut_2_ pin;
instructionOut_1_ pin;
instructionOut_0_ pin;
41
42
43
44
// Buses
instructionByteIn = [instructionByteIn_7_,instructionByteIn_6_,
instructionByteIn_5_,instructionByteIn_4_,instructionByteIn_3_,
instructionByteIn_2_,instructionByteIn_1_,instructionByteIn_0_];
instructionOut = [instructionOut_15_,instructionOut_14_,instructionOut_13_
,instructionOut_12_,instructionOut_11_,instructionOut_10_,
instructionOut_9_,instructionOut_8_,instructionOut_7_,
instructionOut_6_,instructionOut_5_,instructionOut_4_,
instructionOut_3_,instructionOut_2_,instructionOut_1_,
43
B.2
Program counter
instructionOut_0_];
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Test_vectors
([clock,reset,setHigh,setLow,instructionByteIn] -> [instructionOut])
[u, 0, 0, 0, ^hde] -> [^h0000]; // Reset
[u, 1, 1, 0, ^hde] -> [^hde00]; // Set high
[u, 1, 0, 1, ^had] -> [^hdead]; // Set low
[u, 0, 1, 0, ^hfa] -> [^h0000]; // Reset while setting high; reset should
take precedence
[u, 1, 1, 1, ^hfa] -> [^hfa00]; // Set both high and low; high should should
take precedence, low will not be set
[u, 1, 0, 1, ^hce] -> [^hface]; // Set low
END
B.2
1
2
3
4
5
6
Program counter
/* program_counter_test.v
* Verilog testbench for program_counter.v
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 11 September 2010
* $LastChangedDate: 2010-11-23 09:34:58 -0600 (Tue, 23 Nov 2010) $
*/
7
8
9
10
11
12
module program_counter_test();
13
14
15
16
17
18
19
20
21
22
// Clock
reg clock = 1b0;
always #50 clock = !clock; // 100 time ticks per cycle = 10 MHz clock
23
24
25
26
27
28
29
30
31
32
// Test
initial begin
// Reset
@(negedge clock) begin
reset = 1b0;
end
checkCount(16b0, __LINE__);
33
34
// Check that counter doesnt increment without the signal being asserted
44
B.2
35
36
37
38
Program counter
39
40
41
42
43
44
// Load a value
@(negedge clock) begin
set = 1b1;
end
checkCount(16hfffe, __LINE__);
45
46
47
48
49
50
51
// Load a value while incrementing, the new value should take precendence
@(negedge clock) begin
set = 1b1;
increment = 1b1;
end
checkCount(16hfffe, __LINE__);
52
53
54
55
56
57
58
// Increment
@(negedge clock) begin
set = 1b0;
increment = 1b1;
end
checkCount(16hffff, __LINE__);
59
60
61
62
63
64
// Test rollover
@(negedge clock) begin
increment = 1b1;
end
checkCount(16h0000, __LINE__);
65
66
67
$finish;
end
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
45
B.3
88
ALU
endtask
89
90
endmodule
B.3
1
2
3
4
5
6
ALU
/* alu_test.v
* Testbench for the arithmetic logic unit
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 30 September 2010
* $LastChangedDate: 2010-12-13 18:04:13 -0600 (Mon, 13 Dec 2010) $
*/
7
8
9
10
11
12
module alu_test();
13
14
15
16
17
18
19
reg reset = 1;
reg[7:0] registerParam; // Parameter from the general purpose registers (
primary)
reg[7:0] databusParam; // Parameter from the data bus (secondary)
reg[3:0] operation; // Operation to perform
wire[15:0] result; // ALU result
wire[2:0] flags;
20
21
22
23
// Clock
reg clock = 0;
always #50 clock = !clock; //100 time ticks per cycle = 10 MHz clock
24
25
26
// DUT
alu aluDUT(clock, reset, registerParam, databusParam, operation, result,
flags);
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
initial begin
perform_reset();
// Test PASSTHROUGH
// Passthrough uses the secondary input (data bus) rather than the primary
(GP registers)
test_operation(8d0, 8d2, ALU_PASSTHROUGH, 8d2, 3b000, __LINE__); // "
Normal" passthrough
test_operation(8d1, 8d0, ALU_PASSTHROUGH, 8d0, 3b100, __LINE__); //
Test zero
test_operation(8d0, -8d1, ALU_PASSTHROUGH, -8d1, 3b001, __LINE__); //
Test negative
46
B.3
ALU
43
44
45
46
47
48
49
// Test ADD
test_operation(8d1, 8d2, ALU_ADD, 8d3, 3b000, __LINE__); // Normal
add
test_operation(8d255, 8d2, ALU_ADD, 8d1, 3b010, __LINE__); // Test
carry
test_operation(8d125, 8d10, ALU_ADD, 8d135, 3b001, __LINE__); // Test
negative
test_operation(-8d15, 8d10, ALU_ADD, -8d5, 3b001, __LINE__); // Test
negative another way
test_operation(8d250, 8d6, ALU_ADD, 8d0, 3b110, __LINE__); // Test
carry and zero
50
51
52
53
54
55
56
57
58
// Test SUBTRACT
// Note that the subtraction of a negative number causes a borrow because
of the sign bit. This
// is not exactly the desired behavior, but it is the simplest logically
consistent behavior.
test_operation(8d10, 8d6, ALU_SUBTRACT, 8d4, 3b000, __LINE__); //
Normal subtract
test_operation(8d10, 8d10, ALU_SUBTRACT, 8d0, 3b100, __LINE__); //
Test zero
test_operation(8d10, 8d15, ALU_SUBTRACT, -8d5, 3b011, __LINE__); //
Test borrow and negative
test_operation(8d2, -8d6, ALU_SUBTRACT, 8d8, 3b010, __LINE__); //
Subtraction of negative number
test_operation(-8d128, 8d1, ALU_SUBTRACT, 8d127, 3b000, __LINE__); //
Test underflow (no borrow)
59
60
61
62
63
64
65
66
// Test MULTIPLY
test_operation16(8d10, 8d6, ALU_MULTIPLY, 16d60, 3b000, __LINE__); //
Small multiply
test_operation16(8d100, 8d60, ALU_MULTIPLY, 16d6000, 3b000, __LINE__)
; // Large multiply
test_operation16(-8d1, -8d1, ALU_MULTIPLY, 16d1, 3b000, __LINE__); //
Huge multiply
test_operation16(-8d10, 8d6, ALU_MULTIPLY, -16d60, 3b000, __LINE__);
// Normal multiply
// BUG: Signed multiplication doesnt work exactly as I expect, due to the
input values having only
// 8 bits but producing a 16-bit result.
67
68
69
70
71
// Test AND
test_operation(8b10101010, 8b01100110, ALU_AND, 8b00100010, 3b000,
__LINE__); // Normal AND
test_operation(8b10101010, 8b01010101, ALU_AND, 8b00000000, 3b100,
__LINE__); // Test zero
test_operation(8b10101010, 8b11100110, ALU_AND, 8b10100010, 3b001,
__LINE__); // Test negative
72
73
74
// Test OR
test_operation(8b00101010, 8b01100110, ALU_OR, 8b01101110, 3b000,
__LINE__); // Normal OR
47
B.3
75
76
ALU
77
78
79
80
81
// Test LOGICAL_SHIFT_RIGHT
test_operation(8b10101010, 8b11111111, ALU_LOGICAL_SHIFT_RIGHT, 8
b01010101, 3b000, __LINE__); // Shift out a 0
test_operation(8b10101011, 8b11111111, ALU_LOGICAL_SHIFT_RIGHT, 8
b01010101, 3b010, __LINE__); // Shift out a 1
test_operation(8b00000000, 8b11111111, ALU_LOGICAL_SHIFT_RIGHT, 8
b00000000, 3b100, __LINE__); // Test zero
82
83
84
85
86
87
// Test LOGICAL_SHIFT_LEFT
test_operation(8b00101010, 8b11111111, ALU_LOGICAL_SHIFT_LEFT,
b01010100, 3b000, __LINE__); // Shift out a 0
test_operation(8b10101010, 8b11111111, ALU_LOGICAL_SHIFT_LEFT,
b01010100, 3b010, __LINE__); // Shift out a 1
test_operation(8b00000000, 8b11111111, ALU_LOGICAL_SHIFT_LEFT,
b00000000, 3b100, __LINE__); // Test zero
test_operation(8b11000000, 8b11111111, ALU_LOGICAL_SHIFT_LEFT,
b10000000, 3b011, __LINE__); // Test carry and negative
8
8
8
8
88
89
90
91
92
93
94
95
96
// Test ARITH_SHIFT_RIGHT
test_operation(8b00101010, 8b11111111, ALU_ARITH_SHIFT_RIGHT, 8
b00010101, 3b000, __LINE__); // Shift out a 0
test_operation(8b00101011, 8b11111111, ALU_ARITH_SHIFT_RIGHT, 8
b00010101, 3b010, __LINE__); // Shift out a 1
test_operation(8b00000000, 8b11111111, ALU_ARITH_SHIFT_RIGHT, 8
b00000000, 3b100, __LINE__); // Test zero
test_operation(8b10101010, 8b11111111, ALU_ARITH_SHIFT_RIGHT, 8
b11010101, 3b001, __LINE__); // Test sign bit shift
// BUG: The test above fails - apparently Verilog only does an arithmetic
shift if the value is signed
// so it seems to just be doing a logical shift. I could hack an
arithmetic shift, or maybe there is
// a way to treat the input as a signed value?
97
98
99
100
101
102
// Test ARITH_SHIFT_LEFT
test_operation(8b00101010, 8b11111111, ALU_ARITH_SHIFT_LEFT,
b01010100, 3b000, __LINE__); // Shift out a 0
test_operation(8b10101010, 8b11111111, ALU_ARITH_SHIFT_LEFT,
b01010100, 3b010, __LINE__); // Shift out a 1
test_operation(8b01101010, 8b11111111, ALU_ARITH_SHIFT_LEFT,
b11010100, 3b001, __LINE__); // Test overflow
test_operation(8b00000000, 8b11111111, ALU_ARITH_SHIFT_LEFT,
b00000000, 3b100, __LINE__); // Test zero
8
8
8
8
103
104
105
106
// Test TWOS_COMPLEMENT
test_operation(8b00000001, 8b11111111, ALU_TWOS_COMPLEMENT, 8b11111111
, 3b001, __LINE__); // 1 -> -1
test_operation(8b10000000, 8b11111111, ALU_TWOS_COMPLEMENT, 8b10000000
, 3b001, __LINE__); // 128 -> -128
48
B.3
107
108
109
ALU
110
111
112
113
114
// Test COMPLEMENT
test_operation(8b10000001,
b000, __LINE__); // Test
test_operation(8b00000001,
b001, __LINE__); // Test
test_operation(8b11111111,
b100, __LINE__); // Test
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* Cycles the reset input to the ALU to put it into a known state.
* Takes no parameters. */
task perform_reset();
begin
@(negedge clock) begin
reset = 0;
end
@(negedge clock) begin
reset = 1;
end
end
endtask
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* Performs an ALU operation giving an 8 bit result and determines whether the
* result and flags match the expected results and flags.
*
* tParam1 - First operand for the ALU; typically from the general purpose
registers
* tParam2 - Second operand for the ALU; typically from the data bus
* tOperation - Operation to perform on the two operands
* tExpectedValue - Expected result of the operation
* tExpectedFlags - Expected zero, carry, and negative flags from the
operation
lineNum
- Line number the test is on. This should generally be a
*
preprocessor macro.
*/
task test_operation(input[7:0] tParam1, input[7:0] tParam2, input[3:0]
tOperation,
input[7:0] tExpectedValue, input[2:0] tExpectedFlags,
input integer lineNum);
begin
@(negedge clock) begin // Wait for falling edge
49
B.3
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
ALU
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/* Performs an ALU operation giving a 16-bit result and determines whether the
* result and flags match the expected results and flags.
*
* tParam1 - First operand for the ALU; typically from the general purpose
registers
* tParam2 - Second operand for the ALU; typically from the data bus
* tOperation - Operation to perform on the two operands
* tExpectedValue - Expected result of the operation
* tExpectedFlags - Expected zero, carry, and negative flags from the
operation
* lineNum - Line number the test is on. This should generally be a
preprocessor macro.
*/
task test_operation16(input[7:0] tParam1, input[7:0] tParam2, input[3:0]
tOperation,
input[15:0] tExpectedValue, input[2:0] tExpectedFlags,
input integer lineNum);
begin
@(negedge clock) begin // Wait for falling edge
registerParam = tParam1; // Set the inputs
databusParam = tParam2;
operation = tOperation; // Select the operation
end
@(posedge clock) begin // Wait for rising edge, and delay so the values
are stable
#5;
if(result[15:0] != tExpectedValue) begin // Check the outputs
$display("%3d - Test failed! Expected result %d, got %d", lineNum,
tExpectedValue, result[7:0]);
end
else if(flags != tExpectedFlags) begin
50
B.4
194
195
196
197
198
199
200
201
202
ALU latch
203
204
205
endmodule
B.4
1
2
3
4
5
6
ALU latch
/* alu_latch_test.v
* Testbench for the ALU latch
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 14 October 2010
* $LastChangedDate: 2010-12-13 18:04:13 -0600 (Mon, 13 Dec 2010) $
*/
7
8
9
10
11
12
13
14
15
16
17
18
module alu_latch_test();
reg reset = 1;
reg[15:0] alu_result;
reg grab;
reg store_high;
reg store_low;
wire[7:0] databus; // Output of ALU latch goes to data bus (for now)
19
20
21
22
// Clock
reg clock = 0;
always #50 clock = ~clock; // 100 time ticks per cycle = 10 MHz clock
23
24
25
26
27
28
29
30
31
// DUT
alu_latch latchDUT(.clock(clock),
.reset(reset),
.alu_result(alu_result),
.grab(grab),
.store_high(store_high),
.store_low(store_low),
.out(databus));
32
33
34
35
36
37
38
51
B.5
39
40
41
42
43
44
45
46
// Beginning of test
initial begin
@(negedge clock) begin
reset = 0;
end
@(negedge clock) begin
reset = 1;
end
47
48
//
input
grab high
do_test(16hbeef, 1b1, 1b0,
but dont put it out
do_test(16hdead, 1b0, 1b1,
and put the high half out
do_test(16hdead, 1b0, 1b0,
and put the low half out
do_test(16hface, 1b1, 1b0,
and put its low half out
49
50
51
52
low
expected
1b0, 8hzz, __LINE__); // Latch a value,
1b0, 8hbe, __LINE__); // Hold the value
1b1, 8hef, __LINE__); // Hold the value
1b1, 8hce, __LINE__); // Load a new value
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
endmodule
B.5
1
2
3
4
5
/*
*
*
*
*
gp_registers_test.v
Testbench for the general purpose register set.
Author: Steven Bell <steven.bell@student.oc.edu>
Date: 23 September 2010
$LastChangedDate: 2010-12-13 18:04:13 -0600 (Mon, 13 Dec 2010) $
52
B.5
*/
7
8
9
10
11
12
module gp_registers_test;
13
14
15
16
17
18
19
reg reset;
reg read_data; // save data to register
reg write_data; // write data from register
reg[2:0] input_select; // Register to put the input value into
reg[2:0] output_select; // Index of the register we want to put on the data
bus output
reg[2:0] alu_output_select; // Index of the register we want to put on the
ALU output
20
21
22
23
24
25
26
27
// Data bus
reg[7:0] data_bus_driver; // Simulation of another device driving the data
bus
reg data_bus_driven; // Whether or not something else is driving the data
bus
assign data_bus = data_bus_driven ? data_bus_driver : 8hzz;
28
29
30
31
// Test variables
parameter NUM_REGISTERS = 8; // Number of registers we have
integer regidx; // Used to cycle through the registers
32
33
34
35
// Clock
reg clock = 0;
always #50 clock = !clock; //100 time ticks per cycle = 10 MHz clock
36
37
38
39
40
// DUT
gp_registers registers(clock, reset, read_data, write_data,
input_select, output_select, alu_output_select,
data_bus, alu_output_value);
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Test code
initial begin
// Reset the registers
@(negedge clock)
reset = 0;
@(negedge clock)
53
B.5
55
reset = 1;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// Iterate through the registers and check that they were reset
for(regidx = 0; regidx < NUM_REGISTERS; regidx = regidx + 1) begin
// On the negative edge of the clock, request the value out both ports
@(negedge clock) begin
write_data = 1b1; // The registers will be writing data out to the
bus
read_data = 1b0;
output_select = regidx;
alu_output_select = regidx;
end
// On the positive edge, read the output and check it
@(posedge clock) begin
#30; // Wait for the value to change - is there a better way?
if(data_bus != 8h00 || alu_output_value != 8h00) begin
$display("Register %d not reset! Value is %d/%d", regidx, data_bus,
alu_output_value);
end // if
end // posedge clock
end // checking reset
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Iterate throught the registers and assign values that we will read
later
for(regidx = 0; regidx < NUM_REGISTERS; regidx = regidx + 1) begin
// On the negative edge of the clock, set up the inputs
@(negedge clock) begin
write_data = 1b0;
read_data = 1b1; // The registers will now be reading data in
data_bus_driven = 1b1; // And we will be driving the data bus
data_bus_driver = regidx + 10; // Store a unique nonzero value for
each register
input_select = regidx;
output_select = (regidx + 1) % NUM_REGISTERS; // Read out a different
register than
alu_output_select = (regidx + 1) % NUM_REGISTERS; // the one we are
writing to
end
// On the positive edge, read the output and check it
@(posedge clock) begin
#30; // Wait for the value to change - is there a better way?
// BUG: This will fail on the last loop
//if(data_bus != 8hzz || alu_output_value != 8h00) begin
// $display("Register %d not writing properly! Output is %d/%d",
regidx, data_bus, alu_output_value);
//end // if
end // posedge clock
end // assigning test values
98
99
100
// Iterate through the registers and check that we cna read the test
values out again
54
B.6
101
Datapath
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
@(negedge clock)
$finish;
120
121
122
end
123
124
endmodule
B.6
1
2
3
4
5
6
Datapath
/* datapath_test.v
* Testbench for the arithmetic logic unit
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 6 October 2010
* $LastChangedDate: 2010-12-13 18:04:13 -0600 (Mon, 13 Dec 2010) $
*/
7
8
9
10
11
12
include "constants.v"
13
14
module datapath_test();
15
16
parameter NAME_LEN = 239; // Length of the string in bytes, minus one (30 *
8 - 1)
17
18
19
20
21
22
23
24
reg reset;
reg gp_read;
reg gp_write;
reg pc_increment;
reg pc_set;
reg[2:0] gp_input_select;
reg[2:0] gp_output_select;
55
B.6
25
26
27
28
29
30
31
32
33
34
35
Datapath
reg[2:0] gp_alu_output_select;
reg[3:0] alu_operation;
reg latch_alu;
reg alu_store_high;
reg alu_store_low;
reg mar_set_high;
reg mar_set_low;
reg ir_set_high;
reg ir_set_low;
reg jr_set_high;
reg jr_set_low;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/* Data bus
* Because the data bus is a bidirectional port, we cant treat it as a wire
* (which must have continuous assignment) or a reg (which cant be
continuously
* assigned). We have to create a reg which holds the value, and then use
an
* assign statement to pick what we want. */
reg[7:0] data_bus_driver; // Holds the value we want to put onto the bus
reg data_bus_input; // When true, the data bus reads from data_bus_driver,
when false, its an output
wire[7:0] data_bus; // Wire connected to the DUT
50
51
52
53
54
55
// Testbench variables
integer regIdx; // Index variable for the general purpose registers
reg[NAME_LEN:0] testName; // Holds the printed name for some tests
56
57
58
59
// Clock
reg clock = 0;
always #50 clock = !clock; // 100 time ticks per cycle = 10 MHz clock
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// DUT
datapath dp(
.clock(clock),
.reset(reset),
.pc_increment(pc_increment),
.pc_set(pc_set),
.gp_read(gp_read),
.gp_write(gp_write),
.gp_input_select(gp_input_select),
.gp_output_select(gp_output_select),
.gp_alu_output_select(gp_alu_output_select),
.alu_operation(alu_operation),
.latch_alu(latch_alu),
.alu_store_high(alu_store_high),
.alu_store_low(alu_store_low),
56
B.6
76
77
78
79
80
81
82
83
84
85
86
Datapath
.mar_set_high(mar_set_high),
.mar_set_low(mar_set_low),
.ir_set_high(ir_set_high),
.ir_set_low(ir_set_low),
.jr_set_high(jr_set_high),
.jr_set_low(jr_set_low),
.pc_count(pc_count),
.mar_value(mar_value),
.ir_value(ir_value),
.flags(alu_flags),
.data_bus(data_bus));
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
57
B.6
130
131
132
133
134
135
136
137
138
139
Datapath
resetSignals();
data_bus_driver = 8hfa;
data_bus_input = 1b1;
jr_set_high = 1b1;
// Put the jump register value into the program counter and check it
@(negedge clock)
resetSignals();
pc_set = 1b1;
@(posedge clock) #5
check16("Jump register", pc_count, 16hface, __LINE__);
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Put each general purpose register back on the data bus and check it
for(regIdx = 0; regIdx < 8; regIdx = regIdx + 1) begin
@(negedge clock)
resetSignals();
gp_output_select = regIdx;
gp_write = 1b1;
@(posedge clock) #5
$sformat(testName, "General-purpose reg #%1d", regIdx);
checkDatabus(testName, regIdx, __LINE__);
end
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
58
B.6
183
Datapath
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
59
B.6
236
237
Datapath
@(posedge clock)
checkDatabus("ALU binary with immediate low", 8h58, __LINE__);
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
@(negedge clock)
$finish;
end // End of the test
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
60
B.7
289
291
292
293
294
296
mar_set_high = 0;
mar_set_low = 0;
ir_set_high = 0;
ir_set_low = 0;
jr_set_high = 0;
jr_set_low = 0;
290
295
end
endtask
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
endmodule
B.7
1
2
3
4
5
6
7
8
9
10
11
12
/* control_test.v
* Testbench for the control module. This code uses an external text file,
* control_vectors, which contains a series of control module states and
opcodes
* where necessary. After performing a reset, the code reads a line from the
* file, executes a clock cycle, and checks that the control module entered
the
* specified state.
* This code does not check that the state vectors are outputted properly. It
only
* checks that the state sequence is correct.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 23 November 2010
* $LastChangedDate: 2010-12-13 18:04:13 -0600 (Mon, 13 Dec 2010) $
*/
61
B.7
13
14
15
16
17
18
19
20
21
module control_test();
parameter STRING_LEN = 239; // Maximum length of the strings we read in bits
(minus one)
reg reset = 1; // Reset signal for the part
reg[15:0] instruction_register; // Dummy instruction register which we load
from the file
22
23
24
25
26
27
// Clock
reg clock = 0;
always #50 clock = ~clock;
28
29
30
31
32
33
// DUT
control controlDUT(.clock(clock),
.reset(reset),
.instruction(instruction_register),
.state(control_state));
34
35
36
37
38
39
// Logging
initial begin
$dumpfile("control.vcd");
$dumpvars(); // Dump everything
end
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Beginning of test
initial begin
// Perform reset
@(negedge clock)
reset = 1b0;
@(negedge clock)
reset = 1b1;
55
56
57
58
59
60
61
62
63
62
B.7
64
65
66
$display("%s", stateString);
r = $fscanf(file, "%s", stateString);
end
67
68
69
70
// On the rising edge of the clock, the module should be in that state
@(posedge clock) #5
testOpcode(stateString, control_state);
71
72
73
74
75
76
77
78
79
80
81
// If the state is a fetch, then read the opcode byte from the file and
// set the instruction register appropriately
if(stateString == "FETCH_1") begin
r = $fscanf(file, "%2h", opcodeByte);
instruction_register[15:8] = opcodeByte;
end
else if(stateString == "FETCH_2") begin
r = $fscanf(file, "%2h", opcodeByte);
instruction_register[7:0] = opcodeByte;
end
82
83
end
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
case(string)
"RESET":
desiredState = S_RESET;
"FETCH_1":
desiredState = S_FETCH_1;
"FETCH_2":
desiredState = S_FETCH_2;
"ALU_OPERATION":
desiredState = S_ALU_OPERATION;
"ALU_IMMEDIATE":
desiredState = S_ALU_IMMEDIATE;
"STORE_RESULT_1":
desiredState = S_STORE_RESULT_1;
"STORE_RESULT_2":
desiredState = S_STORE_RESULT_2;
"FETCH_IMMEDIATE":
desiredState = S_FETCH_IMMEDIATE;
"COPY_REGISTER":
63
B.7
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
desiredState = S_COPY_REGISTER;
"FETCH_ADDRESS_1":
desiredState = S_FETCH_ADDRESS_1;
"FETCH_ADDRESS_2":
desiredState = S_FETCH_ADDRESS_2;
"FETCH_MEMORY":
desiredState = S_FETCH_MEMORY;
"STORE_MEMORY":
desiredState = S_STORE_MEMORY;
"TEMP_FETCH":
desiredState = S_TEMP_FETCH;
"FETCH_ADDRESS_3":
desiredState = S_FETCH_ADDRESS_3;
"FETCH_ADDRESS_4":
desiredState = S_FETCH_ADDRESS_4;
"TEMP_STORE":
desiredState = S_TEMP_STORE;
"LOAD_JUMP_1":
desiredState = S_LOAD_JUMP_1;
"LOAD_JUMP_2":
desiredState = S_LOAD_JUMP_2;
"EXECUTE_JUMP":
desiredState = S_EXECUTE_JUMP;
"HALT":
desiredState = S_HALT;
default:
desiredState = 5b00000;
endcase
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
endmodule
64
B.8
B.8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module control_signals_test();
// Inputs to the DUT
reg[4:0] state;
reg[15:0] opcode;
reg[2:0] alu_flags;
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
65
B.8
53
54
55
56
57
58
59
60
61
62
63
reg d_latch_alu;
reg d_alu_store_high;
reg d_alu_store_low;
reg d_jr_load_high;
reg d_jr_load_low;
reg d_mar_load_high;
reg d_mar_load_low;
reg[3:0] d_alu_operation;
reg[2:0] d_gp_input_select;
reg[2:0] d_gp_output_select;
reg[2:0] d_gp_alu_output_select;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// DUT
control_signals csDUT(.state(state),
.opcode(opcode),
.alu_flags(alu_flags),
.ir_load_high(ir_load_high),
.ir_load_low(ir_load_low),
.gp_read(gp_read),
.gp_write(gp_write),
.pc_set(pc_set),
.pc_increment(pc_increment),
.mem_read(mem_read),
.mem_write(mem_write),
.latch_alu(latch_alu),
.alu_store_high(alu_store_high),
.alu_store_low(alu_store_low),
.jr_load_high(jr_load_high),
.jr_load_low(jr_load_low),
.mar_load_high(mar_load_high),
.mar_load_low(mar_load_low),
.alu_operation(alu_operation),
.gp_input_select(gp_input_select),
.gp_output_select(gp_output_select),
.gp_alu_output_select(gp_alu_output_select));
91
92
93
94
95
96
97
98
99
100
101
102
103
// Beginning of test
initial begin
// Reset
state = S_RESET;
opcode = 16hbeef;
zeroDesired();
104
105
checkSignals(__LINE__);
106
66
B.8
107
108
109
110
111
112
113
114
// Fetch 1
state = S_FETCH_1;
opcode = 16hface;
zeroDesired();
d_ir_load_high = 1;
d_mem_read = 1;
d_pc_increment = 1;
115
116
checkSignals(__LINE__);
117
118
119
120
121
122
123
124
125
// Fetch 2
state = S_FETCH_2;
opcode = 16hface;
zeroDesired();
d_ir_load_low = 1;
d_mem_read = 1;
d_pc_increment = 1;
126
127
checkSignals(__LINE__);
128
129
130
131
132
133
134
135
136
checkSignals(__LINE__);
137
138
139
140
141
142
143
144
145
146
checkSignals(__LINE__);
147
148
149
150
151
152
153
154
// Store result
state = S_STORE_RESULT_1;
opcode = 16h0c00;
zeroDesired();
d_gp_read = 1;
d_alu_store_low = 1;
155
156
checkSignals(__LINE__);
157
158
159
160
// Store a multiply
state = S_STORE_RESULT_1;
67
B.8
161
162
163
164
165
opcode = 16h1820;
zeroDesired();
d_gp_read = 1;
d_alu_store_high = 1;
checkSignals(__LINE__);
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Do a copy
state = S_COPY_REGISTER;
opcode = 16h0000;
zeroDesired();
d_gp_read = 1;
d_gp_write = 1;
checkSignals(__LINE__);
182
183
184
185
186
187
188
189
190
// Do an address fetch
state = S_FETCH_ADDRESS_1;
opcode = 16h0000;
zeroDesired();
d_pc_increment = 1;
d_mem_read = 1;
d_mar_load_high = 1;
checkSignals(__LINE__);
191
192
193
194
195
196
197
198
state = S_FETCH_ADDRESS_2;
opcode = 16h0000;
zeroDesired();
d_pc_increment = 1;
d_mem_read = 1;
d_mar_load_low = 1;
checkSignals(__LINE__);
199
200
201
202
203
204
205
206
// Memory fetch
state = S_FETCH_MEMORY;
opcode = 16h0000;
zeroDesired();
d_gp_read = 1;
d_mem_read = 1;
checkSignals(__LINE__);
207
208
209
210
211
212
213
214
// Memory store
state = S_STORE_MEMORY;
opcode = 16h0000;
zeroDesired();
d_gp_write = 1;
d_mem_write = 1;
checkSignals(__LINE__);
68
B.8
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
state = S_FETCH_ADDRESS_4;
opcode = 16h9000;
zeroDesired();
d_pc_increment = 1;
d_mem_read = 1;
d_mar_load_low = 1;
checkSignals(__LINE__);
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
state = S_LOAD_JUMP_2;
opcode = 16h7800;
zeroDesired();
d_pc_increment = 1;
d_mem_read = 1;
d_jr_load_low = 1;
checkSignals(__LINE__);
265
266
267
268
69
B.8
269
270
271
zeroDesired();
d_pc_set = 1;
checkSignals(__LINE__);
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
// Check halt
70
B.8
323
324
325
326
state = HALT;
opcode = 16hff00;
zeroDesired();
checkSignals(__LINE__);
327
328
329
330
331
332
333
334
$finish;
end
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
71
B.8
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
passed = 1b0;
end
if(latch_alu !== d_latch_alu) begin
$display("%4d : ALU latch test failed; expected %h but got %h", lineNum,
d_latch_alu, latch_alu);
passed = 1b0;
end
if(alu_store_high !== d_alu_store_high) begin
$display("%4d : ALU store high test failed; expected %h but got %h",
lineNum, d_alu_store_high, alu_store_high);
passed = 1b0;
end
if(alu_store_low !== d_alu_store_low) begin
$display("%4d : ALU store low test failed; expected %h but got %h",
lineNum, d_alu_store_low, alu_store_low);
passed = 1b0;
end
if(jr_load_high !== d_jr_load_high) begin
$display("%4d : JR high test failed; expected %h but got %h", lineNum,
d_jr_load_high, jr_load_high);
passed = 1b0;
end
if(ir_load_low !== d_ir_load_low) begin
$display("%4d : JR low test failed; expected %h but got %h", lineNum,
d_jr_load_low, jr_load_low);
passed = 1b0;
end
if(mar_load_high !== d_mar_load_high) begin
$display("%4d : MAR high test failed; expected %h but got %h", lineNum,
d_mar_load_high, mar_load_high);
passed = 1b0;
end
if(mar_load_low !== d_mar_load_low) begin
$display("%4d : MAR low test failed; expected %h but got %h", lineNum,
d_mar_load_low, mar_load_low);
passed = 1b0;
end
if(passed === 1b1) begin
$display("%4d : Test passed", lineNum);
end
402
403
404
405
end
endtask
406
407
408
409
410
411
412
413
414
415
task zeroDesired();
begin
d_ir_load_high = 1b0;
d_ir_load_low = 1b0;
d_gp_primary_addr = 1b0;
d_gp_alu_addr = 1b0;
d_gp_read = 1b0;
d_gp_write = 1b0;
d_pc_set = 1b0;
72
B.9
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
CPU
d_pc_increment = 1b0;
d_mem_read = 1b0;
d_mem_write = 1b0;
d_latch_alu = 1b0;
d_alu_store_high = 1b0;
d_alu_store_low = 1b0;
d_jr_load_high = 1b0;
d_jr_load_low = 1b0;
d_mar_load_high = 1b0;
d_mar_load_low = 1b0;
d_alu_operation = 4d0;
d_gp_input_select = 3d0;
d_gp_output_select = 3d0;
d_gp_alu_output_select = 3d0;
end
endtask
432
433
434
endmodule
B.9
1
2
3
4
5
CPU
6
7
8
9
10
11
12
13
14
15
16
module cpu_test();
parameter RAM_SIZE = 16; // Size of the RAM in bytes
parameter RAM_ADDRESS_BITS = 4; // How many address bits the RAM needs
parameter ROM_SIZE = 1024; // Size of the ROM in bytes
parameter ROM_ADDRESS_BITS = 10; // How many address bits the ROM needs
parameter MAX_LINE_LENGTH = 200; // Maximum length of line in input file
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
73
B.9
33
34
35
36
CPU
37
38
39
40
// Clock
reg clock = 0;
always #50 clock = ~clock;
41
42
43
44
45
46
47
48
49
// DUT
cpu cpuDUT(.clock(clock),
.reset(reset),
.external_data_bus(data_bus),
.address_bus(address_bus),
.ram_enable(ram_enable),
.rom_enable(rom_enable),
.write(write));
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// Beginning of test
initial begin
// Initialize ROM to all zeros
for(i = 0; i < ROM_SIZE; i = i + 1) begin
rom[i] = 8d0;
end
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Loop until we get to the end of the file and initialize ROM with the
contents
i = 0; // Start back at the beginning of ROM
while(! $feof(file)) begin
// Check if the first character is a #, signifiying a comment
c = $fgetc(file);
if(c == "#") begin
// If weve got a comment, skip to the next line
r = $fgets(line, file);
end
else begin
// Otherwise, assume that its a hex value and try to read it
r = $ungetc(c, file);
r = $fscanf(file, "%h\n", rom[i]);
i = i + 1;
74
B.9
85
86
CPU
end
end
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Perform a reset
@(negedge clock)
reset = 1b0;
@(negedge clock)
reset = 1b1;
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
endmodule
75
Output waveforms
Waveforms were created by dumping the signals to a VCD le directly from Verilog, converting them to
Aldec's .abf le format using the Aldec command-line utilities
vcd2asdb
and
awfconv,
76
0.0 ns
200.0 ns
400.0 ns
600.0 ns
800.0 ns
1,000.0 ns
200.0 ns
400.0 ns
600.0 ns
800.0 ns
1,000.0 ns
CLOCK
RESET
SETHIGH
SETLOW
0.0 ns
77
Z:\IC_DESIGN\ISPLEVER_CLASSIC\REGISTER_16BIT_TEST
Page 1 of 1
Program Counter
Name
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
clock
reset
increment
set
counterIn
FFFE
counterOut
XXXX
0000
FFFE
FFFF
78
Page 1 / 1
ALU
Name
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
clock
reset
primaryOperand
XX
00
01
00
01
secondaryOperand
XX
02
00
FF
02
operation
result
XXXX
0002
0000
00FF
0003
0101
0087
flags
XXX
000
100
001
000
010
001
Name
1490
1590
1690
FF
7D
F1
0A
FA
06
1790
1890
1990
0A
02
0A
0F
FA
2090
2190
2290
00FB
2390
0100
0004
0000
01FB
0108
110
000
100
011
010
2490
2590
2690
2790
2890
ns
clock
reset
primaryOperand
80
0A
64
FF
F6
AA
secondaryOperand
01
06
3C
FF
06
66
operation
result
007F
flags
000
Name
2980
003C
3080
2A
55
E6
4
1770
3180
FE01
05C4
001
000
3280
3380
0022
3480
AA
66
00
AA
00
FF
5
00A2
006E
00EE
0000
0055
100
001
000
001
100
000
3680
3780
00
0000
3580
AB
3880
3980
4080
2A
010
4180
0000
0054
100
000
4280
4380
ns
clock
reset
primaryOperand
AA
00
C0
2A
2B
00
AA
2A
AA
6A
00
01
80
32
CE
FF80
FFCE
FF32
secondaryOperand
9
operation
result
flags
010
0000
0080
0015
100
011
000
010
0000
0055
100
000
79
Page 1 / 2
0054
010
00D4
0000
FFFF
001
100
001
000
ALU
Name
4470
4570
4670
4770
4870
4970
5070
5270
5370
5470
5570
5670
5770
5870
ns
clock
reset
primaryOperand
5170
00
81
01
FF
secondaryOperand
8
operation
result
0000
FF7E
FFFE
FF00
flags
100
000
001
100
80
Page 2 / 2
ALU Latch
Name
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
clock
reset
grab
alu_result
XXXX
BEEF
DEAD
FACE
store_high
store_low
databus
Name
XX
1490
ZZ
1590
BE
1690
1790
1890
EF
1990
2090
2190
2290
2390
2490
2590
2690
2790
2890
ns
clock
reset
grab
alu_result
store_high
store_low
databus
Name
2980
3080
3180
3280
3380
3480
3580
3680
3780
3880
3980
4080
4180
4280
4380
ns
clock
reset
grab
alu_result
store_high
store_low
databus
81
Page 1 / 1
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
clock
reset
read_data
write_data
input_select
output_select
alu_output_select
data_bus
XX
alu_output_value
XX
Name
1490
0A
0B
0C
0D
00
1590
1690
1790
1890
1990
2090
2190
2290
2390
2490
2590
2690
2890
ns
clock
reset
read_data
write_data
input_select
output_select
alu_output_select
data_bus
0E
0F
10
11
alu_output_value
2790
0A
0A
0B
0B
0C
0C
82
Page 1 / 1
0D
0D
0E
0E
0F
0F
10
10
11
11
Datapath
Name
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
clock
reset
pc_increment
pc_set
gp_read
gp_write
gp_input_select
gp_output_select
gp_alu_output_select
alu_operation
01
02
03
04
05
06
latch_alu
alu_store_high
alu_store_low
mar_set_high
mar_set_low
ir_set_high
ir_set_low
jr_set_high
jr_set_low
pc_count
XXXX
0000
mar_value
XXXX
0000
ir_value
XXXX
0000
flags
data_bus
XX
ZZ
FACE
00EF
EF
BE
FACF
BEEF
CE
FA
ZZ
83
Page 1 / 3
00
Datapath
Name
1490
1590
1690
1790
1890
1990
2090
2190
2290
2390
2490
2590
2690
2790
2890
ns
clock
reset
pc_increment
pc_set
gp_read
gp_write
gp_input_select
0
1
gp_output_select
gp_alu_output_select
alu_operation
latch_alu
alu_store_high
alu_store_low
mar_set_high
mar_set_low
ir_set_high
ir_set_low
jr_set_high
jr_set_low
pc_count
00AD
mar_value
DEAD
00AD
0004
ir_value
0
flags
data_bus
07
00
01
02
03
04
84
Page 2 / 3
05
06
07
AD
DE
00
04
05
0B
Datapath
Name
2980
3080
3180
3280
3380
3480
3580
3680
3780
3980
4080
4180
4280
4380
ns
clock
reset
pc_increment
pc_set
gp_read
gp_write
gp_input_select
gp_output_select
gp_alu_output_select
alu_operation
latch_alu
alu_store_high
alu_store_low
mar_set_high
mar_set_low
ir_set_high
ir_set_low
jr_set_high
jr_set_low
pc_count
mar_value
ir_value
1
flags
data_bus
3880
64
02
58
ZZ
0
FE
7D
85
Page 3 / 3
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
clock
reset
instruction
XXXX
state
XX
Name
1490
00
1590
1690
00XX
0000
0800
0820
01
02
01
02
1790
1890
1990
1820
03
2090
05
2190
01
2290
02
2390
03
2490
05
2590
06
2690
2790
8420
8400
01
02
2890
ns
clock
reset
instruction
8400
07
state
Name
0C00
2980
3080
01
3180
8200
02
3280
04
3380
05
01
3480
3580
8900
02
3680
0A
3780
0B
3880
0C
3980
01
4080
02
4180
0A
4280
0B
0D
4380
ns
clock
reset
9300
instruction
state
Name
0D
4470
01
4570
7800
02
4670
0A
4770
0B
4870
0E
0F
4970
5070
5170
11
5270
01
5370
02
5470
12
5570
13
5670
14
5770
01
02
5870
ns
clock
reset
instruction
state
10
F800
02
15
86
Page 1 / 1
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
state
00
01
02
03
opcode
BEEF
FACE
0C00
alu_flags
05
0800
0C00
06
08
09
0A
0B
0C
0D
0E
1820
0000
9000
ir_load_high
ir_load_low
gp_read
gp_write
pc_set
pc_increment
mem_read
mem_write
latch_alu
alu_store_high
alu_store_low
jr_load_high
jr_load_low
mar_load_high
mar_load_low
alu_operation
gp_input_select
gp_output_select
gp_alu_output_select
0
6
0
0
87
Page 1 / 2
1490
1590
1690
1790
1890
1990
2090
2290
2390
2490
2590
2690
2790
2890
ns
0F
10
11
12
7800
13
14
1F
7801
0
alu_flags
ir_load_high
ir_load_low
gp_read
gp_write
pc_set
pc_increment
mem_read
mem_write
latch_alu
alu_store_high
alu_store_low
jr_load_high
jr_load_low
mar_load_high
mar_load_low
alu_operation
2190
gp_input_select
gp_output_select
gp_alu_output_select
88
Page 2 / 2
7802
2
7803
4
FF00
1
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
clock
reset
address_bus
XXXX
data_bus
XX
state
XX
0000
00
00
01
0001
0002
0003
0004
0005
0006
0007
0008
00
84
00
55
89
00
20
00
02
01
02
06
01
02
08
09
2000
55
0B
0009
000A
000B
82
04
20
01
02
08
ram_enable
rom_enable
write
Name
1490
1590
1690
1790
1890
1990
2090
2190
2290
2390
2490
2590
2690
2790
2890
ns
clock
reset
address_bus
data_bus
state
000B
000C
2000
000D
000E
000F
0010
00
55
89
20
20
01
09
0A
01
02
08
09
ram_enable
rom_enable
write
89
Page 1 / 13
2001
55
0B
0011
0012
0013
80
28
0C
01
02
07
0C
01
0014
0015
0016
08
22
89
02
14
04
89
01
2980
3080
3180
3280
3380
3480
3580
3680
3780
3880
3980
4080
4180
4280
4380
ns
clock
reset
address_bus
data_bus
89
0017
0018
0019
40
20
02
02
state
08
09
2002
77
0B
001A
001B
001C
001D
001E
001F
84
10
5A
08
04
0C
01
02
06
01
02
03
0C
04
0C
01
0020
0021
0022
10
A5
78
02
14
04
ram_enable
rom_enable
write
Name
4470
4570
4670
4770
4870
4970
5070
5170
5270
5370
5470
5570
5670
5770
5870
ns
clock
reset
address_bus
data_bus
state
0022
78
04
78
01
0023
0024
0025
0026
01
01
19
89
02
10
11
12
89
01
ram_enable
rom_enable
write
90
Page 2 / 13
0027
0028
0029
20
20
03
02
08
09
2003
AA
0B
002A
002B
002C
002D
89
80
20
04
01
02
08
09
2004
FF
0B
5960
6060
6160
6260
6360
6460
6560
6660
6760
6860
6960
7060
7160
7260
7360
ns
clock
reset
address_bus
2004
002E
002F
0030
0031
0032
78
02
01
19
84
data_bus
FF
state
0B
01
02
10
11
12
01
02
06
01
02
07
01
02
14
7450
7550
7650
7750
7850
7950
8050
8150
8250
8350
8450
8550
8650
8750
8850
84
0033
0034
0035
0036
0037
0C
A9
80
34
14
14
0038
0039
14
33
ram_enable
rom_enable
write
Name
ns
clock
reset
address_bus
data_bus
state
003A
10
04
10
01
003B
003C
4C
78
02
03
78
04
78
01
003D
003E
003F
0040
01
01
19
78
02
ram_enable
rom_enable
write
91
Page 3 / 13
10
11
12
78
01
0041
0042
0043
0044
02
01
19
89
02
10
11
12
8.94
9.04
9.14
9.24
9.34
9.44
9.54
9.64
9.74
9.84
9.94
10.04
10.14
10.24
10.34
us
clock
reset
address_bus
0046
0047
60
20
05
89
data_bus
state
0045
01
02
08
09
2005
0048
0049
004A
004B
89
A0
20
06
32
0B
01
02
08
09
2006
004C
004D
004E
004F
0050
78
00
00
52
F8
77
0B
01
02
10
11
12
ram_enable
rom_enable
write
Name
10.43
10.53
10.63
10.73
10.83
10.93
11.03
11.13
11.23
11.33
11.43
11.53
11.63
11.73
11.83
us
clock
reset
address_bus
data_bus
state
0052
0053
0054
80
80
0C
01
02
07
0C
01
0055
0056
0057
00
FF
89
02
14
04
ram_enable
rom_enable
write
92
Page 4 / 13
89
01
0058
0059
005A
00
20
07
02
08
09
2007
FE
0B
005B
005C
005D
78
02
01
01
02
10
11.92
12.02
12.12
12.22
12.32
12.42
12.52
12.62
12.72
12.82
12.92
13.02
13.12
13.22
13.32
us
clock
reset
address_bus
data_bus
005E
005F
19
78
11
state
78
12
01
0060
0061
0062
0063
0065
0066
0067
0068
01
00
65
F8
0C
00
01
78
02
10
11
12
01
02
14
78
04
01
0069
006A
006B
02
01
19
02
10
11
ram_enable
rom_enable
write
Name
13.41
13.51
13.61
13.71
13.81
13.91
14.01
14.11
14.21
14.31
14.41
14.51
14.61
14.71
14.81
us
clock
reset
address_bus
data_bus
state
006C
78
12
78
01
006D
006E
006F
0070
01
01
19
89
02
10
11
12
ram_enable
rom_enable
write
93
Page 5 / 13
89
01
0071
0072
0073
00
20
08
02
08
09
2008
FF
0B
0074
0075
0076
0077
0C
00
01
78
01
02
14
04
14.9
15
15.1
15.2
15.3
15.4
15.5
15.6
15.7
15.8
15.9
16
16.1
16.2
16.3
us
clock
reset
address_bus
0077
78
data_bus
01
state
0078
0079
007A
007B
007D
007E
007F
0080
02
00
7D
F8
89
00
20
09
02
10
11
12
01
02
08
09
2009
00
0B
0081
0082
0083
0084
14
0C
21
78
01
02
14
04
78
01
ram_enable
rom_enable
write
Name
16.39
16.49
16.59
16.69
16.79
16.89
16.99
17.09
17.19
17.29
17.39
17.49
17.59
17.69
17.79
us
clock
reset
address_bus
data_bus
state
0085
0086
0087
0088
02
01
19
78
02
10
11
12
78
01
0089
008A
008B
008C
01
01
19
89
02
ram_enable
rom_enable
write
94
Page 6 / 13
10
11
12
89
01
008D
008E
008F
60
20
0A
02
08
09
200A
11
0B
0090
14
01
17.88
17.98
18.08
18.18
18.28
18.38
18.48
18.58
18.68
18.78
18.88
18.98
19.08
19.18
19.28
us
clock
reset
address_bus
data_bus
0090
0091
0092
0093
14
0C
11
78
state
78
0094
0095
0096
0097
01
01
19
78
78
0098
0099
009A
009B
009D
009E
02
00
9D
F8
89
60
02
14
04
01
02
10
11
12
01
02
10
11
12
01
19.47
19.57
19.67
19.77
19.87
19.97
20.07
20.17
20.27
20.37
20.47
20.57
20.67
20.77
02
ram_enable
rom_enable
write
Name
19.37
us
clock
reset
address_bus
data_bus
state
009E
009F
00A0
60
20
0B
02
08
09
200B
00
0B
00A1
00A2
00A3
00A4
14
0C
33
78
01
02
14
ram_enable
rom_enable
write
95
Page 7 / 13
04
78
01
00A5
00A6
00A7
00A8
02
01
19
78
02
10
11
12
00A9
78
01
00AA
03
02
10
20.86
20.96
21.06
21.16
21.26
21.36
21.46
21.56
21.66
21.76
21.86
21.96
22.06
22.16
22.26
us
clock
reset
address_bus
data_bus
state
00AA
00AB
00AC
00AE
00AF
00B0
00B1
00
AE
F8
89
60
20
0C
200C
CD
00B2
00B3
00B4
00B5
0C
14
00
78
78
00B6
00B7
01
01
10
11
12
01
02
08
09
0B
01
02
14
04
01
02
10
22.35
22.45
22.55
22.65
22.75
22.85
22.95
23.05
23.15
23.25
23.35
23.45
23.55
23.65
23.75
ram_enable
rom_enable
write
Name
us
clock
reset
address_bus
data_bus
state
00B8
00B9
19
10
11
12
10
01
00BA
00BB
94
78
02
03
78
04
78
01
ram_enable
rom_enable
write
96
Page 8 / 13
00BC
00BD
00BE
00BF
02
01
19
78
02
10
11
12
78
01
00C0
00C1
00C2
03
01
19
02
10
11
23.84
23.94
24.04
24.14
24.24
24.34
24.44
24.54
24.64
24.74
24.84
24.94
25.04
25.14
25.24
us
clock
reset
address_bus
00C3
78
data_bus
state
12
00C4
00C5
00C6
00C7
01
00
C7
89
78
01
02
10
11
12
00C8
00C9
00CA
A0
20
0D
89
01
02
08
09
200D
00CB
00CC
00CD
80
38
1C
78
0B
01
02
07
1C
01
ram_enable
rom_enable
write
Name
25.33
25.43
25.53
25.63
25.73
25.83
25.93
26.03
26.13
26.23
26.33
26.43
26.53
26.63
26.73
us
clock
reset
address_bus
data_bus
state
00CE
00CF
00D0
18
A5
89
02
14
04
89
05
89
01
00D1
00D2
00D3
C0
20
0E
02
08
ram_enable
rom_enable
write
97
Page 9 / 13
09
200E
6D
0B
00D4
00D5
00D6
00D7
89
E0
20
0F
01
02
08
09
200F
92
0B
00D8
84
01
26.82
26.92
27.02
27.12
27.22
27.32
27.42
27.52
27.62
27.72
27.82
27.92
28.02
28.12
28.22
us
clock
reset
address_bus
data_bus
00D9
00DA
00DB
00DC
00DD
1C
BB
18
DC
89
02
state
06
01
02
89
03
89
04
89
05
01
00DE
00DF
00E0
C0
20
10
02
08
2010
4F
09
0B
00E1
00E2
00E3
89
E0
20
01
02
08
ram_enable
rom_enable
write
Name
28.31
28.41
28.51
28.61
28.71
28.81
28.91
29.01
29.11
29.21
29.31
29.41
29.51
29.61
29.71
us
clock
reset
address_bus
data_bus
state
00E4
11
09
2011
9F
0B
00E5
00E6
00E7
80
04
40
01
02
07
40
01
ram_enable
rom_enable
write
98
Page 10 / 13
00E8
00E9
04
89
02
03
89
04
89
01
00EA
00EB
00EC
20
20
12
02
08
09
2012
FF
0B
00ED
40
01
29.8
29.9
30
30.1
30.2
30.3
30.4
30.5
30.6
30.7
30.8
30.9
31
31.1
31.2
us
clock
reset
address_bus
00ED
data_bus
00EE
00EF
04
89
02
state
03
89
04
89
01
00F0
00F1
00F2
20
20
13
02
08
09
2013
00
0B
00F3
00F4
00F5
00F6
00F7
78
01
01
19
78
01
02
10
11
12
00F8
78
01
02
02
ram_enable
rom_enable
write
Name
31.29
31.39
31.49
31.59
31.69
31.79
31.89
31.99
32.09
32.19
32.29
32.39
32.49
32.59
32.69
us
clock
reset
address_bus
data_bus
state
00F8
00F9
00FA
00FB
00FD
00FE
00FF
00
FD
F8
80
70
30
10
11
12
01
02
07
ram_enable
rom_enable
write
99
Page 11 / 13
30
01
0100
0101
10
89
02
03
89
04
89
01
0102
0103
0104
80
20
14
02
08
09
2014
66
0B
32.78
32.88
32.98
33.08
33.18
33.28
33.38
33.48
33.58
33.68
33.78
33.88
33.98
34.08
34.18
us
clock
reset
address_bus
2014
data_bus
state
0105
0106
0107
30
10
89
89
89
0108
0109
010A
80
20
15
2015
33
010B
010C
010D
80
98
38
38
010E
010F
18
89
0B
01
02
03
04
01
02
08
09
0B
01
02
07
01
02
34.27
34.37
34.47
34.57
34.67
34.77
34.87
34.97
35.07
35.17
35.27
35.37
35.47
35.57
35.67
03
ram_enable
rom_enable
write
Name
us
clock
reset
address_bus
data_bus
state
010F
89
03
89
04
89
01
0110
0111
0112
C0
20
16
02
08
09
2016
66
0B
ram_enable
rom_enable
write
100
Page 12 / 13
0113
0114
0115
38
18
89
01
02
03
89
04
89
01
0116
0117
0118
C0
20
17
02
08
09
2017
CC
0B
35.76
35.86
35.96
36.06
36.16
36.26
36.36
36.46
36.56
36.66
36.76
36.86
36.96
37.06
37.16
us
clock
reset
address_bus
2017
data_bus
CC
state
0B
0119
011A
011B
011C
011D
011E
011F
00
00
00
00
F8
00
00
01
02
01
02
01
02
ram_enable
rom_enable
write
101
Page 13 / 13
13
00
00
00
00
00
00
00
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
ns
clock
reset
address_bus
XXXX
data_bus
XX
state
XX
0000
84
00
01
0001
0002
0003
0004
0005
0006
0007
0008
0009
000A
000B
000C
00
55
84
04
FF
84
08
FF
84
0C
33
84
02
06
01
02
06
01
02
06
01
02
06
01
ram_enable
rom_enable
write
Name
1490
1590
1690
1790
1890
1990
2090
2190
2290
2390
2490
2590
2690
2790
2890
ns
clock
reset
address_bus
data_bus
state
000C
000D
000E
000F
0010
0011
0012
0013
0014
14
03
84
1C
C0
80
70
30
02
06
01
02
06
01
ram_enable
rom_enable
write
102
Page 1 / 8
02
07
30
01
0015
0016
10
89
02
03
89
04
89
01
0017
0018
80
20
02
08
2980
3080
3180
3280
3380
3480
3580
3680
3780
3880
3980
4080
4180
4280
4380
ns
clock
reset
address_bus
data_bus
0018
0019
20
00
09
state
2000
19
0B
001A
001B
001C
30
10
89
01
02
89
03
04
89
01
001D
001E
001F
80
20
01
02
08
09
2001
0C
0B
0020
0021
0022
80
98
38
01
02
07
38
01
ram_enable
rom_enable
write
Name
4470
4570
4670
4770
4870
4970
5070
5170
5270
5370
5470
5570
5670
5770
5870
ns
clock
reset
address_bus
data_bus
state
38
01
0023
0024
18
89
02
03
89
04
89
01
0025
0026
0027
C0
20
02
02
08
ram_enable
rom_enable
write
103
Page 2 / 8
09
2002
18
0B
0028
0029
002A
38
18
89
01
02
03
002B
89
04
89
01
002C
C0
02
08
5960
6060
6160
6260
6360
6460
6560
6660
6760
6860
6960
7060
7160
7260
7360
ns
clock
reset
address_bus
data_bus
state
002C
002D
20
03
2003
30
002E
002F
0030
30
14
78
78
78
0031
0032
0033
0034
0036
0037
0038
01
00
36
F8
30
14
78
08
09
0B
01
02
03
04
01
02
10
11
12
01
02
03
7450
7550
7650
7750
7850
7950
8050
8150
8250
8350
8450
8550
8650
8750
8850
ram_enable
rom_enable
write
Name
ns
clock
reset
address_bus
data_bus
state
78
04
78
01
0039
003A
003B
003C
003E
003F
0040
02
00
3E
F8
38
1C
78
02
10
11
12
01
ram_enable
rom_enable
write
104
Page 3 / 8
02
03
78
04
78
01
0041
0042
0043
0044
01
00
46
F8
02
10
11
12
8.94
9.04
9.14
9.24
9.34
9.44
9.54
9.64
9.74
9.84
9.94
10.04
10.14
10.24
10.34
us
clock
reset
address_bus
0046
0047
0048
38
1C
78
data_bus
state
01
02
03
78
04
0049
004A
004B
004C
004E
004F
0050
02
00
4E
F8
80
14
24
78
01
02
10
11
12
01
02
07
0051
0052
14
0F
24
01
02
14
ram_enable
rom_enable
write
Name
10.43
10.53
10.63
10.73
10.83
10.93
11.03
11.13
11.23
11.33
11.43
11.53
11.63
11.73
11.83
us
clock
reset
address_bus
data_bus
state
0053
89
04
89
01
0054
0055
0056
A0
20
04
02
08
09
2004
0057
0058
0059
20
10
89
05
0B
01
ram_enable
rom_enable
write
105
Page 4 / 8
02
03
89
04
89
01
005A
005B
005C
80
20
05
02
08
09
2005
04
0B
11.92
12.02
12.12
12.22
12.32
12.42
12.52
12.62
12.72
12.82
12.92
13.02
13.12
13.22
13.32
us
clock
reset
address_bus
data_bus
005D
005E
005F
80
A4
24
01
state
02
24
07
01
0060
0061
0062
04
F0
89
02
14
89
04
01
0063
0064
0065
20
20
06
02
08
2006
00
09
0B
0066
0067
0068
78
02
00
01
02
10
ram_enable
rom_enable
write
Name
13.41
13.51
13.61
13.71
13.81
13.91
14.01
14.11
14.21
14.31
14.41
14.51
14.61
14.71
14.81
us
clock
reset
address_bus
data_bus
state
0069
006A
006C
006D
006E
6C
F8
20
28
89
11
12
01
02
03
89
04
ram_enable
rom_enable
write
106
Page 5 / 8
89
01
006F
0070
0071
40
20
07
02
08
09
2007
00
0B
0072
0073
0074
0075
78
02
00
78
01
02
10
11
14.9
15
15.1
15.2
15.3
15.4
15.5
15.6
15.7
15.8
15.9
16
16.1
16.2
16.3
us
clock
reset
address_bus
0075
data_bus
0076
0078
0079
007A
F8
80
08
2C
12
state
01
02
07
2C
01
007B
007C
007D
08
A0
89
02
14
04
89
01
007E
007F
0080
40
20
08
02
08
09
2008
F5
0B
0081
0082
28
98
01
02
ram_enable
rom_enable
write
Name
16.39
16.49
16.59
16.69
16.79
16.89
16.99
17.09
17.19
17.29
17.39
17.49
17.59
17.69
17.79
us
clock
reset
address_bus
data_bus
state
0082
0083
89
03
89
04
89
01
0084
0085
0086
C0
20
09
02
08
09
ram_enable
rom_enable
write
107
Page 6 / 8
2009
34
0B
0087
0088
0089
80
E8
2C
01
02
07
2C
01
008A
008B
008C
08
00
89
02
14
04
89
01
17.88
17.98
18.08
18.18
18.28
18.38
18.48
18.58
18.68
18.78
18.88
18.98
19.08
19.18
19.28
us
clock
reset
address_bus
data_bus
89
state
008D
008E
008F
40
20
0A
200A
00
0090
0091
0092
0093
0094
0096
0097
0098
78
02
00
96
F8
28
3C
89
0099
89
89
02
08
09
0B
01
02
10
11
12
01
02
03
04
01
19.47
19.57
19.67
19.77
19.87
19.97
20.07
20.17
20.27
20.37
20.47
20.57
20.67
20.77
E0
02
ram_enable
rom_enable
write
Name
19.37
us
clock
reset
address_bus
data_bus
state
0099
009A
009B
E0
20
0B
02
08
09
200B
00
0B
009C
009D
009E
009F
00A0
00A2
00A3
00A4
00A5
78
02
00
A2
F8
89
00
20
0C
01
02
10
ram_enable
rom_enable
write
108
Page 7 / 8
11
12
01
02
08
09
200C
55
0B
00A6
00A7
F8
01
02
20.86
20.96
21.06
21.16
21.26
21.36
21.46
21.56
21.66
21.76
21.86
21.96
22.06
22.16
22.26
us
clock
reset
address_bus
data_bus
state
00A7
00A8
00
00
02
00
00
00
00
00
13
ram_enable
rom_enable
write
109
Page 8 / 8
00
00
00
00
00
00
00
00
D
D.1
PCB diagrams
Eagle schematic
110
D.2
Eagle layout
111
E
1
2
3
4
5
6
7
Assembler code
/**
* \file main.cpp
* Main code file for Stevens (purposeful|powerful|pimpin|pernicious)
assembler (SPASM)
* \author Steven Bell <steven.bell@student.oc.edu>
* \date 4 November 2010
* $LastChangedDate: 2010-12-14 23:24:10 -0600 (Tue, 14 Dec 2010) $
*/
8
9
10
11
12
13
14
15
16
17
18
/*
*
*
*
*
*
*
Command-line arguments
Usage:
spasm [args] inputfile
-o
-v, --verbose
going on
* -d, --dump
* -h, --help
*/
Output file
Verbose mode, print out lots of information about whats
Do a hex dump of the program after it is assembled
Print this help message
19
20
21
22
23
24
25
#include
#include
#include
#include
#include
#include
<QCoreApplication>
<QStringList>
<QFile>
"cstdio"
"console.h"
"parser.h"
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// If the help flag was specified, then just print the help message and quit
if(argList.contains("-h") || argList.contains("--help")){
printf("SPASM - Stevens special-purpose assembler\n");
printf("Copyright (c) 2010 Steven Bell <steven.bell@student.oc.edu>\n\n");
printf("Usage:\n");
printf(" spasm [args] inputfile\n\n");
printf(" -o, --output
Output file\n");
printf(" -v, --verbose
Verbose mode, print out lots of information
about whats going on\n");
printf(" -s, --simulator Do a hex dump of the program for the Verilog
testbench\n");
printf(" -l, --listing
Print a command listing useful for debugging\n")
;
printf(" -h, --help
Print this help message\n");
112
46
printf(" Note that the -s, -l, and -v arguments are mutually exclusive.\n\
n");
return(0);
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// Determine
bool verbose
bool simDump
bool listing
71
72
73
74
75
76
77
78
79
80
81
if(argList.contains("-v") || argList.contains("--verbose")){
verbose = true;
}
else if(argList.contains("-s") || argList.contains("--simulator")){
simDump = true;
}
else if(argList.contains("-l") || argList.contains("--listing")){
listing = true;
}
Console::instance().setVerbose(verbose);
82
83
84
85
86
87
88
89
90
91
Parser p;
QByteArray programBytes;
92
93
94
95
113
96
97
98
99
while(!inputFile.atEnd())
{
QString command(inputFile.readLine()); // Get the command string to parse
VERBOSE(p.linesRead(), command.trimmed().toAscii().constData()); // Print
the command
100
101
// TODO: for each line, store the starting address so we can create a
listing-style output
QByteArray commandBytes = p.parseLine(command);
programBytes.append(commandBytes);
102
103
104
105
106
107
108
109
110
111
112
113
if(simDump){
for(int i = 0; i < programBytes.length(); i++){
printf("%02x\n", (unsigned char)(programBytes[i]));
}
}
114
115
116
117
118
119
120
121
*/
122
123
124
125
126
127
128
129
130
int i = 0;
while(i < programBytes.length())
{
unsigned char checksum; // The checksum is the ones complement of the sum
of the byte count, address, and data
131
132
133
134
135
136
137
138
139
140
141
114
142
lineString.append(QString("%1").arg((unsigned char)(programBytes[i]), 2,
16, QChar(0)));
checksum += programBytes[i];
i++;
143
144
145
}
// Write the checksum
checksum = ~checksum;
lineString.append(QString("%1").arg(checksum, 2, 16, QChar(0)));
outputFile.write(lineString.toAscii().constData());
outputFile.write("\n"); // Write a newline
146
147
148
149
150
151
152
153
154
155
1
2
3
4
5
6
return(0);
}
/** parser.cpp
* Class declaration for the parser class, which parses sets of instructions
passed to it.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 24 November 2010
* $LastChangedDate: 2010-12-14 23:24:10 -0600 (Tue, 14 Dec 2010) $
*/
7
8
9
#ifndef PARSER_H
#define PARSER_H
10
11
12
13
#include <QString>
#include <QHash>
#include <QByteArray>
14
15
16
class Parser
{
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public:
typedef enum
{
NOP = 0x00,
ADD = 0x01,
SUB = 0x02,
MUL = 0x03,
AND = 0x04,
OR = 0x05,
LSR = 0x06,
LSL = 0x07,
COMP = 0x08,
ASR = 0x09,
ASL = 0x0a,
NEG = 0x0b, // Twos complement
// PASSTHROUGH (0x0c) is for internal use only
JUMP = 0x0f,
LOAD = 0x10,
STORE = 0x11,
MOVE = 0x12,
115
38
39
40
41
42
43
44
LSTACK = 0x13,
JSR = 0x14,
RSUB = 0x15,
RINT = 0x16,
HALT = 0x1F,
INVALID = 0xFF
} Opcode;
45
46
47
48
49
50
51
52
53
54
55
56
typedef enum
{
A = 0,
B = 1,
C = 2,
D = 3,
E = 4,
F = 5,
G = 6,
H = 7
} RegisterCode;
57
58
59
60
61
62
63
64
typedef enum
{
NONE = 0,
REGISTER = 2,
IMMEDIATE = 4,
ADDRESS = 8
} TokenType;
65
66
67
68
69
Parser();
QByteArray parseLine(QString line);
void assignUnknownLabels(QByteArray& code);
int linesRead(void) {return(mLineCount);}
70
71
72
73
74
private:
bool parseRegisterDest(QStringList* tokens, unsigned short* opcodeBytes);
Opcode stringToOpcode(QString str);
TokenType parseParameterToken(QString token, int allowable, unsigned short &
value);
75
76
int mLineCount; ///< Counts how many lines have been parsed
77
78
79
/// Address where the next instruction will be stored in memory, used for
labels
unsigned int mByteLocation;
80
81
82
83
84
85
86
87
};
88
89
#endif // PARSER_H
116
1
2
3
4
5
6
/** parser.cpp
* Code to parse instructions given one at a time. Labels are held
persistently and handled appropriately.
* Author: Steven Bell <steven.bell@student.oc.edu>
* Date: 24 November 2010
* $LastChangedDate: 2010-12-14 23:24:10 -0600 (Tue, 14 Dec 2010) $
*/
7
8
9
10
11
#include
#include
#include
#include
<cstdio>
<QStringList>
"console.h"
"parser.h"
12
13
14
15
16
17
18
19
20
/** Constructor
*/
Parser::Parser()
{
mByteLocation = 0;
mLineCount = 1; // Line numbers start at 1, not 0!
}
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// TODO: should use a regex here to make sure that we dont end up with
// funky characters in the labels.
while(!tokens.isEmpty() && tokens.first().contains(QRegExp("^[a-zA-Z]\\w+:$"
)))
{
// Parse the label(s) from the front, if there are any
QString label = tokens.first();
label = label.remove(QChar(:)); // Take the colon off the end
VERBOSE(mLineCount, "Label found at 0x%04x: \"%s\"", mByteLocation, label.
toAscii().constData());
43
44
// Create a string with the memory address so we can use it like any other
define
mDefineTable[label] = QString("0x%1").arg(mByteLocation, 4, 16, QChar(0)
);
tokens.removeFirst();
45
46
47
117
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
switch(code){
case Parser::NOP:
case Parser::HALT:
case Parser::RSUB:
case Parser::RINT:
VERBOSE(mLineCount, "No args required");
break;
case Parser::ADD:
case Parser::SUB:
case Parser::MUL:
case Parser::AND:
case Parser::OR:
VERBOSE(mLineCount, "Two args required, register and register/immediate"
);
79
80
parseRegisterDest(&tokens, &opcodeBytes);
81
82
83
84
85
86
87
88
89
90
91
92
93
94
118
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
break;
case Parser::LOAD:
VERBOSE(mLineCount, "Two args required, register and register/immediate/
memory");
parseRegisterDest(&tokens, &opcodeBytes); // The first argument must
always be a the destination register
parseResult = parseParameterToken(tokens.first(), Parser::REGISTER |
Parser::IMMEDIATE | Parser::ADDRESS, parsedBytes);
tokens.removeFirst();
if(parseResult == REGISTER){ // COPY
opcodeBytes = opcodeBytes | (parsedBytes << 5); // Put the source
register as
// Dont have to set the source type, since its already 00
119
142
143
144
145
146
147
148
149
150
151
152
153
}
else if(parseResult == IMMEDIATE){
commandBytes.append((char)parsedBytes);
mByteLocation += 1;
opcodeBytes = opcodeBytes | (0x0400); // Set the source type bits to
immediate
}
else if(parseResult == ADDRESS){
commandBytes.append((char)(parsedBytes >> 8));
commandBytes.append((char)parsedBytes);
mByteLocation += 2;
opcodeBytes = opcodeBytes | (0x0200); // Set the source type bits to
memory
}
154
155
156
157
break;
case Parser::STORE:
VERBOSE(mLineCount, "Two args required, register and memory");
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
break;
case Parser::MOVE:
// This code is repeated several times essentially verbatim. Time for a
function?
VERBOSE(mLineCount, "Two addresses required\n");
parseResult = parseParameterToken(tokens.first(), Parser::ADDRESS,
parsedBytes);
tokens.removeFirst();
if(parseResult == ADDRESS){
commandBytes.append((char)(parsedBytes >> 8));
commandBytes.append((char)parsedBytes);
120
189
mByteLocation += 2;
}
else{
ERROR(mLineCount, "Expected address as first argument");
}
parseResult = parseParameterToken(tokens.first(), Parser::ADDRESS,
parsedBytes);
tokens.removeFirst();
if(parseResult == ADDRESS){
commandBytes.append((char)(parsedBytes >> 8));
commandBytes.append((char)parsedBytes);
mByteLocation += 2;
}
else{
ERROR(mLineCount, "Expected address as second argument");
}
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
break;
default:
ERROR(mLineCount, "Unrecognized opcode");
break;
207
208
209
210
211
212
213
214
215
If not, print a
216
217
218
219
220
mLineCount++;
// Byte location was already handled in-line
221
222
223
224
return(commandBytes);
}
225
226
227
228
229
230
231
232
233
234
235
236
237
/** This function goes through all of the locations in the unknown labels list
and
* replaces the placeholder address with the correct value. If the label is
not
* found, then it prints an error.
*/
void Parser::assignUnknownLabels(QByteArray& code)
{
QHash<unsigned short, QString>::iterator i;
for(i = mUnknownLabels.begin(); i != mUnknownLabels.end(); i++)
{
if(mDefineTable.contains(i.value())){
QString replacementString = mDefineTable[i.value()];
bool conversionOk; // Assume that it works; since we created the value!
121
238
239
240
// TODO: This will fail badly if the code has multiple segments or doesn
t start at 0.
code[i.key()] = (replacementValue >> 8);
code[i.key() + 1] = (replacementValue & 0x00FF);
241
242
243
244
245
246
}
else{
ERROR(mLineCount, "Unknown label \"%s\"", i.value().toAscii().constData
());
}
247
248
249
250
251
}
}
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/** Converts a string token (e.g, ADD or HALT) into an enum constant
representing
* the opcode.
*/
Parser::Opcode Parser::stringToOpcode(QString str)
{
str = str.toUpper(); // Force everything to uppercase
278
279
280
281
282
283
if(str == "NOP"){
return(NOP);
}
else if(str == "ADD"){
return(ADD);
122
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
}
else if(str == "SUB"){
return(SUB);
}
else if(str == "MUL"){
return(MUL);
}
else if(str == "AND"){
return(AND);
}
else if(str == "OR"){
return(OR);
}
else if(str == "LSR"){
return(LSR);
}
else if(str == "LSL"){
return(LSL);
}
else if(str == "COMP"){
return(COMP);
}
else if(str == "ASR"){
return(ASR);
}
else if(str == "ASL"){
return(ASL);
}
else if(str == "NEG"){
return(NEG);
}
else if(str == "JMP" || str == "JCAR" || str == "JZERO" || str == "JNEG"){
return(JUMP);
}
else if(str == "LOAD" || str == "COPY"){
return(LOAD);
}
else if(str == "STORE"){
return(STORE);
}
else if(str == "MOVE"){
return(MOVE);
}
else if(str == "LSTACK"){
return(LSTACK);
}
else if(str == "JSR"){
return(JSR);
}
else if(str == "RSUB"){
return(RSUB);
}
else if(str == "RINT"){
return(RINT);
123
338
}
else if(str == "HALT"){
return(HALT);
}
else{
return(INVALID);
}
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/** Takes a single token, determines what type of token it is, and parses its
value.
* If the token is a label or macro, it looks it up in the appropriate table
and
* substitutes that value.
* \param token The token to parse.
* \param allowable Acceptable types of tokens. Multiple types can be
selected using bitwise OR. If
* a token of the selected type is not found, this function will return
failure.
* \param value 2-byte variable which will hold the parsed value.
* \return The type of token that was parsed. This could be a 3-bit register
(registerCode),
* a one byte immediate value, a two byte immediate address, or a failure.
*/
Parser::TokenType Parser::parseParameterToken(QString token, int allowable,
unsigned short &value)
{
bool conversionOk;
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
124
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
125
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
if(mDefineTable.contains(token)){
// Replace the macro or label with the appropriate token
// Call this function recursively on the replaced token
return(parseParameterToken(mDefineTable[token], allowable, value));
}
else{
// If the table doesnt contain what were looking for, just substitute
a placeholder
// address and put this location into the unknown labels table.
if(allowable & ADDRESS){
VERBOSE(mLineCount, "Encountered unknown label %s at 0x%04x", token.
toAscii().constData(), mByteLocation);
mUnknownLabels[mByteLocation] = token;
value = 0;
return(ADDRESS);
}
else{
// If an address isnt allowed here, then its an error
ERROR(mLineCount, "Unexpected token \"%s\"", token.toAscii().constData
());
return(NONE);
}
}
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
}
else{
ERROR(mLineCount, "Unexpected token \"%s\"", token.toAscii().constData());
return(NONE);
}
463
464
465
466
467
1
2
3
4
5
6
7
}
/** \file console.h
* Singleton class which handles printing of messages, errors and warnings
* to the console. It contains flags which can be used to turn messages on
* and off, and keeps track of the total number of errors/warnings.
* \author Steven Bell <steven.bell@student.oc.edu>
* \date 12 December 2010
*/
126
8
9
10
11
12
13
14
15
16
17
18
19
class Console
{
public:
static Console& instance();
void setVerbose(bool verbose);
void printError(int lineNum, const char* format, ...);
void printWarning(int lineNum, const char* format, ...);
void printMessage(int lineNum, const char* format, ...);
void printVerbose(int lineNum, const char* format, ...);
void printSummary(void);
bool errorOccured(void) {return(mErrorCount > 0);}
20
21
22
23
24
25
26
private:
Console(); ///< Private singleton constructor
static Console mInstance;
int mErrorCount; ///< Number of times the error message function has been
called
int mWarningCount; ///< Number of times the warning function has been called
bool mVerbose; ///< Whether or not to print verbose stuff.
27
28
};
29
30
31
32
33
34
1
2
3
4
// Convenience macros
#define ERROR(line, ...) Console::instance().printError(line, __VA_ARGS__)
#define WARNING(line, ...) Console::instance().printWarning(line, __VA_ARGS__)
#define MESSAGE(line, ...) Console::instance().printMessage(line, __VA_ARGS__)
#define VERBOSE(line, ...) Console::instance().printVerbose(line, __VA_ARGS__)
/** \file console.cpp
* \author Steven Bell <steven.bell@student.oc.edu>
* \date 12 December 2010
*/
5
6
7
8
#include <cstdio>
#include <cstdarg>
#include "console.h"
9
10
11
12
13
14
15
16
17
Console::Console()
{
mErrorCount = 0;
mWarningCount = 0;
}
18
19
20
21
22
Console& Console::instance(void)
{
return(mInstance);
}
23
24
25
127
26
mErrorCount++;
27
28
va_list argptr;
va_start(argptr, format);
printf("%d Error: ", lineNum);
vprintf(format, argptr);
printf("\n");
va_end(argptr);
29
30
31
32
33
34
35
36
37
38
39
40
va_list argptr;
va_start(argptr, format);
printf("%d Warning: ", lineNum);
vprintf(format, argptr);
printf("\n");
va_end(argptr);
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
void Console::printSummary(void)
{
printf("\n");
printf("%d errors, %d warnings\n", mErrorCount, mWarningCount);
}
75
76
77
78
79
128
80
129
The code on the following pages is based on the test code provided on Blackboard and modied for my
assembler. The code was syntax-highlighted with Vim.
130
*
*
*
*
*
*
*
*
*
*
* Test NOP
NOP
* Test LOAD and STORE with RAM
LOAD a, #0x55 * Load immediate
STORE a, 0x2000 * Store to RAM, 0x55 expected
LOAD b, 0x2000 * Load back from RAM into another register
STORE b, 0x2001 * Store back to RAM, 0x55 expected
* Test ADD
COPY c, b * Copy from b into c
ADD c, #0x22 * Add an immediate to c
STORE c, 0x2002 * Expect 0x77
* Test flags from ADD
LOAD e, #0x5A
ADD b, a * Should give 0xAA in b
ADD e, #0xA5 * Should give 0xFF in e
JCAR end * Should not jump
STORE b, 0x2003 * Should be 0xAA
STORE e, 0x2004 * Should be 0xFF
JZERO end * Should not jump
* Test SUBtract and flags
LOAD d, #0xA9
COPY f, b * Copy b to f (should be 0xAA)
SUB f, #0x33 * Subtract 0x33, f should be 0x77
SUB d, c * Subtract c from d, d should be 0x32
JCAR end * Should not jump
JZERO end * Should not jump
STORE d, 0x2005 * Should be 0x32
STORE f, 0x2006 * Should be 0x77
JMP pass1
HALT
pass1:
COPY a, e * Copy 0xFF into a
ADD a, #0xFF * Add 0xFF, should give 0xFE with carry
STORE a, 0x2007 * Should be 0xFE
JZERO end * Should not jump
JCAR pass2 * Should jump
HALT
pass2:
ADD a, #0x01 * Should give 0xFF, no carry
JZERO end * Should not jump
JCAR end * Should not jump
STORE a, 0x2008 * Should give 0xFF
ADD a, #0x01 * Should give 0x00 with a carry
JZERO pass3 * Should jump
HALT
pass3:
STORE a, 0x2009 * Should give 0x00
SUB d, #0x21 * Should give 0x11 in d
JZERO end * Should not jump
JCAR end * Should not jump
STORE d, 0x200A * Should give 0x11
SUB d, #0x11 * Should give 0x00 in d
JCAR end * Should not jump
JZERO pass4 * Should jump
HALT
pass4:
131
132
*
*
*
*
*
*
*
*
*
*
133
pass10:
COPY c, a * Copy 0x55 into c
OR c, #0xA0 * 0b 0101 0101 OR 0b 1010 0000 gives 0xF5
STORE c, 0x2008 * Should be 0xF5
OR g, e * g = 0x30 OR e = 0x04
STORE g, 0x2009 * Should be 0x34
COPY c, h * Copy 0x00 into c
OR c, #0x00
STORE c, 0x200A * Should be 0x00
JZERO pass11 * Should jump
HALT
pass11:
OR h, b * 0x00 OR 0x00
STORE h, 0x200B * Should be 0x00
JZERO end * Should jump
HALT
end:
STORE a, 0x200C * Should be 0x55
MOVE 0x200C, 0x200D * Put 0x55 into 0x200C
LOAD b, 0x200D
HALT
134
135
12/16/10 14:40:38
0s
60.004 us
0000
Address bus
State
0001
00
Data bus
00
01
02
0002
0003
0004
0005
0006
0007
0008
2000
0009
000A
000B
000C
2000
000D
84
00
55
89
00
20
00
55
82
04
20
00
55
89
01
02
06
01
02
08
09
0B
01
02
08
09
0A
01
000E
20
02
Reset
Write
ROM enable
RAM enable
Trigger = 0 s
Page 1
12/16/10 14:40:38
63.336 us
120.008 us
Address bus
0010
2001
0011
0012
0013
0014
0015
0016
0017
0018
0019
2002
001A
001B
001C
Data bus
20
01
55
80
28
0C
08
22
89
40
20
02
77
84
10
5A
State
08
09
0B
01
02
02
14
02
08
09
0B
01
02
06
07
01
04
01
Reset
Write
ROM enable
RAM enable
Page 2
136
12/16/10 14:40:38
123.34 us
180.012 us
001E
001F
0020
0021
0022
Data bus
04
0C
10
A5
78
State
02
02
14
Address bus
03
04
01
04
0023
0024
01
01
02
10
0025
0026
19
89
11
12
0027
0028
20
01
02
08
0029
2003
03
AA
89
09
0B
01
Reset
Write
ROM enable
RAM enable
Page 3
12/16/10 14:40:38
183.348 us
240.016 us
002B
002C
002D
2004
002E
002F
0030
0031
0032
0033
0034
0035
0036
Data bus
80
20
04
FF
78
02
01
19
84
0C
A9
80
34
State
02
08
09
0B
01
02
10
11
02
06
01
02
Address bus
12
01
0037
0038
14
07
01
0039
33
02
14
Reset
Write
ROM enable
RAM enable
Page 4
137
12/16/10 14:40:38
243.352 us
303.356 us
003A
003B
003C
10
4C
78
04
01
02
03
04
003D
003E
01
01
02
10
003F
0040
0041
0042
0043
0044
0045
0046
19
78
02
01
19
89
60
20
02
10
11
02
08
11
12
Reset
Write
ROM enable
RAM enable
01
12
01
Page 5
12/16/10 14:40:38
306.688 us
363.36 us
Address bus
2005
0048
0049
004A
004B
2006
004C
Data bus
05
32
89
A0
20
06
77
78
State
09
0B
01
02
08
09
0B
01
004D
004E
00
02
10
004F
0050
52
F8
11
12
0052
0053
80
01
02
07
0054
0055
0056
0C
00
FF
02
14
01
Reset
Write
ROM enable
RAM enable
Page 6
138
12/16/10 14:40:38
366.692 us
423.364 us
0057
0058
0059
005A
2007
005B
005C
005D
005E
005F
0060
0061
0062
0063
0065
0066
89
00
20
07
FE
78
02
01
19
78
01
00
65
F8
0C
00
01
02
08
09
0B
01
02
10
11
02
10
11
12
01
02
14
01
State
12
01
Reset
Write
ROM enable
RAM enable
Page 7
12/16/10 14:40:38
426.696 us
Address bus
Data bus
State
04
483.368 us
0068
0069
006A
006B
006C
78
02
01
19
78
02
10
11
01
12
006D
006E
01
01
02
10
006F
0070
0071
0072
0073
2008
0074
0075
19
89
00
20
08
FF
0C
00
02
08
09
0B
01
02
11
12
01
Reset
Write
ROM enable
RAM enable
Page 8
139
12/16/10 14:40:38
486.704 us
546.708 us
0076
0077
0078
0079
007A
007B
007D
007E
007F
0080
2009
0081
0082
0083
0084
0085
Data bus
01
78
02
00
7D
F8
89
00
20
09
00
14
0C
21
78
02
State
14
02
10
11
12
01
02
08
09
0B
01
02
14
Address bus
04
01
04
01
02
Reset
Write
ROM enable
RAM enable
Page 9
12/16/10 14:40:38
550.04 us
606.712 us
Address bus
0087
0088
Data bus
01
19
78
State
10
11
12
0089
008A
008B
008C
008D
008E
008F
200A
0090
0091
0092
0093
19
89
60
20
0A
11
14
0C
11
78
02
08
09
0B
01
02
14
01
01
02
10
11
12
01
04
Write
ROM enable
RAM enable
01
Reset
Page 10
140
0095
Address bus
Data bus
12/16/10 14:40:38
610.044 us
01
10
State
666.716 us
0096
0097
0098
0099
009A
009B
009D
009E
009F
00A0
200B
00A1
00A2
00A3
00A4
19
78
02
00
9D
F8
89
60
20
0B
00
14
0C
33
78
02
10
11
12
01
02
08
09
0B
01
02
14
11
12
01
04
Reset
Write
ROM enable
RAM enable
Page 11
01
12/16/10 14:40:38
670.048 us
726.72 us
00A5
00A6
00A7
00A8
00A9
00AA
00AB
00AC
00AE
00AF
00B0
00B1
200C
00B2
00B3
00B4
00B5
Data bus
02
01
19
78
03
00
AE
F8
89
60
20
0C
CD
0C
14
00
78
State
02
10
11
02
10
11
12
01
02
08
09
0B
01
02
14
04
Address bus
12
01
Reset
Write
ROM enable
RAM enable
Page 12
141
12/16/10 14:40:38
733.388 us
00B5
Data bus
78
State
01
790.056 us
00B6
00B7
01
02
10
00B8
00B9
00BA
00BB
00BC
00BD
00BE
00BF
00C0
00C1
00C2
19
10
94
78
02
01
19
78
03
01
19
02
10
11
02
10
11
11
12
01
02
03
04
01
Reset
Write
ROM enable
RAM enable
12
01
Page 13
12/16/10 14:40:38
793.392 us
12
850.064 us
00C3
00C4
00C5
00C6
00C7
00C8
00C9
00CA
200D
00CB
00CC
00CD
00CE
00CF
00D0
78
01
00
C7
89
A0
20
0D
78
80
38
1C
18
A5
89
02
10
11
02
08
09
0B
01
02
02
14
01
12
01
07
01
Write
ROM enable
RAM enable
04
Reset
Page 14
142
12/16/10 14:40:38
853.396 us
910.068 us
00D0
00D1
00D2
00D3
200E
00D4
00D5
00D6
00D7
200F
00D8
00D9
00DA
00DB
00DC
00DD
89
C0
20
0E
6D
89
E0
20
0F
92
84
1C
BB
18
DC
89
02
08
09
0B
01
02
08
09
0B
01
02
06
01
02
01
State
03
04
Reset
Write
ROM enable
RAM enable
Page 15
05
12/16/10 14:40:38
913.4 us
973.404 us
00DD
00DE
00DF
00E0
2010
00E1
00E2
00E3
00E4
2011
00E5
00E6
00E7
00E8
00E9
89
C0
20
10
4F
89
E0
20
11
9F
80
04
40
04
89
02
08
09
0B
01
02
08
09
0B
01
02
01
07
01
02
03
04
01
Reset
Write
ROM enable
RAM enable
Page 16
143
00EA
1.033408 ms
00EB
20
Data bus
State
12/16/10 14:40:38
976.74 us
02
08
00EC
2012
00ED
00EE
00EF
12
FF
40
04
89
09
0B
01
02
03
00F0
00F1
20
04
01
02
08
00F2
2013
00F3
13
00
78
09
0B
01
00F4
00F5
00F6
00F7
19
78
01
02
10
11
Reset
Write
ROM enable
RAM enable
Page 17
12
12/16/10 14:40:38
1.036744 ms
1.093412 ms
Address bus
00F8
00F9
00FA
00FB
00FD
00FE
00FF
0100
0101
0102
0103
0104
2014
0105
Data bus
78
02
00
FD
F8
80
70
30
10
89
80
20
14
66
30
State
01
02
10
11
12
01
02
02
08
09
0B
01
07
01
02
03
04
01
Reset
Write
ROM enable
RAM enable
Page 18
144
12/16/10 14:40:38
1.096748 ms
Address bus
Data bus
03
State
1.15342 ms
0107
0108
0109
010A
2015
010B
010C
010D
010E
010F
0110
0111
89
80
20
15
33
80
98
38
18
89
C0
20
16
02
08
09
0B
01
02
02
08
09
04
01
07
01
02
03
04
01
Reset
Write
ROM enable
RAM enable
Page 19
12/16/10 14:40:38
1.156752 ms
1.216756 ms
2016
0113
0114
0115
0116
0117
0118
2017
Data bus
66
38
18
89
C0
20
17
CC
State
0B
01
02
02
08
09
Address bus
03
04
01
0B
0119
011A
011B
011C
011D
00
01
02
011E
F8
01
02
01
011F
00
02
13
Reset
Write
ROM enable
RAM enable
1
M2 = 1.216756 ms
Page 20
145
56.672 us
Address bus
Data bus
State
12/16/10 14:49:41
0s
0000
0001
0002
0003
0004
0005
0006
0007
0008
0009
000A
000B
000C
000D
000E
000F
84
00
55
84
04
FF
84
08
FF
84
0C
33
84
14
03
84
02
06
01
02
06
01
02
06
01
02
06
01
02
06
01
00
01
Reset
Write
ROM enable
0
1
RAM enable
Trigger = 0 s
Page 1
12/16/10 14:49:41
60.004 us
113.344 us
0011
0012
0013
0014
0015
0016
0017
0018
0019
2000
001A
001B
001C
Data bus
C0
80
70
30
10
89
80
20
00
19
30
10
89
State
06
01
02
02
08
09
0B
01
02
Address bus
07
01
02
03
04
01
03
Write
ROM enable
RAM enable
04
Reset
Page 2
146
12/16/10 14:49:41
116.676 us
173.348 us
001C
001D
001E
001F
2001
0020
0021
0022
0023
0024
0025
0026
0027
2002
Data bus
89
80
20
01
0C
80
98
38
18
89
C0
20
02
18
State
01
02
08
09
0B
01
02
02
08
09
0B
Address bus
07
01
02
03
04
01
Reset
Write
ROM enable
RAM enable
Page 3
12/16/10 14:49:41
176.68 us
230.016 us
0029
002A
002B
002C
002D
Data bus
18
89
C0
20
03
State
02
02
08
09
Address bus
03
04
01
2003
002E
30
0B
01
002F
0030
0031
0032
0033
0034
14
78
01
00
36
F8
02
10
11
12
02
03
04
01
Reset
Write
ROM enable
RAM enable
Page 4
147
12/16/10 14:49:41
233.352 us
290.024 us
0036
0037
0038
0039
003A
003B
003C
003E
003F
0040
0041
0042
0043
Data bus
30
14
78
02
00
3E
F8
38
1C
78
01
00
46
State
01
02
02
10
11
12
01
02
02
10
11
Address bus
03
04
01
Reset
Write
ROM enable
RAM enable
03
04
01
Page 5
12/16/10 14:49:41
293.356 us
346.692 us
0046
0047
0048
0049
004A
004B
004C
004E
004F
0050
0051
0052
0053
Data bus
38
1C
78
02
00
4E
F8
80
14
24
14
0F
89
State
01
02
02
10
11
12
01
02
02
14
Address bus
03
04
01
Reset
Write
ROM enable
RAM enable
07
01
04
01
Page 6
148
12/16/10 14:49:41
350.028 us
406.696 us
0054
0055
0056
2004
0057
0058
0059
005A
005B
005C
2005
005D
005E
005F
Data bus
A0
20
04
05
20
10
89
80
20
05
04
80
A4
24
State
02
08
09
0B
01
02
02
08
09
0B
01
02
Address bus
03
04
01
07
01
Reset
Write
ROM enable
RAM enable
Page 7
12/16/10 14:49:41
410.032 us
463.368 us
0061
0062
Data bus
F0
89
State
14
Address bus
04
0063
0064
20
01
02
08
0065
2006
0066
0067
0068
0069
006A
006C
006D
006E
06
00
78
02
00
6C
F8
20
28
89
09
0B
01
02
10
11
12
01
02
03
04
01
Reset
Write
ROM enable
RAM enable
Page 8
149
12/16/10 14:49:41
470.036 us
523.372 us
006F
0070
0071
2007
0072
0073
0074
0075
0076
0078
0079
007A
007B
007C
007D
Data bus
40
20
07
00
78
02
00
78
F8
80
08
2C
08
A0
89
State
02
08
09
0B
01
02
10
11
12
01
02
02
14
Address bus
07
01
04
01
Reset
Write
ROM enable
RAM enable
Page 9
12/16/10 14:49:41
526.704 us
583.376 us
007F
0080
2008
0081
0082
0083
0084
0085
0086
2009
0087
0088
0089
008A
Data bus
20
08
F5
28
98
89
C0
20
09
34
80
E8
2C
08
State
08
09
0B
01
02
02
08
09
0B
01
02
Address bus
03
04
01
07
01
02
Reset
Write
ROM enable
RAM enable
Page 10
150
12/16/10 14:49:41
586.712 us
640.048 us
008B
008C
008D
008E
008F
200A
0090
0091
0092
0093
0094
0096
0097
0098
Data bus
00
89
40
20
0A
00
78
02
00
96
F8
28
3C
89
State
14
02
08
09
0B
01
02
10
11
12
01
02
Address bus
04
01
03
04
01
Reset
Write
ROM enable
RAM enable
Page 11
12/16/10 14:49:41
643.38 us
700.052 us
009A
009B
200B
009C
009D
009E
009F
00A0
00A2
00A3
00A4
00A5
200C
00A6
Data bus
20
0B
00
78
02
00
A2
F8
89
00
20
0C
55
F8
State
08
09
0B
01
02
10
11
12
01
02
08
09
0B
01
Address bus
00A7
00A8
00
02
13
Reset
Write
ROM enable
RAM enable
1
M2 = 700.052 us
Page 12
151