@@ 1,5 1,5 @@
/*
- * Copyright (c) 2011-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ * Copyright (c) 2011-2021 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ 25,132 25,121 @@
#include <string.h>
#include <sys/stat.h>
-static char *deck_head =
-"#\n"
-"# NOTE: This file was automatically generated by " __FILE__ "\n"
-"#\n"
-"# During the system IPL, 24 bytes are read from the device.\n"
-"#\n"
-"# NOTE: zArch IPLs in ESA/390 mode.\n"
+#define PAD_LINE \
+ " .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n"
+
+#define DECK_HEAD \
+"#\n" \
+"# NOTE: This file was automatically generated by " __FILE__ "\n" \
+"#\n" \
+"# During the system IPL, 24 bytes are read from the device.\n" \
+"#\n" \
+"# NOTE: zArch IPLs in ESA/390 mode.\n" \
+"#\n" \
+"\n" \
+".text\n" \
+" .align 4\n" \
+".globl START\n" \
+" .type START, @function\n" \
+"START:\n"
+
+#define PSW_HEAD \
+"#\n" \
+"# Bytes 0-7 contain PSW to be loaded after IO operation completes\n" \
"#\n"
-"\n"
-".text\n"
-" .align 4\n"
-".globl START\n"
-" .type START, @function\n"
-"START:\n";
-
-static char *card_head =
-"\n"
-"#######################################################################\n"
-"# CARD %-3d #\n"
-"#######################################################################\n";
-
-static char *psw_head =
-"#\n"
-"# Bytes 0-7 contain PSW to be loaded after IO operation completes\n"
-"#\n";
-static char *psw =
-" .byte 0x%c%c\n"
-" # bits value name desc\n"
-" # 0 0 <zero>\n"
-" # 1 0 PER Mask (R) disabled\n"
-" # 2-4 0 <zero>\n"
-" # 5 0 DAT Mode (T) disabled\n"
-" # 6 0 I/O Mask (IO) disabled\n"
-" # 7 0 External Mask (EX) disabled\n"
-"\n"
-" .byte 0x%c%c\n"
-" # bits value name desc\n"
-" # 8-11 0 Key\n"
-" # 12 1 <one>\n"
-" # 13 0 Machine-Check Mask (M) disabled\n"
-" # 14 0 Wait State (W) executing\n"
-" # 15 0 Problem State (P) supervisor state\n"
-"\n"
-" .byte 0x%c%c\n"
-" # bits value name desc\n"
-" # 16-17 0 Address-Space Control (AS) disabled\n"
-" # 18-19 0 Condition Code (CC)\n"
-" # 20-23 0 Program Mask exceptions disabled\n"
-"\n"
-" .byte 0x%c%c\n"
-" # bits value name desc\n"
-" # 24-30 0 <zero>\n"
-" # 31 0 Extended Addressing (EA) ! 64 mode\n"
-"\n"
-" .byte 0x%c%c # bits 32-39\n"
-" .byte 0x%c%c # bits 40-47\n"
-" .byte 0x%c%c # bits 48-55\n"
-" .byte 0x%c%c # bits 56-63\n"
-" # bits value name desc\n"
-" # 32 1 Basic Addressing (BA) BA = 31, !BA = 24\n"
-" # 33-63 addr Instruction Address Address to exec\n";
+#define PSW \
+" .byte 0x%c%c\n" \
+" # bits value name desc\n" \
+" # 0 0 <zero>\n" \
+" # 1 0 PER Mask (R) disabled\n" \
+" # 2-4 0 <zero>\n" \
+" # 5 0 DAT Mode (T) disabled\n" \
+" # 6 0 I/O Mask (IO) disabled\n" \
+" # 7 0 External Mask (EX) disabled\n" \
+"\n" \
+" .byte 0x%c%c\n" \
+" # bits value name desc\n" \
+" # 8-11 0 Key\n" \
+" # 12 1 <one>\n" \
+" # 13 0 Machine-Check Mask (M) disabled\n" \
+" # 14 0 Wait State (W) executing\n" \
+" # 15 0 Problem State (P) supervisor state\n" \
+"\n" \
+" .byte 0x%c%c\n" \
+" # bits value name desc\n" \
+" # 16-17 0 Address-Space Control (AS) disabled\n" \
+" # 18-19 0 Condition Code (CC)\n" \
+" # 20-23 0 Program Mask exceptions disabled\n" \
+"\n" \
+" .byte 0x%c%c\n" \
+" # bits value name desc\n" \
+" # 24-30 0 <zero>\n" \
+" # 31 0 Extended Addressing (EA) ! 64 mode\n" \
+"\n" \
+" .byte 0x%c%c # bits 32-39\n" \
+" .byte 0x%c%c # bits 40-47\n" \
+" .byte 0x%c%c # bits 48-55\n" \
+" .byte 0x%c%c # bits 56-63\n" \
+" # bits value name desc\n" \
+" # 32 1 Basic Addressing (BA) BA = 31, !BA = 24\n" \
+" # 33-63 addr Instruction Address Address to exec\n"
-static char *psw_tail =
-"\n"
-"#\n"
-"# The remaining 16 bytes should contain CCW to read data from device\n"
-"#\n"
-"\n"
-"# CCW format-0:\n"
-"# bits name\n"
-"# 0-7 Cmd Code\n"
-"# 8-31 Data Address\n"
-"# 32 Chain-Data (CD)\n"
-"# 33 Chain-Command (CC)\n"
-"# 34 Sup.-Len.-Inditcation (SLI)\n"
-"# 35 Skip (SKP)\n"
-"# 36 Prog.-Contr.-Inter. (PCI)\n"
-"# 37 Indir.-Data-Addr. (IDA)\n"
-"# 38 Suspend (S)\n"
-"# 39 Modified I.D.A. (MIDA)\n"
-"# 40-47 <ignored>\n"
-"# 48-63 number of bytes to read\n"
-"\n"
-"# CP-CCW 1\n"
-" # READ 80 bytes of CCWs to 0x%06X\n"
-" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n"
-" .byte 0x%02X, 0x00, 0x00, 0x50\n"
-"\n"
-"# CP-CCW 2\n"
-" # TIC to 0x%06X\n"
-" .byte 0x08, 0x%02X, 0x%02X, 0x%02X\n"
-" .byte 0x00, 0x00, 0x00, 0x00\n";
+#define PSW_TAIL \
+"\n" \
+"#\n" \
+"# The remaining 16 bytes should contain CCW to read data from device\n" \
+"#\n" \
+"\n" \
+"# CCW format-0:\n" \
+"# bits name\n" \
+"# 0-7 Cmd Code\n" \
+"# 8-31 Data Address\n" \
+"# 32 Chain-Data (CD)\n" \
+"# 33 Chain-Command (CC)\n" \
+"# 34 Sup.-Len.-Inditcation (SLI)\n" \
+"# 35 Skip (SKP)\n" \
+"# 36 Prog.-Contr.-Inter. (PCI)\n" \
+"# 37 Indir.-Data-Addr. (IDA)\n" \
+"# 38 Suspend (S)\n" \
+"# 39 Modified I.D.A. (MIDA)\n" \
+"# 40-47 <ignored>\n" \
+"# 48-63 number of bytes to read\n" \
+"\n" \
+"# IPL CCW 1\n" \
+" # READ 80 bytes of CCWs to 0x%06X\n" \
+" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n" \
+" .byte 0x%02X, 0x00, 0x00, 0x50\n" \
+"\n" \
+"# IPL CCW 2\n" \
+" # TIC to 0x%06X\n" \
+" .byte 0x08, 0x%02X, 0x%02X, 0x%02X\n" \
+" .byte 0x00, 0x00, 0x00, 0x00\n" \
+"\n" \
+"#\n" \
+"# Pad to 80 bytes\n" \
+"#\n" \
+PAD_LINE \
+PAD_LINE \
+PAD_LINE \
+PAD_LINE \
+PAD_LINE \
+PAD_LINE \
+PAD_LINE
-static char *pad =
-"\n"
-"#\n"
-"# Pad to 80 bytes\n"
-"#\n"
-" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n"
-" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n"
-" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n"
-" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n"
-" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n"
-" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n"
-" .byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40\n";
-
-static char *cp_ccw =
-"\n"
-"# CP-CCW %d\n"
-" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n"
-" .byte 0x40, 0x00, 0x00, 0x50\n";
+#define CCW \
+"\n" \
+"# CP CCW %d: READ CCWs @ 0x%06X\n" \
+" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n" \
+" .byte 0x40, 0x00, 0x00, 0x50\n"
#define CHAIN 0x40
-static char *data_ccw =
-"\n"
-"# LOADER-CCW %d\n"
-" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n"
-" .byte 0x%02X, 0x00, 0x00, 0x50\n";
-
-static char *nop_ccw =
-"\n"
-"# NOP-CCW %d\n"
-" .byte 0x03, 0x00, 0x00, 0x08\n"
-" .byte 0x60, 0x00, 0x00, 0x01\n";
+#define DATA_CCW \
+"\n" \
+"# DATA CCW %d: READ data @ 0x%06X\n" \
+" .byte 0x02, 0x%02X, 0x%02X, 0x%02X\n" \
+" .byte 0x%02X, 0x00, 0x00, 0x50\n"
#define ADDR(x) (((x)[0]<<16) | \
((x)[1]<<8) | \
@@ 201,14 190,38 @@ static void __add(unsigned int *addr, in
}
}
+/*
+ * return the number of CCWs needed to load the whole channel program to
+ * load the data
+ */
+static unsigned int count_ccws(unsigned int data_cards)
+{
+ const unsigned int ccws_per_card = 80 / 8;
+ unsigned int last_level;
+ unsigned int ccws;
+
+ /* each data card needs a CCW, but we don't count them */
+ ccws = 0;
+ last_level = data_cards;
+
+ /* each card full of CCWs needs a CCW */
+ while (last_level > 1) {
+ last_level = (last_level + ccws_per_card - 1) / ccws_per_card;
+ ccws += last_level;
+ }
+
+ /* except the first CCW is already part of the 24-byte IPL card */
+ return ccws - 1;
+}
+
int main(int argc, char **argv)
{
- int i = 1, j;
- unsigned int card;
unsigned int ccw_addr[3];
unsigned int addr[3];
unsigned int size;
unsigned int data_cards;
+ unsigned int ccw_cards;
+ unsigned int i;
if (argc != 6)
die(argv[0], "Invalid number of args");
@@ 239,53 252,71 @@ int main(int argc, char **argv)
ccw_addr[2] = (unhex(argv[0], argv[5][4]) << 4) |
unhex(argv[0], argv[5][5]);
+ if (!size)
+ die(argv[0], "Cannot handle empty files");
+
/* round up */
if (size % 80)
size = size - (size % 80) + 80;
data_cards = size / 80;
- printf(deck_head);
+ printf(DECK_HEAD);
- printf(card_head, i);
- printf(psw_head);
- printf(psw,
+ printf(PSW_HEAD);
+ printf(PSW,
argv[1][0], argv[1][1], argv[1][2], argv[1][3],
argv[1][4], argv[1][5], argv[1][6], argv[1][7],
argv[2][0], argv[2][1], argv[2][2], argv[2][3],
argv[2][4], argv[2][5], argv[2][6], argv[2][7]);
- if (data_cards == 1)
- die(argv[0], "Cannot handle the case where size <= 80");
+ printf(PSW_TAIL,
+ ADDR(ccw_addr),
+ ccw_addr[0], ccw_addr[1], ccw_addr[2],
+ CHAIN,
+ ADDR(ccw_addr),
+ ccw_addr[0], ccw_addr[1], ccw_addr[2]);
- card = 2;
- i = 0;
- j = 1;
-
- printf(psw_tail, ADDR(ccw_addr), ADDRS(ccw_addr), CHAIN,
- ADDR(ccw_addr), ADDRS(ccw_addr));
- printf(pad);
__add(ccw_addr, 80);
- for(i=0; i<=((data_cards+9)/10) + (((data_cards+9)/10)+9)/10 - 2; i++) {
- printf(cp_ccw, i+3, ADDRS(ccw_addr));
+ /*
+ * We want to read in (size) bytes. This requires reading (size /
+ * 80) data cards - and we need a CCW for each. Those read CCWs are
+ * also stored on cards. Since we can fit 10 CCWs per card, there
+ * are (size / 80 / 10) of those and reading each one will require
+ * another CCW. And so on...
+ *
+ * Things get a bit more complicated because different things should
+ * get loaded in different places. Overall, the generated cards
+ * should be:
+ *
+ * 1. IPL card (8 byte PSW, 8 byte CCW to read more CCWs at
+ * ccw_addr, 8 byte TIC CCW) - generated above
+ * 2. Some number of cards with CCWs loading itself at ccw_addr
+ * 3. Some number of cards with CCWs loading the data at addr
+ * 4. Data itself - not written out by us
+ */
+
+ ccw_cards = count_ccws(data_cards);
+
+ /* 2. generate the CCWs that load the rest of the channel program */
+ for (i = 0; i < ccw_cards; i++) {
+ printf(CCW, i, ADDR(ccw_addr), ADDRS(ccw_addr));
+
__add(ccw_addr, 80);
}
- while (i % 10) {
- printf(nop_ccw, i);
- i++;
- }
-
- for(i=1; i<=data_cards; i++) {
- printf(data_ccw, i, ADDRS(addr),
- (i == data_cards) ? 0 : CHAIN);
+ /* 3. generate the CCWs that load the data itself */
+ for (i = 0; i < data_cards; i++) {
+ printf(DATA_CCW, i, ADDR(addr), ADDRS(addr),
+ (i == (data_cards - 1)) ? 0 : CHAIN);
__add(addr, 80);
}
- return 0;
+ /* pad the last card to be full */
+ for (i = (ccw_cards + data_cards) % 10; i < 10; i++)
+ printf(PAD_LINE);
- printf(card_head, card++);
return 0;
}