(3)Verilogに基づくRISC CPUテスト


これは、上述したPIC 16 C 57機能設計に基づくCPUシミュレーションテストであり、Vivadoソフトウェアに基づくRTL Simulationモジュールは、アセンブラプログラムの複数のテストプログラムのシミュレーション検証により、その設計の正しさを確認している。


アセンブラは次のようになります.
INDF	equ	    H'00'	; Magic register that uses INDIRECT register
TIMER0	equ	    H'01'	; Timer register
STATUS  equ     H'03'	; STATUS register F3
FSR	    equ	    H'04'	; INDIRECT Pointer Register
porta   equ     H'05'	; I/O register F5
portb   equ     H'06'	; I/O register F6
portc   equ     H'07'	; I/O register F7
x       equ     H'0A'   ; Our general variable
y       equ     H'0B'   ; Another variable..
CARRY   equ     H'00'	; Carry bit in STATUS register
ZERO    equ     H'02'	; Zero bit in STATUS register
W	    equ	    H'00'	; W indicator for many instruction (not the address!)

; These are some locations used for the Bank and Indirection tests
varb0	equ	H'1A'	; This is in upper part of Bank0
varb1	equ	H'3A'	; This is in upper part of Bank1
varb2	equ	H'5A'	; This is in upper part of Bank2
varb3	equ	H'7A'	; This is in upper part of Bank3

; ************  Start Up Code  **************
start:
; Set up TRIS registers
	movlw	H'ff'
	tris	porta		; PORTA is Input
	clrw
	tris	portb		; PORTB is Output
	tris	portc		; PORTC is Output
	movwf	portb		; PORTB <= 00

; Start at begining...
	goto	test1
	
; *** TEST1 ***
; Test increment and decrement
test1:
	movlw	H'FD'		; W <= FD
	movwf	x			; X <= FD
	incf	x, f		; X <= FE
	incf	x, f		; X <= FF
	incf	x, f		; X <= 00
	incf	x, f		; X <= 01
	decf	x, f		; X <= 00
	decf	x, f		; X <= FF
	decf	x, f		; X <= FE
	movf	x, W		; W <= FE
	xorlw	H'FE'		; Does W == FE?
	btfss	STATUS, ZERO
	goto	fail1
	goto	pass1
fail1	movlw	H'F1'
	movwf	portb		; PORTB <= F1
	goto	test2	
pass1	movlw	H'01'
	movwf	portb		; PORTB <= 01
	goto	test2	

; *** TEST2 ***
; Test Add and Subtract
test2:
	clrf	x		; x <= 0
	movlw	H'A0'		; w <= A0
	addwf	x, f		; x <= A0
	addwf	x, f		; x <= 40
	btfss	STATUS, CARRY	; carry should be set, if not then FAIL
	goto	fail2
	addwf	x, f		; x <= E0
	btfsc	STATUS, CARRY	; carry should be clear, if not then FAIL
	goto	fail2
	movf	x, W		; W <= E0
	xorlw	H'E0'		; Does W == E0?
	btfss	STATUS, ZERO
	goto	fail2

	movlw	H'30'
	subwf	x, f		; x <= B0
	subwf	x, f		; x <= 80
	btfss	STATUS, CARRY	; borrow should be clear, if not then FAIL
	goto	fail2
	subwf	x, f		; x <= 50
	subwf	x, f		; x <= 20
	subwf	x, f		; x <= F0
	btfsc	STATUS, CARRY	; borrow should be set, if not then FAIL
	goto	fail2
	movf	x, W		; W <= F0
	xorlw	H'F0'		; Does W == F0?
	btfss	STATUS, ZERO
	goto	fail2
	goto	pass2
fail2	movlw	H'F2'
	movwf	portb		; PORTB <= F2
	goto	test3	
pass2	movlw	H'02'
	movwf	portb		; PORTB <= 02
	goto	test3	

