Subversion Repositories ht46f47_simulator

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
unit HT46F47;
2
 
3
interface
4
 
5
type
6
  Nibble = 0..15;
7
 
8
  TRom = array[0..$FF] of byte;
9
 
10
  THT46F47 = class(TObject)
11
  strict private
12
    procedure WaitMs(milliseconds: integer);
13
  strict protected
14
    // ROM
15
    // Registers
16
    FPC: byte;
17
    FReturnAddress: byte;
18
    FPage: Nibble;
19
    FRegA: Nibble;
20
    FRegB: Nibble;
21
    FRegC: Nibble;
22
    FRegD: Nibble;
23
    FCalledOnce: boolean;
24
    // In
25
    FS1: boolean;
26
    FS2: boolean;
27
    FDIn: Nibble;
28
    FAD1: Nibble;
29
    FAD2: Nibble;
30
    // Out
31
    FPWM: Nibble;
32
    FPortOut: Nibble;
33
  public
34
    // ROM
35
    ROM: TRom;
36
    property FROM: TRom read ROM;
37
    // Registers
38
    property PC: byte read FPC;
39
    property ReturnAddress: byte read FReturnAddress;
40
    property Page: Nibble read FPage;
41
    property RegA: Nibble read FRegA;
42
    property RegB: Nibble read FRegB;
43
    property RegC: Nibble read FRegC;
44
    property RegD: Nibble read FRegD;
45
    // In
46
    property S1: boolean read FS1 write FS1;
47
    property S2: boolean read FS2 write FS2;
48
    property DIn: Nibble read FDIn write FDIn;
49
    property AD1: Nibble read FAD1 write FAD1;
50
    property AD2: Nibble read FAD2 write FAD2;
51
    // Out
52
    property PWM: Nibble read FPWM;
53
    property PortOut: Nibble read FPortOut;
54
    // Functions
55
    constructor Create;
56
    procedure Step;
57
    procedure Reset;
58
  end;
59
 
60
implementation
61
 
62
uses
63
  SysUtils, Forms;
64
 
65
{ THT46F47 }
66
 
67
constructor THT46F47.Create;
68
var
69
  i: integer;
70
begin
71
  for i := Low(FROM) to High(FROM) do
72
  begin
73
    ROM[i] := $00;
74
  end;
75
  Reset;
76
end;
77
 
78
procedure THT46F47.Reset;
79
begin
80
  // Internal
81
  FPC := 0;
82
  FReturnAddress := 0;
83
  FPage := 0;
84
  FRegA := 0; // Note: The registers don't seem to be reset in the actual chip, if a "soft reset" is done
85
  FRegB := 0;
86
  FRegC := 0;
87
  FRegD := 0;
88
  FCalledOnce := false;
89
  // In
90
  FS1 := false;
91
  FS2 := false;
92
  FDIn := 0;
93
  FAD1 := 0;
94
  FAD2 := 0;
95
  // Out
96
  FPWM := 0;
97
  FPortOut := 0;
98
end;
99
 
100
procedure THT46F47.Step;
101
var
102
  Instruction: byte;
103
  ProgramCounterNext: Byte;
104
  ProgramCounterCurrent: Byte;
105
begin
106
  Instruction := FROM[FPC];
107
 
108
  ProgramCounterCurrent := FPC;
109
  ProgramCounterNext := FPC+1;
110
 
111
  try
112
    (*
113
    ----------------------------------------------------
114
    Code        Assembly        Alternative     Comment
115
    ----------------------------------------------------
116
    10  LED 0000        PORT 0
117
    11  LED 0001        PORT 1
118
    12  LED 0010        PORT 2
119
    13  LED 0011        PORT 3
120
    14  LED 0100        PORT 4
121
    15  LED 0101        PORT 5
122
    16  LED 0110        PORT 6
123
    17  LED 0111        PORT 7
124
    18  LED 1000        PORT 8
125
    19  LED 1001        PORT 9
126
    1A  LED 1010        PORT 10
127
    1B  LED 1011        PORT 11
128
    1C  LED 1100        PORT 12
129
    1D  LED 1101        PORT 13
130
    1E  LED 1110        PORT 14
131
    1F  LED 1111        PORT 15
132
    *)
133
    if (Instruction >= $10) and (Instruction <= $1F) then
