20
20
#include <stdlib.h>
21
21
#include <string.h>
22
22
23
+ #include "cbin.h"
23
24
#include "cpu6.h"
24
25
#include "disassemble.h"
25
26
@@ -447,6 +448,69 @@ static uint8_t block_op_getLen(int inst, int op) {
447
448
}
448
449
}
449
450
451
+ static void cbin_load_segment (uint16_t sa , uint16_t load_offset , unsigned trace )
452
+ {
453
+ uint8_t type = mmu_mem_read8 (sa );
454
+ uint8_t len = mmu_mem_read8 (sa + 1 );
455
+ uint16_t addr = mmu_mem_read16 (sa + 2 );
456
+ uint8_t checksum = type + len + (addr >> 8 ) + (addr & 0xFF );
457
+ uint8_t expected ;
458
+
459
+ if (trace )
460
+ fprintf (stderr , "%04X: cbin section @ %04X type %08X length %u addr %04X load_offset %04X\n" ,
461
+ cpu6_pc (), sa , type , len , addr , load_offset );
462
+
463
+ sa += 4 ;
464
+ alu_out &= ~ALU_L ;
465
+
466
+ switch (type )
467
+ {
468
+ case CBIN_DATA :
469
+ for (int i = 0 ; i < len ; i ++ ) {
470
+ uint8_t val = mmu_mem_read8 (sa ++ );
471
+
472
+ mmu_mem_write8 (load_offset + addr + i , val );
473
+ checksum += val ;
474
+ }
475
+ break ;
476
+ case CBIN_FIXUPS :
477
+ // Apply fixups
478
+ if (len % 2 == 1 ){
479
+ fprintf (stderr , "%04X: loadseg: FIXUPS record must have even length; have %u\n" , cpu6_pc (), len );
480
+ alu_out |= ALU_F ;
481
+ } else {
482
+ uint16_t offset = load_offset + addr ;
483
+
484
+ for (size_t i = 0 ; i < len ; i += 2 ) {
485
+ uint16_t fixup_addr = mmu_mem_read16 (sa );
486
+ uint16_t fixup_val = mmu_mem_read16 (fixup_addr + load_offset );
487
+
488
+ mmu_mem_write16 (fixup_addr + load_offset , fixup_val + offset );
489
+ checksum += (fixup_addr >> 8 ) + (fixup_addr & 0xFF );
490
+ sa += 2 ;
491
+ }
492
+ }
493
+ break ;
494
+ default :
495
+ fprintf (stderr , "%04X: unknown cbin segment type %02x\n" , cpu6_pc (), type );
496
+ alu_out |= ALU_F ;
497
+ }
498
+
499
+ checksum = 0x0100 - checksum ;
500
+ expected = mmu_mem_read8 (sa ++ );
501
+ if (checksum != expected ) {
502
+ fprintf (stderr , "%04X: loadseg checksum error: %08X vs %08X\n" ,
503
+ cpu6_pc (), checksum , expected );
504
+ alu_out |= ALU_F ;
505
+ }
506
+
507
+ // It looks like A is implicit here
508
+ regpair_write (A , load_offset + addr );
509
+ // loadseg operation modifies its second argument. For simplicity we
510
+ // assume only a register is valid.
511
+ regpair_write (twobit_cached_reg & 0xe , sa );
512
+ }
513
+
450
514
/*
451
515
* Block/String operations
452
516
*
@@ -460,7 +524,7 @@ static uint8_t block_op_getLen(int inst, int op) {
460
524
* Not all sub-ops take a length.
461
525
* Some sub-ops take additional args, as immediate or implicit reg
462
526
*/
463
- static int block_op (int inst )
527
+ static int block_op (int inst , unsigned trace )
464
528
{
465
529
unsigned op = fetch ();
466
530
unsigned am = op & 0x0F ;
@@ -491,6 +555,12 @@ static int block_op(int inst)
491
555
da = get_twobit (am , 1 , dst_len );
492
556
493
557
switch (op & 0xF0 ) {
558
+ case 0x00 :
559
+ // Load a segment of a binary file
560
+ // [sa] = destination offset
561
+ // da = a pointer to a segment
562
+ cbin_load_segment (da , mmu_mem_read16 (sa ), trace );
563
+ return 0 ;
494
564
case 0x20 :
495
565
// copies bytes from src to dst, stopping if a byte matches chr
496
566
// appears to be combined memcpy/memchr/strcpy
@@ -2412,15 +2482,15 @@ unsigned cpu6_execute_one(unsigned trace)
2412
2482
if (op == 0x46 )
2413
2483
return bignum_op ();
2414
2484
if (op == 0x47 )
2415
- return block_op (0x47 );
2485
+ return block_op (0x47 , trace );
2416
2486
if (op < 0x50 )
2417
2487
return alu4x_op ();
2418
2488
if (op == 0x66 )
2419
2489
return jsys_op ();
2420
2490
if (op < 0x60 )
2421
2491
return alu5x_op ();
2422
2492
if (op == 0x67 )
2423
- return block_op (0x67 );
2493
+ return block_op (0x67 , trace );
2424
2494
if (op < 0x70 )
2425
2495
return x_op ();
2426
2496
if (op == 0x77 || op == 0x78 )
0 commit comments