Browse Source

HACKING: New text file to document the internal workings of (currently) the device API

Luke Dashjr 13 years ago
parent
commit
7cfa42ebbe
1 changed files with 116 additions and 0 deletions
  1. 116 0
      HACKING

+ 116 - 0
HACKING

@@ -0,0 +1,116 @@
+Driver API
+==========
+
+NOTE: This API is subject to change. It is recommended that you submit your
+driver, even if obscure, to the mainline BFGMiner codebase so that it will be
+updated when the API changes.
+
+BFGMiner defines 3 different units that drivers can use:
+- "Device" is a logical unit used for mining. It is represented by its first
+  processor's `struct cgpu_info`. Example: ButterFly Labs MiniRig SC.
+- "Processor" is a logical work processing unit. It is represented by a `struct
+  cgpu_info` and one or more `struct thr_info`. Example: a single board within
+  ButterFly Labs MiniRig SC.
+- "Thread" is a sequence of instructions and stack that manages hashing on one
+  or more Processors within a single Device. It is represented by a `struct
+  thr_info`.
+
+It should be noted that while every Processor has a `struct thr_info`, this may
+not represent the same Thread which is managing hashing on the Processor.
+Instead, this `struct thr_info` is only used to store status information needed
+for the Processor, and is maintained by the managing Thread in addition to its
+own `struct thr_info`. New drivers are encouraged to use an asynchronous model
+to manage as many Processors as possible within a single Thread.
+
+struct device_api basics
+------------------------
+
+Every driver defines a `struct device_api`. The `dname` field contains a
+short name of the driver. This should be the same name used in the source file:
+driver-foobar.c defines `dname` "foobar". The `name` field contains a three-
+letter abbreviation for the device, used in the representation of devices. For
+example, `dname` "FOO" would result in devices represented as "FOO 0", "FOO 1",
+etc and processors represented as "FOO 0a", "FOO 0b", etc.
+
+Drivers must define a function `api_detect`, which is run at startup to detect
+devices. For each device (note: NOT each processor), it should allocate a
+`struct cgpu_info`, set some basic parameters on it, and call the `add_cgpu`
+function with it as an argument. Various values you can initialize are:
+	.api         This MUST be set to your driver's `struct driver_api`!
+	.deven       Should be set to DEV_ENABLED
+	.procs       Number of Processors for this device
+	.threads     Number of threads your device needs - should be either an even
+	             multiple of .procs (threads will be allocated to each
+	             Processor), or a number less than .procs (threads will be
+	             allocated only to the Device, to manage all Processors)
+	.name        Null-terminated name of the device itself
+`api_detect` should return the total number of devices created. It should leave
+the device in an unused state, as the user may opt to delete it outright.
+
+Threads
+-------
+
+The first interaction BFGMiner will have with a device is by calling the
+driver's `thread_prepare` function for each Thread. This occurs while BFGMiner
+is still in a single-threaded state, before any Threads have actually started
+running independently. It should do only the minimal initialization necessary
+to proceed, and return true iff successful.
+
+Once all the Threads are setup, BFGMiner starts them off by calling the
+`thread_init` function. This should do all initialization that can occur in
+parallel with other Threads.
+
+The driver should specify a `minerloop` to use. For the purposes of this
+document, it is assumed you will be using `minerloop_async`. Please note that
+the default is currently `minerloop_scanhash`, and much of the documentation
+here will NOT work with this `minerloop`.
+
+Processors
+----------
+
+Processors work with `struct work` objects, which each represent a block header
+to find a solution for. Before your driver sees a `struct work`, it will be
+passed to the function `prepare_work` with pointers to the Processor `struct
+thr_info` and the `struct work` as arguments. Most drivers do not need to do
+anything at this stage, so feel free to omit the `prepare_work` function.
+
+For each job, the `job_prepare` function is called in advance, with three
+arguments: Processor `struct thr_info *`, `struct work *`, and a `uint64_t`
+limiting how many nonces to check (starting from `work->blk.nonce`). Unless you
+implement a `can_limit_work` function, you will always receive a full nonce
+range from 0 to 0xffffffff. `job_prepare` increments `work->blk.nonce` to the
+last nonce the processor will be attempting and returns true when successful.
+Please note this will be called while the previous job is still executing.
+
+When it is time to actually start the new job, the `job_start` function will be
+called. This is given the Processor `struct thr_info *` as its only argument,
+and should start the job most recently prepared with `job_prepare`. Note that
+it is possible for `job_prepare` to be called for a job that never starts
+(another `job_prepare` may be executed to override the previous one instead).
+`job_start` must set `thr->tv_morework` to the time the device expects to need
+its next work item. It is generally advisable to set this a bit early to ensure
+any delays do not make it late. `job_start` is expected to always succeed and
+does not have a return value.
+
+Immediately before `job_start` is called to change from one job to the next,
+`job_get_results` will be called to fetch any volatile results from the
+previous job. It is provided the Processor's `struct thr_info *` and the
+currently executing job's `struct work *`. It should ONLY fetch the raw data
+for the results, and not spend any time processing or submitting it. After the
+new job has been started, your driver's `job_process_results` function will be
+called with the same arguments to complete the submission of these results.
+
+Drivers may define a `poll` function. If this is defined, `thr->tv_poll` must
+always be set to a valid time to next execute it, for each Processor.
+
+Whenever a solution is found (at any point), the function `submit_nonce` should
+be called, passing the Processor `struct thr_info *`, `struct work *`, and
+nonce as arguments. If the solution is invalid (any of the final 32 bits of the
+hash are nonzero), it will be recorded as a hardware error and your driver's
+`hw_error` function (if one is defined) will be called.
+
+As often as results are processed, your driver should call the `hashes_done`
+function with a number of arguments: Processor `struct thr_info *`, count of
+hashes completed (including calls to `submit_nonce`), a `struct timeval *`
+that tells how long it took to find these hashes (usually time since the last
+call to `hashes_done`, and a `uint32_t *` which should usually be NULL.