134
    begin
135
      FPortOut := Instruction and $F;
136
    end;
137
 
138
    (*
139
    ----------------------------------------------------
140
    Code        Assembly        Alternative     Comment
141
    ----------------------------------------------------
142
    20  WAIT 1ms
143
    21  WAIT 2ms
144
    22  WAIT 5ms
145
    23  WAIT 10ms
146
    24  WAIT 20ms
147
    25  WAIT 50ms
148
    26  WAIT 100ms
149
    27  WAIT 200ms
150
    28  WAIT 500ms
151
    29  WAIT 1s
152
    2A  WAIT 2s
153
    2B  WAIT 5s
154
    2C  WAIT 10s
155
    2D  WAIT 20s
156
    2E  WAIT 30s
157
    2F  WAIT 60s
158
    *)
159
    case Instruction of
160
      $20: WaitMs(1);      // WAIT 1ms
161
      $21: WaitMs(2);      // WAIT 2ms
162
      $22: WaitMs(5);      // WAIT 5ms
163
      $23: WaitMs(10);     // WAIT 10ms
164
      $24: WaitMs(20);     // WAIT 20ms
165
      $25: WaitMs(50);     // WAIT 50ms
166
      $26: WaitMs(100);    // WAIT 100ms
167
      $27: WaitMs(200);    // WAIT 200ms
168
      $28: WaitMs(500);    // WAIT 500ms
169
      $29: WaitMs(1000);   // WAIT 1s
170
      $2A: WaitMs(2000);   // WAIT 2s
171
      $2B: WaitMs(5000);   // WAIT 5s
172
      $2C: WaitMs(10000);  // WAIT 10s
173
      $2D: WaitMs(20000);  // WAIT 20s
174
      $2E: WaitMs(30000);  // WAIT 30s
175
      $2F: WaitMs(60000);  // WAIT 60s
176
    end;
177
 
178
    (*
179
    ----------------------------------------------------
180
    Code        Assembly        Alternative     Comment
181
    ----------------------------------------------------
182
    30  JUMP -0         HALT
183
    31  JUMP -1
184
    32  JUMP -2
185
    33  JUMP -3
186
    34  JUMP -4
187
    35  JUMP -5
188
    36  JUMP -6
189
    37  JUMP -7
190
    38  JUMP -8
191
    39  JUMP -9
192
    3A  JUMP -10
193
    3B  JUMP -11
194
    3C  JUMP -12
195
    3D  JUMP -13
196
    3E  JUMP -14
197
    3F  JUMP -15
198
    *)
199
    if (Instruction >= $30) and (Instruction <= $3F) then
200
    begin
201
      ProgramCounterNext := ProgramCounterCurrent - (Instruction and $F);
202
    end;
203
 
204
    (*
205
    ----------------------------------------------------
206
    Code        Assembly        Alternative     Comment
207
    ----------------------------------------------------
208
    40  SET A=0
209
    41  SET A=1
210
    42  SET A=2
211
    43  SET A=3
212
    44  SET A=4
213
    45  SET A=5
214
    46  SET A=6
215
    47  SET A=7
216
    48  SET A=8
217
    49  SET A=9
218
    4A  SET A=10
219
    4B  SET A=11
220
    4C  SET A=12
221
    4D  SET A=13
222
    4E  SET A=14
223
    4F  SET A=15
224
    *)
225
    if (Instruction >= $40) and (Instruction <= $4F) then
226
    begin
227
      FRegA := Instruction and $F;
228
    end;
229
 
230
    (*
231
    ----------------------------------------------------
232
    Code        Assembly        Alternative     Comment
233
    ----------------------------------------------------
234
    50
235
    51  SET B=A
236
    52  SET C=A
237
    53  SET D=A
238
    54  SET Dout=A
239
    55  SET Dout.0=A.0
240
    56  SET Dout.1=A.0
241
    57  SET Dout.2=A.0
242
    58  SET Dout.3=A.0
243
    59  SET PWM=A
244
    5A
245
    5B
246
    5C
247
    5D
248
    5E
249
    5F
250
    *)
251
    case Instruction of
252
      $51: FRegB := FRegA;     // SET B=A
253
      $52: FRegC := FRegA;     // SET C=A
