PiDP-8/I Software

Check-in [d3432d4092]
Log In

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Work in progress The association of dev no and I2C address per unit need more work
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | i2c-bridge-device
Files: files | file ages | folders
SHA1: d3432d40923b7245a290e87b3685dec765ba2acd
User & Date: HBEggenstein 2021-10-16 00:41:46.637
References
2021-10-18
00:51 Reply: simulating or interfacing devices via an I2C bridge artifact: a8656d7997 user: tangent
Context
2021-10-16
13:50
work in progress. minor tweaks but seems to compile and have basic device configuration working now, except attach/detach logic and flawed association between I2C addr and dev no check-in: 6b2c49bf4c user: HBEggenstein tags: i2c-bridge-device
00:41
Work in progress The association of dev no and I2C address per unit need more work check-in: d3432d4092 user: HBEggenstein tags: i2c-bridge-device
2021-10-13
23:07
Initial commit to start a branch exploring the idea of having a generic SIMH device that will forward IOT instructions for configurable PDP-8 devices so they can be implemented on external hardware, typically a microcontroller connected to the host via I2C. This could be used for rapid prototyping of either historical device emulation or emulating custom I/O logic. check-in: fbcfafaf43 user: HBEggenstein tags: i2c-bridge-device
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/SIMH/PDP8/pdp8_cpu.c.
1776
1777
1778
1779
1780
1781
1782

