Switch from ackbuilder to bazel.

This commit is contained in:
David Given 2022-06-01 21:21:24 +02:00
parent c12cf80bff
commit a4739d5e8d
78 changed files with 1442 additions and 3527 deletions

5
BUILD Normal file
View file

@ -0,0 +1,5 @@
package(default_visibility = ["//visibility:public"])
exports_files([ "diskdefs" ])

View file

@ -1,22 +1,6 @@
OBJDIR = $(PWD)/.obj
LUA_5_1 = lua5.1
all:
bazel build -c opt //...
all: $(OBJDIR)/build.ninja
@ninja -f $(OBJDIR)/build.ninja
verbose:
bazel build -s -c opt //...
clean:
rm -rf $(OBJDIR)
lua-files = $(shell find . -name 'build*.lua')
$(OBJDIR)/build.ninja: build/ackbuilder.lua build/cpm.lua Makefile $(lua-files)
@mkdir -p $(OBJDIR)
@$(LUA_5_1) \
build/ackbuilder.lua \
build/build.lua \
build/cpm.lua \
build.lua \
--ninja \
OBJDIR=$(OBJDIR) \
CC=gcc \
AR=ar \
> $@

106
arch/brotherop2/BUILD Normal file
View file

@ -0,0 +1,106 @@
load("//build:cpm.bzl", "diskimage")
load("//third_party/ld80:build.bzl", "ld80")
load("//third_party/zmac:build.bzl", "zmac")
load("//utils:build.bzl", "unix2cpm")
package(default_visibility = ["//visibility:public"])
genrule(
name = "font_inc",
tools = [ "//arch/brotherop2/utils:fontconvert" ],
srcs = [ "//utils:6x7font.bdf" ],
outs = [ "font.inc" ],
cmd = "$(location //arch/brotherop2/utils:fontconvert) $< > $@"
)
zmac(
name = "boot_o",
srcs = [
"boot.z80",
"//arch/brotherop2/include:brotherop2.lib",
"//arch/common/utils:tty.lib",
"//include:cpmish.lib",
"//include:z180.lib",
":font_inc",
],
)
ld80(
name = "boot",
address = 0x5000,
objs = {
0x5000: [ ":boot_o" ]
}
)
[
zmac(
name = n,
srcs = [
n + ".z80",
"//arch/brotherop2/include:brotherop2.lib",
"//arch/common/utils:print.lib",
"//arch/common/utils:tty.lib",
"//include:cpm.lib",
"//include:cpmish.lib",
"//include:z180.lib",
]
)
for n in [ "bios", "floppy", "tty" ]
]
# This is the bit which CP/M reloads on warm boot (well, some of it).
ld80(
name = "cpmfile",
address = 0x9300,
objs = {
0x9300: [ "//third_party/zcpr1" ],
0x9b00: [ "//third_party/zsdos" ],
0xa900: [
":bios",
":floppy",
":tty",
]
}
)
# Produces the FAT bit of the disk image.
zmac(
name = "fat",
srcs = [
"fat.z80",
":boot",
":cpmfile"
]
)
ld80(
name = "bootfile",
objs = {
0x0000: [ ":fat" ]
}
)
unix2cpm(
name = "readme",
src = "README.md"
)
diskimage(
name = "diskimage",
format = "brother-op2",
bootfile = ":bootfile",
map = {
"-readme.txt": ":readme",
"dump.com": "//cpmtools:dump",
"stat.com": "//cpmtools:stat",
"asm.com": "//cpmtools:asm",
"copy.com": "//cpmtools:copy",
"submit.com": "//cpmtools:submit",
"rawdisk.com": "//cpmtools:rawdisk",
"bbcbasic.com": "//third_party/bbcbasic:bbcbasic_ADM3A",
"camel80.com": "//third_party/camelforth",
"qe.com": "//cpmtools:qe_BROTHEROP2",
},
)

View file

@ -1,100 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
include "utils/build.lua"
normalrule {
name = "font_inc",
ins = {
"arch/brotherop2/utils+fontconvert",
"utils/6x7font.bdf",
},
outleaves = { "font.inc" },
commands = {
"%{ins} > %{outs}"
}
}
zmac {
name = "boot_o",
srcs = { "./boot.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/tty.lib",
"+font_inc"
},
}
ld80 {
name = "boot",
address = 0x5000,
srcs = {
"-P5000",
"+boot_o"
}
}
for _, n in pairs({"bios", "floppy", "tty"}) do
zmac {
name = n,
srcs = { "./"..n..".z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/tty.lib",
},
}
end
-- This is the bit which CP/M reloads on warm boot (well, some of it).
ld80 {
name = "cpmfile",
address = 0x9300,
srcs = {
"-P9300", "third_party/zcpr1+zcpr",
"-P9b00", "third_party/zsdos+zsdos",
"-Pa900",
"+bios",
"+floppy",
"+tty",
}
}
-- Produces the FAT bit of the disk image.
zmac {
name = "fat",
srcs = { "./fat.z80" },
deps = {
"+boot",
"+cpmfile"
}
}
ld80 {
name = "bootfile",
srcs = { "+fat" }
}
unix2cpm {
name = "readme",
srcs = { "README.md" }
}
diskimage {
name = "diskimage",
format = "brother-op2",
bootfile = { "+bootfile" },
map = {
["dump.com"] = "cpmtools+dump",
["stat.com"] = "cpmtools+stat",
["asm.com"] = "cpmtools+asm",
["copy.com"] = "cpmtools+copy",
["submit.com"] = "cpmtools+submit",
["bbcbasic.com"] = "third_party/bbcbasic+bbcbasic_ADM3A",
["qe.com"] = "cpmtools+qe_BROTHEROP2",
["mkfs.com"] = "cpmtools+mkfs",
["rawdisk.com"] = "cpmtools+rawdisk",
["-readme.txt"] = "+readme",
},
}

View file

@ -0,0 +1,5 @@
package(default_visibility = ["//visibility:public"])
exports_files(glob(["*.lib"]))

View file

@ -0,0 +1,8 @@
package(default_visibility = ["//visibility:public"])
cc_binary(
name = "fontconvert",
srcs = [ "fontconvert.c" ],
deps = [ "//utils:libbdf" ],
)

View file

@ -1,5 +0,0 @@
cprogram {
name = "fontconvert",
srcs = { "./fontconvert.c" },
deps = { "utils+libbdf" },
}

145
arch/brotherwp1/BUILD Normal file
View file

@ -0,0 +1,145 @@
load("//build:cpm.bzl", "cpm_addresses", "binslice", "diskimage")
load("//third_party/zmac:build.bzl", "zmac")
load("//third_party/ld80:build.bzl", "ld80")
load("//utils:build.bzl", "unix2cpm")
# Memory layout configuration -----------------------------------------------
# Configure the BIOS size here; this will then emit an addresses.lib file
# which contains the position of the BDOS and CCP.
top_of_memory = 0x9000
(cbase, fbase, bbase) = cpm_addresses(
name = "addresses",
top_of_memory = top_of_memory,
bios_size = 0x0a00
)
# Bootstrapper --------------------------------------------------------------
# This is the .APL file which the Brother OS loads. It's responsible for
# remapping the memory, doing some device setup, and loading the BIOS into
# the top of memory.
zmac(
name = "boot_img",
srcs = [
"boot.z80",
"//include:z180.lib",
":addresses",
],
relocatable = False
)
# BIOS ----------------------------------------------------------------------
BIOS_SRCS = [
"bios",
"floppy",
"keyboard",
"tty",
]
[
zmac(
name = name + "_o",
srcs = [
name + ".z80",
"//include:cpm.lib",
"//include:cpmish.lib",
"//include:z180.lib",
"//arch/brotherwp1/include:brotherwp1.lib",
"//arch/common/utils:tty.lib",
"//arch/common/utils:print.lib",
":addresses",
":keytab",
]
)
for name in BIOS_SRCS
]
genrule(
name = "keytab",
tools = [ "//arch/brotherwp1/utils:mkkeytab" ],
srcs = [],
outs = [ "keytab.inc" ],
cmd = "$(location //arch/brotherwp1/utils:mkkeytab) > $@"
)
# This is a 64kB file containing the entire CP/M memory image.
ld80(
name = "memory_img",
address = 0,
objs = {
cbase: [ "//third_party/zcpr1" ],
fbase: [ "//third_party/zsdos" ],
bbase: [
":bios_o",
":tty_o",
":floppy_o",
":keyboard_o",
]
}
)
# We now chop it up to remove the BIOS and the combined CCP/BDOS (which
# go into the system track).
binslice(
name = "bios_img",
src = ":memory_img",
start = bbase,
length = top_of_memory - bbase
)
binslice(
name = "ccpbdos_img",
src = ":memory_img",
start = cbase,
length = bbase - cbase
)
# Brother file system -------------------------------------------------------
# Produces the fake Brother file system image
zmac(
name = "bootfile_img",
srcs = [
"fs.z80",
":boot_img",
":bios_img",
":ccpbdos_img",
],
relocatable = False
)
# Disk image ----------------------------------------------------------------
# Assembles the bootable disk which you can actually run.
unix2cpm(
name = "readme",
src = "README.md"
)
diskimage(
name = "diskimage",
format = "brother-wp1",
bootfile = ":bootfile_img",
map = {
"-readme.txt": ":readme",
"dump.com": "//cpmtools:dump",
"stat.com": "//cpmtools:stat",
"asm.com": "//cpmtools:asm",
"copy.com": "//cpmtools:copy",
"submit.com": "//cpmtools:submit",
"bbcbasic.com": "//third_party/bbcbasic:bbcbasic_ADM3A",
"camel80.com": "//third_party/camelforth",
"qe.com": "//cpmtools:qe_BROTHER_WP1",
},
)
# vim: ts=4 sw=4 et

View file

@ -1,181 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
include "utils/build.lua"
--- Memory layout configuration ---------------------------------------------
-- Configure the BIOS size here; this will then emit an addresses.lib file
-- which contains the position of the BDOS and CCP.
local BIOS_SIZE = 0x0a00
local BDOS_SIZE = 3584 -- fixed
local CCP_SIZE = 2048 -- fixed
local BBASE = 0x9000 - BIOS_SIZE
local FBASE = BBASE - BDOS_SIZE
local CBASE = FBASE - CCP_SIZE
normalrule {
name = "addresses_lib",
ins = {},
outleaves = { "addresses.lib" },
commands = {
"echo BIOS_SIZE = "..BIOS_SIZE.." > %{outs[1]}",
"echo BDOS_SIZE = "..BDOS_SIZE.." >> %{outs[1]}",
"echo CCP_SIZE = "..CCP_SIZE.." >> %{outs[1]}",
"echo BBASE = "..BBASE.." >> %{outs[1]}",
"echo FBASE = "..FBASE.." >> %{outs[1]}",
"echo CBASE = "..CBASE.." >> %{outs[1]}",
}
}
--- Bootstrapper ------------------------------------------------------------
-- This is the .APL file which the Brother OS loads. It's responsible for
-- remapping the memory, doing some device setup, and loading the BIOS into
-- the top of memory.
zmac {
name = "boot_img",
srcs = { "./boot.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"+addresses_lib"
},
relocatable = false
}
--- BIOS --------------------------------------------------------------------
-- The keyboard map.
normalrule {
name = "keytab_inc",
ins = { "arch/brotherwp1/utils+mkkeytab" },
outleaves = { "keytab.inc" },
commands = {
"%{ins} > %{outs}"
}
}
-- The CP/M BIOS itself.
zmac {
name = "bios_o",
srcs = { "./bios.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/tty.lib",
"arch/common/utils/deblocker.lib",
"+addresses_lib",
},
}
zmac {
name = "tty_o",
srcs = { "./tty.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/tty.lib",
},
}
zmac {
name = "floppy_o",
srcs = { "./floppy.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/deblocker.lib",
},
}
zmac {
name = "keyboard_o",
srcs = { "./keyboard.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"+keytab_inc",
},
}
-- This is a 64kB file containing the entire CP/M memory image.
ld80 {
name = "memory_img",
address = 0,
srcs = {
"-P"..string.format("%x", CBASE), "third_party/zcpr1+zcpr",
"-P"..string.format("%x", FBASE), "third_party/zsdos+zsdos",
"-P"..string.format("%x", BBASE),
"+bios_o",
"+tty_o",
"+floppy_o",
"+keyboard_o",
}
}
-- We now chop it up to remove the BIOS and the combined CCP/BDOS (which
-- go into the system track).
binslice {
name = "bios_img",
src = { "+memory_img" },
start = BBASE,
length = BIOS_SIZE
}
binslice {
name = "ccpbdos_img",
src = { "+memory_img" },
start = CBASE,
length = BBASE - CBASE
}
--- Brother file system -----------------------------------------------------
-- Produces the fake Brother file system image
zmac {
name = "bootfile_img",
srcs = { "./fs.z80" },
deps = {
"+boot_img",
"+bios_img",
"+ccpbdos_img",
},
relocatable = false
}
--- Disk image --------------------------------------------------------------
-- Assembles the bootable disk which you can actually run.
unix2cpm {
name = "readme",
srcs = { "README.md" }
}
diskimage {
name = "diskimage",
format = "brother-wp1",
bootfile = { "+bootfile_img" },
map = {
["-readme.txt"] = "+readme",
["dump.com"] = "cpmtools+dump",
["stat.com"] = "cpmtools+stat",
["asm.com"] = "cpmtools+asm",
["copy.com"] = "cpmtools+copy",
["submit.com"] = "cpmtools+submit",
["bbcbasic.com"] = "third_party/bbcbasic+bbcbasic_ADM3A",
["camel80.com"] = "third_party/camelforth+camelforth",
["qe.com"] = "cpmtools+qe_BROTHER_WP1",
["pterm.com"] = "arch/brotherwp1/tools+pterm",
},
}

View file

@ -0,0 +1,5 @@
package(default_visibility = ["//visibility:public"])
exports_files(glob(["*.lib"]))

View file

@ -1,9 +0,0 @@
zmac {
name = "pterm",
srcs = { "./pterm.z80" },
deps = {
"arch/brotherwp1+addresses_lib"
},
relocatable = false
}

View file