254
      $53: FRegD := FRegA;     // SET D=A
255
      $54: FPortOut := FRegA;  // SET Dout=A
256
      $55: FPortOut := ((FRegA and 1) shl 0) + (PortOut and 14); // SET Dout.0=A.0
257
      $56: FPortOut := ((FRegA and 1) shl 1) + (PortOut and 13); // SET Dout.1=A.0
258
      $57: FPortOut := ((FRegA and 1) shl 2) + (PortOut and 11); // SET Dout.2=A.0
259
      $58: FPortOut := ((FRegA and 1) shl 3) + (PortOut and  7); // SET Dout.3=A.0
260
      $59: FPWM := FRegA;      // SET PWM=A
261
    end;
262
 
263
    (*
264
    ----------------------------------------------------
265
    Code        Assembly        Alternative     Comment
266
    ----------------------------------------------------
267
    60
268
    61  SET A=B
269
    62  SET A=C
270
    63  SET A=D
271
    64  SET A=Din
272
    65  SET A=Din.0
273
    66  SET A=Din.1
274
    67  SET A=Din.2
275
    68  SET A=Din.3
276
    69  SET A=AD1
277
    6A  SET A=AD2
278
    6B
279
    6C
280
    6D
281
    6E
282
    6F
283
    *)
284
    case Instruction of
285
      $61: FRegA := FRegB; // SET A=B
286
      $62: FRegA := FRegC; // SET A=C
287
      $63: FRegA := FRegD; // SET A=D
288
      $64: FRegA := DIn;  // SET A=Din
289
      $65: FRegA := (DIn and 1) shr 0;  // SET A=Din.0
290
      $66: FRegA := (DIn and 2) shr 1;  // SET A=Din.1
291
      $67: FRegA := (DIn and 4) shr 1;  // SET A=Din.2
292
      $68: FRegA := (DIn and 8) shr 1;  // SET A=Din.3
293
      $69: FRegA := AD1;
294
      $6A: FRegA := AD2;
295
    end;
296
 
297
    (*
298
    ----------------------------------------------------
299
    Code        Assembly        Alternative     Comment
300
    ----------------------------------------------------
301
    70
302
    71  SET A=A+1
303
    72  SET A=A-1
304
    73  SET A=A+B
305
    74  SET A=A-B
306
    75  SET A=A*B
307
    76  SET A=A/B
308
    77  SET A=A&B                       AND
309
    78  SET A=A|B                       OR
310
    79  SET A=A^B                       XOR
311
    7A  SET A=~A                        NOT
312
    7B
313
    7C
314
    7D
315
    7E
316
    7F
317
    *)
318
    case Instruction of
319
      $71: FRegA := FRegA + 1;      // SET A=A+1
320
      $72: FRegA := FRegA - 1;      // SET A=A-1
321
      $73: FRegA := FRegA + FRegB;   // SET A=A+B
322
      $74: FRegA := FRegA - FRegB;   // SET A=A-B
323
      $75: FRegA := FRegA * FRegB;   // SET A=A*B
324
      $76: begin
325
             if FRegB = 0 then
326
               FRegA := $F // this is the actual behavior of the microchip (program 40 51 45 76 54 30)
327
             else
328
               FRegA := FRegA div FRegB; // SET A=A/B
329
           end;
330
      $77: FRegA := FRegA and FRegB; // SET A=A&B                       AND
331
      $78: FRegA := FRegA  or FRegB; // SET A=A|B                       OR
332
      $79: FRegA := FRegA xor FRegB; // SET A=A^B                       XOR
333
      $7A: FRegA := not FRegA;      // SET A=~A                 NOT
334
    end;
335
 
336
    (*
337
    ----------------------------------------------------
338
    Code        Assembly        Alternative     Comment
339
    ----------------------------------------------------
340
    80  PAGE 0                          Page is used by JUMP, CALL, CTIMES and DTIMES
341
    81  PAGE 1
342
    82  PAGE 2
343
    83  PAGE 3
344
    84  PAGE 4
345
    85  PAGE 5
346
    86  PAGE 6
347
    87  PAGE 7
348
    88  PAGE 8
349
    89  PAGE 9
350
    8A  PAGE A
351
    8B  PAGE B
352
    8C  PAGE C
353
    8D  PAGE D
354
    8E  PAGE E
355
    8F  PAGE F
356
    *)
