Skip to content

Commit

Permalink
Merge pull request emu-russia#446 from ogamespec/main
Browse files Browse the repository at this point in the history
IO subsystem draft
  • Loading branch information
ogamespec authored Aug 24, 2023
2 parents 1de418a + 425f5a2 commit e1df0c5
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 0 deletions.
111 changes: 111 additions & 0 deletions IO/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# IO Devices

This section contains the implementation of logic for various I/O devices for NES/Famicom/Dendy, expansion ports and accompanying chips.

TBD: expansion ports are not yet implemented and are not considered.

## Overview

As it may seem - what could be complicated in an ordinary controller? However...

- Controller connection differs between NES/Famicom/Dendy. NES/Dendy uses a port connection. In the Famicom, the controllers are seamlessly connected to the main unit.
- The second Famicom controller has a microphone (yeah, that's wtf from the 90's).
- Dendy controllers have Turbo buttons.

And how to generalize all this nicely? :-)

## IO Subsystem Architecture

- The implementation of the device logic is in native code
- Each input device is provided with a unique identifier that fully defines its model and implementation (DeviceID); a list of all identifiers is in io.h
- The Motherboard description in BoardDescription.json contains a list of ports (IOPort). Each port contains a list of device IDs that can be attached to it (Attach / Detach)
- IO subsystem contains a factory for creating devices by its DeviceID. The created device is defined by a descriptor, an integer > 0 (Handle)
- Each device provides a list of its I/O controls (IOState). Each IOState is defined by an integer > 0
- The device contains a SetState method that can be used by the consumer to set the states of the IOState controls

## Configuring IO Devices

On the emulator side, the setup simply involves binding IOState to some API for working with input devices on the PC side.
The associative link is then used to set the SetState of the connected device.

The emulator contains a pool of registered devices with DeviceID (devices are added and removed by the user).

Then each device can be configured (roughly speaking to make binding IOState to DirectInput/XInput or some other API).

After configuration, the device can be attached or detached to the specified motherboard model (Attach / Detach). After starting the emulation for the IO subsystem will be created instances of connected devices, connected to the ports and then the emulator can call SetState from its side, so that the native implementation will convert IOState into specific signals for IO ports.

Again the description is very abstract, it will crystallize into particular classes/methods as the work progresses.

## Famicom Controller (Port1)

![famicom_controller1](/UserManual/imgstore/famicom_controller1.png)

DeviceID: 0x00000001

|IOState|Actuator|Values|
|---|---|---|
|1|Up|0/1|
|2|Down|0/1|
|3|Left|0/1|
|4|Right|0/1|
|5|Select|0/1|
|6|Start|0/1|
|7|B|0/1|
|8|A|0/1|

Although Famicom controllers are not removable, they can be detached inside the case, so for the sake of code unification we will consider them removable.

## Famicom Controller (Port2)

![famicom_controller2](/UserManual/imgstore/famicom_controller2.png)

DeviceID: 0x00000002

|IOState|Actuator|Values|
|---|---|---|
|1|Up|0/1|
|2|Down|0/1|
|3|Left|0/1|
|4|Right|0/1|
|5|Volume|0...255|
|6|MicLevel|0...255|
|7|B|0/1|
|8|A|0/1|

Volume and mic level values are in the UInt8 range so far, we'll see how good this model is in the process.

## NES Controller (Port1/2)

![nes_controller](/UserManual/imgstore/nes_controller.png)

DeviceID: 0x00000003

|IOState|Actuator|Values|
|---|---|---|
|1|Up|0/1|
|2|Down|0/1|
|3|Left|0/1|
|4|Right|0/1|
|5|Select|0/1|
|6|Start|0/1|
|7|B|0/1|
|8|A|0/1|

## Dendy Controller (Port1/2)

![dendy_controller](/UserManual/imgstore/dendy_controller.png)

DeviceID: 0x00000004

|IOState|Actuator|Values|
|---|---|---|
|1|Up|0/1|
|2|Down|0/1|
|3|Left|0/1|
|4|Right|0/1|
|5|Select|0/1|
|6|Start|0/1|
|7|TurboB|0/1|
|8|TurboA|0/1|
|9|B|0/1|
|10|A|0/1|
111 changes: 111 additions & 0 deletions IO/ReadmeRus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# IO Устройства

Данный раздел содержит реализацию логики различных устройств ввода/вывода для NES/Famicom/Dendy, портов расширения и сопроводительных чипов.

