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 + -
显示快捷键?