@ -0,0 +1,9 @@
package(default_visibility = ["//visibility:public"])
cc_binary(
name = "mkkeytab",
srcs = [ "mkkeytab.c" ]
)
# vim: ts=4 sw=4 et

View file

@ -1,4 +0,0 @@
cprogram {
name = "mkkeytab",
srcs = { "./mkkeytab.c" }
}

4
arch/common/utils/BUILD Normal file
View file

@ -0,0 +1,4 @@
package(default_visibility = ["//visibility:public"])
exports_files(glob(["*.lib"]))

View file

@ -1,21 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
include "build/z80test.lua"
local deblocker_tests = {
"deblocker_calculate_physical",
"deblocker_change_block",
"deblocker_calculate_buffer_address",
"deblocker_capacity",
}
for _, n in pairs(deblocker_tests) do
z80test {
name = n,
srcs = { "./tests/"..n..".z80" },
deps = {
"./deblocker.lib",
"include/cpm.lib"
}
}
end

88
arch/kayproii/BUILD Normal file
View file

@ -0,0 +1,88 @@
load("//build:cpm.bzl", "diskimage")
load("//third_party/zmac:build.bzl", "zmac")
load("//third_party/ld80:build.bzl", "ld80")
load("//utils:build.bzl", "unix2cpm")
package(default_visibility = ["//visibility:public"])
zmac(
name = "boot",
srcs = [ "boot.z80" ],
relocatable = False
)
zmac(
name = "bios",
srcs = [
"bios.z80",
"//arch/kayproii/include:kayproii.lib",
"//include:cpm.lib",
"//include:cpmish.lib",
],
)
# Builds the memory image.
ld80(
name = "bootfile_mem",
objs = {
0xe400: [ "//third_party/zcpr1" ],
0xec00: [ "//third_party/zsdos" ],
0xfa00: [ ":bios" ],
}
)
# Repackages the memory image as a boot track. This doesn't include the extra
# section of boot image which exists above the directory.
genrule(
name = "bootfile",
srcs = [
":boot",
":bootfile_mem"
],
outs = [ "bootfile.img" ],
cmd = " && ".join([
"dd if=$(location :boot) of=$@ bs=128 count=1 2> /dev/null",
"dd if=$(location :bootfile_mem) of=$@ bs=128 seek=1 skip=456 count=16 2> /dev/null",
"dd if=$(location :bootfile_mem) of=$@ bs=128 seek=17 skip=472 count=23 2> /dev/null",
])
)
unix2cpm(
name = "readme",
src = "README.md"
)
diskimage(
name = "partialimg",
format = "kpii",
bootfile = ":bootfile",
map = {
"-readme.txt": ":readme",
"dump.com": "//cpmtools:dump",
"stat.com": "//cpmtools:stat",
"asm.com": "//cpmtools:asm",
"copy.com": "//cpmtools:copy",
"submit.com": "//cpmtools:submit",
"bbcbasic.com": "//third_party/bbcbasic:bbcbasic_ADM3A",
"camel80.com": "//third_party/camelforth",
"qe.com": "//cpmtools:qe_KAYPROII",
},
)
# Patches the special extra bit of BDOS/BIOS into the area above the
# directory; yuch.
genrule(
name = "diskimage",
srcs = [
":partialimg",
":bootfile_mem"
],
outs = [ "diskimage.img" ],
cmd = " && ".join([
"cp $(location :partialimg) $@",
"chmod +w $@",
"truncate -s 204800 $@",
"dd if=$(location :bootfile_mem) of=$@ bs=128 seek=56 skip=495 count=9 conv=notrunc 2> /dev/null"
])
)

View file

@ -1,76 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
include "utils/build.lua"
zmac {
name = "boot",
srcs = { "./boot.z80" },
relocatable = false
}
zmac {
name = "bios",
srcs = { "./bios.z80" },
deps = {
"include/*.lib",
"./include/*.lib"
},
}
-- Builds the memory image.
ld80 {
name = "bootfile_mem",
srcs = {
"-Pe400", "third_party/zcpr1+zcpr",
"-Pec00", "third_party/zsdos+zsdos",
"-Pfa00", "+bios",
}
}
-- Repackages the memory image as a boot track. This doesn't include the extra
-- section of boot image which exists above the directory.
normalrule {
name = "bootfile",
ins = {
"+boot",
"+bootfile_mem"
},
outleaves = { "bootfile.img" },
commands = {
"dd if=%{ins[1]} of=%{outs} bs=128 count=1 2> /dev/null",
"dd if=%{ins[3]} of=%{outs} bs=128 seek=1 skip=456 count=16 2> /dev/null",
"dd if=%{ins[3]} of=%{outs} bs=128 seek=17 skip=472 count=23 2> /dev/null",
}
}
diskimage {
name = "partialimg",
format = "kpii",
bootfile = { "arch/kayproii+bootfile" },
map = {
["dump.com"] = "cpmtools+dump",
["stat.com"] = "cpmtools+stat",
["asm.com"] = "cpmtools+asm",
["copy.com"] = "cpmtools+copy",
["submit.com"] = "cpmtools+submit",
["bbcbasic.com"] = "third_party/bbcbasic+bbcbasic_ADM3A",
["qe.com"] = "cpmtools+qe_KAYPROII",
["camel80.com"] = "third_party/camelforth+camelforth",
},
}
-- Patches the special extra bit of BDOS/BIOS into the area above the
-- directory; yuch.
normalrule {
name = "diskimage",
ins = {
"+partialimg",
"+bootfile_mem"
},
outleaves = { "diskimage.img" },
commands = {
"cp %{ins[1]} %{outs}",
"truncate -s 204800 %{outs}",
"dd if=%{ins[2]} of=%{outs} bs=128 seek=56 skip=495 count=9 conv=notrunc 2> /dev/null"
}
}

View file

@ -0,0 +1,5 @@
package(default_visibility = ["//visibility:public"])
exports_files(glob(["*.lib"]))

87
arch/nc200/BUILD Normal file
View file

@ -0,0 +1,87 @@
load("//build:cpm.bzl", "cpm_addresses", "diskimage")
load("//third_party/zmac:build.bzl", "zmac")
load("//third_party/ld80:build.bzl", "ld80")
load("//utils:build.bzl", "objectify", "unix2cpm")
package(default_visibility = ["//visibility:public"])
# Memory layout configuration -----------------------------------------------
# Configure the BIOS size here; this will then emit an addresses.lib file
# which contains the position of the BDOS and CCP.
(cbase, fbase, bbase) = cpm_addresses(
name = "addresses",
bios_size = 0x0300
)
# Bootstrap -----------------------------------------------------------------
# The program the NC200 runs on startup.
zmac(
name = "auto",
srcs = [
"auto.z80",
"//arch/nc200/include:nc200.lib",
],
relocatable = False
)
objectify(
name = "auto_inc",
src = ":auto"
)
# FAT boot data -------------------------------------------------------------
[
zmac(
name = f.replace(".z80", ""),
srcs = [
f,
":auto_inc",
]
)
for f in glob(["boot/*.z80"])
]
# BIOS ----------------------------------------------------------------------
# The CP/M BIOS itself.
zmac(
name = "bios",
srcs = [
"bios.z80",
"//arch/nc200/include:nc200.lib",
"//arch/nc200/include:supervisor.lib",
"//include:cpm.lib",
"//include:cpmish.lib",
":addresses",
]
)
# Builds the memory image. This is a 64kB file containing the entire CP/M
# memory image, including the supervisor at the bottom.
ld80(
name = "memory_img",
address = 0,
objs = {
0x0000: [ ":boot/startup", ],
0x000b: [ ":boot/bpb1", ],
0x0038: [ ":boot/sirq", ],
0x01fe: [ ":boot/bootsig", ],
0x020b: [ ":boot/bpb2", ],
0x0400: [ ":boot/fat", "//arch/nc200/supervisor:variables" ],
0x1000: [ ":boot/rootdir", "//arch/nc200/supervisor" ],
0x1e00: [ ":boot/relauto", ],
cbase: [ "//third_party/zcpr1" ],
fbase: [ "//third_party/zsdos" ],
bbase: [ ":bios" ],
}
)

View file

@ -1,163 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
include "utils/build.lua"
--- Memory layout configuration ------------------------------------------
-- Configure the BIOS size here; this will then emit an addresses.lib file
-- which contains the position of the BDOS and CCP.
local BIOS_SIZE = 0x0300
local BDOS_SIZE = 3584 -- fixed
local CCP_SIZE = 2048 -- fixed
local CPM_SIZE = BIOS_SIZE + BDOS_SIZE + CCP_SIZE
local BBASE = 0x10000 - BIOS_SIZE
local FBASE = BBASE - BDOS_SIZE
local CBASE = FBASE - CCP_SIZE
normalrule {
name = "addresses_lib",
ins = {},
outleaves = { "addresses.lib" },
commands = {
"echo BIOS_SIZE = "..BIOS_SIZE.." > %{outs[1]}",
"echo BDOS_SIZE = "..BDOS_SIZE.." >> %{outs[1]}",
"echo CCP_SIZE = "..CCP_SIZE.." >> %{outs[1]}",
"echo CPM_SIZE = "..CPM_SIZE.." >> %{outs[1]}",
"echo BBASE = "..BBASE.." >> %{outs[1]}",
"echo FBASE = "..FBASE.." >> %{outs[1]}",
"echo CBASE = "..CBASE.." >> %{outs[1]}",
}
}
--- Bootstrap ------------------------------------------------------------
-- The program the NC200 runs on startup.
zmac {
name = "auto",
srcs = { "./auto.z80" },
deps = {
"include/*.lib",
"./include/*.lib"
},
relocatable = false
}
objectify {
name = "auto_inc",
srcs = { "+auto" }
}
--- FAT boot data --------------------------------------------------------
local bootfiles = filenamesof("./boot/*.z80")
for _, f in pairs(bootfiles) do
local base = basename(f)
zmac {
name = base,
srcs = { f },
deps = {
"include/*.lib",
"./include/*.lib",
"+auto_inc"
}
}
end
--- BIOS -----------------------------------------------------------------
-- The CP/M BIOS itself.
zmac {
name = "bios",
srcs = { "./bios.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"+addresses_lib",
},
}
-- Builds the memory image. This is a 64kB file containing the entire CP/M
-- memory image, including the supervisor at the bottom.
ld80 {
name = "memory_img",
address = 0,
srcs = {
"-P0000", "+startup.z80",
"-P000b", "+bpb1.z80",
"-P0038", "+sirq.z80",
"-P01fe", "+bootsig.z80",
"-P020b", "+bpb2.z80",
"-P0400", "+fat.z80",
"arch/nc200/supervisor+variables",
"-P1000", "+rootdir.z80",
"arch/nc200/supervisor+supervisor",
"-P1e00", "+relauto.z80",
"-P"..string.format("%x", CBASE), "third_party/zcpr1+zcpr",
"-P"..string.format("%x", FBASE), "third_party/zsdos+zsdos",
"-P"..string.format("%x", BBASE), "+bios",
}
}
-- We now chop it up to remove the supervisor and the CCP/BDOS/BIOS, which go into
-- the system tracks.
binslice {
name = "cpm_img",
src = { "+memory_img" },
start = CBASE,
length = CPM_SIZE
}
binslice {
name = "supervisor_img",
src = { "+memory_img" },
start = 0,
length = 9*1024
}
-- And combine them into the system track image.
normalrule {
name = "systemtrack_img",
ins = {
"+supervisor_img",
"+cpm_img",
},
outleaves = { "systemtrack.img" },
commands = {
"cat %{ins} > %{outs[1]}"
}
}
unix2cpm {
name = "readme",
srcs = { "README.md" }
}
diskimage {
name = "diskimage",
format = "nc200cpm",
bootfile = { "arch/nc200+systemtrack_img" },
map = {
["dump.com"] = "cpmtools+dump",
["stat.com"] = "cpmtools+stat",
["asm.com"] = "cpmtools+asm",
["copy.com"] = "cpmtools+copy",
["submit.com"] = "cpmtools+submit",
["bbcbasic.com"] = "third_party/bbcbasic+bbcbasic_ADM3A",
["qe.com"] = "cpmtools+qe_NC200",
["flash.com"] = "arch/nc200/tools+flash",
["flipdisk.com"] = "arch/nc200/tools+flipdisk",
["mkfs.com"] = "cpmtools+mkfs",
["rawdisk.com"] = "cpmtools+rawdisk",
["z8e.com"] = "third_party/z8e+z8e_NC200",
["ted.com"] = "third_party/ted+ted_NC200",
["camel80.com"] = "third_party/camelforth+camelforth",
["-readme.txt"] = "+readme",
},
}

5
arch/nc200/include/BUILD Normal file
View file

@ -0,0 +1,5 @@
package(default_visibility = ["//visibility:public"])
exports_files(glob(["*.lib"]))

View file

@ -0,0 +1,45 @@
load("//third_party/zmac:build.bzl", "zmac")
package(default_visibility = ["//visibility:public"])
genrule(
name = "keytab_inc",
tools = [ "//arch/nc200/utils:mkkeytab" ],
outs = [ "keytab.inc" ],
cmd = "$(location //arch/nc200/utils:mkkeytab) > $@"
)
genrule(
name = "font_inc",
tools = [ "//arch/nc200/utils:fontconvert" ],
srcs = [ "//utils:6x7font.bdf" ],
outs = [ "font.inc" ],
cmd = "$(location //arch/nc200/utils:fontconvert) $< > $@"
)
zmac(
name = "supervisor",
srcs = [
"supervisor.z80",
"//arch/common/utils:deblocker.lib",
"//arch/nc200/include:nc200.lib",
"//arch/nc200/include:supervisor.lib",
"//arch/nc200:addresses",
"//include:cpm.lib",
"//include:cpmish.lib",
":keytab_inc",
] + glob(["*.inc"]),
)
zmac(
name = "variables",
srcs = [
"variables.z80",
"//arch/nc200/include:nc200.lib",
"//arch/nc200/include:supervisor.lib",
"//include:cpm.lib",
"//include:cpmish.lib",
":font_inc",
],
)

View file