357
    if (Instruction >= $80) and (Instruction <= $8F) then
358
    begin
359
      FPage := Instruction and $F;
360
    end;
361
 
362
    (*
363
    ----------------------------------------------------
364
    Code        Assembly        Alternative     Comment
365
    ----------------------------------------------------
366
    90  JUMP <PAGE>0
367
    91  JUMP <PAGE>1
368
    92  JUMP <PAGE>2
369
    93  JUMP <PAGE>3
370
    94  JUMP <PAGE>4
371
    95  JUMP <PAGE>5
372
    96  JUMP <PAGE>6
373
    97  JUMP <PAGE>7
374
    98  JUMP <PAGE>8
375
    99  JUMP <PAGE>9
376
    9A  JUMP <PAGE>A
377
    9B  JUMP <PAGE>B
378
    9C  JUMP <PAGE>C
379
    9D  JUMP <PAGE>D
380
    9E  JUMP <PAGE>E
381
    9F  JUMP <PAGE>F
382
    *)
383
    if (Instruction >= $90) and (Instruction <= $9F) then
384
    begin
385
      ProgramCounterNext := (FPage shl 4) + (Instruction and $F);
386
    end;
387
 
388
    (*
389
    ----------------------------------------------------
390
    Code        Assembly        Alternative     Comment
391
    ----------------------------------------------------
392
    A0  CTIMES <PAGE>0                  IF C>0 THEN ( C=C-1 ; JUMP <PAGE>X ) ELSE CONTINUE
393
    A1  CTIMES <PAGE>1
394
    A2  CTIMES <PAGE>2
395
    A3  CTIMES <PAGE>3
396
    A4  CTIMES <PAGE>4
397
    A5  CTIMES <PAGE>5
398
    A6  CTIMES <PAGE>6
399
    A7  CTIMES <PAGE>7
400
    A8  CTIMES <PAGE>8
401
    A9  CTIMES <PAGE>9
402
    AA  CTIMES <PAGE>A
403
    AB  CTIMES <PAGE>B
404
    AC  CTIMES <PAGE>C
405
    AD  CTIMES <PAGE>D
406
    AE  CTIMES <PAGE>E
407
    AF  CTIMES <PAGE>F
408
    *)
409
    if (Instruction >= $A0) and (Instruction <= $AF) then
410
    begin
411
      if FRegC > 0 then
412
      begin
413
        Dec(FRegC);
414
        FReturnAddress     := ProgramCounterCurrent;
415
        ProgramCounterNext := (FPage shl 4) + (Instruction and $F);
416
      end;
417
    end;
418
 
419
    (*
420
    ----------------------------------------------------
421
    Code        Assembly        Alternative     Comment
422
    ----------------------------------------------------
423
    B0  DTIMES <PAGE>0                  IF D>0 THEN ( D=D-1 ; JUMP <PAGE>X ) ELSE CONTINUE
424
    B1  DTIMES <PAGE>1
425
    B2  DTIMES <PAGE>2
426
    B3  DTIMES <PAGE>3
427
    B4  DTIMES <PAGE>4
428
    B5  DTIMES <PAGE>5
429
    B6  DTIMES <PAGE>6
430
    B7  DTIMES <PAGE>7
431
    B8  DTIMES <PAGE>8
432
    B9  DTIMES <PAGE>9
433
    BA  DTIMES <PAGE>A
434
    BB  DTIMES <PAGE>B
435
    BC  DTIMES <PAGE>C
436
    BD  DTIMES <PAGE>D
437
    BE  DTIMES <PAGE>E
438
    BF  DTIMES <PAGE>F
439
    *)
440
    if (Instruction >= $B0) and (Instruction <= $BF) then
441
    begin
442
      if FRegD > 0 then
443
      begin
444
        Dec(FRegD);
445
        FReturnAddress     := ProgramCounterCurrent;
446
        ProgramCounterNext := (FPage shl 4) + (Instruction and $F);
447
      end;
448
    end;
449
 