1783
1784
1785
1786
1787
1788
1789
        if (dibp->dsp_tbl) {                            /* dispatch table? */
            DIB_DSP *dspp = dibp->dsp_tbl;              /* set ptr */
            for (j = 0; j < dibp->num; j++, dspp++) {   /* loop thru tbl */
                if (dspp->dsp) {                        /* any dispatch? */
                    if (dev_tab[dspp->dev]) {           /* already filled? */
                        sim_printf ("%s device number conflict at %02o\n",
                            sim_dname (dptr), dibp->dev + j);

                        return TRUE;
                        }
                    dev_tab[dspp->dev] = dspp->dsp;     /* fill */
                    }                                   /* end if dsp */
                }                                       /* end for j */
            }                                           /* end if dsp_tbl */
        else {                                          /* inline dispatches */







>







1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
        if (dibp->dsp_tbl) {                            /* dispatch table? */
            DIB_DSP *dspp = dibp->dsp_tbl;              /* set ptr */
            for (j = 0; j < dibp->num; j++, dspp++) {   /* loop thru tbl */
                if (dspp->dsp) {                        /* any dispatch? */
                    if (dev_tab[dspp->dev]) {           /* already filled? */
                        sim_printf ("%s device number conflict at %02o\n",
                            sim_dname (dptr), dibp->dev + j);
                              /* TODO this mesageseems to be wrong if dev bnr are not consecutive?? */
                        return TRUE;
                        }
                    dev_tab[dspp->dev] = dspp->dsp;     /* fill */
                    }                                   /* end if dsp */
                }                                       /* end for j */
            }                                           /* end if dsp_tbl */
        else {                                          /* inline dispatches */
Changes to src/SIMH/PDP8/pdp8_i2cb.c.
24
25
26
27
28
29
30



































































31
32











































33
34
35
36
37
38
39

#define I2C_BR_DEV_PATH "/dev/i2c-1"


extern int32 stop_inst;





































































static uint8 I2C_device_map[64] = {};
static struct i2cd * i2cdev;














































int32 i2c_forward_IOT(uint8 i2c_addr, int32 IR, int32 AC, int32 * AC_new_out, int32 * skip_flag_out );
int32 check_i2c_open();

int32 check_i2c_open() {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

#define I2C_BR_DEV_PATH "/dev/i2c-1"


extern int32 stop_inst;


int32 i2c_bridge (int32 IR, int32 AC);
t_stat i2cb_show_dev (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat i2cb_set_dev (UNIT *uptr, int32 val, CONST char *cptr, void *desc);

t_stat i2cb_show_addr (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat i2cb_set_addr (UNIT *uptr, int32 val, CONST char *cptr, void *desc);


#define I2CB_MAX 8                               /* max number of bridges */


/* Initial device numbers for 8 bridges, reserved for customer
   applications by DEC so conflict free wrt DEC products */


#define DEV_I2CB0 030
#define DEV_I2CB1 031
#define DEV_I2CB2 032
#define DEV_I2CB3 033
#define DEV_I2CB4 034
#define DEV_I2CB5 035
#define DEV_I2CB6 036
#define DEV_I2CB7 037



DIB_DSP i2cb_dsp[I2CB_MAX] = {
    { DEV_I2CB0,  &i2c_bridge},
    { DEV_I2CB1,  &i2c_bridge},
    { DEV_I2CB2,  &i2c_bridge},
    { DEV_I2CB3,  &i2c_bridge},
    { DEV_I2CB4,  &i2c_bridge},
    { DEV_I2CB5,  &i2c_bridge},
    { DEV_I2CB6,  &i2c_bridge},
    { DEV_I2CB7,  &i2c_bridge}
    };





REG i2cb_reg[] = {
    { NULL } /* TODO ?? any registers that we need? */
    };



MTAB i2cb_mod[] = {
    { MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "I2C address", "I2CADDR",
      &i2cb_set_addr, &i2cb_show_addr, NULL },
    { MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DEVNO", "DEVNO",
      &i2cb_set_dev, &i2cb_show_dev, NULL },
    { 0 }
    };





const char *i2cb_description (DEVICE *dptr);



/* TODO move into unit specific data, but this is faster so maybe
   regenerate this table each time the dev or addr is changed 
   for a unit */
 
static uint8 I2C_device_map[64] = {};
static struct i2cd * i2cdev;


t_stat i2cb_reset(DEVICE *dp);                /* reset routine */
t_stat i2cb_boot(int32 u, DEVICE *dp);         /* boot routine */
t_stat i2cb_attach(UNIT *up, CONST char *cp);  /* attach routine */
t_stat i2cb_detach(UNIT *up);                     /* detach routine */


DIB i2cb_dib = { DEV_I2CB0, I2CB_MAX, { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, i2cb_dsp };


/* TODO for now, all "action" i taking place in the IOT dipatch
   routines, so no unit service code is needed , and also no
   registers. Will change with interrupt support?? */



UNIT i2cb_unit[] = {
    { UDATA (NULL, UNIT_ATTABLE+UNIT_DISABLE, 0) },
    { UDATA (NULL, UNIT_ATTABLE+UNIT_DISABLE, 0) },
    { UDATA (NULL, UNIT_ATTABLE+UNIT_DISABLE, 0) },
    { UDATA (NULL, UNIT_ATTABLE+UNIT_DISABLE, 0) },
    { UDATA (NULL, UNIT_ATTABLE+UNIT_DISABLE, 0) },
    { UDATA (NULL, UNIT_ATTABLE+UNIT_DISABLE, 0) },
    { UDATA (NULL, UNIT_ATTABLE+UNIT_DISABLE, 0) },
    { UDATA (NULL, UNIT_ATTABLE+UNIT_DISABLE, 0) }
    };



DEVICE i2cb_dev = {
    "I2Cbridge", i2cb_unit, i2cb_reg, i2cb_mod,
    8, 10, 31, 1, 8, 12,
    NULL, NULL, &i2cb_reset,
    &i2cb_boot, &i2cb_attach, &i2cb_detach,
    &i2cb_dib, DEV_DISABLE, 0,
    NULL, NULL, NULL, NULL, NULL, NULL,
    &i2cb_description
    };







int32 i2c_forward_IOT(uint8 i2c_addr, int32 IR, int32 AC, int32 * AC_new_out, int32 * skip_flag_out );
int32 check_i2c_open();

int32 check_i2c_open() {
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  rather allow IOT  instructions to be forwaded over I2C to (typically) a microcontroller that would then
  implement the desired logic.

  The user would be able to configure several instances, where each instance maps a PDP-8 device address
  to an address on the I2C bus.

  So let's say we want to implement a PDP-8 device 30 (that's in the range reserved for user applications
  so it should not clash with DEC product device numbers) with a microcontroller on the I2C bas with address
  0x11 .

  Then the instruction
  6301
  would transmit a data packet consisting of the 12 bit instruction code plus 12 bit AC (so 3 bytes)
  to the I2C device 0X11 which would then need to compute anf send back a potentially changed AC value and
  a flag indicating whether to skip the next instruction or not. That's all.








|
|







181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  rather allow IOT  instructions to be forwaded over I2C to (typically) a microcontroller that would then
  implement the desired logic.

  The user would be able to configure several instances, where each instance maps a PDP-8 device address
  to an address on the I2C bus.

  So let's say we want to implement a PDP-8 device 30 (that's in the range reserved for user applications
  so it should not clash with DEC product device numbers) with a microcontroller on the I2C bus with address
  (say) 0x11.

  Then the instruction
  6301
  would transmit a data packet consisting of the 12 bit instruction code plus 12 bit AC (so 3 bytes)
  to the I2C device 0X11 which would then need to compute anf send back a potentially changed AC value and
  a flag indicating whether to skip the next instruction or not. That's all.

137
138
139
140
141
142
143
144

145












































































































































































146
147
148
149


/* fall through TODO ill instr is probably not we want here but for prototyping it's ok */

return (stop_inst << IOT_V_REASON) + AC;                /* ill inst */

}















































































































































































#endif

/* ---PiDP end---------------------------------------------------------------------------------------------- */









>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432


/* fall through TODO ill instr is probably not we want here but for prototyping it's ok */

return (stop_inst << IOT_V_REASON) + AC;                /* ill inst */

}

const char *i2cb_description (DEVICE *dptr)
{
return "I2C bridge prototyping device";
}

t_stat i2cb_reset(DEVICE *dp) {
/* TODO */
  return SCPE_OK;
}

t_stat i2cb_boot(int32 u, DEVICE *dp){
/* TODO */
  return SCPE_OK;
}



t_stat i2cb_attach(UNIT *up, CONST char *cp){
/* TODO */
  return SCPE_OK;
}


t_stat i2cb_detach(UNIT *up){
/* TODO */
  return SCPE_OK;
}


/* set device number for the specific unit (!) not the device */

t_stat i2cb_set_dev (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newdev;
t_stat r;
uint32 i;

if (cptr == NULL)
    return SCPE_ARG;
if (uptr == NULL)
    return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
    return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
    return SCPE_IERR;

/* find unit index */ 
for (i=0; i < dibp->num ; i++) {
    if  (dptr->units +i  == uptr) 
        break;
}
if(i == dibp->num) {
    return SCPE_IERR;
}

newdev = get_uint (cptr, 8, DEV_MAX - 1, &r);           /* get new */
if ((r != SCPE_OK) || (newdev == dibp->dsp_tbl[i].dev))
    return r;
dibp->dsp_tbl[i].dev = newdev;                          /* store */
return SCPE_OK;
}



t_stat i2cb_show_dev (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 i;

if (uptr == NULL)
    return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
    return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
    return SCPE_IERR;

/* find unit index */ 
for (i=0; i < dibp->num ; i++) {
    if  (dptr->units + i  == uptr) 
        break;
}
if(i == dibp->num) {
    return SCPE_IERR;
}

fprintf (st, "devno=%02o", dibp->dsp_tbl[i].dev);

return SCPE_OK;
}



/* Set I2C addr */

t_stat i2cb_set_addr (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{

DEVICE *dptr;
DIB *dibp;
uint32 i;
t_stat r;
uint32 addr;
if (uptr == NULL)
    return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
    return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
    return SCPE_IERR;

/* find unit index */ 
for (i=0; i < dibp->num ; i++) {
    if  (dptr->units + i  == uptr) 
        break;
}
if(i == dibp->num) {
    return SCPE_IERR;
}

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_ARG;
if (uptr->flags & UNIT_ATT)
    return SCPE_ALATT;

addr =  get_uint (cptr, 16, 63 , &r);
if (r != SCPE_OK)
    return SCPE_ARG;
I2C_device_map[dibp->dsp_tbl[i].dev]=(uint8) addr;
return SCPE_OK;
}

/* Show I2C address */

t_stat i2cb_show_addr (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 i;

if (uptr == NULL)
    return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
    return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
    return SCPE_IERR;

/* find unit index */ 
for (i=0; i < dibp->num ; i++) {
    if  (dptr->units + i  == uptr) 
        break;
}
if(i == dibp->num) {
    return SCPE_IERR;
}

fprintf (st, "I2c addr=%02x", I2C_device_map[dibp->dsp_tbl[i].dev]);

return SCPE_OK;
}





#endif

/* ---PiDP end---------------------------------------------------------------------------------------------- */

Changes to src/SIMH/PDP8/pdp8_sys.c.
61
62
63
64
65
66
67

68
69
70
71
72
73
74
extern DEVICE clk_dev, lpt_dev;
extern DEVICE rk_dev, rl_dev;
extern DEVICE rx_dev;
extern DEVICE df_dev, rf_dev;
extern DEVICE dt_dev, td_dev;
extern DEVICE mt_dev, ct_dev;
extern DEVICE ttix_dev, ttox_dev;

extern REG cpu_reg[];
extern uint16 M[];

t_stat fprint_sym_fpp (FILE *of, t_value *val);
t_stat parse_sym_fpp (CONST char *cptr, t_value *val);
CONST char *parse_field (CONST char *cptr, uint32 max, uint32 *val, uint32 c);
CONST char *parse_fpp_xr (CONST char *cptr, uint32 *xr, t_bool inc);







>







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
extern DEVICE clk_dev, lpt_dev;
extern DEVICE rk_dev, rl_dev;
extern DEVICE rx_dev;
extern DEVICE df_dev, rf_dev;
extern DEVICE dt_dev, td_dev;
extern DEVICE mt_dev, ct_dev;
extern DEVICE ttix_dev, ttox_dev;
extern DEVICE i2cb_dev;
extern REG cpu_reg[];
extern uint16 M[];

t_stat fprint_sym_fpp (FILE *of, t_value *val);
t_stat parse_sym_fpp (CONST char *cptr, t_value *val);
CONST char *parse_field (CONST char *cptr, uint32 max, uint32 *val, uint32 c);
CONST char *parse_fpp_xr (CONST char *cptr, uint32 *xr, t_bool inc);
108
109
110
111
112
113
114

115
116
117
118
119
120
121
    &rx_dev,
    &df_dev,
    &rf_dev,
    &dt_dev,
    &td_dev,
    &mt_dev,
    &ct_dev,

    NULL
    };

const char *sim_stop_messages[SCPE_BASE] = {
    "Unknown error",
    "Unimplemented instruction",
    "HALT instruction",







>







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
    &rx_dev,
    &df_dev,
    &rf_dev,
    &dt_dev,
    &td_dev,
    &mt_dev,
    &ct_dev,
    &i2cb_dev,
    NULL
    };

const char *sim_stop_messages[SCPE_BASE] = {
    "Unknown error",
    "Unimplemented instruction",
    "HALT instruction",
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
            continue;                                   /* skip charactder */
        }
    if (c == 0377)                                      /* rubout? */
        rubout = 1;                                     /* set, skip */
    else
        if (c > 0200)                                   /* channel 8 set? */
            *newf = (c & 070) << 9;                     /* change field */
    else 
        return c;                                       /* otherwise ok */
    }
return EOF;
}

t_stat sim_load_bin (FILE *fi, t_bool do_load)
{







|







186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
            continue;                                   /* skip charactder */
        }
    if (c == 0377)                                      /* rubout? */
        rubout = 1;                                     /* set, skip */
    else
        if (c > 0200)                                   /* channel 8 set? */
            *newf = (c & 070) << 9;                     /* change field */
    else
        return c;                                       /* otherwise ok */
    }
return EOF;
}

t_stat sim_load_bin (FILE *fi, t_bool do_load)
{