@ -1,47 +0,0 @@
include "third_party/zmac/build.lua"
normalrule {
name = "keytab_inc",
ins = { "arch/nc200/utils+mkkeytab" },
outleaves = { "keytab.inc" },
commands = {
"%{ins} > %{outs}"
}
}
normalrule {
name = "font_inc",
ins = {
"arch/nc200/utils+fontconvert",
"utils/6x7font.bdf"
},
outleaves = { "font.inc" },
commands = {
"%{ins} > %{outs}"
}
}
zmac {
name = "supervisor",
srcs = { "./supervisor.z80" },
deps = {
"include/*.lib",
"arch/common/utils/deblocker.lib",
"arch/common/utils/tty.lib",
"arch/nc200/include/*.lib",
"arch/nc200+addresses_lib",
"./*.inc",
"+keytab_inc",
"+font_inc",
},
}
zmac {
name = "variables",
srcs = { "./variables.z80" },
deps = {
"include/*.lib",
"arch/nc200/include/*.lib",
"+font_inc",
},
}

View file

@ -1,25 +0,0 @@
include "cpmtools/libcuss/build.lua"
ackprogram {
name = "flash",
srcs = {
"./flash.c",
"./pcmcia-tools.s"
},
}
zmac {
name = "flipdisk_o",
srcs = { "./flipdisk.z80" },
deps = { "arch/nc200+addresses_lib" }
}
ld80 {
name = "flipdisk",
address = 0x100,
srcs = {
"-P0100",
"+flipdisk_o"
}
}

15
arch/nc200/utils/BUILD Normal file
View file

@ -0,0 +1,15 @@
package(default_visibility = ["//visibility:public"])
cc_binary(
name = "fontconvert",
srcs = [ "fontconvert.c" ],
deps = [
"//utils:libbdf"
]
)
cc_binary(
name = "mkkeytab",
srcs = [ "mkkeytab.c" ]
)

View file

@ -1,12 +0,0 @@
cprogram {
name = "mkkeytab",
srcs = { "./mkkeytab.c" }
}
cprogram {
name = "fontconvert",
srcs = { "./fontconvert.c" },
deps = {
"utils+libbdf"
},
}

View file

@ -68,3 +68,6 @@ int main(int argc, const char* argv[])
return 0;
}
// vim: ts=4 sw=4 et

203
arch/wp2450ds/BUILD Normal file
View file

@ -0,0 +1,203 @@
load("//build:cpm.bzl", "binslice", "cpm_addresses", "diskimage")
load("//third_party/zmac:build.bzl", "zmac")
load("//third_party/ld80:build.bzl", "ld80")
load("//utils:build.bzl", "objectify", "unix2cpm")
package(default_visibility = ["//visibility:public"])
# Memory layout configuration -----------------------------------------------
# Configure the BIOS size here; this will then emit an addresses.lib file
# which contains the position of the BDOS and CCP.
(cbase, fbase, bbase) = cpm_addresses(
name = "addresses",
bios_size = 0x0f00
)
# Generated tables ----------------------------------------------------------
# Font and keyboard table.
genrule(
name = "keytab_inc",
tools = [ "//arch/wp2450ds/utils:mkkeytab" ],
outs = [ "keytab.inc" ],
cmd = "$(location //arch/wp2450ds/utils:mkkeytab) > $@"
)
genrule(
name = "font_inc",
tools = [ "//arch/wp2450ds/utils:fontconvert" ],
srcs = [ "//utils:6x7font.bdf" ],
outs = [ "font.inc" ],
cmd = "$(location //arch/wp2450ds/utils:fontconvert) $< > $@"
)
# Libraries -----------------------------------------------------------------
# These may be used by both the BIOS proper and the bootstrap program.
zmac(
name = "tty_o",
srcs = [
"tty.z80",
"//include:cpm.lib",
"//include:cpmish.lib",
"//include:z180.lib",
"//arch/common/utils:tty.lib",
"//arch/common/utils:print.lib",
"//arch/wp2450ds/include:wp2450ds.lib",
":font_inc"
],
)
zmac(
name = "upd765_o",
srcs = [
"upd765.z80",
"//include:cpm.lib",
"//include:cpmish.lib",
"//include:z180.lib",
"//arch/common/utils:upd765.lib",
"//arch/common/utils:deblocker.lib",
"//arch/wp2450ds/include:wp2450ds.lib",
],
)
zmac(
name = "keyboard_o",
srcs = [
"keyboard.z80",
"//include:cpm.lib",
"//include:cpmish.lib",
"//include:z180.lib",
"//arch/wp2450ds/include:wp2450ds.lib",
":keytab_inc",
]
)
# Bootstrapper --------------------------------------------------------------
# This is the .APL file which the Brother OS loads. It's responsible for
# remapping the memory, doing some device setup, and loading the BIOS into
# the top of memory.
zmac(
name = "boot_o",
srcs = [
"boot.z80",
"//include:cpm.lib",
"//include:cpmish.lib",
"//include:z180.lib",
"//arch/wp2450ds/include:wp2450ds.lib",
":addresses",
],
)
ld80(
name = "boot_img",
address = 0x5000,
objs = {
0x5000: [ ":boot_o", ":upd765_o" ]
}
)
# BIOS ----------------------------------------------------------------------
# The CP/M BIOS itself.
zmac(
name = "bios_o",
srcs = [
"bios.z80",
"//include:cpm.lib",
"//include:cpmish.lib",
"//include:z180.lib",
"//arch/wp2450ds/include:wp2450ds.lib",
":addresses",
],
)
# This is a 64kB file containing the entire CP/M memory image.
ld80(
name = "memory_img",
address = 0,
objs = {
cbase: [ "//third_party/zcpr1" ],
fbase: [ "//third_party/zsdos" ],
bbase: [
":bios_o",
":upd765_o",
":tty_o",
":keyboard_o",
]
}
)
# We now chop it up to remove the BIOS and the combined CCP/BDOS (which
# go into the system track).
binslice(
name = "bios_img",
src = ":memory_img",
start = bbase,
length = 0x10000 - bbase
)
binslice(
name = "systemtrack_img",
src = ":memory_img",
start = cbase,
length = bbase - cbase
)
# FAT file system -----------------------------------------------------------
# Produces the FAT bit of the disk image.
zmac(
name = "bootfile_img",
srcs = [
"fat.z80",
":boot_img",
":bios_img",
":systemtrack_img",
],
relocatable = False
)
# Disk image ----------------------------------------------------------------
# Assembles the bootable disk which you can actually run.
unix2cpm(
name = "readme",
src = "README.md"
)
diskimage(
name = "diskimage",
format = "brother-wp2450ds",
bootfile = ":bootfile_img",
map = {
"-readme.txt": ":readme",
"asm.com": "//cpmtools:asm",
"bbcbasic.com": "//third_party/bbcbasic:bbcbasic_ADM3A",
"camel80.com": "//third_party/camelforth",
"copy.com": "//cpmtools:copy",
"mkfs.com": "//cpmtools:mkfs",
"rawdisk.com": "//cpmtools:rawdisk",
"dump.com": "//cpmtools:dump",
"qe.com": "//cpmtools:qe_BROTHER_WP2450DS",
"ted.com": "//third_party/ted:ted_WP2450DS",
"z8e.com": "//third_party/z8e:z8e_WP2450DS",
"stat.com": "//cpmtools:stat",
"submit.com": "//cpmtools:submit",
"startrek.com": "//third_party/startrek",
},
)

View file

@ -1,216 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
include "utils/build.lua"
--- Memory layout configuration ---------------------------------------------
-- Configure the BIOS size here; this will then emit an addresses.lib file
-- which contains the position of the BDOS and CCP.
local BIOS_SIZE = 0x0f00
local BDOS_SIZE = 3584 -- fixed
local CCP_SIZE = 2048 -- fixed
local BBASE = 0x10000 - BIOS_SIZE
local FBASE = BBASE - BDOS_SIZE
local CBASE = FBASE - CCP_SIZE
normalrule {
name = "addresses_lib",
ins = {},
outleaves = { "addresses.lib" },
commands = {
"echo BIOS_SIZE = "..BIOS_SIZE.." > %{outs[1]}",
"echo BDOS_SIZE = "..BDOS_SIZE.." >> %{outs[1]}",
"echo CCP_SIZE = "..CCP_SIZE.." >> %{outs[1]}",
"echo BBASE = "..BBASE.." >> %{outs[1]}",
"echo FBASE = "..FBASE.." >> %{outs[1]}",
"echo CBASE = "..CBASE.." >> %{outs[1]}",
}
}
--- Generated tables --------------------------------------------------------
-- Font and keyboard table.
normalrule {
name = "font_inc",
ins = {
"arch/wp2450ds/utils+fontconvert",
"utils/6x7font.bdf",
},
outleaves = { "font.inc" },
commands = {
"%{ins} > %{outs}"
}
}
normalrule {
name = "keytab_inc",
ins = { "arch/wp2450ds/utils+mkkeytab" },
outleaves = { "keytab.inc" },
commands = {
"%{ins} > %{outs}"
}
}
--- Libraries ---------------------------------------------------------------
-- These may be used by both the BIOS proper and the bootstrap program.
zmac {
name = "tty_o",
srcs = { "./tty.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/tty.lib",
"+font_inc"
},
}
zmac {
name = "upd765_o",
srcs = { "./upd765.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/upd765.lib",
"arch/common/utils/deblocker.lib",
},
}
zmac {
name = "keyboard_o",
srcs = { "./keyboard.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"+keytab_inc",
},
}
--- Bootstrapper ------------------------------------------------------------
-- This is the .APL file which the Brother OS loads. It's responsible for
-- remapping the memory, doing some device setup, and loading the BIOS into
-- the top of memory.
zmac {
name = "boot_o",
srcs = { "./boot.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/upd765.lib",
"arch/common/utils/deblocker.lib",
"+addresses_lib"
},
}
ld80 {
name = "boot_img",
address = 0x5000,
srcs = {
"-P5000",
"+boot_o",
"+upd765_o",
}
}
--- BIOS --------------------------------------------------------------------
-- The CP/M BIOS itself.
zmac {
name = "bios_o",
srcs = { "./bios.z80" },
deps = {
"include/*.lib",
"./include/*.lib",
"arch/common/utils/tty.lib",
"arch/common/utils/upd765.lib",
"arch/common/utils/deblocker.lib",
"+font_inc",
"+addresses_lib",
},
}
-- This is a 64kB file containing the entire CP/M memory image.
ld80 {
name = "memory_img",
address = 0,
srcs = {
"-P"..string.format("%x", CBASE), "third_party/zcpr1+zcpr",
"-P"..string.format("%x", FBASE), "third_party/zsdos+zsdos",
"-P"..string.format("%x", BBASE),
"+bios_o",
"+upd765_o",
"+tty_o",
"+keyboard_o",
}
}
-- We now chop it up to remove the BIOS and the combined CCP/BDOS (which
-- go into the system track).
binslice {
name = "bios_img",
src = { "+memory_img" },
start = BBASE,
length = BIOS_SIZE
}
binslice {
name = "systemtrack_img",
src = { "+memory_img" },
start = CBASE,
length = BBASE - CBASE
}
--- FAT file system ---------------------------------------------------------
-- Produces the FAT bit of the disk image.
zmac {
name = "bootfile_img",
srcs = { "./fat.z80" },
deps = {
"+boot_img",
"+bios_img",
"+systemtrack_img"
},
relocatable = false
}
--- Disk image --------------------------------------------------------------
-- Assembles the bootable disk which you can actually run.
unix2cpm {
name = "readme",
srcs = { "README.md" }
}
diskimage {
name = "diskimage",
format = "brother-wp2450ds",
bootfile = { "+bootfile_img" },
map = {
["asm.com"] = "cpmtools+asm",
["copy.com"] = "cpmtools+copy",
["dump.com"] = "cpmtools+dump",
["mkfs.com"] = "cpmtools+mkfs",
["rawdisk.com"] = "cpmtools+rawdisk",
["stat.com"] = "cpmtools+stat",
["submit.com"] = "cpmtools+submit",
["-readme.txt"] = "+readme",
["bbcbasic.com"] = "third_party/bbcbasic+bbcbasic_ADM3A",
["qe.com"] = "cpmtools+qe_BROTHER_WP2450DS",
["z8e.com"] = "third_party/z8e+z8e_WP2450DS",
["ted.com"] = "third_party/ted+ted_WP2450DS",
["camel80.com"] = "third_party/camelforth+camelforth",
},
}

View file

@ -0,0 +1,5 @@
package(default_visibility = ["//visibility:public"])
exports_files(glob(["*.lib"]))

15
arch/wp2450ds/utils/BUILD Normal file
View file

@ -0,0 +1,15 @@
package(default_visibility = ["//visibility:public"])
cc_binary(
name = "fontconvert",
srcs = [ "fontconvert.c" ],
deps = [
"//utils:libbdf"
]
)
cc_binary(
name = "mkkeytab",
srcs = [ "mkkeytab.c" ]
)

View file

@ -1,10 +0,0 @@
cprogram {
name = "mkkeytab",
srcs = { "./mkkeytab.c" }
}
cprogram {
name = "fontconvert",
srcs = { "./fontconvert.c" },
deps = { "utils+libbdf" },
}

View file

@ -54,3 +54,5 @@ int main(int argc, const char* argv[])
return 0;
}
// vim: ts=4 sw=4 et

View file

@ -1,16 +0,0 @@
vars.cflags = { "-g", "-Og" }
vars.ldflags = { "-lm" }
vars.cpmcflags = { "-O6" }
vars.cpmldflags = {}
installable {
name = "all",
map = {
["emu"] = "utils/emu+emu",
["nc200.img"] = "arch/nc200+diskimage",
["kayproii.img"] = "arch/kayproii+diskimage",
["brotherop2.img"] = "arch/brotherop2+diskimage",
["wp2450ds.img"] = "arch/wp2450ds+diskimage",
["brotherwp1.img"] = "arch/brotherwp1+diskimage",
}
}

0
build/BUILD Normal file
View file

127
build/ack.bzl Normal file
View file