; *** TEST3 ***
; Test Rotates, start with rrf
test3:	bsf	STATUS, CARRY	; CARRY <= 1
	movlw	H'A0'		; w <= A0
	movwf	x		; x <= A0 (10100000)
	rrf	x, f		; x <= D0 (11010000)
	bsf	STATUS, CARRY	; CARRY <= 1
	rrf	x, f		; x <= E8 (11101000)
	bcf	STATUS, CARRY	; CARRY <= 0
	rrf	x, f		; x <= 74 (01110100)
	bcf	STATUS, CARRY	; CARRY <= 0
	rrf	x, f		; x <= 3A (00111010)
	movf	x, W		; W <= 3A 
	xorlw	H'3A'		; Does W == 3A ?
	btfss	STATUS, ZERO
	goto	fail3
	; Do same sort of thing using rlf
	bsf	STATUS, CARRY	; CARRY <= 1
	movlw	H'A0'		; w <= A0
	movwf	x		; x <= A0 (10100000)
	rlf	x, f		; x <= 41 (01000001)
	bsf	STATUS, CARRY	; CARRY <= 1
	rlf	x, f		; x <= 83 (10000011)
	bcf	STATUS, CARRY	; CARRY <= 0
	rlf	x, f		; x <= 06 (00000110)
	bcf	STATUS, CARRY	; CARRY <= 0
	rlf	x, f		; x <= 0C (00001100)
	movf	x, W		; W <= 0C 
	xorlw	H'0C'		; Does W == 0C ?
	btfss	STATUS, ZERO
	goto	fail3
	goto	pass3
fail3	movlw	H'F3'
	movwf	portb		; PORTB <= F3
	goto	test4	
pass3	movlw	H'03'
	movwf	portb		; PORTB <= 03
	goto	test4	

; *** TEST4 ***
; Test TIMER0
;
; Option is:
;     7       6       5       4       3       2       1       0
; +---------------------------------------------------------------+
; |   x   |   x   |  T0CS |  T0SE |  PSA  |  PS2  |  PS1  |  PS0  |
; +---------------------------------------------------------------+
;    T0CS  -  0: Use chip clock as source, 1: use external pin
;    T0SE  -  Invert input when using external source
;     PSA  -  Set to '0' to use prescaler
; PS2:PS0  -  Divide by 0 up to 7
;
; To use maximum prescaler using internal clock, program
; OPTION register to:
;
; 00000111 = 7
;
test4:	movlw	H'07'		; Set TIMER0 prescaler to ...
	option
	movlw	H'FF'		; W <= FF
	movwf	x		; x <= FF
	clrf	TIMER0
test4loop:
	decf	x, f
	btfss	STATUS, ZERO
	goto	test4loop

	movf	TIMER0, W
	xorlw	H'03'		; Does W == ?
	btfss	STATUS, ZERO
	goto	fail4
	goto	pass4
fail4	movlw	H'F4'
	movwf	portb		; PORTB <= F4
	goto	test5	
pass4	movlw	H'04'
	movwf	portb		; PORTB <= 04
	goto	test5	

; *** TEST5 ***
; Test various logic instructions
test5:	clrf	x		; x <= 00
	movlw	B'00000101'	; W <= 00000101
	iorwf	x, f		; x <= 00000101
	comf	x, f		; x <= 11111010
	movlw	B'1110011'	; W <= 01110011
	andwf	x, f		; x <= 01110010
	movlw	B'11110000'	; W <= 11110000
	xorwf	x, f		; x <= 10000010
	swapf	x, f		; x <= 00101000
	
	; Check results up to now
	movfw	x		; W <= 00101000
	xorlw	B'00101000'	; Does W == 00101000
	btfss	STATUS, ZERO
	goto	fail5

	; Check some bit tests and clears.  Invert
	; all the bits of X which is now: 00101000
	bsf	x, 7
	bsf	x, 6
	bcf	x, 5
	bsf	x, 4
	bcf	x, 3
	bsf	x, 2
	bsf	x, 1
	bsf	x, 0		; x <= 11010111 
	movfw	x		; W <= 11010111
	xorlw	B'11010111'	; Does W == 11010111
	btfss	STATUS, ZERO
	goto	fail5
	goto	pass5

