/* 3b2_cpu.h: AT&T 3B2 Model 400 IO dispatch (Header) | |
Copyright (c) 2017, Seth J. Morabito | |
Permission is hereby granted, free of charge, to any person | |
obtaining a copy of this software and associated documentation | |
files (the "Software"), to deal in the Software without | |
restriction, including without limitation the rights to use, copy, | |
modify, merge, publish, distribute, sublicense, and/or sell copies | |
of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be | |
included in all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
Except as contained in this notice, the name of the author shall | |
not be used in advertising or otherwise to promote the sale, use or | |
other dealings in this Software without prior written authorization | |
from the author. | |
*/ | |
/* Reference Documentation | |
* ======================= | |
* | |
* All communication between the system board and feature cards is | |
* done through in-memory queues, and causing interrupts in the | |
* feature card by accessing the Control or ID/VEC memory-mapped IO | |
* addresses. The structure of these queues is defined below in | |
* tables. | |
* | |
* Sysgen Block | |
* ------------ | |
* | |
* Pointed to by address at 0x2000000 after an INT0/INT1 combo | |
* | |
* | |
* | Address | Size | Contents | | |
* +---------------+------+-----------------------------------------+ | |
* | SYSGEN_P | 4 | Address of request queue | | |
* | SYSGEN_P + 4 | 4 | Address of completion queue | | |
* | SYSGEN_P + 8 | 1 | Number of entries in request queue | | |
* | SYSGEN_P + 9 | 1 | Number of entries in completion queue | | |
* | SYSGEN_P + 10 | 1 | Interrupt Vector number | | |
* | SYSGEN_P + 11 | 1 | Number of request queues | | |
* | |
* | |
* Queue Entry | |
* ----------- | |
* | |
* Each queue has one Express Entry, and n regular entries. | |
* | |
* | Address | Size | Contents | | |
* +---------------+------+-----------------------------------------+ | |
* | ENTRY_P | 2 | Byte Count | | |
* | ENTRY_P + 2 | 1 | Subdevice [1] | | |
* | ENTRY_P + 3 | 1 | Opcode | | |
* | ENTRY_P + 4 | 4 | Address / Data | | |
* | ENTRY_P + 8 | 4 | Application Specific Data | | |
* | |
* [1] The "Subdevice" entry is further divided into a bitset: | |
* Bit 7: Command (1) / Status (0) | |
* Bit 6: Sequence Bit | |
* Bit 5-1: Subdevice | |
* | |
* | |
* Queue | |
* ----- | |
* | |
* The Queue structures (one for request, one for completion) hold: | |
* - An express entry | |
* | |
* And then one or more queues, each queue consiting of | |
* - A set of pointers for load and unload from the queue | |
* - One or more Queue Entries | |
* | |
* | Address | Size | Contents | | |
* +---------------+------+-----------------------------------------+ | |
* | QUEUE_P | 12 | Express Queue Entry [1] | | |
* +---------------+------+-----------------------------------------+ | |
* | QUEUE_P + 12 | 2 | Load Pointer for Queue 0 | | |
* | QUEUE_P + 14 | 2 | Unload Pointer for Queue 0 | | |
* | QUEUE_P + 16 | 12 | Queue 0 Entry 0 [1] | | |
* | QUEUE_P + 28 | 12 | Queue 0 Entry 1 [1] | | |
* | ... | ... | ... | | |
* +---------------+------+-----------------------------------------+ | |
* | QUEUE_P + n | 2 | Load Pointer for Queue 1 | | |
* | QUEUE_P + n | 2 | Unload Pointer for Queue 1 | | |
* | QUEUE_P + n | 12 | Queue 1 Entry 0 [1] | | |
* | QUEUE_P + n | 12 | Queue 1 Entry 1 [1] | | |
* | ... | ... | ... | | |
* | |
* [1] See Queue Entry above | |
* | |
* NB: There are multiple Request queues, usually one per subdevice, | |
* and EACH Request queue starts with a Load Pointer, an Unload | |
* Pointer, and then 'n' Queue Entries. | |
* | |
*/ | |
#ifndef _3B2_IO_H_ | |
#define _3B2_IO_H_ | |
#include "3b2_sysdev.h" | |
#include "3b2_iu.h" | |
#include "3b2_if.h" | |
#include "3b2_id.h" | |
#include "3b2_dmac.h" | |
#include "3b2_mmu.h" | |
#include "sim_tmxr.h" | |
#define IOF_ID 0 | |
#define IOF_VEC 1 | |
#define IOF_CTRL 3 | |
#define IOF_STAT 5 | |
#define SYSGEN_PTR PHYS_MEM_BASE | |
/* CIO opcodes */ | |
#define CIO_DLM 1 | |
#define CIO_ULM 2 | |
#define CIO_FCF 3 | |
#define CIO_DOS 4 | |
#define CIO_DSD 5 | |
/* Map a physical address to a card ID */ | |
#define CID(pa) (((((pa) >> 0x14) & 0x1f) / 2) - 1) | |
/* Map a card ID to a base address */ | |
#define CADDR(bid) (((((bid) + 1) * 2) << 0x14)) | |
/* Offsets into the request/completion queues of various values */ | |
#define LUSIZE 4 /* Load/Unload pointers size */ | |
#define QESIZE 8 /* Queue entry is 8 bytes + application data */ | |
#define CIO_STAT 0 | |
#define CIO_CMD 1 | |
/* Sysgen State */ | |
#define CIO_INT_NONE 0 | |
#define CIO_INT0 1 | |
#define CIO_INT1 2 | |
#define CIO_SYSGEN 3 | |
typedef struct { | |
uint16 id; /* Card ID */ | |
void (*exp_handler)(uint8 cid); /* Handler for express jobs */ | |
void (*full_handler)(uint8 cid); /* Handler for full jobs */ | |
void (*sysgen)(uint8 cid); /* Sysgen routine (optional) */ | |
uint32 rqp; /* Request Queue Pointer */ | |
uint32 cqp; /* Completion Queue Pointer */ | |
uint8 rqs; /* Request queue size */ | |
uint8 cqs; /* Completion queue size */ | |
uint8 ivec; /* Interrupt Vector */ | |
uint8 no_rque; /* Number of request queues */ | |
uint8 ipl; /* IPL that this card uses */ | |
t_bool intr; /* Card needs to interrupt */ | |
uint8 sysgen_s; /* Sysgen state */ | |
uint8 seqbit; /* Squence Bit */ | |
uint8 op; /* Last received opcode */ | |
} CIO_STATE; | |
typedef struct { | |
uint16 byte_count; | |
uint8 subdevice; | |
uint8 opcode; | |
uint32 address; | |
} cio_entry; | |
struct iolink { | |
uint32 low; | |
uint32 high; | |
uint32 (*read)(uint32 pa, size_t size); | |
void (*write)(uint32 pa, uint32 val, size_t size); | |
}; | |
/* Example pump structure | |
* ---------------------- | |
* | |
* Used during initial setup of PORTS card in slot 0: | |
* | |
* dev = 0100 | |
* min = 0000 | |
* cmdcode = 0003 | |
* options = 0000 | |
* bufaddr = 808821A0 | |
* ioaddr = 00000500 | |
* size = 00000650 | |
* numbrd = 00000000 | |
* retcode = 00000008 (PU_NULL) | |
*/ | |
typedef struct { | |
uint16 dev; | |
uint16 min; | |
uint16 cmdcode; | |
uint16 options; | |
uint32 bufaddr; | |
uint32 ioaddr; | |
uint32 size; | |
uint32 numbrd; | |
uint32 retcode; | |
} pump; | |
extern uint16 cio_ints; | |
extern CIO_STATE cio[CIO_SLOTS]; | |
t_stat cio_reset(DEVICE *dptr); | |
t_stat cio_svc(UNIT *uptr); | |
void cio_clear(uint8 cid); | |
uint32 cio_crc32_shift(uint32 crc, uint8 data); | |
void cio_cexpress(uint8 cid, uint16 esize, cio_entry *cqe, uint8 *app_data); | |
void cio_cqueue(uint8 cid, uint8 cmd_stat, uint16 esize, cio_entry *cqe, uint8 *app_data); | |
void cio_rexpress(uint8 cid, uint16 esize, cio_entry *rqe, uint8 *app_data); | |
t_stat cio_rqueue(uint8 cid, uint8 qnum, uint16 esize, cio_entry *rqe, uint8 *app_data); | |
t_bool cio_cqueue_avail(uint8 cid, uint16 esize); | |
uint16 cio_r_lp(uint8 cid, uint8 qnum, uint16 esize); | |
uint16 cio_r_ulp(uint8 cid, uint8 qnum, uint16 esize); | |
uint16 cio_c_lp(uint8 cid, uint16 esize); | |
uint16 cio_c_ulp(uint8 cid, uint16 esize); | |
void cio_sysgen(uint8 cid); | |
void dump_entry(uint32 dbits, DEVICE *dev, CONST char *type, | |
uint16 esize, cio_entry *entry, uint8 *app_data); | |
#endif |