@ -0,0 +1,127 @@
def _removeextension(s):
i = s.rindex(".")
return s[:i]
def _compile_ack_files(ctx, srcfiles, headers):
ofiles = []
for src in srcfiles:
n = src.basename[:src.basename.rindex(".")]
o = ctx.actions.declare_file(ctx.label.name + "/" + n + ".o")
h = [ header.dirname for header in headers ]
args = ctx.actions.args()
args.add("-m" + ctx.attr.arch)
args.add_all(ctx.attr.cflags)
args.add_all(h, format_each="-I%s")
args.add("-c")
args.add("-o", o)
args.add(src)
ctx.actions.run(
mnemonic = "AckCompile",
executable = "/usr/local/bin/ack",
arguments = [args],
inputs = [src] + headers,
outputs = [o]
)
ofiles += [o]
return ofiles
AckLibrary = provider(
"Ack Library fields",
fields = {
"public_headers": "depset of header Files from transitive dependencies.",
"files_to_link": "depset of Files from compilation.",
}
)
def _ack_library_impl(ctx):
sources = [f for f in ctx.files.srcs if f.extension == "c"]
private_headers = [f for f in ctx.files.srcs if f.extension == "h"]
public_headers = ctx.files.hdrs + [dep[AckLibrary].public_headers for dep in ctx.attr.deps]
ofiles = _compile_ack_files(ctx, sources, private_headers + public_headers)
output_file = ctx.actions.declare_file(ctx.label.name + ".a")
args = ctx.actions.args()
args.add("qc")
args.add(output_file)
args.add_all(ofiles)
ctx.actions.run(
mnemonic = "AckLibrary",
executable = "/usr/local/bin/aal",
arguments = [args],
inputs = ofiles,
outputs = [output_file],
)
return [
AckLibrary(
public_headers = depset(public_headers),
files_to_link = depset(
[output_file],
transitive = [
dep[AckLibrary].files_to_link for dep in ctx.attr.deps
],
),
),
DefaultInfo(files = depset([output_file])),
]
ack_library = rule(
implementation = _ack_library_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
"cflags": attr.string_list(),
"arch": attr.string(default = "cpm"),
"deps": attr.label_list(providers = [AckLibrary]),
"hdrs": attr.label_list(allow_files = True),
}
)
def _ack_binary_impl(ctx):
sources = [f for f in ctx.files.srcs if f.extension == ".c"]
private_headers = [f for f in ctx.files.srcs if f.extension == ".h"]
public_headers = [f for dep in ctx.attr.deps for f in dep[AckLibrary].public_headers.to_list()]
files_to_link = [f for dep in ctx.attr.deps for f in dep[AckLibrary].files_to_link.to_list()]
ofiles = _compile_ack_files(ctx, ctx.files.srcs, private_headers + public_headers)
output_file = ctx.actions.declare_file(ctx.label.name + ".exe")
args = ctx.actions.args()
args.add("-m" + ctx.attr.arch)
args.add("-." + ctx.attr.lang)
args.add("-o", output_file)
args.add_all(ofiles)
args.add_all(files_to_link)
ctx.actions.run(
mnemonic = "AckBinary",
executable = "/usr/local/bin/ack",
arguments = [args],
inputs = ofiles + files_to_link,
outputs = [output_file],
)
return [
DefaultInfo(files = depset([output_file])),
]
ack_binary = rule(
implementation = _ack_binary_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
"cflags": attr.string_list(),
"arch": attr.string(default = "cpm"),
"deps": attr.label_list(providers = [AckLibrary]),
"lang": attr.string(default = "c"),
}
)
# vim: ts=4 sw=4 et

View file