450
    (*
451
    ----------------------------------------------------
452
    Code        Assembly        Alternative     Comment
453
    ----------------------------------------------------
454
    C0
455
    C1  SKIP_IF A>B
456
    C2  SKIP_IF A<B
457
    C3  SKIP_IF A=B
458
    C4  SKIP_IF Din.0=1
459
    C5  SKIP_IF Din.1=1
460
    C6  SKIP_IF Din.2=1
461
    C7  SKIP_IF Din.3=1
462
    C8  SKIP_IF Din.0=0
463
    C9  SKIP_IF Din.1=0
464
    CA  SKIP_IF Din.2=0
465
    CB  SKIP_IF Din.3=0
466
    CC  SKIP_IF S1=0
467
    CD  SKIP_IF S2=0
468
    CE  SKIP_IF S1=1
469
    CF  SKIP_IF S2=1
470
    *)
471
    case Instruction of
472
      $C1: if FRegA > FRegB then Inc(ProgramCounterNext);
473
      $C2: if FRegA < FRegB then Inc(ProgramCounterNext);
474
      $C3: if FRegA = FRegB then Inc(ProgramCounterNext);
475
      $C4: if ((Din and 1) shr 0) = 1 then Inc(ProgramCounterNext);
476
      $C5: if ((Din and 2) shr 1) = 1 then Inc(ProgramCounterNext);
477
      $C6: if ((Din and 4) shr 2) = 1 then Inc(ProgramCounterNext);
478
      $C7: if ((Din and 8) shr 3) = 1 then Inc(ProgramCounterNext);
479
      $C8: if ((Din and 1) shr 0) = 0 then Inc(ProgramCounterNext);
480
      $C9: if ((Din and 2) shr 1) = 0 then Inc(ProgramCounterNext);
481
      $CA: if ((Din and 4) shr 2) = 0 then Inc(ProgramCounterNext);
482
      $CB: if ((Din and 8) shr 3) = 0 then Inc(ProgramCounterNext);
483
      $CC: if S1 = false then Inc(ProgramCounterNext);
484
      $CD: if S2 = false then Inc(ProgramCounterNext);
485
      $CE: if S1 = true then Inc(ProgramCounterNext);
486
      $CF: if S2 = true then Inc(ProgramCounterNext);
487
    end;
488
 
489
    (*
490
    ----------------------------------------------------
491
    Code        Assembly        Alternative     Comment
492
    ----------------------------------------------------
493
    D0  CALL <PAGE>0
494
    D1  CALL <PAGE>1
495
    D2  CALL <PAGE>2
496
    D3  CALL <PAGE>3
497
    D4  CALL <PAGE>4
498
    D5  CALL <PAGE>5
499
    D6  CALL <PAGE>6
500
    D7  CALL <PAGE>7
501
    D8  CALL <PAGE>8
502
    D9  CALL <PAGE>9
503
    DA  CALL <PAGE>A
504
    DB  CALL <PAGE>B
505
    DC  CALL <PAGE>C
506
    DD  CALL <PAGE>D
507
    DE  CALL <PAGE>E
508
    DF  CALL <PAGE>F
509
    *)
510
    if (Instruction >= $D0) and (Instruction <= $DF) then
511
    begin
512
      FCalledOnce        := true;
513
      FReturnAddress     := ProgramCounterNext;
514
      ProgramCounterNext := (FPage shl 4) + (Instruction and $F)
515
    end;
516
 
517
    (*
518
    ----------------------------------------------------
519
    Code        Assembly        Alternative     Comment
520
    ----------------------------------------------------
521
    E0  RET
522
    *)
523
    if Instruction = $E0 then
524
    begin
525
      if not FCalledOnce then
526
      begin
527
        // "Freeze" is the behavior of the actual chip (see test program 41 54 27 42 54 27 E0 7A 27 54 33)
528
        ProgramCounterNext := ProgramCounterCurrent;
529
      end
530
      else
531
      begin
532
        ProgramCounterNext := FReturnAddress;
533
      end;
534
    end;
535
  finally
536
    FPC := ProgramCounterNext;
537
  end;
538
end;
539
 
540
procedure THT46F47.WaitMs(milliseconds: integer);
541
var
542
  i: integer;
543
begin
544
  for i := 0 to milliseconds div 10 do
545
  begin
546
    Sleep(10);
547
    Application.ProcessMessages;
548
    if Application.Terminated then break;
549
  end;
550
end;
551
 
552
end.