diff --git a/.gitattributes b/.gitattributes index d4de2ec5..4755f2db 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,6 +4,7 @@ *.vcproj binary *.exe binary *.bin binary +*.imd binary *.rim binary sim_rev.h export-subst diff --git a/PDQ-3/hdt/CPU_C5.bin b/PDQ-3/hdt/CPU_C5.bin new file mode 100644 index 00000000..b590d503 Binary files /dev/null and b/PDQ-3/hdt/CPU_C5.bin differ diff --git a/PDQ-3/master.imd b/PDQ-3/master.imd new file mode 100644 index 00000000..3a64eccc Binary files /dev/null and b/PDQ-3/master.imd differ diff --git a/PDQ-3/names.sim b/PDQ-3/names.sim new file mode 100644 index 00000000..6f075c69 --- /dev/null +++ b/PDQ-3/names.sim @@ -0,0 +1,174 @@ +name CSP:proc53 initdriver +name CSP:proc52 ExtractSegno +name CSP:proc51 getsib +name CSP:proc50 myselfer +name CSP:proc49 S_IOR_Set +name CSP:proc48 S_Read_Seg +name CSP:proc47 S_Chuck_G_Dir +name CSP:proc46 S_Finish_CU +name CSP:proc45 S_Execute_CU +name CSP:proc44 S_Geq_U +name CSP:proc43 S_Blow_Up +name CSP:proc42 S_Bump_Heap +name CSP:proc41 S_R_Mem_Avail +name CSP:proc40 S_Mem_Avail +name CSP:proc39 S_Halt +name CSP:proc38 S_Unit_Clear +name CSP:proc37 S_Unit_Wait +name CSP:proc36 S_Pwr_of_Ten +name CSP:proc35 S_Unit_Busy +name CSP:proc34 S_Io_Result +name CSP:proc33 S_Release +name CSP:proc32 S_Mark +name CSP:proc31 X_Sqrt +name CSP:proc30 X_Exp +name CSP:proc29 X_Ln +name CSP:proc28 S_Unload_Seg +name CSP:proc27 S_Load_Seg +name CSP:proc26 S_Unit_Status +name CSP:proc25 X_Sin +name CSP:proc24 S_Blk_Exit +name CSP:proc23 S_Attach +name CSP:proc22 S_Rel_Seg +name CSP:proc21 S_Get_Seg +name CSP:proc20 S_Stop_P +name CSP:proc19 S_Start_P +name CSP:proc18 S_Check +name CSP:proc17 S_Assign +name CSP:proc16 S_Geq_S +name CSP:proc15 S_Leq_S +name CSP:proc14 S_Equ_S +name CSP:proc13 S_New +name CSP:proc12 S_IO_Check +name CSP:proc11 S_Scan +name CSP:proc10 S_Fill_Char +name CSP:proc9 S_Time +name CSP:proc8 S_Tree_Search +name CSP:proc17 S_Id_Search +name CSP:proc6 S_Unit_Write +name CSP:proc5 S_Unit_Read +name CSP:proc4 S_Exit +name CSP:proc3 S_Move_Right +name CSP:proc2 S_Move_Left +name CSP:proc1 csp_initunit +name GOTOXYU:proc1 gotoxyu_initunit +name GOTOXYU:proc2 Z19_XY +name PASCALIO:proc1 pascalio_initunit +name PASCALIO:proc2 F_Read_Real +name PASCALIO:proc3 F_Write_Real +name PASCALIO:proc4 F_Seek +name LONGINT:proc1 longint_initunit +name LONGINT:proc2 F_Read_Dec +name LONGINT:proc3 F_Write_Dec +name LONGINT:proc4 Decops +name TRANSCEN:proc1 transcen_initunit +name TRANSCEN:proc2 S_Sin +name TRANSCEN:proc3 S_Cos +name TRANSCEN:proc4 S_Log10 +name TRANSCEN:proc5 S_Arctan +name TRANSCEN:proc6 S_Ln +name TRANSCEN:proc7 S_Exp +name TRANSCEN:proc8 S_Sqrt +name HEAPOPS:proc1 heapops_initunit +name HEAPOPS:proc2 H_Mark +name HEAPOPS:proc3 H_Release +name HEAPOPS:proc4 H_New +name HEAPOPS:proc5 H_Dispose +name HEAPOPS:proc6 H_Mem_Lock +name HEAPOPS:proc7 H_Mem_Swap +name HEAPOPS:proc8 H_Var_New +name HEAPOPS:proc9 H_Var_Dispose +name HEAPOPS:proc10 H_Var_Avail +name HEAPOPS:proc11 H_Unlock_Seg +name HEAPOPS:proc12 H_Clean_Up +name EXCEPTIO:proc1 exceptio_initunit +name EXCEPTIO:proc2 Handle_Exception +name EXCEPTIN:proc1 exceptin_initunit +name EXCEPTIN:proc2 Ex_Stats +name HALTUNIT:proc1 haltunit_initunit +name HALTUNIT:proc2 Do_Halt +name CLOCKDRI:proc1 clockdri_initunit +name CLOCKDRI:proc2 Clk_Init +name CLOCKDRI:proc3 Clk_Read +name CLOCKDRI:proc4 Clk_Write +name CLOCKDRI:proc5 Clk_Clear +name CLOCKDRI:proc6 Clk_Power +name CLOCKDRI:proc7 Clk_Status +name CLOCKDRI:proc8 Clk_Term +name DTCDRIVE:proc1 dtcdrive_initunit +name DTCDRIVE:proc2 Dtc_Init +name DTCDRIVE:proc3 Dtc_Read +name DTCDRIVE:proc4 Dtc_Write +name DTCDRIVE:proc5 Dtc_Clear +name DTCDRIVE:proc6 Dtc_Power +name DTCDRIVE:proc7 Dtc_Status +name DTCDRIVE:proc8 Dtc_Term +name DZ11DRIV:proc1 dz11driv_initunit +name DZ11DRIV:proc2 DZ_Init +name DZ11DRIV:proc3 DZ_Read +name DZ11DRIV:proc4 DZ_Write +name DZ11DRIV:proc5 DZ_Clear +name DZ11DRIV:proc6 DZ_Power +name DZ11DRIV:proc7 DZ_Status +name DZ11DRIV:proc8 DZ_Term +name FLOPPYDR:proc1 floppydr_initunit +name FLOPPYDR:proc2 Fl_Init +name FLOPPYDR:proc3 Fl_Read +name FLOPPYDR:proc4 Fl_Write +name FLOPPYDR:proc5 Fl_Clear +name FLOPPYDR:proc6 Fl_Power +name FLOPPYDR:proc7 Fl_Status +name FLOPPYDR:proc8 Fl_Term +name PRIAMDRI:proc1 priamdri_initunit +name PRIAMDRI:proc2 Prm_Init +name PRIAMDRI:proc3 Prm_Read +name PRIAMDRI:proc4 Prm_Write +name PRIAMDRI:proc5 Prm_Clear +name PRIAMDRI:proc6 Prm_Power +name PRIAMDRI:proc7 Prm_Status +name PRIAMDRI:proc8 Prm_Term +name RL02DRIV:proc1 rl02driv_initunit +name RL02DRIV:proc2 RL_Init +name RL02DRIV:proc3 RL_Read +name RL02DRIV:proc4 RL_Write +name RL02DRIV:proc5 RL_Clear +name RL02DRIV:proc6 RL_Power +name RL02DRIV:proc7 RL_Status +name RL02DRIV:proc8 RL_Term +name SERDRIVE:proc1 serdrive_initunit +name SERDRIVE:proc2 Ser_Init +name SERDRIVE:proc3 Ser_Read +name SERDRIVE:proc4 Ser_Write +name SERDRIVE:proc5 Ser_Clear +name SERDRIVE:proc6 Ser_Power +name SERDRIVE:proc7 Ser_Status +name SERDRIVE:proc8 Ser_Term +name STANDRIV:proc1 standriv_initunit +name STANDRIV:proc2 Stan_Init +name STANDRIV:proc3 Stan_Read +name STANDRIV:proc4 Stan_Write +name STANDRIV:proc5 Stan_Clear +name STANDRIV:proc6 Stan_Power +name STANDRIV:proc7 Stan_Status +name STANDRIV:proc8 Stan_Term +name SYSDRIVE:proc1 sysdrive_initunit +name SYSDRIVE:proc2 Intr_Init +name SYSDRIVE:proc3 Intr_Enable +name SYSDRIVE:proc4 Enter_HDT +name TM11DRIV:proc1 standriv_initunit +name TM11DRIV:proc2 TM_Init +name TM11DRIV:proc3 TM_Read +name TM11DRIV:proc4 TM_Write +name TM11DRIV:proc5 TM_Clear +name TM11DRIV:proc6 TM_Power +name TM11DRIV:proc7 TM_Status +name TM11DRIV:proc8 TM_Term +name SPOOLUNI:proc1 spooluni_initunit +name SPOOLUNI:proc2 Spool_Status +name SPOOLUNI:proc3 Spool_Restart +name SPOOLUNI:proc4 Spool_Stop +name SPOOLUNI:proc5 Spool_File +name SHELL:proc1 SHELL_initunit +name GETCMD:proc1 GETCMD_initunit +name SERDRIVE:proc9 SER_EnDis_RCVXMIT +name SERDRIVE:proc16 SER_RawEmit diff --git a/PDQ-3/opcode.dbg b/PDQ-3/opcode.dbg new file mode 100644 index 00000000..1dfa9a73 --- /dev/null +++ b/PDQ-3/opcode.dbg @@ -0,0 +1,232 @@ +0 0 ;SLDC0 +1 0 ;SLDC1 +2 0 ;SLDC2 +3 0 ;SLDC3 +4 0 ;SLDC4 +5 0 ;SLDC5 +6 0 ;SLDC6 +7 0 ;SLDC7 +8 0 ;SLDC8 +9 0 ;SLDC9 +a 0 ;SLDC10 +b 0 ;SLDC11 +c 0 ;SLDC12 +d 0 ;SLDC13 +e 0 ;SLDC14 +f 0 ;SLDC15 +10 0 ;SLDC16 +11 0 ;SLDC17 +12 0 ;SLDC18 +13 0 ;SLDC19 +14 0 ;SLDC20 +15 0 ;SLDC21 +16 0 ;SLDC22 +17 0 ;SLDC23 +18 0 ;SLDC24 +19 0 ;SLDC25 +1a 0 ;SLDC26 +1b 0 ;SLDC27 +1c 0 ;SLDC28 +1d 0 ;SLDC29 +1e 0 ;SLDC30 +1f 0 ;SLDC31 +20 0 ;SLDL1 +21 0 ;SLDL2 +22 0 ;SLDL3 +23 0 ;SLDL4 +24 0 ;SLDL5 +25 0 ;SLDL6 +26 0 ;SLDL7 +27 0 ;SLDL8 +28 0 ;SLDL9 +29 0 ;SLDL10 +2a 0 ;SLDL11 +2b 0 ;SLDL12 +2c 0 ;SLDL13 +2d 0 ;SLDL14 +2e 0 ;SLDL15 +2f 0 ;SLDL16 +30 0 ;SLDO1 +31 0 ;SLDO2 +32 0 ;SLDO3 +33 0 ;SLDO4 +34 0 ;SLDO5 +35 0 ;SLDO6 +36 0 ;SLDO7 +37 0 ;SLDO8 +38 0 ;SLDO9 +39 0 ;SLDO10 +3a 0 ;SLDO11 +3b 0 ;SLDO12 +3c 0 ;SLDO13 +3d 0 ;SLDO14 +3e 0 ;SLDO15 +3f 0 ;SLDO16 +40 3 ; +41 3 ; +42 3 ; +43 3 ; +44 3 ; +45 3 ; +46 3 ; +47 3 ; +48 3 ; +49 3 ; +4a 3 ; +4b 3 ; +4c 3 ; +4d 3 ; +4e 3 ; +4f 3 ; +50 3 ; +51 3 ; +52 3 ; +53 3 ; +54 3 ; +55 3 ; +56 3 ; +57 3 ; +58 3 ; +59 3 ; +5a 3 ; +5b 3 ; +5c 3 ; +5d 3 ; +5e 3 ; +5f 3 ; +60 3 ; +61 3 ; +62 3 ; +63 3 ; +64 3 ; +65 3 ; +66 3 ; +67 3 ; +68 3 ; +69 3 ; +6a 3 ; +6b 3 ; +6c 3 ; +6d 3 ; +6e 3 ; +6f 3 ; +70 3 ; +71 3 ; +72 3 ; +73 3 ; +74 3 ; +75 3 ; +76 3 ; +77 3 ; +78 0 ;SIND0 +79 0 ;SIND1 +7a 0 ;SIND2 +7b 0 ;SIND3 +7c 0 ;SIND4 +7d 0 ;SIND5 +7e 0 ;SIND6 +7f 0 ;SIND7 +80 0 ;LDCB +81 0 ;LDCI +82 0 ;LCA +83 0 ;LDC +84 0 ;LLA +85 3 ;LDO +86 0 ;LAO +87 0 ;LDL +88 0 ;LDA +89 0 ;LOD +8a 0 ;UJP +8b 0 ;UJPL +8c 0 ;MPI +8d 0 ;DVI +8e 0 ;STM +8f 0 ;MODI +90 0 ;CPL +91 0 ;CPG +92 0 ;CPI +93 0 ;CXL +94 0 ;CXG +95 0 ;CXI +96 0 ;RPU +97 0 ;CPF +98 0 ;LDCN +99 0 ;LSL +9a 3 ;LDE +9b 3 ;LAE +9c 0 ;NOP +9d 0 ;LPR +9e 3 ;BPT +9f 0 ;BNOT +a0 0 ;LOR +a1 0 ;LAND +a2 0 ;ADI +a3 0 ;SBI +a4 0 ;STL +a5 0 ;SRO +a6 0 ;STR +a7 0 ;LDB +a8 3 ; +a9 3 ; +aa 3 ; +ab 3 ; +ac 3 ; +ad 3 ; +ae 3 ; +af 3 ; +b0 0 ;EQUI +b1 0 ;NEQI +b2 0 ;LEQI +b3 0 ;GEQI +b4 0 ;LEUSW +b5 0 ;GEUSW +b6 0 ;EQUPWR +b7 0 ;LEQPWR +b8 0 ;GEQPWR +b9 0 ;EQUBYT +ba 3 ;LEQBYT +bb 3 ;GEQBYT +bc 0 ;SRS +bd 3 ;SWAP +be 3 ;TNC +bf 3 ;RND +c0 3 ;ADR +c1 3 ;SBR +c2 3 ;MPR +c3 0 ;DVR +c4 0 ;STO +c5 0 ;MOV +c6 3 ;DUP2 +c7 0 ;ADJ +c8 0 ;STB +c9 0 ;LDP +ca 0 ;STP +cb 0 ;CHK +cc 0 ;FLT +cd 0 ;EQUREAL +ce 0 ;LEQREAL +cf 3 ;GEQREAL +d0 0 ;LDM +d1 0 ;SPR +d2 3 ;EFJ +d3 3 ;NFJ +d4 0 ;FJP +d5 0 ;FJPL +d6 0 ;XJP +d7 0 ;IXA +d8 0 ;IXP +d9 3 ;STE +da 0 ;INN +db 0 ;UNI +dc 0 ;INT +dd 0 ;DIF +de 0 ;SIGNAL +df 0 ;WAIT +e0 3 ;ABI +e1 0 ;NGI +e2 0 ;DUP1 +e3 3 ;ABR +e4 3 ;NGR +e5 0 ;LNOT +e6 0 ;IND +e7 0 ;INC diff --git a/PDQ-3/pdq3_cpu.c b/PDQ-3/pdq3_cpu.c new file mode 100644 index 00000000..dab8e464 --- /dev/null +++ b/PDQ-3/pdq3_cpu.c @@ -0,0 +1,1733 @@ +/* + Work derived from Copyright (c) 2004-2012, Robert M. Supnik + PDQ-3 related code Copyright (c) 2013 Holger Veit + + 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 + ROBERT M SUPNIK 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 names of Robert M Supnik and Holger Veit + shall not be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik and Holger Veit. + + 2013xxxx hv initial version (written up to the level to be tested against bootloader) + 20130826 hv fix problem in SPR(-1): taskswitch mustn't modify sp afterwards + 20130901 hv CXG didn't store correct callers seg# in MSCW + 20130903 hv fix wrong stackspace calculation in createmscw + 20130908 hv Segment refcount was not decremented correctly in RPU + 20130914 hv Degredation in SRS instruction + 20130914 hv SPR didn't set registers correctly; mustn't adjust modified SP again + 20130921 hv Rewrite of memory/io handling to allow adding of QBUS devices, + prevent buserror by cpu_ex prefetch and attempts to write to HDT rombased TIB + 20130921 hv WAIT/SIGNAL enque used the wrong queue address + 20130927 hv Defect in WAIT overwriting semaphore queue with its own address + 20131012 hv Previous fix was wrong: WAIT mustn't store qhead back unless it changed + 20131019 hv WAIT doesn't always discard argument, error in specification + 20131019 hv SIGNAL has same problem as WAIT when storing back qhead + 20131103 hv Interrupt idle loop didn't process simh queue + 20131110 hv A really hard one: INT 3 (RCV CONSOLE) incremented waiter sema, because + interrupt changed reg_intpending within a WAIT. Need to latch interrupt before + execution and process afterwards +*/ + +#include "pdq3_defs.h" + + +/* some simulator publics */ +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_boot(int32 unitnum, DEVICE *dptr); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_size (FILE *st, UNIT *uptr, int32 val, void *desc); + +/* some forwards */ +static t_stat Raise(uint16 err); +static uint16 Pop(); +static void Push(uint16 val); +static int16 PopS(); +static void PushS(int16 val); +static uint16 createMSCW(uint16 ptbl, uint8 procno, uint16 stat, uint8 segno, uint16 osegb); +static uint16 enque(uint16 qhead, uint16 qtask); /* return new qhead */ +static uint16 deque(uint16 qhead, uint16 *qtask); /* return tail of queue */ +static t_stat DoSIGNAL(uint16 sem); +static uint16 Get(t_addr addr); +static void Put(t_addr addr, uint16 val); +static uint16 GetSIB(uint8 segno); +static t_stat cpu_set_flag(UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_noflag(UNIT *uptr, int32 value, char *cptr, void *desc); + +static t_stat ssr_read(t_addr ioaddr, uint16 *data); +static t_stat ssr_write(t_addr ioaddr, uint16 data); +static t_stat ses_read(t_addr ioaddr, uint16 *data); +static t_stat cpu_readserial(t_addr dummy, uint16 *data); +static t_stat rom_baseread(t_addr dummy, uint16 *data); +static t_stat rom_ignore(t_addr ea, uint16 data); + +/* the CPU registers */ +uint16 reg_ipc; /* point to current instruction within reg_segb segment */ +uint16 reg_sp; +uint16 reg_splow; +uint16 reg_spupr; +uint16 reg_mp; +uint16 reg_bp; +uint16 reg_segb; /* point to current code segment */ +uint16 reg_ctp; +uint16 reg_rq; +uint16 reg_ssv; +uint16 reg_lm; +uint16 reg_lsv; +uint32 reg_intpending; +uint32 reg_intlatch; +uint16 reg_ssr = 0; /* system status register */ +uint16 reg_ses = 0; /* system environment switch */ +uint16 reg_cpuserial = 0; /* CPU serial number */ + +/* PC address of currently executed instruction */ +t_addr PCX; + +uint16 reg_fc68 = 0; /* location of HDT boot ROM */ +uint16 reg_romsize = 0; /* size of HDT boot ROM */ + +/* possible hack to enforce DMA being initialized to 0x2000 (word address) + * the boot code from Don Maslin's PDQ-3 floppy implies it is run from 0x2000 */ +uint32 reg_dmabase = 0x2000; + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BINK, MEMSIZE) }; +REG cpu_reg[] = { + /* must be at location 0: This is to display the combined segb:ipc address, + refers to start of currently executed instruction. Refer to STATE to + see actual IPC value */ + { HRDATA (PC, PCX, 32), REG_RO|REG_HIDDEN }, + + { HRDATA (SEGB, reg_segb, 16) }, + { HRDATA (IPC, reg_ipc, 16) }, + + { HRDATA (SP, reg_sp, 16) }, + { HRDATA (SPLOW, reg_splow, 16) }, + { HRDATA (SPUPR, reg_spupr, 16) }, + + { HRDATA (MP, reg_mp, 16) }, + { HRDATA (BP, reg_bp, 16) }, + { HRDATA (CTP, reg_ctp, 16) }, + { HRDATA (RQ, reg_rq, 16) }, + { HRDATA (SSV, reg_ssv, 16) }, + + { HRDATA (_LM, reg_lm, 16), REG_HIDDEN }, + { HRDATA (_LSV, reg_lsv, 16), REG_HIDDEN }, + { HRDATA (_SSR, reg_ssr, 8), REG_HIDDEN }, + { HRDATA (_SES, reg_ses, 8), REG_HIDDEN }, + { HRDATA (_INT, reg_intpending, 32), REG_HIDDEN }, + { HRDATA (_FC68, reg_fc68, 16 ), REG_RO|REG_HIDDEN }, + { HRDATA (_INITLOC,reg_dmabase, 17 ), REG_RO|REG_HIDDEN }, + + { HRDATA (_ROMSZ, reg_romsize, 16 ), REG_RO|REG_HIDDEN }, + { HRDATA (_CPUSERIAL, reg_cpuserial, 16), REG_HIDDEN }, + + { NULL } +}; +MTAB cpu_mod[] = { + { UNIT_MSIZE, 0, NULL, "32K", &cpu_set_size, NULL }, + { UNIT_MSIZE, 1, NULL, "64K", &cpu_set_size, NULL }, + { UNIT_PASEXC, UNIT_PASEXC, "halt on EXC", "EXC", &cpu_set_flag, NULL }, + { UNIT_PASEXC, 0, "no EXC", NULL, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, UNIT_PASEXC, NULL, "NOEXC", &cpu_set_noflag, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", NULL, &show_iobase }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", NULL, &show_iovec }, + { MTAB_XTD|MTAB_VDV, 0, "PRIO", "PRIO", NULL, &show_ioprio }, + { 0 } +}; + +DEBTAB cpu_dflags[] = { + { "INT", DBG_CPU_INT }, + { "INT2", DBG_CPU_INT2 }, + { "WRITE", DBG_CPU_WRITE }, + { "READ", DBG_CPU_READ }, + { "FETCH", DBG_CPU_FETCH }, + { "STACK", DBG_CPU_STACK }, + { "CONC", DBG_CPU_CONC }, + { "CONC2", DBG_CPU_CONC2 }, + { "CONC3", DBG_CPU_CONC3 }, + { 0, 0 } +}; + +IOINFO cpu_ioinfo1 = { NULL, SSR_IOBASE, 1, SES_BERR_VEC, 0, ssr_read, ssr_write }; +IOINFO cpu_ioinfo2 = { &cpu_ioinfo1, SES_IOBASE, 1, SES_PWRF_VEC, 1, ses_read, rom_ignore }; +IOINFO cpu_ioinfo3 = { &cpu_ioinfo2, ROM_BASE, 1, 0, -1, rom_baseread, rom_ignore }; +IOINFO cpu_ioinfo4 = { &cpu_ioinfo3, ROM, ROM_SIZE, 0, -1, rom_read, rom_ignore }; +IOINFO cpu_ioinfo5 = { &cpu_ioinfo4, CPU_SERIALNO, 1, 0, -1, cpu_readserial, rom_ignore }; +DEVCTXT cpu_ctxt = { &cpu_ioinfo5 }; + +DEVICE cpu_dev = { + "CPU", /*name*/ + &cpu_unit, /*units*/ + cpu_reg, /*registers*/ + cpu_mod, /*modifiers*/ + 1, /*numunits*/ + 16, /*aradix*/ + 32, /*awidth*/ + 1, /*aincr*/ + 16, /*dradix*/ + 16, /*dwidth*/ + &cpu_ex, /*examine*/ + &cpu_dep, /*deposit*/ + &cpu_reset, /*reset*/ + &cpu_boot, /*boot*/ + NULL, /*attach*/ + NULL, /*detach*/ + &cpu_ctxt, /*ctxt*/ + DEV_DEBUG, /*flags*/ + 0, /*dctrl*/ + cpu_dflags, /*debflags*/ + NULL, /*msize*/ + NULL /*lname*/ +}; + +/* return start address of proctbl of current code segment */ +static uint16 GetPtbl() { + uint16 ptbl; + Read(reg_segb, 0, &ptbl, DBG_NONE); + return reg_segb + ptbl; +} + +/* return segment base of segment */ +static uint16 GetSegbase(uint8 segno) { + uint16 data, sib; + sib = GetSIB(segno); + Read(sib,OFF_SEGBASE, &data, DBG_NONE); + return data; +} + +/* get segment# from code segment: + * this is the first byte of the proctbl at the end of the code segment + *(the second byte is the proc count) */ +static uint8 GetSegno() { + uint16 data; + uint16 ptbl = GetPtbl(); + ReadB(ptbl, 0, &data, DBG_NONE); /* get first byte from proctbl */ + return (uint8)data; +} + +/* set SEGB and return address of proc tbl (optimization for segb + segb[0] ) */ +static uint16 SetSEGB(uint8 segno) { + /* obtain pointer to SIB for segno */ + uint16 sib = GetSIB(segno); + + /* set SEGB and get pointer to proc tbl */ + Read(sib, OFF_SEGBASE, ®_segb, DBG_NONE); + return GetPtbl(); +} + +static void AdjustRefCount(uint8 segno, int incr) { + uint16 sib = GetSIB(segno); + uint16 ref = Get(sib + OFF_SEGREFS); + Put(sib + OFF_SEGREFS, ref + incr); + //printf("ref(%x) %s = %d\n",segno,incr>0 ? "increment":"decrement", ref+incr); +} + +/* save CPU regs into TIB */ +static void save_to_tib() { + Write(reg_ctp, OFF_SP, reg_sp, DBG_NONE); + Write(reg_ctp, OFF_MP, reg_mp, DBG_NONE); + Write(reg_ctp, OFF_BP, reg_bp, DBG_NONE); + Write(reg_ctp, OFF_IPC, reg_ipc, DBG_NONE); + Write(reg_ctp, OFF_SEGB, reg_segb, DBG_NONE); +} + +/* restore CPU regs from TIB */ +static void restore_from_tib() { + Read(reg_ctp, OFF_SP, ®_sp, DBG_NONE); + Read(reg_ctp, OFF_SPLOW, ®_splow, DBG_NONE); + Read(reg_ctp, OFF_SPUPR, ®_spupr, DBG_NONE); + Read(reg_ctp, OFF_MP, ®_mp, DBG_NONE); + Read(reg_ctp, OFF_BP, ®_bp, DBG_NONE); + Read(reg_ctp, OFF_IPC, ®_ipc, DBG_NONE); + Read(reg_ctp, OFF_SEGB, ®_segb, DBG_NONE); +} + +/* initialize registers for boot */ +void cpu_setRegs(uint16 newctp, uint16 newssv, uint16 newrq) +{ + reg_ctp = newctp; + reg_ssv = newssv; + reg_rq = newrq; + restore_from_tib(); +// if (sim_deb) dbg_dump_tib(sim_deb, reg_ctp); + + /* initialize the simh PC */ + PCX = MAKE_BADDR(reg_segb,reg_ipc); +} + +/* this is a dummy routine to ignore invalid writes to the ROM + * which occur during context switch from HDT to boot loader */ +static t_stat rom_ignore(t_addr ea, uint16 data) { + return SCPE_OK; +} + +/* this is the central point to explain the various methods of booting. + * 1. boot from ROM: + * if (0xfc68) == 0 then try method 2 + * else + * MR := (0xfc68) + * CTP := (MR) -> set TIB + * SSV := (MR+1) -> segment dictionary pointer + * RQ := (MR+2) -> request queue + * SEGB := CTP->segb + * load SP, MP, BP, IPC from TIB + * run + * 2. boot from floppy: + * load first track via autoload at reg_dmabase + * CTP := reg_dmabase + * if CTP->sibvec == NIL then + * SSV := unknown + * RQ := CTP->waitq + * SEGB := CTP->segb + * load SP, MP, BP, IPC from TIB + * else + * SSV := CTP->sibvec + * RQ := CTP->waitq + * SEGB := ((SEGB)) // double deref + * load SP, MP, BP, IPC from TIB + * run + * + * This is not fully compliant with W9693_PasIII_OSRef_Jul82, but matches + * the different boot sectors I found. + */ +t_stat cpu_boot(int32 unitnum, DEVICE *dptr) { + t_stat rc; + uint16 ctp, ssv, rq; + printf("BOOT CPU\n"); + cpu_reset(dptr); + dbg_init(); + + /* boot from external ROM? */ + if (reg_fc68 != 0) { +// printf("Booting from HDT ROM\n"); + /* cf. WD9593_PasIII_OSRef_Jul82.pdf */ + Read(reg_fc68, 0, &ctp, DBG_NONE); + Read(reg_fc68, 1, &ssv, DBG_NONE); + Read(reg_fc68, 2, &rq, DBG_NONE); + cpu_setRegs(ctp, ssv, rq); + } else { + /* autoload the 1st track into meory at reg_dmabase */ + if ((rc = fdc_dev.boot(0, &fdc_dev)) != SCPE_OK) return rc; + } + return SCPE_OK; +} + +void cpu_finishAutoload() { + uint16 ssv, rq, sbase; + uint16 ctp = reg_dmabase; + Read(ctp, OFF_SIBS, &ssv, DBG_NONE); + Read(ctp, OFF_WAITQ, &rq, DBG_NONE); + cpu_setRegs(ctp, ssv, rq); + if (ssv != NIL) { + Read(reg_segb, 0, &sbase, DBG_NONE); /* reg_segb is a pointer into sibvec, sbase points to SIB */ + Read(sbase, OFF_SEGBASE, ®_segb, DBG_NONE); /* reg_segb is segbase from SIB entry */ + } +} + +/* CPU reset */ +t_stat cpu_reset (DEVICE *dptr) { + printf("CPU RESET\n"); + sim_brk_types = SWMASK('E')|SWMASK('R')|SWMASK('W'); + sim_brk_dflt = SWMASK('E'); + + /* initialize I/O system, and register standard IO handlers */ + pdq3_ioinit(); + add_ioh(((DEVCTXT*)dptr->ctxt)->ioi); + + /* reset important CPU registers */ + reg_ctp = NIL; + reg_intpending = 0; + reg_intlatch = 0; + PCX = reg_ipc = 0; + + return SCPE_OK; +} + +/* Memory examine */ +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { + uint16 data; + t_addr off = ADDR_OFF(addr); + t_addr seg = ADDR_SEG(addr); + if (seg==0) seg = NIL; + addr = MAKE_BADDR(seg,off); + +// printf("Examine: addr=%x seg=%x off=%x\n",addr,seg,off); +// printf("sw=%x, isword=%d\n",sw, ADDR_ISWORD(addr)); + if (ADDR_ISWORD(addr) || (sw & SWMASK('W'))) { +// printf("addr=%x seg=%x off=%x\n",addr,seg,off); + if (off >= memorysize || + ReadEx(off, 0, &data) != SCPE_OK) return SCPE_IOERR; + } else if (!ADDR_ISWORD(addr) || (sw & SWMASK('B'))) { + if ((seg*2 + off) >= (2*memorysize) || + ReadBEx(seg, off, &data) != SCPE_OK) return SCPE_IOERR; + } + if (vptr) + *vptr = data; + return SCPE_OK; +} + +/* Memory deposit */ +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + t_addr off = ADDR_OFF(addr); + t_addr seg = ADDR_SEG(addr); + if (seg==0) seg = NIL; + addr = MAKE_BADDR(seg,off); + + if (ADDR_ISWORD(addr) || (sw & SWMASK('W'))) { + if (off >= memorysize || + Write(off, 0, val, 0) != SCPE_OK) return SCPE_ARG; + } else { + if (!ADDR_ISWORD(addr) || (sw & SWMASK('B'))) { + if ((seg*2 + off) >= (2*memorysize) || + WriteB(seg, off, val, 0)) return SCPE_ARG; + } + } + return SCPE_OK; +} + +t_stat cpu_buserror() { + reg_ssr |= SSR_BERR; + return cpu_raiseInt(INT_BERR); +} + +static t_stat ssr_read(t_addr ioaddr, uint16 *data) { + *data = reg_ssr & ~(SSR_PRNT|SSR_BIT3); + return SCPE_OK; +} + +static t_stat ssr_write(t_addr ioaddr, uint16 data) { + if (isbitset(data,SSR_BERR)) { + clrbit(reg_ssr,SSR_BERR); + sim_debug(DBG_CPU_INT2, &cpu_dev, DBG_PCFORMAT1 "Clear BERR\n", DBG_PC); + } + if (isbitset(data,SSR_TICK)) { + clrbit(reg_ssr,SSR_TICK); + sim_debug(DBG_CPU_INT2, &cpu_dev, DBG_PCFORMAT1 "Acknowledge TICK\n", DBG_PC); + } + if (isbitset(data,SSR_INTVL)) { + clrbit(reg_ssr,SSR_INTVL); + sim_debug(DBG_CPU_INT2, &cpu_dev, DBG_PCFORMAT1 "Acknowledge INTVL\n", DBG_PC); + } + if (isbitset(data,SSR_BIT3)) + printf("Warning: Attempt to set SSR bit 3\n"); + if (isbitset(data,SSR_PWRF)) { + clrbit(reg_ssr,SSR_PWRF); + sim_debug(DBG_CPU_INT2, &cpu_dev, DBG_PCFORMAT1 "Acknowledge PWRF\n", DBG_PC); + } + clrbit(reg_ssr,SSR_PRNT|SSR_INTEN); + setbit(reg_ssr,data & (SSR_PRNT|SSR_INTEN)); + sim_debug(DBG_CPU_INT, &cpu_dev, DBG_PCFORMAT2 "%sable Interrupt system\n", + DBG_PC, isbitset(reg_ssr,SSR_INTEN) ? "En" : "Dis"); + + if (data & SSR_INIT) { + sim_debug(DBG_CPU_INT2, &cpu_dev, DBG_PCFORMAT1 "Bus Reset BINIT\n", DBG_PC); + /* @TODO: send binit also to a future HDC */ + fdc_binit(); + con_binit(); + } + return SCPE_OK; +} + +static t_stat ses_read(t_addr ioaddr, uint16 *data) +{ + *data = reg_ses; +// printf("ses is %x\n",reg_ses); + return SCPE_OK; +} + +static t_stat cpu_readserial(t_addr dummy, uint16 *data) +{ + *data = reg_cpuserial; + return SCPE_OK; +} + +static t_stat rom_baseread(t_addr dummy, uint16 *data) +{ + *data = reg_fc68; + return SCPE_OK; +} + +/************************************************************************************* + * Interrupt handling + ************************************************************************************/ +static uint16 int_vectors[32] = { + 0x0002, /* INT_BERR */ + 0x0006, /* INT_PWRF */ + 0x000a, /* INT_DMAFD */ + 0x000e, /* INT_CONR */ + 0x0012, /* INT_CONT */ + 0x0016, /* INT_PRNT */ + 0x001a, /* INT_SCLK */ + 0x001e, /* INT_INTVL */ + NIL +}; + +t_bool cpu_isIntEnabled() { + return reg_ssr & SSR_INTEN; +} + +/* latch interrupts */ +void cpu_assertInt(int level, t_bool tf) { + uint16 bit = 1 << level; + if (tf) + setbit(reg_intlatch, bit); + else + clrbit(reg_intlatch, bit); + sim_debug(DBG_CPU_INT2, &cpu_dev, DBG_PCFORMAT1 "%sssert Interrupt Level %d\n", + DBG_PC, tf?"A":"Dea", level); +} + +t_stat cpu_raiseInt(int level) { + uint16 vector = int_vectors[level]; + + if (level > 15) { + printf("Implementation error: raiseInt with level>15! Need fix\n"); + exit(1); + } + + if (!cpu_isIntEnabled()) return STOP_ERRIO; /* interrupts disabled, or invalid vector */ + + cpu_assertInt(level, TRUE); + return SCPE_OK; +} + +static void cpu_ackInt(int level) { + uint16 bit = 1<31) return SCPE_ARG; + int_vectors[level] = vec; + return SCPE_OK; +} + +static int getIntLevel() { + int i; + uint32 bit = 1; + for (i=0; i<31; i++) { + if (reg_intpending & bit) return i; + bit <<= 1; + } + return -1; +} + +static t_stat cpu_processInt() { + int level = getIntLevel(); /* obtain highest pending interupt */ + uint16 vector, sem; + t_stat rc; + + if (level == -1) return SCPE_OK; /* don't signal: spurious interrupt */ + + vector = int_vectors[level]; + if (vector == NIL) return SCPE_OK; + + save_to_tib(); /* save current context into ctp */ + reg_rq = enque(reg_rq, reg_ctp); /* put current task into rq queue */ + + reg_ctp = NIL; /* set no active task (marker for int processing in SIGNAL) */ + sem = Get(vector); /* get semaphore from interrupt vector */ + sim_debug(DBG_CPU_INT, &cpu_dev, DBG_PCFORMAT2 "processInt: level=%d vector=$%04x sema=$%04x\n", + DBG_PC,level,vector,sem); + + cpu_ackInt(level); /* acknowledge this interrupt */ + rc = DoSIGNAL(sem); /* process SIGNAL, i.e. check semaphore at interrupt vector */ + return rc; +} + +/************************************************************************************* + * instruction interpreter + ************************************************************************************/ + +static uint16 UB() { + uint16 val; + ReadB(reg_segb, reg_ipc++, &val, DBG_CPU_FETCH); + return val; +} +static uint16 W() { + uint16 high, data; + if (ReadB(reg_segb, reg_ipc++, &data, DBG_CPU_FETCH) != SCPE_OK) + return data; + if (ReadB(reg_segb, reg_ipc++, &high, DBG_CPU_FETCH) != SCPE_OK) + return high; + data |= (high << 8); + return data; +} +static uint16 DB() { + return UB(); +} +static uint16 SB() { + uint16 data; + ReadB(reg_segb, reg_ipc++, &data, DBG_CPU_FETCH); + if (data & 0x80) data |= 0xff80; + return data; +} +static uint16 B() { + uint16 high, data; + if (ReadB(reg_segb, reg_ipc++, &high, DBG_CPU_FETCH) != SCPE_OK) + return high; + if (high & 0x80) { + if (ReadB(reg_segb, reg_ipc++, &data, DBG_CPU_FETCH) != SCPE_OK) + return high; + data |= ((high & 0x7f) << 8); + return data; + } else + return high; +} +static void Put(t_addr addr, uint16 val) { + Write(0, addr, val, DBG_CPU_WRITE); +} +static uint16 Get(t_addr addr) { + uint16 val; + Read(0, addr, &val, DBG_CPU_READ); + return val; +} + +static void Putb(t_addr base, t_addr idx, uint16 val) { + WriteB(base, idx, val, DBG_CPU_WRITE); +} + +static uint16 Getb(t_addr addr,t_addr idx) { + uint16 val; + ReadB(addr, idx, &val, DBG_CPU_READ); + return val; +} + +static uint16 TraverseMSstat(uint16 db) { + int i; + uint16 lm = reg_mp; + for(i=1; i<=db; i++) lm = Get(lm + OFF_MSSTAT); + return lm; +} + +static uint16 Tos() { + uint16 val; + if (reg_sp >= reg_spupr) { Raise(PASERROR_STKOVFL); return 0; } + Read(0,reg_sp,&val, DBG_CPU_PICK); + return val; +} + +static uint16 Pick(int i) { + uint16 val; + if ((reg_sp+i) >= reg_spupr) { Raise(PASERROR_STKOVFL); return 0; } + Read(0,reg_sp+i,&val, DBG_CPU_PICK); + return val; +} + +static uint16 Pop() { + uint16 val; + if ((reg_sp+1) > reg_spupr) { Raise(PASERROR_STKOVFL); return 0; } + Read(0,reg_sp++,&val, DBG_CPU_POP); + return val; +} + +static void Push(uint16 val) { + if (reg_sp < reg_splow) Raise(PASERROR_STKOVFL); + else + Write(0,--reg_sp,val,DBG_CPU_PUSH); +} + +static int16 PopS() { + return (int16)Pop(); +} + +static void PushS(int16 val) { + Push((uint16)val); +} + +static float PopF() { + T_FLCVT t; + t.i[1] = Pop(); + t.i[0] = Pop(); +// printf("POPF: %.6e\n",t.f); + return t.f; +}; + +static void PushF(float f) { + T_FLCVT t; + t.f = f; +// printf("PUSHF: %.6e\n",t.f); + Push(t.i[0]); + Push(t.i[1]); +} + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +static uint16 masks[] = { +0x0000, +0x0001, 0x0003, 0x0007, 0x000f, +0x001f, 0x003f, 0x007f, 0x00ff, +0x01ff, 0x03ff, 0x07ff, 0x0fff, +0x1fff, 0x3fff, 0x7fff, 0xffff +}; +/* to produce a mask for a bit field , + * e.g. <3:5> 0000000011111000 == 0x00f8 + */ +static uint16 GetMask(int lowbit,int nbits) { + return masks[nbits] << lowbit; +} + +/* get address of SIB entry of segment */ +static uint16 GetSIB(uint8 segno) { + return segno < 128 ? + Get(reg_ssv + segno) : + Get(Get(reg_ctp + OFF_SIBS) + segno - 128); +} + +/* do a CXG instruction into segment SEGNO to procedure procno */ +static float DoCXG(uint16 segno, uint16 procno) { + uint16 ptbl; + uint16 osegno = GetSegno(); /* obtain segment of caller to be set into MSCW */ + uint16 osegb = reg_segb; + +// printf("CXG: seg=%d proc=%d, osegno=%d\n",segno,procno,osegno); + ptbl = SetSEGB(segno); /* get ptbl of new segment */ + AdjustRefCount(segno,1); + +// printf("CXG: ptbl=%x, reg_segb=%x\n",ptbl,reg_segb); + reg_ipc = createMSCW(ptbl, procno, reg_bp, osegno, osegb); /* call new segment */ + return 63.2; +} + +static t_stat Raise(uint16 err) { + + /* HALT on Pascal Exception? */ + if (Q_PASEXC) return STOP_PASEXC; + + /* push error code + * attention: potential double fault: STKOVFL */ + if (err==PASERROR_STKOVFL) + Write(0,reg_sp,err,TRUE); + else + Push(err); + sim_debug(DBG_CPU_INT, &cpu_dev, DBG_PCFORMAT2 "Raised Pascal Exception #%d\n",DBG_PC,err); + + /* call OS trap handler + * Note: if an exception occurs in boot loader (CHK instruction for CPU serial), + * this goes to nirvana because HALTUNIT is not yet linked correctly */ + sim_interval -= DoCXG(2,2); + return SCPE_OK; +} + +static int GetBit(t_addr base, int bitno) +{ + int wnum = bitno / WORD_SZ; + int bnum = bitno % WORD_SZ; + uint16 bitmask = 1 << bnum; + return (Get(base + wnum) & bitmask) ? 1 : 0; +} + +static uint16 createMSCW(uint16 ptbl, uint8 procno, uint16 stat, uint8 segno, uint16 osegb) { + uint16 procstart = Get(ptbl - procno); /* word index into segment */ + uint16 datasz = Get(reg_segb + procstart); /* word index */ + dbg_segtrack(reg_segb); +// printf("createMSCW: ptbl=%x procno=%d stat=%x segno=%x\n",ptbl,procno,stat,segno); + + if (reg_sp < reg_splow || (datasz+MSCW_SZ) > (reg_sp-reg_splow)) { /* verify enough space on stack */ +// printf("Stk overflow in mscw: sp=%x spl=%x ds=%d dsm=%d sp-spl=%d\n",reg_sp,reg_splow,datasz,datasz+MSCW_SZ, reg_sp-reg_splow); + Raise(PASERROR_STKOVFL); return reg_ipc; + } + reg_sp = reg_sp - MSCW_SZ - datasz; /* allocate space on stack for local data and MSCW */ + + reg_lm = reg_mp; /* save old MP */ + reg_mp = reg_sp; /* set MP to new stack base */ + Put(reg_mp+OFF_MSDYNL,reg_lm); /* set the dyn link to point to previous MSCW */ + Put(reg_mp+OFF_MSIPC, reg_ipc); /* save the IPC of the caller, already adjusted to point to next instr */ + Put(reg_mp+OFF_MSSTAT,stat); /* set the static link */ + Put(reg_mp+OFFB_MSSEG, segno); /* set the segment # of the caller */ + dbg_procenter(reg_segb, procno, reg_sp, osegb); + return (procstart+1) * 2; // new reg_ipc, byte address in segement */ +} + +/* for context switching */ +//uint16 qtask = NIL; + +/* put qtask into priority queue */ +static uint16 enque(uint16 qhead, uint16 qtask) { + uint16 t1 = qhead; + uint16 t2 = NIL; + uint8 qtaskprio = Getb(qtask+OFFB_PRIOR,0); + sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "Enque: qhead=$%04x qtask=$%04x\n", DBG_PC, qhead, qtask); + while (t1 != NIL) { /* loop until end of queue found */ + if (Getb(t1+OFFB_PRIOR,0) < qtaskprio) break; /* exit loop if priority less than qitem */ + t2 = t1; t1 = Get(t1+OFF_WAITQ); /* otherwise store pointer to current element, advance to next item */ + } + /* now t1 points to an item (or NIL) with a prio less than qtask, t2 points to previous item */ + sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "Enque: t1=$%04x t2=$%04x\n", DBG_PC, t1, t2); + + Put(qtask+OFF_QLINK, t1); /* append this item */ + if (t2 == NIL) qhead = qtask; /* if no higher prio item present, qtask becomes new head */ + else Put(t2+OFF_QLINK, qtask); /* otherwise prepend higher prio list */ + sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "Enqueue: DONE qhead=$%04x qtask=$%04x\n",DBG_PC, qhead, qtask); + return qhead; /* return the new qhead */ +} + +/* perform a task switch. If no task ready to run, wait for an interrupt */ +static t_stat taskswitch6() { + uint16 vector, sem; + int level; + t_stat rc = SCPE_OK; + int kbdc; + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "Taskswitch6: ctp=$%04x rq=$%04x\n",DBG_PC, reg_ctp, reg_rq); + + while (reg_rq == NIL) { /* no task ready to run? */ + if (reg_intpending) { /* wait for an interrupt */ + sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "Taskswitch6: reg_intpending=%08x\n",DBG_PC, reg_intpending); + reg_ctp = NIL; /* set no active task */ + level = getIntLevel(); /* obtain highest pending interupt */ + vector = int_vectors[level]; + sem = Get(vector); + sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "Taskswitch6: SIGNAL sem=$%04x\n",DBG_PC, sem); + rc = DoSIGNAL(sem); + return rc; + } else { + kbdc = sim_poll_kbd(); /* check keyboard */ + if (kbdc == SCPE_STOP) return kbdc; /* handle CTRL-E */ + /* process timer */ + if (sim_interval <= 0) { + if ((rc = sim_process_event())) + return rc; + } + sim_interval -= 3.6; /* NOP cycle */ + } + } + + reg_rq = deque(reg_rq, ®_ctp); /* get first task from ready queue */ + restore_from_tib(); /* restore registers from TIB */ + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "Taskswitch6: DONE newTIB=$%04x\n", DBG_PC2, reg_ctp); + + /* continue processing in this context */ + return rc; +} + +static t_stat taskswitch5() { + t_stat rc; + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "Taskswitch5: reg_rq=$%04x\n",DBG_PC, reg_rq); + save_to_tib(); /* save current context into ctp */ + rc = taskswitch6(); /* and switch to highest task in ready queue */ + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "Taskswitch5: DONE\n",DBG_PC2); + return rc; +} + +static uint16 deque(uint16 qhead, uint16* qtask) { + uint16 newhead; + *qtask = qhead; /* store first element of queue */ + newhead = Get(qhead+OFF_QLINK); /* discard first element from queue, and return new qhead address */ + sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "Dequeue: qtask=$%04x newhead=$%04x\n",DBG_PC,*qtask,newhead); + return newhead; +} + +static t_stat DoSIGNAL(uint16 sem) { + t_stat rc = SCPE_OK; + uint16 qtask, qhead; + uint16 wqaddr = sem + OFF_SEMWAITQ; /* address of wait queue */ + + uint16 count = Get(sem+OFF_SEMCOUNT); /* get count value from semaphore*/ + uint16 wait = Get(wqaddr); /* get top of wait queue */ + + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "SIGNAL: Sem=$%x(count=%d wait=$%x)\n", + DBG_PC,sem,count,wait); + if (count == 0) { + if (wait != NIL) { /* queue is not empty */ + qhead = deque(wait, &qtask); /* extract head of queue (qtask), and store tail back */ + Put(wqaddr, qhead); + + sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "SIGNAL: dequeued qtask=$%x\n",DBG_PC, qtask); + reg_rq = enque(reg_rq, qtask); /* put qtask into rq queue */ + sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "SIGNAL: reg_rq=$%x, reg_ctp=$%x\n", DBG_PC, reg_rq, reg_ctp); + + if (reg_ctp == NIL) { /* no current task (marker for int processing */ + sim_interval -= 134.8; /* consume time */ + return taskswitch6(); /* and switch task */ + } + if (Getb(reg_ctp+OFFB_PRIOR,0) < Getb(qtask+OFFB_PRIOR,0)) { /* is qtask higher prio than current task? */ + reg_rq = enque(reg_rq, reg_ctp); /* yes, put current task back into ready queue */ + rc = taskswitch5(); /* save context in TIB, and switch to new task from ready queue */ + } else { + /* else: nothing is waiting on this semaphore, discard argument, and continue */ + reg_sp++; + sim_interval -= 52.0; + } + return rc; + } + } + /* count is > 0, or sem has no waiters */ + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "SIGNAL: Sem=$%x(count=%d): increment\n",DBG_PC, sem, count); + Put(sem+OFF_SEMCOUNT,count+1); + if (reg_ctp == NIL) { /* if no active task, get one from ready queue */ + sim_interval -= 134.8; + return taskswitch6(); + } + reg_sp++; + sim_interval -= 18.0; + return rc; +} + +static float DoWAIT(uint16 sem) { + uint16 qhead; + uint16 wqaddr = sem + OFF_SEMWAITQ; + t_stat rc = SCPE_OK; + + uint16 count = Get(sem + OFF_SEMCOUNT); /* get count of semaphore */ + sim_debug(DBG_CPU_CONC, &cpu_dev, DBG_PCFORMAT1 "WAIT: Sem=$%04x(count=%d)\n",DBG_PC,sem, count); + if (count == 0) { +// sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "WAIT: Semaphore %x has count 0: do a task switch\n",DBG_PC,sem); + + qhead = enque(Get(wqaddr), reg_ctp); /* have current task wait on semaphore */ + Put(wqaddr, qhead); +// sim_debug(DBG_CPU_CONC3, &cpu_dev, DBG_PCFORMAT0 "WAIT: new qhead=%x\n",DBG_PC, qhead); + + rc = taskswitch5(); /* save context in TIB, and switch to new task from ready queue */ + sim_interval -= 90.8; + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: DONE, switch to newTIB=$%04x\n",DBG_PC, reg_ctp); + return rc; + } else { + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: Sem=$%04x(count=%d): decrement\n", DBG_PC, sem, count); + Put(sem+OFF_SEMCOUNT,count-1); + } + sim_interval -= 11.6; + sim_debug(DBG_CPU_CONC2, &cpu_dev, DBG_PCFORMAT0 "WAIT: DONE, continue\n",DBG_PC); + return rc; +} + +static uint16 HiByte(uint16 reg) { + return (reg>>8) & 0xff; +} + +static uint16 LoByte(uint16 reg) { + return reg & 0xff; +} + +static t_stat DoInstr(void) { + t_stat rc = SCPE_OK; + uint16 opcode, ub1, db, b, ub2, src, dst, inx, len0, len1, hi,lo; + uint16 t1, t2, t3, t4, t5, min1, max1, ptbl, procno, osegb; + int16 ts1, ts2, w; + uint8 segno, osegno; + float tf1, tf2, cyc = 0.0; + int i; + + /* set PCX: current instr in progress */ + PCX = MAKE_BADDR(reg_segb,reg_ipc); + + /* process breakpoints */ + if (sim_brk_summ && sim_brk_test(PCX, SWMASK('E'))) { + return STOP_IBKPT; + } + + /* get opcode */ + opcode = UB(); + + if (dbg_check(opcode, DEBUG_PRE)) { + reg_ipc = ADDR_OFF(PCX); /* restore PC for potential redo */ + return STOP_DBGPRE; + } + + switch (opcode) { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + /* SLDCi */ + Push(opcode & 0x1f); + cyc = 2.8; + break; + case 0x98: /* LDCN */ + Push(NIL); + cyc = 6.4; + break; + case 0x80: /* LDCB */ + Push(UB()); + cyc = 5.6; + break; + case 0x81: /* LDCI */ + Push(W()); + cyc = 8.4; + break; + case 0x82: /* LCA */ + Push(reg_segb + B()); + cyc = 8.0; + break; + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + /* SLDLi */ + Push(Get(reg_mp + MSCW_SZ + (opcode & 0x0f))); + cyc = 6.4; + break; + case 0x87: /* LDL */ + Push(Get(reg_mp + MSCW_SZ -1 + B())); + cyc = 9.6; + break; + case 0x84: /* LLA */ + Push(reg_mp + MSCW_SZ -1 + B()); + cyc = 7.6; + break; + case 0xa4: /* STL */ + Put(reg_mp + MSCW_SZ -1 + B(), Pop()); + cyc = 9.6; + break; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + /* SLDOi */ + Push(Get(reg_bp + MSCW_SZ + (opcode & 0x0f))); + cyc = 7.2; + break; + case 0x85: /* LDO */ + Push(Get(reg_bp + MSCW_SZ -1 + B())); + cyc = 10.0; + break; + case 0x86: /* LAO */ + Push(reg_bp + MSCW_SZ -1 + B()); + cyc = 8.0; + break; + case 0xa5: /* SRO */ + Put(reg_bp + MSCW_SZ -1 + B(),Pop()); + cyc = 13.2; + break; + case 0x89: /* LOD */ + db = DB(); + reg_lm = TraverseMSstat(db); + Push(Get(reg_lm + MSCW_SZ -1 + B())); + cyc = 17.2 + 3.2*db; + break; + case 0x88: /* LDA */ + db = DB(); + reg_lm = TraverseMSstat(db); + Push(reg_lm + MSCW_SZ -1 + B()); + cyc = 15.2 + 3.2*db; + break; + case 0xa6: /* STR */ + db = DB(); + reg_lm = TraverseMSstat(db); + Put(reg_lm + MSCW_SZ -1 + B(),Pop()); + cyc = 16.8 * 3.2*db; + break; + case 0xc4: /* STO */ + t1 = Pop(); Put(Pop(),t1); + cyc = 8.0; + break; + case 0x9a: /* LDE */ + t2 = GetSegbase(UB()); Push(Get(t2 + B())); + cyc = 26.8; + break; + case 0x9b: /* LAE */ + ub1 = UB(); + Push(GetSegbase(ub1) + B()); + cyc = 24.8; + break; + case 0xd9: /* STE */ + ub1 = UB(); + Put(GetSegbase(ub1) + B(), Pop()); + cyc = 26.0; + break; + case 0x83: /* LDC */ + b = B(); ub1 = UB(); + src = reg_segb + b + ub1; + for (i=1; i<=ub1; i++) Put(reg_sp-i,Get(src-i)); + reg_sp -= ub1; + cyc = 18.0 + 4.0*ub1; + break; + case 0xd0: /* LDM */ + ub1 = UB(); src = Pop() + ub1; + for (i=1; i<=ub1; i++) Put(reg_sp-i,Get(src-i)); + reg_sp -= ub1; + cyc = 10.4 + 6.0*ub1; + break; + case 0x8e: /* STM */ + ub1 = UB(); dst = Get(reg_sp+ub1); + for (i=0; i<=(ub1-1); i++) Put(dst+i,Pick(i)); + reg_sp += (ub1+1); + cyc = 12.4 + 6.0*ub1; + break; + case 0xa7: /* LDB */ + b = Pop(); + Push(Getb(Pop(), b)); + cyc = 12.0; + break; + case 0xc8: /* STB */ + ub1 = Pop(); /* index */ b = Pop(); /* byteaddr */ + Putb(Pop(), b, ub1); + cyc = 13.6; + break; + case 0xc5: /* MOV */ + b = B(); src = Pop(); dst = Pop(); + for (i=0; i<=(b-1); i++) Put(dst+i,Get(src+i)); + cyc = 13.2 + 6.0*b; + break; + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + /* SINDi */ + Push(Get(Pop() + (opcode & 0x07))); + cyc = 8.4; + break; + case 0xe6: /* IND */ + Push(Get(Pop() + B())); + cyc = 12.4; + break; + case 0xe7: /* INC */ + Push(Pop() + B()); + cyc = 9.6; + break; + case 0xd7: /* IXA */ + t1 = Pop(); Push(Pop() + t1*B()); + cyc = 9.6 + b/16384.*46.4; + break; + case 0xd8: /* IXP */ + ub1 = UB(); ub2 = UB(); inx = Pop(); + Push(Pop() + inx / ub1); + Push(ub2); Push((inx % ub1) * ub2); + cyc = 35.6; /* inaccurate */ + break; + case 0xc9: /* LDP */ + t1 = Pop(); /*start*/ t2 = Pop(); /*nbits*/ + /* Bogus warning: WD9693_PasIII_OSref_Jul82 is wrong here: + * (sp+2) is an address not a value, so must be dereferenced first */ + Push((Get(Pop() /*addr*/) & GetMask(t1,t2)) >> t1); + cyc = 18.4 + 2.0*(t1+t2); + break; + case 0xca: /* STP */ + t4 = Pop(); /*data*/ t1 = Pop(); /*start*/ t2 = Pop(); /*nbits*/ + t3 = Pop(); /*addr*/ t5 = Get(t3); + clrbit(t5,GetMask(t1,t2)); t4 = (t4 & masks[t2]) << t1; + Put(t3, t5 | t4); + cyc = 20.4 + 2.0*t2 + 2.8*t1; + break; + case 0xa1: /* LAND */ + Push(Pop() & Pop()); + cyc = 8.0; + break; + case 0xa0: /* LOR */ + Push(Pop() | Pop()); + cyc = 8.0; + break; + case 0xe5: /* LNOT */ + Push(~Pop()); + cyc = 5.2; + break; + case 0x9f: /* BNOT */ + Push((~Pop()) & 1); + cyc = 6.0; + break; + case 0xb4: /* LEUSW */ + t1 = Pop(); t2 = Pop() <= t1 ? 1 : 0; + Push(t2); + cyc = t2 ? 9.6 : 10.4; + break; + case 0xb5: /* GEUSW */ + t1 = Pop(); t2 = Pop() >= t1 ? 1 : 0; + Push(t2); + cyc = t2 ? 9.6 : 10.4; + break; + case 0xe0: /* ABI */ + ts1 = PopS(); + PushS(ts1 < 0 ? -ts1 : ts1); + cyc = ts1 < 0 ? 6.0 : 4.8; + break; + case 0xe1: /* NGI */ + PushS(-PopS()); + cyc = 5.2; + break; + case 0xe2: /* DUP1 */ + Push(Tos()); + cyc = 5.2; + break; + case 0xa2: /* ADI */ + PushS(PopS() + Pop()); + cyc = 8.0; + break; + case 0xa3: /* SBI */ + ts1 = PopS(); PushS(PopS() - ts1); + cyc = 8.0; + break; + case 0x8c: /* MPI */ + PushS(Pop() * Pop()); + cyc = 28.0; /* average */ + break; + case 0x8d: /* DVI */ + ts1 = PopS(); if (ts1 == 0) { Raise(PASERROR_DIVZERO); break; } + ts2 = PopS() / ts1; + PushS(ts2); + cyc = ts2 == 0 ? 8.4 : (ts2 > 0 ? 89.2 : 91.2); + break; + case 0x8f: /* MODI */ + ts1 = PopS(); if (ts1 <= 0) { Raise(PASERROR_DIVZERO); /* XXX */ break; } + ts2 = Pop() % ts1; + PushS(ts2); + cyc = ts2 == 0 ? 8.4 : (ts2 > 0 ? 89.2 : 91.2); + break; + case 0xcb: /* CHK */ + t1 = Tos(); t2 = Pick(1); t3 = Pick(2); + if (t2 <= t3 && t3 <= t1) + reg_sp += 2; + else + Raise(PASERROR_VALRANGE); + cyc = 14.4; + break; + case 0xb0: /* EQUI */ + t1 = PopS()==PopS() ? 1 : 0; + Push(t1); + cyc = t1 ? 9.6 : 10.4; + break; + case 0xb1: /* NEQI */ + t1 = PopS()==PopS() ? 0 : 1; + Push(t1); + cyc = t1 ? 9.6 : 10.4; + break; + case 0xb2: /* LEQI */ + ts1 = PopS(); t2 = PopS() <= ts1 ? 1 : 0; + Push(t2); + cyc = t2 ? 10.4 : 11.2; + break; + case 0xb3: /* GEQI */ + ts1 = PopS(); t2 = PopS() >= ts1 ? 1 : 0; + Push(t2); + cyc = t2 ? 10.4 : 11.2; + break; + case 0xcc: /* FLT */ + t1 = PopS(); + PushF((float)t1); + cyc = t1 ? 30.8 : 10.8; + break; + case 0xbe: /* TNC */ + tf1 = PopF(); + PushS((int16)tf1); + cyc = tf1 ? (abs(tf1)<0.5 ? 15.6 : 37.4) : 12.4; /* approximate */ + break; + case 0xbf: /* RND */ + tf1 = PopF(); + PushS((int16)(tf1+0.5)); + cyc = tf1 ? (abs(tf1)<0.5 ? 15.6 : 37.4) : 12.4; /* approximate */ + break; + case 0xe3: /* ABR */ + PushF(abs(PopF())); + cyc = 5.2; + break; + case 0xe4: /* NGR */ + PushF(-PopF()); + cyc = 5.2; + break; + case 0xc0: /* ADR */ + tf1 = PopF(); + PushF(tf1 + PopF()); + cyc = tf1 ? 106.8 : 18.8; /* average */ + break; + case 0xc1: /* SBR */ + tf1 = PopF(); PushF(PopF() - tf1); + cyc = tf1 ? 110.0 : 19.2; /* average */ + break; + case 0xc2: /* MPR */ + tf1 = PopF(); + PushF(tf1 * PopF()); + cyc = tf1 ? 168.6 : 26.4; /* average */ + break; + case 0xc3: /* DVR */ + tf1 = PopF(); if (tf1 == 0) { Raise(PASERROR_DIVZERO); break; } + tf2 = PopF(); + PushF(tf2 / tf1); + cyc = tf2 ? 217.2 : 32.4; /* average */ + break; + case 0xcd: /* EQUREAL */ + tf1 = PopF(); + t1 = tf1==PopF() ? 1 : 0; + Push(t1); + cyc = t1 ? 16.4 : (tf1 ? 18.4 : 14.8); /* average */ + break; + case 0xce: /* LEQREAL */ + tf1 = PopF(); tf2 = PopF(); + t1 = tf2 <= tf1 ? 1 : 0; + Push(t1); + cyc = tf1==tf2 ? 16.4 : (tf1 < tf2 ? 18.2 : 19.4); /* average */ + break; + case 0xcf: /* GEQREAL */ + tf1 = PopF(); tf2 = PopF(); + Push(tf2 >= tf1 ? 1 : 0); + cyc = tf1==tf2 ? 16.4 : 18.2; /* average */ + break; + case 0xc6: /* DUP2 */ + Push(Pick(1)); Push(Pick(1)); + cyc = 12.0; + break; + case 0xc7: /* ADJ */ + ub1 = UB(); len0 = Tos(); src = reg_sp+1; dst = reg_sp + len0 - ub1 +1; + cyc = 14.4; + if (len0 > ub1) { + for (i=1; i<=ub1; i++) Put(dst + ub1 -i, Get(src + ub1 - i)); + cyc = 13.6 + 6.8*ub1; + } else { + for (i=0; i hi) { + reg_sp++; Put(reg_sp,0); + cyc = 18.0; + } else { + len0 = hi / WORD_SZ +1; + reg_sp -= (len0-1); Put(reg_sp,len0); + for (i=0; i= len0) { + src = reg_sp + 1; dst = reg_sp + len0 + 2; + for (i=0; i len0) { + src = reg_sp+1; dst = reg_sp+len0 + 2; + for (i=0; i len0) { + src = reg_sp + 1; dst = reg_sp + len0 + 2; + for (i=0; i len1) { + while (i < max1) { + if (Get(src+i) != 0) break; + i++; + } + } else if (len1 > len0) { + while (i < max1) { + if (Get(dst+i) != 0) break; + i++; + } + } + reg_sp += (len0+len1+1); Put(reg_sp,(i >= max1 ? 1 : 0)); + cyc = 16.0 + 7.6*min1 + 4.0*max1; /* inaccurate */ + break; + case 0xb7: /* LEQPWR */ + len0 = Tos(); len1 = Pick(len0 + 1); i=0; + min1 = MIN(len0,len1); max1 = MAX(len0,len1); + /* Bogus warning: WD9693_PasIII_OSref_Jul82 is wrong here: + * src and dst are not addresses on stack (^p) but addresses OF stack */ + src = reg_sp + 1; dst = reg_sp + len0 + 2; + while (i len1) { + while (i < max1) { + if (Get(src+i) != 0) break; + i++; + } + } else i = max1; + reg_sp += (len0+len1+1); Put(reg_sp,(i >= max1 ? 1 : 0)); + cyc = 16.0 + 8.4*min1 + 4.0*max1; /* inaccurate */ + break; + case 0xb8: /* GEQPWR */ + len0 = Tos(); len1 = Pick(len0 + 1); i=0; + min1 = MIN(len0,len1); max1 = MAX(len0,len1); + /* Bogus warning: WD9693_PasIII_OSref_Jul82 is wrong here: + * src and dst are not addresses on stack (^p) but addresses OF stack */ + src = reg_sp + 1; dst = reg_sp + len0 + 2; + while (i= max1 ? 1 : 0)); + cyc = 21.6 + 8.4*min1 + 4.0*max1; /* inaccurate */ + break; + case 0xb9: /* EQUBYT */ + b = B(); src = Pop(); dst = Pop(); i = 0; + while (i < b && Getb(src,i) == Getb(dst,i)) i++; + t1 = i >= b ? 1 : 0; + Push(t1); + cyc = t1 ? (19.2 + 5.1*b) : (11.4 + 5.1*i); /* inaccurate */ + break; + case 0xba: /* LEQBYT */ + b = B(); src = Pop(); dst = Pop(); i = 0; + while (i < b && Getb(src,i) <= Getb(dst,i)) i++; + Push(i >= b ? 1 : 0); + cyc = 18.4 + 10.4*b; /* inaccurate */ + break; + case 0xbb: /* GEQBYT */ + b = B(); src = Pop(); dst = Pop(); i = 0; + while (i < b && Getb(src,i) >= Getb(dst,i)) i++; + Push(i >= b ? 1 : 0); + cyc = 18.4 + 10.4*b; /* inaccurate */ + break; + case 0x8a: /* UJP */ + b = SB(); reg_ipc += b; + cyc = 12.4; + break; + case 0xd4: /* FJP */ + b = SB(); t1 = Pop(); + cyc = 10.8; + if ((t1 & 1)==0) { + reg_ipc += b; + cyc += 6.0; + } + break; + case 0xd2: /* EFJ */ + b = SB(); t1 = Pop(); t2 = Pop(); + cyc = 11.8; + if (t2 != t1) { + reg_ipc += b; + cyc += 7.4; + } + break; + case 0xd3: /* NFJ */ + b = SB(); t1 = Pop(); t2 = Pop(); + cyc = 12.0; + if (t2 == t1) { + reg_ipc += b; + cyc += 7.2; + } + break; + case 0x8b: /* UJPL */ + w = W(); reg_ipc += w; + cyc = 12.8; + break; + case 0xd5: /* FJPL */ + w = W(); t1 = Pop(); + cyc = 10.0; + if ((t1 & 1)== 0) { + reg_ipc += w; + cyc += 8.8; + } + break; + case 0xd6: /* XJP */ + b = B(); t1 = Pop(); + t2 = Get(reg_segb + b); + if (t2 <= t1 && Get(reg_segb + b + 1) >= t1) { + reg_ipc += Get(reg_segb + b + 2 + (t1-t2)); + cyc = 32.0; + } else { + cyc = t1 < t2 ? 29.2 : 34.0; + } + break; + case 0x90: /* CPL */ + procno = UB(); + ptbl = GetPtbl(); + reg_ipc = createMSCW(ptbl, procno, reg_mp, 0, reg_segb); + cyc = 45.6; + break; + case 0x91: /* CPG */ + procno = UB(); + ptbl = GetPtbl(); + reg_ipc = createMSCW(ptbl, procno, reg_bp, 0, reg_segb); + cyc = 44.8; + break; + case 0x92: /* CPI */ + db = DB(); procno = UB(); + ptbl = GetPtbl(); + /* Bogus warning: WD9693_PasIII_OSref_Jul82 is wrong here: + * msstat is preserved, CPI page 46 does not set it */ + reg_ipc = createMSCW(ptbl, procno, Get(reg_mp+OFF_MSSTAT), 0, reg_segb); + reg_lm = reg_mp; + for (i=1; i<= db; i++) + reg_lm = Get(reg_lm+OFF_MSSTAT); + Put(reg_mp+OFF_MSSTAT,reg_lm); /* fix stat link */ + cyc = 53.6 + 3.2*db; + break; + case 0x93: /* CXL */ + segno = UB(); procno = UB(); + osegno = GetSegno(); + osegb = reg_segb; + ptbl = SetSEGB(segno); + AdjustRefCount(segno, 1); + reg_ipc = createMSCW(ptbl, procno, reg_mp, osegno, osegb); + cyc = 64.4; + break; + case 0x94: /* CXG */ + ub1 = UB(); ub2 = UB(); + cyc = DoCXG(ub1, ub2); + break; + case 0x95: /* CXI */ + segno = UB(); db = DB(); procno = UB(); + osegno = GetSegno(); + osegb = reg_segb; + ptbl = SetSEGB(segno); + AdjustRefCount(segno, 1); + reg_ipc = createMSCW(ptbl, procno, reg_mp, osegno, osegb); + reg_lm = reg_mp; + for (i=1; i<= db; i++) reg_lm = Get(reg_lm+OFF_MSSTAT); + Put(reg_mp+OFF_MSSTAT,reg_lm); /* fix stat link */ + cyc = 73.2 + 3.2*db; + break; + case 0x97: /* CPF */ + t1 = Pop(); reg_lm = Pop(); + segno = HiByte(t1); + procno = LoByte(t1); + osegno = GetSegno(); + osegb = reg_segb; + ptbl = SetSEGB(segno); + AdjustRefCount(segno, 1); + reg_ipc = createMSCW(ptbl, procno, reg_lm, osegno, osegb); + cyc = 75.6; + break; + case 0x96: /* RPU */ + dbg_procleave(); + b = B(); reg_sp = reg_mp; reg_lm = reg_mp; + reg_mp = Get(reg_lm+OFF_MSDYNL); + reg_ipc = Get(reg_lm+OFF_MSIPC); + segno = Getb(reg_lm+OFFB_MSSEG,0); + if (segno) { + osegno = GetSegno(); + AdjustRefCount(osegno, -1); + (void)SetSEGB(segno); + } + reg_sp += (b + MSCW_SZ); + cyc = 26.0; + break; + case 0x99: /* LSL */ + db = DB(); reg_lm = reg_mp; + for (i=1; i<= db; i++) reg_lm = Get(reg_lm+OFF_MSSTAT); + Push(reg_lm); + cyc = 12.4 + 3.2*db; + break; + case 0xde: /* SIGNAL */ + t1 = Pick(0); + rc = DoSIGNAL(t1); + break; + case 0xdf: /* WAIT */ + t1 = Pop(); + rc = DoWAIT(t1); break; + case 0x9d: /* LPR */ + w = Tos(); + cyc = 0.0; + if (w >= 0) { + save_to_tib(); + cyc = 55.2; + } else + cyc = 8.4; + if (w == -3) Put(reg_sp, reg_rq); + else if (w == -2) Put(reg_sp, reg_ssv); + else if (w == -1) Put(reg_sp, reg_ctp); + else if (w > 0) Put(reg_sp, Get(reg_ctp + w)); + break; + case 0xd1: /* SPR */ + t1 = Tos(); + w = (int16)Pick(1); + if (w >= -1) + save_to_tib(); + cyc = 8.4; + if (w == -3) { + reg_rq = t1; + } else if (w == -2) { + reg_ssv = t1; + } else if (w == -1) { +// printf("SPR Taskswitch reg_ctp=%x\n",t1); + reg_rq = t1; + taskswitch5(); +// printf("SPR Taskswitch done reg_ctp=%x reg_rq=%x\n",reg_ctp,reg_rq); + cyc = 53.2; + break; /* mustn't fall through reg_sp +=2 */ + } else if (w >= 1) { + cyc = 54.8; + switch (w) { + case OFF_SP: reg_sp = t1; break; + case OFF_MP: reg_mp = t1; break; + case OFF_BP: reg_bp = t1; break; + case OFF_IPC: reg_ipc = t1; break; + case OFF_SEGB: reg_segb = t1; break; + default: Put(reg_ctp + w, t1); break; + } + } + if (w >= -1) + save_to_tib(); + if (w != OFF_SP) reg_sp += 2; /* mustn't change modified SP again */ + break; + case 0x9e: /* BPT */ + Raise(PASERROR_USERBRK); + cyc = 0; /* added in Raise() -> DoCXG() */ + return STOP_BPT; +// break; + case 0x9c: /* NOP */ + cyc = 3.6; + break; + case 0xbd: /* SWAP */ + t1 = Tos(); + Put(reg_sp, Pick(1)); + Put(reg_sp+1, t1); + cyc = 12.4; + break; + default: +// Raise(PASERROR_UNIMPL); + return STOP_IMPL; + } + + if (rc != SCPE_OK) return rc; + + /* set new PCX */ + PCX = MAKE_BADDR(reg_segb,reg_ipc); + if (dbg_check(opcode, DEBUG_POST)) return STOP_DBGPOST; + + /* count cycles */ + sim_interval -= (int)(cyc+0.5); + + return SCPE_OK; +} + +t_stat sim_instr(void) +{ + t_stat rc = SCPE_OK; + while (rc == SCPE_OK) { + + /* set PCX of instruction in progress */ + PCX = MAKE_BADDR(reg_segb,reg_ipc); + + /* process timer */ + if (sim_interval <= 0) { + if ((rc = sim_process_event())) + break; + } + + /* effectively latch interrupts now: + * there is a known CPU bug: interrupts are latched here. + * If the following instruction will disable interrupts, + * the interrupt is processed anyway + */ + + /* if reg_ctp is NIL, CPU waits for interrupt or autoload done. + * handle time by NOP cycles + */ + if (reg_ctp != NIL) { + if ((rc = DoInstr())) break; + } else { + /* waste time by doing a NOP */ + sim_interval -= 3.6; + } + + /* process interrupts + * CPU latches interrupt request now, and after instr + * execution, will process them. Note: this is a known bug in CPU, because + * if the instruction disables interrupts, the interrupt is processed anyway */ + if (cpu_isIntEnabled()) { + reg_intpending |= reg_intlatch; + if (reg_intpending) { + if ((rc = cpu_processInt())) { + printf("processint returns %d\n",rc); fflush(stdout); + break; + } + } + } + + } + return rc; +} + +static t_stat cpu_set_flag(UNIT *uptr, int32 value, char *cptr, void *desc) { + uptr->flags |= value; + return SCPE_OK; +} + +static t_stat cpu_set_noflag(UNIT *uptr, int32 value, char *cptr, void *desc) { + uptr->flags &= ~value; + return SCPE_OK; +} + diff --git a/PDQ-3/pdq3_debug.c b/PDQ-3/pdq3_debug.c new file mode 100644 index 00000000..33397870 --- /dev/null +++ b/PDQ-3/pdq3_debug.c @@ -0,0 +1,441 @@ +/* pdq3_debug.c: PDQ3 debug helper + + Work derived from Copyright (c) 2004-2012, Robert M. Supnik + Copyright (c) 2013 Holger Veit + + 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 + ROBERT M SUPNIK 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 names of Robert M Supnik and Holger Veit + shall not be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik and Holger Veit. + + 20130421 hv initial version + 20130928 hv fix problem with callstack when S_Start_P patches MSCW + 20131012 hv view calltree returned incorrect segment of caller +*/ +#include "pdq3_defs.h" + +static uint8 *opdebug = NULL; + +static void dbg_opdbgcreate() { + int i; + FILE *fd = fopen(DEBUG_OPDBGFILE, "w"); + if (fd==NULL) { + fprintf(stderr,"Cannot create %s\n", DEBUG_OPDBGFILE); + exit(1); + } + for (i=DEBUG_MINOPCODE; i",q); + if ((rc=ReadEx(q, OFF_WAITQ, &q)) != SCPE_OK) return rc; + } + fprintf(fd, "NIL\n"); + return SCPE_OK; +} + +t_stat dbg_dump_mscw(FILE* fd, uint16 base) { + t_stat rc; + uint16 data; + fprintf(fd, "MSCW at $%04x\n",base); + if ((rc=ReadEx(base, OFF_MSSTAT, &data)) != SCPE_OK) return rc; + fprintf(fd, " MSSTAT: $%04x\n", data); + if ((rc=ReadEx(base, OFF_MSDYNL, &data)) != SCPE_OK) return rc; + fprintf(fd, " MSDYNL: $%04x\n", data); + if ((rc=ReadEx(base, OFF_MSIPC, &data)) != SCPE_OK) return rc; + fprintf(fd, " MSIPC: $%04x\n", data); + if ((rc=ReadBEx(base+OFFB_MSSEG, 0, &data)) != SCPE_OK) return rc; + fprintf(fd, " MSSEG: %02x\n", data); + return SCPE_OK; +} + +void dbg_enable() { + cpu_dev.dctrl |= (DBG_CPU_READ|DBG_CPU_WRITE|DBG_CPU_STACK); +} + +/****************************************************************************** + * Segment Tracking support + *****************************************************************************/ + +static char* pdq3_segname(uint16 nameptr) { + static char name[10]; + uint16 data; + int i; + for (i=0; i<8; i++) { + ReadBEx(nameptr,i,&data); + name[i] = data != ' ' ? data : 0; + } + name[8] = 0; + return name; +} + +t_stat dbg_dump_seg(FILE* fd, uint16 segptr) { + t_stat rc; + uint16 data; + if ((rc=ReadEx(segptr, OFF_SEGBASE, &data)) != SCPE_OK) return rc; + fprintf(fd, " BASE: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_SEGLENG, &data)) != SCPE_OK) return rc; + fprintf(fd, " LENGTH: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_SEGREFS, &data)) != SCPE_OK) return rc; + fprintf(fd, " REFS: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_SEGADDR, &data)) != SCPE_OK) return rc; + fprintf(fd, " ADDR: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_SEGUNIT, &data)) != SCPE_OK) return rc; + fprintf(fd, " UNIT: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_PREVSP, &data)) != SCPE_OK) return rc; + fprintf(fd, " PREVSP: $%04x\n",data); + fprintf(fd, " NAME: %s\n", pdq3_segname(segptr+OFF_SEGNAME)); + if ((rc=ReadEx(segptr, OFF_SEGLINK, &data)) != SCPE_OK) return rc; + fprintf(fd, " LINK: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_SEGGLOBAL, &data)) != SCPE_OK) return rc; + fprintf(fd, " GLOBAL: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_SEGINIT, &data)) != SCPE_OK) return rc; + fprintf(fd, " INIT: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_SEG13, &data)) != SCPE_OK) return rc; + fprintf(fd, " entry13: $%04x\n",data); + if ((rc=ReadEx(segptr, OFF_SEGBACK, &data)) != SCPE_OK) return rc; + fprintf(fd, " SELF: $%04x\n",data); + return SCPE_OK; +} + +t_stat dbg_dump_segtbl(FILE* fd) { + int i; + uint16 segptr, nsegs; + t_stat rc; + + if (reg_ssv < 0x2030 || reg_ssv > 0xf000) { + printf("Cannot list segments in bootloader: incomplete tables\n"); + return SCPE_NXM; + } + + if ((rc=Read(reg_ssv, -1, &nsegs, 0)) != SCPE_OK) return rc; + + fprintf(fd, "Segment table: ssv=$%04x size=%d\n",reg_ssv, nsegs); + for (i=0; i<=nsegs; i++) { + if ((rc=ReadEx(reg_ssv, i, &segptr)) != SCPE_OK) return rc; + fprintf(fd, " %02x %04x %s\n",i,segptr, pdq3_segname(segptr + OFF_SEGNAME)); + } + return SCPE_OK; +} + +/* segment tracking */ +typedef struct _seginfo { + uint16 base; /* base load address */ + struct _seginfo* next; + uint16 idx; /* index into SSV table */ + char name[10]; /* segment name */ + uint16 size; + uint16 nproc; + uint16 segno; +} SEGINFO; + +#define SEGHASHSIZE 97 +SEGINFO* seghash[SEGHASHSIZE]; +#define SEGHASHFUNC(i) (i % SEGHASHSIZE) + +void dbg_segtrackinit() { + int i; + for (i=0; inext = next; + s->base = base; + return s; +} + +static SEGINFO* find_seginfo(uint16 base, int* idx) { + SEGINFO* s; + *idx = SEGHASHFUNC(base); + s = seghash[*idx]; + while (s && s->base != base) s = s->next; + return s; +} + +t_stat dbg_segtrack(uint16 segbase) { + t_stat rc; + int idx; + SEGINFO* s = find_seginfo(segbase, &idx); + if (!s) { + s = seghash[idx] = new_seginfo(seghash[idx], segbase); + if ((rc=ReadEx(segbase, 0, &s->size)) != SCPE_OK) return rc; + strcpy(s->name, segbase==0xf418 ? "HDT" : pdq3_segname(segbase+2)); + if ((rc=ReadBEx(segbase+s->size, 0, &s->segno)) != SCPE_OK) return rc; + if ((rc=ReadBEx(segbase+s->size, 1, &s->nproc)) != SCPE_OK) return rc; +// printf("Entered at %04x: %s sz=%x seg=%x np=%x\n",segbase, s->name, s->size, s->segno, s->nproc); + } + return SCPE_OK; +} + +/****************************************************************************** + * Name Alias Handling + *****************************************************************************/ + +typedef struct _aliases { + char* key; + char* alias; + struct _aliases* next; +} ALIASES; + +#define ALIASHASHSIZE 97 +static ALIASES* aliases[ALIASHASHSIZE]; + +static void dbg_initaliases() { + int i; + for (i=0; ikey, gbuf2, 0); + while (a && strcmp(gbuf2,gbuf)) { + a = a->next; + if (a) get_glyph(a->key, gbuf2, 0); + } + return a; +} + +t_stat dbg_enteralias(const char* key, const char* value) { + int idx; + ALIASES* a = find_alias(key, &idx); + if (!a) { + a = (ALIASES*)malloc(sizeof(ALIASES)); + a->key = strdup(key); + a->alias = strdup(value); + a->next = aliases[idx]; + aliases[idx] = a; + } + return SCPE_OK; +} + +t_stat dbg_listalias(FILE* fd) { + int i; + ALIASES* a; + fprintf(fd, "Name table:\n"); + for (i=0; ikey, a->alias); + a = a->next; + } + } + return SCPE_OK; +} + +/****************************************************************************** + * Procedure tracking support + *****************************************************************************/ + +typedef struct _procinfo { + struct _procinfo *next; + uint16 procno; + SEGINFO* seg; + uint16 localsz; + uint16 freesz; + uint16 mscw; + uint16 segb; + uint16 instipc; + uint16 ipc; +} PROCINFO; + +const char* find_procname(PROCINFO* p) { + ALIASES* a; + int dummy; + static char buf[100]; + sprintf(buf,"%s:proc%d", p->seg->name, p->procno); + a = find_alias(buf, &dummy); + if (a) return a->alias; + return buf; +} + +static PROCINFO* procroot = NULL; + +static PROCINFO* new_procinfo(uint16 segbase, uint16 procno, uint16 mscw, uint16 osegb) { + int dummy; + uint16 procbase, procaddr; + uint16 exitic, sz1, sz2; + PROCINFO* p = (PROCINFO*)malloc(sizeof(PROCINFO)); + p->procno = procno; + p->mscw = mscw; + p->seg = find_seginfo(segbase, &dummy); + p->segb = osegb; + p->instipc = ADDR_OFF(PCX); + ReadEx(mscw,OFF_MSIPC, &p->ipc); + ReadEx(segbase, 0, &procbase); + ReadEx(segbase+procbase-procno, 0, &procaddr); + ReadEx(segbase+procaddr, 0, &p->localsz); + ReadEx(segbase+procaddr-1, 0, &exitic); + ReadBEx(segbase, exitic, &sz1); + if (sz1==0x96) { + ReadBEx(segbase, exitic+1, &sz1); + if (sz1 & 0x80) { + ReadBEx(segbase, exitic+2, &sz2); + sz1 = ((sz1 & 0x7f)<<8) | sz2; + } + p->freesz = sz1; + } + return p; +} + +t_stat dbg_procenter(uint16 segbase, uint16 procno, uint16 mscw, uint16 osegb) { + PROCINFO* p = new_procinfo(segbase, procno, mscw, osegb); + p->next = procroot; + procroot = p; + return SCPE_OK; +} + +t_stat dbg_procleave() { + t_stat rc; + PROCINFO* p = procroot; + uint16 ipc,pipc; + while (p) { + pipc = p->ipc; + if ((rc=ReadEx(p->mscw,OFF_MSIPC, &ipc)) != SCPE_OK) return rc; + procroot = p->next; + free(p); + if (pipc == ipc) break; + p = procroot; + } + return SCPE_OK; +} + +t_stat dbg_calltree(FILE* fd) { + PROCINFO* p = procroot, *lastp; + + if (!p) { + fprintf(fd,"Callstack is empty\n"); + return SCPE_OK; + } + + fprintf(fd,"Calltree:\nCurrently in %s at %04x:%04x\n", + find_procname(p), reg_segb, reg_ipc); + lastp = p; + p = p->next; + while (p) { + fprintf(fd," at %04x:%04x called by %s (%04x:%04x)\n", + lastp->segb, lastp->instipc, find_procname(p), p->segb, p->instipc); + lastp = p; + p = p->next; + } + return SCPE_OK; +} + +/****************************************************************************** + * Initialization + *****************************************************************************/ + +t_stat dbg_init() { + dbg_opdbginit(); + dbg_segtrackinit(); + return SCPE_OK; +} + + diff --git a/PDQ-3/pdq3_defs.h b/PDQ-3/pdq3_defs.h new file mode 100644 index 00000000..3833cf98 --- /dev/null +++ b/PDQ-3/pdq3_defs.h @@ -0,0 +1,415 @@ +/* pdq3_defs.h: PDQ3 simulator definitions + + Work derived from Copyright (c) 2004-2012, Robert M. Supnik + Copyright (c) 2013 Holger Veit + + 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 + ROBERT M SUPNIK 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 names of Robert M Supnik and Holger Veit + shall not be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik and Holger Veit. + + 20131103 hv INT_CONR/CONT assignments incorrect in docs, must be swapped +*/ +#ifndef _PDQ3_DEFS_H_ +#define _PDQ3_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ +#include "sim_sock.h" +#include "sim_tmxr.h" + +/* constants */ +#define NIL 0xfc00 /* Pascal Microengine NIL value */ +#define MSCW_SZ 4 /* size of MSCW */ +#define REAL_SZ 2 /* size of real number (REAL*4) */ +#define BSET_SZ 4080 /* usable size of set in bits */ +#define ISET_SZ 255 /* size of set in words */ +#define WORD_SZ 16 /* size of machine word in bits */ + +#define OFF_SEGBASE 0 /* offsets into SIB entry */ +#define OFF_SEGLENG 1 +#define OFF_SEGREFS 2 +#define OFF_SEGADDR 3 +#define OFF_SEGUNIT 4 +#define OFF_PREVSP 5 +#define OFF_SEGNAME 6 +#define OFF_SEGLINK 10 +#define OFF_SEGGLOBAL 11 +#define OFF_SEGINIT 12 +#define OFF_SEG13 13 +#define OFF_SEGBACK 14 + +#define OFF_MSSTAT 0 /* offsets into MSCW */ +#define OFF_MSDYNL 1 +#define OFF_MSIPC 2 +#define OFFB_MSSEG 3 +#define OFFB_MSFLAG 3 + +#define OFF_WAITQ 0 /* offset into TIB */ +#define OFF_QLINK 0 +#define OFFB_PRIOR 1 +#define OFFB_FLAGS 1 +#define OFF_SPLOW 2 +#define OFF_SPUPR 3 +#define OFF_SP 4 +#define OFF_MP 5 +#define OFF_BP 6 +#define OFF_IPC 7 +#define OFF_SEGB 8 +#define OFF_HANGP 9 +#define OFF_IORSLT 10 +#define OFF_SIBS 11 + +#define OFF_SEMCOUNT 0 /* offset into SEMA variable */ +#define OFF_SEMWAITQ 1 + +#define SSR_BERR 0x01 /* bits of system status register */ +#define SSR_TICK 0x02 +#define SSR_INTVL 0x04 +#define SSR_BIT3 0x08 +#define SSR_PWRF 0x10 +#define SSR_PRNT 0x20 +#define SSR_INTEN 0x40 +#define SSR_INIT 0x80 + +/* fixed interrupts */ +#define INT_BERR 0 /* interrupt levels */ +#define INT_PWRF 1 +#define INT_DMAFD 2 +#define INT_CONR 3 /* Appendix B.0.1 has CONT and CONR swapped, see Errata */ +#define INT_CONT 4 +#define INT_PRNT 5 +#define INT_TICK 6 +#define INT_INTVL 7 + +/* assignable QBUS interrupts, daisy-chained - highest prio = 8, lowest = 31 */ +#define INT_QBUS8 8 +#define INT_QBUS9 9 +#define INT_QBUS10 10 +#define INT_QBUS11 11 +#define INT_QBUS12 12 +#define INT_QBUS13 13 +#define INT_QBUS14 14 +#define INT_QBUS15 15 +#define INT_QBUS16 16 +#define INT_QBUS17 17 +#define INT_QBUS18 18 +#define INT_QBUS19 19 +#define INT_QBUS20 20 +#define INT_QBUS21 21 +#define INT_QBUS22 22 +#define INT_QBUS23 23 +#define INT_QBUS24 24 +#define INT_QBUS25 25 +#define INT_QBUS26 26 +#define INT_QBUS27 27 +#define INT_QBUS28 28 +#define INT_QBUS29 29 +#define INT_QBUS30 30 +#define INT_QBUS31 31 + +/* common unit user-defined attributes */ +#define u_unitno u3 + +/* Memory */ +#define MEMSIZE 65536 /* memory size in bytes */ +#define MAXMEMSIZE (65535 * 2) /* maximum memory size in bytes */ +#define memorysize uptr->capac + +/* CPU Unit flags */ +#define UNIT_V_PDQ3 (UNIT_V_UF + 0) +#define UNIT_V_MSIZE (UNIT_V_UF + 1) +#define UNIT_V_PASEXC (UNIT_V_UF + 2) + + +#define UNIT_PDQ3 (1u << UNIT_V_PDQ3) +#define UNIT_MSIZE (1u << UNIT_V_MSIZE) +#define UNIT_PASEXC (1u << UNIT_V_PASEXC) + +#define Q_PDQ3 (cpu_unit.flags & UNIT_PDQ3) +#define Q_MSIZE (cpu_unit.flags & UNIT_MSIZE) +#define Q_PASEXC (cpu_unit.flags & UNIT_PASEXC) + +#define setbit(reg,val) reg |= (val) +#define clrbit(reg,val) reg &= ~(val) +#define isbitset(reg, val) (reg & (val)) +#define isbitclr(reg, val) ((reg & (val)) == 0) + +/* debug flags */ +#define DBG_NONE 0x0000 + +#define DBG_FD_CMD 0x0001 +#define DBG_FD_READ 0x0002 +#define DBG_FD_WRITE 0x0004 +#define DBG_FD_SVC 0x0008 +#define DBG_FD_IMD 0x0010 +#define DBG_FD_IMD2 0x0020 /* deep inspection */ +#define DBG_FD_DMA 0x0040 +#define DBG_FD_DMA2 0x0080 /* deep inspection */ + +//define DBG_CPU_TRACE 0x0001 unused +#define DBG_CPU_INT 0x0001 +#define DBG_CPU_INT2 0x0002 /* deep inspection */ +#define DBG_CPU_READ 0x0004 +#define DBG_CPU_WRITE 0x0008 +#define DBG_CPU_FETCH 0x0010 +#define DBG_CPU_PUSH 0x0020 +#define DBG_CPU_POP 0x0040 +#define DBG_CPU_PICK 0x0080 +#define DBG_CPU_STACK (DBG_CPU_PUSH|DBG_CPU_POP|DBG_CPU_PICK) +#define DBG_CPU_CONC 0x0100 +#define DBG_CPU_CONC2 0x0200 /* deep inspection */ +#define DBG_CPU_CONC3 0x0400 /* even deeper inspection */ + +#define DBG_CON_READ 0x0001 +#define DBG_CON_WRITE 0x0002 +#define DBG_CON_SVC 0x0004 + +#define DBG_TIM_READ 0x0001 +#define DBG_TIM_WRITE 0x0002 +#define DBG_TIM_SVC 0x0004 + +#define DBG_PCFORMAT0 "[%04x:%04x] " +#define DBG_PCFORMAT1 " [%04x:%04x] " +#define DBG_PCFORMAT2 " [%04x:%04x] " +#define DBG_PC reg_segb,ADDR_OFF(PCX) +#define DBG_PC2 reg_segb,reg_ipc + +/* calibration timers */ +#define TMR_CONPOLL 0 + +/* console sio data rates */ +#define CON_POLLUNIT 0 +#define CON_TERMUNIT 1 +#define CON_POLLFIRST 1 /* immediate */ +#define CON_POLLRATE 100 +#define CON_POLLWAIT 12500 +//#define CON_TERMRATE 1300 +#define CON_TERMRATE 300 + +/* floppy size */ +#define FDC_MAX_TRACKS 77 + +/* IMD anachronism */ +#ifndef MAX_COMMENT_LEN +#define MAX_COMMENT_LEN 256 +#endif + +/* XXX @TODO Pascal error codes (Raise()) */ +#define PASERROR_SYSTEM 0 +#define PASERROR_VALRANGE 1 +#define PASERROR_NOSEG 2 +#define PASERROR_PROCERR 3 +#define PASERROR_STKOVFL 4 +#define PASERROR_INTOVFL 5 +#define PASERROR_DIVZERO 6 +#define PASERROR_MEMERR 7 +#define PASERROR_USERBRK 8 +#define PASERROR_SYSIO 9 +#define PASERROR_USERIO 10 +#define PASERROR_UNIMPL 11 +#define PASERROR_FPERR 12 +#define PASERROR_STRINGOVFL 13 +#define PASERROR_HALT 14 + +/* simh error codes */ +#define STOP_IBKPT 1 +#define STOP_MEM 2 +#define STOP_ERROP 3 +#define STOP_ERRADR 4 +#define STOP_ERRIO 5 +#define STOP_IMPL 6 +#define STOP_BPT 7 +#define STOP_DBGPRE 8 +#define STOP_DBGPOST 9 +#define STOP_PASEXC 10 + +/* IO addresses and vectors */ +#define CON_IOBASE 0xfc10 +#define CON_RCV_VEC 0x0012 +#define CON_XMT_VEC 0x000e +#define CON_PRT_VEC 0x0016 +#define SES_IOBASE 0xfc18 +#define SES_BERR_VEC 0x0002 +#define SES_PWRF_VEC 0x0006 +#define SSR_IOBASE 0xfc24 +#define TIM_IOBASE 0xfc20 +#define TIM_TICK_VEC 0x001a +#define TIM_INTVL_VEC 0x001e +#define FDC_IOBASE 0xfc30 +#define FDC_VEC 0x000a +#define CPU_SERIALNO 0xf5ff /* is part of ROM */ +#define ROM_BASE 0xfc68 +#define ROM 0xf400 +#define ROM_SIZE 0x01ff /* excluding serial number */ + +/* address calculations */ +#define ADDRMASK_SEG 0xffff0000 +#define ADDRMASK_OFF 0x0000ffff +#define ADDR_16bit(a) ((a) & 0x0000ffff) +#define ADDR_SEG(a) (((a)>>16) & ADDRMASK_OFF) +#define ADDR_OFF(a) ((a) & ADDRMASK_OFF) +#define MAKE_BADDR(s,o) ((ADDR_16bit(s)<<16) | ADDR_16bit(o)) +#define MAKE_WADDR(a) MAKE_BADDR(NIL,ADDR_OFF(a)) +#define ADDR_ISWORD(a) (ADDR_SEG(a) == NIL) + +/* opcode table */ +#define OP_ERROR -1 +#define OP_NULL 0 +#define OP_UB 1 +#define OP_W 2 +#define OP_B 3 +#define OP_DBB 4 +#define OP_UBB 5 +#define OP_BUB 6 +#define OP_SB 7 +#define OP_DBUB 8 +#define OP_UBUB 9 +#define OP_UBDBUB 10 +#define OP_DB 11 +#define OP_SW 12 +#define OP_AB 13 + +typedef struct _optable { + char* name; + int16 flags; +} OPTABLE; +extern OPTABLE optable[]; + +/* debug support */ +#define DEBUG_OPDBGFILE "opcode.dbg" +#define DEBUG_MINOPCODE 0 +#define DEBUG_MAXOPCODE 0xe8 +#define DEBUG_VALIDOP(op) (optable[op].flags >= 0) +#define DEBUG_PRE 0x01 +#define DEBUG_POST 0x02 +extern t_stat dbg_init(); +extern t_stat dbg_check(t_value data,uint8 prepost); +extern t_stat dbg_dump_tib(FILE* fd, uint16 base); +extern t_stat dbg_dump_queue(FILE* fd, const char* qname, uint16 q); +extern t_stat dbg_dump_mscw(FILE* fd, uint16 base); +extern t_stat dbg_dump_seg(FILE* fd, uint16 segptr); +extern t_stat dbg_dump_segtbl(FILE* fd); +extern t_stat dbg_segtrack(uint16 segbase); +extern t_stat dbg_procenter(uint16 segbase, uint16 procno, uint16 mscw, uint16 osegb); +extern t_stat dbg_procleave(); +extern void dbg_enable(); +extern t_stat dbg_calltree(FILE* fd); +extern t_stat dbg_enteralias(const char* key, const char* value); +extern t_stat dbg_listalias(FILE*); +/* floating point */ +typedef union flcvt { + float f; + uint16 i[2]; +} T_FLCVT; + +/* wrapper structure for terminal multiplexer, + pointer to pointer stored in device->ctxt */ +typedef struct { + int pfirst, prate; /* pollrate first time, later */ + TMLN ldsc; + TMXR desc; + UNIT* term; + UNIT* poll; +} SERMUX; +extern t_stat mux_attach(UNIT*, char*, SERMUX*); +extern t_stat mux_detach(UNIT*, SERMUX*); + +/* externals */ +extern DEVICE cpu_dev; +extern UNIT cpu_unit; +extern DEVICE con_dev; +extern UNIT con_unit[]; +extern DEVICE fdc_dev; +extern UNIT fdc_unit[]; +extern DEVICE timer_dev; +extern UNIT timer_unit[]; +extern t_addr PCX; /* PC at the begin of execution */ +extern uint16 reg_segb; +extern uint32 reg_dmabase; +extern uint16 reg_mp; +extern uint16 reg_bp; +extern uint16 reg_sp; +extern uint16 reg_splow; +extern uint16 reg_spupr; +extern uint16 reg_ctp; +extern uint16 reg_rq; +extern uint16 reg_ipc; +extern uint16 reg_fc68; +extern uint16 reg_romsize; +extern uint16 reg_ssv; +extern uint16 reg_ssr; +extern uint16 reg_cpuserial; +extern uint32 reg_intpending; + +extern t_stat Read(t_addr base, t_addr woffset, uint16 *data, uint32 dctrl); +extern t_stat Write(t_addr base, t_addr boffset, uint16 data, uint32 dctrl); +extern t_stat ReadB(t_addr base, t_addr boffset, uint16 *data, uint32 dctrl); +extern t_stat WriteB(t_addr base, t_addr boffset, uint16 data, uint32 dctrl); +extern t_stat ReadEx(t_addr base, t_addr woffset, uint16 *data); +extern t_stat ReadBEx(t_addr base, t_addr boffset, uint16 *data); + +extern t_stat rom_read(t_addr base, uint16 *data); +extern t_stat rom_write(t_addr base, uint16 data); +extern t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); + +extern t_stat con_read(t_addr ioaddr, uint16 *data); +extern t_stat con_write(t_addr ioaddr, uint16 data); +extern t_stat con_binit(); +extern t_stat fdc_read(t_addr ioaddr, uint16 *data); +extern t_stat fdc_write(t_addr ioaddr, uint16 data); +extern t_stat fdc_autoload(); +extern t_stat fdc_binit(); +extern t_stat tim_read(t_addr ioaddr, uint16 *data); +extern t_stat tim_write(t_addr ioaddr, uint16 data); + +extern void cpu_assertInt(int level, t_bool tf); +extern t_stat cpu_raiseInt(int level); +extern t_stat cpu_setIntVec(uint16 vector,int level); +extern void cpu_setRegs(uint16 ctp, uint16 ssv, uint16 rq); +extern void cpu_finishAutoload(); +extern t_stat cpu_buserror(); + +typedef t_stat (*IOREAD)(t_addr ioaddr, uint16 *data); +typedef t_stat (*IOWRITE)(t_addr ioaddr, uint16 data); + +typedef struct _ioinfo { + struct _ioinfo* next; + uint16 iobase; + uint16 iosize; + uint16 qvector; + uint16 qprio; + IOREAD read; + IOWRITE write; +} IOINFO; + +typedef struct _devctxt { + IOINFO* ioi; +} DEVCTXT; + +extern t_stat pdq3_ioinit(); +extern t_stat add_ioh(IOINFO* ioi); +extern t_stat del_ioh(IOINFO* ioi); +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern t_stat set_iovec(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iovec(FILE *st, UNIT *uptr, int value, void *desc); +extern t_stat set_ioprio(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_ioprio(FILE *st, UNIT *uptr, int value, void *desc); + +#endif diff --git a/PDQ-3/pdq3_fdc.c b/PDQ-3/pdq3_fdc.c new file mode 100644 index 00000000..8812c9f6 --- /dev/null +++ b/PDQ-3/pdq3_fdc.c @@ -0,0 +1,1176 @@ +/* PDQ3_fdc.c: PDQ3 simulator Floppy disk device + + Work derived from Copyright (c) 2004-2012, Robert M. Supnik + Copyright (c) 2013 Holger Veit + + 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 + ROBERT M SUPNIK 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 names of Robert M Supnik and Holger Veit + shall not be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik and Holger Veit. +*/ +#include "pdq3_defs.h" +#include "sim_imd.h" +#include + +/* FDC/DMA bit definitions */ +/* declarations of FDC and DMA chip */ +/* drive select register */ +#define FDC_SEL_SIDE 0x80 /* 0=side0, 1=side1 */ +#define FDC_SEL_SDEN 0x40 /* 0=DDEN, 1=SDEN */ +#define FDC_SEL_UNIT3 0x08 /* 1=select */ +#define FDC_SEL_UNIT2 0x04 /* 1=select */ +#define FDC_SEL_UNIT1 0x02 /* 1=select */ +#define FDC_SEL_UNIT0 0x01 /* 1=select */ + +/* command register */ +#define FDC_BIT_HEADLOAD 0x08 +#define FDC_BIT_VERIFY 0x04 +#define FDC_BIT_STEP3 0x00 +#define FDC_BIT_STEP6 0x01 +#define FDC_BIT_STEP10 0x02 +#define FDC_BIT_STEP15 0x03 +#define FDC_BIT_UPDATE 0x10 +#define FDC_BIT_MULTI 0x10 +#define FDC_BIT_SIDESEL 0x08 +#define FDC_BIT_SIDECMP 0x02 +#define FDC_BIT_DATAMARK 0x01 +#define FDC_BIT_INTIMM 0x08 +#define FDC_BIT_INTIDX 0x04 +#define FDC_BIT_INTN2R 0x02 +#define FDC_BIT_INTR2N 0x01 + +#define FDC_RESTORE 0x00 +#define FDC_SEEK 0x10 +#define FDC_STEP 0x20 +#define FDC_STEP_U 0x30 +#define FDC_STEPIN 0x40 +#define FDC_STEPIN_U 0x50 +#define FDC_STEPOUT 0x60 +#define FDC_STEPOUT_U 0x70 +#define FDC_READSEC 0x80 +#define FDC_READSEC_M 0x90 +#define FDC_WRITESEC 0xa0 +#define FDC_WRITESEC_M 0xb0 +#define FDC_READADDR 0xc4 +#define FDC_READTRK 0xe4 +#define FDC_WRITETRK 0xf4 +#define FDC_FORCEINT 0xd0 +#define FDC_IDLECMD 0xff + +#define FDC_CMDMASK 0xf0 + +/* status register */ +#define FDC_ST1_NOTREADY 0x80 +#define FDC_ST1_WRTPROT 0x40 +#define FDC_ST1_HEADLOAD 0x20 +#define FDC_ST1_SEEKERROR 0x10 +#define FDC_ST1_CRCERROR 0x08 +#define FDC_ST1_TRACK0 0x04 +#define FDC_ST1_IDXPULSE 0x02 +#define FDC_ST1_BUSY 0x01 +#define FDC_ST2_NOTREADY FDC_ST1_NOTREADY +#define FDC_ST2_WRTPROT FDC_ST1_WRTPROT +#define FDC_ST2_TYPEWFLT 0x20 +#define FDC_ST2_RECNOTFND 0x10 +#define FDC_ST2_CRCERROR FDC_ST1_CRCERROR +#define FDC_ST2_LOSTDATA 0x04 +#define FDC_ST2_DRQ 0x02 +#define FDC_ST2_BUSY FDC_ST1_BUSY + +/* DMA ctrl reg */ +#define DMA_CTRL_AECE 0x40 +#define DMA_CTRL_HBUS 0x20 +#define DMA_CTRL_IOM 0x10 +#define DMA_CTRL_TCIE 0x08 +#define DMA_CTRL_TOIE 0x04 +#define DMA_CTRL_DIE 0x02 +#define DMA_CTRL_RUN 0x01 + +/* DMA status reg */ +#define DMA_ST_BUSY 0x80 +#define DMA_ST_AECE DMA_CTRL_AECE +#define DMA_ST_HBUS DMA_CTRL_HBUS +#define DMA_ST_IOM DMA_CTRL_IOM +#define DMA_ST_TCZI 0x08 +#define DMA_ST_TOI 0x04 +#define DMA_ST_DINT 0x02 +#define DMA_ST_BOW 0x01 + +/* FDC unit flags */ +#define UNIT_V_FDC_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_FDC_WLK (1 << UNIT_V_FDC_WLK) +#define UNIT_V_FDC_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_FDC_VERBOSE (1 << UNIT_V_FDC_VERBOSE) + +/* FDC timing */ +#define FDC_WAIT_STEP 3000 +#define FDC_WAIT_READ 8000 +#define FDC_WAIT_READNEXT 800 +#define FDC_WAIT_WRITE 8000 +#define FDC_WAIT_WRITENEXT 800 +#define FDC_WAIT_FORCEINT 100 +#define FDC_WAIT_IDXPULSE 16000 + +uint8 reg_fdc_cmd; /* FC30 write */ +uint8 reg_fdc_status; /* FC30 read */ +int8 reg_fdc_track; /* FC31 */ +int8 reg_fdc_sector; /* FC32 */ +int8 reg_fdc_data; /* FC33 */ +uint8 reg_fdc_drvsel; /* only combined */ + +uint8 reg_dma_ctrl; /* FC38 writeonly */ +uint8 reg_dma_status; /* FC39 */ +uint8 reg_dma_cntl; /* FC3A */ +uint8 reg_dma_cnth; /* FC3B */ +uint8 reg_dma_addrl; /* FC3C */ +uint8 reg_dma_addrh; /* FC3D */ +uint8 reg_dma_addre; /* FC3E */ +uint8 reg_dma_id; /* FC3F - unusable */ +uint16 _reg_dma_cnt; /* combined reg */ +uint32 _reg_dma_addr; /* combined reg */ + +int8 fdc_selected; /* currently selected drive, -1=none */ +uint8 fdc_intpending; /* currently executing force interrupt command, 0=none */ + +uint8 fdc_recbuf[1024]; +uint32 fdc_recsize; + +t_bool dma_isautoload; + +/* externals */ +extern UNIT cpu_unit; + +/* forwards */ +t_stat fdc_svc (UNIT *uptr); +t_stat fdc_boot(int32 unitnum, DEVICE *dptr); +t_stat fdc_reset (DEVICE *uptr); +t_stat fdc_attach(UNIT *uptr, char *cptr); +t_stat fdc_detach(UNIT *uptr); +t_stat pdq3_diskCreate(FILE *fileref, char *ctlr_comment); +t_stat pdq3_diskFormat(DISK_INFO *myDisk); +static void dma_reqinterrupt(); + +/* data structures */ +typedef struct _drvdata { + UNIT *dr_unit; + DISK_INFO *dr_imd; + uint8 dr_ready; + uint8 dr_head; + uint8 dr_trk; + uint8 dr_sec; + uint8 dr_stepdir; /* 0=in, 1=out */ +} DRVDATA; + +DRVDATA fdc_drv[] = { + { NULL, NULL, 0, }, + { NULL, NULL, 0, }, + { NULL, NULL, 0, }, + { NULL, NULL, 0, } +}; + +/* FDC data structures + fdc_dev FDC device descriptor + fdc_unit FDC unit descriptor + fdc_mod FDC modifier list + fdc_reg FDC register list +*/ +IOINFO fdc_ioinfo = { NULL, FDC_IOBASE, 16, FDC_VEC, 2, fdc_read, fdc_write }; +IOINFO fdc_ctxt = { &fdc_ioinfo }; + +UNIT fdc_unit[] = { + { UDATA (&fdc_svc, UNIT_ATTABLE|UNIT_FIX|UNIT_BINK|UNIT_ROABLE|UNIT_DISABLE, 0), 0, }, + { UDATA (&fdc_svc, UNIT_ATTABLE|UNIT_FIX|UNIT_BINK|UNIT_ROABLE|UNIT_DISABLE, 0), 1, }, +}; +REG fdc_reg[] = { + { HRDATA (FCMD, reg_fdc_cmd, 8) }, + { HRDATA (FSTAT, reg_fdc_status, 8) }, + { HRDATA (FTRK, reg_fdc_track, 8) }, + { HRDATA (FSEC, reg_fdc_sector, 8) }, + { HRDATA (FDATA, reg_fdc_data, 8) }, + { HRDATA (FSEL, reg_fdc_drvsel, 8) }, + + { HRDATA (DCMD, reg_dma_ctrl, 8) }, + { HRDATA (DSTAT, reg_dma_status, 8) }, + { HRDATA (DCNTH, reg_dma_cnth, 8) }, + { HRDATA (DCNTL, reg_dma_cntl, 8) }, + { HRDATA (_DCNT, _reg_dma_cnt, 16), REG_RO|REG_HIDDEN }, + { HRDATA (DADDRE, reg_dma_addre, 8) }, + { HRDATA (DADDRH, reg_dma_addrh, 8) }, + { HRDATA (DADDRL, reg_dma_addrl, 8) }, + { HRDATA (_DADDR, _reg_dma_addr, 18), REG_RO|REG_HIDDEN }, + { NULL } +}; +MTAB fdc_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", NULL, &show_iobase }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", NULL, &show_iovec }, + { MTAB_XTD|MTAB_VDV, 0, "PRIO", "PRIO", NULL, &show_ioprio }, + { UNIT_FDC_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_FDC_WLK, UNIT_FDC_WLK, "WRTLCK", "WRTLCK", NULL }, + { 0 } +}; +DEBTAB fdc_dflags[] = { + { "CMD", DBG_FD_CMD }, + { "READ", DBG_FD_READ }, + { "WRITE", DBG_FD_WRITE }, + { "SVC", DBG_FD_SVC }, + { "IMD", DBG_FD_IMD }, + { "IMD2", DBG_FD_IMD2 }, /* deep inspection */ + { "DMA", DBG_FD_DMA }, + { "DMA2", DBG_FD_DMA2 }, /* deep inspection */ + { 0, 0 } +}; + +DEVICE fdc_dev = { + "FDC", /*name*/ + fdc_unit, /*units*/ + fdc_reg, /*registers*/ + fdc_mod, /*modifiers*/ + 2, /*numunits*/ + 16, /*aradix*/ + 16, /*awidth*/ + 1, /*aincr*/ + 8, /*dradix*/ + 8, /*dwidth*/ + NULL, /*examine*/ + NULL, /*deposit*/ + &fdc_reset, /*reset*/ + NULL, /*boot. Note this is hidden, use BOOT CPU. */ + &fdc_attach,/*attach*/ + &fdc_detach,/*detach*/ + &fdc_ctxt, /*ctxt*/ + DEV_DEBUG, /*flags*/ + 0, /*dctrl*/ + fdc_dflags, /*debflags*/ + NULL, /*msize*/ + NULL /*lname*/ +}; + +/* boot unit - not available through BOOT FDC cmd, use BOOT CPU instead */ +t_stat fdc_boot(int32 unitnum, DEVICE *dptr) { + if (unitnum < 0 || ((uint32)unitnum > dptr->numunits)) + return SCPE_NXUN; +// printf("BOOT FDC%d\n",unitnum); + return fdc_autoload(unitnum); +} + +t_stat fdc_attach(UNIT *uptr, char *cptr) { + t_stat rc; + int i = uptr->u_unitno; + char header[4]; + + sim_debug(DBG_FD_IMD, &fdc_dev, DBG_PCFORMAT1 "Attach FDC drive %d\n", DBG_PC, i); + + sim_cancel(uptr); + if ((rc=attach_unit(uptr,cptr)) != SCPE_OK) return rc; + + fdc_drv[i].dr_unit = uptr; + uptr->capac = sim_fsize(uptr->fileref); + fdc_drv[i].dr_ready = 0; + + if (uptr->capac > 0) { + fgets(header, 4, uptr->fileref); + if (strncmp(header, "IMD", 3) != 0) { + printf("FDC: Only IMD disk images are supported\n"); + fdc_drv[i].dr_unit = NULL; + return SCPE_OPENERR; + } + } else { + /* create a disk image file in IMD format. */ + if (pdq3_diskCreate(uptr->fileref, "SIMH pdq3_fdc created") != SCPE_OK) { + printf("FDC: Failed to create IMD disk.\n"); + fdc_drv[i].dr_unit = NULL; + return SCPE_OPENERR; + } + uptr->capac = sim_fsize(uptr->fileref); + } + sim_debug(DBG_FD_IMD, &fdc_dev, DBG_PCFORMAT2 "Attached to '%s', type=IMD, len=%d\n", + DBG_PC, cptr, uptr->capac); + fdc_drv[i].dr_imd = diskOpenEx(uptr->fileref, isbitset(uptr->flags,UNIT_FDC_VERBOSE), &fdc_dev, DBG_FD_IMD, DBG_FD_IMD2); + if (fdc_drv[i].dr_imd == NULL) { + printf("FDC: IMD disk corrupt.\n"); + fdc_drv[i].dr_unit = NULL; + return SCPE_OPENERR; + } + fdc_drv[i].dr_ready = 1; + + /* handle force interrupt to wait for disk change */ + if (isbitset(fdc_intpending,0x01)) { + dma_reqinterrupt(); + clrbit(reg_fdc_status,FDC_ST1_BUSY); + clrbit(fdc_intpending,0x01); + } + + return SCPE_OK; +} + +t_stat fdc_detach(UNIT *uptr) { + t_stat rc; + int i = uptr->u_unitno; + + sim_debug(DBG_FD_IMD, &fdc_dev, DBG_PCFORMAT1 "Detach FDC drive %d\n", DBG_PC, i); + sim_cancel(uptr); + rc = diskClose(&fdc_drv[i].dr_imd); + fdc_drv[i].dr_ready = 0; + + /* handle force interrupt to wait for disk change */ + if (isbitset(fdc_intpending,0x02)) { + cpu_raiseInt(INT_DMAFD); + clrbit(reg_fdc_status,FDC_ST1_BUSY); + clrbit(fdc_intpending,0x02); + } + + if (rc != SCPE_OK) return rc; + return detach_unit(uptr); /* detach unit */ +} + +static t_stat fdc_start(UNIT *uptr,int time) { + /* request service */ + sim_debug(DBG_FD_SVC, &fdc_dev, DBG_PCFORMAT2 "Start Service after %d ticks\n", DBG_PC, time); + return sim_activate(uptr, time); +} + +static t_stat fdc_stop(UNIT *uptr) { + /* request service */ + sim_debug(DBG_FD_SVC, &fdc_dev, DBG_PCFORMAT2 "Cancel Service\n", DBG_PC, time); + return sim_cancel(uptr); +} + +static void fdc_update_rdonly(DRVDATA *curdrv) { + /* read only drive? */ + if (isbitset(curdrv->dr_unit->flags,UNIT_RO)) + setbit(reg_fdc_status,FDC_ST1_WRTPROT); + else + clrbit(reg_fdc_status,FDC_ST1_WRTPROT); +} + +t_bool fdc_driveready(DRVDATA *curdrv) { + /* some drive selected, and disk in drive? */ + if (curdrv==NULL || curdrv->dr_ready == 0) { + setbit(reg_fdc_status,FDC_ST1_NOTREADY); + clrbit(reg_fdc_status,FDC_ST1_BUSY); + reg_fdc_cmd = FDC_IDLECMD; + return FALSE; + } + + /* drive is ready */ + clrbit(reg_fdc_status,FDC_ST1_NOTREADY); + + /* read only drive? */ + fdc_update_rdonly(curdrv); + return TRUE; +} + +static t_bool fdc_istrk0(DRVDATA *curdrv,int8 trk) { + curdrv->dr_trk = trk; + if (trk <= 0) { + setbit(reg_fdc_status,FDC_ST1_TRACK0); + reg_fdc_track = 0; + return TRUE; + } + return FALSE; +} + +/* return true if invalid track (CRC error) */ +static t_bool fdc_stepin(DRVDATA *curdrv, t_bool upd) { + curdrv->dr_stepdir = FDC_STEPIN; + curdrv->dr_trk++; + if (upd) reg_fdc_track = curdrv->dr_trk; + if (curdrv->dr_trk > FDC_MAX_TRACKS) { + setbit(reg_fdc_status,FDC_ST1_CRCERROR); + return TRUE; + } + return FALSE; +} + +/* return true if trk0 reached */ +static t_bool fdc_stepout(DRVDATA *curdrv, t_bool upd) { + curdrv->dr_stepdir = FDC_STEPOUT; + curdrv->dr_trk--; + if (upd) reg_fdc_track = curdrv->dr_trk; + return fdc_istrk0(curdrv, reg_fdc_track); +} + +static void fdc_clr_st1_error() { + clrbit(reg_fdc_status,FDC_ST1_NOTREADY|FDC_ST1_SEEKERROR|FDC_ST1_CRCERROR); +} + +static void dma_interrupt(int bit) { + if (isbitset(reg_dma_ctrl,bit)) { + sim_debug(DBG_FD_DMA, & fdc_dev, DBG_PCFORMAT2 "Raise DMA/FDC interrupt\n", DBG_PC); + cpu_raiseInt(INT_DMAFD); + } +} + +static t_bool dma_abort(t_bool fromfinish) { + clrbit(reg_dma_status,DMA_ST_BUSY); + clrbit(reg_dma_ctrl,DMA_CTRL_RUN); + + /* if autoload was finished, finally start the CPU. + * note: autoload will read the first track, and then fail at end of track with an error */ + if (dma_isautoload) { + sim_debug(DBG_FD_DMA, & fdc_dev, DBG_PCFORMAT2 "AUTOLOAD finished by end-of-track (DMA aborted)\n", DBG_PC); + cpu_finishAutoload(); + dma_isautoload = FALSE; + } else + if (!fromfinish) { + sim_debug(DBG_FD_DMA, & fdc_dev, DBG_PCFORMAT2 "Aborted transfer\n", DBG_PC); + } + return FALSE; +} + +/* all data transferred */ +static void dma_finish() { + setbit(reg_dma_status,DMA_ST_TCZI); + dma_abort(TRUE); + dma_interrupt(DMA_CTRL_TCIE); + sim_debug(DBG_FD_DMA, & fdc_dev, DBG_PCFORMAT2 "Finished transfer\n", DBG_PC); +} + +/* request interrupt from FDC */ +static void dma_reqinterrupt() { + setbit(reg_dma_status,DMA_ST_DINT); + dma_interrupt(DMA_CTRL_DIE); +} + +static void dma_fix_regs() { + reg_dma_cntl = _reg_dma_cnt & 0xff; + reg_dma_cnth = _reg_dma_cnt>>8; + reg_dma_addre = (_reg_dma_addr>>16) & 0x03; + reg_dma_addrh = (_reg_dma_addr>>8) & 0xff; + reg_dma_addrl = _reg_dma_addr & 0xff; +} + +/* return true if successfully transferred */ +static t_bool dma_transfer_to_ram(uint8 *buf, int bufsize) { + t_bool rc = TRUE; + int i; + uint16 data; + t_addr tstart = _reg_dma_addr/2; + int cnt = _reg_dma_cnt ^ 0xffff; + int xfersz = bufsize > cnt ? cnt : bufsize; + + sim_debug(DBG_FD_DMA, &fdc_dev, DBG_PCFORMAT2 "Transfer to RAM $%x...$%x\n", + DBG_PC, _reg_dma_addr/2,(_reg_dma_addr + xfersz - 1)/2); + for (i=0; i cnt ? cnt : bufsize; + + sim_debug(DBG_FD_DMA, &fdc_dev, DBG_PCFORMAT2 "Transfer from RAM $%x...$%x\n", + DBG_PC, _reg_dma_addr/2, (_reg_dma_addr + xfersz - 1)/2); + + if (isbitset(reg_dma_ctrl,DMA_CTRL_IOM)) + printf("Warning: wrong IOM direction for DMA transfer from RAM\n"); + + for (i=0; idr_imd, curdrv->dr_trk, curdrv->dr_head)) { + setbit(reg_fdc_status,FDC_ST2_RECNOTFND); + return FALSE; + } + + /* get sector size available */ + fdc_recsize = curdrv->dr_imd->track[curdrv->dr_trk][curdrv->dr_head].sectsize; + + /* clear errors. Also clear LOSTDATA bit due to aliasing to TRACK00 bit from previous seek operation */ + clrbit(reg_fdc_status,FDC_ST2_NOTREADY|FDC_ST2_LOSTDATA|FDC_ST2_WRTPROT); + + if (sectRead(curdrv->dr_imd, curdrv->dr_trk, curdrv->dr_head, curdrv->dr_sec, + fdc_recbuf, fdc_recsize, &flags, &fdc_recsize)) { + setbit(reg_fdc_status,FDC_ST2_RECNOTFND); + return FALSE; + } + if (isbitset(flags,IMD_DISK_IO_ERROR_CRC)) { + setbit(reg_fdc_status,FDC_ST2_CRCERROR); + return FALSE; /* terminate read */ + } + if (isbitset(flags,IMD_DISK_IO_DELETED_ADDR_MARK)) + setbit(reg_fdc_status,FDC_ST2_TYPEWFLT); + + /* trigger DMA transfer */ + if (!dma_transfer_to_ram(fdc_recbuf, fdc_recsize)) + return FALSE; + + /* now finished */ + return TRUE; +} + +static t_bool fdc_writesec(DRVDATA *curdrv) { + uint32 flags; + + /* write protect? */ + if (imdIsWriteLocked(curdrv->dr_imd)) { + dma_abort(FALSE); + setbit(reg_fdc_status,FDC_ST2_WRTPROT); + return FALSE; + } + + /* is sector available? */ + if (sectSeek(curdrv->dr_imd, curdrv->dr_trk, curdrv->dr_head)) { + setbit(reg_fdc_status,FDC_ST2_RECNOTFND); + return FALSE; + } + /* clear errors. Also clear LOSTDATA bit due to aliasing to TRACK00 bit from previous seek operation */ + clrbit(reg_fdc_status,FDC_ST2_NOTREADY|FDC_ST2_LOSTDATA|FDC_ST2_WRTPROT); + + /* get sector size */ + fdc_recsize = curdrv->dr_imd->track[curdrv->dr_trk][curdrv->dr_head].sectsize; + + /* get from ram into write buffer */ + if (!dma_transfer_from_ram(fdc_recbuf, fdc_recsize)) + return FALSE; + + if (sectWrite(curdrv->dr_imd, curdrv->dr_trk, curdrv->dr_head, curdrv->dr_sec, + fdc_recbuf, fdc_recsize, &flags, &fdc_recsize)) { + setbit(reg_fdc_status,FDC_ST2_RECNOTFND); + return FALSE; + } + if (isbitset(flags,IMD_DISK_IO_ERROR_GENERAL)) { + setbit(reg_fdc_status,FDC_ST2_TYPEWFLT); + return FALSE; + } + if (isbitset(flags,IMD_DISK_IO_ERROR_WPROT)) { + setbit(reg_fdc_status,FDC_ST2_WRTPROT); + return FALSE; + } + /* advance to next sector for multiwrite */ + if (isbitset(reg_fdc_cmd,FDC_BIT_MULTI)) { /* multi bit */ + curdrv->dr_sec++; + reg_fdc_sector++; + } + + /* now finished */ + return TRUE; +} + +static t_bool fdc_rwerror() { + /* note: LOSTDATA cannot occur */ + return isbitset(reg_fdc_status,FDC_ST2_TYPEWFLT|FDC_ST2_RECNOTFND|FDC_ST2_CRCERROR /*|FDC_ST2_LOSTDATA*/); +} + +static t_stat fdc_set_notready(uint8 cmd) +{ + switch (cmd & FDC_CMDMASK) { + default: + case FDC_RESTORE: + case FDC_SEEK: + case FDC_STEP: /* single step in current direction, no update */ + case FDC_STEPIN: /* single step towards center */ + case FDC_STEPOUT: /* single step towards edge of disk */ + case FDC_STEP_U: + case FDC_STEPIN_U: + case FDC_STEPOUT_U: + setbit(reg_fdc_status,FDC_ST1_SEEKERROR); + break; + + case FDC_READSEC_M: + case FDC_READSEC: /* type II: read a sector via DMA */ + setbit(reg_fdc_status,FDC_ST2_CRCERROR); + break; + case FDC_WRITESEC_M: + case FDC_WRITESEC: /* type II: read a sector via DMA */ + setbit(reg_fdc_status,FDC_ST2_TYPEWFLT); + break; + } + return SCPE_OK; +} + +static t_stat fdc_restartmulti(DRVDATA *curdrv,int wait) { + /* advance to next sector for multiread */ + sim_debug(DBG_FD_SVC, &fdc_dev, " Restarting FDC_SVC for multiple R/W\n"); + curdrv->dr_sec++; + reg_fdc_sector++; + /* restart service for multi-sector */ + return fdc_start(curdrv->dr_unit, wait); +} + +/* process the FDC commands, and restart, if necessary */ +t_stat fdc_svc(UNIT *uptr) { + DRVDATA *curdrv = fdc_selected==-1 ? NULL : &fdc_drv[fdc_selected]; + t_bool rdy = fdc_driveready(curdrv); + t_bool um_flg; /* update or multi bit */ + + sim_debug(DBG_FD_SVC,&fdc_dev, DBG_PCFORMAT2 "Calling FDC_SVC for unit=%x cmd=%x\n", + DBG_PC, fdc_selected, reg_fdc_cmd); + + if (reg_fdc_cmd == FDC_IDLECMD) return SCPE_OK; + + if (!rdy) return fdc_set_notready(reg_fdc_cmd & FDC_CMDMASK); + + um_flg = isbitset(reg_fdc_cmd,FDC_BIT_UPDATE); + switch (reg_fdc_cmd & FDC_CMDMASK) { + case FDC_RESTORE: + fdc_istrk0(curdrv,0); + curdrv->dr_stepdir = FDC_STEPOUT; + break; + case FDC_SEEK: + if (reg_fdc_track > reg_fdc_data) { + if (fdc_stepout(curdrv, TRUE)) break; + return fdc_start(curdrv->dr_unit,FDC_WAIT_STEP); + } else if (reg_fdc_track < reg_fdc_data) { + if (fdc_stepin(curdrv, TRUE)) break; + return fdc_start(curdrv->dr_unit,FDC_WAIT_STEP); + } + /* found position */ + fdc_clr_st1_error(); + break; + case FDC_STEP: /* single step in current direction, no update */ + case FDC_STEP_U: + if (curdrv->dr_stepdir == FDC_STEPIN) { + if (fdc_stepin(curdrv, um_flg)) break; + } else + fdc_stepout(curdrv, um_flg); + fdc_clr_st1_error(); + break; + case FDC_STEPIN: /* single step towards center */ + case FDC_STEPIN_U: + if (fdc_stepin(curdrv, um_flg)) break; + fdc_clr_st1_error(); + break; + case FDC_STEPOUT: /* single step towards edge of disk */ + case FDC_STEPOUT_U: + if (fdc_stepin(curdrv, um_flg)) break; + fdc_clr_st1_error(); + break; + + case FDC_READSEC_M: + case FDC_READSEC: /* type II: read a sector via DMA */ + if (!fdc_readsec(curdrv) || fdc_rwerror()) { + dma_abort(TRUE); + break; + } + if (isbitset(reg_dma_status,DMA_ST_BUSY) && um_flg) + return fdc_restartmulti(curdrv,FDC_WAIT_READNEXT); + break; + case FDC_WRITESEC_M: + case FDC_WRITESEC: /* type II: read a sector via DMA */ + if (!fdc_writesec(curdrv) || fdc_rwerror()) { + dma_abort(TRUE); + break; + } + if (isbitset(reg_dma_status,DMA_ST_BUSY) && um_flg) + return fdc_restartmulti(curdrv,FDC_WAIT_WRITENEXT); + break; + default: + printf("fdc_svc: Fix me - command not yet implemented: cmd=0x%x\n", reg_fdc_cmd); + } + + clrbit(reg_fdc_status,FDC_ST1_BUSY); + reg_fdc_cmd = FDC_IDLECMD; + return SCPE_OK; +} + +t_stat fdc_binit() { + fdc_selected = -1; + fdc_intpending = 0; + + /* reset FDC registers */ + reg_fdc_cmd = FDC_IDLECMD; /* invalid command, used as idle marker */ + reg_fdc_status = 0; + reg_fdc_track = 0; + reg_fdc_sector = 1; + reg_fdc_data = 1; + reg_fdc_drvsel = 0; + + /* reset DMA registers */ + reg_dma_ctrl = DMA_CTRL_AECE | DMA_CTRL_HBUS | DMA_CTRL_IOM; + reg_dma_status = DMA_ST_AECE | DMA_ST_HBUS | DMA_ST_IOM; + _reg_dma_cnt = 0x0001; + /* hack: initialize boot code to load ad 0x2000(word address). + * However, DMA is based on byte addresses, so multiply with 2 */ + _reg_dma_addr = reg_dmabase*2; + reg_dma_id = 0; + + dma_fix_regs(); + return SCPE_OK; +} + +t_stat fdc_reset (DEVICE *dptr) { + int i; + DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt; +// printf("RESET FDC\n"); + + if (dptr->flags & DEV_DIS) + del_ioh(ctxt->ioi); + else + add_ioh(ctxt->ioi); + + for (i=0; i<4; i++) { + DRVDATA *cur = &fdc_drv[i]; + cur->dr_unit = &fdc_unit[i]; + cur->dr_trk = 0; + cur->dr_sec = 1; + cur->dr_head = 0; + cur->dr_stepdir = 0; + } + return fdc_binit(); +} + +/* select drive, according to select register */ +static DRVDATA *fdc_select() { + DRVDATA *curdrv = NULL; + + if (isbitset(reg_fdc_drvsel,FDC_SEL_UNIT0)) fdc_selected = 0; + else if (isbitset(reg_fdc_drvsel,FDC_SEL_UNIT1)) fdc_selected = 1; + else if (isbitset(reg_fdc_drvsel,FDC_SEL_UNIT2)) fdc_selected = 2; + else if (isbitset(reg_fdc_drvsel,FDC_SEL_UNIT3)) fdc_selected = 3; + else fdc_selected = -1; + + if (fdc_selected >= 0) { + curdrv = &fdc_drv[fdc_selected]; + + fdc_update_rdonly(curdrv); /* update R/O flag */ + curdrv->dr_head = isbitset(reg_fdc_drvsel,FDC_SEL_SIDE) ? 1 : 0; + curdrv->dr_unit = &fdc_unit[fdc_selected]; + } + return curdrv; +} + +static char *cmdlist[] = { + "Restore","Seek","Step","Step+Upd","StepIn","StepIn+Upd", + "StepOut","StepOut+Upd","Read","Read+Multi","Write","WriteMulti", + "ReadAddr","ForceInt","ReadTrack","WriteTrack" +}; + +static void debug_fdccmd(uint16 cmd) { + char buf[200]; + uint16 dsel = cmd >> 8, cr = (cmd >> 4) & 0x0f; + + buf[0] = 0; + if (cmd & 0xff00) { + strcat(buf,"DSR=["); + strcat(buf,dsel & FDC_SEL_SIDE ? "SIDE1" : "SIDE0"); + if (dsel & FDC_SEL_SDEN) strcat(buf,",SDEN"); + strcat(buf,",UNIT"); + if (dsel & FDC_SEL_UNIT3) strcat(buf,"3"); + else if (dsel & FDC_SEL_UNIT2) strcat(buf,"2"); + else if (dsel & FDC_SEL_UNIT1) strcat(buf,"1"); + else if (dsel & FDC_SEL_UNIT0) strcat(buf,"0"); + strcat(buf,"] "); + } + strcat(buf,"CR=["); + strcat(buf,cmdlist[cr]); + if (cr < 8) { + if (cmd & FDC_BIT_HEADLOAD) strcat(buf,"+Load"); + if (cmd & FDC_BIT_VERIFY) strcat(buf,"+Vrfy"); + cmd &= FDC_BIT_STEP15; + if (cmd == FDC_BIT_STEP3) strcat(buf,"+Step3"); + else if (cmd == FDC_BIT_STEP6) strcat(buf,"+Step6"); + else if (cmd == FDC_BIT_STEP10) strcat(buf,"+Step10"); + else if (cmd == FDC_BIT_STEP15) strcat(buf,"+Step15"); + } else + switch (cr) { + case 8: case 9: + case 0xa: case 0xb: + strcat(buf, cmd & FDC_BIT_SIDESEL ? "+SideSel1" : "+SideSel0"); + strcat(buf, cmd & FDC_BIT_SIDECMP ? "+SideCmp1" : "+SideCmp0"); + if (cr > 9) + strcat(buf, cmd & FDC_BIT_DATAMARK ? "+DelMark" : "+DataMark"); + default: + break; + case 0x0f: + if (cmd & FDC_BIT_INTIMM) strcat(buf,"+IMM"); + if (cmd & FDC_BIT_INTIDX) strcat(buf,"+IDX"); + if (cmd & FDC_BIT_INTN2R) strcat(buf,"+N2R"); + if (cmd & FDC_BIT_INTR2N) strcat(buf,"+R2N"); + } + strcat(buf,"]"); + sim_debug(DBG_FD_CMD, &fdc_dev, DBG_PCFORMAT2 "Command: %s\n", DBG_PC,buf); +} + +static t_stat fdc_docmd(uint16 data) { + UNIT *uptr; + DRVDATA *curdrv = fdc_select(); + if (curdrv== NULL) return SCPE_IOERR; + + debug_fdccmd(data); + uptr = curdrv->dr_unit; + + if (!fdc_driveready(curdrv)) { + sim_debug(DBG_FD_CMD,&fdc_dev, DBG_PCFORMAT2 "fdc_docmd: drive not ready\n", DBG_PC); + return SCPE_OK; + } + + reg_fdc_cmd = data & 0xff; + switch (data & FDC_CMDMASK) { + /* type I commands */ + case FDC_RESTORE: + case FDC_SEEK: + case FDC_STEP: + case FDC_STEP_U: + case FDC_STEPIN: + case FDC_STEPIN_U: + case FDC_STEPOUT: + case FDC_STEPOUT_U: + setbit(reg_fdc_status, FDC_ST1_BUSY); + return fdc_start(uptr,FDC_WAIT_STEP); + + /* type II commands */ + case FDC_READSEC: + case FDC_READSEC_M: + curdrv->dr_sec = reg_fdc_sector; /* sector to start */ + setbit(reg_fdc_status, FDC_ST2_BUSY); + return fdc_start(uptr,FDC_WAIT_READ); + case FDC_WRITESEC: + case FDC_WRITESEC_M: + curdrv->dr_sec = reg_fdc_sector; /* sector to start */ + setbit(reg_fdc_status, FDC_ST2_BUSY); + return fdc_start(uptr,FDC_WAIT_WRITE); + + /* type III commands */ + default: + printf("fdc_docmd: Fix me - command not yet implemented: cmd=0x%x\n", reg_fdc_cmd); + setbit(reg_fdc_status, FDC_ST2_BUSY); + return SCPE_NOFNC; + + /* type IV command */ + case FDC_FORCEINT: + if (isbitset(data,0x01)) { /* int on transition from not-ready to ready */ + fdc_stop(uptr); + } else if (isbitset(data,0x06)) { /* int on transition from ready to not-ready, or vice versa */ + /* handle in fdc_detach */ + fdc_intpending |= reg_fdc_cmd; + return SCPE_OK; + } else if (isbitset(data,0x08)) { /* immediate int */ + dma_reqinterrupt(); + return SCPE_OK; /* don't reset BUSY */ + } else { /* terminate */ + fdc_stop(uptr); + /* successful cmd clears errors */ + clrbit(reg_fdc_status,FDC_ST2_TYPEWFLT|FDC_ST2_RECNOTFND|FDC_ST2_CRCERROR|FDC_ST2_LOSTDATA); + } + /* reset busy bit */ + clrbit(reg_fdc_status,FDC_ST1_BUSY); + } + return SCPE_OK; +} + +void dma_docmd(uint16 data) { + reg_dma_ctrl = data; + reg_dma_status &= 0x8f; + reg_dma_status |= (reg_dma_ctrl & 0x70); + + if (isbitset(reg_dma_ctrl,DMA_CTRL_RUN)) + setbit(reg_dma_status,DMA_ST_BUSY); +} + +/* setup FDC/DMA to read first track into low memory */ +t_stat fdc_autoload(int unitnum) { + int unitbit = 1 << unitnum; + + sim_debug(DBG_FD_CMD, &fdc_dev, DBG_PCFORMAT2 "Autoload Unit=%d\n", DBG_PC, unitnum); + dma_isautoload = TRUE; + + + /* note: this is partly in microcode/ROM. The DMA cntrlr itself does not set the + * FDC register for multi_read */ + fdc_reset(&fdc_dev); + dma_docmd(DMA_CTRL_RUN|DMA_CTRL_DIE|DMA_CTRL_TCIE|DMA_CTRL_IOM|DMA_CTRL_HBUS|DMA_CTRL_AECE); + + reg_fdc_drvsel = FDC_SEL_SDEN | unitbit; + return fdc_docmd(FDC_READSEC_M); +} + +static t_bool fd_reg16bit[] = { + FALSE,FALSE,FALSE,FALSE, + TRUE, TRUE, TRUE, TRUE, + FALSE,FALSE,FALSE,FALSE, + FALSE,FALSE,FALSE,FALSE +}; + +t_stat fdc_write(t_addr ioaddr, uint16 data) { + int io = ioaddr & 15; + sim_debug(DBG_FD_WRITE, &fdc_dev, DBG_PCFORMAT0 "%s write %04x to IO=$%04x\n", + DBG_PC, fd_reg16bit[io] ? "Byte":"Word", data, ioaddr); + switch (io) { + case 4: /* cmd + drvsel */ + reg_fdc_drvsel = (data >> 8) & 0xff; + case 0: /* cmd writeonly */ + fdc_docmd(data); + break; + case 5: /* track + drvsel */ + reg_fdc_drvsel = (data >> 8) & 0xff; + case 1: /* track */ + reg_fdc_track = data & 0xff; + break; + case 6: /* sector + drvsel */ + reg_fdc_drvsel = (data >> 8) & 0xff; + case 2: /* sector */ + reg_fdc_sector = data & 0xff; + break; + case 7: /* data + drvsel */ + reg_fdc_drvsel = (data >> 8) & 0xff; + case 3: /* data */ + reg_fdc_data = data & 0xff; + break; + case 8: /* dma ctrl */ + dma_docmd(data); + break; + case 9: /* dma status */ + if (isbitset(reg_dma_status,DMA_ST_BUSY)) + printf("Warning: DMA: write status while BUSY\n"); + reg_dma_status = data & 0x8f; + break; + case 0x0a: /* count low */ + reg_dma_cntl = data; + break; + case 0x0b: /* count high */ + reg_dma_cnth = data; + break; + case 0x0c: /* addr low */ + reg_dma_addrl = data; + break; + case 0x0d: /* addr high */ + reg_dma_addrh = data; + break; + case 0x0e: /* addr ext */ + reg_dma_addre = data & 0x03; + break; + case 0x0f: /* ID register */ + reg_dma_id = data; + break; + } + _reg_dma_cnt = (reg_dma_cnth << 8) | reg_dma_cntl; + if (_reg_dma_cnt) clrbit(reg_dma_status,DMA_ST_TCZI); + _reg_dma_addr = (((uint32)reg_dma_addre)<<16) | (((uint32)reg_dma_addrh)<<8) | reg_dma_addrl; + + (void)fdc_select(); + return SCPE_OK; +} + +t_stat fdc_read(t_addr ioaddr, uint16 *data) { + switch (ioaddr & 15) { + case 0: /* status readonly */ + case 4: + *data = reg_fdc_status; + break; + case 1: /* track */ + case 5: + *data = reg_fdc_track; + break; + case 2: /* sector */ + case 6: + *data = reg_fdc_sector; + break; + case 3: /* data */ + case 7: + *data = reg_fdc_data; + break; + case 8: /* read nothing */ + *data = 0; + break; + case 9: + *data = reg_dma_status; + break; + case 0x0a: /* byte low */ + *data = reg_dma_cntl; + break; + case 0x0b: + *data = reg_dma_cnth; + break; + case 0x0c: + *data = reg_dma_addrl; + break; + case 0x0d: + *data = reg_dma_addrh; + break; + case 0x0e: + *data = reg_dma_addre; + break; + default: /* note: ID register 0xfc3f is unusable because RE is tied to VCC */ + *data = reg_dma_id; + break; + } + sim_debug(DBG_FD_READ, &fdc_dev, DBG_PCFORMAT1 "Byte read %02x from IO=$%04x\n", + DBG_PC, *data, ioaddr); + return SCPE_OK; +} + +/* + * Create an ImageDisk (IMD) file. This function just creates the comment header, and allows + * the user to enter a comment. After the IMD is created, it must be formatted with a format + * program on the simulated operating system, ie CP/M, CDOS, 86-DOS. + * + * If the IMD file already exists, the user will be given the option of overwriting it. + */ +t_stat pdq3_diskCreate(FILE *fileref, char *ctlr_comment) { + DISK_INFO *myDisk = NULL; + char *comment; + char *curptr; + uint8 answer; + int32 len, remaining; + + if(fileref == NULL) { + return (SCPE_OPENERR); + } + + if(sim_fsize(fileref) != 0) { + printf("PDQ3_IMD: Disk image already has data, do you want to overwrite it? "); + answer = getchar(); + + if((answer != 'y') && (answer != 'Y')) { + return (SCPE_OPENERR); + } + } + + if((curptr = comment = calloc(1, MAX_COMMENT_LEN)) == 0) { + printf("PDQ3_IMD: Memory allocation failure.\n"); + return (SCPE_MEM); + } + + printf("PDQ3_IMD: Enter a comment for this disk.\n" + "PDQ3_IMD: Terminate with a '.' on an otherwise blank line.\n"); + remaining = MAX_COMMENT_LEN; + do { + printf("IMD> "); + fgets(curptr, remaining - 3, stdin); + if (strcmp(curptr, ".\n") == 0) { + remaining = 0; + } else { + len = strlen(curptr) - 1; + if (curptr[len] != '\n') + len++; + remaining -= len; + curptr += len; + *curptr++ = 0x0d; + *curptr++ = 0x0a; + } + } while (remaining > 4); + *curptr = 0x00; + + /* rewind to the beginning of the file. */ + rewind(fileref); + + /* Erase the contents of the IMD file in case we are overwriting an existing image. */ + sim_set_fsize(fileref, ftell (fileref)); + + fprintf(fileref, "IMD SIMH %s %s\n", __DATE__, __TIME__); + fputs(comment, fileref); + free(comment); + fprintf(fileref, "%s\n", ctlr_comment); + fputc(0x1A, fileref); /* EOF marker for IMD comment. */ + fflush(fileref); + + if((myDisk = diskOpen(fileref, 0)) == NULL) { + printf("PDQ3_IMD: Error opening disk for format.\n"); + return(SCPE_OPENERR); + } + + if(pdq3_diskFormat(myDisk) != SCPE_OK) { + printf("PDQ3_IMD: error formatting disk.\n"); + } + + return diskClose(&myDisk); +} + +t_stat pdq3_diskFormat(DISK_INFO *myDisk) { + uint8 i; + uint8 sector_map[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26}; + uint32 flags; + + printf("PDQ3_IMD: Formatting disk in PDQ3 format.\n"); + + /* format first track as 26 sectors with 128 bytes */ + if((trackWrite(myDisk, 0, 0, 26, 128, sector_map, IMD_MODE_500K_FM, 0xE5, &flags)) != 0) { + printf("PDQ3_IMD: Error formatting track 0\n"); + return SCPE_IOERR; + } + putchar('.'); + + /* format the remaining tracks as 26 sectors with 256 bytes */ + for(i=1;i<77;i++) { + if((trackWrite(myDisk, i, 0, 26, 256, sector_map, IMD_MODE_500K_MFM, 0xE5, &flags)) != 0) { + printf("PDQ3_IMD: Error formatting track %d\n", i); + return SCPE_IOERR; + } else { + putchar('.'); + } + } + + printf("\nPDQ3_IMD: Format Complete.\n"); + return SCPE_OK; +} diff --git a/PDQ-3/pdq3_mem.c b/PDQ-3/pdq3_mem.c new file mode 100644 index 00000000..e90b73ce --- /dev/null +++ b/PDQ-3/pdq3_mem.c @@ -0,0 +1,355 @@ +/* + Work derived from Copyright (c) 2004-2012, Robert M. Supnik + Copyright (c) 2013 Holger Veit + + 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 + ROBERT M SUPNIK 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 names of Robert M Supnik and Holger Veit + shall not be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik and Holger Veit. + + 20130920 hv initial version, moved some code from pdq3_cpu.c +*/ +#include "pdq3_defs.h" + +/* the memory */ +uint16 M[MAXMEMSIZE]; + +/****************************************************************************** + * IO dispatcher + *****************************************************************************/ + +static t_bool initio = FALSE; +#define IOSIZE 4096 +#define IOPAGEMASK 0x0fff +IOREAD ioreaders[IOSIZE]; +IOWRITE iowriters[IOSIZE]; + +/* I/O devices are implemented this way: + * a unit will register its own I/O addresses together with its handler + * in a hash which allows simple lookup of memory mapped I/O addresses + */ +t_stat pdq3_ioinit() { + int i; + if (!initio) { + for (i=0; i < IOSIZE; i++) { + ioreaders[i] = NULL; + iowriters[i] = NULL; + } + for (i=8; i < 32; i++) + cpu_setIntVec(NIL, i); + initio = TRUE; + } + return SCPE_OK; +} + +t_stat add_ioh(IOINFO* ioi) { + while (ioi) { + int i; + for (i=0; iiosize; i++) { + int idx = (ioi->iobase + i) & IOPAGEMASK; + ioreaders[idx] = ioi->read; + iowriters[idx] = ioi->write; + } + ioi = ioi->next; + } + return SCPE_OK; +} + +t_stat del_ioh(IOINFO* ioi) { + while (ioi) { + int i; + for (i=0; iiosize; i++) { + int idx = (ioi->iobase + i) & IOPAGEMASK; + ioreaders[idx] = NULL; + iowriters[idx] = NULL; + } + ioi = ioi->next; + } + return SCPE_OK; +} + +/****************************************************************************** + * configuration + *****************************************************************************/ +t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc) { + DEVICE* dptr; + DEVCTXT* ctxt; + IOINFO* ioi; + t_bool first = TRUE; + if (!uptr) return SCPE_IERR; + if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR; + ctxt = (DEVCTXT*)dptr->ctxt; + ioi = ctxt->ioi; + while (ioi) { + if (ioi->iobase) { + if (ioi->iobase > 0xfc00) { + fprintf(st, first ? "IOBASE=$%04x":",$%04x", ioi->iobase); + first = FALSE; + } + } + ioi = ioi->next; + } + return SCPE_OK; +} + +t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc) { + t_stat rc; + DEVICE* dptr; + DEVCTXT* ctxt; + IOINFO* ioi; + t_bool first = TRUE; + if (!cptr) return SCPE_ARG; + if (!uptr) return SCPE_IERR; + if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR; + ctxt = (DEVCTXT*)dptr->ctxt; + ioi = ctxt->ioi; + if (ioi->next) + return SCPE_ARG; /* note: fixed devices on mainboard cannot be changed */ + ioi->iobase = get_uint(cptr, 16, 0xffff, &rc); + return rc; +} + +t_stat set_iovec(UNIT *uptr, int32 val, char *cptr, void *desc) { + t_stat rc; + DEVICE* dptr; + DEVCTXT* ctxt; + IOINFO* ioi; + t_bool first = TRUE; + if (!cptr) return SCPE_ARG; + if (!uptr) return SCPE_IERR; + if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR; + ctxt = (DEVCTXT*)dptr->ctxt; + ioi = ctxt->ioi; + if (ioi->next) + return SCPE_ARG; /* note: fixed devices on mainboard cannot be changed */ + ioi->qvector = get_uint(cptr, 16, 0xff, &rc); + return rc; +} + +t_stat show_iovec(FILE *st, UNIT *uptr, int value, void *desc) { + DEVICE* dptr; + DEVCTXT* ctxt; + IOINFO* ioi; + t_bool first = TRUE; + if (!uptr) return SCPE_IERR; + if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR; + ctxt = (DEVCTXT*)dptr->ctxt; + ioi = ctxt->ioi; + while (ioi) { + if (ioi->qprio < 32) { + fprintf(st, first ? "VECTOR=$%04x":",$%04x", ioi->qvector); + first = FALSE; + } + ioi = ioi->next; + } + return SCPE_OK; +} + +t_stat set_ioprio(UNIT *uptr, int32 val, char *cptr, void *desc) { + t_stat rc; + DEVICE* dptr; + DEVCTXT* ctxt; + IOINFO* ioi; + t_bool first = TRUE; + if (!cptr) return SCPE_ARG; + if (!uptr) return SCPE_IERR; + if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR; + ctxt = (DEVCTXT*)dptr->ctxt; + ioi = ctxt->ioi; + if (ioi->next) + return SCPE_ARG; /* note: fixed devices on mainboard cannot be changed */ + ioi->qprio = get_uint(cptr, 16, 31, &rc); + return rc; +} + +t_stat show_ioprio(FILE *st, UNIT *uptr, int value, void *desc) { + DEVICE* dptr; + DEVCTXT* ctxt; + IOINFO* ioi; + t_bool first = TRUE; + if (!uptr) return SCPE_IERR; + if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR; + ctxt = (DEVCTXT*)dptr->ctxt; + ioi = ctxt->ioi; + while (ioi) { + if (ioi->qprio < 32) { + fprintf(st, first ? "PRIO=%d":",%d", ioi->qprio); + first = FALSE; + } + ioi = ioi->next; + } + return SCPE_OK; +} + +/****************************************************************************** + * central memory handling + *****************************************************************************/ +t_stat Read(t_addr base, t_addr woffset, uint16 *data, uint32 dctrl) { + t_stat rc; + uint16 ea = base + woffset; + + /* Note: the PRIAM driver attempts to read the ready bit from FF25 (bit 9) which should be 1. + * As long as we don't have a HDP device, the invalid value should be 0x0000 */ + *data = 0x0000; /* preload invalid data value */ + + if (ea < 0xf000 || (ea == 0xfffe && cpu_unit.capac > 65535)) { + *data = M[ea]; /* normal memory */ + rc = SCPE_OK; + } else { + IOREAD reader = ioreaders[ea & IOPAGEMASK]; + rc = reader ? (*reader)(ea, data) : SCPE_NXM; + } + if (rc != SCPE_OK) { + cpu_buserror(); + sim_debug(DBG_CPU_READ, &cpu_dev, DBG_PCFORMAT1 "Invalid Mem read from $%04x\n", DBG_PC, ea); + printf("read buserror: ea=$%04x at $%x:#%x\n",ea,reg_segb,reg_ipc); + return rc; + } + if (dctrl & DBG_CPU_PICK) { + sim_debug(DBG_CPU_PICK, &cpu_dev, DBG_PCFORMAT1 "Pick %04x at SP=$%04x\n", DBG_PC, *data, ea); + } else if (dctrl & DBG_CPU_POP) { + sim_debug(DBG_CPU_POP, &cpu_dev, DBG_PCFORMAT2 "Pop %04x from SP=$%04x\n", DBG_PC, *data, ea); + } else { + sim_debug(dctrl, &cpu_dev, DBG_PCFORMAT2 "Word read %04x from $%04x\n", DBG_PC, *data, ea); + } + return rc; +} + +/* read routine that does not generate bus errors, for SIMH Examine + * will read 0x0000 for unknown memory */ +t_stat ReadEx(t_addr base, t_addr woffset, uint16 *data) { + t_stat rc; + uint16 ea = base + woffset; + *data = 0x0000; /* preload invalid data value */ + if (ea < 0xf000) { + *data = M[ea]; /* normal memory */ + rc = SCPE_OK; + } else { + IOREAD reader = ioreaders[ea & IOPAGEMASK]; + rc = reader ? (*reader)(ea, data) : SCPE_NXM; + } + return rc; +} + +t_stat Write(t_addr base, t_addr woffset, uint16 data, uint32 dctrl) { + t_stat rc; + uint16 ea = base + woffset; + if (ea < 0xf000) { + M[ea] = data; + rc = SCPE_OK; + } else { + IOWRITE write = iowriters[ea & IOPAGEMASK]; + rc = write ? (*write)(ea, data) : SCPE_NXM; + } + if (rc != SCPE_OK) { + cpu_buserror(); + sim_debug(DBG_CPU_WRITE, &cpu_dev, DBG_PCFORMAT0 "Invalid Mem write to $%04x\n", DBG_PC, ea); +printf("write buserror %x at %x:%x\n",ea,reg_segb,reg_ipc); +//exit(1); + return rc; + } + if (dctrl & DBG_CPU_STACK) + sim_debug(DBG_CPU_PUSH, &cpu_dev, DBG_PCFORMAT1 "Push %04x to SP=$%04x\n", DBG_PC, data, ea); + else + sim_debug(dctrl, &cpu_dev, DBG_PCFORMAT2 "Word write %04x to $%04x\n", DBG_PC, data, ea); + return rc; +} + +t_stat ReadB(t_addr base, t_addr boffset, uint16 *data, uint32 dctrl) +{ + t_stat rc; + t_addr ea = base + boffset/2; + if ((rc=Read(ea, 0, data, DBG_NONE)) != SCPE_OK) return rc; + if (boffset & 1) + *data >>= 8; + *data &= 0xff; + if (dctrl & DBG_CPU_FETCH) + sim_debug(DBG_CPU_FETCH, &cpu_dev, DBG_PCFORMAT0 "Fetch %02x from SEGB:%04x\n", + DBG_PC, *data, reg_ipc); + else + sim_debug(dctrl, &cpu_dev, DBG_PCFORMAT2 "Byte[%d] read %02x from $%04x\n", + DBG_PC, boffset & 1, *data, ea); + return SCPE_OK; +} + +t_stat ReadBEx(t_addr base, t_addr boffset, uint16 *data) +{ + t_stat rc; + t_addr ea = base + boffset/2; + if ((rc=ReadEx(ea, 0, data)) != SCPE_OK) return rc; + if (boffset & 1) + *data >>= 8; + *data &= 0xff; + return SCPE_OK; +} + +t_stat WriteB(t_addr base, t_addr boffset, uint16 data, uint32 dctrl) +{ + uint16 wdata; + t_addr ea = base + boffset/2; + if (ea < 0xfc00) { + sim_debug(dctrl, &cpu_dev, DBG_PCFORMAT2 "Byte[%d] write %02x to $%04x\n", + DBG_PC, boffset & 1, data, ea); + wdata = M[ea]; + } else { + printf(DBG_PCFORMAT0 "Invalid byte[%d] write %02x to I/O addr $%04x\n", DBG_PC, boffset & 1, data, ea); + return STOP_ERRIO; + } + if (boffset & 1) { + wdata = (wdata & 0xff) | (data<<8); + } else { + wdata = (wdata & 0xff00) | (data & 0xff); + } + return Write(ea, 0, wdata, 0); +} + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + int32 mc; + t_addr i; + + if (val < 0 || val > 1) + return SCPE_ARG; + + val = val ? 65536 : 32768; + + for (mc = 0, i = val; i < memorysize; i++) + mc = mc | M[i]; + + if (mc && !get_yn ("Really truncate memory [N]?", FALSE)) + return SCPE_OK; + + memorysize = val; + for (i = memorysize; i < MAXMEMSIZE; i++) + M[i] = 0; + return SCPE_OK; +} + +t_stat rom_read(t_addr ea, uint16 *data) +{ + *data = M[ea]; + return SCPE_OK; +} + +t_stat rom_write(t_addr ea, uint16 data) { + M[ea] = data; + return SCPE_OK; +} + + diff --git a/PDQ-3/pdq3_stddev.c b/PDQ-3/pdq3_stddev.c new file mode 100644 index 00000000..d4f93272 --- /dev/null +++ b/PDQ-3/pdq3_stddev.c @@ -0,0 +1,641 @@ +/* PDQ3_stddev.c: PDQ3 simulator standard devices + + Work derived from Copyright (c) 2004-2012, Robert M. Supnik + Copyright (c) 2013 Holger Veit + + 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 + ROBERT M SUPNIK 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 names of Robert M Supnik and Holger Veit + shall not be used in advertising or otherwise to promote the sale, use or + other dealings in this Software without prior written authorization from + Robert M Supnik and Holger Veit. + + 20130902 hv added telnet multiplexer code + 20131020 hv fixed CON interrupt handling + 20131103 hv connect CON_ATTACH logic with DSR, so that DSR is set if tcp connect +*/ +#include "pdq3_defs.h" +#include + +extern UNIT cpu_unit; +extern int32 sim_switches; +extern UNIT con_unit[]; + +static t_stat con_termsvc(UNIT *uptr); +static t_stat con_pollsvc(UNIT *uptr); +static t_stat con_attach(UNIT*, char*); +static t_stat con_detach(UNIT*); +static t_stat con_reset(DEVICE* dptr); + +static t_stat tim_reset(DEVICE *dptr); +static t_stat tim0_svc(UNIT* uptr); +static t_stat tim1_svc(UNIT* uptr); +static t_stat tim2_svc(UNIT* uptr); + +/* CON USART registers */ +/* This is described as positive logic, and represents the + * content of the corresponding registers. + * However, the USART is connected to inverted DAL lines + * and needs to be written to with the inverted value + * This is done in CPU Read/Write */ +#define CONC1_LOOP 0x80 /* 0=loopmode diagnostic, 1=normal full duplex */ +#define CONC1_BRK 0x40 /* 1=send break */ +#define CONC1_MISC 0x20 /* 1=one stop bit, 0=two */ +#define CONC1_ECHO 0x10 /* 1=echo received data */ +#define CONC1_PE 0x08 /* 1=check parity */ +#define CONC1_RE 0x04 /* 1=enable receiver */ +#define CONC1_RTS 0x02 /* 1=enable transmitter if CTS */ +#define CONC1_DTR 0x01 /* 1=enable CD, DSR,RI interrupts */ +static uint8 con_ctrl1; +#define CONC2_CLENMASK 0xc0 /* number of bits */ +#define CONC2_CLEN8 0x00 +#define CONC2_CLEN7 0x40 +#define CONC2_CLEN6 0x80 +#define CONC2_CLEN5 0xc0 +#define CONC2_MODE 0x20 /* not used set to 0 (async mode) */ +#define CONC2_ODDEVN 0x10 /* 0=even parity */ +#define CONC2_RXCLK 0x08 /* not used, set to 1 */ +#define CONC2_CLKMASK 0x07 /* clock selector */ +#define CONC2_CLK110 0x06 /* must be set to 001 (rate 1 clock) */ +static uint8 con_ctrl2; +#define CONS_DSC 0x80 /* set to 1 after status read, cleared by DSR/DCD/RI */ +#define CONS_DSR 0x40 /* DSR input */ +#define CONS_CD 0x20 /* DCD input */ +#define CONS_FE 0x10 /* 1=framing error */ +#define CONS_PE 0x08 /* 1=parity error */ +#define CONS_OE 0x04 /* 1= overrun error */ +#define CONS_DR 0x02 /* set to 1 if data received, 0 if data read */ +#define CONS_THRE 0x01 /* set to 1 if data xmit buffer empty */ +static uint8 con_status; +static uint8 con_xmit; +static uint8 con_rcv; + +/************************************************************************************************ + * Utilities + ***********************************************************************************************/ +t_stat mux_attach(UNIT* uptr, char* cptr, SERMUX* mux) { + t_stat rc; + mux->desc.ldsc = &mux->ldsc; + if ((rc = tmxr_attach(&mux->desc, uptr, cptr)) == SCPE_OK) { + mux->poll->wait = mux->pfirst; + sim_activate(mux->poll, mux->poll->wait); + } + return rc; +} + +t_stat mux_detach(UNIT* uptr, SERMUX* mux) { + t_stat rc = tmxr_detach(&mux->desc, uptr); + mux->ldsc.rcve = 0; + sim_cancel(mux->poll); + sim_cancel(mux->term); + return rc; +} + +/************************************************************************************************ + * Onboard Console + ***********************************************************************************************/ + +/* con data structures + con_dev con device descriptor + con_unit con unit descriptor + con_mod con modifier list + con_reg con register list +*/ +IOINFO con_ioinfo1 = { NULL, CON_IOBASE, 4, CON_RCV_VEC, 4, con_read, con_write }; +IOINFO con_ioinfo2 = { &con_ioinfo1, 0, 0, CON_XMT_VEC, 3, con_read, con_write }; +DEVCTXT con_ctxt = { &con_ioinfo2 }; + +UNIT con_unit[] = { + { UDATA (&con_pollsvc, UNIT_ATTABLE, 0), CON_POLLRATE, }, + { UDATA (&con_termsvc, UNIT_IDLE, 0), CON_TERMRATE, } +}; + +REG con_reg[] = { + { HRDATA (CTRL1, con_ctrl1, 8) }, + { HRDATA (CTRL2, con_ctrl2, 8) }, + { HRDATA (STAT, con_status, 8) }, + { HRDATA (XMIT, con_xmit, 8) }, + { HRDATA (RCV, con_rcv, 8) }, + { NULL } + }; +MTAB con_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", NULL, &show_iobase }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", NULL, &show_iovec }, + { MTAB_XTD|MTAB_VDV, 0, "PRIO", "PRIO", NULL, &show_ioprio }, + { 0 } + }; +DEBTAB con_dflags[] = { + { "WRITE", DBG_CON_WRITE }, + { "READ", DBG_CON_READ }, + { "SVC", DBG_CON_SVC }, + { 0, 0 } +}; + +SERMUX con_mux[1] = { + { CON_POLLFIRST, /*pfirst*/ + CON_POLLRATE, /*prate*/ + { 0 }, /*ldsc*/ + { 1,0,0,0 }, /*desc*/ + &con_unit[1], /*term*/ + &con_unit[0] /*poll*/ + } +}; + +DEVICE con_dev = { + "CON", /*name*/ + con_unit, /*units*/ + con_reg, /*registers*/ + con_mod, /*modifiers*/ + 2, /*numunits*/ + 16, /*aradix*/ + 16, /*awidth*/ + 1, /*aincr*/ + 8, /*dradix*/ + 8, /*dwidth*/ + NULL, /*examine*/ + NULL, /*deposit*/ + &con_reset, /*reset*/ + NULL, /*boot*/ + con_attach, /*attach*/ + con_detach, /*detach*/ + &con_ctxt, /*ctxt*/ + DEV_DEBUG|DEV_DISABLE, /*flags*/ + 0, /*dctrl*/ + con_dflags, /*debflags*/ + NULL, /*msize*/ + NULL /*lname*/ +}; + +/* bus reset handler */ +t_stat con_binit() { + SERMUX *mux = &con_mux[0]; + + con_status = CONS_THRE; + if (mux->ldsc.conn) setbit(con_status, CONS_DSR); + + con_ctrl1 = 0; /* no echo, receiver disabled, transmitter disabled */ + con_ctrl2 = 0; /* ASYNC mode, 8bits, Clock 1X */ + con_xmit = 0; + con_rcv = 0; + return SCPE_OK; +} + +/* common handlers */ +static t_stat con_reset(DEVICE* dptr) +{ + int32 wait; + SERMUX * mux = &con_mux[0]; + UNIT *term = mux->term; + UNIT *poll = mux->poll; + DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt; + + wait = poll->wait = CON_POLLWAIT; + sim_rtcn_init (wait, TMR_CONPOLL); /* init poll timer */ + + sim_cancel(term); + + /* register/deregister I/O handlers */ + if (dptr->flags & DEV_DIS) { + del_ioh(ctxt->ioi); + } else { + add_ioh(ctxt->ioi); + poll->buf = 0; + sim_activate (poll, wait); + } + return con_binit(); +} + +t_stat con_attach(UNIT* uptr, char* cptr) { + setbit(con_status, CONS_DSR|CONS_DSC); + return mux_attach(uptr, cptr, &con_mux[0]); +} + +t_stat con_detach(UNIT* uptr) { + clrbit(con_status, CONS_DSR); + setbit(con_status, CONS_DSC); + return mux_detach(uptr, &con_mux[0]); +} + +#define XMITENABLED() (isbitset(con_ctrl1,CONC1_RTS)) +#define XMITENABLE() setbit(con_ctrl1,CONC1_RTS) +#define XMITDISABLE() clrbit(con_ctrl1,CONC1_RTS) +#define XMITEMPTY() (isbitset(con_status, CONS_THRE)) + +#define RCVENABLED() (isbitset(con_ctrl1,CONC1_RE)) +#define RCVFULL() (isbitset(con_status, CONS_DR)) +#define RCVENABLE() setbit(con_ctrl1,CONC1_RE) +#define RCVDISABLE() clrbit(con_ctrl1,CONC1_RE) + +#define DSRACTIVE() (isbitset(con_ctrl1,CONC1_DTR) && isbitset(con_status,CONS_DSR)) + +/* The transmit interrupt is raised continuously, + * as long as the transmit holding reg is empty and the transmitter is enabled. + * It will be deasserted when the tranmit reg is full or tranmitter disabled. + */ +#define XMITINTR() cpu_assertInt(INT_CONT, XMITEMPTY()) + +/* The receive interrupt is raised continuously, + * when the receiver holding register is full and the receiver is enabled. + * it will be deasserted when the receiver reg is read or the receiver disabled. + */ +#define RCVINTR() cpu_assertInt(INT_CONR, RCVFULL()) + +/* The DSR interrupt is raised when DSC is set to 1 (pos logic) + * and DTR is active, cleared if status is read */ +#define DSRINTR() cpu_assertInt(INT_PRNT, DSRACTIVE()) + +/* Terminal output service */ +t_stat con_termsvc (UNIT *uptr) { + SERMUX *mux = &con_mux[0]; + t_bool isnetwork = (mux->poll->flags & UNIT_ATT); + t_stat rc; + int ch = uptr->buf & 0xff; + +// sim_debug(DBG_CON_SVC, &con_dev, "termsvc: isnetwork=%d\n",isnetwork); + /* TODO? sim_tt_outcvt */ + + if (XMITENABLED()) { /* tranmitter enabled */ + /* attached to a telnet port? */ +// printf("*** Emit: %02x ***\n",uptr->buf & 0xff); + if (isnetwork) { + if ((rc=tmxr_putc_ln(&mux->ldsc, ch)) != SCPE_OK) { + sim_activate(uptr, uptr->wait); + return SCPE_OK; + } else + tmxr_poll_tx(&mux->desc); + } else { + if ((rc=sim_putchar_s(ch)) != SCPE_OK) { + sim_activate(uptr, uptr->wait); + return rc==SCPE_STALL ? SCPE_OK : rc; + } + } + setbit(con_status,CONS_THRE); /* set transmitter holding reg empty */ + cpu_assertInt(INT_CONT, TRUE); /* generate an interrupt because of DRQO */ + } + return SCPE_OK; +} + +/* Terminal input service */ +t_stat con_pollsvc(UNIT *uptr) { + int32 c, kbdc; + SERMUX *mux = &con_mux[0]; + t_bool isnetwork = (mux->poll->flags & UNIT_ATT); + + uptr->wait = sim_rtcn_calb(mux->prate, TMR_CONPOLL); /* calibrate timer */ + sim_activate (uptr, uptr->wait); /* restart polling */ + + kbdc = sim_poll_kbd(); /* check keyboard */ + if (kbdc == SCPE_STOP) return kbdc; /* handle CTRL-E */ + + /* network-redirected input? */ + if (isnetwork) { + if (tmxr_poll_conn(&mux->desc) >= 0) /* incoming connection */ + mux->ldsc.rcve = 1; + tmxr_poll_rx(&mux->desc); /* poll for input */ + if (!tmxr_rqln(&mux->ldsc)) return SCPE_OK; + /* input ready */ + c = tmxr_getc_ln(&mux->ldsc); + if ((c & TMXR_VALID) == 0) return SCPE_OK; + } else { + c = kbdc; /* use char polled from keyboard */ + if (c < SCPE_KFLAG) return c; /* ignore data if not valid */ + } + + c = sim_tt_inpcvt(c, TT_GET_MODE(uptr->flags)); + uptr->buf = c & 0xff; + uptr->pos = uptr->pos + 1; + + if (RCVENABLED()) { /* receiver enabled? */ + if (RCVFULL()) /* handle data overrun */ + setbit(con_status,CONS_OE); + + con_rcv = c & 0xff; /* put in receiver register */ + setbit(con_status,CONS_DR); /* notify: data received */ + cpu_assertInt(INT_CONR, TRUE); /* generate interrupt because of DRQI */ + + if (isbitset(con_ctrl1, CONC1_ECHO)) { /* echo? XXX handle in telnet handler? */ + /* XXX use direct send here, not sending via con_termsvc */ + if (isnetwork) + tmxr_putc_ln(&mux->ldsc, c); + else + sim_putchar_s(c); + } + } + return SCPE_OK; +} + +static int set_parity(int c, int odd) +{ + int i, p = 0; + for (i=0; i<8; i++) + if (c & (1<term; + UNIT *poll = mux->poll; + + /* note usart has inverted bus, so all data is inverted */ + data = (~data) & 0xff; + switch (ioaddr & 0x0003) { + case 0: /* CTRL1 */ + con_ctrl1 = data; + if (!RCVENABLED()) { /* disable receiver */ + clrbit(con_status,CONS_FE|CONS_PE|CONS_OE|CONS_DR); + sim_cancel(poll); + } else { + sim_activate(poll, poll->wait); /* start poll service, will raise interrupt if buffer full */ + } + if (!XMITENABLED()) { /* disable transmitter */ + /* will drain current pending xmit service. RTS output is assumed to become inactive + * (it is not necessary to emulate it) */ + } else { + if (XMITEMPTY()) { + } else { + /* some char in THR, start service to emit */ + sim_activate(term, term->wait); + } + } + break; + case 1: + con_ctrl2 = data; + break; + case 2: + // ignore this here - DLE register + break; + case 3: + switch (con_ctrl2 & CONC2_CLENMASK) { + case CONC2_CLEN5: data &= 0x1f; break; + case CONC2_CLEN6: data &= 0x3f; break; + case CONC2_CLEN7: data &= 0x7f; + if (isbitset(con_ctrl1,CONC1_PE)) + data = set_parity(data, con_ctrl2 & CONC2_ODDEVN); + break; + case CONC2_CLEN8: data &= 0xff; break; + } + con_xmit = data; + term->buf = data; + clrbit(con_status,CONS_THRE); + if (XMITENABLED()) + sim_activate(term,term->wait); + } +// RCVINTR(); + XMITINTR(); + DSRINTR(); + + sim_debug(DBG_CON_WRITE, &con_dev, DBG_PCFORMAT0 "Byte write %02x (pos logic) to $%04x\n", DBG_PC, data & 0xff, ioaddr); + return SCPE_OK; +} + +t_stat con_read(t_addr ioaddr, uint16 *data) { + SERMUX *mux = &con_mux[0]; + + switch (ioaddr & 0x0003) { + case 0: /* CTRL1 */ + *data = con_ctrl1; + break; + case 1: + *data = con_ctrl2; + break; + case 2: + if (mux->ldsc.conn) setbit(con_status, CONS_DSR); + else clrbit(con_status, CONS_DSR); + *data = con_status; + clrbit(con_status,CONS_DSC); /* acknowledge change in DSR/DCD */ + break; + case 3: + *data = con_rcv; + clrbit(con_status,CONS_DR); + cpu_assertInt(INT_CONR, FALSE); + } + sim_debug(DBG_CON_READ, &con_dev, DBG_PCFORMAT1 "Byte read %02x (pos logic) from $%04x\n", DBG_PC, *data & 0xff, ioaddr); + + /* note usart has inverted bus, so returned data must be negated */ + *data = ~(*data); + return SCPE_OK; +} + +/************************************************************************************************ + * Onboard 8253 timer + ***********************************************************************************************/ + +struct i8253 { + uint16 cnt; + uint16 preset; + uint16 mode; + t_bool hilo; /* which half of 16 bit cnt is to be set */ +}; +struct i8253 tim[3]; + +IOINFO tim_ioinfo1 = { NULL, TIM_IOBASE, 4, TIM_TICK_VEC, 6, tim_read, tim_write }; +IOINFO tim_ioinfo2 = { &tim_ioinfo1, 0, 0, TIM_INTVL_VEC, 7, tim_read, tim_write }; +DEVCTXT tim_ctxt = { &tim_ioinfo2 }; + +UNIT tim_unit[] = { + { UDATA (&tim0_svc, 0, 0), CON_POLLRATE, }, + { UDATA (&tim1_svc, 0, 0), CON_POLLRATE, }, + { UDATA (&tim2_svc, 0, 0), CON_POLLRATE, } +}; + +REG tim_reg[] = { + { HRDATA (CNT0, tim[0].cnt, 16) }, + { HRDATA (CNT1, tim[1].cnt, 16) }, + { HRDATA (CNT2, tim[2].cnt, 16) }, + { HRDATA (MODE0, tim[0].mode, 8) }, + { HRDATA (MODE1, tim[1].mode, 8) }, + { HRDATA (MODE2, tim[2].mode, 8) }, + { NULL } +}; +MTAB tim_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", NULL, &show_iobase }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", NULL, &show_iovec }, + { MTAB_XTD|MTAB_VDV, 0, "PRIO", "PRIO", NULL, &show_ioprio }, + { 0 } +}; +DEBTAB tim_dflags[] = { + { "WRITE", DBG_TIM_WRITE }, + { "READ", DBG_TIM_READ }, + { "SVC", DBG_TIM_SVC }, + { 0, 0 } +}; + +DEVICE tim_dev = { + "TIM", /*name*/ + tim_unit, /*units*/ + tim_reg, /*registers*/ + tim_mod, /*modifiers*/ + 3, /*numunits*/ + 16, /*aradix*/ + 16, /*awidth*/ + 1, /*aincr*/ + 8, /*dradix*/ + 8, /*dwidth*/ + NULL, /*examine*/ + NULL, /*deposit*/ + &tim_reset, /*reset*/ + NULL, /*boot*/ + NULL, /*attach*/ + NULL, /*detach*/ + &tim_ctxt, /*ctxt*/ + DEV_DEBUG, /*flags*/ + 0, /*dctrl*/ + tim_dflags, /*debflags*/ + NULL, /*msize*/ + NULL /*lname*/ +}; + +t_stat tim_reset(DEVICE *dptr) +{ + DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt; + + if (dptr->flags & DEV_DIS) { + del_ioh(ctxt->ioi); + sim_cancel(&tim_unit[0]); + sim_cancel(&tim_unit[1]); + sim_cancel(&tim_unit[2]); + } else { + add_ioh(ctxt->ioi); + } + return SCPE_OK; +} + +t_stat tim_read(t_addr ioaddr, uint16 *data) +{ + int n = ioaddr & 0x0003; + if (n == 3) + *data = 0xff; + else { + *data = (tim[n].hilo ? tim[n].cnt : (tim[n].cnt >> 8)) & 0xff; + sim_debug(DBG_TIM_READ, &tim_dev, DBG_PCFORMAT1 "Read %s timer%d: %02x\n", + DBG_PC, tim[n].hilo ? "high" : "low", n, *data); + tim[n].hilo = ! tim[n].hilo; + } + return SCPE_OK; +} + +static uint16 sethi(uint16 val, uint16 data) { + val &= 0xff; + val |= (data << 8); + return val; +} +static uint16 setlo(uint16 val, uint16 data) { + val &= 0xff00; + val |= data; + return val; +} +t_stat tim_write(t_addr ioaddr, uint16 data) +{ + int n = ioaddr & 0x0003; + data &= 0xff; + if (n == 3) { + n = (data & 0xc0) >> 6; + sim_debug(DBG_TIM_WRITE, &tim_dev, DBG_PCFORMAT0 "Timer%d: mode=%d\n", + DBG_PC, n, (data >> 1) & 7); + if (n == 3) { + printf("Unimplemented: Mode=0xc0\n"); + return STOP_IMPL; + } + if (data & 0x01) { + printf("Unimplemented: BCD mode: timer=%d\n",n); + return STOP_IMPL; + } + if (!( (data & 0x0e)==0x00 || (data & 0x0e)==0x04)) { + printf("Unimplemented: Mode not 0 or 2: timer=%d\n",n); + return STOP_IMPL; + } + if ((data & 0x30) != 0x30) { + printf("Unimplemented: not 16 bit load: timer=%d\n",n); + return STOP_IMPL; + } + tim[n].mode = data; + } else { + if (tim[n].hilo) { + tim[n].preset = sethi(tim[n].preset, data); + tim[n].cnt = sethi(tim[n].cnt, data); + if (n < 2) { /* timer 2 is triggered by timer 1 */ + int32 time = 1250000 / tim[n].cnt; + sim_cancel(&tim_unit[n]); + sim_activate(&tim_unit[n], time); + } + } else { + tim[n].preset = setlo(tim[n].preset, data); + tim[n].cnt = setlo(tim[n].cnt, data); + } + sim_debug(DBG_TIM_WRITE, &tim_dev, DBG_PCFORMAT0 "Timer%d: %s cnt=%02x\n", + DBG_PC, n, tim[n].hilo ? "high":"low", data); + tim[n].hilo = !tim[n].hilo; + } + return SCPE_OK; +} + +/* baud rate timer 0 is programmed in mode 2 - actually, this is ignored */ +static t_stat tim0_svc(UNIT* uptr) +{ + int32 time = 1250000 / tim[0].preset; + sim_activate(uptr, time); + sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer0: SVC call\n", DBG_PC); + return SCPE_OK; +} + +/* system timer 1 is programmed in mode 2, causes interrupt each time it is 0 */ +static t_stat tim1_svc(UNIT* uptr) +{ + int32 time = 1250000 / tim[0].preset; + sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer1: SVC call\n", DBG_PC); + sim_activate(uptr, time); + cpu_raiseInt(INT_TICK); + reg_ssr |= SSR_TICK; /* notify TICK timer int occurred */ + + /* handle interval timer */ + if (tim[2].cnt > 0) tim[2].cnt--; + if (tim[2].cnt == 0) { + cpu_raiseInt(INT_INTVL); + reg_ssr |= SSR_INTVL; /* notify INTVL timer int occurred */ + if ((tim[2].mode & 0x0e) == 0x04) { + tim[2].cnt = tim[2].preset; /* restart timer */ + } /* otherwise single shot */ + } + return SCPE_OK; +} + +/* interval timer 2 is programmed in mode 0 (single shot) or 2 (rate generator) + * this is triggered by timer1 - svc is ignored here */ +static t_stat tim2_svc(UNIT* uptr) +{ + sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer2: SVC call - should not occur\n", DBG_PC); + return SCPE_OK; +} + diff --git a/PDQ-3/pdq3_sys.c b/PDQ-3/pdq3_sys.c new file mode 100644 index 00000000..4f4c57fe --- /dev/null +++ b/PDQ-3/pdq3_sys.c @@ -0,0 +1,621 @@ +/* pdq3_sys.c: PDQ3 simulator interface + + Work derived from Copyright (c) 2004-2012, Robert M. Supnik + Copyright (c) 2013 Holger Veit + + 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 + ROBERT M SUPNIK 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 names of Robert M Supnik and Holger Veit + shall not be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik and Holger Veit. + + 2013xxxx hv initial version (written up to the leval to test against bootloader) + 20130907 hv added VIEWSEG command + 20130925 hv added CALL and NAME command + 20130927 hv wrong disassembly of LDC instr +*/ +#include "pdq3_defs.h" +#include + +static int disass(t_addr addr); +t_stat parse_sym_m (char *cptr, t_value *val, int32 sw); +void pdq3_vm_init (void); +static t_stat pdq3_cmd_exstack(int32 arg, char *buf); +static t_stat pdq3_cmd_exmscw(int32 arg, char *buf); +static t_stat pdq3_cmd_extib(int32 arg, char *buf); +static t_stat pdq3_cmd_exseg(int32 arg, char *buf); +static t_stat pdq3_cmd_calcea(int32 arg, char *buf); +static t_stat pdq3_cmd_calltree(int32 arg, char *buf); +static t_stat pdq3_cmd_namealias(int32 arg, char *buf); + +extern DEVICE cpu_dev; +extern UNIT cpu_unit; +extern DEVICE tty_dev; +extern DEVICE fdc_dev; +extern DEVICE tim_dev; +extern REG cpu_reg[]; +extern uint16 M[]; +extern uint16 reg_pc; + + +/* SCP data structures and interface routines + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax maximum number of words for examine/deposit + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "PDQ3"; +REG *sim_PC = &cpu_reg[0]; /* note this is the artifical register PCX */ +int32 sim_emax = 6; +DEVICE *sim_devices[] = { + &cpu_dev, + &con_dev, + &fdc_dev, + &tim_dev, + NULL + }; +const char *sim_stop_messages[] = { + "---", + "PC Breakpoint", + "MEM Breakpoint", + "Invalid Opcode", + "Invalid MEM Access", + "Invalid I/O Access", + "Not yet implemented", + "BPT instruction", + "DEBUG PRE exec stop", + "DEBUG POST exec stop", + "HALT on Pascal Exception", +}; + +CTAB pdq3_cmds[] = { + { "VSTACK", &pdq3_cmd_exstack, 0, "Display last N elements of stack. Top is where SP points to" }, + { "VMSCW", &pdq3_cmd_exmscw, 0, "Display current MSCW" }, + { "VTIB", &pdq3_cmd_extib, 0, "Display current TIB" }, + { "VSEG", &pdq3_cmd_exseg, 0, "Display a segment table entry" }, + { "VCALL", &pdq3_cmd_calltree, 0, "Display the call tree" }, + { "NAME", &pdq3_cmd_namealias, 0, "Define a name" }, + { NULL, NULL, 0, NULL } +}; + +void (*sim_vm_init)(void) = &pdq3_vm_init; + +/* Loader proper */ +t_stat sim_load (FILE *fi, char *cptr, char *fnam, int flag) +{ + int rombase; + int c1, c2, i; + if (flag == 1) /* don't dump */ + return SCPE_ARG; + /* this assumes a HDT style ROM, where the first 2 bytes refer to the + * actual word start of the ROM, e.g. with PDQ-3 the HDT ROM has 0xf401 + * as the first word, so it will load at word address 0xf400, and 0xfc68 + * will be preset to 0xf401 + */ + c1 = fgetc(fi); + c2 = fgetc(fi); + rombase = c1 + c2 * 256; + rom_write(rombase & 0xfffe, rombase); + reg_fc68 = rombase; + i = 0; + while (!feof(fi) && i<0x1ff) { + c1 = fgetc(fi); + c2 = fgetc(fi); + rom_write(rombase+i, (uint16)(c1 + c2*256)); + i++; + } + reg_romsize = i; + /* preset the cpu_serial number from ROM, may be overwritten manually for special purposes */ + rom_read(rombase+i-1, ®_cpuserial); + return SCPE_OK; +} + +/* Note: this simh handles ABSOLUTE word addresses and segmented byte addresses. + * A word address addresses a single cell in memory (up to 65536 cells). + * A byte address only occurs in IPC context, it is relative to the content of + * the reg_segb register. + * Convention: + * $xxxx = word address + * xxxx:yyyy = byte address yyyy relative to segment xxxx + * #yyyy = byte address relative to current reg_segb + * The t_addr type must be 32 bit, the upper half contains the segment, the lower + * half contains the offset. If the upper half is NIL, it is a word address + */ +void pdq3_fprint_addr (FILE *st, DEVICE *dptr, t_addr addr) +{ + if (ADDR_ISWORD(addr)) + fprintf(st,"$"); + else if (ADDR_SEG(addr) == reg_segb) + fprintf(st,"#"); + else { + fprint_val (st, ADDR_SEG(addr), dptr->dradix, dptr->dwidth, PV_LEFT); + fprintf(st,":"); + } + fprint_val (st, ADDR_OFF(addr), dptr->dradix, dptr->dwidth, PV_LEFT); + return; +} + +t_addr pdq3_parse_addr (DEVICE *dptr, char *cptr, char **tptr) +{ + t_addr seg, off; + if (cptr[0] == '#') { + off = strtotv(cptr+1, tptr, dptr->aradix); + return MAKE_BADDR(reg_segb,off); + } else if (cptr[0] == '$') { + off = strtotv(cptr+1, tptr, dptr->aradix); + return MAKE_WADDR(off); + } else { + char gbuf[CBUFSIZE]; + get_glyph (cptr, gbuf, 0); + if (!strncmp(gbuf,"SEGB",4)) { + seg = reg_segb; *tptr = cptr+4; + } else + seg = strtotv(cptr, tptr, dptr->aradix); + if (*tptr[0] == ':') { + cptr = *tptr + 1; + off = strtotv(cptr, tptr, dptr->aradix); + return MAKE_BADDR(seg,off); + } else + return MAKE_WADDR(seg); + } +} + +void pdq3_vm_init (void) +{ + sim_vm_fprint_addr = &pdq3_fprint_addr; + sim_vm_parse_addr = &pdq3_parse_addr; + sim_vm_cmd = pdq3_cmds; +return; +} + +static t_stat pdq3_cmd_exstack(int32 arg, char *buf) +{ + t_stat rc; + uint16 data; + int i; + int n = buf[0] ? atol(buf) : 0; + if (n < 0) n = 0; + printf("SP: $%04x LOW: $%04x UPR: $%04x\n", + reg_sp, reg_splow, reg_spupr); + for (i=n; i>=0; i--) { + if ((rc=Read(reg_sp+i, 0, &data, 0)) != SCPE_OK) continue; + if (i==0) printf(" TOS: "); else printf(" %3d: ",i); + printf("%04x ($%04x)\n", data, reg_sp+i); + } + return SCPE_OK; +} + +static t_stat pdq3_cmd_exmscw(int32 arg, char *buf) +{ + char* next; + return dbg_dump_mscw(stdout, buf[0] ? pdq3_parse_addr(&cpu_dev, buf, &next) : reg_mp); +} + +static t_stat pdq3_cmd_extib(int32 arg, char *buf) +{ + char* next; + return dbg_dump_tib(stdout, buf[0] ? pdq3_parse_addr(&cpu_dev, buf, &next) : reg_ctp); +} + +static t_stat pdq3_cmd_exseg(int32 arg, char *buf) +{ + t_stat rc; + uint16 nsegs; + uint16 segnum, segptr; + char* next; + FILE* fd = stdout; /* XXX */ + + if (reg_ssv < 0x2030 || reg_ssv > 0xf000) { + fprintf(fd, "Cannot list segments in bootloader: incomplete tables\n"); + return SCPE_NXM; + } + + if ((rc=Read(reg_ssv, -1, &nsegs, 0)) != SCPE_OK) return rc; + + if (buf[0]) { + segnum = pdq3_parse_addr(&cpu_dev, buf, &next); + fprintf(fd, "Segment $%02x\n", segnum); + if (segnum > nsegs) { + fprintf(fd, "Too high: maxsegs=$%02x\n",nsegs); + return SCPE_ARG; + } + if ((rc=Read(reg_ssv, segnum, &segptr, 0)) != SCPE_OK) return rc; + rc = dbg_dump_seg(fd, segptr); + } else + rc = dbg_dump_segtbl(fd); + return rc; +} + +static t_stat pdq3_cmd_calltree(int32 arg, char *buf) { + return dbg_calltree(stdout); +} + +static t_stat pdq3_cmd_namealias(int32 arg, char *buf) { + char* name, *alias; + + if (buf[0]==0) + return dbg_listalias(stdout); + + name = strtok(buf, " \t"); + alias = strtok(NULL, " \t\n"); + return dbg_enteralias(name,alias); +} + +/************************************************************************************** + * PDQ utility functions + *************************************************************************************/ +OPTABLE optable[] = { +/*00*/ { "SLDC0", OP_NULL }, { "SLDC1", OP_NULL }, +/*02*/ { "SLDC2", OP_NULL }, { "SLDC3", OP_NULL }, +/*04*/ { "SLDC4", OP_NULL }, { "SLDC5", OP_NULL }, +/*06*/ { "SLDC6", OP_NULL }, { "SLDC7", OP_NULL }, +/*08*/ { "SLDC8", OP_NULL }, { "SLDC9", OP_NULL }, +/*0a*/ { "SLDC10", OP_NULL }, { "SLDC11", OP_NULL }, +/*0c*/ { "SLDC12", OP_NULL }, { "SLDC13", OP_NULL }, +/*0e*/ { "SLDC14", OP_NULL }, { "SLDC15", OP_NULL }, +/*10*/ { "SLDC16", OP_NULL }, { "SLDC17", OP_NULL }, +/*12*/ { "SLDC18", OP_NULL }, { "SLDC19", OP_NULL }, +/*14*/ { "SLDC20", OP_NULL }, { "SLDC21", OP_NULL }, +/*16*/ { "SLDC22", OP_NULL }, { "SLDC23", OP_NULL }, +/*18*/ { "SLDC24", OP_NULL }, { "SLDC25", OP_NULL }, +/*1a*/ { "SLDC26", OP_NULL }, { "SLDC27", OP_NULL }, +/*1c*/ { "SLDC28", OP_NULL }, { "SLDC29", OP_NULL }, +/*1e*/ { "SLDC30", OP_NULL }, { "SLDC31", OP_NULL }, +/*20*/ { "SLDL1", OP_NULL }, { "SLDL2", OP_NULL }, +/*22*/ { "SLDL3", OP_NULL }, { "SLDL4", OP_NULL }, +/*24*/ { "SLDL5", OP_NULL }, { "SLDL6", OP_NULL }, +/*26*/ { "SLDL7", OP_NULL }, { "SLDL8", OP_NULL }, +/*28*/ { "SLDL9", OP_NULL }, { "SLDL10", OP_NULL }, +/*2a*/ { "SLDL11", OP_NULL }, { "SLDL12", OP_NULL }, +/*2c*/ { "SLDL13", OP_NULL }, { "SLDL14", OP_NULL }, +/*2e*/ { "SLDL15", OP_NULL }, { "SLDL16", OP_NULL }, +/*30*/ { "SLDO1", OP_NULL }, { "SLDO2", OP_NULL }, +/*32*/ { "SLDO3", OP_NULL }, { "SLDO4", OP_NULL }, +/*34*/ { "SLDO5", OP_NULL }, { "SLDO6", OP_NULL }, +/*36*/ { "SLDO7", OP_NULL }, { "SLDO8", OP_NULL }, +/*38*/ { "SLDO9", OP_NULL }, { "SLDO10", OP_NULL }, +/*3a*/ { "SLDO11", OP_NULL }, { "SLDO12", OP_NULL }, +/*3c*/ { "SLDO13", OP_NULL }, { "SLDO14", OP_NULL }, +/*3e*/ { "SLDO15", OP_NULL }, { "SLDO16", OP_NULL }, +/*40*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*42*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*44*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*46*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*48*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*4a*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*4c*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*4e*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*50*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*52*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*54*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*56*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*58*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*5a*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*5c*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*5e*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*60*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*62*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*64*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*66*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*68*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*6a*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*6c*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*6e*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*70*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*72*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*74*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*76*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*78*/ { "SIND0", OP_NULL }, { "SIND1", OP_NULL }, +/*7a*/ { "SIND2", OP_NULL }, { "SIND3", OP_NULL }, +/*7c*/ { "SIND4", OP_NULL }, { "SIND5", OP_NULL }, +/*7e*/ { "SIND6", OP_NULL }, { "SIND7", OP_NULL }, +/*80*/ { "LDCB", OP_UB }, { "LDCI", OP_W }, +/*82*/ { "LCA", OP_AB }, { "LDC", OP_BUB }, +/*84*/ { "LLA", OP_B }, { "LDO", OP_B }, +/*86*/ { "LAO", OP_B }, { "LDL", OP_B }, +/*88*/ { "LDA", OP_DBB }, { "LOD", OP_DBB }, +/*8a*/ { "UJP", OP_SB }, { "UJPL", OP_SW }, +/*8c*/ { "MPI", OP_NULL }, { "DVI", OP_NULL }, +/*8e*/ { "STM", OP_UB }, { "MODI", OP_NULL }, +/*90*/ { "CPL", OP_UB }, { "CPG", OP_UB }, +/*92*/ { "CPI", OP_DBUB }, { "CXL", OP_UBUB }, +/*94*/ { "CXG", OP_UBUB }, { "CXI", OP_UBDBUB }, +/*96*/ { "RPU", OP_B }, { "CPF", OP_NULL }, +/*98*/ { "LDCN", OP_NULL }, { "LSL", OP_DB }, +/*9a*/ { "LDE", OP_UBB }, { "LAE", OP_UBB }, +/*9c*/ { "NOP", OP_NULL }, { "LPR", OP_NULL }, +/*9e*/ { "BPT", OP_NULL }, { "BNOT", OP_NULL }, +/*a0*/ { "LOR", OP_NULL }, { "LAND", OP_NULL }, +/*a2*/ { "ADI", OP_NULL }, { "SBI", OP_NULL }, +/*a4*/ { "STL", OP_B }, { "SRO", OP_B }, +/*a6*/ { "STR", OP_DBB }, { "LDB", OP_NULL }, +/*a8*/ { "LHO", OP_NULL }, { "LVO", OP_NULL }, +/*aa*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*ac*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*ae*/ { "", OP_ERROR }, { "", OP_ERROR }, +/*b0*/ { "EQUI", OP_NULL }, { "NEQI", OP_NULL }, +/*b2*/ { "LEQI", OP_NULL }, { "GEQI", OP_NULL }, +/*b4*/ { "LEUSW", OP_NULL }, { "GEUSW", OP_NULL }, +/*b6*/ { "EQUPWR", OP_NULL }, { "LEQPWR", OP_NULL }, +/*b8*/ { "GEQPWR", OP_NULL }, { "EQUBYT", OP_B }, +/*ba*/ { "LEQBYT", OP_B }, { "GEQBYT", OP_B }, +/*bc*/ { "SRS", OP_NULL }, { "SWAP", OP_NULL }, +/*be*/ { "TNC", OP_NULL }, { "RND", OP_NULL }, +/*c0*/ { "ADR", OP_NULL }, { "SBR", OP_NULL }, +/*c2*/ { "MPR", OP_NULL }, { "DVR", OP_NULL }, +/*c4*/ { "STO", OP_NULL }, { "MOV", OP_B }, +/*c6*/ { "DUP2", OP_NULL }, { "ADJ", OP_UB }, +/*c8*/ { "STB", OP_NULL }, { "LDP", OP_NULL }, +/*ca*/ { "STP", OP_NULL }, { "CHK", OP_NULL }, +/*cc*/ { "FLT", OP_NULL }, { "EQUREAL",OP_NULL }, +/*ce*/ { "LEQREAL",OP_NULL }, { "GEQREAL",OP_NULL }, +/*d0*/ { "LDM", OP_UB }, { "SPR", OP_NULL }, +/*d2*/ { "EFJ", OP_SB }, { "NFJ", OP_SB }, +/*d4*/ { "FJP", OP_SB }, { "FJPL", OP_SW }, +/*d6*/ { "XJP", OP_B }, { "IXA", OP_B }, +/*d8*/ { "IXP", OP_UBUB }, { "STE", OP_UBB }, +/*da*/ { "INN", OP_NULL }, { "UNI", OP_NULL }, +/*dc*/ { "INT", OP_NULL }, { "DIF", OP_NULL }, +/*de*/ { "SIGNAL", OP_NULL }, { "WAIT", OP_NULL }, +/*e0*/ { "ABI", OP_NULL }, { "NGI", OP_NULL }, +/*e2*/ { "DUP1", OP_NULL }, { "ABR", OP_NULL }, +/*e4*/ { "NGR", OP_NULL }, { "LNOT", OP_NULL }, +/*e6*/ { "IND", OP_B }, { "INC", OP_B }, +}; + +static uint16 UB(t_value arg) +{ + return arg & 0xff; +} +static uint16 DB(t_value arg) +{ + return UB(arg); +} +static int16 W(t_value arg1, t_value arg2) +{ + uint16 wl = arg1 & 0xff; + uint16 wh = arg2 & 0xff; + return wl | ((wh << 8) & 0xff00); +} + +static int16 SW(t_value arg1, t_value arg2) +{ + return W(arg1,arg2); +} +static int16 SB(t_value arg) +{ + int16 w = arg & 0xff; + if (w & 0x80) w |= 0xff00; + return w; +} +static uint16 B(t_value arg1, t_value arg2, int* sz) { + uint16 wh = arg1 & 0xff; + uint16 wl; + if (wh & 0x80) { + wl = arg2 & 0xff; + wl |= ((wh & 0x7f) << 8); + *sz = 2; + return wl; + } else { + *sz = 1; + return wh; + } +} + +t_stat print_hd(FILE *of, t_value val, t_bool hexdec, t_bool isbyte) +{ + uint16 data = isbyte ? (val & 0xff) : (val & 0xffff); + + if (hexdec) + fprintf(of,"%0xh",data); + else + fprintf(of,"%d",data); + return SCPE_OK; +} + +t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + uint16 op, arg1, arg2, arg3; + int16 sarg; + t_stat size = 0; + int optype, sz; + t_bool hexdec = (sw & SWMASK('H')) ? TRUE : FALSE; + addr = ADDR_OFF(addr); + + op = val[0]; + if (op > 0xe7) return SCPE_ARG; + + optype = optable[op].flags; + if (optype > OP_ERROR) { + fprintf(of,"%-8s", optable[op].name); + switch (optype) { + case OP_NULL: + break; + case OP_UB: + size = 1; arg1 = UB(val[1]); + print_hd(of, arg1, hexdec, FALSE); + break; + case OP_W: + size = 2; sarg = W(val[1],val[2]); + print_hd(of, sarg, hexdec, FALSE); + break; + case OP_AB: + arg1 = B(val[1],val[2], &sz); size = sz; + fprintf(of,"#%x", arg1*2); + break; + case OP_B: + arg1 = B(val[1],val[2], &sz); size = sz; + print_hd(of, arg1, hexdec, FALSE); + break; + case OP_DBB: + arg1 = DB(val[1]); + arg2 = B(val[2],val[3], &sz); size = sz+1; + print_hd(of, arg1, hexdec, TRUE); fputc(',',of); + print_hd(of, arg2, hexdec, FALSE); + break; + case OP_UBB: + arg1 = UB(val[1]); + arg2 = B(val[2],val[3], &sz); size = sz+1; + print_hd(of, arg1, hexdec, TRUE); fputc(',',of); + print_hd(of, arg2, hexdec, FALSE); + break; + case OP_BUB: + arg1 = B(val[1],val[2], &sz); size = sz+1; + arg2 = UB(val[sz+1]); + print_hd(of, arg1, hexdec, FALSE); fputc(',',of); + print_hd(of, arg2, hexdec, TRUE); + break; + case OP_SB: + size = 1; sarg = SB(val[1]); + fprintf(of,"#%x", addr+sarg+2); + break; + case OP_SW: + size = 2; sarg = SW(val[1],val[2]); + fprintf(of,"#%x", addr+sarg+3); + break; + case OP_DBUB: + size = 2; arg1 = DB(val[1]); + arg2 = UB(val[2]); + print_hd(of, arg1, hexdec, TRUE); fputc(',',of); + print_hd(of, arg2, hexdec, TRUE); + break; + case OP_UBUB: + size = 2; arg1 = UB(val[1]); + arg2 = UB(val[2]); + print_hd(of, arg1, hexdec, TRUE); fputc(',',of); + print_hd(of, arg2, hexdec, TRUE); + break; + case OP_UBDBUB: + size = 3; arg1 = UB(val[1]); + arg2 = DB(val[2]); + arg3 = UB(val[3]); + print_hd(of, arg1, hexdec, TRUE); fputc(',',of); + print_hd(of, arg2, hexdec, TRUE); fputc(',',of); + print_hd(of, arg3, hexdec, TRUE); + break; + case OP_DB: + size = 1; arg1 = DB(val[1]); + print_hd(of, arg1, hexdec, TRUE); + break; + } + return -size; + } else { + fprintf(of,"%-8s","DB"); print_hd(of, op, hexdec, TRUE); + return SCPE_OK; + } +} + +/* Symbolic decode + Inputs: + *of = output stream + addr = current PC + *val = pointer to data + *uptr = pointer to unit + sw = switches + Outputs: + return = status code +*/ +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ + t_addr off; + T_FLCVT t; + int ch; + + t_bool hexdec = (sw & SWMASK('H')) ? TRUE : FALSE; + if (sw & SWMASK('M') && !ADDR_ISWORD(addr)) { + return fprint_sym_m(of, addr, val, uptr, sw); + } + if (sw & SWMASK('B')) { /* as BYTE */ + if (ADDR_ISWORD(addr)) { + fprint_val(of, (val[0]>>8) & 0xff, cpu_dev.dradix, 8, PV_RZRO); + fprintf(of, ","); + fprint_val(of, val[0] & 0xff, cpu_dev.dradix, 8, PV_RZRO); + } else + fprint_val(of, val[0], cpu_dev.dradix, 8, PV_RZRO); + return SCPE_OK; + } + if (sw & SWMASK('C')) { /* as CHAR */ + if (ADDR_ISWORD(addr)) { + ch = val[0] & 0xff; + fprintf(of, isprint(ch) ? "%c," : "%02x,", ch); + ch = val[0]>>8; + fprintf(of, isprint(ch) ? "%c" : "%02x", ch); + } else { + ch = val[0] & 0xff; + fprintf(of, isprint(ch) ? "%c" : "%02x", ch); + } + return SCPE_OK; + } + if (sw & SWMASK('W')) { /* as WORD */ + if (ADDR_ISWORD(addr)) { + fprint_val(of, val[0], cpu_dev.dradix, 16, PV_RZRO); + off = ADDR_OFF(addr); + if (off > (reg_bp+MSCW_SZ-1)) + fprintf(of," (GLOBAL+%d)", off - reg_bp - MSCW_SZ + 1); + else if (off >= reg_mp && off <= (reg_mp+OFFB_MSSEG)) + fprintf(of," (MP+%d)", off - reg_mp); + else if (off > (reg_mp+MSCW_SZ-1)) + fprintf(of," (LOCAL+%d)", off - reg_mp - MSCW_SZ + 1); + else if (off >= reg_sp && off < reg_spupr) + fprintf(of," (SP+%d)", off - reg_sp); + } else { + fprint_val(of, val[0], cpu_dev.dradix, 8, PV_RZRO); + fprint_val(of, val[1], cpu_dev.dradix, 8, PV_RZRO); + } + return SCPE_OK; + } + if (sw & SWMASK('F')) { /* as FLOAT */ + t.i[0] = val[1]; + t.i[1] = val[0]; + fprintf(of, "%12.6e", t.f); + return -1; + } + if (sw & SWMASK('S')) { /* as semaphore */ + fprintf(of, "SEM(count=%d, waitq=$%04x)", val[0], val[1]); + return -1; + } + if (sw & SWMASK('M')) { /* as MSCW */ + dbg_dump_mscw(of, val[0]); + return SCPE_OK; + } + if (sw & SWMASK('T')) { /* as TIB */ + dbg_dump_tib(of, addr); + return SCPE_OK; + } + return SCPE_ARG; +} + +/* Symbolic input + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + return SCPE_ARG; +} diff --git a/PDQ-3/run.cmd b/PDQ-3/run.cmd new file mode 100644 index 00000000..63886fe4 --- /dev/null +++ b/PDQ-3/run.cmd @@ -0,0 +1,2 @@ +@echo off +pdq3.exe testhdt.sim diff --git a/PDQ-3/testhdt.sim b/PDQ-3/testhdt.sim new file mode 100644 index 00000000..9748c7ac --- /dev/null +++ b/PDQ-3/testhdt.sim @@ -0,0 +1,125 @@ +;set debug debug.log +set debug stdout +;set fdc debug=read +;set fdc debug=write +;set fdc debug=verbose +;set fdc debug=svc +;set fdc debug=imd +;set fdc debug=dma +;set fdc debug=dmavb +;set fdc debug=cmd +;set cpu exc +;set cpu debug=int +;set cpu debug=trace +;set cpu debug=write +;set cpu debug=read +;set cpu debug=fetch +;set cpu debug=stack +;set cpu debug=conc +;set con debug=svc +;set con debug=read +;set con debug=write +;set tim debug=read +;set tim debug=write +;set tim debug=svc + +att con 8000 + +att fdc0 master.imd +set fdc0 wrtlck +set fdc1 disable + +; HDT boot +;break f418:368 +;break f418:36a +;break f418:218 + +; HDT:bootfd +;break f418:e0 + +; HDT CHK instruction: will fail if CPU serial is > 0x7fff +;break 2018:067d +;break 2018:070f + +; entering PASCALSY +;break eb1e:10 + +; problem main loop in syscode1 +;break dc26:1d0a +;break d488:b1b +;break d488:b55 + +; bug in SPR(4), does not save SP in TIB? +;break d488:bb8 +;break d488:bc7 + +; problem with wait? +;break d488:0917 + +; interrupt debugging +;break d078:4f +;break d488:919 +;break d488:ebe +;break dc26:ec3 +;break d1bd:79 +;break b80d:715 +;break dc26:1d35 +;break d488:806 +;break d488:915 +;break dc26:1d36 + +; SHELL handling +;break badf:98 +;break badf:51 +;break bbd2:1ba +;break bbd2:1be +;break bbd2:32a + +; Ser_RawEmit +;break c964:5f2 +;break d488:d80 +;break c964:6be + +; ticker interrrupts +;break d078:4f +;break d1bd:6e + +; Start/Stop Process +;break d488:7f0 +;break d488:92e +;break d488:934 +;break d488:958 +;break d488:0dd9 +;break c964:756 +;break c964:a6 +;break c964:cf4 + +; waiting for DSR sem +;break c964:624 + +; Ser_Read +;break c964:466 +;break c964:4f9 +;break c964:4fa +;break c964:327 +;break c964:59e +;break c964:323 + +;break d078:4c +;break d078:4f +;break d1bd:6a +;break d1bd:6d + +;break d488:ed0 + + + +load hdt/CPU_C5.BIN +dep _ssr 80 +dep _ses 80 + + +do names.sim +boot cpu +set debug stdout + diff --git a/README.md b/README.md index 527bfb8b..97d29df1 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ #### Updated HP2100 simulator from Dave Bryan. +#### Beta Sigma 5, 6 & 7 simulator from Bob Supnik + +#### Beta SAGE-II and PDQ-3 simulators from Holger Veit + ### New Host Platform support - HP-UX and AIX ### New Functionality diff --git a/SAGE/FILES/68k-s133.sim b/SAGE/FILES/68k-s133.sim new file mode 100644 index 00000000..15dcddfb --- /dev/null +++ b/SAGE/FILES/68k-s133.sim @@ -0,0 +1,31 @@ +set cpu debug=int +set cpu debug=exc +set cpu 512k +set cpu nostop +set cpu bios=s133.hex +set debug debug.log +;set debug stdout +break fe1ad6 +break 7bd08 +break 7def2 + +set timer1 debug=read +set timer1 debug=write +;set timer2 debug=read +;set timer2 debug=write +;set pic debug=read +set pic debug=write +set pic debug=irqin +set pic debug=irqout +;set fd debug=verbose +set fd debug=cmd +;set fd debug=seek +set fd debug=irq +set fd debug=state +;set fd debug=status +;set fd debug=rddata +set lp debug=rdc +set lp debug=rdb +set dip debug=wrc +att fd0 cpm68k12.imd +boot cpu diff --git a/SAGE/FILES/68k-sii.sim b/SAGE/FILES/68k-sii.sim new file mode 100644 index 00000000..ebcf8ceb --- /dev/null +++ b/SAGE/FILES/68k-sii.sim @@ -0,0 +1,31 @@ +set cpu debug=int +set cpu debug=exc +set cpu 512k +set cpu nostop +set cpu bios=sii.hex +set debug debug.log +;set debug stdout +break fe1ad6 +break 7bd08 +break 7def2 + +set timer1 debug=read +set timer1 debug=write +;set timer2 debug=read +;set timer2 debug=write +;set pic debug=read +set pic debug=write +set pic debug=irqin +set pic debug=irqout +;set fd debug=verbose +set fd debug=cmd +;set fd debug=seek +set fd debug=irq +set fd debug=state +;set fd debug=status +;set fd debug=rddata +set lp debug=rdc +set lp debug=rdb +set dip debug=wrc +att fd0 cpm68k12.imd +boot cpu diff --git a/SAGE/FILES/68k-v204.sim b/SAGE/FILES/68k-v204.sim new file mode 100644 index 00000000..44573c73 --- /dev/null +++ b/SAGE/FILES/68k-v204.sim @@ -0,0 +1,31 @@ +set cpu debug=int +set cpu debug=exc +set cpu 512k +set cpu nostop +set cpu bios=v2-04.hex +set debug debug.log +;set debug stdout +break fe1ad6 +break 7bd08 +break 7def2 + +set timer1 debug=read +set timer1 debug=write +;set timer2 debug=read +;set timer2 debug=write +;set pic debug=read +set pic debug=write +set pic debug=irqin +set pic debug=irqout +;set fd debug=verbose +set fd debug=cmd +;set fd debug=seek +set fd debug=irq +set fd debug=state +;set fd debug=status +;set fd debug=rddata +set lp debug=rdc +set lp debug=rdb +set dip debug=wrc +att fd0 cpm68k12.imd +boot cpu diff --git a/SAGE/FILES/68k-v22.sim b/SAGE/FILES/68k-v22.sim new file mode 100644 index 00000000..1f424af1 --- /dev/null +++ b/SAGE/FILES/68k-v22.sim @@ -0,0 +1,31 @@ +set cpu debug=int +set cpu debug=exc +set cpu 512k +set cpu nostop +set cpu bios=v2-2.hex +set debug debug.log +;set debug stdout +break fe1ad6 +break 7bd08 +break 7def2 + +set timer1 debug=read +set timer1 debug=write +;set timer2 debug=read +;set timer2 debug=write +;set pic debug=read +set pic debug=write +set pic debug=irqin +set pic debug=irqout +;set fd debug=verbose +set fd debug=cmd +;set fd debug=seek +set fd debug=irq +set fd debug=state +;set fd debug=status +;set fd debug=rddata +set lp debug=rdc +set lp debug=rdb +set dip debug=wrc +att fd0 cpm68k12.imd +boot cpu diff --git a/SAGE/FILES/68k-v23.sim b/SAGE/FILES/68k-v23.sim new file mode 100644 index 00000000..5a7f6872 --- /dev/null +++ b/SAGE/FILES/68k-v23.sim @@ -0,0 +1,31 @@ +set cpu debug=int +set cpu debug=exc +set cpu 512k +set cpu nostop +set cpu bios=v2-3.hex +set debug debug.log +;set debug stdout +break fe1ad6 +break 7bd08 +break 7def2 + +set timer1 debug=read +set timer1 debug=write +;set timer2 debug=read +;set timer2 debug=write +;set pic debug=read +set pic debug=write +set pic debug=irqin +set pic debug=irqout +;set fd debug=verbose +set fd debug=cmd +;set fd debug=seek +set fd debug=irq +set fd debug=state +;set fd debug=status +;set fd debug=rddata +set lp debug=rdc +set lp debug=rdb +set dip debug=wrc +att fd0 cpm68k12.imd +boot cpu diff --git a/SAGE/FILES/68k.sim b/SAGE/FILES/68k.sim new file mode 100644 index 00000000..0c9734cc --- /dev/null +++ b/SAGE/FILES/68k.sim @@ -0,0 +1,45 @@ +;set cpu debug=int +;set cpu debug=exc +;set cpu debug=ctrace +;set cpu debug=btrace +set cpu 512k +set cpu nostop +set debug debug.log +;set debug stdout +;break fe1ad6 +;break 7bd08 +;break 7def2 +;break 8d8 +;break 794 +;break 78076 +;break 75612 +;break 77ef4 +;break 75618 +;break 73518 +;break 7353a + +;set timer1 debug=read +;set timer1 debug=write +;set timer2 debug=read +;set timer2 debug=write +;set pic debug=read +;set pic debug=write +;set pic debug=irqin +;set pic debug=irqout +;set fd debug=verbose +;set fd debug=cmd +;set fd debug=seek +;set fd debug=imd +;set fd debug=irq +;set fd debug=state +;set fd debug=status +;set fd debug=rddata +;set fd debug=wrdata +;set lp debug=rdc +;set lp debug=rdb +;set dip debug=wrc +;set cons debug=read +;set cons debug=write +;set cons debug=irq +att fd0 cpm68k12.imd +boot cpu diff --git a/SAGE/FILES/68kdbg.sim b/SAGE/FILES/68kdbg.sim new file mode 100644 index 00000000..c8c08a39 --- /dev/null +++ b/SAGE/FILES/68kdbg.sim @@ -0,0 +1,71 @@ +set cpu debug=int +set cpu debug=exc +set cpu 512k +set cpu nostop +set debug debug.log +;set debug stdout +break fe1ad6 +;break 7bd08 + + +; raise PICINT7 for fdcread +break 7def2 +; softint7_fdcread +break 7db38 +;fdcint6_callback +break 7d5ba +;fdc_read +break 7d832 +;fdc_cb_reenable_pic7_2 +break 7d82a +;fdc_reset +break 7d7f4 +;fdc_sendcmd +break 7d454 +;fdc_senseint +break 7d48e +;fdc_readstatus +break 7d544 +;fdc_startdrive +break 7d6d6 +;process_schedqueue +break 7c64c +;fdc_readid +break 7d956 +;fdc_recalibrate_routine +break 7da14 +;fdc_Recalibrate_done +break 7da60 +;fdc_autointhandler +break 7d7d0 +;handler_autoint6_default +break 7d7ec +;cancelschedule +break 7c614 +;addschedule +break 7c5b0 +;fdc_getstatus7 +break 7d4dc + + + +set timer1 debug=read +set timer1 debug=write +set timer2 debug=read +set timer2 debug=write +;set pic debug=read +set pic debug=write +set pic debug=irqin +set pic debug=irqout +;set fd debug=verbose +set fd debug=cmd +set fd debug=seek +;set fd debug=irq +;set fd debug=state +;set fd debug=status +;set fd debug=rddata +set lp debug=rdc +set lp debug=rdb +set dip debug=wrc +att fd0 cpm68k12.imd +boot cpu diff --git a/SAGE/FILES/bin2sage.c.txt b/SAGE/FILES/bin2sage.c.txt new file mode 100644 index 00000000..1480f80b --- /dev/null +++ b/SAGE/FILES/bin2sage.c.txt @@ -0,0 +1,95 @@ +#include +#include +#include + +#define CRLF "\r\n" + +#define BASE 0xfe0000 +#define RECLEN 32 + +void putS0(FILE* out, const char* header) +{ + int i, csum, c; + int len = strlen(header); + fprintf(out, "S0%02X0000", 2 + len + 1); + csum = 0; + for (i=0; i>16) & 0xff) + ((BASE>>8) & 0xff) + (BASE & 0xff); + fprintf(out, "S804%06X%02X" CRLF, BASE & 0xffffff, (~csum) &0xff); +} + +void putS2(FILE* out, int addr, unsigned char* data, int n) +{ + int i, csum, c; + + fprintf(out, "S2%02X%06X", 3 + n + 1, addr & 0xffffff); + csum = 3 + n + 1 + ((addr>>16) & 0xff) + ((addr>>8) & 0xff) + (addr & 0xff); + + for (i=0; i +#include +#include + +#define CRLF "\r\n" + +#define BASE 0xfe0000 +#define RECLEN 32 + +int main(int argc, char* argv[]) +{ + FILE *e,*o,*out; + int c,i; + unsigned char eprombuf[65536]; + int size; + + + if (argc != 4) { + fprintf(stderr, + "Combine two 8bit-EPROM files into a single merged one\n" + "and output it in 16bit binary format.\n" + "Usage: %s even.dat odd.dat output.dat\n\n", argv[0]); + exit(1); + } + + e = fopen(argv[1], "rb"); + o = fopen(argv[2], "rb"); + out = fopen(argv[3], "wb"); + + if (!e) { + fprintf(stderr, "Could not open %s\n", argv[1]); + exit(1); + } + if (!o) { + fprintf(stderr, "Could not open %s\n", argv[2]); + exit(1); + } + if (!out) { + fprintf(stderr, "Could not open %s\n", argv[3]); + exit(1); + } + + size = 0; + while (!feof(e)) { + if ((c = fgetc(e)) == EOF) break; + eprombuf[size++] = c; + if ((c = fgetc(o)) == EOF) break; + eprombuf[size++] = c; + } + printf("%s: Size = %d\n", argv[3], size); + fclose(e); + fclose(o); + + for (i=0; i + +struct dir0 { + unsigned short dfirstblk; + unsigned short dflastblk; + unsigned short dfkind; + char length; + char dvid[7]; + unsigned short deovblk; + unsigned short dnumfiles; + unsigned short dloadtime; + unsigned short dlastboot; + unsigned short padding; +}; +struct dirn { + unsigned short dfirstblk; + unsigned short dflastblk; + unsigned short dfkind; + char length; + char dtid[15]; + unsigned short dlastbyte; + unsigned short daccess; +}; + +unsigned short swap(unsigned short x) { + union u { + unsigned short x; + unsigned char c[2]; + } u; + unsigned char s; + u.x = x; + s = u.c[0]; + u.c[0] = u.c[1]; + u.c[1] = s; + return u.x; +} + + +int main(int argc, char* argv[]) +{ + char name[17]; + char cbuf[512]; + char buf[512*4]; + FILE* in,*out; + int i,n,k; + int b,e,l; + struct dir0* dir0; + struct dirn* dirn; + + if (argc != 2) { + fprintf(stderr,"Usage: %s diskimage.bin\n",argv[0]); + exit (1); + } + + if ((in=fopen(argv[1],"rb"))==NULL) { + fprintf(stderr,"Can't read %s\n",argv[1]); + exit(2); + } + + /* read boot block (two sectors) */ + printf("Extract boot record\n"); + fread(buf,2,512,in); + out = fopen("bootrec.bin","wb"); + fwrite(buf,2,512,out); + fclose(out); + + /* read directory records */ + fread(buf,4,512,in); + dir0 = (struct dir0*)buf; + dirn = (struct dirn*)(buf+26); + printf("Directory:\n"); + printf(" firstblock=%d\n",swap(dir0->dfirstblk)); + printf(" lastblock=%d\n",swap(dir0->dflastblk)); + printf(" volumeid="); + for (i=0; ilength; i++) printf("%c",dir0->dvid[i]); + putchar('\n'); + printf(" lastblock=%d\n",swap(dir0->deovblk)); + printf(" numfiles=%d\n",swap(dir0->dnumfiles)); + + for (n=0; ndnumfiles); n++) { + if (dirn[n].dfkind) { + printf("\nFile="); + for (i=0; i +#include +#include + +typedef unsigned char u_char; +typedef unsigned short u_short; + +typedef struct direntry { + unsigned char une[12]; +#define d_user une[0] +#define d_name une[1] +#define d_ext une[9] + u_short d_fext; + u_char d_fill; + u_char d_last; + u_short d_blks[8]; +} DIR; + +#define UNUSED 0xE5 + +#define DIROFFSET 0x2000 +#define DIRBLKS 16 +#define BLKSTART (DIROFFSET+DIRBLKS*128) +#define CLSTSIZE 2048 + +typedef struct fileentry { + char f_name[30]; + u_short f_fext; + u_char f_last; + u_short f_blks[200]; +} FENTRY; + +void makename(char* name, DIR* dir) +{ + int i; + char *p = name; + for (i=0; i<8; i++) { + if ((&dir->d_name)[i]==' ') break; + *p++ = (&dir->d_name)[i]; + } + *p++ = '.'; + for (i=0; i<3; i++) { + if ((&dir->d_ext)[i]==' ') break; + *p++ = (&dir->d_ext)[i]; + } + *p = 0; +} + +FENTRY* lookup(char* name, FENTRY* files) +{ + FENTRY* nul=0, *p = files; + int i; + + for (i = 0; i<64; i++) { + if (p->f_name[0]==0) { + if (nul==0) nul = p; + } else { + if (!strcmp(p->f_name,name)) { + return p; + } + } + p++; + } + if (nul==0) { + printf("File table full!\n"); + exit(1); + } + return nul; +} + +int main(int argc,char* argv[]) +{ + FILE *in,*out; + unsigned char cpmbuf[2048]; + int i,k,n,s,ls; + char name[30]; + FENTRY files[64], *fe; + DIR* dir; + + if (argc != 2) { + fprintf(stderr,"Usage: %s cpmdisk.bin\n",argv[0]); + exit(1); + } + + for (i=0; i<64; i++) { + files[i].f_name[0] = 0; + files[i].f_fext = 0; + files[i].f_last = 0; + memset(files[i].f_blks,0,sizeof(u_short)*200); + } + + in = fopen(argv[1],"rb"); + if (!in) { + perror("open file"); + exit(1); + } + fseek(in,DIROFFSET,0); + for (i=0; id_user == UNUSED) continue; + makename(name,dir); + fe = lookup(name,files); + strcpy(fe->f_name,name); + if (dir->d_fext >= fe->f_fext) { + fe->f_fext = dir->d_fext; + fe->f_last = dir->d_last; + } + for (n=0; n<8; n++) { + fe->f_blks[dir->d_fext*8+n] = dir->d_blks[n]; + } + } + } + + for (i=0; i<64; i++) { + if (!files[i].f_name[0]) continue; + printf("File %s: (last=%d)\n",files[i].f_name,files[i].f_last%16); + FILE* out = fopen(files[i].f_name,"wb"); + + + + for (k=0; k<199; k++) { + n = files[i].f_blks[k]; + if (n==0) break; + fseek(in,BLKSTART+CLSTSIZE*(n-1),0); + fread(cpmbuf,1,2048,in); + ls = files[i].f_last % 16; + if (!ls) ls = 16; + s = files[i].f_blks[k+1]==0 ? ls*128 : CLSTSIZE; + fwrite(cpmbuf,1,s,out); + printf("%d ",files[i].f_blks[k]); + } + printf("\n"); + fclose(out); + } + exit(0); +} diff --git a/SAGE/FILES/s133.hex b/SAGE/FILES/s133.hex new file mode 100644 index 00000000..a1879c9b --- /dev/null +++ b/SAGE/FILES/s133.hex @@ -0,0 +1,258 @@ +S00B0000733133332E68657882 +S224FE00000000040000FE0034600003AE600003A2600007B060000334600002DE600002B68B +S224FE0020600002E4600002EA600016E4600016E6600002204E70203CFFFFFFFFB0BCFFFF73 +S224FE0040FFFF664E220046812E402A412C4F4E65284E4E6B244C224B204A2E092C082A07E9 +S224FE0060280626052404C741D2826A266524672252816B1E641C661A691892BC8000000053 +S224FE00806810B2BC800000006608E38065B6660201C16676018157C9FFFA0141676C223CF7 +S224FE00A000001234C2FCFEDC82FC1234B2BC0000FEDC6656428008C0000008C0000108C07C +S224FE00C0000208C0000308C0000408C0000508C0000608C000070880000808800009088071 +S224FE00E0000A0880000B0880000C0880000D0880000E0880000FB0BC000000FF660C7207B4 +S224FE0100034057C9FFFC4A8067044E7227004FF8040011FC0092C02711FC0038C02511FC5A +S224FE01200092C06711FC0031C06543FA00066000012611FC0001C06749FA19574BFA0006A3 +S224FE014060001858307C000072014841323CFFFE224145FA000660001798663047FA002407 +S224FE016021CB000872024841D3C1303CA5A53280B051660E46403280B05166064640D3C15B +S224FE018060EC93C145FA000660001766303C00BF41F80100429851C8FFFC548921C901007F +S224FE01A04E6121C9014A21C901426100032A11FC0000C0676100011E41FA18B96100013A41 +S224FE01C032380100E2415341C2FC000541FB100C61000126610000FE60143132384B00326C +S224FE01E035364B003338344B003531324B007228740208380006C0216702725011C201C67D +S224FE020011C101C7423801CA11C201CE11C101CF11FC000101D27206610000861038C0214F +S224FE0220C07C00306706B07C0020671E21F80100014A21F80100014231FC2700014E41FA71 +S224FE0240001221C801466000057A42676100160860DA4E4F60FC41F8C0734200108011FCD4 +S224FE02600076C007E01810801238C021E0181080706E080100036702707E10BC0040024173 +S224FE0280000711FB1014C003108011FC0000C003E01810BC00254ED10280402010080402F9 +S224FE02A041F8C0334240108011FC00B6C007E018108011FB10E4C005E018108011C0C00508 +S224FE02C0E01810BC0040E01810BC004EE01810BC00274E752F00700D6170700A616C420051 +S224FE02E061686166616461626160201F4E752F0070206156201F4E753F0010186704614A2B +S224FE030060F8301F4E75E9186126E91861224E753F017203E958611851C9FFFA321F4E750B +S224FE03203F017207E998610851C9FFFA321F4E753F000200000FB03C000963040600000737 +S224FE0340060000306104301F4E754A380104662C3F01323CFFFF08380002C07356C9FFF89D +S224FE0360670811C0C071321F4E7548E7C0C043FA00066000FEE24CDF030360D64E4A4E7501 +S224FE03804A38010466262F011238C0730801000167F61038C071020100386604221F4E7511 +S224FE03A011FC0035C073700761A060DC4E494E7508380001C0734E7561C6088000070C00BE +S224FE03C000616D0A0C00007A6E04088000054E756116611461126110610E610C610A61087A +S224FE03E06106610461024E7148F87FFF01064E6821C8014A2A1F41FAFFD89A887016BA8020 +S224FE04006256BA3C00046206381F261F341F31DF014E21DF014621CF01424FF804000C059B +S224FE0420001467000B486E000AC00C050012660611FC0001C06746FC270011FC0038C0255C +S224FE044008B8000601504238010470FF51C8FFFE43FA000A6000FE00428560C249FA159206 +S224FE04604BFA00066000153449FA1694D8F450004BFA000460EE49FA169A4BFA000460E465 +S224FE04802038014630780152610009FE6100FE460C050012660611FC0000C0670C050004DA +S224FE04A06200032041FA16F26100FE4E30046100FE6041FA16EF6100FE4020036100FE620E +S224FE04C041FA16EC6100FE3230026100FE446100FE04600002EE41F8000843FA14EC45FA06 +S224FE04E0FB204280301967186B06D08A20C060F2424112003019D08A20C051C9FFFC60E2E8 +S224FE05004E75225F02800000000FD080D089C1893251D3C04ED148E780B02478000847FA97 +S224FE0520001421CB0008101121CA00084CDF0D01B0004E75508F321F46C141FA14C2610047 +S224FE0540FDB8588F2009307801526100093C21CA00084CDF0D01000000014E750838000101 +S224FE0560C0734E752F00703A6100FDE0201F6100FD7E4E752F00702C6100FDD0201F4E7592 +S224FE05802F0070076100FDC4201F4E75C03C007F0C0000206D060C00007E6D02702E4E751A +S224FE05A02F092F01224842816100FE0E0C00001B6700006E0C000012670000680C00000D34 +S224FE05C0674A0C000008661AB3C867DC6100FD7C6100FD1C6100FD7451C9FFF25389528234 +S224FE05E060C40C00007F6614B3C867BC61585389528210116100FD54544160AC611A428116 +S224FE060053826B0812C06100FD42609C610A421912C0221F225F4E758281673C4281602C0F +S224FE0620224842812F0870236100FD206100FCA6B3C86700000C10186100FD10B3C866F6E4 +S224FE0640205F6000FF648281660E72013F00103C005C6100FCF6301F4E75428010188000B5 +S224FE0660660253884E7561F28000670A0C00002067040C00002C4E7561E067080C000020BF +S224FE068067F653884E7561D2244942411219B011568957C9FFFA6600011C1021E158102137 +S224FE06A0D4C04ED2428161BE6736040000306D2A0C0000096F0C040000076D060C00000F10 +S224FE06C06E18E999484010010200000F660C48408200848267D0B48164CC428053804E75EF +S224FE06E0C1414E752F036190428395CA6100FF78670000480C00002367360C0000246708F9 +S224FE0700347801525388602A6100FF5C6700002C0400003065240C000004641E244093C914 +S224FE07206100FF44670000180C00002B660C6002528342826100FF6E670257832240D5CADD +S224FE0740D5CAD4FC0154D3D2201FC14380804E752F0242826100FF22670000520C000027C4 +S224FE0760671C0C00002E674624016100FF386B06241F92814E75241F428153814E756100C7 +S224FE0780FEDA6100FED6670000200C0000276712E19A4A0266E0D480828167E6B28264E2EB +S224FE07A060D46100FEC266CEC14260C47001241F22004E756100FB38703F6100FB8E61005F +S224FE07C0FDC04FF8040042B801546100FB080838000601506700000870546100FB6E363859 +S224FE07E00152670C70246100FB6210036100FB42703E6100FB56742841F801886100FDA26F +S224FE080043FA09FE6100FE8060B843FA0A1C6000FE766100FE642838017E3878018210106E +S224FE0820670E6100FEC0668C2809284A31CA01826100FE46327C01001010670A6100FEA624 +S224FE08406B00FF726704D3C45389528921C9017E2A09611C6718280B6100FD0267F4610019 +S224FE0860FB580C00001367F60C00000366E44E756100FA6220046100FAA86100FA722004B5 +S224FE088090946100FA9C6100FCDC760F2644C7496100FC84C7496600FF1C101B6100FA68A2 +S224FE08A008030000660000066100FA44BA8B57CBFFDE6100FA3A760F2644101B6100FCCE01 +S224FE08C06100FA88BA8B57CBFFF24E7543F80154323C20247403601443F80126323C2041B9 +S224FE08E0600843F80106323C204474076100FD6C6718903C00306B00FEBC1800B8026C0056 +S224FE0900FEB461226100F9CE4E754284611852846100F9DC0C04000466046100F9D2612E30 +S224FE0920B8026DEA4E75616842833001E0880C000020670000066100FA1210016100FA0C3B +S224FE09408683660610046100F9E86100FC182004E5804A836A0A303100006100F9B46008B3 +S224FE0960203100006100F9BA4E756100FCEE6600FE446100FF646100FF6A61186108613256 +S224FE09806104611E4E756100F9666100F9624E756000F94261FA43F80146323C5043601C79 +S224FE09A061EE76FF43F8014E223C00005352600E61DE43F8014A223C00005553760142846D +S224FE09C06100FF684E757C00600001566000FDF443FA08726000FCB06100FD0A6600FDD6A1 +S224FE09E060046100FB9C2809284A2A0454856100FE806100FB7041F80188243C00000028F9 +S224FE0A006100FB9E428110106716223C0000FFFF6100FD3E6BCC6E0A13400001E08012808C +S224FE0A2054890C01002E66BE4E7543F80154323C202474047A01601643F80126323C2041D8 +S224FE0A40600843F80106323C2044740842856100FC0A671A903C00306B00FD5AB0056B000E +S224FE0A60FD54B0026C00FD4E4282610E4E75200561085280B0026DF84E7542832F023A0158 +S224FE0A8028002C00E5864A82660E6100FBEC4A10662260046100FAEA32056100F838610058 +S224FE0AA0FE8A6100FAC0742841F801886100FAF21010671C42816100FC986BD866000012CF +S224FE0AC086836A0833806000600000062380600032051004241F4E756100FB806600FCD6B7 +S224FE0AE06100FF566100FF5C6106611E610E4E7543F80146323C50436000001843F8014EE4 +S224FE0B00323C535276FF6000000C43F8014A323C55537601428242806100FF624E757CFF45 +S224FE0B207A0242806100FB3467144486903C00306B00FC82B03C00026E00FC7A3A00360078 +S224FE0B4060046100FA3C3643D7CB284BD7CB4A866B0A675A6100FB224A106614616A6100E3 +S224FE0B60FA04742841F801886100FA366100FB0A101067320C00002E660607B8015060262A +S224FE0B806100FB626BBC6100FAF0243C0000FFFF6100FB126BAC426C01723940017807F82D +S224FE0BA00150274901605243B6456F9A4E75611860F4427265616B706F696E742000496E01 +S224FE0BC061637469766500006100F70A41FAFFE46100F72610036100F7586100F9880738B4 +S224FE0BE00150660A41FAFFD86100F70E4E75202B01606100F72C6100F6F670286100F74C3D +S224FE0C00302C01786100F70A6100F96A302C01726100F6FE70296100F7324E7543FA064247 +S224FE0C206000FA64243C000000FF613A6600FB861A00E1401005600C243C0000FFFF612671 +S224FE0C406600FB723A00484030056008428261166600FB626100F8C06600FB5AE19812C042 +S224FE0C60538466F04E752F026100FA7A661828096100FA72C9896B0E6E0498895284221F8A +S224FE0C806100FACE4E75225F4E7543FA05DE6000F9F643FA05E06000F9EE6100FA48660040 +S224FE0CA0FB1420096100F67A6100F8BA10116100F6564E756100FA2E6600FAFA3C0908064E +S224FE0CC000006600FAF020096100F6566100F89630116100F63C4E7543FA05A16000F9A881 +S224FE0CE06100FA026600FACE223C000000FF6100FA606600FAC012804E756100F9E8660031 +S224FE0D00FAB43C09080600006600FAAA223C0000FFFF6100FA3C6600FA9C32804E75610000 +S224FE0D20F95874076100F97E6B00FA8A22006000F57008B80005015043FA05486000F948F5 +S224FE0D40740261000120426A017251CAFFF661226600FA6208F80006015008F80007015075 +S224FE0D601038015002000007660608B800060150604C6100F9041010670A6100F968660C7C +S224FE0D8021C9014608F800060150B0004E756100F54443FA04F56000F8EE083800060150A8 +S224FE0DA0661C4E7508F800050150600608B80005015061BE6600F9FE08B8000701502C3821 +S224FE0DC00146284608060000671641FA00706100F528307801522006610000AE6000F9E43A +S224FE0DE0224C6100F7326600F9CC3C38014E08380006015066207400616A6B00F9B8670C1F +S224FE0E003551016C32BC4E4F0886000F52420C42000366E4600408C6000F3014B07C4E4F37 +S224FE0E2066040886000F2078014A4E602E7801422F0C3F064CF87FFF01064E73496C6C659E +S224FE0E4067616C2070726F6772616D20737461727420616464726573733A200008B80006CF +S224FE0E6001504E7542803242D3C92449D3C905380150670E226901606100F69C6600000632 +S224FE0E8052804E7553804E756100F4966100F4602F0070286100F4B470246100F4AE3008E5 +S224FE0EA06100F48E6100F6BED1C8D1C8201F90A801546100F46C70296100F4904E750D0A20 +S224FE0EC0556E657870656374656420747261636520636F6E646974696F6E2061743A200095 +S224FE0EE054726163653A2000083800060150660641FAFFCC6016083800070150670A08B85E +S224FE0F00000601506000FEB841FAFFD6203801466100F3E62840307801526100FF6C6100E8 +S224FE0F20F644224C6100F5F0660630116100F3E2083800050150670A41F801884210610061 +S224FE0F40FA2A6000F87E0D0A556E657870656374656420627265616B20706F696E743A209F +S224FE0F6000000D0A427265616B3A200042854286283801465584760008380007015066068F +S224FE0F8041FAFFC4602C74026100FEDA6F1CB3C4661476023A2A01723C2A0178BC456706FD +S224FE0FA052453545017232AA016C51CAFFDC41FAFFB220380146908321C00146BC4566003E +S224FE0FC0FD946000FF4C43FA02D26000F6BA11FC000101BB49F8C031606E423801BB49F870 +S224FE0FE0C071428574016100F6BC6B00F7C83C00243C0000FFFF6100F6AC6B00F7B83F004E +S224FE10006100F6E26600F7AE2F0942826100F6966B00F7A22F003F064A856706610006F68F +S224FE10206004610006EA6700000E41FA000C6100F2C86100F2D24E750D0A4469736B206512 +S224FE104072726F723A20000061720C000051670000AC0C00005366F0420561601E006100EF +S224FE106000A81C01550642816100009E6100009A26410C070030660E4A0667066100008ACA +S224FE108060F6616060C20C0700326612220B6100007826414A0667EA616E16C160F60C073A +S224FE10A0003167F00C07003966524A06664E613441FA095D6100F2426000F708082C00013E +S224FE10C0000267081014088000074E754A3801BB67EA6100F2DC67E46100F2DE0C0000518F +S224FE10E066DA4E756122460566024E75588F41FA093D6100F2046000F6CA508F41FA091BD4 +S224FE11006100F1F66000F6BC61086106DA0153064E7561A80C0000306DE00C0000396E0A5C +S224FE112004000030E989D2004E750C0000416DCA0C0000466EC45F0060E643FA01576000CF +S224FE1140F5467A016000FE9E6000F67843FA01566000F53453797374656D207265696E6933 +S224FE11607469616C697A696E672E2E2E2E0041FAFFE46100F1846000EEBC42801010670A98 +S224FE118074016100F5206B00F62C3F00610006C84E754E7542801010670A74036100F506BA +S224FE11A06B00F61231C001524E756100F5386600F60428096100F52E6B00F5FAC9896604F9 +S224FE11C09889600253846500F5EC26496100F5166600F5E27201B7C96406D3C4D7C472FF54 +S224FE11E06100F3346B00F5CEC34B6100F32AC34B6B00F5C21293D3C1D7C151CCFFE44E75E6 +S224FE12000C440AF653D0F7461CFA2494FF4DAAFF508AFA548EFB4732FB573AFF4CC6FD0094 +S224FE12209AFB494CFF41CCF7084DEAF55242F744BAF641B0F6506CF75378F75588F724A4D3 +S224FE1240F6429EF7084D94F75294F844FEF741F4F750ACF853B8F855C6F824E6F742DAF87C +S224FE12600242C4F957D8F94CECF9024928FA4F6EFA53B4FA014226FA5740FA014265FA57FF +S224FE12807FFA014FBEFA43CCFA024223FB45D3FB521BFB0141B5FE46AFFE024134FD5440F4 +S224FE12A0FD4648FD0346D6FE48EEFE47EEFE53CAFE00441BF7005453540043484700434C52 +S224FE12C05200534554004F524900414E4449535542494144444942000000454F5249434D81 +S224FE12E050492E4200002E5700002E3F00002E4C00004E454758434C52004E4547004E4FEC +S224FE13005400000000005453540054524150545241504C494E4B554E4C4B524553454E4FD9 +S224FE1320500053544F5052544500344537345254530054524150525452004A5352004A4D97 +S224FE1340500043484B004C45410044495655444956534D554C554D554C5354004600484975 +S224FE13604C53434343534E45455156435653504C4D4947454C5447544C454F520000535571 +S224FE13804200454F5200434D5000414E440041444400534243445355425800000000434DB8 +S224FE13A050414142434441444458415352004C535200524F5852524F520041534C004C53DA +S224FE13C04C00524F584C524F4C0048E760401219143C00AD1038C0510800000756CAFFF618 +S224FE13E0671A08000006661411D9C053740951CAFFFE530166DA4CDF02064E7511FC0001B7 +S224FE140001C560F248E7604043FA07B461BC6624720243F801C36174661A123801C302016A +S224FE142000C0670C08010006670472036002720211C101C54CDF02064E7548E760407207DB +S224FE144043F801BC42116144663C123801BC020100C0672E0801000667267205103801BD7F +S224FE1460E208651E7206E40865187207E40865127208E208650C7209E4086506720A6002BA +S224FE1480720211C101C54CDF02064E75343C10FE1038C0510800000756CAFFF667160800C7 +S224FE14A00006671012F8C053740951CAFFFE530166DA4E7511FC000101C54E752F0170026A +S224FE14C0484008380000C0636612538066F411FC0002C02711FC000401C5600C4A0266206E +S224FE14E012F8C053534166D611FC0001C02711FC0000C0276100FF44221F4A3801C54E7523 +S224FE150011D9C053534166B660DE48E76040720143FA06A96100FEB46638740248420838BE +S224FE15200000C063660C538266F411FC000401C56020422C00036100FECC67160C3800032D +S224FE154001C5660E0C2C00500001660651C9FFC270034CDF02064E7548E76040720210388A +S224FE156001D6B02C0003674C43F801B032BC030F42290002137801D600036100FE4E6634FA +S224FE15807402484208380000C063660C538266F411FC000401C5601C6100FE6A660A197827 +S224FE15A001D600034200600C6100FF60660651C9FFAE70034CDF02064E7500000000000044 +S224FE15C00000423801C54A2C0000670000D23F077E0111FC000FC02711FC0000C02711FC50 +S224FE15E00003C02743FA05D111FC000EC0276100FDDA663270064A2C00046702540011C09B +S224FE1600C02770FF51C8FFFE08380000C06367086100FDF2423801C56100FEF067120C38ED +S224FE1620000301C5670451CFFFAA3E1F70014E7570024840538066FC43FA05866100FD8C38 +S224FE164066E4343CFFFE1038C0510800000756CAFFF6660E11FC0002C02711FC000401C512 +S224FE166060C86100FDD666BE4240103801C267260C0000026E2067067210742060047208D0 +S224FE1680740EE1483940000619410002194200053E1F42004E7511FC000901C5608C11FC2A +S224FE16A0000B01C54E754A2C0000675A4281323C020082EC00064282343801DEC4C142815E +S224FE16C0122C000284C14241082C000000006604E24AE31111C101D711C201D6B42C00010C +S224FE16E06C244842122C00029202C2EC0006B2B801E06F04223801E0520211C201D831C15A +S224FE170001DC42004E7511FC000B01C54E75423801DA600611FC000101DA225F49F801C616 +S224FE1720301F670449F801CE21DF01E021DF01E431DF01DE2F097E034A6C0006660000FE4E +S224FE17406100FE80660000E24AB801E0670000DA11FC0003C0274A3801DA672C0838000113 +S224FE1760C063670A11FC000C01C5600000BC102C0001E208B03801D66F0811FC000DC02779 +S224FE1780600611FC000CC0276100FF1C6600009A6100FDC6667443F801B0303C09454A383E +S224FE17A001DA6602524032C0103801D7E50812C012F801D612F801D712F801D8302C000678 +S224FE17C0E04812C012EC000212EC000512FC00FF43F801B06100FBF46630227801E44281E8 +S224FE17E0323801DC143801DA6100FCD2661C303C032051C8FFFED3B801E493B801E082FC08 +S224FE18000200D37801DE6000FF405307671A103801C50C0000016700FF280C0000036708F8 +S224FE18200C0000046600FF2270074A2C00046702540011C0C027103801C54E7570064A2CEB +S224FE184000046702540011C0C02770024840538066FC6000FEF46100EC7E6100EA7841FAC2 +S224FE1860024A6100EA946100EA6C4267307C04002F082F083F2F000E6100FE946612307C29 +S224FE188004000C58424F663C0C584F5466364ED06100EA42103801C50C000004673041FA6C +S224FE18A0019B6100EA546100EA5E41FA01AC6100EA48102C00046100EA786100EA18205FE1 +S224FE18C0548F4ED041FA01836100EA2E60DC41FA01EE6100EA246100EAE06100E9F80C007E +S224FE18E000516600FF7241FA01F76100EA0C60BA264842804281468126804A93661C2681B3 +S224FE1900B293661C26CBB7C963EE2648B7D3660E588BB7C963F642804ED222006002220B80 +S224FE1920201349FA013F4BFA00066000006E2A0B4BFA00066000007049FA01454BFA0006B1 +S224FE1940600000582A004BFA00066000005A49FA01344BFA0006600000422A014BFA0006C2 +S224FE19606000004449FA01874BFA00066000002C49FA01354BFA00066000002070014ED249 +S224FE19803E3CFFFF08380002C07356CFFFF8670611C6C0714ED64E7227001C1C67064DFACF +S224FE19A0FFFA60DC4ED57807E99D7C0FCC050C060009630406060007060600304DFA00044F +S224FE19C060BE51CCFFE44ED503D003D203D4800203D603D803E403D403D4800B03DA80068B +S224FE19E003DE03E0800E03DC03E2800F03DA000007455843455054494F4E3A20200007200B +S224FE1A004E4F204D656D6F72792061743A20004C6F616420446F6E650007426164204C6F2F +S224FE1A20616420436861726163746572000742616420436865636B73756D00074472697634 +S224FE1A4065204572726F722000074E6F7420424F4F54204469736B00206F6E2064726976CB +S224FE1A6065200007424144204D656D6F7279206174200052414D2053697A65203D2000202A +S224FE1A806973200020696E7374656164206F6620000D0A5341474520494920537461727413 +S224FE1AA0757020546573740D0A00426F6F74696E672066726F6D20466C6F70707900507562 +S224FE1AC07420696E20424F4F54206469736B20616E642070726573732061206B65790007E8 +S224FE1AE0426F6F742041626F72746564002028546573742041626F72746564290000001F5D +S224FE1B000027002B003300470052005C006A007A008F204572726F722061742000556E6B68 +S224FE1B206E6F776E00427573004164647265737300496C6C6567616C20496E73747275632E +S224FE1B4074696F6E0041726974686D657469630050726976696C65676500526573657276A0 +S224FE1B606564205452415000556E61737369676E6564205452415000556E61737369676E92 +S224FE1B80656420496E746572727570740052414D205061726974790046756E6374696F6ECD +S224FE1BA03A200020204163636573733A20002020496E73743A20000303D1070207000108B4 +S224FE1BC0024A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +S224FE1BE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +S224FE1C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +S224FE1C20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +S224FE1C40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +S224FE1C60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +S224FE1C80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +S224FE1CA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +S224FE1CC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +S224FE1CE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +S224FE1D00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +S224FE1D20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +S224FE1D40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +S224FE1D60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +S224FE1D80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +S224FE1DA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +S224FE1DC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +S224FE1DE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +S224FE1E00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +S224FE1E20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +S224FE1E40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +S224FE1E60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +S224FE1E80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +S224FE1EA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +S224FE1EC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +S224FE1EE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +S224FE1F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +S224FE1F20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +S224FE1F40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +S224FE1F60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +S224FE1F80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +S224FE1FA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +S224FE1FC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +S224FE1FE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +S804FE0000FD diff --git a/SAGE/FILES/sage-ii.hex b/SAGE/FILES/sage-ii.hex new file mode 100644 index 00000000..10bba9ab --- /dev/null +++ b/SAGE/FILES/sage-ii.hex @@ -0,0 +1,258 @@ +S00E0000736167652D69692E686578ED +S224FE0000000004000000003C600004286000041C6000085E6000037E6000032860000300FC +S224FE00206000032E60000334600018E6600018E86000026A14D801026000025C4E704FF859 +S224FE0040040011FC0092C02711FC0038C02511FC0092C06711FC0031C065700072FF343C6F +S224FE006042D741F8C0FE3080308151CAFFFA43F8000045F87FFE343C34423011301030125A +S224FE008051CAFFF8343C06C541F8C00172084A10D0FC001051C9FFF851CAFFEE43FA00060A +S224FE00A0600001FE49FA1C514BFA0012200D4840303C00FE48402A4060001B3E49FA1C436B +S224FE00C04BFA000660001B321038C0216B64E60802400006303B00064EFB000200180024FF +S224FE00E0001800084238010449FA1CE94BFA078260001B0649FA1CED4BFA003860001AFA8A +S224FE010049FA1CF04BFA000660001AEE74FF720070001038C023460008000002670272FF30 +S224FE0120E308024000064840204030C151CAFFFC60DA41FAFECC343C0FFF42004201D01870 +S224FE0140D21851CAFFFA4A00671449FA1C6B4BFA000660001AA44A38C0216A0000D84A01B6 +S224FE0160671449FA1C614BFA000660001A8C4A38C0216A0000C011FC0001C067307C000082 +S224FE018072014841323CFFFE224145FA0006600019A8663047FA002421CB00087202484140 +S224FE01A0D3C1303CA5A53280B051660E46403280B05166064640D3C160EC93C145FA000627 +S224FE01C06000197667084A38C0216A000068303C00BF41F80100429851C8FFFC548921C96F +S224FE01E001004E6121C9014A21C901426100039611FC0000C0674A38C0216B1611FC0007C4 +S224FE0200C06770FF51C8FFFE11FC0006C0676000FF226100010A41FA1AC161000126303802 +S224FE02200100ED48610001A4704B61000168610000EE60044E72270072287402083800060A +S224FE0240C0216702725011C201C611C101C7423801CA11C201CE11C101CF11FC000101D2F1 +S224FE02607206610000861038C021C07C00306706B07C0020671E21F80100014A21F80100CA +S224FE0280014231FC2700014E41FA001221C80146600005DE4267610017E660DA4E4F60FC7B +S224FE02A041F8C0734200108011FC0076C007E01810801238C021E0181080706E080100038E +S224FE02C06702707E10BC00400241000711FB1014C003108011FC0000C003E01810BC002532 +S224FE02E04ED1028040201008040241F8C0334240108011FC00B6C007E018108011FB10E48C +S224FE0300C005E018108011C0C005E01810BC0040E01810BC004EE01810BC00274E752F0004 +S224FE0320700D6170700A616C420061686166616461626160201F4E752F0070206156201F53 +S224FE03404E753F0010186704614A60F8301F4E75E9186126E91861224E753F017203E9582B +S224FE0360611851C9FFFA321F4E753F017207E998610851C9FFFA321F4E753F000200000FC0 +S224FE0380B03C0009630406000007060000306104301F4E754A380104662C3F01323CFFFF7F +S224FE03A008380002C07356C9FFF8670811C0C071321F4E7548E7C0C043FA00066000FEE2F8 +S224FE03C04CDF030360D64E4A4E7548E7F000720032007400343C2710420382C266044A033A +S224FE03E067061001619450C34241484184FC000A66E84CDF000F4E754A38010466282F014E +S224FE04001238C0730801000167F61038C071020100386604221F4E7511FC0035C0737007E7 +S224FE04206100FF7260DA4E494E7508380001C0734E7561C4088000070C0000616D0A0C0078 +S224FE0440007A6E04088000054E7521C001067002604E21C001067004604621C001067006F5 +S224FE0460603E21C001067008603621C00106700A602E21C00106700C602621C00106700EA5 +S224FE0480601E21C001067010601621C001067012600E21C001067014600621C001067016E5 +S224FE04A048F87FFE010A4E6821C8014A2A007016BA80625EBA3C00046206381F261F341F8C +S224FE04C031DF014E21DF014621CF01424FF804000C05001467000B686E000AD20C05001289 +S224FE04E0660C11FC0001C06711FC0000C06770FFE01851C8FFFC46FC270011FC0038C02510 +S224FE050008B8000601504238010443FA000A6000FD90428560BA49FA17364BFA00066000F2 +S224FE052016D849FA18E0D8F450004BFA000460EE49FA18E64BFA000460E4203801463078C7 +S224FE0540015261000A146100FDD60C0500046200032041FA194A6100FDEA30046100FDFC84 +S224FE056041FA19476100FDDC20036100FDFE41FA19446100FDCE30026100FDE06100FDA0F2 +S224FE0580600002EE41F8000843FA169C45FAFA724280301967186B06D08A20C060F2424123 +S224FE05A012003019D08A20C051C9FFFC60E24E75225F02800000000FD080D089C189325101 +S224FE05C0D3C04ED148E780B02478000847FA001421CB0008101121CA00084CDF0D01B0001D +S224FE05E04E75508F321F46C141FA16746100FD54588F2009307801526100095E21CA0008C1 +S224FE06004CDF0D01000000014E7508380001C0734E752F00703A6100FD7C201F6100FD1A39 +S224FE06204E752F00702C6100FD6C201F4E752F0070076100FD60201F4E75C03C007F0C0070 +S224FE064000206D060C00007E6D02702E4E752F092F01224842816100FDDA0C00001B67004F +S224FE0660006E0C000012670000680C00000D674A0C000008661AB3C867DC6100FD18610029 +S224FE0680FCB86100FD1051C9FFF25389528260C40C00007F6614B3C867BC6158538952824A +S224FE06A010116100FCF0544160AC611A428153826B0812C06100FCDE609C610A421912C001 +S224FE06C0221F225F4E758281673C4281602C224842812F0870236100FCBC6100FC42B3C873 +S224FE06E06700000C10186100FCACB3C866F6205F6000FF648281660E72013F00103C005C69 +S224FE07006100FC92301F4E75428010188000660253884E7561F28000670A0C00002067048A +S224FE07200C00002C4E7561E067080C00002067F653884E7561D2244942411219B0115689F6 +S224FE074057C9FFFA6600011C1021E1581021D4C04ED2428161BE6736040000306D2A0C0055 +S224FE076000096F0C040000076D060C00000F6E18E999484010010200000F660C484082002B +S224FE0780848267D0B48164CC428053804E75C1414E752F036190428395CA6100FF78670011 +S224FE07A000480C00002367360C0000246708347801525388602A6100FF5C6700002C0400CC +S224FE07C0003065240C000004641E244093C96100FF44670000180C00002B660C6002528308 +S224FE07E042826100FF6E670257832240D5CAD5CAD4FC0154D3D2201FC14380804E752F0280 +S224FE080042826100FF22670000520C000027671C0C00002E674624016100FF386B06241FC8 +S224FE082092814E75241F428153814E756100FEDA6100FED6670000200C0000276712E19A26 +S224FE08404A0266E0D480828167E6B28264E260D46100FEC266CEC14260C47001241F22005F +S224FE08604E756100FAD4703F6100FB2A6100FDC04FF8040042B801546100FAA40838000651 +S224FE088001506700000870546100FB0A36380152670C70246100FAFE10036100FADE703E50 +S224FE08A06100FAF2742841F801886100FDA243FA0AF26100FE8060B843FA0B136000FE762B +S224FE08C06100FE642838017E387801821010670E6100FEC0668C2809284A31CA0182610018 +S224FE08E0FE46327C01001010670A6100FEA66B00FF726704D3C45389528921C9017E2A093B +S224FE0900611C6718280B6100FD0267F46100FB240C00001367F60C00000366E44E75610071 +S224FE0920F9FE20046100FA446100FA0E200490946100FA386100FCDC760F2644C74961001D +S224FE0940FC84C7496600FF1C101B6100FA0408030000660000066100F9E0BA8B57CBFFDE04 +S224FE09606100F9D6760F2644101B6100FCCE6100FA24BA8B57CBFFF24E7543F80154323C67 +S224FE098020247403601443F80126323C2041600843F80106323C204474076100FD6C671AB2 +S224FE09A0903C00306B00FEBC78001800B8026E00FEB261226100F9684E754284611852848E +S224FE09C06100F9760C04000466046100F96C612EB8026DEA4E75616E42833001E0880C0064 +S224FE09E00020670000066100F9AC10016100F9A68683660610046100F9826100FC16200454 +S224FE0A00E5800280000000FF4A836A0A303100006100F9486008203100006100F94E4E7585 +S224FE0A206100FCE66600FE3C6100FF5C6100FF626118610861326104611E4E756100F8FAE3 +S224FE0A406100F8F64E756000F8D661FA43F80146323C5043601C61EE76FF43F8014E223C4D +S224FE0A6000005352600E61DE43F8014A223C00005553760142846100FF624E757C006000F7 +S224FE0A80015C6000FDEC4E7543FA095F6000FCA66100FD006600FDCC60046100FB92280933 +S224FE0AA0284A2A0454856100FE766100FB6641F80188243C000000286100FB944281101006 +S224FE0AC06716223C0000FFFF6100FD346BCC6E0A13400001E080128054890C01002E66BE77 +S224FE0AE04E7543F80154323C202474047A01601643F80126323C2041600843F80106323C3C +S224FE0B002044740842856100FC00671A903C00306B00FD50B0056B00FD4AB0026C00FD44D3 +S224FE0B204282610E4E75200561085280B0026DF84E7542832F023A0128002C00E5864A82C6 +S224FE0B40660E6100FBE24A10662260046100FAE032056100F7CA6100FE826100FAB6742878 +S224FE0B6041F801886100FAE81010672042816100FC8E6BD8660000160286000000FF8683C9 +S224FE0B806A063380600060042380600032051004241F4E756100FB726600FCC86100FF526D +S224FE0BA06100FF586106611E610E4E7543F80146323C50436000001843F8014E323C5352CA +S224FE0BC076FF6000000C43F8014A323C55537601428242806100FF5E4E757CFF7A0242805E +S224FE0BE06100FB2667144486903C00306B00FC74B03C00026E00FC6C3A003600600461005B +S224FE0C00FA2E3643D7CB284BD7CB4A866B0A675A6100FB144A106614616A6100F9F6742878 +S224FE0C2041F801886100FA286100FAFC101067320C00002E660607B8015060266100FB5470 +S224FE0C406BBC6100FAE2243C0000FFFF6100FB046BAC426C01723940017807F80150274985 +S224FE0C6001605243B6456F9A4E75611860F4427265616B706F696E742000496E6163746960 +S224FE0C80766500006100F69841FAFFE46100F6B410036100F6E66100F97A07380150660A3A +S224FE0CA041FAFFD86100F69C4E75202B01606100F6BA6100F68470286100F6DA302C017833 +S224FE0CC06100F6986100F95C302C01726100F68C70296100F6C04E7543FA072B6000FA5628 +S224FE0CE0243C000000FF61426600FB781A00E1401005600C243C0000FFFF612E6600FB64A8 +S224FE0D003A004840300560084282611E6600FB5441FA10646100F62C6100F8AA6600FB449F +S224FE0D20E19812C0538466F04E752F026100FA64661828096100FA5CC9896B0E6E049889C1 +S224FE0D405284221F6100FAB84E75225F4E756100F5E86100F5E443FA06B76000F9D843FA7F +S224FE0D6006B96000F9D06100FA2A6600FAF620096100F5F86100F89C10116100F5D44E7533 +S224FE0D806100FA106600FADC3C09080600006600FAD220096100F5D46100F878301161005E +S224FE0DA0F5BA4E7543FA067A6000F98A6100F9E46600FAB0223C000000FF6100FA42660070 +S224FE0DC0FAA212804E756100F9CA6600FA963C09080600006600FA8C223C0000FFFF610009 +S224FE0DE0FA1E6600FA7E32804E756100F93A74076100F9606B00FA6C22006000F4EE08B8C7 +S224FE0E000005015043FA06216000F92A740261000124426A017251CAFFF661226600FA4440 +S224FE0E2008F80006015008F8000701501038015002000007660608B80006015060506100CA +S224FE0E40F8E61010670A6100F94A660C21C9014608F800060150B0006100F4C44E75610095 +S224FE0E60F4BE43FA05CA6000F8CC083800060150661C4E7508F800050150600608B8000530 +S224FE0E80015061BA6600F9DC08B8000701502C380146284608060000671641FA00706100E0 +S224FE0EA0F4A2307801522006610000AE6000F9C2224C6100F7106600F9AA3C38014E08386C +S224FE0EC00006015066207400616A6B00F99667083551016C32BC4E4F52420C42000366E8D9 +S224FE0EE00886000F600408C6000F3014B07C4E4F66040886000F2078014A4E602E78014283 +S224FE0F002F0C3F064CF87FFF01064E73496C6C6567616C2070726F6772616D207374617218 +S224FE0F207420616464726573733A200008B8000601504E7542803242D3C92449D3C90538E8 +S224FE0F400150670E226901606100F67A6600000652804E7553804E756100F4106100F3DAE1 +S224FE0F602F0070286100F42E70246100F42830086100F4086100F69CD1C8D1C8201F90A8E2 +S224FE0F8001546100F3E670296100F40A4E750D0A556E6578706563746564207472616365A9 +S224FE0FA03A200054726163653A200000083800060150660641FAFFD8601608380007015068 +S224FE0FC0670A08B8000601506000FEC441FAFFD5203801466100F36C284030780152610032 +S224FE0FE0FF786100F62E224C6100F5DA661430116100F3686100F3426100F33E2C496100DF +S224FE1000FA86083800050150670A41F8018842106100FA0E6000F85A0D0A556E657870658B +S224FE10206374656420627265616B20706F696E743A2000000D0A427265616B3A2000428527 +S224FE104042862838014655847600083800070150660641FAFFC4602C74026100FED86F1C09 +S224FE1060B3C4661476023A2A01723C2A0178BC45670652453545017232AA016C51CAFFDC1D +S224FE108041FAFFB220380146908321C00146BC456600FD8E6000FF3E43FA03A56000F69627 +S224FE10A011FC000101BB6004423801BB41FA0CDC6100F2906076428574016100F6966B0059 +S224FE10C0F7A23C00243C0000FFFF6100F6866B00F7923F006100F6BC6600F7882F094282D6 +S224FE10E06100F6706B00F77C2F003F064A85670E41FA0CA56100F24C6100081C600C41FAD9 +S224FE11000C8A6100F23E610008086700000E41FA000C6100F22E6100F2384E750D0A4469E5 +S224FE1120736B206572726F723A20000061740C000051670000C00C00005366F04205616212 +S224FE11401E00610000BC1C0153064281610000B2610000AE26410C070030660E4A0667061B +S224FE11606100009E60F6617460C20C0700326614220B6100008C26414A0667EA610000825C +S224FE118016C160F40C07003167EE0C07003966644A066660614641FA0AD96100F1A660003F +S224FE11A0F6D04A3801BB672408380001C033670A1038C031088000074E756100F26E67E263 +S224FE11C06100F2700C00005166D84E756100F22A0C00000D6700F1486000F1BA61224605DC +S224FE11E066024E75588F41FA0AAB6100F1566000F680508F41FA0A876100F1486000F6725F +S224FE120061086106DA0153064E7561960C0000306DE00C0000396E0A04000030E989D2004F +S224FE12204E750C0000416DCA0C0000466EC45F0060E643FA02046000F4FC7A016000FE7A55 +S224FE12406000F62E43FA02036000F4EA202053797374656D207265696E697469616C697AFE +S224FE1260696E672E2E2E2E0041FAFFE26100F0D46000EDCA4280428710100C800000005294 +S224FE128066063E3C010052881010670A74016100F4C26B00F5CE80473F00610007E24E752C +S224FE12A04E7542801010670A74036100F4A66B00F5B231C001524E756100F4D86600F5A45E +S224FE12C028096100F4CE6B00F59AC98966049889600253846500F58C26496100F4B66600E1 +S224FE12E0F58241FA0AC06100F05A7201B7C96406D3C4D7C472FF6100F2CC6B00F566C34BD1 +S224FE13006100F2C2C34B6B00F55A1293D3C1D7C151CCFFE44E7543FA01456000F4183F3CEF +S224FE132000016002426774016100F4286B00F5343F00243C0000FFFF6100F4186B00F5248A +S224FE13403F00427801CC427801D411FC000101DB3F172F3C000004002F3C000010003F2F9D +S224FE1360000C4A6F000E6706610005AC6004610005A0662A702E6100F01C08F8000101DB36 +S224FE13806100F0A867CA6100F07011FC0007C02711FC0009C027423801DB5C8F4E7570589B +S224FE13A060D40D4416F553E6F64636F92400FF4D16FF50ACF954BCFA475CFA5790FE4CF6AE +S224FE13C0FC00C8FA49A2FE41E0F64574FF084DF3F45253F644C3F541B9F5507DF65389F63D +S224FE13E05599F624ADF542AFF6084DA7F652ABF74411F74107F750C3F753CFF755DDF72478 +S224FE1400F9F642F1F70242DBF857EFF84C03F902494FF94F95F953DBF901424DF95767F93C +S224FE142001428CF957A6F9014FE5F943F3F902424EFA45FEFA5246FA014108FE4602FE02A3 +S224FE14404161FC5469FC4677FC03462BFE4857FE4757FE531FFE01442CF6522CF60152C769 +S224FE1460FE57C1FE5453540043484700434C5200534554004F524900414E44495355424982 +S224FE14804144444942000000454F5249434D50492E4200002E5700002E3F00002E4C0000C1 +S224FE14A04E454758434C52004E4547004E4F540000000000545354005452415054524150E2 +S224FE14C04C494E4B554E4C4B524553454E4F500053544F5052544500344537345254530077 +S224FE14E054524150525452004A5352004A4D500043484B004C4541004449565544495653CE +S224FE15004D554C554D554C535400460048494C53434343534E45455156435653504C4D49C1 +S224FE152047454C5447544C454F52000053554200454F5200434D5000414E44004144440063 +S224FE15405355424141444441534243445355425800000000434D50414142434441444458A9 +S224FE1560415352004C535200524F5852524F520041534C004C534C00524F584C524F4C0056 +S224FE158048E760401219143C00AD1038C0510800000756CAFFF6671A08000006661411D9E1 +S224FE15A0C053740951CAFFFE530166DA4CDF02064E7511FC000101C560F248E7604043FAC4 +S224FE15C0090461BC6624720243F801C36174661A123801C3020100C0670C080100066704CE +S224FE15E072036002720211C101C54CDF02064E7548E76040720743F801BC42116144663C35 +S224FE1600123801BC020100C0672E0801000667267205103801BDE208651E7206E408651801 +S224FE16207207E40865127208E208650C7209E4086506720A6002720211C101C54CDF020607 +S224FE16404E75343C10FE1038C0510800000756CAFFF6671608000006671012F8C05374092D +S224FE166051CAFFFE530166DA4E7511FC000101C54E752F017002484008380000C06366125C +S224FE1680538066F411FC0002C02711FC000401C5600C4A02662012F8C053534166D611FC15 +S224FE16A00001C02711FC0000C0276100FF44221F4A3801C54E7511D9C053534166B660DE70 +S224FE16C048E76040720143FA07F96100FEB466387402484208380000C063660C538266F4D3 +S224FE16E011FC000401C56020422C00036100FECC67160C38000301C5660E0C2C005000016D +S224FE1700660651C9FFC270034CDF02064E7548E760407202103801D6B02C0003674C43F8E7 +S224FE172001B032BC030F42290002137801D600036100FE4E66347402484208380000C06379 +S224FE1740660C538266F411FC000401C5601C6100FE6A660A197801D600034200600C6100DF +S224FE1760FF60660651C9FFAE70034CDF02064E750000000000000000423801C54A2C0000B5 +S224FE17806700010C3F077E0111FC000FC02711FC0000C02711FC0003C02743FA072111FCAD +S224FE17A0000EC0276100FDDA663870064A2C00046702540011C0C02711FC000AC02770FF89 +S224FE17C051C8FFFE08380000C06367086100FDEC423801C56100FEEA671C0C38000301C5BB +S224FE17E0670451CFFFA43E1F70014E7570080838000001DB667070044840538066FC197CF7 +S224FE1800FFFF000243FA06C06100FD7666D4343CFFFE1038C0510800000756CAFFF6660E56 +S224FE182011FC0002C02711FC000401C560B86100FDC066AE103801C1B02C000267086DC406 +S224FE18401940000260BE0C000008671A0C00000967100C000010673E0C00000A66267418FC +S224FE1860600674206002742A0C38000201C26614397C0200000619400002194200053E1F13 +S224FE188042004E7511FC000901C56000FF5A11FC000B01C54E750C38000101C266E6397C01 +S224FE18A001000006742060CE4A2C0000675A4281323C020082EC00064282343801DEC4C1EA +S224FE18C04281122C000284C14241082C000000006604E24AE31111C101D711C201D6B42C48 +S224FE18E000016C244842122C00029202C2EC0006B2B801E06F04223801E0520211C201D849 +S224FE190031C101DC42004E7511FC000B01C54E75423801DA600611FC000101DA225F49F8E9 +S224FE192001C6301F670449F801CE21DF01E021DF01E431DF01DE2F097E034A6C0006660083 +S224FE194001146100FE34660000EA4AB801E0670000E211FC0003C0274A3801DA672C083839 +S224FE19600001C063670A11FC000C01C5600000C4102C0001E208B03801D66F0811FC000D55 +S224FE1980C027600611FC000CC0276100FF1C660000A26100FD7A667443F801B0303C09451B +S224FE19A04A3801DA6602524032C0103801D7E50812C012F801D612F801D712F801D8302CFA +S224FE19C00006E04812C012EC000212EC000512FC00FF43F801B06100FBA86630227801E4EF +S224FE19E04281323801DC143801DA6100FC86661C303C032051C8FFFED3B801E493B801E00D +S224FE1A0082FC0200D37801DE6000FF400838000001DB663A5307671A103801C50C000001C8 +S224FE1A206700FF200C00000367080C0000046600FF1A0838000001DB661470074A2C000489 +S224FE1A406702540011C0C02711FC000BC027103801C54E750838000101DB6600FEEE700659 +S224FE1A604A2C00046702540011C0C02711FC000AC02770044840538066FC6000FECE11EF19 +S224FE1A8000040105422F0004427801CC427801D46100EAF246FC270011FC0025C073423829 +S224FE1AA001046100E87A41FA026F6100E8966100E86E4267307C04002F082F083F2F000ED6 +S224FE1AC06100FE4E6612307C04000C58424F663C0C584F5466364ED06100E844103801C53B +S224FE1AE00C000004673041FA01B96100E8566100E86041FA01CA6100E84A102C00046100C5 +S224FE1B00E87A6100E81A205F548F4ED041FA01A16100E83060DC41FA02136100E8266100CB +S224FE1B20E9126100E7FA0C0000516600FF5C41FA02286100E80E60BA2648428042814681B7 +S224FE1B4026804A93661C2681B293661C26CBB7C963EE2648B7D3660E588BB7C963F6428063 +S224FE1B604ED222006002220B201349FA015D4BFA0006600000842A0B4BFA00066000008628 +S224FE1B8049FA01634BFA00066000006E2A004BFA00066000007049FA01524BFA00066000FC +S224FE1BA000582A014BFA00066000005A49FA01B84BFA00066000004249FA015A4BFA0006C8 +S224FE1BC06000003670014ED23E3CFFFF08380002C07356CFFFF8671411C6C0717E0E51CFA3 +S224FE1BE0FFFE08380002C07366024ED608780003C06551CFFFFE60F41C1C67064DFAFFFAE6 +S224FE1C0060C64ED57807E99D7C0FCC050C060009630406060007060600304DFA000460A8F3 +S224FE1C2051CCFFE44ED5044A0452045A80020462046A049A045A045A800B047280060482BF +S224FE1C40048A800E047A0492800F04720000070D0A455843455054494F4E3A202000070DF1 +S224FE1C600A204E4F204D656D6F72792061743A20000D0A4C6F616420446F6E6500070D0A57 +S224FE1C80426164204C6F616420436861726163746572000742616420436865636B73756D8C +S224FE1CA000074472697665204572726F722000074E6F7420424F4F54204469736B00206F10 +S224FE1CC06E206472697665200007424144204D656D6F7279206174200052414D2053697A87 +S224FE1CE065203D2000206973200020696E7374656164206F6620000D0A53414745204949DD +S224FE1D000020537461727475702054657374205B312E325D0D0A00426F6F74696E67206615 +S224FE1D20726F6D20466C6F7070790050757420696E20424F4F54206469736B20616E6420F6 +S224FE1D4070726573732061206B6579202851202D207175697473290007426F6F74204162A6 +S224FE1D606F72746564002028546573742041626F727465642900202046696C6C696E67202B +S224FE1D806D656D6F72792E2E2E0020204C6F6164696E672E2E2E00202057726974696E6771 +S224FE1DA02E2E2E0020204D6F76696E67206D656D6F72792E2E2E000750524F4D20312042AB +S224FE1DC061640D0A000750524F4D2032204261640D0A00427970617373656420496E697460 +S224FE1DE00D0A004C6F6F7065642054657374730D0A0052414D207772697465206C6F6F7017 +S224FE1E000D0A0000001F0027002B003300470052005C006A007A008F204572726F722061F1 +S224FE1E20742000556E6B6E6F776E00427573004164647265737300496C6C6567616C204908 +S224FE1E406E737472756374696F6E0041726974686D657469630050726976696C6567650075 +S224FE1E605265736572766564205452415000556E61737369676E6564205452415000556E9D +S224FE1E8061737369676E656420496E746572727570740052414D20506172697479004675D0 +S224FE1EA06E6374696F6E3A200020204163636573733A20002020496E73743A20000303D13F +S224FE1EC0070207000108024A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +S224FE1EE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +S224FE1F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +S224FE1F20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +S224FE1F40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +S224FE1F60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +S224FE1F80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +S224FE1FA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +S224FE1FC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +S224FE1FE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +S804FE0000FD diff --git a/SAGE/FILES/sii.hex b/SAGE/FILES/sii.hex new file mode 100644 index 00000000..066c7d57 --- /dev/null +++ b/SAGE/FILES/sii.hex @@ -0,0 +1,514 @@ +S00A00007369692E68657847 +S224FE00000000040000FE0044600004F2600004E66000095E60000448600003F2600003CA02 +S224FE0020600003F8600003FE600029A2600029A460000334E4A70201600002F66000340098 +S224FE0040600034FA4E704FF8040011FC0092C02711FC0038C02511FC0092C06711FC003152 +S224FE0060C065700072FF343C42D741F8C0FE3080308151CAFFFA43F8000045F87FFE343C1D +S224FE0080344230113010301251CAFFF8343C06C541F8C00172084A10D0FC001051C9FFF81C +S224FE00A051CAFFEE43FA0006600002C049FA2D054BFA000660002BFE41FA00362278000874 +S224FE00C021C80008B1F80008662E11FC0090C58711FC0090C50711FC0000C58311FC00CD66 +S224FE00E0C50311FC0000C58511FC0005C50560044FF8040021C900081038C0216B64E6087B +S224FE010002400006303B00064EFB000200180024001800084238010449FA2D744BFA08527A +S224FE012060002B9249FA2D784BFA003860002B8649FA2D7B4BFA000660002B7A74FF720009 +S224FE014070001038C023460008000002670272FFE308024000064840204030C151CAFFFCB5 +S224FE016060DA41FAFE9C343C1FFF42004201D018D21851CAFFFA4A00671449FA2CF64BFA05 +S224FE0180000660002B304A38C0216A0001004A01671449FA2CEC4BFA000660002B184A383C +S224FE01A0C0216A0000E811FC0001C067307C000072014841323CFFFE224145FA00066000B9 +S224FE01C02A34664647FA000C21CB000808F80002C5034FF8040047FA002421CB00087202EF +S224FE01E04841D3C1303CA5A53280B051660E46403280B05166064640D3C160EC4FF80400AC +S224FE020093C145FA0006600029EC67084A38C0216A00007A303C00BF41F80100429851C8BF +S224FE0220FFFC548921C901004E6121C9014A21C9014243FA000C21C9000808B80002C50322 +S224FE02404FF804006100041611FC0000C0674A38C0216B1611FC0007C06770FF51C8FFFEFD +S224FE026011FC0006C0676000FEFA6100017C41FA2B256100019830380100ED48610002166F +S224FE0280704B610001DA6100016060044E7227007228740208380006C0216702725011C222 +S224FE02A001C611C101C7423801CA11C201CE11C101CF11FC000101D27206610000F8423825 +S224FE02C001BA2278000841FA002A21C8000811FC00AAC58311FC0005C5050C3800AAC58357 +S224FE02E0661011FC0000C58350F801BA31FC023001F04FF8040021C900081038C021C07C3B +S224FE03000030670CB07C00206724B07C0010672621F80100014A21F80100014231FC270081 +S224FE0320014E41FA004221C801466000064442676100280860DA4A3801BA67D420380100CF +S224FE03404840720C92406F12C2FC000A5341303C6F9A51C8FFFE51C9FFF6426770012F0002 +S224FE03606100332260AA4E4F60FC41F8C0734200108011FC0076C007E01810801238C02186 +S224FE0380E0181080706E080100036702707E10BC00400241000711FB1014C003108011FCAB +S224FE03A00000C003E01810BC00254ED1028040201008040241F8C0334240108011FC00B66E +S224FE03C0C007E018108011FB10E4C005E018108011C0C005E01810BC0040E01810BC004ED2 +S224FE03E0E01810BC00274E752F00700D6170700A616C420061686166616461626160201F2E +S224FE04004E752F0070206156201F4E753F0010186704614A60F8301F4E75E9186126E9182E +S224FE042061224E752F017203E958611851C9FFFA221F4E752F017207E998610851C9FFFA57 +S224FE0440221F4E753F000200000FB03C0009630406000007060000306104301F4E754A38AD +S224FE04600104662C3F01323CFFFF08380002C07356C9FFF8670811C0C071321F4E7548E7F7 +S224FE0480C0C043FA00066000FEE24CDF030360D64E4A4E7548E7F000720032007400343CED +S224FE04A02710420382C266044A0367061001619450C34241484184FC000A66E84CDF000F1E +S224FE04C04E754A38010466282F011238C0730801000167F61038C071020100386604221FCE +S224FE04E04E7511FC0035C07370076100FF7260DA4E494E7508380001C0734E7561C4088000 +S224FE050000070C0000616D0A0C00007A6E04088000054E7521C001067002604E21C00106B5 +S224FE05207004604621C001067006603E21C001067008603621C00106700A602E21C00106D4 +S224FE0540700C602621C00106700E601E21C001067010601621C001067012600E21C0010614 +S224FE05607014600621C00106701648F87FFE010A4E6821C8014A2A007016BA806270BA3CBC +S224FE058000046206381F261F341F31DF014E21DF014621CF01424FF804000C05001467004D +S224FE05A0199A6E0018B80C050012661E11FC0001C06711FC0000C0674A3801BA670C08F887 +S224FE05C00002C50308B80002C50370FFE01851C8FFFC46FC270011FC0038C02508B80006F0 +S224FE05E001504238010443FA000A6000FD7E428560A849FA27164BFA0006600026B849FAEB +S224FE06002954D8F450004BFA000460EE49FA295A4BFA000460E420380146610017F66100E6 +S224FE0620FDC80C0500046200034841FA29C26100FDDC30046100FDEE41FA29BF6100FDCE01 +S224FE064020036100FDF041FA29BC6100FDC030026100FDD26100FD926000031641F80008DC +S224FE066043FA268045FAF99A4280301967186B06D08A20C060F2424112003019D08A20C023 +S224FE068051C9FFFC60E24E75225F02800000000FD080D089C1893251D3C04ED148E780B0A4 +S224FE06A02478000847FA001421CB0008101121CA00084CDF0D01B0004E75508F321F46C153 +S224FE06C041FA26586100FD46588F20096100174421CA00084CDF0D01000000014E750838BE +S224FE06E00001C0734E752F00703A6100FD72201F6100FD104E752F00702C6100FD62201F1D +S224FE07004E752F0070076100FD56201F4E75C03C007F0C0000206D060C00007E6D02702E06 +S224FE07204E752F092F01224842816100FDD00C00001B6700006E0C000012670000680C003B +S224FE0740000D674A0C000008661AB3C867DC6100FD0E6100FCAE6100FD0651C9FFF25389C4 +S224FE0760528260C40C00007F6614B3C867BC61585389528210116100FCE6544160AC611AF2 +S224FE0780428153826B0812C06100FCD4609C610A421912C0221F225F4E758281673C4281C6 +S224FE07A0602C224842812F0870236100FCB26100FC38B3C86700000C10186100FCA2B3C87F +S224FE07C066F6205F6000FF648281660E72013F00103C005C6100FC88301F4E7542801018C6 +S224FE07E08000660253884E7561F28000670A0C00002067040C00002C4E7561E067080C00DE +S224FE0800002067F653884E7561D2244942411219B011568957C9FFFA660001481021E1589A +S224FE08201021D4C04ED248E7180042817801E89C61B667540C00002F660E383C33334844E2 +S224FE0840383C333461A26740040000306D380C0000096F144A04662E040000070C00000A9C +S224FE08606D240C00000F6E1E26014A046708E799E39BD2836002E999B684640AD280848222 +S224FE088067C2B48164BE72FFC1414CDF00184E752F036100FF66428395CA6100FF4C67002D +S224FE08A000480C00002367360C0000246708347801525388602A6100FF306700002C0400F7 +S224FE08C0003065240C000003641E244093C96100FF18670000180C00002B660C6002528334 +S224FE08E042826100FF42670257832240D5CAD5CAD4FC0154D3D2201FC14380804E752F02AB +S224FE090042826100FEF6670000520C000027671C0C00002E674624016100FF0C6B06241F20 +S224FE092092814E75241F428153814E756100FEAE6100FEAA670000200C0000276712E19A7D +S224FE09404A0266E0D480828167E6B28264E260D46100FE9666CEC14260C47001241F22008A +S224FE09604E756100FA9E703F6100FAF46100FD944FF8040042B801546100FA6E083800061F +S224FE098001506700000870546100FAD436380152670C70246100FAC810036100FAA8703EF2 +S224FE09A06100FABC742841F801886100FD7643FA1A686100FE5460B843FA1A8C6000FE4AD6 +S224FE09C06100FE382838017E387801821010670E6100FEBE668C2809284A31CA0182610045 +S224FE09E0FE1A327C01001010670A6100FEA46B00FF726704D3C45389528921C9017E2A0968 +S224FE0A00611C6718280B6100FCD667F46100FAEE0C00001367F60C00000366E44E756100D4 +S224FE0A20F9C820046100FA0EB8FC0154670C6100F9D2200490946100F9FC6100FCAA760F93 +S224FE0A402644C7496100FC56C7496600FF16101B6100F9C808030000660000066100F9A419 +S224FE0A60BA8B57CBFFDE6100F99A760F2644101B6100FC9C6100F9E8BA8B57CBFFF24E75CB +S224FE0A8043F80154323C20247402601443F80126323C2041600843F80106323C20447407FF +S224FE0AA06100FD3A671A903C00306B00FEB678001800B8026E00FEAC61226100F92C4E75D1 +S224FE0AC04284611852846100F93A0C04000466046100F9306130B8026DEA4E756100F90A99 +S224FE0AE042833001E0880C000020670000066100F96E10016100F968868366061004610077 +S224FE0B00F9446100FBE22004E5800280000000FF4A836A42303100006100F90A0C4153521D +S224FE0B20663C48E7704036006100F8D870286100F92E428243FA18D21419670E1019E57B94 +S224FE0B40650270206100F91860EE4CDF020E70296100F90C6008203100006100F8D84E75F4 +S224FE0B606100FC7A6600FDFC6100FF226100FF28611861086148610461344E756100F8840D +S224FE0B806100F8804E756000F86061FA103C00506100F8CC103C00436100F8C46100FB4892 +S224FE0BA020380146307801526000126861D876FF43F8014E223C00005352600E61C843F8B1 +S224FE0BC0014A223C00005553760142846100FF144E757C0060000C2C700072104A10670A7C +S224FE0BE06100FC446B00FD7C12006100000E5200B0016DF66100F7F24E756100F7EC41FAFA +S224FE0C0000206100F8086100F83C41FA001B3438017C0102670441FA001B6100F7F04E75AD +S224FE0C205452415020230020204E6F2074726163652000202054726163652020202000003C +S224FE0C4043FA18A26000FBC26100FCB46600FD142A006100FCAA6600FD0A2800D085610079 +S224FE0C60F7882200103C002B614822059284103C002D613E2205C2C4103C002A61344A4415 +S224FE0C806746220582C4103C002F61186132103C00726100F7CA103C00656100F7C2103CB9 +S224FE0CA0006D48416100F7B86100FA3C30016000F7746100F7AA6100FA2E20016100F7761E +S224FE0CC06100F7406000F73C4E757C106100FB2C2838017E38780182101067106100FBB258 +S224FE0CE06600FC802809284A31CA01826100FB0C327C00141010670C7CFF6100FB946B005B +S224FE0D00FC6267062C096B00FC5A52892A092C446100F6D6200E6100F71CB8FC0154670C46 +S224FE0D206100F6E0200E90946100F70A6100F9B848E7060061304CDF006021CE017E4A8624 +S224FE0D406B065386671E2A0EBA8E650000186100F98E67BC6100F7A60C00001367F60C0033 +S224FE0D60000366AC4E75300EE2086500FBF67C07610006F03E00E9586100F90E0020010038 +S224FE0D8001080104014003880428046E0512060606CC053A05A60606065206CC08070008AC +S224FE0DA0664E43FA176C3207E049E249610006F659016F5E0401001067585801660642458B +S224FE0DC0611C60063A07610006C4610006FC6100070216076100F920610007364E75428535 +S224FE0DE043FA171E3207EC5902410003600006B63007020000380C00000867367042610069 +S224FE0E0006AE61DA610006C23607EC5B6100072860C030070200003F0C00003C66A64282F3 +S224FE0E20263A084C080700066704263A0846600000F2203A082A610006767050610006707B +S224FE0E403A07E35D08C500066100064E6100067A08070007670A61126100F89C61144E757E +S224FE0E6061106100F89261024E753607EC5B600006C6360708C30005600006964285600607 +S224FE0E807A4060027AFF203A07D6610006223007EC5802000007530066067041610006108F +S224FE0EA0610005F6610006223607610006646100F8463607EC5B610006644E75080700087A +S224FE0EC0660002043007EF580240000732006100F7B8001000320014001C007C011800B2E1 +S224FE0EE001527401600A263A0786428260064282263A0780283A07683007020000C00C0025 +S224FE0F0000C0671843FA16366100059A3A076100057C610005B4610005F64E752004610025 +S224FE0F20058E7A40610005A228034A026614610005DE4A84670A6100F7BE200461000570D5 +S224FE0F404E7561F66100F7B0610005C44E753207E65902410007080700076624203A0718A4 +S224FE0F6008070006670C203A07124A016604203A070E6100053A61000550610005924E753E +S224FE0F804A016756203A06D861000524704D3A07E35D08C5000661000516610004FC610035 +S224FE0FA005287A40610004BC31C001880807000A661E6100000C6100F73E610005524E7591 +S224FE0FC070236100F49A303801886100F4584E7561E86100F72261E84E75203A06AA080743 +S224FE0FE00006678E203A069C60880C0700FC6612203A0698610004B8203A0694610004B06A +S224FE10004E753A07024500C00C4500C0670A3005E2588A406000FEEE283A06784282428352 +S224FE10206000FED608070007660000983207E6590201000714010C01000667520C010003F2 +S224FE10406F14263A065E024200010247000F004700C86000FEA043FA14FC61000448610041 +S224FE10600468E20A660E70236100F3F430076100F3D44E753607E75B610004C008070003EE +S224FE1080660A6100F6727A40610004484E75320702410007340143FA14CC610004080C029A +S224FE10A00002660A610004227A406100042670544A02670870560C02000666046100F3A038 +S224FE10C04E754280600270023207EC59C27C0001D2407A4043FA14AE610003CA610003EAB0 +S224FE10E06100042C0807000867186100F60A3607EF5B70200807000667027028B1436100E3 +S224FE110004104E753207020100C00C0100C0673E203A0588080700086704203A05826100DC +S224FE1120038E3A07610003666100039E70236100F32E3007EF58020000074A006602700848 +S224FE11406100F3026100F5B0610003C44E7570533807020400380C040008660808870003ED +S224FE1160303C4442611C610003A60C04000866106100F5847A40610003603440610003FA3B +S224FE11804E7543FA1440610003263207EE5902810000001ED3C142803011610003126100DF +S224FE11A003284E757A40320702410F000C410100670A704243FA13EE61CC600C203A04D87B +S224FE11C0610002EC6100030230074A0067106100F24AE158E040548E6108558E4E75610017 +S224FE11E002F83440610003924E750807000866000258203A046A610002B67051610002B039 +S224FE1200610002C670236100F25610076100F20C6100F4E43607EC5B6100031C4E753A07AF +S224FE122043FA13C2612208070008670C61106100F4C6610002DA4E7561F86100F4BA36075B +S224FE1240EC5B610002F24E753207E95902410007610002524A456704610002326100026A56 +S224FE12604E75428560023A0743FA139A61DA3607E75B61086100F4803607EC5B08070003C6 +S224FE12806606610002B24E75610002C04E753007024001F00C40010067C8EC4872045740FA +S224FE12A0670859406600FF787205088700068E7C41006000FE1E3007EC580240000755401A +S224FE12C06F00FF5C43FA133E7A4053406706E35D594066166100FF72610002346100F418CE +S224FE12E03607EC5B610002544E75044710003007024000380C4000086600FF24203A03A8FF +S224FE1300610001AC3A0761000184610001BC3607E75B61086100F3E03607EC5B610002264E +S224FE13204E753007024001F878000C400140671078030C400148670878020C4001886624A1 +S224FE1340203A0368610001686100017E3607EC5B61086100F3A23607E75BE21C650001DC79 +S224FE1360600001D4E8480C0000106700FEF67206E44857406700FF347207594067F66000EA +S224FE1380FE9E3007024000C00C4000C067123007024001300C4001006700FECC6000FE80EA +S224FE13A03A07E25D43FA12563207E55902410001610000F2610000E26100010E6100015092 +S224FE13C06100F3343607EC5B610001704E7532073A07024500C00C4500C06744E65961503C +S224FE13E0610000AA610000E2360702430E00080700056708EC5B6100013E60167023610038 +S224FE1400F05E3003EF580200000F660270086100F0346100F2E23607E75B6100011A4E7598 +S224FE1420EF59610C4285610000A0610000E24E7502410003340702420100EC5A824243FA19 +S224FE144011DC610000604E75702E61000062203A02126100005A6100007030076100EFC670 +S224FE14604E752F09224E6100F2346600F4F6301E225F4E752F09224E6100F2226600F4E43A +S224FE148054896100F218201E225F4E75024500C00C05008066027AC03205EC5902010003C3 +S224FE14A043FA108AE519024100FF203110002F017203E1984A00670000086100EFA253068F +S224FE14C051C9FFF0221F4E756100EF3851CEFFFA4E7570236100EF883205EC59C27C000371 +S224FE14E0B23C000267206100FF7A53016C066100EF2A4E756100EF2E53016D086100FF648A +S224FE15006100EF224E75703F6100EF544E7536071003E60802000007E70B86001003024069 +S224FE152000076100F164001000140018001E00240076008000C67244601472416010223A08 +S224FE15400112600A223A01106004223A010E7403E1991001671C6100EF060C000044670637 +S224FE15600C000041660C3003E618020000076100EED451CAFFDC4E75705B6100EEE2D5CEF4 +S224FE1580200A558030780152D1C8D1C890A801546100EEA2705D6100EEC64E756100FEC4D6 +S224FE15A06100EE8260986100FEBA38006100EE6C70286100EEAA61826100F13C3604EF5BCD +S224FE15C00804000F66066100FF6E60046100FF6C702E6100EE8A70570804000B6702704C09 +S224FE15E06100EE7C70296100EE764E75E61BC63C000710036100F0920012001C0026003E6A +S224FE160000540010001000104E756100FE566100EE144E756100FE5E6100EE1A4E7561005B +S224FE1620FE4234406100EDFE223A003C6100FF206100FF464E756100FE2A38006100EDDC3B +S224FE1640203A00286100FE686000FF6E6100FE844E75284129002841292B2D2841294D4F21 +S224FE16605645574F5244285043292850430043435200535200004E424344504541005357DD +S224FE168041504558544C45585457494C4C4547414C005441530042535200414444515355A6 +S224FE16A0425155535000434D504D4558470043FA0DB56000F1546100F1D86600F2A660045B +S224FE16C06100F0402809284A2A0454856100F3506100F01441F80188243C00000028610018 +S224FE16E0F042428110106716223C0000FFFF6100F20E6BCC6E0A13400001E08012805489C6 +S224FE17000C01002E66BE4E7543F80154323C202474037A01601643F80126323C2041600861 +S224FE172043F80106323C2044740842856100F0AE671A903C00306B00F22AB0056B00F22416 +S224FE1740B0026C00F21E4282610E4E75200561085280B0026DF84E7542832F023A012800CF +S224FE17602C00E5864A82660E6100F0904A10662260046100EF8E32056100EC6E6100F364E0 +S224FE17806100EF64742841F801886100EF961010672042816100F1686BD8660000160286E3 +S224FE17A0000000FF86836A063380600060042380600032051004241F4E756100F02066000C +S224FE17C0F1A26100FF526100FF586106611E610E4E7543F80146323C50436000001843F8BB +S224FE17E0014E323C535276FF6000000C43F8014A323C55537601428242806100FF5E4E7589 +S224FE18007CFF7A0142806100EFD467144486903C00306B00F14EB03C00016E00F1463A0032 +S224FE1820360060046100EEDC3643D7CB284BD7CB4A866B0A675A6100EFC24A106614616AF9 +S224FE18406100EEA4742841F801886100EED66100EFAA101067320C00002E660607B80150A6 +S224FE186060266100F02C6BBC6100EF90243C0000FFFF6100EFB26BAC426C017239400176D3 +S224FE188007F80150274901605243B6456F9A4E75611860F4427265616B706F696E742000CC +S224FE18A0496E61637469766500006100EB3C41FAFFE46100EB5810036100EB8A6100EE2848 +S224FE18C007380150660A41FAFFD86100EB404E75202B01606100EB5E6100EB2870286100E1 +S224FE18E0EB7E302C01766100EB3C6100EE0A302C01726100EB3070296100EB644E757600FB +S224FE190078104A10671C6100EF1E6B00F056160018006100EEE60C00005467460C00004E76 +S224FE192067386100EAC441FA004C6100EAE010036100F2C86100EDB0742841F80188610059 +S224FE1940EDE26100EEB667240C00005467140C00004E67066100EDAC60C83238017C0781F2 +S224FE196060063238017C07C131C1017C5203B6046DBC4E7528542972616365206F7220285C +S224FE19804E296F2074726163650043FA0AF86000EE78243C000000FF616C6600EFC61A00C9 +S224FE19A0E1401005600C243C0000FFFF61586600EFB23A0048403005600842826148660032 +S224FE19C0EFA241FA146D6100EA4461000942E19812C0538466F821CA00084E7548E7F00027 +S224FE19E06100EEAE661A28096100EEA62449C9896B0E6E06988952846004D5C9538A4280FD +S224FE1A004CDF000F4E7561D4660622026100EEF04E7561F266142C0098876D00EF4670FFD6 +S224FE1A204A10670A22026100EED66600EF3641FA14E96100E9D8610008D64E7543FA0AB4AD +S224FE1A406000EDC6243C000000FF7E0161C41219C200B206670453846CF46100009660F6D9 +S224FE1A60243C0000FFFF7E0261A81219E1991211C240B246670453846CF06100007660F6EF +S224FE1A8042827E04618C2649548B1219E1991211E199121BE1991213C280B28667045384F8 +S224FE1AA06CE86100004E60F66100FF326600EEB448E708606100FF266600EEA82A492C0474 +S224FE1AC04CDF0610C34D41FA14516100E9406100083E9C846518284952892E04264D121C25 +S224FE1AE0B21B6606538766F6610853866CE861024E7148E7FE7E663E41FA142E6100E90E98 +S224FE1B00538920096100030C6100EBDC7203E198101951C9FFFA6100E91C41FA14186100CD +S224FE1B20E8EC6100E9D80C00004366126100E9304CDF7E7F4E7541FA13D06100E8D04CDF1E +S224FE1B407E7F21CA00086000EE286100E8B66100E8B243FA093A6000ECB043FA093C6000C4 +S224FE1B60ECA86100ED2C6600EDFA20096100E8C66100EB7410116100E8A24E756100ED12E0 +S224FE1B806600EDE03C09080600006600EDD620096100E8A26100EB5030116100E8884E750E +S224FE1BA043FA08FD6000EC626100ECE66600EDB4223C000000FF6100ED466600EDA612807C +S224FE1BC04E756100ECCC6600ED9A3C09080600006600ED90223C0000FFFF6100ED226600D1 +S224FE1BE0ED8232804E756100EC1274076100EC386B00ED7022006000E7BC43FA08AA600063 +S224FE1C00EC086100006443FA07B654894A516700ED523014C059B05966F0D8D121CC016835 +S224FE1C2008F80002015008F800040150600261387401610001BA426A017251CAFFF66002DC +S224FE1C40612608B80005015008F80006015008F8000701501038015002000007660608B867 +S224FE1C6000060150600001506100EB901010670C6100EC1E6600ECEC21C901466106610048 +S224FE1C80E7684E752C380146284608060000671241FA001C6100E77620066100017660001C +S224FE1CA0ECD0224C6100E9F66600ECB84E75496C6C6567616C2070726F6772616D20737411 +S224FE1CC061727420616464726573733A20006100E71843FA07DC6000EB30083800060150C8 +S224FE1CE0670461A0604E4E7508F8000501506040619208B8000301500C100049660808F834 +S224FE1D000003015052887005083800050150660270104A10670E747F6100EAE06100EB085E +S224FE1D206B00EC406100E6C2600C08B8000501506100FF36700111C0015108F800060150FD +S224FE1D4008B80007015030140240FFF00C404E406664301C0240000F3C38017C41FA002C5A +S224FE1D600106661C21CC016808F80007015008F80002015008B800040150673A41FA0021C4 +S224FE1D806100E68A6100E662602C2A2A2A2054726163696E672054524150202A2A2A002AB5 +S224FE1DA02A2A204753207465726D696E61746564202A2A2A0000287801463C38014E08383D +S224FE1DC00006015066060886000F600408C6000F2078014A4E602E7801422F0C3F064CF821 +S224FE1DE07FFF01064E7308B8000601504E7542803242D3C92449D3C905380150670E226957 +S224FE1E0001606100E8986600000652804E7553804E756100E62030780152D0C8D0C84A7892 +S224FE1E200152672E6100E5DC2F0070286100E63070246100E62A303801526100E6086100E7 +S224FE1E40E8A6201F90A801546100E5EA70296100E60E4E7554726163653A200008380006B5 +S224FE1E6001506700FF52083800070150672608B80006015074006100FF766B00EAE6670826 +S224FE1E803551016C32BC4E4F52420C42000366E66000FF2441FAFFBE2038014621C0017E16 +S224FE1EA06100E56A28406100FF6AD0FC015431C801826100E832224C6100E7E266143011D2 +S224FE1EC06100E5626100E53C6100E5382C496100EE96083800050150670A41F801884210E2 +S224FE1EE06100EC7E533801516F1E083800030150671A6100E7EA67146100E6020C00001380 +S224FE1F0067F60C00000366046000EA666100E4DA6000FE280D0A556E657870656374656467 +S224FE1F2020627265616B20706F696E743A2000000D0A427265616B3A200042854286283890 +S224FE1F4001465584760041FAFFCC74026100FEA06F32B3C4661E41FAFFD876020C02000237 +S224FE1F6067123A2A01723C2A0176BC4567065245354501720C514E4F670605B80150600466 +S224FE1F8032AA016C51CAFFC60838000201506728B8B80168662208B80002015008B80004BB +S224FE1FA00150661421C4014608F80006015008B8000701506000FEA620380146908321C021 +S224FE1FC00146BC456600FC824A436600FED028440C544E4F6600FEC620046000FEC043FAFF +S224FE1FE004E46000E82411FC000101BB6004423801BB41FA0E516100E41460764285740121 +S224FE20006100E8246B00E95C3C00243C0000FFFF6100E8146B00E94C3F006100E8746600A7 +S224FE2020E9422F0942826100E7FE6B00E9362F003F064A85670E41FA0E1A6100E3D0610016 +S224FE20400992600C41FA0DFF6100E3C26100097E6700000E41FA000C6100E3B26100E3BC8F +S224FE20604E750D0A4469736B206572726F723A20000061740C000051670000C00C0000539C +S224FE208066F0420561621E00610000BC1C0153064281610000B2610000AE26410C0700309D +S224FE20A0660E4A0667066100009E60F6617460C20C0700326614220B6100008C26414A0610 +S224FE20C067EA6100008216C160F40C07003167EE0C07003966644A066660614641FA0C4F9C +S224FE20E06100E32A6000E88A4A3801BB672408380001C033670A1038C031088000074E75A4 +S224FE21006100E3F267E26100E3F40C00005166D84E756100E3AE0C00000D6700E2CC600027 +S224FE2120E33E6122460566024E75588F41FA0C216100E2DA6000E83A508F41FA0BFD610011 +S224FE2140E2CC6000E82C61086106DA0153064E7561960C0000306DE00C0000396E0A040052 +S224FE21600030E989D2004E750C0000416DCA0C0000466EC45F0060E643FA03436000E68A25 +S224FE21807A016000FE7A6000E7E843FA03426000E678202053797374656D207265696E697E +S224FE21A07469616C697A696E672E2E2E2E0046FC270011FC0025C0734238010441FAFFD43E +S224FE21C06100E24A70FF51C8FFFE6000DE784280428710100C00005266063E3C010052886A +S224FE21E01010670A74016100E63E6B00E77680473F00610009464E754A3801BA6700E76421 +S224FE2200428042877C0110100C00005266063E3C010052881010675C0C00002067140400E6 +S224FE222000306D00E73E0C0000036E00E7368E0052886100E5C64A00673A0C00002366004B +S224FE2240001652884A10672C740F6100E5DA6B00E7123C00601E740743F801F62C09429128 +S224FE226042A90004422900086100E572670612C051CAFFF63F072F066100140A4E754E7572 +S224FE228074186100E16451CAFFFA4E7543FAE2D621C9002443FAE2C621C900BC4E7542801F +S224FE22A01010670A74026100E57E6B00E6B631C00152E540D07C015431C001824E756100A7 +S224FE22C0E5D06600E69E28096100E5C66B00E694C98966049889600253846500E6862649E4 +S224FE22E06100E5AE6600E67C41FA0B756100E11E7201B7C96406D3C4D7C472FF61101293EE +S224FE2300D3C1D7C153846CF621CA00084E752478000849FA000821CC00084E7541FA09FCB8 +S224FE23206100E0EA548F201F6100FAE821CA00086000E63E43FA01B56000E4CE3F3C000112 +S224FE23406002426774016100E4DE6B00E6163F00243C0000FFFF6100E4CE6B00E6063F002A +S224FE2360427801CC427801D411FC000101DB3F172F3C000004002F3C000010003F2F000CA0 +S224FE23804A6F001067066100064A60046100063E662A702E6100E0C808F8000101DB6100D5 +S224FE23A0E15467CA6100E11C11FC0007C02711FC0009C027423801DB5C8F4E75705860D45E +S224FE23C0F0FF60000004F00060000002F0F850C80004FFB84E900002FFB84EA80004FFB852 +S224FE23E04EB00004FFBF4EB80004FFBF4EB90006FFBF4EBA0004FFBF4EBB0004FFF04E4033 +S224FE24000002000000000000015402530958014E015A0156014300000E44A0E55396F2466F +S224FE242072F52486FE4DA6FE5032F754B6F847E2F75760FD4CC6FB00C2F84972FD4128E87A +S224FE2440451CFF5824F6094D7AE5521AE74450E64146E65044E75366E75576E7243AE64265 +S224FE24608CE75492E7094D51F25255F344BBF241B1F2506DF35379F35587F324A3F2429B3D +S224FE2480F35499F402420EF55722F54C36F50249CCF64F12F75358F70142CAF657E4F601FD +S224FE24A04209F75723F7024F88F7439AF7535CF703427AF84536F95238F84E40F80141C9DE +S224FE24C0FC46C3FC024122FB542AFB4638FB064600FD482AFD47B0FD53E0FC568EE143B211 +S224FE24E0FD54BEFD0144E6E75264E7015257FE5751FE034252F5576EF54C8EF54DB6F500C3 +S224FE25005453540043484700434C5200534554004F524900414E44495355424941444449D3 +S224FE252042000000454F5249434D50492E4200002E5700002E3F00002E4C00004E454758F0 +S224FE2540434C52004E4547004E4F5400000000005453540054524150545241504C494E4B35 +S224FE2560554E4C4B524553454E4F500053544F5052544500344537345254530054524150BD +S224FE2580525452004A5352004A4D500043484B004C45410044495655444956534D554C5511 +S224FE25A04D554C535241460048494C53434343534E45455156435653504C4D4947454C54E9 +S224FE25C047544C455400460048494C53434343534E45455156435653504C4D4947454C541D +S224FE25E047544C454F52000053554200454F5200434D5000414E4400414444005355424194 +S224FE260041444441534243445355425800000000434D50414142434441444458415352001D +S224FE26204C535200524F5852524F520041534C004C534C00524F584C524F4C0048E760409C +S224FE26401219143C00AD1038C0510800000756CAFFF6671A08000006661411D9C05374094F +S224FE266051CAFFFE530166DA4CDF02064E7511FC000101C560F248E7604043FA099861BCC5 +S224FE26806624720243F801C36174661A123801C3020100C0670C0801000667047203600250 +S224FE26A0720211C101C54CDF02064E7548E76040720743F801BC42116144663C123801BC34 +S224FE26C0020100C0672E0801000667267205103801BDE208651E7206E40865187207E408D3 +S224FE26E065127208E208650C7209E4086506720A6002720211C101C54CDF02064E75343C69 +S224FE270010FE1038C0510800000756CAFFF6671608000006671012F8C053740951CAFFFE77 +S224FE2720530166DA4E7511FC000101C54E752F017002484008380000C0636612538066F476 +S224FE274011FC0002C02711FC000401C5600C4A02662012F8C053534166D611FC0001C02789 +S224FE276011FC0000C0276100FF44221F4A3801C54E7511D9C053534166B660DE48E76040B8 +S224FE2780720143FA088D6100FEB466387402484208380000C063660C538266F411FC00042B +S224FE27A001C56020422C00036100FECC67160C38000301C5660E0C2C00500001660651C927 +S224FE27C0FFC270034CDF02064E7548E760407202103801D6B02C0003674C43F801B032BCFE +S224FE27E0030F42290002137801D600036100FE4E66347402484208380000C063660C538201 +S224FE280066F411FC000401C5601C6100FE6A660A197801D600034200600C6100FF6066068A +S224FE282051C9FFAE70034CDF02064E750000000000000000423801C54A2C00006700010C3B +S224FE28403F077E0111FC000FC02711FC0000C02711FC0003C02743FA07B511FC000EC027C7 +S224FE28606100FDDA663870064A2C00046702540011C0C02711FC000AC02770FF51C8FFFE97 +S224FE288008380000C06367086100FDEC423801C56100FEEA671C0C38000301C5670451CF75 +S224FE28A0FFA43E1F70014E7570080838000001DB667070044840538066FC197CFFFF0002B1 +S224FE28C043FA07546100FD7666D4343CFFFE1038C0510800000756CAFFF6660E11FC0002E2 +S224FE28E0C02711FC000401C560B86100FDC066AE103801C1B02C000267086DC419400002EA +S224FE290060BE0C000008671A0C00000967100C000010673E0C00000A66267418600674208C +S224FE29206002742A0C38000201C26614397C0200000619400002194200053E1F42004E7537 +S224FE294011FC000901C56000FF5A11FC000B01C54E750C38000101C266E6397C010000062E +S224FE2960742060CE4A2C0000675A4281323C020082EC00064282343801DEC4C14281122C1F +S224FE2980000284C14241082C000000006604E24AE31111C101D711C201D6B42C00016C24E7 +S224FE29A04842122C00029202C2EC0006B2B801E06F04223801E0520211C201D831C101DC3A +S224FE29C042004E7511FC000B01C54E75423801DA600611FC000101DA225F49F801C6301FD2 +S224FE29E0670449F801CE21DF01E021DF01E431DF01DE2F097E034A6C000666000114610053 +S224FE2A00FE34660000EA4AB801E0670000E211FC0003C0274A3801DA672C08380001C063BA +S224FE2A20670A11FC000C01C5600000C4102C0001E208B03801D66F0811FC000DC02760065B +S224FE2A4011FC000CC0276100FF1C660000A26100FD7A667443F801B0303C09454A3801DA3A +S224FE2A606602524032C0103801D7E50812C012F801D612F801D712F801D8302C0006E04858 +S224FE2A8012C012EC000212EC000512FC00FF43F801B06100FBA86630227801E4428132381F +S224FE2AA001DC143801DA6100FC86661C303C032051C8FFFED3B801E493B801E082FC0200E9 +S224FE2AC0D37801DE6000FF400838000001DB663A5307671A103801C50C0000016700FF20F2 +S224FE2AE00C00000367080C0000046600FF1A0838000001DB661470074A2C00046702540082 +S224FE2B0011C0C02711FC000BC027103801C54E750838000101DB6600FEEE70064A2C0004CB +S224FE2B206702540011C0C02711FC000AC02770044840538066FC6000FECE11EF00040105B8 +S224FE2B40422F0004427801CC427801D46100DB0E46FC270011FC0025C073423801046100EF +S224FE2B60D88841FA026E6100D8A46100D87C4267307C04002F082F083F2F000E6100FE4EC5 +S224FE2B806612307C04000C58424F663C0C584F5466364ED06100D852103801C50C00000409 +S224FE2BA0673041FA01B96100D8646100D86E41FA01CA6100D858102C00046100D888610049 +S224FE2BC0D828205F548F4ED041FA01A16100D83E60DC41FA02126100D8346100D92061006B +S224FE2BE0D8080C0000516600FF5C41FA02276100D81C60BA264842804281468126804A93C4 +S224FE2C00661C2681B293661C26CBB7C963EE2648B7D3660E588BB7C963F642804ED22200D3 +S224FE2C206002220B201349FA015D4BFA0006600000842A0B4BFA00066000008649FA0163F2 +S224FE2C404BFA00066000006E2A004BFA00066000007049FA01524BFA0006600000582A014F +S224FE2C604BFA00066000005A49FA01B74BFA00066000004249FA01594BFA000660000036E6 +S224FE2C8070014ED23E3CFFFF08380002C07356CFFFF8671411C6C0717E0E51CFFFFE08382B +S224FE2CA00002C07366024ED608780003C06551CFFFFE60F41C1C67064DFAFFFA60C64ED509 +S224FE2CC07807E99D7C0FCC050C060009630406060007060600304DFA000460A851CCFFE46C +S224FE2CE04ED50514051C05248002052C0534056405240524800B053C8006054C0554800E1A +S224FE2D000544055C800F053C0000070D0A455843455054494F4E3A202000070D0A204E4F14 +S224FE2D20204D656D6F72792061743A20000D0A4C6F616420446F6E6500070D0A4261642026 +S224FE2D404C6F616420436861726163746572000742616420436865636B73756D0007447225 +S224FE2D60697665204572726F722000074E6F7420424F4F54204469736B00206F6E20647298 +S224FE2D80697665200007424144204D656D6F7279206174200052414D2053697A65203D2038 +S224FE2DA000206973200020696E7374656164206F6620000D0A534147452049562053746199 +S224FE2DC0727475702054657374205B322E315D0D0A00426F6F74696E672066726F6D2046D9 +S224FE2DE06C6F7070790050757420696E20424F4F54206469736B20616E64207072657373AD +S224FE2E002061206B6579202851202D207175697473290007426F6F742041626F72746564E4 +S224FE2E20002028546573742041626F727465642900202046696C6C696E67206D656D6F7258 +S224FE2E40792E2E2E0020204C6F6164696E672E2E2E00202057726974696E672E2E2E002016 +S224FE2E60204D6F76696E67206D656D6F72792E2E2E000750524F4D2031204261640D0A00A8 +S224FE2E800750524F4D2032204261640D0A00427970617373656420496E69740D0A004C6F99 +S224FE2EA06F7065642054657374730D0A0052414D207772697465206C6F6F700D0A00426F50 +S224FE2EC06F74696E672066726F6D204861726420447269766500436F756C64206E6F7420B9 +S224FE2EE066696E64200057616974696E6720666F72204472697665205265616479203C51F8 +S224FE2F002D71756974733E000D0A4E6F204D6174636820666F756E640020205365617263C2 +S224FE2F2068696E672E2E2E000D0A4D617463682061742000202D20436F6E74696E75652073 +S224FE2F40736561726368202843203D20596573293F200000001F0027002B003300470052FA +S224FE2F60005C006A007A008F204572726F722061742000556E6B6E6F776E004275730041E5 +S224FE2F8064647265737300496C6C6567616C20496E737472756374696F6E00417269746835 +S224FE2FA06D657469630050726976696C656765005265736572766564205452415000556EFB +S224FE2FC061737369676E6564205452415000556E61737369676E656420496E74657272752F +S224FE2FE070740052414D205061726974790046756E6374696F6E3A200020204163636573B2 +S224FE3000733A20002020496E73743A20000303D1070207000108024A00006100000C423885 +S224FE302001C250F801BB4E7548E71C0011FC0000C50708F80000C5037080740011C0C5C15C +S224FE3040723251C9FFFE7A0411FC00B0C60711FC0000C60511FC0000C605323C174051C91B +S224FE3060FFFE11FC0080C60776001638C605E15B1638C605E15B444386FC000C31C301F2DA +S224FE3080967801F067226E1244430C4300026F185202671C530066A460160C4300026F0854 +S224FE30A05202670C520060EE51CDFF9E50F801BB11C001EF11FC0001C507303C174051C870 +S224FE30C0FFFE4CDF00384E75223801D67000103801B934004841B2406200006E484182C0DD +S224FE30E04841303801B0C4C0C0C142414841944048C231C001E8203801DAB4806D0C9440AE +S224FE310031C201EC31C001EA600831C201EA427801ECD27801BC6530B27801BE622A43F8B7 +S224FE3120020030196708B2406504524160F431C101E27000103801B882C031C101E44841A8 +S224FE314031C101E642004E7511FCFFF501C34E7511FCFFF201C34E752F02343C07D00838C9 +S224FE31600001C58167305342672611FC000CC58772016100011C4A3801C366000092701434 +S224FE3180484008380000C58167D45380670260F270FD6000007611FC000DC587720A6100CF +S224FE31A000F04A3801C3660000667014484008380000C5816706538067D660F20838000168 +S224FE31C0C58167CC343C07D008380001C5816728534267BC11FC000CC5877201610000B273 +S224FE31E04A3801C366287014484008380000C58167D65380679A60F2303C251C51C8FFFE40 +S224FE32004200427801C050F801C211C001C3241F4E7508380000C58166604A3801C266064B +S224FE32206100FF3666521038C585020000F8807801E611C0C585323801C0927801E4673204 +S224FE32406E0A444111FC000DC587600611FC000CC5876100003C4A3801C3661C72FFE0196E +S224FE326008380000C58157C9FFF6660E31F801E401C0700011C001C34E7570FD60F610389A +S224FE3280C583020000F0803801BA11C0C5834E7548E7E000E349534111FC0036C60711FCB6 +S224FE32A000B0C607303801B211C0C601E04811C0C601741851CAFFFE11C1C605E05911C1CF +S224FE32C0C605741851CAFFFE08B80000C503343C08EC51CAFFFE720C484111FC0080C60717 +S224FE32E01038C605E1581038C605E158670C6B0A538166E611FCFFFD01C308F80000C50396 +S224FE33004CDF00074E7543F8C7C1247801DE08F80007C50311FC000FC50711FC000DC507DA +S224FE332011FC000CC5074A114A1111FC0003C78311FC0041C7851011E148101131C001C4DA +S224FE3340343801E8670853424A1151CAFFFC343801EA534214D151CAFFFC343801EC6708F1 +S224FE336053424A1151CAFFFC4A114A1108380000C7836610303801C4B07801E2660E423868 +S224FE338001C34E7511FCFFF801C34E757400143801B880C231C001C011FCFFF401C34E7524 +S224FE33A011FC0002C50711FC0008C50708F80006C50308B80007C50311FC000DC50711FCFE +S224FE33C0000CC50711FC000EC50711FC0030C60711FC0070C607303801B411C0C601E048FA +S224FE33E011C0C601303801B611C0C603E04811C0C60311FC000BC50711FC000AC50708F8F0 +S224FE34000001C50370FF08380004C58156C8FFF8660611FCFFFA01C308B80001C50311FC06 +S224FE34200008C50708F80006C50311FC0005C50708F80007C50311FC000FC5074E75225F0E +S224FE344021DF01DA21DF01DE21DF01D62F096100FE2E4A3801BB66046100FBC011FC000A38 +S224FE346001EE423801C308380005C581660000564A3801BB66046100FBA24AB801DA6700EB +S224FE348000AA6100FC44660000426100FD864A3801C3660000366100FF084A3801C366005C +S224FE34A0002A6100FE62660000227000303801EAD1B801DE91B801DA80F801B048C0D1B88D +S224FE34C001D6609811FCFFFC01C3533801EE6F00005A103801C30C00FFF967260C00FFF86B +S224FE34E067200C00FFF7671A0C00FFFA67100C00FFF4660000360C38000301EE6C04423888 +S224FE350001C2303CFFFF51C8FFFE523801FF103801FF0200001F670A0C38000501EE660063 +S224FE3520FF426100FB046000FF3A1038C583020000F011C0C583103801C34E75225F261F1E +S224FE3540321F700003C011C001BAE90911C101F42F09423801BB11FC000101B811FC00134A +S224FE356001B931FC020001B031FC004001B431FC004801B631FC177001B242780200427883 +S224FE358001BC427801BE6100FCF6722F484108380005C581673441FAF94E6100CE706100CD +S224FE35A0CE48600808380005C581671E6100CF46670A6100CF480C0000516704538166E435 +S224FE35C011FCFFFC01C36000FF6270FF08380005C58156C8FFF86700001248410C41002FCE +S224FE35E057C048414A0066AE60BA42A741F804002F08203C000004002F006100FE426600BD +S224FE3600FF2A7010B6806D2E204343F8060076002211B290660A22290004B2A80004671604 +S224FE3620D2FC00205243B67C00106DE411FC000101C36000FEF6873801F4E54B41F804002A +S224FE364031F0300001BC31F0300201BE11E801F601B911E801F701B831E801F801B031E817 +S224FE366001FA01B431E801FC01B631E801FE01B2D0FC004043F80200701F22D851C8FFFC19 +S224FE36806000FEA82C5F11EF0004010508F800010105422F00046100CFC446FC270011FCA6 +S224FE36A00025C073423801046100CD3E41FAF8106100CD5A6100CD326100FE82665242A717 +S224FE36C0307C04002F082F086100FD74661C307C04000C58424F662E0C584F546628700037 +S224FE36E0103801F43F002F0E4ED06100CCFC103801C3440041FAF6676100CD126100CD1C55 +S224FE37006100CCE64ED641FAF6636100CD0060F00C38000101C366D26100CCCE41FAF7B837 +S224FE37206100CCEA41F801F66100CCE260D2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +S224FE3740FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 +S224FE3760FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 +S224FE3780FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 +S224FE37A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 +S224FE37C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 +S224FE37E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 +S224FE3800FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 +S224FE3820FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +S224FE3840FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 +S224FE3860FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 +S224FE3880FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +S224FE38A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +S224FE38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +S224FE38E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 +S224FE3900FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 +S224FE3920FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 +S224FE3940FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +S224FE3960FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +S224FE3980FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +S224FE39A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +S224FE39C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +S224FE39E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +S224FE3A00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +S224FE3A20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +S224FE3A40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +S224FE3A60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +S224FE3A80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +S224FE3AA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +S224FE3AC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +S224FE3AE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +S224FE3B00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +S224FE3B20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +S224FE3B40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +S224FE3B60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +S224FE3B80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +S224FE3BA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +S224FE3BC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +S224FE3BE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +S224FE3C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +S224FE3C20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +S224FE3C40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +S224FE3C60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +S224FE3C80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +S224FE3CA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +S224FE3CC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +S224FE3CE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +S224FE3D00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +S224FE3D20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +S224FE3D40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +S224FE3D60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +S224FE3D80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +S224FE3DA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +S224FE3DC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +S224FE3DE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +S224FE3E00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +S224FE3E20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +S224FE3E40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +S224FE3E60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +S224FE3E80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +S224FE3EA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +S224FE3EC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +S224FE3EE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +S224FE3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +S224FE3F20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +S224FE3F40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +S224FE3F60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +S224FE3F80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +S224FE3FA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +S224FE3FC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +S224FE3FE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +S804FE0000FD diff --git a/SAGE/FILES/sim2bin.c.txt b/SAGE/FILES/sim2bin.c.txt new file mode 100644 index 00000000..e28d611b --- /dev/null +++ b/SAGE/FILES/sim2bin.c.txt @@ -0,0 +1,29 @@ +#include +#include + +int main(int argc,char* argv[]) +{ + FILE *in,*out; + unsigned int n,i; + unsigned int c[16]; + char buf[101]; + + if (argc != 3) { + fprintf(stderr,"Usage:\n\t%s txtfile binfile\n",argv[0]); + exit(1); + } + + in = fopen(argv[1],"r"); + out = fopen(argv[2],"wb"); + + while (!feof(in)) { + fgets(buf,100,in); + sscanf(buf,"%x: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + &n,c,c+1,c+2,c+3,c+4,c+5,c+6,c+7, + c+8,c+9,c+10,c+11,c+12,c+13,c+14,c+15); + for (i=0; i<16; i++) fputc(c[i]&0xff,out); + } + fclose(out); + fclose(in); + exit(0); +} diff --git a/SAGE/FILES/system.imd b/SAGE/FILES/system.imd new file mode 100644 index 00000000..b905e011 Binary files /dev/null and b/SAGE/FILES/system.imd differ diff --git a/SAGE/FILES/ucsd.sim b/SAGE/FILES/ucsd.sim new file mode 100644 index 00000000..114647a6 --- /dev/null +++ b/SAGE/FILES/ucsd.sim @@ -0,0 +1,15 @@ +set cpu debug=int +set cpu debug=exc +set cpu 512k +set debug debug.log +break fe1ad6 + +set fd debug=verbose +set fd debug=cmd +;set fd debug=seek +;set fd debug=irq +;set fd debug=state +set fd debug=status +set fd debug=rddata +att fd0 system.imd +boot cpu diff --git a/SAGE/FILES/v2-04.hex b/SAGE/FILES/v2-04.hex new file mode 100644 index 00000000..57b6a077 --- /dev/null +++ b/SAGE/FILES/v2-04.hex @@ -0,0 +1,514 @@ +S00C000076322D30342E68657853 +S224FE00000000040000FE0044600004F8600004EC600009646000044E600003F8600003D0DE +S224FE0020600003FE60000404600029A8600029AA6000033AF58A0204600002FC6000344C30 +S224FE0040600037144E704FF8040011FC0092C02711FC0038C02511FC0092C06711FC003135 +S224FE0060C065700072FF343C42D741F8C0FE3080308151CAFFFA43F8000045F87FFE343C1D +S224FE0080344230113010301251CAFFF8343C06C541F8C00172084A10D0FC001051C9FFF81C +S224FE00A051CAFFEE43FA0006600002C649FA2D0B4BFA000660002C0441FA00362278000861 +S224FE00C021C80008B1F80008662E11FC0090C58711FC0090C50711FC0000C58311FC00CD66 +S224FE00E0C50311FC0000C58511FC0005C50560044FF8040021C900081038C0216B64E6087B +S224FE010002400006303B00064EFB000200180024001800084238010449FA2DB74BFA085831 +S224FE012060002B9849FA2DBB4BFA003860002B8C49FA2DBE4BFA000660002B8074FF720071 +S224FE014070001038C023460008000002670272FFE308024000064840204030C151CAFFFCB5 +S224FE016060DA41FAFE9C343C1FFF42004201D018D21851CAFFFA4A00671449FA2D394BFAC1 +S224FE0180000660002B364A38C0216A0001004A01671449FA2D2F4BFA000660002B1E4A38EC +S224FE01A0C0216A0000E811FC0001C067307C000072014841323CFFFE224145FA00066000B9 +S224FE01C02A3A664647FA000C21CB000808F80002C5034FF8040047FA002421CB00087202E9 +S224FE01E04841D3C1303CA5A53280B051660E46403280B05166064640D3C160EC4FF80400AC +S224FE020093C145FA0006600029F267084A38C0216A00007A303C00BF41F80100429851C8B9 +S224FE0220FFFC548921C901004E6121C9014A21C9014243FA000C21C9000808B80002C50322 +S224FE02404FF804006100041C11FC0000C0674A38C0216B1611FC0007C06770FF51C8FFFEF7 +S224FE026011FC0006C0676000FEFA6100018241FA2B2B6100019E30380100ED486100021C57 +S224FE0280704B610001E06100016660044E7227007228740208380006C0216702725011C216 +S224FE02A001C611C101C7423801CA11C201CE11C101CF11FC000101D27206610000FE42381F +S224FE02C001BA2278000841FA003021C8000811FC00AAC58311FC0005C5050C3800AAC58351 +S224FE02E0661611FC0000C58350F801BA31FC027001F011FC008001F54FF8040021C90008D7 +S224FE03001038C021C07C0030670CB07C00206724B07C0010672621F80100014A21F80100B3 +S224FE0320014231FC2700014E41FA004221C801466000064442676100280860DA4A3801BACC +S224FE034067D4203801004840720C92406F12C2FC000A5341303C6F9A51C8FFFE51C9FFF6B7 +S224FE0360426770012F006100356A60AA4E4F60FC41F8C0734200108011FC0076C007E018AE +S224FE038010801238C021E0181080706E080100036702707E10BC00400241000711FB101450 +S224FE03A0C003108011FC0000C003E01810BC00254ED1028040201008040241F8C033424061 +S224FE03C0108011FC00B6C007E018108011FB10E4C005E018108011C0C005E01810BC004091 +S224FE03E0E01810BC004EE01810BC00274E752F00700D6170700A616C4200616861666164DF +S224FE040061626160201F4E752F0070206156201F4E753F0010186704614A60F8301F4E75F4 +S224FE0420E9186126E91861224E752F017203E958611851C9FFFA221F4E752F017207E9984A +S224FE0440610851C9FFFA221F4E753F000200000FB03C0009630406000007060000306104C5 +S224FE0460301F4E754A380104662C3F01323CFFFF08380002C07356C9FFF8670811C0C071A6 +S224FE0480321F4E7548E7C0C043FA00066000FEE24CDF030360D64E4A4E7548E7F0007200C0 +S224FE04A032007400343C2710420382C266044A0367061001619450C34241484184FC000A90 +S224FE04C066E84CDF000F4E754A38010466282F011238C0730801000167F61038C071020129 +S224FE04E000386604221F4E7511FC0035C07370076100FF7260DA4E494E7508380001C0738D +S224FE05004E7561C4088000070C0000616D0A0C00007A6E04088000054E7521C001067002DB +S224FE0520604E21C001067004604621C001067006603E21C001067008603621C00106700AB4 +S224FE0540602E21C00106700C602621C00106700E601E21C001067010601621C001067012F4 +S224FE0560600E21C001067014600621C00106701648F87FFE010A4E6821C8014A2A00701668 +S224FE0580BA806270BA3C00046206381F261F341F31DF014E21DF014621CF01424FF80400D7 +S224FE05A00C0500146700199A6E0018B80C050012661E11FC0001C06711FC0000C0674A3829 +S224FE05C001BA670C08F80002C50308B80002C50370FFE01851C8FFFC46FC270011FC00386D +S224FE05E0C02508B8000601504238010443FA000A6000FD7E428560A849FA27164BFA0006C1 +S224FE0600600026B849FA2990D8F450004BFA000460EE49FA29964BFA000460E420380146BC +S224FE0620610017F66100FDC80C0500046200034841FA29FE6100FDDC30046100FDEE41FA0A +S224FE064029FB6100FDCE20036100FDF041FA29F86100FDC030026100FDD26100FD926000AA +S224FE0660031641F8000843FA268045FAF9944280301967186B06D08A20C060F24241120052 +S224FE06803019D08A20C051C9FFFC60E24E75225F02800000000FD080D089C1893251D3C09F +S224FE06A04ED148E780B02478000847FA001421CB0008101121CA00084CDF0D01B0004E750C +S224FE06C0508F321F46C141FA26586100FD46588F20096100174421CA00084CDF0D0100008B +S224FE06E000014E7508380001C0734E752F00703A6100FD72201F6100FD104E752F00702C18 +S224FE07006100FD62201F4E752F0070076100FD56201F4E75C03C007F0C0000206D060C0092 +S224FE0720007E6D02702E4E752F092F01224842816100FDD00C00001B6700006E0C0000128B +S224FE0740670000680C00000D674A0C000008661AB3C867DC6100FD0E6100FCAE6100FD06D0 +S224FE076051C9FFF25389528260C40C00007F6614B3C867BC61585389528210116100FCE627 +S224FE0780544160AC611A428153826B0812C06100FCD4609C610A421912C0221F225F4E7513 +S224FE07A08281673C4281602C224842812F0870236100FCB26100FC38B3C86700000C101890 +S224FE07C06100FCA2B3C866F6205F6000FF648281660E72013F00103C005C6100FC88301FF9 +S224FE07E04E75428010188000660253884E7561F28000670A0C00002067040C00002C4E75ED +S224FE080061E067080C00002067F653884E7561D2244942411219B011568957C9FFFA660091 +S224FE082001481021E1581021D4C04ED248E7180042817801E89C61B667540C00002F660E95 +S224FE0840383C33334844383C333461A26740040000306D380C0000096F144A04662E040053 +S224FE086000070C00000A6D240C00000F6E1E26014A046708E799E39BD2836002E999B684CB +S224FE0880640AD280848267C2B48164BE72FFC1414CDF00184E752F036100FF66428395CA7A +S224FE08A06100FF4C670000480C00002367360C0000246708347801525388602A6100FF307B +S224FE08C06700002C0400003065240C000003641E244093C96100FF18670000180C00002B46 +S224FE08E0660C6002528342826100FF42670257832240D5CAD5CAD4FC0154D3D2201FC143F6 +S224FE090080804E752F0242826100FEF6670000520C000027671C0C00002E674624016100EB +S224FE0920FF0C6B06241F92814E75241F428153814E756100FEAE6100FEAA670000200C00D9 +S224FE094000276712E19A4A0266E0D480828167E6B28264E260D46100FE9666CEC14260C445 +S224FE09607001241F22004E756100FA9E703F6100FAF46100FD944FF8040042B801546100F7 +S224FE0980FA6E0838000601506700000870546100FAD436380152670C70246100FAC81003F5 +S224FE09A06100FAA8703E6100FABC742841F801886100FD7643FA1A686100FE5460B843FA73 +S224FE09C01A8C6000FE4A6100FE382838017E387801821010670E6100FEBE668C2809284AD6 +S224FE09E031CA01826100FE1A327C01001010670A6100FEA46B00FF726704D3C45389528925 +S224FE0A0021C9017E2A09611C6718280B6100FCD667F46100FAEE0C00001367F60C000003A6 +S224FE0A2066E44E756100F9C820046100FA0EB8FC0154670C6100F9D2200490946100F9FCB1 +S224FE0A406100FCAA760F2644C7496100FC56C7496600FF16101B6100F9C808030000660091 +S224FE0A6000066100F9A4BA8B57CBFFDE6100F99A760F2644101B6100FC9C6100F9E8BA8B9D +S224FE0A8057CBFFF24E7543F80154323C20247402601443F80126323C2041600843F8010676 +S224FE0AA0323C204474076100FD3A671A903C00306B00FEB678001800B8026E00FEAC6122CD +S224FE0AC06100F92C4E754284611852846100F93A0C04000466046100F9306130B8026DEA77 +S224FE0AE04E756100F90A42833001E0880C000020670000066100F96E10016100F968868331 +S224FE0B00660610046100F9446100FBE22004E5800280000000FF4A836A4230310000610031 +S224FE0B20F90A0C415352663C48E7704036006100F8D870286100F92E428243FA18D214199D +S224FE0B40670E1019E57B650270206100F91860EE4CDF020E70296100F90C600820310000EA +S224FE0B606100F8D84E756100FC7A6600FDFC6100FF226100FF2861186108614861046134B9 +S224FE0B804E756100F8846100F8804E756000F86061FA103C00506100F8CC103C0043610052 +S224FE0BA0F8C46100FB4820380146307801526000126861D876FF43F8014E223C0000535223 +S224FE0BC0600E61C843F8014A223C00005553760142846100FF144E757C0060000C2C7000F7 +S224FE0BE072104A10670A6100FC446B00FD7C12006100000E5200B0016DF66100F7F24E752C +S224FE0C006100F7EC41FA00206100F8086100F83C41FA001B3438017C0102670441FA001B39 +S224FE0C206100F7F04E755452415020230020204E6F207472616365200020205472616365B1 +S224FE0C4020202020000043FA18A26000FBC26100FCB46600FD142A006100FCAA6600FD0AD7 +S224FE0C602800D0856100F7882200103C002B614822059284103C002D613E2205C2C4103C84 +S224FE0C80002A61344A446746220582C4103C002F61186132103C00726100F7CA103C0065D2 +S224FE0CA06100F7C2103C006D48416100F7B86100FA3C30016000F7746100F7AA6100FA2EA7 +S224FE0CC020016100F7766100F7406000F73C4E757C106100FB2C2838017E387801821010EE +S224FE0CE067106100FBB26600FC802809284A31CA01826100FB0C327C00141010670C7CFF31 +S224FE0D006100FB946B00FC6267062C096B00FC5A52892A092C446100F6D6200E6100F71C67 +S224FE0D20B8FC0154670C6100F6E0200E90946100F70A6100F9B848E7060061304CDF0060E6 +S224FE0D4021CE017E4A866B065386671E2A0EBA8E650000186100F98E67BC6100F7A60C0071 +S224FE0D60001367F60C00000366AC4E75300EE2086500FBF67C07610006F03E00E9586100E4 +S224FE0D80F90E0020010001080104014003880428046E0512060606CC053A05A6060606526D +S224FE0DA006CC08070008664E43FA176C3207E049E249610006F659016F5E040100106758EE +S224FE0DC0580166064245611C60063A07610006C4610006FC6100070216076100F9206100B0 +S224FE0DE007364E75428543FA171E3207EC5902410003600006B63007020000380C00000852 +S224FE0E0067367042610006AE61DA610006C23607EC5B6100072860C030070200003F0C004F +S224FE0E20003C66A64282263A084C080700066704263A0846600000F2203A082A6100067606 +S224FE0E407050610006703A07E35D08C500066100064E6100067A08070007670A61126100B3 +S224FE0E60F89C61144E7561106100F89261024E753607EC5B600006C6360708C30005600004 +S224FE0E800696428560067A4060027AFF203A07D6610006223007EC580200000753006606EE +S224FE0EA0704161000610610005F6610006223607610006646100F8463607EC5B610006642C +S224FE0EC04E7508070008660002043007EF580240000732006100F7B8001000320014001C4E +S224FE0EE0007C011800B201527401600A263A0786428260064282263A0780283A07683007AC +S224FE0F00020000C00C0000C0671843FA16366100059A3A076100057C610005B4610005F69F +S224FE0F204E7520046100058E7A40610005A228034A026614610005DE4A84670A6100F7BE87 +S224FE0F402004610005704E7561F66100F7B0610005C44E753207E6590241000708070007AD +S224FE0F606624203A071808070006670C203A07124A016604203A070E6100053A61000550F6 +S224FE0F80610005924E754A016756203A06D861000524704D3A07E35D08C50006610005163C +S224FE0FA0610004FC610005287A40610004BC31C001880807000A661E6100000C6100F73E4A +S224FE0FC0610005524E7570236100F49A303801886100F4584E7561E86100F72261E84E75E1 +S224FE0FE0203A06AA08070006678E203A069C60880C0700FC6612203A0698610004B8203A00 +S224FE10000694610004B04E753A07024500C00C4500C0670A3005E2588A406000FEEE283AAA +S224FE10200678428242836000FED608070007660000983207E6590201000714010C010006B4 +S224FE104067520C0100036F14263A065E024200010247000F004700C86000FEA043FA14FC86 +S224FE10606100044861000468E20A660E70236100F3F430076100F3D44E753607E75B6100B6 +S224FE108004C008070003660A6100F6727A40610004484E75320702410007340143FA14CC3F +S224FE10A0610004080C020002660A610004227A406100042670544A02670870560C0200061B +S224FE10C066046100F3A04E754280600270023207EC59C27C0001D2407A4043FA14AE61006D +S224FE10E003CA610003EA6100042C0807000867186100F60A3607EF5B7020080700066702B5 +S224FE11007028B143610004104E753207020100C00C0100C0673E203A058808070008670431 +S224FE1120203A05826100038E3A07610003666100039E70236100F32E3007EF580200000730 +S224FE11404A00660270086100F3026100F5B0610003C44E7570533807020400380C040008C3 +S224FE1160660808870003303C4442611C610003A60C04000866106100F5847A40610003600D +S224FE11803440610003FA4E7543FA1440610003263207EE5902810000001ED3C142803011E4 +S224FE11A061000312610003284E757A40320702410F000C410100670A704243FA13EE61CC46 +S224FE11C0600C203A04D8610002EC6100030230074A0067106100F24AE158E040548E61087C +S224FE11E0558E4E75610002F83440610003924E750807000866000258203A046A610002B606 +S224FE12007051610002B0610002C670236100F25610076100F20C6100F4E43607EC5B6100FE +S224FE1220031C4E753A0743FA13C2612208070008670C61106100F4C6610002DA4E7561F884 +S224FE12406100F4BA3607EC5B610002F24E753207E95902410007610002524A45670461000B +S224FE126002326100026A4E75428560023A0743FA139A61DA3607E75B61086100F48036071E +S224FE1280EC5B080700036606610002B24E75610002C04E753007024001F00C40010067C8E2 +S224FE12A0EC4872045740670859406600FF787205088700068E7C41006000FE1E3007EC58B7 +S224FE12C00240000755406F00FF5C43FA133E7A4053406706E35D594066166100FF72610093 +S224FE12E002346100F4183607EC5B610002544E75044710003007024000380C400008660084 +S224FE1300FF24203A03A8610001AC3A0761000184610001BC3607E75B61086100F3E03607F6 +S224FE1320EC5B610002264E753007024001F878000C400140671078030C4001486708780230 +S224FE13400C4001886624203A0368610001686100017E3607EC5B61086100F3A23607E75B5A +S224FE1360E21C650001DC600001D4E8480C0000106700FEF67206E44857406700FF34720700 +S224FE1380594067F66000FE9E3007024000C00C4000C067123007024001300C40010067003C +S224FE13A0FECC6000FE803A07E25D43FA12563207E55902410001610000F2610000E26100AB +S224FE13C0010E610001506100F3343607EC5B610001704E7532073A07024500C00C4500C016 +S224FE13E06744E6596150610000AA610000E2360702430E00080700056708EC5B6100013E07 +S224FE1400601670236100F05E3003EF580200000F660270086100F0346100F2E23607E75B6D +S224FE14206100011A4E75EF59610C4285610000A0610000E24E750241000334070242010021 +S224FE1440EC5A824243FA11DC610000604E75702E61000062203A02126100005A6100007076 +S224FE146030076100EFC64E752F09224E6100F2346600F4F6301E225F4E752F09224E61003F +S224FE1480F2226600F4E454896100F218201E225F4E75024500C00C05008066027AC03205BC +S224FE14A0EC590201000343FA108AE519024100FF203110002F017203E1984A00670000088F +S224FE14C06100EFA2530651C9FFF0221F4E756100EF3851CEFFFA4E7570236100EF883205AC +S224FE14E0EC59C27C0003B23C000267206100FF7A53016C066100EF2A4E756100EF2E53013D +S224FE15006D086100FF646100EF224E75703F6100EF544E7536071003E60802000007E70B0B +S224FE152086001003024000076100F164001000140018001E00240076008000C672446014AC +S224FE154072416010223A0112600A223A01106004223A010E7403E1991001671C6100EF0675 +S224FE15600C00004467060C000041660C3003E618020000076100EED451CAFFDC4E75705B0B +S224FE15806100EEE2D5CE200A558030780152D1C8D1C890A801546100EEA2705D6100EEC6E8 +S224FE15A04E756100FEC46100EE8260986100FEBA38006100EE6C70286100EEAA6182610098 +S224FE15C0F13C3604EF5B0804000F66066100FF6E60046100FF6C702E6100EE8A7057080488 +S224FE15E0000B6702704C6100EE7C70296100EE764E75E61BC63C000710036100F0920012BA +S224FE1600001C0026003E00540010001000104E756100FE566100EE144E756100FE5E610007 +S224FE1620EE1A4E756100FE4234406100EDFE223A003C6100FF206100FF464E756100FE2A71 +S224FE164038006100EDDC203A00286100FE686000FF6E6100FE844E75284129002841292B1A +S224FE16602D2841294D4F5645574F5244285043292850430043435200535200004E42434402 +S224FE168050454100535741504558544C45585457494C4C4547414C005441530042535200E8 +S224FE16A0414444515355425155535000434D504D4558470043FA0DB56000F1546100F1D8FB +S224FE16C06600F2A660046100F0402809284A2A0454856100F3506100F01441F80188243C3F +S224FE16E0000000286100F042428110106716223C0000FFFF6100F20E6BCC6E0A134000010C +S224FE1700E080128054890C01002E66BE4E7543F80154323C202474037A01601643F80126C9 +S224FE1720323C2041600843F80106323C2044740842856100F0AE671A903C00306B00F22A15 +S224FE1740B0056B00F224B0026C00F21E4282610E4E75200561085280B0026DF84E7542832D +S224FE17602F023A0128002C00E5864A82660E6100F0904A10662260046100EF8E320561005E +S224FE1780EC6E6100F3646100EF64742841F801886100EF961010672042816100F1686BD8D5 +S224FE17A0660000160286000000FF86836A063380600060042380600032051004241F4E75DF +S224FE17C06100F0206600F1A26100FF526100FF586106611E610E4E7543F80146323C504397 +S224FE17E06000001843F8014E323C535276FF6000000C43F8014A323C555376014282428057 +S224FE18006100FF5E4E757CFF7A0142806100EFD467144486903C00306B00F14EB03C000190 +S224FE18206E00F1463A00360060046100EEDC3643D7CB284BD7CB4A866B0A675A6100EFC2B9 +S224FE18404A106614616A6100EEA4742841F801886100EED66100EFAA101067320C00002E83 +S224FE1860660607B8015060266100F02C6BBC6100EF90243C0000FFFF6100EFB26BAC426CBA +S224FE188001723940017607F80150274901605243B6456F9A4E75611860F4427265616B7043 +S224FE18A06F696E742000496E61637469766500006100EB3C41FAFFE46100EB58100361005A +S224FE18C0EB8A6100EE2807380150660A41FAFFD86100EB404E75202B01606100EB5E610001 +S224FE18E0EB2870286100EB7E302C01766100EB3C6100EE0A302C01726100EB307029610077 +S224FE1900EB644E75760078104A10671C6100EF1E6B00F056160018006100EEE60C000054F5 +S224FE192067460C00004E67386100EAC441FA004C6100EAE010036100F2C86100EDB0742875 +S224FE194041F801886100EDE26100EEB667240C00005467140C00004E67066100EDAC60C83E +S224FE19603238017C078160063238017C07C131C1017C5203B6046DBC4E752854297261639B +S224FE198065206F7220284E296F2074726163650043FA0AF86000EE78243C000000FF616C50 +S224FE19A06600EFC61A00E1401005600C243C0000FFFF61586600EFB23A00484030056008D0 +S224FE19C0428261486600EFA241FA14AA6100EA4461000942E19812C0538466F821CA0008F9 +S224FE19E04E7548E7F0006100EEAE661A28096100EEA62449C9896B0E6E0698895284600458 +S224FE1A00D5C9538A42804CDF000F4E7561D4660622026100EEF04E7561F266142C009887AA +S224FE1A206D00EF4670FF4A10670A22026100EED66600EF3641FA15266100E9D8610008D61C +S224FE1A404E7543FA0AB46000EDC6243C000000FF7E0161C41219C200B206670453846CF468 +S224FE1A606100009660F6243C0000FFFF7E0261A81219E1991211C240B246670453846CF0CF +S224FE1A806100007660F642827E04618C2649548B1219E1991211E199121BE1991213C28045 +S224FE1AA0B286670453846CE86100004E60F66100FF326600EEB448E708606100FF26660033 +S224FE1AC0EEA82A492C044CDF0610C34D41FA148E6100E9406100083E9C8465182849528982 +S224FE1AE02E04264D121CB21B6606538766F6610853866CE861024E7148E7FE7E663E41FA5F +S224FE1B00146B6100E90E538920096100030C6100EBDC7203E198101951C9FFFA6100E91CBE +S224FE1B2041FA14556100E8EC6100E9D80C00004366126100E9304CDF7E7F4E7541FA140D1F +S224FE1B406100E8D04CDF7E7F21CA00086000EE286100E8B66100E8B243FA093A6000ECB062 +S224FE1B6043FA093C6000ECA86100ED2C6600EDFA20096100E8C66100EB7410116100E8A221 +S224FE1B804E756100ED126600EDE03C09080600006600EDD620096100E8A26100EB5030117F +S224FE1BA06100E8884E7543FA08FD6000EC626100ECE66600EDB4223C000000FF6100ED4673 +S224FE1BC06600EDA612804E756100ECCC6600ED9A3C09080600006600ED90223C0000FFFF1C +S224FE1BE06100ED226600ED8232804E756100EC1274076100EC386B00ED7022006000E7BCDC +S224FE1C0043FA08AA6000EC086100006443FA07B654894A516700ED523014C059B05966F0E5 +S224FE1C20D8D121CC016808F80002015008F800040150600261387401610001BA426A01724F +S224FE1C4051CAFFF66002612608B80005015008F80006015008F80007015010380150020028 +S224FE1C600007660608B800060150600001506100EB901010670C6100EC1E6600ECEC21C924 +S224FE1C80014661066100E7684E752C380146284608060000671241FA001C6100E776200645 +S224FE1CA0610001766000ECD0224C6100E9F66600ECB84E75496C6C6567616C2070726F6720 +S224FE1CC072616D20737461727420616464726573733A20006100E71843FA07DC6000EB3018 +S224FE1CE0083800060150670461A0604E4E7508F8000501506040619208B8000301500C1054 +S224FE1D000049660808F80003015052887005083800050150660270104A10670E747F6100C5 +S224FE1D20EAE06100EB086B00EC406100E6C2600C08B8000501506100FF36700111C0015136 +S224FE1D4008F80006015008B80007015030140240FFF00C404E406664301C0240000F3C38E7 +S224FE1D60017C41FA002C0106661C21CC016808F80007015008F80002015008B800040150DD +S224FE1D80673A41FA00216100E68A6100E662602C2A2A2A2054726163696E67205452415080 +S224FE1DA0202A2A2A002A2A2A204753207465726D696E61746564202A2A2A00002878014678 +S224FE1DC03C38014E08380006015066060886000F600408C6000F2078014A4E602E780142E2 +S224FE1DE02F0C3F064CF87FFF01064E7308B8000601504E7542803242D3C92449D3C90538E4 +S224FE1E000150670E226901606100E8986600000652804E7553804E756100E6203078015233 +S224FE1E20D0C8D0C84A780152672E6100E5DC2F0070286100E63070246100E62A30380152A5 +S224FE1E406100E6086100E8A6201F90A801546100E5EA70296100E60E4E7554726163653A6B +S224FE1E6020000838000601506700FF52083800070150672608B80006015074006100FF766A +S224FE1E806B00EAE667083551016C32BC4E4F52420C42000366E66000FF2441FAFFBE203813 +S224FE1EA0014621C0017E6100E56A28406100FF6AD0FC015431C801826100E832224C6100AF +S224FE1EC0E7E2661430116100E5626100E53C6100E5382C496100EE96083800050150670A72 +S224FE1EE041F8018842106100EC7E533801516F1E083800030150671A6100E7EA6714610073 +S224FE1F00E6020C00001367F60C00000366046000EA666100E4DA6000FE280D0A556E6578D5 +S224FE1F2070656374656420627265616B20706F696E743A2000000D0A427265616B3A20000A +S224FE1F4042854286283801465584760041FAFFCC74026100FEA06F32B3C4661E41FAFFD8D0 +S224FE1F6076020C02000267123A2A01723C2A0176BC4567065245354501720C514E4F670650 +S224FE1F8005B80150600432AA016C51CAFFC60838000201506728B8B80168662208B800025E +S224FE1FA0015008B800040150661421C4014608F80006015008B8000701506000FEA6203847 +S224FE1FC00146908321C00146BC456600FC824A436600FED028440C544E4F6600FEC620041F +S224FE1FE06000FEC043FA04E46000E82411FC000101BB6004423801BB41FA0E8E6100E4149B +S224FE20006076428574016100E8246B00E95C3C00243C0000FFFF6100E8146B00E94C3F00B8 +S224FE20206100E8746600E9422F0942826100E7FE6B00E9362F003F064A85670E41FA0E572B +S224FE20406100E3D061000992600C41FA0E3C6100E3C26100097E6700000E41FA000C610071 +S224FE2060E3B26100E3BC4E750D0A4469736B206572726F723A20000061740C000051670026 +S224FE208000C00C00005366F0420561621E00610000BC1C0153064281610000B2610000AE28 +S224FE20A026410C070030660E4A0667066100009E60F6617460C20C0700326614220B6100A9 +S224FE20C0008C26414A0667EA6100008216C160F40C07003167EE0C07003966644A06666096 +S224FE20E0614641FA0C4F6100E32A6000E88A4A3801BB672408380001C033670A1038C031B9 +S224FE2100088000074E756100E3F267E26100E3F40C00005166D84E756100E3AE0C00000D4A +S224FE21206700E2CC6000E33E6122460566024E75588F41FA0C216100E2DA6000E83A508F40 +S224FE214041FA0BFD6100E2CC6000E82C61086106DA0153064E7561960C0000306DE00C0063 +S224FE216000396E0A04000030E989D2004E750C0000416DCA0C0000466EC45F0060E643FA86 +S224FE218003436000E68A7A016000FE7A6000E7E843FA03426000E678202053797374656D9F +S224FE21A0207265696E697469616C697A696E672E2E2E2E0046FC270011FC0025C07342381A +S224FE21C0010441FAFFD46100E24A70FF51C8FFFE6000DE724280428710100C0000526606B2 +S224FE21E03E3C010052881010670A74016100E63E6B00E77680473F00610009464E754A3839 +S224FE220001BA6700E764428042877C0110100C00005266063E3C010052881010675C0C0018 +S224FE222000206714040000306D00E73E0C0000036E00E7368E0052886100E5C64A00673A41 +S224FE22400C0000236600001652884A10672C740F6100E5DA6B00E7123C00601E740743F892 +S224FE226001F62C09429142A90004422900086100E572670612C051CAFFF63F072F06610017 +S224FE228016524E754E7574186100E16451CAFFFA4E7543FAE2D621C9002443FAE2C621C972 +S224FE22A000BC4E7542801010670A74026100E57E6B00E6B631C00152E540D07C015431C00D +S224FE22C001824E756100E5D06600E69E28096100E5C66B00E694C98966049889600253847D +S224FE22E06500E68626496100E5AE6600E67C41FA0BB26100E11E7201B7C96406D3C4D7C4F8 +S224FE230072FF61101293D3C1D7C153846CF621CA00084E752478000849FA000821CC000834 +S224FE23204E7541FA09FC6100E0EA548F201F6100FAE821CA00086000E63E43FA01B560003D +S224FE2340E4CE3F3C00016002426774016100E4DE6B00E6163F00243C0000FFFF6100E4CE92 +S224FE23606B00E6063F00427801CC427801D411FC000101DB3F172F3C000004002F3C000094 +S224FE238010003F2F000C4A6F001067066100064A60046100063E662A702E6100E0C808F889 +S224FE23A0000101DB6100E15467CA6100E11C11FC0007C02711FC0009C027423801DB5C8FDF +S224FE23C04E75705860D4F0FF60000004F00060000002F0F850C80004FFB84E900002FFB844 +S224FE23E04EA80004FFB84EB00004FFBF4EB80004FFBF4EB90006FFBF4EBA0004FFBF4EBB03 +S224FE24000004FFF04E400002000000000000015402530958014E015A0156014300000E4494 +S224FE2420A0E55396F24672F52486FE4DA6FE5032F754B6F847E2F75760FD4CC6FB00C2F8DD +S224FE24404972FD4128E8451CFF5824F6094D7AE5521AE74450E64146E65044E75366E7553F +S224FE246076E7243AE6428CE75492E7094D51F25255F344BBF241B1F2506DF35379F35587E3 +S224FE2480F324A3F2429BF35499F402420EF55722F54C36F50249CCF64F12F75358F7014266 +S224FE24A0CAF657E4F6014209F75723F7024F88F7439AF7535CF703427AF84536F95238F87D +S224FE24C04E40F80141C9FC46C3FC024122FB542AFB4638FB064600FD482AFD47B0FD53E036 +S224FE24E0FC568EE143B2FD54BEFD0144E6E75264E7015257FE5751FE034252F5576EF54C88 +S224FE25008EF54DB6F5005453540043484700434C5200534554004F524900414E44495355F5 +S224FE252042494144444942000000454F5249434D50492E4200002E5700002E3F00002E4C85 +S224FE254000004E454758434C52004E4547004E4F54000000000054535400545241505452C2 +S224FE256041504C494E4B554E4C4B524553454E4F500053544F505254450034453734525488 +S224FE2580530054524150525452004A5352004A4D500043484B004C45410044495655444973 +S224FE25A056534D554C554D554C535241460048494C53434343534E45455156435653504CBF +S224FE25C04D4947454C5447544C455400460048494C53434343534E45455156435653504C1D +S224FE25E04D4947454C5447544C454F52000053554200454F5200434D5000414E4400414441 +S224FE260044005355424141444441534243445355425800000000434D504141424344414430 +S224FE26204458415352004C535200524F5852524F520041534C004C534C00524F584C524F35 +S224FE26404C0048E760401219143C00AD1038C0510800000756CAFFF6671A080000066614AE +S224FE266011D9C053740951CAFFFE530166DA4CDF02064E7511FC000101C560F248E7604046 +S224FE268043FA09D461BC6624720243F801C36174661A123801C3020100C0670C080100065B +S224FE26A0670472036002720211C101C54CDF02064E7548E76040720743F801BC421161449B +S224FE26C0663C123801BC020100C0672E0801000667267205103801BDE208651E7206E4080C +S224FE26E065187207E40865127208E208650C7209E4086506720A6002720211C101C54CDFC2 +S224FE270002064E75343C10FE1038C0510800000756CAFFF6671608000006671012F8C053D1 +S224FE2720740951CAFFFE530166DA4E7511FC000101C54E752F017002484008380000C06386 +S224FE27406612538066F411FC0002C02711FC000401C5600C4A02662012F8C053534166D6D9 +S224FE276011FC0001C02711FC0000C0276100FF44221F4A3801C54E7511D9C053534166B6D0 +S224FE278060DE48E76040720143FA08C96100FEB466387402484208380000C063660C53824D +S224FE27A066F411FC000401C56020422C00036100FECC67160C38000301C5660E0C2C005043 +S224FE27C00001660651C9FFC270034CDF02064E7548E760407202103801D6B02C0003674C51 +S224FE27E043F801B032BC030F42290002137801D600036100FE4E6634740248420838000091 +S224FE2800C063660C538266F411FC000401C5601C6100FE6A660A197801D600034200600C4C +S224FE28206100FF60660651C9FFAE70034CDF02064E750000000000000000423801C54A2C83 +S224FE284000006700010C3F077E0111FC000FC02711FC0000C02711FC0003C02743FA07F119 +S224FE286011FC000EC0276100FDDA663870064A2C00046702540011C0C02711FC000AC0271A +S224FE288070FF51C8FFFE08380000C06367086100FDEC423801C56100FEEA671C0C38000341 +S224FE28A001C5670451CFFFA43E1F70014E7570080838000001DB667070044840538066FCF5 +S224FE28C0197CFFFF000243FA07906100FD7666D4343CFFFE1038C0510800000756CAFFF694 +S224FE28E0660E11FC0002C02711FC000401C560B86100FDC066AE103801C1B02C00026708F3 +S224FE29006DC41940000260BE0C000008671A0C00000967100C000010673E0C00000A662686 +S224FE29207418600674206002742A0C38000201C26614397C02000006194000021942000513 +S224FE29403E1F42004E7511FC000901C56000FF5A11FC000B01C54E750C38000101C266E688 +S224FE2960397C01000006742060CE4A2C0000675A4281323C020082EC00064282343801DEE9 +S224FE2980C4C14281122C000284C14241082C000000006604E24AE31111C101D711C201D6D2 +S224FE29A0B42C00016C244842122C00029202C2EC0006B2B801E06F04223801E0520211C271 +S224FE29C001D831C101DC42004E7511FC000B01C54E75423801DA600611FC000101DA225F81 +S224FE29E049F801C6301F670449F801CE21DF01E021DF01E431DF01DE2F097E034A6C0006D8 +S224FE2A00660001146100FE34660000EA4AB801E0670000E211FC0003C0274A3801DA672C42 +S224FE2A2008380001C063670A11FC000C01C5600000C4102C0001E208B03801D66F0811FC51 +S224FE2A40000DC027600611FC000CC0276100FF1C660000A26100FD7A667443F801B0303C8B +S224FE2A6009454A3801DA6602524032C0103801D7E50812C012F801D612F801D712F801D837 +S224FE2A80302C0006E04812C012EC000212EC000512FC00FF43F801B06100FBA866302278A7 +S224FE2AA001E44281323801DC143801DA6100FC86661C303C032051C8FFFED3B801E493B838 +S224FE2AC001E082FC0200D37801DE6000FF400838000001DB663A5307671A103801C50C0018 +S224FE2AE000016700FF200C00000367080C0000046600FF1A0838000001DB661470074A2CBC +S224FE2B0000046702540011C0C02711FC000BC027103801C54E750838000101DB6600FEEEFA +S224FE2B2070064A2C00046702540011C0C02711FC000AC02770044840538066FC6000FECED2 +S224FE2B4011EF00040105422F0004427801CC427801D46100DB0E46FC270011FC0025C073C5 +S224FE2B60423801046100D88841FA02AB6100D8A46100D87C4267307C04002F082F083F2F63 +S224FE2B80000E6100FE4E6612307C04000C58424F663C0C584F5466364ED06100D852103824 +S224FE2BA001C50C000004673041FA01B96100D8646100D86E41FA01CA6100D858102C000495 +S224FE2BC06100D8886100D828205F548F4ED041FA01A16100D83E60DC41FA024F6100D834C7 +S224FE2BE06100D9206100D8080C0000516600FF5C41FA02646100D81C60BA26484280428116 +S224FE2C00468126804A93661C2681B293661C26CBB7C963EE2648B7D3660E588BB7C963F68D +S224FE2C2042804ED222006002220B201349FA015D4BFA0006600000842A0B4BFA000660001B +S224FE2C40008649FA01634BFA00066000006E2A004BFA00066000007049FA01524BFA000605 +S224FE2C60600000582A014BFA00066000005A49FA01F44BFA00066000004249FA01964BFA25 +S224FE2C8000066000003670014ED23E3CFFFF08380002C07356CFFFF8671411C6C0717E0EEC +S224FE2CA051CFFFFE08380002C07366024ED608780003C06551CFFFFE60F41C1C67064DFAEE +S224FE2CC0FFFA60C64ED57807E99D7C0FCC050C060009630406060007060600304DFA000432 +S224FE2CE060A851CCFFE44ED5051A0522052A80020532053A056A052A052A800B0542800614 +S224FE2D000552055A800E054A0562800F05420000070D0A455843455054494F4E3A20200099 +S224FE2D20070D0A204E4F204D656D6F72792061743A20000D0A4C6F616420446F6E65000789 +S224FE2D400D0A426164204C6F616420436861726163746572000742616420436865636B7386 +S224FE2D60756D00074472697665204572726F722000074E6F7420424F4F54204469736B00EC +S224FE2D80206F6E206472697665200007424144204D656D6F7279206174200052414D20530A +S224FE2DA0697A65203D2000206973200020696E7374656164206F6620000D0A5341474520BB +S224FE2DC0537461727475702054657374205B322E345D0D0A0A436F707972696768742031A6 +S224FE2DE039383320205361676520436F6D707574657220546563686E6F6C6F67790D0A4169 +S224FE2E006C6C205269676874732052657365727665640D0A00426F6F74696E672066726F96 +S224FE2E206D20466C6F7070790050757420696E20424F4F54206469736B20616E64207072E4 +S224FE2E406573732061206B6579202851202D207175697473290007426F6F742041626F7296 +S224FE2E60746564002028546573742041626F727465642900202046696C6C696E67206D6529 +S224FE2E806D6F72792E2E2E0020204C6F6164696E672E2E2E00202057726974696E672E2ED6 +S224FE2EA02E0020204D6F76696E67206D656D6F72792E2E2E000750524F4D20312042616431 +S224FE2EC00D0A000750524F4D2032204261640D0A00427970617373656420496E69740D0AFD +S224FE2EE0004C6F6F7065642054657374730D0A0052414D207772697465206C6F6F700D0A06 +S224FE2F0000426F6F74696E672066726F6D204861726420447269766500436F756C64206ECA +S224FE2F206F742066696E64200057616974696E6720666F7220447269766520526561647961 +S224FE2F40203C512D71756974733E000D0A4E6F204D6174636820666F756E6400202053650B +S224FE2F6061726368696E672E2E2E000D0A4D617463682061742000202D20436F6E74696EF7 +S224FE2F80756520736561726368202843203D20596573293F2000001F0027002B0033004712 +S224FE2FA00052005C006A007A008F204572726F722061742000556E6B6E6F776E0042757394 +S224FE2FC0004164647265737300496C6C6567616C20496E737472756374696F6E0041726990 +S224FE2FE074686D657469630050726976696C656765005265736572766564205452415000A2 +S224FE3000556E61737369676E6564205452415000556E61737369676E656420496E74657212 +S224FE3020727570740052414D205061726974790046756E6374696F6E3A2000202041636362 +S224FE30406573733A20002020496E73743A20000303D1070207000108024A00006100000CE7 +S224FE3060423801C250F801BB4E7548E71C0011FC0000C50708F80000C5037080740011C028 +S224FE3080C5C1723251C9FFFE7A046100004A967801F067226E1244430C4300026F18520208 +S224FE30A0671C530066D860160C4300026F085202670C520060EE51CDFFD250F801BB11C090 +S224FE30C001EF11FC0001C507303C174051C8FFFE4CDF00384E7511FC00B0C60711FC00008D +S224FE30E0C60511FC0000C605323C174051C9FFFE11FC0080C60776001638C605E15B1638DB +S224FE3100C605E15B444386FC000C31C301F24E75223801D67000103801B934004841B24094 +S224FE31206200006E484182C04841303801B0C4C0C0C142414841944048C231C001E820382E +S224FE314001DAB4806D0C944031C201EC31C001EA600831C201EA427801ECD27801BC6530CB +S224FE3160B27801BE622A43F8020030196708B2406504524160F431C101E27000103801B85A +S224FE318082C031C101E4484131C101E642004E7511FCFFF501C34E7511FCFFF201C34E759F +S224FE31A02F02343C07D008380001C58167305342672611FC000CC5877201610001204A3878 +S224FE31C001C3660000927014484008380000C58167D45380670260F270FD6000007611FC85 +S224FE31E0000DC587720A610000F44A3801C3660000667014484008380000C58167065380BE +S224FE320067D660F208380001C58167CC343C07D008380001C5816728534267BC11FC000C34 +S224FE3220C5877201610000B64A3801C366287014484008380000C58167D65380679A60F2EC +S224FE3240303C251C51C8FFFE4200427801C050F801C211C001C3241F4E7508380000C581BF +S224FE326066644A3801C2660A6100FF364A3801C366521038C585020000F8807801E611C0FC +S224FE3280C585323801C0927801E467326E0A444111FC000DC587600611FC000CC58761009F +S224FE32A0003C4A3801C3661C72FFE01908380000C58157C9FFF6660E31F801E401C070004F +S224FE32C011C001C34E7570FD60F61038C583020000F0803801BA11C0C5834E7548E7E000F0 +S224FE32E0E349534111FC0036C60711FC00B0C607303801B211C0C601E04811C0C601741872 +S224FE330051CAFFFE11C1C605E05911C1C605741851CAFFFE08B80000C503343C08EC51CA74 +S224FE3320FFFE720C484111FC0080C6071038C605E1581038C605E158670C6B0A538166E68C +S224FE334011FCFFFD01C308F80000C5034CDF00074E7543F8C7C1247801DE08F80007C503D3 +S224FE336011FC000FC50711FC000DC50711FC000CC5074A114A1111FC0003C78311FC004139 +S224FE3380C7851011E148101131C001C4343801E8670853424A1151CAFFFC343801EA534207 +S224FE33A014D151CAFFFC343801EC670853424A1151CAFFFC4A114A1108380000C78366108B +S224FE33C0303801C4B07801E2660E423801C34E7511FCFFF801C34E757400143801B880C2F7 +S224FE33E031C001C011FCFFF401C34E7511FC0002C50711FC0008C50708F80006C50308B847 +S224FE34000007C50311FC000DC50711FC000CC50711FC000EC50711FC0030C60711FC0070A1 +S224FE3420C607303801B411C0C601E04811C0C601303801B611C0C603E04811C0C60311FCBF +S224FE3440000BC50711FC000AC50708F80001C50370FF08380004C58156C8FFF8660611FC5F +S224FE3460FFFA01C308B80001C50311FC0008C50708F80006C50311FC0005C50708F800076F +S224FE3480C50311FC000FC5074E75225F21DF01DA21DF01DE21DF01D62F096100FE2E4A385D +S224FE34A001BB66046100FBB65D8F0C38008001F56700010811FC000A01EE423801C3083837 +S224FE34C00005C581660000684A3801BB66046100FB8C4AB801DA6700026A6100FC34660099 +S224FE34E000546100FD764A3801C3660000486100FEFC4A3801C36600003C6100FE5666004F +S224FE350000344A3801F5670C6A0000E8423801F5610001FA7000303801EAD1B801DE91B8F7 +S224FE352001DA80F801B048C0D1B801D6608611FCFFFC01C3533801EE6F00005A103801C31B +S224FE35400C00FFF967260C00FFF867200C00FFF7671A0C00FFFA67100C00FFF4660001E404 +S224FE35600C38000301EE6C04423801C2303CFFFF51C8FFFE523801FF103801FF0200001FF2 +S224FE3580670A0C38000501EE6600FF306100FADC6000FF284A3801F567186A00011C423834 +S224FE35A001F5102F000011C001EF11C0C5C1600001920C00FFF86600018A11FC000101F5D0 +S224FE35C01F7801EF000011FC000A01EF11F801EFC5C1422F00021F7C000100011F7C00022E +S224FE35E00003423801EE303C257F51C8FFFE6000FECA102F00010C0000016700007A0C00D4 +S224FE3600000367000086102F00026604502F000352001F4000020C0000056D00009C0C2F82 +S224FE362000020001671E103801EF1F400005902F00046500006AE208D02F000411C001EF23 +S224FE3640600000621F7801EF000411FC00F501EF1F7C00030001303C257F51C8FFFE1F7CC8 +S224FE366000020003422F000211F801EFC5C1423801EE6000FE460438000F01EF6404423826 +S224FE368001EF1F7C0002000160D40638000F01EF640450F801EF1F7C0004000160C011EFC8 +S224FE36A0000001EF11F801EFC5C150F801F511FC000A01EE6000FDFE532F0003670E423885 +S224FE36C001EE11F801EFC5C16000FDF0422F00021F7C00020003102F00010C0000026D223C +S224FE36E067180C0000036708533801EF67B060CE0438000A01EF65A660C4523801EF659E28 +S224FE370060BC0638000A01EF659460B248E75000303C258051C8FFFE11FC0000C507705008 +S224FE372051C8FFFE6100F9B031F801F201F011FC0001C507303C257F51C8FFFE4CDF000A24 +S224FE37404E751038C583020000F011C0C5835C8F103801C34E75225F261F321F700003C004 +S224FE376011C001BAE90911C101F42F09423801BB11FC000101B811FC001301B931FC0200C3 +S224FE378001B031FC004001B431FC004801B631FC177001B242780200427801BC427801BE14 +S224FE37A06100FB28722F484108380005C581673441FAF7776100CC5C6100CC3460080838F7 +S224FE37C00005C581671E6100CD32670A6100CD340C0000516704538166E411FCFFFC01C331 +S224FE37E0600000DE70FF08380005C58156C8FFF86700001248410C41002F57C048414A0011 +S224FE380066AE60BA223C00000000722F484108380000C58167146100CCE2670A6100CCE45D +S224FE38200C00005167B4538166E442A741F804002F08203C000004002F006100FC4E6600F2 +S224FE384000807010B6806D2E204343F8060076002211B290660A22290004B2A8000467166B +S224FE3860D2FC00205243B67C00106DE411FC000101C36000004C873801F4E54B41F8040090 +S224FE388031F0300001BC31F0300201BE11E801F601B911E801F701B831E801F801B031E8D5 +S224FE38A001FA01B431E801FC01B631E801FE01B2D0FC004043F80200701F22D851C8FFFCD7 +S224FE38C01038C583020000F011C0C583103801C34E752C5F11EF0004010508F800010105DF +S224FE38E0422F00046100CD7C46FC270011FC0025C073423801046100CAF641FAF6056100A1 +S224FE3900CB126100CAEA6100FE4E665242A7307C04002F082F086100FB72661C307C040046 +S224FE39200C58424F662E0C584F5466287000103801F43F002F0E4ED06100CAB4103801C334 +S224FE3940440041FAF41F6100CACA6100CAD46100CA9E4ED641FAF41B6100CAB860F00C3830 +S224FE3960000101C366D26100CA8641FAF5AD6100CAA241F801F66100CA9A60D2FFFFFFFFC9 +S224FE3980FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +S224FE39A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +S224FE39C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +S224FE39E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +S224FE3A00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +S224FE3A20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +S224FE3A40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +S224FE3A60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +S224FE3A80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +S224FE3AA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +S224FE3AC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +S224FE3AE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +S224FE3B00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +S224FE3B20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +S224FE3B40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +S224FE3B60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +S224FE3B80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +S224FE3BA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +S224FE3BC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +S224FE3BE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +S224FE3C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +S224FE3C20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +S224FE3C40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +S224FE3C60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +S224FE3C80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +S224FE3CA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +S224FE3CC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +S224FE3CE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +S224FE3D00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +S224FE3D20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +S224FE3D40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +S224FE3D60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +S224FE3D80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +S224FE3DA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +S224FE3DC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +S224FE3DE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +S224FE3E00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +S224FE3E20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +S224FE3E40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +S224FE3E60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +S224FE3E80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +S224FE3EA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +S224FE3EC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +S224FE3EE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +S224FE3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +S224FE3F20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +S224FE3F40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +S224FE3F60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +S224FE3F80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +S224FE3FA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +S224FE3FC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +S224FE3FE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +S804FE0000FD diff --git a/SAGE/FILES/v2-2.hex b/SAGE/FILES/v2-2.hex new file mode 100644 index 00000000..514818cb --- /dev/null +++ b/SAGE/FILES/v2-2.hex @@ -0,0 +1,514 @@ +S00B000076322D322E68657885 +S224FE00000000040000FE0044600004F2600004E66000095E60000448600003F2600003CA02 +S224FE0020600003F8600003FE600029A2600029A460000334F1940202600002F66000343C61 +S224FE0040600035364E704FF8040011FC0092C02711FC0038C02511FC0092C06711FC003115 +S224FE0060C065700072FF343C42D741F8C0FE3080308151CAFFFA43F8000045F87FFE343C1D +S224FE0080344230113010301251CAFFF8343C06C541F8C00172084A10D0FC001051C9FFF81C +S224FE00A051CAFFEE43FA0006600002C049FA2D054BFA000660002BFE41FA00362278000874 +S224FE00C021C80008B1F80008662E11FC0090C58711FC0090C50711FC0000C58311FC00CD66 +S224FE00E0C50311FC0000C58511FC0005C50560044FF8040021C900081038C0216B64E6087B +S224FE010002400006303B00064EFB000200180024001800084238010449FA2DB14BFA08523D +S224FE012060002B9249FA2DB54BFA003860002B8649FA2DB84BFA000660002B7A74FF72008F +S224FE014070001038C023460008000002670272FFE308024000064840204030C151CAFFFCB5 +S224FE016060DA41FAFE9C343C1FFF42004201D018D21851CAFFFA4A00671449FA2D334BFAC7 +S224FE0180000660002B304A38C0216A0001004A01671449FA2D294BFA000660002B184A38FE +S224FE01A0C0216A0000E811FC0001C067307C000072014841323CFFFE224145FA00066000B9 +S224FE01C02A34664647FA000C21CB000808F80002C5034FF8040047FA002421CB00087202EF +S224FE01E04841D3C1303CA5A53280B051660E46403280B05166064640D3C160EC4FF80400AC +S224FE020093C145FA0006600029EC67084A38C0216A00007A303C00BF41F80100429851C8BF +S224FE0220FFFC548921C901004E6121C9014A21C9014243FA000C21C9000808B80002C50322 +S224FE02404FF804006100041611FC0000C0674A38C0216B1611FC0007C06770FF51C8FFFEFD +S224FE026011FC0006C0676000FEFA6100017C41FA2B256100019830380100ED48610002166F +S224FE0280704B610001DA6100016060044E7227007228740208380006C0216702725011C222 +S224FE02A001C611C101C7423801CA11C201CE11C101CF11FC000101D27206610000F8423825 +S224FE02C001BA2278000841FA002A21C8000811FC00AAC58311FC0005C5050C3800AAC58357 +S224FE02E0661011FC0000C58350F801BA31FC023001F04FF8040021C900081038C021C07C3B +S224FE03000030670CB07C00206724B07C0010672621F80100014A21F80100014231FC270081 +S224FE0320014E41FA004221C801466000064442676100280860DA4A3801BA67D420380100CF +S224FE03404840720C92406F12C2FC000A5341303C6F9A51C8FFFE51C9FFF6426770012F0002 +S224FE03606100338460AA4E4F60FC41F8C0734200108011FC0076C007E01810801238C02124 +S224FE0380E0181080706E080100036702707E10BC00400241000711FB1014C003108011FCAB +S224FE03A00000C003E01810BC00254ED1028040201008040241F8C0334240108011FC00B66E +S224FE03C0C007E018108011FB10E4C005E018108011C0C005E01810BC0040E01810BC004ED2 +S224FE03E0E01810BC00274E752F00700D6170700A616C420061686166616461626160201F2E +S224FE04004E752F0070206156201F4E753F0010186704614A60F8301F4E75E9186126E9182E +S224FE042061224E752F017203E958611851C9FFFA221F4E752F017207E998610851C9FFFA57 +S224FE0440221F4E753F000200000FB03C0009630406000007060000306104301F4E754A38AD +S224FE04600104662C3F01323CFFFF08380002C07356C9FFF8670811C0C071321F4E7548E7F7 +S224FE0480C0C043FA00066000FEE24CDF030360D64E4A4E7548E7F000720032007400343CED +S224FE04A02710420382C266044A0367061001619450C34241484184FC000A66E84CDF000F1E +S224FE04C04E754A38010466282F011238C0730801000167F61038C071020100386604221FCE +S224FE04E04E7511FC0035C07370076100FF7260DA4E494E7508380001C0734E7561C4088000 +S224FE050000070C0000616D0A0C00007A6E04088000054E7521C001067002604E21C00106B5 +S224FE05207004604621C001067006603E21C001067008603621C00106700A602E21C00106D4 +S224FE0540700C602621C00106700E601E21C001067010601621C001067012600E21C0010614 +S224FE05607014600621C00106701648F87FFE010A4E6821C8014A2A007016BA806270BA3CBC +S224FE058000046206381F261F341F31DF014E21DF014621CF01424FF804000C05001467004D +S224FE05A0199A6E0018B80C050012661E11FC0001C06711FC0000C0674A3801BA670C08F887 +S224FE05C00002C50308B80002C50370FFE01851C8FFFC46FC270011FC0038C02508B80006F0 +S224FE05E001504238010443FA000A6000FD7E428560A849FA27164BFA0006600026B849FAEB +S224FE06002990D8F450004BFA000460EE49FA29964BFA000460E420380146610017F661006E +S224FE0620FDC80C0500046200034841FA29FE6100FDDC30046100FDEE41FA29FB6100FDCE89 +S224FE064020036100FDF041FA29F86100FDC030026100FDD26100FD926000031641F80008A0 +S224FE066043FA268045FAF99A4280301967186B06D08A20C060F2424112003019D08A20C023 +S224FE068051C9FFFC60E24E75225F02800000000FD080D089C1893251D3C04ED148E780B0A4 +S224FE06A02478000847FA001421CB0008101121CA00084CDF0D01B0004E75508F321F46C153 +S224FE06C041FA26586100FD46588F20096100174421CA00084CDF0D01000000014E750838BE +S224FE06E00001C0734E752F00703A6100FD72201F6100FD104E752F00702C6100FD62201F1D +S224FE07004E752F0070076100FD56201F4E75C03C007F0C0000206D060C00007E6D02702E06 +S224FE07204E752F092F01224842816100FDD00C00001B6700006E0C000012670000680C003B +S224FE0740000D674A0C000008661AB3C867DC6100FD0E6100FCAE6100FD0651C9FFF25389C4 +S224FE0760528260C40C00007F6614B3C867BC61585389528210116100FCE6544160AC611AF2 +S224FE0780428153826B0812C06100FCD4609C610A421912C0221F225F4E758281673C4281C6 +S224FE07A0602C224842812F0870236100FCB26100FC38B3C86700000C10186100FCA2B3C87F +S224FE07C066F6205F6000FF648281660E72013F00103C005C6100FC88301F4E7542801018C6 +S224FE07E08000660253884E7561F28000670A0C00002067040C00002C4E7561E067080C00DE +S224FE0800002067F653884E7561D2244942411219B011568957C9FFFA660001481021E1589A +S224FE08201021D4C04ED248E7180042817801E89C61B667540C00002F660E383C33334844E2 +S224FE0840383C333461A26740040000306D380C0000096F144A04662E040000070C00000A9C +S224FE08606D240C00000F6E1E26014A046708E799E39BD2836002E999B684640AD280848222 +S224FE088067C2B48164BE72FFC1414CDF00184E752F036100FF66428395CA6100FF4C67002D +S224FE08A000480C00002367360C0000246708347801525388602A6100FF306700002C0400F7 +S224FE08C0003065240C000003641E244093C96100FF18670000180C00002B660C6002528334 +S224FE08E042826100FF42670257832240D5CAD5CAD4FC0154D3D2201FC14380804E752F02AB +S224FE090042826100FEF6670000520C000027671C0C00002E674624016100FF0C6B06241F20 +S224FE092092814E75241F428153814E756100FEAE6100FEAA670000200C0000276712E19A7D +S224FE09404A0266E0D480828167E6B28264E260D46100FE9666CEC14260C47001241F22008A +S224FE09604E756100FA9E703F6100FAF46100FD944FF8040042B801546100FA6E083800061F +S224FE098001506700000870546100FAD436380152670C70246100FAC810036100FAA8703EF2 +S224FE09A06100FABC742841F801886100FD7643FA1A686100FE5460B843FA1A8C6000FE4AD6 +S224FE09C06100FE382838017E387801821010670E6100FEBE668C2809284A31CA0182610045 +S224FE09E0FE1A327C01001010670A6100FEA46B00FF726704D3C45389528921C9017E2A0968 +S224FE0A00611C6718280B6100FCD667F46100FAEE0C00001367F60C00000366E44E756100D4 +S224FE0A20F9C820046100FA0EB8FC0154670C6100F9D2200490946100F9FC6100FCAA760F93 +S224FE0A402644C7496100FC56C7496600FF16101B6100F9C808030000660000066100F9A419 +S224FE0A60BA8B57CBFFDE6100F99A760F2644101B6100FC9C6100F9E8BA8B57CBFFF24E75CB +S224FE0A8043F80154323C20247402601443F80126323C2041600843F80106323C20447407FF +S224FE0AA06100FD3A671A903C00306B00FEB678001800B8026E00FEAC61226100F92C4E75D1 +S224FE0AC04284611852846100F93A0C04000466046100F9306130B8026DEA4E756100F90A99 +S224FE0AE042833001E0880C000020670000066100F96E10016100F968868366061004610077 +S224FE0B00F9446100FBE22004E5800280000000FF4A836A42303100006100F90A0C4153521D +S224FE0B20663C48E7704036006100F8D870286100F92E428243FA18D21419670E1019E57B94 +S224FE0B40650270206100F91860EE4CDF020E70296100F90C6008203100006100F8D84E75F4 +S224FE0B606100FC7A6600FDFC6100FF226100FF28611861086148610461344E756100F8840D +S224FE0B806100F8804E756000F86061FA103C00506100F8CC103C00436100F8C46100FB4892 +S224FE0BA020380146307801526000126861D876FF43F8014E223C00005352600E61C843F8B1 +S224FE0BC0014A223C00005553760142846100FF144E757C0060000C2C700072104A10670A7C +S224FE0BE06100FC446B00FD7C12006100000E5200B0016DF66100F7F24E756100F7EC41FAFA +S224FE0C0000206100F8086100F83C41FA001B3438017C0102670441FA001B6100F7F04E75AD +S224FE0C205452415020230020204E6F2074726163652000202054726163652020202000003C +S224FE0C4043FA18A26000FBC26100FCB46600FD142A006100FCAA6600FD0A2800D085610079 +S224FE0C60F7882200103C002B614822059284103C002D613E2205C2C4103C002A61344A4415 +S224FE0C806746220582C4103C002F61186132103C00726100F7CA103C00656100F7C2103CB9 +S224FE0CA0006D48416100F7B86100FA3C30016000F7746100F7AA6100FA2E20016100F7761E +S224FE0CC06100F7406000F73C4E757C106100FB2C2838017E38780182101067106100FBB258 +S224FE0CE06600FC802809284A31CA01826100FB0C327C00141010670C7CFF6100FB946B005B +S224FE0D00FC6267062C096B00FC5A52892A092C446100F6D6200E6100F71CB8FC0154670C46 +S224FE0D206100F6E0200E90946100F70A6100F9B848E7060061304CDF006021CE017E4A8624 +S224FE0D406B065386671E2A0EBA8E650000186100F98E67BC6100F7A60C00001367F60C0033 +S224FE0D60000366AC4E75300EE2086500FBF67C07610006F03E00E9586100F90E0020010038 +S224FE0D8001080104014003880428046E0512060606CC053A05A60606065206CC08070008AC +S224FE0DA0664E43FA176C3207E049E249610006F659016F5E0401001067585801660642458B +S224FE0DC0611C60063A07610006C4610006FC6100070216076100F920610007364E75428535 +S224FE0DE043FA171E3207EC5902410003600006B63007020000380C00000867367042610069 +S224FE0E0006AE61DA610006C23607EC5B6100072860C030070200003F0C00003C66A64282F3 +S224FE0E20263A084C080700066704263A0846600000F2203A082A610006767050610006707B +S224FE0E403A07E35D08C500066100064E6100067A08070007670A61126100F89C61144E757E +S224FE0E6061106100F89261024E753607EC5B600006C6360708C30005600006964285600607 +S224FE0E807A4060027AFF203A07D6610006223007EC5802000007530066067041610006108F +S224FE0EA0610005F6610006223607610006646100F8463607EC5B610006644E75080700087A +S224FE0EC0660002043007EF580240000732006100F7B8001000320014001C007C011800B2E1 +S224FE0EE001527401600A263A0786428260064282263A0780283A07683007020000C00C0025 +S224FE0F0000C0671843FA16366100059A3A076100057C610005B4610005F64E752004610025 +S224FE0F20058E7A40610005A228034A026614610005DE4A84670A6100F7BE200461000570D5 +S224FE0F404E7561F66100F7B0610005C44E753207E65902410007080700076624203A0718A4 +S224FE0F6008070006670C203A07124A016604203A070E6100053A61000550610005924E753E +S224FE0F804A016756203A06D861000524704D3A07E35D08C5000661000516610004FC610035 +S224FE0FA005287A40610004BC31C001880807000A661E6100000C6100F73E610005524E7591 +S224FE0FC070236100F49A303801886100F4584E7561E86100F72261E84E75203A06AA080743 +S224FE0FE00006678E203A069C60880C0700FC6612203A0698610004B8203A0694610004B06A +S224FE10004E753A07024500C00C4500C0670A3005E2588A406000FEEE283A06784282428352 +S224FE10206000FED608070007660000983207E6590201000714010C01000667520C010003F2 +S224FE10406F14263A065E024200010247000F004700C86000FEA043FA14FC61000448610041 +S224FE10600468E20A660E70236100F3F430076100F3D44E753607E75B610004C008070003EE +S224FE1080660A6100F6727A40610004484E75320702410007340143FA14CC610004080C029A +S224FE10A00002660A610004227A406100042670544A02670870560C02000666046100F3A038 +S224FE10C04E754280600270023207EC59C27C0001D2407A4043FA14AE610003CA610003EAB0 +S224FE10E06100042C0807000867186100F60A3607EF5B70200807000667027028B1436100E3 +S224FE110004104E753207020100C00C0100C0673E203A0588080700086704203A05826100DC +S224FE1120038E3A07610003666100039E70236100F32E3007EF58020000074A006602700848 +S224FE11406100F3026100F5B0610003C44E7570533807020400380C040008660808870003ED +S224FE1160303C4442611C610003A60C04000866106100F5847A40610003603440610003FA3B +S224FE11804E7543FA1440610003263207EE5902810000001ED3C142803011610003126100DF +S224FE11A003284E757A40320702410F000C410100670A704243FA13EE61CC600C203A04D87B +S224FE11C0610002EC6100030230074A0067106100F24AE158E040548E6108558E4E75610017 +S224FE11E002F83440610003924E750807000866000258203A046A610002B67051610002B039 +S224FE1200610002C670236100F25610076100F20C6100F4E43607EC5B6100031C4E753A07AF +S224FE122043FA13C2612208070008670C61106100F4C6610002DA4E7561F86100F4BA36075B +S224FE1240EC5B610002F24E753207E95902410007610002524A456704610002326100026A56 +S224FE12604E75428560023A0743FA139A61DA3607E75B61086100F4803607EC5B08070003C6 +S224FE12806606610002B24E75610002C04E753007024001F00C40010067C8EC4872045740FA +S224FE12A0670859406600FF787205088700068E7C41006000FE1E3007EC580240000755401A +S224FE12C06F00FF5C43FA133E7A4053406706E35D594066166100FF72610002346100F418CE +S224FE12E03607EC5B610002544E75044710003007024000380C4000086600FF24203A03A8FF +S224FE1300610001AC3A0761000184610001BC3607E75B61086100F3E03607EC5B610002264E +S224FE13204E753007024001F878000C400140671078030C400148670878020C4001886624A1 +S224FE1340203A0368610001686100017E3607EC5B61086100F3A23607E75BE21C650001DC79 +S224FE1360600001D4E8480C0000106700FEF67206E44857406700FF347207594067F66000EA +S224FE1380FE9E3007024000C00C4000C067123007024001300C4001006700FECC6000FE80EA +S224FE13A03A07E25D43FA12563207E55902410001610000F2610000E26100010E6100015092 +S224FE13C06100F3343607EC5B610001704E7532073A07024500C00C4500C06744E65961503C +S224FE13E0610000AA610000E2360702430E00080700056708EC5B6100013E60167023610038 +S224FE1400F05E3003EF580200000F660270086100F0346100F2E23607E75B6100011A4E7598 +S224FE1420EF59610C4285610000A0610000E24E7502410003340702420100EC5A824243FA19 +S224FE144011DC610000604E75702E61000062203A02126100005A6100007030076100EFC670 +S224FE14604E752F09224E6100F2346600F4F6301E225F4E752F09224E6100F2226600F4E43A +S224FE148054896100F218201E225F4E75024500C00C05008066027AC03205EC5902010003C3 +S224FE14A043FA108AE519024100FF203110002F017203E1984A00670000086100EFA253068F +S224FE14C051C9FFF0221F4E756100EF3851CEFFFA4E7570236100EF883205EC59C27C000371 +S224FE14E0B23C000267206100FF7A53016C066100EF2A4E756100EF2E53016D086100FF648A +S224FE15006100EF224E75703F6100EF544E7536071003E60802000007E70B86001003024069 +S224FE152000076100F164001000140018001E00240076008000C67244601472416010223A08 +S224FE15400112600A223A01106004223A010E7403E1991001671C6100EF060C000044670637 +S224FE15600C000041660C3003E618020000076100EED451CAFFDC4E75705B6100EEE2D5CEF4 +S224FE1580200A558030780152D1C8D1C890A801546100EEA2705D6100EEC64E756100FEC4D6 +S224FE15A06100EE8260986100FEBA38006100EE6C70286100EEAA61826100F13C3604EF5BCD +S224FE15C00804000F66066100FF6E60046100FF6C702E6100EE8A70570804000B6702704C09 +S224FE15E06100EE7C70296100EE764E75E61BC63C000710036100F0920012001C0026003E6A +S224FE160000540010001000104E756100FE566100EE144E756100FE5E6100EE1A4E7561005B +S224FE1620FE4234406100EDFE223A003C6100FF206100FF464E756100FE2A38006100EDDC3B +S224FE1640203A00286100FE686000FF6E6100FE844E75284129002841292B2D2841294D4F21 +S224FE16605645574F5244285043292850430043435200535200004E424344504541005357DD +S224FE168041504558544C45585457494C4C4547414C005441530042535200414444515355A6 +S224FE16A0425155535000434D504D4558470043FA0DB56000F1546100F1D86600F2A660045B +S224FE16C06100F0402809284A2A0454856100F3506100F01441F80188243C00000028610018 +S224FE16E0F042428110106716223C0000FFFF6100F20E6BCC6E0A13400001E08012805489C6 +S224FE17000C01002E66BE4E7543F80154323C202474037A01601643F80126323C2041600861 +S224FE172043F80106323C2044740842856100F0AE671A903C00306B00F22AB0056B00F22416 +S224FE1740B0026C00F21E4282610E4E75200561085280B0026DF84E7542832F023A012800CF +S224FE17602C00E5864A82660E6100F0904A10662260046100EF8E32056100EC6E6100F364E0 +S224FE17806100EF64742841F801886100EF961010672042816100F1686BD8660000160286E3 +S224FE17A0000000FF86836A063380600060042380600032051004241F4E756100F02066000C +S224FE17C0F1A26100FF526100FF586106611E610E4E7543F80146323C50436000001843F8BB +S224FE17E0014E323C535276FF6000000C43F8014A323C55537601428242806100FF5E4E7589 +S224FE18007CFF7A0142806100EFD467144486903C00306B00F14EB03C00016E00F1463A0032 +S224FE1820360060046100EEDC3643D7CB284BD7CB4A866B0A675A6100EFC24A106614616AF9 +S224FE18406100EEA4742841F801886100EED66100EFAA101067320C00002E660607B80150A6 +S224FE186060266100F02C6BBC6100EF90243C0000FFFF6100EFB26BAC426C017239400176D3 +S224FE188007F80150274901605243B6456F9A4E75611860F4427265616B706F696E742000CC +S224FE18A0496E61637469766500006100EB3C41FAFFE46100EB5810036100EB8A6100EE2848 +S224FE18C007380150660A41FAFFD86100EB404E75202B01606100EB5E6100EB2870286100E1 +S224FE18E0EB7E302C01766100EB3C6100EE0A302C01726100EB3070296100EB644E757600FB +S224FE190078104A10671C6100EF1E6B00F056160018006100EEE60C00005467460C00004E76 +S224FE192067386100EAC441FA004C6100EAE010036100F2C86100EDB0742841F80188610059 +S224FE1940EDE26100EEB667240C00005467140C00004E67066100EDAC60C83238017C0781F2 +S224FE196060063238017C07C131C1017C5203B6046DBC4E7528542972616365206F7220285C +S224FE19804E296F2074726163650043FA0AF86000EE78243C000000FF616C6600EFC61A00C9 +S224FE19A0E1401005600C243C0000FFFF61586600EFB23A0048403005600842826148660032 +S224FE19C0EFA241FA14AA6100EA4461000942E19812C0538466F821CA00084E7548E7F000EA +S224FE19E06100EEAE661A28096100EEA62449C9896B0E6E06988952846004D5C9538A4280FD +S224FE1A004CDF000F4E7561D4660622026100EEF04E7561F266142C0098876D00EF4670FFD6 +S224FE1A204A10670A22026100EED66600EF3641FA15266100E9D8610008D64E7543FA0AB46F +S224FE1A406000EDC6243C000000FF7E0161C41219C200B206670453846CF46100009660F6D9 +S224FE1A60243C0000FFFF7E0261A81219E1991211C240B246670453846CF06100007660F6EF +S224FE1A8042827E04618C2649548B1219E1991211E199121BE1991213C280B28667045384F8 +S224FE1AA06CE86100004E60F66100FF326600EEB448E708606100FF266600EEA82A492C0474 +S224FE1AC04CDF0610C34D41FA148E6100E9406100083E9C846518284952892E04264D121CE8 +S224FE1AE0B21B6606538766F6610853866CE861024E7148E7FE7E663E41FA146B6100E90E5B +S224FE1B00538920096100030C6100EBDC7203E198101951C9FFFA6100E91C41FA1455610090 +S224FE1B20E8EC6100E9D80C00004366126100E9304CDF7E7F4E7541FA140D6100E8D04CDFE0 +S224FE1B407E7F21CA00086000EE286100E8B66100E8B243FA093A6000ECB043FA093C6000C4 +S224FE1B60ECA86100ED2C6600EDFA20096100E8C66100EB7410116100E8A24E756100ED12E0 +S224FE1B806600EDE03C09080600006600EDD620096100E8A26100EB5030116100E8884E750E +S224FE1BA043FA08FD6000EC626100ECE66600EDB4223C000000FF6100ED466600EDA612807C +S224FE1BC04E756100ECCC6600ED9A3C09080600006600ED90223C0000FFFF6100ED226600D1 +S224FE1BE0ED8232804E756100EC1274076100EC386B00ED7022006000E7BC43FA08AA600063 +S224FE1C00EC086100006443FA07B654894A516700ED523014C059B05966F0D8D121CC016835 +S224FE1C2008F80002015008F800040150600261387401610001BA426A017251CAFFF66002DC +S224FE1C40612608B80005015008F80006015008F8000701501038015002000007660608B867 +S224FE1C6000060150600001506100EB901010670C6100EC1E6600ECEC21C901466106610048 +S224FE1C80E7684E752C380146284608060000671241FA001C6100E77620066100017660001C +S224FE1CA0ECD0224C6100E9F66600ECB84E75496C6C6567616C2070726F6772616D20737411 +S224FE1CC061727420616464726573733A20006100E71843FA07DC6000EB30083800060150C8 +S224FE1CE0670461A0604E4E7508F8000501506040619208B8000301500C100049660808F834 +S224FE1D000003015052887005083800050150660270104A10670E747F6100EAE06100EB085E +S224FE1D206B00EC406100E6C2600C08B8000501506100FF36700111C0015108F800060150FD +S224FE1D4008B80007015030140240FFF00C404E406664301C0240000F3C38017C41FA002C5A +S224FE1D600106661C21CC016808F80007015008F80002015008B800040150673A41FA0021C4 +S224FE1D806100E68A6100E662602C2A2A2A2054726163696E672054524150202A2A2A002AB5 +S224FE1DA02A2A204753207465726D696E61746564202A2A2A0000287801463C38014E08383D +S224FE1DC00006015066060886000F600408C6000F2078014A4E602E7801422F0C3F064CF821 +S224FE1DE07FFF01064E7308B8000601504E7542803242D3C92449D3C905380150670E226957 +S224FE1E0001606100E8986600000652804E7553804E756100E62030780152D0C8D0C84A7892 +S224FE1E200152672E6100E5DC2F0070286100E63070246100E62A303801526100E6086100E7 +S224FE1E40E8A6201F90A801546100E5EA70296100E60E4E7554726163653A200008380006B5 +S224FE1E6001506700FF52083800070150672608B80006015074006100FF766B00EAE6670826 +S224FE1E803551016C32BC4E4F52420C42000366E66000FF2441FAFFBE2038014621C0017E16 +S224FE1EA06100E56A28406100FF6AD0FC015431C801826100E832224C6100E7E266143011D2 +S224FE1EC06100E5626100E53C6100E5382C496100EE96083800050150670A41F801884210E2 +S224FE1EE06100EC7E533801516F1E083800030150671A6100E7EA67146100E6020C00001380 +S224FE1F0067F60C00000366046000EA666100E4DA6000FE280D0A556E657870656374656467 +S224FE1F2020627265616B20706F696E743A2000000D0A427265616B3A200042854286283890 +S224FE1F4001465584760041FAFFCC74026100FEA06F32B3C4661E41FAFFD876020C02000237 +S224FE1F6067123A2A01723C2A0176BC4567065245354501720C514E4F670605B80150600466 +S224FE1F8032AA016C51CAFFC60838000201506728B8B80168662208B80002015008B80004BB +S224FE1FA00150661421C4014608F80006015008B8000701506000FEA620380146908321C021 +S224FE1FC00146BC456600FC824A436600FED028440C544E4F6600FEC620046000FEC043FAFF +S224FE1FE004E46000E82411FC000101BB6004423801BB41FA0E8E6100E414607642857401E4 +S224FE20006100E8246B00E95C3C00243C0000FFFF6100E8146B00E94C3F006100E8746600A7 +S224FE2020E9422F0942826100E7FE6B00E9362F003F064A85670E41FA0E576100E3D06100D9 +S224FE20400992600C41FA0E3C6100E3C26100097E6700000E41FA000C6100E3B26100E3BC51 +S224FE20604E750D0A4469736B206572726F723A20000061740C000051670000C00C0000539C +S224FE208066F0420561621E00610000BC1C0153064281610000B2610000AE26410C0700309D +S224FE20A0660E4A0667066100009E60F6617460C20C0700326614220B6100008C26414A0610 +S224FE20C067EA6100008216C160F40C07003167EE0C07003966644A066660614641FA0C4F9C +S224FE20E06100E32A6000E88A4A3801BB672408380001C033670A1038C031088000074E75A4 +S224FE21006100E3F267E26100E3F40C00005166D84E756100E3AE0C00000D6700E2CC600027 +S224FE2120E33E6122460566024E75588F41FA0C216100E2DA6000E83A508F41FA0BFD610011 +S224FE2140E2CC6000E82C61086106DA0153064E7561960C0000306DE00C0000396E0A040052 +S224FE21600030E989D2004E750C0000416DCA0C0000466EC45F0060E643FA03436000E68A25 +S224FE21807A016000FE7A6000E7E843FA03426000E678202053797374656D207265696E697E +S224FE21A07469616C697A696E672E2E2E2E0046FC270011FC0025C0734238010441FAFFD43E +S224FE21C06100E24A70FF51C8FFFE6000DE784280428710100C00005266063E3C010052886A +S224FE21E01010670A74016100E63E6B00E77680473F00610009464E754A3801BA6700E76421 +S224FE2200428042877C0110100C00005266063E3C010052881010675C0C00002067140400E6 +S224FE222000306D00E73E0C0000036E00E7368E0052886100E5C64A00673A0C00002366004B +S224FE2240001652884A10672C740F6100E5DA6B00E7123C00601E740743F801F62C09429128 +S224FE226042A90004422900086100E572670612C051CAFFF63F072F066100146C4E754E7510 +S224FE228074186100E16451CAFFFA4E7543FAE2D621C9002443FAE2C621C900BC4E7542801F +S224FE22A01010670A74026100E57E6B00E6B631C00152E540D07C015431C001824E756100A7 +S224FE22C0E5D06600E69E28096100E5C66B00E694C98966049889600253846500E6862649E4 +S224FE22E06100E5AE6600E67C41FA0BB26100E11E7201B7C96406D3C4D7C472FF61101293B1 +S224FE2300D3C1D7C153846CF621CA00084E752478000849FA000821CC00084E7541FA09FCB8 +S224FE23206100E0EA548F201F6100FAE821CA00086000E63E43FA01B56000E4CE3F3C000112 +S224FE23406002426774016100E4DE6B00E6163F00243C0000FFFF6100E4CE6B00E6063F002A +S224FE2360427801CC427801D411FC000101DB3F172F3C000004002F3C000010003F2F000CA0 +S224FE23804A6F001067066100064A60046100063E662A702E6100E0C808F8000101DB6100D5 +S224FE23A0E15467CA6100E11C11FC0007C02711FC0009C027423801DB5C8F4E75705860D45E +S224FE23C0F0FF60000004F00060000002F0F850C80004FFB84E900002FFB84EA80004FFB852 +S224FE23E04EB00004FFBF4EB80004FFBF4EB90006FFBF4EBA0004FFBF4EBB0004FFF04E4033 +S224FE24000002000000000000015402530958014E015A0156014300000E44A0E55396F2466F +S224FE242072F52486FE4DA6FE5032F754B6F847E2F75760FD4CC6FB00C2F84972FD4128E87A +S224FE2440451CFF5824F6094D7AE5521AE74450E64146E65044E75366E75576E7243AE64265 +S224FE24608CE75492E7094D51F25255F344BBF241B1F2506DF35379F35587F324A3F2429B3D +S224FE2480F35499F402420EF55722F54C36F50249CCF64F12F75358F70142CAF657E4F601FD +S224FE24A04209F75723F7024F88F7439AF7535CF703427AF84536F95238F84E40F80141C9DE +S224FE24C0FC46C3FC024122FB542AFB4638FB064600FD482AFD47B0FD53E0FC568EE143B211 +S224FE24E0FD54BEFD0144E6E75264E7015257FE5751FE034252F5576EF54C8EF54DB6F500C3 +S224FE25005453540043484700434C5200534554004F524900414E44495355424941444449D3 +S224FE252042000000454F5249434D50492E4200002E5700002E3F00002E4C00004E454758F0 +S224FE2540434C52004E4547004E4F5400000000005453540054524150545241504C494E4B35 +S224FE2560554E4C4B524553454E4F500053544F5052544500344537345254530054524150BD +S224FE2580525452004A5352004A4D500043484B004C45410044495655444956534D554C5511 +S224FE25A04D554C535241460048494C53434343534E45455156435653504C4D4947454C54E9 +S224FE25C047544C455400460048494C53434343534E45455156435653504C4D4947454C541D +S224FE25E047544C454F52000053554200454F5200434D5000414E4400414444005355424194 +S224FE260041444441534243445355425800000000434D50414142434441444458415352001D +S224FE26204C535200524F5852524F520041534C004C534C00524F584C524F4C0048E760409C +S224FE26401219143C00AD1038C0510800000756CAFFF6671A08000006661411D9C05374094F +S224FE266051CAFFFE530166DA4CDF02064E7511FC000101C560F248E7604043FA09D461BC89 +S224FE26806624720243F801C36174661A123801C3020100C0670C0801000667047203600250 +S224FE26A0720211C101C54CDF02064E7548E76040720743F801BC42116144663C123801BC34 +S224FE26C0020100C0672E0801000667267205103801BDE208651E7206E40865187207E408D3 +S224FE26E065127208E208650C7209E4086506720A6002720211C101C54CDF02064E75343C69 +S224FE270010FE1038C0510800000756CAFFF6671608000006671012F8C053740951CAFFFE77 +S224FE2720530166DA4E7511FC000101C54E752F017002484008380000C0636612538066F476 +S224FE274011FC0002C02711FC000401C5600C4A02662012F8C053534166D611FC0001C02789 +S224FE276011FC0000C0276100FF44221F4A3801C54E7511D9C053534166B660DE48E76040B8 +S224FE2780720143FA08C96100FEB466387402484208380000C063660C538266F411FC0004EF +S224FE27A001C56020422C00036100FECC67160C38000301C5660E0C2C00500001660651C927 +S224FE27C0FFC270034CDF02064E7548E760407202103801D6B02C0003674C43F801B032BCFE +S224FE27E0030F42290002137801D600036100FE4E66347402484208380000C063660C538201 +S224FE280066F411FC000401C5601C6100FE6A660A197801D600034200600C6100FF6066068A +S224FE282051C9FFAE70034CDF02064E750000000000000000423801C54A2C00006700010C3B +S224FE28403F077E0111FC000FC02711FC0000C02711FC0003C02743FA07F111FC000EC0278B +S224FE28606100FDDA663870064A2C00046702540011C0C02711FC000AC02770FF51C8FFFE97 +S224FE288008380000C06367086100FDEC423801C56100FEEA671C0C38000301C5670451CF75 +S224FE28A0FFA43E1F70014E7570080838000001DB667070044840538066FC197CFFFF0002B1 +S224FE28C043FA07906100FD7666D4343CFFFE1038C0510800000756CAFFF6660E11FC0002A6 +S224FE28E0C02711FC000401C560B86100FDC066AE103801C1B02C000267086DC419400002EA +S224FE290060BE0C000008671A0C00000967100C000010673E0C00000A66267418600674208C +S224FE29206002742A0C38000201C26614397C0200000619400002194200053E1F42004E7537 +S224FE294011FC000901C56000FF5A11FC000B01C54E750C38000101C266E6397C010000062E +S224FE2960742060CE4A2C0000675A4281323C020082EC00064282343801DEC4C14281122C1F +S224FE2980000284C14241082C000000006604E24AE31111C101D711C201D6B42C00016C24E7 +S224FE29A04842122C00029202C2EC0006B2B801E06F04223801E0520211C201D831C101DC3A +S224FE29C042004E7511FC000B01C54E75423801DA600611FC000101DA225F49F801C6301FD2 +S224FE29E0670449F801CE21DF01E021DF01E431DF01DE2F097E034A6C000666000114610053 +S224FE2A00FE34660000EA4AB801E0670000E211FC0003C0274A3801DA672C08380001C063BA +S224FE2A20670A11FC000C01C5600000C4102C0001E208B03801D66F0811FC000DC02760065B +S224FE2A4011FC000CC0276100FF1C660000A26100FD7A667443F801B0303C09454A3801DA3A +S224FE2A606602524032C0103801D7E50812C012F801D612F801D712F801D8302C0006E04858 +S224FE2A8012C012EC000212EC000512FC00FF43F801B06100FBA86630227801E4428132381F +S224FE2AA001DC143801DA6100FC86661C303C032051C8FFFED3B801E493B801E082FC0200E9 +S224FE2AC0D37801DE6000FF400838000001DB663A5307671A103801C50C0000016700FF20F2 +S224FE2AE00C00000367080C0000046600FF1A0838000001DB661470074A2C00046702540082 +S224FE2B0011C0C02711FC000BC027103801C54E750838000101DB6600FEEE70064A2C0004CB +S224FE2B206702540011C0C02711FC000AC02770044840538066FC6000FECE11EF00040105B8 +S224FE2B40422F0004427801CC427801D46100DB0E46FC270011FC0025C073423801046100EF +S224FE2B60D88841FA02AB6100D8A46100D87C4267307C04002F082F083F2F000E6100FE4E88 +S224FE2B806612307C04000C58424F663C0C584F5466364ED06100D852103801C50C00000409 +S224FE2BA0673041FA01B96100D8646100D86E41FA01CA6100D858102C00046100D888610049 +S224FE2BC0D828205F548F4ED041FA01A16100D83E60DC41FA024F6100D8346100D92061002E +S224FE2BE0D8080C0000516600FF5C41FA02646100D81C60BA264842804281468126804A9387 +S224FE2C00661C2681B293661C26CBB7C963EE2648B7D3660E588BB7C963F642804ED22200D3 +S224FE2C206002220B201349FA015D4BFA0006600000842A0B4BFA00066000008649FA0163F2 +S224FE2C404BFA00066000006E2A004BFA00066000007049FA01524BFA0006600000582A014F +S224FE2C604BFA00066000005A49FA01F44BFA00066000004249FA01964BFA0006600000366C +S224FE2C8070014ED23E3CFFFF08380002C07356CFFFF8671411C6C0717E0E51CFFFFE08382B +S224FE2CA00002C07366024ED608780003C06551CFFFFE60F41C1C67064DFAFFFA60C64ED509 +S224FE2CC07807E99D7C0FCC050C060009630406060007060600304DFA000460A851CCFFE46C +S224FE2CE04ED50514051C05248002052C0534056405240524800B053C8006054C0554800E1A +S224FE2D000544055C800F053C0000070D0A455843455054494F4E3A202000070D0A204E4F14 +S224FE2D20204D656D6F72792061743A20000D0A4C6F616420446F6E6500070D0A4261642026 +S224FE2D404C6F616420436861726163746572000742616420436865636B73756D0007447225 +S224FE2D60697665204572726F722000074E6F7420424F4F54204469736B00206F6E20647298 +S224FE2D80697665200007424144204D656D6F7279206174200052414D2053697A65203D2038 +S224FE2DA000206973200020696E7374656164206F6620000D0A5341474520537461727475FD +S224FE2DC0702054657374205B322E325D0D0A0A436F707972696768742031393833202053F4 +S224FE2DE061676520436F6D707574657220546563686E6F6C6F67790D0A416C6C2052696786 +S224FE2E006874732052657365727665640D0A00426F6F74696E672066726F6D20466C6F7092 +S224FE2E2070790050757420696E20424F4F54206469736B20616E6420707265737320612016 +S224FE2E406B6579202851202D207175697473290007426F6F742041626F72746564002028FD +S224FE2E60546573742041626F727465642900202046696C6C696E67206D656D6F72792E2E8B +S224FE2E802E0020204C6F6164696E672E2E2E00202057726974696E672E2E2E0020204D6FCF +S224FE2EA076696E67206D656D6F72792E2E2E000750524F4D2031204261640D0A000750529B +S224FE2EC04F4D2032204261640D0A00427970617373656420496E69740D0A004C6F6F7065BE +S224FE2EE0642054657374730D0A0052414D207772697465206C6F6F700D0A00426F6F746908 +S224FE2F006E672066726F6D204861726420447269766500436F756C64206E6F742066696E87 +S224FE2F2064200057616974696E6720666F72204472697665205265616479203C512D7175E1 +S224FE2F406974733E000D0A4E6F204D6174636820666F756E64002020536561726368696E56 +S224FE2F60672E2E2E000D0A4D617463682061742000202D20436F6E74696E75652073656139 +S224FE2F80726368202843203D20596573293F2000001F0027002B003300470052005C006A2D +S224FE2FA0007A008F204572726F722061742000556E6B6E6F776E00427573004164647265CC +S224FE2FC0737300496C6C6567616C20496E737472756374696F6E0041726974686D657469E5 +S224FE2FE0630050726976696C656765005265736572766564205452415000556E61737369BA +S224FE3000676E6564205452415000556E61737369676E656420496E74657272757074005268 +S224FE3020414D205061726974790046756E6374696F6E3A200020204163636573733A2000DA +S224FE30402020496E73743A20000303D1070207000108024A00006100000C423801C250F807 +S224FE306001BB4E7548E71C0011FC0000C50708F80000C5037080740011C0C5C1723251C969 +S224FE3080FFFE7A0411FC00B0C60711FC0000C60511FC0000C605323C174051C9FFFE11FC8F +S224FE30A00080C60776001638C605E15B1638C605E15B444386FC000C31C301F2967801F0A5 +S224FE30C067226E1244430C4300026F185202671C530066A460160C4300026F085202670C4C +S224FE30E0520060EE51CDFF9E50F801BB11C001EF11FC0001C507303C174051C8FFFE4CDFCF +S224FE310000384E75223801D67000103801B934004841B2406200006E484182C048413038D3 +S224FE312001B0C4C0C0C142414841944048C231C001E8203801DAB4806D0C944031C201EC7E +S224FE314031C001EA600831C201EA427801ECD27801BC6530B27801BE622A43F8020030190C +S224FE31606708B2406504524160F431C101E27000103801B882C031C101E4484131C101E6DA +S224FE318042004E7511FCFFF501C34E7511FCFFF201C34E752F02343C07D008380001C5811B +S224FE31A067305342672611FC000CC58772016100011C4A3801C36600009270144840083873 +S224FE31C00000C58167D45380670260F270FD6000007611FC000DC587720A610000F04A38E5 +S224FE31E001C3660000667014484008380000C5816706538067D660F208380001C58167CC21 +S224FE3200343C07D008380001C5816728534267BC11FC000CC5877201610000B24A3801C365 +S224FE322066287014484008380000C58167D65380679A60F2303C251C51C8FFFE4200427849 +S224FE324001C050F801C211C001C3241F4E7508380000C58166604A3801C266066100FF3671 +S224FE326066521038C585020000F8807801E611C0C585323801C0927801E467326E0A44415D +S224FE328011FC000DC587600611FC000CC5876100003C4A3801C3661C72FFE01908380000EB +S224FE32A0C58157C9FFF6660E31F801E401C0700011C001C34E7570FD60F61038C583020050 +S224FE32C000F0803801BA11C0C5834E7548E7E000E349534111FC0036C60711FC00B0C60743 +S224FE32E0303801B211C0C601E04811C0C601741851CAFFFE11C1C605E05911C1C6057418B5 +S224FE330051CAFFFE08B80000C503343C08EC51CAFFFE720C484111FC0080C6071038C6051A +S224FE3320E1581038C605E158670C6B0A538166E611FCFFFD01C308F80000C5034CDF000736 +S224FE33404E7543F8C7C1247801DE08F80007C50311FC000FC50711FC000DC50711FC000CB3 +S224FE3360C5074A114A1111FC0003C78311FC0041C7851011E148101131C001C4343801E85E +S224FE3380670853424A1151CAFFFC343801EA534214D151CAFFFC343801EC670853424A1116 +S224FE33A051CAFFFC4A114A1108380000C7836610303801C4B07801E2660E423801C34E7591 +S224FE33C011FCFFF801C34E757400143801B880C231C001C011FCFFF401C34E7511FC00025C +S224FE33E0C50711FC0008C50708F80006C50308B80007C50311FC000DC50711FC000CC507F5 +S224FE340011FC000EC50711FC0030C60711FC0070C607303801B411C0C601E04811C0C601F9 +S224FE3420303801B611C0C603E04811C0C60311FC000BC50711FC000AC50708F80001C5037E +S224FE344070FF08380004C58156C8FFF8660611FCFFFA01C308B80001C50311FC0008C507BB +S224FE346008F80006C50311FC0005C50708F80007C50311FC000FC5074E75225F21DF01DAC7 +S224FE348021DF01DE21DF01D62F096100FE2E4A3801BB66046100FBC011FC000A01EE42386A +S224FE34A001C308380005C581660000564A3801BB66046100FBA24AB801DA670000AA610009 +S224FE34C0FC44660000426100FD864A3801C3660000366100FF084A3801C36600002A61009C +S224FE34E0FE62660000227000303801EAD1B801DE91B801DA80F801B048C0D1B801D6609809 +S224FE350011FCFFFC01C3533801EE6F00005A103801C30C00FFF967260C00FFF867200C0066 +S224FE3520FFF7671A0C00FFFA67100C00FFF4660000360C38000301EE6C04423801C2303CAB +S224FE3540FFFF51C8FFFE523801FF103801FF0200001F670A0C38000501EE6600FF426100B0 +S224FE3560FB046000FF3A1038C583020000F011C0C583103801C34E75225F261F321F7000BF +S224FE358003C011C001BAE90911C101F42F09423801BB11FC000101B811FC001301B931FCE4 +S224FE35A0020001B031FC004001B431FC004801B631FC177001B242780200427801BC4278B3 +S224FE35C001BE6100FCF6722F484108380005C581673441FAF94F6100CE346100CE0C6008FD +S224FE35E008380005C581671E6100CF0A670A6100CF0C0C0000516704538166E411FCFFFCE3 +S224FE360001C36000FF6270FF08380005C58156C8FFF86700001248410C41002F57C04841F5 +S224FE36204A0066AE60BA223C00000000722F484108380000C58167146100CEBA670A6100CB +S224FE3640CEBC0C00005167B4538166E442A741F804002F08203C000004002F006100FE1CE0 +S224FE36606600FF047010B6806D2E204343F8060076002211B290660A22290004B2A80004E1 +S224FE36806716D2FC00205243B67C00106DE411FC000101C36000FED0873801F4E54B41F877 +S224FE36A0040031F0300001BC31F0300201BE11E801F601B911E801F701B831E801F801B0CC +S224FE36C031E801FA01B431E801FC01B631E801FE01B2D0FC004043F80200701F22D851C89B +S224FE36E0FFFC6000FE822C5F11EF0004010508F800010105422F00046100CF6246FC2700E0 +S224FE370011FC0025C073423801046100CCDC41FAF7EB6100CCF86100CCD06100FE5C665207 +S224FE372042A7307C04002F082F086100FD4E661C307C04000C58424F662E0C584F54662883 +S224FE37407000103801F43F002F0E4ED06100CC9A103801C3440041FAF6056100CCB0610094 +S224FE3760CCBA6100CC844ED641FAF6016100CC9E60F00C38000101C366D26100CC6C41FA89 +S224FE3780F7936100CC8841F801F66100CC8060D2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 +S224FE37A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 +S224FE37C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 +S224FE37E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 +S224FE3800FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 +S224FE3820FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +S224FE3840FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 +S224FE3860FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 +S224FE3880FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +S224FE38A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +S224FE38C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +S224FE38E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 +S224FE3900FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 +S224FE3920FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 +S224FE3940FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +S224FE3960FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +S224FE3980FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +S224FE39A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +S224FE39C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +S224FE39E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +S224FE3A00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +S224FE3A20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +S224FE3A40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +S224FE3A60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +S224FE3A80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +S224FE3AA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +S224FE3AC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +S224FE3AE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +S224FE3B00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +S224FE3B20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +S224FE3B40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +S224FE3B60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +S224FE3B80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +S224FE3BA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +S224FE3BC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +S224FE3BE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +S224FE3C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +S224FE3C20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +S224FE3C40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +S224FE3C60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +S224FE3C80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +S224FE3CA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +S224FE3CC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +S224FE3CE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +S224FE3D00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +S224FE3D20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +S224FE3D40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +S224FE3D60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +S224FE3D80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +S224FE3DA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +S224FE3DC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +S224FE3DE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +S224FE3E00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +S224FE3E20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +S224FE3E40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +S224FE3E60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +S224FE3E80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +S224FE3EA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +S224FE3EC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +S224FE3EE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +S224FE3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +S224FE3F20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +S224FE3F40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +S224FE3F60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +S224FE3F80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +S224FE3FA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +S224FE3FC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +S224FE3FE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +S804FE0000FD diff --git a/SAGE/FILES/v2-3.hex b/SAGE/FILES/v2-3.hex new file mode 100644 index 00000000..0f5c4d02 --- /dev/null +++ b/SAGE/FILES/v2-3.hex @@ -0,0 +1,514 @@ +S00B000076322D332E68657884 +S224FE00000000040000FE0044600004F8600004EC600009646000044E600003F8600003D0DE +S224FE0020600003FE60000404600029A8600029AA6000033A43380203600002FC6000344839 +S224FE0040600037104E704FF8040011FC0092C02711FC0038C02511FC0092C06711FC003139 +S224FE0060C065700072FF343C42D741F8C0FE3080308151CAFFFA43F8000045F87FFE343C1D +S224FE0080344230113010301251CAFFF8343C06C541F8C00172084A10D0FC001051C9FFF81C +S224FE00A051CAFFEE43FA0006600002C649FA2D0B4BFA000660002C0441FA00362278000861 +S224FE00C021C80008B1F80008662E11FC0090C58711FC0090C50711FC0000C58311FC00CD66 +S224FE00E0C50311FC0000C58511FC0005C50560044FF8040021C900081038C0216B64E6087B +S224FE010002400006303B00064EFB000200180024001800084238010449FA2DB74BFA085831 +S224FE012060002B9849FA2DBB4BFA003860002B8C49FA2DBE4BFA000660002B8074FF720071 +S224FE014070001038C023460008000002670272FFE308024000064840204030C151CAFFFCB5 +S224FE016060DA41FAFE9C343C1FFF42004201D018D21851CAFFFA4A00671449FA2D394BFAC1 +S224FE0180000660002B364A38C0216A0001004A01671449FA2D2F4BFA000660002B1E4A38EC +S224FE01A0C0216A0000E811FC0001C067307C000072014841323CFFFE224145FA00066000B9 +S224FE01C02A3A664647FA000C21CB000808F80002C5034FF8040047FA002421CB00087202E9 +S224FE01E04841D3C1303CA5A53280B051660E46403280B05166064640D3C160EC4FF80400AC +S224FE020093C145FA0006600029F267084A38C0216A00007A303C00BF41F80100429851C8B9 +S224FE0220FFFC548921C901004E6121C9014A21C9014243FA000C21C9000808B80002C50322 +S224FE02404FF804006100041C11FC0000C0674A38C0216B1611FC0007C06770FF51C8FFFEF7 +S224FE026011FC0006C0676000FEFA6100018241FA2B2B6100019E30380100ED486100021C57 +S224FE0280704B610001E06100016660044E7227007228740208380006C0216702725011C216 +S224FE02A001C611C101C7423801CA11C201CE11C101CF11FC000101D27206610000FE42381F +S224FE02C001BA2278000841FA003021C8000811FC00AAC58311FC0005C5050C3800AAC58351 +S224FE02E0661611FC0000C58350F801BA31FC027001F011FC008001F54FF8040021C90008D7 +S224FE03001038C021C07C0030670CB07C00206724B07C0010672621F80100014A21F80100B3 +S224FE0320014231FC2700014E41FA004221C801466000064442676100280860DA4A3801BACC +S224FE034067D4203801004840720C92406F12C2FC000A5341303C6F9A51C8FFFE51C9FFF6B7 +S224FE0360426770012F006100356660AA4E4F60FC41F8C0734200108011FC0076C007E018B2 +S224FE038010801238C021E0181080706E080100036702707E10BC00400241000711FB101450 +S224FE03A0C003108011FC0000C003E01810BC00254ED1028040201008040241F8C033424061 +S224FE03C0108011FC00B6C007E018108011FB10E4C005E018108011C0C005E01810BC004091 +S224FE03E0E01810BC004EE01810BC00274E752F00700D6170700A616C4200616861666164DF +S224FE040061626160201F4E752F0070206156201F4E753F0010186704614A60F8301F4E75F4 +S224FE0420E9186126E91861224E752F017203E958611851C9FFFA221F4E752F017207E9984A +S224FE0440610851C9FFFA221F4E753F000200000FB03C0009630406000007060000306104C5 +S224FE0460301F4E754A380104662C3F01323CFFFF08380002C07356C9FFF8670811C0C071A6 +S224FE0480321F4E7548E7C0C043FA00066000FEE24CDF030360D64E4A4E7548E7F0007200C0 +S224FE04A032007400343C2710420382C266044A0367061001619450C34241484184FC000A90 +S224FE04C066E84CDF000F4E754A38010466282F011238C0730801000167F61038C071020129 +S224FE04E000386604221F4E7511FC0035C07370076100FF7260DA4E494E7508380001C0738D +S224FE05004E7561C4088000070C0000616D0A0C00007A6E04088000054E7521C001067002DB +S224FE0520604E21C001067004604621C001067006603E21C001067008603621C00106700AB4 +S224FE0540602E21C00106700C602621C00106700E601E21C001067010601621C001067012F4 +S224FE0560600E21C001067014600621C00106701648F87FFE010A4E6821C8014A2A00701668 +S224FE0580BA806270BA3C00046206381F261F341F31DF014E21DF014621CF01424FF80400D7 +S224FE05A00C0500146700199A6E0018B80C050012661E11FC0001C06711FC0000C0674A3829 +S224FE05C001BA670C08F80002C50308B80002C50370FFE01851C8FFFC46FC270011FC00386D +S224FE05E0C02508B8000601504238010443FA000A6000FD7E428560A849FA27164BFA0006C1 +S224FE0600600026B849FA2990D8F450004BFA000460EE49FA29964BFA000460E420380146BC +S224FE0620610017F66100FDC80C0500046200034841FA29FE6100FDDC30046100FDEE41FA0A +S224FE064029FB6100FDCE20036100FDF041FA29F86100FDC030026100FDD26100FD926000AA +S224FE0660031641F8000843FA268045FAF9944280301967186B06D08A20C060F24241120052 +S224FE06803019D08A20C051C9FFFC60E24E75225F02800000000FD080D089C1893251D3C09F +S224FE06A04ED148E780B02478000847FA001421CB0008101121CA00084CDF0D01B0004E750C +S224FE06C0508F321F46C141FA26586100FD46588F20096100174421CA00084CDF0D0100008B +S224FE06E000014E7508380001C0734E752F00703A6100FD72201F6100FD104E752F00702C18 +S224FE07006100FD62201F4E752F0070076100FD56201F4E75C03C007F0C0000206D060C0092 +S224FE0720007E6D02702E4E752F092F01224842816100FDD00C00001B6700006E0C0000128B +S224FE0740670000680C00000D674A0C000008661AB3C867DC6100FD0E6100FCAE6100FD06D0 +S224FE076051C9FFF25389528260C40C00007F6614B3C867BC61585389528210116100FCE627 +S224FE0780544160AC611A428153826B0812C06100FCD4609C610A421912C0221F225F4E7513 +S224FE07A08281673C4281602C224842812F0870236100FCB26100FC38B3C86700000C101890 +S224FE07C06100FCA2B3C866F6205F6000FF648281660E72013F00103C005C6100FC88301FF9 +S224FE07E04E75428010188000660253884E7561F28000670A0C00002067040C00002C4E75ED +S224FE080061E067080C00002067F653884E7561D2244942411219B011568957C9FFFA660091 +S224FE082001481021E1581021D4C04ED248E7180042817801E89C61B667540C00002F660E95 +S224FE0840383C33334844383C333461A26740040000306D380C0000096F144A04662E040053 +S224FE086000070C00000A6D240C00000F6E1E26014A046708E799E39BD2836002E999B684CB +S224FE0880640AD280848267C2B48164BE72FFC1414CDF00184E752F036100FF66428395CA7A +S224FE08A06100FF4C670000480C00002367360C0000246708347801525388602A6100FF307B +S224FE08C06700002C0400003065240C000003641E244093C96100FF18670000180C00002B46 +S224FE08E0660C6002528342826100FF42670257832240D5CAD5CAD4FC0154D3D2201FC143F6 +S224FE090080804E752F0242826100FEF6670000520C000027671C0C00002E674624016100EB +S224FE0920FF0C6B06241F92814E75241F428153814E756100FEAE6100FEAA670000200C00D9 +S224FE094000276712E19A4A0266E0D480828167E6B28264E260D46100FE9666CEC14260C445 +S224FE09607001241F22004E756100FA9E703F6100FAF46100FD944FF8040042B801546100F7 +S224FE0980FA6E0838000601506700000870546100FAD436380152670C70246100FAC81003F5 +S224FE09A06100FAA8703E6100FABC742841F801886100FD7643FA1A686100FE5460B843FA73 +S224FE09C01A8C6000FE4A6100FE382838017E387801821010670E6100FEBE668C2809284AD6 +S224FE09E031CA01826100FE1A327C01001010670A6100FEA46B00FF726704D3C45389528925 +S224FE0A0021C9017E2A09611C6718280B6100FCD667F46100FAEE0C00001367F60C000003A6 +S224FE0A2066E44E756100F9C820046100FA0EB8FC0154670C6100F9D2200490946100F9FCB1 +S224FE0A406100FCAA760F2644C7496100FC56C7496600FF16101B6100F9C808030000660091 +S224FE0A6000066100F9A4BA8B57CBFFDE6100F99A760F2644101B6100FC9C6100F9E8BA8B9D +S224FE0A8057CBFFF24E7543F80154323C20247402601443F80126323C2041600843F8010676 +S224FE0AA0323C204474076100FD3A671A903C00306B00FEB678001800B8026E00FEAC6122CD +S224FE0AC06100F92C4E754284611852846100F93A0C04000466046100F9306130B8026DEA77 +S224FE0AE04E756100F90A42833001E0880C000020670000066100F96E10016100F968868331 +S224FE0B00660610046100F9446100FBE22004E5800280000000FF4A836A4230310000610031 +S224FE0B20F90A0C415352663C48E7704036006100F8D870286100F92E428243FA18D214199D +S224FE0B40670E1019E57B650270206100F91860EE4CDF020E70296100F90C600820310000EA +S224FE0B606100F8D84E756100FC7A6600FDFC6100FF226100FF2861186108614861046134B9 +S224FE0B804E756100F8846100F8804E756000F86061FA103C00506100F8CC103C0043610052 +S224FE0BA0F8C46100FB4820380146307801526000126861D876FF43F8014E223C0000535223 +S224FE0BC0600E61C843F8014A223C00005553760142846100FF144E757C0060000C2C7000F7 +S224FE0BE072104A10670A6100FC446B00FD7C12006100000E5200B0016DF66100F7F24E752C +S224FE0C006100F7EC41FA00206100F8086100F83C41FA001B3438017C0102670441FA001B39 +S224FE0C206100F7F04E755452415020230020204E6F207472616365200020205472616365B1 +S224FE0C4020202020000043FA18A26000FBC26100FCB46600FD142A006100FCAA6600FD0AD7 +S224FE0C602800D0856100F7882200103C002B614822059284103C002D613E2205C2C4103C84 +S224FE0C80002A61344A446746220582C4103C002F61186132103C00726100F7CA103C0065D2 +S224FE0CA06100F7C2103C006D48416100F7B86100FA3C30016000F7746100F7AA6100FA2EA7 +S224FE0CC020016100F7766100F7406000F73C4E757C106100FB2C2838017E387801821010EE +S224FE0CE067106100FBB26600FC802809284A31CA01826100FB0C327C00141010670C7CFF31 +S224FE0D006100FB946B00FC6267062C096B00FC5A52892A092C446100F6D6200E6100F71C67 +S224FE0D20B8FC0154670C6100F6E0200E90946100F70A6100F9B848E7060061304CDF0060E6 +S224FE0D4021CE017E4A866B065386671E2A0EBA8E650000186100F98E67BC6100F7A60C0071 +S224FE0D60001367F60C00000366AC4E75300EE2086500FBF67C07610006F03E00E9586100E4 +S224FE0D80F90E0020010001080104014003880428046E0512060606CC053A05A6060606526D +S224FE0DA006CC08070008664E43FA176C3207E049E249610006F659016F5E040100106758EE +S224FE0DC0580166064245611C60063A07610006C4610006FC6100070216076100F9206100B0 +S224FE0DE007364E75428543FA171E3207EC5902410003600006B63007020000380C00000852 +S224FE0E0067367042610006AE61DA610006C23607EC5B6100072860C030070200003F0C004F +S224FE0E20003C66A64282263A084C080700066704263A0846600000F2203A082A6100067606 +S224FE0E407050610006703A07E35D08C500066100064E6100067A08070007670A61126100B3 +S224FE0E60F89C61144E7561106100F89261024E753607EC5B600006C6360708C30005600004 +S224FE0E800696428560067A4060027AFF203A07D6610006223007EC580200000753006606EE +S224FE0EA0704161000610610005F6610006223607610006646100F8463607EC5B610006642C +S224FE0EC04E7508070008660002043007EF580240000732006100F7B8001000320014001C4E +S224FE0EE0007C011800B201527401600A263A0786428260064282263A0780283A07683007AC +S224FE0F00020000C00C0000C0671843FA16366100059A3A076100057C610005B4610005F69F +S224FE0F204E7520046100058E7A40610005A228034A026614610005DE4A84670A6100F7BE87 +S224FE0F402004610005704E7561F66100F7B0610005C44E753207E6590241000708070007AD +S224FE0F606624203A071808070006670C203A07124A016604203A070E6100053A61000550F6 +S224FE0F80610005924E754A016756203A06D861000524704D3A07E35D08C50006610005163C +S224FE0FA0610004FC610005287A40610004BC31C001880807000A661E6100000C6100F73E4A +S224FE0FC0610005524E7570236100F49A303801886100F4584E7561E86100F72261E84E75E1 +S224FE0FE0203A06AA08070006678E203A069C60880C0700FC6612203A0698610004B8203A00 +S224FE10000694610004B04E753A07024500C00C4500C0670A3005E2588A406000FEEE283AAA +S224FE10200678428242836000FED608070007660000983207E6590201000714010C010006B4 +S224FE104067520C0100036F14263A065E024200010247000F004700C86000FEA043FA14FC86 +S224FE10606100044861000468E20A660E70236100F3F430076100F3D44E753607E75B6100B6 +S224FE108004C008070003660A6100F6727A40610004484E75320702410007340143FA14CC3F +S224FE10A0610004080C020002660A610004227A406100042670544A02670870560C0200061B +S224FE10C066046100F3A04E754280600270023207EC59C27C0001D2407A4043FA14AE61006D +S224FE10E003CA610003EA6100042C0807000867186100F60A3607EF5B7020080700066702B5 +S224FE11007028B143610004104E753207020100C00C0100C0673E203A058808070008670431 +S224FE1120203A05826100038E3A07610003666100039E70236100F32E3007EF580200000730 +S224FE11404A00660270086100F3026100F5B0610003C44E7570533807020400380C040008C3 +S224FE1160660808870003303C4442611C610003A60C04000866106100F5847A40610003600D +S224FE11803440610003FA4E7543FA1440610003263207EE5902810000001ED3C142803011E4 +S224FE11A061000312610003284E757A40320702410F000C410100670A704243FA13EE61CC46 +S224FE11C0600C203A04D8610002EC6100030230074A0067106100F24AE158E040548E61087C +S224FE11E0558E4E75610002F83440610003924E750807000866000258203A046A610002B606 +S224FE12007051610002B0610002C670236100F25610076100F20C6100F4E43607EC5B6100FE +S224FE1220031C4E753A0743FA13C2612208070008670C61106100F4C6610002DA4E7561F884 +S224FE12406100F4BA3607EC5B610002F24E753207E95902410007610002524A45670461000B +S224FE126002326100026A4E75428560023A0743FA139A61DA3607E75B61086100F48036071E +S224FE1280EC5B080700036606610002B24E75610002C04E753007024001F00C40010067C8E2 +S224FE12A0EC4872045740670859406600FF787205088700068E7C41006000FE1E3007EC58B7 +S224FE12C00240000755406F00FF5C43FA133E7A4053406706E35D594066166100FF72610093 +S224FE12E002346100F4183607EC5B610002544E75044710003007024000380C400008660084 +S224FE1300FF24203A03A8610001AC3A0761000184610001BC3607E75B61086100F3E03607F6 +S224FE1320EC5B610002264E753007024001F878000C400140671078030C4001486708780230 +S224FE13400C4001886624203A0368610001686100017E3607EC5B61086100F3A23607E75B5A +S224FE1360E21C650001DC600001D4E8480C0000106700FEF67206E44857406700FF34720700 +S224FE1380594067F66000FE9E3007024000C00C4000C067123007024001300C40010067003C +S224FE13A0FECC6000FE803A07E25D43FA12563207E55902410001610000F2610000E26100AB +S224FE13C0010E610001506100F3343607EC5B610001704E7532073A07024500C00C4500C016 +S224FE13E06744E6596150610000AA610000E2360702430E00080700056708EC5B6100013E07 +S224FE1400601670236100F05E3003EF580200000F660270086100F0346100F2E23607E75B6D +S224FE14206100011A4E75EF59610C4285610000A0610000E24E750241000334070242010021 +S224FE1440EC5A824243FA11DC610000604E75702E61000062203A02126100005A6100007076 +S224FE146030076100EFC64E752F09224E6100F2346600F4F6301E225F4E752F09224E61003F +S224FE1480F2226600F4E454896100F218201E225F4E75024500C00C05008066027AC03205BC +S224FE14A0EC590201000343FA108AE519024100FF203110002F017203E1984A00670000088F +S224FE14C06100EFA2530651C9FFF0221F4E756100EF3851CEFFFA4E7570236100EF883205AC +S224FE14E0EC59C27C0003B23C000267206100FF7A53016C066100EF2A4E756100EF2E53013D +S224FE15006D086100FF646100EF224E75703F6100EF544E7536071003E60802000007E70B0B +S224FE152086001003024000076100F164001000140018001E00240076008000C672446014AC +S224FE154072416010223A0112600A223A01106004223A010E7403E1991001671C6100EF0675 +S224FE15600C00004467060C000041660C3003E618020000076100EED451CAFFDC4E75705B0B +S224FE15806100EEE2D5CE200A558030780152D1C8D1C890A801546100EEA2705D6100EEC6E8 +S224FE15A04E756100FEC46100EE8260986100FEBA38006100EE6C70286100EEAA6182610098 +S224FE15C0F13C3604EF5B0804000F66066100FF6E60046100FF6C702E6100EE8A7057080488 +S224FE15E0000B6702704C6100EE7C70296100EE764E75E61BC63C000710036100F0920012BA +S224FE1600001C0026003E00540010001000104E756100FE566100EE144E756100FE5E610007 +S224FE1620EE1A4E756100FE4234406100EDFE223A003C6100FF206100FF464E756100FE2A71 +S224FE164038006100EDDC203A00286100FE686000FF6E6100FE844E75284129002841292B1A +S224FE16602D2841294D4F5645574F5244285043292850430043435200535200004E42434402 +S224FE168050454100535741504558544C45585457494C4C4547414C005441530042535200E8 +S224FE16A0414444515355425155535000434D504D4558470043FA0DB56000F1546100F1D8FB +S224FE16C06600F2A660046100F0402809284A2A0454856100F3506100F01441F80188243C3F +S224FE16E0000000286100F042428110106716223C0000FFFF6100F20E6BCC6E0A134000010C +S224FE1700E080128054890C01002E66BE4E7543F80154323C202474037A01601643F80126C9 +S224FE1720323C2041600843F80106323C2044740842856100F0AE671A903C00306B00F22A15 +S224FE1740B0056B00F224B0026C00F21E4282610E4E75200561085280B0026DF84E7542832D +S224FE17602F023A0128002C00E5864A82660E6100F0904A10662260046100EF8E320561005E +S224FE1780EC6E6100F3646100EF64742841F801886100EF961010672042816100F1686BD8D5 +S224FE17A0660000160286000000FF86836A063380600060042380600032051004241F4E75DF +S224FE17C06100F0206600F1A26100FF526100FF586106611E610E4E7543F80146323C504397 +S224FE17E06000001843F8014E323C535276FF6000000C43F8014A323C555376014282428057 +S224FE18006100FF5E4E757CFF7A0142806100EFD467144486903C00306B00F14EB03C000190 +S224FE18206E00F1463A00360060046100EEDC3643D7CB284BD7CB4A866B0A675A6100EFC2B9 +S224FE18404A106614616A6100EEA4742841F801886100EED66100EFAA101067320C00002E83 +S224FE1860660607B8015060266100F02C6BBC6100EF90243C0000FFFF6100EFB26BAC426CBA +S224FE188001723940017607F80150274901605243B6456F9A4E75611860F4427265616B7043 +S224FE18A06F696E742000496E61637469766500006100EB3C41FAFFE46100EB58100361005A +S224FE18C0EB8A6100EE2807380150660A41FAFFD86100EB404E75202B01606100EB5E610001 +S224FE18E0EB2870286100EB7E302C01766100EB3C6100EE0A302C01726100EB307029610077 +S224FE1900EB644E75760078104A10671C6100EF1E6B00F056160018006100EEE60C000054F5 +S224FE192067460C00004E67386100EAC441FA004C6100EAE010036100F2C86100EDB0742875 +S224FE194041F801886100EDE26100EEB667240C00005467140C00004E67066100EDAC60C83E +S224FE19603238017C078160063238017C07C131C1017C5203B6046DBC4E752854297261639B +S224FE198065206F7220284E296F2074726163650043FA0AF86000EE78243C000000FF616C50 +S224FE19A06600EFC61A00E1401005600C243C0000FFFF61586600EFB23A00484030056008D0 +S224FE19C0428261486600EFA241FA14AA6100EA4461000942E19812C0538466F821CA0008F9 +S224FE19E04E7548E7F0006100EEAE661A28096100EEA62449C9896B0E6E0698895284600458 +S224FE1A00D5C9538A42804CDF000F4E7561D4660622026100EEF04E7561F266142C009887AA +S224FE1A206D00EF4670FF4A10670A22026100EED66600EF3641FA15266100E9D8610008D61C +S224FE1A404E7543FA0AB46000EDC6243C000000FF7E0161C41219C200B206670453846CF468 +S224FE1A606100009660F6243C0000FFFF7E0261A81219E1991211C240B246670453846CF0CF +S224FE1A806100007660F642827E04618C2649548B1219E1991211E199121BE1991213C28045 +S224FE1AA0B286670453846CE86100004E60F66100FF326600EEB448E708606100FF26660033 +S224FE1AC0EEA82A492C044CDF0610C34D41FA148E6100E9406100083E9C8465182849528982 +S224FE1AE02E04264D121CB21B6606538766F6610853866CE861024E7148E7FE7E663E41FA5F +S224FE1B00146B6100E90E538920096100030C6100EBDC7203E198101951C9FFFA6100E91CBE +S224FE1B2041FA14556100E8EC6100E9D80C00004366126100E9304CDF7E7F4E7541FA140D1F +S224FE1B406100E8D04CDF7E7F21CA00086000EE286100E8B66100E8B243FA093A6000ECB062 +S224FE1B6043FA093C6000ECA86100ED2C6600EDFA20096100E8C66100EB7410116100E8A221 +S224FE1B804E756100ED126600EDE03C09080600006600EDD620096100E8A26100EB5030117F +S224FE1BA06100E8884E7543FA08FD6000EC626100ECE66600EDB4223C000000FF6100ED4673 +S224FE1BC06600EDA612804E756100ECCC6600ED9A3C09080600006600ED90223C0000FFFF1C +S224FE1BE06100ED226600ED8232804E756100EC1274076100EC386B00ED7022006000E7BCDC +S224FE1C0043FA08AA6000EC086100006443FA07B654894A516700ED523014C059B05966F0E5 +S224FE1C20D8D121CC016808F80002015008F800040150600261387401610001BA426A01724F +S224FE1C4051CAFFF66002612608B80005015008F80006015008F80007015010380150020028 +S224FE1C600007660608B800060150600001506100EB901010670C6100EC1E6600ECEC21C924 +S224FE1C80014661066100E7684E752C380146284608060000671241FA001C6100E776200645 +S224FE1CA0610001766000ECD0224C6100E9F66600ECB84E75496C6C6567616C2070726F6720 +S224FE1CC072616D20737461727420616464726573733A20006100E71843FA07DC6000EB3018 +S224FE1CE0083800060150670461A0604E4E7508F8000501506040619208B8000301500C1054 +S224FE1D000049660808F80003015052887005083800050150660270104A10670E747F6100C5 +S224FE1D20EAE06100EB086B00EC406100E6C2600C08B8000501506100FF36700111C0015136 +S224FE1D4008F80006015008B80007015030140240FFF00C404E406664301C0240000F3C38E7 +S224FE1D60017C41FA002C0106661C21CC016808F80007015008F80002015008B800040150DD +S224FE1D80673A41FA00216100E68A6100E662602C2A2A2A2054726163696E67205452415080 +S224FE1DA0202A2A2A002A2A2A204753207465726D696E61746564202A2A2A00002878014678 +S224FE1DC03C38014E08380006015066060886000F600408C6000F2078014A4E602E780142E2 +S224FE1DE02F0C3F064CF87FFF01064E7308B8000601504E7542803242D3C92449D3C90538E4 +S224FE1E000150670E226901606100E8986600000652804E7553804E756100E6203078015233 +S224FE1E20D0C8D0C84A780152672E6100E5DC2F0070286100E63070246100E62A30380152A5 +S224FE1E406100E6086100E8A6201F90A801546100E5EA70296100E60E4E7554726163653A6B +S224FE1E6020000838000601506700FF52083800070150672608B80006015074006100FF766A +S224FE1E806B00EAE667083551016C32BC4E4F52420C42000366E66000FF2441FAFFBE203813 +S224FE1EA0014621C0017E6100E56A28406100FF6AD0FC015431C801826100E832224C6100AF +S224FE1EC0E7E2661430116100E5626100E53C6100E5382C496100EE96083800050150670A72 +S224FE1EE041F8018842106100EC7E533801516F1E083800030150671A6100E7EA6714610073 +S224FE1F00E6020C00001367F60C00000366046000EA666100E4DA6000FE280D0A556E6578D5 +S224FE1F2070656374656420627265616B20706F696E743A2000000D0A427265616B3A20000A +S224FE1F4042854286283801465584760041FAFFCC74026100FEA06F32B3C4661E41FAFFD8D0 +S224FE1F6076020C02000267123A2A01723C2A0176BC4567065245354501720C514E4F670650 +S224FE1F8005B80150600432AA016C51CAFFC60838000201506728B8B80168662208B800025E +S224FE1FA0015008B800040150661421C4014608F80006015008B8000701506000FEA6203847 +S224FE1FC00146908321C00146BC456600FC824A436600FED028440C544E4F6600FEC620041F +S224FE1FE06000FEC043FA04E46000E82411FC000101BB6004423801BB41FA0E8E6100E4149B +S224FE20006076428574016100E8246B00E95C3C00243C0000FFFF6100E8146B00E94C3F00B8 +S224FE20206100E8746600E9422F0942826100E7FE6B00E9362F003F064A85670E41FA0E572B +S224FE20406100E3D061000992600C41FA0E3C6100E3C26100097E6700000E41FA000C610071 +S224FE2060E3B26100E3BC4E750D0A4469736B206572726F723A20000061740C000051670026 +S224FE208000C00C00005366F0420561621E00610000BC1C0153064281610000B2610000AE28 +S224FE20A026410C070030660E4A0667066100009E60F6617460C20C0700326614220B6100A9 +S224FE20C0008C26414A0667EA6100008216C160F40C07003167EE0C07003966644A06666096 +S224FE20E0614641FA0C4F6100E32A6000E88A4A3801BB672408380001C033670A1038C031B9 +S224FE2100088000074E756100E3F267E26100E3F40C00005166D84E756100E3AE0C00000D4A +S224FE21206700E2CC6000E33E6122460566024E75588F41FA0C216100E2DA6000E83A508F40 +S224FE214041FA0BFD6100E2CC6000E82C61086106DA0153064E7561960C0000306DE00C0063 +S224FE216000396E0A04000030E989D2004E750C0000416DCA0C0000466EC45F0060E643FA86 +S224FE218003436000E68A7A016000FE7A6000E7E843FA03426000E678202053797374656D9F +S224FE21A0207265696E697469616C697A696E672E2E2E2E0046FC270011FC0025C07342381A +S224FE21C0010441FAFFD46100E24A70FF51C8FFFE6000DE724280428710100C0000526606B2 +S224FE21E03E3C010052881010670A74016100E63E6B00E77680473F00610009464E754A3839 +S224FE220001BA6700E764428042877C0110100C00005266063E3C010052881010675C0C0018 +S224FE222000206714040000306D00E73E0C0000036E00E7368E0052886100E5C64A00673A41 +S224FE22400C0000236600001652884A10672C740F6100E5DA6B00E7123C00601E740743F892 +S224FE226001F62C09429142A90004422900086100E572670612C051CAFFF63F072F06610017 +S224FE2280164E4E754E7574186100E16451CAFFFA4E7543FAE2D621C9002443FAE2C621C976 +S224FE22A000BC4E7542801010670A74026100E57E6B00E6B631C00152E540D07C015431C00D +S224FE22C001824E756100E5D06600E69E28096100E5C66B00E694C98966049889600253847D +S224FE22E06500E68626496100E5AE6600E67C41FA0BB26100E11E7201B7C96406D3C4D7C4F8 +S224FE230072FF61101293D3C1D7C153846CF621CA00084E752478000849FA000821CC000834 +S224FE23204E7541FA09FC6100E0EA548F201F6100FAE821CA00086000E63E43FA01B560003D +S224FE2340E4CE3F3C00016002426774016100E4DE6B00E6163F00243C0000FFFF6100E4CE92 +S224FE23606B00E6063F00427801CC427801D411FC000101DB3F172F3C000004002F3C000094 +S224FE238010003F2F000C4A6F001067066100064A60046100063E662A702E6100E0C808F889 +S224FE23A0000101DB6100E15467CA6100E11C11FC0007C02711FC0009C027423801DB5C8FDF +S224FE23C04E75705860D4F0FF60000004F00060000002F0F850C80004FFB84E900002FFB844 +S224FE23E04EA80004FFB84EB00004FFBF4EB80004FFBF4EB90006FFBF4EBA0004FFBF4EBB03 +S224FE24000004FFF04E400002000000000000015402530958014E015A0156014300000E4494 +S224FE2420A0E55396F24672F52486FE4DA6FE5032F754B6F847E2F75760FD4CC6FB00C2F8DD +S224FE24404972FD4128E8451CFF5824F6094D7AE5521AE74450E64146E65044E75366E7553F +S224FE246076E7243AE6428CE75492E7094D51F25255F344BBF241B1F2506DF35379F35587E3 +S224FE2480F324A3F2429BF35499F402420EF55722F54C36F50249CCF64F12F75358F7014266 +S224FE24A0CAF657E4F6014209F75723F7024F88F7439AF7535CF703427AF84536F95238F87D +S224FE24C04E40F80141C9FC46C3FC024122FB542AFB4638FB064600FD482AFD47B0FD53E036 +S224FE24E0FC568EE143B2FD54BEFD0144E6E75264E7015257FE5751FE034252F5576EF54C88 +S224FE25008EF54DB6F5005453540043484700434C5200534554004F524900414E44495355F5 +S224FE252042494144444942000000454F5249434D50492E4200002E5700002E3F00002E4C85 +S224FE254000004E454758434C52004E4547004E4F54000000000054535400545241505452C2 +S224FE256041504C494E4B554E4C4B524553454E4F500053544F505254450034453734525488 +S224FE2580530054524150525452004A5352004A4D500043484B004C45410044495655444973 +S224FE25A056534D554C554D554C535241460048494C53434343534E45455156435653504CBF +S224FE25C04D4947454C5447544C455400460048494C53434343534E45455156435653504C1D +S224FE25E04D4947454C5447544C454F52000053554200454F5200434D5000414E4400414441 +S224FE260044005355424141444441534243445355425800000000434D504141424344414430 +S224FE26204458415352004C535200524F5852524F520041534C004C534C00524F584C524F35 +S224FE26404C0048E760401219143C00AD1038C0510800000756CAFFF6671A080000066614AE +S224FE266011D9C053740951CAFFFE530166DA4CDF02064E7511FC000101C560F248E7604046 +S224FE268043FA09D461BC6624720243F801C36174661A123801C3020100C0670C080100065B +S224FE26A0670472036002720211C101C54CDF02064E7548E76040720743F801BC421161449B +S224FE26C0663C123801BC020100C0672E0801000667267205103801BDE208651E7206E4080C +S224FE26E065187207E40865127208E208650C7209E4086506720A6002720211C101C54CDFC2 +S224FE270002064E75343C10FE1038C0510800000756CAFFF6671608000006671012F8C053D1 +S224FE2720740951CAFFFE530166DA4E7511FC000101C54E752F017002484008380000C06386 +S224FE27406612538066F411FC0002C02711FC000401C5600C4A02662012F8C053534166D6D9 +S224FE276011FC0001C02711FC0000C0276100FF44221F4A3801C54E7511D9C053534166B6D0 +S224FE278060DE48E76040720143FA08C96100FEB466387402484208380000C063660C53824D +S224FE27A066F411FC000401C56020422C00036100FECC67160C38000301C5660E0C2C005043 +S224FE27C00001660651C9FFC270034CDF02064E7548E760407202103801D6B02C0003674C51 +S224FE27E043F801B032BC030F42290002137801D600036100FE4E6634740248420838000091 +S224FE2800C063660C538266F411FC000401C5601C6100FE6A660A197801D600034200600C4C +S224FE28206100FF60660651C9FFAE70034CDF02064E750000000000000000423801C54A2C83 +S224FE284000006700010C3F077E0111FC000FC02711FC0000C02711FC0003C02743FA07F119 +S224FE286011FC000EC0276100FDDA663870064A2C00046702540011C0C02711FC000AC0271A +S224FE288070FF51C8FFFE08380000C06367086100FDEC423801C56100FEEA671C0C38000341 +S224FE28A001C5670451CFFFA43E1F70014E7570080838000001DB667070044840538066FCF5 +S224FE28C0197CFFFF000243FA07906100FD7666D4343CFFFE1038C0510800000756CAFFF694 +S224FE28E0660E11FC0002C02711FC000401C560B86100FDC066AE103801C1B02C00026708F3 +S224FE29006DC41940000260BE0C000008671A0C00000967100C000010673E0C00000A662686 +S224FE29207418600674206002742A0C38000201C26614397C02000006194000021942000513 +S224FE29403E1F42004E7511FC000901C56000FF5A11FC000B01C54E750C38000101C266E688 +S224FE2960397C01000006742060CE4A2C0000675A4281323C020082EC00064282343801DEE9 +S224FE2980C4C14281122C000284C14241082C000000006604E24AE31111C101D711C201D6D2 +S224FE29A0B42C00016C244842122C00029202C2EC0006B2B801E06F04223801E0520211C271 +S224FE29C001D831C101DC42004E7511FC000B01C54E75423801DA600611FC000101DA225F81 +S224FE29E049F801C6301F670449F801CE21DF01E021DF01E431DF01DE2F097E034A6C0006D8 +S224FE2A00660001146100FE34660000EA4AB801E0670000E211FC0003C0274A3801DA672C42 +S224FE2A2008380001C063670A11FC000C01C5600000C4102C0001E208B03801D66F0811FC51 +S224FE2A40000DC027600611FC000CC0276100FF1C660000A26100FD7A667443F801B0303C8B +S224FE2A6009454A3801DA6602524032C0103801D7E50812C012F801D612F801D712F801D837 +S224FE2A80302C0006E04812C012EC000212EC000512FC00FF43F801B06100FBA866302278A7 +S224FE2AA001E44281323801DC143801DA6100FC86661C303C032051C8FFFED3B801E493B838 +S224FE2AC001E082FC0200D37801DE6000FF400838000001DB663A5307671A103801C50C0018 +S224FE2AE000016700FF200C00000367080C0000046600FF1A0838000001DB661470074A2CBC +S224FE2B0000046702540011C0C02711FC000BC027103801C54E750838000101DB6600FEEEFA +S224FE2B2070064A2C00046702540011C0C02711FC000AC02770044840538066FC6000FECED2 +S224FE2B4011EF00040105422F0004427801CC427801D46100DB0E46FC270011FC0025C073C5 +S224FE2B60423801046100D88841FA02AB6100D8A46100D87C4267307C04002F082F083F2F63 +S224FE2B80000E6100FE4E6612307C04000C58424F663C0C584F5466364ED06100D852103824 +S224FE2BA001C50C000004673041FA01B96100D8646100D86E41FA01CA6100D858102C000495 +S224FE2BC06100D8886100D828205F548F4ED041FA01A16100D83E60DC41FA024F6100D834C7 +S224FE2BE06100D9206100D8080C0000516600FF5C41FA02646100D81C60BA26484280428116 +S224FE2C00468126804A93661C2681B293661C26CBB7C963EE2648B7D3660E588BB7C963F68D +S224FE2C2042804ED222006002220B201349FA015D4BFA0006600000842A0B4BFA000660001B +S224FE2C40008649FA01634BFA00066000006E2A004BFA00066000007049FA01524BFA000605 +S224FE2C60600000582A014BFA00066000005A49FA01F44BFA00066000004249FA01964BFA25 +S224FE2C8000066000003670014ED23E3CFFFF08380002C07356CFFFF8671411C6C0717E0EEC +S224FE2CA051CFFFFE08380002C07366024ED608780003C06551CFFFFE60F41C1C67064DFAEE +S224FE2CC0FFFA60C64ED57807E99D7C0FCC050C060009630406060007060600304DFA000432 +S224FE2CE060A851CCFFE44ED5051A0522052A80020532053A056A052A052A800B0542800614 +S224FE2D000552055A800E054A0562800F05420000070D0A455843455054494F4E3A20200099 +S224FE2D20070D0A204E4F204D656D6F72792061743A20000D0A4C6F616420446F6E65000789 +S224FE2D400D0A426164204C6F616420436861726163746572000742616420436865636B7386 +S224FE2D60756D00074472697665204572726F722000074E6F7420424F4F54204469736B00EC +S224FE2D80206F6E206472697665200007424144204D656D6F7279206174200052414D20530A +S224FE2DA0697A65203D2000206973200020696E7374656164206F6620000D0A5341474520BB +S224FE2DC0537461727475702054657374205B322E335D0D0A0A436F707972696768742031A7 +S224FE2DE039383320205361676520436F6D707574657220546563686E6F6C6F67790D0A4169 +S224FE2E006C6C205269676874732052657365727665640D0A00426F6F74696E672066726F96 +S224FE2E206D20466C6F7070790050757420696E20424F4F54206469736B20616E64207072E4 +S224FE2E406573732061206B6579202851202D207175697473290007426F6F742041626F7296 +S224FE2E60746564002028546573742041626F727465642900202046696C6C696E67206D6529 +S224FE2E806D6F72792E2E2E0020204C6F6164696E672E2E2E00202057726974696E672E2ED6 +S224FE2EA02E0020204D6F76696E67206D656D6F72792E2E2E000750524F4D20312042616431 +S224FE2EC00D0A000750524F4D2032204261640D0A00427970617373656420496E69740D0AFD +S224FE2EE0004C6F6F7065642054657374730D0A0052414D207772697465206C6F6F700D0A06 +S224FE2F0000426F6F74696E672066726F6D204861726420447269766500436F756C64206ECA +S224FE2F206F742066696E64200057616974696E6720666F7220447269766520526561647961 +S224FE2F40203C512D71756974733E000D0A4E6F204D6174636820666F756E6400202053650B +S224FE2F6061726368696E672E2E2E000D0A4D617463682061742000202D20436F6E74696EF7 +S224FE2F80756520736561726368202843203D20596573293F2000001F0027002B0033004712 +S224FE2FA00052005C006A007A008F204572726F722061742000556E6B6E6F776E0042757394 +S224FE2FC0004164647265737300496C6C6567616C20496E737472756374696F6E0041726990 +S224FE2FE074686D657469630050726976696C656765005265736572766564205452415000A2 +S224FE3000556E61737369676E6564205452415000556E61737369676E656420496E74657212 +S224FE3020727570740052414D205061726974790046756E6374696F6E3A2000202041636362 +S224FE30406573733A20002020496E73743A20000303D1070207000108024A00006100000CE7 +S224FE3060423801C250F801BB4E7548E71C0011FC0000C50708F80000C5037080740011C028 +S224FE3080C5C1723251C9FFFE7A046100004A967801F067226E1244430C4300026F18520208 +S224FE30A0671C530066D860160C4300026F085202670C520060EE51CDFFD250F801BB11C090 +S224FE30C001EF11FC0001C507303C174051C8FFFE4CDF00384E7511FC00B0C60711FC00008D +S224FE30E0C60511FC0000C605323C174051C9FFFE11FC0080C60776001638C605E15B1638DB +S224FE3100C605E15B444386FC000C31C301F24E75223801D67000103801B934004841B24094 +S224FE31206200006E484182C04841303801B0C4C0C0C142414841944048C231C001E820382E +S224FE314001DAB4806D0C944031C201EC31C001EA600831C201EA427801ECD27801BC6530CB +S224FE3160B27801BE622A43F8020030196708B2406504524160F431C101E27000103801B85A +S224FE318082C031C101E4484131C101E642004E7511FCFFF501C34E7511FCFFF201C34E759F +S224FE31A02F02343C07D008380001C58167305342672611FC000CC58772016100011C4A387C +S224FE31C001C3660000927014484008380000C58167D45380670260F270FD6000007611FC85 +S224FE31E0000DC587720A610000F04A3801C3660000667014484008380000C58167065380C2 +S224FE320067D660F208380001C58167CC343C07D008380001C5816728534267BC11FC000C34 +S224FE3220C5877201610000B24A3801C366287014484008380000C58167D65380679A60F2F0 +S224FE3240303C251C51C8FFFE4200427801C050F801C211C001C3241F4E7508380000C581BF +S224FE326066604A3801C266066100FF3666521038C585020000F8807801E611C0C585323896 +S224FE328001C0927801E467326E0A444111FC000DC587600611FC000CC5876100003C4A3895 +S224FE32A001C3661C72FFE01908380000C58157C9FFF6660E31F801E401C0700011C001C378 +S224FE32C04E7570FD60F61038C583020000F0803801BA11C0C5834E7548E7E000E3495341C5 +S224FE32E011FC0036C60711FC00B0C607303801B211C0C601E04811C0C601741851CAFFFE1A +S224FE330011C1C605E05911C1C605741851CAFFFE08B80000C503343C08EC51CAFFFE720C11 +S224FE3320484111FC0080C6071038C605E1581038C605E158670C6B0A538166E611FCFFFDFE +S224FE334001C308F80000C5034CDF00074E7543F8C7C1247801DE08F80007C50311FC000FC0 +S224FE3360C50711FC000DC50711FC000CC5074A114A1111FC0003C78311FC0041C7851011E8 +S224FE3380E148101131C001C4343801E8670853424A1151CAFFFC343801EA534214D151CA74 +S224FE33A0FFFC343801EC670853424A1151CAFFFC4A114A1108380000C7836610303801C45E +S224FE33C0B07801E2660E423801C34E7511FCFFF801C34E757400143801B880C231C001C072 +S224FE33E011FCFFF401C34E7511FC0002C50711FC0008C50708F80006C50308B80007C5032A +S224FE340011FC000DC50711FC000CC50711FC000EC50711FC0030C60711FC0070C60730383B +S224FE342001B411C0C601E04811C0C601303801B611C0C603E04811C0C60311FC000BC5071D +S224FE344011FC000AC50708F80001C50370FF08380004C58156C8FFF8660611FCFFFA01C379 +S224FE346008B80001C50311FC0008C50708F80006C50311FC0005C50708F80007C50311FC57 +S224FE3480000FC5074E75225F21DF01DA21DF01DE21DF01D62F096100FE2E4A3801BB66040C +S224FE34A06100FBBA5D8F0C38008001F56700010811FC000A01EE423801C308380005C5810E +S224FE34C0660000684A3801BB66046100FB904AB801DA6700026A6100FC3866000054610027 +S224FE34E0FD7A4A3801C3660000486100FEFC4A3801C36600003C6100FE56660000344A384A +S224FE350001F5670C6A0000E8423801F5610001FA7000303801EAD1B801DE91B801DA80F85A +S224FE352001B048C0D1B801D6608611FCFFFC01C3533801EE6F00005A103801C30C00FFF96A +S224FE354067260C00FFF867200C00FFF7671A0C00FFFA67100C00FFF4660001E40C380003C1 +S224FE356001EE6C04423801C2303CFFFF51C8FFFE523801FF103801FF0200001F670A0C3884 +S224FE3580000501EE6600FF306100FAE06000FF284A3801F567186A00011C423801F5102FB0 +S224FE35A0000011C001EF11C0C5C1600001920C00FFF86600018A11FC000101F51F7801EF7E +S224FE35C0000011FC000A01EF11F801EFC5C1422F00021F7C000100011F7C00020003423838 +S224FE35E001EE303C257F51C8FFFE6000FECA102F00010C0000016700007A0C0000036700E7 +S224FE36000086102F00026604502F000352001F4000020C0000056D00009C0C2F00020001E9 +S224FE3620671E103801EF1F400005902F00046500006AE208D02F000411C001EF6000006264 +S224FE36401F7801EF000411FC00F501EF1F7C00030001303C257F51C8FFFE1F7C0002000385 +S224FE3660422F000211F801EFC5C1423801EE6000FE460438000F01EF6404423801EF1F7CA0 +S224FE36800002000160D40638000F01EF640450F801EF1F7C0004000160C011EF000001EF63 +S224FE36A011F801EFC5C150F801F511FC000A01EE6000FDFE532F0003670E423801EE11F87D +S224FE36C001EFC5C16000FDF0422F00021F7C00020003102F00010C0000026D2267180C00A9 +S224FE36E000036708533801EF67B060CE0438000A01EF65A660C4523801EF659E60BC063859 +S224FE3700000A01EF659460B248E75000303C258051C8FFFE11FC0000C507705051C8FFFE4C +S224FE37206100F9B431F801F201F011FC0001C507303C257F51C8FFFE4CDF000A4E7510382B +S224FE3740C583020000F011C0C5835C8F103801C34E75225F261F321F700003C011C001BA83 +S224FE3760E90911C101F42F09423801BB11FC000101B811FC001301B931FC020001B031FC71 +S224FE3780004001B431FC004801B631FC177001B242780200427801BC427801BE6100FB286E +S224FE37A0722F484108380005C581673441FAF77B6100CC606100CC38600808380005C58124 +S224FE37C0671E6100CD36670A6100CD380C0000516704538166E411FCFFFC01C3600000DE36 +S224FE37E070FF08380005C58156C8FFF86700001248410C41002F57C048414A0066AE60BA21 +S224FE3800223C00000000722F484108380000C58167146100CCE6670A6100CCE80C00005126 +S224FE382067B4538166E442A741F804002F08203C000004002F006100FC4E6600008070104F +S224FE3840B6806D2E204343F8060076002211B290660A22290004B2A800046716D2FC00207D +S224FE38605243B67C00106DE411FC000101C36000004C873801F4E54B41F8040031F030002D +S224FE388001BC31F0300201BE11E801F601B911E801F701B831E801F801B031E801FA01B476 +S224FE38A031E801FC01B631E801FE01B2D0FC004043F80200701F22D851C8FFFC1038C583F7 +S224FE38C0020000F011C0C583103801C34E752C5F11EF0004010508F800010105422F0004FA +S224FE38E06100CD8046FC270011FC0025C073423801046100CAFA41FAF6096100CB166100C8 +S224FE3900CAEE6100FE4E665242A7307C04002F082F086100FB72661C307C04000C58424F8B +S224FE3920662E0C584F5466287000103801F43F002F0E4ED06100CAB8103801C3440041FAA6 +S224FE3940F4236100CACE6100CAD86100CAA24ED641FAF41F6100CABC60F00C38000101C3D2 +S224FE396066D26100CA8A41FAF5B16100CAA641F801F66100CA9E60D2FFFFFFFFFFFFFFFF82 +S224FE3980FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +S224FE39A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +S224FE39C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +S224FE39E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +S224FE3A00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +S224FE3A20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +S224FE3A40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +S224FE3A60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +S224FE3A80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +S224FE3AA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +S224FE3AC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +S224FE3AE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +S224FE3B00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +S224FE3B20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +S224FE3B40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +S224FE3B60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +S224FE3B80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +S224FE3BA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +S224FE3BC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +S224FE3BE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +S224FE3C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +S224FE3C20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +S224FE3C40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +S224FE3C60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +S224FE3C80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +S224FE3CA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +S224FE3CC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +S224FE3CE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +S224FE3D00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +S224FE3D20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +S224FE3D40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +S224FE3D60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +S224FE3D80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +S224FE3DA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +S224FE3DC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +S224FE3DE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +S224FE3E00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +S224FE3E20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +S224FE3E40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +S224FE3E60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +S224FE3E80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +S224FE3EA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +S224FE3EC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +S224FE3EE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +S224FE3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +S224FE3F20FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +S224FE3F40FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +S224FE3F60FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +S224FE3F80FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +S224FE3FA0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +S224FE3FC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +S224FE3FE0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +S804FE0000FD diff --git a/SAGE/chip_defs.h b/SAGE/chip_defs.h new file mode 100644 index 00000000..443106fa --- /dev/null +++ b/SAGE/chip_defs.h @@ -0,0 +1,435 @@ +/* chip_defs.h: definitions for several chips + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 22-Jan-10 HV Initial version +*/ +#ifndef CHIP_DEFS_H_ +#define CHIP_DEFS_H_ + +#include "sim_imd.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + +/***************************************************************************************** + * General implementation note: + * + * Each chip device is implemented through a specific data structure, e.g. struct i8251 + * The address of this data structure MUST be passed to the device->ctxt variable. + * The data structure MUST contain a PNP_INFO attribute at the beginning. + * + * In case each unit of a complex device has an own chip, device->ctxt points to an array + * of as much elements as there are units. + * The device reset routine MUST call add_iohandler and del_iohandler depending on + * enable or disable of the device. add_iohandler and del_iohandler will be passed + * the corresponding address of the data structure for the chip (device->ctxt). + * + *****************************************************************************************/ + +/* set this to 0 to remove debug messages */ +#ifndef DBG_MSG +#define DBG_MSG 1 +#endif + +/* generic debug tracing support */ +#if DBG_MSG==1 +extern FILE* sim_deb; + +#define ADDRESS_FORMAT "[0x%08x]" +#if UNIX_PLATFORM +#define NLP "\r\n" +#else +#define NLP "\n" +#endif + +#define TRACE_PRINT(level,args)\ + if(sim_deb && chip->dev->dctrl & level) { \ + fprintf(sim_deb,"%-4s: " ADDRESS_FORMAT " ", chip->dev->name, PCX); \ + fprintf args; fputs(NLP,sim_deb); } +#define TRACE_PRINT0(level,fmt)\ + if(sim_deb && chip->dev->dctrl & level) { \ + fprintf(sim_deb,"%-4s: " ADDRESS_FORMAT " ", chip->dev->name, PCX); \ + fprintf(sim_deb,fmt NLP); } +#define TRACE_PRINT1(level,fmt,arg1)\ + if(sim_deb && chip->dev->dctrl & level) { \ + fprintf(sim_deb,"%-4s: " ADDRESS_FORMAT " ", chip->dev->name, PCX); \ + fprintf(sim_deb,fmt NLP,arg1); } +#define TRACE_PRINT2(level,fmt,arg1,arg2)\ + if(sim_deb && chip->dev->dctrl & level) { \ + fprintf(sim_deb,"%-4s: " ADDRESS_FORMAT " ", chip->dev->name, PCX); \ + fprintf(sim_deb,fmt NLP,arg1,arg2); } +#else +#define TRACE_PRINT(level,args) +#define TRACE_PRINT0(level,fmt) +#define TRACE_PRINT1(level,fmt,arg1) +#define TRACE_PRINT2(level,fmt,arg1,arg2) +#endif + +/***************************************************************************************** + * general terminal multiplexer/socket support + *****************************************************************************************/ + +typedef struct { + int pfirst; + int prate; + TMLN ldsc; + TMXR desc; + UNIT* term; + UNIT* poll; +} SERMUX; +t_stat mux_attach(UNIT*,char*,SERMUX*); +t_stat mux_detach(UNIT*,SERMUX*); + +/***************************************************************************************** + * 8259 PIC + *****************************************************************************************/ +#define I8259_ICW1 0x10 +#define I8259_ICW1_A765 0xe0 +#define I8259_ICW1_LTIM 0x08 +#define I8259_ICW1_ADI 0x04 +#define I8259_ICW1_SNGL 0x02 +#define I8259_ICW1_IC4 0x01 +#define I8259_ICW4_SFNM 0x10 +#define I8259_ICW4_BUF 0x08 +#define I8259_ICW4_MS 0x04 +#define I8259_ICW4_AEOI 0x02 +#define I8259_ICW4_UPM 0x01 +#define I8259_OCW2_MODE 0xe0 +#define I8259_OCW2_LEVEL 0x07 +#define I8259_OCW3_ESMM 0x40 +#define I8259_OCW3_SMM 0x20 +#define I8259_OCW3 0x08 +#define I8259_OCW3_POLL 0x04 +#define I8259_OCW3_RR 0x02 +#define I8259_OCW3_RIS 0x01 + +typedef struct i8259 { + PNP_INFO pnp; + DEVICE* dev; /* backlink to device */ + t_stat (*write)(struct i8259* chip,int port,uint32 value); + t_stat (*read)(struct i8259* chip,int port,uint32* value); + t_stat (*reset)(struct i8259* chip); + int state; + int rmode; + int32 imr; + int32 isr; + int32 irr; + int32 icw1; + int32 icw2; + int32 icw4; + int32 prio; /* which IR* has prio 7? */ + t_bool autoint; + int intlevel; + int intvector; +} I8259; + +extern t_stat i8259_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask); +extern t_stat i8259_read(I8259* pic,int addr,uint32* value); +extern t_stat i8259_write(I8259* pic,int addr, uint32 value); +extern t_stat i8259_reset(I8259* chip); +extern t_stat i8259_raiseint(I8259* chip,int level); + +/* Debug flags */ +#define DBG_PIC_RD (1 << 0) +#define DBG_PIC_WR (1 << 1) +#define DBG_PIC_II (1 << 2) +#define DBG_PIC_IO (1 << 3) +extern DEBTAB i8259_dt[]; + +/***************************************************************************************** + * 8251 USART + *****************************************************************************************/ +#define I8251_AMODE_STOP 0xc0 +#define I8251_AMODE_S1 0x40 +#define I8251_AMODE_S15 0x80 +#define I8251_AMODE_S2 0xc0 +#define I8251_MODE_EP 0x20 +#define I8251_MODE_PEN 0x10 +#define I8251_AMODE_BITS 0x0c +#define I8251_AMODE_BITS5 0x00 +#define I8251_AMODE_BITS6 0x04 +#define I8251_AMODE_BITS7 0x08 +#define I8251_AMODE_BITS8 0x0c +#define I8251_MODE_BAUD 0x03 +#define I8251_MODE_SYNC 0x00 +#define I8251_AMODE_BAUD1 0x01 +#define I8251_AMODE_BAUD16 0x02 +#define I8251_AMODE_BAUD64 0x03 +#define I8251_SMODE_ESD 0x40 +#define I8251_SMODE_SCS 0x80 +#define I8251_CMD_EH 0x80 +#define I8251_CMD_IR 0x40 +#define I8251_CMD_RTS 0x20 +#define I8251_CMD_ER 0x10 +#define I8251_CMD_SBRK 0x08 +#define I8251_CMD_RXE 0x04 +#define I8251_CMD_DTR 0x02 +#define I8251_CMD_TXEN 0x01 +#define I8251_ST_DSR 0x80 +#define I8251_ST_SYNBRK 0x40 +#define I8251_ST_FE 0x20 +#define I8251_ST_OE 0x10 +#define I8251_ST_PE 0x08 +#define I8251_ST_TXEMPTY 0x04 +#define I8251_ST_RXRDY 0x02 +#define I8251_ST_TXRDY 0x01 + +typedef struct i8251 { + PNP_INFO pnp; + DEVICE* dev; /* backlink to device */ + t_stat (*write)(struct i8251* chip,int port,uint32 value); + t_stat (*read)(struct i8251* chip,int port,uint32* value); + t_stat (*reset)(struct i8251* chip); + t_stat (*txint)(struct i8251* chip); + t_stat (*rxint)(struct i8251* chip); + UNIT* in; + UNIT* out; + SERMUX* mux; + int init; + int mode; + int sync1; + int sync2; + int cmd; + int ibuf; + int obuf; + int status; + int bitmask; + t_bool oob; /* out-of-band=1 will allow a console to receive CTRL-E even when receiver is disabled */ + int crlf; /* CRLF state machine to suppress NUL bytes */ +} I8251; + +/* default handlers */ +extern t_stat i8251_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask); +extern t_stat i8251_write(I8251* chip,int port,uint32 value); +extern t_stat i8251_read(I8251* chip,int port,uint32* value); +extern t_stat i8251_reset(I8251* chip); + +/* Debug flags */ +#define DBG_UART_RD (1 << 0) +#define DBG_UART_WR (1 << 1) +#define DBG_UART_IRQ (1 << 2) +extern DEBTAB i8251_dt[]; + + +/***************************************************************************************** + * 8253 TIMER + *****************************************************************************************/ +/*forward*/ struct i8253; +typedef struct { + t_stat (*call)(struct i8253* chip,int rw,uint32* src); + int state; /* the current output state (latching, MSB/LSB out */ + int mode; /* programmed mode */ + int32 latch; /* the latched value of count */ + int32 divider; /* programmed divider value */ + int32 count; /* the real count value as calculated by rcall callback */ +} I8253CNTR; + +typedef struct i8253 { + PNP_INFO pnp; + DEVICE* dev; /* backlink to device */ + UNIT* unit; /* backlink to unit */ + t_stat (*reset)(struct i8253* chip); + t_stat (*ckmode)(struct i8253* chip, uint32 value); + I8253CNTR cntr[3]; + int init; +} I8253; + +#define I8253_SCMASK 0xc0 +#define I8253_SC0 0x00 +#define I8253_SC1 0x40 +#define I8253_SC2 0x80 +#define I8253_RLMASK 0x30 +#define I8253_LATCH 0x00 +#define I8253_LSB 0x10 +#define I8253_MSB 0x20 +#define I8253_BOTH 0x30 +#define I8253_MODEMASK 0xe0 +#define I8253_MODE0 0x00 +#define I8253_MODE1 0x02 +#define I8253_MODE2 0x04 +#define I8253_MODE2a 0x0c +#define I8253_MODE3 0x06 +#define I8253_MODE3a 0x0e +#define I8253_MODE4 0x08 +#define I8253_MODE5 0x0a +#define I8253_MODEBIN 0x00 +#define I8253_MODEBCD 0x01 + +#define I8253_ST_LSBNEXT 0x01 +#define I8253_ST_MSBNEXT 0x02 +#define I8253_ST_LATCH 0x08 + +/* default handlers */ +extern t_stat i8253_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask); +extern t_stat i8253_reset(I8253* chip); + +/* Debug flags */ +#define DBG_TMR_RD (1 << 0) +#define DBG_TMR_WR (1 << 1) +extern DEBTAB i8253_dt[]; + +/**************************************************************************************** + * upd765 FDC chip + ***************************************************************************************/ +#define I8272_MAX_DRIVES 4 +#define I8272_MAX_SECTOR 26 +#define I8272_MAX_SECTOR_SZ 8192 +/* 2^(7 + I8272_MAX_N) == I8272_MAX_SECTOR_SZ */ +#define I8272_MAX_N 6 + +#define I8272_FDC_MSR 0 /* R=FDC Main Status Register, W=Drive Select Register */ +#define I8272_FDC_DATA 1 /* R/W FDC Data Register */ + +typedef struct { + UNIT *uptr; + DISK_INFO *imd; + uint8 ntracks; /* number of tracks */ + uint8 nheads; /* number of heads */ + uint32 sectsize; /* sector size, not including pre/postamble */ + uint8 track; /* Current Track */ + uint8 ready; /* Is drive ready? */ +} I8272_DRIVE_INFO; + +typedef enum i8272state { + S_CMD=1, S_CMDREAD, S_EXEC, S_DATAWRITE, S_SECWRITE, S_SECREAD, S_DATAREAD, S_RESULT +} I8272_STATE; + +typedef struct i8272 { + PNP_INFO pnp; /* Plug-n-Play Information */ + DEVICE* dev; /* backlink to device */ + t_stat (*write)(struct i8272* chip,int port,uint32 data); + t_stat (*read)(struct i8272* chip,int port,uint32* data); + t_stat (*reset)(struct i8272* chip); + void (*seldrv)(struct i8272* chip,int seldrv); + void (*irq)(struct i8272* chip,int delay); + + I8272_STATE fdc_state; /* internal state machine */ + uint32 fdc_dma_addr;/* DMA Transfer Address */ + uint8 fdc_msr; /* 8272 Main Status Register */ + uint8 fdc_nd; /* Non-DMA Mode 1=Non-DMA, 0=DMA */ + uint8 fdc_head; /* H Head Number */ + uint8 fdc_sector; /* R Record (Sector) */ + uint8 fdc_sec_len; /* N Sector Length in controller units (2^(7+fdc_sec_len)) */ + uint8 fdc_eot; /* EOT End of Track (Final sector number of cyl) */ + uint8 fdc_gap; /* GAP Length */ + uint8 fdc_dtl; /* DTL Data Length */ + uint8 fdc_mt; /* Multiple sectors */ + uint8 fdc_mfm; /* MFM mode */ + uint8 fdc_sk; /* Skip Deleted Data */ + uint8 fdc_hds; /* Head Select */ + uint8 fdc_seek_end; /* Seek was executed successfully */ + int fdc_secsz; /* N Sector Length in bytes: 2^(7 + fdc_sec_len), fdc_sec_len <= I8272_MAX_N */ + int fdc_nd_cnt; /* read/write count in non-DMA mode, -1 if start read */ + uint8 fdc_sdata[I8272_MAX_SECTOR_SZ]; /* sector buffer */ + uint8 fdc_fault; /* error code passed from some commands to sense_int */ + + uint8 cmd_cnt; /* command read count */ + uint8 cmd[10]; /* Storage for current command */ + uint8 cmd_len; /* FDC Command Length */ + + uint8 result_cnt; /* result emit count */ + uint8 result[10]; /* Result data */ + uint8 result_len; /* FDC Result Length */ + + uint8 idcount; /* used to cycle sector numbers during ReadID */ + uint8 irqflag; /* set by interrupt, cleared by I8272_SENSE_INTERRUPT */ + + uint8 fdc_curdrv; /* Currently selected drive */ + I8272_DRIVE_INFO drive[I8272_MAX_DRIVES]; +} I8272; + +extern t_stat i8272_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask); +extern t_stat i8272_write(I8272* chip, int addr, uint32 value); +extern t_stat i8272_read(I8272* chip,int addr,uint32* value); +extern t_stat i8272_reset(I8272* chip); +extern void i8272_seldrv(I8272* chip,int drvnum); +extern t_stat i8272_abortio(I8272* chip); +extern t_stat i8272_finish(I8272* chip); +extern t_stat i8272_attach(UNIT *uptr, char *cptr); +extern t_stat i8272_detach(UNIT *uptr); +extern t_stat i8272_setDMA(I8272* chip, uint32 dma_addr); + +/* Debug flags */ +#define DBG_FD_ERROR (1 << 0) +#define DBG_FD_SEEK (1 << 1) +#define DBG_FD_CMD (1 << 2) +#define DBG_FD_RDDATA (1 << 3) +#define DBG_FD_WRDATA (1 << 4) +#define DBG_FD_STATUS (1 << 5) +#define DBG_FD_FMT (1 << 6) +#define DBG_FD_VERBOSE (1 << 7) +#define DBG_FD_IRQ (1 << 8) +#define DBG_FD_STATE (1 << 9) +#define DBG_FD_IMD (1 << 10) +#define DBG_FD_DATA (1 << 11) +extern DEBTAB i8272_dt[]; +extern DEVICE* i8272_dev; + +/* moved from i8272.c */ +#define UNIT_V_I8272_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_I8272_WLK (1 << UNIT_V_I8272_WLK) +#define UNIT_V_I8272_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_I8272_VERBOSE (1 << UNIT_V_I8272_VERBOSE) +#define I8272_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ +#define I8272_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */ + +/***************************************************************************************** + * 8255 PARPORT + *****************************************************************************************/ +typedef struct i8255 { + PNP_INFO pnp; + DEVICE* dev; /* backlink to device */ + t_stat (*write)(struct i8255* chip,int port,uint32 data); + t_stat (*read)(struct i8255* chip,int port,uint32* data); + t_stat (*reset)(struct i8255* chip); + t_stat (*calla)(struct i8255* chip,int rw); + t_stat (*callb)(struct i8255* chip,int rw); + t_stat (*callc)(struct i8255* chip,int rw); + t_stat (*ckmode)(struct i8255* chip,uint32 data); + uint32 porta; + uint32 last_porta; /* for edge detection */ + uint32 portb; + uint32 last_portb; /* for edge detection */ + uint32 portc; + uint32 last_portc; /* for edge detection */ + uint32 ctrl; +} I8255; +extern t_stat i8255_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask); +extern t_stat i8255_read(I8255* chip,int port,uint32* data); +extern t_stat i8255_write(I8255* chip,int port,uint32 data); +#define I8255_RISEEDGE(port,bit) ((chip->last_##port & bit)==0 && (chip->port & bit)) +#define I8255_FALLEDGE(port,bit) ((chip->last_##port & bit) && (chip->port & bit)==0) +#define I8255_ISSET(port,bit) ((chip->port & (bit))==(bit)) +#define I8255_ISCLR(port,bit) ((chip->port & (bit))==0) + +/* debug flags */ +#define DBG_PP_WRA (1<<0) +#define DBG_PP_WRB (1<<1) +#define DBG_PP_WRC (1<<2) +#define DBG_PP_RDA (1<<3) +#define DBG_PP_RDB (1<<4) +#define DBG_PP_RDC (1<<5) +#define DBG_PP_MODE (1<<6) + +#endif /*CHIP_DEFS_H_*/ diff --git a/SAGE/i8251.c b/SAGE/i8251.c new file mode 100644 index 00000000..45b671ed --- /dev/null +++ b/SAGE/i8251.c @@ -0,0 +1,145 @@ +/* sage_stddev.c: Standard devices for sage-II system + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 22-Jan-10 HV Initial version +*/ + +#include "sim_defs.h" +#include "m68k_cpu.h" +#include "chip_defs.h" + +static int i8251_bitmask[] = { 0x1f, 0x3f, 0x7f, 0xff }; + +/* Debug Flags */ +DEBTAB i8251_dt[] = { + { "READ", DBG_UART_RD }, + { "WRITE", DBG_UART_WR }, + { "IRQ", DBG_UART_IRQ }, + { NULL, 0 } +}; + +t_stat i8251_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask) +{ + int port = ioh->offset; + I8251* chip = (I8251*)ioh->ctxt; + if (rw==MEM_WRITE) { + return chip->write ? chip->write(chip,port,*value) : i8251_write(chip,port,*value); + } else { + return chip->read ? chip->read(chip,port,value) : i8251_read(chip,port,value); + } +} + +t_stat i8251_write(I8251* chip,int port,uint32 value) +{ + int bits; + + if (port==0) { /* data port */ + chip->obuf = value & chip->bitmask; + TRACE_PRINT1(DBG_UART_WR,"WR DATA = 0x%02x",chip->obuf); + if (chip->init==3) { /* is fully initialized */ + if ((chip->mode & I8251_MODE_BAUD)==I8251_MODE_SYNC) { + printf("i8251: sync mode not implemented\n"); + return STOP_IMPL; + } + if (chip->cmd & I8251_CMD_TXEN) { + /* transmit data */ + chip->status &= ~(I8251_ST_TXEMPTY|I8251_ST_TXRDY); + sim_activate(chip->out,chip->out->wait); + } + } + return SCPE_OK; + } else { /* control port */ + switch (chip->init) { + case 0: /* expect mode word */ + chip->mode = value; + TRACE_PRINT1(DBG_UART_WR,"WR MODE = 0x%02x",value); + chip->init = (value & I8251_MODE_BAUD)==I8251_MODE_SYNC ? 1 : 3; + bits = (chip->mode & I8251_AMODE_BITS) >> 2; + chip->bitmask = i8251_bitmask[bits]; + break; + case 1: /* expect sync1 */ + chip->sync1 = value; + TRACE_PRINT1(DBG_UART_WR,"WR SYNC1 = 0x%02x",value); + chip->init = 2; + break; + case 2: /* expect sync2 */ + chip->sync2 = value; + TRACE_PRINT1(DBG_UART_WR,"WR SYNC2 = 0x%02x",value); + chip->init = 3; + break; + case 3: /* expect cmd word */ + chip->cmd = value; + TRACE_PRINT1(DBG_UART_WR,"WR CMD = 0x%02x",value); + if (value & I8251_CMD_EH) { + printf("i8251: hunt mode not implemented\n"); + return STOP_IMPL; + } + if (value & I8251_CMD_IR) + chip->init = 0; + if (value & I8251_CMD_ER) + chip->status &= ~(I8251_ST_FE|I8251_ST_OE|I8251_ST_PE); + if (value & I8251_CMD_SBRK) + printf("i8251: BREAK sent\n"); + if (value & I8251_CMD_RXE) { + sim_activate(chip->in,chip->in->wait); + } else { + if (!chip->oob) sim_cancel(chip->in); + } + if (value & I8251_CMD_TXEN) { + if (!(chip->status & I8251_ST_TXEMPTY)) + sim_activate(chip->out,chip->out->wait); + else { + chip->status |= I8251_ST_TXRDY; + if (chip->txint) chip->txint(chip); + } + } else { + chip->status &= ~I8251_ST_TXRDY; + sim_cancel(chip->out); + } + } + return SCPE_OK; + } +} + +t_stat i8251_read(I8251* chip,int port,uint32* value) +{ + if (port==0) { /* data read */ + *value = chip->ibuf; + chip->status &= ~I8251_ST_RXRDY; /* mark read buffer as empty */ + TRACE_PRINT1(DBG_UART_RD,"RD DATA = 0x%02x",*value); + } else { /* status read */ + *value = chip->status & 0xff; + TRACE_PRINT1(DBG_UART_RD,"RD STATUS = 0x%02x",*value); + } + return SCPE_OK; +} + +t_stat i8251_reset(I8251* chip) +{ + chip->init = 0; + chip->oob = FALSE; + chip->crlf = 0; + return SCPE_OK; +} diff --git a/SAGE/i8253.c b/SAGE/i8253.c new file mode 100644 index 00000000..543616c4 --- /dev/null +++ b/SAGE/i8253.c @@ -0,0 +1,143 @@ +/* sage_stddev.c: Standard devices for sage-II system + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 22-Jan-10 HV Initial version +*/ + +#include "sim_defs.h" +#include "m68k_cpu.h" +#include "chip_defs.h" + +/* Debug Flags */ +DEBTAB i8253_dt[] = { + { "READ", DBG_TMR_RD }, + { "WRITE", DBG_TMR_WR }, + { NULL, 0 } +}; + +static char* rltype[] = { "latch","8bitL","8bitH", "16bit" }; + +t_stat i8253_write(I8253* chip, int addr, uint32 value) +{ + I8253CNTR* cntr; + t_stat rc; + int num; + + if (addr==3) { /* mode reg */ + TRACE_PRINT(DBG_TMR_WR,(sim_deb,"WR MODE=%x (SC=%d RL=%s MODE=%d BCD=%d)", + value,(value>>6)&3,rltype[(value>>4)&3],(value>>1)&7,value&1)); + if (chip->ckmode && (rc=chip->ckmode(chip,value))!= SCPE_OK) return rc; + num = (value & I8253_SCMASK)>>6; + cntr = &chip->cntr[num]; + if ((value & I8253_RLMASK)==I8253_LATCH) { + /* calculate current value of count */ + cntr->latch = cntr->count; /* latch it */ + cntr->state |= I8253_ST_LATCH; + } else { + cntr->mode = value; + cntr->state = (value & I8253_RLMASK)==I8253_MSB ? I8253_ST_MSBNEXT : I8253_ST_LSBNEXT; + } + } else { /* write dividers */ + cntr = &chip->cntr[addr]; + switch (cntr->mode & I8253_RLMASK) { + case I8253_MSB: + TRACE_PRINT2(DBG_TMR_WR,"WR CNT=%d DIVMSB=%x",addr,value); + cntr->divider = (cntr->divider & 0x00ff) | ((value<<8) | 0xff); + cntr->state &= ~I8253_ST_LATCH; + cntr->count = cntr->divider; + break; + case I8253_LSB: + TRACE_PRINT2(DBG_TMR_WR,"WR CNT=%d DIVLSB=%x",addr,value); + cntr->divider = (cntr->divider & 0xff00) | (value | 0xff); + cntr->state &= ~I8253_ST_LATCH; + cntr->count = cntr->divider; + break; + case I8253_BOTH: + if (cntr->state & I8253_ST_MSBNEXT) { + TRACE_PRINT2(DBG_TMR_WR,"WR CNT=%d DIV16MSB=%x",addr,value); + cntr->divider = (cntr->divider & 0x00ff) | ((value & 0xff)<<8); + cntr->state = I8253_ST_LSBNEXT; /* reset latch mode and MSB bit */ + cntr->count = cntr->divider; + } else { + TRACE_PRINT2(DBG_TMR_WR,"WR CNT=%d DIV16LSB=%x",addr,value); + cntr->divider = (cntr->divider & 0xff00) | (value & 0xff); + cntr->state = I8253_ST_MSBNEXT; /* reset latch mode and LSB bit */ + } + default: + break; + } + /* execute a registered callback before returning result */ + if (cntr->call && (rc=(*cntr->call)(chip,1,&value)) != SCPE_OK) return rc; + } + return SCPE_OK; +} + +t_stat i8253_read(I8253* chip,int addr,uint32* value) +{ + t_stat rc; + I8253CNTR* cntr = &chip->cntr[addr]; + int32 src = cntr->state & I8253_ST_LATCH ? cntr->latch : cntr->count; + if (cntr->call && (rc=(*cntr->call)(chip,0,(uint32*)&src)) != SCPE_OK) return rc; + + switch (cntr->mode & I8253_RLMASK) { + case I8253_MSB: + src >>= 8; + TRACE_PRINT2(DBG_TMR_RD,"RD CNT=%d CNTMSB=%x",addr,src&0xff); + cntr->state &= ~I8253_ST_LATCH; + break; + case I8253_LSB: + cntr->state &= ~I8253_ST_LATCH; + TRACE_PRINT2(DBG_TMR_RD,"RD CNT=%d CNTLSB=%x",addr,src&0xff); + break; + case I8253_BOTH: + if (cntr->state & I8253_ST_MSBNEXT) { + src >>= 8; cntr->state = I8253_ST_LSBNEXT; /* reset latch mode and MSB bit */ + TRACE_PRINT2(DBG_TMR_RD,"RD CNT=%d CNT16MSB=%x",addr,src&0xff); + } else { + TRACE_PRINT2(DBG_TMR_RD,"RD CNT=%d CNT16LSB=%x",addr,src&0xff); + cntr->state |= I8253_ST_MSBNEXT; /* does not reset latch mode if set */ + } + break; + default: + return SCPE_OK; + } + *value = src & 0xff; + return SCPE_OK; +} + +t_stat i8253_reset(I8253* chip) +{ + int i; + for (i=0; i<3; i++) chip->cntr[i].state = 0; + return SCPE_OK; +} + +t_stat i8253_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask) +{ + int port = ioh->offset; + I8253* chip = (I8253*)ioh->ctxt; + return rw==MEM_WRITE ? i8253_write(chip,port,*value) : i8253_read(chip,port,value); +} + diff --git a/SAGE/i8255.c b/SAGE/i8255.c new file mode 100644 index 00000000..f68067eb --- /dev/null +++ b/SAGE/i8255.c @@ -0,0 +1,106 @@ +/* i8255.c: helper for 8255 implementation + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 14-Mar-10 HV Initial version +*/ + +#include "sim_defs.h" +#include "m68k_cpu.h" +#include "chip_defs.h" + +static t_stat i8255_error(const char* err) +{ + printf("I8255: Missing method '%s'\n",err); + return STOP_IMPL; +} + +t_stat i8255_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask) +{ + int port = ioh->offset; + I8255* chip = (I8255*)ioh->ctxt; + if (rw==MEM_WRITE) { + return chip->write ? chip->write(chip,port,*value) : i8255_error("write"); + } else { + return chip->read ? chip->read(chip,port,value) : i8255_error("read"); + } +} + +t_stat i8255_read(I8255* chip,int port,uint32* data) +{ + t_stat rc; + switch (port) { + case 0: + if (chip->calla && (rc=(*chip->calla)(chip,0)) != SCPE_OK) return rc; + *data = chip->porta; + return SCPE_OK; + case 1: + if (chip->callb && (rc=(*chip->callb)(chip,0)) != SCPE_OK) return rc; + *data = chip->portb; + return SCPE_OK; + case 2: + if (chip->callc && (rc=(*chip->callc)(chip,0)) != SCPE_OK) return rc; + *data = chip->portc; + return SCPE_OK; + case 3: + *data = 0xff; /* undefined */ + return SCPE_OK; + default: + return SCPE_IERR; + } +} + +t_stat i8255_write(I8255* chip,int port,uint32 data) +{ + t_stat rc; + uint32 bit; + switch(port) { + case 0: /*port a*/ + chip->last_porta = chip->porta; + chip->porta = data; + return chip->calla ? (*chip->calla)(chip,1) : SCPE_OK; + case 1: /*port b*/ + chip->last_portb = chip->portb; + return chip->callb ? (*chip->callb)(chip,1) : SCPE_OK; + case 2: + chip->last_portc = chip->portc; + chip->portc = data & 0xff; + return chip->callc ? (*chip->callc)(chip,1) : SCPE_OK; + case 3: + if (data & 0x80) { /* mode set mode */ + if (chip->ckmode && (rc=chip->ckmode(chip,data))) return rc; + chip->ctrl = data & 0x7f; + return SCPE_OK; + } else { /* bit set mode */ + chip->last_portc = chip->portc; + bit = 1 << ((data & 0x0e)>>1); + TRACE_PRINT2(DBG_PP_WRC,"WR PORTC %s bit=%x",data&1 ? "SET": "CLR",bit); + if (data & 1) chip->portc |= bit; else chip->portc &= ~bit; + chip->portc &= 0xff; + return chip->callc ? (*chip->callc)(chip,1) : SCPE_OK; + } + default: + return SCPE_IERR; + } +} diff --git a/SAGE/i8259.c b/SAGE/i8259.c new file mode 100644 index 00000000..adca56d5 --- /dev/null +++ b/SAGE/i8259.c @@ -0,0 +1,244 @@ +/* chip_i8259.c: system independent implementation of PIC chip + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 22-Jan-10 HV Initial version + 03-Jun-10 HV Repair POLL function (defective FDC interrupt handling in SAGEBIOS) +*/ + +#include "sim_defs.h" +#include "m68k_cpu.h" +#include "chip_defs.h" + +/* Debug Flags */ +DEBTAB i8259_dt[] = { + { "READ", DBG_PIC_RD }, + { "WRITE", DBG_PIC_WR }, + { "IRQIN", DBG_PIC_II }, + { "IRQOUT", DBG_PIC_IO }, + { NULL, 0 } +}; + +static int32 priomask[] = { 0x0000,0x4000,0x6000,0x7000,0x7800,0x7c00,0x7e00,0x7f00 }; + +t_stat i8259_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask) +{ + int port = ioh->offset; + I8259* chip = (I8259*)ioh->ctxt; + if (rw==MEM_WRITE) { + return chip->write ? chip->write(chip,port,*value) : i8259_write(chip,port,*value); + } else { + return chip->read ? chip->read(chip,port,value) : i8259_read(chip,port,value); + } +} + +t_stat i8259_write(I8259* chip,int addr,uint32 value) +{ + int i, bit; + +#if 0 + TRACE_PRINT2(DBG_PIC_WR,"WR addr=%d data=0x%x",addr,value); +#endif + if (addr==1) { + switch (chip->state) { + default: + case 0: /* after reset */ + printf("PIC: write addr=1 without initialization\n"); + return SCPE_IOERR; + case 1: /* expect ICW2 */ + TRACE_PRINT2(DBG_PIC_WR,"WR ICW2: addr=%d data=0x%x",addr,value); + chip->icw2 = value; + if (chip->icw1 & I8259_ICW1_SNGL) { + chip->state = (chip->icw1 & I8259_ICW1_IC4) ? 4 : 5; + } else { + /* attempt to program cascade mode */ + printf("PIC: attempt to program chip for cascade mode - not wired for this!\n"); + chip->state = 0; + return SCPE_IOERR; + } + break; + case 4: /* expect ICW4 */ + TRACE_PRINT2(DBG_PIC_WR,"WR ICW4 addr=%d data=0x%x",addr,value); + chip->icw4 = value; + if (chip->icw4 & I8259_ICW4_AEOI) { + printf("PIC: attempt to program chip for AEOI mode - not wired for this!\n"); + return SCPE_IOERR; + } + if (chip->icw4 & I8259_ICW4_BUF) { + printf("PIC: attempt to program chip for buffered mode - not wired for this!\n"); + return SCPE_IOERR; + } + if (chip->icw4 & I8259_ICW4_SFNM) { + printf("PIC: attempt to program chip for spc nested mode - not wired for this!\n"); + return SCPE_IOERR; + } + chip->state = 5; + break; + case 5: /* ready to accept interrupt requests and ocw commands */ + /* ocw1 */ + TRACE_PRINT2(DBG_PIC_WR,"WR IMR addr=%d data=0x%x",addr,value); + chip->imr = value; + break; + } + } else { + if (value & I8259_ICW1) { /* state initialization sequence */ + TRACE_PRINT2(DBG_PIC_WR,"WR ICW1 addr=%d data=0x%x",addr,value); + chip->icw1 = value; + chip->state = 1; + chip->rmode = 0; + chip->prio = 7; + if ((chip->icw1 & I8259_ICW1_IC4)==0) chip->icw4 = 0; + + return SCPE_OK; + } else { /* ocw2 and ocw3 */ + if (value & I8259_OCW3) { /* ocw3 */ + TRACE_PRINT2(DBG_PIC_WR,"WR OCW3 addr=%d data=0x%x",addr,value); + if (value & I8259_OCW3_ESMM) { + printf("PIC: ESMM not yet supported\n"); + return STOP_IMPL; + } + if (value & I8259_OCW3_POLL) { + chip->rmode |= 2; + return SCPE_OK; + } + if (value & I8259_OCW3_RR) + chip->rmode = (value & I8259_OCW3_RIS) ? 1 /*isr*/ : 0; /* irr */ + } else { /* ocw2 */ + TRACE_PRINT2(DBG_PIC_WR,"WR OCW2 addr=%d data=0x%x",addr,value); + switch (value & I8259_OCW2_MODE) { + case 0xa0: /* rotate on nospecific eoi */ + case 0x20: /* nonspecific eoi */ + bit = 1 << (7 - chip->prio); + for (i=0; i<7; i++) { + if (chip->isr & bit) break; + bit = bit << 1; if (bit==0x100) bit = 1; + } + chip->isr &= ~bit; break; + if ((value & I8259_OCW2_MODE) == 0xa0) { + chip->prio = 7 - i + chip->prio; if (chip->prio>7) chip->prio -= 8; + } + break; + case 0xe0: /* rotate on specific eoi */ + chip->prio = 7 - (value & 7) + chip->prio; if (chip->prio>7) chip->prio -= 8; + /*fallthru*/ + case 0x60: /* specific eoi */ + bit = 1 << (value & 7); + chip->isr = chip->isr & ~bit & 0xff; + break; + case 0x80: /* rotate in autoeoi (set) */ + case 0x00: /* rotate in autoeoi (clear) */ + printf("PIC: AEOI not supported\n"); + return SCPE_IOERR; + case 0xc0: /* set prio */ + chip->prio = value & 7; + return SCPE_OK; + case 0x40: /* nop */ + break; + default: + return SCPE_IERR; + } + } + } + } + return SCPE_OK; +} + +t_stat i8259_read(I8259* chip,int addr, uint32* value) +{ + int i, bit, num; + + if (addr) { + *value = chip->imr; + } else { + switch (chip->rmode) { + case 0: + TRACE_PRINT2(DBG_PIC_RD,"Read IRR addr=%d data=0x%x",addr,chip->irr); + *value = chip->irr; break; + case 1: + TRACE_PRINT2(DBG_PIC_RD,"Read ISR addr=%d data=0x%x",addr,chip->irr); + *value = chip->isr; break; + case 2: + case 3: + TRACE_PRINT2(DBG_PIC_RD,"Read POLL addr=%d data=0x%x",addr,chip->irr); + num = chip->prio; + bit = 1 << chip->prio; + for (i=0; i<8; i++,num--) { + if (chip->isr & bit) { + *value = 0x80 | (num & 7); + TRACE_PRINT2(DBG_PIC_RD,"Read POLL addr=%d data=0x%x",addr,*value); + return SCPE_OK; + } + bit >>= 1; + if (bit==0) { bit = 0x80; num = 7; } + } + chip->rmode &= ~2; + } + } +#if 0 + TRACE_PRINT2(DBG_PIC_RD,"Read addr=%d data=0x%x",addr,*value); +#endif + return SCPE_OK; +} + +t_stat i8259_raiseint(I8259* chip,int level) +{ + int32 bit, isr, myprio; + + TRACE_PRINT1(DBG_PIC_II,"Request INT level=%d",level); + + if (chip->state != 5) return SCPE_OK; /* not yet initialized, ignore interrupts */ + bit = 1<imr & bit) return SCPE_OK; /* inhibited */ + chip->isr = (chip->isr | bit) & 0xff; /* request this interrupt level */ + + /* bit7=prio7 => bitN = prioN + bit7=prio6 => bitN = prioN-1 + ... + bit7=prio0 => bitN = prioN-7 + */ + isr = (chip->isr<<8) | chip->isr; /* simple rotation */ + isr = isr << (7-level); /* shift level bit into bit 15 */ + myprio = chip->prio - 7 + level; if (myprio < 0) myprio += 8; + if (!(isr & priomask[myprio])) { /* higher interrupt is pending */ + if (chip->autoint) { + TRACE_PRINT1(DBG_PIC_IO,"Raise AUTOINT level=%d",chip->intlevel); + return m68k_raise_autoint(chip->intlevel); + } else { + TRACE_PRINT2(DBG_PIC_IO,"Raise VECTORINT level=%d vector=%x",chip->intlevel,chip->intvector); + return m68k_raise_vectorint(chip->intlevel,chip->intvector); + } + } + return SCPE_OK; +} + +t_stat i8259_reset(I8259* chip) +{ + chip->autoint = TRUE; + chip->intlevel = 1; + chip->intvector = 0; + chip->state = 0; + chip->rmode = 0; + chip->imr = 0; + return SCPE_OK; +} diff --git a/SAGE/i8272.c b/SAGE/i8272.c new file mode 100644 index 00000000..2e5a03ab --- /dev/null +++ b/SAGE/i8272.c @@ -0,0 +1,1058 @@ +/* i8272.c: Generic i8272/upd765 fdc chip + + Copyright (c) 2009,2010 Holger Veit + Copyright (c) 2007-2008 Howard M. Harte http://www.hartetec.com + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + Change log: + - 22-Jul-2008, Howard M. Harte, original code in AltairZ80/i8272.c + - 19-Apr-2008, Tony Nicholson, added other .IMD formats + - 06-Aug-2008, Tony Nicholson, READID should use HDS bit and add support + for logical Head and Cylinder maps in the .IMD image file (AGN) + - 15-Feb-2010, Holger Veit, Support for M68K emulation, UPD765A/B commands + - 05-Apr-2010, Holger Veit, use sim_deb for trace and dbg + - 11-Apr-2010, Holger Veit, ReadID fixed, non-DMA RW fixed + - 12-Apr-2010, Holger Veit, The whole mess rewritten for readability, and functionality + - 17-Jul-2010, Holger Veit, Incorrect ST0 return from Recalibrate, should not set SEEK_END + - 18-Jul-2010, Holger Veit, Adjust Interrupt delays, too fast for ReadID and Seek + - 18-Jul-2010, Holger Veit, Lost last byte of a track, because ST0 was delivered too fast + - 23-Jul-2010, Holger Veit, Fix error handling case of unattached drive + - 25-Jul-2010, Holger Veit, One-Off error in i8251_datawrite +*/ + +#include "m68k_cpu.h" +#include "chip_defs.h" + +#if defined (_WIN32) +#include +#endif + +#include "sim_imd.h" + +/* internal state machine: + * + * fromstate condition for transition tostate comment + * ----------- ------------------------- ------------- --------------------------------------------------- + * any reset S_CMD expect a command byte + * S_CMD commandcode S_CMDREAD has cmd, expect further arguments + * S_CMDREAD !cmdread S_CMDREAD has some args, but need more + * S_CMDREAD cmdread S_EXEC has all args, gather info, get data for read cmds + * + * S_EXEC readsector S_SECREAD read sector + * S_EXEC writesector S_DATAWRITE expect data from system for write + * S_EXEC !(readsector|writesector) S_RESULT process commands not requiring read/write (e.g. SPECIFY) + * + * S_SECREAD IMMEDIATE S_DATAREAD deliver read data back to system + * S_DATAREAD !dataread S_DATAREAD did not deliver all data back yet + * S_DATAREAD dataread&moresectors S_SECREAD has return all data, but still more sectors to read + * S_DATAREAD dataread&!moresectors S_RESULT has return all data, reading finished + * + * S_DATAWRITE !datawritten S_DATAWRITE expect more data to write + * S_DATAWRITE datawritten S_SECWRITE has all data, write data to disk + * S_SECWRITE moresectors S_DATAWRITE data written to disk, more data to write + * + * S_RESULT !resultdone S_RESULT has not yet delivered all result codes + * S_RESULT resultdone S_CMD finished with result output, wait for next cmd + */ +#if DBG_MSG==1 +#include +#define NEXTSTATE(s) TRACE_PRINT2(DBG_FD_STATE,"TRANSITION from=%s to=%s",states[chip->fdc_state],states[s]); chip->fdc_state = s +#else +#define NEXTSTATE(s) chip->fdc_state = s +#endif + +extern uint32 PCX; + +int32 find_unit_index (UNIT *uptr); +static void i8272_interrupt(I8272* chip,int delay); + +/* need to be implemented elsewhere */ +extern void PutByteDMA(const uint32 Addr, const uint32 Value); +extern uint8 GetByteDMA(const uint32 Addr); + +#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ +#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ +#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ + +/* Intel 8272 Commands */ +#define I8272_READ_TRACK 0x02 +#define I8272_SPECIFY 0x03 +#define I8272_SENSE_DRIVE_STATUS 0x04 +#define I8272_WRITE_DATA 0x05 +#define I8272_READ_DATA 0x06 +#define I8272_RECALIBRATE 0x07 +#define I8272_SENSE_INTR_STATUS 0x08 +#define I8272_WRITE_DELETED_DATA 0x09 +#define I8272_READ_ID 0x0A +#define I8272_READ_DELETED_DATA 0x0C +#define I8272_FORMAT_TRACK 0x0D +#define I8272_SEEK 0x0F +#define UPD765_VERSION 0x10 +#define I8272_SCAN_EQUAL 0x11 +#define I8272_SCAN_LOW_EQUAL 0x19 +#define I8272_SCAN_HIGH_EQUAL 0x1D + +/* SENSE DRIVE STATUS bit definitions */ +#define DRIVE_STATUS_TWO_SIDED 0x08 +#define DRIVE_STATUS_TRACK0 0x10 +#define DRIVE_STATUS_READY 0x20 +#define DRIVE_STATUS_WP 0x40 +#define DRIVE_STATUS_FAULT 0x80 + +#define I8272_MSR_RQM (1 << 7) +#define I8272_MSR_DATA_OUT (1 << 6) +#define I8272_MSR_NON_DMA (1 << 5) +#define I8272_MSR_FDC_BUSY (1 << 4) + +/* convert coded i8272 sector size to real byte length */ +#define I8272_SEC2SZ(s) (128 << (s)) + +/* pointer to system specific FD device, to be set by implementation */ +DEVICE* i8272_dev = NULL; + +/* Debug Flags */ +DEBTAB i8272_dt[] = { + { "ERROR", DBG_FD_ERROR }, + { "SEEK", DBG_FD_SEEK }, + { "CMD", DBG_FD_CMD }, + { "RDDATA", DBG_FD_RDDATA }, + { "WRDATA", DBG_FD_WRDATA }, + { "STATUS", DBG_FD_STATUS }, + { "FMT", DBG_FD_FMT }, + { "VERBOSE",DBG_FD_VERBOSE }, + { "IRQ", DBG_FD_IRQ }, + { "STATE", DBG_FD_STATE }, + { "IMD", DBG_FD_IMD }, + { "DATA", DBG_FD_DATA}, + { NULL, 0 } +}; + +static char* states[] = { + "invalid", "S_CMD", "S_CMDREAD", "S_EXEC", "S_DATAWRITE", "S_SECWRITE", + "S_SECREAD", "S_DATAREAD", "S_RESULT" +}; + +static char* messages[] = { + "Undefined Command 0x0", "Undefined Command 0x1", "Read Track", "Specify", + "Sense Drive Status", "Write Data", "Read Data", "Recalibrate", + "Sense Interrupt Status","Write Deleted Data", "Read ID", "Undefined Command 0xB", + "Read Deleted Data", "Format Track", "Undefined Command 0xE", "Seek", + "Undefined Command 0x10","Scan Equal", "Undefined Command 0x12","Undefined Command 0x13", + "Undefined Command 0x14","Undefined Command 0x15","Undefined Command 0x16","Undefined Command 0x17", + "Undefined Command 0x18","Scan Low Equal", "Undefined Command 0x1A","Undefined Command 0x1B", + "Undefined Command 0x1C","Scan High Equal", "Undefined Command 0x1E","Undefined Command 0x1F" +}; + +static int8 cmdsizes[] = { + 1, 1, 9, 3, 2, 9, 9, 2, + 1, 9, 2, 1, 9, 6, 1, 3, + 1, 9, 1, 1, 1, 1, 1, 1, + 1, 9, 1, 1, 1, 9, 1, 1 +}; + +static int8 resultsizes[] = { + 1, 1, 7, 0, 1, 7, 7, 0, + 2, 7, 7, 1, 7, 7, 1, 0, + 1, 7, 1, 1, 1, 1, 1, 1, + 1, 7, 1, 1, 1, 7, 1, 1 +}; + +/* default routine to select the drive. + * In principle, it just passes the US0/US1 bits into fdc_curdrv, + * but the Sage FD does not use US0/US1 bits of FDC, for whatever reason... + */ +void i8272_seldrv(I8272* chip, int drvnum) +{ + chip->fdc_curdrv = drvnum & 0x03; +} + +/* + * find_unit_index find index of a unit + */ +int32 find_unit_index (UNIT *uptr) +{ + DEVICE *dptr; + uint32 i; + + if (uptr == NULL) return -1; + dptr = find_dev_from_unit(uptr); + + for(i=0; inumunits; i++) + if(dptr->units + i == uptr) break; + + return i == dptr->numunits ? -1 : i; +} + +/* Attach routine */ +t_stat i8272_attach(UNIT *uptr, char *cptr) +{ + char header[4]; + t_stat rc; + int32 i = 0; + I8272* chip; + DEVICE* dptr; + + if ((dptr = find_dev_from_unit(uptr))==NULL) return SCPE_IERR; + if ((chip = (I8272*)dptr->ctxt)==NULL) return SCPE_IERR; + if ((rc = attach_unit(uptr, cptr)) != SCPE_OK) return rc; + + /* Determine length of this disk */ + uptr->capac = sim_fsize(uptr->fileref); + + if ((i = find_unit_index(uptr)) == -1) return SCPE_IERR; + + TRACE_PRINT1(DBG_FD_VERBOSE,"Attach I8272 drive %d\n",i); + chip->drive[i].uptr = uptr; + + /* Default to drive not ready */ + chip->drive[i].ready = 0; + + if(uptr->capac > 0) { + fgets(header, 4, uptr->fileref); + if(strncmp(header, "IMD", 3)) { + printf("I8272: Only IMD disk images are supported\n"); + chip->drive[i].uptr = NULL; + return SCPE_OPENERR; + } + } else { + /* create a disk image file in IMD format. */ + if (diskCreate(uptr->fileref, "$Id: i8272.c 1999 2008-07-22 04:25:28Z hharte $") != SCPE_OK) { + printf("I8272: Failed to create IMD disk.\n"); + chip->drive[i].uptr = NULL; + return SCPE_OPENERR; + } + uptr->capac = sim_fsize(uptr->fileref); + } + + uptr->u3 = IMAGE_TYPE_IMD; + + if (uptr->flags & UNIT_I8272_VERBOSE) { + printf("I8272%d: attached to '%s', type=%s, len=%d\n", i, cptr, + uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->capac); + } + + if(uptr->u3 == IMAGE_TYPE_IMD) { + if (uptr->flags & UNIT_I8272_VERBOSE) + printf("--------------------------------------------------------\n"); + chip->drive[i].imd = diskOpenEx(uptr->fileref, uptr->flags & UNIT_I8272_VERBOSE, dptr, DBG_FD_IMD, 0); + if (uptr->flags & UNIT_I8272_VERBOSE) + printf("\n"); + if (chip->drive[i].imd == NULL) { + printf("I8272: IMD disk corrupt.\n"); + chip->drive[i].uptr = NULL; + return SCPE_OPENERR; + } + chip->drive[i].ready = 1; + } else + chip->drive[i].imd = NULL; + + return SCPE_OK; +} + +/* Detach routine */ +t_stat i8272_detach(UNIT *uptr) +{ + t_stat rc; + int8 i; + DEVICE* dptr; + I8272* chip; + + if ((dptr = find_dev_from_unit(uptr))==NULL) return SCPE_IERR; + if ((chip = (I8272*)dptr->ctxt)==NULL) return SCPE_IERR; + if ((i = find_unit_index(uptr)) == -1) return SCPE_IERR; + + TRACE_PRINT1(DBG_FD_VERBOSE,"Detach I8272 drive %d\n",i); + rc = diskClose(&chip->drive[i].imd); + chip->drive[i].ready = 0; + if (rc != SCPE_OK) return rc; + + return detach_unit(uptr); /* detach unit */ +} + +t_stat i8272_setDMA(I8272* chip, uint32 dma_addr) +{ + chip->fdc_dma_addr = dma_addr & 0xFFFFFF; + return SCPE_OK; +} + +t_stat i8272_io(IOHANDLER* ioh,uint32* value,uint32 rw,uint32 mask) +{ + int port = ioh->offset; + I8272* chip = (I8272*)ioh->ctxt; + if (rw==MEM_WRITE) + return chip->write ? chip->write(chip,port,*value) : i8272_write(chip,port,*value); + else + return chip->read ? chip->read(chip,port,value) : i8272_read(chip,port,value); +} + +t_stat i8272_reset(I8272* chip) +{ + NEXTSTATE(S_CMD); + chip->idcount = 0; + chip->fdc_fault = 0; + + return SCPE_OK; +} + +static uint8 floorlog2(unsigned int n) +{ + /* Compute log2(n) */ + uint8 r = 0; + if (n >= 1<<16) { n >>=16; r += 16; } + if (n >= 1<< 8) { n >>= 8; r += 8; } + if (n >= 1<< 4) { n >>= 4; r += 4; } + if (n >= 1<< 2) { n >>= 2; r += 2; } + if (n >= 1<< 1) { r += 1; } + return ((n == 0) ? (0xFF) : r); /* 0xFF is error return value */ +} + +static t_stat i8272_resultphase(I8272* chip,int delay) +{ + uint8 cmd = chip->cmd[0] & 0x1f; + chip->fdc_msr &= ~I8272_MSR_NON_DMA; + chip->result_len = resultsizes[cmd]; + chip->result_cnt = 0; + NEXTSTATE(S_RESULT); + if (delay) i8272_interrupt(chip,delay); + return SCPE_OK; +} + +/* + * this routine effectively sets the TC input of the FDC; this results in + * terminating a current read or write operation and switches state to RESULT delivery + * Sage-II needs this because during boot it tries to read sector 1...EOT (=9), but actually + * stops polling after 2 sectors by asserting TC + */ +t_stat i8272_finish(I8272* chip) +{ + switch (chip->fdc_state) { + case S_DATAREAD: + case S_DATAWRITE: + case S_SECREAD: + case S_SECWRITE: + case S_RESULT: + TRACE_PRINT0(DBG_FD_VERBOSE,"Finish I/O, returning result"); + chip->irqflag = 0; + chip->result[0] &= 0x3f; /* IC=normal termination */ + return i8272_resultphase(chip,0); + default: /* @TODO is this correct? */ + TRACE_PRINT0(DBG_FD_VERBOSE,"Finish I/O, reset to S_CMD state"); + NEXTSTATE(S_CMD); + return SCPE_OK; + } +} + +/* this routine is called when RDY pin goes to zero, effectively + * terminating I/O immediately and going to S_RESULT state. + */ +t_stat i8272_abortio(I8272* chip) +{ + switch (chip->fdc_state) { + case S_DATAREAD: + case S_DATAWRITE: + case S_SECREAD: + case S_SECWRITE: + TRACE_PRINT0(DBG_FD_VERBOSE,"RDY=0 during I/O, aborting and returning result"); + chip->irqflag = 0; + chip->result[0] |= 0xc0; /* notify RDY change condition */ + return i8272_resultphase(chip,0); + + case S_RESULT: + TRACE_PRINT0(DBG_FD_VERBOSE,"RDY=0, returning result"); + chip->irqflag = 0; + return i8272_resultphase(chip,0); + + default: /* @TODO is this correct? */ + TRACE_PRINT0(DBG_FD_VERBOSE,"Abort I/O, reset to S_CMD state"); + NEXTSTATE(S_CMD); + return SCPE_OK; + } +} + + +static t_stat i8272_dataread(I8272* chip,uint32* value) +{ + if (chip->fdc_nd_cnt < chip->fdc_secsz) { + /* return a single byte */ + chip->irqflag = 0; + *value = chip->fdc_sdata[chip->fdc_nd_cnt]; + TRACE_PRINT2(DBG_FD_RDDATA,"read buffer #%d value=%x", chip->fdc_nd_cnt, *value); + chip->fdc_nd_cnt++; + if (chip->fdc_nd_cnt != chip->fdc_secsz) { + i8272_interrupt(chip,1); /* notify one more byte is ready */ + return SCPE_OK; + } + } + /* more sectors to read? */ + if (chip->fdc_sector <= chip->fdc_eot) { + NEXTSTATE(S_SECREAD); + return SCPE_OK; + } + + /* finished data read */ + TRACE_PRINT0(DBG_FD_RDDATA,"read buffer complete."); + chip->result[0] &= 0x3f; /* clear bits 7,6: terminated correctly */ + return i8272_resultphase(chip,0); +} + +static I8272_DRIVE_INFO* i8272_select_drive(I8272* chip, uint8 drive) +{ + I8272_DRIVE_INFO* dip; + + (*chip->seldrv)(chip,drive); + dip = &chip->drive[chip->fdc_curdrv]; + return dip->uptr == NULL ? NULL : dip; +} + +static t_stat i8272_secread(I8272* chip) +{ + int i; + unsigned int flags = 0; + unsigned int readlen; + I8272_DRIVE_INFO* dip = &chip->drive[chip->fdc_curdrv]; + + /* finished with sector read? */ + if (chip->fdc_sector > chip->fdc_eot) { + TRACE_PRINT2(DBG_FD_RDDATA,"No more sectors: sec=%d EOT=%d",chip->fdc_sector,chip->fdc_eot); + return i8272_resultphase(chip,10); + } + + /* no, read a buffer */ + TRACE_PRINT(DBG_FD_RDDATA,(sim_deb,"RD Data, C/H/S=%d/%d/%d sector len=%d", + dip->track, chip->fdc_head, chip->fdc_sector, chip->fdc_secsz)); + + if (dip->imd == NULL) { + printf(".imd is NULL!" NLP); + return SCPE_STOP; + } + + sectRead(dip->imd, dip->track, chip->fdc_head, chip->fdc_sector, + chip->fdc_sdata, chip->fdc_secsz, &flags, &readlen); + + chip->result[5] = chip->fdc_sector; + chip->result[1] = 0x80; + chip->fdc_sector++; /* prepare next sector */ + + /* DMA mode? */ + if (chip->fdc_nd==0) { /* DMA mode */ + for (i=0; i < chip->fdc_secsz; i++) { + PutByteDMA(chip->fdc_dma_addr, chip->fdc_sdata[i]); + chip->fdc_dma_addr++; + } + TRACE_PRINT(DBG_FD_RDDATA, (sim_deb,"C:%d/H:%d/S:%d/L:%4d: Data transferred to RAM at 0x%06x", + dip->track, chip->fdc_head, chip->fdc_sector, + chip->fdc_secsz, chip->fdc_dma_addr - i)); + } else { + chip->fdc_nd_cnt = 0; /* start buffer transfer */ + TRACE_PRINT0(DBG_FD_RDDATA,"read buffer started."); + + /* go to data transfer state */ + NEXTSTATE(S_DATAREAD); + i8272_interrupt(chip,100); + } + return SCPE_OK; +} + +t_stat i8272_read(I8272* chip,int addr,uint32* value) +{ + t_stat rc; + I8272_DRIVE_INFO* dip; + if ((dip = &chip->drive[chip->fdc_curdrv]) == NULL) { + printf("i8272_read: chip->drive returns NULL, fdc_curdrv=%d\n",chip->fdc_curdrv); + return SCPE_IERR; + } + + switch(addr & 0x1) { + case I8272_FDC_MSR: + *value = chip->fdc_msr | I8272_MSR_RQM; + switch (chip->fdc_state) { + case S_CMD: + case S_CMDREAD: + *value &= ~(I8272_MSR_DATA_OUT|I8272_MSR_FDC_BUSY); + return SCPE_OK; + case S_SECREAD: + case S_DATAWRITE: + case S_DATAREAD: + case S_SECWRITE: + case S_EXEC: + *value |= (I8272_MSR_DATA_OUT|I8272_MSR_FDC_BUSY); + break; + + case S_RESULT: + *value |= I8272_MSR_DATA_OUT; + *value &= ~I8272_MSR_FDC_BUSY; + break; + default: + printf("Default case in i8272_read(FDC_MSR): state=%d\n",chip->fdc_state); + return SCPE_IERR; + } + TRACE_PRINT1(DBG_FD_STATUS,"RD FDC MSR = 0x%02x",*value); + return SCPE_OK; + + case I8272_FDC_DATA: + for (;;) { + switch (chip->fdc_state) { + case S_DATAREAD: /* only comes here in non-DMA mode */ + if ((rc=i8272_dataread(chip,value)) != SCPE_OK) return rc; + if (chip->fdc_state == S_RESULT || + chip->fdc_state == S_DATAREAD) return SCPE_OK; + /* otherwise will immediately move to state S_SECREAD */ + break; + + case S_SECREAD: + if ((rc=i8272_secread(chip)) != SCPE_OK) return rc; + if (chip->fdc_state ==S_DATAREAD) return SCPE_OK; + /* will immediately move to state S_RESULT */ + case S_RESULT: + *value = chip->result[chip->result_cnt]; + TRACE_PRINT2(DBG_FD_STATUS, "Result [%d]=0x%02x",chip->result_cnt, *value); + chip->irqflag = 0; + chip->result_cnt ++; + if(chip->result_cnt == chip->result_len) { + TRACE_PRINT0(DBG_FD_STATUS,"Result phase complete.\n"); + NEXTSTATE(S_CMD); + } + +#if 0 + else { + i8272_interrupt(chip,5); + } +#endif + return SCPE_OK; + + case S_CMD: + case S_CMDREAD: + case S_EXEC: + case S_DATAWRITE: + case S_SECWRITE: + *value = chip->result[0]; /* hack, in theory any value should be ok but this makes "format" work */ + TRACE_PRINT1(DBG_FD_VERBOSE,"error, reading data register when not in data phase. Returning 0x%02x",*value); + return SCPE_OK; + + default: + printf("Default case in i8272_read(FDC_DATA): state=%d\n",chip->fdc_state); + return SCPE_IERR; + } + } + return SCPE_OK; + default: + TRACE_PRINT1(DBG_FD_VERBOSE,"Cannot read register %x",addr); + *value = 0xFF; + } + + return SCPE_OK; +} + +static t_stat i8272_makeresult(I8272* chip, uint8 s0, uint8 s1, uint8 s2, uint8 s3,uint8 s4, uint8 s5, uint8 s6) +{ + chip->result[0] = s0; + chip->result[1] = s1; + chip->result[2] = s2; + chip->result[3] = s3; + chip->result[4] = s4; + chip->result[5] = s5; + chip->result[6] = s6; + chip->result_cnt = 0; + chip->fdc_fault = 0; + return SCPE_OK; +} + +static I8272_DRIVE_INFO* i8272_decodecmdbits(I8272* chip) +{ + /* note this routine is also used in places where MT or SK bits are irrelevant. + * chip docs imply these bits to be set to 0 + */ + chip->fdc_mt = (chip->cmd[0] & 0x80) >> 7; + chip->fdc_mfm = (chip->cmd[0] & 0x40) >> 6; + chip->fdc_sk = (chip->cmd[0] & 0x20) >> 5; + chip->fdc_hds = (chip->cmd[1] & 0x04) ? 1 : 0; + return i8272_select_drive(chip,chip->cmd[1]); +} + +#define msgMFM (chip->fdc_mfm ? "MFM" : "FM") +#define msgMT (chip->fdc_mt ? "Multi" : "Single") +#define msgSK (chip->fdc_sk ? "True" : "False") +#define msgHDS (chip->fdc_hds ? "True" : "False") +#define msgND (chip->fdc_nd ? "NON-DMA" : "DMA") +#define msgCMD messages[cmd] + +static t_stat i8272_nodriveerror(I8272* chip,const char* command,int delay) +{ + uint8 st0; + + TRACE_PRINT1(DBG_FD_ERROR,"%s: no drive or disk\n",command); + st0 = 0x40 | 0x10 | chip->fdc_curdrv; + i8272_makeresult(chip, st0, 0, 0, 0, 0, 0, 0); + return i8272_resultphase(chip,delay); +} + + +static t_stat i8272_format(I8272* chip) +{ + uint8 track, fillbyte, sc, cnt; + uint8 sectormap[I8272_MAX_SECTOR]; /* Physical to logical sector map for FORMAT TRACK */ + unsigned int flags = 0; + int i; + I8272_DRIVE_INFO* dip; + + /* get MFM bit, others are irrelevant */ + if ((dip = i8272_decodecmdbits(chip)) == NULL) + return i8272_nodriveerror(chip,"Format",10); + + track = dip->track; + chip->fdc_seek_end = track != chip->cmd[2] ? 1 : 0; + chip->fdc_sec_len = chip->cmd[2]; + chip->fdc_secsz = I8272_SEC2SZ(chip->fdc_sec_len); + if(chip->fdc_sec_len > I8272_MAX_N) { + TRACE_PRINT(DBG_FD_ERROR, (sim_deb,"Illegal sector size %d [N=%d]. Reset to %d [N=%d].", + chip->fdc_secsz, chip->fdc_sec_len, + I8272_MAX_SECTOR_SZ, I8272_MAX_N)); + chip->fdc_sec_len = I8272_MAX_N; + } + chip->fdc_secsz = I8272_SEC2SZ(chip->fdc_sec_len); + + sc = chip->cmd[3]; + chip->fdc_gap = chip->cmd[4]; + fillbyte = chip->cmd[5]; + + TRACE_PRINT(DBG_FD_FMT,(sim_deb,"Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x", + chip->fdc_curdrv, msgMFM, track, chip->fdc_head, chip->fdc_sec_len, sc, chip->fdc_gap, fillbyte)); + + cnt = 0; + + i8272_makeresult(chip, + ((chip->fdc_hds & 1) << 2) | chip->fdc_curdrv, + 0, 0, track, + chip->fdc_head, /* AGN for now we cannot format with logicalHead */ + chip->fdc_sector, /* AGN ditto for logicalCyl */ + chip->fdc_sec_len); + + for(i = 1; i <= sc; i++) { + TRACE_PRINT(DBG_FD_CMD, (sim_deb,"Format Track %d, Sector=%d, len=%d", + track, i, chip->fdc_secsz)); + + if(cnt >= I8272_MAX_SECTOR) { + TRACE_PRINT0(DBG_FD_ERROR,"Illegal sector count"); + cnt = 0; + } + sectormap[cnt] = i; + cnt++; + if(cnt == sc) { + trackWrite(dip->imd, track, chip->fdc_head, sc, + chip->fdc_secsz, sectormap, chip->fdc_mfm ? 3 : 0, + fillbyte, &flags); + + /* Recalculate disk size */ + dip->uptr->capac = sim_fsize(dip->uptr->fileref); + } + } + chip->fdc_sector = sc; + return i8272_resultphase(chip,1000); +} + +static t_stat i8272_readid(I8272* chip) +{ + TRACK_INFO* curtrk; + I8272_DRIVE_INFO* dip; + uint8 hds = chip->fdc_hds; + + if ((dip = i8272_decodecmdbits(chip)) == NULL) + return i8272_nodriveerror(chip,"Readid",10); + + curtrk = &dip->imd->track[dip->track][hds]; + + /* Compute the i8272 "N" value from the sectorsize of this */ + /* disk's current track - i.e. N = log2(sectsize) - log2(128) */ + /* The calculation also works for non-standard format disk images with */ + /* sectorsizes of 2048, 4096 and 8192 bytes */ + chip->fdc_sec_len = floorlog2(curtrk->sectsize) - 7; /* AGN fix to use fdc_hds (was fdc_head)*/ + chip->fdc_secsz = I8272_SEC2SZ(chip->fdc_sec_len); + + /* HV we cycle the read sectors on each call of READID to emulator disk spinning */ + /* Sage BIOS need this to find the highest sector number. */ + /* This could be improved by adding some delay based */ + /* on elapsed time for a more "realistic" simulation. */ + /* This would allow disk analysis programs that use */ + /* READID to detect non-standard disk formats. */ + if (chip->idcount == 0 || chip->idcount >= curtrk->nsects) { + chip->fdc_sector = curtrk->start_sector; + chip->idcount = 1; + } else { + chip->fdc_sector++; + chip->idcount++; + } + if((chip->fdc_sec_len == 0xF8) || (chip->fdc_sec_len > I8272_MAX_N)) { /* Error calculating N or N too large */ + TRACE_PRINT1(DBG_FD_ERROR,"Illegal sector size N=%d. Reset to 0.",chip->fdc_sec_len); + chip->fdc_sec_len = 0; + chip->fdc_secsz = 0; + return SCPE_OK; + } + + /* build result */ + i8272_makeresult(chip, + ((hds & 1) << 2) | chip->fdc_curdrv, + 0, 0, + curtrk->logicalCyl[chip->fdc_sector], /* AGN logicalCyl */ + curtrk->logicalHead[chip->fdc_sector], /* AGN logicalHead */ + chip->fdc_sector, + chip->fdc_sec_len); + + TRACE_PRINT(DBG_FD_CMD, (sim_deb, + "READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x C=%d H=%d R=%02x N=%d", + chip->fdc_curdrv, chip->result[0], + chip->result[1],chip->result[2],chip->result[3], + chip->result[4],chip->result[5],chip->result[6])); + return i8272_resultphase(chip,20); +} + +static t_stat i8272_seek(I8272* chip) +{ + I8272_DRIVE_INFO* dip; + if ((dip = i8272_decodecmdbits(chip)) == NULL) + return i8272_nodriveerror(chip,"Seek",10); + + dip->track = chip->cmd[2]; + chip->fdc_head = chip->fdc_hds; /*AGN seek should save the head */ + chip->fdc_seek_end = 1; + TRACE_PRINT(DBG_FD_SEEK, (sim_deb,"Seek Drive: %d, %s %s, C=%d. Skip Deleted Data=%s Head Select=%s", + chip->fdc_curdrv, msgMT, msgMFM, chip->cmd[2], msgSK, msgHDS)); + + NEXTSTATE(S_CMD); /* no result phase */ + i8272_interrupt(chip,100); + return SCPE_OK; +} + +static t_stat i8272_senseint(I8272* chip) +{ + I8272_DRIVE_INFO* dip = &chip->drive[chip->fdc_curdrv]; + uint8 st0 = (chip->fdc_seek_end ? 0x20 : 0x00) | chip->fdc_curdrv; + if (chip->fdc_fault) + st0 |= (0x40 | chip->fdc_fault); + + TRACE_PRINT2(DBG_FD_CMD,"Sense Interrupt Status ST0=0x%x PCN=%d",st0,dip->track); + i8272_makeresult(chip, st0, dip->track, 0,0,0,0,0); + chip->irqflag = 0; /* clear interrupt flag, don't raise a new one */ + return i8272_resultphase(chip,0); +} + +static t_stat i8272_sensedrive(I8272* chip) +{ + uint8 st3; + I8272_DRIVE_INFO* dip; + t_bool track0; + + if ((dip = i8272_select_drive(chip,chip->cmd[1])) == NULL) { + printf("i8272_sensedrive: i8272_select_drive returns 0\n"); + st3 = DRIVE_STATUS_FAULT; + track0 = FALSE; + } else { + track0 = dip->track == 0; + st3 = dip->ready ? DRIVE_STATUS_READY : 0; /* Drive Ready */ + if(imdGetSides(dip->imd) == 2) { + st3 |= DRIVE_STATUS_TWO_SIDED; /* Two-sided? */ + } + if(imdIsWriteLocked(dip->imd) || (dip->uptr->flags & UNIT_I8272_WLK)) { + st3 |= DRIVE_STATUS_WP; /* Write Protected? */ + } + } + st3 |= (chip->fdc_hds & 1) << 2; + st3 |= chip->fdc_curdrv; + st3 |= track0 ? DRIVE_STATUS_TRACK0 : 0x00; /* Track 0 */ + i8272_makeresult(chip, st3, 0, 0, 0, 0, 0, 0); + + TRACE_PRINT1(DBG_FD_CMD,"Sense Drive Status = 0x%02x", st3); + return i8272_resultphase(chip,5); +} + +static t_stat i8272_recalibrate(I8272* chip) +{ + I8272_DRIVE_INFO* dip; + if ((dip = i8272_select_drive(chip,chip->cmd[1])) == NULL) { + TRACE_PRINT1(DBG_FD_ERROR,"Recalibrate: no drive or disk drive=%x\n",chip->cmd[1]); + chip->fdc_fault = 0x10; /* EC error */ + } else { + dip->track = 0; + chip->idcount = 0; /* initialize the ID cycler (used by READID) */ +// chip->fdc_seek_end = 1; + chip->fdc_seek_end = 0; + } + TRACE_PRINT2(DBG_FD_SEEK,"Recalibrate: Drive 0x%02x, EC=%d",chip->fdc_curdrv,chip->fdc_fault?1:0); + + NEXTSTATE(S_CMD); /* No result phase */ + i8272_interrupt(chip,20); + return SCPE_OK; +} + +static t_stat i8272_specify(I8272* chip) +{ + chip->fdc_fault = 0; + chip->fdc_nd = chip->cmd[2] & 0x01; /* DMA/non-DMA mode */ + TRACE_PRINT(DBG_FD_CMD, (sim_deb,"Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s", + 16 - ((chip->cmd[1] & 0xF0) >> 4), /*SRT*/ + (chip->cmd[1] & 0x0F) * 16, /*HUT*/ + ((chip->cmd[2] & 0xFE) >> 1) * 2, /*HLT*/ + msgND)); + + NEXTSTATE(S_CMD); /* no result phase */ + i8272_interrupt(chip,1); + return SCPE_OK; +} + +static t_bool i8272_secrw(I8272* chip,uint8 cmd) +{ + TRACK_INFO* curtrk; + I8272_DRIVE_INFO* dip; + if ((dip = i8272_decodecmdbits(chip)) == NULL) return FALSE; + + chip->fdc_seek_end = dip->track != chip->cmd[2] ? 1 : 0; + if (dip->track != chip->cmd[2]) { + TRACE_PRINT(DBG_FD_CMD, (sim_deb, + "ERROR: CMD=0x%02x[%s]: Drive: %d, Command wants track %d, but positioner is on track %d.", + cmd, msgCMD, chip->fdc_curdrv, chip->cmd[2], dip->track)); + } + + dip->track = chip->cmd[2]; + chip->fdc_head = chip->cmd[3] & 1; /* AGN mask to head 0 or 1 */ + curtrk = &dip->imd->track[dip->track][chip->fdc_head]; + + chip->fdc_sector = chip->cmd[4]; + chip->fdc_sec_len = chip->cmd[5]; + if(chip->fdc_sec_len > I8272_MAX_N) { + TRACE_PRINT(DBG_FD_ERROR, (sim_deb,"Illegal sector size %d [N=%d]. Reset to %d [N=%d].", + I8272_SEC2SZ(chip->fdc_sec_len), chip->fdc_sec_len, + I8272_MAX_SECTOR_SZ, I8272_MAX_N)); + chip->fdc_sec_len = I8272_MAX_N; + } + chip->fdc_secsz = I8272_SEC2SZ(chip->fdc_sec_len); + chip->fdc_eot = chip->cmd[6]; + chip->fdc_gap = chip->cmd[7]; + chip->fdc_dtl = chip->cmd[8]; + + TRACE_PRINT(DBG_FD_CMD, (sim_deb, + "CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, EOT=%02x, GPL=%02x, DTL=%02x", + cmd, msgCMD, chip->fdc_curdrv, msgMT, msgMFM, + dip->track, chip->fdc_head, chip->fdc_sector, + chip->fdc_sec_len, chip->fdc_eot, chip->fdc_gap, chip->fdc_dtl)); + + i8272_makeresult(chip, + ((chip->fdc_hds & 1) << 2) | chip->fdc_curdrv | 0x40, + 0, 0, + curtrk->logicalCyl[chip->fdc_sector], /* AGN logicalCyl */ + curtrk->logicalHead[chip->fdc_sector], /* AGN logicalHead */ + chip->fdc_sector, + chip->fdc_sec_len); + chip->result_cnt = 0; + chip->fdc_nd_cnt = 0; /* start buffer transfer */ + return TRUE; +} + +static t_bool i8272_secwrite(I8272* chip) +{ + unsigned int readlen; + unsigned int flags = 0; + I8272_DRIVE_INFO* dip = &chip->drive[chip->fdc_curdrv]; + + TRACE_PRINT(DBG_FD_WRDATA, (sim_deb,"SecWrite: C:%d/H:%d/S:%d/L:%4d", + dip->track, chip->fdc_head, chip->fdc_sector, + chip->fdc_secsz)); + sectWrite(dip->imd, dip->track, chip->fdc_head, chip->fdc_sector, + chip->fdc_sdata, chip->fdc_secsz, &flags, &readlen); + chip->fdc_sector++; + if (chip->fdc_sector > chip->fdc_eot) + return i8272_resultphase(chip,200); + + NEXTSTATE(S_DATAWRITE); + if (chip->fdc_nd) { /* non-DMA */ + chip->fdc_nd_cnt = 0; + i8272_interrupt(chip,10); /* non-DMA: initiate next sector write */ + return TRUE; + } + return FALSE; +} + +static t_bool i8272_datawrite(I8272* chip,uint32 value,I8272_DRIVE_INFO* dip) +{ + int i; + + /* finished with sector write? */ + if (chip->fdc_sector > chip->fdc_eot) { + TRACE_PRINT0(DBG_FD_WRDATA,"Finished sector write"); + return i8272_resultphase(chip,200); + } + if (chip->fdc_nd == 0) { /* DMA */ + for (i=0; i< chip->fdc_secsz; i++) { + chip->fdc_sdata[i] = GetByteDMA(chip->fdc_dma_addr); + chip->fdc_dma_addr++; + } + TRACE_PRINT(DBG_FD_WRDATA, (sim_deb,"C:%d/H:%d/S:%d/L:%4d: Data transferred from RAM at 0x%06x", + dip->track, chip->fdc_head, chip->fdc_sector, + chip->fdc_secsz, chip->fdc_dma_addr - i)); + } else { /* non-DMA */ + chip->fdc_msr |= I8272_MSR_NON_DMA; + if ((chip->fdc_nd_cnt+1) < chip->fdc_secsz) { + chip->fdc_sdata[chip->fdc_nd_cnt] = value; + TRACE_PRINT(DBG_FD_WRDATA,(sim_deb,"write buffer #%d value=%x (%c)", chip->fdc_nd_cnt,value,isprint(value)?value:'?')); + chip->fdc_nd_cnt++; + /* not yet finished buffering data, leave writer routine */ + i8272_interrupt(chip,10); + TRACE_PRINT0(DBG_FD_WRDATA,"Expect more data"); + return TRUE; + } + } + TRACE_PRINT0(DBG_FD_WRDATA,"Finished with data write"); + return FALSE; +} + +t_stat i8272_write(I8272* chip, int addr, uint32 value) +{ + uint8 cmd; + I8272_DRIVE_INFO* dip; + if ((dip = &chip->drive[chip->fdc_curdrv]) == NULL) { + printf("i8272_write: chip->drive returns 0 fdc_curdrv=%d\n",chip->fdc_curdrv); + return SCPE_IERR; + } + + switch(addr & 0x1) { + case I8272_FDC_MSR: + TRACE_PRINT1(DBG_FD_VERBOSE,"WR Drive Select Reg=%02x", value); + return SCPE_OK; + + case I8272_FDC_DATA: + chip->fdc_msr &= 0xF0; + TRACE_PRINT2(DBG_FD_VERBOSE,"WR Data, index=%d value=%x", chip->cmd_cnt,value); + + for (;;) { + switch (chip->fdc_state) { + case S_CMD: + /* first cmd byte */ + cmd = value & 0x1f; + chip->cmd_cnt = 0; + TRACE_PRINT2(DBG_FD_CMD,"CMD=0x%02x[%s]", cmd, msgCMD); + chip->cmd_len = cmdsizes[cmd]; + NEXTSTATE(S_CMDREAD); + /*fallthru*/ + case S_CMDREAD: + /* following cmd bytes */ + chip->cmd[chip->cmd_cnt] = value; + chip->cmd_cnt++; + + if (chip->cmd_cnt == chip->cmd_len) { + chip->fdc_nd_cnt = 0; /* initialize counter for Non-DMA mode */ + chip->cmd_cnt = 0; /* reset index for next CMD */ + NEXTSTATE(S_EXEC); /* continue immediately with S_EXEC code */ + break; + } + return SCPE_OK; + case S_DATAREAD: /* data reading happens in i8272_read */ + return SCPE_OK; + case S_RESULT: /* result polling happens in i8272_read */ + return SCPE_OK; + case S_DATAWRITE: + if (i8272_datawrite(chip,value,dip)) return SCPE_OK; + TRACE_PRINT0(DBG_FD_WRDATA,"Go Sector Write"); + NEXTSTATE(S_SECWRITE); + /*fallthru*/ + case S_SECWRITE: /* write buffer */ + if (i8272_secwrite(chip)) return SCPE_OK; + break; + case S_SECREAD: + return i8272_secread(chip); + case S_EXEC: + cmd = chip->cmd[0] & 0x1f; + switch (cmd) { + case I8272_SPECIFY: + return i8272_specify(chip); + + case I8272_SENSE_INTR_STATUS: + return i8272_senseint(chip); + + case I8272_SENSE_DRIVE_STATUS: /* Setup Status3 Byte */ + return i8272_sensedrive(chip); + + case I8272_RECALIBRATE: /* RECALIBRATE */ + return i8272_recalibrate(chip); + + case UPD765_VERSION: + i8272_makeresult(chip, 0x80, 0, 0, 0, 0, 0, 0); + /* signal UPD765A, don't know whether B version (0x90) is relevant */ + return i8272_resultphase(chip,5); + + case I8272_SEEK: /* SEEK */ + return i8272_seek(chip); + + case I8272_READ_ID: + return i8272_readid(chip); + + case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ + return i8272_format(chip); + + case I8272_READ_TRACK: + printf("I8272: " ADDRESS_FORMAT " Read a track (untested.)" NLP, PCX); + chip->fdc_sector = 1; /* Read entire track from sector 1...eot */ + case I8272_READ_DATA: + case I8272_READ_DELETED_DATA: + if (!i8272_secrw(chip,cmd)) + return i8272_nodriveerror(chip,"I8272_READ_*_DATA",10); + + /* go directly to secread state */ + NEXTSTATE(S_SECREAD); + break; + + case I8272_WRITE_DATA: + case I8272_WRITE_DELETED_DATA: + if (!i8272_secrw(chip,cmd)) + return i8272_nodriveerror(chip,"I8272_WRITE_*_DATA",10); + + NEXTSTATE(S_DATAWRITE); /* fill buffer */ + if (chip->fdc_nd != 0) { /* non-DMA */ + i8272_interrupt(chip,100); /* request the first data byte */ + return SCPE_OK; + } + break; + + case I8272_SCAN_LOW_EQUAL: + case I8272_SCAN_HIGH_EQUAL: + case I8272_SCAN_EQUAL: + if (!i8272_secrw(chip,cmd)) + return i8272_nodriveerror(chip,"I8272_SCAN_*",10); + + TRACE_PRINT0(DBG_FD_CMD,"Scan Data"); + TRACE_PRINT0(DBG_FD_ERROR,"ERROR: Scan not implemented."); + return i8272_resultphase(chip,200); + } + } + } + /*NOTREACHED*/ + + default: + return SCPE_OK; + } +} + +static void i8272_interrupt(I8272* chip,int delay) +{ + TRACE_PRINT0(DBG_FD_IRQ,"FDC Interrupt"); + chip->irqflag = 1; + (*chip->irq)(chip,delay); +} diff --git a/SAGE/m68k_cpu.c b/SAGE/m68k_cpu.c new file mode 100644 index 00000000..c759185d --- /dev/null +++ b/SAGE/m68k_cpu.c @@ -0,0 +1,3352 @@ +/* m68k_cpu.c: 68k-CPU simulator + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version + 25-Apr-10 HV Fixed LSR.W and ROXR.B instructions + 26-Jun-10 HV Incomplete decoding of BCHG d,d instruction + 15-Jul-10 HV IRQ logic loses lower prio interrupts + 17-Jul-10 HV Implement Call/Exit Tracing with symbol table lookup + 17-Jul-10 HV Mustn't grant interrupt at level == IPL + 18-Jul-10 HV Broken address calculation for AIDX and EA_W_RMW, wonder why this didn't pop up earlier. + 20-Jul-10 HV Corrected ADDQ.W/SUBQ.W for EA_ADIR, EOR.[WL] + 23-Jul-10 HV Broken C code sequence in lsl.l + 23-Jul-10 HV RTE didn't set/reset S bit +*/ + +#include "m68k_cpu.h" +#include + +#if defined(_WIN32) +#include +#else +#include +#endif + +/* status reg flags */ +#define FLAG_C 0x0001 +#define FLAG_V 0x0002 +#define FLAG_Z 0x0004 +#define FLAG_N 0x0008 +#define FLAG_X 0x0010 +#define FLAG_I0 0x0100 +#define FLAG_I1 0x0200 +#define FLAG_I2 0x0400 +#define FLAG_IPL_MASK (FLAG_I0|FLAG_I1|FLAG_I2) +#define FLAG_S 0x2000 +#define FLAG_T 0x8000 +#define FLAG_T1 FLAG_T +#define FLAG_T0 0x4000 + +#define BIT7 0x80 +#define BIT8 0x100 +#define BIT15 0x8000 +#define BIT16 0x10000 +#define BIT31 0x80000000 +#define BIT32 0x100000000L + +#define MASK_0(x) ((x) & 1) +#define MASK_8U(x) ((x) & 0xffffff00) +#define MASK_8L(x) ((x) & 0x000000ff) +#define MASK_8SGN(x) ((x) & BIT7) +#define MASK_9(x) ((x) & BIT8) +#define MASK_16U(x) ((x) & 0xffff0000) +#define MASK_16L(x) ((x) & 0x0000ffff) +#define MASK_16SGN(x) ((x) & BIT15) +#define MASK_17(x) ((x) & BIT16) +#define MASK_32U(x) (0) +#define MASK_32L(x) ((x) & 0xffffffff) +#define MASK_32SGN(x) ((x) & BIT31) +#define MASK_33(x) ((x) & BIT32) + +#define COMBINE8(tgt,src) (MASK_8U(tgt) | MASK_8L(src)) +#define COMBINE16(tgt,src) (MASK_16U(tgt) | MASK_16L(src)) +#define COMBINE32(tgt,src) MASK_32L(src) + +extern t_addr addrmask; + +static t_addr addrmasks[] = { + 0x00ffffff, /*68000*/ + 0x000fffff, /*68008*/ + 0x00ffffff, /*68010*/ + 0xffffffff, /*68020*/ + 0xffffffff /*68030*/ +}; + +int16 cputype = CPU_TYPE_68000 >> UNIT_CPU_V_TYPE; + +/* CPU data structures + * m68kcpu_dev CPU device descriptor + * m68kcpu_unit CPU unit descriptor + * m68kcpu_reg CPU register list + * m68kcpu_mod CPU modifiers list + */ + +UNIT *m68kcpu_unit; /* must be set elsewhere */ +DEVICE *m68kcpu_dev; /* must be set elsewhere */ + +void (*m68kcpu_trapcallback)(DEVICE* dptr,int trapnum) = 0; + +/* register set */ +int32 DR[8]; +#define D0 DR[0] +#define D1 DR[1] +#define D2 DR[2] +#define D3 DR[3] +#define D4 DR[4] +#define D5 DR[5] +#define D6 DR[6] +#define D7 DR[7] +t_addr AR[8]; +#define A0 AR[0] +#define A1 AR[1] +#define A2 AR[2] +#define A3 AR[3] +#define A4 AR[4] +#define A5 AR[5] +#define A6 AR[6] +#define A7 AR[7] +t_addr USP; +t_addr *cur_sp; + +uint16 SR; +#define CCR_C (SR & FLAG_C) +#define CCR_V (SR & FLAG_V) +#define CCR_Z (SR & FLAG_Z) +#define CCR_N (SR & FLAG_N) +#define CCR_X (SR & FLAG_X) +#define SR_IPL ((SR & FLAG_IPL_MASK)>>8) +#define SR_S (SR & FLAG_S) +#define SR_T (SR & FLAG_T) +#define SR_T0 (SR & FLAG_T0) +#define SR_T1 (SR & FLAG_T1) + +#define ONEF(flag) SR |= (flag) +#define CLRF(flag) SR &= ~(flag) +#define SETF(cond,flag) if (cond) SR |= (flag); else SR &= ~(flag) +#define SETZ8(cond) if (MASK_8L(cond)) SR &= ~FLAG_Z; else SR |= FLAG_Z +#define SETZ16(cond) if (MASK_16L(cond)) SR &= ~FLAG_Z; else SR |= FLAG_Z +#define SETZ32(cond) if (MASK_32L(cond)) SR &= ~FLAG_Z; else SR |= FLAG_Z +#define SETNZ8(cond) SETZ8(cond); if (MASK_8SGN(cond)) SR |= FLAG_N; else SR &= ~FLAG_N +#define SETNZ16(cond) SETZ16(cond); if (MASK_16SGN(cond)) SR |= FLAG_N; else SR &= ~FLAG_N +#define SETNZ32(cond) SETZ32(cond); if (MASK_32SGN(cond)) SR |= FLAG_N; else SR &= ~FLAG_N +#define SETV_ADD8(a1,a2,r) SETF(MASK_8SGN(((a1)^(r))&((a2)^(r))),FLAG_V); +#define SETV_ADD16(a1,a2,r) SETF(MASK_16SGN(((a1)^(r))&((a2)^(r))),FLAG_V); +#define SETV_ADD32(a1,a2,r) SETF(MASK_32SGN(((a1)^(r))&((a2)^(r))),FLAG_V); +#define SETV_SUB8(s,d,r) SETF(MASK_8SGN(((s)^(d))&((r)^(d))),FLAG_V) +#define SETV_SUB16(s,d,r) SETF(MASK_16SGN(((s)^(d))&((r)^(d))),FLAG_V) +#define SETV_SUB32(s,d,r) SETF(MASK_32SGN(((s)^(d))&((r)^(d))),FLAG_V) + +#define ASSERT_PRIV() if (!SR_S) { rc = STOP_PRVIO; break; } +#define ASSERT_OK(func) if ((rc=(func)) != SCPE_OK) break +#define ASSERT_OKRET(func) if ((rc=(func)) != SCPE_OK) return rc + +#define AREG(r) (r==7 ? cur_sp : &AR[r]) + +uint16 SFC; +uint16 DFC; +uint32 VBR; +t_addr saved_PC; +static t_bool intpending; +static int m68k_sublevel; + +REG m68kcpu_reg[] = { + { HRDATA (D0, DR[0], 32) }, + { HRDATA (D1, DR[1], 32) }, + { HRDATA (D2, DR[2], 32) }, + { HRDATA (D3, DR[3], 32) }, + { HRDATA (D4, DR[4], 32) }, + { HRDATA (D5, DR[5], 32) }, + { HRDATA (D6, DR[6], 32) }, + { HRDATA (D7, DR[7], 32) }, + { HRDATA (A0, AR[0], 32) }, + { HRDATA (A1, AR[1], 32) }, + { HRDATA (A2, AR[2], 32) }, + { HRDATA (A3, AR[3], 32) }, + { HRDATA (A4, AR[4], 32) }, + { HRDATA (A5, AR[5], 32) }, + { HRDATA (A6, AR[6], 32) }, + { HRDATA (A7, AR[7], 32) }, + { HRDATA (SSP, AR[7], 32) }, + { HRDATA (USP, USP, 32) }, + { HRDATA (PC, saved_PC, 32) }, + { HRDATA (SR, SR, 16) }, + { HRDATA (CCR, SR, 8) }, + { FLDATA (C, SR, 0) }, + { FLDATA (V, SR, 1) }, + { FLDATA (Z, SR, 2) }, + { FLDATA (N, SR, 3) }, + { FLDATA (X, SR, 4) }, + { GRDATA (IPL, SR, 8, 3, 8) }, + { FLDATA (S, SR, 13) }, + { FLDATA (T, SR, 15) }, + { HRDATA (SFC, SFC, 3), REG_HIDDEN }, + { HRDATA (DFC, DFC, 3), REG_HIDDEN }, + { HRDATA (VBR, VBR, 32), REG_RO }, + { FLDATA (IRQPEN, intpending, 0), REG_HIDDEN }, + { NULL } +}; + +DEBTAB m68kcpu_dt[] = { + { "EXC", DBG_CPU_EXC }, + { "PC", DBG_CPU_PC }, + { "INT", DBG_CPU_INT }, + { "CTRACE", DBG_CPU_CTRACE }, + { "BTRACE", DBG_CPU_BTRACE }, + { NULL, 0 } +}; + +static char *condnames[] = { + "RA", "SR", "HI", "LS", "CC", "CS", "NE", "EQ", "VC", "VS", "PL", "MI", "GE", "LT", "GT", "LE" +}; + +#if 0 +/* sample code */ +static MTAB m68kcpu_mod[] = { + M68KCPU_STDMOD, + { 0 } +}; + +DEVICE m68kcpu_dev = { + "CPU", &m68kcpu_unit, m68kcpu_reg, m68kcpu_mod, + 1, 16, 32, 2, 16, 16, + &m68kcpu_ex, &m68kcpu_dep, &m68kcpu_reset, + &m68kcpu_boot, NULL, NULL, + NULL, DEV_DEBUG, 0, + m68kcpu_dt, NULL, NULL +}; +#endif + +static DEVICE* cpudev_self = 0; + +t_stat m68kcpu_peripheral_reset() +{ + t_stat rc; + DEVICE** devs = sim_devices; + DEVICE* dptr; + if (!devs) return SCPE_IERR; + + while ((dptr = *devs) != NULL) { + if (dptr != cpudev_self) { + ASSERT_OKRET(dptr->reset(dptr)); + } + devs++; + } + return SCPE_OK; +} + +/* simple prefetch I cache */ +#define CACHE_SIZE 16 +#define CACHE_MASK 0x0f + +static t_addr cache_pc; +static uint8 cache_line[CACHE_SIZE]; + +static t_stat ReadICache(t_addr tpc) +{ + int i; + t_stat rc; + uint8* mem; + + ASSERT_OKRET(Mem((tpc+CACHE_SIZE)&addrmask,&mem)); + + /* 68000/08/10 do not like unaligned access */ + if (cputype < 3 && (tpc & 1)) return STOP_ERRADR; + + for (i=CACHE_SIZE; i>=0; i--) { + cache_line[i] = *mem--; + } +// for (i=0; i<16; i++) printf("icache[%d]=0x%08x\n",i,cache_line[i]); + return SCPE_OK; +} + +static t_stat ReadInstr(t_addr pc,uint32* inst) +{ + t_stat rc; + t_addr tpc; + IOHANDLER* ioh; + + if ((rc=TranslateAddr(pc & ~CACHE_MASK,&tpc,&ioh,MEM_READ,FALSE,FALSE)) != SCPE_OK) + return rc==SIM_ISIO ? STOP_PCIO : rc; + if (tpc != cache_pc) { + ASSERT_OKRET(ReadICache(tpc)); + } + pc &= CACHE_MASK; + *inst = (cache_line[pc]<<8) | cache_line[pc+1]; + return SCPE_OK; +} + +static t_stat ReadInstrInc(t_addr* pc,uint32* inst) +{ + t_stat rc; + ASSERT_OKRET(ReadInstr(*pc,inst)); + *pc += 2; + return SCPE_OK; +} + +static t_stat ReadInstrLongInc(t_addr* pc,uint32* inst) +{ + t_stat rc; + uint32 val1,val2; + ASSERT_OKRET(ReadInstr(*pc,&val1)); + *pc += 2; + ASSERT_OKRET(ReadInstr(*pc,&val2)); + *pc += 2; + *inst = COMBINE16(val1<<16,val2); + return SCPE_OK; +} + + +void m68k_set_s(t_bool tf) +{ + if (tf) { + SR |= FLAG_S; + cur_sp = &A7; + } else { + SR &= ~FLAG_S; + cur_sp = &USP; + } +} + +void m68k_setipl(int ipl) +{ +// printf("set ipl to %d\n",ipl); + SR &= ~FLAG_IPL_MASK; + SR |= (ipl & 7) << 8; +} + +/* interrupt logic */ +static int intvectors[8]; + +static t_stat m68k_irqinit() +{ + int i; + for (i=0; i<8; i++) intvectors[i] = 0; + intpending = 0; + return SCPE_OK; +} + +t_stat m68k_raise_vectorint(int level,int vector) +{ + int mask = 1<reset(dptr); +} + +/* for instruction decoder */ +#define IR_1512 (IR&0170000) +#define IR_1109 (IR&0007000) +#define IR_1108 (IR&0007400) +#define IR_1106 (IR&0007700) +#define IR_1103 (IR&0007770) +#define IR_08 (IR&0000400) +#define IR_0806 (IR&0000700) +#define IR_0803 (IR&0000770) +#define IR_0706 (IR&0000300) +#define IR_0703 (IR&0000370) +#define IR_0503 (IR&0000070) +#define IR_080403 (IR&0000430) +#define IR_08060403 (IR&0000730) +#define IR_0200 (IR&0000007) +#define IR_EAMOD (IR&0000070) +#define IR_0503 (IR&0000070) +#define IR_COND (IR&0007400) +#define IR_EA (IR&0000077) +#define IR_EAM12 (IR&0000060) +#define IR_EAREG (IR&0000007) +#define IR_DISP (IR&0000377) +#define IR_EATGT ((IR&0000700)>>3) +#define IR_REGX ((IR&0007000)>>9) +#define IR_REGY (IR&0000007) +#define IR_TRAP (IR&0000017) +#define IR_SIZE ((IR&0000300)>>6) +#define IR_DATA (IR&0000377) +#define IRE_DA (IRE&0100000) +#define IRE_REG ((IRE&0070000)>>12) +#define IRE_WL (IRE&0004000) +#define IRE_DISP (IRE&0000377) + +/* EA modes */ +#define EA_DDIR 0000 +#define EA_ADIR 0010 +#define EA_AIND 0020 +#define EA_API 0030 +#define EA_APD 0040 +#define EA_AIDX 0050 +#define EA_AXIDX 0060 +#define EA_EXT 0070 +#define EA_IMM 0074 +#define EAX_AW 000 +#define EAX_AL 001 +#define EAX_PCIDX 002 +#define EAX_PCXIDX 003 +#define EAX_IMM 004 + +#define EXTB(x) ((int32)((int8)((x)&0xff))) +#define EXTW(x) ((int32)((int16)((x)&0xffff))) + +#define DRX DR[IR_REGX] +#define DRY DR[IR_REGY] + +static uint32 quickarg[] = { 8,1,2,3,4,5,6,7 }; +static int32 shmask8[] = { 0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; +static int32 shmask16[] = { 0x0000, + 0x8000,0xc000,0xe000,0xf000,0xf800,0xfc00,0xfe00,0xff00, + 0xff80,0xffc0,0xffe0,0xfff0,0xff80,0xffc0,0xffe0,0xffff, + 0xffff }; +static int32 shmask32[] = { 0x00000000, + 0x80000000,0xc0000000,0xe0000000,0xf0000000, + 0xf8000000,0xfc000000,0xfe000000,0xff000000, + 0xff800000,0xffc00000,0xffe00000,0xfff00000, + 0xfff80000,0xfffc0000,0xfffe0000,0xffff0000, + 0xffff8000,0xffffc000,0xffffe000,0xfffff000, + 0xfffff800,0xfffffc00,0xfffffe00,0xffffff00, + 0xffffff80,0xffffffc0,0xffffffe0,0xfffffff0, + 0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff, + 0xffffffff }; +static int32 bitmask[] = { 0x00000000, + 0x00000001,0x00000002,0x00000004,0x00000008, + 0x00000010,0x00000020,0x00000040,0x00000080, + 0x00000100,0x00000200,0x00000400,0x00000800, + 0x00001000,0x00002000,0x00004000,0x00000800, + 0x00010000,0x00020000,0x00040000,0x00008000, + 0x00100000,0x00200000,0x00400000,0x00080000, + 0x01000000,0x02000000,0x04000000,0x00800000, + 0x10000000,0x20000000,0x40000000,0x80000000, + 0x00000000 }; + +static t_addr saved_ea; + +static t_stat ea_src_b(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc) +{ + t_stat rc = SCPE_OK; + uint32 reg, regno, IRE; + t_addr *areg; +// printf("src eamod=%x eareg=%x\n",eamod,eareg); + switch (eamod) { + case EA_DDIR: + *val = MASK_8L(DR[eareg]); + return SCPE_OK; + case EA_ADIR: + *val = MASK_8L(*AREG(eareg)); + return SCPE_OK; + case EA_AIND: + return ReadVB(saved_ea = *AREG(eareg),val); + case EA_API: + areg = AREG(eareg); + rc = ReadVB(saved_ea = *areg,val); + *areg += (eareg==7 ? 2 : 1); + return rc; + case EA_APD: + areg = AREG(eareg); + *areg -= (eareg==7 ? 2 : 1); + return ReadVB(saved_ea = *areg,val); + case EA_AIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return ReadVB(saved_ea = *AREG(eareg)+EXTW(IRE),val); + case EA_AXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = IRE_DA ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return ReadVB(saved_ea = *AREG(eareg) + EXTW(IRE_DISP) + reg, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + saved_ea = EXTW(IRE); + rc = ReadVB(saved_ea, val); + return rc; + case EAX_AL: + ASSERT_OKRET(ReadPL(*pc,&IRE)); + *pc += 4; + return ReadVB(saved_ea = IRE, val); + case EAX_PCIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return ReadVB(saved_ea = *pc-2 + EXTW(IRE), val); + case EAX_PCXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = (IRE_DA) ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return ReadVB(saved_ea = *pc-2 + EXTW(IRE_DISP) + reg, val); + case EAX_IMM: + ASSERT_OKRET(ReadInstrInc(pc,val)); + *val = MASK_8L(*val); + return SCPE_OK; + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +static t_stat ea_src_bs(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc) +{ + if (eamod==EA_EXT && eareg==EAX_IMM) { + *val = MASK_8L(SR); + return SCPE_OK; + } + return ea_src_b(eamod,eareg,val,pc); +} + +static t_stat ea_src_w(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc) +{ + t_stat rc = SCPE_OK; + uint32 reg, regno, IRE; + t_addr *areg; + + switch (eamod) { + case EA_DDIR: + *val = MASK_16L(DR[eareg]); + return SCPE_OK; + case EA_ADIR: + *val = MASK_16L(*AREG(eareg)); + return SCPE_OK; + case EA_AIND: + return ReadVW(saved_ea = *AREG(eareg), val); + case EA_API: + areg = AREG(eareg); + rc = ReadVW(saved_ea = *areg, val); + *areg += 2; + return rc; + case EA_APD: + areg = AREG(eareg); + *areg -= 2; + return ReadVW(saved_ea = *areg, val); + case EA_AIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return ReadVW(saved_ea = *AREG(eareg) + EXTW(IRE), val); + case EA_AXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = IRE_DA ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return ReadVW(saved_ea = *AREG(eareg) + EXTW(IRE_DISP) + reg, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return ReadVW(saved_ea = EXTW(IRE), val); + case EAX_AL: + ASSERT_OKRET(ReadPL(*pc,&IRE)); + *pc += 4; + return ReadVW(saved_ea = IRE, val); + case EAX_PCIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return ReadVW(saved_ea = *pc-2 + EXTW(IRE), val); + case EAX_PCXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = (IRE_DA) ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return ReadVW(saved_ea = *pc-2 + EXTW(IRE_DISP) + reg, val); + case EAX_IMM: + return ReadInstrInc(pc,val); + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +static t_stat ea_src_ws(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc) +{ + if (eamod==EA_EXT && eareg==EAX_IMM) { + *val = SR; + return SCPE_OK; + } + return ea_src_w(eamod,eareg,val,pc); +} + +/* non dereferencing version of ea_src_l, only accepts ea category control */ +static t_stat ea_src_l_nd(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc) +{ + t_stat rc = SCPE_OK; + uint32 reg, regno, IRE; + + switch (eamod) { + case EA_AIND: + *val = *AREG(eareg); + return SCPE_OK; + case EA_AIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + *val = *AREG(eareg) + EXTW(IRE); + return SCPE_OK; + case EA_AXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = IRE_DA ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + *val = *AREG(eareg) + EXTW(IRE_DISP) + reg; + return SCPE_OK; + case EA_EXT: + switch (eareg) { + case EAX_AW: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + *val = EXTW(IRE); + return SCPE_OK; + case EAX_AL: + ASSERT_OKRET(ReadPL(*pc,val)); + *pc += 4; + return SCPE_OK; + case EAX_PCIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + *val = *pc-2 + EXTW(IRE); + return SCPE_OK; + case EAX_PCXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = (IRE_DA) ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + *val = *pc-2 + EXTW(IRE_DISP) + reg; + return SCPE_OK; + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +static t_stat ea_src_l(uint32 eamod,uint32 eareg,uint32* val,t_addr* pc) +{ + t_stat rc = SCPE_OK; + uint32 reg, regno, IRE; + t_addr *areg; + + switch (eamod) { + case EA_DDIR: + *val = DR[eareg]; + return SCPE_OK; + case EA_ADIR: + *val = *AREG(eareg); + return SCPE_OK; + case EA_AIND: + return ReadVL(saved_ea = *AREG(eareg), val); + case EA_API: + areg = AREG(eareg); + rc = ReadVL(saved_ea = *areg, val); + *areg += 4; + return rc; + case EA_APD: + areg = AREG(eareg); + *areg -= 4; + return ReadVL(saved_ea = *areg, val); + case EA_AIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return ReadVL(saved_ea = *AREG(eareg) + EXTW(IRE), val); + case EA_AXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = IRE_DA ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return ReadVL(saved_ea = *AREG(eareg) + EXTW(IRE_DISP) + reg, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return ReadVL(saved_ea = EXTW(IRE), val); + case EAX_AL: + ASSERT_OKRET(ReadPL(*pc,&IRE)); + *pc += 4; + return ReadVL(saved_ea = IRE, val); + case EAX_PCIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return ReadVL(saved_ea = *pc-2 + EXTW(IRE), val); + case EAX_PCXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = (IRE_DA) ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return ReadVL(saved_ea = *pc-2 + EXTW(IRE_DISP) + reg, val); + case EAX_IMM: + ASSERT_OKRET(ReadVL(*pc,val)); + *pc += 4; + return SCPE_OK; + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +static t_stat ea_src_l64(uint32 eamod,uint32 eareg,t_uint64* val64,t_addr* pc) +{ + uint32 val32; + t_stat rc = ea_src_l(eamod,eareg,&val32,pc); + *val64 = (t_uint64)val32; + return rc; +} + +t_stat ea_src(uint32 eamod,uint32 eareg,uint32* val,int sz,t_addr* pc) +{ + switch (sz) { + case SZ_BYTE: + return ea_src_b(eamod,eareg,val,pc); + case SZ_WORD: + return ea_src_w(eamod,eareg,val,pc); + case SZ_LONG: + return ea_src_l(eamod,eareg,val,pc); + default: + return STOP_ERROP; + } +} + +static t_stat ea_dst_b(uint32 eamod,uint32 eareg,uint32 val,t_addr* pc) +{ + t_stat rc; + uint32 IRE,reg,regno; + t_addr *areg; + +// printf("dst: eamod=%x eareg=%x\n",eamod,eareg); +// printf("val=%x\n",val); + switch (eamod) { + case EA_DDIR: + DR[eareg] = COMBINE8(DR[eareg],val); + return SCPE_OK; + case EA_AIND: + return WriteVB(*AREG(eareg), val); + case EA_API: + areg = AREG(eareg); + rc = WriteVB(*areg, val); + *areg += (eareg==7 ? 2 : 1); + return rc; + case EA_APD: + areg = AREG(eareg); + *areg -= (eareg==7 ? 2 : 1); + return WriteVB(*areg, val); + case EA_AIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return WriteVB(*AREG(eareg) + EXTW(IRE), val); + case EA_AXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = IRE_DA ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return WriteVB(*AREG(eareg) + EXTW(IRE_DISP) + reg, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return WriteVB(EXTW(IRE), val); + case EAX_AL: + ASSERT_OKRET(ReadPL(*pc,&IRE)); + *pc += 4; + return WriteVB(IRE, val); + default: + return STOP_ERROP; + } + case EA_ADIR: + default: + return STOP_ERROP; + } +} + +t_stat ea_dst_b_rmw(uint32 eamod,uint32 eareg,uint32 val) +{ + switch (eamod) { + case EA_DDIR: + DR[eareg] = COMBINE8(DR[eareg],val); + return SCPE_OK; + case EA_AIND: + case EA_API: + case EA_APD: + case EA_AIDX: + case EA_AXIDX: + return WriteVB(saved_ea, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + case EAX_AL: + return WriteVB(saved_ea, val); + case EAX_IMM: + SR = COMBINE8(SR,val); + return SCPE_OK; + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +static t_stat ea_dst_w(uint32 eamod,uint32 eareg,uint32 val,t_addr* pc) +{ + t_stat rc; + uint32 IRE,reg,regno; + t_addr *areg; + + switch (eamod) { + case EA_DDIR: + DR[eareg] = COMBINE16(DR[eareg],val); + return SCPE_OK; + case EA_ADIR: + *AREG(eareg) = COMBINE16(*AREG(eareg),val); +// *AREG(eareg) = EXTW(val); + return SCPE_OK; + case EA_AIND: + return WriteVW(*AREG(eareg), val); + case EA_API: + areg = AREG(eareg); + rc = WriteVW(*areg, val); + *areg += 2; + return rc; + case EA_APD: + areg = AREG(eareg); + *areg -= 2; + return WriteVW(*areg, val); + case EA_AIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return WriteVW(*AREG(eareg) + EXTW(IRE), val); + case EA_AXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = IRE_DA ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return WriteVW(*AREG(eareg) + EXTW(IRE_DISP) + reg, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return WriteVW(EXTW(IRE), val); + case EAX_AL: + ASSERT_OKRET(ReadPL(*pc,&IRE)); + *pc += 4; + return WriteVW(IRE, val); + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +static t_stat ea_dst_w_rmw(uint32 eamod,uint32 eareg,uint32 val) +{ + switch (eamod) { + case EA_DDIR: + DR[eareg] = COMBINE16(DR[eareg],val); + return SCPE_OK; + case EA_ADIR: + printf("ea_dst_w_rmw EA_ADIR: pc=%x\n",saved_PC); + *AREG(eareg) = val; /* use full 32 bits even for word operand */ + return SCPE_OK; + case EA_AIND: + case EA_API: + case EA_APD: + case EA_AIDX: + case EA_AXIDX: + return WriteVW(saved_ea, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + case EAX_AL: + return WriteVW(saved_ea, val); + case EAX_IMM: + SR = val; + return SCPE_OK; + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +static t_stat ea_dst_l(uint32 eamod,uint32 eareg,uint32 val,t_addr* pc) +{ + t_stat rc; + uint32 IRE,reg,regno; + t_addr *areg; + + switch (eamod) { + case EA_DDIR: + DR[eareg] = val; + return SCPE_OK; + case EA_ADIR: + *AREG(eareg) = val; + return SCPE_OK; + case EA_AIND: + return WriteVL(*AREG(eareg), val); + case EA_API: + areg = AREG(eareg); + rc = WriteVL(*areg, val); + *areg += 4; + return rc; + case EA_APD: + areg = AREG(eareg); + *areg -= 4; + return WriteVL(*areg, val); + case EA_AIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return WriteVL(*AREG(eareg) + EXTW(IRE), val); + case EA_AXIDX: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + regno = IRE_REG; + reg = IRE_DA ? *AREG(regno) : DR[regno]; + if (!IRE_WL) reg = EXTW(reg); + return WriteVL(*AREG(eareg) + EXTW(IRE_DISP) + reg, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + ASSERT_OKRET(ReadInstrInc(pc,&IRE)); + return WriteVL(EXTW(IRE), val); + case EAX_AL: + ASSERT_OKRET(ReadPL(*pc,&IRE)); + *pc += 4; + return WriteVL(IRE, val); + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +t_stat ea_dst_l_rmw(uint32 eamod,uint32 eareg,uint32 val) +{ + + switch (eamod) { + case EA_DDIR: + DR[eareg] = val; + return SCPE_OK; + case EA_ADIR: + *AREG(eareg) = val; + return SCPE_OK; + case EA_AIND: + case EA_API: + case EA_APD: + case EA_AIDX: + case EA_AXIDX: + return WriteVL(saved_ea, val); + case EA_EXT: + switch (eareg) { + case EAX_AW: + case EAX_AL: + return WriteVL(saved_ea, val); + default: + return STOP_ERROP; + } + default: + return STOP_ERROP; + } +} + +t_stat ea_dst(uint32 eamod,uint32 eareg,uint32 val,int sz,t_addr* pc) +{ + switch (sz) { + case SZ_BYTE: + return ea_dst_b(eamod,eareg,val,pc); + case SZ_WORD: + return ea_dst_w(eamod,eareg,val,pc); + case SZ_LONG: + return ea_dst_l(eamod,eareg,val,pc); + default: + return STOP_ERROP; + } +} + +static t_bool testcond(uint32 c) +{ + int n,v; + + switch (c) { + case 0x0000: /*T*/ + return TRUE; + case 0x0100: /*F*/ + return FALSE; + case 0x0200: /*HI*/ + return !(CCR_C || CCR_Z); + case 0x0300: /*LS*/ + return CCR_C || CCR_Z; + case 0x0400: /*CC*/ + return !CCR_C; + case 0x0500: /*CS*/ + return CCR_C; + case 0x0600: /*NE*/ + return !CCR_Z; + case 0x0700: /*EQ*/ + return CCR_Z; + case 0x0800: /*VC*/ + return !CCR_V; + case 0x0900: /*VS*/ + return CCR_V; + case 0x0a00: /*PL*/ + return !CCR_N; + case 0x0b00: /*MI*/ + return CCR_N; + case 0x0c00: /*GE*/ + n = CCR_N; v = CCR_V; + return (n && v) || !(n || v); + case 0x0d00: /*LT*/ + n = CCR_N; v = CCR_V; + return (n && !v) || (!n && v); + case 0x0e00: /*GT*/ + n = CCR_N; v = CCR_V; + return !CCR_Z && (n || !v) && (!n || v); + case 0x0f00: /*LE*/ + n = CCR_N; v = CCR_V; + return CCR_Z || (!n && v) || (n && !v); + default: /*notreached*/ + return FALSE; + } +} + +/* push/pop on supervisor sp */ +static t_stat m68k_push16(uint32 data) +{ + A7 -= 2; + return WriteVW(A7,data); +} + +static t_stat m68k_push32(uint32 data) +{ + A7 -= 4; + return WriteVL(A7,data); +} + +static t_stat m68k_pop16(uint32* data) +{ + A7 += 2; + return ReadVW(A7-2,data); +} + +static t_stat m68k_pop32(uint32* data) +{ + A7 += 4; + return ReadVL(A7-4,data); +} + +/* push/pop on current sp */ +t_stat m68k_cpush16(uint32 data) +{ + *cur_sp -= 2; + return WriteVW(*cur_sp,data); +} + +static t_stat m68k_cpush32(uint32 data) +{ + *cur_sp -= 4; + return WriteVL(*cur_sp,data); +} + +static t_stat m68k_cpop16(uint32* data) +{ + *cur_sp += 2; + return ReadVW(*cur_sp-2,data); +} + +static t_stat m68k_cpop32(uint32* data) +{ + *cur_sp += 4; + return ReadVL(*cur_sp-4,data); +} + +t_stat m68k_gen_exception(int vecno,t_addr* pc) +{ + t_stat rc; + uint32 dummy; + t_addr oldpc = *pc; + char out[20]; + + /* @TODO VBR! */ + if (cputype<2) { + ASSERT_OKRET(m68k_push32(*pc)); + ASSERT_OKRET(m68k_push16(SR)); + m68k_set_s(TRUE); + CLRF(FLAG_T0|FLAG_T1); + } else { + /* no support for 68010 and above yet */ + return STOP_IMPL; + } + + /* set the new PC */ + ASSERT_OKRET(ReadPL(vecno<<2,pc)); + IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: vec=%d to %s\n",oldpc,vecno,m68k_getsym(*pc,XFMT,out))); + return ReadInstr(*pc,&dummy); /* fill prefetch cache */ +} + +static uint32 m68k_add8(uint32 src1,uint32 src2,uint32 x) +{ + uint32 res = MASK_8L(src1) + MASK_8L(src2) + x; + SETNZ8(res); + SETF(MASK_9(res),FLAG_C|FLAG_X); + SETV_ADD8(src1,src2,res); + return res; +} + +static uint32 m68k_add16(uint32 src1,uint32 src2,uint32 x,t_bool chgflags) +{ + uint32 res = MASK_16L(src1) + MASK_16L(src2) + x; + if (chgflags) { + SETNZ16(res); + SETF(MASK_17(res),FLAG_C|FLAG_X); + SETV_ADD16(src1,src2,res); + } + return res; +} + +static uint32 m68k_add32(t_uint64 src1,t_uint64 src2,t_uint64 x,t_bool chgflags) +{ + t_uint64 resx = MASK_32L(src1) + MASK_32L(src2) + x; + if (chgflags) { + SETNZ32(resx); + SETF(MASK_33(resx),FLAG_C|FLAG_X); + SETV_ADD32(src1,src2,resx); + } + return (uint32)resx; +} + +static uint32 m68k_sub8(uint32 dst,uint32 src,uint32 x) +{ + uint32 res = MASK_8L(dst) - MASK_8L(src) - x; + SETNZ8(res); + SETF(MASK_9(res),FLAG_C|FLAG_X); + SETV_SUB8(src,dst,res); + return res; +} + +static uint32 m68k_sub16(uint32 dst,uint32 src,uint32 x,t_bool chgflags) +{ + uint32 res = MASK_16L(dst) - MASK_16L(src) - x; + if (chgflags) { + SETNZ16(res); + SETF(MASK_17(res),FLAG_C|FLAG_X); + SETV_SUB16(src,dst,res); + } + return res; +} + +static uint32 m68k_sub32(t_uint64 dst,t_uint64 src, t_uint64 x,t_bool chgflags) +{ + t_uint64 resx = MASK_32L(dst) - MASK_32L(src) - x; + if (chgflags) { + SETNZ32(resx); + SETF(MASK_33(resx),FLAG_C|FLAG_X); + SETV_SUB32(src,dst,resx); + } + return (uint32)resx; +} + +static uint32* movem_regs[] = { + (uint32*)&D0, (uint32*)&D1, (uint32*)&D2, (uint32*)&D3, (uint32*)&D4, (uint32*)&D5, (uint32*)&D6, (uint32*)&D7, + (uint32*)&A0, (uint32*)&A1, (uint32*)&A2, (uint32*)&A3, (uint32*)&A4, (uint32*)&A5, (uint32*)&A6, 0 +}; + +static t_stat m68k_movem_r_pd(t_addr* areg,uint32 regs,t_bool sz) +{ + int i; + t_stat rc; + t_addr ea = *areg; + movem_regs[15] = cur_sp; + for (i=0; i<16; i++) { + if (regs & (1<=1; i--) { + if (intpending & (1< SR_IPL)) { + /* found a pending irq at level i, that must be serviced now */ + IFDEBUG(DBG_CPU_INT,fprintf(sim_deb,"CPU : [0x%08x] Interrupt: granting level=%d, IPL=%d, pending=%x\n", + *pc,i,SR_IPL,intpending)); + m68k_gen_exception(intvectors[i],pc); /* generate an exception */ + intpending &= ~(1<001| bchg,bclr,bset,btst + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 0 0 0 | Register | 1 |Opcode | 0 0 1 | Register | movep + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0x0000: + switch (IR_1103) { + case 0000400: case 0001400: case 0002400: case 0003400: + case 0004400: case 0005400: case 0006400: case 0007400: /* btst d,d */ + cnt = DRX & 0x1f; + goto do_btstd; + case 0004000: /* btst #,d */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + cnt = IRE & 0x1f; +do_btstd: SETZ32(DRY & bitmask[cnt+1]); + rc = SCPE_OK; break; + case 0000420: case 0000430: case 0000440: case 0000450: + case 0000460: case 0000470: case 0001420: case 0001430: + case 0001440: case 0001450: case 0001460: case 0001470: + case 0002420: case 0002430: case 0002440: case 0002450: + case 0002460: case 0002470: case 0003420: case 0003430: + case 0003440: case 0003450: case 0003460: case 0003470: + case 0004420: case 0004430: case 0004440: case 0004450: + case 0004460: case 0004470: case 0005420: case 0005430: + case 0005440: case 0005450: case 0005460: case 0005470: + case 0006420: case 0006430: case 0006440: case 0006450: + case 0006460: case 0006470: case 0007420: case 0007430: + case 0007440: case 0007450: case 0007460: case 0007470: /* btst d,ea */ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + cnt = DRX & 7; + goto do_btst8; + case 0004020: case 0004030: case 0004040: case 0004050: + case 0004060: case 0004070: /* btst #,ea */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + cnt = IRE & 7; +do_btst8: SETZ8(src1 & bitmask[cnt+1]); + rc = SCPE_OK; + break; + + case 0000700: case 0001700: case 0002700: case 0003700: + case 0004700: case 0005700: case 0006700: case 0007700: /* bset d,d */ + cnt = DRX & 0x1f; + src1 = bitmask[cnt+1]; + goto do_bsetd; + case 0004300: /* bset #,d */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + src1 = bitmask[(IRE & 0x1f)+1]; +do_bsetd: reg = &DRY; + SETZ32(*reg & src1); + *reg |= src1; + rc = SCPE_OK; break; + case 0000720: case 0000730: case 0000740: case 0000750: + case 0000760: case 0000770: case 0001720: case 0001730: + case 0001740: case 0001750: case 0001760: case 0001770: + case 0002720: case 0002730: case 0002740: case 0002750: + case 0002760: case 0002770: case 0003720: case 0003730: + case 0003740: case 0003750: case 0003760: case 0003770: + case 0004720: case 0004730: case 0004740: case 0004750: + case 0004760: case 0004770: case 0005720: case 0005730: + case 0005740: case 0005750: case 0005760: case 0005770: + case 0006720: case 0006730: case 0006740: case 0006750: + case 0006760: case 0006770: case 0007720: case 0007730: + case 0007740: case 0007750: case 0007760: case 0007770: /* bset d,ea */ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC)); + cnt = DRY & 7; + src1 = bitmask[cnt+1]; + goto do_bset8; + case 0004320: case 0004330: case 0004340: case 0004350: + case 0004360: case 0004370: /* bset # */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC)); + src1 = bitmask[(IRE&7)+1]; +do_bset8: SETZ8(res & src1); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res | src1); break; + + case 0000500: case 0001500: case 0002500: case 0003500: + case 0004500: case 0005500: case 0006500: case 0007500: /* bchg d,d */ + cnt = DRX & 0x1f; + src1 = bitmask[cnt+1]; + goto do_bchgd; + case 0004100: /* bchg #,d */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + src1 = bitmask[(IRE & 0x1f)+1]; +do_bchgd: reg = &DRY; + SETZ32(*reg & src1); + *reg ^= src1; + rc = SCPE_OK; break; + case 0000520: case 0000530: case 0000540: case 0000550: + case 0000560: case 0000570: case 0001520: case 0001530: + case 0001540: case 0001550: case 0001560: case 0001570: + case 0002520: case 0002530: case 0002540: case 0002550: + case 0002560: case 0002570: case 0003520: case 0003530: + case 0003540: case 0003550: case 0003560: case 0003570: + case 0004520: case 0004530: case 0004540: case 0004550: + case 0004560: case 0004570: case 0005520: case 0005530: + case 0005540: case 0005550: case 0005560: case 0005570: + case 0006520: case 0006530: case 0006540: case 0006550: + case 0006560: case 0006570: case 0007520: case 0007530: + case 0007540: case 0007550: case 0007560: case 0007570: /* bchg d,ea */ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC)); + cnt = DRX & 7; + src1 = bitmask[cnt+1]; + goto do_bchg8; + case 0004120: case 0004130: case 0004140: case 0004150: + case 0004160: case 0004170: /* bchg #,ea */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC)); + src1 = bitmask[(IRE&7)+1]; +do_bchg8: SETZ8(res & src1); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res ^ src1); break; + + case 0000600: case 0001600: case 0002600: case 0003600: + case 0004600: case 0005600: case 0006600: case 0007600: /* bclr d,d */ + cnt = DRX & 0x1f; + src1 = bitmask[cnt+1]; + goto do_bclrd; + case 0004200: /* bclr #,d */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + src1 = bitmask[(IRE & 0x1f)+1]; +do_bclrd: reg = &DRY; + SETZ32(*reg & src1); + *reg &= ~src1; + rc = SCPE_OK; break; + case 0000620: case 0000630: case 0000640: case 0000650: + case 0000660: case 0000670: case 0001620: case 0001630: + case 0001640: case 0001650: case 0001660: case 0001670: + case 0002620: case 0002630: case 0002640: case 0002650: + case 0002660: case 0002670: case 0003620: case 0003630: + case 0003640: case 0003650: case 0003660: case 0003670: + case 0004620: case 0004630: case 0004640: case 0004650: + case 0004660: case 0004670: case 0005620: case 0005630: + case 0005640: case 0005650: case 0005660: case 0005670: + case 0006620: case 0006630: case 0006640: case 0006650: + case 0006660: case 0006670: case 0007620: case 0007630: + case 0007640: case 0007650: case 0007660: case 0007670: /* bclr d,ea */ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC)); + cnt = DRX & 7; + src1 = bitmask[cnt+1]; + goto do_bclr8; + case 0004220: case 0004230: case 0004240: case 0004250: + case 0004260: case 0004270: /* bclr #,ea */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&res,&PC)); + src1 = bitmask[(IRE&7)+1]; +do_bclr8: SETZ8(res & src1); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res & ~src1); break; + + case 0000410: case 0001410: case 0002410: case 0003410: + case 0004410: case 0005410: case 0006410: case 0007410: /*movep.w m,r*/ + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + ASSERT_OK(ReadVB(srca,&src1)); + reg = &DRX; + *reg = src1<<8; + rc = ReadVB(srca+2,&src1); + *reg = COMBINE8(*reg,src1); + break; + case 0000510: case 0001510: case 0002510: case 0003510: + case 0004510: case 0005510: case 0006510: case 0007510: /*movep.l m,r*/ + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + ASSERT_OK(ReadVB(srca,&src1)); + reg = &DRX; + *reg = src1<<8; + ASSERT_OK(ReadVB(srca+2,&src1)); + *reg = (COMBINE8(*reg,src1))<<8; + ASSERT_OK(ReadVB(srca+4,&src1)); + *reg = (COMBINE8(*reg,src1))<<8; + rc = ReadVB(srca+6,&src1); + *reg = (COMBINE8(*reg,src1))<<8; + break; + case 0000610: case 0001610: case 0002610: case 0003610: + case 0004610: case 0005610: case 0006610: case 0007610: /*movep.w r,m*/ + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + src1 = DRX; + ASSERT_OK(WriteVB(srca,src1>>8)); + rc = WriteVB(srca+2,src1); break; + case 0000710: case 0001710: case 0002710: case 0003710: + case 0004710: case 0005710: case 0006710: case 0007710: /*movep.l r,m*/ + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + ASSERT_OK(WriteVB(srca,src1>>24)); + ASSERT_OK(WriteVB(srca+2,src1>>16)); + ASSERT_OK(WriteVB(srca+4,src1>>8)); + rc = WriteVB(srca+6,src1); break; + + case 0000000: case 0000020: case 0000030: case 0000040: + case 0000050: case 0000060: case 0000070: /*ori.b*/ + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_bs(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 | src2; + if (IR_EA != EA_IMM) { + SETNZ8(res); + CLRF(FLAG_C|FLAG_V); + } + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + tracet0 = SR_T0; break; + case 0000100: case 0000120: case 0000130: case 0000140: + case 0000150: case 0000160: case 0000170: /*ori.w*/ + if (IR_EA == EA_IMM) ASSERT_PRIV(); + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_ws(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 | src2; + if (IR_EA != EA_IMM) { + SETNZ16(res); + CLRF(FLAG_C|FLAG_V); + } + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + tracet0 = SR_T0; break; + case 0000200: case 0000220: case 0000230: case 0000240: + case 0000250: case 0000260: case 0000270: /*ori.l*/ + ASSERT_OK(ReadInstrLongInc(&PC,&src2)); + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 | src2; + SETNZ32(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); break; + + case 0001000: case 0001020: case 0001030: case 0001040: + case 0001050: case 0001060: case 0001070: /*andi.b*/ + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_bs(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 & src2; + if (IR_EA != EA_IMM) { + SETNZ8(res); + CLRF(FLAG_C|FLAG_V); + } + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + tracet0 = SR_T0; break; + case 0001100: case 0001120: case 0001130: case 0001140: + case 0001150: case 0001160: case 0001170: /*andi.w*/ + if (IR_EA==EA_IMM) ASSERT_PRIV(); + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_ws(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 & src2; + if (IR_EA != EA_IMM) { + SETNZ16(res); + CLRF(FLAG_C|FLAG_V); + } + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + tracet0 = SR_T0; break; + case 0001200: case 0001220: case 0001230: case 0001240: + case 0001250: case 0001260: case 0001270: /*andi.l*/ + ASSERT_OK(ReadInstrLongInc(&PC,&src2)); + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 & src2; + SETNZ32(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + + case 0006000: case 0006020: case 0006030: case 0006040: + case 0006050: case 0006060: case 0006070: /*cmpi.b*/ + case 0002000: case 0002020: case 0002030: case 0002040: + case 0002050: case 0002060: case 0002070: /*subi.b*/ + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_sub8(src1,src2,0); + rc = IR_1103 < 0006000 ? ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res) : SCPE_OK; + break; + case 0006100: case 0006120: case 0006130: case 0006140: + case 0006150: case 0006160: case 0006170: /*cmpi.w*/ + case 0002100: case 0002120: case 0002130: case 0002140: + case 0002150: case 0002160: case 0002170: /*subi.w*/ + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_sub16(src1,src2,0,TRUE); + rc = IR_1103 < 0006000 ? ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res) : SCPE_OK; + break; + case 0006200: case 0006220: case 0006230: case 0006240: + case 0006250: case 0006260: case 0006270: /*cmpi.l*/ + case 0002200: case 0002220: case 0002230: case 0002240: + case 0002250: case 0002260: case 0002270: /*subi.l*/ + ASSERT_OK(ReadInstrLongInc(&PC,&src2)); + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + res = m68k_sub32(srcx1,(t_uint64)src2,0,TRUE); + rc = IR_1103 < 0006000 ? ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res) : SCPE_OK; + break; + + case 0003000: case 0003020: case 0003030: case 0003040: + case 0003050: case 0003060: case 0003070: /*addi.b*/ + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_add8(src1,src2,0); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); break; + case 0003100: case 0003120: case 0003130: case 0003140: + case 0003150: case 0003160: case 0003170: /*addi.w*/ + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_add16(src1,src2,0,TRUE); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); break; + case 0003200: case 0003220: case 0003230: case 0003240: + case 0003250: case 0003260: case 0003270: /*addi.l*/ + ASSERT_OK(ReadInstrLongInc(&PC,&src2)); + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + res = m68k_add32(srcx1,(t_uint64)src2,0,TRUE); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0005000: case 0005020: case 0005030: case 0005040: + case 0005050: case 0005060: case 0005070: /*eori.b*/ + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_bs(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 ^ src2; + if (IR_EA != EA_IMM) { + SETNZ8(res); + CLRF(FLAG_C|FLAG_V); + } + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + tracet0 = SR_T0; break; + case 0005100: case 0005120: case 0005130: case 0005140: + case 0005150: case 0005160: case 0005170: /*eori.w*/ + if (IR_EA==EA_IMM) ASSERT_PRIV(); + ASSERT_OK(ReadInstrInc(&PC,&src2)); + ASSERT_OK(ea_src_ws(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 ^ src2; + if (IR_EA != EA_IMM) { + SETNZ16(res); + CLRF(FLAG_C|FLAG_V); + } + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + tracet0 = SR_T0; break; + case 0005200: case 0005220: case 0005230: case 0005240: + case 0005250: case 0005260: case 0005270: /*eori.l*/ + ASSERT_OK(ReadInstrLongInc(&PC,&src2)); + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 ^ src2; + SETNZ32(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); break; + + default: + rc = STOP_ERROP; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 0 |Length2| TargetReg | TargetMode| SourceMode| SourceReg | move + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 0 |Length2| TargetReg | 0 0 1 | SourceMode| SourceReg | movea + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0x1000: + ea = IR_EATGT; + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + if (ea == EA_ADIR) + rc = STOP_ERROP; /* movea.b */ + else { + ASSERT_OK(ea_dst_b(ea,IR_REGX,src1,&PC)); + SETNZ8(src1); + } + break; + case 0x2000: + ea = IR_EATGT; + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + if (ea==EA_ADIR) { /* movea.l */ + *AREG(IR_REGX) = src1; + rc = SCPE_OK; + } else { + rc = ea_dst_l(ea,IR_REGX,src1,&PC); + SETNZ32(src1); + } + break; + case 0x3000: + ea = IR_EATGT; + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + if (ea==EA_ADIR) { /* movea.w */ + *AREG(IR_REGX) = EXTW(src1); + rc = SCPE_OK; + } else { + rc = ea_dst_w(ea,IR_REGX,src1,&PC); + SETNZ16(src1); + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 0 | Opcode | 0 |Length | effective address | clr,neg,negx,not,tst + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 0 | Opcode | 0 | 1 1 | effective address | moveccr,movesr + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 0 | Opcode | 0 |Mode | 0 0 0 | Register | ext + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 0 | Opcode | 0 |Opcode | effective address | jmp,jsr,movem,nbcd,pea,tas + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 0 | Opcode | 0 |Opcode | Vector | trap + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 0 | Opcode | 0 |Opcode | Register | link,moveusp,swap,unlink + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 0 | Opcode | 0 |Opcode | illegal,nop,reset,rte,rtr,rts,stop,trapv + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 0 | Register | 1 |Opcode | effective address | chk,lea + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0x4000: + switch (IR_1106) { + case 000600: case 001600: case 002600: case 003600: + case 004600: case 005600: case 006600: case 007600: /*chk*/ + src1 = DRX; + SETF(src1 < 0,FLAG_N); + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC)); + rc = CCR_N || src1 > res ? m68k_gen_exception(6,&PC) : SCPE_OK; + break; + case 000700: case 001700: case 002700: case 003700: + case 004700: case 005700: case 006700: case 007700: /*lea*/ + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + *AREG(IR_REGX) = srca; + rc = SCPE_OK; + break; + + case 000300: /*move from sr*/ + rc = ea_dst_w(IR_EAMOD,IR_EAREG,SR,&PC); + break; + + case 001000: /*clr.b*/ + ONEF(FLAG_Z); + CLRF(FLAG_N|FLAG_C|FLAG_V); + rc = ea_dst_b(IR_EAMOD,IR_EAREG,0,&PC); + break; + case 001100: /*clr.w*/ + ONEF(FLAG_Z); + CLRF(FLAG_N|FLAG_C|FLAG_V); + rc = ea_dst_w(IR_EAMOD,IR_EAREG,0,&PC); + break; + case 001200: /*clr.l*/ + ONEF(FLAG_Z); + CLRF(FLAG_N|FLAG_C|FLAG_V); + rc = ea_dst_l(IR_EAMOD,IR_EAREG,0,&PC); + break; + + case 000000: /*negx.b*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + src1 += (CCR_X ? 1 : 0); + goto do_neg8; + case 002000: /*neg.b*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); +do_neg8: res = m68k_sub8(0,src1,0); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + + case 000100: /*negx.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + src1 += (CCR_X ? 1 : 0); + goto do_neg16; + case 002100: /*neg.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); +do_neg16: res = m68k_sub16(0,src1,0,TRUE); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + break; + + case 000200: /*negx.l*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + srcx1 = (t_uint64)src1 + (CCR_X ? 1 : 0); + goto do_neg32; + case 002200: /*neg.l*/ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); +do_neg32: res = m68k_sub32(0,srcx1,0,TRUE); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + + case 002300: /*move to ccr*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + SR = COMBINE8(SR,src1); + break; + + case 003000: /*not.b*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = ~src1; + SETNZ8(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 003100: /*not.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = ~src1; + SETNZ16(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + break; + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + case 003200: /*not.l*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = ~src1; + SETNZ32(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + + case 003300: /*move to sr*/ + ASSERT_PRIV(); + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + SR = src1; + tracet0 = SR_T0; + break; + + case 004000: /*nbcd*/ + rc = STOP_IMPL; + break; + + case 004100: /*pea or swap*/ + if (IR_0503==000) { /*swap*/ + reg = &DRY; + src1 = *reg << 16; + res = *reg >> 16; + *reg = COMBINE16(src1,res); + SETNZ32(*reg); + CLRF(FLAG_C|FLAG_V); + rc = SCPE_OK; + } else { /*pea*/ + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + ASSERT_OK(m68k_cpush32(srca)); + } + break; + case 004200: /*movem.w or ext*/ + if (IR_0503==000) { /*ext.w*/ + reg = &DRY; + res = EXTB(*reg); + *reg = COMBINE16(*reg,res); + SETNZ16(res); + CLRF(FLAG_C|FLAG_V); + rc = SCPE_OK; + } else { /*movem.w regs,ea*/ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + if (IR_EAMOD==EA_APD) + rc = m68k_movem_r_pd(AREG(IR_REGY),IRE,FALSE); + else { + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + rc = m68k_movem_r_ea(srca,IRE,FALSE); + } + } + break; + case 004300: /*movem or ext*/ + if (IR_0503==000) { /*ext.l*/ + reg = &DRY; + *reg = EXTW(*reg); + SETNZ32(*reg); + CLRF(FLAG_C|FLAG_V); + rc = SCPE_OK; + } else { /*movem.l regs,ea */ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + if (IR_EAMOD==EA_APD) + rc = m68k_movem_r_pd(AREG(IR_REGY),IRE,TRUE); + else { + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + rc = m68k_movem_r_ea(srca,IRE,TRUE); + } + } + break; + case 005000: /*tst.b*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + SETNZ8(src1); + CLRF(FLAG_V|FLAG_C); + break; + case 005100: /*tst.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + SETNZ16(src1); + CLRF(FLAG_V|FLAG_C); + break; + case 005200: /*tst.l*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + SETNZ32(src1); + CLRF(FLAG_V|FLAG_C); + break; + + case 005300: /*tas or illegal*/ + if (IR==045374) { /*illegal*/ + rc = STOP_ERROP; + } else { /*tas*/ + rc = STOP_IMPL; + } + break; + case 006200: /*movem.w ea,regs*/ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + if (IR_EAMOD==EA_API) + rc = m68k_movem_pi_r(AREG(IR_REGY),IRE,FALSE); + else { + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + rc = m68k_movem_ea_r(srca,IRE,FALSE); + } + break; + case 006300: /*movem.l ea,regs*/ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + if (IR_EAMOD==EA_API) + rc = m68k_movem_pi_r(AREG(IR_REGY),IRE,TRUE); + else { + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + rc = m68k_movem_ea_r(srca,IRE,TRUE); + } + break; + case 007100: + switch(IR_0503) { + case 000000: + case 000010: /*trap*/ + (*m68kcpu_trapcallback)(m68kcpu_dev,IR_TRAP); + rc = m68k_gen_exception(32+IR_TRAP,&PC); + break; + case 000020: /*link*/ + ASSERT_OK(ReadInstrInc(&PC,&IRE)); + if (IR_REGY==7) { + *cur_sp -= 4; + ASSERT_OK(WriteVL(*cur_sp,*cur_sp)); + } else { + areg = AREG(IR_REGY); + ASSERT_OK(m68k_cpush32(*areg)); + *areg = *cur_sp; + } + *cur_sp += EXTW(IRE); + break; + case 000030: /*unlk*/ + if (IR_REGY==7) { + ASSERT_OK(ReadVL(*cur_sp,&srca)); + *cur_sp = srca; + } else { + areg = AREG(IR_REGY); + *cur_sp = *areg; + ASSERT_OK(m68k_cpop32(areg)); + } + break; + case 000040: /*move to usp*/ + ASSERT_PRIV(); + USP = AR[IR_REGY]; + tracet0 = SR_T0; + rc = SCPE_OK; + break; + case 000050: /*move from usp*/ + ASSERT_PRIV(); + AR[IR_REGY] = USP; + rc = SCPE_OK; + break; + case 000060: + switch(IR_0200) { + case 000000: /*reset*/ + ASSERT_PRIV(); + rc = m68kcpu_peripheral_reset(); + break; + case 000001: /*nop*/ + rc = SCPE_OK; + tracet0 = SR_T0; + break; + case 000002: /*stop*/ + ASSERT_PRIV(); + ASSERT_OKRET(ReadInstrInc(&PC,&IRE)); + SR = (uint16)IRE; + rc = STOP_HALT; + tracet0 = SR_T0; + break; + case 000003: /*rte*/ + ASSERT_PRIV(); + ASSERT_OK(m68k_pop16(&src1)); + SR = src1; + m68k_set_s(SR_S != 0); + oldpc = PC; + rc = m68k_pop32(&PC); + tracet0 = SR_T0; + IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] RTE to 0x%08x, IPL=%d S=%d\n", + oldpc-2,PC,SR_IPL,SR_S?1:0)); + break; + case 000005: /*rts*/ + oldpc = PC; + rc = m68k_cpop32(&PC); + m68k_sublevel--; + IFDEBUG(DBG_CPU_CTRACE,fprintf(sim_deb,"CPU : [0x%08x] <<< RTS to 0x%08x (level=%d)\n", + oldpc-2,PC,m68k_sublevel)); + tracet0 = SR_T0; + break; + case 000006: /*trapv*/ + rc = CCR_V ? m68k_gen_exception(7,&PC) : SCPE_OK; + break; + case 000007: /*rtr*/ + ASSERT_OK(m68k_cpop16(&src1)); + SR = COMBINE8(SR,src1); + oldpc = PC; + rc = m68k_cpop32(&PC); + tracet0 = SR_T0; + IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] RTR to 0x%08x\n",oldpc-2,PC)); + break; + default: + rc = STOP_ERROP; + } + break; + default: + rc = STOP_ERROP; + } + break; + case 007200: /*jsr*/ + oldpc = PC; + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + ASSERT_OK(m68k_cpush32(PC)); + IFDEBUG(DBG_CPU_CTRACE,fprintf(sim_deb,"CPU : [0x%08x] >>> JSR %s (level=%d)\n", + oldpc-2,m68k_getsym(srca,XFMT,out),m68k_sublevel)); + PC = srca; + m68k_sublevel++; + tracet0 = SR_T0; + break; + case 007300: /*jmp*/ + oldpc = PC; + ASSERT_OK(ea_src_l_nd(IR_EAMOD,IR_EAREG,&srca,&PC)); + IFDEBUG(DBG_CPU_BTRACE,fprintf(sim_deb,"CPU : [0x%08x] ||| JMP %s\n", + oldpc-2,m68k_getsym(srca,XFMT,out))); + PC = srca; + tracet0 = SR_T0; + break; + default: + rc = STOP_ERROP; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 1 | Quickdata |Opc|Length | effective address<>001| addq,subq + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 1 | Condition | 1 1 0 0 1 | Register | dbcc + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 0 1 | Condition | 1 1 | effective address<>001| scc + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0x5000: + switch (IR_0806) { + case 0000300: + case 0000700: + if (IR_0503==010) { /*dbcc*/ + if (!IR_COND || !testcond(IR_COND)) { /* dbt is a NOP */ + reg = &DRY; + src1 = MASK_16L((*reg-1)); + *reg = MASK_16U(*reg) | src1; + if (src1 != 0xffff) { + ASSERT_OK(ReadInstr(PC,&IRE)); + PC += (EXTW(IRE)); + rc = SCPE_OK; + tracet0 = SR_T0; + break; + } /* else loop terminated */ + } + /* loop cond not met or dbt */ + PC += 2; + rc = SCPE_OK; + } else { /*scc*/ + src1 = testcond(IR_COND) ? 0xff : 0x00; + rc = ea_dst_b(IR_EAMOD,IR_EAREG,src1,&PC); + } + break; + case 0000000: /*addq.b*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_add8(src1,quickarg[IR_REGX],0); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000100: /*addq.w*/ + if (IR_EAMOD == EA_ADIR) { + *AREG(IR_REGY) += EXTW(quickarg[IR_REGX]); + rc = SCPE_OK; + } else { + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_add16(src1,quickarg[IR_REGX],0,TRUE); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } + break; + case 0000200: /*addq.l*/ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + res = m68k_add32(srcx1,(t_uint64)quickarg[IR_REGX],0,IR_EAMOD!=EA_ADIR); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000400: /*subq.b*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_sub8(src1,quickarg[IR_REGX],0); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000500: /*subq.w*/ + if (IR_EAMOD == EA_ADIR) { + *AREG(IR_REGY) -= EXTW(quickarg[IR_REGX]); + rc = SCPE_OK; + } else { + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_sub16(src1,quickarg[IR_REGX],0,TRUE); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } + break; + case 0000600: /*subq.l*/ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + res = m68k_sub32(srcx1,(t_uint64)quickarg[IR_REGX],0,IR_EAMOD!=EA_ADIR); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 1 0 | Condition | Displacement | Bcc,bra,bsr + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0x6000: + isbsr = IR_COND==0x100; /* is bsr */ + iscond = isbsr || testcond(IR_COND); /* condition matched */ + if (IR_DISP) { + if (iscond) { + if (isbsr) { + IFDEBUG(DBG_CPU_CTRACE,fprintf(sim_deb,"CPU : [0x%08x] >>> BSR %s (level=%d\n", + PC-2,m68k_getsym(PC+EXTB(IR_DISP),XFMT,out),m68k_sublevel)); + ASSERT_OK(m68k_cpush32(PC)); /* save PC for BSR */ + m68k_sublevel++; + } else { + IFDEBUG(DBG_CPU_BTRACE,fprintf(sim_deb,"CPU : [0x%08x] ||| B%s %s\n", + PC-2,condnames[IR_COND>>8],m68k_getsym(PC+EXTB(IR_DISP),XFMT,out))); + } + PC += EXTB(IR_DISP); /* go to new location */ + } /* else condition not matched */ + } else { /* 16 bit ext word */ + if (iscond) { + ASSERT_OK(ReadInstr(PC,&IRE)); /* get extension word */ + if (isbsr) { + IFDEBUG(DBG_CPU_CTRACE,fprintf(sim_deb,"CPU : [0x%08x] >>> BSR %s (level=%d)\n", + PC-2,m68k_getsym(PC+EXTW(IRE),XFMT,out),m68k_sublevel)); + ASSERT_OK(m68k_cpush32(PC+2)); /* save PC for BSR */ + m68k_sublevel++; + } else { + IFDEBUG(DBG_CPU_BTRACE,fprintf(sim_deb,"CPU : [0x%08x] ||| B%s %s\n", + PC-2,condnames[IR_COND>>8],m68k_getsym(PC+EXTW(IRE),XFMT,out))); + } + PC += EXTW(IRE); /* go to new location */ + } else { + PC += 2; /* condition not matched */ + } + } + tracet0 = SR_T0; + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 0 1 1 1 | Register | 0 | Data | moveq + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0x7000: + src1 = DRX = EXTB(IR_DATA); + SETNZ32(src1); + CLRF(FLAG_C|FLAG_V); + rc = SCPE_OK; break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 0 0 | Register |Opc|Length | effective address<>00x| or + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 0 0 | Reg X | 1 0 0 | 0 0 |R/M| Reg Y | sbcd + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 0 0 | Register |Opc| 1 1 | effective address | divs,divu + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0x8000: + switch(IR_0803) { + case 0000300: case 0000320: case 0000330: case 0000340: + case 0000350: case 0000360: case 0000370: /*divu.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + rc = m68k_divu_w(src1,&DR[IR_REGX], &PC); + break; + case 0000700: case 0000720: case 0000730: case 0000740: + case 0000750: case 0000760: case 0000770: /*divs.w*/ + rc = m68k_divs_w(src1,&DR[IR_REGX], &PC); + break; + case 0000400: /*sbcd d*/ + rc = STOP_IMPL; break; + case 0000410: /*sbcd a*/ + rc = STOP_IMPL; break; + case 0000000: case 0000020: case 0000030: case 0000040: + case 0000050: case 0000060: case 0000070: /*or.b ->d*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = MASK_8L(src1 | DRX); + SETNZ8(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000100: case 0000120: case 0000130: case 0000140: + case 0000150: case 0000160: case 0000170: /*or.w ->d*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = MASK_16L(src1 | DRX); + SETNZ16(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000200: case 0000220: case 0000230: case 0000240: + case 0000250: case 0000260: case 0000270: /*or.l ->d*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 & DRX; + SETNZ32(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000420: case 0000430: case 0000440: case 0000450: + case 0000460: case 0000470: /*or.b ->ea*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 | DRX; + SETNZ8(res); + CLRF(FLAG_V|FLAG_C); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000520: case 0000530: case 0000540: case 0000550: + case 0000560: case 0000570: /*or.w ->ea*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 | DRX; + SETNZ16(res); + CLRF(FLAG_V|FLAG_C); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000620: case 0000630: case 0000640: case 0000650: + case 0000660: case 0000670: /*or.l ->ea*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 | DRX; + SETNZ32(res); + CLRF(FLAG_V|FLAG_C); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + default: + rc = STOP_ERROP; break; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 0 1 | Register |Opc|Length | effective address<>00x| sub + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 0 1 | Register |Opc| 1 1 | effective address | suba + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 0 1 | Reg X | 1 |Length | 0 0 |R/M| Reg Y | subx + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0x9000: + switch (IR_0803) { + case 0000300: case 0000310: case 0000320: case 0000330: + case 0000340: case 0000350: case 0000360: case 0000370: /* suba.w */ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&srca,&PC)); + *AREG(IR_REGX) -= EXTW(srca); /* note: no flag changes! */ + break; + case 0000700: case 0000710: case 0000720: case 0000730: + case 0000740: case 0000750: case 0000760: case 0000770: /* suba.l */ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&srca,&PC)); + *AREG(IR_REGX) -= srca; /* note: no flag changes! */ + break; + case 0000400: /*subx.b d*/ + res = m68k_sub8(MASK_8L(DRY),DRX,CCR_X?1:0); + rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000410: /*subx.b -a*/ + ASSERT_OK(ea_src_b(EA_APD,IR_REGY,&src1,&PC)); + ASSERT_OK(ea_src_b(EA_APD,IR_REGX,&src2,&PC)); + res = m68k_sub8(src1,src2,CCR_X?1:0); + rc = ea_dst_b_rmw(EA_APD,IR_REGX,res); + break; + case 0000500: /*subx.w d*/ + res = m68k_sub16(MASK_16L(DRY),DRX,CCR_X?1:0,TRUE); + rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000510: /*subx.w -a*/ + ASSERT_OK(ea_src_w(EA_APD,IR_REGY,&src1,&PC)); + ASSERT_OK(ea_src_w(EA_APD,IR_REGX,&src2,&PC)); + res = m68k_sub16(src1,src2,CCR_X?1:0,TRUE); + rc = ea_dst_w_rmw(EA_APD,IR_REGX,res); + break; + case 0000600: /*subx.l d*/ + res = m68k_sub32((t_uint64)DRY,(t_uint64)DRX,CCR_X?1:0,TRUE); + rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000610: /*subx.l -a*/ + ASSERT_OK(ea_src_l64(EA_APD,IR_REGY,&srcx1,&PC)); + ASSERT_OK(ea_src_l64(EA_APD,IR_REGX,&srcx2,&PC)); + res = m68k_sub32(srcx1,srcx2,CCR_X?1:0,TRUE); + rc = ea_dst_l_rmw(EA_APD,IR_REGX,res); + break; + case 0000000: case 0000020: case 0000030: case 0000040: + case 0000050: case 0000060: case 0000070: /* sub.b ->d */ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_sub8(DRX,src1,0); + rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000100: case 0000110: case 0000120: case 0000130: + case 0000140: case 0000150: case 0000160: case 0000170: /* sub.w ->d */ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_sub16(DRX,src1,0,TRUE); + rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000200: case 0000210: case 0000220: case 0000230: + case 0000240: case 0000250: case 0000260: case 0000270: /* sub.l ->d */ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + res = m68k_sub32((t_uint64)DRX,srcx1,0,TRUE); + rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000420: case 0000430: case 0000440: case 0000450: + case 0000460: case 0000470: /* sub.b ->ea */ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_sub8(src1,DRX,0); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000520: case 0000530: case 0000540: case 0000550: + case 0000560: case 0000570: /* sub.w ->ea */ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_sub16(src1,DRX,0,TRUE); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000620: case 0000630: case 0000640: case 0000650: + case 0000660: case 0000670: /* sub.l ->ea */ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + res = m68k_sub32(srcx1,(t_uint64)DRX,0,TRUE); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + default: + rc = STOP_ERROP; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 1 0 | Opcode | trapa + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0xa000: + rc = m68k_gen_exception(10,&PC); + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 1 1 | Register | 0 |Length | effective address | cmp,cmpa + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 1 1 | Register | 1 |Length | effective address<>001| eor + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 0 1 1 | Reg X | 1 |Length | 0 0 1 | Reg Y | cmpm + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0xb000: + switch (IR_0803) { + case 0000410: /*cmpm.b*/ + rc = STOP_IMPL; break; + case 0000510: /*cmpm.w*/ + rc = STOP_IMPL; break; + case 0000610: /*cmpm.l*/ + rc = STOP_IMPL; break; + case 0000400: case 0000420: case 0000430: case 0000440: + case 0000450: case 0000460: case 0000470: /*eor.b*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 ^ DRX; + SETNZ8(res); + CLRF(FLAG_V|FLAG_C); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000500: case 0000520: case 0000530: case 0000540: + case 0000550: case 0000560: case 0000570: /*eor.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 ^ DRX; + SETNZ16(res); + CLRF(FLAG_V|FLAG_C); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000600: case 0000620: case 0000630: case 0000640: + case 0000650: case 0000660: case 0000670: /*eor.l*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 ^ DRX; + SETNZ32(res); + CLRF(FLAG_V|FLAG_C); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000000: case 0000020: case 0000030: case 0000040: + case 0000050: case 0000060: case 0000070: /*cmp.b*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + (void)m68k_sub8(DRX,src1,0); + break; + case 0000100: case 0000110: case 0000120: case 0000130: + case 0000140: case 0000150: case 0000160: case 0000170: /*cmp.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + (void)m68k_sub16(DRX,src1,0,TRUE); + break; + case 0000200: case 0000210: case 0000220: case 0000230: + case 0000240: case 0000250: case 0000260: case 0000270: /*cmp.l*/ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + (void)m68k_sub32((t_uint64)DRX,srcx1,0,TRUE); + break; + case 0000300: case 0000310: case 0000320: case 0000330: + case 0000340: case 0000350: case 0000360: case 0000370: /*cmpa.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + areg = AREG(IR_REGX); + (void)m68k_sub32((t_uint64)EXTW(*areg),(t_uint64)src1,0,TRUE); + break; + + case 0000700: case 0000710: case 0000720: case 0000730: + case 0000740: case 0000750: case 0000760: case 0000770: /*cmpa.l*/ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + (void)m68k_sub32((t_uint64)*AREG(IR_REGX),srcx1,0,TRUE); + break; + default: + rc = STOP_ERROP; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 0 0 | Register |Opc|Length | effective address<>00x| and + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 0 0 | Reg X | 1 0 0 | 0 0 |R/M| Reg Y | abcd + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 0 0 | Reg X | 1 |Opcode | 0 0 |Opc| Reg Y | exg + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 0 0 | Register |Opc| 1 1 | effective address | muls,mulu + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0xc000: + switch(IR_0803) { + case 0000300: case 0000310: case 0000320: case 0000330: + case 0000340: case 0000350: case 0000360: case 0000370: /*mulu*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = (uint16)MASK_16L(src1) * (uint16)MASK_16L(DRX); + DRX = res; + SETNZ32(res); + CLRF(FLAG_C|FLAG_V); + break; + case 0000700: case 0000710: case 0000720: case 0000730: + case 0000740: case 0000750: case 0000760: case 0000770: /*muls*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + sres = (int16)MASK_16L(src1) * (int16)MASK_16L(DRX); + DRX = (uint32)sres; + SETNZ32(sres); + CLRF(FLAG_C|FLAG_V); + break; + case 0000500: /* exg d,d */ + res = DRX; DRX = DRY; DRY = res; + rc = SCPE_OK; break; + case 0000510: /* exg a,a */ + srca = *AREG(IR_REGX); *AREG(IR_REGX) = *AREG(IR_REGY); *AREG(IR_REGY) = srca; + rc = SCPE_OK; break; + case 0000610: /* exg a,d */ + res = DRX; DRX = (uint32)*AREG(IR_REGY); *AREG(IR_REGY) = (t_addr)res; + rc = SCPE_OK; break; + case 0000400: /* abcd d */ + rc = STOP_IMPL; break; + case 0000410: /* abcd a */ + rc = STOP_IMPL; break; + case 0000000: case 00000020: case 0000030: case 0000040: + case 0000050: case 00000060: case 0000070: /* and.b -> d*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 & DRX; + SETNZ8(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000100: case 00000120: case 0000130: case 0000140: + case 0000150: case 00000160: case 0000170: /* and.w -> d*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 & DRX; + SETNZ16(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC); + break; + rc = STOP_IMPL; break; + case 0000200: case 00000220: case 0000230: case 0000240: + case 0000250: case 00000260: case 0000270: /* and.l -> d*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1 & DRX; + SETNZ32(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000420: case 00000430: case 0000440: case 0000450: + case 0000460: case 00000470: /* and.b -> ea*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = DRX & src1; + SETNZ8(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000520: case 00000530: case 0000540: case 0000550: + case 0000560: case 00000570: /* and.w -> ea*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = DRX & src1; + SETNZ16(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000620: case 00000630: case 0000640: case 0000650: + case 0000660: case 00000670: /* and.l -> ea*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = DRX & src1; + SETNZ32(res); + CLRF(FLAG_C|FLAG_V); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + default: + rc = STOP_ERROP; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 0 1 | Register |Opc| 1 1 | effective address<>00x| add,adda + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 0 1 | Reg X | 1 |Length | 0 0 |R/M| Reg Y | addx + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0xd000: + switch (IR_0803) { + case 0000300: case 0000310: case 0000320: case 0000330: + case 0000340: case 0000350: case 0000360: case 0000370: /*adda.w*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&srca,&PC)); + *AREG(IR_REGX) += EXTW(srca); /* note: no flag changes! */ + break; + case 0000700: case 0000710: case 0000720: case 0000730: + case 0000740: case 0000750: case 0000760: case 0000770: /*adda.l*/ + ASSERT_OK(ea_src_l(IR_EAMOD,IR_EAREG,&srca,&PC)); + *AREG(IR_REGX) += srca; /* note: no flag changes! */ + break; + case 0000400: /* addx.b d*/ + res = m68k_add8(MASK_8L(DRY),DRX,CCR_X?1:0); + rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000410: /* addx.b -a*/ + ASSERT_OK(ea_src_b(EA_APD,IR_REGY,&src1,&PC)); + ASSERT_OK(ea_src_b(EA_APD,IR_REGX,&src2,&PC)); + res = m68k_add8(src1,src2,CCR_X?1:0); + rc = ea_dst_b_rmw(EA_APD,IR_REGX,res); + break; + case 0000500: /* addx.w d*/ + res = m68k_add16(MASK_16L(DRY),DRX,CCR_X?1:0,TRUE); + rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000510: /* addx.w -a*/ + ASSERT_OK(ea_src_w(EA_APD,IR_REGY,&src1,&PC)); + ASSERT_OK(ea_src_w(EA_APD,IR_REGX,&src2,&PC)); + res = m68k_add16(src1,src2,CCR_X?1:0,TRUE); + rc = ea_dst_w_rmw(EA_APD,IR_REGX,res); + break; + case 0000600: /* addx.l d*/ + res = m68k_add32((t_uint64)DRY,(t_uint64)DRX,CCR_X?1:0,TRUE); + rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000610: /* addx.l -a*/ + ASSERT_OK(ea_src_l64(EA_APD,IR_REGY,&srcx1,&PC)); + ASSERT_OK(ea_src_l64(EA_APD,IR_REGX,&srcx2,&PC)); + res = m68k_add32(srcx1,srcx2,CCR_X?1:0,TRUE); + rc = ea_dst_l_rmw(EA_APD,IR_REGX,res); + break; + case 0000000: case 0000010: case 0000020: case 0000030: + case 0000040: case 0000050: case 0000060: case 0000070: /*add.b ->d*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_add8(src1,DRX,0); + rc = ea_dst_b(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000100: case 0000110: case 0000120: case 0000130: + case 0000140: case 0000150: case 0000160: case 0000170: /*add.w ->d*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_add16(src1,DRX,0,TRUE); + rc = ea_dst_w(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000200: case 0000210: case 0000220: case 0000230: + case 0000240: case 0000250: case 0000260: case 0000270: /*add.l ->d*/ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + res = m68k_add32(srcx1,(t_uint64)DRX,0,TRUE); + rc = ea_dst_l(EA_DDIR,IR_REGX,res,&PC); + break; + case 0000420: case 0000430: case 0000440: case 0000450: + case 0000460: case 0000470: /*add.b ->ea*/ + ASSERT_OK(ea_src_b(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_add8(src1,DRX,0); + rc = ea_dst_b_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000520: case 0000530: case 0000540: case 0000550: + case 0000560: case 0000570: /*add.w ->ea*/ + ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = m68k_add16(src1,DRX,0,TRUE); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + break; + case 0000620: case 0000630: case 0000640: case 0000650: + case 0000660: case 0000670: /*add.l ->ea*/ + ASSERT_OK(ea_src_l64(IR_EAMOD,IR_EAREG,&srcx1,&PC)); + res = m68k_add32(srcx1,(t_uint64)DRX,0,TRUE); + rc = ea_dst_l_rmw(IR_EAMOD,IR_EAREG,res); + break; + default: + rc = STOP_ERROP; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 1 0 |Size/Reg X |dir|Length |i/r|Opcode2| Reg Y | asl,asr,lsl,lsr,rol,ror,roxl,roxr + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 1 0 | Opcode |dir| 1 1 | effective address | asl,asr,lsl,lsr,rol,ror,roxl,roxr + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0xe000: + switch (IR_1103) { + case 000040: case 001040: case 002040: case 003040: + case 004040: case 005040: case 006040: case 007040: /*asr.b r*/ + cnt = DRX & 077; + goto do_asr8; + case 000000: case 001000: case 002000: case 003000: + case 004000: case 005000: case 006000: case 007000: /*asr.b #*/ + cnt = quickarg[IR_REGX]; +do_asr8: reg = DR+IR_REGY; + res = src1 = MASK_8L(*reg); + if (cnt) { + if (cnt<8) { + res >>= cnt; + if (MASK_8SGN(src1)) res |= shmask8[cnt]; + SETF(src1&bitmask[cnt],FLAG_C|FLAG_X); + } else { + res = MASK_8SGN(src1) ? 0xff : 0x00; + SETF(res,FLAG_C|FLAG_X); + } + *reg = COMBINE8(*reg,res); + } else + CLRF(FLAG_C); + SETNZ8(res); + CLRF(FLAG_V); + rc =SCPE_OK; break; + + case 000320: case 000330: case 000340: case 000350: + case 000360: case 000370: /*asr*/ + cnt = 1; + goto do_asr16; + case 000140: case 001140: case 002140: case 003140: + case 004140: case 005140: case 006140: case 007140: /*asr.w r*/ + cnt = DRX & 077; + IR = EA_DDIR | IR_REGY; + goto do_asr16; + case 000100: case 001100: case 002100: case 003100: + case 004100: case 005100: case 006100: case 007100: /*asr.w #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_asr16: ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + if (cnt) { + if (cnt<16) { + res = src1 >> cnt; + if (MASK_16SGN(src1)) res |= shmask16[cnt]; + SETF(src1&bitmask[cnt],FLAG_C|FLAG_X); + } else { + res = MASK_16SGN(src1) ? 0xffff : 0x0000; + SETF(res,FLAG_C|FLAG_X); + } + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } else { + CLRF(FLAG_C); + res = src1; + rc = SCPE_OK; + } + SETNZ16(res); + CLRF(FLAG_V); + break; + + case 000240: case 001240: case 002240: case 003240: + case 004240: case 005240: case 006240: case 007240: /*asr.l r*/ + cnt = DRX & 077; + goto do_asr32; + case 000200: case 001200: case 002200: case 003200: + case 004200: case 005200: case 006200: case 007200: /*asr.l #*/ + cnt = quickarg[IR_REGX]; +do_asr32: reg = DR+IR_REGY; + res = src1 = *reg; + if (cnt) { + if (cnt < 32) { + res >>= cnt; + if (MASK_32SGN(src1)) res |= shmask32[cnt]; + SETF(src1&bitmask[cnt],FLAG_C|FLAG_X); + } else { + res = MASK_32SGN(src1) ? 0xffffffff : 0x00000000; + SETF(res,FLAG_C|FLAG_X); + } + *reg = res; + } else CLRF(FLAG_C); + SETNZ32(res); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 000440: case 001440: case 002440: case 003440: + case 004440: case 005440: case 006440: case 007440: /*asl.b r*/ + cnt = DRX & 077; + goto do_asl8; + case 000400: case 001400: case 002400: case 003400: + case 004400: case 005400: case 006400: case 007400: /*asl.b #*/ + cnt = quickarg[IR_REGX]; +do_asl8: reg = DR+IR_REGY; + res = src1 = MASK_8L(*reg); + if (cnt) { + if (cnt<8) { + res = src1 << cnt; + SETF(MASK_9(res),FLAG_C|FLAG_X); + src1 &= shmask8[cnt+1]; + SETF(src1 && src1 != shmask8[cnt+1],FLAG_V); + } else { + res = 0; + SETF(cnt==8?(src1 & 1):0,FLAG_C|FLAG_X); + SETF(src1,FLAG_V); + } + *reg = COMBINE8(*reg,res); + } else CLRF(FLAG_C|FLAG_V); + SETNZ8(res); + rc = SCPE_OK; break; + + case 000720: case 000730: case 000740: case 000750: + case 000760: case 000770: /*asl*/ + cnt = 1; + goto do_asl16; + case 000540: case 001540: case 002540: case 003540: + case 004540: case 005540: case 006540: case 007540: /*asl.w r*/ + cnt = DRX & 077; + IR = EA_DDIR | IR_REGY; + goto do_asl16; + case 000500: case 001500: case 002500: case 003500: + case 004500: case 005500: case 006500: case 007500: /*asl.w #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_asl16: ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + if (cnt) { + if (cnt<16) { + res = src1 << cnt; + SETF(MASK_17(res),FLAG_C|FLAG_X); + src1 &= shmask16[cnt+1]; + SETF(src1 && src1 != shmask16[cnt+1],FLAG_V); + } else { + res = 0; + SETF(cnt==16?(src1 & 1):0,FLAG_C|FLAG_X); + SETF(src1,FLAG_V); + } + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } else { + CLRF(FLAG_C|FLAG_V); + rc = SCPE_OK; + } + SETNZ16(res); + break; + + case 000640: case 001640: case 002640: case 003640: + case 004640: case 005640: case 006640: case 007640: /*asl.l r*/ + cnt = DRX & 077; + goto do_asl32; + case 000600: case 001600: case 002600: case 003600: + case 004600: case 005600: case 006600: case 007600: /*asl.l #*/ + cnt = quickarg[IR_REGX]; +do_asl32: reg = DR+IR_REGY; + res = src1 = *reg; + if (cnt) { + if (cnt<32) { + res <<= cnt; + SETF(src1 & bitmask[32-cnt],FLAG_C|FLAG_X); + src1 &= shmask32[cnt+1]; + SETF(src1 && src1 != shmask32[cnt+1],FLAG_V); + } else { + res = 0; + SETF(cnt==16?(src1 & 1):0,FLAG_C|FLAG_X); + SETF(src1,FLAG_V); + } + *reg = res; + } else CLRF(FLAG_C|FLAG_V); + SETNZ32(res); + rc = SCPE_OK; break; + + case 000050: case 001050: case 002050: case 003050: + case 004050: case 005050: case 006050: case 007050: /*lsr.b r*/ + cnt = DRX & 077; + goto do_lsr8; + case 000010: case 001010: case 002010: case 003010: + case 004010: case 005010: case 006010: case 007010: /*lsr.b #*/ + cnt = quickarg[IR_REGX]; +do_lsr8: reg = DR+IR_REGY; + res = src1 = MASK_8L(*reg); + if (cnt) { + if (cnt <= 8) { + res = src1 >> cnt; + SETF(src1&bitmask[cnt],FLAG_C|FLAG_X); + } else { + res = 0; + CLRF(FLAG_X|FLAG_C); + } + *reg = COMBINE8(*reg,res); + } else CLRF(FLAG_C); + CLRF(FLAG_V); + SETNZ8(res); + rc = SCPE_OK; break; + + case 001320: case 001330: case 001340: case 001350: + case 001360: case 001370: /*lsr*/ + cnt = 1; + goto do_lsr16; + case 000150: case 001150: case 002150: case 003150: + case 004150: case 005150: case 006150: case 007150: /*lsr.w r*/ + cnt = DRX & 077; + IR = EA_DDIR | IR_REGY; + goto do_lsr16; + case 000110: case 001110: case 002110: case 003110: + case 004110: case 005110: case 006110: case 007110: /*lsr.w #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_lsr16: ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + if (cnt) { + if (cnt <= 16) { + res = src1 >> cnt; + SETF(src1&bitmask[cnt],FLAG_C|FLAG_X); + } else { + res = 0; + CLRF(FLAG_X|FLAG_C); + } + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } else { + CLRF(FLAG_C); + rc = SCPE_OK; + } + CLRF(FLAG_V); + SETNZ16(res); + break; + + case 000250: case 001250: case 002250: case 003250: + case 004250: case 005250: case 006250: case 007250: /*lsr.l r*/ + cnt = DRX & 077; + goto do_lsr32; + case 000210: case 001210: case 002210: case 003210: + case 004210: case 005210: case 006210: case 007210: /*lsr.l #*/ + cnt = quickarg[IR_REGX]; +do_lsr32: reg = DR+IR_REGY; + res = src1 = *reg; + if (cnt) { + if (cnt <= 32) { + res = src1 >> cnt; + SETF(src1&bitmask[cnt],FLAG_C|FLAG_X); + } else { + res = 0; + CLRF(FLAG_X|FLAG_C); + } + *reg = res; + } else CLRF(FLAG_C); + CLRF(FLAG_V); + SETNZ32(res); + rc = SCPE_OK; + break; + + case 000450: case 001450: case 002450: case 003450: + case 004450: case 005450: case 006450: case 007450: /*lsl.b r*/ + cnt = DRX & 077; + goto do_lsl8; + case 000410: case 001410: case 002410: case 003410: + case 004410: case 005410: case 006410: case 007410: /*lsl.b #*/ + cnt = quickarg[IR_REGX]; +do_lsl8: reg = DR+IR_REGY; + res = src1 = MASK_8L(*reg); + if (cnt) { + if (cnt <= 8) { + res = src1 << cnt; + SETF(src1&bitmask[9-cnt],FLAG_C|FLAG_X); + } else { + res = 0; + CLRF(FLAG_X|FLAG_C); + } + *reg = COMBINE8(*reg,res); + } else CLRF(FLAG_C); + SETNZ8(res); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 001720: case 001730: case 001740: case 001750: + case 001760: case 001770: /*lsl*/ + cnt = 1; + goto do_lsl16; + case 000550: case 001550: case 002550: case 003550: + case 004550: case 005550: case 006550: case 007550: /*lsl.w r*/ + cnt = DRX & 077; + IR = EA_DDIR | IR_REGY; + goto do_lsl16; + case 000510: case 001510: case 002510: case 003510: + case 004510: case 005510: case 006510: case 007510: /*lsl.w #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_lsl16: ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&src1,&PC)); + res = src1; + if (cnt) { + if (cnt <= 16) { + res = src1 << cnt; + SETF(src1&bitmask[17-cnt],FLAG_C|FLAG_X); + } else { + res = 0; + CLRF(FLAG_X|FLAG_C); + } + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } else { + CLRF(FLAG_C); + rc = SCPE_OK; + } + SETNZ16(res); + CLRF(FLAG_V); + break; + + case 000650: case 001650: case 002650: case 003650: + case 004650: case 005650: case 006650: case 007650: /*lsl.l r*/ + cnt = DRX & 077; + goto do_lsl32; + case 000610: case 001610: case 002610: case 003610: + case 004610: case 005610: case 006610: case 007610: /*lsl.l #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_lsl32: reg = DR+IR_REGY; + res = src1 = *reg; + if (cnt) { + if (cnt <= 32) { + res = src1 << cnt; + SETF(src1&bitmask[33-cnt],FLAG_C|FLAG_X); + } else { + res = 0; + CLRF(FLAG_X|FLAG_C); + } + *reg = res; + } else { + CLRF(FLAG_C); + rc = SCPE_OK; + } + SETNZ32(res); + CLRF(FLAG_V); + break; + + case 000060: case 001060: case 002060: case 003060: + case 004060: case 005060: case 006060: case 007060: /*roxr.b r*/ + cnt = DRX & 077; + goto do_roxr8; + case 000020: case 001020: case 002020: case 003020: + case 004020: case 005020: case 006020: case 007020: /*roxr.b #*/ + cnt = quickarg[IR_REGX]; +do_roxr8: reg = DR+IR_REGY; + res = MASK_8L(*reg); + if (cnt) { + cnt %= 9; + if (CCR_X) res |= BIT8; + res = (res>>cnt) | (res<<(9-cnt)); + *reg = COMBINE8(*reg,res); + SETF(MASK_9(res),FLAG_X|FLAG_C); + } else SETF(CCR_X,FLAG_C); + SETNZ8(res); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 002320: case 002330: case 002340: case 002350: + case 002360: case 002370: /*roxr*/ + cnt = 1; + goto do_roxr16; + case 000160: case 001160: case 002160: case 003160: + case 004160: case 005160: case 006160: case 007160: /*roxr.w r*/ + cnt = DRX & 077; + IR = EA_DDIR | IR_REGY; + goto do_roxr16; + case 000120: case 001120: case 002120: case 003120: + case 004120: case 005120: case 006120: case 007120: /*roxr.w #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_roxr16: ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC)); + if (cnt) { + cnt %= 17; + if (CCR_X) res |= BIT16; + res = (res>>cnt) | (res<<(17-cnt)); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + SETF(MASK_17(res),FLAG_X|FLAG_C); + } else { + SETF(CCR_X,FLAG_C); + rc = SCPE_OK; + } + SETNZ16(res); + CLRF(FLAG_V); + break; + + case 000260: case 001260: case 002260: case 003260: + case 004260: case 005260: case 006260: case 007260: /*roxr.l r*/ + cnt = DRX & 077; + goto do_roxr32; + case 000220: case 001220: case 002220: case 003220: + case 004220: case 005220: case 006220: case 007220: /*roxr.l #*/ + cnt = quickarg[IR_REGX]; +do_roxr32: reg = DR+IR_REGY; + resx = *reg; + if (cnt) { + cnt %= 33; + if (CCR_X) resx |= BIT32; + resx = (resx>>cnt) | (resx<<(33-cnt)); + *reg = MASK_32L(resx); + SETF(MASK_33(res),FLAG_X|FLAG_C); + } else SETF(CCR_X,FLAG_C); + SETNZ32(resx); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 000460: case 001460: case 002460: case 003460: + case 004460: case 005460: case 006460: case 007460: /*roxl.b r*/ + cnt = DRX & 077; + goto do_roxl8; + case 000420: case 001420: case 002420: case 003420: + case 004420: case 005420: case 006420: case 007420: /*roxl.b #*/ + cnt = quickarg[IR_REGX]; +do_roxl8: reg = DR+IR_REGY; + res = MASK_8L(*reg); + if (cnt) { + cnt %= 9; + if (CCR_X) res |= BIT8; + res = (res<>(9-cnt)); + *reg = COMBINE8(*reg,res); + SETF(MASK_9(res),FLAG_X|FLAG_C); + } else SETF(CCR_X,FLAG_C); + SETNZ8(res); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 002720: case 002730: case 002740: case 002750: + case 002760: case 002770: /*roxl*/ + cnt = 1; + goto do_roxl16; + case 000560: case 001560: case 002560: case 003560: + case 004560: case 005560: case 006560: case 007560: /*roxl.w r*/ + cnt = DRX & 077; + IR = EA_DDIR | IR_REGY; + goto do_roxl16; + case 000520: case 001520: case 002520: case 003520: + case 004520: case 005520: case 006520: case 007520: /*roxl.w #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_roxl16: ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC)); + if (cnt) { + cnt %= 17; + if (CCR_X) res |= BIT16; + res = (res<>(17-cnt)); + SETF(MASK_17(res),FLAG_X|FLAG_C); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } else { + SETF(CCR_X,FLAG_C); + rc = SCPE_OK; + } + SETNZ16(res); + CLRF(FLAG_V); + break; + + case 000660: case 001660: case 002660: case 003660: + case 004660: case 005660: case 006660: case 007660: /*roxl.l r*/ + cnt = DRX & 077; + goto do_roxl32; + case 000620: case 001620: case 002620: case 003620: + case 004620: case 005620: case 006620: case 007620: /*roxl.l #*/ + cnt = quickarg[IR_REGX]; +do_roxl32: reg = DR+IR_REGY; + resx = *reg; + if (cnt) { + cnt %= 33; + if (CCR_X) resx |= BIT32; + resx = (resx<>(33-cnt)); + SETF(MASK_33(resx),FLAG_X|FLAG_C); + *reg = MASK_32L(resx); + } else SETF(CCR_X,FLAG_C); + SETNZ32(resx); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 000070: case 001070: case 002070: case 003070: + case 004070: case 005070: case 006070: case 007070: /*ror.b r*/ + cnt = DRX & 077; + goto do_ror8; + case 000030: case 001030: case 002030: case 003030: + case 004030: case 005030: case 006030: case 007030: /*ror.b #*/ + cnt = quickarg[IR_REGX]; +do_ror8: reg = DR+IR_REGY; + res = MASK_8L(*reg); + if (cnt) { + cnt &= 7; + res = (res>>cnt) | (res<<(8-cnt)); + SETF(MASK_9(res),FLAG_C); + *reg = COMBINE8(*reg,res); + } else CLRF(FLAG_C); + SETNZ8(res); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 003320: case 003330: case 003340: case 003350: + case 003360: case 003370: /*ror*/ + cnt = 1; + goto do_ror16; + case 000170: case 001170: case 002170: case 003170: + case 004170: case 005170: case 006170: case 007170: /*ror.w r*/ + cnt = DRX & 077; + IR = EA_DDIR | IR_REGY; + goto do_ror16; + case 000130: case 001130: case 002130: case 003130: + case 004130: case 005130: case 006130: case 007130: /*ror.w #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_ror16: ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC)); + if (cnt) { + cnt &= 15; + res = (res>>cnt) | (res<<(16-cnt)); + SETF(MASK_17(res),FLAG_C); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } else { + CLRF(FLAG_C); + rc = SCPE_OK; + } + SETNZ16(res); + CLRF(FLAG_V); + break; + + case 000270: case 001270: case 002270: case 003270: + case 004270: case 005270: case 006270: case 007270: /*ror.l r*/ + cnt = DRX & 077; + goto do_ror32; + case 000230: case 001230: case 002230: case 003230: + case 004230: case 005230: case 006230: case 007230: /*ror.l #*/ + cnt = quickarg[IR_REGX]; +do_ror32: reg = DR+IR_REGY; + resx = *reg; + if (cnt) { + cnt &= 31; + resx = (resx>>cnt) | (resx<<(32-cnt)); + SETF(MASK_33(res),FLAG_C); + *reg = (int32)resx; + } else { + CLRF(FLAG_C); + rc = SCPE_OK; + } + SETNZ32(resx); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 000470: case 001470: case 002470: case 003470: + case 004470: case 005470: case 006470: case 007470: /*rol.b r*/ + cnt = DRX & 077; + goto do_rol8; + case 000430: case 001430: case 002430: case 003430: + case 004430: case 005430: case 006430: case 007430: /*rol.b #*/ + cnt = quickarg[IR_REGX]; +do_rol8: reg = DR+IR_REGY; + res = MASK_8L(*reg); + if (cnt) { + cnt &= 7; + res = (res<>(8-cnt)); + SETF(MASK_9(res),FLAG_C); + *reg = COMBINE8(*reg,res); + } else CLRF(FLAG_C); + SETNZ8(res); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + case 003720: case 003730: case 003740: case 003750: + case 003760: case 003770: /*rol*/ + cnt = 1; + goto do_rol16; + case 000570: case 001570: case 002570: case 003570: + case 004570: case 005570: case 006570: case 007570: /*rol.w r*/ + cnt = DRX & 077; + IR = EA_DDIR | IR_REGY; + goto do_rol16; + case 000530: case 001530: case 002530: case 003530: + case 004530: case 005530: case 006530: case 007530: /*rol.w #*/ + cnt = quickarg[IR_REGX]; + IR = EA_DDIR | IR_REGY; +do_rol16: ASSERT_OK(ea_src_w(IR_EAMOD,IR_EAREG,&res,&PC)); + if (cnt) { + cnt &= 15; + res = (res<>(16-cnt)); + SETF(MASK_17(res),FLAG_C); + rc = ea_dst_w_rmw(IR_EAMOD,IR_EAREG,res); + } else { + CLRF(FLAG_C); + rc = SCPE_OK; + } + SETNZ16(res); + CLRF(FLAG_V); + break; + + case 000670: case 001670: case 002670: case 003670: + case 004670: case 005670: case 006670: case 007670: /*rol.l r*/ + cnt = DRX & 077; + goto do_rol32; + case 000630: case 001630: case 002630: case 003630: + case 004630: case 005630: case 006630: case 007630: /*rol.l #*/ + cnt = quickarg[IR_REGX]; +do_rol32: reg = DR+IR_REGY; + resx = (uint32)*reg; + if (cnt) { + cnt &= 31; + resx = (resx<>(32-cnt)); + SETF(MASK_32L(resx),FLAG_C); + *reg = MASK_32L(resx); + } else CLRF(FLAG_C); + SETNZ32(resx); + CLRF(FLAG_V); + rc = SCPE_OK; break; + + default: + rc = STOP_ERROP; + } + break; + + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | 1 1 1 1 | Opcode | trapf + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---*/ + case 0xf000: + rc = m68k_gen_exception(11,&PC); break; + + /* unreachable */ + default: + rc = STOP_ERROP; break; + } + + /* handle tracing */ + if (tracet0 || SR_T1) { + if (m68kcpu_unit->flags & UNIT_CPU_TRACE) { + /* leave loop */ + sim_interval = -1; + rc = STOP_TRACE; + break; + } + IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Tracebit set\n",PC)); + ASSERT_OK(m68k_gen_exception(9,&PC)); + /* remain in loop */ + } + tracet0 = 0; + + /* handle interrupts (sets/resets intpending) */ + m68k_checkints(&PC); + + /* handle STOP instr */ + if (rc==STOP_HALT) { + if (m68kcpu_unit->flags & UNIT_CPU_STOP) { + PC -= 4; /* correct PC to point to STOP instr */ + break; + } + if ((rc = m68k_stop(&PC)) != SCPE_OK) + break; /* does not return until interrupt occurs, will react to CTRL-E */ + } + } + + /* handle various exit codes */ + switch (rc) { + case STOP_ERRADR: /* address error */ + if ((m68kcpu_unit->flags & UNIT_CPU_EXC)==0) { + IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Address error\n",PC)); + if ((rc = m68k_gen_exception(3,&PC)) != SCPE_OK) { + /* double bus fault */ + rc = STOP_DBF; /* cannot be masked, will stop simulator */ + } + } + return rc; + case STOP_PCIO: /* cannot be masked, will stop simulator */ + return rc; + case STOP_ERRIO: /* bus error */ + if ((m68kcpu_unit->flags & UNIT_CPU_EXC)==0) { + IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Bus error\n",PC)); + if ((rc = m68k_gen_exception(2,&PC)) != SCPE_OK) { + /* double bus fault */ + rc = STOP_DBF; /* cannot be masked, will stop simulator */ + } + } + return rc; + case STOP_ERROP: /* illegal opcode */ + if (!(m68kcpu_unit->flags & UNIT_CPU_EXC)) { + IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Illegal opcode\n",PC)); + rc = m68k_gen_exception(4,&PC); + } + return rc; + case STOP_PRVIO: /* privilege violation */ + if (!(m68kcpu_unit->flags & UNIT_CPU_PRVIO)) { + IFDEBUG(DBG_CPU_EXC,fprintf(sim_deb,"CPU : [0x%08x] Exception: Privilege violation\n",PC)); + rc = m68k_gen_exception(8,&PC); + } + break; + case STOP_IMPL: + return rc; /* leave sim_instr */ + default: + return rc; /* leave sim_instr */ + } + + /* save state */ + saved_PC = PC; + + return rc; +} diff --git a/SAGE/m68k_cpu.h b/SAGE/m68k_cpu.h new file mode 100644 index 00000000..4474d6cf --- /dev/null +++ b/SAGE/m68k_cpu.h @@ -0,0 +1,252 @@ +/* 68k_cpu.c: 68k-CPU simulator for sage-II system + + Copyright (c) 2009, Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version +*/ + +#ifndef M68K_CPU_H_ +#define M68K_CPU_H_ 0 + +#include "sim_defs.h" + +/* define this o 1 for adding debugging code */ +#define DBG_MSG 1 + +#if !defined(HAVE_INT64) +#error Fix me, I need 64 bit data types! +#endif + +/* these must be set in the system-specific CPU reset */ +extern UNIT* m68kcpu_unit; +extern DEVICE* m68kcpu_dev; + +/* implemented in m68k_cpu.c */ +extern REG m68kcpu_reg[]; + +/* debug flags */ +#define DBG_CPU_EXC (1 << 0) +#define DBG_CPU_PC (1 << 1) +#define DBG_CPU_INT (1 << 2) +#define DBG_CPU_CTRACE (1 << 3) +#define DBG_CPU_BTRACE (1 << 4) +#define DBG_CPU_CUSTOM1 (1 << 5) /* reserved for custom debugging */ +#define DBG_CPU_CUSTOM2 (1 << 6) /* reserved for custom debugging */ +extern FILE* sim_deb; +extern DEBTAB m68kcpu_dt[]; +#if DBG_MSG==1 +#define IFDEBUG(flag,func) if ((m68kcpu_dev->dctrl & flag) && sim_deb) { (void)(func); fflush(sim_deb); } +#else +#define IFDEBUG(flag,func) +#endif + +#define SIM_EMAX 16 /* ? */ +#define MAXMEMORY (256*256*256) /* 2^24 bytes */ +#define MINMEMORY (256*256) /* reserve 64k by default */ +#define MEMORYSIZE (m68kcpu_unit->capac) /* actual memory size */ +#define KB 1024 /* kilobyte */ + +/* simulator stop codes */ +#define STOP_IBKPT 1 /* pc breakpoint */ +#define STOP_MEM 2 /* memory breakpoint */ +#define STOP_ERROP 3 /* invalid opcode, normally exception 4 */ +#define STOP_ERRIO 4 /* invalid I/O address, normally exception 2 */ +#define STOP_ERRADR 5 /* invalid memory address, normally exception 3 */ +#define STOP_IMPL 6 /* not yet implemented (should disappear) */ +#define SIM_ISIO 7 /* internal indicator that I/O dispatch is required */ +#define SIM_NOMEM 8 /* allows to signal that there is no memory at that location */ +#define STOP_PCIO 9 /* code error, PC steps on I/O address */ +#define STOP_PRVIO 10 /* internal indicator: privileged instruction */ +#define STOP_TRACE 11 /* halt on trace */ +#define STOP_HALT 12 /* STOP instruction */ +#define STOP_DBF 13 /* double bus fault */ +#define STOP_OFFLINE 14 /* printer offline */ + +#define UNIT_CPU_M_TYPE 017 +#define UNIT_CPU_V_TYPE (UNIT_V_UF+0) /* CPUTYPE */ +#define UNIT_CPU_TYPE (1 << UNIT_CPU_V_CPU) +#define UNIT_CPU_V_EXC (UNIT_V_UF+4) /* halt on exception 2..4 */ +#define UNIT_CPU_EXC (1 << UNIT_CPU_V_EXC) +#define UNIT_CPU_V_STOP (UNIT_V_UF+5) /* halt on STOP instruction */ +#define UNIT_CPU_STOP (1 << UNIT_CPU_V_STOP) +#define UNIT_CPU_V_PRVIO (UNIT_V_UF+6) /* halt on privilege violation */ +#define UNIT_CPU_PRVIO (1 << UNIT_CPU_V_PRVIO) +#define UNIT_CPU_V_TRACE (UNIT_V_UF+7) /* halt on TRACE exception */ +#define UNIT_CPU_TRACE (1 << UNIT_CPU_V_TRACE) +#define UNIT_CPU_V_FPU (UNIT_V_UF+8) /* has FPU */ +#define UNIT_CPU_FPU (1 << UNIT_CPU_V_FPU) +#define UNIT_CPU_V_MMU (UNIT_V_UF+9) /* has MMU */ +#define UNIT_CPU_MMU (1 << UNIT_CPU_V_MMU) +#define UNIT_CPU_V_MSIZE (UNIT_V_UF+10) /* set memsize */ +#define UNIT_CPU_MSIZE (1 << UNIT_CPU_V_MSIZE) + +#define UNIT_CPU_V_FREE (UNIT_V_UF+11) /* next free bit */ + +/* the various CPUs */ +#define UNIT_CPUTYPE_MASK (UNIT_CPU_M_TYPE << UNIT_CPU_V_TYPE) +#define CPU_TYPE_68000 (0 << UNIT_CPU_V_TYPE) +#define CPU_TYPE_68008 (1 << UNIT_CPU_V_TYPE) +#define CPU_TYPE_68010 (2 << UNIT_CPU_V_TYPE) /* not yet! */ +#define CPU_TYPE_68020 (3 << UNIT_CPU_V_TYPE) /* not yet! */ +#define CPU_TYPE_68030 (4 << UNIT_CPU_V_TYPE) /* not yet! */ + +extern uint8 *M; +extern int16 cputype; +extern t_addr saved_PC; +#define PCX saved_PC + +/* breakpoint space for data accesses (R=read, W=write) */ +#define E_BKPT_SPC (0) +#define R_BKPT_SPC (1< + +#if defined(_WIN32) +#include +#else +#include +#endif + +/* io hash */ +#define IOHASHSIZE 97 /* must be prime */ +#define MAKEIOHASH(p) (p % IOHASHSIZE) +static IOHANDLER** iohash = NULL; + +/* + * memory + */ +uint8* M = 0; +t_addr addrmask = 0xffffffff; +int m68k_fcode = 0; +int m68k_dma = 0; + +#if 0 +/* TODO */ +t_stat m68k_set_mmu(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + uptr->flags |= value; + + /* TODO initialize the MMU */ + TranslateAddr = &m68k_translateaddr; + return SCPE_OK; +} + +t_stat m68k_set_nommu(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + uptr->flags &= ~value; + + /* initialize NO MMU */ + TranslateAddr = &m68k_translateaddr; + return SCPE_OK; +} +#endif + +/* I/O dispatcher + * + * I/O devices are implemented this way: + * a unit will register its own I/O addresses together with its handler + * in a hash which allows simple translation of physical addresses + * into units in the ReadPx/WritePx routines. + * These routines call the iohandler entry on memory mapped read/write. + * The handler has the option to enqueue an event for its unit for + * asynchronous callback, e.g. interrupt processing + */ +t_stat m68k_ioinit() +{ + if (iohash == NULL) { + iohash = (IOHANDLER**)calloc(IOHASHSIZE,sizeof(IOHANDLER*)); + if (iohash == NULL) return SCPE_MEM; + } + return SCPE_OK; +} + +t_stat add_iohandler(UNIT* u,void* ctxt, + t_stat (*io)(struct _iohandler* ioh,uint32* value,uint32 rw,uint32 mask)) +{ + PNP_INFO* pnp = (PNP_INFO*)ctxt; + IOHANDLER* ioh; + uint32 i,k; + + if (!pnp) return SCPE_IERR; + for (k=i=0; iio_size; i+=pnp->io_incr,k++) { + t_addr p = (pnp->io_base+i) & addrmask; + t_addr idx = MAKEIOHASH(p); + ioh = iohash[idx]; + while (ioh != NULL && ioh->port != p) ioh = ioh->next; + if (ioh) continue; /* already registered */ + +// printf("Register IO for address %x offset=%d\n",p,k); + ioh = (IOHANDLER*)malloc(sizeof(IOHANDLER)); + if (ioh == NULL) return SCPE_MEM; + ioh->ctxt = ctxt; + ioh->port = p; + ioh->offset = k; + ioh->u = u; + ioh->io = io; + ioh->next = iohash[idx]; + iohash[idx] = ioh; + } + return SCPE_OK; +} +t_stat del_iohandler(void* ctxt) +{ + uint32 i; + PNP_INFO* pnp = (PNP_INFO*)ctxt; + + if (!pnp) return SCPE_IERR; + for (i=0; iio_size; i += pnp->io_incr) { + t_addr p = (pnp->io_base+i) & addrmask; + t_addr idx = MAKEIOHASH(p); + IOHANDLER **ioh = &iohash[idx]; + while (*ioh != NULL && (*ioh)->port != p) ioh = &((*ioh)->next); + if (*ioh) { + IOHANDLER *e = *ioh; + *ioh = (*ioh)->next; + free((void*)e); + } + } + return SCPE_OK; +} + +/*********************************************************************************************** + * Memory handling + * ReadP{B|W|L} and WriteP{B|W|L} simply access physical memory (addrmask applies) + * ReadV{B|W|L} and WriteV{B|W|L} access virtual memory, i.e. after a "decoder" or mmu has processed + * the address/rwmode/fcode + * TranslateAddr is a user-supplied function, to be set into the function pointer, + * which converts an address and other data (e.g. rw, fcode) provided by the CPU + * into the real physical address. This is basically the MMU. + * + * TranslateAddr returns SCPE_OK for valid translation + * SIM_ISIO if I/O dispatch is required; ioh contains pointer to iohandler + * STOP_ERRADDR if address is invalid + * Mem accesses memory, selected by a (translated) address. Override in own code for non-contiguous memory + * Mem returns SCPE_OK and a pointer to the selected byte, if okay, STOP_ERRADR for invalid accesses + */ + +/* default handler */ +t_stat m68k_translateaddr(t_addr in,t_addr* out, IOHANDLER** ioh,int rw,int fc,int dma) +{ + t_addr ma = in & addrmask; + t_addr idx = MAKEIOHASH(ma); + IOHANDLER* i = iohash[idx]; + + *out = ma; + *ioh = 0; + while (i != NULL && i->port != ma) i = i->next; + if (i) { + *ioh = i; + return SIM_ISIO; + } else + return SCPE_OK; +} + +/* default memory pointer */ +t_stat m68k_mem(t_addr addr,uint8** mem) +{ + if (addr > MEMORYSIZE) return STOP_ERRADR; + *mem = M+addr; + return SCPE_OK; +} + +t_stat (*TranslateAddr)(t_addr in,t_addr* out,IOHANDLER** ioh,int rw,int fc,int dma) = &m68k_translateaddr; +t_stat (*Mem)(t_addr addr,uint8** mem) = &m68k_mem; + +/* memory access routines + * The Motorola CPU is big endian, whereas others like the i386 is + * little endian. The memory uses the natural order of the emulating CPU. + * + * addressing uses all bits but LSB to access the memory cell + * + * Memorybits 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 + * ------68K Byte0-(MSB)-- ---68K Byte1----------- + * ------68K Byte2-------- ---68K Byte3-(LSB)----- + */ +t_stat ReadPB(t_addr a, uint32* val) +{ + uint8* mem; + + t_stat rc = Mem(a & addrmask,&mem); + switch (rc) { + default: + return rc; + case SIM_NOMEM: + *val = 0xff; + return SCPE_OK; + case SCPE_OK: + *val = *mem & BMASK; + return SCPE_OK; + } +} + +t_stat ReadPW(t_addr a, uint32* val) +{ + uint8* mem; + uint32 dat1,dat2; + + t_stat rc = Mem((a+1)&addrmask,&mem); + switch (rc) { + default: + return rc; + case SIM_NOMEM: + *val = 0xffff; + return SCPE_OK; + case SCPE_OK: + /* 68000/08/10 do not like unaligned access */ + if (cputype < 3 && (a & 1)) return STOP_ERRADR; + dat1 = (*(mem-1) & BMASK) << 8; + dat2 = *mem & BMASK; + *val = (dat1 | dat2) & WMASK; + return SCPE_OK; + } +} + +t_stat ReadPL(t_addr a, uint32* val) +{ + uint8* mem; + uint32 dat1,dat2,dat3,dat4; + + t_stat rc = Mem((a+3)&addrmask,&mem); + switch (rc) { + default: + return rc; + case SIM_NOMEM: + *val = 0xffffffff; + return SCPE_OK; + case SCPE_OK: + /* 68000/08/10 do not like unaligned access */ + if (cputype < 3 && (a & 1)) return STOP_ERRADR; + dat1 = *(mem-3) & BMASK; + dat2 = *(mem-2) & BMASK; + dat3 = *(mem-1) & BMASK; + dat4 = *mem & BMASK; + *val = (((((dat1 << 8) | dat2) << 8) | dat3) << 8) | dat4; + return SCPE_OK; + } +} + +t_stat WritePB(t_addr a, uint32 val) +{ + uint8* mem; + + t_stat rc = Mem(a&addrmask,&mem); + switch (rc) { + default: + return rc; + case SCPE_OK: + *mem = val & BMASK; + /*fallthru*/ + case SIM_NOMEM: + return SCPE_OK; + } +} + +t_stat WritePW(t_addr a, uint32 val) +{ + uint8* mem; + t_stat rc = Mem((a+1)&addrmask,&mem); + switch (rc) { + default: + return rc; + case SCPE_OK: + /* 68000/08/10 do not like unaligned access */ + if (cputype < 3 && (a & 1)) return STOP_ERRADR; + *(mem-1) = (val >> 8) & BMASK; + *mem = val & BMASK; + /*fallthru*/ + case SIM_NOMEM: + return SCPE_OK; + } +} + +t_stat WritePL(t_addr a, uint32 val) +{ + uint8* mem; + + t_stat rc = Mem((a+3)&addrmask,&mem); + switch (rc) { + default: + return rc; + case SCPE_OK: + /* 68000/08/10 do not like unaligned access */ + if (cputype < 3 && (a & 1)) return STOP_ERRADR; + *(mem-3) = (val >> 24) & BMASK; + *(mem-2) = (val >> 16) & BMASK; + *(mem-1) = (val >> 8) & BMASK; + *mem = val & BMASK; + /*fallthru*/ + case SIM_NOMEM: + return SCPE_OK; + } +} + +t_stat ReadVB(t_addr a, uint32* val) +{ + t_addr addr; + IOHANDLER* ioh; + t_stat rc = TranslateAddr(a,&addr,&ioh,MEM_READ,m68k_fcode,m68k_dma); + switch (rc) { + case SIM_NOMEM: + /* note this is a hack to persuade memory testing code that there is no memory: + * writing to such an address is a bit bucket, + * and reading from it will return some arbitrary value. + * + * SIM_NOMEM has to be defined for systems without a strict memory handling that will + * result in reading out anything without trapping a memory fault + */ + *val = 0xff; + return SCPE_OK; + case SIM_ISIO: + return ioh->io(ioh,val,IO_READ,BMASK); + case SCPE_OK: + return ReadPB(addr,val); + default: + return rc; + } +} + +t_stat ReadVW(t_addr a, uint32* val) +{ + t_addr addr; + IOHANDLER* ioh; + t_stat rc = TranslateAddr(a,&addr,&ioh,MEM_READ,m68k_fcode,m68k_dma); + switch (rc) { + case SIM_NOMEM: + *val = 0xffff; + return SCPE_OK; + case SIM_ISIO: + return ioh->io(ioh,val,IO_READ,WMASK); + case SCPE_OK: + return ReadPW(addr,val); + default: + return rc; + } +} + +t_stat ReadVL(t_addr a, uint32* val) +{ + t_addr addr; + IOHANDLER* ioh; + t_stat rc = TranslateAddr(a,&addr,&ioh,MEM_READ,m68k_fcode,m68k_dma); + switch (rc) { + case SIM_NOMEM: + *val = 0xffffffff; + return SCPE_OK; + case SIM_ISIO: + return ioh->io(ioh,val,IO_READ,LMASK); + case SCPE_OK: + return ReadPL(addr,val); + default: + return rc; + } +} + +t_stat WriteVB(t_addr a, uint32 val) +{ + t_addr addr; + IOHANDLER* ioh; + t_stat rc = TranslateAddr(a,&addr,&ioh,MEM_WRITE,m68k_fcode,m68k_dma); + switch (rc) { + case SIM_NOMEM: + /* part 2 of hack for less strict memory handling: ignore anything written + * to a nonexisting address + */ + return SCPE_OK; + case SIM_ISIO: + return ioh->io(ioh,&val,IO_WRITE,BMASK); + case SCPE_OK: + return WritePB(addr,val); + default: + return rc; + } +} + +t_stat WriteVW(t_addr a, uint32 val) +{ + t_addr addr; + IOHANDLER* ioh; + t_stat rc = TranslateAddr(a,&addr,&ioh,MEM_WRITE,m68k_fcode,m68k_dma); + switch (rc) { + case SIM_NOMEM: + return SCPE_OK; + case SIM_ISIO: + return ioh->io(ioh,&val,IO_WRITE,WMASK); + case SCPE_OK: + return WritePW(addr,val); + default: + return rc; + } +} + +t_stat WriteVL(t_addr a, uint32 val) +{ + t_addr addr; + IOHANDLER* ioh; + t_stat rc = TranslateAddr(a,&addr,&ioh,MEM_WRITE,m68k_fcode,m68k_dma); + switch (rc) { + case SIM_NOMEM: + return SCPE_OK; + case SIM_ISIO: + return ioh->io(ioh,&val,IO_WRITE,LMASK); + case SCPE_OK: + return WritePL(addr,val); + default: + return rc; + } +} diff --git a/SAGE/m68k_parse.tab.c b/SAGE/m68k_parse.tab.c new file mode 100644 index 00000000..5492e71e --- /dev/null +++ b/SAGE/m68k_parse.tab.c @@ -0,0 +1,3786 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + A0 = 258, + A1 = 259, + A2 = 260, + A3 = 261, + A4 = 262, + A5 = 263, + A6 = 264, + A7 = 265, + D0 = 266, + D1 = 267, + D2 = 268, + D3 = 269, + D4 = 270, + D5 = 271, + D6 = 272, + D7 = 273, + CCR = 274, + SR = 275, + USP = 276, + PC = 277, + NUMBER = 278, + ABCD = 279, + ADD = 280, + ADDA = 281, + ADDI = 282, + ADDQ = 283, + ADDX = 284, + AND = 285, + ANDI = 286, + OR = 287, + ORI = 288, + SBCD = 289, + SUB = 290, + SUBA = 291, + SUBI = 292, + SUBQ = 293, + SUBX = 294, + ASL = 295, + ASR = 296, + LSL = 297, + LSR = 298, + ROL = 299, + ROR = 300, + ROXL = 301, + ROXR = 302, + BCC = 303, + BCS = 304, + BEQ = 305, + BGE = 306, + BGT = 307, + BHI = 308, + BLE = 309, + BLS = 310, + BLT = 311, + BMI = 312, + BNE = 313, + BPL = 314, + BVC = 315, + BVS = 316, + BSR = 317, + BRA = 318, + BCLR = 319, + BSET = 320, + BCHG = 321, + BTST = 322, + CHK = 323, + CMP = 324, + CMPA = 325, + CMPI = 326, + CMPM = 327, + EOR = 328, + EORI = 329, + EXG = 330, + EXT = 331, + DIVU = 332, + DIVS = 333, + MULU = 334, + MULS = 335, + DBCC = 336, + DBCS = 337, + DBEQ = 338, + DBF = 339, + DBGE = 340, + DBGT = 341, + DBHI = 342, + DBLE = 343, + DBLS = 344, + DBLT = 345, + DBMI = 346, + DBNE = 347, + DBPL = 348, + DBT = 349, + DBVC = 350, + DBVS = 351, + SCC = 352, + SCS = 353, + SEQ = 354, + SF = 355, + SGE = 356, + SGT = 357, + SHI = 358, + SLE = 359, + SLS = 360, + SLT = 361, + SMI = 362, + SNE = 363, + SPL = 364, + ST = 365, + SVC = 366, + SVS = 367, + ILLEGAL = 368, + NOP = 369, + RESET = 370, + RTE = 371, + RTR = 372, + RTS = 373, + TRAPV = 374, + JMP = 375, + JSR = 376, + LEA = 377, + LINK = 378, + MOVE = 379, + MOVEA = 380, + MOVEM = 381, + MOVEP = 382, + MOVEQ = 383, + CLR = 384, + NEG = 385, + NEGX = 386, + NBCD = 387, + NOT = 388, + PEA = 389, + STOP = 390, + TAS = 391, + SWAP = 392, + TRAP = 393, + TST = 394, + UNLK = 395, + PREDEC = 396, + POSTINC = 397, + BSIZE = 398, + WSIZE = 399, + LSIZE = 400, + SSIZE = 401 + }; +#endif +/* Tokens. */ +#define A0 258 +#define A1 259 +#define A2 260 +#define A3 261 +#define A4 262 +#define A5 263 +#define A6 264 +#define A7 265 +#define D0 266 +#define D1 267 +#define D2 268 +#define D3 269 +#define D4 270 +#define D5 271 +#define D6 272 +#define D7 273 +#define CCR 274 +#define SR 275 +#define USP 276 +#define PC 277 +#define NUMBER 278 +#define ABCD 279 +#define ADD 280 +#define ADDA 281 +#define ADDI 282 +#define ADDQ 283 +#define ADDX 284 +#define AND 285 +#define ANDI 286 +#define OR 287 +#define ORI 288 +#define SBCD 289 +#define SUB 290 +#define SUBA 291 +#define SUBI 292 +#define SUBQ 293 +#define SUBX 294 +#define ASL 295 +#define ASR 296 +#define LSL 297 +#define LSR 298 +#define ROL 299 +#define ROR 300 +#define ROXL 301 +#define ROXR 302 +#define BCC 303 +#define BCS 304 +#define BEQ 305 +#define BGE 306 +#define BGT 307 +#define BHI 308 +#define BLE 309 +#define BLS 310 +#define BLT 311 +#define BMI 312 +#define BNE 313 +#define BPL 314 +#define BVC 315 +#define BVS 316 +#define BSR 317 +#define BRA 318 +#define BCLR 319 +#define BSET 320 +#define BCHG 321 +#define BTST 322 +#define CHK 323 +#define CMP 324 +#define CMPA 325 +#define CMPI 326 +#define CMPM 327 +#define EOR 328 +#define EORI 329 +#define EXG 330 +#define EXT 331 +#define DIVU 332 +#define DIVS 333 +#define MULU 334 +#define MULS 335 +#define DBCC 336 +#define DBCS 337 +#define DBEQ 338 +#define DBF 339 +#define DBGE 340 +#define DBGT 341 +#define DBHI 342 +#define DBLE 343 +#define DBLS 344 +#define DBLT 345 +#define DBMI 346 +#define DBNE 347 +#define DBPL 348 +#define DBT 349 +#define DBVC 350 +#define DBVS 351 +#define SCC 352 +#define SCS 353 +#define SEQ 354 +#define SF 355 +#define SGE 356 +#define SGT 357 +#define SHI 358 +#define SLE 359 +#define SLS 360 +#define SLT 361 +#define SMI 362 +#define SNE 363 +#define SPL 364 +#define ST 365 +#define SVC 366 +#define SVS 367 +#define ILLEGAL 368 +#define NOP 369 +#define RESET 370 +#define RTE 371 +#define RTR 372 +#define RTS 373 +#define TRAPV 374 +#define JMP 375 +#define JSR 376 +#define LEA 377 +#define LINK 378 +#define MOVE 379 +#define MOVEA 380 +#define MOVEM 381 +#define MOVEP 382 +#define MOVEQ 383 +#define CLR 384 +#define NEG 385 +#define NEGX 386 +#define NBCD 387 +#define NOT 388 +#define PEA 389 +#define STOP 390 +#define TAS 391 +#define SWAP 392 +#define TRAP 393 +#define TST 394 +#define UNLK 395 +#define PREDEC 396 +#define POSTINC 397 +#define BSIZE 398 +#define WSIZE 399 +#define LSIZE 400 +#define SSIZE 401 + + + + +/* Copy the first part of user declarations. */ +#line 1 "m68k_parse.y" + +/* m68k_parse.c: line assembler for generic m68k_cpu + + Copyright (c) 2009-2010 Holger Veit + + 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 + HOLGER VEIT 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version +*/ + +#include "m68k_cpu.h" +#include +#include + +#if defined(_WIN32) +#include +#else +#include +#endif + +struct _ea { + int ea; + int cnt; + t_value arg[10]; +}; +struct _rea { + int reg; + struct _ea ea; +}; +struct _mask { + int x; + int d; +}; +struct _brop { + int opc; + int len; +}; + +static int oplen; +static int movemx[] = { 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, + 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080 }; +static int movemd[] = { 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001, + 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100 }; +static int yyrc; +static int yyerrc; +extern int yylex(); +static int _genop(t_value arg); +static int _genea(struct _ea arg); +static int _genbr(t_value arg,t_value,int); +static void yyerror(char* s); + +#define YYDEBUG 1 + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 74 "m68k_parse.y" +{ + int rc; + int reg; + int wl; + int opc; + struct _ea ea; + t_value num; + struct _rea rea; + struct _mask mask; + struct _brop brop; +} +/* Line 187 of yacc.c. */ +#line 473 "m68k_parse.tab.c" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ +#line 486 "m68k_parse.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 266 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 928 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 153 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 49 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 276 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 462 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 401 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 147, 2, 2, 2, 2, + 151, 152, 2, 2, 148, 150, 2, 149, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 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 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 6, 9, 15, 21, 27, 29, 32, + 37, 43, 48, 51, 57, 62, 68, 74, 79, 85, + 90, 95, 100, 105, 109, 111, 114, 119, 125, 131, + 136, 141, 146, 152, 158, 164, 170, 176, 182, 186, + 192, 195, 199, 202, 204, 206, 208, 211, 213, 216, + 219, 222, 225, 228, 231, 234, 237, 240, 243, 246, + 249, 252, 255, 259, 262, 266, 269, 273, 276, 280, + 283, 287, 290, 294, 297, 301, 304, 308, 310, 312, + 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, + 334, 336, 338, 340, 343, 346, 349, 352, 355, 358, + 361, 364, 367, 370, 373, 376, 379, 382, 385, 388, + 390, 392, 394, 396, 399, 401, 404, 407, 410, 412, + 414, 416, 418, 420, 422, 424, 426, 428, 430, 432, + 434, 436, 438, 440, 442, 444, 447, 449, 451, 453, + 455, 457, 459, 461, 463, 465, 467, 469, 471, 473, + 475, 477, 479, 481, 483, 485, 487, 489, 491, 493, + 495, 497, 499, 501, 503, 505, 507, 511, 516, 520, + 524, 528, 532, 534, 536, 538, 540, 542, 544, 546, + 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, + 568, 570, 572, 574, 576, 578, 580, 582, 584, 586, + 588, 592, 594, 596, 600, 604, 606, 608, 610, 612, + 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, + 634, 636, 638, 640, 642, 644, 646, 648, 650, 652, + 654, 656, 658, 660, 662, 664, 666, 668, 670, 672, + 674, 676, 678, 680, 682, 684, 686, 688, 690, 692, + 694, 696, 698, 700, 702, 704, 706, 708, 710, 712, + 714, 716, 718, 722, 726, 730, 736, 745, 754, 759, + 763, 769, 771, 780, 789, 792, 794 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 154, 0, -1, 156, 170, -1, 157, 171, -1, 158, + 147, 23, 148, 185, -1, 160, 147, 23, 148, 182, + -1, 159, 147, 23, 148, 186, -1, 161, -1, 162, + 23, -1, 163, 173, 148, 185, -1, 163, 147, 23, + 148, 185, -1, 68, 183, 148, 173, -1, 164, 185, + -1, 69, 176, 184, 148, 173, -1, 165, 183, 148, + 173, -1, 70, 175, 184, 148, 172, -1, 72, 176, + 193, 148, 193, -1, 166, 173, 148, 23, -1, 73, + 176, 173, 148, 185, -1, 75, 173, 148, 173, -1, + 75, 172, 148, 172, -1, 75, 172, 148, 173, -1, + 75, 173, 148, 172, -1, 76, 175, 173, -1, 167, + -1, 168, 187, -1, 122, 187, 148, 172, -1, 123, + 172, 148, 147, 23, -1, 124, 177, 184, 148, 186, + -1, 124, 20, 148, 185, -1, 124, 21, 148, 172, + -1, 124, 172, 148, 21, -1, 125, 178, 185, 148, + 172, -1, 126, 175, 179, 148, 189, -1, 126, 175, + 188, 148, 179, -1, 127, 175, 173, 148, 195, -1, + 127, 175, 195, 148, 173, -1, 128, 147, 23, 148, + 173, -1, 135, 147, 23, -1, 155, 175, 184, 148, + 172, -1, 137, 173, -1, 138, 147, 23, -1, 140, + 172, -1, 26, -1, 36, -1, 24, -1, 29, 176, + -1, 34, -1, 39, 176, -1, 25, 176, -1, 30, + 176, -1, 32, 176, -1, 35, 176, -1, 27, 176, + -1, 71, 176, -1, 37, 176, -1, 31, 176, -1, + 74, 176, -1, 33, 176, -1, 28, 176, -1, 38, + 176, -1, 40, 181, -1, 40, 176, 169, -1, 41, + 181, -1, 41, 176, 169, -1, 42, 181, -1, 42, + 176, 169, -1, 43, 181, -1, 43, 176, 169, -1, + 44, 181, -1, 44, 176, 169, -1, 45, 181, -1, + 45, 176, 169, -1, 46, 181, -1, 46, 176, 169, + -1, 47, 181, -1, 47, 176, 169, -1, 48, -1, + 49, -1, 50, -1, 51, -1, 52, -1, 53, -1, + 54, -1, 55, -1, 56, -1, 57, -1, 58, -1, + 59, -1, 60, -1, 61, -1, 62, -1, 63, -1, + 48, 174, -1, 49, 174, -1, 50, 174, -1, 51, + 174, -1, 52, 174, -1, 53, 174, -1, 54, 174, + -1, 55, 174, -1, 56, 174, -1, 57, 174, -1, + 58, 174, -1, 59, 174, -1, 60, 174, -1, 61, + 174, -1, 62, 174, -1, 63, 174, -1, 66, -1, + 64, -1, 65, -1, 67, -1, 129, 176, -1, 132, + -1, 130, 176, -1, 131, 176, -1, 133, 176, -1, + 97, -1, 98, -1, 99, -1, 100, -1, 101, -1, + 102, -1, 103, -1, 104, -1, 105, -1, 106, -1, + 107, -1, 108, -1, 109, -1, 110, -1, 111, -1, + 112, -1, 136, -1, 139, 176, -1, 78, -1, 77, + -1, 80, -1, 79, -1, 81, -1, 82, -1, 83, + -1, 85, -1, 86, -1, 87, -1, 88, -1, 89, + -1, 90, -1, 91, -1, 92, -1, 93, -1, 95, + -1, 96, -1, 84, -1, 94, -1, 113, -1, 114, + -1, 115, -1, 116, -1, 117, -1, 118, -1, 119, + -1, 120, -1, 121, -1, 134, -1, 173, 148, 173, + -1, 147, 23, 148, 173, -1, 190, 148, 190, -1, + 194, 148, 194, -1, 173, 148, 182, -1, 181, 148, + 173, -1, 3, -1, 4, -1, 5, -1, 6, -1, + 7, -1, 8, -1, 9, -1, 10, -1, 11, -1, + 12, -1, 13, -1, 14, -1, 15, -1, 16, -1, + 17, -1, 18, -1, 146, -1, 144, -1, 145, -1, + 143, -1, 144, -1, 145, -1, 143, -1, 144, -1, + 145, -1, 144, -1, 145, -1, 180, -1, 180, 149, + 179, -1, 172, -1, 173, -1, 172, 150, 172, -1, + 173, 150, 173, -1, 191, -1, 192, -1, 193, -1, + 194, -1, 195, -1, 196, -1, 197, -1, 198, -1, + 199, -1, 200, -1, 190, -1, 191, -1, 192, -1, + 193, -1, 194, -1, 195, -1, 196, -1, 197, -1, + 190, -1, 192, -1, 193, -1, 194, -1, 195, -1, + 196, -1, 197, -1, 198, -1, 199, -1, 200, -1, + 190, -1, 181, -1, 190, -1, 192, -1, 193, -1, + 194, -1, 195, -1, 196, -1, 197, -1, 185, -1, + 201, -1, 192, -1, 195, -1, 196, -1, 197, -1, + 198, -1, 199, -1, 192, -1, 193, -1, 195, -1, + 196, -1, 197, -1, 192, -1, 194, -1, 195, -1, + 196, -1, 197, -1, 173, -1, 172, -1, 151, 172, + 152, -1, 151, 172, 142, -1, 141, 172, 152, -1, + 151, 23, 148, 172, 152, -1, 151, 23, 148, 172, + 148, 173, 175, 152, -1, 151, 23, 148, 172, 148, + 172, 175, 152, -1, 151, 23, 152, 175, -1, 151, + 23, 152, -1, 151, 23, 148, 22, 152, -1, 23, + -1, 151, 23, 148, 22, 148, 173, 175, 152, -1, + 151, 23, 148, 22, 148, 172, 175, 152, -1, 147, + 23, -1, 19, -1, 20, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 115, 115, 116, 117, 119, 120, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 163, 164, 167, 168, 169, 170, 174, + 175, 176, 177, 181, 182, 183, 187, 188, 189, 193, + 194, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 252, + 253, 254, 255, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 285, 286, 287, 288, + 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 311, 312, 313, 314, + 315, 316, 317, 321, 322, 323, 326, 327, 330, 331, + 334, 337, 340, 341, 342, 343, 344, 345, 346, 347, + 350, 351, 352, 353, 354, 355, 356, 357, 360, 363, + 364, 367, 368, 369, 372, 373, 374, 377, 378, 381, + 382, 385, 386, 387, 389, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 394, 394, 394, 394, 394, + 394, 394, 394, 395, 395, 395, 395, 395, 395, 395, + 395, 395, 395, 396, 396, 397, 397, 397, 397, 397, + 397, 397, 398, 398, 399, 399, 399, 399, 399, 399, + 400, 400, 400, 400, 400, 401, 401, 401, 401, 401, + 404, 406, 408, 410, 412, 414, 416, 418, 421, 423, + 426, 427, 429, 431, 434, 438, 439 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "A0", "A1", "A2", "A3", "A4", "A5", "A6", + "A7", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "CCR", "SR", "USP", + "PC", "NUMBER", "ABCD", "ADD", "ADDA", "ADDI", "ADDQ", "ADDX", "AND", + "ANDI", "OR", "ORI", "SBCD", "SUB", "SUBA", "SUBI", "SUBQ", "SUBX", + "ASL", "ASR", "LSL", "LSR", "ROL", "ROR", "ROXL", "ROXR", "BCC", "BCS", + "BEQ", "BGE", "BGT", "BHI", "BLE", "BLS", "BLT", "BMI", "BNE", "BPL", + "BVC", "BVS", "BSR", "BRA", "BCLR", "BSET", "BCHG", "BTST", "CHK", "CMP", + "CMPA", "CMPI", "CMPM", "EOR", "EORI", "EXG", "EXT", "DIVU", "DIVS", + "MULU", "MULS", "DBCC", "DBCS", "DBEQ", "DBF", "DBGE", "DBGT", "DBHI", + "DBLE", "DBLS", "DBLT", "DBMI", "DBNE", "DBPL", "DBT", "DBVC", "DBVS", + "SCC", "SCS", "SEQ", "SF", "SGE", "SGT", "SHI", "SLE", "SLS", "SLT", + "SMI", "SNE", "SPL", "ST", "SVC", "SVS", "ILLEGAL", "NOP", "RESET", + "RTE", "RTR", "RTS", "TRAPV", "JMP", "JSR", "LEA", "LINK", "MOVE", + "MOVEA", "MOVEM", "MOVEP", "MOVEQ", "CLR", "NEG", "NEGX", "NBCD", "NOT", + "PEA", "STOP", "TAS", "SWAP", "TRAP", "TST", "UNLK", "PREDEC", "POSTINC", + "BSIZE", "WSIZE", "LSIZE", "SSIZE", "'#'", "','", "'/'", "'-'", "'('", + "')'", "$accept", "stmt", "arop", "bcdop", "dualop", "immop", "immop2", + "qop", "shftop", "brop", "btop", "monop", "mdop", "dbop", "direct", + "jop", "shftarg", "bcdarg", "dualarg", "areg", "dreg", "szs", "szwl", + "szbwl", "szmv", "szm", "reglist", "regs", "eama", "eaa", "ead", "eaall", + "eada", "eadas", "eac", "eacai", "eacad", "ea0", "ea1", "ea2", "ea3", + "ea4", "ea5", "ea6", "ea70", "ea72", "ea73", "ea74", "easr", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 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, 35, 44, 47, + 45, 40, 41 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 153, 154, 154, 154, 154, 154, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, + 154, 154, 154, 155, 155, 156, 156, 156, 156, 157, + 157, 157, 157, 158, 158, 158, 159, 159, 159, 160, + 160, 161, 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 163, + 163, 163, 163, 164, 164, 164, 164, 164, 164, 164, + 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, + 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 166, 166, 166, 166, 167, 167, 167, 167, + 167, 167, 167, 168, 168, 168, 169, 169, 170, 170, + 171, 171, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 174, 175, + 175, 176, 176, 176, 177, 177, 177, 178, 178, 179, + 179, 180, 180, 180, 180, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 182, 182, 182, 182, 182, + 182, 182, 182, 183, 183, 183, 183, 183, 183, 183, + 183, 183, 183, 184, 184, 185, 185, 185, 185, 185, + 185, 185, 186, 186, 187, 187, 187, 187, 187, 187, + 188, 188, 188, 188, 188, 189, 189, 189, 189, 189, + 190, 191, 192, 193, 194, 195, 196, 196, 197, 197, + 198, 198, 199, 199, 200, 201, 201 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 2, 5, 5, 5, 1, 2, 4, + 5, 4, 2, 5, 4, 5, 5, 4, 5, 4, + 4, 4, 4, 3, 1, 2, 4, 5, 5, 4, + 4, 4, 5, 5, 5, 5, 5, 5, 3, 5, + 2, 3, 2, 1, 1, 1, 2, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, + 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 4, 3, 3, + 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 1, 1, 3, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 3, 3, 5, 8, 8, 4, 3, + 5, 1, 8, 8, 2, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 0, 45, 0, 43, 0, 0, 0, 0, 0, 0, + 0, 47, 0, 44, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 110, 111, 109, 112, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 137, 136, 139, 138, 140, 141, + 142, 154, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 155, 152, 153, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, + 0, 165, 0, 134, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, + 0, 24, 0, 191, 192, 193, 49, 53, 59, 46, + 50, 56, 51, 58, 52, 55, 60, 48, 172, 173, + 174, 175, 176, 177, 178, 179, 271, 0, 0, 0, + 261, 0, 61, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 0, 63, 0, 65, 0, 67, 0, + 69, 0, 71, 0, 73, 0, 75, 188, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 180, 181, 182, 183, 184, 185, + 186, 187, 260, 0, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 0, 189, 190, 0, 54, 0, + 0, 57, 0, 0, 0, 0, 0, 244, 245, 246, + 247, 248, 249, 0, 0, 0, 194, 195, 196, 0, + 0, 197, 198, 0, 0, 0, 0, 113, 115, 116, + 117, 0, 40, 0, 135, 42, 1, 0, 2, 0, + 0, 3, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 12, 235, 236, 237, 238, 239, 240, 241, 0, + 0, 25, 0, 274, 0, 0, 0, 62, 0, 64, + 66, 68, 70, 72, 74, 76, 0, 234, 0, 233, + 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 201, 202, 0, 199, 0, + 250, 251, 252, 253, 254, 0, 0, 0, 0, 38, + 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 264, 0, 269, 263, 262, 0, + 0, 11, 0, 0, 0, 0, 0, 20, 21, 22, + 19, 26, 0, 29, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 168, 169, + 170, 215, 216, 217, 218, 219, 220, 221, 222, 171, + 0, 0, 0, 0, 9, 0, 14, 17, 0, 0, + 268, 0, 166, 13, 15, 16, 18, 27, 275, 276, + 242, 28, 243, 32, 203, 204, 0, 33, 255, 256, + 257, 258, 259, 200, 34, 0, 35, 36, 37, 39, + 4, 6, 5, 10, 0, 270, 0, 265, 167, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 273, 272, + 267, 266 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 297, 268, 271, 160, + 212, 188, 227, 136, 250, 253, 327, 328, 307, 390, + 213, 308, 420, 421, 236, 329, 427, 282, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 422 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -343 +static const yytype_int16 yypact[] = +{ + 675, -343, -126, -343, -126, -126, -126, -126, -126, -126, + -126, -343, -126, -343, -126, -126, -126, 456, 456, 456, + 456, 456, 456, 456, 456, -139, -139, -139, -139, -139, + -139, -139, -139, -139, -139, -139, -139, -139, -139, -139, + -139, -343, -343, -343, -343, 477, -126, -107, -126, -126, + -126, -126, 626, -107, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, -343, -343, -343, -20, + 642, 141, -105, -107, -107, -137, -126, -126, -126, -343, + -126, -343, -82, -343, 646, -80, -126, 642, 72, -107, + 557, 18, -72, -65, -50, -343, 78, 31, 76, 477, + 646, -343, -20, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, -343, 642, 85, 203, + -343, 236, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, 236, -343, 236, -343, 236, -343, 236, + -343, 236, -343, 236, -343, 236, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -37, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, 18, -343, -343, 18, -343, -42, + 646, -343, -36, -35, 646, 203, -32, -343, -343, -343, + -343, -343, -343, -29, -27, -19, -343, -343, -343, -13, + 18, -343, -343, 76, 538, 41, 92, -343, -343, -343, + -343, 100, -343, 113, -343, -343, -343, 18, -343, -10, + -9, -343, -8, -7, 119, 120, 129, -343, 131, 8, + 581, -343, -343, -343, -343, -343, -343, -343, -343, 15, + 16, -343, 19, -343, -143, -138, 149, -343, 25, -343, + -343, -343, -343, -343, -343, -343, 646, -343, 27, -343, + 29, 642, 32, 33, 626, 626, -343, 22, 642, 37, + 76, 642, 155, 39, 40, 35, 36, 43, 45, 47, + -343, -343, -343, -343, -343, 166, 51, 54, 57, -343, + -343, 66, 646, 77, 515, 646, 71, 73, 74, 83, + 76, -84, 646, 197, -343, 605, -107, -343, -343, 84, + 646, -343, 646, 642, 93, -42, 76, -343, -343, -343, + -343, -343, 211, -343, -343, -343, 546, 642, 642, 646, + -135, 626, 626, 90, 88, 646, 646, 642, -343, -343, + -343, -343, -343, -343, -343, -343, -343, -343, -343, -343, + 76, 546, 515, 76, -343, 642, -343, -343, -68, -67, + -343, 646, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, 581, -343, -343, -343, + -343, -343, -343, -343, -343, 642, -343, -343, -343, -343, + -343, -343, -343, -343, 626, -343, 626, -343, -343, 91, + -107, -107, -107, -107, 104, 106, 107, 109, -343, -343, + -343, -343 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -343, -343, -343, -343, -343, -343, -343, -343, -343, -343, + -343, -343, -343, -343, -343, -343, 248, -343, -343, -39, + -51, 811, -53, 812, -343, -343, -276, -343, 559, -162, + 115, -150, -120, -159, 128, -343, -343, -34, -342, -25, + 108, 137, -30, 38, 69, 26, 28, -33, -343 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint16 yytable[] = +{ + 234, 233, 392, 156, 357, 355, 157, 187, 281, 356, + 256, 214, 223, 232, 358, 218, 426, 133, 134, 135, + 215, 148, 149, 150, 151, 152, 153, 154, 155, 204, + 205, 206, 207, 208, 209, 210, 211, 225, 226, 251, + 252, 156, 204, 205, 206, 207, 208, 209, 210, 211, + 254, 255, 204, 205, 206, 207, 208, 209, 210, 211, + 392, 243, 249, 262, 405, 261, 267, 263, 356, 238, + 272, 221, 266, 222, 237, 274, 279, 310, 265, 290, + 444, 446, 275, 219, 445, 447, 269, 204, 205, 206, + 207, 208, 209, 210, 211, 214, 223, 276, 286, 218, + 323, 277, 238, 283, 215, 433, 434, 237, 293, 311, + 298, 306, 314, 315, 220, 338, 318, 341, 292, 319, + 295, 320, 298, 339, 298, 241, 298, 242, 298, 321, + 298, 235, 298, 324, 298, 322, 340, 239, 342, 343, + 344, 345, 346, 347, 148, 149, 150, 151, 152, 153, + 154, 155, 348, 216, 349, 221, 350, 222, 241, 157, + 242, 244, 245, 352, 353, 158, 287, 219, 240, 159, + 239, 354, 359, 360, 358, 362, 375, 363, 278, 313, + 365, 366, 217, 316, 372, 378, 379, 376, 377, 383, + 309, 380, 335, 309, 381, 382, 317, 288, 220, 384, + 373, 240, 385, 326, 336, 386, 148, 149, 150, 151, + 152, 153, 154, 155, 387, 325, 309, 157, 157, 400, + 407, 401, 402, 286, 332, 337, 294, 280, 283, 330, + 404, 403, 411, 309, 417, 357, 284, 216, 435, 335, + 442, 295, 441, 447, 289, 0, 416, 204, 205, 206, + 207, 208, 209, 210, 211, 361, 458, 270, 459, 460, + 291, 461, 0, 368, 370, 285, 217, 0, 0, 0, + 0, 0, 364, 0, 0, 367, 369, 0, 0, 371, + 440, 0, 374, 443, 246, 247, 248, 0, 0, 0, + 286, 287, 333, 0, 399, 283, 0, 0, 0, 0, + 0, 406, 0, 410, 0, 0, 0, 0, 388, 412, + 391, 413, 0, 0, 396, 0, 409, 0, 0, 393, + 286, 0, 288, 334, 414, 283, 0, 0, 425, 0, + 326, 326, 0, 0, 437, 438, 286, 312, 423, 424, + 0, 283, 325, 325, 0, 0, 286, 0, 439, 0, + 430, 283, 0, 0, 436, 428, 0, 0, 287, 0, + 448, 284, 331, 0, 0, 0, 409, 0, 391, 0, + 286, 286, 396, 286, 0, 283, 283, 393, 283, 0, + 0, 0, 397, 296, 0, 0, 0, 317, 287, 288, + 285, 0, 0, 451, 0, 453, 449, 454, 455, 456, + 457, 0, 0, 0, 287, 450, 0, 452, 0, 0, + 0, 0, 0, 398, 287, 0, 0, 0, 431, 288, + 0, 299, 0, 300, 0, 301, 0, 302, 284, 303, + 0, 304, 0, 305, 0, 288, 0, 0, 287, 287, + 397, 287, 0, 0, 0, 288, 0, 0, 0, 432, + 0, 0, 394, 0, 0, 0, 0, 285, 284, 148, + 149, 150, 151, 152, 153, 154, 155, 0, 0, 288, + 288, 398, 288, 415, 284, 0, 0, 0, 0, 156, + 389, 395, 0, 0, 284, 0, 0, 285, 204, 205, + 206, 207, 208, 209, 210, 211, 0, 0, 0, 0, + 156, 0, 0, 285, 0, 0, 0, 0, 284, 284, + 394, 284, 0, 285, 0, 0, 0, 429, 148, 149, + 150, 151, 152, 153, 154, 155, 204, 205, 206, 207, + 208, 209, 210, 211, 0, 0, 0, 285, 285, 395, + 285, 148, 149, 150, 151, 152, 153, 154, 155, 204, + 205, 206, 207, 208, 209, 210, 211, 204, 205, 206, + 207, 208, 209, 210, 211, 418, 419, 0, 204, 205, + 206, 207, 208, 209, 210, 211, 162, 174, 176, 178, + 180, 182, 184, 186, 148, 149, 150, 151, 152, 153, + 154, 155, 0, 0, 0, 0, 0, 157, 0, 133, + 134, 135, 0, 158, 351, 0, 0, 159, 148, 149, + 150, 151, 152, 153, 154, 155, 0, 0, 157, 0, + 0, 0, 0, 0, 158, 0, 0, 408, 159, 148, + 149, 150, 151, 152, 153, 154, 155, 204, 205, 206, + 207, 208, 209, 210, 211, 148, 149, 150, 151, 152, + 153, 154, 155, 0, 0, 0, 157, 204, 205, 206, + 207, 208, 209, 210, 211, 0, 280, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 273, 0, 0, 0, 0, 0, 0, 157, 0, 280, + 0, 0, 0, 0, 0, 0, 0, 280, 157, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 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, 137, 138, 139, 140, + 141, 142, 143, 0, 144, 0, 145, 146, 147, 161, + 173, 175, 177, 179, 181, 183, 185, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, + 202, 203, 0, 0, 0, 0, 0, 0, 224, 0, + 228, 229, 230, 231, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 257, 258, + 259, 0, 260, 0, 0, 0, 0, 0, 264 +}; + +static const yytype_int16 yycheck[] = +{ + 53, 52, 344, 23, 142, 148, 141, 146, 128, 152, + 147, 45, 45, 52, 152, 45, 151, 143, 144, 145, + 45, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 144, 145, 144, + 145, 23, 11, 12, 13, 14, 15, 16, 17, 18, + 103, 104, 11, 12, 13, 14, 15, 16, 17, 18, + 402, 100, 101, 114, 148, 147, 119, 147, 152, 99, + 121, 45, 0, 45, 99, 147, 127, 227, 117, 130, + 148, 148, 147, 45, 152, 152, 120, 11, 12, 13, + 14, 15, 16, 17, 18, 129, 129, 147, 128, 129, + 250, 23, 132, 128, 129, 381, 382, 132, 23, 151, + 161, 148, 148, 148, 45, 23, 148, 267, 157, 148, + 159, 148, 173, 23, 175, 99, 177, 99, 179, 148, + 181, 151, 183, 253, 185, 148, 23, 99, 148, 148, + 148, 148, 23, 23, 3, 4, 5, 6, 7, 8, + 9, 10, 23, 45, 23, 129, 148, 129, 132, 141, + 132, 20, 21, 148, 148, 147, 128, 129, 99, 151, + 132, 152, 23, 148, 152, 148, 21, 148, 147, 230, + 148, 148, 45, 234, 147, 150, 150, 148, 148, 23, + 224, 148, 151, 227, 149, 148, 235, 128, 129, 148, + 320, 132, 148, 254, 255, 148, 3, 4, 5, 6, + 7, 8, 9, 10, 148, 254, 250, 141, 141, 148, + 23, 148, 148, 253, 254, 255, 23, 151, 253, 254, + 350, 148, 148, 267, 23, 142, 128, 129, 148, 151, + 402, 280, 401, 152, 129, -1, 366, 11, 12, 13, + 14, 15, 16, 17, 18, 306, 152, 120, 152, 152, + 132, 152, -1, 314, 315, 128, 129, -1, -1, -1, + -1, -1, 311, -1, -1, 314, 315, -1, -1, 318, + 400, -1, 321, 403, 143, 144, 145, -1, -1, -1, + 320, 253, 254, -1, 345, 320, -1, -1, -1, -1, + -1, 352, -1, 356, -1, -1, -1, -1, 342, 360, + 344, 362, -1, -1, 344, -1, 355, -1, -1, 344, + 350, -1, 253, 254, 363, 350, -1, -1, 379, -1, + 381, 382, -1, -1, 385, 386, 366, 229, 377, 378, + -1, 366, 381, 382, -1, -1, 376, -1, 387, -1, + 380, 376, -1, -1, 384, 380, -1, -1, 320, -1, + 411, 253, 254, -1, -1, -1, 405, -1, 402, -1, + 400, 401, 402, 403, -1, 400, 401, 402, 403, -1, + -1, -1, 344, 147, -1, -1, -1, 426, 350, 320, + 253, -1, -1, 444, -1, 446, 435, 450, 451, 452, + 453, -1, -1, -1, 366, 444, -1, 446, -1, -1, + -1, -1, -1, 344, 376, -1, -1, -1, 380, 350, + -1, 173, -1, 175, -1, 177, -1, 179, 320, 181, + -1, 183, -1, 185, -1, 366, -1, -1, 400, 401, + 402, 403, -1, -1, -1, 376, -1, -1, -1, 380, + -1, -1, 344, -1, -1, -1, -1, 320, 350, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, 400, + 401, 402, 403, 365, 366, -1, -1, -1, -1, 23, + 343, 344, -1, -1, 376, -1, -1, 350, 11, 12, + 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, + 23, -1, -1, 366, -1, -1, -1, -1, 400, 401, + 402, 403, -1, 376, -1, -1, -1, 380, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, -1, -1, -1, 400, 401, 402, + 403, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, -1, 11, 12, + 13, 14, 15, 16, 17, 18, 17, 18, 19, 20, + 21, 22, 23, 24, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, 141, -1, 143, + 144, 145, -1, 147, 23, -1, -1, 151, 3, 4, + 5, 6, 7, 8, 9, 10, -1, -1, 141, -1, + -1, -1, -1, -1, 147, -1, -1, 22, 151, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 3, 4, 5, 6, 7, + 8, 9, 10, -1, -1, -1, 141, 11, 12, 13, + 14, 15, 16, 17, 18, -1, 151, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 121, -1, -1, -1, -1, -1, -1, 141, -1, 151, + -1, -1, -1, -1, -1, -1, -1, 151, 141, 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, 4, 5, 6, 7, + 8, 9, 10, -1, 12, -1, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, -1, -1, -1, -1, -1, -1, 46, -1, + 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 106, 107, + 108, -1, 110, -1, -1, -1, -1, -1, 116 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 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, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 143, 144, 145, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 3, 4, + 5, 6, 7, 8, 9, 10, 23, 141, 147, 151, + 172, 176, 181, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 176, 181, 176, 181, 176, 181, 176, + 181, 176, 181, 176, 181, 176, 181, 146, 174, 174, + 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, + 174, 174, 174, 174, 11, 12, 13, 14, 15, 16, + 17, 18, 173, 183, 190, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 176, 144, 145, 175, 176, 176, + 176, 176, 172, 173, 175, 151, 187, 192, 195, 196, + 197, 198, 199, 172, 20, 21, 143, 144, 145, 172, + 177, 144, 145, 178, 175, 175, 147, 176, 176, 176, + 176, 147, 173, 147, 176, 172, 0, 175, 170, 190, + 194, 171, 173, 181, 147, 147, 147, 23, 147, 173, + 151, 185, 190, 192, 193, 194, 195, 196, 197, 183, + 173, 187, 172, 23, 23, 172, 147, 169, 173, 169, + 169, 169, 169, 169, 169, 169, 148, 181, 184, 190, + 184, 151, 193, 173, 148, 148, 173, 172, 148, 148, + 148, 148, 148, 184, 185, 172, 173, 179, 180, 188, + 192, 193, 195, 196, 197, 151, 173, 195, 23, 23, + 23, 184, 148, 148, 148, 148, 23, 23, 23, 23, + 148, 23, 148, 148, 152, 148, 152, 142, 152, 23, + 148, 173, 148, 148, 172, 148, 148, 172, 173, 172, + 173, 172, 147, 185, 172, 21, 148, 148, 150, 150, + 148, 149, 148, 23, 148, 148, 148, 148, 190, 194, + 182, 190, 191, 192, 193, 194, 195, 196, 197, 173, + 148, 148, 148, 148, 185, 148, 173, 23, 22, 172, + 175, 148, 173, 173, 172, 193, 185, 23, 19, 20, + 185, 186, 201, 172, 172, 173, 151, 189, 192, 194, + 195, 196, 197, 179, 179, 148, 195, 173, 173, 172, + 185, 186, 182, 185, 148, 152, 148, 152, 173, 172, + 172, 173, 172, 173, 175, 175, 175, 175, 152, 152, + 152, 152 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 115 "m68k_parse.y" + { _genop((yyvsp[(1) - (2)].opc) | (yyvsp[(2) - (2)].opc)); yyrc = -1; ;} + break; + + case 3: +#line 116 "m68k_parse.y" + { _genop((yyvsp[(1) - (2)].opc) | (yyvsp[(2) - (2)].rea).reg | (yyvsp[(2) - (2)].rea).ea.ea); yyrc = _genea((yyvsp[(2) - (2)].rea).ea) -1; ;} + break; + + case 4: +#line 117 "m68k_parse.y" + { _genop((yyvsp[(1) - (5)].opc) | (yyvsp[(5) - (5)].ea).ea); if (oplen==0) { _genop((yyvsp[(3) - (5)].num) & 0xff); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 3; } + else if (oplen==1) { _genop((yyvsp[(3) - (5)].num)); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 3; } else { _genop((yyvsp[(3) - (5)].num)>>16); _genop((yyvsp[(3) - (5)].num) & 0xffff); yyrc = _genea((yyvsp[(5) - (5)].ea))-5; } ;} + break; + + case 5: +#line 119 "m68k_parse.y" + { _genop((yyvsp[(1) - (5)].opc) | (((yyvsp[(3) - (5)].num)&7)<<9) | (yyvsp[(5) - (5)].ea).ea); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 1; ;} + break; + + case 6: +#line 120 "m68k_parse.y" + { _genop((yyvsp[(1) - (5)].opc) | (yyvsp[(5) - (5)].ea).ea); if (oplen==0) { _genop((yyvsp[(3) - (5)].num) & 0xff); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 3; } + else if (oplen==1) { _genop((yyvsp[(3) - (5)].num)); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 3; } else { _genop((yyvsp[(3) - (5)].num)>>16); _genop((yyvsp[(3) - (5)].num) & 0xffff); yyrc = _genea((yyvsp[(5) - (5)].ea))-5; } ;} + break; + + case 7: +#line 122 "m68k_parse.y" + { _genop((yyvsp[(1) - (1)].rea).reg); if (((yyvsp[(1) - (1)].rea).reg&0xc0)==0xc0) yyrc = _genea((yyvsp[(1) - (1)].rea).ea) - 1; else { yyrc = -1; } ;} + break; + + case 8: +#line 123 "m68k_parse.y" + { yyrc = _genbr((yyvsp[(1) - (2)].brop).opc,(yyvsp[(2) - (2)].num),(yyvsp[(1) - (2)].brop).len) - 1; ;} + break; + + case 9: +#line 124 "m68k_parse.y" + { _genop((yyvsp[(1) - (4)].opc) | ((yyvsp[(2) - (4)].reg)<<9) | 0x100 | (yyvsp[(4) - (4)].ea).ea); yyrc = _genea((yyvsp[(4) - (4)].ea)) - 1; ;} + break; + + case 10: +#line 125 "m68k_parse.y" + { _genop((yyvsp[(1) - (5)].opc) | 0x0800 | (yyvsp[(5) - (5)].ea).ea); _genop((yyvsp[(3) - (5)].num)); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 3; ;} + break; + + case 11: +#line 126 "m68k_parse.y" + { _genop(0x4180 | ((yyvsp[(4) - (4)].reg)<<9) | (yyvsp[(2) - (4)].ea).ea); yyrc = _genea((yyvsp[(2) - (4)].ea)) - 1; ;} + break; + + case 12: +#line 127 "m68k_parse.y" + { _genop((yyvsp[(1) - (2)].opc) | (yyvsp[(2) - (2)].ea).ea); yyrc = _genea((yyvsp[(2) - (2)].ea)) - 1; ;} + break; + + case 13: +#line 128 "m68k_parse.y" + { _genop(0xb000 | ((yyvsp[(2) - (5)].wl)<<6) | ((yyvsp[(5) - (5)].reg)<<9) | (yyvsp[(3) - (5)].ea).ea); yyrc = _genea((yyvsp[(3) - (5)].ea)) - 1; ;} + break; + + case 14: +#line 129 "m68k_parse.y" + { _genop((yyvsp[(1) - (4)].opc) | ((yyvsp[(4) - (4)].reg)<<9) | (yyvsp[(2) - (4)].ea).ea); yyrc = _genea((yyvsp[(2) - (4)].ea)) - 1; ;} + break; + + case 15: +#line 130 "m68k_parse.y" + { _genop(0xb0c0 | ((yyvsp[(2) - (5)].wl)<<8) | ((yyvsp[(5) - (5)].reg)<<9) | (yyvsp[(3) - (5)].ea).ea); yyrc = _genea((yyvsp[(3) - (5)].ea)) - 1; ;} + break; + + case 16: +#line 131 "m68k_parse.y" + { _genop(0xb108 | ((yyvsp[(5) - (5)].ea).ea<<9) | ((yyvsp[(2) - (5)].wl)<<6) | (yyvsp[(3) - (5)].ea).ea); yyrc = -1; ;} + break; + + case 17: +#line 132 "m68k_parse.y" + { yyrc = _genbr((yyvsp[(1) - (4)].opc) | (yyvsp[(2) - (4)].reg), (yyvsp[(4) - (4)].num), 1) - 1; ;} + break; + + case 18: +#line 133 "m68k_parse.y" + { _genop(0xb000 | ((yyvsp[(2) - (5)].wl) << 6) | 0x100 | (yyvsp[(5) - (5)].ea).ea); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 1; ;} + break; + + case 19: +#line 134 "m68k_parse.y" + { _genop(0xc140 | ((yyvsp[(2) - (4)].reg)<<9) | (yyvsp[(4) - (4)].reg)); yyrc = -1; ;} + break; + + case 20: +#line 135 "m68k_parse.y" + { _genop(0xc148 | ((yyvsp[(2) - (4)].reg)<<9) | (yyvsp[(4) - (4)].reg)); yyrc = -1; ;} + break; + + case 21: +#line 136 "m68k_parse.y" + { _genop(0xc188 | ((yyvsp[(4) - (4)].reg)<<9) | (yyvsp[(2) - (4)].reg)); yyrc = -1; ;} + break; + + case 22: +#line 137 "m68k_parse.y" + { _genop(0xc188 | ((yyvsp[(2) - (4)].reg)<<9) | (yyvsp[(4) - (4)].reg)); yyrc = -1; ;} + break; + + case 23: +#line 138 "m68k_parse.y" + { _genop(0x4840 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].reg)); yyrc = -1; ;} + break; + + case 24: +#line 139 "m68k_parse.y" + { _genop((yyvsp[(1) - (1)].opc)); yyrc = -1; ;} + break; + + case 25: +#line 140 "m68k_parse.y" + { _genop((yyvsp[(1) - (2)].opc) | (yyvsp[(2) - (2)].ea).ea); yyrc = _genea((yyvsp[(2) - (2)].ea)) -1; ;} + break; + + case 26: +#line 141 "m68k_parse.y" + { _genop(0x41c0 | (yyvsp[(2) - (4)].ea).ea); yyrc = _genea((yyvsp[(2) - (4)].ea)) - 1; ;} + break; + + case 27: +#line 142 "m68k_parse.y" + { _genop(0x4e50 | (yyvsp[(2) - (5)].reg)); _genop((yyvsp[(5) - (5)].num)); yyrc = -3; ;} + break; + + case 28: +#line 143 "m68k_parse.y" + { if ((yyvsp[(5) - (5)].ea).ea==074) { _genop(0x44c0 | ((yyvsp[(5) - (5)].ea).cnt==1?0x0200:0x0000) | (yyvsp[(3) - (5)].ea).ea); yyrc = _genea((yyvsp[(3) - (5)].ea)) - 1; } + else { int tmp = (((yyvsp[(5) - (5)].ea).ea&070)>>3)|(((yyvsp[(5) - (5)].ea).ea&7)<<3); _genop(0x0000 | ((yyvsp[(2) - (5)].wl)<<12) | (tmp<<6) | (yyvsp[(3) - (5)].ea).ea); + yyrc = _genea((yyvsp[(3) - (5)].ea)) - 1; yyrc += _genea((yyvsp[(5) - (5)].ea)); } ;} + break; + + case 29: +#line 146 "m68k_parse.y" + { _genop(0x40c0 | (yyvsp[(4) - (4)].ea).ea); yyrc = _genea((yyvsp[(4) - (4)].ea)) - 1; ;} + break; + + case 30: +#line 147 "m68k_parse.y" + { _genop(0x4e68 | (yyvsp[(4) - (4)].reg)); yyrc = -1; ;} + break; + + case 31: +#line 148 "m68k_parse.y" + { _genop(0x4e60 | (yyvsp[(2) - (4)].reg)); yyrc = -1; ;} + break; + + case 32: +#line 149 "m68k_parse.y" + { _genop(0x0040 | ((yyvsp[(2) - (5)].wl)<<12) | ((yyvsp[(5) - (5)].reg)<<9) | (yyvsp[(3) - (5)].ea).ea); yyrc = _genea((yyvsp[(3) - (5)].ea)) - 1; ;} + break; + + case 33: +#line 150 "m68k_parse.y" + { _genop(0x4880 | ((yyvsp[(2) - (5)].wl)<<6) | (yyvsp[(5) - (5)].ea).ea); _genop(((yyvsp[(5) - (5)].ea).ea&070)==040 ? (yyvsp[(3) - (5)].mask).d : (yyvsp[(3) - (5)].mask).x); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 3; ;} + break; + + case 34: +#line 151 "m68k_parse.y" + { _genop(0x4c80 | ((yyvsp[(2) - (5)].wl)<<6) | (yyvsp[(3) - (5)].ea).ea); _genop((yyvsp[(5) - (5)].mask).x); yyrc = _genea((yyvsp[(3) - (5)].ea)) - 3; ;} + break; + + case 35: +#line 152 "m68k_parse.y" + { _genop(0x0108 | ((yyvsp[(3) - (5)].reg)<<9) | ((yyvsp[(2) - (5)].wl)<<6) | ((yyvsp[(5) - (5)].ea).ea & 7)); yyrc = _genea((yyvsp[(5) - (5)].ea)) - 1; ;} + break; + + case 36: +#line 153 "m68k_parse.y" + { _genop(0x0188 | ((yyvsp[(5) - (5)].reg)<<9) | ((yyvsp[(2) - (5)].wl)<<6) | ((yyvsp[(3) - (5)].ea).ea & 7)); yyrc = _genea((yyvsp[(3) - (5)].ea)) - 1; ;} + break; + + case 37: +#line 154 "m68k_parse.y" + { _genop(0x7000 | ((yyvsp[(5) - (5)].reg)<<9) | ((yyvsp[(3) - (5)].num)&0xff)); yyrc = -1; ;} + break; + + case 38: +#line 155 "m68k_parse.y" + { _genop(0x4e72); yyrc = _genop((yyvsp[(3) - (3)].num)&0xffff) - 1; ;} + break; + + case 39: +#line 156 "m68k_parse.y" + { _genop((yyvsp[(1) - (5)].opc) | ((yyvsp[(5) - (5)].reg)<<9) | ((yyvsp[(2) - (5)].wl)<<8) | (yyvsp[(3) - (5)].ea).ea); yyrc = _genea((yyvsp[(3) - (5)].ea)) - 1; ;} + break; + + case 40: +#line 157 "m68k_parse.y" + { _genop(0x4840 | (yyvsp[(2) - (2)].reg)); yyrc = -1; ;} + break; + + case 41: +#line 158 "m68k_parse.y" + { _genop(0x4e40 | ((yyvsp[(3) - (3)].num) & 0x0f)); yyrc = -1; ;} + break; + + case 42: +#line 159 "m68k_parse.y" + { _genop(0x4e58 | (yyvsp[(2) - (2)].reg)); yyrc = -1; ;} + break; + + case 43: +#line 163 "m68k_parse.y" + { (yyval.opc) = 0xd0c0; ;} + break; + + case 44: +#line 164 "m68k_parse.y" + { (yyval.opc) = 0x90c0; ;} + break; + + case 45: +#line 167 "m68k_parse.y" + { (yyval.opc) = 0xc100; ;} + break; + + case 46: +#line 168 "m68k_parse.y" + { (yyval.opc) = 0xd100 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 47: +#line 169 "m68k_parse.y" + { (yyval.opc) = 0x8100; ;} + break; + + case 48: +#line 170 "m68k_parse.y" + { (yyval.opc) = 0x9100 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 49: +#line 174 "m68k_parse.y" + { (yyval.opc) = 0xd000 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 50: +#line 175 "m68k_parse.y" + { (yyval.opc) = 0xc000 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 51: +#line 176 "m68k_parse.y" + { (yyval.opc) = 0x8000 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 52: +#line 177 "m68k_parse.y" + { (yyval.opc) = 0x9000 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 53: +#line 181 "m68k_parse.y" + { (yyval.opc) = 0x0600 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 54: +#line 182 "m68k_parse.y" + { (yyval.opc) = 0x0c00 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 55: +#line 183 "m68k_parse.y" + { (yyval.opc) = 0x0400 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 56: +#line 187 "m68k_parse.y" + { (yyval.opc) = 0x0200 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 57: +#line 188 "m68k_parse.y" + { (yyval.opc) = 0x0a00 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 58: +#line 189 "m68k_parse.y" + { (yyval.opc) = 0x0000 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 59: +#line 193 "m68k_parse.y" + { (yyval.opc) = 0x5000 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 60: +#line 194 "m68k_parse.y" + { (yyval.opc) = 0x5100 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 61: +#line 198 "m68k_parse.y" + { (yyval.rea).reg = 0xe1c0 | (yyvsp[(2) - (2)].ea).ea; (yyval.rea).ea = (yyvsp[(2) - (2)].ea); ;} + break; + + case 62: +#line 199 "m68k_parse.y" + { (yyval.rea).reg = 0xe100 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].opc); ;} + break; + + case 63: +#line 200 "m68k_parse.y" + { (yyval.rea).reg = 0xe0c0 | (yyvsp[(2) - (2)].ea).ea; (yyval.rea).ea = (yyvsp[(2) - (2)].ea); ;} + break; + + case 64: +#line 201 "m68k_parse.y" + { (yyval.rea).reg = 0xe000 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].opc); ;} + break; + + case 65: +#line 202 "m68k_parse.y" + { (yyval.rea).reg = 0xe3c0 | (yyvsp[(2) - (2)].ea).ea; (yyval.rea).ea = (yyvsp[(2) - (2)].ea); ;} + break; + + case 66: +#line 203 "m68k_parse.y" + { (yyval.rea).reg = 0xe108 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].opc); ;} + break; + + case 67: +#line 204 "m68k_parse.y" + { (yyval.rea).reg = 0xe2c0 | (yyvsp[(2) - (2)].ea).ea; (yyval.rea).ea = (yyvsp[(2) - (2)].ea); ;} + break; + + case 68: +#line 205 "m68k_parse.y" + { (yyval.rea).reg = 0xe008 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].opc); ;} + break; + + case 69: +#line 206 "m68k_parse.y" + { (yyval.rea).reg = 0xe7c0 | (yyvsp[(2) - (2)].ea).ea; (yyval.rea).ea = (yyvsp[(2) - (2)].ea); ;} + break; + + case 70: +#line 207 "m68k_parse.y" + { (yyval.rea).reg = 0xe118 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].opc); ;} + break; + + case 71: +#line 208 "m68k_parse.y" + { (yyval.rea).reg = 0xe6c0 | (yyvsp[(2) - (2)].ea).ea; (yyval.rea).ea = (yyvsp[(2) - (2)].ea); ;} + break; + + case 72: +#line 209 "m68k_parse.y" + { (yyval.rea).reg = 0xe018 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].opc); ;} + break; + + case 73: +#line 210 "m68k_parse.y" + { (yyval.rea).reg = 0xe5c0 | (yyvsp[(2) - (2)].ea).ea; (yyval.rea).ea = (yyvsp[(2) - (2)].ea); ;} + break; + + case 74: +#line 211 "m68k_parse.y" + { (yyval.rea).reg = 0xe100 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].opc); ;} + break; + + case 75: +#line 212 "m68k_parse.y" + { (yyval.rea).reg = 0xe4c0 | (yyvsp[(2) - (2)].ea).ea; (yyval.rea).ea = (yyvsp[(2) - (2)].ea); ;} + break; + + case 76: +#line 213 "m68k_parse.y" + { (yyval.rea).reg = 0xe000 | ((yyvsp[(2) - (3)].wl)<<6) | (yyvsp[(3) - (3)].opc); ;} + break; + + case 77: +#line 217 "m68k_parse.y" + { (yyval.brop).opc = 0x6400; (yyval.brop).len = 1; ;} + break; + + case 78: +#line 218 "m68k_parse.y" + { (yyval.brop).opc = 0x6500; (yyval.brop).len = 1; ;} + break; + + case 79: +#line 219 "m68k_parse.y" + { (yyval.brop).opc = 0x6700; (yyval.brop).len = 1; ;} + break; + + case 80: +#line 220 "m68k_parse.y" + { (yyval.brop).opc = 0x6c00; (yyval.brop).len = 1; ;} + break; + + case 81: +#line 221 "m68k_parse.y" + { (yyval.brop).opc = 0x6e00; (yyval.brop).len = 1; ;} + break; + + case 82: +#line 222 "m68k_parse.y" + { (yyval.brop).opc = 0x6200; (yyval.brop).len = 1; ;} + break; + + case 83: +#line 223 "m68k_parse.y" + { (yyval.brop).opc = 0x6f00; (yyval.brop).len = 1; ;} + break; + + case 84: +#line 224 "m68k_parse.y" + { (yyval.brop).opc = 0x6300; (yyval.brop).len = 1; ;} + break; + + case 85: +#line 225 "m68k_parse.y" + { (yyval.brop).opc = 0x6d00; (yyval.brop).len = 1; ;} + break; + + case 86: +#line 226 "m68k_parse.y" + { (yyval.brop).opc = 0x6b00; (yyval.brop).len = 1; ;} + break; + + case 87: +#line 227 "m68k_parse.y" + { (yyval.brop).opc = 0x6600; (yyval.brop).len = 1; ;} + break; + + case 88: +#line 228 "m68k_parse.y" + { (yyval.brop).opc = 0x6a00; (yyval.brop).len = 1; ;} + break; + + case 89: +#line 229 "m68k_parse.y" + { (yyval.brop).opc = 0x6800; (yyval.brop).len = 1; ;} + break; + + case 90: +#line 230 "m68k_parse.y" + { (yyval.brop).opc = 0x6900; (yyval.brop).len = 1; ;} + break; + + case 91: +#line 231 "m68k_parse.y" + { (yyval.brop).opc = 0x6100; (yyval.brop).len = 1; ;} + break; + + case 92: +#line 232 "m68k_parse.y" + { (yyval.brop).opc = 0x6000; (yyval.brop).len = 1; ;} + break; + + case 93: +#line 233 "m68k_parse.y" + { (yyval.brop).opc = 0x6400; (yyval.brop).len = 0; ;} + break; + + case 94: +#line 234 "m68k_parse.y" + { (yyval.brop).opc = 0x6500; (yyval.brop).len = 0; ;} + break; + + case 95: +#line 235 "m68k_parse.y" + { (yyval.brop).opc = 0x6700; (yyval.brop).len = 0; ;} + break; + + case 96: +#line 236 "m68k_parse.y" + { (yyval.brop).opc = 0x6c00; (yyval.brop).len = 0; ;} + break; + + case 97: +#line 237 "m68k_parse.y" + { (yyval.brop).opc = 0x6e00; (yyval.brop).len = 0; ;} + break; + + case 98: +#line 238 "m68k_parse.y" + { (yyval.brop).opc = 0x6200; (yyval.brop).len = 0; ;} + break; + + case 99: +#line 239 "m68k_parse.y" + { (yyval.brop).opc = 0x6f00; (yyval.brop).len = 0; ;} + break; + + case 100: +#line 240 "m68k_parse.y" + { (yyval.brop).opc = 0x6300; (yyval.brop).len = 0; ;} + break; + + case 101: +#line 241 "m68k_parse.y" + { (yyval.brop).opc = 0x6d00; (yyval.brop).len = 0; ;} + break; + + case 102: +#line 242 "m68k_parse.y" + { (yyval.brop).opc = 0x6b00; (yyval.brop).len = 0; ;} + break; + + case 103: +#line 243 "m68k_parse.y" + { (yyval.brop).opc = 0x6600; (yyval.brop).len = 0; ;} + break; + + case 104: +#line 244 "m68k_parse.y" + { (yyval.brop).opc = 0x6a00; (yyval.brop).len = 0; ;} + break; + + case 105: +#line 245 "m68k_parse.y" + { (yyval.brop).opc = 0x6800; (yyval.brop).len = 0; ;} + break; + + case 106: +#line 246 "m68k_parse.y" + { (yyval.brop).opc = 0x6900; (yyval.brop).len = 0; ;} + break; + + case 107: +#line 247 "m68k_parse.y" + { (yyval.brop).opc = 0x6100; (yyval.brop).len = 0; ;} + break; + + case 108: +#line 248 "m68k_parse.y" + { (yyval.brop).opc = 0x6000; (yyval.brop).len = 0; ;} + break; + + case 109: +#line 252 "m68k_parse.y" + { (yyval.opc) = 0x0040; ;} + break; + + case 110: +#line 253 "m68k_parse.y" + { (yyval.opc) = 0x0080; ;} + break; + + case 111: +#line 254 "m68k_parse.y" + { (yyval.opc) = 0x00c0; ;} + break; + + case 112: +#line 255 "m68k_parse.y" + { (yyval.opc) = 0x0000; ;} + break; + + case 113: +#line 259 "m68k_parse.y" + { (yyval.opc) = 0x4200 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 114: +#line 260 "m68k_parse.y" + { (yyval.opc) = 0x4800; ;} + break; + + case 115: +#line 261 "m68k_parse.y" + { (yyval.opc) = 0x4400 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 116: +#line 262 "m68k_parse.y" + { (yyval.opc) = 0x4000 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 117: +#line 263 "m68k_parse.y" + { (yyval.opc) = 0x4600 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 118: +#line 264 "m68k_parse.y" + { (yyval.opc) = 0x54c0; ;} + break; + + case 119: +#line 265 "m68k_parse.y" + { (yyval.opc) = 0x55c0; ;} + break; + + case 120: +#line 266 "m68k_parse.y" + { (yyval.opc) = 0x57c0; ;} + break; + + case 121: +#line 267 "m68k_parse.y" + { (yyval.opc) = 0x51c0; ;} + break; + + case 122: +#line 268 "m68k_parse.y" + { (yyval.opc) = 0x5cc0; ;} + break; + + case 123: +#line 269 "m68k_parse.y" + { (yyval.opc) = 0x5ec0; ;} + break; + + case 124: +#line 270 "m68k_parse.y" + { (yyval.opc) = 0x52c0; ;} + break; + + case 125: +#line 271 "m68k_parse.y" + { (yyval.opc) = 0x5fc0; ;} + break; + + case 126: +#line 272 "m68k_parse.y" + { (yyval.opc) = 0x53c0; ;} + break; + + case 127: +#line 273 "m68k_parse.y" + { (yyval.opc) = 0x5dc0; ;} + break; + + case 128: +#line 274 "m68k_parse.y" + { (yyval.opc) = 0x5bc0; ;} + break; + + case 129: +#line 275 "m68k_parse.y" + { (yyval.opc) = 0x56c0; ;} + break; + + case 130: +#line 276 "m68k_parse.y" + { (yyval.opc) = 0x5ac0; ;} + break; + + case 131: +#line 277 "m68k_parse.y" + { (yyval.opc) = 0x50c0; ;} + break; + + case 132: +#line 278 "m68k_parse.y" + { (yyval.opc) = 0x58c0; ;} + break; + + case 133: +#line 279 "m68k_parse.y" + { (yyval.opc) = 0x59c0; ;} + break; + + case 134: +#line 280 "m68k_parse.y" + { (yyval.opc) = 0x4ac0; ;} + break; + + case 135: +#line 281 "m68k_parse.y" + { (yyval.opc) = 0x4a00 | ((yyvsp[(2) - (2)].wl)<<6); ;} + break; + + case 136: +#line 285 "m68k_parse.y" + { (yyval.opc) = 0x81c0; ;} + break; + + case 137: +#line 286 "m68k_parse.y" + { (yyval.opc) = 0x80c0; ;} + break; + + case 138: +#line 287 "m68k_parse.y" + { (yyval.opc) = 0xc1c0; ;} + break; + + case 139: +#line 288 "m68k_parse.y" + { (yyval.opc) = 0xc0c0; ;} + break; + + case 140: +#line 292 "m68k_parse.y" + { (yyval.opc) = 0x54c8; ;} + break; + + case 141: +#line 293 "m68k_parse.y" + { (yyval.opc) = 0x55c8; ;} + break; + + case 142: +#line 294 "m68k_parse.y" + { (yyval.opc) = 0x57c8; ;} + break; + + case 143: +#line 295 "m68k_parse.y" + { (yyval.opc) = 0x5cc8; ;} + break; + + case 144: +#line 296 "m68k_parse.y" + { (yyval.opc) = 0x5ec8; ;} + break; + + case 145: +#line 297 "m68k_parse.y" + { (yyval.opc) = 0x52c8; ;} + break; + + case 146: +#line 298 "m68k_parse.y" + { (yyval.opc) = 0x5fc8; ;} + break; + + case 147: +#line 299 "m68k_parse.y" + { (yyval.opc) = 0x53c8; ;} + break; + + case 148: +#line 300 "m68k_parse.y" + { (yyval.opc) = 0x5dc8; ;} + break; + + case 149: +#line 301 "m68k_parse.y" + { (yyval.opc) = 0x5bc8; ;} + break; + + case 150: +#line 302 "m68k_parse.y" + { (yyval.opc) = 0x56c8; ;} + break; + + case 151: +#line 303 "m68k_parse.y" + { (yyval.opc) = 0x5ac8; ;} + break; + + case 152: +#line 304 "m68k_parse.y" + { (yyval.opc) = 0x58c8; ;} + break; + + case 153: +#line 305 "m68k_parse.y" + { (yyval.opc) = 0x59c8; ;} + break; + + case 154: +#line 306 "m68k_parse.y" + { (yyval.opc) = 0x51c8; ;} + break; + + case 155: +#line 307 "m68k_parse.y" + { (yyval.opc) = 0x50c8; ;} + break; + + case 156: +#line 311 "m68k_parse.y" + { (yyval.opc) = 0x4afc; ;} + break; + + case 157: +#line 312 "m68k_parse.y" + { (yyval.opc) = 0x4e71; ;} + break; + + case 158: +#line 313 "m68k_parse.y" + { (yyval.opc) = 0x4e70; ;} + break; + + case 159: +#line 314 "m68k_parse.y" + { (yyval.opc) = 0x4e73; ;} + break; + + case 160: +#line 315 "m68k_parse.y" + { (yyval.opc) = 0x4e77; ;} + break; + + case 161: +#line 316 "m68k_parse.y" + { (yyval.opc) = 0x4e75; ;} + break; + + case 162: +#line 317 "m68k_parse.y" + { (yyval.opc) = 0x4e76; ;} + break; + + case 163: +#line 321 "m68k_parse.y" + { (yyval.opc) = 0x4ec0; ;} + break; + + case 164: +#line 322 "m68k_parse.y" + { (yyval.opc) = 0x4e80; ;} + break; + + case 165: +#line 323 "m68k_parse.y" + { (yyval.opc) = 0x4840; ;} + break; + + case 166: +#line 326 "m68k_parse.y" + { (yyval.opc) = ((yyvsp[(1) - (3)].reg)<<9) | 0x20 | (yyvsp[(3) - (3)].reg); ;} + break; + + case 167: +#line 327 "m68k_parse.y" + { (yyval.opc) = (((yyvsp[(2) - (4)].num) & 7)<<9) | (yyvsp[(4) - (4)].reg); ;} + break; + + case 168: +#line 330 "m68k_parse.y" + { (yyval.opc) = (((yyvsp[(1) - (3)].ea).ea & 7) << 9) | ((yyvsp[(3) - (3)].ea).ea & 7); ;} + break; + + case 169: +#line 331 "m68k_parse.y" + { (yyval.opc) = (((yyvsp[(1) - (3)].ea).ea & 7) << 9) | 0x0008 | ((yyvsp[(3) - (3)].ea).ea & 7); ;} + break; + + case 170: +#line 334 "m68k_parse.y" + { if (((yyvsp[(3) - (3)].ea).ea & 070)==0) { /* dx,dy must be swapped */ + (yyval.rea).reg = ((yyvsp[(3) - (3)].ea).ea & 7)<<9; (yyvsp[(3) - (3)].ea).ea = (yyvsp[(1) - (3)].reg) & 7; (yyval.rea).ea = (yyvsp[(3) - (3)].ea); } + else { (yyval.rea).reg = ((yyvsp[(1) - (3)].reg)<<9) | 0x100; (yyval.rea).ea = (yyvsp[(3) - (3)].ea); } ;} + break; + + case 171: +#line 337 "m68k_parse.y" + { (yyval.rea).reg = ((yyvsp[(3) - (3)].reg)<<9); (yyval.rea).ea = (yyvsp[(1) - (3)].ea); ;} + break; + + case 172: +#line 340 "m68k_parse.y" + { (yyval.reg)=0; ;} + break; + + case 173: +#line 341 "m68k_parse.y" + { (yyval.reg)=1; ;} + break; + + case 174: +#line 342 "m68k_parse.y" + { (yyval.reg)=2; ;} + break; + + case 175: +#line 343 "m68k_parse.y" + { (yyval.reg)=3; ;} + break; + + case 176: +#line 344 "m68k_parse.y" + { (yyval.reg)=4; ;} + break; + + case 177: +#line 345 "m68k_parse.y" + { (yyval.reg)=5; ;} + break; + + case 178: +#line 346 "m68k_parse.y" + { (yyval.reg)=6; ;} + break; + + case 179: +#line 347 "m68k_parse.y" + { (yyval.reg)=7; ;} + break; + + case 180: +#line 350 "m68k_parse.y" + { (yyval.reg)=0; ;} + break; + + case 181: +#line 351 "m68k_parse.y" + { (yyval.reg)=1; ;} + break; + + case 182: +#line 352 "m68k_parse.y" + { (yyval.reg)=2; ;} + break; + + case 183: +#line 353 "m68k_parse.y" + { (yyval.reg)=3; ;} + break; + + case 184: +#line 354 "m68k_parse.y" + { (yyval.reg)=4; ;} + break; + + case 185: +#line 355 "m68k_parse.y" + { (yyval.reg)=5; ;} + break; + + case 186: +#line 356 "m68k_parse.y" + { (yyval.reg)=6; ;} + break; + + case 187: +#line 357 "m68k_parse.y" + { (yyval.reg)=7; ;} + break; + + case 188: +#line 360 "m68k_parse.y" + { (yyval.wl) = 1; oplen = 0; ;} + break; + + case 189: +#line 363 "m68k_parse.y" + { (yyval.wl) = 0; oplen = 1; ;} + break; + + case 190: +#line 364 "m68k_parse.y" + { (yyval.wl) = 1; oplen = 2; ;} + break; + + case 191: +#line 367 "m68k_parse.y" + { (yyval.wl) = 0; oplen = 0; ;} + break; + + case 192: +#line 368 "m68k_parse.y" + { (yyval.wl) = 1; oplen = 1; ;} + break; + + case 193: +#line 369 "m68k_parse.y" + { (yyval.wl) = 2; oplen = 2; ;} + break; + + case 194: +#line 372 "m68k_parse.y" + { (yyval.wl) = 1; oplen = 0; ;} + break; + + case 195: +#line 373 "m68k_parse.y" + { (yyval.wl) = 3; oplen = 1; ;} + break; + + case 196: +#line 374 "m68k_parse.y" + { (yyval.wl) = 2; oplen = 2; ;} + break; + + case 197: +#line 377 "m68k_parse.y" + { (yyval.wl) = 3; oplen = 1; ;} + break; + + case 198: +#line 378 "m68k_parse.y" + { (yyval.wl) = 2; oplen = 2; ;} + break; + + case 199: +#line 381 "m68k_parse.y" + { (yyval.mask) = (yyvsp[(1) - (1)].mask); ;} + break; + + case 200: +#line 382 "m68k_parse.y" + { (yyval.mask).x = (yyvsp[(1) - (3)].mask).x | (yyvsp[(3) - (3)].mask).x; (yyval.mask).d = (yyvsp[(1) - (3)].mask).d | (yyvsp[(3) - (3)].mask).d; ;} + break; + + case 201: +#line 385 "m68k_parse.y" + { (yyval.mask).x = movemx[(yyvsp[(1) - (1)].reg)]; (yyval.mask).d = movemd[(yyvsp[(1) - (1)].reg)]; ;} + break; + + case 202: +#line 386 "m68k_parse.y" + { (yyval.mask).x = movemx[(yyvsp[(1) - (1)].reg)+8]; (yyval.mask).d = movemd[(yyvsp[(1) - (1)].reg)+8]; ;} + break; + + case 203: +#line 387 "m68k_parse.y" + { int i,l=(yyvsp[(1) - (3)].reg),h=(yyvsp[(3) - (3)].reg); if (l>h) { l=(yyvsp[(3) - (3)].reg); h=(yyvsp[(1) - (3)].reg); } (yyval.mask).x = (yyval.mask).d = 0; + for (i=l; i<=h; i++) { (yyval.mask).d |= movemx[i]; (yyval.mask).d |= movemd[i]; } ;} + break; + + case 204: +#line 389 "m68k_parse.y" + { int i,l=(yyvsp[(1) - (3)].reg),h=(yyvsp[(3) - (3)].reg); if (l>h) { l=(yyvsp[(3) - (3)].reg); h=(yyvsp[(1) - (3)].reg); } (yyval.mask).x = (yyval.mask).d = 0; + for (i=l; i<=h; i++) { (yyval.mask).x |= movemx[i+8]; (yyval.mask).d |= movemd[i+8]; } ;} + break; + + case 260: +#line 404 "m68k_parse.y" + { (yyval.ea).ea = (yyvsp[(1) - (1)].reg); (yyval.ea).cnt = 0; ;} + break; + + case 261: +#line 406 "m68k_parse.y" + { (yyval.ea).ea = 010 | (yyvsp[(1) - (1)].reg); (yyval.ea).cnt = 0; ;} + break; + + case 262: +#line 408 "m68k_parse.y" + { (yyval.ea).ea = 020 | (yyvsp[(2) - (3)].reg); (yyval.ea).cnt = 0; ;} + break; + + case 263: +#line 410 "m68k_parse.y" + { (yyval.ea).ea = 030 | (yyvsp[(2) - (3)].reg); (yyval.ea).cnt = 0; ;} + break; + + case 264: +#line 412 "m68k_parse.y" + { (yyval.ea).ea = 040 | (yyvsp[(2) - (3)].reg); (yyval.ea).cnt = 0; ;} + break; + + case 265: +#line 414 "m68k_parse.y" + { (yyval.ea).ea = 050 | (yyvsp[(4) - (5)].reg); (yyval.ea).cnt = 1; (yyval.ea).arg[0] = (yyvsp[(2) - (5)].num); ;} + break; + + case 266: +#line 417 "m68k_parse.y" + { (yyval.ea).ea = 060 | (yyvsp[(4) - (8)].reg); (yyval.ea).cnt = 1; (yyval.ea).arg[0] = 0x8000 | ((yyvsp[(6) - (8)].reg)<<12) | ((yyvsp[(7) - (8)].wl)<<11) | ((yyvsp[(2) - (8)].num) & 0xff); ;} + break; + + case 267: +#line 419 "m68k_parse.y" + { (yyval.ea).ea = 060 | (yyvsp[(4) - (8)].reg); (yyval.ea).cnt = 1; (yyval.ea).arg[0] = ((yyvsp[(6) - (8)].reg)<<12) | ((yyvsp[(7) - (8)].wl)<<11) | ((yyvsp[(2) - (8)].num) & 0xff); ;} + break; + + case 268: +#line 421 "m68k_parse.y" + { if ((yyvsp[(4) - (4)].wl)==0) { (yyval.ea).ea = 070; (yyval.ea).cnt = 1; (yyval.ea).arg[0] = (yyvsp[(2) - (4)].num); } + else { (yyval.ea).ea = 071; (yyval.ea).cnt = 2; (yyval.ea).arg[0] = (yyvsp[(2) - (4)].num) >> 16; (yyval.ea).arg[1] = (yyvsp[(2) - (4)].num) & 0xffff; } ;} + break; + + case 269: +#line 423 "m68k_parse.y" + { int tmp = ((yyvsp[(2) - (3)].num)>>15) & 0x1ffff; if (tmp==0 || tmp==0x1ffff) { (yyval.ea).ea = 070; (yyval.ea).cnt = 1; (yyval.ea).arg[0] = (yyvsp[(2) - (3)].num); } + else { (yyval.ea).ea = 070; (yyval.ea).cnt = 2; (yyval.ea).arg[0] = (yyvsp[(2) - (3)].num) >> 16; (yyval.ea).arg[1] = (yyvsp[(2) - (3)].num) & 0xffff; } ;} + break; + + case 270: +#line 426 "m68k_parse.y" + { (yyval.ea).ea = 072; (yyval.ea).cnt = 1; (yyval.ea).arg[0] = (yyvsp[(2) - (5)].num); ;} + break; + + case 271: +#line 427 "m68k_parse.y" + { (yyval.ea).ea = 072; (yyval.ea).cnt = 1; (yyval.ea).arg[0] = (yyvsp[(1) - (1)].num); ;} + break; + + case 272: +#line 430 "m68k_parse.y" + { (yyval.ea).ea = 073; (yyval.ea).cnt = 1; (yyval.ea).arg[0] = 0x8000 | ((yyvsp[(6) - (8)].reg)<<12) | ((yyvsp[(7) - (8)].wl)<<11) | ((yyvsp[(2) - (8)].num) & 0xff); ;} + break; + + case 273: +#line 432 "m68k_parse.y" + { (yyval.ea).ea = 073; (yyval.ea).cnt = 1; (yyval.ea).arg[0] = ((yyvsp[(6) - (8)].reg)<<12) | ((yyvsp[(7) - (8)].wl)<<11) | ((yyvsp[(2) - (8)].num) & 0xff); ;} + break; + + case 274: +#line 434 "m68k_parse.y" + { (yyval.ea).ea = 074; if (oplen==0) { (yyval.ea).cnt = 1; (yyval.ea).arg[0] = (yyvsp[(2) - (2)].num) & 0xff; } + else if (oplen==1) { (yyval.ea).cnt = 1; (yyval.ea).arg[0] = (yyvsp[(2) - (2)].num) & 0xffff; } + else { (yyval.ea).cnt = 2; (yyval.ea).arg[0] = (yyvsp[(2) - (2)].num) >> 16; (yyval.ea).arg[1] = (yyvsp[(2) - (2)].num) & 0xffff; } ;} + break; + + case 275: +#line 438 "m68k_parse.y" + { (yyval.ea).ea = 074; (yyval.ea).cnt = 0; ;} + break; + + case 276: +#line 439 "m68k_parse.y" + { (yyval.ea).ea = 074; (yyval.ea).cnt = 1; ;} + break; + + +/* Line 1267 of yacc.c. */ +#line 3344 "m68k_parse.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +#line 440 "m68k_parse.y" + + +static void yyerror(char* s) +{ + /* do not emit anything, but set error flag */ + yyerrc = 1; +} + +struct _optable { + char* mnem; + int token; +}; + +static struct _optable ops[] = { + { "abcd", ABCD }, { "add", ADD }, { "adda", ADDA }, { "addi", ADDI }, + { "addq", ADDQ }, { "addx", ADDX }, { "and", AND }, { "andi", ANDI }, + { "asl", ASL }, { "asr", ASR }, { "bcc", BCC }, { "bcs", BCS }, + { "beq", BEQ }, { "bge", BGE }, { "bgt", BGT }, { "bhi", BHI }, + { "ble", BLE }, { "bls", BLS }, { "blt", BLT }, { "bmi", BMI }, + { "bne", BNE }, { "bpl", BPL }, { "bvc", BVC }, { "bvs", BVS }, + { "bchg", BCHG }, { "bclr", BCLR }, { "bra", BRA }, { "bset", BSET }, + { "bsr", BSR }, { "btst", BTST }, { "chk", CHK }, { "clr", CLR }, + { "cmp", CMP }, { "cmpa", CMPA }, { "cmpi", CMPI }, { "cmpm", CMPM }, + { "dbcc", DBCC }, { "dbcs", DBCS }, { "dbeq", DBEQ }, { "dbf", DBF }, + { "dbge", DBGE }, { "dbgt", DBGT }, { "dbhi", DBHI }, { "dble", DBLE }, + { "dbls", DBLS }, { "dblt", DBLT }, { "dbmi", DBMI }, { "dbne", DBNE }, + { "dbpl", DBPL }, { "dbt", DBT }, { "dbvc", DBVC }, { "dbvs", DBVS }, + { "divs", DIVS }, { "divu", DIVU }, { "eor", EOR }, { "eori", EORI }, + { "exg", EXG }, { "ext", EXT }, { "illegal",ILLEGAL }, { "jmp", JMP }, + { "jsr", JSR }, { "lea", LEA }, { "link", LINK }, { "lsl", LSL }, + { "lsr", LSR }, { "move", MOVE }, { "movea", MOVEA }, { "movem", MOVEM }, + { "movep", MOVEP }, { "moveq", MOVEQ }, { "muls", MULS }, { "mulu", MULU }, + { "nbcd", NBCD }, { "neg", NEG }, { "negx", NEGX }, { "nop", NOP }, + { "not", NOT }, { "or", OR }, { "ori", ORI }, { "pea", PEA }, + { "reset", RESET }, { "rol", ROL }, { "ror", ROR }, { "roxl", ROXL }, + { "roxr", ROXR }, { "rte", RTE }, { "rtr", RTR }, + { "rts", RTS }, { "scc", SCC }, { "scs", SCS }, { "seq", SEQ }, + { "sf", SF }, { "sge", SGE }, { "sgt", SGT }, { "shi", SHI }, + { "sle", SLE }, { "sls", SLS }, { "slt", SLT }, { "smi", SMI }, + { "sne", SNE }, { "spl", SPL }, { "st", ST }, { "svc", SVC }, + { "svs", SVS }, { "stop", STOP }, { "sub", SUB }, { "suba", SUBA }, + { "subi", SUBI }, { "subq", SUBQ }, { "subx", SUBX }, { "swap", SWAP }, + { "tas", TAS }, { "trap", TRAP }, { "trapv", TRAPV }, { "tst", TST }, + { "unlk", UNLK }, { "a0", A0 }, { "a1", A1 }, { "a2", A2 }, + { "a3", A3 }, { "a4", A4 }, { "a5", A5 }, { "a6", A6 }, + { "a7", A7 }, { "d0", D0 }, { "d1", D1 }, { "d2", D2 }, + { "d3", D3 }, { "d4", D4 }, { "d5", D5 }, { "d6", D6 }, + { "d7", D7 }, { "ccr", CCR }, { "sr", SR }, { "usp", USP }, + { "pc", PC }, + { 0, 0 } +}; + +typedef struct _ophash { + struct _ophash* next; + struct _optable* op; +} OPHASH; +#define OPHASHSIZE 97 + +static OPHASH **ophash = 0; + +static int getophash(const char* s) +{ + int h = 0; + while (*s++) h += (int)*s; + return h % OPHASHSIZE; +} + +static int oplookup(const char* s) +{ + int idx = getophash(s); + OPHASH* oph = ophash[idx]; + if (oph) { + if (oph->next) { + while (oph) { + if (!strcmp(s,oph->op->mnem)) return oph->op->token; + oph = oph->next; + } + return 0; + } + return oph->op->token; + } + return 0; +} + +static void init_ophash() +{ + struct _optable* op = ops; + OPHASH* oph; + ophash = (OPHASH**)calloc(sizeof(OPHASH*),OPHASHSIZE); + while (op->mnem) { + int idx = getophash(op->mnem); + oph = (OPHASH*)malloc(sizeof(OPHASH)); + oph->next = ophash[idx]; + oph->op = op; + ophash[idx] = oph; + op++; + } +} + +static char* yystream; + +int yylex() +{ + char ident[30]; + char *p = ident; + char c = yystream[0]; + + while (c != 0 && (c=='\t' || c==' ')) { + c = *++yystream; + } + if (c==0) return EOF; + + if (isalpha(c)) { + while (isalnum(c) && (p-ident)<28) { + *p++ = tolower(c); c = *++yystream; + } + *p = 0; + if (p>ident) { return oplookup(ident); } + return EOF; + } else if (isdigit(c)) { + *p++ = c; + if (yystream[1]=='x' || yystream[1]=='X') { *p++ = 'x'; yystream++; } + c = *++yystream; + while ((isdigit(c) || isxdigit(c)) && (p-ident)<28) { + *p++ = c; c = *++yystream; + } + *p = 0; + yylval.num = strtol(ident,0,0); + return NUMBER; + } else if (c=='$') { + if (isdigit(yystream[1]) || isxdigit(yystream[1])) { + c = *++yystream; + while ((isdigit(c) || isxdigit(c)) && (p-ident)<28) { + *p++ = c; c = *++yystream; + } + *p = 0; + yylval.num = strtol(ident,0,16); + return NUMBER; + } else return '$'; + } else if (c == '-' && yystream[1] == '(') { + yystream += 2; return PREDEC; + } else if (c == ')' && yystream[1] == '+') { + yystream += 2; return POSTINC; + } else if (c == '.') { + switch (yystream[1]) { + case 'b': yystream += 2; return BSIZE; + case 'w': yystream += 2; return WSIZE; + case 'l': yystream += 2; return LSIZE; + case 's': yystream += 2; return SSIZE; + default: yystream++; return '.'; + } + } else { + ++yystream; return c; + } +} + +static t_value *yyvalptr; +static t_addr yyaddr; + +t_stat parse_sym(char* c, t_addr a, UNIT* u, t_value* val, int32 sw) +{ + char ch; + + if (!ophash) init_ophash(); + + yyvalptr = val; + yyaddr = a; + + yystream = c; + yyerrc = 0; + + ch = *yystream; + while (ch != 0 && (ch=='\t' || ch==' ')) { + ch = *++yystream; + } + if (ch == 0) return 0; + + if (sw & SWMASK('Y')) yydebug = 1 - yydebug; + if ((sw & SWMASK('A')) || ch=='\'') { + if ((ch = yystream[1])) { + val[0] = (uint32)ch; + return SCPE_OK; + } else return SCPE_ARG; + } + if ((sw & SWMASK('C')) || ch=='"') { + if ((ch = yystream[1])) { + val[0] = ((uint32)ch << 8) | (uint32)yystream[1]; + return SCPE_OK; + } else return SCPE_ARG; + } + + yyparse(); + printf("rc=%d\n",yyrc); + if (yyerrc) return SCPE_ARG; + return yyrc; +} + +static int _genop(t_value arg) +{ +// printf("_genop(%x)@%x\n",arg,(int)yyvalptr); + *yyvalptr = arg; + yyvalptr++; + return -1; +} + +static int _genea(struct _ea arg) +{ + int i; + for (i=0; i +#include + +#if defined(_WIN32) +#include +#else +#include +#endif + +struct _ea { + int ea; + int cnt; + t_value arg[10]; +}; +struct _rea { + int reg; + struct _ea ea; +}; +struct _mask { + int x; + int d; +}; +struct _brop { + int opc; + int len; +}; + +static int oplen; +static int movemx[] = { 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, + 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080 }; +static int movemd[] = { 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001, + 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100 }; +static int yyrc; +static int yyerrc; +extern int yylex(); +static int _genop(t_value arg); +static int _genea(struct _ea arg); +static int _genbr(t_value arg,t_value,int); +static void yyerror(char* s); + +#define YYDEBUG 1 +%} + +%union { + int rc; + int reg; + int wl; + int opc; + struct _ea ea; + t_value num; + struct _rea rea; + struct _mask mask; + struct _brop brop; +} + +%token A0 A1 A2 A3 A4 A5 A6 A7 D0 D1 D2 D3 D4 D5 D6 D7 +%token CCR SR USP PC +%token NUMBER +%token ABCD ADD ADDA ADDI ADDQ ADDX AND ANDI OR ORI SBCD SUB SUBA SUBI SUBQ SUBX +%token ASL ASR LSL LSR ROL ROR ROXL ROXR +%token BCC BCS BEQ BGE BGT BHI BLE BLS BLT BMI BNE BPL BVC BVS BSR BRA +%token BCLR BSET BCHG BTST CHK CMP CMPA CMPI CMPM EOR EORI EXG EXT +%token DIVU DIVS MULU MULS +%token DBCC DBCS DBEQ DBF DBGE DBGT DBHI DBLE DBLS DBLT DBMI DBNE DBPL DBT DBVC DBVS +%token SCC SCS SEQ SF SGE SGT SHI SLE SLS SLT SMI SNE SPL ST SVC SVS +%token ILLEGAL NOP RESET RTE RTR RTS TRAPV +%token JMP JSR LEA LINK MOVE MOVEA MOVEM MOVEP MOVEQ +%token CLR NEG NEGX NBCD NOT PEA STOP TAS SWAP TRAP TST UNLK + +%token PREDEC POSTINC BSIZE WSIZE LSIZE SSIZE + +%start stmt +%type bcdop bcdarg dualop immop qop immop2 shftarg monop btop +%type mdop dbop jop arop +%type direct +%type brop +%type dualarg shftop +%type dreg areg +%type ea0 ea1 ea2 ea3 ea4 ea5 ea6 ea70 ea72 ea73 ea74 eama eaa eaall eada eadas easr ead eac eacad eacai +%type szwl szbwl szmv szm szs +%type regs reglist + +%% +stmt: + bcdop bcdarg { _genop($1 | $2); yyrc = -1; } +| dualop dualarg { _genop($1 | $2.reg | $2.ea.ea); yyrc = _genea($2.ea) -1; } +| immop '#' NUMBER ',' eada { _genop($1 | $5.ea); if (oplen==0) { _genop($3 & 0xff); yyrc = _genea($5) - 3; } + else if (oplen==1) { _genop($3); yyrc = _genea($5) - 3; } else { _genop($3>>16); _genop($3 & 0xffff); yyrc = _genea($5)-5; } } +| qop '#' NUMBER ',' eaa { _genop($1 | (($3&7)<<9) | $5.ea); yyrc = _genea($5) - 1; } +| immop2 '#' NUMBER ',' eadas { _genop($1 | $5.ea); if (oplen==0) { _genop($3 & 0xff); yyrc = _genea($5) - 3; } + else if (oplen==1) { _genop($3); yyrc = _genea($5) - 3; } else { _genop($3>>16); _genop($3 & 0xffff); yyrc = _genea($5)-5; } } +| shftop { _genop($1.reg); if (($1.reg&0xc0)==0xc0) yyrc = _genea($1.ea) - 1; else { yyrc = -1; } } +| brop NUMBER { yyrc = _genbr($1.opc,$2,$1.len) - 1; } +| btop dreg ',' eada { _genop($1 | ($2<<9) | 0x100 | $4.ea); yyrc = _genea($4) - 1; } +| btop '#' NUMBER ',' eada { _genop($1 | 0x0800 | $5.ea); _genop($3); yyrc = _genea($5) - 3; } +| CHK ead ',' dreg { _genop(0x4180 | ($4<<9) | $2.ea); yyrc = _genea($2) - 1; } +| monop eada { _genop($1 | $2.ea); yyrc = _genea($2) - 1; } +| CMP szbwl eaall ',' dreg { _genop(0xb000 | ($2<<6) | ($5<<9) | $3.ea); yyrc = _genea($3) - 1; } +| mdop ead ',' dreg { _genop($1 | ($4<<9) | $2.ea); yyrc = _genea($2) - 1; } +| CMPA szwl eaall ',' areg { _genop(0xb0c0 | ($2<<8) | ($5<<9) | $3.ea); yyrc = _genea($3) - 1; } +| CMPM szbwl ea3 ',' ea3 { _genop(0xb108 | ($5.ea<<9) | ($2<<6) | $3.ea); yyrc = -1; } +| dbop dreg ',' NUMBER { yyrc = _genbr($1 | $2, $4, 1) - 1; } +| EOR szbwl dreg ',' eada { _genop(0xb000 | ($2 << 6) | 0x100 | $5.ea); yyrc = _genea($5) - 1; } +| EXG dreg ',' dreg { _genop(0xc140 | ($2<<9) | $4); yyrc = -1; } +| EXG areg ',' areg { _genop(0xc148 | ($2<<9) | $4); yyrc = -1; } +| EXG areg ',' dreg { _genop(0xc188 | ($4<<9) | $2); yyrc = -1; } +| EXG dreg ',' areg { _genop(0xc188 | ($2<<9) | $4); yyrc = -1; } +| EXT szwl dreg { _genop(0x4840 | ($2<<6) | $3); yyrc = -1; } +| direct { _genop($1); yyrc = -1; } +| jop eac { _genop($1 | $2.ea); yyrc = _genea($2) -1; } +| LEA eac ',' areg { _genop(0x41c0 | $2.ea); yyrc = _genea($2) - 1; } +| LINK areg ',' '#' NUMBER { _genop(0x4e50 | $2); _genop($5); yyrc = -3; } +| MOVE szmv eaall ',' eadas { if ($5.ea==074) { _genop(0x44c0 | ($5.cnt==1?0x0200:0x0000) | $3.ea); yyrc = _genea($3) - 1; } + else { int tmp = (($5.ea&070)>>3)|(($5.ea&7)<<3); _genop(0x0000 | ($2<<12) | (tmp<<6) | $3.ea); + yyrc = _genea($3) - 1; yyrc += _genea($5); } } +| MOVE SR ',' eada { _genop(0x40c0 | $4.ea); yyrc = _genea($4) - 1; } +| MOVE USP ',' areg { _genop(0x4e68 | $4); yyrc = -1; } +| MOVE areg ',' USP { _genop(0x4e60 | $2); yyrc = -1; } +| MOVEA szm eada ',' areg { _genop(0x0040 | ($2<<12) | ($5<<9) | $3.ea); yyrc = _genea($3) - 1; } +| MOVEM szwl reglist ',' eacad { _genop(0x4880 | ($2<<6) | $5.ea); _genop(($5.ea&070)==040 ? $3.d : $3.x); yyrc = _genea($5) - 3; } +| MOVEM szwl eacai ',' reglist { _genop(0x4c80 | ($2<<6) | $3.ea); _genop($5.x); yyrc = _genea($3) - 3; } +| MOVEP szwl dreg ',' ea5 { _genop(0x0108 | ($3<<9) | ($2<<6) | ($5.ea & 7)); yyrc = _genea($5) - 1; } +| MOVEP szwl ea5 ',' dreg { _genop(0x0188 | ($5<<9) | ($2<<6) | ($3.ea & 7)); yyrc = _genea($3) - 1; } +| MOVEQ '#' NUMBER ',' dreg { _genop(0x7000 | ($5<<9) | ($3&0xff)); yyrc = -1; } +| STOP '#' NUMBER { _genop(0x4e72); yyrc = _genop($3&0xffff) - 1; } +| arop szwl eaall ',' areg { _genop($1 | ($5<<9) | ($2<<8) | $3.ea); yyrc = _genea($3) - 1; } +| SWAP dreg { _genop(0x4840 | $2); yyrc = -1; } +| TRAP '#' NUMBER { _genop(0x4e40 | ($3 & 0x0f)); yyrc = -1; } +| UNLK areg { _genop(0x4e58 | $2); yyrc = -1; } +; + +arop: + ADDA { $$ = 0xd0c0; } +| SUBA { $$ = 0x90c0; }; + +bcdop: + ABCD { $$ = 0xc100; } +| ADDX szbwl { $$ = 0xd100 | ($2<<6); } +| SBCD { $$ = 0x8100; } +| SUBX szbwl { $$ = 0x9100 | ($2<<6); } +; + +dualop: + ADD szbwl { $$ = 0xd000 | ($2<<6); } +| AND szbwl { $$ = 0xc000 | ($2<<6); } +| OR szbwl { $$ = 0x8000 | ($2<<6); } +| SUB szbwl { $$ = 0x9000 | ($2<<6); } +; + +immop: + ADDI szbwl { $$ = 0x0600 | ($2<<6); } +| CMPI szbwl { $$ = 0x0c00 | ($2<<6); } +| SUBI szbwl { $$ = 0x0400 | ($2<<6); } +; + +immop2: + ANDI szbwl { $$ = 0x0200 | ($2<<6); } +| EORI szbwl { $$ = 0x0a00 | ($2<<6); } +| ORI szbwl { $$ = 0x0000 | ($2<<6); } +; + +qop: + ADDQ szbwl { $$ = 0x5000 | ($2<<6); } +| SUBQ szbwl { $$ = 0x5100 | ($2<<6); } +; + +shftop: + ASL eama { $$.reg = 0xe1c0 | $2.ea; $$.ea = $2; } +| ASL szbwl shftarg { $$.reg = 0xe100 | ($2<<6) | $3; } +| ASR eama { $$.reg = 0xe0c0 | $2.ea; $$.ea = $2; } +| ASR szbwl shftarg { $$.reg = 0xe000 | ($2<<6) | $3; } +| LSL eama { $$.reg = 0xe3c0 | $2.ea; $$.ea = $2; } +| LSL szbwl shftarg { $$.reg = 0xe108 | ($2<<6) | $3; } +| LSR eama { $$.reg = 0xe2c0 | $2.ea; $$.ea = $2; } +| LSR szbwl shftarg { $$.reg = 0xe008 | ($2<<6) | $3; } +| ROL eama { $$.reg = 0xe7c0 | $2.ea; $$.ea = $2; } +| ROL szbwl shftarg { $$.reg = 0xe118 | ($2<<6) | $3; } +| ROR eama { $$.reg = 0xe6c0 | $2.ea; $$.ea = $2; } +| ROR szbwl shftarg { $$.reg = 0xe018 | ($2<<6) | $3; } +| ROXL eama { $$.reg = 0xe5c0 | $2.ea; $$.ea = $2; } +| ROXL szbwl shftarg { $$.reg = 0xe100 | ($2<<6) | $3; } +| ROXR eama { $$.reg = 0xe4c0 | $2.ea; $$.ea = $2; } +| ROXR szbwl shftarg { $$.reg = 0xe000 | ($2<<6) | $3; } +; + +brop: + BCC { $$.opc = 0x6400; $$.len = 1; } +| BCS { $$.opc = 0x6500; $$.len = 1; } +| BEQ { $$.opc = 0x6700; $$.len = 1; } +| BGE { $$.opc = 0x6c00; $$.len = 1; } +| BGT { $$.opc = 0x6e00; $$.len = 1; } +| BHI { $$.opc = 0x6200; $$.len = 1; } +| BLE { $$.opc = 0x6f00; $$.len = 1; } +| BLS { $$.opc = 0x6300; $$.len = 1; } +| BLT { $$.opc = 0x6d00; $$.len = 1; } +| BMI { $$.opc = 0x6b00; $$.len = 1; } +| BNE { $$.opc = 0x6600; $$.len = 1; } +| BPL { $$.opc = 0x6a00; $$.len = 1; } +| BVC { $$.opc = 0x6800; $$.len = 1; } +| BVS { $$.opc = 0x6900; $$.len = 1; } +| BSR { $$.opc = 0x6100; $$.len = 1; } +| BRA { $$.opc = 0x6000; $$.len = 1; } +| BCC szs { $$.opc = 0x6400; $$.len = 0; } +| BCS szs { $$.opc = 0x6500; $$.len = 0; } +| BEQ szs { $$.opc = 0x6700; $$.len = 0; } +| BGE szs { $$.opc = 0x6c00; $$.len = 0; } +| BGT szs { $$.opc = 0x6e00; $$.len = 0; } +| BHI szs { $$.opc = 0x6200; $$.len = 0; } +| BLE szs { $$.opc = 0x6f00; $$.len = 0; } +| BLS szs { $$.opc = 0x6300; $$.len = 0; } +| BLT szs { $$.opc = 0x6d00; $$.len = 0; } +| BMI szs { $$.opc = 0x6b00; $$.len = 0; } +| BNE szs { $$.opc = 0x6600; $$.len = 0; } +| BPL szs { $$.opc = 0x6a00; $$.len = 0; } +| BVC szs { $$.opc = 0x6800; $$.len = 0; } +| BVS szs { $$.opc = 0x6900; $$.len = 0; } +| BSR szs { $$.opc = 0x6100; $$.len = 0; } +| BRA szs { $$.opc = 0x6000; $$.len = 0; } +; + +btop: + BCHG { $$ = 0x0040; } +| BCLR { $$ = 0x0080; } +| BSET { $$ = 0x00c0; } +| BTST { $$ = 0x0000; } +; + +monop: + CLR szbwl { $$ = 0x4200 | ($2<<6); } +| NBCD { $$ = 0x4800; } +| NEG szbwl { $$ = 0x4400 | ($2<<6); } +| NEGX szbwl { $$ = 0x4000 | ($2<<6); } +| NOT szbwl { $$ = 0x4600 | ($2<<6); } +| SCC { $$ = 0x54c0; } +| SCS { $$ = 0x55c0; } +| SEQ { $$ = 0x57c0; } +| SF { $$ = 0x51c0; } +| SGE { $$ = 0x5cc0; } +| SGT { $$ = 0x5ec0; } +| SHI { $$ = 0x52c0; } +| SLE { $$ = 0x5fc0; } +| SLS { $$ = 0x53c0; } +| SLT { $$ = 0x5dc0; } +| SMI { $$ = 0x5bc0; } +| SNE { $$ = 0x56c0; } +| SPL { $$ = 0x5ac0; } +| ST { $$ = 0x50c0; } +| SVC { $$ = 0x58c0; } +| SVS { $$ = 0x59c0; } +| TAS { $$ = 0x4ac0; } +| TST szbwl { $$ = 0x4a00 | ($2<<6); } +; + +mdop: + DIVS { $$ = 0x81c0; } +| DIVU { $$ = 0x80c0; } +| MULS { $$ = 0xc1c0; } +| MULU { $$ = 0xc0c0; } +; + +dbop: + DBCC { $$ = 0x54c8; } +| DBCS { $$ = 0x55c8; } +| DBEQ { $$ = 0x57c8; } +| DBGE { $$ = 0x5cc8; } +| DBGT { $$ = 0x5ec8; } +| DBHI { $$ = 0x52c8; } +| DBLE { $$ = 0x5fc8; } +| DBLS { $$ = 0x53c8; } +| DBLT { $$ = 0x5dc8; } +| DBMI { $$ = 0x5bc8; } +| DBNE { $$ = 0x56c8; } +| DBPL { $$ = 0x5ac8; } +| DBVC { $$ = 0x58c8; } +| DBVS { $$ = 0x59c8; } +| DBF { $$ = 0x51c8; } +| DBT { $$ = 0x50c8; } +; + +direct: + ILLEGAL { $$ = 0x4afc; } +| NOP { $$ = 0x4e71; } +| RESET { $$ = 0x4e70; } +| RTE { $$ = 0x4e73; } +| RTR { $$ = 0x4e77; } +| RTS { $$ = 0x4e75; } +| TRAPV { $$ = 0x4e76; } +; + +jop: + JMP { $$ = 0x4ec0; } +| JSR { $$ = 0x4e80; } +| PEA { $$ = 0x4840; }; + +shftarg: + dreg ',' dreg { $$ = ($1<<9) | 0x20 | $3; } +| '#' NUMBER ',' dreg { $$ = (($2 & 7)<<9) | $4; }; + +bcdarg: + ea0 ',' ea0 { $$ = (($1.ea & 7) << 9) | ($3.ea & 7); } +| ea4 ',' ea4 { $$ = (($1.ea & 7) << 9) | 0x0008 | ($3.ea & 7); }; + +dualarg: + dreg ',' eaa { if (($3.ea & 070)==0) { /* dx,dy must be swapped */ + $$.reg = ($3.ea & 7)<<9; $3.ea = $1 & 7; $$.ea = $3; } + else { $$.reg = ($1<<9) | 0x100; $$.ea = $3; } } +| eama ',' dreg { $$.reg = ($3<<9); $$.ea = $1; }; + +areg: + A0 { $$=0; } +| A1 { $$=1; } +| A2 { $$=2; } +| A3 { $$=3; } +| A4 { $$=4; } +| A5 { $$=5; } +| A6 { $$=6; } +| A7 { $$=7; }; + +dreg: + D0 { $$=0; } +| D1 { $$=1; } +| D2 { $$=2; } +| D3 { $$=3; } +| D4 { $$=4; } +| D5 { $$=5; } +| D6 { $$=6; } +| D7 { $$=7; }; + +szs: + SSIZE { $$ = 1; oplen = 0; } + +szwl: + WSIZE { $$ = 0; oplen = 1; } +| LSIZE { $$ = 1; oplen = 2; }; + +szbwl: + BSIZE { $$ = 0; oplen = 0; } +| WSIZE { $$ = 1; oplen = 1; } +| LSIZE { $$ = 2; oplen = 2; }; + +szmv: + BSIZE { $$ = 1; oplen = 0; } +| WSIZE { $$ = 3; oplen = 1; } +| LSIZE { $$ = 2; oplen = 2; }; + +szm: + WSIZE { $$ = 3; oplen = 1; } +| LSIZE { $$ = 2; oplen = 2; }; + +reglist: + regs { $$ = $1; } +| regs '/' reglist { $$.x = $1.x | $3.x; $$.d = $1.d | $3.d; }; + +regs: + areg { $$.x = movemx[$1]; $$.d = movemd[$1]; } +| dreg { $$.x = movemx[$1+8]; $$.d = movemd[$1+8]; } +| areg '-' areg { int i,l=$1,h=$3; if (l>h) { l=$3; h=$1; } $$.x = $$.d = 0; + for (i=l; i<=h; i++) { $$.d |= movemx[i]; $$.d |= movemd[i]; } } +| dreg '-' dreg { int i,l=$1,h=$3; if (l>h) { l=$3; h=$1; } $$.x = $$.d = 0; + for (i=l; i<=h; i++) { $$.x |= movemx[i+8]; $$.d |= movemd[i+8]; } } +; + +eama: ea1 | ea2 | ea3 | ea4 | ea5 | ea6 | ea70 | ea72 | ea73 | ea74; +eaa: ea0 | ea1 | ea2 | ea3 | ea4 | ea5 | ea6 | ea70; +ead: ea0 | ea2 | ea3 | ea4 | ea5 | ea6 | ea70 | ea72 | ea73 | ea74; +eaall: ea0 | eama; +eada: ea0 | ea2 | ea3 | ea4 | ea5 | ea6 | ea70; +eadas: eada | easr; +eac: ea2 | ea5 | ea6 | ea70 | ea72 | ea73; +eacai: ea2 | ea3 | ea5 | ea6 | ea70; +eacad: ea2 | ea4 | ea5 | ea6 | ea70; + +ea0: + dreg { $$.ea = $1; $$.cnt = 0; }; +ea1: + areg { $$.ea = 010 | $1; $$.cnt = 0; }; +ea2: + '(' areg ')' { $$.ea = 020 | $2; $$.cnt = 0; }; +ea3: + '(' areg POSTINC { $$.ea = 030 | $2; $$.cnt = 0; }; +ea4: + PREDEC areg ')' { $$.ea = 040 | $2; $$.cnt = 0; }; +ea5: + '(' NUMBER ',' areg ')' { $$.ea = 050 | $4; $$.cnt = 1; $$.arg[0] = $2; }; +ea6: + '(' NUMBER ',' areg ',' dreg szwl ')' + { $$.ea = 060 | $4; $$.cnt = 1; $$.arg[0] = 0x8000 | ($6<<12) | ($7<<11) | ($2 & 0xff); } +| '(' NUMBER ',' areg ',' areg szwl ')' + { $$.ea = 060 | $4; $$.cnt = 1; $$.arg[0] = ($6<<12) | ($7<<11) | ($2 & 0xff); }; +ea70: + '(' NUMBER ')' szwl { if ($4==0) { $$.ea = 070; $$.cnt = 1; $$.arg[0] = $2; } + else { $$.ea = 071; $$.cnt = 2; $$.arg[0] = $2 >> 16; $$.arg[1] = $2 & 0xffff; } } +| '(' NUMBER ')' { int tmp = ($2>>15) & 0x1ffff; if (tmp==0 || tmp==0x1ffff) { $$.ea = 070; $$.cnt = 1; $$.arg[0] = $2; } + else { $$.ea = 070; $$.cnt = 2; $$.arg[0] = $2 >> 16; $$.arg[1] = $2 & 0xffff; } }; +ea72: + '(' NUMBER ',' PC ')' { $$.ea = 072; $$.cnt = 1; $$.arg[0] = $2; } +| NUMBER { $$.ea = 072; $$.cnt = 1; $$.arg[0] = $1; }; +ea73: + '(' NUMBER ',' PC ',' dreg szwl ')' + { $$.ea = 073; $$.cnt = 1; $$.arg[0] = 0x8000 | ($6<<12) | ($7<<11) | ($2 & 0xff); } +| '(' NUMBER ',' PC ',' areg szwl ')' + { $$.ea = 073; $$.cnt = 1; $$.arg[0] = ($6<<12) | ($7<<11) | ($2 & 0xff); }; +ea74: + '#' NUMBER { $$.ea = 074; if (oplen==0) { $$.cnt = 1; $$.arg[0] = $2 & 0xff; } + else if (oplen==1) { $$.cnt = 1; $$.arg[0] = $2 & 0xffff; } + else { $$.cnt = 2; $$.arg[0] = $2 >> 16; $$.arg[1] = $2 & 0xffff; } }; +easr: + CCR { $$.ea = 074; $$.cnt = 0; } +| SR { $$.ea = 074; $$.cnt = 1; }; +%% + +static void yyerror(char* s) +{ + /* do not emit anything, but set error flag */ + yyerrc = 1; +} + +struct _optable { + char* mnem; + int token; +}; + +static struct _optable ops[] = { + { "abcd", ABCD }, { "add", ADD }, { "adda", ADDA }, { "addi", ADDI }, + { "addq", ADDQ }, { "addx", ADDX }, { "and", AND }, { "andi", ANDI }, + { "asl", ASL }, { "asr", ASR }, { "bcc", BCC }, { "bcs", BCS }, + { "beq", BEQ }, { "bge", BGE }, { "bgt", BGT }, { "bhi", BHI }, + { "ble", BLE }, { "bls", BLS }, { "blt", BLT }, { "bmi", BMI }, + { "bne", BNE }, { "bpl", BPL }, { "bvc", BVC }, { "bvs", BVS }, + { "bchg", BCHG }, { "bclr", BCLR }, { "bra", BRA }, { "bset", BSET }, + { "bsr", BSR }, { "btst", BTST }, { "chk", CHK }, { "clr", CLR }, + { "cmp", CMP }, { "cmpa", CMPA }, { "cmpi", CMPI }, { "cmpm", CMPM }, + { "dbcc", DBCC }, { "dbcs", DBCS }, { "dbeq", DBEQ }, { "dbf", DBF }, + { "dbge", DBGE }, { "dbgt", DBGT }, { "dbhi", DBHI }, { "dble", DBLE }, + { "dbls", DBLS }, { "dblt", DBLT }, { "dbmi", DBMI }, { "dbne", DBNE }, + { "dbpl", DBPL }, { "dbt", DBT }, { "dbvc", DBVC }, { "dbvs", DBVS }, + { "divs", DIVS }, { "divu", DIVU }, { "eor", EOR }, { "eori", EORI }, + { "exg", EXG }, { "ext", EXT }, { "illegal",ILLEGAL }, { "jmp", JMP }, + { "jsr", JSR }, { "lea", LEA }, { "link", LINK }, { "lsl", LSL }, + { "lsr", LSR }, { "move", MOVE }, { "movea", MOVEA }, { "movem", MOVEM }, + { "movep", MOVEP }, { "moveq", MOVEQ }, { "muls", MULS }, { "mulu", MULU }, + { "nbcd", NBCD }, { "neg", NEG }, { "negx", NEGX }, { "nop", NOP }, + { "not", NOT }, { "or", OR }, { "ori", ORI }, { "pea", PEA }, + { "reset", RESET }, { "rol", ROL }, { "ror", ROR }, { "roxl", ROXL }, + { "roxr", ROXR }, { "rte", RTE }, { "rtr", RTR }, + { "rts", RTS }, { "scc", SCC }, { "scs", SCS }, { "seq", SEQ }, + { "sf", SF }, { "sge", SGE }, { "sgt", SGT }, { "shi", SHI }, + { "sle", SLE }, { "sls", SLS }, { "slt", SLT }, { "smi", SMI }, + { "sne", SNE }, { "spl", SPL }, { "st", ST }, { "svc", SVC }, + { "svs", SVS }, { "stop", STOP }, { "sub", SUB }, { "suba", SUBA }, + { "subi", SUBI }, { "subq", SUBQ }, { "subx", SUBX }, { "swap", SWAP }, + { "tas", TAS }, { "trap", TRAP }, { "trapv", TRAPV }, { "tst", TST }, + { "unlk", UNLK }, { "a0", A0 }, { "a1", A1 }, { "a2", A2 }, + { "a3", A3 }, { "a4", A4 }, { "a5", A5 }, { "a6", A6 }, + { "a7", A7 }, { "d0", D0 }, { "d1", D1 }, { "d2", D2 }, + { "d3", D3 }, { "d4", D4 }, { "d5", D5 }, { "d6", D6 }, + { "d7", D7 }, { "ccr", CCR }, { "sr", SR }, { "usp", USP }, + { "pc", PC }, + { 0, 0 } +}; + +typedef struct _ophash { + struct _ophash* next; + struct _optable* op; +} OPHASH; +#define OPHASHSIZE 97 + +static OPHASH **ophash = 0; + +static int getophash(const char* s) +{ + int h = 0; + while (*s++) h += (int)*s; + return h % OPHASHSIZE; +} + +static int oplookup(const char* s) +{ + int idx = getophash(s); + OPHASH* oph = ophash[idx]; + if (oph) { + if (oph->next) { + while (oph) { + if (!strcmp(s,oph->op->mnem)) return oph->op->token; + oph = oph->next; + } + return 0; + } + return oph->op->token; + } + return 0; +} + +static void init_ophash() +{ + struct _optable* op = ops; + OPHASH* oph; + ophash = (OPHASH**)calloc(sizeof(OPHASH*),OPHASHSIZE); + while (op->mnem) { + int idx = getophash(op->mnem); + oph = (OPHASH*)malloc(sizeof(OPHASH)); + oph->next = ophash[idx]; + oph->op = op; + ophash[idx] = oph; + op++; + } +} + +static char* yystream; + +int yylex() +{ + char ident[30]; + char *p = ident; + char c = yystream[0]; + + while (c != 0 && (c=='\t' || c==' ')) { + c = *++yystream; + } + if (c==0) return EOF; + + if (isalpha(c)) { + while (isalnum(c) && (p-ident)<28) { + *p++ = tolower(c); c = *++yystream; + } + *p = 0; + if (p>ident) { return oplookup(ident); } + return EOF; + } else if (isdigit(c)) { + *p++ = c; + if (yystream[1]=='x' || yystream[1]=='X') { *p++ = 'x'; yystream++; } + c = *++yystream; + while ((isdigit(c) || isxdigit(c)) && (p-ident)<28) { + *p++ = c; c = *++yystream; + } + *p = 0; + yylval.num = strtol(ident,0,0); + return NUMBER; + } else if (c=='$') { + if (isdigit(yystream[1]) || isxdigit(yystream[1])) { + c = *++yystream; + while ((isdigit(c) || isxdigit(c)) && (p-ident)<28) { + *p++ = c; c = *++yystream; + } + *p = 0; + yylval.num = strtol(ident,0,16); + return NUMBER; + } else return '$'; + } else if (c == '-' && yystream[1] == '(') { + yystream += 2; return PREDEC; + } else if (c == ')' && yystream[1] == '+') { + yystream += 2; return POSTINC; + } else if (c == '.') { + switch (yystream[1]) { + case 'b': yystream += 2; return BSIZE; + case 'w': yystream += 2; return WSIZE; + case 'l': yystream += 2; return LSIZE; + case 's': yystream += 2; return SSIZE; + default: yystream++; return '.'; + } + } else { + ++yystream; return c; + } +} + +static t_value *yyvalptr; +static t_addr yyaddr; + +t_stat parse_sym(char* c, t_addr a, UNIT* u, t_value* val, int32 sw) +{ + char ch; + + if (!ophash) init_ophash(); + + yyvalptr = val; + yyaddr = a; + + yystream = c; + yyerrc = 0; + + ch = *yystream; + while (ch != 0 && (ch=='\t' || ch==' ')) { + ch = *++yystream; + } + if (ch == 0) return 0; + + if (sw & SWMASK('Y')) yydebug = 1 - yydebug; + if ((sw & SWMASK('A')) || ch=='\'') { + if ((ch = yystream[1])) { + val[0] = (uint32)ch; + return SCPE_OK; + } else return SCPE_ARG; + } + if ((sw & SWMASK('C')) || ch=='"') { + if ((ch = yystream[1])) { + val[0] = ((uint32)ch << 8) | (uint32)yystream[1]; + return SCPE_OK; + } else return SCPE_ARG; + } + + yyparse(); + printf("rc=%d\n",yyrc); + if (yyerrc) return SCPE_ARG; + return yyrc; +} + +static int _genop(t_value arg) +{ +// printf("_genop(%x)@%x\n",arg,(int)yyvalptr); + *yyvalptr = arg; + yyvalptr++; + return -1; +} + +static int _genea(struct _ea arg) +{ + int i; + for (i=0; i + +static t_bool symtrace = TRUE; +static void m68k_sim_init(void); +static t_stat hdump_cmd(int32 arg,char* buf); +static t_stat symset_cmd(int32 arg,char* buf); +static t_stat symclr_cmd(int32 arg,char* buf); +static t_stat symlist_cmd(int32 arg,char* buf); +static t_stat symtrace_cmd(int32 arg,char* buf); + +static CTAB m68k_sim_cmds[] = { + {"STEP", &run_cmd, RU_STEP, + "s{tep} {n} simulate n instructions\n" }, + {"HEXDUMP", &hdump_cmd, 0, + "hex{dump} range dump memory\n" }, + {"SYMSET", &symset_cmd, 0, + "syms{et} name=value define symbolic name for disassembler/tracer\n"}, + {"SYMCLR",&symclr_cmd, 0, + "symc{lr} {-a|name} clear symbolic name / all symbolic names\n"}, + {"SYMLIST", &symlist_cmd, 0, + "syml{ist} [name] list symbol table\n"}, + {"SYMTRACE", &symtrace_cmd, 1, + "symt{race} enable symbolic tracing\n"}, + {"NOSYMTRACE", &symtrace_cmd, 0, + "nosymt{race} disable symbolic tracing\n"}, + {0,0,0,0} +}; + +void (*sim_vm_init)(void) = &m68k_sim_init; + +typedef struct _symhash { + struct _symhash* nnext; + struct _symhash* vnext; + char* name; + t_addr val; +} SYMHASH; +#define SYMHASHSIZE 397 + +static SYMHASH *symbyname = 0; +static SYMHASH *symbyval = 0; + +static void sym_clearall(void) +{ + int i; + SYMHASH *p,*n; + + if (!symbyname) return; + for (i=0; innext; + free(n->name); + free(n); + } + symbyname[i].nnext = symbyval[i].vnext = 0; + } + return; +} + +static void m68k_sim_init(void) +{ + int i; + sim_vm_cmd = m68k_sim_cmds; + + sym_clearall(); + symbyname = (SYMHASH*)calloc(sizeof(SYMHASH),SYMHASHSIZE); + symbyval = (SYMHASH*)calloc(sizeof(SYMHASH),SYMHASHSIZE); + for (i=0; iname)) p = p->nnext; + *n = p; + return p != 0; +} + +static t_bool sym_lookupval(t_addr val, SYMHASH **v) +{ + int hash = getvhash(val); + SYMHASH *p = symbyval[hash].vnext; + while (p && p->val != val) p = p->vnext; + *v = p; + return p != 0; +} + +static t_bool sym_enter(const char* name,t_addr val) +{ + int nhash = getnhash(name); + int vhash = getvhash(val); + SYMHASH *v, *n, *e; + + if (sym_lookupname(name,&n) || sym_lookupval(val,&v)) return FALSE; + n = symbyname[nhash].nnext; + v = symbyval[vhash].vnext; + e = (SYMHASH*)malloc(sizeof(SYMHASH)); + e->nnext = n; + e->vnext = v; + e->name = malloc(strlen(name)+1); + strcpy(e->name,name); + e->val = val; + symbyname[nhash].nnext = symbyval[vhash].vnext = e; + return TRUE; +} + +static t_bool sym_delete(const char* name) +{ + int hash = getnhash(name); + SYMHASH *p, *q, **n, **v; + n = &symbyname[hash].nnext; + while ((p = *n) != 0) { + if (!strcmp(p->name,name)) { /*found*/ + hash = getvhash(p->val); + v = &symbyval[hash].vnext; + while ((q = *v) != 0) { + if (q->val == p->val) { /*found*/ + *v = q->vnext; + break; + } + v = &(q->vnext); + } + *n = p->nnext; + free(p->name); + free(p); + return TRUE; + } + } + return FALSE; +} + +static t_stat symset_cmd(int32 arg,char* buf) +{ + char *name,*vstr; + t_addr val; + + if ((name = strtok(buf, "= ")) == 0) return SCPE_2FARG; + if ((vstr = strtok(NULL, " \t\n")) == 0) return SCPE_2FARG; + val = strtol(vstr, 0, 16); + if (!sym_enter(name, val)) + printf("Name or value already exists\n"); + return SCPE_OK; +} + +static t_stat symclr_cmd(int32 arg,char* buf) +{ + char* token; + if (buf[0] == '-' && buf[1]=='a') { + sym_clearall(); + return SCPE_OK; + } else { + token = strtok(buf," \t\n"); + if (!token) return SCPE_2FARG; + return sym_delete(token) ? SCPE_OK : SCPE_ARG; + } +} + +static t_stat symlist_cmd(int32 arg,char* buf) +{ + int i; + SYMHASH* n; + char *name; + t_bool found = FALSE; + + name = strtok(buf," \t\n"); + if (name) { + if (sym_lookupname(name,&n)) + printf(" %s = 0x%08x\n",n->name,n->val); + else + printf("Unknown\n"); + } else { + for (i=0; iname,n->val); + n = n->nnext; + found = TRUE; + } + } + if (!found) printf("Symbol table is empty\n"); + } + return SCPE_OK; +} + +static t_stat symtrace_cmd(int32 arg,char* buf) +{ + if (!*buf) + symtrace = arg ? TRUE : FALSE; + + printf("Symbolic tracing %sabled\n",symtrace ? "en" : "dis"); + return SCPE_OK; +} + +static void putascii(uint32* buf) +{ + int i; + putchar('|'); + for (i=0; i<16; i++) { + if (isprint(buf[i])) putchar(buf[i]); + else putchar('.'); + } + putchar('|'); +} + +static t_stat hdump_cmd(int32 arg, char* buf) +{ + int i; + t_addr low, high, base, top; + char *token; + uint32 byte[16]; + t_bool ascii = FALSE; + t_bool first = TRUE; + + if (buf[0]=='-' && buf[1]=='a') { + ascii = TRUE; + buf += 2; + while (*buf && isspace(*buf)) buf++; + } + memset(byte,0,sizeof(uint32)*16); + + token = strtok(buf,"- \t\n"); + if (!token) return SCPE_2FARG; + low = strtol(token,0,16); + token = strtok(NULL,"- \t\n"); + if (!token) return SCPE_2FARG; + high = strtol(token,0,16); + + base = low - (low % 16); + top = (high + 15) - ((high+15) % 16); + for (; base high) printf(" "); + else { + i = base %16; + if (ReadPB(base,byte+i) != SCPE_OK) printf("?? "); + else printf("%02x ",byte[i] & 0xff); + } + } + if (!first && ascii) putascii(byte); + putchar('\n'); + return SCPE_OK; +} + +char* m68k_getsym(t_addr val,const char* fmt, char* outbuf) +{ + SYMHASH *v; + if (symtrace && sym_lookupval(val,&v)) + return v->name; + else { + sprintf(outbuf,fmt,val); + return outbuf; + } +} + diff --git a/SAGE/m68k_sys.c b/SAGE/m68k_sys.c new file mode 100644 index 00000000..3f07a829 --- /dev/null +++ b/SAGE/m68k_sys.c @@ -0,0 +1,999 @@ +/* m68k_sys.c: assembler/disassembler/misc simfuncs for generic m68k_cpu + + Copyright (c) 2009, Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version + 15-Mar-10 HV fix 2nd arg bug in disassembling btst + 24-Apr-10 HV fix _fsymea for jsr.l + 27-Apr-10 HV fix stop instr + 27-Jun-10 HV improve error handling in Motorola S0 reader + 20-Jul-10 HV fix disassemble error for LINK +*/ + +#include "m68k_cpu.h" +#include +#include + +#if defined(_WIN32) +#include +#else +#include +#endif + +t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + DEVICE* dptr; + PNP_INFO* pnp; + t_stat rc; + uint16 newbase; + + if (!cptr) return SCPE_ARG; + if (!uptr) return SCPE_IERR; + if (!(dptr = find_dev_from_unit(uptr))) return SCPE_IERR; + if (!(pnp = (PNP_INFO*)dptr->ctxt)) return SCPE_IERR; + + newbase = get_uint (cptr, 16, 0xFF, &rc); + if (rc != SCPE_OK) return rc; + + if (dptr->flags & DEV_DIS) { + printf("Device not enabled yet.\n"); + pnp->io_base = newbase; + } else { + dptr->flags |= DEV_DIS; + dptr->reset(dptr); + pnp->io_base = newbase; + dptr->flags &= ~DEV_DIS; + dptr->reset(dptr); + } + return SCPE_OK; +} + +t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + DEVICE *dptr; + PNP_INFO *pnp; + + if (!uptr) return SCPE_IERR; + if (!(dptr = find_dev_from_unit(uptr))) return SCPE_IERR; + if (!(pnp = (PNP_INFO *) dptr->ctxt)) return SCPE_IERR; + + fprintf(st, "I/O=0x%02X-0x%02X", pnp->io_base, pnp->io_base + pnp->io_size - pnp->io_incr); + return SCPE_OK; +} + +t_stat m68k_set_cpu(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + if (value < 0 || value > CPU_TYPE_68030) + return SCPE_ARG; + + cputype = (value & UNIT_CPUTYPE_MASK) >> UNIT_CPU_V_TYPE; + uptr->flags &= ~UNIT_CPUTYPE_MASK; + uptr->flags |= value; + return SCPE_OK; +} + +t_stat m68k_show_cpu(FILE* st,UNIT *uptr, int32 value, void *desc) +{ + fprintf(st,"TYPE=%s",(char*)desc); + return SCPE_OK; +} + +t_stat m68k_alloc_mem() +{ + if (M == NULL) + M = (uint8*)calloc(MEMORYSIZE, 1); + else + M = (uint8*)realloc(M, MEMORYSIZE); + return M == NULL ? SCPE_MEM : SCPE_OK; +} + +t_stat m68k_set_size(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + t_stat rc; + uptr->capac = value; + if ((rc=m68k_alloc_mem()) != SCPE_OK) return rc; + return SCPE_OK; +} + +t_stat m68k_set_fpu(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + uptr->flags |= value; + return SCPE_OK; +} +t_stat m68k_set_nofpu(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + uptr->flags |= value; + return SCPE_OK; +} + +t_stat m68kcpu_set_flag(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + uptr->flags |= value; + return SCPE_OK; +} + +t_stat m68kcpu_set_noflag(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + uptr->flags &= ~value; + return SCPE_OK; +} + + +t_stat m68kcpu_ex(t_value* eval_array, t_addr addr, UNIT* uptr, int32 sw) +{ + uint32 val = 0; + t_stat rc = (sw & SWMASK('V')) ? ReadVW(addr,&val) : ReadPW(addr,&val); + if (rc==SCPE_OK) *eval_array = val; + return rc; +} + +t_stat m68kcpu_dep(t_value value, t_addr addr, UNIT* uptr, int32 sw) +{ + return (sw & SWMASK('V')) ? WriteVW(addr,value) : WritePW(addr,value); +} + +static int getHex(FILE* fptr,int* chksum) +{ + char buf[3]; + int c; + if ((c = fgetc(fptr))==EOF) return EOF; + buf[0] = c; + if ((c = fgetc(fptr))==EOF) return EOF; + buf[1] = c; + buf[2] = 0; + return strtol(buf,0,16); +} + +/* Motorola S-Record reader + * Format: + * type 2 Bytes (S0, S1, S2, S3, S5, S7, S8, S9) + * reclength 2 Bytes + * address 4,6,8 Bytes + * data 0...2n + * checksum 2 Bytes (lsb of 1'comp of fields reclength-data + */ +static t_stat m68k_sread(FILE* fptr) +{ + int typ; + t_addr addr=0, a; + int d, len, chksum, i; + int end = FALSE; + int line = 0; + + fseek(fptr,0l,SEEK_SET); + for(;;) { + while ((i = fgetc(fptr)) == '\r' || i == '\n'); + line++; + if (end && i == EOF) return SCPE_OK; + if (i != 'S') { printf("Line %d: expected S but did not find one (found %x)\n",line,i); return SCPE_FMT; } + + typ = fgetc(fptr); + chksum = 0; + len = getHex(fptr,&chksum); + addr = getHex(fptr,&chksum); + a = getHex(fptr,&chksum); + if (len==EOF || addr==EOF || a==EOF) { typ = 'X'; goto error; } + addr = (addr << 8) | a; + i = 3; + + switch (typ) { + case '0': + for (i=2; i>9)&7) + '0' +#define OPLEN_FIELD(inst) (inst>>6)&3 +#define EA_FIELD(inst) inst&077 +#define EAMOD_FIELD(inst) inst & 070 +#define BWL_CHAR(oplen) (oplen==0) ? 'b' : ((oplen==1) ? 'w' : 'l') +#define DATA_B(x) (x&0xff) +#define DATA_W(x) (x&0xffff) + +static t_stat _fsymea(FILE* of,t_addr addr,int ea, int oplen,t_value* rest) +{ + int eamod = EAMOD_FIELD(ea); + char eareg = REG0_CHAR(ea); + t_value offb = DATA_B(rest[0]); + t_value offw = DATA_W(rest[0]); + t_value offw2 = DATA_W(rest[1]); + char da = (rest[0] & 0x8000)? 'a' : 'd'; + char xreg = ((rest[0]>>12) & 7) + '0'; + char wl = (rest[0] & 0x800) ? 'l' : 'w'; + + switch (eamod) { + case 000: fprintf(of,"d%c",eareg); return 0; + case 010: fprintf(of,"a%c",eareg); return 0; + case 020: fprintf(of,"(a%c)",eareg); return 0; + case 030: fprintf(of,"(a%c)+",eareg); return 0; + case 040: fprintf(of,"-(a%c)",eareg); return 0; + case 050: fprintf(of,"($%x,a%c)",offw,eareg); return -2; + case 060: + if (offb) + fprintf(of,"($%x,a%c,%c%c.%c)",offb,eareg,da,xreg,wl); + else + fprintf(of,"(a%c,%c%c.%c)",eareg,da,xreg,wl); + return -2; + case 070: + switch (eareg) { + case '0': fprintf(of,"($%x).w",(uint32)((uint16)offw)); return -2; + case '1': + if (offw) + fprintf(of,"($%x%04x).l",offw,offw2); + else + fprintf(of,"($%x).l",offw2); + return -4; + case '2': //fprintf(of,"($%x,pc)",offw); + if (offw & 0x8000) offw |= 0xffff0000; + fprintf(of,"$%x",addr+offw+2); + return -2; + case '3': + if (offb) + fprintf(of,"($%x,pc,%c%c.%c)",offb,da,xreg,wl); + else + fprintf(of,"(pc,%c%c.%c)",da,xreg,wl); + return -2; + case '4': + switch(oplen) { + case 0: fprintf(of,"#$%x",offb); return -2; + case 1: fprintf(of,"#$%x",offw); return -2; + case 2: + if (offw) + fprintf(of,"#$%x%04x",offw,offw2); + else + fprintf(of,"#$%x",offw2); + return -4; + case 3: fprintf(of,"ccr"); return 0; + case 4: fprintf(of,"sr"); return 0; + default: return SCPE_ARG; + } + default: return SCPE_ARG; + } + default: return SCPE_ARG; + } +} + +static t_stat _fsymead(FILE* of,int dir,char reg9,t_addr addr,int ea,int oplen,t_value* rest) +{ + int rc; + if (dir) { + fprintf(of,"d%c,",reg9); rc = _fsymea(of,addr,ea,oplen,rest); + } else { + rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); fprintf(of,",d%c",reg9); + } + return rc-1; +} + +static t_stat _fsymimm(FILE* of,int oplen,t_value* rest) +{ + t_value offb = rest[0] & 0xff; + t_value offw = rest[0] & 0xffff; + t_value offw2 = rest[1] & 0xffff; + switch(oplen) { + case 0: fprintf(of,"#$%x",offb); return 1; + case 1: fprintf(of,"#$%x",offw); return 1; + case 2: fprintf(of,"#$%x%04x",offw,offw2); return 2; + default: return SCPE_ARG; + } +} + +static t_stat _fsym0(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + int rc; + int oplen = OPLEN_FIELD(inst); + char bwl = BWL_CHAR(oplen); + char reg9 = REG9_CHAR(inst); + char reg0 = REG0_CHAR(inst); + int bitnum= DATA_B(rest[0]); + int ea = EA_FIELD(inst); + int eamod = EAMOD_FIELD(inst); + char* s = 0; + + switch (inst & 000700) { + case 000400: + if (eamod==010) { + fprintf(of,"movep.w $%x(a%c),d%c",rest[0],reg0,reg9); return -3; + } else s = "btst"; + break; + case 000500: + if (eamod==010) { + fprintf(of,"movep.l $%x(a%c),d%c",rest[0],reg0,reg9); return -3; + } else s = "bchg"; + break; + case 000600: + if (eamod==010) { + fprintf(of,"movep.w d%c,$%x(a%c)",reg9,rest[0],reg0); return -3; + } else s = "bclr"; + break; + case 000700: + if (eamod==010) { + fprintf(of,"movep.l d%c,$%x(a%c)",reg9,rest[0],reg0); return -3; + } else s = "bset"; + break; + } + if (s) { + fprintf(of,"%s d%c,",s,reg9); rc = _fsymea(of,addr,ea,3,rest); ONERR_QUIT(); return rc-1; + } + + switch (inst & 007000) { + case 000000: + s = "ori"; break; + case 001000: + s = "andi"; break; + case 002000: + s = "subi"; break; + case 003000: + s = "addi"; break; + case 004000: + switch (inst & 000700) { + case 000000: + s = "btst"; break; + case 000100: + s = "bchg"; break; + case 000200: + s = "bclr"; break; + case 000300: + s = "bset"; break; + default: + return SCPE_ARG; + } + fprintf(of,"%s #%x,",s,bitnum); rc = _fsymea(of,addr,ea,0,rest+1); ONERR_QUIT(); return rc-3; + case 005000: + s = "eori"; break; + case 006000: + s = "cmpi"; break; + default: + return SCPE_ARG; + } + + fprintf(of,"%s.%c ",s,bwl); rc = _fsymimm(of,oplen,rest); ONERR_QUIT(); + fputc(',',of); rc = _fsymea(of,addr,ea,oplen+3,rest+rc); + return rc - 3 - ((oplen==2) ? 2 : 0); +} + +static t_stat _fsym123(FILE* of,t_value inst,t_addr addr,t_value* rest,char w,int oplen) +{ + int rc, rc2; + int eas = inst & 077; + int eat = ((inst>>9)&7)|((inst&0700)>>3); + char *s = ((eat&070)==010) ? "movea" : "move"; + fprintf(of,"%s.%c ",s,w); + rc = _fsymea(of,addr,eas,oplen,rest); ONERR_QUIT(); rc2 = rc; + fputc(',',of); + rc = _fsymea(of,addr,eat,oplen,rest-rc2/2); ONERR_QUIT(); + return rc2 + rc -1; +} + +static char* moveregs[] = { + "d0","d1","d2","d3","d4","d5","d6","d7","a0","a1","a2","a3","a4","a5","a6","a7" +}; +static char* moveregsp[] = { + "a7","a6","a5","a4","a3","a2","a1","a0","d7","d6","d5","d4","d3","d2","d1","d0" +}; + +#define BITEMIT() if (sl) fputc('/',of); sl = 1; \ + if (hi==lo) fprintf(of,"%s",regs[lo]); \ + else if (ispredec) fprintf(of,"%s-%s",regs[hi],regs[lo]); \ + else fprintf(of,"%s-%s",regs[lo],regs[hi]); \ + lo = hi = -1; +#define BITSEQ() bit = regset & 1; regset >>= 1; \ + if (bit && lo == -1) lo = i; \ + if (bit == 0 && lo != -1) { hi = i-1; BITEMIT(); } + +static void _fsymregs(FILE* of, int regset,int ispredec) +{ + int lo, hi, bit, sl, i; + char** regs = ispredec ? moveregsp : moveregs; + +//printf("regset=%x\n",regset); + sl = 0; + bit = lo = hi = -1; + for (i=0; i<8; i++) { BITSEQ(); } + if (lo != -1) { hi = 7; BITEMIT(); } + bit = -1; + for (i=8; i<16; i++) { BITSEQ(); } + if (lo != -1) { hi = 15; BITEMIT(); } +} + +static t_stat _fsym4(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + t_stat rc; + char reg9 = REG9_CHAR(inst); + int ea = EA_FIELD(inst); + int eamod = EAMOD_FIELD(inst); + char reg0 = REG0_CHAR(inst); + int oplen = OPLEN_FIELD(inst); + char* s; + + switch (inst & 000700) { + case 000600: + fprintf(of,"chk "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); + fprintf(of,",d%c",reg9); return rc-1; + case 000700: + fprintf(of,"lea "); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); + fprintf(of,",a%c",reg9); return rc-1; + case 000000: + switch (inst & 007000) { + case 000000: + s = "negx.b "; break; + case 001000: + s = "clr.b "; break; + case 002000: + s = "neg.b "; break; + case 003000: + s = "not.b "; break; + case 004000: + s = "nbcd "; break; + case 005000: + s = "tst.b "; break; + default: + return SCPE_ARG; + } + fputs(s,of); rc = _fsymea(of,addr,ea,0,rest); ONERR_QUIT(); return rc-1; + case 000100: + switch (inst & 007000) { + case 007000: + switch (inst & 000070) { + case 000000: + case 000010: + fprintf(of,"trap #$%x",inst & 0xf); return -1; + case 000020: + fprintf(of,"link a%c,#$%x",reg0,rest[0]); return -3; + case 000030: + fprintf(of,"unlk a%c",reg0); return -1; + case 000040: + fprintf(of,"move a%c,usp",reg0); return -1; + case 000050: + fprintf(of,"move usp,a%c",reg0); return -1; + case 000060: + switch (inst & 000007) { + case 000000: + s = "reset"; break; + case 000001: + s = "nop"; break; + case 000002: + fprintf(of,"stop #%x",DATA_W(rest[0])); return -3; + case 000003: + s = "rte"; break; + case 000005: + s = "rts"; break; + case 000006: + s = "trapv"; break; + case 000007: + s = "rtr"; break; + default: + return SCPE_ARG; + } + fputs(s,of); return -1; + default: + return SCPE_ARG; + } + case 000000: + s = "negx.w "; break; + case 001000: + s = "clr.w "; break; + case 002000: + s = "neg.w "; break; + case 003000: + s = "not.w "; break; + case 005000: + s = "tst.w "; break; + case 004000: + if (eamod==0) { + fprintf(of,"swap d%c",reg0); return -1; + } else { + fputs("pea ",of); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); return rc-1; + } + default: + return SCPE_ARG; + } + fputs(s,of); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); return rc-1; + + case 000200: + switch (inst & 007000) { + case 000000: + s = "negx.l "; break; + case 001000: + s = "clr.l "; break; + case 002000: + s = "neg.l "; break; + case 003000: + s = "not.l "; break; + case 004000: + if (eamod==0) { + fprintf(of,"ext.w d%c",reg0); return -1; + } else { + fprintf(of,"movem.w "); _fsymregs(of,rest[0],eamod==040); + fputc(',',of); rc = _fsymea(of,addr,ea,oplen==2?1:2,rest+1); return rc-3; + } + case 005000: + s = "tst.l "; break; + case 006000: + fprintf(of,"movem.w "); rc = _fsymea(of,addr,ea,oplen==2?1:2,rest+1); + fputc(',',of); _fsymregs(of,rest[0],0); return rc-3; + case 007000: + s = "jsr "; break; + default: + return SCPE_ARG; + } + fputs(s,of); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); return rc-1; + + case 000300: + switch (inst & 007000) { + case 000000: + fprintf(of,"move sr,"); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); return rc-1; + case 003000: + fprintf(of,"move "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); fputs(",sr",of); return rc-1; + case 002000: + fprintf(of,"move "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); fputs(",ccr",of); return rc-1; + case 004000: + if (eamod==0) { + fprintf(of,"ext.l d%c",reg0); return -1; + } else { + fprintf(of,"movem.l "); _fsymregs(of,rest[0],eamod==040); + fputc(',',of); rc = _fsymea(of,addr,ea,oplen==2?1:2,rest+1); return rc-3; + } + case 005000: + switch (inst & 000077) { + case 000074: + fputs("illegal",of); return -1; + default: + fprintf(of,"tas "); rc = _fsymea(of,addr,ea,0,rest); return rc-1; + } + case 006000: + fprintf(of,"movem.l "); rc = _fsymea(of,addr,ea,oplen==2?1:2,rest+1); + fputc(',',of); _fsymregs(of,rest[0],0); return rc-3; + case 007000: + fputs("jmp ",of); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); return rc-1; + default: + return SCPE_ARG; + } + default: + return SCPE_ARG; + } +} + +static char* conds[] = { "ra","sr","hi","ls","cc","cs","ne","eq","vc","vs","pl","mi","ge","lt","gt","le" }; +static char* conds2[] = { "t", "f","hi","ls","cc","cs","ne","eq","vc","vs","pl","mi","ge","lt","gt","le" }; + +static t_stat _fsym5(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + t_stat rc; + int ea = EA_FIELD(inst); + int eamod = EAMOD_FIELD(inst); + int reg0 = REG0_CHAR(inst); + int oplen = OPLEN_FIELD(inst); + char bwl = BWL_CHAR(oplen); + t_addr a; + + if (oplen==3) { + char* cond = conds2[(inst>>8)&0xf]; + if (eamod==010) { + a = rest[0] & 0xffff; + if (a & 0x8000) a |= 0xffff0000; + //printf("addr=%x a=%x sum=%x\n",addr,a,addr+a+2); + fprintf(of,"db%s d%c,$%x",cond,reg0,addr+a+2); + return -3; + } else { + fprintf(of,"s%s ",cond); rc = _fsymea(of,addr,ea,0,rest); return rc-3; + } + } else { + int data = (inst>>9) & 07; + char *s = (inst & 0x0100) ? "subq" : "addq"; + + if (data==0) data = 8; + fprintf(of,"%s.%c #%d,",s,bwl,data); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); return rc-1; + } + +} +static t_stat _fsym6(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + char* cond = conds[(inst>>8)&0xf]; + t_addr a = inst & 0xff; + if (a) { + if (a & 0x80) a |= 0xffffff00; + fprintf(of,"b%s.s $%x",cond,addr+a+2); return -1; + } else { + a = rest[0] & 0xffff; + if (a & 0x8000) a |= 0xffff0000; + fprintf(of,"b%s.w $%x",cond,addr+a+2); return -3; + } +} + +static t_stat _fsym7(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + int reg9 = REG9_CHAR(inst); + switch (inst & 000400) { + case 000000: + fprintf(of,"moveq #$%x,d%c",(int32)((int8)(inst&0xff)),reg9); return -1; + default: + return SCPE_ARG; + } +} + +static t_stat _fsym8(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + t_stat rc; + int oplen = OPLEN_FIELD(inst); + int eamod = EAMOD_FIELD(inst); + int ea = EA_FIELD(inst); + char reg9 = REG9_CHAR(inst); + char reg0 = REG0_CHAR(inst); + char bwl = BWL_CHAR(oplen); + + switch (inst & 000700) { + case 000000: + case 000100: + case 000200: + fprintf(of,"or.%c ",bwl); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); + fprintf(of,",d%c",reg9); return rc-1; + case 000300: + fprintf(of,"divu.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); + fprintf(of,",d%c",reg9); return rc-1; + case 000400: + switch (eamod) { + case 000: + fprintf(of,"sbcd d%c,d%c",reg0,reg9); return -1; + case 010: + fprintf(of,"sbcd -(a%c),-(a%c)",reg0,reg9); return -1; + default: + fprintf(of,"or.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); + return rc-1; + } + case 000500: + case 000600: + fprintf(of,"or.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); + return rc-1; + case 000700: + fprintf(of,"divs.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); + fprintf(of,",d%c",reg9); return rc-1; + } + return SCPE_ARG; /* Not reached, but silence agressive compiler warnings */ +} + +static t_stat _fsym9(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + t_stat rc; + int oplen = OPLEN_FIELD(inst); + char reg9 = REG9_CHAR(inst); + char reg0 = REG0_CHAR(inst); + char bwl = BWL_CHAR(oplen); + int ea = EA_FIELD(inst); + int eamod = EAMOD_FIELD(inst); + + switch (inst & 000700) { + case 000000: + case 000100: + case 000200: + fprintf(of,"sub.%c ",bwl); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); + fprintf(of,",d%c",reg9);return rc-1; + case 000300: + fprintf(of,"suba.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); + fprintf(of,",a%c",reg9);return rc-1; + case 000400: + switch (eamod) { + case 000: + fprintf(of,"subx.%c d%c,d%c",bwl,reg9,reg0); return -1; + case 001: + fprintf(of,"subx.%c d%c,d%c",bwl,reg9,reg0); return -1; + default: + fprintf(of,"sub.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); return rc-1; + } + case 000500: + case 000600: + fprintf(of,"sub.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); return rc-1; + case 000700: + fprintf(of,"suba.l "); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); + fprintf(of,",a%c",reg9);return rc-1; + default: + return SCPE_ARG; + } +} + +static t_stat _fsyma(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + fprintf(of,"trapa #$%x",inst&0xfff); return -1; +} + +static t_stat _fsymb(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + int rc; + char reg9 = REG9_CHAR(inst); + char reg0 = REG0_CHAR(inst); + int ea = EA_FIELD(inst); + int eamod = EAMOD_FIELD(inst); + int oplen = OPLEN_FIELD(inst); + char bwl = BWL_CHAR(oplen); + + switch (inst & 000700) { + case 000000: + case 000100: + case 000200: + fprintf(of,"cmp.%c ",bwl); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); + fprintf(of,",d%c",reg9); return rc-1; + case 000300: + fprintf(of,"cmpa.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); + fprintf(of,",a%c",reg9); return rc-1; + case 000400: + case 000500: + case 000600: + if (eamod==010) { + fprintf(of,"cmpm.%c (a%c)+,(a%c)+",bwl,reg0,reg9); return -1; + } else { + fprintf(of,"eor.%c d%c,",bwl,reg9); rc = _fsymea(of,addr,ea,oplen,rest); ONERR_QUIT(); + return rc-1; + } + case 000700: + fprintf(of,"cmpa.l "); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); + fprintf(of,",a%c",reg9); return rc-1; + default: + return SCPE_ARG; + } +} + +static t_stat _fsymc(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + char reg9 = REG9_CHAR(inst); + int ea = EA_FIELD(inst); + int reg0 = REG0_CHAR(inst); + int oplen = OPLEN_FIELD(inst); + char bwl = BWL_CHAR(oplen); + + switch (inst & 0000770) { + case 0000500: + fprintf(of,"exg d%c,d%c",reg9,reg0); return -1; + case 0000510: + fprintf(of,"exg a%c,a%c",reg9,reg0); return -1; + case 0000610: + fprintf(of,"exg d%c,a%c",reg9,reg0); return -1; + case 0000400: + fprintf(of,"abcd d%c,d%c",reg9,reg0); return -1; + case 0000410: + fprintf(of,"abcd -(a%c),-(a%c)",reg9,reg0); return -1; + default: + break; + } + + switch (inst & 0000700) { + case 0000400: + fprintf(of,"and.%c ",bwl); return _fsymead(of,1,reg9,addr,ea,oplen,rest); + case 0000000: + case 0000100: + case 0000200: + fprintf(of,"and.%c ",bwl); return _fsymead(of,0,reg9,addr,ea,oplen,rest); + case 0000300: + fprintf(of,"mulu.w "); return _fsymead(of,0,reg9,addr,ea,1,rest); + case 0000700: + fprintf(of,"muls.w "); return _fsymead(of,0,reg9,addr,ea,1,rest); + default: + return SCPE_ARG; + } +} + +static t_stat _fsymd(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + int rc; + char reg9 = REG9_CHAR(inst); + char reg0 = REG0_CHAR(inst); + int ea = EA_FIELD(inst); + int eamod = EAMOD_FIELD(inst); + int oplen = OPLEN_FIELD(inst); + char bwl = BWL_CHAR(oplen); + + switch (inst & 000700) { + case 000000: + case 000100: + case 000200: + fprintf(of,"add.%c ",bwl); return _fsymead(of,0,reg9,addr,ea,oplen,rest); + case 000300: + fprintf(of,"adda.w "); rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); + fprintf(of,",a%c",reg9); return rc-1; + case 000400: + switch (eamod) { + case 000: + fprintf(of,"addx.%c d%c,d%c",bwl,reg9,reg0); return -1; + case 001: + fprintf(of,"addx.%c d%c,d%c",bwl,reg9,reg0); return -1; + default: + fprintf(of,"add.%c ",bwl); return _fsymead(of,1,reg9,addr,ea,oplen,rest); + } + case 000500: + case 000600: + fprintf(of,"add.%c ",bwl); return _fsymead(of,1,reg9,addr,ea,oplen,rest); + case 000700: + fprintf(of,"adda.l "); rc = _fsymea(of,addr,ea,2,rest); ONERR_QUIT(); + fprintf(of,",a%c",reg9); return rc-1; + } + return SCPE_ARG; /* Not reached, but silence agressive compiler warnings */ +} + +static t_stat _fsyme(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + int rc; + int oplen = OPLEN_FIELD(inst); + char bwl = BWL_CHAR(oplen); + int op = (oplen==3 ? (inst>>9) : (inst>>3)) & 3; + char dir = (inst&0x100) ? 'l' : 'r'; + int ir = inst & 0x20; + int ea = EA_FIELD(inst); + char reg9 = REG9_CHAR(inst); + char reg0 = REG0_CHAR(inst); + char *s; + + switch (op) { + case 0: s = "as"; break; + case 1: s = "ls"; break; + case 2: s = "rox"; break; + case 3: s = "ro"; break; + default: s = "??"; break; + } + fprintf(of,"%s%c",s,dir); + if (oplen<3) { + fprintf(of,".%c ",bwl); + if (ir) + fprintf(of,"d%c,d%c",reg9,reg0); + else { + if (reg9=='0') reg9 = '8'; + fprintf(of,"#%d,d%c",reg9-'0',reg0); + } + return -1; + } else { + fputc(' ',of); + rc = _fsymea(of,addr,ea,1,rest); ONERR_QUIT(); return rc-1; + } +} + +static t_stat _fsymf(FILE* of,t_value inst,t_addr addr,t_value* rest) +{ + fprintf(of,"trapf #$%x",inst&0xfff); return -1; +} + +t_stat fprint_sym(FILE* of, t_addr addr, t_value* val, UNIT* uptr, int32 sw) +{ + int32 c1, c2, inst; + + c1 = (val[0] >> 8) & 0177; + c2 = val[0] & 0177; + if (sw & SWMASK ('A')) { + fprintf (of, (c2 < 040)? "<%02x>": "%c", c2); + return SCPE_OK; + } + if (sw & SWMASK ('C')) { + fprintf (of, (c1 < 040)? "<%02x>": "%c", c1); + fprintf (of, (c2 < 040)? "<%02x>": "%c", c2); + return -1; + } + if (!(sw & SWMASK ('M'))) return SCPE_ARG; + + inst = val[0]; + switch ((inst>>12) & 0xf) { + case 0x0: return _fsym0(of,inst,addr,val+1); + case 0x1: return _fsym123(of,inst,addr,val+1,'b',0); + case 0x2: return _fsym123(of,inst,addr,val+1,'l',2); + case 0x3: return _fsym123(of,inst,addr,val+1,'w',1); + case 0x4: return _fsym4(of,inst,addr,val+1); + case 0x5: return _fsym5(of,inst,addr,val+1); + case 0x6: return _fsym6(of,inst,addr,val+1); + case 0x7: return _fsym7(of,inst,addr,val+1); + case 0x8: return _fsym8(of,inst,addr,val+1); + case 0x9: return _fsym9(of,inst,addr,val+1); + case 0xa: return _fsyma(of,inst,addr,val+1); + case 0xb: return _fsymb(of,inst,addr,val+1); + case 0xc: return _fsymc(of,inst,addr,val+1); + case 0xd: return _fsymd(of,inst,addr,val+1); + case 0xe: return _fsyme(of,inst,addr,val+1); + case 0xf: return _fsymf(of,inst,addr,val+1); + } + return SCPE_OK; +} diff --git a/SAGE/readme-sage.txt b/SAGE/readme-sage.txt new file mode 100644 index 00000000..52eebb3d --- /dev/null +++ b/SAGE/readme-sage.txt @@ -0,0 +1,91 @@ +This is version 0.5 of a simulator for the SAGE-68K computer. See www.sageandstride.org for details. + +This is called Version 0.5 because it still lacks a few things and has a number of known bugs. + +Features and problems +- currently is at the level of a SAGE-II system with two floppy drives +- Currently runs CP/M-68K 1.2 (IMD-Disk included) +- Console and SIO can be redirected to a telnet session +- does not run UCSD-Pascal yet (in progress) +- does not support IEEE-interface yet (and maybe won't ever - not really useful) +- does not support Winchester operation yet, although BIOS ROMs are included +- m68k_cpu.c has a number of not yet implemented instructions (although sufficient for CP/M-68K!) + (implementation in progress) +- does not yet fully support 68010 CPU (in progress, not needed for Sage, though) +- does not implement 68881 FPU (in progress, not needed for Sage, though) +- has stubs for MMU integration, but does not yet implement one - passthrough (in progress, not needed for Sage, though) + +- still contains some timing bug in floppy operation (timing loop, 8253 emulation, IRQ speed) which + results in rather long floppy recognition time (disk change), after that I/O is at acceptable speed +- probably there is still a bug in console/sio telnet handling when the character buffer + is full (no automatic draining, will be investigated) +- no optimization of simulation speed at all, but runs acceptable with current PCs. +- not yet tested under anything else than MINGW + +Holger Veit, March 2011 + + + +$ BIN/sage + +Sage-II/IV 68k simulator V3.8-2 +sim> show dev +Sage-II/IV 68k simulator configuration + +CPU, BIOS=sage-ii.hex +PIC, I/O=0xFFC041-0xFFC043 +TIMER1, I/O=0xFFC001-0xFFC007 +TIMER2, I/O=0xFFC081-0xFFC087 +DIP, I/O=0xFFC021-0xFFC027, GROUPA=11100111, GROUPB=11111000 +FD, I/O=0xFFC051-0xFFC053, 2 units +CONS, I/O=0xFFC071-0xFFC073, 2 units +SIO, I/O=0xFFC031-0xFFC033, 2 units +LP, I/O=0xFFC061-0xFFC067 +sim> quit +Goodbye +Debug output disabled + +$ cp SAGE/FILES/68k.sim . +$ cp SAGE/FILES/cpm68k12.imd . +$ cp SAGE/sage-ii.hex . +$ BIN/sage 68k.sim + +Sage-II/IV 68k simulator V3.8-2 +Debug output to "debug.log" +Loading boot code from sage-ii.hex + +SAGE II Startup Test [1.2] + +RAM Size = 512K + + Booting from Floppy + +SAGE CP/M-68k Bootstrap v2.1 + +SAGE CP/M-68k v1.2 447K TPA + +A>STARTUP + +A>SETENV TERM TVI950 + +A>SETENV PATH |A0: + +A>dir +A: MINCE SWP : MINCE 68K : CPM SYS : SAGEBIOS SYS : PIP 68K +A: STAT 68K : AR68 68K : LO68 68K : AS68 68K : MIND SUB +A: DDT 68K : SAGE4UTL 68K : INIT 68K : DUMP 68K : COPY 68K +A: DDT68000 68K : P SUB : ASGO SUB : PE SUB : AS SUB +A: LNK SUB : M SUB : ARMATH SUB : FIND 68K : RED SUB +A: SCREEN 68K : MCC SUB : LINKCORE SUB : SETPRNTR 68K : AS68SYMB DAT +A: E SUB : REDASM SUB : CORE SUB : PRINT 68K : SETENV 68K +A: STARTUP SUB : HALT 68K : SPACE SUB : SIG TXT : SPACEM SUB +A: ORBIT SUB : TLNK SUB : BRWNIES TXT +A>stat a: + +A: RW, FREE SPACE: 0K +A>^E +Simulation stopped, PC: 0007C8C4 (stop #2000) +sim>quit +Goodbye +Debug output disabled + diff --git a/SAGE/sage_aux.c b/SAGE/sage_aux.c new file mode 100644 index 00000000..c27e21a6 --- /dev/null +++ b/SAGE/sage_aux.c @@ -0,0 +1,62 @@ +/* sage_aux.c: serial device for sage-II system + + Copyright (c) 2009, Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 12-Oct-09 HV Initial version +*/ + +#include "sage_defs.h" + +static t_stat sageaux_reset(DEVICE* dptr); + +UNIT sageaux_unit[] = { + { UDATA (NULL, UNIT_FIX | UNIT_BINK, 0) }, + { UDATA (NULL, UNIT_FIX | UNIT_BINK, 0) }, + { UDATA (NULL, UNIT_FIX | UNIT_BINK, 0) }, + { UDATA (NULL, UNIT_FIX | UNIT_BINK, 0) } +}; + +REG sageaux_reg[] = { + { NULL } +}; + +static MTAB sageaux_mod[] = { + { 0 } +}; + +DEVICE sageaux_dev = { + "AUX", sageaux_unit, sageaux_reg, sageaux_mod, + 4, 16, 32, 2, 16, 16, + NULL, NULL, &sageaux_reset, + NULL, NULL, NULL, + NULL, DEV_DISABLE|DEV_DIS, 0, + NULL, NULL, NULL +}; + +static t_stat sageaux_reset(DEVICE* dptr) +{ + printf("sageaux_reset\n"); + return SCPE_OK; +} + diff --git a/SAGE/sage_cons.c b/SAGE/sage_cons.c new file mode 100644 index 00000000..decb8e0a --- /dev/null +++ b/SAGE/sage_cons.c @@ -0,0 +1,464 @@ +/* sage_sio.c: serial devices for sage-II system + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 12-Oct-09 HV Initial version + 24-Jul-10 HV Added TMXR code to attach CONS and SIO to network +*/ + +#include "sim_defs.h" +#include "sim_timer.h" +#include "sage_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + +#define SIOPOLL 0 +#define SIOTERM 1 + +#define SIO_POLL_FIRST 1 /* immediate */ +#define SIO_POLL_RATE 100 /* sample 100 times /sec */ +#define SIO_POLL_WAIT 15800 /* about 10ms */ +#define SIO_OUT_WAIT 200 + +static t_stat sio_reset(DEVICE* dptr); +static t_stat sioterm_svc(UNIT*); +static t_stat siopoll_svc(UNIT*); +static t_stat sio_attach(UNIT*,char*); +static t_stat sio_detach(UNIT*); +static t_stat sio_txint(I8251* chip); +static t_stat sio_rxint(I8251* chip); +extern DEVICE sagesio_dev; + +UNIT sio_unit[] = { + { UDATA (&siopoll_svc, UNIT_ATTABLE, 0), SIO_POLL_WAIT }, + { UDATA (&sioterm_svc, UNIT_IDLE, 0), SIO_OUT_WAIT } +}; + +static SERMUX sio_mux = { + SIO_POLL_FIRST, /*pollfirst*/ + SIO_POLL_RATE, /*pollrate*/ + { 0 }, /*ldsc*/ + { 1, 0, 0, 0 }, /*desc*/ + &sio_unit[SIOTERM], /*term_unit*/ + &sio_unit[SIOPOLL] /*poll unit*/ +}; + +static I8251 u58 = { + {0,0,U58_ADDR,4,2}, + &sagesio_dev,NULL,NULL,i8251_reset, + &sio_txint,&sio_rxint, + &sio_unit[SIOPOLL],&sio_unit[SIOTERM], + &sio_mux +}; + +REG sio_reg[] = { + { DRDATA(INIT, u58.init, 3) }, + { HRDATA(MODE, u58.mode, 8) }, + { HRDATA(SYNC1, u58.sync1, 8) }, + { HRDATA(SYNC2, u58.sync2, 8) }, + { HRDATA(CMD, u58.cmd, 8) }, + { HRDATA(IBUF, u58.ibuf, 8) }, + { HRDATA(OBUF, u58.obuf, 8) }, + { HRDATA(STATUS, u58.status, 8) }, + { HRDATA(STATUS, u58.bitmask, 8), REG_HRO }, + { 0 } +}; + +static MTAB sio_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, + { 0 } +}; + +DEVICE sagesio_dev = { + "SIO", sio_unit, sio_reg, sio_mod, + 2, 16, 32, 2, 16, 16, + NULL, NULL, &sio_reset, + NULL, &sio_attach, &sio_detach, + &u58, DEV_DEBUG, 0, + i8251_dt, NULL, NULL +}; + +static t_stat sioterm_svc(UNIT* uptr) +{ + DEVICE* dptr = find_dev_from_unit(uptr); + I8251* chip = (I8251*)dptr->ctxt; + SERMUX* mux = chip->mux; + t_stat rc; + int ch = chip->obuf; + + /* suppress NUL bytes after CR LF */ + switch (ch) { + case 0x0d: + chip->crlf = 1; break; + case 0x0a: + chip->crlf = chip->crlf==1 ? 2 : 0; break; + case 0: + if (chip->crlf==2) goto set_stat; + default: + chip->crlf = 0; + } + + /* TODO? sim_tt_outcvt */ + + /* attached to a telnet port? */ + if (mux->poll->flags & UNIT_ATT) { + if ((rc=tmxr_putc_ln(&mux->ldsc, ch & chip->bitmask)) != SCPE_OK) { + sim_activate(uptr, uptr->wait); + return SCPE_OK; + } else + tmxr_poll_tx(&mux->desc); + } else { + /* no, use normal terminal output */ + if ((rc=sim_putchar_s(ch & chip->bitmask)) != SCPE_OK) { + sim_activate(uptr, uptr->wait); + return rc==SCPE_STALL ? SCPE_OK : rc; + } + } +set_stat: + chip->status |= I8251_ST_TXEMPTY; + if (chip->cmd & I8251_CMD_TXEN) { + chip->status |= I8251_ST_TXRDY; + return sio_txint(chip); + } + chip->status &= ~I8251_ST_TXRDY; + return SCPE_OK; +} + +static t_stat siopoll_svc(UNIT* uptr) +{ + int32 c; + DEVICE* dptr = find_dev_from_unit(uptr); + I8251* chip = (I8251*)dptr->ctxt; + SERMUX* mux = chip->mux; + + sim_activate(uptr, uptr->wait); /* restart it again */ + + /* network attached? */ + if (mux->poll->flags & UNIT_ATT) { + if (tmxr_poll_conn(&mux->desc) >= 0) /* new connection? */ + mux->ldsc.rcve = 1; + tmxr_poll_rx(&mux->desc); + if (!tmxr_rqln(&mux->ldsc)) return SCPE_OK; + /* input ready */ + c = tmxr_getc_ln(&mux->ldsc); + if ((c & TMXR_VALID)==0) return SCPE_OK; + c &= 0xff; /* extract character */ + } else + return SCPE_OK; + + if (!(chip->cmd & I8251_CMD_RXE)) { /* ignore data if receiver not enabled */ + chip->status &= ~I8251_ST_RXRDY; + return SCPE_OK; + } + + /* got char */ + if (c & SCPE_BREAK) { /* a break? */ + c = 0; + chip->status |= I8251_ST_SYNBRK; + } else + chip->status &= ~I8251_ST_SYNBRK; + + /* TODO? sim_tt_icvt */ + chip->ibuf = c & chip->bitmask; + if (chip->status & I8251_ST_RXRDY) + chip->status |= I8251_ST_OE; + chip->status |= I8251_ST_RXRDY; + return sio_rxint(chip); +} + +static t_stat sio_reset(DEVICE* dptr) +{ + t_stat rc; + I8251* chip = (I8251*)dptr->ctxt; + SERMUX* mux = chip->mux; + + if ((rc = (dptr->flags & DEV_DIS) ? + del_iohandler(chip) : + add_iohandler(mux->poll,chip,i8251_io)) != SCPE_OK) return rc; + + u58.reset(&u58); + mux->term->wait = 1000; /* TODO adjust to realistic speed */ + + /* network attached? */ + if (mux->poll->flags & UNIT_ATT) { + mux->poll->wait = mux->pfirst; + sim_activate(mux->poll,mux->poll->wait); /* start poll routine */ + } else + sim_cancel(mux->poll); + sim_cancel(mux->term); + return SCPE_OK; +} + +static t_stat sio_attach(UNIT* uptr, char* cptr) +{ + return mux_attach(uptr,cptr,&sio_mux); +} + +static t_stat sio_detach(UNIT* uptr) +{ + return mux_detach(uptr,&sio_mux); +} + +static t_stat sio_txint(I8251* chip) +{ + TRACE_PRINT0(DBG_UART_IRQ,"Raise TX Interrupt"); + return sage_raiseint(SIOTX_PICINT); +} + +static t_stat sio_rxint(I8251* chip) +{ + TRACE_PRINT0(DBG_UART_IRQ,"Raise RX Interrupt"); + return sage_raiseint(SIORX_PICINT); +} + +/***************************************************************************************************/ + +#define CONSPOLL 0 +#define CONSTERM 1 + +#define CONS_POLL_FIRST 1 /* immediate */ +#define CONS_POLL_RATE 100 /* sample 100 times /sec */ +#define CONS_POLL_WAIT 15800 /* about 10ms */ +#define CONS_OUT_WAIT 200 + +static t_stat cons_reset(DEVICE* dptr); +static t_stat cons_txint(I8251* chip); +static t_stat cons_rxint(I8251* chip); +static t_stat conspoll_svc(UNIT*); +static t_stat consterm_svc(UNIT*); +static t_stat cons_attach(UNIT*,char*); +static t_stat cons_detach(UNIT*); +extern DEVICE sagecons_dev; + +UNIT cons_unit[] = { + { UDATA (&conspoll_svc, UNIT_ATTABLE, 0), CONS_POLL_WAIT }, + { UDATA (&consterm_svc, UNIT_IDLE, 0), CONS_OUT_WAIT } +}; + +static SERMUX cons_mux = { + CONS_POLL_FIRST, + CONS_POLL_RATE, + { 0 }, + { 1, 0, 0, 0 }, + &cons_unit[CONSTERM], + &cons_unit[CONSPOLL] +}; + +static I8251 u57 = { + { 0,0,U57_ADDR,4,2}, + &sagecons_dev,NULL,NULL,&i8251_reset, + &cons_txint,&cons_rxint, + &cons_unit[CONSPOLL],&cons_unit[CONSTERM], + &cons_mux +}; + +REG cons_reg[] = { + { DRDATA(INIT, u57.init, 3) }, + { HRDATA(MODE, u57.mode, 8) }, + { HRDATA(SYNC1, u57.sync1, 8) }, + { HRDATA(SYNC2, u57.sync2, 8) }, + { HRDATA(CMD, u57.cmd, 8) }, + { HRDATA(IBUF, u57.ibuf, 8) }, + { HRDATA(OBUF, u57.obuf, 8) }, + { HRDATA(STATUS, u57.status, 8) }, + { HRDATA(BITS, u57.bitmask,8), REG_HRO }, + { 0 } +}; + +static MTAB cons_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, + { 0 } +}; + +DEVICE sagecons_dev = { + "CONS", cons_unit, cons_reg, cons_mod, + 2, 16, 32, 2, 16, 16, + NULL, NULL, &cons_reset, + NULL, &cons_attach, &cons_detach, + &u57, DEV_DEBUG, 0, + i8251_dt, NULL, NULL +}; + +static t_stat cons_reset(DEVICE* dptr) +{ + t_stat rc; + int32 wait; + I8251* chip = (I8251*)dptr->ctxt; + SERMUX* mux = chip->mux; + + if ((rc = (dptr->flags & DEV_DIS) ? + del_iohandler(chip) : + add_iohandler(mux->poll,chip,&i8251_io)) != SCPE_OK) return rc; + + u57.reset(&u57); + + /* initialize POLL timer */ + wait = mux->poll->wait = CONS_POLL_WAIT; + sim_rtcn_init(wait, TMR_CONS); + + u57.oob = TRUE; /* this is the console */ + sim_activate(mux->poll, wait); + sim_cancel(mux->term); + return SCPE_OK; +} + +/* this service is started when a unit is attached, or characters are available on keyboard */ +static t_stat conspoll_svc(UNIT* uptr) +{ + int32 c, kbdc; + DEVICE* dptr = find_dev_from_unit(uptr); + I8251* chip = (I8251*)dptr->ctxt; + SERMUX* mux = chip->mux; + + uptr->wait = sim_rtcn_calb(mux->prate, TMR_CONS); /* calibrate timer */ + sim_activate(uptr, uptr->wait); /* restart it again */ + + kbdc = sim_poll_kbd(); /* check keyboard */ + if (kbdc==SCPE_STOP) return kbdc; /* handle CTRL-E */ + + /* network-redirected input? */ + if (mux->poll->flags & UNIT_ATT) { + if (tmxr_poll_conn(&mux->desc) >= 0) /* incoming connection */ + mux->ldsc.rcve = 1; + + tmxr_poll_rx(&mux->desc); /* poll for input */ + if (!tmxr_rqln(&mux->ldsc)) return SCPE_OK; + /* input ready */ + c = tmxr_getc_ln(&mux->ldsc); + if ((c & TMXR_VALID)==0) return SCPE_OK; + c &= 0xff; /* extract character */ + } else { + c = kbdc; /* use char polled from keyboard instead */ + if (c < SCPE_KFLAG) return c; /* ignore data if not valid */ + } + + if (!(chip->cmd & I8251_CMD_RXE)) { /* ignore data if receiver not enabled */ + chip->status &= ~I8251_ST_RXRDY; + return SCPE_OK; + } + + /* got char */ + if (c & SCPE_BREAK) { /* a break? */ + c = 0; + chip->status |= I8251_ST_SYNBRK; + } else + chip->status &= ~I8251_ST_SYNBRK; + + /* TODO? sim_tt_icvt */ + chip->ibuf = c & chip->bitmask; + if (chip->status & I8251_ST_RXRDY) + chip->status |= I8251_ST_OE; + chip->status |= I8251_ST_RXRDY; + return cons_rxint(chip); +} + +static t_stat consterm_svc(UNIT* uptr) +{ + DEVICE* dptr = find_dev_from_unit(uptr); + I8251* chip = (I8251*)dptr->ctxt; + SERMUX* mux = chip->mux; + t_stat rc; + + int ch = chip->obuf; + + /* suppress NUL bytes after CR LF */ + switch (ch) { + case 0x0d: + chip->crlf = 1; break; + case 0x0a: + chip->crlf = (chip->crlf==1) ? 2 : 0; break; + case 0: + if (chip->crlf==2) goto set_stat; + default: + chip->crlf = 0; + } + + /* TODO? sim_tt_outcvt */ + + /* attached to a telnet port? */ + if (mux->poll->flags & UNIT_ATT) { + if ((rc=tmxr_putc_ln(&mux->ldsc, ch & chip->bitmask)) != SCPE_OK) { + sim_activate(uptr, uptr->wait); + return SCPE_OK; + } else + tmxr_poll_tx(&mux->desc); + } else { + /* no, use normal terminal output */ + if ((rc=sim_putchar_s(ch & chip->bitmask)) != SCPE_OK) { + sim_activate(uptr, uptr->wait); + return rc==SCPE_STALL ? SCPE_OK : rc; + } + } +set_stat: + chip->status |= I8251_ST_TXEMPTY; + if (chip->cmd & I8251_CMD_TXEN) { + chip->status |= I8251_ST_TXRDY; + return cons_txint(chip); + } + chip->status &= ~I8251_ST_TXRDY; + return SCPE_OK; +} + +static t_stat cons_txint(I8251* chip) +{ + TRACE_PRINT0(DBG_UART_IRQ,"Raise TX Interrupt"); + return sage_raiseint(CONSTX_PICINT); +} + +static t_stat cons_rxint(I8251* chip) +{ + TRACE_PRINT0(DBG_UART_IRQ,"Raise RX Interrupt"); + return m68k_raise_autoint(CONSRX_AUTOINT); +} + +static t_stat cons_attach(UNIT* uptr,char* cptr) +{ + return mux_attach(uptr,cptr,&cons_mux); +} + +static t_stat cons_detach(UNIT* uptr) +{ + return mux_detach(uptr,&cons_mux); +} + +t_stat mux_attach(UNIT* uptr, char* cptr, SERMUX* mux) +{ + t_stat rc; + + mux->desc.ldsc = &mux->ldsc; + if ((rc = tmxr_attach(&mux->desc, uptr, cptr)) == SCPE_OK) { + mux->poll->wait = mux->pfirst; + sim_activate(mux->poll,mux->poll->wait); + } + return rc; +} + +t_stat mux_detach(UNIT* uptr,SERMUX* mux) +{ + t_stat rc = tmxr_detach(&mux->desc, uptr); + mux->ldsc.rcve = 0; + sim_cancel(mux->poll); + sim_cancel(mux->term); + return rc; +} diff --git a/SAGE/sage_cpu.c b/SAGE/sage_cpu.c new file mode 100644 index 00000000..4c5a9eb3 --- /dev/null +++ b/SAGE/sage_cpu.c @@ -0,0 +1,195 @@ +/* sage_cpu.c: CPU simulator for sage-II/IV system + + Copyright (c) 20092010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version +*/ + +#include "sage_defs.h" + +static t_stat sagecpu_reset(DEVICE* dptr); +static t_stat sagecpu_boot(int unit,DEVICE* dptr); +static t_stat sage_translateaddr(t_addr in,t_addr* out, IOHANDLER** ioh,int rw,int fc,int dma); +static t_stat sage_mem(t_addr addr,uint8** mem); +static t_stat sagecpu_set_bios(UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat sagecpu_show_bios(FILE *st, UNIT *uptr, int32 val, void *desc); +static uint8* ROM = 0; +static int rom_enable = TRUE; /* LS74 U51 in CPU schematic */ + +extern int32 DR[]; +extern t_addr AR[]; + +#define UNIT_CPU_V_BIOS UNIT_CPU_V_FREE /* has custom BIOS */ +#define UNIT_CPU_BIOS (1 << UNIT_CPU_V_BIOS) + + +#define MAX_ROMSIZE 16384 +#ifdef SAGE_IV +char* biosfile = "sage-iv.hex"; +#else +char* biosfile = "sage-ii.hex"; +#endif + +static MTAB sagecpu_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "BIOS", "BIOS", &sagecpu_set_bios, &sagecpu_show_bios }, + M68KCPU_STDMOD, + { 0 } +}; +UNIT sagecpu_unit = { + UDATA (NULL, UNIT_FIX|UNIT_BINK|CPU_TYPE_68000|UNIT_CPU_EXC|UNIT_CPU_STOP|UNIT_CPU_PRVIO, SAGEMEM) +}; + +#define DBG_CPU_OSCPM DBG_CPU_CUSTOM1 +DEBTAB sagecpu_dt[] = { + { "EXC", DBG_CPU_EXC }, + { "PC", DBG_CPU_PC }, + { "INT", DBG_CPU_INT }, + { "CTRACE", DBG_CPU_CTRACE }, + { "BTRACE", DBG_CPU_BTRACE }, + { "OSCPM", DBG_CPU_OSCPM }, + { NULL, 0 } +}; + +DEVICE sagecpu_dev = { + "CPU", &sagecpu_unit, m68kcpu_reg, sagecpu_mod, + 1, 16, 32, 2, 16, 16, + &m68kcpu_ex, &m68kcpu_dep, &sagecpu_reset, + &sagecpu_boot, NULL, NULL, + NULL, DEV_DEBUG, 0, + sagecpu_dt, NULL, NULL +}; + +static t_stat sagecpu_set_bios(UNIT *uptr, int32 value, char *cptr, void *desc) +{ + FILE* fp; + if (cptr==NULL) return SCPE_ARG; + if ((fp=fopen(cptr,"r"))==0) return SCPE_OPENERR; + fclose(fp); + + biosfile = malloc(strlen(cptr)+1); + strcpy(biosfile,cptr); + + /* enforce reload of BIOS code on next boot */ + if (ROM != 0) free(ROM); + ROM = 0; + return SCPE_OK; +} + +static t_stat sagecpu_show_bios(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + fprintf(st, "BIOS=%s", biosfile); + return SCPE_OK; +} + +t_stat sagecpu_boot(int32 unitno,DEVICE* dptr) +{ + t_stat rc; + + if (!ROM) return SCPE_IERR; + + if (*ROM==0) { + printf("Loading boot code from %s\n",biosfile); + if ((rc = load_cmd(0,biosfile)) != SCPE_OK) return rc; + } + return m68kcpu_boot(unitno,dptr); +} + +/* special logic: capture essential TRAP 8-14 for debugging */ +static void sage_trapcallback(DEVICE* dptr,int trapnum) +{ + if ((dptr->dctrl & DBG_CPU_OSCPM) && sim_deb) { + if (trapnum>=0x08 && trapnum<=0x0e) { + fprintf(sim_deb,"SAGE: TRAP #%x: D0=%x A0=%x\n",trapnum,DR[0],AR[0]); + } + if (trapnum==2) { + fprintf(sim_deb,"SAGE: CPM BDOS #%d D1=0x%x D2=0x%x\n",DR[0]&0xff,DR[1],DR[2]); + } + if (trapnum==3) { + fprintf(sim_deb,"SAGE: CPM BIOS #%d D1=0x%x D2=0x%x\n",DR[0]&0xff,DR[1],DR[2]); + } + } +} + +static t_stat sagecpu_reset(DEVICE* dptr) +{ + t_stat rc; + + /* set CPU pointers */ + m68kcpu_dev = &sagecpu_dev; + m68kcpu_unit = &sagecpu_unit; + + /* redefine memory handlers */ + TranslateAddr = &sage_translateaddr; + Mem = &sage_mem; + + if (!ROM) ROM = (uint8*)calloc(MAX_ROMSIZE,1); + rom_enable = TRUE; + + if ((rc=m68kcpu_reset(dptr)) != SCPE_OK) return rc; + + /* redirect callbacks */ + m68kcpu_trapcallback = &sage_trapcallback; + + return SCPE_OK; +} + +uint8 ioemul[4] = { 0,0,0,0 }; + +/* sage memory */ +static t_stat sage_mem(t_addr addr,uint8** mem) +{ + t_addr a; +// printf("Try to access %x\n",addr); fflush(stdout); + if (rom_enable && addr >= 0 && addr < MAX_ROMSIZE) { /* boot rom mapped to zero page */ + *mem = ROM+addr; + return SCPE_OK; + } + a = addr - 0xfe0000; /* boot rom at normal ROM page */ + if (a >= 0 && a < MAX_ROMSIZE) { + rom_enable = FALSE; + *mem = ROM+a; + return SCPE_OK; + } + a = addr - 0xffc0fe; + if (a >= 0 && a < 2) { /* boot rom diagnostic address: black hole */ + ioemul[0] = ioemul[1] = 0; + *mem = ioemul+a; + return SCPE_OK; + } + a = addr - 0xff0000; + if (a >= 0 && a < 0x10000) { + *mem = ioemul; + return SCPE_OK; + } + if (addr > MEMORYSIZE) return SIM_NOMEM; + return m68k_mem(addr,mem); +} + +t_stat sage_translateaddr(t_addr in,t_addr* out, IOHANDLER** ioh,int rw,int fc,int dma) +{ + static uint32 bptype[] = { R_BKPT_SPC|SWMASK('R'), W_BKPT_SPC|SWMASK('W') }; + t_addr ma = in & addrmask; + if (sim_brk_summ && sim_brk_test(ma, bptype[rw])) return STOP_IBKPT; + return m68k_translateaddr(in,out,ioh,rw,fc,dma); +} diff --git a/SAGE/sage_defs.h b/SAGE/sage_defs.h new file mode 100644 index 00000000..61e42288 --- /dev/null +++ b/SAGE/sage_defs.h @@ -0,0 +1,152 @@ +/* sage_defs.h: simulator header file for sage-II system + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 10-Jan-10 HV Defines for certain chip bits/registers + 04-Oct-09 HV Initial version +*/ + +#ifndef SAGE_DEFS_H_ +#define SAGE_DEFS_H_ + +#include "sim_defs.h" +#include "m68k_cpu.h" + +/* don't define this yet, won't work */ +#undef SAGE_IV + +#define UNIT_CPU_V_ROM UNIT_CPU_V_FREE /* has switchable ROM */ +#define UNIT_CPU_ROM (1 << UNIT_CPU_V_ROM) + +#define SAGEMEM (128*1024) + +#define ROMBASE 0xfe0000 /* base address of ROM */ +#ifdef SAGE_IV +#define ROMSIZE 0x004000 /* size of ROM (4K words) */ +#else +#define ROMSIZE 0x002000 /* size of ROM (4K words) */ +#endif + +/* simh timers */ +#define TMR_RTC1 0 +#define TMR_RTC2 1 +#define TMR_CONS 2 +#define TMR_INT 3 + +/* definitions for certain chips */ +#include "chip_defs.h" + +/* PIC base address */ +#define U73_ADDR 0xffc041 +extern t_stat sage_raiseint(int level); /* sage specific interrupt handler */ + +/* 8255 for dip switches and floppy control */ +#define U22_ADDR 0xffc021 +extern uint32 *u22_portc; /* exposed for use by FD device */ +#define U22C_FRES 0x80 +#define U22C_PCRMP 0x40 +#define U22C_MOT 0x20 +#define U22C_SL1 0x10 +#define U22C_SL0 0x08 +#define U22C_FDIE 0x04 +#define U22C_RDY 0x02 +#define U22C_TC 0x01 + +/* 8253 timer units */ +#define U75_ADDR 0xffc001 +#define U74_ADDR 0xffc081 +#define TIMER2C0_PICINT 6 +#define TIMER2C2_PICINT 0 + +/* FDC */ +#define U21_ADDR 0xffc051 +extern I8272 u21; +#define FDC_AUTOINT 6 + +/* LP port */ +#define U39_ADDR 0xffc061 +#define LP_PICINT 5 +#define SI_PICINT 7 + +#define U39B_FDI 0x01 +#define U39B_WP 0x02 +#define U39B_RG 0x04 +#define U39B_CD 0x08 +#define U39B_BUSY 0x10 +#define U39B_PAPER 0x20 +#define U39B_SEL 0x40 +#define U39B_FAULT 0x80 +#define U39C_PRES 0x01 +#define U39C_SC 0x02 +#define U39C_SI 0x04 +#define U39C_LEDR 0x08 +#define U39C_STROBE 0x10 +#define U39C_PRIME 0x20 +#define U39C_RCNI 0x40 +#define U39C_RMI 0x80 + + +/* SIO port */ +#define U58_ADDR 0xffc031 +#define SIORX_PICINT 1 +#define SIOTX_PICINT 3 + +/* CONS port */ +#define U57_ADDR 0xffc071 +#define CONSRX_AUTOINT 5 +#define CONSTX_PICINT 2 + +/* unimplemented */ +#define IEEEBASE 0xffc011 /* IEEE-488 interface (TMS9914) */ + +/* winchester board: not yet */ +#define S2651d 0xffc401 /* aux serial 4 */ +#define S2651d_DATA (S2651d+0) /* RW data port aux 4 */ +#define S2651d_STATUS (S2651d+2) /* R status aux 4 */ +#define S2651d_MODE (S2651d+4) /* W mode aux 4 */ +#define S2651d_CTRL (S2651d+6) /* W mode aux 4 */ + +#define S2651c 0xffc441 /* aux serial 3 */ +#define S2651c_DATA (S2651c+0) /* RW data port aux 3 */ +#define S2651c_STATUS (S2651c+2) /* R status aux 3 */ +#define S2651c_MODE (S2651c+4) /* W mode aux 3 */ +#define S2651c_CTRL (S2651c+6) /* W mode aux 3 */ + +#define S2651b 0xffc481 /* aux serial 2 */ +#define S2651b_DATA (S2651b+0) /* RW data port aux 2 */ +#define S2651b_STATUS (S2651b+2) /* R status aux 2 */ +#define S2651b_MODE (S2651b+4) /* W mode aux 2 */ +#define S2651b_CTRL (S2651b+6) /* W mode aux 2 */ + +#define S2651a 0xff4c1 /* aux serial 1 */ +#define S2651a_DATA (S2651a+0) /* RW data port aux 1 */ +#define S2651a_STATUS (S2651a+2) /* R status aux 1 */ +#define S2651a_MODE (S2651a+4) /* W mode aux 1 */ +#define S2651a_CTRL (S2651a+6) /* W mode aux 1 */ + +/* must be included at the end */ +#include "m68k_cpu.h" + +#endif + diff --git a/SAGE/sage_fd.c b/SAGE/sage_fd.c new file mode 100644 index 00000000..76c58046 --- /dev/null +++ b/SAGE/sage_fd.c @@ -0,0 +1,139 @@ +/* sage_fd.c: Floppy device for sage-II system + + Copyright (c) 2009,2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version +*/ + +#include "sage_defs.h" + +static t_stat sagefd_reset(DEVICE* dptr); +static t_stat sagefd_boot(int32 unit_num,DEVICE* dptr); +static void sagefd_seldrv(I8272* chip,int drvnum); +static void sagefd_interrupt(I8272* chip,int delay); +extern DEVICE sagefd_dev; +static t_stat fdcint_svc(UNIT*); + +/* this is the FDC chip */ +I8272 u21 = { + { 0, 0, U21_ADDR, 4, 2 }, + &sagefd_dev, + NULL, NULL, &i8272_reset, &sagefd_seldrv, &sagefd_interrupt +}; + +UNIT sagefd_unit[] = { + { UDATA (&fdcint_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY), 58200 }, + { UDATA (&fdcint_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY), 58200 } +}; + +REG sagefd_reg[] = { + { NULL } +}; + +static MTAB sagefd_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, + { UNIT_I8272_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_I8272_WLK, UNIT_I8272_WLK, "WRTLCK", "WRTLCK", NULL }, + { UNIT_I8272_VERBOSE, 0, "QUIET", "QUIET", NULL }, + { UNIT_I8272_VERBOSE, UNIT_I8272_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE sagefd_dev = { + "FD", sagefd_unit, sagefd_reg, sagefd_mod, + 2, 16, 32, 2, 16, 16, + NULL, NULL, &sagefd_reset, + &sagefd_boot, &i8272_attach, &i8272_detach, + &u21, (DEV_DISABLE|DEV_DEBUG), 0, + i8272_dt, NULL, NULL +}; + +static void sagefd_seldrv(I8272* chip,int drvnum) +{ + /* this routine defeats the standard drive select in i8272.c + * which interprets the US0/US1 bits of various commands. + * Sage uses 8255 portc bits for that, and always leaves + * US0/US1 = 0, despite which drive is selected. + * The actual code to select drives is in sage_stddev.c in u22callc() + */ + return; +} + +static t_stat sagefd_reset(DEVICE* dptr) +{ + t_stat rc; + I8272* chip = (I8272*)dptr->ctxt; + + /* fixup device link */ + i8272_dev = dptr; + + rc = (dptr->flags & DEV_DIS) ? /* Disconnect I/O Ports */ + del_iohandler((void*)chip) : + add_iohandler(&sagefd_unit[0],(void*)chip,i8272_io); + if (rc != SCPE_OK) return rc; + return (*chip->reset)(chip); +} + +static t_stat fdcint_svc(UNIT* unit) +{ +#if DBG_MSG==1 + I8272* chip; + DEVICE* dptr; + if (!unit) return -1; + dptr = find_dev_from_unit(unit); + if (!dptr) return -1; + chip = (I8272*)dptr->ctxt; +#endif + if (*u22_portc & U22C_FDIE) { + TRACE_PRINT0(DBG_FD_IRQ,"FDCINT_SVC: deliver interrupt"); + m68k_raise_autoint(FDC_AUTOINT); + + } else { + TRACE_PRINT0(DBG_FD_IRQ,"FDCINT_SVC: int not granted"); + } + return SCPE_OK; +} + + +static t_stat sagefd_boot(int32 unit_num,DEVICE* dptr) +{ + printf("sagefd_boot\n"); + return SCPE_OK; +} + +static void sagefd_interrupt(I8272* chip,int delay) +{ + TRACE_PRINT0(DBG_FD_IRQ,"SAGEFD_INT: request interrupt"); + sim_activate(&sagefd_unit[0],delay); +} + +/* dummy routines for i8272 - sage does not use DMA */ +void PutByteDMA(uint32 addr, uint8 data) +{ +} + +uint8 GetByteDMA(uint32 addr) +{ + return 0; +} diff --git a/SAGE/sage_hd.c b/SAGE/sage_hd.c new file mode 100644 index 00000000..f5c267a2 --- /dev/null +++ b/SAGE/sage_hd.c @@ -0,0 +1,84 @@ +/* sage_fd.c: Harddisk device for sage-II system + + Copyright (c) 2009, Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 12-Oct-09 HV Initial version +*/ + +#include "sage_defs.h" + +static t_stat sagehd_reset(DEVICE* dptr); +static t_stat sagehd_boot(int32 unit_num,DEVICE* dptr); +static t_stat sagehd_attach(UNIT* uptr, char* file); +static t_stat sagehd_detach(UNIT* uptr); + + +UNIT sagehd_unit[] = { + { UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_DISABLE | UNIT_ROABLE, 0) }, + { UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_DISABLE | UNIT_DIS | UNIT_ROABLE, 0) }, + { UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_DISABLE | UNIT_DIS | UNIT_ROABLE, 0) }, + { UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_DISABLE | UNIT_DIS | UNIT_ROABLE, 0) } +}; + +REG sagehd_reg[] = { + { NULL } +}; + +/* +static MTAB sagehd_mod[] = { + { NULL } +}; +*/ +DEVICE sagehd_dev = { + "HD", sagehd_unit, sagehd_reg, /*sagehd_mod*/NULL, + 4, 16, 32, 2, 16, 16, + NULL, NULL, &sagehd_reset, + &sagehd_boot, &sagehd_attach, &sagehd_detach, + NULL, DEV_DISABLE|DEV_DIS, 0, + NULL, NULL, NULL +}; + +static t_stat sagehd_reset(DEVICE* dptr) +{ + printf("sagehd_reset\n"); + return SCPE_OK; +} + +static t_stat sagehd_boot(int32 unit_num,DEVICE* dptr) +{ + printf("sagehd_boot\n"); + return SCPE_OK; +} + +static t_stat sagehd_attach(UNIT* uptr, char* file) +{ + printf("sagehd_attach\n"); + return SCPE_OK; +} + +static t_stat sagehd_detach(UNIT* uptr) +{ + printf("sagehd_detach\n"); + return SCPE_OK; +} diff --git a/SAGE/sage_ieee.c b/SAGE/sage_ieee.c new file mode 100644 index 00000000..3db6512e --- /dev/null +++ b/SAGE/sage_ieee.c @@ -0,0 +1,62 @@ +/* sage_ieee.c: IEEE 488 device for Sage-II-system + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 12-Oct-09 HV Initial version +*/ + +/* N O T Y E T I M P L E M E N T E D ! ! ! */ +#include "sage_defs.h" + +#if 0 +static t_stat sageieee_reset(DEVICE* dptr); + +UNIT sageieee_unit = { + UDATA (NULL, UNIT_FIX | UNIT_BINK, 0) +}; + +REG sageieee_reg[] = { + { NULL } +}; + +static MTAB sageieee_mod[] = { + { 0 } +}; + +DEVICE sageieee_dev = { + "IEEE", &sageieee_unit, sageieee_reg, sageieee_mod, + 1, 16, 32, 2, 16, 16, + NULL, NULL, &sageieee_reset, + NULL, NULL, NULL, + NULL, DEV_DISABLE|DEV_DIS, 0, + NULL, NULL, NULL +}; + +static t_stat sageieee_reset(DEVICE* dptr) +{ + printf("sageieee_reset\n"); + return SCPE_OK; +} + +#endif diff --git a/SAGE/sage_lp.c b/SAGE/sage_lp.c new file mode 100644 index 00000000..02b301bb --- /dev/null +++ b/SAGE/sage_lp.c @@ -0,0 +1,247 @@ +/* sage_lp.c: Printer device for sage-II system + + Copyright (c) 2009, Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version +*/ + +#include "sage_defs.h" + +#define UNIT_V_OFFLINE (UNIT_V_UF + 0) /* unit offline */ +#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE) + +static t_stat sagelp_reset(DEVICE* dptr); +static t_stat sagelp_attach(UNIT *uptr, char *cptr); +static t_stat sagelp_detach(UNIT *uptr); +static t_stat sagelp_output(UNIT *uptr); +static t_stat u39_reset(I8255* chip); +static t_stat u39_calla(I8255* chip,int rw); +static t_stat u39_callb(I8255* chip,int rw); +static t_stat u39_callc(I8255* chip,int rw); +static t_stat u39_ckmode(I8255* chip,uint32 data); +extern DEVICE sagelp_dev; + +/* The LP Centronics device in sage is implemented by a 8255 with the following settings: + * port A output data + * port B input status from printer, and from misc devices + * B0 Floppy interrupt flag + * B1 Floppy write protect flag + * B2 Modem ringing indicator + * B3 Modem carrier detect + * B4 Printer BUSY flag + * B5 Printer PAPER flag + * B6 Printer SELECT flag (on/offline) + * B7 Printer FAULT flag + * port C lower half output control for misc devices + * C0 Parity error reset + * C1 IEEE enable + * C2 Interrupt level 7 + * C3 activity LED + * port C upper half input status from printers + * C4 printer STROBE flag + * C5 printer PRIME flag + * C6 printer ACK INT clear + * C7 modem Ringing/Carrier INT clear (MI) + */ + +static I8255 u39 = { + { 0,0,U39_ADDR,8,2}, + &sagelp_dev, + i8255_write,i8255_read,u39_reset,u39_calla,u39_callb,u39_callc,u39_ckmode +}; + +UNIT sagelp_unit = { + UDATA (NULL, UNIT_SEQ|UNIT_ATTABLE|UNIT_TEXT, 0), SERIAL_OUT_WAIT +}; + +REG sagelp_reg[] = { + { HRDATA(PORTA, u39.porta, 8) }, + { HRDATA(PORTB, u39.portb, 8) }, + { HRDATA(PORTC, u39.portc, 8) }, + { HRDATA(CTRL, u39.ctrl, 8) }, + { GRDATA (BUF, sagelp_unit.buf, 16, 8, 0) }, + { DRDATA (POS, sagelp_unit.pos, T_ADDR_W), PV_LEFT }, + { NULL } +}; + +static MTAB sagelp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, + { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL }, + { UNIT_OFFLINE, 0, "online", "ONLINE", NULL }, + { 0 } +}; + +DEBTAB sagelp_dt[] = { + { "WRA", DBG_PP_WRA }, + { "RDB", DBG_PP_RDB }, + { "RDC", DBG_PP_RDC }, + { "WRC", DBG_PP_WRC }, + { "WRMODE", DBG_PP_MODE }, + { NULL, 0 } +}; + +DEVICE sagelp_dev = { + "LP", &sagelp_unit, sagelp_reg, sagelp_mod, + 1, 16, 32, 2, 16, 16, + NULL, NULL, &sagelp_reset, + NULL, &sagelp_attach, &sagelp_detach, + &u39, (DEV_DISABLE|DEV_DEBUG), 0, + sagelp_dt, NULL, NULL +}; + +t_stat sagelp_reset(DEVICE* dptr) +{ + t_stat rc; + if ((rc = (dptr->flags & DEV_DIS) ? /* Disconnect I/O Ports */ + del_iohandler(dptr->ctxt) : + add_iohandler(&sagelp_unit,dptr->ctxt,i8255_io)) != SCPE_OK) return rc; + + return u39.reset(&u39); +} + +/* we don't accept any mode and combination that a 8255 can do, because + * u39 is hardwired to porta=output, portb=input and portc=output + */ + +static t_stat u39_calla(I8255* chip, int rw) +{ + if (rw) { + sagelp_unit.buf = chip->porta; + TRACE_PRINT1(DBG_PP_WRA,"WR PortA = 0x%x",chip->porta); + } + return SCPE_OK; +} + +static t_stat u39_callb(I8255* chip, int rw) +{ + if (rw==0) { /* only when reading port */ + /* propagate FDC Write Protect */ + int portb = 0; + I8272_DRIVE_INFO* dip = &u21.drive[u21.fdc_curdrv]; + if (dip->uptr && (dip->uptr->flags & UNIT_I8272_WLK)) { + portb |= U39B_WP; + TRACE_PRINT1(DBG_PP_RDB,"RD PortB: WP+=%d",(portb&U39B_WP)?1:0); + } + + /* propagate FDC interrupt */ + if (u21.irqflag) { + portb |= U39B_FDI; + TRACE_PRINT0(DBG_PP_RDB,"RD PortB: FDI+=1"); + } else { + TRACE_PRINT0(DBG_PP_RDB,"RD PortB: FDI+=0"); + } + chip->portb = portb; + } + return SCPE_OK; +} + +static t_stat u39_callc(I8255* chip,int rw) +{ + if (rw==1) { + if (I8255_FALLEDGE(portc,U39C_STROBE)) { + sagelp_output(&sagelp_unit); + TRACE_PRINT1(DBG_PP_RDC,"RD PortC: STROBE-=%d",chip->portc&U39C_STROBE?1:0); + } + if (I8255_RISEEDGE(portc,U39C_SI)) { +/* printf("rising edge on SI: PC=%x!\n",PCX);*/ + TRACE_PRINT1(DBG_PP_RDC,"RD PortC: SI+=%d",chip->portc&U39C_SI?1:0); + sage_raiseint(SI_PICINT); + } + } + return SCPE_OK; +} + +static t_stat u39_ckmode(I8255* chip,uint32 data) +{ + TRACE_PRINT1(DBG_PP_MODE,"WR Mode: 0x%x",data); + + /* BIOS initializes port A as input, later LP is initialized to output */ + if (!(data==0x82 || data==0x92)) { + /* hardwired: + * d7=1 -- mode set flag + * d6=0 -+ group a mode 0: basic I/O + * d5=0 -+ + * d4=0 -- port a = output / input + * d3=0 -- port c upper = output + * d2=0 -- group b mode 0: basic I/O + * d1=1 -- port b = input + * d0=0 -- port c lower = output + */ + printf("u39_ckmode: unsupported ctrl=0x%02x\n",data); + return STOP_IMPL; + } + chip->portc = 0; /* reset port */ + return SCPE_OK; +} + +static t_stat u39_reset(I8255* chip) +{ + sagelp_unit.buf = 0; + sim_cancel (&sagelp_unit); + return SCPE_OK; +} + +static t_stat sagelp_attach (UNIT *uptr, char *cptr) +{ + t_stat rc; + rc = attach_unit(uptr, cptr); + if ((sagelp_unit.flags & UNIT_ATT) == 0) + u39.portb |= U39B_PAPER; /* no paper */ + + return rc; +} + +static t_stat sagelp_detach (UNIT *uptr) +{ + u39.portb |= U39B_PAPER; /* no paper */ + return detach_unit (uptr); +} + +static t_stat sagelp_output(UNIT *uptr) +{ + if ((uptr->flags & UNIT_ATT)==0) { + u39.portb |= U39B_PAPER; /* unattached means: no paper */ + return SCPE_UNATT; + } else if (uptr->flags & UNIT_OFFLINE) { + u39.portb &= ~U39B_SEL; /* offline means: SEL = 0 */ + return STOP_OFFLINE; + } + u39.portb &= ~U39B_PAPER; /* has paper */ + u39.portb |= U39B_SEL; /* is online */ + u39.portb |= U39B_FAULT; /* no fault */ + u39.portb &= ~U39B_BUSY; /* not busy */ + if ((u39.portc & U39C_STROBE)==0) { /* strobe presented */ + fputc (uptr->buf & 0177, uptr->fileref); /* put out char */ + if (ferror (uptr->fileref)) { + perror ("LP I/O error"); + clearerr (uptr->fileref); + return SCPE_IOERR; + } + sagelp_unit.pos = ftell(uptr->fileref); /* update pos */ + u39.portc |= U39C_STROBE; /* XXX reset strobe directly */ + sage_raiseint(LP_PICINT); + return SCPE_OK; + } + return SCPE_OK; +} diff --git a/SAGE/sage_stddev.c b/SAGE/sage_stddev.c new file mode 100644 index 00000000..ac1f0629 --- /dev/null +++ b/SAGE/sage_stddev.c @@ -0,0 +1,633 @@ +/* sage_stddev.c: Standard devices for sage-II system + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version +*/ + +#include "sim_defs.h" +#include "m68k_cpu.h" +#include "sage_defs.h" + +/*********************************************************************************** + * 8259-5 interrupt controller + * + * IRQ output hardwired to Interrupt Priority Level 1 in the Sage + * Level 2: from external bus (wired to HDC board, AUX devices) + * Level 3: from external bus + * Level 4: IEEE 488 Interrupt U6 + * Level 5: Console Uart U67 Receiver Interrupt + * Level 6: FDI floppy controller + * Level 7: nonmaskable RAM parity error (not possible in simh) + * + * hardwired inputs: + * IR0 = Output 2 of U74 real time clock + * IR1 = Modem Uart U58 Receiver Interrupt + * IR2 = Console Uart U67 Transmitter Interrupt + * IR3 = Modem Uart U58 Receiver Interrupt + * IR4 = Modem Carrier Detect Interrupt U38 + * IR5 = LP Port Acknowledge U39/U38 + * IR6 = Output 0 of U74 real time clock + * IR7 = Output C2 of U39 + * + * Notes: + * INTA- is hardwired to VCC, so vectoring is not possible + * SP- is hardwired to VCC, so buffered mode is not possible, and device is a master. + * CAS0-2 lines are open, no need to handle + * UCSD bios and boot prom do not program the PIC for rotating priorities, + * so effectively prio is always 7. + * + **********************************************************************************/ +extern DEVICE sagepic_dev; +static t_stat sagepic_reset(DEVICE* dptr); +static I8259 u73 = { {0,0,U73_ADDR,4,2}, + &sagepic_dev,NULL,NULL,i8259_reset +}; + +UNIT sagepic_unit = { + UDATA (NULL, UNIT_IDLE, 0) +}; + +REG sagepic_reg[] = { + { DRDATA(STATE, u73.state, 8) }, + { HRDATA(IRR, u73.irr, 8) }, + { HRDATA(IMR, u73.imr, 8) }, + { HRDATA(ISR, u73.isr, 8) }, + { HRDATA(ICW1, u73.icw1, 8) }, + { HRDATA(ICW2, u73.icw2, 8) }, + { HRDATA(ICW4, u73.icw4, 8) }, + { HRDATA(OCW2, u73.prio, 3) }, + { NULL } +}; + +static MTAB sagepic_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, + { 0 } +}; + +DEVICE sagepic_dev = { + "PIC", &sagepic_unit, sagepic_reg, sagepic_mod, + 1, 16, 32, 2, 16, 16, + NULL, NULL, &sagepic_reset, + NULL, NULL, NULL, + &u73, DEV_DEBUG, 0, + i8259_dt, NULL, NULL +}; + +static t_stat sagepic_reset(DEVICE* dptr) +{ + t_stat rc; + if ((rc = (dptr->flags & DEV_DIS) ? + del_iohandler(dptr->ctxt) : + add_iohandler(&sagepic_unit,dptr->ctxt,i8259_io)) != SCPE_OK) return rc; + return u73.reset(&u73); +} + +t_stat sage_raiseint(int level) +{ + return i8259_raiseint(&u73,level); +} + +/****************************************************************************************************** + * DIP switches at the back panel. + * + * In the technical manual, switches are layed out 12345678 left to right, + * but here seen as two HEX digits 8765 4321, i.e. 0xc0 is bit 8 and bit 7 set on + * + * a "d" (down) means switch is off or "0", and a "u" (up) means switch is on or "1" + * + * Note that programatically dip switches are port a and b of the onboard 8255 U22 + * which also through port c serves part of the FDC signals + * + * group-a: + * 8 7 6 5 4 3 2 1 + * | | | | | d d d--- 19,2K baud + * | | | | | d d u--- 9600 baud + * | | | | | d u d--- 4800 baud + * | | | | | d u u--- 2400 baud + * | | | | | u d d--- 1200 baud + * | | | | | u d u--- 600 baud + * | | | | | u u d--- 300 baud + * | | | | | u u u--- reserved + * | | | | d--------- even parity + * | | | | u--------- parity disabled + * | | d d----------- boot to debugger + * | | d u----------- boot to floppy 0 + * | | u d----------- boot to harddisk 0 partition 0 + * | | u u----------- reserved + * | d--------------- 96 tpi drive + * | u--------------- 48 tpi drive + * x----------------- reserved + * + * group-b: + * 8 7 6 5 4 3 2 1 + * | | | +-+-+-+-+--- device talk and listen address + * | | u------------- enable talk + * | | d------------- disable talk + * | u--------------- enable listen + * | d--------------- disable listen + * u----------------- 2 consecutive addresses + * d----------------- 1 address + */ + +#if defined(SAGE_IV) + uint32 groupa = 0xd7; /* used by cons device, 19k2, no parity, boot floppy 0 */ + uint32 groupb = 0xf8; /* used by ieee device */ +#else + uint32 groupa = 0xe7; /* used by cons device, 19k2, no parity, boot winchester 0 */ + uint32 groupb = 0xf8; /* used by ieee device */ +#endif + +static t_stat sagedip_reset(DEVICE* dptr); +static t_stat set_groupa(UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat show_groupa(FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat set_groupb(UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat show_groupb(FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat u22_reset(I8255* chip); +static t_stat u22_calla(I8255* chip,int rw); +static t_stat u22_callb(I8255* chip,int rw); +static t_stat u22_callc(I8255* chip,int rw); +static t_stat u22_ckmode(I8255* chip,uint32 data); + +extern DEVICE sagedip_dev; +static I8255 u22 = { + { 0,0,U22_ADDR,8,2 }, + &sagedip_dev,i8255_write,i8255_read,u22_reset,u22_calla,u22_callb,u22_callc,u22_ckmode +}; +uint32* u22_portc = &u22.portc; /* this is used in the FD device as well, but whole 8255 is handled here */ + +UNIT sagedip_unit = { + UDATA (NULL, UNIT_IDLE, 0) +}; + +REG sagedip_reg[] = { + { HRDATA(PORTA, u22.porta, 8) }, + { HRDATA(PORTB, u22.portb, 8) }, + { HRDATA(PORTC, u22.portc, 8) }, + { HRDATA(CTRL, u22.ctrl, 8) }, + { NULL } +}; + +static MTAB sagedip_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "GROUPA", "GROUPA", &set_groupa, &show_groupa, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "GROUPB", "GROUPB", &set_groupb, &show_groupb, NULL }, + { 0 } +}; + +/* Debug Flags */ +DEBTAB sagedip_dt[] = { + { "RDA", DBG_PP_RDA }, + { "RDB", DBG_PP_RDB }, + { "WRC", DBG_PP_WRC }, + { "WRMODE", DBG_PP_MODE }, + { NULL, 0 } +}; + +DEVICE sagedip_dev = { + "DIP", &sagedip_unit, sagedip_reg, sagedip_mod, + 1, 16, 32, 2, 16, 16, + NULL, NULL, &sagedip_reset, + NULL, NULL, NULL, + &u22, DEV_DEBUG, 0, + sagedip_dt, NULL, NULL +}; + +static t_stat sagedip_reset(DEVICE* dptr) +{ + t_stat rc; + + if ((rc = (dptr->flags & DEV_DIS) ? /* Disconnect I/O Ports */ + del_iohandler(dptr->ctxt) : + add_iohandler(&sagedip_unit,dptr->ctxt,i8255_io)) != SCPE_OK) return rc; + + /* clear 8255 ctrl register */ + return u22.reset(&u22); +} + +static t_stat set_gr(char* cptr, uint32* sw) +{ + int i; + char c; + + if (!cptr) return SCPE_ARG; + + *sw = 0; + for (i=0; *cptr && i<8; i++) { + c = *cptr++; + *sw <<= 1; + if (c=='1') *sw |= 1; + else if (c=='0') continue; + else if (c==0) break; + else return SCPE_ARG; + } + return SCPE_OK; +} + +static t_stat set_groupa(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + return set_gr(cptr,&groupa); +} + +static t_stat set_groupb(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + return set_gr(cptr,&groupb); +} + +static t_stat show_gr(FILE* st, char* prefix, uint32 gr) +{ + int i; + fputs(prefix, st); + for (i = 0x80; i > 0; i = i >> 1) + fprintf(st,"%c", gr&i ? '1' : '0'); + return SCPE_OK; +} + +static t_stat show_groupa(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + return show_gr(st, "GROUPA=", groupa); +} + +static t_stat show_groupb(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + return show_gr(st, "GROUPB=", groupb); +} + +static t_stat u22_reset(I8255* chip) +{ + chip->ctrl = 0; + chip->portc = 0; + return SCPE_OK; +} + +extern I8272 u21; + +static t_stat u22_calla(I8255* chip,int rw) +{ + if (rw==0) { + chip->porta = groupa & 0xff; + TRACE_PRINT1(DBG_PP_RDA,"WR PortA: 0x%x",groupa); + } + return SCPE_OK; +} + +static t_stat u22_callb(I8255* chip,int rw) +{ + if (rw==0) { + chip->portb = groupb & 0xff; + TRACE_PRINT1(DBG_PP_RDA,"WR PortB: 0x%x",groupb); + } + return SCPE_OK; +} + +/* callback handler for FDC bits */ +static t_stat u22_callc(I8255* chip,int rw) +{ + /* bit0: TC+ positive enforce that internal data counter of FDC is reset + * bit1: RDY+ positive enable the FDC + * bit2: FDIE+ positive enable FDC interrupt (handled directly by reading portc in sage_fd.c) + * bit3: SL0- negative select of drive 0 + * bit4: SL1- negative select of drive 1 + * bit5: MOT- negative switch on drive motor (ignored) + * bit6: PCRMP- negative precompensation (ignored) + * bit7: FRES+ positive FDC reset + */ + + if (I8255_ISSET(portc,U22C_TC)) { /* TC+ */ + i8272_finish(&u21); /* terminate a read/write in progress */ + } + if (I8255_ISCLR(portc,U22C_RDY)) { /* RDY+ */ + i8272_abortio(&u21); /* abort current op */ + } + if (I8255_ISCLR(portc,U22C_SL0)) { /* SL0- */ + u21.fdc_curdrv = 0; + } else if (I8255_ISCLR(portc,U22C_SL1)) { /* SL1- */ + u21.fdc_curdrv = 1; + } else if (I8255_ISSET(portc,U22C_SL0|U22C_SL1)) { /* deselect drives */ + u21.fdc_curdrv = 0; + } + if (I8255_ISSET(portc,U22C_FRES)) { /* FRES+ */ + i8272_reset(&u21); + } + TRACE_PRINT(DBG_PP_WRC,(sim_deb,"PORTC Flags: %s%s%s%s%s%s%s%s", + I8255_ISSET(portc,U22C_TC)?"TC ":"", + I8255_ISSET(portc,U22C_RDY)?"RDY ":"", + I8255_ISSET(portc,U22C_FDIE)?"FDIE ":"", + I8255_ISSET(portc,U22C_SL0)?"":"SL0 ", + I8255_ISSET(portc,U22C_SL1)?"":"SL1 ", + I8255_ISSET(portc,U22C_MOT)?"":"MOT ", + I8255_ISSET(portc,U22C_PCRMP)?"":"PCRMP ", + I8255_ISSET(portc,U22C_FRES)?"FRES ":"")); + return SCPE_OK; +} + +static t_stat u22_ckmode(I8255* chip, uint32 data) +{ + /* hardwired: + * d7=1 -- mode set flag + * d6=0 -+ group a mode 0: basic I/O + * d5=0 -+ + * d4=1 -- porta = input + * d3=0 -- portc upper = output + * d2=0 -- group b mode 0: basic I/O + * d1=1 -- portb = input + * d0=0 -- portc lower = output + */ + TRACE_PRINT1(DBG_PP_MODE,"WR Mode: 0x%x",data); + if (data != 0x92) { + printf("u22_ckmode: unsupported ctrl=0x%02x\n",data); + return STOP_IMPL; + } + return SCPE_OK; +} + +/*********************************************************************************** + * Two 8553 timers U75 (TIMER1) and U74 (TIMER2) + * Each contain three 8/16 bit timers + * In the sage hardwired in the following way: + * + * +---------+ + * 615kHz--+->|Timer1 C1|---> Baud ser0 + * | +---------+ + * +->|Timer1 C2|---> Baud ser1 + * +---------+ + * +---------+ +---------+ + * 64kHz---+->|Timer1 C0|--->|Timer2 C0|--> PIC IR6 + * | |div 64000| |mode0 | + * | +---------+ +---------+ + * | +---------+ +---------+ + * +->|Timer2 C1|--->|Timer2 C2|--> PIC IR0 + * | | | | + * +---------+ +---------+ + * + * NOT UNITS: Timer1 C1 and C2 are programmed in mode 2 as clock dividers for the USARTs + * In this emulation we allow programming them, but since they don't produce interrupts, + * their work is ignored. + * + * Timer1 C0 and timer2 C0 form a clock divider which produces an interrupt at PIC level 6 + * Likewise, timer2 C1 and timer2 C2 form a clock divider which produces an interrupt at PIC level 0 + * + * Typically, the first one in cascade is programmed in mode 2, the second one in mode 0. + * Timer1 C0 is explicitly programmed as a divider by 64k, so that it feeds timer2 C0 + * with a 1Hz clock. + * + * The way the timers are hardwired makes certain mode settings impossible: all GATE + * inputs are set to VCC, so MODE1 and MODE5 are impossible, and MODE4 becomes a + * variant of MODE0. MODE3 is used by the baudrate generators. The timers may run in + * 8 bit mode, but analysis of existing BIOS code (BOOT PROM and UCSD BIOS) uncovered + * they are used in 16 bit mode only. + * So, this implementation only contains the most likely usages, and the other ones have + * to be added when there is a necessity. + * + * Notes on actual implementation: + * Since we know the input clocks, we have just to take care about the division factors + * stored in T1C0 and T2C1. Whenever one of these timers are read out, the actual count + * has to be calculated on the fly. The actual cnt registers only hold the count factors + * programmed, but are never counted down, as, in the case of the 64kHz clock this would + * mean to trigger sim_* events 64000 times a second. + * + ***********************************************************************************/ + +/************************************************************************************ + * timer 1 + ***********************************************************************************/ +static t_stat sagetimer1_reset(DEVICE* dptr); +static t_stat timer1_svc(UNIT* uptr); +static t_stat u75_ckmode(I8253* chip, uint32 data); +static t_stat u75_call0(I8253* chip,int addr, uint32* value); + +static t_stat sagetimer2_reset(DEVICE* dptr); +static t_stat timer2_svc(UNIT* uptr); +static t_stat u74_ckmode(I8253* chip, uint32 data); +static t_stat u74_call1(I8253* chip,int addr, uint32* value); + +extern DEVICE sagetimer1_dev; +extern DEVICE sagetimer2_dev; + +/* forward timer 2 */ +UNIT sagetimer2_unit = { + UDATA (&timer2_svc, UNIT_IDLE, 0) +}; + +static I8253 u74 = { {0,0,U74_ADDR,8,2}, + &sagetimer2_dev,&sagetimer2_unit,i8253_reset,u74_ckmode, + { { 0, }, { u74_call1, }, { 0, } } +}; + +/* timer 1 */ +UNIT sagetimer1_unit = { + UDATA (&timer1_svc, UNIT_IDLE, 1) +}; + +static I8253 u75 = { {0,0,U75_ADDR,8,2}, + &sagetimer1_dev,&sagetimer1_unit,i8253_reset,u75_ckmode, + { { u75_call0, }, { 0, }, { 0, } } +}; + +REG sagetimer1_reg[] = { + { HRDATA(INIT, u75.init, 8), REG_HRO }, + { HRDATA(STATE0,u75.cntr[0].state, 8),REG_HRO }, + { HRDATA(STATE1,u75.cntr[1].state, 8),REG_HRO }, + { HRDATA(STATE2,u75.cntr[2].state, 8),REG_HRO }, + { HRDATA(MODE0, u75.cntr[0].mode, 8) }, + { HRDATA(MODE1, u75.cntr[1].mode, 8) }, + { HRDATA(MODE2, u75.cntr[2].mode, 8) }, + { HRDATA(CNT0, u75.cntr[0].count, 16) }, + { HRDATA(CNT1, u75.cntr[1].count, 16) }, + { HRDATA(CNT2, u75.cntr[2].count, 16) }, + { HRDATA(LATCH0,u75.cntr[0].latch, 16) }, + { HRDATA(LATCH1,u75.cntr[1].latch, 16) }, + { HRDATA(LATCH2,u75.cntr[2].latch, 16) }, + { HRDATA(DIV0, u75.cntr[0].divider, 16),REG_HRO }, + { HRDATA(DIV1, u75.cntr[1].divider, 16),REG_HRO }, + { HRDATA(DIV2, u75.cntr[2].divider, 16),REG_HRO }, + { NULL } +}; + +static MTAB sagetimer1_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, + { 0 } +}; + +DEVICE sagetimer1_dev = { + "TIMER1", &sagetimer1_unit, sagetimer1_reg, sagetimer1_mod, + 1, 16, 32, 2, 16, 16, + NULL, NULL, &sagetimer1_reset, + NULL, NULL, NULL, + &u75, DEV_DEBUG, 0, + i8253_dt, NULL, NULL +}; + +static t_stat sagetimer1_reset(DEVICE* dptr) +{ + t_stat rc; + if (!(rc = (dptr->flags & DEV_DIS) ? + del_iohandler(dptr->ctxt) : + add_iohandler(&sagetimer1_unit,dptr->ctxt,i8253_io)) != SCPE_OK) return rc; + return u75.reset(&u75); +} + +static t_stat timer1_svc(UNIT* uptr) +{ + int32 wait; + I8253CNTR* t1c0 = &u75.cntr[0]; + I8253CNTR* t2c0 = &u74.cntr[0]; + +// fprintf(sim_deb,"TIMER1: timer1_svc called T1C0=%d T2C0=%d\n",t1c0->count,t2c0->count); + /* we call this service 64000 times a second to decrement counter T1C0. + * When T1C0 reaches 0, it will decrement T2C0 */ + t1c0->count--; + if (t1c0->count <= 0) { + /* reload from divider */ + t1c0->count = t1c0->divider; + /* decrement T2C0 counter and raise interrupt 6 if counter is zero */ + if (t2c0->count == 0) { + sage_raiseint(TIMER2C0_PICINT); +// printf("timer1 heartbeat\n"); + t2c0->count = 65536; + } + t2c0->count--; + } + + /* adjust timing */ + wait = sim_rtcn_calb(64000,TMR_RTC1); + sim_activate(u75.unit,wait); /* 64000 ticks per second */ + return SCPE_OK; +} + +static t_stat u75_ckmode(I8253* chip,uint32 mode) +{ + /* @TODO check valid modes */ + return SCPE_OK; +} + +static t_stat u75_call0(I8253* chip,int rw,uint32* value) +{ + if (rw==1) { + I8253CNTR* cntr = &chip->cntr[0]; + if ((cntr->mode & I8253_BOTH) && (cntr->state & I8253_ST_MSBNEXT)) { + sim_cancel(chip->unit); + return SCPE_OK; /* not fully loaded yet */ + } else { + /* start the CK0 clock at 64000Hz */ + sim_activate(chip->unit,sim_rtcn_init(64000,TMR_RTC1)); /* use timer1 C0 for this clock */ + } + } + return SCPE_OK; +} + + +/************************************************************************************ + * timer 2 + ***********************************************************************************/ + +REG sagetimer2_reg[] = { + { HRDATA(INIT, u74.init, 8), REG_HRO }, + { HRDATA(STATE0,u74.cntr[0].state, 8),REG_HRO }, + { HRDATA(STATE1,u74.cntr[1].state, 8),REG_HRO }, + { HRDATA(STATE2,u74.cntr[2].state, 8),REG_HRO }, + { HRDATA(MODE0, u74.cntr[0].mode, 8) }, + { HRDATA(MODE1, u74.cntr[1].mode, 8) }, + { HRDATA(MODE2, u74.cntr[2].mode, 8) }, + { HRDATA(CNT0, u74.cntr[0].count, 16) }, + { HRDATA(CNT1, u74.cntr[1].count, 16) }, + { HRDATA(CNT2, u74.cntr[2].count, 16) }, + { HRDATA(LATCH0,u74.cntr[0].latch, 16) }, + { HRDATA(LATCH1,u74.cntr[1].latch, 16) }, + { HRDATA(LATCH2,u74.cntr[2].latch, 16) }, + { HRDATA(DIV0, u74.cntr[0].divider, 16),REG_HRO }, + { HRDATA(DIV1, u74.cntr[1].divider, 16),REG_HRO }, + { HRDATA(DIV2, u74.cntr[2].divider, 16),REG_HRO }, + { NULL } +}; + +static MTAB sagetimer2_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IO", "IO", &set_iobase, &show_iobase, NULL }, + { 0 } +}; + +DEVICE sagetimer2_dev = { + "TIMER2", &sagetimer2_unit, sagetimer2_reg, sagetimer2_mod, + 1, 16, 32, 2, 16, 16, + NULL, NULL, &sagetimer2_reset, + NULL, NULL, NULL, + &u74, DEV_DEBUG, 0, + i8253_dt, NULL, NULL +}; + +static t_stat sagetimer2_reset(DEVICE* dptr) +{ + t_stat rc; + if ((rc = (dptr->flags & DEV_DIS) ? + del_iohandler(dptr->ctxt) : + add_iohandler(&sagetimer2_unit,dptr->ctxt,i8253_io)) != SCPE_OK) return rc; + return u74.reset(&u74); +} + +static t_stat u74_ckmode(I8253* chip,uint32 mode) +{ + /* @TODO check valid modes */ + return SCPE_OK; +} + +static t_stat u74_call1(I8253* chip,int rw,uint32* value) +{ + if (rw==1) { + I8253CNTR* cntr = &chip->cntr[1]; + if ((cntr->mode & I8253_BOTH) && (cntr->state & I8253_ST_MSBNEXT)) { + sim_cancel(chip->unit); + return SCPE_OK; /* not fully loaded yet */ + } else { + /* start the CK0 clock at 64000Hz */ + sim_activate(chip->unit,sim_rtcn_init(64000,TMR_RTC1)); /* use timer1 C0 for this clock */ + } + } + return SCPE_OK; +} + +static t_stat timer2_svc(UNIT* uptr) +{ + int32 wait; + I8253CNTR* t2c1 = &u74.cntr[1]; + I8253CNTR* t2c2 = &u74.cntr[2]; + + /* we call this service 64000 times a second to decrement counter T2C1. + * When T2C1 reaches 0, it will decrement T2C2 */ + t2c1->count--; + if (t2c1->count <= 0) { + /* reload from divider */ + t2c1->count = t2c1->divider; + /* decrement T2C2 counter and raise interrupt 0 if counter is zero */ + if (t2c2->count == 0) { +// printf("timer2 heartbeat\n"); + sage_raiseint(TIMER2C2_PICINT); + } + t2c2->count--; + } + + /* adjust timing */ + wait = sim_rtcn_calb(64000,TMR_RTC1); + sim_activate(u74.unit,wait); /* 64000 ticks per second */ + return SCPE_OK; +} diff --git a/SAGE/sage_sys.c b/SAGE/sage_sys.c new file mode 100644 index 00000000..c4eee9d9 --- /dev/null +++ b/SAGE/sage_sys.c @@ -0,0 +1,71 @@ +/* sage_sys.c: SYS definitions for sage-II system + + Copyright (c) 2009-2010 Holger Veit + + 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 + Holger Veit 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 Holger Veit et al shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Holger Veit et al. + + 04-Oct-09 HV Initial version +*/ + +#include +#include "sage_defs.h" + +extern DEVICE sagecpu_dev; +extern DEVICE sagepic_dev; +extern DEVICE sagetimer1_dev; +extern DEVICE sagetimer2_dev; +extern DEVICE sagedip_dev; +extern DEVICE sagefd_dev; +extern DEVICE sagecons_dev; +extern DEVICE sagesio_dev; +extern DEVICE sagelp_dev; +#if 0 +extern DEVICE sageieee_dev; +#endif +#ifdef SAGE_IV +extern DEVICE sagehd_dev; +extern DEVICE sageaux_dev; +#endif + +char sim_name[] = "Sage-II/IV 68k"; + +REG *sim_PC = &m68kcpu_reg[18]; +int sim_emax = SIM_EMAX; +DEVICE *sim_devices[] = { + &sagecpu_dev, + &sagepic_dev, + &sagetimer1_dev, + &sagetimer2_dev, + &sagedip_dev, + &sagefd_dev, + &sagecons_dev, + &sagesio_dev, + &sagelp_dev, +#if 0 + &sageieee_dev, +#endif +#ifdef SAGE_IV + &sagehd_dev, + &sageaux_dev, +#endif + NULL +}; diff --git a/Visual Studio Projects/PDQ3.vcproj b/Visual Studio Projects/PDQ3.vcproj new file mode 100644 index 00000000..577c290a --- /dev/null +++ b/Visual Studio Projects/PDQ3.vcproj @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/SAGE.vcproj b/Visual Studio Projects/SAGE.vcproj new file mode 100644 index 00000000..04db9e2f --- /dev/null +++ b/Visual Studio Projects/SAGE.vcproj @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln index e48fc6bb..58927e55 100644 --- a/Visual Studio Projects/Simh.sln +++ b/Visual Studio Projects/Simh.sln @@ -109,6 +109,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alpha", "alpha.vcproj", "{1 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sigma", "sigma.vcproj", "{7DDB6DF6-3837-4DE3-80D7-63181195021F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sage", "SAGE.vcproj", "{9D0DAC36-2C75-41CD-905C-93B2F5ADF9E2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDQ3", "PDQ3.vcproj", "{D4F5761A-B543-40ED-9892-12A0255C2B6D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -271,6 +275,14 @@ Global {7DDB6DF6-3837-4DE3-80D7-63181195021F}.Debug|Win32.Build.0 = Debug|Win32 {7DDB6DF6-3837-4DE3-80D7-63181195021F}.Release|Win32.ActiveCfg = Release|Win32 {7DDB6DF6-3837-4DE3-80D7-63181195021F}.Release|Win32.Build.0 = Release|Win32 + {9D0DAC36-2C75-41CD-905C-93B2F5ADF9E2}.Debug|Win32.ActiveCfg = Debug|Win32 + {9D0DAC36-2C75-41CD-905C-93B2F5ADF9E2}.Debug|Win32.Build.0 = Debug|Win32 + {9D0DAC36-2C75-41CD-905C-93B2F5ADF9E2}.Release|Win32.ActiveCfg = Release|Win32 + {9D0DAC36-2C75-41CD-905C-93B2F5ADF9E2}.Release|Win32.Build.0 = Release|Win32 + {D4F5761A-B543-40ED-9892-12A0255C2B6D}.Debug|Win32.ActiveCfg = Debug|Win32 + {D4F5761A-B543-40ED-9892-12A0255C2B6D}.Debug|Win32.Build.0 = Debug|Win32 + {D4F5761A-B543-40ED-9892-12A0255C2B6D}.Release|Win32.ActiveCfg = Release|Win32 + {D4F5761A-B543-40ED-9892-12A0255C2B6D}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/alpha/alpha_defs.h b/alpha/alpha_defs.h index 4ea2a7c8..6f1ee907 100644 --- a/alpha/alpha_defs.h +++ b/alpha/alpha_defs.h @@ -28,14 +28,14 @@ Alpha Program Office. */ -#ifndef ALPHA_DEFS_H_ -#define ALPHA_DEFS_H_ 0 +#ifndef _ALPHA_DEFS_H_ +#define _ALPHA_DEFS_H_ 0 #include "sim_defs.h" #include #if defined (__GNUC__) -#define INLINE +#define INLINE inline #else #define INLINE #endif diff --git a/makefile b/makefile index 12135e16..65533098 100644 --- a/makefile +++ b/makefile @@ -1097,7 +1097,6 @@ TX0 = ${TX0D}/tx0_cpu.c ${TX0D}/tx0_dpy.c ${TX0D}/tx0_stddev.c \ ${TX0D}/tx0_sys.c ${TX0D}/tx0_sys_orig.c ${DISPLAYL} TX0_OPT = -I ${TX0D} $(DISPLAY_OPT) - SSEMD = SSEM SSEM = ${SSEMD}/ssem_cpu.c ${SSEMD}/ssem_sys.c SSEM_OPT = -I ${SSEMD} @@ -1122,6 +1121,19 @@ ALPHA = ${ALPHAD}/alpha_500au_syslist.c ${ALPHAD}/alpha_cpu.c \ ${ALPHAD}/alpha_mmu.c ${ALPHAD}/alpha_sys.c ALPHA_OPT = -I ${ALPHAD} -DUSE_ADDR64 -DUSE_INT64 +SAGED = SAGE +SAGE = ${SAGED}/sage_cpu.c ${SAGED}/sage_sys.c ${SAGED}/sage_stddev.c \ + ${SAGED}/sage_cons.c ${SAGED}/sage_fd.c ${SAGED}/sage_lp.c \ + ${SAGED}/m68k_cpu.c ${SAGED}/m68k_mem.c ${SAGED}/m68k_scp.c \ + ${SAGED}/m68k_parse.tab.c ${SAGED}/m68k_sys.c \ + ${SAGED}/i8251.c ${SAGED}/i8253.c ${SAGED}/i8255.c ${SAGED}/i8259.c ${SAGED}/i8272.c +SAGE_OPT = -I ${SAGED} -DHAVE_INT64 -DUSE_SIM_IMD + +PDQ3D = PDQ-3 +PDQ3 = ${PDQ3D}/pdq3_cpu.c ${PDQ3D}/pdq3_sys.c ${PDQ3D}/pdq3_stddev.c \ + ${PDQ3D}/pdq3_mem.c ${PDQ3D}/pdq3_debug.c ${PDQ3D}/pdq3_fdc.c +PDQ3_OPT = -I ${PDQ3D} -DUSE_SIM_IMD + # # Build everything (not the unsupported/incomplete simulators) @@ -1404,3 +1416,15 @@ ${BIN}alpha${EXE} : ${ALPHA} ${SIM} ${MKDIRBIN} ${CC} ${ALPHA} ${SIM} ${ALPHA_OPT} $(CC_OUTSPEC) ${LDFLAGS} +sage : ${BIN}sage${EXE} + +${BIN}sage${EXE} : ${SAGE} ${SIM} + ${MKDIRBIN} + ${CC} ${SAGE} ${SIM} ${SAGE_OPT} $(CC_OUTSPEC) ${LDFLAGS} + +pdq3 : ${BIN}pdq3${EXE} + +${BIN}pdq3${EXE} : ${PDQ3} ${SIM} + ${MKDIRBIN} + ${CC} ${PDQ3} ${SIM} ${PDQ3_OPT} $(CC_OUTSPEC) ${LDFLAGS} +