Very very preliminary ucode disassembler
authorNick Downing <nick@ndcode.org>
Fri, 24 Jun 2022 14:27:06 +0000 (00:27 +1000)
committerNick Downing <nick@ndcode.org>
Fri, 24 Jun 2022 14:27:30 +0000 (00:27 +1000)
.gitignore
disasm/Makefile
disasm/star_blazer.asm.patch
disasm/ucode_defs.inc [new file with mode: 0644]
disasm/ucode_disasm.py [new file with mode: 0755]

index 1b2bec3..44a74d5 100644 (file)
@@ -29,6 +29,7 @@
 /disasm/star_blazer.asm
 /disasm/star_blazer.asm0
 /disasm/star_blazer.dsk
+/disasm/ucode_data.inc
 /emu_65c02/emu_65c02
 /emu_65c02/cg_default/*.inc
 /emu_65c02/cg_default/*.pbm
index 222aec8..e235d8c 100644 (file)
@@ -59,9 +59,15 @@ dhgr_pixel_shape_data_aux.inc \
 pixel_shape_index.inc \
 pixel_shape_data.inc \
 shape_index.inc \
-shape_data.inc
+shape_data.inc \
+ucode_defs.inc \
+ucode_data.inc
        ${AS6500} -3 -l -o $<
 
+ucode_data.inc: star_blazer.asm
+       sed -ne '/^ucode1080_countdown_30_pixel:/,/; 9dec/p' $< |\
+./ucode_disasm.py >$@
+
 star_blazer.asm: \
 trace.txt \
 star_blazer.txt \
index fe81e25..607d247 100644 (file)
@@ -1,22 +1,20 @@
---- star_blazer.asm0   2022-06-24 22:42:12.399889990 +1000
-+++ star_blazer.asm    2022-06-24 22:43:07.007889315 +1000
-@@ -1,3 +1,8 @@
+--- star_blazer.asm0   2022-06-25 00:04:33.079828875 +1000
++++ star_blazer.asm    2022-06-25 00:04:33.083828875 +1000
+@@ -1,3 +1,9 @@
 +ALIGN = 0
 +DHGR = 1
 +PIXEL_SHAPE = 1
 +SHAPE = 1
++UCODE = 1
 +
  HIRES_SCREEN = 0x2000                 ; 2000
  HW_KBD = 0xc000                               ; c000
  HW_KBDSTRB = 0xc010                   ; c010
-@@ -12,19 +17,49 @@
+@@ -12,19 +18,48 @@
  HW_PTRIG = 0xc070                     ; c070
  ROM_PREAD = 0xfb1e                    ; fb1e
  
 +.if DHGR
-+; read/write
-+HW_PAGE2 = 0xc055
-+
 +; read
 +HW_SETDHIRES = 0xc05e
 +HW_SETIOUDIS = 0xc07e
@@ -41,6 +39,8 @@
 +HW_SET80VID = 0xc00d
 +.endif
 +
++.include /ucode_defs.inc/
++
 +      .globl  start
 +
        .area   zpage
  shape_20_bomb0:
        .db     0x5c                    ; 5c00 r
        .db     0x02                    ; 5c01 r
-@@ -21884,510 +22236,12 @@
+@@ -21884,510 +22236,15 @@
        .db     0xe0                    ; 8c05 r
        .db     0x83                    ; 8c06 r
        .db     0x9e                    ; 8c07 r
 +.if ALIGN
 +      .ds     0x8e00 - 0x4000 - (. - data0_start)
 +.endif
++.if UCODE
++.include /ucode_data.inc/
++.else
  ucode1080_countdown_30_pixel:
-       .db     0x30                    ; 8e00 r
-       .db     0x0f                    ; 8e01 r
-@@ -26958,31 +26812,308 @@
-       .db     0x7c                    ; 9dea r
-       .db     0x98                    ; 9deb r
+       .dw     0x0f30                  ; 8e00 r
+       .db     0x00                    ; 8e02 r
+@@ -25710,31 +25567,309 @@
+       .dw     0xf1f1                  ; 9de8 r
+       .dw     0x987c                  ; 9dea r
        .db     0x00                    ; 9dec r
 -recrack_loader:
 -      cld                             ; 09fd -> 9ded -> r
 -      lda     #>restart               ; 9e16 r
 -      sta     vec_restart + 1         ; 9e18 r
 -      jmp     start                   ; 9e1b r
++.endif
 +
 +.if DHGR ; move to here
 +sub_1e00:
  
        .area   udata2
  
-@@ -27065,3 +27196,4 @@
+@@ -25817,3 +25952,4 @@
  object6080_b560:
        .ds     0x20                    ; b560 rw
  
diff --git a/disasm/ucode_defs.inc b/disasm/ucode_defs.inc
new file mode 100644 (file)
index 0000000..96149fc
--- /dev/null
@@ -0,0 +1,355 @@
+; objects
+OBJECT_10_PIXEL = 0x10
+OBJECT_11_PIXEL = 0x11
+OBJECT_12_PIXEL = 0x12
+OBJECT_13_PIXEL = 0x13
+OBJECT_14_FRAGMENT = 0x14
+OBJECT_15_FRAGMENT = 0x15
+OBJECT_16_FRAGMENT = 0x16
+OBJECT_17_FRAGMENT = 0x17
+OBJECT_18_FRAGMENT = 0x18
+OBJECT_19_FRAGMENT = 0x19
+OBJECT_1A_FRAGMENT = 0x1a
+OBJECT_1B_FRAGMENT = 0x1b
+OBJECT_1C_FRAGMENT = 0x1c
+OBJECT_1D_FRAGMENT = 0x1d
+OBJECT_1E_FRAGMENT = 0x1e
+OBJECT_1F_FRAGMENT = 0x1f
+OBJECT_20_PIXEL = 0x20
+OBJECT_21_PIXEL = 0x21
+OBJECT_22_PIXEL = 0x22
+OBJECT_23_PIXEL = 0x23
+OBJECT_24_PIXEL = 0x24
+OBJECT_25_PIXEL = 0x25
+OBJECT_26_PIXEL = 0x26
+OBJECT_27_PIXEL = 0x27
+OBJECT_28_EXHAUST = 0x28
+OBJECT_29_PIXEL = 0x29
+OBJECT_2A_EXPLOSION = 0x2a
+OBJECT_2C_PIXEL = 0x2c
+OBJECT_2D_PIXEL = 0x2d
+OBJECT_2E_PIXEL = 0x2e
+OBJECT_2F_PIXEL = 0x2f
+OBJECT_30_PIXEL = 0x30
+OBJECT_31_PIXEL = 0x31
+OBJECT_32_PIXEL = 0x32
+OBJECT_33_PIXEL = 0x33
+OBJECT_34_PIXEL = 0x34
+OBJECT_35_PIXEL = 0x35
+OBJECT_36_PIXEL = 0x36
+OBJECT_37_PIXEL = 0x37
+OBJECT_38_PIXEL = 0x38
+OBJECT_39_PIXEL = 0x39
+OBJECT_3A_PIXEL = 0x3a
+OBJECT_3B_PIXEL = 0x3b
+OBJECT_3C_PIXEL = 0x3c
+OBJECT_3D_PIXEL = 0x3d
+OBJECT_40_BIRD = 0x40
+OBJECT_41_TREE_CACTUS = 0x41
+OBJECT_42_TREE_CACTUS = 0x42
+OBJECT_43_TREE_CACTUS = 0x43
+OBJECT_44_MISSILE_LAUNCHER = 0x44
+OBJECT_45_MISSILE_LAUNCHER = 0x45
+OBJECT_46_MISSILE_LAUNCHER = 0x46
+OBJECT_47_PYLON = 0x47
+OBJECT_48_PYLON = 0x48
+OBJECT_49_SILO = 0x49
+OBJECT_4A_SILO_HAYSTACK = 0x4a
+OBJECT_4B_HAYSTACK_HOUSE = 0x4b
+OBJECT_4C_SILO_HOUSE = 0x4c
+OBJECT_4D_HEADQUARTERS_RADAR_ICBM = 0x4d
+OBJECT_4E_PIXEL = 0x4e
+OBJECT_4F_PIXEL = 0x4f
+OBJECT_50_BULLET = 0x50
+OBJECT_51_BULLET = 0x51
+OBJECT_52_BULLET = 0x52
+OBJECT_53_PIXEL_BALLOON_EXPLOSION = 0x53
+OBJECT_54_PIXEL_BALLOON_EXPLOSION = 0x54
+OBJECT_55_PIXEL_BALLOON_EXPLOSION = 0x55
+OBJECT_56_PIXEL_BALLOON_EXPLOSION = 0x56
+OBJECT_57_PIXEL_BALLOON_EXPLOSION = 0x57
+OBJECT_58_BOMB_EXPLOSION = 0x58
+OBJECT_59_BOMB_EXPLOSION = 0x59
+OBJECT_5A_BOMB_EXPLOSION = 0x5a
+OBJECT_5B_BOMB_EXPLOSION = 0x5b
+OBJECT_5C_BOMB_EXPLOSION = 0x5c
+OBJECT_5D_BOMB_EXPLOSION = 0x5d
+OBJECT_5E_BOMB_EXPLOSION = 0x5e
+OBJECT_5F_BOMB_EXPLOSION = 0x5f
+OBJECT_60_PIXEL = 0x60
+OBJECT_61_SHIP = 0x61
+OBJECT_62_SHIP = 0x62
+OBJECT_63_PIXEL = 0x63
+OBJECT_64_PIXEL_SHIP = 0x64
+OBJECT_65_PIXEL_EXHAUST = 0x65
+OBJECT_66_SHIP = 0x66
+OBJECT_67_BIRD = 0x67
+OBJECT_68_MISSILE = 0x68
+OBJECT_69_MISSILE = 0x69
+OBJECT_6A_MISSILE = 0x6a
+OBJECT_6B_HELICOPTER_ENEMY_PLANE = 0x6b
+OBJECT_6C_HELICOPTER_ENEMY_PLANE = 0x6c
+OBJECT_6D_HELICOPTER_ENEMY_PLANE = 0x6d
+OBJECT_6E_HELICOPTER_ENEMY_PLANE = 0x6e
+OBJECT_6F_HELICOPTER_ENEMY_PLANE = 0x6f
+OBJECT_70_SUPPLY_PLANE = 0x70
+OBJECT_71_PARACHUTE = 0x71
+OBJECT_72_FUEL_EXPLOSION = 0x72
+OBJECT_73_BULLET = 0x73
+OBJECT_74_BULLET = 0x74
+OBJECT_75_BULLET = 0x75
+OBJECT_76_PIXEL = 0x76
+OBJECT_77_TANK = 0x77
+OBJECT_78_PIXEL = 0x78
+OBJECT_79_PIXEL = 0x79
+OBJECT_7A_PIXEL = 0x7a
+OBJECT_7B_PIXEL = 0x7b
+OBJECT_7C_PIXEL = 0x7c
+OBJECT_7D_PIXEL = 0x7d
+OBJECT_7E_PIXEL = 0x7e
+OBJECT_7F_PIXEL = 0x7f
+
+; shapes
+SHAPE_00_PIXEL0 = 0x00
+SHAPE_01_PIXEL1 = 0x01
+SHAPE_02_PIXEL2 = 0x02
+SHAPE_03_PIXEL3 = 0x03
+SHAPE_04_PIXEL4 = 0x04
+SHAPE_05_PIXEL5 = 0x05
+SHAPE_06_PIXEL6 = 0x06
+SHAPE_07_PIXEL7 = 0x07
+SHAPE_08_BULLET3 = 0x08
+SHAPE_09_BULLET5 = 0x09
+SHAPE_0A_BULLET7 = 0x0a
+SHAPE_0B_BULLET9 = 0x0b
+SHAPE_0C_BIRD0 = 0x0c
+SHAPE_0D_BIRD1 = 0x0d
+SHAPE_0E_BIRD2 = 0x0e
+SHAPE_0F_BIRD3 = 0x0f
+SHAPE_10_SHIP = 0x10
+SHAPE_11_SHIP_OPEN = 0x11
+SHAPE_12_EXHAUST0 = 0x12
+SHAPE_13_EXHAUST1 = 0x13
+SHAPE_14_PARACHUTE0 = 0x14
+SHAPE_15_PARACHUTE1 = 0x15
+SHAPE_16_PARACHUTE_OPEN = 0x16
+SHAPE_17_FUEL = 0x17
+SHAPE_18_SUPPLY_PLANE = 0x18
+SHAPE_1C_TANK = 0x1c
+SHAPE_1E_MISSILE_TANK = 0x1e
+SHAPE_1F_MISSILE_TANK_EMPTY = 0x1f
+SHAPE_20_BOMB0 = 0x20
+SHAPE_21_BOMB1 = 0x21
+SHAPE_22_BOMB2 = 0x22
+SHAPE_23_BOMB3 = 0x23
+SHAPE_28_BALLOON0 = 0x28
+SHAPE_29_BALLOON1 = 0x29
+SHAPE_2A_BALLOON2 = 0x2a
+SHAPE_2C_HELICOPTER = 0x2c
+SHAPE_2E_ENEMY_PLANE0 = 0x2e
+SHAPE_2F_ENEMY_PLANE1 = 0x2f
+SHAPE_30_SILO0 = 0x30
+SHAPE_31_SILO1 = 0x31
+SHAPE_36_PYLON = 0x36
+SHAPE_40_MISSILE0 = 0x40
+SHAPE_41_MISSILE1 = 0x41
+SHAPE_42_MISSILE2 = 0x42
+SHAPE_43_MISSILE3 = 0x43
+SHAPE_44_MISSILE4 = 0x44
+SHAPE_45_MISSILE5 = 0x45
+SHAPE_46_MISSILE6 = 0x46
+SHAPE_47_MISSILE7 = 0x47
+SHAPE_48_MISSILE8 = 0x48
+SHAPE_49_MISSILE9 = 0x49
+SHAPE_4A_MISSILE10 = 0x4a
+SHAPE_4B_MISSILE11 = 0x4b
+SHAPE_4C_MISSILE12 = 0x4c
+SHAPE_4D_MISSILE13 = 0x4d
+SHAPE_4E_MISSILE14 = 0x4e
+SHAPE_4F_MISSILE15 = 0x4f
+SHAPE_50_MISSILE_LAUNCHER0_EMPTY = 0x50
+SHAPE_51_MISSILE_LAUNCHER1_EMPTY = 0x51
+SHAPE_52_MISSILE_LAUNCHER2_EMPTY = 0x52
+SHAPE_54_MISSILE_LAUNCHER0 = 0x54
+SHAPE_55_MISSILE_LAUNCHER1 = 0x55
+SHAPE_56_MISSILE_LAUNCHER2 = 0x56
+SHAPE_60_FRAGMENT0 = 0x60
+SHAPE_61_FRAGMENT1 = 0x61
+SHAPE_62_FRAGMENT2 = 0x62
+SHAPE_63_FRAGMENT3 = 0x63
+SHAPE_64_FRAGMENT4 = 0x64
+SHAPE_65_FRAGMENT5 = 0x65
+SHAPE_66_FRAGMENT6 = 0x66
+SHAPE_67_FRAGMENT7 = 0x67
+SHAPE_70_HAYSTACK = 0x70
+SHAPE_71_HOUSE = 0x71
+SHAPE_72_HEADQUARTERS = 0x72
+SHAPE_73_RADAR0 = 0x73
+SHAPE_74_RADAR1 = 0x74
+SHAPE_75_RADAR2 = 0x75
+SHAPE_76_ICBM = 0x76
+SHAPE_78_TREE = 0x78
+SHAPE_79_CACTUS = 0x79
+SHAPE_88_EXPLOSION0 = 0x88
+SHAPE_89_EXPLOSION1 = 0x89
+SHAPE_8A_EXPLOSION2 = 0x8a
+SHAPE_8B_EXPLOSION3 = 0x8b
+SHAPE_A0_TEXT_0 = 0xa0
+SHAPE_A1_TEXT_1 = 0xa1
+SHAPE_A2_TEXT_2 = 0xa2
+SHAPE_A3_TEXT_3 = 0xa3
+SHAPE_A4_TEXT_4 = 0xa4
+SHAPE_A5_TEXT_5 = 0xa5
+SHAPE_A6_TEXT_6 = 0xa6
+SHAPE_A7_TEXT_7 = 0xa7
+SHAPE_A8_TEXT_8 = 0xa8
+SHAPE_A9_TEXT_9 = 0xa9
+SHAPE_AA_TEXT_SCORE = 0xaa
+SHAPE_AB_TEXT_COLON = 0xab
+SHAPE_AC_TEXT_HIGH = 0xac
+SHAPE_B0_TEXT_MISSION = 0xb0
+SHAPE_B2_TEXT_FUEL = 0xb2
+SHAPE_B3_TEXT_EMPTY = 0xb3
+SHAPE_B4_TEXT_BOMB = 0xb4
+SHAPE_B6_TEXT_SHIP_LEFT = 0xb6
+SHAPE_B7_TEXT_COMPLETE = 0xb7
+SHAPE_B8_TEXT_THE = 0xb8
+SHAPE_B9_TEXT_RADAR = 0xb9
+SHAPE_BA_TEXT_ICBM = 0xba
+SHAPE_BC_TEXT_ATTACK = 0xbc
+SHAPE_BD_TEXT_TANK = 0xbd
+SHAPE_BE_TEXT_HEADQUARTERS = 0xbe
+SHAPE_BF_TEXT_A = 0xbf
+SHAPE_C0_SHIPS0 = 0xc0
+SHAPE_C1_SHIPS1 = 0xc1
+SHAPE_C2_SHIPS2 = 0xc2
+SHAPE_C3_SHIPS3 = 0xc3
+SHAPE_D0_TEXT_STAR = 0xd0
+SHAPE_D1_TEXT_BLAZER = 0xd1
+SHAPE_D2_TEXT_BY = 0xd2
+SHAPE_D3_TEXT_TONY = 0xd3
+SHAPE_D4_TEXT_SUZUKI = 0xd4
+SHAPE_D8_TEXT_GAME = 0xd8
+SHAPE_D9_TEXT_OVER = 0xd9
+SHAPE_DA_TEXT_BONUS = 0xda
+SHAPE_DC_TEXT_GREAT = 0xdc
+SHAPE_DD_TEXT_PERFORMANCE = 0xdd
+SHAPE_E1_TEXT_COPYRIGHT = 0xe1
+SHAPE_E2_TEXT_STAR_CRAFT = 0xe2
+SHAPE_E3_TEXT_INC = 0xe3
+SHAPE_E4_TEXT_THANKS = 0xe4
+SHAPE_E5_TEXT_LOT_COMMA = 0xe5
+SHAPE_E6_TEXT_RALY = 0xe6
+SHAPE_E7_TEXT_MINUS_20 = 0xe7
+SHAPE_E8_TEXT_20_40_60_80 = 0xe8
+SHAPE_E9_TEXT_100_120_300_1500 = 0xe9
+SHAPE_F0_GROUND0 = 0xf0
+SHAPE_F1_GROUND1 = 0xf1
+SHAPE_F2_GROUND2 = 0xf2
+SHAPE_F3_GROUND3 = 0xf3
+SHAPE_FF_BLANK = 0xff
+
+; ucode sections
+
+; these occur in byte-wide tables
+UCODE_SECTION_F0 = 0xf0
+UCODE_SECTION_F1 = 0xf1
+UCODE_SECTION_F2 = 0xf2
+UCODE_SECTION_F3 = 0xf3
+UCODE_SECTION_F8_REPEAT = 0xf8
+UCODE_SECTION_F9_REPEAT = 0xf9
+UCODE_SECTION_FA_REPEAT = 0xfa
+UCODE_SECTION_FB_REPEAT = 0xfb
+UCODE_SECTION_FF = 0xff
+
+; these occur in word-wide tables
+UCODE_SECTION_F0F0 = 0xf0f0
+UCODE_SECTION_F1F1 = 0xf1f1
+UCODE_SECTION_F2F2 = 0xf2f2
+UCODE_SECTION_F3F3 = 0xf3f3
+
+; ucode 1st byte (escape) bit 0
+UCODE_0001_IF_DEMO = 0x0001
+
+; ucode 1st byte (escape) bit1
+UCODE_0002_IF_NOT_DEMO = 0x0002
+
+; ucode 1st byte (escape) bits 2 to 7
+UCODE_0000_CONTROL_GAME = 0x0000
+UCODE_0004_SET_DECIMAL = 0x0004
+UCODE_0008_TITLE_DISPLAY = 0x0008
+UCODE_000C_SOUND_CHANNEL = 0x000c
+
+; ucode 2nd byte under a given ucode escape
+UCODE_CONTROL_GAME_0000_CLEAR_DEMO_SET_MISSION = 0x0000
+UCODE_CONTROL_GAME_2000_SET_DEMO_SET_MISSION = 0x2000
+UCODE_CONTROL_GAME_4000_START_GAME = 0x4000
+UCODE_CONTROL_GAME_A000_START_GAME_DEMO = 0xa000
+
+UCODE_SET_DECIMAL_0000_0 = 0x0000
+UCODE_SET_DECIMAL_0100_0 = 0x0100
+UCODE_SET_DECIMAL_0200_SCORE_VAR_4B80_SCORE_VAR_4B00_BY_MISSION = 0x0200
+UCODE_SET_DECIMAL_0300_1 = 0x0300
+UCODE_SET_DECIMAL_0400_SCORE_VAR_4880_SCORE_VAR_4800 = 0x0400
+UCODE_SET_DECIMAL_0500_SCORE_VAR_4980_SCORE_VAR_4900 = 0x0500
+UCODE_SET_DECIMAL_0600_SCORE_VAR_4A80_SCORE_VAR_4A00 = 0x0600
+UCODE_SET_DECIMAL_0700_SCORE_VAR_4B80_SCORE_VAR_4B00 = 0x0700
+
+UCODE_TITLE_DISPLAY_E100_RESTART = 0xe100
+UCODE_TITLE_DISPLAY_E200_CLEAR_RECTANGLE = 0xe200
+
+UCODE_SOUND_CHANNEL_0100_00 = 0x0100
+UCODE_SOUND_CHANNEL_0200_01 = 0x0200
+UCODE_SOUND_CHANNEL_0300_02 = 0x0300
+UCODE_SOUND_CHANNEL_0400_03 = 0x0400
+UCODE_SOUND_CHANNEL_0500_04 = 0x0500
+UCODE_SOUND_CHANNEL_0600_05 = 0x0600
+UCODE_SOUND_CHANNEL_0700_06 = 0x0700
+UCODE_SOUND_CHANNEL_0800_07 = 0x0800
+UCODE_SOUND_CHANNEL_0900_08 = 0x0900
+UCODE_SOUND_CHANNEL_0A00_09 = 0x0a00
+UCODE_SOUND_CHANNEL_0B00_0A = 0x0b00
+UCODE_SOUND_CHANNEL_0C00_0B = 0x0c00
+UCODE_SOUND_CHANNEL_0D00_0C = 0x0d00
+UCODE_SOUND_CHANNEL_0E00_0D = 0x0e00
+UCODE_SOUND_CHANNEL_0F00_0E = 0x0f00
+UCODE_SOUND_CHANNEL_1000_0F = 0x1000
+
+; the following occur by themselves
+
+; ucode 2nd byte
+UCODE_0800_HORIZONTAL_COLLISION_AND_ZERO = 0x0800
+UCODE_0900_VERTICAL_COLLISION_AND_ZERO = 0x0900
+UCODE_0A00_HORIZONTAL_COLLISION = 0x0a00
+UCODE_0B00_VERTICAL_COLLISION = 0x0b00
+UCODE_0C00_HORIZONTAL_COLLISION_AND_COPY = 0x0c00
+UCODE_0D00_VERTICAL_COLLISION_AND_COPY = 0x0d00
+UCODE_0F00_INACTIVATE_OBJECT = 0x0f00
+
+; the following are used with UCODE_(0|8)000_UPDATE_OBJECT(_IF_INACTIVE)
+
+; ucode 2nd byte bits 0 to 2
+UCODE_0100_RANDOMIZE_OBJECT_VELOCITY = 0x0100
+UCODE_0200_COPY_OBJECT_VELOCITY = 0x0200
+UCODE_0300_RANDOMIZE_OBJECT_VELOCITY_RELATIVE = 0x0300
+UCODE_0400_UPDATE_OBJECT_VELOCITY = 0x0400
+UCODE_0500_UPDATE_OBJECT_VELOCITY_ROTATE_90 = 0x0500
+UCODE_0600_UPDATE_OBJECT_VELOCITY_ROTATE_180 = 0x0600
+UCODE_0700_UPDATE_OBJECT_VELOCITY_ROTATE_270 = 0x0700
+
+; ucode 2nd byte bit 3
+UCODE_0000_RESET_OBJECT = 0x0000
+UCODE_0800_ACTIVATE_OBJECT = 0x0800
+
+; ucode 2nd byte bits 4 to 6
+UCODE_1000_RANDOMIZE_OBJECT_POSITION = 0x1000
+UCODE_2000_COPY_OBJECT_POSITION = 0x2000
+UCODE_3000_RANDOMIZE_OBJECT_POSITION_RELATIVE = 0x3000
+UCODE_4000_MOVE_OBJECT_POS_POS = 0x4000
+UCODE_5000_MOVE_OBJECT_NEG_POS = 0x5000
+UCODE_6000_MOVE_OBJECT_NEG_NEG = 0x6000
+UCODE_7000_MOVE_OBJECT_POS_NEG = 0x7000
+
+; ucode 2nd byte bit 7
+UCODE_0000_UPDATE_OBJECT_IF_INACTIVE = 0x0000
+UCODE_8000_UPDATE_OBJECT = 0x8000
diff --git a/disasm/ucode_disasm.py b/disasm/ucode_disasm.py
new file mode 100755 (executable)
index 0000000..52bffbe
--- /dev/null
@@ -0,0 +1,427 @@
+#!/usr/bin/env python3
+
+import sys
+
+objects = {
+  0x10: 'OBJECT_10_PIXEL',
+  0x11: 'OBJECT_11_PIXEL',
+  0x12: 'OBJECT_12_PIXEL',
+  0x13: 'OBJECT_13_PIXEL',
+  0x14: 'OBJECT_14_FRAGMENT',
+  0x15: 'OBJECT_15_FRAGMENT',
+  0x16: 'OBJECT_16_FRAGMENT',
+  0x17: 'OBJECT_17_FRAGMENT',
+  0x18: 'OBJECT_18_FRAGMENT',
+  0x19: 'OBJECT_19_FRAGMENT',
+  0x1a: 'OBJECT_1A_FRAGMENT',
+  0x1b: 'OBJECT_1B_FRAGMENT',
+  0x1c: 'OBJECT_1C_FRAGMENT',
+  0x1d: 'OBJECT_1D_FRAGMENT',
+  0x1e: 'OBJECT_1E_FRAGMENT',
+  0x1f: 'OBJECT_1F_FRAGMENT',
+  0x20: 'OBJECT_20_PIXEL',
+  0x21: 'OBJECT_21_PIXEL',
+  0x22: 'OBJECT_22_PIXEL',
+  0x23: 'OBJECT_23_PIXEL',
+  0x24: 'OBJECT_24_PIXEL',
+  0x25: 'OBJECT_25_PIXEL',
+  0x26: 'OBJECT_26_PIXEL',
+  0x27: 'OBJECT_27_PIXEL',
+  0x28: 'OBJECT_28_EXHAUST',
+  0x29: 'OBJECT_29_PIXEL',
+  0x2a: 'OBJECT_2A_EXPLOSION',
+  0x2c: 'OBJECT_2C_PIXEL',
+  0x2d: 'OBJECT_2D_PIXEL',
+  0x2e: 'OBJECT_2E_PIXEL',
+  0x2f: 'OBJECT_2F_PIXEL',
+  0x30: 'OBJECT_30_PIXEL',
+  0x31: 'OBJECT_31_PIXEL',
+  0x32: 'OBJECT_32_PIXEL',
+  0x33: 'OBJECT_33_PIXEL',
+  0x34: 'OBJECT_34_PIXEL',
+  0x35: 'OBJECT_35_PIXEL',
+  0x36: 'OBJECT_36_PIXEL',
+  0x37: 'OBJECT_37_PIXEL',
+  0x38: 'OBJECT_38_PIXEL',
+  0x39: 'OBJECT_39_PIXEL',
+  0x3a: 'OBJECT_3A_PIXEL',
+  0x3b: 'OBJECT_3B_PIXEL',
+  0x3c: 'OBJECT_3C_PIXEL',
+  0x3d: 'OBJECT_3D_PIXEL',
+  0x40: 'OBJECT_40_BIRD',
+  0x41: 'OBJECT_41_TREE_CACTUS',
+  0x42: 'OBJECT_42_TREE_CACTUS',
+  0x43: 'OBJECT_43_TREE_CACTUS',
+  0x44: 'OBJECT_44_MISSILE_LAUNCHER',
+  0x45: 'OBJECT_45_MISSILE_LAUNCHER',
+  0x46: 'OBJECT_46_MISSILE_LAUNCHER',
+  0x47: 'OBJECT_47_PYLON',
+  0x48: 'OBJECT_48_PYLON',
+  0x49: 'OBJECT_49_SILO',
+  0x4a: 'OBJECT_4A_SILO_HAYSTACK',
+  0x4b: 'OBJECT_4B_HAYSTACK_HOUSE',
+  0x4c: 'OBJECT_4C_SILO_HOUSE',
+  0x4d: 'OBJECT_4D_HEADQUARTERS_RADAR_ICBM',
+  0x4e: 'OBJECT_4E_PIXEL',
+  0x4f: 'OBJECT_4F_PIXEL',
+  0x50: 'OBJECT_50_BULLET',
+  0x51: 'OBJECT_51_BULLET',
+  0x52: 'OBJECT_52_BULLET',
+  0x53: 'OBJECT_53_PIXEL_BALLOON_EXPLOSION',
+  0x54: 'OBJECT_54_PIXEL_BALLOON_EXPLOSION',
+  0x55: 'OBJECT_55_PIXEL_BALLOON_EXPLOSION',
+  0x56: 'OBJECT_56_PIXEL_BALLOON_EXPLOSION',
+  0x57: 'OBJECT_57_PIXEL_BALLOON_EXPLOSION',
+  0x58: 'OBJECT_58_BOMB_EXPLOSION',
+  0x59: 'OBJECT_59_BOMB_EXPLOSION',
+  0x5a: 'OBJECT_5A_BOMB_EXPLOSION',
+  0x5b: 'OBJECT_5B_BOMB_EXPLOSION',
+  0x5c: 'OBJECT_5C_BOMB_EXPLOSION',
+  0x5d: 'OBJECT_5D_BOMB_EXPLOSION',
+  0x5e: 'OBJECT_5E_BOMB_EXPLOSION',
+  0x5f: 'OBJECT_5F_BOMB_EXPLOSION',
+  0x60: 'OBJECT_60_PIXEL',
+  0x61: 'OBJECT_61_SHIP',
+  0x62: 'OBJECT_62_SHIP',
+  0x63: 'OBJECT_63_PIXEL',
+  0x64: 'OBJECT_64_PIXEL_SHIP',
+  0x65: 'OBJECT_65_PIXEL_EXHAUST',
+  0x66: 'OBJECT_66_SHIP',
+  0x67: 'OBJECT_67_BIRD',
+  0x68: 'OBJECT_68_MISSILE',
+  0x69: 'OBJECT_69_MISSILE',
+  0x6a: 'OBJECT_6A_MISSILE',
+  0x6b: 'OBJECT_6B_HELICOPTER_ENEMY_PLANE',
+  0x6c: 'OBJECT_6C_HELICOPTER_ENEMY_PLANE',
+  0x6d: 'OBJECT_6D_HELICOPTER_ENEMY_PLANE',
+  0x6e: 'OBJECT_6E_HELICOPTER_ENEMY_PLANE',
+  0x6f: 'OBJECT_6F_HELICOPTER_ENEMY_PLANE',
+  0x70: 'OBJECT_70_SUPPLY_PLANE',
+  0x71: 'OBJECT_71_PARACHUTE',
+  0x72: 'OBJECT_72_FUEL_EXPLOSION',
+  0x73: 'OBJECT_73_BULLET',
+  0x74: 'OBJECT_74_BULLET',
+  0x75: 'OBJECT_75_BULLET',
+  0x76: 'OBJECT_76_PIXEL',
+  0x77: 'OBJECT_77_TANK',
+  0x78: 'OBJECT_78_PIXEL',
+  0x79: 'OBJECT_79_PIXEL',
+  0x7a: 'OBJECT_7A_PIXEL',
+  0x7b: 'OBJECT_7B_PIXEL',
+  0x7c: 'OBJECT_7C_PIXEL',
+  0x7d: 'OBJECT_7D_PIXEL',
+  0x7e: 'OBJECT_7E_PIXEL',
+  0x7f: 'OBJECT_7F_PIXEL',
+}
+
+shapes = {
+  0x00: 'SHAPE_00_PIXEL0',
+  0x01: 'SHAPE_01_PIXEL1',
+  0x02: 'SHAPE_02_PIXEL2',
+  0x03: 'SHAPE_03_PIXEL3',
+  0x04: 'SHAPE_04_PIXEL4',
+  0x05: 'SHAPE_05_PIXEL5',
+  0x06: 'SHAPE_06_PIXEL6',
+  0x07: 'SHAPE_07_PIXEL7',
+  0x08: 'SHAPE_08_BULLET3',
+  0x09: 'SHAPE_09_BULLET5',
+  0x0a: 'SHAPE_0A_BULLET7',
+  0x0b: 'SHAPE_0B_BULLET9',
+  0x0c: 'SHAPE_0C_BIRD0',
+  0x0d: 'SHAPE_0D_BIRD1',
+  0x0e: 'SHAPE_0E_BIRD2',
+  0x0f: 'SHAPE_0F_BIRD3',
+  0x10: 'SHAPE_10_SHIP',
+  0x11: 'SHAPE_11_SHIP_OPEN',
+  0x12: 'SHAPE_12_EXHAUST0',
+  0x13: 'SHAPE_13_EXHAUST1',
+  0x14: 'SHAPE_14_PARACHUTE0',
+  0x15: 'SHAPE_15_PARACHUTE1',
+  0x16: 'SHAPE_16_PARACHUTE_OPEN',
+  0x17: 'SHAPE_17_FUEL',
+  0x18: 'SHAPE_18_SUPPLY_PLANE',
+  0x1c: 'SHAPE_1C_TANK',
+  0x1e: 'SHAPE_1E_MISSILE_TANK',
+  0x1f: 'SHAPE_1F_MISSILE_TANK_EMPTY',
+  0x20: 'SHAPE_20_BOMB0',
+  0x21: 'SHAPE_21_BOMB1',
+  0x22: 'SHAPE_22_BOMB2',
+  0x23: 'SHAPE_23_BOMB3',
+  0x28: 'SHAPE_28_BALLOON0',
+  0x29: 'SHAPE_29_BALLOON1',
+  0x2a: 'SHAPE_2A_BALLOON2',
+  0x2c: 'SHAPE_2C_HELICOPTER',
+  0x2e: 'SHAPE_2E_ENEMY_PLANE0',
+  0x2f: 'SHAPE_2F_ENEMY_PLANE1',
+  0x30: 'SHAPE_30_SILO0',
+  0x31: 'SHAPE_31_SILO1',
+  0x36: 'SHAPE_36_PYLON',
+  0x40: 'SHAPE_40_MISSILE0',
+  0x41: 'SHAPE_41_MISSILE1',
+  0x42: 'SHAPE_42_MISSILE2',
+  0x43: 'SHAPE_43_MISSILE3',
+  0x44: 'SHAPE_44_MISSILE4',
+  0x45: 'SHAPE_45_MISSILE5',
+  0x46: 'SHAPE_46_MISSILE6',
+  0x47: 'SHAPE_47_MISSILE7',
+  0x48: 'SHAPE_48_MISSILE8',
+  0x49: 'SHAPE_49_MISSILE9',
+  0x4a: 'SHAPE_4A_MISSILE10',
+  0x4b: 'SHAPE_4B_MISSILE11',
+  0x4c: 'SHAPE_4C_MISSILE12',
+  0x4d: 'SHAPE_4D_MISSILE13',
+  0x4e: 'SHAPE_4E_MISSILE14',
+  0x4f: 'SHAPE_4F_MISSILE15',
+  0x50: 'SHAPE_50_MISSILE_LAUNCHER0_EMPTY',
+  0x51: 'SHAPE_51_MISSILE_LAUNCHER1_EMPTY',
+  0x52: 'SHAPE_52_MISSILE_LAUNCHER2_EMPTY',
+  0x54: 'SHAPE_54_MISSILE_LAUNCHER0',
+  0x55: 'SHAPE_55_MISSILE_LAUNCHER1',
+  0x56: 'SHAPE_56_MISSILE_LAUNCHER2',
+  0x60: 'SHAPE_60_FRAGMENT0',
+  0x61: 'SHAPE_61_FRAGMENT1',
+  0x62: 'SHAPE_62_FRAGMENT2',
+  0x63: 'SHAPE_63_FRAGMENT3',
+  0x64: 'SHAPE_64_FRAGMENT4',
+  0x65: 'SHAPE_65_FRAGMENT5',
+  0x66: 'SHAPE_66_FRAGMENT6',
+  0x67: 'SHAPE_67_FRAGMENT7',
+  0x70: 'SHAPE_70_HAYSTACK',
+  0x71: 'SHAPE_71_HOUSE',
+  0x72: 'SHAPE_72_HEADQUARTERS',
+  0x73: 'SHAPE_73_RADAR0',
+  0x74: 'SHAPE_74_RADAR1',
+  0x75: 'SHAPE_75_RADAR2',
+  0x76: 'SHAPE_76_ICBM',
+  0x78: 'SHAPE_78_TREE',
+  0x79: 'SHAPE_79_CACTUS',
+  0x88: 'SHAPE_88_EXPLOSION0',
+  0x89: 'SHAPE_89_EXPLOSION1',
+  0x8a: 'SHAPE_8A_EXPLOSION2',
+  0x8b: 'SHAPE_8B_EXPLOSION3',
+  0xa0: 'SHAPE_A0_TEXT_0',
+  0xa1: 'SHAPE_A1_TEXT_1',
+  0xa2: 'SHAPE_A2_TEXT_2',
+  0xa3: 'SHAPE_A3_TEXT_3',
+  0xa4: 'SHAPE_A4_TEXT_4',
+  0xa5: 'SHAPE_A5_TEXT_5',
+  0xa6: 'SHAPE_A6_TEXT_6',
+  0xa7: 'SHAPE_A7_TEXT_7',
+  0xa8: 'SHAPE_A8_TEXT_8',
+  0xa9: 'SHAPE_A9_TEXT_9',
+  0xaa: 'SHAPE_AA_TEXT_SCORE',
+  0xab: 'SHAPE_AB_TEXT_COLON',
+  0xac: 'SHAPE_AC_TEXT_HIGH',
+  0xb0: 'SHAPE_B0_TEXT_MISSION',
+  0xb2: 'SHAPE_B2_TEXT_FUEL',
+  0xb3: 'SHAPE_B3_TEXT_EMPTY',
+  0xb4: 'SHAPE_B4_TEXT_BOMB',
+  0xb6: 'SHAPE_B6_TEXT_SHIP_LEFT',
+  0xb7: 'SHAPE_B7_TEXT_COMPLETE',
+  0xb8: 'SHAPE_B8_TEXT_THE',
+  0xb9: 'SHAPE_B9_TEXT_RADAR',
+  0xba: 'SHAPE_BA_TEXT_ICBM',
+  0xbc: 'SHAPE_BC_TEXT_ATTACK',
+  0xbd: 'SHAPE_BD_TEXT_TANK',
+  0xbe: 'SHAPE_BE_TEXT_HEADQUARTERS',
+  0xbf: 'SHAPE_BF_TEXT_A',
+  0xc0: 'SHAPE_C0_SHIPS0',
+  0xc1: 'SHAPE_C1_SHIPS1',
+  0xc2: 'SHAPE_C2_SHIPS2',
+  0xc3: 'SHAPE_C3_SHIPS3',
+  0xd0: 'SHAPE_D0_TEXT_STAR',
+  0xd1: 'SHAPE_D1_TEXT_BLAZER',
+  0xd2: 'SHAPE_D2_TEXT_BY',
+  0xd3: 'SHAPE_D3_TEXT_TONY',
+  0xd4: 'SHAPE_D4_TEXT_SUZUKI',
+  0xd8: 'SHAPE_D8_TEXT_GAME',
+  0xd9: 'SHAPE_D9_TEXT_OVER',
+  0xda: 'SHAPE_DA_TEXT_BONUS',
+  0xdc: 'SHAPE_DC_TEXT_GREAT',
+  0xdd: 'SHAPE_DD_TEXT_PERFORMANCE',
+  0xe1: 'SHAPE_E1_TEXT_COPYRIGHT',
+  0xe2: 'SHAPE_E2_TEXT_STAR_CRAFT',
+  0xe3: 'SHAPE_E3_TEXT_INC',
+  0xe4: 'SHAPE_E4_TEXT_THANKS',
+  0xe5: 'SHAPE_E5_TEXT_LOT_COMMA',
+  0xe6: 'SHAPE_E6_TEXT_RALY',
+  0xe7: 'SHAPE_E7_TEXT_MINUS_20',
+  0xe8: 'SHAPE_E8_TEXT_20_40_60_80',
+  0xe9: 'SHAPE_E9_TEXT_100_120_300_1500',
+  0xf0: 'SHAPE_F0_GROUND0',
+  0xf1: 'SHAPE_F1_GROUND1',
+  0xf2: 'SHAPE_F2_GROUND2',
+  0xf3: 'SHAPE_F3_GROUND3',
+  0xff: 'SHAPE_FF_BLANK',
+}
+
+ucode_sections_db = {
+  0xf0: 'UCODE_SECTION_F0',
+  0xf1: 'UCODE_SECTION_F1',
+  0xf2: 'UCODE_SECTION_F2',
+  0xf3: 'UCODE_SECTION_F3',
+  0xf8: 'UCODE_SECTION_F8_REPEAT',
+  0xf9: 'UCODE_SECTION_F9_REPEAT',
+  0xfa: 'UCODE_SECTION_FA_REPEAT',
+  0xfb: 'UCODE_SECTION_FB_REPEAT',
+  0xff: 'UCODE_SECTION_FF',
+}
+
+ucode_sections_dw = {
+  0xf0f0: 'UCODE_SECTION_F0F0',
+  0xf1f1: 'UCODE_SECTION_F1F1',
+  0xf2f2: 'UCODE_SECTION_F2F2',
+  0xf3f3: 'UCODE_SECTION_F3F3',
+}
+
+ucode_escape_bit_0 = {
+  0x0001: ' | UCODE_0001_IF_DEMO',
+}
+
+ucode_escape_bit_1 = {
+  0x0002: ' | UCODE_0002_IF_NOT_DEMO',
+}
+
+ucode_escape_bits_2_to_7 = {
+  0x0000: ' | UCODE_0000_CONTROL_GAME',
+  0x0004: ' | UCODE_0004_SET_DECIMAL',
+  0x0008: ' | UCODE_0008_TITLE_DISPLAY',
+  0x000c: ' | UCODE_000C_SOUND_CHANNEL',
+}
+
+ucode_control_game = {
+  0x0000: ' | UCODE_CONTROL_GAME_0000_CLEAR_DEMO_SET_MISSION',
+  0x2000: ' | UCODE_CONTROL_GAME_2000_SET_DEMO_SET_MISSION',
+  0x4000: ' | UCODE_CONTROL_GAME_4000_START_GAME',
+  0xa000: ' | UCODE_CONTROL_GAME_A000_START_GAME_DEMO',
+}
+
+ucode_set_decimal = {
+  0x0000: ' | UCODE_SET_DECIMAL_0000_0',
+  0x0100: ' | UCODE_SET_DECIMAL_0100_0',
+  0x0200: ' | UCODE_SET_DECIMAL_0200_SCORE_VAR_4B80_SCORE_VAR_4B00_BY_MISSION',
+  0x0300: ' | UCODE_SET_DECIMAL_0300_1',
+  0x0400: ' | UCODE_SET_DECIMAL_0400_SCORE_VAR_4880_SCORE_VAR_4800',
+  0x0500: ' | UCODE_SET_DECIMAL_0500_SCORE_VAR_4980_SCORE_VAR_4900',
+  0x0600: ' | UCODE_SET_DECIMAL_0600_SCORE_VAR_4A80_SCORE_VAR_4A00',
+  0x0700: ' | UCODE_SET_DECIMAL_0700_SCORE_VAR_4B80_SCORE_VAR_4B00',
+}
+
+ucode_title_display = {
+  0xe100: ' | UCODE_TITLE_DISPLAY_E100_RESTART',
+  0xe200: ' | UCODE_TITLE_DISPLAY_E200_CLEAR_RECTANGLE',
+}
+
+ucode_sound_channel = {
+  0x0100: ' | UCODE_SOUND_CHANNEL_0100_00',
+  0x0200: ' | UCODE_SOUND_CHANNEL_0200_01',
+  0x0300: ' | UCODE_SOUND_CHANNEL_0300_02',
+  0x0400: ' | UCODE_SOUND_CHANNEL_0400_03',
+  0x0500: ' | UCODE_SOUND_CHANNEL_0500_04',
+  0x0600: ' | UCODE_SOUND_CHANNEL_0600_05',
+  0x0700: ' | UCODE_SOUND_CHANNEL_0700_06',
+  0x0800: ' | UCODE_SOUND_CHANNEL_0800_07',
+  0x0900: ' | UCODE_SOUND_CHANNEL_0900_08',
+  0x0a00: ' | UCODE_SOUND_CHANNEL_0A00_09',
+  0x0b00: ' | UCODE_SOUND_CHANNEL_0B00_0A',
+  0x0c00: ' | UCODE_SOUND_CHANNEL_0C00_0B',
+  0x0d00: ' | UCODE_SOUND_CHANNEL_0D00_0C',
+  0x0e00: ' | UCODE_SOUND_CHANNEL_0E00_0D',
+  0x0f00: ' | UCODE_SOUND_CHANNEL_0F00_0E',
+  0x1000: ' | UCODE_SOUND_CHANNEL_1000_0F',
+}
+
+ucode_byte = {
+  0x0800: ' | UCODE_0800_HORIZONTAL_COLLISION_AND_ZERO',
+  0x0900: ' | UCODE_0900_VERTICAL_COLLISION_AND_ZERO',
+  0x0a00: ' | UCODE_0A00_HORIZONTAL_COLLISION',
+  0x0b00: ' | UCODE_0B00_VERTICAL_COLLISION',
+  0x0c00: ' | UCODE_0C00_HORIZONTAL_COLLISION_AND_COPY',
+  0x0d00: ' | UCODE_0D00_VERTICAL_COLLISION_AND_COPY',
+  0x0f00: ' | UCODE_0F00_INACTIVATE_OBJECT',
+}
+
+ucode_update_bits_0_to_2 = {
+  0x0100: ' | UCODE_0100_RANDOMIZE_OBJECT_VELOCITY',
+  0x0200: ' | UCODE_0200_COPY_OBJECT_VELOCITY',
+  0x0300: ' | UCODE_0300_RANDOMIZE_OBJECT_VELOCITY_RELATIVE',
+  0x0400: ' | UCODE_0400_UPDATE_OBJECT_VELOCITY',
+  0x0500: ' | UCODE_0500_UPDATE_OBJECT_VELOCITY_ROTATE_90',
+  0x0600: ' | UCODE_0600_UPDATE_OBJECT_VELOCITY_ROTATE_180',
+  0x0700: ' | UCODE_0700_UPDATE_OBJECT_VELOCITY_ROTATE_270',
+}
+ucode_update_bit_3 = {
+  0x0000: ' | UCODE_0000_RESET_OBJECT',
+  0x0800: ' | UCODE_0800_ACTIVATE_OBJECT',
+}
+ucode_update_bits_4_to_6 = {
+  0x1000: ' | UCODE_1000_RANDOMIZE_OBJECT_POSITION',
+  0x2000: ' | UCODE_2000_COPY_OBJECT_POSITION',
+  0x3000: ' | UCODE_3000_RANDOMIZE_OBJECT_POSITION_RELATIVE',
+  0x4000: ' | UCODE_4000_MOVE_OBJECT_POS_POS',
+  0x5000: ' | UCODE_5000_MOVE_OBJECT_NEG_POS',
+  0x6000: ' | UCODE_6000_MOVE_OBJECT_NEG_NEG',
+  0x7000: ' | UCODE_7000_MOVE_OBJECT_POS_NEG',
+}
+ucode_update_bit_7 = {
+  0x0000: ' | UCODE_0000_UPDATE_OBJECT_IF_INACTIVE',
+  0x8000: ' | UCODE_8000_UPDATE_OBJECT',
+}
+
+for line in sys.stdin:
+  fields = line.rstrip().split()
+  if len(fields) == 1:
+    label = fields[0]
+    assert label[-1:] == ':'
+    label = label[:-1]
+    sys.stdout.write(f'{label:s}:\n')
+  elif fields[0] == '.db':
+    assert fields[1][:2] == '0x'
+    value = int(fields[1][2:], 16)
+    if value == 0:
+      text = '0'
+    elif value in ucode_sections_db:
+      text = ucode_sections_db[value]
+    elif label[:24] == 'ucode1080_animate_shape_':
+      text = shapes[value]
+    elif label[:25] == 'ucode1080_collision_test_':
+      text = objects[value]
+    else:
+      assert False
+    sys.stdout.write(f'\t.db\t{text:s}\n')
+  elif fields[0] == '.dw':
+    assert fields[1][:2] == '0x'
+    value = int(fields[1][2:], 16)
+    if value in ucode_sections_dw:
+      text = ucode_sections_dw[value]
+    elif (value & 0xff) < 0x10: # escapes
+      text = '0'
+      text += ucode_escape_bit_0.get(value & 1, '')
+      text += ucode_escape_bit_1.get(value & 2, '')
+      bits_2_to_7 = value & 0xfc
+      text += ucode_escape_bits_2_to_7.get(bits_2_to_7, ' | ' + hex(bits_2_to_7))
+      value &= 0xff00
+      if bits_2_to_7 == 0:
+        text += ucode_control_game.get(value, ' | ' + hex(value))
+      elif bits_2_to_7 == 4:
+        text += ucode_set_decimal.get(value, ' | ' + hex(value))
+      elif bits_2_to_7 == 8:
+        text += ucode_title_display.get(value, ' | ' + hex(value))
+      elif bits_2_to_7 == 0xc:
+        text += ucode_sound_channel.get(value, ' | ' + hex(value))
+      if text[:4] == '0 | ':
+        text = text[4:]
+    else:
+      object = value & 0xff
+      text = objects.get(object, hex(object))
+      value &= 0xff00
+      if value in ucode_byte:
+        text += ucode_byte.get(value, '')
+      else:
+        text += ucode_update_bits_0_to_2.get(value & 0x700, '')
+        text += ucode_update_bit_3.get(value & 0x800, '')
+        text += ucode_update_bits_4_to_6.get(value & 0x7000, '')
+        text += ucode_update_bit_7.get(value & 0x8000, '')
+    sys.stdout.write(f'\t.dw\t{text:s}\n')
+  else:
+    assert False