build/ccw_gen: rewrite to handle arbitrary file sizes

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
1 files changed, 178 insertions(+), 147 deletions(-)

M build/ccw_gen.c
M build/ccw_gen.c +178 -147
@@ 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;
 }