single_producer.uc

来自「这是一个intel网络处理器ixp24xx系列中微码例子。用汇编写的。可以参考一」· UC 代码 · 共 171 行

UC
171
字号
;------------------------------------------------------------------------------------
;                                                                      
;                   I N T E L   P R O P R I E T A R Y                   
;                                                                       
;      COPYRIGHT (c)  2001 BY  INTEL  CORPORATION.  ALL RIGHTS          
;      RESERVED.   NO  PART  OF THIS PROGRAM  OR  PUBLICATION  MAY      
;      BE  REPRODUCED,   TRANSMITTED,   TRANSCRIBED,   STORED  IN  A    
;      RETRIEVAL SYSTEM, OR TRANSLATED INTO ANY LANGUAGE OR COMPUTER    
;      LANGUAGE IN ANY FORM OR BY ANY MEANS, ELECTRONIC, MECHANICAL,    
;      MAGNETIC,  OPTICAL,  CHEMICAL, MANUAL, OR OTHERWISE,  WITHOUT    
;      THE PRIOR WRITTEN PERMISSION OF :                                
;                                                                       
;                         INTEL  CORPORATION                            
;                                                                      
;                      2200 MISSION COLLEGE BLVD                        
;                                                                       
;                SANTA  CLARA,  CALIFORNIA  95052-8119                  
;                                                                       
;------------------------------------------------------------------------------------

// File 			: single_producer.uc
//
// Description 	:
// This example illustrates how to use scratch rings by showing a single producer - single 
// consumer ring. ME 0 is the producer and produces(puts) one word (4 bytes) at a 
// time on to the ring. ME 1 is the consumer which gets one word at a time. The important
// thing to note here is that before producing, producer should always check if the ring
// is full and the consumer, before consuming, should always check if the ring is empty.
// Code for ME 1 can be found in consumer.uc
//
// Psuedo Code
// 1. Initialise Scratch Ring. 
//	  Scratch ring is initialised at address 0x1000. The size of the ring is set 
//    to 128 entries. Init the head and tail to 0.
// 2. Signal the consumer. (telling that we are ready to produce)
// 3. Start producing onto the ring

#include "scratchring.h"
#include "sig_macros.uc"



///////////////////////////////////////////////////////////////////////////////
// init_scratch_ring
//	 	Description: 
//		Initialise and setup scratch ring. Ring is setup at address specified by
//		SCRATCH_RING_BASE, ring number is specified by RING_NUMBER and the size
//		of the ring as specifed by RING_SIZE_128(all are defined in scratchring.h).
// 		
//		For this example the ring is initialised at base address 0x1000, ring number 
//		is 0, and ring size is 128.
//
//	 	Outputs:
//			None
//
//		Inputs:
//			RBASE			The base address of the ring in scratch memory. Should
//							aligned on a 4 byte boundary. This should be constant.
//			RSIZE			The size of the ring. Either 128, 256, 512 or 1024. This
//							should be a constant.
//			RING			Ring number (0-15). This should be a constant.
//		
//		Size:   			8 instructions
//	
//
#macro	init_scratch_ring[RBASE, RSIZE, RING]

.begin 	

.sig 	cw1, cw2, cw3								; signals used in cap[write...]
.reg	$_rhead, $_rtail, $_rbase, _base
 
// These define_eval are required. Otherwise the caller cannot have spaces
// in between parameters like init[a, b, c].

#define_eval RN		RING
#define_eval RS		RSIZE
#define_eval RB		RBASE

	immed[$_rhead, 0x0]								; Initialise ring head to 0
	immed[$_rtail, 0x0]								; Initialise ring tail to 0;
	immed[_base, RB]								; Initialise ring base to 0x1000
	alu_shf[$_rbase, _base, or, RING_SIZE_/**/RS, <<30]; [31:30]= 0 => Ring size is 128

	// Initialise the Scratch Ring base (and size), head and tail.

	// Note: We can Queue a max. of 4 commands to any external unit 
	// (like sram, dram, cap, etc). Beyond this limit the ME will stall.
	// The limit of 4 includes all the commands issued by all other MEs 
	// as well. It is the programmers responsibility to ensure this.

	// Since this is the only thread and ME that is queuing cmds at this time,
	// we can queue 3 commands safely.

	cap[write, $_rbase, SCRATCH_RING_BASE_/**/RN], sig_done[cw1]	; base = 0x1000
	cap[write, $_rhead, SCRATCH_RING_HEAD_/**/RN], sig_done[cw2]	; head = 0
	cap[write, $_rtail, SCRATCH_RING_TAIL_/**/RN], sig_done[cw3]	; tail = 0
	ctx_arb[cw1, cw2, cw3]


#undef RN
#undef RS
#undef RB

.end

#endm

// register and signal declarations
.reg $wdata, ring, @data
.sig scr_put											; signal for scratch put, 
.sig volatile wake_prod, wake_cons						; signals waking producer, waking consumer

	// 	We use manual allocation for these signals because we have problems
	//	using "visible" (.sig visible wakeup in this file) and "remote" in consumer.uc
	// 	Until it is solved, we'll have to use this manual allocation.

	// This is manual allocation of signal

.addr	wake_prod		SIG_WAKE_PROD
.addr	wake_cons		SIG_WAKE_CONS

// Execute only on thread 0.

.if (ctx() == 0)

	// Configure the Scratch Ring

	init_scratch_ring[RING_BASE, RING_SIZE, RING_NUMBER]

	// Ideally, we could signal the consumer here to start/get ready to consume.
	// But in order to hit the ring full condition, we'll not signal the consumer
	// here.

	// some one time initialisation code
	
	alu_shf[ring, --, b, RING_NUMBER, <<2]			; ring number in a register
	immed[@data, 1]									; data to be put into the ring
	
	// Produce on the ring, only if the ring is not full.

poll#:	
	br_inp_state[RING_FULL, sig_consumer#]			; Check if ring is full and signal consumer

	alu[$wdata, --, b, @data]						; Ring not full
	scratch[put, $wdata, 0, ring, 1], ctx_swap[scr_put]	; Produce one word on the ring

	alu[@data, @data, +, 1]							; Increment next value to be put 

	br[poll#]										; Keep producing on the ring.


sig_consumer#:
	// Signal the ME (ME 1) that is going to consume from the ring.
	// It takes about 1800 cycles to reach here.

	signal_next_me[wake_cons]						; Signal "consumer" (next) ME

	ctx_arb[wake_prod]								; Wait for consumer to finish everything

	br[poll#]										; back to producing.

.endif
	

	// All other threads are killed.

other_threads#:

	ctx_arb[kill]

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?