mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2025-04-18 05:38:36 +01:00
Remove ugly HPET implementation
This commit is contained in:
parent
8c7d478d86
commit
af86b51e29
15 changed files with 1781 additions and 1920 deletions
src
Binary file not shown.
Binary file not shown.
|
@ -2,7 +2,7 @@ $WW,1$The $FG,2$Programmable Interval Timer$FG$ has two purposes: Generate inter
|
|||
|
||||
It has 3 channels:
|
||||
|
||||
$LK,"Channel 0",A="MN:PIT0"$ can generate an interrupt, IRQ 0, at a defined frequency. We set it up in $LK,"TimersInit",A="MN:TimersInit"$(), and use it in $LK,"SysTimerRead",A="MN:SysTimerRead"$().
|
||||
$LK,"Channel 0",A="MN:PIT0"$ can generate an interrupt, IRQ 0, at a defined frequency. We set it up in $LK,"TimerInit",A="MN:TimerInit"$(), and use it in $LK,"SysTimerRead",A="MN:SysTimerRead"$().
|
||||
|
||||
Channel 1 ised to be used to refresh the DRAM, but now it is obsolete as the hardware does this itself. Channel 1 is useless and might not even be implemented anymore on modern machines.
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
$WW,1$The HPET, high precision event timer, is read with $LK,"HPET",A="MN:HPET"$() and has a frequency of $LK,"counts.HPET_freq",A="MN:CCountsGlobals"$. A typical freq value is 14.3 Mhz It might not be available on all systems.
|
|
@ -4,7 +4,7 @@ If a feature cannot be made to work correctly and consistently, professional com
|
|||
|
||||
The PCI bus interface is what modern hardware uses. Before PCI, life was simple and devices used I/O ports. After studying $LK,"PCI Interrupts",A="FI:::/Demo/Lectures/PCIInterrupts.CC"$ and attempting to do a HDAudio driver, I came to realize that modern PCI devices require ten times more code and I cannot even come close to making them work on everyone's machine because with PCI devices there are several models to worry about, unlike with the older ISA bus devices which can be done with one driver.
|
||||
|
||||
Currently, I have no PCI drivers. My drivers use I/O ports and operate in ISA bus mode. At this point, I only have one driver for each type of device and it is delightfully simple that way. I have one $LK,"keyboard",A="FI:::/Kernel/SerialDev/Keyboard.CC"$ driver, one $LK,"mouse",A="FI:::/Kernel/SerialDev/Mouse.CC"$ driver, one $LK,"ATA hard drive",A="FI:::/Kernel/BlkDev/DiskATA.CC"$ driver, one $LK,"ATAPI CD/DVD",A="FI:::/Kernel/BlkDev/DiskATA.CC"$ driver, one $LK,"VGA 640x480 16 color",A="FI:::/Zenith/Gr/GrScreen.CC"$ video driver and one $LK,"PC Speaker",A="MN:Sound"$ driver. I use the $LK,"PIT and HPET timers",A="MN:TimersInit"$ and $LK,"PIC Interrupt Controller",A="MN:IntsInit"$. I use IRQ0 for timer, IRQ1 for keyboard, and IRQ12 for mouse. If IRQ12 is not firing, I am able to poll the mouse.
|
||||
Currently, I have no PCI drivers. My drivers use I/O ports and operate in ISA bus mode. At this point, I only have one driver for each type of device and it is delightfully simple that way. I have one $LK,"keyboard",A="FI:::/Kernel/SerialDev/Keyboard.CC"$ driver, one $LK,"mouse",A="FI:::/Kernel/SerialDev/Mouse.CC"$ driver, one $LK,"ATA hard drive",A="FI:::/Kernel/BlkDev/DiskATA.CC"$ driver, one $LK,"ATAPI CD/DVD",A="FI:::/Kernel/BlkDev/DiskATA.CC"$ driver, one $LK,"VGA 640x480 16 color",A="FI:::/Zenith/Gr/GrScreen.CC"$ video driver and one $LK,"PC Speaker",A="MN:Sound"$ driver. I use the $LK,"PIT timer",A="MN:TimerInit"$ and $LK,"PIC Interrupt Controller",A="MN:IntsInit"$. I use IRQ0 for timer, IRQ1 for keyboard, and IRQ12 for mouse. If IRQ12 is not firing, I am able to poll the mouse.
|
||||
|
||||
In the CPU department, I have state of the art 64-bit $LK,"long mode",A="FI:::/Kernel/KStart64.CC"$ with $LK,"multicore",A="FI:::/Kernel/MultiProc.CC"$ support. I use the $LK,"APIC",A="MN:MPAPICInit"$ and start-up $LK,"multicore",A="MN:Core0StartMP"$ operation.
|
||||
|
||||
|
@ -12,7 +12,7 @@ I have made an incredible accomplishment by getting it to work on practically ev
|
|||
|
||||
Adding a USB driver would be really ugly with UHCI, EHCI, OHCI, USB1, USB2, USB3, ICH6, ICH7, ICH8, ICH9, ICH10, ICH11, ICH12, boot mode and regular mode for keyboard/mouse and a diversity of HID reports. It's hopeless. I could never offer anything but crappy, limited support and it would just add a ton of crappy code that mostly didn't work. What would I gain? Nothing. A keyboard or mouse would not be improved. Solid State USB drives would be really nice, but it's not going to happen.
|
||||
|
||||
The same story is basically true for GPUs, audio, networking and AHCI hard drive drivers. God said 640x480 16 color was a covenant like circumcision, so the video will never change, even if a $LK,"Standard PC",A="FI:::/Doc/StdZenithOSPC.DD"$ was made. If you attempt multimedia, everything will break because memory will get fragmented with huge multimedia files. Some day, if super-simple high speed serial allows networking, there will be no browser within the 100,000 line limit and, with only 16 colors, the world wide web is not tolerable. FTP and telnet might be possible, in the far distant future, if they could fit within the 100,000 line limit. Currently, there are $TX,"82,150",D="DD_TEMPLEOS_LOC"$ lines of code.
|
||||
The same story is basically true for GPUs, audio, networking and AHCI hard drive drivers. God said 640x480 16 color was a covenant like circumcision, so the video will never change, even if a $LK,"Standard PC",A="FI:::/Doc/StdZenithOSPC.DD"$ was made. If you attempt multimedia, everything will break because memory will get fragmented with huge multimedia files. Some day, if super-simple high speed serial allows networking, there will be no browser within the 100,000 line limit and, with only 16 colors, the world wide web is not tolerable. FTP and telnet might be possible, in the far distant future, if they could fit within the 100,000 line limit. Currently, there are $TX,"80,849",D="DD_TEMPLEOS_LOC"$ lines of code.
|
||||
|
||||
I don't stand a chance working on native hardware, anymore. I could install and run natively on hardware from about 2005-2010. It requires BIOS's being nice enough to write USB mode PS/2 legacy keyboard/mouse support. As it turns-out, sometimes the BIOS has PS/2 drivers but purposely disables them, just to be mean. The CIA and whole industry is trying to mess everything up, on purpose. Perhaps, at a point of sale in a store, a thief could hack a credit card machine. Therefore, the BIOS companies actually want it difficult to make drivers and purposely make it broken.
|
||||
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
$WW+H,1$0.000011s
|
||||
C:/Home>$PT$ExeFile2("C:/Home/K.CC",CCF_CMD_LINE);
|
||||
$PT$$FG$$BG$Errs:0 Warns:0 Code:2BBCF Size:2F600
|
||||
|
||||
|
||||
In anticipation of the drives you will
|
||||
define shortly, enter the drive letter
|
||||
of the drive with the account directory.
|
||||
|
||||
($FG,5$<ENTER>$FG$ for cur drv) Boot Drive:$PT$C$FG$
|
||||
|
||||
$BK,1$$FG,5$Mount drives so they will be present when you boot.$FG$$BK,0$
|
||||
|
||||
****** Mount Drives ******
|
||||
$FG,2$A$FG$-$FG,2$B$FG$ are RAM drives.
|
||||
$FG,2$C$FG$-$FG,2$L$FG$ are ATA hard drives.
|
||||
$FG,2$M$FG$-$FG,2$P$FG$ are ISO file read drives.
|
||||
$FG,2$Q$FG$-$FG,2$S$FG$ are ISO file write drives.
|
||||
$FG,2$T$FG$-$FG,2$Z$FG$ are ATAPI CD/DVD drives.
|
||||
|
||||
Drive Letter ($FG,5$<ENTER>$FG$ to exit):$PT$C$FG$
|
||||
Partition Num (Default=All):$PT$
|
||||
$PT$$FG$$BG$
|
||||
We're going to probe hardware.
|
||||
$FG,4$Exit all other applications.$FG$
|
||||
Press '$FG,5$p$FG$' to probe or '$FG,5$s$FG$' to skip.
|
||||
|
||||
Subcode:0x8A Bus:0x0 Dev:0x1 Fun:0x1
|
||||
|
||||
$FG,5$ $BT,"1",LM="1\n"$$FG$$LM,4$$FG,4$Hard Drive $FG,9$ATA Primary IDE$FG$
|
||||
Base0:0x01F0 Base1:0x03F4 Unit:0$LM,0$
|
||||
|
||||
$FG,5$ $BT,"2",LM="2\n"$$FG$$LM,4$$FG,4$CD/DVD Drive $FG,9$ATAPI Secondary IDE$FG$
|
||||
$FG,5$(Drive originally installed from.)$FG$
|
||||
Base0:0x0170 Base1:0x0374 Unit:0$LM,0$
|
||||
|
||||
|
||||
Enter dev number or
|
||||
port with $FG,5$0x$FG$ prefix.
|
||||
I/O Port Base0:
|
||||
$PT$1
|
||||
$PT$$FG$$BG$
|
||||
****** Mount Drives ******
|
||||
$FG,2$A$FG$-$FG,2$B$FG$ are RAM drives.
|
||||
$FG,2$C$FG$-$FG,2$L$FG$ are ATA hard drives.
|
||||
$FG,2$M$FG$-$FG,2$P$FG$ are ISO file read drives.
|
||||
$FG,2$Q$FG$-$FG,2$S$FG$ are ISO file write drives.
|
||||
$FG,2$T$FG$-$FG,2$Z$FG$ are ATAPI CD/DVD drives.
|
||||
|
||||
Drive Letter ($FG,5$<ENTER>$FG$ to exit):$PT$
|
||||
$FG$
|
||||
Disk Cache Size in Bytes,
|
||||
gets rounded-up funny,
|
||||
($FG,5$<ENTER>$FG$ will use default.):$PT$
|
||||
$PT$$FG$$BG$$FG,5$ MemInit$FG$:Off
|
||||
$FG,5$ HeapInit$FG$:Off
|
||||
$FG,5$ VarInit$FG$:Off
|
||||
$FG,5$ StaffMode$FG$:Off
|
||||
$FG,5$ HomeDir$FG$:"::/Home"
|
||||
$FG,5$ NoMP$FG$:Off
|
||||
$FG,5$ TextMode$FG$:Off
|
||||
$FG,5$ DontProbe$FG$:Off
|
||||
$FG,5$ MountIDEAuto$FG$:Off
|
||||
$FG,5$ DebugDistro$FG$:Off
|
||||
|
||||
Type '$FG,5$Help$FG$' for help.
|
||||
Option ($FG,5$<ENTER>$FG$ when done):$PT$
|
||||
$PT$$FG$$BG$Errs:0 Warns:0 Code:29420 Size:2E1A0
|
||||
Copying /Kernel/Kernel.BIN to /Kernel.BIN.C
|
||||
Del Kernel.BIN
|
||||
Modifying partition boot record.
|
||||
|
||||
|
||||
Successful? (y or n)? $PT$NO$FG$
|
||||
1.611867s ans=0x00000000=0
|
||||
C:/Kernel>$PT$F("ClassRep(");
|
||||
$PT$$FG$$BG$$LK,"C:/Demo/Disk/BlkDevRep.CC,0007",A="PL:C:/Demo/Disk/BlkDevRep.CC,7"$ ClassRep(&blkdev.blkdevs[i]);
|
||||
$LK,"C:/Demo/Disk/DataBase.CC,0046",A="PL:C:/Demo/Disk/DataBase.CC,46"$ ClassRep(&a);
|
||||
$LK,"C:/Demo/Disk/DiskRaw.CC,0011",A="PL:C:/Demo/Disk/DiskRaw.CC,11"$ ClassRep(drive);
|
||||
$LK,"C:/Demo/Disk/DiskRaw.CC,0014",A="PL:C:/Demo/Disk/DiskRaw.CC,14"$ ClassRep(bd);
|
||||
$LK,"C:/Demo/DolDoc/Form.CC,0045",A="PL:C:/Demo/DolDoc/Form.CC,45"$ ClassRep(&fds);
|
||||
$LK,"C:/Demo/LastClass.CC,0031",A="PL:C:/Demo/LastClass.CC,31"$ ClassRep(Fs);
|
||||
$LK,"C:/Kernel/KDebug.CC,0507",A="PL:C:/Kernel/KDebug.CC,507"$ ">ClassRep(Fs,\"CTask\",1);\t//Dump current task record.\n"
|
||||
$LK,"C:/Kernel/KDebug.CC,0508",A="PL:C:/Kernel/KDebug.CC,508"$ ">ClassRep(Fs,,1);\t\t//(It knows lastclass.)\n"
|
||||
$LK,"C:/Kernel/KExterns.CC,0007",A="PL:C:/Kernel/KExterns.CC,7"$ import U0 ClassRep(U8 *_d,U8 *class_name=lastclass,
|
||||
$LK,"C:/Zenith/ZDebug.CC,0161",A="PL:C:/Zenith/ZDebug.CC,161"$ public U0 ClassRep(U8 *_d,U8 *class_name=lastclass,
|
||||
$LK,"C:/Zenith/ZDebug.CC,0243",A="PL:C:/Zenith/ZDebug.CC,243"$ ClassRep(img-tmpf->size,st,max_depth,FALSE,TRUE,rbp-img+tmpf->size);
|
||||
$LK,"C:/Zenith/ZDebug.CC,0246",A="PL:C:/Zenith/ZDebug.CC,246"$ ClassRep(rbp,st,max_depth,FALSE,TRUE);
|
||||
0.378766s ans=0x0000000C=12
|
||||
C:/Kernel>$PT$
|
||||
$PT$$FG$$BG$C:/Kernel>$PT$
|
||||
$PT$$FG$$BG$C:/Kernel>$PT$
|
||||
$PT$$FG$$BG$C:/Kernel>$PT$
|
||||
$PT$$FG$$BG$C:/Kernel>$PT$
|
||||
$PT$$FG$$BG$C:/Kernel>$PT$
|
||||
$PT$$FG$$BG$C:/Kernel>$PT$
|
BIN
src/Kernel.BIN.C
BIN
src/Kernel.BIN.C
Binary file not shown.
|
@ -18,7 +18,7 @@ F64 *pow10_I64,
|
|||
CAutoCompleteDictGlobals acd;
|
||||
CAutoCompleteGlobals ac;
|
||||
CBlkDevGlobals blkdev;
|
||||
CCountsGlobals counts={1,0,2676302000,2676302,2676302000,0,0,0,FALSE};
|
||||
CCountsGlobals counts={1,0,2676302000,2676302,2676302000,FALSE};
|
||||
CDebugGlobals debug;
|
||||
CDevGlobals dev;
|
||||
CGridGlobals mouse_grid; //See $LK,"::/Demo/Graphics/Grid.CC"$.
|
||||
|
|
|
@ -97,37 +97,11 @@ U0 SysGrInit()
|
|||
}
|
||||
}
|
||||
|
||||
U0 TimersInit()
|
||||
{//See $LK,"::/Doc/PIT.DD",A="FI:::/Doc/PIT.DD"$.
|
||||
I64 i,*_q;
|
||||
U32 *_d;
|
||||
|
||||
U0 TimerInit()
|
||||
{//See $LK,"::/Doc/PIT.DD",A="FI:::/Doc/PIT.DD"$.
|
||||
OutU8(PIT_CMD, PIT_CMDF_CHANNEL0 | PIT_CMDF_OPMODE_RATE_GEN | PIT_CMDF_ACCESS_WORD);
|
||||
OutU8(PIT0,SYS_TIMER0_PERIOD);
|
||||
OutU8(PIT0,SYS_TIMER0_PERIOD >> 8);
|
||||
|
||||
//High Precision Event Timer
|
||||
if (PCIReadU16(0,31,0,0)==0x8086) {//Intel?
|
||||
//D31 F0, config 0xF0=RCBA of PCI-LPC Bridge
|
||||
_d=PCIReadU32(0,31,0,0xF0)(U8 *)&~0x3FFF+0x3404; //HPET config
|
||||
//7 enable
|
||||
//1:0 HPET is at 0xFED00000,0xFED01000, 0xFED02000 or 0xFED03000.
|
||||
*_d=*_d&3|0x80;
|
||||
}
|
||||
|
||||
_q=dev.uncached_alias+HPET_GCAP_ID;
|
||||
i=*_q; //i.u32[1]= period in femtoS (10e-15)
|
||||
if (100000<i.u32[1]<1000000000) {
|
||||
counts.HPET_freq =1000000000000000/i.u32[1];
|
||||
counts.HPET_kHz_freq=1000000000000/i.u32[1];
|
||||
_q=dev.uncached_alias+HPET_GEN_CONF;
|
||||
*_q|=1; //Enable counting
|
||||
counts.HPET_initial=HPET;
|
||||
} else {
|
||||
counts.HPET_freq=0;
|
||||
counts.HPET_kHz_freq=0;
|
||||
counts.HPET_initial=0;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Reboot(Bool format_ramdisks=FALSE)
|
||||
|
@ -178,7 +152,7 @@ U0 KMain()
|
|||
"ZenithOS V%5.3f\t%D %T\n\n",
|
||||
sys_os_version,sys_compile_time,sys_compile_time;
|
||||
|
||||
TimersInit;
|
||||
TimerInit;
|
||||
if (BIOSTotalMem<ToI64(0.95*MEM_MIN_MEG*0x100000))
|
||||
RawPrint(4000,"!!! Requires $TX,"512Meg",D="DD_MEM_MIN_MEG"$ of RAM Memory !!!");
|
||||
|
||||
|
|
|
@ -78,25 +78,15 @@ I64 SysTimerRead()
|
|||
return res;
|
||||
}
|
||||
|
||||
I64 HPET()
|
||||
{ //Get high precision event timer.
|
||||
return *(dev.uncached_alias+HPET_MAIN_COUNT)(I64 *);
|
||||
}
|
||||
|
||||
I64 TimeCal()
|
||||
{
|
||||
static I64 time_stamp_start=0,timer_start=0,HPET_start=0;
|
||||
static I64 time_stamp_start=0,timer_start=0;
|
||||
I64 i;
|
||||
if (time_stamp_start) {
|
||||
PUSHFD
|
||||
CLI
|
||||
if (HPET_start) {
|
||||
counts.time_stamp_freq=counts.HPET_freq*(GetTSC-time_stamp_start);
|
||||
i=HPET-HPET_start;
|
||||
} else {
|
||||
counts.time_stamp_freq=SYS_TIMER_FREQ*(GetTSC-time_stamp_start);
|
||||
i=SysTimerRead-timer_start;
|
||||
}
|
||||
if (!i)
|
||||
ZenithErr("Timer Cal Error");
|
||||
else {
|
||||
|
@ -108,13 +98,7 @@ I64 TimeCal()
|
|||
}
|
||||
PUSHFD
|
||||
CLI
|
||||
if (counts.HPET_freq) {
|
||||
timer_start=0;
|
||||
HPET_start=HPET;
|
||||
} else {
|
||||
timer_start=SysTimerRead;
|
||||
HPET_start=0;
|
||||
}
|
||||
timer_start=SysTimerRead;
|
||||
time_stamp_start=GetTSC;
|
||||
POPFD
|
||||
return counts.time_stamp_freq;
|
||||
|
@ -122,10 +106,7 @@ I64 TimeCal()
|
|||
|
||||
F64 tS()
|
||||
{//Time since boot in seconds as a float.
|
||||
if (counts.HPET_freq)
|
||||
return ToF64(HPET-counts.HPET_initial)/counts.HPET_freq;
|
||||
else
|
||||
return SysTimerRead/ToF64(SYS_TIMER_FREQ);
|
||||
return SysTimerRead/ToF64(SYS_TIMER_FREQ);
|
||||
}
|
||||
|
||||
Bool Blink(F64 Hz=2.5)
|
||||
|
@ -137,12 +118,8 @@ Bool Blink(F64 Hz=2.5)
|
|||
U0 Busy(I64 æS)
|
||||
{//Loosely timed.
|
||||
I64 i;
|
||||
if (counts.HPET_freq) {
|
||||
i=HPET+counts.HPET_freq*æS/1000000;
|
||||
while (HPET<i);
|
||||
} else
|
||||
for (i=0;i<æS;i++)
|
||||
PortNop;
|
||||
for (i=0;i<æS;i++)
|
||||
PortNop;
|
||||
}
|
||||
|
||||
U0 SleepUntil(I64 wake_jiffy)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -509,7 +509,7 @@ class CKernel
|
|||
#define CR4F_PAE (1<<CR4f_PAE)
|
||||
#define CR4F_PGE (1<<CR4f_PGE)
|
||||
#define CR4F_OSFXSR (1<<CR4f_OSFXSR)
|
||||
|
||||
|
||||
//Model specific regs.
|
||||
#define IA32F_SCE 0x001
|
||||
#define IA32F_LME 0x100
|
||||
|
@ -584,22 +584,13 @@ class CAP16BitInit
|
|||
#define PIT_CMDF_CHANNEL0 0x00
|
||||
#define PIT_CMDF_CHANNEL2 0x80
|
||||
|
||||
#help_index "Time/CPU Cycles;Time/HPET;Time/Jiffies"
|
||||
//High Performance Event Timer
|
||||
#define HPET_GCAP_ID (0xFED00000+0x00)
|
||||
#define HPET_GEN_CONF (0xFED00000+0x10)
|
||||
#define HPET_MAIN_COUNT (0xFED00000+0xF0)
|
||||
|
||||
public class CCountsGlobals
|
||||
{
|
||||
I64 jiffies, //$LK,"JIFFY_FREQ",A="MN:JIFFY_FREQ"$
|
||||
timer, //$LK,"SYS_TIMER_FREQ",A="MN:SYS_TIMER_FREQ"$. Use $LK,"SysTimerRead",A="MN:SysTimerRead"$().
|
||||
time_stamp_freq,
|
||||
time_stamp_kHz_freq,
|
||||
time_stamp_freq_initial, //Initial freq, sampled once at boot time.
|
||||
HPET_freq,
|
||||
HPET_kHz_freq,
|
||||
HPET_initial; //Initial count, sampled at boot time.
|
||||
time_stamp_freq_initial; //Initial freq, sampled once at boot time.
|
||||
Bool time_stamp_calibrated;
|
||||
};
|
||||
|
||||
|
|
|
@ -727,7 +727,7 @@ public extern CTask *Spawn(U0 (*fp_addr)(U8 *data),U8 *data=NULL,
|
|||
CTask *parent=NULL, //NULL means zenith
|
||||
I64 stack_size=0,I64 flags=1<<JOBf_ADD_TO_QUE);
|
||||
|
||||
#help_index "Time/CPU Cycles;Time/HPET;Time/Jiffies"
|
||||
#help_index "Time/CPU Cycles;Time/Jiffies"
|
||||
public extern CCountsGlobals counts;
|
||||
|
||||
#help_index "Time/Date/CDate;Date/CDate"
|
||||
|
@ -750,10 +750,6 @@ public extern I64 YearStartDate(I64 year);
|
|||
public extern U16 mon_start_days1[12];
|
||||
public extern U16 mon_start_days2[12];
|
||||
|
||||
#help_index "Time/HPET"
|
||||
#help_file "::/Doc/TimeHPET"
|
||||
public extern I64 HPET();
|
||||
|
||||
#help_index "Time/Jiffies"
|
||||
#help_file "::/Doc/TimeJiffy"
|
||||
public extern I64 SysTimerRead();//18.33333*65536Hz (SYS_TIMER_FREQ)
|
||||
|
|
Binary file not shown.
|
@ -128,7 +128,7 @@ U0 ACPutChoices(CDoc *focus_l,CDocEntry *doc_e,CTask *focus_task,
|
|||
}
|
||||
ACDocReset(ac.col, ac.row);
|
||||
if (ac.cur_word && *ac.cur_word) {
|
||||
"$$PURPLE$$Word:%s$$FG$$\n",ac.cur_word;
|
||||
"$$RED$$Word:%s$$FG$$\n",ac.cur_word;
|
||||
for (i=0;i<ac.num_fillins;i++) {
|
||||
st=ac.fillin_matches[i]->str;
|
||||
"$$GREEN$$F%02d$$FG$$$$HL$$ ",i+1;
|
||||
|
|
Loading…
Reference in a new issue