fail5	movlw	H'F5'
	movwf	portb		; PORTB <= F5
	goto	test6
pass5	movlw	H'05'
	movwf	portb		; PORTB <= 05
	goto	test6

; *** TEST6 ***
; Test subroutines
test6:	clrf	x		; x <= 00
	call	sub6c		; x <= 2
	call	sub6c		; x <= 4
	call	sub6c		; x <= 6
	goto	cont6
	
sub6a:	movlw	5		; ** ADD 5 TO X
	addwf	x, f
	retlw	0
sub6b:	movlw	3		; ** SUB 3 FROM X
	subwf	x, f
	retlw	0
sub6c:	call sub6a		; ** ADD 2 TO X (by call others)
	call sub6b		;
	retlw	0

cont6:	movfw	x		; W <= 6
	xorlw	6		; Does W == 6
	btfss	STATUS, ZERO
	goto	fail6
	goto	pass6

fail6	movlw	H'F6'
	movwf	portb		; PORTB <= F6
	goto	test7
pass6	movlw	H'06'
	movwf	portb		; PORTB <= 06
	goto	test7
	
; *** TEST7 ***
; Test Register File Banks and address mapping, and Indirect Addressing.
;
; Write the values 1,2,3 and 4 into 4 different
; registers in each of the 4 banks.  Then, go back and verify.
; This will test bank logic and indirect addressing.
;

test7:	movlw	1		; W <= 1
	movwf	x		; X <= 1

	; Point to a location in upper part of Bank #0
	movlw	varb0	; Get Address
	movwf	FSR	; Set index register
	movf	x,W	; Get the 'x' value
	movwf	INDF	; Write using index
	incf	x,f	; Increment the counter

	; Point to a location in upper part of Bank #1
	movlw	varb1	; Get Address
	movwf	FSR	; Set index register
	movf	x,W	; Get the 'x' value
	movwf	INDF	; Write using index
	incf	x,f	; Increment the counter

	; Point to a location in upper part of Bank #2
	movlw	varb2	; Get Address
	movwf	FSR	; Set index register
	movf	x,W	; Get the 'x' value
	movwf	INDF	; Write using index
	incf	x,f	; Increment the counter

	; Point to a location in upper part of Bank #3
	movlw	varb3	; Get Address
	movwf	FSR	; Set index register
	movf	x,W	; Get the 'x' value
	movwf	INDF	; Write using index
	incf	x,f	; Increment the counter

	; OK.  Go back and read each count and output to PORTB
	movlw	varb0		; Get Address
	movwf	FSR		; Set index register
	movf	INDF,W		; Retrieve the 'x' value to W
	xorlw	H'01'		; Should be 1
	btfss	STATUS, ZERO	; IF yes, keep going
	goto	fail7
	movlw	varb1		; Get Address
	movwf	FSR		; Set index register
	movf	INDF,W		; Retrieve the 'x' value to W
	xorlw	H'02'		; Should be 2
	btfss	STATUS, ZERO	; IF yes, keep going
	goto	fail7
	movlw	varb2		; Get Address
	movwf	FSR		; Set index register
	movf	INDF,W		; Retrieve the 'x' value to W
	xorlw	H'03'		; Should be 3
	btfss	STATUS, ZERO	; IF yes, keep going
	goto	fail7
	movlw	varb3		; Get Address
	movwf	FSR		; Set index register
	movf	INDF,W		; Retrieve the 'x' value to W
	xorlw	H'04'		; Should be 4
	btfss	STATUS, ZERO	; IF yes, keep going
	goto	fail7

	goto	pass7

fail7	movlw	0F7h
	movwf	portb		; PORTB <= F7
	goto	test8
