mirror of https://github.com/wwarthen/RomWBW.git
Browse Source
- Credit and thanks to Ladislau Szilagyi. Co-Authored-By: ladislau szilagyi <87603175+laci1953@users.noreply.github.com>pull/393/head v3.5.0-dev.11
46 changed files with 1451 additions and 8 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,45 @@ |
|||||
|
===== Cowgol 2.0 for CP/M ===== |
||||
|
|
||||
|
This disk contains the Cowgol 2.0 compiler and related tools. |
||||
|
These files were provided by Ladislau Szilagyi and were sourced |
||||
|
from his GitHub repository at https://github.com/Laci1953/Cowgol_on_CP_M. |
||||
|
|
||||
|
The COWFE program included here is the RomWBW-specific version that |
||||
|
is tailored to RomWBW memory management. |
||||
|
|
||||
|
The primary distribution site for Cowgol 2.0 is at |
||||
|
https://github.com/davidgiven/cowgol. |
||||
|
|
||||
|
The Hi-Tech C compiler components were sourced from the updated |
||||
|
version by Tony Nicholson at https://github.com/agn453/HI-TECH-Z80-C. |
||||
|
However, the CPP.COM component was sourced from Ladislau Szilagyi's |
||||
|
enhanced Hi-Tech C at https://github.com/Laci1953/HiTech-C-compiler-enhanced. |
||||
|
|
||||
|
Note that only the minimum required Hi-Tech C compiler components |
||||
|
are provided. Additional components from Hi-Tech C may be required |
||||
|
depending on your needs. |
||||
|
|
||||
|
There are two example Cowgol applications included: |
||||
|
|
||||
|
- HEXDUMP is a simple hex dump utility and is purely a Cowgol |
||||
|
application (no assembler or C components). The command |
||||
|
line to build the application is: |
||||
|
|
||||
|
COWGOL HEXDUMP.COW |
||||
|
|
||||
|
- DYNMSORT demonstrates a sort algorithm and is composed of |
||||
|
Cowgol, C, and assembler components. The command line to |
||||
|
build the application is: |
||||
|
|
||||
|
COWGOL -LC DYNMSORT.COW MERGES.C RAND.AS |
||||
|
|
||||
|
There are also SUBMIT files provided to build the example |
||||
|
applications which can be used as follows: |
||||
|
|
||||
|
SUBMIT HEXDUMP |
||||
|
SUBMIT DYNMSORT |
||||
|
|
||||
|
-- WBW 12:38 PM 2/10/2024 |
||||
|
|
||||
|
|
||||
|
|
||||
Binary file not shown.
@ -0,0 +1,48 @@ |
|||||
|
var argv_pointer: [uint8]; |
||||
|
|
||||
|
sub ArgvInit() is |
||||
|
argv_pointer := 0x81 as [uint8]; |
||||
|
[argv_pointer + [0x80 as [uint8]] as intptr] := 0; |
||||
|
end sub; |
||||
|
|
||||
|
# Returns null is there's no next argument. |
||||
|
sub ArgvNext(): (arg: [uint8]) is |
||||
|
# No more arguments? |
||||
|
|
||||
|
if argv_pointer == (0 as [uint8]) then |
||||
|
arg := argv_pointer; |
||||
|
return; |
||||
|
end if; |
||||
|
|
||||
|
# Skip leading whitespace. |
||||
|
|
||||
|
var c: uint8; |
||||
|
loop |
||||
|
c := [argv_pointer]; |
||||
|
if c != ' ' then |
||||
|
break; |
||||
|
end if; |
||||
|
argv_pointer := argv_pointer + 1; |
||||
|
end loop; |
||||
|
|
||||
|
arg := argv_pointer; |
||||
|
|
||||
|
# Skip to end of word and terminate. |
||||
|
|
||||
|
loop |
||||
|
c := [argv_pointer]; |
||||
|
if (c == ' ') or (c == '\n') or (c == 0) then |
||||
|
break; |
||||
|
end if; |
||||
|
argv_pointer := argv_pointer + 1; |
||||
|
end loop; |
||||
|
[argv_pointer] := 0; |
||||
|
|
||||
|
if c == ' ' then |
||||
|
argv_pointer := argv_pointer + 1; |
||||
|
else |
||||
|
argv_pointer := 0 as [uint8]; |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
|
||||
Binary file not shown.
@ -0,0 +1,27 @@ |
|||||
|
sub FCBPutString(fcb: [FCB], s: [uint8]) is |
||||
|
loop |
||||
|
var c := [s]; |
||||
|
if c == 0 then |
||||
|
break; |
||||
|
end if; |
||||
|
FCBPutChar(fcb, c); |
||||
|
s := @next s; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBGetBlock(fcb: [FCB], buffer: [uint8], length: intptr) is |
||||
|
while length != 0 loop; |
||||
|
[buffer] := FCBGetChar(fcb); |
||||
|
buffer := buffer + 1; |
||||
|
length := length - 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBPutBlock(fcb: [FCB], buffer: [uint8], length: intptr) is |
||||
|
while length != 0 loop; |
||||
|
FCBPutChar(fcb, [buffer]); |
||||
|
buffer := buffer + 1; |
||||
|
length := length - 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
@ -0,0 +1,150 @@ |
|||||
|
sub print(ptr: [uint8]) is |
||||
|
loop |
||||
|
var c := [ptr]; |
||||
|
if c == 0 then |
||||
|
return; |
||||
|
end if; |
||||
|
print_char(c); |
||||
|
ptr := ptr + 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub print_nl() is |
||||
|
print_char('\n'); |
||||
|
end sub; |
||||
|
|
||||
|
sub UIToA(value: uint32, base: uint8, buffer: [uint8]): (ptr: [uint8]) is |
||||
|
ptr := buffer; |
||||
|
loop |
||||
|
var rem := value % (base as uint32); |
||||
|
value := value / (base as uint32); |
||||
|
if rem < 10 then |
||||
|
rem := rem + '0'; |
||||
|
else |
||||
|
rem := rem + ('a' - 10); |
||||
|
end if; |
||||
|
[ptr] := rem as uint8; |
||||
|
ptr := @next ptr; |
||||
|
|
||||
|
if value == 0 then |
||||
|
break; |
||||
|
end if; |
||||
|
end loop; |
||||
|
|
||||
|
var s1 := buffer; |
||||
|
var s2 := @prev ptr; |
||||
|
while s2 > s1 loop |
||||
|
var c := [s1]; |
||||
|
[s1] := [s2]; |
||||
|
[s2] := c; |
||||
|
s1 := @next s1; |
||||
|
s2 := @prev s2; |
||||
|
end loop; |
||||
|
|
||||
|
[ptr] := 0; |
||||
|
end sub; |
||||
|
|
||||
|
sub IToA(value: int32, base: uint8, buffer: [uint8]): (ptr: [uint8]) is |
||||
|
if value < 0 then |
||||
|
[buffer] := '-'; |
||||
|
buffer := @next buffer; |
||||
|
value := -value; |
||||
|
end if; |
||||
|
ptr := UIToA(value as uint32, base, buffer); |
||||
|
end sub; |
||||
|
|
||||
|
sub print_i32(value: uint32) is |
||||
|
var buffer: uint8[12]; |
||||
|
var pe := UIToA(value, 10, &buffer[0]); |
||||
|
print(&buffer[0]); |
||||
|
end sub; |
||||
|
|
||||
|
sub print_i16(value: uint16) is |
||||
|
print_i32(value as uint32); |
||||
|
end sub; |
||||
|
|
||||
|
sub print_i8(value: uint8) is |
||||
|
print_i32(value as uint32); |
||||
|
end sub; |
||||
|
|
||||
|
sub print_hex_i8(value: uint8) is |
||||
|
var i: uint8 := 2; |
||||
|
loop |
||||
|
var digit := value >> 4; |
||||
|
if digit < 10 then |
||||
|
digit := digit + '0'; |
||||
|
else |
||||
|
digit := digit + ('a' - 10); |
||||
|
end if; |
||||
|
print_char(digit); |
||||
|
value := value << 4; |
||||
|
i := i - 1; |
||||
|
if i == 0 then |
||||
|
break; |
||||
|
end if; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub print_hex_i16(value: uint16) is |
||||
|
print_hex_i8((value >> 8) as uint8); |
||||
|
print_hex_i8(value as uint8); |
||||
|
end sub; |
||||
|
|
||||
|
sub print_hex_i32(value: uint32) is |
||||
|
print_hex_i8((value >> 24) as uint8); |
||||
|
print_hex_i8((value >> 16) as uint8); |
||||
|
print_hex_i8((value >> 8) as uint8); |
||||
|
print_hex_i8(value as uint8); |
||||
|
end sub; |
||||
|
|
||||
|
sub AToI(buffer: [uint8]): (result: int32, ptr: [uint8]) is |
||||
|
var negative: uint8 := 0; |
||||
|
var base: uint8 := 10; |
||||
|
ptr := buffer; |
||||
|
result := 0; |
||||
|
|
||||
|
var c := [ptr]; |
||||
|
if (c == '-') then |
||||
|
negative := 1; |
||||
|
ptr := ptr + 1; |
||||
|
c := [ptr]; |
||||
|
end if; |
||||
|
if (c == '0') then |
||||
|
case [ptr+1] is |
||||
|
when 'x': base := 16; |
||||
|
when 'o': base := 8; |
||||
|
when 'b': base := 2; |
||||
|
when 'd': base := 10; |
||||
|
|
||||
|
when else: ptr := ptr - 2; |
||||
|
end case; |
||||
|
ptr := ptr + 2; |
||||
|
c := [ptr]; |
||||
|
end if; |
||||
|
|
||||
|
loop |
||||
|
if c >= 'a' then |
||||
|
c := c - 'a' + 10; |
||||
|
elseif c >= 'A' then |
||||
|
c := c - 'A' + 10; |
||||
|
else |
||||
|
c := c - '0'; |
||||
|
end if; |
||||
|
if c >= (base as uint8) then |
||||
|
break; |
||||
|
end if; |
||||
|
result := (result * base as int32) + (c as int32); |
||||
|
|
||||
|
ptr := ptr + 1; |
||||
|
c := [ptr]; |
||||
|
end loop; |
||||
|
|
||||
|
if negative != 0 then |
||||
|
result := -result; |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub MemZero(ptr: [uint8], size: intptr) is |
||||
|
MemSet(ptr, 0, size); |
||||
|
end sub; |
||||
|
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,52 @@ |
|||||
|
var LOMEM: [uint8]; |
||||
|
@asm "ld hl, LOMEM"; |
||||
|
@asm "ld (", LOMEM, "), hl"; |
||||
|
|
||||
|
var HIMEM: [uint8]; |
||||
|
@asm "ld hl, (6)"; |
||||
|
@asm "ld (", HIMEM, "), hl"; |
||||
|
|
||||
|
sub Exit() is |
||||
|
@asm "rst 0"; |
||||
|
end sub; |
||||
|
|
||||
|
sub ExitWithError() is |
||||
|
@asm "rst 0"; |
||||
|
end sub; |
||||
|
|
||||
|
sub AlignUp(in: intptr): (out: intptr) is |
||||
|
out := in; |
||||
|
end sub; |
||||
|
|
||||
|
sub get_char(): (c: uint8) is |
||||
|
@asm "ld c, 1"; |
||||
|
@asm "call 5"; |
||||
|
@asm "ld (", c, "), a"; |
||||
|
end sub; |
||||
|
|
||||
|
sub print_char(c: uint8) is |
||||
|
if c == 10 then |
||||
|
@asm "ld e, 13"; |
||||
|
@asm "ld c, 2"; |
||||
|
@asm "call 5"; |
||||
|
end if; |
||||
|
@asm "ld a, (", c, ")"; |
||||
|
@asm "ld e, a"; |
||||
|
@asm "ld c, 2"; |
||||
|
@asm "call 5"; |
||||
|
end sub; |
||||
|
|
||||
|
sub MemSet(buf: [uint8], byte: uint8, len: uint16) is |
||||
|
var bufend := buf + len; |
||||
|
loop |
||||
|
if buf == bufend then |
||||
|
return; |
||||
|
end if; |
||||
|
[buf] := byte; |
||||
|
buf := buf + 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
include "common.coh"; |
||||
|
|
||||
|
|
||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,52 @@ |
|||||
|
var LOMEM: [uint8]; |
||||
|
@asm "ld hl, __Hbss"; |
||||
|
@asm "ld (", LOMEM, "), hl"; |
||||
|
|
||||
|
var HIMEM: [uint8]; |
||||
|
@asm "ld hl, (6)"; |
||||
|
@asm "ld (", HIMEM, "), hl"; |
||||
|
|
||||
|
sub Exit() is |
||||
|
@asm "rst 0"; |
||||
|
end sub; |
||||
|
|
||||
|
sub ExitWithError() is |
||||
|
@asm "rst 0"; |
||||
|
end sub; |
||||
|
|
||||
|
sub AlignUp(in: intptr): (out: intptr) is |
||||
|
out := in; |
||||
|
end sub; |
||||
|
|
||||
|
sub get_char(): (c: uint8) is |
||||
|
@asm "ld c, 1"; |
||||
|
@asm "call 5"; |
||||
|
@asm "ld (", c, "), a"; |
||||
|
end sub; |
||||
|
|
||||
|
sub print_char(c: uint8) is |
||||
|
if c == 10 then |
||||
|
@asm "ld e, 13"; |
||||
|
@asm "ld c, 2"; |
||||
|
@asm "call 5"; |
||||
|
end if; |
||||
|
@asm "ld a, (", c, ")"; |
||||
|
@asm "ld e, a"; |
||||
|
@asm "ld c, 2"; |
||||
|
@asm "call 5"; |
||||
|
end sub; |
||||
|
|
||||
|
sub MemSet(buf: [uint8], byte: uint8, len: uint16) is |
||||
|
var bufend := buf + len; |
||||
|
loop |
||||
|
if buf == bufend then |
||||
|
return; |
||||
|
end if; |
||||
|
[buf] := byte; |
||||
|
buf := buf + 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
include "common.coh"; |
||||
|
|
||||
|
|
||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,78 @@ |
|||||
|
################################ |
||||
|
# Cowgol program # |
||||
|
# # |
||||
|
# Sorting 1000 random integers # |
||||
|
# stored in a vector allocated # |
||||
|
# using Cowgol's Alloc # |
||||
|
# # |
||||
|
# calls: # |
||||
|
# assembler routine xrndseed # |
||||
|
# assembler routine xrnd # |
||||
|
# C routine mergeSort # |
||||
|
# # |
||||
|
# Ladislau Szilagyi, Nov. 2023 # |
||||
|
################################ |
||||
|
|
||||
|
include "cowgolc.coh"; |
||||
|
include "strings.coh"; |
||||
|
include "malloc.coh"; |
||||
|
|
||||
|
typedef intstring is [uint16]; |
||||
|
|
||||
|
var Unsorted: intstring; |
||||
|
var size: uint16 := 999; |
||||
|
|
||||
|
sub random(): (n: uint16) is |
||||
|
@asm "call _xrnd"; #calls assembler routine |
||||
|
@asm "ld (", n, "),hl"; |
||||
|
end sub; |
||||
|
|
||||
|
sub PrintArray(array: intstring) is |
||||
|
var i: uint16 := 0; |
||||
|
var p := array; |
||||
|
print("\r\nArray:\r\n"); |
||||
|
while i != 1000 loop |
||||
|
print_i16([p]); |
||||
|
print(","); |
||||
|
p := p + 2; |
||||
|
i := i + 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub PopulateArray(array: intstring) is |
||||
|
var i: uint16 := 0; |
||||
|
var p := array; |
||||
|
while i != 1000 loop |
||||
|
[p] := random(); |
||||
|
p := p + 2; |
||||
|
i := i + 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub RandSeed() is |
||||
|
@asm "call _xrndseed"; #calls assembler routine |
||||
|
end sub; |
||||
|
|
||||
|
sub MergeSort() is |
||||
|
print("\r\nSorting...\r\n"); |
||||
|
@asm "ld hl,(", size, ")"; |
||||
|
@asm "push hl"; # r on stack as param # 3 |
||||
|
@asm "ld hl,0"; |
||||
|
@asm "push hl"; # l on stack as param # 2 |
||||
|
@asm "ld hl,(", Unsorted, ")"; |
||||
|
@asm "push hl"; # vector addr on stack as param # 1 |
||||
|
@asm "call _mergeSort"; # calls C routine msort(int* array, int l, int r) |
||||
|
@asm "pop bc"; # drops C routine params |
||||
|
@asm "pop bc"; # drops C routine params |
||||
|
@asm "pop bc"; # drops C routine params |
||||
|
end sub; |
||||
|
|
||||
|
### start ### |
||||
|
|
||||
|
RandSeed(); |
||||
|
Unsorted := Alloc(2000) as intstring; |
||||
|
PopulateArray(Unsorted); |
||||
|
PrintArray(Unsorted); |
||||
|
MergeSort(); |
||||
|
PrintArray(Unsorted); # now is sorted ! |
||||
|
Exit(); |
||||
@ -0,0 +1,2 @@ |
|||||
|
COWGOL -LC DYNMSORT.COW MERGES.C RAND.AS |
||||
|
|
||||
@ -0,0 +1,200 @@ |
|||||
|
# vim: ts=4 sw=4 et |
||||
|
|
||||
|
record CpmFCB is |
||||
|
dr: uint8; |
||||
|
f: uint8[11]; |
||||
|
ex: uint8; |
||||
|
s1: uint8; |
||||
|
s2: uint8; |
||||
|
rc: uint8; |
||||
|
d: uint8[16]; |
||||
|
cr: uint8; |
||||
|
r: uint16; |
||||
|
r2: uint8; |
||||
|
end record; |
||||
|
|
||||
|
record FCB is |
||||
|
bufferptr: uint8; # byte just read |
||||
|
dirty: uint8; |
||||
|
cpm: CpmFCB; |
||||
|
buffer: uint8[128]; |
||||
|
end record; |
||||
|
|
||||
|
sub file_i_init(fcb: [FCB], filename: [uint8]) is |
||||
|
sub fill(dest: [uint8], src: [uint8], len: uint8): (srcout: [uint8]) is |
||||
|
loop |
||||
|
var c := [src]; |
||||
|
if (c < 32) or (c == '.') then |
||||
|
c := ' '; |
||||
|
elseif (c == '*') then |
||||
|
c := '?'; |
||||
|
else |
||||
|
src := src + 1; |
||||
|
end if; |
||||
|
if (c >= 'a') and (c <= 'z') then |
||||
|
c := c - ('a' - 'A'); |
||||
|
end if; |
||||
|
[dest] := c; |
||||
|
dest := dest + 1; |
||||
|
|
||||
|
len := len - 1; |
||||
|
if len == 0 then |
||||
|
break; |
||||
|
end if; |
||||
|
end loop; |
||||
|
srcout := src; |
||||
|
end sub; |
||||
|
|
||||
|
MemSet(fcb as [uint8], 0, @bytesof FCB); |
||||
|
MemSet(&fcb.cpm.f[0] as [uint8], ' ', 11); |
||||
|
filename := fill(&fcb.cpm.f[0], filename, 8); |
||||
|
|
||||
|
var c: uint8; |
||||
|
loop |
||||
|
c := [filename]; |
||||
|
if (c < 32) or (c == '.') then |
||||
|
break; |
||||
|
end if; |
||||
|
filename := filename + 1; |
||||
|
end loop; |
||||
|
|
||||
|
if c == '.' then |
||||
|
filename := fill(&fcb.cpm.f[8], filename+1, 3); |
||||
|
end if; |
||||
|
|
||||
|
fcb.cpm.r := 0xffff; |
||||
|
fcb.bufferptr := 127; |
||||
|
end sub; |
||||
|
|
||||
|
sub fcb_i_gbpb(fcb: [FCB], c: uint8) is |
||||
|
var cpmfcb := &fcb.cpm; |
||||
|
var dma := &fcb.buffer[0]; |
||||
|
|
||||
|
@asm "ld c, 26"; # SET DMA |
||||
|
@asm "ld de, (", dma, ")"; |
||||
|
@asm "call 5"; |
||||
|
|
||||
|
@asm "ld a, (", c, ")"; |
||||
|
@asm "ld c, a"; |
||||
|
@asm "ld de, (", cpmfcb, ")"; |
||||
|
@asm "call 5"; |
||||
|
end sub; |
||||
|
|
||||
|
sub fcb_i_blockin(fcb: [FCB]) is |
||||
|
MemSet(&fcb.buffer[0], 0, 128); |
||||
|
fcb_i_gbpb(fcb, 33); # READ RANDOM |
||||
|
fcb.dirty := 0; |
||||
|
end sub; |
||||
|
|
||||
|
sub fcb_i_blockout(fcb: [FCB]) is |
||||
|
if fcb.dirty != 0 then |
||||
|
fcb_i_gbpb(fcb, 34); # WRITE RANDOM |
||||
|
fcb.dirty := 0; |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub fcb_i_changeblock(fcb: [FCB], newblock: uint16) is |
||||
|
if newblock != fcb.cpm.r then |
||||
|
fcb_i_blockout(fcb); |
||||
|
fcb.cpm.r := newblock; |
||||
|
fcb_i_blockin(fcb); |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub fcb_i_convert_a_to_error() is |
||||
|
@asm "cp 0xff"; |
||||
|
@asm "ld a, 0"; |
||||
|
@asm "ret nz"; |
||||
|
@asm "inc a"; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBOpenIn(fcb: [FCB], filename: [uint8]): (errno: uint8) is |
||||
|
file_i_init(fcb, filename); |
||||
|
|
||||
|
var cpmfcb := &fcb.cpm; |
||||
|
@asm "ld c, 15"; # OPEN_FILE |
||||
|
@asm "ld de, (", cpmfcb, ")"; |
||||
|
@asm "call 5"; |
||||
|
@asm "call", fcb_i_convert_a_to_error; |
||||
|
@asm "ld (", errno, "), a"; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBOpenUp(fcb: [FCB], filename: [uint8]): (errno: uint8) is |
||||
|
(errno) := FCBOpenIn(fcb, filename); |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBOpenOut(fcb: [FCB], filename: [uint8]): (errno: uint8) is |
||||
|
file_i_init(fcb, filename); |
||||
|
|
||||
|
var cpmfcb := &fcb.cpm; |
||||
|
@asm "ld c, 19"; # DELETE_FILE |
||||
|
@asm "ld de, (", cpmfcb, ")"; |
||||
|
@asm "call 5"; |
||||
|
|
||||
|
@asm "ld c, 22"; # CREATE_FILE |
||||
|
@asm "ld de, (", cpmfcb, ")"; |
||||
|
@asm "call 5"; |
||||
|
@asm "call", fcb_i_convert_a_to_error; |
||||
|
@asm "ld (", errno, "), a"; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBClose(fcb: [FCB]): (errno: uint8) is |
||||
|
fcb_i_blockout(fcb); |
||||
|
|
||||
|
var cpmfcb := &fcb.cpm; |
||||
|
@asm "ld c, 16"; # CLOSE_FILE |
||||
|
@asm "ld de, (", cpmfcb, ")"; |
||||
|
@asm "call 5"; |
||||
|
@asm "call", fcb_i_convert_a_to_error; |
||||
|
@asm "ld (", errno, "), a"; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBSeek(fcb: [FCB], pos: uint32) is |
||||
|
pos := pos - 1; # seek to *previous* character |
||||
|
var newblock := (pos >> 7) as uint16; |
||||
|
var newptr := (pos as uint8) & 127; |
||||
|
fcb_i_changeblock(fcb, newblock); |
||||
|
fcb.bufferptr := newptr; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBPos(fcb: [FCB]): (pos: uint32) is |
||||
|
pos := (((fcb.cpm.r as uint32) << 7) | (fcb.bufferptr as uint32)) + 1; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBExt(fcb: [FCB]): (len: uint32) is |
||||
|
var oldblock := fcb.cpm.r; |
||||
|
var cpmfcb := &fcb.cpm; |
||||
|
|
||||
|
@asm "ld c, 16"; # CLOSE_FILE (actually flushing it to disk) |
||||
|
@asm "ld de, (", cpmfcb, ")"; |
||||
|
@asm "call 5"; |
||||
|
|
||||
|
@asm "ld c, 35"; # COMPUTE FILE SIZE |
||||
|
@asm "ld de, (", cpmfcb, ")"; |
||||
|
@asm "call 5"; |
||||
|
|
||||
|
len := ([&fcb.cpm.r as [uint32]] & 0x00ffffff) << 7; |
||||
|
fcb.cpm.r := oldblock; |
||||
|
end sub; |
||||
|
|
||||
|
sub fcb_i_nextchar(fcb: [FCB]) is |
||||
|
fcb.bufferptr := fcb.bufferptr + 1; |
||||
|
if fcb.bufferptr == 128 then |
||||
|
fcb_i_changeblock(fcb, fcb.cpm.r + 1); |
||||
|
fcb.bufferptr := 0; |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBGetChar(fcb: [FCB]): (c: uint8) is |
||||
|
fcb_i_nextchar(fcb); |
||||
|
c := fcb.buffer[fcb.bufferptr]; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBPutChar(fcb: [FCB], c: uint8) is |
||||
|
fcb_i_nextchar(fcb); |
||||
|
fcb.buffer[fcb.bufferptr] := c; |
||||
|
fcb.dirty := 1; |
||||
|
end sub; |
||||
|
|
||||
|
include "commfile.coh"; |
||||
|
|
||||
@ -0,0 +1,121 @@ |
|||||
|
const FCB_FLAG_ERROR := 1<<0; |
||||
|
const FCB_FLAG_READ := 1<<1; |
||||
|
const FCB_FLAG_WRITE := 1<<2; |
||||
|
|
||||
|
record FCB: RawFCB is |
||||
|
pos: uint32; |
||||
|
buflen: FCBIndexType; |
||||
|
index: FCBIndexType; |
||||
|
buffer: uint8[FCB_BUFFER_SIZE]; |
||||
|
flags: uint8; |
||||
|
end record; |
||||
|
|
||||
|
@decl sub FCBRawRead(fcb: [FCB], pos: uint32, len: FCBIndexType): (amount: FCBIndexType); |
||||
|
@decl sub FCBRawWrite(fcb: [FCB], pos: uint32, len: FCBIndexType); |
||||
|
|
||||
|
sub _fcb_init(fcb: [FCB]) is |
||||
|
fcb.pos := 0; |
||||
|
fcb.buflen := 0; |
||||
|
fcb.index := 0; |
||||
|
fcb.flags := 0; |
||||
|
end sub; |
||||
|
|
||||
|
sub _fcb_advance(fcb: [FCB]) is |
||||
|
fcb.index := fcb.index + 1; |
||||
|
end sub; |
||||
|
|
||||
|
sub _fcb_fillbuffer(fcb: [FCB]): (b: uint8) is |
||||
|
var bufpos := fcb.pos + (fcb.index as uint32); |
||||
|
fcb.buflen := FCBRawRead(fcb, bufpos, FCB_BUFFER_SIZE); |
||||
|
b := 0; |
||||
|
if (fcb.flags & FCB_FLAG_ERROR) != 0 then |
||||
|
return; |
||||
|
end if; |
||||
|
fcb.flags := FCB_FLAG_READ; |
||||
|
fcb.pos := bufpos; |
||||
|
fcb.index := 0; |
||||
|
if fcb.buflen != 0 then |
||||
|
b := fcb.buffer[0]; |
||||
|
_fcb_advance(fcb); |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBFlush(fcb: [FCB]) is |
||||
|
var bufpos := fcb.pos; |
||||
|
if (fcb.flags & FCB_FLAG_WRITE) != 0 then |
||||
|
FCBRawWrite(fcb, bufpos, fcb.index); |
||||
|
if (fcb.flags & FCB_FLAG_ERROR) != 0 then |
||||
|
return; |
||||
|
end if; |
||||
|
end if; |
||||
|
fcb.pos := bufpos + (fcb.index as uint32); |
||||
|
fcb.flags := 0; |
||||
|
fcb.index := 0; |
||||
|
fcb.buflen := 0; |
||||
|
end sub; |
||||
|
|
||||
|
sub _fcb_flushbuffer(fcb: [FCB], b: uint8) is |
||||
|
FCBFlush(fcb); |
||||
|
if (fcb.flags & FCB_FLAG_ERROR) != 0 then |
||||
|
return; |
||||
|
end if; |
||||
|
fcb.flags := FCB_FLAG_WRITE; |
||||
|
fcb.buffer[0] := b; |
||||
|
_fcb_advance(fcb); |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBGetChar(fcb: [FCB]): (b: uint8) is |
||||
|
if (fcb.flags & FCB_FLAG_WRITE) != 0 then |
||||
|
FCBFlush(fcb); |
||||
|
end if; |
||||
|
var i := fcb.index; |
||||
|
if i == fcb.buflen then |
||||
|
b := _fcb_fillbuffer(fcb); |
||||
|
else |
||||
|
b := fcb.buffer[i]; |
||||
|
_fcb_advance(fcb); |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBPutChar(fcb: [FCB], b: uint8) is |
||||
|
if (fcb.flags & FCB_FLAG_READ) != 0 then |
||||
|
FCBFlush(fcb); |
||||
|
end if; |
||||
|
var i := fcb.index; |
||||
|
if i == FCB_BUFFER_SIZE then |
||||
|
_fcb_flushbuffer(fcb, b); |
||||
|
else |
||||
|
fcb.buffer[i] := b; |
||||
|
_fcb_advance(fcb); |
||||
|
end if; |
||||
|
fcb.flags := fcb.flags | FCB_FLAG_WRITE; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBPos(fcb: [FCB]): (pos: uint32) is |
||||
|
pos := fcb.pos + (fcb.index as uint32); |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBError(fcb: [FCB]): (e: uint8) is |
||||
|
e := 0; |
||||
|
if (fcb.flags & FCB_FLAG_ERROR) != 0 then |
||||
|
e := 1; |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub FCBSeek(fcb: [FCB], pos: uint32) is |
||||
|
var delta := pos - fcb.pos; |
||||
|
if (fcb.flags & FCB_FLAG_READ) != 0 then |
||||
|
if delta < (fcb.buflen as uint32) then |
||||
|
fcb.index := delta as FCBIndexType; |
||||
|
return; |
||||
|
end if; |
||||
|
elseif (fcb.flags & FCB_FLAG_WRITE) != 0 then |
||||
|
if delta <= (fcb.index as uint32) then |
||||
|
fcb.index := delta as FCBIndexType; |
||||
|
return; |
||||
|
end if; |
||||
|
end if; |
||||
|
FCBFlush(fcb); |
||||
|
fcb.pos := pos; |
||||
|
end sub; |
||||
|
|
||||
@ -0,0 +1,115 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2020 Brian Callahan <bcallah@openbsd.org> |
||||
|
# |
||||
|
# Permission to use, copy, modify, and distribute this software for any |
||||
|
# purpose with or without fee is hereby granted, provided that the above |
||||
|
# copyright notice and this permission notice appear in all copies. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
# Clone of Unix hexdump -C |
||||
|
# Should work on all Cowgol systems |
||||
|
|
||||
|
include "stdcow.coh"; |
||||
|
include "argv.coh"; |
||||
|
|
||||
|
var InputFile: FCB; |
||||
|
|
||||
|
var addr: uint32; |
||||
|
var len: uint32; |
||||
|
|
||||
|
sub Hexdump() is |
||||
|
var buf: uint8[16]; |
||||
|
var i: uint8; |
||||
|
var j: uint8; |
||||
|
|
||||
|
print_hex_i32(addr); |
||||
|
print(" "); |
||||
|
|
||||
|
i := 0; |
||||
|
|
||||
|
loop |
||||
|
var c: uint8 := FCBGetChar(&InputFile); |
||||
|
|
||||
|
buf[i] := c; |
||||
|
print_hex_i8(c); |
||||
|
print(" "); |
||||
|
if i == 7 then |
||||
|
print(" "); |
||||
|
end if; |
||||
|
|
||||
|
i := i + 1; |
||||
|
len := len - 1; |
||||
|
|
||||
|
if len == 0 or i > 15 then |
||||
|
break; |
||||
|
end if; |
||||
|
end loop; |
||||
|
|
||||
|
addr := addr + (i as uint32); |
||||
|
|
||||
|
var k: uint8 := i; |
||||
|
if len == 0 then |
||||
|
if i < 8 then |
||||
|
print(" "); |
||||
|
end if; |
||||
|
|
||||
|
while i < 16 loop |
||||
|
print(" "); |
||||
|
buf[i] := ' '; |
||||
|
i := i + 1; |
||||
|
end loop; |
||||
|
end if; |
||||
|
|
||||
|
print(" |"); |
||||
|
|
||||
|
j := 0; |
||||
|
|
||||
|
while j < k loop |
||||
|
if buf[j] >= 0x20 and buf[j] <= 0x7e then |
||||
|
print_char(buf[j]); |
||||
|
else |
||||
|
print_char('.'); |
||||
|
end if; |
||||
|
|
||||
|
j := j + 1; |
||||
|
end loop; |
||||
|
|
||||
|
print("|\n"); |
||||
|
end sub; |
||||
|
|
||||
|
ArgvInit(); |
||||
|
|
||||
|
var FileName: [uint8] := ArgvNext(); |
||||
|
|
||||
|
if FileName == (0 as [uint8]) then |
||||
|
print("usage: hexdump file\n"); |
||||
|
ExitWithError(); |
||||
|
end if; |
||||
|
|
||||
|
if FCBOpenIn(&InputFile, FileName) != 0 then |
||||
|
print("hexdump: cannot open "); |
||||
|
print(FileName); |
||||
|
print("\n"); |
||||
|
ExitWithError(); |
||||
|
end if; |
||||
|
|
||||
|
addr := 0; |
||||
|
len := FCBExt(&InputFile); |
||||
|
while len > 0 loop |
||||
|
Hexdump(); |
||||
|
end loop; |
||||
|
|
||||
|
print_hex_i32(addr); |
||||
|
print("\n"); |
||||
|
|
||||
|
if FCBClose(&InputFile) != 0 then |
||||
|
ExitWithError(); |
||||
|
end if; |
||||
@ -0,0 +1,2 @@ |
|||||
|
COWGOL HEXDUMP.COW |
||||
|
|
||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,237 @@ |
|||||
|
record MallocFreeBlock is |
||||
|
next: [MallocFreeBlock]; |
||||
|
size: intptr; # bytes |
||||
|
end record; |
||||
|
|
||||
|
record MallocUsedBlock is |
||||
|
size: intptr; # bytes |
||||
|
end record; |
||||
|
|
||||
|
var freeList: [MallocFreeBlock] := LOMEM as [MallocFreeBlock]; |
||||
|
freeList.next := 0 as [MallocFreeBlock]; |
||||
|
freeList.size := HIMEM - LOMEM; |
||||
|
|
||||
|
sub DumpBlocks() is |
||||
|
var p := freeList; |
||||
|
var bytes: intptr := 0; |
||||
|
print("* freelist: "); |
||||
|
print_hex_i32(p as intptr as uint32); |
||||
|
print_nl(); |
||||
|
while p != (0 as [MallocFreeBlock]) loop |
||||
|
print("* block @"); |
||||
|
print_hex_i32(p as intptr as uint32); |
||||
|
print("+"); |
||||
|
print_hex_i32(p.size as intptr as uint32); |
||||
|
print("="); |
||||
|
print_hex_i32((p+p.size) as intptr as uint32); |
||||
|
print(" -> "); |
||||
|
print_hex_i32(p.next as intptr as uint32); |
||||
|
print_nl(); |
||||
|
|
||||
|
bytes := bytes + p.size; |
||||
|
p := p.next; |
||||
|
end loop; |
||||
|
print("* free bytes: "); |
||||
|
print_i32(bytes as intptr as uint32); |
||||
|
print_nl(); |
||||
|
print_nl(); |
||||
|
end sub; |
||||
|
|
||||
|
sub CheckMemoryChain() is |
||||
|
var p := freeList; |
||||
|
while p != (0 as [MallocFreeBlock]) loop |
||||
|
var next := p.next; |
||||
|
if next == (0 as [MallocFreeBlock]) then |
||||
|
break; |
||||
|
end if; |
||||
|
if next <= p then |
||||
|
DumpBlocks(); |
||||
|
print("bad chain: block "); |
||||
|
print_hex_i32(p as intptr as uint32); |
||||
|
print(" points at prior block "); |
||||
|
print_hex_i32(next as intptr as uint32); |
||||
|
print_nl(); |
||||
|
ExitWithError(); |
||||
|
end if; |
||||
|
|
||||
|
p := p.next; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub RawAlloc(length: intptr): (block: [uint8]) is |
||||
|
var totallength := AlignUp(length + @bytesof MallocUsedBlock); |
||||
|
if totallength < @bytesof MallocFreeBlock then |
||||
|
totallength := @bytesof MallocFreeBlock; |
||||
|
end if; |
||||
|
|
||||
|
# Make sure everything's rounded to 8 bytes to try and reduce |
||||
|
# fragmentation. |
||||
|
totallength := (totallength + 7) & ~7; |
||||
|
|
||||
|
# Fragmentation is a killer on small systems, so we use best fit. |
||||
|
|
||||
|
var p := freeList; |
||||
|
var prev: [MallocFreeBlock] := 0 as [MallocFreeBlock]; |
||||
|
var candidate: [MallocFreeBlock] := 0 as [MallocFreeBlock]; |
||||
|
var cprev: [MallocFreeBlock] := 0 as [MallocFreeBlock]; |
||||
|
var csize: intptr := -1; |
||||
|
|
||||
|
# Try to find the smallest block which will fit. |
||||
|
while p != (0 as [MallocFreeBlock]) loop |
||||
|
var s := p.size; |
||||
|
if (s >= totallength) and (s < csize) then |
||||
|
candidate := p; |
||||
|
csize := s; |
||||
|
cprev := prev; |
||||
|
if csize == totallength then |
||||
|
# This is an exact fit. We can't do better than this, so stop here. |
||||
|
break; |
||||
|
end if; |
||||
|
end if; |
||||
|
prev := p; |
||||
|
p := p.next; |
||||
|
end loop; |
||||
|
if candidate == (0 as [MallocFreeBlock]) then |
||||
|
# Nothing was found. |
||||
|
block := 0 as [uint8]; |
||||
|
return; |
||||
|
end if; |
||||
|
|
||||
|
var delta := csize - totallength; |
||||
|
if delta < @bytesof MallocFreeBlock then |
||||
|
# Consume the entire block. |
||||
|
if cprev != (0 as [MallocFreeBlock]) then |
||||
|
cprev.next := candidate.next; |
||||
|
else |
||||
|
freeList := candidate.next; |
||||
|
end if; |
||||
|
totallength := csize; |
||||
|
else |
||||
|
# We found a hole bigger than we need. We shrink the hole and return |
||||
|
# what's left. |
||||
|
candidate.size := delta; |
||||
|
candidate := candidate + candidate.size; |
||||
|
end if; |
||||
|
|
||||
|
#print("malloc "); |
||||
|
#print_hex_i32(candidate as intptr as uint32); |
||||
|
#print("+"); |
||||
|
#print_hex_i32(totallength as uint32); |
||||
|
#print_nl(); |
||||
|
|
||||
|
var usedblock := candidate as [MallocUsedBlock]; |
||||
|
usedblock.size := totallength; |
||||
|
block := (@next usedblock) as [uint8]; |
||||
|
|
||||
|
#print("malloc "); |
||||
|
#print_hex_i32(block as intptr as uint32); |
||||
|
#print("+"); |
||||
|
#print_hex_i32(length as uint32); |
||||
|
#print_nl(); |
||||
|
|
||||
|
MemSet(block, 0, totallength - @bytesof MallocUsedBlock); |
||||
|
#CheckMemoryChain(); |
||||
|
end sub; |
||||
|
|
||||
|
sub Alloc(length: intptr): (block: [uint8]) is |
||||
|
block := RawAlloc(length); |
||||
|
if block == (0 as [uint8]) then |
||||
|
print("Out of memory"); |
||||
|
ExitWithError(); |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub AddFreeBlock(start: [uint8], length: intptr) is |
||||
|
#print("free "); |
||||
|
#print_hex_i32(start as intptr as uint32); |
||||
|
#print("+"); |
||||
|
#print_hex_i32(length as uint32); |
||||
|
#print_nl(); |
||||
|
|
||||
|
MemSet(start, 0xaa, length); |
||||
|
|
||||
|
var h := start as [MallocFreeBlock]; |
||||
|
h.size := length; |
||||
|
|
||||
|
# freeList points at an ordered list of free blocks. First, we run |
||||
|
# through the list until we find the last block *before* this one. |
||||
|
|
||||
|
var p := freeList; |
||||
|
if h < p then |
||||
|
# Special case: the new block will become the new *first* block. |
||||
|
|
||||
|
if (h + h.size) == p then |
||||
|
h.size := length + p.size; |
||||
|
h.next := p.next; |
||||
|
else |
||||
|
h.next := p; |
||||
|
end if; |
||||
|
freeList := h; |
||||
|
else |
||||
|
# Otherwise, work through the list and find the block immediately |
||||
|
# preceding the one we're going to insert. |
||||
|
|
||||
|
loop |
||||
|
# Is this the last block? |
||||
|
|
||||
|
if p.next == (0 as [MallocFreeBlock]) then |
||||
|
# Insert the new block after it. |
||||
|
|
||||
|
p.next := h; |
||||
|
h.next := 0 as [MallocFreeBlock]; |
||||
|
break; |
||||
|
end if; |
||||
|
|
||||
|
# We know that h cannot be before p, so if h is before the |
||||
|
# *next* block, then this must be the block preceding it. |
||||
|
|
||||
|
if h < p.next then |
||||
|
# Try to merge the next block onto the end of h. |
||||
|
|
||||
|
if (h + length) == p.next then |
||||
|
h.size := length + p.next.size; |
||||
|
h.next := p.next.next; |
||||
|
else |
||||
|
h.next := p.next; |
||||
|
end if; |
||||
|
p.next := h; |
||||
|
break; |
||||
|
end if; |
||||
|
|
||||
|
p := p.next; |
||||
|
end loop; |
||||
|
|
||||
|
# p now points at the preceding block. Try to merge h onto the |
||||
|
# end of it. |
||||
|
|
||||
|
if (p + p.size) == h then |
||||
|
p.size := p.size + h.size; |
||||
|
p.next := h.next; |
||||
|
end if; |
||||
|
end if; |
||||
|
|
||||
|
#CheckMemoryChain(); |
||||
|
end sub; |
||||
|
|
||||
|
sub Free(start: [uint8]) is |
||||
|
if start != (0 as [uint8]) then |
||||
|
var usedblock := @prev (start as [MallocUsedBlock]); |
||||
|
AddFreeBlock(usedblock as [uint8], usedblock.size); |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub GetFreeMemory(): (bytes: intptr) is |
||||
|
bytes := 0; |
||||
|
var p := freeList; |
||||
|
while p != (0 as [MallocFreeBlock]) loop |
||||
|
bytes := bytes + p.size; |
||||
|
p := p.next; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub StrDup(s: [uint8]): (news: [uint8]) is |
||||
|
var len := StrLen(s) + 1; |
||||
|
news := Alloc(len); |
||||
|
MemCopy(s, len, news); |
||||
|
end sub; |
||||
|
|
||||
@ -0,0 +1,78 @@ |
|||||
|
|
||||
|
int L[500], R[500]; |
||||
|
|
||||
|
// Merges two subarrays of arr[].
|
||||
|
// First subarray is arr[l..m]
|
||||
|
// Second subarray is arr[m+1..r]
|
||||
|
void merge(int arr[], int l, int m, int r) |
||||
|
{ |
||||
|
int i, j, k; |
||||
|
int n1 = m - l + 1; |
||||
|
int n2 = r - m; |
||||
|
|
||||
|
// Copy data to temp arrays L[] and R[]
|
||||
|
for (i = 0; i < n1; i++) |
||||
|
L[i] = arr[l + i]; |
||||
|
|
||||
|
for (j = 0; j < n2; j++) |
||||
|
R[j] = arr[m + 1 + j]; |
||||
|
|
||||
|
// Merge the temp arrays back into arr[l..r
|
||||
|
i = 0; |
||||
|
j = 0; |
||||
|
k = l; |
||||
|
|
||||
|
while (i < n1 && j < n2) |
||||
|
{ |
||||
|
if (L[i] <= R[j]) |
||||
|
{ |
||||
|
arr[k] = L[i]; |
||||
|
i++; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
arr[k] = R[j]; |
||||
|
j++; |
||||
|
} |
||||
|
|
||||
|
k++; |
||||
|
} |
||||
|
|
||||
|
// Copy the remaining elements of L[],
|
||||
|
// if there are any
|
||||
|
while (i < n1) |
||||
|
{ |
||||
|
arr[k] = L[i]; |
||||
|
i++; |
||||
|
k++; |
||||
|
} |
||||
|
|
||||
|
// Copy the remaining elements of R[],
|
||||
|
// if there are any
|
||||
|
while (j < n2) |
||||
|
{ |
||||
|
arr[k] = R[j]; |
||||
|
j++; |
||||
|
k++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// l is for left index and r is right index of the
|
||||
|
// sub-array of arr to be sorted
|
||||
|
// first call with l = 0, r = sizeof(arr) - 1
|
||||
|
void mergeSort(int arr[], int l, int r) |
||||
|
{ |
||||
|
int m; |
||||
|
|
||||
|
if (l < r) |
||||
|
{ |
||||
|
m = l + (r - l) / 2; |
||||
|
|
||||
|
// Sort first and second halves
|
||||
|
mergeSort(arr, l, m); |
||||
|
mergeSort(arr, m + 1, r); |
||||
|
|
||||
|
merge(arr, l, m, r); |
||||
|
} |
||||
|
} |
||||
|
|
||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,52 @@ |
|||||
|
; Xorshift is a class of pseudorandom number generators discovered |
||||
|
; by George Marsaglia and detailed in his 2003 paper, Xorshift RNGs. |
||||
|
; |
||||
|
; 16-bit xorshift pseudorandom number generator by John Metcalf |
||||
|
; returns hl = pseudorandom number |
||||
|
; corrupts a |
||||
|
|
||||
|
; generates 16-bit pseudorandom numbers with a period of 65535 |
||||
|
; using the xorshift method: |
||||
|
|
||||
|
; hl ^= hl << 7 |
||||
|
; hl ^= hl >> 9 |
||||
|
; hl ^= hl << 8 |
||||
|
|
||||
|
; some alternative shift triplets which also perform well are: |
||||
|
; 6, 7, 13; 7, 9, 13; 9, 7, 13. |
||||
|
|
||||
|
psect text |
||||
|
|
||||
|
GLOBAL _xrnd, _xrndseed |
||||
|
|
||||
|
_xrnd: |
||||
|
ld hl,1 ; seed must not be 0 |
||||
|
ld a,h |
||||
|
rra |
||||
|
ld a,l |
||||
|
rra |
||||
|
xor h |
||||
|
ld h,a |
||||
|
ld a,l |
||||
|
rra |
||||
|
ld a,h |
||||
|
rra |
||||
|
xor l |
||||
|
ld l,a |
||||
|
xor h |
||||
|
ld h,a |
||||
|
ld (_xrnd+1),hl |
||||
|
res 7,h ;make-it positive... |
||||
|
ret |
||||
|
|
||||
|
_xrndseed: |
||||
|
ld a,r |
||||
|
ld l,a |
||||
|
ld a,r |
||||
|
ld h,a |
||||
|
or l ; HL must be not NULL |
||||
|
jr nz,1f |
||||
|
inc hl |
||||
|
1: |
||||
|
ld (_xrnd+1),hl |
||||
|
ret |
||||
@ -0,0 +1,91 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2020 Brian Callahan <bcallah@openbsd.org> |
||||
|
# |
||||
|
# Permission to use, copy, modify, and distribute this software for any |
||||
|
# purpose with or without fee is hereby granted, provided that the above |
||||
|
# copyright notice and this permission notice appear in all copies. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
# Cowgol standard library |
||||
|
|
||||
|
# Uncomment these if you'd like to abstract the includes away. |
||||
|
include "cowgol.coh"; |
||||
|
include "file.coh"; |
||||
|
include "strings.coh"; |
||||
|
include "malloc.coh"; |
||||
|
|
||||
|
# Print a properly formatted 8-bit hex number to a file. |
||||
|
sub FCBPutHex8(fcb: [FCB], number: uint8) is |
||||
|
var i: uint8 := 0; |
||||
|
var nibble: uint8; |
||||
|
|
||||
|
while i < 2 loop |
||||
|
nibble := number >> 4; |
||||
|
|
||||
|
if nibble < 10 then |
||||
|
nibble := nibble + '0'; |
||||
|
else |
||||
|
nibble := nibble + ('A' - 10); |
||||
|
end if; |
||||
|
|
||||
|
FCBPutChar(fcb, nibble); |
||||
|
|
||||
|
number := number << 4; |
||||
|
|
||||
|
i := i + 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
# Print a properly formatted 16-bit hex number to a file. |
||||
|
sub FCBPutHex16(fcb: [FCB], number: uint16) is |
||||
|
FCBPutHex8(fcb, ((number >> 8) as uint8)); |
||||
|
FCBPutHex8(fcb, (number as uint8)); |
||||
|
end sub; |
||||
|
|
||||
|
# Print a properly formatted 32-bit hex number to a file. |
||||
|
sub FCBPutHex32(fcb: [FCB], number: uint32) is |
||||
|
FCBPutHex16(fcb, ((number >> 16) as uint16)); |
||||
|
FCBPutHex16(fcb, (number as uint16)); |
||||
|
end sub; |
||||
|
|
||||
|
# Print a signed 32-bit integer to the console. |
||||
|
sub print_d32(value: int32) is |
||||
|
var buffer: uint8[12]; |
||||
|
var pe := IToA(value, 10, &buffer[0]); |
||||
|
print(&buffer[0]); |
||||
|
end sub; |
||||
|
|
||||
|
# Read in a string. |
||||
|
sub GetString(): (s: [uint8]) is |
||||
|
var temp: uint8[256]; |
||||
|
var c: uint8; |
||||
|
var i: uint8 := 0; |
||||
|
|
||||
|
while i < 255 loop |
||||
|
c := get_char(); |
||||
|
if c == 10 or c == 13 then |
||||
|
break; |
||||
|
end if; |
||||
|
|
||||
|
temp[i] := c; |
||||
|
|
||||
|
i := i + 1; |
||||
|
end loop; |
||||
|
temp[i] := 0; |
||||
|
|
||||
|
if i == 0 then |
||||
|
s := (0 as [uint8]); |
||||
|
return; |
||||
|
end if; |
||||
|
|
||||
|
s := Alloc(((i + 1) as intptr)); |
||||
|
CopyString(&temp[0], s); |
||||
|
end sub; |
||||
@ -0,0 +1,63 @@ |
|||||
|
sub StrCmp(s1: [uint8], s2: [uint8]): (res: int8) is |
||||
|
loop |
||||
|
res := ([s1] - [s2]) as int8; |
||||
|
if (res != 0) or ([s1] == 0) then |
||||
|
break; |
||||
|
end if; |
||||
|
s1 := s1 + 1; |
||||
|
s2 := s2 + 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub ToLower(c: uint8): (cc: uint8) is |
||||
|
if (c >= 'A') and (c <= 'Z') then |
||||
|
cc := c | 32; |
||||
|
else |
||||
|
cc := c; |
||||
|
end if; |
||||
|
end sub; |
||||
|
|
||||
|
sub StrICmp(s1: [uint8], s2: [uint8]): (res: int8) is |
||||
|
loop |
||||
|
res := (ToLower([s1]) - ToLower([s2])) as int8; |
||||
|
if (res != 0) or ([s1] == 0) then |
||||
|
break; |
||||
|
end if; |
||||
|
s1 := s1 + 1; |
||||
|
s2 := s2 + 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub StrLen(s: [uint8]): (size: intptr) is |
||||
|
var p := s; |
||||
|
loop |
||||
|
var c := [p]; |
||||
|
if c == 0 then |
||||
|
break; |
||||
|
end if; |
||||
|
p := p + 1; |
||||
|
end loop; |
||||
|
size := p - s; |
||||
|
end sub; |
||||
|
|
||||
|
sub CopyString(src: [uint8], dest: [uint8]) is |
||||
|
loop |
||||
|
var c := [src]; |
||||
|
[dest] := c; |
||||
|
src := src + 1; |
||||
|
dest := dest + 1; |
||||
|
if c == 0 then |
||||
|
break; |
||||
|
end if; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
|
sub MemCopy(src: [uint8], size: intptr, dest: [uint8]) is |
||||
|
while size != 0 loop |
||||
|
[dest] := [src]; |
||||
|
dest := dest + 1; |
||||
|
src := src + 1; |
||||
|
size := size - 1; |
||||
|
end loop; |
||||
|
end sub; |
||||
|
|
||||
Binary file not shown.
Loading…
Reference in new issue