TBD: порты расширения пока не реализованы и не рассматриваются.

## Введение

Как может показаться - что может быть сложного в обычном контроллере? Однако...

- Соединение контроллеров различается у NES/Famicom/Dendy. NES/Dendy использует соединение через порты. В Famicom контроллеры неразъёмно соединены с основным юнитом.
- На втором контроллере Famicom пристутствует микрофон (да, такой вот wtf из 90-х)
- На Dendy контроллерах присутствуют Turbo-кнопки

И как вот это всё генерализовать красиво? :-)

## Архитектура IO подсистемы

- Реализация логики устройств находится в нативном коде
- Каждое устройство ввода снабжается уникальным идентификатором, полностью определяющим его модель и реализацию (DeviceID); список всех идентификаторов в io.h
- Описание Motherboard в BoardDescription.json содержит список портов (IOPort). Каждый порт содержит список ID устройств, которые можно к нему подключить (Attach / Detach)
- IO подсистема содержит фабрику для создания устройств по его DeviceID. Созданное устройство определяется описателем, целым числом > 0 (Handle)
- Каждое устройство предоставляет список своих контролов ввода/вывода (IOState). Каждый IOState определяется целым числом > 0
- Устройство содержит метод SetState, которым может пользоваться потребитель, для установки состояний IOState контролов

## Настройка IO устройств

Со стороны эмулятора настройка подразумевает просто привязку IOState к какому-то API для работы с устройствами ввода на стороне ПК.
После чего ассоциативная связь используется для установки SetState подключенному устройству.

Эмулятор содержит пул зарегистрированных устройств с указанием DeviceID (устройства добавляет и удаляет пользователь).

Далее каждое устройство можно настроить (грубо говоря сделать привязку IOState к DirectInput/XInput или ещё какому-то API).

После настройки устройство можно подключить или отключить к указанной модели материнской платы (Attach / Detach). После запуска эмуляции для IO подсистемы будут созданы инстанции подключенных устройств, подключены к портам и далее эмулятор может вызывать со своей стороны SetState, чтобы нативная реализация преобразовывала IOState в конкретные сигналы для портов ввода/вывода.

Опять же описание весьма абстрактное, по ходу работ оно кристаллизуется в конкретные классы/методы.

## Famicom Controller (Port1)

![famicom_controller1](/UserManual/imgstore/famicom_controller1.png)

DeviceID: 0x00000001

|IOState|Actuator|Values|
|---|---|---|
|1|Up|0/1|
|2|Down|0/1|
|3|Left|0/1|
|4|Right|0/1|
|5|Select|0/1|
|6|Start|0/1|
|7|B|0/1|
|8|A|0/1|

Контроллеры Famicom хотя внешне и не съёмные, но внутри корпуса их таки можно отсоединить, поэтому для унификации кода будем считать их съёмными.

## Famicom Controller (Port2)

![famicom_controller2](/UserManual/imgstore/famicom_controller2.png)

DeviceID: 0x00000002

|IOState|Actuator|Values|
|---|---|---|
|1|Up|0/1|
|2|Down|0/1|
|3|Left|0/1|
|4|Right|0/1|
|5|Volume|0...255|
|6|MicLevel|0...255|
|7|B|0/1|
|8|A|0/1|

Значения громкости и уровня микрофона пока в диапазоне UInt8, посмотрим насколько эта модель хорошая в процессе.

## NES Controller (Port1/2)

![nes_controller](/UserManual/imgstore/nes_controller.png)

DeviceID: 0x00000003

|IOState|Actuator|Values|
|---|---|---|
|1|Up|0/1|
|2|Down|0/1|
|3|Left|0/1|
|4|Right|0/1|
|5|Select|0/1|
|6|Start|0/1|
|7|B|0/1|
|8|A|0/1|

## Dendy Controller (Port1/2)

![dendy_controller](/UserManual/imgstore/dendy_controller.png)

DeviceID: 0x00000004

|IOState|Actuator|Values|
|---|---|---|
|1|Up|0/1|
|2|Down|0/1|
|3|Left|0/1|
|4|Right|0/1|
|5|Select|0/1|
|6|Start|0/1|
|7|TurboB|0/1|
|8|TurboA|0/1|
|9|B|0/1|
|10|A|0/1|
Binary file added UserManual/imgstore/dendy_controller.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added UserManual/imgstore/famicom_controller1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added UserManual/imgstore/famicom_controller2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added UserManual/imgstore/nes_controller.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit e1df0c5

Please sign in to comment.