pass7	movlw	007h
	movwf	portb		; PORTB <= 07
	goto	test8

; *** TEST8 ***
; Quick test of PORTA input with PORTC
;
; Expect the repeating patter of H'55' and H'AA' on PORTA.
; Those inputs should remain on input for at least a dozen cycles.
; Code waits until both values are seen.  Also use TIMER0 so
; that we do not hang.  Timeout if nothing is seen after, say, about
; 64 cycles.
	
test8:	movlw	H'07'		; Set TIMER0 prescaler to ...
	option
	clrf	TIMER0

	; Look for H'55' first...
test8scan1:
	movf	porta, W	; Read PORTA
	xorlw	H'55'		; Is it H'55'?
	btfsc	STATUS, ZERO
	goto	test8scan2	; Saw the H'55'!
	movf	TIMER0,W	; Check the timer
	xorlw	H'02'
	btfsc	STATUS, ZERO
	goto	fail8		; Timeout  :-(
	goto	test8scan1	; Keep scanning

	; Now look for H'AA'...
test8scan2:
	movf	porta, W	; Read PORTA
	xorlw	H'AA'		; Is it H'AA'?
	btfsc	STATUS, ZERO
	goto	pass8		; Saw the H'AA'!
	movf	TIMER0,W	; Check the timer
	xorlw	H'04'
	btfsc	STATUS, ZERO
	goto	fail8		; Timeout  :-(
	goto	test8scan2	; Keep looking

fail8	movlw	H'F8'
	movwf	portb		; PORTB <= F8
	goto	test9
pass8	movlw	H'08'
	movwf	portb		; PORTB <= 08
	goto	test9

test9:
done:	goto	done		; Spin forever..
	
; *** End of main code, place start vector ***
        org     D'2047'
        goto    start
    END

命令プログラムは次のようになります.
@000 CFF
@001 005
@002 040
@003 006
@004 007
@005 026
@006 A07
@007 CFD
@008 02A
@009 2AA
@00A 2AA
@00B 2AA
@00C 2AA
@00D 0EA
@00E 0EA
@00F 0EA
@010 20A
@011 FFE
@012 743
@013 A15
@014 A18
@015 CF1
@016 026
@017 A1B
@018 C01
@019 026
@01A A1B
@01B 06A
@01C CA0
@01D 1EA
@01E 1EA
@01F 703
@020 A37
@021 1EA
@022 603
@023 A37
@024 20A
@025 FE0
@026 743
@027 A37
@028 C30
@029 0AA
@02A 0AA
@02B 703
@02C A37
@02D 0AA
@02E 0AA
@02F 0AA
@030 603
@031 A37
@032 20A
@033 FF0
@034 743
@035 A37
@036 A3A
@037 CF2
@038 026
@039 A3D
@03A C02
@03B 026
@03C A3D
@03D 503
@03E CA0
@03F 02A
@040 32A
@041 503
@042 32A
@043 403
@044 32A
@045 403
@046 32A
@047 20A
@048 F3A
@049 743
@04A A5A
@04B 503
@04C CA0
@04D 02A
@04E 36A
@04F 503
@050 36A
@051 403
@052 36A
@053 403
@054 36A
@055 20A
@056 F0C
@057 743
@058 A5A
@059 A5D
@05A CF3
@05B 026
@05C A60
@05D C03
@05E 026
@05F A60
@060 C07
@061 002
@062 CFF
@063 02A
@064 061
@065 0EA
@066 743
@067 A65
@068 201
@069 F03
@06A 743
@06B A6D
@06C A70
@06D CF4
@06E 026
@06F A73
@070 C04
@071 026
@072 A73
@073 06A
@074 C05
@075 12A
@076 26A
@077 C73
@078 16A
@079 CF0
@07A 1AA
@07B 3AA
@07C 20A
@07D F28
@07E 743
@07F A8D
@080 5EA
@081 5CA
@082 4AA
@083 58A
@084 46A
@085 54A
@086 52A
@087 50A
@088 20A
@089 FD7
@08A 743
@08B A8D
@08C A90
@08D CF5
@08E 026
@08F A93
@090 C05
@091 026
@092 A93
@093 06A
@094 99E
@095 99E
@096 99E
@097 AA1
@098 C05
@099 1EA
@09A 800
@09B C03
@09C 0AA
@09D 800
@09E 998
@09F 99B
@0A0 800
@0A1 20A
@0A2 F06
@0A3 743
@0A4 AA6
@0A5 AA9
@0A6 CF6
@0A7 026
@0A8 AAC
@0A9 C06
@0AA 026
@0AB AAC
@0AC C01
@0AD 02A
@0AE C1A
@0AF 024
@0B0 20A
@0B1 020
@0B2 2AA
@0B3 C3A
@0B4 024
@0B5 20A
@0B6 020
@0B7 2AA
@0B8 C5A
@0B9 024
@0BA 20A
@0BB 020
@0BC 2AA
@0BD C7A
@0BE 024
@0BF 20A
@0C0 020
@0C1 2AA
@0C2 C1A
@0C3 024
@0C4 200
@0C5 F01
@0C6 743
@0C7 ADB
@0C8 C3A
@0C9 024
@0CA 200
@0CB F02
@0CC 743
@0CD ADB
@0CE C5A
@0CF 024
@0D0 200
@0D1 F03
@0D2 743
@0D3 ADB
@0D4 C7A
@0D5 024
@0D6 200
@0D7 F04
@0D8 743
@0D9 ADB
@0DA ADE
@0DB CF7
@0DC 026
@0DD AE1
@0DE C07
@0DF 026
@0E0 AE1
@0E1 C07
@0E2 002
@0E3 061
@0E4 205
@0E5 F55
@0E6 643
@0E7 AED
@0E8 201
@0E9 F02
@0EA 643
@0EB AF6
@0EC AE4
@0ED 205
@0EE FAA
@0EF 643
@0F0 AF9
@0F1 201
@0F2 F04
@0F3 643
@0F4 AF6
@0F5 AED
@0F6 CF8
@0F7 026
@0F8 AFC
@0F9 C08
@0FA 026
@0FB AFC
@0FC AFC
@7FF A00

シミュレーションプログラムは次のようになります.
`timescale 1ns / 10ps

module TB;

// For 50Mhz, Period is 20ns, So Set CLKHI to 10 and CLKLO to 10
parameter CLKHI = 10;
parameter CLKLO = 10;

parameter NOP	   = 1;
parameter MOVWF	= 2;
parameter CLRW	   = 3;
parameter CLRF	   = 4;
parameter SUBWF	= 5;
parameter DECF	   = 6;
parameter IORWF	= 7;
parameter ANDWF	= 8;
parameter XORWF	= 9;
parameter ADDWF	= 10;
parameter MOVF	   = 11;
parameter COMF	   = 12;
parameter INCF	   = 13;
parameter DECFSZ  = 14;
parameter RRF	   = 15;
parameter RLF	   = 16;
parameter SWAPF	= 17;
parameter INCFSZ  = 18;
parameter BCF	   = 19;
parameter BSF	   = 20;
parameter BTFSC	= 21;
parameter BTFSS	= 22;
parameter OPTION  = 23;
parameter SLEEP	= 24;
parameter CLRWDT  = 25;
parameter TRIS	   = 26;
parameter RETLW	= 27;
parameter CALL	   = 28;
parameter GOTO	   = 29;
parameter MOVLW	= 30;
parameter IORLW	= 31;
parameter ANDLW	= 32;
parameter XORLW	= 33;

// Basic Interface to the PI CCPU
reg		clk;
reg		reset;

// Declare I/O Port connections
reg  [7:0]	porta; // INPUT
wire [7:0]	portb; // OUTPUT
wire [7:0]	portc; // OUTPUT

// Debug Signals
wire [11:0] debuginst;
wire [7:0]  debugdbus;
wire [7:0]  debugsbus;
wire [7:0]  debugw;

// Declare ROM and rom signals
wire [10:0]	inst_addr;
wire [11:0]	inst_data;


wire [7:0] fsr = CPU.fsr;
wire [7:0] status = CPU.status;

wire [7:0] debugmem0  = CPU.regs.dram.mem[0];
wire [7:0] debugmem1  = CPU.regs.dram.mem[1];
wire [7:0] debugmem2  = CPU.regs.dram.mem[2];
wire [7:0] debugmem3  = CPU.regs.dram.mem[3];

wire [7:0] debugmem9  = CPU.regs.dram.mem[9];
wire [7:0] debugmem10  = CPU.regs.dram.mem[10];
wire [7:0] debugmem11  = CPU.regs.dram.mem[11];
wire [7:0] debugmem12  = CPU.regs.dram.mem[12];
// Instantiate one CPU to be tested.
CPU CPU(
   .clk		 (clk),
   .rst_n	 (reset),
   .inst_addr(inst_addr),
   .inst_data(inst_data),
   .portain	 (porta),
   .portbout (portb),
   .portcout (portc),
   .debuginst(debuginst),
   .debugdbus(debugdbus),
   .debugsbus(debugsbus),
   .debugw   (debugw)
);

// Instantiate the Program RAM.
pram pram (
   .clk		(clk),
   .address	(inst_addr),
   .we		(1'b0),			// This testbench doesn't allow writing to PRAM
   .din		(12'b000000000000),	// This testbench doesn't allow writing to PRAM
   .dout	   (inst_data)
);

initial begin
   $display ("Free-RISC8. Version 1.0");
   basic;
end

event ENDSIM;

// Capture some data
task capture_data;
   begin
      $dumpfile ("risc8.vcd");
      $dumpvars (0, TB);
      @(ENDSIM);
      $dumpflush;
   end
endtask

// Reset
task reset_pic;
   begin
      reset = 0;
      #200;
      reset = 1;
      $display ("End RESET.");
   end
endtask
  
// Drive the clock input
task drive_clock;
   begin
      clk  = 0;
      forever begin
         #(CLKLO) clk = 1;
         #(CLKHI) clk = 0;
      end
   end
endtask

// *************  BASIC CONFIDENCE Test Tasks **************
//
// BASIC CONFIDENCE Test.
//
// This task will fork off all the other necessary tasks to cause reset, drive the clock, etc. etc.
//
// 
task basic;
   
   integer  num_outputs;
   integer  num_matches;
   integer  num_mismatches;
   
   begin
      $display ("Free-RISC8 1.0.  This is the BASIC CONFIDENCE TEST.");
      #1;
   
      $display ("Loading program memory with %s", "basic.rom");
      $readmemh ("C:/Users/HOWARD/Desktop/Microchip_16C57/basic.rom", pram.mem);

      fork
         // Capture data
         capture_data;
         
         // Run the clock
         drive_clock;
         
         // Do a reset
         reset_pic;
         
         // Monitor the number of cycles and set an absolute maximum number of cycles.
         monitor_cycles (5000);
         
         // More specific monitors
         //monitor_inst;
         monitor_portb;
         monitor_portc;
         
         // Drive PORTA with a toggling pattern.  This is for one of the subtests.
         //
         basic_drive_porta;
         
         // Monitor the counting pattern on PORTB.  This is our self-checking scheme for the test.
         // 
         begin
            // 
            num_outputs = 9;  // Expect exactly 7 changes on the PORTB (0..6).
            
            // Call the following task which will watch PORTB for the patterns.
            //
            basic_monitor_output_signature (num_outputs, num_matches, num_mismatches);
            
            // See how we did!
            repeat (2) @(posedge clk);
            $display ("Done monitoring for output signature.  %0d Matches, %0d Mismatches.", num_matches, num_mismatches);
            if (num_matches == num_outputs && num_mismatches == 0) begin
               $display ("SUCCESS.");
            end
            else begin
               $display ("Test FAILED!!");
            end
            
            // We are done.  Throw the ENDSIM event.
            ->ENDSIM;
            #0;
            $finish;
         end
         
         // Catch end of simulation event due to max number of cycles or pattern from PIC code.
         begin
            @(ENDSIM);  // Catch the event.
            
            // Got it!
            $display ("End of simulation signalled.  Killing simulation in a moment.");
            #0; // Let anything else see this event...
            $finish;
         end
      join
   end
endtask

// Monitor PORTB for an incrementing pattern.  This is how we are doing our self-checking.
// A good run will count from ZERO up to some number.
//
task basic_monitor_output_signature;
   input   num_outputs;
   output  num_matches;
   output  num_mismatches;
   
   integer  num_outputs;
   integer  num_matches;
   integer  num_mismatches;
   
   integer      i;
   reg [7:0]    expected_output;
   begin
      num_matches    = 0;
      num_mismatches = 0;
      
      expected_output = 8'h00;
      
      i = 0;
      while (i < num_outputs) begin
         // Wait for any change on output port B.
         @(portb);
         #1;  // Wait for a moment for any wiggling on different 
              // bits to seetle out, just in case there's any gate-level going on..
         if (portb == expected_output) begin
            $display ("MONITOR_OUTPUT_SIGNATURE: Expected output observed on PORTB: %h", portb);
            num_matches = num_matches + 1;
         end
         else begin
            $display ("MONITOR_OUTPUT_SIGNATURE: Unexpected output on PORTB: %h", portb);
            num_mismatches = num_mismatches + 1;
         end
            
         expected_output = expected_output + 1;
         i = i + 1;
      end
   end
endtask

task basic_drive_porta;
   begin
      forever begin
         porta = 8'h55;
         repeat (32) @(posedge clk);
         porta = 8'hAA;
         repeat (32) @(posedge clk);
      end
   end
endtask

// *****************************  Generic Tasks  **************************  //

// CYCLE monitor and end-of-simulation checker.
//
task monitor_cycles;
   input max_cycles;
   
   integer max_cycles;
   integer cycles;
   begin
      cycles = 0;
      fork
         // Count cycles.
         forever begin
            @(posedge clk);
            cycles = cycles + 1;
         end
         
         // Watch for max cycles.  If we detect max cycles then throw our testbench ENDSIM event.
         //
         begin
            wait (cycles == max_cycles);
            $display ("MAXIMUM CYCLES EXCEEDED!");
            ->ENDSIM;
         end
      join
   end
endtask

// Generic Debug Display stuff.
//
task monitor_rom;
   begin
      forever begin
         @(negedge clk);
         $display ("ROM Address = %h, Data = %h", inst_addr, inst_data);
      end
   end
endtask

task monitor_porta;
   reg [7:0] last_porta;
   begin
      forever begin
         @(negedge clk);
         if (last_porta !== porta) begin
            $display ("porta changes to: %h", porta);
            last_porta = porta;
         end
      end
   end         
endtask

task monitor_portb;
   reg [7:0] last_portb;
   begin
      forever begin
         @(negedge clk);
         if (last_portb !== portb) begin
            $display ("MONITOR_PORTB: Port B changes to: %h", portb);
            last_portb = portb;
         end
      end
   end
endtask

task monitor_portc;
   reg [7:0] last_portc;
   begin
      forever begin
         @(negedge clk);
         if (last_portc !== portc) begin
            $display ("MONITOR_PORTC: Port C changes to: %h", portc);
            last_portc = portc;
         end
      end
   end
endtask

endmodule

このRISC CPUのシミュレーションにより、CPUの具体的な実装の流れをより明確に知ることができる.全体の工事については、前のブログを参考にして、私のリソースで無料でダウンロードします.