@ -1,951 +0,0 @@
-- Targets:
--
-- {
-- fullname = full name of target
-- dir = target's build directory
-- outs = target's object files
-- is = { set of rule types which made the target }
-- }
local emitter = {}
local rules = {}
local targets = {}
local buildfiles = {}
local globals
local cwd = "."
local vars = {}
local parente = {}
local loadingstack = {}
local PWD = os.getenv("PWD")
-- Forward references
local loadtarget
-- Posix replacement
local function access(filename, mode)
local fp = io.open(filename, mode)
if not fp then
return false
end
fp:close()
return true
end
local function glob(path)
local _, _, lhs, rhs = path:find("(.*)/([^/]*)$")
if lhs:find("[*?]") then
error("directory part of glob may not contain wildcards")
end
if not rhs:find("[*?]") then
return {path}
end
local fp = io.popen("find '"..lhs.."' -name '"..rhs.."' -type f 2> /dev/null", "r")
local files = {}
for f in fp:lines() do
files[#files+1] = f
end
fp:close()
return files
end
local function print(...)
local function print_no_nl(list)
for _, s in ipairs(list) do
if (type(s) == "table") then
io.stderr:write("{")
for k, v in pairs(s) do
print_no_nl({k})
io.stderr:write("=")
print_no_nl({v})
io.stderr:write(" ")
end
io.stderr:write("}")
else
io.stderr:write(tostring(s))
end
end
end
print_no_nl({...})
io.stderr:write("\n")
end
local function assertString(s, i)
if (type(s) ~= "string") then
error(string.format("parameter %d must be a string", i))
end
end
local function concat(...)
local r = {}
local function process(list)
for _, t in ipairs(list) do
if (type(t) == "table") and not t.is then
process(t)
else
r[#r+1] = t
end
end
end
process({...})
return r
end
-- Test table membership (crudely).
local function contains(needle, haystack)
for _, k in ipairs(haystack) do
if (k == needle) then
return true
end
end
return false
end
local function inherit(high, low)
local o = {}
setmetatable(o, {
__index = function(self, k)
local x = high[k]
if x then
return x
end
return low[k]
end
})
for k, v in pairs(high) do
local _, _, kk = k:find("^%+(.*)$")
if kk then
o[kk] = concat(low[kk], v)
end
end
return o
end
local function asstring(o)
local t = type(o)
if (t == "nil") then
return ""
elseif (t == "string") then
return o
elseif (t == "number") then
return o
elseif (t == "table") then
if o.is then
return asstring(o.outs)
else
local s = {}
for _, v in pairs(o) do
s[#s+1] = asstring(v)
end
return table.concat(s, " ")
end
else
error(string.format("can't turn values of type '%s' into strings", t))
end
end
local function concatpath(...)
local p = table.concat({...}, "/")
return (p:gsub("/+", "/"):gsub("^%./", ""):gsub("/%./", "/"))
end
-- Returns a list of the targets within the given collection; the keys of any
-- keyed items are lost. Lists and wildcards are expanded.
local function targetsof(...)
local o = {}
local function process(items)
for _, item in pairs(items) do
if (type(item) == "table") then
if item.is then
-- This is a target.
o[#o+1] = item
else
-- This is a list.
process(item)
end
elseif (type(item) == "string") then
-- Filename!
if item:find("^%+") then
item = cwd..item
elseif item:find("^%./") then
item = concatpath(cwd, item)
end
o[#o+1] = loadtarget(item)
else
error(string.format("member of target list is not a string or a target"))
end
end
end
process({...})
return o
end
local function filenamesof(...)
local targets = targetsof(...)
local f = {}
for _, r in ipairs(targets) do
if (type(r) == "table") and r.is then
if r.outs then
for _, o in ipairs(r.outs) do
f[#f+1] = o
end
end
elseif (type(r) == "string") then
f[#f+1] = r
else
error(string.format("list of targets contains a %s which isn't a target",
type(r)))
end
end
return f
end
local function targetnamesof(...)
local targets = targetsof(...)
local f
for _, r in pairs(targets) do
if (type(r) == "table") and r.is then
f[#f+1] = r.fullname
elseif (type(r) == "string") then
f[#f+1] = r
else
error(string.format("list of targets contains a %s which isn't a target",
type(r)))
end
end
return f
end
local function dotocollection(files, callback)
if (#files == 1) and (type(files[1]) == "string") then
return callback(files[1])
end
local o = {}
local function process(files)
for _, s in ipairs(files) do
if (type(s) == "table") then
if s.is then
error("passed target to a filename manipulation function")
else
process(s)
end
else
local b = callback(s)
if (b ~= "") then
o[#o+1] = b
end
end
end
end
process(files)
return o
end
local function abspath(...)
return dotocollection({...},
function(filename)
assertString(filename, 1)
if not filename:find("^[/$]") then
filename = concatpath(PWD, filename)
end
return filename
end
)
end
local function basename(...)
return dotocollection({...},
function(filename)
assertString(filename, 1)
local _, _, b = filename:find("^.*/([^/]*)$")
if not b then
return filename
end
return b
end
)
end
local function dirname(...)
return dotocollection({...},
function(filename)
assertString(filename, 1)
local _, _, b = filename:find("^(.*)/[^/]*$")
if not b then
return ""
end
return b
end
)
end
local function replace(files, pattern, repl)
return dotocollection({files},
function(filename)
return filename:gsub(pattern, repl)
end
)
end
local function fpairs(...)
return ipairs(filenamesof(...))
end
local function matching(collection, pattern)
local o = {}
dotocollection(collection,
function(filename)
if filename:find(pattern) then
o[#o+1] = filename
end
end
)
return o
end
-- Selects all targets containing at least one output file that matches
-- the pattern (or all, if the pattern is nil).
local function selectof(targets, pattern)
local targets = targetsof(targets)
local o = {}
for k, v in pairs(targets) do
if v.is and v.outs then
local matches = false
for _, f in pairs(v.outs) do
if f:find(pattern) then
matches = true
break
end
end
if matches then
o[#o+1] = v
end
end
end
return o
end
local function uniquify(...)
local s = {}
return dotocollection({...},
function(filename)
if not s[filename] then
s[filename] = true
return filename
end
end
)
end
local function startswith(needle, haystack)
return haystack:sub(1, #needle) == needle
end
local function emit(...)
local n = select("#", ...)
local args = {...}
for i=1, n do
local s = asstring(args[i])
io.stdout:write(s)
if not s:find("\n$") then
io.stdout:write(" ")
end
end
end
local function templateexpand(list, vars)
vars = inherit(vars, globals)
local o = {}
for _, s in ipairs(list) do
o[#o+1] = s:gsub("%%%b{}",
function(expr)
expr = expr:sub(3, -2)
local chunk, e = loadstring("return ("..expr..")", expr)
if e then
error(string.format("error evaluating expression: %s", e))
end
setfenv(chunk, vars)
local value = chunk()
if (value == nil) then
error(string.format("template expression '%s' expands to nil (probably an undefined variable)", expr))
end
return asstring(value)
end
)
end
return o
end
local function loadbuildfile(filename)
if contains(filename, loadingstack) then
error(string.format("build file cycle; '%s' refers to itself indirectly; stack is: %s %s",
filename, asstring(loadingstack), filename))
end
loadingstack[#loadingstack+1] = filename
if not buildfiles[filename] then
buildfiles[filename] = true
local fp, data, chunk, e
io.stderr:write("loading ", filename, "\n")
fp, e = io.open(filename)
if not e then
data, e = fp:read("*a")
fp:close()
if not e then
local thisglobals = {}
thisglobals._G = thisglobals
setmetatable(thisglobals, {__index = globals})
chunk, e = loadstring(data, "@"..filename)
if not e then
setfenv(chunk, thisglobals)
end
end
end
if e then
error(string.format("couldn't load '%s': %s", filename, e))
end
local oldcwd = cwd
cwd = dirname(filename)
chunk()
cwd = oldcwd
end
loadingstack[#loadingstack] = nil
end
local function loadbuildfilefor(filepart, targetpart)
local normalname = concatpath(filepart, "/build.lua")
if access(normalname, "r") then
loadbuildfile(normalname)
return
end
local extendedname = concatpath(filepart, "/build-"..targetpart..".lua")
if access(extendedname, "r") then
loadbuildfile(extendedname)
return
end
error(string.format("could not access either '%s' or '%s'", normalname, extendedname))
end
loadtarget = function(targetname)
if targets[targetname] then
return targets[targetname]
end
local target
if not targetname:find("%+") then
local files
if targetname:find("[?*]") then
files = glob(targetname)
if not files then
files = {}
end
else
files = {targetname}
end
target = {
outs = files,
is = {
__implicitfile = true
}
}
targets[targetname] = target
else
local _, _, filepart, targetpart = targetname:find("^([^+]*)%+([%w-_]+)$")
if not filepart or not targetpart then
error(string.format("malformed target name '%s'", targetname))
end
if (filepart == "") then
filepart = cwd
end
loadbuildfilefor(filepart, targetpart)
target = targets[targetname]
if not target then
error(string.format("build file '%s' contains no target '%s'",
filepart, targetpart))
end
end
return target
end
local typeconverters = {
targets = function(propname, i)
if (type(i) == "string") then
i = {i}
elseif (type(i) ~= "table") then
error(string.format("property '%s' must be a target list", propname))
end
local m = {}
for k, v in pairs(i) do
local ts = targetsof(v)
if (type(k) == "number") then
for _, t in ipairs(ts) do
m[#m+1] = t
end
else
if (#ts ~= 1) then
error(string.format("named target '%s' can only be assigned from a single target", k))
else
m[k] = ts[1]
end
end
end
return m
end,
strings = function(propname, i)
if (type(i) == "string") then
i = {i}
elseif (type(i) ~= "table") then
error(string.format("property '%s' must be a string list", propname))
end
return concat(i)
end,
boolean = function(propname, i)
if (type(i) ~= "boolean") then
error(string.format("property '%s' must be a boolean", propname))
end
return i
end,
string = function(propname, i)
if (type(i) ~= "string") then
error(string.format("property '%s' must be a string", propname))
end
return i
end,
number = function(propname, i)
if (type(i) ~= "number") then
error(string.format("property '%s' must be a number", propname))
end
return i
end,
table = function(propname, i)
if (type(i) ~= "table") then
error(string.format("property '%s' must be a table", propname))
end
return i
end,
object = function(propname, i)
return i
end,
}
local function definerule(rulename, types, cb)
if rulename and rules[rulename] then
error(string.format("rule '%s' is already defined", rulename))
end
types.name = { type="string" }
types.cwd = { type="string", optional=true }
types.vars = { type="table", default={} }
for propname, typespec in pairs(types) do
if not typeconverters[typespec.type] then
error(string.format("property '%s' has unrecognised type '%s'",
propname, typespec.type))
end
end
local rulecwd = cwd
local rule = function(e)
local definedprops = {}
for propname, _ in pairs(e) do
definedprops[propname] = true
end
local args = {}
for propname, typespec in pairs(types) do
if e[propname] == nil then
if not typespec.optional and (typespec.default == nil) then
error(string.format("missing mandatory property '%s'", propname))
end
args[propname] = typespec.default
else
args[propname] = typeconverters[typespec.type](propname, e[propname])
definedprops[propname] = nil
end
end
local propname, _ = next(definedprops)
if propname then
error(string.format("don't know what to do with property '%s'", propname))
end
if not args.cwd then
args.cwd = cwd
end
args.fullname = args.cwd.."+"..args.name
local oldparente = parente
parente = args
args.vars = inherit(args.vars, oldparente.vars)
local result = cb(args) or {}
parente = oldparente
result.is = result.is or {}
if rulename then
result.is[rulename] = true
end
result.fullname = args.fullname
if targets[arg.fullname] and (targets[arg.fullname] ~= result) then
error(string.format("target '%s' is already defined", args.fullname))
end
targets[result.fullname] = result
return result
end
if rulename then
if rules[rulename] then
error(string.format("rule '%s' is already defined", rulename))
end
rules[rulename] = rule
end
return rule
end
-----------------------------------------------------------------------------
-- DEFAULT RULES --
-----------------------------------------------------------------------------
local function install_make_emitter()
emit("hide = @\n")
function emitter:var(name, value)
-- Don't let emit insert spaces.
emit(name.."="..value.."\n")
end
function emitter:rule(name, ins, outs)
if (#outs == 0) then
local n = name.."-IMAGINARY-OUT"
emit(".INTERMEDIATE:", n, "\n")
outs = {n}
end
local impl = name.."-IMPL"
emit(".INTERMEDIATE:", name, "\n")
emit(".INTERMEDIATE:", impl, "\n")
for i = 1, #outs do
emit(name..":", outs[i], "\n")
end
for i = 1, #outs do
emit(outs[i]..":", impl, ";\n")
end
for i = 1, #ins do
emit(impl..":", ins[i], "\n")
end
emit(impl..":", "\n")
local dirs = uniquify(dirname(outs))
if (#dirs > 0) then
emit("\t@mkdir -p", dirs, "\n")
end
end
function emitter:phony(name, ins, outs)
emit(".PHONY:", name, "\n")
self:rule(name, ins, outs)
end
function emitter:label(...)
local s = table.concat({...}, " ")
emit("\t@echo", s, "\n")
end
function emitter:exec(commands)
for _, s in ipairs(commands) do
emit("\t$(hide)", s, "\n")
end
end
function emitter:endrule()
emit("\n")
end
end
local function install_ninja_emitter()
emit("rule build\n")
emit(" command = $command\n")
emit("\n")
local function unmake(collection)
return dotocollection({collection},
function(s)
return s:gsub("%$%b()",
function(expr)
return "${"..expr:sub(3, -2).."}"
end
)
end
)
end
function emitter:var(name, value)
-- Don't let emit insert spaces.
emit(name.."="..unmake(value).."\n")
end
function emitter:rule(name, ins, outs)
if (#outs == 0) then
emit("build", name, ": phony", unmake(ins), "\n")
else
emit("build", name, ": phony", unmake(outs), "\n")
emit("build", unmake(outs), ": build", unmake(ins), "\n")
end
end
function emitter:label(...)
end
function emitter:exec(commands)
emit(" command =", table.concat(unmake(commands), " && "), "\n")
end
function emitter:endrule()
emit("\n")
end
end
definerule("simplerule",
{
ins = { type="targets" },
outs = { type="strings" },
deps = { type="targets", default={} },
label = { type="string", optional=true },
commands = { type="strings" },
vars = { type="table", default={} },
},
function (e)
emitter:rule(e.fullname, filenamesof(e.ins, e.deps), e.outs)
emitter:label(e.fullname, " ", e.label or "")
local vars = inherit(e.vars, {
ins = filenamesof(e.ins),
outs = filenamesof(e.outs)
})
emitter:exec(templateexpand(e.commands, vars))
emitter:endrule()
return {
outs = e.outs
}
end
)
definerule("installable",
{
map = { type="targets", default={} },
deps = { type="targets", default={} },
},
function (e)
local deps = filenamesof(e.deps)
local commands = {}
local srcs = {}
local outs = {}
local dests = {}
for dest, src in pairs(e.map) do
if src.is.installable then
if (type(dest) ~= "number") then
error("can't specify a destination filename when installing an installable")
end
deps[#deps+1] = src.fullname
outs = concat(outs, filenamesof(src))
elseif (type(dest) == "number") then
error("only references to other installables can be missing a destination")
else
local f = filenamesof(src)
if (#f ~= 1) then
error("installable can only cope with targets emitting single files")
end
deps[#deps+1] = f
dests[#dests+1] = dest
outs[#outs+1] = dest
commands[#commands+1] = "cp "..f[1].." "..dest
end
end
emitter:rule(e.fullname, deps, dests)
emitter:label(e.fullname, " ", e.label or "")
if (#commands > 0) then
emitter:exec(commands)
end
emitter:endrule()
return {
outs = outs
}
end
)
-----------------------------------------------------------------------------
-- MAIN PROGRAM --
-----------------------------------------------------------------------------
local function parse_arguments(argmap, arg)
local i = 1
local files = {}
local function unrecognisedarg(arg)
argmap[" unrecognised"](arg)
end
while (i <= #arg) do
local o = arg[i]
local op
if (o:byte(1) == 45) then
-- This is an option.
if (o:byte(2) == 45) then
-- ...with a -- prefix.
o = o:sub(3)
local fn = argmap[o]
if not fn then
unrecognisedarg("--"..o)
end
i = i + fn(arg[i+1], arg[i+2])
else
-- ...without a -- prefix.
local od = o:sub(2, 2)
local fn = argmap[od]
if not fn then
unrecognisedarg("-"..od)
end
op = o:sub(3)
if (op == "") then
i = i + fn(arg[i+1], arg[i+2])
else
fn(op)
end
end
else
files[#files+1] = o
end
i = i + 1
end
argmap[" files"](files)
end
globals = {
abspath = abspath,
asstring = asstring,
basename = basename,
concat = concat,
concatpath = concatpath,
cwd = function() return cwd end,
definerule = definerule,
dirname = dirname,
emit = emit,
filenamesof = filenamesof,
fpairs = fpairs,
include = loadbuildfile,
inherit = inherit,
print = print,
replace = replace,
matching = matching,
selectof = selectof,
startswith = startswith,
uniquify = uniquify,
vars = vars,
}
setmetatable(globals,
{
__index = function(self, k)
local rule = rules[k]
if rule then
return rule
else
return _G[k]
end
end
}
)
vars.cflags = {}
parente.vars = vars
setmetatable(_G,
{
__index = function(self, k)
local value = rawget(_G, k)
if not value then
error(string.format("access of undefined variable '%s'", k))
end
return value
end
}
)
do
local emitter_type = install_make_emitter
parse_arguments(
{
["make"] = function()
emitter_type = install_make_emitter
return 0
end,
["ninja"] = function()
emitter_type = install_ninja_emitter
return 0
end,
[" unrecognised"] = function(arg)
error(string.format("unrecognised argument '%s'", arg))
end,
[" files"] = function(files)
emitter_type()
for _, f in ipairs(files) do
local _, _, name, value = f:find("^([%w_]+)=(.*)$")
if name then
emitter:var(name, value)
end
end
for _, f in ipairs(files) do
if not f:find("=") then
loadbuildfile(f)
end
end
end
},
{...}
)
end

View file

@ -1,351 +0,0 @@
# ackbuilder
## What is it?
ackbuilder is a very small build tool inspired by [bazel](https://bazel.io/)
which uses either make or [ninja](https://ninja-build.org/) as a backend.
It supports fully parallelisable builds (in both make and ninja), as well as
hopefully-robust support for rules which generate more than one output file,
which is something make is very, very bad at.
It was written because the ACK is a really horribly complex thing to build and
there wasn't anything else. ackbuilder is pretty rough and ready but it does
sort of work. Be prepared for bugs.
This document is a very rapid brain dump of how the build file works. It
doesn't cover actually running the tool (because that bit's pretty nasty) ---
go look at the top level Makefile to see that for now.
## Basic concepts
Complete example, using the built-in C rules. This should be saved in a file
called `build.lua`:
cprogram {
name = 'prog',
srcs = { "./*.c" },
}
This defines a rule `prog` which, when built, compiles all the source files in
the same directory as the `build.lua` file into an executable.
Slightly more complex example:
clibrary {
name = "library",
srcs = { "./library.c" },
hdrs = { "./library.h" },
}
cprogram {
name = 'prog2',
srcs = { "./prog2.c" },
deps = { "+library" }
}
If we move the library into another directory, we can invoke it like this:
cprogram {
name = 'prog3',
srcs = { "./prog3.c" },
deps = { "path/to/library+library" }
}
* Targets starting with `./` are relative to **the current directory** (i.e.
the one the build file is in).
* Targets starting with a path are relative to the top directory of the
project.
* Targets containing a `+` refer to a named target in another build file. So,
on encountering the library in `prog3` above, ackbuilder will look for
`path/to/library/build.lua`, load it, and then try to find a target in it
called `library`.
**Warning**: files are interpreted from top to bottom; every time a target
referring to another build file is seen for the first time, that file is
interpreted then and there. You can't have circular dependencies (these are
caught and an error is generated). You can't refer to a target defined below
you in the same source file (these are not caught, and just won't be found).
Build files each get their own private global scope. If you randomly set a
variable, it won't be seen by other build files. (Use `vars` for that; see
below.) Build files are only loaded once.
The `cprogram` and `clibrary` rules, by the way, are sophisticated enough to
automatically handle library and header paths. The exported headers by the
library are automatically imported into the program.
## `simplerule` and `normalrule`
These are the building blocks out of which all other rules are made. If you
want to run your own programs, you will be using these.
`simplerule` is the simplest. You give it inputs, and outputs, and commands,
and it does it.
simplerule {
name = 'sorted-input',
ins = { './input.txt' },
outs = { './output.txt' },
commands = {
"sort < %{ins} > %{outs}"
}
}
In a command block, `%{...}` will evaluate the Lua expression between the
braces; various useful things are in scope, including the list of inputs and
outputs.
However, this ends up leaving the output file lying around in the project
directory, which we don't want, so we usually use `normalrule` instead.
(`normalrule` is not strictly part of the ackbuilder core; it's in the standard
library along with `cprogram` and `clibrary`.)
normalrule {
name = 'sorted-input',
ins = { './input.txt' },
outleaves = { 'output.txt' },
commands = {
"sort < %{ins} > %{outs}"
}
}
Note `outleaves`; there is no `./`. This is a list of leaf filenames. The rule
will create a directory in the object tree and put the files specified in it,
somewhere; you don't care where. You can refer to the output file via the
target name, so:
normalrule {
name = 'reversed',
ins = { '+sorted-input' },
outleaves = { 'reversed.txt' },
commands = {
"rev < %{ins} > %{outs}"
}
}
One common use for this is to generate C header or source files.
normalrule {
name = 'reversed_h',
ins = { '+reversed' },
outleaves = { 'reversed.h' },
commands = {
'xxd -i %{ins} > %{outs}'
}
}
cprogram {
name = 'prog',
srcs = { './*.c' },
deps = { '+reversed_h' }
}
Now you can refer to `reversed.h` in one of your C files and it'll just work
(`+reversed_h`'s output directory gets added to the include path
automatically).
## Defining your own rules
Like this:
definerule("sort",
{
srcs = { type="targets" },
},
function(e)
return normalrule {
name = e.name,
ins = e.srcs,
outleaves = { 'sorted.txt' },
commands = {
"sort < %{ins} > %{outs}"
}
}
}
)
sort {
name = 'sorted',
srcs = { './input.txt' }
}
You give `definerule()` the name of the rule you want to define, a description
of the properties the rule will take, and a callback that does the work.
You can do anything you like in the callback, including defining as many
targets as you like; but remember that all targets must have unique names, so
for any temporary files you probably want something like `name =
e.name.."/intermediate"` to ensure uniqueness.
The callback should end by returning an invocation of another rule, with `name
= e.name` as above.
Rules are defined whenever a build file containing them is seen. Letting this
happen automatically doesn't always work so you probably want to explicitly
include it:
include("foo/bar/baz/build.lua")
Rule properties are typed and can be specified to be required or optional (or
have a default value). If you try to invoke a rule with a property which isn't
declared, or missing a property which should be declared, you'll get an error.
definerule("sort",
{
srcs = { type="targets" },
numeric = { type="boolean", optional=true, default=false }
}
...omitted...
(The `optional=true` part can be omitted if you specify a default which isn't
`nil`.)
Types include:
* `targets`: the most common one. When the rule is invoked, ackbuilder will
resolve these for you so that when your callback fires, the property is a
flattened list of target objects.
* `strings`: a Lua table of strings. If the invoker supplies a single string
which isn't a table, it'll get wrapped in one.
* `string`: a string.
* `boolean`: a boolean (either `true` or `false`; nothing else is allowed).
* `table`: a Lua table.
* `object`: any Lua value.
## Target objects
When a rule callback is run, any targets it needs will be resolved into target
objects. These are Lua objects with assorted useful stuff in them.
* `object.is`: contains a set telling you which rules made the object. e.g.
`object.is.cprogram` is true if `object` was built with `cprogram`. Bear in
mind that `object.is.normalrule` is _also_ going to be true.
* `object.dir`: the object's build directory. Only exists if the object was
built with `normalrule`.
There are other properties (`fullname` and `outs`). Please don't use these; use
`targetnamesof()` and `filenamesof()` as described below.
## The standard library
Your build files are supplied a pile of useful functions.
### Manipulating target lists
A target list is a possibly nested set of tables containing either target
objects or strings. All of these functions will implicitly flatten the list and
resolve any strings into target objects before doing anything else to them.
Most of these functions can be supplied with varargs parameters.
e.g. `targetsof(a, b)` is equivalent to `targetsof({a, b})` is equivalent to
`targetsof({a, {b}})`.
* `targetsof(...)`: just flattens the list and resolves any string target
names.
* `filenamesof(...)`: returns a list of output files for all the supplied
targets.
* `targetnamesof(...)`: returns a list of fully qualified target names for
all the supplied stargets.
* `selectof(targets, pattern)`: returns only those targets whose outputs
contain at least one file matching the pattern.
### Manipulating filename lists
Like the target list functions, all of these implicitly flatten any nested
tables. They all return lists; however, as a special exception, if any of the
functions which take varargs parameters have a single parameter which is a
string, they return just a string.
e.g. `abspath({f})` returns a table; `abspath(f)` returns a string.
* `abspath(...)`: attempts to return the absolute path of its arguments. This
isn't always possible due to variable references.
* `basename(...)`: returns the basenames of its arguments (the file part of
the path).
* `dirname(...)`: returns the directory name of its arguments.
* `matching(files, pattern)`: returns only those files which match a Lua
pattern.
* `replace(files, pattern, repl)`: performs a Lua pattern replace on the list
of files.
* `uniquify(...)`: removes duplicates.
### Other things
* `include(file)`: loads another build file, if it hasn't been loaded before.
## Variables
There are two types of variable, mostly for hysterical reasons.
### Makefile variables
(Despite the name, these work on ninja too.)
Filenames can contain variable references of the form `$(FOO)`. These are
expanded at build time based on definitions supplied on the ackbuilder command
line.
ackbuilder assumes that these are absolute paths and won't attempt to
manipulate them much.
I want to get rid of these at some point.
### ackbuilder variables
These are expanded by ackbuilder itself.
Every rule invocation contains a magic property, `vars`. When a rule's commands
are executed, the variables provided in the template expansion are calculated
by combining all `vars` settings in the call stack (including the top level
build file).
Easiest to explain with an example:
cprogram {
name = 'another_test',
srcs = { './*.c' },
vars = {
cflags = { '-g', '-O3' }
}
}
When `cprogram` builds each C file, the command will refer to `%{cflags}`. The
value above will be flattened into a space-separated string and substituted in.
Setting a variable this way will _override_ any definition further up the call
stack. However, you can do this:
vars.cflags = { '-g' }
cprogram {
name = 'another_test',
srcs = { './*.c' },
vars = {
["+cflags"] = { '-O3' }
}
}
Now `cflags` will default to `-g` everywhere, because it's set at the top
level; but when `another_test` is built, it'll be `-g -O3`.
ackbuilder variables are only expanded in command templates, not in filenames.
<!-- # vim: set ts=2 sw=2 expandtab : -->

22
build/build.bzl Normal file
View file

@ -0,0 +1,22 @@
def bison(name, src):
CFILE = "%s.c" % name
HFILE = "%s.h" % name
native.genrule(
name = name,
srcs = [src],
outs = [CFILE, HFILE],
cmd = "bison --defines=$(location {}) --output=$(location {}) $<".format(HFILE, CFILE)
)
def gperf(name, src, hash_function_name="hash", lookup_function_name="name"):
HFILE = "%s.h" % name
native.genrule(
name = name,
srcs = [src],
outs = [HFILE],
cmd = "gperf -o -E --constants-prefix={} -H{} -N{} -DptlC --output-file=$@ $<".format(
name, hash_function_name, lookup_function_name)
)
# vim: ts=4 sw=4 et

View file

@ -1,262 +0,0 @@
local function objdir(e)
return concatpath("$(OBJDIR)", e.cwd, e.name)
end
definerule("normalrule",
{
ins = { type="targets" },
deps = { type="targets", default={} },
outleaves = { type="strings" },
label = { type="string", optional=true },
objdir = { type="string", optional=true },
commands = { type="strings" },
},
function (e)
local dir = e.objdir or objdir(e)
local realouts = {}
for _, v in pairs(e.outleaves) do
realouts[#realouts+1] = concatpath(dir, v)
end
local vars = inherit(e.vars, {
dir = dir
})
local result = simplerule {
name = e.name,
ins = e.ins,
deps = e.deps,
outs = realouts,
label = e.label,
commands = e.commands,
vars = vars,
}
result.dir = dir
return result
end
)
definerule("cfile",
{
srcs = { type="targets" },
deps = { type="targets", default={} },
suffix = { type="string", default=".o" },
commands = {
type="strings",
default={
"$(CC) -c -o %{outs[1]} %{ins[1]} %{hdrpaths} %{cflags}"
},
}
},
function (e)
local hdrpaths = {}
for _, t in pairs(e.deps) do
if t.dir then
hdrpaths[#hdrpaths+1] = "-I"..t.dir
end
end
hdrpaths = uniquify(hdrpaths)
local outleaf = basename(e.name)..e.suffix
return normalrule {
name = e.name,
cwd = e.cwd,
ins = e.srcs,
deps = e.deps,
outleaves = {outleaf},
label = e.label,
commands = e.commands,
vars = {
hdrpaths = hdrpaths,
}
}
end
)
definerule("cppfile",
{
srcs = { type="targets" },
deps = { type="targets", default={} },
outleaf = { type="string" },
commands = {
type="strings",
default={
"$(CC) -E -P -o %{outs[1]} %{hdrpaths} %{cflags} -x c %{ins}"
}
},
},
function (e)
if (#e.srcs ~= 1) then
error("you must have exactly one input file")
end
local hdrpaths = {}
for _, t in pairs(e.deps) do
if t.dir then
hdrpaths[#hdrpaths+1] = "-I"..t.dir
end
end
hdrpaths = uniquify(hdrpaths)
return normalrule {
name = e.name,
cwd = e.cwd,
ins = e.srcs,
deps = e.deps,
outleaves = {e.outleaf},
label = e.label,
commands = e.commands,
vars = {
hdrpaths = hdrpaths,
}
}
end
)
definerule("bundle",
{
srcs = { type="targets" },
commands = {
type="strings",
default={
"tar cf - %{ins} | (cd %{dir} && tar xf -)"
}
}
},
function (e)
local outleaves = {}
local commands = {}
for _, f in fpairs(e.srcs) do
local localf = basename(f)
outleaves[#outleaves+1] = localf
commands[#commands+1] = "cp "..f.." %{dir}/"..localf
end
return normalrule {
name = e.name,
cwd = e.cwd,
ins = e.srcs,
outleaves = outleaves,
label = e.label,
commands = commands
}
end
)
definerule("clibrary",
{
srcs = { type="targets", default={} },
hdrs = { type="targets", default={} },
deps = { type="targets", default={} },
_cfile = { type="object", default=cfile },
suffix = { type="string", default=".o" },
commands = {
type="strings",
default={
"rm -f %{outs[1]}",
"$(AR) cqs %{outs[1]} %{ins}",
},
}
},
function (e)
local ins = {}
for _, src in fpairs(e.srcs) do
local n = basename(src):gsub("%.%w*$", "")
ins[#ins+1] = e._cfile {
name = e.name.."/"..n,
cwd = e.cwd,
srcs = {src},
deps = e.deps,
suffix = e.suffix,
vars = {
["+cflags"] = { "-I"..e.cwd, },
},
}
end
local commands = {}
local outleaves = {}
if (#e.srcs > 0) then
for _, s in ipairs(e.commands) do
commands[#commands+1] = s
end
outleaves[#outleaves+1] = e.name..".a"
end
local hdrsin = {}
for dest, src in pairs(e.hdrs) do
if (type(dest) == "number") then
for _, f in ipairs(filenamesof(src)) do
hdrsin[#hdrsin+1] = f
outleaves[#outleaves+1] = basename(f)
commands[#commands+1] = "cp "..asstring(f).." %{dir}"
end
else
local fs = filenamesof(src)
if (#fs ~= 1) then
error(string.format("keyed header '%s' can only be a single file", dest))
end
local f = fs[1]
hdrsin[#hdrsin+1] = f
outleaves[#outleaves+1] = dest
commands[#commands+1] = "cp "..asstring(f).." %{dir}/"..dest
end
end
return normalrule {
name = e.name,
cwd = e.cwd,
ins = ins,
deps = {hdrsin, e.deps},
outleaves = outleaves,
label = e.label,
commands = commands,
}
end
)
definerule("cprogram",
{
srcs = { type="targets", default={} },
deps = { type="targets", default={} },
_clibrary = { type="object", default=clibrary },
commands = {
type="strings",
default={
"$(CC) -o %{outs[1]} %{ins} %{ins} %{ldflags}"
},
}
},
function (e)
local libs = matching(filenamesof(e.deps), "%.a$")
local srcs = {}
if (#e.srcs > 0) then
for _, f in pairs(
matching(
filenamesof(
e._clibrary {
name = e.name .. "/main",
cwd = e.cwd,
srcs = e.srcs,
deps = e.deps,
}
),
"%.a$"
)
) do
srcs[#srcs+1] = f
end
end
return normalrule {
name = e.name,
cwd = e.cwd,
deps = e.deps,
ins = { srcs, libs },
outleaves = { e.name },
commands = e.commands,
}
end
)

59
build/cpm.bzl Normal file
View file

@ -0,0 +1,59 @@
def cpm_addresses(name, top_of_memory=0x10000, bios_size=None):
bdos_size = 3584 # fixed
ccp_size = 2048 # fixed
bbase = top_of_memory - bios_size
fbase = bbase - bdos_size
cbase = fbase - ccp_size
native.genrule(
name = name,
srcs = [],
outs = [ name + ".lib" ],
cmd = " && ".join([
"echo BIOS_SIZE = %d > $@" % bios_size,
"echo BDOS_SIZE = %d >> $@" % bdos_size,
"echo CCP_SIZE = %d >> $@" % ccp_size,
"echo CPM_SIZE = %d >> $@" % (bios_size + bdos_size + ccp_size),
"echo BBASE = %d >> $@" % bbase,
"echo FBASE = %d >> $@" % fbase,
"echo CBASE = %d >> $@" % cbase,
])
)
return (cbase, fbase, bbase)
def binslice(name, src, start, length=None):
if length == None:
native.genrule(
name = name,
srcs = [ src ],
outs = [ name + ".img" ],
cmd = "tail -c+%d $< > $@" % start
)
else:
native.genrule(
name = name,
srcs = [ src ],
outs = [ name + ".img" ],
cmd = "tail -c+%d $< | head -c%d > $@" % (start, length)
)
def diskimage(name, format, bootfile, map):
out = name + ".img"
native.genrule(
name = name,
srcs = [ bootfile, "//:diskdefs" ] + map.values(),
outs = [ out ],
cmd = " && ".join([
"mkfs.cpm -f {} -b $(location {}) $@".format(format, bootfile)
] + [
"cpmcp -f {} $@ $(location {}) 0:{}".format(format, map[name], name)
for name in map
] + [
"(cpmcp -f {} $@ /dev/zero 0:padding 2> /dev/null) || true".format(format),
"cpmrm -f {} $@ 0:padding".format(format)
])
)
# vim: sw=4 ts=4 et

View file

@ -1,135 +0,0 @@
definerule("ackfile",
{
srcs = { type="targets" },
deps = { type="targets", default={} },
suffix = { type="string", default=".o" },
},
function (e)
return cfile {
name = e.name,
srcs = e.srcs,
deps = e.deps,
suffix = e.suffix,
commands = {
"ack -mcpm -c -o %{outs} %{ins} %{hdrpaths} %{cpmcflags}"
}
}
end
)
definerule("acklibrary",
{
srcs = { type="targets", default={} },
hdrs = { type="targets", default={} },
deps = { type="targets", default={} },
suffix = { type="string", default=".o" },
},
function (e)
return clibrary {
name = e.name,
srcs = e.srcs,
hdrs = e.hdrs,
deps = e.deps,
suffix = e.suffix,
_cfile = ackfile,
commands = {
"rm -f %{outs[1]}",
"aal qc %{outs[1]} %{ins}"
}
}
end
)
definerule("ackprogram",
{
srcs = { type="targets", default={} },
deps = { type="targets", default={} },
},
function (e)
return cprogram {
name = e.name,
srcs = e.srcs,
deps = e.deps,
_clibrary = acklibrary,
commands = {
"ack -mcpm -.c -o %{outs} %{ins} %{cpmldflags}"
}
}
end
)
definerule("diskimage",
{
diskdefs = { type="targets", default={ "diskdefs" } },
format = { type="string" },
bootfile = { type="targets" },
map = { type="targets", default={} },
deps = { type="targets", default={} },
},
function (e)
local bootfile = filenamesof(e.bootfile)[1]
local deps = { e.deps, e.diskdefs, e.bootfile }
local commands = {}
local outs = {}
for dest, src in pairs(e.map) do
if (type(dest) == "number") then
error("all references must have a destination")
else
local f = filenamesof(src)
if not f[1] then
error("target must return at least one file (only the first of which will be installed)")
end
deps[#deps+1] = {f[1]}
commands[#commands+1] = "cpmcp -f "..e.format.." %{outs} "..f[1].." 0:"..dest
end
end
return normalrule {
name = e.name,
outleaves = { e.name..".img" },
ins = deps,
commands = {
"mkfs.cpm -f "..e.format.." -b "..bootfile.." %{outs}",
commands,
"(cpmcp -f "..e.format.." %{outs} /dev/zero 0:padding 2> /dev/null) || true",
"cpmrm -f "..e.format.." %{outs} 0:padding"
}
}
end
)
definerule("binslice",
{
src = { type="targets" },
start = { type="number" },
length = { type="number", optional=true },
},
function (e)
local f = filenamesof(e.src)
if #f ~= 1 then
error("binslice can only operate on a single file")
end
if e.length == nil then
return normalrule {
name = e.name,
outleaves = { e.name..".img" },
ins = e.src,
commands = {
"tail -c+"..(e.start+1).." %{ins} > %{outs}"
}
}
else
return normalrule {
name = e.name,
outleaves = { e.name..".img" },
ins = e.src,
commands = {
"tail -c+"..(e.start+1).." %{ins} | head -c"..e.length.." > %{outs}"
}
}
end
end
)

View file

@ -1,44 +0,0 @@
definerule("yacc",
{
srcs = { type="targets" },
commands = {
type="strings",
default={
"yacc -t -b %{dir}/y -d %{ins}"
}
},
},
function (e)
return normalrule {
name = e.name,
cwd = e.cwd,
ins = e.srcs,
outleaves = { "y.tab.c", "y.tab.h" },
label = e.label,
commands = e.commands,
}
end
)
definerule("flex",
{
srcs = { type="targets" },
commands = {
type="strings",
default={
"flex -s -t %{ins} > %{outs[1]}"
}
}
},
function (e)
return normalrule {
name = e.name,
cwd = e.cwd,
ins = e.srcs,
outleaves = { "lex.yy.c" },
label = e.label,
commands = e.commands
}
end
)

35
cpmtools/BUILD Normal file
View file

@ -0,0 +1,35 @@
load("//build:ack.bzl", "ack_binary")
load("//cpmtools/libcuss:libcuss.bzl", "libcuss_ack_binary")
package(default_visibility = ["//visibility:public"])
SIMPLE_TOOLS = [
"asm",
"copy",
"dump",
"mkfs",
"rawdisk",
"stat",
"submit"
]
LIBCUSS_TOOLS = [
"qe",
]
[
ack_binary(
name = tool,
srcs = [tool + ".c"]
)
for tool in SIMPLE_TOOLS
]
[
libcuss_ack_binary(
name = tool,
srcs = [tool + ".c"]
)
for tool in LIBCUSS_TOOLS
]

View file

@ -1,41 +0,0 @@
include "cpmtools/libcuss/build.lua"
ackprogram {
name = "dump",
srcs = { "./dump.c" },
}
ackprogram {
name = "stat",
srcs = { "./stat.c" },
}
ackprogram {
name = "asm",
srcs = { "./asm.c" },
}
ackprogram {
name = "copy",
srcs = { "./copy.c" },
}
ackprogram {
name = "submit",
srcs = { "./submit.c" },
}
ackprogram {
name = "mkfs",
srcs = { "./mkfs.c" },
}
ackprogram {
name = "rawdisk",
srcs = { "./rawdisk.c" },
}
libcussprogram {
name = "qe",
srcs = { "./qe.c" },
}

17
cpmtools/libcuss/BUILD Normal file
View file

@ -0,0 +1,17 @@
load("//build:ack.bzl", "ack_library")
load("libcuss.bzl", "libcuss_terminals")
package(default_visibility = ["//visibility:public"])
[
ack_library(
name = "libcuss_" + terminal,
cflags = ["-DLIBCUSS_" + terminal],
srcs = glob(["*.c"]),
hdrs = ["libcuss.h"],
)
for terminal in libcuss_terminals
]
# vim: ts=4 sw=4 et

View file

@ -1,39 +0,0 @@
local libcuss_terminals = {
"KAYPROII",
"NC200",
"BROTHEROP2",
"BROTHER_WP1",
"BROTHER_WP2450DS",
"SPECTRUM_PLUS_THREE",
"SPECTRUM_NEXT",
}
for _, terminal in ipairs(libcuss_terminals) do
acklibrary {
name = "libcuss_"..terminal,
srcs = { "./*.c" },
hdrs = { "./*.h" },
vars = {
["+cpmcflags"] = "-DLIBCUSS_"..terminal
}
}
end
definerule("libcussprogram",
{
srcs = { type="targets", default={} },
deps = { type="targets", default={} },
},
function (e)
for _, terminal in ipairs(libcuss_terminals) do
ackprogram {
name = e.name.."_"..terminal,
srcs = e.srcs,
deps = { e.deps, "cpmtools/libcuss+libcuss_"..terminal },
vars = {
["+cpmcflags"] = "-DLIBCUSS_"..terminal
}
}
end
end
)

View file

@ -0,0 +1,38 @@
load("//build:ack.bzl", "ack_binary")
libcuss_terminals = [
"KAYPROII",
"NC200",
"BROTHEROP2",
"BROTHER_WP1",
"BROTHER_WP2450DS",
"SPECTRUM_PLUS_THREE",
"SPECTRUM_NEXT",
]
def libcuss_ack_binary(**kwargs):
name = kwargs["name"]
kwargs.pop("name")
deps = kwargs.get("deps")
if not deps:
deps = []
else:
kwargs.pop("deps")
cflags = kwargs.get("cflags")
if not cflags:
cflags = []
else:
kwargs.pop("cflags")
for terminal in libcuss_terminals:
ack_binary(
name = name + "_" + terminal,
deps = deps + ["//cpmtools/libcuss:libcuss_" + terminal],
cflags = ["-DLIBCUSS_" + terminal] + cflags,
**kwargs
)
# vim: ts=4 sw=4 et

4
include/BUILD Normal file
View file

@ -0,0 +1,4 @@
package(default_visibility = ["//visibility:public"])
exports_files(glob(["*.lib"]))

View file

@ -143,13 +143,5 @@ otimr macro
dw 0x93ed
endm
tsthl macro
db 0xed, 0x34
endm
tstio macro const
db 0xed, 0x24, const
endm
; vim: ts=4 sw=4 et ft=asm

43
third_party/bbcbasic/BUILD vendored Normal file
View file

@ -0,0 +1,43 @@
load("//third_party/zmac:build.bzl", "zmac")
load("//third_party/ld80:build.bzl", "ld80")
package(default_visibility = ["//visibility:public"])
VERSIONS = [
"ADM3A"
]
[
zmac(
name = f,
srcs = [ f+".z80" ]
)
for f in [
"cmos",
"eval",
"exec",
"fpp",
"main",
"ram",
"sorry"
]
]
[
[
zmac(
name = "boot_" + v,
srcs = [ v.lower() + "/boot.z80" ]
),
ld80(
name = "bbcbasic_" + v,
objs = {
0x0100: [ ":boot_" + v ],
0x0200: [ ":main", ":exec", ":eval", ":fpp", ":sorry", ":cmos" ],
0x3b00: [ ":ram" ]
}
)
]
for v in VERSIONS
]

View file

@ -1,40 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
local VERSIONS = {
"ADM3A",
}
local srcs = {"cmos", "eval", "exec", "fpp", "main", "ram", "sorry"}
local generated = {}
for _, f in pairs(srcs) do
generated[#generated+1] = zmac {
name = f,
srcs = { "./"..f..".z80" }
}
end
for _, version in ipairs(VERSIONS) do
zmac {
name = "boot_"..version,
srcs = { "./"..version:lower().."/boot.z80" }
}
ld80 {
name = "bbcbasic_"..version,
address = 0x100,
srcs = {
"+boot_"..version,
"-P0200",
"+main",
"+exec",
"+eval",
"+fpp",
"+sorry",
"+cmos",
"-P3b00",
"+ram"
}
}
end

10
third_party/camelforth/BUILD vendored Normal file
View file

@ -0,0 +1,10 @@
load("//third_party/zmac:build.bzl", "zmac")
package(default_visibility = ["//visibility:public"])
zmac(
name = "camelforth",
srcs = ["camel80.z80"] + glob(["*.inc"]),
relocatable = False
)

View file

@ -1,12 +0,0 @@
zmac {
name = "camelforth",
srcs = {
"./camel80.z80",
"./camel80.inc",
"./camel80d.inc",
"./camel80h.inc",
"./camel80i.inc",
},
relocatable = false
}

12
third_party/ld80/BUILD vendored Normal file
View file

@ -0,0 +1,12 @@
package(default_visibility = ["//visibility:public"])
cc_binary(
name = "ld80",
srcs = glob(["*.c", "*.h"]),
copts = [
"-Wno-main",
"-Wno-stringop-truncation",
"-Wno-format-overflow",
]
)

26
third_party/ld80/build.bzl vendored Normal file
View file

@ -0,0 +1,26 @@
def ld80(name, address=0x0100, objs={}):
args = []
targets = []
for addr in objs:
args += ["-P$$(printf '%%x' %d)" % addr]
for obj in objs[addr]:
args += ["$(location "+obj+")"]
targets += [obj]
out_file = name + ".cim"
native.genrule(
name = name,
srcs = targets,
outs = [out_file],
tools = ["//third_party/ld80"],
cmd = " && ".join([
"$(location //third_party/ld80) -m -O bin -o $(location "+out_file+").all -s /dev/null "+
(" ".join(args)),
"tail -c+{address} $(location {out_file}).all > $(location {out_file})".format(
address=address+1, out_file=out_file),
"rm $(location {}).all".format(out_file)
])
)
# vim: ts=4 sw=4 et

View file

@ -1,60 +0,0 @@
cprogram {
name = "ld80",
srcs = {
"./main.c",
"./readobj.c",
"./section.c",
"./symbol.c",
"./fixup.c",
"./do_out.c",
"./optget.c"
}
}
definerule("ld80",
{
srcs = { type="table" },
address = { type="number", default=0 },
},
function (e)
local args = {}
local deps = {}
for _, src in ipairs(e.srcs) do
if (type(src) == "string") and src:find("^%-") then
args[#args+1] = src
else
deps[#deps+1] = src
args[#args+1] = filenamesof(src)[1]
end
end
return normalrule {
name = e.name,
outleaves = {
e.name..".cim",
},
ins = {
"third_party/ld80+ld80",
deps,
},
commands = {
"%{ins[1]} -m -O bin -o %{outs[1]}.all -s %{outs[1]}.sym "..table.concat(args, " "),
"tail -c+"..(e.address+1).." %{outs[1]}.all > %{outs[1]}"
}
}
end
)
definerule("bintocom",
{
srcs = { type="table" },
},
function (e)
return binrule {
name = e.name,
src = { e.ins[1] },
start = 0x100
}
end
)

View file

@ -1,285 +0,0 @@
/* Copyright (C) 1993,1995-1997,2002,2005,2007,2008,2009
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include "ld80.h"
#define __set_errno(x)
struct hsearch_data
{
struct _ENTRY *table;
unsigned int size;
unsigned int filled;
};
/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
[Knuth] The Art of Computer Programming, part 3 (6.4) */
/* The reentrant version has no static variables to maintain the state.
Instead the interface of all functions is extended to take an argument
which describes the current status. */
typedef struct _ENTRY
{
unsigned int used;
ENTRY entry;
}
_ENTRY;
/* For the used double hash method the table size has to be a prime. To
correct the user given table size we need a prime test. This trivial
algorithm is adequate because
a) the code is (most probably) called a few times per program run and
b) the number is small because the table must fit in the core */
static int
isprime (unsigned int number)
{
/* no even number will be passed */
unsigned int div = 3;
while (div * div < number && number % div != 0)
div += 2;
return number % div != 0;
}
/* Before using the hash table we must allocate memory for it.
Test for an existing table are done. We allocate one element
more as the found prime number says. This is done for more effective
indexing as explained in the comment for the hsearch function.
The contents of the table is zeroed, especially the field used
becomes zero. */
int
hcreate_r (nel, htab)
size_t nel;
struct hsearch_data *htab;
{
/* Test for correct arguments. */
if (htab == NULL)
{
__set_errno (EINVAL);
return 0;
}
/* There is still another table active. Return with error. */
if (htab->table != NULL)
return 0;
/* We need a size of at least 3. Otherwise the hash functions we
use will not work. */
if (nel < 3)
nel = 3;
/* Change nel to the first prime number not smaller as nel. */
nel |= 1; /* make odd */
while (!isprime (nel))
nel += 2;
htab->size = nel;
htab->filled = 0;
/* allocate memory and zero out */
htab->table = (_ENTRY *) calloc (htab->size + 1, sizeof (_ENTRY));
if (htab->table == NULL)
return 0;
/* everything went alright */
return 1;
}
/* After using the hash table it has to be destroyed. The used memory can
be freed and the local static variable can be marked as not used. */
void
hdestroy_r (htab)
struct hsearch_data *htab;
{
/* Test for correct arguments. */
if (htab == NULL)
{
__set_errno (EINVAL);
return;
}
/* Free used memory. */
free (htab->table);
/* the sign for an existing table is an value != NULL in htable */
htab->table = NULL;
}
/* This is the search function. It uses double hashing with open addressing.
The argument item.key has to be a pointer to an zero terminated, most
probably strings of chars. The function for generating a number of the
strings is simple but fast. It can be replaced by a more complex function
like ajw (see [Aho,Sethi,Ullman]) if the needs are shown.
We use an trick to speed up the lookup. The table is created by hcreate
with one more element available. This enables us to use the index zero
special. This index will never be used because we store the first hash
index in the field used where zero means not used. Every other value
means used. The used field can be used as a first fast comparison for
equality of the stored and the parameter value. This helps to prevent
unnecessary expensive calls of strcmp. */
int
hsearch_r (item, action, retval, htab)
ENTRY item;
ACTION action;
ENTRY **retval;
struct hsearch_data *htab;
{
unsigned int hval, hval2, first_idx;
unsigned int count;
unsigned int len = strlen (item.key);
unsigned int idx;
/* Compute an value for the given string. Perhaps use a better method. */
hval = len;
count = len;
while (count-- > 0)
{
hval <<= 4;
hval += item.key[count];
}
if (hval == 0)
++hval;
/* First hash function: simply take the modul but prevent zero. */
idx = hval % htab->size + 1;
if (htab->table[idx].used)
{
/* Further action might be required according to the action value. */
if (htab->table[idx].used == hval
&& strcmp (item.key, htab->table[idx].entry.key) == 0)
{
*retval = &htab->table[idx].entry;
return 1;
}
/* Second hash function, as suggested in [Knuth] */
hval2 = 1 + hval % (htab->size - 2);
first_idx = idx;
do
{
/* Because SIZE is prime this guarantees to step through all
available indeces. */
if (idx <= hval2)
idx = htab->size + idx - hval2;
else
idx -= hval2;
/* If we visited all entries leave the loop unsuccessfully. */
if (idx == first_idx)
break;
/* If entry is found use it. */
if (htab->table[idx].used == hval
&& strcmp (item.key, htab->table[idx].entry.key) == 0)
{
*retval = &htab->table[idx].entry;
return 1;
}
}
while (htab->table[idx].used);
}
/* An empty bucket has been found. */
if (action == ENTER)
{
/* If table is full and another entry should be entered return
with error. */
if (htab->filled == htab->size)
{
__set_errno (ENOMEM);
*retval = NULL;
return 0;
}
htab->table[idx].used = hval;
htab->table[idx].entry = item;
++htab->filled;
*retval = &htab->table[idx].entry;
return 1;
}
__set_errno (ESRCH);
*retval = NULL;
return 0;
}
/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* The non-reentrant version use a global space for storing the table. */
static struct hsearch_data htab;
/* Define the non-reentrant function using the reentrant counterparts. */
ENTRY *
hsearch (item, action)
ENTRY item;
ACTION action;
{
ENTRY *result;
(void) hsearch_r (item, action, &result, &htab);
return result;
}
int
hcreate (nel)
size_t nel;
{
return hcreate_r (nel, &htab);
}
void
hdestroy()
{
hdestroy_r(&htab);
}

View file

@ -1,4 +0,0 @@
clibrary {
name = "libstb",
hdrs = { "./*.h" }
}

View file

@ -1,24 +0,0 @@
clibrary {
name = "libz80ex",
srcs = {
"./z80ex.c",
"./z80ex_dasm.c",
},
deps = {
"./include/z80ex.h",
"./include/z80ex_dasm.h",
},
hdrs = { "./include/*.h" },
vars = {
["+cflags"] = {
"-DENDIANNESS=WORDS_LITTLE_ENDIAN",
"-DZ80EX_API_REVISION=1",
"-DZ80EX_VERSION_MAJOR=1",
"-DZ80EX_VERSION_MINOR=21",
"-DZ80EX_RELEASE_TYPE=cpmish",
"-DZ80EX_VERSION_STR=1.1.21-cpmish",
"-Ithird_party/libz80ex/include",
},
}
}

9
third_party/startrek/BUILD vendored Normal file
View file

@ -0,0 +1,9 @@
load("//build:ack.bzl", "ack_binary")
package(default_visibility = ["//visibility:public"])
ack_binary(
name = "startrek",
srcs = ["startrek.c"]
)

62
third_party/ted/BUILD vendored Normal file
View file

@ -0,0 +1,62 @@
load("//third_party/zmac:build.bzl", "zmac")
load("//third_party/ld80:build.bzl", "ld80")
package(default_visibility = ["//visibility:public"])
VERSIONS = [
"NC200",
"WP2450DS",
]
[
zmac(
name = f,
srcs = [
f + ".mac",
"ted.inc",
]
)
for f in [
"cpmio",
"main",
"fileio",
"cmds",
]
]
[
[
zmac(
name = "termdef_" + v,
srcs = [
"termdef.mac",
v.lower() + "/config.inc",
"ted.inc",
]
),
zmac(
name = "scrn_" + v,
srcs = [
"scrn.mac",
v.lower() + "/config.inc",
"ted.inc",
]
),
ld80(
name = "ted_" + v,
address = 0x0100,
objs = {
0x0100: [
":main",
":termdef_" + v,
":fileio",
":scrn_" + v,
":cmds",
":cpmio"
]
}
)
]
for v in VERSIONS
]

View file

@ -1,52 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
local PLATFORMS = {
"NC200",
"WP2450DS",
}
-- These files are the same for all platforms.
for _, f in ipairs({ "cpmio", "main", "fileio", "cmds" }) do
zmac {
name = f,
srcs = { "./"..f..".mac" }
}
end
local srcs = {
"cpmio",
"main",
"termdef",
"fileio",
"scrn",
"cmds"
}
for _, platform in ipairs(PLATFORMS) do
-- These need to be compiled individually per platform.
--
for _, f in ipairs({ "termdef", "scrn" }) do
zmac {
name = f.."_"..platform,
srcs = { "./"..f..".mac" },
deps = { "./"..platform:lower().."/config.inc" }
}
end
ld80 {
name = "ted_"..platform,
address = 0x100,
srcs = {
"-P0100",
"+main",
"+termdef_"..platform,
"+fileio",
"+scrn_"..platform,
"+cmds",
"+cpmio"
}
}
end

25
third_party/z8e/BUILD vendored Normal file
View file

@ -0,0 +1,25 @@
load("//build:cpm.bzl", "binslice", "cpm_addresses", "diskimage")
load("//third_party/zmac:build.bzl", "zmac")
load("//third_party/ld80:build.bzl", "ld80")
load("//utils:build.bzl", "objectify", "unix2cpm")
package(default_visibility = ["//visibility:public"])
VERSIONS = [
"NC200",
"WP2450DS",
]
[
zmac(
name = "z8e_" + version,
srcs = [
"src/z8e.z80",
"src/terminal.inc",
version.lower() + "/config.inc",
] + glob(["src/*.tty"]),
relocatable = False
)
for version in VERSIONS
]

View file

@ -1,22 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
local VERSIONS = {
"NC200",
"WP2450DS",
}
for _, version in ipairs(VERSIONS) do
zmac {
name = "z8e_"..version,
srcs = { "./src/z8e.z80" },
deps = {
"./"..version:lower().."/config.inc",
"./src/terminal.inc",
"./src/*.tty",
},
relocatable = false
}
end

12
third_party/zcpr1/BUILD vendored Normal file
View file

@ -0,0 +1,12 @@
load("//third_party/zmac:build.bzl", "zmac")
package(default_visibility = ["//visibility:public"])
zmac(
name = "zcpr1",
srcs = [
"zcpr.asm"
]
)

View file

@ -1,6 +0,0 @@
include("third_party/zmac/build.lua")
zmac {
name = "zcpr",
srcs = { "./zcpr.asm" }
}

43
third_party/zmac/BUILD vendored Normal file
View file

@ -0,0 +1,43 @@
load("//build:build.bzl", "bison")
package(default_visibility = ["//visibility:public"])
bison(
name = "parser",
src = "zmac.y"
)
cc_binary(
name = "doc",
srcs = ["doc.c"],
defines = ["DOC_DEBUG", "doc=main"],
copts = ["-Wno-main"],
)
genrule(
name = "doc_inl",
tools = [":doc"],
outs = ["doc.inl"],
srcs = ["doc.txt"],
cmd = "EXE=$$PWD/$(execpath :doc) && cp $(execpath doc.txt) $(RULEDIR) && (cd $(@D) && $$EXE) >/dev/null && rm $(RULEDIR)/doc.txt",
)
cc_binary(
name = "zmac",
copts = [
"-Wno-unused-result"
],
srcs = [
":doc.inl",
":parser.c",
":parser.h",
"doc.c",
"mio.c",
"mio.h",
"zi80dis.cpp",
"zi80dis.h",
],
includes = [
":doc.inl/.."
],
)

26
third_party/zmac/build.bzl vendored Normal file
View file

@ -0,0 +1,26 @@
def zmac(name, srcs, relocatable=True):
srcfiles = [f for f in srcs if f.endswith(".z80") or f.endswith(".asm") or f.endswith(".mac")]
if len(srcfiles) != 1:
fail("you may only have one .z80 or .asm file")
depfiles = [f for f in srcs if f not in srcfiles]
ext = ".rel" if relocatable else ".cim"
relflag = "--rel7" if relocatable else ""
archflag = "-z" if srcfiles[0].endswith(".z80") else "-8"
outfile = name + ext
hdrflags = ""
for f in depfiles:
hdrflags += "-I$$(dirname $(location {})) ".format(f)
native.genrule(
name = name,
srcs = srcfiles + depfiles,
outs = [outfile],
tools = ["//third_party/zmac"],
cmd = "$(execpath //third_party/zmac) --zmac -m {} {} {} -o $(execpath {}) $(execpath {})".format(
relflag, archflag, hdrflags, outfile, srcfiles[0])
)
# vim: ts=4 sw=4 et

View file

@ -1,76 +0,0 @@
include("build/yacc.lua")
yacc {
name = "zmacparser",
srcs = { "./zmac.y" }
}
cprogram {
name = "doc",
srcs = { "./doc.c" },
vars = {
["+cflags"] = { "-DDOC_DEBUG", "-Ddoc=main" }
}
}
normalrule {
name = "doc_inl",
ins = {
"+doc",
"./doc.txt"
},
outleaves = { "doc.inl" },
commands = { "cd %{dirname(ins[2])} && (%{abspath(ins[1])} > /dev/null) && mv doc.inl %{outs}" }
}
cprogram {
name = "zmac",
srcs = {
"./mio.c",
"./zi80dis.cpp",
"./doc.c",
matching(filenamesof("+zmacparser"), "%.c$"),
},
deps = {
"./zi80dis.h",
"+zmacparser",
"+doc_inl",
}
}
definerule("zmac",
{
srcs = { type="targets" },
deps = { type="targets", default={} },
relocatable = { type="boolean", default=true },
},
function (e)
local firstfilename = filenamesof(e.srcs)[1]
local _, _, ext = firstfilename:find("%.(%w+)$")
local archflag = (ext == "z80") and "-z" or "-8"
local relflag = e.relocatable and "--rel7" or ""
local ext = e.relocatable and ".rel" or ".cim"
local hdrpaths = {}
for _, t in pairs(uniquify(dirname(filenamesof(e.deps)))) do
hdrpaths[#hdrpaths+1] = "-I"..t
end
return normalrule {
name = e.name,
ins = {
"third_party/zmac+zmac",
e.srcs
},
outleaves = { e.name..ext, e.name..".lst" },
deps = e.deps,
commands = {
"%{ins[1]} --zmac -m "..relflag.." "..archflag.." -o %{outs[1]} -o %{outs[2]} %{hdrpaths} %{ins[2]}"
},
vars = {
hdrpaths = hdrpaths,
}
}
end
)

12
third_party/zsdos/BUILD vendored Normal file
View file

@ -0,0 +1,12 @@
load("//third_party/zmac:build.bzl", "zmac")
package(default_visibility = ["//visibility:public"])
zmac(
name = "zsdos",
srcs = [
"zsdos-gp.z80",
"zsdos.lib"
]
)

View file

@ -1,6 +0,0 @@
include("third_party/zmac/build.lua")
zmac {
name = "zsdos",
srcs = { "./zsdos-gp.z80" }
}

29
utils/BUILD Normal file
View file

@ -0,0 +1,29 @@
package(default_visibility = ["//visibility:public"])
exports_files([ "6x7font.bdf" ])
cc_binary(
name = "objectify",
srcs = [ "objectify.c" ]
)
cc_binary(
name = "objectifyc",
srcs = [ "objectifyc.c" ]
)
cc_binary(
name = "unix2cpm",
srcs = [ "unix2cpm.c" ]
)
cc_library(
name = "libbdf",
hdrs = [ "libbdf.h" ],
srcs = [ "libbdf.c" ],
strip_include_prefix = ".",
copts = [
"-Wno-unused-label"
]
)

20
utils/build.bzl Normal file
View file

@ -0,0 +1,20 @@
def unix2cpm(name, src):
native.genrule(
name = name,
srcs = [ src ],
outs = [ name + ".txt" ],
tools = [ "//utils:unix2cpm" ],
cmd = "$(location //utils:unix2cpm) $< > $@"
)
def objectify(name, src):
native.genrule(
name = name,
srcs = [ src ],
outs = [ name + ".inc" ],
tools = [ "//utils:objectify" ],
cmd = "$(location //utils:objectify) $< > $@"
)
# vim: ts=4 sw=4 et

View file

@ -1,78 +0,0 @@
cprogram {
name = "objectify",
srcs = { "./objectify.c" }
}
definerule("objectify",
{
srcs = { type="targets" },
},
function (e)
return normalrule {
name = e.name,
ins = {
"utils+objectify",
e.srcs,
},
outleaves = { e.name..".inc" },
commands = {
"%{ins[1]} < %{ins[2]} > %{outs}"
}
}
end
)
cprogram {
name = "objectifyc",
srcs = { "./objectifyc.c" }
}
definerule("objectifyc",
{
srcs = { type="targets" },
},
function (e)
return normalrule {
name = e.name,
ins = {
"utils+objectifyc",
e.srcs,
},
outleaves = { e.name..".h" },
commands = {
"%{ins[1]} < %{ins[2]} > %{outs}"
}
}
end
)
cprogram {
name = "unix2cpm",
srcs = { "./unix2cpm.c" }
}
definerule("unix2cpm",
{
srcs = { type="targets" },
},
function (e)
return normalrule {
name = e.name,
ins = {
"utils+unix2cpm",
e.srcs,
},
outleaves = { e.name..".txt" },
commands = {
"%{ins[1]} < %{ins[2]} > %{outs}"
}
}
end
)
clibrary {
name = "libbdf",
srcs = { "./libbdf.c" },
hdrs = { "./libbdf.h" }
}

View file

@ -1,39 +0,0 @@
include "third_party/ld80/build.lua"
include "third_party/zmac/build.lua"
include "utils/build.lua"
zmac {
name = "biosbdos_rel",
srcs = { "./biosbdos.z80" }
}
ld80 {
name = "biosbdos_memimg",
srcs = {
"-Pf700", "third_party/zcpr1+zcpr",
"-Pff00", "+biosbdos_rel"
}
}
binslice {
name = "biosbdos_cim",
src = "+biosbdos_memimg",
start = 0xf700
}
objectifyc {
name = "biosbdos_cim_h",
srcs = { "+biosbdos_cim" }
}
cprogram {
name = "emu",
srcs = { "./*.c" },
deps = {
"+biosbdos_cim_h",
"third_party/libz80ex+libz80ex"
},
vars = {
["+ldflags"] = { "-lreadline" }
}
}

View file

@ -1,20 +0,0 @@
OUTPUT_FORMAT(binary)
SECTIONS {
ram : {
. = 0x0000;
*(.text);
. = 0xe800;
CBASE = .;
*(CCP);
. = 0xf000;
FBASE = .;
*(BDOS);
. = 0xfe00;
BBASE = .;
*(BIOS);
}
}

View file

@ -1,20 +0,0 @@
OUTPUT_FORMAT(binary)
MEMORY {
supervisor : ORIGIN = 0x0000, LENGTH = 8K
splashscreen : ORIGIN = 0x2000, LENGTH = 1K
autoprg : ORIGIN = 0x4000, LENGTH = 512
bios : ORIGIN = 0xfe00, LENGTH = 0x0200
bdos : ORIGIN = 0xf000, LENGTH = 0x0e00
ccp : ORIGIN = 0xe800, LENGTH = 0x0800
}
SECTIONS {
autoprg : { *(AUTOPRG) } >autoprg
splashscreen : { *(SPLASH) } >splashscreen
ccp : { *(CCP) } >ccp
bdos : { *(BDOS) } >bdos
bios : { *(BIOS) } >bios
supervisor : { *(.text) } >supervisor
}