Case Study: RCA 1802 Processor
Demonstrating complex behavioral modeling in Simic.
Overview
The RCA 1802 (COSMAC) is a classic 8-bit microprocessor. Modeling its internal logic at the gate level would be prohibitively complex. Instead, we provide a Behavioral Model that implements its instruction set.
This case study demonstrates how behavioral modeling enables simulation of complete processor systems by implementing functional behavior at the instruction level rather than transistor or gate level.
Design Approach
Why Behavioral Modeling for Microprocessors?
Microprocessors are ideal candidates for behavioral modeling for several reasons:
- Complexity: Modern processors contain millions of transistors. Gate-level simulation would be impractically slow for system-level verification.
- Abstraction Match: System designers care about instruction-level behavior (what the program does), not internal data paths.
- Datasheet Specification: Processor behavior is precisely defined by the instruction set architecture (ISA), making it straightforward to implement functionally.
- Simulation Speed: Executing instructions behaviorally is orders of magnitude faster than propagating signals through gate-level logic.
RCA 1802 Characteristics
The CDP1802 has several features that make it suitable for behavioral modeling:
- RISC-like Architecture: Simple instruction set with 91 instructions
- Register File: 16 general-purpose 16-bit registers (R0-RF)
- Accumulator: 8-bit D register for ALU operations
- Memory Interface: 8-bit data bus with external memory addressing
- I/O Flags: Four external flag inputs (EF1-EF4)
- Control Signals: State code outputs (SC0, SC1) indicate fetch/execute cycles
SNL Definition
To use the model, you declare it as a behavioral type in your .net file:
type=cdp1802 p1 p2 p3 i=mclk,clear,wait,pause,irq,ef1,ef2,ef3,ef4,d[0:7] $
o=ma[0:7],q,sc0,sc1,tpa,tpb,mrd,n0,n1,n2,ceo,d[0:7] $
composition=behavioral
Pin Description
| Pin | Type | Description |
|---|---|---|
mclk |
Input | Master clock - drives instruction execution |
clear |
Input | Reset signal - initializes processor state |
wait, pause |
Input | Execution control - halt or single-step |
ef1-ef4 |
Input | External flags - read by branch instructions |
d[0:7] |
Bidir | Data bus - memory and I/O interface |
ma[0:7] |
Output | Memory address (low byte) |
q |
Output | Q register output bit |
sc0, sc1 |
Output | State code - indicates fetch vs execute cycle |
tpa, tpb |
Output | Timing pulses for external logic |
mrd |
Output | Memory read strobe |
n0-n2 |
Output | Instruction type indicators |
d[0:7] for the data bus. These must be declared
with the %declare statement to define their print radix and width.
Behavioral Implementation
Internal State Management
The 1802 model maintains internal state that persists between evaluations. This state captures the processor's architectural registers and control state:
Architectural State
- PC (Program Counter): 16-bit address of next instruction to fetch
- R[0:15]: 16-bit general-purpose register file
- D: 8-bit accumulator for ALU operations
- DF: Data flag (carry/borrow flag for arithmetic)
- P: 4-bit register pointer designating PC register
- X: 4-bit register pointer designating data pointer
- T: 8-bit temporary register
- IE: Interrupt enable flag
- Q: 1-bit output flip-flop
Execution Cycle State
- Machine State: Tracks fetch vs execute phase
- Instruction Register (I): Currently executing opcode
- Cycle Counter: Timing within multi-cycle instructions
Instruction Execution Model
On each mclk rising edge (assuming no WAIT/PAUSE), the evaluation
routine performs these steps:
- Fetch: Read instruction byte from memory at address R[P]
opcode = memory[R[P]] R[P] = R[P] + 1 // Increment PC - Decode: Determine instruction type from opcode high nibble
instr_type = (opcode >> 4) & 0x0F register_num = opcode & 0x0F - Execute: Perform instruction-specific operation
switch (instr_type) { case 0x3: // BR, BZ, BDF, etc. (branch instructions) offset = memory[R[P]] R[P] = (R[P] & 0xFF00) | offset break case 0x8: // GLO (Get Low byte of register) D = R[register_num] & 0xFF break // ... 91 instructions total ... } - Update Outputs: Set state code, timing pulses, memory strobes
Key Implementation Patterns
Memory Interface Handling
The bidirectional data bus requires careful state management:
// During memory read cycles:
if (cycle == FETCH || instr_type == LOAD) {
// Drive MRD signal, read from d[0:7]
outputs[MRD_PIN] = LEVEL_ONE
data_byte = read_data_bus(inputs)
}
// During memory write cycles:
if (instr_type == STORE) {
// Drive data bus with value to write
drive_data_bus(outputs, value)
}
Instruction Timing
Most instructions complete in 2 machine cycles (16 clock periods), but some multi-byte instructions take 3 cycles. The model tracks cycle count per instruction to accurately model timing:
cycle_count = instruction_cycles[opcode]
// Update state code outputs based on cycle phase
sc0 = (current_cycle == 0) ? LEVEL_ZERO : LEVEL_ONE
sc1 = (current_cycle == 1) ? LEVEL_ONE : LEVEL_ZERO
System Integration
Building a Complete System
The CDP1802 behavioral model integrates with other circuit components to create a complete computer system:
!LOGICAL
* Top-level system with 1802 CPU
type=computer_system i=clock,reset o=output_port[7:0]
* CPU (behavioral model)
p=cpu t=cdp1802 i=clock,reset,wait_n,pause_n,irq,ef1,ef2,ef3,ef4 $
b=data_bus o=addr_bus,q,sc0,sc1,tpa,tpb,mrd composition=behavioral
* ROM for program storage (4KB)
p=rom t=rom i=cs,re,we,ae,addr[11:0] b=data_bus size=4096
* RAM for data storage (1KB)
p=ram t=rama i=cs,re,we,clock,addr[9:0],data_in[7:0] o=data[7:0]
* Address decoder logic (determines ROM vs RAM access)
p=decode t=address_decoder i=addr_bus[15:12] o=rom_cs,ram_cs
* I/O peripherals connected to EF flags
p=uart t=uart16550 i=clock,data_in b=data_bus o=ef1_ready
p=timer t=timer8bit i=clock,reset o=ef2_tick
Memory Initialization
Load the processor's program into ROM using SIMIC's memory initialization directives:
>>: define file=computer_system
>>: get type=computer_system
>>: load rom file=program.hex format=intel
Simulation and Debugging
The behavioral model's state code outputs (SC0, SC1) help track execution progress:
>>: simulate
>>: print cpu.sc0,cpu.sc1,cpu.ma # Monitor fetch/execute and address
>>: break cpu.ma=0x0100 # Break when PC reaches address 0x0100
>>: continue
Benefits of Behavioral Modeling
Simulation Speed
Executes instructions in nanoseconds of simulation time, compared to milliseconds required for gate-level logic. Enables running complete firmware through simulation.
Functional Accuracy
Implements exact instruction cycle behavior as defined in the datasheet. All 91 instructions produce architecturally correct results verified against hardware.
System-Level Verification
Validates firmware running on the processor in the context of the complete system, including memory, peripherals, and I/O devices.
Mixed Abstraction
Combine behavioral CPU with gate-level peripherals. Critical custom logic can be verified at gate level while processor remains fast behavioral model.